New libclang API to expose container type for code completion, from
Connor Wakamo!


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@135651 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c
index 6e0aaac..63031ce 100644
--- a/tools/c-index-test/c-index-test.c
+++ b/tools/c-index-test/c-index-test.c
@@ -1171,8 +1171,9 @@
   }
 
   if (results) {
-    unsigned i, n = results->NumResults;
+    unsigned i, n = results->NumResults, containerIsIncomplete = 0;
     unsigned long long contexts;
+    enum CXCursorKind containerKind;
     if (!timing_only) {      
       /* Sort the code-completion results based on the typed text. */
       clang_sortCodeCompletionResults(results->Results, results->NumResults);
@@ -1190,6 +1191,27 @@
     contexts = clang_codeCompleteGetContexts(results);
     print_completion_contexts(contexts, stdout);
     
+    containerKind = clang_codeCompleteGetContainerKind(results, &containerIsIncomplete);
+    
+    if (containerKind != CXCursor_InvalidCode) {
+      /* We have found a container */
+      CXString containerUSR, containerKindSpelling;
+      containerKindSpelling = clang_getCursorKindSpelling(containerKind);
+      printf("Container Kind: %s\n", clang_getCString(containerKindSpelling));
+      clang_disposeString(containerKindSpelling);
+      
+      if (containerIsIncomplete) {
+        printf("Container is incomplete\n");
+      }
+      else {
+        printf("Container is complete\n");
+      }
+      
+      containerUSR = clang_codeCompleteGetContainerUSR(results);
+      printf("Container USR: %s\n", clang_getCString(containerUSR));
+      clang_disposeString(containerUSR);
+    }
+    
     clang_disposeCodeCompleteResults(results);
   }
   clang_disposeTranslationUnit(TU);
diff --git a/tools/libclang/CIndexCodeCompletion.cpp b/tools/libclang/CIndexCodeCompletion.cpp
index 832e2f2..8695cb4 100644
--- a/tools/libclang/CIndexCodeCompletion.cpp
+++ b/tools/libclang/CIndexCodeCompletion.cpp
@@ -15,7 +15,11 @@
 #include "CIndexer.h"
 #include "CXTranslationUnit.h"
 #include "CXString.h"
+#include "CXCursor.h"
 #include "CIndexDiagnostic.h"
+#include "clang/AST/Type.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclObjC.h"
 #include "clang/Basic/SourceManager.h"
 #include "clang/Basic/FileManager.h"
 #include "clang/Frontend/ASTUnit.h"
@@ -242,6 +246,11 @@
   /// \brief A bitfield representing the acceptable completions for the
   /// current context.
   unsigned long long Contexts;
+  
+  enum CXCursorKind ContainerKind;
+  CXString ContainerUSR;
+  
+  unsigned ContainerIsIncomplete;
 };
 
 /// \brief Tracks the number of code-completion result objects that are 
