mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-30 02:09:59 +07:00
[devkit] plugin.xml: new inspection "Dynamic Plugin verification" (IDEA-228484)
GitOrigin-RevId: d4ef7c4de7348af14435eeee93929d6ce5defd56
This commit is contained in:
committed by
intellij-monorepo-bot
parent
1566d4df15
commit
d603ec12fe
@@ -92,6 +92,11 @@
|
||||
groupPath="Plugin DevKit" groupKey="inspections.group.descriptor"
|
||||
enabledByDefault="true" level="WARNING"
|
||||
implementationClass="org.jetbrains.idea.devkit.inspections.PluginXmlCapitalizationInspection"/>
|
||||
<localInspection language="XML" displayName="Plugin.xml dynamic plugin verification" applyToDialects="false"
|
||||
groupPath="Plugin DevKit" groupKey="inspections.group.descriptor"
|
||||
enabledByDefault="false" level="WARNING"
|
||||
implementationClass="org.jetbrains.idea.devkit.inspections.PluginXmlDynamicPluginInspection"/>
|
||||
|
||||
<localInspection language="JVM" shortName="ComponentNotRegistered"
|
||||
groupPath="Plugin DevKit"
|
||||
key="inspections.component.not.registered.name" groupKey="inspections.group.code" enabledByDefault="true"
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
<html>
|
||||
<body>
|
||||
Reports problems preventing dynamic plugin.
|
||||
<p>
|
||||
Dynamic plugins can be installed, updated and uninstalled without restarting the IDE (supported in 2020.1 and later).
|
||||
</p>
|
||||
<p><small>New in 2020.1</small>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,126 @@
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.idea.devkit.inspections;
|
||||
|
||||
import com.intellij.codeInspection.IntentionAndQuickFixAction;
|
||||
import com.intellij.codeInspection.LocalQuickFix;
|
||||
import com.intellij.codeInspection.ProblemHighlightType;
|
||||
import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel;
|
||||
import com.intellij.openapi.actionSystem.ActionManager;
|
||||
import com.intellij.openapi.actionSystem.ActionPlaces;
|
||||
import com.intellij.openapi.actionSystem.AnAction;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.editor.ex.EditorEx;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.util.xml.DomElement;
|
||||
import com.intellij.util.xml.DomUtil;
|
||||
import com.intellij.util.xml.highlighting.AddDomElementQuickFix;
|
||||
import com.intellij.util.xml.highlighting.BasicDomElementsInspection;
|
||||
import com.intellij.util.xml.highlighting.DomElementAnnotationHolder;
|
||||
import com.intellij.util.xml.highlighting.DomHighlightingHelper;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.idea.devkit.dom.*;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.util.Objects;
|
||||
|
||||
public class PluginXmlDynamicPluginInspection extends BasicDomElementsInspection<IdeaPlugin> {
|
||||
|
||||
public boolean highlightNonDynamicEPUsages = false;
|
||||
|
||||
public PluginXmlDynamicPluginInspection() {
|
||||
super(IdeaPlugin.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public JComponent createOptionsPanel() {
|
||||
return new SingleCheckboxOptionsPanel("Highlight usage of non-dynamic extension points", this, "highlightNonDynamicEPUsages");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void checkDomElement(DomElement element, DomElementAnnotationHolder holder, DomHighlightingHelper helper) {
|
||||
if (element instanceof ApplicationComponents ||
|
||||
element instanceof ProjectComponents ||
|
||||
element instanceof ModuleComponents) {
|
||||
highlightComponents(holder, element);
|
||||
}
|
||||
|
||||
else if (element instanceof ExtensionPoint) {
|
||||
highlightExtensionPoint(holder, ((ExtensionPoint)element));
|
||||
}
|
||||
|
||||
else if (element instanceof Group) {
|
||||
highlightGroup(holder, (Group)element);
|
||||
}
|
||||
|
||||
else if (highlightNonDynamicEPUsages && element instanceof Extension) {
|
||||
highlightExtension(holder, ((Extension)element));
|
||||
}
|
||||
}
|
||||
|
||||
private static void highlightComponents(DomElementAnnotationHolder holder, DomElement component) {
|
||||
holder.createProblem(component, ProblemHighlightType.LIKE_DEPRECATED,
|
||||
"<html>Replace Components with " +
|
||||
"<a href=\"http://www.jetbrains.org/intellij/sdk/docs/basics/plugin_structure/plugin_components.html\">alternatives</a></html>",
|
||||
null).highlightWholeElement();
|
||||
}
|
||||
|
||||
private static void highlightExtensionPoint(DomElementAnnotationHolder holder, ExtensionPoint extensionPoint) {
|
||||
if (!DomUtil.hasXml(extensionPoint.getDynamic())) {
|
||||
final LocalQuickFix[] fixes = holder.isOnTheFly() ? new LocalQuickFix[]{
|
||||
createAnalyzeEPFix("AnalyzeEPUsage", extensionPoint),
|
||||
createAnalyzeEPFix("AnalyzeEPUsageIgnoreSafeClasses", extensionPoint)
|
||||
} : LocalQuickFix.EMPTY_ARRAY;
|
||||
holder.createProblem(extensionPoint, "Non-dynamic extension point '" + extensionPoint.getEffectiveQualifiedName() + "'",
|
||||
fixes);
|
||||
}
|
||||
else if (Boolean.FALSE == extensionPoint.getDynamic().getValue()) {
|
||||
holder.createProblem(extensionPoint, "Explicit non-dynamic extension point '" + extensionPoint.getEffectiveQualifiedName() + "'");
|
||||
}
|
||||
}
|
||||
|
||||
private static IntentionAndQuickFixAction createAnalyzeEPFix(String actionId, ExtensionPoint extensionPoint) {
|
||||
final AnAction action = ActionManager.getInstance().getAction(actionId);
|
||||
assert action != null : actionId;
|
||||
|
||||
return new IntentionAndQuickFixAction() {
|
||||
@Nls(capitalization = Nls.Capitalization.Sentence)
|
||||
@NotNull
|
||||
@Override
|
||||
public String getName() {
|
||||
return action.getTemplateText() + " for '" + extensionPoint.getEffectiveQualifiedName() + "'";
|
||||
}
|
||||
|
||||
@Nls(capitalization = Nls.Capitalization.Sentence)
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return Objects.requireNonNull(action.getTemplateText());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyFix(@NotNull Project project, PsiFile file, @Nullable Editor editor) {
|
||||
assert editor != null;
|
||||
action.actionPerformed(AnActionEvent.createFromDataContext(ActionPlaces.UNKNOWN, null, ((EditorEx)editor).getDataContext()));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static void highlightGroup(DomElementAnnotationHolder holder, Group group) {
|
||||
if (!DomUtil.hasXml(group.getId())) {
|
||||
holder.createProblem(group, "'id' must be specified for <group>", new AddDomElementQuickFix<>(group.getId()));
|
||||
}
|
||||
}
|
||||
|
||||
private static void highlightExtension(DomElementAnnotationHolder holder, Extension extension) {
|
||||
final ExtensionPoint extensionPoint = extension.getExtensionPoint();
|
||||
|
||||
if (extensionPoint != null && Boolean.TRUE != extensionPoint.getDynamic().getValue()) {
|
||||
holder.createProblem(extension, "Usage of non-dynamic extension point '" + extensionPoint.getEffectiveQualifiedName() + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<idea-plugin>
|
||||
|
||||
<id>myPlugin</id>
|
||||
<extensionPoints>
|
||||
<extensionPoint name="dynamicEP" dynamic="true"/>
|
||||
<<warning descr="Non-dynamic extension point 'myPlugin.nonDynamicEP'">extensionPoint</warning> name="nonDynamicEP"/>
|
||||
<<warning descr="Explicit non-dynamic extension point 'myPlugin.explicitNonDynamicEP'">extensionPoint</warning> name="explicitNonDynamicEP" dynamic="false"/>
|
||||
</extensionPoints>
|
||||
|
||||
|
||||
<extensions defaultExtensionNs="myPlugin">
|
||||
<dynamicEP/>
|
||||
<nonDynamicEP/>
|
||||
<explicitNonDynamicEP/>
|
||||
</extensions>
|
||||
|
||||
|
||||
<actions>
|
||||
<group id="requiredIdIsPresent"/>
|
||||
<<warning descr="'id' must be specified for <group>">group</warning>>
|
||||
<separator/>
|
||||
<reference ref="requiredIdIsPresent"/>
|
||||
</group>
|
||||
</actions>
|
||||
|
||||
|
||||
<warning descr="Replace Components with alternatives"><application-components>
|
||||
</application-components></warning>
|
||||
|
||||
<warning descr="Replace Components with alternatives"><project-components>
|
||||
</project-components></warning>
|
||||
|
||||
<warning descr="Replace Components with alternatives"><module-components>
|
||||
</module-components></warning>
|
||||
|
||||
</idea-plugin>
|
||||
@@ -0,0 +1,17 @@
|
||||
<idea-plugin>
|
||||
|
||||
<id>myPlugin</id>
|
||||
<extensionPoints>
|
||||
<extensionPoint name="dynamicEP" dynamic="true"/>
|
||||
<<warning descr="Non-dynamic extension point 'myPlugin.nonDynamicEP'">extensionPoint</warning> name="nonDynamicEP"/>
|
||||
<<warning descr="Explicit non-dynamic extension point 'myPlugin.explicitNonDynamicEP'">extensionPoint</warning> name="explicitNonDynamicEP" dynamic="false"/>
|
||||
</extensionPoints>
|
||||
|
||||
|
||||
<extensions defaultExtensionNs="myPlugin">
|
||||
<dynamicEP/>
|
||||
<<warning descr="Usage of non-dynamic extension point 'myPlugin.nonDynamicEP'">nonDynamicEP</warning>/>
|
||||
<<warning descr="Usage of non-dynamic extension point 'myPlugin.explicitNonDynamicEP'">explicitNonDynamicEP</warning>/>
|
||||
</extensions>
|
||||
|
||||
</idea-plugin>
|
||||
@@ -0,0 +1,28 @@
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package org.jetbrains.idea.devkit.codeInsight;
|
||||
|
||||
import com.intellij.testFramework.TestDataPath;
|
||||
import com.intellij.testFramework.fixtures.LightJavaCodeInsightFixtureTestCase;
|
||||
import org.jetbrains.idea.devkit.DevkitJavaTestsUtil;
|
||||
import org.jetbrains.idea.devkit.inspections.PluginXmlDynamicPluginInspection;
|
||||
|
||||
@TestDataPath("$CONTENT_ROOT/testData/codeInsight/pluginXmlDynamicPluginInspection")
|
||||
public class PluginXmlDynamicPluginInspectionTest extends LightJavaCodeInsightFixtureTestCase {
|
||||
|
||||
@Override
|
||||
protected String getBasePath() {
|
||||
return DevkitJavaTestsUtil.TESTDATA_PATH + "codeInsight/pluginXmlDynamicPluginInspection";
|
||||
}
|
||||
|
||||
public void testHighlighting() {
|
||||
myFixture.enableInspections(new PluginXmlDynamicPluginInspection());
|
||||
myFixture.testHighlighting("pluginXmlDynamicPluginInspection-highlighting.xml");
|
||||
}
|
||||
|
||||
public void testUsingExtensionPoints() {
|
||||
final PluginXmlDynamicPluginInspection inspection = new PluginXmlDynamicPluginInspection();
|
||||
inspection.highlightNonDynamicEPUsages = true;
|
||||
myFixture.enableInspections(inspection);
|
||||
myFixture.testHighlighting("pluginXmlDynamicPluginInspection-usingExtensionPoints.xml");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user