IG: ignore local classes but do check inner classes in "Cyclic class dependency"...
authorBas Leijdekkers <basleijdekkers@gmail.com>
Wed, 5 Oct 2016 18:08:01 +0000 (20:08 +0200)
committerBas Leijdekkers <basleijdekkers@gmail.com>
Thu, 6 Oct 2016 10:23:53 +0000 (12:23 +0200)
plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/dependency/CyclicClassDependencyInspection.java
plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/dependency/DependencyUtils.java
plugins/InspectionGadgets/test/com/siyeh/igtest/dependency/cyclic_class_dependency/expected.xml
plugins/InspectionGadgets/test/com/siyeh/igtest/dependency/cyclic_class_dependency/src/Cyclic.java

index c7d2cbf70388ca6a8d3852d802645b92e83280ea..3f774dbbc813bca4ebaadf32258264efdecd14b7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2006-2015 Dave Griffith, Bas Leijdekkers
+ * Copyright 2006-2016 Dave Griffith, Bas Leijdekkers
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,7 +20,6 @@ import com.intellij.codeInspection.*;
 import com.intellij.codeInspection.reference.RefClass;
 import com.intellij.codeInspection.reference.RefEntity;
 import com.intellij.codeInspection.util.RefEntityAlphabeticalComparator;
-import com.intellij.psi.PsiAnonymousClass;
 import com.intellij.psi.PsiClass;
 import com.intellij.psi.PsiElement;
 import com.siyeh.InspectionGadgetsBundle;
@@ -51,8 +50,7 @@ public class CyclicClassDependencyInspection extends BaseGlobalInspection {
       return null;
     }
     final RefClass refClass = (RefClass)refEntity;
