Skip to content

Commit b53a413

Browse files
committed
Improve completion for missing type
1 parent 8b3df99 commit b53a413

File tree

4 files changed

+143
-25
lines changed

4 files changed

+143
-25
lines changed

Jenkinsfile

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,15 @@ pipeline {
6969
unset JAVA_TOOL_OPTIONS
7070
unset _JAVA_OPTIONS
7171
# force qualifier to start with `z` so we identify it more easily and it always seem more recent than upstrea
72-
mvn install -X -DskipTests -Djava.io.tmpdir=$WORKSPACE/tmp \
72+
mvn install -DskipTests -Djava.io.tmpdir=$WORKSPACE/tmp -Dmaven.repo.local=$WORKSPACE/.m2/repository \
73+
-Pbree-libs \
7374
-Dtycho.buildqualifier.format="'z'yyyyMMdd-HHmm" \
7475
-Pp2-repo \
76+
-Djava.io.tmpdir=$WORKSPACE/tmp -Dproject.build.sourceEncoding=UTF-8 \
77+
-Dcbi-ecj-version=99.99 \
7578
-pl org.eclipse.jdt.core.compiler.batch,org.eclipse.jdt.core,org.eclipse.jdt.core.javac,org.eclipse.jdt.core.javac.feature,org.eclipse.jdt.core.tests.model,org.eclipse.jdt.core.tests.compiler,repository
7679
77-
mvn verify --batch-mode -f org.eclipse.jdt.core.tests.javac \
80+
mvn verify --batch-mode -f org.eclipse.jdt.core.tests.javac -Dmaven.repo.local=$WORKSPACE/.m2/repository \
7881
--fail-at-end -Ptest-on-javase-23 -Pbree-libs \
7982
-DfailIfNoTests=false -DexcludedGroups=org.junit.Ignore -DproviderHint=junit47 \
8083
-Papi-check -Djava.io.tmpdir=$WORKSPACE/tmp -Dproject.build.sourceEncoding=UTF-8 \

org.eclipse.jdt.core.javac/src/org/eclipse/jdt/internal/codeassist/DOMCompletionEngine.java

Lines changed: 59 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
import org.eclipse.jdt.core.dom.AST;
6363
import org.eclipse.jdt.core.dom.ASTNode;
6464
import org.eclipse.jdt.core.dom.ASTParser;
65+
import org.eclipse.jdt.core.dom.ASTVisitor;
6566
import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
6667
import org.eclipse.jdt.core.dom.Annotation;
6768
import org.eclipse.jdt.core.dom.AnnotationTypeMemberDeclaration;
@@ -996,7 +997,7 @@ public void complete(org.eclipse.jdt.internal.compiler.env.ICompilationUnit sour
996997
}
997998
} else if (qualifiedNameBinding instanceof IVariableBinding variableBinding) {
998999
ITypeBinding typeBinding = variableBinding.getType();
999-
if (typeBinding == null && unit.findDeclaringNode(variableBinding) instanceof VariableDeclaration decl) {
1000+
if ((typeBinding == null || typeBinding.isRecovered()) && unit.findDeclaringNode(variableBinding) instanceof VariableDeclaration decl) {
10001001
Type type = null;
10011002
if (decl instanceof SingleVariableDeclaration single) {
10021003
type = single.getType();
@@ -1577,24 +1578,66 @@ private boolean isTypeInVariableDeclaration(ASTNode context) {
15771578
}
15781579

15791580
private void completeMissingType(Type type) throws JavaModelException {
1580-
if (type instanceof ParameterizedType parameterized) {
1581-
type = parameterized.getType();
1582-
}
1583-
final Type finalType = type;
1581+
Type simpleType = type instanceof ParameterizedType parameterized ?
1582+
parameterized.getType() : type;
15841583
var scope = SearchEngine.createJavaSearchScope(new IJavaElement[] { this.javaProject });
1585-
new SearchEngine(this.workingCopyOwner).searchAllTypeNames(null, SearchPattern.R_PREFIX_MATCH, type.toString().toCharArray(), SearchPattern.R_EXACT_MATCH, IJavaSearchConstants.TYPE, scope, new TypeNameMatchRequestor() {
1584+
SearchEngine searchEngine = new SearchEngine(this.workingCopyOwner);
1585+
List<IType> types = new ArrayList<>();
1586+
searchEngine.searchAllTypeNames(null, SearchPattern.R_PREFIX_MATCH, simpleType.toString().toCharArray(), SearchPattern.R_EXACT_MATCH, IJavaSearchConstants.TYPE, scope, new TypeNameMatchRequestor() {
15861587
@Override
15871588
public void acceptTypeNameMatch(TypeNameMatch match) {
1588-
processMembers(match.getType()).stream()
1589-
.map(member -> {
1590-
CompletionProposal typeProposal = toProposal(match.getType());
1591-
typeProposal.setReplaceRange(finalType.getStartPosition(), finalType.getStartPosition() + finalType.getLength());
1592-
typeProposal.setRelevance(member.getRelevance());
1593-
member.setRequiredProposals(new CompletionProposal[] { typeProposal });
1594-
return member;
1595-
}).forEach(DOMCompletionEngine.this.requestor::accept);
1589+
types.add(match.getType());
15961590
}
15971591
}, IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH, monitor);
1592+
StringBuilder builder = new StringBuilder();
1593+
if (type instanceof ParameterizedType parameterized) {
1594+
builder.append(Signature.C_GENERIC_START);
1595+
for (Type typeParam : (List<Type>)parameterized.typeArguments()) {
1596+
builder.append(SignatureUtils.createSignature(typeParam, searchEngine, scope, monitor));
1597+
}
1598+
builder.append(Signature.C_GENERIC_END);
1599+
}
1600+
for (IType matchedType : types) {
1601+
processMembers(matchedType)
1602+
.map(member -> {
1603+
StringBuilder declaringSignature = new StringBuilder();
1604+
declaringSignature.append(member.getDeclarationSignature());
1605+
declaringSignature.deleteCharAt(declaringSignature.length() - 1); // `;`
1606+
declaringSignature.append(builder);
1607+
declaringSignature.append(';');
1608+
member.setDeclarationSignature(declaringSignature.toString().toCharArray());
1609+
CompletionProposal typeProposal = toProposal(matchedType);
1610+
typeProposal.setReplaceRange(simpleType.getStartPosition(), simpleType.getStartPosition() + simpleType.getLength());
1611+
typeProposal.setRelevance(member.getRelevance());
1612+
type.accept(new ASTVisitor() {
1613+
@Override
1614+
public boolean visit(SimpleType simpleType) {
1615+
ITypeBinding binding = simpleType.resolveBinding();
1616+
if (binding == null || binding.isRecovered()) {
1617+
List<IType> matchingITypes = new ArrayList<>();
1618+
try {
1619+
searchEngine.searchAllTypeNames(null, SearchPattern.R_PREFIX_MATCH, simpleType.toString().toCharArray(), SearchPattern.R_EXACT_MATCH, IJavaSearchConstants.TYPE, scope, new TypeNameMatchRequestor() {
1620+
@Override
1621+
public void acceptTypeNameMatch(TypeNameMatch match) {
1622+
matchingITypes.add(match.getType());
1623+
}
1624+
}, IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH, monitor);
1625+
} catch (JavaModelException ex) {
1626+
ILog.get().error(ex.getMessage(), ex);
1627+
}
1628+
if (matchingITypes.size() == 1) {
1629+
CompletionProposal typeProposal = toProposal(matchingITypes.get(0));
1630+
typeProposal.setReplaceRange(simpleType.getStartPosition(), simpleType.getStartPosition() + simpleType.getLength());
1631+
typeProposal.setRelevance(member.getRelevance());
1632+
}
1633+
}
1634+
return true;
1635+
}
1636+
});
1637+
member.setRequiredProposals(new CompletionProposal[] { typeProposal });
1638+
return member;
1639+
}).forEach(DOMCompletionEngine.this.requestor::accept);
1640+
}
15981641
}
15991642

16001643
private void suggestSuperConstructors() {
@@ -2493,7 +2536,7 @@ private void processMembers(ITypeBinding typeBinding, Bindings scope,
24932536
}
24942537
}
24952538

2496-
private List<CompletionProposal> processMembers(IType type) {
2539+
private Stream<CompletionProposal> processMembers(IType type) {
24972540
IJavaElement[] children;
24982541
try {
24992542
children = type.getChildren();
@@ -2504,8 +2547,7 @@ private List<CompletionProposal> processMembers(IType type) {
25042547
return Arrays.stream(children)
25052548
.filter(element -> element.getElementType() == IJavaElement.FIELD || element.getElementType() == IJavaElement.METHOD)
25062549
.filter(this::isVisible)
2507-
.map(this::toProposal)
2508-
.toList();
2550+
.map(this::toProposal);
25092551
}
25102552

25112553
private String getSignature(IMethodBinding method) {

org.eclipse.jdt.core.javac/src/org/eclipse/jdt/internal/codeassist/SignatureUtils.java

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,83 @@
1010
*******************************************************************************/
1111
package org.eclipse.jdt.internal.codeassist;
1212

13+
import java.util.ArrayList;
14+
import java.util.List;
15+
16+
import org.eclipse.core.runtime.ILog;
17+
import org.eclipse.core.runtime.IProgressMonitor;
1318
import org.eclipse.jdt.core.IType;
19+
import org.eclipse.jdt.core.JavaModelException;
20+
import org.eclipse.jdt.core.Signature;
21+
import org.eclipse.jdt.core.dom.ITypeBinding;
22+
import org.eclipse.jdt.core.dom.ParameterizedType;
23+
import org.eclipse.jdt.core.dom.SimpleType;
24+
import org.eclipse.jdt.core.dom.Type;
25+
import org.eclipse.jdt.core.search.IJavaSearchConstants;
26+
import org.eclipse.jdt.core.search.IJavaSearchScope;
27+
import org.eclipse.jdt.core.search.SearchEngine;
28+
import org.eclipse.jdt.core.search.SearchPattern;
29+
import org.eclipse.jdt.core.search.TypeNameMatch;
30+
import org.eclipse.jdt.core.search.TypeNameMatchRequestor;
1431

1532
public class SignatureUtils {
1633

17-
public static final String createSignature(IType type) {
34+
public static String createSignature(Type type, SearchEngine searchEngine, IJavaSearchScope scope, IProgressMonitor monitor) {
35+
ITypeBinding binding = type.resolveBinding();
36+
if (binding != null && !binding.isRecovered()) {
37+
return binding.getKey().replace('/', '.');
38+
}
39+
String simpleName = simpleName(type);
40+
IType resolvedType = binding.getJavaElement() instanceof IType element ? element : null;
41+
if (resolvedType == null || resolvedType.exists()) {
42+
List<IType> types = new ArrayList<>();
43+
try {
44+
searchEngine.searchAllTypeNames(null, SearchPattern.R_PREFIX_MATCH, simpleName.toCharArray(), SearchPattern.R_EXACT_MATCH, IJavaSearchConstants.TYPE, scope, new TypeNameMatchRequestor() {
45+
@Override
46+
public void acceptTypeNameMatch(TypeNameMatch match) {
47+
types.add(match.getType());
48+
}
49+
}, IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH, monitor);
50+
} catch (JavaModelException ex) {
51+
ILog.get().error(ex.getMessage(), ex);
52+
}
53+
if (types.size() == 1) {
54+
resolvedType = types.get(0);
55+
}
56+
}
57+
StringBuilder res = new StringBuilder();
58+
if (resolvedType != null && resolvedType.exists()) {
59+
res.append(Signature.C_RESOLVED);
60+
res.append(resolvedType.getFullyQualifiedName());
61+
} else {
62+
res.append(Signature.C_UNRESOLVED);
63+
res.append(simpleName);
64+
}
65+
if (type instanceof ParameterizedType parameterized) {
66+
res.append(Signature.C_GENERIC_START);
67+
((List<Type>)parameterized.typeArguments()).stream()
68+
.map(param -> createSignature(param, searchEngine, scope, monitor))
69+
.forEach(res::append);
70+
res.append(Signature.C_GENERIC_END);
71+
}
72+
res.append(';');
73+
return res.toString();
74+
}
75+
76+
private static String simpleName(Type type) {
77+
if (type instanceof SimpleType simple) {
78+
return simple.getName().toString();
79+
}
80+
if (type instanceof ParameterizedType parameterized) {
81+
return simpleName(parameterized.getType());
82+
}
83+
return type.toString();
84+
}
85+
86+
public static String createSignature(IType type) {
87+
return type.getKey().replace('/', '.');
88+
}
89+
public static String createSignature(ITypeBinding type) {
1890
return type.getKey().replace('/', '.');
1991
}
2092
}

org.eclipse.jdt.core.javac/src/org/eclipse/jdt/internal/javac/dom/JavacTypeBinding.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,11 @@
5252
import org.eclipse.jdt.core.dom.ITypeBinding;
5353
import org.eclipse.jdt.core.dom.IVariableBinding;
5454
import org.eclipse.jdt.core.dom.JavacBindingResolver;
55-
import org.eclipse.jdt.core.dom.JavacBindingResolver.BindingKeyException;
5655
import org.eclipse.jdt.core.dom.MethodDeclaration;
5756
import org.eclipse.jdt.core.dom.Modifier;
5857
import org.eclipse.jdt.core.dom.RecordDeclaration;
5958
import org.eclipse.jdt.core.dom.TypeDeclaration;
59+
import org.eclipse.jdt.core.dom.JavacBindingResolver.BindingKeyException;
6060
import org.eclipse.jdt.internal.compiler.codegen.ConstantPool;
6161
import org.eclipse.jdt.internal.core.BinaryType;
6262
import org.eclipse.jdt.internal.core.JavaElement;
@@ -67,9 +67,12 @@
6767
import com.sun.tools.javac.code.Attribute;
6868
import com.sun.tools.javac.code.Flags;
6969
import com.sun.tools.javac.code.Kinds;
70+
import com.sun.tools.javac.code.Symbol;
71+
import com.sun.tools.javac.code.Type;
72+
import com.sun.tools.javac.code.TypeTag;
73+
import com.sun.tools.javac.code.Types;
7074
import com.sun.tools.javac.code.Kinds.Kind;
7175
import com.sun.tools.javac.code.Kinds.KindSelector;
72-
import com.sun.tools.javac.code.Symbol;
7376
import com.sun.tools.javac.code.Symbol.ClassSymbol;
7477
import com.sun.tools.javac.code.Symbol.CompletionFailure;
7578
import com.sun.tools.javac.code.Symbol.MethodSymbol;
@@ -78,7 +81,6 @@
7881
import com.sun.tools.javac.code.Symbol.TypeSymbol;
7982
import com.sun.tools.javac.code.Symbol.TypeVariableSymbol;
8083
import com.sun.tools.javac.code.Symbol.VarSymbol;
81-
import com.sun.tools.javac.code.Type;
8284
import com.sun.tools.javac.code.Type.ArrayType;
8385
import com.sun.tools.javac.code.Type.ClassType;
8486
import com.sun.tools.javac.code.Type.ErrorType;
@@ -88,8 +90,6 @@
8890
import com.sun.tools.javac.code.Type.MethodType;
8991
import com.sun.tools.javac.code.Type.TypeVar;
9092
import com.sun.tools.javac.code.Type.WildcardType;
91-
import com.sun.tools.javac.code.TypeTag;
92-
import com.sun.tools.javac.code.Types;
9393
import com.sun.tools.javac.code.Types.FunctionDescriptorLookupError;
9494
import com.sun.tools.javac.util.Name;
9595
import com.sun.tools.javac.util.Names;
@@ -168,6 +168,7 @@ public boolean isRecovered() {
168168
return getComponentType().isRecovered();
169169
}
170170
return this.typeSymbol.kind == Kinds.Kind.ERR ||
171+
this.type.allparams().stream().anyMatch(param -> param.isErroneous()) ||
171172
(Object.class.getName().equals(this.typeSymbol.getQualifiedName().toString())
172173
&& getJavaElement() == null);
173174
}

0 commit comments

Comments
 (0)