diff --git a/its/autoscan/src/test/java/org/sonar/java/it/AutoScanTest.java b/its/autoscan/src/test/java/org/sonar/java/it/AutoScanTest.java index a17dd65453f..6e25b8a73c0 100644 --- a/its/autoscan/src/test/java/org/sonar/java/it/AutoScanTest.java +++ b/its/autoscan/src/test/java/org/sonar/java/it/AutoScanTest.java @@ -199,7 +199,7 @@ public void javaCheckTestSources() throws Exception { softly.assertThat(newDiffs).containsExactlyInAnyOrderElementsOf(knownDiffs.values()); softly.assertThat(newTotal).isEqualTo(knownTotal); softly.assertThat(rulesCausingFPs).hasSize(10); - softly.assertThat(rulesNotReporting).hasSize(15); + softly.assertThat(rulesNotReporting).hasSize(16); /** * 4. Check total number of differences (FPs + FNs) diff --git a/its/autoscan/src/test/resources/autoscan/diffs/diff_S8444.json b/its/autoscan/src/test/resources/autoscan/diffs/diff_S8444.json new file mode 100644 index 00000000000..5c4d1d40100 --- /dev/null +++ b/its/autoscan/src/test/resources/autoscan/diffs/diff_S8444.json @@ -0,0 +1,6 @@ +{ + "ruleKey": "S8444", + "hasTruePositives": false, + "falseNegatives": 0, + "falsePositives": 0 +} \ No newline at end of file diff --git a/java-checks-test-sources/default/src/main/files/non-compiling/checks/PresuperLogicShoudntBloatConstructorSample.java b/java-checks-test-sources/default/src/main/files/non-compiling/checks/PresuperLogicShoudntBloatConstructorSample.java new file mode 100644 index 00000000000..ad7bdefff88 --- /dev/null +++ b/java-checks-test-sources/default/src/main/files/non-compiling/checks/PresuperLogicShoudntBloatConstructorSample.java @@ -0,0 +1,144 @@ +package org.sonar.java.checks; + +public class PresuperLogicShoudntBloatConstructorSample { + public static class File { + public File(String path) { + // Simulate file initialization logic + } + } + + public static class NonCompliantSecureFile extends File { + public NonCompliantSecureFile(String path) { + if (path == null || path.isBlank()) { // Noncompliant {{Excessive logic in this "pre-construction" phase makes the code harder to read and maintain.}} + // ^[el=+19;ec=7] + throw new IllegalArgumentException("Path cannot be empty"); + } + if (path.contains("..")) { + throw new IllegalArgumentException("Relative path traversal is forbidden"); + } + if (path.startsWith("/root") || path.startsWith("/etc")) { + throw new SecurityException("Access to system directories is restricted"); + } + if (path.length() > 255) { + throw new IllegalArgumentException("Path exceeds maximum length"); + } + if (!path.matches("^[a-zA-Z0-9/._-]+$")) { + throw new IllegalArgumentException("Path contains illegal characters"); + } + String sanitizedPath = path.trim().replace("//", "/"); + if (sanitizedPath.endsWith("/")) { + sanitizedPath = sanitizedPath.substring(0, sanitizedPath.length() - 1); + } + super(sanitizedPath); + } + } + + public static class NonCompliantSecureFileNestedStatements extends File { + public NonCompliantSecureFile(String path) { + if (true) { // Noncompliant {{Excessive logic in this "pre-construction" phase makes the code harder to read and maintain.}} + // ^[el=+21;ec=7] + if (path == null || path.isBlank()) { + throw new IllegalArgumentException("Path cannot be empty"); + } + if (path.contains("..")) { + throw new IllegalArgumentException("Relative path traversal is forbidden"); + } + if (path.startsWith("/root") || path.startsWith("/etc")) { + throw new SecurityException("Access to system directories is restricted"); + } + if (path.length() > 255) { + throw new IllegalArgumentException("Path exceeds maximum length"); + } + if (!path.matches("^[a-zA-Z0-9/._-]+$")) { + throw new IllegalArgumentException("Path contains illegal characters"); + } + String sanitizedPath = path.trim().replace("//", "/"); + if (sanitizedPath.endsWith("/")) { + sanitizedPath = sanitizedPath.substring(0, sanitizedPath.length() - 1); + } + } + super(sanitizedPath); + } + } + + public static class CompliantSecureFile extends File { + public CompliantSecureFile(String path) { + // Compliant: Logic is encapsulated in static helpers + validatePathSecurity(path); + validatePathFormat(path); + String sanitizedPath = normalizePath(path); + super(sanitizedPath); + } + } + + public static class EdgeCaseSecureFile extends File { + public EdgeCaseSecureFile(String path) { + // Compliant: There are 3 statements before super() : if, throw, var declaration + if (path.length() > 255 || !path.matches("^[a-zA-Z0-9/._-]+$")) { + throw new IllegalArgumentException("Path format or length is invalid"); + } + String sanitizedPath = normalizePath(path); + super(sanitizedPath); + } + + public EdgeCaseSecureFile(String path, boolean b) { + // Non-compliant: There are 4 statements before super() : if, throw, var declaration, method call + validatePathSecurity(path); // Noncompliant {{Excessive logic in this "pre-construction" phase makes the code harder to read and maintain.}} + // ^[el=+5;ec=49] + if (path.length() > 255 || !path.matches("^[a-zA-Z0-9/._-]+$")) { + throw new IllegalArgumentException("Path format or length is invalid"); + } + String sanitizedPath = normalizePath(path); + super(sanitizedPath); + } + + public EdgeCaseSecureFile(String path, int i) { + // Compliant: There are 3 statements before super() : if, if, try-catch block + if (true) { + if (true) { + try {} + catch (Exception e) {} + finally {} + } + } + super(sanitizedPath); + } + + + public EdgeCaseSecureFile(String path, float f) { + // Compliant: There are 4 statements before super() : if, if, try-catch block, if + if (true) { // Noncompliant {{Excessive logic in this "pre-construction" phase makes the code harder to read and maintain.}} + // ^[el=+9;ec=7] + if (true) { + try { + if (true) {} + } + catch (Exception e) {} + finally {} + } + } + super(sanitizedPath); + } + } + + + private static void validatePathSecurity(String path) { + if (path == null || path.contains("..")) { + throw new IllegalArgumentException("Invalid or dangerous path sequence"); + } + if (path.startsWith("/root") || path.startsWith("/etc")) { + throw new SecurityException("Access to system directories is restricted"); + } + } + + private static void validatePathFormat(String path) { + if (path.length() > 255 || !path.matches("^[a-zA-Z0-9/._-]+$")) { + throw new IllegalArgumentException("Path format or length is invalid"); + } + } + + private static String normalizePath(String path) { + String cleaned = path.trim().replace("//", "/"); + return cleaned.endsWith("/") ? cleaned.substring(0, cleaned.length() - 1) : cleaned; + } +} diff --git a/java-checks/src/main/java/org/sonar/java/checks/FlexibleConstructorBodyValidationCheck.java b/java-checks/src/main/java/org/sonar/java/checks/FlexibleConstructorBodyValidationCheck.java index bdcfee0fa17..caf7e2ec485 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/FlexibleConstructorBodyValidationCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/FlexibleConstructorBodyValidationCheck.java @@ -16,21 +16,15 @@ */ package org.sonar.java.checks; -import java.util.Collections; -import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.stream.Collectors; import org.sonar.check.Rule; -import org.sonar.java.model.ExpressionUtils; -import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; -import org.sonar.plugins.java.api.JavaVersion; -import org.sonar.plugins.java.api.JavaVersionAwareVisitor; import org.sonar.plugins.java.api.semantic.MethodMatchers; import org.sonar.plugins.java.api.semantic.Symbol; import org.sonar.plugins.java.api.semantic.Type; import org.sonar.plugins.java.api.tree.BaseTreeVisitor; -import org.sonar.plugins.java.api.tree.BlockTree; import org.sonar.plugins.java.api.tree.ExpressionStatementTree; import org.sonar.plugins.java.api.tree.ExpressionTree; import org.sonar.plugins.java.api.tree.IdentifierTree; @@ -40,9 +34,10 @@ import org.sonar.plugins.java.api.tree.StatementTree; import org.sonar.plugins.java.api.tree.ThrowStatementTree; import org.sonar.plugins.java.api.tree.Tree; +import org.sonar.plugins.java.api.tree.VariableTree; @Rule(key = "S8433") -public class FlexibleConstructorBodyValidationCheck extends IssuableSubscriptionVisitor implements JavaVersionAwareVisitor { +public class FlexibleConstructorBodyValidationCheck extends FlexibleConstructorVisitor { private static final MethodMatchers VALIDATION_METHODS = MethodMatchers.or( MethodMatchers.create() @@ -68,42 +63,18 @@ public class FlexibleConstructorBodyValidationCheck extends IssuableSubscription ); @Override - public List nodesToVisit() { - return Collections.singletonList(Tree.Kind.CONSTRUCTOR); - } - - @Override - public boolean isCompatibleWithJavaVersion(JavaVersion version) { - return version.isJava25Compatible(); - } - - @Override - public void visitNode(Tree tree) { - MethodTree constructor = (MethodTree) tree; - BlockTree body = constructor.block(); - - if (body == null || body.body().isEmpty()) { - return; - } - - // Find the super() or this() call - int constructorCallIndex = findConstructorCallIndex(body); - - // Get statements after the constructor call - List statements = body.body(); - if (constructorCallIndex == statements.size() - 1 + void validateConstructor(MethodTree constructor, List body, int constructorCallIndex) { + if (constructorCallIndex == body.size() - 1 || (constructorCallIndex == -1 && hasNoExplicitSuperClass(constructor))) { // No statements after constructor call or no superclass and no constructor call return; } - // Collect constructor parameters for analysis - Set parameters = new HashSet<>(); - constructor.parameters().forEach(param -> parameters.add(param.symbol())); + Set parameters = constructor.parameters().stream().map(VariableTree::symbol).collect(Collectors.toSet()); // Analyze statements after the constructor call for movable validation - for (int i = constructorCallIndex + 1; i < statements.size(); i++) { - StatementTree statement = statements.get(i); + for (int i = constructorCallIndex + 1; i < body.size(); i++) { + StatementTree statement = body.get(i); if (isValidationStatement(statement) && canBeMovedToPrologue(statement, parameters)) { reportIssue(statement, "Move this validation logic before the super() or this() call."); @@ -111,26 +82,6 @@ public void visitNode(Tree tree) { } } - /** - * Find the index of an explicit super() or this() call in the constructor body. - * - * @param body the constructor body to search - * @return the index of the explicit super() or this() call, or -1 if no explicit call is found (implicit super()) - */ - private static int findConstructorCallIndex(BlockTree body) { - List statements = body.body(); - for (int i = 0; i < statements.size(); i++) { - if (statements.get(i) instanceof ExpressionStatementTree expressionStatementTree - && expressionStatementTree.expression() instanceof MethodInvocationTree methodInvocationTree - && methodInvocationTree.methodSelect() instanceof IdentifierTree identifierTree - && ExpressionUtils.isThisOrSuper(identifierTree.name())){ - return i; - } - } - // No explicit super() or this() call - return -1; - } - private static boolean hasNoExplicitSuperClass(MethodTree constructor) { Type superClass = constructor.symbol().enclosingClass().superClass(); return (superClass == null || superClass.is("java.lang.Object")); @@ -202,7 +153,7 @@ public void visitIdentifier(IdentifierTree tree) { Symbol symbol = tree.symbol(); // Allow parameters, local variables and static fields / methods - if (symbol.isLocalVariable() || symbol.isStatic()|| parameters.contains(symbol)) { + if (symbol.isLocalVariable() || symbol.isStatic() || parameters.contains(symbol)) { return; } diff --git a/java-checks/src/main/java/org/sonar/java/checks/FlexibleConstructorVisitor.java b/java-checks/src/main/java/org/sonar/java/checks/FlexibleConstructorVisitor.java new file mode 100644 index 00000000000..b2a7eefe1cc --- /dev/null +++ b/java-checks/src/main/java/org/sonar/java/checks/FlexibleConstructorVisitor.java @@ -0,0 +1,87 @@ +/* + * SonarQube Java + * Copyright (C) 2012-2025 SonarSource Sàrl + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the Sonar Source-Available License Version 1, as published by SonarSource SA. + * + * 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 Sonar Source-Available License for more details. + * + * You should have received a copy of the Sonar Source-Available License + * along with this program; if not, see https://sonarsource.com/license/ssal/ + */ +package org.sonar.java.checks; + +import java.util.Collections; +import java.util.List; +import org.sonar.java.model.ExpressionUtils; +import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; +import org.sonar.plugins.java.api.JavaVersion; +import org.sonar.plugins.java.api.JavaVersionAwareVisitor; +import org.sonar.plugins.java.api.tree.BlockTree; +import org.sonar.plugins.java.api.tree.ExpressionStatementTree; +import org.sonar.plugins.java.api.tree.IdentifierTree; +import org.sonar.plugins.java.api.tree.MethodInvocationTree; +import org.sonar.plugins.java.api.tree.MethodTree; +import org.sonar.plugins.java.api.tree.StatementTree; +import org.sonar.plugins.java.api.tree.Tree; + +public abstract class FlexibleConstructorVisitor extends IssuableSubscriptionVisitor implements JavaVersionAwareVisitor { + + /** + * Validate the constructor body, providing the constructor method tree, the list of statements in the constructor body, and the index of any explicit super() or this() call + * (or -1 if no explicit call is found). + * @param constructor the constructor method tree being validated + * @param body the list of statements in the constructor body + * @param constructorCallIndex the index of any explicit super() or this() call in the body, or -1 if no explicit call is found (implicit super()) + */ + abstract void validateConstructor(MethodTree constructor, List body, int constructorCallIndex); + + @Override + public final List nodesToVisit() { + return Collections.singletonList(Tree.Kind.CONSTRUCTOR); + } + + @Override + public final boolean isCompatibleWithJavaVersion(JavaVersion version) { + return version.isJava25Compatible(); + } + + @Override + public final void visitNode(Tree tree) { + MethodTree constructor = (MethodTree) tree; + BlockTree block = constructor.block(); + if (block == null || block.body().isEmpty()) { + // No body or empty body, nothing to validate + return; + } + List body = block.body(); + + // Find the super() or this() call + int constructorCallIndex = findConstructorCallIndex(body); + validateConstructor(constructor, body, constructorCallIndex); + } + + /** + * Find the index of an explicit super() or this() call in the constructor body. + * + * @param body the constructor body to search + * @return the index of the explicit super() or this() call, or -1 if no explicit call is found (implicit super()) + */ + private static int findConstructorCallIndex(List body) { + for (int i = 0; i < body.size(); i++) { + if (body.get(i) instanceof ExpressionStatementTree expressionStatementTree + && expressionStatementTree.expression() instanceof MethodInvocationTree methodInvocationTree + && methodInvocationTree.methodSelect() instanceof IdentifierTree identifierTree + && ExpressionUtils.isThisOrSuper(identifierTree.name())) { + return i; + } + } + // No explicit super() or this() call + return -1; + } +} diff --git a/java-checks/src/main/java/org/sonar/java/checks/PresuperLogicBloatsConstructorCheck.java b/java-checks/src/main/java/org/sonar/java/checks/PresuperLogicBloatsConstructorCheck.java new file mode 100644 index 00000000000..b39d9514768 --- /dev/null +++ b/java-checks/src/main/java/org/sonar/java/checks/PresuperLogicBloatsConstructorCheck.java @@ -0,0 +1,53 @@ +/* + * SonarQube Java + * Copyright (C) 2012-2025 SonarSource Sàrl + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the Sonar Source-Available License Version 1, as published by SonarSource SA. + * + * 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 Sonar Source-Available License for more details. + * + * You should have received a copy of the Sonar Source-Available License + * along with this program; if not, see https://sonarsource.com/license/ssal/ + */ +package org.sonar.java.checks; + +import java.util.List; +import org.sonar.check.Rule; +import org.sonar.check.RuleProperty; +import org.sonar.java.ast.visitors.StatementVisitor; +import org.sonar.plugins.java.api.tree.MethodTree; +import org.sonar.plugins.java.api.tree.StatementTree; + +@Rule(key = "S8444") +public class PresuperLogicBloatsConstructorCheck extends FlexibleConstructorVisitor { + + private static final int DEFAULT_STATEMENTS_THRESHOLD = 5; + @RuleProperty( + key = "statementsThreshold", + description = "Maximum number of statements allowed before the constructor call.", + defaultValue = "" + DEFAULT_STATEMENTS_THRESHOLD) + public int statementsThreshold = DEFAULT_STATEMENTS_THRESHOLD; + + @Override + void validateConstructor(MethodTree constructor, List body, int constructorCallIndex) { + if (constructorCallIndex < 0) { + // No constructor call, nothing to check + return; + } + StatementVisitor statementVisitor = new StatementVisitor(); + int statementsBeforeConstructorCall = body.stream().limit(constructorCallIndex).map(statementVisitor::numberOfStatements).reduce(0, Integer::sum); + if (statementsBeforeConstructorCall > statementsThreshold) { + reportIssue( + body.get(0), + body.get(constructorCallIndex - 1), + "Excessive logic in this \"pre-construction\" phase makes the code harder to read and maintain." + ); + } + } +} + diff --git a/java-checks/src/test/java/org/sonar/java/checks/PresuperLogicBloatsConstructorCheckTest.java b/java-checks/src/test/java/org/sonar/java/checks/PresuperLogicBloatsConstructorCheckTest.java new file mode 100644 index 00000000000..8931867e421 --- /dev/null +++ b/java-checks/src/test/java/org/sonar/java/checks/PresuperLogicBloatsConstructorCheckTest.java @@ -0,0 +1,51 @@ +/* + * SonarQube Java + * Copyright (C) 2012-2025 SonarSource Sàrl + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the Sonar Source-Available License Version 1, as published by SonarSource SA. + * + * 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 Sonar Source-Available License for more details. + * + * You should have received a copy of the Sonar Source-Available License + * along with this program; if not, see https://sonarsource.com/license/ssal/ + */ +package org.sonar.java.checks; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.sonar.java.checks.verifier.CheckVerifier; + +import static org.sonar.java.checks.verifier.TestUtils.nonCompilingTestSourcesPath; + +class PresuperLogicBloatsConstructorCheckTest { + private static final PresuperLogicBloatsConstructorCheck check = new PresuperLogicBloatsConstructorCheck(); + + @BeforeAll + static void setUp() { + check.statementsThreshold = 3; + } + + @Test + void test() { + + CheckVerifier.newVerifier() + .onFile(nonCompilingTestSourcesPath("checks/PresuperLogicShoudntBloatConstructorSample.java")) + .withCheck(check) + .withJavaVersion(25) + .verifyIssues(); + } + + @Test + void test_java_24() { + CheckVerifier.newVerifier() + .onFile(nonCompilingTestSourcesPath("checks/PresuperLogicShoudntBloatConstructorSample.java")) + .withCheck(check) + .withJavaVersion(24) + .verifyNoIssues(); + } +} diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S8444.html b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S8444.html new file mode 100644 index 00000000000..279550c2a9e --- /dev/null +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S8444.html @@ -0,0 +1,82 @@ +

While Java 25+ allows statements to appear before the super(…​) or this(…​) call in a constructor, this area should be +reserved for simple validation, transformation, or preparation of arguments. Excessive logic in this "pre-construction" phase makes the code harder to +read and maintain.

+

Why is this an issue?

+

The ability to place code before super() is intended for basic tasks like parameter validation or simple transformations. Using this +space for complex logic obscures the primary purpose of the constructor, increases maintenance risk by introducing complex control flow before object +initialization, and violates the separation of concerns.

+

How to fix it

+

Refactor complex pre-construction logic into private static helper methods or static factory methods. Keep statements before super() +limited to simple validations and direct parameter transformations.

+

Parameters

statementsThreshold +
+5
+
+

Maximum number of statements allowed before the constructor call.

+

Code examples

+
+public class SecureFile extends File {
+    public SecureFile(String path) {
+        // Noncompliant: Validation and path normalization logic is too verbose
+        if (path == null || path.isBlank()) {
+            throw new IllegalArgumentException("Path cannot be empty");
+        }
+        if (path.contains("..")) {
+            throw new IllegalArgumentException("Relative path traversal is forbidden");
+        }
+        if (path.startsWith("/root") || path.startsWith("/etc")) {
+            throw new SecurityException("Access to system directories is restricted");
+        }
+        if (path.length() > 255) {
+            throw new IllegalArgumentException("Path exceeds maximum length");
+        }
+        if (!path.matches("^[a-zA-Z0-9/._-]+$")) {
+            throw new IllegalArgumentException("Path contains illegal characters");
+        }
+
+        String sanitizedPath = path.trim().replace("//", "/");
+        if (sanitizedPath.endsWith("/")) {
+            sanitizedPath = sanitizedPath.substring(0, sanitizedPath.length() - 1);
+        }
+
+        super(sanitizedPath);
+    }
+}
+
+

Compliant solution

+
+public class SecureFile extends File {
+    public SecureFile(String path) {
+        // Compliant: Logic is encapsulated in static helpers
+        validatePathSecurity(path);
+        validatePathFormat(path);
+        String sanitizedPath = normalizePath(path);
+        super(sanitizedPath);
+    }
+
+    private static void validatePathSecurity(String path) {
+        if (path == null || path.contains("..")) {
+            throw new IllegalArgumentException("Invalid or dangerous path sequence");
+        }
+        if (path.startsWith("/root") || path.startsWith("/etc")) {
+            throw new SecurityException("Access to system directories is restricted");
+        }
+    }
+
+    private static void validatePathFormat(String path) {
+        if (path.length() > 255 || !path.matches("^[a-zA-Z0-9/._-]+$")) {
+            throw new IllegalArgumentException("Path format or length is invalid");
+        }
+    }
+
+    private static String normalizePath(String path) {
+        String cleaned = path.trim().replace("//", "/");
+        return cleaned.endsWith("/") ? cleaned.substring(0, cleaned.length() - 1) : cleaned;
+    }
+}
+
+

Documentation

+ + diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S8444.json b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S8444.json new file mode 100644 index 00000000000..c336600dadf --- /dev/null +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S8444.json @@ -0,0 +1,23 @@ +{ + "title": "Excessive logic before super() should not bloat constructor", + "type": "CODE_SMELL", + "status": "ready", + "remediation": { + "func": "Constant\/Issue", + "constantCost": "5min" + }, + "tags": [ + "java25" + ], + "defaultSeverity": "Major", + "ruleSpecification": "RSPEC-8444", + "sqKey": "S8444", + "scope": "All", + "quickfix": "unknown", + "code": { + "impacts": { + "MAINTAINABILITY": "MEDIUM" + }, + "attribute": "CONVENTIONAL" + } +} diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/Sonar_way_profile.json b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/Sonar_way_profile.json index d5a11a963cf..c6ee6637bd6 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/Sonar_way_profile.json +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/Sonar_way_profile.json @@ -519,6 +519,7 @@ "S7629", "S8346", "S8432", - "S8433" + "S8433", + "S8444" ] } diff --git a/sonarpedia.json b/sonarpedia.json index daa120100b9..323b874aace 100644 --- a/sonarpedia.json +++ b/sonarpedia.json @@ -8,4 +8,4 @@ "no-language-in-filenames": true, "preserve-filenames": false } -} \ No newline at end of file +}