diff --git a/scan-command/src/main/java/io/ballerina/scan/internal/CoreRule.java b/scan-command/src/main/java/io/ballerina/scan/internal/CoreRule.java index 742f91c..bb85395 100644 --- a/scan-command/src/main/java/io/ballerina/scan/internal/CoreRule.java +++ b/scan-command/src/main/java/io/ballerina/scan/internal/CoreRule.java @@ -30,8 +30,10 @@ * @since 0.1.0 * */ enum CoreRule { + AVOID_CHECKPANIC(RuleFactory.createRule(1, "Avoid checkpanic", RuleKind.CODE_SMELL)), - UNUSED_FUNCTION_PARAMETER(RuleFactory.createRule(2, "Unused function parameter", RuleKind.CODE_SMELL)), + UNUSED_FUNCTION_PARAMETER(RuleFactory.createRule(2, + "Unused function parameter", RuleKind.CODE_SMELL)), PUBLIC_NON_ISOLATED_FUNCTION_CONSTRUCT(RuleFactory.createRule(3, "Non isolated public function", RuleKind.CODE_SMELL)), PUBLIC_NON_ISOLATED_METHOD_CONSTRUCT(RuleFactory.createRule(4, @@ -39,7 +41,15 @@ enum CoreRule { PUBLIC_NON_ISOLATED_CLASS_CONSTRUCT(RuleFactory.createRule(5, "Non isolated public class", RuleKind.CODE_SMELL)), PUBLIC_NON_ISOLATED_OBJECT_CONSTRUCT(RuleFactory.createRule(6, - "Non isolated public object", RuleKind.CODE_SMELL)); + "Non isolated public object", RuleKind.CODE_SMELL)), + OPERATION_ALWAYS_EVALUATES_TO_TRUE(RuleFactory.createRule(7, + "This operation always evaluates to true", RuleKind.CODE_SMELL)), + OPERATION_ALWAYS_EVALUATES_TO_FALSE(RuleFactory.createRule(8, + "This operation always evaluates to false", RuleKind.CODE_SMELL)), + OPERATION_ALWAYS_EVALUATES_TO_SELF_VALUE(RuleFactory.createRule(9, + "This operation always evaluates to the same value", RuleKind.CODE_SMELL)), + SELF_ASSIGNMENT(RuleFactory.createRule(10, + "This variable is assigned to itself", RuleKind.CODE_SMELL)); private final Rule rule; diff --git a/scan-command/src/main/java/io/ballerina/scan/internal/StaticCodeAnalyzer.java b/scan-command/src/main/java/io/ballerina/scan/internal/StaticCodeAnalyzer.java index b39c720..5af096f 100644 --- a/scan-command/src/main/java/io/ballerina/scan/internal/StaticCodeAnalyzer.java +++ b/scan-command/src/main/java/io/ballerina/scan/internal/StaticCodeAnalyzer.java @@ -25,8 +25,11 @@ import io.ballerina.compiler.api.symbols.SymbolKind; import io.ballerina.compiler.api.symbols.TypeDefinitionSymbol; import io.ballerina.compiler.api.symbols.TypeSymbol; +import io.ballerina.compiler.syntax.tree.AssignmentStatementNode; +import io.ballerina.compiler.syntax.tree.BinaryExpressionNode; import io.ballerina.compiler.syntax.tree.CheckExpressionNode; import io.ballerina.compiler.syntax.tree.ClassDefinitionNode; +import io.ballerina.compiler.syntax.tree.CompoundAssignmentStatementNode; import io.ballerina.compiler.syntax.tree.ExplicitAnonymousFunctionExpressionNode; import io.ballerina.compiler.syntax.tree.FunctionDefinitionNode; import io.ballerina.compiler.syntax.tree.FunctionSignatureNode; @@ -44,6 +47,7 @@ import io.ballerina.compiler.syntax.tree.TypeDefinitionNode; import io.ballerina.projects.Document; import io.ballerina.scan.ScannerContext; +import io.ballerina.scan.utils.Constants; import java.util.List; import java.util.Optional; @@ -52,6 +56,9 @@ import static io.ballerina.compiler.syntax.tree.SyntaxKind.PUBLIC_KEYWORD; import static io.ballerina.scan.utils.Constants.INIT_FUNCTION; import static io.ballerina.scan.utils.Constants.MAIN_FUNCTION; +import static io.ballerina.scan.utils.ScanCodeAnalyzerUtils.isDefinedQualifiedNameReference; +import static io.ballerina.scan.utils.ScanCodeAnalyzerUtils.isEqualToProvidedLiteralIdentifier; +import static io.ballerina.scan.utils.ScanCodeAnalyzerUtils.isSameSimpleExpression; /** * {@code StaticCodeAnalyzer} contains the logic to perform core static code analysis on Ballerina documents. @@ -88,6 +95,159 @@ public void visit(CheckExpressionNode checkExpressionNode) { } @Override + public void visit(BinaryExpressionNode binaryExpressionNode) { + reportIssuesWithTrivialOperations(binaryExpressionNode); + filterSameReferenceIssueBasedOnOperandType(binaryExpressionNode.operator()).ifPresent(rule -> { + checkUsageOfSameOperandInBinaryExpr(binaryExpressionNode.lhsExpr(), + binaryExpressionNode.rhsExpr(), rule, binaryExpressionNode); + }); + } + + @Override + public void visit(AssignmentStatementNode assignmentStatementNode) { + checkUsageOfAssignment(assignmentStatementNode.varRef(), assignmentStatementNode.expression(), + CoreRule.SELF_ASSIGNMENT, assignmentStatementNode); + this.visitSyntaxNode(assignmentStatementNode); + } + + @Override + public void visit(CompoundAssignmentStatementNode compoundAssignmentStatementNode) { + checkUsageOfAssignment(compoundAssignmentStatementNode.lhsExpression(), + compoundAssignmentStatementNode.rhsExpression(), CoreRule.SELF_ASSIGNMENT, + compoundAssignmentStatementNode); + this.visitSyntaxNode(compoundAssignmentStatementNode); + } + + private void checkUsageOfSameOperandInBinaryExpr(Node lhs, Node rhs, CoreRule rule, Node binaryExprNode) { + if (isSameSimpleExpression(lhs, rhs)) { + reportIssue(binaryExprNode, rule); + } + } + + private void checkUsageOfAssignment(Node lhs, Node rhs, CoreRule rule, Node assignmentNode) { + if (isSameSimpleExpression(lhs, rhs)) { + reportIssue(assignmentNode, rule); + } + } + + private void reportIssuesWithTrivialOperations(BinaryExpressionNode binaryExpressionNode) { + SyntaxKind binaryOperatorKind = binaryExpressionNode.operator().kind(); + if (binaryOperatorKind == SyntaxKind.GT_TOKEN) { + if (isDefinedQualifiedNameReference(binaryExpressionNode.rhsExpr(), + Constants.Token.FLOAT, Constants.Token.INFINITY)) { + // a > Infinity is always false. + reportIssue(binaryExpressionNode, CoreRule.OPERATION_ALWAYS_EVALUATES_TO_FALSE); + } + + if (isDefinedQualifiedNameReference(binaryExpressionNode.rhsExpr(), + Constants.Token.INT, Constants.Token.MAX_VALUE)) { + // a > MAX_VALUE is always false. + reportIssue(binaryExpressionNode, CoreRule.OPERATION_ALWAYS_EVALUATES_TO_FALSE); + } + } + + if (binaryOperatorKind == SyntaxKind.LT_EQUAL_TOKEN) { + if (isDefinedQualifiedNameReference(binaryExpressionNode.rhsExpr(), + Constants.Token.FLOAT, Constants.Token.INFINITY)) { + // a <= Infinity is always true. + reportIssue(binaryExpressionNode, CoreRule.OPERATION_ALWAYS_EVALUATES_TO_TRUE); + } + + if (isDefinedQualifiedNameReference(binaryExpressionNode.rhsExpr(), + Constants.Token.INT, Constants.Token.MAX_VALUE)) { + // a <= MAX_VALUE is always true. + reportIssue(binaryExpressionNode, CoreRule.OPERATION_ALWAYS_EVALUATES_TO_TRUE); + } + } + + if (binaryOperatorKind == SyntaxKind.LT_TOKEN) { + if (isDefinedQualifiedNameReference(binaryExpressionNode.rhsExpr(), + Constants.Token.INT, Constants.Token.MIN_VALUE)) { + // a < MIN_VALUE is always false. + reportIssue(binaryExpressionNode, CoreRule.OPERATION_ALWAYS_EVALUATES_TO_FALSE); + } + } + + if (binaryOperatorKind == SyntaxKind.GT_EQUAL_TOKEN) { + if (isDefinedQualifiedNameReference(binaryExpressionNode.rhsExpr(), + Constants.Token.INT, Constants.Token.MIN_VALUE)) { + // a >= MIN_VALUE is always true. + reportIssue(binaryExpressionNode, CoreRule.OPERATION_ALWAYS_EVALUATES_TO_TRUE); + } + } + + if (binaryOperatorKind == SyntaxKind.LOGICAL_AND_TOKEN) { + if (isEqualToProvidedLiteralIdentifier(binaryExpressionNode.rhsExpr(), Constants.Token.FALSE) + || isEqualToProvidedLiteralIdentifier(binaryExpressionNode.lhsExpr(), Constants.Token.FALSE)) { + // a && false is always false. + reportIssue(binaryExpressionNode, CoreRule.OPERATION_ALWAYS_EVALUATES_TO_FALSE); + } + + if (isEqualToProvidedLiteralIdentifier(binaryExpressionNode.rhsExpr(), Constants.Token.TRUE) + || isEqualToProvidedLiteralIdentifier(binaryExpressionNode.lhsExpr(), Constants.Token.TRUE)) { + // a && true is always `a`. + reportIssue(binaryExpressionNode, CoreRule.OPERATION_ALWAYS_EVALUATES_TO_SELF_VALUE); + } + } + + if (binaryOperatorKind == SyntaxKind.LOGICAL_OR_TOKEN) { + if (isEqualToProvidedLiteralIdentifier(binaryExpressionNode.rhsExpr(), Constants.Token.FALSE) + || isEqualToProvidedLiteralIdentifier(binaryExpressionNode.lhsExpr(), Constants.Token.FALSE)) { + // a || false is always `a`. + reportIssue(binaryExpressionNode, CoreRule.OPERATION_ALWAYS_EVALUATES_TO_SELF_VALUE); + } + + if (isEqualToProvidedLiteralIdentifier(binaryExpressionNode.rhsExpr(), Constants.Token.TRUE) + || isEqualToProvidedLiteralIdentifier(binaryExpressionNode.lhsExpr(), Constants.Token.TRUE)) { + // a || true is always true. + reportIssue(binaryExpressionNode, CoreRule.OPERATION_ALWAYS_EVALUATES_TO_TRUE); + } + } + + if (binaryOperatorKind == SyntaxKind.BITWISE_AND_TOKEN) { + if (isEqualToProvidedLiteralIdentifier(binaryExpressionNode.rhsExpr(), Constants.Token.ZERO) + || isEqualToProvidedLiteralIdentifier(binaryExpressionNode.lhsExpr(), Constants.Token.ZERO)) { + // a & 0 is always false. + reportIssue(binaryExpressionNode, CoreRule.OPERATION_ALWAYS_EVALUATES_TO_FALSE); + } + + if (isEqualToProvidedLiteralIdentifier(binaryExpressionNode.rhsExpr(), Constants.Token.MINUS_ONE) + || isEqualToProvidedLiteralIdentifier(binaryExpressionNode.lhsExpr(), Constants.Token.MINUS_ONE)) { + // a & -1 is always `a`. + reportIssue(binaryExpressionNode, CoreRule.OPERATION_ALWAYS_EVALUATES_TO_SELF_VALUE); + } + } + + if (binaryOperatorKind == SyntaxKind.PIPE_TOKEN) { + if (isEqualToProvidedLiteralIdentifier(binaryExpressionNode.rhsExpr(), Constants.Token.ZERO) + || isEqualToProvidedLiteralIdentifier(binaryExpressionNode.lhsExpr(), Constants.Token.ZERO)) { + // a | 0 is always `a`. + reportIssue(binaryExpressionNode, CoreRule.OPERATION_ALWAYS_EVALUATES_TO_SELF_VALUE); + } + + if (isEqualToProvidedLiteralIdentifier(binaryExpressionNode.rhsExpr(), Constants.Token.MINUS_ONE) + || isEqualToProvidedLiteralIdentifier(binaryExpressionNode.lhsExpr(), Constants.Token.MINUS_ONE)) { + // a | -1 is always true. + reportIssue(binaryExpressionNode, CoreRule.OPERATION_ALWAYS_EVALUATES_TO_TRUE); + } + } + } + + private Optional filterSameReferenceIssueBasedOnOperandType(Token operator) { + switch (operator.kind()) { + case GT_EQUAL_TOKEN, LT_EQUAL_TOKEN, DOUBLE_EQUAL_TOKEN, TRIPPLE_EQUAL_TOKEN -> { + return Optional.of(CoreRule.OPERATION_ALWAYS_EVALUATES_TO_TRUE); + } + case GT_TOKEN, LT_TOKEN, NOT_DOUBLE_EQUAL_TOKEN, NOT_EQUAL_TOKEN -> { + return Optional.of(CoreRule.OPERATION_ALWAYS_EVALUATES_TO_FALSE); + } + case LOGICAL_OR_TOKEN, LOGICAL_AND_TOKEN, BITWISE_AND_TOKEN, PIPE_TOKEN -> { + return Optional.of(CoreRule.OPERATION_ALWAYS_EVALUATES_TO_SELF_VALUE); + } + } + return Optional.empty(); + } + public void visit(FunctionDefinitionNode functionDefinitionNode) { checkUnusedFunctionParameters(functionDefinitionNode.functionSignature()); String functionName = functionDefinitionNode.functionName().text(); diff --git a/scan-command/src/main/java/io/ballerina/scan/utils/Constants.java b/scan-command/src/main/java/io/ballerina/scan/utils/Constants.java index e7a07c2..8f1edfc 100644 --- a/scan-command/src/main/java/io/ballerina/scan/utils/Constants.java +++ b/scan-command/src/main/java/io/ballerina/scan/utils/Constants.java @@ -64,6 +64,21 @@ public class Constants { public static final String MAIN_FUNCTION = "main"; public static final String INIT_FUNCTION = "init"; + public static class Token { + public static final String FLOAT = "float"; + public static final String INT = "int"; + public static final String INFINITY = "Infinity"; + public static final String MAX_VALUE = "MAX_VALUE"; + public static final String MIN_VALUE = "MIN_VALUE"; + public static final String TRUE = "true"; + public static final String FALSE = "false"; + public static final String ZERO = "0"; + public static final String ONE = "1"; + public static final String MINUS_ONE = "-1"; + private Token() { + } + } + private Constants() { } } diff --git a/scan-command/src/main/java/io/ballerina/scan/utils/ScanCodeAnalyzerUtils.java b/scan-command/src/main/java/io/ballerina/scan/utils/ScanCodeAnalyzerUtils.java new file mode 100644 index 0000000..1c52e4c --- /dev/null +++ b/scan-command/src/main/java/io/ballerina/scan/utils/ScanCodeAnalyzerUtils.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2025, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package io.ballerina.scan.utils; + +import io.ballerina.compiler.syntax.tree.BasicLiteralNode; +import io.ballerina.compiler.syntax.tree.BuiltinSimpleNameReferenceNode; +import io.ballerina.compiler.syntax.tree.ExpressionNode; +import io.ballerina.compiler.syntax.tree.FieldAccessExpressionNode; +import io.ballerina.compiler.syntax.tree.IndexedExpressionNode; +import io.ballerina.compiler.syntax.tree.Node; +import io.ballerina.compiler.syntax.tree.QualifiedNameReferenceNode; +import io.ballerina.compiler.syntax.tree.SeparatedNodeList; +import io.ballerina.compiler.syntax.tree.SimpleNameReferenceNode; +import io.ballerina.compiler.syntax.tree.SyntaxKind; +import io.ballerina.compiler.syntax.tree.UnaryExpressionNode; +import io.ballerina.projects.Document; +import io.ballerina.scan.Rule; +import io.ballerina.scan.ScannerContext; +import io.ballerina.tools.diagnostics.Location; + +/** + * {@code ScanCodeAnalyzerUtils} contains the util functions for the static code analysis. + * + * @since 0.1.0 + * */ +public class ScanCodeAnalyzerUtils { + public static void reportIssue(ScannerContext scannerContext, Document document, Node node, Rule rule) { + scannerContext.getReporter().reportIssue(document, node.location(), rule); + } + + public static void reportIssue(ScannerContext scannerContext, Document document, Location location, Rule rule) { + scannerContext.getReporter().reportIssue(document, location, rule); + } + + public static boolean isSameSimpleExpression(Node n1, Node n2) { + if (n1 instanceof SimpleNameReferenceNode lhsExp && n2 instanceof SimpleNameReferenceNode rhsExpr) { + return lhsExp.name().text().equals(rhsExpr.name().text()); + } + + if (n1 instanceof QualifiedNameReferenceNode lhsExp && n2 instanceof QualifiedNameReferenceNode rhsExpr) { + return lhsExp.modulePrefix() != null && rhsExpr.modulePrefix() != null + && lhsExp.modulePrefix().text().equals(rhsExpr.modulePrefix().text()) + && lhsExp.identifier().text().equals(rhsExpr.identifier().text()); + } + + if (n1 instanceof FieldAccessExpressionNode lhsExp && n2 instanceof FieldAccessExpressionNode rhsExpr) { + // only the simple field access expressions will be considered. + return isSameSimpleExpression(lhsExp.fieldName(), rhsExpr.fieldName()) + && isSameSimpleExpression(lhsExp.expression(), rhsExpr.expression()); + } + + if (n1 instanceof IndexedExpressionNode lhsExp && n2 instanceof IndexedExpressionNode rhsExpr) { + // only the simple field access expressions will be considered. + return isSameSimpleExpression(lhsExp.containerExpression(), rhsExpr.containerExpression()) + && isSameKeyExpression(lhsExp.keyExpression(), rhsExpr.keyExpression()); + } + + if (n1 instanceof BuiltinSimpleNameReferenceNode lhsExp + && n2 instanceof BuiltinSimpleNameReferenceNode rhsExpr) { + return lhsExp.name().text().equals(rhsExpr.name().text()); + } + + if (n1 instanceof BasicLiteralNode lhsExp && n2 instanceof BasicLiteralNode rhsExpr) { + return lhsExp.literalToken().text().equals(rhsExpr.literalToken().text()); + } + + return false; + } + + private static boolean isSameKeyExpression(SeparatedNodeList lhsKeyExpNodes, + SeparatedNodeList rhsKeyExpNodes) { + if (lhsKeyExpNodes.size() != rhsKeyExpNodes.size()) { + return false; + } + + for (int i = 0; i < lhsKeyExpNodes.size(); i++) { + if (!isSameSimpleExpression(lhsKeyExpNodes.get(i), rhsKeyExpNodes.get(i))) { + return false; + } + } + return true; + } + + public static boolean isDefinedQualifiedNameReference(Node node, String module, String identifier) { + if (node instanceof QualifiedNameReferenceNode ref) { + return ref.modulePrefix() != null && ref.identifier() != null + && ref.modulePrefix().text().equals(module) && ref.identifier().text().equals(identifier); + } + return false; + } + + public static boolean isEqualToProvidedLiteralIdentifier(Node node, String identifierName) { + if (identifierName.equals(Constants.Token.MINUS_ONE)) { + if (node instanceof UnaryExpressionNode exp) { + return exp.unaryOperator().kind().equals(SyntaxKind.MINUS_TOKEN) + && isEqualToProvidedLiteralIdentifier(exp.expression(), Constants.Token.ONE); + } + return false; + } + if (node instanceof BasicLiteralNode ref) { + return ref.literalToken().text().equals(identifierName); + } + return false; + } +} diff --git a/scan-command/src/test/java/io/ballerina/scan/internal/CoreRuleTest.java b/scan-command/src/test/java/io/ballerina/scan/internal/CoreRuleTest.java index ec24936..5da964b 100644 --- a/scan-command/src/test/java/io/ballerina/scan/internal/CoreRuleTest.java +++ b/scan-command/src/test/java/io/ballerina/scan/internal/CoreRuleTest.java @@ -31,6 +31,11 @@ public class CoreRuleTest { public static final String AVOID_CHECKPANIC = "Avoid checkpanic"; public static final String UNUSED_FUNCTION_PARAMETER = "Unused function parameter"; + public static final String OPERATION_ALWAYS_EVALUATES_TO_TRUE = "This operation always evaluates to true"; + public static final String OPERATION_ALWAYS_EVALUATES_TO_FALSE = "This operation always evaluates to false"; + public static final String OPERATION_ALWAYS_EVALUATES_TO_SELF_VALUE = + "This operation always evaluates to the same value"; + public static final String SELF_ASSIGNMENT = "This variable is assigned to itself"; public static final String PUBLIC_NON_ISOLATED_FUNCTION_CONSTRUCT = "Non isolated public function"; public static final String PUBLIC_NON_ISOLATED_METHOD_CONSTRUCT = @@ -42,7 +47,7 @@ public class CoreRuleTest { @Test(description = "test all rules") void testAllRules() { - Assert.assertEquals(CoreRule.rules().size(), 6); + Assert.assertEquals(CoreRule.rules().size(), 10); } @Test(description = "test checkpanic rule") @@ -63,6 +68,41 @@ void testUnusedFunctionParameterRule() { Assert.assertEquals(rule.kind(), RuleKind.CODE_SMELL); } + @Test(description = "test always true evaluates") + void testTrueEvaluates() { + Rule rule = CoreRule.OPERATION_ALWAYS_EVALUATES_TO_TRUE.rule(); + Assert.assertEquals(rule.id(), "ballerina:7"); + Assert.assertEquals(rule.numericId(), 7); + Assert.assertEquals(rule.description(), OPERATION_ALWAYS_EVALUATES_TO_TRUE); + Assert.assertEquals(rule.kind(), RuleKind.CODE_SMELL); + } + + @Test(description = "test always false evaluates") + void testFalseEvaluates() { + Rule rule = CoreRule.OPERATION_ALWAYS_EVALUATES_TO_FALSE.rule(); + Assert.assertEquals(rule.id(), "ballerina:8"); + Assert.assertEquals(rule.numericId(), 8); + Assert.assertEquals(rule.description(), OPERATION_ALWAYS_EVALUATES_TO_FALSE); + Assert.assertEquals(rule.kind(), RuleKind.CODE_SMELL); + } + + @Test(description = "test evaluate to the same value") + void testSelfEvaluates() { + Rule rule = CoreRule.OPERATION_ALWAYS_EVALUATES_TO_SELF_VALUE.rule(); + Assert.assertEquals(rule.id(), "ballerina:9"); + Assert.assertEquals(rule.numericId(), 9); + Assert.assertEquals(rule.description(), OPERATION_ALWAYS_EVALUATES_TO_SELF_VALUE); + Assert.assertEquals(rule.kind(), RuleKind.CODE_SMELL); + } + + @Test(description = "test self assignment") + void testSelfAssignmentAnalyzer() { + Rule rule = CoreRule.SELF_ASSIGNMENT.rule(); + Assert.assertEquals(rule.id(), "ballerina:10"); + Assert.assertEquals(rule.numericId(), 10); + Assert.assertEquals(rule.description(), SELF_ASSIGNMENT); + } + @Test(description = "test non isolated public functions") void testNonIsolatedPublicFunctionConstructsRule() { Rule rule = CoreRule.PUBLIC_NON_ISOLATED_FUNCTION_CONSTRUCT.rule(); diff --git a/scan-command/src/test/java/io/ballerina/scan/internal/Rule007Test.java b/scan-command/src/test/java/io/ballerina/scan/internal/Rule007Test.java new file mode 100644 index 0000000..1906dff --- /dev/null +++ b/scan-command/src/test/java/io/ballerina/scan/internal/Rule007Test.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package io.ballerina.scan.internal; + +import io.ballerina.compiler.api.SemanticModel; +import io.ballerina.projects.Document; +import io.ballerina.scan.Issue; +import io.ballerina.scan.RuleKind; +import org.testng.Assert; +import org.testng.annotations.Test; + +import java.util.List; + +/** + * Always true evaluates tests. + * + * @since 0.5.0 + */ +public class Rule007Test extends StaticCodeAnalyzerTest { + public static final String OPERATION_ALWAYS_EVALUATES_TO_TRUE = "This operation always evaluates to true"; + + @Test(description = "test always true evaluates") + void testTrueEvaluates() { + String documentName = "rule_007_always_true.bal"; + Document document = loadDocument(documentName); + ScannerContextImpl scannerContext = new ScannerContextImpl(List.of( + CoreRule.OPERATION_ALWAYS_EVALUATES_TO_TRUE.rule())); + + SemanticModel semanticModel = document.module().getCompilation().getSemanticModel(); + StaticCodeAnalyzer staticCodeAnalyzer = new StaticCodeAnalyzer(document, scannerContext, semanticModel); + staticCodeAnalyzer.analyze(); + List issues = scannerContext.getReporter().getIssues(); + Assert.assertEquals(issues.size(), 21); + + assertIssue(issues.get(0), documentName, 15, 10, 15, 16, "ballerina:7", 7, + OPERATION_ALWAYS_EVALUATES_TO_TRUE, RuleKind.CODE_SMELL); + assertIssue(issues.get(1), documentName, 16, 10, 16, 16, "ballerina:7", 7, + OPERATION_ALWAYS_EVALUATES_TO_TRUE, RuleKind.CODE_SMELL); + assertIssue(issues.get(2), documentName, 17, 10, 17, 16, "ballerina:7", 7, + OPERATION_ALWAYS_EVALUATES_TO_TRUE, RuleKind.CODE_SMELL); + assertIssue(issues.get(3), documentName, 18, 10, 18, 17, "ballerina:7", 7, + OPERATION_ALWAYS_EVALUATES_TO_TRUE, RuleKind.CODE_SMELL); + assertIssue(issues.get(4), documentName, 19, 10, 19, 20, "ballerina:7", 7, + OPERATION_ALWAYS_EVALUATES_TO_TRUE, RuleKind.CODE_SMELL); + assertIssue(issues.get(5), documentName, 20, 10, 20, 20, "ballerina:7", 7, + OPERATION_ALWAYS_EVALUATES_TO_TRUE, RuleKind.CODE_SMELL); + assertIssue(issues.get(6), documentName, 21, 10, 21, 20, "ballerina:7", 7, + OPERATION_ALWAYS_EVALUATES_TO_TRUE, RuleKind.CODE_SMELL); + assertIssue(issues.get(7), documentName, 22, 10, 22, 21, "ballerina:7", 7, + OPERATION_ALWAYS_EVALUATES_TO_TRUE, RuleKind.CODE_SMELL); + assertIssue(issues.get(8), documentName, 23, 10, 23, 52, "ballerina:7", 7, + OPERATION_ALWAYS_EVALUATES_TO_TRUE, RuleKind.CODE_SMELL); + assertIssue(issues.get(9), documentName, 24, 10, 24, 52, "ballerina:7", 7, + OPERATION_ALWAYS_EVALUATES_TO_TRUE, RuleKind.CODE_SMELL); + assertIssue(issues.get(10), documentName, 25, 10, 25, 52, "ballerina:7", 7, + OPERATION_ALWAYS_EVALUATES_TO_TRUE, RuleKind.CODE_SMELL); + assertIssue(issues.get(11), documentName, 26, 10, 26, 53, "ballerina:7", 7, + OPERATION_ALWAYS_EVALUATES_TO_TRUE, RuleKind.CODE_SMELL); + assertIssue(issues.get(12), documentName, 27, 10, 27, 26, "ballerina:7", 7, + OPERATION_ALWAYS_EVALUATES_TO_TRUE, RuleKind.CODE_SMELL); + assertIssue(issues.get(13), documentName, 28, 10, 28, 26, "ballerina:7", 7, + OPERATION_ALWAYS_EVALUATES_TO_TRUE, RuleKind.CODE_SMELL); + assertIssue(issues.get(14), documentName, 29, 10, 29, 26, "ballerina:7", 7, + OPERATION_ALWAYS_EVALUATES_TO_TRUE, RuleKind.CODE_SMELL); + assertIssue(issues.get(15), documentName, 30, 10, 30, 27, "ballerina:7", 7, + OPERATION_ALWAYS_EVALUATES_TO_TRUE, RuleKind.CODE_SMELL); + assertIssue(issues.get(16), documentName, 31, 13, 31, 31, "ballerina:7", 7, + OPERATION_ALWAYS_EVALUATES_TO_TRUE, RuleKind.CODE_SMELL); + assertIssue(issues.get(17), documentName, 32, 13, 32, 31, "ballerina:7", 7, + OPERATION_ALWAYS_EVALUATES_TO_TRUE, RuleKind.CODE_SMELL); + assertIssue(issues.get(18), documentName, 33, 13, 33, 32, "ballerina:7", 7, + OPERATION_ALWAYS_EVALUATES_TO_TRUE, RuleKind.CODE_SMELL); + assertIssue(issues.get(19), documentName, 34, 13, 34, 22, "ballerina:7", 7, + OPERATION_ALWAYS_EVALUATES_TO_TRUE, RuleKind.CODE_SMELL); + assertIssue(issues.get(20), documentName, 35, 14, 35, 20, "ballerina:7", 7, + OPERATION_ALWAYS_EVALUATES_TO_TRUE, RuleKind.CODE_SMELL); + } +} diff --git a/scan-command/src/test/java/io/ballerina/scan/internal/Rule008Test.java b/scan-command/src/test/java/io/ballerina/scan/internal/Rule008Test.java new file mode 100644 index 0000000..bb4c693 --- /dev/null +++ b/scan-command/src/test/java/io/ballerina/scan/internal/Rule008Test.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package io.ballerina.scan.internal; + +import io.ballerina.compiler.api.SemanticModel; +import io.ballerina.projects.Document; +import io.ballerina.scan.Issue; +import io.ballerina.scan.RuleKind; +import org.testng.Assert; +import org.testng.annotations.Test; + +import java.util.List; + +/** + * Always false evaluates tests. + * + * @since 0.5.0 + */ +public class Rule008Test extends StaticCodeAnalyzerTest { + public static final String OPERATION_ALWAYS_EVALUATES_TO_FALSE = "This operation always evaluates to false"; + + @Test(description = "test always false evaluates") + void testFalseEvaluates() { + String documentName = "rule_008_always_false.bal"; + Document document = loadDocument(documentName); + ScannerContextImpl scannerContext = new ScannerContextImpl(List.of( + CoreRule.OPERATION_ALWAYS_EVALUATES_TO_FALSE.rule())); + + SemanticModel semanticModel = document.module().getCompilation().getSemanticModel(); + StaticCodeAnalyzer staticCodeAnalyzer = new StaticCodeAnalyzer(document, scannerContext, semanticModel); + staticCodeAnalyzer.analyze(); + List issues = scannerContext.getReporter().getIssues(); + Assert.assertEquals(issues.size(), 21); + + assertIssue(issues.get(0), documentName, 17, 10, 17, 16, "ballerina:8", 8, + OPERATION_ALWAYS_EVALUATES_TO_FALSE, RuleKind.CODE_SMELL); + assertIssue(issues.get(1), documentName, 18, 10, 18, 15, "ballerina:8", 8, + OPERATION_ALWAYS_EVALUATES_TO_FALSE, RuleKind.CODE_SMELL); + assertIssue(issues.get(2), documentName, 19, 10, 19, 15, "ballerina:8", 8, + OPERATION_ALWAYS_EVALUATES_TO_FALSE, RuleKind.CODE_SMELL); + assertIssue(issues.get(3), documentName, 20, 10, 20, 17, "ballerina:8", 8, + OPERATION_ALWAYS_EVALUATES_TO_FALSE, RuleKind.CODE_SMELL); + assertIssue(issues.get(4), documentName, 21, 10, 21, 20, "ballerina:8", 8, + OPERATION_ALWAYS_EVALUATES_TO_FALSE, RuleKind.CODE_SMELL); + assertIssue(issues.get(5), documentName, 22, 10, 22, 19, "ballerina:8", 8, + OPERATION_ALWAYS_EVALUATES_TO_FALSE, RuleKind.CODE_SMELL); + assertIssue(issues.get(6), documentName, 23, 10, 23, 19, "ballerina:8", 8, + OPERATION_ALWAYS_EVALUATES_TO_FALSE, RuleKind.CODE_SMELL); + assertIssue(issues.get(7), documentName, 24, 10, 24, 21, "ballerina:8", 8, + OPERATION_ALWAYS_EVALUATES_TO_FALSE, RuleKind.CODE_SMELL); + assertIssue(issues.get(8), documentName, 25, 10, 25, 52, "ballerina:8", 8, + OPERATION_ALWAYS_EVALUATES_TO_FALSE, RuleKind.CODE_SMELL); + assertIssue(issues.get(9), documentName, 26, 10, 26, 51, "ballerina:8", 8, + OPERATION_ALWAYS_EVALUATES_TO_FALSE, RuleKind.CODE_SMELL); + assertIssue(issues.get(10), documentName, 27, 10, 27, 51, "ballerina:8", 8, + OPERATION_ALWAYS_EVALUATES_TO_FALSE, RuleKind.CODE_SMELL); + assertIssue(issues.get(11), documentName, 28, 10, 28, 53, "ballerina:8", 8, + OPERATION_ALWAYS_EVALUATES_TO_FALSE, RuleKind.CODE_SMELL); + assertIssue(issues.get(12), documentName, 29, 10, 29, 26, "ballerina:8", 8, + OPERATION_ALWAYS_EVALUATES_TO_FALSE, RuleKind.CODE_SMELL); + assertIssue(issues.get(13), documentName, 30, 10, 30, 25, "ballerina:8", 8, + OPERATION_ALWAYS_EVALUATES_TO_FALSE, RuleKind.CODE_SMELL); + assertIssue(issues.get(14), documentName, 31, 10, 31, 25, "ballerina:8", 8, + OPERATION_ALWAYS_EVALUATES_TO_FALSE, RuleKind.CODE_SMELL); + assertIssue(issues.get(15), documentName, 32, 10, 32, 27, "ballerina:8", 8, + OPERATION_ALWAYS_EVALUATES_TO_FALSE, RuleKind.CODE_SMELL); + assertIssue(issues.get(16), documentName, 33, 13, 33, 30, "ballerina:8", 8, + OPERATION_ALWAYS_EVALUATES_TO_FALSE, RuleKind.CODE_SMELL); + assertIssue(issues.get(17), documentName, 34, 13, 34, 30, "ballerina:8", 8, + OPERATION_ALWAYS_EVALUATES_TO_FALSE, RuleKind.CODE_SMELL); + assertIssue(issues.get(18), documentName, 35, 13, 35, 31, "ballerina:8", 8, + OPERATION_ALWAYS_EVALUATES_TO_FALSE, RuleKind.CODE_SMELL); + assertIssue(issues.get(19), documentName, 36, 13, 36, 23, "ballerina:8", 8, + OPERATION_ALWAYS_EVALUATES_TO_FALSE, RuleKind.CODE_SMELL); + assertIssue(issues.get(20), documentName, 37, 14, 37, 19, "ballerina:8", 8, + OPERATION_ALWAYS_EVALUATES_TO_FALSE, RuleKind.CODE_SMELL); + } +} diff --git a/scan-command/src/test/java/io/ballerina/scan/internal/Rule009Test.java b/scan-command/src/test/java/io/ballerina/scan/internal/Rule009Test.java new file mode 100644 index 0000000..2f78670 --- /dev/null +++ b/scan-command/src/test/java/io/ballerina/scan/internal/Rule009Test.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package io.ballerina.scan.internal; + +import io.ballerina.compiler.api.SemanticModel; +import io.ballerina.projects.Document; +import io.ballerina.scan.Issue; +import io.ballerina.scan.RuleKind; +import org.testng.Assert; +import org.testng.annotations.Test; + +import java.util.List; + +/** + * Always self value evaluates tests tests. + * + * @since 0.5.0 + */ +public class Rule009Test extends StaticCodeAnalyzerTest { + public static final String OPERATION_ALWAYS_EVALUATES_TO_SELF_VALUE = + "This operation always evaluates to the same value"; + + @Test(description = "test evaluate to the same value") + void testSelfEvaluates() { + String documentName = "rule_009_evaluates_same_value.bal"; + Document document = loadDocument(documentName); + ScannerContextImpl scannerContext = new ScannerContextImpl(List.of( + CoreRule.OPERATION_ALWAYS_EVALUATES_TO_SELF_VALUE.rule())); + + SemanticModel semanticModel = document.module().getCompilation().getSemanticModel(); + StaticCodeAnalyzer staticCodeAnalyzer = new StaticCodeAnalyzer(document, scannerContext, semanticModel); + staticCodeAnalyzer.analyze(); + List issues = scannerContext.getReporter().getIssues(); + Assert.assertEquals(issues.size(), 18); + + assertIssue(issues.get(0), documentName, 16, 10, 16, 15, "ballerina:9", 9, + OPERATION_ALWAYS_EVALUATES_TO_SELF_VALUE, RuleKind.CODE_SMELL); + assertIssue(issues.get(1), documentName, 17, 10, 17, 15, "ballerina:9", 9, + OPERATION_ALWAYS_EVALUATES_TO_SELF_VALUE, RuleKind.CODE_SMELL); + assertIssue(issues.get(2), documentName, 18, 10, 18, 16, "ballerina:9", 9, + OPERATION_ALWAYS_EVALUATES_TO_SELF_VALUE, RuleKind.CODE_SMELL); + assertIssue(issues.get(3), documentName, 19, 10, 19, 16, "ballerina:9", 9, + OPERATION_ALWAYS_EVALUATES_TO_SELF_VALUE, RuleKind.CODE_SMELL); + assertIssue(issues.get(4), documentName, 20, 10, 20, 19, "ballerina:9", 9, + OPERATION_ALWAYS_EVALUATES_TO_SELF_VALUE, RuleKind.CODE_SMELL); + assertIssue(issues.get(5), documentName, 21, 10, 21, 19, "ballerina:9", 9, + OPERATION_ALWAYS_EVALUATES_TO_SELF_VALUE, RuleKind.CODE_SMELL); + assertIssue(issues.get(6), documentName, 22, 10, 22, 20, "ballerina:9", 9, + OPERATION_ALWAYS_EVALUATES_TO_SELF_VALUE, RuleKind.CODE_SMELL); + assertIssue(issues.get(7), documentName, 23, 10, 23, 20, "ballerina:9", 9, + OPERATION_ALWAYS_EVALUATES_TO_SELF_VALUE, RuleKind.CODE_SMELL); + assertIssue(issues.get(8), documentName, 24, 10, 24, 51, "ballerina:9", 9, + OPERATION_ALWAYS_EVALUATES_TO_SELF_VALUE, RuleKind.CODE_SMELL); + assertIssue(issues.get(9), documentName, 25, 10, 25, 51, "ballerina:9", 9, + OPERATION_ALWAYS_EVALUATES_TO_SELF_VALUE, RuleKind.CODE_SMELL); + assertIssue(issues.get(10), documentName, 26, 10, 26, 25, "ballerina:9", 9, + OPERATION_ALWAYS_EVALUATES_TO_SELF_VALUE, RuleKind.CODE_SMELL); + assertIssue(issues.get(11), documentName, 27, 10, 27, 25, "ballerina:9", 9, + OPERATION_ALWAYS_EVALUATES_TO_SELF_VALUE, RuleKind.CODE_SMELL); + assertIssue(issues.get(12), documentName, 28, 10, 28, 26, "ballerina:9", 9, + OPERATION_ALWAYS_EVALUATES_TO_SELF_VALUE, RuleKind.CODE_SMELL); + assertIssue(issues.get(13), documentName, 29, 10, 29, 26, "ballerina:9", 9, + OPERATION_ALWAYS_EVALUATES_TO_SELF_VALUE, RuleKind.CODE_SMELL); + assertIssue(issues.get(14), documentName, 30, 13, 30, 22, "ballerina:9", 9, + OPERATION_ALWAYS_EVALUATES_TO_SELF_VALUE, RuleKind.CODE_SMELL); + assertIssue(issues.get(15), documentName, 31, 13, 31, 23, "ballerina:9", 9, + OPERATION_ALWAYS_EVALUATES_TO_SELF_VALUE, RuleKind.CODE_SMELL); + assertIssue(issues.get(16), documentName, 32, 18, 32, 23, "ballerina:9", 9, + OPERATION_ALWAYS_EVALUATES_TO_SELF_VALUE, RuleKind.CODE_SMELL); + assertIssue(issues.get(17), documentName, 33, 14, 33, 20, "ballerina:9", 9, + OPERATION_ALWAYS_EVALUATES_TO_SELF_VALUE, RuleKind.CODE_SMELL); + } +} diff --git a/scan-command/src/test/java/io/ballerina/scan/internal/Rule010Test.java b/scan-command/src/test/java/io/ballerina/scan/internal/Rule010Test.java new file mode 100644 index 0000000..ab5722b --- /dev/null +++ b/scan-command/src/test/java/io/ballerina/scan/internal/Rule010Test.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package io.ballerina.scan.internal; + +import io.ballerina.compiler.api.SemanticModel; +import io.ballerina.projects.Document; +import io.ballerina.scan.Issue; +import io.ballerina.scan.RuleKind; +import org.testng.Assert; +import org.testng.annotations.Test; + +import java.util.List; + +/** + * Self assignment tests. + * + * @since 0.1.0 + */ +public class Rule010Test extends StaticCodeAnalyzerTest { + public static final String SELF_ASSIGNMENT = "This variable is assigned to itself"; + + @Test(description = "test self assignment") + void testSelfAssignmentAnalyzer() { + String documentName = "rule009_self_assignment.bal"; + Document document = loadDocument(documentName); + ScannerContextImpl scannerContext = new ScannerContextImpl(List.of(CoreRule.SELF_ASSIGNMENT.rule())); + SemanticModel semanticModel = document.module().getCompilation().getSemanticModel(); + StaticCodeAnalyzer staticCodeAnalyzer = new StaticCodeAnalyzer(document, scannerContext, semanticModel); + staticCodeAnalyzer.analyze(); + List issues = scannerContext.getReporter().getIssues(); + + Assert.assertEquals(issues.size(), 33); + + assertIssue(issues.get(0), documentName, 5, 4, 5, 10, "ballerina:10", 10, + SELF_ASSIGNMENT, RuleKind.CODE_SMELL); + assertIssue(issues.get(1), documentName, 6, 4, 6, 11, "ballerina:10", 10, + SELF_ASSIGNMENT, RuleKind.CODE_SMELL); + assertIssue(issues.get(2), documentName, 7, 4, 7, 11, "ballerina:10", 10, + SELF_ASSIGNMENT, RuleKind.CODE_SMELL); + assertIssue(issues.get(3), documentName, 8, 4, 8, 11, "ballerina:10", 10, + SELF_ASSIGNMENT, RuleKind.CODE_SMELL); + assertIssue(issues.get(4), documentName, 9, 4, 9, 11, "ballerina:10", 10, + SELF_ASSIGNMENT, RuleKind.CODE_SMELL); + assertIssue(issues.get(5), documentName, 10, 4, 10, 11, "ballerina:10", 10, + SELF_ASSIGNMENT, RuleKind.CODE_SMELL); + assertIssue(issues.get(6), documentName, 11, 4, 11, 11, "ballerina:10", 10, + SELF_ASSIGNMENT, RuleKind.CODE_SMELL); + assertIssue(issues.get(7), documentName, 12, 4, 12, 11, "ballerina:10", 10, + SELF_ASSIGNMENT, RuleKind.CODE_SMELL); + assertIssue(issues.get(8), documentName, 13, 4, 13, 12, "ballerina:10", 10, + SELF_ASSIGNMENT, RuleKind.CODE_SMELL); + assertIssue(issues.get(9), documentName, 14, 4, 14, 12, "ballerina:10", 10, + SELF_ASSIGNMENT, RuleKind.CODE_SMELL); + assertIssue(issues.get(10), documentName, 15, 4, 15, 13, "ballerina:10", 10, + SELF_ASSIGNMENT, RuleKind.CODE_SMELL); + assertIssue(issues.get(11), documentName, 28, 4, 28, 14, "ballerina:10", 10, + SELF_ASSIGNMENT, RuleKind.CODE_SMELL); + assertIssue(issues.get(12), documentName, 29, 4, 29, 15, "ballerina:10", 10, + SELF_ASSIGNMENT, RuleKind.CODE_SMELL); + assertIssue(issues.get(13), documentName, 30, 4, 30, 15, "ballerina:10", 10, + SELF_ASSIGNMENT, RuleKind.CODE_SMELL); + assertIssue(issues.get(14), documentName, 31, 4, 31, 15, "ballerina:10", 10, + SELF_ASSIGNMENT, RuleKind.CODE_SMELL); + assertIssue(issues.get(15), documentName, 32, 4, 32, 15, "ballerina:10", 10, + SELF_ASSIGNMENT, RuleKind.CODE_SMELL); + assertIssue(issues.get(16), documentName, 33, 4, 33, 15, "ballerina:10", 10, + SELF_ASSIGNMENT, RuleKind.CODE_SMELL); + assertIssue(issues.get(17), documentName, 34, 4, 34, 15, "ballerina:10", 10, + SELF_ASSIGNMENT, RuleKind.CODE_SMELL); + assertIssue(issues.get(18), documentName, 35, 4, 35, 15, "ballerina:10", 10, + SELF_ASSIGNMENT, RuleKind.CODE_SMELL); + assertIssue(issues.get(19), documentName, 36, 4, 36, 16, "ballerina:10", 10, + SELF_ASSIGNMENT, RuleKind.CODE_SMELL); + assertIssue(issues.get(20), documentName, 37, 4, 37, 16, "ballerina:10", 10, + SELF_ASSIGNMENT, RuleKind.CODE_SMELL); + assertIssue(issues.get(21), documentName, 38, 4, 38, 17, "ballerina:10", 10, + SELF_ASSIGNMENT, RuleKind.CODE_SMELL); + assertIssue(issues.get(22), documentName, 62, 4, 62, 20, "ballerina:10", 10, + SELF_ASSIGNMENT, RuleKind.CODE_SMELL); + assertIssue(issues.get(23), documentName, 63, 4, 63, 21, "ballerina:10", 10, + SELF_ASSIGNMENT, RuleKind.CODE_SMELL); + assertIssue(issues.get(24), documentName, 64, 4, 64, 21, "ballerina:10", 10, + SELF_ASSIGNMENT, RuleKind.CODE_SMELL); + assertIssue(issues.get(25), documentName, 65, 4, 65, 21, "ballerina:10", 10, + SELF_ASSIGNMENT, RuleKind.CODE_SMELL); + assertIssue(issues.get(26), documentName, 66, 4, 66, 21, "ballerina:10", 10, + SELF_ASSIGNMENT, RuleKind.CODE_SMELL); + assertIssue(issues.get(27), documentName, 67, 4, 67, 21, "ballerina:10", 10, + SELF_ASSIGNMENT, RuleKind.CODE_SMELL); + assertIssue(issues.get(28), documentName, 68, 4, 68, 21, "ballerina:10", 10, + SELF_ASSIGNMENT, RuleKind.CODE_SMELL); + assertIssue(issues.get(29), documentName, 69, 4, 69, 21, "ballerina:10", 10, + SELF_ASSIGNMENT, RuleKind.CODE_SMELL); + assertIssue(issues.get(30), documentName, 70, 4, 70, 22, "ballerina:10", 10, + SELF_ASSIGNMENT, RuleKind.CODE_SMELL); + assertIssue(issues.get(31), documentName, 71, 4, 71, 22, "ballerina:10", 10, + SELF_ASSIGNMENT, RuleKind.CODE_SMELL); + assertIssue(issues.get(32), documentName, 72, 4, 72, 23, "ballerina:10", 10, + SELF_ASSIGNMENT, RuleKind.CODE_SMELL); + + } +} diff --git a/scan-command/src/test/resources/command-outputs/unix/list-rules-output.txt b/scan-command/src/test/resources/command-outputs/unix/list-rules-output.txt index 6dea19c..dd47e97 100644 --- a/scan-command/src/test/resources/command-outputs/unix/list-rules-output.txt +++ b/scan-command/src/test/resources/command-outputs/unix/list-rules-output.txt @@ -1,12 +1,16 @@ Loading scan tool configurations from src/test/resources/test-resources/bal-project-with-config-file/Scan.toml - RuleID | Rule Kind | Rule Description - ------------------------------------------------------------------------------------------------ + RuleID | Rule Kind | Rule Description + --------------------------------------------------------------------------------------------------------------------- ballerina:1 | CODE_SMELL | Avoid checkpanic ballerina:2 | CODE_SMELL | Unused function parameter ballerina:3 | CODE_SMELL | Non isolated public function ballerina:4 | CODE_SMELL | Non isolated public method ballerina:5 | CODE_SMELL | Non isolated public class ballerina:6 | CODE_SMELL | Non isolated public object + ballerina:7 | CODE_SMELL | This operation always evaluates to true + ballerina:8 | CODE_SMELL | This operation always evaluates to false + ballerina:9 | CODE_SMELL | This operation always evaluates to the same value + ballerina:10 | CODE_SMELL | This variable is assigned to itself ballerina/example_module_static_code_analyzer:1 | CODE_SMELL | rule 1 ballerina/example_module_static_code_analyzer:2 | BUG | rule 2 ballerina/example_module_static_code_analyzer:3 | VULNERABILITY | rule 3 diff --git a/scan-command/src/test/resources/command-outputs/unix/print-rules-to-console.txt b/scan-command/src/test/resources/command-outputs/unix/print-rules-to-console.txt index 6dea19c..dd47e97 100644 --- a/scan-command/src/test/resources/command-outputs/unix/print-rules-to-console.txt +++ b/scan-command/src/test/resources/command-outputs/unix/print-rules-to-console.txt @@ -1,12 +1,16 @@ Loading scan tool configurations from src/test/resources/test-resources/bal-project-with-config-file/Scan.toml - RuleID | Rule Kind | Rule Description - ------------------------------------------------------------------------------------------------ + RuleID | Rule Kind | Rule Description + --------------------------------------------------------------------------------------------------------------------- ballerina:1 | CODE_SMELL | Avoid checkpanic ballerina:2 | CODE_SMELL | Unused function parameter ballerina:3 | CODE_SMELL | Non isolated public function ballerina:4 | CODE_SMELL | Non isolated public method ballerina:5 | CODE_SMELL | Non isolated public class ballerina:6 | CODE_SMELL | Non isolated public object + ballerina:7 | CODE_SMELL | This operation always evaluates to true + ballerina:8 | CODE_SMELL | This operation always evaluates to false + ballerina:9 | CODE_SMELL | This operation always evaluates to the same value + ballerina:10 | CODE_SMELL | This variable is assigned to itself ballerina/example_module_static_code_analyzer:1 | CODE_SMELL | rule 1 ballerina/example_module_static_code_analyzer:2 | BUG | rule 2 ballerina/example_module_static_code_analyzer:3 | VULNERABILITY | rule 3 diff --git a/scan-command/src/test/resources/command-outputs/windows/list-rules-output.txt b/scan-command/src/test/resources/command-outputs/windows/list-rules-output.txt index 7fd737b..346c9e3 100644 --- a/scan-command/src/test/resources/command-outputs/windows/list-rules-output.txt +++ b/scan-command/src/test/resources/command-outputs/windows/list-rules-output.txt @@ -1,12 +1,16 @@ Loading scan tool configurations from src\test\resources\test-resources\bal-project-with-config-file\Scan.toml - RuleID | Rule Kind | Rule Description - ------------------------------------------------------------------------------------------------ + RuleID | Rule Kind | Rule Description + --------------------------------------------------------------------------------------------------------------------- ballerina:1 | CODE_SMELL | Avoid checkpanic ballerina:2 | CODE_SMELL | Unused function parameter ballerina:3 | CODE_SMELL | Non isolated public function ballerina:4 | CODE_SMELL | Non isolated public method ballerina:5 | CODE_SMELL | Non isolated public class ballerina:6 | CODE_SMELL | Non isolated public object + ballerina:7 | CODE_SMELL | This operation always evaluates to true + ballerina:8 | CODE_SMELL | This operation always evaluates to false + ballerina:9 | CODE_SMELL | This operation always evaluates to the same value + ballerina:10 | CODE_SMELL | This variable is assigned to itself ballerina/example_module_static_code_analyzer:1 | CODE_SMELL | rule 1 ballerina/example_module_static_code_analyzer:2 | BUG | rule 2 ballerina/example_module_static_code_analyzer:3 | VULNERABILITY | rule 3 diff --git a/scan-command/src/test/resources/command-outputs/windows/print-rules-to-console.txt b/scan-command/src/test/resources/command-outputs/windows/print-rules-to-console.txt index 7fd737b..346c9e3 100644 --- a/scan-command/src/test/resources/command-outputs/windows/print-rules-to-console.txt +++ b/scan-command/src/test/resources/command-outputs/windows/print-rules-to-console.txt @@ -1,12 +1,16 @@ Loading scan tool configurations from src\test\resources\test-resources\bal-project-with-config-file\Scan.toml - RuleID | Rule Kind | Rule Description - ------------------------------------------------------------------------------------------------ + RuleID | Rule Kind | Rule Description + --------------------------------------------------------------------------------------------------------------------- ballerina:1 | CODE_SMELL | Avoid checkpanic ballerina:2 | CODE_SMELL | Unused function parameter ballerina:3 | CODE_SMELL | Non isolated public function ballerina:4 | CODE_SMELL | Non isolated public method ballerina:5 | CODE_SMELL | Non isolated public class ballerina:6 | CODE_SMELL | Non isolated public object + ballerina:7 | CODE_SMELL | This operation always evaluates to true + ballerina:8 | CODE_SMELL | This operation always evaluates to false + ballerina:9 | CODE_SMELL | This operation always evaluates to the same value + ballerina:10 | CODE_SMELL | This variable is assigned to itself ballerina/example_module_static_code_analyzer:1 | CODE_SMELL | rule 1 ballerina/example_module_static_code_analyzer:2 | BUG | rule 2 ballerina/example_module_static_code_analyzer:3 | VULNERABILITY | rule 3 diff --git a/scan-command/src/test/resources/test-resources/core-rules/rule009_self_assignment.bal b/scan-command/src/test/resources/test-resources/core-rules/rule009_self_assignment.bal new file mode 100644 index 0000000..e15a65e --- /dev/null +++ b/scan-command/src/test/resources/test-resources/core-rules/rule009_self_assignment.bal @@ -0,0 +1,79 @@ +function testSimpleVariableReference() { + int a = 1; + int a2 = 1; + string|int a3 = 1; + + a = a; // warning + a += a; // warning + a -= a; // warning + a *= a; // warning + a /= a; // warning + a &= a; // warning + a |= a; // warning + a ^= a; // warning + a <<= a; // warning + a >>= a; // warning + a >>>= a; // warning + + a = a2; + a3 = "a3"; + + a += a2; + a += 1; +} + +function testFieldAccessVariableReference() { + A a = new; + A b = new; + + a.a = a.a; // warning + a.a += a.a; // warning + a.a -= a.a; // warning + a.a *= a.a; // warning + a.a /= a.a; // warning + a.a &= a.a; // warning + a.a |= a.a; // warning + a.a ^= a.a; // warning + a.a <<= a.a; // warning + a.a >>= a.a; // warning + a.a >>>= a.a; // warning + + a.a = b.a; + a.a3 = "a.a3"; + a.a += 1; + a.a += a.a4; +} + +class A { + int a = 3; + boolean b = false; + string c = "string"; + int|string a3 = 3; + int a4 = 3; +} + +function test2(any c) { + _ = c; +} + +function t() { + map a = {}; + map b = {}; + + a["a"] = a["a"]; // warning + a["a"] += a["a"]; // warning + a["a"] -= a["a"]; // warning + a["a"] *= a["a"]; // warning + a["a"] /= a["a"]; // warning + a["a"] &= a["a"]; // warning + a["a"] |= a["a"]; // warning + a["a"] ^= a["a"]; // warning + a["a"] <<= a["a"]; // warning + a["a"] >>= a["a"]; // warning + a["a"] >>>= a["a"]; // warning + + a["a"] = b["a"]; + a.["a3"] = "a.[\"a3\"]"; + a.["a"] += 1; + a.["a"] += a.["a4"]; +} \ No newline at end of file diff --git a/scan-command/src/test/resources/test-resources/core-rules/rule_007_always_true.bal b/scan-command/src/test/resources/test-resources/core-rules/rule_007_always_true.bal new file mode 100644 index 0000000..6e7fcb8 --- /dev/null +++ b/scan-command/src/test/resources/test-resources/core-rules/rule_007_always_true.bal @@ -0,0 +1,128 @@ +import ballerina/lang.'int as i; + +function testSimpleVariableReference() { + int a = 1; + int a2 = 1; + boolean b = true; + boolean b2 = true; + string s = "string"; + A a = new; + A b = new; + int i = 3; + int SIGNED8_MIN_VALUE = 10; + map a = {}; + map b = {}; + + test2(a <= a); // warning + test2(a >= a); // warning + test2(a == a); // warning + test2(a === a); // warning + test2(a.a <= a.a); // warning + test2(a.a >= a.a); // warning + test2(a.a == a.a); // warning + test2(a.a === a.a); // warning + test2(i:SIGNED8_MIN_VALUE <= i:SIGNED8_MIN_VALUE); // warning + test2(i:SIGNED8_MIN_VALUE >= i:SIGNED8_MIN_VALUE); // warning + test2(i:SIGNED8_MIN_VALUE == i:SIGNED8_MIN_VALUE); // warning + test2(i:SIGNED8_MIN_VALUE === i:SIGNED8_MIN_VALUE); // warning + test2(a["a"] <= a["a"]); // warning + test2(a["a"] >= a["a"]); // warning + test2(a["a"] == a["a"]); // warning + test2(a["a"] === a["a"]); // warning + result = x >= int:MIN_VALUE; // warning + result = x <= int:MAX_VALUE; // warning + result = y <= float:Infinity; // warning + result = b || true; // warning + result2 = x | -1;// warning + + test2(a <= a2); + test2(b2 || b); + test2(s == "string"); + test2(a.a <= b.a); + test2(a.b && b.b); + test2(a.c == "a.c"); + + test2(SIGNED8_MIN_VALUE <= i:SIGNED8_MIN_VALUE); + test2(i <= i:SIGNED8_MIN_VALUE); + + test2(a["a"] <= b["a"]); + test2(a["a"] || b["a"]); + test2(a["a"] == "b[\"a\"]"); + + test2(a["a"] <= a["b"]); + test2(a["a"] || a["b"]); + test2(a["a"] == "a[\"b\"]"); +} + +class A { + int a = 3; + boolean b = false; + string c = "string"; +} + +function test2(any c) { + _ = c; +} + +function testOperators() { + int x = 1; + float y = 2.3f; + boolean result; +} + +function testRelationaOperatorsWithoutWarnings() { + string x = "1"; + string y = "2.3f"; + boolean result; + + // Arithmetic operators + result = x < "int:MIN_VALUE"; + result = x >= "int:MIN_VALUE"; + + result = x <= "int:MAX_VALUE"; + result = x > "int:MAX_VALUE"; + + result = y <= "float:Infinity"; + result = y > "float:Infinity"; + + // Logical operators + boolean 'false = false; + boolean 'true = true; + boolean b = true; + + result = b && 'false; + result = b || 'true; + result = b && 'true; + result = b || 'false; + + // Bitwise operators + int '0 = 0; + int \-1 = -1; + int x2 = 1; + + int result2 = x2 | '0; + result2 = x2 & \-1; + result2 = x2 | \-1; + result2 = x2 & '0; + result2 = x2 | 1; + result2 = x2 & 1; + + + int x = 1; + float y = 2.3f; + boolean result; + + // Arithmetic operators + result = x > int:MIN_VALUE; + result = x <= int:MIN_VALUE; + + result = x >= int:MAX_VALUE; + result = x < int:MAX_VALUE; + + result = y >= float:Infinity; + result = y < float:Infinity; + + // Bitwise operators + int result2 = x | 1; + result2 = x & --1; +} diff --git a/scan-command/src/test/resources/test-resources/core-rules/rule_008_always_false.bal b/scan-command/src/test/resources/test-resources/core-rules/rule_008_always_false.bal new file mode 100644 index 0000000..fd2ea5d --- /dev/null +++ b/scan-command/src/test/resources/test-resources/core-rules/rule_008_always_false.bal @@ -0,0 +1,126 @@ +import ballerina/lang.'int as i; + +function testSimpleVariableReference() { + int a = 1; + int a2 = 1; + boolean b = true; + boolean b2 = true; + string s = "string"; + A a = new; + A b = new; + int i = 3; + int SIGNED8_MIN_VALUE = 10; + map a = { + "a": 1 + }; + map b = {}; + + test2(a != a); // warning + test2(a < a); // warning + test2(a > a); // warning + test2(a !== a); // warning + test2(a.a != a.a); // warning + test2(a.a < a.a); // warning + test2(a.a > a.a); // warning + test2(a.a !== a.a); // warning + test2(i:SIGNED8_MIN_VALUE != i:SIGNED8_MIN_VALUE); // warning + test2(i:SIGNED8_MIN_VALUE < i:SIGNED8_MIN_VALUE); // warning + test2(i:SIGNED8_MIN_VALUE > i:SIGNED8_MIN_VALUE); // warning + test2(i:SIGNED8_MIN_VALUE !== i:SIGNED8_MIN_VALUE); // warning + test2(a["a"] != a["a"]); // warning + test2(a["a"] < a["a"]); // warning + test2(a["a"] > a["a"]); // warning + test2(a["a"] !== a["a"]); // warning + result = x < int:MIN_VALUE; // warning + result = x > int:MAX_VALUE; // warning + result = y > float:Infinity; // warning + result = b && false; // warning + result2 = x & 0; // warning + + test2(a <= a2); + test2(b2 || b); + test2(s == "string"); + + test2(a.a <= b.a); + test2(a.b && b.b); + test2(a.c == "a.c"); + + test2(SIGNED8_MIN_VALUE <= i:SIGNED8_MIN_VALUE); + test2(i <= i:SIGNED8_MIN_VALUE); + + test2(a["a"] <= b["a"]); + test2(a["a"] || b["a"]); + test2(a["a"] == "b[\"a\"]"); + + test2(a["a"] <= a["b"]); + test2(a["a"] || a["b"]); + test2(a["a"] == "a[\"b\"]"); +} + +class A { + int a = 3; + boolean b = false; + string c = "string"; +} + +function test2(any c) { + _ = c; +} + +function testRelationaOperatorsWithoutWarnings() { + string x = "1"; + string y = "2.3f"; + boolean result; + + // Arithmetic operators + result = x < "int:MIN_VALUE"; + result = x >= "int:MIN_VALUE"; + + result = x <= "int:MAX_VALUE"; + result = x > "int:MAX_VALUE"; + + result = y <= "float:Infinity"; + result = y > "float:Infinity"; + + // Logical operators + boolean 'false = false; + boolean 'true = true; + boolean b = true; + + result = b && 'false; + result = b || 'true; + result = b && 'true; + result = b || 'false; + + // Bitwise operators + int '0 = 0; + int \-1 = -1; + int x2 = 1; + + int result2 = x2 | '0; + result2 = x2 & \-1; + result2 = x2 | \-1; + result2 = x2 & '0; + result2 = x2 | 1; + result2 = x2 & 1; +} + +function testRelationaOperatorsWithoutWarnings2() { + int x = 1; + float y = 2.3f; + boolean result; + + // Arithmetic operators + result = x > int:MIN_VALUE; + result = x <= int:MIN_VALUE; + + result = x >= int:MAX_VALUE; + result = x < int:MAX_VALUE; + + result = y >= float:Infinity; + result = y < float:Infinity; + + // Bitwise operators + int result2 = x | 1; + result2 = x & --1; +} diff --git a/scan-command/src/test/resources/test-resources/core-rules/rule_009_evaluates_same_value.bal b/scan-command/src/test/resources/test-resources/core-rules/rule_009_evaluates_same_value.bal new file mode 100644 index 0000000..7ec1b95 --- /dev/null +++ b/scan-command/src/test/resources/test-resources/core-rules/rule_009_evaluates_same_value.bal @@ -0,0 +1,126 @@ +import ballerina/lang.'int as i; + +function testSimpleVariableReference() { + + int a = 1; + int a2 = 1; + boolean b = true; + boolean b2 = true; + string s = "string"; + A a = new; + A b = new; + int i = 3; + int SIGNED8_MIN_VALUE = 10; + map a = {}; + map b = {}; + + test2(a & a); // warning + test2(a | a); // warning + test2(b && b); // warning + test2(b || b); // warning + test2(a.a & a.a); // warning + test2(a.a | a.a); // warning + test2(a.b && a.b); // warning + test2(a.b || a.b); // warning + test2(i:SIGNED8_MIN_VALUE & i:SIGNED8_MIN_VALUE); // warning + test2(i:SIGNED8_MIN_VALUE | i:SIGNED8_MIN_VALUE); // warning + test2(a["a"] & a["a"]); // warning + test2(a["a"] | a["a"]); // warning + test2(b["a"] && b["a"]); // warning + test2(b["a"] || b["a"]); // warning + result = b && true; // warning + result = b || false; // warning + int result2 = x | 0;// warning + result2 = x & -1; // warning + + test2(a <= a2); + test2(b2 || b); + test2(s == "string"); + test2(a.a <= b.a); + test2(a.b && b.b); + test2(a.c == "a.c"); + + test2(SIGNED8_MIN_VALUE <= i:SIGNED8_MIN_VALUE); + test2(i <= i:SIGNED8_MIN_VALUE); + + test2(a["a"] <= b["a"]); + test2(a["a"] || b["a"]); + test2(a["a"] == "b[\"a\"]"); + + test2(a["a"] <= a["b"]); + test2(a["a"] || a["b"]); + test2(a["a"] == "a[\"b\"]"); +} + +class A { + int a = 3; + boolean b = false; + string c = "string"; +} + +function test2(any c) { + _ = c; +} + +function testOperators() { + int x = 1; + float y = 2.3f; + boolean result; +} + +function testRelationaOperatorsWithoutWarnings() { + string x = "1"; + string y = "2.3f"; + boolean result; + + // Arithmetic operators + result = x < "int:MIN_VALUE"; + result = x >= "int:MIN_VALUE"; + + result = x <= "int:MAX_VALUE"; + result = x > "int:MAX_VALUE"; + + result = y <= "float:Infinity"; + result = y > "float:Infinity"; + + // Logical operators + boolean 'false = false; + boolean 'true = true; + boolean b = true; + + result = b && 'false; + result = b || 'true; + result = b && 'true; + result = b || 'false; + + // Bitwise operators + int '0 = 0; + int \-1 = -1; + int x2 = 1; + + int result2 = x2 | '0; + result2 = x2 & \-1; + result2 = x2 | \-1; + result2 = x2 & '0; + result2 = x2 | 1; + result2 = x2 & 1; + + + int x = 1; + float y = 2.3f; + boolean result; + + // Arithmetic operators + result = x > int:MIN_VALUE; + result = x <= int:MIN_VALUE; + + result = x >= int:MAX_VALUE; + result = x < int:MAX_VALUE; + + result = y >= float:Infinity; + result = y < float:Infinity; + + // Bitwise operators + int result2 = x | 1; + result2 = x & --1; +} diff --git a/scan-command/src/test/resources/test-resources/core-rules/self_comparison_rule.bal b/scan-command/src/test/resources/test-resources/core-rules/self_comparison_rule.bal new file mode 100644 index 0000000..db9f54c --- /dev/null +++ b/scan-command/src/test/resources/test-resources/core-rules/self_comparison_rule.bal @@ -0,0 +1,103 @@ +import ballerina/lang.'int as i; + +function testSimpleVariableReference() { + int a = 1; + int a2 = 1; + boolean b = true; + boolean b2 = true; + string s = "string"; + + test2(a <= a); // warning + test2(a >= a); // warning + test2(a == a); // warning + test2(a != a); // warning + test2(a < a); // warning + test2(a > a); // warning + test2(a === a); // warning + test2(a !== a); // warning + test2(a & a); // warning + test2(a | a); // warning + test2(b && b); // warning + test2(b || b); // warning + + test2(a <= a2); + test2(b2 || b); + test2(s == "string"); +} + +function testFieldAccessVariableReference() { + A a = new; + A b = new; + + test2(a.a <= a.a); // warning + test2(a.a >= a.a); // warning + test2(a.a == a.a); // warning + test2(a.a != a.a); // warning + test2(a.a < a.a); // warning + test2(a.a > a.a); // warning + test2(a.a === a.a); // warning + test2(a.a !== a.a); // warning + test2(a.a & a.a); // warning + test2(a.a | a.a); // warning + test2(a.b && a.b); // warning + test2(a.b || a.b); // warning + + test2(a.a <= b.a); + test2(a.b && b.b); + test2(a.c == "a.c"); +} + +function testQualifiedVariableReference() { + int i = 3; + int SIGNED8_MIN_VALUE = 10; + + test2(i:SIGNED8_MIN_VALUE <= i:SIGNED8_MIN_VALUE); // warning + test2(i:SIGNED8_MIN_VALUE >= i:SIGNED8_MIN_VALUE); // warning + test2(i:SIGNED8_MIN_VALUE == i:SIGNED8_MIN_VALUE); // warning + test2(i:SIGNED8_MIN_VALUE != i:SIGNED8_MIN_VALUE); // warning + test2(i:SIGNED8_MIN_VALUE < i:SIGNED8_MIN_VALUE); // warning + test2(i:SIGNED8_MIN_VALUE > i:SIGNED8_MIN_VALUE); // warning + test2(i:SIGNED8_MIN_VALUE === i:SIGNED8_MIN_VALUE); // warning + test2(i:SIGNED8_MIN_VALUE !== i:SIGNED8_MIN_VALUE); // warning + test2(i:SIGNED8_MIN_VALUE & i:SIGNED8_MIN_VALUE); // warning + test2(i:SIGNED8_MIN_VALUE | i:SIGNED8_MIN_VALUE); // warning + + test2(SIGNED8_MIN_VALUE <= i:SIGNED8_MIN_VALUE); + test2(i <= i:SIGNED8_MIN_VALUE); +} + +function testIndexedExpression() { + map a = {}; + map b = {}; + + test2(a["a"] <= a["a"]); // warning + test2(a["a"] >= a["a"]); // warning + test2(a["a"] == a["a"]); // warning + test2(a["a"] != a["a"]); // warning + test2(a["a"] < a["a"]); // warning + test2(a["a"] > a["a"]); // warning + test2(a["a"] === a["a"]); // warning + test2(a["a"] !== a["a"]); // warning + test2(a["a"] & a["a"]); // warning + test2(a["a"] | a["a"]); // warning + test2(b["a"] && b["a"]); // warning + test2(b["a"] || b["a"]); // warning + + test2(a["a"] <= b["a"]); + test2(a["a"] || b["a"]); + test2(a["a"] == "b[\"a\"]"); + + test2(a["a"] <= a["b"]); + test2(a["a"] || a["b"]); + test2(a["a"] == "a[\"b\"]"); +} + +class A { + int a = 3; + boolean b = false; + string c = "string"; +} + +function test2(any c) { + _ = c; +} \ No newline at end of file diff --git a/scan-command/src/test/resources/test-resources/core-rules/trivial_operations.bal b/scan-command/src/test/resources/test-resources/core-rules/trivial_operations.bal new file mode 100644 index 0000000..954ebf0 --- /dev/null +++ b/scan-command/src/test/resources/test-resources/core-rules/trivial_operations.bal @@ -0,0 +1,86 @@ +function testOperators() { + int x = 1; + float y = 2.3f; + boolean result; + + // Arithmetic operators + result = x < int:MIN_VALUE; // warning + result = x >= int:MIN_VALUE; // warning + + result = x <= int:MAX_VALUE; // warning + result = x > int:MAX_VALUE; // warning + + result = y <= float:Infinity; // warning + result = y > float:Infinity; // warning + + // Logical operators + boolean b = true; + result = b && false; // warning + result = b || true; // warning + result = b && true; // warning + result = b || false; // warning + + // Bitwise operators + int result2 = x | 0;// warning + result2 = x & -1; // warning + result2 = x | -1;// warning + result2 = x & 0; // warning +} + +function testRelationaOperatorsWithoutWarnings() { + string x = "1"; + string y = "2.3f"; + boolean result; + + // Arithmetic operators + result = x < "int:MIN_VALUE"; + result = x >= "int:MIN_VALUE"; + + result = x <= "int:MAX_VALUE"; + result = x > "int:MAX_VALUE"; + + result = y <= "float:Infinity"; + result = y > "float:Infinity"; + + // Logical operators + boolean 'false = false; + boolean 'true = true; + boolean b = true; + + result = b && 'false; + result = b || 'true; + result = b && 'true; + result = b || 'false; + + // Bitwise operators + int '0 = 0; + int \-1 = -1; + int x2 = 1; + + int result2 = x2 | '0; + result2 = x2 & \-1; + result2 = x2 | \-1; + result2 = x2 & '0; + result2 = x2 | 1; + result2 = x2 & 1; +} + +function testRelationaOperatorsWithoutWarnings2() { + int x = 1; + float y = 2.3f; + boolean result; + + // Arithmetic operators + result = x > int:MIN_VALUE; + result = x <= int:MIN_VALUE; + + result = x >= int:MAX_VALUE; + result = x < int:MAX_VALUE; + + result = y >= float:Infinity; + result = y < float:Infinity; + + // Bitwise operators + int result2 = x | 1; + result2 = x & --1; +} diff --git a/scan-command/src/test/resources/testng.xml b/scan-command/src/test/resources/testng.xml index 1546574..6a42a0a 100644 --- a/scan-command/src/test/resources/testng.xml +++ b/scan-command/src/test/resources/testng.xml @@ -31,6 +31,10 @@ under the License. + + + +