diff options
-rw-r--r-- | include/clang/Lex/CodeCompletionHandler.h | 5 | ||||
-rw-r--r-- | include/clang/Lex/Preprocessor.h | 4 | ||||
-rw-r--r-- | include/clang/Parse/Parser.h | 1 | ||||
-rw-r--r-- | include/clang/Sema/Action.h | 4 | ||||
-rw-r--r-- | include/clang/Sema/Sema.h | 1 | ||||
-rw-r--r-- | lib/Lex/Lexer.cpp | 28 | ||||
-rw-r--r-- | lib/Lex/Preprocessor.cpp | 7 | ||||
-rw-r--r-- | lib/Parse/Parser.cpp | 4 | ||||
-rw-r--r-- | lib/Sema/SemaCodeComplete.cpp | 7 | ||||
-rw-r--r-- | test/Index/complete-exprs.c | 4 | ||||
-rw-r--r-- | test/Index/complete-natural.m | 34 |
11 files changed, 89 insertions, 10 deletions
diff --git a/include/clang/Lex/CodeCompletionHandler.h b/include/clang/Lex/CodeCompletionHandler.h index bb8705b9a6..d28a3aa7d6 100644 --- a/include/clang/Lex/CodeCompletionHandler.h +++ b/include/clang/Lex/CodeCompletionHandler.h @@ -55,6 +55,11 @@ public: virtual void CodeCompleteMacroArgument(IdentifierInfo *Macro, MacroInfo *MacroInfo, unsigned ArgumentIndex) { } + + /// \brief Callback invoked when performing code completion in a part of the + /// file where we expect natural language, e.g., a comment, string, or + /// #error directive. + virtual void CodeCompleteNaturalLanguage() { } }; } diff --git a/include/clang/Lex/Preprocessor.h b/include/clang/Lex/Preprocessor.h index 543cb74226..018d1947a0 100644 --- a/include/clang/Lex/Preprocessor.h +++ b/include/clang/Lex/Preprocessor.h @@ -392,6 +392,10 @@ public: CodeComplete = 0; } + /// \brief Hook used by the lexer to invoke the "natural language" code + /// completion point. + void CodeCompleteNaturalLanguage(); + /// \brief Retrieve the preprocessing record, or NULL if there is no /// preprocessing record. PreprocessingRecord *getPreprocessingRecord() const { return Record; } diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 1f680f8854..e4dad1fba5 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -1540,6 +1540,7 @@ private: virtual void CodeCompleteMacroArgument(IdentifierInfo *Macro, MacroInfo *MacroInfo, unsigned ArgumentIndex); + virtual void CodeCompleteNaturalLanguage(); }; } // end namespace clang diff --git a/include/clang/Sema/Action.h b/include/clang/Sema/Action.h index 3b7fc2cc62..e7fb732c34 100644 --- a/include/clang/Sema/Action.h +++ b/include/clang/Sema/Action.h @@ -3244,6 +3244,10 @@ public: IdentifierInfo *Macro, MacroInfo *MacroInfo, unsigned Argument) { } + + /// \brief Callback invoked when performing code completion in a context where + /// we expect a natural language, e.g., inside a comment or string. + virtual void CodeCompleteNaturalLanguage() { } //@} }; diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 0ee864c66a..ba1122e1ee 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -4363,6 +4363,7 @@ public: IdentifierInfo *Macro, MacroInfo *MacroInfo, unsigned Argument); + virtual void CodeCompleteNaturalLanguage(); void GatherGlobalCodeCompletions( llvm::SmallVectorImpl<CodeCompletionResult> &Results); //@} diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp index 3a77bbbfba..6cd1873e28 100644 --- a/lib/Lex/Lexer.cpp +++ b/lib/Lex/Lexer.cpp @@ -27,6 +27,7 @@ #include "clang/Lex/Lexer.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/LexDiagnostic.h" +#include "clang/Lex/CodeCompletionHandler.h" #include "clang/Basic/SourceManager.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/Compiler.h" @@ -962,8 +963,9 @@ void Lexer::LexStringLiteral(Token &Result, const char *CurPtr, bool Wide) { if (C == '\n' || C == '\r' || // Newline. (C == 0 && CurPtr-1 == BufferEnd)) { // End of file. - if (!isLexingRawMode() && !Features.AsmPreprocessor && - !PP->isCodeCompletionFile(FileLoc)) + if (C == 0 && PP && PP->isCodeCompletionFile(FileLoc)) + PP->CodeCompleteNaturalLanguage(); + else if (!isLexingRawMode() && !Features.AsmPreprocessor) Diag(BufferPtr, diag::err_unterminated_string); FormTokenWithChars(Result, CurPtr-1, tok::unknown); return; @@ -1040,8 +1042,9 @@ void Lexer::LexCharConstant(Token &Result, const char *CurPtr) { C = getAndAdvanceChar(CurPtr, Result); } else if (C == '\n' || C == '\r' || // Newline. (C == 0 && CurPtr-1 == BufferEnd)) { // End of file. - if (!isLexingRawMode() && !Features.AsmPreprocessor && - !PP->isCodeCompletionFile(FileLoc)) + if (C == 0 && PP && PP->isCodeCompletionFile(FileLoc)) + PP->CodeCompleteNaturalLanguage(); + else if (!isLexingRawMode() && !Features.AsmPreprocessor) Diag(BufferPtr, diag::err_unterminated_char); FormTokenWithChars(Result, CurPtr-1, tok::unknown); return; @@ -1185,7 +1188,13 @@ bool Lexer::SkipBCPLComment(Token &Result, const char *CurPtr) { } } - if (CurPtr == BufferEnd+1) { --CurPtr; break; } + if (CurPtr == BufferEnd+1) { + if (PP && PP->isCodeCompletionFile(FileLoc)) + PP->CodeCompleteNaturalLanguage(); + + --CurPtr; + break; + } } while (C != '\n' && C != '\r'); // Found but did not consume the newline. Notify comment handlers about the @@ -1424,7 +1433,9 @@ bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr) { Diag(CurPtr-1, diag::warn_nested_block_comment); } } else if (C == 0 && CurPtr == BufferEnd+1) { - if (!isLexingRawMode() && !PP->isCodeCompletionFile(FileLoc)) + if (PP && PP->isCodeCompletionFile(FileLoc)) + PP->CodeCompleteNaturalLanguage(); + else if (!isLexingRawMode()) Diag(BufferPtr, diag::err_unterminated_block_comment); // Note: the user probably forgot a */. We could continue immediately // after the /*, but this would involve lexing a lot of what really is the @@ -1510,6 +1521,11 @@ std::string Lexer::ReadToEndOfLine() { // Next, lex the character, which should handle the EOM transition. Lex(Tmp); + if (Tmp.is(tok::code_completion)) { + if (PP && PP->getCodeCompletionHandler()) + PP->getCodeCompletionHandler()->CodeCompleteNaturalLanguage(); + Lex(Tmp); + } assert(Tmp.is(tok::eom) && "Unexpected token!"); // Finally, we're done, return the string we found. diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp index 04de68baef..a23290e952 100644 --- a/lib/Lex/Preprocessor.cpp +++ b/lib/Lex/Preprocessor.cpp @@ -284,6 +284,13 @@ bool Preprocessor::isCodeCompletionFile(SourceLocation FileLoc) const { == CodeCompletionFile; } +void Preprocessor::CodeCompleteNaturalLanguage() { + SetCodeCompletionPoint(0, 0, 0); + getDiagnostics().setSuppressAllDiagnostics(true); + if (CodeComplete) + CodeComplete->CodeCompleteNaturalLanguage(); +} + //===----------------------------------------------------------------------===// // Token Spelling //===----------------------------------------------------------------------===// diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index dd244bb895..e277c3f80e 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -1154,3 +1154,7 @@ void Parser::CodeCompleteMacroArgument(IdentifierInfo *Macro, Actions.CodeCompletePreprocessorMacroArgument(getCurScope(), Macro, MacroInfo, ArgumentIndex); } + +void Parser::CodeCompleteNaturalLanguage() { + Actions.CodeCompleteNaturalLanguage(); +} diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index ad4382e09b..3aa3e6df8c 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -4873,6 +4873,13 @@ void Sema::CodeCompletePreprocessorMacroArgument(Scope *S, : Action::PCC_Namespace); } +void Sema::CodeCompleteNaturalLanguage() { + // FIXME: Use a dedicated completion context for this! + HandleCodeCompleteResults(this, CodeCompleter, + CodeCompletionContext::CCC_Other, + 0, 0); +} + void Sema::GatherGlobalCodeCompletions( llvm::SmallVectorImpl<CodeCompletionResult> &Results) { ResultBuilder Builder(*this); diff --git a/test/Index/complete-exprs.c b/test/Index/complete-exprs.c index 170f6d549f..aed825e045 100644 --- a/test/Index/complete-exprs.c +++ b/test/Index/complete-exprs.c @@ -52,10 +52,6 @@ void f4(const char* str) { // CHECK-CC4: FunctionDecl:{ResultType int}{TypedText f}{LeftParen (}{Placeholder int}{RightParen )} (50) // CHECK-CC4: VarDecl:{ResultType struct X}{TypedText f1} (50) (deprecated) -// RUN: c-index-test -code-completion-at=%s:13:28 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC5 %s -// CHECK-CC5: NotImplemented:{TypedText void} (65) -// CHECK-CC5: NotImplemented:{TypedText volatile} (65) - // RUN: c-index-test -code-completion-at=%s:19:3 -Xclang -code-completion-patterns %s | FileCheck -check-prefix=CHECK-CC6 %s // CHECK-CC6: FunctionDecl:{ResultType void}{TypedText f3}{LeftParen (}{Placeholder char const *}{Placeholder , ...}{Text , NULL}{RightParen )} (45) // CHECK-CC6: NotImplemented:{TypedText void} (65) diff --git a/test/Index/complete-natural.m b/test/Index/complete-natural.m new file mode 100644 index 0000000000..df804e64d7 --- /dev/null +++ b/test/Index/complete-natural.m @@ -0,0 +1,34 @@ +// Note: the run lines follow their respective tests, since line/column +// matter in this test. + +const char *in_string = "string"; +char in_char = 'a'; +// in comment +/* in comment */ +#warning blarg +#error blarg +#pragma mark this is the spot +// RUN: c-index-test -code-completion-at=%s:4:32 %s > %t +// RUN: echo "DONE" >> %t +// RUN: FileCheck -check-prefix=CHECK-CC1 %s < %t +// CHECK-CC1-NOT: : +// CHECK-CC1: DONE +// RUN: c-index-test -code-completion-at=%s:5:18 %s > %t +// RUN: echo "DONE" >> %t +// RUN: FileCheck -check-prefix=CHECK-CC1 %s < %t +// RUN: c-index-test -code-completion-at=%s:6:7 %s > %t +// RUN: echo "DONE" >> %t +// RUN: FileCheck -check-prefix=CHECK-CC1 %s < %t +// RUN: c-index-test -code-completion-at=%s:7:7 %s > %t +// RUN: echo "DONE" >> %t +// RUN: FileCheck -check-prefix=CHECK-CC1 %s < %t +// RUN: c-index-test -code-completion-at=%s:8:10 %s > %t +// RUN: echo "DONE" >> %t +// RUN: FileCheck -check-prefix=CHECK-CC1 %s < %t +// RUN: c-index-test -code-completion-at=%s:9:9 %s > %t +// RUN: echo "DONE" >> %t +// RUN: FileCheck -check-prefix=CHECK-CC1 %s < %t +// RUN: c-index-test -code-completion-at=%s:10:19 %s > %t +// RUN: echo "DONE" >> %t +// RUN: FileCheck -check-prefix=CHECK-CC1 %s < %t + |