From 6522175598ec3009166a0dfae03ddee7ac8d889d Mon Sep 17 00:00:00 2001 From: Tagir Valeev Date: Tue, 10 May 2022 17:15:39 +0200 Subject: [PATCH] [java-analysis] Check field finality when deciding whether class is immutable Fixes IDEA-293687 Incorrectly claims "expression is always false" GitOrigin-RevId: 74a3d8f7b3b0a66a974aa35d55147cbc3336393f --- .../fixture/FieldUpdateViaSetter.java | 25 +++++++++++++++++++ .../DataFlowInspectionTest.java | 1 + .../src/com/siyeh/ig/psiutils/ClassUtils.java | 5 ++-- 3 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 java/java-tests/testData/inspection/dataFlow/fixture/FieldUpdateViaSetter.java diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/FieldUpdateViaSetter.java b/java/java-tests/testData/inspection/dataFlow/fixture/FieldUpdateViaSetter.java new file mode 100644 index 000000000000..a91473ea5ee4 --- /dev/null +++ b/java/java-tests/testData/inspection/dataFlow/fixture/FieldUpdateViaSetter.java @@ -0,0 +1,25 @@ +// IDEA-293687 +public class FieldUpdateViaSetter { + private static final MutableBoolean flag = new MutableBoolean(); + + public static void main(String[] args) { + for (int i = 0; i < 10; ++i) { + if (flag.value && i == 0) { + break; + } + if (flag.value && i == 3) { + System.out.println("IDEA thinks we can't get here"); + break; + } + flag.setValue(true); + } + } + + private static final class MutableBoolean { + private boolean value; + + public void setValue(boolean newValue) { + value = newValue; + } + } +} \ No newline at end of file diff --git a/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspectionTest.java b/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspectionTest.java index c0b1fd3b961d..42181265e233 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspectionTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspectionTest.java @@ -697,6 +697,7 @@ public class DataFlowInspectionTest extends DataFlowInspectionTestCase { public void testBoxedDivisionComparison() { doTest(); } public void testUnknownComparedToNullable() { doTest(); } public void testCastInCatch() { doTest(); } + public void testFieldUpdateViaSetter() { doTest(); } public void testInitArrayInConstructor() { doTest(); } public void testGetterNullityAfterCheck() { doTest(); } public void testInferenceNullityMismatch() { doTestWith(insp -> insp.SUGGEST_NULLABLE_ANNOTATIONS = false); } diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ClassUtils.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ClassUtils.java index 5f74b7e73cea..a1be6b9c0ec9 100644 --- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ClassUtils.java +++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/psiutils/ClassUtils.java @@ -152,8 +152,9 @@ public final class ClassUtils { return aClass.hasModifierProperty(PsiModifier.FINAL) && Arrays.stream(aClass.getAllFields()) .filter(field -> !field.hasModifierProperty(PsiModifier.STATIC)) - .map(field -> field.getType()) - .allMatch(type -> TypeConversionUtil.isPrimitiveAndNotNull(type) || immutableTypes.contains(type.getCanonicalText())); + .allMatch(field -> field.hasModifierProperty(PsiModifier.FINAL) && + (TypeConversionUtil.isPrimitiveAndNotNull(field.getType()) || + immutableTypes.contains(field.getType().getCanonicalText()))); } public static boolean inSamePackage(@Nullable PsiElement element1, @Nullable PsiElement element2) {