mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
speedup java class resolve a bit
don't even look for class in on-demand imports when named import matches
This commit is contained in:
@@ -22,6 +22,7 @@ import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.NotNullLazyKey;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.pom.java.LanguageLevel;
|
||||
import com.intellij.psi.*;
|
||||
@@ -313,106 +314,150 @@ public abstract class PsiJavaFileBaseImpl extends PsiFileImpl implements PsiJava
|
||||
}
|
||||
|
||||
private boolean processDeclarationsNoGuess(PsiScopeProcessor processor, @NotNull ResolveState state, PsiElement lastParent, PsiElement place) {
|
||||
PsiImportList importList = getImportList();
|
||||
PsiImportStatement[] importStatements = importList != null ? importList.getImportStatements() : PsiImportStatement.EMPTY_ARRAY;
|
||||
PsiImportStaticStatement[] importStaticStatements = importList != null ? importList.getImportStaticStatements() : PsiImportStaticStatement.EMPTY_ARRAY;
|
||||
StaticImportFilteringProcessor staticImportProcessor = new StaticImportFilteringProcessor(processor);
|
||||
|
||||
boolean shouldProcessClasses = shouldProcessClasses(processor);
|
||||
if (shouldProcessClasses && !processOwnClasses(processor, state)) return false;
|
||||
|
||||
if (!processNamedImports(state, importStatements, importStaticStatements, staticImportProcessor)) return false;
|
||||
|
||||
if (shouldProcessClasses) {
|
||||
if (!processCurrentPackage(processor, state, place)) return false;
|
||||
if (!processOnDemandTypeImports(processor, state, place, importStatements)) return false;
|
||||
}
|
||||
|
||||
if (!processOnDemandStaticImports(state, lastParent, place, importStaticStatements, staticImportProcessor)) return false;
|
||||
|
||||
if (shouldProcessClasses && !processImplicitImports(processor, state, place)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean processOwnClasses(PsiScopeProcessor processor, @NotNull ResolveState state) {
|
||||
processor.handleEvent(PsiScopeProcessor.Event.SET_DECLARATION_HOLDER, this);
|
||||
for (PsiClass aClass : getClasses()) {
|
||||
if (!processor.execute(aClass, state)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean shouldProcessClasses(PsiScopeProcessor processor) {
|
||||
final ElementClassHint classHint = processor.getHint(ElementClassHint.KEY);
|
||||
final NameHint nameHint = processor.getHint(NameHint.KEY);
|
||||
final String name = nameHint != null ? nameHint.getName(state) : null;
|
||||
final PsiImportList importList = getImportList();
|
||||
return classHint == null || classHint.shouldProcess(ElementClassHint.DeclarationKind.CLASS);
|
||||
}
|
||||
|
||||
if (classHint == null || classHint.shouldProcess(ElementClassHint.DeclarationKind.CLASS)) {
|
||||
final PsiClass[] classes = getClasses();
|
||||
for (PsiClass aClass : classes) {
|
||||
if (!processor.execute(aClass, state)) return false;
|
||||
}
|
||||
private static boolean processNamedImports(ResolveState state,
|
||||
PsiImportStatement[] importStatements,
|
||||
PsiImportStaticStatement[] importStaticStatements,
|
||||
StaticImportFilteringProcessor staticImportProcessor) {
|
||||
PsiScopeProcessor processor = staticImportProcessor.myDelegate;
|
||||
|
||||
final PsiImportStatement[] importStatements = importList != null ? importList.getImportStatements() : PsiImportStatement.EMPTY_ARRAY;
|
||||
NameHint nameHint = processor.getHint(NameHint.KEY);
|
||||
String name = nameHint != null ? nameHint.getName(state) : null;
|
||||
|
||||
// single-type processing
|
||||
for (PsiImportStatement statement : importStatements) {
|
||||
if (!statement.isOnDemand()) {
|
||||
if (name != null) {
|
||||
final String refText = statement.getQualifiedName();
|
||||
if (refText == null || !refText.endsWith(name)) continue;
|
||||
}
|
||||
if (shouldProcessClasses(processor) && !processNamedTypeImports(processor, state, name, importStatements)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final PsiElement resolved = statement.resolve();
|
||||
if (resolved instanceof PsiClass) {
|
||||
processor.handleEvent(JavaScopeProcessorEvent.SET_CURRENT_FILE_CONTEXT, statement);
|
||||
final PsiClass containingClass = ((PsiClass)resolved).getContainingClass();
|
||||
if (containingClass != null && containingClass.hasTypeParameters()) {
|
||||
if (!processor.execute(resolved, state.put(PsiSubstitutor.KEY,
|
||||
createRawSubstitutor(containingClass)))) return false;
|
||||
}
|
||||
else if (!processor.execute(resolved, state)) return false;
|
||||
}
|
||||
return processNamedStaticImports(state, name, importStaticStatements, staticImportProcessor);
|
||||
}
|
||||
|
||||
private static boolean processNamedTypeImports(PsiScopeProcessor processor, @NotNull ResolveState state, @Nullable String nameHint, PsiImportStatement[] imports) {
|
||||
for (PsiImportStatement statement : imports) {
|
||||
if (!statement.isOnDemand()) {
|
||||
if (nameHint != null) {
|
||||
final String refText = statement.getQualifiedName();
|
||||
if (refText == null || !nameHint.equals(StringUtil.getShortName(refText))) continue;
|
||||
}
|
||||
}
|
||||
processor.handleEvent(JavaScopeProcessorEvent.SET_CURRENT_FILE_CONTEXT, null);
|
||||
|
||||
// check in current package
|
||||
final PsiPackage aPackage = JavaPsiFacade.getInstance(myManager.getProject()).findPackage(getPackageName());
|
||||
if (aPackage != null && !processPackageDeclarations(processor, state, place, aPackage)) return false;
|
||||
final PsiElement resolved = statement.resolve();
|
||||
if (resolved instanceof PsiClass) {
|
||||
processor.handleEvent(JavaScopeProcessorEvent.SET_CURRENT_FILE_CONTEXT, statement);
|
||||
PsiClass containingClass = ((PsiClass)resolved).getContainingClass();
|
||||
ResolveState classState = containingClass != null && containingClass.hasTypeParameters()
|
||||
? state.put(PsiSubstitutor.KEY, createRawSubstitutor(containingClass))
|
||||
: state;
|
||||
|
||||
// on-demand processing
|
||||
for (PsiImportStatement statement : importStatements) {
|
||||
if (statement.isOnDemand()) {
|
||||
final PsiElement resolved = statement.resolve();
|
||||
if (resolved != null) {
|
||||
processor.handleEvent(JavaScopeProcessorEvent.SET_CURRENT_FILE_CONTEXT, statement);
|
||||
processOnDemandTarget(resolved, processor, state, place);
|
||||
}
|
||||
if (!processor.execute(resolved, classState)) return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
final PsiImportStaticStatement[] importStaticStatements = importList != null ? importList.getImportStaticStatements() : PsiImportStaticStatement.EMPTY_ARRAY;
|
||||
if (importStaticStatements.length > 0) {
|
||||
final StaticImportFilteringProcessor staticImportProcessor = new StaticImportFilteringProcessor(processor);
|
||||
private boolean processCurrentPackage(PsiScopeProcessor processor, ResolveState state, PsiElement place) {
|
||||
processor.handleEvent(JavaScopeProcessorEvent.SET_CURRENT_FILE_CONTEXT, null);
|
||||
PsiPackage aPackage = JavaPsiFacade.getInstance(myManager.getProject()).findPackage(getPackageName());
|
||||
if (aPackage != null && !processPackageDeclarations(processor, state, place, aPackage)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// single member processing
|
||||
for (PsiImportStaticStatement importStaticStatement : importStaticStatements) {
|
||||
if (importStaticStatement.isOnDemand()) continue;
|
||||
|
||||
String referenceName = importStaticStatement.getReferenceName();
|
||||
if (name != null && !name.equals(referenceName)) continue;
|
||||
|
||||
final PsiJavaCodeReferenceElement reference = importStaticStatement.getImportReference();
|
||||
if (reference != null) {
|
||||
final JavaResolveResult[] results = reference.multiResolve(false);
|
||||
if (results.length > 0) {
|
||||
staticImportProcessor.handleEvent(JavaScopeProcessorEvent.SET_CURRENT_FILE_CONTEXT, importStaticStatement);
|
||||
for (JavaResolveResult result : results) {
|
||||
staticImportProcessor.registerSingleStaticImportHiding(result, referenceName);
|
||||
PsiElement element = result.getElement();
|
||||
if (element != null && !staticImportProcessor.execute(element, state)) return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// on-demand processing
|
||||
for (PsiImportStaticStatement importStaticStatement : importStaticStatements) {
|
||||
if (!importStaticStatement.isOnDemand()) continue;
|
||||
final PsiClass targetElement = importStaticStatement.resolveTargetClass();
|
||||
if (targetElement != null) {
|
||||
staticImportProcessor.handleEvent(JavaScopeProcessorEvent.SET_CURRENT_FILE_CONTEXT, importStaticStatement);
|
||||
if (!targetElement.processDeclarations(staticImportProcessor, state, lastParent, place)) return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (classHint == null || classHint.shouldProcess(ElementClassHint.DeclarationKind.CLASS)) {
|
||||
processor.handleEvent(JavaScopeProcessorEvent.SET_CURRENT_FILE_CONTEXT, null);
|
||||
|
||||
final PsiJavaCodeReferenceElement[] implicitlyImported = getImplicitlyImportedPackageReferences();
|
||||
for (PsiJavaCodeReferenceElement aImplicitlyImported : implicitlyImported) {
|
||||
final PsiElement resolved = aImplicitlyImported.resolve();
|
||||
private static boolean processOnDemandTypeImports(PsiScopeProcessor processor, ResolveState state, PsiElement place, PsiImportStatement[] imports) {
|
||||
for (PsiImportStatement statement : imports) {
|
||||
if (statement.isOnDemand()) {
|
||||
final PsiElement resolved = statement.resolve();
|
||||
if (resolved != null) {
|
||||
processor.handleEvent(JavaScopeProcessorEvent.SET_CURRENT_FILE_CONTEXT, statement);
|
||||
if (!processOnDemandTarget(resolved, processor, state, place)) return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean processNamedStaticImports(@NotNull ResolveState state,
|
||||
@Nullable String nameHint,
|
||||
@NotNull PsiImportStaticStatement[] importStaticStatements,
|
||||
StaticImportFilteringProcessor staticImportProcessor) {
|
||||
for (PsiImportStaticStatement importStaticStatement : importStaticStatements) {
|
||||
if (importStaticStatement.isOnDemand()) continue;
|
||||
|
||||
String referenceName = importStaticStatement.getReferenceName();
|
||||
if (nameHint != null && !nameHint.equals(referenceName)) continue;
|
||||
|
||||
final PsiJavaCodeReferenceElement reference = importStaticStatement.getImportReference();
|
||||
if (reference != null) {
|
||||
final JavaResolveResult[] results = reference.multiResolve(false);
|
||||
if (results.length > 0) {
|
||||
staticImportProcessor.handleEvent(JavaScopeProcessorEvent.SET_CURRENT_FILE_CONTEXT, importStaticStatement);
|
||||
for (JavaResolveResult result : results) {
|
||||
staticImportProcessor.registerSingleStaticImportHiding(result, referenceName);
|
||||
PsiElement element = result.getElement();
|
||||
if (element != null && !staticImportProcessor.execute(element, state)) return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean processOnDemandStaticImports(@NotNull ResolveState state,
|
||||
PsiElement lastParent,
|
||||
PsiElement place,
|
||||
PsiImportStaticStatement[] importStaticStatements,
|
||||
StaticImportFilteringProcessor staticImportProcessor) {
|
||||
for (PsiImportStaticStatement importStaticStatement : importStaticStatements) {
|
||||
if (!importStaticStatement.isOnDemand()) continue;
|
||||
final PsiClass targetElement = importStaticStatement.resolveTargetClass();
|
||||
if (targetElement != null) {
|
||||
staticImportProcessor.handleEvent(JavaScopeProcessorEvent.SET_CURRENT_FILE_CONTEXT, importStaticStatement);
|
||||
if (!targetElement.processDeclarations(staticImportProcessor, state, lastParent, place)) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean processImplicitImports(PsiScopeProcessor processor, ResolveState state, PsiElement place) {
|
||||
processor.handleEvent(JavaScopeProcessorEvent.SET_CURRENT_FILE_CONTEXT, null);
|
||||
for (PsiJavaCodeReferenceElement aImplicitlyImported : getImplicitlyImportedPackageReferences()) {
|
||||
final PsiElement resolved = aImplicitlyImported.resolve();
|
||||
if (resolved != null) {
|
||||
if (!processOnDemandTarget(resolved, processor, state, place)) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
+4
-1
@@ -239,7 +239,10 @@ public class ClassResolverProcessor implements PsiScopeProcessor, NameHint, Elem
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return myCurrentFileContext instanceof PsiImportStatementBase;
|
||||
if (myCurrentFileContext instanceof PsiImportStatementBase) {
|
||||
return ((PsiImportStatementBase)myCurrentFileContext).isOnDemand();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean checkAccessibility(final PsiClass aClass) {
|
||||
|
||||
+1
-1
@@ -18,6 +18,6 @@ import static <error descr="'D' is already defined in a single-type import">x.Ba
|
||||
|
||||
class UsageMixed {
|
||||
void use() {
|
||||
<error descr="Reference to 'D' is ambiguous, both 'x.Base1.D' and 'x.Base2.D' match">D</error>.class.getName();
|
||||
D.class.getName();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.intellij.java.psi.resolve
|
||||
|
||||
|
||||
import com.intellij.psi.impl.source.PsiFileImpl
|
||||
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
class LightResolveClassTest extends LightCodeInsightFixtureTestCase {
|
||||
|
||||
void "test no loading for star imported class when named import matches"() {
|
||||
def unnamedFile = myFixture.addFileToProject('unnamed/Bar.java', 'package unnamed; public class Bar {}') as PsiFileImpl
|
||||
def named = myFixture.addClass 'package named; public class Bar {}'
|
||||
def foo = myFixture.addClass '''
|
||||
import unnamed.*;
|
||||
import named.Bar;
|
||||
class Foo extends Bar {}
|
||||
'''
|
||||
|
||||
assertContentsNotLoaded(unnamedFile)
|
||||
assert named == foo.superClass
|
||||
assertContentsNotLoaded(unnamedFile)
|
||||
}
|
||||
|
||||
private static void assertContentsNotLoaded(PsiFileImpl unnamedFile) {
|
||||
assert unnamedFile.derefStub() == null
|
||||
assert unnamedFile.treeElement == null
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
package com.intellij.psi.impl.source;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.intellij.ide.util.PsiNavigationSupport;
|
||||
import com.intellij.lang.*;
|
||||
import com.intellij.navigation.ItemPresentation;
|
||||
@@ -617,7 +618,8 @@ public abstract class PsiFileImpl extends ElementBase implements PsiFileEx, PsiF
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private StubTree derefStub() {
|
||||
@VisibleForTesting
|
||||
public StubTree derefStub() {
|
||||
return myTrees.derefStub();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user