==========================
Ellipses as args
==========================

insecure_function(...);
func(1, ...);
func(..., 1);
requests.get(..., $arg, ...);

---

(script
  (expression_statement
    (call_expression
      function: (qualified_identifier
        (identifier))
      (arguments
        (argument
          (ellipsis)))))
  (expression_statement
    (call_expression
      function: (qualified_identifier
        (identifier))
      (arguments
        (argument
          (integer))
        (argument
          (ellipsis)))))
  (expression_statement
    (call_expression
      function: (qualified_identifier
        (identifier))
      (arguments
        (argument
          (ellipsis))
        (argument
          (integer)))))
  (expression_statement
    (binary_expression
      left: (qualified_identifier
        (identifier))
      right: (call_expression
        function: (qualified_identifier
          (identifier))
        (arguments
          (argument
            (ellipsis))
          (argument
            (variable))
          (argument
            (ellipsis)))))))

==========================
Ellipses as params
==========================

function is_int(...);

function is_int(..., $var);

function is_int($var, ...);

function is_int($var, ...);

function is_int(..., int ...$arg1);

(...) ==> $x + 1;

<<Attribute, Attribute(...)>>
class C {
  <<Attribute(1, ..., 1)>>
  function method() {}
}

$f4 = function(..., $p1): int use ($p2, $p3) {};
$f4 = function(...): int use ($p2, $p3) {};

---

(script
  (function_declaration
    name: (identifier)
    (parameters
      (variadic_modifier)))
  (function_declaration
    name: (identifier)
    (parameters
      (parameter
        (ellipsis))
      (parameter
        name: (variable))))
  (function_declaration
    name: (identifier)
    (parameters
      (parameter
        name: (variable))
      (parameter
        (ellipsis))))
  (function_declaration
    name: (identifier)
    (parameters
      (parameter
        name: (variable))
      (parameter
        (ellipsis))))
  (function_declaration
    name: (identifier)
    (parameters
      (parameter
        (ellipsis))
      (parameter
        type: (type_specifier)
        (variadic_modifier)
        name: (variable))))
  (expression_statement
    (lambda_expression
      (parameters
        (variadic_modifier))
      body: (binary_expression
        left: (variable)
        right: (integer))))
  (class_declaration
    (attribute_modifier
      (qualified_identifier
        (identifier))
      (qualified_identifier
        (identifier))
      (arguments
        (argument
          (ellipsis))))
    name: (identifier)
    body: (member_declarations
      (method_declaration
        (attribute_modifier
          (qualified_identifier
            (identifier))
          (arguments
            (argument
              (integer))
            (argument
              (ellipsis))
            (argument
              (integer))))
        name: (identifier)
        (parameters)
        body: (compound_statement))))
  (expression_statement
    (binary_expression
      left: (variable)
      right: (anonymous_function_expression
        (parameters
          (parameter
            (ellipsis))
          (parameter
            name: (variable)))
        return_type: (type_specifier)
        (use_clause
          (variable)
          (variable))
        body: (compound_statement))))
  (expression_statement
    (binary_expression
      left: (variable)
      right: (anonymous_function_expression
        (parameters
          (variadic_modifier))
        return_type: (type_specifier)
        (use_clause
          (variable)
          (variable))
        body: (compound_statement)))))

==========================
Ellipses in method chaining
==========================

$var->make_test()->{...}->test_made();
// TODO: This should work in XHP attributes and interpolated strings

---

(script
  (expression_statement
    (call_expression
      function: (selection_expression
        (selection_expression
          (call_expression
            function: (selection_expression
              (variable)
              (qualified_identifier
                (identifier)))
            (arguments))
          (braced_expression
            (ellipsis)))
        (qualified_identifier
          (identifier)))
      (arguments)))
  (comment))

==========================
Ellipses in class def
==========================
class Test {
    ...
}

class Test {
    const int hello = 4;
    ...
    function tester() {
    }
}

---

(script
  (class_declaration
    name: (identifier)
    body: (member_declarations
      (ellipsis)))
  (class_declaration
    name: (identifier)
    body: (member_declarations
      (const_declaration
        type: (type_specifier)
        (const_declarator
          name: (identifier)
          value: (integer)))
      (ellipsis)
      (method_declaration
        name: (identifier)
        (parameters)
        body: (compound_statement)))))

