1//===--- RedundantMemberInitCheck.cpp - clang-tidy-------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "RedundantMemberInitCheck.h"
10#include "../utils/LexerUtils.h"
11#include "../utils/Matchers.h"
12#include "clang/AST/ASTContext.h"
13#include "clang/ASTMatchers/ASTMatchFinder.h"
14#include "clang/Lex/Lexer.h"
15#include <algorithm>
16
17using namespace clang::ast_matchers;
18using namespace clang::tidy::matchers;
19
20namespace clang::tidy::readability {
21
22static SourceRange
23getFullInitRangeInclWhitespaces(SourceRange Range, const SourceManager &SM,
24 const LangOptions &LangOpts) {
25 const Token PrevToken =
26 utils::lexer::getPreviousToken(Location: Range.getBegin(), SM, LangOpts, SkipComments: false);
27 if (PrevToken.is(K: tok::unknown))
28 return Range;
29
30 if (PrevToken.isNot(K: tok::equal))
31 return {PrevToken.getEndLoc(), Range.getEnd()};
32
33 return getFullInitRangeInclWhitespaces(
34 Range: {PrevToken.getLocation(), Range.getEnd()}, SM, LangOpts);
35}
36
37void RedundantMemberInitCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
38 Options.store(Options&: Opts, LocalName: "IgnoreBaseInCopyConstructors",
39 Value: IgnoreBaseInCopyConstructors);
40}
41
42void RedundantMemberInitCheck::registerMatchers(MatchFinder *Finder) {
43 auto ConstructorMatcher =
44 cxxConstructExpr(argumentCountIs(N: 0),
45 hasDeclaration(InnerMatcher: cxxConstructorDecl(ofClass(InnerMatcher: cxxRecordDecl(
46 unless(isTriviallyDefaultConstructible()))))))
47 .bind(ID: "construct");
48
49 Finder->addMatcher(
50 NodeMatch: cxxConstructorDecl(
51 unless(isDelegatingConstructor()), ofClass(InnerMatcher: unless(isUnion())),
52 forEachConstructorInitializer(
53 InnerMatcher: cxxCtorInitializer(withInitializer(InnerMatcher: ConstructorMatcher),
54 unless(forField(InnerMatcher: fieldDecl(
55 anyOf(hasType(InnerMatcher: isConstQualified()),
56 hasParent(recordDecl(isUnion())))))))
57 .bind(ID: "init")))
58 .bind(ID: "constructor"),
59 Action: this);
60
61 Finder->addMatcher(NodeMatch: fieldDecl(hasInClassInitializer(InnerMatcher: ConstructorMatcher),
62 unless(hasParent(recordDecl(isUnion()))))
63 .bind(ID: "field"),
64 Action: this);
65}
66
67void RedundantMemberInitCheck::check(const MatchFinder::MatchResult &Result) {
68 const auto *Construct = Result.Nodes.getNodeAs<CXXConstructExpr>(ID: "construct");
69
70 if (const auto *Field = Result.Nodes.getNodeAs<FieldDecl>(ID: "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>(ID: "init");
80 const auto *ConstructorDecl =
81 Result.Nodes.getNodeAs<CXXConstructorDecl>(ID: "constructor");
82
83 if (IgnoreBaseInCopyConstructors && ConstructorDecl->isCopyConstructor() &&
84 Init->isBaseInitializer())
85 return;
86
87 if (Init->isAnyMemberInitializer()) {
88 diag(Loc: Init->getSourceLocation(), Description: "initializer for member %0 is redundant")
89 << Init->getAnyMember()
90 << FixItHint::CreateRemoval(RemoveRange: Init->getSourceRange());
91 } else {
92 diag(Loc: Init->getSourceLocation(),
93 Description: "initializer for base class %0 is redundant")
94 << Construct->getType()
95 << FixItHint::CreateRemoval(RemoveRange: Init->getSourceRange());
96 }
97}
98
99} // namespace clang::tidy::readability
100

source code of clang-tools-extra/clang-tidy/readability/RedundantMemberInitCheck.cpp