IG: don't warn about not synced when annotated with a proper @GuardedBy() (IDEA-154598)
authorBas Leijdekkers <basleijdekkers@gmail.com>
Fri, 30 Sep 2016 08:32:54 +0000 (10:32 +0200)
committerBas Leijdekkers <basleijdekkers@gmail.com>
Fri, 30 Sep 2016 08:32:54 +0000 (10:32 +0200)
java/java-analysis-impl/src/com/intellij/codeInspection/concurrencyAnnotations/JCiPUtil.java
plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/WaitNotifyNotInSynchronizedContextInspection.java
plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/WaitNotifyNotInSynchronizedContextInspectionMerger.java
plugins/InspectionGadgets/test/com/siyeh/igtest/threading/wait_notify_not_in_synchronized_context/WaitNotifyNotInSynchronizedContext.java

index 624659f1c90a7f74bef5820bb51646dadeb71643..871f5da974c4ef49a92c424f46bacd7fab3d9d6a 100644 (file)
@@ -44,7 +44,7 @@ public class JCiPUtil {
   }
 
   @Nullable
-  static String findGuardForMember(@NotNull PsiMember member) {
+  public static String findGuardForMember(@NotNull PsiMember member) {
     final PsiAnnotation annotation = AnnotationUtil.findAnnotation(member, ConcurrencyAnnotationsManager.getInstance(member.getProject()).getGuardedByAnnotations());
     if (annotation != null) {
       return getGuardValue(annotation);
index 9abfdc05c4195a65738c3e0147ec21ec3cd3e364..d09a9f5b86bb95538de3ae302ab3aad8aaa9cb62 100644 (file)
  */
 package com.siyeh.ig.threading;
 
+import com.intellij.codeInspection.concurrencyAnnotations.JCiPUtil;
 import com.intellij.psi.*;
 import com.intellij.psi.util.PsiTreeUtil;
-import com.siyeh.HardcodedMethodConstants;
 import com.siyeh.InspectionGadgetsBundle;
 import com.siyeh.ig.BaseInspection;
 import com.siyeh.ig.BaseInspectionVisitor;
 import com.siyeh.ig.psiutils.EquivalenceChecker;
 import com.siyeh.ig.psiutils.ParenthesesUtils;
 import org.jetbrains.annotations.Nls;
-import org.jetbrains.annotations.NonNls;
 import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
 
 /**
  * @author Bas Leijdekkers
@@ -62,28 +60,14 @@ public class WaitNotifyNotInSynchronizedContextInspection extends BaseInspection
     @Override
     public void visitMethodCallExpression(@NotNull PsiMethodCallExpression expression) {
       super.visitMethodCallExpression(expression);
-      final PsiReferenceExpression methodExpression = expression.getMethodExpression();
-      @NonNls final String methodName = methodExpression.getReferenceName();
-      if (!HardcodedMethodConstants.WAIT.equals(methodName) &&
-          !HardcodedMethodConstants.NOTIFY.equals(methodName) &&
-          !HardcodedMethodConstants.NOTIFY_ALL.equals(methodName)) {
-        return;
-      }
-      final PsiMethod method = expression.resolveMethod();
-      if (method == null) {
-        return;
-      }
-      final PsiClass aClass = method.getContainingClass();
-      if (aClass == null) {
-        return;
-      }
-      final String qualifiedName = aClass.getQualifiedName();
-      if (!CommonClassNames.JAVA_LANG_OBJECT.equals(qualifiedName)) {
+      if (!ThreadingUtils.isNotifyOrNotifyAllCall(expression) &&
+          !ThreadingUtils.isWaitCall(expression)) {
         return;
       }
+      final PsiReferenceExpression methodExpression = expression.getMethodExpression();
       final PsiExpression qualifier = ParenthesesUtils.stripParentheses(methodExpression.getQualifierExpression());
       if (qualifier == null || qualifier instanceof PsiThisExpression || qualifier instanceof PsiSuperExpression) {
-        if (isSynchronizedOnThis(expression)) {
+        if (isSynchronizedOnThis(expression) || isCoveredByGuardedByAnnotation(expression, "this")) {
           return;
         }
         registerError(expression, PsiKeyword.THIS);
@@ -92,8 +76,20 @@ public class WaitNotifyNotInSynchronizedContextInspection extends BaseInspection
         if (isSynchronizedOn(expression, qualifier)) {
           return;
         }
-        registerError(expression, qualifier.getText());
+        final String text = qualifier.getText();
+        if (isCoveredByGuardedByAnnotation(expression, text)) {
+          return;
+        }
+        registerError(expression, text);
+      }
+    }
+
+    private static boolean isCoveredByGuardedByAnnotation(PsiElement context, String guard) {
+      final PsiMember member = PsiTreeUtil.getParentOfType(context, PsiMember.class);
+      if (member == null) {
+        return false;
       }
+      return guard.equals(JCiPUtil.findGuardForMember(member));
     }
 
     private static boolean isSynchronizedOn(@NotNull PsiElement element, @NotNull PsiExpression target) {
index b9791e2f230fbbd04401c5c0a4562ded5f91d677..b1a30f2bae923d2e347a1d5edb4bcbc5bd21a5c3 100644 (file)
@@ -38,7 +38,7 @@ public class WaitNotifyNotInSynchronizedContextInspectionMerger extends Inspecti
   public String[] getSuppressIds() {
     return new String[]{
       "WaitWhileNotSynced",
-      "WaitNotInSynchronizedContext"
+      "NotifyNotInSynchronizedContext"
     };
   }
 }
index 39e93b74cd5631a9aedef439b99fb5eb8e15ca87..8c55885d6cb3e09d785caa50dbcc6fd627169c87 100644 (file)
@@ -71,4 +71,19 @@ class NotifyNotInSynchronizedContext
       lock.notifyAll();
     }
   }
+
+  public void suppressed() throws InterruptedException {
+    //noinspection NotifyNotInSynchronizedContext
+    lock.notify();
+    //noinspection WaitWhileNotSynced
+    lock.wait();
+  }
+
+  /**
+   * @GuardedBy(lock)
+   */
+  public void guarded() throws InterruptedException {
+    lock.wait();
+    lock.notifyAll();
+  }
 }