1. 程式人生 > >Clang外掛學習 Clang外掛常用API

Clang外掛學習 Clang外掛常用API

1.定義一個plugin子類標頭檔案

#ifndef MyPlugin_hpp
#define MyPlugin_hpp

#include <stdio.h>

#include<iostream>
#include<sstream>
#include<typeinfo>

#include "clang/Frontend/FrontendPluginRegistry.h"
#include "clang/AST/AST.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/AST/RecursiveASTVisitor.h" #include "ValidAPIUtil.hpp" #pragma GCC visibility push(default) using namespace clang; using namespace std; using namespace llvm; extern string gSrcRootPath; namespace my { class MyASTVisitor : public RecursiveASTVisitor<MyASTVisitor> { private
: ASTContext *context; public: void setContext(ASTContext &context); bool VisitDecl(Decl *decl); bool VisitStmt(Stmt *s); }; ast解析完成後呼叫 class MyASTConsumer : public ASTConsumer { private: MyASTVisitor visitor; void HandleTranslationUnit(ASTContext &context); }; class
MyASTAction : public PluginASTAction { public: // this gets called by Clang when it invokes our Plugin unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler,llvm::StringRef InFile); //處理外掛的命令列引數 bool ParseArgs(const CompilerInstance &CI, const std::vector<std::string>& args); }; } #pragma GCC visibility pop #endif /* MyPlugin_hpp */

2.註冊plugin

static clang::FrontendPluginRegistry::Add<my::MyASTAction>
X("MyPluginName", "MyPlugin description");

第一個引數是外掛名稱,第二個是外掛描述

3.處理命令列引數

編譯的時候新增plugin對應的param就可以通過該方法將param獲取到.例如在other_cflag除了上期配置外新增中新增-Xclang -plugin-arg-MyPlugin -Xclang $SRCROOT/..,就可以將srcroot的路徑打印出來

    //處理命令列引數
bool MyASTAction::ParseArgs(const CompilerInstance &CI, const std::vector<std::string>& args) {
        size_t cnt = args.size();
        for(int i = 0;i < cnt;i++){
            cout<<"myparam:"<<args.at(i)<<endl;
        }
       return true;
}

4.重寫VisitDel

這個方法獲得到宣告的介面,實現類,categore等

1.是否是interface宣告if(isa<ObjCInterfaceDecl>(decl)){}

獲取父類名稱:interfDecl->getSuperClass()->>getNameAsString()

獲取當前類名稱:objcClsInterface = interfDecl->getNameAsString();後面獲取類的名稱都與此類似

獲取實現的所有ObjCProtocolDecl:
for(ObjCList<ObjCProtocolDecl>::iterator it = interfDecl->all_referenced_protocol_begin();it!=interfDecl->all_referenced_protocol_end();it++){
    (*it)->getNameAsString();
}

獲取介面檔名稱: context->getSourceManager().getFilename(interfDecl->getSourceRange().getBegin()).str();

2.是否是實現類

if(isa<ObjCImplDecl>(decl)){}

3.是否是category

if(isa<ObjCCategoryDecl>(decl)){}

4.是否是協議

if(isa<ObjCProtocolDecl>(decl)){}

5.是否是property

if(isa<ObjCPropertyDecl>(decl)){}

是否是例項變數:objcIsInstanceMethod = propertyDecl->isInstanceProperty();
property型別(修飾符例如NSString):propertyDecl->getType().getAsString();
getter方法名稱:propertyDecl->getGetterName().getAsString()
setter方法名稱:propertyDecl->getSetterName().getAsString()
是否只讀:propertyDecl->isReadOnly()
是否是類property:propertyDecl->isClassProperty()
是否是原子性:propertyDecl->isAtomic()

6.是否是成員變數

if (isa<ObjCIvarDecl>(decl)) {}

成員變數名稱:ivarDecl->getNameAsString()

7.是否是引數
if (isa<ObjCTypeParamDecl>(decl)){}

@interface NSDictionary<Key : id<NSCopying>, Value>@end
key,value就是paramter

8.是否是方法
if(isa<ObjCMethodDecl>(decl)){}

是否是例項方法: methodDecl->isInstanceMethod()
selector名稱: methodDecl->getSelector().getAsString()
返回值型別:methodDecl->getReturnType().getAsString()
引數:
for(ArrayRef<ParmVarDecl *>::iterator it = methodDecl->param_begin();it!=methodDecl->param_end();it++){
    cout<<"引數:"<<((*it)->getNameAsString())<<"引數型別:"<<(*it)->getType().getAsString()<<endl;
}

5.重寫VisitStmt

1.是否是變數方法列舉等
if(isa<DeclRefExpr>(s)){}

宣告的名稱:callExpr->getDecl()->->getNameAsString()
是否是變數:isa<VarDecl>(decl)
是否是函式:isa<FunctionDecl>(decl)
是否是列舉:isa<EnumConstantDecl>(decl)

2.向object-c物件傳送訊息
isa<ObjCMessageExpr>(s)
呼叫者:objcExpr->getSelector().getAsString()
函式本身名稱: objcExpr->getSelector().getAsString()
接受訊息型別:objcExpr->getReceiverType().getAsString()

6.完成ast讀取

ast解析完成後呼叫
    void MyASTConsumer::HandleTranslationUnit(ASTContext &context){
   }

7.參考