diff options
-rw-r--r-- | clang/include/clang/Basic/SourceManager.h | 55 | ||||
-rw-r--r-- | clang/include/clang/Lex/Lexer.h | 10 | ||||
-rw-r--r-- | clang/include/clang/Lex/Preprocessor.h | 24 | ||||
-rw-r--r-- | clang/lib/Basic/SourceManager.cpp | 106 | ||||
-rw-r--r-- | clang/lib/Frontend/CompilerInstance.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Lex/Lexer.cpp | 31 | ||||
-rw-r--r-- | clang/lib/Lex/Preprocessor.cpp | 60 |
7 files changed, 144 insertions, 144 deletions
diff --git a/clang/include/clang/Basic/SourceManager.h b/clang/include/clang/Basic/SourceManager.h index 6cf92e674b1..3b170a6a74f 100644 --- a/clang/include/clang/Basic/SourceManager.h +++ b/clang/include/clang/Basic/SourceManager.h @@ -54,9 +54,6 @@ namespace SrcMgr { /// file. This is owned by the ContentCache object. mutable const llvm::MemoryBuffer *Buffer; - /// The line and column at which we should truncate the file. - unsigned TruncateAtLine, TruncateAtColumn; - public: /// Reference to the file entry. This reference does not own /// the FileEntry object. It is possible for this to be NULL if @@ -93,28 +90,19 @@ namespace SrcMgr { Buffer = B; } - /// \brief Truncate this file at the given line and column. - /// - /// \param Line the line on which to truncate the current file (1-based). - /// \param Column the column at which to truncate the current file. - /// (1-based). - void truncateAt(unsigned Line, unsigned Column); - - /// \brief Determines whether the file was artificially truncated with - /// truncateAt(). - bool isTruncated() const { return TruncateAtLine && TruncateAtColumn; } - + /// \brief Replace the existing buffer (which will be deleted) + /// with the given buffer. + void replaceBuffer(const llvm::MemoryBuffer *B); + ContentCache(const FileEntry *Ent = 0) - : Buffer(0), TruncateAtLine(0), TruncateAtColumn(0), Entry(Ent), - SourceLineCache(0), NumLines(0) {} + : Buffer(0), Entry(Ent), SourceLineCache(0), NumLines(0) {} ~ContentCache(); /// The copy ctor does not allow copies where source object has either /// a non-NULL Buffer or SourceLineCache. Ownership of allocated memory /// is not transfered, so this is a logical error. - ContentCache(const ContentCache &RHS) - : Buffer(0), TruncateAtLine(0), TruncateAtColumn(0), SourceLineCache(0) { + ContentCache(const ContentCache &RHS) : Buffer(0), SourceLineCache(0) { Entry = RHS.Entry; assert (RHS.Buffer == 0 && RHS.SourceLineCache == 0 @@ -344,19 +332,13 @@ class SourceManager { mutable FileID LastRFIDForBeforeTUCheck; mutable bool LastResForBeforeTUCheck; - // Keep track of the file/line/column that we should truncate. - const FileEntry *TruncateFile; - unsigned TruncateAtLine; - unsigned TruncateAtColumn; - // SourceManager doesn't support copy construction. explicit SourceManager(const SourceManager&); void operator=(const SourceManager&); public: SourceManager() - : ExternalSLocEntries(0), LineTable(0), NumLinearScans(0), - NumBinaryProbes(0), TruncateFile(0), TruncateAtLine(0), - TruncateAtColumn(0) { + : ExternalSLocEntries(0), LineTable(0), NumLinearScans(0), + NumBinaryProbes(0) { clearIDTables(); } ~SourceManager(); @@ -425,6 +407,21 @@ public: unsigned PreallocatedID = 0, unsigned Offset = 0); + /// \brief Retrieve the memory buffer associated with the given file. + const llvm::MemoryBuffer *getMemoryBufferForFile(const FileEntry *File); + + /// \brief Override the contents of the given source file by providing an + /// already-allocated buffer. + /// + /// \param SourceFile the source file whose contents will be override. + /// + /// \param Buffer the memory buffer whose contents will be used as the + /// data in the given source file. + /// + /// \returns true if an error occurred, false otherwise. + bool overrideFileContents(const FileEntry *SourceFile, + const llvm::MemoryBuffer *Buffer); + //===--------------------------------------------------------------------===// // FileID manipulation methods. //===--------------------------------------------------------------------===// @@ -668,12 +665,6 @@ public: /// \returns true if LHS source location comes before RHS, false otherwise. bool isBeforeInTranslationUnit(SourceLocation LHS, SourceLocation RHS) const; - /// \brief Truncate the given file at the specified line/column. - void truncateFileAt(const FileEntry *Entry, unsigned Line, unsigned Column); - - /// \brief Determine whether this file was truncated. - bool isTruncatedFile(FileID FID) const; - // Iterators over FileInfos. typedef llvm::DenseMap<const FileEntry*, SrcMgr::ContentCache*> ::const_iterator fileinfo_iterator; diff --git a/clang/include/clang/Lex/Lexer.h b/clang/include/clang/Lex/Lexer.h index 52bf194883d..eac197afd65 100644 --- a/clang/include/clang/Lex/Lexer.h +++ b/clang/include/clang/Lex/Lexer.h @@ -39,7 +39,6 @@ class Lexer : public PreprocessorLexer { SourceLocation FileLoc; // Location for start of file. LangOptions Features; // Features enabled by this language (cache). bool Is_PragmaLexer; // True if lexer for _Pragma handling. - bool IsEofCodeCompletion; // True if EOF is treated as a code-completion. //===--------------------------------------------------------------------===// // Context-specific lexing flags set by the preprocessor. @@ -180,15 +179,6 @@ public: ExtendedTokenMode = Mode ? 1 : 0; } - /// \brief Specify that end-of-file is to be considered a code-completion - /// token. - /// - /// When in this mode, the end-of-file token will be immediately preceded - /// by a code-completion token. - void SetEofIsCodeCompletion(bool Val = true) { - IsEofCodeCompletion = Val; - } - const char *getBufferStart() const { return BufferStart; } /// ReadToEndOfLine - Read the rest of the current preprocessor line as an diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h index c8e4a0f2097..939444167bb 100644 --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -121,6 +121,9 @@ class Preprocessor { /// with this preprocessor. std::vector<CommentHandler *> CommentHandlers; + /// \brief The file that we're performing code-completion for, if any. + const FileEntry *CodeCompletionFile; + /// CurLexer - This is the current top of the stack that we're lexing from if /// not expanding a macro and we are lexing directly from source code. /// Only one of CurLexer, CurPTHLexer, or CurTokenLexer will be non-null. @@ -485,6 +488,27 @@ public: CachedTokens[CachedLexPos-1] = Tok; } + /// \brief Specify the point at which code-completion will be performed. + /// + /// \param File the file in which code completion should occur. If + /// this file is included multiple times, code-completion will + /// perform completion the first time it is included. If NULL, this + /// function clears out the code-completion point. + /// + /// \param Line the line at which code completion should occur + /// (1-based). + /// + /// \param Column the column at which code completion should occur + /// (1-based). + /// + /// \returns true if an error occurred, false otherwise. + bool SetCodeCompletionPoint(const FileEntry *File, + unsigned Line, unsigned Column); + + /// \brief Determine if this source location refers into the file + /// for which we are performing code completion. + bool isCodeCompletionFile(SourceLocation FileLoc); + /// Diag - Forwarding function for diagnostics. This emits a diagnostic at /// the specified Token's location, translating the token's start /// position in the current buffer into a SourcePosition object for rendering. diff --git a/clang/lib/Basic/SourceManager.cpp b/clang/lib/Basic/SourceManager.cpp index c27675f38bc..8cc7a8438d2 100644 --- a/clang/lib/Basic/SourceManager.cpp +++ b/clang/lib/Basic/SourceManager.cpp @@ -41,66 +41,29 @@ unsigned ContentCache::getSizeBytesMapped() const { /// getSize - Returns the size of the content encapsulated by this ContentCache. /// This can be the size of the source file or the size of an arbitrary /// scratch buffer. If the ContentCache encapsulates a source file, that -/// file is not lazily brought in from disk to satisfy this query unless it -/// needs to be truncated due to a truncateAt() call. +/// file is not lazily brought in from disk to satisfy this query. unsigned ContentCache::getSize() const { return Buffer ? Buffer->getBufferSize() : Entry->getSize(); } +void ContentCache::replaceBuffer(const llvm::MemoryBuffer *B) { + if (B == Buffer) + return; + + delete Buffer; + Buffer = B; +} + const llvm::MemoryBuffer *ContentCache::getBuffer(std::string *ErrorStr) const { // Lazily create the Buffer for ContentCaches that wrap files. if (!Buffer && Entry) { // FIXME: Should we support a way to not have to do this check over // and over if we cannot open the file? Buffer = MemoryBuffer::getFile(Entry->getName(), ErrorStr,Entry->getSize()); - if (isTruncated()) - const_cast<ContentCache *>(this)->truncateAt(TruncateAtLine, - TruncateAtColumn); } return Buffer; } -void ContentCache::truncateAt(unsigned Line, unsigned Column) { - TruncateAtLine = Line; - TruncateAtColumn = Column; - - if (!isTruncated() || !Buffer) - return; - - // Find the byte position of the truncation point. - const char *Position = Buffer->getBufferStart(); - for (unsigned Line = 1; Line < TruncateAtLine; ++Line) { - for (; *Position; ++Position) { - if (*Position != '\r' && *Position != '\n') - continue; - - // Eat \r\n or \n\r as a single line. - if ((Position[1] == '\r' || Position[1] == '\n') && - Position[0] != Position[1]) - ++Position; - ++Position; - break; - } - } - - for (unsigned Column = 1; Column < TruncateAtColumn; ++Column, ++Position) { - if (!*Position) - break; - - if (*Position == '\t') - Column += 7; - } - - // Truncate the buffer. - if (Position != Buffer->getBufferEnd()) { - MemoryBuffer *TruncatedBuffer - = MemoryBuffer::getMemBufferCopy(Buffer->getBufferStart(), Position, - Buffer->getBufferIdentifier()); - delete Buffer; - Buffer = TruncatedBuffer; - } -} - unsigned LineTableInfo::getLineTableFilenameID(const char *Ptr, unsigned Len) { // Look up the filename in the string table, returning the pre-existing value // if it exists. @@ -332,16 +295,6 @@ SourceManager::getOrCreateContentCache(const FileEntry *FileEnt) { EntryAlign = std::max(8U, EntryAlign); Entry = ContentCacheAlloc.Allocate<ContentCache>(1, EntryAlign); new (Entry) ContentCache(FileEnt); - - if (FileEnt == TruncateFile) { - // If we had queued up a file truncation request, perform the truncation - // now. - Entry->truncateAt(TruncateAtLine, TruncateAtColumn); - TruncateFile = 0; - TruncateAtLine = 0; - TruncateAtColumn = 0; - } - return Entry; } @@ -457,6 +410,25 @@ SourceLocation SourceManager::createInstantiationLoc(SourceLocation SpellingLoc, return SourceLocation::getMacroLoc(NextOffset-(TokLength+1)); } +const llvm::MemoryBuffer * +SourceManager::getMemoryBufferForFile(const FileEntry *File) { + const SrcMgr::ContentCache *IR = getOrCreateContentCache(File); + if (IR == 0) + return 0; + + return IR->getBuffer(); +} + +bool SourceManager::overrideFileContents(const FileEntry *SourceFile, + const llvm::MemoryBuffer *Buffer) { + const SrcMgr::ContentCache *IR = getOrCreateContentCache(SourceFile); + if (IR == 0) + return true; + + const_cast<SrcMgr::ContentCache *>(IR)->replaceBuffer(Buffer); + return false; +} + /// getBufferData - Return a pointer to the start and end of the source buffer /// data for the specified FileID. std::pair<const char*, const char*> @@ -1124,28 +1096,6 @@ bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS, return LastResForBeforeTUCheck = (LOffs.first < ROffs.first); } -void SourceManager::truncateFileAt(const FileEntry *Entry, unsigned Line, - unsigned Column) { - llvm::DenseMap<const FileEntry*, SrcMgr::ContentCache*>::iterator FI - = FileInfos.find(Entry); - if (FI != FileInfos.end()) { - FI->second->truncateAt(Line, Column); - return; - } - - // We cannot perform the truncation until we actually see the file, so - // save the truncation information. - assert(TruncateFile == 0 && "Can't queue up multiple file truncations!"); - TruncateFile = Entry; - TruncateAtLine = Line; - TruncateAtColumn = Column; -} - -/// \brief Determine whether this file was truncated. -bool SourceManager::isTruncatedFile(FileID FID) const { - return getSLocEntry(FID).getFile().getContentCache()->isTruncated(); -} - /// PrintStats - Print statistics to stderr. /// void SourceManager::PrintStats() const { diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index 1083d5ef1c0..2d58beead8b 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -287,7 +287,7 @@ CompilerInstance::createCodeCompletionConsumer(Preprocessor &PP, } // Truncate the named file at the given line/column. - PP.getSourceManager().truncateFileAt(Entry, Line, Column); + PP.SetCodeCompletionPoint(Entry, Line, Column); // Set up the creation routine for code-completion. if (UseDebugPrinter) diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp index 52a7a04567a..451e1cebfff 100644 --- a/clang/lib/Lex/Lexer.cpp +++ b/clang/lib/Lex/Lexer.cpp @@ -70,7 +70,6 @@ void Lexer::InitLexer(const char *BufStart, const char *BufPtr, " to simplify lexing!"); Is_PragmaLexer = false; - IsEofCodeCompletion = false; // Start of the file is a start of line. IsAtStartOfLine = true; @@ -105,10 +104,6 @@ Lexer::Lexer(FileID FID, const llvm::MemoryBuffer *InputFile, Preprocessor &PP) // Default to keeping comments if the preprocessor wants them. SetCommentRetentionState(PP.getCommentRetentionState()); - - // If the input file is truncated, the EOF is a code-completion token. - if (PP.getSourceManager().isTruncatedFile(FID)) - IsEofCodeCompletion = true; } /// Lexer constructor - Create a new raw lexer object. This object is only @@ -1326,24 +1321,16 @@ bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) { // Otherwise, check if we are code-completing, then issue diagnostics for // unterminated #if and missing newline. - if (IsEofCodeCompletion) { - bool isIntendedFile = true; - if (PP && FileLoc.isFileID()) { - SourceManager &SM = PP->getSourceManager(); - isIntendedFile = SM.isTruncatedFile(SM.getFileID(FileLoc)); - } + if (PP && PP->isCodeCompletionFile(FileLoc)) { + // We're at the end of the file, but we've been asked to consider the + // end of the file to be a code-completion token. Return the + // code-completion token. + Result.startToken(); + FormTokenWithChars(Result, CurPtr, tok::code_completion); - if (isIntendedFile) { - // We're at the end of the file, but we've been asked to consider the - // end of the file to be a code-completion token. Return the - // code-completion token. - Result.startToken(); - FormTokenWithChars(Result, CurPtr, tok::code_completion); - - // Only do the eof -> code_completion translation once. - IsEofCodeCompletion = false; - return true; - } + // Only do the eof -> code_completion translation once. + PP->SetCodeCompletionPoint(0, 0, 0); + return true; } // If we are in a #if directive, emit an error. diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp index 066909475fe..c7578204944 100644 --- a/clang/lib/Lex/Preprocessor.cpp +++ b/clang/lib/Lex/Preprocessor.cpp @@ -50,7 +50,8 @@ Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts, bool OwnsHeaders) : Diags(&diags), Features(opts), Target(target),FileMgr(Headers.getFileMgr()), SourceMgr(SM), HeaderInfo(Headers), Identifiers(opts, IILookup), - BuiltinInfo(Target), CurPPLexer(0), CurDirLookup(0), Callbacks(0) { + BuiltinInfo(Target), CodeCompletionFile(0), CurPPLexer(0), CurDirLookup(0), + Callbacks(0) { ScratchBuf = new ScratchBuffer(SourceMgr); CounterValue = 0; // __COUNTER__ starts at 0. OwnsHeaderSearch = OwnsHeaders; @@ -188,6 +189,63 @@ void Preprocessor::PrintStats() { << NumFastTokenPaste << " on the fast path.\n"; } +bool Preprocessor::SetCodeCompletionPoint(const FileEntry *File, + unsigned TruncateAtLine, + unsigned TruncateAtColumn) { + using llvm::MemoryBuffer; + + CodeCompletionFile = File; + + // Okay to clear out the code-completion point by passing NULL. + if (!CodeCompletionFile) + return false; + + // Load the actual file's contents. + const MemoryBuffer *Buffer = SourceMgr.getMemoryBufferForFile(File); + if (!Buffer) + return true; + + // Find the byte position of the truncation point. + const char *Position = Buffer->getBufferStart(); + for (unsigned Line = 1; Line < TruncateAtLine; ++Line) { + for (; *Position; ++Position) { + if (*Position != '\r' && *Position != '\n') + continue; + + // Eat \r\n or \n\r as a single line. + if ((Position[1] == '\r' || Position[1] == '\n') && + Position[0] != Position[1]) + ++Position; + ++Position; + break; + } + } + + for (unsigned Column = 1; Column < TruncateAtColumn; ++Column, ++Position) { + if (!*Position) + break; + + if (*Position == '\t') + Column += 7; + } + + // Truncate the buffer. + if (Position != Buffer->getBufferEnd()) { + MemoryBuffer *TruncatedBuffer + = MemoryBuffer::getMemBufferCopy(Buffer->getBufferStart(), Position, + Buffer->getBufferIdentifier()); + SourceMgr.overrideFileContents(File, TruncatedBuffer); + } + + return false; +} + +bool Preprocessor::isCodeCompletionFile(SourceLocation FileLoc) { + return CodeCompletionFile && FileLoc.isFileID() && + SourceMgr.getFileEntryForID(SourceMgr.getFileID(FileLoc)) + == CodeCompletionFile; +} + //===----------------------------------------------------------------------===// // Token Spelling //===----------------------------------------------------------------------===// |