]> granicus.if.org Git - clang/commitdiff
Introduce a preprocessor code-completion hook for contexts where we
authorDouglas Gregor <dgregor@apple.com>
Wed, 25 Aug 2010 17:04:25 +0000 (17:04 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 25 Aug 2010 17:04:25 +0000 (17:04 +0000)
expect "natural" language and should not provide any completions,
e.g., comments, string literals, #error.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@112054 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Lex/CodeCompletionHandler.h
include/clang/Lex/Preprocessor.h
include/clang/Parse/Parser.h
include/clang/Sema/Action.h
include/clang/Sema/Sema.h
lib/Lex/Lexer.cpp
lib/Lex/Preprocessor.cpp
lib/Parse/Parser.cpp
lib/Sema/SemaCodeComplete.cpp
test/Index/complete-exprs.c
test/Index/complete-natural.m [new file with mode: 0644]

index bb8705b9a63dd5f6fd4db7a4fb43f293531a3547..d28a3aa7d6309d1e108c10503f73ead18501e8fe 100644 (file)
@@ -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() { }
 };
   
 }
index 543cb742262a26124086d1d0dac656336c60bfec..018d1947a049b76e26c7a59188cbd5d29bbf43f3 100644 (file)
@@ -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; }
index 1f680f8854f93ad1811ac34a163201435bf4aabc..e4dad1fba545266bd9b24b161db82a03361a815e 100644 (file)
@@ -1540,6 +1540,7 @@ private:
   virtual void CodeCompleteMacroArgument(IdentifierInfo *Macro,
                                          MacroInfo *MacroInfo,
                                          unsigned ArgumentIndex);
+  virtual void CodeCompleteNaturalLanguage();
 };
 
 }  // end namespace clang
index 3b7fc2cc6239d247c3debe6af6911a56a45cfe54..e7fb732c34296216abfa54b1b3a591002e8b0249 100644 (file)
@@ -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() { }
   //@}
 };
 
index 0ee864c66a784f18323ebc3351044c4ec67db8fe..ba1122e1eee8c9393e0e188a1cf5c27d82ab8d18 100644 (file)
@@ -4363,6 +4363,7 @@ public:
                                                      IdentifierInfo *Macro,
                                                      MacroInfo *MacroInfo,
                                                      unsigned Argument);
+  virtual void CodeCompleteNaturalLanguage();
   void GatherGlobalCodeCompletions(
                   llvm::SmallVectorImpl<CodeCompletionResult> &Results);
   //@}
index 3a77bbbfba71ad51c6d202d46fea7c55297d6e2e..6cd1873e2890ce7301ab4fd93e9db76644e2efa0 100644 (file)
@@ -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.
index 04de68baef9f9ae331c23df7cf68b359854ef8b7..a23290e952e39c58d7ca282791a8f5eb1c08941e 100644 (file)
@@ -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
 //===----------------------------------------------------------------------===//
index dd244bb895a2109a947af858a34f7377bbd4d05f..e277c3f80e14d69cc5dbc5938c419f4b8066efe9 100644 (file)
@@ -1154,3 +1154,7 @@ void Parser::CodeCompleteMacroArgument(IdentifierInfo *Macro,
   Actions.CodeCompletePreprocessorMacroArgument(getCurScope(), Macro, MacroInfo, 
                                                 ArgumentIndex);
 }
+
+void Parser::CodeCompleteNaturalLanguage() {
+  Actions.CodeCompleteNaturalLanguage();
+}
index ad4382e09b384a2498e9e2e1cae896894d931c48..3aa3e6df8cf25029e40f9b5bf4616587c60cfcdc 100644 (file)
@@ -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);
index 170f6d549fa6b01f610fe1d598ec43d4153c2eaf..aed825e045509db0ffd2919841ae78c7b5138f79 100644 (file)
@@ -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 (file)
index 0000000..df804e6
--- /dev/null
@@ -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
+