summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/LibASTMatchersReference.html24
-rw-r--r--docs/tools/dump_ast_matchers.py19
-rw-r--r--include/clang/ASTMatchers/ASTMatchers.h11
-rw-r--r--include/clang/ASTMatchers/ASTMatchersMacros.h19
-rw-r--r--include/clang/ASTMatchers/Dynamic/VariantValue.h8
-rw-r--r--lib/ASTMatchers/Dynamic/Registry.cpp2
-rw-r--r--lib/ASTMatchers/Dynamic/VariantValue.cpp21
-rw-r--r--unittests/ASTMatchers/Dynamic/RegistryTest.cpp21
8 files changed, 99 insertions, 26 deletions
diff --git a/docs/LibASTMatchersReference.html b/docs/LibASTMatchersReference.html
index ce92259813..f701f11d15 100644
--- a/docs/LibASTMatchersReference.html
+++ b/docs/LibASTMatchersReference.html
@@ -3213,12 +3213,6 @@ nestedNameSpecifierLoc(hasPrefix(loc(specifiesType(asString("struct A")))))
</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('loc1')"><a name="loc1Anchor">loc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifier.html">NestedNameSpecifier</a>&gt; InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="loc1"><pre>Matches NestedNameSpecifierLocs for which the given inner
-NestedNameSpecifier-matcher matches.
-</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('specifiesTypeLoc0')"><a name="specifiesTypeLoc0Anchor">specifiesTypeLoc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt; InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="specifiesTypeLoc0"><pre>Matches nested name specifier locs that specify a type matching the
given TypeLoc.
@@ -3613,12 +3607,6 @@ Usable as: Any Matcher
</pre></td></tr>
-<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;</td><td class="name" onclick="toggle('loc0')"><a name="loc0Anchor">loc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt; InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="loc0"><pre>Matches TypeLocs for which the given inner
-QualType-matcher matches.
-</pre></td></tr>
-
-
<tr><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>&gt;</td><td class="name" onclick="toggle('hasDeclaration1')"><a name="hasDeclaration1Anchor">hasDeclaration</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="hasDeclaration1"><pre>Matches a node if the declaration associated with that node
matches the given matcher.
@@ -3778,6 +3766,18 @@ Example matches true (matcher = hasCondition(boolLiteral(equals(true))))
if (true) {}
</pre></td></tr>
+
+<tr><td>Matcher&lt;internal::BindableMatcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifierLoc.html">NestedNameSpecifierLoc</a>&gt;&gt;</td><td class="name" onclick="toggle('loc1')"><a name="loc1Anchor">loc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifier.html">NestedNameSpecifier</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="loc1"><pre>Matches NestedNameSpecifierLocs for which the given inner
+NestedNameSpecifier-matcher matches.
+</pre></td></tr>
+
+
+<tr><td>Matcher&lt;internal::BindableMatcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>&gt;&gt;</td><td class="name" onclick="toggle('loc0')"><a name="loc0Anchor">loc</a></td><td>Matcher&lt<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="loc0"><pre>Matches TypeLocs for which the given inner
+QualType-matcher matches.
+</pre></td></tr>
+
<!--END_TRAVERSAL_MATCHERS -->
</table>
diff --git a/docs/tools/dump_ast_matchers.py b/docs/tools/dump_ast_matchers.py
index c04df8573a..4ece46ae34 100644
--- a/docs/tools/dump_ast_matchers.py
+++ b/docs/tools/dump_ast_matchers.py
@@ -204,6 +204,25 @@ def act_on_decl(declaration, comment, allowed_types):
add_matcher(result_type, name, args, comment)
return
+ m = re.match(r"""^\s*AST_MATCHER_FUNCTION(_P)?(.?)(?:_OVERLOAD)?\(
+ (?:\s*([^\s,]+)\s*,)?
+ \s*([^\s,]+)\s*
+ (?:,\s*([^\s,]+)\s*
+ ,\s*([^\s,]+)\s*)?
+ (?:,\s*([^\s,]+)\s*
+ ,\s*([^\s,]+)\s*)?
+ (?:,\s*\d+\s*)?
+ \)\s*{\s*$""", declaration, flags=re.X)
+ if m:
+ p, n, result, name = m.groups()[0:4]
+ args = m.groups()[4:]
+ if n not in ['', '2']:
+ raise Exception('Cannot parse "%s"' % declaration)
+ args = ', '.join('%s %s' % (args[i], args[i+1])
+ for i in range(0, len(args), 2) if args[i])
+ add_matcher(result, name, args, comment)
+ return
+
m = re.match(r"""^\s*AST_MATCHER(_P)?(.?)(?:_OVERLOAD)?\(
(?:\s*([^\s,]+)\s*,)?
\s*([^\s,]+)\s*
diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h
index 81faa922ed..3f00ec1954 100644
--- a/include/clang/ASTMatchers/ASTMatchers.h
+++ b/include/clang/ASTMatchers/ASTMatchers.h
@@ -2869,8 +2869,8 @@ AST_POLYMORPHIC_MATCHER(
/// \brief Matches \c TypeLocs for which the given inner
/// QualType-matcher matches.
-inline internal::BindableMatcher<TypeLoc> loc(
- const internal::Matcher<QualType> &InnerMatcher) {
+AST_MATCHER_FUNCTION_P_OVERLOAD(internal::BindableMatcher<TypeLoc>, loc,
+ internal::Matcher<QualType>, InnerMatcher, 0) {
return internal::BindableMatcher<TypeLoc>(
new internal::TypeLocTypeMatcher(InnerMatcher));
}
@@ -3353,8 +3353,9 @@ const internal::VariadicAllOfMatcher<
/// \brief Matches \c NestedNameSpecifierLocs for which the given inner
/// NestedNameSpecifier-matcher matches.
-inline internal::BindableMatcher<NestedNameSpecifierLoc> loc(
- const internal::Matcher<NestedNameSpecifier> &InnerMatcher) {
+AST_MATCHER_FUNCTION_P_OVERLOAD(
+ internal::BindableMatcher<NestedNameSpecifierLoc>, loc,
+ internal::Matcher<NestedNameSpecifier>, InnerMatcher, 1) {
return internal::BindableMatcher<NestedNameSpecifierLoc>(
new internal::LocMatcher<NestedNameSpecifierLoc, NestedNameSpecifier>(
InnerMatcher));
@@ -3390,7 +3391,7 @@ AST_MATCHER_P(NestedNameSpecifier, specifiesType,
/// matches "A::"
AST_MATCHER_P(NestedNameSpecifierLoc, specifiesTypeLoc,
internal::Matcher<TypeLoc>, InnerMatcher) {
- return InnerMatcher.matches(Node.getTypeLoc(), Finder, Builder);
+ return Node && InnerMatcher.matches(Node.getTypeLoc(), Finder, Builder);
}
/// \brief Matches on the prefix of a \c NestedNameSpecifier.
diff --git a/include/clang/ASTMatchers/ASTMatchersMacros.h b/include/clang/ASTMatchers/ASTMatchersMacros.h
index b5d5303125..e4394836ec 100644
--- a/include/clang/ASTMatchers/ASTMatchersMacros.h
+++ b/include/clang/ASTMatchers/ASTMatchersMacros.h
@@ -37,6 +37,25 @@
#ifndef LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_MACROS_H
#define LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_MACROS_H
+/// \brief AST_MATCHER_FUNCTION_P(ReturnType, DefineMatcher, ParamType, Param) {
+/// defines a single-parameter function named DefineMatcher() that returns a
+/// ReturnType object.
+///
+/// The code between the curly braces has access to the following variables:
+///
+/// Param: the parameter passed to the function; its type
+/// is ParamType.
+///
+/// The code should return an instance of ReturnType.
+#define AST_MATCHER_FUNCTION_P(ReturnType, DefineMatcher, ParamType, Param) \
+ AST_MATCHER_FUNCTION_P_OVERLOAD(ReturnType, DefineMatcher, ParamType, Param, \
+ 0)
+#define AST_MATCHER_FUNCTION_P_OVERLOAD(ReturnType, DefineMatcher, ParamType, \
+ Param, OverloadId) \
+ inline ReturnType DefineMatcher(const ParamType &Param); \
+ typedef ReturnType (&DefineMatcher##_Type##OverloadId)(const ParamType &); \
+ inline ReturnType DefineMatcher(const ParamType &Param)
+
/// \brief AST_MATCHER(Type, DefineMatcher) { ... }
/// defines a zero parameter function named DefineMatcher() that returns a
/// Matcher<Type> object.
diff --git a/include/clang/ASTMatchers/Dynamic/VariantValue.h b/include/clang/ASTMatchers/Dynamic/VariantValue.h
index 9328d4a9be..1a69a64127 100644
--- a/include/clang/ASTMatchers/Dynamic/VariantValue.h
+++ b/include/clang/ASTMatchers/Dynamic/VariantValue.h
@@ -49,7 +49,8 @@ class VariantMatcher {
class MatcherOps {
public:
virtual ~MatcherOps();
- virtual bool canConstructFrom(const DynTypedMatcher &Matcher) const = 0;
+ virtual bool canConstructFrom(const DynTypedMatcher &Matcher,
+ bool &IsExactMatch) const = 0;
virtual void constructFrom(const DynTypedMatcher &Matcher) = 0;
virtual void constructVariadicOperator(
ast_matchers::internal::VariadicOperatorFunction Func,
@@ -144,7 +145,10 @@ private:
public:
typedef ast_matchers::internal::Matcher<T> MatcherT;
- virtual bool canConstructFrom(const DynTypedMatcher &Matcher) const {
+ virtual bool canConstructFrom(const DynTypedMatcher &Matcher,
+ bool &IsExactMatch) const {
+ IsExactMatch = Matcher.getSupportedKind().isSame(
+ ast_type_traits::ASTNodeKind::getFromNodeKind<T>());
return Matcher.canConvertTo<T>();
}
diff --git a/lib/ASTMatchers/Dynamic/Registry.cpp b/lib/ASTMatchers/Dynamic/Registry.cpp
index d4b68bf0d0..59f01c848f 100644
--- a/lib/ASTMatchers/Dynamic/Registry.cpp
+++ b/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -80,7 +80,6 @@ RegistryMaps::RegistryMaps() {
// findAll
//
// Other:
- // loc
// equals
// equalsNode
@@ -89,6 +88,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_OVERLOADED_2(hasType);
REGISTER_OVERLOADED_2(isDerivedFrom);
REGISTER_OVERLOADED_2(isSameOrDerivedFrom);
+ REGISTER_OVERLOADED_2(loc);
REGISTER_OVERLOADED_2(pointsTo);
REGISTER_OVERLOADED_2(references);
REGISTER_OVERLOADED_2(thisPointerType);
diff --git a/lib/ASTMatchers/Dynamic/VariantValue.cpp b/lib/ASTMatchers/Dynamic/VariantValue.cpp
index e4a02c5225..70d37ca399 100644
--- a/lib/ASTMatchers/Dynamic/VariantValue.cpp
+++ b/lib/ASTMatchers/Dynamic/VariantValue.cpp
@@ -37,7 +37,8 @@ public:
}
virtual void makeTypedMatcher(MatcherOps &Ops) const {
- if (Ops.canConstructFrom(Matcher))
+ bool Ignore;
+ if (Ops.canConstructFrom(Matcher, Ignore))
Ops.constructFrom(Matcher);
}
@@ -69,15 +70,25 @@ public:
}
virtual void makeTypedMatcher(MatcherOps &Ops) const {
+ bool FoundIsExact = false;
const DynTypedMatcher *Found = NULL;
+ int NumFound = 0;
for (size_t i = 0, e = Matchers.size(); i != e; ++i) {
- if (Ops.canConstructFrom(Matchers[i])) {
- if (Found)
- return;
+ bool IsExactMatch;
+ if (Ops.canConstructFrom(Matchers[i], IsExactMatch)) {
+ if (Found) {
+ if (FoundIsExact) {
+ assert(!IsExactMatch && "We should not have two exact matches.");
+ continue;
+ }
+ }
Found = &Matchers[i];
+ FoundIsExact = IsExactMatch;
+ ++NumFound;
}
}
- if (Found)
+ // We only succeed if we found exactly one, or if we found an exact match.
+ if (Found && (FoundIsExact || NumFound == 1))
Ops.constructFrom(*Found);
}
diff --git a/unittests/ASTMatchers/Dynamic/RegistryTest.cpp b/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
index 1d81f2f55b..150f8c929c 100644
--- a/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
+++ b/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
@@ -66,7 +66,7 @@ public:
VariantMatcher Out;
if (Ctor)
Out = Registry::constructMatcher(*Ctor, SourceRange(), Args(Arg1), Error);
- EXPECT_EQ("", DummyError.toStringFull());
+ EXPECT_EQ("", DummyError.toStringFull()) << MatcherName;
return Out;
}
@@ -211,6 +211,25 @@ TEST_F(RegistryTest, OverloadedMatchers) {
Code = "class Z { public: void z() { this->z(); } };";
EXPECT_TRUE(matches(Code, CallExpr0));
EXPECT_FALSE(matches(Code, CallExpr1));
+
+ Matcher<Decl> DeclDecl = declaratorDecl(hasTypeLoc(
+ constructMatcher(
+ "loc", constructMatcher("asString", std::string("const double *")))
+ .getTypedMatcher<TypeLoc>()));
+
+ Matcher<NestedNameSpecifierLoc> NNSL =
+ constructMatcher(
+ "loc", VariantMatcher::SingleMatcher(nestedNameSpecifier(
+ specifiesType(hasDeclaration(recordDecl(hasName("A")))))))
+ .getTypedMatcher<NestedNameSpecifierLoc>();
+
+ Code = "const double * x = 0;";
+ EXPECT_TRUE(matches(Code, DeclDecl));
+ EXPECT_FALSE(matches(Code, NNSL));
+
+ Code = "struct A { struct B {}; }; A::B a_b;";
+ EXPECT_FALSE(matches(Code, DeclDecl));
+ EXPECT_TRUE(matches(Code, NNSL));
}
TEST_F(RegistryTest, PolymorphicMatchers) {