29 const Stmt *Stmt2,
bool IgnoreSideEffects =
false);
35class FindIdenticalExprVisitor
49 bool VisitIfStmt(
const IfStmt *I);
53 void reportIdenticalExpr(
const BinaryOperator *B,
bool CheckBitwise,
55 void checkBitwiseOrLogicalOp(
const BinaryOperator *B,
bool CheckBitwise);
60void 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";
71 BR.EmitBasicReport(AC->getDecl(),
Checker,
72 "Use of identical expressions",
77void FindIdenticalExprVisitor::checkBitwiseOrLogicalOp(
const BinaryOperator *B,
93 Sr[1] = B2->getRHS()->getSourceRange();
94 reportIdenticalExpr(B, CheckBitwise, Sr);
102 reportIdenticalExpr(B, CheckBitwise, Sr);
106bool 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());
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();
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();
173 BR.EmitBasicReport(AC->getDecl(),
Checker,
174 "Identical branches",
176 "true and false branches are identical", ELoc);
181bool FindIdenticalExprVisitor::VisitBinaryOperator(
const BinaryOperator *B) {
185 checkBitwiseOrLogicalOp(B,
true);
188 checkBitwiseOrLogicalOp(B,
false);
191 checkComparisonOp(B);
199void FindIdenticalExprVisitor::checkComparisonOp(
const BinaryOperator *B) {
225 const DeclRefExpr *DeclRef1 = dyn_cast<DeclRefExpr>(LHS);
226 const DeclRefExpr *DeclRef2 = dyn_cast<DeclRefExpr>(RHS);
229 if ((DeclRef1) && (DeclRef2)) {
233 if ((Op == BO_EQ) || (Op == BO_NE)) {
238 }
else if ((FloatLit1) && (FloatLit2)) {
240 if ((Op == BO_EQ) || (Op == BO_NE)) {
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",
270bool FindIdenticalExprVisitor::VisitConditionalOperator(
277 C->getFalseExpr(),
true)) {
280 C, BR.getSourceManager());
283 Sr[0] =
C->getTrueExpr()->getSourceRange();
284 Sr[1] =
C->getFalseExpr()->getSourceRange();
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) {
335 if (!*I1 || !*I2 || !
isIdenticalStmt(Ctx, *I1, *I2, IgnoreSideEffects))
351 case Stmt::CallExprClass:
352 case Stmt::ArraySubscriptExprClass:
353 case Stmt::ArraySectionExprClass:
354 case Stmt::OMPArrayShapingExprClass:
355 case Stmt::OMPIteratorExprClass:
356 case Stmt::ImplicitCastExprClass:
357 case Stmt::ParenExprClass:
358 case Stmt::BreakStmtClass:
359 case Stmt::ContinueStmtClass:
360 case Stmt::NullStmtClass:
362 case Stmt::CStyleCastExprClass: {
368 case Stmt::ReturnStmtClass: {
369 const ReturnStmt *ReturnStmt1 = cast<ReturnStmt>(Stmt1);
370 const ReturnStmt *ReturnStmt2 = cast<ReturnStmt>(Stmt2);
375 case Stmt::ForStmtClass: {
376 const ForStmt *ForStmt1 = cast<ForStmt>(Stmt1);
377 const ForStmt *ForStmt2 = cast<ForStmt>(Stmt2);
393 case Stmt::DoStmtClass: {
394 const DoStmt *DStmt1 = cast<DoStmt>(Stmt1);
395 const DoStmt *DStmt2 = cast<DoStmt>(Stmt2);
405 case Stmt::WhileStmtClass: {
406 const WhileStmt *WStmt1 = cast<WhileStmt>(Stmt1);
407 const WhileStmt *WStmt2 = cast<WhileStmt>(Stmt2);
417 case Stmt::IfStmtClass: {
418 const IfStmt *IStmt1 = cast<IfStmt>(Stmt1);
419 const IfStmt *IStmt2 = cast<IfStmt>(Stmt2);
432 case Stmt::CompoundStmtClass: {
433 const CompoundStmt *CompStmt1 = cast<CompoundStmt>(Stmt1);
434 const CompoundStmt *CompStmt2 = cast<CompoundStmt>(Stmt2);
436 if (CompStmt1->
size() != CompStmt2->
size())
450 case Stmt::CompoundAssignOperatorClass:
451 case Stmt::BinaryOperatorClass: {
456 case Stmt::CharacterLiteralClass: {
461 case Stmt::DeclRefExprClass: {
462 const DeclRefExpr *DeclRef1 = cast<DeclRefExpr>(Stmt1);
463 const DeclRefExpr *DeclRef2 = cast<DeclRefExpr>(Stmt2);
466 case Stmt::IntegerLiteralClass: {
470 llvm::APInt I1 = IntLit1->
getValue();
471 llvm::APInt I2 = IntLit2->
getValue();
472 if (I1.getBitWidth() != I2.getBitWidth())
476 case Stmt::FloatingLiteralClass: {
481 case Stmt::StringLiteralClass: {
482 const StringLiteral *StringLit1 = cast<StringLiteral>(Stmt1);
483 const StringLiteral *StringLit2 = cast<StringLiteral>(Stmt2);
486 case Stmt::MemberExprClass: {
487 const MemberExpr *MemberStmt1 = cast<MemberExpr>(Stmt1);
488 const MemberExpr *MemberStmt2 = cast<MemberExpr>(Stmt2);
491 case Stmt::UnaryOperatorClass: {
504class FindIdenticalExprChecker :
public Checker<check::ASTCodeBody> {
509 Visitor.TraverseDecl(
const_cast<Decl *
>(
D));
518bool ento::shouldRegisterIdenticalExprChecker(
const CheckerManager &mgr) {
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.
llvm::APInt getValue() 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, method or block under analysis.
A builtin binary operation expression such as "x + y" or "x <= y".
bool isComparisonOp() const
CStyleCastExpr - An explicit cast in C (C99 6.5.4) or a C-style cast in C++ (C++ [expr....
unsigned getValue() const
CompoundStmt - This represents a group of statements like { stmt stmt }.
Stmt *const * const_body_iterator
body_iterator body_begin()
ConditionalOperator - The ?: ternary operator.
A reference to a declared variable, function, enum, etc.
Decl - This represents one declaration (or definition), e.g.
DoStmt - This represents a 'do/while' stmt.
QualType getTypeAsWritten() const
getTypeAsWritten - Returns the type that this expression is casting to, as written in the source code...
This represents one expression.
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
bool HasSideEffects(const ASTContext &Ctx, bool IncludePossibleEffects=true) const
HasSideEffects - This routine returns true for all those expressions which have any effect other than...
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
llvm::APFloat getValue() const
ForStmt - This represents a 'for (init;cond;inc)' stmt.
IfStmt - This represents an if/then/else.
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
ValueDecl * getMemberDecl() const
Retrieve the member declaration to which this expression refers.
A class that does preorder or postorder depth-first traversal on the entire Clang AST and visits each...
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
A trivial tuple used to represent a source range.
Stmt - This represents one statement.
child_iterator child_begin()
StmtClass getStmtClass() const
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
child_iterator child_end()
StringLiteral - This represents a string literal expression, e.g.
StringRef getBytes() const
Allow access to clients that need the byte representation, such as ASTWriterStmt::VisitStringLiteral(...
bool hasFloatingRepresentation() const
Determine whether this type has a floating-point representation of some sort, e.g....
UnaryOperator - This represents the unary-expression's (except sizeof and alignof),...
WhileStmt - This represents a 'while' stmt.
AnalysisDeclContext * getAnalysisDeclContext(const Decl *D)
BugReporter is a utility class for generating PathDiagnostics for analysis.
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
static PathDiagnosticLocation createOperatorLoc(const BinaryOperator *BO, const SourceManager &SM)
Create the location for the operator of the binary expression.
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)
const char *const LogicError
The JSON file list parser is used to communicate input to InstallAPI.