diff options
-rw-r--r-- | include/clang-c/Index.h | 118 | ||||
-rw-r--r-- | test/Index/print-typekind.c | 20 | ||||
-rw-r--r-- | tools/c-index-test/c-index-test.c | 29 | ||||
-rw-r--r-- | tools/libclang/CMakeLists.txt | 1 | ||||
-rw-r--r-- | tools/libclang/CXTypes.cpp | 246 | ||||
-rw-r--r-- | tools/libclang/libclang.darwin.exports | 6 | ||||
-rw-r--r-- | tools/libclang/libclang.exports | 6 |
7 files changed, 426 insertions, 0 deletions
diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h index e1826df76f..a4741df84d 100644 --- a/include/clang-c/Index.h +++ b/include/clang-c/Index.h @@ -1024,6 +1024,124 @@ CINDEX_LINKAGE CXSourceRange clang_getCursorExtent(CXCursor); */ /** + * \defgroup CINDEX_TYPES Type information for CXCursors + * + * @{ + */ + +/** + * \brief Describes the kind of type + */ +enum CXTypeKind { + /** + * \brief Reprents an invalid type (e.g., where no type is available). + */ + CXType_Invalid = 0, + + /** + * \brief A type whose specific kind is not exposed via this + * interface. + */ + CXType_Unexposed = 1, + + /* Builtin types */ + CXType_Void = 2, + CXType_Bool = 3, + CXType_Char_U = 4, + CXType_UChar = 5, + CXType_Char16 = 6, + CXType_Char32 = 7, + CXType_UShort = 8, + CXType_UInt = 9, + CXType_ULong = 10, + CXType_ULongLong = 11, + CXType_UInt128 = 12, + CXType_Char_S = 13, + CXType_SChar = 14, + CXType_WChar = 15, + CXType_Short = 16, + CXType_Int = 17, + CXType_Long = 18, + CXType_LongLong = 19, + CXType_Int128 = 20, + CXType_Float = 21, + CXType_Double = 22, + CXType_LongDouble = 23, + CXType_NullPtr = 24, + CXType_Overload = 25, + CXType_Dependent = 26, + CXType_ObjCId = 27, + CXType_ObjCClass = 28, + CXType_ObjCSel = 29, + CXType_FirstBuiltin = CXType_Void, + CXType_LastBuiltin = CXType_ObjCSel, + + CXType_Complex = 100, + CXType_Pointer = 101, + CXType_BlockPointer = 102, + CXType_LValueReference = 103, + CXType_RValueReference = 104, + CXType_Record = 105, + CXType_Enum = 106, + CXType_Typedef = 107, + CXType_ObjCInterface = 108, + CXType_ObjCObjectPointer = 109 +}; + +/** + * \brief The type of an element in the abstract syntax tree. + * + */ +typedef struct { + enum CXTypeKind kind; + void *data[2]; +} CXType; + +/** + * \brief Retrieve the type of a CXCursor (if any). + */ +CINDEX_LINKAGE CXType clang_getCursorType(CXCursor C); + +/** + * \determine Determine whether two CXTypes represent the same type. + * + * \returns non-zero if the CXTypes represent the same type and + zero otherwise. + */ +CINDEX_LINKAGE unsigned clang_equalTypes(CXType A, CXType B); + +/** + * \brief Return the canonical type for a CXType. + * + * Clang's type system explicitly models typedefs and all the ways + * a specific type can be represented. The canonical type is the underlying + * type with all the "sugar" removed. For example, if 'T' is a typedef + * for 'int', the canonical type for 'T' would be 'int'. + */ +CINDEX_LINKAGE CXType clang_getCanonicalType(CXType T); + +/** + * \brief For pointer types, returns the type of the pointee. + * + */ +CINDEX_LINKAGE CXType clang_getPointeeType(CXType T); + +/** + * \brief Return the cursor for the declaration of the given type. + */ +CINDEX_LINKAGE CXCursor clang_getTypeDeclaration(CXType T); + + +/** + * \brief Retrieve the spelling of a given CXTypeKind. + */ +CINDEX_LINKAGE CXString clang_getTypeKindSpelling(enum CXTypeKind K); + +/** + * @} + */ + +/** * \defgroup CINDEX_CURSOR_TRAVERSAL Traversing the AST with cursors * * These routines provide the ability to traverse the abstract syntax tree diff --git a/test/Index/print-typekind.c b/test/Index/print-typekind.c new file mode 100644 index 0000000000..79a9965d4d --- /dev/null +++ b/test/Index/print-typekind.c @@ -0,0 +1,20 @@ +typedef int FooType; +int *p; +int *f(int *p, char *x, FooType z) { + FooType w = z; + return p + z; +} + +// RUN: c-index-test -test-print-typekind %s | FileCheck %s +// CHECK: TypedefDecl=FooType:1:13 (Definition) typekind=Typedef [canonical=Int] +// CHECK: VarDecl=p:2:6 typekind=Pointer +// CHECK: FunctionDecl=f:3:6 (Definition) typekind=Unexposed [canonical=Unexposed] +// CHECK: ParmDecl=p:3:13 (Definition) typekind=Pointer +// CHECK: ParmDecl=x:3:22 (Definition) typekind=Pointer +// CHECK: ParmDecl=z:3:33 (Definition) typekind=Typedef [canonical=Int] +// CHECK: VarDecl=w:4:11 (Definition) typekind=Typedef [canonical=Int] +// CHECK: DeclRefExpr=z:3:33 typekind=Typedef [canonical=Int] +// CHECK: UnexposedExpr= typekind=Pointer +// CHECK: DeclRefExpr=p:3:13 typekind=Pointer +// CHECK: DeclRefExpr=z:3:33 typekind=Typedef [canonical=Int] + diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c index 494181675c..12fede209e 100644 --- a/tools/c-index-test/c-index-test.c +++ b/tools/c-index-test/c-index-test.c @@ -447,6 +447,31 @@ static enum CXChildVisitResult PrintLinkage(CXCursor cursor, CXCursor p, } /******************************************************************************/ +/* Typekind testing. */ +/******************************************************************************/ + +static enum CXChildVisitResult PrintTypeKind(CXCursor cursor, CXCursor p, + CXClientData d) { + + if (!clang_isInvalid(clang_getCursorKind(cursor))) { + CXType T = clang_getCursorType(cursor); + CXType CT = clang_getCanonicalType(T); + CXString S = clang_getTypeKindSpelling(T.kind); + PrintCursor(cursor); + printf(" typekind=%s", clang_getCString(S)); + if (!clang_equalTypes(T, CT)) { + CXString CS = clang_getTypeKindSpelling(CT.kind); + printf(" [canonical=%s]", clang_getCString(CS)); + clang_disposeString(CS); + } + clang_disposeString(S); + printf("\n"); + } + return CXChildVisit_Recurse; +} + + +/******************************************************************************/ /* Loading ASTs/source. */ /******************************************************************************/ @@ -1179,6 +1204,7 @@ static void print_usage(void) { " c-index-test -test-inclusion-stack-source {<args>}*\n" " c-index-test -test-inclusion-stack-tu <AST file>\n" " c-index-test -test-print-linkage-source {<args>}*\n" + " c-index-test -test-print-typekind {<args>}*\n" " c-index-test -print-usr [<CursorKind> {<args>}]*\n" " c-index-test -print-usr-file <file>\n\n" " <symbol filter> values:\n%s", @@ -1223,6 +1249,9 @@ int 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) + return perform_test_load_source(argc - 2, argv + 2, "all", + PrintTypeKind, 0); else if (argc > 1 && strcmp(argv[1], "-print-usr") == 0) { if (argc > 2) return print_usrs(argv + 2, argv + argc); diff --git a/tools/libclang/CMakeLists.txt b/tools/libclang/CMakeLists.txt index d3de94a7a5..62c973852d 100644 --- a/tools/libclang/CMakeLists.txt +++ b/tools/libclang/CMakeLists.txt @@ -26,6 +26,7 @@ add_clang_library(libclang CIndexUSRs.cpp CIndexer.cpp CXCursor.cpp + CXTypes.cpp ../../include/clang-c/Index.h ) set_target_properties(libclang PROPERTIES OUTPUT_NAME clang) diff --git a/tools/libclang/CXTypes.cpp b/tools/libclang/CXTypes.cpp new file mode 100644 index 0000000000..28dc12a344 --- /dev/null +++ b/tools/libclang/CXTypes.cpp @@ -0,0 +1,246 @@ +//===- CXTypes.cpp - Implements 'CXTypes' aspect of libclang ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===--------------------------------------------------------------------===// +// +// This file implements the 'CXTypes' API hooks in the Clang-C library. +// +//===--------------------------------------------------------------------===// + +#include "CIndexer.h" +#include "CXCursor.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Type.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Frontend/ASTUnit.h" + +using namespace clang; + +static CXTypeKind GetBuiltinTypeKind(const BuiltinType *BT) { +#define BTCASE(K) case BuiltinType::K: return CXType_##K + switch (BT->getKind()) { + BTCASE(Void); + BTCASE(Bool); + BTCASE(Char_U); + BTCASE(UChar); + BTCASE(Char16); + BTCASE(Char32); + BTCASE(UShort); + BTCASE(UInt); + BTCASE(ULong); + BTCASE(ULongLong); + BTCASE(UInt128); + BTCASE(Char_S); + BTCASE(SChar); + BTCASE(WChar); + BTCASE(Short); + BTCASE(Int); + BTCASE(Long); + BTCASE(LongLong); + BTCASE(Int128); + BTCASE(Float); + BTCASE(Double); + BTCASE(LongDouble); + BTCASE(NullPtr); + BTCASE(Overload); + BTCASE(Dependent); + BTCASE(ObjCId); + BTCASE(ObjCClass); + BTCASE(ObjCSel); + default: + return CXType_Unexposed; + } +#undef BTCASE +} + +static CXTypeKind GetTypeKind(QualType T) { + Type *TP = T.getTypePtr(); + if (!TP) + return CXType_Invalid; + +#define TKCASE(K) case Type::K: return CXType_##K + switch (TP->getTypeClass()) { + case Type::Builtin: + return GetBuiltinTypeKind(cast<BuiltinType>(TP)); + TKCASE(Complex); + TKCASE(Pointer); + TKCASE(BlockPointer); + TKCASE(LValueReference); + TKCASE(RValueReference); + TKCASE(Record); + TKCASE(Enum); + TKCASE(Typedef); + TKCASE(ObjCInterface); + TKCASE(ObjCObjectPointer); + default: + return CXType_Unexposed; + } +#undef TKCASE +} + +static CXType MakeCXType(QualType T, ASTUnit *TU) { + CXTypeKind TK = GetTypeKind(T); + CXType CT = { TK, { TK == CXType_Invalid ? 0 : T.getAsOpaquePtr(), TU }}; + return CT; +} + +static inline QualType GetQualType(CXType CT) { + return QualType::getFromOpaquePtr(CT.data[0]); +} + +static inline ASTUnit* GetASTU(CXType CT) { + return static_cast<ASTUnit*>(CT.data[1]); +} + +extern "C" { + +CXType clang_getCursorType(CXCursor C) { + ASTUnit *AU = cxcursor::getCursorASTUnit(C); + + if (clang_isExpression(C.kind)) { + QualType T = cxcursor::getCursorExpr(C)->getType(); + return MakeCXType(T, AU); + } + + if (clang_isDeclaration(C.kind)) { + Decl *D = cxcursor::getCursorDecl(C); + + if (TypeDecl *TD = dyn_cast<TypeDecl>(D)) + return MakeCXType(QualType(TD->getTypeForDecl(), 0), AU); + if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) + return MakeCXType(QualType(ID->getTypeForDecl(), 0), AU); + if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) + return MakeCXType(VD->getType(), AU); + + return MakeCXType(QualType(), AU); + } + + return MakeCXType(QualType(), AU); +} + +CXType clang_getCanonicalType(CXType CT) { + if (CT.kind == CXType_Invalid) + return CT; + + QualType T = GetQualType(CT); + + if (T.isNull()) + return MakeCXType(QualType(), GetASTU(CT)); + + ASTUnit *AU = GetASTU(CT); + return MakeCXType(AU->getASTContext().getCanonicalType(T), AU); +} + +CXType clang_getPointeeType(CXType CT) { + QualType T = GetQualType(CT); + Type *TP = T.getTypePtr(); + + if (!TP) + return MakeCXType(QualType(), GetASTU(CT)); + + switch (TP->getTypeClass()) { + case Type::Pointer: + T = cast<PointerType>(TP)->getPointeeType(); + break; + case Type::BlockPointer: + T = cast<BlockPointerType>(TP)->getPointeeType(); + break; + case Type::LValueReference: + case Type::RValueReference: + T = cast<ReferenceType>(TP)->getPointeeType(); + break; + case Type::ObjCObjectPointer: + T = cast<ObjCObjectPointerType>(TP)->getPointeeType(); + break; + default: + T = QualType(); + break; + } + return MakeCXType(T, GetASTU(CT)); +} + +CXCursor clang_getTypeDeclaration(CXType CT) { + QualType T = GetQualType(CT); + Type *TP = T.getTypePtr(); + Decl *D = 0; + + switch (TP->getTypeClass()) { + case Type::Typedef: + D = cast<TypedefType>(TP)->getDecl(); + break; + case Type::ObjCInterface: + D = cast<ObjCInterfaceType>(TP)->getDecl(); + break; + case Type::Record: + case Type::Enum: + D = cast<TagType>(TP)->getDecl(); + break; + default: + break; + } + + if (!D) + return cxcursor::MakeCXCursorInvalid(CXCursor_NoDeclFound); + + return cxcursor::MakeCXCursor(D, GetASTU(CT)); +} + +CXString clang_getTypeKindSpelling(enum CXTypeKind K) { + const char *s = 0; +#define TKIND(X) case CXType_##X: s = "" #X ""; break + switch (K) { + TKIND(Invalid); + TKIND(Unexposed); + TKIND(Void); + TKIND(Bool); + TKIND(Char_U); + TKIND(UChar); + TKIND(Char16); + TKIND(Char32); + TKIND(UShort); + TKIND(UInt); + TKIND(ULong); + TKIND(ULongLong); + TKIND(UInt128); + TKIND(Char_S); + TKIND(SChar); + TKIND(WChar); + TKIND(Short); + TKIND(Int); + TKIND(Long); + TKIND(LongLong); + TKIND(Int128); + TKIND(Float); + TKIND(Double); + TKIND(LongDouble); + TKIND(NullPtr); + TKIND(Overload); + TKIND(Dependent); + TKIND(ObjCId); + TKIND(ObjCClass); + TKIND(ObjCSel); + TKIND(Complex); + TKIND(Pointer); + TKIND(BlockPointer); + TKIND(LValueReference); + TKIND(RValueReference); + TKIND(Record); + TKIND(Enum); + TKIND(Typedef); + TKIND(ObjCInterface); + TKIND(ObjCObjectPointer); + } +#undef TKIND + return cxstring::createCXString(s); +} + +unsigned clang_equalTypes(CXType A, CXType B) { + return A.data[0] == B.data[0] && A.data[1] == B.data[1];; +} + +} // end: extern "C" diff --git a/tools/libclang/libclang.darwin.exports b/tools/libclang/libclang.darwin.exports index b361168053..2ea3677add 100644 --- a/tools/libclang/libclang.darwin.exports +++ b/tools/libclang/libclang.darwin.exports @@ -21,7 +21,9 @@ _clang_disposeTranslationUnit _clang_enableStackTraces _clang_equalCursors _clang_equalLocations +_clang_equalTypes _clang_formatDiagnostic +_clang_getCanonicalType _clang_getCString _clang_getClangVersion _clang_getCompletionChunkCompletionString @@ -37,6 +39,7 @@ _clang_getCursorLinkage _clang_getCursorLocation _clang_getCursorReferenced _clang_getCursorSpelling +_clang_getCursorType _clang_getCursorUSR _clang_getDefinitionSpellingAndExtent _clang_getDiagnostic @@ -58,6 +61,7 @@ _clang_getNullLocation _clang_getNullRange _clang_getNumCompletionChunks _clang_getNumDiagnostics +_clang_getPointeeType _clang_getRange _clang_getRangeEnd _clang_getRangeStart @@ -67,6 +71,8 @@ _clang_getTokenLocation _clang_getTokenSpelling _clang_getTranslationUnitCursor _clang_getTranslationUnitSpelling +_clang_getTypeDeclaration +_clang_getTypeKindSpelling _clang_isCursorDefinition _clang_isDeclaration _clang_isExpression diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports index 991bb067f7..321a4ccab4 100644 --- a/tools/libclang/libclang.exports +++ b/tools/libclang/libclang.exports @@ -21,7 +21,9 @@ clang_disposeTranslationUnit clang_enableStackTraces clang_equalCursors clang_equalLocations +clang_equalTypes clang_formatDiagnostic +clang_getCanonicalType clang_getCString clang_getClangVersion clang_getCompletionChunkCompletionString @@ -37,6 +39,7 @@ clang_getCursorLinkage clang_getCursorLocation clang_getCursorReferenced clang_getCursorSpelling +clang_getCursorType clang_getCursorUSR clang_getDefinitionSpellingAndExtent clang_getDiagnostic @@ -58,6 +61,7 @@ clang_getNullLocation clang_getNullRange clang_getNumCompletionChunks clang_getNumDiagnostics +clang_getPointeeType clang_getRange clang_getRangeEnd clang_getRangeStart @@ -67,6 +71,8 @@ clang_getTokenLocation clang_getTokenSpelling clang_getTranslationUnitCursor clang_getTranslationUnitSpelling +clang_getTypeDeclaration +clang_getTypeKindSpelling clang_isCursorDefinition clang_isDeclaration clang_isExpression |