aboutsummaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>2013-04-11 01:20:11 +0000
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>2013-04-11 01:20:11 +0000
commit411d33aa0b0d3bc9b2faec40cd821bdd836094ab (patch)
treead773459e753fb37a1418cf90c351148e0a698c1 /tools
parent1fd1e288d0f45b86d191d8f53f569e5143f3a18a (diff)
[libclang] Expose record layout info via new libclang functions:
clang_Type_getAlignOf clang_Type_getSizeOf clang_Type_getOffsetOf clang_Cursor_isBitField Patch by Loïc Jaquemet! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@179251 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'tools')
-rw-r--r--tools/c-index-test/c-index-test.c59
-rw-r--r--tools/libclang/CXType.cpp120
-rw-r--r--tools/libclang/libclang.exports4
3 files changed, 183 insertions, 0 deletions
diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c
index ce9e4910ae..e97cb30589 100644
--- a/tools/c-index-test/c-index-test.c
+++ b/tools/c-index-test/c-index-test.c
@@ -1144,6 +1144,61 @@ static enum CXChildVisitResult PrintType(CXCursor cursor, CXCursor p,
return CXChildVisit_Recurse;
}
+static enum CXChildVisitResult PrintTypeSize(CXCursor cursor, CXCursor p,
+ CXClientData d) {
+ CXType T;
+ enum CXCursorKind K = clang_getCursorKind(cursor);
+ if (clang_isInvalid(K))
+ return CXChildVisit_Recurse;
+ T = clang_getCursorType(cursor);
+ PrintCursor(cursor, NULL);
+ PrintTypeAndTypeKind(T, " [type=%s] [typekind=%s]");
+ /* Print the type sizeof if applicable. */
+ {
+ long long Size = clang_Type_getSizeOf(T);
+ if (Size >= 0 || Size < -1 ) {
+ printf(" [sizeof=%lld]", Size);
+ }
+ }
+ /* Print the type alignof if applicable. */
+ {
+ long long Align = clang_Type_getAlignOf(T);
+ if (Align >= 0 || Align < -1) {
+ printf(" [alignof=%lld]", Align);
+ }
+ }
+ /* Print the record field offset if applicable. */
+ {
+ const char *FieldName = clang_getCString(clang_getCursorSpelling(cursor));
+ /* recurse to get the root anonymous record parent */
+ CXCursor Parent, Root;
+ if (clang_getCursorKind(cursor) == CXCursor_FieldDecl ) {
+ const char *RootParentName;
+ Root = Parent = p;
+ do {
+ Root = Parent;
+ RootParentName = clang_getCString(clang_getCursorSpelling(Root));
+ Parent = clang_getCursorSemanticParent(Root);
+ } while ( clang_getCursorType(Parent).kind == CXType_Record &&
+ !strcmp(RootParentName, "") );
+ /* if RootParentName is "", record is anonymous. */
+ {
+ long long Offset = clang_Type_getOffsetOf(clang_getCursorType(Root),
+ FieldName);
+ printf(" [offsetof=%lld]", Offset);
+ }
+ }
+ }
+ /* Print if its a bitfield */
+ {
+ int IsBitfield = clang_Cursor_isBitField(cursor);
+ if (IsBitfield)
+ printf(" [BitFieldSize=%d]", clang_getFieldDeclBitWidth(cursor));
+ }
+ printf("\n");
+ return CXChildVisit_Recurse;
+}
+
/******************************************************************************/
/* Bitwidth testing. */
/******************************************************************************/
@@ -3642,6 +3697,7 @@ static void print_usage(void) {
fprintf(stderr,
" c-index-test -test-print-linkage-source {<args>}*\n"
" c-index-test -test-print-type {<args>}*\n"
+ " c-index-test -test-print-type-size {<args>}*\n"
" c-index-test -test-print-bitwidth {<args>}*\n"
" c-index-test -print-usr [<CursorKind> {<args>}]*\n"
" c-index-test -print-usr-file <file>\n"
@@ -3728,6 +3784,9 @@ int cindextest_main(int argc, const char **argv) {
else if (argc > 2 && strcmp(argv[1], "-test-print-type") == 0)
return perform_test_load_source(argc - 2, argv + 2, "all",
PrintType, 0);
+ else if (argc > 2 && strcmp(argv[1], "-test-print-type-size") == 0)
+ return perform_test_load_source(argc - 2, argv + 2, "all",
+ PrintTypeSize, 0);
else if (argc > 2 && strcmp(argv[1], "-test-print-bitwidth") == 0)
return perform_test_load_source(argc - 2, argv + 2, "all",
PrintBitWidth, 0);
diff --git a/tools/libclang/CXType.cpp b/tools/libclang/CXType.cpp
index 6f87fc51a4..16009bf47a 100644
--- a/tools/libclang/CXType.cpp
+++ b/tools/libclang/CXType.cpp
@@ -651,6 +651,126 @@ long long clang_getArraySize(CXType CT) {
return result;
}
+long long clang_Type_getAlignOf(CXType T) {
+ if (T.kind == CXType_Invalid)
+ return CXTypeLayoutError_Invalid;
+ ASTContext &Ctx = cxtu::getASTUnit(GetTU(T))->getASTContext();
+ QualType QT = GetQualType(T);
+ // [expr.alignof] p1: return size_t value for complete object type, reference
+ // or array.
+ // [expr.alignof] p3: if reference type, return size of referenced type
+ if (QT->isReferenceType())
+ QT = QT.getNonReferenceType();
+ if (QT->isIncompleteType())
+ return CXTypeLayoutError_Incomplete;
+ if (QT->isDependentType())
+ return CXTypeLayoutError_Dependent;
+ // Exceptions by GCC extension - see ASTContext.cpp:1313 getTypeInfoImpl
+ // if (QT->isFunctionType()) return 4; // Bug #15511 - should be 1
+ // if (QT->isVoidType()) return 1;
+ return Ctx.getTypeAlignInChars(QT).getQuantity();
+}
+
+long long clang_Type_getSizeOf(CXType T) {
+ if (T.kind == CXType_Invalid)
+ return CXTypeLayoutError_Invalid;
+ ASTContext &Ctx = cxtu::getASTUnit(GetTU(T))->getASTContext();
+ QualType QT = GetQualType(T);
+ // [expr.sizeof] p2: if reference type, return size of referenced type
+ if (QT->isReferenceType())
+ QT = QT.getNonReferenceType();
+ // [expr.sizeof] p1: return -1 on: func, incomplete, bitfield, incomplete
+ // enumeration
+ // Note: We get the cxtype, not the cxcursor, so we can't call
+ // FieldDecl->isBitField()
+ // [expr.sizeof] p3: pointer ok, function not ok.
+ // [gcc extension] lib/AST/ExprConstant.cpp:1372 HandleSizeof : vla == error
+ if (QT->isIncompleteType())
+ return CXTypeLayoutError_Incomplete;
+ if (QT->isDependentType())
+ return CXTypeLayoutError_Dependent;
+ if (!QT->isConstantSizeType())
+ return CXTypeLayoutError_NotConstantSize;
+ // [gcc extension] lib/AST/ExprConstant.cpp:1372
+ // HandleSizeof : {voidtype,functype} == 1
+ // not handled by ASTContext.cpp:1313 getTypeInfoImpl
+ if (QT->isVoidType() || QT->isFunctionType())
+ return 1;
+ return Ctx.getTypeSizeInChars(QT).getQuantity();
+}
+
+static long long visitRecordForValidation(const RecordDecl *RD) {
+ for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
+ I != E; ++I){
+ QualType FQT = (*I)->getType();
+ if (FQT->isIncompleteType())
+ return CXTypeLayoutError_Incomplete;
+ if (FQT->isDependentType())
+ return CXTypeLayoutError_Dependent;
+ // recurse
+ if (const RecordType *ChildType = (*I)->getType()->getAs<RecordType>()) {
+ if (const RecordDecl *Child = ChildType->getDecl()) {
+ long long ret = visitRecordForValidation(Child);
+ if (ret < 0)
+ return ret;
+ }
+ }
+ // else try next field
+ }
+ return 0;
+}
+
+long long clang_Type_getOffsetOf(CXType PT, const char *S) {
+ // check that PT is not incomplete/dependent
+ CXCursor PC = clang_getTypeDeclaration(PT);
+ if (clang_isInvalid(PC.kind))
+ return CXTypeLayoutError_Invalid;
+ const RecordDecl *RD =
+ dyn_cast_or_null<RecordDecl>(cxcursor::getCursorDecl(PC));
+ if (!RD)
+ return CXTypeLayoutError_Invalid;
+ RD = RD->getDefinition();
+ if (!RD)
+ return CXTypeLayoutError_Incomplete;
+ QualType RT = GetQualType(PT);
+ if (RT->isIncompleteType())
+ return CXTypeLayoutError_Incomplete;
+ if (RT->isDependentType())
+ return CXTypeLayoutError_Dependent;
+ // We recurse into all record fields to detect incomplete and dependent types.
+ long long Error = visitRecordForValidation(RD);
+ if (Error < 0)
+ return Error;
+ if (!S)
+ return CXTypeLayoutError_InvalidFieldName;
+ // lookup field
+ ASTContext &Ctx = cxtu::getASTUnit(GetTU(PT))->getASTContext();
+ IdentifierInfo *II = &Ctx.Idents.get(S);
+ DeclarationName FieldName(II);
+ RecordDecl::lookup_const_result Res = RD->lookup(FieldName);
+ // If a field of the parent record is incomplete, lookup will fail.
+ // and we would return InvalidFieldName instead of Incomplete.
+ // But this erroneous results does protects again a hidden assertion failure
+ // in the RecordLayoutBuilder
+ if (Res.size() != 1)
+ return CXTypeLayoutError_InvalidFieldName;
+ if (const FieldDecl *FD = dyn_cast<FieldDecl>(Res.front()))
+ return Ctx.getFieldOffset(FD);
+ if (const IndirectFieldDecl *IFD = dyn_cast<IndirectFieldDecl>(Res.front()))
+ return Ctx.getFieldOffset(IFD);
+ // we don't want any other Decl Type.
+ return CXTypeLayoutError_InvalidFieldName;
+}
+
+unsigned clang_Cursor_isBitField(CXCursor C) {
+ if (!clang_isDeclaration(C.kind))
+ return 0;
+ const FieldDecl *FD = dyn_cast_or_null<FieldDecl>(cxcursor::getCursorDecl(C));
+ if (!FD)
+ return 0;
+ return FD->isBitField();
+}
+
CXString clang_getDeclObjCTypeEncoding(CXCursor C) {
if (!clang_isDeclaration(C.kind))
return cxstring::createEmpty();
diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports
index d99f24ef03..1f179f13bd 100644
--- a/tools/libclang/libclang.exports
+++ b/tools/libclang/libclang.exports
@@ -14,6 +14,7 @@ clang_Cursor_getObjCSelectorIndex
clang_Cursor_getSpellingNameRange
clang_Cursor_getTranslationUnit
clang_Cursor_getReceiverType
+clang_Cursor_isBitField
clang_Cursor_isDynamicCall
clang_Cursor_isNull
clang_Cursor_getModule
@@ -53,6 +54,9 @@ clang_TParamCommandComment_getParamName
clang_TParamCommandComment_isParamPositionValid
clang_TParamCommandComment_getDepth
clang_TParamCommandComment_getIndex
+clang_Type_getAlignOf
+clang_Type_getSizeOf
+clang_Type_getOffsetOf
clang_VerbatimBlockLineComment_getText
clang_VerbatimLineComment_getText
clang_HTMLTagComment_getAsString