accept that with different library versions inheritance relation may be intransitive (a fix for IDEA-88527 which doesn't break many web projects)

This commit is contained in:
peter
2012-08-09 18:02:39 +02:00
parent e06e7a51d8
commit 3b29956955
11 changed files with 83 additions and 55 deletions
@@ -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)) {
@@ -50,6 +50,10 @@ public class JavaOverridingMethodsSearcher implements QueryExecutor<PsiMethod, O
@Nullable
private static PsiMethod findOverridingMethod(PsiClass inheritor, @NotNull PsiClass parentClass, PsiMethod method) {
if (!inheritor.isInheritor(parentClass, true)) {
return null;
}
PsiSubstitutor substitutor = TypeConversionUtil.getSuperClassSubstitutor(parentClass, inheritor, PsiSubstitutor.EMPTY);
MethodSignature signature = method.getSignature(substitutor);
PsiMethod found = MethodSignatureUtil.findMethodBySuperSignature(inheritor, signature, false);
@@ -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;
@@ -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);
}
@@ -14,14 +14,16 @@
* 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)
}
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)
}
}
}
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]) {
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 }
}
@@ -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);
@@ -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;
}
@@ -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;
/**
@@ -59,11 +56,6 @@ public class ProjectFileIndexFacade extends FileIndexFacade {
return myFileIndex.isInLibraryClasses(file);
}
@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);
@@ -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;
}