diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/Parser.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/Parser.java index ff0cf5c8ec4..c08f2696887 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/Parser.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/Parser.java @@ -1138,6 +1138,13 @@ public RecoveredElement buildInitialRecoveryState(){ } if (this.statementRecoveryActivated) { + if (this.expressionPtr >= 0 && this.expressionStack[0] instanceof FieldReference fr) { + var snr = new SingleNameReference(new char[0], fr.sourceEnd); + snr.sourceStart = fr.sourceEnd; + var assignment = new Assignment(fr, snr, fr.sourceEnd); + assignment.statementEnd = assignment.sourceEnd; + element = element.add(assignment, 0); + } if (this.pendingRecoveredType != null && this.scanner.startPosition - 1 <= this.pendingRecoveredType.declarationSourceEnd) { // Add the pending type to the AST if this type isn't already added in the AST. @@ -11770,7 +11777,7 @@ protected void parse() { this.scanner.checkUninternedIdentityComparison = false; } - if (this.reportSyntaxErrorIsRequired && this.hasError && !this.statementRecoveryActivated) { + if (this.reportSyntaxErrorIsRequired && this.hasError) { if(!this.options.performStatementsRecovery) { reportSyntaxErrors(isDietParse, oldFirstToken); } else { @@ -12086,12 +12093,18 @@ public void parse(MethodDeclaration md, CompilationUnitDeclaration unit) { return; boolean oldMethodRecoveryActivated = this.methodRecoveryActivated; + if(this.options.performMethodsFullRecovery) { // we should not relocate bodyStart if there is a block within the statements this.ignoreNextOpeningBrace = true; this.methodRecoveryActivated = true; this.rParenPos = md.sourceEnd; } + boolean oldStatementRecoveryActivated = this.statementRecoveryActivated; + if (this.options.performStatementsRecovery) { + this.statementRecoveryActivated = true; + } + initialize(); goForBlockStatementsopt(); this.nestedMethod[this.nestedType]++; @@ -12108,9 +12121,12 @@ public void parse(MethodDeclaration md, CompilationUnitDeclaration unit) { this.lastAct = ERROR_ACTION; } finally { this.nestedMethod[this.nestedType]--; - if(this.options.performStatementsRecovery) { + if (this.options.performStatementsRecovery) { this.methodRecoveryActivated = oldMethodRecoveryActivated; } + if (this.options.performStatementsRecovery) { + this.statementRecoveryActivated = oldStatementRecoveryActivated; + } } checkNonNLSAfterBodyEnd(md.declarationSourceEnd); diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/dom/StandAloneASTParserTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/dom/StandAloneASTParserTest.java index 286903fc58a..161d6bf3f8c 100644 --- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/dom/StandAloneASTParserTest.java +++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/dom/StandAloneASTParserTest.java @@ -92,6 +92,7 @@ public void testBug529654_001() { ModuleDeclaration module = unit.getModule(); assertTrue("Incorrect Module Name", module.getName().getFullyQualifiedName().equals("m")); } + public void test1() { String contents = "package p;\n" + @@ -2026,4 +2027,49 @@ public static void main(String[] args) { } } } + + public void testGH4530_001() { + String contents = + """ + package p; + import java.util.function.Function; + public class X { + public static void main(String[] args) { + Function myFunc = a -> a; + System.out.println("yippeeee!"); + word + } + } + """; + ASTNode node = runConversion(AST_JLS_LATEST, contents, true, true, true, "p/X.java"); + assertTrue("should be compilation unit", node instanceof CompilationUnit); + CompilationUnit unit = (CompilationUnit)node; + TypeDeclaration typeDecl = (TypeDeclaration)unit.types().get(0); + MethodDeclaration methodDecl = (MethodDeclaration)typeDecl.getMethods()[0]; + Block block = methodDecl.getBody(); + assertEquals(block.statements().size(), 2); + } + + public void testGH4530_002() { + String contents = + """ + package p; + import java.util.stream.Stream; + public class X { + public static void main(String[] args) { + int a = 4; + Stream.iterate(0,i -> ++i).limit(10); + "String".var + } + } + """; + ASTNode node = runConversion(AST_JLS_LATEST, contents, true, true, true, "p/X.java"); + assertTrue("should be compilation unit", node instanceof CompilationUnit); + CompilationUnit unit = (CompilationUnit)node; + TypeDeclaration typeDecl = (TypeDeclaration)unit.types().get(0); + MethodDeclaration methodDecl = (MethodDeclaration)typeDecl.getMethods()[0]; + Block block = methodDecl.getBody(); + assertEquals(block.statements().size(), 3); + assertTrue(block.statements().get(2) instanceof ExpressionStatement); + } } \ No newline at end of file diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionParser.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionParser.java index 55f94c26440..d976b40da67 100644 --- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionParser.java +++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionParser.java @@ -6326,6 +6326,12 @@ protected CompilationUnitDeclaration endParse(int act) { } element = element.parent; } + } else if (method.statements != null) { + // "double" recovery; base parser recovered statements and assist parser recovered the assist node + Statement[] newStatements = new Statement[method.statements.length + 1]; + System.arraycopy(method.statements, 0, newStatements, 0, method.statements.length); + newStatements[method.statements.length] = statement; + method.statements = newStatements; } } } diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/AssistParser.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/AssistParser.java index 90212ffb73c..13342ab1df5 100644 --- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/AssistParser.java +++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/impl/AssistParser.java @@ -2070,6 +2070,8 @@ public void parseBlockStatements(MethodDeclaration md, CompilationUnitDeclaratio if ((md.modifiers & ExtraCompilerModifiers.AccSemicolonBody) != 0) return; + boolean oldStateRecoveryActivated = this.statementRecoveryActivated; + this.statementRecoveryActivated = true; initialize(); // set the lastModifiers to reflect the modifiers of the method whose // block statements are being parsed @@ -2090,6 +2092,7 @@ public void parseBlockStatements(MethodDeclaration md, CompilationUnitDeclaratio this.lastAct = ERROR_ACTION; } finally { this.nestedMethod[this.nestedType]--; + this.statementRecoveryActivated = oldStateRecoveryActivated; } if (this.lastAct == ERROR_ACTION) {