summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp')
-rw-r--r--contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp404
1 files changed, 334 insertions, 70 deletions
diff --git a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp
index e696e38..d5c52b4 100644
--- a/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp
+++ b/contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp
@@ -11,22 +11,23 @@
/// \brief This defines IdenticalExprChecker, a check that warns about
/// unintended use of identical expressions.
///
-/// It checks for use of identical expressions with comparison operators.
+/// It checks for use of identical expressions with comparison operators and
+/// inside conditional expressions.
///
//===----------------------------------------------------------------------===//
#include "ClangSACheckers.h"
+#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/AST/RecursiveASTVisitor.h"
using namespace clang;
using namespace ento;
-static bool isIdenticalExpr(const ASTContext &Ctx, const Expr *Expr1,
- const Expr *Expr2);
+static bool isIdenticalStmt(const ASTContext &Ctx, const Stmt *Stmt1,
+ const Stmt *Stmt2, bool IgnoreSideEffects = false);
//===----------------------------------------------------------------------===//
// FindIdenticalExprVisitor - Identify nodes using identical expressions.
//===----------------------------------------------------------------------===//
@@ -34,23 +35,153 @@ static bool isIdenticalExpr(const ASTContext &Ctx, const Expr *Expr1,
namespace {
class FindIdenticalExprVisitor
: public RecursiveASTVisitor<FindIdenticalExprVisitor> {
+ BugReporter &BR;
+ const CheckerBase *Checker;
+ AnalysisDeclContext *AC;
public:
- explicit FindIdenticalExprVisitor(BugReporter &B, AnalysisDeclContext *A)
- : BR(B), AC(A) {}
+ explicit FindIdenticalExprVisitor(BugReporter &B,
+ const CheckerBase *Checker,
+ AnalysisDeclContext *A)
+ : BR(B), Checker(Checker), AC(A) {}
// FindIdenticalExprVisitor only visits nodes
- // that are binary operators.
+ // that are binary operators, if statements or
+ // conditional operators.
bool VisitBinaryOperator(const BinaryOperator *B);
+ bool VisitIfStmt(const IfStmt *I);
+ bool VisitConditionalOperator(const ConditionalOperator *C);
private:
- BugReporter &BR;
- AnalysisDeclContext *AC;
+ void reportIdenticalExpr(const BinaryOperator *B, bool CheckBitwise,
+ ArrayRef<SourceRange> Sr);
+ void checkBitwiseOrLogicalOp(const BinaryOperator *B, bool CheckBitwise);
+ void checkComparisonOp(const BinaryOperator *B);
};
} // end anonymous namespace
+void FindIdenticalExprVisitor::reportIdenticalExpr(const BinaryOperator *B,
+ bool CheckBitwise,
+ ArrayRef<SourceRange> Sr) {
+ StringRef Message;
+ if (CheckBitwise)
+ Message = "identical expressions on both sides of bitwise operator";
+ else
+ Message = "identical expressions on both sides of logical operator";
+
+ PathDiagnosticLocation ELoc =
+ PathDiagnosticLocation::createOperatorLoc(B, BR.getSourceManager());
+ BR.EmitBasicReport(AC->getDecl(), Checker,
+ "Use of identical expressions",
+ categories::LogicError,
+ Message, ELoc, Sr);
+}
+
+void FindIdenticalExprVisitor::checkBitwiseOrLogicalOp(const BinaryOperator *B,
+ bool CheckBitwise) {
+ SourceRange Sr[2];
+
+ const Expr *LHS = B->getLHS();
+ const Expr *RHS = B->getRHS();
+
+ // Split operators as long as we still have operators to split on. We will
+ // get called for every binary operator in an expression so there is no need
+ // to check every one against each other here, just the right most one with
+ // the others.
+ while (const BinaryOperator *B2 = dyn_cast<BinaryOperator>(LHS)) {
+ if (B->getOpcode() != B2->getOpcode())
+ break;
+ if (isIdenticalStmt(AC->getASTContext(), RHS, B2->getRHS())) {
+ Sr[0] = RHS->getSourceRange();
+ Sr[1] = B2->getRHS()->getSourceRange();
+ reportIdenticalExpr(B, CheckBitwise, Sr);
+ }
+ LHS = B2->getLHS();
+ }
+
+ if (isIdenticalStmt(AC->getASTContext(), RHS, LHS)) {
+ Sr[0] = RHS->getSourceRange();
+ Sr[1] = LHS->getSourceRange();
+ reportIdenticalExpr(B, CheckBitwise, Sr);
+ }
+}
+
+bool FindIdenticalExprVisitor::VisitIfStmt(const IfStmt *I) {
+ const Stmt *Stmt1 = I->getThen();
+ const Stmt *Stmt2 = I->getElse();
+
+ // Check for identical conditions:
+ //
+ // if (b) {
+ // foo1();
+ // } else if (b) {
+ // foo2();
+ // }
+ if (Stmt1 && Stmt2) {
+ const Expr *Cond1 = I->getCond();
+ const Stmt *Else = Stmt2;
+ while (const IfStmt *I2 = dyn_cast_or_null<IfStmt>(Else)) {
+ const Expr *Cond2 = I2->getCond();
+ if (isIdenticalStmt(AC->getASTContext(), Cond1, Cond2, false)) {
+ SourceRange Sr = Cond1->getSourceRange();
+ PathDiagnosticLocation ELoc(Cond2, BR.getSourceManager(), AC);
+ BR.EmitBasicReport(AC->getDecl(), Checker, "Identical conditions",
+ categories::LogicError,
+ "expression is identical to previous condition",
+ ELoc, Sr);
+ }
+ Else = I2->getElse();
+ }
+ }
+
+ if (!Stmt1 || !Stmt2)
+ return true;
+
+ // Special handling for code like:
+ //
+ // if (b) {
+ // i = 1;
+ // } else
+ // i = 1;
+ if (const CompoundStmt *CompStmt = dyn_cast<CompoundStmt>(Stmt1)) {
+ if (CompStmt->size() == 1)
+ Stmt1 = CompStmt->body_back();
+ }
+ if (const CompoundStmt *CompStmt = dyn_cast<CompoundStmt>(Stmt2)) {
+ if (CompStmt->size() == 1)
+ Stmt2 = CompStmt->body_back();
+ }
+
+ if (isIdenticalStmt(AC->getASTContext(), Stmt1, Stmt2, true)) {
+ PathDiagnosticLocation ELoc =
+ PathDiagnosticLocation::createBegin(I, BR.getSourceManager(), AC);
+ BR.EmitBasicReport(AC->getDecl(), Checker,
+ "Identical branches",
+ categories::LogicError,
+ "true and false branches are identical", ELoc);
+ }
+ return true;
+}
+
bool FindIdenticalExprVisitor::VisitBinaryOperator(const BinaryOperator *B) {
BinaryOperator::Opcode Op = B->getOpcode();
- if (!BinaryOperator::isComparisonOp(Op))
- return true;
+
+ if (BinaryOperator::isBitwiseOp(Op))
+ checkBitwiseOrLogicalOp(B, true);
+
+ if (BinaryOperator::isLogicalOp(Op))
+ checkBitwiseOrLogicalOp(B, false);
+
+ if (BinaryOperator::isComparisonOp(Op))
+ checkComparisonOp(B);
+
+ // We want to visit ALL nodes (subexpressions of binary comparison
+ // expressions too) that contains comparison operators.
+ // True is always returned to traverse ALL nodes.
+ return true;
+}
+
+void FindIdenticalExprVisitor::checkComparisonOp(const BinaryOperator *B) {
+ BinaryOperator::Opcode Op = B->getOpcode();
+
//
// Special case for floating-point representation.
//
@@ -83,26 +214,26 @@ bool FindIdenticalExprVisitor::VisitBinaryOperator(const BinaryOperator *B) {
(DeclRef2->getType()->hasFloatingRepresentation())) {
if (DeclRef1->getDecl() == DeclRef2->getDecl()) {
if ((Op == BO_EQ) || (Op == BO_NE)) {
- return true;
+ return;
}
}
}
} else if ((FloatLit1) && (FloatLit2)) {
if (FloatLit1->getValue().bitwiseIsEqual(FloatLit2->getValue())) {
if ((Op == BO_EQ) || (Op == BO_NE)) {
- return true;
+ return;
}
}
} else if (LHS->getType()->hasFloatingRepresentation()) {
// If any side of comparison operator still has floating-point
// representation, then it's an expression. Don't warn.
// Here only LHS is checked since RHS will be implicit casted to float.
- return true;
+ return;
} else {
// No special case with floating-point representation, report as usual.
}
- if (isIdenticalExpr(AC->getASTContext(), B->getLHS(), B->getRHS())) {
+ if (isIdenticalStmt(AC->getASTContext(), B->getLHS(), B->getRHS())) {
PathDiagnosticLocation ELoc =
PathDiagnosticLocation::createOperatorLoc(B, BR.getSourceManager());
StringRef Message;
@@ -110,15 +241,41 @@ bool FindIdenticalExprVisitor::VisitBinaryOperator(const BinaryOperator *B) {
Message = "comparison of identical expressions always evaluates to true";
else
Message = "comparison of identical expressions always evaluates to false";
- BR.EmitBasicReport(AC->getDecl(), "Compare of identical expressions",
+ BR.EmitBasicReport(AC->getDecl(), Checker,
+ "Compare of identical expressions",
categories::LogicError, Message, ELoc);
}
- // We want to visit ALL nodes (subexpressions of binary comparison
- // expressions too) that contains comparison operators.
- // True is always returned to traverse ALL nodes.
+}
+
+bool FindIdenticalExprVisitor::VisitConditionalOperator(
+ const ConditionalOperator *C) {
+
+ // Check if expressions in conditional expression are identical
+ // from a symbolic point of view.
+
+ if (isIdenticalStmt(AC->getASTContext(), C->getTrueExpr(),
+ C->getFalseExpr(), true)) {
+ PathDiagnosticLocation ELoc =
+ PathDiagnosticLocation::createConditionalColonLoc(
+ C, BR.getSourceManager());
+
+ SourceRange Sr[2];
+ Sr[0] = C->getTrueExpr()->getSourceRange();
+ Sr[1] = C->getFalseExpr()->getSourceRange();
+ BR.EmitBasicReport(
+ AC->getDecl(), Checker,
+ "Identical expressions in conditional expression",
+ categories::LogicError,
+ "identical expressions on both sides of ':' in conditional expression",
+ ELoc, Sr);
+ }
+ // We want to visit ALL nodes (expressions in conditional
+ // expressions too) that contains conditional operators,
+ // thus always return true to traverse ALL nodes.
return true;
}
-/// \brief Determines whether two expression trees are identical regarding
+
+/// \brief Determines whether two statement trees are identical regarding
/// operators and symbols.
///
/// Exceptions: expressions containing macros or functions with possible side
@@ -126,82 +283,189 @@ bool FindIdenticalExprVisitor::VisitBinaryOperator(const BinaryOperator *B) {
/// Limitations: (t + u) and (u + t) are not considered identical.
/// t*(u + t) and t*u + t*t are not considered identical.
///
-static bool isIdenticalExpr(const ASTContext &Ctx, const Expr *Expr1,
- const Expr *Expr2) {
- // If Expr1 & Expr2 are of different class then they are not
- // identical expression.
- if (Expr1->getStmtClass() != Expr2->getStmtClass())
- return false;
- // If Expr1 has side effects then don't warn even if expressions
- // are identical.
- if (Expr1->HasSideEffects(Ctx))
- return false;
- // Is expression is based on macro then don't warn even if
- // the expressions are identical.
- if ((Expr1->getExprLoc().isMacroID()) || (Expr2->getExprLoc().isMacroID()))
- return false;
- // If all children of two expressions are identical, return true.
- Expr::const_child_iterator I1 = Expr1->child_begin();
- Expr::const_child_iterator I2 = Expr2->child_begin();
- while (I1 != Expr1->child_end() && I2 != Expr2->child_end()) {
- const Expr *Child1 = dyn_cast<Expr>(*I1);
- const Expr *Child2 = dyn_cast<Expr>(*I2);
- if (!Child1 || !Child2 || !isIdenticalExpr(Ctx, Child1, Child2))
- return false;
- ++I1;
- ++I2;
- }
- // If there are different number of children in the expressions, return false.
- // (TODO: check if this is a redundant condition.)
- if (I1 != Expr1->child_end())
+static bool isIdenticalStmt(const ASTContext &Ctx, const Stmt *Stmt1,
+ const Stmt *Stmt2, bool IgnoreSideEffects) {
+
+ if (!Stmt1 || !Stmt2) {
+ if (!Stmt1 && !Stmt2)
+ return true;
return false;
- if (I2 != Expr2->child_end())
+ }
+
+ // If Stmt1 & Stmt2 are of different class then they are not
+ // identical statements.
+ if (Stmt1->getStmtClass() != Stmt2->getStmtClass())
return false;
- switch (Expr1->getStmtClass()) {
+ const Expr *Expr1 = dyn_cast<Expr>(Stmt1);
+ const Expr *Expr2 = dyn_cast<Expr>(Stmt2);
+
+ if (Expr1 && Expr2) {
+ // If Stmt1 has side effects then don't warn even if expressions
+ // are identical.
+ if (!IgnoreSideEffects && Expr1->HasSideEffects(Ctx))
+ return false;
+ // If either expression comes from a macro then don't warn even if
+ // the expressions are identical.
+ if ((Expr1->getExprLoc().isMacroID()) || (Expr2->getExprLoc().isMacroID()))
+ return false;
+
+ // If all children of two expressions are identical, return true.
+ Expr::const_child_iterator I1 = Expr1->child_begin();
+ Expr::const_child_iterator I2 = Expr2->child_begin();
+ while (I1 != Expr1->child_end() && I2 != Expr2->child_end()) {
+ if (!*I1 || !*I2 || !isIdenticalStmt(Ctx, *I1, *I2, IgnoreSideEffects))
+ return false;
+ ++I1;
+ ++I2;
+ }
+ // If there are different number of children in the statements, return
+ // false.
+ if (I1 != Expr1->child_end())
+ return false;
+ if (I2 != Expr2->child_end())
+ return false;
+ }
+
+ switch (Stmt1->getStmtClass()) {
default:
return false;
+ case Stmt::CallExprClass:
case Stmt::ArraySubscriptExprClass:
- case Stmt::CStyleCastExprClass:
case Stmt::ImplicitCastExprClass:
case Stmt::ParenExprClass:
+ case Stmt::BreakStmtClass:
+ case Stmt::ContinueStmtClass:
+ case Stmt::NullStmtClass:
+ return true;
+ case Stmt::CStyleCastExprClass: {
+ const CStyleCastExpr* CastExpr1 = cast<CStyleCastExpr>(Stmt1);
+ const CStyleCastExpr* CastExpr2 = cast<CStyleCastExpr>(Stmt2);
+
+ return CastExpr1->getTypeAsWritten() == CastExpr2->getTypeAsWritten();
+ }
+ case Stmt::ReturnStmtClass: {
+ const ReturnStmt *ReturnStmt1 = cast<ReturnStmt>(Stmt1);
+ const ReturnStmt *ReturnStmt2 = cast<ReturnStmt>(Stmt2);
+
+ return isIdenticalStmt(Ctx, ReturnStmt1->getRetValue(),
+ ReturnStmt2->getRetValue(), IgnoreSideEffects);
+ }
+ case Stmt::ForStmtClass: {
+ const ForStmt *ForStmt1 = cast<ForStmt>(Stmt1);
+ const ForStmt *ForStmt2 = cast<ForStmt>(Stmt2);
+
+ if (!isIdenticalStmt(Ctx, ForStmt1->getInit(), ForStmt2->getInit(),
+ IgnoreSideEffects))
+ return false;
+ if (!isIdenticalStmt(Ctx, ForStmt1->getCond(), ForStmt2->getCond(),
+ IgnoreSideEffects))
+ return false;
+ if (!isIdenticalStmt(Ctx, ForStmt1->getInc(), ForStmt2->getInc(),
+ IgnoreSideEffects))
+ return false;
+ if (!isIdenticalStmt(Ctx, ForStmt1->getBody(), ForStmt2->getBody(),
+ IgnoreSideEffects))
+ return false;
+ return true;
+ }
+ case Stmt::DoStmtClass: {
+ const DoStmt *DStmt1 = cast<DoStmt>(Stmt1);
+ const DoStmt *DStmt2 = cast<DoStmt>(Stmt2);
+
+ if (!isIdenticalStmt(Ctx, DStmt1->getCond(), DStmt2->getCond(),
+ IgnoreSideEffects))
+ return false;
+ if (!isIdenticalStmt(Ctx, DStmt1->getBody(), DStmt2->getBody(),
+ IgnoreSideEffects))
+ return false;
+ return true;
+ }
+ case Stmt::WhileStmtClass: {
+ const WhileStmt *WStmt1 = cast<WhileStmt>(Stmt1);
+ const WhileStmt *WStmt2 = cast<WhileStmt>(Stmt2);
+
+ if (!isIdenticalStmt(Ctx, WStmt1->getCond(), WStmt2->getCond(),
+ IgnoreSideEffects))
+ return false;
+ if (!isIdenticalStmt(Ctx, WStmt1->getBody(), WStmt2->getBody(),
+ IgnoreSideEffects))
+ return false;
return true;
+ }
+ case Stmt::IfStmtClass: {
+ const IfStmt *IStmt1 = cast<IfStmt>(Stmt1);
+ const IfStmt *IStmt2 = cast<IfStmt>(Stmt2);
+
+ if (!isIdenticalStmt(Ctx, IStmt1->getCond(), IStmt2->getCond(),
+ IgnoreSideEffects))
+ return false;
+ if (!isIdenticalStmt(Ctx, IStmt1->getThen(), IStmt2->getThen(),
+ IgnoreSideEffects))
+ return false;
+ if (!isIdenticalStmt(Ctx, IStmt1->getElse(), IStmt2->getElse(),
+ IgnoreSideEffects))
+ return false;
+ return true;
+ }
+ case Stmt::CompoundStmtClass: {
+ const CompoundStmt *CompStmt1 = cast<CompoundStmt>(Stmt1);
+ const CompoundStmt *CompStmt2 = cast<CompoundStmt>(Stmt2);
+
+ if (CompStmt1->size() != CompStmt2->size())
+ return false;
+
+ CompoundStmt::const_body_iterator I1 = CompStmt1->body_begin();
+ CompoundStmt::const_body_iterator I2 = CompStmt2->body_begin();
+ while (I1 != CompStmt1->body_end() && I2 != CompStmt2->body_end()) {
+ if (!isIdenticalStmt(Ctx, *I1, *I2, IgnoreSideEffects))
+ return false;
+ ++I1;
+ ++I2;
+ }
+
+ return true;
+ }
+ case Stmt::CompoundAssignOperatorClass:
case Stmt::BinaryOperatorClass: {
- const BinaryOperator *BinOp1 = dyn_cast<BinaryOperator>(Expr1);
- const BinaryOperator *BinOp2 = dyn_cast<BinaryOperator>(Expr2);
+ const BinaryOperator *BinOp1 = cast<BinaryOperator>(Stmt1);
+ const BinaryOperator *BinOp2 = cast<BinaryOperator>(Stmt2);
return BinOp1->getOpcode() == BinOp2->getOpcode();
}
case Stmt::CharacterLiteralClass: {
- const CharacterLiteral *CharLit1 = dyn_cast<CharacterLiteral>(Expr1);
- const CharacterLiteral *CharLit2 = dyn_cast<CharacterLiteral>(Expr2);
+ const CharacterLiteral *CharLit1 = cast<CharacterLiteral>(Stmt1);
+ const CharacterLiteral *CharLit2 = cast<CharacterLiteral>(Stmt2);
return CharLit1->getValue() == CharLit2->getValue();
}
case Stmt::DeclRefExprClass: {
- const DeclRefExpr *DeclRef1 = dyn_cast<DeclRefExpr>(Expr1);
- const DeclRefExpr *DeclRef2 = dyn_cast<DeclRefExpr>(Expr2);
+ const DeclRefExpr *DeclRef1 = cast<DeclRefExpr>(Stmt1);
+ const DeclRefExpr *DeclRef2 = cast<DeclRefExpr>(Stmt2);
return DeclRef1->getDecl() == DeclRef2->getDecl();
}
case Stmt::IntegerLiteralClass: {
- const IntegerLiteral *IntLit1 = dyn_cast<IntegerLiteral>(Expr1);
- const IntegerLiteral *IntLit2 = dyn_cast<IntegerLiteral>(Expr2);
+ const IntegerLiteral *IntLit1 = cast<IntegerLiteral>(Stmt1);
+ const IntegerLiteral *IntLit2 = cast<IntegerLiteral>(Stmt2);
return IntLit1->getValue() == IntLit2->getValue();
}
case Stmt::FloatingLiteralClass: {
- const FloatingLiteral *FloatLit1 = dyn_cast<FloatingLiteral>(Expr1);
- const FloatingLiteral *FloatLit2 = dyn_cast<FloatingLiteral>(Expr2);
+ const FloatingLiteral *FloatLit1 = cast<FloatingLiteral>(Stmt1);
+ const FloatingLiteral *FloatLit2 = cast<FloatingLiteral>(Stmt2);
return FloatLit1->getValue().bitwiseIsEqual(FloatLit2->getValue());
}
+ case Stmt::StringLiteralClass: {
+ const StringLiteral *StringLit1 = cast<StringLiteral>(Stmt1);
+ const StringLiteral *StringLit2 = cast<StringLiteral>(Stmt2);
+ return StringLit1->getString() == StringLit2->getString();
+ }
case Stmt::MemberExprClass: {
- const MemberExpr *MemberExpr1 = dyn_cast<MemberExpr>(Expr1);
- const MemberExpr *MemberExpr2 = dyn_cast<MemberExpr>(Expr2);
- return MemberExpr1->getMemberDecl() == MemberExpr2->getMemberDecl();
+ const MemberExpr *MemberStmt1 = cast<MemberExpr>(Stmt1);
+ const MemberExpr *MemberStmt2 = cast<MemberExpr>(Stmt2);
+ return MemberStmt1->getMemberDecl() == MemberStmt2->getMemberDecl();
}
case Stmt::UnaryOperatorClass: {
- const UnaryOperator *UnaryOp1 = dyn_cast<UnaryOperator>(Expr1);
- const UnaryOperator *UnaryOp2 = dyn_cast<UnaryOperator>(Expr2);
- if (UnaryOp1->getOpcode() != UnaryOp2->getOpcode())
- return false;
- return !UnaryOp1->isIncrementDecrementOp();
+ const UnaryOperator *UnaryOp1 = cast<UnaryOperator>(Stmt1);
+ const UnaryOperator *UnaryOp2 = cast<UnaryOperator>(Stmt2);
+ return UnaryOp1->getOpcode() == UnaryOp2->getOpcode();
}
}
}
@@ -215,7 +479,7 @@ class FindIdenticalExprChecker : public Checker<check::ASTCodeBody> {
public:
void checkASTCodeBody(const Decl *D, AnalysisManager &Mgr,
BugReporter &BR) const {
- FindIdenticalExprVisitor Visitor(BR, Mgr.getAnalysisDeclContext(D));
+ FindIdenticalExprVisitor Visitor(BR, this, Mgr.getAnalysisDeclContext(D));
Visitor.TraverseDecl(const_cast<Decl *>(D));
}
};
OpenPOWER on IntegriCloud