Author: Nathan James Date: 2020-02-25T07:51:20Z New Revision: 6a0c066c6102cd463e8ad48881e91e596547507a
URL: https://github.com/llvm/llvm-project/commit/6a0c066c6102cd463e8ad48881e91e596547507a DIFF: https://github.com/llvm/llvm-project/commit/6a0c066c6102cd463e8ad48881e91e596547507a.diff LOG: [ASTMatchers] Adds a matcher called `hasAnyOperatorName` Summary: Acts on `BinaryOperator` and `UnaryOperator` and functions the same as `anyOf(hasOperatorName(...), hasOperatorName(...), ...)` Documentation generation isn't perfect but I feel that the python doc script needs updating for that Reviewers: aaron.ballman, gribozavr2 Reviewed By: aaron.ballman, gribozavr2 Subscribers: cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D75040 Added: Modified: clang/docs/LibASTMatchersReference.html clang/docs/tools/dump_ast_matchers.py clang/include/clang/ASTMatchers/ASTMatchers.h clang/include/clang/ASTMatchers/ASTMatchersInternal.h clang/lib/ASTMatchers/ASTMatchersInternal.cpp clang/lib/ASTMatchers/Dynamic/Registry.cpp clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp Removed: ################################################################################ diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html index 577ea79a4a6f..d6f6b9132bcd 100644 --- a/clang/docs/LibASTMatchersReference.html +++ b/clang/docs/LibASTMatchersReference.html @@ -2128,6 +2128,16 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2> </pre></td></tr> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1BinaryOperator.html">BinaryOperator</a>></td><td class="name" onclick="toggle('hasAnyOperatorName0')"><a name="hasAnyOperatorName0Anchor">hasAnyOperatorName</a></td><td>StringRef, ..., StringRef</td></tr> +<tr><td colspan="4" class="doc" id="hasAnyOperatorName0"><pre>Matches operator expressions (binary or unary) that have any of the +specified names. + + hasAnyOperatorName("+", "-") + Is equivalent to + anyOf(hasOperatorName("+"), hasOperatorName("-")) +</pre></td></tr> + + <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1BinaryOperator.html">BinaryOperator</a>></td><td class="name" onclick="toggle('hasOperatorName0')"><a name="hasOperatorName0Anchor">hasOperatorName</a></td><td>std::string Name</td></tr> <tr><td colspan="4" class="doc" id="hasOperatorName0"><pre>Matches the operator Name of operator expressions (binary or unary). @@ -4373,6 +4383,16 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2> </pre></td></tr> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1UnaryOperator.html">UnaryOperator</a>></td><td class="name" onclick="toggle('hasAnyOperatorName1')"><a name="hasAnyOperatorName1Anchor">hasAnyOperatorName</a></td><td>StringRef, ..., StringRef</td></tr> +<tr><td colspan="4" class="doc" id="hasAnyOperatorName1"><pre>Matches operator expressions (binary or unary) that have any of the +specified names. + + hasAnyOperatorName("+", "-") + Is equivalent to + anyOf(hasOperatorName("+"), hasOperatorName("-")) +</pre></td></tr> + + <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1UnaryOperator.html">UnaryOperator</a>></td><td class="name" onclick="toggle('hasOperatorName1')"><a name="hasOperatorName1Anchor">hasOperatorName</a></td><td>std::string Name</td></tr> <tr><td colspan="4" class="doc" id="hasOperatorName1"><pre>Matches the operator Name of operator expressions (binary or unary). diff --git a/clang/docs/tools/dump_ast_matchers.py b/clang/docs/tools/dump_ast_matchers.py index c44ffa49d1ec..a8f284d55b64 100755 --- a/clang/docs/tools/dump_ast_matchers.py +++ b/clang/docs/tools/dump_ast_matchers.py @@ -284,6 +284,22 @@ def act_on_decl(declaration, comment, allowed_types): add_matcher(result, name, '%s, ..., %s' % (arg, arg), comment) return + m = re.match( + r"""^.*internal::VariadicFunction\s*<\s* + internal::PolymorphicMatcherWithParam1<[\S\s]+ + AST_POLYMORPHIC_SUPPORTED_TYPES\(([^)]*)\)>,\s*([^,]+), + \s*[^>]+>\s*([a-zA-Z]*);$""", + declaration, flags=re.X) + + if m: + results, arg, name = m.groups()[:3] + + result_types = [r.strip() for r in results.split(',')] + for result_type in result_types: + add_matcher(result_type, name, '%s, ..., %s' % (arg, arg), comment) + return + + # Parse Variadic operator matchers. m = re.match( r"""^.*VariadicOperatorMatcherFunc\s*<\s*([^,]+),\s*([^\s]+)\s*>\s* diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h index fa0896da4919..d45825de67db 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -4762,6 +4762,19 @@ AST_POLYMORPHIC_MATCHER_P(hasOperatorName, return Name == Node.getOpcodeStr(Node.getOpcode()); } +/// Matches operator expressions (binary or unary) that have any of the +/// specified names. +/// +/// hasAnyOperatorName("+", "-") +/// Is equivalent to +/// anyOf(hasOperatorName("+"), hasOperatorName("-")) +extern const internal::VariadicFunction< + internal::PolymorphicMatcherWithParam1< + internal::HasAnyOperatorNameMatcher, std::vector<std::string>, + AST_POLYMORPHIC_SUPPORTED_TYPES(BinaryOperator, UnaryOperator)>, + StringRef, internal::hasAnyOperatorNameFunc> + hasAnyOperatorName; + /// Matches all kinds of assignment operators. /// /// Example 1: matches a += b (matcher = binaryOperator(isAssignmentOperator())) diff --git a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h index 03eb1f79eea0..6e4310fa0ee8 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h +++ b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h @@ -1858,6 +1858,47 @@ CompoundStmtMatcher<StmtExpr>::get(const StmtExpr &Node) { llvm::Optional<SourceLocation> getExpansionLocOfMacro(StringRef MacroName, SourceLocation Loc, const ASTContext &Context); + +/// Matches overloaded operators with a specific name. +/// +/// The type argument ArgT is not used by this matcher but is used by +/// PolymorphicMatcherWithParam1 and should be std::vector<std::string>>. +template <typename T, typename ArgT = std::vector<std::string>> +class HasAnyOperatorNameMatcher : public SingleNodeMatcherInterface<T> { + static_assert(std::is_same<T, BinaryOperator>::value || + std::is_same<T, UnaryOperator>::value, + "Matcher only supports `BinaryOperator` and `UnaryOperator`"); + static_assert(std::is_same<ArgT, std::vector<std::string>>::value, + "Matcher ArgT must be std::vector<std::string>"); + +public: + explicit HasAnyOperatorNameMatcher(std::vector<std::string> Names) + : SingleNodeMatcherInterface<T>(), Names(std::move(Names)) {} + + bool matchesNode(const T &Node) const override { + StringRef OpName = getOpName(Node); + return llvm::any_of( + Names, [&](const std::string &Name) { return Name == OpName; }); + } + +private: + static StringRef getOpName(const UnaryOperator &Node) { + return Node.getOpcodeStr(Node.getOpcode()); + } + static StringRef getOpName(const BinaryOperator &Node) { + return Node.getOpcodeStr(); + } + + const std::vector<std::string> Names; +}; + +using HasOpNameMatcher = + PolymorphicMatcherWithParam1<HasAnyOperatorNameMatcher, + std::vector<std::string>, + void(TypeList<BinaryOperator, UnaryOperator>)>; + +HasOpNameMatcher hasAnyOperatorNameFunc(ArrayRef<const StringRef *> NameRefs); + } // namespace internal } // namespace ast_matchers diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp index 2a50089aed5c..59c77a167b1f 100644 --- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -375,6 +375,10 @@ Matcher<ObjCMessageExpr> hasAnySelectorFunc( return hasAnySelectorMatcher(vectorFromRefs(NameRefs)); } +HasOpNameMatcher hasAnyOperatorNameFunc(ArrayRef<const StringRef *> NameRefs) { + return HasOpNameMatcher(vectorFromRefs(NameRefs)); +} + HasNameMatcher::HasNameMatcher(std::vector<std::string> N) : UseUnqualifiedMatch(llvm::all_of( N, [](StringRef Name) { return Name.find("::") == Name.npos; })), @@ -849,6 +853,10 @@ const internal::VariadicOperatorMatcherFunc< const internal::VariadicFunction<internal::Matcher<NamedDecl>, StringRef, internal::hasAnyNameFunc> hasAnyName = {}; + +const internal::VariadicFunction<internal::HasOpNameMatcher, StringRef, + internal::hasAnyOperatorNameFunc> + hasAnyOperatorName = {}; const internal::VariadicFunction<internal::Matcher<ObjCMessageExpr>, StringRef, internal::hasAnySelectorFunc> hasAnySelector = {}; diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp index 7344c622cc9d..5452b408a817 100644 --- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp +++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp @@ -243,6 +243,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(hasAnyConstructorInitializer); REGISTER_MATCHER(hasAnyDeclaration); REGISTER_MATCHER(hasAnyName); + REGISTER_MATCHER(hasAnyOperatorName); REGISTER_MATCHER(hasAnyParameter); REGISTER_MATCHER(hasAnyPlacementArg); REGISTER_MATCHER(hasAnySelector); diff --git a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp index 3e94dde80e8a..2972fc91b908 100644 --- a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -1123,6 +1123,19 @@ TEST(MatchBinaryOperator, HasOperatorName) { EXPECT_TRUE(notMatches("void x() { true && false; }", OperatorOr)); } +TEST(MatchBinaryOperator, HasAnyOperatorName) { + StatementMatcher Matcher = + binaryOperator(hasAnyOperatorName("+", "-", "*", "/")); + + EXPECT_TRUE(matches("int x(int I) { return I + 2; }", Matcher)); + EXPECT_TRUE(matches("int x(int I) { return I - 2; }", Matcher)); + EXPECT_TRUE(matches("int x(int I) { return I * 2; }", Matcher)); + EXPECT_TRUE(matches("int x(int I) { return I / 2; }", Matcher)); + EXPECT_TRUE(notMatches("int x(int I) { return I % 2; }", Matcher)); + // Ensure '+= isn't mistaken. + EXPECT_TRUE(notMatches("void x(int &I) { I += 1; }", Matcher)); +} + TEST(MatchBinaryOperator, HasLHSAndHasRHS) { StatementMatcher OperatorTrueFalse = binaryOperator(hasLHS(cxxBoolLiteral(equals(true))), @@ -1255,6 +1268,18 @@ TEST(MatchUnaryOperator, HasOperatorName) { EXPECT_TRUE(notMatches("void x() { true; } ", OperatorNot)); } +TEST(MatchUnaryOperator, HasAnyOperatorName) { + StatementMatcher Matcher = unaryOperator(hasAnyOperatorName("-", "*", "++")); + + EXPECT_TRUE(matches("int x(int *I) { return *I; }", Matcher)); + EXPECT_TRUE(matches("int x(int I) { return -I; }", Matcher)); + EXPECT_TRUE(matches("void x(int &I) { I++; }", Matcher)); + EXPECT_TRUE(matches("void x(int &I) { ++I; }", Matcher)); + EXPECT_TRUE(notMatches("void x(int &I) { I--; }", Matcher)); + EXPECT_TRUE(notMatches("void x(int &I) { --I; }", Matcher)); + EXPECT_TRUE(notMatches("int *x(int &I) { return &I; }", Matcher)); +} + TEST(MatchUnaryOperator, HasUnaryOperand) { StatementMatcher OperatorOnFalse = unaryOperator(hasUnaryOperand(cxxBoolLiteral(equals(false)))); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits