Clang教程之实现源源变化(3)

一个高级的源源变换,主要是为了展示如何进行AST Declaration的遍历和代码的规整化处理,可以将其作为一个代码自动规整化工具进行使用

实现代码如下:

  1 //------------------------------------------------------------------------------
  2 // Simple Rewrtie Sample 
  3 //
  4 //
  5 // jourluohua (jourluohua@gmail.com)
  6 // This code is in the public domain
  7 //------------------------------------------------------------------------------
  8 #include <sstream>
  9 #include <string>
 10 #include <fstream>
 11 
 12 #include "clang/AST/AST.h"
 13 #include "clang/AST/ASTConsumer.h"
 14 #include "clang/AST/RecursiveASTVisitor.h"
 15 #include "clang/Frontend/ASTConsumers.h"
 16 #include "clang/Frontend/CompilerInstance.h"
 17 #include "clang/Frontend/FrontendActions.h"
 18 #include "clang/Rewrite/Core/Rewriter.h"
 19 #include "clang/Tooling/CommonOptionsParser.h"
 20 #include "clang/Tooling/Tooling.h"
 21 #include "llvm/Support/raw_ostream.h"
 22 
 23 using namespace clang;
 24 using namespace clang::driver;
 25 using namespace clang::tooling;
 26 
 27 static llvm::cl::OptionCategory ToolingSampleCategory("Simple Rewriter");
 28 
 29 // Implementation of the ASTConsumer interface for reading an AST produced
 30 // by the Clang parser.
 31 class MyASTConsumer : public ASTConsumer {
 32 private:
 33     std::string InFile;
 34     SourceManager *SM;
 35     Rewriter TheRewriter;
 36     
 37   public:
 38     MyASTConsumer(SourceManager* sm, StringRef _InFile, Rewriter& theRew)
 39         : SM(sm), InFile(_InFile), TheRewriter(theRew){}
 40 
 41     void HandleTranslationUnit(ASTContext &Context) override;
 42 
 43     StringRef getInFile() { return InFile; }
 44 };
 45 void MyASTConsumer::HandleTranslationUnit(ASTContext &Context){
 46   DeclContext::decl_iterator D = Context.getTranslationUnitDecl()->decls_begin();
 47   DeclContext::decl_iterator DEnd = Context.getTranslationUnitDecl()->decls_end();
 48   PrintingPolicy Policy(Context.getLangOpts());
 49   while (D != DEnd)
 50   {
 51     SourceLocation Loc = SM->getExpansionLoc(D->getLocation());
 52     SourceLocation LocStart = D->getBeginLoc();
 53     SourceLocation LocEnd = D->getEndLoc();
 54     //(*D)->dump();
 55     if (Loc.isInvalid() || !SM->isWrittenInMainFile(Loc) || D->isImplicit() ||
 56         LocStart.isInvalid()) {
 57       ++D;
 58       continue;
 59     }
 60 
 61     std::string prettyBufS;
 62     llvm::raw_string_ostream prettyBuf(prettyBufS);
 63     D->print(prettyBuf, Policy);
 64 
 65     if (LocEnd.isInvalid()) {
 66       TheRewriter.InsertTextAfter(LocStart, "
" + prettyBuf.str());
 67       ++D;
 68       continue;
 69     }
 70 
 71     const char *startBuf = SM->getCharacterData(LocStart);
 72     const char *endBuf = SM->getCharacterData(LocEnd);
 73 
 74     char separator;
 75     const char *separatorBuf;
 76 
 77     switch (D->getKind()) {
 78       case Decl::Function: {
 79         FunctionDecl *FD = cast<FunctionDecl>(*D);
 80 
 81         if (!FD->isThisDeclarationADefinition()) {
 82           separator = ';';
 83           separatorBuf = strchr(endBuf, separator);
 84           TheRewriter.ReplaceText(LocStart, separatorBuf - startBuf, prettyBuf.str());
 85         }
 86         else {
 87           separator = '}';
 88           separatorBuf = strchr(endBuf, separator);
 89           TheRewriter.ReplaceText(LocStart, separatorBuf - startBuf + 1, prettyBuf.str());
 90         }
 91         ++D;
 92         break;
 93       }
 94       case Decl::Var: {
 95         ++D;
 96         bool flag = true;
 97         while (D != DEnd && flag == true) {
 98           flag = false;
 99           if (VarDecl *VD = dyn_cast<VarDecl>(*D)) {
100             if (VD->getBeginLoc() == LocStart) {
101               prettyBuf << "; ";
102               VD->print(prettyBuf, Policy);
103               ++D;
104               flag = true;
105             }
106           }
107         }
108 
109         separator = ';';
110         separatorBuf = strchr(endBuf, separator);
111         TheRewriter.ReplaceText(LocStart, separatorBuf - startBuf, prettyBuf.str());
112         break;
113       }
114       case Decl::TypeAlias:
115       case Decl::Typedef: {
116         separator = ';';
117         separatorBuf = strchr(endBuf, separator);
118         TheRewriter.ReplaceText(LocStart, separatorBuf - startBuf, prettyBuf.str());
119         ++D;
120         break;
121       }
122       case Decl::Record: {
123         ++D;
124         if (D != DEnd) {
125           SourceLocation NextLocStart = D->getBeginLoc();
126           SourceLocation NextLocEnd = D->getEndLoc();
127           // Handle the following case:
128           // typedef struct abc {
129           //   ...;
130           // } abc;
131           if (NextLocStart.isValid() && NextLocStart < LocStart) {
132             prettyBuf << ";
";
133             D->print(prettyBuf, Policy);
134             startBuf = SM->getCharacterData(NextLocStart);
135             endBuf = SM->getCharacterData(NextLocEnd);
136             LocStart = NextLocStart;
137             ++D;
138           }
139         }
140 
141         separator = ';';
142         separatorBuf = strchr(endBuf, separator);
143         TheRewriter.ReplaceText(LocStart, separatorBuf - startBuf, prettyBuf.str());
144         break;
145       }
146       
147       default:
148         llvm_unreachable("should handle the decl kind");
149     }
150   }
151 
152   const RewriteBuffer *RewriteBuf = TheRewriter.getRewriteBufferFor(SM->getMainFileID());
153   
154   //*OutFile << std::string(RewriteBuf->begin(), RewriteBuf->end()); 
155   std::ofstream outEdF("dpu_test.cpp", std::ofstream::out);
156 
157   if(outEdF.good()){
158       std::string tmp(RewriteBuf->begin(), RewriteBuf->end()); 
159       outEdF << tmp;
160       //std::cout << tmp;
161   }
162 
163 
164   outEdF.close();
165 
166 
167 }
168 // For each source file provided to the tool, a new FrontendAction is created.
169 class MyFrontendAction : public ASTFrontendAction {
170 public:
171   MyFrontendAction() {}
172 
173 
174   std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
175                                                  StringRef inFile) override {
176     llvm::errs() << "** Creating AST consumer for: " << inFile << "
";
177     TheRewriter.setSourceMgr(CI.getSourceManager(), CI.getLangOpts());
178     return std::make_unique<MyASTConsumer>(&(CI.getSourceManager()), inFile, TheRewriter);
179   }
180   Rewriter TheRewriter;
181 };
182 
183 int main(int argc, const char **argv) {
184   llvm::Expected<CommonOptionsParser> op=CommonOptionsParser::create(argc, argv, ToolingSampleCategory);
185   
186   ClangTool Tool(op.get().getCompilations(), op.get().getSourcePathList());
187 
188   // ClangTool::run accepts a FrontendActionFactory, which is then used to
189   // create new objects implementing the FrontendAction interface. Here we use
190   // the helper newFrontendActionFactory to create a default factory that will
191   // return a new MyFrontendAction object every time.
192   // To further customize this, we could create our own factory class.
193   return Tool.run(newFrontendActionFactory<MyFrontendAction>().get());
194 }
原文地址:https://www.cnblogs.com/jourluohua/p/14520336.html