[clang] Allow DynTypedNode to store a TemplateArgumentLoc

The patch also adds a templateArgumentLoc() AST matcher.

Differential Revision: https://reviews.llvm.org/D85621
This commit is contained in:
Nathan Ridge 2020-08-09 20:37:18 -04:00
parent 1970eefb17
commit b1c7f84643
9 changed files with 111 additions and 25 deletions

View File

@ -679,7 +679,8 @@ Given
#pragma omp parallel default(firstprivate)
#pragma omp parallel
``ompDefaultClause()`` matches ``default(none)``, ``default(shared)``, and ``default(firstprivate)``.
``ompDefaultClause()`` matches ``default(none)``, ``default(shared)``, and
``default(firstprivate)``
</pre></td></tr>
@ -1625,6 +1626,17 @@ whileStmt()
</pre></td></tr>
<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1TemplateArgumentLoc.html">TemplateArgumentLoc</a>&gt;</td><td class="name" onclick="toggle('templateArgumentLoc0')"><a name="templateArgumentLoc0Anchor">templateArgumentLoc</a></td><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1TemplateArgumentLoc.html">TemplateArgumentLoc</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="templateArgumentLoc0"><pre>Matches template arguments (with location info).
Given
template &lt;typename T&gt; struct C {};
C&lt;int&gt; c;
templateArgumentLoc()
matches 'int' in C&lt;int&gt;.
</pre></td></tr>
<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>&gt;</td><td class="name" onclick="toggle('templateArgument0')"><a name="templateArgument0Anchor">templateArgument</a></td><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="templateArgument0"><pre>Matches template arguments.
@ -3776,6 +3788,22 @@ namespaceDecl(isInline()) will match n::m.
</pre></td></tr>
<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1OMPDefaultClause.html">OMPDefaultClause</a>&gt;</td><td class="name" onclick="toggle('isFirstPrivateKind0')"><a name="isFirstPrivateKind0Anchor">isFirstPrivateKind</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isFirstPrivateKind0"><pre>Matches if the OpenMP ``default`` clause has ``firstprivate`` kind
specified.
Given
#pragma omp parallel
#pragma omp parallel default(none)
#pragma omp parallel default(shared)
#pragma omp parallel default(firstprivate)
``ompDefaultClause(isFirstPrivateKind())`` matches only
``default(firstprivate)``.
</pre></td></tr>
<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1OMPDefaultClause.html">OMPDefaultClause</a>&gt;</td><td class="name" onclick="toggle('isNoneKind0')"><a name="isNoneKind0Anchor">isNoneKind</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isNoneKind0"><pre>Matches if the OpenMP ``default`` clause has ``none`` kind specified.
@ -3804,20 +3832,6 @@ Given
</pre></td></tr>
<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1OMPDefaultClause.html">OMPDefaultClause</a>&gt;</td><td class="name" onclick="toggle('isFirstPrivateKind0')"><a name="isFirstPrivateKind0Anchor">isSharedKind</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isFirstPrivateKind0"><pre>Matches if the OpenMP ``default`` clause has ``firstprivate`` kind specified.
Given
#pragma omp parallel
#pragma omp parallel default(none)
#pragma omp parallel default(shared)
#pragma omp parallel default(firstprivate)
``ompDefaultClause(isFirstPrivateKind())`` matches only ``default(firstprivate)``.
</pre></td></tr>
<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1OMPExecutableDirective.html">OMPExecutableDirective</a>&gt;</td><td class="name" onclick="toggle('isAllowedToContainClauseKind0')"><a name="isAllowedToContainClauseKind0Anchor">isAllowedToContainClauseKind</a></td><td>OpenMPClauseKind CKind</td></tr>
<tr><td colspan="4" class="doc" id="isAllowedToContainClauseKind0"><pre>Matches if the OpenMP directive is allowed to contain the specified OpenMP
clause kind.

View File

