diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -810,6 +810,8 @@ is a replacement for a template type parameter (previously reported a ``CXType_Unexposed``). - Introduced the new function ``clang_Type_getReplacementType`` which gets the type replacing the template type parameter when type kind is ``CXType_SubstTemplateTypeParm``. +- Introduced the new function ``clang_Type_getFullyQualifiedName``, which gets the fully + qualified name of the given type, including qualification of all template parameters. Static Analyzer --------------- diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h --- a/clang/include/clang-c/Index.h +++ b/clang/include/clang-c/Index.h @@ -2846,6 +2846,13 @@ */ CINDEX_LINKAGE CXString clang_getTypeSpelling(CXType CT); +/** + * Get the fully qualified name for a type. + * + * This includes full qualification of all template parameters. +*/ +CINDEX_LINKAGE CXString clang_Type_getFullyQualifiedName(CXType CT); + /** * Retrieve the underlying type of a typedef declaration. * diff --git a/clang/test/Index/print-qualified-type.cpp b/clang/test/Index/print-qualified-type.cpp new file mode 100644 --- /dev/null +++ b/clang/test/Index/print-qualified-type.cpp @@ -0,0 +1,17 @@ +namespace A { + namespace B { + struct Foo {}; + template + struct Bar { + }; + + typedef Bar FooBar; + void foobar(const FooBar&); + } + +} + + + +// RUN: c-index-test -test-print-type -print-qualified-type-names %s -std=c++14 | FileCheck %s +// CHECK: FunctionDecl=foobar:9:10 [type=void (const FooBar &)] [typekind=FunctionProto] [canonicaltype=void (const A::B::Bar &)] [canonicaltypekind=FunctionProto] [resulttype=void] [resulttypekind=Void] [args= [const A::B::FooBar &] [LValueReference]] [isPOD=0] [isAnonRecDecl=0] diff --git a/clang/tools/c-index-test/c-index-test.c b/clang/tools/c-index-test/c-index-test.c --- a/clang/tools/c-index-test/c-index-test.c +++ b/clang/tools/c-index-test/c-index-test.c @@ -373,6 +373,19 @@ return CommentSchemaFile; } +static int parse_print_qualified_type_names(int argc, const char **argv) { + const char *PrintQualifiedTypeNamesArg = "-print-qualified-type-names"; + int PrintQualifiedTypeNames = 0; + + if (argc == 0) + return PrintQualifiedTypeNames; + + if (!strncmp(argv[0], PrintQualifiedTypeNamesArg, strlen(PrintQualifiedTypeNamesArg))) + PrintQualifiedTypeNames = 1; + + return PrintQualifiedTypeNames; +} + /******************************************************************************/ /* Pretty-printing. */ /******************************************************************************/ @@ -1300,6 +1313,7 @@ CXTranslationUnit TU; enum CXCursorKind *Filter; const char *CommentSchemaFile; + int PrintQualifiedTypeNames; } VisitorData; @@ -1507,10 +1521,15 @@ /* Typekind testing. */ /******************************************************************************/ -static void PrintTypeAndTypeKind(CXType T, const char *Format) { +static void PrintTypeAndTypeKind(CXType T, const char *Format, + int PrintQualifiedName) { CXString TypeSpelling, TypeKindSpelling; - TypeSpelling = clang_getTypeSpelling(T); + if (PrintQualifiedName != 0) { + TypeSpelling = clang_Type_getFullyQualifiedName(T); + } else { + TypeSpelling = clang_getTypeSpelling(T); + } TypeKindSpelling = clang_getTypeKindSpelling(T.kind); printf(Format, clang_getCString(TypeSpelling), @@ -1525,7 +1544,8 @@ return CXVisit_Continue; } -static void PrintTypeTemplateArgs(CXType T, const char *Format) { +static void PrintTypeTemplateArgs(CXType T, const char *Format, + int PrintQualifiedName) { int NumTArgs = clang_Type_getNumTemplateArguments(T); if (NumTArgs != -1 && NumTArgs != 0) { int i; @@ -1534,7 +1554,8 @@ for (i = 0; i < NumTArgs; ++i) { TArg = clang_Type_getTemplateArgumentAsType(T, i); if (TArg.kind != CXType_Invalid) { - PrintTypeAndTypeKind(TArg, " [type=%s] [typekind=%s]"); + PrintTypeAndTypeKind(TArg, " [type=%s] [typekind=%s]", + PrintQualifiedName); } } /* Ensure that the returned type is invalid when indexing off-by-one. */ @@ -1577,7 +1598,9 @@ CXType PT = clang_getPointeeType(T); enum CXRefQualifierKind RQ = clang_Type_getCXXRefQualifier(T); PrintCursor(cursor, NULL); - PrintTypeAndTypeKind(T, " [type=%s] [typekind=%s]"); + VisitorData *Data = (VisitorData *)d; + PrintTypeAndTypeKind(T, " [type=%s] [typekind=%s]", + Data->PrintQualifiedTypeNames); PrintNullabilityKind(T, " [nullability=%s]"); if (clang_isConstQualifiedType(T)) printf(" const"); @@ -1590,33 +1613,39 @@ if (RQ == CXRefQualifier_RValue) printf(" rvalue-ref-qualifier"); /* Print the template argument types if they exist. */ - PrintTypeTemplateArgs(T, " [templateargs/%d="); + PrintTypeTemplateArgs(T, + " [templateargs/%d=", Data->PrintQualifiedTypeNames); /* Print the canonical type if it is different. */ { CXType CT = clang_getCanonicalType(T); if (!clang_equalTypes(T, CT)) { - PrintTypeAndTypeKind(CT, " [canonicaltype=%s] [canonicaltypekind=%s]"); - PrintTypeTemplateArgs(CT, " [canonicaltemplateargs/%d="); + PrintTypeAndTypeKind(CT, " [canonicaltype=%s] [canonicaltypekind=%s]", + Data->PrintQualifiedTypeNames); + PrintTypeTemplateArgs( + CT, " [canonicaltemplateargs/%d=", Data->PrintQualifiedTypeNames); } } /* Print the value type if it exists. */ { CXType VT = clang_Type_getValueType(T); if (VT.kind != CXType_Invalid) - PrintTypeAndTypeKind(VT, " [valuetype=%s] [valuetypekind=%s]"); + PrintTypeAndTypeKind(VT, " [valuetype=%s] [valuetypekind=%s]", + Data->PrintQualifiedTypeNames); } /* Print the modified type if it exists. */ { CXType MT = clang_Type_getModifiedType(T); if (MT.kind != CXType_Invalid) { - PrintTypeAndTypeKind(MT, " [modifiedtype=%s] [modifiedtypekind=%s]"); + PrintTypeAndTypeKind(MT, " [modifiedtype=%s] [modifiedtypekind=%s]", + Data->PrintQualifiedTypeNames); } } /* Print the return type if it exists. */ { CXType RT = clang_getCursorResultType(cursor); if (RT.kind != CXType_Invalid) { - PrintTypeAndTypeKind(RT, " [resulttype=%s] [resulttypekind=%s]"); + PrintTypeAndTypeKind(RT, " [resulttype=%s] [resulttypekind=%s]", + Data->PrintQualifiedTypeNames); } PrintNullabilityKind(RT, " [resultnullability=%s]"); } @@ -1629,7 +1658,8 @@ for (i = 0; i < NumArgs; ++i) { CXType T = clang_getCursorType(clang_Cursor_getArgument(cursor, i)); if (T.kind != CXType_Invalid) { - PrintTypeAndTypeKind(T, " [%s] [%s]"); + PrintTypeAndTypeKind(T, " [%s] [%s]", + Data->PrintQualifiedTypeNames); PrintNullabilityKind(T, " [%s]"); } } @@ -1640,7 +1670,8 @@ { CXType BT = clang_Type_getObjCObjectBaseType(PT); if (BT.kind != CXType_Invalid) { - PrintTypeAndTypeKind(BT, " [basetype=%s] [basekind=%s]"); + PrintTypeAndTypeKind(BT, " [basetype=%s] [basekind=%s]", + Data->PrintQualifiedTypeNames); } } { @@ -1651,7 +1682,8 @@ for (i = 0; i < NumTypeArgs; ++i) { CXType TA = clang_Type_getObjCTypeArg(PT, i); if (TA.kind != CXType_Invalid) { - PrintTypeAndTypeKind(TA, " [%s] [%s]"); + PrintTypeAndTypeKind(TA, " [%s] [%s]", + Data->PrintQualifiedTypeNames); } } printf("]"); @@ -1676,7 +1708,8 @@ /* Print the pointee type. */ { if (PT.kind != CXType_Invalid) { - PrintTypeAndTypeKind(PT, " [pointeetype=%s] [pointeekind=%s]"); + PrintTypeAndTypeKind(PT, " [pointeetype=%s] [pointeekind=%s]", + Data->PrintQualifiedTypeNames); } } /* Print the number of fields if they exist. */ @@ -1717,8 +1750,9 @@ static void PrintSingleTypeSize(CXType T, const char *TypeKindFormat, const char *SizeFormat, - const char *AlignFormat) { - PrintTypeAndTypeKind(T, TypeKindFormat); + const char *AlignFormat, + int PrintQualifiedName) { + PrintTypeAndTypeKind(T, TypeKindFormat, PrintQualifiedName); /* Print the type sizeof if applicable. */ { long long Size = clang_Type_getSizeOf(T); @@ -1739,7 +1773,8 @@ CXType RT = clang_getResultType(T); if (RT.kind != CXType_Invalid) PrintSingleTypeSize(RT, " [resulttype=%s] [resulttypekind=%s]", - " [resultsizeof=%lld]", " [resultalignof=%lld]"); + " [resultsizeof=%lld]", " [resultalignof=%lld]", + PrintQualifiedName); } } @@ -1751,8 +1786,9 @@ return CXChildVisit_Recurse; T = clang_getCursorType(cursor); PrintCursor(cursor, NULL); + VisitorData *Data = (VisitorData *)d; PrintSingleTypeSize(T, " [type=%s] [typekind=%s]", " [sizeof=%lld]", - " [alignof=%lld]"); + " [alignof=%lld]", Data->PrintQualifiedTypeNames); /* Print the record field offset if applicable. */ { CXString FieldSpelling = clang_getCursorSpelling(cursor); @@ -1869,7 +1905,10 @@ if (clang_isDeclaration(typeDeclaration.kind)) { PrintCursor(cursor, NULL); - PrintTypeAndTypeKind(clang_getCursorType(typeDeclaration), " [typedeclaration=%s] [typekind=%s]\n"); + VisitorData *Data = (VisitorData *)d; + PrintTypeAndTypeKind(clang_getCursorType(typeDeclaration), + " [typedeclaration=%s] [typekind=%s]\n", + Data->PrintQualifiedTypeNames); } return CXChildVisit_Recurse; @@ -1945,7 +1984,8 @@ const char *filter, const char *prefix, CXCursorVisitor Visitor, PostVisitTU PV, - const char *CommentSchemaFile) { + const char *CommentSchemaFile, + int PrintQualifiedTypeNames) { if (prefix) FileCheckPrefix = prefix; @@ -1982,6 +2022,7 @@ Data.TU = TU; Data.Filter = ck; Data.CommentSchemaFile = CommentSchemaFile; + Data.PrintQualifiedTypeNames = PrintQualifiedTypeNames; clang_visitChildren(clang_getTranslationUnitCursor(TU), Visitor, &Data); } @@ -2000,7 +2041,7 @@ int perform_test_load_tu(const char *file, const char *filter, const char *prefix, CXCursorVisitor Visitor, - PostVisitTU PV) { + PostVisitTU PV, int PrintQualifiedTypeNames) { CXIndex Idx; CXTranslationUnit TU; int result; @@ -2013,7 +2054,8 @@ return 1; } - result = perform_test_load(Idx, TU, filter, prefix, Visitor, PV, NULL); + result = perform_test_load(Idx, TU, filter, prefix, Visitor, PV, NULL, + PrintQualifiedTypeNames); clang_disposeIndex(Idx); return result; } @@ -2024,6 +2066,7 @@ CXIndex Idx; CXTranslationUnit TU; const char *CommentSchemaFile; + int PrintQualifiedTypeNames = 0; struct CXUnsavedFile *unsaved_files = 0; int num_unsaved_files = 0; enum CXErrorCode Err; @@ -2048,6 +2091,11 @@ argv++; } + if ((PrintQualifiedTypeNames = parse_print_qualified_type_names(argc, argv))) { + argc--; + argv++; + } + if (parse_remapped_files(argc, argv, 0, &unsaved_files, &num_unsaved_files)) { clang_disposeIndex(Idx); return -1; @@ -2088,7 +2136,7 @@ } result = perform_test_load(Idx, TU, filter, NULL, Visitor, PV, - CommentSchemaFile); + CommentSchemaFile, PrintQualifiedTypeNames); free_remapped_files(unsaved_files, num_unsaved_files); clang_disposeIndex(Idx); return result; @@ -2109,6 +2157,7 @@ const char *execute_command = NULL; int remap_after_trial = 0; char *endptr = 0; + int PrintQualifiedTypeNames = 0; Idx = clang_createIndex(/* excludeDeclsFromPCH */ !strcmp(filter, "local") ? 1 : 0, @@ -2190,8 +2239,9 @@ if (checkForErrors(TU) != 0) return -1; } - - result = perform_test_load(Idx, TU, filter, NULL, Visitor, PV, NULL); + + result = perform_test_load(Idx, TU, filter, NULL, Visitor, PV, NULL, + PrintQualifiedTypeNames); free_remapped_files(unsaved_files, num_unsaved_files); clang_disposeIndex(Idx); @@ -2221,7 +2271,8 @@ } result = perform_test_load(Idx, TU, /*filter=*/"all", /*prefix=*/NULL, FilteredPrintingVisitor, /*PostVisit=*/NULL, - /*CommentSchemaFile=*/NULL); + /*CommentSchemaFile=*/NULL, + /*PrintQualifiedTypeNames*/ 0); clang_disposeIndex(Idx); return result; } @@ -2249,7 +2300,8 @@ } result = perform_test_load(Idx, TU, /*filter=*/"all", /*prefix=*/NULL, FilteredPrintingVisitor, /*PostVisit=*/NULL, - /*CommentSchemaFile=*/NULL); + /*CommentSchemaFile=*/NULL, + /*PrintQualifiedTypeNames*/ 0); clang_disposeIndex(Idx); return result; } @@ -4901,7 +4953,7 @@ CXCursorVisitor I = GetVisitor(argv[1] + 13); if (I) return perform_test_load_tu(argv[2], argv[3], argc >= 5 ? argv[4] : 0, I, - NULL); + NULL, 0); } else if (argc >= 5 && strncmp(argv[1], "-test-load-source-reparse", 25) == 0){ CXCursorVisitor I = GetVisitor(argv[1] + 25); @@ -4936,7 +4988,7 @@ PrintInclusionStack); else if (argc > 2 && strcmp(argv[1], "-test-inclusion-stack-tu") == 0) return perform_test_load_tu(argv[2], "all", NULL, NULL, - PrintInclusionStack); + PrintInclusionStack, 0); else if (argc > 2 && strcmp(argv[1], "-test-print-linkage-source") == 0) return perform_test_load_source(argc - 2, argv + 2, "all", PrintLinkage, NULL); @@ -4959,9 +5011,9 @@ return perform_test_load_source(argc - 2, argv + 2, "all", PrintBitWidth, 0); else if (argc > 2 && strcmp(argv[1], "-test-print-mangle") == 0) - return perform_test_load_tu(argv[2], "all", NULL, PrintMangledName, NULL); + return perform_test_load_tu(argv[2], "all", NULL, PrintMangledName, NULL, 0); else if (argc > 2 && strcmp(argv[1], "-test-print-manglings") == 0) - return perform_test_load_tu(argv[2], "all", NULL, PrintManglings, NULL); + return perform_test_load_tu(argv[2], "all", NULL, PrintManglings, NULL, 0); else if (argc > 2 && strcmp(argv[1], "-test-print-target-info") == 0) return print_target_info(argc - 2, argv + 2); else if (argc > 1 && strcmp(argv[1], "-print-usr") == 0) { diff --git a/clang/tools/libclang/CXType.cpp b/clang/tools/libclang/CXType.cpp --- a/clang/tools/libclang/CXType.cpp +++ b/clang/tools/libclang/CXType.cpp @@ -20,6 +20,7 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/Type.h" +#include "clang/AST/QualTypeNames.h" #include "clang/Basic/AddressSpaces.h" #include "clang/Frontend/ASTUnit.h" @@ -309,6 +310,18 @@ return cxstring::createDup(OS.str()); } +CXString clang_Type_getFullyQualifiedName(CXType CT) { + QualType T = GetQualType(CT); + if (T.isNull()) + return cxstring::createEmpty(); + + const ASTContext &Ctx = cxtu::getASTUnit(GetTU(CT))->getASTContext(); + std::string QualName = clang::TypeName::getFullyQualifiedName( + T, Ctx, Ctx.getLangOpts()); + + return cxstring::createDup(QualName); +} + CXType clang_getTypedefDeclUnderlyingType(CXCursor C) { using namespace cxcursor; CXTranslationUnit TU = cxcursor::getCursorTU(C); diff --git a/clang/tools/libclang/libclang.map b/clang/tools/libclang/libclang.map --- a/clang/tools/libclang/libclang.map +++ b/clang/tools/libclang/libclang.map @@ -413,6 +413,7 @@ clang_CXXMethod_isDeleted; clang_CXXMethod_isCopyAssignmentOperator; clang_CXXMethod_isMoveAssignmentOperator; + clang_Type_getFullyQualifiedName; }; # Example of how to add a new symbol version entry. If you do add a new symbol