anderslanglands updated this revision to Diff 477085.
anderslanglands added a comment.

Now tested by adding a -print-qualified-type-names flag to c-index-test and 
creating a (small) dedicated test in print-qualified-type.cpp


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D138377/new/

https://reviews.llvm.org/D138377

Files:
  clang/docs/ReleaseNotes.rst
  clang/include/clang-c/Index.h
  clang/test/Index/print-qualified-type.cpp
  clang/tools/c-index-test/c-index-test.c
  clang/tools/libclang/CXType.cpp
  clang/tools/libclang/libclang.map

Index: clang/tools/libclang/libclang.map
===================================================================
--- clang/tools/libclang/libclang.map
+++ 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
Index: clang/tools/libclang/CXType.cpp
===================================================================
--- clang/tools/libclang/CXType.cpp
+++ 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);
Index: clang/tools/c-index-test/c-index-test.c
===================================================================
--- clang/tools/c-index-test/c-index-test.c
+++ 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) {
Index: clang/test/Index/print-qualified-type.cpp
===================================================================
--- /dev/null
+++ clang/test/Index/print-qualified-type.cpp
@@ -0,0 +1,17 @@
+namespace A {
+  namespace B {
+    struct Foo {};
+    template <class T>
+    struct Bar {
+    };
+
+    typedef Bar<Foo> 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<A::B::Foo> &)] [canonicaltypekind=FunctionProto] [resulttype=void] [resulttypekind=Void] [args= [const A::B::FooBar &] [LValueReference]] [isPOD=0] [isAnonRecDecl=0]
Index: clang/include/clang-c/Index.h
===================================================================
--- clang/include/clang-c/Index.h
+++ 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.
  *
Index: clang/docs/ReleaseNotes.rst
===================================================================
--- clang/docs/ReleaseNotes.rst
+++ 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
 ---------------
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to