https://github.com/vabridgers updated https://github.com/llvm/llvm-project/pull/114715
>From 2834ec4708bfd54bafd28e5d55f5610bcd8593c8 Mon Sep 17 00:00:00 2001 From: Vince Bridgers <vince.a.bridg...@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..83f181dedec57e 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 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(); + } + } } 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..cab7a20105ab51 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 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 (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; -} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits