2

I am having a clang::VarDecl object. I want to fetch the file name/location of the variable (at least if they are global). I also skimmed through a question:-

How to get location of variable name in clang::VarDecl

But I guess it is not about file name in which variables are declared. I also referred to

http://clang.llvm.org/doxygen/classclang_1_1SourceLocation.html

There isn't any function which may return file name. Can anybody tell me how to get it?

Community
  • 1
  • 1
Prakhar Mishra
  • 1,586
  • 4
  • 28
  • 52

2 Answers2

4

You're supposed to use SourceManager to get concrete data out of a SourceLocation. In particular, take a look at the SourceManager::getFilename(SourceLocation) method.

You can get an instance of a SourceManager by using CompilerInstance::getSourceManager.

Oak
  • 26,231
  • 8
  • 93
  • 152
  • But `CompilerInstance::createSourceManager` is having void as its return type. How will I get an instance of it? Same with `CompilerInstance::createFileManager`. I am new to CLang libtooling, could you explain a bit further? – Prakhar Mishra Dec 19 '13 at 06:38
  • Thanks for your help. But when I am trying to use `ci.getSourceManager().getFilename(var->getLocation()).str()`, where `ci` is object of `CompilerInstance` and `var` is object of `VarDecl`, then I am getting segmentation fault. This is what gdb says:- `Program received signal SIGSEGV, Segmentation fault. 0x08060d52 in clang::SourceManager::getFileID (this=0x0, SpellingLoc=...) at /home/prakhar/Source/CLang/llvm/tools/clang/include/clang/Basic/SourceManager.h:974`. Do you have any idea of what may the reasons for this error? – Prakhar Mishra Dec 19 '13 at 11:19
  • I figured out that `&ci.getSourceManager()` is NULL every time. At least tell me if I am missing something? Do I have to initialize SourceManager inside CompilerInstance? If yes, then how to construct a SourceManager? – Prakhar Mishra Dec 19 '13 at 13:35
  • 1
    @PrakharMishra have you created the source manager first (with the `createSourceManager` method)? – Oak Dec 19 '13 at 14:18
  • Thanks to the `compileModule` fn in `CompilerInstance.cpp`, I get to know how to create a `SourceManager`. Even before calling `createSourceManager`, one need to call `createDiagnostics` on `CompilerInstance` object or you will get `segmentation fault` otherwise. Thanks for your help, @Oak. – Prakhar Mishra Dec 20 '13 at 06:47
  • But, I am not getting file name by calling `ci.getSourceManager().getFilename(var->getLocation()).str()`. It returns empty string. – Prakhar Mishra Dec 20 '13 at 06:57
4

There was no need to create a SourceManager object. MatchFinder::MatchResult::Context gives me the ASTContext* on which I can call getSourceManager to get the SourceManager object. The rest is as we were doing previously.

class VarDeclPrinter : public MatchFinder::MatchCallback {
  public:

  virtual void run(const MatchFinder::MatchResult &Result) {

    SourceManager &srcMgr = Result.Context->getSourceManager();

    if(const VarDecl* var = Result.Nodes.getNodeAs<VarDecl>("var")) {
      if(var->isFunctionOrMethodVarDecl()) {
        cout << setw(20) << left << "Local Variable: " << var->getName().str() << "\t\t";
        cout << ((CXXMethodDecl*)(var->getParentFunctionOrMethod()))->getQualifiedNameAsString() << "\t";
        cout << "--" << srcMgr.getFilename(var->getLocation()).str();
        cout << "\n";
      }
      if(var->hasExternalStorage()) {
        cout << setw(20) << left << "External Variable: " << var->getName().str() << "\t\t";
        cout << "--" << srcMgr.getFilename(var->getLocation()).str();
        cout << "\n";
      }
      else if(var->hasGlobalStorage()) {
        cout << setw(20) << left << "Global Variable: " << var->getName().str() << "\t\t";
        cout << "--" << srcMgr.getFilename(var->getLocation()).str();
        cout << "\n";
      }
    }
  }
};

Thanks for your help, @Oak.

Prakhar Mishra
  • 1,586
  • 4
  • 28
  • 52