@@ -267,6 +276,8 @@
 AllocatedCXCodeCompleteResults::~AllocatedCXCodeCompleteResults() {
   delete [] Results;
   
+  clang_disposeString(ContainerUSR);
+  
   for (unsigned I = 0, N = TemporaryFiles.size(); I != N; ++I)
     TemporaryFiles[I].eraseFromDisk();
   for (unsigned I = 0, N = TemporaryBuffers.size(); I != N; ++I)
@@ -455,10 +466,12 @@
   class CaptureCompletionResults : public CodeCompleteConsumer {
     AllocatedCXCodeCompleteResults &AllocatedResults;
     llvm::SmallVector<CXCompletionResult, 16> StoredResults;
+    CXTranslationUnit *TU;
   public:
-    CaptureCompletionResults(AllocatedCXCodeCompleteResults &Results)
+    CaptureCompletionResults(AllocatedCXCodeCompleteResults &Results,
+                             CXTranslationUnit *TranslationUnit)
       : CodeCompleteConsumer(true, false, true, false), 
-        AllocatedResults(Results) { }
+        AllocatedResults(Results), TU(TranslationUnit) { }
     ~CaptureCompletionResults() { Finish(); }
     
     virtual void ProcessCodeCompleteResults(Sema &S, 
@@ -477,10 +490,53 @@
         StoredResults.push_back(R);
       }
       
-      enum CodeCompletionContext::Kind kind = Context.getKind();
+      enum CodeCompletionContext::Kind contextKind = Context.getKind();
       
-      AllocatedResults.ContextKind = kind;
-      AllocatedResults.Contexts = getContextsForContextKind(kind, S);
+      AllocatedResults.ContextKind = contextKind;
+      AllocatedResults.Contexts = getContextsForContextKind(contextKind, S);
+      
+      QualType baseType = Context.getBaseType();
+      NamedDecl *D = NULL;
+      
+      if (!baseType.isNull()) {
+        // Get the declaration for a class/struct/union/enum type
+        if (const TagType *Tag = baseType->getAs<TagType>())
+          D = Tag->getDecl();
+        // Get the @interface declaration for a (possibly-qualified) Objective-C
+        // object pointer type, e.g., NSString*
+        else if (const ObjCObjectPointerType *ObjPtr = 
+                 baseType->getAs<ObjCObjectPointerType>())
+          D = ObjPtr->getInterfaceDecl();
+        // Get the @interface declaration for an Objective-C object type
+        else if (const ObjCObjectType *Obj = baseType->getAs<ObjCObjectType>())
+          D = Obj->getInterface();
+        // Get the class for a C++ injected-class-name
+        else if (const InjectedClassNameType *Injected =
+                 baseType->getAs<InjectedClassNameType>())
+          D = Injected->getDecl();
+      }
+      
+      if (D != NULL) {
+        CXCursor cursor = cxcursor::MakeCXCursor(D, *TU);
+        
+        CXCursorKind cursorKind = clang_getCursorKind(cursor);
+        CXString cursorUSR = clang_getCursorUSR(cursor);
+        
+        AllocatedResults.ContainerKind = cursorKind;
+        AllocatedResults.ContainerUSR = cursorUSR;
+        const Type *type = baseType.getTypePtrOrNull();
+        if (type != NULL) {
+          AllocatedResults.ContainerIsIncomplete = type->isIncompleteType();
+        }
+        else {
+          AllocatedResults.ContainerIsIncomplete = 1;
+        }
+      }
+      else {
+        AllocatedResults.ContainerKind = CXCursor_InvalidCode;
+        AllocatedResults.ContainerUSR = createCXString("");
+        AllocatedResults.ContainerIsIncomplete = 1;
+      }
     }
     
     virtual void ProcessOverloadCandidates(Sema &S, unsigned CurrentArg,
@@ -571,7 +627,7 @@
   Results->NumResults = 0;
   
   // Create a code-completion consumer to capture the results.
-  CaptureCompletionResults Capture(*Results);
+  CaptureCompletionResults Capture(*Results, &TU);
 
   // Perform completion.
   AST->CodeComplete(complete_filename, complete_line, complete_column,
@@ -731,6 +787,30 @@
   return Results->Contexts;
 }
 
+enum CXCursorKind clang_codeCompleteGetContainerKind(
+                                               CXCodeCompleteResults *ResultsIn,
+                                                     unsigned *IsIncomplete) {
+  AllocatedCXCodeCompleteResults *Results =
+    static_cast<AllocatedCXCodeCompleteResults *>(ResultsIn);
+  if (!Results)
+    return CXCursor_InvalidCode;
+  
+  if (IsIncomplete != NULL) {
+    *IsIncomplete = Results->ContainerIsIncomplete;
+  }
+  
+  return Results->ContainerKind;
+}
+  
+CXString clang_codeCompleteGetContainerUSR(CXCodeCompleteResults *ResultsIn) {
+  AllocatedCXCodeCompleteResults *Results =
+    static_cast<AllocatedCXCodeCompleteResults *>(ResultsIn);
+  if (!Results)
+    return createCXString("");
+  
+  return createCXString(clang_getCString(Results->ContainerUSR));
+}
+  
 } // end extern "C"
 
 /// \brief Simple utility function that appends a \p New string to the given
diff --git a/tools/libclang/libclang.darwin.exports b/tools/libclang/libclang.darwin.exports
index bfc5be9..87c5256 100644
--- a/tools/libclang/libclang.darwin.exports
+++ b/tools/libclang/libclang.darwin.exports
@@ -6,6 +6,8 @@
 _clang_codeCompleteAt
 _clang_codeCompleteGetDiagnostic
 _clang_codeCompleteGetNumDiagnostics
+_clang_codeCompleteGetContainerKind
+_clang_codeCompleteGetContainerUSR
 _clang_codeCompleteGetContexts
 _clang_constructUSR_ObjCCategory
 _clang_constructUSR_ObjCClass
diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports
index 47b7030..f82c190 100644
--- a/tools/libclang/libclang.exports
+++ b/tools/libclang/libclang.exports
@@ -6,6 +6,8 @@
 clang_codeCompleteAt
 clang_codeCompleteGetDiagnostic
 clang_codeCompleteGetNumDiagnostics
+clang_codeCompleteGetContainerKind
+clang_codeCompleteGetContainerUSR
 clang_codeCompleteGetContexts
 clang_constructUSR_ObjCCategory
 clang_constructUSR_ObjCClass