我正在使用clang进行libtooling。我开发了一种工具来查找全局变量以及在哪里引用这些全局变量。
现在,我想获取使用这些全局变量的函数名称。
这是示例代码
int Var;
int display()
{
Var = 10;
return Var;
}
int main()
{
display();
return 0;
}
在这里,我想在函数Var
中引用全局变量display
。
如何使用LibTooling clang获得此输出?请让我知道是否有解决办法。
答案 0 :(得分:0)
可以使用libTooling
。如果您已经找到DeclRefExpr
个引用全局变量的节点,则可以将AST移至其FunctionDecl
的父节点。
另一方面,走AST需要Clang构造从节点到其父节点的映射(对于大型翻译单元而言,这可能是相当昂贵的)。在这里,我整理了一个简短的解决方案,该解决方案只是查找引用全局变量的函数并打印其名称:
class GlobalVariableFinder final
: public RecursiveASTVisitor<GlobalVariableFinder> {
public:
static bool find(FunctionDecl *CandidateFunction) {
GlobalVariableFinder ActualFinder;
ActualFinder.TraverseDecl(CandidateFunction);
return ActualFinder.Found;
}
bool VisitDeclRefExpr(DeclRefExpr *SymbolUse) {
// we are interested only in variables
if (auto *Declaration = dyn_cast<VarDecl>(SymbolUse->getDecl())) {
Found = Declaration->hasGlobalStorage();
// if we found one global variable use, there is no need in traversing
// this function any further
if (Found) return false;
}
return true;
}
private:
bool Found = false;
};
class VisitingASTConsumer final
: public ASTConsumer,
public RecursiveASTVisitor<VisitingASTConsumer> {
public:
void HandleTranslationUnit(ASTContext &C) {
this->TraverseTranslationUnitDecl(Context->getTranslationUnitDecl());
}
bool VisitFunctionDecl(FunctionDecl *CandidateFunction) {
if (GlobalVariableFinder::find(CandidateFunction)) {
llvm::errs() << CandidateFunction->getQualifiedNameAsString() << "\n";
}
return true;
}
};
如果要存储全局变量引用,则可能需要修改GlobalVariableFinder
类以包含其他逻辑。
以下解决方案在此代码段上产生以下输出:
int Var;
int display()
{
Var = 10;
return Var;
}
int foo() {
return Var;
}
int bar() {
return foo();
}
int main()
{
display();
return 0;
}
display
foo
您会注意到,它仅包含语法上使用全局变量的函数。如果您想让算法也找到bar
,则需要构建目标程序的调用图,并通过图的反向边缘(例如来自foo
)传播有关全局变量的信息。到我们示例中的bar
。
我希望这些信息对您有所帮助。使用Clang进行快乐的黑客入侵!