]> granicus.if.org Git - clang/commitdiff
Improve code-completion results for the flags in an @property
authorDouglas Gregor <dgregor@apple.com>
Thu, 19 Nov 2009 00:01:57 +0000 (00:01 +0000)
committerDouglas Gregor <dgregor@apple.com>
Thu, 19 Nov 2009 00:01:57 +0000 (00:01 +0000)
declaration by providing patterns for "getter = <method>" and "setter
= <method>". As part of this, invented a new "pattern" result kind
that is merely a semantic string. The "pattern" result kind should
help with other kinds of code templates.

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

include/clang/Sema/CodeCompleteConsumer.h
lib/Sema/CodeCompleteConsumer.cpp
lib/Sema/SemaCodeComplete.cpp
test/CodeCompletion/property.m [deleted file]
test/Index/complete-property-flags.m [new file with mode: 0644]

index 43ff6869184d96e2761f2c8541f149b2de0291b5..f8c4c5281c63da1465a9a64b8f9b82e9c631528e 100644 (file)
@@ -123,6 +123,9 @@ public:
     /// \brief Create a new current-parameter chunk.
     static Chunk CreateCurrentParameter(llvm::StringRef CurrentParameter);
 
+    /// \brief Clone the given chunk.
+    Chunk Clone() const;
+    
     /// \brief Destroy this chunk, deallocating any memory it owns.
     void Destroy();
   };
@@ -192,15 +195,21 @@ public:
   /// \brief Add a new chunk.
   void AddChunk(Chunk C) { Chunks.push_back(C); }
   
+  /// \brief Returns the text in the TypedText chunk.
+  const char *getTypedText() const;
+
   /// \brief Retrieve a string representation of the code completion string,
   /// which is mainly useful for debugging.
   std::string getAsString() const; 
   
+  /// \brief Clone this code-completion string.
+  CodeCompletionString *Clone() const;
+  
   /// \brief Serialize this code-completion string to the given stream.
   void Serialize(llvm::raw_ostream &OS) const;
   
   /// \brief Deserialize a code-completion string from the given string.
-  static CodeCompletionString *Deserialize(llvm::StringRef &Str);
+  static CodeCompletionString *Deserialize(llvm::StringRef &Str);  
 };
   
 llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, 
@@ -220,7 +229,8 @@ public:
     enum ResultKind {
       RK_Declaration = 0, //< Refers to a declaration
       RK_Keyword,         //< Refers to a keyword or symbol.
-      RK_Macro            //< Refers to a macro
+      RK_Macro,           //< Refers to a macro
+      RK_Pattern          //< Refers to a precomputed pattern.
     };
     
     /// \brief The kind of result stored here.
@@ -235,6 +245,10 @@ public:
       /// or symbol's spelling.
       const char *Keyword;
       
+      /// \brief When Kind == RK_Pattern, the code-completion string that
+      /// describes the completion text to insert.
+      CodeCompletionString *Pattern;
+      
       /// \brief When Kind == RK_Macro, the identifier that refers to a macro.
       IdentifierInfo *Macro;
     };
@@ -277,6 +291,12 @@ public:
      : Kind(RK_Macro), Macro(Macro), Rank(Rank), Hidden(false), 
        QualifierIsInformative(0), StartsNestedNameSpecifier(false),
        Qualifier(0) { }
