move functionality of GrClassEnhancer to NonCodeMembersContributor.

This commit is contained in:
Sergey Evdokimov
2011-10-07 17:52:21 +04:00
parent 61c9304f84
commit 1d7596ae92
6 changed files with 103 additions and 133 deletions
+2 -5
View File
@@ -29,7 +29,6 @@
<extensionPoints>
<extensionPoint name="membersContributor" interface="org.jetbrains.plugins.groovy.lang.resolve.NonCodeMembersContributor"/>
<extensionPoint name="classEnhancer" interface="org.jetbrains.plugins.groovy.lang.resolve.GrClassEnhancer"/>
<extensionPoint name="astTransformContributor" interface="org.jetbrains.plugins.groovy.lang.resolve.AstTransformContributor"/>
<extensionPoint name="closureMissingMethodContributor" interface="org.jetbrains.plugins.groovy.lang.resolve.ClosureMissingMethodContributor"/>
<extensionPoint name="variableEnhancer" interface="org.jetbrains.plugins.groovy.lang.psi.GrVariableEnhancer"/>
@@ -70,12 +69,10 @@
<membersContributor implementation="org.jetbrains.plugins.groovy.annotator.intentions.dynamic.DynamicMembersContributor"/>
<membersContributor implementation="org.jetbrains.plugins.groovy.lang.resolve.noncode.ConstructorAnnotationsProcessor"/>
<membersContributor implementation="org.jetbrains.plugins.groovy.lang.resolve.noncode.GrInheritConstructorContributor"/>
<membersContributor implementation="org.jetbrains.plugins.groovy.lang.resolve.noncode.GrCollectionTypeMembersProvider"/>
<membersContributor implementation="org.jetbrains.plugins.groovy.lang.resolve.noncode.LoggingContributor"/>
<membersContributor implementation="org.jetbrains.plugins.groovy.spock.SpockMemberContributor"/>
<membersContributor implementation="org.jetbrains.plugins.groovy.lang.resolve.MixinMemberContributor"/>
<membersContributor implementation="org.jetbrains.plugins.groovy.lang.resolve.GrClassNonCodeMembersContributor"/>
<classEnhancer implementation="org.jetbrains.plugins.groovy.lang.resolve.noncode.GrCollectionTypeMembersProvider"/>
<classEnhancer implementation="org.jetbrains.plugins.groovy.spock.SpockMemberContributor"/>
<astTransformContributor implementation="org.jetbrains.plugins.groovy.lang.resolve.ast.DelegatedMethodsContributor"/>
<astTransformContributor implementation="org.jetbrains.plugins.groovy.lang.resolve.ast.AutoExternalizeContributor"/>
@@ -1,44 +0,0 @@
package org.jetbrains.plugins.groovy.lang.resolve;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiType;
import com.intellij.psi.ResolveState;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.util.containers.MultiMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
/**
* @author Sergey Evdokimov
*/
public abstract class GrClassEnhancer {
private static final ExtensionPointName<GrClassEnhancer> EP_NAME = ExtensionPointName.create("org.intellij.groovy.classEnhancer");
private static volatile MultiMap<String, GrClassEnhancer> ourEnhancers;
@NotNull
public abstract String getQualifiedName();
public abstract boolean processDynamicElements(@NotNull PsiType qualifierType,
@NotNull PsiClass aClass,
PsiScopeProcessor processor,
GroovyPsiElement place,
ResolveState state);
public static MultiMap<String, GrClassEnhancer> getEnhancers() {
MultiMap<String, GrClassEnhancer> res = ourEnhancers;
if (ourEnhancers == null) {
res = new MultiMap<String, GrClassEnhancer>();
for (GrClassEnhancer enhancer : EP_NAME.getExtensions()) {
res.putValue(enhancer.getQualifiedName(), enhancer);
}
ourEnhancers = res;
}
return res;
}
}
@@ -1,56 +0,0 @@
package org.jetbrains.plugins.groovy.lang.resolve;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiType;
import com.intellij.psi.ResolveState;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.PsiTypesUtil;
import com.intellij.util.containers.MultiMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
import org.jetbrains.plugins.groovy.util.LightCacheKey;
import java.util.HashSet;
import java.util.Set;
/**
* @author Sergey Evdokimov
*/
public class GrClassNonCodeMembersContributor extends NonCodeMembersContributor {
private static final LightCacheKey<String[]> KEY = LightCacheKey.create();
@Override
public void processDynamicElements(@NotNull final PsiType qualifierType,
final PsiScopeProcessor processor,
final GroovyPsiElement place,
final ResolveState state) {
final PsiClass aClass = PsiTypesUtil.getPsiClass(qualifierType);
if (aClass == null) return;
String[] superClassNames = KEY.getCachedValue(aClass);
if (superClassNames == null) {
Set<PsiClass> superClasses = new HashSet<PsiClass>();
superClasses.add(aClass);
InheritanceUtil.getSuperClasses(aClass, superClasses, true);
superClassNames = new String[superClasses.size()];
int i = 0;
for (PsiClass superClass : superClasses) {
superClassNames[i++] = superClass.getQualifiedName();
}
superClassNames = KEY.putCachedValue(aClass, superClassNames);
}
final MultiMap<String, GrClassEnhancer> enhancers = GrClassEnhancer.getEnhancers();
for (String superClassName : superClassNames) {
for (GrClassEnhancer enhancer : enhancers.get(superClassName)) {
if (!enhancer.processDynamicElements(qualifierType, aClass, processor, place, state)) return;
}
}
}
}
@@ -17,14 +17,22 @@
package org.jetbrains.plugins.groovy.lang.resolve;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
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.psi.util.InheritanceUtil;
import com.intellij.psi.util.PsiTypesUtil;
import com.intellij.util.containers.MultiMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.dsl.GroovyDslFileIndex;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
import org.jetbrains.plugins.groovy.util.LightCacheKey;
import java.util.*;
/**
* @author peter
@@ -32,11 +40,45 @@ import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
public abstract class NonCodeMembersContributor {
private static final ExtensionPointName<NonCodeMembersContributor> EP_NAME = ExtensionPointName.create("org.intellij.groovy.membersContributor");
public abstract void processDynamicElements(@NotNull PsiType qualifierType,
private static final LightCacheKey<String[]> KEY = LightCacheKey.create();
private static volatile MultiMap<String, NonCodeMembersContributor> ourClassSpecifiedContributors;
private static NonCodeMembersContributor[] ourAllTypeContributors;
public void processDynamicElements(@NotNull PsiType qualifierType,
PsiScopeProcessor processor,
GroovyPsiElement place,
ResolveState state);
ResolveState state) {
throw new RuntimeException("One of two 'processDynamicElements()' methods must be implemented");
}
public void processDynamicElements(@NotNull PsiType qualifierType,
PsiClass aClass,
PsiScopeProcessor processor,
GroovyPsiElement place,
ResolveState state) {
processDynamicElements(qualifierType, processor, place, state);
}
@Nullable
protected String getParentClassName() {
return null;
}
private static void ensureInit() {
if (ourClassSpecifiedContributors != null) return;
MultiMap<String, NonCodeMembersContributor> contributorMap = new MultiMap<String, NonCodeMembersContributor>();
for (final NonCodeMembersContributor contributor : EP_NAME.getExtensions()) {
contributorMap.putValue(contributor.getParentClassName(), contributor);
}
Collection<NonCodeMembersContributor> allTypeContributors = contributorMap.remove(null);
ourAllTypeContributors = allTypeContributors.toArray(new NonCodeMembersContributor[allTypeContributors.size()]);
ourClassSpecifiedContributors = contributorMap;
}
public static boolean runContributors(@NotNull final PsiType qualifierType,
PsiScopeProcessor processor,
final GroovyPsiElement place,
@@ -44,15 +86,50 @@ public abstract class NonCodeMembersContributor {
MyDelegatingScopeProcessor delegatingProcessor = new MyDelegatingScopeProcessor(processor);
for (final NonCodeMembersContributor contributor : EP_NAME.getExtensions()) {
contributor.processDynamicElements(qualifierType, delegatingProcessor, place, state);
ensureInit();
final PsiClass aClass = PsiTypesUtil.getPsiClass(qualifierType);
if (aClass != null) {
for (String superClassName : getParentClassNames(aClass)) {
for (NonCodeMembersContributor enhancer : ourClassSpecifiedContributors.get(superClassName)) {
enhancer.processDynamicElements(qualifierType, aClass, delegatingProcessor, place, state);
if (!delegatingProcessor.wantMore) {
return false;
}
}
}
}
for (NonCodeMembersContributor contributor : ourAllTypeContributors) {
contributor.processDynamicElements(qualifierType, aClass, delegatingProcessor, place, state);
if (!delegatingProcessor.wantMore) {
return false;
}
}
return GroovyDslFileIndex.processExecutors(qualifierType, place, processor, state);
}
protected static String[] getParentClassNames(PsiClass aClass) {
String[] superClassNames = KEY.getCachedValue(aClass);
if (superClassNames == null) {
Set<PsiClass> superClasses = new HashSet<PsiClass>();
superClasses.add(aClass);
InheritanceUtil.getSuperClasses(aClass, superClasses, true);
superClassNames = new String[superClasses.size()];
int i = 0;
for (PsiClass superClass : superClasses) {
superClassNames[i++] = superClass.getQualifiedName();
}
superClassNames = KEY.putCachedValue(aClass, superClassNames);
}
return superClassNames;
}
private static class MyDelegatingScopeProcessor extends DelegatingScopeProcessor {
public boolean wantMore = true;
@@ -24,32 +24,31 @@ import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.psi.util.PsiUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
import org.jetbrains.plugins.groovy.lang.resolve.GrClassEnhancer;
import org.jetbrains.plugins.groovy.lang.resolve.NonCodeMembersContributor;
import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassHint;
/**
* @author Maxim.Medvedev
*/
public class GrCollectionTypeMembersProvider extends GrClassEnhancer {
public class GrCollectionTypeMembersProvider extends NonCodeMembersContributor {
@NotNull
@Override
public String getQualifiedName() {
public String getParentClassName() {
return CommonClassNames.JAVA_UTIL_COLLECTION;
}
@Override
public boolean processDynamicElements(final @NotNull PsiType qualifierType,
@NotNull PsiClass aClass,
public void processDynamicElements(final @NotNull PsiType qualifierType,
PsiClass aClass,
final PsiScopeProcessor processor,
final GroovyPsiElement place,
final ResolveState state) {
final PsiType collectionType = PsiUtil.extractIterableTypeParameter(qualifierType, true);
if (collectionType == null) return true;
if (collectionType == null) return;
final PsiScopeProcessor fieldSearcher = new FieldSearcher(processor, JavaPsiFacade.getInstance(place.getProject()).findClass(CommonClassNames.JAVA_UTIL_COLLECTION, place.getResolveScope()));
return ResolveUtil.processAllDeclarations(collectionType, fieldSearcher, state, place);
ResolveUtil.processAllDeclarations(collectionType, fieldSearcher, state, place);
}
private static class FieldSearcher implements PsiScopeProcessor, ClassHint, ElementClassHint {
@@ -8,7 +8,7 @@ import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
import org.jetbrains.plugins.groovy.lang.resolve.GrClassEnhancer;
import org.jetbrains.plugins.groovy.lang.resolve.NonCodeMembersContributor;
import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassHint;
@@ -17,43 +17,40 @@ import java.util.Map;
/**
* @author Sergey Evdokimov
*/
public class SpockMemberContributor extends GrClassEnhancer {
public class SpockMemberContributor extends NonCodeMembersContributor {
@Override
public boolean processDynamicElements(@NotNull PsiType qualifierType,
@NotNull PsiClass aClass,
PsiScopeProcessor processor,
GroovyPsiElement place,
ResolveState state) {
public void processDynamicElements(@NotNull PsiType qualifierType,
PsiClass aClass,
PsiScopeProcessor processor,
GroovyPsiElement place,
ResolveState state) {
ClassHint classHint = processor.getHint(ClassHint.KEY);
if (classHint != null && !classHint.shouldProcess(ClassHint.ResolveKind.PROPERTY)) return true;
if (classHint != null && !classHint.shouldProcess(ClassHint.ResolveKind.PROPERTY)) return;
GrMethod method = PsiTreeUtil.getParentOfType(place, GrMethod.class);
if (method == null) return true;
if (method == null) return;
if (aClass != method.getContainingClass()) return true;
if (aClass != method.getContainingClass()) return;
Map<String, SpockVariableDescriptor> cachedValue = SpockUtils.getVariableMap(method);
String nameHint = ResolveUtil.getNameHint(processor);
if (nameHint == null) {
for (SpockVariableDescriptor spockVar : cachedValue.values()) {
if (!processor.execute(spockVar.getVariable(), state)) return false;
if (!processor.execute(spockVar.getVariable(), state)) return;
}
}
else {
SpockVariableDescriptor spockVar = cachedValue.get(nameHint);
if (spockVar != null && spockVar.getNavigationElement() != place) {
if (!processor.execute(spockVar.getVariable(), state)) return false;
if (!processor.execute(spockVar.getVariable(), state)) return;
}
}
return true;
}
@NotNull
@Override
public String getQualifiedName() {
public String getParentClassName() {
return SpockUtils.SPEC_CLASS_NAME;
}
}