accept that with different library versions inheritance relation may be intransitive...
authorpeter <peter@jetbrains.com>
Thu, 9 Aug 2012 15:44:37 +0000 (17:44 +0200)
committerpeter <peter@jetbrains.com>
Thu, 9 Aug 2012 16:02:39 +0000 (18:02 +0200)
java/java-impl/src/com/intellij/util/xml/impl/ExtendsClassChecker.java
java/java-indexing-impl/src/com/intellij/psi/impl/search/JavaOverridingMethodsSearcher.java
java/java-psi-impl/src/com/intellij/psi/impl/InheritanceImplUtil.java
java/java-psi-impl/src/com/intellij/psi/impl/PsiClassImplUtil.java
java/java-tests/testData/libResolve/inheritance/fullLibrary.jar [new file with mode: 0644]
java/java-tests/testData/libResolve/inheritance/middleBottom.jar [new file with mode: 0644]
java/java-tests/testSrc/com/intellij/psi/resolve/ResolveInLibrariesTest.groovy
platform/core-api/src/com/intellij/openapi/roots/FileIndexFacade.java
platform/core-impl/src/com/intellij/mock/MockFileIndexFacade.java
platform/projectModel-impl/src/com/intellij/openapi/roots/impl/ProjectFileIndexFacade.java
platform/vcs-impl/src/com/intellij/openapi/vcs/impl/DefaultFileIndexFacade.java

index bcf0c747dc13f01ef286991680158ad0890b8b99..3fe146e787c0300e7141a7a9af120ab45cad718d 100644 (file)
@@ -19,7 +19,6 @@ import com.intellij.openapi.project.Project;
 import com.intellij.psi.*;
 import com.intellij.psi.impl.source.resolve.reference.impl.providers.JavaClassReference;
 import com.intellij.psi.impl.source.resolve.reference.impl.providers.JavaClassReferenceProvider;
-import com.intellij.psi.search.GlobalSearchScope;
 import com.intellij.psi.util.InheritanceUtil;
 import com.intellij.psi.util.PsiUtil;
 import com.intellij.util.ProcessingContext;
@@ -82,7 +81,7 @@ public class ExtendsClassChecker extends DomCustomAnnotationChecker<ExtendClass>
                                                                    final boolean allowEnum,
                                                                    final DomElementAnnotationHolder holder) {
     final Project project = element.getManager().getProject();
-    PsiClass extendClass = JavaPsiFacade.getInstance(project).findClass(name, GlobalSearchScope.allScope(project));
+    PsiClass extendClass = JavaPsiFacade.getInstance(project).findClass(name, value.getResolveScope());
     final SmartList<DomElementProblemDescriptor> list = new SmartList<DomElementProblemDescriptor>();
     if (extendClass != null) {
       if (!name.equals(value.getQualifiedName()) && !value.isInheritor(extendClass, true)) {
index a4155ab975bb7b60490a2ad5467e06a512b4ac89..e65c666cf57b4b09b4a1e8845b257fcb8f570309 100644 (file)
@@ -50,6 +50,10 @@ public class JavaOverridingMethodsSearcher implements QueryExecutor<PsiMethod, O
 \r
   @Nullable\r
   private static PsiMethod findOverridingMethod(PsiClass inheritor, @NotNull PsiClass parentClass, PsiMethod method) {\r
+    if (!inheritor.isInheritor(parentClass, true)) {\r
+      return null;\r
+    }\r
+\r
     PsiSubstitutor substitutor = TypeConversionUtil.getSuperClassSubstitutor(parentClass, inheritor, PsiSubstitutor.EMPTY);\r
     MethodSignature signature = method.getSignature(substitutor);\r
     PsiMethod found = MethodSignatureUtil.findMethodBySuperSignature(inheritor, signature, false);\r
index 205facdaadfa3a073454139b9d32f434ef78e5da..28fc636cbb26be044164d93bf84e095e4a6e0534 100644 (file)
@@ -19,6 +19,7 @@ import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.openapi.progress.ProgressIndicatorProvider;
 import com.intellij.openapi.util.Comparing;
 import com.intellij.psi.*;
+import com.intellij.psi.search.GlobalSearchScope;
 import com.intellij.psi.util.InheritanceUtil;
 import com.intellij.util.containers.HashSet;
 import gnu.trove.THashSet;
@@ -70,8 +71,12 @@ public class InheritanceImplUtil {
       final boolean bInt = baseClass.isInterface();
 
       if (candidateClass instanceof PsiCompiledElement) {
-        if (cInt == bInt && checkReferenceListWithQualifiedNames(candidateClass.getExtendsList(), baseClass)) return true;
-        return bInt && !cInt && checkReferenceListWithQualifiedNames(candidateClass.getImplementsList(), baseClass);
+        String baseQName = baseClass.getQualifiedName();
+        if (baseQName == null) return false;
+
+        GlobalSearchScope scope = candidateClass.getResolveScope();
+        if (cInt == bInt && checkReferenceListWithQualifiedNames(baseQName, candidateClass.getExtendsList(), manager, scope)) return true;
+        return bInt && !cInt && checkReferenceListWithQualifiedNames(baseQName, candidateClass.getImplementsList(), manager, scope);
       }
       if (cInt == bInt) {
         for (PsiClassType type : candidateClass.getExtendsListTypes()) {
@@ -98,16 +103,14 @@ public class InheritanceImplUtil {
     return isInheritorWithoutCaching(candidateClass, baseClass, checkDeep, checkedClasses);
   }
 
-  private static boolean checkReferenceListWithQualifiedNames(final PsiReferenceList extList, PsiClass baseClass) {
+  private static boolean checkReferenceListWithQualifiedNames(final String baseQName, final PsiReferenceList extList, final PsiManager manager,
+                                                              final GlobalSearchScope scope) {
     if (extList != null) {
-      String qname = baseClass.getQualifiedName();
-      if (qname != null) {
-        for (PsiJavaCodeReferenceElement ref : extList.getReferenceElements()) {
-          if (Comparing.equal(PsiNameHelper.getQualifiedClassName(ref.getQualifiedName(), false), qname) &&
-              baseClass.isEquivalentTo(ref.resolve())) {
-            return true;
-          }
-        }
+      final PsiJavaCodeReferenceElement[] refs = extList.getReferenceElements();
+      for (PsiJavaCodeReferenceElement ref : refs) {
+        if (Comparing.equal(PsiNameHelper.getQualifiedClassName(ref.getQualifiedName(), false), baseQName) && JavaPsiFacade
+          .getInstance(manager.getProject()).findClass(baseQName, scope) != null)
+          return true;
       }
     }
     return false;
index 8bfd2f8c168e8dfee789719afbb2d8b86a596262..6992c102574a12ca439ead977ccfd250f097b2ff 100644 (file)
@@ -994,12 +994,6 @@ public class PsiClassImplUtil {
     final VirtualFile vfile2 = file2.getViewProvider().getVirtualFile();
     boolean lib1 = fileIndex.isInLibraryClasses(vfile1);
     boolean lib2 = fileIndex.isInLibraryClasses(vfile2);
-    if (aClass instanceof PsiCompiledElement && another instanceof PsiCompiledElement && lib1 && lib2) {
-      if (fileIndex.isInSdkClasses(vfile1) && fileIndex.isInSdkClasses(vfile2)) {
-        return true;
-      }
-      return vfile1.equals(vfile2);
-    }
 
     return (fileIndex.isInSource(vfile1) || lib1) && (fileIndex.isInSource(vfile2) || lib2);
   }
diff --git a/java/java-tests/testData/libResolve/inheritance/fullLibrary.jar b/java/java-tests/testData/libResolve/inheritance/fullLibrary.jar
new file mode 100644 (file)
index 0000000..0b8be7a
Binary files /dev/null and b/java/java-tests/testData/libResolve/inheritance/fullLibrary.jar differ
diff --git a/java/java-tests/testData/libResolve/inheritance/middleBottom.jar b/java/java-tests/testData/libResolve/inheritance/middleBottom.jar
new file mode 100644 (file)
index 0000000..2fe3e51
Binary files /dev/null and b/java/java-tests/testData/libResolve/inheritance/middleBottom.jar differ
index 2f7fe69025d027a05ae9292ec53b9014eb529cd2..4d7d3930bbe771517f2b2b09f878ff8bd9bb01ba 100644 (file)
  * limitations under the License.
  */
 package com.intellij.psi.resolve
-
 import com.intellij.openapi.application.ex.PathManagerEx
 import com.intellij.openapi.vfs.LocalFileSystem
 import com.intellij.psi.JavaPsiFacade
+import com.intellij.psi.PsiClass
+import com.intellij.psi.PsiMethod
 import com.intellij.psi.search.GlobalSearchScope
+import com.intellij.psi.search.searches.ClassInheritorsSearch
+import com.intellij.psi.search.searches.OverridingMethodsSearch
 import com.intellij.testFramework.PsiTestUtil
 import com.intellij.testFramework.fixtures.JavaCodeInsightFixtureTestCase
-
 /**
  * @author peter
  */
@@ -72,18 +74,62 @@ class ResolveInLibrariesTest extends JavaCodeInsightFixtureTestCase {
     assert intfs.size() == 2
 
     for (i in 0..1) {
+      assert ClassInheritorsSearch.search(intfs[i]).findAll().containsAll([middles[i], bottoms[i]])
+      intfs[i].methods.each {
+        assert OverridingMethodsSearch.search(it).findAll()
+      }
+
       assert middles[i].isInheritor(intfs[i], true)
       assert bottoms[i].isInheritor(intfs[i], true)
       assert bottoms[i].isInheritor(middles[i], true)
     }
 
+  }
+
+  public void "test accept that with different library versions inheritance relation may be intransitive"() {
+    def lib = LocalFileSystem.getInstance().refreshAndFindFileByPath(PathManagerEx.getTestDataPath() + "/libResolve/inheritance")
+
+    //Foo, Middle implements Foo, Other extends Middle
+    PsiTestUtil.addLibrary(myModule, 'full', lib.path, ["/fullLibrary.jar!/"] as String[], [] as String[])
+
+    //Middle, Bottom extends Middle
+    PsiTestUtil.addLibrary(myModule, 'partial', lib.path, ["/middleBottom.jar!/"] as String[], [] as String[])
+
+    def scope = GlobalSearchScope.allScope(project)
+
+    def i0 = JavaPsiFacade.getInstance(project).findClass('Intf', scope)
+    def other0 = JavaPsiFacade.getInstance(project).findClass('Other', scope)
+    def b1 = JavaPsiFacade.getInstance(project).findClass('Bottom', scope)
+
+    def middles = JavaPsiFacade.getInstance(project).findClasses('Middle', scope)
+    assert middles.size() == 2
+    def m0 = middles[0]
+    def m1 = middles[1]
+
     for (deep in [false, true]) {
-      for (i in 0..1) {
-        assert !middles[i].isInheritor(intfs[1-i], deep)
-        assert !bottoms[i].isInheritor(intfs[1-i], deep)
-        assert !bottoms[i].isInheritor(middles[1-i], deep)
-      }
+      assert m0.isInheritor(i0, deep)
+      assert other0.isInheritor(m0, deep)
+
+      assert !b1.isInheritor(i0, deep)
+
+      assert b1.isInheritor(m0, deep)
+      assert b1.isInheritor(m1, deep)
+
+      assert !m1.isInheritor(i0, deep)
     }
+
+    assert other0.isInheritor(i0, true)
+    assert !other0.isInheritor(i0, false)
+
+    assert ClassInheritorsSearch.search(i0).findAll() == [m0, b1, other0]
+    assert ClassInheritorsSearch.search(m0).findAll() == [b1, other0]
+
+    assert fooInheritors(i0) == [fooMethod(m0), fooMethod(other0)] as Set
+    assert fooInheritors(m0) == [fooMethod(other0), fooMethod(b1)] as Set
+    assert fooInheritors(m1) == [fooMethod(other0), fooMethod(b1)] as Set
   }
 
+  private PsiMethod fooMethod(PsiClass c) { c.findMethodsByName('foo', false)[0] }
+  private Set<PsiMethod> fooInheritors(PsiClass c) { OverridingMethodsSearch.search(fooMethod(c)).findAll() as Set }
+
 }
index 411229af0c02a0b7509ac0ed5eb085a31395fa70..2f3b7dad1885e840e6435a1c76ef65fb463822af 100644 (file)
@@ -37,13 +37,13 @@ public abstract class FileIndexFacade {
     return ServiceManager.getService(project, FileIndexFacade.class);
   }
 
-  public abstract boolean isInContent(@NotNull VirtualFile file);
-  public abstract boolean isInSource(@NotNull VirtualFile file);
-  public abstract boolean isInSourceContent(@NotNull VirtualFile file);
-  public abstract boolean isInLibraryClasses(@NotNull VirtualFile file);
-  public abstract boolean isInSdkClasses(@NotNull VirtualFile file);
-  public abstract boolean isInLibrarySource(@NotNull VirtualFile file);
-  public abstract boolean isExcludedFile(@NotNull VirtualFile file);
+  public abstract boolean isInContent(VirtualFile file);
+  public abstract boolean isInSource(VirtualFile file);
+  public abstract boolean isInSourceContent(VirtualFile file);
+  public abstract boolean isInLibraryClasses(VirtualFile file);
+
+  public abstract boolean isInLibrarySource(VirtualFile file);
+  public abstract boolean isExcludedFile(VirtualFile file);
 
   @Nullable
   public abstract Module getModuleForFile(VirtualFile file);
index 7eba34873f7d7b47146359580773f8af6517401c..aa6014021ac94fcdf9c416619b9f7b421133a59d 100644 (file)
@@ -63,12 +63,7 @@ public class MockFileIndexFacade extends FileIndexFacade {
   }
 
   @Override
-  public boolean isInSdkClasses(@NotNull VirtualFile file) {
-    return false;
-  }
-
-  @Override
-  public boolean isInLibrarySource(@NotNull VirtualFile file) {
+  public boolean isInLibrarySource(VirtualFile file) {
     return false;
   }
 
index bc327d052846d7f119e19ead8934468e91837dbc..4c52b7f5c3a3c7e6a786284550086909be76fca7 100644 (file)
@@ -19,12 +19,9 @@ package com.intellij.openapi.roots.impl;
 import com.intellij.openapi.module.Module;
 import com.intellij.openapi.project.Project;
 import com.intellij.openapi.roots.FileIndexFacade;
-import com.intellij.openapi.roots.JdkOrderEntry;
 import com.intellij.openapi.roots.ProjectFileIndex;
 import com.intellij.openapi.roots.ProjectRootManager;
 import com.intellij.openapi.vfs.VirtualFile;
-import com.intellij.util.containers.ContainerUtil;
-import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 /**
@@ -60,11 +57,6 @@ public class ProjectFileIndexFacade extends FileIndexFacade {
   }
 
   @Override
-  public boolean isInSdkClasses(@NotNull VirtualFile file) {
-    return ContainerUtil.findInstance(myFileIndex.getOrderEntriesForFile(file), JdkOrderEntry.class) != null;
-  }
-
-  @Override
   public boolean isInLibrarySource(@NotNull VirtualFile file) {
     return myFileIndex.isInLibrarySource(file);
   }
index 91a2c18b13b66bd90752d34ac2a75b1682799803..d6fc0f9388c25050b2852f6cf7d8be0a29d896fa 100644 (file)
@@ -56,12 +56,7 @@ public class DefaultFileIndexFacade extends FileIndexFacade {
   }
 
   @Override
-  public boolean isInSdkClasses(@NotNull VirtualFile file) {
-    return false;
-  }
-
-  @Override
-  public boolean isInLibrarySource(@NotNull VirtualFile file) {
+  public boolean isInLibrarySource(VirtualFile file) {
     return false;
   }