26 using namespace clang;
30 const Stmt *Stmt2,
bool IgnoreSideEffects =
false);
36 class FindIdenticalExprVisitor
45 : BR(B), Checker(Checker), AC(A) {}
50 bool VisitIfStmt(
const IfStmt *I);
54 void reportIdenticalExpr(
const BinaryOperator *B,
bool CheckBitwise,
56 void checkBitwiseOrLogicalOp(
const BinaryOperator *B,
bool CheckBitwise);
61 void FindIdenticalExprVisitor::reportIdenticalExpr(
const BinaryOperator *B,
66 Message =
"identical expressions on both sides of bitwise operator";
68 Message =
"identical expressions on both sides of logical operator";
72 BR.EmitBasicReport(AC->getDecl(),
Checker,
73 "Use of identical expressions",
78 void FindIdenticalExprVisitor::checkBitwiseOrLogicalOp(
const BinaryOperator *B,
93 Sr[0] = RHS->getSourceRange();
94 Sr[1] = B2->getRHS()->getSourceRange();
95 reportIdenticalExpr(B, CheckBitwise, Sr);
101 Sr[0] = RHS->getSourceRange();
102 Sr[1] = LHS->getSourceRange();
103 reportIdenticalExpr(B, CheckBitwise, Sr);
107 bool FindIdenticalExprVisitor::VisitIfStmt(
const IfStmt *I) {
118 if (Stmt1 && Stmt2) {
120 const Stmt *Else = Stmt2;
121 while (
const IfStmt *I2 = dyn_cast_or_null<IfStmt>(Else)) {
122 const Expr *Cond2 = I2->getCond();
126 BR.EmitBasicReport(AC->getDecl(),
Checker,
"Identical conditions",
128 "expression is identical to previous condition",
131 Else = I2->getElse();
135 if (!Stmt1 || !Stmt2)
144 if (
const CompoundStmt *CompStmt = dyn_cast<CompoundStmt>(Stmt1)) {
145 if (CompStmt->size() == 1)
146 Stmt1 = CompStmt->body_back();
148 if (
const CompoundStmt *CompStmt = dyn_cast<CompoundStmt>(Stmt2)) {
149 if (CompStmt->size() == 1)
150 Stmt2 = CompStmt->body_back();
156 BR.EmitBasicReport(AC->getDecl(),
Checker,
157 "Identical branches",
159 "true and false branches are identical", ELoc);
164 bool FindIdenticalExprVisitor::VisitBinaryOperator(
const BinaryOperator *B) {
168 checkBitwiseOrLogicalOp(B,
true);
171 checkBitwiseOrLogicalOp(B,
false);
174 checkComparisonOp(B);
182 void FindIdenticalExprVisitor::checkComparisonOp(
const BinaryOperator *B) {
212 if ((DeclRef1) && (DeclRef2)) {
214 (DeclRef2->getType()->hasFloatingRepresentation())) {
215 if (DeclRef1->
getDecl() == DeclRef2->getDecl()) {
221 }
else if ((FloatLit1) && (FloatLit2)) {
222 if (FloatLit1->getValue().bitwiseIsEqual(FloatLit2->getValue())) {
241 Message =
"comparison of identical expressions always evaluates to true";
243 Message =
"comparison of identical expressions always evaluates to false";
244 BR.EmitBasicReport(AC->getDecl(),
Checker,
245 "Compare of identical expressions",
250 bool FindIdenticalExprVisitor::VisitConditionalOperator(
260 C, BR.getSourceManager());
267 "Identical expressions in conditional expression",
269 "identical expressions on both sides of ':' in conditional expression",
287 const Stmt *Stmt2,
bool IgnoreSideEffects) {
289 if (!Stmt1 || !Stmt2) {
290 if (!Stmt1 && !Stmt2)
297 if (Stmt1->getStmtClass() != Stmt2->getStmtClass())
300 const Expr *Expr1 = dyn_cast<
Expr>(Stmt1);
301 const Expr *Expr2 = dyn_cast<
Expr>(Stmt2);
303 if (Expr1 && Expr2) {
314 Expr::const_child_iterator I1 = Expr1->child_begin();
315 Expr::const_child_iterator I2 = Expr2->child_begin();
316 while (I1 != Expr1->child_end() && I2 != Expr2->child_end()) {
317 if (!*I1 || !*I2 || !
isIdenticalStmt(Ctx, *I1, *I2, IgnoreSideEffects))
324 if (I1 != Expr1->child_end())
326 if (I2 != Expr2->child_end())
330 switch (Stmt1->getStmtClass()) {
333 case Stmt::CallExprClass:
334 case Stmt::ArraySubscriptExprClass:
335 case Stmt::ImplicitCastExprClass:
336 case Stmt::ParenExprClass:
337 case Stmt::BreakStmtClass:
338 case Stmt::ContinueStmtClass:
339 case Stmt::NullStmtClass:
341 case Stmt::CStyleCastExprClass: {
347 case Stmt::ReturnStmtClass: {
348 const ReturnStmt *ReturnStmt1 = cast<ReturnStmt>(Stmt1);
349 const ReturnStmt *ReturnStmt2 = cast<ReturnStmt>(Stmt2);
352 ReturnStmt2->getRetValue(), IgnoreSideEffects);
354 case Stmt::ForStmtClass: {
355 const ForStmt *ForStmt1 = cast<ForStmt>(Stmt1);
356 const ForStmt *ForStmt2 = cast<ForStmt>(Stmt2);
372 case Stmt::DoStmtClass: {
373 const DoStmt *DStmt1 = cast<DoStmt>(Stmt1);
374 const DoStmt *DStmt2 = cast<DoStmt>(Stmt2);
384 case Stmt::WhileStmtClass: {
385 const WhileStmt *WStmt1 = cast<WhileStmt>(Stmt1);
386 const WhileStmt *WStmt2 = cast<WhileStmt>(Stmt2);
396 case Stmt::IfStmtClass: {
397 const IfStmt *IStmt1 = cast<IfStmt>(Stmt1);
398 const IfStmt *IStmt2 = cast<IfStmt>(Stmt2);
411 case Stmt::CompoundStmtClass: {
412 const CompoundStmt *CompStmt1 = cast<CompoundStmt>(Stmt1);
413 const CompoundStmt *CompStmt2 = cast<CompoundStmt>(Stmt2);
415 if (CompStmt1->
size() != CompStmt2->size())
420 while (I1 != CompStmt1->
body_end() && I2 != CompStmt2->body_end()) {
429 case Stmt::CompoundAssignOperatorClass:
430 case Stmt::BinaryOperatorClass: {
433 return BinOp1->
getOpcode() == BinOp2->getOpcode();
435 case Stmt::CharacterLiteralClass: {
438 return CharLit1->
getValue() == CharLit2->getValue();
440 case Stmt::DeclRefExprClass: {
441 const DeclRefExpr *DeclRef1 = cast<DeclRefExpr>(Stmt1);
442 const DeclRefExpr *DeclRef2 = cast<DeclRefExpr>(Stmt2);
443 return DeclRef1->
getDecl() == DeclRef2->getDecl();
445 case Stmt::IntegerLiteralClass: {
449 llvm::APInt I1 = IntLit1->
getValue();
450 llvm::APInt I2 = IntLit2->getValue();
451 if (I1.getBitWidth() != I2.getBitWidth())
455 case Stmt::FloatingLiteralClass: {
458 return FloatLit1->
getValue().bitwiseIsEqual(FloatLit2->getValue());
460 case Stmt::StringLiteralClass: {
461 const StringLiteral *StringLit1 = cast<StringLiteral>(Stmt1);
462 const StringLiteral *StringLit2 = cast<StringLiteral>(Stmt2);
463 return StringLit1->
getBytes() == StringLit2->getBytes();
465 case Stmt::MemberExprClass: {
466 const MemberExpr *MemberStmt1 = cast<MemberExpr>(Stmt1);
467 const MemberExpr *MemberStmt2 = cast<MemberExpr>(Stmt2);
468 return MemberStmt1->
getMemberDecl() == MemberStmt2->getMemberDecl();
470 case Stmt::UnaryOperatorClass: {
473 return UnaryOp1->
getOpcode() == UnaryOp2->getOpcode();
483 class FindIdenticalExprChecker :
public Checker<check::ASTCodeBody> {
488 Visitor.TraverseDecl(const_cast<Decl *>(D));
ValueDecl * getMemberDecl() const
Retrieve the member declaration to which this expression refers.
bool hasFloatingRepresentation() const
Determine whether this type has a floating-point representation of some sort, e.g., it is a floating-point type or a vector thereof.
const Stmt * getElse() const
bool HasSideEffects(const ASTContext &Ctx, bool IncludePossibleEffects=true) const
unsigned getValue() const
bool isComparisonOp() const
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
const char *const LogicError
static bool isIdenticalStmt(const ASTContext &Ctx, const Stmt *Stmt1, const Stmt *Stmt2, bool IgnoreSideEffects=false)
Determines whether two statement trees are identical regarding operators and symbols.
A builtin binary operation expression such as "x + y" or "x <= y".
QualType getTypeAsWritten() const
A class that does preorder depth-first traversal on the entire Clang AST and visits each node...
AnalysisDeclContext * getAnalysisDeclContext(const Decl *D)
Expr * getFalseExpr() const
llvm::APInt getValue() const
Expr * getTrueExpr() const
static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)
Create a location for the beginning of the declaration.
CHECKER * registerChecker()
Used to register checkers.
static PathDiagnosticLocation createConditionalColonLoc(const ConditionalOperator *CO, const SourceManager &SM)
SourceLocation getExprLoc() const LLVM_READONLY
StringRef getBytes() const
const Expr * getRetValue() const
body_iterator body_begin()
Stmt *const * const_body_iterator
llvm::APFloat getValue() const
Expr * IgnoreParenImpCasts() LLVM_READONLY
const Stmt * getThen() const
static PathDiagnosticLocation createOperatorLoc(const BinaryOperator *BO, const SourceManager &SM)
const Expr * getCond() const
A reference to a declared variable, function, enum, etc. [C99 6.5.1p2].
A trivial tuple used to represent a source range.