clang-tools 22.0.0git
RedundantMemberInitCheck.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
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
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
16using namespace clang::ast_matchers;
17using namespace clang::tidy::matchers;
18
20
21static SourceRange
22getFullInitRangeInclWhitespaces(SourceRange Range, const SourceManager &SM,
23 const LangOptions &LangOpts) {
24 const Token PrevToken =
25 utils::lexer::getPreviousToken(Range.getBegin(), SM, LangOpts, false);
26 if (PrevToken.is(tok::unknown))
27 return Range;
28
29 if (PrevToken.isNot(tok::equal))
30 return {PrevToken.getEndLoc(), Range.getEnd()};
31
33 {PrevToken.getLocation(), Range.getEnd()}, SM, LangOpts);
34}
35
37 Options.store(Opts, "IgnoreBaseInCopyConstructors",
38 IgnoreBaseInCopyConstructors);
39}
40
42 auto ConstructorMatcher =
43 cxxConstructExpr(
44 argumentCountIs(0),
45 hasDeclaration(cxxConstructorDecl(
46 ofClass(cxxRecordDecl(unless(isTriviallyDefaultConstructible()))
47 .bind("class")))))
48 .bind("construct");
49
50 auto HasUnionAsParent = hasParent(recordDecl(isUnion()));
51
52 auto HasTypeEqualToConstructorClass = hasType(qualType(
53 hasCanonicalType(qualType(hasDeclaration(equalsBoundNode("class"))))));
54
55 Finder->addMatcher(
56 cxxConstructorDecl(
57 unless(isDelegatingConstructor()), ofClass(unless(isUnion())),
58 forEachConstructorInitializer(
59 cxxCtorInitializer(
60 withInitializer(ConstructorMatcher),
61 anyOf(isBaseInitializer(),
62 forField(fieldDecl(unless(hasType(isConstQualified())),
63 unless(HasUnionAsParent),
64 HasTypeEqualToConstructorClass))))
65 .bind("init")))
66 .bind("constructor"),
67 this);
68
69 Finder->addMatcher(fieldDecl(hasInClassInitializer(ConstructorMatcher),
70 HasTypeEqualToConstructorClass,
71 unless(HasUnionAsParent))
72 .bind("field"),
73 this);
74}
75
76void RedundantMemberInitCheck::check(const MatchFinder::MatchResult &Result) {
77 const auto *Construct = Result.Nodes.getNodeAs<CXXConstructExpr>("construct");
78
79 if (const auto *Field = Result.Nodes.getNodeAs<FieldDecl>("field")) {
80 const Expr *Init = Field->getInClassInitializer();
81 diag(Construct->getExprLoc(), "initializer for member %0 is redundant")
82 << Field
83 << FixItHint::CreateRemoval(getFullInitRangeInclWhitespaces(
84 Init->getSourceRange(), *Result.SourceManager, getLangOpts()));
85 return;
86 }
87
88 const auto *Init = Result.Nodes.getNodeAs<CXXCtorInitializer>("init");
89 const auto *ConstructorDecl =
90 Result.Nodes.getNodeAs<CXXConstructorDecl>("constructor");
91
92 if (IgnoreBaseInCopyConstructors && ConstructorDecl->isCopyConstructor() &&
93 Init->isBaseInitializer())
94 return;
95
96 if (Init->isAnyMemberInitializer()) {
97 diag(Init->getSourceLocation(), "initializer for member %0 is redundant")
98 << Init->getAnyMember()
99 << FixItHint::CreateRemoval(Init->getSourceRange());
100 } else {
101 diag(Init->getSourceLocation(),
102 "initializer for base class %0 is redundant")
103 << Construct->getType()
104 << FixItHint::CreateRemoval(Init->getSourceRange());
105 }
106}
107
108} // namespace clang::tidy::readability
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
void registerMatchers(ast_matchers::MatchFinder *Finder) override
static SourceRange getFullInitRangeInclWhitespaces(SourceRange Range, const SourceManager &SM, const LangOptions &LangOpts)
Token getPreviousToken(SourceLocation Location, const SourceManager &SM, const LangOptions &LangOpts, bool SkipComments)
Returns previous token or tok::unknown if not found.
llvm::StringMap< ClangTidyValue > OptionMap