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>.

llvm-svn: 112296
This commit is contained in:
Ted Kremenek 2010-08-27 21:34:58 +00:00
parent 2c2c5f3789
commit ae9e221513
9 changed files with 132 additions and 5 deletions

View File

@ -1001,7 +1001,8 @@ enum CXCursorKind {
* referenced by the type of size is the typedef for size_type. * referenced by the type of size is the typedef for size_type.
*/ */
CXCursor_TypeRef = 43, CXCursor_TypeRef = 43,
CXCursor_LastRef = 43, CXCursor_CXXBaseSpecifier = 44,
CXCursor_LastRef = CXCursor_CXXBaseSpecifier,
/* Error conditions */ /* Error conditions */
CXCursor_FirstInvalid = 70, CXCursor_FirstInvalid = 70,
@ -1438,6 +1439,29 @@ CINDEX_LINKAGE CXType clang_getCursorResultType(CXCursor C);
*/ */
CINDEX_LINKAGE unsigned clang_isPODType(CXType T); 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);
/** /**
* @} * @}
*/ */

View File

@ -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 // 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: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] // 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: <invalid loc>:0:0: UnexposedStmt= Extent=[9:3 - 9:17] // CHECK: <invalid loc>:0:0: UnexposedStmt= Extent=[9:3 - 9:17]
// CHECK: load-stmts.cpp:9:8: UnexposedExpr= Extent=[9:8 - 9:10] // CHECK: load-stmts.cpp:9:8: UnexposedExpr= Extent=[9:8 - 9:10]
// CHECK: <invalid loc>:0:0: UnexposedStmt= Extent=[9:12 - 9:17] // CHECK: <invalid loc>: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: <invalid loc>:0:0: C++ base class specifier=class A:14:7 [access=public isVirtual=false]
// CHECK: <invalid loc>: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: <invalid loc>:0:0: C++ base class specifier=class C:22:7 [access=public isVirtual=true]
// CHECK: <invalid loc>:0:0: C++ base class specifier=class A:14:7 [access=private isVirtual=true]

View File

@ -204,6 +204,26 @@ static void PrintCursor(CXCursor Cursor) {
printf(" [IBOutletCollection=%s]", clang_getCString(S)); printf(" [IBOutletCollection=%s]", clang_getCString(S));
clang_disposeString(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");
}
} }
} }

View File

