aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPiyush Sharma <ps26oct@gmail.com>2017-07-13 15:50:03 +0530
committerRoman Ivanov <romani@users.noreply.github.com>2017-09-08 05:40:02 -0700
commit3660e750a3835eaeffec0f5451bee7a5189d0e0f (patch)
treef77ec014d54d9c865a79e06e5dec462e85fc8939
parentc31bffe59c342dd5fdcfc8f55ca339b3520eef3e (diff)
downloadcheckstyle-3660e750a3835eaeffec0f5451bee7a5189d0e0f.tar.gz
Issue #3311: Modified javadoc grammar, JavadocDetailNodeParser, AbstractJavadocCheck to enable selective processing of javadoc with non tight HTML
-rw-r--r--pom.xml8
-rw-r--r--src/main/java/com/puppycrawl/tools/checkstyle/JavadocDetailNodeParser.java81
-rw-r--r--src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/AbstractJavadocCheck.java51
-rw-r--r--src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocStyleCheck.java3
-rw-r--r--src/main/resources/com/puppycrawl/tools/checkstyle/grammars/javadoc/JavadocParser.g4612
-rw-r--r--src/test/java/com/puppycrawl/tools/checkstyle/checks/javadoc/AbstractJavadocCheckTest.java165
-rw-r--r--src/test/resources/com/puppycrawl/tools/checkstyle/checks/javadoc/abstractjavadoc/InputAbstractJavadocNonTightHtmlTags.java129
-rw-r--r--src/test/resources/com/puppycrawl/tools/checkstyle/checks/javadoc/abstractjavadoc/InputAbstractJavadocNonTightHtmlTags2.java90
8 files changed, 866 insertions, 273 deletions
diff --git a/pom.xml b/pom.xml
index 156875225..08b018112 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1577,13 +1577,13 @@
</regex>
<regex>
<pattern>com.puppycrawl.tools.checkstyle.grammars.javadoc.JavadocParser</pattern>
- <branchRate>37</branchRate>
- <lineRate>48</lineRate>
+ <branchRate>42</branchRate>
+ <lineRate>53</lineRate>
</regex>
<regex>
<pattern>com.puppycrawl.tools.checkstyle.grammars.javadoc.JavadocLexer</pattern>
- <branchRate>63</branchRate>
- <lineRate>83</lineRate>
+ <branchRate>64</branchRate>
+ <lineRate>84</lineRate>
</regex>
</regexes>
</check>
diff --git a/src/main/java/com/puppycrawl/tools/checkstyle/JavadocDetailNodeParser.java b/src/main/java/com/puppycrawl/tools/checkstyle/JavadocDetailNodeParser.java
index 8ba390496..d5df6e786 100644
--- a/src/main/java/com/puppycrawl/tools/checkstyle/JavadocDetailNodeParser.java
+++ b/src/main/java/com/puppycrawl/tools/checkstyle/JavadocDetailNodeParser.java
@@ -27,6 +27,7 @@ import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.BailErrorStrategy;
import org.antlr.v4.runtime.BaseErrorListener;
import org.antlr.v4.runtime.BufferedTokenStream;
+import org.antlr.v4.runtime.CommonToken;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.FailedPredicateException;
import org.antlr.v4.runtime.InputMismatchException;
@@ -82,6 +83,11 @@ public class JavadocDetailNodeParser {
*/
public static final String MSG_KEY_PARSE_ERROR = "javadoc.parse.error";
+ /**
+ * Message property key for the Unclosed HTML message.
+ */
+ public static final String MSG_UNCLOSED_HTML_TAG = "javadoc.unclosedHtml";
+
/** Symbols with which javadoc starts. */
private static final String JAVADOC_START = "/**";
@@ -119,14 +125,17 @@ public class JavadocDetailNodeParser {
final ParseStatus result = new ParseStatus();
try {
- final ParseTree parseTree = parseJavadocAsParseTree(javadocComment);
+ final JavadocParser javadocParser = createJavadocParser(javadocComment);
+
+ final ParseTree javadocParseTree = javadocParser.javadoc();
- final DetailNode tree = convertParseTreeToDetailNode(parseTree);
+ final DetailNode tree = convertParseTreeToDetailNode(javadocParseTree);
// adjust first line to indent of /**
adjustFirstLineToJavadocIndent(tree,
javadocCommentAst.getColumnNo()
+ JAVADOC_START.length());
result.setTree(tree);
+ result.firstNonTightHtmlTag = getFirstNonTightHtmlTag(javadocParser);
}
catch (ParseCancellationException | IllegalArgumentException ex) {
ParseErrorMessage parseErrorMessage = null;
@@ -164,7 +173,7 @@ public class JavadocDetailNodeParser {
* @return parse tree
* @noinspection deprecation
*/
- private ParseTree parseJavadocAsParseTree(String blockComment) {
+ private JavadocParser createJavadocParser(String blockComment) {
final ANTLRInputStream input = new ANTLRInputStream(blockComment);
final JavadocLexer lexer = new JavadocLexer(input);
@@ -179,11 +188,11 @@ public class JavadocDetailNodeParser {
// add custom error listener that logs syntax errors
parser.addErrorListener(errorListener);
- // This strategy stops parsing when parser error occurs.
- // By default it uses Error Recover Strategy which is slow and useless.
+ // JavadocParserErrorStrategy stops parsing on first parse error encountered unlike the
+ // DefaultErrorStrategy used by ANTLR which rather attempts error recovery.
parser.setErrorHandler(new JavadocParserErrorStrategy());
- return parser.javadoc();
+ return parser;
}
/**
@@ -503,6 +512,31 @@ public class JavadocDetailNodeParser {
}
/**
+ * This method is used to get the first non-tight HTML tag encountered while parsing javadoc.
+ * This shall eventually be reflected by the {@link ParseStatus} object returned by
+ * {@link #parseJavadocAsDetailNode(DetailAST)} method via the instance member
+ * {@link ParseStatus#firstNonTightHtmlTag}, and checks not supposed to process non-tight HTML
+ * or the ones which are supposed to log violation for non-tight javadocs can utilize that.
+ *
+ * @param javadocParser The ANTLR recognizer instance which has been used to parse the javadoc
+ * @return First non-tight HTML tag if one exists; null otherwise
+ */
+ private Token getFirstNonTightHtmlTag(JavadocParser javadocParser) {
+ final CommonToken offendingToken;
+ final ParserRuleContext nonTightTagStartContext = javadocParser.nonTightTagStartContext;
+ if (nonTightTagStartContext == null) {
+ offendingToken = null;
+ }
+ else {
+ final Token token = ((TerminalNode) nonTightTagStartContext.getChild(1))
+ .getSymbol();
+ offendingToken = new CommonToken(token);
+ offendingToken.setLine(offendingToken.getLine() + errorListener.offset);
+ }
+ return offendingToken;
+ }
+
+ /**
* Custom error listener for JavadocParser that prints user readable errors.
*/
private static class DescriptiveErrorListener extends BaseErrorListener {
@@ -590,6 +624,15 @@ public class JavadocDetailNodeParser {
private ParseErrorMessage parseErrorMessage;
/**
+ * Stores the first non-tight HTML tag encountered while parsing javadoc.
+ *
+ * @see <a
+ * href="http://checkstyle.sourceforge.net/writingjavadocchecks.html#Tight-HTML_rules">
+ * Tight HTML rules</a>
+ */
+ private Token firstNonTightHtmlTag;
+
+ /**
* Getter for DetailNode tree.
* @return DetailNode tree if parsing was successful, null otherwise.
*/
@@ -621,6 +664,28 @@ public class JavadocDetailNodeParser {
this.parseErrorMessage = parseErrorMessage;
}
+ /**
+ * This method is used to check if the javadoc parsed has non-tight HTML tags.
+ *
+ * @return returns true if the javadoc has at least one non-tight HTML tag; false otherwise
+ * @see <a
+ * href="http://checkstyle.sourceforge.net/writingjavadocchecks.html#Tight-HTML_rules">
+ * Tight HTML rules</a>
+ */
+ public boolean isNonTight() {
+ return firstNonTightHtmlTag != null;
+ }
+
+ /**
+ * Getter for {@link #firstNonTightHtmlTag}.
+ *
+ * @return the first non-tight HTML tag that is encountered while parsing Javadoc,
+ * if one exists
+ */
+ public Token getFirstNonTightHtmlTag() {
+ return firstNonTightHtmlTag;
+ }
+
}
/**
@@ -681,6 +746,10 @@ public class JavadocDetailNodeParser {
}
/**
+ * The DefaultErrorStrategy used by ANTLR attempts to recover from parse errors
+ * which might result in a performance overhead. Also, a parse error indicate
+ * that javadoc doesn't follow checkstyle Javadoc grammar and the user should be made aware
+ * of it.
* <a href="http://www.antlr.org/api/Java/org/antlr/v4/runtime/BailErrorStrategy.html">
* BailErrorStrategy</a> is used to make ANTLR generated parser bail out on the first error
* in parser and not attempt any recovery methods but it doesn't report error to the
diff --git a/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/AbstractJavadocCheck.java b/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/AbstractJavadocCheck.java
index bf87d3503..4e9575ca3 100644
--- a/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/AbstractJavadocCheck.java
+++ b/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/AbstractJavadocCheck.java
@@ -88,6 +88,19 @@ public abstract class AbstractJavadocCheck extends AbstractCheck {
private final Set<Integer> javadocTokens = new HashSet<>();
/**
+ * This property determines if a check should log a violation upon encountering javadoc with
+ * non-tight html. The default return value for this method is set to false since checks
+ * generally tend to be fine with non tight html. It can be set through config file if a check
+ * is to log violation upon encountering non-tight HTML in javadoc.
+ *
+ * @see ParseStatus#firstNonTightHtmlTag
+ * @see ParseStatus#isNonTight()
+ * @see <a href="http://checkstyle.sourceforge.net/writingjavadocchecks.html#Tight-HTML_rules">
+ * Tight HTML rules</a>
+ */
+ private boolean violateExecutionOnNonTightHtml;
+
+ /**
* Returns the default javadoc token types a check is interested in.
* @return the default javadoc token types
* @see JavadocTokenTypes
@@ -126,6 +139,31 @@ public abstract class AbstractJavadocCheck extends AbstractCheck {
}
/**
+ * This method determines if a check should process javadoc containing non-tight html tags.
+ * This method must be overridden in checks extending {@code AbstractJavadocCheck} which
+ * are not supposed to process javadoc containing non-tight html tags.
+ *
+ * @return true if the check should or can process javadoc containing non-tight html tags;
+ * false otherwise
+ * @see ParseStatus#isNonTight()
+ * @see <a href="http://checkstyle.sourceforge.net/writingjavadocchecks.html#Tight-HTML_rules">
+ * Tight HTML rules</a>
+ */
+ public boolean acceptJavadocWithNonTightHtml() {
+ return true;
+ }
+
+ /**
+ * Setter for {@link #violateExecutionOnNonTightHtml}.
+ * @param shouldReportViolation value to which the field shall be set to
+ * @see <a href="http://checkstyle.sourceforge.net/writingjavadocchecks.html#Tight-HTML_rules">
+ * Tight HTML rules</a>
+ */
+ public final void setViolateExecutionOnNonTightHtml(boolean shouldReportViolation) {
+ violateExecutionOnNonTightHtml = shouldReportViolation;
+ }
+
+ /**
* Adds a set of tokens the check is interested in.
* @param strRep the string representation of the tokens interested in
*/
@@ -261,12 +299,21 @@ public abstract class AbstractJavadocCheck extends AbstractCheck {
result = TREE_CACHE.get().get(treeCacheKey);
}
else {
- result = context.get().parser.parseJavadocAsDetailNode(blockCommentNode);
+ result = context.get().parser
+ .parseJavadocAsDetailNode(blockCommentNode);
TREE_CACHE.get().put(treeCacheKey, result);
}
if (result.getParseErrorMessage() == null) {
- processTree(result.getTree());
+ if (acceptJavadocWithNonTightHtml() || !result.isNonTight()) {
+ processTree(result.getTree());
+ }
+
+ if (violateExecutionOnNonTightHtml && result.isNonTight()) {
+ log(result.getFirstNonTightHtmlTag().getLine(),
+ JavadocDetailNodeParser.MSG_UNCLOSED_HTML_TAG,
+ result.getFirstNonTightHtmlTag().getText());
+ }
}
else {
final ParseErrorMessage parseErrorMessage = result.getParseErrorMessage();
diff --git a/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocStyleCheck.java b/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocStyleCheck.java
index 0da1de8f4..198723dbc 100644
--- a/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocStyleCheck.java
+++ b/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocStyleCheck.java
@@ -30,6 +30,7 @@ import java.util.TreeSet;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
+import com.puppycrawl.tools.checkstyle.JavadocDetailNodeParser;
import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
import com.puppycrawl.tools.checkstyle.api.DetailAST;
import com.puppycrawl.tools.checkstyle.api.FileContents;
@@ -63,7 +64,7 @@ public class JavadocStyleCheck
public static final String MSG_INCOMPLETE_TAG = "javadoc.incompleteTag";
/** Message property key for the Unclosed HTML message. */
- public static final String MSG_UNCLOSED_HTML = "javadoc.unclosedHtml";
+ public static final String MSG_UNCLOSED_HTML = JavadocDetailNodeParser.MSG_UNCLOSED_HTML_TAG;
/** Message property key for the Extra HTML message. */
public static final String MSG_EXTRA_HTML = "javadoc.extraHtml";
diff --git a/src/main/resources/com/puppycrawl/tools/checkstyle/grammars/javadoc/JavadocParser.g4 b/src/main/resources/com/puppycrawl/tools/checkstyle/grammars/javadoc/JavadocParser.g4
index 1baa520ae..94d70301e 100644
--- a/src/main/resources/com/puppycrawl/tools/checkstyle/grammars/javadoc/JavadocParser.g4
+++ b/src/main/resources/com/puppycrawl/tools/checkstyle/grammars/javadoc/JavadocParser.g4
@@ -31,11 +31,13 @@ options { tokenVocab=JavadocLexer; }
}
}
- boolean isSameTagNames(ParserRuleContext htmlTagStart, ParserRuleContext htmlTagEnd) {
- String startTag = htmlTagStart.getToken(HTML_TAG_NAME, 0).getText().toLowerCase();
- String endTag = htmlTagEnd.getToken(HTML_TAG_NAME, 0).getText().toLowerCase();
- return startTag.equals(endTag);
- }
+ boolean isSameTagNames(ParserRuleContext htmlTagStart, ParserRuleContext htmlTagEnd) {
+ String startTag = htmlTagStart.getToken(HTML_TAG_NAME, 0).getText().toLowerCase();
+ String endTag = htmlTagEnd.getToken(HTML_TAG_NAME, 0).getText().toLowerCase();
+ return startTag.equals(endTag);
+ }
+
+ public ParserRuleContext nonTightTagStartContext;
}
javadoc: (
@@ -68,21 +70,21 @@ htmlElement: htmlTag
| thead
| tfoot
- | pTagStart
- | liTagStart
- | trTagStart
- | tdTagStart
- | thTagStart
- | bodyTagStart
- | colgroupTagStart
- | ddTagStart
- | dtTagStart
- | headTagStart
- | htmlTagStart
- | optionTagStart
- | tbodyTagStart
- | theadTagStart
- | tfootTagStart
+ | pTagStart[true]
+ | liTagStart[true]
+ | trTagStart[true]
+ | tdTagStart[true]
+ | thTagStart[true]
+ | bodyTagStart[true]
+ | colgroupTagStart[true]
+ | ddTagStart[true]
+ | dtTagStart[true]
+ | headTagStart[true]
+ | htmlTagStart[true]
+ | optionTagStart[true]
+ | tbodyTagStart[true]
+ | theadTagStart[true]
+ | tfootTagStart[true]
| pTagEnd
| liTagEnd
@@ -120,9 +122,15 @@ htmlTag: htmlElementStart (htmlElement
//////////////////////////////////////////////////////////////////////////////////////
//////////////////// HTML TAGS WITH OPTIONAL END TAG ////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////
-pTagStart: START P_HTML_TAG_NAME (attribute | NEWLINE | LEADING_ASTERISK | WS)* END;
+pTagStart[boolean isNonTight]
+@after {
+ if (isNonTight && nonTightTagStartContext == null) {
+ nonTightTagStartContext = _localctx;
+ }
+}
+ : START P_HTML_TAG_NAME (attribute | NEWLINE | LEADING_ASTERISK | WS)* END;
pTagEnd: START SLASH P_HTML_TAG_NAME (NEWLINE | LEADING_ASTERISK | WS)* END;
-paragraph: pTagStart
+paragraph: pTagStart[false]
(htmlTag
| singletonElement
| li
@@ -139,20 +147,20 @@ paragraph: pTagStart
| tbody
| thead
| tfoot
- | liTagStart
- | trTagStart
- | tdTagStart
- | thTagStart
- | bodyTagStart
- | colgroupTagStart
- | ddTagStart
- | dtTagStart
- | headTagStart
- | htmlTagStart
- | optionTagStart
- | tbodyTagStart
- | theadTagStart
- | tfootTagStart
+ | liTagStart[true]
+ | trTagStart[true]
+ | tdTagStart[true]
+ | thTagStart[true]
+ | bodyTagStart[true]
+ | colgroupTagStart[true]
+ | ddTagStart[true]
+ | dtTagStart[true]
+ | headTagStart[true]
+ | htmlTagStart[true]
+ | optionTagStart[true]
+ | tbodyTagStart[true]
+ | theadTagStart[true]
+ | tfootTagStart[true]
| ({!isNextJavadocTag()}? LEADING_ASTERISK)
| htmlComment
| CDATA
@@ -162,9 +170,15 @@ paragraph: pTagStart
pTagEnd
;
-liTagStart: START LI_HTML_TAG_NAME (attribute | NEWLINE | LEADING_ASTERISK | WS)* END;
+liTagStart[boolean isNonTight]
+@after {
+ if (isNonTight && nonTightTagStartContext == null) {
+ nonTightTagStartContext = _localctx;
+ }
+}
+ : START LI_HTML_TAG_NAME (attribute | NEWLINE | LEADING_ASTERISK | WS)* END;
liTagEnd: START SLASH LI_HTML_TAG_NAME (NEWLINE | LEADING_ASTERISK | WS)* END;
-li: liTagStart
+li: liTagStart[false]
(htmlTag
| singletonElement
| paragraph
@@ -181,20 +195,20 @@ li: liTagStart
| tbody
| thead
| tfoot
- | pTagStart
- | trTagStart
- | tdTagStart
- | thTagStart
- | bodyTagStart
- | colgroupTagStart
- | ddTagStart
- | dtTagStart
- | headTagStart
- | htmlTagStart
- | optionTagStart
- | tbodyTagStart
- | theadTagStart
- | tfootTagStart
+ | pTagStart[true]
+ | trTagStart[true]
+ | tdTagStart[true]
+ | thTagStart[true]
+ | bodyTagStart[true]
+ | colgroupTagStart[true]
+ | ddTagStart[true]
+ | dtTagStart[true]
+ | headTagStart[true]
+ | htmlTagStart[true]
+ | optionTagStart[true]
+ | tbodyTagStart[true]
+ | theadTagStart[true]
+ | tfootTagStart[true]
| ({!isNextJavadocTag()}? LEADING_ASTERISK)
| htmlComment
| CDATA
@@ -204,9 +218,15 @@ li: liTagStart
liTagEnd
;
-trTagStart: START TR_HTML_TAG_NAME (attribute | NEWLINE | LEADING_ASTERISK | WS)* END;
+trTagStart[boolean isNonTight]
+@after {
+ if (isNonTight && nonTightTagStartContext == null) {
+ nonTightTagStartContext = _localctx;
+ }
+}
+ : START TR_HTML_TAG_NAME (attribute | NEWLINE | LEADING_ASTERISK | WS)* END;
trTagEnd: START SLASH TR_HTML_TAG_NAME (NEWLINE | LEADING_ASTERISK | WS)* END;
-tr: trTagStart
+tr: trTagStart[false]
(htmlTag
| singletonElement
| paragraph
@@ -223,20 +243,20 @@ tr: trTagStart
| tbody
| thead
| tfoot
- | pTagStart
- | liTagStart
- | tdTagStart
- | thTagStart
- | bodyTagStart
- | colgroupTagStart
- | ddTagStart
- | dtTagStart
- | headTagStart
- | htmlTagStart
- | optionTagStart
- | tbodyTagStart
- | theadTagStart
- | tfootTagStart
+ | pTagStart[true]
+ | liTagStart[true]
+ | tdTagStart[true]
+ | thTagStart[true]
+ | bodyTagStart[true]
+ | colgroupTagStart[true]
+ | ddTagStart[true]
+ | dtTagStart[true]
+ | headTagStart[true]
+ | htmlTagStart[true]
+ | optionTagStart[true]
+ | tbodyTagStart[true]
+ | theadTagStart[true]
+ | tfootTagStart[true]
| ({!isNextJavadocTag()}? LEADING_ASTERISK)
| htmlComment
| CDATA
@@ -246,9 +266,15 @@ tr: trTagStart
trTagEnd
;
-tdTagStart: START TD_HTML_TAG_NAME (attribute | NEWLINE | LEADING_ASTERISK | WS)* END;
+tdTagStart[boolean isNonTight]
+@after {
+ if (isNonTight && nonTightTagStartContext == null) {
+ nonTightTagStartContext = _localctx;
+ }
+}
+ : START TD_HTML_TAG_NAME (attribute | NEWLINE | LEADING_ASTERISK | WS)* END;
tdTagEnd: START SLASH TD_HTML_TAG_NAME (NEWLINE | LEADING_ASTERISK | WS)* END;
-td: tdTagStart
+td: tdTagStart[false]
(htmlTag
| singletonElement
| paragraph
@@ -265,20 +291,20 @@ td: tdTagStart
| tbody
| thead
| tfoot
- | pTagStart
- | liTagStart
- | tdTagStart
- | thTagStart
- | bodyTagStart
- | colgroupTagStart
- | ddTagStart
- | dtTagStart
- | headTagStart
- | htmlTagStart
- | optionTagStart
- | tbodyTagStart
- | theadTagStart
- | tfootTagStart
+ | pTagStart[true]
+ | liTagStart[true]
+ | tdTagStart[true]
+ | thTagStart[true]
+ | bodyTagStart[true]
+ | colgroupTagStart[true]
+ | ddTagStart[true]
+ | dtTagStart[true]
+ | headTagStart[true]
+ | htmlTagStart[true]
+ | optionTagStart[true]
+ | tbodyTagStart[true]
+ | theadTagStart[true]
+ | tfootTagStart[true]
| ({!isNextJavadocTag()}? LEADING_ASTERISK)
| htmlComment
| CDATA
@@ -288,9 +314,15 @@ td: tdTagStart
tdTagEnd
;
-thTagStart: START TH_HTML_TAG_NAME (attribute | NEWLINE | LEADING_ASTERISK | WS)* END;
+thTagStart[boolean isNonTight]
+@after {
+ if (isNonTight && nonTightTagStartContext == null) {
+ nonTightTagStartContext = _localctx;
+ }
+}
+ : START TH_HTML_TAG_NAME (attribute | NEWLINE | LEADING_ASTERISK | WS)* END;
thTagEnd: START SLASH TH_HTML_TAG_NAME (NEWLINE | LEADING_ASTERISK | WS)* END;
-th: thTagStart
+th: thTagStart[false]
(htmlTag
| singletonElement
| paragraph
@@ -307,20 +339,20 @@ th: thTagStart
| tbody
| thead
| tfoot
- | pTagStart
- | liTagStart
- | trTagStart
- | tdTagStart
- | bodyTagStart
- | colgroupTagStart
- | ddTagStart
- | dtTagStart
- | headTagStart
- | htmlTagStart
- | optionTagStart
- | tbodyTagStart
- | theadTagStart
- | tfootTagStart
+ | pTagStart[true]
+ | liTagStart[true]
+ | trTagStart[true]
+ | tdTagStart[true]
+ | bodyTagStart[true]
+ | colgroupTagStart[true]
+ | ddTagStart[true]
+ | dtTagStart[true]
+ | headTagStart[true]
+ | htmlTagStart[true]
+ | optionTagStart[true]
+ | tbodyTagStart[true]
+ | theadTagStart[true]
+ | tfootTagStart[true]
| ({!isNextJavadocTag()}? LEADING_ASTERISK)
| htmlComment
| CDATA
@@ -330,9 +362,15 @@ th: thTagStart
thTagEnd
;
-bodyTagStart: START BODY_HTML_TAG_NAME (attribute | NEWLINE | LEADING_ASTERISK | WS)* END;
+bodyTagStart[boolean isNonTight]
+@after {
+ if (isNonTight && nonTightTagStartContext == null) {
+ nonTightTagStartContext = _localctx;
+ }
+}
+ : START BODY_HTML_TAG_NAME (attribute | NEWLINE | LEADING_ASTERISK | WS)* END;
bodyTagEnd: START SLASH BODY_HTML_TAG_NAME (NEWLINE | LEADING_ASTERISK | WS)* END;
-body: bodyTagStart
+body: bodyTagStart[false]
(htmlTag
| singletonElement
| paragraph
@@ -349,20 +387,20 @@ body: bodyTagStart
| tbody
| thead
| tfoot
- | pTagStart
- | liTagStart
- | trTagStart
- | tdTagStart
- | thTagStart
- | colgroupTagStart
- | ddTagStart
- | dtTagStart
- | headTagStart
- | htmlTagStart
- | optionTagStart
- | tbodyTagStart
- | theadTagStart
- | tfootTagStart
+ | pTagStart[true]
+ | liTagStart[true]
+ | trTagStart[true]
+ | tdTagStart[true]
+ | thTagStart[true]
+ | colgroupTagStart[true]
+ | ddTagStart[true]
+ | dtTagStart[true]
+ | headTagStart[true]
+ | htmlTagStart[true]
+ | optionTagStart[true]
+ | tbodyTagStart[true]
+ | theadTagStart[true]
+ | tfootTagStart[true]
| ({!isNextJavadocTag()}? LEADING_ASTERISK)
| htmlComment
| CDATA
@@ -372,9 +410,15 @@ body: bodyTagStart
bodyTagEnd
;
-colgroupTagStart: START COLGROUP_HTML_TAG_NAME (attribute | NEWLINE | LEADING_ASTERISK | WS)* END;
+colgroupTagStart[boolean isNonTight]
+@after {
+ if (isNonTight && nonTightTagStartContext == null) {
+ nonTightTagStartContext = _localctx;
+ }
+}
+ : START COLGROUP_HTML_TAG_NAME (attribute | NEWLINE | LEADING_ASTERISK | WS)* END;
colgroupTagEnd: START SLASH COLGROUP_HTML_TAG_NAME (NEWLINE | LEADING_ASTERISK | WS)* END;
-colgroup: colgroupTagStart
+colgroup: colgroupTagStart[false]
(htmlTag
| singletonElement
| paragraph
@@ -391,20 +435,20 @@ colgroup: colgroupTagStart
| tbody
| thead
| tfoot
- | pTagStart
- | liTagStart
- | trTagStart
- | tdTagStart
- | thTagStart
- | bodyTagStart
- | ddTagStart
- | dtTagStart
- | headTagStart
- | htmlTagStart
- | optionTagStart
- | tbodyTagStart
- | theadTagStart
- | tfootTagStart
+ | pTagStart[true]
+ | liTagStart[true]
+ | trTagStart[true]
+ | tdTagStart[true]
+ | thTagStart[true]
+ | bodyTagStart[true]
+ | ddTagStart[true]
+ | dtTagStart[true]
+ | headTagStart[true]
+ | htmlTagStart[true]
+ | optionTagStart[true]
+ | tbodyTagStart[true]
+ | theadTagStart[true]
+ | tfootTagStart[true]
| ({!isNextJavadocTag()}? LEADING_ASTERISK)
| htmlComment
| CDATA
@@ -414,9 +458,15 @@ colgroup: colgroupTagStart
colgroupTagEnd
;
-ddTagStart: START DD_HTML_TAG_NAME (attribute | NEWLINE | LEADING_ASTERISK | WS)* END;
+ddTagStart[boolean isNonTight]
+@after {
+ if (isNonTight && nonTightTagStartContext == null) {
+ nonTightTagStartContext = _localctx;
+ }
+}
+ : START DD_HTML_TAG_NAME (attribute | NEWLINE | LEADING_ASTERISK | WS)* END;
ddTagEnd: START SLASH DD_HTML_TAG_NAME (NEWLINE | LEADING_ASTERISK | WS)* END;
-dd: ddTagStart
+dd: ddTagStart[false]
(htmlTag
| singletonElement
| paragraph
@@ -433,20 +483,20 @@ dd: ddTagStart
| tbody
| thead
| tfoot
- | pTagStart
- | liTagStart
- | trTagStart
- | tdTagStart
- | thTagStart
- | bodyTagStart
- | colgroupTagStart
- | dtTagStart
- | headTagStart
- | htmlTagStart
- | optionTagStart
- | tbodyTagStart
- | theadTagStart
- | tfootTagStart
+ | pTagStart[true]
+ | liTagStart[true]
+ | trTagStart[true]
+ | tdTagStart[true]
+ | thTagStart[true]
+ | bodyTagStart[true]
+ | colgroupTagStart[true]
+ | dtTagStart[true]
+ | headTagStart[true]
+ | htmlTagStart[true]
+ | optionTagStart[true]
+ | tbodyTagStart[true]
+ | theadTagStart[true]
+ | tfootTagStart[true]
| ({!isNextJavadocTag()}? LEADING_ASTERISK)
| htmlComment
| CDATA
@@ -456,9 +506,15 @@ dd: ddTagStart
ddTagEnd
;
-dtTagStart: START DT_HTML_TAG_NAME (attribute | NEWLINE | LEADING_ASTERISK | WS)* END;
+dtTagStart[boolean isNonTight]
+@after {
+ if (isNonTight && nonTightTagStartContext == null) {
+ nonTightTagStartContext = _localctx;
+ }
+}
+ : START DT_HTML_TAG_NAME (attribute | NEWLINE | LEADING_ASTERISK | WS)* END;
dtTagEnd: START SLASH DT_HTML_TAG_NAME (NEWLINE | LEADING_ASTERISK | WS)* END;
-dt: dtTagStart
+dt: dtTagStart[false]
(htmlTag
| singletonElement
| paragraph
@@ -475,20 +531,20 @@ dt: dtTagStart
| tbody
| thead
| tfoot
- | pTagStart
- | liTagStart
- | trTagStart
- | tdTagStart
- | thTagStart
- | bodyTagStart
- | colgroupTagStart
- | ddTagStart
- | headTagStart
- | htmlTagStart
- | optionTagStart
- | tbodyTagStart
- | theadTagStart
- | tfootTagStart
+ | pTagStart[true]
+ | liTagStart[true]
+ | trTagStart[true]
+ | tdTagStart[true]
+ | thTagStart[true]
+ | bodyTagStart[true]
+ | colgroupTagStart[true]
+ | ddTagStart[true]
+ | headTagStart[true]
+ | htmlTagStart[true]
+ | optionTagStart[true]
+ | tbodyTagStart[true]
+ | theadTagStart[true]
+ | tfootTagStart[true]
| ({!isNextJavadocTag()}? LEADING_ASTERISK)
| htmlComment
| CDATA
@@ -498,9 +554,15 @@ dt: dtTagStart
dtTagEnd
;
-headTagStart: START HEAD_HTML_TAG_NAME (attribute | NEWLINE | LEADING_ASTERISK | WS)* END;
+headTagStart[boolean isNonTight]
+@after {
+ if (isNonTight && nonTightTagStartContext == null) {
+ nonTightTagStartContext = _localctx;
+ }
+}
+ : START HEAD_HTML_TAG_NAME (attribute | NEWLINE | LEADING_ASTERISK | WS)* END;
headTagEnd: START SLASH HEAD_HTML_TAG_NAME (NEWLINE | LEADING_ASTERISK | WS)* END;
-head: headTagStart
+head: headTagStart[false]
(htmlTag
| singletonElement
| paragraph
@@ -517,20 +579,20 @@ head: headTagStart
| tbody
| thead
| tfoot
- | pTagStart
- | liTagStart
- | trTagStart
- | tdTagStart
- | thTagStart
- | bodyTagStart
- | colgroupTagStart
- | ddTagStart
- | dtTagStart
- | htmlTagStart
- | optionTagStart
- | tbodyTagStart
- | theadTagStart
- | tfootTagStart
+ | pTagStart[true]
+ | liTagStart[true]
+ | trTagStart[true]
+ | tdTagStart[true]
+ | thTagStart[true]
+ | bodyTagStart[true]
+ | colgroupTagStart[true]
+ | ddTagStart[true]
+ | dtTagStart[true]
+ | htmlTagStart[true]
+ | optionTagStart[true]
+ | tbodyTagStart[true]
+ | theadTagStart[true]
+ | tfootTagStart[true]
| ({!isNextJavadocTag()}? LEADING_ASTERISK)
| htmlComment
| CDATA
@@ -540,9 +602,15 @@ head: headTagStart
headTagEnd
;
-htmlTagStart: START HTML_HTML_TAG_NAME (attribute | NEWLINE | LEADING_ASTERISK | WS)* END;
+htmlTagStart[boolean isNonTight]
+@after {
+ if (isNonTight && nonTightTagStartContext == null) {
+ nonTightTagStartContext = _localctx;
+ }
+}
+ : START HTML_HTML_TAG_NAME (attribute | NEWLINE | LEADING_ASTERISK | WS)* END;
htmlTagEnd: START SLASH HTML_HTML_TAG_NAME (NEWLINE | LEADING_ASTERISK | WS)* END;
-html: htmlTagStart
+html: htmlTagStart[false]
(htmlTag
| singletonElement
| paragraph
@@ -559,20 +627,20 @@ html: htmlTagStart
| tbody
| thead
| tfoot
- | pTagStart
- | liTagStart
- | trTagStart
- | tdTagStart
- | thTagStart
- | bodyTagStart
- | colgroupTagStart
- | ddTagStart
- | dtTagStart
- | headTagStart
- | optionTagStart
- | tbodyTagStart
- | theadTagStart
- | tfootTagStart
+ | pTagStart[true]
+ | liTagStart[true]
+ | trTagStart[true]
+ | tdTagStart[true]
+ | thTagStart[true]
+ | bodyTagStart[true]
+ | colgroupTagStart[true]
+ | ddTagStart[true]
+ | dtTagStart[true]
+ | headTagStart[true]
+ | optionTagStart[true]
+ | tbodyTagStart[true]
+ | theadTagStart[true]
+ | tfootTagStart[true]
| ({!isNextJavadocTag()}? LEADING_ASTERISK)
| htmlComment
| CDATA
@@ -582,9 +650,15 @@ html: htmlTagStart
htmlTagEnd
;
-optionTagStart: START OPTION_HTML_TAG_NAME (attribute | NEWLINE | LEADING_ASTERISK | WS)* END;
+optionTagStart[boolean isNonTight]
+@after {
+ if (isNonTight && nonTightTagStartContext == null) {
+ nonTightTagStartContext = _localctx;
+ }
+}
+ : START OPTION_HTML_TAG_NAME (attribute | NEWLINE | LEADING_ASTERISK | WS)* END;
optionTagEnd: START SLASH OPTION_HTML_TAG_NAME (NEWLINE | LEADING_ASTERISK | WS)* END;
-option: optionTagStart
+option: optionTagStart[false]
(htmlTag
| singletonElement
| paragraph
@@ -601,20 +675,20 @@ option: optionTagStart
| tbody
| thead
| tfoot
- | pTagStart
- | liTagStart
- | trTagStart
- | tdTagStart
- | thTagStart
- | bodyTagStart
- | colgroupTagStart
- | ddTagStart
- | dtTagStart
- | headTagStart
- | htmlTagStart
- | tbodyTagStart
- | theadTagStart
- | tfootTagStart
+ | pTagStart[true]
+ | liTagStart[true]
+ | trTagStart[true]
+ | tdTagStart[true]
+ | thTagStart[true]
+ | bodyTagStart[true]
+ | colgroupTagStart[true]
+ | ddTagStart[true]
+ | dtTagStart[true]
+ | headTagStart[true]
+ | htmlTagStart[true]
+ | tbodyTagStart[true]
+ | theadTagStart[true]
+ | tfootTagStart[true]
| ({!isNextJavadocTag()}? LEADING_ASTERISK)
| htmlComment
| CDATA
@@ -624,9 +698,15 @@ option: optionTagStart
optionTagEnd
;
-tbodyTagStart: START TBODY_HTML_TAG_NAME (attribute | NEWLINE | LEADING_ASTERISK | WS)* END;
+tbodyTagStart[boolean isNonTight]
+@after {
+ if (isNonTight && nonTightTagStartContext == null) {
+ nonTightTagStartContext = _localctx;
+ }
+}
+ : START TBODY_HTML_TAG_NAME (attribute | NEWLINE | LEADING_ASTERISK | WS)* END;
tbodyTagEnd: START SLASH TBODY_HTML_TAG_NAME (NEWLINE | LEADING_ASTERISK | WS)* END;
-tbody: tbodyTagStart
+tbody: tbodyTagStart[false]
(htmlTag
| singletonElement
| paragraph
@@ -643,20 +723,20 @@ tbody: tbodyTagStart
| option
| thead
| tfoot
- | pTagStart
- | liTagStart
- | trTagStart
- | tdTagStart
- | thTagStart
- | bodyTagStart
- | colgroupTagStart
- | ddTagStart
- | dtTagStart
- | headTagStart
- | htmlTagStart
- | optionTagStart
- | theadTagStart
- | tfootTagStart
+ | pTagStart[true]
+ | liTagStart[true]
+ | trTagStart[true]
+ | tdTagStart[true]
+ | thTagStart[true]
+ | bodyTagStart[true]
+ | colgroupTagStart[true]
+ | ddTagStart[true]
+ | dtTagStart[true]
+ | headTagStart[true]
+ | htmlTagStart[true]
+ | optionTagStart[true]
+ | theadTagStart[true]
+ | tfootTagStart[true]
| ({!isNextJavadocTag()}? LEADING_ASTERISK)
| htmlComment
| CDATA
@@ -666,9 +746,15 @@ tbody: tbodyTagStart
tbodyTagEnd
;
-tfootTagStart: START TFOOT_HTML_TAG_NAME (attribute | NEWLINE | LEADING_ASTERISK | WS)* END;
+tfootTagStart[boolean isNonTight]
+@after {
+ if (isNonTight && nonTightTagStartContext == null) {
+ nonTightTagStartContext = _localctx;
+ }
+}
+ : START TFOOT_HTML_TAG_NAME (attribute | NEWLINE | LEADING_ASTERISK | WS)* END;
tfootTagEnd: START SLASH TFOOT_HTML_TAG_NAME (NEWLINE | LEADING_ASTERISK | WS)* END;
-tfoot: tfootTagStart
+tfoot: tfootTagStart[false]
(htmlTag
| singletonElement
| paragraph
@@ -685,20 +771,20 @@ tfoot: tfootTagStart
| option
| tbody
| thead
- | pTagStart
- | liTagStart
- | trTagStart
- | tdTagStart
- | thTagStart
- | bodyTagStart
- | colgroupTagStart
- | ddTagStart
- | dtTagStart
- | headTagStart
- | htmlTagStart
- | optionTagStart
- | tbodyTagStart
- | theadTagStart
+ | pTagStart[true]
+ | liTagStart[true]
+ | trTagStart[true]
+ | tdTagStart[true]
+ | thTagStart[true]
+ | bodyTagStart[true]
+ | colgroupTagStart[true]
+ | ddTagStart[true]
+ | dtTagStart[true]
+ | headTagStart[true]
+ | htmlTagStart[true]
+ | optionTagStart[true]
+ | tbodyTagStart[true]
+ | theadTagStart[true]
| ({!isNextJavadocTag()}? LEADING_ASTERISK)
| htmlComment
| CDATA
@@ -708,9 +794,15 @@ tfoot: tfootTagStart
tfootTagEnd
;
-theadTagStart: START THEAD_HTML_TAG_NAME (attribute | NEWLINE | LEADING_ASTERISK | WS)* END;
+theadTagStart[boolean isNonTight]
+@after {
+ if (isNonTight && nonTightTagStartContext == null) {
+ nonTightTagStartContext = _localctx;
+ }
+}
+ : START THEAD_HTML_TAG_NAME (attribute | NEWLINE | LEADING_ASTERISK | WS)* END;
theadTagEnd: START SLASH THEAD_HTML_TAG_NAME (NEWLINE | LEADING_ASTERISK | WS)* END;
-thead: theadTagStart
+thead: theadTagStart[false]
(htmlTag
| singletonElement
| paragraph
@@ -727,20 +819,20 @@ thead: theadTagStart
| option
| tbody
| tfoot
- | pTagStart
- | liTagStart
- | trTagStart
- | tdTagStart
- | thTagStart
- | bodyTagStart
- | colgroupTagStart
- | ddTagStart
- | dtTagStart
- | headTagStart
- | htmlTagStart
- | optionTagStart
- | tbodyTagStart
- | tfootTagStart
+ | pTagStart[true]
+ | liTagStart[true]
+ | trTagStart[true]
+ | tdTagStart[true]
+ | thTagStart[true]
+ | bodyTagStart[true]
+ | colgroupTagStart[true]
+ | ddTagStart[true]
+ | dtTagStart[true]
+ | headTagStart[true]
+ | htmlTagStart[true]
+ | optionTagStart[true]
+ | tbodyTagStart[true]
+ | tfootTagStart[true]
| ({!isNextJavadocTag()}? LEADING_ASTERISK)
| htmlComment
| CDATA
diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/checks/javadoc/AbstractJavadocCheckTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/checks/javadoc/AbstractJavadocCheckTest.java
index 56718b078..4c8f912d2 100644
--- a/src/test/java/com/puppycrawl/tools/checkstyle/checks/javadoc/AbstractJavadocCheckTest.java
+++ b/src/test/java/com/puppycrawl/tools/checkstyle/checks/javadoc/AbstractJavadocCheckTest.java
@@ -20,8 +20,10 @@
package com.puppycrawl.tools.checkstyle.checks.javadoc;
import static com.puppycrawl.tools.checkstyle.JavadocDetailNodeParser.MSG_JAVADOC_PARSE_RULE_ERROR;
+import static com.puppycrawl.tools.checkstyle.JavadocDetailNodeParser.MSG_UNCLOSED_HTML_TAG;
import static com.puppycrawl.tools.checkstyle.checks.javadoc.AbstractJavadocCheck.MSG_JAVADOC_MISSED_HTML_CLOSE;
import static com.puppycrawl.tools.checkstyle.checks.javadoc.AbstractJavadocCheck.MSG_JAVADOC_WRONG_SINGLETON_TAG;
+import static com.puppycrawl.tools.checkstyle.checks.javadoc.SummaryJavadocCheck.MSG_SUMMARY_FIRST_SENTENCE;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonList;
import static org.junit.Assert.assertEquals;
@@ -48,6 +50,7 @@ import com.puppycrawl.tools.checkstyle.utils.BlockCommentPosition;
import com.puppycrawl.tools.checkstyle.utils.CommonUtils;
public class AbstractJavadocCheckTest extends AbstractModuleTestSupport {
+
@Rule
public final SystemErrRule systemErr = new SystemErrRule().enableLog().mute();
@@ -350,6 +353,113 @@ public class AbstractJavadocCheckTest extends AbstractModuleTestSupport {
expected);
}
+ @Test
+ public void testNonTightHtmlTagIntolerantCheck() throws Exception {
+ final DefaultConfiguration checkConfig =
+ createModuleConfig(NonTightHtmlTagIntolerantCheck.class);
+ checkConfig.addAttribute("violateExecutionOnNonTightHtml", "true");
+ final String[] expected = {
+ "6: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
+ "13: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
+ "16: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "li"),
+ "21: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
+ "27: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "tr"),
+ "34: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "li"),
+ "54: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "li"),
+ "71: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
+ "80: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "tr"),
+ "124: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
+ };
+ verify(checkConfig, getPath("InputAbstractJavadocNonTightHtmlTags.java"), expected);
+ }
+
+ @Test
+ public void testNonTightHtmlTagIntolerantCheckReportingNoViolation() throws Exception {
+ final DefaultConfiguration checkConfig =
+ createModuleConfig(NonTightHtmlTagIntolerantCheck.class);
+ final String[] expected = CommonUtils.EMPTY_STRING_ARRAY;
+ verify(checkConfig, getPath("InputAbstractJavadocNonTightHtmlTags.java"), expected);
+ }
+
+ @Test
+ public void testNonTightHtmlTagIntolerantCheckVisitCount()
+ throws Exception {
+ final DefaultConfiguration checkConfig =
+ createModuleConfig(NonTightHtmlTagIntolerantCheck.class);
+ checkConfig.addAttribute("violateExecutionOnNonTightHtml", "true");
+ checkConfig.addAttribute("reportVisitJavadocToken", "true");
+ final String[] expected = {
+ "6: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
+ "13: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
+ "16: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "li"),
+ "21: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
+ "27: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "tr"),
+ "34: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "li"),
+ "41:8: " + getCheckMessage(MSG_SUMMARY_FIRST_SENTENCE),
+ "54: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "li"),
+ "62:13: " + getCheckMessage(MSG_SUMMARY_FIRST_SENTENCE),
+ "71: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
+ "80: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "tr"),
+ "99:8: " + getCheckMessage(MSG_SUMMARY_FIRST_SENTENCE),
+ "105:8: " + getCheckMessage(MSG_SUMMARY_FIRST_SENTENCE),
+ "109:8: " + getCheckMessage(MSG_SUMMARY_FIRST_SENTENCE),
+ "124: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
+ };
+ verify(checkConfig, getPath("InputAbstractJavadocNonTightHtmlTags.java"), expected);
+ }
+
+ @Test
+ public void testVisitCountForCheckAcceptingJavadocWithNonTightHtml()
+ throws Exception {
+ final DefaultConfiguration checkConfig =
+ createModuleConfig(NonTightHtmlTagTolerantCheck.class);
+ checkConfig.addAttribute("violateExecutionOnNonTightHtml", "true");
+ checkConfig.addAttribute("reportVisitJavadocToken", "true");
+ final String[] expected = {
+ "4:4: " + getCheckMessage(MSG_SUMMARY_FIRST_SENTENCE),
+ "5:4: " + getCheckMessage(MSG_SUMMARY_FIRST_SENTENCE),
+ "6: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
+ "6:4: " + getCheckMessage(MSG_SUMMARY_FIRST_SENTENCE),
+ "7:4: " + getCheckMessage(MSG_SUMMARY_FIRST_SENTENCE),
+ "7:39: " + getCheckMessage(MSG_SUMMARY_FIRST_SENTENCE),
+ "13: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
+ "13:9: " + getCheckMessage(MSG_SUMMARY_FIRST_SENTENCE),
+ "13:13: " + getCheckMessage(MSG_SUMMARY_FIRST_SENTENCE),
+ "16: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "li"),
+ "16:8: " + getCheckMessage(MSG_SUMMARY_FIRST_SENTENCE),
+ "20:8: " + getCheckMessage(MSG_SUMMARY_FIRST_SENTENCE),
+ "21: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
+ "21:8: " + getCheckMessage(MSG_SUMMARY_FIRST_SENTENCE),
+ "21:30: " + getCheckMessage(MSG_SUMMARY_FIRST_SENTENCE),
+ "26:8: " + getCheckMessage(MSG_SUMMARY_FIRST_SENTENCE),
+ "26:22: " + getCheckMessage(MSG_SUMMARY_FIRST_SENTENCE),
+ "27: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "tr"),
+ "32:8: " + getCheckMessage(MSG_SUMMARY_FIRST_SENTENCE),
+ "33:8: " + getCheckMessage(MSG_SUMMARY_FIRST_SENTENCE),
+ "34: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "li"),
+ "34:8: " + getCheckMessage(MSG_SUMMARY_FIRST_SENTENCE),
+ "34:23: " + getCheckMessage(MSG_SUMMARY_FIRST_SENTENCE),
+ "39:8: " + getCheckMessage(MSG_SUMMARY_FIRST_SENTENCE),
+ "39:20: " + getCheckMessage(MSG_SUMMARY_FIRST_SENTENCE),
+ "39:34: " + getCheckMessage(MSG_SUMMARY_FIRST_SENTENCE),
+ "41: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "li"),
+ "41:16: " + getCheckMessage(MSG_SUMMARY_FIRST_SENTENCE),
+ "41:21: " + getCheckMessage(MSG_SUMMARY_FIRST_SENTENCE),
+ "49:8: " + getCheckMessage(MSG_SUMMARY_FIRST_SENTENCE),
+ "51: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
+ "51:22: " + getCheckMessage(MSG_SUMMARY_FIRST_SENTENCE),
+ "56:8: " + getCheckMessage(MSG_SUMMARY_FIRST_SENTENCE),
+ "57:8: " + getCheckMessage(MSG_SUMMARY_FIRST_SENTENCE),
+ "60: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "tr"),
+ "79:8: " + getCheckMessage(MSG_SUMMARY_FIRST_SENTENCE),
+ "85: " + getCheckMessage(MSG_UNCLOSED_HTML_TAG, "p"),
+ "85:9: " + getCheckMessage(MSG_SUMMARY_FIRST_SENTENCE),
+ "85:13: " + getCheckMessage(MSG_SUMMARY_FIRST_SENTENCE),
+ "85:33: " + getCheckMessage(MSG_SUMMARY_FIRST_SENTENCE),
+ };
+ verify(checkConfig, getPath("InputAbstractJavadocNonTightHtmlTags2.java"), expected);
+ }
+
private static class TempCheck extends AbstractJavadocCheck {
@Override
@@ -460,4 +570,59 @@ public class AbstractJavadocCheckTest extends AbstractModuleTestSupport {
leaveCount++;
}
}
+
+ public static class NonTightHtmlTagIntolerantCheck extends AbstractJavadocCheck {
+
+ private boolean reportVisitJavadocToken;
+
+ public final void setReportVisitJavadocToken(boolean reportVisitJavadocToken) {
+ this.reportVisitJavadocToken = reportVisitJavadocToken;
+ }
+
+ @Override
+ public int[] getDefaultJavadocTokens() {
+ return new int[] {
+ JavadocTokenTypes.P_TAG_START,
+ JavadocTokenTypes.LI_TAG_START,
+ JavadocTokenTypes.BODY_TAG_START,
+ };
+ }
+
+ @Override
+ public void visitJavadocToken(DetailNode ast) {
+ if (reportVisitJavadocToken) {
+ log(ast.getLineNumber(), ast.getColumnNumber(), MSG_SUMMARY_FIRST_SENTENCE);
+ }
+ }
+
+ @Override
+ public boolean acceptJavadocWithNonTightHtml() {
+ return false;
+ }
+ }
+
+ public static class NonTightHtmlTagTolerantCheck extends AbstractJavadocCheck {
+
+ private boolean reportVisitJavadocToken;
+
+ public final void setReportVisitJavadocToken(boolean reportVisitJavadocToken) {
+ this.reportVisitJavadocToken = reportVisitJavadocToken;
+ }
+
+ @Override
+ public int[] getDefaultJavadocTokens() {
+ return new int[] {
+ JavadocTokenTypes.P_TAG_START,
+ JavadocTokenTypes.LI_TAG_START,
+ JavadocTokenTypes.BODY_TAG_START,
+ };
+ }
+
+ @Override
+ public void visitJavadocToken(DetailNode ast) {
+ if (reportVisitJavadocToken) {
+ log(ast.getLineNumber(), ast.getColumnNumber(), MSG_SUMMARY_FIRST_SENTENCE);
+ }
+ }
+ }
}
diff --git a/src/test/resources/com/puppycrawl/tools/checkstyle/checks/javadoc/abstractjavadoc/InputAbstractJavadocNonTightHtmlTags.java b/src/test/resources/com/puppycrawl/tools/checkstyle/checks/javadoc/abstractjavadoc/InputAbstractJavadocNonTightHtmlTags.java
new file mode 100644
index 000000000..a2e2ec563
--- /dev/null
+++ b/src/test/resources/com/puppycrawl/tools/checkstyle/checks/javadoc/abstractjavadoc/InputAbstractJavadocNonTightHtmlTags.java
@@ -0,0 +1,129 @@
+package com.puppycrawl.tools.checkstyle.checks.javadoc.abstractjavadoc;
+
+/**
+ * <body>
+ * <p> This class is only meant for testing. </p>
+ * <p> In html, closing all tags is not necessary.
+ * <li> neither is opening every tag <p> </li>
+ * </body>
+ *
+ * @see "https://www.w3.org/TR/html51/syntax.html#optional-start-and-end-tags"
+ */
+public class InputAbstractJavadocNonTightHtmlTags {
+ /** <p> <p> paraception </p> </p> */
+ private int field1;
+
+ /**<li> paraTags should be opened</p> list isn't nested in parse tree </li>*/
+ private int field2;
+
+ /**
+ * <p> this paragraph is closed and would be nested in javadoc tree </p>
+ * <li> this list has an <p> unclosed para, but still the list would get nested </li>
+ */
+ private int field3;
+
+ /**
+ * <li> Complete <p> nesting </p> </li>
+ * <tr> Zero </p> nesting despite `tr` is closed </tr>
+ */
+ private int field4;
+
+ /**
+ * <p> <a href="www.something.com">something</a> paragraph with `htmlTag` </p>
+ * <p> <a href="www.something.com"/> Nested paragraph with `singletonTag` </p>
+ * <li> Outer tag <li> Inner tag nested </li> not nested </li>
+ */
+ private int field5;
+
+ /**
+ * <th> !isNonTight </th>
+ * <th> th with <base/> singletonElement </th>
+ * <body> body with <br/> singletonElement </body>
+ * <colgroup><col><col><col></colgroup>
+ * <dd> dd with <hr> singletonElement </dd>
+ * <dt> dt with <img src="~/singletonElement.jpg" alt="" width="100" height="150"/>
+ * singletonElement </dt>
+ * <head> head with <img src="~/singletonElement.jpg" alt="" width="100" height="150">
+ * singletonElement </head>
+ */
+ private int field6;
+
+ /**
+ * <body> body <p> paragraph <li> list </li> </p> </body>
+ *
+ * @return <li> <li> outer list isn't nested in parse tree </li> </li>
+ */
+ int getField1() {return field1;}
+
+ /***/
+ int getField2() {return field2;} //method with empty javadoc
+
+ /**
+ * <tr> <li> list is going to be nested in the parse tree </li> </tr>
+ *
+ * @param field1 {@code <p> paraTag will not be recognized} in javadoc tree </p>
+ */
+ void setField1(int field1) {this.field1 = field1;}
+
+ /**
+ * <p>This is a setter method.
+ * And paraTag shall be nested in parse tree </p>
+ * @param field2 <p> settter
+ */
+ void setField2(int field2) {this.field2 = field2;}
+
+ /**
+ * <p> paragraph with a <br>singletonElement. <hr> And it contains another one. </p>
+ * <li> List with singletonElement
+ * <param name=mov value="~/imitation game.mp4"> <param name=allowfullscreen value=true> </li>
+ * @return <tr> tr with <base href="www.something.com"> singletonElement </tr>
+ * <tr> nonTight </th>
+ */
+ private int getField3() {return field3;}
+
+ /**
+ * @param field3 <td> td with singletonElement <br/> </td>
+ */
+ private void setField3(int field3) { this.field3 = field3;}
+
+ /**
+ * <html> <bR> <Br> <BR> <Br/> <BR/> <bR/> </html>
+ * <option> <INPut/> </option>
+ * @return <tbody> <input/> <br> </tbody>
+ */
+ private int getField4() {return field4;}
+
+ /**
+ * <thead> <br> </thead>
+ * <tfoot> <AREA ALT="alt" COORDS="100,0,200,50" HREF="/href/"> </tfoot>
+ * <p> </p>
+ * @param field4 value to which {@link #field4} is to be set to
+ */
+ private void setField4(int field4) {this.field4 = field4;}
+
+ /**
+ * <li> </li>
+ * <TR> </tr>
+ * <Td> </td>
+ * <tH> </th>
+ * <body> </body>
+ * <colGROUP> </COLgroup>
+ * <DD> </dd>
+ * <dt> </dt>
+ * <Head> </head>
+ * <HTML> </HTML>
+ * <option> </option>
+ * <tBody> </TbODY>
+ * <tHead> </ThEAD>
+ * <tFoot> </TfOOT>
+ * @param field5 value to which {@link #field5} is to be set to
+ */
+ private void setField5(int field5) {this.field5 = field5;}
+
+ /**
+ * <p> <li> <TR> <Td> <tH> <body> <colGROUP> <DD> <dt> <Head> <HTML> <option> <tBody> <tHead>
+ * <tFoot>
+ * @param field6 </p> value to which {@link #field6} is to be set to
+ */
+ private void setField6(int field6) {this.field6 = field6;}
+}
diff --git a/src/test/resources/com/puppycrawl/tools/checkstyle/checks/javadoc/abstractjavadoc/InputAbstractJavadocNonTightHtmlTags2.java b/src/test/resources/com/puppycrawl/tools/checkstyle/checks/javadoc/abstractjavadoc/InputAbstractJavadocNonTightHtmlTags2.java
new file mode 100644
index 000000000..1cf6024f4
--- /dev/null
+++ b/src/test/resources/com/puppycrawl/tools/checkstyle/checks/javadoc/abstractjavadoc/InputAbstractJavadocNonTightHtmlTags2.java
@@ -0,0 +1,90 @@
+package com.puppycrawl.tools.checkstyle.checks.javadoc.abstractjavadoc;
+
+/**
+ * <body>
+ * <p> This class is only meant for testing. </p>
+ * <p> In html, closing all tags is not necessary.
+ * <li> neither is opening every tag. <p>Only the first non-tight tag is logged</li>
+ * </body>
+ *
+ * @see "https://www.w3.org/TR/html51/syntax.html#optional-start-and-end-tags"
+ */
+public class InputAbstractJavadocNonTightHtmlTags2 {
+ /** <p> <p> paraception </p> </p> */
+ private int field1;
+
+ /**<li> paraTags should be opened</p> list isn't nested in parse tree </li>*/
+ private int field2;
+
+ /**
+ * <p> this paragraph is closed and would be nested in javadoc tree </p>
+ * <li> this list has an <p> unclosed para, but still the list would get nested </li>
+ */
+ private int field3;
+
+ /**
+ * <li> Complete <p> nesting </p> </li>
+ * <tr> Zero </p> nesting despite `tr` is closed </tr>
+ */
+ private int field4;
+
+ /**
+ * <p> <a href="www.something.com">something</a> paragraph with `htmlTag` </p>
+ * <p> <a href="www.something.com"/> Nested paragraph with `singletonTag` </p>
+ * <li> Outer tag <li> Inner tag nested </li> not nested </li>
+ */
+ private int field5;
+
+ /**
+ * <body> body <p> paragraph <li> list </li> </p> </body>
+ *
+ * @return <li> <li> outer list isn't nested in parse tree </li> </li>
+ */
+ int getField1() {return field1;}
+
+ /***/
+ int getField2() {return field2;} //method with empty javadoc
+
+ /**
+ * <p>This is a setter method.
+ * And paraTag shall be nested in parse tree </p>
+ * @param field2 <p> settter
+ */
+ void setField2(int field2) {this.field2 = field2;}
+
+ /**
+ * <p> paragraph with a <br>singletonElement. <hr> And it contains another one. </p>
+ * <li> List with singletonElement
+ * <param name=mov value="~/imitation game.mp4"> <param name=allowfullscreen value=true> </li>
+ * @return <tr> tr with <base href="www.something.com"> singletonElement </tr>
+ * <tr> nonTight </th>
+ */
+ private int getField3() {return field3;}
+
+ /**
+ * @param field3 <td> td with singletonElement <br/> </td>
+ */
+ private void setField3(int field3) { this.field3 = field3;}
+
+ /**
+ * <html> <bR> <Br> <BR> <Br/> <BR/> <bR/> </html>
+ * <option> <INPut/> </option>
+ * @return <tbody> <input/> <br> </tbody>
+ */
+ private int getField4() {return field4;}
+
+ /**
+ * <thead> <br> </thead>
+ * <tfoot> <AREA ALT="alt" COORDS="100,0,200,50" HREF="/href/"> </tfoot>
+ * <p> </p>
+ * @param field4 value to which {@link #field4} is to be set to
+ */
+ private void setField4(int field4) {this.field4 = field4;}
+
+ /**
+ * <p> <li> <TR> <Td> <tH> <body> <colGROUP> <DD> <dt> <Head> <HTML> <option> <tBody> <tHead>
+ * <tFoot>
+ * @param field5 </p> value to which {@link #field5} is to be set to
+ */
+ private void setField5(int field5) {this.field5 = field5;}
+}