diff options
| -rw-r--r-- | clang/include/clang/Basic/SourceManager.h | 2 | ||||
| -rw-r--r-- | clang/lib/Basic/SourceManager.cpp | 102 | ||||
| -rw-r--r-- | clang/tools/libclang/CIndex.cpp | 18 | 
3 files changed, 99 insertions, 23 deletions
diff --git a/clang/include/clang/Basic/SourceManager.h b/clang/include/clang/Basic/SourceManager.h index a19272f29dd..c0fbd089e76 100644 --- a/clang/include/clang/Basic/SourceManager.h +++ b/clang/include/clang/Basic/SourceManager.h @@ -783,7 +783,7 @@ public:    /// If the source file is included multiple times, the source location will    /// be based upon the first inclusion.    SourceLocation getLocation(const FileEntry *SourceFile, -                             unsigned Line, unsigned Col) const; +                             unsigned Line, unsigned Col);    /// \brief Determines the order of 2 source locations in the translation unit.    /// diff --git a/clang/lib/Basic/SourceManager.cpp b/clang/lib/Basic/SourceManager.cpp index e476cb2e299..9d5569aa396 100644 --- a/clang/lib/Basic/SourceManager.cpp +++ b/clang/lib/Basic/SourceManager.cpp @@ -16,6 +16,7 @@  #include "clang/Basic/Diagnostic.h"  #include "clang/Basic/FileManager.h"  #include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/Optional.h"  #include "llvm/Support/Compiler.h"  #include "llvm/Support/MemoryBuffer.h"  #include "llvm/Support/raw_ostream.h" @@ -23,6 +24,7 @@  #include <algorithm>  #include <string>  #include <cstring> +#include <sys/stat.h>  using namespace clang;  using namespace SrcMgr; @@ -1107,38 +1109,58 @@ PresumedLoc SourceManager::getPresumedLoc(SourceLocation Loc) const {  // Other miscellaneous methods.  //===----------------------------------------------------------------------===// +/// \brief Retrieve the inode for the given file entry, if possible. +/// +/// This routine involves a system call, and therefore should only be used +/// in non-performance-critical code. +static llvm::Optional<ino_t> getActualFileInode(const FileEntry *File) { +  if (!File) +    return llvm::Optional<ino_t>(); +   +  struct stat StatBuf; +  if (::stat(File->getName(), &StatBuf)) +    return llvm::Optional<ino_t>(); +     +  return StatBuf.st_ino; +} +  /// \brief Get the source location for the given file:line:col triplet.  ///  /// If the source file is included multiple times, the source location will  /// be based upon the first inclusion.  SourceLocation SourceManager::getLocation(const FileEntry *SourceFile, -                                          unsigned Line, unsigned Col) const { +                                          unsigned Line, unsigned Col) {    assert(SourceFile && "Null source file!");    assert(Line && Col && "Line and column should start from 1!"); -  fileinfo_iterator FI = FileInfos.find(SourceFile); -  if (FI == FileInfos.end()) -    return SourceLocation(); -  ContentCache *Content = FI->second; - -  // If this is the first use of line information for this buffer, compute the -  /// SourceLineCache for it on demand. -  if (Content->SourceLineCache == 0) { -    bool MyInvalid = false; -    ComputeLineNumbers(Diag, Content, ContentCacheAlloc, *this, MyInvalid); -    if (MyInvalid) -      return SourceLocation(); -  } -    // Find the first file ID that corresponds to the given file.    FileID FirstFID;    // First, check the main file ID, since it is common to look for a    // location in the main file. +  llvm::Optional<ino_t> SourceFileInode; +  llvm::Optional<llvm::StringRef> SourceFileName;    if (!MainFileID.isInvalid()) {      const SLocEntry &MainSLoc = getSLocEntry(MainFileID); -    if (MainSLoc.isFile() && MainSLoc.getFile().getContentCache() == Content) -      FirstFID = MainFileID; +    if (MainSLoc.isFile()) { +      const ContentCache *MainContentCache +        = MainSLoc.getFile().getContentCache(); +      if (MainContentCache->Entry == SourceFile) +        FirstFID = MainFileID; +      else if (MainContentCache) { +        // Fall back: check whether we have the same base name and inode +        // as the main file. +        const FileEntry *MainFile = MainContentCache->Entry; +        SourceFileName = llvm::sys::path::filename(SourceFile->getName()); +        if (*SourceFileName == llvm::sys::path::filename(MainFile->getName())) { +          SourceFileInode = getActualFileInode(SourceFile); +          if (SourceFileInode == getActualFileInode(MainFile)) { +            FirstFID = MainFileID; +            SourceFile = MainFile; +          } +        } +      } +    }    }    if (FirstFID.isInvalid()) { @@ -1146,16 +1168,60 @@ SourceLocation SourceManager::getLocation(const FileEntry *SourceFile,      // through all of the source locations.      for (unsigned I = 0, N = sloc_entry_size(); I != N; ++I) {        const SLocEntry &SLoc = getSLocEntry(I); -      if (SLoc.isFile() && SLoc.getFile().getContentCache() == Content) { +      if (SLoc.isFile() &&  +          SLoc.getFile().getContentCache() && +          SLoc.getFile().getContentCache()->Entry == SourceFile) {          FirstFID = FileID::get(I);          break;        }      }    } + +  // If we haven't found what we want yet, try again, but this time stat() +  // each of the files in case the files have changed since we originally  +  // parsed the file.  +  if (FirstFID.isInvalid() && +      (SourceFileName ||  +       (SourceFileName = llvm::sys::path::filename(SourceFile->getName()))) && +      (SourceFileInode || +       (SourceFileInode = getActualFileInode(SourceFile)))) { +    for (unsigned I = 0, N = sloc_entry_size(); I != N; ++I) { +      const SLocEntry &SLoc = getSLocEntry(I); +      if (SLoc.isFile()) {  +        const ContentCache *FileContentCache  +          = SLoc.getFile().getContentCache(); +        const FileEntry *Entry =FileContentCache? FileContentCache->Entry : 0; +        if (Entry &&  +            *SourceFileName == llvm::sys::path::filename(Entry->getName()) && +            SourceFileInode == getActualFileInode(Entry)) { +          FirstFID = FileID::get(I); +          SourceFile = Entry; +          break; +        } +      } +    }       +  }    if (FirstFID.isInvalid())      return SourceLocation(); +  if (Line == 1 && Col == 1) +    return getLocForStartOfFile(FirstFID); + +  ContentCache *Content +    = const_cast<ContentCache *>(getOrCreateContentCache(SourceFile)); +  if (!Content) +    return SourceLocation(); +     +  // If this is the first use of line information for this buffer, compute the +  /// SourceLineCache for it on demand. +  if (Content->SourceLineCache == 0) { +    bool MyInvalid = false; +    ComputeLineNumbers(Diag, Content, ContentCacheAlloc, *this, MyInvalid); +    if (MyInvalid) +      return SourceLocation(); +  } +    if (Line > Content->NumLines) {      unsigned Size = Content->getBuffer(Diag, *this)->getBufferSize();      if (Size > 0) diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index ec0f54fa1a1..32e0039b0d3 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -2483,12 +2483,22 @@ CXSourceLocation clang_getLocation(CXTranslationUnit tu,    if (!tu || !file)      return clang_getNullLocation(); +  bool Logging = ::getenv("LIBCLANG_LOGGING");    ASTUnit *CXXUnit = static_cast<ASTUnit *>(tu->TUData); +  const FileEntry *File = static_cast<const FileEntry *>(file);    SourceLocation SLoc -    = CXXUnit->getSourceManager().getLocation( -                                        static_cast<const FileEntry *>(file), -                                              line, column); -  if (SLoc.isInvalid()) return clang_getNullLocation(); +    = CXXUnit->getSourceManager().getLocation(File, line, column); +  if (SLoc.isInvalid()) { +    if (Logging) +      llvm::errs() << "clang_getLocation(\"" << File->getName()  +                   << "\", " << line << ", " << column << ") = invalid\n"; +    return clang_getNullLocation(); +  } + +  if (Logging) +    llvm::errs() << "clang_getLocation(\"" << File->getName()  +                 << "\", " << line << ", " << column << ") = "  +                 << SLoc.getRawEncoding() << "\n";    return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc);  }  | 

