steveire created this revision.
steveire added a reviewer: njames93.
Herald added subscribers: mgrang, mgorny.
steveire requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Extend the matchers gathering API for types to record template
parameters.  The TypeLoc type hierarchy has some types which are
templates used in CRTP such as PointerLikeTypeLoc.  Record the inherited
template and template arguments of types inheriting those CRTP types in
the ClassInheritance map.  Because the name inherited from is now
computed, the value type in that map changes from StringRef to
std::string.  This also causes the toJSON override signature used to
serialize that map to change.

Remove the logic for skipping over empty ClassData instances.  Several
classes such as TypeOfExprTypeLoc inherit a CRTP class which provides
interesting locations though the derived class does not.  Record it as a
class to make the locations it inherits available.

Record the typeSourceInfo accessors too as they provide access to
TypeLocs in many classes.

Fix the LocationCallFormatter to print the correct function name.  Now
that the output includes chained function calls, the bug became
apparent.

The existing unit tests use UnorderedElementsAre to compare the
introspection result with the expected result.  Our current
implementation of google mock (in gmock-generated-matchers.h) is limited
to support for comparing a container of 10 elements.  As we are now
returning more than 10 results for one of the introspection tests,
change it to instead compare against an ordered vector of pairs.

Because a macro is used to generate API strings and API calls, disable
clang-format in blocks of expected results.  Otherwise clang-format
would insert whitespaces which would then be compared against the
introspected strings and fail the test.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D100516

Files:
  clang/include/clang/Tooling/NodeIntrospection.h
  clang/lib/Tooling/CMakeLists.txt
  clang/lib/Tooling/DumpTool/APIData.h
  clang/lib/Tooling/DumpTool/ASTSrcLocProcessor.cpp
  clang/lib/Tooling/DumpTool/ASTSrcLocProcessor.h
  clang/lib/Tooling/DumpTool/generate_cxx_src_locs.py
  clang/lib/Tooling/NodeIntrospection.cpp
  clang/unittests/Introspection/IntrospectionTest.cpp

Index: clang/unittests/Introspection/IntrospectionTest.cpp
===================================================================
--- clang/unittests/Introspection/IntrospectionTest.cpp
+++ clang/unittests/Introspection/IntrospectionTest.cpp
@@ -23,19 +23,19 @@
 using namespace clang::ast_matchers;
 using namespace clang::tooling;
 
+using ::testing::ElementsAre;
 using ::testing::Pair;
 using ::testing::UnorderedElementsAre;
 
-template<typename T, typename MapType>
-std::map<std::string, T>
+template <typename T, typename MapType>
+std::vector<std::pair<std::string, T>>
 FormatExpected(const MapType &Accessors) {
-  std::map<std::string, T> Result;
+  std::vector<std::pair<std::string, T>> Result;
   llvm::transform(llvm::make_filter_range(Accessors,
                                           [](const auto &Accessor) {
                                             return Accessor.first.isValid();
                                           }),
-                  std::inserter(Result, Result.end()),
-                  [](const auto &Accessor) {
+                  std::back_inserter(Result), [](const auto &Accessor) {
                     return std::make_pair(
                         LocationCallFormatterCpp::format(Accessor.second.get()),
                         Accessor.first);
@@ -45,6 +45,31 @@
 
 #define STRING_LOCATION_PAIR(INSTANCE, LOC) Pair(#LOC, INSTANCE->LOC)
 
+#define STRING_LOCATION_STDPAIR(INSTANCE, LOC)                                 \
+  std::make_pair(std::string(#LOC), INSTANCE->LOC)
+
+/**
+  A test formatter for a hypothetical language which needs
+  neither casts nor '->'.
+*/
+class LocationCallFormatterSimple {
+public:
+  static std::string format(LocationCall *Call) {
+    std::vector<LocationCall *> vec;
+    while (Call) {
+      if (!Call->isCast())
+        vec.push_back(Call);
+      Call = Call->on();
+    }
+    std::string result;
+    for (auto *VecCall : llvm::reverse(llvm::makeArrayRef(vec).drop_front())) {
+      result += (VecCall->name() + "().").str();
+    }
+    result += (vec.front()->name() + "()").str();
+    return result;
+  }
+};
+
 TEST(Introspection, SourceLocations_Stmt) {
   auto AST = buildASTFromCode("void foo() {} void bar() { foo(); }", "foo.cpp",
                               std::make_shared<PCHContainerOperations>());
@@ -125,26 +150,75 @@
   auto ExpectedLocations =
       FormatExpected<SourceLocation>(Result.LocationAccessors);
 
-  EXPECT_THAT(ExpectedLocations,
-              UnorderedElementsAre(
-                  STRING_LOCATION_PAIR(MethodDecl, getBeginLoc()),
-                  STRING_LOCATION_PAIR(MethodDecl, getBodyRBrace()),
-                  STRING_LOCATION_PAIR(MethodDecl, getInnerLocStart()),
-                  STRING_LOCATION_PAIR(MethodDecl, getLocation()),
-                  STRING_LOCATION_PAIR(MethodDecl, getOuterLocStart()),
-                  STRING_LOCATION_PAIR(MethodDecl, getTypeSpecEndLoc()),
-                  STRING_LOCATION_PAIR(MethodDecl, getTypeSpecStartLoc()),
-                  STRING_LOCATION_PAIR(MethodDecl, getEndLoc())));
+  llvm::sort(ExpectedLocations);
+
+  // clang-format off
+  EXPECT_EQ(
+      ExpectedLocations,
+      (std::vector<std::pair<std::string, SourceLocation>>{
+STRING_LOCATION_STDPAIR(MethodDecl, getBeginLoc()),
+STRING_LOCATION_STDPAIR(MethodDecl, getBodyRBrace()),
+STRING_LOCATION_STDPAIR(MethodDecl, getEndLoc()),
+STRING_LOCATION_STDPAIR(MethodDecl, getInnerLocStart()),
+STRING_LOCATION_STDPAIR(MethodDecl, getLocation()),
+STRING_LOCATION_STDPAIR(MethodDecl, getOuterLocStart()),
+STRING_LOCATION_STDPAIR(MethodDecl,
+  getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getLParenLoc()),
+STRING_LOCATION_STDPAIR(MethodDecl,
+  getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getLocalRangeBegin()),
+STRING_LOCATION_STDPAIR(MethodDecl,
+  getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getLocalRangeEnd()),
+STRING_LOCATION_STDPAIR(MethodDecl,
+  getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getRParenLoc()),
+STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getBeginLoc()),
+STRING_LOCATION_STDPAIR(MethodDecl,
+                      getTypeSourceInfo()->getTypeLoc().getEndLoc()),
+STRING_LOCATION_STDPAIR(
+    MethodDecl,
+    getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getAs<clang::TemplateSpecializationTypeLoc>().getLAngleLoc()),
+STRING_LOCATION_STDPAIR(
+    MethodDecl,
+    getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getAs<clang::TemplateSpecializationTypeLoc>().getRAngleLoc()),
+STRING_LOCATION_STDPAIR(
+    MethodDecl,
+    getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getAs<clang::TemplateSpecializationTypeLoc>().getTemplateNameLoc()),
+STRING_LOCATION_STDPAIR(
+    MethodDecl,
+    getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getBeginLoc()),
+STRING_LOCATION_STDPAIR(
+    MethodDecl,
+    getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getEndLoc()),
+STRING_LOCATION_STDPAIR(MethodDecl, getTypeSpecEndLoc()),
+STRING_LOCATION_STDPAIR(MethodDecl, getTypeSpecStartLoc())
+  }));
+  // clang-format on
 
   auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors);
 
+  // clang-format off
   EXPECT_THAT(
       ExpectedRanges,
       UnorderedElementsAre(
-          STRING_LOCATION_PAIR(MethodDecl, getExceptionSpecSourceRange()),
-          STRING_LOCATION_PAIR(MethodDecl, getParametersSourceRange()),
-          STRING_LOCATION_PAIR(MethodDecl, getReturnTypeSourceRange()),
-          STRING_LOCATION_PAIR(MethodDecl, getSourceRange())));
+STRING_LOCATION_PAIR(MethodDecl, getReturnTypeSourceRange()),
+STRING_LOCATION_PAIR(MethodDecl,
+  getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getLocalSourceRange()),
+STRING_LOCATION_PAIR(MethodDecl,
+  getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getSourceRange()),
+STRING_LOCATION_PAIR(MethodDecl, getSourceRange()),
+STRING_LOCATION_PAIR(
+    MethodDecl,
+    getTypeSourceInfo()->getTypeLoc().getSourceRange()),
+STRING_LOCATION_PAIR(MethodDecl,
+  getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getParensRange()),
+STRING_LOCATION_PAIR(
+    MethodDecl,
+    getTypeSourceInfo()->getTypeLoc().getLocalSourceRange()),
+STRING_LOCATION_PAIR(MethodDecl, getParametersSourceRange()),
+STRING_LOCATION_PAIR(MethodDecl, getExceptionSpecSourceRange()),
+STRING_LOCATION_PAIR(MethodDecl,
+  getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getExceptionSpecRange())
+  ));
+  // clang-format on
 }
 
 TEST(Introspection, SourceLocations_NNS) {
@@ -180,17 +254,25 @@
 
   EXPECT_THAT(
       ExpectedLocations,
-      UnorderedElementsAre(STRING_LOCATION_PAIR(NNS, getBeginLoc()),
-                           STRING_LOCATION_PAIR(NNS, getEndLoc()),
-                           STRING_LOCATION_PAIR(NNS, getLocalBeginLoc()),
-                           STRING_LOCATION_PAIR(NNS, getLocalEndLoc())));
+      UnorderedElementsAre(
+          STRING_LOCATION_PAIR(NNS, getBeginLoc()),
+          STRING_LOCATION_PAIR(NNS, getEndLoc()),
+          STRING_LOCATION_PAIR(NNS, getLocalBeginLoc()),
+          STRING_LOCATION_PAIR(NNS, getLocalEndLoc()),
+          STRING_LOCATION_PAIR(
+              NNS, getTypeLoc().getAs<clang::TypeSpecTypeLoc>().getNameLoc()),
+          STRING_LOCATION_PAIR(NNS, getTypeLoc().getEndLoc()),
+          STRING_LOCATION_PAIR(NNS, getTypeLoc().getBeginLoc())));
 
   auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors);
 
   EXPECT_THAT(
       ExpectedRanges,
-      UnorderedElementsAre(STRING_LOCATION_PAIR(NNS, getLocalSourceRange()),
-                           STRING_LOCATION_PAIR(NNS, getSourceRange())));
+      UnorderedElementsAre(
+          STRING_LOCATION_PAIR(NNS, getLocalSourceRange()),
+          STRING_LOCATION_PAIR(NNS, getSourceRange()),
+          STRING_LOCATION_PAIR(NNS, getTypeLoc().getSourceRange()),
+          STRING_LOCATION_PAIR(NNS, getTypeLoc().getLocalSourceRange())));
 }
 
 TEST(Introspection, SourceLocations_TA_Type) {
@@ -226,13 +308,31 @@
   auto ExpectedLocations =
       FormatExpected<SourceLocation>(Result.LocationAccessors);
 
+  // clang-format off
   EXPECT_THAT(ExpectedLocations,
-              UnorderedElementsAre(STRING_LOCATION_PAIR(TA, getLocation())));
+              UnorderedElementsAre(
+STRING_LOCATION_PAIR(TA, getLocation()),
+STRING_LOCATION_PAIR(TA,
+  getTypeSourceInfo()->getTypeLoc().getAs<clang::BuiltinTypeLoc>().getBuiltinLoc()),
+STRING_LOCATION_PAIR(TA,
+  getTypeSourceInfo()->getTypeLoc().getAs<clang::BuiltinTypeLoc>().getNameLoc()),
+STRING_LOCATION_PAIR(
+    TA, getTypeSourceInfo()->getTypeLoc().getBeginLoc()),
+STRING_LOCATION_PAIR(
+    TA, getTypeSourceInfo()->getTypeLoc().getEndLoc())
+  ));
+  // clang-format on
 
   auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors);
 
