Index: clang-tidy/readability/CMakeLists.txt =================================================================== --- clang-tidy/readability/CMakeLists.txt +++ clang-tidy/readability/CMakeLists.txt @@ -16,6 +16,7 @@ NonConstParameterCheck.cpp ReadabilityTidyModule.cpp RedundantControlFlowCheck.cpp + RedundantMemberInitCheck.cpp RedundantStringCStrCheck.cpp RedundantSmartptrGetCheck.cpp RedundantStringInitCheck.cpp Index: clang-tidy/readability/ReadabilityTidyModule.cpp =================================================================== --- clang-tidy/readability/ReadabilityTidyModule.cpp +++ clang-tidy/readability/ReadabilityTidyModule.cpp @@ -23,6 +23,7 @@ #include "NamedParameterCheck.h" #include "NonConstParameterCheck.h" #include "RedundantControlFlowCheck.h" +#include "RedundantMemberInitCheck.h" #include "RedundantSmartptrGetCheck.h" #include "RedundantStringCStrCheck.h" #include "RedundantStringInitCheck.h" @@ -57,6 +58,8 @@ "readability-inconsistent-declaration-parameter-name"); CheckFactories.registerCheck( "readability-misplaced-array-index"); + CheckFactories.registerCheck( + "readability-redundant-member-init"); CheckFactories.registerCheck( "readability-static-definition-in-anonymous-namespace"); CheckFactories.registerCheck( Index: clang-tidy/readability/RedundantMemberInitCheck.h =================================================================== --- /dev/null +++ clang-tidy/readability/RedundantMemberInitCheck.h @@ -0,0 +1,36 @@ +//===--- RedundantMemberInitCheck.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_READABILITY_REDUNDANT_MEMBER_INIT_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANT_MEMBER_INIT_H + +#include "../ClangTidy.h" + +namespace clang { +namespace tidy { +namespace readability { + +/// Finds member initializations that are unnecessary because the same default +/// constructor would be called if they were not present. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/readability-redundant-member-init.html +class RedundantMemberInitCheck : public ClangTidyCheck { +public: + RedundantMemberInitCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; +}; + +} // namespace readability +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANT_MEMBER_INIT_H Index: clang-tidy/readability/RedundantMemberInitCheck.cpp =================================================================== --- /dev/null +++ clang-tidy/readability/RedundantMemberInitCheck.cpp @@ -0,0 +1,67 @@ +//===--- RedundantMemberInitCheck.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 "RedundantMemberInitCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Lex/Lexer.h" +#include "../utils/Matchers.h" +#include + +using namespace clang::ast_matchers; +using namespace clang::tidy::matchers; + +namespace clang { +namespace tidy { +namespace readability { + +void RedundantMemberInitCheck::registerMatchers(MatchFinder *Finder) { + auto Construct = + cxxConstructExpr( + hasDeclaration(cxxConstructorDecl(hasParent( + cxxRecordDecl(unless(isTriviallyDefaultConstructible())))))) + .bind("construct"); + + Finder->addMatcher( + cxxConstructorDecl( + unless(isDelegatingConstructor()), + ofClass(unless( + anyOf(isUnion(), ast_matchers::isTemplateInstantiation()))), + forEachConstructorInitializer( + cxxCtorInitializer( + isWritten(), + withInitializer( + anyOf(Construct, exprWithCleanups(has(Construct)))), + unless(forField(hasType(isConstQualified())))) + .bind("init"))), + this); +} + +void RedundantMemberInitCheck::check(const MatchFinder::MatchResult &Result) { + const auto *Init = Result.Nodes.getNodeAs("init"); + const auto *Construct = Result.Nodes.getNodeAs("construct"); + + if (Construct->getNumArgs() == 0 || + Construct->getArg(0)->isDefaultArgument()) { + if (Init->isAnyMemberInitializer()) { + diag(Init->getSourceLocation(), "initializer for member %0 is redundant") + << Init->getMember() + << FixItHint::CreateRemoval(Init->getSourceRange()); + } else { + diag(Init->getSourceLocation(), + "initializer for base class %0 is redundant") + << Init->getTypeSourceInfo()->getType() + << FixItHint::CreateRemoval(Init->getSourceRange()); + } + } +} + +} // namespace readability +} // namespace tidy +} // namespace clang Index: clang-tidy/utils/TypeTraits.cpp =================================================================== --- clang-tidy/utils/TypeTraits.cpp +++ clang-tidy/utils/TypeTraits.cpp @@ -58,7 +58,7 @@ // constructible. if (ClassDecl->hasUserProvidedDefaultConstructor()) return false; - // A class is trivially constructible if it has a trivial default constructor. + // A class isn't trivially constructible if it doesn't have a trivial default constructor. if (ClassDecl->hasTrivialDefaultConstructor()) return true; Index: docs/ReleaseNotes.rst =================================================================== --- docs/ReleaseNotes.rst +++ docs/ReleaseNotes.rst @@ -111,6 +111,12 @@ Flags function parameters of a pointer type that could be changed to point to a constant type instead. +- New `readability-redundant-member-init + `_ check + + Flags member initializations that are unnecessary because the same default + constructor would be called if they were not present. + Fixed bugs: - `modernize-make-unique Index: docs/clang-tidy/checks/list.rst =================================================================== --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -133,6 +133,7 @@ readability-named-parameter readability-non-const-parameter readability-redundant-control-flow + readability-redundant-member-init readability-redundant-smartptr-get readability-redundant-string-cstr readability-redundant-string-init Index: docs/clang-tidy/checks/readability-redundant-member-init.rst =================================================================== --- /dev/null +++ docs/clang-tidy/checks/readability-redundant-member-init.rst @@ -0,0 +1,20 @@ +.. title:: clang-tidy - readability-redundant-member-init + +readability-redundant-member-init +================================= + +Finds member initializations that are unnecessary because the same default +constructor would be called if they were not present. + +Example: + +.. code-block:: c++ + + // Explicitly initializing the member s is unnecessary. + class Foo { + public: + Foo() : s() {} + + private: + std::string s; + }; Index: test/clang-tidy/readability-redundant-member-init.cpp =================================================================== --- /dev/null +++ test/clang-tidy/readability-redundant-member-init.cpp @@ -0,0 +1,181 @@ +// RUN: %check_clang_tidy %s readability-redundant-member-init %t + +struct S { + S() = default; + S(int i) : i(i) {} + int i = 1; +}; + +struct T { + T(int i = 1) : i(i) {} + int i; +}; + +struct U { + int i; +}; + +union V { + int i; + double f; +}; + +// Initializer calls default constructor +struct F1 { + F1() : f() {} + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: initializer for member 'f' is redundant + // CHECK-FIXES: F1() {} + S f; +}; + +// Initializer calls default constructor with default argument +struct F2 { + F2() : f() {} + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: initializer for member 'f' is redundant + // CHECK-FIXES: F2() {} + T f; +}; + +// Multiple redundant initializers for same constructor +struct F3 { + F3() : f(), g(1), h() {} + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: initializer for member 'f' is redundant + // CHECK-MESSAGES: :[[@LINE-2]]:21: warning: initializer for member 'h' is redundant + // CHECK-FIXES: F3() : g(1) {} + S f, g, h; +}; + +// Templated class independent type +template +struct F4 { + F4() : f() {} + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: initializer for member 'f' is redundant + // CHECK-FIXES: F4() {} + S f; +}; +F4 f4i; +F4 f4s; + +// Base class +struct F5 : S { + F5() : S() {} + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: initializer for base class 'S' is redundant + // CHECK-FIXES: F5() {} +}; + +// Constructor call requires cleanup +struct Cleanup { + ~Cleanup() {} +}; + +struct UsesCleanup { + UsesCleanup(const Cleanup &c = Cleanup()) {} +}; + +struct F6 { + F6() : uc() {} + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: initializer for member 'uc' is redundant + // CHECK-FIXES: F6() {} + UsesCleanup uc; +}; + +// Multiple inheritance +struct F7 : S, T { + F7() : S(), T() {} + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: initializer for base class 'S' is redundant + // CHECK-MESSAGES: :[[@LINE-2]]:15: warning: initializer for base class 'T' is redundant + // CHECK-FIXES: F7() {} +}; + +// Initializer not written +struct NF1 { + NF1() {} + S f; +}; + +// Initializer doesn't call default constructor +struct NF2 { + NF2() : f(1) {} + S f; +}; + +// Initializer calls default constructor without using default argument +struct NF3 { + NF3() : f(1) {} + T f; +}; + +// Initializer calls default constructor without using default argument +struct NF4 { + NF4() : f(2) {} + T f; +}; + +// Initializer is zero-initialization +struct NF5 { + NF5() : i() {} + int i; +}; + +// Initializer is direct-initialization +struct NF6 { + NF6() : i(1) {} + int i; +}; + +// Initializer is aggregate initialization of struct +struct NF7 { + NF7() : f{} {} + U f; +}; + +// Initializer is zero-initialization of struct +struct NF7b { + NF7b() : f() {} + U f; +}; + +// Initializer is aggregate initialization of array +struct NF8 { + NF8() : f{} {} + int f[2]; +}; + +struct NF9 { + NF9() : f{} {} + S f[2]; +}; + +// Initializing member of union +union NF10 { + NF10() : s() {} + int i; + S s; +}; + +// Templated class dependent type +template +struct NF11 { + NF11() : f() {} + V f; +}; +NF11 nf11i; +NF11 nf11s; + +// Delegating constructor +class NF12 { + NF12() = default; + NF12(int) : NF12() {} +}; + +// Const member +struct NF13 { + NF13() : f() {} + const S f; +}; + +// Union member +struct NF14 { + NF14() : f() {} + V f; +};