[cfe-commits] r125696 - in /cfe/trunk: include/clang/Sema/CodeCompleteConsumer.h lib/Sema/CodeCompleteConsumer.cpp lib/Sema/SemaCodeComplete.cpp test/Index/complete-kvc.m

Douglas Gregor dgregor at apple.com
Wed Feb 16 16:22:45 PST 2011


Author: dgregor
Date: Wed Feb 16 18:22:45 2011
New Revision: 125696

URL: http://llvm.org/viewvc/llvm-project?rev=125696&view=rev
Log:
Implement code completion results for the Objective-C Key-Value Coding
(KVC) and Key-Value Observing (KVO) protocols.

Added:
    cfe/trunk/test/Index/complete-kvc.m
Modified:
    cfe/trunk/include/clang/Sema/CodeCompleteConsumer.h
    cfe/trunk/lib/Sema/CodeCompleteConsumer.cpp
    cfe/trunk/lib/Sema/SemaCodeComplete.cpp

Modified: cfe/trunk/include/clang/Sema/CodeCompleteConsumer.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/CodeCompleteConsumer.h?rev=125696&r1=125695&r2=125696&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/CodeCompleteConsumer.h (original)
+++ cfe/trunk/include/clang/Sema/CodeCompleteConsumer.h Wed Feb 16 18:22:45 2011
@@ -23,6 +23,7 @@
 
 namespace llvm {
   class raw_ostream;
+  class Twine;
 }
 
 namespace clang {
@@ -80,7 +81,11 @@
   
   /// \brief Adjustment to the "bool" type in Objective-C, where the typedef
   /// "BOOL" is preferred.
-  CCD_bool_in_ObjC = 1
+  CCD_bool_in_ObjC = 1,
+  
+  /// \brief Adjustment for KVC code pattern priorities when it doesn't look
+  /// like the
+  CCD_ProbablyNotObjCCollection = 15
 };
 
 /// \brief Priority value factors by which we will divide or multiply the
@@ -426,6 +431,19 @@
 public:
   /// \brief Copy the given string into this allocator.
   const char *CopyString(llvm::StringRef String);
+
+  /// \brief Copy the given string into this allocator.
+  const char *CopyString(llvm::Twine String);
+  
+  // \brief Copy the given string into this allocator.
+  const char *CopyString(const char *String) {
+    return CopyString(llvm::StringRef(String));
+  }
+  
+  /// \brief Copy the given string into this allocator.
+  const char *CopyString(const std::string &String) {
+    return CopyString(llvm::StringRef(String));
+  }
 };
   
 /// \brief A builder class used to construct new code-completion strings.
@@ -451,7 +469,7 @@
     : Allocator(Allocator), Priority(Priority), Availability(Availability) { }
 
   /// \brief Retrieve the allocator into which the code completion
-  /// strings will be 
+  /// strings should be allocated.
   CodeCompletionAllocator &getAllocator() const { return Allocator; }
   
   /// \brief Take the resulting completion string. 
@@ -460,42 +478,36 @@
   CodeCompletionString *TakeString();
   
   /// \brief Add a new typed-text chunk.
-  /// The text string will be copied.
   void AddTypedTextChunk(const char *Text) { 
     Chunks.push_back(Chunk(CodeCompletionString::CK_TypedText, Text));
   }
   
   /// \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(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 Add a new informative chunk.
-  /// The text will be copied.
   void AddInformativeChunk(const char *Text) {
     Chunks.push_back(Chunk::CreateInformative(Text));
   }
   
   /// \brief Add a new result-type chunk.
-  /// The text will be copied.
   void AddResultTypeChunk(const char *ResultType) {
     Chunks.push_back(Chunk::CreateResultType(ResultType));
   }
   
   /// \brief Add a new current-parameter chunk.
-  /// The text will be copied.
   void AddCurrentParameterChunk(const char *CurrentParameter) {
     Chunks.push_back(Chunk::CreateCurrentParameter(CurrentParameter));
   }

Modified: cfe/trunk/lib/Sema/CodeCompleteConsumer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/CodeCompleteConsumer.cpp?rev=125696&r1=125695&r2=125696&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/CodeCompleteConsumer.cpp (original)
+++ cfe/trunk/lib/Sema/CodeCompleteConsumer.cpp Wed Feb 16 18:22:45 2011
@@ -19,6 +19,7 @@
 #include "clang/Lex/Preprocessor.h"
 #include "clang-c/Index.h"
 #include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Twine.h"
 #include "llvm/Support/raw_ostream.h"
 #include <algorithm>
 #include <cstring>
@@ -227,6 +228,14 @@
   return Mem;
 }
 
+const char *CodeCompletionAllocator::CopyString(llvm::Twine String) {
+  // FIXME: It would be more efficient to teach Twine to tell us its size and
+  // then add a routine there to fill in an allocated char* with the contents
+  // of the string.
+  llvm::SmallString<128> Data;
+  return CopyString(String.toStringRef(Data));
+}
+
 CodeCompletionString *CodeCompletionBuilder::TakeString() {
   void *Mem = Allocator.Allocate(
                   sizeof(CodeCompletionString) + sizeof(Chunk) * Chunks.size(), 

Modified: cfe/trunk/lib/Sema/SemaCodeComplete.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaCodeComplete.cpp?rev=125696&r1=125695&r2=125696&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaCodeComplete.cpp (original)
+++ cfe/trunk/lib/Sema/SemaCodeComplete.cpp Wed Feb 16 18:22:45 2011
@@ -5427,6 +5427,631 @@
   }
 }
 
