[ASTMatchers] Add matchers canReferToDecl() and hasUnderlyingDecl()

Summary: Required for D22220

Reviewers: sbenza, klimek, aaron.ballman, alexfh

Subscribers: alexfh, klimek, cfe-commits

Differential Revision: https://reviews.llvm.org/D23004

llvm-svn: 278123
This commit is contained in:
Martin Bohme 2016-08-09 15:07:52 +00:00
parent c710a461b5
commit 8cef2c2f2d
4 changed files with 106 additions and 0 deletions

View File

@ -4970,6 +4970,19 @@ Usable as: Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1Block
</pre></td></tr>
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1NamedDecl.html">NamedDecl</a>&gt;</td><td class="name" onclick="toggle('hasUnderlyingDecl0')"><a name="hasUnderlyingDecl0Anchor">hasUnderlyingDecl</a></td><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1NamedDecl.html">NamedDecl</a>&gt; InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasUnderlyingDecl0"><pre>Matches a NamedDecl whose underlying declaration matches the given
matcher.
Given
namespace N { template&lt;class T&gt; void f(T t); }
template &lt;class T&gt; void g() { using N::f; f(T()); }
unresolvedLookupExpr(hasAnyDeclaration(
namedDecl(hasUnderlyingDecl(hasName("::N::f")))))
matches the use of f in g() .
</pre></td></tr>
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifierLoc.html">NestedNameSpecifierLoc</a>&gt;</td><td class="name" onclick="toggle('hasPrefix1')"><a name="hasPrefix1Anchor">hasPrefix</a></td><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifierLoc.html">NestedNameSpecifierLoc</a>&gt; InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasPrefix1"><pre>Matches on the prefix of a NestedNameSpecifierLoc.
@ -5057,6 +5070,23 @@ matches the [webView ...] message invocation.
<tr><td colspan="4" class="doc" id="hasSourceExpression1"><pre></pre></td></tr>
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1OverloadExpr.html">OverloadExpr</a>&gt;</td><td class="name" onclick="toggle('hasAnyDeclaration0')"><a name="hasAnyDeclaration0Anchor">hasAnyDeclaration</a></td><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt; InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasAnyDeclaration0"><pre>Matches an OverloadExpr if any of the declarations in the set of
overloads matches the given matcher.
Given
template &lt;typename T&gt; void foo(T);
template &lt;typename T&gt; void bar(T);
template &lt;typename T&gt; void baz(T t) {
foo(t);
bar(t);
}
unresolvedLookupExpr(hasAnyDeclaration(
functionTemplateDecl(hasName("foo"))))
matches foo in foo(t); but not bar in bar(t);
</pre></td></tr>
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1ParenType.html">ParenType</a>&gt;</td><td class="name" onclick="toggle('innerType0')"><a name="innerType0Anchor">innerType</a></td><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1Type.html">Type</a>&gt;</td></tr>
<tr><td colspan="4" class="doc" id="innerType0"><pre>Matches ParenType nodes where the inner type is a specific type.

View File

@ -2468,6 +2468,25 @@ hasDeclaration(const internal::Matcher<Decl> &InnerMatcher) {
void(internal::HasDeclarationSupportedTypes)>(InnerMatcher);
}
/// \brief Matches a \c NamedDecl whose underlying declaration matches the given
/// matcher.
///
/// Given
/// \code
/// namespace N { template<class T> void f(T t); }
/// template <class T> void g() { using N::f; f(T()); }
/// \endcode
/// \c unresolvedLookupExpr(hasAnyDeclaration(
/// namedDecl(hasUnderlyingDecl(hasName("::N::f")))))
/// matches the use of \c f in \c g() .
AST_MATCHER_P(NamedDecl, hasUnderlyingDecl, internal::Matcher<NamedDecl>,
InnerMatcher) {
const NamedDecl *UnderlyingDecl = Node.getUnderlyingDecl();
return UnderlyingDecl != nullptr &&
InnerMatcher.matches(*UnderlyingDecl, Finder, Builder);
}
/// \brief Matches on the implicit object argument of a member call expression.
///
/// Example matches y.x()
@ -2823,6 +2842,27 @@ AST_MATCHER_P(DeclRefExpr, throughUsingDecl,
return false;
}
/// \brief Matches an \c OverloadExpr if any of the declarations in the set of
/// overloads matches the given matcher.
///
/// Given
/// \code
/// template <typename T> void foo(T);
/// template <typename T> void bar(T);
/// template <typename T> void baz(T t) {
/// foo(t);
/// bar(t);
/// }
/// \endcode
/// unresolvedLookupExpr(hasAnyDeclaration(
/// functionTemplateDecl(hasName("foo"))))
/// matches \c foo in \c foo(t); but not \c bar in \c bar(t);
AST_MATCHER_P(OverloadExpr, hasAnyDeclaration, internal::Matcher<Decl>,
InnerMatcher) {
return matchesFirstInPointerRange(InnerMatcher, Node.decls_begin(),
Node.decls_end(), Finder, Builder);
}
/// \brief Matches the Decl of a DeclStmt which has a single declaration.
///
/// Given

