diff --git a/CHANGELOG.md b/CHANGELOG.md index a5c8c92c..806858c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -116,6 +116,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Update ecocode-rules-specifications to 1.4.6 + +## [unreleased] + +### Changed + +- #183 GCI94 - reduce false positives by not flagging orElse with already-defined values (literals, constants, identifiers) + +## [2.1.2] - 2026-05-20 + [unreleased](https://github.com/green-code-initiative/creedengo-java/compare/2.1.2...HEAD) [2.1.2](https://github.com/green-code-initiative/creedengo-java/compare/2.1.1...2.1.2) [2.1.1](https://github.com/green-code-initiative/creedengo-java/compare/2.1.0...2.1.1) diff --git a/src/it/test-projects/creedengo-java-plugin-test-project/src/main/java/org/greencodeinitiative/creedengo/java/checks/GCI94/UseOptionalOrElseGetVsOrElse.java b/src/it/test-projects/creedengo-java-plugin-test-project/src/main/java/org/greencodeinitiative/creedengo/java/checks/GCI94/UseOptionalOrElseGetVsOrElse.java index 6a93a0be..595ea9b6 100644 --- a/src/it/test-projects/creedengo-java-plugin-test-project/src/main/java/org/greencodeinitiative/creedengo/java/checks/GCI94/UseOptionalOrElseGetVsOrElse.java +++ b/src/it/test-projects/creedengo-java-plugin-test-project/src/main/java/org/greencodeinitiative/creedengo/java/checks/GCI94/UseOptionalOrElseGetVsOrElse.java @@ -34,4 +34,54 @@ private static String getUnpredictedMethod() { return "unpredicted"; } + private static final String DEFAULT_VALUE = "default"; + + void badMethodCall(String value) { + Optional.ofNullable(value).orElse(getDefaultValue()); // Noncompliant + } + + void badNewObject(String value) { + Optional.ofNullable(value).orElse(new String("default")); // Noncompliant + } + + void goodBooleanConstant(Boolean value) { + Optional.ofNullable(value).orElse(Boolean.FALSE); + } + + void goodStringLiteral(String value) { + Optional.ofNullable(value).orElse("default"); + } + + void goodNull(String value) { + Optional.ofNullable(value).orElse(null); + } + + void goodIdentifier(String value) { + Optional.ofNullable(value).orElse(DEFAULT_VALUE); + } + + void goodAlreadyOrElseGet(String value) { + Optional.ofNullable(value).orElseGet(this::getDefaultValue); + } + + private String getDefaultValue() { + return "default"; + } + + void badConcatenation(String value, String suffix) { + Optional.ofNullable(value).orElse("default" + suffix); // Noncompliant + } + + void badTernary(String value, boolean condition) { + Optional.ofNullable(value).orElse(condition ? "default" : "fallback"); // Noncompliant + } + + void badCast(String value, Object defaultValue) { + Optional.ofNullable(value).orElse((String) defaultValue); // Noncompliant + } + + void badArrayAccess(String value, String[] values) { + Optional.ofNullable(value).orElse(values[0]); // Noncompliant + } + } diff --git a/src/main/java/org/greencodeinitiative/creedengo/java/checks/UseOptionalOrElseGetVsOrElse.java b/src/main/java/org/greencodeinitiative/creedengo/java/checks/UseOptionalOrElseGetVsOrElse.java index ec971a6c..5895c2d3 100644 --- a/src/main/java/org/greencodeinitiative/creedengo/java/checks/UseOptionalOrElseGetVsOrElse.java +++ b/src/main/java/org/greencodeinitiative/creedengo/java/checks/UseOptionalOrElseGetVsOrElse.java @@ -19,10 +19,8 @@ import org.sonar.check.Rule; import org.sonar.plugins.java.api.IssuableSubscriptionVisitor; -import org.sonar.plugins.java.api.tree.BaseTreeVisitor; -import org.sonar.plugins.java.api.tree.MemberSelectExpressionTree; -import org.sonar.plugins.java.api.tree.MethodInvocationTree; -import org.sonar.plugins.java.api.tree.Tree; +import org.sonar.plugins.java.api.tree.*; + import javax.annotation.Nonnull; import java.util.Collections; import java.util.List; @@ -51,9 +49,32 @@ public void visitMethodInvocation(MethodInvocationTree tree) { Objects.requireNonNull(tree.methodSelect().firstToken()).text().equals("Optional")) { MemberSelectExpressionTree memberSelect = (MemberSelectExpressionTree) tree.methodSelect(); if (memberSelect.identifier().name().equals("orElse")) { + if (tree.arguments().isEmpty()) { + return; + } + ExpressionTree argument = tree.arguments().get(0); + + if (isAlreadyDefinedValue(argument)) { + return; + } + reportIssue(memberSelect, MESSAGE_RULE); } } } + private boolean isAlreadyDefinedValue(ExpressionTree argument) { + return argument.is( + Tree.Kind.STRING_LITERAL, + Tree.Kind.INT_LITERAL, + Tree.Kind.LONG_LITERAL, + Tree.Kind.FLOAT_LITERAL, + Tree.Kind.DOUBLE_LITERAL, + Tree.Kind.CHAR_LITERAL, + Tree.Kind.BOOLEAN_LITERAL, + Tree.Kind.NULL_LITERAL, + Tree.Kind.IDENTIFIER, + Tree.Kind.MEMBER_SELECT + ); + } } }