diff --git a/plugins/devkit/devkit-core/resources/META-INF/plugin.xml b/plugins/devkit/devkit-core/resources/META-INF/plugin.xml index de193806acde..8bcbfce9123f 100644 --- a/plugins/devkit/devkit-core/resources/META-INF/plugin.xml +++ b/plugins/devkit/devkit-core/resources/META-INF/plugin.xml @@ -71,7 +71,7 @@ - COMPONENT_TYPE_TO_REGISTRATION_TYPE = + ContainerUtil.immutableMapBuilder() + .put(ComponentType.APPLICATION, RegistrationCheckerUtil.RegistrationType.APPLICATION_COMPONENT) + .put(ComponentType.PROJECT, RegistrationCheckerUtil.RegistrationType.PROJECT_COMPONENT) + .put(ComponentType.MODULE, RegistrationCheckerUtil.RegistrationType.MODULE_COMPONENT) + .build(); @Nullable public JComponent createOptionsPanel() { @@ -84,90 +91,87 @@ public class ComponentNotRegisteredInspection extends DevKitInspectionBase { } @Nullable - public ProblemDescriptor[] checkClass(@NotNull PsiClass checkedClass, @NotNull InspectionManager manager, boolean isOnTheFly) { - PsiIdentifier classIdentifier = checkedClass.getNameIdentifier(); - if (classIdentifier != null && - checkedClass.getQualifiedName() != null && - checkedClass.getContainingFile().getVirtualFile() != null && - !checkedClass.hasModifierProperty(PsiModifier.ABSTRACT) && - !checkedClass.isEnum() && - !PsiUtil.isInnerClass(checkedClass)) { - - GlobalSearchScope scope = checkedClass.getResolveScope(); - - if (shouldCheckActionClass(checkedClass)) { - PsiClass actionClass = JavaPsiFacade.getInstance(manager.getProject()).findClass(AnAction.class.getName(), scope); - if (actionClass == null) { - // stop if action class cannot be found (non-devkit module/project) - return null; - } - if (checkedClass.isInheritor(actionClass, true)) { - if (!isActionRegistered(checkedClass) && canFix(checkedClass)) { - LocalQuickFix fix = new RegisterActionFix(org.jetbrains.idea.devkit.util.PsiUtil.createPointer(checkedClass)); - ProblemDescriptor problem = - manager.createProblemDescriptor(classIdentifier, - DevKitBundle.message("inspections.component.not.registered.message", - DevKitBundle.message("new.menu.action.text")), - fix, ProblemHighlightType.GENERIC_ERROR_OR_WARNING, isOnTheFly); - return new ProblemDescriptor[]{problem}; - } - // action IS registered, stop here + @Override + protected JvmElementVisitor buildVisitor(@NotNull Project project, @NotNull HighlightSink sink, boolean isOnTheFly) { + return new DefaultJvmElementVisitor() { + @Override + public Boolean visitClass(@NotNull JvmClass clazz) { + PsiElement sourceElement = clazz.getSourceElement(); + if (!(sourceElement instanceof PsiClass)) { return null; } + checkClass(project, (PsiClass)sourceElement, sink); + return false; } - - PsiClass compClass = JavaPsiFacade.getInstance(manager.getProject()).findClass(BaseComponent.class.getName(), scope); - if (compClass == null) { - // stop if component class cannot be found (non-devkit module/project) - return null; - } - if (!checkedClass.isInheritor(compClass, true)) { - return null; - } - - for (ComponentType componentType : ComponentType.values()) { - if (!InheritanceUtil.isInheritor(checkedClass, componentType.myClassName)) { - continue; - } - - if (findRegistrationType(checkedClass, COMPONENT_TYPE_TO_REGISTRATION_TYPE.get(componentType)) != null) { - return null; - } - - if (!canFix(checkedClass)) { - return null; - } - LocalQuickFix fix = new RegisterComponentFix(componentType, org.jetbrains.idea.devkit.util.PsiUtil.createPointer(checkedClass)); - ProblemDescriptor problem = - manager.createProblemDescriptor(classIdentifier, - DevKitBundle.message("inspections.component.not.registered.message", - DevKitBundle.message(componentType.myPropertyKey)), - fix, ProblemHighlightType.GENERIC_ERROR_OR_WARNING, isOnTheFly); - return new ProblemDescriptor[]{problem}; - } - } - return null; + }; } - private static final Map COMPONENT_TYPE_TO_REGISTRATION_TYPE = - ContainerUtil.immutableMapBuilder() - .put(ComponentType.APPLICATION, RegistrationCheckerUtil.RegistrationType.APPLICATION_COMPONENT) - .put(ComponentType.PROJECT, RegistrationCheckerUtil.RegistrationType.PROJECT_COMPONENT) - .put(ComponentType.MODULE, RegistrationCheckerUtil.RegistrationType.MODULE_COMPONENT) - .build(); + private void checkClass(@NotNull Project project, @NotNull PsiClass checkedClass, @NotNull HighlightSink sink) { + if (checkedClass.getQualifiedName() == null || + checkedClass.getContainingFile().getVirtualFile() == null || + checkedClass.hasModifierProperty(PsiModifier.ABSTRACT) || + checkedClass.isEnum() || + PsiUtil.isInnerClass(checkedClass) || + !shouldCheckActionClass(checkedClass)) { + return; + } - private static PsiClass findRegistrationType(@Nullable PsiClass checkedClass, RegistrationCheckerUtil.RegistrationType type) { + GlobalSearchScope scope = checkedClass.getResolveScope(); + PsiClass actionClass = JavaPsiFacade.getInstance(project).findClass(AnAction.class.getName(), scope); + if (actionClass == null) { + // stop if action class cannot be found (non-devkit module/project) + return; + } + + if (checkedClass.isInheritor(actionClass, true)) { + if (!isActionRegistered(checkedClass) && canFix(checkedClass)) { + LocalQuickFix fix = new RegisterActionFix(org.jetbrains.idea.devkit.util.PsiUtil.createPointer(checkedClass)); + sink.highlight(DevKitBundle.message("inspections.component.not.registered.message", + DevKitBundle.message("new.menu.action.text")), fix); + } + // action IS registered, stop here + return; + } + + PsiClass compClass = JavaPsiFacade.getInstance(project).findClass(BaseComponent.class.getName(), scope); + if (compClass == null) { + // stop if component class cannot be found (non-devkit module/project) + return; + } + if (!checkedClass.isInheritor(compClass, true)) { + return; + } + + for (ComponentType componentType : ComponentType.values()) { + if (!InheritanceUtil.isInheritor(checkedClass, componentType.myClassName)) { + continue; + } + + if (findRegistrationType(checkedClass, COMPONENT_TYPE_TO_REGISTRATION_TYPE.get(componentType)) != null) { + return; + } + if (!canFix(checkedClass)) { + return; + } + + LocalQuickFix fix = new RegisterComponentFix(componentType, org.jetbrains.idea.devkit.util.PsiUtil.createPointer(checkedClass)); + sink.highlight(DevKitBundle.message("inspections.component.not.registered.message", + DevKitBundle.message(componentType.myPropertyKey)), fix); + } + } + + private static PsiClass findRegistrationType(@NotNull PsiClass checkedClass, @NotNull RegistrationCheckerUtil.RegistrationType type) { final Set types = RegistrationCheckerUtil.getRegistrationTypes(checkedClass, type); return ContainerUtil.getFirstItem(types); } - private boolean shouldCheckActionClass(PsiClass psiClass) { + private boolean shouldCheckActionClass(@NotNull PsiClass psiClass) { if (!CHECK_ACTIONS) return false; if (IGNORE_NON_PUBLIC && !psiClass.hasModifierProperty(PsiModifier.PUBLIC)) return false; return true; } - private static boolean isActionRegistered(PsiClass actionClass) { + private static boolean isActionRegistered(@NotNull PsiClass actionClass) { final PsiClass registrationType = findRegistrationType(actionClass, RegistrationCheckerUtil.RegistrationType.ACTION); if (registrationType != null) { return true; @@ -197,7 +201,7 @@ public class ComponentNotRegisteredInspection extends DevKitInspectionBase { return false; } - private static boolean canFix(PsiClass psiClass) { + private static boolean canFix(@NotNull PsiClass psiClass) { Project project = psiClass.getProject(); PsiFile psiFile = psiClass.getContainingFile(); LOG.assertTrue(psiFile != null); diff --git a/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/ComponentNotRegisteredInspectionTest.java b/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/ComponentNotRegisteredInspectionTest.java index c9b9d5f821d8..9e0fc26d3df7 100644 --- a/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/ComponentNotRegisteredInspectionTest.java +++ b/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/ComponentNotRegisteredInspectionTest.java @@ -15,159 +15,18 @@ */ package org.jetbrains.idea.devkit.inspections; -import com.intellij.codeInsight.intention.IntentionAction; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.testFramework.TestDataPath; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.devkit.DevkitJavaTestsUtil; -import org.jetbrains.idea.devkit.dom.Anchor; -import org.jetbrains.idea.devkit.inspections.quickfix.RegisterActionFix; -import org.jetbrains.idea.devkit.util.ActionData; -import org.jetbrains.idea.devkit.util.PsiUtil; @TestDataPath("$CONTENT_ROOT/testData/inspections/componentNotRegistered") -public class ComponentNotRegisteredInspectionTest extends PluginModuleTestCase { - +public class ComponentNotRegisteredInspectionTest extends ComponentNotRegisteredInspectionTestBase { @Override protected String getBasePath() { return DevkitJavaTestsUtil.TESTDATA_PATH + "inspections/componentNotRegistered"; } @Override - protected void setUp() throws Exception { - super.setUp(); - - myFixture.addClass("package com.intellij.openapi.actionSystem; public class AnAction {}"); - myFixture.addClass("package com.intellij.openapi.components; public interface BaseComponent {}"); - myFixture.addClass("package com.intellij.openapi.components; public interface ApplicationComponent extends BaseComponent {}"); - - myFixture.enableInspections(new ComponentNotRegisteredInspection()); - } - - public void testRegisteredAction() { - setPluginXml("registeredAction-plugin.xml"); - myFixture.testHighlighting("RegisteredAction.java"); - } - - public void testRegisteredActionInIDEAProject() { - PsiUtil.markAsIdeaProject(getProject(), true); - - try { - myFixture.copyFileToProject("registeredAction-plugin.xml", "someOtherPluginXmlName.xml"); - myFixture.testHighlighting("RegisteredAction.java"); - } - finally { - PsiUtil.markAsIdeaProject(getProject(), false); - } - } - - public void testRegisteredActionInOptionalPluginDescriptor() { - setPluginXml("registeredActionInOptionalPluginDescriptor-plugin.xml"); - myFixture.copyFileToProject("registeredActionInOptionalPluginDescriptor-optional-plugin.xml", - "META-INF/optional-plugin.xml"); - - myFixture.testHighlighting("RegisteredAction.java"); - } - - public void testRegisteredInIncludedFileAction() { - setPluginXml("ActionXInclude.xml"); - myFixture.copyFileToProject("ActionXInclude_included.xml", "META-INF/ActionXInclude_included.xml"); - myFixture.testHighlighting("ActionXInclude.java"); - } - - public void testUnregisteredAction() { - setPluginXml("unregisteredAction-plugin.xml"); - myFixture.testHighlighting("UnregisteredAction.java"); - - RegisterActionFix.ourTestActionData = new MyActionData("UnregisteredAction"); - final IntentionAction registerAction = myFixture.findSingleIntention("Register Action"); - myFixture.launchAction(registerAction); - - myFixture.checkResultByFile("META-INF/plugin.xml", "unregisteredAction-plugin_after.xml", true); - } - - public void testUnregisteredActionUsedViaConstructor() { - myFixture.testHighlighting("UnregisteredActionUsedViaConstructor.java"); - } - - public void testRegisteredApplicationComponent() { - setPluginXml("registeredApplicationComponent-plugin.xml"); - myFixture.testHighlighting("RegisteredApplicationComponent.java"); - } - - public void testUnregisteredAbstractApplicationComponent() { - myFixture.testHighlighting("UnregisteredAbstractApplicationComponent.java"); - } - - public void testUnregisteredApplicationComponentWithoutPluginXml() { - myFixture.testHighlighting("UnregisteredApplicationComponent.java", - "UnregisteredApplicationComponentInterface.java"); - } - - public void testUnregisteredApplicationComponentWithRegisterFix() { - setPluginXml("unregisteredApplicationComponent-plugin.xml"); - - myFixture.testHighlighting("UnregisteredApplicationComponent.java", - "UnregisteredApplicationComponentInterface.java"); - final IntentionAction registerAction = myFixture.findSingleIntention("Register Application Component"); - myFixture.launchAction(registerAction); - - myFixture.checkResultByFile("META-INF/plugin.xml", "unregisteredApplicationComponent-plugin_after.xml", true); - } - - - private static class MyActionData implements ActionData { - private final String myActionClassFqn; - - public MyActionData(String actionClassFqn) { - myActionClassFqn = actionClassFqn; - } - - @NotNull - @Override - public String getActionId() { - return StringUtil.getShortName(myActionClassFqn); - } - - @NotNull - @Override - public String getActionText() { - return "Action Text " + myActionClassFqn; - } - - @Override - public String getActionDescription() { - return "Description " + myActionClassFqn; - } - - @Nullable - @Override - public String getSelectedGroupId() { - return getActionId() + "Group"; - } - - @Nullable - @Override - public String getSelectedActionId() { - return getActionId() + "SelectedAction"; - } - - @Override - public String getSelectedAnchor() { - return Anchor.before.name(); - } - - @Nullable - @Override - public String getFirstKeyStroke() { - return "1st Key " + getActionId(); - } - - @Nullable - @Override - public String getSecondKeyStroke() { - return "2nd Key " + getActionId(); - } + protected String getSourceFileExtension() { + return "java"; } } diff --git a/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/ActionXInclude.kt b/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/ActionXInclude.kt new file mode 100644 index 000000000000..f12bbe971fe2 --- /dev/null +++ b/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/ActionXInclude.kt @@ -0,0 +1 @@ +class ActionXInclude : com.intellij.openapi.actionSystem.AnAction() \ No newline at end of file diff --git a/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/ActionXInclude.xml b/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/ActionXInclude.xml new file mode 100644 index 000000000000..9797654e4ba9 --- /dev/null +++ b/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/ActionXInclude.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/ActionXInclude_included.xml b/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/ActionXInclude_included.xml new file mode 100644 index 000000000000..9b4831cb2b12 --- /dev/null +++ b/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/ActionXInclude_included.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/RegisteredAction.kt b/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/RegisteredAction.kt new file mode 100644 index 000000000000..a3ffa00c573e --- /dev/null +++ b/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/RegisteredAction.kt @@ -0,0 +1,7 @@ +import com.intellij.openapi.actionSystem.AnAction + +class RegisteredAction : AnAction() { + + class InnerAction : AnAction() + +} \ No newline at end of file diff --git a/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/RegisteredApplicationComponent.kt b/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/RegisteredApplicationComponent.kt new file mode 100644 index 000000000000..50b1becd7231 --- /dev/null +++ b/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/RegisteredApplicationComponent.kt @@ -0,0 +1,6 @@ +import com.intellij.openapi.components.ApplicationComponent + +class RegisteredApplicationComponent : ApplicationComponent { + + class InnerStaticClassApplicationContext : ApplicationComponent +} \ No newline at end of file diff --git a/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/UnregisteredAbstractApplicationComponent.kt b/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/UnregisteredAbstractApplicationComponent.kt new file mode 100644 index 000000000000..2cd52da6f36f --- /dev/null +++ b/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/UnregisteredAbstractApplicationComponent.kt @@ -0,0 +1,3 @@ +import com.intellij.openapi.components.ApplicationComponent + +abstract class UnregisteredAbstractApplicationComponent : ApplicationComponent \ No newline at end of file diff --git a/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/UnregisteredAction.kt b/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/UnregisteredAction.kt new file mode 100644 index 000000000000..92afa81742cd --- /dev/null +++ b/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/UnregisteredAction.kt @@ -0,0 +1,7 @@ +import com.intellij.openapi.actionSystem.AnAction + +class UnregisteredAction : AnAction() { + class InnerAction : AnAction() + + protected class NonPublicIsIgnored : AnAction() +} \ No newline at end of file diff --git a/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/UnregisteredActionUsedViaConstructor.kt b/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/UnregisteredActionUsedViaConstructor.kt new file mode 100644 index 000000000000..2a5c7180fc5b --- /dev/null +++ b/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/UnregisteredActionUsedViaConstructor.kt @@ -0,0 +1,9 @@ +@file:Suppress("UNUSED_VARIABLE") + +import com.intellij.openapi.actionSystem.AnAction + +class UnregisteredActionUsedViaConstructor : AnAction() + +fun main(args: Array) { + val mine = UnregisteredActionUsedViaConstructor() +} \ No newline at end of file diff --git a/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/UnregisteredApplicationComponent.kt b/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/UnregisteredApplicationComponent.kt new file mode 100644 index 000000000000..522b4e6bd207 --- /dev/null +++ b/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/UnregisteredApplicationComponent.kt @@ -0,0 +1,12 @@ +import com.intellij.openapi.components.ApplicationComponent + +class UnregisteredApplicationComponent + : ApplicationComponent, UnregisteredApplicationComponentInterface { + + class InnerStaticClassApplicationContext + : ApplicationComponent + + inner class InnerClassApplicationContextIsNotChecked : ApplicationComponent + + fun getInstance() : UnregisteredApplicationComponentInterface? = null +} \ No newline at end of file diff --git a/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/UnregisteredApplicationComponentInterface.kt b/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/UnregisteredApplicationComponentInterface.kt new file mode 100644 index 000000000000..72bc731fa042 --- /dev/null +++ b/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/UnregisteredApplicationComponentInterface.kt @@ -0,0 +1 @@ +interface UnregisteredApplicationComponentInterface \ No newline at end of file diff --git a/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/registeredAction-plugin.xml b/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/registeredAction-plugin.xml new file mode 100644 index 000000000000..1896809e55eb --- /dev/null +++ b/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/registeredAction-plugin.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/registeredActionInOptionalPluginDescriptor-optional-plugin.xml b/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/registeredActionInOptionalPluginDescriptor-optional-plugin.xml new file mode 100644 index 000000000000..e2216421f271 --- /dev/null +++ b/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/registeredActionInOptionalPluginDescriptor-optional-plugin.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/registeredActionInOptionalPluginDescriptor-plugin.xml b/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/registeredActionInOptionalPluginDescriptor-plugin.xml new file mode 100644 index 000000000000..0ace22f7d835 --- /dev/null +++ b/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/registeredActionInOptionalPluginDescriptor-plugin.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/registeredApplicationComponent-plugin.xml b/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/registeredApplicationComponent-plugin.xml new file mode 100644 index 000000000000..9e8405a71961 --- /dev/null +++ b/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/registeredApplicationComponent-plugin.xml @@ -0,0 +1,11 @@ + + + + RegisteredApplicationComponent + + + RegisteredApplicationComponent$InnerStaticClassApplicationContext + + + + \ No newline at end of file diff --git a/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/unregisteredAction-plugin.xml b/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/unregisteredAction-plugin.xml new file mode 100644 index 000000000000..6fb76a66265d --- /dev/null +++ b/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/unregisteredAction-plugin.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/unregisteredAction-plugin_after.xml b/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/unregisteredAction-plugin_after.xml new file mode 100644 index 000000000000..89977dbe52d4 --- /dev/null +++ b/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/unregisteredAction-plugin_after.xml @@ -0,0 +1,11 @@ + + + + + + + + \ No newline at end of file diff --git a/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/unregisteredApplicationComponent-plugin.xml b/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/unregisteredApplicationComponent-plugin.xml new file mode 100644 index 000000000000..9d47e45ee4de --- /dev/null +++ b/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/unregisteredApplicationComponent-plugin.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/unregisteredApplicationComponent-plugin_after.xml b/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/unregisteredApplicationComponent-plugin_after.xml new file mode 100644 index 000000000000..abc6a373be6d --- /dev/null +++ b/plugins/devkit/devkit-kotlin-tests/testData/inspections/componentNotRegistered/unregisteredApplicationComponent-plugin_after.xml @@ -0,0 +1,9 @@ + + + + + UnregisteredApplicationComponent + UnregisteredApplicationComponentInterface + + + \ No newline at end of file diff --git a/plugins/devkit/devkit-kotlin-tests/testSrc/org/jetbrains/idea/devkit/kotlin/inspections/KtComponentNotRegisteredInspectionTest.java b/plugins/devkit/devkit-kotlin-tests/testSrc/org/jetbrains/idea/devkit/kotlin/inspections/KtComponentNotRegisteredInspectionTest.java new file mode 100644 index 000000000000..13d25b44c479 --- /dev/null +++ b/plugins/devkit/devkit-kotlin-tests/testSrc/org/jetbrains/idea/devkit/kotlin/inspections/KtComponentNotRegisteredInspectionTest.java @@ -0,0 +1,27 @@ +// Copyright 2000-2018 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.kotlin.inspections; + +import com.intellij.testFramework.TestDataPath; +import kotlin.KotlinVersion; +import org.jetbrains.idea.devkit.inspections.ComponentNotRegisteredInspectionTestBase; +import org.jetbrains.idea.devkit.kotlin.DevkitKtTestsUtil; +import org.junit.Assume; + +@TestDataPath("$CONTENT_ROOT/testData/inspections/componentNotRegistered") +public class KtComponentNotRegisteredInspectionTest extends ComponentNotRegisteredInspectionTestBase { + @Override + protected void setUp() throws Exception { + super.setUp(); + Assume.assumeTrue(KotlinVersion.CURRENT.isAtLeast(1, 2, 50)); + } + + @Override + protected String getSourceFileExtension() { + return "kt"; + } + + @Override + protected String getBasePath() { + return DevkitKtTestsUtil.TESTDATA_PATH + "inspections/componentNotRegistered"; + } +} diff --git a/plugins/devkit/devkit-tests-api/src/org/jetbrains/idea/devkit/inspections/ComponentNotRegisteredInspectionTestBase.java b/plugins/devkit/devkit-tests-api/src/org/jetbrains/idea/devkit/inspections/ComponentNotRegisteredInspectionTestBase.java new file mode 100644 index 000000000000..f88f770d9c9c --- /dev/null +++ b/plugins/devkit/devkit-tests-api/src/org/jetbrains/idea/devkit/inspections/ComponentNotRegisteredInspectionTestBase.java @@ -0,0 +1,158 @@ +// Copyright 2000-2018 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.codeInsight.intention.IntentionAction; +import com.intellij.openapi.util.text.StringUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.idea.devkit.dom.Anchor; +import org.jetbrains.idea.devkit.inspections.quickfix.RegisterActionFix; +import org.jetbrains.idea.devkit.util.ActionData; +import org.jetbrains.idea.devkit.util.PsiUtil; + +public abstract class ComponentNotRegisteredInspectionTestBase extends PluginModuleTestCase { + @Override + protected void setUp() throws Exception { + super.setUp(); + + myFixture.addClass("package com.intellij.openapi.actionSystem; public class AnAction {}"); + myFixture.addClass("package com.intellij.openapi.components; public interface BaseComponent {}"); + myFixture.addClass("package com.intellij.openapi.components; public interface ApplicationComponent extends BaseComponent {}"); + + myFixture.enableInspections(new ComponentNotRegisteredInspection()); + } + + protected abstract String getSourceFileExtension(); + + + public void testRegisteredAction() { + setPluginXml("registeredAction-plugin.xml"); + myFixture.testHighlighting("RegisteredAction." + getSourceFileExtension()); + } + + public void testRegisteredActionInIDEAProject() { + PsiUtil.markAsIdeaProject(getProject(), true); + + try { + myFixture.copyFileToProject("registeredAction-plugin.xml", "someOtherPluginXmlName.xml"); + myFixture.testHighlighting("RegisteredAction." + getSourceFileExtension()); + } + finally { + PsiUtil.markAsIdeaProject(getProject(), false); + } + } + + public void testRegisteredActionInOptionalPluginDescriptor() { + setPluginXml("registeredActionInOptionalPluginDescriptor-plugin.xml"); + myFixture.copyFileToProject("registeredActionInOptionalPluginDescriptor-optional-plugin.xml", + "META-INF/optional-plugin.xml"); + + myFixture.testHighlighting("RegisteredAction." + getSourceFileExtension()); + } + + public void testRegisteredInIncludedFileAction() { + setPluginXml("ActionXInclude.xml"); + myFixture.copyFileToProject("ActionXInclude_included.xml", "META-INF/ActionXInclude_included.xml"); + myFixture.testHighlighting("ActionXInclude." + getSourceFileExtension()); + } + + @SuppressWarnings("AssignmentToStaticFieldFromInstanceMethod") + public void testUnregisteredAction() { + setPluginXml("unregisteredAction-plugin.xml"); + myFixture.testHighlighting("UnregisteredAction." + getSourceFileExtension()); + + RegisterActionFix.ourTestActionData = new MyActionData("UnregisteredAction"); + try { + final IntentionAction registerAction = myFixture.findSingleIntention("Register Action"); + myFixture.launchAction(registerAction); + + myFixture.checkResultByFile("META-INF/plugin.xml", "unregisteredAction-plugin_after.xml", true); + } finally { + RegisterActionFix.ourTestActionData = null; + } + } + + public void testUnregisteredActionUsedViaConstructor() { + myFixture.testHighlighting("UnregisteredActionUsedViaConstructor." + getSourceFileExtension()); + } + + public void testRegisteredApplicationComponent() { + setPluginXml("registeredApplicationComponent-plugin.xml"); + myFixture.testHighlighting("RegisteredApplicationComponent." + getSourceFileExtension()); + } + + public void testUnregisteredAbstractApplicationComponent() { + myFixture.testHighlighting("UnregisteredAbstractApplicationComponent." + getSourceFileExtension()); + } + + public void testUnregisteredApplicationComponentWithoutPluginXml() { + myFixture.testHighlighting("UnregisteredApplicationComponent." + getSourceFileExtension(), + "UnregisteredApplicationComponentInterface." + getSourceFileExtension()); + } + + public void testUnregisteredApplicationComponentWithRegisterFix() { + setPluginXml("unregisteredApplicationComponent-plugin.xml"); + + myFixture.testHighlighting("UnregisteredApplicationComponent." + getSourceFileExtension(), + "UnregisteredApplicationComponentInterface." + getSourceFileExtension()); + final IntentionAction registerAction = myFixture.findSingleIntention("Register Application Component"); + myFixture.launchAction(registerAction); + + myFixture.checkResultByFile("META-INF/plugin.xml", "unregisteredApplicationComponent-plugin_after.xml", true); + } + + + public static class MyActionData implements ActionData { + private final String myActionClassFqn; + + public MyActionData(String actionClassFqn) { + myActionClassFqn = actionClassFqn; + } + + @NotNull + @Override + public String getActionId() { + return StringUtil.getShortName(myActionClassFqn); + } + + @NotNull + @Override + public String getActionText() { + return "Action Text " + myActionClassFqn; + } + + @Override + public String getActionDescription() { + return "Description " + myActionClassFqn; + } + + @Nullable + @Override + public String getSelectedGroupId() { + return getActionId() + "Group"; + } + + @Nullable + @Override + public String getSelectedActionId() { + return getActionId() + "SelectedAction"; + } + + @Override + public String getSelectedAnchor() { + return Anchor.before.name(); + } + + @Nullable + @Override + public String getFirstKeyStroke() { + return "1st Key " + getActionId(); + } + + @Nullable + @Override + public String getSecondKeyStroke() { + return "2nd Key " + getActionId(); + } + } +} diff --git a/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/PluginModuleTestCase.java b/plugins/devkit/devkit-tests-api/src/org/jetbrains/idea/devkit/inspections/PluginModuleTestCase.java similarity index 100% rename from plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/PluginModuleTestCase.java rename to plugins/devkit/devkit-tests-api/src/org/jetbrains/idea/devkit/inspections/PluginModuleTestCase.java