[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