Added clang_getCompletionAnnotation and clang_getCompletionNumAnnotations to
retrieve annotations from completion string.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@141953 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h
index 3df1670..1320145 100644
--- a/include/clang-c/Index.h
+++ b/include/clang-c/Index.h
@@ -3281,8 +3281,7 @@
  * \param chunk_number the 0-based index of the chunk in the completion string.
  *
  * \returns the completion string associated with the chunk at index
- * \c chunk_number, or NULL if that chunk is not represented by a completion
- * string.
+ * \c chunk_number.
  */
 CINDEX_LINKAGE CXCompletionString
 clang_getCompletionChunkCompletionString(CXCompletionString completion_string,
@@ -3321,6 +3320,33 @@
 clang_getCompletionAvailability(CXCompletionString completion_string);
 
 /**
+ * \brief Retrieve the number of annotations associated with the given
+ * completion string.
+ *
+ * \param completion_string the completion string to query.
+ *
+ * \returns the number of annotations associated with the given completion
+ * string.
+ */
+CINDEX_LINKAGE unsigned
+clang_getCompletionNumAnnotations(CXCompletionString completion_string);
+
+/**
+ * \brief Retrieve the annotation associated with the given completion string.
+ *
+ * \param completion_string the completion string to query.
+ *
+ * \param annotation_number the 0-based index of the annotation of the
+ * completion string.
+ *
+ * \returns annotation string associated with the completion at index
+ * \c annotation_number, or a NULL string if that annotation is not available.
+ */
+CINDEX_LINKAGE CXString
+clang_getCompletionAnnotation(CXCompletionString completion_string,
+                              unsigned annotation_number);
+
+/**
  * \brief Retrieve a completion string for an arbitrary declaration or macro
  * definition cursor.
  *
diff --git a/include/clang/Sema/CodeCompleteConsumer.h b/include/clang/Sema/CodeCompleteConsumer.h
index a20468e..9e2d60d 100644
--- a/include/clang/Sema/CodeCompleteConsumer.h
+++ b/include/clang/Sema/CodeCompleteConsumer.h
@@ -428,19 +428,23 @@
   
 private:
   /// \brief The number of chunks stored in this string.
-  unsigned NumChunks;
+  unsigned NumChunks : 16;
   
+  /// \brief The number of annotations for this code-completion result.
+  unsigned NumAnnotations : 16;
+
   /// \brief The priority of this code-completion string.
   unsigned Priority : 30;
   
   /// \brief The availability of this code-completion result.
   unsigned Availability : 2;
-  
+
   CodeCompletionString(const CodeCompletionString &); // DO NOT IMPLEMENT
   CodeCompletionString &operator=(const CodeCompletionString &); // DITTO
   
   CodeCompletionString(const Chunk *Chunks, unsigned NumChunks,
-                       unsigned Priority, CXAvailabilityKind Availability);
+                       unsigned Priority, CXAvailabilityKind Availability,
+                       const char **Annotations, unsigned NumAnnotations);
   ~CodeCompletionString() { }
   
   friend class CodeCompletionBuilder;
@@ -464,8 +468,14 @@
   /// \brief Retrieve the priority of this code completion result.
   unsigned getPriority() const { return Priority; }
   
-  /// \brief Reteirve the availability of this code completion result.
+  /// \brief Retrieve the availability of this code completion result.
   unsigned getAvailability() const { return Availability; }
+
+  /// \brief Retrieve the number of annotations for this code completion result.
+  unsigned getAnnotationCount() const;
+
+  /// \brief Retrieve the annotation string specified by \c AnnotationNr.
+  const char *getAnnotation(unsigned AnnotationNr) const;
   
   /// \brief Retrieve a string representation of the code completion string,
   /// which is mainly useful for debugging.
@@ -504,6 +514,8 @@
   
   /// \brief The chunks stored in this string.
   SmallVector<Chunk, 4> Chunks;
+
+  SmallVector<const char *, 2> Annotations;
   
 public:
   CodeCompletionBuilder(CodeCompletionAllocator &Allocator) 
@@ -560,6 +572,8 @@
   
   /// \brief Add a new chunk.
   void AddChunk(Chunk C) { Chunks.push_back(C); }
+
+  void AddAnnotation(const char *A) { Annotations.push_back(A); }
 };
   
 /// \brief Captures a result of code completion.
diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp
index ab69938..de87b80 100644
--- a/lib/Sema/CodeCompleteConsumer.cpp
+++ b/lib/Sema/CodeCompleteConsumer.cpp
@@ -190,14 +190,36 @@
 CodeCompletionString::CodeCompletionString(const Chunk *Chunks, 
                                            unsigned NumChunks,
                                            unsigned Priority, 
-                                           CXAvailabilityKind Availability) 
-  : NumChunks(NumChunks), Priority(Priority), Availability(Availability) 
+                                           CXAvailabilityKind Availability,
+                                           const char **Annotations,
+                                           unsigned NumAnnotations)
+  : NumChunks(NumChunks), NumAnnotations(NumAnnotations)
+  , Priority(Priority), Availability(Availability)
 { 
+  assert(NumChunks <= 0xffff);
+  assert(NumAnnotations <= 0xffff);
+
   Chunk *StoredChunks = reinterpret_cast<Chunk *>(this + 1);
   for (unsigned I = 0; I != NumChunks; ++I)
     StoredChunks[I] = Chunks[I];
+
+  const char **StoredAnnotations = reinterpret_cast<const char **>(StoredChunks + NumChunks);
+  for (unsigned I = 0; I != NumAnnotations; ++I)
+    StoredAnnotations[I] = Annotations[I];
 }
 
+unsigned CodeCompletionString::getAnnotationCount() const {
+  return NumAnnotations;
+}
+
+const char *CodeCompletionString::getAnnotation(unsigned AnnotationNr) const {
+  if (AnnotationNr < NumAnnotations)
+    return reinterpret_cast<const char * const*>(end())[AnnotationNr];
+  else
+    return 0;
+}
+
+
 std::string CodeCompletionString::getAsString() const {
   std::string Result;
   llvm::raw_string_ostream OS(Result);
@@ -244,11 +266,13 @@
 
 CodeCompletionString *CodeCompletionBuilder::TakeString() {
   void *Mem = Allocator.Allocate(
-                  sizeof(CodeCompletionString) + sizeof(Chunk) * Chunks.size(), 
+                  sizeof(CodeCompletionString) + sizeof(Chunk) * Chunks.size()
+                                    + sizeof(const char *) * Annotations.size(),
                                  llvm::alignOf<CodeCompletionString>());
   CodeCompletionString *Result 
     = new (Mem) CodeCompletionString(Chunks.data(), Chunks.size(),
-                               Priority, Availability);
+                                     Priority, Availability,
+                                     Annotations.data(), Annotations.size());
   Chunks.clear();
   return Result;
 }
diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp
index 56b351c..405d626 100644
--- a/lib/Sema/SemaCodeComplete.cpp
+++ b/lib/Sema/SemaCodeComplete.cpp
@@ -2424,6 +2424,12 @@
     Result.AddTextChunk("::");
     return Result.TakeString();
   }
+
+  for (Decl::attr_iterator i = ND->attr_begin(); i != ND->attr_end(); ++i) {
+    if (AnnotateAttr *Attr = dyn_cast_or_null<AnnotateAttr>(*i)) {
+      Result.AddAnnotation(Result.getAllocator().CopyString(Attr->getAnnotation()));
+    }
+  }
   
   AddResultTypeChunk(S.Context, Policy, ND, Result);
   
diff --git a/test/Index/complete-with-annotations.cpp b/test/Index/complete-with-annotations.cpp
new file mode 100644
index 0000000..afa8d9e
--- /dev/null
+++ b/test/Index/complete-with-annotations.cpp
@@ -0,0 +1,23 @@
+class X {
+  void doSomething();
+
+  int field __attribute((annotate("one"), annotate("two"), annotate("three")));
+
+public __attribute__((annotate("some annotation"))):
+  void func2();
+  int member2 __attribute__((annotate("another annotation")));
+};
+
+void X::doSomething() {
+  // RUN: c-index-test -code-completion-at=%s:13:9 %s | FileCheck %s
+  this->;
+}
+
+// CHECK: CXXMethod:{ResultType void}{TypedText doSomething}{LeftParen (}{RightParen )} (34)
+// CHECK: FieldDecl:{ResultType int}{TypedText field} (35) ("three", "two", "one")
+// CHECK: CXXMethod:{ResultType void}{TypedText func2}{LeftParen (}{RightParen )} (34) ("some annotation")
+// CHECK: FieldDecl:{ResultType int}{TypedText member2} (35) ("another annotation", "some annotation")
+// CHECK: CXXMethod:{ResultType X &}{TypedText operator=}{LeftParen (}{Placeholder const X &}{RightParen )} (34)
+// CHECK: ClassDecl:{TypedText X}{Text ::} (75)
+// CHECK: CXXDestructor:{ResultType void}{TypedText ~X}{LeftParen (}{RightParen )} (34)
+
diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c
index 063c4ad..2a3584b 100644
--- a/tools/c-index-test/c-index-test.c
+++ b/tools/c-index-test/c-index-test.c
@@ -1033,6 +1033,7 @@
                              CXClientData client_data) {
   FILE *file = (FILE *)client_data;
   CXString ks = clang_getCursorKindSpelling(completion_result->CursorKind);
+  unsigned annotationCount;
 
   fprintf(file, "%s:", clang_getCString(ks));
   clang_disposeString(ks);
@@ -1056,6 +1057,22 @@
     fprintf(file, " (inaccessible)");
     break;
   }
+
+  annotationCount = clang_getCompletionNumAnnotations(
+        completion_result->CompletionString);
+  if (annotationCount) {
+    unsigned i;
+    fprintf(file, " (");
+    for (i = 0; i < annotationCount; ++i) {
+      if (i != 0)
+        fprintf(file, ", ");
+      fprintf(file, "\"%s\"",
+              clang_getCString(clang_getCompletionAnnotation(
+                                 completion_result->CompletionString, i)));
+    }
+    fprintf(file, ")");
+  }
+
   fprintf(file, "\n");
 }
 
diff --git a/tools/libclang/CIndexCodeCompletion.cpp b/tools/libclang/CIndexCodeCompletion.cpp
index 3ce0d24..c19b340 100644
--- a/tools/libclang/CIndexCodeCompletion.cpp
+++ b/tools/libclang/CIndexCodeCompletion.cpp
@@ -203,6 +203,20 @@
               : CXAvailability_Available;
 }
 
+unsigned clang_getCompletionNumAnnotations(CXCompletionString completion_string)
+{
+  CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
+  return CCStr ? CCStr->getAnnotationCount() : 0;
+}
+
+CXString clang_getCompletionAnnotation(CXCompletionString completion_string,
+                                       unsigned annotation_number) {
+  CodeCompletionString *CCStr = (CodeCompletionString *)completion_string;
+  return CCStr ? createCXString(CCStr->getAnnotation(annotation_number))
+               : createCXString((const char *) 0);
+}
+
+
 /// \brief The CXCodeCompleteResults structure we allocate internally;
 /// the client only sees the initial CXCodeCompleteResults structure.
 struct AllocatedCXCodeCompleteResults : public CXCodeCompleteResults {
diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports
index 68c0ad5..989ed83 100644
--- a/tools/libclang/libclang.exports
+++ b/tools/libclang/libclang.exports
@@ -54,9 +54,11 @@
 clang_getCanonicalType
 clang_getClangVersion
 clang_getCompletionAvailability
+clang_getCompletionAnnotation
 clang_getCompletionChunkCompletionString
 clang_getCompletionChunkKind
 clang_getCompletionChunkText
+clang_getCompletionNumAnnotations
 clang_getCompletionPriority
 clang_getCursor
 clang_getCursorAvailability