From 9989dfb6402aedfbeed904f4f5ce204f01f854f8 Mon Sep 17 00:00:00 2001 From: Samuel Benzaquen Date: Mon, 10 Mar 2014 15:40:23 +0000 Subject: [PATCH] Add loc() to the dynamic registry. Summary: Add loc() to the dynamic registry. Other fixes: - Fix the polymorphic variant value to accept an exact match, even if there are other possible conversions. - Fix specifiesTypeLoc() to not crash on an empty NestedNameSpecifierLoc. Reviewers: klimek CC: cfe-commits, klimek Differential Revision: http://llvm-reviews.chandlerc.com/D2928 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@203467 91177308-0d34-0410-b5e6-96231b3b80d8 --- docs/LibASTMatchersReference.html | 24 +++++++++---------- docs/tools/dump_ast_matchers.py | 19 +++++++++++++++ include/clang/ASTMatchers/ASTMatchers.h | 11 +++++---- include/clang/ASTMatchers/ASTMatchersMacros.h | 19 +++++++++++++++ .../clang/ASTMatchers/Dynamic/VariantValue.h | 8 +++++-- lib/ASTMatchers/Dynamic/Registry.cpp | 2 +- lib/ASTMatchers/Dynamic/VariantValue.cpp | 21 ++++++++++++---- .../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"))))) -Matcher<NestedNameSpecifierLoc>locMatcher<NestedNameSpecifier> InnerMatcher -
Matches NestedNameSpecifierLocs for which the given inner
-NestedNameSpecifier-matcher matches.
-
- - Matcher<NestedNameSpecifierLoc>specifiesTypeLocMatcher<TypeLoc> InnerMatcher
Matches nested name specifier locs that specify a type matching the
 given TypeLoc.
@@ -3613,12 +3607,6 @@ Usable as: Any Matcher
 
-Matcher<TypeLoc>locMatcher<QualType> InnerMatcher -
Matches TypeLocs for which the given inner
-QualType-matcher matches.
-
- - Matcher<TypedefType>hasDeclarationMatcher<Decl> InnerMatcher
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) {}
 
+ +Matcher<internal::BindableMatcher<NestedNameSpecifierLoc>>locMatcher<NestedNameSpecifier> InnerMatcher +
Matches NestedNameSpecifierLocs for which the given inner
+NestedNameSpecifier-matcher matches.
+
+ + +Matcher<internal::BindableMatcher<TypeLoc>>locMatcher<QualType> InnerMatcher +
Matches TypeLocs for which the given inner
+QualType-matcher matches.
+
+ 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 loc( - const internal::Matcher &InnerMatcher) { +AST_MATCHER_FUNCTION_P_OVERLOAD(internal::BindableMatcher, loc, + internal::Matcher, InnerMatcher, 0) { return internal::BindableMatcher( 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 loc( - const internal::Matcher &InnerMatcher) { +AST_MATCHER_FUNCTION_P_OVERLOAD( + internal::BindableMatcher, loc, + internal::Matcher, InnerMatcher, 1) { return internal::BindableMatcher( new internal::LocMatcher( InnerMatcher)); @@ -3390,7 +3391,7 @@ AST_MATCHER_P(NestedNameSpecifier, specifiesType, /// matches "A::" AST_MATCHER_P(NestedNameSpecifierLoc, specifiesTypeLoc, internal::Matcher, 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 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 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()); return Matcher.canConvertTo(); } 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 DeclDecl = declaratorDecl(hasTypeLoc( + constructMatcher( + "loc", constructMatcher("asString", std::string("const double *"))) + .getTypedMatcher())); + + Matcher NNSL = + constructMatcher( + "loc", VariantMatcher::SingleMatcher(nestedNameSpecifier( + specifiesType(hasDeclaration(recordDecl(hasName("A"))))))) + .getTypedMatcher(); + + 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) { -- 2.40.0