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