@ -132,6 +132,7 @@ private:
enum NodeKindId {
NKI_None,
NKI_TemplateArgument,
NKI_TemplateArgumentLoc,
NKI_TemplateName,
NKI_NestedNameSpecifierLoc,
NKI_QualType,
@ -191,6 +192,7 @@ private:
};
KIND_TO_KIND_ID(CXXCtorInitializer)
KIND_TO_KIND_ID(TemplateArgument)
KIND_TO_KIND_ID(TemplateArgumentLoc)
KIND_TO_KIND_ID(TemplateName)
KIND_TO_KIND_ID(NestedNameSpecifier)
KIND_TO_KIND_ID(NestedNameSpecifierLoc)
@ -456,12 +458,13 @@ private:
/// Note that we can store \c Decls, \c Stmts, \c Types,
/// \c NestedNameSpecifiers and \c CXXCtorInitializer by pointer as they are
/// guaranteed to be unique pointers pointing to dedicated storage in the AST.
/// \c QualTypes, \c NestedNameSpecifierLocs, \c TypeLocs and
/// \c TemplateArguments on the other hand do not have storage or unique
/// pointers and thus need to be stored by value.
/// \c QualTypes, \c NestedNameSpecifierLocs, \c TypeLocs,
/// \c TemplateArguments and \c TemplateArgumentLocs on the other hand do not
/// have storage or unique pointers and thus need to be stored by value.
llvm::AlignedCharArrayUnion<const void *, TemplateArgument,
NestedNameSpecifierLoc, QualType,
TypeLoc> Storage;
TemplateArgumentLoc, NestedNameSpecifierLoc,
QualType, TypeLoc>
Storage;
};
template <typename T>
@ -496,6 +499,10 @@ template <>
struct DynTypedNode::BaseConverter<
TemplateArgument, void> : public ValueConverter<TemplateArgument> {};
template <>
struct DynTypedNode::BaseConverter<TemplateArgumentLoc, void>
: public ValueConverter<TemplateArgumentLoc> {};
template <>
struct DynTypedNode::BaseConverter<
TemplateName, void> : public ValueConverter<TemplateName> {};

View File

@ -159,6 +159,8 @@ public:
MatchCallback *Action);
void addMatcher(const CXXCtorInitializerMatcher &NodeMatch,
MatchCallback *Action);
void addMatcher(const TemplateArgumentLocMatcher &NodeMatch,
MatchCallback *Action);
/// @}
/// Adds a matcher to execute when running over the AST.
@ -209,6 +211,8 @@ public:
NestedNameSpecifierLoc;
std::vector<std::pair<TypeLocMatcher, MatchCallback *>> TypeLoc;
std::vector<std::pair<CXXCtorInitializerMatcher, MatchCallback *>> CtorInit;
std::vector<std::pair<TemplateArgumentLocMatcher, MatchCallback *>>
TemplateArgumentLoc;
/// All the callbacks in one container to simplify iteration.
llvm::SmallPtrSet<MatchCallback *, 16> AllCallbacks;
};

View File

@ -145,6 +145,7 @@ using TypeLocMatcher = internal::Matcher<TypeLoc>;
using NestedNameSpecifierMatcher = internal::Matcher<NestedNameSpecifier>;
using NestedNameSpecifierLocMatcher = internal::Matcher<NestedNameSpecifierLoc>;
using CXXCtorInitializerMatcher = internal::Matcher<CXXCtorInitializer>;
using TemplateArgumentLocMatcher = internal::Matcher<TemplateArgumentLoc>;
/// @}
/// Matches any node.
@ -515,6 +516,18 @@ extern const internal::VariadicAllOfMatcher<CXXCtorInitializer>
/// matches 'int' in C<int>.
extern const internal::VariadicAllOfMatcher<TemplateArgument> templateArgument;
/// Matches template arguments (with location info).
///
/// Given
/// \code
/// template <typename T> struct C {};
/// C<int> c;
/// \endcode
/// templateArgumentLoc()
/// matches 'int' in C<int>.
extern const internal::VariadicAllOfMatcher<TemplateArgumentLoc>
templateArgumentLoc;
/// Matches template name.
///
/// Given

