From 507097ec40105ed927cb5a744fad98f5875aacac Mon Sep 17 00:00:00 2001 From: Argyrios Kyrtzidis Date: Mon, 19 Sep 2011 20:40:35 +0000 Subject: [PATCH] [libclang] When getting a source location from a file:line:col triplet check whether the requested location points inside the precompiled preamble, in which case the returned source location will be a "loaded" one. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@140060 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/SourceManager.h | 24 ++++++++------ include/clang/Frontend/ASTUnit.h | 49 ++++++++++++++++++++++++++++- lib/Basic/SourceManager.cpp | 12 ++++--- lib/Frontend/ASTUnit.cpp | 44 ++++++++++++++++++++++++-- lib/Frontend/CompilerInstance.cpp | 7 ++--- lib/Serialization/ASTReader.cpp | 18 +++-------- test/PCH/preamble.c | 6 ++-- tools/libclang/CIndex.cpp | 13 ++------ 8 files changed, 127 insertions(+), 46 deletions(-) diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h index 09aadcebba..46fdbe5066 100644 --- a/include/clang/Basic/SourceManager.h +++ b/include/clang/Basic/SourceManager.h @@ -559,6 +559,9 @@ class SourceManager : public llvm::RefCountedBase { /// MainFileID - The file ID for the main source file of the translation unit. FileID MainFileID; + /// \brief The file ID for the precompiled preamble there is one. + FileID PreambleFileID; + // Statistics for -print-stats. mutable unsigned NumLinearScans, NumBinaryProbes; @@ -610,13 +613,15 @@ public: return MainFileID; } - /// \brief Set the file ID for the precompiled preamble, which is also the - /// main file. - void SetPreambleFileID(FileID Preamble) { - assert(MainFileID.isInvalid() && "MainFileID already set!"); - MainFileID = Preamble; + /// \brief Set the file ID for the precompiled preamble. + void setPreambleFileID(FileID Preamble) { + assert(PreambleFileID.isInvalid() && "PreambleFileID already set!"); + PreambleFileID = Preamble; } + /// \brief Get the file ID for the precompiled preamble if there is one. + FileID getPreambleFileID() const { return PreambleFileID; } + //===--------------------------------------------------------------------===// // Methods to create new FileID's and macro expansions. //===--------------------------------------------------------------------===// @@ -1117,11 +1122,12 @@ public: /// If the source file is included multiple times, the source location will /// be based upon the first inclusion. SourceLocation translateFileLineCol(const FileEntry *SourceFile, - unsigned Line, unsigned Col); + unsigned Line, unsigned Col) const; /// \brief Get the source location in \arg FID for the given line:col. /// Returns null location if \arg FID is not a file SLocEntry. - SourceLocation translateLineCol(FileID FID, unsigned Line, unsigned Col); + SourceLocation translateLineCol(FileID FID, + unsigned Line, unsigned Col) const; /// \brief If \arg Loc points inside a function macro argument, the returned /// location will be the macro location in which the argument was expanded. @@ -1132,7 +1138,7 @@ public: /// ^ /// Passing a file location pointing at 'foo', will yield a macro location /// where 'foo' was expanded into. - SourceLocation getMacroArgExpandedLocation(SourceLocation Loc); + SourceLocation getMacroArgExpandedLocation(SourceLocation Loc) const; /// \brief Determines the order of 2 source locations in the translation unit. /// @@ -1309,7 +1315,7 @@ private: std::pair getDecomposedSpellingLocSlowCase(const SrcMgr::SLocEntry *E, unsigned Offset) const; - void computeMacroArgsCache(SrcMgr::ContentCache *Content, FileID FID); + void computeMacroArgsCache(SrcMgr::ContentCache *Content, FileID FID) const; friend class ASTReader; friend class ASTWriter; diff --git a/include/clang/Frontend/ASTUnit.h b/include/clang/Frontend/ASTUnit.h index e2fa5574fe..4a8475bb6c 100644 --- a/include/clang/Frontend/ASTUnit.h +++ b/include/clang/Frontend/ASTUnit.h @@ -196,9 +196,41 @@ private: /// \brief The file in which the precompiled preamble is stored. std::string PreambleFile; + class PreambleData { + const FileEntry *File; + std::vector Buffer; + mutable unsigned NumLines; + + public: + PreambleData() : File(0), NumLines(0) { } + + void assign(const FileEntry *F, const char *begin, const char *end) { + File = F; + Buffer.assign(begin, end); + NumLines = 0; + } + + void clear() { Buffer.clear(); File = 0; NumLines = 0; } + + size_t size() const { return Buffer.size(); } + bool empty() const { return Buffer.empty(); } + + const char *getBufferStart() const { return &Buffer[0]; } + + unsigned getNumLines() const { + if (NumLines) + return NumLines; + countLines(); + return NumLines; + } + + private: + void countLines() const; + }; + /// \brief The contents of the preamble that has been precompiled to /// \c PreambleFile. - std::vector Preamble; + PreambleData Preamble; /// \brief Whether the preamble ends at the start of a new line. /// @@ -515,6 +547,21 @@ public: PreprocessedEntitiesByFileMap &getPreprocessedEntitiesByFile() { return PreprocessedEntitiesByFile; } + + /// \brief Get the source location for the given file:line:col triplet. + /// + /// The difference with SourceManager::getLocation is that this method checks + /// whether the requested location points inside the precompiled preamble + /// in which case the returned source location will be a "loaded" one. + SourceLocation getLocation(const FileEntry *File, + unsigned Line, unsigned Col) const; + + /// \brief Get the source location for the given file:offset pair. + /// + /// The difference with SourceManager::getLocation is that this method checks + /// whether the requested location points inside the precompiled preamble + /// in which case the returned source location will be a "loaded" one. + SourceLocation getLocation(const FileEntry *File, unsigned Offset) const; // Retrieve the diagnostics associated with this AST typedef const StoredDiagnostic *stored_diag_iterator; diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp index 38cc9946be..68c98fe02c 100644 --- a/lib/Basic/SourceManager.cpp +++ b/lib/Basic/SourceManager.cpp @@ -1324,7 +1324,8 @@ static llvm::Optional getActualFileInode(const FileEntry *File) { /// If the source file is included multiple times, the source location will /// be based upon an arbitrary inclusion. SourceLocation SourceManager::translateFileLineCol(const FileEntry *SourceFile, - unsigned Line, unsigned Col) { + unsigned Line, + unsigned Col) const { assert(SourceFile && "Null source file!"); assert(Line && Col && "Line and column should start from 1!"); @@ -1439,7 +1440,8 @@ SourceLocation SourceManager::translateFileLineCol(const FileEntry *SourceFile, /// \brief Get the source location in \arg FID for the given line:col. /// Returns null location if \arg FID is not a file SLocEntry. SourceLocation SourceManager::translateLineCol(FileID FID, - unsigned Line, unsigned Col) { + unsigned Line, + unsigned Col) const { if (FID.isInvalid()) return SourceLocation(); @@ -1496,7 +1498,8 @@ SourceLocation SourceManager::translateLineCol(FileID FID, /// 0 -> SourceLocation() /// 100 -> Expanded macro arg location /// 110 -> SourceLocation() -void SourceManager::computeMacroArgsCache(ContentCache *Content, FileID FID) { +void SourceManager::computeMacroArgsCache(ContentCache *Content, + FileID FID) const { assert(!Content->MacroArgsCache); assert(!FID.isInvalid()); @@ -1575,7 +1578,8 @@ void SourceManager::computeMacroArgsCache(ContentCache *Content, FileID FID) { /// ^ /// Passing a file location pointing at 'foo', will yield a macro location /// where 'foo' was expanded into. -SourceLocation SourceManager::getMacroArgExpandedLocation(SourceLocation Loc) { +SourceLocation +SourceManager::getMacroArgExpandedLocation(SourceLocation Loc) const { if (Loc.isInvalid() || !Loc.isFileID()) return Loc; diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index 6f9b437814..53e0412750 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -1200,7 +1200,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( if (Preamble.size() == NewPreamble.second.first && PreambleEndsAtStartOfLine == NewPreamble.second.second && NewPreamble.first->getBufferSize() < PreambleReservedSize-2 && - memcmp(&Preamble[0], NewPreamble.first->getBufferStart(), + memcmp(Preamble.getBufferStart(), NewPreamble.first->getBufferStart(), NewPreamble.second.first) == 0) { // The preamble has not changed. We may be able to re-use the precompiled // preamble. @@ -1332,7 +1332,9 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( // Save the preamble text for later; we'll need to compare against it for // subsequent reparses. - Preamble.assign(NewPreamble.first->getBufferStart(), + StringRef MainFilename = PreambleInvocation->getFrontendOpts().Inputs[0].second; + Preamble.assign(FileMgr->getFile(MainFilename), + NewPreamble.first->getBufferStart(), NewPreamble.first->getBufferStart() + NewPreamble.second.first); PreambleEndsAtStartOfLine = NewPreamble.second.second; @@ -2396,3 +2398,41 @@ void ASTUnit::TranslateStoredDiagnostics( } Result.swap(Out); } + +SourceLocation ASTUnit::getLocation(const FileEntry *File, + unsigned Line, unsigned Col) const { + const SourceManager &SM = getSourceManager(); + SourceLocation Loc; + if (!Preamble.empty() && Line <= Preamble.getNumLines()) + Loc = SM.translateLineCol(SM.getPreambleFileID(), Line, Col); + else + Loc = SM.translateFileLineCol(File, Line, Col); + + return SM.getMacroArgExpandedLocation(Loc); +} + +SourceLocation ASTUnit::getLocation(const FileEntry *File, + unsigned Offset) const { + const SourceManager &SM = getSourceManager(); + SourceLocation FileLoc; + if (!Preamble.empty() && Offset < Preamble.size()) + FileLoc = SM.getLocForStartOfFile(SM.getPreambleFileID()); + else + FileLoc = SM.translateFileLineCol(File, 1, 1); + + return SM.getMacroArgExpandedLocation(FileLoc.getLocWithOffset(Offset)); +} + +void ASTUnit::PreambleData::countLines() const { + NumLines = 0; + if (empty()) + return; + + for (std::vector::const_iterator + I = Buffer.begin(), E = Buffer.end(); I != E; ++I) { + if (*I == '\n') + ++NumLines; + } + if (Buffer.back() != '\n') + ++NumLines; +} diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index 92798c8c29..924864c8cc 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -539,11 +539,8 @@ bool CompilerInstance::InitializeSourceManager(StringRef InputFile, FileManager &FileMgr, SourceManager &SourceMgr, const FrontendOptions &Opts) { - // Figure out where to get and map in the main file, unless it's already - // been created (e.g., by a precompiled preamble). - if (!SourceMgr.getMainFileID().isInvalid()) { - // Do nothing: the main file has already been set. - } else if (InputFile != "-") { + // Figure out where to get and map in the main file. + if (InputFile != "-") { const FileEntry *File = FileMgr.getFile(InputFile); if (!File) { Diags.Report(diag::err_fe_error_reading) << InputFile; diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 0f3cad5513..02d7eeaa8d 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -2508,23 +2508,15 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName, if (DeserializationListener) DeserializationListener->ReaderInitialized(this); - // If this AST file is a precompiled preamble, then set the main file ID of - // the source manager to the file source file from which the preamble was - // built. This is the only valid way to use a precompiled preamble. + // If this AST file is a precompiled preamble, then set the preamble file ID + // of the source manager to the file source file from which the preamble was + // built. if (Type == MK_Preamble) { - if (OriginalFileID.isInvalid()) { - SourceLocation Loc - = SourceMgr.getLocation(FileMgr.getFile(getOriginalSourceFile()), 1, 1); - if (Loc.isValid()) - OriginalFileID = SourceMgr.getDecomposedLoc(Loc).first; - } - else { + if (!OriginalFileID.isInvalid()) { OriginalFileID = FileID::get(ModuleMgr.getPrimaryModule().SLocEntryBaseID + OriginalFileID.getOpaqueValue() - 1); + SourceMgr.setPreambleFileID(OriginalFileID); } - - if (!OriginalFileID.isInvalid()) - SourceMgr.SetPreambleFileID(OriginalFileID); } return Success; diff --git a/test/PCH/preamble.c b/test/PCH/preamble.c index bdc0aea656..6a61fa10ff 100644 --- a/test/PCH/preamble.c +++ b/test/PCH/preamble.c @@ -1,7 +1,7 @@ // Check that using the preamble option actually skips the preamble. -// RUN: %clang_cc1 -emit-pch -o %t %S/Inputs/preamble.h -// RUN: %clang_cc1 -include-pch %t -preamble-bytes=278,1 -DFOO=f -verify %s +// RUN: %clang_cc1 -emit-pch -o %t %S/Inputs/preamble.h -DFOO=f +// RUN: %clang_cc1 -include-pch %t -preamble-bytes=317,1 -DFOO=f -verify %s -emit-llvm -o - | FileCheck %s float f(int); // Not an error, because we skip this via the preamble! @@ -19,3 +19,5 @@ float f(int); // Not an error, because we skip this via the preamble! int g(int x) { return FOO(x); } + +// CHECK: call {{.*}} @f( diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index 3654a58a5d..8390a7ce8d 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -2750,8 +2750,7 @@ CXSourceLocation clang_getLocation(CXTranslationUnit tu, bool Logging = ::getenv("LIBCLANG_LOGGING"); ASTUnit *CXXUnit = static_cast(tu->TUData); const FileEntry *File = static_cast(file); - SourceLocation SLoc - = CXXUnit->getSourceManager().getLocation(File, line, column); + SourceLocation SLoc = CXXUnit->getLocation(File, line, column); if (SLoc.isInvalid()) { if (Logging) llvm::errs() << "clang_getLocation(\"" << File->getName() @@ -2774,14 +2773,8 @@ CXSourceLocation clang_getLocationForOffset(CXTranslationUnit tu, return clang_getNullLocation(); ASTUnit *CXXUnit = static_cast(tu->TUData); - SourceLocation Start - = CXXUnit->getSourceManager().getLocation( - static_cast(file), - 1, 1); - if (Start.isInvalid()) return clang_getNullLocation(); - - SourceLocation SLoc = Start.getLocWithOffset(offset); - + SourceLocation SLoc + = CXXUnit->getLocation(static_cast(file), offset); if (SLoc.isInvalid()) return clang_getNullLocation(); return cxloc::translateSourceLocation(CXXUnit->getASTContext(), SLoc); -- 2.40.0