cache super types used in groovy resolve

This commit is contained in:
peter
2010-06-28 18:44:27 +04:00
parent 0eeb73e4c9
commit 565d121b2b
14 changed files with 79 additions and 75 deletions
@@ -22,7 +22,6 @@ import com.intellij.openapi.util.UserDataHolderEx;
import com.intellij.patterns.compiler.PatternCompilerImpl;
import com.intellij.psi.*;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.util.ProcessingContext;
import org.intellij.plugins.intelliLang.inject.InjectorUtils;
import org.intellij.plugins.intelliLang.inject.config.BaseInjection;
import org.jetbrains.annotations.NotNull;
@@ -41,8 +40,7 @@ public class PatternEditorContextMembersProvider extends NonCodeMembersContribut
public void processDynamicElements(@NotNull PsiType qualifierType,
PsiScopeProcessor processor,
PsiElement place,
ResolveState state,
ProcessingContext ctx) {
ResolveState state) {
final PsiFile file = place.getContainingFile().getOriginalFile();
final BaseInjection injection = file.getUserData(BaseInjection.INJECTION_KEY);
if (injection == null) return;
@@ -2,7 +2,6 @@ package org.jetbrains.plugins.groovy.annotator.intentions.dynamic;
import com.intellij.psi.*;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.util.ProcessingContext;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.lang.resolve.NonCodeMembersContributor;
import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
@@ -15,10 +14,9 @@ public class DynamicMembersContributor extends NonCodeMembersContributor {
public void processDynamicElements(@NotNull PsiType qualifierType,
PsiScopeProcessor processor,
PsiElement place,
ResolveState state,
ProcessingContext ctx) {
ResolveState state) {
final DynamicManager manager = DynamicManager.getInstance(place.getProject());
for (String qName : ResolveUtil.getAllSuperTypes(qualifierType, place, ctx).keySet()) {
for (String qName : ResolveUtil.getAllSuperTypes(qualifierType, place).keySet()) {
for (PsiMethod method : manager.getMethods(qName)) {
if (!ResolveUtil.processElement(processor, method)) return;
}
@@ -20,7 +20,6 @@ import com.intellij.psi.impl.light.LightMethodBuilder;
import com.intellij.psi.impl.light.LightVariableBuilder;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ProcessingContext;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentLabel;
@@ -38,9 +37,8 @@ public class GantMemberContributor extends NonCodeMembersContributor {
public void processDynamicElements(@NotNull PsiType qualifierType,
PsiScopeProcessor processor,
PsiElement place,
ResolveState state,
ProcessingContext ctx) {
if (ResolveUtil.isInheritor(qualifierType, "groovy.util.AntBuilder", place, ctx)) {
ResolveState state) {
if (ResolveUtil.isInheritor(qualifierType, "groovy.util.AntBuilder", place)) {
processAntTasks(processor, place);
return;
}
@@ -2,7 +2,6 @@ package org.jetbrains.plugins.groovy.lang.psi.impl;
import com.intellij.psi.*;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.util.ProcessingContext;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.lang.resolve.NonCodeMembersContributor;
import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
@@ -15,10 +14,9 @@ public class GdkMembersContributor extends NonCodeMembersContributor {
public void processDynamicElements(@NotNull PsiType qualifierType,
PsiScopeProcessor processor,
PsiElement place,
ResolveState state,
ProcessingContext ctx) {
ResolveState state) {
final GroovyPsiManager manager = GroovyPsiManager.getInstance(place.getProject());
for (String qName : ResolveUtil.getAllSuperTypes(qualifierType, place, ctx).keySet()) {
for (String qName : ResolveUtil.getAllSuperTypes(qualifierType, place).keySet()) {
for (PsiMethod defaultMethod : manager.getDefaultMethods(qName)) {
if (!ResolveUtil.processElement(processor, defaultMethod)) return;
}
@@ -106,7 +106,7 @@ public class GrConstructorInvocationImpl extends GroovyPsiElementImpl implements
for (NonCodeMembersProcessor membersProcessor : NonCodeMembersProcessor.EP_NAME.getExtensions()) {
if (!membersProcessor.processNonCodeMembers(thisType, processor, this, true)) break;
}
NonCodeMembersContributor.processDynamicElements(thisType, processor, this, ResolveState.initial());
NonCodeMembersContributor.runContributors(thisType, processor, this, ResolveState.initial());
return processor.getCandidates();
}
@@ -138,7 +138,7 @@ public class GrArgumentLabelImpl extends GroovyPsiElementImpl implements GrArgum
if (field != null) return field;
final PropertyResolverProcessor processor = new PropertyResolverProcessor(propName, this);
ResolveUtil
.processNonCodeMethods(JavaPsiFacade.getElementFactory(getProject()).createType(clazz), processor, getProject(), this, false);
.processNonCodeMethods(JavaPsiFacade.getElementFactory(getProject()).createType(clazz), processor, this, false);
final GroovyResolveResult[] candidates = processor.getCandidates();
if (candidates.length == 0) return null;
return candidates[0].getElement();
@@ -87,7 +87,7 @@ public class GrClosableBlockImpl extends GrBlockImpl implements GrClosableBlock
// Process non-code in closures
PsiType clType = JavaPsiFacade.getInstance(getProject()).getElementFactory().createType(closureClass, PsiSubstitutor.EMPTY);
if (!ResolveUtil.processNonCodeMethods(clType, processor, getProject(), place, true)) return false;
if (!ResolveUtil.processNonCodeMethods(clType, processor, place, true)) return false;
}
return true;
@@ -284,7 +284,7 @@ public class CompleteReferenceExpression {
javaLangClass.processDeclarations(processor, ResolveState.initial(), null, refExpr);
PsiType javaLangClassType =
JavaPsiFacade.getInstance(refExpr.getProject()).getElementFactory().createType(javaLangClass, substitutor);
ResolveUtil.processNonCodeMethods(javaLangClassType, processor, refExpr.getProject(), refExpr, true);
ResolveUtil.processNonCodeMethods(javaLangClassType, processor, refExpr, true);
}
}
}
@@ -352,6 +352,6 @@ public class CompleteReferenceExpression {
return;
}
ResolveUtil.processNonCodeMethods(qualifierType, processor, project, refExpr, true);
ResolveUtil.processNonCodeMethods(qualifierType, processor, refExpr, true);
}
}
@@ -624,7 +624,7 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl implements
}
if (!javaLangClass.processDeclarations(processor, state, null, refExpr)) return;
PsiType javaLangClassType = JavaPsiFacade.getInstance(refExpr.getProject()).getElementFactory().createType(javaLangClass, substitutor);
ResolveUtil.processNonCodeMethods(javaLangClassType, processor, refExpr.getProject(), refExpr, false);
ResolveUtil.processNonCodeMethods(javaLangClassType, processor, refExpr, false);
}
}
}
@@ -653,7 +653,7 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl implements
return;
}
ResolveUtil.processNonCodeMethods(qualifierType, processor, project, refExpr, false);
ResolveUtil.processNonCodeMethods(qualifierType, processor, refExpr, false);
}
}
@@ -134,7 +134,7 @@ public class TypesUtil {
}
}
ResolveUtil.processNonCodeMethods(thisType, processor, place.getProject(), place, false);
ResolveUtil.processNonCodeMethods(thisType, processor, place, false);
return processor.getCandidates();
}
return GroovyResolveResult.EMPTY_ARRAY;
@@ -641,7 +641,7 @@ public class PsiUtil {
qClass.processDeclarations(processor, ResolveState.initial().put(PsiSubstitutor.KEY, PsiSubstitutor.EMPTY), null, expr);
}
ResolveUtil.processNonCodeMethods(qualifierType, processor, expr.getProject(), expr, false);
ResolveUtil.processNonCodeMethods(qualifierType, processor, expr, false);
final GroovyResolveResult[] candidates = processor.getCandidates();
PsiType type = null;
if (candidates.length == 1) {
@@ -838,7 +838,7 @@ public class PsiUtil {
for (NonCodeMembersProcessor membersProcessor : NonCodeMembersProcessor.EP_NAME.getExtensions()) {
if (!membersProcessor.processNonCodeMembers(thisType, processor, place, true)) break;
}
NonCodeMembersContributor.processDynamicElements(thisType, processor, place, ResolveState.initial());
NonCodeMembersContributor.runContributors(thisType, processor, place, ResolveState.initial());
constructorResults.addAll(Arrays.asList(processor.getCandidates()));
if (!toBreak) break;
}
@@ -23,7 +23,6 @@ import com.intellij.psi.PsiType;
import com.intellij.psi.ResolveState;
import com.intellij.psi.scope.DelegatingScopeProcessor;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.util.ProcessingContext;
import org.jetbrains.annotations.NotNull;
/**
@@ -32,13 +31,15 @@ import org.jetbrains.annotations.NotNull;
public abstract class NonCodeMembersContributor {
private static final ExtensionPointName<NonCodeMembersContributor> EP_NAME = ExtensionPointName.create("org.intellij.groovy.membersContributor");
public abstract void processDynamicElements(@NotNull PsiType qualifierType, PsiScopeProcessor processor, PsiElement place, ResolveState state, ProcessingContext ctx);
public abstract void processDynamicElements(@NotNull PsiType qualifierType,
PsiScopeProcessor processor,
PsiElement place,
ResolveState state);
public static boolean processDynamicElements(@NotNull final PsiType qualifierType,
public static boolean runContributors(@NotNull final PsiType qualifierType,
PsiScopeProcessor processor,
final PsiElement place,
final ResolveState state) {
final ProcessingContext ctx = new ProcessingContext();
final Ref<Boolean> result = Ref.create(true);
final PsiScopeProcessor wrapper = new DelegatingScopeProcessor(processor) {
@Override
@@ -52,7 +53,7 @@ public abstract class NonCodeMembersContributor {
}
};
for (final NonCodeMembersContributor contributor : EP_NAME.getExtensions()) {
contributor.processDynamicElements(qualifierType, wrapper, place, state, ctx);
contributor.processDynamicElements(qualifierType, wrapper, place, state);
if (!result.get()) {
return false;
}
@@ -17,6 +17,7 @@
package org.jetbrains.plugins.groovy.lang.resolve;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ProjectRootManager;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.*;
@@ -24,11 +25,11 @@ import com.intellij.psi.scope.JavaScopeProcessorEvent;
import com.intellij.psi.scope.NameHint;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.MethodSignature;
import com.intellij.psi.util.MethodSignatureUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.util.ProcessingContext;
import com.intellij.psi.util.*;
import com.intellij.util.containers.ConcurrentFactoryMap;
import com.intellij.util.containers.ConcurrentHashMap;
import com.intellij.util.containers.FactoryMap;
import gnu.trove.TObjectHashingStrategy;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.dsl.GroovyDslFileIndex;
@@ -60,7 +61,19 @@ import java.util.*;
*/
@SuppressWarnings({"StringBufferReplaceableByString"})
public class ResolveUtil {
public static final PsiScopeProcessor.Event DECLARATION_SCOPE_PASSED = new PsiScopeProcessor.Event() {
public static final PsiScopeProcessor.Event DECLARATION_SCOPE_PASSED = new PsiScopeProcessor.Event() {};
private static final Key<CachedValue<FactoryMap<PsiType, Map<String, PsiType>>>> SUPER_TYPES = Key.create("SUPER_TYPES");
private static final TObjectHashingStrategy<PsiType> RAW_TYPE_HASHING_STRATEGY = new TObjectHashingStrategy<PsiType>() {
@Override
public int computeHashCode(PsiType object) {
return rawCanonicalText(object).hashCode();
}
@Override
public boolean equals(PsiType o1, PsiType o2) {
return rawCanonicalText(o1).equals(rawCanonicalText(o2));
}
};
private ResolveUtil() {
@@ -77,12 +90,12 @@ public class ResolveUtil {
if (!run.processDeclarations(processor, ResolveState.initial(), lastParent, place)) return false;
if (processNonCodeMethods) {
if (run instanceof GrTypeDefinition) {
processNonCodeMethods(factory.createType(((GrTypeDefinition)run)), processor, project, place, false);
processNonCodeMethods(factory.createType(((GrTypeDefinition)run)), processor, place, false);
}
else if ((run instanceof GroovyFileBase) && ((GroovyFileBase)run).isScript()) {
final PsiClass psiClass = ((GroovyFileBase)run).getScriptClass();
if (psiClass != null) {
processNonCodeMethods(factory.createType(psiClass), processor, project, place, false);
processNonCodeMethods(factory.createType(psiClass), processor, place, false);
}
}
}
@@ -121,16 +134,9 @@ public class ResolveUtil {
public static boolean processNonCodeMethods(PsiType type,
PsiScopeProcessor processor,
Project project,
PsiElement place,
boolean forCompletion) {
String qName = rawCanonicalText(type);
if (qName == null) {
return true;
}
if (!NonCodeMembersContributor.processDynamicElements(type, processor, place, ResolveState.initial())) {
if (!NonCodeMembersContributor.runContributors(type, processor, place, ResolveState.initial())) {
return false;
}
@@ -141,8 +147,7 @@ public class ResolveUtil {
}
}
final HashMap<String, PsiType> visited = getSuperTypes(type, project);
for (PsiType psiType : visited.values()) {
for (PsiType psiType : getAllSuperTypes(type, place).values()) {
for (NonCodeMembersProcessor membersProcessor : NonCodeMembersProcessor.EP_NAME.getExtensions()) {
if (!membersProcessor.processNonCodeMembers(psiType, processor, place, forCompletion)) return false;
}
@@ -152,51 +157,59 @@ public class ResolveUtil {
private static HashMap<String, PsiType> getSuperTypes(PsiType type, Project project) {
final HashMap<String, PsiType> visited = new HashMap<String, PsiType>();
collectSuperTypes(type, visited, project);
collectSuperTypes(type, visited);
if (type instanceof PsiArrayType) {
final PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
collectSuperTypes(factory.createTypeFromText(CommonClassNames.JAVA_LANG_COMPARABLE, null), visited, project);
collectSuperTypes(factory.createTypeFromText(CommonClassNames.JAVA_IO_SERIALIZABLE, null), visited, project);
collectSuperTypes(factory.createTypeFromText(CommonClassNames.JAVA_LANG_COMPARABLE, null), visited);
collectSuperTypes(factory.createTypeFromText(CommonClassNames.JAVA_IO_SERIALIZABLE, null), visited);
}
return visited;
}
private static void collectSuperTypes(PsiType type, Map<String, PsiType> visited, Project project) {
private static void collectSuperTypes(PsiType type, Map<String, PsiType> visited) {
String qName = rawCanonicalText(type);
if (qName == null || visited.put(qName, type) != null) {
if (visited.put(qName, type) != null) {
return;
}
for (PsiType superType : type.getSuperTypes()) {
collectSuperTypes(TypeConversionUtil.erasure(superType), visited, project);
collectSuperTypes(TypeConversionUtil.erasure(superType), visited);
}
}
private static final Key<FactoryMap<PsiType, Map<String, PsiType>>> SUPER_TYPES = Key.create("SUPER_TYPES");
public static Map<String, PsiType> getAllSuperTypes(PsiType base, final PsiElement place, ProcessingContext ctx) {
FactoryMap<PsiType, Map<String, PsiType>> classes = ctx.get(SUPER_TYPES);
if (classes == null) {
ctx.put(SUPER_TYPES, classes = new FactoryMap<PsiType, Map<String, PsiType>>() {
@Override
protected Map<String, PsiType> create(PsiType key) {
return getSuperTypes(key, place.getProject());
}
});
}
return classes.get(base);
public static Map<String, PsiType> getAllSuperTypes(PsiType base, final PsiElement place) {
final Project project = place.getProject();
return CachedValuesManager.getManager(project).getCachedValue(project, SUPER_TYPES, new CachedValueProvider<FactoryMap<PsiType, Map<String, PsiType>>>() {
@Override
public Result<FactoryMap<PsiType, Map<String, PsiType>>> compute() {
final FactoryMap<PsiType, Map<String, PsiType>> map = new ConcurrentFactoryMap<PsiType, Map<String, PsiType>>() {
@Override
protected Map<PsiType, Map<String, PsiType>> createMap() {
return new ConcurrentHashMap<PsiType, Map<String, PsiType>>(RAW_TYPE_HASHING_STRATEGY);
}
@Override
protected Map<String, PsiType> create(PsiType key) {
return getSuperTypes(key, project);
}
};
return Result.create(map, PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT, ProjectRootManager.getInstance(project));
}
}, false).get(base);
}
public static boolean isInheritor(PsiType type, @NotNull String baseClass, PsiElement place, ProcessingContext ctx) {
return getAllSuperTypes(type, place, ctx).keySet().contains(baseClass);
public static boolean isInheritor(PsiType type, @NotNull String baseClass, PsiElement place) {
return getAllSuperTypes(type, place).keySet().contains(baseClass);
}
@Nullable
private static String rawCanonicalText(PsiType type) {
@NotNull
private static String rawCanonicalText(@NotNull PsiType type) {
final String result = type.getCanonicalText();
if (result == null) return null;
if (result == null) return "";
final int i = result.indexOf('<');
if (i > 0) return result.substring(0, i);
return result;
@@ -446,7 +459,7 @@ public class ResolveUtil {
}
}
else if (parent instanceof GrApplicationStatement) {
final GrExpression funExpr = ((GrApplicationStatement) parent).getFunExpression();
final GrExpression funExpr = ((GrApplicationStatement) parent).getInvokedExpression();
if (funExpr instanceof GrReferenceExpression) {
variants = ((GrReferenceExpression) funExpr).getSameNameVariants();
}
@@ -459,7 +472,7 @@ public class ResolveUtil {
public static GroovyResolveResult[] getConstructorResolveResult(PsiMethod[] constructors, PsiElement place) {
GroovyResolveResult[] variants = new GroovyResolveResult[constructors.length];
for (int i = 0; i < constructors.length; i++) {
final boolean isAccessible = com.intellij.psi.util.PsiUtil.isAccessible(constructors[i], place, null);
final boolean isAccessible = PsiUtil.isAccessible(constructors[i], place, null);
variants[i] = new GroovyResolveResultImpl(constructors[i], isAccessible);
}
return variants;
@@ -19,7 +19,6 @@ package org.jetbrains.plugins.groovy.lang.resolve.noncode;
import com.intellij.psi.*;
import com.intellij.psi.impl.light.LightMethodBuilder;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.util.ProcessingContext;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.annotator.inspections.GroovyImmutableAnnotationInspection;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
@@ -34,8 +33,7 @@ public class ImmutableAnnotationProcessor extends NonCodeMembersContributor {
public void processDynamicElements(@NotNull PsiType qualifierType,
PsiScopeProcessor processor,
PsiElement place,
ResolveState state,
ProcessingContext ctx) {
ResolveState state) {
if (!(qualifierType instanceof PsiClassType)) return;
PsiClass psiClass = ((PsiClassType)qualifierType).resolve();