From 7a5ed76cc074e7c69efccd1f208f634b30ccb17f Mon Sep 17 00:00:00 2001 From: Gregory Shrago Date: Sat, 24 Jul 2010 07:14:38 +0400 Subject: [PATCH] support modules & PsiReferenceProviderBean. And fix missing Action/Group methods. --- plugins/devkit/src/dom/Action.java | 7 +- plugins/devkit/src/dom/Actions.java | 2 + plugins/devkit/src/dom/Group.java | 2 +- .../src/dom/impl/ExtensionDomExtender.java | 130 ++++++++++++++---- .../src/dom/impl/IdeaPluginConverter.java | 20 ++- .../codeInsight/DependsHighlighting.xml | 2 +- .../codeInsight/PluginXmlFunctionalTest.java | 1 + 7 files changed, 127 insertions(+), 37 deletions(-) diff --git a/plugins/devkit/src/dom/Action.java b/plugins/devkit/src/dom/Action.java index 773d3a5ebfa5..bd03efde2566 100644 --- a/plugins/devkit/src/dom/Action.java +++ b/plugins/devkit/src/dom/Action.java @@ -142,6 +142,9 @@ public interface Action extends DomElement { */ AddToGroup addAddToGroup(); - @NotNull - GenericAttributeValue getUseShortcutOf(); + @NotNull + GenericAttributeValue getUseShortcutOf(); + + @NotNull + GenericAttributeValue getKeymap(); } diff --git a/plugins/devkit/src/dom/Actions.java b/plugins/devkit/src/dom/Actions.java index 4e06ec6da85f..3fa4320c2596 100644 --- a/plugins/devkit/src/dom/Actions.java +++ b/plugins/devkit/src/dom/Actions.java @@ -39,4 +39,6 @@ public interface Actions extends DomElement { @NotNull List getReferences(); + + Reference addReference(); } diff --git a/plugins/devkit/src/dom/Group.java b/plugins/devkit/src/dom/Group.java index cadec21dc3aa..0fc11ff8aa6d 100644 --- a/plugins/devkit/src/dom/Group.java +++ b/plugins/devkit/src/dom/Group.java @@ -28,7 +28,7 @@ import java.util.List; /** * plugin.dtd:group interface. */ -public interface Group extends DomElement { +public interface Group extends Actions { /** * Returns the value of the popup child. diff --git a/plugins/devkit/src/dom/impl/ExtensionDomExtender.java b/plugins/devkit/src/dom/impl/ExtensionDomExtender.java index 071e6450b422..0387e2fcc025 100644 --- a/plugins/devkit/src/dom/impl/ExtensionDomExtender.java +++ b/plugins/devkit/src/dom/impl/ExtensionDomExtender.java @@ -20,6 +20,7 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.util.PsiTypesUtil; import com.intellij.psi.xml.XmlElement; import com.intellij.psi.xml.XmlFile; import com.intellij.util.containers.ContainerUtil; @@ -27,7 +28,10 @@ import com.intellij.util.xml.*; import com.intellij.util.xml.reflect.DomExtender; import com.intellij.util.xml.reflect.DomExtension; import com.intellij.util.xml.reflect.DomExtensionsRegistrar; +import com.intellij.util.xmlb.Constants; +import com.intellij.util.xmlb.annotations.AbstractCollection; import com.intellij.util.xmlb.annotations.Attribute; +import com.intellij.util.xmlb.annotations.Property; import com.intellij.util.xmlb.annotations.Tag; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -65,7 +69,8 @@ public class ExtensionDomExtender extends DomExtender { final Collection dependencies = getDependencies(ideaPlugin); for (IdeaPlugin plugin : IdeaPluginConverter.collectAllVisiblePlugins(DomUtil.getFile(extensions))) { final String value = plugin.getPluginId(); - if (value != null && dependencies.contains(value)) { + // value == null for "included" platform plugins like DomPlugin.xml, XmlPlugin.xml, etc. + if (value == null || dependencies.contains(value)) { registerExtensions(prefix, plugin, registrar, psiManager); } } @@ -74,7 +79,7 @@ public class ExtensionDomExtender extends DomExtender { private static void registerExtensions(final String prefix, final IdeaPlugin plugin, final DomExtensionsRegistrar registrar, final PsiManager psiManager) { - final String pluginId = plugin.getPluginId(); + final String pluginId = StringUtil.notNullize(plugin.getPluginId(), "com.intellij"); for (ExtensionPoints points : plugin.getExtensionPoints()) { for (ExtensionPoint point : points.getExtensionPoints()) { registerExtensionPoint(registrar, point, psiManager, prefix, pluginId); @@ -129,36 +134,109 @@ public class ExtensionDomExtender extends DomExtender { } private static void registerField(final DomExtensionsRegistrar registrar, @NotNull final PsiField field) { - final PsiAnnotation[] annotations = field.getModifierList().getAnnotations(); + final PsiModifierList modifierList = field.getModifierList(); + if (modifierList == null) return; final PsiConstantEvaluationHelper evalHelper = JavaPsiFacade.getInstance(field.getProject()).getConstantEvaluationHelper(); - for (PsiAnnotation annotation : annotations) { - final String qName = annotation.getQualifiedName(); - if (qName != null) { - if (qName.equals(Attribute.class.getName())) { - final PsiAnnotationMemberValue attributeName = annotation.findAttributeValue("value"); - if (attributeName != null && attributeName instanceof PsiExpression) { - final Class type = String.class; - PsiExpression expression = (PsiExpression)attributeName; - final Object evaluatedExpression = evalHelper.computeConstantExpression(expression, false); - if (evaluatedExpression != null) { - registrar.registerGenericAttributeValueChildExtension(new XmlName(evaluatedExpression.toString()), type); - } - } - } else if (qName.equals(Tag.class.getName())) { - final PsiAnnotationMemberValue attributeName = annotation.findAttributeValue("value"); - if (attributeName != null && attributeName instanceof PsiExpression) { - PsiExpression expression = (PsiExpression)attributeName; - final Object evaluatedExpression = evalHelper.computeConstantExpression(expression, false); - if (evaluatedExpression != null) { - // I guess this actually needs something like registrar.registerGenericTagValueChildExtension... - registrar.registerFixedNumberChildExtension(new XmlName(evaluatedExpression.toString()), SimpleTagValue.class); - } - } + final PsiAnnotation attrAnno = modifierList.findAnnotation(Attribute.class.getName()); + if (attrAnno != null) { + final PsiAnnotationMemberValue attributeName = attrAnno.findAttributeValue("value"); + if (attributeName != null && attributeName instanceof PsiExpression) { + final Class type = String.class; + PsiExpression expression = (PsiExpression)attributeName; + final Object evaluatedExpression = evalHelper.computeConstantExpression(expression, false); + if (evaluatedExpression != null) { + registrar.registerGenericAttributeValueChildExtension(new XmlName(evaluatedExpression.toString()), type); } } + return; + } + final PsiAnnotation tagAnno = modifierList.findAnnotation(Tag.class.getName()); + final PsiAnnotation propAnno = modifierList.findAnnotation(Property.class.getName()); + final PsiAnnotation absColAnno = modifierList.findAnnotation(AbstractCollection.class.getName()); + //final PsiAnnotation colAnno = modifierList.findAnnotation(Collection.class.getName()); // todo + final String tagName = tagAnno != null? getStringAttribute(tagAnno, "value", evalHelper) : + propAnno != null && getBooleanAttribute(propAnno, "surroundWithTag", evalHelper)? Constants.OPTION : null; + if (tagName != null) { + if (absColAnno == null) { + registrar.registerFixedNumberChildExtension(new XmlName(tagName), SimpleTagValue.class); + } + else { + registrar.registerFixedNumberChildExtension(new XmlName(tagName), DomElement.class).addExtender(new DomExtender() { + @Override + public void registerExtensions(@NotNull DomElement domElement, @NotNull DomExtensionsRegistrar registrar) { + registerCollectionBinding(field.getType(), registrar, absColAnno, evalHelper); + } + }); + } + } + else if (absColAnno != null) { + registerCollectionBinding(field.getType(), registrar, absColAnno, evalHelper); + } + } + + private static void registerCollectionBinding(PsiType type, + DomExtensionsRegistrar registrar, + PsiAnnotation anno, + PsiConstantEvaluationHelper evalHelper) { + final boolean surroundWithTag = getBooleanAttribute(anno, "surroundWithTag", evalHelper); + if (surroundWithTag) return; // todo Set, List, Array + final String tagName = getStringAttribute(anno, "elementTag", evalHelper); + final String attrName = getStringAttribute(anno, "elementValueAttribute", evalHelper); + final PsiClass psiClass = getElementType(type); + if (tagName != null && attrName == null) { + registrar.registerCollectionChildrenExtension(new XmlName(tagName), SimpleTagValue.class); + } + else if (tagName != null) { + registrar.registerCollectionChildrenExtension(new XmlName(tagName), DomElement.class).addExtender(new DomExtender() { + @Override + public void registerExtensions(@NotNull DomElement domElement, @NotNull DomExtensionsRegistrar registrar) { + registrar.registerGenericAttributeValueChildExtension(new XmlName(attrName), String.class); + } + }); + } + else if (psiClass != null) { + final PsiModifierList modifierList = psiClass.getModifierList(); + final PsiAnnotation tagAnno = modifierList == null? null : modifierList.findAnnotation(Tag.class.getName()); + final String classTagName = tagAnno == null? psiClass.getName() : getStringAttribute(tagAnno, "value", evalHelper); + if (classTagName != null) { + registrar.registerCollectionChildrenExtension(new XmlName(classTagName), DomElement.class).addExtender(new DomExtender() { + @Override + public void registerExtensions(@NotNull DomElement domElement, @NotNull DomExtensionsRegistrar registrar) { + registerXmlb(registrar, psiClass); + } + }); + } } } + @Nullable + private static String getStringAttribute(final PsiAnnotation annotation, + final String name, + final PsiConstantEvaluationHelper evalHelper) { + final Object o = evalHelper.computeConstantExpression(annotation.findAttributeValue(name), false); + return o instanceof String && StringUtil.isNotEmpty((String)o)? (String)o : null; + } + + private static boolean getBooleanAttribute(final PsiAnnotation annotation, + final String name, + final PsiConstantEvaluationHelper evalHelper) { + final Object o = evalHelper.computeConstantExpression(annotation.findAttributeValue(name), false); + return o instanceof Boolean? ((Boolean)o).booleanValue() : false; + } + + @Nullable + public static PsiClass getElementType(final PsiType psiType) { + final PsiType elementType; + if (psiType instanceof PsiArrayType) elementType = ((PsiArrayType)psiType).getComponentType(); + else if (psiType instanceof PsiClassType) { + final PsiType[] types = ((PsiClassType)psiType).getParameters(); + elementType = types.length == 1? types[0] : null; + } + else elementType = null; + return PsiTypesUtil.getPsiClass(elementType); + } + + public static Collection getDependencies(IdeaPlugin ideaPlugin) { Set result = new HashSet(); diff --git a/plugins/devkit/src/dom/impl/IdeaPluginConverter.java b/plugins/devkit/src/dom/impl/IdeaPluginConverter.java index 3e5e18deeb30..766603b59f51 100644 --- a/plugins/devkit/src/dom/impl/IdeaPluginConverter.java +++ b/plugins/devkit/src/dom/impl/IdeaPluginConverter.java @@ -19,17 +19,18 @@ import com.intellij.openapi.project.Project; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.xml.XmlFile; import com.intellij.util.Function; -import com.intellij.util.containers.CollectionFactory; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.xml.ConvertContext; import com.intellij.util.xml.DomFileElement; import com.intellij.util.xml.DomService; import com.intellij.util.xml.ResolvingConverter; +import gnu.trove.THashSet; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.devkit.DevKitBundle; import org.jetbrains.idea.devkit.dom.IdeaPlugin; +import org.jetbrains.idea.devkit.dom.PluginModule; import java.util.Collection; import java.util.List; @@ -39,11 +40,6 @@ import java.util.Set; * @author mike */ public class IdeaPluginConverter extends ResolvingConverter { - @NonNls private static final Set PLATFORM_MODULES = CollectionFactory.newTroveSet("com.intellij.modules.platform", - "com.intellij.modules.lang", - "com.intellij.modules.vcs", - "com.intellij.modules.xdebugger", - "com.intellij.modules.xml"); @NotNull public Collection getVariants(final ConvertContext context) { @@ -53,7 +49,13 @@ public class IdeaPluginConverter extends ResolvingConverter { @NotNull @Override public Set getAdditionalVariants(@NotNull final ConvertContext context) { - return PLATFORM_MODULES; + final THashSet result = new THashSet(); + for (IdeaPlugin ideaPlugin : getVariants(context)) { + for (PluginModule module : ideaPlugin.getModules()) { + ContainerUtil.addIfNotNull(module.getValue().getValue(), result); + } + } + return result; } @Override @@ -78,6 +80,10 @@ public class IdeaPluginConverter extends ResolvingConverter { final String otherId = ideaPlugin.getPluginId(); if (otherId == null) continue; if (otherId.equals(s)) return ideaPlugin; + for (PluginModule module : ideaPlugin.getModules()) { + final String moduleName = module.getValue().getValue(); + if (moduleName != null && moduleName.equals(s)) return ideaPlugin; + } } return null; } diff --git a/plugins/devkit/testData/codeInsight/DependsHighlighting.xml b/plugins/devkit/testData/codeInsight/DependsHighlighting.xml index 8f64ff62008b..243fc2fffcad 100644 --- a/plugins/devkit/testData/codeInsight/DependsHighlighting.xml +++ b/plugins/devkit/testData/codeInsight/DependsHighlighting.xml @@ -2,7 +2,7 @@ com.intellij.myPlugin com.intellij - com.intellij.modules.vcs + com.intellij.modules.vcs com.intellij.custom com.intellij.xxx diff --git a/plugins/devkit/testSources/codeInsight/PluginXmlFunctionalTest.java b/plugins/devkit/testSources/codeInsight/PluginXmlFunctionalTest.java index b9a3ec0226ea..1a5ad0f47b4a 100644 --- a/plugins/devkit/testSources/codeInsight/PluginXmlFunctionalTest.java +++ b/plugins/devkit/testSources/codeInsight/PluginXmlFunctionalTest.java @@ -67,6 +67,7 @@ public class PluginXmlFunctionalTest extends JavaCodeInsightFixtureTestCase { final String root = "idea_core"; addPluginXml(root, "\n" + " com.intellij\n" + + " \n" + ""); addPluginXml("custom", "\n" + " com.intellij.custom\n" +