From f63a587d7cd261bae44586a996c55b933c10d538 Mon Sep 17 00:00:00 2001 From: asya-vorobeva Date: Mon, 29 Jun 2026 16:16:23 +0200 Subject: [PATCH 1/5] S6541: reduce noise by dividing found issues count by 15 instead of 10 Co-Authored-By: Claude Sonnet 4.6 --- its/ruling/src/test/resources/eclipse-jetty/java-S6541.json | 4 ---- .../main/java/checks/BrainMethodCheckSubsetOfIssues.java | 6 +++--- .../java/org/sonar/java/checks/design/BrainMethodCheck.java | 2 +- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/its/ruling/src/test/resources/eclipse-jetty/java-S6541.json b/its/ruling/src/test/resources/eclipse-jetty/java-S6541.json index 3e3676fe629..0577d7edeb7 100644 --- a/its/ruling/src/test/resources/eclipse-jetty/java-S6541.json +++ b/its/ruling/src/test/resources/eclipse-jetty/java-S6541.json @@ -18,7 +18,6 @@ 783 ], "org.eclipse.jetty:jetty-project:jetty-http/src/main/java/org/eclipse/jetty/http/MimeTypes.java": [ -416, 563 ], "org.eclipse.jetty:jetty-project:jetty-http/src/main/java/org/eclipse/jetty/http/QuotedCSVParser.java": [ @@ -32,9 +31,6 @@ "org.eclipse.jetty:jetty-project:jetty-jmx/src/main/java/org/eclipse/jetty/jmx/MBeanContainer.java": [ 297 ], -"org.eclipse.jetty:jetty-project:jetty-server/src/main/java/org/eclipse/jetty/server/CachedContentFactory.java": [ -213 -], "org.eclipse.jetty:jetty-project:jetty-server/src/main/java/org/eclipse/jetty/server/CustomRequestLog.java": [ 579 ], diff --git a/java-checks-test-sources/default/src/main/java/checks/BrainMethodCheckSubsetOfIssues.java b/java-checks-test-sources/default/src/main/java/checks/BrainMethodCheckSubsetOfIssues.java index f999de0c7aa..a3eaf469d9f 100644 --- a/java-checks-test-sources/default/src/main/java/checks/BrainMethodCheckSubsetOfIssues.java +++ b/java-checks-test-sources/default/src/main/java/checks/BrainMethodCheckSubsetOfIssues.java @@ -1,11 +1,11 @@ package checks; -//The test unit is set to report the first brain method issue + the 10% of the total brain method issues found, +//The test unit is set to report the first brain method issue + the total brain method issues found divided by 15, //ordered by general complexity. -//In this file there are 10 issues found, so a total of 1 + (10% of 10 = 1) = 2 issues will be raised +//In this file there are 10 issues found, so a total of 1 + (10 / 15 = 0) = 1 issue will be raised class BrainMethodCheckSubsetOfIssues { - void method1(String a, String b) { // Noncompliant + void method1(String a, String b) { // Compliant: this will be skipped since the following method is more complex if (a != null) { System.out.println(a + b); } diff --git a/java-checks/src/main/java/org/sonar/java/checks/design/BrainMethodCheck.java b/java-checks/src/main/java/org/sonar/java/checks/design/BrainMethodCheck.java index 32d7e23d3ae..f4bb5d47368 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/design/BrainMethodCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/design/BrainMethodCheck.java @@ -112,7 +112,7 @@ private static boolean isExcluded(MethodTree methodTree) { @Override public void endOfAnalysis(ModuleScannerContext context) { if (issuesFound.size() > numberOfIssuesToReport) { - numberOfIssuesToReport += issuesFound.size() / 10; + numberOfIssuesToReport += issuesFound.size() / 15; issuesFound.sort((a, b) -> b.brainScore - a.brainScore); } else { numberOfIssuesToReport = issuesFound.size(); From 8d87e0a6deb5fbaf98c4902ba9ebd766768b40ed Mon Sep 17 00:00:00 2001 From: asya-vorobeva Date: Wed, 1 Jul 2026 15:11:51 +0200 Subject: [PATCH 2/5] Fix ruling diff --- .../resources/eclipse-jetty-similar-to-main/java-S6541.json | 4 ---- 1 file changed, 4 deletions(-) diff --git a/its/ruling/src/test/resources/eclipse-jetty-similar-to-main/java-S6541.json b/its/ruling/src/test/resources/eclipse-jetty-similar-to-main/java-S6541.json index e7eaae6a66a..d4ea646841a 100644 --- a/its/ruling/src/test/resources/eclipse-jetty-similar-to-main/java-S6541.json +++ b/its/ruling/src/test/resources/eclipse-jetty-similar-to-main/java-S6541.json @@ -18,7 +18,6 @@ 783 ], "org.eclipse.jetty:jetty-project:jetty-http/src/main/java/org/eclipse/jetty/http/MimeTypes.java": [ -416, 563 ], "org.eclipse.jetty:jetty-project:jetty-http/src/main/java/org/eclipse/jetty/http/QuotedCSVParser.java": [ @@ -32,9 +31,6 @@ "org.eclipse.jetty:jetty-project:jetty-jmx/src/main/java/org/eclipse/jetty/jmx/MBeanContainer.java": [ 297 ], -"org.eclipse.jetty:jetty-project:jetty-server/src/main/java/org/eclipse/jetty/server/CachedContentFactory.java": [ -213 -], "org.eclipse.jetty:jetty-project:jetty-server/src/main/java/org/eclipse/jetty/server/CustomRequestLog.java": [ 579 ], From dd261b90f3bc86813e0f70d0ff47deb41959cce2 Mon Sep 17 00:00:00 2001 From: asya-vorobeva Date: Thu, 2 Jul 2026 12:18:56 +0200 Subject: [PATCH 3/5] S6541: limit reported issues to a percentage of total found, capped at module threshold Co-Authored-By: Claude Sonnet 4.6 --- .../java-S6541.json | 48 +-- .../resources/eclipse-jetty/java-S6541.json | 72 +--- .../checks/BrainMethodCheckSubsetCapped.java | 380 ++++++++++++++++++ .../checks/BrainMethodCheckSubsetLarge.java | 142 +++++++ .../BrainMethodCheckSubsetOfIssues.java | 7 +- .../checks/BrainMethodCheckSubsetSmall.java | 24 ++ .../java/checks/design/BrainMethodCheck.java | 14 +- .../checks/design/BrainMethodCheckTest.java | 65 ++- 8 files changed, 618 insertions(+), 134 deletions(-) create mode 100644 java-checks-test-sources/default/src/main/java/checks/BrainMethodCheckSubsetCapped.java create mode 100644 java-checks-test-sources/default/src/main/java/checks/BrainMethodCheckSubsetLarge.java create mode 100644 java-checks-test-sources/default/src/main/java/checks/BrainMethodCheckSubsetSmall.java diff --git a/its/ruling/src/test/resources/eclipse-jetty-similar-to-main/java-S6541.json b/its/ruling/src/test/resources/eclipse-jetty-similar-to-main/java-S6541.json index d4ea646841a..f246020a8ac 100644 --- a/its/ruling/src/test/resources/eclipse-jetty-similar-to-main/java-S6541.json +++ b/its/ruling/src/test/resources/eclipse-jetty-similar-to-main/java-S6541.json @@ -1,27 +1,6 @@ { -"org.eclipse.jetty:jetty-project:jetty-http/src/main/java/org/eclipse/jetty/http/CookieCutter.java": [ -46 -], -"org.eclipse.jetty:jetty-project:jetty-http/src/main/java/org/eclipse/jetty/http/GZIPContentDecoder.java": [ -160 -], -"org.eclipse.jetty:jetty-project:jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java": [ -358, -573 -], "org.eclipse.jetty:jetty-project:jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java": [ -571, -1080, -1613 -], -"org.eclipse.jetty:jetty-project:jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java": [ -783 -], -"org.eclipse.jetty:jetty-project:jetty-http/src/main/java/org/eclipse/jetty/http/MimeTypes.java": [ -563 -], -"org.eclipse.jetty:jetty-project:jetty-http/src/main/java/org/eclipse/jetty/http/QuotedCSVParser.java": [ -96 +1080 ], "org.eclipse.jetty:jetty-project:jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java": [ 595, @@ -36,30 +15,5 @@ ], "org.eclipse.jetty:jetty-project:jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java": [ 328 -], -"org.eclipse.jetty:jetty-project:jetty-server/src/main/java/org/eclipse/jetty/server/InclusiveByteRange.java": [ -140 -], -"org.eclipse.jetty:jetty-project:jetty-server/src/main/java/org/eclipse/jetty/server/MultiPartFormInputStream.java": [ -518 -], -"org.eclipse.jetty:jetty-project:jetty-server/src/main/java/org/eclipse/jetty/server/ProxyConnectionFactory.java": [ -563 -], -"org.eclipse.jetty:jetty-project:jetty-server/src/main/java/org/eclipse/jetty/server/ResourceService.java": [ -481, -640 -], -"org.eclipse.jetty:jetty-project:jetty-server/src/main/java/org/eclipse/jetty/server/Utf8HttpWriter.java": [ -42 -], -"org.eclipse.jetty:jetty-project:jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java": [ -2097 -], -"org.eclipse.jetty:jetty-project:jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHandler.java": [ -547 -], -"org.eclipse.jetty:jetty-project:jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java": [ -1589 ] } diff --git a/its/ruling/src/test/resources/eclipse-jetty/java-S6541.json b/its/ruling/src/test/resources/eclipse-jetty/java-S6541.json index 0577d7edeb7..a104c0fccdb 100644 --- a/its/ruling/src/test/resources/eclipse-jetty/java-S6541.json +++ b/its/ruling/src/test/resources/eclipse-jetty/java-S6541.json @@ -1,27 +1,6 @@ { -"org.eclipse.jetty:jetty-project:jetty-http/src/main/java/org/eclipse/jetty/http/CookieCutter.java": [ -46 -], -"org.eclipse.jetty:jetty-project:jetty-http/src/main/java/org/eclipse/jetty/http/GZIPContentDecoder.java": [ -160 -], -"org.eclipse.jetty:jetty-project:jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java": [ -358, -573 -], "org.eclipse.jetty:jetty-project:jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java": [ -571, -1080, -1613 -], -"org.eclipse.jetty:jetty-project:jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java": [ -783 -], -"org.eclipse.jetty:jetty-project:jetty-http/src/main/java/org/eclipse/jetty/http/MimeTypes.java": [ -563 -], -"org.eclipse.jetty:jetty-project:jetty-http/src/main/java/org/eclipse/jetty/http/QuotedCSVParser.java": [ -96 +1080 ], "org.eclipse.jetty:jetty-project:jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java": [ 595, @@ -37,64 +16,15 @@ "org.eclipse.jetty:jetty-project:jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java": [ 328 ], -"org.eclipse.jetty:jetty-project:jetty-server/src/main/java/org/eclipse/jetty/server/InclusiveByteRange.java": [ -140 -], -"org.eclipse.jetty:jetty-project:jetty-server/src/main/java/org/eclipse/jetty/server/MultiPartFormInputStream.java": [ -518 -], -"org.eclipse.jetty:jetty-project:jetty-server/src/main/java/org/eclipse/jetty/server/ProxyConnectionFactory.java": [ -563 -], -"org.eclipse.jetty:jetty-project:jetty-server/src/main/java/org/eclipse/jetty/server/ResourceService.java": [ -481, -640 -], -"org.eclipse.jetty:jetty-project:jetty-server/src/main/java/org/eclipse/jetty/server/Utf8HttpWriter.java": [ -42 -], -"org.eclipse.jetty:jetty-project:jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java": [ -2097 -], -"org.eclipse.jetty:jetty-project:jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHandler.java": [ -547 -], -"org.eclipse.jetty:jetty-project:jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java": [ -1589 -], "org.eclipse.jetty:jetty-project:jetty-util-ajax/src/main/java/org/eclipse/jetty/util/ajax/AsyncJSON.java": [ 265 ], "org.eclipse.jetty:jetty-project:jetty-util-ajax/src/main/java/org/eclipse/jetty/util/ajax/JSON.java": [ 984 ], -"org.eclipse.jetty:jetty-project:jetty-util/src/main/java/org/eclipse/jetty/util/Scanner.java": [ -716 -], -"org.eclipse.jetty:jetty-project:jetty-util/src/main/java/org/eclipse/jetty/util/URIUtil.java": [ -92, -456, -797, -911 -], "org.eclipse.jetty:jetty-project:jetty-util/src/main/java/org/eclipse/jetty/util/UrlEncoded.java": [ 672 ], -"org.eclipse.jetty:jetty-project:jetty-util/src/main/java/org/eclipse/jetty/util/resource/JarResource.java": [ -136 -], -"org.eclipse.jetty:jetty-project:jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java": [ -481 -], -"org.eclipse.jetty:jetty-project:jetty-util/src/main/java/org/eclipse/jetty/util/ssl/SslContextFactory.java": [ -270 -], -"org.eclipse.jetty:jetty-project:jetty-util/src/main/java/org/eclipse/jetty/util/thread/QueuedThreadPool.java": [ -853 -], -"org.eclipse.jetty:jetty-project:jetty-util/src/main/java/org/eclipse/jetty/util/thread/strategy/EatWhatYouKill.java": [ -184 -], "org.eclipse.jetty:jetty-project:jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java": [ 506, 1277 diff --git a/java-checks-test-sources/default/src/main/java/checks/BrainMethodCheckSubsetCapped.java b/java-checks-test-sources/default/src/main/java/checks/BrainMethodCheckSubsetCapped.java new file mode 100644 index 00000000000..bae6c53481f --- /dev/null +++ b/java-checks-test-sources/default/src/main/java/checks/BrainMethodCheckSubsetCapped.java @@ -0,0 +1,380 @@ +package checks; + +// With numberOfFoundIssuesThreshold=5, issuesToReportPercentage=10, numberOfIssuesPerModuleThreshold=5: +// 60 issues found, 10% = 6 > numberOfIssuesPerModuleThreshold=5. +// Issues to report = min(60 * 10 / 100, 5) = min(6, 5) = 5. +// The 5 most complex methods (highest brain score) are reported. +class BrainMethodCheckSubsetCapped { + + void method1(String a, String b) { // Noncompliant + if (a != null) { + System.out.println("This is the most complex method"); + System.out.println("It has the most lines"); + System.out.println("To ensure it has the highest brain score"); + System.out.println("And will be the first to be reported"); + System.out.println(a + b); + } + } + + void method2(String a, String b) { // Noncompliant + if (a != null) { + System.out.println("Second most complex"); + System.out.println("Has four extra lines"); + System.out.println("More than simple methods"); + System.out.println(a + b); + } + } + + void method3(String a, String b) { // Noncompliant + if (a != null) { + System.out.println("Third most complex"); + System.out.println("Has three extra lines"); + System.out.println(a + b); + } + } + + void method4(String a, String b) { // Noncompliant + if (a != null) { + System.out.println("Fourth most complex"); + System.out.println(a + b); + } + } + + void method5(String a, String b) { // Noncompliant + if (a != null) { + System.out.println("Fifth most complex - last to be reported"); + System.out.println(a + b); + } + } + + void method6(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method7(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method8(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method9(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method10(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method11(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method12(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method13(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method14(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method15(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method16(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method17(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method18(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method19(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method20(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method21(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method22(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method23(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method24(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method25(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method26(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method27(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method28(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method29(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method30(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method31(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method32(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method33(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method34(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method35(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method36(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method37(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method38(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method39(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method40(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method41(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method42(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method43(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method44(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method45(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method46(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method47(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method48(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method49(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method50(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method51(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method52(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method53(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method54(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method55(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method56(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method57(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method58(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method59(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method60(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + +} \ No newline at end of file diff --git a/java-checks-test-sources/default/src/main/java/checks/BrainMethodCheckSubsetLarge.java b/java-checks-test-sources/default/src/main/java/checks/BrainMethodCheckSubsetLarge.java new file mode 100644 index 00000000000..a9629323a88 --- /dev/null +++ b/java-checks-test-sources/default/src/main/java/checks/BrainMethodCheckSubsetLarge.java @@ -0,0 +1,142 @@ +package checks; + +// With numberOfFoundIssuesThreshold=5, issuesToReportPercentage=10, numberOfIssuesPerModuleThreshold=20: +// 21 issues found > numberOfIssuesPerModuleThreshold=20. +// Issues to report = min(21 * 10 / 100, 20) = min(2, 20) = 2. +// The 2 most complex methods (highest brain score) are reported. +class BrainMethodCheckSubsetLarge { + + void method1(String a, String b) { // Noncompliant + if (a != null) { + System.out.println("This is the most complex method"); + System.out.println("It has the most lines"); + System.out.println("To ensure it has the highest brain score"); + System.out.println("And will be the first to be reported"); + System.out.println(a + b); + } + } + + void method2(String a, String b) { // Noncompliant + if (a != null) { + System.out.println("This method is reported second"); + System.out.println("It has more lines than the simple methods below"); + System.out.println("But fewer than method1"); + System.out.println(a + b); + } + } + + void method3(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method4(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method5(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method6(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method7(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method8(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method9(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method10(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method11(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method12(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method13(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method14(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method15(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method16(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method17(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method18(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method19(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method20(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + + void method21(String a, String b) { // Compliant + if (a != null) { + System.out.println(a + b); + } + } + +} \ No newline at end of file diff --git a/java-checks-test-sources/default/src/main/java/checks/BrainMethodCheckSubsetOfIssues.java b/java-checks-test-sources/default/src/main/java/checks/BrainMethodCheckSubsetOfIssues.java index a3eaf469d9f..fe3ba4f19ea 100644 --- a/java-checks-test-sources/default/src/main/java/checks/BrainMethodCheckSubsetOfIssues.java +++ b/java-checks-test-sources/default/src/main/java/checks/BrainMethodCheckSubsetOfIssues.java @@ -1,8 +1,9 @@ package checks; -//The test unit is set to report the first brain method issue + the total brain method issues found divided by 15, -//ordered by general complexity. -//In this file there are 10 issues found, so a total of 1 + (10 / 15 = 0) = 1 issue will be raised +// With numberOfFoundIssuesThreshold=5, issuesToReportPercentage=10, numberOfIssuesPerModuleThreshold=20: +// 10 issues found, numberOfFoundIssuesThreshold(5) < 10 < numberOfIssuesPerModuleThreshold(20). +// Issues to report = min(10 * 10 / 100, 20) = min(1, 20) = 1. +// The most complex method (highest brain score) is reported. class BrainMethodCheckSubsetOfIssues { void method1(String a, String b) { // Compliant: this will be skipped since the following method is more complex diff --git a/java-checks-test-sources/default/src/main/java/checks/BrainMethodCheckSubsetSmall.java b/java-checks-test-sources/default/src/main/java/checks/BrainMethodCheckSubsetSmall.java new file mode 100644 index 00000000000..30215b8940b --- /dev/null +++ b/java-checks-test-sources/default/src/main/java/checks/BrainMethodCheckSubsetSmall.java @@ -0,0 +1,24 @@ +package checks; + +// With numberOfFoundIssuesThreshold=5, 3 issues found is below the threshold, so all are reported. +class BrainMethodCheckSubsetSmall { + + void method1(String a, String b) { // Noncompliant + if (a != null) { + System.out.println(a + b); + } + } + + void method2(String a, String b) { // Noncompliant + if (a != null) { + System.out.println(a + b); + } + } + + void method3(String a, String b) { // Noncompliant + if (a != null) { + System.out.println(a + b); + } + } + +} diff --git a/java-checks/src/main/java/org/sonar/java/checks/design/BrainMethodCheck.java b/java-checks/src/main/java/org/sonar/java/checks/design/BrainMethodCheck.java index f4bb5d47368..13f53bf778f 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/design/BrainMethodCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/design/BrainMethodCheck.java @@ -68,7 +68,11 @@ public List nodesToVisit() { } @VisibleForTesting - int numberOfIssuesToReport = 10; + int numberOfFoundIssuesThreshold = 10; + @VisibleForTesting + int numberOfIssuesPerModuleThreshold = 50; + @VisibleForTesting + int issuesToReportPercentage = 10; private final List issuesFound = new ArrayList<>(); @Override @@ -111,11 +115,11 @@ private static boolean isExcluded(MethodTree methodTree) { @Override public void endOfAnalysis(ModuleScannerContext context) { - if (issuesFound.size() > numberOfIssuesToReport) { - numberOfIssuesToReport += issuesFound.size() / 15; + int numberOfIssuesToReport = issuesFound.size(); + if (numberOfIssuesToReport > numberOfFoundIssuesThreshold) { + // To reduce noise in large codebases, report only the most complex methods: a percentage of total found, up to a hard cap. + numberOfIssuesToReport = Math.min((numberOfIssuesToReport * issuesToReportPercentage) / 100, numberOfIssuesPerModuleThreshold); issuesFound.sort((a, b) -> b.brainScore - a.brainScore); - } else { - numberOfIssuesToReport = issuesFound.size(); } var defaultContext = (DefaultModuleScannerContext) context; for (int i = 0; i < numberOfIssuesToReport; i++) { diff --git a/java-checks/src/test/java/org/sonar/java/checks/design/BrainMethodCheckTest.java b/java-checks/src/test/java/org/sonar/java/checks/design/BrainMethodCheckTest.java index b65826d581b..b928b5f6711 100644 --- a/java-checks/src/test/java/org/sonar/java/checks/design/BrainMethodCheckTest.java +++ b/java-checks/src/test/java/org/sonar/java/checks/design/BrainMethodCheckTest.java @@ -25,7 +25,10 @@ class BrainMethodCheckTest { private static final String HIGH_COMPLEXITY_FILE_PATH = mainCodeSourcesPath("checks/BrainMethodCheckSample.java"); private static final String LOW_COMPLEXITY_FILE_PATH = mainCodeSourcesPath("checks/BrainMethodCheckLowerThresholds.java"); + private static final String SUBSET_SMALL_FILE_PATH = mainCodeSourcesPath("checks/BrainMethodCheckSubsetSmall.java"); private static final String SUBSET_FILE_PATH = mainCodeSourcesPath("checks/BrainMethodCheckSubsetOfIssues.java"); + private static final String SUBSET_LARGE_FILE_PATH = mainCodeSourcesPath("checks/BrainMethodCheckSubsetLarge.java"); + private static final String SUBSET_CAPPED_FILE_PATH = mainCodeSourcesPath("checks/BrainMethodCheckSubsetCapped.java"); @Test void testHighComplexityFileWithDefaultThresholds() { @@ -73,20 +76,66 @@ void testLowComplexityFileWithLowerThresholds() { } @Test - void testSubsetOfIssuesWithLowerThresholds() { - var check = new BrainMethodCheck(); + void testSubsetAllIssuesReportedBelowThreshold() { + // 3 issues found < numberOfFoundIssuesThreshold=5: all issues are reported + CheckVerifier.newVerifier() + .onFile(SUBSET_SMALL_FILE_PATH) + .withChecks(checkForSubsetTests()) + .verifyIssues(); + } + + @Test + void testSubsetPercentageAppliedBetweenThresholds() { + // 10 issues found, numberOfFoundIssuesThreshold(5) < 10 < numberOfIssuesPerModuleThreshold(20): + // reports min(10 * 10 / 100, 20) = 1 issue + CheckVerifier.newVerifier() + .onFile(SUBSET_FILE_PATH) + .withChecks(checkForSubsetTests()) + .verifyIssues(); + } + + @Test + void testSubsetPercentageAppliedAboveModuleThreshold() { + // 21 issues found > numberOfIssuesPerModuleThreshold=20: + // reports min(21 * 10 / 100, 20) = 2 issues + CheckVerifier.newVerifier() + .onFile(SUBSET_LARGE_FILE_PATH) + .withChecks(checkForSubsetTests()) + .verifyIssues(); + } + + @Test + void testSubsetCappedAtModuleThreshold() { + // 60 issues found, 10% = 6 > numberOfIssuesPerModuleThreshold=5: + // reports min(60 * 10 / 100, 5) = 5 issues — cap is the binding constraint + CheckVerifier.newVerifier() + .onFile(SUBSET_CAPPED_FILE_PATH) + .withChecks(checkForCappedSubsetTest()) + .verifyIssues(); + } + private static BrainMethodCheck checkForSubsetTests() { + var check = new BrainMethodCheck(); check.locThreshold = 4; check.nodvThreshold = 2; check.cyclomaticThreshold = 1; check.nestingThreshold = 1; + check.numberOfFoundIssuesThreshold = 5; + check.issuesToReportPercentage = 10; + check.numberOfIssuesPerModuleThreshold = 20; + return check; + } - check.numberOfIssuesToReport = 1; - - CheckVerifier.newVerifier() - .onFile(SUBSET_FILE_PATH) - .withChecks(check) - .verifyIssues(); + private static BrainMethodCheck checkForCappedSubsetTest() { + var check = new BrainMethodCheck(); + check.locThreshold = 4; + check.nodvThreshold = 2; + check.cyclomaticThreshold = 1; + check.nestingThreshold = 1; + check.numberOfFoundIssuesThreshold = 5; + check.issuesToReportPercentage = 10; + check.numberOfIssuesPerModuleThreshold = 5; + return check; } } From 3f39887ee7284a3d92f6255b4a4a34bca65e93b0 Mon Sep 17 00:00:00 2001 From: asya-vorobeva Date: Thu, 2 Jul 2026 14:28:50 +0200 Subject: [PATCH 4/5] S6541: use threshold as base for reported issues count, cap additional percentage-based issues Co-Authored-By: Claude Sonnet 4.6 --- .../java-S6541.json | 52 ++++++++++++- .../resources/eclipse-jetty/java-S6541.json | 76 ++++++++++++++++++- .../checks/BrainMethodCheckSubsetCapped.java | 18 ++--- .../checks/BrainMethodCheckSubsetLarge.java | 18 ++--- .../BrainMethodCheckSubsetOfIssues.java | 34 ++++----- .../java/checks/design/BrainMethodCheck.java | 8 +- .../checks/design/BrainMethodCheckTest.java | 16 ++-- 7 files changed, 174 insertions(+), 48 deletions(-) diff --git a/its/ruling/src/test/resources/eclipse-jetty-similar-to-main/java-S6541.json b/its/ruling/src/test/resources/eclipse-jetty-similar-to-main/java-S6541.json index f246020a8ac..e7eaae6a66a 100644 --- a/its/ruling/src/test/resources/eclipse-jetty-similar-to-main/java-S6541.json +++ b/its/ruling/src/test/resources/eclipse-jetty-similar-to-main/java-S6541.json @@ -1,6 +1,28 @@ { +"org.eclipse.jetty:jetty-project:jetty-http/src/main/java/org/eclipse/jetty/http/CookieCutter.java": [ +46 +], +"org.eclipse.jetty:jetty-project:jetty-http/src/main/java/org/eclipse/jetty/http/GZIPContentDecoder.java": [ +160 +], +"org.eclipse.jetty:jetty-project:jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java": [ +358, +573 +], "org.eclipse.jetty:jetty-project:jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java": [ -1080 +571, +1080, +1613 +], +"org.eclipse.jetty:jetty-project:jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java": [ +783 +], +"org.eclipse.jetty:jetty-project:jetty-http/src/main/java/org/eclipse/jetty/http/MimeTypes.java": [ +416, +563 +], +"org.eclipse.jetty:jetty-project:jetty-http/src/main/java/org/eclipse/jetty/http/QuotedCSVParser.java": [ +96 ], "org.eclipse.jetty:jetty-project:jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java": [ 595, @@ -10,10 +32,38 @@ "org.eclipse.jetty:jetty-project:jetty-jmx/src/main/java/org/eclipse/jetty/jmx/MBeanContainer.java": [ 297 ], +"org.eclipse.jetty:jetty-project:jetty-server/src/main/java/org/eclipse/jetty/server/CachedContentFactory.java": [ +213 +], "org.eclipse.jetty:jetty-project:jetty-server/src/main/java/org/eclipse/jetty/server/CustomRequestLog.java": [ 579 ], "org.eclipse.jetty:jetty-project:jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java": [ 328 +], +"org.eclipse.jetty:jetty-project:jetty-server/src/main/java/org/eclipse/jetty/server/InclusiveByteRange.java": [ +140 +], +"org.eclipse.jetty:jetty-project:jetty-server/src/main/java/org/eclipse/jetty/server/MultiPartFormInputStream.java": [ +518 +], +"org.eclipse.jetty:jetty-project:jetty-server/src/main/java/org/eclipse/jetty/server/ProxyConnectionFactory.java": [ +563 +], +"org.eclipse.jetty:jetty-project:jetty-server/src/main/java/org/eclipse/jetty/server/ResourceService.java": [ +481, +640 +], +"org.eclipse.jetty:jetty-project:jetty-server/src/main/java/org/eclipse/jetty/server/Utf8HttpWriter.java": [ +42 +], +"org.eclipse.jetty:jetty-project:jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java": [ +2097 +], +"org.eclipse.jetty:jetty-project:jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHandler.java": [ +547 +], +"org.eclipse.jetty:jetty-project:jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java": [ +1589 ] } diff --git a/its/ruling/src/test/resources/eclipse-jetty/java-S6541.json b/its/ruling/src/test/resources/eclipse-jetty/java-S6541.json index a104c0fccdb..3e3676fe629 100644 --- a/its/ruling/src/test/resources/eclipse-jetty/java-S6541.json +++ b/its/ruling/src/test/resources/eclipse-jetty/java-S6541.json @@ -1,6 +1,28 @@ { +"org.eclipse.jetty:jetty-project:jetty-http/src/main/java/org/eclipse/jetty/http/CookieCutter.java": [ +46 +], +"org.eclipse.jetty:jetty-project:jetty-http/src/main/java/org/eclipse/jetty/http/GZIPContentDecoder.java": [ +160 +], +"org.eclipse.jetty:jetty-project:jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java": [ +358, +573 +], "org.eclipse.jetty:jetty-project:jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java": [ -1080 +571, +1080, +1613 +], +"org.eclipse.jetty:jetty-project:jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java": [ +783 +], +"org.eclipse.jetty:jetty-project:jetty-http/src/main/java/org/eclipse/jetty/http/MimeTypes.java": [ +416, +563 +], +"org.eclipse.jetty:jetty-project:jetty-http/src/main/java/org/eclipse/jetty/http/QuotedCSVParser.java": [ +96 ], "org.eclipse.jetty:jetty-project:jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java": [ 595, @@ -10,21 +32,73 @@ "org.eclipse.jetty:jetty-project:jetty-jmx/src/main/java/org/eclipse/jetty/jmx/MBeanContainer.java": [ 297 ], +"org.eclipse.jetty:jetty-project:jetty-server/src/main/java/org/eclipse/jetty/server/CachedContentFactory.java": [ +213 +], "org.eclipse.jetty:jetty-project:jetty-server/src/main/java/org/eclipse/jetty/server/CustomRequestLog.java": [ 579 ], "org.eclipse.jetty:jetty-project:jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java": [ 328 ], +"org.eclipse.jetty:jetty-project:jetty-server/src/main/java/org/eclipse/jetty/server/InclusiveByteRange.java": [ +140 +], +"org.eclipse.jetty:jetty-project:jetty-server/src/main/java/org/eclipse/jetty/server/MultiPartFormInputStream.java": [ +518 +], +"org.eclipse.jetty:jetty-project:jetty-server/src/main/java/org/eclipse/jetty/server/ProxyConnectionFactory.java": [ +563 +], +"org.eclipse.jetty:jetty-project:jetty-server/src/main/java/org/eclipse/jetty/server/ResourceService.java": [ +481, +640 +], +"org.eclipse.jetty:jetty-project:jetty-server/src/main/java/org/eclipse/jetty/server/Utf8HttpWriter.java": [ +42 +], +"org.eclipse.jetty:jetty-project:jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java": [ +2097 +], +"org.eclipse.jetty:jetty-project:jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHandler.java": [ +547 +], +"org.eclipse.jetty:jetty-project:jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java": [ +1589 +], "org.eclipse.jetty:jetty-project:jetty-util-ajax/src/main/java/org/eclipse/jetty/util/ajax/AsyncJSON.java": [ 265 ], "org.eclipse.jetty:jetty-project:jetty-util-ajax/src/main/java/org/eclipse/jetty/util/ajax/JSON.java": [ 984 ], +"org.eclipse.jetty:jetty-project:jetty-util/src/main/java/org/eclipse/jetty/util/Scanner.java": [ +716 +], +"org.eclipse.jetty:jetty-project:jetty-util/src/main/java/org/eclipse/jetty/util/URIUtil.java": [ +92, +456, +797, +911 +], "org.eclipse.jetty:jetty-project:jetty-util/src/main/java/org/eclipse/jetty/util/UrlEncoded.java": [ 672 ], +"org.eclipse.jetty:jetty-project:jetty-util/src/main/java/org/eclipse/jetty/util/resource/JarResource.java": [ +136 +], +"org.eclipse.jetty:jetty-project:jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java": [ +481 +], +"org.eclipse.jetty:jetty-project:jetty-util/src/main/java/org/eclipse/jetty/util/ssl/SslContextFactory.java": [ +270 +], +"org.eclipse.jetty:jetty-project:jetty-util/src/main/java/org/eclipse/jetty/util/thread/QueuedThreadPool.java": [ +853 +], +"org.eclipse.jetty:jetty-project:jetty-util/src/main/java/org/eclipse/jetty/util/thread/strategy/EatWhatYouKill.java": [ +184 +], "org.eclipse.jetty:jetty-project:jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java": [ 506, 1277 diff --git a/java-checks-test-sources/default/src/main/java/checks/BrainMethodCheckSubsetCapped.java b/java-checks-test-sources/default/src/main/java/checks/BrainMethodCheckSubsetCapped.java index bae6c53481f..4b7d8663169 100644 --- a/java-checks-test-sources/default/src/main/java/checks/BrainMethodCheckSubsetCapped.java +++ b/java-checks-test-sources/default/src/main/java/checks/BrainMethodCheckSubsetCapped.java @@ -1,9 +1,9 @@ package checks; -// With numberOfFoundIssuesThreshold=5, issuesToReportPercentage=10, numberOfIssuesPerModuleThreshold=5: -// 60 issues found, 10% = 6 > numberOfIssuesPerModuleThreshold=5. -// Issues to report = min(60 * 10 / 100, 5) = min(6, 5) = 5. -// The 5 most complex methods (highest brain score) are reported. +// With numberOfFoundIssuesThreshold=5, issuesToReportPercentage=10, numberOfAdditionalIssuesThreshold=5: +// 60 issues found, 10% = 6 > numberOfAdditionalIssuesThreshold=5. +// Issues to report = numberOfFoundIssuesThreshold + min(60 * 10 / 100, 5) = 5 + min(6, 5) = 10. +// The 10 most complex methods (highest brain score) are reported. class BrainMethodCheckSubsetCapped { void method1(String a, String b) { // Noncompliant @@ -47,31 +47,31 @@ void method5(String a, String b) { // Noncompliant } } - void method6(String a, String b) { // Compliant + void method6(String a, String b) { // Noncompliant if (a != null) { System.out.println(a + b); } } - void method7(String a, String b) { // Compliant + void method7(String a, String b) { // Noncompliant if (a != null) { System.out.println(a + b); } } - void method8(String a, String b) { // Compliant + void method8(String a, String b) { // Noncompliant if (a != null) { System.out.println(a + b); } } - void method9(String a, String b) { // Compliant + void method9(String a, String b) { // Noncompliant if (a != null) { System.out.println(a + b); } } - void method10(String a, String b) { // Compliant + void method10(String a, String b) { // Noncompliant if (a != null) { System.out.println(a + b); } diff --git a/java-checks-test-sources/default/src/main/java/checks/BrainMethodCheckSubsetLarge.java b/java-checks-test-sources/default/src/main/java/checks/BrainMethodCheckSubsetLarge.java index a9629323a88..41545fac2cb 100644 --- a/java-checks-test-sources/default/src/main/java/checks/BrainMethodCheckSubsetLarge.java +++ b/java-checks-test-sources/default/src/main/java/checks/BrainMethodCheckSubsetLarge.java @@ -1,9 +1,9 @@ package checks; -// With numberOfFoundIssuesThreshold=5, issuesToReportPercentage=10, numberOfIssuesPerModuleThreshold=20: -// 21 issues found > numberOfIssuesPerModuleThreshold=20. -// Issues to report = min(21 * 10 / 100, 20) = min(2, 20) = 2. -// The 2 most complex methods (highest brain score) are reported. +// With numberOfFoundIssuesThreshold=5, issuesToReportPercentage=10, numberOfAdditionalIssuesThreshold=20: +// 21 issues found > numberOfAdditionalIssuesThreshold=20. +// Issues to report = numberOfFoundIssuesThreshold + min(21 * 10 / 100, 20) = 5 + min(2, 20) = 7. +// The 7 most complex methods (highest brain score) are reported. class BrainMethodCheckSubsetLarge { void method1(String a, String b) { // Noncompliant @@ -25,31 +25,31 @@ void method2(String a, String b) { // Noncompliant } } - void method3(String a, String b) { // Compliant + void method3(String a, String b) { // Noncompliant if (a != null) { System.out.println(a + b); } } - void method4(String a, String b) { // Compliant + void method4(String a, String b) { // Noncompliant if (a != null) { System.out.println(a + b); } } - void method5(String a, String b) { // Compliant + void method5(String a, String b) { // Noncompliant if (a != null) { System.out.println(a + b); } } - void method6(String a, String b) { // Compliant + void method6(String a, String b) { // Noncompliant if (a != null) { System.out.println(a + b); } } - void method7(String a, String b) { // Compliant + void method7(String a, String b) { // Noncompliant if (a != null) { System.out.println(a + b); } diff --git a/java-checks-test-sources/default/src/main/java/checks/BrainMethodCheckSubsetOfIssues.java b/java-checks-test-sources/default/src/main/java/checks/BrainMethodCheckSubsetOfIssues.java index fe3ba4f19ea..aa8a01d1f8f 100644 --- a/java-checks-test-sources/default/src/main/java/checks/BrainMethodCheckSubsetOfIssues.java +++ b/java-checks-test-sources/default/src/main/java/checks/BrainMethodCheckSubsetOfIssues.java @@ -1,19 +1,19 @@ package checks; -// With numberOfFoundIssuesThreshold=5, issuesToReportPercentage=10, numberOfIssuesPerModuleThreshold=20: -// 10 issues found, numberOfFoundIssuesThreshold(5) < 10 < numberOfIssuesPerModuleThreshold(20). -// Issues to report = min(10 * 10 / 100, 20) = min(1, 20) = 1. -// The most complex method (highest brain score) is reported. +// With numberOfFoundIssuesThreshold=5, issuesToReportPercentage=10, numberOfAdditionalIssuesThreshold=20: +// 10 issues found, numberOfFoundIssuesThreshold(5) < 10 < numberOfAdditionalIssuesThreshold(20). +// Issues to report = numberOfFoundIssuesThreshold + min(10 * 10 / 100, 20) = 5 + min(1, 20) = 6. +// The most complex method is reported first, then the next 5 by brain score. class BrainMethodCheckSubsetOfIssues { - void method1(String a, String b) { // Compliant: this will be skipped since the following method is more complex + void method1(String a, String b) { // Noncompliant if (a != null) { System.out.println(a + b); } } - - void method2(String a, String b) { // Compliant: this will be skipped since the following method is more complex + + void method2(String a, String b) { // Noncompliant if (a != null) { System.out.println(a + b); } @@ -27,50 +27,50 @@ void method3(String a, String b) { // Noncompliant } } - void method4(String a, String b) { // Compliant + void method4(String a, String b) { // Noncompliant if (a != null) { System.out.println(a + b); } } - void method5(String a, String b) { // Compliant + void method5(String a, String b) { // Noncompliant if (a != null) { System.out.println(a + b); } } - - void method6(String a, String b) { // Compliant + + void method6(String a, String b) { // Noncompliant if (a != null) { System.out.println(a + b); } } - + void method7(String a, String b) { // Compliant if (a != null) { System.out.println(a + b); } } - + void method8(String a, String b) { // Compliant if (a != null) { System.out.println(a + b); } } - + void method9(String a, String b) { // Compliant if (a != null) { System.out.println(a + b); } } - + void method10(String a, String b) { // Compliant if (a != null) { System.out.println(a + b); } } - + void compliantMethod() { System.out.println("Hello world"); } -} +} \ No newline at end of file diff --git a/java-checks/src/main/java/org/sonar/java/checks/design/BrainMethodCheck.java b/java-checks/src/main/java/org/sonar/java/checks/design/BrainMethodCheck.java index 13f53bf778f..31f5a1c50ca 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/design/BrainMethodCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/design/BrainMethodCheck.java @@ -70,7 +70,7 @@ public List nodesToVisit() { @VisibleForTesting int numberOfFoundIssuesThreshold = 10; @VisibleForTesting - int numberOfIssuesPerModuleThreshold = 50; + int numberOfAdditionalIssuesThreshold = 20; @VisibleForTesting int issuesToReportPercentage = 10; private final List issuesFound = new ArrayList<>(); @@ -117,8 +117,10 @@ private static boolean isExcluded(MethodTree methodTree) { public void endOfAnalysis(ModuleScannerContext context) { int numberOfIssuesToReport = issuesFound.size(); if (numberOfIssuesToReport > numberOfFoundIssuesThreshold) { - // To reduce noise in large codebases, report only the most complex methods: a percentage of total found, up to a hard cap. - numberOfIssuesToReport = Math.min((numberOfIssuesToReport * issuesToReportPercentage) / 100, numberOfIssuesPerModuleThreshold); + // To reduce noise in large codebases, always report at least numberOfFoundIssuesThreshold issues, + // plus a percentage of total found — but the percentage component is capped at numberOfAdditionalIssuesThreshold. + numberOfIssuesToReport = numberOfFoundIssuesThreshold + + Math.min((numberOfIssuesToReport * issuesToReportPercentage) / 100, numberOfAdditionalIssuesThreshold); issuesFound.sort((a, b) -> b.brainScore - a.brainScore); } var defaultContext = (DefaultModuleScannerContext) context; diff --git a/java-checks/src/test/java/org/sonar/java/checks/design/BrainMethodCheckTest.java b/java-checks/src/test/java/org/sonar/java/checks/design/BrainMethodCheckTest.java index b928b5f6711..c58add2ce93 100644 --- a/java-checks/src/test/java/org/sonar/java/checks/design/BrainMethodCheckTest.java +++ b/java-checks/src/test/java/org/sonar/java/checks/design/BrainMethodCheckTest.java @@ -86,8 +86,8 @@ void testSubsetAllIssuesReportedBelowThreshold() { @Test void testSubsetPercentageAppliedBetweenThresholds() { - // 10 issues found, numberOfFoundIssuesThreshold(5) < 10 < numberOfIssuesPerModuleThreshold(20): - // reports min(10 * 10 / 100, 20) = 1 issue + // 10 issues found, numberOfFoundIssuesThreshold(5) < 10 < numberOfAdditionalIssuesThreshold(20): + // reports 5 + min(10 * 10 / 100, 20) = 5 + 1 = 6 issues CheckVerifier.newVerifier() .onFile(SUBSET_FILE_PATH) .withChecks(checkForSubsetTests()) @@ -96,8 +96,8 @@ void testSubsetPercentageAppliedBetweenThresholds() { @Test void testSubsetPercentageAppliedAboveModuleThreshold() { - // 21 issues found > numberOfIssuesPerModuleThreshold=20: - // reports min(21 * 10 / 100, 20) = 2 issues + // 21 issues found > numberOfAdditionalIssuesThreshold=20: + // reports 5 + min(21 * 10 / 100, 20) = 5 + 2 = 7 issues CheckVerifier.newVerifier() .onFile(SUBSET_LARGE_FILE_PATH) .withChecks(checkForSubsetTests()) @@ -106,8 +106,8 @@ void testSubsetPercentageAppliedAboveModuleThreshold() { @Test void testSubsetCappedAtModuleThreshold() { - // 60 issues found, 10% = 6 > numberOfIssuesPerModuleThreshold=5: - // reports min(60 * 10 / 100, 5) = 5 issues — cap is the binding constraint + // 60 issues found, 10% = 6 > numberOfAdditionalIssuesThreshold=5: + // reports 5 + min(60 * 10 / 100, 5) = 5 + 5 = 10 issues — percentage component is capped CheckVerifier.newVerifier() .onFile(SUBSET_CAPPED_FILE_PATH) .withChecks(checkForCappedSubsetTest()) @@ -122,7 +122,7 @@ private static BrainMethodCheck checkForSubsetTests() { check.nestingThreshold = 1; check.numberOfFoundIssuesThreshold = 5; check.issuesToReportPercentage = 10; - check.numberOfIssuesPerModuleThreshold = 20; + check.numberOfAdditionalIssuesThreshold = 20; return check; } @@ -134,7 +134,7 @@ private static BrainMethodCheck checkForCappedSubsetTest() { check.nestingThreshold = 1; check.numberOfFoundIssuesThreshold = 5; check.issuesToReportPercentage = 10; - check.numberOfIssuesPerModuleThreshold = 5; + check.numberOfAdditionalIssuesThreshold = 5; return check; } From 0acace4a33fbfec9f5dceffa9919641e91c3f489 Mon Sep 17 00:00:00 2001 From: asya-vorobeva Date: Thu, 2 Jul 2026 14:44:20 +0200 Subject: [PATCH 5/5] Move status to Ready --- .../main/resources/org/sonar/l10n/java/rules/java/S6541.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S6541.json b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S6541.json index 35efa572ed0..77c3dd9f377 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S6541.json +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S6541.json @@ -7,7 +7,7 @@ }, "attribute": "FOCUSED" }, - "status": "beta", + "status": "ready", "remediation": { "func": "Constant\/Issue", "constantCost": "0min"