subType pointcut working on types

This commit is contained in:
peter
2011-05-25 20:13:07 +02:00
parent ce7241ce7a
commit 53ce64e3a8
5 changed files with 52 additions and 15 deletions
@@ -1,10 +1,7 @@
package org.jetbrains.plugins.groovy.dsl;
import com.intellij.openapi.util.Key;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ProcessingContext;
import org.jetbrains.annotations.Nullable;
@@ -36,13 +33,42 @@ public abstract class DslPointcut<T,V> {
abstract boolean operatesOn(Class c);
public static DslPointcut<GdslType, GdslType> subType(final Object arg) {
return new DslPointcut<GdslType, GdslType>() {
@Override
List<GdslType> matches(GdslType src, ProcessingContext context) {
final PsiFile placeFile = context.get(GroovyDslScript.INITIAL_CONTEXT).getPlaceFile();
if (ClassContextFilter.isSubtype(src.psiType, placeFile, (String)arg)) {
return Arrays.asList(src);
}
return null;
}
@Override
boolean operatesOn(Class c) {
return GdslType.class == c;
}
};
}
public static DslPointcut<GroovyClassDescriptor, GdslType> currentType(final Object arg) {
final DslPointcut<GdslType,?> inner;
if (arg instanceof String) {
inner = subType(arg);
} else {
inner = (DslPointcut<GdslType, ?>)arg;
assert inner.operatesOn(GdslType.class) : "The argument to currentType should be a pointcut working with types, e.g. subType";
}
return new DslPointcut<GroovyClassDescriptor, GdslType>() {
@Override
List<GdslType> matches(GroovyClassDescriptor src, ProcessingContext context) {
if (ClassContextFilter.subtypeOf((String)arg).isApplicable(src, context)) {
return Arrays.asList(new GdslType(ClassContextFilter.findPsiType(src, context)));
final GdslType currentType = new GdslType(ClassContextFilter.findPsiType(src, context));
if (inner.matches(currentType, context) != null) {
return Arrays.asList(currentType);
}
return null;
}
@@ -9,14 +9,14 @@ import com.intellij.psi.PsiWildcardType;
* @author peter
*/
public class GdslType {
private final PsiType myPsiType;
public final PsiType psiType;
public GdslType(PsiType psiType) {
myPsiType = psiType;
this.psiType = psiType;
}
public String getName() {
PsiType type = myPsiType;
PsiType type = psiType;
if (type instanceof PsiWildcardType) {
type = ((PsiWildcardType)type).getBound();
}
@@ -5,6 +5,7 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProcessCanceledException;
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.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
@@ -29,6 +30,7 @@ import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
* @author peter
*/
public class GroovyDslScript {
public static final Key<GroovyClassDescriptor> INITIAL_CONTEXT = Key.create("gdsl.initialContext");
private static final Logger LOG = Logger.getInstance("#org.jetbrains.plugins.groovy.dsl.GroovyDslScript");
private final Project project;
@Nullable private final VirtualFile file;
@@ -76,6 +78,7 @@ public class GroovyDslScript {
private CustomMembersHolder addGdslMembers(GroovyClassDescriptor descriptor, String qname, final PsiType psiType) {
final ProcessingContext ctx = new ProcessingContext();
ctx.put(ClassContextFilter.getClassKey(qname), psiType);
ctx.put(INITIAL_CONTEXT, descriptor);
try {
if (!isApplicable(executor, descriptor, ctx)) {
return CustomMembersHolder.EMPTY;
@@ -63,18 +63,20 @@ public class ClassContextFilter implements ContextFilter {
return new ClassContextFilter(new Condition<Pair<PsiType, PsiFile>>() {
@Override
public boolean value(Pair<PsiType, PsiFile> p) {
PsiFile place = p.second;
//PsiType myType = JavaPsiFacade.getElementFactory(place.getProject()).createTypeFromText(typeText, place);
PsiType myType = getCachedType(typeText, place);
if (p.first == PsiType.NULL) return myType == PsiType.NULL;
return TypesUtil.isAssignable(myType, p.first, place.getManager(), place.getResolveScope(), false);
return isSubtype(p.first, p.second, typeText);
}
});
}
public static boolean isSubtype(PsiType checked, PsiFile placeFile, String typeText) {
PsiType myType = getCachedType(typeText, placeFile);
if (checked == PsiType.NULL) return myType == PsiType.NULL;
return TypesUtil.isAssignable(myType, checked, placeFile.getManager(), placeFile.getResolveScope(), false);
}
private static final Key<Map<String, PsiType>> CACHED_TYPES = Key.create("Cached types");
private static PsiType getCachedType(String typeText, PsiFile context) {
public static PsiType getCachedType(String typeText, PsiFile context) {
Map<String, PsiType> map = context.getUserData(CACHED_TYPES);
if (map == null) {
map = new ConcurrentHashMap<String, PsiType>();
@@ -22,6 +22,11 @@ class DsldTest extends LightGroovyTestCase {
'println "".foo + [].<warning>foo</warning>'
}
public void testSubType() {
checkHighlighting 'contribute(currentType(subType("java.lang.String"))) { property name:"foo" }',
'println "".foo + [].<warning>foo</warning>'
}
public void testBind() {
checkHighlighting 'contribute(bind(types:currentType("java.lang.CharSequence"))) { property name:types[0].name[-3..-1] }',
'println "".ing + "".<warning>foo</warning>'
@@ -53,6 +58,7 @@ class Foo {
'''
}
private def checkHighlighting(String dsl, String code) {
def file = myFixture.addFileToProject('a.gdsl', dsl)
GroovyDslFileIndex.activateUntilModification(file.virtualFile)