Skip to content

Commit 345e149

Browse files
Vladimir.ShapkinVladimir.Shapkin
authored andcommitted
Fixed issue 1079
The error no longer appears for string literals similar to comments.
1 parent 8c8068c commit 345e149

File tree

11 files changed

+322
-32
lines changed

11 files changed

+322
-32
lines changed
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
/*
2+
* Copyright (c) 2011-2024 Qulice.com
3+
*
4+
* All rights reserved.
5+
*
6+
* Redistribution and use in source and binary forms, with or without
7+
* modification, are permitted provided that the following conditions
8+
* are met: 1) Redistributions of source code must retain the above
9+
* copyright notice, this list of conditions and the following
10+
* disclaimer. 2) Redistributions in binary form must reproduce the above
11+
* copyright notice, this list of conditions and the following
12+
* disclaimer in the documentation and/or other materials provided
13+
* with the distribution. 3) Neither the name of the Qulice.com nor
14+
* the names of its contributors may be used to endorse or promote
15+
* products derived from this software without specific prior written
16+
* permission.
17+
*
18+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19+
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
20+
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21+
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
22+
* THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
23+
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24+
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26+
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27+
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
29+
* OF THE POSSIBILITY OF SUCH DAMAGE.
30+
*/
31+
package com.qulice.checkstyle;
32+
33+
import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
34+
import com.puppycrawl.tools.checkstyle.api.DetailAST;
35+
import com.puppycrawl.tools.checkstyle.api.TokenTypes;
36+
import java.util.regex.Matcher;
37+
import java.util.regex.Pattern;
38+
39+
/**
40+
* Multi line comment checker.
41+
* @since 0.23.1
42+
*/
43+
public final class MultiLineCommentCheck extends AbstractCheck {
44+
/**
45+
* Pattern for check.
46+
*/
47+
private Pattern format = Pattern.compile("^$");
48+
49+
/**
50+
* The message to report for a match.
51+
*/
52+
private String message = "";
53+
54+
/**
55+
* Comment line.
56+
*/
57+
@SuppressWarnings("PMD.AvoidStringBufferField")
58+
private StringBuilder line;
59+
60+
@Override
61+
public boolean isCommentNodesRequired() {
62+
return true;
63+
}
64+
65+
@Override
66+
public int[] getDefaultTokens() {
67+
return new int[]{
68+
TokenTypes.BLOCK_COMMENT_BEGIN,
69+
TokenTypes.COMMENT_CONTENT,
70+
TokenTypes.BLOCK_COMMENT_END,
71+
};
72+
}
73+
74+
@Override
75+
public int[] getAcceptableTokens() {
76+
return this.getDefaultTokens();
77+
}
78+
79+
@Override
80+
public int[] getRequiredTokens() {
81+
return this.getDefaultTokens();
82+
}
83+
84+
@Override
85+
public void visitToken(final DetailAST ast) {
86+
if (ast.getType() == TokenTypes.BLOCK_COMMENT_BEGIN) {
87+
this.line = new StringBuilder(ast.getText());
88+
} else if (ast.getType() == TokenTypes.COMMENT_CONTENT) {
89+
this.line.append(ast.getText());
90+
} else {
91+
this.line.append(ast.getText());
92+
final Matcher matcher = this.format.matcher(this.line.toString());
93+
if (matcher.matches()) {
94+
this.log(ast, this.message);
95+
}
96+
}
97+
}
98+
99+
public void setFormat(final String fmt) {
100+
this.format = Pattern.compile(fmt);
101+
}
102+
103+
public void setMessage(final String msg) {
104+
this.message = msg;
105+
}
106+
}

