25 using namespace clang;
29 const Stmt *Stmt2,
bool IgnoreSideEffects =
false);
35 class FindIdenticalExprVisitor
38 const CheckerBase *Checker;
41 explicit FindIdenticalExprVisitor(BugReporter &B,
42 const CheckerBase *Checker,
44 : BR(B), Checker(Checker), AC(A) {}
49 bool VisitIfStmt(
const IfStmt *I);
53 void reportIdenticalExpr(
const BinaryOperator *B,
bool CheckBitwise,
55 void checkBitwiseOrLogicalOp(
const BinaryOperator *B,
bool CheckBitwise);
60 void FindIdenticalExprVisitor::reportIdenticalExpr(
const BinaryOperator *B,
65 Message =
"identical expressions on both sides of bitwise operator";
67 Message =
"identical expressions on both sides of logical operator";
69 PathDiagnosticLocation ELoc =
71 BR.EmitBasicReport(AC->getDecl(), Checker,
72 "Use of identical expressions",
77 void FindIdenticalExprVisitor::checkBitwiseOrLogicalOp(
const BinaryOperator *B,
93 Sr[1] = B2->getRHS()->getSourceRange();
94 reportIdenticalExpr(B, CheckBitwise, Sr);
102 reportIdenticalExpr(B, CheckBitwise, Sr);
106 bool FindIdenticalExprVisitor::VisitIfStmt(
const IfStmt *I) {
115 if (
const CompoundStmt *CS = dyn_cast<CompoundStmt>(Stmt1)) {
116 if (!CS->body_empty()) {
117 const IfStmt *InnerIf = dyn_cast<
IfStmt>(*CS->body_begin());
119 PathDiagnosticLocation ELoc(InnerIf->
getCond(), BR.getSourceManager(), AC);
120 BR.EmitBasicReport(AC->getDecl(), Checker,
"Identical conditions",
122 "conditions of the inner and outer statements are identical",
135 if (Stmt1 && Stmt2) {
137 const Stmt *Else = Stmt2;
138 while (
const IfStmt *I2 = dyn_cast_or_null<IfStmt>(Else)) {
139 const Expr *Cond2 = I2->getCond();
142 PathDiagnosticLocation ELoc(Cond2, BR.getSourceManager(), AC);
143 BR.EmitBasicReport(AC->getDecl(), Checker,
"Identical conditions",
145 "expression is identical to previous condition",
148 Else = I2->getElse();
152 if (!Stmt1 || !Stmt2)
161 if (
const CompoundStmt *CompStmt = dyn_cast<CompoundStmt>(Stmt1)) {
162 if (CompStmt->size() == 1)
163 Stmt1 = CompStmt->body_back();
165 if (
const CompoundStmt *CompStmt = dyn_cast<CompoundStmt>(Stmt2)) {
166 if (CompStmt->size() == 1)
167 Stmt2 = CompStmt->body_back();
171 PathDiagnosticLocation ELoc =
173 BR.EmitBasicReport(AC->getDecl(), Checker,
174 "Identical branches",
176 "true and false branches are identical", ELoc);
181 bool FindIdenticalExprVisitor::VisitBinaryOperator(
const BinaryOperator *B) {
185 checkBitwiseOrLogicalOp(B,
true);
188 checkBitwiseOrLogicalOp(B,
false);
191 checkComparisonOp(B);
199 void FindIdenticalExprVisitor::checkComparisonOp(
const BinaryOperator *B) {
229 if ((DeclRef1) && (DeclRef2)) {
231 (DeclRef2->getType()->hasFloatingRepresentation())) {
232 if (DeclRef1->
getDecl() == DeclRef2->getDecl()) {
233 if ((Op == BO_EQ) || (Op == BO_NE)) {
238 }
else if ((FloatLit1) && (FloatLit2)) {
239 if (FloatLit1->getValue().bitwiseIsEqual(FloatLit2->getValue())) {
240 if ((Op == BO_EQ) || (Op == BO_NE)) {
254 PathDiagnosticLocation ELoc =
258 Message =
"comparison of identical expressions always evaluates to " 260 else if (((Op == BO_EQ) || (Op == BO_LE) || (Op == BO_GE)))
261 Message =
"comparison of identical expressions always evaluates to true";
263 Message =
"comparison of identical expressions always evaluates to false";
264 BR.EmitBasicReport(AC->getDecl(), Checker,
265 "Compare of identical expressions",
270 bool FindIdenticalExprVisitor::VisitConditionalOperator(
278 PathDiagnosticLocation ELoc =
280 C, BR.getSourceManager());
286 AC->getDecl(), Checker,
287 "Identical expressions in conditional expression",
289 "identical expressions on both sides of ':' in conditional expression",
307 const Stmt *Stmt2,
bool IgnoreSideEffects) {
309 if (!Stmt1 || !Stmt2) {
310 return !Stmt1 && !Stmt2;
318 const Expr *Expr1 = dyn_cast<
Expr>(Stmt1);
319 const Expr *Expr2 = dyn_cast<
Expr>(Stmt2);
321 if (Expr1 && Expr2) {
334 while (I1 != Expr1->
child_end() && I2 != Expr2->child_end()) {
335 if (!*I1 || !*I2 || !
isIdenticalStmt(Ctx, *I1, *I2, IgnoreSideEffects))
344 if (I2 != Expr2->child_end())
351 case Stmt::CallExprClass:
352 case Stmt::ArraySubscriptExprClass:
353 case Stmt::OMPArraySectionExprClass:
354 case Stmt::ImplicitCastExprClass:
355 case Stmt::ParenExprClass:
356 case Stmt::BreakStmtClass:
357 case Stmt::ContinueStmtClass:
358 case Stmt::NullStmtClass:
360 case Stmt::CStyleCastExprClass: {
366 case Stmt::ReturnStmtClass: {
367 const ReturnStmt *ReturnStmt1 = cast<ReturnStmt>(Stmt1);
368 const ReturnStmt *ReturnStmt2 = cast<ReturnStmt>(Stmt2);
371 ReturnStmt2->getRetValue(), IgnoreSideEffects);
373 case Stmt::ForStmtClass: {
374 const ForStmt *ForStmt1 = cast<ForStmt>(Stmt1);
375 const ForStmt *ForStmt2 = cast<ForStmt>(Stmt2);
391 case Stmt::DoStmtClass: {
392 const DoStmt *DStmt1 = cast<DoStmt>(Stmt1);
393 const DoStmt *DStmt2 = cast<DoStmt>(Stmt2);
403 case Stmt::WhileStmtClass: {
404 const WhileStmt *WStmt1 = cast<WhileStmt>(Stmt1);
405 const WhileStmt *WStmt2 = cast<WhileStmt>(Stmt2);
415 case Stmt::IfStmtClass: {
416 const IfStmt *IStmt1 = cast<IfStmt>(Stmt1);
417 const IfStmt *IStmt2 = cast<IfStmt>(Stmt2);
430 case Stmt::CompoundStmtClass: {
431 const CompoundStmt *CompStmt1 = cast<CompoundStmt>(Stmt1);
432 const CompoundStmt *CompStmt2 = cast<CompoundStmt>(Stmt2);
434 if (CompStmt1->
size() != CompStmt2->size())
439 while (I1 != CompStmt1->
body_end() && I2 != CompStmt2->body_end()) {
448 case Stmt::CompoundAssignOperatorClass:
449 case Stmt::BinaryOperatorClass: {
452 return BinOp1->
getOpcode() == BinOp2->getOpcode();
454 case Stmt::CharacterLiteralClass: {
457 return CharLit1->
getValue() == CharLit2->getValue();
459 case Stmt::DeclRefExprClass: {
460 const DeclRefExpr *DeclRef1 = cast<DeclRefExpr>(Stmt1);
461 const DeclRefExpr *DeclRef2 = cast<DeclRefExpr>(Stmt2);
462 return DeclRef1->
getDecl() == DeclRef2->getDecl();
464 case Stmt::IntegerLiteralClass: {
468 llvm::APInt I1 = IntLit1->
getValue();
469 llvm::APInt I2 = IntLit2->getValue();
470 if (I1.getBitWidth() != I2.getBitWidth())
474 case Stmt::FloatingLiteralClass: {
477 return FloatLit1->
getValue().bitwiseIsEqual(FloatLit2->getValue());
479 case Stmt::StringLiteralClass: {
480 const StringLiteral *StringLit1 = cast<StringLiteral>(Stmt1);
481 const StringLiteral *StringLit2 = cast<StringLiteral>(Stmt2);
482 return StringLit1->
getBytes() == StringLit2->getBytes();
484 case Stmt::MemberExprClass: {
485 const MemberExpr *MemberStmt1 = cast<MemberExpr>(Stmt1);
486 const MemberExpr *MemberStmt2 = cast<MemberExpr>(Stmt2);
487 return MemberStmt1->
getMemberDecl() == MemberStmt2->getMemberDecl();
489 case Stmt::UnaryOperatorClass: {
492 return UnaryOp1->
getOpcode() == UnaryOp2->getOpcode();
502 class FindIdenticalExprChecker :
public Checker<check::ASTCodeBody> {
504 void checkASTCodeBody(
const Decl *D, AnalysisManager &Mgr,
505 BugReporter &BR)
const {
506 FindIdenticalExprVisitor Visitor(BR,
this, Mgr.getAnalysisDeclContext(D));
507 Visitor.TraverseDecl(const_cast<Decl *>(D));
512 void ento::registerIdenticalExprChecker(CheckerManager &Mgr) {
513 Mgr.registerChecker<FindIdenticalExprChecker>();
516 bool ento::shouldRegisterIdenticalExprChecker(
const LangOptions &LO) {
child_iterator child_begin()
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.
Stmt *const * const_body_iterator
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
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...
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...
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.
DoStmt - This represents a 'do/while' stmt.
bool isComparisonOp() const
static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)
Create a location for the beginning of the declaration.
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
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
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.
A trivial tuple used to represent a source range.
child_iterator child_end()