forked from OSchip/llvm-project
[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:
parent
1970eefb17
commit
b1c7f84643
|
@ -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<<a href="https://clang.llvm.org/doxygen/classclang_1_1TemplateArgumentLoc.html">TemplateArgumentLoc</a>></td><td class="name" onclick="toggle('templateArgumentLoc0')"><a name="templateArgumentLoc0Anchor">templateArgumentLoc</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TemplateArgumentLoc.html">TemplateArgumentLoc</a>>...</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="templateArgumentLoc0"><pre>Matches template arguments (with location info).
|
||||
|
||||
Given
|
||||
template <typename T> struct C {};
|
||||
C<int> c;
|
||||
templateArgumentLoc()
|
||||
matches 'int' in C<int>.
|
||||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>></td><td class="name" onclick="toggle('templateArgument0')"><a name="templateArgument0Anchor">templateArgument</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TemplateArgument.html">TemplateArgument</a>>...</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<<a href="https://clang.llvm.org/doxygen/classclang_1_1OMPDefaultClause.html">OMPDefaultClause</a>></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<<a href="https://clang.llvm.org/doxygen/classclang_1_1OMPDefaultClause.html">OMPDefaultClause</a>></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<<a href="https://clang.llvm.org/doxygen/classclang_1_1OMPDefaultClause.html">OMPDefaultClause</a>></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<<a href="https://clang.llvm.org/doxygen/classclang_1_1OMPExecutableDirective.html">OMPExecutableDirective</a>></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.
|
||||
|
|
|
@ -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> {};
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue