inheritance transitivity with several versions of same library in classpath (IDEA-88527)

This commit is contained in:
peter
2012-08-02 14:41:29 +02:00
parent 03e6af3c44
commit fc7ad3de9e
7 changed files with 74 additions and 16 deletions
@@ -19,7 +19,6 @@ 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;
@@ -71,12 +70,8 @@ public class InheritanceImplUtil {
final boolean bInt = baseClass.isInterface();
if (candidateClass instanceof PsiCompiledElement) {
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 && checkReferenceListWithQualifiedNames(candidateClass.getExtendsList(), baseClass)) return true;
return bInt && !cInt && checkReferenceListWithQualifiedNames(candidateClass.getImplementsList(), baseClass);
}
if (cInt == bInt) {
for (PsiClassType type : candidateClass.getExtendsListTypes()) {
@@ -103,14 +98,16 @@ public class InheritanceImplUtil {
return isInheritorWithoutCaching(candidateClass, baseClass, checkDeep, checkedClasses);
}
private static boolean checkReferenceListWithQualifiedNames(final String baseQName, final PsiReferenceList extList, final PsiManager manager,
final GlobalSearchScope scope) {
private static boolean checkReferenceListWithQualifiedNames(final PsiReferenceList extList, PsiClass baseClass) {
if (extList != null) {
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;
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;
}
}
}
}
return false;
@@ -992,8 +992,16 @@ public class PsiClassImplUtil {
final FileIndexFacade fileIndex = ServiceManager.getService(file1.getProject(), FileIndexFacade.class);
final VirtualFile vfile1 = file1.getViewProvider().getVirtualFile();
final VirtualFile vfile2 = file2.getViewProvider().getVirtualFile();
return (fileIndex.isInSource(vfile1) || fileIndex.isInLibraryClasses(vfile1)) &&
(fileIndex.isInSource(vfile2) || fileIndex.isInLibraryClasses(vfile2));
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);
}
private static boolean compareClassSeqNumber(@NotNull PsiClass aClass, @NotNull PsiClass another) {
@@ -51,4 +51,39 @@ class ResolveInLibrariesTest extends JavaCodeInsightFixtureTestCase {
}
public void "test inheritance transitivity"() {
def lib = LocalFileSystem.getInstance().refreshAndFindFileByPath(PathManagerEx.getTestDataPath() + "/../../../lib")
def protoJar = lib.children.find { it.name.startsWith("protobuf") }
def jarCopy = myFixture.copyFileToProject(protoJar.path, 'lib/protoJar.jar')
PsiTestUtil.addLibrary(myModule, 'proto1', lib.path, ["/$protoJar.name!/"] as String[], [] as String[])
PsiTestUtil.addLibrary(myModule, 'proto2', jarCopy.parent.path, ["/$jarCopy.name!/"] as String[], [] as String[])
def scope = GlobalSearchScope.allScope(project)
def bottoms = JavaPsiFacade.getInstance(project).findClasses('com.google.protobuf.AbstractMessage', scope)
assert bottoms.size() == 2
def middles = JavaPsiFacade.getInstance(project).findClasses('com.google.protobuf.AbstractMessageLite', scope)
assert middles.size() == 2
def intfs = JavaPsiFacade.getInstance(project).findClasses('com.google.protobuf.MessageLite', scope)
assert intfs.size() == 2
for (i in 0..1) {
assert middles[i].isInheritor(intfs[i], true)
assert bottoms[i].isInheritor(intfs[i], true)
assert bottoms[i].isInheritor(middles[i], true)
}
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)
}
}
}
}
@@ -40,6 +40,7 @@ public abstract class FileIndexFacade {
public abstract boolean isInSource(VirtualFile file);
public abstract boolean isInSourceContent(VirtualFile file);
public abstract boolean isInLibraryClasses(VirtualFile file);
public abstract boolean isInSdkClasses(VirtualFile file);
public abstract boolean isInLibrarySource(VirtualFile file);
public abstract boolean isExcludedFile(VirtualFile file);
@@ -61,6 +61,11 @@ public class MockFileIndexFacade extends FileIndexFacade {
return false;
}
@Override
public boolean isInSdkClasses(VirtualFile file) {
return false;
}
@Override
public boolean isInLibrarySource(VirtualFile file) {
return false;
@@ -19,9 +19,11 @@ 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.Nullable;
/**
@@ -56,6 +58,11 @@ public class ProjectFileIndexFacade extends FileIndexFacade {
return myFileIndex.isInLibraryClasses(file);
}
@Override
public boolean isInSdkClasses(VirtualFile file) {
return ContainerUtil.findInstance(myFileIndex.getOrderEntriesForFile(file), JdkOrderEntry.class) != null;
}
@Override
public boolean isInLibrarySource(VirtualFile file) {
return myFileIndex.isInLibrarySource(file);
@@ -54,6 +54,11 @@ public class DefaultFileIndexFacade extends FileIndexFacade {
return false;
}
@Override
public boolean isInSdkClasses(VirtualFile file) {
return false;
}
@Override
public boolean isInLibrarySource(VirtualFile file) {
return false;