[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
This commit is contained in:
Nathan James 2020-02-25 07:51:07 +00:00
parent 3e9a7b2ba4
commit 6a0c066c61
7 changed files with 124 additions and 0 deletions

View File

@ -2128,6 +2128,16 @@ Usable as: Any Matcher
</pre></td></tr>
<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1BinaryOperator.html">BinaryOperator</a>&gt;</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&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1BinaryOperator.html">BinaryOperator</a>&gt;</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 @@ should be passed as a quoted string. e.g., ofKind("UETT_SizeOf").
</pre></td></tr>
<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1UnaryOperator.html">UnaryOperator</a>&gt;</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&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1UnaryOperator.html">UnaryOperator</a>&gt;</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).

View File

@ -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*

View File

@ -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()))

View File

@ -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

View File

@ -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 = {};

View File

@ -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);

View File

@ -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))));