qulice-checkstyle/src/main/java/com/qulice/checkstyle/RequiredJavaDocTag.java

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -81,16 +81,16 @@ final class RequiredJavaDocTag {
8181
/**
8282
* Reference to a method for writing a message to the log.
8383
*/
84-
private final LogWriter writer;
84+
private final Reporter reporter;
8585

8686
/**
8787
* Ctor.
8888
* @param name Tag name.
8989
* @param patt Pattern for checking the contents of a tag in a string.
90-
* @param lwriter Reference to a method for writing a message to the log.
90+
* @param rep Reference to a method for writing a message to the log.
9191
*/
9292
RequiredJavaDocTag(final String name, final Pattern patt,
93-
final LogWriter lwriter) {
93+
final Reporter rep) {
9494
this(
9595
name,
9696
Pattern.compile(
@@ -100,7 +100,7 @@ final class RequiredJavaDocTag {
100100
)
101101
),
102102
patt,
103-
lwriter
103+
rep
104104
);
105105
}
106106

@@ -109,15 +109,15 @@ final class RequiredJavaDocTag {
109109
* @param cname Tag name.
110110
* @param ptag Pattern for searching a tag in a string.
111111
* @param patt Pattern for checking the contents of a tag in a string.
112-
* @param lwriter Reference to a method for writing a message to the log.
112+
* @param rep Reference to a method for writing a message to the log.
113113
* @checkstyle ParameterNumberCheck (3 lines)
114114
*/
115115
RequiredJavaDocTag(final String cname, final Pattern ptag,
116-
final Pattern patt, final LogWriter lwriter) {
116+
final Pattern patt, final Reporter rep) {
117117
this.name = cname;
118118
this.tag = ptag;
119119
this.content = patt;
120-
this.writer = lwriter;
120+
this.reporter = rep;
121121
}
122122

123123
/**
@@ -132,24 +132,21 @@ public void matchTagFormat(final String[] lines, final int start,
132132
for (int pos = start; pos <= end; pos += 1) {
133133
final String line = lines[pos];
134134
final Matcher matcher = this.tag.matcher(line);
135-
if (matcher.matches()
136-
&& !RequiredJavaDocTag.empty(matcher.group("name"))
137-
&& !RequiredJavaDocTag.empty(matcher.group("cont"))
138-
) {
135+
if (RequiredJavaDocTag.tagFound(matcher)) {
139136
found.put(pos, matcher.group("cont"));
140137
break;
141138
}
142139
}
143140
if (found.isEmpty()) {
144-
this.writer.log(
141+
this.reporter.log(
145142
start + 1,
146143
"Missing ''@{0}'' tag in class/interface comment",
147144
this.name
148145
);
149146
} else {
150147
for (final Map.Entry<Integer, String> item : found.entrySet()) {
151148
if (!this.content.matcher(item.getValue()).matches()) {
152-
this.writer.log(
149+
this.reporter.log(
153150
item.getKey() + 1,
154151
"Tag text ''{0}'' does not match the pattern ''{1}''",
155152
item.getValue(),
@@ -160,6 +157,17 @@ public void matchTagFormat(final String[] lines, final int start,
160157
}
161158
}
162159

160+
/**
161+
* Finds the tag name and the following sentences.
162+
* @param matcher Tag name matcher.
163+
* @return True if the tag and its clauses are found.
164+
*/
165+
private static boolean tagFound(final Matcher matcher) {
166+
return matcher.matches()
167+
&& !RequiredJavaDocTag.empty(matcher.group("name"))
168+
&& !RequiredJavaDocTag.empty(matcher.group("cont"));
169+
}
170+
163171
/**
164172
* Checks for an empty string.
165173
* @param str Line to check.
@@ -171,10 +179,10 @@ private static boolean empty(final String str) {
171179

172180
/**
173181
* Logger.
174-
* @see com.puppycrawl.tools.checkstyle.api.AbstractCheck.log
182+
* @see com.puppycrawl.tools.checkstyle.api.AbstractCheck#log(int, String, Object...)
175183
* @since 0.23.1
176184
*/
177-
interface LogWriter {
185+
interface Reporter {
178186
/**
179187
* Log a message that has no column information.
180188
*

qulice-checkstyle/src/main/java/com/qulice/checkstyle/SingleLineCommentCheck.java

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,32 @@
3333
import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
3434
import com.puppycrawl.tools.checkstyle.api.DetailAST;
3535
import com.puppycrawl.tools.checkstyle.api.TokenTypes;
36+
import java.util.regex.Matcher;
37+
import java.util.regex.Pattern;
3638

3739
/**
3840
* C++ style inline comment is not allowed.
3941
* Use //-style comment instead.
4042
* @since 0.18
4143
*/
4244
public final class SingleLineCommentCheck extends AbstractCheck {
45+
46+
/**
47+
* Pattern for check.
48+
*/
49+
private Pattern format = Pattern.compile("^$");
50+
51+
/**
52+
* The message to report for a match.
53+
*/
54+
private String message = "";
55+
56+
/**
57+
* Comment line.
58+
*/
59+
@SuppressWarnings("PMD.AvoidStringBufferField")
60+
private StringBuilder line;
61+
4362
/**
4463
* When inside a block comment, holds begin line number.
4564
*/
@@ -54,6 +73,7 @@ public boolean isCommentNodesRequired() {
5473
public int[] getDefaultTokens() {
5574
return new int[]{
5675
TokenTypes.BLOCK_COMMENT_BEGIN,
76+
TokenTypes.COMMENT_CONTENT,
5777
TokenTypes.BLOCK_COMMENT_END,
5878
};
5979
}
@@ -71,9 +91,34 @@ public int[] getRequiredTokens() {
7191
@Override
7292
public void visitToken(final DetailAST ast) {
7393
if (ast.getType() == TokenTypes.BLOCK_COMMENT_BEGIN) {
94+
this.line = new StringBuilder(ast.getText());
7495
this.begin = ast.getLineNo();
75-
} else if (this.begin == ast.getLineNo()) {
76-
this.log(ast, "This kind of comment is not allowed.");
96+
} else if (ast.getType() == TokenTypes.COMMENT_CONTENT) {
97+
this.line.append(ast.getText());
98+
} else {
99+
this.line.append(ast.getText());
100+
final Matcher matcher = this.format.matcher(this.line.toString());
101+
if (matcher.matches() && this.singleLineCStyleComment(ast)) {
102+
this.log(ast, this.message);
103+
}
77104
}
78105
}
106+
107+
public void setFormat(final String fmt) {
108+
this.format = Pattern.compile(fmt);
109+
}
110+
111+
public void setMessage(final String msg) {
112+
this.message = msg;
113+
}
114+
115+
/**
116+
* Checks for the end of a comment line.
117+
* @param ast Checkstyle's AST nodes.
118+
* @return True if this is the end of the comment
119+
* and the starting line number is equal to the ending line number.
120+
*/
121+
private boolean singleLineCStyleComment(final DetailAST ast) {
122+
return ast.getType() == TokenTypes.BLOCK_COMMENT_END && this.begin == ast.getLineNo();
123+
}
79124
}

qulice-checkstyle/src/main/resources/com/qulice/checkstyle/checks.xml

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -115,18 +115,6 @@ OF THE POSSIBILITY OF SUCH DAMAGE.
115115
<property name="id" value="ParamShouldStartWithCapitalLetter"/>
116116
<property name="message" value="@param tag description should start with capital letter"/>
117117
</module>
118-
<module name="RegexpSingleline">
119-
<property name="format" value="/\*\* +[^A-Z\{ ]"/>
120-
<property name="fileExtensions" value="java"/>
121-
<property name="id" value="FirstLetterInCommentShouldBeCapital"/>
122-
<property name="message" value="First sentence in a comment should start with a capital letter"/>
123-
</module>
124-
<module name="RegexpMultiline">
125-
<property name="format" value="/\*\*\W+\* +[^A-Z\{ ]"/>
126-
<property name="fileExtensions" value="java"/>
127-
<property name="id" value="FirstLetterInCommentShouldBeCapital2"/>
128-
<property name="message" value="First sentence in a comment should start with a capital letter"/>
129-
</module>
130118
<module name="RegexpSingleline">
131119
<property name="format" value="synchronized +\(this\) +\{"/>
132120
<property name="fileExtensions" value="java"/>
@@ -380,6 +368,26 @@ OF THE POSSIBILITY OF SUCH DAMAGE.
380368
<module name="com.qulice.checkstyle.DiamondOperatorCheck"/>
381369
<module name="com.qulice.checkstyle.JavadocParameterOrderCheck"/>
382370
<module name="com.qulice.checkstyle.JavadocTagsCheck"/>
371+
<module name="com.qulice.checkstyle.SingleLineCommentCheck">
372+
<property name="format" value=" */\*[^*].*\*/ *"/>
373+
<property name="message" value="This kind of comment is not allowed."/>
374+
<property name="id" value="CStyleCommentNotAllowed"/>
375+
</module>
376+
<module name="com.qulice.checkstyle.SingleLineCommentCheck">
377+
<property name="format" value=" */\*\* +[^A-Z\{ ][\W\s\S]*"/>
378+
<property name="message" value="First sentence in a comment should start with a capital letter."/>
379+
<property name="id" value="FirstLetterInCommentShouldBeCapital"/>
380+
</module>
381+
<module name="com.qulice.checkstyle.MultiLineCommentCheck">
382+
<property name="format" value=" */\*\*\W+\* +[^A-Z\{ ][\W\s\S]*"/>
383+
<property name="message" value="First sentence in a comment should start with a capital letter."/>
384+
<property name="id" value="FirstLetterInCommentShouldBeCapital2"/>
385+
</module>
386+
<module name="com.qulice.checkstyle.MultiLineCommentCheck">
387+
<property name="format" value=" */\*\* +[^A-Z\{ ][\W\s\S]*"/>
388+
<property name="message" value="First sentence in a comment should start with a capital letter."/>
389+
<property name="id" value="FirstLetterInCommentShouldBeCapital3"/>
390+
</module>
383391
</module>
384392
<!--
385393
Our custom checkers.

qulice-checkstyle/src/test/java/com/qulice/checkstyle/ChecksTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,8 @@ private static Stream<String> checks() {
195195
"JavadocEmptyLineCheck",
196196
"JavadocTagsCheck",
197197
"ProhibitNonFinalClassesCheck",
198-
"QualifyInnerClassCheck"
198+
"QualifyInnerClassCheck",
199+
"CommentCheck"
199200
).map(s -> String.format("ChecksTest/%s", s));
200201
}
201202

qulice-checkstyle/src/test/java/com/qulice/checkstyle/RequiredJavaDocTagTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,10 +108,10 @@ void tagNotMatched() {
108108
}
109109

110110
/**
111-
* Stub for {@link RequiredJavaDocTag.LogWriter} class.
111+
* Stub for {@link RequiredJavaDocTag.Reporter} class.
112112
* @since 0.23.1
113113
*/
114-
private static class WriterStub implements RequiredJavaDocTag.LogWriter {
114+
private static class WriterStub implements RequiredJavaDocTag.Reporter {
115115

116116
/**
117117
* Message.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* This is not a real Java class. It won't be compiled ever. It is used
3+
* only as a text resource in integration.ChecksIT.
4+
*/
5+
6+
/* C-style comment */
7+
public final class ProhibitedCStyleComment {
8+
9+
/** first sentence in a comment should start with a capital letter */
10+
public void main() {
11+
}
12+
13+
/**
14+
* first sentence in a comment should start with a capital letter
15+
*/
16+
private static String TEXT = "some text";
17+
18+
/** first sentence in a comment should start with a capital letter
19+
*/
20+
private static String OTHER_TEXT = "some text";
21+
}
22+

0 commit comments

Comments
 (0)