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"; + const char *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,13 +1521,17 @@ /* 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), + printf(Format, clang_getCString(TypeSpelling), clang_getCString(TypeKindSpelling)); clang_disposeString(TypeSpelling); clang_disposeString(TypeKindSpelling); @@ -1525,7 +1543,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 +1553,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 +1597,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 +1612,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 +1657,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 +1669,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 +1681,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,13 +1707,14 @@ /* 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. */ { int numFields = 0; - if (clang_Type_visitFields(T, FieldVisitor, &numFields)){ + if (clang_Type_visitFields(T, FieldVisitor, &numFields)) { if (numFields != 0) { printf(" [nbFields=%d]", numFields); } @@ -1716,13 +1748,13 @@ } static void PrintSingleTypeSize(CXType T, const char *TypeKindFormat, - const char *SizeFormat, - const char *AlignFormat) { - PrintTypeAndTypeKind(T, TypeKindFormat); + const char *SizeFormat, const char *AlignFormat, + int PrintQualifiedName) { + PrintTypeAndTypeKind(T, TypeKindFormat, PrintQualifiedName); /* Print the type sizeof if applicable. */ { long long Size = clang_Type_getSizeOf(T); - if (Size >= 0 || Size < -1 ) { + if (Size >= 0 || Size < -1) { printf(SizeFormat, Size); } } @@ -1739,7 +1771,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 +1784,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); @@ -1768,17 +1802,17 @@ RecordIsAnonymous = clang_Cursor_isAnonymous(Record); /* Recurse as long as the parent is a CXType_Record and the Record is anonymous */ - } while ( clang_getCursorType(Parent).kind == CXType_Record && - RecordIsAnonymous > 0); + } while (clang_getCursorType(Parent).kind == CXType_Record && + RecordIsAnonymous > 0); { - long long Offset = clang_Type_getOffsetOf(clang_getCursorType(Record), - FieldName); + long long Offset = + clang_Type_getOffsetOf(clang_getCursorType(Record), FieldName); long long Offset2 = clang_Cursor_getOffsetOfField(cursor); - if (Offset == Offset2){ - printf(" [offsetof=%lld]", Offset); + if (Offset == Offset2) { + printf(" [offsetof=%lld]", Offset); } else { - /* Offsets will be different in anonymous records. */ - printf(" [offsetof=%lld/%lld]", Offset, Offset2); + /* Offsets will be different in anonymous records. */ + printf(" [offsetof=%lld/%lld]", Offset, Offset2); } } } @@ -1864,12 +1898,16 @@ /******************************************************************************/ static enum CXChildVisitResult PrintTypeDeclaration(CXCursor cursor, CXCursor p, - CXClientData d) { - CXCursor typeDeclaration = clang_getTypeDeclaration(clang_getCursorType(cursor)); + CXClientData d) { + CXCursor typeDeclaration = + clang_getTypeDeclaration(clang_getCursorType(cursor)); 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; @@ -1943,9 +1981,9 @@ static int perform_test_load(CXIndex Idx, CXTranslationUnit TU, const char *filter, const char *prefix, - CXCursorVisitor Visitor, - PostVisitTU PV, - const char *CommentSchemaFile) { + CXCursorVisitor Visitor, PostVisitTU PV, + const char *CommentSchemaFile, + int PrintQualifiedTypeNames) { if (prefix) FileCheckPrefix = prefix; @@ -1956,24 +1994,30 @@ VisitorData Data; /* Perform some simple filtering. */ - if (!strcmp(filter, "all") || !strcmp(filter, "local")) ck = NULL; - else if (!strcmp(filter, "all-display") || + if (!strcmp(filter, "all") || !strcmp(filter, "local")) + ck = NULL; + else if (!strcmp(filter, "all-display") || !strcmp(filter, "local-display")) { ck = NULL; wanted_display_type = DisplayType_DisplayName; - } - else if (!strcmp(filter, "all-pretty") || - !strcmp(filter, "local-pretty")) { + } else if (!strcmp(filter, "all-pretty") || + !strcmp(filter, "local-pretty")) { ck = NULL; wanted_display_type = DisplayType_Pretty; - } - else if (!strcmp(filter, "none")) K = (enum CXCursorKind) ~0; - else if (!strcmp(filter, "category")) K = CXCursor_ObjCCategoryDecl; - else if (!strcmp(filter, "interface")) K = CXCursor_ObjCInterfaceDecl; - else if (!strcmp(filter, "protocol")) K = CXCursor_ObjCProtocolDecl; - else if (!strcmp(filter, "function")) K = CXCursor_FunctionDecl; - else if (!strcmp(filter, "typedef")) K = CXCursor_TypedefDecl; - else if (!strcmp(filter, "scan-function")) Visitor = FunctionScanVisitor; + } else if (!strcmp(filter, "none")) + K = (enum CXCursorKind) ~0; + else if (!strcmp(filter, "category")) + K = CXCursor_ObjCCategoryDecl; + else if (!strcmp(filter, "interface")) + K = CXCursor_ObjCInterfaceDecl; + else if (!strcmp(filter, "protocol")) + K = CXCursor_ObjCProtocolDecl; + else if (!strcmp(filter, "function")) + K = CXCursor_FunctionDecl; + else if (!strcmp(filter, "typedef")) + K = CXCursor_TypedefDecl; + else if (!strcmp(filter, "scan-function")) + Visitor = FunctionScanVisitor; else { fprintf(stderr, "Unknown filter for -test-load-tu: %s\n", filter); return 1; @@ -1982,6 +2026,7 @@ Data.TU = TU; Data.Filter = ck; Data.CommentSchemaFile = CommentSchemaFile; + Data.PrintQualifiedTypeNames = PrintQualifiedTypeNames; clang_visitChildren(clang_getTranslationUnitCursor(TU), Visitor, &Data); } @@ -2000,7 +2045,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 +2058,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 +2070,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 +2095,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 +2140,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 +2161,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, @@ -2191,7 +2244,7 @@ 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); @@ -2204,7 +2257,7 @@ enum CXErrorCode Err; int result; - Idx = clang_createIndex(/* excludeDeclsFromPCH */1, + Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1, /* displayDiagnostics=*/1); Err = clang_parseTranslationUnit2(Idx, filename, @@ -2220,8 +2273,10 @@ return 1; } - result = perform_test_load(Idx, TU, /*filter=*/"all", /*prefix=*/NULL, FilteredPrintingVisitor, /*PostVisit=*/NULL, - /*CommentSchemaFile=*/NULL); + result = perform_test_load(Idx, TU, /*filter=*/"all", /*prefix=*/NULL, + FilteredPrintingVisitor, /*PostVisit=*/NULL, + /*CommentSchemaFile=*/NULL, + /*PrintQualifiedTypeNames*/ 0); clang_disposeIndex(Idx); return result; } @@ -2232,15 +2287,16 @@ enum CXErrorCode Err; int result; - Idx = clang_createIndex(/* excludeDeclsFromPCH */1, + Idx = clang_createIndex(/* excludeDeclsFromPCH */ 1, /* displayDiagnostics=*/1); - Err = clang_parseTranslationUnit2(Idx, filename, - /*command_line_args=*/NULL, - /*num_command_line_args=*/0, - /*unsaved_files=*/NULL, - /*num_unsaved_files=*/0, - CXTranslationUnit_RetainExcludedConditionalBlocks, &TU); + Err = clang_parseTranslationUnit2( + Idx, filename, + /*command_line_args=*/NULL, + /*num_command_line_args=*/0, + /*unsaved_files=*/NULL, + /*num_unsaved_files=*/0, + CXTranslationUnit_RetainExcludedConditionalBlocks, &TU); if (Err != CXError_Success) { fprintf(stderr, "Unable to load translation unit!\n"); describeLibclangFailure(Err); @@ -2248,8 +2304,10 @@ return 1; } - result = perform_test_load(Idx, TU, /*filter=*/"all", /*prefix=*/NULL, FilteredPrintingVisitor, /*PostVisit=*/NULL, - /*CommentSchemaFile=*/NULL); + result = perform_test_load(Idx, TU, /*filter=*/"all", /*prefix=*/NULL, + FilteredPrintingVisitor, /*PostVisit=*/NULL, + /*CommentSchemaFile=*/NULL, + /*PrintQualifiedTypeNames*/ 0); clang_disposeIndex(Idx); return result; } @@ -4901,7 +4959,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 +4994,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 +5017,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,22 @@ return cxstring::createDup(OS.str()); } +CXString clang_Type_getFullyQualifiedName(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()); + + std::string qname = clang::TypeName::getFullyQualifiedName( + T, cxtu::getASTUnit(TU)->getASTContext(), PP); + + return cxstring::createDup(qname); +} + 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