forked from OSchip/llvm-project
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
This commit is contained in:
parent
320a1c4083
commit
ea9b03e6e2
|
@ -17,6 +17,8 @@ def err_fe_error_reading_stdin : Error<"error reading stdin">;
|
|||
def err_fe_error_backend : Error<"error in backend: %0">, DefaultFatal;
|
||||
def err_fe_invalid_ast_file : Error<"invalid AST file: '%0'">, DefaultFatal;
|
||||
def err_fe_invalid_ast_action : Error<"invalid action for AST input">, DefaultFatal;
|
||||
def err_fe_invalid_code_complete_file
|
||||
: Error<"cannot locate code-completion file %0">, DefaultFatal;
|
||||
|
||||
def note_fixit_applied : Note<"FIX-IT applied suggested code changes">;
|
||||
def note_fixit_in_macro : Note<
|
||||
|
|
|
@ -54,6 +54,9 @@ 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,15 +96,28 @@ 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; }
|
||||
|
||||
ContentCache(const FileEntry *Ent = 0)
|
||||
: Buffer(0), Entry(Ent), SourceLineCache(0), NumLines(0) {}
|
||||
: Buffer(0), TruncateAtLine(0), TruncateAtColumn(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), SourceLineCache(0) {
|
||||
ContentCache(const ContentCache &RHS)
|
||||
: Buffer(0), TruncateAtLine(0), TruncateAtColumn(0), SourceLineCache(0) {
|
||||
Entry = RHS.Entry;
|
||||
|
||||
assert (RHS.Buffer == 0 && RHS.SourceLineCache == 0
|
||||
|
@ -331,13 +347,19 @@ 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) {
|
||||
NumBinaryProbes(0), TruncateFile(0), TruncateAtLine(0),
|
||||
TruncateAtColumn(0) {
|
||||
clearIDTables();
|
||||
}
|
||||
~SourceManager();
|
||||
|
@ -647,6 +669,12 @@ 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;
|
||||
|
|
|
@ -92,10 +92,6 @@ class Preprocessor {
|
|||
bool DisableMacroExpansion : 1; // True if macro expansion is disabled.
|
||||
bool InMacroArgs : 1; // True if parsing fn macro invocation args.
|
||||
|
||||
/// \brief True if the end-of-file of the main file should be treated as
|
||||
/// a code-completion token.
|
||||
bool IsMainFileEofCodeCompletion : 1;
|
||||
|
||||
/// Identifiers - This is mapping/lookup information for all identifiers in
|
||||
/// the program, including program keywords.
|
||||
IdentifierTable Identifiers;
|
||||
|
@ -263,12 +259,6 @@ public:
|
|||
Callbacks = C;
|
||||
}
|
||||
|
||||
/// \brief Note that, for the main source file, the end-of-file should be
|
||||
/// treated as a code-completion token.
|
||||
void SetMainFileEofCodeCompletion() {
|
||||
IsMainFileEofCodeCompletion = true;
|
||||
}
|
||||
|
||||
/// getMacroInfo - Given an identifier, return the MacroInfo it is #defined to
|
||||
/// or null if it isn't #define'd.
|
||||
MacroInfo *getMacroInfo(IdentifierInfo *II) const {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -107,6 +107,10 @@ Lexer::Lexer(FileID FID, 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
|
||||
|
@ -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.
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// RUN: clang-cc -fsyntax-only -code-completion-dump=1 %s -o - | FileCheck -check-prefix=CC1 %s &&
|
||||
// RUN: true
|
||||
// Note: the run lines follow their respective tests, since line/column
|
||||
// matter in this test.
|
||||
void f(float x, float y);
|
||||
void f(int i, int j, int k);
|
||||
struct X { };
|
||||
|
@ -10,13 +10,20 @@ namespace N {
|
|||
|
||||
operator int() const;
|
||||
};
|
||||
void f(Y y);
|
||||
void f(Y y, int);
|
||||
}
|
||||
typedef N::Y Y;
|
||||
void f();
|
||||
|
||||
void test() {
|
||||
// CHECK-CC1: f : 0 : f(<#struct N::Y y#>)
|
||||
f(Y(), 0, 0);
|
||||
// RUN: clang-cc -fsyntax-only -code-completion-at=%s:19:9 %s -o - | FileCheck -check-prefix=CC1 %s &&
|
||||
// CHECK-CC1: f : 0 : f(<#struct N::Y y#>, <#int#>)
|
||||
// CHECK-NEXT-CC1: f : 0 : f(<#int i#>, <#int j#>, <#int k#>)
|
||||
// CHECK-NEXT-CC1: f : 0 : f(<#float x#>, <#float y#>)
|
||||
f(Y(),
|
||||
// RUN: clang-cc -fsyntax-only -code-completion-at=%s:19:13 %s -o - | FileCheck -check-prefix=CC2 %s &&
|
||||
// CHECK-NOT-CC2: f : 0 : f(<#struct N::Y y#>, <#int#>)
|
||||
// CHECK-CC2: f : 0 : f(<#int i#>, <#int j#>, <#int k#>)
|
||||
// CHECK-NEXT-CC2: f : 0 : f(<#float x#>, <#float y#>)
|
||||
// RUN: true
|
||||
}
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
// RUN: clang-cc -fsyntax-only -code-completion-dump=1 %s -o - | FileCheck -check-prefix=CC1 %s &&
|
||||
// RUN: true
|
||||
|
||||
namespace M {
|
||||
|
||||
namespace N {
|
||||
|
@ -23,11 +20,14 @@ namespace M {
|
|||
|
||||
void test(enum N::C::Color color) {
|
||||
switch (color) {
|
||||
// CHECK-NEXT-CC1: Blue : 0 : N::C::Blue
|
||||
// CHECK-NEXT-CC1: Green : 0 : N::C::Green
|
||||
// CHECK-NEXT-CC1: Indigo : 0 : N::C::Indigo
|
||||
// CHECK-NEXT-CC1: Orange : 0 : N::C::Orange
|
||||
// CHECK-NEXT-CC1: Red : 0 : N::C::Red
|
||||
// CHECK-NEXT-CC1: Violet : 0 : N::C::Violet
|
||||
// CHECK-NEXT-CC1: Yellow : 0 : N::C::Yellow
|
||||
case
|
||||
case
|
||||
// RUN: clang-cc -fsyntax-only -code-completion-at=%s:23:8 %s -o - | FileCheck -check-prefix=CC1 %s &&
|
||||
// RUN: true
|
||||
// CHECK-NEXT-CC1: Blue : 0 : N::C::Blue
|
||||
// CHECK-NEXT-CC1: Green : 0 : N::C::Green
|
||||
// CHECK-NEXT-CC1: Indigo : 0 : N::C::Indigo
|
||||
// CHECK-NEXT-CC1: Orange : 0 : N::C::Orange
|
||||
// CHECK-NEXT-CC1: Red : 0 : N::C::Red
|
||||
// CHECK-NEXT-CC1: Violet : 0 : N::C::Violet
|
||||
// CHECK-NEXT-CC1: Yellow : 0 : N::C::Yellow
|
||||
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
// RUN: clang-cc -fsyntax-only -code-completion-dump=1 %s -o - | FileCheck -check-prefix=CC1 %s &&
|
||||
// RUN: true
|
||||
|
||||
enum Color {
|
||||
Red,
|
||||
Orange,
|
||||
|
@ -19,9 +16,14 @@ void test(enum Color color) {
|
|||
case Yellow:
|
||||
break;
|
||||
|
||||
case Green:
|
||||
break;
|
||||
|
||||
// RUN: clang-cc -fsyntax-only -code-completion-at=%s:19:10 %s -o - | FileCheck -check-prefix=CC1 %s &&
|
||||
// CHECK-CC1: Blue : 0
|
||||
// CHECK-NEXT-CC1: Green : 0
|
||||
// CHECK-NEXT-CC1: Indigo : 0
|
||||
// CHECK-NEXT-CC1: Orange : 0
|
||||
// CHECK-NEXT-CC1: Violet : 0
|
||||
case
|
||||
// RUN: true
|
||||
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
// RUN: clang-cc -fsyntax-only -code-completion-dump=1 %s -o - | FileCheck -check-prefix=CC1 %s &&
|
||||
// RUN: true
|
||||
|
||||
namespace N {
|
||||
enum Color {
|
||||
Red,
|
||||
|
@ -15,15 +12,18 @@ namespace N {
|
|||
|
||||
void test(enum N::Color color) {
|
||||
switch (color) {
|
||||
case N::Red:
|
||||
break;
|
||||
case N::Red:
|
||||
break;
|
||||
|
||||
case N::Yellow:
|
||||
break;
|
||||
case N::Yellow:
|
||||
break;
|
||||
|
||||
// CHECK-CC1: Blue : 0 : N::Blue
|
||||
// CHECK-NEXT-CC1: Green : 0 : N::Green
|
||||
// CHECK-NEXT-CC1: Indigo : 0 : N::Indigo
|
||||
// CHECK-NEXT-CC1: Orange : 0 : N::Orange
|
||||
// CHECK-NEXT-CC1: Violet : 0 : N::Violet
|
||||
case
|
||||
case
|
||||
// RUN: clang-cc -fsyntax-only -code-completion-at=%s:21:8 %s -o - | FileCheck -check-prefix=CC1 %s &&
|
||||
// CHECK-CC1: Blue : 0 : N::Blue
|
||||
// CHECK-NEXT-CC1: Green : 0 : N::Green
|
||||
// CHECK-NEXT-CC1: Indigo : 0 : N::Indigo
|
||||
// CHECK-NEXT-CC1: Orange : 0 : N::Orange
|
||||
// CHECK-NEXT-CC1: Violet : 0 : N::Violet
|
||||
|
||||
// RUN: true
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
// RUN: clang-cc -fsyntax-only -code-completion-dump=1 %s -o - | FileCheck -check-prefix=CC1 %s &&
|
||||
// RUN: true
|
||||
|
||||
namespace std {
|
||||
template<typename RandomAccessIterator>
|
||||
void sort(RandomAccessIterator first, RandomAccessIterator last);
|
||||
|
@ -10,7 +7,9 @@ namespace std {
|
|||
}
|
||||
|
||||
void f() {
|
||||
std::
|
||||
// RUN: clang-cc -fsyntax-only -code-completion-at=%s:10:8 %s -o - | FileCheck -check-prefix=CC1 %s &&
|
||||
// CHECK-CC1: dyn_cast<<#class X#>>(<#Y *Val#>)
|
||||
// CHECK-CC1: sort(<#RandomAccessIterator first#>, <#RandomAccessIterator last#>)
|
||||
std::
|
||||
// RUN: true
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
// RUN: clang-cc -fsyntax-only -code-completion-dump=1 %s -o - | FileCheck -check-prefix=CC1 %s &&
|
||||
// RUN: true
|
||||
void f(int i, int j = 2, int k = 5);
|
||||
void f(float x, float y);
|
||||
|
||||
void test() {
|
||||
::
|
||||
// RUN: clang-cc -fsyntax-only -code-completion-at=%s:5:5 %s -o - | FileCheck -check-prefix=CC1 %s &&
|
||||
// CHECK-CC1: f(<#int i#>{#, <#int j#>{#, <#int k#>#}#})
|
||||
// CHECK-CC1: f(<#float x#>, <#float y#>)
|
||||
::
|
||||
// RUN: true
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// RUN: clang-cc -fsyntax-only -code-completion-dump=1 %s -o - | FileCheck -check-prefix=CC1 %s &&
|
||||
// RUN: true
|
||||
struct Point {
|
||||
float x;
|
||||
float y;
|
||||
|
@ -7,7 +5,9 @@ struct Point {
|
|||
};
|
||||
|
||||
void test(struct Point *p) {
|
||||
p->
|
||||
// RUN: clang-cc -fsyntax-only -code-completion-at=%s:8:6 %s -o - | FileCheck -check-prefix=CC1 %s &&
|
||||
// CHECK-CC1: x
|
||||
// CHECK-CC1: y
|
||||
// CHECK-CC1: z
|
||||
p->
|
||||
// RUN: true
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
// RUN: clang-cc -fsyntax-only -code-completion-dump=1 %s -o - | FileCheck -check-prefix=CC1 %s &&
|
||||
// RUN: true
|
||||
|
||||
struct Base1 {
|
||||
int member1;
|
||||
float member2;
|
||||
|
@ -29,6 +26,8 @@ public:
|
|||
};
|
||||
|
||||
void test(const Proxy &p) {
|
||||
p->
|
||||
// RUN: clang-cc -fsyntax-only -code-completion-at=%s:29:6 %s -o - | FileCheck -check-prefix=CC1 %s &&
|
||||
// CHECK-CC1: member4 : 0
|
||||
// CHECK-CC1: memfun3 : 0
|
||||
// CHECK-CC1: memfun1 : 1
|
||||
|
@ -39,4 +38,5 @@ void test(const Proxy &p) {
|
|||
// CHECK-CC1: member2 : 2
|
||||
// CHECK-CC1: member3 : 2
|
||||
// CHECK-CC1: memfun1 : 2 (Hidden) : Base2::memfun1(<#int#>)
|
||||
p->
|
||||
// RUN: true
|
||||
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
// RUN: clang-cc -fsyntax-only -code-completion-dump=1 %s -o - | FileCheck -check-prefix=CC1 %s &&
|
||||
// RUN: true
|
||||
|
||||
namespace N4 {
|
||||
namespace N3 { }
|
||||
}
|
||||
|
@ -13,10 +10,12 @@ namespace N2 {
|
|||
namespace I5 { }
|
||||
namespace I1 { }
|
||||
|
||||
namespace New =
|
||||
// RUN: clang-cc -fsyntax-only -code-completion-at=%s:13:18 %s -o - | FileCheck -check-prefix=CC1 %s &&
|
||||
// CHECK-CC1: I1 : 1
|
||||
// CHECK-CC1: I4 : 1
|
||||
// CHECK-CC1: I5 : 1
|
||||
// CHECK-CC1: N2 : 2
|
||||
// CHECK-NEXT-CC1: N4 : 2
|
||||
namespace New =
|
||||
// RUN: true
|
||||
|
|
@ -1,6 +1,3 @@
|
|||
// RUN: clang-cc -fsyntax-only -code-completion-dump=1 %s -o - | FileCheck -check-prefix=CC1 %s &&
|
||||
// RUN: true
|
||||
|
||||
namespace N3 {
|
||||
}
|
||||
|
||||
|
@ -10,6 +7,9 @@ namespace N2 {
|
|||
namespace I5 { }
|
||||
namespace I1 { }
|
||||
|
||||
namespace
|
||||
// RUN: clang-cc -fsyntax-only -code-completion-at=%s:10:12 %s -o - | FileCheck -check-prefix=CC1 %s &&
|
||||
// CHECK-CC1: I1 : 0
|
||||
// CHECK-NEXT-CC1: I5 : 0
|
||||
namespace
|
||||
// RUN: true
|
||||
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
// RUN: clang-cc -fsyntax-only -code-completion-dump=1 %s -o - | FileCheck -check-prefix=CC1 %s &&
|
||||
// RUN: true
|
||||
|
||||
namespace N {
|
||||
struct A { };
|
||||
namespace M {
|
||||
|
@ -12,7 +9,10 @@ namespace N {
|
|||
struct B { };
|
||||
}
|
||||
|
||||
N::
|
||||
// RUN: clang-cc -fsyntax-only -code-completion-at=%s:12:4 %s -o - | FileCheck -check-prefix=CC1 %s &&
|
||||
// CHECK-CC1: A : 0
|
||||
// CHECK-CC1: B : 0
|
||||
// CHECK-CC1: M : 0
|
||||
N::
|
||||
// RUN: true
|
||||
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
// RUN: clang-cc -fsyntax-only -code-completion-dump=1 %s -o - | FileCheck -check-prefix=CC1 %s &&
|
||||
// RUN: true
|
||||
|
||||
class T { };
|
||||
|
||||
typedef int Integer;
|
||||
|
@ -10,10 +7,12 @@ namespace N { }
|
|||
void f() {
|
||||
typedef float Float;
|
||||
|
||||
operator
|
||||
// RUN: clang-cc -fsyntax-only -code-completion-at=%s:10:11 %s -o - | FileCheck -check-prefix=CC1 %s &&
|
||||
// CHECK-CC1: Float : 0
|
||||
// CHECK-CC1: + : 0
|
||||
// CHECK-CC1: short : 0
|
||||
// CHECK-CC1: Integer : 2
|
||||
// CHECK-CC1: T : 2
|
||||
// CHECK-CC1: N : 5
|
||||
operator
|
||||
// RUN: true
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
// RUN: clang-cc -fsyntax-only -code-completion-dump=1 %s -o - | FileCheck -check-prefix=CC1 %s &&
|
||||
// RUN: true
|
||||
|
||||
struct X { int x; };
|
||||
|
||||
typedef struct X TYPEDEF;
|
||||
|
@ -10,3 +7,5 @@ void foo() {
|
|||
// CHECK-CC1: y : 0
|
||||
// CHECK-NEXT-CC1: TYPEDEF : 2
|
||||
// CHECK-NEXT-CC1: foo : 2
|
||||
// RUN: clang-cc -fsyntax-only -code-completion-at=%s:6:9 %s -o - | FileCheck -check-prefix=CC1 %s &&
|
||||
// RUN: true
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
// RUN: clang-cc -fsyntax-only -code-completion-dump=1 %s -o - | FileCheck -check-prefix=CC1 %s &&
|
||||
// RUN: true
|
||||
|
||||
enum X { x };
|
||||
enum Y { y };
|
||||
struct Z { };
|
||||
|
@ -9,6 +6,8 @@ void X();
|
|||
|
||||
void test() {
|
||||
enum X { x };
|
||||
enum
|
||||
// RUN: clang-cc -fsyntax-only -code-completion-at=%s:9:7 %s -o - | FileCheck -check-prefix=CC1 %s &&
|
||||
// CHECK-CC1: X : 0
|
||||
// CHECK-CC1: Y : 2
|
||||
enum
|
||||
// RUN: true
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
// RUN: clang-cc -fsyntax-only -code-completion-dump=1 %s -o - | FileCheck -check-prefix=CC1 %s &&
|
||||
// RUN: true
|
||||
|
||||
class X { };
|
||||
struct Y { };
|
||||
|
||||
|
@ -17,6 +14,8 @@ namespace N {
|
|||
class Y;
|
||||
|
||||
void test() {
|
||||
class
|
||||
// RUN: clang-cc -fsyntax-only -code-completion-at=%s:17:10 %s -o - | FileCheck -check-prefix=CC1 %s &&
|
||||
// CHECK-CC1: Y : 2
|
||||
// CHECK-CC1: Z : 2
|
||||
// CHECK-CC1: A : 3
|
||||
|
@ -24,4 +23,4 @@ namespace N {
|
|||
// CHECK-CC1: Y : 3
|
||||
// CHECK-CC1: M : 6
|
||||
// CHECK-CC1: N : 6
|
||||
class
|
||||
// RUN: true
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
// RUN: clang-cc -fsyntax-only -code-completion-dump=1 %s -o - | FileCheck -check-prefix=CC1 %s &&
|
||||
// RUN: true
|
||||
|
||||
namespace std {
|
||||
template<typename T>
|
||||
class allocator;
|
||||
|
@ -10,8 +7,11 @@ namespace std {
|
|||
}
|
||||
|
||||
void f() {
|
||||
std::
|
||||
// RUN: clang-cc -fsyntax-only -code-completion-at=%s:10:8 %s -o - | FileCheck -check-prefix=CC1 %s &&
|
||||
// CHECK-CC1: allocator<<#typename T#>>
|
||||
// CHECK-CC1: vector<<#typename T#>{#, <#typename Alloc#>#}>
|
||||
std::
|
||||
// RUN: true
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
#include "truncation.c.h"
|
||||
|
||||
struct
|
||||
|
||||
// RUN: clang-cc -fsyntax-only -code-completion-at=%s.h:4:8 -o - %s | FileCheck -check-prefix=CC1 %s &&
|
||||
// CHECK-CC1: X : 1
|
||||
// CHECK-NEXT-CC1: Y : 1
|
||||
// RUN: clang-cc -fsyntax-only -code-completion-at=%s:3:8 -o - %s | FileCheck -check-prefix=CC2 %s &&
|
||||
// CHECK-CC2: X : 1
|
||||
// CHECK-CC2: Xa : 1
|
||||
// CHECK-CC2: Y : 1
|
||||
// RUN: true
|
|
@ -0,0 +1,5 @@
|
|||
struct X { };
|
||||
struct Y { };
|
||||
|
||||
struct Xa { };
|
||||
|
|
@ -1,6 +1,3 @@
|
|||
// RUN: clang-cc -fsyntax-only -code-completion-dump=1 %s -o - | FileCheck -check-prefix=CC1 %s &&
|
||||
// RUN: true
|
||||
|
||||
namespace N4 {
|
||||
namespace N3 { }
|
||||
}
|
||||
|
@ -14,11 +11,11 @@ namespace N2 {
|
|||
namespace I1 { }
|
||||
|
||||
void foo() {
|
||||
using namespace
|
||||
// RUN: clang-cc -fsyntax-only -code-completion-at=%s:14:20 %s -o - | FileCheck -check-prefix=CC1 %s &&
|
||||
// CHECK-CC1: I1 : 2
|
||||
// CHECK-CC1: I4 : 2
|
||||
// CHECK-CC1: I5 : 2
|
||||
// CHECK-CC1: N2 : 3
|
||||
// CHECK-NEXT-CC1: N4 : 3
|
||||
using namespace
|
||||
|
||||
|
||||
// RUN: true
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
// RUN: clang-cc -fsyntax-only -code-completion-dump=1 %s -o - | FileCheck -check-prefix=CC1 %s &&
|
||||
// RUN: true
|
||||
|
||||
namespace N4 {
|
||||
namespace N3 { }
|
||||
}
|
||||
|
@ -16,12 +13,13 @@ namespace N2 {
|
|||
void foo() {
|
||||
int N3;
|
||||
|
||||
using
|
||||
// RUN: clang-cc -fsyntax-only -code-completion-at=%s:16:10 %s -o - | FileCheck -check-prefix=CC1 %s &&
|
||||
// CHECK-CC1: I1 : 2
|
||||
// CHECK-CC1: I4 : 2
|
||||
// CHECK-CC1: I5 : 2
|
||||
// CHECK-CC1: N2 : 3
|
||||
// CHECK-CC1: N3 : 3
|
||||
// CHECK-NEXT-CC1: N4 : 3
|
||||
using
|
||||
|
||||
// RUN: true
|
||||
|
||||
|
|
|
@ -214,10 +214,10 @@ OutputFile("o",
|
|||
llvm::cl::desc("Specify output file"));
|
||||
|
||||
|
||||
static llvm::cl::opt<int>
|
||||
DumpCodeCompletion("code-completion-dump",
|
||||
llvm::cl::value_desc("N"),
|
||||
llvm::cl::desc("Dump code-completion information at $$N$$"));
|
||||
static llvm::cl::opt<ParsedSourceLocation>
|
||||
CodeCompletionAt("code-completion-at",
|
||||
llvm::cl::value_desc("file:line:column"),
|
||||
llvm::cl::desc("Dump code-completion information at a location"));
|
||||
|
||||
/// \brief Buld a new code-completion consumer that prints the results of
|
||||
/// code completion to standard output.
|
||||
|
@ -2057,17 +2057,22 @@ static void ProcessInputFile(Preprocessor &PP, PreprocessorFactory &PPF,
|
|||
CodeCompleteConsumer *(*CreateCodeCompleter)(Sema &, void *) = 0;
|
||||
void *CreateCodeCompleterData = 0;
|
||||
|
||||
if (DumpCodeCompletion) {
|
||||
// To dump code-completion information, we chop off the file at the
|
||||
// location of the string $$N$$, where N is the value provided to
|
||||
// -code-completion-dump, and then tell the lexer to return a
|
||||
// code-completion token before it hits the end of the file.
|
||||
// FIXME: Find $$N$$ in the main file buffer
|
||||
if (!CodeCompletionAt.FileName.empty()) {
|
||||
// Tell the source manager to chop off the given file at a specific
|
||||
// line and column.
|
||||
if (const FileEntry *Entry
|
||||
= PP.getFileManager().getFile(CodeCompletionAt.FileName)) {
|
||||
// Truncate the named file at the given line/column.
|
||||
PP.getSourceManager().truncateFileAt(Entry, CodeCompletionAt.Line,
|
||||
CodeCompletionAt.Column);
|
||||
|
||||
PP.SetMainFileEofCodeCompletion();
|
||||
|
||||
// Set up the creation routine for code-completion.
|
||||
CreateCodeCompleter = BuildPrintingCodeCompleter;
|
||||
// Set up the creation routine for code-completion.
|
||||
CreateCodeCompleter = BuildPrintingCodeCompleter;
|
||||
} else {
|
||||
PP.getDiagnostics().Report(FullSourceLoc(),
|
||||
diag::err_fe_invalid_code_complete_file)
|
||||
<< CodeCompletionAt.FileName;
|
||||
}
|
||||
}
|
||||
|
||||
ParseAST(PP, Consumer.get(), *ContextOwner.get(), Stats,
|
||||
|
|
Loading…
Reference in New Issue