==========================
Ellipses in func def
==========================

function test() {
    ...
}

function test() {
    ...;

}
function test() {
    $var = "hello";
    ...
    $hello = "hi";
}
function test() {
    $var = "hello";
    ...;
    $hello = "hi";
}

---

(script
  (function_declaration
    name: (identifier)
    (parameters)
    body: (compound_statement
      (empty_statement
        (ellipsis))))
  (function_declaration
    name: (identifier)
    (parameters)
    body: (compound_statement
      (expression_statement
        (ellipsis))))
  (function_declaration
    name: (identifier)
    (parameters)
    body: (compound_statement
      (expression_statement
        (binary_expression
          left: (variable)
          right: (string)))
      (empty_statement
        (ellipsis))
      (expression_statement
        (binary_expression
          left: (variable)
          right: (string)))))
  (function_declaration
    name: (identifier)
    (parameters)
    body: (compound_statement
      (expression_statement
        (binary_expression
          left: (variable)
          right: (string)))
      (expression_statement
        (ellipsis))
      (expression_statement
        (binary_expression
          left: (variable)
          right: (string))))))

==========================
Ellipses in binary ops and containers 
==========================

$X = 1 + 2 + ...;

$v = vec[...];
$v = vec[..., 1];
$v = vec[1, ..., 2];

$items = Vector {...};
$items = Vector {'a', ...};
$items = Vector {'a', ..., 'b'};

$items = darray['a' => 1, ...];
$items = darray[..., 'a' => 1];

$v = vec[..., "test", 1 + 2 + ...];
$v = vec[1 + 2 + ..., ...];

---

(script
  (expression_statement
    (binary_expression
      left: (variable)
      right: (binary_expression
        left: (binary_expression
          left: (integer)
          right: (integer))
        right: (ellipsis))))
  (expression_statement
    (binary_expression
      left: (variable)
      right: (array
        (array_type)
        (ellipsis))))
  (expression_statement
    (binary_expression
      left: (variable)
      right: (array
        (array_type)
        (ellipsis)
        (integer))))
  (expression_statement
    (binary_expression
      left: (variable)
      right: (array
        (array_type)
        (integer)
        (ellipsis)
        (integer))))
  (expression_statement
    (binary_expression
      left: (variable)
      right: (collection
        (qualified_identifier
          (identifier))
        (ellipsis))))
  (expression_statement
    (binary_expression
      left: (variable)
      right: (collection
        (qualified_identifier
          (identifier))
        (string)
        (ellipsis))))
  (expression_statement
    (binary_expression
      left: (variable)
      right: (collection
        (qualified_identifier
          (identifier))
        (string)
        (ellipsis)
        (string))))
  (expression_statement
    (binary_expression
      left: (variable)
      right: (array
        (array_type)
        (element_initializer
          (string)
          (integer))
        (ellipsis))))
  (expression_statement
    (binary_expression
      left: (variable)
      right: (array
        (array_type)
        (ellipsis)
        (element_initializer
          (string)
          (integer)))))
  (expression_statement
    (binary_expression
      left: (variable)
      right: (array
        (array_type)
        (ellipsis)
        (string)
        (binary_expression
          left: (binary_expression
            left: (integer)
            right: (integer))
          right: (ellipsis)))))
  (expression_statement
    (binary_expression
      left: (variable)
      right: (array
        (array_type)
        (binary_expression
          left: (binary_expression
            left: (integer)
            right: (integer))
          right: (ellipsis))
        (ellipsis)))))

==========================
Ellipses in conditionals
==========================

if (...) {
  ...
}
if (...) {
  ...
} else {
  ...
}


if (...)
  ...
if (...)
  ...;
else
  ...

---

(script
  (if_statement
    condition: (parenthesized_expression
      (ellipsis))
    body: (compound_statement
      (empty_statement
        (ellipsis))))
  (if_statement
    condition: (parenthesized_expression
      (ellipsis))
    body: (compound_statement
      (empty_statement
        (ellipsis)))
    else: (compound_statement
      (empty_statement
        (ellipsis))))
  (if_statement
    condition: (parenthesized_expression
      (ellipsis))
    body: (empty_statement
      (ellipsis)))
  (if_statement
    condition: (parenthesized_expression
      (ellipsis))
    body: (expression_statement
      (ellipsis))
    else: (empty_statement
      (ellipsis))))

