Skip to content

Commit c429131

Browse files
datho7561mickaelistria
authored andcommitted
Add support for MyClass.|this completion
`ThisExpression` is it's own node, which we will need to handle differently. Should fix 2 test cases. Signed-off-by: David Thompson <[email protected]>
1 parent 1020101 commit c429131

File tree

2 files changed

+96
-5
lines changed

2 files changed

+96
-5
lines changed

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

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@
121121
import org.eclipse.jdt.core.dom.TagElement;
122122
import org.eclipse.jdt.core.dom.TextBlock;
123123
import org.eclipse.jdt.core.dom.TextElement;
124+
import org.eclipse.jdt.core.dom.ThisExpression;
124125
import org.eclipse.jdt.core.dom.Type;
125126
import org.eclipse.jdt.core.dom.TypeDeclaration;
126127
import org.eclipse.jdt.core.dom.TypePattern;
@@ -181,6 +182,7 @@ public class DOMCompletionEngine implements ICompletionEngine {
181182
private ExpectedTypes expectedTypes;
182183
private String prefix;
183184
private String qualifiedPrefix;
185+
private ITypeBinding qualifyingType;
184186
private ASTNode toComplete;
185187
private String textContent;
186188

@@ -543,6 +545,10 @@ public void complete(org.eclipse.jdt.internal.compiler.env.ICompilationUnit sour
543545
}
544546
this.qualifiedPrefix = packageName;
545547
}
548+
} else if (this.toComplete instanceof ThisExpression thisExpression) {
549+
if (thisExpression.getQualifier() != null) {
550+
this.qualifiedPrefix = thisExpression.getQualifier().toString();
551+
}
546552
}
547553
// some flags to controls different applicable completion search strategies
548554
boolean suggestDefaultCompletions = true;
@@ -1399,6 +1405,26 @@ public void complete(org.eclipse.jdt.internal.compiler.env.ICompilationUnit sour
13991405
}
14001406
suggestDefaultCompletions = false;
14011407
}
1408+
if (context instanceof ThisExpression thisExpression) {
1409+
if (thisExpression.getQualifier() != null) {
1410+
IBinding binding = thisExpression.getQualifier().resolveBinding();
1411+
if (binding instanceof ITypeBinding typeBinding) {
1412+
this.qualifyingType = typeBinding;
1413+
Bindings typesMembers = new Bindings();
1414+
processMembers(this.toComplete, typeBinding, typesMembers, true);
1415+
publishFromScope(typesMembers);
1416+
this.requestor.accept(createClassKeywordProposal(typeBinding, -1,-1));
1417+
}
1418+
for (char[] keyword : List.of(Keywords.SUPER, Keywords.THIS)) {
1419+
if (!isFailedMatch(this.prefix.toCharArray(), keyword)) {
1420+
CompletionProposal res = createKeywordProposal(keyword, -1, -1);
1421+
res.setRelevance(res.getRelevance() + RelevanceConstants.R_NON_INHERITED);
1422+
this.requestor.accept(res);
1423+
}
1424+
}
1425+
suggestDefaultCompletions = false;
1426+
}
1427+
}
14021428
if (context != null && context.getLocationInParent() == QualifiedType.NAME_PROPERTY && context.getParent() instanceof QualifiedType qType) {
14031429
Type qualifier = qType.getQualifier();
14041430
if (qualifier != null) {
@@ -2652,6 +2678,7 @@ private CompletionProposal toProposal(IBinding binding, String completion) {
26522678
this.toComplete.getAST().resolveWellKnownType(Object.class.getName()), this.expectedTypes) +
26532679
(isInQualifiedName || res.getRequiredProposals() != null || inJavadoc ? 0 : RelevanceUtils.computeRelevanceForQualification(false, this.prefix, this.qualifiedPrefix)) +
26542680
RelevanceConstants.R_NON_RESTRICTED +
2681+
RelevanceUtils.computeRelevanceForInheritance(this.qualifyingType, binding) +
26552682
((insideQualifiedReference() && !staticOnly() && !Modifier.isStatic(binding.getModifiers())) || (inJavadoc && !res.isConstructor()) ? RelevanceConstants.R_NON_STATIC : 0) +
26562683
(!staticOnly() || inheritedValue ? 0 : RelevanceConstants.R_NON_INHERITED) + // TODO: when is this active?
26572684
(binding instanceof IVariableBinding field && field.isEnumConstant() ? RelevanceConstants.R_ENUM + RelevanceConstants.R_ENUM_CONSTANT : 0)
@@ -2756,6 +2783,10 @@ private CompletionProposal toProposal(IType type) {
27562783
res.setReplaceRange(this.offset, this.offset);
27572784
} else if (this.toComplete instanceof SimpleName) {
27582785
res.setReplaceRange(this.toComplete.getStartPosition(), this.toComplete.getStartPosition() + this.toComplete.getLength());
2786+
} else if (this.toComplete instanceof ThisExpression thisExpression
2787+
&& thisExpression.getQualifier() != null
2788+
&& this.offset > (thisExpression.getQualifier().getStartPosition() + thisExpression.getQualifier().getLength())) {
2789+
setRange(res);
27592790
} else {
27602791
res.setReplaceRange(this.toComplete.getStartPosition(), this.offset);
27612792
}
@@ -2792,6 +2823,7 @@ private CompletionProposal toProposal(IType type) {
27922823
+ RelevanceConstants.R_RESOLVED
27932824
+ RelevanceConstants.R_INTERESTING
27942825
+ RelevanceConstants.R_NON_RESTRICTED
2826+
+ RelevanceUtils.computeRelevanceForInheritance(this.qualifyingType, type)
27952827
+ RelevanceUtils.computeRelevanceForQualification(!type.getFullyQualifiedName().startsWith("java.") && !nodeInImports && !fromCurrentCU && !inSamePackage && !typeIsImported, this.prefix, this.qualifiedPrefix)
27962828
+ (type.getFullyQualifiedName().startsWith("java.") ? RelevanceConstants.R_JAVA_LIBRARY : 0)
27972829
+ (expectedTypes.getExpectedTypes().stream().map(ITypeBinding::getQualifiedName).anyMatch(type.getFullyQualifiedName()::equals) ? RelevanceConstants.R_EXACT_EXPECTED_TYPE :
@@ -3511,13 +3543,21 @@ private CompletionProposal createClassKeywordProposal(ITypeBinding typeBinding,
35113543
+ RelevanceConstants.R_RESOLVED
35123544
+ RelevanceConstants.R_INTERESTING
35133545
+ RelevanceConstants.R_NON_RESTRICTED
3514-
+ RelevanceConstants.R_EXPECTED_TYPE;
3515-
if (!isFailedMatch(this.prefix.toCharArray(), Keywords.CLASS)) {
3516-
relevance += RelevanceConstants.R_SUBSTRING;
3517-
}
3546+
+ RelevanceConstants.R_NON_INHERITED
3547+
+ RelevanceUtils.computeRelevanceForCaseMatching(this.prefix.toCharArray(), Keywords.CLASS, assistOptions)
3548+
// + RelevanceUtils.computeRelevanceForExpectingType(typeBinding, this.expectedTypes)
3549+
;
3550+
35183551
DOMInternalCompletionProposal keywordProposal = createProposal(CompletionProposal.FIELD_REF);
35193552
keywordProposal.setCompletion(Keywords.CLASS);
3520-
keywordProposal.setReplaceRange(startPos, endPos);
3553+
3554+
if (startPos == -1 && endPos == -1) {
3555+
setRange(keywordProposal);
3556+
} else {
3557+
keywordProposal.setReplaceRange(startPos, endPos);
3558+
keywordProposal.setTokenRange(startPos, endPos);
3559+
}
3560+
35213561
keywordProposal.setRelevance(relevance);
35223562
keywordProposal.setPackageName(CharOperation.concatWith(TypeConstants.JAVA_LANG, '.'));
35233563
keywordProposal.setTypeName("Class".toCharArray()); //$NON-NLS-1$

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

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,15 @@
1212

1313
import java.util.Objects;
1414

15+
import org.eclipse.jdt.core.IType;
1516
import org.eclipse.jdt.core.compiler.CharOperation;
17+
import org.eclipse.jdt.core.dom.IBinding;
18+
import org.eclipse.jdt.core.dom.IMethodBinding;
1619
import org.eclipse.jdt.core.dom.ITypeBinding;
20+
import org.eclipse.jdt.core.dom.IVariableBinding;
1721
import org.eclipse.jdt.core.dom.PrimitiveType;
1822
import org.eclipse.jdt.internal.codeassist.impl.AssistOptions;
23+
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
1924

2025
/**
2126
* Helper methods for calculating the relevance numbers of completion proposals.
@@ -120,4 +125,50 @@ static int computeRelevanceForExpectingType(ITypeBinding proposalType, ExpectedT
120125
return 0;
121126
}
122127

128+
/**
129+
* Returns the appropriate relevance number based on if the given member is directly implemented in the qualifying type.
130+
*
131+
* @see CompletionEngine#computeRelevanceForInheritance(ReferenceBinding, ReferenceBinding)
132+
* @param qualifyingType the qualifying type
133+
* @param member the member to check if it's directly or indirectly inherited
134+
* @return the appropriate relevance number based on if the given member is directly implemented in the qualifying type
135+
*/
136+
static int computeRelevanceForInheritance(ITypeBinding qualifyingType, IBinding member) {
137+
if (qualifyingType == null) {
138+
return 0;
139+
}
140+
if (member instanceof IMethodBinding methodBinding) {
141+
if (methodBinding.getDeclaringClass().getKey().equals(qualifyingType.getKey())) {
142+
return RelevanceConstants.R_NON_INHERITED;
143+
}
144+
} else if (member instanceof IVariableBinding varBinding) {
145+
if (varBinding.getDeclaringClass().getKey().equals(qualifyingType.getKey())) {
146+
return RelevanceConstants.R_NON_INHERITED;
147+
}
148+
} else if (member instanceof ITypeBinding typeBinding) {
149+
if (typeBinding.getDeclaringClass().getKey().equals(qualifyingType.getKey())) {
150+
return RelevanceConstants.R_NON_INHERITED;
151+
}
152+
}
153+
return 0;
154+
}
155+
156+
/**
157+
* Returns the appropriate relevance number based on if the given member type is directly implemented in the qualifying type.
158+
*
159+
* @see CompletionEngine#computeRelevanceForInheritance(ReferenceBinding, ReferenceBinding)
160+
* @param qualifyingType the qualifying type
161+
* @param memberType the member type to check if it's directly or indirectly inherited
162+
* @return the appropriate relevance number based on if the given member is directly implemented in the qualifying type
163+
*/
164+
static int computeRelevanceForInheritance(ITypeBinding qualifyingType, IType memberType) {
165+
if (qualifyingType == null || memberType.getDeclaringType() == null) {
166+
return 0;
167+
}
168+
if (memberType.getDeclaringType().getKey().equals(qualifyingType.getKey())) {
169+
return RelevanceConstants.R_NON_INHERITED;
170+
}
171+
return 0;
172+
}
173+
123174
}

0 commit comments

Comments
 (0)