mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
inheritance transitivity with several versions of same library in classpath (IDEA-88527)
This commit is contained in:
@@ -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;
|
||||
|
||||
+7
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user