-  EXPECT_THAT(ExpectedRanges,
-              UnorderedElementsAre(STRING_LOCATION_PAIR(TA, getSourceRange())));
+  EXPECT_THAT(
+      ExpectedRanges,
+      UnorderedElementsAre(
+          STRING_LOCATION_PAIR(TA, getSourceRange()),
+          STRING_LOCATION_PAIR(
+              TA, getTypeSourceInfo()->getTypeLoc().getSourceRange()),
+          STRING_LOCATION_PAIR(
+              TA, getTypeSourceInfo()->getTypeLoc().getLocalSourceRange())));
 }
 
 TEST(Introspection, SourceLocations_TA_Decl) {
@@ -498,13 +598,31 @@
   auto ExpectedLocations =
       FormatExpected<SourceLocation>(Result.LocationAccessors);
 
+  // clang-format off
   EXPECT_THAT(ExpectedLocations,
-              UnorderedElementsAre(STRING_LOCATION_PAIR(TA, getLocation())));
+              UnorderedElementsAre(
+STRING_LOCATION_PAIR(TA, getLocation()),
+STRING_LOCATION_PAIR(TA,
+  getTypeSourceInfo()->getTypeLoc().getAs<clang::BuiltinTypeLoc>().getBuiltinLoc()),
+STRING_LOCATION_PAIR(TA,
+  getTypeSourceInfo()->getTypeLoc().getAs<clang::BuiltinTypeLoc>().getNameLoc()),
+STRING_LOCATION_PAIR(
+    TA, getTypeSourceInfo()->getTypeLoc().getBeginLoc()),
+STRING_LOCATION_PAIR(
+    TA, getTypeSourceInfo()->getTypeLoc().getEndLoc())
+  ));
+  // clang-format on
 
   auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors);
 
-  EXPECT_THAT(ExpectedRanges,
-              UnorderedElementsAre(STRING_LOCATION_PAIR(TA, getSourceRange())));
+  EXPECT_THAT(
+      ExpectedRanges,
+      UnorderedElementsAre(
+          STRING_LOCATION_PAIR(TA, getSourceRange()),
+          STRING_LOCATION_PAIR(
+              TA, getTypeSourceInfo()->getTypeLoc().getSourceRange()),
+          STRING_LOCATION_PAIR(
+              TA, getTypeSourceInfo()->getTypeLoc().getLocalSourceRange())));
 }
 
 TEST(Introspection, SourceLocations_CXXCtorInitializer_base) {
@@ -539,16 +657,27 @@
   auto ExpectedLocations =
       FormatExpected<SourceLocation>(Result.LocationAccessors);
 
-  EXPECT_THAT(ExpectedLocations,
-              UnorderedElementsAre(
-                  STRING_LOCATION_PAIR(CtorInit, getLParenLoc()),
-                  STRING_LOCATION_PAIR(CtorInit, getRParenLoc()),
-                  STRING_LOCATION_PAIR(CtorInit, getSourceLocation())));
+  EXPECT_THAT(
+      ExpectedLocations,
+      UnorderedElementsAre(
+          STRING_LOCATION_PAIR(CtorInit, getLParenLoc()),
+          STRING_LOCATION_PAIR(CtorInit, getRParenLoc()),
+          STRING_LOCATION_PAIR(CtorInit, getSourceLocation()),
+          STRING_LOCATION_PAIR(CtorInit, getBaseClassLoc().getBeginLoc()),
+          STRING_LOCATION_PAIR(
+              CtorInit,
+              getBaseClassLoc().getAs<clang::TypeSpecTypeLoc>().getNameLoc()),
+          STRING_LOCATION_PAIR(CtorInit, getBaseClassLoc().getEndLoc())));
 
   auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors);
 
