diff --git a/plugins/ant/ant.iml b/plugins/ant/ant.iml index d0adaec1ca6e..23e5720400f3 100644 --- a/plugins/ant/ant.iml +++ b/plugins/ant/ant.iml @@ -19,7 +19,7 @@ - + diff --git a/plugins/ant/src/com/intellij/lang/ant/dom/AntDomExtender.java b/plugins/ant/src/com/intellij/lang/ant/dom/AntDomExtender.java index b3692cb2642e..b64dd2b01b2c 100644 --- a/plugins/ant/src/com/intellij/lang/ant/dom/AntDomExtender.java +++ b/plugins/ant/src/com/intellij/lang/ant/dom/AntDomExtender.java @@ -53,13 +53,13 @@ public class AntDomExtender extends DomExtender{ } else { final Map tasks = reflected.getTaskDefinitions(); - final Class taskClass = (Class)tasks.get(tagName); + final Class taskClass = tasks.get(tagName); if (taskClass != null) { parentElementIntrospector = getIntrospector(taskClass); } else { final Map dataTypes = reflected.getDataTypeDefinitions(); - final Class dataClass = (Class)dataTypes.get(tagName); + final Class dataClass = dataTypes.get(tagName); if (dataClass != null) { parentElementIntrospector = getIntrospector(dataClass); } @@ -83,9 +83,9 @@ public class AntDomExtender extends DomExtender{ } } else { - final Enumeration nested = parentElementIntrospector.getNestedElements(); + final Enumeration nested = parentElementIntrospector.getNestedElements(); while (nested.hasMoreElements()) { - registerChild(registrar, genericInfo, (String)nested.nextElement()); + registerChild(registrar, genericInfo, nested.nextElement()); } } } @@ -113,7 +113,7 @@ public class AntDomExtender extends DomExtender{ } @Nullable - private static AntIntrospector getIntrospector(Class c) { + public static AntIntrospector getIntrospector(Class c) { try { return AntIntrospector.getInstance(c); } diff --git a/plugins/ant/src/com/intellij/lang/ant/psi/impl/AntIntrospector.java b/plugins/ant/src/com/intellij/lang/ant/psi/impl/AntIntrospector.java index 596e9cdb6eaf..42acaa1d4454 100644 --- a/plugins/ant/src/com/intellij/lang/ant/psi/impl/AntIntrospector.java +++ b/plugins/ant/src/com/intellij/lang/ant/psi/impl/AntIntrospector.java @@ -99,7 +99,7 @@ public final class AntIntrospector { return types; } - public Enumeration getNestedElements() { + public Enumeration getNestedElements() { return invokeMethod("getNestedElements", false); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/gant/AntBuilderMethod.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/gant/AntBuilderMethod.java new file mode 100644 index 000000000000..f569794d0736 --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/gant/AntBuilderMethod.java @@ -0,0 +1,59 @@ +package org.jetbrains.plugins.groovy.gant; + +import com.intellij.lang.ant.dom.AntDomExtender; +import com.intellij.lang.ant.psi.impl.AntIntrospector; +import com.intellij.psi.*; +import com.intellij.psi.impl.light.LightMethodBuilder; +import com.intellij.psi.scope.PsiScopeProcessor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.plugins.groovy.GroovyFileType; +import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightParameter; +import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; + +import java.util.Enumeration; + +/** +* @author peter +*/ +class AntBuilderMethod extends LightMethodBuilder { + private final PsiFile myPlace; + @Nullable private final Class myAntClass; + + public AntBuilderMethod(PsiFile place, String name, PsiType closureType, @Nullable Class antClass) { + super(place.getManager(), GroovyFileType.GROOVY_LANGUAGE, name); + myPlace = place; + myAntClass = antClass; + setModifiers(PsiModifier.PUBLIC); + addParameter("args", CommonClassNames.JAVA_UTIL_MAP); + setBaseIcon(GantIcons.ANT_TASK); + addParameter(new GrLightParameter("body", closureType, this).setOptional(true)); + } + + @NotNull + @Override + public PsiElement getNavigationElement() { + if (myAntClass != null) { + final PsiClass psiClass = JavaPsiFacade.getInstance(getProject()).findClass(myAntClass.getName(), myPlace.getResolveScope()); + if (psiClass != null) { + return psiClass; + } + } + return this; + } + + public boolean processNestedElements(PsiScopeProcessor processor) { + final AntIntrospector introspector = AntDomExtender.getIntrospector(myAntClass); + if (introspector != null) { + final Enumeration nested = introspector.getNestedElements(); + while (nested.hasMoreElements()) { + final AntBuilderMethod method = + new AntBuilderMethod(myPlace, nested.nextElement(), getParameterList().getParameters()[1].getType(), null); + if (!ResolveUtil.processElement(processor, method)) { + return false; + } + } + } + return true; + } +} diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/gant/AntTasksProvider.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/gant/AntTasksProvider.java index b987f4f51a87..8114d61f725b 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/gant/AntTasksProvider.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/gant/AntTasksProvider.java @@ -27,18 +27,15 @@ import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.impl.light.LightMethodBuilder; -import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.util.CachedValue; import com.intellij.psi.util.CachedValueProvider; import com.intellij.psi.util.CachedValuesManager; import com.intellij.psi.util.PsiModificationTracker; import com.intellij.util.PathUtil; import com.intellij.util.lang.UrlClassLoader; -import org.jetbrains.plugins.groovy.GroovyFileType; import org.jetbrains.plugins.groovy.extensions.GroovyScriptType; import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; -import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightParameter; import java.net.URL; import java.util.*; @@ -79,29 +76,12 @@ public class AntTasksProvider { final Set result = new HashSet(); final Project project = file.getProject(); - final JavaPsiFacade facade = JavaPsiFacade.getInstance(project); - final GlobalSearchScope scope = file.getResolveScope(); - - final PsiType closureType = JavaPsiFacade.getElementFactory(project).createTypeFromText(GrClosableBlock.GROOVY_LANG_CLOSURE, - file); + final PsiType closureType = JavaPsiFacade.getElementFactory(project).createTypeFromText(GrClosableBlock.GROOVY_LANG_CLOSURE, file); for (String name : antObjects.keySet()) { - final PsiClass psiClass = facade.findClass(antObjects.get(name).getName(), scope); - - final LightMethodBuilder tdMethod = - new LightMethodBuilder(PsiManager.getInstance(project), GroovyFileType.GROOVY_LANGUAGE, name). - setModifiers(PsiModifier.PUBLIC). - addParameter("args", CommonClassNames.JAVA_UTIL_MAP). - setBaseIcon(GantIcons.ANT_TASK); - - tdMethod.addParameter(new GrLightParameter("body", closureType, tdMethod).setOptional(true)); - - if (psiClass != null) { - tdMethod.setNavigationElement(psiClass); - } - result.add(tdMethod); + result.add(new AntBuilderMethod(file, name, closureType, antObjects.get(name))); } - return Result.create(result, PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT, ProjectRootManager.getInstance(file.getProject())); + return Result.create(result, PsiModificationTracker.JAVA_STRUCTURE_MODIFICATION_COUNT, ProjectRootManager.getInstance(project)); } }, false); } diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/gant/GantMemberContributor.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/gant/GantMemberContributor.java index ed8162023a2b..205a067e9945 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/gant/GantMemberContributor.java +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/gant/GantMemberContributor.java @@ -15,10 +15,7 @@ */ package org.jetbrains.plugins.groovy.gant; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiFile; -import com.intellij.psi.PsiNamedElement; -import com.intellij.psi.PsiType; +import com.intellij.psi.*; import com.intellij.psi.impl.light.LightMethodBuilder; import com.intellij.psi.impl.light.LightVariableBuilder; import com.intellij.psi.scope.PsiScopeProcessor; @@ -26,6 +23,7 @@ import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.plugins.groovy.lang.psi.GroovyFile; import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentLabel; import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethodCall; import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; import org.jetbrains.plugins.groovy.lang.resolve.NonCodeMembersProcessor; import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil; @@ -45,13 +43,35 @@ public class GantMemberContributor implements NonCodeMembersProcessor { return true; } - PsiFile file = place.getContainingFile(); - if (!GantUtils.isGantScriptFile(file)) { + GrClosableBlock closure = PsiTreeUtil.getContextOfType(place, GrClosableBlock.class, true); + if (closure == null) { return true; } - final GrClosableBlock closure = PsiTreeUtil.getContextOfType(place, GrClosableBlock.class, true); - if (closure == null) { + boolean antTasksProcessed = false; + while (closure != null) { + final PsiElement parent = closure.getParent(); + if (parent instanceof GrMethodCall) { + final PsiMethod method = ((GrMethodCall)parent).resolveMethod(); + if (method instanceof AntBuilderMethod) { + antTasksProcessed = true; + if (!processAntTasks(processor, place)) { + return false; + } + if (!((AntBuilderMethod)method).processNestedElements(processor)) { + return false; + } + break; + } + } + + closure = PsiTreeUtil.getContextOfType(closure, GrClosableBlock.class, true); + } + + // ------- gant-specific + + PsiFile file = place.getContainingFile(); + if (!GantUtils.isGantScriptFile(file)) { return true; } @@ -66,7 +86,7 @@ public class GantMemberContributor implements NonCodeMembersProcessor { } } - return processAntTasks(processor, place); + return antTasksProcessed || processAntTasks(processor, place); } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/gant/completion/GantReferenceCompletionTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/gant/completion/GantReferenceCompletionTest.groovy index e2bd83205322..4dad2bc7c506 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/gant/completion/GantReferenceCompletionTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/gant/completion/GantReferenceCompletionTest.groovy @@ -106,6 +106,29 @@ def foo() { checkVariants "ant.pattt", "patternset" } + public void testTagsInsideTags() throws Exception { + myFixture.configureByText "a.groovy", """ +AntBuilder ant +ant.zip { + patternset { + includ + } +}""" + myFixture.completeBasic() + assertSameElements myFixture.lookupElementStrings, "include", "includesfile" + } + + public void testTagsInsideTagsInGantTarget() throws Exception { + checkVariants """ +target(aaa: "") { + zip { + patternset { + includ + } + } +}""", "include", "includesfile", "includeTargets", "includeTool" + } + static final def GANT_JARS = ["gant.jar", "ant.jar", "ant-junit.jar", "ant-launcher.jar", "commons.jar"] }