From 281a13a3015e645a113c56053476ffca8fe596a7 Mon Sep 17 00:00:00 2001 From: nathsou Date: Tue, 25 Aug 2026 16:48:43 +0200 Subject: [PATCH 1/4] Implement S9366 --- ...ortedChronoUnitWithInstantCheckSample.java | 143 ++++++++++++++++++ ...UnsupportedChronoUnitWithInstantCheck.java | 102 +++++++++++++ ...pportedChronoUnitWithInstantCheckTest.java | 53 +++++++ .../org/sonar/l10n/java/rules/java/S9366.html | 85 +++++++++++ .../org/sonar/l10n/java/rules/java/S9366.json | 25 +++ .../main/resources/profiles/Sonar_way/S9366 | 0 6 files changed, 408 insertions(+) create mode 100644 java-checks-test-sources/default/src/main/java/checks/UnsupportedChronoUnitWithInstantCheckSample.java create mode 100644 java-checks/src/main/java/org/sonar/java/checks/UnsupportedChronoUnitWithInstantCheck.java create mode 100644 java-checks/src/test/java/org/sonar/java/checks/UnsupportedChronoUnitWithInstantCheckTest.java create mode 100644 sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9366.html create mode 100644 sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9366.json create mode 100644 sonar-java-plugin/src/main/resources/profiles/Sonar_way/S9366 diff --git a/java-checks-test-sources/default/src/main/java/checks/UnsupportedChronoUnitWithInstantCheckSample.java b/java-checks-test-sources/default/src/main/java/checks/UnsupportedChronoUnitWithInstantCheckSample.java new file mode 100644 index 00000000000..7690dd44930 --- /dev/null +++ b/java-checks-test-sources/default/src/main/java/checks/UnsupportedChronoUnitWithInstantCheckSample.java @@ -0,0 +1,143 @@ +package checks; + +import java.time.Duration; +import java.time.Instant; +import java.time.ZonedDateTime; +import java.time.temporal.ChronoUnit; +import java.time.temporal.Temporal; +import java.time.temporal.TemporalUnit; + +import static java.time.temporal.ChronoUnit.YEARS; +import static checks.UnsupportedChronoUnitWithInstantCheckSample.CustomUnit.MONTHS; + +class UnsupportedChronoUnitWithInstantCheckSample { + + private static final TemporalUnit STORED_UNIT = ChronoUnit.MONTHS; + + void unsupported(Instant instant, Instant end) { + instant.plus(1, ChronoUnit.WEEKS); // Noncompliant {{"WEEKS" is unsupported by Instant and causes an UnsupportedTemporalTypeException.}} +// ^^^^^^^^^^^^^^^^ + instant.plus(1, ChronoUnit.MONTHS); // Noncompliant {{"MONTHS" is unsupported by Instant and causes an UnsupportedTemporalTypeException.}} +// ^^^^^^^^^^^^^^^^^ + instant.plus(1, YEARS); // Noncompliant {{"YEARS" is unsupported by Instant and causes an UnsupportedTemporalTypeException.}} +// ^^^^^ + instant.plus(1, ChronoUnit.DECADES); // Noncompliant + instant.plus(1, ChronoUnit.CENTURIES); // Noncompliant + instant.plus(1, java.time.temporal.ChronoUnit.MILLENNIA); // Noncompliant + instant.plus(1, ChronoUnit.ERAS); // Noncompliant + instant.plus(1, ChronoUnit.FOREVER); // Noncompliant + + instant.minus(1, ChronoUnit.WEEKS); // Noncompliant + instant.minus(1, ChronoUnit.MONTHS); // Noncompliant + instant.minus(1, ChronoUnit.YEARS); // Noncompliant + instant.minus(1, ChronoUnit.DECADES); // Noncompliant + instant.minus(1, ChronoUnit.CENTURIES); // Noncompliant + instant.minus(1, ChronoUnit.MILLENNIA); // Noncompliant + instant.minus(1, ChronoUnit.ERAS); // Noncompliant + instant.minus(1, ChronoUnit.FOREVER); // Noncompliant + + instant.until(end, ChronoUnit.WEEKS); // Noncompliant + instant.until(end, (ChronoUnit.MONTHS)); // Noncompliant +// ^^^^^^^^^^^^^^^^^^^ + instant.until(end, ChronoUnit.YEARS); // Noncompliant + instant.until(end, ChronoUnit.DECADES); // Noncompliant + instant.until(end, ChronoUnit.CENTURIES); // Noncompliant + instant.until(end, ChronoUnit.MILLENNIA); // Noncompliant + instant.until(end, ChronoUnit.ERAS); // Noncompliant + instant.until(end, ChronoUnit.FOREVER); // Noncompliant + } + + void supported(Instant instant, Instant end) { + instant.plus(1, ChronoUnit.NANOS); + instant.plus(1, ChronoUnit.MICROS); + instant.plus(1, ChronoUnit.MILLIS); + instant.plus(1, ChronoUnit.SECONDS); + instant.plus(1, ChronoUnit.MINUTES); + instant.plus(1, ChronoUnit.HOURS); + instant.plus(1, ChronoUnit.HALF_DAYS); + instant.plus(1, ChronoUnit.DAYS); + + instant.minus(1, ChronoUnit.NANOS); + instant.minus(1, ChronoUnit.MICROS); + instant.minus(1, ChronoUnit.MILLIS); + instant.minus(1, ChronoUnit.SECONDS); + instant.minus(1, ChronoUnit.MINUTES); + instant.minus(1, ChronoUnit.HOURS); + instant.minus(1, ChronoUnit.HALF_DAYS); + instant.minus(1, ChronoUnit.DAYS); + + instant.until(end, ChronoUnit.NANOS); + instant.until(end, ChronoUnit.MICROS); + instant.until(end, ChronoUnit.MILLIS); + instant.until(end, ChronoUnit.SECONDS); + instant.until(end, ChronoUnit.MINUTES); + instant.until(end, ChronoUnit.HOURS); + instant.until(end, ChronoUnit.HALF_DAYS); + instant.until(end, ChronoUnit.DAYS); + } + + void excludedApis(Instant instant) { + instant.plus(Duration.ofDays(1)); + instant.minus(Duration.ofDays(1)); + instant.truncatedTo(ChronoUnit.WEEKS); + } + + void otherReceiver(ZonedDateTime dateTime, ZonedDateTime end) { + dateTime.plus(1, ChronoUnit.MONTHS); + dateTime.minus(1, ChronoUnit.YEARS); + dateTime.until(end, ChronoUnit.WEEKS); + } + + void indirectAndDynamic(Instant instant, Instant end, TemporalUnit unit, boolean condition) { + TemporalUnit localUnit = ChronoUnit.YEARS; + instant.plus(1, localUnit); + instant.minus(1, STORED_UNIT); + instant.until(end, unit); + instant.plus(1, condition ? ChronoUnit.MONTHS : ChronoUnit.DAYS); + } + + void customUnits(Instant instant, Instant end) { + instant.plus(1, CustomUnit.MONTHS); + instant.minus(1, MONTHS); + instant.until(end, CustomUnit.MONTHS); + } + + enum CustomUnit implements TemporalUnit { + MONTHS; + + @Override + public Duration getDuration() { + return Duration.ZERO; + } + + @Override + public boolean isDurationEstimated() { + return false; + } + + @Override + public boolean isDateBased() { + return false; + } + + @Override + public boolean isTimeBased() { + return true; + } + + @Override + public boolean isSupportedBy(Temporal temporal) { + return true; + } + + @Override + public R addTo(R temporal, long amount) { + return temporal; + } + + @Override + public long between(Temporal first, Temporal second) { + return 0; + } + } +} diff --git a/java-checks/src/main/java/org/sonar/java/checks/UnsupportedChronoUnitWithInstantCheck.java b/java-checks/src/main/java/org/sonar/java/checks/UnsupportedChronoUnitWithInstantCheck.java new file mode 100644 index 00000000000..4c9e2b3e320 --- /dev/null +++ b/java-checks/src/main/java/org/sonar/java/checks/UnsupportedChronoUnitWithInstantCheck.java @@ -0,0 +1,102 @@ +/* + * SonarQube Java + * Copyright (C) SonarSource Sàrl + * mailto:info AT sonarsource DOT com + * + * You can redistribute and/or modify this program under the terms of + * the Sonar Source-Available License Version 1, as published by SonarSource Sàrl. + * + * 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.Set; +import org.sonar.check.Rule; +import org.sonar.java.checks.methods.AbstractMethodDetection; +import org.sonar.java.model.ExpressionUtils; +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.tree.ExpressionTree; +import org.sonar.plugins.java.api.tree.IdentifierTree; +import org.sonar.plugins.java.api.tree.MemberSelectExpressionTree; +import org.sonar.plugins.java.api.tree.MethodInvocationTree; + +@Rule(key = "S9366") +public class UnsupportedChronoUnitWithInstantCheck extends AbstractMethodDetection implements JavaVersionAwareVisitor { + + private static final String INSTANT = "java.time.Instant"; + private static final String TEMPORAL = "java.time.temporal.Temporal"; + private static final String TEMPORAL_UNIT = "java.time.temporal.TemporalUnit"; + private static final String CHRONO_UNIT = "java.time.temporal.ChronoUnit"; + + private static final Set UNSUPPORTED_UNITS = Set.of( + "WEEKS", + "MONTHS", + "YEARS", + "DECADES", + "CENTURIES", + "MILLENNIA", + "ERAS", + "FOREVER" + ); + + private static final MethodMatchers MATCHERS = MethodMatchers.create() + .ofTypes(INSTANT) + .names("plus", "minus") + .addParametersMatcher("long", TEMPORAL_UNIT) + .build(); + + private static final MethodMatchers UNTIL_MATCHER = MethodMatchers.create() + .ofTypes(INSTANT) + .names("until") + .addParametersMatcher(TEMPORAL, TEMPORAL_UNIT) + .build(); + + @Override + public boolean isCompatibleWithJavaVersion(JavaVersion version) { + return version.isJava8Compatible(); + } + + @Override + protected MethodMatchers getMethodInvocationMatchers() { + return MethodMatchers.or(MATCHERS, UNTIL_MATCHER); + } + + @Override + protected void onMethodInvocationFound(MethodInvocationTree mit) { + if (context.getSemanticModel() == null || mit.arguments().size() < 2) { + return; + } + ExpressionTree argument = mit.arguments().get(1); + Symbol symbol = referencedSymbol(ExpressionUtils.skipParentheses(argument)); + if (isChronoUnitConstant(symbol) && UNSUPPORTED_UNITS.contains(symbol.name())) { + reportIssue(argument, String.format("\"%s\" is unsupported by Instant and causes an UnsupportedTemporalTypeException.", symbol.name())); + } + } + + private static Symbol referencedSymbol(ExpressionTree argument) { + if (argument instanceof IdentifierTree identifier) { + return identifier.symbol(); + } + if (argument instanceof MemberSelectExpressionTree memberSelect) { + return memberSelect.identifier().symbol(); + } + return null; + } + + private static boolean isChronoUnitConstant(Symbol symbol) { + if (symbol == null || symbol.isUnknown() || !symbol.isVariableSymbol() || !symbol.isEnum()) { + return false; + } + Symbol owner = symbol.owner(); + return owner != null && !owner.isUnknown() && owner.type().is(CHRONO_UNIT); + } +} diff --git a/java-checks/src/test/java/org/sonar/java/checks/UnsupportedChronoUnitWithInstantCheckTest.java b/java-checks/src/test/java/org/sonar/java/checks/UnsupportedChronoUnitWithInstantCheckTest.java new file mode 100644 index 00000000000..0e6cb268b1e --- /dev/null +++ b/java-checks/src/test/java/org/sonar/java/checks/UnsupportedChronoUnitWithInstantCheckTest.java @@ -0,0 +1,53 @@ +/* + * SonarQube Java + * Copyright (C) SonarSource Sàrl + * mailto:info AT sonarsource DOT com + * + * You can redistribute and/or modify this program under the terms of + * the Sonar Source-Available License Version 1, as published by SonarSource Sàrl. + * + * 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.Test; +import org.sonar.java.checks.verifier.CheckVerifier; + +import static org.sonar.java.checks.verifier.TestUtils.mainCodeSourcesPath; + +class UnsupportedChronoUnitWithInstantCheckTest { + + private static final String SAMPLE = "checks/UnsupportedChronoUnitWithInstantCheckSample.java"; + + @Test + void test() { + CheckVerifier.newVerifier() + .onFile(mainCodeSourcesPath(SAMPLE)) + .withCheck(new UnsupportedChronoUnitWithInstantCheck()) + .verifyIssues(); + } + + @Test + void test_without_semantic() { + CheckVerifier.newVerifier() + .onFile(mainCodeSourcesPath(SAMPLE)) + .withCheck(new UnsupportedChronoUnitWithInstantCheck()) + .withoutSemantic() + .verifyNoIssues(); + } + + @Test + void no_issue_before_java_8() { + CheckVerifier.newVerifier() + .onFile(mainCodeSourcesPath(SAMPLE)) + .withCheck(new UnsupportedChronoUnitWithInstantCheck()) + .withJavaVersion(7) + .verifyNoIssues(); + } +} diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9366.html b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9366.html new file mode 100644 index 00000000000..ccb89abb221 --- /dev/null +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9366.html @@ -0,0 +1,85 @@ +

Instant supports only time-based ChronoUnit values and ChronoUnit.DAYS. Passing another +ChronoUnit value to its arithmetic methods causes an UnsupportedTemporalTypeException when the unit is evaluated.

+

Why is this an issue?

+

An Instant represents a point on the timeline as a number of seconds and nanoseconds from the epoch. It does not define how date-based +ChronoUnit values such as MONTHS or YEARS apply to its timeline. Custom TemporalUnit +implementations may define their own behavior.

+

The plus(long, TemporalUnit), minus(long, TemporalUnit), and until(Temporal, TemporalUnit) methods support +the following ChronoUnit values:

+
    +
  • NANOS
  • +
  • MICROS
  • +
  • MILLIS
  • +
  • SECONDS
  • +
  • MINUTES
  • +
  • HOURS
  • +
  • HALF_DAYS
  • +
  • DAYS
  • +
+

Using WEEKS, MONTHS, YEARS, DECADES, CENTURIES, MILLENNIA, +ERAS, or FOREVER with these methods throws an UnsupportedTemporalTypeException when the unit is evaluated. The +operation cannot produce a result, which can interrupt date and time processing in the application.

+

Exceptions

+

This rule reports only direct ChronoUnit constants. It does not track a constant stored in a variable.

+

Custom TemporalUnit implementations are not reported because Instant delegates the operation to them. The +plus(TemporalAmount) and minus(TemporalAmount) overloads and the truncatedTo(TemporalUnit) method are also +outside the scope of this rule.

+

How to fix it

+

Use a supported ChronoUnit for a fixed amount of elapsed time. When an operation must follow calendar rules, convert the +Instant to a calendar type such as ZonedDateTime using the intended ZoneId. A custom TemporalUnit +is also valid when its implementation explicitly defines the required timeline behavior.

+

Code examples

+

Noncompliant code example

+
+import static java.time.temporal.ChronoUnit.YEARS;
+
+void update(Instant instant, Instant end) {
+  instant.plus(
+    1,
+    ChronoUnit.MONTHS); // Noncompliant: "MONTHS" is unsupported by Instant and causes an UnsupportedTemporalTypeException.
+
+  instant.minus(
+    1,
+    YEARS); // Noncompliant: "YEARS" is unsupported by Instant and causes an UnsupportedTemporalTypeException.
+
+  instant.until(
+    end,
+    ChronoUnit.WEEKS); // Noncompliant: "WEEKS" is unsupported by Instant and causes an UnsupportedTemporalTypeException.
+}
+
+

Compliant solution

+
+import static java.time.temporal.ChronoUnit.YEARS;
+
+void update(Instant instant, Instant end, ZoneId zone, TemporalUnit customUnit) {
+  // Use supported units for elapsed-time operations.
+  instant.plus(1, ChronoUnit.DAYS);
+  instant.minus(12, ChronoUnit.HOURS);
+  instant.until(end, ChronoUnit.MINUTES);
+
+  // Use a calendar type and an explicit time zone for calendar arithmetic.
+  ZonedDateTime dateTime = instant.atZone(zone);
+  ZonedDateTime endDateTime = end.atZone(zone);
+  dateTime.plus(1, ChronoUnit.MONTHS);
+  dateTime.minus(1, YEARS);
+  dateTime.until(endDateTime, ChronoUnit.WEEKS);
+
+  // Support for custom units is defined by their implementation.
+  instant.plus(1, customUnit);
+  instant.minus(1, customUnit);
+  instant.until(end, customUnit);
+}
+
+

Resources

+

Documentation

+ + diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9366.json b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9366.json new file mode 100644 index 00000000000..8ac5e4464aa --- /dev/null +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9366.json @@ -0,0 +1,25 @@ +{ + "title": "Unsupported \"ChronoUnit\" values should not be used with \"Instant\"", + "type": "BUG", + "status": "ready", + "remediation": { + "func": "Constant\/Issue", + "constantCost": "5min" + }, + "tags": [ + "java8", + "datetime", + "pitfall" + ], + "defaultSeverity": "Major", + "ruleSpecification": "RSPEC-9366", + "sqKey": "S9366", + "scope": "All", + "quickfix": "infeasible", + "code": { + "impacts": { + "RELIABILITY": "MEDIUM" + }, + "attribute": "LOGICAL" + } +} diff --git a/sonar-java-plugin/src/main/resources/profiles/Sonar_way/S9366 b/sonar-java-plugin/src/main/resources/profiles/Sonar_way/S9366 new file mode 100644 index 00000000000..e69de29bb2d From fb7b90ee9bfd39a3e471033e638fb2540d45b341 Mon Sep 17 00:00:00 2001 From: nathsou Date: Tue, 25 Aug 2026 16:59:10 +0200 Subject: [PATCH 2/4] fix-ci: declare nullable symbol contract --- .../java/checks/UnsupportedChronoUnitWithInstantCheck.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/java-checks/src/main/java/org/sonar/java/checks/UnsupportedChronoUnitWithInstantCheck.java b/java-checks/src/main/java/org/sonar/java/checks/UnsupportedChronoUnitWithInstantCheck.java index 4c9e2b3e320..b5b595fadc2 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/UnsupportedChronoUnitWithInstantCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/UnsupportedChronoUnitWithInstantCheck.java @@ -17,6 +17,7 @@ package org.sonar.java.checks; import java.util.Set; +import javax.annotation.Nullable; import org.sonar.check.Rule; import org.sonar.java.checks.methods.AbstractMethodDetection; import org.sonar.java.model.ExpressionUtils; @@ -82,7 +83,7 @@ protected void onMethodInvocationFound(MethodInvocationTree mit) { } } - private static Symbol referencedSymbol(ExpressionTree argument) { + private static @Nullable Symbol referencedSymbol(ExpressionTree argument) { if (argument instanceof IdentifierTree identifier) { return identifier.symbol(); } @@ -92,7 +93,7 @@ private static Symbol referencedSymbol(ExpressionTree argument) { return null; } - private static boolean isChronoUnitConstant(Symbol symbol) { + private static boolean isChronoUnitConstant(@Nullable Symbol symbol) { if (symbol == null || symbol.isUnknown() || !symbol.isVariableSymbol() || !symbol.isEnum()) { return false; } From 68339dafc879fdc586aba3d70a48b1f099c87cd7 Mon Sep 17 00:00:00 2001 From: nathsou Date: Wed, 26 Aug 2026 10:40:04 +0200 Subject: [PATCH 3/4] SONARJAVA-6304 Migrate rule to S8218 --- .../java/checks/UnsupportedChronoUnitWithInstantCheck.java | 2 +- .../sonar/l10n/java/rules/java/{S9366.html => S8218.html} | 0 .../sonar/l10n/java/rules/java/{S9366.json => S8218.json} | 6 +++--- .../src/main/resources/profiles/Sonar_way/{S9366 => S8218} | 0 4 files changed, 4 insertions(+), 4 deletions(-) rename sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/{S9366.html => S8218.html} (100%) rename sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/{S9366.json => S8218.json} (71%) rename sonar-java-plugin/src/main/resources/profiles/Sonar_way/{S9366 => S8218} (100%) diff --git a/java-checks/src/main/java/org/sonar/java/checks/UnsupportedChronoUnitWithInstantCheck.java b/java-checks/src/main/java/org/sonar/java/checks/UnsupportedChronoUnitWithInstantCheck.java index b5b595fadc2..628e71a0a20 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/UnsupportedChronoUnitWithInstantCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/UnsupportedChronoUnitWithInstantCheck.java @@ -30,7 +30,7 @@ import org.sonar.plugins.java.api.tree.MemberSelectExpressionTree; import org.sonar.plugins.java.api.tree.MethodInvocationTree; -@Rule(key = "S9366") +@Rule(key = "S8218") public class UnsupportedChronoUnitWithInstantCheck extends AbstractMethodDetection implements JavaVersionAwareVisitor { private static final String INSTANT = "java.time.Instant"; diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9366.html b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S8218.html similarity index 100% rename from sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9366.html rename to sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S8218.html diff --git a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9366.json b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S8218.json similarity index 71% rename from sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9366.json rename to sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S8218.json index 8ac5e4464aa..aa04cabd2bf 100644 --- a/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S9366.json +++ b/sonar-java-plugin/src/main/resources/org/sonar/l10n/java/rules/java/S8218.json @@ -1,5 +1,5 @@ { - "title": "Unsupported \"ChronoUnit\" values should not be used with \"Instant\"", + "title": "Instant APIs should only use supported temporal units", "type": "BUG", "status": "ready", "remediation": { @@ -12,8 +12,8 @@ "pitfall" ], "defaultSeverity": "Major", - "ruleSpecification": "RSPEC-9366", - "sqKey": "S9366", + "ruleSpecification": "RSPEC-8218", + "sqKey": "S8218", "scope": "All", "quickfix": "infeasible", "code": { diff --git a/sonar-java-plugin/src/main/resources/profiles/Sonar_way/S9366 b/sonar-java-plugin/src/main/resources/profiles/Sonar_way/S8218 similarity index 100% rename from sonar-java-plugin/src/main/resources/profiles/Sonar_way/S9366 rename to sonar-java-plugin/src/main/resources/profiles/Sonar_way/S8218 From 4c9d12370ca6d84d4b5bd0a11a5c60008ffa6cd1 Mon Sep 17 00:00:00 2001 From: nathsou Date: Wed, 26 Aug 2026 14:17:00 +0200 Subject: [PATCH 4/4] Remove redundant argument count guard --- .../java/checks/UnsupportedChronoUnitWithInstantCheck.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java-checks/src/main/java/org/sonar/java/checks/UnsupportedChronoUnitWithInstantCheck.java b/java-checks/src/main/java/org/sonar/java/checks/UnsupportedChronoUnitWithInstantCheck.java index 628e71a0a20..b54f7a7edaf 100644 --- a/java-checks/src/main/java/org/sonar/java/checks/UnsupportedChronoUnitWithInstantCheck.java +++ b/java-checks/src/main/java/org/sonar/java/checks/UnsupportedChronoUnitWithInstantCheck.java @@ -73,7 +73,7 @@ protected MethodMatchers getMethodInvocationMatchers() { @Override protected void onMethodInvocationFound(MethodInvocationTree mit) { - if (context.getSemanticModel() == null || mit.arguments().size() < 2) { + if (context.getSemanticModel() == null) { return; } ExpressionTree argument = mit.arguments().get(1);