-  EXPECT_THAT(ExpectedRanges, UnorderedElementsAre(STRING_LOCATION_PAIR(
-                                  CtorInit, getSourceRange())));
+  EXPECT_THAT(
+      ExpectedRanges,
+      UnorderedElementsAre(
+          STRING_LOCATION_PAIR(CtorInit, getSourceRange()),
+          STRING_LOCATION_PAIR(CtorInit,
+                               getBaseClassLoc().getLocalSourceRange()),
+          STRING_LOCATION_PAIR(CtorInit, getBaseClassLoc().getSourceRange())));
 }
 
 TEST(Introspection, SourceLocations_CXXCtorInitializer_member) {
@@ -624,16 +753,33 @@
   auto ExpectedLocations =
       FormatExpected<SourceLocation>(Result.LocationAccessors);
 
-  EXPECT_THAT(ExpectedLocations,
-              UnorderedElementsAre(
-                  STRING_LOCATION_PAIR(CtorInit, getLParenLoc()),
-                  STRING_LOCATION_PAIR(CtorInit, getRParenLoc()),
-                  STRING_LOCATION_PAIR(CtorInit, getSourceLocation())));
+  // clang-format off
+  EXPECT_THAT(
+      ExpectedLocations,
+      UnorderedElementsAre(
+STRING_LOCATION_PAIR(CtorInit, getLParenLoc()),
+STRING_LOCATION_PAIR(CtorInit, getRParenLoc()),
+STRING_LOCATION_PAIR(CtorInit, getSourceLocation()),
+STRING_LOCATION_PAIR(CtorInit,
+                     getTypeSourceInfo()->getTypeLoc().getBeginLoc()),
+STRING_LOCATION_PAIR(CtorInit,
+                     getTypeSourceInfo()->getTypeLoc().getEndLoc()),
+STRING_LOCATION_PAIR(CtorInit,
+  getTypeSourceInfo()->getTypeLoc().getAs<clang::TypeSpecTypeLoc>().getNameLoc())
+  ));
+  // clang-format on
 
   auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors);
 
-  EXPECT_THAT(ExpectedRanges, UnorderedElementsAre(STRING_LOCATION_PAIR(
-                                  CtorInit, getSourceRange())));
+  EXPECT_THAT(
+      ExpectedRanges,
+      UnorderedElementsAre(
+          STRING_LOCATION_PAIR(CtorInit, getSourceRange()),
+          STRING_LOCATION_PAIR(
+              CtorInit,
+              getTypeSourceInfo()->getTypeLoc().getLocalSourceRange()),
+          STRING_LOCATION_PAIR(
+              CtorInit, getTypeSourceInfo()->getTypeLoc().getSourceRange())));
 }
 
 TEST(Introspection, SourceLocations_CXXCtorInitializer_pack) {
@@ -671,18 +817,81 @@
   auto ExpectedLocations =
       FormatExpected<SourceLocation>(Result.LocationAccessors);
 
-  EXPECT_THAT(ExpectedLocations,
-              UnorderedElementsAre(
-                  STRING_LOCATION_PAIR(CtorInit, getEllipsisLoc()),
-                  STRING_LOCATION_PAIR(CtorInit, getLParenLoc()),
-                  STRING_LOCATION_PAIR(CtorInit, getMemberLocation()),
-                  STRING_LOCATION_PAIR(CtorInit, getRParenLoc()),
-                  STRING_LOCATION_PAIR(CtorInit, getSourceLocation())));
+  // clang-format off
+  EXPECT_THAT(
+      ExpectedLocations,
+      UnorderedElementsAre(
+STRING_LOCATION_PAIR(CtorInit, getEllipsisLoc()),
+STRING_LOCATION_PAIR(CtorInit, getLParenLoc()),
+STRING_LOCATION_PAIR(CtorInit, getMemberLocation()),
+STRING_LOCATION_PAIR(CtorInit, getRParenLoc()),
+STRING_LOCATION_PAIR(CtorInit, getSourceLocation()),
+STRING_LOCATION_PAIR(CtorInit, getBaseClassLoc().getBeginLoc()),
+STRING_LOCATION_PAIR(
+    CtorInit, getBaseClassLoc().getAs<clang::TemplateSpecializationTypeLoc>().getTemplateNameLoc()),
+STRING_LOCATION_PAIR(
+    CtorInit, getBaseClassLoc().getAs<clang::TemplateSpecializationTypeLoc>().getLAngleLoc()),
+STRING_LOCATION_PAIR(CtorInit, getBaseClassLoc().getEndLoc()),
+STRING_LOCATION_PAIR(
+    CtorInit, getBaseClassLoc().getAs<clang::TemplateSpecializationTypeLoc>().getRAngleLoc())
+  ));
+  // clang-format on
 
   auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors);
 
-  EXPECT_THAT(ExpectedRanges, UnorderedElementsAre(STRING_LOCATION_PAIR(
-                                  CtorInit, getSourceRange())));
+  EXPECT_THAT(
+      ExpectedRanges,
+      UnorderedElementsAre(
+          STRING_LOCATION_PAIR(CtorInit, getSourceRange()),
+          STRING_LOCATION_PAIR(CtorInit,
+                               getBaseClassLoc().getLocalSourceRange()),
+          STRING_LOCATION_PAIR(CtorInit, getBaseClassLoc().getSourceRange())));
+}
+
+TEST(Introspection, SourceLocations_Formatter) {
+  auto AST =
+      buildASTFromCode(R"cpp(
+class A {};
+class B : A {};
+)cpp",
+                       "foo.cpp", std::make_shared<PCHContainerOperations>());
+  auto &Ctx = AST->getASTContext();
+  auto &TU = *Ctx.getTranslationUnitDecl();
+
+  auto BoundNodes = ast_matchers::match(
+      decl(hasDescendant(cxxRecordDecl(hasDirectBase(
+          cxxBaseSpecifier(hasType(asString("class A"))).bind("base"))))),
+      TU, Ctx);
+
+  EXPECT_EQ(BoundNodes.size(), 1u);
+
+  const auto *Base = BoundNodes[0].getNodeAs<CXXBaseSpecifier>("base");
+
+  auto Result = NodeIntrospection::GetLocations(Base);
+
+  if (Result.LocationAccessors.empty() && Result.RangeAccessors.empty()) {
+    return;
+  }
+
+  auto Iter = llvm::find_if(Result.LocationAccessors, [Base](auto Item) {
+    return Item.first == Base->getTypeSourceInfo()
+                             ->getTypeLoc()
+                             .getAs<clang::TypeSpecTypeLoc>()
+                             .getNameLoc() &&
+           Item.second->name() == "getNameLoc";
+  });
+  EXPECT_NE(Iter, Result.LocationAccessors.end());
+
+  EXPECT_EQ(Iter->first, Base->getTypeSourceInfo()
+                             ->getTypeLoc()
+                             .getAs<clang::TypeSpecTypeLoc>()
+                             .getNameLoc());
+
+  EXPECT_EQ("getTypeSourceInfo()->getTypeLoc().getAs<clang::TypeSpecTypeLoc>()."
+            "getNameLoc()",
+            LocationCallFormatterCpp::format(Iter->second.get()));
+  EXPECT_EQ("getTypeSourceInfo().getTypeLoc().getNameLoc()",
+            LocationCallFormatterSimple::format(Iter->second.get()));
 }
 
 TEST(Introspection, SourceLocations_CXXBaseSpecifier_plain) {
@@ -713,15 +922,27 @@
   auto ExpectedLocations =
       FormatExpected<SourceLocation>(Result.LocationAccessors);
 
+  // clang-format off
   EXPECT_THAT(ExpectedLocations,
-              UnorderedElementsAre(STRING_LOCATION_PAIR(Base, getBaseTypeLoc()),
-                                   STRING_LOCATION_PAIR(Base, getBeginLoc()),
-                                   STRING_LOCATION_PAIR(Base, getEndLoc())));
+              UnorderedElementsAre(
+STRING_LOCATION_PAIR(Base, getBaseTypeLoc()),
+STRING_LOCATION_PAIR(Base, getBeginLoc()),
+STRING_LOCATION_PAIR(Base, getEndLoc()),
+STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getAs<clang::TypeSpecTypeLoc>().getNameLoc()),
+STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getEndLoc()),
+STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getBeginLoc())
+  ));
+  // clang-format on
 
   auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors);
 