==========================
Ellipses + metavariables as args
==========================

foo($...ARGS, 3, $...ARGS);

---

(script
  (expression_statement
    (call_expression
      function: (qualified_identifier
        (identifier))
      (arguments
        (argument)
        (argument
          (integer))
        (argument)))))

==========================
Metavariables as declaration identifiers
==========================

function $TEST() {
  ...
}

class $TE_ST {
}

class $F<Ta as A, Tb super B<A, C>> extends B implements A\B<A, C>, C\D {
  function $M<Ta as A, Tb super B>(): Tc {}
}

interface $X {
}

interface $INTER<Ta as A, Tb super B<A, C>> extends B, A\B<A, C>, C\D {
  function $METHOD<Ta as A, Tb super B>(): Tc {}
}


trait $_X {
}

trait $F<Ta as A, Tb super B<A, C>> implements A\B<A, C>, C\D {
}

---

(script
  (function_declaration
    name: (semgrep_identifier)
    (parameters)
    body: (compound_statement
      (empty_statement
        (ellipsis))))
  (class_declaration
    name: (semgrep_identifier)
    body: (member_declarations))
  (class_declaration
    name: (semgrep_identifier)
    (type_parameters
      (type_parameter
        name: (identifier)
        constraint_type: (type_specifier
          (qualified_identifier
            (identifier))))
      (type_parameter
        name: (identifier)
        constraint_type: (type_specifier
          (qualified_identifier
            (identifier))
          (type_arguments
            (type_specifier
              (qualified_identifier
                (identifier)))
            (type_specifier
              (qualified_identifier
                (identifier)))))))
    (extends_clause
      (type_specifier
        (qualified_identifier
          (identifier))))
    (implements_clause
      (type_specifier
        (qualified_identifier
          (identifier)
          (identifier))
        (type_arguments
          (type_specifier
            (qualified_identifier
              (identifier)))
          (type_specifier
            (qualified_identifier
              (identifier)))))
      (type_specifier
        (qualified_identifier
          (identifier)
          (identifier))))
    body: (member_declarations
      (method_declaration
        name: (semgrep_identifier)
        (type_parameters
          (type_parameter
            name: (identifier)
            constraint_type: (type_specifier
              (qualified_identifier
                (identifier))))
          (type_parameter
            name: (identifier)
            constraint_type: (type_specifier
              (qualified_identifier
                (identifier)))))
        (parameters)
        return_type: (type_specifier
          (qualified_identifier
            (identifier)))
        body: (compound_statement))))
  (interface_declaration
    name: (semgrep_identifier)
    body: (member_declarations))
  (interface_declaration
    name: (semgrep_identifier)
    (type_parameters
      (type_parameter
        name: (identifier)
        constraint_type: (type_specifier
          (qualified_identifier
            (identifier))))
      (type_parameter
        name: (identifier)
        constraint_type: (type_specifier
          (qualified_identifier
            (identifier))
          (type_arguments
            (type_specifier
              (qualified_identifier
                (identifier)))
            (type_specifier
              (qualified_identifier
                (identifier)))))))
    (extends_clause
      (type_specifier
        (qualified_identifier
          (identifier)))
      (type_specifier
        (qualified_identifier
          (identifier)
          (identifier))
        (type_arguments
          (type_specifier
            (qualified_identifier
              (identifier)))
          (type_specifier
            (qualified_identifier
              (identifier)))))
      (type_specifier
        (qualified_identifier
          (identifier)
          (identifier))))
    body: (member_declarations
      (method_declaration
        name: (semgrep_identifier)
        (type_parameters
          (type_parameter
            name: (identifier)
            constraint_type: (type_specifier
              (qualified_identifier
                (identifier))))
          (type_parameter
            name: (identifier)
            constraint_type: (type_specifier
              (qualified_identifier
                (identifier)))))
        (parameters)
        return_type: (type_specifier
          (qualified_identifier
            (identifier)))
        body: (compound_statement))))
  (trait_declaration
    name: (semgrep_identifier)
    body: (member_declarations))
  (trait_declaration
    name: (semgrep_identifier)
    (type_parameters
      (type_parameter
        name: (identifier)
        constraint_type: (type_specifier
          (qualified_identifier
            (identifier))))
      (type_parameter
        name: (identifier)
        constraint_type: (type_specifier
          (qualified_identifier
            (identifier))
          (type_arguments
            (type_specifier
              (qualified_identifier
                (identifier)))
            (type_specifier
              (qualified_identifier
                (identifier)))))))
    (implements_clause
      (type_specifier
        (qualified_identifier
          (identifier)
          (identifier))
        (type_arguments
          (type_specifier
            (qualified_identifier
              (identifier)))
          (type_specifier
            (qualified_identifier
              (identifier)))))
      (type_specifier
        (qualified_identifier
          (identifier)
          (identifier))))
    body: (member_declarations)))

