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