Implement CXCursor support for walking C++ base specifiers.  This includes adding the API hooks clang_isVirtualBase() and clang_getCXXAccessSpecifier() to query properties of the base specifier.

Implements <rdar://problem/8274883>.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@112296 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 67e0c77..cdf0cd0 100644
--- a/tools/c-index-test/c-index-test.c
+++ b/tools/c-index-test/c-index-test.c
@@ -204,6 +204,26 @@
       printf(" [IBOutletCollection=%s]", clang_getCString(S));
       clang_disposeString(S);
     }
+    
+    if (Cursor.kind == CXCursor_CXXBaseSpecifier) {
+      enum CX_CXXAccessSpecifier access = clang_getCXXAccessSpecifier(Cursor);
+      unsigned isVirtual = clang_isVirtualBase(Cursor);
+      const char *accessStr = 0;
+
+      switch (access) {
+        case CX_CXXInvalidAccessSpecifier:
+          accessStr = "invalid"; break;
+        case CX_CXXPublic:
+          accessStr = "public"; break;
+        case CX_CXXProtected:
+          accessStr = "protected"; break;
+        case CX_CXXPrivate:
+          accessStr = "private"; break;
+      }      
+      
+      printf(" [access=%s isVirtual=%s]", accessStr,
+             isVirtual ? "true" : "false");
+    }
   }
 }
 
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index 4ec2bf4..2361f42 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -285,6 +285,7 @@
   // Declaration visitors
   bool VisitAttributes(Decl *D);
   bool VisitBlockDecl(BlockDecl *B);
+  bool VisitCXXRecordDecl(CXXRecordDecl *D);
   bool VisitDeclContext(DeclContext *DC);
   bool VisitTranslationUnitDecl(TranslationUnitDecl *D);
   bool VisitTypedefDecl(TypedefDecl *D);
@@ -1080,6 +1081,19 @@
   return false;
 }
 
+bool CursorVisitor::VisitCXXRecordDecl(CXXRecordDecl *D) {
+  if (D->isDefinition()) {
+    for (CXXRecordDecl::base_class_iterator I = D->bases_begin(),
+         E = D->bases_end(); I != E; ++I) {
+      if (Visit(cxcursor::MakeCursorCXXBaseSpecifier(I, TU)))
+        return true;
+    }
+  }
+
+  return VisitTagDecl(D);
+}
+
+
 bool CursorVisitor::VisitBlockExpr(BlockExpr *B) {
   return Visit(B->getBlockDecl());
 }
@@ -1825,6 +1839,10 @@
       assert(OID && "getCursorSpelling(): Missing protocol decl");
       return createCXString(OID->getIdentifier()->getNameStart());
     }
+    case CXCursor_CXXBaseSpecifier: {
+      CXXBaseSpecifier *B = getCursorCXXBaseSpecifier(C);
+      return createCXString(B->getType().getAsString());
+    }
     case CXCursor_TypeRef: {
       TypeDecl *Type = getCursorTypeRef(C).first;
       assert(Type && "Missing type decl");
@@ -1953,6 +1971,8 @@
     return createCXString("Namespace");
   case CXCursor_LinkageSpec:
     return createCXString("LinkageSpec");
+  case CXCursor_CXXBaseSpecifier:
+    return createCXString("C++ base class specifier");  
   }
 
   llvm_unreachable("Unhandled CXCursorKind");
@@ -2076,6 +2096,11 @@
       std::pair<TypeDecl *, SourceLocation> P = getCursorTypeRef(C);
       return cxloc::translateSourceLocation(P.first->getASTContext(), P.second);
     }
+    
+    case CXCursor_CXXBaseSpecifier: {
+      // FIXME: Figure out what location to return for a CXXBaseSpecifier.
+      return clang_getNullLocation();
+    }
 
     default:
       // FIXME: Need a way to enumerate all non-reference cases.
@@ -2129,6 +2154,10 @@
 
     case CXCursor_TypeRef:
       return getCursorTypeRef(C).second;
+      
+    case CXCursor_CXXBaseSpecifier:
+      // FIXME: Figure out what source range to use for a CXBaseSpecifier.
+      return SourceRange();
 
     default:
       // FIXME: Need a way to enumerate all non-reference cases.
@@ -2202,6 +2231,12 @@
 
     case CXCursor_TypeRef:
       return MakeCXCursor(getCursorTypeRef(C).first, CXXUnit);
+      
+    case CXCursor_CXXBaseSpecifier: {
+      CXXBaseSpecifier *B = cxcursor::getCursorCXXBaseSpecifier(C);
+      return clang_getTypeDeclaration(cxtype::MakeCXType(B->getType(),
+                                                         CXXUnit));
+    }
 
     default:
       // We would prefer to enumerate all non-reference cursor kinds here.
