2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package org
.jetbrains
.idea
.devkit
.inspections
;
18 import com
.intellij
.codeInspection
.BaseJavaLocalInspectionTool
;
19 import com
.intellij
.openapi
.actionSystem
.ActionGroup
;
20 import com
.intellij
.openapi
.actionSystem
.AnAction
;
21 import com
.intellij
.openapi
.module
.Module
;
22 import com
.intellij
.openapi
.module
.ModuleUtil
;
23 import com
.intellij
.openapi
.project
.Project
;
24 import com
.intellij
.openapi
.vfs
.VirtualFile
;
25 import com
.intellij
.psi
.*;
26 import com
.intellij
.psi
.search
.GlobalSearchScope
;
27 import com
.intellij
.psi
.xml
.*;
28 import gnu
.trove
.THashSet
;
29 import gnu
.trove
.TObjectHashingStrategy
;
30 import org
.jetbrains
.annotations
.NotNull
;
31 import org
.jetbrains
.annotations
.Nullable
;
32 import org
.jetbrains
.idea
.devkit
.DevKitBundle
;
33 import org
.jetbrains
.idea
.devkit
.module
.PluginModuleType
;
34 import org
.jetbrains
.idea
.devkit
.util
.ActionType
;
35 import org
.jetbrains
.idea
.devkit
.util
.ComponentType
;
36 import org
.jetbrains
.idea
.devkit
.util
.DescriptorUtil
;
38 import java
.util
.List
;
44 public abstract class DevKitInspectionBase
extends BaseJavaLocalInspectionTool
{
47 public String
getGroupDisplayName() {
48 return DevKitBundle
.message("inspections.group.name");
52 protected static Set
<PsiClass
> getRegistrationTypes(PsiClass psiClass
, boolean includeActions
) {
53 final Project project
= psiClass
.getProject();
54 final PsiFile psiFile
= psiClass
.getContainingFile();
56 assert psiFile
!= null;
58 final VirtualFile virtualFile
= psiFile
.getVirtualFile();
59 if (virtualFile
== null) return null;
60 final Module module
= ModuleUtil
.findModuleForFile(virtualFile
, project
);
62 if (module
== null) return null;
64 if (PluginModuleType
.isOfType(module
)) {
65 return checkModule(module
, psiClass
, null, includeActions
);
67 Set
<PsiClass
> types
= null;
68 final List
<Module
> modules
= PluginModuleType
.getCandidateModules(module
);
69 for (Module m
: modules
) {
70 types
= checkModule(m
, psiClass
, types
, includeActions
);
76 private static Set
<PsiClass
> checkModule(Module module
, PsiClass psiClass
, Set
<PsiClass
> types
, boolean includeActions
) {
77 final XmlFile pluginXml
= PluginModuleType
.getPluginXml(module
, false);
78 if (!isPluginXml(pluginXml
)) return types
;
79 assert pluginXml
!= null;
81 final XmlDocument document
= pluginXml
.getDocument();
82 assert document
!= null;
84 final XmlTag rootTag
= document
.getRootTag();
85 assert rootTag
!= null;
87 final String qualifiedName
= psiClass
.getQualifiedName();
88 if (qualifiedName
!= null) {
89 final RegistrationTypeFinder finder
= new RegistrationTypeFinder(psiClass
, types
);
91 DescriptorUtil
.processComponents(rootTag
, finder
);
94 DescriptorUtil
.processActions(rootTag
, finder
);
97 types
= finder
.getTypes();
103 protected static boolean isPluginXml(PsiFile file
) {
104 if (!(file
instanceof XmlFile
)) return false;
105 final XmlFile pluginXml
= (XmlFile
)file
;
107 final XmlDocument document
= pluginXml
.getDocument();
108 if (document
== null) return false;
109 final XmlTag rootTag
= document
.getRootTag();
110 return rootTag
!= null && "idea-plugin".equals(rootTag
.getLocalName());
115 protected static PsiElement
getAttValueToken(@NotNull XmlAttribute attribute
) {
116 final XmlAttributeValue valueElement
= attribute
.getValueElement();
117 if (valueElement
== null) return null;
119 final PsiElement
[] children
= valueElement
.getChildren();
120 if (children
.length
== 3 && children
[1] instanceof XmlToken
) {
126 protected static boolean isAbstract(PsiModifierListOwner checkedClass
) {
127 return checkedClass
.hasModifierProperty(PsiModifier
.ABSTRACT
);
130 protected static boolean isPublic(PsiModifierListOwner checkedClass
) {
131 return checkedClass
.hasModifierProperty(PsiModifier
.PUBLIC
);
134 protected static boolean isActionRegistered(PsiClass psiClass
) {
135 final Set
<PsiClass
> registrationTypes
= getRegistrationTypes(psiClass
, true);
136 if (registrationTypes
!= null) {
137 for (PsiClass type
: registrationTypes
) {
138 if (AnAction
.class.getName().equals(type
.getQualifiedName())) return true;
139 if (ActionGroup
.class.getName().equals(type
.getQualifiedName())) return true;
145 static class RegistrationTypeFinder
implements ComponentType
.Processor
, ActionType
.Processor
{
146 private Set
<PsiClass
> myTypes
;
147 private final String myQualifiedName
;
148 private final PsiManager myManager
;
149 private final GlobalSearchScope myScope
;
151 public RegistrationTypeFinder(PsiClass psiClass
, Set
<PsiClass
> types
) {
153 myQualifiedName
= psiClass
.getQualifiedName();
154 myManager
= psiClass
.getManager();
155 myScope
= psiClass
.getResolveScope();
158 public boolean process(ComponentType type
, XmlTag component
, XmlTagValue impl
, XmlTagValue intf
) {
159 if (impl
!= null && myQualifiedName
.equals(impl
.getTrimmedText())) {
160 final PsiClass clazz
= JavaPsiFacade
.getInstance(myManager
.getProject()).findClass(type
.myClassName
, myScope
);
168 public boolean process(ActionType type
, XmlTag action
) {
169 final String actionClass
= action
.getAttributeValue("class");
170 if (actionClass
!= null) {
171 if (actionClass
.trim().equals(myQualifiedName
)) {
172 final PsiClass clazz
= JavaPsiFacade
.getInstance(myManager
.getProject()).findClass(type
.myClassName
, myScope
);
182 private void addType(PsiClass clazz
) {
183 if (myTypes
== null) {
184 //noinspection unchecked
185 myTypes
= new THashSet
<PsiClass
>(2, TObjectHashingStrategy
.IDENTITY
);
190 public Set
<PsiClass
> getTypes() {