+/// \brief Add the parenthesized return or parameter type chunk to a code 
+/// completion string.
+static void AddObjCPassingTypeChunk(QualType Type,
+                                    ASTContext &Context,
+                                    CodeCompletionBuilder &Builder) {
+  Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+  Builder.AddTextChunk(GetCompletionTypeString(Type, Context, 
+                                               Builder.getAllocator()));
+  Builder.AddChunk(CodeCompletionString::CK_RightParen);
+}
+
+/// \brief Determine whether the given class is or inherits from a class by
+/// the given name.
+static bool InheritsFromClassNamed(ObjCInterfaceDecl *Class, 
+                                   llvm::StringRef Name) {
+  if (!Class)
+    return false;
+  
+  if (Class->getIdentifier() && Class->getIdentifier()->getName() == Name)
+    return true;
+  
+  return InheritsFromClassNamed(Class->getSuperClass(), Name);
+}
+                  
+/// \brief Add code completions for Objective-C Key-Value Coding (KVC) and
+/// Key-Value Observing (KVO).
+static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property,
+                                       bool IsInstanceMethod,
+                                       QualType ReturnType,
+                                       ASTContext &Context,
+                                       const KnownMethodsMap &KnownMethods,
+                                       ResultBuilder &Results) {
+  IdentifierInfo *PropName = Property->getIdentifier();
+  if (!PropName || PropName->getLength() == 0)
+    return;
+  
+  
+  // Builder that will create each code completion.
+  typedef CodeCompletionResult Result;
+  CodeCompletionAllocator &Allocator = Results.getAllocator();
+  CodeCompletionBuilder Builder(Allocator);
+  
+  // The selector table.
+  SelectorTable &Selectors = Context.Selectors;
+  
+  // The property name, copied into the code completion allocation region
+  // on demand.
+  struct KeyHolder {
+    CodeCompletionAllocator &Allocator;
+    llvm::StringRef Key;
+    const char *CopiedKey;
+    
+    KeyHolder(CodeCompletionAllocator &Allocator, llvm::StringRef Key)
+    : Allocator(Allocator), Key(Key), CopiedKey(0) { }
+    
+    operator const char *() {
+      if (CopiedKey)
+        return CopiedKey;
+      
+      return CopiedKey = Allocator.CopyString(Key);
+    }
+  } Key(Allocator, PropName->getName());
+  
+  // The uppercased name of the property name.
+  std::string UpperKey = PropName->getName();
+  if (!UpperKey.empty())
+    UpperKey[0] = toupper(UpperKey[0]);      
+  
+  bool ReturnTypeMatchesProperty = ReturnType.isNull() ||
+    Context.hasSameUnqualifiedType(ReturnType.getNonReferenceType(), 
+                                   Property->getType());
+  bool ReturnTypeMatchesVoid 
+    = ReturnType.isNull() || ReturnType->isVoidType();
+  
+  // Add the normal accessor -(type)key.
+  if (IsInstanceMethod &&
+      !KnownMethods.count(Selectors.getNullarySelector(PropName)) &&
+      ReturnTypeMatchesProperty && !Property->getGetterMethodDecl()) {
+    if (ReturnType.isNull())
+      AddObjCPassingTypeChunk(Property->getType(), Context, Builder);
+    
+    Builder.AddTypedTextChunk(Key);
+    Results.AddResult(Result(Builder.TakeString(), CCP_CodePattern, 
+                             CXCursor_ObjCInstanceMethodDecl));
+  }
+  
+  // If we have an integral or boolean property (or the user has provided
+  // an integral or boolean return type), add the accessor -(type)isKey.
+  if (IsInstanceMethod &&
+      ((!ReturnType.isNull() && 
+        (ReturnType->isIntegerType() || ReturnType->isBooleanType())) ||
+       (ReturnType.isNull() && 
+        (Property->getType()->isIntegerType() || 
+         Property->getType()->isBooleanType())))) {
+    llvm::Twine SelectorName = llvm::Twine("is") + UpperKey;
+    IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName.str());
+    if (!KnownMethods.count(Selectors.getNullarySelector(SelectorId))) {
+      if (ReturnType.isNull()) {
+        Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+        Builder.AddTextChunk("BOOL");
+        Builder.AddChunk(CodeCompletionString::CK_RightParen);
+      }
+      
+      Builder.AddTypedTextChunk(
+                                Allocator.CopyString(SelectorId->getName()));
+      Results.AddResult(Result(Builder.TakeString(), CCP_CodePattern, 
+                               CXCursor_ObjCInstanceMethodDecl));
+    }
+  }
+  
+  // Add the normal mutator.
+  if (IsInstanceMethod && ReturnTypeMatchesVoid && 
+      !Property->getSetterMethodDecl()) {
+    llvm::Twine SelectorName = llvm::Twine("set") + UpperKey;
+    IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName.str());
+    if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) {
+      if (ReturnType.isNull()) {
+        Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+        Builder.AddTextChunk("void");
+        Builder.AddChunk(CodeCompletionString::CK_RightParen);
+      }
+      
+      Builder.AddTypedTextChunk(
+                                Allocator.CopyString(SelectorId->getName()));
+      Builder.AddTypedTextChunk(":");
+      AddObjCPassingTypeChunk(Property->getType(), Context, Builder);
+      Builder.AddTextChunk(Key);
+      Results.AddResult(Result(Builder.TakeString(), CCP_CodePattern, 
+                               CXCursor_ObjCInstanceMethodDecl));
+    }
+  }
+  
+  // Indexed and unordered accessors
+  unsigned IndexedGetterPriority = CCP_CodePattern;
+  unsigned IndexedSetterPriority = CCP_CodePattern;
+  unsigned UnorderedGetterPriority = CCP_CodePattern;
+  unsigned UnorderedSetterPriority = CCP_CodePattern;
+  if (const ObjCObjectPointerType *ObjCPointer 
+                    = Property->getType()->getAs<ObjCObjectPointerType>()) {
+    if (ObjCInterfaceDecl *IFace = ObjCPointer->getInterfaceDecl()) {
+      // If this interface type is not provably derived from a known
+      // collection, penalize the corresponding completions.
+      if (!InheritsFromClassNamed(IFace, "NSMutableArray")) {
+        IndexedSetterPriority += CCD_ProbablyNotObjCCollection;            
+        if (!InheritsFromClassNamed(IFace, "NSArray"))
+          IndexedGetterPriority += CCD_ProbablyNotObjCCollection;
+      }
+
+      if (!InheritsFromClassNamed(IFace, "NSMutableSet")) {
+        UnorderedSetterPriority += CCD_ProbablyNotObjCCollection;            
+        if (!InheritsFromClassNamed(IFace, "NSSet"))
+          UnorderedGetterPriority += CCD_ProbablyNotObjCCollection;
+      }
+    }
+  } else {
+    IndexedGetterPriority += CCD_ProbablyNotObjCCollection;
+    IndexedSetterPriority += CCD_ProbablyNotObjCCollection;
+    UnorderedGetterPriority += CCD_ProbablyNotObjCCollection;
+    UnorderedSetterPriority += CCD_ProbablyNotObjCCollection;
+  }
+  
+  // Add -(NSUInteger)countOf<key>
+  if (IsInstanceMethod &&  
+      (ReturnType.isNull() || ReturnType->isIntegerType())) {
+    llvm::Twine SelectorName = llvm::Twine("countOf") + UpperKey;
+    IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName.str());
+    if (!KnownMethods.count(Selectors.getNullarySelector(SelectorId))) {
+      if (ReturnType.isNull()) {
+        Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+        Builder.AddTextChunk("NSUInteger");
+        Builder.AddChunk(CodeCompletionString::CK_RightParen);
+      }
+      
+      Builder.AddTypedTextChunk(
+                                Allocator.CopyString(SelectorId->getName()));
+      Results.AddResult(Result(Builder.TakeString(), 
+                               std::min(IndexedGetterPriority, 
+                                        UnorderedGetterPriority),
+                               CXCursor_ObjCInstanceMethodDecl));
+    }
+  }
+  
+  // Indexed getters
+  // Add -(id)objectInKeyAtIndex:(NSUInteger)index
+  if (IsInstanceMethod &&
+      (ReturnType.isNull() || ReturnType->isObjCObjectPointerType())) {
+    llvm::Twine SelectorName
+      = llvm::Twine("objectIn") + UpperKey + "AtIndex";
+    IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName.str());
+    if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) {
+      if (ReturnType.isNull()) {
+        Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+        Builder.AddTextChunk("id");
+        Builder.AddChunk(CodeCompletionString::CK_RightParen);
+      }
+      
+      Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":"));
+      Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+      Builder.AddTextChunk("NSUInteger");
+      Builder.AddChunk(CodeCompletionString::CK_RightParen);
+      Builder.AddTextChunk("index");
+      Results.AddResult(Result(Builder.TakeString(), IndexedGetterPriority, 
+                               CXCursor_ObjCInstanceMethodDecl));
+    }
+  }
+  
+  // Add -(NSArray *)keyAtIndexes:(NSIndexSet *)indexes
+  if (IsInstanceMethod &&
+      (ReturnType.isNull() || 
+       (ReturnType->isObjCObjectPointerType() &&
+        ReturnType->getAs<ObjCObjectPointerType>()->getInterfaceDecl() &&
+        ReturnType->getAs<ObjCObjectPointerType>()->getInterfaceDecl()
+                                                ->getName() == "NSArray"))) {
+    llvm::Twine SelectorName
+      = llvm::Twine(Property->getName()) + "AtIndexes";
+    IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName.str());
+    if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) {
+      if (ReturnType.isNull()) {
+        Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+        Builder.AddTextChunk("NSArray *");
+        Builder.AddChunk(CodeCompletionString::CK_RightParen);
+      }
+       
+      Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":"));
+      Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+      Builder.AddTextChunk("NSIndexSet *");
+      Builder.AddChunk(CodeCompletionString::CK_RightParen);
+      Builder.AddTextChunk("indexes");
+      Results.AddResult(Result(Builder.TakeString(), IndexedGetterPriority, 
+                               CXCursor_ObjCInstanceMethodDecl));
+    }
+  }
+  
+  // Add -(void)getKey:(type **)buffer range:(NSRange)inRange
+  if (IsInstanceMethod && ReturnTypeMatchesVoid) {
+    llvm::Twine SelectorName = llvm::Twine("get") + UpperKey;
+    IdentifierInfo *SelectorIds[2] = {
+      &Context.Idents.get(SelectorName.str()),
+      &Context.Idents.get("range")
+    };
+    
+    if (!KnownMethods.count(Selectors.getSelector(2, SelectorIds))) {
+      if (ReturnType.isNull()) {
+        Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+        Builder.AddTextChunk("void");
+        Builder.AddChunk(CodeCompletionString::CK_RightParen);
+      }
+      
+      Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":"));
+      Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+      Builder.AddPlaceholderChunk("object-type");
+      Builder.AddTextChunk(" **");
+      Builder.AddChunk(CodeCompletionString::CK_RightParen);
+      Builder.AddTextChunk("buffer");
+      Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
+      Builder.AddTypedTextChunk("range:");
+      Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+      Builder.AddTextChunk("NSRange");
+      Builder.AddChunk(CodeCompletionString::CK_RightParen);
+      Builder.AddTextChunk("inRange");
+      Results.AddResult(Result(Builder.TakeString(), IndexedGetterPriority, 
+                               CXCursor_ObjCInstanceMethodDecl));
+    }
+  }
+  
+  // Mutable indexed accessors
+  
+  // - (void)insertObject:(type *)object inKeyAtIndex:(NSUInteger)index
+  if (IsInstanceMethod && ReturnTypeMatchesVoid) {
+    llvm::Twine SelectorName = llvm::Twine("in") + UpperKey + "AtIndex";
+    IdentifierInfo *SelectorIds[2] = {
+      &Context.Idents.get("insertObject"),
+      &Context.Idents.get(SelectorName.str())
+    };
+    
+    if (!KnownMethods.count(Selectors.getSelector(2, SelectorIds))) {
+      if (ReturnType.isNull()) {
+        Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+        Builder.AddTextChunk("void");
+        Builder.AddChunk(CodeCompletionString::CK_RightParen);
+      }
+      
+      Builder.AddTypedTextChunk("insertObject:");
+      Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+      Builder.AddPlaceholderChunk("object-type");
+      Builder.AddTextChunk(" *");
+      Builder.AddChunk(CodeCompletionString::CK_RightParen);
+      Builder.AddTextChunk("object");
+      Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
+      Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":"));
+      Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+      Builder.AddPlaceholderChunk("NSUInteger");
+      Builder.AddChunk(CodeCompletionString::CK_RightParen);
+      Builder.AddTextChunk("index");
+      Results.AddResult(Result(Builder.TakeString(), IndexedSetterPriority, 
+                               CXCursor_ObjCInstanceMethodDecl));
+    }
+  }
+  
+  // - (void)insertKey:(NSArray *)array atIndexes:(NSIndexSet *)indexes
+  if (IsInstanceMethod && ReturnTypeMatchesVoid) {
+    llvm::Twine SelectorName = llvm::Twine("insert") + UpperKey;
+    IdentifierInfo *SelectorIds[2] = {
+      &Context.Idents.get(SelectorName.str()),
+      &Context.Idents.get("atIndexes")
+    };
+    
+    if (!KnownMethods.count(Selectors.getSelector(2, SelectorIds))) {
+      if (ReturnType.isNull()) {
+        Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+        Builder.AddTextChunk("void");
+        Builder.AddChunk(CodeCompletionString::CK_RightParen);
+      }
+      
+      Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":"));
+      Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+      Builder.AddTextChunk("NSArray *");
+      Builder.AddChunk(CodeCompletionString::CK_RightParen);
+      Builder.AddTextChunk("array");
+      Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
+      Builder.AddTypedTextChunk("atIndexes:");
+      Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+      Builder.AddPlaceholderChunk("NSIndexSet *");
+      Builder.AddChunk(CodeCompletionString::CK_RightParen);
+      Builder.AddTextChunk("indexes");
+      Results.AddResult(Result(Builder.TakeString(), IndexedSetterPriority, 
+                               CXCursor_ObjCInstanceMethodDecl));
+    }
+  }
+  
+  // -(void)removeObjectFromKeyAtIndex:(NSUInteger)index
+  if (IsInstanceMethod && ReturnTypeMatchesVoid) {
+    llvm::Twine SelectorName
+      = llvm::Twine("removeObjectFrom") + UpperKey + "AtIndex";
+    IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName.str());        
+    if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) {
+      if (ReturnType.isNull()) {
+        Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+        Builder.AddTextChunk("void");
+        Builder.AddChunk(CodeCompletionString::CK_RightParen);
+      }
+      
+      Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":"));
+      Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+      Builder.AddTextChunk("NSUInteger");
+      Builder.AddChunk(CodeCompletionString::CK_RightParen);
+      Builder.AddTextChunk("index");
+      Results.AddResult(Result(Builder.TakeString(), IndexedSetterPriority, 
+                               CXCursor_ObjCInstanceMethodDecl));
+    }
+  }
+  
+  // -(void)removeKeyAtIndexes:(NSIndexSet *)indexes
+  if (IsInstanceMethod && ReturnTypeMatchesVoid) {
+    llvm::Twine SelectorName
+      = llvm::Twine("remove") + UpperKey + "AtIndexes";
+    IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName.str());        
+    if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) {
+      if (ReturnType.isNull()) {
+        Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+        Builder.AddTextChunk("void");
+        Builder.AddChunk(CodeCompletionString::CK_RightParen);
+      }
+      
+      Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":"));
+      Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+      Builder.AddTextChunk("NSIndexSet *");
+      Builder.AddChunk(CodeCompletionString::CK_RightParen);
+      Builder.AddTextChunk("indexes");
+      Results.AddResult(Result(Builder.TakeString(), IndexedSetterPriority, 
+                               CXCursor_ObjCInstanceMethodDecl));
+    }
+  }
+  
+  // - (void)replaceObjectInKeyAtIndex:(NSUInteger)index withObject:(id)object
+  if (IsInstanceMethod && ReturnTypeMatchesVoid) {
+    llvm::Twine SelectorName
+      = llvm::Twine("replaceObjectIn") + UpperKey + "AtIndex";
+    IdentifierInfo *SelectorIds[2] = {
+      &Context.Idents.get(SelectorName.str()),
+      &Context.Idents.get("withObject")
+    };
+    
+    if (!KnownMethods.count(Selectors.getSelector(2, SelectorIds))) {
+      if (ReturnType.isNull()) {
+        Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+        Builder.AddTextChunk("void");
+        Builder.AddChunk(CodeCompletionString::CK_RightParen);
+      }
+      
+      Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":"));
+      Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+      Builder.AddPlaceholderChunk("NSUInteger");
+      Builder.AddChunk(CodeCompletionString::CK_RightParen);
+      Builder.AddTextChunk("index");
+      Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
+      Builder.AddTypedTextChunk("withObject:");
+      Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+      Builder.AddTextChunk("id");
+      Builder.AddChunk(CodeCompletionString::CK_RightParen);
+      Builder.AddTextChunk("object");
+      Results.AddResult(Result(Builder.TakeString(), IndexedSetterPriority, 
+                               CXCursor_ObjCInstanceMethodDecl));
+    }
+  }
+  
+  // - (void)replaceKeyAtIndexes:(NSIndexSet *)indexes withKey:(NSArray *)array
+  if (IsInstanceMethod && ReturnTypeMatchesVoid) {
+    llvm::Twine SelectorName1 = llvm::Twine("replace") + UpperKey + "AtIndexes";
+    llvm::Twine SelectorName2 = llvm::Twine("with") + UpperKey;
+    IdentifierInfo *SelectorIds[2] = {
+      &Context.Idents.get(SelectorName1.str()),
+      &Context.Idents.get(SelectorName2.str())
+    };
+    
+    if (!KnownMethods.count(Selectors.getSelector(2, SelectorIds))) {
+      if (ReturnType.isNull()) {
+        Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+        Builder.AddTextChunk("void");
+        Builder.AddChunk(CodeCompletionString::CK_RightParen);
+      }
+      
+      Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName1 + ":"));
+      Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+      Builder.AddPlaceholderChunk("NSIndexSet *");
+      Builder.AddChunk(CodeCompletionString::CK_RightParen);
+      Builder.AddTextChunk("indexes");
+      Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace);
+      Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName2 + ":"));
+      Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+      Builder.AddTextChunk("NSArray *");
+      Builder.AddChunk(CodeCompletionString::CK_RightParen);
+      Builder.AddTextChunk("array");
+      Results.AddResult(Result(Builder.TakeString(), IndexedSetterPriority, 
+                               CXCursor_ObjCInstanceMethodDecl));
+    }
+  }  
+  
+  // Unordered getters
+  // - (NSEnumerator *)enumeratorOfKey
+  if (IsInstanceMethod && 
+      (ReturnType.isNull() || 
+       (ReturnType->isObjCObjectPointerType() &&
+        ReturnType->getAs<ObjCObjectPointerType>()->getInterfaceDecl() &&
+        ReturnType->getAs<ObjCObjectPointerType>()->getInterfaceDecl()
+          ->getName() == "NSEnumerator"))) {
+    llvm::Twine SelectorName = llvm::Twine("enumeratorOf") + UpperKey;
+    IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName.str());
+    if (!KnownMethods.count(Selectors.getNullarySelector(SelectorId))) {
+      if (ReturnType.isNull()) {
+        Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+        Builder.AddTextChunk("NSEnumerator *");
+        Builder.AddChunk(CodeCompletionString::CK_RightParen);
+      }
+       
+      Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName));
+      Results.AddResult(Result(Builder.TakeString(), UnorderedGetterPriority, 
+                              CXCursor_ObjCInstanceMethodDecl));
+    }
+  }
+
+  // - (type *)memberOfKey:(type *)object
+  if (IsInstanceMethod && 
+      (ReturnType.isNull() || ReturnType->isObjCObjectPointerType())) {
+    llvm::Twine SelectorName = llvm::Twine("memberOf") + UpperKey;
+    IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName.str());
+    if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) {
+      if (ReturnType.isNull()) {
+        Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+        Builder.AddPlaceholderChunk("object-type");
+        Builder.AddTextChunk(" *");
+        Builder.AddChunk(CodeCompletionString::CK_RightParen);
+      }
+      
+      Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":"));
+      Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+      if (ReturnType.isNull()) {
+        Builder.AddPlaceholderChunk("object-type");
+        Builder.AddTextChunk(" *");
+      } else {
+        Builder.AddTextChunk(GetCompletionTypeString(ReturnType, Context, 
+                                                     Builder.getAllocator()));
+      }
+      Builder.AddChunk(CodeCompletionString::CK_RightParen);
+      Builder.AddTextChunk("object");
+      Results.AddResult(Result(Builder.TakeString(), UnorderedGetterPriority, 
+                               CXCursor_ObjCInstanceMethodDecl));
+    }
+  }
+  
+  // Mutable unordered accessors
+  // - (void)addKeyObject:(type *)object
+  if (IsInstanceMethod && ReturnTypeMatchesVoid) {
+    llvm::Twine SelectorName
+      = llvm::Twine("add") + UpperKey + llvm::Twine("Object");
+    IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName.str());
+    if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) {
+      if (ReturnType.isNull()) {
+        Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+        Builder.AddTextChunk("void");
+        Builder.AddChunk(CodeCompletionString::CK_RightParen);
+      }
+      
+      Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":"));
+      Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+      Builder.AddPlaceholderChunk("object-type");
+      Builder.AddTextChunk(" *");
+      Builder.AddChunk(CodeCompletionString::CK_RightParen);
+      Builder.AddTextChunk("object");
+      Results.AddResult(Result(Builder.TakeString(), UnorderedSetterPriority, 
+                               CXCursor_ObjCInstanceMethodDecl));
+    }
+  }  
+
+  // - (void)addKey:(NSSet *)objects
+  if (IsInstanceMethod && ReturnTypeMatchesVoid) {
+    llvm::Twine SelectorName = llvm::Twine("add") + UpperKey;
+    IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName.str());
+    if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) {
+      if (ReturnType.isNull()) {
+        Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+        Builder.AddTextChunk("void");
+        Builder.AddChunk(CodeCompletionString::CK_RightParen);
+      }
+      
+      Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":"));
+      Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+      Builder.AddTextChunk("NSSet *");
+      Builder.AddChunk(CodeCompletionString::CK_RightParen);
+      Builder.AddTextChunk("objects");
+      Results.AddResult(Result(Builder.TakeString(), UnorderedSetterPriority, 
+                               CXCursor_ObjCInstanceMethodDecl));
+    }
+  }  
+  
+  // - (void)removeKeyObject:(type *)object
+  if (IsInstanceMethod && ReturnTypeMatchesVoid) {
+    llvm::Twine SelectorName
+    = llvm::Twine("remove") + UpperKey + llvm::Twine("Object");
+    IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName.str());
+    if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) {
+      if (ReturnType.isNull()) {
+        Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+        Builder.AddTextChunk("void");
+        Builder.AddChunk(CodeCompletionString::CK_RightParen);
+      }
+      
+      Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":"));
+      Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+      Builder.AddPlaceholderChunk("object-type");
+      Builder.AddTextChunk(" *");
+      Builder.AddChunk(CodeCompletionString::CK_RightParen);
+      Builder.AddTextChunk("object");
+      Results.AddResult(Result(Builder.TakeString(), UnorderedSetterPriority, 
+                               CXCursor_ObjCInstanceMethodDecl));
+    }
+  }  
+  
+  // - (void)removeKey:(NSSet *)objects
+  if (IsInstanceMethod && ReturnTypeMatchesVoid) {
+    llvm::Twine SelectorName = llvm::Twine("remove") + UpperKey;
+    IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName.str());
+    if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) {
+      if (ReturnType.isNull()) {
+        Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+        Builder.AddTextChunk("void");
+        Builder.AddChunk(CodeCompletionString::CK_RightParen);
+      }
+      
+      Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":"));
+      Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+      Builder.AddTextChunk("NSSet *");
+      Builder.AddChunk(CodeCompletionString::CK_RightParen);
+      Builder.AddTextChunk("objects");
+      Results.AddResult(Result(Builder.TakeString(), UnorderedSetterPriority, 
+                               CXCursor_ObjCInstanceMethodDecl));
+    }
+  }    
+
+  // - (void)intersectKey:(NSSet *)objects
+  if (IsInstanceMethod && ReturnTypeMatchesVoid) {
+    llvm::Twine SelectorName = llvm::Twine("intersect") + UpperKey;
+    IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName.str());
+    if (!KnownMethods.count(Selectors.getUnarySelector(SelectorId))) {
+      if (ReturnType.isNull()) {
+        Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+        Builder.AddTextChunk("void");
+        Builder.AddChunk(CodeCompletionString::CK_RightParen);
+      }
+      
+      Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName + ":"));
+      Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+      Builder.AddTextChunk("NSSet *");
+      Builder.AddChunk(CodeCompletionString::CK_RightParen);
+      Builder.AddTextChunk("objects");
+      Results.AddResult(Result(Builder.TakeString(), UnorderedSetterPriority, 
+                               CXCursor_ObjCInstanceMethodDecl));
+    }
+  }  
+  
+  // Key-Value Observing
+  // + (NSSet *)keyPathsForValuesAffectingKey
+  if (!IsInstanceMethod && 
+      (ReturnType.isNull() || 
+       (ReturnType->isObjCObjectPointerType() &&
+        ReturnType->getAs<ObjCObjectPointerType>()->getInterfaceDecl() &&
+        ReturnType->getAs<ObjCObjectPointerType>()->getInterfaceDecl()
+                                                    ->getName() == "NSSet"))) {
+    llvm::Twine SelectorName 
+      = llvm::Twine("keyPathsForValuesAffecting") + UpperKey;
+    IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName.str());
+    if (!KnownMethods.count(Selectors.getNullarySelector(SelectorId))) {
+      if (ReturnType.isNull()) {
+        Builder.AddChunk(CodeCompletionString::CK_LeftParen);
+        Builder.AddTextChunk("NSSet *");
+        Builder.AddChunk(CodeCompletionString::CK_RightParen);
+      }
+       
+      Builder.AddTypedTextChunk(Allocator.CopyString(SelectorName));
+      Results.AddResult(Result(Builder.TakeString(), CCP_CodePattern, 
+                              CXCursor_ObjCInstanceMethodDecl));
+    }
+  }
+}
+
 void Sema::CodeCompleteObjCMethodDecl(Scope *S, 
                                       bool IsInstanceMethod,
                                       ParsedType ReturnTy,
@@ -5482,13 +6107,8 @@
     
     // If the result type was not already provided, add it to the
     // pattern as (type).
-    if (ReturnType.isNull()) {
-      Builder.AddChunk(CodeCompletionString::CK_LeftParen);
-      Builder.AddTextChunk(GetCompletionTypeString(Method->getResultType(),
-                                                   Context, 
-                                                   Builder.getAllocator()));
-      Builder.AddChunk(CodeCompletionString::CK_RightParen);
-    }
+    if (ReturnType.isNull())
+      AddObjCPassingTypeChunk(Method->getResultType(), Context, Builder);
 
     Selector Sel = Method->getSelector();
 
@@ -5514,11 +6134,7 @@
         break;
 
       // Add the parameter type.
-      Builder.AddChunk(CodeCompletionString::CK_LeftParen);
-      Builder.AddTextChunk(GetCompletionTypeString((*P)->getOriginalType(), 
-                                                   Context,
-                                                   Builder.getAllocator()));
-      Builder.AddChunk(CodeCompletionString::CK_RightParen);
+      AddObjCPassingTypeChunk((*P)->getOriginalType(), Context, Builder);
       
       if (IdentifierInfo *Id = (*P)->getIdentifier())
         Builder.AddTextChunk(Builder.getAllocator().CopyString( Id->getName())); 
@@ -5558,6 +6174,33 @@
                                : CXCursor_ObjCClassMethodDecl));
   }
 