diff --git a/tools/libclang/CMakeLists.txt b/tools/libclang/CMakeLists.txt
index dbb28ec..29ef574 100644
--- a/tools/libclang/CMakeLists.txt
+++ b/tools/libclang/CMakeLists.txt
@@ -21,6 +21,7 @@
 
 add_clang_library(libclang
   CIndex.cpp
+  CIndexCXX.cpp
   CIndexCodeCompletion.cpp
   CIndexDiagnostic.cpp
   CIndexInclusionStack.cpp
diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp
index 318fd51..40f91a7 100644
--- a/tools/libclang/CXCursor.cpp
+++ b/tools/libclang/CXCursor.cpp
@@ -302,6 +302,16 @@
                                       reinterpret_cast<uintptr_t>(C.data[1])));
 }
 
+CXCursor cxcursor::MakeCursorCXXBaseSpecifier(CXXBaseSpecifier *B, ASTUnit *TU){
+  CXCursor C = { CXCursor_CXXBaseSpecifier, { B, 0, TU } };
+  return C;  
+}
+
+CXXBaseSpecifier *cxcursor::getCursorCXXBaseSpecifier(CXCursor C) {
+  assert(C.kind == CXCursor_CXXBaseSpecifier);
+  return static_cast<CXXBaseSpecifier*>(C.data[0]);
+}
+
 CXCursor cxcursor::MakePreprocessingDirectiveCursor(SourceRange Range, 
                                                     ASTUnit *TU) {
   CXCursor C = { CXCursor_PreprocessingDirective, 
diff --git a/tools/libclang/CXCursor.h b/tools/libclang/CXCursor.h
index 5a8428a..958e331 100644
--- a/tools/libclang/CXCursor.h
+++ b/tools/libclang/CXCursor.h
@@ -23,6 +23,7 @@
 class ASTContext;
 class ASTUnit;
 class Attr;
+class CXXBaseSpecifier;
 class Decl;
 class Expr;
 class MacroDefinition;
@@ -75,6 +76,12 @@
 /// and optionally the location where the reference occurred.
 std::pair<TypeDecl *, SourceLocation> getCursorTypeRef(CXCursor C);
 
+/// \brief Create a CXX base specifier cursor.
+CXCursor MakeCursorCXXBaseSpecifier(CXXBaseSpecifier *B, ASTUnit *TU);
+
+/// \brief Unpack a CXXBaseSpecifier cursor into a CXXBaseSpecifier.
+CXXBaseSpecifier *getCursorCXXBaseSpecifier(CXCursor C);
+
 /// \brief Create a preprocessing directive cursor.
 CXCursor MakePreprocessingDirectiveCursor(SourceRange Range, ASTUnit *TU);
 
diff --git a/tools/libclang/libclang.darwin.exports b/tools/libclang/libclang.darwin.exports
index d779190..0d01dd9 100644
--- a/tools/libclang/libclang.darwin.exports
+++ b/tools/libclang/libclang.darwin.exports
@@ -14,8 +14,8 @@
 _clang_createTranslationUnit
 _clang_createTranslationUnitFromSourceFile
 _clang_defaultCodeCompleteOptions
-_clang_defaultEditingTranslationUnitOptions
 _clang_defaultDiagnosticDisplayOptions
+_clang_defaultEditingTranslationUnitOptions
 _clang_defaultReparseOptions
 _clang_defaultSaveOptions
 _clang_disposeCodeCompleteResults
@@ -30,7 +30,7 @@
 _clang_equalTypes
 _clang_formatDiagnostic
 _clang_getCString
-_clang_getIBOutletCollectionType
+_clang_getCXXAccessSpecifier
 _clang_getCanonicalType
 _clang_getClangVersion
 _clang_getCompletionAvailability
@@ -48,8 +48,8 @@
 _clang_getCursorLinkage
 _clang_getCursorLocation
 _clang_getCursorReferenced
-_clang_getCursorSpelling
 _clang_getCursorResultType
+_clang_getCursorSpelling
 _clang_getCursorType
 _clang_getCursorUSR
 _clang_getDefinitionSpellingAndExtent
@@ -64,6 +64,7 @@
 _clang_getFile
 _clang_getFileName
 _clang_getFileTime
+_clang_getIBOutletCollectionType
 _clang_getInclusions
 _clang_getInstantiationLocation
 _clang_getLocation
@@ -89,12 +90,13 @@
 _clang_isDeclaration
 _clang_isExpression
 _clang_isInvalid
-_clang_isPreprocessing
 _clang_isPODType
+_clang_isPreprocessing
 _clang_isReference
 _clang_isStatement
 _clang_isTranslationUnit
 _clang_isUnexposed
+_clang_isVirtualBase
 _clang_parseTranslationUnit
 _clang_reparseTranslationUnit
 _clang_saveTranslationUnit
diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports
index df93a79..60d3352 100644
--- a/tools/libclang/libclang.exports
+++ b/tools/libclang/libclang.exports
@@ -30,6 +30,7 @@
 clang_equalTypes
 clang_formatDiagnostic
 clang_getCString
+clang_getCXXAccessSpecifier
 clang_getCanonicalType
 clang_getClangVersion
 clang_getCompletionAvailability
@@ -95,6 +96,7 @@
 clang_isStatement
 clang_isTranslationUnit
 clang_isUnexposed
+clang_isVirtualBase
 clang_parseTranslationUnit
 clang_reparseTranslationUnit
 clang_saveTranslationUnit