From 68771cfa263d6bc19e5877f7718d706ddd82fcdc Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Thu, 10 Feb 2011 17:39:01 +0100 Subject: [PATCH] it's an inspection: IDEA-64769 (Intention to convert (all) package.html into package-info.java) --- .../siyeh/InspectionGadgetsBundle.properties | 9 +- .../com/siyeh/ig/InspectionGadgetsPlugin.java | 2 + ...kageDotHtmlMayBePackageInfoInspection.java | 266 ++++++++++++++++++ .../PackageDotHtmlMayBePackageInfo.html | 14 + 4 files changed, 290 insertions(+), 1 deletion(-) create mode 100644 plugins/InspectionGadgets/src/com/siyeh/ig/javadoc/PackageDotHtmlMayBePackageInfoInspection.java create mode 100644 plugins/InspectionGadgets/src/inspectionDescriptions/PackageDotHtmlMayBePackageInfo.html diff --git a/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties b/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties index 7cfdd938a2bf..5734a1f02ef7 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties +++ b/plugins/InspectionGadgets/src/com/siyeh/InspectionGadgetsBundle.properties @@ -1834,4 +1834,11 @@ boxing.boxed.value.quickfix=Remove unnecessary boxing unnecessary.javadoc.link.option=Ignore inline links to super methods constant.junit.assert.argument.display.name=Constant JUnit assert argument constant.junit.assert.argument.problem.descriptor=Argument #ref is constant -test.case.with.no.test.methods.option=Ignore test cases which have super classes with test methods \ No newline at end of file +test.case.with.no.test.methods.option=Ignore test cases which have super classes with test methods +package.dot.html.may.be.package.info.display.name=package.html may be converted to package-info.java +package.dot.html.may.be.package.info.exists.problem.descriptor=package.html is ignored because package-info.java exists +package.dot.html.may.be.package.info.problem.descriptor=package.html may be converted to package-info.java +package.dot.html.may.be.package.info.delete.quickfix=Delete package.html +package.dot.html.delete.command=package.html deletion +package.dot.html.may.be.package.info.convert.quickfix=Convert to package-info.java +package.dot.html.convert.command=package.html to package-info.java conversion \ No newline at end of file diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/InspectionGadgetsPlugin.java b/plugins/InspectionGadgets/src/com/siyeh/ig/InspectionGadgetsPlugin.java index 74482e3429b8..f16ffba98be5 100644 --- a/plugins/InspectionGadgets/src/com/siyeh/ig/InspectionGadgetsPlugin.java +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/InspectionGadgetsPlugin.java @@ -54,6 +54,7 @@ import com.siyeh.ig.j2me.*; import com.siyeh.ig.javabeans.ClassWithoutConstructorInspection; import com.siyeh.ig.javabeans.ClassWithoutNoArgConstructorInspection; import com.siyeh.ig.javabeans.FieldHasSetterButNoGetterInspection; +import com.siyeh.ig.javadoc.PackageDotHtmlMayBePackageInfoInspection; import com.siyeh.ig.javadoc.UnnecessaryInheritDocInspection; import com.siyeh.ig.javadoc.UnnecessaryJavaDocLinkInspection; import com.siyeh.ig.jdk.*; @@ -691,6 +692,7 @@ public class InspectionGadgetsPlugin implements ApplicationComponent, } public void registerJavadocInspections() { + m_inspectionClasses.add(PackageDotHtmlMayBePackageInfoInspection.class); m_inspectionClasses.add(UnnecessaryJavaDocLinkInspection.class); m_inspectionClasses.add(UnnecessaryInheritDocInspection.class); } diff --git a/plugins/InspectionGadgets/src/com/siyeh/ig/javadoc/PackageDotHtmlMayBePackageInfoInspection.java b/plugins/InspectionGadgets/src/com/siyeh/ig/javadoc/PackageDotHtmlMayBePackageInfoInspection.java new file mode 100644 index 000000000000..73efd2d9a634 --- /dev/null +++ b/plugins/InspectionGadgets/src/com/siyeh/ig/javadoc/PackageDotHtmlMayBePackageInfoInspection.java @@ -0,0 +1,266 @@ +/* + * Copyright 2011 Bas Leijdekkers + * + * 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 com.siyeh.ig.javadoc; + +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.ide.DataManager; +import com.intellij.ide.IdeView; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.actionSystem.DataKeys; +import com.intellij.openapi.command.CommandProcessor; +import com.intellij.openapi.command.UndoConfirmationPolicy; +import com.intellij.openapi.command.WriteCommandAction; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ProjectFileIndex; +import com.intellij.openapi.roots.ProjectRootManager; +import com.intellij.openapi.util.AsyncResult; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.*; +import com.intellij.psi.html.HtmlTag; +import com.intellij.psi.javadoc.PsiDocComment; +import com.intellij.psi.xml.XmlFile; +import com.intellij.psi.xml.XmlTag; +import com.intellij.psi.xml.XmlTagValue; +import com.intellij.util.IncorrectOperationException; +import com.siyeh.InspectionGadgetsBundle; +import com.siyeh.ig.BaseInspection; +import com.siyeh.ig.BaseInspectionVisitor; +import com.siyeh.ig.InspectionGadgetsFix; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; + +public class PackageDotHtmlMayBePackageInfoInspection extends BaseInspection { + + @Nls + @NotNull + @Override + public String getDisplayName() { + return InspectionGadgetsBundle.message( + "package.dot.html.may.be.package.info.display.name"); + } + + @NotNull + @Override + protected String buildErrorString(Object... infos) { + if (((Boolean)infos[1]).booleanValue()) { + return InspectionGadgetsBundle.message( + "package.dot.html.may.be.package.info.exists.problem.descriptor"); + } + return InspectionGadgetsBundle.message( + "package.dot.html.may.be.package.info.problem.descriptor"); + } + + @Override + protected InspectionGadgetsFix buildFix(Object... infos) { + final boolean packageInfoExists = ((Boolean) infos[1]).booleanValue(); + if (packageInfoExists) { + return new DeletePackageDotHtmlFix(); + } + final String aPackage = (String) infos[0]; + return new PackageDotHtmlMayBePackageInfoFix(aPackage); + } + + private static class DeletePackageDotHtmlFix extends InspectionGadgetsFix { + + @NotNull + public String getName() { + return InspectionGadgetsBundle.message( + "package.dot.html.may.be.package.info.delete.quickfix"); + } + + @Override + protected void doFix(Project project, ProblemDescriptor descriptor) + throws IncorrectOperationException { + final PsiElement element = descriptor.getPsiElement(); + if (!(element instanceof XmlFile)) { + return; + } + final XmlFile xmlFile = (XmlFile) element; + + new WriteCommandAction.Simple(project, + InspectionGadgetsBundle.message( + "package.dot.html.delete.command"), xmlFile) { + @Override + protected void run() throws Throwable { + element.delete(); + } + + @Override + protected UndoConfirmationPolicy getUndoConfirmationPolicy() { + return UndoConfirmationPolicy.REQUEST_CONFIRMATION; + } + }.execute(); + } + } + + private static class PackageDotHtmlMayBePackageInfoFix + extends InspectionGadgetsFix { + + private final String aPackage; + + public PackageDotHtmlMayBePackageInfoFix(String aPackage) { + this.aPackage = aPackage; + } + + @NotNull + public String getName() { + return InspectionGadgetsBundle.message( + "package.dot.html.may.be.package.info.convert.quickfix"); + } + + @Override + protected void doFix(final Project project, + ProblemDescriptor descriptor) + throws IncorrectOperationException { + final PsiElement element = descriptor.getPsiElement(); + if (!(element instanceof XmlFile)) { + return; + } + final XmlFile xmlFile = (XmlFile) element; + final PsiDirectory directory = xmlFile.getContainingDirectory(); + if (directory == null) { + return; + } + final PsiFile file = directory.findFile("package-info.java"); + if (file != null) { + return; + } + new WriteCommandAction.Simple(project, + InspectionGadgetsBundle.message( + "package.dot.html.convert.command"), file) { + @Override + protected void run() throws Throwable { + final PsiJavaFile file = (PsiJavaFile) + directory.createFile("package-info.java"); + CommandProcessor.getInstance().addAffectedFiles(project, + file.getVirtualFile()); + final PsiElementFactory elementFactory = + JavaPsiFacade.getElementFactory(project); + final String packageInfoText = getPackageInfoText(xmlFile); + final String[] lines = + StringUtil.splitByLines(packageInfoText); + final StringBuilder commentText = new StringBuilder("/**\n"); + boolean appended = false; + for (String line : lines) { + if (!appended && line.length() == 0) { + // skip empty lines at the beginning + continue; + } + commentText.append(" * ").append(line).append('\n'); + appended = true; + } + commentText.append("*/"); + final PsiDocComment comment = + elementFactory.createDocCommentFromText( + commentText.toString()); + final PsiPackageStatement packageStatement = + elementFactory.createPackageStatement(aPackage); + final PsiElement addedElement = file.add(packageStatement); + file.addBefore(comment, addedElement); + element.delete(); + if (!isOnTheFly()) { + return; + } + final AsyncResult dataContextFromFocus = + DataManager.getInstance().getDataContextFromFocus(); + dataContextFromFocus.doWhenDone( + new AsyncResult.Handler() { + public void run(DataContext dataContext) { + final IdeView ideView = + DataKeys.IDE_VIEW.getData( + dataContext); + if (ideView == null) { + return; + } + ideView.selectElement(file); + } + } + ); + } + + @Override + protected UndoConfirmationPolicy getUndoConfirmationPolicy() { + return UndoConfirmationPolicy.REQUEST_CONFIRMATION; + } + }.execute(); + } + + private static String getPackageInfoText(XmlFile xmlFile) { + final XmlTag rootTag = xmlFile.getRootTag(); + if (rootTag == null) { + return null; + } + final PsiElement[] children = rootTag.getChildren(); + for (PsiElement child : children) { + if (!(child instanceof HtmlTag)) { + continue; + } + final HtmlTag htmlTag = (HtmlTag) child; + @NonNls final String name = htmlTag.getName(); + if ("body".equals(name)) { + final XmlTagValue value = htmlTag.getValue(); + return value.getText(); + } + } + return null; + } + } + + @Override + public BaseInspectionVisitor buildVisitor() { + return new PackageDotHtmlMayBePackageInfoVisitor(); + } + + private static class PackageDotHtmlMayBePackageInfoVisitor + extends BaseInspectionVisitor { + + @Override + public void visitFile(PsiFile file) { + super.visitFile(file); + if (!(file instanceof XmlFile)) { + return; + } + @NonNls final String fileName = file.getName(); + if (!"package.html".equals(fileName)) { + return; + } + final PsiDirectory directory = + file.getContainingDirectory(); + if (directory == null) { + return; + } + final String aPackage = getPackage(directory); + if (aPackage == null) { + return; + } + final boolean exists = + directory.findFile("package-info.java") != null; + registerError(file, aPackage, Boolean.valueOf(exists)); + } + + public static String getPackage(@NotNull PsiDirectory directory) { + final VirtualFile virtualFile = directory.getVirtualFile(); + final Project project = directory.getProject(); + final ProjectRootManager projectRootManager = + ProjectRootManager.getInstance(project); + final ProjectFileIndex fileIndex = + projectRootManager.getFileIndex(); + return fileIndex.getPackageNameByDirectory(virtualFile); + } + } +} diff --git a/plugins/InspectionGadgets/src/inspectionDescriptions/PackageDotHtmlMayBePackageInfo.html b/plugins/InspectionGadgets/src/inspectionDescriptions/PackageDotHtmlMayBePackageInfo.html new file mode 100644 index 000000000000..4f9309f2049c --- /dev/null +++ b/plugins/InspectionGadgets/src/inspectionDescriptions/PackageDotHtmlMayBePackageInfo.html @@ -0,0 +1,14 @@ + + +This inspection reports any package.html files. These files are used for documenting +packages. Since J2SE 5 it is recommended to use package-info.java files instead, since such +files can also contain package annotations. In this way, package-info.java becomes the +sole repository for package level annotations and documentation. +

+This inspection provides a quickfix to convert the package.html file to a package-info.java file. +If a package-info.java file is already present this inspection provides a quickfix to delete +the package.html file, since the Javadoc tool would ignore it then anyway. +

+New in 10.0.3, Powered by InspectionGadgets + + \ No newline at end of file