IdenticalExprChecker.cpp revision 91934df3ce399e5938695b939943f92e7ff00483
1//== IdenticalExprChecker.cpp - Identical expression checker----------------==// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9/// 10/// \file 11/// \brief This defines IdenticalExprChecker, a check that warns about 12/// unintended use of identical expressions. 13/// 14/// It checks for use of identical expressions with comparison operators. 15/// 16//===----------------------------------------------------------------------===// 17 18#include "ClangSACheckers.h" 19#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 20#include "clang/StaticAnalyzer/Core/Checker.h" 21#include "clang/StaticAnalyzer/Core/CheckerManager.h" 22#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 23#include "clang/AST/RecursiveASTVisitor.h" 24 25using namespace clang; 26using namespace ento; 27 28static bool isIdenticalExpr(const ASTContext &Ctx, const Expr *Expr1, 29 const Expr *Expr2); 30//===----------------------------------------------------------------------===// 31// FindIdenticalExprVisitor - Identify nodes using identical expressions. 32//===----------------------------------------------------------------------===// 33 34namespace { 35class FindIdenticalExprVisitor 36 : public RecursiveASTVisitor<FindIdenticalExprVisitor> { 37public: 38 explicit FindIdenticalExprVisitor(BugReporter &B, AnalysisDeclContext *A) 39 : BR(B), AC(A) {} 40 // FindIdenticalExprVisitor only visits nodes 41 // that are binary operators. 42 bool VisitBinaryOperator(const BinaryOperator *B); 43 44private: 45 BugReporter &BR; 46 AnalysisDeclContext *AC; 47}; 48} // end anonymous namespace 49 50bool FindIdenticalExprVisitor::VisitBinaryOperator(const BinaryOperator *B) { 51 BinaryOperator::Opcode Op = B->getOpcode(); 52 if (!BinaryOperator::isComparisonOp(Op)) 53 return true; 54 // 55 // Special case for floating-point representation. 56 // 57 // If expressions on both sides of comparison operator are of type float, 58 // then for some comparison operators no warning shall be 59 // reported even if the expressions are identical from a symbolic point of 60 // view. Comparison between expressions, declared variables and literals 61 // are treated differently. 62 // 63 // != and == between float literals that have the same value should NOT warn. 64 // < > between float literals that have the same value SHOULD warn. 65 // 66 // != and == between the same float declaration should NOT warn. 67 // < > between the same float declaration SHOULD warn. 68 // 69 // != and == between eq. expressions that evaluates into float 70 // should NOT warn. 71 // < > between eq. expressions that evaluates into float 72 // should NOT warn. 73 // 74 const Expr *LHS = B->getLHS()->IgnoreParenImpCasts(); 75 const Expr *RHS = B->getRHS()->IgnoreParenImpCasts(); 76 77 const DeclRefExpr *DeclRef1 = dyn_cast<DeclRefExpr>(LHS); 78 const DeclRefExpr *DeclRef2 = dyn_cast<DeclRefExpr>(RHS); 79 const FloatingLiteral *FloatLit1 = dyn_cast<FloatingLiteral>(LHS); 80 const FloatingLiteral *FloatLit2 = dyn_cast<FloatingLiteral>(RHS); 81 if ((DeclRef1) && (DeclRef2)) { 82 if ((DeclRef1->getType()->hasFloatingRepresentation()) && 83 (DeclRef2->getType()->hasFloatingRepresentation())) { 84 if (DeclRef1->getDecl() == DeclRef2->getDecl()) { 85 if ((Op == BO_EQ) || (Op == BO_NE)) { 86 return true; 87 } 88 } 89 } 90 } else if ((FloatLit1) && (FloatLit2)) { 91 if (FloatLit1->getValue().bitwiseIsEqual(FloatLit2->getValue())) { 92 if ((Op == BO_EQ) || (Op == BO_NE)) { 93 return true; 94 } 95 } 96 } else if (LHS->getType()->hasFloatingRepresentation()) { 97 // If any side of comparison operator still has floating-point 98 // representation, then it's an expression. Don't warn. 99 // Here only LHS is checked since RHS will be implicit casted to float. 100 return true; 101 } else { 102 // No special case with floating-point representation, report as usual. 103 } 104 105 if (isIdenticalExpr(AC->getASTContext(), B->getLHS(), B->getRHS())) { 106 PathDiagnosticLocation ELoc = 107 PathDiagnosticLocation::createOperatorLoc(B, BR.getSourceManager()); 108 StringRef Message; 109 if (((Op == BO_EQ) || (Op == BO_LE) || (Op == BO_GE))) 110 Message = "comparison of identical expressions always evaluates to true"; 111 else 112 Message = "comparison of identical expressions always evaluates to false"; 113 BR.EmitBasicReport(AC->getDecl(), "Compare of identical expressions", 114 categories::LogicError, Message, ELoc); 115 } 116 // We want to visit ALL nodes (subexpressions of binary comparison 117 // expressions too) that contains comparison operators. 118 // True is always returned to traverse ALL nodes. 119 return true; 120} 121/// \brief Determines whether two expression trees are identical regarding 122/// operators and symbols. 123/// 124/// Exceptions: expressions containing macros or functions with possible side 125/// effects are never considered identical. 126/// Limitations: (t + u) and (u + t) are not considered identical. 127/// t*(u + t) and t*u + t*t are not considered identical. 128/// 129static bool isIdenticalExpr(const ASTContext &Ctx, const Expr *Expr1, 130 const Expr *Expr2) { 131 // If Expr1 & Expr2 are of different class then they are not 132 // identical expression. 133 if (Expr1->getStmtClass() != Expr2->getStmtClass()) 134 return false; 135 // If Expr1 has side effects then don't warn even if expressions 136 // are identical. 137 if (Expr1->HasSideEffects(Ctx)) 138 return false; 139 // Is expression is based on macro then don't warn even if 140 // the expressions are identical. 141 if ((Expr1->getExprLoc().isMacroID()) || (Expr2->getExprLoc().isMacroID())) 142 return false; 143 // If all children of two expressions are identical, return true. 144 Expr::const_child_iterator I1 = Expr1->child_begin(); 145 Expr::const_child_iterator I2 = Expr2->child_begin(); 146 while (I1 != Expr1->child_end() && I2 != Expr2->child_end()) { 147 const Expr *Child1 = dyn_cast<Expr>(*I1); 148 const Expr *Child2 = dyn_cast<Expr>(*I2); 149 if (!Child1 || !Child2 || !isIdenticalExpr(Ctx, Child1, Child2)) 150 return false; 151 ++I1; 152 ++I2; 153 } 154 // If there are different number of children in the expressions, return false. 155 // (TODO: check if this is a redundant condition.) 156 if (I1 != Expr1->child_end()) 157 return false; 158 if (I2 != Expr2->child_end()) 159 return false; 160 161 switch (Expr1->getStmtClass()) { 162 default: 163 return false; 164 case Stmt::ArraySubscriptExprClass: 165 case Stmt::CStyleCastExprClass: 166 case Stmt::ImplicitCastExprClass: 167 case Stmt::ParenExprClass: 168 return true; 169 case Stmt::BinaryOperatorClass: { 170 const BinaryOperator *BinOp1 = dyn_cast<BinaryOperator>(Expr1); 171 const BinaryOperator *BinOp2 = dyn_cast<BinaryOperator>(Expr2); 172 return BinOp1->getOpcode() == BinOp2->getOpcode(); 173 } 174 case Stmt::CharacterLiteralClass: { 175 const CharacterLiteral *CharLit1 = dyn_cast<CharacterLiteral>(Expr1); 176 const CharacterLiteral *CharLit2 = dyn_cast<CharacterLiteral>(Expr2); 177 return CharLit1->getValue() == CharLit2->getValue(); 178 } 179 case Stmt::DeclRefExprClass: { 180 const DeclRefExpr *DeclRef1 = dyn_cast<DeclRefExpr>(Expr1); 181 const DeclRefExpr *DeclRef2 = dyn_cast<DeclRefExpr>(Expr2); 182 return DeclRef1->getDecl() == DeclRef2->getDecl(); 183 } 184 case Stmt::IntegerLiteralClass: { 185 const IntegerLiteral *IntLit1 = dyn_cast<IntegerLiteral>(Expr1); 186 const IntegerLiteral *IntLit2 = dyn_cast<IntegerLiteral>(Expr2); 187 return IntLit1->getValue() == IntLit2->getValue(); 188 } 189 case Stmt::FloatingLiteralClass: { 190 const FloatingLiteral *FloatLit1 = dyn_cast<FloatingLiteral>(Expr1); 191 const FloatingLiteral *FloatLit2 = dyn_cast<FloatingLiteral>(Expr2); 192 return FloatLit1->getValue().bitwiseIsEqual(FloatLit2->getValue()); 193 } 194 case Stmt::MemberExprClass: { 195 const MemberExpr *MemberExpr1 = dyn_cast<MemberExpr>(Expr1); 196 const MemberExpr *MemberExpr2 = dyn_cast<MemberExpr>(Expr2); 197 return MemberExpr1->getMemberDecl() == MemberExpr2->getMemberDecl(); 198 } 199 case Stmt::UnaryOperatorClass: { 200 const UnaryOperator *UnaryOp1 = dyn_cast<UnaryOperator>(Expr1); 201 const UnaryOperator *UnaryOp2 = dyn_cast<UnaryOperator>(Expr2); 202 if (UnaryOp1->getOpcode() != UnaryOp2->getOpcode()) 203 return false; 204 return !UnaryOp1->isIncrementDecrementOp(); 205 } 206 } 207} 208 209//===----------------------------------------------------------------------===// 210// FindIdenticalExprChecker 211//===----------------------------------------------------------------------===// 212 213namespace { 214class FindIdenticalExprChecker : public Checker<check::ASTCodeBody> { 215public: 216 void checkASTCodeBody(const Decl *D, AnalysisManager &Mgr, 217 BugReporter &BR) const { 218 FindIdenticalExprVisitor Visitor(BR, Mgr.getAnalysisDeclContext(D)); 219 Visitor.TraverseDecl(const_cast<Decl *>(D)); 220 } 221}; 222} // end anonymous namespace 223 224void ento::registerIdenticalExprChecker(CheckerManager &Mgr) { 225 Mgr.registerChecker<FindIdenticalExprChecker>(); 226} 227