[clang] dd68942 - [AST] Add TypeLoc support to node introspection

Stephen Kelly via cfe-commits cfe-commits at lists.llvm.org
Sat Apr 17 15:16:18 PDT 2021


Author: Stephen Kelly
Date: 2021-04-17T22:58:02+01:00
New Revision: dd68942f1d79986267a58c9a9924522680d5c82b

URL: https://github.com/llvm/llvm-project/commit/dd68942f1d79986267a58c9a9924522680d5c82b
DIFF: https://github.com/llvm/llvm-project/commit/dd68942f1d79986267a58c9a9924522680d5c82b.diff

LOG: [AST] Add TypeLoc support to node introspection

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.

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.

Introduce a recursion guard in the generated code.  The TypeLoc class
has IgnoreParens() API which by default returns itself, so it would
otherwise recurse infinitely.

Differential Revision: https://reviews.llvm.org/D100516

Added: 
    

Modified: 
    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/unittests/Introspection/IntrospectionTest.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Tooling/NodeIntrospection.h b/clang/include/clang/Tooling/NodeIntrospection.h
index c8518ea635461..dd7ffe3991207 100644
--- a/clang/include/clang/Tooling/NodeIntrospection.h
+++ b/clang/include/clang/Tooling/NodeIntrospection.h
@@ -86,6 +86,7 @@ NodeLocationAccessors GetLocations(clang::CXXCtorInitializer const *Object);
 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

diff  --git a/clang/lib/Tooling/CMakeLists.txt b/clang/lib/Tooling/CMakeLists.txt
index e90b681e16f42..dfb732371dfbf 100644
--- a/clang/lib/Tooling/CMakeLists.txt
+++ b/clang/lib/Tooling/CMakeLists.txt
@@ -58,6 +58,10 @@ NodeLocationAccessors NodeIntrospection::GetLocations(
     clang::CXXBaseSpecifier const*) {
   return {};
 }
+NodeLocationAccessors NodeIntrospection::GetLocations(
+    clang::TypeLoc const&) {
+  return {};
+}
 NodeLocationAccessors
 NodeIntrospection::GetLocations(clang::DynTypedNode const &) {
   return {};

diff  --git a/clang/lib/Tooling/DumpTool/APIData.h b/clang/lib/Tooling/DumpTool/APIData.h
index 0ec53f6e7dc3c..6ebf017b5c8f7 100644
--- a/clang/lib/Tooling/DumpTool/APIData.h
+++ b/clang/lib/Tooling/DumpTool/APIData.h
@@ -16,13 +16,11 @@ namespace clang {
 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.
 };
 

diff  --git a/clang/lib/Tooling/DumpTool/ASTSrcLocProcessor.cpp b/clang/lib/Tooling/DumpTool/ASTSrcLocProcessor.cpp
index a19114a060645..497cd3bdce2ca 100644
--- a/clang/lib/Tooling/DumpTool/ASTSrcLocProcessor.cpp
+++ b/clang/lib/Tooling/DumpTool/ASTSrcLocProcessor.cpp
@@ -22,18 +22,24 @@ ASTSrcLocProcessor::ASTSrcLocProcessor(StringRef JsonPath)
 
   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"),
+          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(
+          cxxRecordDecl(isDefinition(), hasAnyName("clang::PointerLikeTypeLoc",
+                                                   "clang::TypeofLikeTypeLoc"))
+              .bind("templateName"),
       this);
 }
 
@@ -53,7 +59,7 @@ llvm::json::Object toJSON(llvm::StringMap<std::vector<StringRef>> const &Obj) {
   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 +76,12 @@ llvm::json::Object toJSON(ClassData const &Obj) {
     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 +89,8 @@ llvm::json::Object toJSON(llvm::StringMap<ClassData> const &Obj) {
   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,28 +137,40 @@ CaptureMethods(std::string TypeString, const clang::CXXRecordDecl *ASTClass,
                   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);
 
   std::vector<std::string> Methods;
   for (const auto &BN : BoundNodesVec) {
-    const auto *StmtOrDeclBase =
-        BN.getNodeAs<clang::CXXRecordDecl>("stmtOrDeclBase");
     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.
+      const auto *StmtOrDeclBase =
+          BN.getNodeAs<clang::CXXRecordDecl>("stmtOrDeclBase");
+      const auto *TypeLocBase =
+          BN.getNodeAs<clang::CXXRecordDecl>("typeLocBase");
+      const auto *ExprBase = BN.getNodeAs<clang::CXXRecordDecl>("exprBase");
+      // The clang AST has several methods on base classes which are overriden
+      // pseudo-virtually by derived classes.
+      // We record only the pseudo-virtual methods on the base classes to
+      // avoid duplication.
       if (StmtOrDeclBase &&
           (Node->getName() == "getBeginLoc" || Node->getName() == "getEndLoc" ||
            Node->getName() == "getSourceRange"))
         continue;
-
-      // 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 +182,64 @@ void ASTSrcLocProcessor::run(const MatchFinder::MatchResult &Result) {
   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 (const auto *Templ =
+            llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(
+                DerivedFrom)) {
+
+      const 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 (const auto *Templ = ASTClass->getDescribedClassTemplate()) {
+    if (auto *TParams = Templ->getTemplateParameters()) {
+      for (const auto &TParam : *TParams) {
+        CD.TemplateParms.push_back(TParam->getName().str());
+      }
+    }
   }
+
+  ClassEntries[ClassName] = CD;
+  ClassesInClade[CladeName].push_back(ClassName);
 }

diff  --git a/clang/lib/Tooling/DumpTool/ASTSrcLocProcessor.h b/clang/lib/Tooling/DumpTool/ASTSrcLocProcessor.h
index 5d848f48ed548..05c4f92676e88 100644
--- a/clang/lib/Tooling/DumpTool/ASTSrcLocProcessor.h
+++ b/clang/lib/Tooling/DumpTool/ASTSrcLocProcessor.h
@@ -35,7 +35,11 @@ class ASTSrcLocProcessor : public ast_matchers::MatchFinder::MatchCallback {
 private:
   void run(const ast_matchers::MatchFinder::MatchResult &Result) override;
 
-  llvm::StringMap<StringRef> ClassInheritance;
+  llvm::Optional<TraversalKind> getCheckTraversalKind() const override {
+    return TK_IgnoreUnlessSpelledInSource;
+  }
+
+  llvm::StringMap<std::string> ClassInheritance;
   llvm::StringMap<std::vector<StringRef>> ClassesInClade;
   llvm::StringMap<ClassData> ClassEntries;
 

diff  --git a/clang/lib/Tooling/DumpTool/generate_cxx_src_locs.py b/clang/lib/Tooling/DumpTool/generate_cxx_src_locs.py
index b0953df192037..3664f521e27b7 100755
--- a/clang/lib/Tooling/DumpTool/generate_cxx_src_locs.py
+++ b/clang/lib/Tooling/DumpTool/generate_cxx_src_locs.py
@@ -11,6 +11,9 @@ class Generator(object):
 
     implementationContent = ''
 
+    def __init__(self, templateClasses):
+        self.templateClasses = templateClasses
+
     def GeneratePrologue(self):
 
         self.implementationContent += \
@@ -30,25 +33,69 @@ def GeneratePrologue(self):
 using RangeAndString = SourceRangeMap::value_type;
 
 bool NodeIntrospection::hasIntrospectionSupport() { return true; }
+
+struct RecursionPopper
+{
+    RecursionPopper(std::vector<clang::TypeLoc> &TypeLocRecursionGuard)
+    :  TLRG(TypeLocRecursionGuard)
+    {
+
+    }
+
+    ~RecursionPopper()
+    {
+    TLRG.pop_back();
+    }
+
+private:
+std::vector<clang::TypeLoc> &TLRG;
+};
 """
 
     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']:
@@ -70,6 +117,40 @@ def GenerateSrcLocMethod(self, ClassName, ClassData):
 
             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):
@@ -77,32 +158,78 @@ def GenerateFiles(self, OutputFile):
                   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);
+            RecursionPopper RAII(TypeLocRecursionGuard);
+                """
 
+        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 += '}'
 
@@ -111,14 +238,43 @@ def GenerateBaseGetLocationsFunction(self, ASTClassNames, CladeName):
 {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'
 
@@ -132,7 +288,13 @@ def GenerateDynNodeVisitor(self, CladeNames):
             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 {}; }'
 
@@ -200,6 +362,10 @@ def main():
     clang::CXXBaseSpecifier const*) {
   return {};
 }
+NodeLocationAccessors NodeIntrospection::GetLocations(
+    clang::TypeLoc const&) {
+  return {};
+}
 NodeLocationAccessors
 NodeIntrospection::GetLocations(clang::DynTypedNode const &) {
   return {};
@@ -209,19 +375,42 @@ def main():
     """)
         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())
 

diff  --git a/clang/unittests/Introspection/IntrospectionTest.cpp b/clang/unittests/Introspection/IntrospectionTest.cpp
index e56963aa41a66..57431668a19f4 100644
--- a/clang/unittests/Introspection/IntrospectionTest.cpp
+++ b/clang/unittests/Introspection/IntrospectionTest.cpp
@@ -26,25 +26,27 @@ using namespace clang::tooling;
 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) {
-                    return std::make_pair(LocationCallFormatterCpp::format(
-                                              *Accessor.second.get()),
-                                          Accessor.first);
+                  std::back_inserter(Result), [](const auto &Accessor) {
+                    return std::make_pair(
+                        LocationCallFormatterCpp::format(*Accessor.second),
+                        Accessor.first);
                   });
   return Result;
 }
 
 #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 '->'.
@@ -191,26 +193,85 @@ ns1::ns2::Foo<A, B> ns1::ns2::Bar<T, U>::Nested::method(int i, bool b) const
   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(
+      llvm::makeArrayRef(ExpectedLocations),
+      (ArrayRef<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().getAs<clang::FunctionTypeLoc>().getReturnLoc().getAs<clang::ElaboratedTypeLoc>().getNamedTypeLoc().getAs<clang::TemplateSpecializationTypeLoc>().getLAngleLoc()),
+STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getReturnLoc().getAs<clang::ElaboratedTypeLoc>().getNamedTypeLoc().getAs<clang::TemplateSpecializationTypeLoc>().getRAngleLoc()),
+STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getReturnLoc().getAs<clang::ElaboratedTypeLoc>().getNamedTypeLoc().getAs<clang::TemplateSpecializationTypeLoc>().getTemplateNameLoc()),
+STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getReturnLoc().getAs<clang::ElaboratedTypeLoc>().getNamedTypeLoc().getBeginLoc()),
+STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getReturnLoc().getAs<clang::ElaboratedTypeLoc>().getNamedTypeLoc().getEndLoc()),
+STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getReturnLoc().getBeginLoc()),
+STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getReturnLoc().getEndLoc()),
+STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getReturnLoc().getNextTypeLoc().getAs<clang::TemplateSpecializationTypeLoc>().getLAngleLoc()),
+STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getReturnLoc().getNextTypeLoc().getAs<clang::TemplateSpecializationTypeLoc>().getRAngleLoc()),
+STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getReturnLoc().getNextTypeLoc().getAs<clang::TemplateSpecializationTypeLoc>().getTemplateNameLoc()),
+STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getReturnLoc().getNextTypeLoc().getBeginLoc()),
+STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getReturnLoc().getNextTypeLoc().getEndLoc()),
+STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getBeginLoc()),
+STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getEndLoc()),
+STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getAs<clang::ElaboratedTypeLoc>().getNamedTypeLoc().getAs<clang::TemplateSpecializationTypeLoc>().getLAngleLoc()),
+STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getAs<clang::ElaboratedTypeLoc>().getNamedTypeLoc().getAs<clang::TemplateSpecializationTypeLoc>().getRAngleLoc()),
+STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getAs<clang::ElaboratedTypeLoc>().getNamedTypeLoc().getAs<clang::TemplateSpecializationTypeLoc>().getTemplateNameLoc()),
+STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getAs<clang::ElaboratedTypeLoc>().getNamedTypeLoc().getBeginLoc()),
+STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getAs<clang::ElaboratedTypeLoc>().getNamedTypeLoc().getEndLoc()),
+STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getBeginLoc()),
+STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getEndLoc()),
+STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getNextTypeLoc().getAs<clang::TemplateSpecializationTypeLoc>().getLAngleLoc()),
+STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getNextTypeLoc().getAs<clang::TemplateSpecializationTypeLoc>().getRAngleLoc()),
+STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getNextTypeLoc().getAs<clang::TemplateSpecializationTypeLoc>().getTemplateNameLoc()),
+STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getNextTypeLoc().getBeginLoc()),
+STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getNextTypeLoc().getEndLoc()),
+STRING_LOCATION_STDPAIR(MethodDecl, getTypeSpecEndLoc()),
+STRING_LOCATION_STDPAIR(MethodDecl, getTypeSpecStartLoc())
+  }));
+  // clang-format on
 
   auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors);
 
-  EXPECT_THAT(
-      ExpectedRanges,
-      UnorderedElementsAre(
-          STRING_LOCATION_PAIR(MethodDecl, getExceptionSpecSourceRange()),
-          STRING_LOCATION_PAIR(MethodDecl, getParametersSourceRange()),
-          STRING_LOCATION_PAIR(MethodDecl, getReturnTypeSourceRange()),
-          STRING_LOCATION_PAIR(MethodDecl, getSourceRange())));
+  llvm::sort(ExpectedRanges, [](const auto &LHS, const auto &RHS) {
+    return LHS.first < RHS.first;
+  });
+
+  // clang-format off
+  EXPECT_EQ(
+            llvm::makeArrayRef(ExpectedRanges),
+      (ArrayRef<std::pair<std::string, SourceRange>>{
+STRING_LOCATION_STDPAIR(MethodDecl, getExceptionSpecSourceRange()),
+STRING_LOCATION_STDPAIR(MethodDecl, getParametersSourceRange()),
+STRING_LOCATION_STDPAIR(MethodDecl, getReturnTypeSourceRange()),
+STRING_LOCATION_STDPAIR(MethodDecl, getSourceRange()),
+STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getExceptionSpecRange()),
+STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getParensRange()),
+STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getReturnLoc().getAs<clang::ElaboratedTypeLoc>().getNamedTypeLoc().getLocalSourceRange()),
+STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getReturnLoc().getAs<clang::ElaboratedTypeLoc>().getNamedTypeLoc().getSourceRange()),
+STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getReturnLoc().getLocalSourceRange()),
+STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getReturnLoc().getNextTypeLoc().getLocalSourceRange()),
+STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getReturnLoc().getNextTypeLoc().getSourceRange()),
+STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getAs<clang::FunctionTypeLoc>().getReturnLoc().getSourceRange()),
+STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getLocalSourceRange()),
+STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getAs<clang::ElaboratedTypeLoc>().getNamedTypeLoc().getLocalSourceRange()),
+STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getAs<clang::ElaboratedTypeLoc>().getNamedTypeLoc().getSourceRange()),
+STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getLocalSourceRange()),
+STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getNextTypeLoc().getLocalSourceRange()),
+STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getNextTypeLoc().getSourceRange()),
+STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getNextTypeLoc().getSourceRange()),
+STRING_LOCATION_STDPAIR(MethodDecl, getTypeSourceInfo()->getTypeLoc().getSourceRange())
+  }));
+  // clang-format on
 }
 
 TEST(Introspection, SourceLocations_NNS) {
@@ -244,17 +305,25 @@ void ns::A::foo() {}
 
   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().getBeginLoc()),
+          STRING_LOCATION_PAIR(NNS, getTypeLoc().getEndLoc())));
 
   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) {
@@ -288,13 +357,31 @@ void foo()
   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) {
@@ -546,13 +633,31 @@ void foo()
   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) {
@@ -585,16 +690,34 @@ struct B : A {
   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, getBaseClassLoc().getAs<clang::TypeSpecTypeLoc>().getNameLoc()),
+STRING_LOCATION_PAIR(CtorInit, getBaseClassLoc().getBeginLoc()),
+STRING_LOCATION_PAIR(CtorInit, getBaseClassLoc().getEndLoc()),
+STRING_LOCATION_PAIR(CtorInit, getLParenLoc()),
+STRING_LOCATION_PAIR(CtorInit, getRParenLoc()),
+STRING_LOCATION_PAIR(CtorInit, getSourceLocation()),
+STRING_LOCATION_PAIR(CtorInit, getTypeSourceInfo()->getTypeLoc().getAs<clang::TypeSpecTypeLoc>().getNameLoc()),
+STRING_LOCATION_PAIR(CtorInit, getTypeSourceInfo()->getTypeLoc().getBeginLoc()),
+STRING_LOCATION_PAIR(CtorInit, getTypeSourceInfo()->getTypeLoc().getEndLoc())
+ ));
+  // clang-format on
 
   auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors);
 
-  EXPECT_THAT(ExpectedRanges, UnorderedElementsAre(STRING_LOCATION_PAIR(
-                                  CtorInit, getSourceRange())));
+  // clang-format off
+  EXPECT_THAT(
+      ExpectedRanges,
+      UnorderedElementsAre(
+  STRING_LOCATION_PAIR(CtorInit, getBaseClassLoc().getLocalSourceRange()),
+  STRING_LOCATION_PAIR(CtorInit, getBaseClassLoc().getSourceRange()),
+  STRING_LOCATION_PAIR(CtorInit, getTypeSourceInfo()->getTypeLoc().getLocalSourceRange()),
+  STRING_LOCATION_PAIR(CtorInit, getTypeSourceInfo()->getTypeLoc().getSourceRange()),
+  STRING_LOCATION_PAIR(CtorInit, getSourceRange())));
+  // clang-format on
 }
 
 TEST(Introspection, SourceLocations_CXXCtorInitializer_member) {
@@ -666,16 +789,33 @@ struct C {
   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) {
@@ -711,18 +851,44 @@ struct D : Templ<T...> {
   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())));
+  llvm::sort(ExpectedLocations);
+
+  // clang-format off
+  EXPECT_EQ(
+     llvm::makeArrayRef(ExpectedLocations),
+      (ArrayRef<std::pair<std::string, SourceLocation>>{
+STRING_LOCATION_STDPAIR(CtorInit, getBaseClassLoc().getAs<clang::TemplateSpecializationTypeLoc>().getLAngleLoc()),
+STRING_LOCATION_STDPAIR(CtorInit, getBaseClassLoc().getAs<clang::TemplateSpecializationTypeLoc>().getRAngleLoc()),
+STRING_LOCATION_STDPAIR(CtorInit, getBaseClassLoc().getAs<clang::TemplateSpecializationTypeLoc>().getTemplateNameLoc()),
+STRING_LOCATION_STDPAIR(CtorInit, getBaseClassLoc().getBeginLoc()),
+STRING_LOCATION_STDPAIR(CtorInit, getBaseClassLoc().getEndLoc()),
+STRING_LOCATION_STDPAIR(CtorInit, getEllipsisLoc()),
+STRING_LOCATION_STDPAIR(CtorInit, getLParenLoc()),
+STRING_LOCATION_STDPAIR(CtorInit, getMemberLocation()),
+STRING_LOCATION_STDPAIR(CtorInit, getRParenLoc()),
+STRING_LOCATION_STDPAIR(CtorInit, getSourceLocation()),
+STRING_LOCATION_STDPAIR(CtorInit, getTypeSourceInfo()->getTypeLoc().getAs<clang::TemplateSpecializationTypeLoc>().getLAngleLoc()),
+STRING_LOCATION_STDPAIR(CtorInit, getTypeSourceInfo()->getTypeLoc().getAs<clang::TemplateSpecializationTypeLoc>().getRAngleLoc()),
+STRING_LOCATION_STDPAIR(CtorInit, getTypeSourceInfo()->getTypeLoc().getAs<clang::TemplateSpecializationTypeLoc>().getTemplateNameLoc()),
+STRING_LOCATION_STDPAIR(CtorInit, getTypeSourceInfo()->getTypeLoc().getBeginLoc()),
+STRING_LOCATION_STDPAIR(CtorInit, getTypeSourceInfo()->getTypeLoc().getEndLoc())
+  }));
+  // 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,
+                               getBaseClassLoc().getLocalSourceRange()),
+          STRING_LOCATION_PAIR(CtorInit, getBaseClassLoc().getSourceRange()),
+          STRING_LOCATION_PAIR(CtorInit, getSourceRange()),
+          STRING_LOCATION_PAIR(
+              CtorInit,
+              getTypeSourceInfo()->getTypeLoc().getLocalSourceRange()),
+          STRING_LOCATION_PAIR(
+              CtorInit, getTypeSourceInfo()->getTypeLoc().getSourceRange())));
 }
 
 TEST(Introspection, SourceLocations_CXXBaseSpecifier_plain) {
@@ -751,15 +917,27 @@ class B : A {};
   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) {
@@ -788,15 +966,27 @@ class B : public A {};
   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) {
@@ -826,15 +1016,27 @@ class C : virtual B, A {};
   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) {
@@ -864,15 +1066,29 @@ class B : A<int, bool> {};
   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) {
@@ -903,14 +1119,203 @@ struct Templ : T... {
   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);
+
+  llvm::sort(ExpectedLocations);
+
+  // clang-format off
+  EXPECT_EQ(
+      llvm::makeArrayRef(ExpectedLocations),
+          (ArrayRef<std::pair<std::string, SourceLocation>>{
+STRING_LOCATION_STDPAIR(TL, getAs<clang::FunctionTypeLoc>().getLParenLoc()),
+STRING_LOCATION_STDPAIR(TL, getAs<clang::FunctionTypeLoc>().getLocalRangeBegin()),
+STRING_LOCATION_STDPAIR(TL, getAs<clang::FunctionTypeLoc>().getLocalRangeEnd()),
+STRING_LOCATION_STDPAIR(TL, getAs<clang::FunctionTypeLoc>().getRParenLoc()),
+STRING_LOCATION_STDPAIR(TL, getAs<clang::FunctionTypeLoc>().getReturnLoc().getAs<clang::BuiltinTypeLoc>().getBuiltinLoc()),
+STRING_LOCATION_STDPAIR(TL, getAs<clang::FunctionTypeLoc>().getReturnLoc().getAs<clang::BuiltinTypeLoc>().getNameLoc()),
+STRING_LOCATION_STDPAIR(TL, getAs<clang::FunctionTypeLoc>().getReturnLoc().getBeginLoc()),
+STRING_LOCATION_STDPAIR(TL, getAs<clang::FunctionTypeLoc>().getReturnLoc().getEndLoc()),
+STRING_LOCATION_STDPAIR(TL, getBeginLoc()),
+STRING_LOCATION_STDPAIR(TL, getEndLoc()),
+STRING_LOCATION_STDPAIR(TL, getNextTypeLoc().getAs<clang::BuiltinTypeLoc>().getBuiltinLoc()),
+STRING_LOCATION_STDPAIR(TL, getNextTypeLoc().getAs<clang::BuiltinTypeLoc>().getNameLoc()),
+STRING_LOCATION_STDPAIR(TL, getNextTypeLoc().getBeginLoc()),
+STRING_LOCATION_STDPAIR(TL, getNextTypeLoc().getEndLoc())
+        }));
+  // clang-format on
+
+  auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors);
+
+  // clang-format off
+  EXPECT_THAT(
+      ExpectedRanges,
+      UnorderedElementsAre(
+STRING_LOCATION_PAIR(TL, getAs<clang::FunctionTypeLoc>().getParensRange()),
+STRING_LOCATION_PAIR(TL, getAs<clang::FunctionTypeLoc>().getReturnLoc().getLocalSourceRange()),
+STRING_LOCATION_PAIR(TL, getAs<clang::FunctionTypeLoc>().getReturnLoc().getSourceRange()),
+STRING_LOCATION_PAIR(TL, getLocalSourceRange()),
+STRING_LOCATION_PAIR(TL, getNextTypeLoc().getLocalSourceRange()),
+STRING_LOCATION_PAIR(TL, getNextTypeLoc().getSourceRange()),
+STRING_LOCATION_PAIR(TL, getSourceRange())
+          ));
+  // clang-format on
+}
+
+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);
+
+  llvm::sort(ExpectedLocations);
+
+  // clang-format off
+  EXPECT_EQ(
+      llvm::makeArrayRef(ExpectedLocations),
+      (ArrayRef<std::pair<std::string, SourceLocation>>{
+STRING_LOCATION_STDPAIR(TL, getAs<clang::PointerTypeLoc>().getPointeeLoc().getAs<clang::BuiltinTypeLoc>().getBuiltinLoc()),
+STRING_LOCATION_STDPAIR(TL, getAs<clang::PointerTypeLoc>().getPointeeLoc().getAs<clang::BuiltinTypeLoc>().getNameLoc()),
+STRING_LOCATION_STDPAIR(TL, getAs<clang::PointerTypeLoc>().getPointeeLoc().getBeginLoc()),
+STRING_LOCATION_STDPAIR(TL, getAs<clang::PointerTypeLoc>().getPointeeLoc().getEndLoc()),
+STRING_LOCATION_STDPAIR(TL, getAs<clang::PointerTypeLoc>().getSigilLoc()),
+STRING_LOCATION_STDPAIR(TL, getAs<clang::PointerTypeLoc>().getStarLoc()),
+STRING_LOCATION_STDPAIR(TL, getBeginLoc()),
+STRING_LOCATION_STDPAIR(TL, getEndLoc()),
+STRING_LOCATION_STDPAIR(TL, getNextTypeLoc().getAs<clang::BuiltinTypeLoc>().getBuiltinLoc()),
+STRING_LOCATION_STDPAIR(TL, getNextTypeLoc().getAs<clang::BuiltinTypeLoc>().getNameLoc()),
+STRING_LOCATION_STDPAIR(TL, getNextTypeLoc().getBeginLoc()),
+STRING_LOCATION_STDPAIR(TL, getNextTypeLoc().getEndLoc())
+}));
+  // clang-format on
+
+  auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors);
+
+  // clang-format off
+  EXPECT_THAT(
+      ExpectedRanges,
+      UnorderedElementsAre(
+STRING_LOCATION_PAIR(TL, getAs<clang::PointerTypeLoc>().getPointeeLoc().getLocalSourceRange()),
+STRING_LOCATION_PAIR(TL, getAs<clang::PointerTypeLoc>().getPointeeLoc().getSourceRange()),
+STRING_LOCATION_PAIR(TL, getLocalSourceRange()),
+STRING_LOCATION_PAIR(TL, getNextTypeLoc().getLocalSourceRange()),
+STRING_LOCATION_PAIR(TL, getNextTypeLoc().getSourceRange()),
+STRING_LOCATION_PAIR(TL, getSourceRange())
+          ));
+  // clang-format on
+}
+
+#ifndef _WIN32
+// This test doesn't work on windows due to use of the typeof extension.
+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())));
 }
+#endif


        


More information about the cfe-commits mailing list