From 3064ef9e604d19a0cfd0d8e3ed3055bfd83f88fd Mon Sep 17 00:00:00 2001 From: Ted Kremenek Date: Fri, 27 Aug 2010 21:34:58 +0000 Subject: [PATCH] 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 . git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@112296 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang-c/Index.h | 26 ++++++++++++++++++- test/Index/load-stmts.cpp | 26 +++++++++++++++++++ tools/c-index-test/c-index-test.c | 20 +++++++++++++++ tools/libclang/CIndex.cpp | 35 ++++++++++++++++++++++++++ tools/libclang/CMakeLists.txt | 1 + tools/libclang/CXCursor.cpp | 10 ++++++++ tools/libclang/CXCursor.h | 7 ++++++ tools/libclang/libclang.darwin.exports | 10 +++++--- tools/libclang/libclang.exports | 2 ++ 9 files changed, 132 insertions(+), 5 deletions(-) diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h index 064bd21909..3f0dabf1c5 100644 --- a/include/clang-c/Index.h +++ b/include/clang-c/Index.h @@ -1001,7 +1001,8 @@ enum CXCursorKind { * referenced by the type of size is the typedef for size_type. */ CXCursor_TypeRef = 43, - CXCursor_LastRef = 43, + CXCursor_CXXBaseSpecifier = 44, + CXCursor_LastRef = CXCursor_CXXBaseSpecifier, /* Error conditions */ CXCursor_FirstInvalid = 70, @@ -1438,6 +1439,29 @@ CINDEX_LINKAGE CXType clang_getCursorResultType(CXCursor C); */ CINDEX_LINKAGE unsigned clang_isPODType(CXType T); +/** + * \brief Returns 1 if the base class specified by the cursor with kind + * CX_CXXBaseSpecifier is virtual. + */ +CINDEX_LINKAGE unsigned clang_isVirtualBase(CXCursor); + +/** + * \brief Represents the C++ access control level to a base class for a + * cursor with kind CX_CXXBaseSpecifier. + */ +enum CX_CXXAccessSpecifier { + CX_CXXInvalidAccessSpecifier, + CX_CXXPublic, + CX_CXXProtected, + CX_CXXPrivate +}; + +/** + * \brief Returns the access control level for the C++ base specifier + * represented by a cursor with kind CX_CXXBaseSpecifier. + */ +CINDEX_LINKAGE enum CX_CXXAccessSpecifier clang_getCXXAccessSpecifier(CXCursor); + /** * @} */ diff --git a/test/Index/load-stmts.cpp b/test/Index/load-stmts.cpp index cb99aee3ad..efde248a1d 100644 --- a/test/Index/load-stmts.cpp +++ b/test/Index/load-stmts.cpp @@ -10,6 +10,21 @@ void f(int x) { } } +// Test handling of C++ base specifiers. +class A { + void doA(); +}; + +class B { + void doB(); +}; + +class C : public A, private B { + void doC(); +}; + +class D : virtual public C, virtual private A {}; + // RUN: c-index-test -test-load-source all %s | FileCheck %s // CHECK: load-stmts.cpp:1:13: TypedefDecl=T:1:13 (Definition) Extent=[1:13 - 1:14] // CHECK: load-stmts.cpp:2:8: StructDecl=X:2:8 (Definition) Extent=[2:1 - 2:23] @@ -56,4 +71,15 @@ void f(int x) { // CHECK: :0:0: UnexposedStmt= Extent=[9:3 - 9:17] // CHECK: load-stmts.cpp:9:8: UnexposedExpr= Extent=[9:8 - 9:10] // CHECK: :0:0: UnexposedStmt= Extent=[9:12 - 9:17] +// CHECK: load-stmts.cpp:14:7: ClassDecl=A:14:7 (Definition) Extent=[14:1 - 16:2] +// CHECK: load-stmts.cpp:15:8: CXXMethod=doA:15:8 Extent=[15:8 - 15:13] +// CHECK: load-stmts.cpp:18:7: ClassDecl=B:18:7 (Definition) Extent=[18:1 - 20:2] +// CHECK: load-stmts.cpp:19:8: CXXMethod=doB:19:8 Extent=[19:8 - 19:13] +// CHECK: load-stmts.cpp:22:7: ClassDecl=C:22:7 (Definition) Extent=[22:1 - 24:2] +// CHECK: :0:0: C++ base class specifier=class A:14:7 [access=public isVirtual=false] +// CHECK: :0:0: C++ base class specifier=class B:18:7 [access=private isVirtual=false] +// CHECK: load-stmts.cpp:23:8: CXXMethod=doC:23:8 Extent=[23:8 - 23:13] +// CHECK: load-stmts.cpp:26:7: ClassDecl=D:26:7 (Definition) Extent=[26:1 - 26:49] +// CHECK: :0:0: C++ base class specifier=class C:22:7 [access=public isVirtual=true] +// CHECK: :0:0: C++ base class specifier=class A:14:7 [access=private isVirtual=true] diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c index 67e0c7724f..cdf0cd06b5 100644 --- a/tools/c-index-test/c-index-test.c +++ b/tools/c-index-test/c-index-test.c @@ -204,6 +204,26 @@ static void PrintCursor(CXCursor Cursor) { 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 4ec2bf4c29..2361f421a4 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -285,6 +285,7 @@ public: // 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 @@ bool CursorVisitor::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) { 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 @@ CXString clang_getCursorSpelling(CXCursor C) { 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 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) { 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 @@ CXSourceLocation clang_getCursorLocation(CXCursor C) { std::pair 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 @@ static SourceRange getRawCursorExtent(CXCursor C) { 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 @@ CXCursor clang_getCursorReferenced(CXCursor C) { 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 dbb28ec3bb..29ef574fff 100644 --- a/tools/libclang/CMakeLists.txt +++ b/tools/libclang/CMakeLists.txt @@ -21,6 +21,7 @@ set( LLVM_LINK_COMPONENTS 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 318fd51dfb..40f91a7383 100644 --- a/tools/libclang/CXCursor.cpp +++ b/tools/libclang/CXCursor.cpp @@ -302,6 +302,16 @@ cxcursor::getCursorTypeRef(CXCursor C) { reinterpret_cast(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(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 5a8428a2ec..958e331674 100644 --- a/tools/libclang/CXCursor.h +++ b/tools/libclang/CXCursor.h @@ -23,6 +23,7 @@ namespace clang { class ASTContext; class ASTUnit; class Attr; +class CXXBaseSpecifier; class Decl; class Expr; class MacroDefinition; @@ -75,6 +76,12 @@ CXCursor MakeCursorTypeRef(TypeDecl *Type, SourceLocation Loc, ASTUnit *TU); /// and optionally the location where the reference occurred. std::pair 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 d779190cc1..0d01dd9b28 100644 --- a/tools/libclang/libclang.darwin.exports +++ b/tools/libclang/libclang.darwin.exports @@ -14,8 +14,8 @@ _clang_createIndex _clang_createTranslationUnit _clang_createTranslationUnitFromSourceFile _clang_defaultCodeCompleteOptions -_clang_defaultEditingTranslationUnitOptions _clang_defaultDiagnosticDisplayOptions +_clang_defaultEditingTranslationUnitOptions _clang_defaultReparseOptions _clang_defaultSaveOptions _clang_disposeCodeCompleteResults @@ -30,7 +30,7 @@ _clang_equalLocations _clang_equalTypes _clang_formatDiagnostic _clang_getCString -_clang_getIBOutletCollectionType +_clang_getCXXAccessSpecifier _clang_getCanonicalType _clang_getClangVersion _clang_getCompletionAvailability @@ -48,8 +48,8 @@ _clang_getCursorLanguage _clang_getCursorLinkage _clang_getCursorLocation _clang_getCursorReferenced -_clang_getCursorSpelling _clang_getCursorResultType +_clang_getCursorSpelling _clang_getCursorType _clang_getCursorUSR _clang_getDefinitionSpellingAndExtent @@ -64,6 +64,7 @@ _clang_getDiagnosticSpelling _clang_getFile _clang_getFileName _clang_getFileTime +_clang_getIBOutletCollectionType _clang_getInclusions _clang_getInstantiationLocation _clang_getLocation @@ -89,12 +90,13 @@ _clang_isCursorDefinition _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 df93a799f7..60d335299e 100644 --- a/tools/libclang/libclang.exports +++ b/tools/libclang/libclang.exports @@ -30,6 +30,7 @@ clang_equalLocations clang_equalTypes clang_formatDiagnostic clang_getCString +clang_getCXXAccessSpecifier clang_getCanonicalType clang_getClangVersion clang_getCompletionAvailability @@ -95,6 +96,7 @@ clang_isReference clang_isStatement clang_isTranslationUnit clang_isUnexposed +clang_isVirtualBase clang_parseTranslationUnit clang_reparseTranslationUnit clang_saveTranslationUnit -- 2.40.0