StaticInitializerReferencesSubClassInspection: don't report private subclasses that...
authorpeter <peter@jetbrains.com>
Fri, 6 Nov 2015 11:22:21 +0000 (12:22 +0100)
committerpeter <peter@jetbrains.com>
Fri, 6 Nov 2015 15:07:42 +0000 (16:07 +0100)
plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/threading/StaticInitializerReferencesSubClassInspection.java
plugins/InspectionGadgets/test/com/siyeh/igtest/threading/StaticInitializerReferencesSubClass/StaticInitializer.java

index 3cc2178e793f3b6d321ab9c30580cecca462cd5b..d68ab88eb0152cae476bdb71b6e9063c5d8f654c 100644 (file)
@@ -20,7 +20,10 @@ import com.intellij.codeInspection.ProblemsHolder;
 import com.intellij.openapi.util.Pair;
 import com.intellij.openapi.util.Ref;
 import com.intellij.psi.*;
+import com.intellij.psi.search.LocalSearchScope;
+import com.intellij.psi.search.searches.ReferencesSearch;
 import com.intellij.psi.util.PsiUtil;
+import com.intellij.util.Processor;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -68,7 +71,7 @@ public class StaticInitializerReferencesSubClassInspection extends BaseJavaBatch
         if (element instanceof PsiClass || element instanceof PsiReferenceParameterList || element instanceof PsiTypeElement) return;
 
         PsiClass targetClass = extractClass(element);
-        if (targetClass != null && !(targetClass instanceof PsiAnonymousClass) && targetClass.isInheritor(baseClass, true)) {
+        if (targetClass != null && targetClass.isInheritor(baseClass, true) && !hasSingleInitializationPlace(targetClass)) {
           PsiElement problemElement = calcProblemElement(element);
           if (problemElement != null) {
             result.set(Pair.create(problemElement, targetClass));
@@ -81,6 +84,23 @@ public class StaticInitializerReferencesSubClassInspection extends BaseJavaBatch
     return result.get();
   }
 
+  private static boolean hasSingleInitializationPlace(@NotNull PsiClass targetClass) {
+    if (targetClass instanceof PsiAnonymousClass) return true;
+    if (!targetClass.hasModifierProperty(PsiModifier.PRIVATE)) return false;
+
+    PsiFile file = targetClass.getContainingFile();
+    if (file == null) return false;
+
+    LocalSearchScope scope = new LocalSearchScope(file);
+    return ReferencesSearch.search(targetClass, scope).forEach(new Processor<PsiReference>() {
+      int count = 0;
+      @Override
+      public boolean process(PsiReference reference) {
+        return ++count < 2;
+      }
+    });
+  }
+
   @Nullable
   private static PsiElement calcProblemElement(PsiElement element) {
     if (element instanceof PsiNewExpression) return calcProblemElement(((PsiNewExpression)element).getClassOrAnonymousClassReference());
index 21abd1631691b7e33da9afff7d716447789e800c..f5cc496d9d95cfecb0ec5838cc96753ed28b3283 100644 (file)
@@ -4,17 +4,31 @@ class Super {
   static final Sub C3;
   static final Sub C4 = SubFactory.<warning descr="Referencing subclass Sub from superclass Super initializer might lead to class loading deadlock">create</warning>();
   static final String C5 = SubFactory.<warning descr="Referencing subclass Sub from superclass Super initializer might lead to class loading deadlock">create</warning>().toString();
+  static Super USED_PRIVATE = new <warning descr="Referencing subclass MyUsedSub from superclass Super initializer might lead to class loading deadlock">MyUsedSub</warning>();
 
   static Object OK_INSIDE_ANONYMOUS = new Object() {{ Sub s = new Sub(); }};
   static Object OK_UNRELATED = "abc";
   static Super OK_SAME = new Super();
   static Super OK_SAME_ANONYMOUS = new Super(){};
   static Sub[] OK_ARRAY = new Sub[3];
+  static Super OK_PRIVATE = new MySub();
   static java.util.List<Sub> OK_GENERICS = new java.util.ArrayList<Sub>();
 
   static {
     C3 = new <warning descr="Referencing subclass Sub from superclass Super initializer might lead to class loading deadlock">Sub</warning>();
   }
+
+  static void foo() {
+    MyUsedSub.foo();
+  }
+
+  private static class MySub extends Super { }
+  private static class MyUsedSub extends Super {
+    static void foo() {
+      System.out.println("hello");
+    }
+
+  }
 }
 
 class Sub extends Super implements Intf {