
org.sonarsource.slang.checks.utils.ExpressionUtils Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of slang-checks Show documentation
Show all versions of slang-checks Show documentation
SonarSource Language analyzer
/*
* SonarSource SLang
* Copyright (C) 2018-2024 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the Sonar Source-Available License Version 1, as published by SonarSource SA.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the Sonar Source-Available License for more details.
*
* You should have received a copy of the Sonar Source-Available License
* along with this program; if not, see https://sonarsource.com/license/ssal/
*/
package org.sonarsource.slang.checks.utils;
import java.util.Arrays;
import java.util.Deque;
import java.util.List;
import java.util.Optional;
import org.sonarsource.slang.api.BinaryExpressionTree;
import org.sonarsource.slang.api.BlockTree;
import org.sonarsource.slang.api.ExceptionHandlingTree;
import org.sonarsource.slang.api.IdentifierTree;
import org.sonarsource.slang.api.IfTree;
import org.sonarsource.slang.api.LiteralTree;
import org.sonarsource.slang.api.LoopTree;
import org.sonarsource.slang.api.MatchCaseTree;
import org.sonarsource.slang.api.MemberSelectTree;
import org.sonarsource.slang.api.ParenthesizedExpressionTree;
import org.sonarsource.slang.api.PlaceHolderTree;
import org.sonarsource.slang.api.TopLevelTree;
import org.sonarsource.slang.api.Tree;
import org.sonarsource.slang.api.UnaryExpressionTree;
import static org.sonarsource.slang.api.BinaryExpressionTree.Operator.CONDITIONAL_AND;
import static org.sonarsource.slang.api.BinaryExpressionTree.Operator.CONDITIONAL_OR;
public class ExpressionUtils {
private static final String TRUE_LITERAL = "true";
private static final String FALSE_LITERAL = "false";
private static final List BOOLEAN_LITERALS = Arrays.asList(TRUE_LITERAL, FALSE_LITERAL);
private ExpressionUtils() {
}
public static boolean isBooleanLiteral(Tree tree) {
return tree instanceof LiteralTree && BOOLEAN_LITERALS.contains(((LiteralTree) tree).value());
}
public static boolean isFalseValueLiteral(Tree originalTree) {
Tree tree = skipParentheses(originalTree);
return (tree instanceof LiteralTree && FALSE_LITERAL.equals(((LiteralTree) tree).value()))
|| (isNegation(tree) && isTrueValueLiteral(((UnaryExpressionTree) tree).operand()));
}
public static boolean isTrueValueLiteral(Tree originalTree) {
Tree tree = skipParentheses(originalTree);
return (tree instanceof LiteralTree && TRUE_LITERAL.equals(((LiteralTree) tree).value()))
|| (isNegation(tree) && isFalseValueLiteral(((UnaryExpressionTree) tree).operand()));
}
public static boolean isNegation(Tree tree) {
return tree instanceof UnaryExpressionTree && ((UnaryExpressionTree) tree).operator() == UnaryExpressionTree.Operator.NEGATE;
}
public static boolean isBinaryOperation(Tree tree, BinaryExpressionTree.Operator operator) {
return tree instanceof BinaryExpressionTree && ((BinaryExpressionTree) tree).operator() == operator;
}
public static boolean isLogicalBinaryExpression(Tree tree) {
return isBinaryOperation(tree, CONDITIONAL_AND) || isBinaryOperation(tree, CONDITIONAL_OR);
}
public static Tree skipParentheses(Tree tree) {
Tree result = tree;
while (result instanceof ParenthesizedExpressionTree) {
result = ((ParenthesizedExpressionTree) result).expression();
}
return result;
}
public static boolean containsPlaceHolder(Tree tree) {
return tree.descendants().anyMatch(PlaceHolderTree.class::isInstance);
}
public static boolean isTernaryOperator(Deque ancestors, Tree tree) {
if (!isIfWithElse(tree)) {
return false;
}
Tree child = tree;
for (Tree ancestor : ancestors) {
if (ancestor instanceof BlockTree || ancestor instanceof ExceptionHandlingTree || ancestor instanceof TopLevelTree ||
isBranchOfLoopOrCaseOrIfWithoutElse(ancestor, child)) {
break;
}
if (!isBranchOfIf(ancestor, child)) {
return tree.descendants().noneMatch(BlockTree.class::isInstance);
}
child = ancestor;
}
return false;
}
private static boolean isIfWithElse(Tree tree) {
return tree instanceof IfTree && ((IfTree) tree).elseBranch() != null;
}
private static boolean isBranchOfLoopOrCaseOrIfWithoutElse(Tree parent, Tree child) {
return (parent instanceof LoopTree && child == ((LoopTree) parent).body()) ||
(parent instanceof MatchCaseTree && child == ((MatchCaseTree) parent).body()) ||
(isBranchOfIf(parent, child) && ((IfTree) parent).elseBranch() == null);
}
private static boolean isBranchOfIf(Tree parent, Tree child) {
if (parent instanceof IfTree) {
IfTree ifTree = (IfTree) parent;
return child == ifTree.thenBranch() || child == ifTree.elseBranch();
}
return false;
}
public static Optional getMemberSelectOrIdentifierName(Tree tree) {
if (tree instanceof IdentifierTree) {
return Optional.of(((IdentifierTree) tree).name());
} else if (tree instanceof MemberSelectTree) {
return Optional.of(((MemberSelectTree)tree).identifier().name());
} else {
return Optional.empty();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy