From c68f72652169bdc1daa8f09c95697e3e5e5276c0 Mon Sep 17 00:00:00 2001 From: Peter Gromov Date: Wed, 15 Oct 2008 14:01:10 +0400 Subject: [PATCH] plugin.xml: correctly determine extension short name don't red-highlight hacky non-existing vcs plugin reference --- plugins/devkit/src/DevKitBundle.properties | 2 + plugins/devkit/src/dom/Extensions.java | 4 +- .../src/dom/impl/ExtensionDomExtender.java | 90 +++++++++++-------- .../src/dom/impl/IdeaPluginConverter.java | 18 ++-- .../codeInsight/DependsHighlighting.xml | 9 ++ .../codeInsight/ExtensionsHighlighting.xml | 15 ++++ .../codeInsight/PluginXmlFunctionalTest.java | 77 ++++++++++++++++ 7 files changed, 173 insertions(+), 42 deletions(-) create mode 100644 plugins/devkit/testData/codeInsight/DependsHighlighting.xml create mode 100644 plugins/devkit/testData/codeInsight/ExtensionsHighlighting.xml create mode 100644 plugins/devkit/testSources/codeInsight/PluginXmlFunctionalTest.java diff --git a/plugins/devkit/src/DevKitBundle.properties b/plugins/devkit/src/DevKitBundle.properties index 94a673b3d917..3f5dd459b1d6 100644 --- a/plugins/devkit/src/DevKitBundle.properties +++ b/plugins/devkit/src/DevKitBundle.properties @@ -161,3 +161,5 @@ project.title=Plugin Project no.java.sdk.for.idea.sdk.found=No Java SDK of appropriate version found. In addition to the IDEA JDK, you need to define a JSDK with the same Java version ({0}). no.idea.sdk.version.found=Failed to detect JDK version required for IDEA JDK. group.PluginDeployActions.text=Plugin Deployment Actions + +error.cannot.resolve.plugin=Cannot resolve plugin {0} \ No newline at end of file diff --git a/plugins/devkit/src/dom/Extensions.java b/plugins/devkit/src/dom/Extensions.java index cc9433fa68fc..eda21ef237db 100644 --- a/plugins/devkit/src/dom/Extensions.java +++ b/plugins/devkit/src/dom/Extensions.java @@ -13,10 +13,10 @@ import org.jetbrains.idea.devkit.dom.impl.ExtensionNsConverter; public interface Extensions extends DomElement { @NotNull @Attribute("defaultExtensionNs") - @Convert(ExtensionNsConverter.class) + @Convert(value=ExtensionNsConverter.class, soft=true) GenericAttributeValue getDefaultExtensionNs(); @NotNull - @Convert(ExtensionNsConverter.class) + @Convert(value=ExtensionNsConverter.class, soft=true) GenericAttributeValue getXmlns(); } diff --git a/plugins/devkit/src/dom/impl/ExtensionDomExtender.java b/plugins/devkit/src/dom/impl/ExtensionDomExtender.java index 58e47b9aee92..4fa950675003 100644 --- a/plugins/devkit/src/dom/impl/ExtensionDomExtender.java +++ b/plugins/devkit/src/dom/impl/ExtensionDomExtender.java @@ -1,9 +1,11 @@ package org.jetbrains.idea.devkit.dom.impl; import com.intellij.ide.plugins.PluginManager; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.xml.XmlElement; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.xml.*; import com.intellij.util.xml.reflect.DomExtender; import com.intellij.util.xml.reflect.DomExtension; @@ -11,9 +13,12 @@ import com.intellij.util.xml.reflect.DomExtensionsRegistrar; import com.intellij.util.xmlb.annotations.Attribute; import com.intellij.util.xmlb.annotations.Tag; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.devkit.dom.*; -import java.util.*; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; /** * @author mike @@ -31,56 +36,71 @@ public class ExtensionDomExtender extends DomExtender { if (ideaPlugin == null) return; - registerExtensions(extensions, ideaPlugin, registrar, psiManager); - - IdeaPlugin plugin = extensions.getDefaultExtensionNs().getValue(); - if (plugin == null) plugin = extensions.getXmlns().getValue(); - if (plugin != null) { - registerExtensions(extensions, plugin, registrar, psiManager); + String prefix = extensions.getDefaultExtensionNs().getStringValue(); + if (prefix == null) prefix = extensions.getXmlns().getStringValue(); + if (prefix != null) { + prefix += "."; + } else { + prefix = ""; } + + final Collection dependencies = getDependencies(ideaPlugin); + ContainerUtil.addIfNotNull(ideaPlugin.getPluginId(), dependencies); + for (IdeaPlugin plugin : IdeaPluginConverter.collectAllVisiblePlugins(extensions.getRoot().getFile())) { + final String value = plugin.getPluginId(); + if (value != null && dependencies.contains(value)) { + registerExtensions(prefix, plugin, registrar, psiManager); + } + } + } - private static void registerExtensions(final Extensions extensions, final IdeaPlugin plugin, final DomExtensionsRegistrar registrar, + private static void registerExtensions(final String prefix, final IdeaPlugin plugin, final DomExtensionsRegistrar registrar, final PsiManager psiManager) { + final String pluginId = plugin.getPluginId(); for (ExtensionPoints points : plugin.getExtensionPoints()) { for (ExtensionPoint point : points.getExtensionPoints()) { - registerExtensionPoint(registrar, point, psiManager); + registerExtensionPoint(registrar, point, psiManager, prefix, pluginId); } } } - private static void registerExtensionPoint(final DomExtensionsRegistrar registrar, final ExtensionPoint extensionPoint, final PsiManager manager) { - final String epName = extensionPoint.getName().getStringValue(); - if (epName != null) { - final DomExtension domExtension = registrar.registerCollectionChildrenExtension(new XmlName(epName), Extension.class); - domExtension.putUserData(DomExtension.KEY_DECLARATION, extensionPoint); - domExtension.addExtender(new DomExtender() { - public void registerExtensions(@NotNull final DomElement domElement, @NotNull final DomExtensionsRegistrar registrar) { - final String interfaceName = extensionPoint.getInterface().getStringValue(); - if (interfaceName != null) { - registrar.registerGenericAttributeValueChildExtension(new XmlName("implementation"), PsiClass.class).setConverter( - CLASS_CONVERTER); + private static void registerExtensionPoint(final DomExtensionsRegistrar registrar, final ExtensionPoint extensionPoint, final PsiManager manager, String prefix, @Nullable String pluginId) { + String epName = extensionPoint.getName().getStringValue(); + if (epName == null) epName = extensionPoint.getQualifiedName().getStringValue(); + if (epName == null) return; - final PsiClass implClass = - JavaPsiFacade.getInstance(manager.getProject()).findClass(interfaceName, GlobalSearchScope.allScope(manager.getProject())); - if (implClass != null) { - registerXmlb(registrar, implClass); - } + if (StringUtil.isNotEmpty(pluginId)) epName = pluginId + "." + epName; + if (!epName.startsWith(prefix)) return; + + final DomExtension domExtension = registrar.registerCollectionChildrenExtension(new XmlName(epName.substring(prefix.length())), Extension.class); + domExtension.putUserData(DomExtension.KEY_DECLARATION, extensionPoint); + domExtension.addExtender(new DomExtender() { + public void registerExtensions(@NotNull final DomElement domElement, @NotNull final DomExtensionsRegistrar registrar) { + final String interfaceName = extensionPoint.getInterface().getStringValue(); + if (interfaceName != null) { + registrar.registerGenericAttributeValueChildExtension(new XmlName("implementation"), PsiClass.class).setConverter( + CLASS_CONVERTER); + + final PsiClass implClass = + JavaPsiFacade.getInstance(manager.getProject()).findClass(interfaceName, GlobalSearchScope.allScope(manager.getProject())); + if (implClass != null) { + registerXmlb(registrar, implClass); } - else { - final String beanClassName = extensionPoint.getBeanClass().getStringValue(); - if (beanClassName != null) { - final PsiClass beanClass = - JavaPsiFacade.getInstance(manager.getProject()).findClass(beanClassName, GlobalSearchScope.allScope(manager.getProject())); + } + else { + final String beanClassName = extensionPoint.getBeanClass().getStringValue(); + if (beanClassName != null) { + final PsiClass beanClass = + JavaPsiFacade.getInstance(manager.getProject()).findClass(beanClassName, GlobalSearchScope.allScope(manager.getProject())); - if (beanClass != null) { - registerXmlb(registrar, beanClass); - } + if (beanClass != null) { + registerXmlb(registrar, beanClass); } } } - }); - } + } + }); } private static void registerXmlb(final DomExtensionsRegistrar registrar, final PsiClass beanClass) { diff --git a/plugins/devkit/src/dom/impl/IdeaPluginConverter.java b/plugins/devkit/src/dom/impl/IdeaPluginConverter.java index a0a958410247..be2b7949605d 100644 --- a/plugins/devkit/src/dom/impl/IdeaPluginConverter.java +++ b/plugins/devkit/src/dom/impl/IdeaPluginConverter.java @@ -19,13 +19,12 @@ import com.intellij.util.xml.ResolvingConverter; 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.module.PluginModuleType; import org.jetbrains.idea.devkit.projectRoots.IdeaJdk; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; +import java.util.*; /** * @author mike @@ -33,9 +32,18 @@ import java.util.List; public class IdeaPluginConverter extends ResolvingConverter { @NotNull public Collection getVariants(final ConvertContext context) { - final XmlFile xmlFile = context.getFile(); + return collectAllVisiblePlugins(context.getFile()); + } - return collectAllVisiblePlugins(xmlFile); + @NotNull + @Override + public Set getAdditionalVariants(@NotNull final ConvertContext context) { + return Collections.singleton("com.intellij.modules.vcs"); //todo this is a hack + } + + @Override + public String getErrorMessage(@Nullable final String s, final ConvertContext context) { + return DevKitBundle.message("error.cannot.resolve.plugin", s); } public static Collection collectAllVisiblePlugins(final XmlFile xmlFile) { diff --git a/plugins/devkit/testData/codeInsight/DependsHighlighting.xml b/plugins/devkit/testData/codeInsight/DependsHighlighting.xml new file mode 100644 index 000000000000..8f64ff62008b --- /dev/null +++ b/plugins/devkit/testData/codeInsight/DependsHighlighting.xml @@ -0,0 +1,9 @@ + + com.intellij.myPlugin + + com.intellij + com.intellij.modules.vcs + com.intellij.custom + com.intellij.xxx + + \ No newline at end of file diff --git a/plugins/devkit/testData/codeInsight/ExtensionsHighlighting.xml b/plugins/devkit/testData/codeInsight/ExtensionsHighlighting.xml new file mode 100644 index 000000000000..4007dd7e0943 --- /dev/null +++ b/plugins/devkit/testData/codeInsight/ExtensionsHighlighting.xml @@ -0,0 +1,15 @@ + + com.intellij.myPlugin + + + + + com.intellij.custom + + + + + + <custom.error/> + + \ No newline at end of file diff --git a/plugins/devkit/testSources/codeInsight/PluginXmlFunctionalTest.java b/plugins/devkit/testSources/codeInsight/PluginXmlFunctionalTest.java new file mode 100644 index 000000000000..35b41e599e77 --- /dev/null +++ b/plugins/devkit/testSources/codeInsight/PluginXmlFunctionalTest.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2000-2005 by JetBrains s.r.o. All Rights Reserved. + * Use is subject to license terms. + */ +package org.jetbrains.idea.devkit.codeInsight; + +import com.intellij.openapi.application.Result; +import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.testFramework.PsiTestUtil; +import com.intellij.testFramework.fixtures.CodeInsightFixtureTestCase; +import com.intellij.testFramework.fixtures.IdeaTestFixtureFactory; +import com.intellij.testFramework.fixtures.TempDirTestFixture; +import org.jetbrains.idea.devkit.DevKitInspectionToolProvider; + +import java.io.IOException; + +/** + * @author peter + */ +public class PluginXmlFunctionalTest extends CodeInsightFixtureTestCase { + private TempDirTestFixture myTempDirFixture; + + @Override + protected void setUp() throws Exception { + super.setUp(); + myTempDirFixture = IdeaTestFixtureFactory.getFixtureFactory().createTempDirTestFixture(); + myFixture.enableInspections(new DevKitInspectionToolProvider()); + } + + @Override + protected String getBasePath() { + return "/svnPlugins/devkit/testData/codeInsight"; + } + + public void testExtensionsHighlighting() throws Throwable { + final String root = "idea_core"; + addPluginXml(root, "\n" + + " com.intellij\n" + + " \n" + + " \n" + + " \n" + + ""); + addPluginXml("custom", "\n" + + " com.intellij.custom\n" + + " \n" + + " \n" + + " \n" + + ""); + + myFixture.configureFromExistingVirtualFile(myFixture.copyFileToProject(getTestName(false) + ".xml", "META-INF/plugin.xml")); + myFixture.checkHighlighting(false, false, false); + } + + public void testDependsHighlighting() throws Throwable { + final String root = "idea_core"; + addPluginXml(root, "\n" + + " com.intellij\n" + + ""); + addPluginXml("custom", "\n" + + " com.intellij.custom\n" + + ""); + + myFixture.configureFromExistingVirtualFile(myFixture.copyFileToProject(getTestName(false) + ".xml", "META-INF/plugin.xml")); + myFixture.checkHighlighting(false, false, false); + } + + private void addPluginXml(final String root, final String text) throws IOException { + myTempDirFixture.createFile(root + + "/META-INF/plugin.xml", text); + new WriteCommandAction(getProject()) { + protected void run(Result result) throws Throwable { + PsiTestUtil.addSourceContentToRoots(myModule, myTempDirFixture.getFile(root)); + } + }.execute(); + } + +}