==========================
Metavariables as attributes
==========================
<<$ATTR($C,), Attribute>>
function func() {
}

---

(script
  (function_declaration
    (attribute_modifier
      (qualified_identifier
        (semgrep_identifier))
      (arguments
        (argument
          (variable)))
      (qualified_identifier
        (identifier)))
    name: (identifier)
    (parameters)
    body: (compound_statement)))

==========================
Metavariables as attributes
==========================

newtype $I = int;

newtype $I as $INT = $BLAH;

---

(script
  (alias_declaration
    (semgrep_identifier)
    (type_specifier))
  (alias_declaration
    (semgrep_identifier)
    as: (type_specifier
      (qualified_identifier
        (semgrep_identifier)))
    (type_specifier
      (qualified_identifier
        (semgrep_identifier)))))

==========================
Metavariables with class declarations
==========================

class C {
  abstract const $TYPE $NAME;
  const $TYPE $NAME = A\B::C0;
  const $VAR = A\B::C0;

  const int C1 = $TEST;
  const int C2 = 1, $TEST = $TEST;


  const type $VAR;
  const type $VAR = $TYPE;
  <<A3(1), A2(2,3,)>>
  const type T3 as $VAR;
  const type T4<<<Attr>> T3> as $VAR = $VAR;
  abstract const type $VAR as ?$VAR = ?$VAR;
}

---

(script
  (class_declaration
    name: (identifier)
    body: (member_declarations
      (const_declaration
        (abstract_modifier)
        type: (type_specifier
          (qualified_identifier
            (semgrep_identifier)))
        (const_declarator
          name: (semgrep_identifier)))
      (const_declaration
        type: (type_specifier
          (qualified_identifier
            (semgrep_identifier)))
        (const_declarator
          name: (semgrep_identifier)
          value: (scoped_identifier
            (qualified_identifier
              (identifier)
              (identifier))
            (identifier))))
      (const_declaration
        (const_declarator
          name: (semgrep_identifier)
          value: (scoped_identifier
            (qualified_identifier
              (identifier)
              (identifier))
            (identifier))))
      (const_declaration
        type: (type_specifier)
        (const_declarator
          name: (identifier)
          value: (variable)))
      (const_declaration
        type: (type_specifier)
        (const_declarator
          name: (identifier)
          value: (integer))
        (const_declarator
          name: (semgrep_identifier)
          value: (variable)))
      (type_const_declaration
        name: (semgrep_identifier))
      (type_const_declaration
        name: (semgrep_identifier)
        type: (type_specifier
          (qualified_identifier
            (semgrep_identifier))))
      (type_const_declaration
        (attribute_modifier
          (qualified_identifier
            (identifier))
          (arguments
            (argument
              (integer)))
          (qualified_identifier
            (identifier))
          (arguments
            (argument
              (integer))
            (argument
              (integer))))
        name: (identifier)
        as: (type_specifier
          (qualified_identifier
            (semgrep_identifier))))
      (type_const_declaration
        name: (identifier)
        (type_parameters
          (type_parameter
            (attribute_modifier
              (qualified_identifier
                (identifier)))
            name: (identifier)))
        as: (type_specifier
          (qualified_identifier
            (semgrep_identifier)))
        type: (type_specifier
          (qualified_identifier
            (semgrep_identifier))))
      (type_const_declaration
        (abstract_modifier)
        name: (semgrep_identifier)
        as: (type_specifier
          (nullable_modifier)
          (qualified_identifier
            (semgrep_identifier)))
        type: (type_specifier
          (nullable_modifier)
          (qualified_identifier
            (semgrep_identifier)))))))

==========================
Metavariables with enums
==========================

