From 5b962a018fa623688e6ce29ef2a14736a84f43c8 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Mon, 5 Jun 2017 12:31:23 +0300 Subject: [PATCH] method return always constants (IDEA-173896) ensure external derivatives are not ignored, do not report on derivatives - report on api method, don't visit same methods multiple times --- .../siyeh/InspectionGadgetsBundle.properties | 2 +- .../MethodReturnAlwaysConstantInspection.java | 68 ++++++++++--------- .../MethodReturnAlwaysConstant.html | 2 +- 3 files changed, 38 insertions(+), 34 deletions(-) diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties index 3828297a94dd..d067787d0e95 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties @@ -1448,7 +1448,7 @@ integer.multiplication.implicit.cast.to.long.option=Ignore compile time co wait.or.await.without.timeout.display.name='wait()' or 'await()' without timeout wait.or.await.without.timeout.problem.descriptor=#ref without timeout #loc method.return.always.constant.display.name=Method returns per-class constant -method.return.always.constant.problem.descriptor=Method #ref() returns a per-class constant +method.return.always.constant.problem.descriptor=Method #ref() and all it's derivables always return constants class.with.too.many.dependencies.display.name=Class with too many dependencies class.with.too.many.dependencies.problem.descriptor=Class ''{0}'' has too many dependencies ({1} > {2}) class.with.too.many.transitive.dependencies.display.name=Class with too many transitive dependencies diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/MethodReturnAlwaysConstantInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/MethodReturnAlwaysConstantInspection.java index fbced3b0f8c0..b475ee5d422f 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/MethodReturnAlwaysConstantInspection.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/classlayout/MethodReturnAlwaysConstantInspection.java @@ -17,9 +17,7 @@ package com.siyeh.ig.classlayout; import com.intellij.analysis.AnalysisScope; import com.intellij.codeInspection.*; -import com.intellij.codeInspection.reference.RefEntity; -import com.intellij.codeInspection.reference.RefMethod; -import com.intellij.openapi.util.Key; +import com.intellij.codeInspection.reference.*; import com.intellij.psi.*; import com.intellij.psi.util.PsiUtil; import com.siyeh.InspectionGadgetsBundle; @@ -34,14 +32,10 @@ import java.util.Set; public class MethodReturnAlwaysConstantInspection extends BaseGlobalInspection { - private static final Key ALWAYS_CONSTANT = - Key.create("ALWAYS_CONSTANT"); - @NotNull @Override public String getDisplayName() { - return InspectionGadgetsBundle.message( - "method.return.always.constant.display.name"); + return InspectionGadgetsBundle.message("method.return.always.constant.display.name"); } @Override @@ -51,35 +45,24 @@ public class MethodReturnAlwaysConstantInspection extends BaseGlobalInspection { if (!(refEntity instanceof RefMethod)) { return null; } - final RefMethod refMethod = (RefMethod)refEntity; - final Boolean alreadyProcessed = refMethod.getUserData(ALWAYS_CONSTANT); - if (alreadyProcessed != null && alreadyProcessed.booleanValue()) { + //don't warn on overriders + if (((RefMethod)refEntity).hasSuperMethods()) { return null; } + final RefMethod refMethod = (RefMethod)refEntity; if (!(refMethod.getElement() instanceof PsiMethod)) { return null; } - final PsiMethod method = (PsiMethod)refMethod.getElement(); - if (method.getBody() == null) { - return null; //we'll catch it on another method - } - if (!alwaysReturnsConstant(method)) { - return null; - } - final Set siblingMethods = - MethodInheritanceUtils.calculateSiblingMethods(refMethod); - for (RefMethod siblingMethod : siblingMethods) { - final PsiMethod siblingPsiMethod = - (PsiMethod)siblingMethod.getElement(); - if (method.getBody() != null && - !alwaysReturnsConstant(siblingPsiMethod)) { + final Set allScopeInheritors = MethodInheritanceUtils.calculateSiblingMethods(refMethod); + for (RefMethod siblingMethod : allScopeInheritors) { + final PsiMethod siblingPsiMethod = (PsiMethod)siblingMethod.getElement(); + if (siblingPsiMethod.getBody() != null && !alwaysReturnsConstant(siblingPsiMethod)) { return null; } } final List out = new ArrayList<>(); - for (RefMethod siblingRefMethod : siblingMethods) { - final PsiMethod siblingMethod = - (PsiMethod)siblingRefMethod.getElement(); + for (RefMethod siblingRefMethod : allScopeInheritors) { + final PsiMethod siblingMethod = (PsiMethod)siblingRefMethod.getElement(); final PsiIdentifier identifier = siblingMethod.getNameIdentifier(); if (identifier == null) { continue; @@ -88,8 +71,6 @@ public class MethodReturnAlwaysConstantInspection extends BaseGlobalInspection { InspectionGadgetsBundle.message( "method.return.always.constant.problem.descriptor"), false, null, ProblemHighlightType.GENERIC_ERROR_OR_WARNING)); - siblingRefMethod.putUserData(ALWAYS_CONSTANT, - Boolean.valueOf(true)); } return out.toArray(new ProblemDescriptor[out.size()]); } @@ -100,9 +81,32 @@ public class MethodReturnAlwaysConstantInspection extends BaseGlobalInspection { if (!(statement instanceof PsiReturnStatement)) { return false; } - final PsiReturnStatement returnStatement = - (PsiReturnStatement)statement; + final PsiReturnStatement returnStatement = (PsiReturnStatement)statement; final PsiExpression value = returnStatement.getReturnValue(); return value != null && PsiUtil.isConstantExpression(value); } + + @Override + protected boolean queryExternalUsagesRequests(@NotNull final RefManager manager, @NotNull final GlobalJavaInspectionContext globalContext, + @NotNull final ProblemDescriptionsProcessor processor) { + manager.iterate(new RefJavaVisitor() { + @Override public void visitElement(@NotNull RefEntity refEntity) { + if (refEntity instanceof RefElement && processor.getDescriptions(refEntity) != null) { + refEntity.accept(new RefJavaVisitor() { + @Override public void visitMethod(@NotNull final RefMethod refMethod) { + globalContext.enqueueDerivedMethodsProcessor(refMethod, new GlobalJavaInspectionContext.DerivedMethodsProcessor() { + @Override + public boolean process(PsiMethod derivedMethod) { + processor.ignoreElement(refMethod); + return false; + } + }); + } + }); + } + } + }); + + return false; + } } diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/MethodReturnAlwaysConstant.html b/plugins/InspectionGadgets/src/inspectionDescriptions/MethodReturnAlwaysConstant.html index 05c7d7cbdbcc..a48b19716916 100644 --- a/plugins/InspectionGadgets/src/inspectionDescriptions/MethodReturnAlwaysConstant.html +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/MethodReturnAlwaysConstant.html @@ -1,6 +1,6 @@ -Reports methods which only ever return a constant. +Reports methods which only ever return a constant, probably different for different inheritors. Because this inspection requires global code analysis it is only available for Analyze|Inspect Code or Analyze|Run Inspection by Name and it will not report in the editor.