From bd5e9ca16bbf28000c71997967cb2e66b01f00c2 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Tue, 4 Feb 2025 15:18:02 +0100 Subject: [PATCH] Java: make "Field can be local variable" Flexible Constructor Bodies aware (IDEA-364189) GitOrigin-RevId: 370bf973497cc428ff1fa8047684c62e793941be --- .../FieldCanBeLocalInspection.java | 26 +++++++------------ .../fieldCanBeLocal/ConstructorThisRef2.java | 10 +++++++ .../codeInspection/FieldCanBeLocalTest.java | 7 +++++ 3 files changed, 27 insertions(+), 16 deletions(-) create mode 100644 java/java-tests/testData/inspection/fieldCanBeLocal/ConstructorThisRef2.java diff --git a/java/java-impl-inspections/src/com/intellij/codeInspection/varScopeCanBeNarrowed/FieldCanBeLocalInspection.java b/java/java-impl-inspections/src/com/intellij/codeInspection/varScopeCanBeNarrowed/FieldCanBeLocalInspection.java index 3a3316657316..c621f79fb2ac 100644 --- a/java/java-impl-inspections/src/com/intellij/codeInspection/varScopeCanBeNarrowed/FieldCanBeLocalInspection.java +++ b/java/java-impl-inspections/src/com/intellij/codeInspection/varScopeCanBeNarrowed/FieldCanBeLocalInspection.java @@ -19,6 +19,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.JDOMExternalizableStringList; import com.intellij.openapi.util.WriteExternalException; +import com.intellij.pom.java.JavaFeature; import com.intellij.psi.*; import com.intellij.psi.codeStyle.JavaCodeStyleManager; import com.intellij.psi.codeStyle.VariableKind; @@ -43,14 +44,11 @@ public final class FieldCanBeLocalInspection extends AbstractBaseJavaLocalInspec public final JDOMExternalizableStringList EXCLUDE_ANNOS = new JDOMExternalizableStringList(); public boolean IGNORE_FIELDS_USED_IN_MULTIPLE_METHODS = true; - private void doCheckClass(PsiClass aClass, - ProblemsHolder holder, - List excludeAnnos, - boolean ignoreFieldsUsedInMultipleMethods) { + private void doCheckClass(PsiClass aClass, ProblemsHolder holder) { if (aClass.isInterface()) return; - final Set candidates = new LinkedHashSet<>(); + final Set candidates = new HashSet<>(); for (PsiField field : aClass.getFields()) { - if (!field.isPhysical() || AnnotationUtil.isAnnotated(field, excludeAnnos, 0)) { + if (!field.isPhysical() || AnnotationUtil.isAnnotated(field, EXCLUDE_ANNOS, 0)) { continue; } if (field.hasModifierProperty(PsiModifier.VOLATILE)) { @@ -63,16 +61,16 @@ public final class FieldCanBeLocalInspection extends AbstractBaseJavaLocalInspec candidates.add(field); } } + if (candidates.isEmpty()) return; removeFieldsReferencedFromInitializers(aClass, aClass, candidates); if (candidates.isEmpty()) return; final Set usedFields = new HashSet<>(); - removeReadFields(aClass, candidates, usedFields, ignoreFieldsUsedInMultipleMethods); - + removeReadFields(aClass, candidates, usedFields, IGNORE_FIELDS_USED_IN_MULTIPLE_METHODS); if (candidates.isEmpty()) return; - final List implicitUsageProviders = ImplicitUsageProvider.EP_NAME.getExtensionList(); + final List implicitUsageProviders = ImplicitUsageProvider.EP_NAME.getExtensionList(); final PsiClass scope = findVariableScope(aClass); FieldLoop: @@ -120,8 +118,7 @@ public final class FieldCanBeLocalInspection extends AbstractBaseJavaLocalInspec root.accept(new JavaRecursiveElementWalkingVisitor() { @Override public void visitMethod(@NotNull PsiMethod method) { - - if (method.isConstructor()) { + if (method.isConstructor() && !PsiUtil.isAvailable(JavaFeature.STATEMENTS_BEFORE_SUPER, method)) { final PsiCodeBlock body = method.getBody(); if (body != null) { final PsiStatement[] statements = body.getStatements(); @@ -156,7 +153,6 @@ public final class FieldCanBeLocalInspection extends AbstractBaseJavaLocalInspec @Override public void visitReferenceExpression(@NotNull PsiReferenceExpression expression) { excludeFieldCandidate(expression); - super.visitReferenceExpression(expression); } @@ -167,9 +163,7 @@ public final class FieldCanBeLocalInspection extends AbstractBaseJavaLocalInspec } private void excludeFieldCandidate(PsiReference ref) { - if (ref == null) return; - final PsiElement resolved = ref.resolve(); - if (resolved instanceof PsiField field && aClass.equals(field.getContainingClass())) { + if (ref != null && ref.resolve() instanceof PsiField field && aClass.equals(field.getContainingClass())) { candidates.remove(field); } } @@ -339,7 +333,7 @@ public final class FieldCanBeLocalInspection extends AbstractBaseJavaLocalInspec @Override public void visitClass(@NotNull PsiClass aClass) { super.visitClass(aClass); - doCheckClass(aClass, holder, EXCLUDE_ANNOS, IGNORE_FIELDS_USED_IN_MULTIPLE_METHODS); + doCheckClass(aClass, holder); } }; } diff --git a/java/java-tests/testData/inspection/fieldCanBeLocal/ConstructorThisRef2.java b/java/java-tests/testData/inspection/fieldCanBeLocal/ConstructorThisRef2.java new file mode 100644 index 000000000000..f94015829d15 --- /dev/null +++ b/java/java-tests/testData/inspection/fieldCanBeLocal/ConstructorThisRef2.java @@ -0,0 +1,10 @@ +class ClassName { + private static String SOME_CONSTANT = "XXX"; + + public ClassName() { + this(SOME_CONSTANT); + } + + public ClassName(String somethingElse) { + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/codeInspection/FieldCanBeLocalTest.java b/java/java-tests/testSrc/com/intellij/java/codeInspection/FieldCanBeLocalTest.java index 18ae633f94cb..b1c5deb88c46 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInspection/FieldCanBeLocalTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInspection/FieldCanBeLocalTest.java @@ -4,6 +4,8 @@ package com.intellij.java.codeInspection; import com.intellij.JavaTestUtil; import com.intellij.codeInspection.InspectionProfileEntry; import com.intellij.codeInspection.varScopeCanBeNarrowed.FieldCanBeLocalInspection; +import com.intellij.pom.java.LanguageLevel; +import com.intellij.testFramework.IdeaTestUtil; import com.intellij.testFramework.LightProjectDescriptor; import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase; import org.jetbrains.annotations.NotNull; @@ -63,6 +65,11 @@ public class FieldCanBeLocalTest extends LightJavaCodeInsightFixtureTestCase { doTest(); } + public void testConstructorThisRef2() { + IdeaTestUtil.setModuleLanguageLevel(getModule(), LanguageLevel.JDK_23_PREVIEW, myFixture.getTestRootDisposable()); + doTest(); + } + public void testStaticQualifiedFieldAccessForWriting() { doTest(); }