Skip to content

Commit

Permalink
feat(EC22): Implementing Avoid Method Usage for Only Basic Operations
Browse files Browse the repository at this point in the history
  • Loading branch information
moabidi91 committed Apr 6, 2023
1 parent a967a81 commit 8ae4967
Show file tree
Hide file tree
Showing 7 changed files with 248 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,25 +24,7 @@
import java.util.Collections;
import java.util.List;

import fr.greencodeinitiative.java.checks.ArrayCopyCheck;
import fr.greencodeinitiative.java.checks.AvoidConcatenateStringsInLoop;
import fr.greencodeinitiative.java.checks.AvoidFullSQLRequest;
import fr.greencodeinitiative.java.checks.AvoidGettingSizeCollectionInLoop;
import fr.greencodeinitiative.java.checks.AvoidMultipleIfElseStatement;
import fr.greencodeinitiative.java.checks.AvoidRegexPatternNotStatic;
import fr.greencodeinitiative.java.checks.AvoidSQLRequestInLoop;
import fr.greencodeinitiative.java.checks.AvoidSetConstantInBatchUpdate;
import fr.greencodeinitiative.java.checks.AvoidSpringRepositoryCallInLoopCheck;
import fr.greencodeinitiative.java.checks.AvoidStatementForDMLQueries;
import fr.greencodeinitiative.java.checks.AvoidUsageOfStaticCollections;
import fr.greencodeinitiative.java.checks.AvoidUsingGlobalVariablesCheck;
import fr.greencodeinitiative.java.checks.FreeResourcesOfAutoCloseableInterface;
import fr.greencodeinitiative.java.checks.IncrementCheck;
import fr.greencodeinitiative.java.checks.InitializeBufferWithAppropriateSize;
import fr.greencodeinitiative.java.checks.NoFunctionCallWhenDeclaringForLoop;
import fr.greencodeinitiative.java.checks.OptimizeReadFileExceptions;
import fr.greencodeinitiative.java.checks.UnnecessarilyAssignValuesToVariables;
import fr.greencodeinitiative.java.checks.UseCorrectForLoop;
import fr.greencodeinitiative.java.checks.*;
import org.sonar.plugins.java.api.JavaCheck;

public final class RulesList {
Expand Down Expand Up @@ -77,7 +59,8 @@ public static List<Class<? extends JavaCheck>> getJavaChecks() {
AvoidUsingGlobalVariablesCheck.class,
AvoidSetConstantInBatchUpdate.class,
FreeResourcesOfAutoCloseableInterface.class,
AvoidMultipleIfElseStatement.class
AvoidMultipleIfElseStatement.class,
AvoidMethodUsageForOnlyBasicOperations.class
));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package fr.greencodeinitiative.java.checks;

import org.sonar.check.Rule;
import org.sonar.plugins.java.api.IssuableSubscriptionVisitor;
import org.sonar.plugins.java.api.tree.*;

import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.function.Predicate;

import static fr.greencodeinitiative.java.checks.AvoidMethodUsageForOnlyBasicOperations.RULE_MESSAGE;
import static org.sonar.check.Priority.MINOR;

/**
* @author Mohamed Oussama A.
* Created on 05/04/2023
* @version 1.0
*/

