intention description check

This commit is contained in:
Konstantin Bulenkov
2010-06-30 16:39:41 +04:00
parent 4013479fa7
commit aabb42b88e
5 changed files with 174 additions and 21 deletions
@@ -2,4 +2,4 @@
<body>
<font face="verdana" size="-1">This inspection detects missing html-description for an inspection.</font>
</body>
</html>
</html>
@@ -17,18 +17,22 @@ package org.jetbrains.idea.devkit;
import com.intellij.codeInspection.InspectionToolProvider;
import org.jetbrains.idea.devkit.inspections.ComponentNotRegisteredInspection;
import org.jetbrains.idea.devkit.inspections.DescriptionNotFoundInspection;
import org.jetbrains.idea.devkit.inspections.InspectionDescriptionNotFoundInspection;
import org.jetbrains.idea.devkit.inspections.IntentionDescriptionNotFoundInspection;
import org.jetbrains.idea.devkit.inspections.PluginXmlDomInspection;
/**
* @author Konstantin Bulenkov
*/
public class DevKitInspectionToolProvider implements InspectionToolProvider {
public Class[] getInspectionClasses() {
return new Class[] {
//RegistrationProblemsInspection.class,
PluginXmlDomInspection.class,
ComponentNotRegisteredInspection.class,
DescriptionNotFoundInspection.class
InspectionDescriptionNotFoundInspection.class,
IntentionDescriptionNotFoundInspection.class
};
}
}
}
@@ -41,7 +41,7 @@ import java.util.List;
/**
* @author Konstantin Bulenkov
*/
public class DescriptionNotFoundInspection extends DevKitInspectionBase{
public class InspectionDescriptionNotFoundInspection extends DevKitInspectionBase{
@NonNls private static final String INSPECTION_PROFILE_ENTRY = "com.intellij.codeInspection.InspectionProfileEntry";
@NonNls private static final String INSPECTION_DESCRIPTIONS = "inspectionDescriptions";
@@ -77,7 +77,7 @@ public class DescriptionNotFoundInspection extends DevKitInspectionBase{
final PsiElement problem = getProblemElement(aClass, method);
final ProblemDescriptor problemDescriptor = manager
.createProblemDescriptor(problem == null ? nameIdentifier : problem,
"Inspection does not have a description", isOnTheFly, new LocalQuickFix[]{new CreateHtmlDescriptionFix(filename, module)},
"Inspection does not have a description", isOnTheFly, new LocalQuickFix[]{new CreateHtmlDescriptionFix(filename, module, false)},
ProblemHighlightType.GENERIC_ERROR_OR_WARNING);
return new ProblemDescriptor[]{problemDescriptor};
}
@@ -152,7 +152,7 @@ public class DescriptionNotFoundInspection extends DevKitInspectionBase{
@NotNull
public String getShortName() {
return "DescriptionNotFoundInspection";
return "InspectionDescriptionNotFoundInspection";
}
@Override
@@ -0,0 +1,130 @@
/*
* Copyright 2000-2010 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.codeInspection.InspectionManager;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.codeInspection.ProblemHighlightType;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.devkit.inspections.quickfix.CreateHtmlDescriptionFix;
import org.jetbrains.idea.devkit.util.PsiUtil;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @author Konstantin Bulenkov
*/
public class IntentionDescriptionNotFoundInspection extends DevKitInspectionBase{
@NonNls private static final String INTENTION = "com.intellij.codeInsight.intention.IntentionAction";
@NonNls private static final String INSPECTION_DESCRIPTIONS = "intentionDescriptions";
@Override
public ProblemDescriptor[] checkClass(@NotNull PsiClass aClass, @NotNull InspectionManager manager, boolean isOnTheFly) {
final Project project = aClass.getProject();
final PsiIdentifier nameIdentifier = aClass.getNameIdentifier();
final Module module = ModuleUtil.findModuleForPsiElement(aClass);
if (nameIdentifier == null || module == null || !PsiUtil.isInstanciatable(aClass)) return null;
final PsiClass base = JavaPsiFacade.getInstance(project).findClass(INTENTION, GlobalSearchScope.allScope(project));
if (base == null || ! aClass.isInheritor(base, true)) return null;
final PsiMethod method = findNearestMethod("getFamilyName", aClass);
if (method == null) return null;
final String filename = PsiUtil.getReturnedLiteral(method, aClass);
if (filename == null) return null;
for (PsiDirectory description : getIntentionDescriptionsDirs(module)) {
PsiDirectory dir = description.findSubdirectory(filename);
if (dir == null) dir = description.findSubdirectory(aClass.getName());
if (dir == null) continue;
final PsiFile descr = dir.findFile("description.html");
if (descr != null) return null;
}
final PsiElement problem = aClass.getNameIdentifier();
final ProblemDescriptor problemDescriptor = manager
.createProblemDescriptor(problem == null ? nameIdentifier : problem,
"Intention does not have a description", isOnTheFly, new LocalQuickFix[]{new CreateHtmlDescriptionFix(aClass.getName(), module, true)},
ProblemHighlightType.GENERIC_ERROR_OR_WARNING);
return new ProblemDescriptor[]{problemDescriptor};
}
public static List<VirtualFile> getPotentialRoots(Module module) {
final PsiDirectory[] dirs = getIntentionDescriptionsDirs(module);
final List<VirtualFile> result = new ArrayList<VirtualFile>();
if (dirs.length != 0) {
for (PsiDirectory dir : dirs) {
final PsiDirectory parent = dir.getParentDirectory();
if (parent != null) result.add(parent.getVirtualFile());
}
} else {
result.addAll(Arrays.asList(ModuleRootManager.getInstance(module).getSourceRoots()));
}
return result;
}
public static PsiDirectory[] getIntentionDescriptionsDirs(Module module) {
final PsiPackage aPackage = JavaPsiFacade.getInstance(module.getProject()).findPackage(INSPECTION_DESCRIPTIONS);
if (aPackage != null) {
return aPackage.getDirectories(GlobalSearchScope.moduleWithDependenciesScope(module));
} else {
return PsiDirectory.EMPTY_ARRAY;
}
}
@Nullable
private static PsiMethod findNearestMethod(String name, @Nullable PsiClass cls) {
if (cls == null) return null;
for (PsiMethod method : cls.getMethods()) {
if (method.getParameterList().getParametersCount() == 0 && method.getName().equals(name)) {
return method.getModifierList().hasModifierProperty(PsiModifier.ABSTRACT) ? null : method;
}
}
return findNearestMethod(name, cls.getSuperClass());
}
@Nls
@NotNull
public String getDisplayName() {
return "Intention Description Checker";
}
@NotNull
public String getShortName() {
return "IntentionDescriptionNotFoundInspection";
}
@Override
public boolean isEnabledByDefault() {
return true;
}
}
@@ -42,7 +42,8 @@ import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.devkit.DevKitBundle;
import org.jetbrains.idea.devkit.inspections.DescriptionNotFoundInspection;
import org.jetbrains.idea.devkit.inspections.InspectionDescriptionNotFoundInspection;
import org.jetbrains.idea.devkit.inspections.IntentionDescriptionNotFoundInspection;
import javax.swing.*;
import java.io.File;
@@ -54,14 +55,15 @@ import java.util.List;
*/
public class CreateHtmlDescriptionFix implements LocalQuickFix, Iconable {
private final String myFilename;
private final Module myModule;
@NonNls private static final String DESCRIPTIONS_FOLDER = "inspectionDescriptions";
private final Module myModule;
@NonNls private static final String TEMPLATE_NAME = "InspectionDescription.html";
private static final Icon NEW_HTML_ICON = IconLoader.getIcon("/new_html.png");
private final boolean isIntention;
public CreateHtmlDescriptionFix(String filename, Module module) {
public CreateHtmlDescriptionFix(String filename, Module module, boolean isIntention) {
myModule = module;
myFilename = filename + ".html";
this.isIntention = isIntention;
myFilename = isIntention ? filename : filename + ".html";
}
@NotNull
@@ -75,7 +77,10 @@ public class CreateHtmlDescriptionFix implements LocalQuickFix, Iconable {
}
public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) {
final List<VirtualFile> virtualFiles = DescriptionNotFoundInspection.getPotentialRoots(myModule);
final List<VirtualFile> virtualFiles = isIntention ?
IntentionDescriptionNotFoundInspection.getPotentialRoots(myModule)
:
InspectionDescriptionNotFoundInspection.getPotentialRoots(myModule);
final VirtualFile[] roots = prepare(VfsUtil.toVirtualFileArray(virtualFiles));
if (roots.length == 1) {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@@ -88,7 +93,11 @@ public class CreateHtmlDescriptionFix implements LocalQuickFix, Iconable {
else {
List<String> options = new ArrayList<String>();
for (VirtualFile file : roots) {
options.add(file.getPresentableUrl() + File.separator + DESCRIPTIONS_FOLDER + File.separator + myFilename);
String path = file.getPresentableUrl() + File.separator + getDescriptionFolderName() + File.separator + myFilename;
if (isIntention) {
path += File.separator + "description.html";
}
options.add(path);
}
final JList files = new JBList(ArrayUtil.toStringArray(options));
final PopupChooserBuilder builder = JBPopupFactory.getInstance().createListPopupBuilder(files);
@@ -117,16 +126,22 @@ public class CreateHtmlDescriptionFix implements LocalQuickFix, Iconable {
PsiDirectory descrRoot = null;
if (psiRoot == null) return;
for (PsiDirectory dir : psiRoot.getSubdirectories()) {
if (DESCRIPTIONS_FOLDER.equals(dir.getName())) {
if (getDescriptionFolderName().equals(dir.getName())) {
descrRoot = dir;
break;
}
}
try {
descrRoot = descrRoot == null ? psiRoot.createSubdirectory(DESCRIPTIONS_FOLDER) : descrRoot;
descrRoot = descrRoot == null ? psiRoot.createSubdirectory(getDescriptionFolderName()) : descrRoot;
if (isIntention) {
PsiDirectory dir = descrRoot.findSubdirectory(myFilename);
if (dir == null) {
descrRoot = descrRoot.createSubdirectory(myFilename);
}
}
final FileTemplate descrTemplate = FileTemplateManager.getInstance().getJ2eeTemplate(TEMPLATE_NAME);
final PsiElement template = FileTemplateUtil.createFromTemplate(descrTemplate, myFilename, null, descrRoot);
final PsiElement template = FileTemplateUtil.createFromTemplate(descrTemplate, isIntention? "description.html" : myFilename, null, descrRoot);
if (template instanceof PsiFile) {
final VirtualFile file = ((PsiFile)template).getVirtualFile();
if (file != null) {
@@ -142,7 +157,7 @@ public class CreateHtmlDescriptionFix implements LocalQuickFix, Iconable {
return NEW_HTML_ICON;
}
private static VirtualFile[] prepare(VirtualFile[] roots) {
private VirtualFile[] prepare(VirtualFile[] roots) {
List<VirtualFile> found = new ArrayList<VirtualFile>();
for (VirtualFile root : roots) {
if (containsDescriptionDir(root)) {
@@ -152,13 +167,17 @@ public class CreateHtmlDescriptionFix implements LocalQuickFix, Iconable {
return found.size() > 0 ? VfsUtil.toVirtualFileArray(found) : roots;
}
private static boolean containsDescriptionDir(VirtualFile root) {
private boolean containsDescriptionDir(VirtualFile root) {
if (!root.isDirectory()) return false;
for (VirtualFile file : root.getChildren()) {
if (file.isDirectory() && DESCRIPTIONS_FOLDER.equals(file.getName())) {
if (file.isDirectory() && getDescriptionFolderName().equals(file.getName())) {
return true;
}
}
return false;
}
private String getDescriptionFolderName() {
return isIntention ? "intentionDescriptions" : "inspectionDescriptions";
}
}