Skip to content

Commit dfc2c62

Browse files
Vladimir.ShapkinVladimir.Shapkin
authored andcommitted
1. Fixed a bug when adding extra spaces after the parameter name
* @param line Line position. * @param column Column position. 2. Fixed a bug when using comment-like text in string literals: final String comment = "/* some text */"; Fixes for issue #1079
2 parents 345e149 + 65e871c commit dfc2c62

File tree

20 files changed

+463
-85
lines changed

20 files changed

+463
-85
lines changed

pom.xml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -176,19 +176,19 @@ OF THE POSSIBILITY OF SUCH DAMAGE.
176176
<dependency>
177177
<groupId>org.hamcrest</groupId>
178178
<artifactId>hamcrest-core</artifactId>
179-
<version>2.2</version>
179+
<version>3.0</version>
180180
<scope>test</scope>
181181
</dependency>
182182
<dependency>
183183
<groupId>org.hamcrest</groupId>
184184
<artifactId>hamcrest-library</artifactId>
185-
<version>2.2</version>
185+
<version>3.0</version>
186186
<scope>test</scope>
187187
</dependency>
188188
<dependency>
189189
<groupId>org.slf4j</groupId>
190190
<artifactId>slf4j-log4j12</artifactId>
191-
<version>2.0.13</version>
191+
<version>2.0.16</version>
192192
<scope>test</scope>
193193
</dependency>
194194
<dependency>

