[cfe-commits] r82293 - in /cfe/trunk: include/clang/Sema/CodeCompleteConsumer.h lib/Sema/CodeCompleteConsumer.cpp test/CodeCompletion/functions.cpp

Douglas Gregor dgregor at apple.com
Fri Sep 18 15:15:54 PDT 2009


Author: dgregor
Date: Fri Sep 18 17:15:54 2009
New Revision: 82293

URL: http://llvm.org/viewvc/llvm-project?rev=82293&view=rev
Log:
Introduce code completion strings, which describe how to *use* the
results of code completion, e.g., by providing function call syntax
with placeholders for each of the parameters.


Added:
    cfe/trunk/test/CodeCompletion/functions.cpp   (with props)
Modified:
    cfe/trunk/include/clang/Sema/CodeCompleteConsumer.h
    cfe/trunk/lib/Sema/CodeCompleteConsumer.cpp

Modified: cfe/trunk/include/clang/Sema/CodeCompleteConsumer.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/CodeCompleteConsumer.h?rev=82293&r1=82292&r2=82293&view=diff

==============================================================================
--- cfe/trunk/include/clang/Sema/CodeCompleteConsumer.h (original)
+++ cfe/trunk/include/clang/Sema/CodeCompleteConsumer.h Fri Sep 18 17:15:54 2009
@@ -16,8 +16,11 @@
 #include "clang/AST/DeclarationName.h"
 #include "clang/AST/Type.h"
 #include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallVector.h"
 #include <list>
 #include <map>
+#include <memory>
+#include <string>
 #include <vector>
 
 namespace llvm {
@@ -31,6 +34,103 @@
 class NamedDecl;
 class Scope;
 class Sema;
+
+/// \brief A "string" used to describe how code completion can
+/// be performed for an entity.
+///
+/// A code completion string typically shows how a particular entity can be 
+/// used. For example, the code completion string for a function would show
+/// the syntax to call it, including the parentheses, placeholders for the 
+/// arguments, etc.  
+class CodeCompletionString {
+public:
+  /// \brief The different kinds of "chunks" that can occur within a code
+  /// completion string.
+  enum ChunkKind {
+    /// \brief A piece of text that should be placed in the buffer, e.g.,
+    /// parentheses or a comma in a function call.
+    CK_Text,
+    /// \brief A code completion string that is entirely optional. For example,
+    /// an optional code completion string that describes the default arguments
+    /// in a function call.
+    CK_Optional,
+    /// \brief A string that acts as a placeholder for, e.g., a function 
+    /// call argument.
+    CK_Placeholder
+  };
+  
+  /// \brief One piece of the code completion string.
+  struct Chunk {
+    /// \brief The kind of data stored in this piece of the code completion 
+    /// string.
+    ChunkKind Kind;
+    
+    union {
+      /// \brief The text string associated with a CK_Text chunk.
+      /// The string is owned by the chunk and will be deallocated 
+      /// (with delete[]) when the chunk is destroyed.
+      const char *Text;
+      
+      /// \brief The code completion string associated with a CK_Optional chunk.
+      /// The optional code completion string is owned by the chunk, and will
+      /// be deallocated (with delete) when the chunk is destroyed.
+      CodeCompletionString *Optional;
+      
+      /// \brief Placeholder text associated with a CK_Placeholder chunk.
+      /// The string is owned by the chunk and will be deallocated (with 
+      /// delete[]) when the chunk is destroyed.
+      const char *Placeholder;
+    };
+    
+    /// \brief Create a new text chunk.
+    static Chunk CreateText(const char *Text);
+
+    /// \brief Create a new optional chunk.
+    static Chunk CreateOptional(std::auto_ptr<CodeCompletionString> Optional);
+
+    /// \brief Create a new placeholder chunk.
+    static Chunk CreatePlaceholder(const char *Placeholder);
+
+    /// \brief Destroy this chunk.
+    void Destroy();
+  };
+  
+private:
+  /// \brief The chunks stored in this string.
+  llvm::SmallVector<Chunk, 4> Chunks;
+  
+  CodeCompletionString(const CodeCompletionString &); // DO NOT IMPLEMENT
+  CodeCompletionString &operator=(const CodeCompletionString &); // DITTO
+  
+public:
+  CodeCompletionString() { }
+  ~CodeCompletionString();
+  
+  typedef llvm::SmallVector<Chunk, 4>::const_iterator iterator;
+  iterator begin() const { return Chunks.begin(); }
+  iterator end() const { return Chunks.end(); }
+  
+  /// \brief Add a new text chunk.
+  /// The text string will be copied.
+  void AddTextChunk(const char *Text) { 
+    Chunks.push_back(Chunk::CreateText(Text)); 
+  }
+  
+  /// \brief Add a new optional chunk.
+  void AddOptionalChunk(std::auto_ptr<CodeCompletionString> Optional) {
+    Chunks.push_back(Chunk::CreateOptional(Optional));
+  }
+  
+  /// \brief Add a new placeholder chunk.
+  /// The placeholder text will be copied.
+  void AddPlaceholderChunk(const char *Placeholder) {
+    Chunks.push_back(Chunk::CreatePlaceholder(Placeholder));
+  }
+  
+  /// \brief Retrieve a string representation of the code completion string,
+  /// which is mainly useful for debugging.
+  std::string getAsString() const;
+};
   
 /// \brief Abstract interface for a consumer of code-completion 
 /// information.
@@ -264,6 +364,7 @@
   //@{  
   bool canHiddenResultBeFound(NamedDecl *Hidden, NamedDecl *Visible);
   void AddTypeSpecifierResults(unsigned Rank, ResultSet &Results);
+  CodeCompletionString *CreateCodeCompletionString(Result R);
   //@}
 };
   

