From b6b5453229368ef6205202ca3d3f0ea525dcf07a Mon Sep 17 00:00:00 2001 From: Snjezana Peco Date: Mon, 23 Oct 2023 16:09:27 +0200 Subject: [PATCH] Completion for unimported types doesn't work --- .../core/tests/model/CompletionTests18.java | 68 +++++++++++++++++++ .../internal/codeassist/CompletionEngine.java | 44 ++++++++---- .../codeassist/MissingTypesGuesser.java | 16 ++++- .../complete/CompletionOnMemberAccess.java | 6 +- 4 files changed, 118 insertions(+), 16 deletions(-) diff --git a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests18.java b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests18.java index 99159252402..ec71b7127f0 100644 --- a/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests18.java +++ b/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests18.java @@ -7039,4 +7039,72 @@ public static GH979List newInstance() { + (R_DEFAULT + R_RESOLVED + R_INTERESTING + R_CASE + R_UNQUALIFIED + R_NON_RESTRICTED) + "}", result); } + +public void testGH1502() throws JavaModelException { + this.workingCopies = new ICompilationUnit[1]; + this.workingCopies[0] = getWorkingCopy("/Completion/src/X.java", """ + public class X { + void foo() { + new ArrayList<>(). + } + } + """); + + CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(true); + requestor.allowAllRequiredProposals(); + + String str = this.workingCopies[0].getSource(); + String completeBehind = "ArrayList<>()."; + int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.length(); + this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner, new NullProgressMonitor()); + + String result = requestor.getResults(); + assertResults( + "add[METHOD_REF]{add(), Ljava.util.ArrayList<>;, (ITE;)V, add, (arg0, arg1), 61}\n" + + "add[METHOD_REF]{add(), Ljava.util.ArrayList<>;, (TE;)Z, add, (arg0), 61}\n" + + "addAll[METHOD_REF]{addAll(), Ljava.util.ArrayList<>;, (ILjava.util.Collection<+TE;>;)Z, addAll, (arg0, arg1), 61}\n" + + "addAll[METHOD_REF]{addAll(), Ljava.util.ArrayList<>;, (Ljava.util.Collection<+TE;>;)Z, addAll, (arg0), 61}\n" + + "clear[METHOD_REF]{clear(), Ljava.util.ArrayList<>;, ()V, clear, null, 61}\n" + + "clone[METHOD_REF]{clone(), Ljava.util.ArrayList<>;, ()Ljava.lang.Object;, clone, null, 61}\n" + + "contains[METHOD_REF]{contains(), Ljava.util.ArrayList<>;, (Ljava.lang.Object;)Z, contains, (arg0), 61}\n" + + "containsAll[METHOD_REF]{containsAll(), Ljava.util.List;, (Ljava.util.Collection<*>;)Z, containsAll, (arg0), 61}\n" + + "ensureCapacity[METHOD_REF]{ensureCapacity(), Ljava.util.ArrayList<>;, (I)V, ensureCapacity, (arg0), 61}\n" + + "equals[METHOD_REF]{equals(), Ljava.util.List;, (Ljava.lang.Object;)Z, equals, (arg0), 61}\n" + + "finalize[METHOD_REF]{finalize(), Ljava.lang.Object;, ()V, finalize, null, 61}\n" + + "forEach[METHOD_REF]{forEach(), Ljava.util.ArrayList<>;, (Ljava.util.function.Consumer<-TE;>;)V, forEach, (arg0), 61}\n" + + "get[METHOD_REF]{get(), Ljava.util.ArrayList<>;, (I)TE;, get, (arg0), 61}\n" + + "getClass[METHOD_REF]{getClass(), Ljava.lang.Object;, ()Ljava.lang.Class<*>;, getClass, null, 61}\n" + + "hashCode[METHOD_REF]{hashCode(), Ljava.util.List;, ()I, hashCode, null, 61}\n" + + "indexOf[METHOD_REF]{indexOf(), Ljava.util.ArrayList<>;, (Ljava.lang.Object;)I, indexOf, (arg0), 61}\n" + + "isEmpty[METHOD_REF]{isEmpty(), Ljava.util.ArrayList<>;, ()Z, isEmpty, null, 61}\n" + + "iterator[METHOD_REF]{iterator(), Ljava.util.ArrayList<>;, ()Ljava.util.Iterator;, iterator, null, 61}\n" + + "lastIndexOf[METHOD_REF]{lastIndexOf(), Ljava.util.ArrayList<>;, (Ljava.lang.Object;)I, lastIndexOf, (arg0), 61}\n" + + "listIterator[METHOD_REF]{listIterator(), Ljava.util.ArrayList<>;, ()Ljava.util.ListIterator;, listIterator, null, 61}\n" + + "listIterator[METHOD_REF]{listIterator(), Ljava.util.ArrayList<>;, (I)Ljava.util.ListIterator;, listIterator, (arg0), 61}\n" + + "modCount[FIELD_REF]{modCount, Ljava.util.AbstractList;, I, modCount, null, 61}\n" + + "notify[METHOD_REF]{notify(), Ljava.lang.Object;, ()V, notify, null, 61}\n" + + "notifyAll[METHOD_REF]{notifyAll(), Ljava.lang.Object;, ()V, notifyAll, null, 61}\n" + + "parallelStream[METHOD_REF]{parallelStream(), Ljava.util.Collection;, ()Ljava.util.stream.Stream;, parallelStream, null, 61}\n" + + "remove[METHOD_REF]{remove(), Ljava.util.ArrayList<>;, (I)TE;, remove, (arg0), 61}\n" + + "remove[METHOD_REF]{remove(), Ljava.util.ArrayList<>;, (Ljava.lang.Object;)Z, remove, (arg0), 61}\n" + + "removeAll[METHOD_REF]{removeAll(), Ljava.util.ArrayList<>;, (Ljava.util.Collection<*>;)Z, removeAll, (arg0), 61}\n" + + "removeIf[METHOD_REF]{removeIf(), Ljava.util.ArrayList<>;, (Ljava.util.function.Predicate<-TE;>;)Z, removeIf, (arg0), 61}\n" + + "removeRange[METHOD_REF]{removeRange(), Ljava.util.ArrayList<>;, (II)V, removeRange, (arg0, arg1), 61}\n" + + "replaceAll[METHOD_REF]{replaceAll(), Ljava.util.ArrayList<>;, (Ljava.util.function.UnaryOperator;)V, replaceAll, (arg0), 61}\n" + + "retainAll[METHOD_REF]{retainAll(), Ljava.util.ArrayList<>;, (Ljava.util.Collection<*>;)Z, retainAll, (arg0), 61}\n" + + "set[METHOD_REF]{set(), Ljava.util.ArrayList<>;, (ITE;)TE;, set, (arg0, arg1), 61}\n" + + "size[METHOD_REF]{size(), Ljava.util.ArrayList<>;, ()I, size, null, 61}\n" + + "sort[METHOD_REF]{sort(), Ljava.util.ArrayList<>;, (Ljava.util.Comparator<-TE;>;)V, sort, (arg0), 61}\n" + + "spliterator[METHOD_REF]{spliterator(), Ljava.util.ArrayList<>;, ()Ljava.util.Spliterator;, spliterator, null, 61}\n" + + "stream[METHOD_REF]{stream(), Ljava.util.Collection;, ()Ljava.util.stream.Stream;, stream, null, 61}\n" + + "subList[METHOD_REF]{subList(), Ljava.util.ArrayList<>;, (II)Ljava.util.List;, subList, (arg0, arg1), 61}\n" + + "toArray[METHOD_REF]{toArray(), Ljava.util.ArrayList<>;, ()[Ljava.lang.Object;, toArray, null, 61}\n" + + "toArray[METHOD_REF]{toArray(), Ljava.util.ArrayList<>;, ([TT;)[TT;, toArray, (arg0), 61}\n" + + "toString[METHOD_REF]{toString(), Ljava.util.AbstractCollection;, ()Ljava.lang.String;, toString, null, 61}\n" + + "trimToSize[METHOD_REF]{trimToSize(), Ljava.util.ArrayList<>;, ()V, trimToSize, null, 61}\n" + + "wait[METHOD_REF]{wait(), Ljava.lang.Object;, ()V, wait, null, 61}\n" + + "wait[METHOD_REF]{wait(), Ljava.lang.Object;, (J)V, wait, (millis), 61}\n" + + "wait[METHOD_REF]{wait(), Ljava.lang.Object;, (JI)V, wait, (millis, nanos), 61}", + result); +} } diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java index 2da9e42072d..3b59652335f 100644 --- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java +++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java @@ -3176,23 +3176,39 @@ private void completionOnMemberAccess(ASTNode astNode, ASTNode enclosingNode, Bi this.completionToken = access.token; if (qualifiedBinding.problemId() == ProblemReasons.NotFound) { - // complete method members with missing return type - // class X { - // Missing f() {return null;} - // void foo() { - // f().| - // } - // } if (this.assistNodeInJavadoc == 0 && (this.requestor.isAllowingRequiredProposals(CompletionProposal.FIELD_REF, CompletionProposal.TYPE_REF) || this.requestor.isAllowingRequiredProposals(CompletionProposal.METHOD_REF, CompletionProposal.TYPE_REF))) { - ProblemMethodBinding problemMethodBinding = (ProblemMethodBinding) qualifiedBinding; - findFieldsAndMethodsFromMissingReturnType( - problemMethodBinding.selector, - problemMethodBinding.parameters, - scope, - access, - insideTypeAnnotation); + if (qualifiedBinding instanceof ProblemMethodBinding) { + // complete method members with missing return type + // class X { + // Missing f() {return null;} + // void foo() { + // f().| + // } + // } + ProblemMethodBinding problemMethodBinding = (ProblemMethodBinding) qualifiedBinding; + findFieldsAndMethodsFromMissingReturnType(problemMethodBinding.selector, + problemMethodBinding.parameters, scope, access, insideTypeAnnotation); + } else if (access.receiver instanceof AllocationExpression expr) { + // complete on missing type + // class X { + // void foo() { + // new ArrayList().| + // } + // } + TypeReference type = expr.type; + char[] token = null; + if (type instanceof SingleTypeReference ref) { + token = ref.token; + } + if (type instanceof QualifiedTypeReference ref) { + token = ref.tokens[0]; + } + if (token != null) { + findFieldsAndMethodsFromMissingType(type, scope, access, scope); + } + } } } else { if (!access.isInsideAnnotation) { diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/MissingTypesGuesser.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/MissingTypesGuesser.java index e2bf7d336fa..1fd858fb7b7 100644 --- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/MissingTypesGuesser.java +++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/MissingTypesGuesser.java @@ -20,7 +20,15 @@ import org.eclipse.jdt.core.compiler.CharOperation; import org.eclipse.jdt.core.search.IJavaSearchConstants; import org.eclipse.jdt.internal.compiler.ASTVisitor; -import org.eclipse.jdt.internal.compiler.ast.*; +import org.eclipse.jdt.internal.compiler.ast.ASTNode; +import org.eclipse.jdt.internal.compiler.ast.ArrayQualifiedTypeReference; +import org.eclipse.jdt.internal.compiler.ast.ArrayTypeReference; +import org.eclipse.jdt.internal.compiler.ast.ParameterizedQualifiedTypeReference; +import org.eclipse.jdt.internal.compiler.ast.ParameterizedSingleTypeReference; +import org.eclipse.jdt.internal.compiler.ast.QualifiedTypeReference; +import org.eclipse.jdt.internal.compiler.ast.SingleTypeReference; +import org.eclipse.jdt.internal.compiler.ast.TypeReference; +import org.eclipse.jdt.internal.compiler.ast.Wildcard; import org.eclipse.jdt.internal.compiler.env.AccessRestriction; import org.eclipse.jdt.internal.compiler.lookup.Binding; import org.eclipse.jdt.internal.compiler.lookup.BlockScope; @@ -340,6 +348,9 @@ private TypeReference convert(ParameterizedQualifiedTypeReference typeRef) { this.substituedTypes.put(convertedType, typeNames); this.originalTypes.put(convertedType, typeName); this.combinationsCount *= typeNames.length; + if (length > 0 && typeArguments[length - 1] == TypeReference.NO_TYPE_ARGUMENTS) { + convertedType.bits |= ASTNode.IsDiamond; + } return convertedType; } } @@ -385,6 +396,9 @@ private TypeReference convert(ParameterizedSingleTypeReference typeRef) { this.substituedTypes.put(convertedType, typeNames); this.originalTypes.put(convertedType, typeName); this.combinationsCount *= typeNames.length; + if (typeArguments == TypeReference.NO_TYPE_ARGUMENTS) { + convertedType.bits |= ASTNode.IsDiamond; + } return convertedType; } } diff --git a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnMemberAccess.java b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnMemberAccess.java index 14ef87464b4..b2a07868eb8 100644 --- a/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnMemberAccess.java +++ b/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnMemberAccess.java @@ -81,8 +81,12 @@ public TypeBinding resolveType(BlockScope scope) { } } - if (this.actualReceiverType == null || !this.actualReceiverType.isValidBinding()) + if (this.actualReceiverType == null || !this.actualReceiverType.isValidBinding()) { + if (this.receiver.resolvedType != null && this.receiver.resolvedType.problemId() == ProblemReasons.NotFound) { + throw new CompletionNodeFound(this, this.receiver.resolvedType, scope); + } throw new CompletionNodeFound(); + } else throw new CompletionNodeFound(this, this.actualReceiverType, scope); // array types are passed along to find the length field