diff --git a/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInspection/reference/RefImplicitConstructorImpl.java b/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInspection/reference/RefImplicitConstructorImpl.java index 3b2b885b93..0ca477f189 100644 --- a/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInspection/reference/RefImplicitConstructorImpl.java +++ b/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInspection/reference/RefImplicitConstructorImpl.java @@ -13,83 +13,78 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/* - * Created by IntelliJ IDEA. - * User: max - * Date: Nov 28, 2001 - * Time: 4:17:17 PM - * To change template for new class use - * Code Style | Class Templates options (Tools | IDE Options). - */ package com.intellij.java.analysis.impl.codeInspection.reference; import com.intellij.java.analysis.codeInspection.reference.RefClass; import com.intellij.java.analysis.codeInspection.reference.RefImplicitConstructor; import com.intellij.java.analysis.codeInspection.reference.RefJavaUtil; import com.intellij.java.language.psi.PsiModifierListOwner; -import consulo.application.Application; -import consulo.application.util.function.Computable; -import consulo.language.editor.inspection.localize.InspectionLocalize; +import consulo.annotation.access.RequiredReadAction; +import consulo.application.ReadAction; +import consulo.java.analysis.impl.localize.JavaInspectionsLocalize; import consulo.language.psi.PsiFile; import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; +/** + * @author max + * @since 2001-11-28 + */ public class RefImplicitConstructorImpl extends RefMethodImpl implements RefImplicitConstructor { + RefImplicitConstructorImpl(RefClass ownerClass) { + super(JavaInspectionsLocalize.inspectionReferenceImplicitConstructorName(ownerClass.getName()), ownerClass); + } - RefImplicitConstructorImpl(RefClass ownerClass) { - super(InspectionLocalize.inspectionReferenceImplicitConstructorName(ownerClass.getName()).get(), ownerClass); - } - - @Override - public void buildReferences() { - getRefManager().fireBuildReferences(this); - } + @Override + @RequiredReadAction + public void buildReferences() { + getRefManager().fireBuildReferences(this); + } - @Override - public boolean isSuspicious() { - return ((RefClassImpl) getOwnerClass()).isSuspicious(); - } + @Override + public boolean isSuspicious() { + return ((RefClassImpl) getOwnerClass()).isSuspicious(); + } - @Override - @Nonnull - public String getName() { - return InspectionLocalize.inspectionReferenceImplicitConstructorName(getOwnerClass().getName()).get(); - } + @Nonnull + @Override + public String getName() { + return JavaInspectionsLocalize.inspectionReferenceImplicitConstructorName(getOwnerClass().getName()).get(); + } - @Override - public String getExternalName() { - return getOwnerClass().getExternalName(); - } + @Override + public String getExternalName() { + return getOwnerClass().getExternalName(); + } - @Override - public boolean isValid() { - return Application.get().runReadAction((Computable)() -> getOwnerClass().isValid()); - } + @Override + public boolean isValid() { + return ReadAction.compute(() -> getOwnerClass().isValid()); + } - @Override - public String getAccessModifier() { - return getOwnerClass().getAccessModifier(); - } + @Override + public String getAccessModifier() { + return getOwnerClass().getAccessModifier(); + } - @Override - public void setAccessModifier(String am) { - RefJavaUtil.getInstance().setAccessModifier(getOwnerClass(), am); - } + @Override + public void setAccessModifier(String am) { + RefJavaUtil.getInstance().setAccessModifier(getOwnerClass(), am); + } - @Override - public PsiModifierListOwner getElement() { - return getOwnerClass().getElement(); - } + @Override + public PsiModifierListOwner getElement() { + return getOwnerClass().getElement(); + } - @Override - @Nullable - public PsiFile getContainingFile() { - return getOwnerClass().getContainingFile(); - } + @Nullable + @Override + public PsiFile getContainingFile() { + return getOwnerClass().getContainingFile(); + } - @Override - public RefClass getOwnerClass() { - return myOwnerClass == null ? super.getOwnerClass() : myOwnerClass; - } + @Override + public RefClass getOwnerClass() { + return myOwnerClass == null ? super.getOwnerClass() : myOwnerClass; + } } diff --git a/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInspection/reference/RefJavaElementImpl.java b/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInspection/reference/RefJavaElementImpl.java index b0ce4375f6..3840b18ee2 100644 --- a/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInspection/reference/RefJavaElementImpl.java +++ b/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInspection/reference/RefJavaElementImpl.java @@ -58,8 +58,8 @@ public abstract class RefJavaElementImpl extends RefElementImpl implements RefJa private static final int IS_USES_DEPRECATION_MASK = 0x200; private static final int IS_SYNTHETIC_JSP_ELEMENT = 0x400; - protected RefJavaElementImpl(String name, RefJavaElement owner) { - super(name, owner); + protected RefJavaElementImpl(@Nonnull LocalizeValue name, RefJavaElement owner) { + super(name.get(), owner); String am = owner.getAccessModifier(); doSetAccessModifier(am); diff --git a/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInspection/reference/RefMethodImpl.java b/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInspection/reference/RefMethodImpl.java index 5d7a676ede..ad0970a7cd 100644 --- a/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInspection/reference/RefMethodImpl.java +++ b/java-analysis-impl/src/main/java/com/intellij/java/analysis/impl/codeInspection/reference/RefMethodImpl.java @@ -19,723 +19,718 @@ import com.intellij.java.language.impl.codeInsight.ExceptionUtil; import com.intellij.java.language.psi.*; import com.intellij.java.language.psi.util.*; -import consulo.application.ApplicationManager; +import consulo.annotation.access.RequiredReadAction; +import consulo.application.ReadAction; import consulo.language.editor.impl.inspection.reference.RefElementImpl; import consulo.language.editor.inspection.reference.RefElement; import consulo.language.editor.inspection.reference.RefManager; import consulo.language.editor.inspection.reference.RefVisitor; -import consulo.language.psi.PsiElement; import consulo.language.psi.PsiManager; import consulo.language.psi.scope.GlobalSearchScope; import consulo.language.util.IncorrectOperationException; +import consulo.localize.LocalizeValue; import consulo.util.collection.SmartList; import consulo.util.lang.Comparing; -import org.jetbrains.annotations.NonNls; - import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; + import java.util.*; /** * @author max - * Date: Oct 21, 2001 + * @since 2001-10-21 */ public class RefMethodImpl extends RefJavaElementImpl implements RefMethod { - private static final List EMPTY_METHOD_LIST = Collections.emptyList(); - private static final RefParameter[] EMPTY_PARAMS_ARRAY = new RefParameter[0]; + private static final List EMPTY_METHOD_LIST = Collections.emptyList(); + private static final RefParameter[] EMPTY_PARAMS_ARRAY = new RefParameter[0]; - private static final int IS_APPMAIN_MASK = 0x10000; - private static final int IS_LIBRARY_OVERRIDE_MASK = 0x20000; - private static final int IS_CONSTRUCTOR_MASK = 0x40000; - private static final int IS_ABSTRACT_MASK = 0x80000; - private static final int IS_BODY_EMPTY_MASK = 0x100000; - private static final int IS_ONLY_CALLS_SUPER_MASK = 0x200000; - private static final int IS_RETURN_VALUE_USED_MASK = 0x400000; + private static final int IS_APPMAIN_MASK = 0x10000; + private static final int IS_LIBRARY_OVERRIDE_MASK = 0x20000; + private static final int IS_CONSTRUCTOR_MASK = 0x40000; + private static final int IS_ABSTRACT_MASK = 0x80000; + private static final int IS_BODY_EMPTY_MASK = 0x100000; + private static final int IS_ONLY_CALLS_SUPER_MASK = 0x200000; + private static final int IS_RETURN_VALUE_USED_MASK = 0x400000; - private static final int IS_TEST_METHOD_MASK = 0x4000000; - private static final int IS_CALLED_ON_SUBCLASS = 0x8000000; + private static final int IS_TEST_METHOD_MASK = 0x4000000; + private static final int IS_CALLED_ON_SUBCLASS = 0x8000000; - private static final String RETURN_VALUE_UNDEFINED = "#"; + private static final String RETURN_VALUE_UNDEFINED = "#"; - private List mySuperMethods; - private List myDerivedMethods; - private List myUnThrownExceptions; + private List mySuperMethods; + private List myDerivedMethods; + private List myUnThrownExceptions; - private RefParameter[] myParameters; - private String myReturnValueTemplate; - protected final RefClass myOwnerClass; + private RefParameter[] myParameters; + private String myReturnValueTemplate; + protected final RefClass myOwnerClass; - public RefMethodImpl(@Nonnull RefClass ownerClass, PsiMethod method, RefManager manager) { - super(method, manager); + @RequiredReadAction + public RefMethodImpl(@Nonnull RefClass ownerClass, PsiMethod method, RefManager manager) { + super(method, manager); - ((RefClassImpl) ownerClass).add(this); + ((RefClassImpl) ownerClass).add(this); - myOwnerClass = ownerClass; - } + myOwnerClass = ownerClass; + } - // To be used only from RefImplicitConstructor. - protected RefMethodImpl(String name, RefClass ownerClass) { - super(name, ownerClass); - myOwnerClass = ownerClass; - ((RefClassImpl) ownerClass).add(this); + // To be used only from RefImplicitConstructor. + protected RefMethodImpl(@Nonnull LocalizeValue name, RefClass ownerClass) { + super(name, ownerClass); + myOwnerClass = ownerClass; + ((RefClassImpl) ownerClass).add(this); - addOutReference(getOwnerClass()); - ((RefClassImpl) getOwnerClass()).addInReference(this); + addOutReference(getOwnerClass()); + ((RefClassImpl) getOwnerClass()).addInReference(this); - setConstructor(true); - } + setConstructor(true); + } - @Override - public void initialize() { - final PsiMethod method = (PsiMethod) getElement(); - LOG.assertTrue(method != null); - setConstructor(method.isConstructor()); - setFlag(method.getReturnType() == null || PsiType.VOID.equals(method.getReturnType()), IS_RETURN_VALUE_USED_MASK); + @Override + @RequiredReadAction + public void initialize() { + PsiMethod method = (PsiMethod) getElement(); + LOG.assertTrue(method != null); + setConstructor(method.isConstructor()); + setFlag(method.getReturnType() == null || PsiType.VOID.equals(method.getReturnType()), IS_RETURN_VALUE_USED_MASK); - if (!isReturnValueUsed()) { - myReturnValueTemplate = RETURN_VALUE_UNDEFINED; - } + if (!isReturnValueUsed()) { + myReturnValueTemplate = RETURN_VALUE_UNDEFINED; + } + + if (isConstructor()) { + addReference(getOwnerClass(), getOwnerClass().getElement(), method, false, true, null); + } + + setAbstract(!getOwnerClass().isInterface() && method.isAbstract()); + + setAppMain(isAppMain(method, this)); + setLibraryOverride(method.hasModifierProperty(PsiModifier.NATIVE)); - if (isConstructor()) { - addReference(getOwnerClass(), getOwnerClass().getElement(), method, false, true, null); + initializeSuperMethods(method); + if (isExternalOverride()) { + ((RefClassImpl) getOwnerClass()).addLibraryOverrideMethod(this); + } + + String name = method.getName(); + if (getOwnerClass().isTestCase() && name.startsWith("test")) { + setTestMethod(true); + } + + PsiParameter[] paramList = method.getParameterList().getParameters(); + if (paramList.length > 0) { + myParameters = new RefParameterImpl[paramList.length]; + for (int i = 0; i < paramList.length; i++) { + PsiParameter parameter = paramList[i]; + myParameters[i] = getRefJavaManager().getParameterReference(parameter, i, this); + } + } + + if (method.hasModifierProperty(PsiModifier.NATIVE)) { + updateReturnValueTemplate(null); + updateThrowsList(null); + } + collectUncaughtExceptions(method); } - if (getOwnerClass().isInterface()) { - setAbstract(false); - } else { - setAbstract(method.hasModifierProperty(PsiModifier.ABSTRACT)); + private static boolean isAppMain(PsiMethod psiMethod, RefMethod refMethod) { + if (!refMethod.isStatic()) { + return false; + } + if (!PsiType.VOID.equals(psiMethod.getReturnType())) { + return false; + } + + PsiMethod appMainPattern = ((RefMethodImpl) refMethod).getRefJavaManager().getAppMainPattern(); + if (MethodSignatureUtil.areSignaturesEqual(psiMethod, appMainPattern)) { + return true; + } + + PsiMethod appPremainPattern = ((RefMethodImpl) refMethod).getRefJavaManager().getAppPremainPattern(); + return MethodSignatureUtil.areSignaturesEqual(psiMethod, appPremainPattern); } + @RequiredReadAction + private void checkForSuperCall(PsiMethod method) { + if (isConstructor()) { + PsiCodeBlock body = method.getBody(); + if (body == null) { + return; + } + PsiStatement[] statements = body.getStatements(); + boolean isBaseExplicitlyCalled = false; + if (statements.length > 0 + && statements[0] instanceof PsiExpressionStatement first + && first.getExpression() instanceof PsiMethodCallExpression call + && call.getMethodExpression().getQualifierExpression() instanceof PsiReferenceExpression qRefExpr) { + String text = qRefExpr.getText(); + if ("super".equals(text) || text.equals("this")) { + isBaseExplicitlyCalled = true; + } + } - setAppMain(isAppMain(method, this)); - setLibraryOverride(method.hasModifierProperty(PsiModifier.NATIVE)); + if (!isBaseExplicitlyCalled) { + for (RefClass superClass : getOwnerClass().getBaseClasses()) { + RefMethodImpl superDefaultConstructor = (RefMethodImpl) superClass.getDefaultConstructor(); - initializeSuperMethods(method); - if (isExternalOverride()) { - ((RefClassImpl) getOwnerClass()).addLibraryOverrideMethod(this); + if (superDefaultConstructor != null) { + superDefaultConstructor.addInReference(this); + addOutReference(superDefaultConstructor); + } + } + } + } } - @NonNls final String name = method.getName(); - if (getOwnerClass().isTestCase() && name.startsWith("test")) { - setTestMethod(true); + @Override + @Nonnull + public Collection getSuperMethods() { + if (mySuperMethods == null) { + return EMPTY_METHOD_LIST; + } + if (mySuperMethods.size() > 10) { + LOG.info("method: " + getName() + " owner:" + getOwnerClass().getQualifiedName()); + } + return mySuperMethods; } - PsiParameter[] paramList = method.getParameterList().getParameters(); - if (paramList.length > 0) { - myParameters = new RefParameterImpl[paramList.length]; - for (int i = 0; i < paramList.length; i++) { - PsiParameter parameter = paramList[i]; - myParameters[i] = getRefJavaManager().getParameterReference(parameter, i, this); - } + @Override + @Nonnull + public Collection getDerivedMethods() { + if (myDerivedMethods == null) { + return EMPTY_METHOD_LIST; + } + return myDerivedMethods; } - if (method.hasModifierProperty(PsiModifier.NATIVE)) { - updateReturnValueTemplate(null); - updateThrowsList(null); + @Override + public boolean isBodyEmpty() { + return checkFlag(IS_BODY_EMPTY_MASK); } - collectUncaughtExceptions(method); - } - private static boolean isAppMain(PsiMethod psiMethod, RefMethod refMethod) { - if (!refMethod.isStatic()) { - return false; + @Override + public boolean isOnlyCallsSuper() { + return checkFlag(IS_ONLY_CALLS_SUPER_MASK); } - if (!PsiType.VOID.equals(psiMethod.getReturnType())) { - return false; + + @Override + public boolean hasBody() { + return !isAbstract() && !getOwnerClass().isInterface() || !isBodyEmpty(); } - PsiMethod appMainPattern = ((RefMethodImpl) refMethod).getRefJavaManager().getAppMainPattern(); - if (MethodSignatureUtil.areSignaturesEqual(psiMethod, appMainPattern)) { - return true; + @RequiredReadAction + private void initializeSuperMethods(PsiMethod method) { + for (PsiMethod psiSuperMethod : method.findSuperMethods()) { + if (getRefManager().belongsToScope(psiSuperMethod)) { + RefMethodImpl refSuperMethod = (RefMethodImpl) getRefManager().getReference(psiSuperMethod); + if (refSuperMethod != null) { + addSuperMethod(refSuperMethod); + refSuperMethod.markExtended(this); + } + } + else { + setLibraryOverride(true); + } + } } - PsiMethod appPremainPattern = ((RefMethodImpl) refMethod).getRefJavaManager().getAppPremainPattern(); - return MethodSignatureUtil.areSignaturesEqual(psiMethod, appPremainPattern); - } + public void addSuperMethod(RefMethodImpl refSuperMethod) { + if (!getSuperMethods().contains(refSuperMethod) && !refSuperMethod.getSuperMethods().contains(this)) { + if (mySuperMethods == null) { + mySuperMethods = new ArrayList<>(1); + } + mySuperMethods.add(refSuperMethod); + } + } - private void checkForSuperCall(PsiMethod method) { - if (isConstructor()) { - PsiCodeBlock body = method.getBody(); - if (body == null) { - return; - } - PsiStatement[] statements = body.getStatements(); - boolean isBaseExplicitlyCalled = false; - if (statements.length > 0) { - PsiStatement first = statements[0]; - if (first instanceof PsiExpressionStatement) { - PsiExpression firstExpression = ((PsiExpressionStatement) first).getExpression(); - if (firstExpression instanceof PsiMethodCallExpression) { - PsiExpression qualifierExpression = ((PsiMethodCallExpression) firstExpression).getMethodExpression().getQualifierExpression(); - if (qualifierExpression instanceof PsiReferenceExpression) { - @NonNls String text = qualifierExpression.getText(); - if ("super".equals(text) || text.equals("this")) { - isBaseExplicitlyCalled = true; - } + public void markExtended(RefMethodImpl method) { + if (!getDerivedMethods().contains(method) && !method.getDerivedMethods().contains(this)) { + if (myDerivedMethods == null) { + myDerivedMethods = new ArrayList<>(1); } - } - } - } - - if (!isBaseExplicitlyCalled) { - for (RefClass superClass : getOwnerClass().getBaseClasses()) { - RefMethodImpl superDefaultConstructor = (RefMethodImpl) superClass.getDefaultConstructor(); - - if (superDefaultConstructor != null) { - superDefaultConstructor.addInReference(this); - addOutReference(superDefaultConstructor); - } - } - } - } - } - - @Override - @Nonnull - public Collection getSuperMethods() { - if (mySuperMethods == null) { - return EMPTY_METHOD_LIST; - } - if (mySuperMethods.size() > 10) { - LOG.info("method: " + getName() + " owner:" + getOwnerClass().getQualifiedName()); - } - return mySuperMethods; - } - - @Override - @Nonnull - public Collection getDerivedMethods() { - if (myDerivedMethods == null) { - return EMPTY_METHOD_LIST; - } - return myDerivedMethods; - } - - @Override - public boolean isBodyEmpty() { - return checkFlag(IS_BODY_EMPTY_MASK); - } - - @Override - public boolean isOnlyCallsSuper() { - return checkFlag(IS_ONLY_CALLS_SUPER_MASK); - } - - @Override - public boolean hasBody() { - return !isAbstract() && !getOwnerClass().isInterface() || !isBodyEmpty(); - } - - private void initializeSuperMethods(PsiMethod method) { - for (PsiMethod psiSuperMethod : method.findSuperMethods()) { - if (getRefManager().belongsToScope(psiSuperMethod)) { - RefMethodImpl refSuperMethod = (RefMethodImpl) getRefManager().getReference(psiSuperMethod); - if (refSuperMethod != null) { - addSuperMethod(refSuperMethod); - refSuperMethod.markExtended(this); - } - } else { - setLibraryOverride(true); - } - } - } - - public void addSuperMethod(RefMethodImpl refSuperMethod) { - if (!getSuperMethods().contains(refSuperMethod) && !refSuperMethod.getSuperMethods().contains(this)) { - if (mySuperMethods == null) { - mySuperMethods = new ArrayList(1); - } - mySuperMethods.add(refSuperMethod); - } - } - - public void markExtended(RefMethodImpl method) { - if (!getDerivedMethods().contains(method) && !method.getDerivedMethods().contains(this)) { - if (myDerivedMethods == null) { - myDerivedMethods = new ArrayList(1); - } - myDerivedMethods.add(method); - } - } - - @Override - @Nonnull - public RefParameter[] getParameters() { - if (myParameters == null) { - return EMPTY_PARAMS_ARRAY; - } - return myParameters; - } - - @Override - public void buildReferences() { - // Work on code block to find what we're referencing... - PsiMethod method = (PsiMethod) getElement(); - if (method == null) { - return; - } - PsiCodeBlock body = method.getBody(); - final RefJavaUtil refUtil = RefJavaUtil.getInstance(); - refUtil.addReferences(method, this, body); - refUtil.addReferences(method, this, method.getModifierList()); - checkForSuperCall(method); - setOnlyCallsSuper(refUtil.isMethodOnlyCallsSuper(method)); - - setBodyEmpty(isOnlyCallsSuper() || !isExternalOverride() && (body == null || body.getStatements().length == 0)); - - PsiType retType = method.getReturnType(); - if (retType != null) { - PsiType psiType = retType; - RefClass ownerClass = refUtil.getOwnerClass(getRefManager(), method); - - if (ownerClass != null) { - psiType = psiType.getDeepComponentType(); - - if (psiType instanceof PsiClassType) { - PsiClass psiClass = PsiUtil.resolveClassInType(psiType); - if (psiClass != null && getRefManager().belongsToScope(psiClass)) { - RefClassImpl refClass = (RefClassImpl) getRefManager().getReference(psiClass); - if (refClass != null) { - refClass.addTypeReference(ownerClass); - refClass.addClassExporter(this); + myDerivedMethods.add(method); + } + } + + @Override + @Nonnull + public RefParameter[] getParameters() { + if (myParameters == null) { + return EMPTY_PARAMS_ARRAY; + } + return myParameters; + } + + @Override + @RequiredReadAction + public void buildReferences() { + // Work on code block to find what we're referencing... + PsiMethod method = (PsiMethod) getElement(); + if (method == null) { + return; + } + PsiCodeBlock body = method.getBody(); + RefJavaUtil refUtil = RefJavaUtil.getInstance(); + refUtil.addReferences(method, this, body); + refUtil.addReferences(method, this, method.getModifierList()); + checkForSuperCall(method); + setOnlyCallsSuper(refUtil.isMethodOnlyCallsSuper(method)); + + setBodyEmpty(isOnlyCallsSuper() || !isExternalOverride() && (body == null || body.getStatements().length == 0)); + + PsiType retType = method.getReturnType(); + if (retType != null) { + PsiType psiType = retType; + RefClass ownerClass = refUtil.getOwnerClass(getRefManager(), method); + + if (ownerClass != null) { + psiType = psiType.getDeepComponentType(); + + if (psiType instanceof PsiClassType) { + PsiClass psiClass = PsiUtil.resolveClassInType(psiType); + if (psiClass != null && getRefManager().belongsToScope(psiClass)) { + RefClassImpl refClass = (RefClassImpl) getRefManager().getReference(psiClass); + if (refClass != null) { + refClass.addTypeReference(ownerClass); + refClass.addClassExporter(this); + } + } + } } - } } - } + + for (RefParameter parameter : getParameters()) { + PsiParameter element = parameter.getElement(); + refUtil.setIsFinal(parameter, element != null && element.hasModifierProperty(PsiModifier.FINAL)); + } + + getRefManager().fireBuildReferences(this); } - for (RefParameter parameter : getParameters()) { - PsiParameter element = parameter.getElement(); - refUtil.setIsFinal(parameter, element != null && element.hasModifierProperty(PsiModifier.FINAL)); + @RequiredReadAction + private void collectUncaughtExceptions(@Nonnull PsiMethod method) { + if (isExternalOverride()) { + return; + } + String name = method.getName(); + if (getOwnerClass().isTestCase() && name.startsWith("test")) { + return; + } + + if (getSuperMethods().isEmpty()) { + PsiClassType[] throwsList = method.getThrowsList().getReferencedTypes(); + if (throwsList.length > 0) { + myUnThrownExceptions = throwsList.length == 1 ? new SmartList<>() : new ArrayList<>(throwsList.length); + for (PsiClassType type : throwsList) { + PsiClass aClass = type.resolve(); + String fqn = aClass == null ? null : aClass.getQualifiedName(); + if (fqn != null) { + myUnThrownExceptions.add(fqn); + } + } + } + } + + PsiCodeBlock body = method.getBody(); + if (body == null) { + return; + } + + Collection exceptionTypes = ExceptionUtil.collectUnhandledExceptions(body, method, false); + for (PsiClassType exceptionType : exceptionTypes) { + updateThrowsList(exceptionType); + } } - getRefManager().fireBuildReferences(this); - } + public void removeUnThrownExceptions(PsiClass unThrownException) { + if (myUnThrownExceptions != null) { + myUnThrownExceptions.remove(unThrownException.getQualifiedName()); + } + } - private void collectUncaughtExceptions(@Nonnull PsiMethod method) { - if (isExternalOverride()) { - return; + @Override + public void accept(@Nonnull RefVisitor visitor) { + if (visitor instanceof RefJavaVisitor refJavaVisitor) { + ReadAction.run(() -> refJavaVisitor.visitMethod(RefMethodImpl.this)); + } + else { + super.accept(visitor); + } } - @NonNls final String name = method.getName(); - if (getOwnerClass().isTestCase() && name.startsWith("test")) { - return; + + @Override + public boolean isExternalOverride() { + return isLibraryOverride(new HashSet<>()); } - if (getSuperMethods().isEmpty()) { - PsiClassType[] throwsList = method.getThrowsList().getReferencedTypes(); - if (throwsList.length > 0) { - myUnThrownExceptions = throwsList.length == 1 ? new SmartList() : new ArrayList(throwsList.length); - for (final PsiClassType type : throwsList) { - PsiClass aClass = type.resolve(); - String fqn = aClass == null ? null : aClass.getQualifiedName(); - if (fqn != null) { - myUnThrownExceptions.add(fqn); - } + private boolean isLibraryOverride(Collection processed) { + if (processed.contains(this)) { + return false; + } + processed.add(this); + + if (checkFlag(IS_LIBRARY_OVERRIDE_MASK)) { + return true; + } + for (RefMethod superMethod : getSuperMethods()) { + if (((RefMethodImpl) superMethod).isLibraryOverride(processed)) { + setFlag(true, IS_LIBRARY_OVERRIDE_MASK); + return true; + } } - } + + return false; } - final PsiCodeBlock body = method.getBody(); - if (body == null) { - return; + @Override + public boolean isAppMain() { + return checkFlag(IS_APPMAIN_MASK); } - final Collection exceptionTypes = ExceptionUtil.collectUnhandledExceptions(body, method, false); - for (final PsiClassType exceptionType : exceptionTypes) { - updateThrowsList(exceptionType); + @Override + public boolean isAbstract() { + return checkFlag(IS_ABSTRACT_MASK); } - } - public void removeUnThrownExceptions(PsiClass unThrownException) { - if (myUnThrownExceptions != null) { - myUnThrownExceptions.remove(unThrownException.getQualifiedName()); + @Override + public boolean hasSuperMethods() { + return !getSuperMethods().isEmpty() || isExternalOverride(); } - } - @Override - public void accept(final RefVisitor visitor) { - if (visitor instanceof RefJavaVisitor) { - ApplicationManager.getApplication().runReadAction(new Runnable() { - @Override - public void run() { - ((RefJavaVisitor) visitor).visitMethod(RefMethodImpl.this); + @Override + public boolean isReferenced() { + // Directly called from somewhere.. + for (RefElement refCaller : getInReferences()) { + if (!getDerivedMethods().contains(refCaller)) { + return true; + } + } + + // Library override probably called from library code. + return isExternalOverride(); + } + + @Override + public boolean hasSuspiciousCallers() { + // Directly called from somewhere.. + for (RefElement refCaller : getInReferences()) { + if (((RefElementImpl) refCaller).isSuspicious() && !getDerivedMethods().contains(refCaller)) { + return true; + } + } + + // Library override probably called from library code. + if (isExternalOverride()) { + return true; + } + + // Class isn't instantiated. Most probably we have problem with class, not method. + if (!isStatic() && !isConstructor()) { + if (((RefClassImpl) getOwnerClass()).isSuspicious()) { + return true; + } + + // Is an override. Probably called via reference to base class. + for (RefMethod refSuper : getSuperMethods()) { + if (((RefMethodImpl) refSuper).isSuspicious()) { + return true; + } + } + } + + return false; + } + + @Override + public boolean isConstructor() { + return checkFlag(IS_CONSTRUCTOR_MASK); + } + + @Override + public RefClass getOwnerClass() { + return (RefClass) getOwner(); + } + + @Nonnull + @Override + public String getName() { + if (isValid()) { + return ReadAction.compute(() -> { + PsiMethod method = (PsiMethod) getElement(); + /*if (psiMethod instanceof JspHolderMethod) { + result[0] = psiMethod.getName(); + } + else {*/ + return PsiFormatUtil.formatMethod( + method, + PsiSubstitutor.EMPTY, + PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_PARAMETERS, + PsiFormatUtilBase.SHOW_TYPE + ); + //} + }); + } + else { + return super.getName(); } - }); - } else { - super.accept(visitor); } - } - @Override - public boolean isExternalOverride() { - return isLibraryOverride(new HashSet()); - } + @Override + public String getExternalName() { + return ReadAction.compute(() -> { + PsiMethod psiMethod = (PsiMethod) getElement(); + LOG.assertTrue(psiMethod != null); + return PsiFormatUtil.getExternalName(psiMethod); + }); + } - private boolean isLibraryOverride(Collection processed) { - if (processed.contains(this)) { - return false; + @Nullable + public static RefMethod methodFromExternalName(RefManager manager, String externalName) { + return (RefMethod) manager.getReference(findPsiMethod(PsiManager.getInstance(manager.getProject()), externalName)); } - processed.add(this); - if (checkFlag(IS_LIBRARY_OVERRIDE_MASK)) { - return true; + @Nullable + public static PsiMethod findPsiMethod(PsiManager manager, String externalName) { + int spaceIdx = externalName.indexOf(' '); + String className = externalName.substring(0, spaceIdx); + PsiClass psiClass = ClassUtil.findPsiClass(manager, className); + if (psiClass == null) { + return null; + } + try { + PsiElementFactory factory = JavaPsiFacade.getInstance(psiClass.getProject()).getElementFactory(); + String methodSignature = externalName.substring(spaceIdx + 1); + PsiMethod patternMethod = factory.createMethodFromText(methodSignature, psiClass); + return psiClass.findMethodBySignature(patternMethod, false); + } + catch (IncorrectOperationException e) { + // Do nothing. Returning null is acceptable in this case. + return null; + } } - for (RefMethod superMethod : getSuperMethods()) { - if (((RefMethodImpl) superMethod).isLibraryOverride(processed)) { - setFlag(true, IS_LIBRARY_OVERRIDE_MASK); - return true; - } + + @Override + @RequiredReadAction + public void referenceRemoved() { + if (getOwnerClass() != null) { + ((RefClassImpl) getOwnerClass()).methodRemoved(this); + } + + super.referenceRemoved(); + + for (RefMethod superMethod : getSuperMethods()) { + superMethod.getDerivedMethods().remove(this); + } + + for (RefMethod subMethod : getDerivedMethods()) { + subMethod.getSuperMethods().remove(this); + } + + List deletedRefs = new ArrayList<>(); + for (RefParameter parameter : getParameters()) { + getRefManager().removeRefElement(parameter, deletedRefs); + } } - return false; - } + @Override + public boolean isSuspicious() { + //noinspection SimplifiableIfStatement + if (isConstructor() + && PsiModifier.PRIVATE.equals(getAccessModifier()) + && getParameters().length == 0 + && getOwnerClass().getConstructors().size() == 1) { + return false; + } + return super.isSuspicious(); + } - @Override - public boolean isAppMain() { - return checkFlag(IS_APPMAIN_MASK); - } + public void setReturnValueUsed(boolean value) { + if (checkFlag(IS_RETURN_VALUE_USED_MASK) == value) { + return; + } + setFlag(value, IS_RETURN_VALUE_USED_MASK); + for (RefMethod refSuper : getSuperMethods()) { + ((RefMethodImpl) refSuper).setReturnValueUsed(value); + } + } + + @Override + public boolean isReturnValueUsed() { + return checkFlag(IS_RETURN_VALUE_USED_MASK); + } - @Override - public boolean isAbstract() { - return checkFlag(IS_ABSTRACT_MASK); - } + @RequiredReadAction + public void updateReturnValueTemplate(PsiExpression expression) { + if (myReturnValueTemplate == null) { + return; + } - @Override - public boolean hasSuperMethods() { - return !getSuperMethods().isEmpty() || isExternalOverride(); - } + if (!getSuperMethods().isEmpty()) { + for (RefMethod refMethod : getSuperMethods()) { + RefMethodImpl refSuper = (RefMethodImpl) refMethod; + refSuper.updateReturnValueTemplate(expression); + } + } + else { + String newTemplate = null; + RefJavaUtil refUtil = RefJavaUtil.getInstance(); + if (expression instanceof PsiLiteralExpression literal) { + newTemplate = literal.getText(); + } + else if (expression instanceof PsiReferenceExpression referenceExpression) { + if (referenceExpression.resolve() instanceof PsiField field + && field.isStatic() && field.isFinal() + && refUtil.compareAccess(refUtil.getAccessModifier(field), getAccessModifier()) >= 0) { + newTemplate = PsiFormatUtil.formatVariable( + field, + PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_CONTAINING_CLASS | PsiFormatUtilBase.SHOW_FQ_NAME, + PsiSubstitutor.EMPTY + ); + } + } + else if (refUtil.isCallToSuperMethod(expression, (PsiMethod) getElement())) { + return; + } - @Override - public boolean isReferenced() { - // Directly called from somewhere.. - for (RefElement refCaller : getInReferences()) { - if (!getDerivedMethods().contains(refCaller)) { - return true; - } - } - - // Library override probably called from library code. - return isExternalOverride(); - } - - @Override - public boolean hasSuspiciousCallers() { - // Directly called from somewhere.. - for (RefElement refCaller : getInReferences()) { - if (((RefElementImpl) refCaller).isSuspicious() && !getDerivedMethods().contains(refCaller)) { - return true; - } - } - - // Library override probably called from library code. - if (isExternalOverride()) { - return true; + //noinspection StringEquality + if (myReturnValueTemplate == RETURN_VALUE_UNDEFINED) { + myReturnValueTemplate = newTemplate; + } + else if (!Comparing.equal(myReturnValueTemplate, newTemplate)) { + myReturnValueTemplate = null; + } + } } - // Class isn't instantiated. Most probably we have problem with class, not method. - if (!isStatic() && !isConstructor()) { - if (((RefClassImpl) getOwnerClass()).isSuspicious()) { - return true; - } + public void updateParameterValues(PsiExpression[] args) { + if (isExternalOverride()) { + return; + } - // Is an override. Probably called via reference to base class. - for (RefMethod refSuper : getSuperMethods()) { - if (((RefMethodImpl) refSuper).isSuspicious()) { - return true; + if (!getSuperMethods().isEmpty()) { + for (RefMethod refSuper : getSuperMethods()) { + ((RefMethodImpl) refSuper).updateParameterValues(args); + } + } + else { + RefParameter[] params = getParameters(); + if (params.length <= args.length && params.length > 0) { + for (int i = 0; i < args.length; i++) { + RefParameter refParameter; + if (params.length <= i) { + refParameter = params[params.length - 1]; + } + else { + refParameter = params[i]; + } + ((RefParameterImpl) refParameter).updateTemplateValue(args[i]); + } + } } - } } - return false; - } + @Override + public String getReturnValueIfSame() { + //noinspection StringEquality + if (myReturnValueTemplate == RETURN_VALUE_UNDEFINED) { + return null; + } + return myReturnValueTemplate; + } - @Override - public boolean isConstructor() { - return checkFlag(IS_CONSTRUCTOR_MASK); - } - - @Override - public RefClass getOwnerClass() { - return (RefClass) getOwner(); - } + public void updateThrowsList(PsiClassType exceptionType) { + if (!getSuperMethods().isEmpty()) { + for (RefMethod refSuper : getSuperMethods()) { + ((RefMethodImpl) refSuper).updateThrowsList(exceptionType); + } + } + else if (myUnThrownExceptions != null) { + if (exceptionType == null) { + myUnThrownExceptions = null; + return; + } + PsiClass exceptionClass = exceptionType.resolve(); + JavaPsiFacade facade = JavaPsiFacade.getInstance(myManager.getProject()); + for (int i = myUnThrownExceptions.size() - 1; i >= 0; i--) { + String exceptionFqn = myUnThrownExceptions.get(i); + PsiClass classType = facade.findClass(exceptionFqn, GlobalSearchScope.allScope(getRefManager().getProject())); + if (InheritanceUtil.isInheritorOrSelf(exceptionClass, classType, true) || InheritanceUtil.isInheritorOrSelf( + classType, + exceptionClass, + true + )) { + myUnThrownExceptions.remove(i); + } + } - @Override - public String getName() { - if (isValid()) { - final String[] result = new String[1]; - final Runnable runnable = new Runnable() { - @Override - public void run() { - PsiMethod psiMethod = (PsiMethod) getElement(); - /*if (psiMethod instanceof JspHolderMethod) { - result[0] = psiMethod.getName(); - } - else { */ - result[0] = PsiFormatUtil.formatMethod(psiMethod, PsiSubstitutor.EMPTY, PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_PARAMETERS, PsiFormatUtilBase.SHOW_TYPE); - // } + if (myUnThrownExceptions.isEmpty()) { + myUnThrownExceptions = null; + } } - }; + } - ApplicationManager.getApplication().runReadAction(runnable); + @Nullable + @Override + public PsiClass[] getUnThrownExceptions() { + if (myUnThrownExceptions == null) { + return null; + } + JavaPsiFacade facade = JavaPsiFacade.getInstance(myManager.getProject()); + List result = new ArrayList<>(myUnThrownExceptions.size()); + for (String exception : myUnThrownExceptions) { + PsiClass element = facade.findClass(exception, GlobalSearchScope.allScope(myManager.getProject())); + if (element != null) { + result.add(element); + } + } + return result.toArray(new PsiClass[result.size()]); + } + + public void setLibraryOverride(boolean libraryOverride) { + setFlag(libraryOverride, IS_LIBRARY_OVERRIDE_MASK); + } - return result[0]; - } else { - return super.getName(); - } - } - - @Override - public String getExternalName() { - final String[] result = new String[1]; - final Runnable runnable = new Runnable() { - @Override - public void run() { - final PsiMethod psiMethod = (PsiMethod) getElement(); - LOG.assertTrue(psiMethod != null); - result[0] = PsiFormatUtil.getExternalName(psiMethod); - } - }; - - ApplicationManager.getApplication().runReadAction(runnable); - - return result[0]; - } - - @Nullable - public static RefMethod methodFromExternalName(RefManager manager, String externalName) { - return (RefMethod) manager.getReference(findPsiMethod(PsiManager.getInstance(manager.getProject()), externalName)); - } - - @Nullable - public static PsiMethod findPsiMethod(PsiManager manager, String externalName) { - final int spaceIdx = externalName.indexOf(' '); - final String className = externalName.substring(0, spaceIdx); - final PsiClass psiClass = ClassUtil.findPsiClass(manager, className); - if (psiClass == null) { - return null; - } - try { - PsiElementFactory factory = JavaPsiFacade.getInstance(psiClass.getProject()).getElementFactory(); - String methodSignature = externalName.substring(spaceIdx + 1); - PsiMethod patternMethod = factory.createMethodFromText(methodSignature, psiClass); - return psiClass.findMethodBySignature(patternMethod, false); - } catch (IncorrectOperationException e) { - // Do nothing. Returning null is acceptable in this case. - return null; - } - } - - @Override - public void referenceRemoved() { - if (getOwnerClass() != null) { - ((RefClassImpl) getOwnerClass()).methodRemoved(this); - } - - super.referenceRemoved(); - - for (RefMethod superMethod : getSuperMethods()) { - superMethod.getDerivedMethods().remove(this); - } - - for (RefMethod subMethod : getDerivedMethods()) { - subMethod.getSuperMethods().remove(this); - } - - ArrayList deletedRefs = new ArrayList(); - for (RefParameter parameter : getParameters()) { - getRefManager().removeRefElement(parameter, deletedRefs); - } - } - - @Override - public boolean isSuspicious() { - if (isConstructor() && PsiModifier.PRIVATE.equals(getAccessModifier()) && getParameters().length == 0 && getOwnerClass().getConstructors().size() == 1) { - return false; - } - return super.isSuspicious(); - } - - public void setReturnValueUsed(boolean value) { - if (checkFlag(IS_RETURN_VALUE_USED_MASK) == value) { - return; - } - setFlag(value, IS_RETURN_VALUE_USED_MASK); - for (RefMethod refSuper : getSuperMethods()) { - ((RefMethodImpl) refSuper).setReturnValueUsed(value); - } - } - - @Override - public boolean isReturnValueUsed() { - return checkFlag(IS_RETURN_VALUE_USED_MASK); - } - - public void updateReturnValueTemplate(PsiExpression expression) { - if (myReturnValueTemplate == null) { - return; - } - - if (!getSuperMethods().isEmpty()) { - for (final RefMethod refMethod : getSuperMethods()) { - RefMethodImpl refSuper = (RefMethodImpl) refMethod; - refSuper.updateReturnValueTemplate(expression); - } - } else { - String newTemplate = null; - final RefJavaUtil refUtil = RefJavaUtil.getInstance(); - if (expression instanceof PsiLiteralExpression) { - PsiLiteralExpression psiLiteralExpression = (PsiLiteralExpression) expression; - newTemplate = psiLiteralExpression.getText(); - } else if (expression instanceof PsiReferenceExpression) { - PsiReferenceExpression referenceExpression = (PsiReferenceExpression) expression; - PsiElement resolved = referenceExpression.resolve(); - if (resolved instanceof PsiField) { - PsiField psiField = (PsiField) resolved; - if (psiField.hasModifierProperty(PsiModifier.STATIC) && - psiField.hasModifierProperty(PsiModifier.FINAL) && - refUtil.compareAccess(refUtil.getAccessModifier(psiField), getAccessModifier()) >= 0) { - newTemplate = PsiFormatUtil.formatVariable(psiField, PsiFormatUtilBase.SHOW_NAME | - PsiFormatUtilBase.SHOW_CONTAINING_CLASS | - PsiFormatUtilBase.SHOW_FQ_NAME, PsiSubstitutor.EMPTY); - } - } - } else if (refUtil.isCallToSuperMethod(expression, (PsiMethod) getElement())) { - return; - } - - //noinspection StringEquality - if (myReturnValueTemplate == RETURN_VALUE_UNDEFINED) { - myReturnValueTemplate = newTemplate; - } else if (!Comparing.equal(myReturnValueTemplate, newTemplate)) { - myReturnValueTemplate = null; - } - } - } - - public void updateParameterValues(PsiExpression[] args) { - if (isExternalOverride()) { - return; - } - - if (!getSuperMethods().isEmpty()) { - for (RefMethod refSuper : getSuperMethods()) { - ((RefMethodImpl) refSuper).updateParameterValues(args); - } - } else { - final RefParameter[] params = getParameters(); - if (params.length <= args.length && params.length > 0) { - for (int i = 0; i < args.length; i++) { - RefParameter refParameter; - if (params.length <= i) { - refParameter = params[params.length - 1]; - } else { - refParameter = params[i]; - } - ((RefParameterImpl) refParameter).updateTemplateValue(args[i]); - } - } - } - } - - @Override - public String getReturnValueIfSame() { - //noinspection StringEquality - if (myReturnValueTemplate == RETURN_VALUE_UNDEFINED) { - return null; - } - return myReturnValueTemplate; - } - - public void updateThrowsList(PsiClassType exceptionType) { - if (!getSuperMethods().isEmpty()) { - for (RefMethod refSuper : getSuperMethods()) { - ((RefMethodImpl) refSuper).updateThrowsList(exceptionType); - } - } else if (myUnThrownExceptions != null) { - if (exceptionType == null) { - myUnThrownExceptions = null; - return; - } - PsiClass exceptionClass = exceptionType.resolve(); - JavaPsiFacade facade = JavaPsiFacade.getInstance(myManager.getProject()); - for (int i = myUnThrownExceptions.size() - 1; i >= 0; i--) { - String exceptionFqn = myUnThrownExceptions.get(i); - PsiClass classType = facade.findClass(exceptionFqn, GlobalSearchScope.allScope(getRefManager().getProject())); - if (InheritanceUtil.isInheritorOrSelf(exceptionClass, classType, true) || InheritanceUtil.isInheritorOrSelf(classType, exceptionClass, true)) { - myUnThrownExceptions.remove(i); - } - } - - if (myUnThrownExceptions.isEmpty()) { - myUnThrownExceptions = null; - } - } - } - - @Override - @Nullable - public PsiClass[] getUnThrownExceptions() { - if (myUnThrownExceptions == null) { - return null; - } - JavaPsiFacade facade = JavaPsiFacade.getInstance(myManager.getProject()); - List result = new ArrayList(myUnThrownExceptions.size()); - for (String exception : myUnThrownExceptions) { - PsiClass element = facade.findClass(exception, GlobalSearchScope.allScope(myManager.getProject())); - if (element != null) { - result.add(element); - } - } - return result.toArray(new PsiClass[result.size()]); - } - - - public void setLibraryOverride(boolean libraryOverride) { - setFlag(libraryOverride, IS_LIBRARY_OVERRIDE_MASK); - } - - private void setAppMain(boolean appMain) { - setFlag(appMain, IS_APPMAIN_MASK); - } - - private void setAbstract(boolean anAbstract) { - setFlag(anAbstract, IS_ABSTRACT_MASK); - } - - public void setBodyEmpty(boolean bodyEmpty) { - setFlag(bodyEmpty, IS_BODY_EMPTY_MASK); - } - - private void setOnlyCallsSuper(boolean onlyCallsSuper) { - setFlag(onlyCallsSuper, IS_ONLY_CALLS_SUPER_MASK); - } - - - private void setConstructor(boolean constructor) { - setFlag(constructor, IS_CONSTRUCTOR_MASK); - } - - @Override - public boolean isTestMethod() { - return checkFlag(IS_TEST_METHOD_MASK); - } - - private void setTestMethod(boolean testMethod) { - setFlag(testMethod, IS_TEST_METHOD_MASK); - } - - @Override - public PsiModifierListOwner getElement() { - return (PsiModifierListOwner) super.getElement(); - } - - @Override - public boolean isCalledOnSubClass() { - return checkFlag(IS_CALLED_ON_SUBCLASS); - } - - public void setCalledOnSubClass(boolean isCalledOnSubClass) { - setFlag(isCalledOnSubClass, IS_CALLED_ON_SUBCLASS); - } + private void setAppMain(boolean appMain) { + setFlag(appMain, IS_APPMAIN_MASK); + } + private void setAbstract(boolean anAbstract) { + setFlag(anAbstract, IS_ABSTRACT_MASK); + } + + public void setBodyEmpty(boolean bodyEmpty) { + setFlag(bodyEmpty, IS_BODY_EMPTY_MASK); + } + + private void setOnlyCallsSuper(boolean onlyCallsSuper) { + setFlag(onlyCallsSuper, IS_ONLY_CALLS_SUPER_MASK); + } + + + private void setConstructor(boolean constructor) { + setFlag(constructor, IS_CONSTRUCTOR_MASK); + } + + @Override + public boolean isTestMethod() { + return checkFlag(IS_TEST_METHOD_MASK); + } + + private void setTestMethod(boolean testMethod) { + setFlag(testMethod, IS_TEST_METHOD_MASK); + } + + @Override + public PsiModifierListOwner getElement() { + return (PsiModifierListOwner) super.getElement(); + } + + @Override + public boolean isCalledOnSubClass() { + return checkFlag(IS_CALLED_ON_SUBCLASS); + } + + public void setCalledOnSubClass(boolean isCalledOnSubClass) { + setFlag(isCalledOnSubClass, IS_CALLED_ON_SUBCLASS); + } } diff --git a/plugin/src/main/java/com/intellij/java/impl/codeInspection/reference/RefJavaManagerImpl.java b/plugin/src/main/java/com/intellij/java/impl/codeInspection/reference/RefJavaManagerImpl.java index bccddb67c7..e335800dd9 100644 --- a/plugin/src/main/java/com/intellij/java/impl/codeInspection/reference/RefJavaManagerImpl.java +++ b/plugin/src/main/java/com/intellij/java/impl/codeInspection/reference/RefJavaManagerImpl.java @@ -33,6 +33,7 @@ import consulo.annotation.access.RequiredReadAction; import consulo.application.util.UserDataCache; import consulo.disposer.Disposer; +import consulo.java.analysis.impl.localize.JavaInspectionsLocalize; import consulo.language.editor.impl.inspection.reference.RefElementImpl; import consulo.language.editor.impl.inspection.reference.RefManagerImpl; import consulo.language.editor.impl.inspection.reference.RefProjectImpl; @@ -51,9 +52,8 @@ import consulo.language.util.IncorrectOperationException; import consulo.logging.Logger; import consulo.project.Project; -import consulo.util.lang.Comparing; import consulo.util.lang.Pair; -import consulo.util.lang.function.Conditions; +import consulo.util.lang.function.Predicates; import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; import org.jdom.Element; @@ -67,579 +67,477 @@ /** * @author anna - * Date: 20-Dec-2007 + * @since 2007-12-20 */ -public class RefJavaManagerImpl extends RefJavaManager -{ - private static final Logger LOG = Logger.getInstance(RefJavaManagerImpl.class); - private static final Predicate PROBLEM_ELEMENT_CONDITION = Conditions.or( - Conditions.instanceOf(PsiFile.class, PsiJavaModule.class), - Conditions.and( - Conditions.notInstanceOf(PsiTypeParameter.class), - psi -> (psi instanceof PsiField || !(psi instanceof PsiVariable)) && !(psi instanceof PsiClassInitializer) - ) - ); - - private PsiMethod myAppMainPattern; - private PsiMethod myAppPremainPattern; - private PsiClass myApplet; - private PsiClass myServlet; - private RefPackage myDefaultPackage; - private Map myPackages; - private final RefManagerImpl myRefManager; - private PsiElementVisitor myProjectIterator; - private EntryPointsManager myEntryPointsManager; - - public RefJavaManagerImpl(@Nonnull RefManagerImpl manager) - { - myRefManager = manager; - final Project project = manager.getProject(); - final PsiManager psiManager = PsiManager.getInstance(project); - JavaPsiFacade javaPsiFacade = JavaPsiFacade.getInstance(psiManager.getProject()); - PsiElementFactory factory = javaPsiFacade.getElementFactory(); - try - { - myAppMainPattern = factory.createMethodFromText("void main(String[] args);", null); - myAppPremainPattern = factory.createMethodFromText("void premain(String[] args, java.lang.instrument.Instrumentation i);", null); - } - catch (IncorrectOperationException e) - { - LOG.error(e); - } - - myApplet = javaPsiFacade.findClass("java.applet.Applet", GlobalSearchScope.allScope(project)); - myServlet = javaPsiFacade.findClass("javax.servlet.Servlet", GlobalSearchScope.allScope(project)); - } - - @Override - public RefPackage getPackage(String packageName) - { - if (myPackages == null) - { - myPackages = new HashMap<>(); - } - - RefPackage refPackage = myPackages.get(packageName); - if (refPackage == null) - { - refPackage = new RefPackageImpl(packageName, myRefManager); - myPackages.put(packageName, refPackage); - - int dotIndex = packageName.lastIndexOf('.'); - if (dotIndex >= 0) - { - ((RefPackageImpl) getPackage(packageName.substring(0, dotIndex))).add(refPackage); - } - else - { - ((RefProjectImpl) myRefManager.getRefProject()).add(refPackage); - } - } - - return refPackage; - } - - - public boolean isEntryPoint(final RefElement element) - { - Pair pair = getDeadCodeTool(element); - return pair != null && pair.getFirst() != null && pair.getFirst().isEntryPoint(element, pair.getSecond()); - } - - @Nullable - private Pair getDeadCodeTool(RefElement element) - { - PsiFile file = element.getContainingFile(); - return file == null ? null : getDeadCodeTool(file); - } - - private static final UserDataCache, PsiFile, RefManagerImpl> - DEAD_CODE_TOOL = new UserDataCache<>("DEAD_CODE_TOOL") - { - @Override - protected Pair compute(PsiFile file, RefManagerImpl refManager) - { - Tools tools = refManager.getContext().getTools(UnusedDeclarationInspection.SHORT_NAME); - InspectionToolWrapper toolWrapper = tools == null ? null : tools.getEnabledTool(file); - InspectionTool tool = toolWrapper == null ? null : toolWrapper.getTool(); - Object state = toolWrapper == null ? null : toolWrapper.getState(); - return tool instanceof UnusedDeclarationInspection inspection - ? Pair.createNonNull(inspection, (UnusedDeclarationInspectionState)state) - : Pair.empty(); - } - }; - - @Nullable - private Pair getDeadCodeTool(PsiElement element) - { - PsiFile file = element.getContainingFile(); - return file != null ? DEAD_CODE_TOOL.get(file, myRefManager) : null; - } - - @Nullable - @Override - public PsiNamedElement getElementContainer(@Nonnull PsiElement psiElement) - { - return (PsiNamedElement) PsiTreeUtil.findFirstParent(psiElement, PROBLEM_ELEMENT_CONDITION); - } - - @Override - public boolean shouldProcessExternalFile(@Nonnull PsiFile file) - { - return file instanceof PsiClassOwner; - } - - @Nonnull - @Override - public Stream extractExternalFileImplicitReferences(@Nonnull PsiFile psiFile) - { - return Arrays.stream(((PsiClassOwner) psiFile).getClasses()) - .flatMap(c -> Arrays.stream(c.getSuperTypes())) - .map(PsiClassType::resolve) - .filter(Objects::nonNull); - } - - @Override - public void markExternalReferencesProcessed(@Nonnull RefElement file) - { - getEntryPointsManager().addEntryPoint(file, false); - } - - @Override - public RefPackage getDefaultPackage() - { - if (myDefaultPackage == null) - { - myDefaultPackage = getPackage(InspectionLocalize.inspectionReferenceDefaultPackage().get()); - } - return myDefaultPackage; - } - - @Override - public PsiMethod getAppMainPattern() - { - return myAppMainPattern; - } - - @Override - public PsiMethod getAppPremainPattern() - { - return myAppPremainPattern; - } - - @Override - public PsiClass getApplet() - { - return myApplet; - } - - @Override - public PsiClass getServlet() - { - return myServlet; - } - - @Override - public RefParameter getParameterReference(PsiParameter param, int index, RefMethod refMethod) - { - LOG.assertTrue(myRefManager.isValidPointForReference(), "References may become invalid after process is finished"); - - return myRefManager.getFromRefTableOrCache(param, () -> { - RefParameterImpl ref = new RefParameterImpl(param, index, myRefManager, refMethod); - ref.initialize(); - return ref; - }); - } - - @Override - public void iterate(@Nonnull final RefVisitor visitor) - { - if (myPackages != null) - { - for (RefPackage refPackage : myPackages.values()) - { - refPackage.accept(visitor); - } - } - for (RefElement refElement : myRefManager.getSortedElements()) - { - if (refElement instanceof RefClass refClass) - { - RefMethod refDefaultConstructor = refClass.getDefaultConstructor(); - if (refDefaultConstructor instanceof RefImplicitConstructor) - { - refClass.getDefaultConstructor().accept(visitor); - } - } - } - } - - @Override - public void cleanup() - { - if (myEntryPointsManager != null) - { - Disposer.dispose(myEntryPointsManager); - myEntryPointsManager = null; - } - myPackages = null; - myApplet = null; - myAppMainPattern = null; - myAppPremainPattern = null; - myServlet = null; - myDefaultPackage = null; - myProjectIterator = null; - } - - @Override - public void removeReference(@Nonnull final RefElement refElement) - { - if (refElement instanceof RefMethod refMethod) - { - RefParameter[] params = refMethod.getParameters(); - for (RefParameter param : params) - { - myRefManager.removeReference(param); - } - } - } - - @Override - @Nullable - public RefElement createRefElement(@Nonnull final PsiElement elem) - { - if (elem instanceof PsiClass psiClass) - { - return new RefClassImpl(psiClass, myRefManager); - } - else if (elem instanceof PsiMethod method) - { - final RefElement ref = myRefManager.getReference(method.getContainingClass(), true); - if (ref instanceof RefClass refClass) - { - return new RefMethodImpl(refClass, method, myRefManager); - } - } - else if (elem instanceof PsiField field) - { - final RefElement ref = myRefManager.getReference(field.getContainingClass(), true); - if (ref instanceof RefClass refClass) - { - return new RefFieldImpl(refClass, field, myRefManager); - } - } - else if (elem instanceof PsiJavaFile javaFile) - { - return new RefJavaFileImpl(javaFile, myRefManager); - } - return null; - } - - @Override - @Nullable - public RefEntity getReference(final String type, final String fqName) - { - switch (type) { - case METHOD: - return RefMethodImpl.methodFromExternalName(myRefManager, fqName); - case CLASS: - return RefClassImpl.classFromExternalName(myRefManager, fqName); - case FIELD: - return RefFieldImpl.fieldFromExternalName(myRefManager, fqName); - case PARAMETER: - return RefParameterImpl.parameterFromExternalName(myRefManager, fqName); - case PACKAGE: - return RefPackageImpl.packageFromFQName(myRefManager, fqName); - } - return null; - } - - @Override - @Nullable - public String getType(@Nonnull final RefEntity ref) - { - if (ref instanceof RefMethod) - { - return METHOD; - } - else if (ref instanceof RefClass) - { - return CLASS; - } - else if (ref instanceof RefField) - { - return FIELD; - } - else if (ref instanceof RefParameter) - { - return PARAMETER; - } - else if (ref instanceof RefPackage) - { - return PACKAGE; - } - return null; - } - - @Nonnull - @Override - public RefEntity getRefinedElement(@Nonnull final RefEntity ref) - { - return ref instanceof RefImplicitConstructor implicitConstructor ? implicitConstructor.getOwnerClass() : ref; - } - - @Override - public void visitElement(@Nonnull final PsiElement element) - { - if (myProjectIterator == null) - { - myProjectIterator = new MyJavaElementVisitor(); - } - element.accept(myProjectIterator); - } - - @Override - @Nullable - public String getGroupName(@Nonnull final RefEntity entity) - { - return entity instanceof RefFile && !(entity instanceof RefJavaFileImpl) - ? null : RefJavaUtil.getInstance().getPackageName(entity); - } - - @Override - public boolean belongsToScope(@Nonnull final PsiElement psiElement) - { - return !(psiElement instanceof PsiTypeParameter); - } - - @RequiredReadAction - @Override - public void export(@Nonnull final RefEntity refEntity, @Nonnull final Element element) - { - if (refEntity instanceof RefElement refElement) - { - final SmartPsiElementPointer pointer = refElement.getPointer(); - if (pointer != null) - { - final PsiFile psiFile = pointer.getContainingFile(); - if (psiFile instanceof PsiJavaFile javaFile) - { - appendPackageElement(element, javaFile.getPackageName()); - } - } - } - } - - @Override - public void onEntityInitialized(@Nonnull RefElement refElement, @Nonnull PsiElement psiElement) - { - if (isEntryPoint(refElement)) - { - getEntryPointsManager().addEntryPoint(refElement, false); - } - - if (psiElement instanceof PsiClass psiClass) - { - EntryPointsManager entryPointsManager = getEntryPointsManager(); - if (psiClass.isAnnotationType()) - { - entryPointsManager.addEntryPoint(refElement, false); - for (PsiMethod psiMethod : psiClass.getMethods()) - { - entryPointsManager.addEntryPoint(myRefManager.getReference(psiMethod), false); - } - } - else if (psiClass.isEnum()) - { - entryPointsManager.addEntryPoint(refElement, false); - } - } - } - - private static void appendPackageElement(final Element element, final String packageName) - { - final Element packageElement = new Element("package"); - packageElement.addContent(packageName.isEmpty() ? InspectionLocalize.inspectionExportResultsDefault().get() : packageName); - element.addContent(packageElement); - } - - @Override - public EntryPointsManager getEntryPointsManager() - { - if (myEntryPointsManager == null) - { - final Project project = myRefManager.getProject(); - myEntryPointsManager = new EntryPointsManagerImpl(project); - ((EntryPointsManagerBase) myEntryPointsManager).addAllPersistentEntries(EntryPointsManagerBase.getInstance(project)); - } - return myEntryPointsManager; - } - - private class MyJavaElementVisitor extends JavaElementVisitor - { - private final RefJavaUtil myRefUtil; - - public MyJavaElementVisitor() - { - myRefUtil = RefJavaUtil.getInstance(); - } - - @Override - public void visitReferenceExpression(@Nonnull PsiReferenceExpression expression) - { - visitElement(expression); - } - - @Override - public void visitReferenceElement(@Nonnull PsiJavaCodeReferenceElement reference) - { - } - - @Override - public void visitReferenceParameterList(@Nonnull final PsiReferenceParameterList list) - { - super.visitReferenceParameterList(list); - final PsiMember member = PsiTreeUtil.getParentOfType(list, PsiMember.class); - final PsiType[] typeArguments = list.getTypeArguments(); - for (PsiType type : typeArguments) - { - myRefUtil.addTypeReference(member, type, myRefManager); - } - } - - @Override - public void visitClass(@Nonnull PsiClass aClass) - { - if (!(aClass instanceof PsiTypeParameter)) - { - super.visitClass(aClass); - RefElement refClass = myRefManager.getReference(aClass); - if (refClass != null) - { - ((RefClassImpl) refClass).buildReferences(); - } - } - } - - @Override - public void visitMethod(@Nonnull final PsiMethod method) - { - super.visitMethod(method); - final RefElement refElement = myRefManager.getReference(method); - if (refElement instanceof RefMethodImpl refMethod) - { - refMethod.buildReferences(); - } - } - - @Override - public void visitField(@Nonnull final PsiField field) - { - super.visitField(field); - final RefElement refElement = myRefManager.getReference(field); - if (refElement instanceof RefFieldImpl refField) - { - refField.buildReferences(); - } - } - - @Override - @RequiredReadAction - public void visitDocComment(@Nonnull PsiDocComment comment) - { - super.visitDocComment(comment); - final PsiDocTag[] tags = comment.getTags(); - for (PsiDocTag tag : tags) - { - if (Comparing.strEqual(tag.getName(), SuppressionUtil.SUPPRESS_INSPECTIONS_TAG_NAME)) - { - final PsiElement[] dataElements = tag.getDataElements(); - if (dataElements != null && dataElements.length > 0) - { - final PsiModifierListOwner listOwner = PsiTreeUtil.getParentOfType(comment, PsiModifierListOwner.class); - if (listOwner != null) - { - final RefElementImpl element = (RefElementImpl) myRefManager.getReference(listOwner); - if (element != null) - { - String suppression = ""; - for (PsiElement dataElement : dataElements) - { - suppression += "," + dataElement.getText(); - } - element.addSuppression(suppression); - } - } - } - } - } - } - - @Override - @RequiredReadAction - public void visitAnnotation(@Nonnull PsiAnnotation annotation) - { - super.visitAnnotation(annotation); - if (Comparing.strEqual(annotation.getQualifiedName(), BatchSuppressManager.SUPPRESS_INSPECTIONS_ANNOTATION_NAME)) - { - final PsiModifierListOwner listOwner = PsiTreeUtil.getParentOfType(annotation, PsiModifierListOwner.class); - if (listOwner != null) - { - final RefElementImpl element = (RefElementImpl) myRefManager.getReference(listOwner); - if (element != null) - { - StringBuilder buf = new StringBuilder(); - final PsiNameValuePair[] nameValuePairs = annotation.getParameterList().getAttributes(); - for (PsiNameValuePair nameValuePair : nameValuePairs) - { - buf.append(",").append(nameValuePair.getText().replaceAll("[{}\"\"]", "")); - } - if (buf.length() > 0) - { - element.addSuppression(buf.substring(1)); - } - } - } - } - } - - @Override - public void visitVariable(@Nonnull PsiVariable variable) - { - super.visitVariable(variable); - myRefUtil.addTypeReference(variable, variable.getType(), myRefManager); - } - - @Override - public void visitInstanceOfExpression(@Nonnull PsiInstanceOfExpression expression) - { - super.visitInstanceOfExpression(expression); - final PsiTypeElement typeElement = expression.getCheckType(); - if (typeElement != null) - { - myRefUtil.addTypeReference(expression, typeElement.getType(), myRefManager); - } - } - - @Override - @RequiredReadAction - public void visitThisExpression(@Nonnull PsiThisExpression expression) - { - super.visitThisExpression(expression); - final PsiJavaCodeReferenceElement qualifier = expression.getQualifier(); - if (qualifier != null) - { - myRefUtil.addTypeReference(expression, expression.getType(), myRefManager); - RefClass ownerClass = myRefUtil.getOwnerClass(myRefManager, expression); - if (ownerClass != null) - { - RefClassImpl refClass = (RefClassImpl) myRefManager.getReference(qualifier.resolve()); - if (refClass != null) - { - refClass.addInstanceReference(ownerClass); - } - } - } - } - } +public class RefJavaManagerImpl extends RefJavaManager { + private static final Logger LOG = Logger.getInstance(RefJavaManagerImpl.class); + private static final Predicate PROBLEM_ELEMENT_CONDITION = Predicates.or( + Predicates.instanceOf(PsiFile.class, PsiJavaModule.class), + Predicates.and( + Predicates.notInstanceOf(PsiTypeParameter.class), + psi -> (psi instanceof PsiField || !(psi instanceof PsiVariable)) && !(psi instanceof PsiClassInitializer) + ) + ); + + private PsiMethod myAppMainPattern; + private PsiMethod myAppPremainPattern; + private PsiClass myApplet; + private PsiClass myServlet; + private RefPackage myDefaultPackage; + private Map myPackages; + private final RefManagerImpl myRefManager; + private PsiElementVisitor myProjectIterator; + private EntryPointsManager myEntryPointsManager; + + public RefJavaManagerImpl(@Nonnull RefManagerImpl manager) { + myRefManager = manager; + Project project = manager.getProject(); + PsiManager psiManager = PsiManager.getInstance(project); + JavaPsiFacade javaPsiFacade = JavaPsiFacade.getInstance(psiManager.getProject()); + PsiElementFactory factory = javaPsiFacade.getElementFactory(); + try { + myAppMainPattern = factory.createMethodFromText("void main(String[] args);", null); + myAppPremainPattern = + factory.createMethodFromText("void premain(String[] args, java.lang.instrument.Instrumentation i);", null); + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + + myApplet = javaPsiFacade.findClass("java.applet.Applet", GlobalSearchScope.allScope(project)); + myServlet = javaPsiFacade.findClass("javax.servlet.Servlet", GlobalSearchScope.allScope(project)); + } + + @Override + public RefPackage getPackage(String packageName) { + if (myPackages == null) { + myPackages = new HashMap<>(); + } + + RefPackage refPackage = myPackages.get(packageName); + if (refPackage == null) { + refPackage = new RefPackageImpl(packageName, myRefManager); + myPackages.put(packageName, refPackage); + + int dotIndex = packageName.lastIndexOf('.'); + if (dotIndex >= 0) { + ((RefPackageImpl) getPackage(packageName.substring(0, dotIndex))).add(refPackage); + } + else { + ((RefProjectImpl) myRefManager.getRefProject()).add(refPackage); + } + } + + return refPackage; + } + + + public boolean isEntryPoint(RefElement element) { + Pair pair = getDeadCodeTool(element); + return pair != null && pair.getFirst() != null && pair.getFirst().isEntryPoint(element, pair.getSecond()); + } + + @Nullable + private Pair getDeadCodeTool(RefElement element) { + PsiFile file = element.getContainingFile(); + return file == null ? null : getDeadCodeTool(file); + } + + private static final UserDataCache, PsiFile, RefManagerImpl> + DEAD_CODE_TOOL = new UserDataCache<>("DEAD_CODE_TOOL") { + @Override + protected Pair compute(PsiFile file, RefManagerImpl refManager) { + Tools tools = refManager.getContext().getTools(UnusedDeclarationInspection.SHORT_NAME); + InspectionToolWrapper toolWrapper = tools == null ? null : tools.getEnabledTool(file); + InspectionTool tool = toolWrapper == null ? null : toolWrapper.getTool(); + Object state = toolWrapper == null ? null : toolWrapper.getState(); + return tool instanceof UnusedDeclarationInspection inspection + ? Pair.createNonNull(inspection, (UnusedDeclarationInspectionState) state) + : Pair.empty(); + } + }; + + @Nullable + private Pair getDeadCodeTool(PsiElement element) { + PsiFile file = element.getContainingFile(); + return file != null ? DEAD_CODE_TOOL.get(file, myRefManager) : null; + } + + @Nullable + @Override + public PsiNamedElement getElementContainer(@Nonnull PsiElement psiElement) { + return (PsiNamedElement) PsiTreeUtil.findFirstParent(psiElement, PROBLEM_ELEMENT_CONDITION); + } + + @Override + public boolean shouldProcessExternalFile(@Nonnull PsiFile file) { + return file instanceof PsiClassOwner; + } + + @Nonnull + @Override + public Stream extractExternalFileImplicitReferences(@Nonnull PsiFile psiFile) { + return Arrays.stream(((PsiClassOwner) psiFile).getClasses()) + .flatMap(c -> Arrays.stream(c.getSuperTypes())) + .map(PsiClassType::resolve) + .filter(Objects::nonNull); + } + + @Override + public void markExternalReferencesProcessed(@Nonnull RefElement file) { + getEntryPointsManager().addEntryPoint(file, false); + } + + @Override + public RefPackage getDefaultPackage() { + if (myDefaultPackage == null) { + myDefaultPackage = getPackage(JavaInspectionsLocalize.inspectionReferenceDefaultPackage().get()); + } + return myDefaultPackage; + } + + @Override + public PsiMethod getAppMainPattern() { + return myAppMainPattern; + } + + @Override + public PsiMethod getAppPremainPattern() { + return myAppPremainPattern; + } + + @Override + public PsiClass getApplet() { + return myApplet; + } + + @Override + public PsiClass getServlet() { + return myServlet; + } + + @Override + public RefParameter getParameterReference(PsiParameter param, int index, RefMethod refMethod) { + LOG.assertTrue(myRefManager.isValidPointForReference(), "References may become invalid after process is finished"); + + return myRefManager.getFromRefTableOrCache(param, () -> { + RefParameterImpl ref = new RefParameterImpl(param, index, myRefManager, refMethod); + ref.initialize(); + return ref; + }); + } + + @Override + public void iterate(@Nonnull RefVisitor visitor) { + if (myPackages != null) { + for (RefPackage refPackage : myPackages.values()) { + refPackage.accept(visitor); + } + } + for (RefElement refElement : myRefManager.getSortedElements()) { + if (refElement instanceof RefClass refClass) { + RefMethod refDefaultConstructor = refClass.getDefaultConstructor(); + if (refDefaultConstructor instanceof RefImplicitConstructor) { + refClass.getDefaultConstructor().accept(visitor); + } + } + } + } + + @Override + public void cleanup() { + if (myEntryPointsManager != null) { + Disposer.dispose(myEntryPointsManager); + myEntryPointsManager = null; + } + myPackages = null; + myApplet = null; + myAppMainPattern = null; + myAppPremainPattern = null; + myServlet = null; + myDefaultPackage = null; + myProjectIterator = null; + } + + @Override + @RequiredReadAction + public void removeReference(@Nonnull RefElement refElement) { + if (refElement instanceof RefMethod refMethod) { + RefParameter[] params = refMethod.getParameters(); + for (RefParameter param : params) { + myRefManager.removeReference(param); + } + } + } + + @Nullable + @Override + @RequiredReadAction + public RefElement createRefElement(@Nonnull PsiElement elem) { + if (elem instanceof PsiClass psiClass) { + return new RefClassImpl(psiClass, myRefManager); + } + else if (elem instanceof PsiMethod method) { + RefElement ref = myRefManager.getReference(method.getContainingClass(), true); + if (ref instanceof RefClass refClass) { + return new RefMethodImpl(refClass, method, myRefManager); + } + } + else if (elem instanceof PsiField field) { + RefElement ref = myRefManager.getReference(field.getContainingClass(), true); + if (ref instanceof RefClass refClass) { + return new RefFieldImpl(refClass, field, myRefManager); + } + } + else if (elem instanceof PsiJavaFile javaFile) { + return new RefJavaFileImpl(javaFile, myRefManager); + } + return null; + } + + @Override + @Nullable + public RefEntity getReference(String type, String fqName) { + return switch (type) { + case METHOD -> RefMethodImpl.methodFromExternalName(myRefManager, fqName); + case CLASS -> RefClassImpl.classFromExternalName(myRefManager, fqName); + case FIELD -> RefFieldImpl.fieldFromExternalName(myRefManager, fqName); + case PARAMETER -> RefParameterImpl.parameterFromExternalName(myRefManager, fqName); + case PACKAGE -> RefPackageImpl.packageFromFQName(myRefManager, fqName); + default -> null; + }; + } + + @Nullable + @Override + public String getType(@Nonnull RefEntity ref) { + if (ref instanceof RefMethod) { + return METHOD; + } + else if (ref instanceof RefClass) { + return CLASS; + } + else if (ref instanceof RefField) { + return FIELD; + } + else if (ref instanceof RefParameter) { + return PARAMETER; + } + else if (ref instanceof RefPackage) { + return PACKAGE; + } + return null; + } + + @Nonnull + @Override + public RefEntity getRefinedElement(@Nonnull RefEntity ref) { + return ref instanceof RefImplicitConstructor implicitConstructor ? implicitConstructor.getOwnerClass() : ref; + } + + @Override + public void visitElement(@Nonnull PsiElement element) { + if (myProjectIterator == null) { + myProjectIterator = new MyJavaElementVisitor(); + } + element.accept(myProjectIterator); + } + + @Override + @Nullable + public String getGroupName(@Nonnull RefEntity entity) { + return entity instanceof RefFile && !(entity instanceof RefJavaFileImpl) + ? null : RefJavaUtil.getInstance().getPackageName(entity); + } + + @Override + public boolean belongsToScope(@Nonnull PsiElement psiElement) { + return !(psiElement instanceof PsiTypeParameter); + } + + @RequiredReadAction + @Override + public void export(@Nonnull RefEntity refEntity, @Nonnull Element element) { + if (refEntity instanceof RefElement refElement) { + SmartPsiElementPointer pointer = refElement.getPointer(); + if (pointer != null) { + PsiFile psiFile = pointer.getContainingFile(); + if (psiFile instanceof PsiJavaFile javaFile) { + appendPackageElement(element, javaFile.getPackageName()); + } + } + } + } + + @Override + public void onEntityInitialized(@Nonnull RefElement refElement, @Nonnull PsiElement psiElement) { + if (isEntryPoint(refElement)) { + getEntryPointsManager().addEntryPoint(refElement, false); + } + + if (psiElement instanceof PsiClass psiClass) { + EntryPointsManager entryPointsManager = getEntryPointsManager(); + if (psiClass.isAnnotationType()) { + entryPointsManager.addEntryPoint(refElement, false); + for (PsiMethod psiMethod : psiClass.getMethods()) { + entryPointsManager.addEntryPoint(myRefManager.getReference(psiMethod), false); + } + } + else if (psiClass.isEnum()) { + entryPointsManager.addEntryPoint(refElement, false); + } + } + } + + private static void appendPackageElement(Element element, String packageName) { + Element packageElement = new Element("package"); + packageElement.addContent(packageName.isEmpty() ? InspectionLocalize.inspectionExportResultsDefault().get() : packageName); + element.addContent(packageElement); + } + + @Override + public EntryPointsManager getEntryPointsManager() { + if (myEntryPointsManager == null) { + Project project = myRefManager.getProject(); + myEntryPointsManager = new EntryPointsManagerImpl(project); + ((EntryPointsManagerBase) myEntryPointsManager).addAllPersistentEntries(EntryPointsManagerBase.getInstance(project)); + } + return myEntryPointsManager; + } + + private class MyJavaElementVisitor extends JavaElementVisitor { + private final RefJavaUtil myRefUtil; + + public MyJavaElementVisitor() { + myRefUtil = RefJavaUtil.getInstance(); + } + + @Override + public void visitReferenceExpression(@Nonnull PsiReferenceExpression expression) { + visitElement(expression); + } + + @Override + public void visitReferenceElement(@Nonnull PsiJavaCodeReferenceElement reference) { + } + + @Override + public void visitReferenceParameterList(@Nonnull PsiReferenceParameterList list) { + super.visitReferenceParameterList(list); + PsiMember member = PsiTreeUtil.getParentOfType(list, PsiMember.class); + PsiType[] typeArguments = list.getTypeArguments(); + for (PsiType type : typeArguments) { + myRefUtil.addTypeReference(member, type, myRefManager); + } + } + + @Override + public void visitClass(@Nonnull PsiClass aClass) { + if (!(aClass instanceof PsiTypeParameter)) { + super.visitClass(aClass); + RefElement refClass = myRefManager.getReference(aClass); + if (refClass != null) { + ((RefClassImpl) refClass).buildReferences(); + } + } + } + + @Override + @RequiredReadAction + public void visitMethod(@Nonnull PsiMethod method) { + super.visitMethod(method); + RefElement refElement = myRefManager.getReference(method); + if (refElement instanceof RefMethodImpl refMethod) { + refMethod.buildReferences(); + } + } + + @Override + public void visitField(@Nonnull PsiField field) { + super.visitField(field); + RefElement refElement = myRefManager.getReference(field); + if (refElement instanceof RefFieldImpl refField) { + refField.buildReferences(); + } + } + + @Override + @RequiredReadAction + public void visitDocComment(@Nonnull PsiDocComment comment) { + super.visitDocComment(comment); + PsiDocTag[] tags = comment.getTags(); + for (PsiDocTag tag : tags) { + if (SuppressionUtil.SUPPRESS_INSPECTIONS_TAG_NAME.equals(tag.getName())) { + PsiElement[] dataElements = tag.getDataElements(); + if (dataElements != null && dataElements.length > 0) { + PsiModifierListOwner listOwner = PsiTreeUtil.getParentOfType(comment, PsiModifierListOwner.class); + if (listOwner != null) { + RefElementImpl element = (RefElementImpl) myRefManager.getReference(listOwner); + if (element != null) { + String suppression = ""; + for (PsiElement dataElement : dataElements) { + suppression += "," + dataElement.getText(); + } + element.addSuppression(suppression); + } + } + } + } + } + } + + @Override + @RequiredReadAction + public void visitAnnotation(@Nonnull PsiAnnotation annotation) { + super.visitAnnotation(annotation); + if (BatchSuppressManager.SUPPRESS_INSPECTIONS_ANNOTATION_NAME.equals(annotation.getQualifiedName())) { + PsiModifierListOwner listOwner = PsiTreeUtil.getParentOfType(annotation, PsiModifierListOwner.class); + if (listOwner != null) { + RefElementImpl element = (RefElementImpl) myRefManager.getReference(listOwner); + if (element != null) { + StringBuilder buf = new StringBuilder(); + PsiNameValuePair[] nameValuePairs = annotation.getParameterList().getAttributes(); + for (PsiNameValuePair nameValuePair : nameValuePairs) { + buf.append(",").append(nameValuePair.getText().replaceAll("[{}\"\"]", "")); + } + if (buf.length() > 0) { + element.addSuppression(buf.substring(1)); + } + } + } + } + } + + @Override + public void visitVariable(@Nonnull PsiVariable variable) { + super.visitVariable(variable); + myRefUtil.addTypeReference(variable, variable.getType(), myRefManager); + } + + @Override + public void visitInstanceOfExpression(@Nonnull PsiInstanceOfExpression expression) { + super.visitInstanceOfExpression(expression); + PsiTypeElement typeElement = expression.getCheckType(); + if (typeElement != null) { + myRefUtil.addTypeReference(expression, typeElement.getType(), myRefManager); + } + } + + @Override + @RequiredReadAction + public void visitThisExpression(@Nonnull PsiThisExpression expression) { + super.visitThisExpression(expression); + PsiJavaCodeReferenceElement qualifier = expression.getQualifier(); + if (qualifier != null) { + myRefUtil.addTypeReference(expression, expression.getType(), myRefManager); + RefClass ownerClass = myRefUtil.getOwnerClass(myRefManager, expression); + if (ownerClass != null) { + RefClassImpl refClass = (RefClassImpl) myRefManager.getReference(qualifier.resolve()); + if (refClass != null) { + refClass.addInstanceReference(ownerClass); + } + } + } + } + } } diff --git a/plugin/src/main/java/com/intellij/java/impl/codeInspection/reference/RefJavaUtilImpl.java b/plugin/src/main/java/com/intellij/java/impl/codeInspection/reference/RefJavaUtilImpl.java index 4b8c467dff..2a53d76f7c 100644 --- a/plugin/src/main/java/com/intellij/java/impl/codeInspection/reference/RefJavaUtilImpl.java +++ b/plugin/src/main/java/com/intellij/java/impl/codeInspection/reference/RefJavaUtilImpl.java @@ -30,8 +30,7 @@ import com.intellij.java.language.util.VisibilityUtil; import consulo.annotation.access.RequiredReadAction; import consulo.annotation.component.ServiceImpl; -import consulo.language.editor.impl.inspection.reference.RefElementImpl; -import consulo.language.editor.inspection.localize.InspectionLocalize; +import consulo.java.analysis.impl.localize.JavaInspectionsLocalize; import consulo.language.editor.inspection.reference.*; import consulo.language.psi.PsiElement; import consulo.language.psi.scope.GlobalSearchScope; @@ -43,13 +42,13 @@ @Singleton @ServiceImpl public class RefJavaUtilImpl extends RefJavaUtil { - - @Override - public void addReferences(final PsiModifierListOwner psiFrom, final RefJavaElement ref, @Nullable PsiElement findIn) { - final RefJavaElementImpl refFrom = (RefJavaElementImpl) ref; - if (findIn != null) { - findIn.accept( - new JavaRecursiveElementWalkingVisitor() { + @Override + public void addReferences(final PsiModifierListOwner psiFrom, RefJavaElement ref, @Nullable PsiElement findIn) { + final RefJavaElementImpl refFrom = (RefJavaElementImpl) ref; + if (findIn == null) { + return; + } + findIn.accept(new JavaRecursiveElementWalkingVisitor() { @Override public void visitReferenceElement(@Nonnull PsiJavaCodeReferenceElement reference) { } @@ -57,377 +56,384 @@ public void visitReferenceElement(@Nonnull PsiJavaCodeReferenceElement reference @Override @RequiredReadAction public void visitReferenceExpression(PsiReferenceExpression expression) { - visitElement(expression); + visitElement(expression); - PsiElement psiResolved = expression.resolve(); + PsiElement psiResolved = expression.resolve(); - if (psiResolved instanceof PsiModifierListOwner) { - if (isDeprecated(psiResolved)) refFrom.setUsesDeprecatedApi(true); - } + if (psiResolved instanceof PsiModifierListOwner && isDeprecated(psiResolved)) { + refFrom.setUsesDeprecatedApi(true); + } - RefElement refResolved = refFrom.getRefManager().getReference(psiResolved); - refFrom.addReference( - refResolved, psiResolved, psiFrom, PsiUtil.isAccessedForWriting(expression), - PsiUtil.isAccessedForReading(expression), expression - ); + RefElement refResolved = refFrom.getRefManager().getReference(psiResolved); + refFrom.addReference( + refResolved, psiResolved, psiFrom, PsiUtil.isAccessedForWriting(expression), + PsiUtil.isAccessedForReading(expression), expression + ); - if (refResolved instanceof RefMethod) { - updateRefMethod(psiResolved, refResolved, expression, psiFrom, refFrom); - } + if (refResolved instanceof RefMethod) { + updateRefMethod(psiResolved, refResolved, expression, psiFrom, refFrom); + } } - @Override public void visitEnumConstant(@Nonnull PsiEnumConstant enumConstant) { - super.visitEnumConstant(enumConstant); - processNewLikeConstruct(enumConstant.resolveConstructor(), enumConstant.getArgumentList()); + super.visitEnumConstant(enumConstant); + processNewLikeConstruct(enumConstant.resolveConstructor(), enumConstant.getArgumentList()); } @Override public void visitNewExpression(@Nonnull PsiNewExpression newExpr) { - super.visitNewExpression(newExpr); - PsiMethod psiConstructor = newExpr.resolveConstructor(); - final PsiExpressionList argumentList = newExpr.getArgumentList(); + super.visitNewExpression(newExpr); + PsiMethod psiConstructor = newExpr.resolveConstructor(); + PsiExpressionList argumentList = newExpr.getArgumentList(); - RefMethod refConstructor = processNewLikeConstruct(psiConstructor, argumentList); + RefMethod refConstructor = processNewLikeConstruct(psiConstructor, argumentList); - if (refConstructor == null) { // No explicit constructor referenced. Should use default one. - PsiType newType = newExpr.getType(); - if (newType instanceof PsiClassType) { - processClassReference(PsiUtil.resolveClassInType(newType), refFrom, psiFrom, true); + // No explicit constructor referenced. Should use default one. + if (refConstructor == null && newExpr.getType() instanceof PsiClassType newType) { + processClassReference(PsiUtil.resolveClassInType(newType), refFrom, psiFrom, true); } - } } @Nullable - private RefMethod processNewLikeConstruct(final PsiMethod psiConstructor, final PsiExpressionList argumentList) { - if (psiConstructor != null) { - if (isDeprecated(psiConstructor)) refFrom.setUsesDeprecatedApi(true); - } - - RefMethodImpl refConstructor = (RefMethodImpl) refFrom.getRefManager().getReference( - psiConstructor - ); - refFrom.addReference(refConstructor, psiConstructor, psiFrom, false, true, null); - - if (argumentList != null) { - PsiExpression[] psiParams = argumentList.getExpressions(); - for (PsiExpression param : psiParams) { - param.accept(this); + private RefMethod processNewLikeConstruct(PsiMethod psiConstructor, PsiExpressionList argumentList) { + if (psiConstructor != null && isDeprecated(psiConstructor)) { + refFrom.setUsesDeprecatedApi(true); } - if (refConstructor != null) { - refConstructor.updateParameterValues(psiParams); + RefMethodImpl refConstructor = (RefMethodImpl) refFrom.getRefManager().getReference( + psiConstructor + ); + refFrom.addReference(refConstructor, psiConstructor, psiFrom, false, true, null); + + if (argumentList != null) { + PsiExpression[] psiParams = argumentList.getExpressions(); + for (PsiExpression param : psiParams) { + param.accept(this); + } + + if (refConstructor != null) { + refConstructor.updateParameterValues(psiParams); + } } - } - return refConstructor; + return refConstructor; } @Override - public void visitAnonymousClass(PsiAnonymousClass psiClass) { - super.visitAnonymousClass(psiClass); - RefClassImpl refClass = (RefClassImpl) refFrom.getRefManager().getReference(psiClass); - refFrom.addReference(refClass, psiClass, psiFrom, false, true, null); + public void visitAnonymousClass(@Nonnull PsiAnonymousClass psiClass) { + super.visitAnonymousClass(psiClass); + RefClassImpl refClass = (RefClassImpl) refFrom.getRefManager().getReference(psiClass); + refFrom.addReference(refClass, psiClass, psiFrom, false, true, null); } @Override - public void visitReturnStatement(PsiReturnStatement statement) { - super.visitReturnStatement(statement); + @RequiredReadAction + public void visitReturnStatement(@Nonnull PsiReturnStatement statement) { + super.visitReturnStatement(statement); - if (refFrom instanceof RefMethodImpl refMethod) { - refMethod.updateReturnValueTemplate(statement.getReturnValue()); - } + if (refFrom instanceof RefMethodImpl refMethod) { + refMethod.updateReturnValueTemplate(statement.getReturnValue()); + } } @Override - public void visitClassObjectAccessExpression(PsiClassObjectAccessExpression expression) { - super.visitClassObjectAccessExpression(expression); - final PsiTypeElement operand = expression.getOperand(); - final PsiType type = operand.getType(); - if (type instanceof PsiClassType classType) { - processClassReference(classType.resolve(), refFrom, psiFrom, false); - } + public void visitClassObjectAccessExpression(@Nonnull PsiClassObjectAccessExpression expression) { + super.visitClassObjectAccessExpression(expression); + PsiTypeElement operand = expression.getOperand(); + if (operand.getType() instanceof PsiClassType classType) { + processClassReference(classType.resolve(), refFrom, psiFrom, false); + } } private void processClassReference( - final PsiClass psiClass, - final RefJavaElementImpl refFrom, - final PsiModifierListOwner psiFrom, - boolean defaultConstructorOnly + PsiClass psiClass, + RefJavaElementImpl refFrom, + PsiModifierListOwner psiFrom, + boolean defaultConstructorOnly ) { - if (psiClass != null) { - RefClassImpl refClass = (RefClassImpl) refFrom.getRefManager().getReference(psiClass); - - if (refClass != null) { - boolean hasConstructorsMarked = false; - - if (defaultConstructorOnly) { - RefMethodImpl refDefaultConstructor = (RefMethodImpl) refClass.getDefaultConstructor(); - if (refDefaultConstructor != null && !(refDefaultConstructor instanceof RefImplicitConstructor)) { - refDefaultConstructor.addInReference(refFrom); - refFrom.addOutReference(refDefaultConstructor); - hasConstructorsMarked = true; - } - } else { - for (RefMethod cons : refClass.getConstructors()) { - if (cons instanceof RefImplicitConstructor) continue; - ((RefMethodImpl) cons).addInReference(refFrom); - refFrom.addOutReference(cons); - hasConstructorsMarked = true; + if (psiClass != null) { + RefClassImpl refClass = (RefClassImpl) refFrom.getRefManager().getReference(psiClass); + + if (refClass != null) { + boolean hasConstructorsMarked = false; + + if (defaultConstructorOnly) { + RefMethodImpl refDefaultConstructor = (RefMethodImpl) refClass.getDefaultConstructor(); + if (refDefaultConstructor != null && !(refDefaultConstructor instanceof RefImplicitConstructor)) { + refDefaultConstructor.addInReference(refFrom); + refFrom.addOutReference(refDefaultConstructor); + hasConstructorsMarked = true; + } + } + else { + for (RefMethod cons : refClass.getConstructors()) { + if (cons instanceof RefImplicitConstructor) { + continue; + } + ((RefMethodImpl) cons).addInReference(refFrom); + refFrom.addOutReference(cons); + hasConstructorsMarked = true; + } + } + + if (!hasConstructorsMarked) { + refFrom.addReference(refClass, psiClass, psiFrom, false, true, null); + } } - } - - if (!hasConstructorsMarked) { - refFrom.addReference(refClass, psiClass, psiFrom, false, true, null); - } } - } } - } - ); + }); } - } - - private void updateRefMethod( - PsiElement psiResolved, - RefElement refResolved, - PsiElement refExpression, - final PsiElement psiFrom, - final RefElement refFrom - ) { - PsiMethod psiMethod = (PsiMethod) psiResolved; - RefMethodImpl refMethod = (RefMethodImpl) refResolved; - - PsiMethodCallExpression call = PsiTreeUtil.getParentOfType( - refExpression, - PsiMethodCallExpression.class - ); - if (call != null) { - PsiType returnType = psiMethod.getReturnType(); - if (!psiMethod.isConstructor() && !PsiType.VOID.equals(returnType)) { - if (!(call.getParent() instanceof PsiExpressionStatement)) { - refMethod.setReturnValueUsed(true); - } - addTypeReference(psiFrom, returnType, refFrom.getRefManager()); - } - - PsiExpressionList argumentList = call.getArgumentList(); - if (argumentList.getExpressions().length > 0) { - refMethod.updateParameterValues(argumentList.getExpressions()); - } - - final PsiExpression psiExpression = call.getMethodExpression().getQualifierExpression(); - if (psiExpression != null) { - final PsiType usedType = psiExpression.getType(); - if (usedType != null) { - final String fqName = psiMethod.getContainingClass().getQualifiedName(); - if (fqName != null) { - final PsiClassType methodOwnerType = JavaPsiFacade.getInstance(call.getProject()).getElementFactory() - .createTypeByFQClassName(fqName, GlobalSearchScope.allScope(psiMethod.getProject())); - if (!usedType.equals(methodOwnerType)) { - refMethod.setCalledOnSubClass(true); + private void updateRefMethod( + PsiElement psiResolved, + RefElement refResolved, + PsiElement refExpression, + PsiElement psiFrom, + RefElement refFrom + ) { + PsiMethod psiMethod = (PsiMethod) psiResolved; + RefMethodImpl refMethod = (RefMethodImpl) refResolved; + + PsiMethodCallExpression call = PsiTreeUtil.getParentOfType( + refExpression, + PsiMethodCallExpression.class + ); + if (call != null) { + PsiType returnType = psiMethod.getReturnType(); + if (!psiMethod.isConstructor() && !PsiType.VOID.equals(returnType)) { + if (!(call.getParent() instanceof PsiExpressionStatement)) { + refMethod.setReturnValueUsed(true); + } + + addTypeReference(psiFrom, returnType, refFrom.getRefManager()); + } + + PsiExpressionList argumentList = call.getArgumentList(); + if (argumentList.getExpressions().length > 0) { + refMethod.updateParameterValues(argumentList.getExpressions()); + } + + PsiExpression psiExpression = call.getMethodExpression().getQualifierExpression(); + if (psiExpression != null) { + PsiType usedType = psiExpression.getType(); + if (usedType != null) { + String fqName = psiMethod.getContainingClass().getQualifiedName(); + if (fqName != null) { + PsiClassType methodOwnerType = JavaPsiFacade.getInstance(call.getProject()).getElementFactory() + .createTypeByFQClassName(fqName, GlobalSearchScope.allScope(psiMethod.getProject())); + if (!usedType.equals(methodOwnerType)) { + refMethod.setCalledOnSubClass(true); + } + } + } } - } } - } } - } + @Override + public RefClass getTopLevelClass(RefElement refElement) { + RefEntity refParent = refElement.getOwner(); - @Override - public RefClass getTopLevelClass(RefElement refElement) { - RefEntity refParent = refElement.getOwner(); + while (refParent != null && refParent instanceof RefElement refParentElement && !(refParent instanceof RefFile)) { + refElement = refParentElement; + refParent = refParent.getOwner(); + } - while (refParent != null && refParent instanceof RefElement refParentElement && !(refParent instanceof RefFile)) { - refElement = refParentElement; - refParent = refParent.getOwner(); + return (RefClass) refElement; } - return (RefClass) refElement; - } + @Override + public boolean isInheritor(RefClass subClass, RefClass superClass) { + if (subClass == superClass) { + return true; + } - @Override - public boolean isInheritor(RefClass subClass, RefClass superClass) { - if (subClass == superClass) return true; + for (RefClass baseClass : subClass.getBaseClasses()) { + if (isInheritor(baseClass, superClass)) { + return true; + } + } - for (RefClass baseClass : subClass.getBaseClasses()) { - if (isInheritor(baseClass, superClass)) return true; + return false; } - return false; - } + @Nullable + @Override + public String getPackageName(RefEntity refEntity) { + if (refEntity instanceof RefProject) { + return null; + } + RefPackage refPackage = getPackage(refEntity); - @Override - @Nullable - public String getPackageName(RefEntity refEntity) { - if (refEntity instanceof RefProject) { - return null; + return refPackage == null ? JavaInspectionsLocalize.inspectionReferenceDefaultPackage().get() : refPackage.getQualifiedName(); } - RefPackage refPackage = getPackage(refEntity); - return refPackage == null ? InspectionLocalize.inspectionReferenceDefaultPackage().get() : refPackage.getQualifiedName(); - } + @Override + @RequiredReadAction + public String getAccessModifier(PsiModifierListOwner element) { + if (element instanceof PsiParameter) { + return PsiModifier.PACKAGE_LOCAL; + } - @Override - public String getAccessModifier(PsiModifierListOwner psiElement) { - if (psiElement instanceof PsiParameter) { - return PsiModifier.PACKAGE_LOCAL; + if (element.hasModifierProperty(PsiModifier.PRIVATE)) { + return PsiModifier.PRIVATE; + } + else if (element.hasModifierProperty(PsiModifier.PROTECTED)) { + return PsiModifier.PROTECTED; + } + else if (element.hasModifierProperty(PsiModifier.PUBLIC)) { + return PsiModifier.PUBLIC; + } + else if (element.getParent() instanceof PsiClass parentClass && parentClass.isInterface()) { + return PsiModifier.PUBLIC; + } + + return PsiModifier.PACKAGE_LOCAL; } - PsiModifierList list = psiElement.getModifierList(); - String result = PsiModifier.PACKAGE_LOCAL; - - if (list != null) { - if (list.hasModifierProperty(PsiModifier.PRIVATE)) { - result = PsiModifier.PRIVATE; - } else if (list.hasModifierProperty(PsiModifier.PROTECTED)) { - result = PsiModifier.PROTECTED; - } else if (list.hasModifierProperty(PsiModifier.PUBLIC)) { - result = PsiModifier.PUBLIC; - } else if (psiElement.getParent() instanceof PsiClass parentClass) { - PsiClass ownerClass = parentClass; - if (ownerClass.isInterface()) { - result = PsiModifier.PUBLIC; + @Nullable + @Override + public RefClass getOwnerClass(RefManager refManager, PsiElement psiElement) { + while (psiElement != null && !(psiElement instanceof PsiClass)) { + psiElement = psiElement.getParent(); } - } + + return psiElement != null ? (RefClass) refManager.getReference(psiElement) : null; } - return result; - } + @Nullable + @Override + public RefClass getOwnerClass(RefElement refElement) { + RefEntity parent = refElement.getOwner(); + + while (!(parent instanceof RefClass) && parent instanceof RefElement) { + parent = parent.getOwner(); + } - @Override - @Nullable - public RefClass getOwnerClass(RefManager refManager, PsiElement psiElement) { - while (psiElement != null && !(psiElement instanceof PsiClass)) { - psiElement = psiElement.getParent(); + return parent instanceof RefClass refClass ? refClass : null; } - return psiElement != null ? (RefClass) refManager.getReference(psiElement) : null; - } + @Override + @RequiredReadAction + public boolean isMethodOnlyCallsSuper(PsiMethod method) { + boolean hasStatements = false; + PsiCodeBlock body = method.getBody(); + if (body != null) { + PsiStatement[] statements = body.getStatements(); + for (PsiStatement statement : statements) { + boolean isCallToSameSuper = false; + if (statement instanceof PsiExpressionStatement expressionStatement) { + isCallToSameSuper = isCallToSuperMethod(expressionStatement.getExpression(), method); + } + else if (statement instanceof PsiReturnStatement returnStatement) { + PsiExpression expression = returnStatement.getReturnValue(); + isCallToSameSuper = expression == null || isCallToSuperMethod(expression, method); + } - @Override - @Nullable - public RefClass getOwnerClass(RefElement refElement) { - RefEntity parent = refElement.getOwner(); + hasStatements = true; + if (isCallToSameSuper) { + continue; + } - while (!(parent instanceof RefClass) && parent instanceof RefElement) { - parent = parent.getOwner(); - } + return false; + } + } - return parent instanceof RefClass refClass ? refClass : null; - } - - - @Override - public boolean isMethodOnlyCallsSuper(PsiMethod method) { - boolean hasStatements = false; - PsiCodeBlock body = method.getBody(); - if (body != null) { - PsiStatement[] statements = body.getStatements(); - for (PsiStatement statement : statements) { - boolean isCallToSameSuper = false; - if (statement instanceof PsiExpressionStatement expressionStatement) { - isCallToSameSuper = isCallToSuperMethod(expressionStatement.getExpression(), method); - } else if (statement instanceof PsiReturnStatement returnStatement) { - PsiExpression expression = returnStatement.getReturnValue(); - isCallToSameSuper = expression == null || isCallToSuperMethod(expression, method); + if (hasStatements) { + for (PsiMethod superMethod : method.findSuperMethods()) { + if (VisibilityUtil.compare( + VisibilityUtil.getVisibilityModifier(superMethod.getModifierList()), + VisibilityUtil.getVisibilityModifier(method.getModifierList()) + ) > 0) { + return false; + } + } } + return hasStatements; + } + + @Override + @RequiredReadAction + public boolean isCallToSuperMethod(PsiExpression expression, PsiMethod method) { + if (expression instanceof PsiMethodCallExpression methodCall) { + PsiReferenceExpression methodExpression = methodCall.getMethodExpression(); + if (methodExpression.getQualifierExpression() instanceof PsiSuperExpression) { + PsiMethod superMethod = (PsiMethod) methodExpression.resolve(); + if (superMethod == null || !MethodSignatureUtil.areSignaturesEqual(method, superMethod)) { + return false; + } + PsiExpression[] args = methodCall.getArgumentList().getExpressions(); + PsiParameter[] params = method.getParameterList().getParameters(); + + for (int i = 0, n = args.length; i < n; i++) { + if (args[i] instanceof PsiReferenceExpression refExpr && params[i].equals(refExpr.resolve())) { + continue; + } + return false; + } - hasStatements = true; - if (isCallToSameSuper) continue; + return true; + } + } return false; - } } - if (hasStatements) { - final PsiMethod[] superMethods = method.findSuperMethods(); - for (PsiMethod superMethod : superMethods) { - if (VisibilityUtil.compare(VisibilityUtil.getVisibilityModifier(superMethod.getModifierList()), - VisibilityUtil.getVisibilityModifier(method.getModifierList())) > 0) return false; - } + @Override + public int compareAccess(String a1, String a2) { + return Integer.compare(getAccessNumber(a1), getAccessNumber(a2)); } - return hasStatements; - } - - @Override - @RequiredReadAction - public boolean isCallToSuperMethod(PsiExpression expression, PsiMethod method) { - if (expression instanceof PsiMethodCallExpression methodCall) { - if (methodCall.getMethodExpression().getQualifierExpression() instanceof PsiSuperExpression) { - PsiMethod superMethod = (PsiMethod) methodCall.getMethodExpression().resolve(); - if (superMethod == null || !MethodSignatureUtil.areSignaturesEqual(method, superMethod)) return false; - PsiExpression[] args = methodCall.getArgumentList().getExpressions(); - PsiParameter[] parms = method.getParameterList().getParameters(); - - for (int i = 0; i < args.length; i++) { - PsiExpression arg = args[i]; - if (!(arg instanceof PsiReferenceExpression)) return false; - if (!parms[i].equals(((PsiReferenceExpression) arg).resolve())) return false; + + @SuppressWarnings("StringEquality") + private static int getAccessNumber(String a) { + if (a == PsiModifier.PRIVATE) { + return 0; + } + else if (a == PsiModifier.PACKAGE_LOCAL) { + return 1; } + else if (a == PsiModifier.PROTECTED) { + return 2; + } + else if (a == PsiModifier.PUBLIC) { + return 3; + } + + return -1; + } - return true; - } + @Override + public void setAccessModifier(RefJavaElement refElement, String newAccess) { + ((RefJavaElementImpl) refElement).setAccessModifier(newAccess); } - return false; - } - - @Override - public int compareAccess(String a1, String a2) { - int i1 = getAccessNumber(a1); - int i2 = getAccessNumber(a2); - - if (i1 == i2) return 0; - if (i1 < i2) return -1; - return 1; - } - - @SuppressWarnings("StringEquality") - private static int getAccessNumber(String a) { - if (a == PsiModifier.PRIVATE) { - return 0; - } else if (a == PsiModifier.PACKAGE_LOCAL) { - return 1; - } else if (a == PsiModifier.PROTECTED) { - return 2; - } else if (a == PsiModifier.PUBLIC) return 3; - - return -1; - } - - @Override - public void setAccessModifier(RefJavaElement refElement, String newAccess) { - ((RefJavaElementImpl) refElement).setAccessModifier(newAccess); - } - - @Override - public void setIsStatic(RefJavaElement refElement, boolean isStatic) { - ((RefJavaElementImpl) refElement).setIsStatic(isStatic); - } - - @Override - public void setIsFinal(RefJavaElement refElement, boolean isFinal) { - ((RefJavaElementImpl) refElement).setIsFinal(isFinal); - } - - @Override - public void addTypeReference(PsiElement psiElement, PsiType psiType, RefManager refManager) { - RefClass ownerClass = getOwnerClass(refManager, psiElement); - - if (ownerClass != null) { - psiType = psiType.getDeepComponentType(); - - if (psiType instanceof PsiClassType) { - PsiClass psiClass = PsiUtil.resolveClassInType(psiType); - if (psiClass != null && refManager.belongsToScope(psiClass)) { - RefClassImpl refClass = (RefClassImpl) refManager.getReference(psiClass); - if (refClass != null) { - refClass.addTypeReference(ownerClass); - } + @Override + public void setIsStatic(RefJavaElement refElement, boolean isStatic) { + ((RefJavaElementImpl) refElement).setIsStatic(isStatic); + } + + @Override + public void setIsFinal(RefJavaElement refElement, boolean isFinal) { + ((RefJavaElementImpl) refElement).setIsFinal(isFinal); + } + + @Override + public void addTypeReference(PsiElement psiElement, PsiType psiType, RefManager refManager) { + RefClass ownerClass = getOwnerClass(refManager, psiElement); + + if (ownerClass != null) { + psiType = psiType.getDeepComponentType(); + + if (psiType instanceof PsiClassType) { + PsiClass psiClass = PsiUtil.resolveClassInType(psiType); + if (psiClass != null && refManager.belongsToScope(psiClass)) { + RefClassImpl refClass = (RefClassImpl) refManager.getReference(psiClass); + if (refClass != null) { + refClass.addTypeReference(ownerClass); + } + } + } } - } } - } }