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