Skip to content

Commit 47d916c

Browse files
committed
Fix lambda statement recovery in AST generated by ASTParser
Also, recover expressions as an expression statement. i.e. when there is this source in a method: ```java { ... "String".var ... ... } ``` jdt.ui expects it to be recovered like this: ```java { ... "String".var = $missing$; ... ``` Where `$missing$` is a fake, empty identifier. Currently, in some cases, the `"String".var` is being completely discarded, and this should improve that. Related to #4530 Signed-off-by: David Thompson <[email protected]>
1 parent d0da14f commit 47d916c

File tree

4 files changed

+73
-2
lines changed

4 files changed

+73
-2
lines changed

org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/Parser.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1138,6 +1138,13 @@ public RecoveredElement buildInitialRecoveryState(){
11381138
}
11391139

11401140
if (this.statementRecoveryActivated) {
1141+
if (this.expressionPtr >= 0 && this.expressionStack[0] instanceof FieldReference fr) {
1142+
var snr = new SingleNameReference(new char[0], fr.sourceEnd);
1143+
snr.sourceStart = fr.sourceEnd;
1144+
var assignment = new Assignment(fr, snr, fr.sourceEnd);
1145+
assignment.statementEnd = assignment.sourceEnd;
1146+
element = element.add(assignment, 0);
1147+
}
11411148
if (this.pendingRecoveredType != null &&
11421149
this.scanner.startPosition - 1 <= this.pendingRecoveredType.declarationSourceEnd) {
11431150
// Add the pending type to the AST if this type isn't already added in the AST.
@@ -11770,7 +11777,7 @@ protected void parse() {
1177011777
this.scanner.checkUninternedIdentityComparison = false;
1177111778
}
1177211779

11773-
if (this.reportSyntaxErrorIsRequired && this.hasError && !this.statementRecoveryActivated) {
11780+
if (this.reportSyntaxErrorIsRequired && this.hasError) {
1177411781
if(!this.options.performStatementsRecovery) {
1177511782
reportSyntaxErrors(isDietParse, oldFirstToken);
1177611783
} else {
@@ -12086,12 +12093,18 @@ public void parse(MethodDeclaration md, CompilationUnitDeclaration unit) {
1208612093
return;
1208712094

1208812095
boolean oldMethodRecoveryActivated = this.methodRecoveryActivated;
12096+
1208912097
if(this.options.performMethodsFullRecovery) {
1209012098
// we should not relocate bodyStart if there is a block within the statements
1209112099
this.ignoreNextOpeningBrace = true;
1209212100
this.methodRecoveryActivated = true;
1209312101
this.rParenPos = md.sourceEnd;
1209412102
}
12103+
boolean oldStatementRecoveryActivated = this.statementRecoveryActivated;
12104+
if (this.options.performStatementsRecovery) {
12105+
this.statementRecoveryActivated = true;
12106+
}
12107+
1209512108
initialize();
1209612109
goForBlockStatementsopt();
1209712110
this.nestedMethod[this.nestedType]++;
@@ -12108,9 +12121,12 @@ public void parse(MethodDeclaration md, CompilationUnitDeclaration unit) {
1210812121
this.lastAct = ERROR_ACTION;
1210912122
} finally {
1211012123
this.nestedMethod[this.nestedType]--;
12111-
if(this.options.performStatementsRecovery) {
12124+
if (this.options.performStatementsRecovery) {
1211212125
this.methodRecoveryActivated = oldMethodRecoveryActivated;
1211312126
}
12127+
if (this.options.performStatementsRecovery) {
12128+
this.statementRecoveryActivated = oldStatementRecoveryActivated;
12129+
}
1211412130
}
1211512131

1211612132
checkNonNLSAfterBodyEnd(md.declarationSourceEnd);

org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/dom/StandAloneASTParserTest.java

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ public void testBug529654_001() {
9292
ModuleDeclaration module = unit.getModule();
9393
assertTrue("Incorrect Module Name", module.getName().getFullyQualifiedName().equals("m"));
9494
}
95+
9596
public void test1() {
9697
String contents =
9798
"package p;\n" +
@@ -2026,4 +2027,49 @@ public static void main(String[] args) {
20262027
}
20272028
}
20282029
}
2030+
2031+
public void testGH4530_001() {
2032+
String contents =
2033+
"""
2034+
package p;
2035+
import java.util.function.Function;
2036+
public class X {
2037+
public static void main(String[] args) {
2038+
Function<Integer, Integer> myFunc = a -> a;
2039+
System.out.println("yippeeee!");
2040+
word
2041+
}
2042+
}
2043+
""";
2044+
ASTNode node = runConversion(AST_JLS_LATEST, contents, true, true, true, "p/X.java");
2045+
assertTrue("should be compilation unit", node instanceof CompilationUnit);
2046+
CompilationUnit unit = (CompilationUnit)node;
2047+
TypeDeclaration typeDecl = (TypeDeclaration)unit.types().get(0);
2048+
MethodDeclaration methodDecl = (MethodDeclaration)typeDecl.getMethods()[0];
2049+
Block block = methodDecl.getBody();
2050+
assertEquals(block.statements().size(), 2);
2051+
}
2052+
2053+
public void testGH4530_002() {
2054+
String contents =
2055+
"""
2056+
package p;
2057+
import java.util.stream.Stream;
2058+
public class X {
2059+
public static void main(String[] args) {
2060+
int a = 4;
2061+
Stream.iterate(0,i -> ++i).limit(10);
2062+
"String".var
2063+
}
2064+
}
2065+
""";
2066+
ASTNode node = runConversion(AST_JLS_LATEST, contents, true, true, true, "p/X.java");
2067+
assertTrue("should be compilation unit", node instanceof CompilationUnit);
2068+
CompilationUnit unit = (CompilationUnit)node;
2069+
TypeDeclaration typeDecl = (TypeDeclaration)unit.types().get(0);
2070+
MethodDeclaration methodDecl = (MethodDeclaration)typeDecl.getMethods()[0];
2071+
Block block = methodDecl.getBody();
2072+
assertEquals(block.statements().size(), 3);
2073+
assertTrue(block.statements().get(2) instanceof ExpressionStatement);
2074+
}
20292075
}

org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionParser.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6326,6 +6326,12 @@ protected CompilationUnitDeclaration endParse(int act) {
63266326
}
63276327
element = element.parent;
63286328
}
6329+
} else if (method.statements != null) {
6330+
// "double" recovery; base parser recovered statements and assist parser recovered the assist node
6331+
Statement[] newStatements = new Statement[method.statements.length + 1];
6332+
System.arraycopy(method.statements, 0, newStatements, 0, method.statements.length);
6333+
newStatements[method.statements.length] = statement;
6334+
method.statements = newStatements;
63296335
}
63306336
}
63316337
}

org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/AssistParser.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2070,6 +2070,8 @@ public void parseBlockStatements(MethodDeclaration md, CompilationUnitDeclaratio
20702070
if ((md.modifiers & ExtraCompilerModifiers.AccSemicolonBody) != 0)
20712071
return;
20722072

2073+
boolean oldStateRecoveryActivated = this.statementRecoveryActivated;
2074+
this.statementRecoveryActivated = true;
20732075
initialize();
20742076
// set the lastModifiers to reflect the modifiers of the method whose
20752077
// block statements are being parsed
@@ -2090,6 +2092,7 @@ public void parseBlockStatements(MethodDeclaration md, CompilationUnitDeclaratio
20902092
this.lastAct = ERROR_ACTION;
20912093
} finally {
20922094
this.nestedMethod[this.nestedType]--;
2095+
this.statementRecoveryActivated = oldStateRecoveryActivated;
20932096
}
20942097

20952098
if (this.lastAct == ERROR_ACTION) {

0 commit comments

Comments
 (0)