diff --git a/CHANGELOG.md b/CHANGELOG.md index f6eb102e8..1e0298804 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,10 +11,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `ObjectPassedAsInterface` analysis rule, which detects object references that are passed directly as an interface to a routine. +- `TooManyDefaultParameters` analysis rule, which flags routines with an excessive number of default parameters. ### Changed - `EmptyBlock` now ignores all empty blocks containing an explanatory comment. +- `TooManyParameters` now flags routine declarations instead of implementations, improving support for methods +that are virtual, abstract, or on an interface. ## [1.17.2] - 2025-07-03 diff --git a/delphi-checks/src/main/java/au/com/integradev/delphi/checks/CheckList.java b/delphi-checks/src/main/java/au/com/integradev/delphi/checks/CheckList.java index 89a828f99..9a8d4f16d 100644 --- a/delphi-checks/src/main/java/au/com/integradev/delphi/checks/CheckList.java +++ b/delphi-checks/src/main/java/au/com/integradev/delphi/checks/CheckList.java @@ -147,6 +147,7 @@ public final class CheckList { TabulationCharacterCheck.class, TooLargeRoutineCheck.class, TooLongLineCheck.class, + TooManyDefaultParametersCheck.class, TooManyNestedRoutinesCheck.class, TooManyParametersCheck.class, TooManyVariablesCheck.class, diff --git a/delphi-checks/src/main/java/au/com/integradev/delphi/checks/TooManyDefaultParametersCheck.java b/delphi-checks/src/main/java/au/com/integradev/delphi/checks/TooManyDefaultParametersCheck.java new file mode 100644 index 000000000..777fc7978 --- /dev/null +++ b/delphi-checks/src/main/java/au/com/integradev/delphi/checks/TooManyDefaultParametersCheck.java @@ -0,0 +1,75 @@ +/* + * Sonar Delphi Plugin + * Copyright (C) 2025 Integrated Application Development + * + * This program 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 3 of the License, or (at your option) any later version. + * + * This program 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 program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package au.com.integradev.delphi.checks; + +import org.sonar.check.Rule; +import org.sonar.check.RuleProperty; +import org.sonar.plugins.communitydelphi.api.ast.FormalParameterNode.FormalParameterData; +import org.sonar.plugins.communitydelphi.api.ast.RoutineDeclarationNode; +import org.sonar.plugins.communitydelphi.api.ast.RoutineImplementationNode; +import org.sonar.plugins.communitydelphi.api.ast.RoutineNameNode; +import org.sonar.plugins.communitydelphi.api.check.DelphiCheck; +import org.sonar.plugins.communitydelphi.api.check.DelphiCheckContext; +import org.sonar.plugins.communitydelphi.api.type.Parameter; + +@Rule(key = "TooManyDefaultParameters") +public class TooManyDefaultParametersCheck extends DelphiCheck { + private static final int DEFAULT_MAXIMUM = 2; + + @RuleProperty( + key = "max", + description = "Maximum authorized number of default parameters", + defaultValue = "" + DEFAULT_MAXIMUM) + public int max = DEFAULT_MAXIMUM; + + @Override + public DelphiCheckContext visit(RoutineDeclarationNode routine, DelphiCheckContext context) { + var count = + routine.getParameters().stream().filter(FormalParameterData::hasDefaultValue).count(); + checkRoutine(routine.getRoutineNameNode(), (int) count, max, context); + return super.visit(routine, context); + } + + @Override + public DelphiCheckContext visit(RoutineImplementationNode routine, DelphiCheckContext context) { + var declaration = routine.getRoutineNameDeclaration(); + if (declaration == null || !declaration.isImplementationDeclaration()) { + // Don't duplicate issues between the declaration and implementation + return super.visit(routine, context); + } + + // A routine implementation's default parameters MUST match its declaration's, or not have any + // default parameters at all. This means that we need to check the declaration to get the + // authoritative number of default parameters. + var count = declaration.getParameters().stream().filter(Parameter::hasDefaultValue).count(); + checkRoutine(routine.getRoutineNameNode(), (int) count, max, context); + return super.visit(routine, context); + } + + private void checkRoutine(RoutineNameNode node, int count, int max, DelphiCheckContext context) { + if (count > max) { + reportIssue( + context, + node, + String.format( + "Routine has %d default parameters, which is greater than %d authorized.", + count, max)); + } + } +} diff --git a/delphi-checks/src/main/java/au/com/integradev/delphi/checks/TooManyParametersCheck.java b/delphi-checks/src/main/java/au/com/integradev/delphi/checks/TooManyParametersCheck.java index dad951293..4b43a7fc5 100644 --- a/delphi-checks/src/main/java/au/com/integradev/delphi/checks/TooManyParametersCheck.java +++ b/delphi-checks/src/main/java/au/com/integradev/delphi/checks/TooManyParametersCheck.java @@ -20,7 +20,9 @@ import org.sonar.check.Rule; import org.sonar.check.RuleProperty; +import org.sonar.plugins.communitydelphi.api.ast.RoutineDeclarationNode; import org.sonar.plugins.communitydelphi.api.ast.RoutineImplementationNode; +import org.sonar.plugins.communitydelphi.api.ast.RoutineNameNode; import org.sonar.plugins.communitydelphi.api.check.DelphiCheck; import org.sonar.plugins.communitydelphi.api.check.DelphiCheckContext; import org.sonarsource.analyzer.commons.annotations.DeprecatedRuleKey; @@ -42,18 +44,45 @@ public class TooManyParametersCheck extends DelphiCheck { defaultValue = "" + DEFAULT_MAXIMUM) public int constructorMax = DEFAULT_MAXIMUM; + @Override + public DelphiCheckContext visit(RoutineDeclarationNode routine, DelphiCheckContext context) { + checkRoutine( + routine.getRoutineNameNode(), + routine.getParameters().size(), + routine.isConstructor(), + context); + return super.visit(routine, context); + } + @Override public DelphiCheckContext visit(RoutineImplementationNode routine, DelphiCheckContext context) { - int count = routine.getParameters().size(); - int limit = routine.isConstructor() ? constructorMax : max; - if (count > limit) { + var declaration = routine.getRoutineNameDeclaration(); + if (declaration == null || !declaration.isImplementationDeclaration()) { + // Don't duplicate issues between the declaration and implementation + return super.visit(routine, context); + } + + // A routine implementation's default parameters MUST match its declaration's, or not have any + // default parameters at all. This means that we need to check the declaration to get the + // authoritative number of default parameters. + checkRoutine( + routine.getRoutineNameNode(), + declaration.getParameters().size(), + routine.isConstructor(), + context); + return super.visit(routine, context); + } + + private void checkRoutine( + RoutineNameNode node, int count, boolean isConstructor, DelphiCheckContext context) { + var thisMax = isConstructor ? constructorMax : max; + if (count > thisMax) { reportIssue( context, - routine.getRoutineNameNode(), + node, String.format( "%s has %d parameters, which is greater than %d authorized.", - routine.isConstructor() ? "Constructor" : "Routine", count, limit)); + isConstructor ? "Constructor" : "Routine", count, thisMax)); } - return super.visit(routine, context); } } diff --git a/delphi-checks/src/main/resources/org/sonar/l10n/delphi/rules/community-delphi/Sonar_way_profile.json b/delphi-checks/src/main/resources/org/sonar/l10n/delphi/rules/community-delphi/Sonar_way_profile.json index 98f25c080..adebd387e 100644 --- a/delphi-checks/src/main/resources/org/sonar/l10n/delphi/rules/community-delphi/Sonar_way_profile.json +++ b/delphi-checks/src/main/resources/org/sonar/l10n/delphi/rules/community-delphi/Sonar_way_profile.json @@ -86,6 +86,7 @@ "TabulationCharacter", "TooLargeRoutine", "TooLongLine", + "TooManyDefaultParameters", "TooManyNestedRoutines", "TooManyParameters", "TrailingCommaArgumentList", diff --git a/delphi-checks/src/main/resources/org/sonar/l10n/delphi/rules/community-delphi/TooManyDefaultParameters.html b/delphi-checks/src/main/resources/org/sonar/l10n/delphi/rules/community-delphi/TooManyDefaultParameters.html new file mode 100644 index 000000000..c3c0a543a --- /dev/null +++ b/delphi-checks/src/main/resources/org/sonar/l10n/delphi/rules/community-delphi/TooManyDefaultParameters.html @@ -0,0 +1,19 @@ +