@ -285,6 +285,7 @@ public:
// Declaration visitors // Declaration visitors
bool VisitAttributes(Decl *D); bool VisitAttributes(Decl *D);
bool VisitBlockDecl(BlockDecl *B); bool VisitBlockDecl(BlockDecl *B);
bool VisitCXXRecordDecl(CXXRecordDecl *D);
bool VisitDeclContext(DeclContext *DC); bool VisitDeclContext(DeclContext *DC);
bool VisitTranslationUnitDecl(TranslationUnitDecl *D); bool VisitTranslationUnitDecl(TranslationUnitDecl *D);
bool VisitTypedefDecl(TypedefDecl *D); bool VisitTypedefDecl(TypedefDecl *D);
@ -1080,6 +1081,19 @@ bool CursorVisitor::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) {
return false; 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) { bool CursorVisitor::VisitBlockExpr(BlockExpr *B) {
return Visit(B->getBlockDecl()); return Visit(B->getBlockDecl());
} }
@ -1825,6 +1839,10 @@ CXString clang_getCursorSpelling(CXCursor C) {
assert(OID && "getCursorSpelling(): Missing protocol decl"); assert(OID && "getCursorSpelling(): Missing protocol decl");
return createCXString(OID->getIdentifier()->getNameStart()); return createCXString(OID->getIdentifier()->getNameStart());
} }
case CXCursor_CXXBaseSpecifier: {
CXXBaseSpecifier *B = getCursorCXXBaseSpecifier(C);
return createCXString(B->getType().getAsString());
}
case CXCursor_TypeRef: { case CXCursor_TypeRef: {
TypeDecl *Type = getCursorTypeRef(C).first; TypeDecl *Type = getCursorTypeRef(C).first;
assert(Type && "Missing type decl"); assert(Type && "Missing type decl");
@ -1953,6 +1971,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return createCXString("Namespace"); return createCXString("Namespace");
case CXCursor_LinkageSpec: case CXCursor_LinkageSpec:
return createCXString("LinkageSpec"); return createCXString("LinkageSpec");
case CXCursor_CXXBaseSpecifier:
return createCXString("C++ base class specifier");
} }
llvm_unreachable("Unhandled CXCursorKind"); llvm_unreachable("Unhandled CXCursorKind");
@ -2077,6 +2097,11 @@ CXSourceLocation clang_getCursorLocation(CXCursor C) {
return cxloc::translateSourceLocation(P.first->getASTContext(), P.second); 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: default:
// FIXME: Need a way to enumerate all non-reference cases. // FIXME: Need a way to enumerate all non-reference cases.
llvm_unreachable("Missed a reference kind"); llvm_unreachable("Missed a reference kind");
@ -2130,6 +2155,10 @@ static SourceRange getRawCursorExtent(CXCursor C) {
case CXCursor_TypeRef: case CXCursor_TypeRef:
return getCursorTypeRef(C).second; return getCursorTypeRef(C).second;
case CXCursor_CXXBaseSpecifier:
// FIXME: Figure out what source range to use for a CXBaseSpecifier.
return SourceRange();
default: default:
// FIXME: Need a way to enumerate all non-reference cases. // FIXME: Need a way to enumerate all non-reference cases.
llvm_unreachable("Missed a reference kind"); llvm_unreachable("Missed a reference kind");
@ -2203,6 +2232,12 @@ CXCursor clang_getCursorReferenced(CXCursor C) {
case CXCursor_TypeRef: case CXCursor_TypeRef:
return MakeCXCursor(getCursorTypeRef(C).first, CXXUnit); return MakeCXCursor(getCursorTypeRef(C).first, CXXUnit);
case CXCursor_CXXBaseSpecifier: {
CXXBaseSpecifier *B = cxcursor::getCursorCXXBaseSpecifier(C);
return clang_getTypeDeclaration(cxtype::MakeCXType(B->getType(),
CXXUnit));
}
default: default:
// We would prefer to enumerate all non-reference cursor kinds here. // We would prefer to enumerate all non-reference cursor kinds here.
llvm_unreachable("Unhandled reference cursor kind"); llvm_unreachable("Unhandled reference cursor kind");

View File

@ -21,6 +21,7 @@ set( LLVM_LINK_COMPONENTS
add_clang_library(libclang add_clang_library(libclang
CIndex.cpp CIndex.cpp
CIndexCXX.cpp
CIndexCodeCompletion.cpp CIndexCodeCompletion.cpp
CIndexDiagnostic.cpp CIndexDiagnostic.cpp
CIndexInclusionStack.cpp CIndexInclusionStack.cpp

View File

@ -302,6 +302,16 @@ cxcursor::getCursorTypeRef(CXCursor C) {
reinterpret_cast<uintptr_t>(C.data[1]))); 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, CXCursor cxcursor::MakePreprocessingDirectiveCursor(SourceRange Range,
ASTUnit *TU) { ASTUnit *TU) {
CXCursor C = { CXCursor_PreprocessingDirective, CXCursor C = { CXCursor_PreprocessingDirective,

View File

@ -23,6 +23,7 @@ namespace clang {
class ASTContext; class ASTContext;
class ASTUnit; class ASTUnit;
class Attr; class Attr;
class CXXBaseSpecifier;
class Decl; class Decl;
class Expr; class Expr;
class MacroDefinition; class MacroDefinition;
@ -75,6 +76,12 @@ CXCursor MakeCursorTypeRef(TypeDecl *Type, SourceLocation Loc, ASTUnit *TU);
/// and optionally the location where the reference occurred. /// and optionally the location where the reference occurred.
std::pair<TypeDecl *, SourceLocation> getCursorTypeRef(CXCursor C); 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. /// \brief Create a preprocessing directive cursor.
CXCursor MakePreprocessingDirectiveCursor(SourceRange Range, ASTUnit *TU); CXCursor MakePreprocessingDirectiveCursor(SourceRange Range, ASTUnit *TU);

View File

@ -14,8 +14,8 @@ _clang_createIndex
_clang_createTranslationUnit _clang_createTranslationUnit
_clang_createTranslationUnitFromSourceFile _clang_createTranslationUnitFromSourceFile
_clang_defaultCodeCompleteOptions _clang_defaultCodeCompleteOptions
_clang_defaultEditingTranslationUnitOptions
_clang_defaultDiagnosticDisplayOptions _clang_defaultDiagnosticDisplayOptions
_clang_defaultEditingTranslationUnitOptions
_clang_defaultReparseOptions _clang_defaultReparseOptions
_clang_defaultSaveOptions _clang_defaultSaveOptions
_clang_disposeCodeCompleteResults _clang_disposeCodeCompleteResults
@ -30,7 +30,7 @@ _clang_equalLocations
_clang_equalTypes _clang_equalTypes
_clang_formatDiagnostic _clang_formatDiagnostic
_clang_getCString _clang_getCString
_clang_getIBOutletCollectionType _clang_getCXXAccessSpecifier
_clang_getCanonicalType _clang_getCanonicalType
_clang_getClangVersion _clang_getClangVersion
_clang_getCompletionAvailability _clang_getCompletionAvailability
@ -48,8 +48,8 @@ _clang_getCursorLanguage
_clang_getCursorLinkage _clang_getCursorLinkage
_clang_getCursorLocation _clang_getCursorLocation
_clang_getCursorReferenced _clang_getCursorReferenced
_clang_getCursorSpelling
_clang_getCursorResultType _clang_getCursorResultType
_clang_getCursorSpelling
_clang_getCursorType _clang_getCursorType
_clang_getCursorUSR _clang_getCursorUSR
_clang_getDefinitionSpellingAndExtent _clang_getDefinitionSpellingAndExtent
@ -64,6 +64,7 @@ _clang_getDiagnosticSpelling
_clang_getFile _clang_getFile
_clang_getFileName _clang_getFileName
_clang_getFileTime _clang_getFileTime
_clang_getIBOutletCollectionType
_clang_getInclusions _clang_getInclusions
_clang_getInstantiationLocation _clang_getInstantiationLocation
_clang_getLocation _clang_getLocation
@ -89,12 +90,13 @@ _clang_isCursorDefinition
_clang_isDeclaration _clang_isDeclaration
_clang_isExpression _clang_isExpression
_clang_isInvalid _clang_isInvalid
_clang_isPreprocessing
_clang_isPODType _clang_isPODType
_clang_isPreprocessing
_clang_isReference _clang_isReference
_clang_isStatement _clang_isStatement
_clang_isTranslationUnit _clang_isTranslationUnit
_clang_isUnexposed _clang_isUnexposed
_clang_isVirtualBase
_clang_parseTranslationUnit _clang_parseTranslationUnit
_clang_reparseTranslationUnit _clang_reparseTranslationUnit
_clang_saveTranslationUnit _clang_saveTranslationUnit

View File

@ -30,6 +30,7 @@ clang_equalLocations
clang_equalTypes clang_equalTypes
clang_formatDiagnostic clang_formatDiagnostic
clang_getCString clang_getCString
clang_getCXXAccessSpecifier
clang_getCanonicalType clang_getCanonicalType
clang_getClangVersion clang_getClangVersion
clang_getCompletionAvailability clang_getCompletionAvailability
@ -95,6 +96,7 @@ clang_isReference
clang_isStatement clang_isStatement
clang_isTranslationUnit clang_isTranslationUnit
clang_isUnexposed clang_isUnexposed
clang_isVirtualBase
clang_parseTranslationUnit clang_parseTranslationUnit
clang_reparseTranslationUnit clang_reparseTranslationUnit
clang_saveTranslationUnit clang_saveTranslationUnit