+
+    /// \brief Build a result that refers to a pattern.
+    Result(CodeCompletionString *Pattern, unsigned Rank)
+      : Kind(RK_Pattern), Pattern(Pattern), Rank(Rank), Hidden(false), 
+        QualifierIsInformative(0), StartsNestedNameSpecifier(false),
+        Qualifier(0) { }
     
     /// \brief Retrieve the declaration stored in this result.
     NamedDecl *getDeclaration() const {
@@ -293,6 +313,8 @@ public:
     /// \brief Create a new code-completion string that describes how to insert
     /// this result into a program.
     CodeCompletionString *CreateCodeCompletionString(Sema &S);
+    
+    void Destroy();
   };
     
   class OverloadCandidate {
index 88ac4e49cf9edb2d2fd412470be7846d4141e546..a9d83010576a6f90467fec8aef1cb0019c37aee9 100644 (file)
@@ -117,6 +117,33 @@ CodeCompletionString::Chunk::CreateCurrentParameter(
   return Chunk(CK_CurrentParameter, CurrentParameter);
 }
 
+CodeCompletionString::Chunk CodeCompletionString::Chunk::Clone() const {
+  switch (Kind) {
+  case CK_TypedText:
+  case CK_Text:
+  case CK_Placeholder:
+  case CK_Informative:
+  case CK_CurrentParameter:
+  case CK_LeftParen:
+  case CK_RightParen:
+  case CK_LeftBracket:
+  case CK_RightBracket:
+  case CK_LeftBrace:
+  case CK_RightBrace:
+  case CK_LeftAngle:
+  case CK_RightAngle:
+  case CK_Comma:
+    return Chunk(Kind, Text);
+      
+  case CK_Optional: {
+    std::auto_ptr<CodeCompletionString> Opt(Optional->Clone());
+    return CreateOptional(Opt);
+  }
+  }
+
+  // Silence GCC warning.
+  return Chunk();
+}
 
 void
 CodeCompletionString::Chunk::Destroy() {
@@ -168,6 +195,20 @@ std::string CodeCompletionString::getAsString() const {
   return Result;
 }
 
+const char *CodeCompletionString::getTypedText() const {
+  for (iterator C = begin(), CEnd = end(); C != CEnd; ++C)
+    if (C->Kind == CK_TypedText)
+      return C->Text;
+  
+  return 0;
+}
+
+CodeCompletionString *CodeCompletionString::Clone() const {
+  CodeCompletionString *Result = new CodeCompletionString;
+  for (iterator C = begin(), CEnd = end(); C != CEnd; ++C)
+    Result->AddChunk(C->Clone());
+  return Result;
+}
 
 namespace {
   // Escape a string for XML-like formatting.
@@ -473,6 +514,13 @@ CodeCompletionString *CodeCompletionString::Deserialize(llvm::StringRef &Str) {
   return Result;
 }
 
+void CodeCompleteConsumer::Result::Destroy() {
+  if (Kind == RK_Pattern) {
+    delete Pattern;
+    Pattern = 0;
+  }
+}
+
 //===----------------------------------------------------------------------===//
 // Code completion overload candidate implementation
 //===----------------------------------------------------------------------===//
@@ -545,6 +593,12 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef,
       OS << '\n';
       break;
     }
+        
+    case Result::RK_Pattern: {
+      OS << "Pattern : " << Results[I].Rank << " : " 
+         << Results[I].Pattern->getAsString() << '\n';
+      break;
+    }
     }
   }
   
@@ -627,6 +681,13 @@ CIndexCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef,
         OS << '\n';
         break;
       }
+        
+      case Result::RK_Pattern: {
+        OS << "Pattern:";
+        Results[I].Pattern->Serialize(OS);
+        OS << '\n';
+        break;
+      }
     }
   }
   
