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/Matchers.h"
11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 #include "clang/Lex/Lexer.h"
14 #include <algorithm>
15
16 using namespace clang::ast_matchers;
17 using namespace clang::tidy::matchers;
18
19 namespace clang {
20 namespace tidy {
21 namespace readability {
22
storeOptions(ClangTidyOptions::OptionMap & Opts)23 void RedundantMemberInitCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
24 Options.store(Opts, "IgnoreBaseInCopyConstructors",
25 IgnoreBaseInCopyConstructors);
26 }
27
registerMatchers(MatchFinder * Finder)28 void RedundantMemberInitCheck::registerMatchers(MatchFinder *Finder) {
29 if (!getLangOpts().CPlusPlus)
30 return;
31
32 auto Construct =
33 cxxConstructExpr(
34 hasDeclaration(cxxConstructorDecl(hasParent(
35 cxxRecordDecl(unless(isTriviallyDefaultConstructible()))))))
36 .bind("construct");
37
38 Finder->addMatcher(
39 cxxConstructorDecl(
40 unless(isDelegatingConstructor()),
41 ofClass(unless(
42 anyOf(isUnion(), ast_matchers::isTemplateInstantiation()))),
43 forEachConstructorInitializer(
44 cxxCtorInitializer(
45 isWritten(), withInitializer(ignoringImplicit(Construct)),
46 unless(forField(hasType(isConstQualified()))),
47 unless(forField(hasParent(recordDecl(isUnion())))))
48 .bind("init")))
49 .bind("constructor"),
50 this);
51 }
52
check(const MatchFinder::MatchResult & Result)53 void RedundantMemberInitCheck::check(const MatchFinder::MatchResult &Result) {
54 const auto *Init = Result.Nodes.getNodeAs<CXXCtorInitializer>("init");
55 const auto *Construct = Result.Nodes.getNodeAs<CXXConstructExpr>("construct");
56 const auto *ConstructorDecl =
57 Result.Nodes.getNodeAs<CXXConstructorDecl>("constructor");
58
59 if (IgnoreBaseInCopyConstructors && ConstructorDecl->isCopyConstructor() &&
60 Init->isBaseInitializer())
61 return;
62
63 if (Construct->getNumArgs() == 0 ||
64 Construct->getArg(0)->isDefaultArgument()) {
65 if (Init->isAnyMemberInitializer()) {
66 diag(Init->getSourceLocation(), "initializer for member %0 is redundant")
67 << Init->getAnyMember()
68 << FixItHint::CreateRemoval(Init->getSourceRange());
69 } else {
70 diag(Init->getSourceLocation(),
71 "initializer for base class %0 is redundant")
72 << Construct->getType()
73 << FixItHint::CreateRemoval(Init->getSourceRange());
74 }
75 }
76 }
77
78 } // namespace readability
79 } // namespace tidy
80 } // namespace clang
81