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