1 //===----------------------------------------------------------------------===//
2 //
3 // Copyright (c) 2012, 2013, 2014, 2015, 2016, 2017, 2018 The University of Utah
4 // All rights reserved.
5 //
6 // This file is distributed under the University of Illinois Open Source
7 // License.  See the file COPYING for details.
8 //
9 //===----------------------------------------------------------------------===//
10 
11 #if HAVE_CONFIG_H
12 #  include <config.h>
13 #endif
14 
15 #include "RemoveBaseClass.h"
16 
17 #include "clang/AST/ASTContext.h"
18 #include "clang/Basic/SourceManager.h"
19 #include "CommonRenameClassRewriteVisitor.h"
20 
21 #include "TransformationManager.h"
22 
23 using namespace clang;
24 using namespace clang_delta_common_visitor;
25 
26 static const char *DescriptionMsg =
27 "This pass removes a base class from its class hierarchy if \n\
28   * it has less than or equal to 5 declarations, and \n\
29   * it is not a templated class. \n\
30 All its declarations will be moved into one of its subclasses, \
31 and all references to this base class will be replaced with \
32 the corresponding subclass. \n";
33 
34 // Note that this pass doesn't do much analysis, so
35 // it will produce quite a few incompilable code, especially
36 // when multi-inheritance is involved.
37 
38 static RegisterTransformation<RemoveBaseClass>
39          Trans("remove-base-class", DescriptionMsg);
40 
41 class RemoveBaseClassBaseVisitor : public
42   RecursiveASTVisitor<RemoveBaseClassBaseVisitor> {
43 
44 public:
RemoveBaseClassBaseVisitor(RemoveBaseClass * Instance)45   explicit RemoveBaseClassBaseVisitor(
46              RemoveBaseClass *Instance)
47     : ConsumerInstance(Instance)
48   { }
49 
50   bool VisitCXXRecordDecl(CXXRecordDecl *CXXRD);
51 
52 private:
53   RemoveBaseClass *ConsumerInstance;
54 };
55 
VisitCXXRecordDecl(CXXRecordDecl * CXXRD)56 bool RemoveBaseClassBaseVisitor::VisitCXXRecordDecl(
57        CXXRecordDecl *CXXRD)
58 {
59   ConsumerInstance->handleOneCXXRecordDecl(CXXRD);
60   return true;
61 }
62 
63 class RemoveBaseClassRewriteVisitor : public
64   CommonRenameClassRewriteVisitor<RemoveBaseClassRewriteVisitor>
65 {
66 public:
RemoveBaseClassRewriteVisitor(Transformation * Instance,Rewriter * RT,RewriteUtils * Helper,const CXXRecordDecl * CXXRD,const std::string & Name)67   RemoveBaseClassRewriteVisitor(Transformation *Instance,
68                                 Rewriter *RT,
69                                 RewriteUtils *Helper,
70                                 const CXXRecordDecl *CXXRD,
71                                 const std::string &Name)
72     : CommonRenameClassRewriteVisitor<RemoveBaseClassRewriteVisitor>
73       (Instance, RT, Helper, CXXRD, Name)
74   { }
75 };
76 
Initialize(ASTContext & context)77 void RemoveBaseClass::Initialize(ASTContext &context)
78 {
79   Transformation::Initialize(context);
80   CollectionVisitor = new RemoveBaseClassBaseVisitor(this);
81 }
82 
HandleTranslationUnit(ASTContext & Ctx)83 void RemoveBaseClass::HandleTranslationUnit(ASTContext &Ctx)
84 {
85   if (TransformationManager::isCLangOpt() ||
86       TransformationManager::isOpenCLLangOpt()) {
87     ValidInstanceNum = 0;
88   }
89   else {
90     CollectionVisitor->TraverseDecl(Ctx.getTranslationUnitDecl());
91   }
92 
93   if (QueryInstanceOnly)
94     return;
95 
96   if (TransformationCounter > ValidInstanceNum) {
97     TransError = TransMaxInstanceError;
98     return;
99   }
100 
101   TransAssert(TheBaseClass && "TheBaseClass is NULL!");
102   TransAssert(TheDerivedClass && "TheDerivedClass is NULL!");
103   Ctx.getDiagnostics().setSuppressAllDiagnostics(false);
104 
105   RewriteVisitor =
106     new RemoveBaseClassRewriteVisitor(this, &TheRewriter, RewriteHelper,
107                                       TheBaseClass->getCanonicalDecl(),
108                                       TheDerivedClass->getNameAsString());
109 
110   TransAssert(RewriteVisitor && "NULL RewriteVisitor!");
111   RewriteVisitor->TraverseDecl(Ctx.getTranslationUnitDecl());
112   doRewrite();
113 
114   if (Ctx.getDiagnostics().hasErrorOccurred() ||
115       Ctx.getDiagnostics().hasFatalErrorOccurred())
116     TransError = TransInternalError;
117 }
118 
isDirectlyDerivedFrom(const CXXRecordDecl * SubC,const CXXRecordDecl * Base)119 bool RemoveBaseClass::isDirectlyDerivedFrom(const CXXRecordDecl *SubC,
120                                             const CXXRecordDecl *Base)
121 {
122   for (CXXRecordDecl::base_class_const_iterator I = SubC->bases_begin(),
123        E = SubC->bases_end(); I != E; ++I) {
124     if (I->getType()->isDependentType())
125       continue;
126 
127     const CXXRecordDecl *BaseDecl =
128       dyn_cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl());
129     if (Base->getCanonicalDecl() == BaseDecl->getCanonicalDecl())
130       return true;
131   }
132   return false;
133 }
134 
handleOneCXXRecordDecl(const CXXRecordDecl * CXXRD)135 void RemoveBaseClass::handleOneCXXRecordDecl(const CXXRecordDecl *CXXRD)
136 {
137   if (isSpecialRecordDecl(CXXRD) || CXXRD->getDescribedClassTemplate() ||
138       !CXXRD->hasDefinition())
139     return;
140 
141   const CXXRecordDecl *CanonicalRD = CXXRD->getCanonicalDecl();
142   if (VisitedCXXRecordDecls.count(CanonicalRD))
143     return;
144   VisitedCXXRecordDecls.insert(CanonicalRD);
145   if (CanonicalRD->getNumBases()) {
146     const CXXRecordDecl *Base = NULL;
147     for (CXXRecordDeclSet::iterator I = AllBaseClasses.begin(),
148          E = AllBaseClasses.end(); I != E; ++I) {
149       if (const ClassTemplateSpecializationDecl * CTSD =
150           dyn_cast<ClassTemplateSpecializationDecl>
151             (CanonicalRD->getDefinition())) {
152         if (!CTSD->isExplicitSpecialization())
153           continue;
154       }
155 
156       if (isInIncludedFile(*I))
157         continue;
158       if (isDirectlyDerivedFrom(CanonicalRD, *I)) {
159         Base = (*I);
160         ValidInstanceNum++;
161         if (ValidInstanceNum == TransformationCounter) {
162           TransAssert(Base->hasDefinition() &&
163                       "Base class does not have any definition!");
164           TheBaseClass = Base->getDefinition();
165           TransAssert(CanonicalRD->hasDefinition() &&
166                       "Derived class does not have any definition!");
167           TheDerivedClass = CanonicalRD->getDefinition();
168         }
169       }
170     }
171     return;
172   }
173 
174   if (getNumExplicitDecls(CanonicalRD) > MaxNumDecls)
175     return;
176 
177   if (!AllBaseClasses.count(CanonicalRD))
178     AllBaseClasses.insert(CanonicalRD);
179 }
180 
doRewrite(void)181 void RemoveBaseClass::doRewrite(void)
182 {
183   copyBaseClassDecls();
184   removeBaseSpecifier();
185   RewriteHelper->removeClassDecls(TheBaseClass);
186 
187   // ISSUE: I didn't handle Base initializer in a Ctor's initlist.
188   //        * keeping it untouched is wrong, because delegating constructors
189   //        are only valie in c++11
190   //        * naively removing the base initializer doesn't work in some cases,
191   //        e.g.,
192   //        class A {
193   //          A(A&) {}
194   //          A &a;
195   //        };
196   //        class C : A {
197   //          C(A &x) : A(x) {}
198   //        };
199   //        during transformation, removing A(x) will leave &a un-initialized.
200   // I chose to simply delete the base initializer. Seemingly we will
201   // generate fewer incompilable code by doing so...
202   removeBaseInitializer();
203 }
204 
205 // ISSUE: directly copying decls could bring in name conflicts
copyBaseClassDecls(void)206 void RemoveBaseClass::copyBaseClassDecls(void)
207 {
208   if (!getNumExplicitDecls(TheBaseClass))
209     return;
210   SourceLocation StartLoc = TheBaseClass->getBraceRange().getBegin();
211   SourceLocation EndLoc = TheBaseClass->getBraceRange().getEnd();
212   TransAssert(EndLoc.isValid() && "Invalid RBraceLoc!");
213   EndLoc = EndLoc.getLocWithOffset(-1);
214 
215   std::string DeclsStr =
216     TheRewriter.getRewrittenText(SourceRange(StartLoc, EndLoc));
217 
218   TransAssert(!DeclsStr.empty() && "Empty DeclsStr!");
219   SourceLocation InsertLoc = TheDerivedClass->getBraceRange().getEnd();
220   TheRewriter.InsertTextBefore(InsertLoc, DeclsStr);
221 }
222 
isTheBaseClass(const CXXBaseSpecifier & Specifier)223 bool RemoveBaseClass::isTheBaseClass(const CXXBaseSpecifier &Specifier)
224 {
225   const Type *Ty = TheBaseClass->getTypeForDecl();
226   return Context->hasSameType(Specifier.getType(),
227                               Ty->getCanonicalTypeInternal());
228 }
229 
removeBaseSpecifier(void)230 void RemoveBaseClass::removeBaseSpecifier(void)
231 {
232   unsigned NumBases = TheDerivedClass->getNumBases();
233   TransAssert((NumBases >= 1) && "TheDerivedClass doesn't have any base!");
234   if (NumBases == 1) {
235     SourceLocation StartLoc = TheDerivedClass->getLocation();
236     StartLoc = RewriteHelper->getLocationUntil(StartLoc, ':');
237     SourceLocation EndLoc = RewriteHelper->getLocationUntil(StartLoc, '{');
238     EndLoc = EndLoc.getLocWithOffset(-1);
239 
240     TheRewriter.RemoveText(SourceRange(StartLoc, EndLoc));
241     return;
242   }
243 
244   CXXRecordDecl::base_class_const_iterator I = TheDerivedClass->bases_begin();
245   // remove 'Y,' in code like 'class X : public Y, Z {};'
246   if (isTheBaseClass(*I)) {
247     RewriteHelper->removeTextUntil((*I).getSourceRange(), ',');
248     return;
249   }
250 
251   ++I;
252   CXXRecordDecl::base_class_const_iterator E = TheDerivedClass->bases_end();
253   for (; I != E; ++I) {
254     if (isTheBaseClass(*I)) {
255       // remove ',Z' in code like 'class X : public Y, Z {};'
256       SourceRange Range = (*I).getSourceRange();
257       SourceLocation EndLoc = RewriteHelper->getEndLocationFromBegin(Range);
258       RewriteHelper->removeTextFromLeftAt(Range, ',', EndLoc);
259       return;
260     }
261   }
262   TransAssert(0 && "Unreachable code!");
263 }
264 
rewriteOneCtor(const CXXConstructorDecl * Ctor)265 void RemoveBaseClass::rewriteOneCtor(const CXXConstructorDecl *Ctor)
266 {
267   unsigned Idx = 0;
268   const CXXCtorInitializer *Init = NULL;
269   for (CXXConstructorDecl::init_const_iterator I = Ctor->init_begin(),
270        E = Ctor->init_end(); I != E; ++I) {
271     if (!(*I)->isWritten())
272       continue;
273 
274     if ((*I)->isBaseInitializer()) {
275       const Type *Ty = (*I)->getBaseClass();
276       TransAssert(Ty && "Invalid Base Class Type!");
277       if (Context->hasSameType(Ty->getCanonicalTypeInternal(),
278             TheBaseClass->getTypeForDecl()->getCanonicalTypeInternal())) {
279         Init = (*I);
280         break;
281       }
282     }
283     Idx++;
284   }
285   if (Init) {
286     RewriteHelper->removeCXXCtorInitializer(Init, Idx,
287                      getNumCtorWrittenInitializers(*Ctor));
288   }
289 }
290 
removeBaseInitializer(void)291 void RemoveBaseClass::removeBaseInitializer(void)
292 {
293   for (CXXRecordDecl::ctor_iterator I = TheDerivedClass->ctor_begin(),
294        E = TheDerivedClass->ctor_end(); I != E; ++I) {
295     if ((*I)->isThisDeclarationADefinition() && !(*I)->isDefaulted())
296       rewriteOneCtor(*I);
297   }
298 }
299 
~RemoveBaseClass(void)300 RemoveBaseClass::~RemoveBaseClass(void)
301 {
302   delete CollectionVisitor;
303   delete RewriteVisitor;
304 }
305 
306