diff --git a/java/java-impl/src/com/intellij/psi/impl/PsiClassImplUtil.java b/java/java-impl/src/com/intellij/psi/impl/PsiClassImplUtil.java index c7b5702785e1..1f065c2513a6 100644 --- a/java/java-impl/src/com/intellij/psi/impl/PsiClassImplUtil.java +++ b/java/java-impl/src/com/intellij/psi/impl/PsiClassImplUtil.java @@ -21,7 +21,6 @@ import com.intellij.openapi.roots.ProjectRootManager; import com.intellij.openapi.util.*; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; -import com.intellij.psi.augment.PsiAugmentProvider; import com.intellij.psi.filters.OrFilter; import com.intellij.psi.impl.compiled.ClsElementImpl; import com.intellij.psi.impl.source.PsiImmediateClassType; @@ -39,10 +38,7 @@ import com.intellij.psi.search.SearchScope; import com.intellij.psi.util.*; import com.intellij.ui.IconDeferrer; import com.intellij.ui.RowIcon; -import com.intellij.util.Function; -import com.intellij.util.IncorrectOperationException; -import com.intellij.util.ReflectionCache; -import com.intellij.util.SmartList; +import com.intellij.util.*; import com.intellij.util.containers.HashMap; import gnu.trove.THashSet; import org.jetbrains.annotations.NonNls; @@ -864,6 +860,7 @@ public class PsiClassImplUtil { } public static boolean isClassEquivalentTo(PsiClass aClass, PsiElement another) { + if (aClass == another) return true; if (!(another instanceof PsiClass)) return false; String name1 = aClass.getName(); if (name1 == null) return false; @@ -900,17 +897,13 @@ public class PsiClassImplUtil { final PsiFile file1 = aClass.getContainingFile().getOriginalFile(); final PsiFile file2 = another.getContainingFile().getOriginalFile(); - if (file1.equals(file2)) { - return true; - } //see com.intellij.openapi.vcs.changes.PsiChangeTracker //see com.intellij.psi.impl.PsiFileFactoryImpl#createFileFromText(CharSequence,PsiFile) final PsiFile original1 = file1.getUserData(PsiFileFactory.ORIGINAL_FILE); final PsiFile original2 = file2.getUserData(PsiFileFactory.ORIGINAL_FILE); - if (original1 == original2 && original1 != null - || original1 == file2 || original2 == file1) { - return true; + if (original1 == original2 && original1 != null || original1 == file2 || original2 == file1 || file1 == file2) { + return compareClassSeqNumber(aClass, (PsiClass)another); } final ProjectFileIndex fileIndex = ProjectRootManager.getInstance(aClass.getProject()).getFileIndex(); @@ -920,6 +913,28 @@ public class PsiClassImplUtil { (fileIndex.isInSource(vfile2) || fileIndex.isInLibraryClasses(vfile2)); } + private static boolean compareClassSeqNumber(PsiClass aClass, PsiClass another) { + // there may be several classes in one file, they must not be equal + int index1 = getSeqNumber(aClass); + if (index1 == -1) return true; + int index2 = getSeqNumber(another); + return index1 == index2; + } + + private static int getSeqNumber(PsiClass aClass) { + // sequence number of this class among its parent' child classes named the same + PsiElement parent = aClass.getParent(); + if (parent == null) return -1; + int seqNo = 0; + for (PsiElement child : parent.getChildren()) { + if (child == aClass) return seqNo; + if (child instanceof PsiClass && Comparing.strEqual(aClass.getName(), ((PsiClass)child).getName())) { + seqNo++; + } + } + return -1; + } + private static PsiElement originalElement(PsiClass aClass) { final PsiElement originalElement = aClass.getOriginalElement(); final PsiCompiledElement compiled = originalElement.getUserData(ClsElementImpl.COMPILED_ELEMENT); diff --git a/java/java-impl/src/com/intellij/psi/impl/compiled/ClsJavaCodeReferenceElementImpl.java b/java/java-impl/src/com/intellij/psi/impl/compiled/ClsJavaCodeReferenceElementImpl.java index 7238fb8feccd..eb37c848fbcb 100644 --- a/java/java-impl/src/com/intellij/psi/impl/compiled/ClsJavaCodeReferenceElementImpl.java +++ b/java/java-impl/src/com/intellij/psi/impl/compiled/ClsJavaCodeReferenceElementImpl.java @@ -20,6 +20,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.impl.PsiManagerEx; import com.intellij.psi.impl.PsiSubstitutorImpl; +import com.intellij.psi.impl.search.JavaDirectInheritorsSearcher; import com.intellij.psi.impl.source.resolve.ResolveCache; import com.intellij.psi.impl.source.tree.JavaElementType; import com.intellij.psi.impl.source.tree.TreeElement; @@ -167,7 +168,15 @@ public class ClsJavaCodeReferenceElementImpl extends ClsElementImpl implements P for (PsiTypeParameter parameter : PsiUtil.typeParametersIterable((PsiTypeParameterListOwner)element)) { if (myQualifiedName.equals(parameter.getName())) return parameter; } - return JavaPsiFacade.getInstance(getProject()).findClass(myQualifiedName, getResolveScope()); + return resolveClassPreferringMyJar(); + } + + private PsiClass resolveClassPreferringMyJar() { + PsiClass[] classes = JavaPsiFacade.getInstance(getProject()).findClasses(myQualifiedName, getResolveScope()); + for (PsiClass aClass : classes) { + if (JavaDirectInheritorsSearcher.isFromTheSameJar(aClass, this)) return aClass; + } + return classes.length == 0 ? null : classes[0]; } public void processVariants(PsiScopeProcessor processor) { diff --git a/java/java-impl/src/com/intellij/psi/impl/search/JavaDirectInheritorsSearcher.java b/java/java-impl/src/com/intellij/psi/impl/search/JavaDirectInheritorsSearcher.java index 5340828d80fe..8a051aefa30b 100644 --- a/java/java-impl/src/com/intellij/psi/impl/search/JavaDirectInheritorsSearcher.java +++ b/java/java-impl/src/com/intellij/psi/impl/search/JavaDirectInheritorsSearcher.java @@ -8,6 +8,8 @@ import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.JarFileSystem; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.impl.PsiManagerImpl; import com.intellij.psi.impl.java.stubs.index.JavaAnonymousClassBaseRefOccurenceIndex; @@ -19,14 +21,17 @@ import com.intellij.psi.search.searches.AllClassesSearch; import com.intellij.psi.search.searches.DirectClassInheritorsSearch; import com.intellij.util.Processor; import com.intellij.util.QueryExecutor; +import com.intellij.util.containers.HashMap; +import java.util.ArrayList; import java.util.Collection; +import java.util.List; +import java.util.Map; /** * @author max */ public class JavaDirectInheritorsSearcher implements QueryExecutor { - public boolean execute(final DirectClassInheritorsSearch.SearchParameters p, final Processor consumer) { final PsiClass aClass = p.getClassToProcess(); final PsiManagerImpl psiManager = (PsiManagerImpl)PsiManager.getInstance(aClass.getProject()); @@ -73,10 +78,22 @@ public class JavaDirectInheritorsSearcher implements QueryExecutor> classes = new HashMap>(); + for (PsiReferenceList referenceList : candidates) { ProgressManager.checkCanceled(); PsiClass candidate = (PsiClass)referenceList.getParent(); - if (!consumer.process(candidate)) return false; + String fqn = candidate.getQualifiedName(); + List list = classes.get(fqn); + if (list == null) { + list = new ArrayList(); + classes.put(fqn, list); + } + list.add(candidate); + } + + for (List sameNamedClasses : classes.values()) { + if (!processSameNamedClasses(consumer, aClass, sameNamedClasses)) return false; } if (p.includeAnonymous()) { @@ -116,4 +133,37 @@ public class JavaDirectInheritorsSearcher implements QueryExecutor consumer, PsiClass aClass, List sameNamedClasses) { + // if there is a class from the same jar, prefer it + boolean sameJarClassFound = false; + for (PsiClass sameNamedClass : sameNamedClasses) { + boolean fromSameJar = isFromTheSameJar(sameNamedClass, aClass); + if (fromSameJar) { + sameJarClassFound = true; + if (!consumer.process(sameNamedClass)) return false; + } + } + + if (!sameJarClassFound) { + for (PsiClass sameNamedClass : sameNamedClasses) { + if (!consumer.process(sameNamedClass)) return false; + } + } + return true; + } + + private static VirtualFile getJarFile(PsiElement candidate) { + VirtualFile file = candidate.getContainingFile().getVirtualFile(); + if (file != null && file.getFileSystem() instanceof JarFileSystem) { + return JarFileSystem.getInstance().getVirtualFileForJar(file); + } + return file; + } + public static boolean isFromTheSameJar(PsiElement candidate, PsiElement other) { + VirtualFile c1 = getJarFile(candidate); + VirtualFile c2 = getJarFile(other); + return c1 != null && c1 == c2; + } + }