IDEA-130458 (Inspection to find deprecated symbols without @deprecated JavaDoc tag)

This commit is contained in:
Bas Leijdekkers
2014-11-10 16:38:34 +01:00
parent 5c6101f7e1
commit ff0a2db443
5 changed files with 133 additions and 21 deletions
@@ -913,7 +913,7 @@ utility.class.without.private.constructor.problem.descriptor=Class <code>#ref</c
abstract.method.overrides.concrete.method.problem.descriptor=Abstract method <code>#ref()</code> overrides concrete method #loc
abstract.method.with.missing.implementations.problem.descriptor=Abstract method <code>#ref()</code> is not implemented in every subclass #loc
abstract.method.overrides.abstract.method.problem.descriptor=Abstract method <code>#ref()</code> overrides abstract method #loc
abstract.method.overrides.abstract.method.ignore.different.javadoc.option=Ignore methods with different JavaDoc than their super methods
abstract.method.overrides.abstract.method.ignore.different.javadoc.option=Ignore methods with different Javadoc than their super methods
abstract.method.overrides.abstract.method.ignore.different.annotations.option=Ignore methods with different annotations than their super methods
abstract.class.extends.concrete.class.problem.descriptor=Class <code>#ref</code> is declared 'abstract', and extends a concrete class #loc
static.non.final.field.problem.descriptor='static' non-'final' field <code>#ref</code> #loc
@@ -932,7 +932,9 @@ marker.interface.problem.descriptor=Marker interface <code>#ref</code> #loc
field.has.setter.but.no.getter.problem.descriptor=Field <code>#ref</code> has setter but no getter #loc
abstract.class.never.implemented.problem.descriptor=Abstract class <code>#ref</code> has no concrete subclass #loc
interface.never.implemented.problem.descriptor=Interface <code>#ref</code> has no concrete subclass #loc
missing.deprecated.annotation.problem.descriptor=Missing '@Deprecated' annotation on <code>#ref()</code> #loc
missing.deprecated.annotation.problem.descriptor=Missing '@Deprecated' annotation #loc
missing.deprecated.tag.problem.descriptor=Missing '@deprecated' Javadoc tag explanation #loc
missing.deprecated.tag.option=Warn on missing @deprecated Javadoc tag explanation
missing.override.annotation.problem.descriptor=Missing '@Override' annotation on <code>#ref()</code> #loc
non.thread.safe.lazy.initialization.problem.descriptor=Lazy initialization of 'static' field <code>#ref</code> is not thread-safe #loc
empty.catch.block.problem.descriptor=Empty <code>#ref</code> block #loc
@@ -16,6 +16,7 @@
package com.siyeh.ig.javadoc;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.codeInspection.ui.SingleCheckboxOptionsPanel;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.javadoc.PsiDocComment;
@@ -26,9 +27,14 @@ import com.siyeh.ig.BaseInspection;
import com.siyeh.ig.BaseInspectionVisitor;
import com.siyeh.ig.InspectionGadgetsFix;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
public class MissingDeprecatedAnnotationInspection extends BaseInspection {
@SuppressWarnings("PublicField") public boolean warnOnMissingJavadoc = false;
@Override
@NotNull
public String getDisplayName() {
@@ -38,7 +44,17 @@ public class MissingDeprecatedAnnotationInspection extends BaseInspection {
@Override
@NotNull
protected String buildErrorString(Object... infos) {
return InspectionGadgetsBundle.message("missing.deprecated.annotation.problem.descriptor");
final boolean annotationWarning = ((Boolean)infos[0]).booleanValue();
return annotationWarning
? InspectionGadgetsBundle.message("missing.deprecated.annotation.problem.descriptor")
: InspectionGadgetsBundle.message("missing.deprecated.tag.problem.descriptor");
}
@Nullable
@Override
public JComponent createOptionsPanel() {
return new SingleCheckboxOptionsPanel(InspectionGadgetsBundle.message("missing.deprecated.tag.option"),
this, "warnOnMissingJavadoc");
}
@Override
@@ -48,6 +64,10 @@ public class MissingDeprecatedAnnotationInspection extends BaseInspection {
@Override
protected InspectionGadgetsFix buildFix(Object... infos) {
final boolean annotationWarning = ((Boolean)infos[0]).booleanValue();
if (!annotationWarning) {
return null;
}
return new MissingDeprecatedAnnotationFix();
}
@@ -87,7 +107,7 @@ public class MissingDeprecatedAnnotationInspection extends BaseInspection {
return new MissingDeprecatedAnnotationVisitor();
}
private static class MissingDeprecatedAnnotationVisitor extends BaseInspectionVisitor {
private class MissingDeprecatedAnnotationVisitor extends BaseInspectionVisitor {
@Override
public void visitClass(@NotNull PsiClass aClass) {
@@ -95,10 +115,14 @@ public class MissingDeprecatedAnnotationInspection extends BaseInspection {
if (!PsiUtil.isLanguageLevel5OrHigher(aClass)) {
return;
}
if (!hasDeprecatedComment(aClass) || hasDeprecatedAnnotation(aClass)) {
return;
if (hasDeprecatedAnnotation(aClass)) {
if (warnOnMissingJavadoc && !hasDeprecatedComment(aClass, true)) {
registerClassError(aClass, Boolean.FALSE);
}
}
else if (hasDeprecatedComment(aClass, false)) {
registerClassError(aClass, Boolean.TRUE);
}
registerClassError(aClass);
}
@Override
@@ -109,10 +133,14 @@ public class MissingDeprecatedAnnotationInspection extends BaseInspection {
if (method.getNameIdentifier() == null) {
return;
}
if (!hasDeprecatedComment(method) || hasDeprecatedAnnotation(method)) {
return;
if (hasDeprecatedAnnotation(method)) {
if (warnOnMissingJavadoc && !hasDeprecatedComment(method, true)) {
registerMethodError(method, Boolean.FALSE);
}
}
else if (hasDeprecatedComment(method, false)) {
registerMethodError(method, Boolean.TRUE);
}
registerMethodError(method);
}
@Override
@@ -120,28 +148,31 @@ public class MissingDeprecatedAnnotationInspection extends BaseInspection {
if (!PsiUtil.isLanguageLevel5OrHigher(field)) {
return;
}
if (!hasDeprecatedComment(field) || hasDeprecatedAnnotation(field)) {
return;
if (hasDeprecatedAnnotation(field)) {
if (warnOnMissingJavadoc && !hasDeprecatedComment(field, true)) {
registerFieldError(field, Boolean.FALSE);
}
}
else if (hasDeprecatedComment(field, false)) {
registerFieldError(field, Boolean.TRUE);
}
registerFieldError(field);
}
private static boolean hasDeprecatedAnnotation(PsiModifierListOwner element) {
private boolean hasDeprecatedAnnotation(PsiModifierListOwner element) {
final PsiModifierList modifierList = element.getModifierList();
if (modifierList == null) {
return false;
}
final PsiAnnotation annotation = modifierList.findAnnotation(CommonClassNames.JAVA_LANG_DEPRECATED);
return annotation != null;
return modifierList != null && modifierList.findAnnotation(CommonClassNames.JAVA_LANG_DEPRECATED) != null;
}
private static boolean hasDeprecatedComment(PsiDocCommentOwner element) {
private boolean hasDeprecatedComment(PsiDocCommentOwner element, boolean checkContent) {
final PsiDocComment comment = element.getDocComment();
if (comment == null) {
return false;
}
final PsiDocTag deprecatedTag = comment.findTagByName("deprecated");
return deprecatedTag != null;
if (deprecatedTag == null) {
return false;
}
return !checkContent || deprecatedTag.getValueElement() != null;
}
}
}
@@ -7,6 +7,9 @@ This inspection only reports if the project or module is configured to use a
language level of 5.0 or higher.
<!-- tooltip end -->
<p>
Use the checkbox below to warn on symbols annotated with <b>@Deprecated</b> without a corresponding explanation in a
<b>@deprecated</b> Javadoc tag.
<p>
</body>
</html>
@@ -0,0 +1,37 @@
/**
* @deprecated
*/
public class <warning descr="Missing '@Deprecated' annotation">MissingDeprecatedAnnotation</warning> {
/**
* @deprecated Use {@link #b()} instead
*/
@Deprecated
void a() {}
/**
* @deprecated
*/
void <warning descr="Missing '@Deprecated' annotation">b</warning>() {}
/**
* @deprecated
*/
String <warning descr="Missing '@Deprecated' annotation">s</warning>;
}
@Deprecated
class <warning descr="Missing '@deprecated' Javadoc tag explanation">Two</warning> {
/**
* @deprecated
*/
@Deprecated
void <warning descr="Missing '@deprecated' Javadoc tag explanation">a</warning>() {}
@Deprecated
void <warning descr="Missing '@deprecated' Javadoc tag explanation">b</warning>() {}
@Deprecated
String <warning descr="Missing '@deprecated' Javadoc tag explanation">s</warning>;
}
@@ -0,0 +1,39 @@
/*
* Copyright 2000-2014 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 com.siyeh.ig.javadoc;
import com.intellij.codeInspection.InspectionProfileEntry;
import com.siyeh.ig.LightInspectionTestCase;
import junit.framework.TestCase;
import org.jetbrains.annotations.Nullable;
/**
* @author Bas Leijdekkers
*/
public class MissingDeprecatedAnnotationInspectionTest extends LightInspectionTestCase {
public void testMissingDeprecatedAnnotation() {
doTest();
}
@Nullable
@Override
protected InspectionProfileEntry getInspection() {
final MissingDeprecatedAnnotationInspection inspection = new MissingDeprecatedAnnotationInspection();
inspection.warnOnMissingJavadoc = true;
return inspection;
}
}