1 //===----------------------------------------------------------------------===//
2 //
3 // Copyright (c) 2012, 2013, 2015, 2017 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 "RemoveUnresolvedBase.h"
16
17 #include "clang/Basic/SourceManager.h"
18 #include "clang/AST/RecursiveASTVisitor.h"
19 #include "clang/AST/ASTContext.h"
20 #include "TransformationManager.h"
21
22 using namespace clang;
23
24 static const char *DescriptionMsg =
25 "This pass tries to remove a base specifier if we cannot \
26 resolve it. \n";
27
28 static RegisterTransformation<RemoveUnresolvedBase>
29 Trans("remove-unresolved-base", DescriptionMsg);
30
31 class RemoveUnresolvedBaseASTVisitor : public
32 RecursiveASTVisitor<RemoveUnresolvedBaseASTVisitor> {
33
34 public:
RemoveUnresolvedBaseASTVisitor(RemoveUnresolvedBase * Instance)35 explicit RemoveUnresolvedBaseASTVisitor(RemoveUnresolvedBase *Instance)
36 : ConsumerInstance(Instance)
37 { }
38
39 bool VisitCXXRecordDecl(CXXRecordDecl *CXXRD);
40
41 private:
42 RemoveUnresolvedBase *ConsumerInstance;
43 };
44
VisitCXXRecordDecl(CXXRecordDecl * CXXRD)45 bool RemoveUnresolvedBaseASTVisitor::VisitCXXRecordDecl(CXXRecordDecl *CXXRD)
46 {
47 if (ConsumerInstance->isInIncludedFile(CXXRD) || !CXXRD->hasDefinition())
48 return true;
49
50 const CXXRecordDecl *CanonicalRD = CXXRD->getCanonicalDecl();
51 if (ConsumerInstance->VisitedCXXRecordDecls.count(CanonicalRD))
52 return true;
53 ConsumerInstance->VisitedCXXRecordDecls.insert(CanonicalRD);
54
55 unsigned Idx = 0;
56 for (CXXRecordDecl::base_class_const_iterator I =
57 CanonicalRD->bases_begin(), E = CanonicalRD->bases_end(); I != E; ++I) {
58 const CXXBaseSpecifier *BS = I;
59 const Type *Ty = BS->getType().getTypePtr();
60 const CXXRecordDecl *Base = ConsumerInstance->getBaseDeclFromType(Ty);
61 if (Base) {
62 Idx++;
63 continue;
64 }
65
66 ConsumerInstance->ValidInstanceNum++;
67 if (ConsumerInstance->ValidInstanceNum ==
68 ConsumerInstance->TransformationCounter) {
69 ConsumerInstance->TheDerivedClass = CanonicalRD;
70 ConsumerInstance->TheBaseSpecifier = BS;
71 ConsumerInstance->TheIndex = Idx;
72 }
73 Idx++;
74 }
75 return true;
76 }
77
Initialize(ASTContext & context)78 void RemoveUnresolvedBase::Initialize(ASTContext &context)
79 {
80 Transformation::Initialize(context);
81 CollectionVisitor = new RemoveUnresolvedBaseASTVisitor(this);
82 }
83
HandleTranslationUnit(ASTContext & Ctx)84 void RemoveUnresolvedBase::HandleTranslationUnit(ASTContext &Ctx)
85 {
86 if (TransformationManager::isCLangOpt() ||
87 TransformationManager::isOpenCLLangOpt()) {
88 ValidInstanceNum = 0;
89 }
90 else {
91 CollectionVisitor->TraverseDecl(Ctx.getTranslationUnitDecl());
92 }
93
94 if (QueryInstanceOnly)
95 return;
96
97 if (TransformationCounter > ValidInstanceNum) {
98 TransError = TransMaxInstanceError;
99 return;
100 }
101
102 TransAssert(TheDerivedClass && "NULL TheDerivedClass!");
103 TransAssert(TheBaseSpecifier && "NULL TheBaseSpecifier!");
104 Ctx.getDiagnostics().setSuppressAllDiagnostics(false);
105
106 removeBaseSpecifier();
107
108 if (Ctx.getDiagnostics().hasErrorOccurred() ||
109 Ctx.getDiagnostics().hasFatalErrorOccurred())
110 TransError = TransInternalError;
111 }
112
removeBaseSpecifier(void)113 void RemoveUnresolvedBase::removeBaseSpecifier(void)
114 {
115 unsigned NumBases = TheDerivedClass->getNumBases();
116 TransAssert((NumBases >= 1) && "TheDerivedClass doesn't have any base!");
117 CXXRecordDecl::base_class_const_iterator I = TheDerivedClass->bases_begin();
118
119 if (NumBases == 1) {
120 TransAssert((TheIndex == 0) && "Invalid Index for the base specifier!");
121 TransAssert((I == TheBaseSpecifier) && "Unmatched base specifier!");
122 (void)I;
123 SourceLocation StartLoc = TheDerivedClass->getLocation();
124 StartLoc = RewriteHelper->getLocationUntil(StartLoc, ':');
125 SourceLocation EndLoc = RewriteHelper->getLocationUntil(StartLoc, '{');
126 EndLoc = EndLoc.getLocWithOffset(-1);
127
128 TheRewriter.RemoveText(SourceRange(StartLoc, EndLoc));
129 return;
130 }
131
132 SourceRange Range = TheBaseSpecifier->getSourceRange();
133 if (TheIndex == 0) {
134 RewriteHelper->removeTextUntil(Range, ',');
135 }
136 else {
137 SourceLocation EndLoc = RewriteHelper->getEndLocationFromBegin(Range);
138 RewriteHelper->removeTextFromLeftAt(Range, ',', EndLoc);
139 }
140 }
141
~RemoveUnresolvedBase(void)142 RemoveUnresolvedBase::~RemoveUnresolvedBase(void)
143 {
144 delete CollectionVisitor;
145 }
146
147