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) {
116 if (
const CompoundStmt *CS = dyn_cast<CompoundStmt>(Stmt1)) {
117 if (!CS->body_empty()) {
118 const IfStmt *InnerIf = dyn_cast<
IfStmt>(*CS->body_begin());
121 BR.EmitBasicReport(AC->getDecl(),
Checker,
"Identical conditions",
123 "conditions of the inner and outer statements are identical",
136 if (Stmt1 && Stmt2) {
138 const Stmt *Else = Stmt2;
139 while (
const IfStmt *I2 = dyn_cast_or_null<IfStmt>(Else)) {
140 const Expr *Cond2 = I2->getCond();
144 BR.EmitBasicReport(AC->getDecl(),
Checker,
"Identical conditions",
146 "expression is identical to previous condition",
149 Else = I2->getElse();
153 if (!Stmt1 || !Stmt2)
162 if (
const CompoundStmt *CompStmt = dyn_cast<CompoundStmt>(Stmt1)) {
163 if (CompStmt->size() == 1)
164 Stmt1 = CompStmt->body_back();
166 if (
const CompoundStmt *CompStmt = dyn_cast<CompoundStmt>(Stmt2)) {
167 if (CompStmt->size() == 1)
168 Stmt2 = CompStmt->body_back();
174 BR.EmitBasicReport(AC->getDecl(),
Checker,
175 "Identical branches",
177 "true and false branches are identical", ELoc);
182 bool FindIdenticalExprVisitor::VisitBinaryOperator(
const BinaryOperator *B) {
186 checkBitwiseOrLogicalOp(B,
true);
189 checkBitwiseOrLogicalOp(B,
false);
192 checkComparisonOp(B);
200 void FindIdenticalExprVisitor::checkComparisonOp(
const BinaryOperator *B) {
230 if ((DeclRef1) && (DeclRef2)) {
232 (DeclRef2->getType()->hasFloatingRepresentation())) {
233 if (DeclRef1->
getDecl() == DeclRef2->getDecl()) {
234 if ((Op == BO_EQ) || (Op == BO_NE)) {
239 }
else if ((FloatLit1) && (FloatLit2)) {
240 if (FloatLit1->getValue().bitwiseIsEqual(FloatLit2->getValue())) {
241 if ((Op == BO_EQ) || (Op == BO_NE)) {
258 if (((Op == BO_EQ) || (Op == BO_LE) || (Op == BO_GE)))
259 Message =
"comparison of identical expressions always evaluates to true";
261 Message =
"comparison of identical expressions always evaluates to false";
262 BR.EmitBasicReport(AC->getDecl(),
Checker,
263 "Compare of identical expressions",
268 bool FindIdenticalExprVisitor::VisitConditionalOperator(
278 C, BR.getSourceManager());
285 "Identical expressions in conditional expression",
287 "identical expressions on both sides of ':' in conditional expression",
305 const Stmt *Stmt2,
bool IgnoreSideEffects) {
307 if (!Stmt1 || !Stmt2) {
308 return !Stmt1 && !Stmt2;
313 if (Stmt1->getStmtClass() != Stmt2->getStmtClass())
316 const Expr *Expr1 = dyn_cast<
Expr>(Stmt1);
317 const Expr *Expr2 = dyn_cast<
Expr>(Stmt2);
319 if (Expr1 && Expr2) {
330 Expr::const_child_iterator I1 = Expr1->child_begin();
331 Expr::const_child_iterator I2 = Expr2->child_begin();
332 while (I1 != Expr1->child_end() && I2 != Expr2->child_end()) {
333 if (!*I1 || !*I2 || !
isIdenticalStmt(Ctx, *I1, *I2, IgnoreSideEffects))
340 if (I1 != Expr1->child_end())
342 if (I2 != Expr2->child_end())
346 switch (Stmt1->getStmtClass()) {
349 case Stmt::CallExprClass:
350 case Stmt::ArraySubscriptExprClass:
351 case Stmt::OMPArraySectionExprClass:
352 case Stmt::ImplicitCastExprClass:
353 case Stmt::ParenExprClass:
354 case Stmt::BreakStmtClass:
355 case Stmt::ContinueStmtClass:
356 case Stmt::NullStmtClass:
358 case Stmt::CStyleCastExprClass: {
364 case Stmt::ReturnStmtClass: {
365 const ReturnStmt *ReturnStmt1 = cast<ReturnStmt>(Stmt1);
366 const ReturnStmt *ReturnStmt2 = cast<ReturnStmt>(Stmt2);
369 ReturnStmt2->getRetValue(), IgnoreSideEffects);
371 case Stmt::ForStmtClass: {
372 const ForStmt *ForStmt1 = cast<ForStmt>(Stmt1);
373 const ForStmt *ForStmt2 = cast<ForStmt>(Stmt2);
389 case Stmt::DoStmtClass: {
390 const DoStmt *DStmt1 = cast<DoStmt>(Stmt1);
391 const DoStmt *DStmt2 = cast<DoStmt>(Stmt2);
401 case Stmt::WhileStmtClass: {
402 const WhileStmt *WStmt1 = cast<WhileStmt>(Stmt1);
403 const WhileStmt *WStmt2 = cast<WhileStmt>(Stmt2);
413 case Stmt::IfStmtClass: {
414 const IfStmt *IStmt1 = cast<IfStmt>(Stmt1);
415 const IfStmt *IStmt2 = cast<IfStmt>(Stmt2);
428 case Stmt::CompoundStmtClass: {
429 const CompoundStmt *CompStmt1 = cast<CompoundStmt>(Stmt1);
430 const CompoundStmt *CompStmt2 = cast<CompoundStmt>(Stmt2);
432 if (CompStmt1->
size() != CompStmt2->size())
437 while (I1 != CompStmt1->
body_end() && I2 != CompStmt2->body_end()) {
446 case Stmt::CompoundAssignOperatorClass:
447 case Stmt::BinaryOperatorClass: {
450 return BinOp1->
getOpcode() == BinOp2->getOpcode();
452 case Stmt::CharacterLiteralClass: {
455 return CharLit1->
getValue() == CharLit2->getValue();
457 case Stmt::DeclRefExprClass: {
458 const DeclRefExpr *DeclRef1 = cast<DeclRefExpr>(Stmt1);
459 const DeclRefExpr *DeclRef2 = cast<DeclRefExpr>(Stmt2);
460 return DeclRef1->
getDecl() == DeclRef2->getDecl();
462 case Stmt::IntegerLiteralClass: {
466 llvm::APInt I1 = IntLit1->
getValue();
467 llvm::APInt I2 = IntLit2->getValue();
468 if (I1.getBitWidth() != I2.getBitWidth())
472 case Stmt::FloatingLiteralClass: {
475 return FloatLit1->
getValue().bitwiseIsEqual(FloatLit2->getValue());
477 case Stmt::StringLiteralClass: {
478 const StringLiteral *StringLit1 = cast<StringLiteral>(Stmt1);
479 const StringLiteral *StringLit2 = cast<StringLiteral>(Stmt2);
480 return StringLit1->
getBytes() == StringLit2->getBytes();
482 case Stmt::MemberExprClass: {
483 const MemberExpr *MemberStmt1 = cast<MemberExpr>(Stmt1);
484 const MemberExpr *MemberStmt2 = cast<MemberExpr>(Stmt2);
485 return MemberStmt1->
getMemberDecl() == MemberStmt2->getMemberDecl();
487 case Stmt::UnaryOperatorClass: {
490 return UnaryOp1->
getOpcode() == UnaryOp2->getOpcode();
500 class FindIdenticalExprChecker :
public Checker<check::ASTCodeBody> {
505 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.
IfStmt - This represents an if/then/else.
const Stmt * getElse() const
bool HasSideEffects(const ASTContext &Ctx, bool IncludePossibleEffects=true) const
HasSideEffects - This routine returns true for all those expressions which have any effect other than...
unsigned getValue() const
bool isComparisonOp() const
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
AnalysisDeclContext contains the context data for the function or method under analysis.
const char *const LogicError
ForStmt - This represents a 'for (init;cond;inc)' stmt.
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
getTypeAsWritten - Returns the type that this expression is casting to, as written in the source code...
A class that does preordor or postorder depth-first traversal on the entire Clang AST and visits each...
detail::InMemoryDirectory::const_iterator I
AnalysisDeclContext * getAnalysisDeclContext(const Decl *D)
ConditionalOperator - The ?: ternary operator.
Expr * getFalseExpr() const
llvm::APInt getValue() const
CompoundStmt - This represents a group of statements like { stmt stmt }.
Expr - This represents one expression.
ReturnStmt - This represents a return, optionally of an expression: return; return 4;...
UnaryOperator - This represents the unary-expression's (except sizeof and alignof), the postinc/postdec operators from postfix-expression, and various extensions.
CStyleCastExpr - An explicit cast in C (C99 6.5.4) or a C-style cast in C++ (C++ [expr.cast]), which uses the syntax (Type)expr.
Expr * getTrueExpr() const
DoStmt - This represents a 'do/while' stmt.
BugReporter is a utility class for generating PathDiagnostics for analysis.
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
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
StringRef getBytes() const
Allow access to clients that need the byte representation, such as ASTWriterStmt::VisitStringLiteral(...
const Expr * getRetValue() const
body_iterator body_begin()
Stmt *const * const_body_iterator
llvm::APFloat getValue() const
Expr * IgnoreParenImpCasts() LLVM_READONLY
IgnoreParenImpCasts - Ignore parentheses and implicit casts.
const Stmt * getThen() const
static PathDiagnosticLocation createOperatorLoc(const BinaryOperator *BO, const SourceManager &SM)
Create the location for the operator of the binary expression.
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
WhileStmt - This represents a 'while' stmt.
const Expr * getCond() const
StringLiteral - This represents a string literal expression, e.g.
A reference to a declared variable, function, enum, etc.
A trivial tuple used to represent a source range.