njames93 updated this revision to Diff 273960. njames93 added a comment. Moved the code to build and verify the regex out of the macro
Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D82706/new/ https://reviews.llvm.org/D82706 Files: clang/docs/LibASTMatchersReference.html clang/docs/tools/dump_ast_matchers.py clang/include/clang/ASTMatchers/ASTMatchers.h clang/include/clang/ASTMatchers/ASTMatchersInternal.h clang/include/clang/ASTMatchers/ASTMatchersMacros.h clang/lib/ASTMatchers/ASTMatchersInternal.cpp clang/lib/ASTMatchers/Dynamic/Marshallers.cpp clang/lib/ASTMatchers/Dynamic/Marshallers.h clang/lib/ASTMatchers/Dynamic/Registry.cpp clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp clang/unittests/ASTMatchers/Dynamic/ParserTest.cpp llvm/include/llvm/Support/Regex.h llvm/lib/Support/Regex.cpp
Index: llvm/lib/Support/Regex.cpp =================================================================== --- llvm/lib/Support/Regex.cpp +++ llvm/lib/Support/Regex.cpp @@ -26,7 +26,7 @@ Regex::Regex() : preg(nullptr), error(REG_BADPAT) {} -Regex::Regex(StringRef regex, unsigned Flags) { +Regex::Regex(StringRef regex, RegexFlags Flags) { unsigned flags = 0; preg = new llvm_regex(); preg->re_endp = regex.end(); @@ -39,6 +39,9 @@ error = llvm_regcomp(preg, regex.data(), flags|REG_PEND); } +Regex::Regex(StringRef regex, unsigned Flags) + : Regex(regex, static_cast<RegexFlags>(Flags)) {} + Regex::Regex(Regex &®ex) { preg = regex.preg; error = regex.error; Index: llvm/include/llvm/Support/Regex.h =================================================================== --- llvm/include/llvm/Support/Regex.h +++ llvm/include/llvm/Support/Regex.h @@ -16,6 +16,7 @@ #ifndef LLVM_SUPPORT_REGEX_H #define LLVM_SUPPORT_REGEX_H +#include "llvm/ADT/BitmaskEnum.h" #include <string> struct llvm_regex; @@ -26,20 +27,22 @@ class Regex { public: - enum { - NoFlags=0, + enum RegexFlags : unsigned { + NoFlags = 0, /// Compile for matching that ignores upper/lower case distinctions. - IgnoreCase=1, + IgnoreCase = 1, /// Compile for newline-sensitive matching. With this flag '[^' bracket /// expressions and '.' never match newline. A ^ anchor matches the /// null string after any newline in the string in addition to its normal /// function, and the $ anchor matches the null string before any /// newline in the string in addition to its normal function. - Newline=2, + Newline = 2, /// By default, the POSIX extended regular expression (ERE) syntax is /// assumed. Pass this flag to turn on basic regular expressions (BRE) /// instead. - BasicRegex=4 + BasicRegex = 4, + + LLVM_MARK_AS_BITMASK_ENUM(BasicRegex) }; Regex(); @@ -47,7 +50,8 @@ /// /// \param Regex - referenced string is no longer needed after this /// constructor does finish. Only its compiled form is kept stored. - Regex(StringRef Regex, unsigned Flags = NoFlags); + Regex(StringRef Regex, RegexFlags Flags = NoFlags); + Regex(StringRef Regex, unsigned Flags); Regex(const Regex &) = delete; Regex &operator=(Regex regex) { std::swap(preg, regex.preg); Index: clang/unittests/ASTMatchers/Dynamic/ParserTest.cpp =================================================================== --- clang/unittests/ASTMatchers/Dynamic/ParserTest.cpp +++ clang/unittests/ASTMatchers/Dynamic/ParserTest.cpp @@ -259,6 +259,15 @@ EXPECT_TRUE(matches("unsigned X = sizeof(int);", MStmt)); EXPECT_FALSE(matches("unsigned X = alignof(int);", MStmt)); + Code = + R"query(namedDecl(matchesName("^::[ABC]*$", "IgnoreCase | BasicRegex")))query"; + llvm::Optional<DynTypedMatcher> MatchesName( + Parser::parseMatcherExpression(Code, nullptr, nullptr, &Error)); + EXPECT_EQ("", Error.toStringFull()); + M = MatchesName->unconditionalConvertTo<Decl>(); + EXPECT_TRUE(matches("unsigned AAACCBB;", M)); + EXPECT_TRUE(matches("unsigned aaaccbb;", M)); + Code = "hasInitializer(\n binaryOperator(hasLHS(\"A\")))"; EXPECT_TRUE(!Parser::parseMatcherExpression(Code, &Error).hasValue()); EXPECT_EQ("1:1: Error parsing argument 1 for matcher hasInitializer.\n" @@ -348,6 +357,26 @@ "1:14: Incorrect type for arg 1. (Expected = string) != (Actual = " "String)", ParseMatcherWithError(R"query(decl(hasAttr("unrelated")))query")); + EXPECT_EQ("1:1: Error parsing argument 1 for matcher namedDecl.\n" + "1:11: Error building matcher matchesName.\n" + "1:33: Incorrect type for arg 2. (Expected = string) != (Actual = " + "String)", + ParseMatcherWithError( + R"query(namedDecl(matchesName("[ABC]*", "Ignorecase")))query")); + EXPECT_EQ( + "1:1: Error parsing argument 1 for matcher namedDecl.\n" + "1:11: Error building matcher matchesName.\n" + "1:33: Incorrect type for arg 2. (Expected = string) != (Actual = " + "String)", + ParseMatcherWithError( + R"query(namedDecl(matchesName("[ABC]*", "IgnoreCase & BasicRegex")))query")); + EXPECT_EQ( + "1:1: Error parsing argument 1 for matcher namedDecl.\n" + "1:11: Error building matcher matchesName.\n" + "1:33: Incorrect type for arg 2. (Expected = string) != (Actual = " + "String)", + ParseMatcherWithError( + R"query(namedDecl(matchesName("[ABC]*", "IgnoreCase | Basicregex")))query")); } TEST(ParserTest, OverloadErrors) { Index: clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp =================================================================== --- clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp +++ clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp @@ -77,6 +77,12 @@ EXPECT_TRUE(matches("namespace x { int kTest; }", StartsWithK)); EXPECT_TRUE(matches("class C { int k; };", StartsWithK)); EXPECT_TRUE(notMatches("class C { int ckc; };", StartsWithK)); + EXPECT_TRUE(notMatches("int K;", StartsWithK)); + + DeclarationMatcher StartsWithKIgnoreCase = + namedDecl(matchesName(":k[^:]*$", llvm::Regex::IgnoreCase)); + EXPECT_TRUE(matches("int k;", StartsWithKIgnoreCase)); + EXPECT_TRUE(matches("int K;", StartsWithKIgnoreCase)); } TEST(DeclarationMatcher, MatchClass) { Index: clang/lib/ASTMatchers/Dynamic/Registry.cpp =================================================================== --- clang/lib/ASTMatchers/Dynamic/Registry.cpp +++ clang/lib/ASTMatchers/Dynamic/Registry.cpp @@ -90,6 +90,9 @@ REGISTER_MATCHER_OVERLOAD(name); \ } while (false) +#define REGISTER_REGEX_MATCHER(name) \ + registerMatcher(#name, internal::makeMatcherRegexMarshall(name, name)) + /// Generate a registry map with all the known matchers. /// Please keep sorted alphabetically! RegistryMaps::RegistryMaps() { @@ -121,6 +124,10 @@ }; REGISTER_MATCHER_OVERLOAD(equals); + REGISTER_REGEX_MATCHER(isExpansionInFileMatching); + REGISTER_REGEX_MATCHER(matchesName); + REGISTER_REGEX_MATCHER(matchesSelector); + REGISTER_MATCHER(accessSpecDecl); REGISTER_MATCHER(addrLabelExpr); REGISTER_MATCHER(alignOfExpr); @@ -374,7 +381,6 @@ REGISTER_MATCHER(isEnum); REGISTER_MATCHER(isExceptionVariable); REGISTER_MATCHER(isExpandedFromMacro); - REGISTER_MATCHER(isExpansionInFileMatching); REGISTER_MATCHER(isExpansionInMainFile); REGISTER_MATCHER(isExpansionInSystemHeader); REGISTER_MATCHER(isExplicit); @@ -429,8 +435,6 @@ REGISTER_MATCHER(labelStmt); REGISTER_MATCHER(lambdaExpr); REGISTER_MATCHER(linkageSpecDecl); - REGISTER_MATCHER(matchesName); - REGISTER_MATCHER(matchesSelector); REGISTER_MATCHER(materializeTemporaryExpr); REGISTER_MATCHER(member); REGISTER_MATCHER(memberExpr); Index: clang/lib/ASTMatchers/Dynamic/Marshallers.h =================================================================== --- clang/lib/ASTMatchers/Dynamic/Marshallers.h +++ clang/lib/ASTMatchers/Dynamic/Marshallers.h @@ -35,6 +35,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" +#include "llvm/Support/Regex.h" #include <cassert> #include <cstddef> #include <iterator> @@ -192,6 +193,26 @@ static llvm::Optional<std::string> getBestGuess(const VariantValue &Value); }; +template <> struct ArgTypeTraits<llvm::Regex::RegexFlags> { +private: + static Optional<llvm::Regex::RegexFlags> getFlags(llvm::StringRef Flags); + +public: + static bool is(const VariantValue &Value) { + return Value.isString() && getFlags(Value.getString()); + } + + static llvm::Regex::RegexFlags get(const VariantValue &Value) { + return *getFlags(Value.getString()); + } + + static ArgKind getKind() { return ArgKind(ArgKind::AK_String); } + + static llvm::Optional<std::string> getBestGuess(const VariantValue &Value) { + return llvm::None; + } +}; + template <> struct ArgTypeTraits<OpenMPClauseKind> { private: static Optional<OpenMPClauseKind> getClauseKind(llvm::StringRef ClauseKind) { @@ -711,6 +732,63 @@ std::vector<std::unique_ptr<MatcherDescriptor>> Overloads; }; +template <typename ReturnType> +class RegexMatcherDescriptor : public MatcherDescriptor { +public: + RegexMatcherDescriptor(ReturnType (*WithFlags)(StringRef, + llvm::Regex::RegexFlags), + ReturnType (*NoFlags)(StringRef), + ArrayRef<ASTNodeKind> RetKinds) + : WithFlags(WithFlags), NoFlags(NoFlags), + RetKinds(RetKinds.begin(), RetKinds.end()) {} + bool isVariadic() const override { return true; } + unsigned getNumArgs() const override { return 0; } + + void getArgKinds(ASTNodeKind ThisKind, unsigned ArgNo, + std::vector<ArgKind> &Kinds) const override { + assert(ArgNo < 2); + Kinds.push_back(ArgKind::AK_String); + } + + bool isConvertibleTo(ASTNodeKind Kind, unsigned *Specificity, + ASTNodeKind *LeastDerivedKind) const override { + return isRetKindConvertibleTo(RetKinds, Kind, Specificity, + LeastDerivedKind); + } + + VariantMatcher create(SourceRange NameRange, ArrayRef<ParserValue> Args, + Diagnostics *Error) const override { + if (Args.size() < 1 || Args.size() > 2) { + Error->addError(NameRange, Diagnostics::ET_RegistryWrongArgCount) + << "1 or 2" << Args.size(); + return VariantMatcher(); + } + if (!ArgTypeTraits<StringRef>::is(Args[0].Value)) { + Error->addError(Args[0].Range, Error->ET_RegistryWrongArgType) + << 1 << ArgTypeTraits<StringRef>::getKind().asString() + << Args[0].Value.getTypeAsString(); + } + if (Args.size() == 1) { + return outvalueToVariantMatcher( + NoFlags(ArgTypeTraits<StringRef>::get(Args[0].Value))); + } + if (!ArgTypeTraits<llvm::Regex::RegexFlags>::is(Args[1].Value)) { + Error->addError(Args[1].Range, Error->ET_RegistryWrongArgType) + << 2 << ArgTypeTraits<llvm::Regex::RegexFlags>::getKind().asString() + << Args[1].Value.getTypeAsString(); + return VariantMatcher(); + } + return outvalueToVariantMatcher( + WithFlags(ArgTypeTraits<StringRef>::get(Args[0].Value), + ArgTypeTraits<llvm::Regex::RegexFlags>::get(Args[1].Value))); + } + +private: + ReturnType (*const WithFlags)(StringRef, llvm::Regex::RegexFlags); + ReturnType (*const NoFlags)(StringRef); + const std::vector<ASTNodeKind> RetKinds; +}; + /// Variadic operator marshaller function. class VariadicOperatorMatcherDescriptor : public MatcherDescriptor { public: @@ -814,6 +892,16 @@ reinterpret_cast<void (*)()>(Func), MatcherName, RetTypes, AKs); } +template <typename ReturnType> +std::unique_ptr<MatcherDescriptor> makeMatcherRegexMarshall( + ReturnType (*FuncFlags)(llvm::StringRef, llvm::Regex::RegexFlags), + ReturnType (*Func)(llvm::StringRef)) { + std::vector<ASTNodeKind> RetTypes; + BuildReturnTypeVector<ReturnType>::build(RetTypes); + return std::make_unique<RegexMatcherDescriptor<ReturnType>>(FuncFlags, Func, + RetTypes); +} + /// Variadic overload. template <typename ResultT, typename ArgT, ResultT (*Func)(ArrayRef<const ArgT *>)> Index: clang/lib/ASTMatchers/Dynamic/Marshallers.cpp =================================================================== --- clang/lib/ASTMatchers/Dynamic/Marshallers.cpp +++ clang/lib/ASTMatchers/Dynamic/Marshallers.cpp @@ -110,3 +110,27 @@ "UETT_"); return llvm::None; } + +llvm::Optional<llvm::Regex::RegexFlags> +clang::ast_matchers::dynamic::internal::ArgTypeTraits< + llvm::Regex::RegexFlags>::getFlags(llvm::StringRef Flags) { + llvm::Regex::RegexFlags Flag = llvm::Regex::NoFlags; + SmallVector<StringRef, 4> Split; + Flags.split(Split, '|', -1, false); + for (StringRef OrFlag : Split) { + OrFlag = OrFlag.trim(); + if (OrFlag.empty()) + continue; + if (OrFlag == "IgnoreCase") + Flag |= llvm::Regex::IgnoreCase; + else if (OrFlag == "NewLine") + Flag |= llvm::Regex::Newline; + else if (OrFlag == "BasicRegex") + Flag |= llvm::Regex::BasicRegex; + else if (OrFlag == "NoFlags") + continue; + else + return None; + } + return Flag; +} Index: clang/lib/ASTMatchers/ASTMatchersInternal.cpp =================================================================== --- clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -29,6 +29,8 @@ #include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/Regex.h" +#include "llvm/Support/WithColor.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> #include <cassert> @@ -682,6 +684,19 @@ return llvm::None; } +std::shared_ptr<llvm::Regex> createAndVerifyRegex(StringRef Regex, + llvm::Regex::RegexFlags Flags, + StringRef MatcherID) { + assert(!Regex.empty() && "Empty regex string"); + auto SharedRegex = std::make_shared<llvm::Regex>(Regex, Flags); + std::string Error; + if (!SharedRegex->isValid(Error)) { + llvm::WithColor::error() + << "building matcher '" << MatcherID << "': " << Error << "\n"; + llvm::WithColor::note() << " input was '" << Regex << "'\n"; + } + return SharedRegex; +} } // end namespace internal const internal::VariadicDynCastAllOfMatcher<Stmt, ObjCAutoreleasePoolStmt> Index: clang/include/clang/ASTMatchers/ASTMatchersMacros.h =================================================================== --- clang/include/clang/ASTMatchers/ASTMatchersMacros.h +++ clang/include/clang/ASTMatchers/ASTMatchersMacros.h @@ -438,4 +438,122 @@ ReturnTypesF>::Func MatcherName##Loc; \ AST_TYPE_TRAVERSE_MATCHER(MatcherName, FunctionName##Type, ReturnTypesF) +/// AST_MATCHER_REGEX(Type, DefineMatcher, Param) { ... } +/// defines a function named DefineMatcher() that takes a regular expression +/// string paramater and an optional RegexFlags parameter and returns a +/// Matcher<Type> object. +/// +/// The code between the curly braces has access to the following variables: +/// +/// Node: the AST node being matched; its type is Type. +/// Param: a pointer to an \ref llvm::Regex object +/// Finder: an ASTMatchFinder*. +/// Builder: a BoundNodesTreeBuilder*. +/// +/// The code should return true if 'Node' matches. +#define AST_MATCHER_REGEX(Type, DefineMatcher, Param) \ + AST_MATCHER_REGEX_OVERLOAD(Type, DefineMatcher, Param, 0) + +#define AST_MATCHER_REGEX_OVERLOAD(Type, DefineMatcher, Param, OverloadId) \ + namespace internal { \ + class matcher_##DefineMatcher##OverloadId##Matcher \ + : public ::clang::ast_matchers::internal::MatcherInterface<Type> { \ + public: \ + explicit matcher_##DefineMatcher##OverloadId##Matcher( \ + std::shared_ptr<llvm::Regex> RE) \ + : Param(std::move(RE)) {} \ + bool matches(const Type &Node, \ + ::clang::ast_matchers::internal::ASTMatchFinder *Finder, \ + ::clang::ast_matchers::internal::BoundNodesTreeBuilder \ + *Builder) const override; \ + \ + private: \ + std::shared_ptr<llvm::Regex> const Param; \ + }; \ + } \ + inline ::clang::ast_matchers::internal::Matcher<Type> DefineMatcher( \ + llvm::StringRef Param, llvm::Regex::RegexFlags RegexFlags) { \ + return ::clang::ast_matchers::internal::makeMatcher( \ + new internal::matcher_##DefineMatcher##OverloadId##Matcher( \ + ::clang::ast_matchers::internal::createAndVerifyRegex( \ + Param, RegexFlags, #DefineMatcher))); \ + } \ + inline ::clang::ast_matchers::internal::Matcher<Type> DefineMatcher( \ + llvm::StringRef Param) { \ + return DefineMatcher(Param, llvm::Regex::NoFlags); \ + } \ + \ + typedef ::clang::ast_matchers::internal::Matcher<Type> ( \ + &DefineMatcher##_Type##OverloadId##Flags)(llvm::StringRef, \ + llvm::Regex::RegexFlags); \ + typedef ::clang::ast_matchers::internal::Matcher<Type> ( \ + &DefineMatcher##_Type##OverloadId)(llvm::StringRef); \ + inline bool internal::matcher_##DefineMatcher##OverloadId##Matcher::matches( \ + const Type &Node, \ + ::clang::ast_matchers::internal::ASTMatchFinder *Finder, \ + ::clang::ast_matchers::internal::BoundNodesTreeBuilder *Builder) const + +/// AST_POLYMORPHIC_MATCHER_REGEX(DefineMatcher, ReturnTypesF, Param) { ... } +/// defines a function named DefineMatcher() that takes a regular expression +/// string paramater and an optional RegexFlags parameter that is polymorphic in +/// the return type. +/// +/// The variables are the same as for +/// AST_MATCHER_REGEX, with the addition of NodeType, which specifies the node +/// type of the matcher Matcher<NodeType> returned by the function matcher(). +#define AST_POLYMORPHIC_MATCHER_REGEX(DefineMatcher, ReturnTypesF, Param) \ + AST_POLYMORPHIC_MATCHER_REGEX_OVERLOAD(DefineMatcher, ReturnTypesF, Param, 0) + +#define AST_POLYMORPHIC_MATCHER_REGEX_OVERLOAD(DefineMatcher, ReturnTypesF, \ + Param, OverloadId) \ + namespace internal { \ + template <typename NodeType, typename ParamT> \ + class matcher_##DefineMatcher##OverloadId##Matcher \ + : public ::clang::ast_matchers::internal::MatcherInterface<NodeType> { \ + public: \ + explicit matcher_##DefineMatcher##OverloadId##Matcher( \ + std::shared_ptr<llvm::Regex> RE) \ + : Param(std::move(RE)) {} \ + bool matches(const NodeType &Node, \ + ::clang::ast_matchers::internal::ASTMatchFinder *Finder, \ + ::clang::ast_matchers::internal::BoundNodesTreeBuilder \ + *Builder) const override; \ + \ + private: \ + std::shared_ptr<llvm::Regex> const Param; \ + }; \ + } \ + inline ::clang::ast_matchers::internal::PolymorphicMatcherWithParam1< \ + internal::matcher_##DefineMatcher##OverloadId##Matcher, \ + std::shared_ptr<llvm::Regex>, ReturnTypesF> \ + DefineMatcher(llvm::StringRef Param, llvm::Regex::RegexFlags RegexFlags) { \ + return ::clang::ast_matchers::internal::PolymorphicMatcherWithParam1< \ + internal::matcher_##DefineMatcher##OverloadId##Matcher, \ + std::shared_ptr<llvm::Regex>, ReturnTypesF>( \ + ::clang::ast_matchers::internal::createAndVerifyRegex( \ + Param, RegexFlags, #DefineMatcher)); \ + } \ + inline ::clang::ast_matchers::internal::PolymorphicMatcherWithParam1< \ + internal::matcher_##DefineMatcher##OverloadId##Matcher, \ + std::shared_ptr<llvm::Regex>, ReturnTypesF> \ + DefineMatcher(llvm::StringRef Param) { \ + return DefineMatcher(Param, llvm::Regex::NoFlags); \ + } \ + typedef ::clang::ast_matchers::internal::PolymorphicMatcherWithParam1< \ + internal::matcher_##DefineMatcher##OverloadId##Matcher, \ + std::shared_ptr<llvm::Regex>, ReturnTypesF> ( \ + &DefineMatcher##_Type##OverloadId##Flags)( \ + llvm::StringRef Param, llvm::Regex::RegexFlags RegexFlags); \ + typedef ::clang::ast_matchers::internal::PolymorphicMatcherWithParam1< \ + internal::matcher_##DefineMatcher##OverloadId##Matcher, \ + std::shared_ptr<llvm::Regex>, ReturnTypesF> ( \ + &DefineMatcher##_Type##OverloadId)(llvm::StringRef Param); \ + template <typename NodeType, typename ParamT> \ + bool internal:: \ + matcher_##DefineMatcher##OverloadId##Matcher<NodeType, ParamT>::matches( \ + const NodeType &Node, \ + ::clang::ast_matchers::internal::ASTMatchFinder *Finder, \ + ::clang::ast_matchers::internal::BoundNodesTreeBuilder *Builder) \ + const + #endif // LLVM_CLANG_ASTMATCHERS_ASTMATCHERSMACROS_H Index: clang/include/clang/ASTMatchers/ASTMatchersInternal.h =================================================================== --- clang/include/clang/ASTMatchers/ASTMatchersInternal.h +++ clang/include/clang/ASTMatchers/ASTMatchersInternal.h @@ -40,7 +40,6 @@ #include "clang/AST/DeclFriend.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" -#include "clang/AST/ExprObjC.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/NestedNameSpecifier.h" @@ -61,11 +60,13 @@ #include "llvm/ADT/iterator.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/Regex.h" #include <algorithm> #include <cassert> #include <cstddef> #include <cstdint> #include <map> +#include <memory> #include <string> #include <tuple> #include <type_traits> @@ -1948,6 +1949,10 @@ const Matcher<CXXBaseSpecifier> &BaseSpecMatcher, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder); +std::shared_ptr<llvm::Regex> createAndVerifyRegex(StringRef Regex, + llvm::Regex::RegexFlags Flags, + StringRef MatcherID); + } // namespace internal } // namespace ast_matchers Index: clang/include/clang/ASTMatchers/ASTMatchers.h =================================================================== --- clang/include/clang/ASTMatchers/ASTMatchers.h +++ clang/include/clang/ASTMatchers/ASTMatchers.h @@ -283,9 +283,10 @@ /// \endcode /// /// Usable as: Matcher<Decl>, Matcher<Stmt>, Matcher<TypeLoc> -AST_POLYMORPHIC_MATCHER_P(isExpansionInFileMatching, - AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, Stmt, TypeLoc), - std::string, RegExp) { +AST_POLYMORPHIC_MATCHER_REGEX(isExpansionInFileMatching, + AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, Stmt, + TypeLoc), + RegExp) { auto &SourceManager = Finder->getASTContext().getSourceManager(); auto ExpansionLoc = SourceManager.getExpansionLoc(Node.getBeginLoc()); if (ExpansionLoc.isInvalid()) { @@ -298,8 +299,7 @@ } auto Filename = FileEntry->getName(); - llvm::Regex RE(RegExp); - return RE.match(Filename); + return RegExp->match(Filename); } /// Matches statements that are (transitively) expanded from the named macro. @@ -2748,11 +2748,9 @@ /// \code /// namespace foo { namespace bar { class X; } } /// \endcode -AST_MATCHER_P(NamedDecl, matchesName, std::string, RegExp) { - assert(!RegExp.empty()); +AST_MATCHER_REGEX(NamedDecl, matchesName, RegExp) { std::string FullNameString = "::" + Node.getQualifiedNameAsString(); - llvm::Regex RE(RegExp); - return RE.match(FullNameString); + return RegExp->match(FullNameString); } /// Matches overloaded operator names. @@ -3373,11 +3371,9 @@ /// \code /// [self.bodyView loadHTMLString:html baseURL:NULL]; /// \endcode -AST_MATCHER_P(ObjCMessageExpr, matchesSelector, std::string, RegExp) { - assert(!RegExp.empty()); +AST_MATCHER_REGEX(ObjCMessageExpr, matchesSelector, RegExp) { std::string SelectorString = Node.getSelector().getAsString(); - llvm::Regex RE(RegExp); - return RE.match(SelectorString); + return RegExp->match(SelectorString); } /// Matches when the selector is the empty selector Index: clang/docs/tools/dump_ast_matchers.py =================================================================== --- clang/docs/tools/dump_ast_matchers.py +++ clang/docs/tools/dump_ast_matchers.py @@ -230,6 +230,28 @@ add_matcher(result_type, name, args, comment) return + m = re.match(r"""^\s*AST_POLYMORPHIC_MATCHER_REGEX(?:_OVERLOAD)?\( + \s*([^\s,]+)\s*, + \s*AST_POLYMORPHIC_SUPPORTED_TYPES\(([^)]*)\), + \s*([^\s,]+)\s* + (?:,\s*\d+\s*)? + \)\s*{\s*$""", declaration, flags=re.X) + + if m: + name, results, arg_name = m.groups()[0:3] + result_types = [r.strip() for r in results.split(',')] + if allowed_types and allowed_types != result_types: + raise Exception('Inconsistent documentation for: %s' % name) + arg = "StringRef %s, Regex::RegexFlags Flags = NoFlags" % arg_name + comment += """ +If the matcher is used in clang-query, RegexFlags parameter +should be passed as a quoted string. e.g: "NoFlags". +Flags can be combined with '|' example \"IgnoreCase | BasicRegex\" +""" + for result_type in result_types: + add_matcher(result_type, name, arg, comment) + return + m = re.match(r"""^\s*AST_MATCHER_FUNCTION(_P)?(.?)(?:_OVERLOAD)?\( (?:\s*([^\s,]+)\s*,)? \s*([^\s,]+)\s* @@ -275,6 +297,31 @@ add_matcher(result_type, name, args, comment) return + m = re.match(r"""^\s*AST_MATCHER_REGEX(?:_OVERLOAD)?\( + \s*([^\s,]+)\s*, + \s*([^\s,]+)\s*, + \s*([^\s,]+)\s* + (?:,\s*\d+\s*)? + \)\s*{""", declaration, flags=re.X) + if m: + result, name, arg_name = m.groups()[0:3] + if not result: + if not allowed_types: + raise Exception('Did not find allowed result types for: %s' % name) + result_types = allowed_types + else: + result_types = [result] + arg = "StringRef %s, Regex::RegexFlags Flags = NoFlags" % arg_name + comment += """ +If the matcher is used in clang-query, RegexFlags parameter +should be passed as a quoted string. e.g: "NoFlags". +Flags can be combined with '|' example \"IgnoreCase | BasicRegex\" +""" + + for result_type in result_types: + add_matcher(result_type, name, arg, comment) + return + # Parse ArgumentAdapting matchers. m = re.match( r"""^.*ArgumentAdaptingMatcherFunc<.*>\s* Index: clang/docs/LibASTMatchersReference.html =================================================================== --- clang/docs/LibASTMatchersReference.html +++ clang/docs/LibASTMatchersReference.html @@ -3007,7 +3007,7 @@ </pre></td></tr> -<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('isExpansionInFileMatching0')"><a name="isExpansionInFileMatching0Anchor">isExpansionInFileMatching</a></td><td>std::string RegExp</td></tr> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('isExpansionInFileMatching0')"><a name="isExpansionInFileMatching0Anchor">isExpansionInFileMatching</a></td><td>StringRef RegExp, Regex::RegexFlags Flags = NoFlags</td></tr> <tr><td colspan="4" class="doc" id="isExpansionInFileMatching0"><pre>Matches AST nodes that were expanded within files whose name is partially matching a given regex. @@ -3019,6 +3019,10 @@ class Y {}; Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>> + +If the matcher is used in clang-query, RegexFlags parameter +should be passed as a quoted string. e.g: "NoFlags". +Flags can be combined with '|' example "IgnoreCase | BasicRegex" </pre></td></tr> @@ -3725,7 +3729,7 @@ </pre></td></tr> -<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1NamedDecl.html">NamedDecl</a>></td><td class="name" onclick="toggle('matchesName0')"><a name="matchesName0Anchor">matchesName</a></td><td>std::string RegExp</td></tr> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1NamedDecl.html">NamedDecl</a>></td><td class="name" onclick="toggle('matchesName0')"><a name="matchesName0Anchor">matchesName</a></td><td>StringRef RegExp, Regex::RegexFlags Flags = NoFlags</td></tr> <tr><td colspan="4" class="doc" id="matchesName0"><pre>Matches NamedDecl nodes whose fully qualified names contain a substring matched by the given RegExp. @@ -3738,6 +3742,10 @@ Example matches X (regexp is one of "::X", "^foo::.*X", among others) namespace foo { namespace bar { class X; } } + +If the matcher is used in clang-query, RegexFlags parameter +should be passed as a quoted string. e.g: "NoFlags". +Flags can be combined with '|' example "IgnoreCase | BasicRegex" </pre></td></tr> @@ -3932,12 +3940,16 @@ </pre></td></tr> -<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCMessageExpr.html">ObjCMessageExpr</a>></td><td class="name" onclick="toggle('matchesSelector0')"><a name="matchesSelector0Anchor">matchesSelector</a></td><td>std::string RegExp</td></tr> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCMessageExpr.html">ObjCMessageExpr</a>></td><td class="name" onclick="toggle('matchesSelector0')"><a name="matchesSelector0Anchor">matchesSelector</a></td><td>StringRef RegExp, Regex::RegexFlags Flags = NoFlags</td></tr> <tr><td colspan="4" class="doc" id="matchesSelector0"><pre>Matches ObjC selectors whose name contains a substring matched by the given RegExp. matcher = objCMessageExpr(matchesSelector("loadHTMLStringmatches the outer message expr in the code below, but NOT the message invocation for self.bodyView. [self.bodyView loadHTMLString:html baseURL:NULL]; + +If the matcher is used in clang-query, RegexFlags parameter +should be passed as a quoted string. e.g: "NoFlags". +Flags can be combined with '|' example "IgnoreCase | BasicRegex" </pre></td></tr> @@ -4228,7 +4240,7 @@ </pre></td></tr> -<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('isExpansionInFileMatching1')"><a name="isExpansionInFileMatching1Anchor">isExpansionInFileMatching</a></td><td>std::string RegExp</td></tr> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('isExpansionInFileMatching1')"><a name="isExpansionInFileMatching1Anchor">isExpansionInFileMatching</a></td><td>StringRef RegExp, Regex::RegexFlags Flags = NoFlags</td></tr> <tr><td colspan="4" class="doc" id="isExpansionInFileMatching1"><pre>Matches AST nodes that were expanded within files whose name is partially matching a given regex. @@ -4240,6 +4252,10 @@ class Y {}; Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>> + +If the matcher is used in clang-query, RegexFlags parameter +should be passed as a quoted string. e.g: "NoFlags". +Flags can be combined with '|' example "IgnoreCase | BasicRegex" </pre></td></tr> @@ -4410,7 +4426,7 @@ </pre></td></tr> -<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td><td class="name" onclick="toggle('isExpansionInFileMatching2')"><a name="isExpansionInFileMatching2Anchor">isExpansionInFileMatching</a></td><td>std::string RegExp</td></tr> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>></td><td class="name" onclick="toggle('isExpansionInFileMatching2')"><a name="isExpansionInFileMatching2Anchor">isExpansionInFileMatching</a></td><td>StringRef RegExp, Regex::RegexFlags Flags = NoFlags</td></tr> <tr><td colspan="4" class="doc" id="isExpansionInFileMatching2"><pre>Matches AST nodes that were expanded within files whose name is partially matching a given regex. @@ -4422,6 +4438,10 @@ class Y {}; Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1TypeLoc.html">TypeLoc</a>> + +If the matcher is used in clang-query, RegexFlags parameter +should be passed as a quoted string. e.g: "NoFlags". +Flags can be combined with '|' example "IgnoreCase | BasicRegex" </pre></td></tr>
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits