In this playground, the last statement is always ignored and not captured. Why is this?
Test C++ code:
A::A()
: base::Class(a, b, c) {
a;
b;
c;
}
Test rules:
id: testbase_initializer
language: CPP
rule:
pattern:
selector: compound_statement
context: "A::A() : foo() { $$$BODYSTUFF }"
fix: |-
{
f();
$$$BODYSTUFF;
}
Captured by BODYSTUFF
: a;b;
. But c;
is not in it. Why? For reference, the unreduced testcase is this:
id: testbase_initializer
language: CPP
rule:
pattern:
selector: compound_statement
context: "A::A() : foo() { $$$BODYSTUFF }"
follows:
kind: field_initializer_list
has:
pattern:
selector: field_initializer
context: "A::A() : TestBase($NAME, $DETAILS, $ID) { }"
fix: |-
{
setName($NAME);
setId($ID);
$$$BODYSTUFF
}
And it was intended to move part of the base class initializer into the body. But the fix always discarded the last body statement!
This is a tricky issue of tree-sitter parser.
{ $$$A }
is not a valid syntax in CPP, as you can see in the attachment. (Note the show full tree option is toggled on).
While ast-grep recommends pattern should be valid syntax, it is permissive for the pattern and will try its best to perform reasonable matching.
$$$BODYSTUFF
will be parsed as type_identifier
and a missing ;
. So the last statement is wrongly matched into the missing semicolon, and is left out in the capturing.
A workaround for now is using shorter variable name like $$$B
to make tree-sitter parse it as one single ERROR
node.