Java: faster find usages for public methods in private nested classes that are not inherited (IDEA-306501)

GitOrigin-RevId: 9f6f083531e5e68e69a00791a6f61423463ed140
This commit is contained in:
Bas Leijdekkers
2022-12-05 13:46:35 +00:00
committed by intellij-monorepo-bot
parent 6b993dcdf8
commit ccb152a04f
@@ -1,4 +1,4 @@
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.psi.impl;
import com.intellij.codeInsight.AnnotationTargetUtil;
@@ -394,7 +394,8 @@ public final class PsiImplUtil {
PsiModifierList modifierList = member.getModifierList();
int accessLevel = modifierList == null ? PsiUtil.ACCESS_LEVEL_PUBLIC : PsiUtil.getAccessLevel(modifierList);
if (accessLevel == PsiUtil.ACCESS_LEVEL_PUBLIC || accessLevel == PsiUtil.ACCESS_LEVEL_PROTECTED) {
if (accessLevel == PsiUtil.ACCESS_LEVEL_PUBLIC ||
accessLevel == PsiUtil.ACCESS_LEVEL_PROTECTED) {
SearchScope classScope = getClassUseScopeIfApplicable(member, aClass, accessLevel);
return (classScope != null) ? classScope : maximalUseScope;
}
@@ -418,13 +419,51 @@ public final class PsiImplUtil {
if (aClass == null) return null;
final PsiModifierList classModifierList = aClass.getModifierList();
if (classModifierList == null) return null;
if (!classModifierList.hasModifierProperty(PsiModifier.FINAL) &&
!(member instanceof PsiMethod && ((PsiMethod)member).isConstructor())) {
// class use scope doesn't matter, since another very visible class can inherit from aClass
return null;
if (classModifierList.hasModifierProperty(PsiModifier.FINAL) ||
member instanceof PsiMethod && ((PsiMethod)member).isConstructor()) {
// constructors and members of final classes cannot be accessed via a subclass so their use scope can't be wider than their class's
return (PsiUtil.getAccessLevel(classModifierList) < accessLevel) ? aClass.getUseScope() : null;
}
// constructors and members of final classes cannot be accessed via a subclass so their use scope can't be wider than their class's
return (PsiUtil.getAccessLevel(classModifierList) < accessLevel) ? aClass.getUseScope() : null;
else if (classModifierList.hasModifierProperty(PsiModifier.PRIVATE) && !hasSubclassInContainingContext(aClass)) {
return aClass.getUseScope();
}
// class use scope doesn't matter, since another very visible class can inherit from aClass
return null;
}
private static boolean hasSubclassInContainingContext(PsiClass aClass) {
if (aClass instanceof PsiCompiledElement) return true; // don't check library code
class LocalInheritorVisitor extends JavaRecursiveElementWalkingVisitor {
private boolean extended = false;
@Override
public void visitReferenceElement(@NotNull PsiJavaCodeReferenceElement reference) {
if (extended) return;
final PsiElement parent = reference.getParent();
if (!(parent instanceof PsiReferenceList)) return;
final PsiElement grandParent = parent.getParent();
if (!(grandParent instanceof PsiClass)) return;
if (reference.isReferenceTo(aClass)) {
extended = true;
stopWalking();
}
}
@Override
public void visitReferenceExpression(@NotNull PsiReferenceExpression expression) {}
public boolean isExtended() {
return extended;
}
}
PsiClass containingClass = aClass.getContainingClass();
PsiClass context = aClass;
while (containingClass != null) {
context = containingClass;
containingClass = containingClass.getContainingClass();
}
final LocalInheritorVisitor visitor = new LocalInheritorVisitor();
context.accept(visitor);
return visitor.isExtended();
}
public static boolean isInServerPage(@Nullable final PsiElement element) {