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,
94 Sr[1] = B2->getRHS()->getSourceRange();
95 reportIdenticalExpr(B, CheckBitwise, Sr);
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)) {
259 Message =
"comparison of identical expressions always evaluates to " 261 else if (((Op == BO_EQ) || (Op == BO_LE) || (Op == BO_GE)))
262 Message =
"comparison of identical expressions always evaluates to true";
264 Message =
"comparison of identical expressions always evaluates to false";
265 BR.EmitBasicReport(AC->getDecl(),
Checker,
266 "Compare of identical expressions",
271 bool FindIdenticalExprVisitor::VisitConditionalOperator(
281 C, BR.getSourceManager());
288 "Identical expressions in conditional expression",
290 "identical expressions on both sides of ':' in conditional expression",
308 const Stmt *Stmt2,
bool IgnoreSideEffects) {
310 if (!Stmt1 || !Stmt2) {
311 return !Stmt1 && !Stmt2;
319 const Expr *Expr1 = dyn_cast<
Expr>(Stmt1);
320 const Expr *Expr2 = dyn_cast<
Expr>(Stmt2);
322 if (Expr1 && Expr2) {
335 while (I1 != Expr1->
child_end() && I2 != Expr2->child_end()) {
336 if (!*I1 || !*I2 || !
isIdenticalStmt(Ctx, *I1, *I2, IgnoreSideEffects))
345 if (I2 != Expr2->child_end())
352 case Stmt::CallExprClass:
353 case Stmt::ArraySubscriptExprClass:
354 case Stmt::OMPArraySectionExprClass:
355 case Stmt::ImplicitCastExprClass:
356 case Stmt::ParenExprClass:
357 case Stmt::BreakStmtClass:
358 case Stmt::ContinueStmtClass:
359 case Stmt::NullStmtClass:
361 case Stmt::CStyleCastExprClass: {
367 case Stmt::ReturnStmtClass: {
368 const ReturnStmt *ReturnStmt1 = cast<ReturnStmt>(Stmt1);
369 const ReturnStmt *ReturnStmt2 = cast<ReturnStmt>(Stmt2);
372 ReturnStmt2->getRetValue(), IgnoreSideEffects);
374 case Stmt::ForStmtClass: {
375 const ForStmt *ForStmt1 = cast<ForStmt>(Stmt1);
376 const ForStmt *ForStmt2 = cast<ForStmt>(Stmt2);
392 case Stmt::DoStmtClass: {
393 const DoStmt *DStmt1 = cast<DoStmt>(Stmt1);
394 const DoStmt *DStmt2 = cast<DoStmt>(Stmt2);
404 case Stmt::WhileStmtClass: {
405 const WhileStmt *WStmt1 = cast<WhileStmt>(Stmt1);
406 const WhileStmt *WStmt2 = cast<WhileStmt>(Stmt2);
416 case Stmt::IfStmtClass: {
417 const IfStmt *IStmt1 = cast<IfStmt>(Stmt1);
418 const IfStmt *IStmt2 = cast<IfStmt>(Stmt2);
431 case Stmt::CompoundStmtClass: {
432 const CompoundStmt *CompStmt1 = cast<CompoundStmt>(Stmt1);
433 const CompoundStmt *CompStmt2 = cast<CompoundStmt>(Stmt2);
435 if (CompStmt1->
size() != CompStmt2->size())
440 while (I1 != CompStmt1->
body_end() && I2 != CompStmt2->body_end()) {
449 case Stmt::CompoundAssignOperatorClass:
450 case Stmt::BinaryOperatorClass: {
453 return BinOp1->
getOpcode() == BinOp2->getOpcode();
455 case Stmt::CharacterLiteralClass: {
458 return CharLit1->
getValue() == CharLit2->getValue();
460 case Stmt::DeclRefExprClass: {
461 const DeclRefExpr *DeclRef1 = cast<DeclRefExpr>(Stmt1);
462 const DeclRefExpr *DeclRef2 = cast<DeclRefExpr>(Stmt2);
463 return DeclRef1->
getDecl() == DeclRef2->getDecl();
465 case Stmt::IntegerLiteralClass: {
469 llvm::APInt I1 = IntLit1->
getValue();
470 llvm::APInt I2 = IntLit2->getValue();
471 if (I1.getBitWidth() != I2.getBitWidth())
475 case Stmt::FloatingLiteralClass: {
478 return FloatLit1->
getValue().bitwiseIsEqual(FloatLit2->getValue());
480 case Stmt::StringLiteralClass: {
481 const StringLiteral *StringLit1 = cast<StringLiteral>(Stmt1);
482 const StringLiteral *StringLit2 = cast<StringLiteral>(Stmt2);
483 return StringLit1->
getBytes() == StringLit2->getBytes();
485 case Stmt::MemberExprClass: {
486 const MemberExpr *MemberStmt1 = cast<MemberExpr>(Stmt1);
487 const MemberExpr *MemberStmt2 = cast<MemberExpr>(Stmt2);
488 return MemberStmt1->
getMemberDecl() == MemberStmt2->getMemberDecl();
490 case Stmt::UnaryOperatorClass: {
493 return UnaryOp1->
getOpcode() == UnaryOp2->getOpcode();
503 class FindIdenticalExprChecker :
public Checker<check::ASTCodeBody> {
508 Visitor.TraverseDecl(const_cast<Decl *>(D));
child_iterator child_begin()
const Stmt * getElse() const
ValueDecl * getMemberDecl() const
Retrieve the member declaration to which this expression refers.
Stmt - This represents one statement.
IfStmt - This represents an if/then/else.
Decl - This represents one declaration (or definition), e.g.
llvm::APFloat getValue() const
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.
Expr * getFalseExpr() 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 Expr * getRetValue() const
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".
A class that does preorder or postorder depth-first traversal on the entire Clang AST and visits each...
AnalysisDeclContext * getAnalysisDeclContext(const Decl *D)
QualType getTypeAsWritten() const
getTypeAsWritten - Returns the type that this expression is casting to, as written in the source code...
ConditionalOperator - The ?: ternary operator.
CompoundStmt - This represents a group of statements like { stmt stmt }.
ConstStmtIterator const_child_iterator
unsigned getValue() 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...
Expr - This represents one expression.
const Stmt * getThen() const
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.
Stmt *const * const_body_iterator
DoStmt - This represents a 'do/while' stmt.
bool isComparisonOp() const
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...
Dataflow Directional Tag Classes.
StmtClass getStmtClass() const
body_iterator body_begin()
Expr * IgnoreParenImpCasts() LLVM_READONLY
IgnoreParenImpCasts - Ignore parentheses and implicit casts.
llvm::APInt getValue() const
StringRef getBytes() const
Allow access to clients that need the byte representation, such as ASTWriterStmt::VisitStringLiteral(...
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.
Expr * getTrueExpr() const
WhileStmt - This represents a 'while' stmt.
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
StringLiteral - This represents a string literal expression, e.g.
A reference to a declared variable, function, enum, etc.
const Expr * getCond() const
A trivial tuple used to represent a source range.
child_iterator child_end()