我的主要目标是尝试在函数参数之前获取宏(甚至只是文本)。例如:
void Foo(_In_ void* p, _Out_ int* x, _Out_cap_(2) int* y);
我需要妥善处理声明参数的宏之类的东西(忽略它们)。
#define Example _In_ int x
void Foo(Example);
我查看了预处理器记录对象,并使用Lexer :: getSourceText获取了宏名称 In , Out 等,但是看不到干净的宏。将它们映射回功能参数的方法。
我当前的解决方案是将所有宏扩展记录在文件中,然后将其SourceLocation与ParamVarDecl SourceLocation进行比较。除我不知道如何跳过参数后的内容外,这通常可以工作。
void Foo(_In_ void* p _Other_, _In_ int y);
获取逗号的SourceLocation可以,但是我在任何地方都找不到。
答案 0 :(得分:1)
问题的标题要求输入libclang
,但是当您使用Lexer::getSourceText
时,我假设它是libTooling
。我剩下的答案只有在libTooling
上才可行。
Lexer在令牌级别上工作。 逗号也是一个令牌,因此您可以使用参数的结束位置并使用Lexer::findNextToken获取下一个令牌。
这里是ParmVarDecl
(用于函数参数)和CallExpr
(用于函数参数)访问显示如何使用它的函数:
template <class T> void printNextTokenLocation(T *Node) {
auto NodeEndLocation = Node->getSourceRange().getEnd();
auto &SM = Context->getSourceManager();
auto &LO = Context->getLangOpts();
auto NextToken = Lexer::findNextToken(NodeEndLocation, SM, LO);
if (!NextToken) {
return;
}
auto NextTokenLocation = NextToken->getLocation();
llvm::errs() << NextTokenLocation.printToString(SM) << "\n";
}
bool VisitParmVarDecl(ParmVarDecl *Param) {
printNextTokenLocation(Param);
return true;
}
bool VisitCallExpr(CallExpr *Call) {
for (auto *Arg : Call->arguments()) {
printNextTokenLocation(Arg);
}
return true;
}
对于以下代码段:
#define FOO(x) int x
#define BAR float d
#define MINUS -
#define BLANK
void foo(int a, double b ,
FOO(c) , BAR) {}
int main() {
foo( 42 ,
36.6 , MINUS 10 , BLANK 0.0 );
return 0;
}
它产生以下输出(六个位置为逗号,两个为括号):
test.cpp:6:15
test.cpp:6:30
test.cpp:7:19
test.cpp:7:24
test.cpp:10:17
test.cpp:11:12
test.cpp:11:28
test.cpp:11:43
这是一种非常低级且容易出错的方法。但是,您可以更改解决原始问题的方式。
Clang在其源位置存储有关扩展宏的信息。您可以在SourceManager
中找到相关方法(例如isMacroArgExpansion或isMacroBodyExpansion)。结果,您可以访问ParmVarDecl
节点并检查其位置以进行宏扩展。
我强烈建议朝第二方向前进。
我希望这些信息会有所帮助。使用Clang进行快乐的黑客入侵!
UPD 说到属性,很遗憾,您没有太多选择。 Clang会忽略 any 未知属性,并且此行为不可调整。如果您不想修补Clang本身并将属性添加到Attrs.td,那么您实际上仅限于令牌和第一种方法。