From b8615479028fb40523376d6093db01df9db6876a Mon Sep 17 00:00:00 2001 From: Mauryan Kansara Date: Sun, 31 Mar 2024 18:58:41 +0530 Subject: [PATCH] Issue #14726: new check: ConstructorsDeclarationGroupingCheck --- .../checker-lock-tainting-suppressions.xml | 10 ++ config/checkstyle-checks.xml | 1 + ...checkstyle-non-main-files-suppressions.xml | 2 + config/checkstyle-resources-suppressions.xml | 2 + config/jsoref-spellchecker/whitelist.words | 1 + config/linkcheck-suppressions.txt | 2 + pom.xml | 2 + ...onConstructorsDeclarationGroupingTest.java | 138 +++++++++++++++ ...onstructorsDeclarationGroupingRecords.java | 16 ++ ...hConstructorsDeclarationGroupingClass.java | 11 ++ ...thConstructorsDeclarationGroupingEnum.java | 13 ++ .../checkstyle/PackageObjectFactory.java | 2 + .../ConstructorsDeclarationGroupingCheck.java | 161 ++++++++++++++++++ .../checks/coding/messages.properties | 1 + .../checks/coding/messages_de.properties | 1 + .../checks/coding/messages_es.properties | 1 + .../checks/coding/messages_fi.properties | 1 + .../checks/coding/messages_fr.properties | 1 + .../checks/coding/messages_ja.properties | 1 + .../checks/coding/messages_pt.properties | 1 + .../checks/coding/messages_ru.properties | 1 + .../checks/coding/messages_tr.properties | 1 + .../checks/coding/messages_zh.properties | 1 + .../ConstructorsDeclarationGroupingCheck.xml | 25 +++ src/site/site.xml | 2 + ...structorsDeclarationGroupingCheckTest.java | 84 +++++++++ .../checkstyle/meta/XmlMetaReaderTest.java | 6 +- ...onstructorsDeclarationGroupingRecords.java | 80 +++++++++ .../InputConstructorsDeclarationGrouping.java | 130 ++++++++++++++ .../Example1.java | 42 +++++ .../Example2.java | 43 +++++ src/xdocs/checks.xml | 8 + .../constructorsdeclarationgrouping.xml | 143 ++++++++++++++++ ...nstructorsdeclarationgrouping.xml.template | 82 +++++++++ src/xdocs/checks/coding/index.xml | 10 ++ 35 files changed, 1023 insertions(+), 3 deletions(-) create mode 100644 src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionConstructorsDeclarationGroupingTest.java create mode 100644 src/it/resources-noncompilable/org/checkstyle/suppressionxpathfilter/constructorsdeclarationgrouping/InputXpathConstructorsDeclarationGroupingRecords.java create mode 100644 src/it/resources/org/checkstyle/suppressionxpathfilter/constructorsdeclarationgrouping/InputXpathConstructorsDeclarationGroupingClass.java create mode 100644 src/it/resources/org/checkstyle/suppressionxpathfilter/constructorsdeclarationgrouping/InputXpathConstructorsDeclarationGroupingEnum.java create mode 100644 src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/ConstructorsDeclarationGroupingCheck.java create mode 100644 src/main/resources/com/puppycrawl/tools/checkstyle/meta/checks/coding/ConstructorsDeclarationGroupingCheck.xml create mode 100644 src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/ConstructorsDeclarationGroupingCheckTest.java create mode 100644 src/test/resources-noncompilable/com/puppycrawl/tools/checkstyle/checks/coding/constructorsdeclarationgrouping/InputConstructorsDeclarationGroupingRecords.java create mode 100644 src/test/resources/com/puppycrawl/tools/checkstyle/checks/coding/constructorsdeclarationgrouping/InputConstructorsDeclarationGrouping.java create mode 100644 src/xdocs-examples/resources/com/puppycrawl/tools/checkstyle/checks/coding/constructorsdeclarationgrouping/Example1.java create mode 100644 src/xdocs-examples/resources/com/puppycrawl/tools/checkstyle/checks/coding/constructorsdeclarationgrouping/Example2.java create mode 100644 src/xdocs/checks/coding/constructorsdeclarationgrouping.xml create mode 100644 src/xdocs/checks/coding/constructorsdeclarationgrouping.xml.template diff --git a/config/checker-framework-suppressions/checker-lock-tainting-suppressions.xml b/config/checker-framework-suppressions/checker-lock-tainting-suppressions.xml index c36ad2874bc..e732b8b1223 100644 --- a/config/checker-framework-suppressions/checker-lock-tainting-suppressions.xml +++ b/config/checker-framework-suppressions/checker-lock-tainting-suppressions.xml @@ -447,6 +447,16 @@ + + src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/ConstructorsDeclarationGroupingCheck.java + type.arguments.not.inferred + Could not infer type arguments for Optional.map + .map(children::indexOf); +
+ unsatisfiable constraint: @GuardedBy DetailAST <: @GuardSatisfied Object +
+
+ src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/ModifiedControlVariableCheck.java methodref.param diff --git a/config/checkstyle-checks.xml b/config/checkstyle-checks.xml index 90ebb258732..042696f8e49 100644 --- a/config/checkstyle-checks.xml +++ b/config/checkstyle-checks.xml @@ -368,6 +368,7 @@ + diff --git a/config/checkstyle-non-main-files-suppressions.xml b/config/checkstyle-non-main-files-suppressions.xml index 619da4641e0..57063d40aa3 100644 --- a/config/checkstyle-non-main-files-suppressions.xml +++ b/config/checkstyle-non-main-files-suppressions.xml @@ -210,6 +210,8 @@ files="src[\\/]xdocs[\\/]checks[\\/]coding[\\/]avoidinlineconditionals.xml.template"/> + + #%3Cinit%3E(): doesn't exist. #%3Cinit%3E(): doesn't exist. #%3Cinit%3E(): doesn't exist. +#%3Cinit%3E(): doesn't exist. #%3Cinit%3E(): doesn't exist. #%3Cinit%3E(): doesn't exist. #%3Cinit%3E(): doesn't exist. @@ -951,6 +952,7 @@ com/puppycrawl/tools/checkstyle/checks/coding/AvoidDoubleBraceInitializationCheck.html#%3Cinit%3E(): doesn't exist. com/puppycrawl/tools/checkstyle/checks/coding/AvoidInlineConditionalsCheck.html#%3Cinit%3E(): doesn't exist. com/puppycrawl/tools/checkstyle/checks/coding/AvoidNoArgumentSuperConstructorCallCheck.html#%3Cinit%3E(): doesn't exist. +com/puppycrawl/tools/checkstyle/checks/coding/ConstructorsDeclarationGroupingCheck.html#%3Cinit%3E(): doesn't exist. com/puppycrawl/tools/checkstyle/checks/coding/CovariantEqualsCheck.html#%3Cinit%3E(): doesn't exist. com/puppycrawl/tools/checkstyle/checks/coding/DeclarationOrderCheck.ScopeState.html#%3Cinit%3E(): doesn't exist. com/puppycrawl/tools/checkstyle/checks/coding/DeclarationOrderCheck.html#%3Cinit%3E(): doesn't exist. diff --git a/pom.xml b/pom.xml index 999afe1eace..bda93125b5a 100644 --- a/pom.xml +++ b/pom.xml @@ -3264,6 +3264,7 @@ com.puppycrawl.tools.checkstyle.checks.coding.AvoidDoubleBraceInitializationCheck* com.puppycrawl.tools.checkstyle.checks.coding.AvoidInlineConditionalsCheck* com.puppycrawl.tools.checkstyle.checks.coding.AvoidNoArgumentSuperConstructorCallCheck* + com.puppycrawl.tools.checkstyle.checks.coding.ConstructorsDeclarationGroupingCheck* com.puppycrawl.tools.checkstyle.checks.coding.CovariantEqualsCheck* com.puppycrawl.tools.checkstyle.checks.coding.DeclarationOrderCheck* com.puppycrawl.tools.checkstyle.checks.coding.DefaultComesLastCheck* @@ -3288,6 +3289,7 @@ com.puppycrawl.tools.checkstyle.checks.coding.AvoidDoubleBraceInitializationCheckTest com.puppycrawl.tools.checkstyle.checks.coding.AvoidInlineConditionalsCheckTest com.puppycrawl.tools.checkstyle.checks.coding.AvoidNoArgumentSuperConstructorCallCheckTest + com.puppycrawl.tools.checkstyle.checks.coding.ConstructorsDeclarationGroupingCheckTest com.puppycrawl.tools.checkstyle.checks.coding.CovariantEqualsCheckTest com.puppycrawl.tools.checkstyle.checks.coding.DeclarationOrderCheckTest com.puppycrawl.tools.checkstyle.checks.coding.DefaultComesLastCheckTest diff --git a/src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionConstructorsDeclarationGroupingTest.java b/src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionConstructorsDeclarationGroupingTest.java new file mode 100644 index 00000000000..6d054d2388c --- /dev/null +++ b/src/it/java/org/checkstyle/suppressionxpathfilter/XpathRegressionConstructorsDeclarationGroupingTest.java @@ -0,0 +1,138 @@ +/////////////////////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code and other text files for adherence to a set of rules. +// Copyright (C) 2001-2024 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package org.checkstyle.suppressionxpathfilter; + +import java.io.File; +import java.util.Arrays; +import java.util.List; + +import org.junit.jupiter.api.Test; + +import com.puppycrawl.tools.checkstyle.DefaultConfiguration; +import com.puppycrawl.tools.checkstyle.checks.coding.ConstructorsDeclarationGroupingCheck; + +public class XpathRegressionConstructorsDeclarationGroupingTest extends AbstractXpathTestSupport { + + private final Class clazz = + ConstructorsDeclarationGroupingCheck.class; + + @Override + protected String getCheckName() { + return clazz.getSimpleName(); + } + + @Test + public void testClass() throws Exception { + final File fileToProcess = new File( + getPath("InputXpathConstructorsDeclarationGroupingClass.java")); + + final DefaultConfiguration moduleConfig = createModuleConfig(clazz); + + final String[] expectedViolation = { + "10:5: " + getCheckMessage(clazz, + ConstructorsDeclarationGroupingCheck.MSG_KEY, 6), + }; + + final List expectedXpathQueries = Arrays.asList( + "/COMPILATION_UNIT/CLASS_DEF[./IDENT" + + "[@text='InputXpathConstructorsDeclarationGroupingClass']]" + + "/OBJBLOCK/CTOR_DEF[./IDENT" + + "[@text='InputXpathConstructorsDeclarationGroupingClass']]", + "/COMPILATION_UNIT/CLASS_DEF[./IDENT" + + "[@text='InputXpathConstructorsDeclarationGroupingClass']]" + + "/OBJBLOCK/CTOR_DEF[./IDENT" + + "[@text='InputXpathConstructorsDeclarationGroupingClass']]" + + "/MODIFIERS", + "/COMPILATION_UNIT/CLASS_DEF[./IDENT" + + "[@text='InputXpathConstructorsDeclarationGroupingClass']]" + + "/OBJBLOCK/CTOR_DEF/IDENT" + + "[@text='InputXpathConstructorsDeclarationGroupingClass']" + + ); + + runVerifications(moduleConfig, fileToProcess, expectedViolation, expectedXpathQueries); + } + + @Test + public void testEnum() throws Exception { + final File fileToProcess = new File( + getPath("InputXpathConstructorsDeclarationGroupingEnum.java")); + + final DefaultConfiguration moduleConfig = createModuleConfig(clazz); + + final String[] expectedViolation = { + "12:5: " + getCheckMessage(clazz, + ConstructorsDeclarationGroupingCheck.MSG_KEY, 8), + }; + + final List expectedXpathQueries = Arrays.asList( + "/COMPILATION_UNIT/ENUM_DEF[./IDENT" + + "[@text='InputXpathConstructorsDeclarationGroupingEnum']]" + + "/OBJBLOCK/CTOR_DEF" + + "[./IDENT[@text='InputXpathConstructorsDeclarationGroupingEnum']]", + + "/COMPILATION_UNIT/ENUM_DEF[./IDENT" + + "[@text='InputXpathConstructorsDeclarationGroupingEnum']]" + + "/OBJBLOCK/CTOR_DEF" + + "[./IDENT[@text='InputXpathConstructorsDeclarationGroupingEnum']]" + + "/MODIFIERS", + + "/COMPILATION_UNIT/ENUM_DEF[./IDENT" + + "[@text='InputXpathConstructorsDeclarationGroupingEnum']]" + + "/OBJBLOCK/CTOR_DEF/IDENT" + + "[@text='InputXpathConstructorsDeclarationGroupingEnum']" + ); + + runVerifications(moduleConfig, fileToProcess, expectedViolation, expectedXpathQueries); + } + + @Test + public void testRecords() throws Exception { + final File fileToProcess = new File( + getNonCompilablePath("InputXpathConstructorsDeclarationGroupingRecords.java")); + + final DefaultConfiguration moduleConfig = createModuleConfig(clazz); + + final String[] expectedViolation = { + "14:5: " + getCheckMessage(clazz, + ConstructorsDeclarationGroupingCheck.MSG_KEY, 8), + }; + + final List expectedXpathQueries = Arrays.asList( + "/COMPILATION_UNIT/CLASS_DEF[./IDENT" + + "[@text='InputXpathConstructorsDeclarationGroupingRecords']]" + + "/OBJBLOCK/RECORD_DEF[./IDENT[@text='MyRecord']]" + + "/OBJBLOCK/COMPACT_CTOR_DEF[./IDENT[@text='MyRecord']]", + + "/COMPILATION_UNIT/CLASS_DEF[./IDENT" + + "[@text='InputXpathConstructorsDeclarationGroupingRecords']]" + + "/OBJBLOCK/RECORD_DEF[./IDENT[@text='MyRecord']]" + + "/OBJBLOCK/COMPACT_CTOR_DEF[./IDENT[@text='MyRecord']]/MODIFIERS", + + "/COMPILATION_UNIT/CLASS_DEF[./IDENT" + + "[@text='InputXpathConstructorsDeclarationGroupingRecords']]" + + "/OBJBLOCK/RECORD_DEF[./IDENT[@text='MyRecord']]" + + "/OBJBLOCK/COMPACT_CTOR_DEF[./IDENT[@text='MyRecord']]" + + "/MODIFIERS/LITERAL_PUBLIC" + ); + + runVerifications(moduleConfig, fileToProcess, expectedViolation, expectedXpathQueries); + } +} diff --git a/src/it/resources-noncompilable/org/checkstyle/suppressionxpathfilter/constructorsdeclarationgrouping/InputXpathConstructorsDeclarationGroupingRecords.java b/src/it/resources-noncompilable/org/checkstyle/suppressionxpathfilter/constructorsdeclarationgrouping/InputXpathConstructorsDeclarationGroupingRecords.java new file mode 100644 index 00000000000..bf12fe5fd82 --- /dev/null +++ b/src/it/resources-noncompilable/org/checkstyle/suppressionxpathfilter/constructorsdeclarationgrouping/InputXpathConstructorsDeclarationGroupingRecords.java @@ -0,0 +1,16 @@ +//non-compiled with javac: Compilable with Java14 + +package org.checkstyle.suppressionxpathfilter.constructorsdeclarationgrouping; + +public class InputXpathConstructorsDeclarationGroupingRecords { + public record MyRecord(int x, int y) { + + public MyRecord(int a) { + this(a,a); + } + + void foo() {} + + public MyRecord {} // warn + } +} diff --git a/src/it/resources/org/checkstyle/suppressionxpathfilter/constructorsdeclarationgrouping/InputXpathConstructorsDeclarationGroupingClass.java b/src/it/resources/org/checkstyle/suppressionxpathfilter/constructorsdeclarationgrouping/InputXpathConstructorsDeclarationGroupingClass.java new file mode 100644 index 00000000000..925a9881163 --- /dev/null +++ b/src/it/resources/org/checkstyle/suppressionxpathfilter/constructorsdeclarationgrouping/InputXpathConstructorsDeclarationGroupingClass.java @@ -0,0 +1,11 @@ +package org.checkstyle.suppressionxpathfilter.constructorsdeclarationgrouping; + +public class InputXpathConstructorsDeclarationGroupingClass { + InputXpathConstructorsDeclarationGroupingClass() {} + + InputXpathConstructorsDeclarationGroupingClass(int a) {} + + int x; + + InputXpathConstructorsDeclarationGroupingClass(String str) {} // warn +} diff --git a/src/it/resources/org/checkstyle/suppressionxpathfilter/constructorsdeclarationgrouping/InputXpathConstructorsDeclarationGroupingEnum.java b/src/it/resources/org/checkstyle/suppressionxpathfilter/constructorsdeclarationgrouping/InputXpathConstructorsDeclarationGroupingEnum.java new file mode 100644 index 00000000000..5b41b807e06 --- /dev/null +++ b/src/it/resources/org/checkstyle/suppressionxpathfilter/constructorsdeclarationgrouping/InputXpathConstructorsDeclarationGroupingEnum.java @@ -0,0 +1,13 @@ +package org.checkstyle.suppressionxpathfilter.constructorsdeclarationgrouping; + +public enum InputXpathConstructorsDeclarationGroupingEnum { + ONE; + + InputXpathConstructorsDeclarationGroupingEnum() {} + + InputXpathConstructorsDeclarationGroupingEnum(String str) {} + + int f; + + InputXpathConstructorsDeclarationGroupingEnum(int x) {} // warn +} diff --git a/src/main/java/com/puppycrawl/tools/checkstyle/PackageObjectFactory.java b/src/main/java/com/puppycrawl/tools/checkstyle/PackageObjectFactory.java index f859c5ed2f6..d0cab1e2c56 100644 --- a/src/main/java/com/puppycrawl/tools/checkstyle/PackageObjectFactory.java +++ b/src/main/java/com/puppycrawl/tools/checkstyle/PackageObjectFactory.java @@ -495,6 +495,8 @@ private static void fillChecksFromCodingPackage() { BASE_PACKAGE + ".checks.coding.AvoidInlineConditionalsCheck"); NAME_TO_FULL_MODULE_NAME.put("AvoidNoArgumentSuperConstructorCallCheck", BASE_PACKAGE + ".checks.coding.AvoidNoArgumentSuperConstructorCallCheck"); + NAME_TO_FULL_MODULE_NAME.put("ConstructorsDeclarationGroupingCheck", + BASE_PACKAGE + ".checks.coding.ConstructorsDeclarationGroupingCheck"); NAME_TO_FULL_MODULE_NAME.put("CovariantEqualsCheck", BASE_PACKAGE + ".checks.coding.CovariantEqualsCheck"); NAME_TO_FULL_MODULE_NAME.put("DeclarationOrderCheck", diff --git a/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/ConstructorsDeclarationGroupingCheck.java b/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/ConstructorsDeclarationGroupingCheck.java new file mode 100644 index 00000000000..f226d2de4f8 --- /dev/null +++ b/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/ConstructorsDeclarationGroupingCheck.java @@ -0,0 +1,161 @@ +/////////////////////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code and other text files for adherence to a set of rules. +// Copyright (C) 2001-2024 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package com.puppycrawl.tools.checkstyle.checks.coding; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; +import com.puppycrawl.tools.checkstyle.api.DetailAST; +import com.puppycrawl.tools.checkstyle.api.TokenTypes; + +/** + *