Modified: cfe/trunk/lib/Sema/CodeCompleteConsumer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/CodeCompleteConsumer.cpp?rev=82293&r1=82292&r2=82293&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/CodeCompleteConsumer.cpp (original)
+++ cfe/trunk/lib/Sema/CodeCompleteConsumer.cpp Fri Sep 18 17:15:54 2009
@@ -19,9 +19,75 @@
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/raw_ostream.h"
 #include <algorithm>
-#include <string.h>
+#include <cstring>
+#include <functional>
 using namespace clang;
 
+//===----------------------------------------------------------------------===//
+// Code completion string implementation
+//===----------------------------------------------------------------------===//
+CodeCompletionString::Chunk
+CodeCompletionString::Chunk::CreateText(const char *Text) {
+  Chunk Result;
+  Result.Kind = CK_Text;
+  char *New = new char [std::strlen(Text) + 1];
+  std::strcpy(New, Text);
+  Result.Text = New;
+  return Result;  
+}
+
+CodeCompletionString::Chunk 
+CodeCompletionString::Chunk::CreateOptional(
+                                 std::auto_ptr<CodeCompletionString> Optional) {
+  Chunk Result;
+  Result.Kind = CK_Optional;
+  Result.Optional = Optional.release();
+  return Result;
+}
+
+CodeCompletionString::Chunk 
+CodeCompletionString::Chunk::CreatePlaceholder(const char *Placeholder) {
+  Chunk Result;
+  Result.Kind = CK_Placeholder;
+  char *New = new char [std::strlen(Placeholder) + 1];
+  std::strcpy(New, Placeholder);
+  Result.Placeholder = New;
+  return Result;
+}
+
+void
+CodeCompletionString::Chunk::Destroy() {
+  switch (Kind) {
+  case CK_Text: delete [] Text; break;
+  case CK_Optional: delete Optional; break;
+  case CK_Placeholder: delete [] Placeholder; break;
+  }
+}
+
+CodeCompletionString::~CodeCompletionString() {
+  std::for_each(Chunks.begin(), Chunks.end(), 
+                std::mem_fun_ref(&Chunk::Destroy));
+}
+
+std::string CodeCompletionString::getAsString() const {
+  std::string Result;
+  llvm::raw_string_ostream OS(Result);
+                          
+  for (iterator C = begin(), CEnd = end(); C != CEnd; ++C) {
+    switch (C->Kind) {
+    case CK_Text: OS << C->Text; break;
+    case CK_Optional: OS << "{#" << C->Optional->getAsString() << "#}"; break;
+    case CK_Placeholder: OS << "<#" << C->Placeholder << "#>"; break;
+    }
+  }
+  
+  return Result;
+}
+
+//===----------------------------------------------------------------------===//
+// Code completion consumer implementation
+//===----------------------------------------------------------------------===//
+
 CodeCompleteConsumer::CodeCompleteConsumer(Sema &S) : SemaRef(S) {
   SemaRef.setCodeCompleteConsumer(this);
 }
