forked from OSchip/llvm-project
[ASTMatchers] Add hasPlacementArg and hasAnyPlacementArg traversal matcher for CXXNewExpr
Summary: Adds new traversal matchers called `hasPlacementArg` and `hasAnyPlacementArg` that matches on arguments to `placement new` operators. Reviewers: aaron.ballman Reviewed By: aaron.ballman Subscribers: merge_guards_bot, mehdi_amini, hiraditya, steven_wu, dexonsmith, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D73562
This commit is contained in:
parent
ce06d50756
commit
a156a0e28d
|
@ -16,16 +16,13 @@ namespace clang {
|
|||
namespace tidy {
|
||||
namespace cert {
|
||||
|
||||
AST_MATCHER(CXXNewExpr, isPlacementNew) {
|
||||
return Node.getNumPlacementArgs() > 0;
|
||||
}
|
||||
|
||||
void DefaultOperatorNewAlignmentCheck::registerMatchers(MatchFinder *Finder) {
|
||||
// Check not applicable in C++17 (or newer).
|
||||
if (getLangOpts().CPlusPlus17)
|
||||
return;
|
||||
|
||||
Finder->addMatcher(cxxNewExpr(unless(isPlacementNew())).bind("new"), this);
|
||||
Finder->addMatcher(
|
||||
cxxNewExpr(unless(hasAnyPlacementArg(anything()))).bind("new"), this);
|
||||
}
|
||||
|
||||
void DefaultOperatorNewAlignmentCheck::check(
|
||||
|
|
|
@ -84,6 +84,8 @@ void MakeSmartPtrCheck::registerMatchers(ast_matchers::MatchFinder *Finder) {
|
|||
auto CanCallCtor = unless(has(ignoringImpCasts(
|
||||
cxxConstructExpr(hasDeclaration(decl(unless(isPublic())))))));
|
||||
|
||||
auto IsPlacement = hasAnyPlacementArg(anything());
|
||||
|
||||
Finder->addMatcher(
|
||||
cxxBindTemporaryExpr(has(ignoringParenImpCasts(
|
||||
cxxConstructExpr(
|
||||
|
@ -91,7 +93,7 @@ void MakeSmartPtrCheck::registerMatchers(ast_matchers::MatchFinder *Finder) {
|
|||
hasArgument(0,
|
||||
cxxNewExpr(hasType(pointsTo(qualType(hasCanonicalType(
|
||||
equalsBoundNode(PointerType))))),
|
||||
CanCallCtor)
|
||||
CanCallCtor, unless(IsPlacement))
|
||||
.bind(NewExpression)),
|
||||
unless(isInTemplateInstantiation()))
|
||||
.bind(ConstructorCall)))),
|
||||
|
@ -101,7 +103,9 @@ void MakeSmartPtrCheck::registerMatchers(ast_matchers::MatchFinder *Finder) {
|
|||
cxxMemberCallExpr(
|
||||
thisPointerType(getSmartPointerTypeMatcher()),
|
||||
callee(cxxMethodDecl(hasName("reset"))),
|
||||
hasArgument(0, cxxNewExpr(CanCallCtor).bind(NewExpression)),
|
||||
hasArgument(
|
||||
0,
|
||||
cxxNewExpr(CanCallCtor, unless(IsPlacement)).bind(NewExpression)),
|
||||
unless(isInTemplateInstantiation()))
|
||||
.bind(ResetCall),
|
||||
this);
|
||||
|
@ -119,8 +123,6 @@ void MakeSmartPtrCheck::check(const MatchFinder::MatchResult &Result) {
|
|||
const auto *Type = Result.Nodes.getNodeAs<QualType>(PointerType);
|
||||
const auto *New = Result.Nodes.getNodeAs<CXXNewExpr>(NewExpression);
|
||||
|
||||
if (New->getNumPlacementArgs() != 0)
|
||||
return;
|
||||
// Skip when this is a new-expression with `auto`, e.g. new auto(1)
|
||||
if (New->getType()->getPointeeType()->getContainedAutoType())
|
||||
return;
|
||||
|
|
|
@ -5311,6 +5311,16 @@ Example matches A() in the last line
|
|||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXNewExpr.html">CXXNewExpr</a>></td><td class="name" onclick="toggle('hasAnyPlacementArg0')"><a name="hasAnyPlacementArg0Anchor">hasAnyPlacementArg</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="hasAnyPlacementArg0"><pre>Matches any placement new expression arguments.
|
||||
|
||||
Given:
|
||||
MyClass *p1 = new (Storage) MyClass();
|
||||
cxxNewExpr(hasAnyPlacementArg(anything()))
|
||||
matches the expression 'new (Storage, 16) MyClass()'.
|
||||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXNewExpr.html">CXXNewExpr</a>></td><td class="name" onclick="toggle('hasArraySize0')"><a name="hasArraySize0Anchor">hasArraySize</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="hasArraySize0"><pre>Matches array new expressions with a given array size.
|
||||
|
||||
|
@ -5355,6 +5365,16 @@ Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Addr
|
|||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXNewExpr.html">CXXNewExpr</a>></td><td class="name" onclick="toggle('hasPlacementArg0')"><a name="hasPlacementArg0Anchor">hasPlacementArg</a></td><td>unsigned Index, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="hasPlacementArg0"><pre>Matches placement new expression arguments.
|
||||
|
||||
Given:
|
||||
MyClass *p1 = new (Storage, 16) MyClass();
|
||||
cxxNewExpr(hasPlacementArg(1, integerLiteral(equals(16))))
|
||||
matches the expression 'new (Storage, 16) MyClass()'.
|
||||
</pre></td></tr>
|
||||
|
||||
|
||||
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>></td><td class="name" onclick="toggle('hasMethod0')"><a name="hasMethod0Anchor">hasMethod</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>> InnerMatcher</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="hasMethod0"><pre>Matches the first method of a class or struct that satisfies InnerMatcher.
|
||||
|
||||
|
|
|
@ -6783,6 +6783,35 @@ AST_MATCHER(CXXNewExpr, isArray) {
|
|||
return Node.isArray();
|
||||
}
|
||||
|
||||
/// Matches placement new expression arguments.
|
||||
///
|
||||
/// Given:
|
||||
/// \code
|
||||
/// MyClass *p1 = new (Storage, 16) MyClass();
|
||||
/// \endcode
|
||||
/// cxxNewExpr(hasPlacementArg(1, integerLiteral(equals(16))))
|
||||
/// matches the expression 'new (Storage, 16) MyClass()'.
|
||||
AST_MATCHER_P2(CXXNewExpr, hasPlacementArg, unsigned, Index,
|
||||
internal::Matcher<Expr>, InnerMatcher) {
|
||||
return Node.getNumPlacementArgs() > Index &&
|
||||
InnerMatcher.matches(*Node.getPlacementArg(Index), Finder, Builder);
|
||||
}
|
||||
|
||||
/// Matches any placement new expression arguments.
|
||||
///
|
||||
/// Given:
|
||||
/// \code
|
||||
/// MyClass *p1 = new (Storage) MyClass();
|
||||
/// \endcode
|
||||
/// cxxNewExpr(hasAnyPlacementArg(anything()))
|
||||
/// matches the expression 'new (Storage, 16) MyClass()'.
|
||||
AST_MATCHER_P(CXXNewExpr, hasAnyPlacementArg, internal::Matcher<Expr>,
|
||||
InnerMatcher) {
|
||||
return llvm::any_of(Node.placement_arguments(), [&](const Expr *Arg) {
|
||||
return InnerMatcher.matches(*Arg, Finder, Builder);
|
||||
});
|
||||
}
|
||||
|
||||
/// Matches array new expressions with a given array size.
|
||||
///
|
||||
/// Given:
|
||||
|
|
|
@ -243,6 +243,7 @@ RegistryMaps::RegistryMaps() {
|
|||
REGISTER_MATCHER(hasAnyDeclaration);
|
||||
REGISTER_MATCHER(hasAnyName);
|
||||
REGISTER_MATCHER(hasAnyParameter);
|
||||
REGISTER_MATCHER(hasAnyPlacementArg);
|
||||
REGISTER_MATCHER(hasAnySelector);
|
||||
REGISTER_MATCHER(hasAnySubstatement);
|
||||
REGISTER_MATCHER(hasAnyTemplateArgument);
|
||||
|
@ -304,6 +305,7 @@ RegistryMaps::RegistryMaps() {
|
|||
REGISTER_MATCHER(hasReceiverType);
|
||||
REGISTER_MATCHER(hasReplacementType);
|
||||
REGISTER_MATCHER(hasReturnValue);
|
||||
REGISTER_MATCHER(hasPlacementArg);
|
||||
REGISTER_MATCHER(hasSelector);
|
||||
REGISTER_MATCHER(hasSingleDecl);
|
||||
REGISTER_MATCHER(hasSize);
|
||||
|
|
|
@ -3124,5 +3124,45 @@ TEST(ClassTemplateSpecializationDecl, HasSpecializedTemplate) {
|
|||
EXPECT_TRUE(notMatches("template<typename T> class A {};", Matcher));
|
||||
}
|
||||
|
||||
TEST(CXXNewExpr, Array) {
|
||||
StatementMatcher NewArray = cxxNewExpr(isArray());
|
||||
|
||||
EXPECT_TRUE(matches("void foo() { int *Ptr = new int[10]; }", NewArray));
|
||||
EXPECT_TRUE(notMatches("void foo() { int *Ptr = new int; }", NewArray));
|
||||
|
||||
StatementMatcher NewArraySize10 =
|
||||
cxxNewExpr(hasArraySize(integerLiteral(equals(10))));
|
||||
EXPECT_TRUE(
|
||||
matches("void foo() { int *Ptr = new int[10]; }", NewArraySize10));
|
||||
EXPECT_TRUE(
|
||||
notMatches("void foo() { int *Ptr = new int[20]; }", NewArraySize10));
|
||||
}
|
||||
|
||||
TEST(CXXNewExpr, PlacementArgs) {
|
||||
StatementMatcher IsPlacementNew = cxxNewExpr(hasAnyPlacementArg(anything()));
|
||||
|
||||
EXPECT_TRUE(matches(R"(
|
||||
void* operator new(decltype(sizeof(void*)), void*);
|
||||
int *foo(void* Storage) {
|
||||
return new (Storage) int;
|
||||
})",
|
||||
IsPlacementNew));
|
||||
|
||||
EXPECT_TRUE(matches(R"(
|
||||
void* operator new(decltype(sizeof(void*)), void*, unsigned);
|
||||
int *foo(void* Storage) {
|
||||
return new (Storage, 16) int;
|
||||
})",
|
||||
cxxNewExpr(hasPlacementArg(
|
||||
1, ignoringImpCasts(integerLiteral(equals(16)))))));
|
||||
|
||||
EXPECT_TRUE(notMatches(R"(
|
||||
void* operator new(decltype(sizeof(void*)), void*);
|
||||
int *foo(void* Storage) {
|
||||
return new int;
|
||||
})",
|
||||
IsPlacementNew));
|
||||
}
|
||||
|
||||
} // namespace ast_matchers
|
||||
} // namespace clang
|
||||
|
|
Loading…
Reference in New Issue