qulice-checkstyle/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ OF THE POSSIBILITY OF SUCH DAMAGE.
9292
<dependency>
9393
<groupId>org.apache.commons</groupId>
9494
<artifactId>commons-lang3</artifactId>
95-
<version>3.14.0</version>
95+
<version>3.16.0</version>
9696
<scope>test</scope>
9797
</dependency>
9898
<dependency>

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

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -131,8 +131,11 @@ public void visitToken(final DetailAST ast) {
131131
* @param text Text to find.
132132
* @return Line number with found text, or -1 if it wasn't found.
133133
*/
134-
private static int findTrimmedTextUp(final String[] lines,
135-
final int start, final String text) {
134+
private static int findTrimmedTextUp(
135+
final String[] lines,
136+
final int start,
137+
final String text
138+
) {
136139
int found = -1;
137140
for (int pos = start - 1; pos >= 0; pos -= 1) {
138141
if (lines[pos].trim().equals(text)) {
@@ -172,8 +175,13 @@ private static int findCommentEnd(final String[] lines, final int start) {
172175
* @param tag Name of the tag.
173176
* @checkstyle ParameterNumber (3 lines)
174177
*/
175-
private void findProhibited(final String[] lines, final int start,
176-
final int cstart, final int cend, final String tag) {
178+
private void findProhibited(
179+
final String[] lines,
180+
final int start,
181+
final int cstart,
182+
final int cend,
183+
final String tag
184+
) {
177185
final List<Integer> found =
178186
this.findTagLineNum(lines, cstart, cend, tag);
179187
if (!found.isEmpty()) {
@@ -194,8 +202,12 @@ private void findProhibited(final String[] lines, final int start,
194202
* @return Line number with found tag or -1 otherwise.
195203
* @checkstyle ParameterNumber (3 lines)
196204
*/
197-
private List<Integer> findTagLineNum(final String[] lines, final int start,
198-
final int end, final String tag) {
205+
private List<Integer> findTagLineNum(
206+
final String[] lines,
207+
final int start,
208+
final int end,
209+
final String tag
210+
) {
199211
final String prefix = String.format(" * @%s ", tag);
200212
final List<Integer> found = new ArrayList<>(1);
201213
for (int pos = start; pos <= end; pos += 1) {

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

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,24 +38,29 @@
3838

3939
/**
4040
* Multi line comment checker.
41+
* Used by the checkstyle process multiple times as a singleton.
4142
* @since 0.23.1
4243
*/
4344
public final class MultiLineCommentCheck extends AbstractCheck {
4445
/**
4546
* Pattern for check.
47+
* It is not final as it is initialized from the configuration.
4648
*/
4749
private Pattern format = Pattern.compile("^$");
4850

4951
/**
5052
* The message to report for a match.
53+
* It is not final as it is initialized from the configuration.
5154
*/
5255
private String message = "";
5356

5457
/**
5558
* Comment line.
59+
* It is not final because the visitToken method is called many times
60+
* during the class under test and the field is reinitialized with a new object.
5661
*/
5762
@SuppressWarnings("PMD.AvoidStringBufferField")
58-
private StringBuilder line;
63+
private StringBuilder text;
5964

6065
@Override
6166
public boolean isCommentNodesRequired() {
@@ -84,22 +89,39 @@ public int[] getRequiredTokens() {
8489
@Override
8590
public void visitToken(final DetailAST ast) {
8691
if (ast.getType() == TokenTypes.BLOCK_COMMENT_BEGIN) {
87-
this.line = new StringBuilder(ast.getText());
92+
this.text = new StringBuilder(ast.getText());
8893
} else if (ast.getType() == TokenTypes.COMMENT_CONTENT) {
89-
this.line.append(ast.getText());
94+
this.text.append(ast.getText());
9095
} else {
91-
this.line.append(ast.getText());
92-
final Matcher matcher = this.format.matcher(this.line.toString());
96+
this.text.append(ast.getText());
97+
final Matcher matcher = this.format.matcher(this.text.toString());
9398
if (matcher.matches()) {
9499
this.log(ast, this.message);
95100
}
96101
}
97102
}
98103

104+
/**
105+
* The method is called from checkstyle to configure this class.
106+
* The parameter is set from the checks.xml file
107+
* <module name="com.qulice.checkstyle.MultiLineCommentCheck"/> and
108+
* <property name="format" value=" this regexp "/> property
109+
*
110+
* @param fmt Validatig regexp.
111+
*/
99112
public void setFormat(final String fmt) {
100113
this.format = Pattern.compile(fmt);
101114
}
102115

116+
/**
117+
* The method is called from checkstyle to configure this class.
118+
* The parameter is set from the checks.xml file
119+
* <module name="com.qulice.checkstyle.MultiLineCommentCheck"/> and
120+
* <property name="message" value="First sentence in a comment should start with ....."/>
121+
* property
122+
*
123+
* @param msg Error message.
124+
*/
103125
public void setMessage(final String msg) {
104126
this.message = msg;
105127
}
Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
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+
32+
package com.qulice.checkstyle;
33+
34+
import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
35+
import com.puppycrawl.tools.checkstyle.api.DetailAST;
36+
import com.puppycrawl.tools.checkstyle.api.TokenTypes;
37+
import java.util.LinkedList;
38+
import java.util.List;
39+
40+
/**
41+
* Checks that constructor, declared as private class is used more than once.
42+
*
43+
* @since 0.3
44+
*/
45+
public final class ProhibitUnusedPrivateConstructorCheck extends AbstractCheck {
46+
47+
@Override
48+
public int[] getDefaultTokens() {
49+
return new int[] {TokenTypes.CLASS_DEF};
50+
}
51+
52+
@Override
53+
public int[] getAcceptableTokens() {
54+
return this.getDefaultTokens();
55+
}
56+
57+
@Override
58+
public int[] getRequiredTokens() {
59+
return this.getDefaultTokens();
60+
}
61+
62+
@Override
63+
public void visitToken(final DetailAST ast) {
64+
final DetailAST objblock = ast.findFirstToken(TokenTypes.OBJBLOCK);
65+
if (objblock != null) {
66+
this.checkConstructors(objblock);
67+
}
68+
}
69+
70+
/**
71+
* Collects all private constructors in a given object block.
72+
*
73+
* @param objblock Node which contains constructors
74+
* @return List of DetailAST nodes representing the private constructors
75+
*/
76+
private static List<DetailAST> collectPrivateConstructors(final DetailAST objblock) {
77+
final List<DetailAST> prvctors = new LinkedList<>();
78+
final DetailAST firstchld = objblock.getFirstChild();
79+
for (DetailAST child = firstchld; child != null; child = child.getNextSibling()) {
80+
if (child.getType() == TokenTypes.CTOR_DEF && isPrivate(child)) {
81+
prvctors.add(child);
82+
}
83+
}
84+
return prvctors;
85+
}
86+
87+
/**
88+
* Checks if a private constructor is used in the object block.
89+
*
90+
* @param privatector Node representing the private constructor
91+
* @param objblock Node which contains constructors
92+
* @return True if the private constructor is used, False otherwise
93+
*/
94+
private static boolean isPrivateConstructorUsed(
95+
final DetailAST privatector, final DetailAST objblock) {
96+
return
97+
isPrivateCtorUsedInOtherCtors(privatector, objblock)
98+
||
99+
isPrivateCtorUsedInMethods(privatector, objblock);
100+
}
101+
102+
/**
103+
* Checks if a private constructor is used in other constructors.
104+
*
105+
* @param privatector Node representing the private constructor
106+
* @param objblock Node containing constructors
107+
* @return True if the private constructor is used, False otherwise
108+
*/
109+
private static boolean isPrivateCtorUsedInOtherCtors(
110+
final DetailAST privatector, final DetailAST objblock) {
111+
final List<DetailAST> allctors = collectAllConstructors(objblock);
112+
return allctors.stream()
113+
.anyMatch(
114+
otherCtor -> otherCtor != privatector
115+
&&
116+
isCallingConstructor(otherCtor, privatector));
117+
}
118+
119+
/**
120+
* Checks if a private constructor is used in methods of the object block.
121+
*
122+
* @param privatector Node representing the private constructor
123+
* @param objblock Node containing methods
124+
* @return True if the private constructor is used, False otherwise
125+
*/
126+
private static boolean isPrivateCtorUsedInMethods(
127+
final DetailAST privatector, final DetailAST objblock) {
128+
boolean result = false;
129+
final DetailAST firstchld = objblock.getFirstChild();
130+
for (DetailAST child = firstchld; child != null; child = child.getNextSibling()) {
131+
if (child.getType() == TokenTypes.METHOD_DEF
132+
&&
133+
isCallingConstructor(child, privatector)) {
134+
result = true;
135+
break;
136+
}
137+
}
138+
return result;
139+
}
140+
141+
/**
142+
* Collects all constructors in a given object block.
143+
*
144+
* @param objblock Node which contains constructors
145+
* @return List of DetailAST nodes representing all the constructors
146+
*/
147+
private static List<DetailAST> collectAllConstructors(final DetailAST objblock) {
148+
final List<DetailAST> allctors = new LinkedList<>();
149+
final DetailAST firstchld = objblock.getFirstChild();
150+
for (DetailAST child = firstchld; child != null; child = child.getNextSibling()) {
151+
if (child.getType() == TokenTypes.CTOR_DEF) {
152+
allctors.add(child);
153+
}
154+
}
155+
return allctors;
156+
}
157+
158+
/**
159+
* Returns true if specified node has modifiers of type
160+
* <code>PRIVATE</code>.
161+
*
162+
* @param node Node to check.
163+
* @return True if specified node contains modifiers of type
164+
* <code>PRIVATE</code>, else returns <code>false</code>.
165+
*/
166+
private static boolean isPrivate(final DetailAST node) {
167+
final DetailAST modifiers = node.findFirstToken(TokenTypes.MODIFIERS);
168+
return modifiers.getChildCount(TokenTypes.LITERAL_PRIVATE) > 0;
169+
}
170+
171+
private static boolean isCallingConstructor(
172+
final DetailAST methodorctor, final DetailAST targetctor) {
173+
boolean result = false;
174+
final DetailAST body = methodorctor.findFirstToken(TokenTypes.SLIST);
175+
if (body != null) {
176+
DetailAST stmt = body.getFirstChild();
177+
while (stmt != null && !result) {
178+
result = isMatchingConstructorCall(stmt, targetctor);
179+
stmt = stmt.getNextSibling();
180+
}
181+
}
182+
return result;
183+
}
184+
185+
private static boolean isMatchingConstructorCall(
186+
final DetailAST stmt, final DetailAST targetctor) {
187+
return
188+
stmt.getType() == TokenTypes.CTOR_CALL
189+
&&
190+
matchesConstructorSignature(stmt, targetctor);
191+
}
192+
193+
private static boolean matchesConstructorSignature(
194+
final DetailAST callexpr, final DetailAST ctor) {
195+
final DetailAST callparams = callexpr.findFirstToken(TokenTypes.ELIST);
196+
final DetailAST ctorparams = ctor.findFirstToken(TokenTypes.PARAMETERS);
197+
return parametersCountMatch(callparams, ctorparams);
198+
}
199+
200+
private static boolean parametersCountMatch(
201+
final DetailAST callparams, final DetailAST ctorparams) {
202+
final int ncallparams = callparams.getChildCount(TokenTypes.EXPR);
203+
final int nctorparams = ctorparams.getChildCount(TokenTypes.PARAMETER_DEF);
204+
return ncallparams == nctorparams;
205+
}
206+
207+
/**
208+
* Checks if private constructors are used.
209+
* Logs a message if a private constructor is not used.
210+
*
211+
* @param objblock Node which contains constructors
212+
*/
213+
private void checkConstructors(final DetailAST objblock) {
214+
final List<DetailAST> prvctors = collectPrivateConstructors(objblock);
215+
for (final DetailAST ctor : prvctors) {
216+
if (!isPrivateConstructorUsed(ctor, objblock)) {
217+
this.log(ctor.getLineNo(), "Unused private constructor.");
218+
}
219+
}
220+
}
221+
222+
}

0 commit comments

Comments
 (0)