blob: cf57b8dca06386ce276ac8e9fb9966f7532f43ae [file] [log] [blame]
Jordan Rose51327f92013-11-08 01:15:39 +00001//== 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///
Jordan Rose60bd88d2013-12-10 18:18:06 +000014/// It checks for use of identical expressions with comparison operators and
15/// inside conditional expressions.
Jordan Rose51327f92013-11-08 01:15:39 +000016///
17//===----------------------------------------------------------------------===//
18
19#include "ClangSACheckers.h"
Chandler Carruth5553d0d2014-01-07 11:51:46 +000020#include "clang/AST/RecursiveASTVisitor.h"
Jordan Rose51327f92013-11-08 01:15:39 +000021#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"
Jordan Rose51327f92013-11-08 01:15:39 +000025
26using namespace clang;
27using namespace ento;
28
Jordan Rose70e7e872014-02-19 17:44:11 +000029static bool isIdenticalStmt(const ASTContext &Ctx, const Stmt *Stmt1,
30 const Stmt *Stmt2, bool IgnoreSideEffects = false);
Jordan Rose51327f92013-11-08 01:15:39 +000031//===----------------------------------------------------------------------===//
32// FindIdenticalExprVisitor - Identify nodes using identical expressions.
33//===----------------------------------------------------------------------===//
34
Benjamin Kramere8a2c182013-11-14 15:46:10 +000035namespace {
Jordan Rose51327f92013-11-08 01:15:39 +000036class FindIdenticalExprVisitor
37 : public RecursiveASTVisitor<FindIdenticalExprVisitor> {
Jordan Rose94008122014-02-19 17:44:16 +000038 BugReporter &BR;
39 const CheckerBase *Checker;
40 AnalysisDeclContext *AC;
Jordan Rose51327f92013-11-08 01:15:39 +000041public:
Alexander Kornienko4aca9b12014-02-11 21:49:21 +000042 explicit FindIdenticalExprVisitor(BugReporter &B,
43 const CheckerBase *Checker,
44 AnalysisDeclContext *A)
45 : BR(B), Checker(Checker), AC(A) {}
Jordan Rose51327f92013-11-08 01:15:39 +000046 // FindIdenticalExprVisitor only visits nodes
Jordan Rose70e7e872014-02-19 17:44:11 +000047 // that are binary operators, if statements or
48 // conditional operators.
Jordan Rose51327f92013-11-08 01:15:39 +000049 bool VisitBinaryOperator(const BinaryOperator *B);
Jordan Rose70e7e872014-02-19 17:44:11 +000050 bool VisitIfStmt(const IfStmt *I);
Jordan Rose60bd88d2013-12-10 18:18:06 +000051 bool VisitConditionalOperator(const ConditionalOperator *C);
Jordan Rose51327f92013-11-08 01:15:39 +000052
53private:
Jordan Rose94008122014-02-19 17:44:16 +000054 void reportIdenticalExpr(const BinaryOperator *B, bool CheckBitwise,
55 ArrayRef<SourceRange> Sr);
56 void checkBitwiseOrLogicalOp(const BinaryOperator *B, bool CheckBitwise);
57 void checkComparisonOp(const BinaryOperator *B);
Jordan Rose51327f92013-11-08 01:15:39 +000058};
Benjamin Kramere8a2c182013-11-14 15:46:10 +000059} // end anonymous namespace
Jordan Rose51327f92013-11-08 01:15:39 +000060
Jordan Rose94008122014-02-19 17:44:16 +000061void FindIdenticalExprVisitor::reportIdenticalExpr(const BinaryOperator *B,
62 bool CheckBitwise,
63 ArrayRef<SourceRange> Sr) {
64 StringRef Message;
65 if (CheckBitwise)
66 Message = "identical expressions on both sides of bitwise operator";
67 else
68 Message = "identical expressions on both sides of logical operator";
69
70 PathDiagnosticLocation ELoc =
71 PathDiagnosticLocation::createOperatorLoc(B, BR.getSourceManager());
72 BR.EmitBasicReport(AC->getDecl(), Checker,
73 "Use of identical expressions",
74 categories::LogicError,
75 Message, ELoc, Sr);
76}
77
78void FindIdenticalExprVisitor::checkBitwiseOrLogicalOp(const BinaryOperator *B,
79 bool CheckBitwise) {
80 SourceRange Sr[2];
81
82 const Expr *LHS = B->getLHS();
83 const Expr *RHS = B->getRHS();
84
85 // Split operators as long as we still have operators to split on. We will
86 // get called for every binary operator in an expression so there is no need
87 // to check every one against each other here, just the right most one with
88 // the others.
89 while (const BinaryOperator *B2 = dyn_cast<BinaryOperator>(LHS)) {
90 if (B->getOpcode() != B2->getOpcode())
91 break;
92 if (isIdenticalStmt(AC->getASTContext(), RHS, B2->getRHS())) {
93 Sr[0] = RHS->getSourceRange();
94 Sr[1] = B2->getRHS()->getSourceRange();
95 reportIdenticalExpr(B, CheckBitwise, Sr);
96 }
97 LHS = B2->getLHS();
98 }
Ted Kremenek3a0678e2015-09-08 03:50:52 +000099
Jordan Rose94008122014-02-19 17:44:16 +0000100 if (isIdenticalStmt(AC->getASTContext(), RHS, LHS)) {
101 Sr[0] = RHS->getSourceRange();
102 Sr[1] = LHS->getSourceRange();
103 reportIdenticalExpr(B, CheckBitwise, Sr);
104 }
105}
106
Jordan Rose70e7e872014-02-19 17:44:11 +0000107bool FindIdenticalExprVisitor::VisitIfStmt(const IfStmt *I) {
108 const Stmt *Stmt1 = I->getThen();
109 const Stmt *Stmt2 = I->getElse();
110
Daniel Marjamaki30e2a442015-08-10 07:18:29 +0000111 // Check for identical inner condition:
112 //
113 // if (x<10) {
114 // if (x<10) {
115 // ..
116 if (const CompoundStmt *CS = dyn_cast<CompoundStmt>(Stmt1)) {
117 if (!CS->body_empty()) {
118 const IfStmt *InnerIf = dyn_cast<IfStmt>(*CS->body_begin());
119 if (InnerIf && isIdenticalStmt(AC->getASTContext(), I->getCond(), InnerIf->getCond(), /*ignoreSideEffects=*/ false)) {
120 PathDiagnosticLocation ELoc(InnerIf->getCond(), BR.getSourceManager(), AC);
121 BR.EmitBasicReport(AC->getDecl(), Checker, "Identical conditions",
122 categories::LogicError,
123 "conditions of the inner and outer statements are identical",
124 ELoc);
125 }
126 }
127 }
128
Jordan Rosea6839aa2014-03-11 16:52:29 +0000129 // Check for identical conditions:
130 //
131 // if (b) {
132 // foo1();
133 // } else if (b) {
134 // foo2();
135 // }
136 if (Stmt1 && Stmt2) {
137 const Expr *Cond1 = I->getCond();
138 const Stmt *Else = Stmt2;
139 while (const IfStmt *I2 = dyn_cast_or_null<IfStmt>(Else)) {
140 const Expr *Cond2 = I2->getCond();
141 if (isIdenticalStmt(AC->getASTContext(), Cond1, Cond2, false)) {
142 SourceRange Sr = Cond1->getSourceRange();
143 PathDiagnosticLocation ELoc(Cond2, BR.getSourceManager(), AC);
144 BR.EmitBasicReport(AC->getDecl(), Checker, "Identical conditions",
145 categories::LogicError,
146 "expression is identical to previous condition",
147 ELoc, Sr);
148 }
149 Else = I2->getElse();
150 }
151 }
152
Jordan Rose70e7e872014-02-19 17:44:11 +0000153 if (!Stmt1 || !Stmt2)
154 return true;
155
156 // Special handling for code like:
157 //
158 // if (b) {
159 // i = 1;
160 // } else
161 // i = 1;
162 if (const CompoundStmt *CompStmt = dyn_cast<CompoundStmt>(Stmt1)) {
163 if (CompStmt->size() == 1)
164 Stmt1 = CompStmt->body_back();
165 }
166 if (const CompoundStmt *CompStmt = dyn_cast<CompoundStmt>(Stmt2)) {
167 if (CompStmt->size() == 1)
168 Stmt2 = CompStmt->body_back();
169 }
170
171 if (isIdenticalStmt(AC->getASTContext(), Stmt1, Stmt2, true)) {
172 PathDiagnosticLocation ELoc =
173 PathDiagnosticLocation::createBegin(I, BR.getSourceManager(), AC);
174 BR.EmitBasicReport(AC->getDecl(), Checker,
175 "Identical branches",
176 categories::LogicError,
177 "true and false branches are identical", ELoc);
178 }
179 return true;
180}
181
Jordan Rose51327f92013-11-08 01:15:39 +0000182bool FindIdenticalExprVisitor::VisitBinaryOperator(const BinaryOperator *B) {
183 BinaryOperator::Opcode Op = B->getOpcode();
Jordan Rose94008122014-02-19 17:44:16 +0000184
185 if (BinaryOperator::isBitwiseOp(Op))
186 checkBitwiseOrLogicalOp(B, true);
187
188 if (BinaryOperator::isLogicalOp(Op))
189 checkBitwiseOrLogicalOp(B, false);
190
191 if (BinaryOperator::isComparisonOp(Op))
192 checkComparisonOp(B);
193
194 // We want to visit ALL nodes (subexpressions of binary comparison
195 // expressions too) that contains comparison operators.
196 // True is always returned to traverse ALL nodes.
197 return true;
198}
199
200void FindIdenticalExprVisitor::checkComparisonOp(const BinaryOperator *B) {
201 BinaryOperator::Opcode Op = B->getOpcode();
202
Jordan Rose51327f92013-11-08 01:15:39 +0000203 //
204 // Special case for floating-point representation.
205 //
206 // If expressions on both sides of comparison operator are of type float,
207 // then for some comparison operators no warning shall be
208 // reported even if the expressions are identical from a symbolic point of
209 // view. Comparison between expressions, declared variables and literals
210 // are treated differently.
211 //
212 // != and == between float literals that have the same value should NOT warn.
213 // < > between float literals that have the same value SHOULD warn.
214 //
215 // != and == between the same float declaration should NOT warn.
216 // < > between the same float declaration SHOULD warn.
217 //
218 // != and == between eq. expressions that evaluates into float
219 // should NOT warn.
220 // < > between eq. expressions that evaluates into float
221 // should NOT warn.
222 //
223 const Expr *LHS = B->getLHS()->IgnoreParenImpCasts();
224 const Expr *RHS = B->getRHS()->IgnoreParenImpCasts();
225
226 const DeclRefExpr *DeclRef1 = dyn_cast<DeclRefExpr>(LHS);
227 const DeclRefExpr *DeclRef2 = dyn_cast<DeclRefExpr>(RHS);
228 const FloatingLiteral *FloatLit1 = dyn_cast<FloatingLiteral>(LHS);
229 const FloatingLiteral *FloatLit2 = dyn_cast<FloatingLiteral>(RHS);
230 if ((DeclRef1) && (DeclRef2)) {
231 if ((DeclRef1->getType()->hasFloatingRepresentation()) &&
232 (DeclRef2->getType()->hasFloatingRepresentation())) {
233 if (DeclRef1->getDecl() == DeclRef2->getDecl()) {
234 if ((Op == BO_EQ) || (Op == BO_NE)) {
Jordan Rose94008122014-02-19 17:44:16 +0000235 return;
Jordan Rose51327f92013-11-08 01:15:39 +0000236 }
237 }
238 }
239 } else if ((FloatLit1) && (FloatLit2)) {
240 if (FloatLit1->getValue().bitwiseIsEqual(FloatLit2->getValue())) {
241 if ((Op == BO_EQ) || (Op == BO_NE)) {
Jordan Rose94008122014-02-19 17:44:16 +0000242 return;
Jordan Rose51327f92013-11-08 01:15:39 +0000243 }
244 }
245 } else if (LHS->getType()->hasFloatingRepresentation()) {
246 // If any side of comparison operator still has floating-point
247 // representation, then it's an expression. Don't warn.
248 // Here only LHS is checked since RHS will be implicit casted to float.
Jordan Rose94008122014-02-19 17:44:16 +0000249 return;
Jordan Rose51327f92013-11-08 01:15:39 +0000250 } else {
251 // No special case with floating-point representation, report as usual.
252 }
253
Jordan Rose70e7e872014-02-19 17:44:11 +0000254 if (isIdenticalStmt(AC->getASTContext(), B->getLHS(), B->getRHS())) {
Jordan Rose51327f92013-11-08 01:15:39 +0000255 PathDiagnosticLocation ELoc =
256 PathDiagnosticLocation::createOperatorLoc(B, BR.getSourceManager());
257 StringRef Message;
Richard Smithc70f1d62017-12-14 15:16:18 +0000258 if (Op == BO_Cmp)
259 Message = "comparison of identical expressions always evaluates to "
260 "'equal'";
261 else if (((Op == BO_EQ) || (Op == BO_LE) || (Op == BO_GE)))
Jordan Rose51327f92013-11-08 01:15:39 +0000262 Message = "comparison of identical expressions always evaluates to true";
263 else
264 Message = "comparison of identical expressions always evaluates to false";
Alexander Kornienko4aca9b12014-02-11 21:49:21 +0000265 BR.EmitBasicReport(AC->getDecl(), Checker,
266 "Compare of identical expressions",
Jordan Rose51327f92013-11-08 01:15:39 +0000267 categories::LogicError, Message, ELoc);
268 }
Jordan Rose51327f92013-11-08 01:15:39 +0000269}
Jordan Rose60bd88d2013-12-10 18:18:06 +0000270
271bool FindIdenticalExprVisitor::VisitConditionalOperator(
272 const ConditionalOperator *C) {
273
274 // Check if expressions in conditional expression are identical
275 // from a symbolic point of view.
276
Jordan Rose70e7e872014-02-19 17:44:11 +0000277 if (isIdenticalStmt(AC->getASTContext(), C->getTrueExpr(),
Jordan Rose60bd88d2013-12-10 18:18:06 +0000278 C->getFalseExpr(), true)) {
279 PathDiagnosticLocation ELoc =
280 PathDiagnosticLocation::createConditionalColonLoc(
281 C, BR.getSourceManager());
282
283 SourceRange Sr[2];
284 Sr[0] = C->getTrueExpr()->getSourceRange();
285 Sr[1] = C->getFalseExpr()->getSourceRange();
286 BR.EmitBasicReport(
Alexander Kornienko4aca9b12014-02-11 21:49:21 +0000287 AC->getDecl(), Checker,
288 "Identical expressions in conditional expression",
Jordan Rose60bd88d2013-12-10 18:18:06 +0000289 categories::LogicError,
290 "identical expressions on both sides of ':' in conditional expression",
291 ELoc, Sr);
292 }
293 // We want to visit ALL nodes (expressions in conditional
294 // expressions too) that contains conditional operators,
295 // thus always return true to traverse ALL nodes.
296 return true;
297}
298
Jordan Rose70e7e872014-02-19 17:44:11 +0000299/// \brief Determines whether two statement trees are identical regarding
Jordan Rose51327f92013-11-08 01:15:39 +0000300/// operators and symbols.
301///
302/// Exceptions: expressions containing macros or functions with possible side
303/// effects are never considered identical.
304/// Limitations: (t + u) and (u + t) are not considered identical.
305/// t*(u + t) and t*u + t*t are not considered identical.
306///
Jordan Rose70e7e872014-02-19 17:44:11 +0000307static bool isIdenticalStmt(const ASTContext &Ctx, const Stmt *Stmt1,
308 const Stmt *Stmt2, bool IgnoreSideEffects) {
309
310 if (!Stmt1 || !Stmt2) {
Alexander Kornienko9c104902015-12-28 13:06:58 +0000311 return !Stmt1 && !Stmt2;
Jordan Rose51327f92013-11-08 01:15:39 +0000312 }
Jordan Rose70e7e872014-02-19 17:44:11 +0000313
314 // If Stmt1 & Stmt2 are of different class then they are not
315 // identical statements.
316 if (Stmt1->getStmtClass() != Stmt2->getStmtClass())
Jordan Rose51327f92013-11-08 01:15:39 +0000317 return false;
318
Jordan Rose70e7e872014-02-19 17:44:11 +0000319 const Expr *Expr1 = dyn_cast<Expr>(Stmt1);
320 const Expr *Expr2 = dyn_cast<Expr>(Stmt2);
321
322 if (Expr1 && Expr2) {
323 // If Stmt1 has side effects then don't warn even if expressions
324 // are identical.
325 if (!IgnoreSideEffects && Expr1->HasSideEffects(Ctx))
326 return false;
327 // If either expression comes from a macro then don't warn even if
328 // the expressions are identical.
329 if ((Expr1->getExprLoc().isMacroID()) || (Expr2->getExprLoc().isMacroID()))
330 return false;
331
332 // If all children of two expressions are identical, return true.
333 Expr::const_child_iterator I1 = Expr1->child_begin();
334 Expr::const_child_iterator I2 = Expr2->child_begin();
335 while (I1 != Expr1->child_end() && I2 != Expr2->child_end()) {
336 if (!*I1 || !*I2 || !isIdenticalStmt(Ctx, *I1, *I2, IgnoreSideEffects))
337 return false;
338 ++I1;
339 ++I2;
340 }
341 // If there are different number of children in the statements, return
342 // false.
343 if (I1 != Expr1->child_end())
344 return false;
345 if (I2 != Expr2->child_end())
346 return false;
347 }
348
349 switch (Stmt1->getStmtClass()) {
Jordan Rose51327f92013-11-08 01:15:39 +0000350 default:
351 return false;
Jordan Rose60bd88d2013-12-10 18:18:06 +0000352 case Stmt::CallExprClass:
Jordan Rose51327f92013-11-08 01:15:39 +0000353 case Stmt::ArraySubscriptExprClass:
Alexey Bataev1a3320e2015-08-25 14:24:04 +0000354 case Stmt::OMPArraySectionExprClass:
Jordan Rose51327f92013-11-08 01:15:39 +0000355 case Stmt::ImplicitCastExprClass:
356 case Stmt::ParenExprClass:
Jordan Rose70e7e872014-02-19 17:44:11 +0000357 case Stmt::BreakStmtClass:
358 case Stmt::ContinueStmtClass:
359 case Stmt::NullStmtClass:
Jordan Rose51327f92013-11-08 01:15:39 +0000360 return true;
Jordan Rose70e7e872014-02-19 17:44:11 +0000361 case Stmt::CStyleCastExprClass: {
362 const CStyleCastExpr* CastExpr1 = cast<CStyleCastExpr>(Stmt1);
363 const CStyleCastExpr* CastExpr2 = cast<CStyleCastExpr>(Stmt2);
364
365 return CastExpr1->getTypeAsWritten() == CastExpr2->getTypeAsWritten();
366 }
367 case Stmt::ReturnStmtClass: {
368 const ReturnStmt *ReturnStmt1 = cast<ReturnStmt>(Stmt1);
369 const ReturnStmt *ReturnStmt2 = cast<ReturnStmt>(Stmt2);
370
371 return isIdenticalStmt(Ctx, ReturnStmt1->getRetValue(),
372 ReturnStmt2->getRetValue(), IgnoreSideEffects);
373 }
374 case Stmt::ForStmtClass: {
375 const ForStmt *ForStmt1 = cast<ForStmt>(Stmt1);
376 const ForStmt *ForStmt2 = cast<ForStmt>(Stmt2);
377
378 if (!isIdenticalStmt(Ctx, ForStmt1->getInit(), ForStmt2->getInit(),
379 IgnoreSideEffects))
380 return false;
381 if (!isIdenticalStmt(Ctx, ForStmt1->getCond(), ForStmt2->getCond(),
382 IgnoreSideEffects))
383 return false;
384 if (!isIdenticalStmt(Ctx, ForStmt1->getInc(), ForStmt2->getInc(),
385 IgnoreSideEffects))
386 return false;
387 if (!isIdenticalStmt(Ctx, ForStmt1->getBody(), ForStmt2->getBody(),
388 IgnoreSideEffects))
389 return false;
390 return true;
391 }
392 case Stmt::DoStmtClass: {
393 const DoStmt *DStmt1 = cast<DoStmt>(Stmt1);
394 const DoStmt *DStmt2 = cast<DoStmt>(Stmt2);
395
396 if (!isIdenticalStmt(Ctx, DStmt1->getCond(), DStmt2->getCond(),
397 IgnoreSideEffects))
398 return false;
399 if (!isIdenticalStmt(Ctx, DStmt1->getBody(), DStmt2->getBody(),
400 IgnoreSideEffects))
401 return false;
402 return true;
403 }
404 case Stmt::WhileStmtClass: {
405 const WhileStmt *WStmt1 = cast<WhileStmt>(Stmt1);
406 const WhileStmt *WStmt2 = cast<WhileStmt>(Stmt2);
407
Jordan Rose45d71a22014-02-21 00:18:31 +0000408 if (!isIdenticalStmt(Ctx, WStmt1->getCond(), WStmt2->getCond(),
409 IgnoreSideEffects))
410 return false;
411 if (!isIdenticalStmt(Ctx, WStmt1->getBody(), WStmt2->getBody(),
412 IgnoreSideEffects))
413 return false;
414 return true;
Jordan Rose70e7e872014-02-19 17:44:11 +0000415 }
416 case Stmt::IfStmtClass: {
417 const IfStmt *IStmt1 = cast<IfStmt>(Stmt1);
418 const IfStmt *IStmt2 = cast<IfStmt>(Stmt2);
419
420 if (!isIdenticalStmt(Ctx, IStmt1->getCond(), IStmt2->getCond(),
421 IgnoreSideEffects))
422 return false;
423 if (!isIdenticalStmt(Ctx, IStmt1->getThen(), IStmt2->getThen(),
424 IgnoreSideEffects))
425 return false;
426 if (!isIdenticalStmt(Ctx, IStmt1->getElse(), IStmt2->getElse(),
427 IgnoreSideEffects))
428 return false;
429 return true;
430 }
431 case Stmt::CompoundStmtClass: {
432 const CompoundStmt *CompStmt1 = cast<CompoundStmt>(Stmt1);
433 const CompoundStmt *CompStmt2 = cast<CompoundStmt>(Stmt2);
434
435 if (CompStmt1->size() != CompStmt2->size())
436 return false;
437
438 CompoundStmt::const_body_iterator I1 = CompStmt1->body_begin();
439 CompoundStmt::const_body_iterator I2 = CompStmt2->body_begin();
440 while (I1 != CompStmt1->body_end() && I2 != CompStmt2->body_end()) {
441 if (!isIdenticalStmt(Ctx, *I1, *I2, IgnoreSideEffects))
442 return false;
443 ++I1;
444 ++I2;
445 }
446
447 return true;
448 }
449 case Stmt::CompoundAssignOperatorClass:
Jordan Rose51327f92013-11-08 01:15:39 +0000450 case Stmt::BinaryOperatorClass: {
Jordan Rose70e7e872014-02-19 17:44:11 +0000451 const BinaryOperator *BinOp1 = cast<BinaryOperator>(Stmt1);
452 const BinaryOperator *BinOp2 = cast<BinaryOperator>(Stmt2);
Jordan Rose51327f92013-11-08 01:15:39 +0000453 return BinOp1->getOpcode() == BinOp2->getOpcode();
454 }
455 case Stmt::CharacterLiteralClass: {
Jordan Rose70e7e872014-02-19 17:44:11 +0000456 const CharacterLiteral *CharLit1 = cast<CharacterLiteral>(Stmt1);
457 const CharacterLiteral *CharLit2 = cast<CharacterLiteral>(Stmt2);
Jordan Rose51327f92013-11-08 01:15:39 +0000458 return CharLit1->getValue() == CharLit2->getValue();
459 }
460 case Stmt::DeclRefExprClass: {
Jordan Rose70e7e872014-02-19 17:44:11 +0000461 const DeclRefExpr *DeclRef1 = cast<DeclRefExpr>(Stmt1);
462 const DeclRefExpr *DeclRef2 = cast<DeclRefExpr>(Stmt2);
Jordan Rose51327f92013-11-08 01:15:39 +0000463 return DeclRef1->getDecl() == DeclRef2->getDecl();
464 }
465 case Stmt::IntegerLiteralClass: {
Jordan Rose70e7e872014-02-19 17:44:11 +0000466 const IntegerLiteral *IntLit1 = cast<IntegerLiteral>(Stmt1);
467 const IntegerLiteral *IntLit2 = cast<IntegerLiteral>(Stmt2);
Jordan Rosef3544e92014-08-20 16:51:26 +0000468
469 llvm::APInt I1 = IntLit1->getValue();
470 llvm::APInt I2 = IntLit2->getValue();
471 if (I1.getBitWidth() != I2.getBitWidth())
472 return false;
473 return I1 == I2;
Jordan Rose51327f92013-11-08 01:15:39 +0000474 }
475 case Stmt::FloatingLiteralClass: {
Jordan Rose70e7e872014-02-19 17:44:11 +0000476 const FloatingLiteral *FloatLit1 = cast<FloatingLiteral>(Stmt1);
477 const FloatingLiteral *FloatLit2 = cast<FloatingLiteral>(Stmt2);
Jordan Rose51327f92013-11-08 01:15:39 +0000478 return FloatLit1->getValue().bitwiseIsEqual(FloatLit2->getValue());
479 }
Jordan Rose70e7e872014-02-19 17:44:11 +0000480 case Stmt::StringLiteralClass: {
481 const StringLiteral *StringLit1 = cast<StringLiteral>(Stmt1);
482 const StringLiteral *StringLit2 = cast<StringLiteral>(Stmt2);
Jordan Roseb6100302014-08-20 16:51:18 +0000483 return StringLit1->getBytes() == StringLit2->getBytes();
Jordan Rose70e7e872014-02-19 17:44:11 +0000484 }
Jordan Rose51327f92013-11-08 01:15:39 +0000485 case Stmt::MemberExprClass: {
Jordan Rose70e7e872014-02-19 17:44:11 +0000486 const MemberExpr *MemberStmt1 = cast<MemberExpr>(Stmt1);
487 const MemberExpr *MemberStmt2 = cast<MemberExpr>(Stmt2);
488 return MemberStmt1->getMemberDecl() == MemberStmt2->getMemberDecl();
Jordan Rose51327f92013-11-08 01:15:39 +0000489 }
490 case Stmt::UnaryOperatorClass: {
Jordan Rose70e7e872014-02-19 17:44:11 +0000491 const UnaryOperator *UnaryOp1 = cast<UnaryOperator>(Stmt1);
492 const UnaryOperator *UnaryOp2 = cast<UnaryOperator>(Stmt2);
Jordan Rose6f2f3902013-12-10 18:18:10 +0000493 return UnaryOp1->getOpcode() == UnaryOp2->getOpcode();
Jordan Rose51327f92013-11-08 01:15:39 +0000494 }
495 }
496}
497
498//===----------------------------------------------------------------------===//
499// FindIdenticalExprChecker
500//===----------------------------------------------------------------------===//
501
Benjamin Kramere8a2c182013-11-14 15:46:10 +0000502namespace {
Jordan Rose51327f92013-11-08 01:15:39 +0000503class FindIdenticalExprChecker : public Checker<check::ASTCodeBody> {
504public:
505 void checkASTCodeBody(const Decl *D, AnalysisManager &Mgr,
506 BugReporter &BR) const {
Alexander Kornienko4aca9b12014-02-11 21:49:21 +0000507 FindIdenticalExprVisitor Visitor(BR, this, Mgr.getAnalysisDeclContext(D));
Jordan Rose51327f92013-11-08 01:15:39 +0000508 Visitor.TraverseDecl(const_cast<Decl *>(D));
509 }
510};
Benjamin Kramere8a2c182013-11-14 15:46:10 +0000511} // end anonymous namespace
Jordan Rose51327f92013-11-08 01:15:39 +0000512
513void ento::registerIdenticalExprChecker(CheckerManager &Mgr) {
514 Mgr.registerChecker<FindIdenticalExprChecker>();
515}