-    final PsiClass aClass = refClass.getElement();
-    if (aClass == null || aClass.getContainingClass() != null || aClass instanceof PsiAnonymousClass) {
+    if (refClass.isAnonymous() || refClass.isLocalClass() || refClass.isSyntheticJSP()) {
       return null;
     }
     final Set<RefClass> dependencies = DependencyUtils.calculateTransitiveDependenciesForClass(refClass);
@@ -79,6 +77,10 @@ public class CyclicClassDependencyInspection extends BaseGlobalInspection {
       errorString = InspectionGadgetsBundle.message("cyclic.class.dependency.problem.descriptor",
                                                     refEntity.getName(), Integer.valueOf(numMutualDependents));
     }
+    final PsiClass aClass = refClass.getElement();
+    if (aClass == null) {
+      return null;
+    }
     final PsiElement anchor = aClass.getNameIdentifier();
     if (anchor == null) return null;
     return new CommonProblemDescriptor[]{
index 302574bd4b032e1fffdd87acfa6276adf77ec1e2..c539cd96b92d70570b931f9a41c5e539935c3555 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2006-2013 Dave Griffith, Bas Leijdekkers
+ * Copyright 2006-2016 Dave Griffith, Bas Leijdekkers
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -43,10 +43,8 @@ public class DependencyUtils {
   private DependencyUtils() {
   }
 
-  public static Set<RefClass> calculateDependenciesForClass(
-    RefClass refClass) {
-    final Set<RefClass> dependencies =
-      refClass.getUserData(DEPENDENCY_CLASSES_KEY);
+  public static Set<RefClass> calculateDependenciesForClass(RefClass refClass) {
+    final Set<RefClass> dependencies = refClass.getUserData(DEPENDENCY_CLASSES_KEY);
     if (dependencies != null) {
       return dependencies;
     }
@@ -57,40 +55,32 @@ public class DependencyUtils {
     return newDependencies;
   }
 
-  @SuppressWarnings({"MethodWithMultipleLoops"})
-  static void tabulateDependencyClasses(RefJavaElement element,
-                                        Set<RefClass> dependencies) {
-    final Collection<RefElement> references = element.getOutReferences();
-    final RefJavaUtil refUtil = RefJavaUtil.getInstance();
-    for (RefElement reference : references) {
-      final RefClass refClass = refUtil.getTopLevelClass(reference);
-      if (refClass != null) {
-        dependencies.add(refClass);
-      }
-    }
-    final Collection<RefClass> typeReferences =
-      element.getOutTypeReferences();
-    for (RefElement reference : typeReferences) {
-      final RefClass refClass = refUtil.getTopLevelClass(reference);
-      if (refClass != null) {
-        dependencies.add(refClass);
-      }
-    }
+  private static void tabulateDependencyClasses(RefJavaElement element, Set<RefClass> dependencies) {
+    addOwnerClassesToSet(element.getOutReferences(), dependencies);
+    addOwnerClassesToSet(element.getOutTypeReferences(), dependencies);
     final List<RefEntity> children = element.getChildren();
     if (children == null) {
       return;
     }
     for (RefEntity child : children) {
-      if (child instanceof RefJavaElement) {
+      if (child instanceof RefJavaElement && !(child instanceof RefClass)) {
         tabulateDependencyClasses((RefJavaElement)child, dependencies);
       }
     }
   }
 
-  public static Set<RefClass> calculateTransitiveDependenciesForClass(
-    RefClass refClass) {
-    final Set<RefClass> dependencies =
-      refClass.getUserData(TRANSITIVE_DEPENDENCY_CLASSES_KEY);
+  private static void addOwnerClassesToSet(Collection<? extends RefElement> references, Set<RefClass> set) {
+    final RefJavaUtil refUtil = RefJavaUtil.getInstance();
+    for (RefElement reference : references) {
+      final RefClass refClass = (reference instanceof RefClass) ? (RefClass)reference : refUtil.getOwnerClass(reference);
+      if (refClass != null && !refClass.isAnonymous() && !refClass.isLocalClass()) {
+        set.add(refClass);
+      }
+    }
+  }
+
+  public static Set<RefClass> calculateTransitiveDependenciesForClass(RefClass refClass) {
+    final Set<RefClass> dependencies = refClass.getUserData(TRANSITIVE_DEPENDENCY_CLASSES_KEY);
     if (dependencies != null) {
       return dependencies;
     }
@@ -122,51 +112,36 @@ public class DependencyUtils {
   }
 
   public static Set<RefClass> calculateDependentsForClass(RefClass refClass) {
-    final Set<RefClass> dependents =
-      refClass.getUserData(DEPENDENT_CLASSES_KEY);
+    final Set<RefClass> dependents = refClass.getUserData(DEPENDENT_CLASSES_KEY);
     if (dependents != null) {
       return dependents;
     }
     final Set<RefClass> newDependents = new HashSet<>();
     tabulateDependentClasses(refClass, newDependents);
-    final Set<RefElement> typeReferences = refClass.getInTypeReferences();
-    final RefJavaUtil refUtil = RefJavaUtil.getInstance();
-    for (RefElement typeReference : typeReferences) {
-      final RefClass referencingClass =
-        refUtil.getTopLevelClass(typeReference);
-      newDependents.add(referencingClass);
-    }
     newDependents.remove(refClass);
     refClass.putUserData(DEPENDENT_CLASSES_KEY, newDependents);
     return newDependents;
   }
 
-  @SuppressWarnings({"MethodWithMultipleLoops"})
-  private static void tabulateDependentClasses(RefElement element,
-                                               Set<RefClass> dependents) {
-    final Collection<RefElement> references = element.getInReferences();
-    final RefJavaUtil refUtil = RefJavaUtil.getInstance();
-    for (RefElement reference : references) {
-      final RefClass refClass = refUtil.getTopLevelClass(reference);
-      if (refClass != null) {
-        dependents.add(refClass);
-      }
+  private static void tabulateDependentClasses(RefElement element, Set<RefClass> dependents) {
+    addOwnerClassesToSet(element.getInReferences(), dependents);
+    if (element instanceof RefClass) {
+      final RefClass refClass = (RefClass)element;
+      addOwnerClassesToSet(refClass.getInTypeReferences(), dependents);
     }
     final List<RefEntity> children = element.getChildren();
     if (children == null) {
       return;
     }
     for (RefEntity child : children) {
-      if (child instanceof RefElement) {
+      if (child instanceof RefElement && !(child instanceof RefClass)) {
         tabulateDependentClasses((RefElement)child, dependents);
       }
     }
   }
 
-  public static Set<RefClass> calculateTransitiveDependentsForClass(
-    RefClass refClass) {
-    final Set<RefClass> dependents =
-      refClass.getUserData(TRANSITIVE_DEPENDENT_CLASSES_KEY);
+  public static Set<RefClass> calculateTransitiveDependentsForClass(RefClass refClass) {
+    final Set<RefClass> dependents = refClass.getUserData(TRANSITIVE_DEPENDENT_CLASSES_KEY);
     if (dependents != null) {
       return dependents;
     }
@@ -205,15 +180,13 @@ public class DependencyUtils {
       return dependencies;
     }
     final Set<RefPackage> newDependencies = new HashSet<>();
-
     tabulateDependencyPackages(refPackage, newDependencies);
     newDependencies.remove(refPackage);
     refPackage.putUserData(DEPENDENCY_PACKAGES_KEY, newDependencies);
     return newDependencies;
   }
 
-  static void tabulateDependencyPackages(RefEntity entity,
-                                         Set<RefPackage> dependencies) {
+  private static void tabulateDependencyPackages(RefEntity entity, Set<RefPackage> dependencies) {
     if (entity instanceof RefElement) {
       final RefElement element = (RefElement)entity;
       final Collection<RefElement> references = element.getOutReferences();
@@ -249,7 +222,7 @@ public class DependencyUtils {
     return newDependents;
   }
 
-  static void tabulateDependentPackages(RefEntity entity, Set<RefPackage> dependents) {
+  private static void tabulateDependentPackages(RefEntity entity, Set<RefPackage> dependents) {
     if (entity instanceof RefElement) {
       final RefElement element = (RefElement)entity;
       final Collection<RefElement> references = element.getInReferences();
index d75c4d2e2d958a40b3b17152acaaad38394f0e29..0b7f839ac8dea84f7efbcf1c258e3bb1877b2111 100644 (file)
@@ -1,5 +1,12 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <problems>
+  <problem>
+    <file>Cyclic.java</file>
+    <line>6</line>
+    <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Cyclic class dependency</problem_class>
+    <description>Class 'Cyclic' is cyclically dependent on classes 'com.siyeh.igtest.dependency.cyclic_class_dependency.src.Base' and 'com.siyeh.igtest.dependency.cyclic_class_dependency.src.Top'</description>
+  </problem>
+
   <problem>
     <file>Cyclic.java</file>
     <line>17</line>
 
   <problem>
     <file>Cyclic.java</file>
-    <line>6</line>
+    <line>52</line>
     <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Cyclic class dependency</problem_class>
-    <description>Class 'Cyclic' is cyclically dependent on classes 'com.siyeh.igtest.dependency.cyclic_class_dependency.src.Base' and 'com.siyeh.igtest.dependency.cyclic_class_dependency.src.Top'</description>
+    <description>Class 'Inner1' is cyclically dependent on class 'com.siyeh.igtest.dependency.cyclic_class_dependency.src.Outer.Inner2'</description>
+  </problem>
+
+  <problem>
+    <file>Cyclic.java</file>
+    <line>55</line>
+    <problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Cyclic class dependency</problem_class>
+    <description>Class 'Inner2' is cyclically dependent on class 'com.siyeh.igtest.dependency.cyclic_class_dependency.src.Outer.Inner1'</description>
   </problem>
 </problems>
\ No newline at end of file
index e8f750c99fa3d20fd87c287517e3f5a09641d00b..de36b6011c41129bdd188368d27d7f9175cab074 100644 (file)
@@ -42,3 +42,17 @@ enum MyEnum {
 
   abstract int value();
 }
+class Outer {
+
+  void m() {
+    class Local {}
+    class Local2 extends Outer {}
+  }
+
+  class Inner1 {
+    Inner2 field;
+  }
+  class Inner2 {
+    Inner1 field;
+  }
+}
\ No newline at end of file