during resolve and search for inheritors prefer classes from my own jar

This commit is contained in:
Alexey Kudravtsev
2010-08-03 12:35:09 +04:00
parent bc862d3400
commit 289e8164e6
3 changed files with 88 additions and 14 deletions
@@ -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);
@@ -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) {
@@ -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<PsiClass, DirectClassInheritorsSearch.SearchParameters> {
public boolean execute(final DirectClassInheritorsSearch.SearchParameters p, final Processor<PsiClass> consumer) {
final PsiClass aClass = p.getClassToProcess();
final PsiManagerImpl psiManager = (PsiManagerImpl)PsiManager.getInstance(aClass.getProject());
@@ -73,10 +78,22 @@ public class JavaDirectInheritorsSearcher implements QueryExecutor<PsiClass, Dir
}
});
Map<String, List<PsiClass>> classes = new HashMap<String, List<PsiClass>>();
for (PsiReferenceList referenceList : candidates) {
ProgressManager.checkCanceled();
PsiClass candidate = (PsiClass)referenceList.getParent();
if (!consumer.process(candidate)) return false;
String fqn = candidate.getQualifiedName();
List<PsiClass> list = classes.get(fqn);
if (list == null) {
list = new ArrayList<PsiClass>();
classes.put(fqn, list);
}
list.add(candidate);
}
for (List<PsiClass> sameNamedClasses : classes.values()) {
if (!processSameNamedClasses(consumer, aClass, sameNamedClasses)) return false;
}
if (p.includeAnonymous()) {
@@ -116,4 +133,37 @@ public class JavaDirectInheritorsSearcher implements QueryExecutor<PsiClass, Dir
return true;
}
private static boolean processSameNamedClasses(Processor<PsiClass> consumer, PsiClass aClass, List<PsiClass> 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;
}
}