@Rule(key = "EC22",
name = RULE_MESSAGE,
description = RULE_MESSAGE,
priority = MINOR,
tags = {"smell", "ecocode", "eco-design", "memory", "performance"})
public class AvoidMethodUsageForOnlyBasicOperations extends IssuableSubscriptionVisitor {

protected static final String RULE_MESSAGE = "Avoid Method Usage For Only Basic Operations";

@Override
public List<Tree.Kind> nodesToVisit() {
return Collections.singletonList(Tree.Kind.METHOD);
}


@Override
public void visitNode(Tree tree) {
Optional.ofNullable(((MethodTree) tree).block())
.map(BlockTree::body)
.filter(list -> list.size() == 1)
.flatMap(list -> list.stream().findFirst())
.filter(ReturnStatementTree.class::isInstance)
.map(statementTree -> ((ReturnStatementTree) statementTree).expression())
.filter(this.isBasicOperation)
.ifPresent(expressionTree -> reportIssue(expressionTree, RULE_MESSAGE));
}


private Predicate<ExpressionTree> isBasicOperation = expression -> expression instanceof BinaryExpressionTree
|| expression instanceof UnaryExpressionTree
|| expression.is(Tree.Kind.CONDITIONAL_EXPRESSION);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<p>we should not use methods for only basic operations</p>
<h2>Non compliant Code Example</h2>
<pre>
public int sum(int a, int b) {
return a + b; // Noncompliant
}

x = sum(5, 4); // Noncompliant
</pre>
<h2>Compliant Solution</h2>
<pre>
x = a + b;
</pre>
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"title": "we should not use methods for only basic operations",
"type": "CODE_SMELL",
"status": "ready",
"remediation": {
"func": "Constant\/Issue",
"constantCost": "5min"
},
"tags": [
"eco-design",
"memory",
"performance",
"ecocode"
],
"defaultSeverity": "Minor"
}
143 changes: 143 additions & 0 deletions java-plugin/src/test/files/AvoidMethodUsageForOnlyBasicOperations.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
/**
* @author Mohamed Oussama A.
* Created on 05/04/2023
* @version 1.0
*/
public class AvoidBasicOperationsUsageMethods {

private int x =0;

/*
* Below method must be reported by an other Rule of unnecessarily assignment of variable
* (but not with this rule - SRP - SOLID )
* */

public static int getMin(int a, int b) {
int c = a < b ? a : b; // Compliant
return c;
}

public int getX() {
return x; // Compliant
}

/*
* Conditional expressions using ternanry operator
*/
public static int getMin(int a, int b) {
return a < b ? a : b; // Noncompliant {{Avoid Method Usage For Only Basic Operations}}
}

public static int calculateFormuleX(int a, int b) {
return a / a * b < b ? a - b : b + a; // Noncompliant {{Avoid Method Usage For Only Basic Operations}}
}

/*
* Binary Operations
*/

//Using Arithmetic Operators

public static int add(int a, int b) {
return a + b; // Noncompliant {{Avoid Method Usage For Only Basic Operations}}
}

public static int substract(int a, int b) {
return a - b; // Noncompliant {{Avoid Method Usage For Only Basic Operations}}
}

public static int multiply(int a, int b) {
return a * b; // Noncompliant {{Avoid Method Usage For Only Basic Operations}}
}

public static int divide(int a, int b) {
return a / b; // Noncompliant {{Avoid Method Usage For Only Basic Operations}}
}

public static int modulus(int a, int b) {
return a % b; // Noncompliant {{Avoid Method Usage For Only Basic Operations}}
}

//Using Logical Operators

public static boolean compareAnd(int a, int b) {
return (a > b) && (b > 0); // Noncompliant {{Avoid Method Usage For Only Basic Operations}}
}

public static boolean compareOr(int a, int b) {
return (a > b) || (b > 0); // Noncompliant {{Avoid Method Usage For Only Basic Operations}}
}

public static boolean equalsTo(int a, int b) {
return a == b; // Noncompliant {{Avoid Method Usage For Only Basic Operations}}
}

public static boolean notEqualsTo(int a, int b) {
return !(a == b); // Noncompliant {{Avoid Method Usage For Only Basic Operations}}
}

public static boolean compare1(int a, int b) {
return (a > b) && (b > 0); // Noncompliant {{Avoid Method Usage For Only Basic Operations}}
}

// Using Bitwise operators

public static boolean andBitwise(int a, int b) {
return a & b; // Noncompliant {{Avoid Method Usage For Only Basic Operations}}
}

public static boolean orBitwise(int a, int b) {
return a | b; // Noncompliant {{Avoid Method Usage For Only Basic Operations}}
}

public static boolean xorBitwise(int a, int b) {
return a ^ b; // Noncompliant {{Avoid Method Usage For Only Basic Operations}}
}

/*
* Unary Operations
*/

public static int negate(int a) {
return -a; // Noncompliant {{Avoid Method Usage For Only Basic Operations}}
}

public static int preIncrement(int a) {
return ++a; // Noncompliant {{Avoid Method Usage For Only Basic Operations}}
}

public static int postDecrement(int a) {
return a--; // Noncompliant {{Avoid Method Usage For Only Basic Operations}}
}

public static int notBitwise(int a) {
return ~a; // Noncompliant {{Avoid Method Usage For Only Basic Operations}}
}

// Using Bitwise operators

public static int negate(int a) {
return -a; // Noncompliant {{Avoid Method Usage For Only Basic Operations}}
}

public static int preIncrement(int a) {
return ++a; // Noncompliant {{Avoid Method Usage For Only Basic Operations}}
}

public static int postDecrement(int a) {
return a--; // Noncompliant {{Avoid Method Usage For Only Basic Operations}}
}

public static int leftShift(int a) {
return a << 1; // Noncompliant {{Avoid Method Usage For Only Basic Operations}}
}

public static int rightShift(int a) {
return a >> 1; // Noncompliant {{Avoid Method Usage For Only Basic Operations}}
}

public static int zeroFillRightShift(int a) {
return a >>> 1; // Noncompliant {{Avoid Method Usage For Only Basic Operations}}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ void checkNumberRules() {
final JavaCheckRegistrar registrar = new JavaCheckRegistrar();
registrar.register(context);

assertThat(context.checkClasses()).hasSize(19);
assertThat(context.checkClasses()).hasSize(20);
assertThat(context.testCheckClasses()).isEmpty();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package fr.greencodeinitiative.java.checks;

import org.junit.jupiter.api.Test;
import org.sonar.java.checks.verifier.CheckVerifier;

/**
* @author Mohamed Oussama ABIDI.
* Created on 05/04/2023
* @version 1.0
*/
class AvoidMethodUsageForOnlyBasicOperationsTest {

@Test
void it_should_verify_non_compliant_basic_operations_usage_in_methods() {
CheckVerifier.newVerifier()
.onFile("src/test/files/AvoidMethodUsageForOnlyBasicOperations.java")
.withCheck(new AvoidMethodUsageForOnlyBasicOperations())
.verifyIssues();
}
}

0 comments on commit 8ae4967

Please sign in to comment.