diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/DslPointcut.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/DslPointcut.java index 8e18329ac3a0..e8d18f5a3dc0 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/DslPointcut.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/DslPointcut.java @@ -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 { abstract boolean operatesOn(Class c); + public static DslPointcut subType(final Object arg) { + return new DslPointcut() { + + @Override + List 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 currentType(final Object arg) { + final DslPointcut inner; + if (arg instanceof String) { + inner = subType(arg); + } else { + inner = (DslPointcut)arg; + assert inner.operatesOn(GdslType.class) : "The argument to currentType should be a pointcut working with types, e.g. subType"; + } + return new DslPointcut() { @Override List 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; } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/GdslType.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/GdslType.java index da5e8dc244b1..4453e13c52dd 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/GdslType.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/GdslType.java @@ -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(); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/GroovyDslScript.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/GroovyDslScript.java index db95e36a8aa2..4fa678a3ed92 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/GroovyDslScript.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/GroovyDslScript.java @@ -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 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; diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/toplevel/ClassContextFilter.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/toplevel/ClassContextFilter.java index ab494c6b04c7..4fbb04adaaa5 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/toplevel/ClassContextFilter.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/dsl/toplevel/ClassContextFilter.java @@ -63,18 +63,20 @@ public class ClassContextFilter implements ContextFilter { return new ClassContextFilter(new Condition>() { @Override public boolean value(Pair 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> CACHED_TYPES = Key.create("Cached types"); - private static PsiType getCachedType(String typeText, PsiFile context) { + public static PsiType getCachedType(String typeText, PsiFile context) { Map map = context.getUserData(CACHED_TYPES); if (map == null) { map = new ConcurrentHashMap(); diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/dsl/DsldTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/dsl/DsldTest.groovy index ca2319158041..1619f37c204c 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/dsl/DsldTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/dsl/DsldTest.groovy @@ -22,6 +22,11 @@ class DsldTest extends LightGroovyTestCase { 'println "".foo + [].foo' } + public void testSubType() { + checkHighlighting 'contribute(currentType(subType("java.lang.String"))) { property name:"foo" }', + 'println "".foo + [].foo' + } + public void testBind() { checkHighlighting 'contribute(bind(types:currentType("java.lang.CharSequence"))) { property name:types[0].name[-3..-1] }', 'println "".ing + "".foo' @@ -53,6 +58,7 @@ class Foo { ''' } + private def checkHighlighting(String dsl, String code) { def file = myFixture.addFileToProject('a.gdsl', dsl) GroovyDslFileIndex.activateUntilModification(file.virtualFile)