View File

@ -198,6 +198,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(hasAncestor);
REGISTER_MATCHER(hasAnyArgument);
REGISTER_MATCHER(hasAnyConstructorInitializer);
REGISTER_MATCHER(hasAnyDeclaration);
REGISTER_MATCHER(hasAnyName);
REGISTER_MATCHER(hasAnyParameter);
REGISTER_MATCHER(hasAnySubstatement);
@ -265,6 +266,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(hasTypeLoc);
REGISTER_MATCHER(hasUnaryOperand);
REGISTER_MATCHER(hasUnarySelector);
REGISTER_MATCHER(hasUnderlyingDecl);
REGISTER_MATCHER(hasValueType);
REGISTER_MATCHER(ifStmt);
REGISTER_MATCHER(ignoringImplicit);

View File

@ -241,6 +241,21 @@ TEST(HasDeclaration, HasDeclarationOfTemplateSpecializationType) {
hasDeclaration(namedDecl(hasName("A"))))))));
}
TEST(HasUnderlyingDecl, Matches) {
EXPECT_TRUE(matches("namespace N { template <class T> void f(T t); }"
"template <class T> void g() { using N::f; f(T()); }",
unresolvedLookupExpr(hasAnyDeclaration(
namedDecl(hasUnderlyingDecl(hasName("::N::f")))))));
EXPECT_TRUE(matches(
"namespace N { template <class T> void f(T t); }"
"template <class T> void g() { N::f(T()); }",
unresolvedLookupExpr(hasAnyDeclaration(namedDecl(hasName("::N::f"))))));
EXPECT_TRUE(notMatches(
"namespace N { template <class T> void f(T t); }"
"template <class T> void g() { using N::f; f(T()); }",
unresolvedLookupExpr(hasAnyDeclaration(namedDecl(hasName("::N::f"))))));
}
TEST(HasType, TakesQualTypeMatcherAndMatchesExpr) {
TypeMatcher ClassX = hasDeclaration(recordDecl(hasName("X")));
EXPECT_TRUE(
@ -2072,5 +2087,24 @@ TEST(Matcher, ForEachOverriden) {
EXPECT_TRUE(notMatches(Code2, ForEachOverriddenInClass("A1")));
}
TEST(Matcher, HasAnyDeclaration) {
std::string Fragment = "void foo(int p1);"
"void foo(int *p2);"
"void bar(int p3);"
"template <typename T> void baz(T t) { foo(t); }";
EXPECT_TRUE(
matches(Fragment, unresolvedLookupExpr(hasAnyDeclaration(functionDecl(
hasParameter(0, parmVarDecl(hasName("p1"))))))));
EXPECT_TRUE(
matches(Fragment, unresolvedLookupExpr(hasAnyDeclaration(functionDecl(
hasParameter(0, parmVarDecl(hasName("p2"))))))));
EXPECT_TRUE(
notMatches(Fragment, unresolvedLookupExpr(hasAnyDeclaration(functionDecl(
hasParameter(0, parmVarDecl(hasName("p3"))))))));
EXPECT_TRUE(notMatches(Fragment, unresolvedLookupExpr(hasAnyDeclaration(
functionDecl(hasName("bar"))))));
}
} // namespace ast_matchers
} // namespace clang