Improve code-completion results for the flags in an @property
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.

llvm-svn: 89277
diff --git a/clang/lib/Sema/CodeCompleteConsumer.cpp b/clang/lib/Sema/CodeCompleteConsumer.cpp
index 88ac4e4..a9d8301 100644
--- a/clang/lib/Sema/CodeCompleteConsumer.cpp
+++ b/clang/lib/Sema/CodeCompleteConsumer.cpp
@@ -117,6 +117,33 @@
   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 @@
   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 @@
   return Result;
 }
 
+void CodeCompleteConsumer::Result::Destroy() {
+  if (Kind == RK_Pattern) {
+    delete Pattern;
+    Pattern = 0;
+  }
+}
+
 //===----------------------------------------------------------------------===//
 // Code completion overload candidate implementation
 //===----------------------------------------------------------------------===//
@@ -545,6 +593,12 @@
       OS << '\n';
       break;
     }
+        
+    case Result::RK_Pattern: {
+      OS << "Pattern : " << Results[I].Rank << " : " 
+         << Results[I].Pattern->getAsString() << '\n';
+      break;
+    }
     }
   }
   
@@ -627,6 +681,13 @@
         OS << '\n';
         break;
       }
+        
+      case Result::RK_Pattern: {
+        OS << "Pattern:";
+        Results[I].Pattern->Serialize(OS);
+        OS << '\n';
+        break;
+      }
     }
   }
   
diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp
index 22d2884..f3f7d3f 100644
--- a/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/clang/lib/Sema/SemaCodeComplete.cpp
@@ -1066,6 +1066,17 @@
       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 @@
           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 @@
 
   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 @@
     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());
 }