10#include "clang/AST/ASTContext.h"
11#include "clang/ASTMatchers/ASTMatchFinder.h"
12#include "clang/Lex/Lexer.h"
20 return Node.getNumInits() == N;
25 switch (InitType->getScalarTypeKind()) {
26 case Type::STK_CPointer:
27 case Type::STK_BlockPointer:
28 case Type::STK_ObjCObjectPointer:
29 case Type::STK_MemberPointer:
35 case Type::STK_Integral:
36 switch (InitType->castAs<BuiltinType>()->getKind()) {
37 case BuiltinType::Char_U:
38 case BuiltinType::UChar:
39 case BuiltinType::Char_S:
40 case BuiltinType::SChar:
42 case BuiltinType::WChar_U:
43 case BuiltinType::WChar_S:
45 case BuiltinType::Char16:
47 case BuiltinType::Char32:
53 case Type::STK_Floating:
54 switch (InitType->castAs<BuiltinType>()->getKind()) {
55 case BuiltinType::Half:
56 case BuiltinType::Float:
62 case Type::STK_FloatingComplex:
63 case Type::STK_IntegralComplex:
65 InitType->castAs<ComplexType>()->getElementType());
67 case Type::STK_FixedPoint:
68 switch (InitType->castAs<BuiltinType>()->getKind()) {
69 case BuiltinType::ShortAccum:
70 case BuiltinType::SatShortAccum:
72 case BuiltinType::Accum:
73 case BuiltinType::SatAccum:
75 case BuiltinType::LongAccum:
76 case BuiltinType::SatLongAccum:
78 case BuiltinType::UShortAccum:
79 case BuiltinType::SatUShortAccum:
81 case BuiltinType::UAccum:
82 case BuiltinType::SatUAccum:
84 case BuiltinType::ULongAccum:
85 case BuiltinType::SatULongAccum:
87 case BuiltinType::ShortFract:
88 case BuiltinType::SatShortFract:
90 case BuiltinType::Fract:
91 case BuiltinType::SatFract:
93 case BuiltinType::LongFract:
94 case BuiltinType::SatLongFract:
96 case BuiltinType::UShortFract:
97 case BuiltinType::SatUShortFract:
99 case BuiltinType::UFract:
100 case BuiltinType::SatUFract:
102 case BuiltinType::ULongFract:
103 case BuiltinType::SatULongFract:
106 llvm_unreachable(
"Unhandled fixed point BuiltinType");
109 llvm_unreachable(
"Invalid scalar type kind");
113 switch (
E->getStmtClass()) {
114 case Stmt::CXXNullPtrLiteralExprClass:
115 case Stmt::ImplicitValueInitExprClass:
117 case Stmt::InitListExprClass:
118 return cast<InitListExpr>(
E)->getNumInits() == 0;
119 case Stmt::CharacterLiteralClass:
120 return !cast<CharacterLiteral>(
E)->getValue();
121 case Stmt::CXXBoolLiteralExprClass:
122 return !cast<CXXBoolLiteralExpr>(
E)->getValue();
123 case Stmt::IntegerLiteralClass:
124 return !cast<IntegerLiteral>(
E)->getValue();
125 case Stmt::FloatingLiteralClass: {
126 llvm::APFloat Value = cast<FloatingLiteral>(
E)->getValue();
127 return Value.isZero() && !Value.isNegative();
135 auto *UnaryOp = dyn_cast<UnaryOperator>(
E);
136 if (UnaryOp && UnaryOp->getOpcode() == UO_Plus)
137 return UnaryOp->getSubExpr();
142 auto *InitList = dyn_cast<InitListExpr>(
E);
143 if (InitList && InitList->getNumInits() == 1)
144 return InitList->getInit(0)->IgnoreParenImpCasts();
155 if (E1->getStmtClass() != E2->getStmtClass())
158 switch (E1->getStmtClass()) {
159 case Stmt::UnaryOperatorClass:
160 return sameValue(cast<UnaryOperator>(E1)->getSubExpr(),
161 cast<UnaryOperator>(E2)->getSubExpr());
162 case Stmt::CharacterLiteralClass:
163 return cast<CharacterLiteral>(E1)->getValue() ==
164 cast<CharacterLiteral>(E2)->getValue();
165 case Stmt::CXXBoolLiteralExprClass:
166 return cast<CXXBoolLiteralExpr>(E1)->getValue() ==
167 cast<CXXBoolLiteralExpr>(E2)->getValue();
168 case Stmt::IntegerLiteralClass:
169 return cast<IntegerLiteral>(E1)->getValue() ==
170 cast<IntegerLiteral>(E2)->getValue();
171 case Stmt::FloatingLiteralClass:
172 return cast<FloatingLiteral>(E1)->getValue().bitwiseIsEqual(
173 cast<FloatingLiteral>(E2)->getValue());
174 case Stmt::StringLiteralClass:
175 return cast<StringLiteral>(E1)->getString() ==
176 cast<StringLiteral>(E2)->getString();
177 case Stmt::DeclRefExprClass:
178 return cast<DeclRefExpr>(E1)->getDecl() == cast<DeclRefExpr>(E2)->getDecl();
187 UseAssignment(Options.get(
"UseAssignment", false)),
188 IgnoreMacros(Options.getLocalOrGlobal(
"IgnoreMacros", true)) {}
198 anyOf(stringLiteral(), characterLiteral(), integerLiteral(),
199 unaryOperator(hasAnyOperatorName(
"+",
"-"),
200 hasUnaryOperand(integerLiteral())),
202 unaryOperator(hasAnyOperatorName(
"+",
"-"),
203 hasUnaryOperand(floatLiteral())),
204 cxxBoolLiteral(), cxxNullPtrLiteralExpr(), implicitValueInitExpr(),
205 declRefExpr(to(enumConstantDecl())));
208 anyOf(initListExpr(anyOf(allOf(initCountIs(1), hasInit(0, InitBase)),
209 initCountIs(0), hasType(arrayType()))),
213 cxxConstructorDecl(forEachConstructorInitializer(
215 forField(unless(anyOf(
216 getLangOpts().CPlusPlus20 ? unless(anything()) : isBitField(),
217 hasInClassInitializer(anything()),
218 hasParent(recordDecl(isUnion()))))),
219 withInitializer(Init))
224 cxxConstructorDecl(forEachConstructorInitializer(
225 cxxCtorInitializer(forField(hasInClassInitializer(anything())),
226 withInitializer(Init))
232 if (
const auto *Default =
233 Result.Nodes.getNodeAs<CXXCtorInitializer>(
"default"))
234 checkDefaultInit(Result, Default);
235 else if (
const auto *Existing =
236 Result.Nodes.getNodeAs<CXXCtorInitializer>(
"existing"))
237 checkExistingInit(Result, Existing);
239 llvm_unreachable(
"Bad Callback. No node provided.");
242void UseDefaultMemberInitCheck::checkDefaultInit(
243 const MatchFinder::MatchResult &Result,
const CXXCtorInitializer *Init) {
244 const FieldDecl *
Field = Init->getAnyMember();
248 const auto *ClassDecl = cast<CXXRecordDecl>(
Field->getParent());
249 if (llvm::count_if(ClassDecl->decls(), [](
const Decl *D) {
250 if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(D))
251 D = FTD->getTemplatedDecl();
252 if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(D))
253 return !Ctor->isCopyOrMoveConstructor();
258 SourceLocation StartLoc =
Field->getBeginLoc();
259 if (StartLoc.isMacroID() && IgnoreMacros)
262 SourceLocation FieldEnd =
263 Lexer::getLocForEndOfToken(
Field->getSourceRange().getEnd(), 0,
265 SourceLocation LParenEnd = Lexer::getLocForEndOfToken(
266 Init->getLParenLoc(), 0, *Result.SourceManager,
getLangOpts());
267 CharSourceRange InitRange =
268 CharSourceRange::getCharRange(LParenEnd, Init->getRParenLoc());
270 const Expr *InitExpression = Init->getInit();
271 const QualType InitType = InitExpression->getType();
273 const bool ValueInit =
274 isa<ImplicitValueInitExpr>(InitExpression) && !isa<ArrayType>(InitType);
275 const bool CanAssign =
276 UseAssignment && (!ValueInit || !InitType->isEnumeralType());
277 const bool NeedsBraces = !CanAssign || isa<ArrayType>(InitType);
280 diag(
Field->getLocation(),
"use default member initializer for %0")
284 Diag << FixItHint::CreateInsertion(FieldEnd,
" = ");
286 Diag << FixItHint::CreateInsertion(FieldEnd,
"{");
288 if (CanAssign && ValueInit)
291 Diag << FixItHint::CreateInsertionFromRange(FieldEnd, InitRange);
294 Diag << FixItHint::CreateInsertion(FieldEnd,
"}");
296 Diag << FixItHint::CreateRemoval(Init->getSourceRange());
299void UseDefaultMemberInitCheck::checkExistingInit(
300 const MatchFinder::MatchResult &Result,
const CXXCtorInitializer *Init) {
301 const FieldDecl *
Field = Init->getAnyMember();
306 diag(Init->getSourceLocation(),
"member initializer for %0 is redundant")
307 <<
Field << FixItHint::CreateRemoval(Init->getSourceRange());
const FunctionDecl * Decl
llvm::SmallString< 256U > Name
::clang::DynTypedNode Node
void store(ClangTidyOptions::OptionMap &Options, StringRef LocalName, StringRef Value) const
Stores an option with the check-local name LocalName with string value Value to Options.
Base class for all clang-tidy checks.
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.
const LangOptions & getLangOpts() const
Returns the language options from the context.
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
Should store all options supported by this check with their current values or default values for opti...
UseDefaultMemberInitCheck(StringRef Name, ClangTidyContext *Context)
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
AST_MATCHER_P(UserDefinedLiteral, hasLiteral, clang::ast_matchers::internal::Matcher< Expr >, InnerMatcher)
static bool sameValue(const Expr *E1, const Expr *E2)
static const Expr * getInitializer(const Expr *E)
static bool isZero(const Expr *E)
static StringRef getValueOfValueInit(const QualType InitType)
static const Expr * ignoreUnaryPlus(const Expr *E)
llvm::StringMap< ClangTidyValue > OptionMap