diff options
-rw-r--r-- | docs/LibASTMatchersReference.html | 24 | ||||
-rw-r--r-- | docs/tools/dump_ast_matchers.py | 19 | ||||
-rw-r--r-- | include/clang/ASTMatchers/ASTMatchers.h | 11 | ||||
-rw-r--r-- | include/clang/ASTMatchers/ASTMatchersMacros.h | 19 | ||||
-rw-r--r-- | include/clang/ASTMatchers/Dynamic/VariantValue.h | 8 | ||||
-rw-r--r-- | lib/ASTMatchers/Dynamic/Registry.cpp | 2 | ||||
-rw-r--r-- | lib/ASTMatchers/Dynamic/VariantValue.cpp | 21 | ||||
-rw-r--r-- | unittests/ASTMatchers/Dynamic/RegistryTest.cpp | 21 |
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<<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifierLoc.html">NestedNameSpecifierLoc</a>></td><td class="name" onclick="toggle('loc1')"><a name="loc1Anchor">loc</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifier.html">NestedNameSpecifier</a>> 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<<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifierLoc.html">NestedNameSpecifierLoc</a>></td><td class="name" onclick="toggle('specifiesTypeLoc0')"><a name="specifiesTypeLoc0Anchor">specifiesTypeLoc</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>> 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<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td><td class="name" onclick="toggle('loc0')"><a name="loc0Anchor">loc</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> 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<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypedefType.html">TypedefType</a>></td><td class="name" onclick="toggle('hasDeclaration1')"><a name="hasDeclaration1Anchor">hasDeclaration</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> 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<internal::BindableMatcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifierLoc.html">NestedNameSpecifierLoc</a>>></td><td class="name" onclick="toggle('loc1')"><a name="loc1Anchor">loc</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifier.html">NestedNameSpecifier</a>> 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<internal::BindableMatcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>>></td><td class="name" onclick="toggle('loc0')"><a name="loc0Anchor">loc</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1QualType.html">QualType</a>> 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) { |