Why is this an issue?

+

+ Though default parameters can be useful in cases when there is a sensible default value, they also damage API + interfaces when used to make a method's behaviour overly configurable. A method with too many default parameters + is confusing, unpredictable at a glance, unintuitive to use, and likely overloaded in functionality. +

+

+ In most cases, using method overloads, multiple methods, or configuration objects is a more + appropriate solution. +

+

How to fix it

+

+ Refactor this routine by re-evaluating the need for the default values, and either: +

+ \ No newline at end of file diff --git a/delphi-checks/src/main/resources/org/sonar/l10n/delphi/rules/community-delphi/TooManyDefaultParameters.json b/delphi-checks/src/main/resources/org/sonar/l10n/delphi/rules/community-delphi/TooManyDefaultParameters.json new file mode 100644 index 000000000..d7e88a7f6 --- /dev/null +++ b/delphi-checks/src/main/resources/org/sonar/l10n/delphi/rules/community-delphi/TooManyDefaultParameters.json @@ -0,0 +1,19 @@ +{ + "title": "Routines should not have too many default parameters", + "type": "CODE_SMELL", + "status": "ready", + "remediation": { + "func": "Constant/Issue", + "constantCost": "5min" + }, + "code": { + "attribute": "FOCUSED", + "impacts": { + "MAINTAINABILITY": "MEDIUM" + } + }, + "tags": ["brain-overload"], + "defaultSeverity": "Major", + "scope": "MAIN", + "quickfix": "unknown" +} diff --git a/delphi-checks/src/test/java/au/com/integradev/delphi/checks/TooManyDefaultParametersCheckTest.java b/delphi-checks/src/test/java/au/com/integradev/delphi/checks/TooManyDefaultParametersCheckTest.java new file mode 100644 index 000000000..0dbc6db6b --- /dev/null +++ b/delphi-checks/src/test/java/au/com/integradev/delphi/checks/TooManyDefaultParametersCheckTest.java @@ -0,0 +1,219 @@ +/* + * Sonar Delphi Plugin + * Copyright (C) 2025 Integrated Application Development + * + * This program 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 3 of the License, or (at your option) any later version. + * + * This program 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 program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 + */ +package au.com.integradev.delphi.checks; + +import au.com.integradev.delphi.builders.DelphiTestUnitBuilder; +import au.com.integradev.delphi.checks.verifier.CheckVerifier; +import org.junit.jupiter.api.Test; + +class TooManyDefaultParametersCheckTest { + @Test + void testImplOnlyNoDefaultParamsShouldNotAddIssue() { + CheckVerifier.newVerifier() + .withCheck(new TooManyDefaultParametersCheck()) + .onFile( + new DelphiTestUnitBuilder() + .appendImpl("procedure Foo(") + .appendImpl(" Param1: Boolean;") + .appendImpl(" Param2: Boolean;") + .appendImpl(" Param3: Boolean;") + .appendImpl(" Param4: Boolean;") + .appendImpl(" Param5: Boolean;") + .appendImpl(" Param6: Boolean;") + .appendImpl(" Param7: Boolean;") + .appendImpl(" Param8: Boolean") + .appendImpl(");") + .appendImpl("begin") + .appendImpl(" // do nothing") + .appendImpl("end;")) + .verifyNoIssues(); + } + + @Test + void testImplOnlySomeDefaultParamsShouldNotAddIssue() { + CheckVerifier.newVerifier() + .withCheck(new TooManyDefaultParametersCheck()) + .onFile( + new DelphiTestUnitBuilder() + .appendImpl("procedure Foo(") + .appendImpl(" Param1: Boolean;") + .appendImpl(" Param2: Boolean;") + .appendImpl(" Param3: Boolean;") + .appendImpl(" Param4: Boolean;") + .appendImpl(" Param5: Boolean;") + .appendImpl(" Param6: Boolean;") + .appendImpl(" Param7: Boolean = True;") + .appendImpl(" Param8: Boolean = False") + .appendImpl(");") + .appendImpl("begin") + .appendImpl(" // do nothing") + .appendImpl("end;")) + .verifyNoIssues(); + } + + @Test + void testImplMatchingDeclSomeDefaultParamsShouldNotAddIssue() { + CheckVerifier.newVerifier() + .withCheck(new TooManyDefaultParametersCheck()) + .onFile( + new DelphiTestUnitBuilder() + .appendDecl("procedure Foo(") + .appendDecl(" Param1: Boolean;") + .appendDecl(" Param2: Boolean;") + .appendDecl(" Param3: Boolean;") + .appendDecl(" Param4: Boolean;") + .appendDecl(" Param5: Boolean;") + .appendDecl(" Param6: Boolean;") + .appendDecl(" Param7: Boolean = True;") + .appendDecl(" Param8: Boolean = False") + .appendDecl(");") + .appendImpl("procedure Foo(") + .appendImpl(" Param1: Boolean;") + .appendImpl(" Param2: Boolean;") + .appendImpl(" Param3: Boolean;") + .appendImpl(" Param4: Boolean;") + .appendImpl(" Param5: Boolean;") + .appendImpl(" Param6: Boolean;") + .appendImpl(" Param7: Boolean = True;") + .appendImpl(" Param8: Boolean = False") + .appendImpl(");") + .appendImpl("begin") + .appendImpl(" // do nothing") + .appendImpl("end;")) + .verifyNoIssues(); + } + + @Test + void testImplNotMatchingDeclSomeDefaultParamsShouldNotAddIssue() { + CheckVerifier.newVerifier() + .withCheck(new TooManyDefaultParametersCheck()) + .onFile( + new DelphiTestUnitBuilder() + .appendDecl("procedure Foo(") + .appendDecl(" Param1: Boolean;") + .appendDecl(" Param2: Boolean;") + .appendDecl(" Param3: Boolean;") + .appendDecl(" Param4: Boolean;") + .appendDecl(" Param5: Boolean;") + .appendDecl(" Param6: Boolean;") + .appendDecl(" Param7: Boolean = True;") + .appendDecl(" Param8: Boolean = False") + .appendDecl(");") + .appendImpl("procedure Foo(") + .appendImpl(" Param1: Boolean;") + .appendImpl(" Param2: Boolean;") + .appendImpl(" Param3: Boolean;") + .appendImpl(" Param4: Boolean;") + .appendImpl(" Param5: Boolean;") + .appendImpl(" Param6: Boolean;") + .appendImpl(" Param7: Boolean;") + .appendImpl(" Param8: Boolean") + .appendImpl(");") + .appendImpl("begin") + .appendImpl(" // do nothing") + .appendImpl("end;")) + .verifyNoIssues(); + } + + @Test + void testImplOnlyTooManyDefaultParamsShouldAddIssue() { + CheckVerifier.newVerifier() + .withCheck(new TooManyDefaultParametersCheck()) + .onFile( + new DelphiTestUnitBuilder() + .appendImpl("procedure Foo( // Noncompliant") + .appendImpl(" Param1: Boolean;") + .appendImpl(" Param2: Boolean;") + .appendImpl(" Param3: Boolean;") + .appendImpl(" Param4: Boolean = False;") + .appendImpl(" Param5: Boolean = True;") + .appendImpl(" Param6: Boolean = False;") + .appendImpl(" Param7: Boolean = True;") + .appendImpl(" Param8: Boolean = False") + .appendImpl(");") + .appendImpl("begin") + .appendImpl(" // do nothing") + .appendImpl("end;")) + .verifyIssues(); + } + + @Test + void testImplMatchingDeclTooManyDefaultParamsShouldAddIssue() { + CheckVerifier.newVerifier() + .withCheck(new TooManyDefaultParametersCheck()) + .onFile( + new DelphiTestUnitBuilder() + .appendDecl("procedure Foo( // Noncompliant") + .appendDecl(" Param1: Boolean;") + .appendDecl(" Param2: Boolean;") + .appendDecl(" Param3: Boolean;") + .appendDecl(" Param4: Boolean = False;") + .appendDecl(" Param5: Boolean = True;") + .appendDecl(" Param6: Boolean = False;") + .appendDecl(" Param7: Boolean = True;") + .appendDecl(" Param8: Boolean = False") + .appendDecl(");") + .appendImpl("procedure Foo(") + .appendImpl(" Param1: Boolean;") + .appendImpl(" Param2: Boolean;") + .appendImpl(" Param3: Boolean;") + .appendImpl(" Param4: Boolean = False;") + .appendImpl(" Param5: Boolean = True;") + .appendImpl(" Param6: Boolean = False;") + .appendImpl(" Param7: Boolean = True;") + .appendImpl(" Param8: Boolean = False") + .appendImpl(");") + .appendImpl("begin") + .appendImpl(" // do nothing") + .appendImpl("end;")) + .verifyIssues(); + } + + @Test + void testImplNotMatchingDeclTooManyDefaultParamsShouldAddIssue() { + CheckVerifier.newVerifier() + .withCheck(new TooManyDefaultParametersCheck()) + .onFile( + new DelphiTestUnitBuilder() + .appendDecl("procedure Foo( // Noncompliant") + .appendDecl(" Param1: Boolean;") + .appendDecl(" Param2: Boolean;") + .appendDecl(" Param3: Boolean;") + .appendDecl(" Param4: Boolean = False;") + .appendDecl(" Param5: Boolean = True;") + .appendDecl(" Param6: Boolean = False;") + .appendDecl(" Param7: Boolean = True;") + .appendDecl(" Param8: Boolean = False") + .appendDecl(");") + .appendImpl("procedure Foo(") + .appendImpl(" Param1: Boolean;") + .appendImpl(" Param2: Boolean;") + .appendImpl(" Param3: Boolean;") + .appendImpl(" Param4: Boolean;") + .appendImpl(" Param5: Boolean;") + .appendImpl(" Param6: Boolean;") + .appendImpl(" Param7: Boolean;") + .appendImpl(" Param8: Boolean") + .appendImpl(");") + .appendImpl("begin") + .appendImpl(" // do nothing") + .appendImpl("end;")) + .verifyIssues(); + } +} diff --git a/delphi-checks/src/test/java/au/com/integradev/delphi/checks/TooManyParametersCheckTest.java b/delphi-checks/src/test/java/au/com/integradev/delphi/checks/TooManyParametersCheckTest.java index e8b6f207f..fc5c88766 100644 --- a/delphi-checks/src/test/java/au/com/integradev/delphi/checks/TooManyParametersCheckTest.java +++ b/delphi-checks/src/test/java/au/com/integradev/delphi/checks/TooManyParametersCheckTest.java @@ -24,7 +24,7 @@ class TooManyParametersCheckTest { @Test - void testOneVariableShouldNotAddIssue() { + void testImplOkParamsShouldNotAddIssue() { CheckVerifier.newVerifier() .withCheck(new TooManyParametersCheck()) .onFile( @@ -37,7 +37,7 @@ void testOneVariableShouldNotAddIssue() { } @Test - void testTooManyVariablesShouldAddIssue() { + void testImplOnlyTooManyParamsShouldAddIssue() { CheckVerifier.newVerifier() .withCheck(new TooManyParametersCheck()) .onFile( @@ -57,4 +57,144 @@ void testTooManyVariablesShouldAddIssue() { .appendImpl("end;")) .verifyIssues(); } + + @Test + void testImplAndDeclTooManyParamsShouldAddIssue() { + CheckVerifier.newVerifier() + .withCheck(new TooManyParametersCheck()) + .onFile( + new DelphiTestUnitBuilder() + .appendDecl("procedure Foo( // Noncompliant") + .appendDecl(" Param1: Boolean;") + .appendDecl(" Param2: Boolean;") + .appendDecl(" Param3: Boolean;") + .appendDecl(" Param4: Boolean;") + .appendDecl(" Param5: Boolean;") + .appendDecl(" Param6: Boolean;") + .appendDecl(" Param7: Boolean;") + .appendDecl(" Param8: Boolean") + .appendDecl(");") + .appendImpl("procedure Foo(") + .appendImpl(" Param1: Boolean;") + .appendImpl(" Param2: Boolean;") + .appendImpl(" Param3: Boolean;") + .appendImpl(" Param4: Boolean;") + .appendImpl(" Param5: Boolean;") + .appendImpl(" Param6: Boolean;") + .appendImpl(" Param7: Boolean;") + .appendImpl(" Param8: Boolean") + .appendImpl(");") + .appendImpl("begin") + .appendImpl(" // do nothing") + .appendImpl("end;")) + .verifyIssues(); + } + + @Test + void testImplAndDeclOkParamsShouldNotAddIssue() { + CheckVerifier.newVerifier() + .withCheck(new TooManyParametersCheck()) + .onFile( + new DelphiTestUnitBuilder() + .appendDecl("procedure Foo(") + .appendDecl(" Param1: Boolean;") + .appendDecl(" Param2: Boolean") + .appendDecl(");") + .appendImpl("procedure Foo(") + .appendImpl(" Param1: Boolean;") + .appendImpl(" Param2: Boolean") + .appendImpl(");") + .appendImpl("begin") + .appendImpl(" // do nothing") + .appendImpl("end;")) + .verifyNoIssues(); + } + + @Test + void testDeclOnlyTooManyParamsShouldAddIssue() { + CheckVerifier.newVerifier() + .withCheck(new TooManyParametersCheck()) + .onFile( + new DelphiTestUnitBuilder() + .appendDecl("procedure Foo( // Noncompliant") + .appendDecl(" Param1: Boolean;") + .appendDecl(" Param2: Boolean;") + .appendDecl(" Param3: Boolean;") + .appendDecl(" Param4: Boolean;") + .appendDecl(" Param5: Boolean;") + .appendDecl(" Param6: Boolean;") + .appendDecl(" Param7: Boolean;") + .appendDecl(" Param8: Boolean") + .appendDecl(");")) + .verifyIssues(); + } + + @Test + void testInterfaceTooManyParamsShouldAddIssue() { + CheckVerifier.newVerifier() + .withCheck(new TooManyParametersCheck()) + .onFile( + new DelphiTestUnitBuilder() + .appendDecl("type IMyIntf = interface") + .appendDecl(" procedure Foo( // Noncompliant") + .appendDecl(" Param1: Boolean;") + .appendDecl(" Param2: Boolean;") + .appendDecl(" Param3: Boolean;") + .appendDecl(" Param4: Boolean;") + .appendDecl(" Param5: Boolean;") + .appendDecl(" Param6: Boolean;") + .appendDecl(" Param7: Boolean;") + .appendDecl(" Param8: Boolean") + .appendDecl(" );") + .appendDecl("end;")) + .verifyIssues(); + } + + @Test + void testConstructorTooManyParamsShouldAddIssue() { + var check = new TooManyParametersCheck(); + check.max = 9999; + + CheckVerifier.newVerifier() + .withCheck(new TooManyParametersCheck()) + .onFile( + new DelphiTestUnitBuilder() + .appendDecl("type TMyObj = class(TObject)") + .appendDecl(" constructor Create( // Noncompliant") + .appendDecl(" Param1: Boolean;") + .appendDecl(" Param2: Boolean;") + .appendDecl(" Param3: Boolean;") + .appendDecl(" Param4: Boolean;") + .appendDecl(" Param5: Boolean;") + .appendDecl(" Param6: Boolean;") + .appendDecl(" Param7: Boolean;") + .appendDecl(" Param8: Boolean") + .appendDecl(" );") + .appendDecl("end;")) + .verifyIssues(); + } + + @Test + void testNonConstructorTooManyParamsShouldAddIssue() { + var check = new TooManyParametersCheck(); + check.constructorMax = 9999; + + CheckVerifier.newVerifier() + .withCheck(new TooManyParametersCheck()) + .onFile( + new DelphiTestUnitBuilder() + .appendDecl("type TMyObj = class(TObject)") + .appendDecl(" procedure Create( // Noncompliant") + .appendDecl(" Param1: Boolean;") + .appendDecl(" Param2: Boolean;") + .appendDecl(" Param3: Boolean;") + .appendDecl(" Param4: Boolean;") + .appendDecl(" Param5: Boolean;") + .appendDecl(" Param6: Boolean;") + .appendDecl(" Param7: Boolean;") + .appendDecl(" Param8: Boolean") + .appendDecl(" );") + .appendDecl("end;")) + .verifyIssues(); + } }