diff --git a/its/ruling/src/test/java/org/sonar/java/it/JavaRulingTest.java b/its/ruling/src/test/java/org/sonar/java/it/JavaRulingTest.java index 623565518..8a1ccf79b 100644 --- a/its/ruling/src/test/java/org/sonar/java/it/JavaRulingTest.java +++ b/its/ruling/src/test/java/org/sonar/java/it/JavaRulingTest.java @@ -61,7 +61,7 @@ public class JavaRulingTest { private static final Logger LOG = LoggerFactory.getLogger(JavaRulingTest.class); private static final ImmutableSet SUBSET_OF_ENABLED_RULES = ImmutableSet.of( - "S2095", "S2189", "S2222", "S2259", "S2583", "S2589", "S2637", "S2689", "S2755", "S3065", + "S2095", "S2189", "S2222", "S2583", "S2589", "S2637", "S2689", "S2755", "S3065", "S3516", "S3518", "S3546", "S3655", "S3824", "S3958", "S3959", "S4165", "S4449", "S6373", "S6374", "S6376", "S6377"); @ClassRule @@ -96,7 +96,7 @@ public static void prepare() throws Exception { List extraNonDefaultRules = List.of("S3546", "S6374"); ProfileGenerator.generate(ORCHESTRATOR, "Sonar Way", ImmutableMap.of(), new HashSet<>(), SUBSET_OF_ENABLED_RULES, result, extraNonDefaultRules); - assertThat(result).hasSize(23); // ALL symbolic-execution rules + assertThat(result).hasSize(22); // ALL symbolic-execution rules minus S2259 that has been deprecated Path allRulesFolder = Paths.get("src/test/resources"); effectiveDumpOldFolder = tmpDumpOldFolder.getRoot().toPath().toAbsolutePath(); diff --git a/java-symbolic-execution/java-symbolic-execution-plugin/src/main/java/org/sonar/java/se/plugin/JavaSECheckList.java b/java-symbolic-execution/java-symbolic-execution-plugin/src/main/java/org/sonar/java/se/plugin/JavaSECheckList.java index 165fad9c6..b694f3fe9 100644 --- a/java-symbolic-execution/java-symbolic-execution-plugin/src/main/java/org/sonar/java/se/plugin/JavaSECheckList.java +++ b/java-symbolic-execution/java-symbolic-execution-plugin/src/main/java/org/sonar/java/se/plugin/JavaSECheckList.java @@ -17,6 +17,8 @@ package org.sonar.java.se.plugin; import java.util.List; +import java.util.Set; +import java.util.function.Predicate; import org.sonar.java.se.checks.AllowXMLInclusionCheck; import org.sonar.java.se.checks.BooleanGratuitousExpressionsCheck; import org.sonar.java.se.checks.ConditionalUnreachableCodeCheck; @@ -43,6 +45,12 @@ import org.sonar.java.se.checks.XxeProcessingCheck; public class JavaSECheckList { + /** + * A list of checks that are overridden by other analyzers. + */ + public static final Set> OVERRIDDEN_CHECKS = Set.of( + NullDereferenceCheck.class // S2259 + ); private JavaSECheckList(){ // no need to instantiate @@ -79,4 +87,14 @@ public static List> getChecks() { MinMaxRangeCheck.class); } + /** + * Compute a list of checks that are not overridden by other analyzers. + * @return the list of checks returned by {@link #getChecks()} minus the checks in {@link #OVERRIDDEN_CHECKS}. + */ + public static List> getNonOverriddenChecks() { + return getChecks().stream() + .filter(Predicate.not(OVERRIDDEN_CHECKS::contains)) + .toList(); + } + } diff --git a/java-symbolic-execution/java-symbolic-execution-plugin/src/main/java/org/sonar/java/se/plugin/JavaSECheckRegistrar.java b/java-symbolic-execution/java-symbolic-execution-plugin/src/main/java/org/sonar/java/se/plugin/JavaSECheckRegistrar.java index 5a0a79d7d..630668ab3 100644 --- a/java-symbolic-execution/java-symbolic-execution-plugin/src/main/java/org/sonar/java/se/plugin/JavaSECheckRegistrar.java +++ b/java-symbolic-execution/java-symbolic-execution-plugin/src/main/java/org/sonar/java/se/plugin/JavaSECheckRegistrar.java @@ -17,7 +17,10 @@ package org.sonar.java.se.plugin; import java.util.ArrayList; +import java.util.List; import java.util.Set; +import org.sonar.api.SonarEdition; +import org.sonar.api.SonarProduct; import org.sonar.api.SonarRuntime; import org.sonar.api.batch.rule.CheckFactory; import org.sonar.api.batch.rule.Checks; @@ -25,6 +28,7 @@ import org.sonar.api.scanner.ScannerSide; import org.sonar.api.server.ServerSide; import org.sonar.api.server.rule.RulesDefinition; +import org.sonar.java.annotations.VisibleForTesting; import org.sonar.java.se.SymbolicExecutionVisitor; import org.sonar.java.se.checks.SECheck; import org.sonar.plugins.java.api.CheckRegistrar; @@ -54,7 +58,7 @@ public void register(RegistrarContext registrarContext) { @Override public void register(RegistrarContext registrarContext, CheckFactory checkFactory) { - Checks checks = checkFactory.create(REPOSITORY_KEY).addAnnotatedChecks(JavaSECheckList.getChecks()); + Checks checks = checkFactory.create(REPOSITORY_KEY).addAnnotatedChecks(getChecks(runtime)); var seChecks = checks.all().stream() .filter(SECheck.class::isInstance) @@ -71,11 +75,35 @@ public void register(RegistrarContext registrarContext, CheckFactory checkFactor public void customRulesDefinition(RulesDefinition.Context context, RulesDefinition.NewRepository javaRepository) { RuleMetadataLoader ruleMetadataLoader = new RuleMetadataLoader(RESOURCE_BASE_PATH, SONAR_WAY_PATH, runtime); - ruleMetadataLoader.addRulesByAnnotatedClass(javaRepository, new ArrayList<>(JavaSECheckList.getChecks())); + ruleMetadataLoader.addRulesByAnnotatedClass(javaRepository, new ArrayList<>(getChecks(runtime))); setTemplates(javaRepository); } + @VisibleForTesting + /** + * Returns a list of checks based on whether the runtime might include other analyzers that provide alternative implementation of checks. + * @param runtime The analysis runtime + * @returns The full list of checks in SQCB, a reduced list of checks in other runtime. + */ + static List> getChecks(SonarRuntime runtime) { + if (isStandaloneSymbolicExecutionAnalyzer(runtime)) { + return JavaSECheckList.getChecks(); + } + return JavaSECheckList.getNonOverriddenChecks(); + } + + @VisibleForTesting + /** + * Test if the analyzer is running in a context where another analyzer has overridden some of its checks. + * @param The analysis runtime + * @return true if not + */ + static boolean isStandaloneSymbolicExecutionAnalyzer(SonarRuntime runtime) { + return runtime.getProduct() != SonarProduct.SONARLINT && + runtime.getEdition() == SonarEdition.COMMUNITY; + } + private static void setTemplates(RulesDefinition.NewRepository repository) { RULE_TEMPLATES_KEY.forEach(ruleKey -> repository.rule(ruleKey).setTemplate(true)); } diff --git a/java-symbolic-execution/java-symbolic-execution-plugin/src/main/java/org/sonar/java/se/plugin/RulesList.java b/java-symbolic-execution/java-symbolic-execution-plugin/src/main/java/org/sonar/java/se/plugin/RulesList.java index 26608a629..7ee8f3541 100644 --- a/java-symbolic-execution/java-symbolic-execution-plugin/src/main/java/org/sonar/java/se/plugin/RulesList.java +++ b/java-symbolic-execution/java-symbolic-execution-plugin/src/main/java/org/sonar/java/se/plugin/RulesList.java @@ -29,7 +29,6 @@ public static List getSonarWayRuleKeys() { "S2095", "S2189", "S2222", - "S2259", "S2583", "S2589", "S2637", diff --git a/java-symbolic-execution/java-symbolic-execution-plugin/src/main/resources/org/sonar/l10n/java/rules/javase/Sonar_way_profile.json b/java-symbolic-execution/java-symbolic-execution-plugin/src/main/resources/org/sonar/l10n/java/rules/javase/Sonar_way_profile.json index bf7388964..6c131982b 100644 --- a/java-symbolic-execution/java-symbolic-execution-plugin/src/main/resources/org/sonar/l10n/java/rules/javase/Sonar_way_profile.json +++ b/java-symbolic-execution/java-symbolic-execution-plugin/src/main/resources/org/sonar/l10n/java/rules/javase/Sonar_way_profile.json @@ -4,7 +4,6 @@ "S2095", "S2189", "S2222", - "S2259", "S2583", "S2589", "S2637", diff --git a/java-symbolic-execution/java-symbolic-execution-plugin/src/test/java/org/sonar/java/se/plugin/JavaSECheckListTest.java b/java-symbolic-execution/java-symbolic-execution-plugin/src/test/java/org/sonar/java/se/plugin/JavaSECheckListTest.java index 0c9cdc40b..1c18da5f3 100644 --- a/java-symbolic-execution/java-symbolic-execution-plugin/src/test/java/org/sonar/java/se/plugin/JavaSECheckListTest.java +++ b/java-symbolic-execution/java-symbolic-execution-plugin/src/test/java/org/sonar/java/se/plugin/JavaSECheckListTest.java @@ -23,8 +23,16 @@ class JavaSECheckListTest { @Test - void getChecks() { - assertThat(JavaSECheckList.getChecks()).isNotNull().hasSize(23); + void getNonOverriddenChecks_returns_a_list_of_checks_that_are_not_overridden_by_other_plugins() { + assertThat(JavaSECheckList.getNonOverriddenChecks()) + .hasSize(22) + .doesNotContainAnyElementsOf(JavaSECheckList.OVERRIDDEN_CHECKS); + } + + @Test + void getChecks_returns_the_full_list_of_checks() { + assertThat(JavaSECheckList.getChecks()) + .hasSize(23); } } diff --git a/java-symbolic-execution/java-symbolic-execution-plugin/src/test/java/org/sonar/java/se/plugin/JavaSECheckRegistrarTest.java b/java-symbolic-execution/java-symbolic-execution-plugin/src/test/java/org/sonar/java/se/plugin/JavaSECheckRegistrarTest.java index 725c1bca0..fdc805027 100644 --- a/java-symbolic-execution/java-symbolic-execution-plugin/src/test/java/org/sonar/java/se/plugin/JavaSECheckRegistrarTest.java +++ b/java-symbolic-execution/java-symbolic-execution-plugin/src/test/java/org/sonar/java/se/plugin/JavaSECheckRegistrarTest.java @@ -54,9 +54,31 @@ class JavaSECheckRegistrarTest { "S6374" ); + private static final SonarRuntime SQC = SonarRuntimeImpl.forSonarQube( + Version.parse("8.1"), + SonarQubeSide.SERVER, + SonarEdition.SONARCLOUD + ); + private static final SonarRuntime SQCB = SonarRuntimeImpl.forSonarQube( + Version.parse("25.1"), + SonarQubeSide.SERVER, + SonarEdition.COMMUNITY + ); + private static final SonarRuntime SQS_DEVELOPER = SonarRuntimeImpl.forSonarQube( + Version.parse("2025.1"), + SonarQubeSide.SERVER, + SonarEdition.DEVELOPER + ); + private static final SonarRuntime SQ_FOR_IDE = SonarRuntimeImpl.forSonarLint(Version.parse("10.22.0.81232")); + @Test void register_rules() { - CheckRegistrar registrar = new JavaSECheckRegistrar(null); + SonarRuntime sonarqubeServerDeveloper = SonarRuntimeImpl.forSonarQube( + Version.parse("2025.1"), + SonarQubeSide.SERVER, + SonarEdition.DEVELOPER + ); + CheckRegistrar registrar = new JavaSECheckRegistrar(sonarqubeServerDeveloper); TestCheckRegistrarContext context = new TestCheckRegistrarContext(); CheckFactory checkFactory = new CheckFactory(activeRules); @@ -66,6 +88,25 @@ void register_rules() { assertThat(context.testRuleKeys).isEmpty(); } + @Test + void getChecks_returns_the_expected_amount_of_checks_depending_on_the_runtime() { + assertThat(JavaSECheckRegistrar.getChecks(SQC)).hasSize(22); + assertThat(JavaSECheckRegistrar.getChecks(SQS_DEVELOPER)).hasSize(22); + assertThat(JavaSECheckRegistrar.getChecks(SQ_FOR_IDE)).hasSize(22); + assertThat(JavaSECheckRegistrar.getChecks(SQCB)).hasSize(23); + } + + @Test + void is_only_in_standalone_mode_in_sqcb() { + assertThat(JavaSECheckRegistrar.isStandaloneSymbolicExecutionAnalyzer(SQCB)).isTrue(); + + assertThat(JavaSECheckRegistrar.isStandaloneSymbolicExecutionAnalyzer(SQS_DEVELOPER)).isFalse(); + assertThat(JavaSECheckRegistrar.isStandaloneSymbolicExecutionAnalyzer(SQC)).isFalse(); + + assertThat(JavaSECheckRegistrar.isStandaloneSymbolicExecutionAnalyzer(SQ_FOR_IDE)).isFalse(); + } + + @Test void rules_definition() { SonarRuntime sonarRuntime = SonarRuntimeImpl.forSonarQube(Version.create(10, 2), SonarQubeSide.SERVER, SonarEdition.ENTERPRISE); @@ -85,7 +126,7 @@ void rules_definition() { assertThat(repository.name()).isEqualTo("Sonar"); assertThat(repository.language()).isEqualTo("java"); List rules = repository.rules(); - assertThat(rules).hasSize(23); + assertThat(rules).hasSize(22); var activeByDefault = rules.stream() .filter(k -> !rulesNotActiveByDefault.contains(k.key())) @@ -117,7 +158,7 @@ private static String[] getRuleKeysWithRepo() { private static String[] getRuleKeys() { var ruleKeys = new ArrayList(); - for (Class check : JavaSECheckList.getChecks()) { + for (Class check : JavaSECheckList.getNonOverriddenChecks()) { ruleKeys.add(check.getAnnotation(Rule.class).key()); } return ruleKeys.toArray(new String[0]); diff --git a/java-symbolic-execution/java-symbolic-execution-plugin/src/test/java/org/sonar/java/se/plugin/JavaSEProfileRegistrarTest.java b/java-symbolic-execution/java-symbolic-execution-plugin/src/test/java/org/sonar/java/se/plugin/JavaSEProfileRegistrarTest.java index 4bcc00e54..8cdcbca1b 100644 --- a/java-symbolic-execution/java-symbolic-execution-plugin/src/test/java/org/sonar/java/se/plugin/JavaSEProfileRegistrarTest.java +++ b/java-symbolic-execution/java-symbolic-execution-plugin/src/test/java/org/sonar/java/se/plugin/JavaSEProfileRegistrarTest.java @@ -28,7 +28,6 @@ void constructor() { JavaSEProfileRegistrar registrar = new JavaSEProfileRegistrar(); TestProfileRegistrarContext context = new TestProfileRegistrarContext(); registrar.register(context); - assertThat(context.defaultQualityProfileRules).hasSize(21); // 2 are not in the default profile + assertThat(context.defaultQualityProfileRules).hasSize(20); // 3 are not in the default profile } - }