77// ===----------------------------------------------------------------------===//
88
99#include " RedundantMemberInitCheck.h"
10+ #include " ../utils/LexerUtils.h"
1011#include " ../utils/Matchers.h"
1112#include " clang/AST/ASTContext.h"
1213#include " clang/ASTMatchers/ASTMatchFinder.h"
@@ -18,52 +19,80 @@ using namespace clang::tidy::matchers;
1819
1920namespace clang ::tidy::readability {
2021
22+ static SourceRange
23+ getFullInitRangeInclWhitespaces (SourceRange Range, const SourceManager &SM,
24+ const LangOptions &LangOpts) {
25+ const Token PrevToken =
26+ utils::lexer::getPreviousToken (Range.getBegin (), SM, LangOpts, false );
27+ if (PrevToken.is (tok::unknown))
28+ return Range;
29+
30+ if (PrevToken.isNot (tok::equal))
31+ return {PrevToken.getEndLoc (), Range.getEnd ()};
32+
33+ return getFullInitRangeInclWhitespaces (
34+ {PrevToken.getLocation (), Range.getEnd ()}, SM, LangOpts);
35+ }
36+
2137void RedundantMemberInitCheck::storeOptions (ClangTidyOptions::OptionMap &Opts) {
2238 Options.store (Opts, " IgnoreBaseInCopyConstructors" ,
2339 IgnoreBaseInCopyConstructors);
2440}
2541
2642void RedundantMemberInitCheck::registerMatchers (MatchFinder *Finder) {
43+ auto ConstructorMatcher =
44+ cxxConstructExpr (argumentCountIs (0 ),
45+ hasDeclaration (cxxConstructorDecl (ofClass (cxxRecordDecl (
46+ unless (isTriviallyDefaultConstructible ()))))))
47+ .bind (" construct" );
48+
2749 Finder->addMatcher (
2850 cxxConstructorDecl (
2951 unless (isDelegatingConstructor ()), ofClass (unless (isUnion ())),
3052 forEachConstructorInitializer (
31- cxxCtorInitializer (
32- withInitializer (
33- cxxConstructExpr (
34- hasDeclaration (
35- cxxConstructorDecl (ofClass (cxxRecordDecl (
36- unless (isTriviallyDefaultConstructible ()))))))
37- .bind (" construct" )),
38- unless (forField (hasType (isConstQualified ()))),
39- unless (forField (hasParent (recordDecl (isUnion ())))))
53+ cxxCtorInitializer (withInitializer (ConstructorMatcher),
54+ unless (forField (fieldDecl (
55+ anyOf (hasType (isConstQualified ()),
56+ hasParent (recordDecl (isUnion ())))))))
4057 .bind (" init" )))
4158 .bind (" constructor" ),
4259 this );
60+
61+ Finder->addMatcher (fieldDecl (hasInClassInitializer (ConstructorMatcher),
62+ unless (hasParent (recordDecl (isUnion ()))))
63+ .bind (" field" ),
64+ this );
4365}
4466
4567void RedundantMemberInitCheck::check (const MatchFinder::MatchResult &Result) {
46- const auto *Init = Result.Nodes .getNodeAs <CXXCtorInitializer>(" init" );
4768 const auto *Construct = Result.Nodes .getNodeAs <CXXConstructExpr>(" construct" );
69+
70+ if (const auto *Field = Result.Nodes .getNodeAs <FieldDecl>(" field" )) {
71+ const Expr *Init = Field->getInClassInitializer ();
72+ diag (Construct->getExprLoc (), " initializer for member %0 is redundant" )
73+ << Field
74+ << FixItHint::CreateRemoval (getFullInitRangeInclWhitespaces (
75+ Init->getSourceRange (), *Result.SourceManager , getLangOpts ()));
76+ return ;
77+ }
78+
79+ const auto *Init = Result.Nodes .getNodeAs <CXXCtorInitializer>(" init" );
4880 const auto *ConstructorDecl =
4981 Result.Nodes .getNodeAs <CXXConstructorDecl>(" constructor" );
5082
5183 if (IgnoreBaseInCopyConstructors && ConstructorDecl->isCopyConstructor () &&
5284 Init->isBaseInitializer ())
5385 return ;
5486
55- if (Construct->getNumArgs () == 0 ||
56- Construct->getArg (0 )->isDefaultArgument ()) {
57- if (Init->isAnyMemberInitializer ()) {
58- diag (Init->getSourceLocation (), " initializer for member %0 is redundant" )
59- << Init->getAnyMember ()
60- << FixItHint::CreateRemoval (Init->getSourceRange ());
61- } else {
62- diag (Init->getSourceLocation (),
63- " initializer for base class %0 is redundant" )
64- << Construct->getType ()
65- << FixItHint::CreateRemoval (Init->getSourceRange ());
66- }
87+ if (Init->isAnyMemberInitializer ()) {
88+ diag (Init->getSourceLocation (), " initializer for member %0 is redundant" )
89+ << Init->getAnyMember ()
90+ << FixItHint::CreateRemoval (Init->getSourceRange ());
91+ } else {
92+ diag (Init->getSourceLocation (),
93+ " initializer for base class %0 is redundant" )
94+ << Construct->getType ()
95+ << FixItHint::CreateRemoval (Init->getSourceRange ());
6796 }
6897}
6998
0 commit comments