From ced3e2d03ccaa0e10aafe697323134bcd1411209 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yann=20C=C3=A9bron?= Date: Fri, 4 Nov 2016 16:49:01 +0100 Subject: [PATCH] [devkit] DevKitInspectionBase: extract registration functionality into RegistrationCheckerUtil --- .../ComponentNotRegisteredInspection.java | 19 +- .../src/inspections/DevKitInspectionBase.java | 185 +----------------- .../inspections/RegistrationCheckerUtil.java | 170 ++++++++++++++++ .../RegistrationProblemsInspection.java | 29 ++- 4 files changed, 210 insertions(+), 193 deletions(-) create mode 100644 plugins/devkit/src/inspections/RegistrationCheckerUtil.java diff --git a/plugins/devkit/src/inspections/ComponentNotRegisteredInspection.java b/plugins/devkit/src/inspections/ComponentNotRegisteredInspection.java index 936bbcfbed08..c22d2223d706 100644 --- a/plugins/devkit/src/inspections/ComponentNotRegisteredInspection.java +++ b/plugins/devkit/src/inspections/ComponentNotRegisteredInspection.java @@ -19,6 +19,7 @@ import com.intellij.codeInspection.InspectionManager; import com.intellij.codeInspection.LocalQuickFix; import com.intellij.codeInspection.ProblemDescriptor; import com.intellij.codeInspection.ProblemHighlightType; +import com.intellij.openapi.actionSystem.ActionGroup; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.Module; @@ -38,6 +39,7 @@ import org.jetbrains.idea.devkit.util.ComponentType; import javax.swing.*; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; +import java.util.Set; public class ComponentNotRegisteredInspection extends DevKitInspectionBase { public boolean CHECK_ACTIONS = true; @@ -82,7 +84,7 @@ public class ComponentNotRegisteredInspection extends DevKitInspectionBase { classIdentifier != null && psiFile != null && psiFile.getVirtualFile() != null && - !isAbstract(checkedClass)) + !checkedClass.hasModifierProperty(PsiModifier.ABSTRACT)) { if (PsiUtil.isInnerClass(checkedClass)) { // don't check inner classes (make this an option?) @@ -99,7 +101,7 @@ public class ComponentNotRegisteredInspection extends DevKitInspectionBase { return null; } if (checkedClass.isInheritor(actionClass, true)) { - if (IGNORE_NON_PUBLIC && !isPublic(checkedClass)) { + if (IGNORE_NON_PUBLIC && !checkedClass.hasModifierProperty(PsiModifier.PUBLIC)) { return null; } if (!isActionRegistered(checkedClass) && canFix(checkedClass)) { @@ -125,7 +127,7 @@ public class ComponentNotRegisteredInspection extends DevKitInspectionBase { return null; } if (checkedClass.isInheritor(compClass, true)) { - if (getRegistrationTypes(checkedClass, false) == null && canFix(checkedClass)) { + if (RegistrationCheckerUtil.getRegistrationTypes(checkedClass, false) == null && canFix(checkedClass)) { LocalQuickFix fix = new RegisterComponentFix(type, org.jetbrains.idea.devkit.util.PsiUtil.createPointer(checkedClass)); ProblemDescriptor problem = manager.createProblemDescriptor(classIdentifier, DevKitBundle.message("inspections.component.not.registered.message", @@ -142,6 +144,17 @@ public class ComponentNotRegisteredInspection extends DevKitInspectionBase { return null; } + private static boolean isActionRegistered(PsiClass psiClass) { + final Set registrationTypes = RegistrationCheckerUtil.getRegistrationTypes(psiClass, true); + if (registrationTypes != null) { + for (PsiClass type : registrationTypes) { + if (AnAction.class.getName().equals(type.getQualifiedName())) return true; + if (ActionGroup.class.getName().equals(type.getQualifiedName())) return true; + } + } + return false; + } + private static boolean canFix(PsiClass psiClass) { Project project = psiClass.getProject(); PsiFile psiFile = psiClass.getContainingFile(); diff --git a/plugins/devkit/src/inspections/DevKitInspectionBase.java b/plugins/devkit/src/inspections/DevKitInspectionBase.java index d7c01a1fd45e..fafabf4b6b05 100644 --- a/plugins/devkit/src/inspections/DevKitInspectionBase.java +++ b/plugins/devkit/src/inspections/DevKitInspectionBase.java @@ -17,45 +17,19 @@ package org.jetbrains.idea.devkit.inspections; import com.intellij.codeInspection.BaseJavaLocalInspectionTool; import com.intellij.codeInspection.ProblemsHolder; -import com.intellij.openapi.actionSystem.ActionGroup; -import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtilCore; -import com.intellij.openapi.paths.PathReference; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.*; -import com.intellij.psi.search.GlobalSearchScope; -import com.intellij.psi.xml.*; -import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.xml.DomFileElement; -import com.intellij.util.xml.DomUtil; -import com.intellij.util.xml.GenericAttributeValue; +import com.intellij.psi.PsiElementVisitor; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.idea.devkit.DevKitBundle; -import org.jetbrains.idea.devkit.dom.Dependency; -import org.jetbrains.idea.devkit.dom.IdeaPlugin; import org.jetbrains.idea.devkit.module.PluginModuleType; -import org.jetbrains.idea.devkit.util.ActionType; -import org.jetbrains.idea.devkit.util.ComponentType; -import org.jetbrains.idea.devkit.util.DescriptorUtil; import org.jetbrains.idea.devkit.util.PsiUtil; -import java.util.List; -import java.util.Set; - /** * @author swr */ public abstract class DevKitInspectionBase extends BaseJavaLocalInspectionTool { - @NotNull - public String getGroupDisplayName() { - return DevKitBundle.message("inspections.group.name"); - } - @NotNull @Override public final PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) { @@ -79,161 +53,4 @@ public abstract class DevKitInspectionBase extends BaseJavaLocalInspectionTool { protected PsiElementVisitor buildInternalVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) { return super.buildVisitor(holder, isOnTheFly); } - - @Nullable - protected static Set getRegistrationTypes(PsiClass psiClass, boolean includeActions) { - final Project project = psiClass.getProject(); - final PsiFile psiFile = psiClass.getContainingFile(); - - assert psiFile != null; - - final VirtualFile virtualFile = psiFile.getVirtualFile(); - if (virtualFile == null) return null; - final Module module = ModuleUtilCore.findModuleForFile(virtualFile, project); - - if (module == null) return null; - - if (PluginModuleType.isOfType(module)) { - return checkModule(module, psiClass, null, includeActions); - } - else { - Set types = null; - final List modules = PluginModuleType.getCandidateModules(module); - for (Module m : modules) { - types = checkModule(m, psiClass, types, includeActions); - } - return types; - } - } - - @Nullable - private static Set checkModule(Module module, PsiClass psiClass, @Nullable Set types, boolean includeActions) { - final XmlFile pluginXml = PluginModuleType.getPluginXml(module); - if (pluginXml == null) return null; - final DomFileElement fileElement = DescriptorUtil.getIdeaPlugin(pluginXml); - if (fileElement == null) return null; - - final String qualifiedName = psiClass.getQualifiedName(); - if (qualifiedName != null) { - final RegistrationTypeFinder finder = new RegistrationTypeFinder(psiClass, types); - - // "main" plugin.xml - processPluginXml(pluginXml, finder, includeActions); - - // plugin.xml files - for (Dependency dependency : fileElement.getRootElement().getDependencies()) { - final GenericAttributeValue configFileAttribute = dependency.getConfigFile(); - if (!DomUtil.hasXml(configFileAttribute)) continue; - - final PathReference configFile = configFileAttribute.getValue(); - if (configFile != null) { - final PsiElement resolve = configFile.resolve(); - if (!(resolve instanceof XmlFile)) continue; - final XmlFile depPluginXml = (XmlFile)resolve; - if (DescriptorUtil.isPluginXml(depPluginXml)) { - processPluginXml(depPluginXml, finder, includeActions); - } - } - } - - types = finder.getTypes(); - } - - return types; - } - - private static void processPluginXml(XmlFile xmlFile, RegistrationTypeFinder finder, boolean includeActions) { - final XmlDocument document = xmlFile.getDocument(); - if (document == null) return; - final XmlTag rootTag = document.getRootTag(); - if (rootTag == null) return; - - DescriptorUtil.processComponents(rootTag, finder); - if (includeActions) { - DescriptorUtil.processActions(rootTag, finder); - } - } - - @Nullable - protected static PsiElement getAttValueToken(@NotNull XmlAttribute attribute) { - final XmlAttributeValue valueElement = attribute.getValueElement(); - if (valueElement == null) return null; - - final PsiElement[] children = valueElement.getChildren(); - if (children.length == 3 && children[1] instanceof XmlToken) { - return children[1]; - } - if (children.length == 1 && children[0] instanceof PsiErrorElement) return null; - return valueElement; - } - - protected static boolean isAbstract(PsiModifierListOwner checkedClass) { - return checkedClass.hasModifierProperty(PsiModifier.ABSTRACT); - } - - protected static boolean isPublic(PsiModifierListOwner checkedClass) { - return checkedClass.hasModifierProperty(PsiModifier.PUBLIC); - } - - protected static boolean isActionRegistered(PsiClass psiClass) { - final Set registrationTypes = getRegistrationTypes(psiClass, true); - if (registrationTypes != null) { - for (PsiClass type : registrationTypes) { - if (AnAction.class.getName().equals(type.getQualifiedName())) return true; - if (ActionGroup.class.getName().equals(type.getQualifiedName())) return true; - } - } - return false; - } - - - private static class RegistrationTypeFinder implements ComponentType.Processor, ActionType.Processor { - private Set myTypes; - private final String myQualifiedName; - private final PsiManager myManager; - private final GlobalSearchScope myScope; - - private RegistrationTypeFinder(PsiClass psiClass, Set types) { - myTypes = types; - myQualifiedName = psiClass.getQualifiedName(); - myManager = psiClass.getManager(); - myScope = psiClass.getResolveScope(); - } - - public boolean process(ComponentType type, XmlTag component, XmlTagValue impl, XmlTagValue intf) { - if (impl != null && myQualifiedName.equals(impl.getTrimmedText())) { - final PsiClass clazz = JavaPsiFacade.getInstance(myManager.getProject()).findClass(type.myClassName, myScope); - if (clazz != null) { - addType(clazz); - } - } - return true; - } - - public boolean process(ActionType type, XmlTag action) { - final String actionClass = action.getAttributeValue("class"); - if (actionClass != null) { - if (actionClass.trim().equals(myQualifiedName)) { - final PsiClass clazz = JavaPsiFacade.getInstance(myManager.getProject()).findClass(type.myClassName, myScope); - if (clazz != null) { - addType(clazz); - return false; - } - } - } - return true; - } - - private void addType(PsiClass clazz) { - if (myTypes == null) { - //noinspection unchecked - myTypes = ContainerUtil.newIdentityTroveSet(2); - } - myTypes.add(clazz); - } - - public Set getTypes() { - return myTypes; - } - } } diff --git a/plugins/devkit/src/inspections/RegistrationCheckerUtil.java b/plugins/devkit/src/inspections/RegistrationCheckerUtil.java new file mode 100644 index 000000000000..adacbdfc4ba3 --- /dev/null +++ b/plugins/devkit/src/inspections/RegistrationCheckerUtil.java @@ -0,0 +1,170 @@ +/* + * Copyright 2000-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.idea.devkit.inspections; + +import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleUtilCore; +import com.intellij.openapi.paths.PathReference; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.*; +import com.intellij.psi.search.GlobalSearchScope; +import com.intellij.psi.xml.XmlDocument; +import com.intellij.psi.xml.XmlFile; +import com.intellij.psi.xml.XmlTag; +import com.intellij.psi.xml.XmlTagValue; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.xml.DomFileElement; +import com.intellij.util.xml.DomUtil; +import com.intellij.util.xml.GenericAttributeValue; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.idea.devkit.dom.Dependency; +import org.jetbrains.idea.devkit.dom.IdeaPlugin; +import org.jetbrains.idea.devkit.module.PluginModuleType; +import org.jetbrains.idea.devkit.util.ActionType; +import org.jetbrains.idea.devkit.util.ComponentType; +import org.jetbrains.idea.devkit.util.DescriptorUtil; + +import java.util.List; +import java.util.Set; + +class RegistrationCheckerUtil { + + @Nullable + static Set getRegistrationTypes(PsiClass psiClass, boolean includeActions) { + final Project project = psiClass.getProject(); + final PsiFile psiFile = psiClass.getContainingFile(); + + assert psiFile != null; + + final VirtualFile virtualFile = psiFile.getVirtualFile(); + if (virtualFile == null) return null; + final Module module = ModuleUtilCore.findModuleForFile(virtualFile, project); + + if (module == null) return null; + + if (PluginModuleType.isOfType(module)) { + return checkModule(module, psiClass, null, includeActions); + } + else { + Set types = null; + final List modules = PluginModuleType.getCandidateModules(module); + for (Module m : modules) { + types = checkModule(m, psiClass, types, includeActions); + } + return types; + } + } + + @Nullable + private static Set checkModule(Module module, PsiClass psiClass, @Nullable Set types, boolean includeActions) { + final XmlFile pluginXml = PluginModuleType.getPluginXml(module); + if (pluginXml == null) return null; + final DomFileElement fileElement = DescriptorUtil.getIdeaPlugin(pluginXml); + if (fileElement == null) return null; + + final String qualifiedName = psiClass.getQualifiedName(); + if (qualifiedName != null) { + final RegistrationTypeFinder finder = new RegistrationTypeFinder(psiClass, types); + + // "main" plugin.xml + processPluginXml(pluginXml, finder, includeActions); + + // plugin.xml files + for (Dependency dependency : fileElement.getRootElement().getDependencies()) { + final GenericAttributeValue configFileAttribute = dependency.getConfigFile(); + if (!DomUtil.hasXml(configFileAttribute)) continue; + + final PathReference configFile = configFileAttribute.getValue(); + if (configFile != null) { + final PsiElement resolve = configFile.resolve(); + if (!(resolve instanceof XmlFile)) continue; + final XmlFile depPluginXml = (XmlFile)resolve; + if (DescriptorUtil.isPluginXml(depPluginXml)) { + processPluginXml(depPluginXml, finder, includeActions); + } + } + } + + types = finder.getTypes(); + } + + return types; + } + + private static void processPluginXml(XmlFile xmlFile, RegistrationTypeFinder finder, boolean includeActions) { + final XmlDocument document = xmlFile.getDocument(); + if (document == null) return; + final XmlTag rootTag = document.getRootTag(); + if (rootTag == null) return; + + DescriptorUtil.processComponents(rootTag, finder); + if (includeActions) { + DescriptorUtil.processActions(rootTag, finder); + } + } + + private static class RegistrationTypeFinder implements ComponentType.Processor, ActionType.Processor { + + private Set myTypes; + private final String myQualifiedName; + private final PsiManager myManager; + private final GlobalSearchScope myScope; + + private RegistrationTypeFinder(PsiClass psiClass, Set types) { + myTypes = types; + myQualifiedName = psiClass.getQualifiedName(); + myManager = psiClass.getManager(); + myScope = psiClass.getResolveScope(); + } + + public boolean process(ComponentType type, XmlTag component, XmlTagValue impl, XmlTagValue intf) { + if (impl != null && myQualifiedName.equals(impl.getTrimmedText())) { + final PsiClass clazz = JavaPsiFacade.getInstance(myManager.getProject()).findClass(type.myClassName, myScope); + if (clazz != null) { + addType(clazz); + } + } + return true; + } + + public boolean process(ActionType type, XmlTag action) { + final String actionClass = action.getAttributeValue("class"); + if (actionClass != null) { + if (actionClass.trim().equals(myQualifiedName)) { + final PsiClass clazz = JavaPsiFacade.getInstance(myManager.getProject()).findClass(type.myClassName, myScope); + if (clazz != null) { + addType(clazz); + return false; + } + } + } + return true; + } + + private void addType(PsiClass clazz) { + if (myTypes == null) { + //noinspection unchecked + myTypes = ContainerUtil.newIdentityTroveSet(2); + } + myTypes.add(clazz); + } + + public Set getTypes() { + return myTypes; + } + } +} diff --git a/plugins/devkit/src/inspections/RegistrationProblemsInspection.java b/plugins/devkit/src/inspections/RegistrationProblemsInspection.java index 48483039371e..ffd094809228 100644 --- a/plugins/devkit/src/inspections/RegistrationProblemsInspection.java +++ b/plugins/devkit/src/inspections/RegistrationProblemsInspection.java @@ -116,7 +116,7 @@ public class RegistrationProblemsInspection extends DevKitInspectionBase { checkedClass.getQualifiedName() != null && checkedClass.getContainingFile().getVirtualFile() != null) { - final Set componentClasses = getRegistrationTypes(checkedClass, CHECK_ACTIONS); + final Set componentClasses = RegistrationCheckerUtil.getRegistrationTypes(checkedClass, CHECK_ACTIONS); if (componentClasses != null) { List problems = null; @@ -149,14 +149,14 @@ public class RegistrationProblemsInspection extends DevKitInspectionBase { return null; } - private List addProblem(List problems, ProblemDescriptor problemDescriptor) { + private static List addProblem(List problems, ProblemDescriptor problemDescriptor) { if (problems == null) problems = new SmartList<>(); problems.add(problemDescriptor); return problems; } @Nullable - private ProblemDescriptor[] checkPluginXml(XmlFile xmlFile, InspectionManager manager, boolean isOnTheFly) { + private static ProblemDescriptor[] checkPluginXml(XmlFile xmlFile, InspectionManager manager, boolean isOnTheFly) { final XmlDocument document = xmlFile.getDocument(); if (document == null) { return null; @@ -174,7 +174,24 @@ public class RegistrationProblemsInspection extends DevKitInspectionBase { return checker.getProblems(); } - static class RegistrationChecker implements ComponentType.Processor, ActionType.Processor { + private static boolean isAbstract(PsiModifierListOwner checkedClass) { + return checkedClass.hasModifierProperty(PsiModifier.ABSTRACT); + } + + @Nullable + private static PsiElement getAttValueToken(@NotNull XmlAttribute attribute) { + final XmlAttributeValue valueElement = attribute.getValueElement(); + if (valueElement == null) return null; + + final PsiElement[] children = valueElement.getChildren(); + if (children.length == 3 && children[1] instanceof XmlToken) { + return children[1]; + } + if (children.length == 1 && children[0] instanceof PsiErrorElement) return null; + return valueElement; + } + + private static class RegistrationChecker implements ComponentType.Processor, ActionType.Processor { private List myList; private final InspectionManager myManager; private final XmlFile myXmlFile; @@ -183,7 +200,7 @@ public class RegistrationProblemsInspection extends DevKitInspectionBase { private final Set myInterfaceClasses = new THashSet<>(); private final boolean myOnTheFly; - public RegistrationChecker(InspectionManager manager, XmlFile xmlFile, boolean onTheFly) { + private RegistrationChecker(InspectionManager manager, XmlFile xmlFile, boolean onTheFly) { myManager = manager; myXmlFile = xmlFile; myOnTheFly = onTheFly; @@ -370,7 +387,7 @@ public class RegistrationProblemsInspection extends DevKitInspectionBase { } return null; } - return ConstructorType.DEFAULT; + return DEFAULT; } } }