diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests3.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests3.java index 6678fbb9c49..c343bb07bf1 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests3.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests3.java @@ -1553,4 +1553,55 @@ public void testBug575631_comment3d() throws Exception { deleteProject("P"); } } +public void testGH1440() throws Exception { + try { + createJavaProject("P", new String[] {"src"}, new String[]{"JCL11_LIB"}, "bin", "11"); + this.workingCopies = new ICompilationUnit[3]; + this.workingCopies[0] = getWorkingCopy( + "/P/src/test/Aspect.java", + """ + package test; + + import java.lang.annotation.*; + + @Documented + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.TYPE) + public @interface Aspect { + String id() default ""; + String[] fetch() default {}; + } + """); + this.workingCopies[1] = getWorkingCopy( + "/P/src/test/Constants.java", + """ + package test; + public class Constants { + public static final class Group1 { + public static final String val1 = "val1"; + } + public static final class Group2 { + public static final String val2 = "val2"; + } + } + """); + this.workingCopies[2] = getWorkingCopy( + "/P/src/test/Member.java", + """ + package test; + + @Aspect(id = "test", fetch = { Constants.Group1.val + "." + Constants.Group2.val2 }) + public class Member { } + """); + CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true); + String str = this.workingCopies[2].getSource(); + String completeAfter = ".val"; + int cursorLocation = str.indexOf(completeAfter) + completeAfter.length(); + this.workingCopies[2].codeComplete(cursorLocation, requestor, this.wcOwner); + assertResults("val1[FIELD_REF]{val1, Ltest.Constants$Group1;, Ljava.lang.String;, val1, null, 81}", + requestor.getResults()); + } finally { + deleteProject("P"); + } +} } diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnQualifiedNameReference.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnQualifiedNameReference.java index 8d530377965..5acbfadb29e 100644 --- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnQualifiedNameReference.java +++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnQualifiedNameReference.java @@ -37,6 +37,7 @@ */ import org.eclipse.jdt.internal.compiler.ast.*; +import org.eclipse.jdt.internal.compiler.impl.Constant; import org.eclipse.jdt.internal.compiler.lookup.*; public class CompletionOnQualifiedNameReference extends QualifiedNameReference implements CompletionNode { @@ -77,8 +78,16 @@ public TypeBinding resolveType(BlockScope scope) { throw new CompletionNodeFound(); } - - // probably not in the position to do useful resolution, just provide some binding - return new CompletionNodeFound(this, this.binding, scope).throwOrDeferAndReturn(() -> (this.resolvedType = new ProblemReferenceBinding(this.tokens, null, ProblemReasons.NotFound))); + + return new CompletionNodeFound(this, this.binding, scope).throwOrDeferAndReturn(() -> { + // probably not in the position to do useful resolution, just provide some binding + // but perform minimal setup so downstream resolving doesn't throw exceptions: + this.constant = Constant.NotAConstant; + if ((this.bits & Binding.FIELD) != 0) + this.binding = new ProblemFieldBinding( + this.binding instanceof ReferenceBinding ? (ReferenceBinding) this.binding : null, + this.completionIdentifier, ProblemReasons.NotFound); + return this.resolvedType = new ProblemReferenceBinding(this.tokens, null, ProblemReasons.NotFound); + }); } }