+ * Checks that all constructors are grouped together. + * If there is any non-constructor code separating constructors, + * this check identifies and logs a violation for those ungrouped constructors. + * The violation message will specify the line number of the last grouped constructor. + * Comments between constructors are allowed. + *

+ *

+ * Rationale: Grouping constructors together in a class improves code readability + * and maintainability. It allows developers to easily understand + * the different ways an object can be instantiated + * and the tasks performed by each constructor. + *

+ *

+ * Parent is {@code com.puppycrawl.tools.checkstyle.TreeWalker} + *

+ *

+ * Violation Message Keys: + *

+ *
    + *
  • + * {@code constructors.declaration.grouping} + *
  • + *
+ * + * @since 10.17.0 + */ + +@StatelessCheck +public class ConstructorsDeclarationGroupingCheck extends AbstractCheck { + + /** + * A key is pointing to the warning message text in "messages.properties" + * file. + */ + public static final String MSG_KEY = "constructors.declaration.grouping"; + + @Override + public int[] getDefaultTokens() { + return getRequiredTokens(); + } + + @Override + public int[] getAcceptableTokens() { + return getRequiredTokens(); + } + + @Override + public int[] getRequiredTokens() { + return new int[] { + TokenTypes.CLASS_DEF, + TokenTypes.ENUM_DEF, + TokenTypes.RECORD_DEF, + }; + } + + @Override + public void visitToken(DetailAST ast) { + // list of all child ASTs + final List children = getChildList(ast); + + // find first constructor + final DetailAST firstConstructor = children.stream() + .filter(ConstructorsDeclarationGroupingCheck::isConstructor) + .findFirst() + .orElse(null); + + if (firstConstructor != null) { + + // get all children AST after the first constructor + final List childrenAfterFirstConstructor = + children.subList(children.indexOf(firstConstructor), children.size()); + + // find the first index of non-constructor AST after the first constructor, if present + final Optional indexOfFirstNonConstructor = childrenAfterFirstConstructor + .stream() + .filter(currAst -> !isConstructor(currAst)) + .findFirst() + .map(children::indexOf); + + // list of all children after first non-constructor AST + final List childrenAfterFirstNonConstructor = indexOfFirstNonConstructor + .map(index -> children.subList(index, children.size())) + .orElseGet(ArrayList::new); + + // create a list of all constructors that are not grouped to log + final List constructorsToLog = childrenAfterFirstNonConstructor.stream() + .filter(ConstructorsDeclarationGroupingCheck::isConstructor) + .collect(Collectors.toUnmodifiableList()); + + // find the last grouped constructor + final DetailAST lastGroupedConstructor = childrenAfterFirstConstructor.stream() + .takeWhile(ConstructorsDeclarationGroupingCheck::isConstructor) + .reduce((first, second) -> second) + .orElse(firstConstructor); + + // log all constructors that are not grouped + constructorsToLog + .forEach(ctor -> log(ctor, MSG_KEY, lastGroupedConstructor.getLineNo())); + } + } + + /** + * Get a list of all children of the given AST. + * + * @param ast the AST to get children of + * @return a list of all children of the given AST + */ + private static List getChildList(DetailAST ast) { + final List children = new ArrayList<>(); + DetailAST child = ast.findFirstToken(TokenTypes.OBJBLOCK).getFirstChild(); + while (child != null) { + children.add(child); + child = child.getNextSibling(); + } + return children; + } + + /** + * Check if the given AST is a constructor. + * + * @param ast the AST to check + * @return true if the given AST is a constructor, false otherwise + */ + private static boolean isConstructor(DetailAST ast) { + return ast.getType() == TokenTypes.CTOR_DEF + || ast.getType() == TokenTypes.COMPACT_CTOR_DEF; + } +} diff --git a/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages.properties b/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages.properties index 90386f8a7b1..6313230da97 100644 --- a/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages.properties +++ b/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages.properties @@ -3,6 +3,7 @@ assignment.inner.avoid=Inner assignments should be avoided. avoid.clone.method=Avoid using clone method. avoid.double.brace.init=Avoid double brace initialization. avoid.finalizer.method=Avoid using finalizer method. +constructors.declaration.grouping=Constructors should be grouped together. The last grouped constructor is declared at line ''{0}''. covariant.equals=covariant equals without overriding equals(java.lang.Object). declaration.order.access=Variable access definition in wrong order. declaration.order.constructor=Constructor definition in wrong order. diff --git a/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_de.properties b/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_de.properties index 2d4f885d8e0..ce08257c59e 100644 --- a/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_de.properties +++ b/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_de.properties @@ -3,6 +3,7 @@ assignment.inner.avoid=Innere Zuweisungen sollten vermieden werden. avoid.clone.method=Die Methode clone() sollte vermieden werden. avoid.double.brace.init=Vermeiden Sie doppelte geschweifte Klammern. avoid.finalizer.method=Die Methode finalize() sollte vermieden werden. +constructors.declaration.grouping=Alle Konstruktoren sollten zusammengefasst werden. Der vorherige Konstruktor befand sich in der Zeilennummer ''{0}''. covariant.equals=Kovariante Definition von equals(), ohne equals(java.lang.Object) zu überschreiben. declaration.order.access=Fehlerhafte Deklarationsreihenfolge für diesen Scope. declaration.order.constructor=Der Konstruktor steht an der falschen Stelle. diff --git a/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_es.properties b/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_es.properties index 74e04191265..66f8f94f831 100644 --- a/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_es.properties +++ b/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_es.properties @@ -3,6 +3,7 @@ assignment.inner.avoid=Deben evitarse las asignaciones internas. avoid.clone.method=Evite el uso de método clone. avoid.double.brace.init=Evite la inicialización de llaves dobles. avoid.finalizer.method=Evite el uso de método de finalizador. +constructors.declaration.grouping=Todos los constructores deben agruparse. El constructor anterior estaba en la línea número ''{0}''. covariant.equals=equals covariante sin sobrescribir equals(java.lang.Object). declaration.order.access=Definición de acceso a variable en orden incorrecto. declaration.order.constructor=Definición de constructor en orden incorrecto. diff --git a/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_fi.properties b/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_fi.properties index b76df41b25e..0f443585f2d 100644 --- a/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_fi.properties +++ b/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_fi.properties @@ -3,6 +3,7 @@ assignment.inner.avoid=Älä käytä sisäkkäisiä sijoituksia. avoid.clone.method=Vältä klooni menetelmää. avoid.double.brace.init=Vältä kaksinkertaista ahdintuen alustamista. avoid.finalizer.method=Vältä Finalizer menetelmää. +constructors.declaration.grouping=Rakentajat tulee ryhmitellä yhteen. Viimeinen ryhmitelty rakentaja ilmoitetaan rivillä ''{0}''. covariant.equals=covariant vastaa ilman painavaa tasavertaisten (java.lang.Object). declaration.order.access=Muuttuja pääsy määritelmä väärässä järjestyksessä. declaration.order.constructor=Rakentaja määritelmä väärässä järjestyksessä. diff --git a/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_fr.properties b/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_fr.properties index 68169b99999..3b57ed57e2e 100644 --- a/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_fr.properties +++ b/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_fr.properties @@ -3,6 +3,7 @@ assignment.inner.avoid=Évitez d''affecter une valeur à une variable au sein d' avoid.clone.method=Évitez d''utiliser la méthode de clonage. avoid.double.brace.init=Évitez l''initialisation à double accolade. avoid.finalizer.method=Évitez d''utiliser la méthode de finalisation. +constructors.declaration.grouping=Les constructeurs doivent être regroupés. Le dernier constructeur groupé est déclaré à la ligne ''{0}''. covariant.equals=Votre méthode equals compare uniquement les objets de votre classe. N''oubliez pas de surcharger la méthode equals(java.lang.Object). declaration.order.access=La définition des variables n''est pas triée suivant leur portée. declaration.order.constructor=La définition des constructeurs n''apparaît pas dans le bon ordre. diff --git a/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_ja.properties b/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_ja.properties index 5e51efee611..9ad64032485 100644 --- a/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_ja.properties +++ b/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_ja.properties @@ -3,6 +3,7 @@ assignment.inner.avoid=式内部での代入は避けるべきです。 avoid.clone.method=cloneメソッドを使用しないでください。 avoid.double.brace.init=二重中括弧を使った初期化は使用しないでください。 avoid.finalizer.method=ファイナライザメソッドを使用しないでください。 +constructors.declaration.grouping=コンストラクターはグループ化する必要があります。最後にグループ化されたコンストラクターは行 ''{0}'' で宣言されます。 covariant.equals=equals(java.lang.Object) をオーバーライドせずに共変 な equals を定義しています。 declaration.order.access=変数アクセスの定義順序が間違っています。 declaration.order.constructor=コンストラクタの定義順序が間違っています。 diff --git a/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_pt.properties b/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_pt.properties index 8d6be07e192..c8b0cabe7c3 100644 --- a/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_pt.properties +++ b/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_pt.properties @@ -3,6 +3,7 @@ assignment.inner.avoid=Atribuições aninhadas devem ser evitadas. avoid.clone.method=Evite o uso do método ''clone()''. avoid.double.brace.init=Evite a inicialização entre chaves. avoid.finalizer.method=Evite o uso do método ''finalize()''. +constructors.declaration.grouping=Os construtores devem ser agrupados. O último construtor agrupado é declarado na linha ''{0}''. covariant.equals="equals" covariante sem sobrescrever ''equals(java.lang.Object)''. declaration.order.access=Definição de acesso a variável em ordem errada. declaration.order.constructor=Definição de construtor em ordem errada. diff --git a/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_ru.properties b/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_ru.properties index 8d91be6815a..2032e01713c 100644 --- a/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_ru.properties +++ b/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_ru.properties @@ -3,6 +3,7 @@ assignment.inner.avoid=Внутренние присвоения следует avoid.clone.method=Избегайте использования метода clone(). avoid.double.brace.init=Избегайте инициализации в двойных скобках. avoid.finalizer.method=Избегайте использования метода finalize(). +constructors.declaration.grouping=Конструкторы должны быть сгруппированы вместе. Последний сгруппированный конструктор объявляется в строке ''{0}''. covariant.equals=Ковариантный equals() без переопределения equals(java.lang.Object). declaration.order.access=Объявляйте переменные в порядке расширения доступа. declaration.order.constructor=Определение конструктора в неправильном порядке. diff --git a/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_tr.properties b/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_tr.properties index ff90f2debdd..4d672388712 100644 --- a/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_tr.properties +++ b/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_tr.properties @@ -3,6 +3,7 @@ assignment.inner.avoid=Dahili atamalar kullanılmamalıdır. avoid.clone.method=''clone'' metodu kullanılmamalıdır. avoid.double.brace.init=Çift ayraç başlatmadan kaçının. avoid.finalizer.method=''finalize'' metodu kullanılmamalıdır. +constructors.declaration.grouping=Yapıcılar birlikte gruplandırılmalıdır. Gruplandırılan son kurucu ''{0}'' satırında bildirildi. covariant.equals=java.lang.Object sınıfının ''equals'' metodundan başka bir ''equals'' metodu tanımlanmış, java.lang.Object sınıfından gelen ''equals'' metodu da ezilmelidir (override). declaration.order.access=Değişken, erişim seviyesine göre yanlış sırada tanımlanmış. declaration.order.constructor=''constructor'' tanımı yanlış sırada yapılmış. diff --git a/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_zh.properties b/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_zh.properties index a56ff9356c2..16a9fda6d41 100644 --- a/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_zh.properties +++ b/src/main/resources/com/puppycrawl/tools/checkstyle/checks/coding/messages_zh.properties @@ -3,6 +3,7 @@ assignment.inner.avoid=应避免在子表达式中赋值。 avoid.clone.method=避免重写 clone 方法。 avoid.double.brace.init=避免双括号初始化。 avoid.finalizer.method=避免重写finalize方法。 +constructors.declaration.grouping=构造函数应该组合在一起。最后一个分组构造函数在''{0}''行声明。 covariant.equals=重写''equals()''方法时,必须确保重写了''equals(java.lang.Object)''方法。 declaration.order.access=属性访问器定义顺序错误。 declaration.order.constructor=构造器定义顺序错误。 diff --git a/src/main/resources/com/puppycrawl/tools/checkstyle/meta/checks/coding/ConstructorsDeclarationGroupingCheck.xml b/src/main/resources/com/puppycrawl/tools/checkstyle/meta/checks/coding/ConstructorsDeclarationGroupingCheck.xml new file mode 100644 index 00000000000..11b912d9cb8 --- /dev/null +++ b/src/main/resources/com/puppycrawl/tools/checkstyle/meta/checks/coding/ConstructorsDeclarationGroupingCheck.xml @@ -0,0 +1,25 @@ + + + + + <p> + Checks that all constructors are grouped together. + If there is any non-constructor code separating constructors, + this check identifies and logs a violation for those ungrouped constructors. + The violation message will specify the line number of the last grouped constructor. + Comments between constructors are allowed. + </p> + <p> + Rationale: Grouping constructors together in a class improves code readability + and maintainability. It allows developers to easily understand + the different ways an object can be instantiated + and the tasks performed by each constructor. + </p> + + + + + + diff --git a/src/site/site.xml b/src/site/site.xml index 5181f54f6b6..0e21799ec3f 100644 --- a/src/site/site.xml +++ b/src/site/site.xml @@ -114,6 +114,8 @@ + diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/ConstructorsDeclarationGroupingCheckTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/ConstructorsDeclarationGroupingCheckTest.java new file mode 100644 index 00000000000..09c073e125f --- /dev/null +++ b/src/test/java/com/puppycrawl/tools/checkstyle/checks/coding/ConstructorsDeclarationGroupingCheckTest.java @@ -0,0 +1,84 @@ +/////////////////////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code and other text files for adherence to a set of rules. +// Copyright (C) 2001-2024 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +/////////////////////////////////////////////////////////////////////////////////////////////// + +package com.puppycrawl.tools.checkstyle.checks.coding; + +import static com.google.common.truth.Truth.assertWithMessage; +import static com.puppycrawl.tools.checkstyle.checks.coding.ConstructorsDeclarationGroupingCheck.MSG_KEY; + +import org.junit.jupiter.api.Test; + +import com.puppycrawl.tools.checkstyle.AbstractModuleTestSupport; + +public class ConstructorsDeclarationGroupingCheckTest extends AbstractModuleTestSupport { + @Override + protected String getPackageLocation() { + return "com/puppycrawl/tools/checkstyle/checks/coding/constructorsdeclarationgrouping"; + } + + @Test + public void testDefault() throws Exception { + final String[] expected = { + "23:5: " + getCheckMessage(MSG_KEY, 19), + "28:5: " + getCheckMessage(MSG_KEY, 19), + "45:9: " + getCheckMessage(MSG_KEY, 39), + "55:13: " + getCheckMessage(MSG_KEY, 49), + "59:9: " + getCheckMessage(MSG_KEY, 39), + "63:5: " + getCheckMessage(MSG_KEY, 19), + "66:5: " + getCheckMessage(MSG_KEY, 19), + "85:7: " + getCheckMessage(MSG_KEY, 81), + "90:7: " + getCheckMessage(MSG_KEY, 81), + "93:7: " + getCheckMessage(MSG_KEY, 81), + "97:5: " + getCheckMessage(MSG_KEY, 19), + }; + verifyWithInlineConfigParser( + getPath("InputConstructorsDeclarationGrouping.java"), expected); + } + + @Test + public void testConstructorsDeclarationGroupingRecords() throws Exception { + + final String[] expected = { + "20:9: " + getCheckMessage(MSG_KEY, 12), + "23:9: " + getCheckMessage(MSG_KEY, 12), + "28:9: " + getCheckMessage(MSG_KEY, 12), + "45:9: " + getCheckMessage(MSG_KEY, 39), + }; + + verifyWithInlineConfigParser( + getNonCompilablePath("InputConstructorsDeclarationGroupingRecords.java"), + expected); + } + + @Test + public void testTokensNotNull() { + final ConstructorsDeclarationGroupingCheck check = + new ConstructorsDeclarationGroupingCheck(); + assertWithMessage("Acceptable tokens should not be null") + .that(check.getAcceptableTokens()) + .isNotNull(); + assertWithMessage("Default tokens should not be null") + .that(check.getDefaultTokens()) + .isNotNull(); + assertWithMessage("Required tokens should not be null") + .that(check.getRequiredTokens()) + .isNotNull(); + } + +} diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/meta/XmlMetaReaderTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/meta/XmlMetaReaderTest.java index 867cb7f2991..f117d9c4d93 100644 --- a/src/test/java/com/puppycrawl/tools/checkstyle/meta/XmlMetaReaderTest.java +++ b/src/test/java/com/puppycrawl/tools/checkstyle/meta/XmlMetaReaderTest.java @@ -40,20 +40,20 @@ protected String getPackageLocation() { @Test public void test() { - assertThat(XmlMetaReader.readAllModulesIncludingThirdPartyIfAny()).hasSize(200); + assertThat(XmlMetaReader.readAllModulesIncludingThirdPartyIfAny()).hasSize(201); } @Test public void testDuplicatePackage() { assertThat(XmlMetaReader .readAllModulesIncludingThirdPartyIfAny("com.puppycrawl.tools.checkstyle.meta")) - .hasSize(200); + .hasSize(201); } @Test public void testBadPackage() { assertThat(XmlMetaReader.readAllModulesIncludingThirdPartyIfAny("DOES.NOT.EXIST")) - .hasSize(200); + .hasSize(201); } @Test diff --git a/src/test/resources-noncompilable/com/puppycrawl/tools/checkstyle/checks/coding/constructorsdeclarationgrouping/InputConstructorsDeclarationGroupingRecords.java b/src/test/resources-noncompilable/com/puppycrawl/tools/checkstyle/checks/coding/constructorsdeclarationgrouping/InputConstructorsDeclarationGroupingRecords.java new file mode 100644 index 00000000000..d45c0ecc9d9 --- /dev/null +++ b/src/test/resources-noncompilable/com/puppycrawl/tools/checkstyle/checks/coding/constructorsdeclarationgrouping/InputConstructorsDeclarationGroupingRecords.java @@ -0,0 +1,80 @@ +/* +ConstructorsDeclarationGrouping + + +*/ + +//non-compiled with javac: Compilable with Java14 +package com.puppycrawl.tools.checkstyle.checks.coding.constructorsdeclarationgrouping; + +public class InputConstructorsDeclarationGroupingRecords { + public record MyRecord1(int x, int y) { + public MyRecord1(int a) { + this(a,a); + } + + void foo() {} + + void foo2() {} + + public MyRecord1 {} + // violation above 'Constructors should be grouped together.*' + + public MyRecord1(int a, int b, int c, int d) { + // violation above 'Constructors should be grouped together.*' + this(a+b, c+d); + } + + public MyRecord1(int x, int y, int z) { + // violation above 'Constructors should be grouped together.*' + this(x+y, z); + } + } + + class MyClass { + int x = 20; + + MyClass() {} + + MyClass(String s) {} + + String[] str; + + String[] str2; + + MyClass(int a) {} + // violation above 'Constructors should be grouped together.*' + } + + public record MyRecord2(double d) { + public MyRecord2(double a, double b, double c) { + this(a+b+c); + } + + public MyRecord2 {} + + public MyRecord2(double a, double b) { + this(a+b); + } + } + + public record MyRecord3(float f) { + public MyRecord3(float a, float b, float c) { + this(a+b+c); + } + } + + public record MyRecord4(String str) { + public MyRecord4 {} + } + + public record MyRecord5(long l) { + void test() {} + + void test2() {} + + void test3() {} + } + + public record MyRecord6(String str, int x) {} +} diff --git a/src/test/resources/com/puppycrawl/tools/checkstyle/checks/coding/constructorsdeclarationgrouping/InputConstructorsDeclarationGrouping.java b/src/test/resources/com/puppycrawl/tools/checkstyle/checks/coding/constructorsdeclarationgrouping/InputConstructorsDeclarationGrouping.java new file mode 100644 index 00000000000..20035f01712 --- /dev/null +++ b/src/test/resources/com/puppycrawl/tools/checkstyle/checks/coding/constructorsdeclarationgrouping/InputConstructorsDeclarationGrouping.java @@ -0,0 +1,130 @@ +/* +ConstructorsDeclarationGrouping + + +*/ + +package com.puppycrawl.tools.checkstyle.checks.coding.constructorsdeclarationgrouping; + +public class InputConstructorsDeclarationGrouping { + + int a; + + int b; + + void foo() {} + + InputConstructorsDeclarationGrouping() {} + + InputConstructorsDeclarationGrouping(String a) {} + + void foo2() {} + + InputConstructorsDeclarationGrouping(int a) {} + // violation above 'Constructors should be grouped together.*' + + int abc; + + InputConstructorsDeclarationGrouping(double x) {} + // violation above 'Constructors should be grouped together.*' + + private enum InnerEnum1 { + + one; + + int x; + + InnerEnum1() {} + + InnerEnum1(String f) {} + + String str; + + String str2; + + InnerEnum1(int x) {} + // violation above 'Constructors should be grouped together.*' + + private abstract class Inner { + Inner() {} + + int x; + + String neko; + + Inner(String g) {} + // violation above 'Constructors should be grouped together.*' + } + + InnerEnum1(double d) {} + // violation above 'Constructors should be grouped together.*' + } + + InputConstructorsDeclarationGrouping(float x) {} + // violation above 'Constructors should be grouped together.*' + + InputConstructorsDeclarationGrouping(long l) {} + // violation above 'Constructors should be grouped together.*' + + private class Inner { + Inner() {} + + Inner(String str) {} + + // Comments are allowed between constructors. + Inner(int x) {} + } + + private class Inner2 { + Inner2() {} + + Inner2(String str) {} + + int x; + + Inner2(int x) {} + // violation above 'Constructors should be grouped together.*' + + String xx; + + Inner2(double d) {} + // violation above 'Constructors should be grouped together.*' + + Inner2(float f) {} + // violation above 'Constructors should be grouped together.*' + } + + InputConstructorsDeclarationGrouping(long l, double d) {} + // violation above 'Constructors should be grouped together.*' + + InputConstructorsDeclarationGrouping annoynmous = new InputConstructorsDeclarationGrouping() { + int x; + void test() {} + void test2() {} + }; + + private enum InnerEnum2 { + ONE,TWO,THREE; + void test() {} + void test2() {} + void test3() {} + } + + private enum InnerEnum3 { + InnerEnum3() {} + } + + private enum InnerEnum4 {} + + private class Inner3 { + void test() {} + void test2() {} + void test3() {} + } + + private class Inner4 { + Inner4() {} + } + + private class Inner5 {} +} diff --git a/src/xdocs-examples/resources/com/puppycrawl/tools/checkstyle/checks/coding/constructorsdeclarationgrouping/Example1.java b/src/xdocs-examples/resources/com/puppycrawl/tools/checkstyle/checks/coding/constructorsdeclarationgrouping/Example1.java new file mode 100644 index 00000000000..c9d43ffae3e --- /dev/null +++ b/src/xdocs-examples/resources/com/puppycrawl/tools/checkstyle/checks/coding/constructorsdeclarationgrouping/Example1.java @@ -0,0 +1,42 @@ +/*xml + + + + + +*/ + +package com.puppycrawl.tools.checkstyle.checks.coding.constructorsdeclarationgrouping; + +// xdoc section -- start +public class Example1 { + + int x; + + Example1() {} + + Example1(String s) {} + + // comments between constructors are allowed. + Example1(int x) {} + + Example1(String s, int x) {} + + void foo() {} + + private enum ExampleEnum { + + ONE, TWO, THREE; + + ExampleEnum() {} + + ExampleEnum(int x) {} + + ExampleEnum(String s) {} + + int x = 10; + + void foo() {} + } +} +// xdoc section -- end diff --git a/src/xdocs-examples/resources/com/puppycrawl/tools/checkstyle/checks/coding/constructorsdeclarationgrouping/Example2.java b/src/xdocs-examples/resources/com/puppycrawl/tools/checkstyle/checks/coding/constructorsdeclarationgrouping/Example2.java new file mode 100644 index 00000000000..bd3c517e134 --- /dev/null +++ b/src/xdocs-examples/resources/com/puppycrawl/tools/checkstyle/checks/coding/constructorsdeclarationgrouping/Example2.java @@ -0,0 +1,43 @@ +/*xml + + + + + +*/ + +package com.puppycrawl.tools.checkstyle.checks.coding.constructorsdeclarationgrouping; + +// xdoc section -- start +public class Example2 { + + int x; + + Example2() {} + + Example2(String s){} + + void foo() {} + + Example2(int x) {} // violation + + Example2(String s, int x) {} // violation + + private enum ExampleEnum { + + ONE, TWO, THREE; + + ExampleEnum() {} + + ExampleEnum(int x) {} + + final int x = 10; + + ExampleEnum(String str) {} // violation + + void foo() {} + } + + Example2(float f) {} // violation +} +// xdoc section -- end diff --git a/src/xdocs/checks.xml b/src/xdocs/checks.xml index 9dc8ce06ec2..e1784914f97 100644 --- a/src/xdocs/checks.xml +++ b/src/xdocs/checks.xml @@ -208,6 +208,14 @@ ConstantName Checks that constant names conform to a specified pattern. + + + + ConstructorsDeclarationGrouping + + + Checks that all constructors are grouped together. + diff --git a/src/xdocs/checks/coding/constructorsdeclarationgrouping.xml b/src/xdocs/checks/coding/constructorsdeclarationgrouping.xml new file mode 100644 index 00000000000..8a975ee93d3 --- /dev/null +++ b/src/xdocs/checks/coding/constructorsdeclarationgrouping.xml @@ -0,0 +1,143 @@ + + + + ConstructorsDeclarationGrouping + + +
+

Since Checkstyle 10.17.0

+ +

+ Checks that all constructors are grouped together. + If there is any non-constructor code separating constructors, + this check identifies and logs a violation for those ungrouped constructors. + The violation message will specify the line number + of the last grouped constructor. + Comments between constructors are allowed. +

+

+ Rationale: Grouping constructors together in a class improves code readability + and maintainability. It allows developers to easily understand + the different ways an object can be instantiated + and the tasks performed by each constructor. +

+
+ + +

To configure the check:

+ +<module name="Checker"> + <module name="TreeWalker"> + <module name="ConstructorsDeclarationGrouping"/> + </module> +</module> + +

Example of correct grouping of constructors:

+ +public class Example1 { + + int x; + + Example1() {} + + Example1(String s) {} + + // comments between constructors are allowed. + Example1(int x) {} + + Example1(String s, int x) {} + + void foo() {} + + private enum ExampleEnum { + + ONE, TWO, THREE; + + ExampleEnum() {} + + ExampleEnum(int x) {} + + ExampleEnum(String s) {} + + int x = 10; + + void foo() {} + } +} + +

Example of incorrect grouping of constructors:

+ +public class Example2 { + + int x; + + Example2() {} + + Example2(String s){} + + void foo() {} + + Example2(int x) {} // violation + + Example2(String s, int x) {} // violation + + private enum ExampleEnum { + + ONE, TWO, THREE; + + ExampleEnum() {} + + ExampleEnum(int x) {} + + final int x = 10; + + ExampleEnum(String str) {} // violation + + void foo() {} + } + + Example2(float f) {} // violation +} + +
+ + +
+ + + + +

+ All messages can be customized if the default message doesn't suit you. + Please see the documentation + to learn how to. +

+
+ + +

+ com.puppycrawl.tools.checkstyle.checks.coding +

+
+ + +

+ TreeWalker +

+
+
+ + diff --git a/src/xdocs/checks/coding/constructorsdeclarationgrouping.xml.template b/src/xdocs/checks/coding/constructorsdeclarationgrouping.xml.template new file mode 100644 index 00000000000..835f7136824 --- /dev/null +++ b/src/xdocs/checks/coding/constructorsdeclarationgrouping.xml.template @@ -0,0 +1,82 @@ + + + + ConstructorsDeclarationGrouping + + +
+

Since Checkstyle 10.17.0

+ +

+ Checks that all constructors are grouped together. + If there is any non-constructor code separating constructors, + this check identifies and logs a violation for those ungrouped constructors. + The violation message will specify the line number + of the last grouped constructor. + Comments between constructors are allowed. +

+

+ Rationale: Grouping constructors together in a class improves code readability + and maintainability. It allows developers to easily understand + the different ways an object can be instantiated + and the tasks performed by each constructor. +

+
+ + +

To configure the check:

+ + + + +

Example of correct grouping of constructors:

+ + + + +

Example of incorrect grouping of constructors:

+ + + + +
+ + + + + + + + + +

+ All messages can be customized if the default message doesn't suit you. + Please see the documentation + to learn how to. +

+
+ + +

+ com.puppycrawl.tools.checkstyle.checks.coding +

+
+ + + + + + +
+ +
diff --git a/src/xdocs/checks/coding/index.xml b/src/xdocs/checks/coding/index.xml index 612dee1c918..625f97e9d3f 100644 --- a/src/xdocs/checks/coding/index.xml +++ b/src/xdocs/checks/coding/index.xml @@ -49,6 +49,16 @@ Checks if call to superclass constructor without arguments is present. + + + + ConstructorsDeclarationGrouping + + + + Checks that all constructors are grouped together. + +