-  EXPECT_THAT(ExpectedRanges, UnorderedElementsAre(STRING_LOCATION_PAIR(
-                                  Base, getSourceRange())));
+  // clang-format off
+  EXPECT_THAT(ExpectedRanges, UnorderedElementsAre(
+STRING_LOCATION_PAIR(Base, getSourceRange()),
+STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getSourceRange()),
+STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getLocalSourceRange())
+    ));
+  // clang-format on
 }
 
 TEST(Introspection, SourceLocations_CXXBaseSpecifier_accessspec) {
@@ -752,15 +973,27 @@
   auto ExpectedLocations =
       FormatExpected<SourceLocation>(Result.LocationAccessors);
 
+  // clang-format off
   EXPECT_THAT(ExpectedLocations,
-              UnorderedElementsAre(STRING_LOCATION_PAIR(Base, getBaseTypeLoc()),
-                                   STRING_LOCATION_PAIR(Base, getBeginLoc()),
-                                   STRING_LOCATION_PAIR(Base, getEndLoc())));
+              UnorderedElementsAre(
+STRING_LOCATION_PAIR(Base, getBaseTypeLoc()),
+STRING_LOCATION_PAIR(Base, getBeginLoc()),
+STRING_LOCATION_PAIR(Base, getEndLoc()),
+STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getAs<clang::TypeSpecTypeLoc>().getNameLoc()),
+STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getEndLoc()),
+STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getBeginLoc())
+  ));
+  // clang-format on
 
   auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors);
 
-  EXPECT_THAT(ExpectedRanges, UnorderedElementsAre(STRING_LOCATION_PAIR(
-                                  Base, getSourceRange())));
+  // clang-format off
+  EXPECT_THAT(ExpectedRanges, UnorderedElementsAre(
+STRING_LOCATION_PAIR(Base, getSourceRange()),
+STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getLocalSourceRange()),
+STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getSourceRange())
+  ));
+  // clang-format on
 }
 
 TEST(Introspection, SourceLocations_CXXBaseSpecifier_virtual) {
@@ -792,15 +1025,27 @@
   auto ExpectedLocations =
       FormatExpected<SourceLocation>(Result.LocationAccessors);
 
+  // clang-format off
   EXPECT_THAT(ExpectedLocations,
-              UnorderedElementsAre(STRING_LOCATION_PAIR(Base, getBaseTypeLoc()),
-                                   STRING_LOCATION_PAIR(Base, getBeginLoc()),
-                                   STRING_LOCATION_PAIR(Base, getEndLoc())));
+              UnorderedElementsAre(
+STRING_LOCATION_PAIR(Base, getBaseTypeLoc()),
+STRING_LOCATION_PAIR(Base, getBeginLoc()),
+STRING_LOCATION_PAIR(Base, getEndLoc()),
+STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getBeginLoc()),
+STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getAs<clang::TypeSpecTypeLoc>().getNameLoc()),
+STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getEndLoc())
+  ));
+  // clang-format on
 
   auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors);
 
-  EXPECT_THAT(ExpectedRanges, UnorderedElementsAre(STRING_LOCATION_PAIR(
-                                  Base, getSourceRange())));
+  // clang-format off
+  EXPECT_THAT(ExpectedRanges, UnorderedElementsAre(
+STRING_LOCATION_PAIR(Base, getSourceRange()),
+STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getSourceRange()),
+STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getLocalSourceRange())
+  ));
+  // clang-format on
 }
 
 TEST(Introspection, SourceLocations_CXXBaseSpecifier_template_base) {
@@ -832,15 +1077,29 @@
   auto ExpectedLocations =
       FormatExpected<SourceLocation>(Result.LocationAccessors);
 
+  // clang-format off
   EXPECT_THAT(ExpectedLocations,
-              UnorderedElementsAre(STRING_LOCATION_PAIR(Base, getBaseTypeLoc()),
-                                   STRING_LOCATION_PAIR(Base, getBeginLoc()),
-                                   STRING_LOCATION_PAIR(Base, getEndLoc())));
+              UnorderedElementsAre(
+STRING_LOCATION_PAIR(Base, getBaseTypeLoc()),
+STRING_LOCATION_PAIR(Base, getBeginLoc()),
+STRING_LOCATION_PAIR(Base, getEndLoc()),
+STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getBeginLoc()),
+STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getAs<clang::TemplateSpecializationTypeLoc>().getTemplateNameLoc()),
+STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getAs<clang::TemplateSpecializationTypeLoc>().getLAngleLoc()),
+STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getEndLoc()),
+STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getAs<clang::TemplateSpecializationTypeLoc>().getRAngleLoc())
+  ));
+  // clang-format on
 
   auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors);
 
-  EXPECT_THAT(ExpectedRanges, UnorderedElementsAre(STRING_LOCATION_PAIR(
-                                  Base, getSourceRange())));
+  // clang-format off
+  EXPECT_THAT(ExpectedRanges, UnorderedElementsAre(
+STRING_LOCATION_PAIR(Base, getSourceRange()),
+STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getSourceRange()),
+STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getLocalSourceRange())
+  ));
+  // clang-format on
 }
 
 TEST(Introspection, SourceLocations_CXXBaseSpecifier_pack) {
@@ -873,14 +1132,184 @@
   auto ExpectedLocations =
       FormatExpected<SourceLocation>(Result.LocationAccessors);
 
+  // clang-format off
   EXPECT_THAT(ExpectedLocations,
-              UnorderedElementsAre(STRING_LOCATION_PAIR(Base, getBaseTypeLoc()),
-                                   STRING_LOCATION_PAIR(Base, getEllipsisLoc()),
-                                   STRING_LOCATION_PAIR(Base, getBeginLoc()),
-                                   STRING_LOCATION_PAIR(Base, getEndLoc())));
+              UnorderedElementsAre(
+STRING_LOCATION_PAIR(Base, getBaseTypeLoc()),
+STRING_LOCATION_PAIR(Base, getEllipsisLoc()),
+STRING_LOCATION_PAIR(Base, getBeginLoc()),
+STRING_LOCATION_PAIR(Base, getEndLoc()),
+STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getEndLoc()),
+STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getAs<clang::TypeSpecTypeLoc>().getNameLoc()),
+STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getBeginLoc())
+  ));
+  // clang-format on
 
   auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors);
 
-  EXPECT_THAT(ExpectedRanges, UnorderedElementsAre(STRING_LOCATION_PAIR(
-                                  Base, getSourceRange())));
+  // clang-format off
+  EXPECT_THAT(ExpectedRanges, UnorderedElementsAre(
+STRING_LOCATION_PAIR(Base, getSourceRange()),
+STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getSourceRange()),
+STRING_LOCATION_PAIR(Base, getTypeSourceInfo()->getTypeLoc().getLocalSourceRange())
+  ));
+  // clang-format on
+}
+
+TEST(Introspection, SourceLocations_FunctionProtoTypeLoc) {
+  auto AST =
+      buildASTFromCode(R"cpp(
+int foo();
+)cpp",
+                       "foo.cpp", std::make_shared<PCHContainerOperations>());
+  auto &Ctx = AST->getASTContext();
+  auto &TU = *Ctx.getTranslationUnitDecl();
+
+  auto BoundNodes = ast_matchers::match(
+      decl(hasDescendant(loc(functionProtoType()).bind("tl"))), TU, Ctx);
+
+  EXPECT_EQ(BoundNodes.size(), 1u);
+
+  const auto *TL = BoundNodes[0].getNodeAs<TypeLoc>("tl");
+  auto Result = NodeIntrospection::GetLocations(*TL);
+
+  if (Result.LocationAccessors.empty() && Result.RangeAccessors.empty()) {
+    return;
+  }
+
+  auto ExpectedLocations =
+      FormatExpected<SourceLocation>(Result.LocationAccessors);
+
+  EXPECT_THAT(
+      ExpectedLocations,
+      UnorderedElementsAre(
+          STRING_LOCATION_PAIR(TL, getBeginLoc()),
+          STRING_LOCATION_PAIR(TL, getNextTypeLoc().getEndLoc()),
+          STRING_LOCATION_PAIR(
+              TL,
+              getNextTypeLoc().getAs<clang::BuiltinTypeLoc>().getBuiltinLoc()),
+          STRING_LOCATION_PAIR(TL, getNextTypeLoc().getBeginLoc()),
+          STRING_LOCATION_PAIR(
+              TL, getNextTypeLoc().getAs<clang::BuiltinTypeLoc>().getNameLoc()),
+          STRING_LOCATION_PAIR(TL,
+                               getAs<clang::FunctionTypeLoc>().getLParenLoc()),
+          STRING_LOCATION_PAIR(
+              TL, getAs<clang::FunctionTypeLoc>().getLocalRangeBegin()),
+          STRING_LOCATION_PAIR(
+              TL, getAs<clang::FunctionTypeLoc>().getLocalRangeEnd()),
+          STRING_LOCATION_PAIR(TL, getEndLoc()),
+          STRING_LOCATION_PAIR(
+              TL, getAs<clang::FunctionTypeLoc>().getRParenLoc())));
+
+  auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors);
+
+  EXPECT_THAT(
+      ExpectedRanges,
+      UnorderedElementsAre(
+          STRING_LOCATION_PAIR(TL, getNextTypeLoc().getLocalSourceRange()),
+          STRING_LOCATION_PAIR(TL, getNextTypeLoc().getSourceRange()),
+          STRING_LOCATION_PAIR(TL, getSourceRange()),
+          STRING_LOCATION_PAIR(TL, getLocalSourceRange()),
+          STRING_LOCATION_PAIR(
+              TL, getAs<clang::FunctionTypeLoc>().getParensRange())));
+}
+
+TEST(Introspection, SourceLocations_PointerTypeLoc) {
+  auto AST =
+      buildASTFromCode(R"cpp(
+int* i;
+)cpp",
+                       "foo.cpp", std::make_shared<PCHContainerOperations>());
+  auto &Ctx = AST->getASTContext();
+  auto &TU = *Ctx.getTranslationUnitDecl();
+
+  auto BoundNodes = ast_matchers::match(
+      decl(hasDescendant(
+          varDecl(hasName("i"), hasDescendant(loc(pointerType()).bind("tl"))))),
+      TU, Ctx);
+
+  EXPECT_EQ(BoundNodes.size(), 1u);
+
+  const auto *TL = BoundNodes[0].getNodeAs<TypeLoc>("tl");
+  auto Result = NodeIntrospection::GetLocations(*TL);
+
+  if (Result.LocationAccessors.empty() && Result.RangeAccessors.empty()) {
+    return;
+  }
+
+  auto ExpectedLocations =
+      FormatExpected<SourceLocation>(Result.LocationAccessors);
+
+  EXPECT_THAT(
+      ExpectedLocations,
+      UnorderedElementsAre(
+          STRING_LOCATION_PAIR(TL, getBeginLoc()),
+          STRING_LOCATION_PAIR(TL, getEndLoc()),
+          STRING_LOCATION_PAIR(TL, getNextTypeLoc().getBeginLoc()),
+          STRING_LOCATION_PAIR(TL, getNextTypeLoc().getEndLoc()),
+          STRING_LOCATION_PAIR(
+              TL, getNextTypeLoc().getAs<clang::BuiltinTypeLoc>().getNameLoc()),
+          STRING_LOCATION_PAIR(
+              TL,
+              getNextTypeLoc().getAs<clang::BuiltinTypeLoc>().getBuiltinLoc()),
+          STRING_LOCATION_PAIR(TL, getAs<clang::PointerTypeLoc>().getStarLoc()),
+          STRING_LOCATION_PAIR(TL,
+                               getAs<clang::PointerTypeLoc>().getSigilLoc())));
+
+  auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors);
+
+  EXPECT_THAT(
+      ExpectedRanges,
+      UnorderedElementsAre(
+          STRING_LOCATION_PAIR(TL, getLocalSourceRange()),
+          STRING_LOCATION_PAIR(TL, getSourceRange()),
+          STRING_LOCATION_PAIR(TL, getNextTypeLoc().getLocalSourceRange()),
+          STRING_LOCATION_PAIR(TL, getNextTypeLoc().getSourceRange())));
+}
+
+TEST(Introspection, SourceLocations_TypeOfTypeLoc) {
+  auto AST =
+      buildASTFromCode(R"cpp(
+typeof (static_cast<void *>(0)) i;
+)cpp",
+                       "foo.cpp", std::make_shared<PCHContainerOperations>());
+  auto &Ctx = AST->getASTContext();
+  auto &TU = *Ctx.getTranslationUnitDecl();
+
+  auto BoundNodes = ast_matchers::match(
+      decl(hasDescendant(
+          varDecl(hasName("i"), hasDescendant(loc(type()).bind("tl"))))),
+      TU, Ctx);
+
+  EXPECT_EQ(BoundNodes.size(), 1u);
+
+  const auto *TL = BoundNodes[0].getNodeAs<TypeLoc>("tl");
+  auto Result = NodeIntrospection::GetLocations(*TL);
+
+  if (Result.LocationAccessors.empty() && Result.RangeAccessors.empty()) {
+    return;
+  }
+
+  auto ExpectedLocations =
+      FormatExpected<SourceLocation>(Result.LocationAccessors);
+
+  EXPECT_THAT(ExpectedLocations,
+              UnorderedElementsAre(
+                  STRING_LOCATION_PAIR(TL, getBeginLoc()),
+                  STRING_LOCATION_PAIR(TL, getEndLoc()),
+                  STRING_LOCATION_PAIR(
+                      TL, getAs<clang::TypeOfExprTypeLoc>().getTypeofLoc()),
+                  STRING_LOCATION_PAIR(
+                      TL, getAs<clang::TypeOfExprTypeLoc>().getLParenLoc()),
+                  STRING_LOCATION_PAIR(
+                      TL, getAs<clang::TypeOfExprTypeLoc>().getRParenLoc())));
+
+  auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors);
+
+  EXPECT_THAT(ExpectedRanges,
+              UnorderedElementsAre(
+                  STRING_LOCATION_PAIR(TL, getLocalSourceRange()),
+                  STRING_LOCATION_PAIR(TL, getSourceRange()),
+                  STRING_LOCATION_PAIR(
+                      TL, getAs<clang::TypeOfExprTypeLoc>().getParensRange())));
 }
Index: clang/lib/Tooling/NodeIntrospection.cpp
===================================================================
--- clang/lib/Tooling/NodeIntrospection.cpp
+++ clang/lib/Tooling/NodeIntrospection.cpp
@@ -30,7 +30,7 @@
         (VecCall->name() + "()" + (VecCall->returnsPointer() ? "->" : "."))
             .str();
   }
-  result += (vec.back()->name() + "()").str();
+  result += (vec.front()->name() + "()").str();
   return result;
 }
 
@@ -38,27 +38,14 @@
 bool RangeLessThan::operator()(
     std::pair<SourceRange, SharedLocationCall> const &LHS,
     std::pair<SourceRange, SharedLocationCall> const &RHS) const {
-  if (!LHS.first.isValid() || !RHS.first.isValid())
-    return false;
-
-  if (LHS.first.getBegin() < RHS.first.getBegin())
-    return true;
-  else if (LHS.first.getBegin() != RHS.first.getBegin())
-    return false;
-
-  if (LHS.first.getEnd() < RHS.first.getEnd())
-    return true;
-  else if (LHS.first.getEnd() != RHS.first.getEnd())
-    return false;
-
-  return LHS.second->name() < RHS.second->name();
+  return LocationCallFormatterCpp::format(LHS.second.get()) <
+         LocationCallFormatterCpp::format(RHS.second.get());
 }
 bool RangeLessThan::operator()(
     std::pair<SourceLocation, SharedLocationCall> const &LHS,
     std::pair<SourceLocation, SharedLocationCall> const &RHS) const {
-  if (LHS.first == RHS.first)
-    return LHS.second->name() < RHS.second->name();
-  return LHS.first < RHS.first;
+  return LocationCallFormatterCpp::format(LHS.second.get()) <
+         LocationCallFormatterCpp::format(RHS.second.get());
 }
 } // namespace internal
 
Index: clang/lib/Tooling/DumpTool/generate_cxx_src_locs.py
===================================================================
--- clang/lib/Tooling/DumpTool/generate_cxx_src_locs.py
+++ clang/lib/Tooling/DumpTool/generate_cxx_src_locs.py
@@ -11,6 +11,9 @@
 
     implementationContent = ''
 
+    def __init__(self, templateClasses):
+        self.templateClasses = templateClasses
+
     def GeneratePrologue(self):
 
         self.implementationContent += \
@@ -31,22 +34,49 @@
 """
 
     def GenerateBaseGetLocationsDeclaration(self, CladeName):
+        InstanceDecoration = "*"
+        if CladeName == "TypeLoc":
+            InstanceDecoration = "&"
+
         self.implementationContent += \
             """
 void GetLocationsImpl(SharedLocationCall const& Prefix,
-    clang::{0} const *Object, SourceLocationMap &Locs,
-    SourceRangeMap &Rngs);
-""".format(CladeName)
-
-    def GenerateSrcLocMethod(self, ClassName, ClassData):
+    clang::{0} const {1}Object, SourceLocationMap &Locs,
+    SourceRangeMap &Rngs,
+    std::vector<clang::TypeLoc> &TypeLocRecursionGuard);
+""".format(CladeName, InstanceDecoration)
+
+    def GenerateSrcLocMethod(self,
+            ClassName, ClassData, CreateLocalRecursionGuard):
+
+        NormalClassName = ClassName
+        RecursionGuardParam = ('' if CreateLocalRecursionGuard else \
+            ', std::vector<clang::TypeLoc>& TypeLocRecursionGuard')
+
+        if "templateParms" in ClassData:
+            TemplatePreamble = "template <typename "
+            ClassName += "<"
+            First = True
+            for TA in ClassData["templateParms"]:
+                if not First:
+                    ClassName += ", "
+                    TemplatePreamble += ", typename "
+
+                First = False
+                ClassName += TA
+                TemplatePreamble += TA
+
+            ClassName += ">"
+            TemplatePreamble += ">\n";
+            self.implementationContent += TemplatePreamble
 
         self.implementationContent += \
             """
 static void GetLocations{0}(SharedLocationCall const& Prefix,
-    clang::{0} const &Object,
-    SourceLocationMap &Locs, SourceRangeMap &Rngs)
+    clang::{1} const &Object,
+    SourceLocationMap &Locs, SourceRangeMap &Rngs {2})
 {{
-""".format(ClassName)
+""".format(NormalClassName, ClassName, RecursionGuardParam)
 
         if 'sourceLocations' in ClassData:
             for locName in ClassData['sourceLocations']:
@@ -68,6 +98,40 @@
 
             self.implementationContent += '\n'
 
+        if 'typeLocs' in ClassData or 'typeSourceInfos' in ClassData:
+            if CreateLocalRecursionGuard:
+                self.implementationContent += \
+                    'std::vector<clang::TypeLoc> TypeLocRecursionGuard;\n'
+
+            self.implementationContent += '\n'
+
+            if 'typeLocs' in ClassData:
+                for typeLoc in ClassData['typeLocs']:
+
+                    self.implementationContent += \
+                        """
+              if (Object.{0}()) {{
+                GetLocationsImpl(
+                    llvm::makeIntrusiveRefCnt<LocationCall>(Prefix, "{0}"),
+                    Object.{0}(), Locs, Rngs, TypeLocRecursionGuard);
+                }}
+              """.format(typeLoc)
+
+            self.implementationContent += '\n'
+            if 'typeSourceInfos' in ClassData:
+                for tsi in ClassData['typeSourceInfos']:
+                    self.implementationContent += \
+                        """
+              if (Object.{0}()) {{
+                GetLocationsImpl(llvm::makeIntrusiveRefCnt<LocationCall>(
+                    llvm::makeIntrusiveRefCnt<LocationCall>(Prefix, "{0}",
+                        LocationCall::ReturnsPointer), "getTypeLoc"),
+                    Object.{0}()->getTypeLoc(), Locs, Rngs, TypeLocRecursionGuard);
+                    }}
+              """.format(tsi)
+
+                self.implementationContent += '\n'
+
         self.implementationContent += '}\n'
 
     def GenerateFiles(self, OutputFile):
@@ -75,32 +139,77 @@
                   OutputFile), 'w') as f:
             f.write(self.implementationContent)
 
-    def GenerateBaseGetLocationsFunction(self, ASTClassNames, CladeName):
+    def GenerateBaseGetLocationsFunction(self, ASTClassNames,
+            ClassEntries, CladeName, InheritanceMap,
+            CreateLocalRecursionGuard):
 
         MethodReturnType = 'NodeLocationAccessors'
+        InstanceDecoration = "*"
+        if CladeName == "TypeLoc":
+            InstanceDecoration = "&"
 
         Signature = \
-            'GetLocations(clang::{0} const *Object)'.format(CladeName)
+            'GetLocations(clang::{0} const {1}Object)'.format(
+                CladeName, InstanceDecoration)
         ImplSignature = \
             """
-GetLocationsImpl(SharedLocationCall const& Prefix,
-    clang::{0} const *Object, SourceLocationMap &Locs,
-    SourceRangeMap &Rngs)
-""".format(CladeName)
+    GetLocationsImpl(SharedLocationCall const& Prefix,
+        clang::{0} const {1}Object, SourceLocationMap &Locs,
+        SourceRangeMap &Rngs,
+        std::vector<clang::TypeLoc> &TypeLocRecursionGuard)
+    """.format(CladeName, InstanceDecoration)
+
+        self.implementationContent += 'void {0} {{ '.format(ImplSignature)
+
+        if CladeName == "TypeLoc":
+            self.implementationContent += 'if (Object.isNull()) return;'
 
+            self.implementationContent += \
+                """
+            if (llvm::find(TypeLocRecursionGuard, Object) != TypeLocRecursionGuard.end())
+              return;
+            TypeLocRecursionGuard.push_back(Object);
+                """
+
+        RecursionGuardParam = ''
+        if not CreateLocalRecursionGuard:
+            RecursionGuardParam = ', TypeLocRecursionGuard'
+
+        ArgPrefix = '*'
+        if CladeName == "TypeLoc":
+            ArgPrefix = ''
         self.implementationContent += \
-            'void {0} {{ GetLocations{1}(Prefix, *Object, Locs, Rngs);'.format(
-                ImplSignature,
-                CladeName)
+            'GetLocations{0}(Prefix, {1}Object, Locs, Rngs {2});'.format(
+                CladeName, ArgPrefix, RecursionGuardParam)
+
+        if CladeName == "TypeLoc":
+            self.implementationContent += \
+                '''
+        if (auto QTL = Object.getAs<clang::QualifiedTypeLoc>()) {
+            auto Dequalified = QTL.getNextTypeLoc();
+            return GetLocationsImpl(llvm::makeIntrusiveRefCnt<LocationCall>(Prefix, "getNextTypeLoc"),
+                                Dequalified,
+                                Locs,
+                                Rngs,
+                                TypeLocRecursionGuard);
+        }'''
 
         for ASTClassName in ASTClassNames:
-            if ASTClassName != CladeName:
+            if ASTClassName in self.templateClasses:
+                continue
+            if ASTClassName == CladeName:
+                continue
+            if CladeName != "TypeLoc":
                 self.implementationContent += \
-                    """
+                """
 if (auto Derived = llvm::dyn_cast<clang::{0}>(Object)) {{
-  GetLocations{0}(Prefix, *Derived, Locs, Rngs);
+  GetLocations{0}(Prefix, *Derived, Locs, Rngs {1});
 }}
-""".format(ASTClassName)
+""".format(ASTClassName, RecursionGuardParam)
+                continue
+
+            self.GenerateBaseTypeLocVisit(ASTClassName, ClassEntries,
+                RecursionGuardParam, InheritanceMap)
 
         self.implementationContent += '}'
 
@@ -109,14 +218,43 @@
 {0} NodeIntrospection::{1} {{
   NodeLocationAccessors Result;
   SharedLocationCall Prefix;
+  std::vector<clang::TypeLoc> TypeLocRecursionGuard;
 
   GetLocationsImpl(Prefix, Object, Result.LocationAccessors,
-                   Result.RangeAccessors);
-""".format(MethodReturnType,
-                Signature)
+                   Result.RangeAccessors, TypeLocRecursionGuard);
+""".format(MethodReturnType, Signature)
 
         self.implementationContent += 'return Result; }'
 
+    def GenerateBaseTypeLocVisit(self, ASTClassName, ClassEntries,
+            RecursionGuardParam, InheritanceMap):
+        CallPrefix = 'Prefix'
+        if ASTClassName != 'TypeLoc':
+            CallPrefix = \
+                '''llvm::makeIntrusiveRefCnt<LocationCall>(Prefix,
+                    "getAs<clang::{0}>", LocationCall::IsCast)
+                '''.format(ASTClassName)
+
+        if ASTClassName in ClassEntries:
+
+            self.implementationContent += \
+            """
+            if (auto ConcreteTL = Object.getAs<clang::{0}>())
+              GetLocations{1}({2}, ConcreteTL, Locs, Rngs {3});
+            """.format(ASTClassName, ASTClassName,
+                       CallPrefix, RecursionGuardParam)
+
+        if ASTClassName in InheritanceMap:
+            for baseTemplate in self.templateClasses:
+                if baseTemplate in InheritanceMap[ASTClassName]:
+                    self.implementationContent += \
+                    """
+    if (auto ConcreteTL = Object.getAs<clang::{0}>())
+      GetLocations{1}({2}, ConcreteTL, Locs, Rngs {3});
+    """.format(InheritanceMap[ASTClassName], baseTemplate,
+            CallPrefix, RecursionGuardParam)
+
+
     def GenerateDynNodeVisitor(self, CladeNames):
         MethodReturnType = 'NodeLocationAccessors'
 
@@ -130,7 +268,13 @@
             self.implementationContent += \
                 """
     if (const auto *N = Node.get<{0}>())
-      return GetLocations(const_cast<{0} *>(N));""".format(CladeName)
+    """.format(CladeName)
+            ArgPrefix = ""
+            if CladeName == "TypeLoc":
+                ArgPrefix = "*"
+            self.implementationContent += \
+            """
+      return GetLocations({0}const_cast<{1} *>(N));""".format(ArgPrefix, CladeName)
 
         self.implementationContent += '\nreturn {}; }'
 
@@ -196,6 +340,10 @@
     clang::CXXBaseSpecifier const*) {
   return {};
 }
+NodeLocationAccessors NodeIntrospection::GetLocations(
+    clang::TypeLoc const&) {
+  return {};
+}
 NodeLocationAccessors
 NodeIntrospection::GetLocations(clang::DynTypedNode const &) {
   return {};
@@ -205,19 +353,42 @@
     """)
         sys.exit(0)
 
-    g = Generator()
+    templateClasses = []
+    for (ClassName, ClassAccessors) in jsonData['classEntries'].items():
+        if "templateParms" in ClassAccessors:
+            templateClasses.append(ClassName)
+
+    g = Generator(templateClasses)
 
     g.GeneratePrologue()
 
     for (CladeName, ClassNameData) in jsonData['classesInClade'].items():
         g.GenerateBaseGetLocationsDeclaration(CladeName)
 
+    def getCladeName(ClassName):
+      for (CladeName, ClassNameData) in jsonData['classesInClade'].items():
+        if ClassName in ClassNameData:
+          return CladeName
+
     for (ClassName, ClassAccessors) in jsonData['classEntries'].items():
-        if ClassAccessors:
-            g.GenerateSrcLocMethod(ClassName, ClassAccessors)
+        cladeName = getCladeName(ClassName)
+        g.GenerateSrcLocMethod(
+            ClassName, ClassAccessors,
+            cladeName not in [
+                      'NestedNameSpecifierLoc',
+                      'TemplateArgumentLoc',
+                      'TypeLoc'])
 
     for (CladeName, ClassNameData) in jsonData['classesInClade'].items():
-        g.GenerateBaseGetLocationsFunction(ClassNameData, CladeName)
+        g.GenerateBaseGetLocationsFunction(
+            ClassNameData,
+            jsonData['classEntries'],
+            CladeName,
+            jsonData["classInheritance"],
+            CladeName not in [
+                      'NestedNameSpecifierLoc',
+                      'TemplateArgumentLoc',
+                      'TypeLoc'])
 
     g.GenerateDynNodeVisitor(jsonData['classesInClade'].keys())
 
Index: clang/lib/Tooling/DumpTool/ASTSrcLocProcessor.h
===================================================================
--- clang/lib/Tooling/DumpTool/ASTSrcLocProcessor.h
+++ clang/lib/Tooling/DumpTool/ASTSrcLocProcessor.h
@@ -35,7 +35,7 @@
 private:
   void run(const ast_matchers::MatchFinder::MatchResult &Result) override;
 
-  llvm::StringMap<StringRef> ClassInheritance;
+  llvm::StringMap<std::string> ClassInheritance;
   llvm::StringMap<std::vector<StringRef>> ClassesInClade;
   llvm::StringMap<ClassData> ClassEntries;
 
Index: clang/lib/Tooling/DumpTool/ASTSrcLocProcessor.cpp
===================================================================
--- clang/lib/Tooling/DumpTool/ASTSrcLocProcessor.cpp
+++ clang/lib/Tooling/DumpTool/ASTSrcLocProcessor.cpp
@@ -22,18 +22,28 @@
 
   Finder = std::make_unique<MatchFinder>(std::move(FinderOptions));
   Finder->addMatcher(
-      cxxRecordDecl(
-          isDefinition(),
-          isSameOrDerivedFrom(
-              // TODO: Extend this with other clades
-              namedDecl(hasAnyName("clang::Stmt", "clang::Decl",
-                                   "clang::CXXCtorInitializer",
-                                   "clang::NestedNameSpecifierLoc",
-                                   "clang::TemplateArgumentLoc",
-                                   "clang::CXXBaseSpecifier"))
-                  .bind("nodeClade")),
-          optionally(isDerivedFrom(cxxRecordDecl().bind("derivedFrom"))))
-          .bind("className"),
+      traverse(
+          TK_IgnoreUnlessSpelledInSource,
+          cxxRecordDecl(
+              isDefinition(),
+              isSameOrDerivedFrom(
+                  // TODO: Extend this with other clades
+                  namedDecl(hasAnyName("clang::Stmt", "clang::Decl",
+                                       "clang::CXXCtorInitializer",
+                                       "clang::NestedNameSpecifierLoc",
+                                       "clang::TemplateArgumentLoc",
+                                       "clang::CXXBaseSpecifier",
+                                       "clang::TypeLoc"))
+                      .bind("nodeClade")),
+              optionally(isDerivedFrom(cxxRecordDecl().bind("derivedFrom"))))
+              .bind("className")),
+      this);
+  Finder->addMatcher(
+      traverse(
+          TK_IgnoreUnlessSpelledInSource,
+          cxxRecordDecl(isDefinition(), hasAnyName("clang::PointerLikeTypeLoc",
+                                                   "clang::TypeofLikeTypeLoc"))
+              .bind("templateName")),
       this);
 }
 
@@ -53,7 +63,7 @@
   return JsonObj;
 }
 
-llvm::json::Object toJSON(llvm::StringMap<StringRef> const &Obj) {
+llvm::json::Object toJSON(llvm::StringMap<std::string> const &Obj) {
   using llvm::json::toJSON;
 
   llvm::json::Object JsonObj;
@@ -70,6 +80,12 @@
     JsonObj["sourceLocations"] = Obj.ASTClassLocations;
   if (!Obj.ASTClassRanges.empty())
     JsonObj["sourceRanges"] = Obj.ASTClassRanges;
+  if (!Obj.TemplateParms.empty())
+    JsonObj["templateParms"] = Obj.TemplateParms;
+  if (!Obj.TypeSourceInfos.empty())
+    JsonObj["typeSourceInfos"] = Obj.TypeSourceInfos;
+  if (!Obj.TypeLocs.empty())
+    JsonObj["typeLocs"] = Obj.TypeLocs;
   return JsonObj;
 }
 
@@ -77,10 +93,8 @@
   using llvm::json::toJSON;
 
   llvm::json::Object JsonObj;
-  for (const auto &Item : Obj) {
-    if (!Item.second.isEmpty())
-      JsonObj[Item.first()] = ::toJSON(Item.second);
-  }
+  for (const auto &Item : Obj)
+    JsonObj[Item.first()] = ::toJSON(Item.second);
   return JsonObj;
 }
 
@@ -127,7 +141,12 @@
                   equalsNode(ASTClass),
                   optionally(isDerivedFrom(
                       cxxRecordDecl(hasAnyName("clang::Stmt", "clang::Decl"))
-                          .bind("stmtOrDeclBase"))))),
+                          .bind("stmtOrDeclBase"))),
+                  optionally(isDerivedFrom(
+                      cxxRecordDecl(hasName("clang::Expr")).bind("exprBase"))),
+                  optionally(
+                      isDerivedFrom(cxxRecordDecl(hasName("clang::TypeLoc"))
+                                        .bind("typeLocBase"))))),
               returns(asString(TypeString)))
               .bind("classMethod")),
       *ASTClass, *Result.Context);
@@ -136,6 +155,8 @@
   for (const auto &BN : BoundNodesVec) {
     const auto *StmtOrDeclBase =
         BN.getNodeAs<clang::CXXRecordDecl>("stmtOrDeclBase");
+    const auto *TypeLocBase = BN.getNodeAs<clang::CXXRecordDecl>("typeLocBase");
+    const auto *ExprBase = BN.getNodeAs<clang::CXXRecordDecl>("exprBase");
     if (const auto *Node = BN.getNodeAs<clang::NamedDecl>("classMethod")) {
       // Only record the getBeginLoc etc on Stmt etc, because it will call
       // more-derived implementations pseudo-virtually.
@@ -146,9 +167,14 @@
 
       // Only record the getExprLoc on Expr, because it will call
       // more-derived implementations pseudo-virtually.
-      if (ASTClass->getName() != "Expr" && Node->getName() == "getExprLoc") {
+      if (ExprBase && Node->getName() == "getExprLoc")
+        continue;
+      if (TypeLocBase && Node->getName() == "getLocalSourceRange")
+        continue;
+      if ((ASTClass->getName() == "PointerLikeTypeLoc" ||
+           ASTClass->getName() == "TypeofLikeTypeLoc") &&
+          Node->getName() == "getLocalSourceRange")
         continue;
-      }
       Methods.push_back(Node->getName().str());
     }
   }
@@ -160,25 +186,63 @@
   const auto *ASTClass =
       Result.Nodes.getNodeAs<clang::CXXRecordDecl>("className");
 
+  StringRef CladeName;
+  if (ASTClass) {
+    if (const auto *NodeClade =
+            Result.Nodes.getNodeAs<clang::CXXRecordDecl>("nodeClade"))
+      CladeName = NodeClade->getName();
+  } else {
+    ASTClass = Result.Nodes.getNodeAs<clang::CXXRecordDecl>("templateName");
+    CladeName = "TypeLoc";
+  }
+
   StringRef ClassName = ASTClass->getName();
 
   ClassData CD;
 
-  const auto *NodeClade =
-      Result.Nodes.getNodeAs<clang::CXXRecordDecl>("nodeClade");
-  StringRef CladeName = NodeClade->getName();
-
-  if (const auto *DerivedFrom =
-          Result.Nodes.getNodeAs<clang::CXXRecordDecl>("derivedFrom"))
-    ClassInheritance[ClassName] = DerivedFrom->getName();
-
   CD.ASTClassLocations =
       CaptureMethods("class clang::SourceLocation", ASTClass, Result);
   CD.ASTClassRanges =
       CaptureMethods("class clang::SourceRange", ASTClass, Result);
+  CD.TypeSourceInfos =
+      CaptureMethods("class clang::TypeSourceInfo *", ASTClass, Result);
+  CD.TypeLocs = CaptureMethods("class clang::TypeLoc", ASTClass, Result);
 
-  if (!CD.isEmpty()) {
-    ClassEntries[ClassName] = CD;
-    ClassesInClade[CladeName].push_back(ClassName);
+  if (const auto *DerivedFrom =
+          Result.Nodes.getNodeAs<clang::CXXRecordDecl>("derivedFrom")) {
+
+    if (auto Templ = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(
+            DerivedFrom)) {
+
+      auto &TArgs = Templ->getTemplateArgs();
+
+      std::string TArgsString = (DerivedFrom->getName() + "<").str();
+
+      for (unsigned I = 0; I < TArgs.size(); ++I) {
+        if (I > 0) {
+          TArgsString += ", ";
+        }
+        auto Ty = TArgs.get(I).getAsType();
+        clang::PrintingPolicy PPol(Result.Context->getLangOpts());
+        PPol.TerseOutput = true;
+        TArgsString += Ty.getAsString(PPol);
+      }
+      TArgsString += ">";
+
+      ClassInheritance[ClassName] = std::move(TArgsString);
+    } else {
+      ClassInheritance[ClassName] = DerivedFrom->getName().str();
+    }
+  }
+
+  if (auto Templ = ASTClass->getDescribedClassTemplate()) {
+    if (auto TParams = Templ->getTemplateParameters()) {
+      for (auto &TParam : *TParams) {
+        CD.TemplateParms.push_back(TParam->getName().str());
+      }
+    }
   }
+
+  ClassEntries[ClassName] = CD;
+  ClassesInClade[CladeName].push_back(ClassName);
 }
Index: clang/lib/Tooling/DumpTool/APIData.h
===================================================================
--- clang/lib/Tooling/DumpTool/APIData.h
+++ clang/lib/Tooling/DumpTool/APIData.h
@@ -16,13 +16,11 @@
 namespace tooling {
 
 struct ClassData {
-
-  bool isEmpty() const {
-    return ASTClassLocations.empty() && ASTClassRanges.empty();
-  }
-
   std::vector<std::string> ASTClassLocations;
   std::vector<std::string> ASTClassRanges;
+  std::vector<std::string> TemplateParms;
+  std::vector<std::string> TypeSourceInfos;
+  std::vector<std::string> TypeLocs;
   // TODO: Extend this with locations available via typelocs etc.
 };
 
Index: clang/lib/Tooling/CMakeLists.txt
===================================================================
--- clang/lib/Tooling/CMakeLists.txt
+++ clang/lib/Tooling/CMakeLists.txt
@@ -57,6 +57,10 @@
     clang::CXXBaseSpecifier const*) {
   return {};
 }
+NodeLocationAccessors NodeIntrospection::GetLocations(
+    clang::TypeLoc const&) {
+  return {};
+}
 NodeLocationAccessors
 NodeIntrospection::GetLocations(clang::DynTypedNode const &) {
   return {};
Index: clang/include/clang/Tooling/NodeIntrospection.h
===================================================================
--- clang/include/clang/Tooling/NodeIntrospection.h
+++ clang/include/clang/Tooling/NodeIntrospection.h
@@ -90,6 +90,7 @@
 NodeLocationAccessors GetLocations(clang::NestedNameSpecifierLoc const *);
 NodeLocationAccessors GetLocations(clang::TemplateArgumentLoc const *);
 NodeLocationAccessors GetLocations(clang::CXXBaseSpecifier const *);
+NodeLocationAccessors GetLocations(clang::TypeLoc const &);
 NodeLocationAccessors GetLocations(clang::DynTypedNode const &Node);
 } // namespace NodeIntrospection
 } // namespace tooling
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to