26
26
using namespace clang ;
27
27
using namespace ento ;
28
28
29
- static bool isIdenticalExpr (const ASTContext &Ctx, const Expr *Expr1 ,
30
- const Expr *Expr2 , bool IgnoreSideEffects = false );
29
+ static bool isIdenticalStmt (const ASTContext &Ctx, const Stmt *Stmt1 ,
30
+ const Stmt *Stmt2 , bool IgnoreSideEffects = false );
31
31
// ===----------------------------------------------------------------------===//
32
32
// FindIdenticalExprVisitor - Identify nodes using identical expressions.
33
33
// ===----------------------------------------------------------------------===//
@@ -41,8 +41,10 @@ class FindIdenticalExprVisitor
41
41
AnalysisDeclContext *A)
42
42
: BR(B), Checker(Checker), AC(A) {}
43
43
// FindIdenticalExprVisitor only visits nodes
44
- // that are binary operators or conditional operators.
44
+ // that are binary operators, if statements or
45
+ // conditional operators.
45
46
bool VisitBinaryOperator (const BinaryOperator *B);
47
+ bool VisitIfStmt (const IfStmt *I);
46
48
bool VisitConditionalOperator (const ConditionalOperator *C);
47
49
48
50
private:
@@ -52,6 +54,39 @@ class FindIdenticalExprVisitor
52
54
};
53
55
} // end anonymous namespace
54
56
57
+ bool FindIdenticalExprVisitor::VisitIfStmt (const IfStmt *I) {
58
+ const Stmt *Stmt1 = I->getThen ();
59
+ const Stmt *Stmt2 = I->getElse ();
60
+
61
+ if (!Stmt1 || !Stmt2)
62
+ return true ;
63
+
64
+ // Special handling for code like:
65
+ //
66
+ // if (b) {
67
+ // i = 1;
68
+ // } else
69
+ // i = 1;
70
+ if (const CompoundStmt *CompStmt = dyn_cast<CompoundStmt>(Stmt1)) {
71
+ if (CompStmt->size () == 1 )
72
+ Stmt1 = CompStmt->body_back ();
73
+ }
74
+ if (const CompoundStmt *CompStmt = dyn_cast<CompoundStmt>(Stmt2)) {
75
+ if (CompStmt->size () == 1 )
76
+ Stmt2 = CompStmt->body_back ();
77
+ }
78
+
79
+ if (isIdenticalStmt (AC->getASTContext (), Stmt1, Stmt2, true )) {
80
+ PathDiagnosticLocation ELoc =
81
+ PathDiagnosticLocation::createBegin (I, BR.getSourceManager (), AC);
82
+ BR.EmitBasicReport (AC->getDecl (), Checker,
83
+ " Identical branches" ,
84
+ categories::LogicError,
85
+ " true and false branches are identical" , ELoc);
86
+ }
87
+ return true ;
88
+ }
89
+
55
90
bool FindIdenticalExprVisitor::VisitBinaryOperator (const BinaryOperator *B) {
56
91
BinaryOperator::Opcode Op = B->getOpcode ();
57
92
if (!BinaryOperator::isComparisonOp (Op))
@@ -107,7 +142,7 @@ bool FindIdenticalExprVisitor::VisitBinaryOperator(const BinaryOperator *B) {
107
142
// No special case with floating-point representation, report as usual.
108
143
}
109
144
110
- if (isIdenticalExpr (AC->getASTContext (), B->getLHS (), B->getRHS ())) {
145
+ if (isIdenticalStmt (AC->getASTContext (), B->getLHS (), B->getRHS ())) {
111
146
PathDiagnosticLocation ELoc =
112
147
PathDiagnosticLocation::createOperatorLoc (B, BR.getSourceManager ());
113
148
StringRef Message;
@@ -131,7 +166,7 @@ bool FindIdenticalExprVisitor::VisitConditionalOperator(
131
166
// Check if expressions in conditional expression are identical
132
167
// from a symbolic point of view.
133
168
134
- if (isIdenticalExpr (AC->getASTContext (), C->getTrueExpr (),
169
+ if (isIdenticalStmt (AC->getASTContext (), C->getTrueExpr (),
135
170
C->getFalseExpr (), true )) {
136
171
PathDiagnosticLocation ELoc =
137
172
PathDiagnosticLocation::createConditionalColonLoc (
@@ -153,89 +188,191 @@ bool FindIdenticalExprVisitor::VisitConditionalOperator(
153
188
return true ;
154
189
}
155
190
156
- // / \brief Determines whether two expression trees are identical regarding
191
+ // / \brief Determines whether two statement trees are identical regarding
157
192
// / operators and symbols.
158
193
// /
159
194
// / Exceptions: expressions containing macros or functions with possible side
160
195
// / effects are never considered identical.
161
196
// / Limitations: (t + u) and (u + t) are not considered identical.
162
197
// / t*(u + t) and t*u + t*t are not considered identical.
163
198
// /
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))
199
+ static bool isIdenticalStmt (const ASTContext &Ctx, const Stmt *Stmt1,
200
+ const Stmt *Stmt2, bool IgnoreSideEffects) {
201
+
202
+ if (!Stmt1 || !Stmt2) {
203
+ if (!Stmt1 && !Stmt2)
204
+ return true ;
173
205
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 ()))
206
+ }
207
+
208
+ // If Stmt1 & Stmt2 are of different class then they are not
209
+ // identical statements.
210
+ if (Stmt1->getStmtClass () != Stmt2->getStmtClass ())
177
211
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))
212
+
213
+ const Expr *Expr1 = dyn_cast<Expr>(Stmt1);
214
+ const Expr *Expr2 = dyn_cast<Expr>(Stmt2);
215
+
216
+ if (Expr1 && Expr2) {
217
+ // If Stmt1 has side effects then don't warn even if expressions
218
+ // are identical.
219
+ if (!IgnoreSideEffects && Expr1->HasSideEffects (Ctx))
220
+ return false ;
221
+ // If either expression comes from a macro then don't warn even if
222
+ // the expressions are identical.
223
+ if ((Expr1->getExprLoc ().isMacroID ()) || (Expr2->getExprLoc ().isMacroID ()))
224
+ return false ;
225
+
226
+ // If all children of two expressions are identical, return true.
227
+ Expr::const_child_iterator I1 = Expr1->child_begin ();
228
+ Expr::const_child_iterator I2 = Expr2->child_begin ();
229
+ while (I1 != Expr1->child_end () && I2 != Expr2->child_end ()) {
230
+ if (!*I1 || !*I2 || !isIdenticalStmt (Ctx, *I1, *I2, IgnoreSideEffects))
231
+ return false ;
232
+ ++I1;
233
+ ++I2;
234
+ }
235
+ // If there are different number of children in the statements, return
236
+ // false.
237
+ if (I1 != Expr1->child_end ())
238
+ return false ;
239
+ if (I2 != Expr2->child_end ())
186
240
return false ;
187
- ++I1;
188
- ++I2;
189
241
}
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
242
197
- switch (Expr1 ->getStmtClass ()) {
243
+ switch (Stmt1 ->getStmtClass ()) {
198
244
default :
199
245
return false ;
200
246
case Stmt::CallExprClass:
201
247
case Stmt::ArraySubscriptExprClass:
202
- case Stmt::CStyleCastExprClass:
203
248
case Stmt::ImplicitCastExprClass:
204
249
case Stmt::ParenExprClass:
250
+ case Stmt::BreakStmtClass:
251
+ case Stmt::ContinueStmtClass:
252
+ case Stmt::NullStmtClass:
253
+ return true ;
254
+ case Stmt::CStyleCastExprClass: {
255
+ const CStyleCastExpr* CastExpr1 = cast<CStyleCastExpr>(Stmt1);
256
+ const CStyleCastExpr* CastExpr2 = cast<CStyleCastExpr>(Stmt2);
257
+
258
+ return CastExpr1->getTypeAsWritten () == CastExpr2->getTypeAsWritten ();
259
+ }
260
+ case Stmt::ReturnStmtClass: {
261
+ const ReturnStmt *ReturnStmt1 = cast<ReturnStmt>(Stmt1);
262
+ const ReturnStmt *ReturnStmt2 = cast<ReturnStmt>(Stmt2);
263
+
264
+ return isIdenticalStmt (Ctx, ReturnStmt1->getRetValue (),
265
+ ReturnStmt2->getRetValue (), IgnoreSideEffects);
266
+ }
267
+ case Stmt::ForStmtClass: {
268
+ const ForStmt *ForStmt1 = cast<ForStmt>(Stmt1);
269
+ const ForStmt *ForStmt2 = cast<ForStmt>(Stmt2);
270
+
271
+ if (!isIdenticalStmt (Ctx, ForStmt1->getInit (), ForStmt2->getInit (),
272
+ IgnoreSideEffects))
273
+ return false ;
274
+ if (!isIdenticalStmt (Ctx, ForStmt1->getCond (), ForStmt2->getCond (),
275
+ IgnoreSideEffects))
276
+ return false ;
277
+ if (!isIdenticalStmt (Ctx, ForStmt1->getInc (), ForStmt2->getInc (),
278
+ IgnoreSideEffects))
279
+ return false ;
280
+ if (!isIdenticalStmt (Ctx, ForStmt1->getBody (), ForStmt2->getBody (),
281
+ IgnoreSideEffects))
282
+ return false ;
283
+ return true ;
284
+ }
285
+ case Stmt::DoStmtClass: {
286
+ const DoStmt *DStmt1 = cast<DoStmt>(Stmt1);
287
+ const DoStmt *DStmt2 = cast<DoStmt>(Stmt2);
288
+
289
+ if (!isIdenticalStmt (Ctx, DStmt1->getCond (), DStmt2->getCond (),
290
+ IgnoreSideEffects))
291
+ return false ;
292
+ if (!isIdenticalStmt (Ctx, DStmt1->getBody (), DStmt2->getBody (),
293
+ IgnoreSideEffects))
294
+ return false ;
295
+ return true ;
296
+ }
297
+ case Stmt::WhileStmtClass: {
298
+ const WhileStmt *WStmt1 = cast<WhileStmt>(Stmt1);
299
+ const WhileStmt *WStmt2 = cast<WhileStmt>(Stmt2);
300
+
301
+ return isIdenticalStmt (Ctx, WStmt1->getCond (), WStmt2->getCond (),
302
+ IgnoreSideEffects);
303
+ }
304
+ case Stmt::IfStmtClass: {
305
+ const IfStmt *IStmt1 = cast<IfStmt>(Stmt1);
306
+ const IfStmt *IStmt2 = cast<IfStmt>(Stmt2);
307
+
308
+ if (!isIdenticalStmt (Ctx, IStmt1->getCond (), IStmt2->getCond (),
309
+ IgnoreSideEffects))
310
+ return false ;
311
+ if (!isIdenticalStmt (Ctx, IStmt1->getThen (), IStmt2->getThen (),
312
+ IgnoreSideEffects))
313
+ return false ;
314
+ if (!isIdenticalStmt (Ctx, IStmt1->getElse (), IStmt2->getElse (),
315
+ IgnoreSideEffects))
316
+ return false ;
317
+ return true ;
318
+ }
319
+ case Stmt::CompoundStmtClass: {
320
+ const CompoundStmt *CompStmt1 = cast<CompoundStmt>(Stmt1);
321
+ const CompoundStmt *CompStmt2 = cast<CompoundStmt>(Stmt2);
322
+
323
+ if (CompStmt1->size () != CompStmt2->size ())
324
+ return false ;
325
+
326
+ CompoundStmt::const_body_iterator I1 = CompStmt1->body_begin ();
327
+ CompoundStmt::const_body_iterator I2 = CompStmt2->body_begin ();
328
+ while (I1 != CompStmt1->body_end () && I2 != CompStmt2->body_end ()) {
329
+ if (!isIdenticalStmt (Ctx, *I1, *I2, IgnoreSideEffects))
330
+ return false ;
331
+ ++I1;
332
+ ++I2;
333
+ }
334
+
205
335
return true ;
336
+ }
337
+ case Stmt::CompoundAssignOperatorClass:
206
338
case Stmt::BinaryOperatorClass: {
207
- const BinaryOperator *BinOp1 = cast<BinaryOperator>(Expr1 );
208
- const BinaryOperator *BinOp2 = cast<BinaryOperator>(Expr2 );
339
+ const BinaryOperator *BinOp1 = cast<BinaryOperator>(Stmt1 );
340
+ const BinaryOperator *BinOp2 = cast<BinaryOperator>(Stmt2 );
209
341
return BinOp1->getOpcode () == BinOp2->getOpcode ();
210
342
}
211
343
case Stmt::CharacterLiteralClass: {
212
- const CharacterLiteral *CharLit1 = cast<CharacterLiteral>(Expr1 );
213
- const CharacterLiteral *CharLit2 = cast<CharacterLiteral>(Expr2 );
344
+ const CharacterLiteral *CharLit1 = cast<CharacterLiteral>(Stmt1 );
345
+ const CharacterLiteral *CharLit2 = cast<CharacterLiteral>(Stmt2 );
214
346
return CharLit1->getValue () == CharLit2->getValue ();
215
347
}
216
348
case Stmt::DeclRefExprClass: {
217
- const DeclRefExpr *DeclRef1 = cast<DeclRefExpr>(Expr1 );
218
- const DeclRefExpr *DeclRef2 = cast<DeclRefExpr>(Expr2 );
349
+ const DeclRefExpr *DeclRef1 = cast<DeclRefExpr>(Stmt1 );
350
+ const DeclRefExpr *DeclRef2 = cast<DeclRefExpr>(Stmt2 );
219
351
return DeclRef1->getDecl () == DeclRef2->getDecl ();
220
352
}
221
353
case Stmt::IntegerLiteralClass: {
222
- const IntegerLiteral *IntLit1 = cast<IntegerLiteral>(Expr1 );
223
- const IntegerLiteral *IntLit2 = cast<IntegerLiteral>(Expr2 );
354
+ const IntegerLiteral *IntLit1 = cast<IntegerLiteral>(Stmt1 );
355
+ const IntegerLiteral *IntLit2 = cast<IntegerLiteral>(Stmt2 );
224
356
return IntLit1->getValue () == IntLit2->getValue ();
225
357
}
226
358
case Stmt::FloatingLiteralClass: {
227
- const FloatingLiteral *FloatLit1 = cast<FloatingLiteral>(Expr1 );
228
- const FloatingLiteral *FloatLit2 = cast<FloatingLiteral>(Expr2 );
359
+ const FloatingLiteral *FloatLit1 = cast<FloatingLiteral>(Stmt1 );
360
+ const FloatingLiteral *FloatLit2 = cast<FloatingLiteral>(Stmt2 );
229
361
return FloatLit1->getValue ().bitwiseIsEqual (FloatLit2->getValue ());
230
362
}
363
+ case Stmt::StringLiteralClass: {
364
+ const StringLiteral *StringLit1 = cast<StringLiteral>(Stmt1);
365
+ const StringLiteral *StringLit2 = cast<StringLiteral>(Stmt2);
366
+ return StringLit1->getString () == StringLit2->getString ();
367
+ }
231
368
case Stmt::MemberExprClass: {
232
- const MemberExpr *MemberExpr1 = cast<MemberExpr>(Expr1 );
233
- const MemberExpr *MemberExpr2 = cast<MemberExpr>(Expr2 );
234
- return MemberExpr1 ->getMemberDecl () == MemberExpr2 ->getMemberDecl ();
369
+ const MemberExpr *MemberStmt1 = cast<MemberExpr>(Stmt1 );
370
+ const MemberExpr *MemberStmt2 = cast<MemberExpr>(Stmt2 );
371
+ return MemberStmt1 ->getMemberDecl () == MemberStmt2 ->getMemberDecl ();
235
372
}
236
373
case Stmt::UnaryOperatorClass: {
237
- const UnaryOperator *UnaryOp1 = cast<UnaryOperator>(Expr1 );
238
- const UnaryOperator *UnaryOp2 = cast<UnaryOperator>(Expr2 );
374
+ const UnaryOperator *UnaryOp1 = cast<UnaryOperator>(Stmt1 );
375
+ const UnaryOperator *UnaryOp2 = cast<UnaryOperator>(Stmt2 );
239
376
return UnaryOp1->getOpcode () == UnaryOp2->getOpcode ();
240
377
}
241
378
}
0 commit comments