国内写clang的libtool的文章较少,打算写一些有趣但无关紧要的clang api介绍。
预处理回调类:
class PreprocessorCallbacks:public clang::PPCallbacks{
void MacroDefined(const Token ¯oNameToken, const MacroDirective *MD)//源码解析到 #define回调
void MacroExpands(...)//源码发生宏展开时调用。
}
如何获取某个宏的定义呢?通过重写MacroDefined方法,macroNameToken.getIdentifierInfo()->getNameStart()
如果获取function liked宏的参数呢?macroArgs->getUnexpArgument(0).getIdentifierInfo()->getNameStart()
但这样获取的参数有时无法print,例如get_user(target, (uint32_t __user )ptr)),这时我们需要获取tokens, ((clang::MacroArgs)macroArgs)->getPreExpArgument(1, preprocessor);再写一个while循环来解析。
这个解析非常难写,可用性不高,更通用的办法是:
- 获取宏定义在文件中的位置
- 根据位置匹配StmtExpr,找出所有引用
- 手工编写match匹配需要的内容
class PreprocessorCallbacks:public clang::PPCallbacks{
public:
explicit PreprocessorCallbacks(clang::SourceManager& sourceManager, Preprocessor & preprocessor):
sourceManager(sourceManager), preprocessor(preprocessor){
}
void MacroDefined(const Token ¯oNameToken, const MacroDirective *MD) override {
if(macroNameToken.getIdentifierInfo()->getNameStart()==std::string("get_user")){
const MacroInfo* mi = MD->getMacroInfo();
MD->dump();
}
}
void MacroExpands(
const clang::Token& macroNameToken,
const clang::MacroDefinition& macroDirective,
clang::SourceRange range,
const clang::MacroArgs* macroArgs) override {
//#define n
MacroInfo* macroInfo=macroDirective.getMacroInfo();
UserCopyMacroLocAndArg macro;
if(macroInfo && macroArgs &&
macroNameToken.getIdentifierInfo()->getNameStart()==std::string("get_user")){
//macroInfo->getDefinitionLoc().dump(sourceManager);
//macroInfo->dump();
const Token * to_token=macroArgs->getUnexpArgument(0);
const Token * from_token=nullptr;
std::vector<Token> tokens = ((clang::MacroArgs*)macroArgs)->getPreExpArgument(1, preprocessor);
int idx=0;
Token type_token;
std::string from_name;
while(idx < tokens.size()){
if(std::string("l_paren") == tokens[idx].getName() &&
std::string("star") == tokens[idx+2].getName()){
type_token = tokens[idx+1];
idx+=3;
}
else if(std::string("r_paren") == tokens[idx].getName()){
from_token=&tokens[idx+1];
break;
}
}
assert(from_token);
macro.loc = macroInfo->tokens_begin()->getLocation().printToString(sourceManager);
macro.name = macroNameToken.getIdentifierInfo()->getNameStart();
macro.to = std::string(to_token->getIdentifierInfo()->getNameStart());
macro.from = std::string(from_token->getIdentifierInfo()->getNameStart());
macro.type = std::string(type_token.getIdentifierInfo()->getNameStart());
macroData.push_back(macro);
/*
if(macroInfo->getNumTokens()>0){
for(auto arg : macroInfo->tokens()){
std::string loc(arg.getLocation().printToString(sourceManager));
//std::cout << arg.getName() << ": " << loc << "-- ";
//token contain all define value,
if(arg.getIdentifierInfo()){
//std::cout << arg.getIdentifierInfo()->getNameStart() << std::endl;
//arg.getLocation().dump(sourceManager);
}
}
//std::cout << std::endl;
}
*/
}
else{
return;
}
std::cout << "macro.to:\t" << macro.to << std::endl;
std::cout << "macro.from:\t" << macro.from << std::endl;
//macroNameToken.getLocation().dump(sourceManager);
}
private:
clang::SourceManager& sourceManager;
Preprocessor & preprocessor;
};