From f15d0a899d9bafdfe61433ec976ac363ca0036e6 Mon Sep 17 00:00:00 2001 From: Willem Verstraeten Date: Tue, 26 Mar 2019 16:39:32 +0100 Subject: [PATCH] [by Willem Verstraeten] dfa: support @AutoValue and other immutable annotations from ConcurrencyAnnotationsManager (IDEA-208913) adapted from https://github.com/JetBrains/intellij-community/pull/1090 --- .../dataFlow/value/DfaExpressionFactory.java | 9 +++++++-- .../codeInsight/ConcurrencyAnnotationsManager.java | 3 ++- .../fixture/ImmutableClassNonGetterMethod.java | 10 ++++++++++ .../java/codeInspection/DataFlowInspectionTest.java | 1 + 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaExpressionFactory.java b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaExpressionFactory.java index ed8bf17a3abc..2ea8ce36fea6 100644 --- a/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaExpressionFactory.java +++ b/java/java-analysis-impl/src/com/intellij/codeInspection/dataFlow/value/DfaExpressionFactory.java @@ -16,6 +16,7 @@ package com.intellij.codeInspection.dataFlow.value; import com.intellij.codeInsight.AnnotationUtil; +import com.intellij.codeInsight.ConcurrencyAnnotationsManager; import com.intellij.codeInsight.Nullability; import com.intellij.codeInspection.dataFlow.*; import com.intellij.codeInspection.dataFlow.rangeSet.LongRangeSet; @@ -232,8 +233,7 @@ public class DfaExpressionFactory { } } if (method.getParameterList().isEmpty()) { - if ((JavaMethodContractUtil.isPure(method) || - AnnotationUtil.findAnnotation(method.getContainingClass(), "javax.annotation.concurrent.Immutable") != null) && + if ((JavaMethodContractUtil.isPure(method) || isClassAnnotatedImmutable(method)) && isContractAllowedForGetter(method)) { return new GetterDescriptor(method); } @@ -242,6 +242,11 @@ public class DfaExpressionFactory { return null; } + private static boolean isClassAnnotatedImmutable(PsiMethod method) { + List annotations = ConcurrencyAnnotationsManager.getInstance(method.getProject()).getImmutableAnnotations(); + return AnnotationUtil.findAnnotation(method.getContainingClass(), annotations) != null; + } + private static boolean isContractAllowedForGetter(PsiMethod method) { List contracts = JavaMethodContractUtil.getMethodCallContracts(method, null); if (contracts.size() == 1) { diff --git a/java/java-psi-api/src/com/intellij/codeInsight/ConcurrencyAnnotationsManager.java b/java/java-psi-api/src/com/intellij/codeInsight/ConcurrencyAnnotationsManager.java index 65fa76460b4e..1b88deb9a07b 100644 --- a/java/java-psi-api/src/com/intellij/codeInsight/ConcurrencyAnnotationsManager.java +++ b/java/java-psi-api/src/com/intellij/codeInsight/ConcurrencyAnnotationsManager.java @@ -17,7 +17,6 @@ package com.intellij.codeInsight; import com.intellij.openapi.components.ServiceManager; import com.intellij.openapi.project.Project; -import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; import java.util.ArrayList; @@ -42,6 +41,8 @@ public class ConcurrencyAnnotationsManager { fillDefaults(myGuardedByList, GUARDED_BY); fillDefaults(myThreadSafeList, THREAD_SAFE); fillDefaults(myNotThreadSafeList, NOT_THREAD_SAFE); + + myImmutableList.add("com.google.auto.value.AutoValue"); } private static void fillDefaults(List list, final String annoName) { diff --git a/java/java-tests/testData/inspection/dataFlow/fixture/ImmutableClassNonGetterMethod.java b/java/java-tests/testData/inspection/dataFlow/fixture/ImmutableClassNonGetterMethod.java index d0e1032a4c66..a0e845c19a81 100644 --- a/java/java-tests/testData/inspection/dataFlow/fixture/ImmutableClassNonGetterMethod.java +++ b/java/java-tests/testData/inspection/dataFlow/fixture/ImmutableClassNonGetterMethod.java @@ -3,11 +3,21 @@ interface Intf { @org.jetbrains.annotations.Nullable String foo(); } +@com.google.auto.value.AutoValue +abstract class Value { + abstract @org.jetbrains.annotations.Nullable String foo(); +} + class Usage { void bar(Intf i) { if (i.foo() != null) { System.out.println(i.foo().length()); } } + void bar(Value i) { + if (i.foo() != null) { + System.out.println(i.foo().length()); + } + } } \ 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 a0e1035d2f84..95c1dd599a9a 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspectionTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInspection/DataFlowInspectionTest.java @@ -278,6 +278,7 @@ public class DataFlowInspectionTest extends DataFlowInspectionTestCase { } public void testImmutableClassNonGetterMethod() { + myFixture.addClass("package com.google.auto.value; public @interface AutoValue {}"); myFixture.addClass("package javax.annotation.concurrent; public @interface Immutable {}"); doTest(); }