clang操作源码

发布时间 2023-04-02 10:08:17作者: gearslogy

生成注释

假设有下面的源码:

struct Vec3 {
  float x, y, z;
};

struct Vec4 {
  float x, y, z, w;
};

生成这样的代码:

//[[CLASS INFO]] class:Vec3, is pod:true, is aggregate:true
struct Vec3 {
  float x, y, z;
};
//[[CLASS INFO]] use struct-binding method :
//const auto &[_m0,_m1,_m2] = Vec3;



//[[CLASS INFO]] class:Vec4, is pod:true, is aggregate:true
struct Vec4 {
  float x, y, z, w;
};
//[[CLASS INFO]] use struct-binding method :
//const auto &[_m0,_m1,_m2,_m3] = Vec4;

 

#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/PreprocessorOutputOptions.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/Support/raw_ostream.h"
#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Rewrite/Core/Rewriter.h"
#include <format>
#include <iostream>

using namespace clang;

class MyASTVisitor : public RecursiveASTVisitor<MyASTVisitor> {
public:
    MyASTVisitor(Rewriter &w ) : writer{w}{}

    bool VisitCXXRecordDecl(CXXRecordDecl *declaration) {
        auto sourceBeginLoc = declaration->getSourceRange().getBegin();
        auto sourceEndLoc = declaration->getSourceRange().getEnd();  

        declaration->dump();
auto name
= declaration->getNameAsString(); bool isPod = declaration->isPOD(); auto isAggregate = declaration->isAggregate(); auto fieldCount = std::distance(declaration->field_begin(), declaration->field_end()); std::string fieldBinding{"const auto &["}; for(auto i=0;i<fieldCount;i++){ fieldBinding += "_m" + std::to_string(i); if(i!=fieldCount-1) fieldBinding += ","; } fieldBinding += "] = "; fieldBinding += name; auto classInfo = std::format("//[[CLASS INFO]] class:{}, is pod:{}, is aggregate:{}\n", name, isPod, isAggregate); auto howToBind = std::format("\n//[[CLASS INFO]] use struct-binding method : \n//{};\n\n", fieldBinding); writer.InsertText(sourceBeginLoc, classInfo, true, true); writer.InsertText(declaration->getEndLoc().getLocWithOffset(2), howToBind,true, true); // location使用sourceEndLoc变量也可以 return true; } private: Rewriter &writer; }; class MyASTConsumer : public ASTConsumer { public: MyASTConsumer(Rewriter &w) : writer{w}{} void HandleTranslationUnit(ASTContext &context) override { MyASTVisitor visitor{writer}; visitor.TraverseDecl(context.getTranslationUnitDecl()); } Rewriter &writer; }; class MyFrontendAction : public ASTFrontendAction { public: void EndSourceFileAction() override{ auto &sm = writer.getSourceMgr(); writer.getEditBuffer(sm.getMainFileID()).write(llvm::outs()); } std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &compiler, StringRef file) override { llvm::outs() << "create ast consumer for: " << file << "\n"; compiler.getLangOpts().CPlusPlus = true; compiler.getPreprocessorOpts().addMacroDef("__cplusplus"); compiler.getPreprocessorOpts().addMacroDef("Vec3=struct Vec3"); compiler.getLangOpts().CPlusPlus2b = true; writer.setSourceMgr(compiler.getSourceManager(), compiler.getLangOpts()); return std::make_unique<MyASTConsumer>(writer); } private: Rewriter writer; }; int main(int argc, const char **argv) { auto code= R"( struct Vec3 { float x, y, z; }; struct Vec4 { float x, y, z, w; }; )"; clang::tooling::runToolOnCode(std::make_unique<MyFrontendAction>(), code); return 0; }

 

输出:

D:\Plugin_Dev\CPP\LLVM\modify_ast\cmake-build-debug\xxx.exe

create ast consumer for: input.cc
CXXRecordDecl 0x23cdd3e7c48 <input.cc:3:1, line:5:1> line:3:8 struct Vec3 definition
|-DefinitionData pass_in_registers aggregate standard_layout trivially_copyable pod trivial literal
| |-DefaultConstructor exists trivial needs_implicit
| |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param
| |-MoveConstructor exists simple trivial needs_implicit
| |-CopyAssignment simple trivial has_const_param needs_implicit implicit_has_const_param
| |-MoveAssignment exists simple trivial needs_implicit
| `-Destructor simple irrelevant trivial needs_implicit
|-CXXRecordDecl 0x23cdd3e7d68 <col:1, col:8> col:8 implicit struct Vec3
|-FieldDecl 0x23cdd3e7e10 <line:4:3, col:9> col:9 x 'float'
|-FieldDecl 0x23cdd3e7e80 <col:3, col:12> col:12 y 'float'
`-FieldDecl 0x23cdd3e7ef0 <col:3, col:15> col:15 z 'float'
CXXRecordDecl 0x23cdd3e7f80 <input.cc:7:1, line:9:1> line:7:8 struct Vec4 definition
|-DefinitionData pass_in_registers aggregate standard_layout trivially_copyable pod trivial literal
| |-DefaultConstructor exists trivial needs_implicit
| |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param
| |-MoveConstructor exists simple trivial needs_implicit
| |-CopyAssignment simple trivial has_const_param needs_implicit implicit_has_const_param 
| |-MoveAssignment exists simple trivial needs_implicit
| `-Destructor simple irrelevant trivial needs_implicit
|-CXXRecordDecl 0x23cdd3e8098 <col:1, col:8> col:8 implicit struct Vec4
|-FieldDecl 0x23cdd3e8140 <line:8:3, col:9> col:9 x 'float'
|-FieldDecl 0x23cdd3e81b0 <col:3, col:12> col:12 y 'float'
|-FieldDecl 0x23cdd3e8220 <col:3, col:15> col:15 z 'float'                                
`-FieldDecl 0x23cdd3e8290 <col:3, col:18> col:18 w 'float'


//[[CLASS INFO]] class:Vec3, is pod:true, is aggregate:true
struct Vec3 {
  float x, y, z;
};
//[[CLASS INFO]] use struct-binding method :
//const auto &[_m0,_m1,_m2] = Vec3;



//[[CLASS INFO]] class:Vec4, is pod:true, is aggregate:true
struct Vec4 {
  float x, y, z, w;
};
//[[CLASS INFO]] use struct-binding method :
//const auto &[_m0,_m1,_m2,_m3] = Vec4;



Process finished with exit code 0

 

 

 

参考:

编译器 LLVM Clang原理与实战 制作自己的编译器 source-to-source 源代码转换 编译遍 compile pass 代码插桩_llvm emitobjaction_EwenWanW的博客-CSDN博客