diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-09-22 21:11:38 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-09-22 21:11:38 +0000 |
commit | ea9b03e6e23408325145ca089e4d7d6386b65a2d (patch) | |
tree | a43f3c51bb90111c9d4a879c5efd9d7bf78755e5 /clang/lib | |
parent | 320a1c40831272686dca85e03e603b65345eb95c (diff) | |
download | bcm5719-llvm-ea9b03e6e23408325145ca089e4d7d6386b65a2d.tar.gz bcm5719-llvm-ea9b03e6e23408325145ca089e4d7d6386b65a2d.zip |
Replace the -code-completion-dump option with
-code-completion-at=filename:line:column
which performs code completion at the specified location by truncating
the file at that position and enabling code completion. This approach
makes it possible to run multiple tests from a single test file, and
gives a more natural command-line interface.
llvm-svn: 82571
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Basic/SourceManager.cpp | 81 | ||||
-rw-r--r-- | clang/lib/Lex/Lexer.cpp | 30 | ||||
-rw-r--r-- | clang/lib/Lex/Preprocessor.cpp | 8 |
3 files changed, 100 insertions, 19 deletions
diff --git a/clang/lib/Basic/SourceManager.cpp b/clang/lib/Basic/SourceManager.cpp index d1c47095a24..962cb4c42a8 100644 --- a/clang/lib/Basic/SourceManager.cpp +++ b/clang/lib/Basic/SourceManager.cpp @@ -41,9 +41,10 @@ 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. +/// file is not lazily brought in from disk to satisfy this query unless it +/// needs to be truncated due to a truncateAt() call. unsigned ContentCache::getSize() const { - return Entry ? Entry->getSize() : Buffer->getBufferSize(); + return Buffer ? Buffer->getBufferSize() : Entry->getSize(); } const llvm::MemoryBuffer *ContentCache::getBuffer() const { @@ -52,10 +53,54 @@ const llvm::MemoryBuffer *ContentCache::getBuffer() const { // 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(), 0, 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. @@ -287,6 +332,16 @@ 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; } @@ -1058,6 +1113,28 @@ bool SourceManager::isBeforeInTranslationUnit(SourceLocation LHS, } } +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/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp index 74ac55cf2eb..0f01155a8f2 100644 --- a/clang/lib/Lex/Lexer.cpp +++ b/clang/lib/Lex/Lexer.cpp @@ -101,12 +101,16 @@ Lexer::Lexer(FileID FID, Preprocessor &PP) Features(PP.getLangOptions()) { const llvm::MemoryBuffer *InputFile = PP.getSourceManager().getBuffer(FID); - + InitLexer(InputFile->getBufferStart(), InputFile->getBufferStart(), InputFile->getBufferEnd()); // 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 @@ -1323,15 +1327,23 @@ bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) { // unterminated #if and missing newline. if (IsEofCodeCompletion) { - // We're at the end of the file, but we've been asked to conside the - // end of the file to be a code-completion token. Return the - // code-completion token. - Result.startToken(); - FormTokenWithChars(Result, CurPtr, tok::code_completion); + bool isIntendedFile = true; + if (PP && FileLoc.isFileID()) { + SourceManager &SM = PP->getSourceManager(); + isIntendedFile = SM.isTruncatedFile(SM.getFileID(FileLoc)); + } - // Only do the eof -> code_completion translation once. - IsEofCodeCompletion = false; - return true; + 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; + } } // 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 4e522cbb8a4..bfa090a09e8 100644 --- a/clang/lib/Lex/Preprocessor.cpp +++ b/clang/lib/Lex/Preprocessor.cpp @@ -71,7 +71,6 @@ Preprocessor::Preprocessor(Diagnostic &diags, const LangOptions &opts, // Macro expansion is enabled. DisableMacroExpansion = false; InMacroArgs = false; - IsMainFileEofCodeCompletion = false; NumCachedTokenLexers = 0; CachedLexPos = 0; @@ -369,13 +368,6 @@ void Preprocessor::EnterMainSourceFile() { // Enter the main file source buffer. EnterSourceFile(MainFileID, 0); - if (IsMainFileEofCodeCompletion) { - // Tell our newly-created lexer that it should treat its end-of-file as - // a code-completion token. - IsMainFileEofCodeCompletion = false; - static_cast<Lexer *>(getCurrentFileLexer())->SetEofIsCodeCompletion(); - } - // Tell the header info that the main file was entered. If the file is later // #imported, it won't be re-entered. if (const FileEntry *FE = SourceMgr.getFileEntryForID(MainFileID)) |