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.参考

1.官网教程
2plugindemo
3.插件入门

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值