Index: clang-tools-extra/trunk/clang-tidy/modernize/CMakeLists.txt =================================================================== --- clang-tools-extra/trunk/clang-tidy/modernize/CMakeLists.txt +++ clang-tools-extra/trunk/clang-tidy/modernize/CMakeLists.txt @@ -16,6 +16,7 @@ ShrinkToFitCheck.cpp UseAutoCheck.cpp UseBoolLiteralsCheck.cpp + UseDefaultMemberInitCheck.cpp UseEmplaceCheck.cpp UseEqualsDefaultCheck.cpp UseEqualsDeleteCheck.cpp Index: clang-tools-extra/trunk/clang-tidy/modernize/ModernizeTidyModule.cpp =================================================================== --- clang-tools-extra/trunk/clang-tidy/modernize/ModernizeTidyModule.cpp +++ clang-tools-extra/trunk/clang-tidy/modernize/ModernizeTidyModule.cpp @@ -22,6 +22,7 @@ #include "ShrinkToFitCheck.h" #include "UseAutoCheck.h" #include "UseBoolLiteralsCheck.h" +#include "UseDefaultMemberInitCheck.h" #include "UseEmplaceCheck.h" #include "UseEqualsDefaultCheck.h" #include "UseEqualsDeleteCheck.h" @@ -56,6 +57,8 @@ CheckFactories.registerCheck("modernize-use-auto"); CheckFactories.registerCheck( "modernize-use-bool-literals"); + CheckFactories.registerCheck( + "modernize-use-default-member-init"); CheckFactories.registerCheck("modernize-use-emplace"); CheckFactories.registerCheck("modernize-use-equals-default"); CheckFactories.registerCheck( Index: clang-tools-extra/trunk/clang-tidy/modernize/UseDefaultMemberInitCheck.h =================================================================== --- clang-tools-extra/trunk/clang-tidy/modernize/UseDefaultMemberInitCheck.h +++ clang-tools-extra/trunk/clang-tidy/modernize/UseDefaultMemberInitCheck.h @@ -0,0 +1,45 @@ +//===--- UseDefaultMemberInitCheck.h - clang-tidy----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_DEFAULT_MEMBER_INIT_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_DEFAULT_MEMBER_INIT_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace modernize { + +/// Convert a default constructor's member initializers into default member +/// initializers. Remove member initializers that are the same as a default +/// member initializer. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/modernize-use-default-member-init.html +class UseDefaultMemberInitCheck : public ClangTidyCheck { +public: + UseDefaultMemberInitCheck(StringRef Name, ClangTidyContext *Context); + void storeOptions(ClangTidyOptions::OptionMap &Opts) override; + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + +private: + void checkDefaultInit(const ast_matchers::MatchFinder::MatchResult &Result, + const CXXCtorInitializer *Init); + void checkExistingInit(const ast_matchers::MatchFinder::MatchResult &Result, + const CXXCtorInitializer *Init); + + const bool UseAssignment; +}; + +} // namespace modernize +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USE_DEFAULT_MEMBER_INIT_H Index: clang-tools-extra/trunk/clang-tidy/modernize/UseDefaultMemberInitCheck.cpp =================================================================== --- clang-tools-extra/trunk/clang-tidy/modernize/UseDefaultMemberInitCheck.cpp +++ clang-tools-extra/trunk/clang-tidy/modernize/UseDefaultMemberInitCheck.cpp @@ -0,0 +1,241 @@ +//===--- UseDefaultMemberInitCheck.cpp - clang-tidy------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "UseDefaultMemberInitCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Lex/Lexer.h" + +using namespace clang::ast_matchers; + +namespace clang { +namespace tidy { +namespace modernize { + +static StringRef getValueOfValueInit(const QualType InitType) { + switch (InitType->getScalarTypeKind()) { + case Type::STK_CPointer: + case Type::STK_BlockPointer: + case Type::STK_ObjCObjectPointer: + case Type::STK_MemberPointer: + return "nullptr"; + + case Type::STK_Bool: + return "false"; + + case Type::STK_Integral: + switch (InitType->getAs()->getKind()) { + case BuiltinType::Char_U: + case BuiltinType::UChar: + case BuiltinType::Char_S: + case BuiltinType::SChar: + return "'\\0'"; + case BuiltinType::WChar_U: + case BuiltinType::WChar_S: + return "L'\\0'"; + case BuiltinType::Char16: + return "u'\\0'"; + case BuiltinType::Char32: + return "U'\\0'"; + default: + return "0"; + } + + case Type::STK_Floating: + switch (InitType->getAs()->getKind()) { + case BuiltinType::Half: + case BuiltinType::Float: + return "0.0f"; + default: + return "0.0"; + } + + case Type::STK_FloatingComplex: + case Type::STK_IntegralComplex: + return getValueOfValueInit( + InitType->getAs()->getElementType()); + } + llvm_unreachable("Invalid scalar type kind"); +} + +static bool isZero(const Expr *E) { + switch (E->getStmtClass()) { + case Stmt::CXXNullPtrLiteralExprClass: + case Stmt::ImplicitValueInitExprClass: + return true; + case Stmt::InitListExprClass: + return cast(E)->getNumInits() == 0; + case Stmt::CharacterLiteralClass: + return !cast(E)->getValue(); + case Stmt::CXXBoolLiteralExprClass: + return !cast(E)->getValue(); + case Stmt::IntegerLiteralClass: + return !cast(E)->getValue(); + case Stmt::FloatingLiteralClass: { + llvm::APFloat Value = cast(E)->getValue(); + return Value.isZero() && !Value.isNegative(); + } + default: + return false; + } +} + +static const Expr *ignoreUnaryPlus(const Expr *E) { + auto *UnaryOp = dyn_cast(E); + if (UnaryOp && UnaryOp->getOpcode() == UO_Plus) + return UnaryOp->getSubExpr(); + return E; +} + +static const Expr *getInitializer(const Expr *E) { + auto *InitList = dyn_cast(E); + if (InitList && InitList->getNumInits() == 1) + return InitList->getInit(0); + return E; +} + +static bool sameValue(const Expr *E1, const Expr *E2) { + E1 = ignoreUnaryPlus(getInitializer(E1->IgnoreParenImpCasts())); + E2 = ignoreUnaryPlus(getInitializer(E2->IgnoreParenImpCasts())); + + if (isZero(E1) && isZero(E2)) + return true; + + if (E1->getStmtClass() != E2->getStmtClass()) + return false; + + switch (E1->getStmtClass()) { + case Stmt::UnaryOperatorClass: + return sameValue(cast(E1)->getSubExpr(), + cast(E2)->getSubExpr()); + case Stmt::CharacterLiteralClass: + return cast(E1)->getValue() == + cast(E2)->getValue(); + case Stmt::CXXBoolLiteralExprClass: + return cast(E1)->getValue() == + cast(E2)->getValue(); + case Stmt::IntegerLiteralClass: + return cast(E1)->getValue() == + cast(E2)->getValue(); + case Stmt::FloatingLiteralClass: + return cast(E1)->getValue().bitwiseIsEqual( + cast(E2)->getValue()); + case Stmt::StringLiteralClass: + return cast(E1)->getString() == + cast(E2)->getString(); + case Stmt::DeclRefExprClass: + return cast(E1)->getDecl() == cast(E2)->getDecl(); + default: + return false; + } +} + +UseDefaultMemberInitCheck::UseDefaultMemberInitCheck(StringRef Name, + ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + UseAssignment(Options.get("UseAssignment", 0) != 0) {} + +void UseDefaultMemberInitCheck::storeOptions( + ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "UseAssignment", UseAssignment); +} + +AST_MATCHER(FieldDecl, hasInClassInitializer) { + return Node.hasInClassInitializer(); +} + +void UseDefaultMemberInitCheck::registerMatchers(MatchFinder *Finder) { + if (!getLangOpts().CPlusPlus11) + return; + + auto Init = + anyOf(stringLiteral(), characterLiteral(), integerLiteral(), + unaryOperator(anyOf(hasOperatorName("+"), hasOperatorName("-")), + hasUnaryOperand(integerLiteral())), + floatLiteral(), + unaryOperator(anyOf(hasOperatorName("+"), hasOperatorName("-")), + hasUnaryOperand(floatLiteral())), + cxxBoolLiteral(), cxxNullPtrLiteralExpr(), implicitValueInitExpr(), + declRefExpr()); + + Finder->addMatcher( + cxxConstructorDecl( + isDefaultConstructor(), unless(isInstantiated()), + forEachConstructorInitializer(allOf( + forField(unless(anyOf(isBitField(), hasInClassInitializer()))), + cxxCtorInitializer(isWritten(), + withInitializer(ignoringImplicit(Init))) + .bind("default")))), + this); + + Finder->addMatcher( + cxxConstructorDecl( + unless(ast_matchers::isTemplateInstantiation()), + forEachConstructorInitializer( + allOf(forField(hasInClassInitializer()), + cxxCtorInitializer(isWritten(), + withInitializer(ignoringImplicit(Init))) + .bind("existing")))), + this); +} + +void UseDefaultMemberInitCheck::check(const MatchFinder::MatchResult &Result) { + if (const auto *Default = + Result.Nodes.getNodeAs("default")) + checkDefaultInit(Result, Default); + else if (const auto *Existing = + Result.Nodes.getNodeAs("existing")) + checkExistingInit(Result, Existing); + else + llvm_unreachable("Bad Callback. No node provided."); +} + +void UseDefaultMemberInitCheck::checkDefaultInit( + const MatchFinder::MatchResult &Result, const CXXCtorInitializer *Init) { + const FieldDecl *Field = Init->getMember(); + + SourceLocation FieldEnd = + Lexer::getLocForEndOfToken(Field->getSourceRange().getEnd(), 0, + *Result.SourceManager, getLangOpts()); + SourceLocation LParenEnd = Lexer::getLocForEndOfToken( + Init->getLParenLoc(), 0, *Result.SourceManager, getLangOpts()); + CharSourceRange InitRange = + CharSourceRange::getCharRange(LParenEnd, Init->getRParenLoc()); + + auto Diag = + diag(Field->getLocation(), "use default member initializer for %0") + << Field + << FixItHint::CreateInsertion(FieldEnd, UseAssignment ? " = " : "{") + << FixItHint::CreateInsertionFromRange(FieldEnd, InitRange); + + if (UseAssignment && isa(Init->getInit())) + Diag << FixItHint::CreateInsertion( + FieldEnd, getValueOfValueInit(Init->getInit()->getType())); + + if (!UseAssignment) + Diag << FixItHint::CreateInsertion(FieldEnd, "}"); + + Diag << FixItHint::CreateRemoval(Init->getSourceRange()); +} + +void UseDefaultMemberInitCheck::checkExistingInit( + const MatchFinder::MatchResult &Result, const CXXCtorInitializer *Init) { + const FieldDecl *Field = Init->getMember(); + + if (!sameValue(Field->getInClassInitializer(), Init->getInit())) + return; + + diag(Init->getSourceLocation(), "member initializer for %0 is redundant") + << Field + << FixItHint::CreateRemoval(Init->getSourceRange()); +} + +} // namespace modernize +} // namespace tidy +} // namespace clang Index: clang-tools-extra/trunk/docs/ReleaseNotes.rst =================================================================== --- clang-tools-extra/trunk/docs/ReleaseNotes.rst +++ clang-tools-extra/trunk/docs/ReleaseNotes.rst @@ -108,6 +108,12 @@ - The modernize-use-default check has been renamed to `modernize-use-equals-default `_. + +- New `modernize-use-default-member-init + `_ check + + Converts a default constructor's member initializers into default member initializers. + Removes member initializers that are the same as a default member initializer. - New `modernize-use-equals-delete `_ check Index: clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst =================================================================== --- clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst +++ clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst @@ -110,6 +110,7 @@ modernize-shrink-to-fit modernize-use-auto modernize-use-bool-literals + modernize-use-default-member-init modernize-use-emplace modernize-use-equals-default modernize-use-equals-delete Index: clang-tools-extra/trunk/docs/clang-tidy/checks/modernize-use-default-member-init.rst =================================================================== --- clang-tools-extra/trunk/docs/clang-tidy/checks/modernize-use-default-member-init.rst +++ clang-tools-extra/trunk/docs/clang-tidy/checks/modernize-use-default-member-init.rst @@ -0,0 +1,49 @@ +.. title:: clang-tidy - modernize-use-default-member-init + +modernize-use-default-member-init +================================= + +This check converts a default constructor's member initializers into the new +default member initializers in C++11. Other member initializers that match the +default member initializer are removed. This can reduce repeated code or allow +use of '= default'. + +.. code-block:: c++ + + struct A { + A() : i(5), j(10.0) {} + A(int i) : i(i), j(10.0) {} + int i; + double j; + }; + + // becomes + + struct A { + A() {} + A(int i) : i(i) {} + int i{5}; + double j{10.0}; + }; + +.. note:: + Only converts member initializers for built-in types, enums, and pointers. + The `readability-redundant-member-init` check will remove redundant member + initializers for classes. + +Options +------- + +.. option:: UseAssignment + + If this option is set to non-zero (default is `0`), the check will initialise + members with an assignment. For example: + +.. code-block:: c++ + + struct A { + A() {} + A(int i) : i(i) {} + int i = 5; + double j = 10.0; + }; Index: clang-tools-extra/trunk/test/clang-tidy/modernize-use-default-member-init-assignment.cpp =================================================================== --- clang-tools-extra/trunk/test/clang-tidy/modernize-use-default-member-init-assignment.cpp +++ clang-tools-extra/trunk/test/clang-tidy/modernize-use-default-member-init-assignment.cpp @@ -0,0 +1,184 @@ +// RUN: %check_clang_tidy %s modernize-use-default-member-init %t -- \ +// RUN: -config="{CheckOptions: [{key: modernize-use-default-member-init.UseAssignment, value: 1}]}" -- -std=c++11 + +struct S { +}; + +struct PositiveValueChar { + PositiveValueChar() : c0(), c1(), c2(), c3() {} + // CHECK-FIXES: PositiveValueChar() {} + const char c0; + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use default member initializer for 'c0' [modernize-use-default-member-init] + // CHECK-FIXES: const char c0 = '\0'; + wchar_t c1; + // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use default member initializer for 'c1' + // CHECK-FIXES: wchar_t c1 = L'\0'; + char16_t c2; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use default member initializer for 'c2' + // CHECK-FIXES: char16_t c2 = u'\0'; + char32_t c3; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use default member initializer for 'c3' + // CHECK-FIXES: char32_t c3 = U'\0'; +}; + +struct PositiveChar { + PositiveChar() : d('a') {} + // CHECK-FIXES: PositiveChar() {} + char d; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use default member initializer for 'd' + // CHECK-FIXES: char d = 'a'; +}; + +struct PositiveValueInt { + PositiveValueInt() : i() {} + // CHECK-FIXES: PositiveValueInt() {} + const int i; + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use default member initializer for 'i' + // CHECK-FIXES: const int i = 0; +}; + +struct PositiveInt { + PositiveInt() : j(1) {} + // CHECK-FIXES: PositiveInt() {} + int j; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use default member initializer for 'j' + // CHECK-FIXES: int j = 1; +}; + +struct PositiveUnaryMinusInt { + PositiveUnaryMinusInt() : j(-1) {} + // CHECK-FIXES: PositiveUnaryMinusInt() {} + int j; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use default member initializer for 'j' + // CHECK-FIXES: int j = -1; +}; + +struct PositiveUnaryPlusInt { + PositiveUnaryPlusInt() : j(+1) {} + // CHECK-FIXES: PositiveUnaryPlusInt() {} + int j; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use default member initializer for 'j' + // CHECK-FIXES: int j = +1; +}; + +struct PositiveValueComplexInt { + PositiveValueComplexInt() : i() {} + // CHECK-FIXES: PositiveValueComplexInt() {} + _Complex int i; + // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use default member initializer for 'i' + // CHECK-FIXES: _Complex int i = 0; +}; + +struct PositiveValueFloat { + PositiveValueFloat() : f() {} + // CHECK-FIXES: PositiveValueFloat() {} + float f; + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use default member initializer for 'f' + // CHECK-FIXES: float f = 0.0f; +}; + +struct PositiveValueDouble { + PositiveValueDouble() : d() {} + // CHECK-FIXES: PositiveValueDouble() {} + double d; + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use default member initializer for 'd' + // CHECK-FIXES: double d = 0.0; +}; + +struct PositiveDouble { + PositiveDouble() : f(2.5463e43) {} + // CHECK-FIXES: PositiveDouble() {} + double f; + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use default member initializer for 'f' + // CHECK-FIXES: double f = 2.5463e43; +}; + +struct PositiveValueComplexFloat { + PositiveValueComplexFloat() : f() {} + // CHECK-FIXES: PositiveValueComplexFloat() {} + _Complex float f; + // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: use default member initializer for 'f' + // CHECK-FIXES: _Complex float f = 0.0f; +}; + +struct PositiveValueComplexDouble { + PositiveValueComplexDouble() : f() {} + // CHECK-FIXES: PositiveValueComplexDouble() {} + _Complex double f; + // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use default member initializer for 'f' + // CHECK-FIXES: _Complex double f = 0.0; +}; + +struct PositiveUnaryMinusDouble { + PositiveUnaryMinusDouble() : f(-2.5463e43) {} + // CHECK-FIXES: PositiveUnaryMinusDouble() {} + double f; + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use default member initializer for 'f' + // CHECK-FIXES: double f = -2.5463e43; +}; + +struct PositiveUnaryPlusDouble { + PositiveUnaryPlusDouble() : f(+2.5463e43) {} + // CHECK-FIXES: PositiveUnaryPlusDouble() {} + double f; + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use default member initializer for 'f' + // CHECK-FIXES: double f = +2.5463e43; +}; + +struct PositiveValueBool { + PositiveValueBool() : b() {} + // CHECK-FIXES: PositiveValueBool() {} + bool b; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use default member initializer for 'b' + // CHECK-FIXES: bool b = false; +}; + +struct PositiveBool { + PositiveBool() : a(true) {} + // CHECK-FIXES: PositiveBool() {} + bool a; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use default member initializer for 'a' + // CHECK-FIXES: bool a = true; +}; + +struct PositiveValuePointer { + PositiveValuePointer() : p() {} + // CHECK-FIXES: PositiveValuePointer() {} + int *p; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use default member initializer for 'p' + // CHECK-FIXES: int *p = nullptr; +}; + +struct PositiveNullPointer { + PositiveNullPointer() : q(nullptr) {} + // CHECK-FIXES: PositiveNullPointer() {} + int *q; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use default member initializer for 'q' + // CHECK-FIXES: int *q = nullptr; +}; + +enum Enum { Foo }; +struct PositiveEnum { + PositiveEnum() : e(Foo) {} + // CHECK-FIXES: PositiveEnum() {} + Enum e; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use default member initializer for 'e' + // CHECK-FIXES: Enum e = Foo; +}; + +struct PositiveString { + PositiveString() : s("foo") {} + // CHECK-FIXES: PositiveString() {} + const char *s; + // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: use default member initializer for 's' + // CHECK-FIXES: const char *s = "foo"; +}; + +template +struct NegativeTemplate { + NegativeTemplate() : t() {} + T t; +}; + +NegativeTemplate nti; +NegativeTemplate ntd; Index: clang-tools-extra/trunk/test/clang-tidy/modernize-use-default-member-init.cpp =================================================================== --- clang-tools-extra/trunk/test/clang-tidy/modernize-use-default-member-init.cpp +++ clang-tools-extra/trunk/test/clang-tidy/modernize-use-default-member-init.cpp @@ -0,0 +1,376 @@ +// RUN: %check_clang_tidy %s modernize-use-default-member-init %t -- -- -std=c++11 + +struct S { +}; + +struct PositiveValueChar { + PositiveValueChar() : c0(), c1(), c2(), c3() {} + // CHECK-FIXES: PositiveValueChar() {} + const char c0; + // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use default member initializer for 'c0' [modernize-use-default-member-init] + // CHECK-FIXES: const char c0{}; + wchar_t c1; + // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: use default member initializer for 'c1' + // CHECK-FIXES: wchar_t c1{}; + char16_t c2; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use default member initializer for 'c2' + // CHECK-FIXES: char16_t c2{}; + char32_t c3; + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use default member initializer for 'c3' + // CHECK-FIXES: char32_t c3{}; +}; + +struct PositiveChar { + PositiveChar() : d('a') {} + // CHECK-FIXES: PositiveChar() {} + char d; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use default member initializer for 'd' + // CHECK-FIXES: char d{'a'}; +}; + +struct PositiveValueInt { + PositiveValueInt() : i() {} + // CHECK-FIXES: PositiveValueInt() {} + const int i; + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use default member initializer for 'i' + // CHECK-FIXES: const int i{}; +}; + +struct PositiveInt { + PositiveInt() : j(1) {} + // CHECK-FIXES: PositiveInt() {} + int j; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use default member initializer for 'j' + // CHECK-FIXES: int j{1}; +}; + +struct PositiveUnaryMinusInt { + PositiveUnaryMinusInt() : j(-1) {} + // CHECK-FIXES: PositiveUnaryMinusInt() {} + int j; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use default member initializer for 'j' + // CHECK-FIXES: int j{-1}; +}; + +struct PositiveUnaryPlusInt { + PositiveUnaryPlusInt() : j(+1) {} + // CHECK-FIXES: PositiveUnaryPlusInt() {} + int j; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use default member initializer for 'j' + // CHECK-FIXES: int j{+1}; +}; + +struct PositiveValueComplexInt { + PositiveValueComplexInt() : i() {} + // CHECK-FIXES: PositiveValueComplexInt() {} + _Complex int i; + // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use default member initializer for 'i' + // CHECK-FIXES: _Complex int i{}; +}; + +struct PositiveValueFloat { + PositiveValueFloat() : f() {} + // CHECK-FIXES: PositiveValueFloat() {} + float f; + // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use default member initializer for 'f' + // CHECK-FIXES: float f{}; +}; + +struct PositiveValueDouble { + PositiveValueDouble() : d() {} + // CHECK-FIXES: PositiveValueDouble() {} + double d; + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use default member initializer for 'd' + // CHECK-FIXES: double d{}; +}; + +struct PositiveDouble { + PositiveDouble() : f(2.5463e43) {} + // CHECK-FIXES: PositiveDouble() {} + double f; + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use default member initializer for 'f' + // CHECK-FIXES: double f{2.5463e43}; +}; + +struct PositiveValueComplexFloat { + PositiveValueComplexFloat() : f() {} + // CHECK-FIXES: PositiveValueComplexFloat() {} + _Complex float f; + // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: use default member initializer for 'f' + // CHECK-FIXES: _Complex float f{}; +}; + +struct PositiveValueComplexDouble { + PositiveValueComplexDouble() : f() {} + // CHECK-FIXES: PositiveValueComplexDouble() {} + _Complex double f; + // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use default member initializer for 'f' + // CHECK-FIXES: _Complex double f{}; +}; + +struct PositiveUnaryMinusDouble { + PositiveUnaryMinusDouble() : f(-2.5463e43) {} + // CHECK-FIXES: PositiveUnaryMinusDouble() {} + double f; + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use default member initializer for 'f' + // CHECK-FIXES: double f{-2.5463e43}; +}; + +struct PositiveUnaryPlusDouble { + PositiveUnaryPlusDouble() : f(+2.5463e43) {} + // CHECK-FIXES: PositiveUnaryPlusDouble() {} + double f; + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use default member initializer for 'f' + // CHECK-FIXES: double f{+2.5463e43}; +}; + +struct PositiveValueBool { + PositiveValueBool() : b() {} + // CHECK-FIXES: PositiveValueBool() {} + bool b; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use default member initializer for 'b' + // CHECK-FIXES: bool b{}; +}; + +struct PositiveBool { + PositiveBool() : a(true) {} + // CHECK-FIXES: PositiveBool() {} + bool a; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use default member initializer for 'a' + // CHECK-FIXES: bool a{true}; +}; + +struct PositiveValuePointer { + PositiveValuePointer() : p() {} + // CHECK-FIXES: PositiveValuePointer() {} + int *p; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use default member initializer for 'p' + // CHECK-FIXES: int *p{}; +}; + +struct PositiveNullPointer { + PositiveNullPointer() : q(nullptr) {} + // CHECK-FIXES: PositiveNullPointer() {} + int *q; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use default member initializer for 'q' + // CHECK-FIXES: int *q{nullptr}; +}; + +enum Enum { Foo, Bar }; +struct PositiveEnum { + PositiveEnum() : e(Foo) {} + // CHECK-FIXES: PositiveEnum() {} + Enum e; + // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use default member initializer for 'e' + // CHECK-FIXES: Enum e{Foo}; +}; + +struct PositiveString { + PositiveString() : s("foo") {} + // CHECK-FIXES: PositiveString() {} + const char *s; + // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: use default member initializer for 's' + // CHECK-FIXES: const char *s{"foo"}; +}; + +template +struct NegativeTemplate { + NegativeTemplate() : t() {} + T t; +}; + +NegativeTemplate nti; +NegativeTemplate ntd; + +struct NegativeDefaultMember { + NegativeDefaultMember() {} + int i = 2; +}; + +struct NegativeClass : S { + NegativeClass() : s() {} + S s; +}; + +struct NegativeBase : S { + NegativeBase() : S() {} +}; + +struct NegativeDefaultOtherMember{ + NegativeDefaultOtherMember() : i(3) {} + int i = 4; +}; + +struct NegativeUnion { + NegativeUnion() : d(5.0) {} + union { + int i; + double d; + }; +}; + +struct NegativeBitField +{ + NegativeBitField() : i(6) {} + int i : 5; +}; + +struct NegativeNotDefaultInt +{ + NegativeNotDefaultInt(int) : i(7) {} + int i; +}; + +struct ExistingChar { + ExistingChar(short) : e1(), e2(), e3(), e4() {} + // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: member initializer for 'e1' is redundant [modernize-use-default-member-init] + // CHECK-MESSAGES: :[[@LINE-2]]:31: warning: member initializer for 'e2' is redundant + // CHECK-MESSAGES: :[[@LINE-3]]:37: warning: member initializer for 'e3' is redundant + // CHECK-FIXES: ExistingChar(short) : e4() {} + ExistingChar(int) : e1(0), e2(0), e3(0), e4(0) {} + // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: member initializer for 'e1' is redundant + // CHECK-MESSAGES: :[[@LINE-2]]:30: warning: member initializer for 'e2' is redundant + // CHECK-MESSAGES: :[[@LINE-3]]:37: warning: member initializer for 'e3' is redundant + // CHECK-FIXES: ExistingChar(int) : e4(0) {} + ExistingChar(long) : e1('\0'), e2('\0'), e3('\0'), e4('\0') {} + // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: member initializer for 'e1' is redundant + // CHECK-MESSAGES: :[[@LINE-2]]:34: warning: member initializer for 'e2' is redundant + // CHECK-MESSAGES: :[[@LINE-3]]:44: warning: member initializer for 'e3' is redundant + // CHECK-FIXES: ExistingChar(long) : e4('\0') {} + ExistingChar(char) : e1('a'), e2('a'), e3('a'), e4('a') {} + // CHECK-MESSAGES: :[[@LINE-1]]:51: warning: member initializer for 'e4' is redundant + // CHECK-FIXES: ExistingChar(char) : e1('a'), e2('a'), e3('a') {} + char e1{}; + char e2 = 0; + char e3 = '\0'; + char e4 = 'a'; +}; + +struct ExistingInt { + ExistingInt(short) : e1(), e2(), e3(), e4(), e5(), e6() {} + // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: member initializer for 'e1' is redundant [modernize-use-default-member-init] + // CHECK-MESSAGES: :[[@LINE-2]]:30: warning: member initializer for 'e2' is redundant + // CHECK-FIXES: ExistingInt(short) : e3(), e4(), e5(), e6() {} + ExistingInt(int) : e1(0), e2(0), e3(0), e4(0), e5(0), e6(0) {} + // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: member initializer for 'e1' is redundant + // CHECK-MESSAGES: :[[@LINE-2]]:29: warning: member initializer for 'e2' is redundant + // CHECK-FIXES: ExistingInt(int) : e3(0), e4(0), e5(0), e6(0) {} + ExistingInt(long) : e1(5), e2(5), e3(5), e4(5), e5(5), e6(5) {} + // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: member initializer for 'e3' is redundant + // CHECK-MESSAGES: :[[@LINE-2]]:44: warning: member initializer for 'e4' is redundant + // CHECK-MESSAGES: :[[@LINE-3]]:58: warning: member initializer for 'e6' is redundant + // CHECK-FIXES: ExistingInt(long) : e1(5), e2(5), e5(5) {} + ExistingInt(char) : e1(-5), e2(-5), e3(-5), e4(-5), e5(-5), e6(-5) {} + // CHECK-MESSAGES: :[[@LINE-1]]:55: warning: member initializer for 'e5' is redundant + // CHECK-FIXES: ExistingInt(char) : e1(-5), e2(-5), e3(-5), e4(-5), e6(-5) {} + int e1{}; + int e2 = 0; + int e3 = {5}; + int e4 = 5; + int e5 = -5; + int e6 = +5; +}; + +struct ExistingDouble { + ExistingDouble(short) : e1(), e2(), e3(), e4(), e5() {} + // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: member initializer for 'e1' is redundant + // CHECK-MESSAGES: :[[@LINE-2]]:33: warning: member initializer for 'e2' is redundant + // CHECK-FIXES: ExistingDouble(short) : e3(), e4(), e5() {} + ExistingDouble(int) : e1(0.0), e2(0.0), e3(0.0), e4(0.0), e5(0.0) {} + // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: member initializer for 'e1' is redundant + // CHECK-MESSAGES: :[[@LINE-2]]:34: warning: member initializer for 'e2' is redundant + // CHECK-FIXES: ExistingDouble(int) : e3(0.0), e4(0.0), e5(0.0) {} + ExistingDouble(long) : e1(5.0), e2(5.0), e3(5.0), e4(5.0), e5(5.0) {} + // CHECK-MESSAGES: :[[@LINE-1]]:44: warning: member initializer for 'e3' is redundant + // CHECK-MESSAGES: :[[@LINE-2]]:62: warning: member initializer for 'e5' is redundant + // CHECK-FIXES: ExistingDouble(long) : e1(5.0), e2(5.0), e4(5.0) {} + ExistingDouble(char) : e1(-5.0), e2(-5.0), e3(-5.0), e4(-5.0), e5(-5.0) {} + // CHECK-MESSAGES: :[[@LINE-1]]:56: warning: member initializer for 'e4' is redundant + // CHECK-FIXES: ExistingDouble(char) : e1(-5.0), e2(-5.0), e3(-5.0), e5(-5.0) {} + double e1{}; + double e2 = 0.0; + double e3 = 5.0; + double e4 = -5.0; + double e5 = +5.0; +}; + +struct ExistingBool { + ExistingBool(short) : e1(), e2(), e3() {} + // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: member initializer for 'e1' is redundant + // CHECK-MESSAGES: :[[@LINE-2]]:31: warning: member initializer for 'e2' is redundant + // CHECK-FIXES: ExistingBool(short) : e3() {} + ExistingBool(int) : e1(false), e2(false), e3(false) {} + // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: member initializer for 'e1' is redundant + // CHECK-MESSAGES: :[[@LINE-2]]:34: warning: member initializer for 'e2' is redundant + // CHECK-FIXES: ExistingBool(int) : e3(false) {} + ExistingBool(long) : e1(true), e2(true), e3(true) {} + // CHECK-MESSAGES: :[[@LINE-1]]:44: warning: member initializer for 'e3' is redundant + // CHECK-FIXES: ExistingBool(long) : e1(true), e2(true) {} + bool e1{}; + bool e2 = false; + bool e3 = true; +}; + +struct ExistingEnum { + ExistingEnum(short) : e1(Foo), e2(Foo) {} + // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: member initializer for 'e1' is redundant + // CHECK-FIXES: ExistingEnum(short) : e2(Foo) {} + ExistingEnum(int) : e1(Bar), e2(Bar) {} + // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: member initializer for 'e2' is redundant + // CHECK-FIXES: ExistingEnum(int) : e1(Bar) {} + Enum e1 = Foo; + Enum e2{Bar}; +}; + +struct ExistingPointer { + ExistingPointer(short) : e1(), e2(), e3(), e4() {} + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: member initializer for 'e1' is redundant + // CHECK-MESSAGES: :[[@LINE-2]]:34: warning: member initializer for 'e2' is redundant + // CHECK-MESSAGES: :[[@LINE-3]]:40: warning: member initializer for 'e3' is redundant + // CHECK-FIXES: ExistingPointer(short) : e4() {} + ExistingPointer(int) : e1(0), e2(0), e3(0), e4(&e1) {} + // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: member initializer for 'e1' is redundant + // CHECK-MESSAGES: :[[@LINE-2]]:33: warning: member initializer for 'e2' is redundant + // CHECK-MESSAGES: :[[@LINE-3]]:40: warning: member initializer for 'e3' is redundant + // CHECK-FIXES: ExistingPointer(int) : e4(&e1) {} + ExistingPointer(long) : e1(nullptr), e2(nullptr), e3(nullptr), e4(&e2) {} + // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: member initializer for 'e1' is redundant + // CHECK-MESSAGES: :[[@LINE-2]]:40: warning: member initializer for 'e2' is redundant + // CHECK-MESSAGES: :[[@LINE-3]]:53: warning: member initializer for 'e3' is redundant + // CHECK-FIXES: ExistingPointer(long) : e4(&e2) {} + int *e1{}; + int *e2 = 0; + int *e3 = nullptr; + int **e4 = &e1; +}; + +struct ExistingString { + ExistingString(short) : e1(), e2(), e3(), e4() {} + // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: member initializer for 'e1' is redundant [modernize-use-default-member-init] + // CHECK-MESSAGES: :[[@LINE-2]]:33: warning: member initializer for 'e2' is redundant + // CHECK-FIXES: ExistingString(short) : e3(), e4() {} + ExistingString(int) : e1(0), e2(0), e3(0), e4(0) {} + // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: member initializer for 'e1' is redundant + // CHECK-MESSAGES: :[[@LINE-2]]:32: warning: member initializer for 'e2' is redundant + // CHECK-FIXES: ExistingString(int) : e3(0), e4(0) {} + ExistingString(long) : e1(nullptr), e2(nullptr), e3(nullptr), e4(nullptr) {} + // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: member initializer for 'e1' is redundant + // CHECK-MESSAGES: :[[@LINE-2]]:39: warning: member initializer for 'e2' is redundant + // CHECK-FIXES: ExistingString(long) : e3(nullptr), e4(nullptr) {} + ExistingString(char) : e1("foo"), e2("foo"), e3("foo"), e4("foo") {} + // CHECK-MESSAGES: :[[@LINE-1]]:48: warning: member initializer for 'e3' is redundant + // CHECK-FIXES: ExistingString(char) : e1("foo"), e2("foo"), e4("foo") {} + const char *e1{}; + const char *e2 = nullptr; + const char *e3 = "foo"; + const char *e4 = "bar"; +}; + +template +struct NegativeTemplateExisting { + NegativeTemplateExisting(int) : t(0) {} + T t{}; +}; + +NegativeTemplateExisting ntei(0); +NegativeTemplateExisting nted(0);