[AST] Add DeclarationNameInfo to node introspection

Differential Revision: https://reviews.llvm.org/D101049
This commit is contained in:
Stephen Kelly 2021-04-20 22:46:08 +01:00
parent 2149aa73f6
commit a9676febb9
6 changed files with 185 additions and 24 deletions

View File

@ -26,6 +26,7 @@ class CXXCtorInitializer;
class NestedNameSpecifierLoc;
class TemplateArgumentLoc;
class CXXBaseSpecifier;
struct DeclarationNameInfo;
namespace tooling {
@ -92,6 +93,7 @@ NodeLocationAccessors GetLocations(clang::NestedNameSpecifierLoc const &);
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

View File

@ -22,7 +22,7 @@ struct ClassData {
std::vector<std::string> TypeSourceInfos;
std::vector<std::string> TypeLocs;
std::vector<std::string> NestedNameLocs;
// TODO: Extend this with locations available via typelocs etc.
std::vector<std::string> DeclNameInfos;
};
} // namespace tooling

View File

@ -23,19 +23,18 @@ 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",
"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 @@ llvm::json::Object toJSON(ClassData const &Obj) {
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 @@ void ASTSrcLocProcessor::run(const MatchFinder::MatchResult &Result) {
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<clang::CXXRecordDecl>("derivedFrom")) {

View File

@ -12,7 +12,10 @@ class Generator(object):
implementationContent = ''
RefClades = {"NestedNameSpecifierLoc", "TemplateArgumentLoc", "TypeLoc"}
RefClades = {"DeclarationNameInfo",
"NestedNameSpecifierLoc",
"TemplateArgumentLoc",
"TypeLoc"}
def __init__(self, templateClasses):
self.templateClasses = templateClasses
@ -121,7 +124,8 @@ static void GetLocations{0}(SharedLocationCall const& Prefix,
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<clang::TypeLoc> TypeLocRecursionGuard;\n'
@ -165,6 +169,15 @@ static void GetLocations{0}(SharedLocationCall const& Prefix,
Object.{0}(), Locs, Rngs, TypeLocRecursionGuard);
""".format(NN)
if 'declNameInfos' in ClassData:
for declName in ClassData['declNameInfos']:
self.implementationContent += \
"""
GetLocationsImpl(
llvm::makeIntrusiveRefCnt<LocationCall>(Prefix, "{0}"),
Object.{0}(), Locs, Rngs, TypeLocRecursionGuard);
""".format(declName)
self.implementationContent += '}\n'
@ -300,6 +313,8 @@ if (auto Derived = llvm::dyn_cast<clang::{0}>(Object)) {{
+ ' NodeIntrospection::' + Signature + '{'
for CladeName in CladeNames:
if CladeName == "DeclarationNameInfo":
continue
self.implementationContent += \
"""
if (const auto *N = Node.get<{0}>())
@ -376,10 +391,7 @@ def main():
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 @@ def main():
jsonData['classEntries'],
CladeName,
jsonData["classInheritance"],
CladeName not in [
'NestedNameSpecifierLoc',
'TemplateArgumentLoc',
'TypeLoc'])
CladeName not in Generator.RefClades)
g.GenerateDynNodeVisitor(jsonData['classesInClade'].keys())

View File

@ -36,6 +36,10 @@ NodeLocationAccessors NodeIntrospection::GetLocations(
clang::TypeLoc const&) {
return {};
}
NodeLocationAccessors NodeIntrospection::GetLocations(
clang::DeclarationNameInfo const&) {
return {};
}
NodeLocationAccessors
NodeIntrospection::GetLocations(clang::DynTypedNode const &) {
return {};

View File

@ -216,6 +216,9 @@ STRING_LOCATION_STDPAIR(MethodDecl, getBodyRBrace()),
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 @@ STRING_LOCATION_STDPAIR(MethodDecl, getTypeSpecStartLoc())
llvm::makeArrayRef(ExpectedRanges),
(ArrayRef<std::pair<std::string, SourceRange>>{
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 @@ typeof (static_cast<void *>(0)) i;
TL, getAs<clang::TypeOfExprTypeLoc>().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<PCHContainerOperations>());
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<CXXDestructorDecl>("dtor");
auto NI = Dtor->getNameInfo();
auto Result = NodeIntrospection::GetLocations(NI);
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((&NI), getBeginLoc()),
STRING_LOCATION_STDPAIR((&NI), getEndLoc()),
STRING_LOCATION_STDPAIR((&NI), getLoc()),
STRING_LOCATION_STDPAIR((&NI),
getNamedTypeInfo()->getTypeLoc().getAs<clang::TypeSpecTypeLoc>().getNameLoc()),
STRING_LOCATION_STDPAIR(
(&NI), getNamedTypeInfo()->getTypeLoc().getBeginLoc()),
STRING_LOCATION_STDPAIR(
(&NI), getNamedTypeInfo()->getTypeLoc().getEndLoc())}));
// clang-format on
auto ExpectedRanges = FormatExpected<SourceRange>(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<PCHContainerOperations>());
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<CXXMethodDecl>("opeq");
auto NI = Opeq->getNameInfo();
auto Result = NodeIntrospection::GetLocations(NI);
auto ExpectedLocations =
FormatExpected<SourceLocation>(Result.LocationAccessors);
llvm::sort(ExpectedLocations);
EXPECT_EQ(llvm::makeArrayRef(ExpectedLocations),
(ArrayRef<std::pair<std::string, SourceLocation>>{
STRING_LOCATION_STDPAIR((&NI), getBeginLoc()),
STRING_LOCATION_STDPAIR((&NI), getEndLoc()),
STRING_LOCATION_STDPAIR((&NI), getLoc())}));
auto ExpectedRanges = FormatExpected<SourceRange>(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<PCHContainerOperations>());
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<FunctionDecl>("litop");
auto NI = LitOp->getNameInfo();
auto Result = NodeIntrospection::GetLocations(NI);
auto ExpectedLocations =
FormatExpected<SourceLocation>(Result.LocationAccessors);
llvm::sort(ExpectedLocations);
EXPECT_EQ(llvm::makeArrayRef(ExpectedLocations),
(ArrayRef<std::pair<std::string, SourceLocation>>{
STRING_LOCATION_STDPAIR((&NI), getBeginLoc()),
STRING_LOCATION_STDPAIR((&NI), getCXXLiteralOperatorNameLoc()),
STRING_LOCATION_STDPAIR((&NI), getEndLoc()),
STRING_LOCATION_STDPAIR((&NI), getLoc())}));
auto ExpectedRanges = FormatExpected<SourceRange>(Result.RangeAccessors);
EXPECT_THAT(ExpectedRanges, UnorderedElementsAre(STRING_LOCATION_PAIR(
(&NI), getSourceRange())));
}