7
7
// ===----------------------------------------------------------------------===//
8
8
9
9
#include " RedundantMemberInitCheck.h"
10
+ #include " ../utils/LexerUtils.h"
10
11
#include " ../utils/Matchers.h"
11
12
#include " clang/AST/ASTContext.h"
12
13
#include " clang/ASTMatchers/ASTMatchFinder.h"
@@ -18,52 +19,80 @@ using namespace clang::tidy::matchers;
18
19
19
20
namespace clang ::tidy::readability {
20
21
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
+
21
37
void RedundantMemberInitCheck::storeOptions (ClangTidyOptions::OptionMap &Opts) {
22
38
Options.store (Opts, " IgnoreBaseInCopyConstructors" ,
23
39
IgnoreBaseInCopyConstructors);
24
40
}
25
41
26
42
void RedundantMemberInitCheck::registerMatchers (MatchFinder *Finder) {
43
+ auto ConstructorMatcher =
44
+ cxxConstructExpr (argumentCountIs (0 ),
45
+ hasDeclaration (cxxConstructorDecl (ofClass (cxxRecordDecl (
46
+ unless (isTriviallyDefaultConstructible ()))))))
47
+ .bind (" construct" );
48
+
27
49
Finder->addMatcher (
28
50
cxxConstructorDecl (
29
51
unless (isDelegatingConstructor ()), ofClass (unless (isUnion ())),
30
52
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 ())))))))
40
57
.bind (" init" )))
41
58
.bind (" constructor" ),
42
59
this );
60
+
61
+ Finder->addMatcher (fieldDecl (hasInClassInitializer (ConstructorMatcher),
62
+ unless (hasParent (recordDecl (isUnion ()))))
63
+ .bind (" field" ),
64
+ this );
43
65
}
44
66
45
67
void RedundantMemberInitCheck::check (const MatchFinder::MatchResult &Result) {
46
- const auto *Init = Result.Nodes .getNodeAs <CXXCtorInitializer>(" init" );
47
68
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" );
48
80
const auto *ConstructorDecl =
49
81
Result.Nodes .getNodeAs <CXXConstructorDecl>(" constructor" );
50
82
51
83
if (IgnoreBaseInCopyConstructors && ConstructorDecl->isCopyConstructor () &&
52
84
Init->isBaseInitializer ())
53
85
return ;
54
86
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 ());
67
96
}
68
97
}
69
98
0 commit comments