<<$BEENUM>>
enum $E : $TYPE {
  F1 = 1;
  F2 = $VAR;
  F3 = C::CONST;
  $TESTER = $BLAH.'b';
}

---

(script
  (enum_declaration
    (attribute_modifier
      (qualified_identifier
        (semgrep_identifier)))
    name: (semgrep_identifier)
    type: (type_specifier
      (qualified_identifier
        (semgrep_identifier)))
    (enumerator
      (identifier)
      (integer))
    (enumerator
      (identifier)
      (variable))
    (enumerator
      (identifier)
      (scoped_identifier
        (qualified_identifier
          (identifier))
        (identifier)))
    (enumerator
      (semgrep_identifier)
      (binary_expression
        left: (variable)
        right: (string)))))

==========================
Capabilities and updated expression paths with patterns
==========================

class $C {
  ...
  const ctx C = [defaults];
  public function $F(..., int $X)[ctx $X]: void { ... }
}
function $F(...)[defaults]: void { foo($...ARGS, <... $X ...>); }
$x = <<<TXT
{$X->foo($...ARGS)} {$X[...]} {$X->foo(<... $Y ...>)}
TXT;
namespace\foo($...ARGS);
$x = Vector<$T> { ..., <... $X ...> };
$x = <<<TXT
{$X} {$X->foo(...)} {$X[<... $Y ...>]} {$X->$Y}
TXT;
type F = (function(): void);
type G = (function (int): void);
type H = (function /* comment */ (int)[defaults]: void);

---

(script
  (class_declaration
    name: (semgrep_identifier)
    body: (member_declarations
      (ellipsis)
      (context_const_declaration
        name: (identifier)
        context: (capability_list
          (capability
            (identifier))))
      (method_declaration
        (visibility_modifier)
        name: (semgrep_identifier)
        (parameters
          (parameter
            (ellipsis))
          (parameter
            type: (type_specifier)
            name: (variable)))
        (capability_list
          (capability
            (variable)))
        return_type: (type_specifier)
        body: (compound_statement
          (empty_statement
            (ellipsis))))))
  (function_declaration
    name: (semgrep_identifier)
    (parameters
      (variadic_modifier))
    (capability_list
      (capability
        (identifier)))
    return_type: (type_specifier)
    body: (compound_statement
      (expression_statement
        (call_expression
          function: (qualified_identifier
            (identifier))
          (arguments
            (argument)
            (argument
              (deep_ellipsis
                (variable))))))))
  (expression_statement
    (binary_expression
      left: (variable)
      right: (heredoc
        (embedded_braced_expression
          (call_expression
            function: (selection_expression
              (variable)
              (qualified_identifier
                (identifier)))
            (arguments
              (argument))))
        (embedded_braced_expression
          (subscript_expression
            (variable)
            (ellipsis)))
        (embedded_braced_expression
          (call_expression
            function: (selection_expression
              (variable)
              (qualified_identifier
                (identifier)))
            (arguments
              (argument
                (deep_ellipsis
                  (variable)))))))))
  (expression_statement
    (call_expression
      function: (qualified_identifier
        (identifier))
      (arguments
        (argument))))
  (expression_statement
    (binary_expression
      left: (variable)
      right: (collection
        (qualified_identifier
          (identifier))
        (type_arguments
          (type_specifier
            (qualified_identifier
              (semgrep_identifier))))
        (ellipsis)
        (deep_ellipsis
          (variable)))))
  (expression_statement
    (binary_expression
      left: (variable)
      right: (heredoc
        (embedded_braced_expression
          (variable))
        (embedded_braced_expression
          (call_expression
            function: (selection_expression
              (variable)
              (qualified_identifier
                (identifier)))
            (arguments
              (argument
                (ellipsis)))))
        (embedded_braced_expression
          (subscript_expression
            (variable)
            (deep_ellipsis
              (variable))))
        (embedded_braced_expression
          (selection_expression
            (variable)
            (variable))))))
  (alias_declaration
    (identifier)
    (function_type_specifier
      return_type: (type_specifier)))
  (alias_declaration
    (identifier)
    (function_type_specifier
      (type_specifier)
      return_type: (type_specifier)))
  (alias_declaration
    (identifier)
    (function_type_specifier
      (comment)
      (type_specifier)
      (capability_list
        (capability
          (identifier)))
      return_type: (type_specifier))))
