diff --git a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/RecoveredMethod.java b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/RecoveredMethod.java index 39e24a20eeb..259b903aadd 100644 --- a/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/RecoveredMethod.java +++ b/org.eclipse.jdt.core.compiler.batch/src/org/eclipse/jdt/internal/compiler/parser/RecoveredMethod.java @@ -97,6 +97,10 @@ public RecoveredElement add(Block nestedBlockDeclaration, int bracketBalanceValu */ @Override public RecoveredElement add(FieldDeclaration fieldDeclaration, int bracketBalanceValue) { + if (recoverAsArgument(fieldDeclaration)) { + resetPendingModifiers(); + return this; + } resetPendingModifiers(); /* local variables inside method can only be final and non void */ @@ -133,6 +137,27 @@ public RecoveredElement add(FieldDeclaration fieldDeclaration, int bracketBalanc // still inside method, treat as local variable return this; // ignore } + +private boolean recoverAsArgument(FieldDeclaration fieldDeclaration) { + if (!this.foundOpeningBrace + && this.methodDeclaration.declarationSourceEnd == 0 + && this.methodDeclaration.arguments == null) { // misparsed parameter? + long position = ((long) fieldDeclaration.sourceStart << 32)+fieldDeclaration.sourceEnd; + Argument arg = new Argument(fieldDeclaration.name, position, fieldDeclaration.type, fieldDeclaration.modifiers); + this.methodDeclaration.arguments = new Argument[] { arg }; + int annotCount = this.pendingAnnotationCount; + if (this.pendingAnnotations != null) { + arg.annotations = new Annotation[annotCount]; + for (int i = 0; i < this.pendingAnnotationCount; i++) { + arg.annotations[i] = this.pendingAnnotations[i].annotation; + if (i == 0) + arg.declarationSourceStart = arg.annotations[i].sourceStart; + } + } + return true; + } + return false; +} /* * Record a local declaration - regular method should have been created a block body */ diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterRecoveryTest.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterRecoveryTest.java index a85e51425c1..b99b017b2c0 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterRecoveryTest.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/dom/ASTConverterRecoveryTest.java @@ -1085,4 +1085,39 @@ public void test0021() throws JavaModelException { List statements = block.statements(); assertEquals("wrong size", 0, statements.size()); //$NON-NLS-1$ } + + public void testGH3155() throws JavaModelException { + this.workingCopies = new ICompilationUnit[1]; + this.workingCopies[0] = getWorkingCopy( + "/Converter18/src/test/TestDependsOnClass.java", + """ + package test; + public class TestDependsOnClass { + public TestDependsOnClass(@Qualifier(value= ) Object mybean) { } + } + """); + ASTNode result = runConversion(getJLS8(), this.workingCopies[0], true, true); + + assertASTNodeEquals( + """ + package test; + public class TestDependsOnClass { + public TestDependsOnClass( @Qualifier(value=$missing$) Object mybean){ + } + } + """, + result); + + ASTNode node = getASTNode((CompilationUnit) result, 0, 0); + assertNotNull(node); + assertTrue("Not a method declaration", node.getNodeType() == ASTNode.METHOD_DECLARATION); //$NON-NLS-1$ + MethodDeclaration methodDeclaration = (MethodDeclaration) node; + assertTrue(methodDeclaration.isConstructor()); + assertEquals(1, methodDeclaration.parameters().size()); + SingleVariableDeclaration param = (SingleVariableDeclaration) methodDeclaration.parameters().get(0); + assertEquals(1, param.modifiers().size()); + IExtendedModifier mod = (IExtendedModifier) param.modifiers().get(0); + assertTrue(mod.isAnnotation()); + assertEquals("Qualifier", ((Annotation) mod).getTypeName().toString()); + } }