diff --git a/pom.xml b/pom.xml
index ab31cbf7f..c17e77ed2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -176,19 +176,19 @@ OF THE POSSIBILITY OF SUCH DAMAGE.
org.hamcrest
hamcrest-core
- 2.2
+ 3.0
test
org.hamcrest
hamcrest-library
- 2.2
+ 3.0
test
org.slf4j
slf4j-log4j12
- 2.0.13
+ 2.0.16
test
diff --git a/qulice-checkstyle/pom.xml b/qulice-checkstyle/pom.xml
index 2d078b28c..0c0aed8cf 100644
--- a/qulice-checkstyle/pom.xml
+++ b/qulice-checkstyle/pom.xml
@@ -92,7 +92,7 @@ OF THE POSSIBILITY OF SUCH DAMAGE.
org.apache.commons
commons-lang3
- 3.14.0
+ 3.16.0
test
diff --git a/qulice-checkstyle/src/main/java/com/qulice/checkstyle/JavadocTagsCheck.java b/qulice-checkstyle/src/main/java/com/qulice/checkstyle/JavadocTagsCheck.java
index bceeef883..49c27124f 100644
--- a/qulice-checkstyle/src/main/java/com/qulice/checkstyle/JavadocTagsCheck.java
+++ b/qulice-checkstyle/src/main/java/com/qulice/checkstyle/JavadocTagsCheck.java
@@ -131,8 +131,11 @@ public void visitToken(final DetailAST ast) {
* @param text Text to find.
* @return Line number with found text, or -1 if it wasn't found.
*/
- private static int findTrimmedTextUp(final String[] lines,
- final int start, final String text) {
+ private static int findTrimmedTextUp(
+ final String[] lines,
+ final int start,
+ final String text
+ ) {
int found = -1;
for (int pos = start - 1; pos >= 0; pos -= 1) {
if (lines[pos].trim().equals(text)) {
@@ -172,8 +175,13 @@ private static int findCommentEnd(final String[] lines, final int start) {
* @param tag Name of the tag.
* @checkstyle ParameterNumber (3 lines)
*/
- private void findProhibited(final String[] lines, final int start,
- final int cstart, final int cend, final String tag) {
+ private void findProhibited(
+ final String[] lines,
+ final int start,
+ final int cstart,
+ final int cend,
+ final String tag
+ ) {
final List found =
this.findTagLineNum(lines, cstart, cend, tag);
if (!found.isEmpty()) {
@@ -194,8 +202,12 @@ private void findProhibited(final String[] lines, final int start,
* @return Line number with found tag or -1 otherwise.
* @checkstyle ParameterNumber (3 lines)
*/
- private List findTagLineNum(final String[] lines, final int start,
- final int end, final String tag) {
+ private List findTagLineNum(
+ final String[] lines,
+ final int start,
+ final int end,
+ final String tag
+ ) {
final String prefix = String.format(" * @%s ", tag);
final List found = new ArrayList<>(1);
for (int pos = start; pos <= end; pos += 1) {
diff --git a/qulice-checkstyle/src/main/java/com/qulice/checkstyle/MultiLineCommentCheck.java b/qulice-checkstyle/src/main/java/com/qulice/checkstyle/MultiLineCommentCheck.java
index ed51b4eca..7df7235b0 100644
--- a/qulice-checkstyle/src/main/java/com/qulice/checkstyle/MultiLineCommentCheck.java
+++ b/qulice-checkstyle/src/main/java/com/qulice/checkstyle/MultiLineCommentCheck.java
@@ -38,21 +38,26 @@
/**
* Multi line comment checker.
+ * Used by the checkstyle process multiple times as a singleton.
* @since 0.23.1
*/
public final class MultiLineCommentCheck extends AbstractCheck {
/**
* Pattern for check.
+ * It is not final as it is initialized from the configuration.
*/
private Pattern format = Pattern.compile("^$");
/**
* The message to report for a match.
+ * It is not final as it is initialized from the configuration.
*/
private String message = "";
/**
* Comment line.
+ * It is not final because the visitToken method is called many times
+ * during the class under test and the field is reinitialized with a new object.
*/
@SuppressWarnings("PMD.AvoidStringBufferField")
private StringBuilder line;
@@ -96,10 +101,27 @@ public void visitToken(final DetailAST ast) {
}
}
+ /**
+ * The method is called from checkstyle to configure this class.
+ * The parameter is set from the checks.xml file
+ * and
+ * property
+ *
+ * @param fmt Validatig regexp.
+ */
public void setFormat(final String fmt) {
this.format = Pattern.compile(fmt);
}
+ /**
+ * The method is called from checkstyle to configure this class.
+ * The parameter is set from the checks.xml file
+ * and
+ *
+ * property
+ *
+ * @param msg Error message.
+ */
public void setMessage(final String msg) {
this.message = msg;
}
diff --git a/qulice-checkstyle/src/main/java/com/qulice/checkstyle/ProhibitUnusedPrivateConstructorCheck.java b/qulice-checkstyle/src/main/java/com/qulice/checkstyle/ProhibitUnusedPrivateConstructorCheck.java
new file mode 100644
index 000000000..843ec9703
--- /dev/null
+++ b/qulice-checkstyle/src/main/java/com/qulice/checkstyle/ProhibitUnusedPrivateConstructorCheck.java
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2011-2024 Qulice.com
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met: 1) Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer. 2) Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution. 3) Neither the name of the Qulice.com nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
+ * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.qulice.checkstyle;
+
+import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
+import com.puppycrawl.tools.checkstyle.api.DetailAST;
+import com.puppycrawl.tools.checkstyle.api.TokenTypes;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Checks that constructor, declared as private class is used more than once.
+ *
+ * @since 0.3
+ */
+public final class ProhibitUnusedPrivateConstructorCheck extends AbstractCheck {
+
+ @Override
+ public int[] getDefaultTokens() {
+ return new int[] {TokenTypes.CLASS_DEF};
+ }
+
+ @Override
+ public int[] getAcceptableTokens() {
+ return this.getDefaultTokens();
+ }
+
+ @Override
+ public int[] getRequiredTokens() {
+ return this.getDefaultTokens();
+ }
+
+ @Override
+ public void visitToken(final DetailAST ast) {
+ final DetailAST objblock = ast.findFirstToken(TokenTypes.OBJBLOCK);
+ if (objblock != null) {
+ this.checkConstructors(objblock);
+ }
+ }
+
+ /**
+ * Collects all private constructors in a given object block.
+ *
+ * @param objblock Node which contains constructors
+ * @return List of DetailAST nodes representing the private constructors
+ */
+ private static List collectPrivateConstructors(final DetailAST objblock) {
+ final List prvctors = new LinkedList<>();
+ final DetailAST firstchld = objblock.getFirstChild();
+ for (DetailAST child = firstchld; child != null; child = child.getNextSibling()) {
+ if (child.getType() == TokenTypes.CTOR_DEF && isPrivate(child)) {
+ prvctors.add(child);
+ }
+ }
+ return prvctors;
+ }
+
+ /**
+ * Checks if a private constructor is used in the object block.
+ *
+ * @param privatector Node representing the private constructor
+ * @param objblock Node which contains constructors
+ * @return True if the private constructor is used, False otherwise
+ */
+ private static boolean isPrivateConstructorUsed(
+ final DetailAST privatector, final DetailAST objblock) {
+ return
+ isPrivateCtorUsedInOtherCtors(privatector, objblock)
+ ||
+ isPrivateCtorUsedInMethods(privatector, objblock);
+ }
+
+ /**
+ * Checks if a private constructor is used in other constructors.
+ *
+ * @param privatector Node representing the private constructor
+ * @param objblock Node containing constructors
+ * @return True if the private constructor is used, False otherwise
+ */
+ private static boolean isPrivateCtorUsedInOtherCtors(
+ final DetailAST privatector, final DetailAST objblock) {
+ final List allctors = collectAllConstructors(objblock);
+ return allctors.stream()
+ .anyMatch(
+ otherCtor -> otherCtor != privatector
+ &&
+ isCallingConstructor(otherCtor, privatector));
+ }
+
+ /**
+ * Checks if a private constructor is used in methods of the object block.
+ *
+ * @param privatector Node representing the private constructor
+ * @param objblock Node containing methods
+ * @return True if the private constructor is used, False otherwise
+ */
+ private static boolean isPrivateCtorUsedInMethods(
+ final DetailAST privatector, final DetailAST objblock) {
+ boolean result = false;
+ final DetailAST firstchld = objblock.getFirstChild();
+ for (DetailAST child = firstchld; child != null; child = child.getNextSibling()) {
+ if (child.getType() == TokenTypes.METHOD_DEF
+ &&
+ isCallingConstructor(child, privatector)) {
+ result = true;
+ break;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Collects all constructors in a given object block.
+ *
+ * @param objblock Node which contains constructors
+ * @return List of DetailAST nodes representing all the constructors
+ */
+ private static List collectAllConstructors(final DetailAST objblock) {
+ final List allctors = new LinkedList<>();
+ final DetailAST firstchld = objblock.getFirstChild();
+ for (DetailAST child = firstchld; child != null; child = child.getNextSibling()) {
+ if (child.getType() == TokenTypes.CTOR_DEF) {
+ allctors.add(child);
+ }
+ }
+ return allctors;
+ }
+
+ /**
+ * Returns true if specified node has modifiers of type
+ * PRIVATE
.
+ *
+ * @param node Node to check.
+ * @return True if specified node contains modifiers of type
+ * PRIVATE
, else returns false
.
+ */
+ private static boolean isPrivate(final DetailAST node) {
+ final DetailAST modifiers = node.findFirstToken(TokenTypes.MODIFIERS);
+ return modifiers.getChildCount(TokenTypes.LITERAL_PRIVATE) > 0;
+ }
+
+ private static boolean isCallingConstructor(
+ final DetailAST methodorctor, final DetailAST targetctor) {
+ boolean result = false;
+ final DetailAST body = methodorctor.findFirstToken(TokenTypes.SLIST);
+ if (body != null) {
+ DetailAST stmt = body.getFirstChild();
+ while (stmt != null && !result) {
+ result = isMatchingConstructorCall(stmt, targetctor);
+ stmt = stmt.getNextSibling();
+ }
+ }
+ return result;
+ }
+
+ private static boolean isMatchingConstructorCall(
+ final DetailAST stmt, final DetailAST targetctor) {
+ return
+ stmt.getType() == TokenTypes.CTOR_CALL
+ &&
+ matchesConstructorSignature(stmt, targetctor);
+ }
+
+ private static boolean matchesConstructorSignature(
+ final DetailAST callexpr, final DetailAST ctor) {
+ final DetailAST callparams = callexpr.findFirstToken(TokenTypes.ELIST);
+ final DetailAST ctorparams = ctor.findFirstToken(TokenTypes.PARAMETERS);
+ return parametersCountMatch(callparams, ctorparams);
+ }
+
+ private static boolean parametersCountMatch(
+ final DetailAST callparams, final DetailAST ctorparams) {
+ final int ncallparams = callparams.getChildCount(TokenTypes.EXPR);
+ final int nctorparams = ctorparams.getChildCount(TokenTypes.PARAMETER_DEF);
+ return ncallparams == nctorparams;
+ }
+
+ /**
+ * Checks if private constructors are used.
+ * Logs a message if a private constructor is not used.
+ *
+ * @param objblock Node which contains constructors
+ */
+ private void checkConstructors(final DetailAST objblock) {
+ final List prvctors = collectPrivateConstructors(objblock);
+ for (final DetailAST ctor : prvctors) {
+ if (!isPrivateConstructorUsed(ctor, objblock)) {
+ this.log(ctor.getLineNo(), "Unused private constructor.");
+ }
+ }
+ }
+
+}
diff --git a/qulice-checkstyle/src/main/java/com/qulice/checkstyle/RequiredJavaDocTag.java b/qulice-checkstyle/src/main/java/com/qulice/checkstyle/RequiredJavaDocTag.java
index 404be57f8..eddeb63b6 100644
--- a/qulice-checkstyle/src/main/java/com/qulice/checkstyle/RequiredJavaDocTag.java
+++ b/qulice-checkstyle/src/main/java/com/qulice/checkstyle/RequiredJavaDocTag.java
@@ -89,8 +89,11 @@ final class RequiredJavaDocTag {
* @param patt Pattern for checking the contents of a tag in a string.
* @param rep Reference to a method for writing a message to the log.
*/
- RequiredJavaDocTag(final String name, final Pattern patt,
- final Reporter rep) {
+ RequiredJavaDocTag(
+ final String name,
+ final Pattern patt,
+ final Reporter rep
+ ) {
this(
name,
Pattern.compile(
@@ -112,8 +115,12 @@ final class RequiredJavaDocTag {
* @param rep Reference to a method for writing a message to the log.
* @checkstyle ParameterNumberCheck (3 lines)
*/
- RequiredJavaDocTag(final String cname, final Pattern ptag,
- final Pattern patt, final Reporter rep) {
+ RequiredJavaDocTag(
+ final String cname,
+ final Pattern ptag,
+ final Pattern patt,
+ final Reporter rep
+ ) {
this.name = cname;
this.tag = ptag;
this.content = patt;
@@ -126,8 +133,11 @@ final class RequiredJavaDocTag {
* @param start Line number where comment starts.
* @param end Line number where comment ends.
*/
- public void matchTagFormat(final String[] lines, final int start,
- final int end) {
+ public void matchTagFormat(
+ final String[] lines,
+ final int start,
+ final int end
+ ) {
final Map found = new HashMap<>(1);
for (int pos = start; pos <= end; pos += 1) {
final String line = lines[pos];
diff --git a/qulice-checkstyle/src/main/java/com/qulice/checkstyle/SingleLineCommentCheck.java b/qulice-checkstyle/src/main/java/com/qulice/checkstyle/SingleLineCommentCheck.java
index ed7d73cab..c2fe78a36 100644
--- a/qulice-checkstyle/src/main/java/com/qulice/checkstyle/SingleLineCommentCheck.java
+++ b/qulice-checkstyle/src/main/java/com/qulice/checkstyle/SingleLineCommentCheck.java
@@ -45,16 +45,20 @@ public final class SingleLineCommentCheck extends AbstractCheck {
/**
* Pattern for check.
+ * It is not final as it is initialized from the configuration.
*/
private Pattern format = Pattern.compile("^$");
/**
* The message to report for a match.
+ * It is not final as it is initialized from the configuration.
*/
private String message = "";
/**
* Comment line.
+ * It is not final because the visitToken method is called many times
+ * during the class under test and the field is reinitialized with a new object.
*/
@SuppressWarnings("PMD.AvoidStringBufferField")
private StringBuilder line;
@@ -104,10 +108,27 @@ public void visitToken(final DetailAST ast) {
}
}
+ /**
+ * The method is called from checkstyle to configure this class.
+ * The parameter is set from the checks.xml file
+ * and
+ * property
+ *
+ * @param fmt Validatig regexp.
+ */
public void setFormat(final String fmt) {
this.format = Pattern.compile(fmt);
}
+ /**
+ * The method is called from checkstyle to configure this class.
+ * The parameter is set from the checks.xml file
+ * and
+ *
+ * property
+ *
+ * @param msg Error message.
+ */
public void setMessage(final String msg) {
this.message = msg;
}
diff --git a/qulice-checkstyle/src/test/java/com/qulice/checkstyle/ChecksTest.java b/qulice-checkstyle/src/test/java/com/qulice/checkstyle/ChecksTest.java
index e2e4864ff..b5a520d3a 100644
--- a/qulice-checkstyle/src/test/java/com/qulice/checkstyle/ChecksTest.java
+++ b/qulice-checkstyle/src/test/java/com/qulice/checkstyle/ChecksTest.java
@@ -196,7 +196,8 @@ private static Stream checks() {
"JavadocTagsCheck",
"ProhibitNonFinalClassesCheck",
"QualifyInnerClassCheck",
- "CommentCheck"
+ "CommentCheck",
+ "ProhibitUnusedPrivateConstructorCheck"
).map(s -> String.format("ChecksTest/%s", s));
}
diff --git a/qulice-checkstyle/src/test/java/com/qulice/checkstyle/RequiredJavaDocTagTest.java b/qulice-checkstyle/src/test/java/com/qulice/checkstyle/RequiredJavaDocTagTest.java
index 8a8b48d9a..f8f83fe0c 100644
--- a/qulice-checkstyle/src/test/java/com/qulice/checkstyle/RequiredJavaDocTagTest.java
+++ b/qulice-checkstyle/src/test/java/com/qulice/checkstyle/RequiredJavaDocTagTest.java
@@ -32,9 +32,13 @@
import java.text.MessageFormat;
import java.util.regex.Pattern;
+import java.util.stream.Stream;
+import org.hamcrest.Matcher;
import org.hamcrest.MatcherAssert;
import org.hamcrest.Matchers;
-import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
/**
* Test case for {@link RequiredJavaDocTag} class.
@@ -58,50 +62,42 @@ final class RequiredJavaDocTagTest {
this.writer
);
- @Test
- void success() {
- final String[] lines = {" *", " * @since 0.3", " *"};
+ @ParameterizedTest
+ @MethodSource("params")
+ void success(final String[] lines, final String reason, final Matcher expected) {
this.tag.matchTagFormat(lines, 0, 2);
MatcherAssert.assertThat(
- "Empty string expected",
+ reason,
this.writer.formattedMessage(),
- Matchers.emptyString()
+ expected
);
}
- @Test
- void successWithSpaces() {
- final String[] lines = {" *", " * @since 0.3", " *"};
- this.tag.matchTagFormat(lines, 0, 2);
- MatcherAssert.assertThat(
- "Empty string expected",
- this.writer.formattedMessage(),
- Matchers.emptyString()
- );
- }
-
- @Test
- void tagNotFound() {
- final String[] lines = {" *", " * @sinc 0.3", " *"};
- this.tag.matchTagFormat(lines, 0, 2);
- MatcherAssert.assertThat(
- "Expected tag not found",
- this.writer.formattedMessage(),
- Matchers.equalTo("Missing '@since' tag in class/interface comment")
- );
- }
-
- @Test
- void tagNotMatched() {
- final String[] lines = {" *", " * @since 0.3.4.4.", " *"};
- this.tag.matchTagFormat(lines, 0, 2);
- MatcherAssert.assertThat(
- "Regular expression non-match expected",
- this.writer.formattedMessage(),
- Matchers.equalTo(
- String.format(
- "Tag text '0.3.4.4.' does not match the pattern '%s'",
- "^\\d+(\\.\\d+){1,2}(\\.[0-9A-Za-z-]+(\\.[0-9A-Za-z-]+)*)?$"
+ private static Stream params() {
+ return Stream.of(
+ Arguments.arguments(
+ new String[] {" *", " * @since 0.3", " *"},
+ "Empty string expected",
+ Matchers.emptyString()
+ ),
+ Arguments.arguments(
+ new String[] {" *", " * @since 0.3", " *"},
+ "Empty string expected",
+ Matchers.emptyString()
+ ),
+ Arguments.arguments(
+ new String[] {" *", " * @sinc 0.3", " *"},
+ "Expected tag not found",
+ Matchers.equalTo("Missing '@since' tag in class/interface comment")
+ ),
+ Arguments.arguments(
+ new String[] {" *", " * @since 0.3.4.4.", " *"},
+ "Regular expression non-match expected",
+ Matchers.equalTo(
+ String.format(
+ "Tag text '0.3.4.4.' does not match the pattern '%s'",
+ "^\\d+(\\.\\d+){1,2}(\\.[0-9A-Za-z-]+(\\.[0-9A-Za-z-]+)*)?$"
+ )
)
)
);
diff --git a/qulice-checkstyle/src/test/resources/com/qulice/checkstyle/ChecksTest/CommentCheck/Valid.java b/qulice-checkstyle/src/test/resources/com/qulice/checkstyle/ChecksTest/CommentCheck/Valid.java
index c2933bf27..a34f532cb 100644
--- a/qulice-checkstyle/src/test/resources/com/qulice/checkstyle/ChecksTest/CommentCheck/Valid.java
+++ b/qulice-checkstyle/src/test/resources/com/qulice/checkstyle/ChecksTest/CommentCheck/Valid.java
@@ -12,14 +12,29 @@ public final class Valid {
/**
* Valid multiline comment
*/
- private static String VALID_CSTYLE_LITERAL = "/* C-style comment */";
+ private static String VALID_CSTYLE_LITERAL = " /* C-style comment */";
+
+ /**
+ * Valid multiline comment starts with two spaces
+ */
+ private static String VALID_CSTYLE_LITERAL_WITH_TWO_SP = " /* C-style comment */";
/** Valid single-line comment. */
private static String SINGLE_LINE_LITERAL =
- "/** first sentence in a comment should start with a capital letter */";
+ " /** first sentence in a comment should start with a capital letter */";
+
+ /** Valid single-line comment starts with two spaces. */
+ private static String SINGLE_LINE_LITERAL_WITH_TWO_SP =
+ " /** first sentence in a comment should start with a capital letter */";
/** Valid multiline comment
*/
public void main() {
}
+
+ /** Valid multiline comment starts with two spaces
+ */
+ public void mainTwo() {
+ }
+
}
diff --git a/qulice-checkstyle/src/test/resources/com/qulice/checkstyle/ChecksTest/ProhibitUnusedPrivateConstructorCheck/Invalid.java b/qulice-checkstyle/src/test/resources/com/qulice/checkstyle/ChecksTest/ProhibitUnusedPrivateConstructorCheck/Invalid.java
new file mode 100644
index 000000000..4e776fbbd
--- /dev/null
+++ b/qulice-checkstyle/src/test/resources/com/qulice/checkstyle/ChecksTest/ProhibitUnusedPrivateConstructorCheck/Invalid.java
@@ -0,0 +1,23 @@
+package com.qulice.checkstyle.ChecksTest.ProhibitUnusedPrivateConstructorCheck;
+
+/*
+ * This is not a real Java class. It won't be compiled ever. It is used
+ * only as a text resource in integration.ChecksIT.
+ */
+public final class Invalid {
+
+ private final String s;
+
+ public Invalid(String s) {
+ this.s = s;
+ }
+
+ private Invalid(int x) {
+ this(String.valueOf(x));
+ }
+
+ public static Invalid create() {
+ return new Invalid("0");
+ }
+
+}
\ No newline at end of file
diff --git a/qulice-checkstyle/src/test/resources/com/qulice/checkstyle/ChecksTest/ProhibitUnusedPrivateConstructorCheck/Valid.java b/qulice-checkstyle/src/test/resources/com/qulice/checkstyle/ChecksTest/ProhibitUnusedPrivateConstructorCheck/Valid.java
new file mode 100644
index 000000000..2943502be
--- /dev/null
+++ b/qulice-checkstyle/src/test/resources/com/qulice/checkstyle/ChecksTest/ProhibitUnusedPrivateConstructorCheck/Valid.java
@@ -0,0 +1,18 @@
+package com.qulice.checkstyle.ChecksTest.ProhibitUnusedPrivateConstructorCheck;
+/*
+ * This is not a real Java class. It won't be compiled ever. It is used
+ * only as a text resource in integration.ChecksIT.
+ */
+public final class Valid {
+
+ private final int i;
+
+ public Valid(final String s) {
+ this(s.length());
+ }
+
+ private Valid(int i) {
+ this.i = i;
+ }
+
+}
\ No newline at end of file
diff --git a/qulice-checkstyle/src/test/resources/com/qulice/checkstyle/ChecksTest/ProhibitUnusedPrivateConstructorCheck/config.xml b/qulice-checkstyle/src/test/resources/com/qulice/checkstyle/ChecksTest/ProhibitUnusedPrivateConstructorCheck/config.xml
new file mode 100644
index 000000000..35ff7fa56
--- /dev/null
+++ b/qulice-checkstyle/src/test/resources/com/qulice/checkstyle/ChecksTest/ProhibitUnusedPrivateConstructorCheck/config.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
diff --git a/qulice-checkstyle/src/test/resources/com/qulice/checkstyle/ChecksTest/ProhibitUnusedPrivateConstructorCheck/violations.txt b/qulice-checkstyle/src/test/resources/com/qulice/checkstyle/ChecksTest/ProhibitUnusedPrivateConstructorCheck/violations.txt
new file mode 100644
index 000000000..a03db43b0
--- /dev/null
+++ b/qulice-checkstyle/src/test/resources/com/qulice/checkstyle/ChecksTest/ProhibitUnusedPrivateConstructorCheck/violations.txt
@@ -0,0 +1 @@
+15:Unused private constructor.
\ No newline at end of file
diff --git a/qulice-checkstyle/src/test/resources/com/qulice/checkstyle/ValidSingleLineCommentCheck.java b/qulice-checkstyle/src/test/resources/com/qulice/checkstyle/ValidSingleLineCommentCheck.java
index 69d08abfb..3732c86c6 100644
--- a/qulice-checkstyle/src/test/resources/com/qulice/checkstyle/ValidSingleLineCommentCheck.java
+++ b/qulice-checkstyle/src/test/resources/com/qulice/checkstyle/ValidSingleLineCommentCheck.java
@@ -25,6 +25,8 @@ public final class ValidSingleLineCommentCheck {
/**
* Valid multi line literal.
+ * We need to add the @checkstyle ArrayTrailingCommaCheck to pass the test
+ * {@link com.qulice.checkstyle.CheckstyleValidatorTest#acceptsValidSingleLineComment}
* @checkstyle ArrayTrailingCommaCheck (6 lines)
*/
public static final String[] MULTILINE_LITERAL = {
diff --git a/qulice-maven-plugin/src/main/java/com/qulice/maven/CheckMojo.java b/qulice-maven-plugin/src/main/java/com/qulice/maven/CheckMojo.java
index 1f227d12c..6edd804af 100644
--- a/qulice-maven-plugin/src/main/java/com/qulice/maven/CheckMojo.java
+++ b/qulice-maven-plugin/src/main/java/com/qulice/maven/CheckMojo.java
@@ -58,7 +58,8 @@
* @since 0.3
*/
@Mojo(name = "check", defaultPhase = LifecyclePhase.VERIFY,
- requiresDependencyResolution = ResolutionScope.TEST)
+ requiresDependencyResolution = ResolutionScope.TEST,
+ threadSafe = true)
public final class CheckMojo extends AbstractQuliceMojo {
/**