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 auto Construct =
30 cxxConstructExpr(
31 hasDeclaration(cxxConstructorDecl(hasParent(
32 cxxRecordDecl(unless(isTriviallyDefaultConstructible()))))))
33 .bind("construct");
34
35 Finder->addMatcher(
36 traverse(
37 TK_AsIs,
38 cxxConstructorDecl(
39 unless(isDelegatingConstructor()),
40 ofClass(unless(
41 anyOf(isUnion(), ast_matchers::isTemplateInstantiation()))),
42 forEachConstructorInitializer(
43 cxxCtorInitializer(
44 isWritten(), withInitializer(ignoringImplicit(Construct)),
45 unless(forField(hasType(isConstQualified()))),
46 unless(forField(hasParent(recordDecl(isUnion())))))
47 .bind("init")))
48 .bind("constructor")),
49 this);
50 }
51
check(const MatchFinder::MatchResult & Result)52 void RedundantMemberInitCheck::check(const MatchFinder::MatchResult &Result) {
53 const auto *Init = Result.Nodes.getNodeAs<CXXCtorInitializer>("init");
54 const auto *Construct = Result.Nodes.getNodeAs<CXXConstructExpr>("construct");
55 const auto *ConstructorDecl =
56 Result.Nodes.getNodeAs<CXXConstructorDecl>("constructor");
57
58 if (IgnoreBaseInCopyConstructors && ConstructorDecl->isCopyConstructor() &&
59 Init->isBaseInitializer())
60 return;
61
62 if (Construct->getNumArgs() == 0 ||
63 Construct->getArg(0)->isDefaultArgument()) {
64 if (Init->isAnyMemberInitializer()) {
65 diag(Init->getSourceLocation(), "initializer for member %0 is redundant")
66 << Init->getAnyMember()
67 << FixItHint::CreateRemoval(Init->getSourceRange());
68 } else {
69 diag(Init->getSourceLocation(),
70 "initializer for base class %0 is redundant")
71 << Construct->getType()
72 << FixItHint::CreateRemoval(Init->getSourceRange());
73 }
74 }
75 }
76
77 } // namespace readability
78 } // namespace tidy
79 } // namespace clang
80