View File

@ -938,14 +938,13 @@ private:
template <typename T>
struct IsBaseType {
static const bool value =
std::is_same<T, Decl>::value ||
std::is_same<T, Stmt>::value ||
std::is_same<T, QualType>::value ||
std::is_same<T, Type>::value ||
std::is_same<T, Decl>::value || std::is_same<T, Stmt>::value ||
std::is_same<T, QualType>::value || std::is_same<T, Type>::value ||
std::is_same<T, TypeLoc>::value ||
std::is_same<T, NestedNameSpecifier>::value ||
std::is_same<T, NestedNameSpecifierLoc>::value ||
std::is_same<T, CXXCtorInitializer>::value;
std::is_same<T, CXXCtorInitializer>::value ||
std::is_same<T, TemplateArgumentLoc>::value;
};
template <typename T>
const bool IsBaseType<T>::value;

View File

@ -23,6 +23,7 @@ using namespace clang;
const ASTNodeKind::KindInfo ASTNodeKind::AllKindInfo[] = {
{ NKI_None, "<None>" },
{ NKI_None, "TemplateArgument" },
{ NKI_None, "TemplateArgumentLoc" },
{ NKI_None, "TemplateName" },
{ NKI_None, "NestedNameSpecifierLoc" },
{ NKI_None, "QualType" },
@ -129,6 +130,8 @@ void DynTypedNode::print(llvm::raw_ostream &OS,
const PrintingPolicy &PP) const {
if (const TemplateArgument *TA = get<TemplateArgument>())
TA->print(PP, OS);
else if (const TemplateArgumentLoc *TAL = get<TemplateArgumentLoc>())
TAL->getArgument().print(PP, OS);
else if (const TemplateName *TN = get<TemplateName>())
TN->print(OS, PP);
else if (const NestedNameSpecifier *NNS = get<NestedNameSpecifier>())
@ -175,6 +178,8 @@ SourceRange DynTypedNode::getSourceRange() const {
return D->getSourceRange();
if (const Stmt *S = get<Stmt>())
return S->getSourceRange();
if (const TemplateArgumentLoc *TAL = get<TemplateArgumentLoc>())
return TAL->getSourceRange();
if (const auto *C = get<OMPClause>())
return SourceRange(C->getBeginLoc(), C->getEndLoc());
return SourceRange();

View File

@ -128,6 +128,9 @@ public:
traverse(*T);
else if (const auto *C = DynNode.get<CXXCtorInitializer>())
traverse(*C);
else if (const TemplateArgumentLoc *TALoc =
DynNode.get<TemplateArgumentLoc>())
traverse(*TALoc);
// FIXME: Add other base types after adding tests.
// It's OK to always overwrite the bound nodes, as if there was
@ -224,6 +227,10 @@ public:
ScopedIncrement ScopedDepth(&CurrentDepth);
return traverse(*CtorInit);
}
bool TraverseTemplateArgumentLoc(TemplateArgumentLoc TAL) {
ScopedIncrement ScopedDepth(&CurrentDepth);
return traverse(TAL);
}
bool TraverseLambdaExpr(LambdaExpr *Node) {
if (Finder->getASTContext().getParentMapContext().getTraversalKind() !=
TK_IgnoreUnlessSpelledInSource)
@ -304,6 +311,9 @@ private:
return VisitorBase::TraverseConstructorInitializer(
const_cast<CXXCtorInitializer *>(&CtorInit));
}
bool baseTraverse(TemplateArgumentLoc TAL) {
return VisitorBase::TraverseTemplateArgumentLoc(TAL);
}
// Sets 'Matched' to true if 'Matcher' matches 'Node' and:
// 0 < CurrentDepth <= MaxDepth.
@ -447,6 +457,7 @@ public:
bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS);
bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS);
bool TraverseConstructorInitializer(CXXCtorInitializer *CtorInit);
bool TraverseTemplateArgumentLoc(TemplateArgumentLoc TAL);
// Matches children or descendants of 'Node' with 'BaseMatcher'.
bool memoizedMatchesRecursively(const DynTypedNode &Node, ASTContext &Ctx,
@ -557,6 +568,8 @@ public:
match(*N);
} else if (auto *N = Node.get<CXXCtorInitializer>()) {
match(*N);
} else if (auto *N = Node.get<TemplateArgumentLoc>()) {
match(*N);
}
}
@ -680,6 +693,9 @@ private:
void matchDispatch(const CXXCtorInitializer *Node) {
matchWithoutFilter(*Node, Matchers->CtorInit);
}
void matchDispatch(const TemplateArgumentLoc *Node) {
matchWithoutFilter(*Node, Matchers->TemplateArgumentLoc);
}
void matchDispatch(const void *) { /* Do nothing. */ }
/// @}
@ -1035,6 +1051,11 @@ bool MatchASTVisitor::TraverseConstructorInitializer(
CtorInit);
}
bool MatchASTVisitor::TraverseTemplateArgumentLoc(TemplateArgumentLoc Loc) {
match(Loc);
return RecursiveASTVisitor<MatchASTVisitor>::TraverseTemplateArgumentLoc(Loc);
}
class MatchASTConsumer : public ASTConsumer {
public:
MatchASTConsumer(MatchFinder *Finder,
@ -1111,6 +1132,12 @@ void MatchFinder::addMatcher(const CXXCtorInitializerMatcher &NodeMatch,
Matchers.AllCallbacks.insert(Action);
}
void MatchFinder::addMatcher(const TemplateArgumentLocMatcher &NodeMatch,
MatchCallback *Action) {
Matchers.TemplateArgumentLoc.emplace_back(NodeMatch, Action);
Matchers.AllCallbacks.insert(Action);
}
bool MatchFinder::addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch,
MatchCallback *Action) {
if (NodeMatch.canConvertTo<Decl>()) {
@ -1134,6 +1161,9 @@ bool MatchFinder::addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch,
} else if (NodeMatch.canConvertTo<CXXCtorInitializer>()) {
addMatcher(NodeMatch.convertTo<CXXCtorInitializer>(), Action);
return true;
} else if (NodeMatch.canConvertTo<TemplateArgumentLoc>()) {
addMatcher(NodeMatch.convertTo<TemplateArgumentLoc>(), Action);
return true;
}
return false;
}

View File

@ -734,6 +734,7 @@ const internal::VariadicDynCastAllOfMatcher<Decl, AccessSpecDecl>
accessSpecDecl;
const internal::VariadicAllOfMatcher<CXXCtorInitializer> cxxCtorInitializer;
const internal::VariadicAllOfMatcher<TemplateArgument> templateArgument;
const internal::VariadicAllOfMatcher<TemplateArgumentLoc> templateArgumentLoc;
const internal::VariadicAllOfMatcher<TemplateName> templateName;
const internal::VariadicDynCastAllOfMatcher<Decl, NonTypeTemplateParmDecl>
nonTypeTemplateParmDecl;

View File

@ -2637,6 +2637,19 @@ TEST(Has, DoesNotDeleteBindings) {
std::make_unique<VerifyIdIsBoundTo<Decl>>("x", 1)));
}
TEST(TemplateArgumentLoc, Matches) {
EXPECT_TRUE(matchAndVerifyResultTrue(
R"cpp(
template <typename A, int B, template <typename> class C> class X {};
class A {};
const int B = 42;
template <typename> class C {};
X<A, B, C> x;
)cpp",
templateArgumentLoc().bind("x"),
std::make_unique<VerifyIdIsBoundTo<TemplateArgumentLoc>>("x", 3)));
}
TEST(LoopingMatchers, DoNotOverwritePreviousMatchResultOnFailure) {
// Those matchers cover all the cases where an inner matcher is called
// and there is not a 1:1 relationship between the match of the outer