From 1f9e8cbc6dd137949ac2841131e676e9b23c8ca6 Mon Sep 17 00:00:00 2001 From: Anna Kozlova Date: Fri, 14 Jun 2013 14:41:29 +0400 Subject: [PATCH] option to ignore fields used in multiple methods to be converted to local (IDEA-108517) --- .../FieldCanBeLocalInspection.java | 32 +++++++++++++------ .../fieldUsedForWritingInLambda/src/Test.java | 15 ++++----- .../fieldCanBeLocal/twoMethods/src/Test.java | 15 +++++---- .../expected.xml | 9 ++++++ .../src/Test.java | 13 ++++++++ .../codeInspection/FieldCanBeLocalTest.java | 9 ++++++ 6 files changed, 68 insertions(+), 25 deletions(-) create mode 100644 java/java-tests/testData/inspection/fieldCanBeLocal/twoMethodsNotIgnoreMultipleMethods/expected.xml create mode 100644 java/java-tests/testData/inspection/fieldCanBeLocal/twoMethodsNotIgnoreMultipleMethods/src/Test.java diff --git a/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/FieldCanBeLocalInspection.java b/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/FieldCanBeLocalInspection.java index 9090cc9cdb1b..8eb519864e91 100644 --- a/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/FieldCanBeLocalInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/varScopeCanBeNarrowed/FieldCanBeLocalInspection.java @@ -22,6 +22,7 @@ import com.intellij.codeInspection.InspectionsBundle; import com.intellij.codeInspection.ProblemDescriptor; import com.intellij.codeInspection.ProblemsHolder; import com.intellij.codeInspection.ex.BaseLocalInspectionTool; +import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel; import com.intellij.codeInspection.util.SpecialAnnotationsUtil; import com.intellij.lang.java.JavaCommenter; import com.intellij.openapi.extensions.Extensions; @@ -57,6 +58,7 @@ import java.util.Set; public class FieldCanBeLocalInspection extends BaseLocalInspectionTool { @NonNls public static final String SHORT_NAME = "FieldCanBeLocal"; public final JDOMExternalizableStringList EXCLUDE_ANNOS = new JDOMExternalizableStringList(); + public boolean IGNORE_FIELDS_USED_IN_MULTIPLE_METHODS = true; @Override @NotNull @@ -78,7 +80,7 @@ public class FieldCanBeLocalInspection extends BaseLocalInspectionTool { @Override public void writeSettings(@NotNull Element node) throws WriteExternalException { - if (!EXCLUDE_ANNOS.isEmpty()) { + if (!EXCLUDE_ANNOS.isEmpty() || !IGNORE_FIELDS_USED_IN_MULTIPLE_METHODS) { super.writeSettings(node); } } @@ -90,6 +92,7 @@ public class FieldCanBeLocalInspection extends BaseLocalInspectionTool { .createSpecialAnnotationsListControl(EXCLUDE_ANNOS, InspectionsBundle.message("special.annotations.annotations.list")); final JPanel panel = new JPanel(new BorderLayout(2, 2)); + panel.add(new SingleCheckboxOptionsPanel("Ignore fields used in multiple methods", this, "IGNORE_FIELDS_USED_IN_MULTIPLE_METHODS"), BorderLayout.NORTH); panel.add(listPanel, BorderLayout.CENTER); return panel; } @@ -101,13 +104,16 @@ public class FieldCanBeLocalInspection extends BaseLocalInspectionTool { @Override public void visitJavaFile(PsiJavaFile file) { for (PsiClass aClass : file.getClasses()) { - doCheckClass(aClass, holder, EXCLUDE_ANNOS); + doCheckClass(aClass, holder, EXCLUDE_ANNOS, IGNORE_FIELDS_USED_IN_MULTIPLE_METHODS); } } }; } - private static void doCheckClass(final PsiClass aClass, ProblemsHolder holder, final List excludeAnnos) { + private static void doCheckClass(final PsiClass aClass, + ProblemsHolder holder, + final List excludeAnnos, + boolean ignoreFieldsUsedInMultipleMethods) { if (aClass.isInterface()) return; final PsiField[] fields = aClass.getFields(); final Set candidates = new LinkedHashSet(); @@ -125,7 +131,7 @@ public class FieldCanBeLocalInspection extends BaseLocalInspectionTool { if (candidates.isEmpty()) return; final Set usedFields = new THashSet(); - removeReadFields(aClass, candidates, usedFields); + removeReadFields(aClass, candidates, usedFields, ignoreFieldsUsedInMultipleMethods); if (candidates.isEmpty()) return; final ImplicitUsageProvider[] implicitUsageProviders = Extensions.getExtensions(ImplicitUsageProvider.EP_NAME); @@ -138,7 +144,10 @@ public class FieldCanBeLocalInspection extends BaseLocalInspectionTool { } } - private static void removeReadFields(PsiClass aClass, final Set candidates, final Set usedFields) { + private static void removeReadFields(PsiClass aClass, + final Set candidates, + final Set usedFields, + final boolean ignoreFieldsUsedInMultipleMethods) { aClass.accept(new JavaRecursiveElementWalkingVisitor() { @Override public void visitElement(PsiElement element) { @@ -151,7 +160,7 @@ public class FieldCanBeLocalInspection extends BaseLocalInspectionTool { final PsiCodeBlock body = method.getBody(); if (body != null) { - checkCodeBlock(body, candidates, usedFields); + checkCodeBlock(body, candidates, usedFields, ignoreFieldsUsedInMultipleMethods); } } @@ -160,26 +169,29 @@ public class FieldCanBeLocalInspection extends BaseLocalInspectionTool { super.visitLambdaExpression(expression); final PsiElement body = expression.getBody(); if (body != null) { - checkCodeBlock(body, candidates, usedFields); + checkCodeBlock(body, candidates, usedFields, ignoreFieldsUsedInMultipleMethods); } } @Override public void visitClassInitializer(PsiClassInitializer initializer) { super.visitClassInitializer(initializer); - checkCodeBlock(initializer.getBody(), candidates, usedFields); + checkCodeBlock(initializer.getBody(), candidates, usedFields, ignoreFieldsUsedInMultipleMethods); } }); } - private static void checkCodeBlock(final PsiElement body, final Set candidates, Set usedFields) { + private static void checkCodeBlock(final PsiElement body, + final Set candidates, + Set usedFields, + boolean ignoreFieldsUsedInMultipleMethods) { try { final ControlFlow controlFlow = ControlFlowFactory.getInstance(body.getProject()).getControlFlow(body, AllVariablesControlFlowPolicy.getInstance()); final List usedVars = ControlFlowUtil.getUsedVariables(controlFlow, 0, controlFlow.getSize()); for (PsiVariable usedVariable : usedVars) { if (usedVariable instanceof PsiField) { final PsiField usedField = (PsiField)usedVariable; - if (!usedFields.add(usedField)) { + if (!usedFields.add(usedField) && ignoreFieldsUsedInMultipleMethods) { candidates.remove(usedField); //used in more than one code block } } diff --git a/java/java-tests/testData/inspection/fieldCanBeLocal/fieldUsedForWritingInLambda/src/Test.java b/java/java-tests/testData/inspection/fieldCanBeLocal/fieldUsedForWritingInLambda/src/Test.java index 30467475a42b..94df44e854ea 100644 --- a/java/java-tests/testData/inspection/fieldCanBeLocal/fieldUsedForWritingInLambda/src/Test.java +++ b/java/java-tests/testData/inspection/fieldCanBeLocal/fieldUsedForWritingInLambda/src/Test.java @@ -1,13 +1,10 @@ class Test { - private int f; + private int f; - void foo () { - f = 0; - int k = f; - } + public void bar() { + foo(() -> {f++;}); + } - int bar () { - f = 5; - return f; - } + private void foo(Runnable r) { + } } diff --git a/java/java-tests/testData/inspection/fieldCanBeLocal/twoMethods/src/Test.java b/java/java-tests/testData/inspection/fieldCanBeLocal/twoMethods/src/Test.java index 94df44e854ea..30467475a42b 100644 --- a/java/java-tests/testData/inspection/fieldCanBeLocal/twoMethods/src/Test.java +++ b/java/java-tests/testData/inspection/fieldCanBeLocal/twoMethods/src/Test.java @@ -1,10 +1,13 @@ class Test { - private int f; + private int f; - public void bar() { - foo(() -> {f++;}); - } + void foo () { + f = 0; + int k = f; + } - private void foo(Runnable r) { - } + int bar () { + f = 5; + return f; + } } diff --git a/java/java-tests/testData/inspection/fieldCanBeLocal/twoMethodsNotIgnoreMultipleMethods/expected.xml b/java/java-tests/testData/inspection/fieldCanBeLocal/twoMethodsNotIgnoreMultipleMethods/expected.xml new file mode 100644 index 000000000000..3f5c95bb9d78 --- /dev/null +++ b/java/java-tests/testData/inspection/fieldCanBeLocal/twoMethodsNotIgnoreMultipleMethods/expected.xml @@ -0,0 +1,9 @@ + + + + Test.java + 2 + Field can be converted to a local variable + + + diff --git a/java/java-tests/testData/inspection/fieldCanBeLocal/twoMethodsNotIgnoreMultipleMethods/src/Test.java b/java/java-tests/testData/inspection/fieldCanBeLocal/twoMethodsNotIgnoreMultipleMethods/src/Test.java new file mode 100644 index 000000000000..30467475a42b --- /dev/null +++ b/java/java-tests/testData/inspection/fieldCanBeLocal/twoMethodsNotIgnoreMultipleMethods/src/Test.java @@ -0,0 +1,13 @@ +class Test { + private int f; + + void foo () { + f = 0; + int k = f; + } + + int bar () { + f = 5; + return f; + } +} diff --git a/java/java-tests/testSrc/com/intellij/codeInspection/FieldCanBeLocalTest.java b/java/java-tests/testSrc/com/intellij/codeInspection/FieldCanBeLocalTest.java index 3cef83133c78..e6c17b9143f2 100644 --- a/java/java-tests/testSrc/com/intellij/codeInspection/FieldCanBeLocalTest.java +++ b/java/java-tests/testSrc/com/intellij/codeInspection/FieldCanBeLocalTest.java @@ -20,6 +20,11 @@ public class FieldCanBeLocalTest extends InspectionTestCase { public void testSimple () throws Exception { doTest(); } public void testTwoMethods () throws Exception { doTest(); } + public void testTwoMethodsNotIgnoreMultipleMethods () throws Exception { + final FieldCanBeLocalInspection inspection = new FieldCanBeLocalInspection(); + inspection.IGNORE_FIELDS_USED_IN_MULTIPLE_METHODS = false; + doTestConfigured(inspection); + } public void testConstructor () throws Exception { doTest(); } public void testStaticFinal() throws Exception { doTest(); } @@ -35,6 +40,10 @@ public class FieldCanBeLocalTest extends InspectionTestCase { public void testFieldUsedForWritingInLambda() throws Exception {doTest();} public void testIgnoreAnnotated() throws Exception { final FieldCanBeLocalInspection inspection = new FieldCanBeLocalInspection(); + doTestConfigured(inspection); + } + + private void doTestConfigured(FieldCanBeLocalInspection inspection) { inspection.EXCLUDE_ANNOS.add(Deprecated.class.getName()); doTest("fieldCanBeLocal/" + getTestName(true), inspection); }