@@ -180,7 +246,7 @@
   
   // Add the names of overloadable operators.
 #define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly)      \
-  if (strcmp(Spelling, "?"))                                                  \
+  if (std::strcmp(Spelling, "?"))                                                  \
     Results.MaybeAddResult(Result(Spelling, 0));
 #include "clang/Basic/OperatorKinds.def"
   
@@ -663,6 +729,64 @@
   }
 }
 
+/// \brief Add function parameter chunks to the given code completion string.
+static void AddFunctionParameterChunks(ASTContext &Context,
+                                       FunctionDecl *Function,
+                                       CodeCompletionString *Result) {
+  CodeCompletionString *CCStr = Result;
+  
+  for (unsigned P = 0, N = Function->getNumParams(); P != N; ++P) {
+    ParmVarDecl *Param = Function->getParamDecl(P);
+    
+    if (Param->hasDefaultArg()) {
+      // When we see an optional default argument, put that argument and
+      // the remaining default arguments into a new, optional string.
+      CodeCompletionString *Opt = new CodeCompletionString;
+      CCStr->AddOptionalChunk(std::auto_ptr<CodeCompletionString>(Opt));
+      CCStr = Opt;
+    }
+    
+    if (P != 0)
+      CCStr->AddTextChunk(", ");
+    
+    // Format the placeholder string.
+    std::string PlaceholderStr;
+    if (Param->getIdentifier())
+      PlaceholderStr = Param->getIdentifier()->getName();
+    
+    Param->getType().getAsStringInternal(PlaceholderStr, 
+                                         Context.PrintingPolicy);
+    
+    // Add the placeholder string.
+    CCStr->AddPlaceholderChunk(PlaceholderStr.c_str());
+  }
+}
+
+/// \brief If possible, create a new code completion string for the given
+/// result.
+///
+/// \returns Either a new, heap-allocated code completion string describing
+/// how to use this result, or NULL to indicate that the string or name of the
+/// result is all that is needed.
+CodeCompletionString *
+CodeCompleteConsumer::CreateCodeCompletionString(Result R) {
+  if (R.Kind != Result::RK_Declaration)
+    return 0;
+  
+  NamedDecl *ND = R.Declaration;
+
+  if (FunctionDecl *Function = dyn_cast<FunctionDecl>(ND)) {
+    CodeCompletionString *Result = new CodeCompletionString;
+    Result->AddTextChunk(Function->getNameAsString().c_str());
+    Result->AddTextChunk("(");
+    AddFunctionParameterChunks(getSema().Context, Function, Result);
+    Result->AddTextChunk(")");
+    return Result;
+  }
+  
+  return 0;
+}
+
 void 
 PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Result *Results, 
                                                          unsigned NumResults) {
@@ -677,6 +801,11 @@
          << Results[I].Rank;
       if (Results[I].Hidden)
         OS << " (Hidden)";
+      if (CodeCompletionString *CCS = CreateCodeCompletionString(Results[I])) {
+        OS << " : " << CCS->getAsString();
+        delete CCS;
+      }
+        
       OS << '\n';
       break;
       

Added: cfe/trunk/test/CodeCompletion/functions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeCompletion/functions.cpp?rev=82293&view=auto

==============================================================================
--- cfe/trunk/test/CodeCompletion/functions.cpp (added)
+++ cfe/trunk/test/CodeCompletion/functions.cpp Fri Sep 18 17:15:54 2009
@@ -0,0 +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() {
+  // CHECK-CC1: f(<#int i#>{#, <#int j#>{#, <#int k#>#}#})
+  // CHECK-CC1: f(<#float x#>, <#float y#>)
+  ::

Propchange: cfe/trunk/test/CodeCompletion/functions.cpp

------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cfe/trunk/test/CodeCompletion/functions.cpp

------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: cfe/trunk/test/CodeCompletion/functions.cpp

------------------------------------------------------------------------------
    svn:mime-type = text/plain





More information about the cfe-commits mailing list