Skip to content

Commit 82c0364

Browse files
datho7561mickaelistria
authored andcommitted
[WIP] Handle IAccessRules in completion
- hide types from other projects that are marked as inaccessible from completion (unless the appropriate settings to allow them to be completed are enabled) - relevance numbers for those types TODO: - [ ] clean up the code, add comments, etc. Signed-off-by: David Thompson <[email protected]>
1 parent 9dd4b56 commit 82c0364

File tree

2 files changed

+104
-57
lines changed

2 files changed

+104
-57
lines changed

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

Lines changed: 77 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import org.eclipse.jdt.core.CompletionProposal;
4444
import org.eclipse.jdt.core.CompletionRequestor;
4545
import org.eclipse.jdt.core.Flags;
46+
import org.eclipse.jdt.core.IAccessRule;
4647
import org.eclipse.jdt.core.IAnnotation;
4748
import org.eclipse.jdt.core.ICompilationUnit;
4849
import org.eclipse.jdt.core.IField;
@@ -96,6 +97,7 @@
9697
import org.eclipse.jdt.core.dom.IfStatement;
9798
import org.eclipse.jdt.core.dom.ImportDeclaration;
9899
import org.eclipse.jdt.core.dom.InfixExpression;
100+
import org.eclipse.jdt.core.dom.InfixExpression.Operator;
99101
import org.eclipse.jdt.core.dom.Initializer;
100102
import org.eclipse.jdt.core.dom.InstanceofExpression;
101103
import org.eclipse.jdt.core.dom.Javadoc;
@@ -107,6 +109,7 @@
107109
import org.eclipse.jdt.core.dom.MethodInvocation;
108110
import org.eclipse.jdt.core.dom.MethodRef;
109111
import org.eclipse.jdt.core.dom.Modifier;
112+
import org.eclipse.jdt.core.dom.Modifier.ModifierKeyword;
110113
import org.eclipse.jdt.core.dom.ModuleDeclaration;
111114
import org.eclipse.jdt.core.dom.Name;
112115
import org.eclipse.jdt.core.dom.NodeFinder;
@@ -147,8 +150,6 @@
147150
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
148151
import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
149152
import org.eclipse.jdt.core.dom.WhileStatement;
150-
import org.eclipse.jdt.core.dom.InfixExpression.Operator;
151-
import org.eclipse.jdt.core.dom.Modifier.ModifierKeyword;
152153
import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants;
153154
import org.eclipse.jdt.core.search.IJavaSearchConstants;
154155
import org.eclipse.jdt.core.search.IJavaSearchScope;
@@ -814,15 +815,15 @@ public void complete(org.eclipse.jdt.internal.compiler.env.ICompilationUnit sour
814815
if (!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) {
815816
findTypes(this.prefix, null)
816817
// don't care about annotations
817-
.filter(type -> {
818+
.filter(typeMatch -> {
818819
try {
819-
return !type.isAnnotation();
820+
return !typeMatch.getType().isAnnotation();
820821
} catch (JavaModelException e) {
821822
return true;
822823
}
823-
}).filter(type -> defaultCompletionBindings.all().map(typeBinding -> typeBinding.getJavaElement()).noneMatch(elt -> type.equals(elt)))
824-
.filter(type -> this.pattern.matchesName(this.prefix.toCharArray(), type.getElementName().toCharArray()))
825-
.filter(type -> filterBasedOnExtendsOrImplementsInfo(type, this.extendsOrImplementsInfo))
824+
}).filter(typeMatch -> defaultCompletionBindings.all().map(typeBinding -> typeBinding.getJavaElement()).noneMatch(elt -> typeMatch.getType().equals(elt)))
825+
.filter(typeMatch -> this.pattern.matchesName(this.prefix.toCharArray(), typeMatch.getType().getElementName().toCharArray()))
826+
.filter(typeMatch -> filterBasedOnExtendsOrImplementsInfo(typeMatch.getType(), this.extendsOrImplementsInfo))
826827
.map(this::toProposal)
827828
.forEach(this.requestor::accept);
828829
}
@@ -936,13 +937,13 @@ public void complete(org.eclipse.jdt.internal.compiler.env.ICompilationUnit sour
936937
if (context.getParent() instanceof SimpleType simpleType && simpleType.getParent() instanceof MethodDeclaration
937938
&& simpleType.getLocationInParent().getId().equals(MethodDeclaration.THROWN_EXCEPTION_TYPES_PROPERTY.getId())) {
938939
findTypes(completeAfter, null)
939-
.filter(type -> this.pattern.matchesName(this.prefix.toCharArray(),
940-
type.getElementName().toCharArray()))
940+
.filter(typeMatch -> this.pattern.matchesName(this.prefix.toCharArray(),
941+
typeMatch.getType().getElementName().toCharArray()))
941942
// ideally we should filter out all classes that don't descend from Throwable
942943
// however JDT doesn't do this yet from what I can tell
943-
.filter(type -> {
944+
.filter(typeMatch -> {
944945
try {
945-
return !type.isAnnotation() && !type.isInterface();
946+
return !typeMatch.getType().isAnnotation() && !typeMatch.getType().isInterface();
946947
} catch (JavaModelException e) {
947948
return true;
948949
}
@@ -1003,8 +1004,7 @@ public void complete(org.eclipse.jdt.internal.compiler.env.ICompilationUnit sour
10031004
topLevelTypes(typeCompletionBindings);
10041005
typeCompletionBindings.all()
10051006
.filter(ITypeBinding.class::isInstance)
1006-
.map(typeBinding -> (IType)typeBinding.getJavaElement())
1007-
.filter(type -> filterBasedOnExtendsOrImplementsInfo(type, this.extendsOrImplementsInfo))
1007+
.filter(typeBinding -> filterBasedOnExtendsOrImplementsInfo((IType) typeBinding.getJavaElement(), this.extendsOrImplementsInfo))
10081008
.map(this::toProposal)
10091009
.forEach(this.requestor::accept);
10101010
} else {
@@ -1260,7 +1260,7 @@ public void complete(org.eclipse.jdt.internal.compiler.env.ICompilationUnit sour
12601260
publishFromScope(specificCompletionBindings);
12611261
} else {
12621262
// UnimportedType.|
1263-
List<IType> foundTypes = findTypes(qualifiedName.getQualifier().toString(), null).toList();
1263+
List<IType> foundTypes = findTypes(qualifiedName.getQualifier().toString(), null).map(TypeNameMatch::getType).toList();
12641264
// HACK: We requested exact matches from the search engine but some results aren't exact
12651265
foundTypes = foundTypes.stream().filter(type -> type.getElementName().equals(qualifiedName.getQualifier().toString())).toList();
12661266
if (!foundTypes.isEmpty()) {
@@ -1391,18 +1391,18 @@ public void complete(org.eclipse.jdt.internal.compiler.env.ICompilationUnit sour
13911391
packageName = packageDecl.getName().toString();
13921392
}
13931393
this.findTypes(this.prefix, packageName)
1394-
.filter(type -> {
1394+
.filter(typeMatch -> {
13951395
try {
1396-
return !type.isAnnotation();
1396+
return !typeMatch.getType().isAnnotation();
13971397
} catch (JavaModelException e) {
13981398
return true;
13991399
}
14001400
}) //
1401-
.flatMap(type -> {
1401+
.flatMap(typeMatch -> {
14021402
if (this.prefix.isEmpty()) {
1403-
return Stream.of(toProposal(type));
1403+
return Stream.of(toProposal(typeMatch.getType()));
14041404
} else {
1405-
return toConstructorProposals(type, this.toComplete, false).stream();
1405+
return toConstructorProposals(typeMatch.getType(), this.toComplete, false).stream();
14061406
}
14071407
}) //
14081408
.forEach(this.requestor::accept);
@@ -1532,7 +1532,7 @@ public void complete(org.eclipse.jdt.internal.compiler.env.ICompilationUnit sour
15321532
packageName = ""; //$NON-NLS-1$
15331533
}
15341534
}
1535-
List<IType> potentialTypes = findTypes(classToComplete, packageName).toList();
1535+
List<IType> potentialTypes = findTypes(classToComplete, packageName).map(TypeNameMatch::getType).toList();
15361536
List<IType> sourceTypes = potentialTypes.stream().filter(type -> type instanceof SourceType).toList();
15371537
if (!potentialTypes.isEmpty()) {
15381538
IType typeToComplete;
@@ -1582,10 +1582,10 @@ public void complete(org.eclipse.jdt.internal.compiler.env.ICompilationUnit sour
15821582
.map(this::toProposal).forEach(this.requestor::accept);
15831583

15841584
findTypes(completeAfter, completeAfter.equals(this.qualifiedPrefix) ? null : this.qualifiedPrefix)
1585-
.filter(type -> {
1586-
return localTypeBindings.all().map(typeBinding -> typeBinding.getJavaElement()).noneMatch(elt -> type.equals(elt));
1585+
.filter(typeMatch -> {
1586+
return localTypeBindings.all().map(typeBinding -> typeBinding.getJavaElement()).noneMatch(elt -> typeMatch.getType().equals(elt));
15871587
})
1588-
.filter(type -> this.pattern.matchesName(this.prefix.toCharArray(), type.getElementName().toCharArray()))
1588+
.filter(typeMatch -> this.pattern.matchesName(this.prefix.toCharArray(), typeMatch.getType().getElementName().toCharArray()))
15891589
.map(this::toProposal).forEach(this.requestor::accept);
15901590

15911591
suggestDefaultCompletions = false;
@@ -1708,7 +1708,7 @@ public void complete(org.eclipse.jdt.internal.compiler.env.ICompilationUnit sour
17081708
packageName = ""; //$NON-NLS-1$
17091709
}
17101710
}
1711-
List<IType> potentialTypes = findTypes(classToComplete, packageName).toList();
1711+
List<IType> potentialTypes = findTypes(classToComplete, packageName).map(TypeNameMatch::getType).toList();
17121712
List<IType> sourceTypes = potentialTypes.stream().filter(type -> type instanceof SourceType).toList();
17131713
if (!potentialTypes.isEmpty()) {
17141714
IType typeToComplete;
@@ -1861,31 +1861,31 @@ public void complete(org.eclipse.jdt.internal.compiler.env.ICompilationUnit sour
18611861
AbstractTypeDeclaration typeDecl = DOMCompletionUtil.findParentTypeDeclaration(context);
18621862
ITypeBinding currentTypeBinding = typeDecl == null ? null : typeDecl.resolveBinding();
18631863
findTypes(completeAfter, null)
1864-
.filter(type -> this.pattern.matchesName(this.prefix.toCharArray(),
1865-
type.getElementName().toCharArray()))
1866-
.filter(type -> {
1864+
.filter(typeMatch -> this.pattern.matchesName(this.prefix.toCharArray(),
1865+
typeMatch.getType().getElementName().toCharArray()))
1866+
.filter(typeMatch -> {
18671867
for (var scrapedBinding : catchExceptionBindings.all().toList()) {
18681868
if (scrapedBinding instanceof ITypeBinding scrapedTypeBinding) {
1869-
if (type.equals(scrapedTypeBinding.getJavaElement()) || type.getKey().equals(scrapedTypeBinding.getKey())) {
1869+
if (typeMatch.getType().equals(scrapedTypeBinding.getJavaElement()) || typeMatch.getType().getKey().equals(scrapedTypeBinding.getKey())) {
18701870
return false;
18711871
}
18721872
}
18731873
}
18741874
return true;
18751875
})
1876-
.filter(type -> {
1876+
.filter(typeMatch -> {
18771877
for (ITypeBinding caughtException : thrownExceptionFinder.getAlreadyCaughtExceptions()) {
1878-
if (type.getKey().equals(caughtException.getKey())) {
1878+
if (typeMatch.getType().getKey().equals(caughtException.getKey())) {
18791879
return false;
18801880
}
18811881
}
18821882
return true;
18831883
})
1884-
.filter(type -> {
1885-
if (alreadySuggestedFqn.contains(type.getFullyQualifiedName())) {
1884+
.filter(typeMatch -> {
1885+
if (alreadySuggestedFqn.contains(typeMatch.getType().getFullyQualifiedName())) {
18861886
return false;
18871887
}
1888-
alreadySuggestedFqn.add(type.getFullyQualifiedName());
1888+
alreadySuggestedFqn.add(typeMatch.getType().getFullyQualifiedName());
18891889
return true;
18901890
})
18911891
.map(this::toProposal).forEach(this.requestor::accept);
@@ -2072,22 +2072,22 @@ public void complete(org.eclipse.jdt.internal.compiler.env.ICompilationUnit sour
20722072
if (!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) {
20732073
final Set<String> alreadySuggestedFqn = ConcurrentHashMap.newKeySet();
20742074
findTypes(completeAfter, -1, typeMatchRule, null)
2075-
.filter(type -> this.pattern.matchesName(this.prefix.toCharArray(), type.getElementName().toCharArray()))
2076-
.filter(type -> {
2075+
.filter(typeMatch -> this.pattern.matchesName(this.prefix.toCharArray(), typeMatch.getType().getElementName().toCharArray()))
2076+
.filter(typeMatch -> {
20772077
for (var scrapedBinding : defaultCompletionBindings.all().toList()) {
20782078
if (scrapedBinding instanceof ITypeBinding scrapedTypeBinding) {
2079-
if (type.equals(scrapedTypeBinding.getJavaElement()) || type.getKey().equals(scrapedTypeBinding.getKey())) {
2079+
if (typeMatch.getType().equals(scrapedTypeBinding.getJavaElement()) || typeMatch.getType().getKey().equals(scrapedTypeBinding.getKey())) {
20802080
return false;
20812081
}
20822082
}
20832083
}
20842084
return true;
2085-
}).filter(type -> filterBasedOnExtendsOrImplementsInfo(type, this.extendsOrImplementsInfo))
2086-
.filter(type -> {
2087-
if (alreadySuggestedFqn.contains(type.getFullyQualifiedName())) {
2085+
}).filter(typeMatch -> filterBasedOnExtendsOrImplementsInfo(typeMatch.getType(), this.extendsOrImplementsInfo))
2086+
.filter(typeMatch -> {
2087+
if (alreadySuggestedFqn.contains(typeMatch.getType().getFullyQualifiedName())) {
20882088
return false;
20892089
}
2090-
alreadySuggestedFqn.add(type.getFullyQualifiedName());
2090+
alreadySuggestedFqn.add(typeMatch.getType().getFullyQualifiedName());
20912091
return true;
20922092
}).map(this::toProposal)
20932093
.forEach(this.requestor::accept);
@@ -2887,13 +2887,19 @@ private void scrapeAccessibleBindings(Bindings scope) {
28872887
favouriteReference = favouriteReference.substring(0, favouriteReference.length() - 2);
28882888
String packageName = favouriteReference.indexOf('.') < 0 ? "" : favouriteReference.substring(0, favouriteReference.lastIndexOf('.')); //$NON-NLS-1$
28892889
String typeName = favouriteReference.indexOf('.') < 0 ? favouriteReference : favouriteReference.substring(favouriteReference.lastIndexOf('.') + 1);
2890-
findTypes(typeName, SearchPattern.R_EXACT_MATCH, IJavaSearchConstants.TYPE, packageName).filter(type -> type.getElementName().equals(typeName)).forEach(keysToResolve::add);
2890+
findTypes(typeName, SearchPattern.R_EXACT_MATCH, IJavaSearchConstants.TYPE, packageName) //
2891+
.map(TypeNameMatch::getType)
2892+
.filter(type -> type.getElementName().equals(typeName))
2893+
.forEach(keysToResolve::add);
28912894
} else if (favouriteReference.lastIndexOf('.') >= 0) {
28922895
String memberName = favouriteReference.substring(favouriteReference.lastIndexOf('.') + 1);
28932896
String typeFqn = favouriteReference.substring(0, favouriteReference.lastIndexOf('.'));
28942897
String packageName = typeFqn.indexOf('.') < 0 ? "" : typeFqn.substring(0, typeFqn.lastIndexOf('.')); //$NON-NLS-1$
28952898
String typeName = typeFqn.indexOf('.') < 0 ? typeFqn : typeFqn.substring(typeFqn.lastIndexOf('.') + 1);
2896-
findTypes(typeName, SearchPattern.R_EXACT_MATCH, IJavaSearchConstants.TYPE, packageName).filter(type -> type.getElementName().equals(typeName)).findFirst().ifPresent(type -> {
2899+
findTypes(typeName, SearchPattern.R_EXACT_MATCH, IJavaSearchConstants.TYPE, packageName) //
2900+
.map(TypeNameMatch::getType)
2901+
.filter(type -> type.getElementName().equals(typeName)) //
2902+
.findFirst().ifPresent(type -> {
28972903
try {
28982904
for (IMethod method : type.getMethods()) {
28992905
if (method.exists() && (method.getFlags() & Flags.AccStatic) != 0 && memberName.equals(method.getElementName())) {
@@ -3181,11 +3187,11 @@ private void suggestPackages(ASTNode context) {
31813187

31823188
private void suggestTypesInPackage(String packageName) {
31833189
if (!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) {
3184-
List<IType> foundTypes = findTypes(this.prefix, packageName).toList();
3190+
List<TypeNameMatch> foundTypes = findTypes(this.prefix, packageName).toList();
31853191
AbstractTypeDeclaration typeDecl = DOMCompletionUtil.findParentTypeDeclaration(this.toComplete);
3186-
for (IType foundType : foundTypes) {
3187-
if (this.pattern.matchesName(this.prefix.toCharArray(), foundType.getElementName().toCharArray())) {
3188-
if (filterBasedOnExtendsOrImplementsInfo(foundType, this.extendsOrImplementsInfo)) {
3192+
for (TypeNameMatch foundType : foundTypes) {
3193+
if (this.pattern.matchesName(this.prefix.toCharArray(), foundType.getType().getElementName().toCharArray())) {
3194+
if (filterBasedOnExtendsOrImplementsInfo(foundType.getType(), this.extendsOrImplementsInfo)) {
31893195
this.requestor.accept(this.toProposal(foundType));
31903196
}
31913197
}
@@ -3340,8 +3346,8 @@ private static boolean extendsOrImplementsGivenType(TypeDeclaration typeDecl, IT
33403346

33413347
private void completeMarkerAnnotation(String completeAfter) {
33423348
findTypes(completeAfter, -1, IJavaSearchConstants.ANNOTATION_TYPE, null)
3343-
.filter(type -> this.pattern.matchesName(this.prefix.toCharArray(),
3344-
type.getElementName().toCharArray()))
3349+
.filter(typeMatch -> this.pattern.matchesName(this.prefix.toCharArray(),
3350+
typeMatch.getType().getElementName().toCharArray()))
33453351
.map(this::toProposal).forEach(this.requestor::accept);
33463352
}
33473353

@@ -3525,24 +3531,34 @@ private void findOverridableMethods0(ITypeBinding currentType, ITypeBinding type
35253531
}
35263532
}
35273533

3528-
private Stream<IType> findTypes(String namePrefix, String packageName) {
3534+
private Stream<TypeNameMatch> findTypes(String namePrefix, String packageName) {
35293535
return findTypes(namePrefix, -1, IJavaSearchConstants.TYPE, packageName);
35303536
}
35313537

3532-
private Stream<IType> findTypes(String namePrefix, int typeMatchRule, int searchFor, String packageName) {
3538+
private Stream<TypeNameMatch> findTypes(String namePrefix, int typeMatchRule, int searchFor, String packageName) {
35333539
if (namePrefix == null) {
35343540
namePrefix = ""; //$NON-NLS-1$
35353541
}
3536-
List<IType> types = new ArrayList<>();
3542+
List<TypeNameMatch> types = new ArrayList<>();
35373543
var searchScope = SearchEngine.createJavaSearchScope(new IJavaElement[] { this.javaProject });
35383544
TypeNameMatchRequestor typeRequestor = new TypeNameMatchRequestor() {
35393545
@Override
3540-
public void acceptTypeNameMatch(org.eclipse.jdt.core.search.TypeNameMatch match) {
3546+
public void acceptTypeNameMatch(TypeNameMatch match) {
35413547
if (isVisible(match)) {
3542-
types.add(match.getType());
3548+
types.add(match);
35433549
}
35443550
}
35453551
private boolean isVisible(TypeNameMatch match) {
3552+
if (!DOMCompletionEngine.this.settings.get(JavaCore.COMPILER_PB_FORBIDDEN_REFERENCE).equals(JavaCore.IGNORE)
3553+
&& DOMCompletionEngine.this.assistOptions.checkForbiddenReference
3554+
&& match.getAccessibility() == IAccessRule.K_NON_ACCESSIBLE) {
3555+
return false;
3556+
}
3557+
if (!DOMCompletionEngine.this.settings.get(JavaCore.COMPILER_PB_DISCOURAGED_REFERENCE).equals(JavaCore.IGNORE)
3558+
&& DOMCompletionEngine.this.assistOptions.checkDiscouragedReference
3559+
&& match.getAccessibility() == IAccessRule.K_DISCOURAGED) {
3560+
return false;
3561+
}
35463562
if (match.getPackageName().isEmpty() && !currentTypeBinding().getPackage().getName().isEmpty()) {
35473563
// can only access classes in the default package from the default package
35483564
return false;
@@ -3793,7 +3809,7 @@ private CompletionProposal toProposal(IBinding binding) {
37933809

37943810
private CompletionProposal toProposal(IBinding binding, String completion) {
37953811
if (binding instanceof ITypeBinding && binding.getJavaElement() instanceof IType type) {
3796-
return toProposal(type);
3812+
return toProposal(type, IAccessRule.K_ACCESSIBLE);
37973813
}
37983814

37993815
int kind = -1;
@@ -4066,8 +4082,12 @@ private String qualifiedTypeName(ITypeBinding typeBinding) {
40664082
return typeBinding.getQualifiedName();
40674083
}
40684084
}
4085+
4086+
private CompletionProposal toProposal(TypeNameMatch typeNameMatch) {
4087+
return toProposal(typeNameMatch.getType(), typeNameMatch.getAccessibility());
4088+
}
40694089

4070-
private CompletionProposal toProposal(IType type) {
4090+
private CompletionProposal toProposal(IType type, int access) {
40714091
DOMInternalCompletionProposal res = createProposal(CompletionProposal.TYPE_REF);
40724092
char[] simpleName = type.getElementName().toCharArray();
40734093
char[] signature = SignatureUtils.createSignature(type).toCharArray();
@@ -4177,7 +4197,7 @@ private CompletionProposal toProposal(IType type) {
41774197
int relevance = RelevanceConstants.R_DEFAULT
41784198
+ RelevanceConstants.R_RESOLVED
41794199
+ RelevanceUtils.computeRelevanceForInteresting(type, expectedTypes)
4180-
+ RelevanceConstants.R_NON_RESTRICTED
4200+
+ RelevanceUtils.computeRelevanceForRestrictions(access, this.settings)
41814201
+ (inCatchClause && DOMCompletionUtil.findInSupers(type, "Ljava/lang/Exception;", this.workingCopyOwner, this.typeHierarchyCache) ? RelevanceConstants.R_EXCEPTION : 0)
41824202
+ RelevanceUtils.computeRelevanceForInheritance(this.qualifyingType, type)
41834203
+ RelevanceUtils.computeRelevanceForQualification(!"java.lang".equals(type.getPackageFragment().getElementName()) && !nodeInImports && !fromCurrentCU && !inSamePackage && !typeIsImported, this.prefix, this.qualifiedPrefix)
@@ -4266,7 +4286,7 @@ private CompletionProposal toSuperConstructorProposal(IMethodBinding superConstr
42664286

42674287
private CompletionProposal toProposal(IJavaElement element) {
42684288
if (element instanceof IType type) {
4269-
return toProposal(type);
4289+
return toProposal(type, IAccessRule.K_ACCESSIBLE);
42704290
}
42714291
DOMInternalCompletionProposal res = null;
42724292
IType parentType = (IType)element.getAncestor(IJavaElement.TYPE);

0 commit comments

Comments
 (0)