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:
peter
2018-04-16 18:59:52 +02:00
parent a8613266c6
commit b2b723fa44
5 changed files with 163 additions and 83 deletions
@@ -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;
}
@@ -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) {
@@ -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();
}