26 using namespace clang;
30 const Stmt *Stmt2,
bool IgnoreSideEffects =
false);
36 class FindIdenticalExprVisitor
39 const CheckerBase *Checker;
42 explicit FindIdenticalExprVisitor(BugReporter &B,
43 const CheckerBase *Checker,
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";
70 PathDiagnosticLocation ELoc =
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());
120 PathDiagnosticLocation ELoc(InnerIf->
getCond(), BR.getSourceManager(), AC);
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();
143 PathDiagnosticLocation ELoc(Cond2, BR.getSourceManager(), AC);
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();
172 PathDiagnosticLocation ELoc =
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)) {
255 PathDiagnosticLocation ELoc =
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(
279 PathDiagnosticLocation ELoc =
281 C, BR.getSourceManager());
287 AC->getDecl(), Checker,
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> {
505 void checkASTCodeBody(
const Decl *D, AnalysisManager &Mgr,
506 BugReporter &BR)
const {
507 FindIdenticalExprVisitor Visitor(BR,
this, Mgr.getAnalysisDeclContext(D));
508 Visitor.TraverseDecl(const_cast<Decl *>(D));
513 void ento::registerIdenticalExprChecker(CheckerManager &Mgr) {
514 Mgr.registerChecker<FindIdenticalExprChecker>();
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
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
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.
A trivial tuple used to represent a source range.
child_iterator child_end()