[analyzer] Remove alpha.core.IdenticalExpr Checker (#114715)
This change removes the alpha.core.IdenticalExpr static analysis checker since it's checks are present in the clang-tidy checks misc-redundant-expression and bugprone-branch-clone. This check was implemented as a static analysis check using AST matching, and since alpha and duplicated in 2 clang-tidy checks may be removed. Co-authored-by: Vince Bridgers <vince.a.bridgers@ericsson.com>
This commit is contained in:
@@ -102,6 +102,212 @@ void BranchCloneCheck::registerMatchers(MatchFinder *Finder) {
|
||||
this);
|
||||
Finder->addMatcher(switchStmt().bind("switch"), this);
|
||||
Finder->addMatcher(conditionalOperator().bind("condOp"), this);
|
||||
Finder->addMatcher(
|
||||
ifStmt((hasThen(hasDescendant(ifStmt())))).bind("ifWithDescendantIf"),
|
||||
this);
|
||||
}
|
||||
|
||||
/// Determines whether two statement trees are identical regarding
|
||||
/// operators and symbols.
|
||||
///
|
||||
/// Exceptions: expressions containing macros or functions with possible side
|
||||
/// effects are never considered identical.
|
||||
/// Limitations: (t + u) and (u + t) are not considered identical.
|
||||
/// t*(u + t) and t*u + t*t are not considered identical.
|
||||
///
|
||||
static bool isIdenticalStmt(const ASTContext &Ctx, const Stmt *Stmt1,
|
||||
const Stmt *Stmt2, bool IgnoreSideEffects) {
|
||||
|
||||
if (!Stmt1 || !Stmt2)
|
||||
return !Stmt1 && !Stmt2;
|
||||
|
||||
// If Stmt1 & Stmt2 are of different class then they are not
|
||||
// identical statements.
|
||||
if (Stmt1->getStmtClass() != Stmt2->getStmtClass())
|
||||
return false;
|
||||
|
||||
const auto *Expr1 = dyn_cast<Expr>(Stmt1);
|
||||
const auto *Expr2 = dyn_cast<Expr>(Stmt2);
|
||||
|
||||
if (Expr1 && Expr2) {
|
||||
// If Stmt1 has side effects then don't warn even if expressions
|
||||
// are identical.
|
||||
if (!IgnoreSideEffects && Expr1->HasSideEffects(Ctx) &&
|
||||
Expr2->HasSideEffects(Ctx))
|
||||
return false;
|
||||
// If either expression comes from a macro then don't warn even if
|
||||
// the expressions are identical.
|
||||
if ((Expr1->getExprLoc().isMacroID()) || (Expr2->getExprLoc().isMacroID()))
|
||||
return false;
|
||||
|
||||
// If all children of two expressions are identical, return true.
|
||||
Expr::const_child_iterator I1 = Expr1->child_begin();
|
||||
Expr::const_child_iterator I2 = Expr2->child_begin();
|
||||
while (I1 != Expr1->child_end() && I2 != Expr2->child_end()) {
|
||||
if (!isIdenticalStmt(Ctx, *I1, *I2, IgnoreSideEffects))
|
||||
return false;
|
||||
++I1;
|
||||
++I2;
|
||||
}
|
||||
// If there are different number of children in the statements, return
|
||||
// false.
|
||||
if (I1 != Expr1->child_end())
|
||||
return false;
|
||||
if (I2 != Expr2->child_end())
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (Stmt1->getStmtClass()) {
|
||||
default:
|
||||
return false;
|
||||
case Stmt::CallExprClass:
|
||||
case Stmt::ArraySubscriptExprClass:
|
||||
case Stmt::ArraySectionExprClass:
|
||||
case Stmt::OMPArrayShapingExprClass:
|
||||
case Stmt::OMPIteratorExprClass:
|
||||
case Stmt::ImplicitCastExprClass:
|
||||
case Stmt::ParenExprClass:
|
||||
case Stmt::BreakStmtClass:
|
||||
case Stmt::ContinueStmtClass:
|
||||
case Stmt::NullStmtClass:
|
||||
return true;
|
||||
case Stmt::CStyleCastExprClass: {
|
||||
const auto *CastExpr1 = cast<CStyleCastExpr>(Stmt1);
|
||||
const auto *CastExpr2 = cast<CStyleCastExpr>(Stmt2);
|
||||
|
||||
return CastExpr1->getTypeAsWritten() == CastExpr2->getTypeAsWritten();
|
||||
}
|
||||
case Stmt::ReturnStmtClass: {
|
||||
const auto *ReturnStmt1 = cast<ReturnStmt>(Stmt1);
|
||||
const auto *ReturnStmt2 = cast<ReturnStmt>(Stmt2);
|
||||
|
||||
return isIdenticalStmt(Ctx, ReturnStmt1->getRetValue(),
|
||||
ReturnStmt2->getRetValue(), IgnoreSideEffects);
|
||||
}
|
||||
case Stmt::ForStmtClass: {
|
||||
const auto *ForStmt1 = cast<ForStmt>(Stmt1);
|
||||
const auto *ForStmt2 = cast<ForStmt>(Stmt2);
|
||||
|
||||
if (!isIdenticalStmt(Ctx, ForStmt1->getInit(), ForStmt2->getInit(),
|
||||
IgnoreSideEffects))
|
||||
return false;
|
||||
if (!isIdenticalStmt(Ctx, ForStmt1->getCond(), ForStmt2->getCond(),
|
||||
IgnoreSideEffects))
|
||||
return false;
|
||||
if (!isIdenticalStmt(Ctx, ForStmt1->getInc(), ForStmt2->getInc(),
|
||||
IgnoreSideEffects))
|
||||
return false;
|
||||
if (!isIdenticalStmt(Ctx, ForStmt1->getBody(), ForStmt2->getBody(),
|
||||
IgnoreSideEffects))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
case Stmt::DoStmtClass: {
|
||||
const auto *DStmt1 = cast<DoStmt>(Stmt1);
|
||||
const auto *DStmt2 = cast<DoStmt>(Stmt2);
|
||||
|
||||
if (!isIdenticalStmt(Ctx, DStmt1->getCond(), DStmt2->getCond(),
|
||||
IgnoreSideEffects))
|
||||
return false;
|
||||
if (!isIdenticalStmt(Ctx, DStmt1->getBody(), DStmt2->getBody(),
|
||||
IgnoreSideEffects))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
case Stmt::WhileStmtClass: {
|
||||
const auto *WStmt1 = cast<WhileStmt>(Stmt1);
|
||||
const auto *WStmt2 = cast<WhileStmt>(Stmt2);
|
||||
|
||||
if (!isIdenticalStmt(Ctx, WStmt1->getCond(), WStmt2->getCond(),
|
||||
IgnoreSideEffects))
|
||||
return false;
|
||||
if (!isIdenticalStmt(Ctx, WStmt1->getBody(), WStmt2->getBody(),
|
||||
IgnoreSideEffects))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
case Stmt::IfStmtClass: {
|
||||
const auto *IStmt1 = cast<IfStmt>(Stmt1);
|
||||
const auto *IStmt2 = cast<IfStmt>(Stmt2);
|
||||
|
||||
if (!isIdenticalStmt(Ctx, IStmt1->getCond(), IStmt2->getCond(),
|
||||
IgnoreSideEffects))
|
||||
return false;
|
||||
if (!isIdenticalStmt(Ctx, IStmt1->getThen(), IStmt2->getThen(),
|
||||
IgnoreSideEffects))
|
||||
return false;
|
||||
if (!isIdenticalStmt(Ctx, IStmt1->getElse(), IStmt2->getElse(),
|
||||
IgnoreSideEffects))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
case Stmt::CompoundStmtClass: {
|
||||
const auto *CompStmt1 = cast<CompoundStmt>(Stmt1);
|
||||
const auto *CompStmt2 = cast<CompoundStmt>(Stmt2);
|
||||
|
||||
if (CompStmt1->size() != CompStmt2->size())
|
||||
return false;
|
||||
|
||||
if (!llvm::all_of(llvm::zip(CompStmt1->body(), CompStmt2->body()),
|
||||
[&Ctx, IgnoreSideEffects](
|
||||
std::tuple<const Stmt *, const Stmt *> stmtPair) {
|
||||
const Stmt *stmt0 = std::get<0>(stmtPair);
|
||||
const Stmt *stmt1 = std::get<1>(stmtPair);
|
||||
return isIdenticalStmt(Ctx, stmt0, stmt1,
|
||||
IgnoreSideEffects);
|
||||
})) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
case Stmt::CompoundAssignOperatorClass:
|
||||
case Stmt::BinaryOperatorClass: {
|
||||
const auto *BinOp1 = cast<BinaryOperator>(Stmt1);
|
||||
const auto *BinOp2 = cast<BinaryOperator>(Stmt2);
|
||||
return BinOp1->getOpcode() == BinOp2->getOpcode();
|
||||
}
|
||||
case Stmt::CharacterLiteralClass: {
|
||||
const auto *CharLit1 = cast<CharacterLiteral>(Stmt1);
|
||||
const auto *CharLit2 = cast<CharacterLiteral>(Stmt2);
|
||||
return CharLit1->getValue() == CharLit2->getValue();
|
||||
}
|
||||
case Stmt::DeclRefExprClass: {
|
||||
const auto *DeclRef1 = cast<DeclRefExpr>(Stmt1);
|
||||
const auto *DeclRef2 = cast<DeclRefExpr>(Stmt2);
|
||||
return DeclRef1->getDecl() == DeclRef2->getDecl();
|
||||
}
|
||||
case Stmt::IntegerLiteralClass: {
|
||||
const auto *IntLit1 = cast<IntegerLiteral>(Stmt1);
|
||||
const auto *IntLit2 = cast<IntegerLiteral>(Stmt2);
|
||||
|
||||
llvm::APInt I1 = IntLit1->getValue();
|
||||
llvm::APInt I2 = IntLit2->getValue();
|
||||
if (I1.getBitWidth() != I2.getBitWidth())
|
||||
return false;
|
||||
return I1 == I2;
|
||||
}
|
||||
case Stmt::FloatingLiteralClass: {
|
||||
const auto *FloatLit1 = cast<FloatingLiteral>(Stmt1);
|
||||
const auto *FloatLit2 = cast<FloatingLiteral>(Stmt2);
|
||||
return FloatLit1->getValue().bitwiseIsEqual(FloatLit2->getValue());
|
||||
}
|
||||
case Stmt::StringLiteralClass: {
|
||||
const auto *StringLit1 = cast<StringLiteral>(Stmt1);
|
||||
const auto *StringLit2 = cast<StringLiteral>(Stmt2);
|
||||
return StringLit1->getBytes() == StringLit2->getBytes();
|
||||
}
|
||||
case Stmt::MemberExprClass: {
|
||||
const auto *MemberStmt1 = cast<MemberExpr>(Stmt1);
|
||||
const auto *MemberStmt2 = cast<MemberExpr>(Stmt2);
|
||||
return MemberStmt1->getMemberDecl() == MemberStmt2->getMemberDecl();
|
||||
}
|
||||
case Stmt::UnaryOperatorClass: {
|
||||
const auto *UnaryOp1 = cast<UnaryOperator>(Stmt1);
|
||||
const auto *UnaryOp2 = cast<UnaryOperator>(Stmt2);
|
||||
return UnaryOp1->getOpcode() == UnaryOp2->getOpcode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BranchCloneCheck::check(const MatchFinder::MatchResult &Result) {
|
||||
@@ -269,6 +475,21 @@ void BranchCloneCheck::check(const MatchFinder::MatchResult &Result) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (const auto *IS = Result.Nodes.getNodeAs<IfStmt>("ifWithDescendantIf")) {
|
||||
const Stmt *Then = IS->getThen();
|
||||
auto CS = dyn_cast<CompoundStmt>(Then);
|
||||
if (CS && (!CS->body_empty())) {
|
||||
const auto *InnerIf = dyn_cast<IfStmt>(*CS->body_begin());
|
||||
if (InnerIf && isIdenticalStmt(Context, IS->getCond(), InnerIf->getCond(),
|
||||
/*IgnoreSideEffects=*/false)) {
|
||||
diag(IS->getBeginLoc(), "if with identical inner if statement");
|
||||
diag(InnerIf->getBeginLoc(), "inner if starts here",
|
||||
DiagnosticIDs::Note);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
llvm_unreachable("No if statement and no switch statement.");
|
||||
}
|
||||
|
||||
|
||||
@@ -855,9 +855,6 @@ static bool areExprsMacroAndNonMacro(const Expr *&LhsExpr,
|
||||
} // namespace
|
||||
|
||||
void RedundantExpressionCheck::registerMatchers(MatchFinder *Finder) {
|
||||
const auto AnyLiteralExpr = ignoringParenImpCasts(
|
||||
anyOf(cxxBoolLiteral(), characterLiteral(), integerLiteral()));
|
||||
|
||||
const auto BannedIntegerLiteral =
|
||||
integerLiteral(expandedByMacro(KnownBannedMacroNames));
|
||||
const auto IsInUnevaluatedContext = expr(anyOf(
|
||||
@@ -866,19 +863,16 @@ void RedundantExpressionCheck::registerMatchers(MatchFinder *Finder) {
|
||||
// Binary with equivalent operands, like (X != 2 && X != 2).
|
||||
Finder->addMatcher(
|
||||
traverse(TK_AsIs,
|
||||
binaryOperator(
|
||||
anyOf(isComparisonOperator(),
|
||||
hasAnyOperatorName("-", "/", "%", "|", "&", "^", "&&",
|
||||
"||", "=")),
|
||||
operandsAreEquivalent(),
|
||||
// Filter noisy false positives.
|
||||
unless(isInTemplateInstantiation()),
|
||||
unless(binaryOperatorIsInMacro()),
|
||||
unless(hasType(realFloatingPointType())),
|
||||
unless(hasEitherOperand(hasType(realFloatingPointType()))),
|
||||
unless(hasLHS(AnyLiteralExpr)),
|
||||
unless(hasDescendant(BannedIntegerLiteral)),
|
||||
unless(IsInUnevaluatedContext))
|
||||
binaryOperator(anyOf(isComparisonOperator(),
|
||||
hasAnyOperatorName("-", "/", "%", "|", "&",
|
||||
"^", "&&", "||", "=")),
|
||||
operandsAreEquivalent(),
|
||||
// Filter noisy false positives.
|
||||
unless(isInTemplateInstantiation()),
|
||||
unless(binaryOperatorIsInMacro()),
|
||||
unless(hasAncestor(arraySubscriptExpr())),
|
||||
unless(hasDescendant(BannedIntegerLiteral)),
|
||||
unless(IsInUnevaluatedContext))
|
||||
.bind("binary")),
|
||||
this);
|
||||
|
||||
@@ -1238,6 +1232,50 @@ void RedundantExpressionCheck::check(const MatchFinder::MatchResult &Result) {
|
||||
if (const auto *BinOp = Result.Nodes.getNodeAs<BinaryOperator>("binary")) {
|
||||
// If the expression's constants are macros, check whether they are
|
||||
// intentional.
|
||||
|
||||
//
|
||||
// Special case for floating-point representation.
|
||||
//
|
||||
// If expressions on both sides of comparison operator are of type float,
|
||||
// then for some comparison operators no warning shall be
|
||||
// reported even if the expressions are identical from a symbolic point of
|
||||
// view. Comparison between expressions, declared variables and literals
|
||||
// are treated differently.
|
||||
//
|
||||
// != and == between float literals that have the same value should NOT
|
||||
// warn. < > between float literals that have the same value SHOULD warn.
|
||||
//
|
||||
// != and == between the same float declaration should NOT warn.
|
||||
// < > between the same float declaration SHOULD warn.
|
||||
//
|
||||
// != and == between eq. expressions that evaluates into float
|
||||
// should NOT warn.
|
||||
// < > between eq. expressions that evaluates into float
|
||||
// should NOT warn.
|
||||
//
|
||||
const Expr *LHS = BinOp->getLHS()->IgnoreParenImpCasts();
|
||||
const Expr *RHS = BinOp->getRHS()->IgnoreParenImpCasts();
|
||||
const BinaryOperator::Opcode Op = BinOp->getOpcode();
|
||||
const bool OpEqualEQorNE = ((Op == BO_EQ) || (Op == BO_NE));
|
||||
|
||||
const auto *DeclRef1 = dyn_cast<DeclRefExpr>(LHS);
|
||||
const auto *DeclRef2 = dyn_cast<DeclRefExpr>(RHS);
|
||||
const auto *FloatLit1 = dyn_cast<FloatingLiteral>(LHS);
|
||||
const auto *FloatLit2 = dyn_cast<FloatingLiteral>(RHS);
|
||||
|
||||
if (DeclRef1 && DeclRef2 &&
|
||||
DeclRef1->getType()->hasFloatingRepresentation() &&
|
||||
DeclRef2->getType()->hasFloatingRepresentation() &&
|
||||
(DeclRef1->getDecl() == DeclRef2->getDecl()) && OpEqualEQorNE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (FloatLit1 && FloatLit2 &&
|
||||
FloatLit1->getValue().bitwiseIsEqual(FloatLit2->getValue()) &&
|
||||
OpEqualEQorNE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (areSidesBinaryConstExpressions(BinOp, Result.Context)) {
|
||||
const Expr *LhsConst = nullptr, *RhsConst = nullptr;
|
||||
BinaryOperatorKind MainOpcode{}, SideOpcode{};
|
||||
|
||||
@@ -156,6 +156,10 @@ Changes in existing checks
|
||||
<clang-tidy/checks/altera/id-dependent-backward-branch>` check by fixing
|
||||
crashes from invalid code.
|
||||
|
||||
- Improved :doc:`bugprone-branch-clone
|
||||
<clang-tidy/checks/bugprone/branch-clone>` check to improve detection of
|
||||
branch clones by now detecting duplicate inner and outer if statements.
|
||||
|
||||
- Improved :doc:`bugprone-casting-through-void
|
||||
<clang-tidy/checks/bugprone/casting-through-void>` check to suggest replacing
|
||||
the offending code with ``reinterpret_cast``, to more clearly express intent.
|
||||
@@ -230,6 +234,11 @@ Changes in existing checks
|
||||
<clang-tidy/checks/misc/definitions-in-headers>` check by rewording the
|
||||
diagnostic note that suggests adding ``inline``.
|
||||
|
||||
- Improved :doc:`misc-redundant-expression
|
||||
<clang-tidy/checks/misc/redundant-expression>` check by extending the
|
||||
checker to detect floating point and integer literals in redundant
|
||||
expressions.
|
||||
|
||||
- Improved :doc:`misc-unconventional-assign-operator
|
||||
<clang-tidy/checks/misc/unconventional-assign-operator>` check to avoid
|
||||
false positive for C++23 deducing this.
|
||||
|
||||
@@ -32,9 +32,28 @@ If this is the intended behavior, then there is no reason to use a conditional
|
||||
statement; otherwise the issue can be solved by fixing the branch that is
|
||||
handled incorrectly.
|
||||
|
||||
The check also detects repeated branches in longer ``if/else if/else`` chains
|
||||
The check detects repeated branches in longer ``if/else if/else`` chains
|
||||
where it would be even harder to notice the problem.
|
||||
|
||||
The check also detects repeated inner and outer ``if`` statements that may
|
||||
be a result of a copy-paste error. This check cannot currently detect
|
||||
identical inner and outer ``if`` statements if code is between the ``if``
|
||||
conditions. An example is as follows.
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
void test_warn_inner_if_1(int x) {
|
||||
if (x == 1) { // warns, if with identical inner if
|
||||
if (x == 1) // inner if is here
|
||||
;
|
||||
if (x == 1) { // does not warn, cannot detect
|
||||
int y = x;
|
||||
if (x == 1)
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
In ``switch`` statements the check only reports repeated branches when they are
|
||||
consecutive, because it is relatively common that the ``case:`` labels have
|
||||
some natural ordering and rearranging them would decrease the readability of
|
||||
|
||||
@@ -23,3 +23,22 @@ Examples:
|
||||
(p->x == p->x) // always true
|
||||
(p->x < p->x) // always false
|
||||
(speed - speed + 1 == 12) // speed - speed is always zero
|
||||
int b = a | 4 | a // identical expr on both sides
|
||||
((x=1) | (x=1)) // expression is identical
|
||||
|
||||
Floats are handled except in the case that NaNs are checked like so:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
int TestFloat(float F) {
|
||||
if (F == F) // Identical float values used
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int TestFloat(float F) {
|
||||
// Testing NaN.
|
||||
if (F != F && F == F) // does not warn
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core.IdenticalExpr -w -verify %s
|
||||
// RUN: clang-tidy %s -checks="-*,misc-redundant-expression" -- 2>&1 | FileCheck %s --check-prefix=CHECK-MESSAGES-IDENTEXPR
|
||||
// RUN: clang-tidy %s -checks="-*,bugprone-branch-clone" -- 2>&1 | FileCheck %s --check-prefix=CHECK-MESSAGES-BUGPRONEBRANCH
|
||||
|
||||
/* Only one expected warning per function allowed at the very end. */
|
||||
|
||||
@@ -65,7 +66,8 @@ int checkNotEqualFloatDeclCompare6(void) {
|
||||
|
||||
int checkNotEqualCastFloatDeclCompare11(void) {
|
||||
float f = 7.1F;
|
||||
return ((int)f != (int)f); // expected-warning {{comparison of identical expressions always evaluates to false}}
|
||||
return ((int)f != (int)f);
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:18: warning: both sides of operator are equivalent [misc-redundant-expression]
|
||||
}
|
||||
int checkNotEqualCastFloatDeclCompare12(void) {
|
||||
float f = 7.1F;
|
||||
@@ -130,7 +132,8 @@ int checkNotEqualNestedBinaryOpFloatCompare3(void) {
|
||||
/* '!=' with int*/
|
||||
|
||||
int checkNotEqualIntLiteralCompare1(void) {
|
||||
return (5 != 5); // expected-warning {{comparison of identical expressions always evaluates to false}}
|
||||
return (5 != 5);
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:13: warning: both sides of operator are equivalent [misc-redundant-expression]
|
||||
}
|
||||
|
||||
int checkNotEqualIntLiteralCompare2(void) {
|
||||
@@ -155,7 +158,8 @@ int checkNotEqualIntDeclCompare4(void) {
|
||||
|
||||
int checkNotEqualCastIntDeclCompare11(void) {
|
||||
int f = 7;
|
||||
return ((int)f != (int)f); // expected-warning {{comparison of identical expressions always evaluates to false}}
|
||||
return ((int)f != (int)f);
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:18: warning: both sides of operator are equivalent [misc-redundant-expression]
|
||||
}
|
||||
int checkNotEqualCastIntDeclCompare12(void) {
|
||||
int f = 7;
|
||||
@@ -166,7 +170,8 @@ int checkNotEqualBinaryOpIntCompare1(void) {
|
||||
int t= 1;
|
||||
int u= 2;
|
||||
int f= 4;
|
||||
res = (f + 4 != f + 4); // expected-warning {{comparison of identical expressions always evaluates to false}}
|
||||
res = (f + 4 != f + 4);
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:16: warning: both sides of operator are equivalent [misc-redundant-expression]
|
||||
return (0);
|
||||
}
|
||||
int checkNotEqualBinaryOpIntCompare2(void) {
|
||||
@@ -181,7 +186,8 @@ int checkNotEqualBinaryOpIntCompare3(void) {
|
||||
int t= 1;
|
||||
int u= 2;
|
||||
int f= 4;
|
||||
res = ((int)f + 4 != (int)f + 4); // expected-warning {{comparison of identical expressions always evaluates to false}}
|
||||
res = ((int)f + 4 != (int)f + 4);
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:21: warning: both sides of operator are equivalent [misc-redundant-expression]
|
||||
return (0);
|
||||
}
|
||||
int checkNotEqualBinaryOpIntCompare4(void) {
|
||||
@@ -196,7 +202,8 @@ int checkNotEqualBinaryOpIntCompare5(void) {
|
||||
int res;
|
||||
int t= 1;
|
||||
int u= 2;
|
||||
res = (u + t != u + t); // expected-warning {{comparison of identical expressions always evaluates to false}}
|
||||
res = (u + t != u + t);
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:16: warning: both sides of operator are equivalent [misc-redundant-expression]
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -205,7 +212,8 @@ int checkNotEqualNestedBinaryOpIntCompare1(void) {
|
||||
int t= 1;
|
||||
int u= 2;
|
||||
int f= 3;
|
||||
res = (((int)f + (3 - u)*t) != ((int)f + (3 - u)*t)); // expected-warning {{comparison of identical expressions always evaluates to false}}
|
||||
res = (((int)f + (3 - u)*t) != ((int)f + (3 - u)*t));
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:31: warning: both sides of operator are equivalent [misc-redundant-expression]
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -223,7 +231,8 @@ int checkNotEqualNestedBinaryOpIntCompare3(void) {
|
||||
int t= 1;
|
||||
int u= 2;
|
||||
int f= 3;
|
||||
res = (((int)f + (u - 3)*t) != ((int)f + (3 - u)*(t + 1 != t + 1))); // expected-warning {{comparison of identical expressions always evaluates to false}}
|
||||
res = (((int)f + (u - 3)*t) != ((int)f + (3 - u)*(t + 1 != t + 1)));
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:59: warning: both sides of operator are equivalent [misc-redundant-expression]
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -252,7 +261,8 @@ int checkNotEqualIntPointerDeclCompare1(void) {
|
||||
int checkNotEqualCastIntPointerDeclCompare11(void) {
|
||||
int k = 7;
|
||||
int* f = &k;
|
||||
return ((int*)f != (int*)f); // expected-warning {{comparison of identical expressions always evaluates to false}}
|
||||
return ((int*)f != (int*)f);
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:19: warning: both sides of operator are equivalent [misc-redundant-expression]
|
||||
}
|
||||
int checkNotEqualCastIntPointerDeclCompare12(void) {
|
||||
int k = 7;
|
||||
@@ -263,7 +273,8 @@ int checkNotEqualBinaryOpIntPointerCompare1(void) {
|
||||
int k = 7;
|
||||
int res;
|
||||
int* f= &k;
|
||||
res = (f + 4 != f + 4); // expected-warning {{comparison of identical expressions always evaluates to false}}
|
||||
res = (f + 4 != f + 4);
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:16: warning: both sides of operator are equivalent [misc-redundant-expression]
|
||||
return (0);
|
||||
}
|
||||
int checkNotEqualBinaryOpIntPointerCompare2(void) {
|
||||
@@ -278,7 +289,8 @@ int checkNotEqualBinaryOpIntPointerCompare3(void) {
|
||||
int k = 7;
|
||||
int res;
|
||||
int* f= &k;
|
||||
res = ((int*)f + 4 != (int*)f + 4); // expected-warning {{comparison of identical expressions always evaluates to false}}
|
||||
res = ((int*)f + 4 != (int*)f + 4);
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:22: warning: both sides of operator are equivalent [misc-redundant-expression]
|
||||
return (0);
|
||||
}
|
||||
int checkNotEqualBinaryOpIntPointerCompare4(void) {
|
||||
@@ -295,7 +307,8 @@ int checkNotEqualNestedBinaryOpIntPointerCompare1(void) {
|
||||
int t= 1;
|
||||
int* u= &k+2;
|
||||
int* f= &k+3;
|
||||
res = ((f + (3)*t) != (f + (3)*t)); // expected-warning {{comparison of identical expressions always evaluates to false}}
|
||||
res = ((f + (3)*t) != (f + (3)*t));
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:22: warning: both sides of operator are equivalent [misc-redundant-expression]
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -358,7 +371,8 @@ int checkEqualIntPointerDeclCompare(void) {
|
||||
int checkEqualIntPointerDeclCompare0(void) {
|
||||
int k = 3;
|
||||
int* f = &k;
|
||||
return (f+1 == f+1); // expected-warning {{comparison of identical expressions always evaluates to true}}
|
||||
return (f+1 == f+1);
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:15: warning: both sides of operator are equivalent [misc-redundant-expression]
|
||||
}
|
||||
|
||||
/* EQ with float*/
|
||||
@@ -410,7 +424,8 @@ int checkEqualFloatDeclCompare6(void) {
|
||||
|
||||
int checkEqualCastFloatDeclCompare11(void) {
|
||||
float f = 7.1F;
|
||||
return ((int)f == (int)f); // expected-warning {{comparison of identical expressions always evaluates to true}}
|
||||
return ((int)f == (int)f);
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:18: warning: both sides of operator are equivalent [misc-redundant-expression]
|
||||
}
|
||||
int checkEqualCastFloatDeclCompare12(void) {
|
||||
float f = 7.1F;
|
||||
@@ -474,7 +489,8 @@ int checkEqualNestedBinaryOpFloatCompare3(void) {
|
||||
/* Equal with int*/
|
||||
|
||||
int checkEqualIntLiteralCompare1(void) {
|
||||
return (5 == 5); // expected-warning {{comparison of identical expressions always evaluates to true}}
|
||||
return (5 == 5);
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:13: warning: both sides of operator are equivalent [misc-redundant-expression]
|
||||
}
|
||||
|
||||
int checkEqualIntLiteralCompare2(void) {
|
||||
@@ -489,7 +505,8 @@ int checkEqualIntDeclCompare1(void) {
|
||||
|
||||
int checkEqualCastIntDeclCompare11(void) {
|
||||
int f = 7;
|
||||
return ((int)f == (int)f); // expected-warning {{comparison of identical expressions always evaluates to true}}
|
||||
return ((int)f == (int)f);
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:18: warning: both sides of operator are equivalent [misc-redundant-expression]
|
||||
}
|
||||
int checkEqualCastIntDeclCompare12(void) {
|
||||
int f = 7;
|
||||
@@ -511,7 +528,8 @@ int checkEqualBinaryOpIntCompare1(void) {
|
||||
int t= 1;
|
||||
int u= 2;
|
||||
int f= 4;
|
||||
res = (f + 4 == f + 4); // expected-warning {{comparison of identical expressions always evaluates to true}}
|
||||
res = (f + 4 == f + 4);
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:16: warning: both sides of operator are equivalent [misc-redundant-expression]
|
||||
return (0);
|
||||
}
|
||||
int checkEqualBinaryOpIntCompare2(void) {
|
||||
@@ -526,7 +544,8 @@ int checkEqualBinaryOpIntCompare3(void) {
|
||||
int t= 1;
|
||||
int u= 2;
|
||||
int f= 4;
|
||||
res = ((int)f + 4 == (int)f + 4); // expected-warning {{comparison of identical expressions always evaluates to true}}
|
||||
res = ((int)f + 4 == (int)f + 4);
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:21: warning: both sides of operator are equivalent [misc-redundant-expression]
|
||||
return (0);
|
||||
|
||||
}
|
||||
@@ -542,7 +561,8 @@ int checkEqualBinaryOpIntCompare5(void) {
|
||||
int res;
|
||||
int t= 1;
|
||||
int u= 2;
|
||||
res = (u + t == u + t); // expected-warning {{comparison of identical expressions always evaluates to true}}
|
||||
res = (u + t == u + t);
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:16: warning: both sides of operator are equivalent [misc-redundant-expression]
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -551,7 +571,8 @@ int checkEqualNestedBinaryOpIntCompare1(void) {
|
||||
int t= 1;
|
||||
int u= 2;
|
||||
int f= 3;
|
||||
res = (((int)f + (3 - u)*t) == ((int)f + (3 - u)*t)); // expected-warning {{comparison of identical expressions always evaluates to true}}
|
||||
res = (((int)f + (3 - u)*t) == ((int)f + (3 - u)*t));
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:31: warning: both sides of operator are equivalent [misc-redundant-expression]
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -569,7 +590,8 @@ int checkEqualNestedBinaryOpIntCompare3(void) {
|
||||
int t= 1;
|
||||
int u= 2;
|
||||
int f= 3;
|
||||
res = (((int)f + (u - 3)*t) == ((int)f + (3 - u)*(t + 1 == t + 1))); // expected-warning {{comparison of identical expressions always evaluates to true}}
|
||||
res = (((int)f + (u - 3)*t) == ((int)f + (3 - u)*(t + 1 == t + 1)));
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:59: warning: both sides of operator are equivalent [misc-redundant-expression]
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -615,7 +637,8 @@ int checkEqualSameFunctionDifferentParam() {
|
||||
/* LT with float */
|
||||
|
||||
int checkLessThanFloatLiteralCompare1(void) {
|
||||
return (5.14F < 5.14F); // expected-warning {{comparison of identical expressions always evaluates to false}}
|
||||
return (5.14F < 5.14F);
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:17: warning: both sides of operator are equivalent [misc-redundant-expression]
|
||||
}
|
||||
|
||||
int checkLessThanFloatLiteralCompare2(void) {
|
||||
@@ -630,7 +653,8 @@ int checkLessThanFloatDeclCompare1(void) {
|
||||
|
||||
int checkLessThanFloatDeclCompare12(void) {
|
||||
float f = 7.1F;
|
||||
return (f < f); // expected-warning {{comparison of identical expressions always evaluates to false}}
|
||||
return (f < f);
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:13: warning: both sides of operator are equivalent [misc-redundant-expression]
|
||||
}
|
||||
|
||||
int checkLessThanFloatDeclCompare3(void) {
|
||||
@@ -658,7 +682,8 @@ int checkLessThanFloatDeclCompare6(void) {
|
||||
|
||||
int checkLessThanCastFloatDeclCompare11(void) {
|
||||
float f = 7.1F;
|
||||
return ((int)f < (int)f); // expected-warning {{comparison of identical expressions always evaluates to false}}
|
||||
return ((int)f < (int)f);
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:18: warning: both sides of operator are equivalent [misc-redundant-expression]
|
||||
}
|
||||
int checkLessThanCastFloatDeclCompare12(void) {
|
||||
float f = 7.1F;
|
||||
@@ -721,7 +746,8 @@ int checkLessThanNestedBinaryOpFloatCompare3(void) {
|
||||
|
||||
|
||||
int checkLessThanIntLiteralCompare1(void) {
|
||||
return (5 < 5); // expected-warning {{comparison of identical expressions always evaluates to false}}
|
||||
return (5 < 5);
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:13: warning: both sides of operator are equivalent [misc-redundant-expression]
|
||||
}
|
||||
|
||||
int checkLessThanIntLiteralCompare2(void) {
|
||||
@@ -758,7 +784,8 @@ int checkLessThanIntDeclCompare6(void) {
|
||||
|
||||
int checkLessThanCastIntDeclCompare11(void) {
|
||||
int f = 7;
|
||||
return ((int)f < (int)f); // expected-warning {{comparison of identical expressions always evaluates to false}}
|
||||
return ((int)f < (int)f);
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:18: warning: both sides of operator are equivalent [misc-redundant-expression]
|
||||
}
|
||||
int checkLessThanCastIntDeclCompare12(void) {
|
||||
int f = 7;
|
||||
@@ -767,7 +794,8 @@ int checkLessThanCastIntDeclCompare12(void) {
|
||||
int checkLessThanBinaryOpIntCompare1(void) {
|
||||
int res;
|
||||
int f= 3;
|
||||
res = (f + 3 < f + 3); // expected-warning {{comparison of identical expressions always evaluates to false}}
|
||||
res = (f + 3 < f + 3);
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:16: warning: both sides of operator are equivalent [misc-redundant-expression]
|
||||
return (0);
|
||||
}
|
||||
int checkLessThanBinaryOpIntCompare2(void) {
|
||||
@@ -778,7 +806,8 @@ int checkLessThanBinaryOpIntCompare2(void) {
|
||||
int checkLessThanBinaryOpIntCompare3(void) {
|
||||
int res;
|
||||
int f= 3;
|
||||
res = ((int)f + 3 < (int)f + 3); // expected-warning {{comparison of identical expressions always evaluates to false}}
|
||||
res = ((int)f + 3 < (int)f + 3);
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:21: warning: both sides of operator are equivalent [misc-redundant-expression]
|
||||
return (0);
|
||||
}
|
||||
int checkLessThanBinaryOpIntCompare4(void) {
|
||||
@@ -793,7 +822,8 @@ int checkLessThanNestedBinaryOpIntCompare1(void) {
|
||||
int t= 1;
|
||||
int u= 2;
|
||||
int f= 3;
|
||||
res = (((int)f + (3 - u)*t) < ((int)f + (3 - u)*t)); // expected-warning {{comparison of identical expressions always evaluates to false}}
|
||||
res = (((int)f + (3 - u)*t) < ((int)f + (3 - u)*t));
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:31: warning: both sides of operator are equivalent [misc-redundant-expression]
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -811,7 +841,8 @@ int checkLessThanNestedBinaryOpIntCompare3(void) {
|
||||
int t= 1;
|
||||
int u= 2;
|
||||
int f= 3;
|
||||
res = (((int)f + (u - 3)*t) < ((int)f + (3 - u)*(t + u < t + u))); // expected-warning {{comparison of identical expressions always evaluates to false}}
|
||||
res = (((int)f + (u - 3)*t) < ((int)f + (3 - u)*(t + u < t + u)));
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:58: warning: both sides of operator are equivalent [misc-redundant-expression]
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -825,7 +856,8 @@ int checkLessThanNestedBinaryOpIntCompare3(void) {
|
||||
/* GT with float */
|
||||
|
||||
int checkGreaterThanFloatLiteralCompare1(void) {
|
||||
return (5.14F > 5.14F); // expected-warning {{comparison of identical expressions always evaluates to false}}
|
||||
return (5.14F > 5.14F);
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:17: warning: both sides of operator are equivalent [misc-redundant-expression]
|
||||
}
|
||||
|
||||
int checkGreaterThanFloatLiteralCompare2(void) {
|
||||
@@ -841,7 +873,8 @@ int checkGreaterThanFloatDeclCompare1(void) {
|
||||
|
||||
int checkGreaterThanFloatDeclCompare12(void) {
|
||||
float f = 7.1F;
|
||||
return (f > f); // expected-warning {{comparison of identical expressions always evaluates to false}}
|
||||
return (f > f);
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:13: warning: both sides of operator are equivalent [misc-redundant-expression]
|
||||
}
|
||||
|
||||
|
||||
@@ -869,7 +902,8 @@ int checkGreaterThanFloatDeclCompare6(void) {
|
||||
|
||||
int checkGreaterThanCastFloatDeclCompare11(void) {
|
||||
float f = 7.1F;
|
||||
return ((int)f > (int)f); // expected-warning {{comparison of identical expressions always evaluates to false}}
|
||||
return ((int)f > (int)f);
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:18: warning: both sides of operator are equivalent [misc-redundant-expression]
|
||||
}
|
||||
int checkGreaterThanCastFloatDeclCompare12(void) {
|
||||
float f = 7.1F;
|
||||
@@ -932,7 +966,8 @@ int checkGreaterThanNestedBinaryOpFloatCompare3(void) {
|
||||
|
||||
|
||||
int checkGreaterThanIntLiteralCompare1(void) {
|
||||
return (5 > 5); // expected-warning {{comparison of identical expressions always evaluates to false}}
|
||||
return (5 > 5);
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:13: warning: both sides of operator are equivalent [misc-redundant-expression]
|
||||
}
|
||||
|
||||
int checkGreaterThanIntLiteralCompare2(void) {
|
||||
@@ -958,7 +993,8 @@ int checkGreaterThanIntDeclCompare4(void) {
|
||||
|
||||
int checkGreaterThanCastIntDeclCompare11(void) {
|
||||
int f = 7;
|
||||
return ((int)f > (int)f); // expected-warning {{comparison of identical expressions always evaluates to false}}
|
||||
return ((int)f > (int)f);
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:18: warning: both sides of operator are equivalent [misc-redundant-expression]
|
||||
}
|
||||
int checkGreaterThanCastIntDeclCompare12(void) {
|
||||
int f = 7;
|
||||
@@ -967,7 +1003,8 @@ int checkGreaterThanCastIntDeclCompare12(void) {
|
||||
int checkGreaterThanBinaryOpIntCompare1(void) {
|
||||
int res;
|
||||
int f= 3;
|
||||
res = (f + 3 > f + 3); // expected-warning {{comparison of identical expressions always evaluates to false}}
|
||||
res = (f + 3 > f + 3);
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:16: warning: both sides of operator are equivalent [misc-redundant-expression]
|
||||
return (0);
|
||||
}
|
||||
int checkGreaterThanBinaryOpIntCompare2(void) {
|
||||
@@ -978,7 +1015,8 @@ int checkGreaterThanBinaryOpIntCompare2(void) {
|
||||
int checkGreaterThanBinaryOpIntCompare3(void) {
|
||||
int res;
|
||||
int f= 3;
|
||||
res = ((int)f + 3 > (int)f + 3); // expected-warning {{comparison of identical expressions always evaluates to false}}
|
||||
res = ((int)f + 3 > (int)f + 3);
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:21: warning: both sides of operator are equivalent [misc-redundant-expression]
|
||||
return (0);
|
||||
}
|
||||
int checkGreaterThanBinaryOpIntCompare4(void) {
|
||||
@@ -993,7 +1031,8 @@ int checkGreaterThanNestedBinaryOpIntCompare1(void) {
|
||||
int t= 1;
|
||||
int u= 2;
|
||||
int f= 3;
|
||||
res = (((int)f + (3 - u)*t) > ((int)f + (3 - u)*t)); // expected-warning {{comparison of identical expressions always evaluates to false}}
|
||||
res = (((int)f + (3 - u)*t) > ((int)f + (3 - u)*t));
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:31: warning: both sides of operator are equivalent [misc-redundant-expression]
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -1011,7 +1050,8 @@ int checkGreaterThanNestedBinaryOpIntCompare3(void) {
|
||||
int t= 1;
|
||||
int u= 2;
|
||||
int f= 3;
|
||||
res = (((int)f + (u - 3)*t) > ((int)f + (3 - u)*(t + u > t + u))); // expected-warning {{comparison of identical expressions always evaluates to false}}
|
||||
res = (((int)f + (u - 3)*t) > ((int)f + (3 - u)*(t + u > t + u)));
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:58: warning: both sides of operator are equivalent [misc-redundant-expression]
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -1024,45 +1064,61 @@ int checkGreaterThanNestedBinaryOpIntCompare3(void) {
|
||||
|
||||
unsigned test_unsigned(unsigned a) {
|
||||
unsigned b = 1;
|
||||
a = a > 5 ? b : b; // expected-warning {{identical expressions on both sides of ':' in conditional expression}}
|
||||
a = a > 5 ? b : b;
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:17: warning: 'true' and 'false' expressions are equivalent [misc-redundant-expression]
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-2]]:13: warning: conditional operator with identical true and false expressions [bugprone-branch-clone]
|
||||
return a;
|
||||
}
|
||||
|
||||
void test_signed() {
|
||||
int a = 0;
|
||||
a = a > 5 ? a : a; // expected-warning {{identical expressions on both sides of ':' in conditional expression}}
|
||||
a = a > 5 ? a : a;
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:17: warning: 'true' and 'false' expressions are equivalent [misc-redundant-expression]
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-2]]:13: warning: conditional operator with identical true and false expressions [bugprone-branch-clone]
|
||||
}
|
||||
|
||||
void test_bool(bool a) {
|
||||
a = a > 0 ? a : a; // expected-warning {{identical expressions on both sides of ':' in conditional expression}}
|
||||
a = a > 0 ? a : a;
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:17: warning: 'true' and 'false' expressions are equivalent [misc-redundant-expression]
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-2]]:13: warning: conditional operator with identical true and false expressions [bugprone-branch-clone]
|
||||
}
|
||||
|
||||
void test_float() {
|
||||
float a = 0;
|
||||
float b = 0;
|
||||
a = a > 5 ? a : a; // expected-warning {{identical expressions on both sides of ':' in conditional expression}}
|
||||
a = a > 5 ? a : a;
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:17: warning: 'true' and 'false' expressions are equivalent [misc-redundant-expression]
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-2]]:13: warning: conditional operator with identical true and false expressions [bugprone-branch-clone]
|
||||
}
|
||||
|
||||
const char *test_string() {
|
||||
float a = 0;
|
||||
return a > 5 ? "abc" : "abc"; // expected-warning {{identical expressions on both sides of ':' in conditional expression}}
|
||||
return a > 5 ? "abc" : "abc";
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:24: warning: 'true' and 'false' expressions are equivalent [misc-redundant-expression]
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-2]]:16: warning: conditional operator with identical true and false expressions [bugprone-branch-clone]
|
||||
}
|
||||
|
||||
void test_unsigned_expr() {
|
||||
unsigned a = 0;
|
||||
unsigned b = 0;
|
||||
a = a > 5 ? a+b : a+b; // expected-warning {{identical expressions on both sides of ':' in conditional expression}}
|
||||
a = a > 5 ? a+b : a+b;
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:19: warning: 'true' and 'false' expressions are equivalent [misc-redundant-expression]
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-2]]:13: warning: conditional operator with identical true and false expressions [bugprone-branch-clone]
|
||||
}
|
||||
|
||||
void test_signed_expr() {
|
||||
int a = 0;
|
||||
int b = 1;
|
||||
a = a > 5 ? a+b : a+b; // expected-warning {{identical expressions on both sides of ':' in conditional expression}}
|
||||
a = a > 5 ? a+b : a+b;
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:19: warning: 'true' and 'false' expressions are equivalent [misc-redundant-expression]
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-2]]:13: warning: conditional operator with identical true and false expressions [bugprone-branch-clone]
|
||||
}
|
||||
|
||||
void test_bool_expr(bool a) {
|
||||
bool b = 0;
|
||||
a = a > 0 ? a&&b : a&&b; // expected-warning {{identical expressions on both sides of ':' in conditional expression}}
|
||||
a = a > 0 ? a&&b : a&&b;
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:20: warning: 'true' and 'false' expressions are equivalent [misc-redundant-expression]
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-2]]:13: warning: conditional operator with identical true and false expressions [bugprone-branch-clone]
|
||||
}
|
||||
|
||||
void test_unsigned_expr_negative() {
|
||||
@@ -1085,13 +1141,17 @@ void test_bool_expr_negative(bool a) {
|
||||
void test_float_expr_positive() {
|
||||
float a = 0;
|
||||
float b = 0;
|
||||
a = a > 5 ? a+b : a+b; // expected-warning {{identical expressions on both sides of ':' in conditional expression}}
|
||||
a = a > 5 ? a+b : a+b;
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:19: warning: 'true' and 'false' expressions are equivalent [misc-redundant-expression]
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-2]]:13: warning: conditional operator with identical true and false expressions [bugprone-branch-clone]
|
||||
}
|
||||
|
||||
void test_expr_positive_func() {
|
||||
unsigned a = 0;
|
||||
unsigned b = 1;
|
||||
a = a > 5 ? a+func() : a+func(); // expected-warning {{identical expressions on both sides of ':' in conditional expression}}
|
||||
a = a > 5 ? a+func() : a+func();
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:24: warning: 'true' and 'false' expressions are equivalent [misc-redundant-expression]
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-2]]:13: warning: conditional operator with identical true and false expressions [bugprone-branch-clone]
|
||||
}
|
||||
|
||||
void test_expr_negative_func() {
|
||||
@@ -1103,7 +1163,9 @@ void test_expr_negative_func() {
|
||||
void test_expr_positive_funcParam() {
|
||||
unsigned a = 0;
|
||||
unsigned b = 1;
|
||||
a = a > 5 ? a+funcParam(b) : a+funcParam(b); // expected-warning {{identical expressions on both sides of ':' in conditional expression}}
|
||||
a = a > 5 ? a+funcParam(b) : a+funcParam(b);
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:30: warning: 'true' and 'false' expressions are equivalent [misc-redundant-expression]
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-2]]:13: warning: conditional operator with identical true and false expressions [bugprone-branch-clone]
|
||||
}
|
||||
|
||||
void test_expr_negative_funcParam() {
|
||||
@@ -1115,7 +1177,8 @@ void test_expr_negative_funcParam() {
|
||||
void test_expr_positive_inc() {
|
||||
unsigned a = 0;
|
||||
unsigned b = 1;
|
||||
a = a > 5 ? a++ : a++; // expected-warning {{identical expressions on both sides of ':' in conditional expression}}
|
||||
a = a > 5 ? a++ : a++;
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:13: warning: conditional operator with identical true and false expressions [bugprone-branch-clone]
|
||||
}
|
||||
|
||||
void test_expr_negative_inc() {
|
||||
@@ -1127,7 +1190,8 @@ void test_expr_negative_inc() {
|
||||
void test_expr_positive_assign() {
|
||||
unsigned a = 0;
|
||||
unsigned b = 1;
|
||||
a = a > 5 ? a=1 : a=1; // expected-warning {{identical expressions on both sides of ':' in conditional expression}}
|
||||
a = a > 5 ? a=1 : a=1;
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:13: warning: conditional operator with identical true and false expressions [bugprone-branch-clone]
|
||||
}
|
||||
|
||||
void test_expr_negative_assign() {
|
||||
@@ -1140,7 +1204,9 @@ void test_signed_nested_expr() {
|
||||
int a = 0;
|
||||
int b = 1;
|
||||
int c = 3;
|
||||
a = a > 5 ? a+b+(c+a)*(a + b*(c+a)) : a+b+(c+a)*(a + b*(c+a)); // expected-warning {{identical expressions on both sides of ':' in conditional expression}}
|
||||
a = a > 5 ? a+b+(c+a)*(a + b*(c+a)) : a+b+(c+a)*(a + b*(c+a));
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:39: warning: 'true' and 'false' expressions are equivalent [misc-redundant-expression]
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-2]]:13: warning: conditional operator with identical true and false expressions [bugprone-branch-clone]
|
||||
}
|
||||
|
||||
void test_signed_nested_expr_negative() {
|
||||
@@ -1161,23 +1227,29 @@ void test_signed_nested_cond_expr() {
|
||||
int a = 0;
|
||||
int b = 1;
|
||||
int c = 3;
|
||||
a = a > 5 ? (b > 5 ? 1 : 4) : (b > 5 ? 4 : 4); // expected-warning {{identical expressions on both sides of ':' in conditional expression}}
|
||||
a = a > 5 ? (b > 5 ? 1 : 4) : (b > 5 ? 4 : 4);
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:44: warning: 'true' and 'false' expressions are equivalent [misc-redundant-expression]
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-2]]:40: warning: conditional operator with identical true and false expressions [bugprone-branch-clone]
|
||||
}
|
||||
|
||||
void test_identical_branches1(bool b) {
|
||||
int i = 0;
|
||||
if (b) { // expected-warning {{true and false branches are identical}}
|
||||
if (b) {
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone]
|
||||
++i;
|
||||
} else {
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: else branch starts here
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
void test_identical_branches2(bool b) {
|
||||
int i = 0;
|
||||
if (b) { // expected-warning {{true and false branches are identical}}
|
||||
if (b) {
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone]
|
||||
++i;
|
||||
} else
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: else branch starts here
|
||||
++i;
|
||||
}
|
||||
|
||||
@@ -1192,33 +1264,41 @@ void test_identical_branches3(bool b) {
|
||||
|
||||
void test_identical_branches4(bool b) {
|
||||
int i = 0;
|
||||
if (b) { // expected-warning {{true and false branches are identical}}
|
||||
if (b) {
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone]
|
||||
} else {
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: else branch starts here
|
||||
}
|
||||
}
|
||||
|
||||
void test_identical_branches_break(bool b) {
|
||||
while (true) {
|
||||
if (b) // expected-warning {{true and false branches are identical}}
|
||||
if (b)
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: warning: if with identical then and else branches [bugprone-branch-clone]
|
||||
break;
|
||||
else
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: else branch starts here
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void test_identical_branches_continue(bool b) {
|
||||
while (true) {
|
||||
if (b) // expected-warning {{true and false branches are identical}}
|
||||
if (b)
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: warning: if with identical then and else branches [bugprone-branch-clone]
|
||||
continue;
|
||||
else
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: else branch starts here
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
void test_identical_branches_func(bool b) {
|
||||
if (b) // expected-warning {{true and false branches are identical}}
|
||||
if (b)
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone]
|
||||
func();
|
||||
else
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:3: note: else branch starts here
|
||||
func();
|
||||
}
|
||||
|
||||
@@ -1239,27 +1319,33 @@ void test_identical_branches_cast1(bool b) {
|
||||
|
||||
void test_identical_branches_cast2(bool b) {
|
||||
long v = -7;
|
||||
if (b) // expected-warning {{true and false branches are identical}}
|
||||
if (b)
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone]
|
||||
v = (signed int) v;
|
||||
else
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:3: note: else branch starts here
|
||||
v = (signed int) v;
|
||||
}
|
||||
|
||||
int test_identical_branches_return_int(bool b) {
|
||||
int i = 0;
|
||||
if (b) { // expected-warning {{true and false branches are identical}}
|
||||
if (b) {
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone]
|
||||
i++;
|
||||
return i;
|
||||
} else {
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: else branch starts here
|
||||
i++;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
int test_identical_branches_return_func(bool b) {
|
||||
if (b) { // expected-warning {{true and false branches are identical}}
|
||||
if (b) {
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone]
|
||||
return func();
|
||||
} else {
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: else branch starts here
|
||||
return func();
|
||||
}
|
||||
}
|
||||
@@ -1267,10 +1353,12 @@ int test_identical_branches_return_func(bool b) {
|
||||
void test_identical_branches_for(bool b) {
|
||||
int i;
|
||||
int j;
|
||||
if (b) { // expected-warning {{true and false branches are identical}}
|
||||
if (b) {
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone]
|
||||
for (i = 0, j = 0; i < 10; i++)
|
||||
j += 4;
|
||||
} else {
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: else branch starts here
|
||||
for (i = 0, j = 0; i < 10; i++)
|
||||
j += 4;
|
||||
}
|
||||
@@ -1278,10 +1366,12 @@ void test_identical_branches_for(bool b) {
|
||||
|
||||
void test_identical_branches_while(bool b) {
|
||||
int i = 10;
|
||||
if (b) { // expected-warning {{true and false branches are identical}}
|
||||
if (b) {
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone]
|
||||
while (func())
|
||||
i--;
|
||||
} else {
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: else branch starts here
|
||||
while (func())
|
||||
i--;
|
||||
}
|
||||
@@ -1300,11 +1390,13 @@ void test_identical_branches_while_2(bool b) {
|
||||
|
||||
void test_identical_branches_do_while(bool b) {
|
||||
int i = 10;
|
||||
if (b) { // expected-warning {{true and false branches are identical}}
|
||||
if (b) {
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone]
|
||||
do {
|
||||
i--;
|
||||
} while (func());
|
||||
} else {
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: else branch starts here
|
||||
do {
|
||||
i--;
|
||||
} while (func());
|
||||
@@ -1312,27 +1404,32 @@ void test_identical_branches_do_while(bool b) {
|
||||
}
|
||||
|
||||
void test_identical_branches_if(bool b, int i) {
|
||||
if (b) { // expected-warning {{true and false branches are identical}}
|
||||
if (b) {
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone]
|
||||
if (i < 5)
|
||||
i += 10;
|
||||
} else {
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: else branch starts here
|
||||
if (i < 5)
|
||||
i += 10;
|
||||
}
|
||||
}
|
||||
|
||||
void test_identical_bitwise1() {
|
||||
int a = 5 | 5; // expected-warning {{identical expressions on both sides of bitwise operator}}
|
||||
int a = 5 | 5;
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:13: warning: both sides of operator are equivalent [misc-redundant-expression]
|
||||
}
|
||||
|
||||
void test_identical_bitwise2() {
|
||||
int a = 5;
|
||||
int b = a | a; // expected-warning {{identical expressions on both sides of bitwise operator}}
|
||||
int b = a | a;
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:13: warning: both sides of operator are equivalent [misc-redundant-expression]
|
||||
}
|
||||
|
||||
void test_identical_bitwise3() {
|
||||
int a = 5;
|
||||
int b = (a | a); // expected-warning {{identical expressions on both sides of bitwise operator}}
|
||||
int b = (a | a);
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:14: warning: both sides of operator are equivalent [misc-redundant-expression]
|
||||
}
|
||||
|
||||
void test_identical_bitwise4() {
|
||||
@@ -1348,21 +1445,25 @@ void test_identical_bitwise5() {
|
||||
|
||||
void test_identical_bitwise6() {
|
||||
int a = 5;
|
||||
int b = a | 4 | a; // expected-warning {{identical expressions on both sides of bitwise operator}}
|
||||
int b = a | 4 | a;
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:17: warning: operator has equivalent nested operands [misc-redundant-expression]
|
||||
}
|
||||
|
||||
void test_identical_bitwise7() {
|
||||
int a = 5;
|
||||
int b = func() | func(); // no-warning
|
||||
int b = func() | func();
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:18: warning: both sides of operator are equivalent [misc-redundant-expression]
|
||||
}
|
||||
|
||||
void test_identical_logical1(int a) {
|
||||
if (a == 4 && a == 4) // expected-warning {{identical expressions on both sides of logical operator}}
|
||||
if (a == 4 && a == 4)
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:14: warning: both sides of operator are equivalent [misc-redundant-expression]
|
||||
;
|
||||
}
|
||||
|
||||
void test_identical_logical2(int a) {
|
||||
if (a == 4 || a == 5 || a == 4) // expected-warning {{identical expressions on both sides of logical operator}}
|
||||
if (a == 4 || a == 5 || a == 4)
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:24: warning: operator has equivalent nested operands [misc-redundant-expression]
|
||||
;
|
||||
}
|
||||
|
||||
@@ -1384,7 +1485,8 @@ void test_identical_logical5(int x, int y) {
|
||||
}
|
||||
|
||||
void test_identical_logical6(int x, int y) {
|
||||
if (x == 4 && y == 5 || x == 4 && y == 5) // expected-warning {{identical expressions on both sides of logical operator}}
|
||||
if (x == 4 && y == 5 || x == 4 && y == 5)
|
||||
// CHECK-MESSAGES-IDENTEXPR: :[[@LINE-1]]:24: warning: both sides of operator are equivalent [misc-redundant-expression]
|
||||
;
|
||||
}
|
||||
|
||||
@@ -1410,51 +1512,73 @@ void test_identical_logical9(int x, int y) {
|
||||
void test_warn_chained_if_stmts_1(int x) {
|
||||
if (x == 1)
|
||||
;
|
||||
else if (x == 1) // expected-warning {{expression is identical to previous condition}}
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: warning: repeated branch body in conditional chain [bugprone-branch-clone]
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-2]]:6: note: end of the original
|
||||
else if (x == 1)
|
||||
;
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 1 starts here
|
||||
}
|
||||
|
||||
void test_warn_chained_if_stmts_2(int x) {
|
||||
if (x == 1)
|
||||
;
|
||||
else if (x == 1) // expected-warning {{expression is identical to previous condition}}
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: warning: repeated branch body in conditional chain [bugprone-branch-clone]
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-2]]:6: note: end of the original
|
||||
else if (x == 1)
|
||||
;
|
||||
else if (x == 1) // expected-warning {{expression is identical to previous condition}}
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 1 starts here
|
||||
else if (x == 1)
|
||||
;
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 2 starts here
|
||||
}
|
||||
|
||||
void test_warn_chained_if_stmts_3(int x) {
|
||||
if (x == 1)
|
||||
;
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: warning: repeated branch body in conditional chain [bugprone-branch-clone]
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-2]]:6: note: end of the original
|
||||
else if (x == 2)
|
||||
;
|
||||
else if (x == 1) // expected-warning {{expression is identical to previous condition}}
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 1 starts here
|
||||
else if (x == 1)
|
||||
;
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 2 starts here
|
||||
}
|
||||
|
||||
void test_warn_chained_if_stmts_4(int x) {
|
||||
if (x == 1)
|
||||
;
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: warning: repeated branch body in conditional chain [bugprone-branch-clone]
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-2]]:6: note: end of the original
|
||||
else if (func())
|
||||
;
|
||||
else if (x == 1) // expected-warning {{expression is identical to previous condition}}
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 1 starts here
|
||||
else if (x == 1)
|
||||
;
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 2 starts here
|
||||
}
|
||||
|
||||
void test_warn_chained_if_stmts_5(int x) {
|
||||
if (x & 1)
|
||||
;
|
||||
else if (x & 1) // expected-warning {{expression is identical to previous condition}}
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: warning: repeated branch body in conditional chain [bugprone-branch-clone]
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-2]]:6: note: end of the original
|
||||
else if (x & 1)
|
||||
;
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 1 starts here
|
||||
}
|
||||
|
||||
void test_warn_chained_if_stmts_6(int x) {
|
||||
if (x == 1)
|
||||
;
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: warning: repeated branch body in conditional chain [bugprone-branch-clone]
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-2]]:6: note: end of the original
|
||||
else if (x == 2)
|
||||
;
|
||||
else if (x == 2) // expected-warning {{expression is identical to previous condition}}
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 1 starts here
|
||||
else if (x == 2)
|
||||
;
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 2 starts here
|
||||
else if (x == 3)
|
||||
;
|
||||
}
|
||||
@@ -1462,58 +1586,83 @@ void test_warn_chained_if_stmts_6(int x) {
|
||||
void test_warn_chained_if_stmts_7(int x) {
|
||||
if (x == 1)
|
||||
;
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: warning: repeated branch body in conditional chain [bugprone-branch-clone]
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-2]]:6: note: end of the original
|
||||
else if (x == 2)
|
||||
;
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 1 starts here
|
||||
else if (x == 3)
|
||||
;
|
||||
else if (x == 2) // expected-warning {{expression is identical to previous condition}}
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 2 starts here
|
||||
else if (x == 2)
|
||||
;
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 3 starts here
|
||||
else if (x == 5)
|
||||
;
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 4 starts here
|
||||
}
|
||||
|
||||
void test_warn_chained_if_stmts_8(int x) {
|
||||
if (x == 1)
|
||||
;
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: warning: repeated branch body in conditional chain [bugprone-branch-clone]
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-2]]:6: note: end of the original
|
||||
else if (x == 2)
|
||||
;
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 1 starts here
|
||||
else if (x == 3)
|
||||
;
|
||||
else if (x == 2) // expected-warning {{expression is identical to previous condition}}
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 2 starts here
|
||||
else if (x == 2)
|
||||
;
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 3 starts here
|
||||
else if (x == 5)
|
||||
;
|
||||
else if (x == 3) // expected-warning {{expression is identical to previous condition}}
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 4 starts here
|
||||
else if (x == 3)
|
||||
;
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 5 starts here
|
||||
else if (x == 7)
|
||||
;
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 6 starts here
|
||||
}
|
||||
|
||||
void test_nowarn_chained_if_stmts_1(int x) {
|
||||
if (func())
|
||||
;
|
||||
else if (func()) // no-warning
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: warning: repeated branch body in conditional chain [bugprone-branch-clone]
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-2]]:6: note: end of the original
|
||||
else if (func())
|
||||
;
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 1 starts here
|
||||
}
|
||||
|
||||
void test_nowarn_chained_if_stmts_2(int x) {
|
||||
if (func())
|
||||
;
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: warning: repeated branch body in conditional chain [bugprone-branch-clone]
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-2]]:6: note: end of the original
|
||||
else if (x == 1)
|
||||
;
|
||||
else if (func()) // no-warning
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 1 starts here
|
||||
else if (func())
|
||||
;
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 2 starts here
|
||||
}
|
||||
|
||||
void test_nowarn_chained_if_stmts_3(int x) {
|
||||
if (x++)
|
||||
;
|
||||
else if (x++) // no-warning
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: warning: repeated branch body in conditional chain [bugprone-branch-clone]
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-2]]:6: note: end of the original
|
||||
else if (x++)
|
||||
;
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 1 starts here
|
||||
}
|
||||
|
||||
void test_warn_wchar() {
|
||||
const wchar_t * a = 0 ? L"Warning" : L"Warning"; // expected-warning {{identical expressions on both sides of ':' in conditional expression}}
|
||||
const wchar_t * a = 0 ? L"Warning" : L"Warning";
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:25: warning: conditional operator with identical true and false expressions [bugprone-branch-clone]
|
||||
}
|
||||
void test_nowarn_wchar() {
|
||||
const wchar_t * a = 0 ? L"No" : L"Warning";
|
||||
@@ -1525,7 +1674,7 @@ void test_nowarn_long() {
|
||||
if (0) {
|
||||
b -= a;
|
||||
c = 0;
|
||||
} else { // no-warning
|
||||
} else {
|
||||
b -= a;
|
||||
c = 0LL;
|
||||
}
|
||||
@@ -1535,7 +1684,9 @@ void test_nowarn_long() {
|
||||
|
||||
void test_warn_inner_if_1(int x) {
|
||||
if (x == 1) {
|
||||
if (x == 1) // expected-warning {{conditions of the inner and outer statements are identical}}
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:3: warning: if with identical inner if statement [bugprone-branch-clone]
|
||||
if (x == 1)
|
||||
// CHECK-MESSAGES-BUGPRONEBRANCH: :[[@LINE-1]]:5: note: inner if starts here
|
||||
;
|
||||
}
|
||||
|
||||
@@ -1016,6 +1016,10 @@ Improvements
|
||||
Moved checkers
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
- The checker ``alpha.core.IdenticalExpr`` was deleted because it was
|
||||
duplicated in the clang-tidy checkers ``misc-redundant-expression`` and
|
||||
``bugprone-branch-clone``.
|
||||
|
||||
- The checker ``alpha.security.MallocOverflow`` was deleted because it was
|
||||
badly implemented and its agressive logic produced too many false positives.
|
||||
To detect too large arguments passed to malloc, consider using the checker
|
||||
|
||||
@@ -2842,36 +2842,6 @@ Check for assignment of a fixed address to a pointer.
|
||||
p = (int *) 0x10000; // warn
|
||||
}
|
||||
|
||||
.. _alpha-core-IdenticalExpr:
|
||||
|
||||
alpha.core.IdenticalExpr (C, C++)
|
||||
"""""""""""""""""""""""""""""""""
|
||||
Warn about unintended use of identical expressions in operators.
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
// C
|
||||
void test() {
|
||||
int a = 5;
|
||||
int b = a | 4 | a; // warn: identical expr on both sides
|
||||
}
|
||||
|
||||
// C++
|
||||
bool f(void);
|
||||
|
||||
void test(bool b) {
|
||||
int i = 10;
|
||||
if (f()) { // warn: true and false branches are identical
|
||||
do {
|
||||
i--;
|
||||
} while (f());
|
||||
} else {
|
||||
do {
|
||||
i--;
|
||||
} while (f());
|
||||
}
|
||||
}
|
||||
|
||||
.. _alpha-core-PointerArithm:
|
||||
|
||||
alpha.core.PointerArithm (C)
|
||||
|
||||
@@ -275,10 +275,6 @@ def ConversionChecker : Checker<"Conversion">,
|
||||
HelpText<"Loss of sign/precision in implicit conversions">,
|
||||
Documentation<HasDocumentation>;
|
||||
|
||||
def IdenticalExprChecker : Checker<"IdenticalExpr">,
|
||||
HelpText<"Warn about unintended use of identical expressions in operators">,
|
||||
Documentation<HasDocumentation>;
|
||||
|
||||
def FixedAddressChecker : Checker<"FixedAddr">,
|
||||
HelpText<"Check for assignment of a fixed address to a pointer">,
|
||||
Documentation<HasDocumentation>;
|
||||
|
||||
@@ -50,7 +50,6 @@ add_clang_library(clangStaticAnalyzerCheckers
|
||||
GCDAntipatternChecker.cpp
|
||||
GenericTaintChecker.cpp
|
||||
GTestChecker.cpp
|
||||
IdenticalExprChecker.cpp
|
||||
InnerPointerChecker.cpp
|
||||
InvalidatedIteratorChecker.cpp
|
||||
cert/InvalidPtrChecker.cpp
|
||||
|
||||
@@ -1,519 +0,0 @@
|
||||
//== IdenticalExprChecker.cpp - Identical expression checker----------------==//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// This defines IdenticalExprChecker, a check that warns about
|
||||
/// unintended use of identical expressions.
|
||||
///
|
||||
/// It checks for use of identical expressions with comparison operators and
|
||||
/// inside conditional expressions.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/AST/DynamicRecursiveASTVisitor.h"
|
||||
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
|
||||
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
|
||||
#include "clang/StaticAnalyzer/Core/Checker.h"
|
||||
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
|
||||
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
|
||||
|
||||
using namespace clang;
|
||||
using namespace ento;
|
||||
|
||||
static bool isIdenticalStmt(const ASTContext &Ctx, const Stmt *Stmt1,
|
||||
const Stmt *Stmt2, bool IgnoreSideEffects = false);
|
||||
//===----------------------------------------------------------------------===//
|
||||
// FindIdenticalExprVisitor - Identify nodes using identical expressions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace {
|
||||
class FindIdenticalExprVisitor : public DynamicRecursiveASTVisitor {
|
||||
BugReporter &BR;
|
||||
const CheckerBase *Checker;
|
||||
AnalysisDeclContext *AC;
|
||||
public:
|
||||
explicit FindIdenticalExprVisitor(BugReporter &B,
|
||||
const CheckerBase *Checker,
|
||||
AnalysisDeclContext *A)
|
||||
: BR(B), Checker(Checker), AC(A) {}
|
||||
// FindIdenticalExprVisitor only visits nodes
|
||||
// that are binary operators, if statements or
|
||||
// conditional operators.
|
||||
bool VisitBinaryOperator(BinaryOperator *B) override;
|
||||
bool VisitIfStmt(IfStmt *I) override;
|
||||
bool VisitConditionalOperator(ConditionalOperator *C) override;
|
||||
|
||||
private:
|
||||
void reportIdenticalExpr(const BinaryOperator *B, bool CheckBitwise,
|
||||
ArrayRef<SourceRange> Sr);
|
||||
void checkBitwiseOrLogicalOp(const BinaryOperator *B, bool CheckBitwise);
|
||||
void checkComparisonOp(const BinaryOperator *B);
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
void FindIdenticalExprVisitor::reportIdenticalExpr(const BinaryOperator *B,
|
||||
bool CheckBitwise,
|
||||
ArrayRef<SourceRange> Sr) {
|
||||
StringRef Message;
|
||||
if (CheckBitwise)
|
||||
Message = "identical expressions on both sides of bitwise operator";
|
||||
else
|
||||
Message = "identical expressions on both sides of logical operator";
|
||||
|
||||
PathDiagnosticLocation ELoc =
|
||||
PathDiagnosticLocation::createOperatorLoc(B, BR.getSourceManager());
|
||||
BR.EmitBasicReport(AC->getDecl(), Checker,
|
||||
"Use of identical expressions",
|
||||
categories::LogicError,
|
||||
Message, ELoc, Sr);
|
||||
}
|
||||
|
||||
void FindIdenticalExprVisitor::checkBitwiseOrLogicalOp(const BinaryOperator *B,
|
||||
bool CheckBitwise) {
|
||||
SourceRange Sr[2];
|
||||
|
||||
const Expr *LHS = B->getLHS();
|
||||
const Expr *RHS = B->getRHS();
|
||||
|
||||
// Split operators as long as we still have operators to split on. We will
|
||||
// get called for every binary operator in an expression so there is no need
|
||||
// to check every one against each other here, just the right most one with
|
||||
// the others.
|
||||
while (const BinaryOperator *B2 = dyn_cast<BinaryOperator>(LHS)) {
|
||||
if (B->getOpcode() != B2->getOpcode())
|
||||
break;
|
||||
if (isIdenticalStmt(AC->getASTContext(), RHS, B2->getRHS())) {
|
||||
Sr[0] = RHS->getSourceRange();
|
||||
Sr[1] = B2->getRHS()->getSourceRange();
|
||||
reportIdenticalExpr(B, CheckBitwise, Sr);
|
||||
}
|
||||
LHS = B2->getLHS();
|
||||
}
|
||||
|
||||
if (isIdenticalStmt(AC->getASTContext(), RHS, LHS)) {
|
||||
Sr[0] = RHS->getSourceRange();
|
||||
Sr[1] = LHS->getSourceRange();
|
||||
reportIdenticalExpr(B, CheckBitwise, Sr);
|
||||
}
|
||||
}
|
||||
|
||||
bool FindIdenticalExprVisitor::VisitIfStmt(IfStmt *I) {
|
||||
const Stmt *Stmt1 = I->getThen();
|
||||
const Stmt *Stmt2 = I->getElse();
|
||||
|
||||
// Check for identical inner condition:
|
||||
//
|
||||
// if (x<10) {
|
||||
// if (x<10) {
|
||||
// ..
|
||||
if (const CompoundStmt *CS = dyn_cast<CompoundStmt>(Stmt1)) {
|
||||
if (!CS->body_empty()) {
|
||||
const IfStmt *InnerIf = dyn_cast<IfStmt>(*CS->body_begin());
|
||||
if (InnerIf && isIdenticalStmt(AC->getASTContext(), I->getCond(), InnerIf->getCond(), /*IgnoreSideEffects=*/ false)) {
|
||||
PathDiagnosticLocation ELoc(InnerIf->getCond(), BR.getSourceManager(), AC);
|
||||
BR.EmitBasicReport(AC->getDecl(), Checker, "Identical conditions",
|
||||
categories::LogicError,
|
||||
"conditions of the inner and outer statements are identical",
|
||||
ELoc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for identical conditions:
|
||||
//
|
||||
// if (b) {
|
||||
// foo1();
|
||||
// } else if (b) {
|
||||
// foo2();
|
||||
// }
|
||||
if (Stmt1 && Stmt2) {
|
||||
const Expr *Cond1 = I->getCond();
|
||||
const Stmt *Else = Stmt2;
|
||||
while (const IfStmt *I2 = dyn_cast_or_null<IfStmt>(Else)) {
|
||||
const Expr *Cond2 = I2->getCond();
|
||||
if (isIdenticalStmt(AC->getASTContext(), Cond1, Cond2, false)) {
|
||||
SourceRange Sr = Cond1->getSourceRange();
|
||||
PathDiagnosticLocation ELoc(Cond2, BR.getSourceManager(), AC);
|
||||
BR.EmitBasicReport(AC->getDecl(), Checker, "Identical conditions",
|
||||
categories::LogicError,
|
||||
"expression is identical to previous condition",
|
||||
ELoc, Sr);
|
||||
}
|
||||
Else = I2->getElse();
|
||||
}
|
||||
}
|
||||
|
||||
if (!Stmt1 || !Stmt2)
|
||||
return true;
|
||||
|
||||
// Special handling for code like:
|
||||
//
|
||||
// if (b) {
|
||||
// i = 1;
|
||||
// } else
|
||||
// i = 1;
|
||||
if (const CompoundStmt *CompStmt = dyn_cast<CompoundStmt>(Stmt1)) {
|
||||
if (CompStmt->size() == 1)
|
||||
Stmt1 = CompStmt->body_back();
|
||||
}
|
||||
if (const CompoundStmt *CompStmt = dyn_cast<CompoundStmt>(Stmt2)) {
|
||||
if (CompStmt->size() == 1)
|
||||
Stmt2 = CompStmt->body_back();
|
||||
}
|
||||
|
||||
if (isIdenticalStmt(AC->getASTContext(), Stmt1, Stmt2, true)) {
|
||||
PathDiagnosticLocation ELoc =
|
||||
PathDiagnosticLocation::createBegin(I, BR.getSourceManager(), AC);
|
||||
BR.EmitBasicReport(AC->getDecl(), Checker,
|
||||
"Identical branches",
|
||||
categories::LogicError,
|
||||
"true and false branches are identical", ELoc);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FindIdenticalExprVisitor::VisitBinaryOperator(BinaryOperator *B) {
|
||||
BinaryOperator::Opcode Op = B->getOpcode();
|
||||
|
||||
if (BinaryOperator::isBitwiseOp(Op))
|
||||
checkBitwiseOrLogicalOp(B, true);
|
||||
|
||||
if (BinaryOperator::isLogicalOp(Op))
|
||||
checkBitwiseOrLogicalOp(B, false);
|
||||
|
||||
if (BinaryOperator::isComparisonOp(Op))
|
||||
checkComparisonOp(B);
|
||||
|
||||
// We want to visit ALL nodes (subexpressions of binary comparison
|
||||
// expressions too) that contains comparison operators.
|
||||
// True is always returned to traverse ALL nodes.
|
||||
return true;
|
||||
}
|
||||
|
||||
void FindIdenticalExprVisitor::checkComparisonOp(const BinaryOperator *B) {
|
||||
BinaryOperator::Opcode Op = B->getOpcode();
|
||||
|
||||
//
|
||||
// Special case for floating-point representation.
|
||||
//
|
||||
// If expressions on both sides of comparison operator are of type float,
|
||||
// then for some comparison operators no warning shall be
|
||||
// reported even if the expressions are identical from a symbolic point of
|
||||
// view. Comparison between expressions, declared variables and literals
|
||||
// are treated differently.
|
||||
//
|
||||
// != and == between float literals that have the same value should NOT warn.
|
||||
// < > between float literals that have the same value SHOULD warn.
|
||||
//
|
||||
// != and == between the same float declaration should NOT warn.
|
||||
// < > between the same float declaration SHOULD warn.
|
||||
//
|
||||
// != and == between eq. expressions that evaluates into float
|
||||
// should NOT warn.
|
||||
// < > between eq. expressions that evaluates into float
|
||||
// should NOT warn.
|
||||
//
|
||||
const Expr *LHS = B->getLHS()->IgnoreParenImpCasts();
|
||||
const Expr *RHS = B->getRHS()->IgnoreParenImpCasts();
|
||||
|
||||
const DeclRefExpr *DeclRef1 = dyn_cast<DeclRefExpr>(LHS);
|
||||
const DeclRefExpr *DeclRef2 = dyn_cast<DeclRefExpr>(RHS);
|
||||
const FloatingLiteral *FloatLit1 = dyn_cast<FloatingLiteral>(LHS);
|
||||
const FloatingLiteral *FloatLit2 = dyn_cast<FloatingLiteral>(RHS);
|
||||
if ((DeclRef1) && (DeclRef2)) {
|
||||
if ((DeclRef1->getType()->hasFloatingRepresentation()) &&
|
||||
(DeclRef2->getType()->hasFloatingRepresentation())) {
|
||||
if (DeclRef1->getDecl() == DeclRef2->getDecl()) {
|
||||
if ((Op == BO_EQ) || (Op == BO_NE)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if ((FloatLit1) && (FloatLit2)) {
|
||||
if (FloatLit1->getValue().bitwiseIsEqual(FloatLit2->getValue())) {
|
||||
if ((Op == BO_EQ) || (Op == BO_NE)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else if (LHS->getType()->hasFloatingRepresentation()) {
|
||||
// If any side of comparison operator still has floating-point
|
||||
// representation, then it's an expression. Don't warn.
|
||||
// Here only LHS is checked since RHS will be implicit casted to float.
|
||||
return;
|
||||
} else {
|
||||
// No special case with floating-point representation, report as usual.
|
||||
}
|
||||
|
||||
if (isIdenticalStmt(AC->getASTContext(), B->getLHS(), B->getRHS())) {
|
||||
PathDiagnosticLocation ELoc =
|
||||
PathDiagnosticLocation::createOperatorLoc(B, BR.getSourceManager());
|
||||
StringRef Message;
|
||||
if (Op == BO_Cmp)
|
||||
Message = "comparison of identical expressions always evaluates to "
|
||||
"'equal'";
|
||||
else if (((Op == BO_EQ) || (Op == BO_LE) || (Op == BO_GE)))
|
||||
Message = "comparison of identical expressions always evaluates to true";
|
||||
else
|
||||
Message = "comparison of identical expressions always evaluates to false";
|
||||
BR.EmitBasicReport(AC->getDecl(), Checker,
|
||||
"Compare of identical expressions",
|
||||
categories::LogicError, Message, ELoc);
|
||||
}
|
||||
}
|
||||
|
||||
bool FindIdenticalExprVisitor::VisitConditionalOperator(
|
||||
ConditionalOperator *C) {
|
||||
|
||||
// Check if expressions in conditional expression are identical
|
||||
// from a symbolic point of view.
|
||||
|
||||
if (isIdenticalStmt(AC->getASTContext(), C->getTrueExpr(),
|
||||
C->getFalseExpr(), true)) {
|
||||
PathDiagnosticLocation ELoc =
|
||||
PathDiagnosticLocation::createConditionalColonLoc(
|
||||
C, BR.getSourceManager());
|
||||
|
||||
SourceRange Sr[2];
|
||||
Sr[0] = C->getTrueExpr()->getSourceRange();
|
||||
Sr[1] = C->getFalseExpr()->getSourceRange();
|
||||
BR.EmitBasicReport(
|
||||
AC->getDecl(), Checker,
|
||||
"Identical expressions in conditional expression",
|
||||
categories::LogicError,
|
||||
"identical expressions on both sides of ':' in conditional expression",
|
||||
ELoc, Sr);
|
||||
}
|
||||
// We want to visit ALL nodes (expressions in conditional
|
||||
// expressions too) that contains conditional operators,
|
||||
// thus always return true to traverse ALL nodes.
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Determines whether two statement trees are identical regarding
|
||||
/// operators and symbols.
|
||||
///
|
||||
/// Exceptions: expressions containing macros or functions with possible side
|
||||
/// effects are never considered identical.
|
||||
/// Limitations: (t + u) and (u + t) are not considered identical.
|
||||
/// t*(u + t) and t*u + t*t are not considered identical.
|
||||
///
|
||||
static bool isIdenticalStmt(const ASTContext &Ctx, const Stmt *Stmt1,
|
||||
const Stmt *Stmt2, bool IgnoreSideEffects) {
|
||||
|
||||
if (!Stmt1 || !Stmt2) {
|
||||
return !Stmt1 && !Stmt2;
|
||||
}
|
||||
|
||||
// If Stmt1 & Stmt2 are of different class then they are not
|
||||
// identical statements.
|
||||
if (Stmt1->getStmtClass() != Stmt2->getStmtClass())
|
||||
return false;
|
||||
|
||||
const Expr *Expr1 = dyn_cast<Expr>(Stmt1);
|
||||
const Expr *Expr2 = dyn_cast<Expr>(Stmt2);
|
||||
|
||||
if (Expr1 && Expr2) {
|
||||
// If Stmt1 has side effects then don't warn even if expressions
|
||||
// are identical.
|
||||
if (!IgnoreSideEffects && Expr1->HasSideEffects(Ctx))
|
||||
return false;
|
||||
// If either expression comes from a macro then don't warn even if
|
||||
// the expressions are identical.
|
||||
if ((Expr1->getExprLoc().isMacroID()) || (Expr2->getExprLoc().isMacroID()))
|
||||
return false;
|
||||
|
||||
// If all children of two expressions are identical, return true.
|
||||
Expr::const_child_iterator I1 = Expr1->child_begin();
|
||||
Expr::const_child_iterator I2 = Expr2->child_begin();
|
||||
while (I1 != Expr1->child_end() && I2 != Expr2->child_end()) {
|
||||
if (!*I1 || !*I2 || !isIdenticalStmt(Ctx, *I1, *I2, IgnoreSideEffects))
|
||||
return false;
|
||||
++I1;
|
||||
++I2;
|
||||
}
|
||||
// If there are different number of children in the statements, return
|
||||
// false.
|
||||
if (I1 != Expr1->child_end())
|
||||
return false;
|
||||
if (I2 != Expr2->child_end())
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (Stmt1->getStmtClass()) {
|
||||
default:
|
||||
return false;
|
||||
case Stmt::CallExprClass:
|
||||
case Stmt::ArraySubscriptExprClass:
|
||||
case Stmt::ArraySectionExprClass:
|
||||
case Stmt::OMPArrayShapingExprClass:
|
||||
case Stmt::OMPIteratorExprClass:
|
||||
case Stmt::ImplicitCastExprClass:
|
||||
case Stmt::ParenExprClass:
|
||||
case Stmt::BreakStmtClass:
|
||||
case Stmt::ContinueStmtClass:
|
||||
case Stmt::NullStmtClass:
|
||||
return true;
|
||||
case Stmt::CStyleCastExprClass: {
|
||||
const CStyleCastExpr* CastExpr1 = cast<CStyleCastExpr>(Stmt1);
|
||||
const CStyleCastExpr* CastExpr2 = cast<CStyleCastExpr>(Stmt2);
|
||||
|
||||
return CastExpr1->getTypeAsWritten() == CastExpr2->getTypeAsWritten();
|
||||
}
|
||||
case Stmt::ReturnStmtClass: {
|
||||
const ReturnStmt *ReturnStmt1 = cast<ReturnStmt>(Stmt1);
|
||||
const ReturnStmt *ReturnStmt2 = cast<ReturnStmt>(Stmt2);
|
||||
|
||||
return isIdenticalStmt(Ctx, ReturnStmt1->getRetValue(),
|
||||
ReturnStmt2->getRetValue(), IgnoreSideEffects);
|
||||
}
|
||||
case Stmt::ForStmtClass: {
|
||||
const ForStmt *ForStmt1 = cast<ForStmt>(Stmt1);
|
||||
const ForStmt *ForStmt2 = cast<ForStmt>(Stmt2);
|
||||
|
||||
if (!isIdenticalStmt(Ctx, ForStmt1->getInit(), ForStmt2->getInit(),
|
||||
IgnoreSideEffects))
|
||||
return false;
|
||||
if (!isIdenticalStmt(Ctx, ForStmt1->getCond(), ForStmt2->getCond(),
|
||||
IgnoreSideEffects))
|
||||
return false;
|
||||
if (!isIdenticalStmt(Ctx, ForStmt1->getInc(), ForStmt2->getInc(),
|
||||
IgnoreSideEffects))
|
||||
return false;
|
||||
if (!isIdenticalStmt(Ctx, ForStmt1->getBody(), ForStmt2->getBody(),
|
||||
IgnoreSideEffects))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
case Stmt::DoStmtClass: {
|
||||
const DoStmt *DStmt1 = cast<DoStmt>(Stmt1);
|
||||
const DoStmt *DStmt2 = cast<DoStmt>(Stmt2);
|
||||
|
||||
if (!isIdenticalStmt(Ctx, DStmt1->getCond(), DStmt2->getCond(),
|
||||
IgnoreSideEffects))
|
||||
return false;
|
||||
if (!isIdenticalStmt(Ctx, DStmt1->getBody(), DStmt2->getBody(),
|
||||
IgnoreSideEffects))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
case Stmt::WhileStmtClass: {
|
||||
const WhileStmt *WStmt1 = cast<WhileStmt>(Stmt1);
|
||||
const WhileStmt *WStmt2 = cast<WhileStmt>(Stmt2);
|
||||
|
||||
if (!isIdenticalStmt(Ctx, WStmt1->getCond(), WStmt2->getCond(),
|
||||
IgnoreSideEffects))
|
||||
return false;
|
||||
if (!isIdenticalStmt(Ctx, WStmt1->getBody(), WStmt2->getBody(),
|
||||
IgnoreSideEffects))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
case Stmt::IfStmtClass: {
|
||||
const IfStmt *IStmt1 = cast<IfStmt>(Stmt1);
|
||||
const IfStmt *IStmt2 = cast<IfStmt>(Stmt2);
|
||||
|
||||
if (!isIdenticalStmt(Ctx, IStmt1->getCond(), IStmt2->getCond(),
|
||||
IgnoreSideEffects))
|
||||
return false;
|
||||
if (!isIdenticalStmt(Ctx, IStmt1->getThen(), IStmt2->getThen(),
|
||||
IgnoreSideEffects))
|
||||
return false;
|
||||
if (!isIdenticalStmt(Ctx, IStmt1->getElse(), IStmt2->getElse(),
|
||||
IgnoreSideEffects))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
case Stmt::CompoundStmtClass: {
|
||||
const CompoundStmt *CompStmt1 = cast<CompoundStmt>(Stmt1);
|
||||
const CompoundStmt *CompStmt2 = cast<CompoundStmt>(Stmt2);
|
||||
|
||||
if (CompStmt1->size() != CompStmt2->size())
|
||||
return false;
|
||||
|
||||
CompoundStmt::const_body_iterator I1 = CompStmt1->body_begin();
|
||||
CompoundStmt::const_body_iterator I2 = CompStmt2->body_begin();
|
||||
while (I1 != CompStmt1->body_end() && I2 != CompStmt2->body_end()) {
|
||||
if (!isIdenticalStmt(Ctx, *I1, *I2, IgnoreSideEffects))
|
||||
return false;
|
||||
++I1;
|
||||
++I2;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
case Stmt::CompoundAssignOperatorClass:
|
||||
case Stmt::BinaryOperatorClass: {
|
||||
const BinaryOperator *BinOp1 = cast<BinaryOperator>(Stmt1);
|
||||
const BinaryOperator *BinOp2 = cast<BinaryOperator>(Stmt2);
|
||||
return BinOp1->getOpcode() == BinOp2->getOpcode();
|
||||
}
|
||||
case Stmt::CharacterLiteralClass: {
|
||||
const CharacterLiteral *CharLit1 = cast<CharacterLiteral>(Stmt1);
|
||||
const CharacterLiteral *CharLit2 = cast<CharacterLiteral>(Stmt2);
|
||||
return CharLit1->getValue() == CharLit2->getValue();
|
||||
}
|
||||
case Stmt::DeclRefExprClass: {
|
||||
const DeclRefExpr *DeclRef1 = cast<DeclRefExpr>(Stmt1);
|
||||
const DeclRefExpr *DeclRef2 = cast<DeclRefExpr>(Stmt2);
|
||||
return DeclRef1->getDecl() == DeclRef2->getDecl();
|
||||
}
|
||||
case Stmt::IntegerLiteralClass: {
|
||||
const IntegerLiteral *IntLit1 = cast<IntegerLiteral>(Stmt1);
|
||||
const IntegerLiteral *IntLit2 = cast<IntegerLiteral>(Stmt2);
|
||||
|
||||
llvm::APInt I1 = IntLit1->getValue();
|
||||
llvm::APInt I2 = IntLit2->getValue();
|
||||
if (I1.getBitWidth() != I2.getBitWidth())
|
||||
return false;
|
||||
return I1 == I2;
|
||||
}
|
||||
case Stmt::FloatingLiteralClass: {
|
||||
const FloatingLiteral *FloatLit1 = cast<FloatingLiteral>(Stmt1);
|
||||
const FloatingLiteral *FloatLit2 = cast<FloatingLiteral>(Stmt2);
|
||||
return FloatLit1->getValue().bitwiseIsEqual(FloatLit2->getValue());
|
||||
}
|
||||
case Stmt::StringLiteralClass: {
|
||||
const StringLiteral *StringLit1 = cast<StringLiteral>(Stmt1);
|
||||
const StringLiteral *StringLit2 = cast<StringLiteral>(Stmt2);
|
||||
return StringLit1->getBytes() == StringLit2->getBytes();
|
||||
}
|
||||
case Stmt::MemberExprClass: {
|
||||
const MemberExpr *MemberStmt1 = cast<MemberExpr>(Stmt1);
|
||||
const MemberExpr *MemberStmt2 = cast<MemberExpr>(Stmt2);
|
||||
return MemberStmt1->getMemberDecl() == MemberStmt2->getMemberDecl();
|
||||
}
|
||||
case Stmt::UnaryOperatorClass: {
|
||||
const UnaryOperator *UnaryOp1 = cast<UnaryOperator>(Stmt1);
|
||||
const UnaryOperator *UnaryOp2 = cast<UnaryOperator>(Stmt2);
|
||||
return UnaryOp1->getOpcode() == UnaryOp2->getOpcode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// FindIdenticalExprChecker
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace {
|
||||
class FindIdenticalExprChecker : public Checker<check::ASTCodeBody> {
|
||||
public:
|
||||
void checkASTCodeBody(const Decl *D, AnalysisManager &Mgr,
|
||||
BugReporter &BR) const {
|
||||
FindIdenticalExprVisitor Visitor(BR, this, Mgr.getAnalysisDeclContext(D));
|
||||
Visitor.TraverseDecl(const_cast<Decl *>(D));
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
void ento::registerIdenticalExprChecker(CheckerManager &Mgr) {
|
||||
Mgr.registerChecker<FindIdenticalExprChecker>();
|
||||
}
|
||||
|
||||
bool ento::shouldRegisterIdenticalExprChecker(const CheckerManager &mgr) {
|
||||
return true;
|
||||
}
|
||||
Reference in New Issue
Block a user