diff --git a/clang/include/clang/Tooling/NodeIntrospection.h b/clang/include/clang/Tooling/NodeIntrospection.h --- a/clang/include/clang/Tooling/NodeIntrospection.h +++ b/clang/include/clang/Tooling/NodeIntrospection.h @@ -26,6 +26,7 @@ class NestedNameSpecifierLoc; class TemplateArgumentLoc; class CXXBaseSpecifier; +struct DeclarationNameInfo; namespace tooling { @@ -92,6 +93,7 @@ NodeLocationAccessors GetLocations(clang::TemplateArgumentLoc const &); NodeLocationAccessors GetLocations(clang::CXXBaseSpecifier const *); NodeLocationAccessors GetLocations(clang::TypeLoc const &); +NodeLocationAccessors GetLocations(clang::DeclarationNameInfo const &); NodeLocationAccessors GetLocations(clang::DynTypedNode const &Node); } // namespace NodeIntrospection } // namespace tooling diff --git a/clang/lib/Tooling/DumpTool/APIData.h b/clang/lib/Tooling/DumpTool/APIData.h --- a/clang/lib/Tooling/DumpTool/APIData.h +++ b/clang/lib/Tooling/DumpTool/APIData.h @@ -22,7 +22,7 @@ std::vector TypeSourceInfos; std::vector TypeLocs; std::vector NestedNameLocs; - // TODO: Extend this with locations available via typelocs etc. + std::vector DeclNameInfos; }; } // namespace tooling diff --git a/clang/lib/Tooling/DumpTool/ASTSrcLocProcessor.cpp b/clang/lib/Tooling/DumpTool/ASTSrcLocProcessor.cpp --- a/clang/lib/Tooling/DumpTool/ASTSrcLocProcessor.cpp +++ b/clang/lib/Tooling/DumpTool/ASTSrcLocProcessor.cpp @@ -23,19 +23,18 @@ Finder = std::make_unique(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", - "clang::TypeLoc")) - .bind("nodeClade")), - optionally(isDerivedFrom(cxxRecordDecl().bind("derivedFrom")))) - .bind("className"), + cxxRecordDecl( + isDefinition(), + isSameOrDerivedFrom( + namedDecl( + hasAnyName( + "clang::Stmt", "clang::Decl", "clang::CXXCtorInitializer", + "clang::NestedNameSpecifierLoc", + "clang::TemplateArgumentLoc", "clang::CXXBaseSpecifier", + "clang::DeclarationNameInfo", "clang::TypeLoc")) + .bind("nodeClade")), + optionally(isDerivedFrom(cxxRecordDecl().bind("derivedFrom")))) + .bind("className"), this); Finder->addMatcher( cxxRecordDecl(isDefinition(), hasAnyName("clang::PointerLikeTypeLoc", @@ -85,6 +84,8 @@ JsonObj["typeLocs"] = Obj.TypeLocs; if (!Obj.NestedNameLocs.empty()) JsonObj["nestedNameLocs"] = Obj.NestedNameLocs; + if (!Obj.DeclNameInfos.empty()) + JsonObj["declNameInfos"] = Obj.DeclNameInfos; return JsonObj; } @@ -222,6 +223,8 @@ CD.TypeLocs = CaptureMethods("class clang::TypeLoc", ASTClass, Result); CD.NestedNameLocs = CaptureMethods("class clang::NestedNameSpecifierLoc", ASTClass, Result); + CD.DeclNameInfos = + CaptureMethods("struct clang::DeclarationNameInfo", ASTClass, Result); if (const auto *DerivedFrom = Result.Nodes.getNodeAs("derivedFrom")) { diff --git a/clang/lib/Tooling/DumpTool/generate_cxx_src_locs.py b/clang/lib/Tooling/DumpTool/generate_cxx_src_locs.py --- a/clang/lib/Tooling/DumpTool/generate_cxx_src_locs.py +++ b/clang/lib/Tooling/DumpTool/generate_cxx_src_locs.py @@ -12,7 +12,10 @@ implementationContent = '' - RefClades = {"NestedNameSpecifierLoc", "TemplateArgumentLoc", "TypeLoc"} + RefClades = {"DeclarationNameInfo", + "NestedNameSpecifierLoc", + "TemplateArgumentLoc", + "TypeLoc"} def __init__(self, templateClasses): self.templateClasses = templateClasses @@ -121,7 +124,8 @@ self.implementationContent += '\n' if 'typeLocs' in ClassData or 'typeSourceInfos' in ClassData \ - or 'nestedNameLocs' in ClassData: + or 'nestedNameLocs' in ClassData \ + or 'declNameInfos' in ClassData: if CreateLocalRecursionGuard: self.implementationContent += \ 'std::vector TypeLocRecursionGuard;\n' @@ -165,6 +169,15 @@ Object.{0}(), Locs, Rngs, TypeLocRecursionGuard); """.format(NN) + if 'declNameInfos' in ClassData: + for declName in ClassData['declNameInfos']: + + self.implementationContent += \ + """ + GetLocationsImpl( + llvm::makeIntrusiveRefCnt(Prefix, "{0}"), + Object.{0}(), Locs, Rngs, TypeLocRecursionGuard); + """.format(declName) self.implementationContent += '}\n' @@ -300,6 +313,8 @@ + ' NodeIntrospection::' + Signature + '{' for CladeName in CladeNames: + if CladeName == "DeclarationNameInfo": + continue self.implementationContent += \ """ if (const auto *N = Node.get<{0}>()) @@ -376,10 +391,7 @@ cladeName = getCladeName(ClassName) g.GenerateSrcLocMethod( ClassName, ClassAccessors, - cladeName not in [ - 'NestedNameSpecifierLoc', - 'TemplateArgumentLoc', - 'TypeLoc']) + cladeName not in Generator.RefClades) for (CladeName, ClassNameData) in jsonData['classesInClade'].items(): g.GenerateBaseGetLocationsFunction( @@ -387,10 +399,7 @@ jsonData['classEntries'], CladeName, jsonData["classInheritance"], - CladeName not in [ - 'NestedNameSpecifierLoc', - 'TemplateArgumentLoc', - 'TypeLoc']) + CladeName not in Generator.RefClades) g.GenerateDynNodeVisitor(jsonData['classesInClade'].keys()) diff --git a/clang/lib/Tooling/EmptyNodeIntrospection.inc.in b/clang/lib/Tooling/EmptyNodeIntrospection.inc.in --- a/clang/lib/Tooling/EmptyNodeIntrospection.inc.in +++ b/clang/lib/Tooling/EmptyNodeIntrospection.inc.in @@ -36,6 +36,10 @@ clang::TypeLoc const&) { return {}; } +NodeLocationAccessors NodeIntrospection::GetLocations( + clang::DeclarationNameInfo const&) { + return {}; +} NodeLocationAccessors NodeIntrospection::GetLocations(clang::DynTypedNode const &) { return {}; diff --git a/clang/unittests/Introspection/IntrospectionTest.cpp b/clang/unittests/Introspection/IntrospectionTest.cpp --- a/clang/unittests/Introspection/IntrospectionTest.cpp +++ b/clang/unittests/Introspection/IntrospectionTest.cpp @@ -216,6 +216,9 @@ STRING_LOCATION_STDPAIR(MethodDecl, getEndLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getInnerLocStart()), STRING_LOCATION_STDPAIR(MethodDecl, getLocation()), +STRING_LOCATION_STDPAIR(MethodDecl, getNameInfo().getBeginLoc()), +STRING_LOCATION_STDPAIR(MethodDecl, getNameInfo().getEndLoc()), +STRING_LOCATION_STDPAIR(MethodDecl, getNameInfo().getLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getOuterLocStart()), STRING_LOCATION_STDPAIR(MethodDecl, getQualifierLoc().getBeginLoc()), STRING_LOCATION_STDPAIR(MethodDecl, getQualifierLoc().getEndLoc()), @@ -305,6 +308,7 @@ llvm::makeArrayRef(ExpectedRanges), (ArrayRef>{ STRING_LOCATION_STDPAIR(MethodDecl, getExceptionSpecSourceRange()), +STRING_LOCATION_STDPAIR(MethodDecl, getNameInfo().getSourceRange()), STRING_LOCATION_STDPAIR(MethodDecl, getParametersSourceRange()), STRING_LOCATION_STDPAIR(MethodDecl, getQualifierLoc().getLocalSourceRange()), STRING_LOCATION_STDPAIR(MethodDecl, getQualifierLoc().getPrefix().getLocalSourceRange()), @@ -1395,3 +1399,142 @@ TL, getAs().getParensRange()))); } #endif + +TEST(Introspection, SourceLocations_DeclarationNameInfo_Dtor) { + if (!NodeIntrospection::hasIntrospectionSupport()) + return; + auto AST = + buildASTFromCode(R"cpp( +class Foo +{ + ~Foo() {} +}; +)cpp", + "foo.cpp", std::make_shared()); + auto &Ctx = AST->getASTContext(); + auto &TU = *Ctx.getTranslationUnitDecl(); + + auto BoundNodes = ast_matchers::match( + decl(hasDescendant(cxxDestructorDecl(hasName("~Foo")).bind("dtor"))), TU, + Ctx); + + EXPECT_EQ(BoundNodes.size(), 1u); + + const auto *Dtor = BoundNodes[0].getNodeAs("dtor"); + auto NI = Dtor->getNameInfo(); + auto Result = NodeIntrospection::GetLocations(NI); + + auto ExpectedLocations = + FormatExpected(Result.LocationAccessors); + + llvm::sort(ExpectedLocations); + + // clang-format off + EXPECT_EQ( + llvm::makeArrayRef(ExpectedLocations), + (ArrayRef>{ + STRING_LOCATION_STDPAIR((&NI), getBeginLoc()), + STRING_LOCATION_STDPAIR((&NI), getEndLoc()), + STRING_LOCATION_STDPAIR((&NI), getLoc()), + STRING_LOCATION_STDPAIR((&NI), +getNamedTypeInfo()->getTypeLoc().getAs().getNameLoc()), + STRING_LOCATION_STDPAIR( + (&NI), getNamedTypeInfo()->getTypeLoc().getBeginLoc()), + STRING_LOCATION_STDPAIR( + (&NI), getNamedTypeInfo()->getTypeLoc().getEndLoc())})); + // clang-format on + + auto ExpectedRanges = FormatExpected(Result.RangeAccessors); + + EXPECT_THAT( + ExpectedRanges, + UnorderedElementsAre( + STRING_LOCATION_PAIR( + (&NI), getNamedTypeInfo()->getTypeLoc().getLocalSourceRange()), + STRING_LOCATION_PAIR( + (&NI), getNamedTypeInfo()->getTypeLoc().getSourceRange()), + STRING_LOCATION_PAIR((&NI), getSourceRange()))); +} + +TEST(Introspection, SourceLocations_DeclarationNameInfo_ConvOp) { + if (!NodeIntrospection::hasIntrospectionSupport()) + return; + auto AST = + buildASTFromCode(R"cpp( +class Foo +{ + bool operator==(const Foo&) const { return false; } +}; +)cpp", + "foo.cpp", std::make_shared()); + auto &Ctx = AST->getASTContext(); + auto &TU = *Ctx.getTranslationUnitDecl(); + + auto BoundNodes = ast_matchers::match( + decl(hasDescendant(cxxMethodDecl().bind("opeq"))), TU, Ctx); + + EXPECT_EQ(BoundNodes.size(), 1u); + + const auto *Opeq = BoundNodes[0].getNodeAs("opeq"); + auto NI = Opeq->getNameInfo(); + auto Result = NodeIntrospection::GetLocations(NI); + + auto ExpectedLocations = + FormatExpected(Result.LocationAccessors); + + llvm::sort(ExpectedLocations); + + EXPECT_EQ(llvm::makeArrayRef(ExpectedLocations), + (ArrayRef>{ + STRING_LOCATION_STDPAIR((&NI), getBeginLoc()), + STRING_LOCATION_STDPAIR((&NI), getEndLoc()), + STRING_LOCATION_STDPAIR((&NI), getLoc())})); + + auto ExpectedRanges = FormatExpected(Result.RangeAccessors); + + EXPECT_THAT(ExpectedRanges, + UnorderedElementsAre( + STRING_LOCATION_PAIR((&NI), getSourceRange()), + STRING_LOCATION_PAIR((&NI), getCXXOperatorNameRange()))); +} + +TEST(Introspection, SourceLocations_DeclarationNameInfo_LitOp) { + if (!NodeIntrospection::hasIntrospectionSupport()) + return; + auto AST = + buildASTFromCode(R"cpp( +long double operator"" _identity ( long double val ) +{ + return val; +} +)cpp", + "foo.cpp", std::make_shared()); + auto &Ctx = AST->getASTContext(); + auto &TU = *Ctx.getTranslationUnitDecl(); + + auto BoundNodes = ast_matchers::match( + decl(hasDescendant(functionDecl().bind("litop"))), TU, Ctx); + + EXPECT_EQ(BoundNodes.size(), 1u); + + const auto *LitOp = BoundNodes[0].getNodeAs("litop"); + auto NI = LitOp->getNameInfo(); + auto Result = NodeIntrospection::GetLocations(NI); + + auto ExpectedLocations = + FormatExpected(Result.LocationAccessors); + + llvm::sort(ExpectedLocations); + + EXPECT_EQ(llvm::makeArrayRef(ExpectedLocations), + (ArrayRef>{ + STRING_LOCATION_STDPAIR((&NI), getBeginLoc()), + STRING_LOCATION_STDPAIR((&NI), getCXXLiteralOperatorNameLoc()), + STRING_LOCATION_STDPAIR((&NI), getEndLoc()), + STRING_LOCATION_STDPAIR((&NI), getLoc())})); + + auto ExpectedRanges = FormatExpected(Result.RangeAccessors); + + EXPECT_THAT(ExpectedRanges, UnorderedElementsAre(STRING_LOCATION_PAIR( + (&NI), getSourceRange()))); +}