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