个人网站维护费用,搜搜网站提交入口,房天下官方网站,公司文化建设的意义原文
基于RecursiveASTVisitor的ASTFrontendActions.
创建用RecursiveASTVisitor查找特定名字的CXXRecordDeclAST节点的FrontendAction.
创建FrontendAction
编写基于clang的工具(如Clang插件或基于LibTooling的独立工具)时,常见入口是允许在编译过程中执行用户特定操作的F…原文
基于RecursiveASTVisitor的ASTFrontendActions.
创建用RecursiveASTVisitor查找特定名字的CXXRecordDeclAST节点的FrontendAction.
创建FrontendAction
编写基于clang的工具(如Clang插件或基于LibTooling的独立工具)时,常见入口是允许在编译过程中执行用户特定操作的FrontendAction接口.
为了在ASTclang上运行工具,提供了方便的负责执行操作的ASTFrontendAction接口.你只需要实现对每个转换单元返回一个ASTConsumer的CreateASTConsumer方法.
class FindNamedClassAction : public clang::ASTFrontendAction {
public:virtual std::unique_ptrclang::ASTConsumer CreateASTConsumer(clang::CompilerInstance Compiler, llvm::StringRef InFile) {return std::make_uniqueFindNamedClassConsumer();}//FindNamedClassAction
};创建ASTConsumer
ASTConsumer是一个,不管如何生成的AST,在AST上编写的通用操作接口.ASTConsumer提供了许多不同的入口,但在此,只需要用ASTContext调用翻译单元的HandleTranslationUnit.
class FindNamedClassConsumer : public clang::ASTConsumer {
public:virtual void HandleTranslationUnit(clang::ASTContext Context) {//通过RecursiveASTVisitor遍历翻译单元声明,会访问AST中的所有节点.Visitor.TraverseDecl(Context.getTranslationUnitDecl());}
private://RecursiveASTVisitor实现.FindNamedClassVisitor Visitor;
};使用RecursiveASTVisitor
现在已连接了,下一步是实现RecursiveASTVisitor以从AST中提取相关信息.
除了按值传递的TypeLoc节点,RecursiveASTVisitor为大多数AST节点提供bool VisitNodeType(NodeType*)形式的勾挂.只需要为相关节点类型实现方法,就可以了. 首先编写一个访问所有CXXRecordDecl的RecursiveASTVisitor.
class FindNamedClassVisitor: public RecursiveASTVisitorFindNamedClassVisitor {
public:bool VisitCXXRecordDecl(CXXRecordDecl *Declaration) {//为了调试,转储AST节点,会显示已访问的节点.Declaration-dump();//返回值指示是否想继续访问.返回假以停止AST的遍历.return true;}
};在RecursiveASTVisitor的方法中,现在可用ClangAST的全部功能来深入感兴趣部分.如,要查找带特定名字的所有类声明,可检查全名:
bool VisitCXXRecordDecl(CXXRecordDecl *Declaration) {if (Declaration-getQualifiedNameAsString() n::m::C)Declaration-dump();return true;
}访问SourceManager和ASTContext
有关AST的某些信息(如源位置和全局标识信息)不在AST节点自身中,而是在ASTContext及其关联的源管理器中存储.
要提取它们,需要传递ASTContext进RecursiveASTVisitor实现中.
调用CreateASTConsumer时,CompilerInstance可访问ASTContext.因此,可从那里提取,并把它交给新创建的FindNamedClassConsumer:
virtual std::unique_ptrclang::ASTConsumer CreateASTConsumer(clang::CompilerInstance Compiler, llvm::StringRef InFile) {return std::make_uniqueFindNamedClassConsumer(Compiler.getASTContext());
}现在在RecursiveASTVisitor中,可访问ASTContext,可利用AST节点,查找源位置等:
bool VisitCXXRecordDecl(CXXRecordDecl *Declaration) {if (Declaration-getQualifiedNameAsString() n::m::C) {//getFullLoc使用ASTContext的SourceManager来解析源位置,并分解为行和列部分.FullSourceLoc FullLocation Context-getFullLoc(Declaration-getBeginLoc());if (FullLocation.isValid())llvm::outs() Found declaration at FullLocation.getSpellingLineNumber() : FullLocation.getSpellingColumnNumber() \n;}return true;
}组合在一起
如下:
#include clang/AST/ASTConsumer.h
#include clang/AST/RecursiveASTVisitor.h
#include clang/Frontend/CompilerInstance.h
#include clang/Frontend/FrontendAction.h
#include clang/Tooling/Tooling.h
using namespace clang;
class FindNamedClassVisitor: public RecursiveASTVisitorFindNamedClassVisitor {
public:explicit FindNamedClassVisitor(ASTContext *Context): Context(Context) {}bool VisitCXXRecordDecl(CXXRecordDecl *Declaration) {if (Declaration-getQualifiedNameAsString() n::m::C) {FullSourceLoc FullLocation Context-getFullLoc(Declaration-getBeginLoc());if (FullLocation.isValid())llvm::outs() Found declaration at FullLocation.getSpellingLineNumber() : FullLocation.getSpellingColumnNumber() \n;}return true;}
private:ASTContext *Context;
};
class FindNamedClassConsumer : public clang::ASTConsumer {
public:explicit FindNamedClassConsumer(ASTContext *Context): Visitor(Context) {}virtual void HandleTranslationUnit(clang::ASTContext Context) {Visitor.TraverseDecl(Context.getTranslationUnitDecl());}
private:FindNamedClassVisitor Visitor;
};
class FindNamedClassAction : public clang::ASTFrontendAction {
public:virtual std::unique_ptrclang::ASTConsumer CreateASTConsumer(clang::CompilerInstance Compiler, llvm::StringRef InFile) {return std::make_uniqueFindNamedClassConsumer(Compiler.getASTContext());}
};
int main(int argc, char **argv) {if (argc 1) {clang::tooling::runToolOnCode(std::make_uniqueFindNamedClassAction(), argv[1]);}
}在FindClassDecls.cpp文件中存储它,并创建以下CMakeLists.txt来链接它:
set(LLVM_LINK_COMPONENTSSupport)
add_clang_executable(find-class-decls FindClassDecls.cpp)
target_link_libraries(find-class-declsPRIVATEclangASTclangBasicclangFrontendclangSerializationclangTooling)对代码片运行此工具时,输出找到的n::m::C类的所有声明:
$ ./bin/find-class-decls namespace n { namespace m { class C {}; } }在1:29找到声明