================
@@ -0,0 +1,160 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "UseBracedInitializationCheck.h"
+#include "../utils/LexerUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::misc {
+
+namespace {
+
+AST_MATCHER_P(VarDecl, hasInitStyle, VarDecl::InitializationStyle, Style) {
+  return Node.getInitStyle() == Style;
+}
+
+AST_MATCHER(Type, isDependentType) { return Node.isDependentType(); }
+
+AST_MATCHER(CXXConstructExpr, noMacroParens) {
+  const SourceRange Range = Node.getParenOrBraceRange();
+  return Range.isValid() && !Range.getBegin().isMacroID() &&
+         !Range.getEnd().isMacroID();
+}
+
+AST_MATCHER(Expr, isCXXParenListInitExpr) {
+  return isa<CXXParenListInitExpr>(Node);
+}
+
+/// Matches CXXConstructExpr whose target class has any constructor
+/// taking 'std::initializer_list'. When such a constructor exists, braced
+/// initialization may call it instead of the intended constructor.
+AST_MATCHER(CXXConstructExpr, constructsTypeWithInitListCtor) {
+  const CXXRecordDecl *RD = Node.getConstructor()->getParent();
+  if (!RD || !RD->hasDefinition())
+    return false;
+  return llvm::any_of(RD->ctors(), [](const CXXConstructorDecl *Ctor) {
+    if (Ctor->getNumParams() == 0)
+      return false;
+    const QualType FirstParam =
+        Ctor->getParamDecl(0)->getType().getNonReferenceType();
+    const auto *Record = FirstParam->getAsCXXRecordDecl();
+    if (!Record || !Record->getDeclName().isIdentifier() ||
+        Record->getName() != "initializer_list" || !Record->isInStdNamespace())
+      return false;
+    // [dcl.init.list] p2: all other params must have defaults.
+    for (unsigned I = 1; I < Ctor->getNumParams(); ++I)
+      if (!Ctor->getParamDecl(I)->hasDefaultArg())
+        return false;
+    return true;
+  });
+}
+
+} // namespace
+
+void UseBracedInitializationCheck::registerMatchers(MatchFinder *Finder) {
+  auto GoodCtor = allOf(
+      noMacroParens(), unless(constructsTypeWithInitListCtor()),
+      unless(isInTemplateInstantiation()), unless(isListInitialization()));
+  auto GoodCtorExpr = cxxConstructExpr(GoodCtor).bind("ctor");
+  auto GoodVar =
+      allOf(unless(hasType(isDependentType())), unless(hasType(autoType())));
+
+  // Variable declarations: Simple w(1), Takes t({1, 2})
+  Finder->addMatcher(varDecl(hasInitStyle(VarDecl::CallInit),
+                             hasInitializer(ignoringImplicit(GoodCtorExpr)),
+                             GoodVar),
+                     this);
+
+  // Scalar direct-init: int x(42), double d(3.14)
+  Finder->addMatcher(
+      varDecl(hasInitStyle(VarDecl::CallInit),
+              hasInitializer(unless(ignoringImplicit(cxxConstructExpr()))),
+              GoodVar)
+          .bind("scalar"),
+      this);
+
+  Finder->addMatcher(cxxFunctionalCastExpr(has(GoodCtorExpr)), this);
+  Finder->addMatcher(cxxTemporaryObjectExpr(GoodCtor).bind("ctor"), this);
+  Finder->addMatcher(cxxNewExpr(has(GoodCtorExpr)), this);
----------------
vbvictor wrote:

Probably worth to make an option for each of this matcher.. 
C++ core guildelines only suggest it for variable declarations:

```
Flag uses of () initialization syntax that are actually declarations. (Many 
compilers should warn on this already.)
```

https://github.com/llvm/llvm-project/pull/184009
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to