Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/clang/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp
Line
Count
Source (jump to first uncovered line)
1
//== IdenticalExprChecker.cpp - Identical expression checker----------------==//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
///
9
/// \file
10
/// This defines IdenticalExprChecker, a check that warns about
11
/// unintended use of identical expressions.
12
///
13
/// It checks for use of identical expressions with comparison operators and
14
/// inside conditional expressions.
15
///
16
//===----------------------------------------------------------------------===//
17
18
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
19
#include "clang/AST/RecursiveASTVisitor.h"
20
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
21
#include "clang/StaticAnalyzer/Core/Checker.h"
22
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
23
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
24
25
using namespace clang;
26
using namespace ento;
27
28
static bool isIdenticalStmt(const ASTContext &Ctx, const Stmt *Stmt1,
29
                            const Stmt *Stmt2, bool IgnoreSideEffects = false);
30
//===----------------------------------------------------------------------===//
31
// FindIdenticalExprVisitor - Identify nodes using identical expressions.
32
//===----------------------------------------------------------------------===//
33
34
namespace {
35
class FindIdenticalExprVisitor
36
    : public RecursiveASTVisitor<FindIdenticalExprVisitor> {
37
  BugReporter &BR;
38
  const CheckerBase *Checker;
39
  AnalysisDeclContext *AC;
40
public:
41
  explicit FindIdenticalExprVisitor(BugReporter &B,
42
                                    const CheckerBase *Checker,
43
                                    AnalysisDeclContext *A)
44
1.26k
      : BR(B), Checker(Checker), AC(A) {}
45
  // FindIdenticalExprVisitor only visits nodes
46
  // that are binary operators, if statements or
47
  // conditional operators.
48
  bool VisitBinaryOperator(const BinaryOperator *B);
49
  bool VisitIfStmt(const IfStmt *I);
50
  bool VisitConditionalOperator(const ConditionalOperator *C);
51
52
private:
53
  void reportIdenticalExpr(const BinaryOperator *B, bool CheckBitwise,
54
                           ArrayRef<SourceRange> Sr);
55
  void checkBitwiseOrLogicalOp(const BinaryOperator *B, bool CheckBitwise);
56
  void checkComparisonOp(const BinaryOperator *B);
57
};
58
} // end anonymous namespace
59
60
void FindIdenticalExprVisitor::reportIdenticalExpr(const BinaryOperator *B,
61
                                                   bool CheckBitwise,
62
7
                                                   ArrayRef<SourceRange> Sr) {
63
7
  StringRef Message;
64
7
  if (CheckBitwise)
65
4
    Message = "identical expressions on both sides of bitwise operator";
66
3
  else
67
3
    Message = "identical expressions on both sides of logical operator";
68
7
69
7
  PathDiagnosticLocation ELoc =
70
7
      PathDiagnosticLocation::createOperatorLoc(B, BR.getSourceManager());
71
7
  BR.EmitBasicReport(AC->getDecl(), Checker,
72
7
                     "Use of identical expressions",
73
7
                     categories::LogicError,
74
7
                     Message, ELoc, Sr);
75
7
}
76
77
void FindIdenticalExprVisitor::checkBitwiseOrLogicalOp(const BinaryOperator *B,
78
87
                                                       bool CheckBitwise) {
79
87
  SourceRange Sr[2];
80
87
81
87
  const Expr *LHS = B->getLHS();
82
87
  const Expr *RHS = B->getRHS();
83
87
84
87
  // Split operators as long as we still have operators to split on. We will
85
87
  // get called for every binary operator in an expression so there is no need
86
87
  // to check every one against each other here, just the right most one with
87
87
  // the others.
88
90
  while (const BinaryOperator *B2 = dyn_cast<BinaryOperator>(LHS)) {
89
29
    if (B->getOpcode() != B2->getOpcode())
90
26
      break;
91
3
    if (isIdenticalStmt(AC->getASTContext(), RHS, B2->getRHS())) {
92
0
      Sr[0] = RHS->getSourceRange();
93
0
      Sr[1] = B2->getRHS()->getSourceRange();
94
0
      reportIdenticalExpr(B, CheckBitwise, Sr);
95
0
    }
96
3
    LHS = B2->getLHS();
97
3
  }
98
87
99
87
  if (isIdenticalStmt(AC->getASTContext(), RHS, LHS)) {
100
7
    Sr[0] = RHS->getSourceRange();
101
7
    Sr[1] = LHS->getSourceRange();
102
7
    reportIdenticalExpr(B, CheckBitwise, Sr);
103
7
  }
104
87
}
105
106
557
bool FindIdenticalExprVisitor::VisitIfStmt(const IfStmt *I) {
107
557
  const Stmt *Stmt1 = I->getThen();
108
557
  const Stmt *Stmt2 = I->getElse();
109
557
110
557
  // Check for identical inner condition:
111
557
  //
112
557
  // if (x<10) {
113
557
  //   if (x<10) {
114
557
  //   ..
115
557
  if (const CompoundStmt *CS = dyn_cast<CompoundStmt>(Stmt1)) {
116
161
    if (!CS->body_empty()) {
117
138
      const IfStmt *InnerIf = dyn_cast<IfStmt>(*CS->body_begin());
118
138
      if (InnerIf && 
isIdenticalStmt(AC->getASTContext(), I->getCond(), InnerIf->getCond(), /*IgnoreSideEffects=*/ false)14
) {
119
1
        PathDiagnosticLocation ELoc(InnerIf->getCond(), BR.getSourceManager(), AC);
120
1
        BR.EmitBasicReport(AC->getDecl(), Checker, "Identical conditions",
121
1
          categories::LogicError,
122
1
          "conditions of the inner and outer statements are identical",
123
1
          ELoc);
124
1
      }
125
138
    }
126
161
  }
127
557
128
557
  // Check for identical conditions:
129
557
  //
130
557
  // if (b) {
131
557
  //   foo1();
132
557
  // } else if (b) {
133
557
  //   foo2();
134
557
  // }
135
557
  if (Stmt1 && Stmt2) {
136
105
    const Expr *Cond1 = I->getCond();
137
105
    const Stmt *Else = Stmt2;
138
159
    while (const IfStmt *I2 = dyn_cast_or_null<IfStmt>(Else)) {
139
54
      const Expr *Cond2 = I2->getCond();
140
54
      if (isIdenticalStmt(AC->getASTContext(), Cond1, Cond2, false)) {
141
11
        SourceRange Sr = Cond1->getSourceRange();
142
11
        PathDiagnosticLocation ELoc(Cond2, BR.getSourceManager(), AC);
143
11
        BR.EmitBasicReport(AC->getDecl(), Checker, "Identical conditions",
144
11
                           categories::LogicError,
145
11
                           "expression is identical to previous condition",
146
11
                           ELoc, Sr);
147
11
      }
148
54
      Else = I2->getElse();
149
54
    }
150
105
  }
151
557
152
557
  if (!Stmt1 || !Stmt2)
153
452
    return true;
154
105
155
105
  // Special handling for code like:
156
105
  //
157
105
  // if (b) {
158
105
  //   i = 1;
159
105
  // } else
160
105
  //   i = 1;
161
105
  if (const CompoundStmt *CompStmt = dyn_cast<CompoundStmt>(Stmt1)) {
162
28
    if (CompStmt->size() == 1)
163
15
      Stmt1 = CompStmt->body_back();
164
28
  }
165
105
  if (const CompoundStmt *CompStmt = dyn_cast<CompoundStmt>(Stmt2)) {
166
25
    if (CompStmt->size() == 1)
167
22
      Stmt2 = CompStmt->body_back();
168
25
  }
169
105
170
105
  if (isIdenticalStmt(AC->getASTContext(), Stmt1, Stmt2, true)) {
171
13
      PathDiagnosticLocation ELoc =
172
13
          PathDiagnosticLocation::createBegin(I, BR.getSourceManager(), AC);
173
13
      BR.EmitBasicReport(AC->getDecl(), Checker,
174
13
                         "Identical branches",
175
13
                         categories::LogicError,
176
13
                         "true and false branches are identical", ELoc);
177
13
  }
178
105
  return true;
179
105
}
180
181
2.02k
bool FindIdenticalExprVisitor::VisitBinaryOperator(const BinaryOperator *B) {
182
2.02k
  BinaryOperator::Opcode Op = B->getOpcode();
183
2.02k
184
2.02k
  if (BinaryOperator::isBitwiseOp(Op))
185
26
    checkBitwiseOrLogicalOp(B, true);
186
2.02k
187
2.02k
  if (BinaryOperator::isLogicalOp(Op))
188
61
    checkBitwiseOrLogicalOp(B, false);
189
2.02k
190
2.02k
  if (BinaryOperator::isComparisonOp(Op))
191
844
    checkComparisonOp(B);
192
2.02k
193
2.02k
  // We want to visit ALL nodes (subexpressions of binary comparison
194
2.02k
  // expressions too) that contains comparison operators.
195
2.02k
  // True is always returned to traverse ALL nodes.
196
2.02k
  return true;
197
2.02k
}
198
199
844
void FindIdenticalExprVisitor::checkComparisonOp(const BinaryOperator *B) {
200
844
  BinaryOperator::Opcode Op = B->getOpcode();
201
844
202
844
  //
203
844
  // Special case for floating-point representation.
204
844
  //
205
844
  // If expressions on both sides of comparison operator are of type float,
206
844
  // then for some comparison operators no warning shall be
207
844
  // reported even if the expressions are identical from a symbolic point of
208
844
  // view. Comparison between expressions, declared variables and literals
209
844
  // are treated differently.
210
844
  //
211
844
  // != and == between float literals that have the same value should NOT warn.
212
844
  // < > between float literals that have the same value SHOULD warn.
213
844
  //
214
844
  // != and == between the same float declaration should NOT warn.
215
844
  // < > between the same float declaration SHOULD warn.
216
844
  //
217
844
  // != and == between eq. expressions that evaluates into float
218
844
  //           should NOT warn.
219
844
  // < >       between eq. expressions that evaluates into float
220
844
  //           should NOT warn.
221
844
  //
222
844
  const Expr *LHS = B->getLHS()->IgnoreParenImpCasts();
223
844
  const Expr *RHS = B->getRHS()->IgnoreParenImpCasts();
224
844
225
844
  const DeclRefExpr *DeclRef1 = dyn_cast<DeclRefExpr>(LHS);
226
844
  const DeclRefExpr *DeclRef2 = dyn_cast<DeclRefExpr>(RHS);
227
844
  const FloatingLiteral *FloatLit1 = dyn_cast<FloatingLiteral>(LHS);
228
844
  const FloatingLiteral *FloatLit2 = dyn_cast<FloatingLiteral>(RHS);
229
844
  if ((DeclRef1) && 
(DeclRef2)366
) {
230
68
    if ((DeclRef1->getType()->hasFloatingRepresentation()) &&
231
68
        
(DeclRef2->getType()->hasFloatingRepresentation())12
) {
232
8
      if (DeclRef1->getDecl() == DeclRef2->getDecl()) {
233
4
        if ((Op == BO_EQ) || 
(Op == BO_NE)3
) {
234
2
          return;
235
2
        }
236
776
      }
237
8
    }
238
776
  } else if ((FloatLit1) && 
(FloatLit2)12
) {
239
8
    if (FloatLit1->getValue().bitwiseIsEqual(FloatLit2->getValue())) {
240
4
      if ((Op == BO_EQ) || 
(Op == BO_NE)3
) {
241
2
        return;
242
2
      }
243
768
    }
244
768
  } else if (LHS->getType()->hasFloatingRepresentation()) {
245
43
    // If any side of comparison operator still has floating-point
246
43
    // representation, then it's an expression. Don't warn.
247
43
    // Here only LHS is checked since RHS will be implicit casted to float.
248
43
    return;
249
725
  } else {
250
725
    // No special case with floating-point representation, report as usual.
251
725
  }
252
844
253
844
  
if (797
isIdenticalStmt(AC->getASTContext(), B->getLHS(), B->getRHS())797
) {
254
39
    PathDiagnosticLocation ELoc =
255
39
        PathDiagnosticLocation::createOperatorLoc(B, BR.getSourceManager());
256
39
    StringRef Message;
257
39
    if (Op == BO_Cmp)
258
0
      Message = "comparison of identical expressions always evaluates to "
259
0
                "'equal'";
260
39
    else if (((Op == BO_EQ) || 
(Op == BO_LE)30
||
(Op == BO_GE)30
))
261
9
      Message = "comparison of identical expressions always evaluates to true";
262
30
    else
263
30
      Message = "comparison of identical expressions always evaluates to false";
264
39
    BR.EmitBasicReport(AC->getDecl(), Checker,
265
39
                       "Compare of identical expressions",
266
39
                       categories::LogicError, Message, ELoc);
267
39
  }
268
797
}
269
270
bool FindIdenticalExprVisitor::VisitConditionalOperator(
271
58
    const ConditionalOperator *C) {
272
58
273
58
  // Check if expressions in conditional expression are identical
274
58
  // from a symbolic point of view.
275
58
276
58
  if (isIdenticalStmt(AC->getASTContext(), C->getTrueExpr(),
277
58
                      C->getFalseExpr(), true)) {
278
16
    PathDiagnosticLocation ELoc =
279
16
        PathDiagnosticLocation::createConditionalColonLoc(
280
16
            C, BR.getSourceManager());
281
16
282
16
    SourceRange Sr[2];
283
16
    Sr[0] = C->getTrueExpr()->getSourceRange();
284
16
    Sr[1] = C->getFalseExpr()->getSourceRange();
285
16
    BR.EmitBasicReport(
286
16
        AC->getDecl(), Checker,
287
16
        "Identical expressions in conditional expression",
288
16
        categories::LogicError,
289
16
        "identical expressions on both sides of ':' in conditional expression",
290
16
        ELoc, Sr);
291
16
  }
292
58
  // We want to visit ALL nodes (expressions in conditional
293
58
  // expressions too) that contains conditional operators,
294
58
  // thus always return true to traverse ALL nodes.
295
58
  return true;
296
58
}
297
298
/// Determines whether two statement trees are identical regarding
299
/// operators and symbols.
300
///
301
/// Exceptions: expressions containing macros or functions with possible side
302
/// effects are never considered identical.
303
/// Limitations: (t + u) and (u + t) are not considered identical.
304
/// t*(u + t) and t*u + t*t are not considered identical.
305
///
306
static bool isIdenticalStmt(const ASTContext &Ctx, const Stmt *Stmt1,
307
2.12k
                            const Stmt *Stmt2, bool IgnoreSideEffects) {
308
2.12k
309
2.12k
  if (!Stmt1 || 
!Stmt22.12k
) {
310
1
    return !Stmt1 && !Stmt2;
311
1
  }
312
2.12k
313
2.12k
  // If Stmt1 & Stmt2 are of different class then they are not
314
2.12k
  // identical statements.
315
2.12k
  if (Stmt1->getStmtClass() != Stmt2->getStmtClass())
316
765
    return false;
317
1.35k
318
1.35k
  const Expr *Expr1 = dyn_cast<Expr>(Stmt1);
319
1.35k
  const Expr *Expr2 = dyn_cast<Expr>(Stmt2);
320
1.35k
321
1.35k
  if (Expr1 && 
Expr21.34k
) {
322
1.34k
    // If Stmt1 has side effects then don't warn even if expressions
323
1.34k
    // are identical.
324
1.34k
    if (!IgnoreSideEffects && 
Expr1->HasSideEffects(Ctx)964
)
325
33
      return false;
326
1.30k
    // If either expression comes from a macro then don't warn even if
327
1.30k
    // the expressions are identical.
328
1.30k
    if ((Expr1->getExprLoc().isMacroID()) || 
(Expr2->getExprLoc().isMacroID())1.30k
)
329
21
      return false;
330
1.28k
331
1.28k
    // If all children of two expressions are identical, return true.
332
1.28k
    Expr::const_child_iterator I1 = Expr1->child_begin();
333
1.28k
    Expr::const_child_iterator I2 = Expr2->child_begin();
334
1.79k
    while (I1 != Expr1->child_end() && 
I2 != Expr2->child_end()983
) {
335
983
      if (!*I1 || !*I2 || !isIdenticalStmt(Ctx, *I1, *I2, IgnoreSideEffects))
336
478
        return false;
337
505
      ++I1;
338
505
      ++I2;
339
505
    }
340
1.28k
    // If there are different number of children in the statements, return
341
1.28k
    // false.
342
1.28k
    
if (810
I1 != Expr1->child_end()810
)
343
0
      return false;
344
810
    if (I2 != Expr2->child_end())
345
0
      return false;
346
825
  }
347
825
348
825
  switch (Stmt1->getStmtClass()) {
349
825
  default:
350
18
    return false;
351
825
  case Stmt::CallExprClass:
352
224
  case Stmt::ArraySubscriptExprClass:
353
224
  case Stmt::OMPArraySectionExprClass:
354
224
  case Stmt::ImplicitCastExprClass:
355
224
  case Stmt::ParenExprClass:
356
224
  case Stmt::BreakStmtClass:
357
224
  case Stmt::ContinueStmtClass:
358
224
  case Stmt::NullStmtClass:
359
224
    return true;
360
224
  case Stmt::CStyleCastExprClass: {
361
28
    const CStyleCastExpr* CastExpr1 = cast<CStyleCastExpr>(Stmt1);
362
28
    const CStyleCastExpr* CastExpr2 = cast<CStyleCastExpr>(Stmt2);
363
28
364
28
    return CastExpr1->getTypeAsWritten() == CastExpr2->getTypeAsWritten();
365
224
  }
366
224
  case Stmt::ReturnStmtClass: {
367
4
    const ReturnStmt *ReturnStmt1 = cast<ReturnStmt>(Stmt1);
368
4
    const ReturnStmt *ReturnStmt2 = cast<ReturnStmt>(Stmt2);
369
4
370
4
    return isIdenticalStmt(Ctx, ReturnStmt1->getRetValue(),
371
4
                           ReturnStmt2->getRetValue(), IgnoreSideEffects);
372
224
  }
373
224
  case Stmt::ForStmtClass: {
374
1
    const ForStmt *ForStmt1 = cast<ForStmt>(Stmt1);
375
1
    const ForStmt *ForStmt2 = cast<ForStmt>(Stmt2);
376
1
377
1
    if (!isIdenticalStmt(Ctx, ForStmt1->getInit(), ForStmt2->getInit(),
378
1
                         IgnoreSideEffects))
379
0
      return false;
380
1
    if (!isIdenticalStmt(Ctx, ForStmt1->getCond(), ForStmt2->getCond(),
381
1
                         IgnoreSideEffects))
382
0
      return false;
383
1
    if (!isIdenticalStmt(Ctx, ForStmt1->getInc(), ForStmt2->getInc(),
384
1
                         IgnoreSideEffects))
385
0
      return false;
386
1
    if (!isIdenticalStmt(Ctx, ForStmt1->getBody(), ForStmt2->getBody(),
387
1
                         IgnoreSideEffects))
388
0
      return false;
389
1
    return true;
390
1
  }
391
1
  case Stmt::DoStmtClass: {
392
1
    const DoStmt *DStmt1 = cast<DoStmt>(Stmt1);
393
1
    const DoStmt *DStmt2 = cast<DoStmt>(Stmt2);
394
1
395
1
    if (!isIdenticalStmt(Ctx, DStmt1->getCond(), DStmt2->getCond(),
396
1
                         IgnoreSideEffects))
397
0
      return false;
398
1
    if (!isIdenticalStmt(Ctx, DStmt1->getBody(), DStmt2->getBody(),
399
1
                         IgnoreSideEffects))
400
0
      return false;
401
1
    return true;
402
1
  }
403
2
  case Stmt::WhileStmtClass: {
404
2
    const WhileStmt *WStmt1 = cast<WhileStmt>(Stmt1);
405
2
    const WhileStmt *WStmt2 = cast<WhileStmt>(Stmt2);
406
2
407
2
    if (!isIdenticalStmt(Ctx, WStmt1->getCond(), WStmt2->getCond(),
408
2
                         IgnoreSideEffects))
409
0
      return false;
410
2
    if (!isIdenticalStmt(Ctx, WStmt1->getBody(), WStmt2->getBody(),
411
2
                         IgnoreSideEffects))
412
1
      return false;
413
1
    return true;
414
1
  }
415
1
  case Stmt::IfStmtClass: {
416
1
    const IfStmt *IStmt1 = cast<IfStmt>(Stmt1);
417
1
    const IfStmt *IStmt2 = cast<IfStmt>(Stmt2);
418
1
419
1
    if (!isIdenticalStmt(Ctx, IStmt1->getCond(), IStmt2->getCond(),
420
1
                         IgnoreSideEffects))
421
0
      return false;
422
1
    if (!isIdenticalStmt(Ctx, IStmt1->getThen(), IStmt2->getThen(),
423
1
                         IgnoreSideEffects))
424
0
      return false;
425
1
    if (!isIdenticalStmt(Ctx, IStmt1->getElse(), IStmt2->getElse(),
426
1
                         IgnoreSideEffects))
427
0
      return false;
428
1
    return true;
429
1
  }
430
4
  case Stmt::CompoundStmtClass: {
431
4
    const CompoundStmt *CompStmt1 = cast<CompoundStmt>(Stmt1);
432
4
    const CompoundStmt *CompStmt2 = cast<CompoundStmt>(Stmt2);
433
4
434
4
    if (CompStmt1->size() != CompStmt2->size())
435
0
      return false;
436
4
437
4
    CompoundStmt::const_body_iterator I1 = CompStmt1->body_begin();
438
4
    CompoundStmt::const_body_iterator I2 = CompStmt2->body_begin();
439
8
    while (I1 != CompStmt1->body_end() && 
I2 != CompStmt2->body_end()5
) {
440
5
      if (!isIdenticalStmt(Ctx, *I1, *I2, IgnoreSideEffects))
441
1
        return false;
442
4
      ++I1;
443
4
      ++I2;
444
4
    }
445
4
446
4
    
return true3
;
447
4
  }
448
76
  case Stmt::CompoundAssignOperatorClass:
449
76
  case Stmt::BinaryOperatorClass: {
450
76
    const BinaryOperator *BinOp1 = cast<BinaryOperator>(Stmt1);
451
76
    const BinaryOperator *BinOp2 = cast<BinaryOperator>(Stmt2);
452
76
    return BinOp1->getOpcode() == BinOp2->getOpcode();
453
76
  }
454
76
  case Stmt::CharacterLiteralClass: {
455
0
    const CharacterLiteral *CharLit1 = cast<CharacterLiteral>(Stmt1);
456
0
    const CharacterLiteral *CharLit2 = cast<CharacterLiteral>(Stmt2);
457
0
    return CharLit1->getValue() == CharLit2->getValue();
458
76
  }
459
326
  case Stmt::DeclRefExprClass: {
460
326
    const DeclRefExpr *DeclRef1 = cast<DeclRefExpr>(Stmt1);
461
326
    const DeclRefExpr *DeclRef2 = cast<DeclRefExpr>(Stmt2);
462
326
    return DeclRef1->getDecl() == DeclRef2->getDecl();
463
76
  }
464
120
  case Stmt::IntegerLiteralClass: {
465
120
    const IntegerLiteral *IntLit1 = cast<IntegerLiteral>(Stmt1);
466
120
    const IntegerLiteral *IntLit2 = cast<IntegerLiteral>(Stmt2);
467
120
468
120
    llvm::APInt I1 = IntLit1->getValue();
469
120
    llvm::APInt I2 = IntLit2->getValue();
470
120
    if (I1.getBitWidth() != I2.getBitWidth())
471
1
      return false;
472
119
    return  I1 == I2;
473
119
  }
474
119
  case Stmt::FloatingLiteralClass: {
475
6
    const FloatingLiteral *FloatLit1 = cast<FloatingLiteral>(Stmt1);
476
6
    const FloatingLiteral *FloatLit2 = cast<FloatingLiteral>(Stmt2);
477
6
    return FloatLit1->getValue().bitwiseIsEqual(FloatLit2->getValue());
478
119
  }
479
119
  case Stmt::StringLiteralClass: {
480
3
    const StringLiteral *StringLit1 = cast<StringLiteral>(Stmt1);
481
3
    const StringLiteral *StringLit2 = cast<StringLiteral>(Stmt2);
482
3
    return StringLit1->getBytes() == StringLit2->getBytes();
483
119
  }
484
119
  case Stmt::MemberExprClass: {
485
0
    const MemberExpr *MemberStmt1 = cast<MemberExpr>(Stmt1);
486
0
    const MemberExpr *MemberStmt2 = cast<MemberExpr>(Stmt2);
487
0
    return MemberStmt1->getMemberDecl() == MemberStmt2->getMemberDecl();
488
119
  }
489
119
  case Stmt::UnaryOperatorClass: {
490
11
    const UnaryOperator *UnaryOp1 = cast<UnaryOperator>(Stmt1);
491
11
    const UnaryOperator *UnaryOp2 = cast<UnaryOperator>(Stmt2);
492
11
    return UnaryOp1->getOpcode() == UnaryOp2->getOpcode();
493
119
  }
494
825
  }
495
825
}
496
497
//===----------------------------------------------------------------------===//
498
// FindIdenticalExprChecker
499
//===----------------------------------------------------------------------===//
500
501
namespace {
502
class FindIdenticalExprChecker : public Checker<check::ASTCodeBody> {
503
public:
504
  void checkASTCodeBody(const Decl *D, AnalysisManager &Mgr,
505
1.26k
                        BugReporter &BR) const {
506
1.26k
    FindIdenticalExprVisitor Visitor(BR, this, Mgr.getAnalysisDeclContext(D));
507
1.26k
    Visitor.TraverseDecl(const_cast<Decl *>(D));
508
1.26k
  }
509
};
510
} // end anonymous namespace
511
512
70
void ento::registerIdenticalExprChecker(CheckerManager &Mgr) {
513
70
  Mgr.registerChecker<FindIdenticalExprChecker>();
514
70
}
515
516
70
bool ento::shouldRegisterIdenticalExprChecker(const LangOptions &LO) {
517
70
  return true;
518
70
}