@@ -102,6 +102,212 @@ void BranchCloneCheck::registerMatchers(MatchFinder *Finder) {
102102      this );
103103  Finder->addMatcher (switchStmt ().bind (" switch"  ), this );
104104  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+   }
105311}
106312
107313void  BranchCloneCheck::check (const  MatchFinder::MatchResult &Result) {
@@ -269,6 +475,21 @@ void BranchCloneCheck::check(const MatchFinder::MatchResult &Result) {
269475    return ;
270476  }
271477
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+ 
272493  llvm_unreachable (" No if statement and no switch statement."  );
273494}
274495
0 commit comments