</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).
</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).
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*
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()))
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
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; })),
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 = {};
REGISTER_MATCHER(hasAnyConstructorInitializer);
REGISTER_MATCHER(hasAnyDeclaration);
REGISTER_MATCHER(hasAnyName);
+ REGISTER_MATCHER(hasAnyOperatorName);
REGISTER_MATCHER(hasAnyParameter);
REGISTER_MATCHER(hasAnyPlacementArg);
REGISTER_MATCHER(hasAnySelector);
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))),
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))));