From 0035372bb7b3c4512a66cddc264a3418b642a826 Mon Sep 17 00:00:00 2001 From: Dmitri Gribenko Date: Fri, 15 Feb 2013 21:15:49 +0000 Subject: [PATCH] libclang: add clang_getTypeSpelling(CXType CT) Adds a function clang_getTypeSpelling(CXType CT) that returns a CXString containing the underlying type. Patch by Ben Gertzfield. llvm-svn: 175299 --- clang/include/clang-c/Index.h | 10 +++++- clang/test/Index/print-type.c | 44 ++++++++++++++++++++++++++ clang/test/Index/print-type.cpp | 56 +++++++++++++++++++++++++++++++++ clang/test/Index/print-type.m | 10 ++++++ clang/test/Index/print-typekind.c | 28 ----------------- clang/test/Index/print-typekind.m | 10 ------ clang/test/Index/vector-types.c | 6 ---- clang/tools/c-index-test/c-index-test.c | 38 ++++++++++++---------- clang/tools/libclang/CXType.cpp | 15 +++++++++ clang/tools/libclang/libclang.exports | 1 + 10 files changed, 156 insertions(+), 62 deletions(-) create mode 100644 clang/test/Index/print-type.c create mode 100644 clang/test/Index/print-type.cpp create mode 100644 clang/test/Index/print-type.m delete mode 100644 clang/test/Index/print-typekind.c delete mode 100644 clang/test/Index/print-typekind.m delete mode 100644 clang/test/Index/vector-types.c diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h index 2a66e7a..c382fb1 100644 --- a/clang/include/clang-c/Index.h +++ b/clang/include/clang-c/Index.h @@ -32,7 +32,7 @@ * compatible, thus CINDEX_VERSION_MAJOR is expected to remain stable. */ #define CINDEX_VERSION_MAJOR 0 -#define CINDEX_VERSION_MINOR 11 +#define CINDEX_VERSION_MINOR 12 #define CINDEX_VERSION_ENCODE(major, minor) ( \ ((major) * 10000) \ @@ -2695,6 +2695,14 @@ typedef struct { CINDEX_LINKAGE CXType clang_getCursorType(CXCursor C); /** + * \brief Pretty-print the underlying type using the rules of the + * language of the translation unit from which it came. + * + * If the type is invalid, an empty string is returned. + */ +CINDEX_LINKAGE CXString clang_getTypeSpelling(CXType CT); + +/** * \brief Retrieve the underlying type of a typedef declaration. * * If the cursor does not reference a typedef declaration, an invalid type is diff --git a/clang/test/Index/print-type.c b/clang/test/Index/print-type.c new file mode 100644 index 0000000..9358772d --- /dev/null +++ b/clang/test/Index/print-type.c @@ -0,0 +1,44 @@ +typedef int FooType; +int *p; +int *f(int *p, char *x, FooType z, int arr[5], void (*fn)(int)) { + fn(*p); + const FooType w = z; + return p + z + arr[3]; +} +typedef double OtherType; +typedef int ArrayType[5]; +int __attribute__((vector_size(16))) x; +typedef int __attribute__((vector_size(16))) int4_t; + +// RUN: c-index-test -test-print-type %s | FileCheck %s +// CHECK: FunctionDecl=f:3:6 (Definition) [type=int *(int *, char *, FooType, int *, void (*)(int))] [typekind=FunctionProto] [canonicaltype=int *(int *, char *, int, int *, void (*)(int))] [canonicaltypekind=FunctionProto] [resulttype=int *] [resulttypekind=Pointer] [args= [int *] [Pointer] [char *] [Pointer] [FooType] [Typedef] [int *] [Pointer] [void (*)(int)] [Pointer]] [isPOD=0] +// CHECK: ParmDecl=p:3:13 (Definition) [type=int *] [typekind=Pointer] [isPOD=1] +// CHECK: ParmDecl=x:3:22 (Definition) [type=char *] [typekind=Pointer] [isPOD=1] +// CHECK: ParmDecl=z:3:33 (Definition) [type=FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1] +// CHECK: TypeRef=FooType:1:13 [type=FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1] +// CHECK: ParmDecl=arr:3:40 (Definition) [type=int *] [typekind=Pointer] [isPOD=1] +// CHECK: IntegerLiteral= [type=int] [typekind=Int] [isPOD=1] +// CHECK: ParmDecl=fn:3:55 (Definition) [type=void (*)(int)] [typekind=Pointer] [canonicaltype=void (*)(int)] [canonicaltypekind=Pointer] [isPOD=1] +// CHECK: ParmDecl=:3:62 (Definition) [type=int] [typekind=Int] [isPOD=1] +// CHECK: CompoundStmt= [type=] [typekind=Invalid] [isPOD=0] +// CHECK: CallExpr=fn:3:55 [type=void] [typekind=Void] [isPOD=0] +// CHECK: DeclRefExpr=fn:3:55 [type=void (*)(int)] [typekind=Pointer] [canonicaltype=void (*)(int)] [canonicaltypekind=Pointer] [isPOD=1] +// CHECK: UnaryOperator= [type=int] [typekind=Int] [isPOD=1] +// CHECK: DeclRefExpr=p:3:13 [type=int *] [typekind=Pointer] [isPOD=1] +// CHECK: DeclStmt= [type=] [typekind=Invalid] [isPOD=0] +// CHECK: VarDecl=w:5:17 (Definition) [type=const FooType] [typekind=Typedef] const [canonicaltype=const int] [canonicaltypekind=Int] [isPOD=1] +// CHECK: TypeRef=FooType:1:13 [type=FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1] +// CHECK: DeclRefExpr=z:3:33 [type=FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1] +// CHECK: ReturnStmt= [type=] [typekind=Invalid] [isPOD=0] +// CHECK: BinaryOperator= [type=int *] [typekind=Pointer] [isPOD=1] +// CHECK: BinaryOperator= [type=int *] [typekind=Pointer] [isPOD=1] +// CHECK: DeclRefExpr=p:3:13 [type=int *] [typekind=Pointer] [isPOD=1] +// CHECK: DeclRefExpr=z:3:33 [type=FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1] +// CHECK: ArraySubscriptExpr= [type=int] [typekind=Int] [isPOD=1] +// CHECK: DeclRefExpr=arr:3:40 [type=int *] [typekind=Pointer] [isPOD=1] +// CHECK: IntegerLiteral= [type=int] [typekind=Int] [isPOD=1] +// CHECK: TypedefDecl=OtherType:8:16 (Definition) [type=OtherType] [typekind=Typedef] [canonicaltype=double] [canonicaltypekind=Double] [isPOD=1] +// CHECK: TypedefDecl=ArrayType:9:13 (Definition) [type=ArrayType] [typekind=Typedef] [canonicaltype=int [5]] [canonicaltypekind=ConstantArray] [isPOD=1] +// CHECK: IntegerLiteral= [type=int] [typekind=Int] [isPOD=1] +// CHECK: VarDecl=x:10:38 [type=__attribute__((__vector_size__(4 * sizeof(int)))) int] [typekind=Vector] [isPOD=1] +// CHECK: TypedefDecl=int4_t:11:46 (Definition) [type=int4_t] [typekind=Typedef] [canonicaltype=__attribute__((__vector_size__(4 * sizeof(int)))) int] [canonicaltypekind=Vector] [isPOD=1] diff --git a/clang/test/Index/print-type.cpp b/clang/test/Index/print-type.cpp new file mode 100644 index 0000000..876bda9 --- /dev/null +++ b/clang/test/Index/print-type.cpp @@ -0,0 +1,56 @@ +namespace outer { + +template +struct Foo { + T t; +}; + +namespace inner { + +struct Bar { + Bar(outer::Foo* foo) { }; + + typedef int FooType; + int *p; + int *f(int *p, char *x, FooType z) { + const FooType w = z; + return p + z; + } + typedef double OtherType; + typedef int ArrayType[5]; +}; + +} +} + +// RUN: c-index-test -test-print-type %s | FileCheck %s +// CHECK: Namespace=outer:1:11 (Definition) [type=] [typekind=Invalid] [isPOD=0] +// CHECK: ClassTemplate=Foo:4:8 (Definition) [type=] [typekind=Invalid] [isPOD=0] +// CHECK: TemplateTypeParameter=T:3:19 (Definition) [type=T] [typekind=Unexposed] [canonicaltype=type-parameter-0-0] [canonicaltypekind=Unexposed] [isPOD=0] +// CHECK: FieldDecl=t:5:5 (Definition) [type=T] [typekind=Unexposed] [canonicaltype=type-parameter-0-0] [canonicaltypekind=Unexposed] [isPOD=0] +// CHECK: TypeRef=T:3:19 [type=T] [typekind=Unexposed] [canonicaltype=type-parameter-0-0] [canonicaltypekind=Unexposed] [isPOD=0] +// CHECK: Namespace=inner:8:11 (Definition) [type=] [typekind=Invalid] [isPOD=0] +// CHECK: StructDecl=Bar:10:8 (Definition) [type=outer::inner::Bar] [typekind=Record] [isPOD=0] +// CHECK: CXXConstructor=Bar:11:3 (Definition) [type=void (outer::Foo *)] [typekind=FunctionProto] [canonicaltype=void (outer::Foo *)] [canonicaltypekind=FunctionProto] [resulttype=void] [resulttypekind=Void] [args= [outer::Foo *] [Pointer]] [isPOD=0] +// CHECK: ParmDecl=foo:11:25 (Definition) [type=outer::Foo *] [typekind=Pointer] [canonicaltype=outer::Foo *] [canonicaltypekind=Pointer] [isPOD=1] +// CHECK: NamespaceRef=outer:1:11 [type=] [typekind=Invalid] [isPOD=0] +// CHECK: TemplateRef=Foo:4:8 [type=] [typekind=Invalid] [isPOD=0] +// CHECK: CompoundStmt= [type=] [typekind=Invalid] [isPOD=0] +// CHECK: TypedefDecl=FooType:13:15 (Definition) [type=FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1] +// CHECK: FieldDecl=p:14:8 (Definition) [type=int *] [typekind=Pointer] [isPOD=1] +// CHECK: CXXMethod=f:15:8 (Definition) [type=int *(int *, char *, FooType)] [typekind=FunctionProto] [canonicaltype=int *(int *, char *, int)] [canonicaltypekind=FunctionProto] [resulttype=int *] [resulttypekind=Pointer] [args= [int *] [Pointer] [char *] [Pointer] [FooType] [Typedef]] [isPOD=0] +// CHECK: ParmDecl=p:15:15 (Definition) [type=int *] [typekind=Pointer] [isPOD=1] +// CHECK: ParmDecl=x:15:24 (Definition) [type=char *] [typekind=Pointer] [isPOD=1] +// CHECK: ParmDecl=z:15:35 (Definition) [type=FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1] +// CHECK: TypeRef=FooType:13:15 [type=FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1] +// CHECK: CompoundStmt= [type=] [typekind=Invalid] [isPOD=0] +// CHECK: DeclStmt= [type=] [typekind=Invalid] [isPOD=0] +// CHECK: VarDecl=w:16:19 (Definition) [type=const FooType] [typekind=Typedef] const [canonicaltype=const int] [canonicaltypekind=Int] [isPOD=1] +// CHECK: TypeRef=FooType:13:15 [type=FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1] +// CHECK: DeclRefExpr=z:15:35 [type=FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1] +// CHECK: ReturnStmt= [type=] [typekind=Invalid] [isPOD=0] +// CHECK: BinaryOperator= [type=int *] [typekind=Pointer] [isPOD=1] +// CHECK: DeclRefExpr=p:15:15 [type=int *] [typekind=Pointer] [isPOD=1] +// CHECK: DeclRefExpr=z:15:35 [type=FooType] [typekind=Typedef] [canonicaltype=int] [canonicaltypekind=Int] [isPOD=1] +// CHECK: TypedefDecl=OtherType:19:18 (Definition) [type=OtherType] [typekind=Typedef] [canonicaltype=double] [canonicaltypekind=Double] [isPOD=1] +// CHECK: TypedefDecl=ArrayType:20:15 (Definition) [type=ArrayType] [typekind=Typedef] [canonicaltype=int [5]] [canonicaltypekind=ConstantArray] [isPOD=1] diff --git a/clang/test/Index/print-type.m b/clang/test/Index/print-type.m new file mode 100644 index 0000000..9325c3f --- /dev/null +++ b/clang/test/Index/print-type.m @@ -0,0 +1,10 @@ +@interface Foo +@property (readonly) id x; +-(int) mymethod; +-(const id) mymethod2:(id)x blah:(Class)y boo:(SEL)z; +@end + +// RUN: c-index-test -test-print-type %s | FileCheck %s +// CHECK: ObjCPropertyDecl=x:2:25 [type=id] [typekind=ObjCId] [canonicaltype=id] [canonicaltypekind=ObjCObjectPointer] [isPOD=1] +// CHECK: ObjCInstanceMethodDecl=mymethod:3:8 [type=] [typekind=Invalid] [resulttype=int] [resulttypekind=Int] [isPOD=0] +// CHECK: ObjCInstanceMethodDecl=mymethod2:blah:boo::4:13 [type=] [typekind=Invalid] [resulttype=const id] [resulttypekind=ObjCId] [args= [id] [ObjCId] [Class] [ObjCClass] [SEL] [ObjCSel]] [isPOD=0] diff --git a/clang/test/Index/print-typekind.c b/clang/test/Index/print-typekind.c deleted file mode 100644 index 294aea77..0000000 --- a/clang/test/Index/print-typekind.c +++ /dev/null @@ -1,28 +0,0 @@ -typedef int FooType; -int *p; -int *f(int *p, char *x, FooType z) { - const FooType w = z; - return p + z; -} -typedef double OtherType; -typedef int ArrayType[5]; - -// RUN: c-index-test -test-print-typekind %s | FileCheck %s -// CHECK: TypedefDecl=FooType:1:13 (Definition) typekind=Typedef [canonical=Int] [isPOD=1] -// CHECK: VarDecl=p:2:6 typekind=Pointer [isPOD=1] -// CHECK: FunctionDecl=f:3:6 (Definition) typekind=FunctionProto [canonical=FunctionProto] [result=Pointer] [args= Pointer Pointer Typedef] [isPOD=0] -// CHECK: ParmDecl=p:3:13 (Definition) typekind=Pointer [isPOD=1] -// CHECK: ParmDecl=x:3:22 (Definition) typekind=Pointer [isPOD=1] -// CHECK: ParmDecl=z:3:33 (Definition) typekind=Typedef [canonical=Int] [isPOD=1] -// CHECK: TypeRef=FooType:1:13 typekind=Typedef [canonical=Int] [isPOD=1] -// CHECK: CompoundStmt= typekind=Invalid [isPOD=0] -// CHECK: DeclStmt= typekind=Invalid [isPOD=0] -// CHECK: VarDecl=w:4:17 (Definition) typekind=Typedef const [canonical=Int] [isPOD=1] -// CHECK: TypeRef=FooType:1:13 typekind=Typedef [canonical=Int] [isPOD=1] -// CHECK: DeclRefExpr=z:3:33 typekind=Typedef [canonical=Int] [isPOD=1] -// CHECK: ReturnStmt= typekind=Invalid [isPOD=0] -// CHECK: BinaryOperator= typekind=Pointer [isPOD=1] -// CHECK: DeclRefExpr=p:3:13 typekind=Pointer [isPOD=1] -// CHECK: DeclRefExpr=z:3:33 typekind=Typedef [canonical=Int] [isPOD=1] -// CHECK: TypedefDecl=OtherType:7:16 (Definition) typekind=Typedef [canonical=Double] [isPOD=1] -// CHECK: TypedefDecl=ArrayType:8:13 (Definition) typekind=Typedef [canonical=ConstantArray] [isPOD=1] diff --git a/clang/test/Index/print-typekind.m b/clang/test/Index/print-typekind.m deleted file mode 100644 index 565c5e3..0000000 --- a/clang/test/Index/print-typekind.m +++ /dev/null @@ -1,10 +0,0 @@ -@interface Foo -@property (readonly) id x; --(int) mymethod; --(const id) mymethod2:(id)x blah:(Class)y boo:(SEL)z; -@end - -// RUN: c-index-test -test-print-typekind %s | FileCheck %s -// CHECK: ObjCPropertyDecl=x:2:25 typekind=ObjCId [canonical=ObjCObjectPointer] -// CHECK: ObjCInstanceMethodDecl=mymethod:3:8 typekind=Invalid [result=Int] -// CHECK: ObjCInstanceMethodDecl=mymethod2:blah:boo::4:13 typekind=Invalid [result=ObjCId] [args= ObjCId ObjCClass ObjCSel] diff --git a/clang/test/Index/vector-types.c b/clang/test/Index/vector-types.c deleted file mode 100644 index 404e4a5..0000000 --- a/clang/test/Index/vector-types.c +++ /dev/null @@ -1,6 +0,0 @@ -int __attribute__((vector_size(16))) x; -typedef int __attribute__((vector_size(16))) int4_t; - -// RUN: c-index-test -test-print-typekind %s | FileCheck %s -// CHECK: VarDecl=x:1:38 typekind=Vector [isPOD=1] -// CHECK: TypedefDecl=int4_t:2:46 (Definition) typekind=Typedef [canonical=Vector] [isPOD=1] diff --git a/clang/tools/c-index-test/c-index-test.c b/clang/tools/c-index-test/c-index-test.c index be2b6fc..178cbca 100644 --- a/clang/tools/c-index-test/c-index-test.c +++ b/clang/tools/c-index-test/c-index-test.c @@ -1083,36 +1083,42 @@ static enum CXChildVisitResult PrintLinkage(CXCursor cursor, CXCursor p, /* Typekind testing. */ /******************************************************************************/ -static enum CXChildVisitResult PrintTypeKind(CXCursor cursor, CXCursor p, - CXClientData d) { +static void PrintTypeAndTypeKind(CXType T, const char *Format) { + CXString TypeSpelling, TypeKindSpelling; + + TypeSpelling = clang_getTypeSpelling(T); + TypeKindSpelling = clang_getTypeKindSpelling(T.kind); + printf(Format, + clang_getCString(TypeSpelling), + clang_getCString(TypeKindSpelling)); + clang_disposeString(TypeSpelling); + clang_disposeString(TypeKindSpelling); +} + +static enum CXChildVisitResult PrintType(CXCursor cursor, CXCursor p, + CXClientData d) { if (!clang_isInvalid(clang_getCursorKind(cursor))) { CXType T = clang_getCursorType(cursor); - CXString S = clang_getTypeKindSpelling(T.kind); PrintCursor(cursor, NULL); - printf(" typekind=%s", clang_getCString(S)); + PrintTypeAndTypeKind(T, " [type=%s] [typekind=%s]"); if (clang_isConstQualifiedType(T)) printf(" const"); if (clang_isVolatileQualifiedType(T)) printf(" volatile"); if (clang_isRestrictQualifiedType(T)) printf(" restrict"); - clang_disposeString(S); /* Print the canonical type if it is different. */ { CXType CT = clang_getCanonicalType(T); if (!clang_equalTypes(T, CT)) { - CXString CS = clang_getTypeKindSpelling(CT.kind); - printf(" [canonical=%s]", clang_getCString(CS)); - clang_disposeString(CS); + PrintTypeAndTypeKind(CT, " [canonicaltype=%s] [canonicaltypekind=%s]"); } } /* Print the return type if it exists. */ { CXType RT = clang_getCursorResultType(cursor); if (RT.kind != CXType_Invalid) { - CXString RS = clang_getTypeKindSpelling(RT.kind); - printf(" [result=%s]", clang_getCString(RS)); - clang_disposeString(RS); + PrintTypeAndTypeKind(RT, " [resulttype=%s] [resulttypekind=%s]"); } } /* Print the argument types if they exist. */ @@ -1124,9 +1130,7 @@ static enum CXChildVisitResult PrintTypeKind(CXCursor cursor, CXCursor p, for (i = 0; i < numArgs; ++i) { CXType T = clang_getCursorType(clang_Cursor_getArgument(cursor, i)); if (T.kind != CXType_Invalid) { - CXString S = clang_getTypeKindSpelling(T.kind); - printf(" %s", clang_getCString(S)); - clang_disposeString(S); + PrintTypeAndTypeKind(T, " [%s] [%s]"); } } printf("]"); @@ -3543,7 +3547,7 @@ static void print_usage(void) { " c-index-test -test-inclusion-stack-tu \n"); fprintf(stderr, " c-index-test -test-print-linkage-source {}*\n" - " c-index-test -test-print-typekind {}*\n" + " c-index-test -test-print-type {}*\n" " c-index-test -test-print-bitwidth {}*\n" " c-index-test -print-usr [ {}]*\n" " c-index-test -print-usr-file \n" @@ -3625,9 +3629,9 @@ int cindextest_main(int argc, const char **argv) { else if (argc > 2 && strcmp(argv[1], "-test-print-linkage-source") == 0) return perform_test_load_source(argc - 2, argv + 2, "all", PrintLinkage, NULL); - else if (argc > 2 && strcmp(argv[1], "-test-print-typekind") == 0) + else if (argc > 2 && strcmp(argv[1], "-test-print-type") == 0) return perform_test_load_source(argc - 2, argv + 2, "all", - PrintTypeKind, 0); + PrintType, 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/clang/tools/libclang/CXType.cpp b/clang/tools/libclang/CXType.cpp index 3634e32..945eb11 100644 --- a/clang/tools/libclang/CXType.cpp +++ b/clang/tools/libclang/CXType.cpp @@ -200,6 +200,21 @@ CXType clang_getCursorType(CXCursor C) { return MakeCXType(QualType(), TU); } +CXString clang_getTypeSpelling(CXType CT) { + QualType T = GetQualType(CT); + if (T.isNull()) + return cxstring::createEmpty(); + + CXTranslationUnit TU = GetTU(CT); + SmallString<64> Str; + llvm::raw_svector_ostream OS(Str); + PrintingPolicy PP(cxtu::getASTUnit(TU)->getASTContext().getLangOpts()); + + T.print(OS, PP); + + return cxstring::createDup(OS.str()); +} + CXType clang_getTypedefDeclUnderlyingType(CXCursor C) { using namespace cxcursor; CXTranslationUnit TU = cxcursor::getCursorTU(C); diff --git a/clang/tools/libclang/libclang.exports b/clang/tools/libclang/libclang.exports index 616be4c..e0c4db0 100644 --- a/clang/tools/libclang/libclang.exports +++ b/clang/tools/libclang/libclang.exports @@ -205,6 +205,7 @@ clang_getTranslationUnitCursor clang_getTranslationUnitSpelling clang_getTypeDeclaration clang_getTypeKindSpelling +clang_getTypeSpelling clang_getTypedefDeclUnderlyingType clang_hashCursor clang_indexLoc_getCXSourceLocation -- 2.7.4