IG: Support @CanIgnoreReturnValue (IDEA-158576)
authorBas Leijdekkers <basleijdekkers@gmail.com>
Wed, 10 Aug 2016 15:09:28 +0000 (17:09 +0200)
committerBas Leijdekkers <basleijdekkers@gmail.com>
Wed, 10 Aug 2016 15:10:41 +0000 (17:10 +0200)
plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/bugs/IgnoreResultOfCallInspectionBase.java
plugins/InspectionGadgets/testsrc/com/siyeh/ig/bugs/IgnoreResultOfCallInspectionTest.groovy

index 154eaec48c1eff96cd26d9c981051574fbbb0cad..2a7e670a99a57304fc3267c2fb469da0996e37c6 100644 (file)
@@ -30,6 +30,7 @@ import com.siyeh.ig.psiutils.LibraryUtil;
 import com.siyeh.ig.psiutils.MethodMatcher;
 import org.jdom.Element;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 import java.util.Collections;
 import java.util.Set;
@@ -154,15 +155,26 @@ public class IgnoreResultOfCallInspectionBase extends BaseInspection {
         registerMethodCallError(call, aClass);
         return;
       }
-      if (!myMethodMatcher.matches(method) &&
-          findAnnotationInTree(method, Collections.singleton("javax.annotation.CheckReturnValue")) == null) {
+      final PsiAnnotation annotation = findAnnotationInTree(method, null, Collections.singleton("javax.annotation.CheckReturnValue"));
+      if (annotation != null) {
+        final PsiElement owner = (PsiElement)annotation.getOwner();
+        if (findAnnotationInTree(method, owner, Collections.singleton("com.google.errorprone.annotations.CanIgnoreReturnValue")) != null) {
+          return;
+        }
+      }
+      if (!myMethodMatcher.matches(method) && annotation == null) {
         return;
       }
+
       registerMethodCallError(call, aClass);
     }
 
-    private PsiAnnotation findAnnotationInTree(PsiElement element, Set<String> fqAnnotationNames) {
+    @Nullable
+    private PsiAnnotation findAnnotationInTree(PsiElement element, @Nullable PsiElement stop, @NotNull Set<String> fqAnnotationNames) {
       while (element != null) {
+        if (element == stop) {
+          return null;
+        }
         if (element instanceof PsiModifierListOwner) {
           final PsiModifierListOwner modifierListOwner = (PsiModifierListOwner)element;
           final PsiAnnotation annotation =
index 2cb55b3d4952498db9fe80b63ae4ec3a4be92323..51f9c3e30d34a59dc19532770476149597c30693 100644 (file)
@@ -20,6 +20,7 @@ public class IgnoreResultOfCallInspectionTest extends LightInspectionTestCase {
       "package java.util.regex; public class Matcher {" +
       "  public boolean find() {return true;}" +
       "}",
+
       "package javax.annotation;\n" +
       "\n" +
       "import java.lang.annotation.Documented;\n" +
@@ -36,10 +37,37 @@ public class IgnoreResultOfCallInspectionTest extends LightInspectionTestCase {
       "@Retention(RetentionPolicy.RUNTIME)\n" +
       "public @interface CheckReturnValue {\n" +
       "    When when() default When.ALWAYS;\n" +
-      "}"
+      "}",
+
+      "package com.google.errorprone.annotations;" +
+      "import java.lang.annotation.ElementType;\n" +
+      "import java.lang.annotation.Retention;\n" +
+      "import java.lang.annotation.RetentionPolicy;\n" +
+      "import java.lang.annotation.Target;\n" +
+      "@Target(value={ElementType.METHOD, ElementType.TYPE})\n" +
+      "@Retention(value=RetentionPolicy.CLASS)\n" +
+      "public @interface CanIgnoreReturnValue {}"
     ] as String[]
   }
 
+  public void testCanIgnoreReturnValue() {
+    doTest("import com.google.errorprone.annotations.CanIgnoreReturnValue;\n" +
+           "import javax.annotation.CheckReturnValue;\n" +
+           "\n" +
+           "@CheckReturnValue\n" +
+           "class Test {\n" +
+           "  int lookAtMe() { return 1; }\n" +
+           "\n" +
+           "  @CanIgnoreReturnValue\n" +
+           "  int ignoreMe() { return 2; }\n" +
+           "\n" +
+           "  void run() {\n" +
+           "    /*Result of 'Test.lookAtMe()' is ignored*/lookAtMe/**/(); // Bad!  This line should produce a warning.\n" +
+           "    ignoreMe(); // OK.  This line should *not* produce a warning.\n" +
+           "  }\n" +
+           "}");
+  }
+
   public void testObjectMethods() {
     doTest("class C {\n" +
            "  void foo(Object o, String s) {\n" +