From 9a9d34e57aa02e8f925456164282a45746016d65 Mon Sep 17 00:00:00 2001 From: "Vladimir.Shapkin" Date: Tue, 9 Jul 2024 19:49:09 +0400 Subject: [PATCH 1/9] added flag 'threadSafe = true' to CheckMojo class --- .../src/main/java/com/qulice/maven/CheckMojo.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 { /** From 3ed179aad9ab4cd3667d496fda7378e77afd91fe Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 17 Jul 2024 21:37:20 +0000 Subject: [PATCH 2/9] Update dependency org.apache.commons:commons-lang3 to v3.15.0 --- qulice-checkstyle/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qulice-checkstyle/pom.xml b/qulice-checkstyle/pom.xml index 2d078b28c..959b9bc41 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.15.0 test From b72b7af6e06a4b4af034ee161c6945c2402269c1 Mon Sep 17 00:00:00 2001 From: Vladislav Yevtushenko Date: Wed, 31 Jul 2024 20:38:58 +0500 Subject: [PATCH 3/9] Add ProhibitUnusedPrivateConstructorCheck Implemented a new check to ensure private constructors are used at least once. Included test cases and configuration to validate this new check. --- ...ProhibitUnusedPrivateConstructorCheck.java | 222 ++++++++++++++++++ .../com/qulice/checkstyle/ChecksTest.java | 3 +- .../Invalid.java | 23 ++ .../Valid.java | 18 ++ .../config.xml | 37 +++ .../violations.txt | 1 + 6 files changed, 303 insertions(+), 1 deletion(-) create mode 100644 qulice-checkstyle/src/main/java/com/qulice/checkstyle/ProhibitUnusedPrivateConstructorCheck.java create mode 100644 qulice-checkstyle/src/test/resources/com/qulice/checkstyle/ChecksTest/ProhibitUnusedPrivateConstructorCheck/Invalid.java create mode 100644 qulice-checkstyle/src/test/resources/com/qulice/checkstyle/ChecksTest/ProhibitUnusedPrivateConstructorCheck/Valid.java create mode 100644 qulice-checkstyle/src/test/resources/com/qulice/checkstyle/ChecksTest/ProhibitUnusedPrivateConstructorCheck/config.xml create mode 100644 qulice-checkstyle/src/test/resources/com/qulice/checkstyle/ChecksTest/ProhibitUnusedPrivateConstructorCheck/violations.txt 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/test/java/com/qulice/checkstyle/ChecksTest.java b/qulice-checkstyle/src/test/java/com/qulice/checkstyle/ChecksTest.java index 0230decff..620d2b5fc 100644 --- a/qulice-checkstyle/src/test/java/com/qulice/checkstyle/ChecksTest.java +++ b/qulice-checkstyle/src/test/java/com/qulice/checkstyle/ChecksTest.java @@ -195,7 +195,8 @@ private static Stream checks() { "JavadocEmptyLineCheck", "JavadocTagsCheck", "ProhibitNonFinalClassesCheck", - "QualifyInnerClassCheck" + "QualifyInnerClassCheck", + "ProhibitUnusedPrivateConstructorCheck" ).map(s -> String.format("ChecksTest/%s", s)); } 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..fba41cc40 --- /dev/null +++ b/qulice-checkstyle/src/test/resources/com/qulice/checkstyle/ChecksTest/ProhibitUnusedPrivateConstructorCheck/config.xml @@ -0,0 +1,37 @@ + + + + + + + + \ No newline at end of file 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 From ebab0f8b0c05e345bf48b1f6b965191c2201dd96 Mon Sep 17 00:00:00 2001 From: Vladislav Yevtushenko Date: Thu, 1 Aug 2024 11:38:23 +0500 Subject: [PATCH 4/9] Fix missing newline at end of config.xml This change ensures the config.xml file has a newline at the end. --- .../ChecksTest/ProhibitUnusedPrivateConstructorCheck/config.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index fba41cc40..35ff7fa56 100644 --- 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 @@ -34,4 +34,4 @@ OF THE POSSIBILITY OF SUCH DAMAGE. - \ No newline at end of file + From 27b6b9958cd9e8f8a8fd9385201c6745cfa7294c Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 1 Aug 2024 13:06:32 +0000 Subject: [PATCH 5/9] Update javahamcrest monorepo to v3 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index ab31cbf7f..953a13f44 100644 --- a/pom.xml +++ b/pom.xml @@ -176,13 +176,13 @@ OF THE POSSIBILITY OF SUCH DAMAGE. org.hamcrest hamcrest-core - 2.2 + 3.0 test org.hamcrest hamcrest-library - 2.2 + 3.0 test From 149ad45a9ab4aa4e6e67c9e3f4fafecba9b5bfea Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 6 Aug 2024 23:31:36 +0000 Subject: [PATCH 6/9] Update dependency org.slf4j:slf4j-log4j12 to v2.0.14 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 953a13f44..8811348dd 100644 --- a/pom.xml +++ b/pom.xml @@ -188,7 +188,7 @@ OF THE POSSIBILITY OF SUCH DAMAGE. org.slf4j slf4j-log4j12 - 2.0.13 + 2.0.14 test From 81566cc574ef77f29b932411958f17c59105bc63 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 7 Aug 2024 15:55:16 +0000 Subject: [PATCH 7/9] Update dependency org.apache.commons:commons-lang3 to v3.16.0 --- qulice-checkstyle/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qulice-checkstyle/pom.xml b/qulice-checkstyle/pom.xml index 959b9bc41..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.15.0 + 3.16.0 test From f62d7c296d507d1c45ce2a852ee53c495b2e56ba Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 8 Aug 2024 15:12:11 +0000 Subject: [PATCH 8/9] Update dependency org.slf4j:slf4j-log4j12 to v2.0.15 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8811348dd..76e1f5b4d 100644 --- a/pom.xml +++ b/pom.xml @@ -188,7 +188,7 @@ OF THE POSSIBILITY OF SUCH DAMAGE. org.slf4j slf4j-log4j12 - 2.0.14 + 2.0.15 test From b835069839006baf9d6c96e95fa1bff9b33cd235 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sat, 10 Aug 2024 10:42:20 +0000 Subject: [PATCH 9/9] Update dependency org.slf4j:slf4j-log4j12 to v2.0.16 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 76e1f5b4d..c17e77ed2 100644 --- a/pom.xml +++ b/pom.xml @@ -188,7 +188,7 @@ OF THE POSSIBILITY OF SUCH DAMAGE. org.slf4j slf4j-log4j12 - 2.0.15 + 2.0.16 test