Skip to content

Commit

Permalink
Issue checkstyle#4983: convert MissingDeprecatedCheck to use javadoc …
Browse files Browse the repository at this point in the history
…parser
  • Loading branch information
rnveach committed Aug 4, 2019
1 parent ace12fe commit 3c39ca9
Show file tree
Hide file tree
Showing 15 changed files with 182 additions and 175 deletions.
Expand Up @@ -19,17 +19,14 @@

package com.puppycrawl.tools.checkstyle.checks.annotation;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.puppycrawl.tools.checkstyle.StatelessCheck;
import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
import com.puppycrawl.tools.checkstyle.api.DetailAST;
import com.puppycrawl.tools.checkstyle.api.TextBlock;
import com.puppycrawl.tools.checkstyle.api.DetailNode;
import com.puppycrawl.tools.checkstyle.api.JavadocTokenTypes;
import com.puppycrawl.tools.checkstyle.api.TokenTypes;
import com.puppycrawl.tools.checkstyle.checks.javadoc.AbstractJavadocCheck;
import com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocTagInfo;
import com.puppycrawl.tools.checkstyle.utils.AnnotationUtil;
import com.puppycrawl.tools.checkstyle.utils.CommonUtil;

/**
* <p>
Expand All @@ -48,20 +45,35 @@
* </p>
* <p>
* Package deprecation is a exception to the rule of always using the
* javadoc tag and annotation to deprecate. Only the package-info.java
* file can contain a Deprecated annotation and it CANNOT contain
* a deprecated javadoc tag. This is the case with
* Sun's javadoc tool released with JDK 1.6.0_11. As a result, this check
* does not deal with Deprecated packages in any way. <b>No official
* documentation was found confirming this behavior is correct
* (of the javadoc tool).</b>
* javadoc tag and annotation to deprecate. It is not clear if the javadoc
* tool will support it or not as newer versions keep flip flopping on if
* it is supported or will cause an error. The deprecated javadoc tag is
* currently the only way to say why the package is deprecated and what to
* use instead. Until this is resolved, if you don't want to print violations
* on package-info, you can use a
* <a href="https://checkstyle.org/config_filters.html">filter</a> to ignore
* these files until the javadoc tool faithfully supports it. An example
* config using SuppressionSingleFilter is:
* </p>
* <pre>
* &lt;module name="SuppressionSingleFilter"&gt;
* &lt;property name="checks" value="MissingDeprecatedCheck"/&gt;
* &lt;property name="files" value="package-info\.java"/&gt;
* &lt;/module&gt;
* </pre>
* <ul>
* <li>
* Property {@code skipNoJavadoc} - Ignore cases when JavaDoc is missing, but still warns when
* JavaDoc is present but either &#64;deprecated is missing from JavaDoc
* or &#64;Deprecated is missing from the element. Default value is {@code false}.
* </li>
* <li>
* Property {@code violateExecutionOnNonTightHtml} - If turned on, will
* print violations if the Javadoc being examined by this check violates the
* tight html rules defined at
* <a href="writingjavadocchecks.html#Tight-HTML_rules">Tight-HTML Rules</a>.
* Default value is {@code false}.
* </li>
* </ul>
* <p>
* To configure the check:
Expand Down Expand Up @@ -97,7 +109,7 @@
* @since 5.0
*/
@StatelessCheck
public final class MissingDeprecatedCheck extends AbstractCheck {
public final class MissingDeprecatedCheck extends AbstractJavadocCheck {

/**
* A key is pointing to the warning message text in "messages.properties"
Expand All @@ -113,156 +125,98 @@ public final class MissingDeprecatedCheck extends AbstractCheck {
public static final String MSG_KEY_JAVADOC_DUPLICATE_TAG =
"javadoc.duplicateTag";

/**
* A key is pointing to the warning message text in "messages.properties"
* file.
*/
public static final String MSG_KEY_JAVADOC_MISSING = "javadoc.missing";

/** {@link Deprecated Deprecated} annotation name. */
private static final String DEPRECATED = "Deprecated";

/** Fully-qualified {@link Deprecated Deprecated} annotation name. */
private static final String FQ_DEPRECATED = "java.lang." + DEPRECATED;

/** Compiled regexp to match Javadoc tag with no argument. */
private static final Pattern MATCH_DEPRECATED =
CommonUtil.createPattern("@(deprecated)\\s+\\S");

/** Compiled regexp to match first part of multilineJavadoc tags. */
private static final Pattern MATCH_DEPRECATED_MULTILINE_START =
CommonUtil.createPattern("@(deprecated)\\s*$");

/** Compiled regexp to look for a continuation of the comment. */
private static final Pattern MATCH_DEPRECATED_MULTILINE_CONT =
CommonUtil.createPattern("(\\*/|@|[^\\s\\*])");

/** Multiline finished at end of comment. */
private static final String END_JAVADOC = "*/";
/** Multiline finished at next Javadoc. */
private static final String NEXT_TAG = "@";

/**
* Ignore cases when JavaDoc is missing, but still warns when JavaDoc is present but either
* &#64;deprecated is missing from JavaDoc or &#64;Deprecated is missing from the element.
*/
private boolean skipNoJavadoc;

/**
* Setter to ignore cases when JavaDoc is missing, but still warns when JavaDoc is present
* but either &#64;deprecated is missing from JavaDoc or &#64;Deprecated is missing
* from the element.
* @param skipNoJavadoc user's value of skipJavadoc
* @deprecated No longer valid from switch to javadoc parser.
*/
@Deprecated
public void setSkipNoJavadoc(boolean skipNoJavadoc) {
this.skipNoJavadoc = skipNoJavadoc;
// does nothing
}

@Override
public int[] getDefaultTokens() {
return getRequiredTokens();
}

@Override
public int[] getAcceptableTokens() {
return getRequiredTokens();
public int[] getDefaultJavadocTokens() {
return new int[] {
JavadocTokenTypes.JAVADOC,
};
}

@Override
public int[] getRequiredTokens() {
return new int[] {
TokenTypes.INTERFACE_DEF,
TokenTypes.CLASS_DEF,
TokenTypes.ANNOTATION_DEF,
TokenTypes.ENUM_DEF,
TokenTypes.METHOD_DEF,
TokenTypes.CTOR_DEF,
TokenTypes.VARIABLE_DEF,
TokenTypes.ENUM_CONSTANT_DEF,
TokenTypes.ANNOTATION_FIELD_DEF,
};
public int[] getRequiredJavadocTokens() {
return getAcceptableJavadocTokens();
}

@Override
public void visitToken(final DetailAST ast) {
final TextBlock javadoc =
getFileContents().getJavadocBefore(ast.getLineNo());
public void visitJavadocToken(DetailNode ast) {
final DetailAST parentAst = getParent(getBlockCommentAst());

final boolean containsAnnotation =
AnnotationUtil.containsAnnotation(ast, DEPRECATED)
|| AnnotationUtil.containsAnnotation(ast, FQ_DEPRECATED);
AnnotationUtil.containsAnnotation(parentAst, DEPRECATED)
|| AnnotationUtil.containsAnnotation(parentAst, FQ_DEPRECATED);

final boolean containsJavadocTag = containsJavadocTag(javadoc);
final boolean containsJavadocTag = containsDeprecatedTag(ast);

if (containsAnnotation ^ containsJavadocTag && !(skipNoJavadoc && javadoc == null)) {
log(ast.getLineNo(), MSG_KEY_ANNOTATION_MISSING_DEPRECATED);
if (containsAnnotation ^ containsJavadocTag) {
log(parentAst.getLineNo(), MSG_KEY_ANNOTATION_MISSING_DEPRECATED);
}
}

/**
* Checks to see if the text block contains a deprecated tag.
* Checks to see if the javadoc contains a deprecated tag.
*
* @param javadoc the javadoc of the AST
* @return true if contains the tag
*/
private boolean containsJavadocTag(final TextBlock javadoc) {
private boolean containsDeprecatedTag(DetailNode javadoc) {
boolean found = false;
if (javadoc != null) {
final String[] lines = javadoc.getText();
int currentLine = javadoc.getStartLineNo() - 1;

for (int i = 0; i < lines.length; i++) {
currentLine++;
final String line = lines[i];

final Matcher javadocNoArgMatcher = MATCH_DEPRECATED.matcher(line);
final Matcher noArgMultilineStart = MATCH_DEPRECATED_MULTILINE_START.matcher(line);

if (javadocNoArgMatcher.find()) {
if (found) {
log(currentLine, MSG_KEY_JAVADOC_DUPLICATE_TAG,
JavadocTagInfo.DEPRECATED.getText());
}
found = true;
}
else if (noArgMultilineStart.find()) {
checkTagAtTheRestOfComment(lines, found, currentLine, i);
found = true;
for (DetailNode child : javadoc.getChildren()) {
if (child.getType() == JavadocTokenTypes.JAVADOC_TAG
&& child.getChildren()[0].getType() == JavadocTokenTypes.DEPRECATED_LITERAL) {
if (found) {
log(child.getLineNumber(), MSG_KEY_JAVADOC_DUPLICATE_TAG,
JavadocTagInfo.DEPRECATED.getText());
}
found = true;
}
}
return found;
}

/**
* Look for the rest of the comment if all we saw was
* the tag and the name. Stop when we see '*' (end of
* Javadoc), '{@literal @}' (start of next tag), or anything that's
* not whitespace or '*' characters.
* @param lines all lines
* @param foundBefore flag from parent method
* @param currentLine current line
* @param index som index
* Returns the parent node of the comment.
* @param commentBlock child node.
* @return parent node.
*/
private void checkTagAtTheRestOfComment(String[] lines, boolean foundBefore,
int currentLine, int index) {
int reindex = index + 1;
while (reindex <= lines.length - 1) {
final Matcher multilineCont = MATCH_DEPRECATED_MULTILINE_CONT.matcher(lines[reindex]);
private static DetailAST getParent(DetailAST commentBlock) {
DetailAST result = commentBlock.getParent();

if (multilineCont.find()) {
reindex = lines.length;
final String lFin = multilineCont.group(1);
if (lFin.equals(NEXT_TAG) || lFin.equals(END_JAVADOC)) {
log(currentLine, MSG_KEY_JAVADOC_MISSING);
}
if (foundBefore) {
log(currentLine, MSG_KEY_JAVADOC_DUPLICATE_TAG,
JavadocTagInfo.DEPRECATED.getText());
}
if (result == null) {
result = commentBlock.getNextSibling();
}

while (true) {
final int type = result.getType();
if (type == TokenTypes.TYPE || type == TokenTypes.MODIFIERS
|| type == TokenTypes.ANNOTATION || type == TokenTypes.ANNOTATIONS
|| type == TokenTypes.ARRAY_DECLARATOR || type == TokenTypes.TYPE_PARAMETERS
|| type == TokenTypes.DOT) {
result = result.getParent();
}
else {
break;
}
reindex++;
}

return result;
}

}
Expand Up @@ -10,7 +10,9 @@ annotation.same.line=Annotation ''{0}'' should be on the same line with its targ
annotation.trailing.comma.missing=Annotation array values must contain trailing comma.
annotation.trailing.comma.present=Annotation array values cannot contain trailing comma.
javadoc.duplicateTag=Duplicate {0} tag.
javadoc.missing=Missing a Javadoc comment.
javadoc.missed.html.close=Javadoc comment at column {0} has parse error. Missed HTML close tag ''{1}''. Sometimes it means that close tag missed for one of previous tags.
javadoc.parse.rule.error=Javadoc comment at column {0} has parse error. Details: {1} while parsing {2}
javadoc.wrong.singleton.html.tag=Javadoc comment at column {0} has parse error. It is forbidden to close singleton HTML tags. Tag: {1}.
suppressed.warning.not.allowed=The warning ''{0}'' cannot be suppressed at this location.
tag.not.valid.on=The Javadoc {0} tag is not valid at this location.

Expand Up @@ -10,6 +10,8 @@ annotation.same.line=Annotation ''{0}'' sollte in der gleichen Zeile wie ihr Zie
annotation.trailing.comma.missing=Annotation-Array-Werte müssen mit einem Komma abgeschlossen werden.
annotation.trailing.comma.present=Annotation-Array-Werte dürfen nicht mit einem Komma abgeschlossen werden.
javadoc.duplicateTag=Das Javadoc-Tag {0} ist doppelt.
javadoc.missing=Es fehlt ein Javadoc-Kommentar.
javadoc.missed.html.close=Der Javadoc-Kommentar an Position {0} führt zu einem Parserfehler. Fehlendes schließendes HTML-Tag ''{1}''. Manchmal bedeutet dies, dass das schließende Tag eines vorgehenden Tags fehlt.
javadoc.parse.rule.error=Der Javadoc-Kommentar an Position {0} führt zu einem Parserfehler. Details: {1} beim Parsen von {2}
javadoc.wrong.singleton.html.tag=Der Javadoc-Kommentar an Position {0} führt zu einem Parserfehler. Singleton-HTML-Tags dürfen nicht geschlossen werden. Tag: {1}
suppressed.warning.not.allowed=Die Warnung ''{0}'' darf an dieser Stelle nicht unterdrückt werden.
tag.not.valid.on=Das Javadoc-Tag {0} ist an dieser Stelle nicht zulässig.
Expand Up @@ -10,7 +10,9 @@ annotation.same.line=La anotación ''{0}'' debe estar en la misma línea con su
annotation.trailing.comma.missing=Valores de la matriz de anotación deben contener trailing coma.
annotation.trailing.comma.present=Valores de la matriz de anotación no pueden contener trailing coma.
javadoc.duplicateTag=Duplicar {0} etiqueta.
javadoc.missing=Falta un comentario Javadoc.
javadoc.missed.html.close=Javadoc comentario en la columna {0} tiene parse error. Perdidas HTML cerca etiqueta ''{1}''. A veces esto significa que cerca de la etiqueta se perdió por una de las etiquetas anteriores.
javadoc.parse.rule.error=Javadoc comentario en la columna {0} tiene parse error. Detalles: {1} al analizar {2}
javadoc.wrong.singleton.html.tag=Javadoc comentario en la columna {0} tiene parse error. Está prohibido cerrar etiquetas HTML únicos. Tag: {1}
suppressed.warning.not.allowed=La advertencia ''{0}'' no se puede suprimir en este lugar.
tag.not.valid.on=El Javadoc {0} etiqueta no es válido en este lugar.

Expand Up @@ -10,6 +10,8 @@ annotation.same.line=Lisäykset ''{0}'' pitäisi olla samalla linjalla sen tavoi
annotation.trailing.comma.missing=Lisäykset array arvot saa olla perään pilkulla.
annotation.trailing.comma.present=Annotation array arvot voi sisältää perään pilkulla.
javadoc.duplicateTag=Monista {0} tunniste.
javadoc.missing=Puuttuvat Javadoc kommentti.
javadoc.missed.html.close=Javadoc kommentti sarakkeessa {0} on Jäsennysvirhe. Missed HTML lähellä tag ''{1}''. Joskus se tarkoittaa, että lähellä tag jäi yhden edellisen tunnisteita.
javadoc.parse.rule.error=Javadoc kommentti sarakkeessa {0} on Jäsennysvirhe. Tiedot: {1} jäsennettäessä {2}
javadoc.wrong.singleton.html.tag=Javadoc kommentti sarakkeessa {0} on Jäsennysvirhe. On kiellettyä sulkea yksittäiseksi HTML tageja. Tag: {1} .
suppressed.warning.not.allowed=Varoitus ''{0}'' ei voi estää tässä paikassa.
tag.not.valid.on=Javadoc {0} tunniste ei kelpaa tässä paikassa.
Expand Up @@ -10,6 +10,8 @@ annotation.same.line=L''annotation ''{0}'' devrait être sur la même ligne avec
annotation.trailing.comma.missing=Les valeurs de tableau d''annotation doivent contenir une virgule à la fin.
annotation.trailing.comma.present=Les valeurs de tableau d''annotation ne peuvent pas contenir une virgule à la fin.
javadoc.duplicateTag=Balise {0} dupliquée.
javadoc.missing=Commentaire Javadoc manquant.
javadoc.missed.html.close=Le commentaire Javadoc à la colonne {0} ne peut être analysé. La balise HTML fermante ''{1}'' n''a pas été trouvée. Parfois, cela signifie qu''une des balises fermantes précédentes est manquante.
javadoc.parse.rule.error=Le commentaire Javadoc à la colonne {0} ne peut être analysé. Détails : {1} lors de l''analyse {2}
javadoc.wrong.singleton.html.tag=Le commentaire Javadoc à la colonne {0} ne peut être analysé. Il est interdit de fermer les balises HTML singleton. Balise : {1}
suppressed.warning.not.allowed=L''avertissement ''{0}'' ne peut pas être supprimé à cet endroit.
tag.not.valid.on=La balise Javadoc {0} n''est pas valide à cet endroit.
Expand Up @@ -10,6 +10,8 @@ annotation.same.line=注釈 ''{0}'' はそのターゲットと同じ行にな
annotation.trailing.comma.missing=アノテーションの配列値には末尾にカンマをつけてください。
annotation.trailing.comma.present=アノテーションの配列値には末尾にカンマをつけないでください。
javadoc.duplicateTag={0}タグが重複しています。
javadoc.missing=Javadoc コメントがありません。
javadoc.missed.html.close={0} 桁目の Javadoc コメントでパースエラーが発生しました。HTML タグ ''{1}'' が閉じていません。どこかもっと前のタグが閉じていない可能性もあります。
javadoc.parse.rule.error={0} 桁目の Javadoc コメントでパースエラーが発生しました。詳細: {1}、{2} の解析中に発生。
javadoc.wrong.singleton.html.tag={0} 桁目の Javadoc コメントでパースエラーが発生しました。空要素の閉じタグは禁止されています。タグ: {1}。
suppressed.warning.not.allowed=この場所で、警告 ''{0}'' を抑制することはできません。
tag.not.valid.on=この場所で、Javadoc の{0}タグは有効ではありません。
Expand Up @@ -10,6 +10,8 @@ annotation.same.line=A anotação ''{0}'' deveria estar na mesma linha do elemen
annotation.trailing.comma.missing=A lista de valores de um array de anotações deveria ser terminada em uma vírgula.
annotation.trailing.comma.present=A lista de valores de um array de anotações não deveria ser terminada em uma vírgula.
javadoc.duplicateTag=A tag {0} não deveria ser duplicada.
javadoc.missing=Um comentário Javadoc está faltando.
javadoc.missed.html.close=O comentário de Javadoc na coluna {0} tem erro sintático. Faltou uma etiqueta de fechamento HTML ''{1}''. Às vezes, isso significa que uma etiqueta de fechamento foi esquecida em uma das etiquetas HTML anteriores.
javadoc.parse.rule.error=O comentário Javadoc na coluna {0} tem um erro sintático. Detalhes: {1} ao analisar {2}
javadoc.wrong.singleton.html.tag=O comentário Javadoc na coluna {0} tem um erro sintático. É proibido fechar etiquetas HTML auto-fechantes. Tag: {1}.
suppressed.warning.not.allowed=A advertência ''{0}'' não pode ser suprimida neste local.
tag.not.valid.on=A tag Javadoc {0} não pode ser usada neste local.
Expand Up @@ -11,6 +11,8 @@ annotation.same.line=Ek açıklama ''{0}'' hedefi ile aynı hizada olmalıdır.
annotation.trailing.comma.missing=Anotasyonun dizi değerlerini takip eden bir virg\u00FCl kullanılmalıdır.
annotation.trailing.comma.present=Anotasyonun dizi değerlerini takip eden bir virg\u00FCl kullanılmamalıdır.
javadoc.duplicateTag=Tekrarlanmış {0} etiketi.
javadoc.missing=Javadoc açıklaması eksik.
javadoc.missed.html.close=Sütununda Javadoc comment {0} hatası ayrıştırmak vardır. Cevapsız HTML yakın etiketi ''{1}'' Bazen yakın etiketi önceki etiketler biri için kaçırmış demektir.
javadoc.parse.rule.error=Sütununda Javadoc comment {0} hatası ayrıştırmak vardır. Detaylar: {1} ayrıştırılırken {2}
javadoc.wrong.singleton.html.tag=Sütununda Javadoc comment {0} hatası ayrıştırmak vardır. Bu singleton HTML etiketleri kapatmak için yasaktır. Etiket: {1}
suppressed.warning.not.allowed=''{0}'' uyarısı bu konumda bastırılamaz.
tag.not.valid.on={0} Javadoc etiketi bu konumda geçersiz.

0 comments on commit 3c39ca9

Please sign in to comment.