Jaya Bharathi
Jaya Bharathi

Reputation: 11

How to get all the function names where the global variables are used?

I am working on libtooling with clang. I have developed a tools to find the global variables and where those global variables are referred.

Now, i want to get the function name which uses those Global variables.

Here is the Sample Code

int Var;

int display()
{
  Var = 10;
return Var;
}

int main()
{
  display();
return 0;
}

Here, i want to get that global variable Var is referred in Function display.

How can i get this Output using LibTooling clang? Please Let me know if there is any solution.

Upvotes: 1

Views: 1298

Answers (1)

Valeriy Savchenko
Valeriy Savchenko

Reputation: 1614

It is possible to do with libTooling. If you already found DeclRefExpr nodes that refer to global variables, you can walk up the AST to their FunctionDecl parents.

On the other hand, walking up the AST requires Clang to construct a mapping from nodes to their parent nodes (which might be pretty expensive for big translation units). Here I've put together a short solution that just finds function referring to global variables and prints their names:

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;
  }
};

If you want to store global variable references, you might want to modify the GlobalVariableFinder class to include additional logic.

Following solution produces the following output on this snippet of code:

int Var;

int display()
{
  Var = 10;
  return Var;
}

int foo() {
  return Var;
}

int bar() {
  return foo();
}

int main()
{
  display();
  return 0;
}
display
foo

You can notice that it includes only functions that syntactically use global variables. If you want the algorithm to find bar as well, you'll need to build a call graph of the target program and propagate the information about global variables by the reversed edges of the graph (i.e. from foo to bar in our example).

I hope this information is helpful. Happy hacking with Clang!

Upvotes: 1

Related Questions