From 00dc29112006d81c825141e869d0bbe5a219ae33 Mon Sep 17 00:00:00 2001 From: Loup-K Date: Mon, 27 Apr 2026 14:59:46 +0200 Subject: [PATCH 1/4] Add rule GCI22: Avoid use of methods for basic operations --- .../python/integration/tests/GCIRulesIT.java | 13 ++ .../avoidUseOfMethodForBasicOperations.py | 160 ++++++++++++++ .../python/PythonRuleRepository.java | 1 + .../AvoidUseOfMethodForBasicOperations.java | 202 ++++++++++++++++++ .../python/creedengo_way_profile.json | 1 + ...voidUseOfMethodForBasicOperationsTest.java | 28 +++ 6 files changed, 405 insertions(+) create mode 100644 src/it/test-projects/creedengo-python-plugin-test-project/src/GCI22/avoidUseOfMethodForBasicOperations.py create mode 100644 src/main/java/org/greencodeinitiative/creedengo/python/checks/AvoidUseOfMethodForBasicOperations.java create mode 100644 src/test/java/org/greencodeinitiative/creedengo/python/checks/AvoidUseOfMethodForBasicOperationsTest.java diff --git a/src/it/java/org/greencodeinitiative/creedengo/python/integration/tests/GCIRulesIT.java b/src/it/java/org/greencodeinitiative/creedengo/python/integration/tests/GCIRulesIT.java index 1f8167e8..6b228f9e 100644 --- a/src/it/java/org/greencodeinitiative/creedengo/python/integration/tests/GCIRulesIT.java +++ b/src/it/java/org/greencodeinitiative/creedengo/python/integration/tests/GCIRulesIT.java @@ -559,4 +559,17 @@ void testGCI404() { checkIssuesForFile(filePath, ruleId, ruleMsg, startLines, endLines, SEVERITY, TYPE, EFFORT_15MIN); } + @Test + void testGCI22() { + String filePath = "src/avoidUseOfMethodForBasicOperations.py"; + String ruleId = "creedengo-python:GCI22"; + String ruleMsg = "Avoid using methods for simple basic operations."; + int[] startLines = new int[]{9, 10, 11, 12, 13, 14, 17, 18, 19, 20, 21, 22, 26, 30, 35, 36, 41, 42, 44, 45, 46, 47, 48, 51, 52, 57, 58, 59, 65, 70, 73, 76, 79, 82, 85 + }; + int[] endLines = new int[]{9, 10, 11, 12, 13, 14, 17, 18, 19, 20, 21, 22, 26, 30, 35, 36, 41, 42, 44, 45, 46, 47, 48, 51, 52, 57, 58, 59, 65, 70, 73, 76, 79, 82, 85 + }; + + checkIssuesForFile(filePath, ruleId, ruleMsg, startLines, endLines, SEVERITY, TYPE, EFFORT_5MIN); + } + } diff --git a/src/it/test-projects/creedengo-python-plugin-test-project/src/GCI22/avoidUseOfMethodForBasicOperations.py b/src/it/test-projects/creedengo-python-plugin-test-project/src/GCI22/avoidUseOfMethodForBasicOperations.py new file mode 100644 index 00000000..14b36015 --- /dev/null +++ b/src/it/test-projects/creedengo-python-plugin-test-project/src/GCI22/avoidUseOfMethodForBasicOperations.py @@ -0,0 +1,160 @@ +a = 10 +b = 3 +x = 5 +y = 8 +n1 = 0b1010 +n2 = 0b1100 + +#Arithmetic operations: +result_add = a.__add__(b) # Noncompliant {{Avoid using methods for simple basic operations.}} +result_sub = a.__sub__(b) # Noncompliant {{Avoid using methods for simple basic operations.}} +result_mul = a.__mul__(b) # Noncompliant {{Avoid using methods for simple basic operations.}} +result_div = a.__truediv__(b) # Noncompliant {{Avoid using methods for simple basic operations.}} +result_mod = a.__mod__(b) # Noncompliant {{Avoid using methods for simple basic operations.}} +result_pow = a.__pow__(b) # Noncompliant {{Avoid using methods for simple basic operations.}} + +#Comparisons: +is_equal = x.__eq__(y) # Noncompliant {{Avoid using methods for simple basic operations.}} +is_greater = x.__gt__(y) # Noncompliant {{Avoid using methods for simple basic operations.}} +is_less = x.__lt__(y) # Noncompliant {{Avoid using methods for simple basic operations.}} +is_gte = x.__ge__(y) # Noncompliant {{Avoid using methods for simple basic operations.}} +is_lte = x.__le__(y) # Noncompliant {{Avoid using methods for simple basic operations.}} +is_not_eq = x.__ne__(y) # Noncompliant {{Avoid using methods for simple basic operations.}} + +#Collection size: +my_list = [1, 2, 3, 4, 5] +size = my_list.__len__() # Noncompliant {{Avoid using methods for simple basic operations.}} + +#Found element: +words = ["This", "is", "a", "test"] +found = list.__contains__(words, "test") # Noncompliant {{Avoid using methods for simple basic operations.}} + +#String concatenation: +first = "Hello" +last = "World" +greeting = first.__add__(", " + last) # Noncompliant {{Avoid using methods for simple basic operations.}} +greeting = "".join([first, ", ", last]) # Noncompliant {{Avoid using methods for simple basic operations.}} + +#Operations: +flag_a = True +flag_b = False +result_and = flag_a.__and__(flag_b) # Noncompliant {{Avoid using methods for simple basic operations.}} +result_or = flag_a.__or__(flag_b) # Noncompliant {{Avoid using methods for simple basic operations.}} + +bit_and = n1.__and__(n2) # Noncompliant {{Avoid using methods for simple basic operations.}} +bit_or = n1.__or__(n2) # Noncompliant {{Avoid using methods for simple basic operations.}} +bit_xor = n1.__xor__(n2) # Noncompliant {{Avoid using methods for simple basic operations.}} +bit_lshift = n1.__lshift__(2) # Noncompliant {{Avoid using methods for simple basic operations.}} +bit_rshift = n1.__rshift__(2) # Noncompliant {{Avoid using methods for simple basic operations.}} + +#Sequence repetition: +repeated_str = "abc".__mul__(3) # Noncompliant {{Avoid using methods for simple basic operations.}} +repeated_list = [0].__mul__(5) # Noncompliant {{Avoid using methods for simple basic operations.}} + +#Access / modification / deletion of elements: +data = {"key": 42} +my_list2 = [10, 20, 30] +val = data.__getitem__("key") # Noncompliant {{Avoid using methods for simple basic operations.}} +my_list2.__setitem__(1, 99) # Noncompliant {{Avoid using methods for simple basic operations.}} +my_list2.__delitem__(0) # Noncompliant {{Avoid using methods for simple basic operations.}} + +#Accumulation in a loop: +numbers = range(10) +squares = [] +for n in numbers: + squares.append(n ** 2) # Noncompliant {{Avoid using methods for simple basic operations.}} + +#Trivial user-defined functions wrapping a basic operation: + +def add(a, b): + return a + b # Noncompliant {{Avoid using methods for simple basic operations.}} + +def multiply(a, b): + return a * b # Noncompliant {{Avoid using methods for simple basic operations.}} + +def is_eq(a, b): + return a == b # Noncompliant {{Avoid using methods for simple basic operations.}} + +def is_gt(a, b): + return a > b # Noncompliant {{Avoid using methods for simple basic operations.}} + +def contains(collection, item): + return item in collection # Noncompliant {{Avoid using methods for simple basic operations.}} + +def concat(a, b): + return a + b # Noncompliant {{Avoid using methods for simple basic operations.}} + + +# =========================================================================== + +a = 10 +b = 3 +x = 5 +y = 8 +n1 = 0b1010 +n2 = 0b1100 + +result_add = a + b # Compliant {{Native operator.}} +result_sub = a - b # Compliant {{Native operator.}} +result_mul = a * b # Compliant {{Native operator.}} +result_div = a / b # Compliant {{Native operator.}} +result_mod = a % b # Compliant {{Native operator.}} +result_pow = a ** b # Compliant {{Native operator.}} + +is_equal = x == y # Compliant {{Native operator.}} +is_greater = x > y # Compliant {{Native operator.}} +is_less = x < y # Compliant {{Native operator.}} +is_gte = x >= y # Compliant {{Native operator.}} +is_lte = x <= y # Compliant {{Native operator.}} +is_not_eq = x != y # Compliant {{Native operator.}} + +my_list = [1, 2, 3, 4, 5] +size = len(my_list) # Compliant {{use of len().}} + +words = ["This", "is", "a", "test"] +found = "test" in words # Compliant {{Native operator.}} + +first = "Hello" +last = "World" +greeting = first + ", " + last # Compliant {{Native operator.}} +greeting = f"{first}, {last}" # Compliant {{use of f-string.}} + +words = ["word"] * 1000 +sentence = " ".join(words) # Compliant {{use of join().}} + +flag_a = True +flag_b = False +result_and = flag_a and flag_b # Compliant {{Native operator.}} +result_or = flag_a or flag_b # Compliant {{Native operator.}} + +bit_and = n1 & n2 # Compliant {{Native operator.}} +bit_or = n1 | n2 # Compliant {{Native operator.}} +bit_xor = n1 ^ n2 # Compliant {{Native operator.}} +bit_lshift = n1 << 2 # Compliant {{Native operator.}} +bit_rshift = n1 >> 2 # Compliant {{Native operator.}} + +repeated_str = "abc" * 3 # Compliant {{Native operator.}} +repeated_list = [0] * 5 # Compliant {{Native operator.}} + +data = {"key": 42} +my_list2 = [10, 20, 30] +val = data["key"] # Compliant {{Native subscript syntax.}} +my_list2[1] = 99 # Compliant {{Native subscript syntax.}} +del my_list2[0] # Compliant {{Native operator.}} + +numbers = range(10) +squares = [n ** 2 for n in numbers] # Compliant {{Native syntax.}} + +values = [3, 1, 7, 2] +total = sum(values) # Compliant {Use of sum().}} +minimum = min(values) # Compliant {{Use of min().}} +maximum = max(values) # Compliant {{Use of max().}} +flags = [True, False, True] +check = all(flags) # Compliant {{Use of all().}} +check = any(flags) # Compliant {{Use of any().}} + +def is_adult(age): + return age >= 18 # Compliant {{Not a trivial operator wrapper.}} + +def tax_rate_applies(amount): + return amount > 1000 # Compliant {{Not a trivial operator wrapper.}} \ No newline at end of file diff --git a/src/main/java/org/greencodeinitiative/creedengo/python/PythonRuleRepository.java b/src/main/java/org/greencodeinitiative/creedengo/python/PythonRuleRepository.java index a0bb6d86..de2f86bb 100644 --- a/src/main/java/org/greencodeinitiative/creedengo/python/PythonRuleRepository.java +++ b/src/main/java/org/greencodeinitiative/creedengo/python/PythonRuleRepository.java @@ -57,6 +57,7 @@ public record PythonRuleRepository(SonarRuntime sonarRuntime) implements RulesDe GCI110AvoidWildcardImportsCheck.class, GCI109AvoidExceptionsForControlFlowCheck.class, GCI112UsingSlotsOnDataClasses.class + AvoidUseOfMethodForBasicOperations.class ); public static final String LANGUAGE = "py"; diff --git a/src/main/java/org/greencodeinitiative/creedengo/python/checks/AvoidUseOfMethodForBasicOperations.java b/src/main/java/org/greencodeinitiative/creedengo/python/checks/AvoidUseOfMethodForBasicOperations.java new file mode 100644 index 00000000..a4584c3e --- /dev/null +++ b/src/main/java/org/greencodeinitiative/creedengo/python/checks/AvoidUseOfMethodForBasicOperations.java @@ -0,0 +1,202 @@ +/* + * creedengo - Python language - Provides rules to reduce the environmental footprint of your Python programs + * Copyright © 2024 Green Code Initiative (https://green-code-initiative.org) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * 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 + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.greencodeinitiative.creedengo.python.checks; + +import org.sonar.check.Rule; +import org.sonar.plugins.python.api.PythonSubscriptionCheck; +import org.sonar.plugins.python.api.SubscriptionContext; +import org.sonar.plugins.python.api.tree.*; +import org.sonar.plugins.python.api.tree.Expression; + +import java.util.List; +import java.util.Set; + +import org.sonar.plugins.python.api.tree.BinaryExpression; + +@Rule(key = "GCI22") +public class AvoidUseOfMethodForBasicOperations extends PythonSubscriptionCheck { + + static final String MESSAGE = + "Avoid using methods for simple basic operations."; + + /** + * Dunder methods that have a direct native-operator equivalent in Python. + */ + private static final Set DUNDER_METHODS = Set.of( + //arithmetic + "__add__", "__sub__", "__mul__", "__truediv__", "__floordiv__", + "__mod__", "__pow__", "__matmul__", + //reflected arithmetic + "__radd__", "__rsub__", "__rmul__", "__rtruediv__", "__rfloordiv__", + "__rmod__", "__rpow__", + //in-place arithmetic + "__iadd__", "__isub__", "__imul__", "__itruediv__", "__ifloordiv__", + "__imod__", "__ipow__", + //comparisons + "__eq__", "__ne__", "__lt__", "__le__", "__gt__", "__ge__", + //logical + "__and__", "__or__", "__xor__", "__lshift__", "__rshift__", + "__iand__", "__ior__", "__ixor__", "__ilshift__", "__irshift__", + "__invert__", "__neg__", "__pos__", + //container / subscript + "__len__", "__contains__", "__getitem__", "__setitem__", "__delitem__", + //string / sequence + "__bool__", "__int__", "__float__", "__str__" + ); + + /** + * Generic trivial function names that are likely pure operator wrappers. + * We only flag functions whose *name* is in this set AND whose body is + * a single basic expression (or assign + return of a basic expression). + * + * Business-meaningful names (is_adult, tax_rate_applies…) are intentionally + * NOT in this set. + */ + private static final Set TRIVIAL_FUNCTION_NAMES = Set.of( + "add", "sub", "subtract", "mul", "multiply", "div", "divide", + "mod", "pow", "neg", "negate", + "eq", "ne", "lt", "le", "gt", "ge", + "is_eq", "is_gt", "is_lt", "is_gte", "is_lte", "is_ne", + "compare", "cmp", + "contains", "concat", "join_two", + "add_op", "add_one", "increment", "decrement", + "identity", "wrapper", "bool_wrapper" + ); + + @Override + public void initialize(Context context) { + // Detect explicit dunder calls and bad join() at every expression level + context.registerSyntaxNodeConsumer(Tree.Kind.CALL_EXPR, this::visitCallExpr); + // Detect append() inside a for-loop + context.registerSyntaxNodeConsumer(Tree.Kind.FOR_STMT, this::visitForLoop); + // Detect trivial wrapper functions + context.registerSyntaxNodeConsumer(Tree.Kind.FUNCDEF, this::visitFunctionDef); + } + + private void visitCallExpr(SubscriptionContext ctx) { + CallExpression call = (CallExpression) ctx.syntaxNode(); + + Expression callee = call.callee(); + + // Pattern: obj.__dunder__(args) => callee is a QualifiedExpression + if (callee instanceof QualifiedExpression qualifiedExpr) { + String methodName = qualifiedExpr.name().name(); + + if (DUNDER_METHODS.contains(methodName)) { + ctx.addIssue(call, MESSAGE); + return; + } + + if ("join".equals(methodName) + && qualifiedExpr.qualifier() instanceof StringLiteral + && hasListLiteralArgument(call)) { + ctx.addIssue(call, MESSAGE); + } + } + } + + /** + * Returns true if the call has exactly one argument and that argument is + * an inline list literal (e.g. [a, ", ", b]). + */ + private boolean hasListLiteralArgument(CallExpression call) { + if (call.argumentList() == null) return false; + List args = call.argumentList().arguments(); + if (args.size() != 1) return false; + Argument arg = args.get(0); + return arg instanceof RegularArgument regArg + && regArg.expression() instanceof ListLiteral; + } + + private void visitForLoop(SubscriptionContext ctx) { + ForStatement forStmt = (ForStatement) ctx.syntaxNode(); + for (Statement stmt : forStmt.body().statements()) { + findAppendCalls(ctx, stmt); + } + } + + private void findAppendCalls(SubscriptionContext ctx, Statement stmt) { + // We look for ExpressionStatement wrapping a CallExpression to .append() + if (!(stmt instanceof ExpressionStatement exprStmt)) return; + if (!(exprStmt.expressions().get(0) instanceof CallExpression call)) return; + if (!(call.callee() instanceof QualifiedExpression qe)) return; + if ("append".equals(qe.name().name())) { + ctx.addIssue(call, MESSAGE); + } + } + + private void visitFunctionDef(SubscriptionContext ctx) { + FunctionDef funcDef = (FunctionDef) ctx.syntaxNode(); + String name = funcDef.name().name(); + + if (!TRIVIAL_FUNCTION_NAMES.contains(name)) { + return; // business function or unknown name => not concern + } + + List stmts = funcDef.body().statements(); + + if (stmts.size() == 1) { + checkPatternA(ctx, stmts.get(0)); + } else if (stmts.size() == 2) { + checkPatternB(ctx, stmts.get(0), stmts.get(1)); + } + } + + /** + * Pattern A: return + * Flags the ReturnStatement if the returned expression is basic. + */ + private void checkPatternA(SubscriptionContext ctx, Statement stmt) { + if (!(stmt instanceof ReturnStatement returnStmt)) return; + List exprs = returnStmt.expressions(); + if (exprs.size() == 1 && isBasicExpression(exprs.get(0))) { + ctx.addIssue(returnStmt, MESSAGE); + } + } + + /** + * Pattern B: var = followed by return var + * Flags the ReturnStatement when the assignment feeds straight into the return. + */ + private void checkPatternB(SubscriptionContext ctx, Statement first, Statement second) { + if (!(first instanceof AssignmentStatement assignStmt)) return; + if (!(second instanceof ReturnStatement returnStmt)) return; + + // The return must reference the variable that was just assigned + List returnExprs = returnStmt.expressions(); + if (returnExprs.size() != 1) return; + if (!(returnExprs.get(0) instanceof Name returnedName)) return; + + ExpressionList lhsExprs = assignStmt.lhsExpressions().get(0); + if (lhsExprs.expressions().size() != 1) return; + if (!(lhsExprs.expressions().get(0) instanceof Name assignedName)) return; + + if (!assignedName.name().equals(returnedName.name())) return; + + if (isBasicExpression(assignStmt.assignedValue())) { + ctx.addIssue(returnStmt, MESSAGE); + } + } + + private boolean isBasicExpression(Tree expr) { + return expr instanceof BinaryExpression + || expr instanceof UnaryExpression + || expr instanceof Name; + } + +} diff --git a/src/main/resources/org/greencodeinitiative/creedengo/python/creedengo_way_profile.json b/src/main/resources/org/greencodeinitiative/creedengo/python/creedengo_way_profile.json index 6a107ce8..23a203d0 100644 --- a/src/main/resources/org/greencodeinitiative/creedengo/python/creedengo_way_profile.json +++ b/src/main/resources/org/greencodeinitiative/creedengo/python/creedengo_way_profile.json @@ -6,6 +6,7 @@ "GCI4", "GCI7", "GCI10", + "GCI22", "GCI24", "GCI35", "GCI72", diff --git a/src/test/java/org/greencodeinitiative/creedengo/python/checks/AvoidUseOfMethodForBasicOperationsTest.java b/src/test/java/org/greencodeinitiative/creedengo/python/checks/AvoidUseOfMethodForBasicOperationsTest.java new file mode 100644 index 00000000..05f8808f --- /dev/null +++ b/src/test/java/org/greencodeinitiative/creedengo/python/checks/AvoidUseOfMethodForBasicOperationsTest.java @@ -0,0 +1,28 @@ +/* + * creedengo - Python language - Provides rules to reduce the environmental footprint of your Python programs + * Copyright © 2024 Green Code Initiative (https://green-code-initiative.org) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * 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 + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.greencodeinitiative.creedengo.python.checks; + +import org.junit.jupiter.api.Test; +import org.sonar.python.checks.utils.PythonCheckVerifier; + +public class AvoidUseOfMethodForBasicOperationsTest { + @Test + public void test() { + PythonCheckVerifier.verify("src/test/resources/checks/avoidUseOfMethodForBasicOperations.py", new AvoidUseOfMethodForBasicOperations()); + } +} From d584513d49f15eb9f7632473388c16337cfbaa05 Mon Sep 17 00:00:00 2001 From: Loup-K Date: Fri, 22 May 2026 09:35:20 +0200 Subject: [PATCH 2/4] modify pom.xml: use rule snapshot to run the rule test --- pom.xml | 2 +- .../creedengo/python/integration/tests/GCIRulesIT.java | 2 +- .../src/GCI22/avoidUseOfMethodForBasicOperations.py | 2 +- .../creedengo/python/PythonRuleRepository.java | 5 +++-- ...ons.java => GCI22AvoidUseOfMethodForBasicOperations.java} | 2 +- ...java => GCI22AvoidUseOfMethodForBasicOperationsTest.java} | 4 ++-- 6 files changed, 9 insertions(+), 8 deletions(-) rename src/main/java/org/greencodeinitiative/creedengo/python/checks/{AvoidUseOfMethodForBasicOperations.java => GCI22AvoidUseOfMethodForBasicOperations.java} (96%) rename src/test/java/org/greencodeinitiative/creedengo/python/checks/{AvoidUseOfMethodForBasicOperationsTest.java => GCI22AvoidUseOfMethodForBasicOperationsTest.java} (80%) diff --git a/pom.xml b/pom.xml index 9ba470af..6222fe10 100644 --- a/pom.xml +++ b/pom.xml @@ -80,7 +80,7 @@ 2.21.3 - 3.0.0 + rules-gci22-remove-unnecessary-method-calls-SNAPSHOT https://repo1.maven.org/maven2 diff --git a/src/it/java/org/greencodeinitiative/creedengo/python/integration/tests/GCIRulesIT.java b/src/it/java/org/greencodeinitiative/creedengo/python/integration/tests/GCIRulesIT.java index 6b228f9e..c00a02c7 100644 --- a/src/it/java/org/greencodeinitiative/creedengo/python/integration/tests/GCIRulesIT.java +++ b/src/it/java/org/greencodeinitiative/creedengo/python/integration/tests/GCIRulesIT.java @@ -561,7 +561,7 @@ void testGCI404() { @Test void testGCI22() { - String filePath = "src/avoidUseOfMethodForBasicOperations.py"; + String filePath = "src/GCI22/avoidUseOfMethodForBasicOperations.py"; String ruleId = "creedengo-python:GCI22"; String ruleMsg = "Avoid using methods for simple basic operations."; int[] startLines = new int[]{9, 10, 11, 12, 13, 14, 17, 18, 19, 20, 21, 22, 26, 30, 35, 36, 41, 42, 44, 45, 46, 47, 48, 51, 52, 57, 58, 59, 65, 70, 73, 76, 79, 82, 85 diff --git a/src/it/test-projects/creedengo-python-plugin-test-project/src/GCI22/avoidUseOfMethodForBasicOperations.py b/src/it/test-projects/creedengo-python-plugin-test-project/src/GCI22/avoidUseOfMethodForBasicOperations.py index 14b36015..551f749e 100644 --- a/src/it/test-projects/creedengo-python-plugin-test-project/src/GCI22/avoidUseOfMethodForBasicOperations.py +++ b/src/it/test-projects/creedengo-python-plugin-test-project/src/GCI22/avoidUseOfMethodForBasicOperations.py @@ -112,7 +112,7 @@ def concat(a, b): size = len(my_list) # Compliant {{use of len().}} words = ["This", "is", "a", "test"] -found = "test" in words # Compliant {{Native operator.}} +found = "test" in words # Compliant {{use of in.}} first = "Hello" last = "World" diff --git a/src/main/java/org/greencodeinitiative/creedengo/python/PythonRuleRepository.java b/src/main/java/org/greencodeinitiative/creedengo/python/PythonRuleRepository.java index de2f86bb..989bd4b5 100644 --- a/src/main/java/org/greencodeinitiative/creedengo/python/PythonRuleRepository.java +++ b/src/main/java/org/greencodeinitiative/creedengo/python/PythonRuleRepository.java @@ -56,8 +56,9 @@ public record PythonRuleRepository(SonarRuntime sonarRuntime) implements RulesDe GCI104AvoidCreatingTensorUsingNumpyOrNativePython.class, GCI110AvoidWildcardImportsCheck.class, GCI109AvoidExceptionsForControlFlowCheck.class, - GCI112UsingSlotsOnDataClasses.class - AvoidUseOfMethodForBasicOperations.class + GCI112UsingSlotsOnDataClasses.class, + GCI22AvoidUseOfMethodForBasicOperations.class + ); public static final String LANGUAGE = "py"; diff --git a/src/main/java/org/greencodeinitiative/creedengo/python/checks/AvoidUseOfMethodForBasicOperations.java b/src/main/java/org/greencodeinitiative/creedengo/python/checks/GCI22AvoidUseOfMethodForBasicOperations.java similarity index 96% rename from src/main/java/org/greencodeinitiative/creedengo/python/checks/AvoidUseOfMethodForBasicOperations.java rename to src/main/java/org/greencodeinitiative/creedengo/python/checks/GCI22AvoidUseOfMethodForBasicOperations.java index a4584c3e..16af18b0 100644 --- a/src/main/java/org/greencodeinitiative/creedengo/python/checks/AvoidUseOfMethodForBasicOperations.java +++ b/src/main/java/org/greencodeinitiative/creedengo/python/checks/GCI22AvoidUseOfMethodForBasicOperations.java @@ -29,7 +29,7 @@ import org.sonar.plugins.python.api.tree.BinaryExpression; @Rule(key = "GCI22") -public class AvoidUseOfMethodForBasicOperations extends PythonSubscriptionCheck { +public class GCI22AvoidUseOfMethodForBasicOperations extends PythonSubscriptionCheck { static final String MESSAGE = "Avoid using methods for simple basic operations."; diff --git a/src/test/java/org/greencodeinitiative/creedengo/python/checks/AvoidUseOfMethodForBasicOperationsTest.java b/src/test/java/org/greencodeinitiative/creedengo/python/checks/GCI22AvoidUseOfMethodForBasicOperationsTest.java similarity index 80% rename from src/test/java/org/greencodeinitiative/creedengo/python/checks/AvoidUseOfMethodForBasicOperationsTest.java rename to src/test/java/org/greencodeinitiative/creedengo/python/checks/GCI22AvoidUseOfMethodForBasicOperationsTest.java index 05f8808f..94cb24c7 100644 --- a/src/test/java/org/greencodeinitiative/creedengo/python/checks/AvoidUseOfMethodForBasicOperationsTest.java +++ b/src/test/java/org/greencodeinitiative/creedengo/python/checks/GCI22AvoidUseOfMethodForBasicOperationsTest.java @@ -20,9 +20,9 @@ import org.junit.jupiter.api.Test; import org.sonar.python.checks.utils.PythonCheckVerifier; -public class AvoidUseOfMethodForBasicOperationsTest { +public class GCI22AvoidUseOfMethodForBasicOperationsTest { @Test public void test() { - PythonCheckVerifier.verify("src/test/resources/checks/avoidUseOfMethodForBasicOperations.py", new AvoidUseOfMethodForBasicOperations()); + PythonCheckVerifier.verify(System.getProperty("testfiles.path") + "/GCI22/avoidUseOfMethodForBasicOperations.py", new GCI22AvoidUseOfMethodForBasicOperations()); } } From 34c4be297bb26f465d56f26b614e86718ec33ffd Mon Sep 17 00:00:00 2001 From: Loup-K Date: Fri, 22 May 2026 10:15:15 +0200 Subject: [PATCH 3/4] update creedengo_way_profile.json: sync with main --- .../creedengo/python/creedengo_way_profile.json | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/resources/org/greencodeinitiative/creedengo/python/creedengo_way_profile.json b/src/main/resources/org/greencodeinitiative/creedengo/python/creedengo_way_profile.json index 23a203d0..6a107ce8 100644 --- a/src/main/resources/org/greencodeinitiative/creedengo/python/creedengo_way_profile.json +++ b/src/main/resources/org/greencodeinitiative/creedengo/python/creedengo_way_profile.json @@ -6,7 +6,6 @@ "GCI4", "GCI7", "GCI10", - "GCI22", "GCI24", "GCI35", "GCI72", From 82b2ca8133363aee3f760063142f600caed8fb35 Mon Sep 17 00:00:00 2001 From: Loup-K Date: Fri, 22 May 2026 10:55:21 +0200 Subject: [PATCH 4/4] update creedengo_way_profile.json: add GCI22 --- .../creedengo/python/creedengo_way_profile.json | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/resources/org/greencodeinitiative/creedengo/python/creedengo_way_profile.json b/src/main/resources/org/greencodeinitiative/creedengo/python/creedengo_way_profile.json index 6a107ce8..23a203d0 100644 --- a/src/main/resources/org/greencodeinitiative/creedengo/python/creedengo_way_profile.json +++ b/src/main/resources/org/greencodeinitiative/creedengo/python/creedengo_way_profile.json @@ -6,6 +6,7 @@ "GCI4", "GCI7", "GCI10", + "GCI22", "GCI24", "GCI35", "GCI72",