ComponentWithBrowseButton - optional remove listener on hide
[fedora-idea.git] / plugins / devkit / src / inspections / DescriptionNotFoundInspection.java
blobf72017c26dd7d560afa80dc197c902eeaf50591e
1 /*
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.
17 package org.jetbrains.idea.devkit.inspections;
19 import com.intellij.codeInspection.InspectionManager;
20 import com.intellij.codeInspection.LocalQuickFix;
21 import com.intellij.codeInspection.ProblemDescriptor;
22 import com.intellij.codeInspection.ProblemHighlightType;
23 import com.intellij.openapi.module.Module;
24 import com.intellij.openapi.module.ModuleUtil;
25 import com.intellij.openapi.project.Project;
26 import com.intellij.openapi.roots.ModuleRootManager;
27 import com.intellij.openapi.vfs.VirtualFile;
28 import com.intellij.psi.*;
29 import com.intellij.psi.search.GlobalSearchScope;
30 import org.jetbrains.annotations.Nls;
31 import org.jetbrains.annotations.NonNls;
32 import org.jetbrains.annotations.NotNull;
33 import org.jetbrains.annotations.Nullable;
34 import org.jetbrains.idea.devkit.inspections.quickfix.CreateHtmlDescriptionFix;
35 import org.jetbrains.idea.devkit.util.PsiUtil;
37 import java.util.ArrayList;
38 import java.util.Arrays;
39 import java.util.List;
41 /**
42 * @author Konstantin Bulenkov
44 public class DescriptionNotFoundInspection extends DevKitInspectionBase{
45 @NonNls private static final String INSPECTION_PROFILE_ENTRY = "com.intellij.codeInspection.InspectionProfileEntry";
46 @NonNls private static final String INSPECTION_DESCRIPTIONS = "inspectionDescriptions";
48 @Override
49 public ProblemDescriptor[] checkClass(@NotNull PsiClass aClass, @NotNull InspectionManager manager, boolean isOnTheFly) {
50 final Project project = aClass.getProject();
51 final PsiIdentifier nameIdentifier = aClass.getNameIdentifier();
52 final Module module = ModuleUtil.findModuleForPsiElement(aClass);
54 if (nameIdentifier == null || module == null || !PsiUtil.isInstanciatable(aClass)) return null;
56 final PsiClass base = JavaPsiFacade.getInstance(project).findClass(INSPECTION_PROFILE_ENTRY, GlobalSearchScope.allScope(project));
58 if (base == null || ! aClass.isInheritor(base, true) || isPathMethodsAreOverriden(aClass)) return null;
60 final PsiMethod method = findNearestMethod("getShortName", aClass);
61 if (method == null) return null;
62 final String filename = PsiUtil.getReturnedLiteral(method, aClass);
63 if (filename == null) return null;
66 for (PsiDirectory description : getInspectionDescriptionsDirs(module)) {
67 final PsiFile file = description.findFile(filename + ".html");
68 if (file == null) continue;
69 final VirtualFile vf = file.getVirtualFile();
70 if (vf == null) continue;
71 if (vf.getNameWithoutExtension().equals(filename)) {
72 return null;
77 final PsiElement problem = getProblemElement(aClass, method);
78 final ProblemDescriptor problemDescriptor = manager
79 .createProblemDescriptor(problem == null ? nameIdentifier : problem,
80 "Inspection does not have a description", isOnTheFly, new LocalQuickFix[]{new CreateHtmlDescriptionFix(filename, module)},
81 ProblemHighlightType.GENERIC_ERROR_OR_WARNING);
82 return new ProblemDescriptor[]{problemDescriptor};
85 @Nullable
86 private static PsiElement getProblemElement(PsiClass aClass, PsiMethod method) {
87 if (method.getContainingClass() == aClass) {
88 return PsiUtil.getReturnedExpression(method);
89 } else {
90 return aClass.getNameIdentifier();
94 private static boolean isPathMethodsAreOverriden(PsiClass aClass) {
95 return! ( isLastMethodDefinitionIn("getStaticDescription", INSPECTION_PROFILE_ENTRY, aClass)
96 && isLastMethodDefinitionIn("getDescriptionUrl", INSPECTION_PROFILE_ENTRY, aClass)
97 && isLastMethodDefinitionIn("getDescriptionContextClass", INSPECTION_PROFILE_ENTRY, aClass)
98 && isLastMethodDefinitionIn("getDescriptionFileName", INSPECTION_PROFILE_ENTRY, aClass));
101 private static boolean isLastMethodDefinitionIn(@NotNull String methodName, @NotNull String classFQN, PsiClass cls) {
102 if (cls == null) return false;
103 for (PsiMethod method : cls.getMethods()) {
104 if (method.getName().equals(methodName)) {
105 final PsiClass containingClass = method.getContainingClass();
106 if (containingClass == null) return false;
107 return classFQN.equals(containingClass.getQualifiedName());
110 return isLastMethodDefinitionIn(methodName, classFQN, cls.getSuperClass());
113 public static List<VirtualFile> getPotentialRoots(Module module) {
114 final PsiDirectory[] dirs = getInspectionDescriptionsDirs(module);
115 final List<VirtualFile> result = new ArrayList<VirtualFile>();
116 if (dirs.length != 0) {
117 for (PsiDirectory dir : dirs) {
118 final PsiDirectory parent = dir.getParentDirectory();
119 if (parent != null) result.add(parent.getVirtualFile());
121 } else {
122 result.addAll(Arrays.asList(ModuleRootManager.getInstance(module).getSourceRoots()));
124 return result;
127 public static PsiDirectory[] getInspectionDescriptionsDirs(Module module) {
128 final PsiPackage aPackage = JavaPsiFacade.getInstance(module.getProject()).findPackage(INSPECTION_DESCRIPTIONS);
129 if (aPackage != null) {
130 return aPackage.getDirectories(GlobalSearchScope.moduleWithDependenciesScope(module));
131 } else {
132 return PsiDirectory.EMPTY_ARRAY;
136 @Nullable
137 private static PsiMethod findNearestMethod(String name, @Nullable PsiClass cls) {
138 if (cls == null) return null;
139 for (PsiMethod method : cls.getMethods()) {
140 if (method.getParameterList().getParametersCount() == 0 && method.getName().equals(name)) {
141 return method.getModifierList().hasModifierProperty(PsiModifier.ABSTRACT) ? null : method;
144 return findNearestMethod(name, cls.getSuperClass());
147 @Nls
148 @NotNull
149 public String getDisplayName() {
150 return "Inspection Description Checker";
153 @NotNull
154 public String getShortName() {
155 return "DescriptionNotFoundInspection";
158 @Override
159 public boolean isEnabledByDefault() {
160 return true;