index 22d2884ede18fa82ebe7a6fed584e2a8b95a31cf..f3f7d3f40559ec673e67a4a4b1f25545406a3f02 100644 (file)
@@ -1066,6 +1066,17 @@ namespace {
       else if (X.Rank > Y.Rank)
         return false;
       
+      // We use a special ordering for keywords and patterns, based on the
+      // typed text.
+      if ((X.Kind == Result::RK_Keyword || X.Kind == Result::RK_Pattern) &&
+          (Y.Kind == Result::RK_Keyword || Y.Kind == Result::RK_Pattern)) {
+        const char *XStr = (X.Kind == Result::RK_Keyword)? X.Keyword 
+                                                   : X.Pattern->getTypedText();
+        const char *YStr = (Y.Kind == Result::RK_Keyword)? Y.Keyword 
+                                                   : Y.Pattern->getTypedText();
+        return strcmp(XStr, YStr) < 0;
+      }
+      
       // Result kinds are ordered by decreasing importance.
       if (X.Kind < Y.Kind)
         return true;
@@ -1087,12 +1098,14 @@ namespace {
           return isEarlierDeclarationName(X.Declaration->getDeclName(),
                                           Y.Declaration->getDeclName());
           
-        case Result::RK_Keyword:
-          return strcmp(X.Keyword, Y.Keyword) < 0;
-          
         case Result::RK_Macro:
           return llvm::LowercaseString(X.Macro->getName()) < 
                    llvm::LowercaseString(Y.Macro->getName());
+          
+        case Result::RK_Keyword:
+        case Result::RK_Pattern:
+          llvm::llvm_unreachable("Result kinds handled above");
+          break;
       }
       
       // Silence GCC warning.
@@ -1120,6 +1133,9 @@ static void HandleCodeCompleteResults(Sema *S,
 
   if (CodeCompleter)
     CodeCompleter->ProcessCodeCompleteResults(*S, Results, NumResults);
+  
+  for (unsigned I = 0; I != NumResults; ++I)
+    Results[I].Destroy();
 }
 
 void Sema::CodeCompleteOrdinaryName(Scope *S) {
@@ -1635,10 +1651,20 @@ void Sema::CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS) {
     Results.MaybeAddResult(CodeCompleteConsumer::Result("copy", 0));
   if (!(Attributes & ObjCDeclSpec::DQ_PR_nonatomic))
     Results.MaybeAddResult(CodeCompleteConsumer::Result("nonatomic", 0));
-  if (!(Attributes & ObjCDeclSpec::DQ_PR_setter))
-    Results.MaybeAddResult(CodeCompleteConsumer::Result("setter", 0));
-  if (!(Attributes & ObjCDeclSpec::DQ_PR_getter))
-    Results.MaybeAddResult(CodeCompleteConsumer::Result("getter", 0));
+  if (!(Attributes & ObjCDeclSpec::DQ_PR_setter)) {
+    CodeCompletionString *Setter = new CodeCompletionString;
+    Setter->AddTypedTextChunk("setter");
+    Setter->AddTextChunk(" = ");
+    Setter->AddPlaceholderChunk("method");
+    Results.MaybeAddResult(CodeCompleteConsumer::Result(Setter, 0));
+  }
+  if (!(Attributes & ObjCDeclSpec::DQ_PR_getter)) {
+    CodeCompletionString *Getter = new CodeCompletionString;
+    Getter->AddTypedTextChunk("getter");
+    Getter->AddTextChunk(" = ");
+    Getter->AddPlaceholderChunk("method");
+    Results.MaybeAddResult(CodeCompleteConsumer::Result(Getter, 0));
+  }
   Results.ExitScope();
   HandleCodeCompleteResults(this, CodeCompleter, Results.data(),Results.size());
 }
diff --git a/test/CodeCompletion/property.m b/test/CodeCompletion/property.m
deleted file mode 100644 (file)
index 184519b..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-// Note: the run lines follow their respective tests, since line/column
-// matter in this test.
-
-@interface Foo  {
-  void *isa;
-}
-@property(copy) Foo *myprop;
-@property(retain, nonatomic) id xx;
-// RUN: clang-cc -fsyntax-only -code-completion-at=%s:7:11 %s -o - | FileCheck -check-prefix=CC1 %s
-// CC1: assign
-// CC1-NEXT: copy
-// CC1-NEXT: getter
-// CC1-NEXT: nonatomic
-// CC1-NEXT: readonly
-// CC1-NEXT: readwrite
-// CC1-NEXT: retain
-// CC1-NEXT: setter
-// RUN: clang-cc -fsyntax-only -code-completion-at=%s:8:18 %s -o - | FileCheck -check-prefix=CC2 %s
-// CC2: assign
-// CC2-NEXT: copy
-// CC2-NEXT: getter
-// CC2-NEXT: nonatomic
-// CC2-NEXT: readonly
-// CC2-NEXT: readwrite
-// CC2-NEXT: setter
-@end
-
-
-
diff --git a/test/Index/complete-property-flags.m b/test/Index/complete-property-flags.m
new file mode 100644 (file)
index 0000000..65204b5
--- /dev/null
@@ -0,0 +1,29 @@
+// Note: the run lines follow their respective tests, since line/column
+// matter in this test.
+
+@interface Foo  {
+  void *isa;
+}
+@property(copy) Foo *myprop;
+@property(retain, nonatomic) id xx;
+// RUN: c-index-test -code-completion-at=%s:7:11 %s | FileCheck -check-prefix=CHECK-CC1 %s
+// CHECK-CC1: {TypedText assign}
+// CHECK-CC1-NEXT: {TypedText copy}
+// CHECK-CC1-NEXT: {TypedText getter}{Text  = }{Placeholder method}
+// CHECK-CC1-NEXT: {TypedText nonatomic}
+// CHECK-CC1-NEXT: {TypedText readonly}
+// CHECK-CC1-NEXT: {TypedText readwrite}
+// CHECK-CC1-NEXT: {TypedText retain}
+// CHECK-CC1-NEXT: {TypedText setter}{Text  = }{Placeholder method}
+// RUN: c-index-test -code-completion-at=%s:8:18 %s | FileCheck -check-prefix=CHECK-CC2 %s
+// CHECK-CC2: {TypedText assign}
+// CHECK-CC2-NEXT: {TypedText copy}
+// CHECK-CC2-NEXT: {TypedText getter}{Text  = }{Placeholder method}
+// CHECK-CC2-NEXT: {TypedText nonatomic}
+// CHECK-CC2-NEXT: {TypedText readonly}
+// CHECK-CC2-NEXT: {TypedText readwrite}
+// CHECK-CC2-NEXT: {TypedText setter}{Text  = }{Placeholder method}
+@end
+
+
+