[clang-tools-extra] [clang-tidy] Add `modernize-use-uniform-initializer` check (PR #91124)
via cfe-commits
cfe-commits at lists.llvm.org
Sun Sep 8 13:24:10 PDT 2024
https://github.com/AMS21 updated https://github.com/llvm/llvm-project/pull/91124
>From 84c8e546c0826ddcf9c580b9368541670ed05068 Mon Sep 17 00:00:00 2001
From: AMS21 <AMS21.github at gmail.com>
Date: Tue, 16 Apr 2024 08:56:13 +0200
Subject: [PATCH] [clang-tidy] Add `modernize-use-uniform-initializer` check
Finds usage of C-Style initialization that can be rewritten with
C++-11 uniform initializers.
---
.../clang-tidy/modernize/CMakeLists.txt | 1 +
.../modernize/ModernizeTidyModule.cpp | 3 +
.../modernize/UseUniformInitializerCheck.cpp | 320 ++++++++++++++++++
.../modernize/UseUniformInitializerCheck.h | 37 ++
.../clang-tidy/utils/LexerUtils.cpp | 23 ++
.../clang-tidy/utils/LexerUtils.h | 4 +
clang-tools-extra/docs/ReleaseNotes.rst | 6 +
.../docs/clang-tidy/checks/list.rst | 1 +
.../modernize/use-uniform-initializer.rst | 34 ++
.../modernize/use-uniform-initializer.cpp | 174 ++++++++++
10 files changed, 603 insertions(+)
create mode 100644 clang-tools-extra/clang-tidy/modernize/UseUniformInitializerCheck.cpp
create mode 100644 clang-tools-extra/clang-tidy/modernize/UseUniformInitializerCheck.h
create mode 100644 clang-tools-extra/docs/clang-tidy/checks/modernize/use-uniform-initializer.rst
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/modernize/use-uniform-initializer.cpp
diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
index 4f68c487cac9d4..4ca56cb26bd433 100644
--- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -48,6 +48,7 @@ add_clang_library(clangTidyModernizeModule
UseTrailingReturnTypeCheck.cpp
UseTransparentFunctorsCheck.cpp
UseUncaughtExceptionsCheck.cpp
+ UseUniformInitializerCheck.cpp
UseUsingCheck.cpp
LINK_LIBS
diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
index 18607593320635..35fb2bdf042ceb 100644
--- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -49,6 +49,7 @@
#include "UseTrailingReturnTypeCheck.h"
#include "UseTransparentFunctorsCheck.h"
#include "UseUncaughtExceptionsCheck.h"
+#include "UseUniformInitializerCheck.h"
#include "UseUsingCheck.h"
using namespace clang::ast_matchers;
@@ -121,6 +122,8 @@ class ModernizeModule : public ClangTidyModule {
"modernize-use-transparent-functors");
CheckFactories.registerCheck<UseUncaughtExceptionsCheck>(
"modernize-use-uncaught-exceptions");
+ CheckFactories.registerCheck<UseUniformInitializerCheck>(
+ "modernize-use-uniform-initializer");
CheckFactories.registerCheck<UseUsingCheck>("modernize-use-using");
}
};
diff --git a/clang-tools-extra/clang-tidy/modernize/UseUniformInitializerCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseUniformInitializerCheck.cpp
new file mode 100644
index 00000000000000..204a42d8c81895
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseUniformInitializerCheck.cpp
@@ -0,0 +1,320 @@
+//===--- UseUniformInitializerCheck.cpp - clang-tidy ----------------------===//
+//
+// 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 "UseUniformInitializerCheck.h"
+#include "../utils/LexerUtils.h"
+#include "clang/Tooling/FixIt.h"
+
+AST_MATCHER(clang::VarDecl, isVarOldStyleInitializer) {
+ // If it doesn't have any initializer the initializer style is not defined.
+ if (!Node.hasInit())
+ return false;
+
+ const clang::VarDecl::InitializationStyle InitStyle = Node.getInitStyle();
+
+ return InitStyle == clang::VarDecl::InitializationStyle::CInit ||
+ InitStyle == clang::VarDecl::InitializationStyle::CallInit;
+}
+
+AST_MATCHER(clang::FieldDecl, isFieldOldStyleInitializer) {
+ // If it doesn't have any initializer the initializer style is not defined.
+ if (!Node.hasInClassInitializer() || Node.getInClassInitializer() == nullptr)
+ return false;
+
+ const clang::InClassInitStyle InitStyle = Node.getInClassInitStyle();
+
+ return InitStyle == clang::InClassInitStyle::ICIS_CopyInit;
+}
+
+AST_MATCHER(clang::CXXCtorInitializer, isCStyleInitializer) {
+ const clang::Expr *Init = Node.getInit();
+ if (Init == nullptr)
+ return false;
+
+ return !llvm::isa<clang::InitListExpr>(Init);
+}
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::modernize {
+
+namespace {
+
+constexpr const StringRef VarDeclID = "VarDecl";
+constexpr const StringRef FieldDeclId = "FieldDecl";
+constexpr const StringRef CtorInitID = "CtorInit";
+
+constexpr const StringRef CStyleWarningMessage =
+ "Use uniform initializer instead of C-style initializer";
+
+constexpr StringRef
+getInitializerStyleName(VarDecl::InitializationStyle InitStyle) {
+ switch (InitStyle) {
+ case VarDecl::InitializationStyle::CInit:
+ return "C";
+
+ case VarDecl::InitializationStyle::CallInit:
+ return "call";
+
+ default:
+ llvm_unreachable("Invalid initializer style!");
+ }
+}
+
+SourceRange getParenLocationsForCallInit(const Expr *InitExpr,
+ const SourceManager &SM,
+ const LangOptions &LangOpts) {
+ // We need to handle 'CXXConstructExpr' differently
+ if (isa<CXXConstructExpr>(InitExpr))
+ return cast<CXXConstructExpr>(InitExpr)->getParenOrBraceRange();
+
+ // If the init expression itself is a 'ParenExpr' then
+ // 'InitExpr->getBeginLoc()' will already point to a '(' which is not the
+ // opening paren of the 'CallInit' expression. So it that case we need to
+ // start one character before that.
+ const bool NeedOffsetForOpenParen = [&]() {
+ if (!isa<ParenExpr>(InitExpr))
+ return false;
+
+ const clang::StringRef CharBeforeParenExpr =
+ Lexer::getSourceText(CharSourceRange::getCharRange(
+ InitExpr->getBeginLoc().getLocWithOffset(-1),
+ InitExpr->getBeginLoc()),
+ SM, LangOpts);
+
+ return llvm::isSpace(CharBeforeParenExpr[0]);
+ }();
+
+ const SourceLocation OpenParenLoc = utils::lexer::findPreviousTokenKind(
+ NeedOffsetForOpenParen ? InitExpr->getBeginLoc().getLocWithOffset(-1)
+ : InitExpr->getBeginLoc(),
+ SM, LangOpts, tok::l_paren);
+ const SourceLocation CloseParenLoc = utils::lexer::findNextTokenKind(
+ InitExpr->getEndLoc(), SM, LangOpts, tok::r_paren);
+
+ return {OpenParenLoc, CloseParenLoc};
+}
+
+const BuiltinType *getBuiltinType(const Expr *Expr) {
+ assert(Expr);
+ return Expr->getType().getCanonicalType().getTypePtr()->getAs<BuiltinType>();
+}
+
+bool castRequiresStaticCast(const ImplicitCastExpr *CastExpr) {
+ const auto *FromExpr = CastExpr->getSubExpr();
+
+ if (CastExpr->isInstantiationDependent() ||
+ FromExpr->isInstantiationDependent())
+ return false;
+ if (getBuiltinType(CastExpr) == getBuiltinType(FromExpr))
+ return false;
+
+ switch (CastExpr->getCastKind()) {
+ case CastKind::CK_BaseToDerived:
+ case CastKind::CK_DerivedToBaseMemberPointer:
+ case CastKind::CK_IntegralCast:
+ case CastKind::CK_FloatingToIntegral:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+std::string buildReplacementString(const Expr *InitExpr,
+ const ASTContext &Context) {
+ // TODO: This function does not correctly handle the case where you have in
+ // 'ImplicitCastExpr' as an argument for a 'CXXConstructExpr'.
+ // In that case the generated code will not compile due to missing explicit
+ // cast of the sub expression.
+
+ const SourceManager &SM = Context.getSourceManager();
+ const LangOptions &LangOpts = Context.getLangOpts();
+
+ const StringRef InitExprStr = [&]() {
+ if (isa<CXXConstructExpr>(InitExpr)) {
+ const auto *ConstructExpr = llvm::cast<CXXConstructExpr>(InitExpr);
+
+ const SourceRange ParenRange = ConstructExpr->getParenOrBraceRange();
+ if (ParenRange.isValid())
+ return Lexer::getSourceText(
+ CharSourceRange::getCharRange(
+ ParenRange.getBegin().getLocWithOffset(1),
+ ParenRange.getEnd()),
+ SM, LangOpts)
+ .trim();
+
+ // In case the ParenRange is invalid we use Begin/EndLoc
+ const SourceLocation BeginLocation = ConstructExpr->getBeginLoc();
+ const SourceLocation EndLocation = ConstructExpr->getEndLoc();
+
+ return Lexer::getSourceText(
+ CharSourceRange::getCharRange(BeginLocation,
+ EndLocation.getLocWithOffset(1)),
+ SM, LangOpts)
+ .trim();
+ }
+
+ return tooling::fixit::getText(*InitExpr, Context);
+ }();
+
+ // For some 'ImplicitCastExpr' we need to add an extra 'static_cast<T>' around
+ // the expression since implicit conversions are not allowed with uniform
+ // initializer and otherwise will lead to compile errors
+ if (isa<ImplicitCastExpr>(InitExpr)) {
+ const auto *CastExpr = llvm::cast<ImplicitCastExpr>(InitExpr);
+
+ if (castRequiresStaticCast(CastExpr)) {
+ const QualType Type = CastExpr->getType().getUnqualifiedType();
+
+ return ("{static_cast<" + Type.getAsString() + ">(" + InitExprStr + ")}")
+ .str();
+ }
+ }
+
+ // Otherwise just add the braces around the expression
+ return ("{" + InitExprStr + "}").str();
+}
+
+} // namespace
+
+void UseUniformInitializerCheck::registerMatchers(MatchFinder *Finder) {
+ Finder->addMatcher(varDecl(isVarOldStyleInitializer(), unless(parmVarDecl()))
+ .bind(VarDeclID),
+ this);
+ Finder->addMatcher(fieldDecl(isFieldOldStyleInitializer()).bind(FieldDeclId),
+ this);
+ Finder->addMatcher(cxxCtorInitializer(isCStyleInitializer()).bind(CtorInitID),
+ this);
+}
+
+void UseUniformInitializerCheck::check(const MatchFinder::MatchResult &Result) {
+ const SourceManager &SM = *Result.SourceManager;
+ const ASTContext &Context = *Result.Context;
+ const LangOptions &LangOpts = Context.getLangOpts();
+
+ const auto *VDecl = Result.Nodes.getNodeAs<VarDecl>(VarDeclID);
+ const auto *FDecl = Result.Nodes.getNodeAs<FieldDecl>(FieldDeclId);
+ const auto *CtorInit = Result.Nodes.getNodeAs<CXXCtorInitializer>(CtorInitID);
+
+ // Handle variable declarations
+ if (VDecl != nullptr) {
+ const auto *InitExpr = VDecl->getInit();
+ assert(InitExpr);
+
+ // If the expression is an 'ExprWithCleanups' just get the subexpression
+ if (isa<ExprWithCleanups>(InitExpr))
+ InitExpr = llvm::cast<ExprWithCleanups>(InitExpr)->getSubExpr();
+
+ const VarDecl::InitializationStyle InitStyle = VDecl->getInitStyle();
+
+ // Check for the special case that a default constructor with no arguments
+ // is used
+ // Example: struct A{}; A a;
+ const auto *ConstructorExpr = dyn_cast_or_null<CXXConstructExpr>(InitExpr);
+ if (ConstructorExpr && ConstructorExpr->getNumArgs() == 0)
+ return;
+
+ // Ignore declarations inside a 'CXXForRangeStmt'
+ if (VDecl->isCXXForRangeDecl())
+ return;
+
+ if (InitStyle == VarDecl::InitializationStyle::CInit) {
+ const SourceLocation EqualLoc = utils::lexer::findPreviousTokenKind(
+ InitExpr->getBeginLoc(), SM, LangOpts, tok::equal);
+ if (!EqualLoc.isValid())
+ return;
+
+ auto Diag =
+ diag(EqualLoc,
+ "Use uniform initializer instead of %0-style initializer")
+ << getInitializerStyleName(InitStyle);
+
+ // If we have a C-style initializer with an 'InitListExpr', we only need
+ // to remove the '='
+ // For example: 'int a = {0};'
+ if (isa<InitListExpr>(InitExpr))
+ Diag << FixItHint::CreateRemoval(EqualLoc);
+ else {
+ // Otherwise with a normal c-style initializer we also need to add '{'
+ // and '}'
+ // For example: 'int a = 0;'
+ const std::string ReplacementText =
+ buildReplacementString(InitExpr, Context);
+
+ Diag << FixItHint::CreateReplacement(
+ SourceRange{EqualLoc, InitExpr->getEndLoc()}, ReplacementText);
+ }
+ } else if (InitStyle == VarDecl::InitializationStyle::CallInit) {
+ const SourceRange ParenRange =
+ getParenLocationsForCallInit(InitExpr, SM, LangOpts);
+ if (ParenRange.isInvalid())
+ return;
+
+ const std::string ReplacementString =
+ buildReplacementString(InitExpr, Context);
+
+ diag(ParenRange.getBegin(),
+ "Use uniform initializer instead of %0-style initializer")
+ << getInitializerStyleName(InitStyle)
+ << FixItHint::CreateReplacement(ParenRange, ReplacementString);
+ } else {
+ llvm_unreachable("Invalid initializer style!");
+ }
+ }
+ // Handle field declarations
+ else if (FDecl != nullptr) {
+ const auto *InitExpr = FDecl->getInClassInitializer();
+ assert(InitExpr);
+
+ const SourceLocation EqualLoc = utils::lexer::findPreviousTokenKind(
+ InitExpr->getBeginLoc(), SM, LangOpts, tok::equal);
+ if (!EqualLoc.isValid())
+ return;
+
+ if (isa<InitListExpr>(InitExpr))
+ // If we have a C-style initializer with an 'InitListExpr', we only need
+ // to remove the '='
+ diag(EqualLoc, CStyleWarningMessage)
+ << FixItHint::CreateRemoval(EqualLoc);
+ else {
+ // Otherwise with a normal c-style initializer we also need to add '{' and
+ // '}' and rewrite the initializer
+ const StringRef InitExprStr = tooling::fixit::getText(*InitExpr, Context);
+
+ const std::string ReplacementText = ("{" + InitExprStr + "}").str();
+
+ diag(EqualLoc, CStyleWarningMessage) << FixItHint::CreateReplacement(
+ SourceRange{EqualLoc, InitExpr->getEndLoc()}, ReplacementText);
+ }
+ }
+ // Otherwise must be a CXXCtorInitializer
+ else {
+ assert(CtorInit != nullptr);
+
+ const auto *InitExpr = CtorInit->getInit();
+ assert(InitExpr);
+
+ const SourceLocation LParenLoc = CtorInit->getLParenLoc();
+ const SourceLocation RParenLoc = CtorInit->getRParenLoc();
+
+ if (!LParenLoc.isValid() || !RParenLoc.isValid())
+ return;
+
+ if (LParenLoc == RParenLoc)
+ return;
+
+ const std::string ReplacementString =
+ buildReplacementString(InitExpr, Context);
+
+ diag(LParenLoc, CStyleWarningMessage) << FixItHint::CreateReplacement(
+ SourceRange{LParenLoc, RParenLoc}, ReplacementString);
+ }
+}
+
+} // namespace clang::tidy::modernize
diff --git a/clang-tools-extra/clang-tidy/modernize/UseUniformInitializerCheck.h b/clang-tools-extra/clang-tidy/modernize/UseUniformInitializerCheck.h
new file mode 100644
index 00000000000000..8263c8c3d759fc
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/modernize/UseUniformInitializerCheck.h
@@ -0,0 +1,37 @@
+//===--- UseUniformInitializerCheck.h - clang-tidy --------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USEUNIFORMINITIALIZERCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USEUNIFORMINITIALIZERCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::modernize {
+
+/// Finds C-Style initializers and converts them to uniform initializers.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/modernize/use-uniform-initializer.html
+class UseUniformInitializerCheck : public ClangTidyCheck {
+public:
+ UseUniformInitializerCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+ return LangOpts.CPlusPlus11;
+ }
+ std::optional<TraversalKind> getCheckTraversalKind() const override {
+ return TK_IgnoreUnlessSpelledInSource;
+ }
+
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace clang::tidy::modernize
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USEUNIFORMINITIALIZERCHECK_H
diff --git a/clang-tools-extra/clang-tidy/utils/LexerUtils.cpp b/clang-tools-extra/clang-tidy/utils/LexerUtils.cpp
index df2b0bef576ca3..88eb25e3828314 100644
--- a/clang-tools-extra/clang-tidy/utils/LexerUtils.cpp
+++ b/clang-tools-extra/clang-tidy/utils/LexerUtils.cpp
@@ -84,6 +84,29 @@ SourceLocation findNextTerminator(SourceLocation Start, const SourceManager &SM,
return findNextAnyTokenKind(Start, SM, LangOpts, tok::comma, tok::semi);
}
+SourceLocation findNextTokenKind(SourceLocation Start, const SourceManager &SM,
+ const LangOptions &LangOpts,
+ tok::TokenKind TK) {
+ while (true) {
+ std::optional<Token> CurrentToken =
+ Lexer::findNextToken(Start, SM, LangOpts);
+
+ if (!CurrentToken)
+ return {};
+
+ Token PotentialMatch = *CurrentToken;
+ if (PotentialMatch.is(TK))
+ return PotentialMatch.getLocation();
+
+ // If we reach the end of the file, and eof is not the target token, we stop
+ // the loop, otherwise we will get infinite loop (findNextToken will return
+ // eof on eof).
+ if (PotentialMatch.is(tok::eof))
+ return {};
+ Start = PotentialMatch.getLastLoc();
+ }
+}
+
std::optional<Token>
findNextTokenIncludingComments(SourceLocation Start, const SourceManager &SM,
const LangOptions &LangOpts) {
diff --git a/clang-tools-extra/clang-tidy/utils/LexerUtils.h b/clang-tools-extra/clang-tidy/utils/LexerUtils.h
index ea9bd512b68b8f..66e6163008a207 100644
--- a/clang-tools-extra/clang-tidy/utils/LexerUtils.h
+++ b/clang-tools-extra/clang-tidy/utils/LexerUtils.h
@@ -89,6 +89,10 @@ SourceLocation findNextAnyTokenKind(SourceLocation Start,
}
}
+SourceLocation findNextTokenKind(SourceLocation Start, const SourceManager &SM,
+ const LangOptions &LangOpts,
+ tok::TokenKind TK);
+
std::optional<Token>
findNextTokenIncludingComments(SourceLocation Start, const SourceManager &SM,
const LangOptions &LangOpts);
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 8d028f8863cb7a..330a8b3017470e 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -98,6 +98,12 @@ Improvements to clang-tidy
New checks
^^^^^^^^^^
+- New :doc:`modernize-use-uniform-initializer
+ <clang-tidy/checks/modernize/use-uniform-initializer>` check.
+
+ Finds usage of C-Style initialization that can be rewritten with
+ C++-11 uniform initializers.
+
New check aliases
^^^^^^^^^^^^^^^^^
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index a931ebf025a10e..0367c95a774820 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -310,6 +310,7 @@ Clang-Tidy Checks
:doc:`modernize-use-trailing-return-type <modernize/use-trailing-return-type>`, "Yes"
:doc:`modernize-use-transparent-functors <modernize/use-transparent-functors>`, "Yes"
:doc:`modernize-use-uncaught-exceptions <modernize/use-uncaught-exceptions>`, "Yes"
+ :doc:`modernize-use-uniform-initializer <modernize/use-uniform-initializer>`, "Yes"
:doc:`modernize-use-using <modernize/use-using>`, "Yes"
:doc:`mpi-buffer-deref <mpi/buffer-deref>`, "Yes"
:doc:`mpi-type-mismatch <mpi/type-mismatch>`, "Yes"
diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-uniform-initializer.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-uniform-initializer.rst
new file mode 100644
index 00000000000000..eda11e060ed2c4
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-uniform-initializer.rst
@@ -0,0 +1,34 @@
+.. title:: clang-tidy - modernize-use-uniform-initializer
+
+modernize-use-uniform-initializer
+=================================
+
+Finds usage of C-Style initialization that can be rewritten with
+C++-11 uniform initializers.
+
+Example
+-------
+
+.. code-block:: c++
+
+ int foo = 21;
+ int bar(42);
+
+ struct Baz {
+ Baz() : x(3) {}
+
+ int x;
+ };
+
+transforms to:
+
+.. code-block:: c++
+
+ int foo{21};
+ int bar{42};
+
+ struct Baz {
+ Baz() : x{3} {}
+
+ int x;
+ };
diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-uniform-initializer.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-uniform-initializer.cpp
new file mode 100644
index 00000000000000..608af82065a935
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-uniform-initializer.cpp
@@ -0,0 +1,174 @@
+// RUN: %check_clang_tidy -std=c++11 %s modernize-use-uniform-initializer %t
+
+int cinit_0 = 0;
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: Use uniform initializer instead of C-style initializer [modernize-use-uniform-initializer]
+// CHECK-FIXES: int cinit_0 {0};
+
+int cinit_1=0;
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: Use uniform initializer instead of C-style initializer [modernize-use-uniform-initializer]
+// CHECK-FIXES: int cinit_1{0};
+
+int callinit_0(0);
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: Use uniform initializer instead of call-style initializer [modernize-use-uniform-initializer]
+// CHECK-FIXES: int callinit_0{0};
+
+int callinit_1 ( 0 );
+// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: Use uniform initializer instead of call-style initializer [modernize-use-uniform-initializer]
+// CHECK-FIXES: int callinit_1 {0};
+
+int callinit_2 ( ((3 + 1 + 4) + 1 + 5) );
+// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: Use uniform initializer instead of call-style initializer [modernize-use-uniform-initializer]
+// CHECK-FIXES: int callinit_2 {((3 + 1 + 4) + 1 + 5)};
+
+int callinit_3((9-2)+(6+5));
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: Use uniform initializer instead of call-style initializer [modernize-use-uniform-initializer]
+// CHECK-FIXES: int callinit_3{(9-2)+(6+5)};
+
+int callinit_4 ((3 * 5 + (8 - 9) ));
+// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: Use uniform initializer instead of call-style initializer [modernize-use-uniform-initializer]
+// CHECK-FIXES: int callinit_4 {(3 * 5 + (8 - 9) )};
+
+int callinit_5((7 + (-9)));
+// CHECK-MESSAGES: :[[@LINE-1]]:15: warning: Use uniform initializer instead of call-style initializer [modernize-use-uniform-initializer]
+// CHECK-FIXES: int callinit_5{(7 + (-9))};
+
+int mixed_0 = {0};
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: Use uniform initializer instead of C-style initializer [modernize-use-uniform-initializer]
+// CHECK-FIXES: int mixed_0 {0};
+
+int mixed_1={0};
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: Use uniform initializer instead of C-style initializer [modernize-use-uniform-initializer]
+// CHECK-FIXES: int mixed_1{0};
+
+int noinit;
+
+int correct_0{0};
+
+int correct_1 {0};
+
+struct CInitList_0 {
+ CInitList_0() : x(0) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: Use uniform initializer instead of C-style initializer [modernize-use-uniform-initializer]
+ // CHECK-FIXES: CInitList_0() : x{0} {}
+
+ int x;
+};
+
+struct CInitList_1 {
+ CInitList_1():x(0) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: Use uniform initializer instead of C-style initializer [modernize-use-uniform-initializer]
+ // CHECK-FIXES: CInitList_1():x{0} {}
+
+ int x;
+};
+
+struct CInitList_2 {
+ CInitList_2() : x ( 0 ) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: Use uniform initializer instead of C-style initializer [modernize-use-uniform-initializer]
+ // CHECK-FIXES: CInitList_2() : x {0} {}
+
+ int x;
+};
+
+struct Correct_0 {
+ Correct_0() : x{0} {}
+
+ int x;
+};
+
+struct Correct_1 {
+ Correct_1():x{0} {}
+
+ int x;
+};
+
+struct InClassInitializers {
+ int cinit_0 = 0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: Use uniform initializer instead of C-style initializer [modernize-use-uniform-initializer]
+ // CHECK-FIXES: int cinit_0 {0};
+
+ int cinit_1=0;
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: Use uniform initializer instead of C-style initializer [modernize-use-uniform-initializer]
+ // CHECK-FIXES: int cinit_1{0};
+
+ int mixed_0 = {0};
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: Use uniform initializer instead of C-style initializer [modernize-use-uniform-initializer]
+ // CHECK-FIXES: int mixed_0 {0};
+
+ int mixed_1={0};
+ // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: Use uniform initializer instead of C-style initializer [modernize-use-uniform-initializer]
+ // CHECK-FIXES: int mixed_1{0};
+
+ int noinit;
+
+ int correct_0 {0};
+
+ int correct_1{0};
+};
+
+// Defaulted function arguments cannot use the uniform initializer
+void f(int x = 0) {}
+
+struct A {
+ A() = default;
+ A(int) {}
+ A(int, int) {}
+};
+
+A a_0;
+A a_1{};
+A a_2(); // This is not a variable declaration it is actually a function definition (most vexing parse)
+A a_3{21};
+A a_4{ 21 };
+A a_5(42);
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: Use uniform initializer instead of call-style initializer [modernize-use-uniform-initializer]
+// CHECK-FIXES: A a_5{42};
+A a_6 ( 42 );
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: Use uniform initializer instead of call-style initializer [modernize-use-uniform-initializer]
+// CHECK-FIXES: A a_6 {42};
+A a_7{0, 1};
+A a_8{ 0, 1 };
+A a_9(0, 1);
+// CHECK-MESSAGES: :[[@LINE-1]]:6: warning: Use uniform initializer instead of call-style initializer [modernize-use-uniform-initializer]
+// CHECK-FIXES: A a_9{0, 1};
+A a_10( 1, 0 );
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: Use uniform initializer instead of call-style initializer [modernize-use-uniform-initializer]
+// CHECK-FIXES: A a_10{1, 0};
+A a_11(A(3));
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: Use uniform initializer instead of call-style initializer [modernize-use-uniform-initializer]
+// CHECK-FIXES: A a_11{A(3)};
+A a_12 ( A(3) );
+// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: Use uniform initializer instead of call-style initializer [modernize-use-uniform-initializer]
+// CHECK-FIXES: A a_12 {A(3)};
+
+struct Delegating {
+ Delegating() : Delegating(0) {}
+ // CHECK-MESSAGES: :[[@LINE-1]]:30: warning: Use uniform initializer instead of C-style initializer [modernize-use-uniform-initializer]
+ // CHECK-FIXES: Delegating() : Delegating{0} {}
+
+ Delegating(int) {}
+};
+
+int narrow_0 = 3.14;
+// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: Use uniform initializer instead of C-style initializer [modernize-use-uniform-initializer]
+// CHECK-FIXES: int narrow_0 {static_cast<int>(3.14)};
+int narrow_1=37.73;
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: Use uniform initializer instead of C-style initializer [modernize-use-uniform-initializer]
+// CHECK-FIXES: int narrow_1{static_cast<int>(37.73)};
+int narrow_2(0.9);
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: Use uniform initializer instead of call-style initializer [modernize-use-uniform-initializer]
+// CHECK-FIXES: int narrow_2{static_cast<int>(0.9)};
+int narrow_3 ( 5.666 );
+// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: Use uniform initializer instead of call-style initializer [modernize-use-uniform-initializer]
+// CHECK-FIXES: int narrow_3 {static_cast<int>(5.666)};
+
+template <class T> struct Vec {
+ T *begin();
+ T *end();
+};
+
+void for_each() {
+ Vec<int> v;
+ for (int& x : v)
+ {}
+}
More information about the cfe-commits
mailing list