@@ -102,6 +102,212 @@ void BranchCloneCheck::registerMatchers(MatchFinder *Finder) {
102
102
this );
103
103
Finder->addMatcher (switchStmt ().bind (" switch" ), this );
104
104
Finder->addMatcher (conditionalOperator ().bind (" condOp" ), this );
105
+ Finder->addMatcher (
106
+ ifStmt ((hasThen (hasDescendant (ifStmt ())))).bind (" ifWithDescendantIf" ),
107
+ this );
108
+ }
109
+
110
+ // / Determines whether two statement trees are identical regarding
111
+ // / operators and symbols.
112
+ // /
113
+ // / Exceptions: expressions containing macros or functions with possible side
114
+ // / effects are never considered identical.
115
+ // / Limitations: (t + u) and (u + t) are not considered identical.
116
+ // / t*(u + t) and t*u + t*t are not considered identical.
117
+ // /
118
+ static bool isIdenticalStmt (const ASTContext &Ctx, const Stmt *Stmt1,
119
+ const Stmt *Stmt2, bool IgnoreSideEffects) {
120
+
121
+ if (!Stmt1 || !Stmt2)
122
+ return !Stmt1 && !Stmt2;
123
+
124
+ // If Stmt1 & Stmt2 are of different class then they are not
125
+ // identical statements.
126
+ if (Stmt1->getStmtClass () != Stmt2->getStmtClass ())
127
+ return false ;
128
+
129
+ const auto *Expr1 = dyn_cast<Expr>(Stmt1);
130
+ const auto *Expr2 = dyn_cast<Expr>(Stmt2);
131
+
132
+ if (Expr1 && Expr2) {
133
+ // If Stmt1 has side effects then don't warn even if expressions
134
+ // are identical.
135
+ if (!IgnoreSideEffects && Expr1->HasSideEffects (Ctx) &&
136
+ Expr2->HasSideEffects (Ctx))
137
+ return false ;
138
+ // If either expression comes from a macro then don't warn even if
139
+ // the expressions are identical.
140
+ if ((Expr1->getExprLoc ().isMacroID ()) || (Expr2->getExprLoc ().isMacroID ()))
141
+ return false ;
142
+
143
+ // If all children of two expressions are identical, return true.
144
+ Expr::const_child_iterator I1 = Expr1->child_begin ();
145
+ Expr::const_child_iterator I2 = Expr2->child_begin ();
146
+ while (I1 != Expr1->child_end () && I2 != Expr2->child_end ()) {
147
+ if (!isIdenticalStmt (Ctx, *I1, *I2, IgnoreSideEffects))
148
+ return false ;
149
+ ++I1;
150
+ ++I2;
151
+ }
152
+ // If there are different number of children in the statements, return
153
+ // false.
154
+ if (I1 != Expr1->child_end ())
155
+ return false ;
156
+ if (I2 != Expr2->child_end ())
157
+ return false ;
158
+ }
159
+
160
+ switch (Stmt1->getStmtClass ()) {
161
+ default :
162
+ return false ;
163
+ case Stmt::CallExprClass:
164
+ case Stmt::ArraySubscriptExprClass:
165
+ case Stmt::ArraySectionExprClass:
166
+ case Stmt::OMPArrayShapingExprClass:
167
+ case Stmt::OMPIteratorExprClass:
168
+ case Stmt::ImplicitCastExprClass:
169
+ case Stmt::ParenExprClass:
170
+ case Stmt::BreakStmtClass:
171
+ case Stmt::ContinueStmtClass:
172
+ case Stmt::NullStmtClass:
173
+ return true ;
174
+ case Stmt::CStyleCastExprClass: {
175
+ const auto *CastExpr1 = cast<CStyleCastExpr>(Stmt1);
176
+ const auto *CastExpr2 = cast<CStyleCastExpr>(Stmt2);
177
+
178
+ return CastExpr1->getTypeAsWritten () == CastExpr2->getTypeAsWritten ();
179
+ }
180
+ case Stmt::ReturnStmtClass: {
181
+ const auto *ReturnStmt1 = cast<ReturnStmt>(Stmt1);
182
+ const auto *ReturnStmt2 = cast<ReturnStmt>(Stmt2);
183
+
184
+ return isIdenticalStmt (Ctx, ReturnStmt1->getRetValue (),
185
+ ReturnStmt2->getRetValue (), IgnoreSideEffects);
186
+ }
187
+ case Stmt::ForStmtClass: {
188
+ const auto *ForStmt1 = cast<ForStmt>(Stmt1);
189
+ const auto *ForStmt2 = cast<ForStmt>(Stmt2);
190
+
191
+ if (!isIdenticalStmt (Ctx, ForStmt1->getInit (), ForStmt2->getInit (),
192
+ IgnoreSideEffects))
193
+ return false ;
194
+ if (!isIdenticalStmt (Ctx, ForStmt1->getCond (), ForStmt2->getCond (),
195
+ IgnoreSideEffects))
196
+ return false ;
197
+ if (!isIdenticalStmt (Ctx, ForStmt1->getInc (), ForStmt2->getInc (),
198
+ IgnoreSideEffects))
199
+ return false ;
200
+ if (!isIdenticalStmt (Ctx, ForStmt1->getBody (), ForStmt2->getBody (),
201
+ IgnoreSideEffects))
202
+ return false ;
203
+ return true ;
204
+ }
205
+ case Stmt::DoStmtClass: {
206
+ const auto *DStmt1 = cast<DoStmt>(Stmt1);
207
+ const auto *DStmt2 = cast<DoStmt>(Stmt2);
208
+
209
+ if (!isIdenticalStmt (Ctx, DStmt1->getCond (), DStmt2->getCond (),
210
+ IgnoreSideEffects))
211
+ return false ;
212
+ if (!isIdenticalStmt (Ctx, DStmt1->getBody (), DStmt2->getBody (),
213
+ IgnoreSideEffects))
214
+ return false ;
215
+ return true ;
216
+ }
217
+ case Stmt::WhileStmtClass: {
218
+ const auto *WStmt1 = cast<WhileStmt>(Stmt1);
219
+ const auto *WStmt2 = cast<WhileStmt>(Stmt2);
220
+
221
+ if (!isIdenticalStmt (Ctx, WStmt1->getCond (), WStmt2->getCond (),
222
+ IgnoreSideEffects))
223
+ return false ;
224
+ if (!isIdenticalStmt (Ctx, WStmt1->getBody (), WStmt2->getBody (),
225
+ IgnoreSideEffects))
226
+ return false ;
227
+ return true ;
228
+ }
229
+ case Stmt::IfStmtClass: {
230
+ const auto *IStmt1 = cast<IfStmt>(Stmt1);
231
+ const auto *IStmt2 = cast<IfStmt>(Stmt2);
232
+
233
+ if (!isIdenticalStmt (Ctx, IStmt1->getCond (), IStmt2->getCond (),
234
+ IgnoreSideEffects))
235
+ return false ;
236
+ if (!isIdenticalStmt (Ctx, IStmt1->getThen (), IStmt2->getThen (),
237
+ IgnoreSideEffects))
238
+ return false ;
239
+ if (!isIdenticalStmt (Ctx, IStmt1->getElse (), IStmt2->getElse (),
240
+ IgnoreSideEffects))
241
+ return false ;
242
+ return true ;
243
+ }
244
+ case Stmt::CompoundStmtClass: {
245
+ const auto *CompStmt1 = cast<CompoundStmt>(Stmt1);
246
+ const auto *CompStmt2 = cast<CompoundStmt>(Stmt2);
247
+
248
+ if (CompStmt1->size () != CompStmt2->size ())
249
+ return false ;
250
+
251
+ if (!llvm::all_of (llvm::zip (CompStmt1->body (), CompStmt2->body ()),
252
+ [&Ctx, IgnoreSideEffects](
253
+ std::tuple<const Stmt *, const Stmt *> stmtPair) {
254
+ const Stmt *stmt0 = std::get<0 >(stmtPair);
255
+ const Stmt *stmt1 = std::get<1 >(stmtPair);
256
+ return isIdenticalStmt (Ctx, stmt0, stmt1,
257
+ IgnoreSideEffects);
258
+ })) {
259
+ return false ;
260
+ }
261
+
262
+ return true ;
263
+ }
264
+ case Stmt::CompoundAssignOperatorClass:
265
+ case Stmt::BinaryOperatorClass: {
266
+ const auto *BinOp1 = cast<BinaryOperator>(Stmt1);
267
+ const auto *BinOp2 = cast<BinaryOperator>(Stmt2);
268
+ return BinOp1->getOpcode () == BinOp2->getOpcode ();
269
+ }
270
+ case Stmt::CharacterLiteralClass: {
271
+ const auto *CharLit1 = cast<CharacterLiteral>(Stmt1);
272
+ const auto *CharLit2 = cast<CharacterLiteral>(Stmt2);
273
+ return CharLit1->getValue () == CharLit2->getValue ();
274
+ }
275
+ case Stmt::DeclRefExprClass: {
276
+ const auto *DeclRef1 = cast<DeclRefExpr>(Stmt1);
277
+ const auto *DeclRef2 = cast<DeclRefExpr>(Stmt2);
278
+ return DeclRef1->getDecl () == DeclRef2->getDecl ();
279
+ }
280
+ case Stmt::IntegerLiteralClass: {
281
+ const auto *IntLit1 = cast<IntegerLiteral>(Stmt1);
282
+ const auto *IntLit2 = cast<IntegerLiteral>(Stmt2);
283
+
284
+ llvm::APInt I1 = IntLit1->getValue ();
285
+ llvm::APInt I2 = IntLit2->getValue ();
286
+ if (I1.getBitWidth () != I2.getBitWidth ())
287
+ return false ;
288
+ return I1 == I2;
289
+ }
290
+ case Stmt::FloatingLiteralClass: {
291
+ const auto *FloatLit1 = cast<FloatingLiteral>(Stmt1);
292
+ const auto *FloatLit2 = cast<FloatingLiteral>(Stmt2);
293
+ return FloatLit1->getValue ().bitwiseIsEqual (FloatLit2->getValue ());
294
+ }
295
+ case Stmt::StringLiteralClass: {
296
+ const auto *StringLit1 = cast<StringLiteral>(Stmt1);
297
+ const auto *StringLit2 = cast<StringLiteral>(Stmt2);
298
+ return StringLit1->getBytes () == StringLit2->getBytes ();
299
+ }
300
+ case Stmt::MemberExprClass: {
301
+ const auto *MemberStmt1 = cast<MemberExpr>(Stmt1);
302
+ const auto *MemberStmt2 = cast<MemberExpr>(Stmt2);
303
+ return MemberStmt1->getMemberDecl () == MemberStmt2->getMemberDecl ();
304
+ }
305
+ case Stmt::UnaryOperatorClass: {
306
+ const auto *UnaryOp1 = cast<UnaryOperator>(Stmt1);
307
+ const auto *UnaryOp2 = cast<UnaryOperator>(Stmt2);
308
+ return UnaryOp1->getOpcode () == UnaryOp2->getOpcode ();
309
+ }
310
+ }
105
311
}
106
312
107
313
void BranchCloneCheck::check (const MatchFinder::MatchResult &Result) {
@@ -269,6 +475,21 @@ void BranchCloneCheck::check(const MatchFinder::MatchResult &Result) {
269
475
return ;
270
476
}
271
477
478
+ if (const auto *IS = Result.Nodes .getNodeAs <IfStmt>(" ifWithDescendantIf" )) {
479
+ const Stmt *Then = IS->getThen ();
480
+ auto CS = dyn_cast<CompoundStmt>(Then);
481
+ if (CS && (!CS->body_empty ())) {
482
+ const auto *InnerIf = dyn_cast<IfStmt>(*CS->body_begin ());
483
+ if (InnerIf && isIdenticalStmt (Context, IS->getCond (), InnerIf->getCond (),
484
+ /* IgnoreSideEffects=*/ false )) {
485
+ diag (IS->getBeginLoc (), " if with identical inner if statement" );
486
+ diag (InnerIf->getBeginLoc (), " inner if starts here" ,
487
+ DiagnosticIDs::Note);
488
+ }
489
+ }
490
+ return ;
491
+ }
492
+
272
493
llvm_unreachable (" No if statement and no switch statement." );
273
494
}
274
495
0 commit comments