effectively final: check usages inside inner classes/lambdas (IDEA-122686)

This commit is contained in:
Anna Kozlova
2014-03-24 20:22:25 +01:00
parent aa6dbcd24a
commit b500c13eb0
5 changed files with 34 additions and 10 deletions
@@ -675,7 +675,7 @@ public class HighlightControlFlowUtil {
return null;
}
public static boolean isEffectivelyFinal(PsiVariable variable, PsiElement scope, PsiJavaCodeReferenceElement context) {
public static boolean isEffectivelyFinal(PsiVariable variable, PsiElement scope, @Nullable PsiJavaCodeReferenceElement context) {
boolean effectivelyFinal;
if (variable instanceof PsiParameter) {
effectivelyFinal = notAccessedForWriting(variable, new LocalSearchScope(((PsiParameter)variable).getDeclarationScope()));
@@ -15,16 +15,18 @@
*/
package com.siyeh.ig.dataflow;
import com.intellij.codeInsight.daemon.impl.analysis.HighlightControlFlowUtil;
import com.intellij.codeInspection.ui.MultipleCheckboxOptionsPanel;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.DefaultJDOMExternalizer;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.psi.*;
import com.intellij.psi.search.LocalSearchScope;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.util.xmlb.XmlSerializer;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.BaseInspection;
import com.siyeh.ig.BaseInspectionVisitor;
@@ -162,11 +164,17 @@ public class UnnecessaryLocalVariableInspectionBase extends BaseInspection {
VariableAccessUtils.variableIsAssigned(initialization, containingScope, false)) {
return false;
}
if (!initialization.hasModifierProperty(PsiModifier.FINAL) && variable.hasModifierProperty(PsiModifier.FINAL)) {
if (VariableAccessUtils.variableIsUsedInInnerClass(variable, containingScope)) {
return false;
if (!initialization.hasModifierProperty(PsiModifier.FINAL) && variable.hasModifierProperty(PsiModifier.FINAL) ||
PsiUtil.isLanguageLevel8OrHigher(initialization) && !HighlightControlFlowUtil.isEffectivelyFinal(initialization, containingScope, null) && HighlightControlFlowUtil.isEffectivelyFinal(variable, containingScope, null)) {
for (PsiReference ref : ReferencesSearch.search(variable, new LocalSearchScope(containingScope))) {
final PsiElement element = PsiTreeUtil.getParentOfType(ref.getElement(), PsiClass.class, PsiLambdaExpression.class);
if (element != null && PsiTreeUtil.isAncestor(containingScope, element, true)) {
return false;
}
}
}
return !TypeConversionUtil.boxingConversionApplicable(variable.getType(), initialization.getType());
}
@@ -115,4 +115,15 @@ class C {
System.out.println(k);
}
void usedIn8Inner(int j) {
for (int i = 0; i < 7; i++) {
int k = i;
int n = j;
class F {
{
System.out.println(k + n);
}
}
}
}
}
@@ -119,4 +119,10 @@
<description>Local variable &lt;code&gt;k&lt;/code&gt; is redundant #loc</description>
</problem>
<problem>
<file>C.java</file>
<line>121</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Redundant local variable</problem_class>
<description>Local variable &lt;code&gt;n&lt;/code&gt; is redundant #loc</description>
</problem>
</problems>
@@ -15,18 +15,17 @@
*/
package com.siyeh.ig.dataflow;
import com.intellij.testFramework.IdeaTestUtil;
import com.siyeh.ig.IGInspectionTestCase;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.projectRoots.impl.JavaSdkImpl;
import com.intellij.openapi.roots.LanguageLevelProjectExtension;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.testFramework.IdeaTestUtil;
import com.siyeh.ig.IGInspectionTestCase;
public class UnnecessaryLocalVariableInspectionTest extends IGInspectionTestCase {
@Override
protected Sdk getTestProjectSdk() {
final Sdk sdk = IdeaTestUtil.getMockJdk17();
LanguageLevelProjectExtension.getInstance(getProject()).setLanguageLevel(LanguageLevel.JDK_1_7);
LanguageLevelProjectExtension.getInstance(getProject()).setLanguageLevel(LanguageLevel.HIGHEST);
return sdk;
}