mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-08-25 21:44:49 +07:00
IDEADEV-41031
This commit is contained in:
@@ -413,7 +413,7 @@ public class JavaPsiFacadeImpl extends JavaPsiFacadeEx implements Disposable {
|
||||
|
||||
@NotNull
|
||||
public PsiClass[] getClasses(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope scope) {
|
||||
ArrayList<PsiClass> list = new ArrayList<PsiClass>();
|
||||
List<PsiClass> list = new ArrayList<PsiClass>();
|
||||
final PsiDirectory[] dirs = psiPackage.getDirectories(scope);
|
||||
for (PsiDirectory dir : dirs) {
|
||||
PsiClass[] classes = JavaDirectoryService.getInstance().getClasses(dir);
|
||||
|
||||
@@ -38,6 +38,7 @@ import com.intellij.psi.search.LocalSearchScope;
|
||||
import com.intellij.psi.search.searches.ReferencesSearch;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import gnu.trove.THashMap;
|
||||
import gnu.trove.THashSet;
|
||||
import gnu.trove.TObjectIntHashMap;
|
||||
import gnu.trove.TObjectIntProcedure;
|
||||
@@ -123,6 +124,9 @@ public class ImportHelper{
|
||||
packageToCountMap.forEachEntry(new MyVisitorProcedure(true));
|
||||
|
||||
Set<String> classesToUseSingle = findSingleImports(file, resultList, classesOrPackagesToImportOnDemand);
|
||||
Set<String> toReimport = new THashSet<String>();
|
||||
calcClassesConflictingViaOnDemandImports(file, classesOrPackagesToImportOnDemand, file.getResolveScope(), toReimport);
|
||||
classesToUseSingle.addAll(toReimport);
|
||||
|
||||
try {
|
||||
StringBuilder text = buildImportListText(resultList, classesOrPackagesToImportOnDemand, classesToUseSingle);
|
||||
@@ -153,6 +157,13 @@ public class ImportHelper{
|
||||
final String thisPackageName = file.getPackageName();
|
||||
final Set<String> implicitlyImportedPackages = new THashSet<String>(Arrays.asList(file.getImplicitlyImportedPackages()));
|
||||
final PsiManager manager = file.getManager();
|
||||
JavaPsiFacade facade = JavaPsiFacade.getInstance(manager.getProject());
|
||||
List<PsiElement> onDemandElements = new ArrayList<PsiElement>(onDemandImports.size());
|
||||
List<String> onDemandImportsList = new ArrayList<String>(onDemandImports);
|
||||
for (String onDemandName : onDemandImportsList) {
|
||||
PsiElement aClass = facade.findClass(onDemandName, resolveScope);
|
||||
onDemandElements.add(aClass);
|
||||
}
|
||||
for (Pair<String, Boolean> pair : names) {
|
||||
String name = pair.getFirst();
|
||||
Boolean isStatic = pair.getSecond();
|
||||
@@ -169,15 +180,17 @@ public class ImportHelper{
|
||||
}
|
||||
if (!isImplicitlyImported) {
|
||||
String langPackageClass = JAVA_LANG_PACKAGE + "." + shortName; //TODO : JSP!
|
||||
if (JavaPsiFacade.getInstance(manager.getProject()).findClass(langPackageClass, resolveScope) != null) {
|
||||
if (facade.findClass(langPackageClass, resolveScope) != null) {
|
||||
namesToUseSingle.add(name);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
for (String onDemandName : onDemandImports) {
|
||||
for (int i = 0; i < onDemandImportsList.size(); i++) {
|
||||
String onDemandName = onDemandImportsList.get(i);
|
||||
if (prefix.equals(onDemandName)) continue;
|
||||
if (isStatic) {
|
||||
PsiClass aClass = JavaPsiFacade.getInstance(manager.getProject()).findClass(onDemandName, resolveScope);
|
||||
PsiElement element = onDemandElements.get(i);
|
||||
PsiClass aClass = (PsiClass)element;
|
||||
if (aClass != null) {
|
||||
PsiField field = aClass.findFieldByName(shortName, true);
|
||||
if (field != null && field.hasModifierProperty(PsiModifier.STATIC)) {
|
||||
@@ -200,16 +213,62 @@ public class ImportHelper{
|
||||
}
|
||||
}
|
||||
else {
|
||||
PsiClass aClass = JavaPsiFacade.getInstance(manager.getProject()).findClass(onDemandName + "." + shortName, resolveScope);
|
||||
PsiClass aClass = facade.findClass(onDemandName + "." + shortName, resolveScope);
|
||||
if (aClass != null) {
|
||||
namesToUseSingle.add(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return namesToUseSingle;
|
||||
}
|
||||
|
||||
private static void calcClassesConflictingViaOnDemandImports(PsiJavaFile file, Collection<String> onDemandImportsList,
|
||||
GlobalSearchScope resolveScope, final Set<String> namesToUseSingle) {
|
||||
List<String> onDemands = new ArrayList<String>(Arrays.asList(file.getImplicitlyImportedPackages()));
|
||||
onDemands.addAll(onDemandImportsList);
|
||||
if (onDemands.size() < 2) return;
|
||||
|
||||
Map<String, Set<String>> classNames = new THashMap<String, Set<String>>();
|
||||
JavaPsiFacade facade = JavaPsiFacade.getInstance(file.getProject());
|
||||
for (String onDemand : onDemands) {
|
||||
PsiPackage aPackage = facade.findPackage(onDemand);
|
||||
if (aPackage == null) continue;
|
||||
PsiClass[] psiClasses = aPackage.getClasses(resolveScope);
|
||||
Set<String> set = new THashSet<String>(psiClasses.length);
|
||||
for (PsiClass psiClass : psiClasses) {
|
||||
set.add(psiClass.getName());
|
||||
}
|
||||
classNames.put(onDemand, set);
|
||||
}
|
||||
|
||||
final Set<String> conflicts = new THashSet<String>();
|
||||
for (int i = 0; i < onDemands.size(); i++) {
|
||||
String on1 = onDemands.get(i);
|
||||
for (int j = i+1; j < onDemands.size(); j++) {
|
||||
String on2 = onDemands.get(j);
|
||||
Set<String> inter = new THashSet<String>(classNames.get(on1));
|
||||
inter.retainAll(classNames.get(on2));
|
||||
|
||||
conflicts.addAll(inter);
|
||||
}
|
||||
}
|
||||
if (!conflicts.isEmpty()) {
|
||||
file.accept(new JavaRecursiveElementVisitor() {
|
||||
@Override
|
||||
public void visitReferenceElement(PsiJavaCodeReferenceElement reference) {
|
||||
if (reference.getQualifier() != null) return;
|
||||
PsiElement element = reference.resolve();
|
||||
if (element instanceof PsiClass && conflicts.contains(((PsiClass)element).getName())) {
|
||||
String fqn = ((PsiClass)element).getQualifiedName();
|
||||
namesToUseSingle.add(fqn);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static StringBuilder buildImportListText(@NotNull List<Pair<String, Boolean>> names,
|
||||
@NotNull final Set<String> packagesOrClassesToImportOnDemand,
|
||||
@@ -222,7 +281,7 @@ public class ImportHelper{
|
||||
String packageOrClassName = getPackageOrClassName(name);
|
||||
final boolean implicitlyImported = JAVA_LANG_PACKAGE.equals(packageOrClassName);
|
||||
boolean useOnDemand = implicitlyImported || packagesOrClassesToImportOnDemand.contains(packageOrClassName);
|
||||
if (useOnDemand && namesToUseSingle.contains(name)) {
|
||||
if (useOnDemand && namesToUseSingle.remove(name)) {
|
||||
useOnDemand = false;
|
||||
}
|
||||
if (useOnDemand && (importedPackagesOrClasses.contains(packageOrClassName) || implicitlyImported)) continue;
|
||||
@@ -239,6 +298,12 @@ public class ImportHelper{
|
||||
buffer.append(";\n");
|
||||
}
|
||||
|
||||
for (String remainingSingle : namesToUseSingle) {
|
||||
buffer.append("import ");
|
||||
buffer.append(remainingSingle);
|
||||
buffer.append(";\n");
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
@@ -276,7 +341,7 @@ public class ImportHelper{
|
||||
useOnDemand = false;
|
||||
}
|
||||
|
||||
List<PsiElement> classesToReimport = new ArrayList<PsiElement>();
|
||||
List<PsiClass> classesToReimport = new ArrayList<PsiClass>();
|
||||
|
||||
List<PsiJavaCodeReferenceElement> importRefs = getImportsFromPackage(file, packageName);
|
||||
if (useOnDemand){
|
||||
@@ -292,60 +357,30 @@ public class ImportHelper{
|
||||
// check conflicts
|
||||
if (useOnDemand){
|
||||
PsiElement[] onDemandRefs = file.getOnDemandImports(false, true);
|
||||
if (onDemandRefs.length > 0){
|
||||
PsiPackage aPackage = facade.findPackage(packageName);
|
||||
if (aPackage != null){
|
||||
PsiDirectory[] dirs = aPackage.getDirectories();
|
||||
for (PsiDirectory dir : dirs) {
|
||||
PsiFile[] files = dir.getFiles(); // do not iterate classes - too slow when not loaded
|
||||
for (PsiFile aFile : files) {
|
||||
if (aFile instanceof PsiJavaFile) {
|
||||
String name = aFile.getVirtualFile().getNameWithoutExtension();
|
||||
for (PsiElement ref : onDemandRefs) {
|
||||
String refName = ref instanceof PsiClass ? ((PsiClass)ref).getQualifiedName() : ((PsiPackage)ref).getQualifiedName();
|
||||
String conflictClassName = refName + "." + name;
|
||||
GlobalSearchScope resolveScope = file.getResolveScope();
|
||||
PsiClass conflictClass = facade.findClass(conflictClassName, resolveScope);
|
||||
if (conflictClass != null && helper.isAccessible(conflictClass, file, null)) {
|
||||
String conflictClassName2 = aPackage.getQualifiedName() + "." + name;
|
||||
PsiClass conflictClass2 = facade.findClass(conflictClassName2, resolveScope);
|
||||
if (conflictClass2 != null && helper.isAccessible(conflictClass2, file, null)) {
|
||||
if (ReferencesSearch.search(conflictClass, new LocalSearchScope(file), false).findFirst() != null) {
|
||||
classesToReimport.add(conflictClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
List<String> refTexts = new ArrayList<String>(onDemandRefs.length);
|
||||
for (PsiElement ref : onDemandRefs) {
|
||||
String refName = ref instanceof PsiClass ? ((PsiClass)ref).getQualifiedName() : ((PsiPackage)ref).getQualifiedName();
|
||||
refTexts.add(refName);
|
||||
}
|
||||
calcClassesToReimport(file, facade, helper, packageName, classesToReimport, refTexts);
|
||||
}
|
||||
}
|
||||
|
||||
try{
|
||||
try {
|
||||
PsiImportList importList = file.getImportList();
|
||||
PsiImportStatement statement;
|
||||
if (useOnDemand) {
|
||||
statement = factory.createImportStatementOnDemand(packageName);
|
||||
}
|
||||
else {
|
||||
statement = factory.createImportStatement(refClass);
|
||||
}
|
||||
PsiImportStatement statement = useOnDemand ? factory.createImportStatementOnDemand(packageName) : factory.createImportStatement(refClass);
|
||||
importList.add(statement);
|
||||
if (useOnDemand) {
|
||||
for (PsiJavaCodeReferenceElement ref : importRefs) {
|
||||
LOG.assertTrue(ref.getParent() instanceof PsiImportStatement);
|
||||
if (!ref.isValid()) continue; // todo[dsl] Q?
|
||||
classesToReimport.add(ref.resolve());
|
||||
classesToReimport.add((PsiClass)ref.resolve());
|
||||
PsiImportStatement importStatement = (PsiImportStatement) ref.getParent();
|
||||
importStatement.delete();
|
||||
}
|
||||
}
|
||||
|
||||
for (PsiElement aClassesToReimport : classesToReimport) {
|
||||
PsiClass aClass = (PsiClass)aClassesToReimport;
|
||||
for (PsiClass aClass : classesToReimport) {
|
||||
if (aClass != null) {
|
||||
addImport(file, aClass);
|
||||
}
|
||||
@@ -357,6 +392,37 @@ public class ImportHelper{
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void calcClassesToReimport(PsiJavaFile file, JavaPsiFacade facade, PsiResolveHelper helper, String packageName, List<PsiClass> classesToReimport,
|
||||
Collection<String> onDemandRefs) {
|
||||
if (onDemandRefs.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
PsiPackage aPackage = facade.findPackage(packageName);
|
||||
if (aPackage != null) {
|
||||
PsiDirectory[] dirs = aPackage.getDirectories();
|
||||
GlobalSearchScope resolveScope = file.getResolveScope();
|
||||
for (PsiDirectory dir : dirs) {
|
||||
PsiFile[] files = dir.getFiles(); // do not iterate classes - too slow when not loaded
|
||||
for (PsiFile aFile : files) {
|
||||
if (!(aFile instanceof PsiJavaFile)) continue;
|
||||
String name = aFile.getVirtualFile().getNameWithoutExtension();
|
||||
for (String refName : onDemandRefs) {
|
||||
String conflictClassName = refName + "." + name;
|
||||
PsiClass conflictClass = facade.findClass(conflictClassName, resolveScope);
|
||||
if (conflictClass == null || !helper.isAccessible(conflictClass, file, null)) continue;
|
||||
String conflictClassName2 = packageName + "." + name;
|
||||
PsiClass conflictClass2 = facade.findClass(conflictClassName2, resolveScope);
|
||||
if (conflictClass2 != null &&
|
||||
helper.isAccessible(conflictClass2, file, null) &&
|
||||
ReferencesSearch.search(conflictClass, new LocalSearchScope(file), false).findFirst() != null) {
|
||||
classesToReimport.add(conflictClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static List<PsiJavaCodeReferenceElement> getImportsFromPackage(@NotNull PsiJavaFile file, @NotNull String packageName){
|
||||
PsiClass[] refs = file.getSingleClassImports(true);
|
||||
|
||||
+43
-30
@@ -85,7 +85,8 @@ public class ClassResolverProcessor extends BaseScopeProcessor implements NameHi
|
||||
public void handleEvent(Event event, Object associated) {
|
||||
if (event == JavaScopeProcessorEvent.START_STATIC) {
|
||||
myStaticContext = true;
|
||||
} else if (event == JavaScopeProcessorEvent.SET_CURRENT_FILE_CONTEXT) {
|
||||
}
|
||||
else if (event == JavaScopeProcessorEvent.SET_CURRENT_FILE_CONTEXT) {
|
||||
myCurrentFileContext = (PsiElement)associated;
|
||||
}
|
||||
}
|
||||
@@ -94,36 +95,52 @@ public class ClassResolverProcessor extends BaseScopeProcessor implements NameHi
|
||||
if (!(element instanceof PsiClass)) return true;
|
||||
final PsiClass aClass = (PsiClass)element;
|
||||
final String name = aClass.getName();
|
||||
if (myClassName.equals(name)) {
|
||||
if (myCandidates == null) {
|
||||
myCandidates = new SmartList<ClassCandidateInfo>();
|
||||
}
|
||||
else {
|
||||
String fqName = aClass.getQualifiedName();
|
||||
if (fqName != null) {
|
||||
for (ClassCandidateInfo info : myCandidates) {
|
||||
final PsiClass otherClass = info.getElement();
|
||||
assert otherClass != null;
|
||||
if (fqName.equals(otherClass.getQualifiedName())) {
|
||||
return true;
|
||||
}
|
||||
final PsiClass containingclass1 = aClass.getContainingClass();
|
||||
final PsiClass containingclass2 = otherClass.getContainingClass();
|
||||
if (containingclass1 != null && containingclass2 != null && containingclass2.isInheritor(containingclass1, true)) {
|
||||
//shadowing
|
||||
return true;
|
||||
if (!myClassName.equals(name)) {
|
||||
return true;
|
||||
}
|
||||
if (myCandidates == null) {
|
||||
myCandidates = new SmartList<ClassCandidateInfo>();
|
||||
}
|
||||
else {
|
||||
String fqName = aClass.getQualifiedName();
|
||||
if (fqName != null) {
|
||||
for (int i = myCandidates.size()-1; i>=0; i--) {
|
||||
ClassCandidateInfo info = myCandidates.get(i);
|
||||
final PsiClass otherClass = info.getElement();
|
||||
assert otherClass != null;
|
||||
if (fqName.equals(otherClass.getQualifiedName())) {
|
||||
return true;
|
||||
}
|
||||
final PsiClass containingclass1 = aClass.getContainingClass();
|
||||
final PsiClass containingclass2 = otherClass.getContainingClass();
|
||||
if (containingclass1 != null && containingclass2 != null && containingclass2.isInheritor(containingclass1, true)) {
|
||||
//shadowing
|
||||
return true;
|
||||
}
|
||||
|
||||
// single import wins over on-demand
|
||||
if (myCurrentFileContext instanceof PsiImportStatementBase &&
|
||||
info.getCurrentFileResolveScope() instanceof PsiImportStatementBase) {
|
||||
PsiImportStatementBase myImport = (PsiImportStatementBase)myCurrentFileContext;
|
||||
PsiImportStatementBase otherImport = (PsiImportStatementBase)info.getCurrentFileResolveScope();
|
||||
if (myImport.isOnDemand() && !otherImport.isOnDemand()) return true;
|
||||
if (!myImport.isOnDemand() && otherImport.isOnDemand()) {
|
||||
myCandidates.remove(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean accessible = myPlace == null || checkAccessibility(aClass);
|
||||
myHasAccessibleCandidate |= accessible;
|
||||
myHasInaccessibleCandidate |= !accessible;
|
||||
myCandidates.add(new ClassCandidateInfo(aClass, state.get(PsiSubstitutor.KEY), !accessible, myCurrentFileContext));
|
||||
myResult = null;
|
||||
//return !accessible;
|
||||
}
|
||||
|
||||
boolean accessible = myPlace == null || checkAccessibility(aClass);
|
||||
myHasAccessibleCandidate |= accessible;
|
||||
myHasInaccessibleCandidate |= !accessible;
|
||||
myCandidates.add(new ClassCandidateInfo(aClass, state.get(PsiSubstitutor.KEY), !accessible, myCurrentFileContext));
|
||||
myResult = null;
|
||||
if (!accessible) return true;
|
||||
if (!(myCurrentFileContext instanceof PsiImportStatementBase)) return false;
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -183,10 +200,6 @@ public class ClassResolverProcessor extends BaseScopeProcessor implements NameHi
|
||||
return accessible;
|
||||
}
|
||||
|
||||
public void forceResult(JavaResolveResult[] result) {
|
||||
myResult = result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getHint(Key<T> hintKey) {
|
||||
if (hintKey == ElementClassHint.KEY || hintKey == NameHint.KEY) {
|
||||
|
||||
Reference in New Issue
Block a user