diff --git a/clang-tools-extra/clang-tidy/cert/DefaultOperatorNewAlignmentCheck.cpp b/clang-tools-extra/clang-tidy/cert/DefaultOperatorNewAlignmentCheck.cpp --- a/clang-tools-extra/clang-tidy/cert/DefaultOperatorNewAlignmentCheck.cpp +++ b/clang-tools-extra/clang-tidy/cert/DefaultOperatorNewAlignmentCheck.cpp @@ -16,16 +16,13 @@ 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( diff --git a/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp b/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp --- a/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/MakeSmartPtrCheck.cpp @@ -84,6 +84,8 @@ auto CanCallCtor = unless(has(ignoringImpCasts( cxxConstructExpr(hasDeclaration(decl(unless(isPublic()))))))); + auto IsPlacement = hasAnyPlacementArg(anything()); + Finder->addMatcher( cxxBindTemporaryExpr(has(ignoringParenImpCasts( cxxConstructExpr( @@ -91,7 +93,7 @@ hasArgument(0, cxxNewExpr(hasType(pointsTo(qualType(hasCanonicalType( equalsBoundNode(PointerType))))), - CanCallCtor) + CanCallCtor, unless(IsPlacement)) .bind(NewExpression)), unless(isInTemplateInstantiation())) .bind(ConstructorCall)))), @@ -101,7 +103,9 @@ 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 @@ const auto *Type = Result.Nodes.getNodeAs(PointerType); const auto *New = Result.Nodes.getNodeAs(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; diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html --- a/clang/docs/LibASTMatchersReference.html +++ b/clang/docs/LibASTMatchersReference.html @@ -5311,6 +5311,16 @@ +Matcher<CXXNewExpr>hasAnyPlacementArgMatcher<Expr> InnerMatcher +
Matches any placement new expression arguments.
+
+Given:
+  MyClass *p1 = new (Storage) MyClass();
+cxxNewExpr(hasAnyPlacementArg(anything()))
+  matches the expression 'new (Storage, 16) MyClass()'.
+
+ + Matcher<CXXNewExpr>hasArraySizeMatcher<Expr> InnerMatcher
Matches array new expressions with a given array size.
 
@@ -5355,6 +5365,16 @@
 
+Matcher<CXXNewExpr>hasPlacementArgunsigned Index, Matcher<Expr> InnerMatcher +
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()'.
+
+ + Matcher<CXXRecordDecl>hasMethodMatcher<CXXMethodDecl> InnerMatcher
Matches the first method of a class or struct that satisfies InnerMatcher.
 
diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -6783,6 +6783,35 @@
   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, 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,
+              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:
diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
--- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -243,6 +243,7 @@
   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 @@
   REGISTER_MATCHER(hasReceiverType);
   REGISTER_MATCHER(hasReplacementType);
   REGISTER_MATCHER(hasReturnValue);
+  REGISTER_MATCHER(hasPlacementArg);
   REGISTER_MATCHER(hasSelector);
   REGISTER_MATCHER(hasSingleDecl);
   REGISTER_MATCHER(hasSize);
diff --git a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
--- a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -3124,5 +3124,45 @@
   EXPECT_TRUE(notMatches("template 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