Search code examples
clangllvmllvm-clang

getFilename returns an empty string


I have a SourceLocation that I wish to extract its filename from. Apparently, I should be able to do that by using SourceManager's getFilename. However, the result seems to always be an empty string when I process some header files.

I follow the source code and found that the issue is that in the getFilename function, which reads:

/// Return the filename of the file containing a SourceLocation.
StringRef getFilename(SourceLocation SpellingLoc) const {
  if (const FileEntry *F = getFileEntryForID(getFileID(SpellingLoc)))
    return F->getName();
  return StringRef();
}

The result of getFileID is somehow invalid in a sense that SLocEntry constructed from it will have isFile returning false. This causes getFileEntryForID (which does construct SLocEntry under the hood) to return a null pointer.

I have a workaround, which is:

StringRef myGetFilename(SourceLocation SpellingLoc) const {
  std::pair<FileID, unsigned> locInfo = getDecomposedExpansionLoc(SpellingLoc);
  if (const FileEntry *F = srcManager.getFileEntryForID(locInfo.first))
    return F->getName();
  return StringRef();
}

That is, call getDecomposedExpansionLoc first to get a raw FileID and use it in getFileEntryForID instead.

Experimentally, this seems to work well, but this is my first day with clang, so I'm very unsure if it's actually correct. So I have two questions:

  1. Is this a bug in clang?
  2. Is my workaround actually correct?

Thanks!


Solution

  • Ah, so the problem seems to be that getFilename expects a specific kind of SourceLocation, namely "SpellingLoc". So, change:

    srcManager.getFilename(loc)
    

    to

    srcManager.getFilename(srcManager.getSpellingLoc(loc))
    

    will fix the problem.