+  // Add Key-Value-Coding and Key-Value-Observing accessor methods for all of 
+  // the properties in this class and its categories.
+  if (Context.getLangOptions().ObjC2) {
+    llvm::SmallVector<ObjCContainerDecl *, 4> Containers;
+    Containers.push_back(SearchDecl);
+    
+    ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(SearchDecl);
+    if (!IFace)
+      if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(SearchDecl))
+        IFace = Category->getClassInterface();
+    
+    if (IFace) {
+      for (ObjCCategoryDecl *Category = IFace->getCategoryList(); Category;
+           Category = Category->getNextClassCategory())
+        Containers.push_back(Category);
+    }
+    
+    for (unsigned I = 0, N = Containers.size(); I != N; ++I) {
+      for (ObjCContainerDecl::prop_iterator P = Containers[I]->prop_begin(),
+                                         PEnd = Containers[I]->prop_end(); 
+           P != PEnd; ++P) {
+        AddObjCKeyValueCompletions(*P, IsInstanceMethod, ReturnType, Context, 
+                                   KnownMethods, Results);
+      }
+    }
+  }
+  
   Results.ExitScope();
   
   HandleCodeCompleteResults(this, CodeCompleter, 

Added: cfe/trunk/test/Index/complete-kvc.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/complete-kvc.m?rev=125696&view=auto
==============================================================================
--- cfe/trunk/test/Index/complete-kvc.m (added)
+++ cfe/trunk/test/Index/complete-kvc.m Wed Feb 16 18:22:45 2011
@@ -0,0 +1,87 @@
+// Test for code completions related to Key-Value Coding and Key-Value Observing.
+// Since this test is line- and column-sensitive, the run lines are at the end.
+
+typedef signed char BOOL;
+
+ at interface NSSet
+ at end
+
+ at interface NSMutableSet : NSSet
+ at end
+
+ at interface MySet : NSMutableSet
+ at end
+
+ at interface NSArray
+ at end
+
+ at interface NSMutableArray : NSArray
+ at end
+
+ at interface MyArray : NSMutableArray
+ at end
+
+ at interface MyClass
+ at property int intProperty;
+ at property BOOL boolProperty;
+ at property int* intPointerProperty;
+
+ at property NSSet *setProperty;
+ at property NSMutableSet *mutableSetProperty;
+ at property MySet *mySetProperty;
+
+ at property NSArray *arrayProperty;
+ at property NSMutableArray *mutableArrayProperty;
+ at property MyArray *myArrayProperty;
+ at end
+
+ at implementation MyClass
+- (int)intProperty { return 0; }
+- (void)setIntProperty:(int)newValue { }
++ (NSSet *)keyPathsForValuesAffectingIntProperty { return 0; }
+ at end
+
+// RUN: c-index-test -code-completion-at=%s:39:3 %s | FileCheck -check-prefix=CHECK-CC1 %s
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text void}{RightParen )}{TypedText addMutableArrayPropertyObject:}{LeftParen (}{Placeholder object-type}{Text  *}{RightParen )}{Text object} (55)
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text void}{RightParen )}{TypedText addMutableSetProperty:}{LeftParen (}{Text NSSet *}{RightParen )}{Text objects} (40)
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text NSArray *}{RightParen )}{TypedText arrayProperty} (40)
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text NSArray *}{RightParen )}{TypedText arrayPropertyAtIndexes:}{LeftParen (}{Text NSIndexSet *}{RightParen )}{Text indexes} (40)
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text BOOL}{RightParen )}{TypedText boolProperty} (40)
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text NSArray *}{RightParen )}{TypedText boolPropertyAtIndexes:}{LeftParen (}{Text NSIndexSet *}{RightParen )}{Text indexes} (55)
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text NSUInteger}{RightParen )}{TypedText countOfArrayProperty} (40)
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text NSUInteger}{RightParen )}{TypedText countOfBoolProperty} (55)
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text NSUInteger}{RightParen )}{TypedText countOfSetProperty} (40)
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text NSEnumerator *}{RightParen )}{TypedText enumeratorOfMutableArrayProperty} (55)
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text NSEnumerator *}{RightParen )}{TypedText enumeratorOfMutableSetProperty} (40)
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text void}{RightParen )}{TypedText getMyArrayProperty:}{LeftParen (}{Placeholder object-type}{Text  **}{RightParen )}{Text buffer}{HorizontalSpace  }{TypedText range:}{LeftParen (}{Text NSRange}{RightParen )}{Text inRange} (40)
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text void}{RightParen )}{TypedText getMySetProperty:}{LeftParen (}{Placeholder object-type}{Text  **}{RightParen )}{Text buffer}{HorizontalSpace  }{TypedText range:}{LeftParen (}{Text NSRange}{RightParen )}{Text inRange} (55)
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text void}{RightParen )}{TypedText insertIntProperty:}{LeftParen (}{Text NSArray *}{RightParen )}{Text array}{HorizontalSpace  }{TypedText atIndexes:}{LeftParen (}{Placeholder NSIndexSet *}{RightParen )}{Text indexes} (55)
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text void}{RightParen )}{TypedText insertMutableArrayProperty:}{LeftParen (}{Text NSArray *}{RightParen )}{Text array}{HorizontalSpace  }{TypedText atIndexes:}{LeftParen (}{Placeholder NSIndexSet *}{RightParen )}{Text indexes} (40)
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text void}{RightParen )}{TypedText insertObject:}{LeftParen (}{Placeholder object-type}{Text  *}{RightParen )}{Text object}{HorizontalSpace  }{TypedText inMyArrayPropertyAtIndex:}{LeftParen (}{Placeholder NSUInteger}{RightParen )}{Text index} (40)
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text void}{RightParen )}{TypedText insertObject:}{LeftParen (}{Placeholder object-type}{Text  *}{RightParen )}{Text object}{HorizontalSpace  }{TypedText inMySetPropertyAtIndex:}{LeftParen (}{Placeholder NSUInteger}{RightParen )}{Text index} (55)
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text void}{RightParen )}{TypedText intersectMySetProperty:}{LeftParen (}{Text NSSet *}{RightParen )}{Text objects} (40)
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text void}{RightParen )}{TypedText intersectSetProperty:}{LeftParen (}{Text NSSet *}{RightParen )}{Text objects} (55)
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text int *}{RightParen )}{TypedText intPointerProperty} (40)
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text int}{RightParen )}{TypedText intProperty} (40)
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text BOOL}{RightParen )}{TypedText isBoolProperty} (40)
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text BOOL}{RightParen )}{TypedText isIntProperty} (40)
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Placeholder object-type}{Text  *}{RightParen )}{TypedText memberOfMyArrayProperty:}{LeftParen (}{Placeholder object-type}{Text  *}{RightParen )}{Text object} (55)
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Placeholder object-type}{Text  *}{RightParen )}{TypedText memberOfMySetProperty:}{LeftParen (}{Placeholder object-type}{Text  *}{RightParen )}{Text object} (40)
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text NSMutableArray *}{RightParen )}{TypedText mutableArrayProperty} (40)
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text NSMutableSet *}{RightParen )}{TypedText mutableSetProperty} (40)
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text NSArray *}{RightParen )}{TypedText mutableSetPropertyAtIndexes:}{LeftParen (}{Text NSIndexSet *}{RightParen )}{Text indexes} (55)
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text MyArray *}{RightParen )}{TypedText myArrayProperty} (40)
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text NSArray *}{RightParen )}{TypedText myArrayPropertyAtIndexes:}{LeftParen (}{Text NSIndexSet *}{RightParen )}{Text indexes} (40)
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text id}{RightParen )}{TypedText objectInMutableSetPropertyAtIndex:}{LeftParen (}{Text NSUInteger}{RightParen )}{Text index} (55)
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text id}{RightParen )}{TypedText objectInMyArrayPropertyAtIndex:}{LeftParen (}{Text NSUInteger}{RightParen )}{Text index} (40)
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text void}{RightParen )}{TypedText removeMyArrayPropertyAtIndexes:}{LeftParen (}{Text NSIndexSet *}{RightParen )}{Text indexes} (40)
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text void}{RightParen )}{TypedText removeMySetPropertyAtIndexes:}{LeftParen (}{Text NSIndexSet *}{RightParen )}{Text indexes} (55)
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text void}{RightParen )}{TypedText removeObjectFromIntPropertyAtIndex:}{LeftParen (}{Text NSUInteger}{RightParen )}{Text index} (55)
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text void}{RightParen )}{TypedText removeObjectFromMutableArrayPropertyAtIndex:}{LeftParen (}{Text NSUInteger}{RightParen )}{Text index} (40)
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text void}{RightParen )}{TypedText replaceMyArrayPropertyAtIndexes:}{LeftParen (}{Placeholder NSIndexSet *}{RightParen )}{Text indexes}{HorizontalSpace  }{TypedText withMyArrayProperty:}{LeftParen (}{Text NSArray *}{RightParen )}{Text array} (40)
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text void}{RightParen )}{TypedText replaceMySetPropertyAtIndexes:}{LeftParen (}{Placeholder NSIndexSet *}{RightParen )}{Text indexes}{HorizontalSpace  }{TypedText withMySetProperty:}{LeftParen (}{Text NSArray *}{RightParen )}{Text array} (55)
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text void}{RightParen )}{TypedText replaceObjectInMyArrayPropertyAtIndex:}{LeftParen (}{Placeholder NSUInteger}{RightParen )}{Text index}{HorizontalSpace  }{TypedText withObject:}{LeftParen (}{Text id}{RightParen )}{Text object} (40)
+// CHECK-CC1: ObjCInstanceMethodDecl:{LeftParen (}{Text void}{RightParen )}{TypedText replaceObjectInMySetPropertyAtIndex:}{LeftParen (}{Placeholder NSUInteger}{RightParen )}{Text index}{HorizontalSpace  }{TypedText withObject:}{LeftParen (}{Text id}{RightParen )}{Text object} (55)
+
+// RUN: c-index-test -code-completion-at=%s:41:3 %s | FileCheck -check-prefix=CHECK-CC2 %s
+// CHECK-CC2: ObjCInstanceMethodDecl:{LeftParen (}{Text NSSet *}{RightParen )}{TypedText keyPathsForValuesAffectingMutableArrayProperty} (40)





More information about the cfe-commits mailing list