[clang] [clang-tools-extra] [analyzer] Remove alpha.core.IdenticalExpr Checker (PR #114715)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Nov 8 07:58:29 PST 2024
https://github.com/vabridgers updated https://github.com/llvm/llvm-project/pull/114715
>From d20240f0c38a33707ba773a0f49081f076e5421b Mon Sep 17 00:00:00 2001
From: Vince Bridgers <vince.a.bridgers at ericsson.com>
Date: Thu, 7 Nov 2024 01:58:21 +0100
Subject: [PATCH] [analyzer] Port alpha.core.IdenticalExpr to Tidy checks and
remove
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. The
existing LIT test was checked case by case, and the tidy checks
were improved to maintain alpha.core.IdenticalExpr features.
---
.../clang-tidy/bugprone/BranchCloneCheck.cpp | 220 ++++++++
.../misc/RedundantExpressionCheck.cpp | 76 ++-
.../bugprone/alpha-core-identicalexpr.cpp | 329 ++++++++---
clang/docs/ReleaseNotes.rst | 6 +
clang/docs/analyzer/checkers.rst | 30 -
.../clang/StaticAnalyzer/Checkers/Checkers.td | 4 -
.../StaticAnalyzer/Checkers/CMakeLists.txt | 1 -
.../Checkers/IdenticalExprChecker.cpp | 520 ------------------
8 files changed, 529 insertions(+), 657 deletions(-)
rename clang/test/Analysis/identical-expressions.cpp => clang-tools-extra/test/clang-tidy/checkers/bugprone/alpha-core-identicalexpr.cpp (60%)
delete mode 100644 clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp
diff --git a/clang-tools-extra/clang-tidy/bugprone/BranchCloneCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/BranchCloneCheck.cpp
index 356acf968db921..dc7ff50194f04c 100644
--- a/clang-tools-extra/clang-tidy/bugprone/BranchCloneCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/BranchCloneCheck.cpp
@@ -102,6 +102,209 @@ void BranchCloneCheck::registerMatchers(MatchFinder *Finder) {
this);
Finder->addMatcher(switchStmt().bind("switch"), this);
Finder->addMatcher(conditionalOperator().bind("condOp"), this);
+ Finder->addMatcher(ifStmt(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))
+ 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 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 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();
+ }
+ }
}
void BranchCloneCheck::check(const MatchFinder::MatchResult &Result) {
@@ -269,6 +472,23 @@ void BranchCloneCheck::check(const MatchFinder::MatchResult &Result) {
return;
}
+ if (const auto *IS = Result.Nodes.getNodeAs<IfStmt>("ifWithDescendantIf")) {
+ const Stmt *Then = IS->getThen();
+ if (const CompoundStmt *CS = dyn_cast<CompoundStmt>(Then)) {
+ if (!CS->body_empty()) {
+ const IfStmt *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.");
}
diff --git a/clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp b/clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
index 6bb9a349d69b13..84ca357995a2c4 100644
--- a/clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
+++ b/clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
@@ -866,19 +866,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 +1235,59 @@ 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();
+ BinaryOperator::Opcode Op = BinOp->getOpcode();
+
+ 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)) {
+ 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 (areSidesBinaryConstExpressions(BinOp, Result.Context)) {
const Expr *LhsConst = nullptr, *RhsConst = nullptr;
BinaryOperatorKind MainOpcode{}, SideOpcode{};
diff --git a/clang/test/Analysis/identical-expressions.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/alpha-core-identicalexpr.cpp
similarity index 60%
rename from clang/test/Analysis/identical-expressions.cpp
rename to clang-tools-extra/test/clang-tidy/checkers/bugprone/alpha-core-identicalexpr.cpp
index 8bb82372b534ad..bef3ee049afefd 100644
--- a/clang/test/Analysis/identical-expressions.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/alpha-core-identicalexpr.cpp
@@ -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=IDENTEXPR
+// RUN: clang-tidy %s -checks="-*,bugprone-branch-clone" -- 2>&1 | FileCheck %s --check-prefix=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);
+ // 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: :[[@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);
+ // 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);
+ // 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);
+ // 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);
+ // 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));
+ // 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)));
+ // 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);
+ // 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);
+ // 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);
+ // 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));
+ // 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);
+ // 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);
+ // 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: :[[@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);
+ // 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);
+ // 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);
+ // 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);
+ // 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));
+ // 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)));
+ // 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: :[[@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: :[[@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);
+ // 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: :[[@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);
+ // 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);
+ // 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);
+ // 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));
+ // 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)));
+ // IDENTEXPR: :[[@LINE-1]]:58: warning: both sides of operator are equivalent [misc-redundant-expression]
return (0);
}
@@ -826,6 +857,7 @@ int checkLessThanNestedBinaryOpIntCompare3(void) {
int checkGreaterThanFloatLiteralCompare1(void) {
return (5.14F > 5.14F); // expected-warning {{comparison of identical expressions always evaluates to false}}
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: both sides of operator are equivalent [misc-redundant-expression]
}
int checkGreaterThanFloatLiteralCompare2(void) {
@@ -842,6 +874,7 @@ int checkGreaterThanFloatDeclCompare1(void) {
int checkGreaterThanFloatDeclCompare12(void) {
float f = 7.1F;
return (f > f); // expected-warning {{comparison of identical expressions always evaluates to false}}
+ // CHECK-MESSAGES: :[[@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: :[[@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: :[[@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);
+ // 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);
+ // 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);
+ // 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));
+ // 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)));
+ // 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;
+ // IDENTEXPR: :[[@LINE-1]]:17: warning: 'true' and 'false' expressions are equivalent [misc-redundant-expression]
+ // 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;
+ // IDENTEXPR: :[[@LINE-1]]:17: warning: 'true' and 'false' expressions are equivalent [misc-redundant-expression]
+ // 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;
+ // IDENTEXPR: :[[@LINE-1]]:17: warning: 'true' and 'false' expressions are equivalent [misc-redundant-expression]
+ // 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;
+ // IDENTEXPR: :[[@LINE-1]]:17: warning: 'true' and 'false' expressions are equivalent [misc-redundant-expression]
+ // 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";
+ // IDENTEXPR: :[[@LINE-1]]:24: warning: 'true' and 'false' expressions are equivalent [misc-redundant-expression]
+ // 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;
+ // IDENTEXPR: :[[@LINE-1]]:19: warning: 'true' and 'false' expressions are equivalent [misc-redundant-expression]
+ // 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;
+ // IDENTEXPR: :[[@LINE-1]]:19: warning: 'true' and 'false' expressions are equivalent [misc-redundant-expression]
+ // 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;
+ // IDENTEXPR: :[[@LINE-1]]:20: warning: 'true' and 'false' expressions are equivalent [misc-redundant-expression]
+ // 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;
+ // IDENTEXPR: :[[@LINE-1]]:19: warning: 'true' and 'false' expressions are equivalent [misc-redundant-expression]
+ // 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();
+ // IDENTEXPR: :[[@LINE-1]]:24: warning: 'true' and 'false' expressions are equivalent [misc-redundant-expression]
+ // 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);
+ // IDENTEXPR: :[[@LINE-1]]:30: warning: 'true' and 'false' expressions are equivalent [misc-redundant-expression]
+ // 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++;
+ // 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;
+ // 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));
+ // IDENTEXPR: :[[@LINE-1]]:39: warning: 'true' and 'false' expressions are equivalent [misc-redundant-expression]
+ // 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);
+ // IDENTEXPR: :[[@LINE-1]]:44: warning: 'true' and 'false' expressions are equivalent [misc-redundant-expression]
+ // 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) {
+ // BUGPRONEBRANCH: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone]
++i;
} else {
+ // 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) {
+ // BUGPRONEBRANCH: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone]
++i;
} else
+ // 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) {
+ // BUGPRONEBRANCH: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone]
} else {
+ // 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)
+ // BUGPRONEBRANCH: :[[@LINE-1]]:5: warning: if with identical then and else branches [bugprone-branch-clone]
break;
else
+ // 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)
+ // BUGPRONEBRANCH: :[[@LINE-1]]:5: warning: if with identical then and else branches [bugprone-branch-clone]
continue;
else
+ // 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)
+ // BUGPRONEBRANCH: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone]
func();
else
+ // 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)
+ // BUGPRONEBRANCH: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone]
v = (signed int) v;
else
+ // 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) {
+ // BUGPRONEBRANCH: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone]
i++;
return i;
} else {
+ // 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) {
+ // BUGPRONEBRANCH: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone]
return func();
} else {
+ // 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) {
+ // 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 {
+ // 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) {
+ // BUGPRONEBRANCH: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone]
while (func())
i--;
} else {
+ // 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) {
+ // BUGPRONEBRANCH: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone]
do {
i--;
} while (func());
} else {
+ // 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) {
+ // BUGPRONEBRANCH: :[[@LINE-1]]:3: warning: if with identical then and else branches [bugprone-branch-clone]
if (i < 5)
i += 10;
} else {
+ // 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;
+ // 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;
+ // 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);
+ // 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;
+ // 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();
+ // 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)
+ // 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)
+ // 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)
+ // 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}}
+ // BUGPRONEBRANCH: :[[@LINE-1]]:5: warning: repeated branch body in conditional chain [bugprone-branch-clone]
+ // BUGPRONEBRANCH: :[[@LINE-2]]:6: note: end of the original
+ else if (x == 1)
;
+ // 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}}
+ // BUGPRONEBRANCH: :[[@LINE-1]]:5: warning: repeated branch body in conditional chain [bugprone-branch-clone]
+ // 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}}
+ // BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 1 starts here
+ else if (x == 1)
;
+ // BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 2 starts here
}
void test_warn_chained_if_stmts_3(int x) {
if (x == 1)
;
+ // BUGPRONEBRANCH: :[[@LINE-1]]:5: warning: repeated branch body in conditional chain [bugprone-branch-clone]
+ // 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}}
+ // BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 1 starts here
+ else if (x == 1)
;
+ // BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 2 starts here
}
void test_warn_chained_if_stmts_4(int x) {
if (x == 1)
;
+ // BUGPRONEBRANCH: :[[@LINE-1]]:5: warning: repeated branch body in conditional chain [bugprone-branch-clone]
+ // BUGPRONEBRANCH: :[[@LINE-2]]:6: note: end of the original
else if (func())
;
- else if (x == 1) // expected-warning {{expression is identical to previous condition}}
+ // BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 1 starts here
+ else if (x == 1)
;
+ // 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}}
+ // BUGPRONEBRANCH: :[[@LINE-1]]:5: warning: repeated branch body in conditional chain [bugprone-branch-clone]
+ // BUGPRONEBRANCH: :[[@LINE-2]]:6: note: end of the original
+ else if (x & 1)
;
+ // BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 1 starts here
}
void test_warn_chained_if_stmts_6(int x) {
if (x == 1)
;
+ // BUGPRONEBRANCH: :[[@LINE-1]]:5: warning: repeated branch body in conditional chain [bugprone-branch-clone]
+ // 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}}
+ // BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 1 starts here
+ else if (x == 2)
;
+ // 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)
;
+ // BUGPRONEBRANCH: :[[@LINE-1]]:5: warning: repeated branch body in conditional chain [bugprone-branch-clone]
+ // BUGPRONEBRANCH: :[[@LINE-2]]:6: note: end of the original
else if (x == 2)
;
+ // 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}}
+ // BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 2 starts here
+ else if (x == 2)
;
+ // BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 3 starts here
else if (x == 5)
;
+ // BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 4 starts here
}
void test_warn_chained_if_stmts_8(int x) {
if (x == 1)
;
+ // BUGPRONEBRANCH: :[[@LINE-1]]:5: warning: repeated branch body in conditional chain [bugprone-branch-clone]
+ // BUGPRONEBRANCH: :[[@LINE-2]]:6: note: end of the original
else if (x == 2)
;
+ // 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}}
+ // BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 2 starts here
+ else if (x == 2)
;
+ // 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}}
+ // BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 4 starts here
+ else if (x == 3)
;
+ // BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 5 starts here
else if (x == 7)
;
+ // 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
+ // BUGPRONEBRANCH: :[[@LINE-1]]:5: warning: repeated branch body in conditional chain [bugprone-branch-clone]
+ // BUGPRONEBRANCH: :[[@LINE-2]]:6: note: end of the original
+ else if (func())
;
+ // BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 1 starts here
}
void test_nowarn_chained_if_stmts_2(int x) {
if (func())
;
+ // BUGPRONEBRANCH: :[[@LINE-1]]:5: warning: repeated branch body in conditional chain [bugprone-branch-clone]
+ // BUGPRONEBRANCH: :[[@LINE-2]]:6: note: end of the original
else if (x == 1)
;
- else if (func()) // no-warning
+ // BUGPRONEBRANCH: :[[@LINE-1]]:5: note: clone 1 starts here
+ else if (func())
;
+ // 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
+ // BUGPRONEBRANCH: :[[@LINE-1]]:5: warning: repeated branch body in conditional chain [bugprone-branch-clone]
+ // BUGPRONEBRANCH: :[[@LINE-2]]:6: note: end of the original
+ else if (x++)
;
+ // 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";
+ // 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) {
+ // BUGPRONEBRANCH: :[[@LINE-1]]:3: warning: if with identical inner if statement [bugprone-branch-clone]
if (x == 1) // expected-warning {{conditions of the inner and outer statements are identical}}
+ // BUGPRONEBRANCH: :[[@LINE-1]]:5: note: inner if starts here
;
}
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index d0c43ff11f7bae..947deda35910f5 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -862,6 +862,12 @@ Improvements
Moved checkers
^^^^^^^^^^^^^^
+- The checker ``alpha.core.IdenticalExpr`` was removed because it was
+ duplicated in the clang-tidy checkers ``misc-redundant-expression`` and
+ ``bugprone-branch-clone``. ``alpha.core.IdenticalExpr`` was implemented
+ by using AST matching and did not make sense to remain as an alpha
+ static analysis checker.
+
- 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
diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst
index f34b25cd04bd18..a5e31fda13ed24 100644
--- a/clang/docs/analyzer/checkers.rst
+++ b/clang/docs/analyzer/checkers.rst
@@ -2788,36 +2788,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)
diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
index b03e707d638742..232217d9d15b96 100644
--- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
+++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
@@ -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>;
diff --git a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
index f40318f46dea1a..2b15d31053cf40 100644
--- a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
+++ b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
@@ -50,7 +50,6 @@ add_clang_library(clangStaticAnalyzerCheckers
GCDAntipatternChecker.cpp
GenericTaintChecker.cpp
GTestChecker.cpp
- IdenticalExprChecker.cpp
InnerPointerChecker.cpp
InvalidatedIteratorChecker.cpp
cert/InvalidPtrChecker.cpp
diff --git a/clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp
deleted file mode 100644
index 7ac34ef8164e4c..00000000000000
--- a/clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp
+++ /dev/null
@@ -1,520 +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/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
-#include "clang/AST/RecursiveASTVisitor.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 RecursiveASTVisitor<FindIdenticalExprVisitor> {
- 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(const BinaryOperator *B);
- bool VisitIfStmt(const IfStmt *I);
- bool VisitConditionalOperator(const ConditionalOperator *C);
-
-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(const 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(const 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(
- const 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;
-}
More information about the cfe-commits
mailing list