Skip to content

Commit

Permalink
[AST] Add DeclarationNameInfo to node introspection
Browse files Browse the repository at this point in the history
Differential Revision: https://reviews.llvm.org/D101049
  • Loading branch information
steveire committed Apr 25, 2021
1 parent 2149aa7 commit a9676fe
Show file tree
Hide file tree
Showing 6 changed files with 185 additions and 24 deletions.
2 changes: 2 additions & 0 deletions clang/include/clang/Tooling/NodeIntrospection.h
Expand Up @@ -26,6 +26,7 @@ class CXXCtorInitializer;
class NestedNameSpecifierLoc;
class TemplateArgumentLoc;
class CXXBaseSpecifier;
struct DeclarationNameInfo;

namespace tooling {

Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Tooling/DumpTool/APIData.h
Expand Up @@ -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
Expand Down
29 changes: 16 additions & 13 deletions clang/lib/Tooling/DumpTool/ASTSrcLocProcessor.cpp
Expand Up @@ -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",
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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")) {
Expand Down
29 changes: 19 additions & 10 deletions clang/lib/Tooling/DumpTool/generate_cxx_src_locs.py
Expand Up @@ -12,7 +12,10 @@ class Generator(object):

implementationContent = ''

RefClades = {"NestedNameSpecifierLoc", "TemplateArgumentLoc", "TypeLoc"}
RefClades = {"DeclarationNameInfo",
"NestedNameSpecifierLoc",
"TemplateArgumentLoc",
"TypeLoc"}

def __init__(self, templateClasses):
self.templateClasses = templateClasses
Expand Down Expand Up @@ -121,7 +124,8 @@ def GenerateSrcLocMethod(self,
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'
Expand Down Expand Up @@ -165,6 +169,15 @@ def GenerateSrcLocMethod(self,
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'

Expand Down Expand Up @@ -300,6 +313,8 @@ def GenerateDynNodeVisitor(self, CladeNames):
+ ' NodeIntrospection::' + Signature + '{'

for CladeName in CladeNames:
if CladeName == "DeclarationNameInfo":
continue
self.implementationContent += \
"""
if (const auto *N = Node.get<{0}>())
Expand Down Expand Up @@ -376,21 +391,15 @@ def getCladeName(ClassName):
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(
ClassNameData,
jsonData['classEntries'],
CladeName,
jsonData["classInheritance"],
CladeName not in [
'NestedNameSpecifierLoc',
'TemplateArgumentLoc',
'TypeLoc'])
CladeName not in Generator.RefClades)

g.GenerateDynNodeVisitor(jsonData['classesInClade'].keys())

Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Tooling/EmptyNodeIntrospection.inc.in
Expand Up @@ -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 {};
Expand Down
143 changes: 143 additions & 0 deletions clang/unittests/Introspection/IntrospectionTest.cpp
Expand Up @@ -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()),
Expand Down Expand Up @@ -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()),
Expand Down Expand Up @@ -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())));
}

0 comments on commit a9676fe

Please sign in to comment.