clang-tools 10.0.0

ProTypeMemberInitCheck.cpp
Go to the documentation of this file.
1 //===--- ProTypeMemberInitCheck.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 "ProTypeMemberInitCheck.h"
10 #include "../utils/LexerUtils.h"
11 #include "../utils/Matchers.h"
12 #include "../utils/TypeTraits.h"
13 #include "clang/AST/ASTContext.h"
14 #include "clang/ASTMatchers/ASTMatchFinder.h"
15 #include "clang/Lex/Lexer.h"
16 #include "llvm/ADT/SmallPtrSet.h"
17
18 using namespace clang::ast_matchers;
19 using namespace clang::tidy::matchers;
20 using llvm::SmallPtrSet;
21 using llvm::SmallPtrSetImpl;
22
23 namespace clang {
24 namespace tidy {
25 namespace cppcoreguidelines {
26
27 namespace {
28
29 AST_MATCHER(CXXRecordDecl, hasDefaultConstructor) {
30 return Node.hasDefaultConstructor();
31 }
32
33 // Iterate over all the fields in a record type, both direct and indirect (e.g.
34 // if the record contains an anonymous struct).
35 template <typename T, typename Func>
36 void forEachField(const RecordDecl &Record, const T &Fields, Func &&Fn) {
37 for (const FieldDecl *F : Fields) {
38 if (F->isAnonymousStructOrUnion()) {
39 if (const CXXRecordDecl *R = F->getType()->getAsCXXRecordDecl())
40 forEachField(*R, R->fields(), Fn);
41 } else {
42 Fn(F);
43 }
44 }
45 }
46
47 void removeFieldsInitializedInBody(
48 const Stmt &Stmt, ASTContext &Context,
49 SmallPtrSetImpl<const FieldDecl *> &FieldDecls) {
50 auto Matches =
51 match(findAll(binaryOperator(
52 hasOperatorName("="),
53 hasLHS(memberExpr(member(fieldDecl().bind("fieldDecl")))))),
54 Stmt, Context);
55 for (const auto &Match : Matches)
56 FieldDecls.erase(Match.getNodeAs<FieldDecl>("fieldDecl"));
57 }
58
59 StringRef getName(const FieldDecl *Field) { return Field->getName(); }
60
61 StringRef getName(const RecordDecl *Record) {
62 // Get the typedef name if this is a C-style anonymous struct and typedef.
63 if (const TypedefNameDecl *Typedef = Record->getTypedefNameForAnonDecl())
64 return Typedef->getName();
65 return Record->getName();
66 }
67
68 // Creates comma separated list of decls requiring initialization in order of
69 // declaration.
70 template <typename R, typename T>
71 std::string
72 toCommaSeparatedString(const R &OrderedDecls,
73 const SmallPtrSetImpl<const T *> &DeclsToInit) {
74 SmallVector<StringRef, 16> Names;
75 for (const T *Decl : OrderedDecls) {
76 if (DeclsToInit.count(Decl))
77 Names.emplace_back(getName(Decl));
78 }
79 return llvm::join(Names.begin(), Names.end(), ", ");
80 }
81
82 SourceLocation getLocationForEndOfToken(const ASTContext &Context,
83 SourceLocation Location) {
84 return Lexer::getLocForEndOfToken(Location, 0, Context.getSourceManager(),
85 Context.getLangOpts());
86 }
87
88 // There are 3 kinds of insertion placements:
89 enum class InitializerPlacement {
90 // 1. The fields are inserted after an existing CXXCtorInitializer stored in
91 // Where. This will be the case whenever there is a written initializer before
92 // the fields available.
93 After,
94
95 // 2. The fields are inserted before the first existing initializer stored in
96 // Where.
97 Before,
98
99 // 3. There are no written initializers and the fields will be inserted before
100 // the constructor's body creating a new initializer list including the ':'.
101 New
102 };
103
104 // An InitializerInsertion contains a list of fields and/or base classes to
105 // insert into the initializer list of a constructor. We use this to ensure
106 // proper absolute ordering according to the class declaration relative to the
107 // (perhaps improper) ordering in the existing initializer list, if any.
108 struct IntializerInsertion {
109 IntializerInsertion(InitializerPlacement Placement,
110 const CXXCtorInitializer *Where)
111 : Placement(Placement), Where(Where) {}
112
113 SourceLocation getLocation(const ASTContext &Context,
114 const CXXConstructorDecl &Constructor) const {
115 assert((Where != nullptr || Placement == InitializerPlacement::New) &&
116 "Location should be relative to an existing initializer or this "
117 "insertion represents a new initializer list.");
118 SourceLocation Location;
119 switch (Placement) {
120 case InitializerPlacement::New:
121 Location = utils::lexer::getPreviousToken(
122 Constructor.getBody()->getBeginLoc(),
123 Context.getSourceManager(), Context.getLangOpts())
124 .getLocation();
125 break;
126 case InitializerPlacement::Before:
127 Location = utils::lexer::getPreviousToken(
128 Where->getSourceRange().getBegin(),
129 Context.getSourceManager(), Context.getLangOpts())
130 .getLocation();
131 break;
132 case InitializerPlacement::After:
133 Location = Where->getRParenLoc();
134 break;
135 }
136 return getLocationForEndOfToken(Context, Location);
137 }
138
139 std::string codeToInsert() const {
140 assert(!Initializers.empty() && "No initializers to insert");
141 std::string Code;
142 llvm::raw_string_ostream Stream(Code);
143 std::string joined =
144 llvm::join(Initializers.begin(), Initializers.end(), "(), ");
145 switch (Placement) {
146 case InitializerPlacement::New:
147 Stream << " : " << joined << "()";
148 break;
149 case InitializerPlacement::Before:
150 Stream << " " << joined << "(),";
151 break;
152 case InitializerPlacement::After:
153 Stream << ", " << joined << "()";
154 break;
155 }
156 return Stream.str();
157 }
158
159 InitializerPlacement Placement;
160 const CXXCtorInitializer *Where;
161 SmallVector<std::string, 4> Initializers;
162 };
163
164 // Convenience utility to get a RecordDecl from a QualType.
165 const RecordDecl *getCanonicalRecordDecl(const QualType &Type) {
166 if (const auto *RT = Type.getCanonicalType()->getAs<RecordType>())
167 return RT->getDecl();
168 return nullptr;
169 }
170
171 template <typename R, typename T>
172 SmallVector<IntializerInsertion, 16>
173 computeInsertions(const CXXConstructorDecl::init_const_range &Inits,
174 const R &OrderedDecls,
175 const SmallPtrSetImpl<const T *> &DeclsToInit) {
176 SmallVector<IntializerInsertion, 16> Insertions;
177 Insertions.emplace_back(InitializerPlacement::New, nullptr);
178
179 typename R::const_iterator Decl = std::begin(OrderedDecls);
180 for (const CXXCtorInitializer *Init : Inits) {
181 if (Init->isWritten()) {
182 if (Insertions.size() == 1)
183 Insertions.emplace_back(InitializerPlacement::Before, Init);
184
185 // Gets either the field or base class being initialized by the provided
186 // initializer.
187 const auto *InitDecl =
188 Init->isAnyMemberInitializer()
189 ? static_cast<const NamedDecl *>(Init->getAnyMember())
190 : Init->getBaseClass()->getAsCXXRecordDecl();
191
192 // Add all fields between current field up until the next intializer.
193 for (; Decl != std::end(OrderedDecls) && *Decl != InitDecl; ++Decl) {
194 if (const auto *D = dyn_cast<T>(*Decl)) {
195 if (DeclsToInit.count(D) > 0)
196 Insertions.back().Initializers.emplace_back(getName(D));
197 }
198 }
199
200 Insertions.emplace_back(InitializerPlacement::After, Init);
201 }
202 }
203
204 // Add remaining decls that require initialization.
205 for (; Decl != std::end(OrderedDecls); ++Decl) {
206 if (const auto *D = dyn_cast<T>(*Decl)) {
207 if (DeclsToInit.count(D) > 0)
208 Insertions.back().Initializers.emplace_back(getName(D));
209 }
210 }
211 return Insertions;
212 }
213
214 // Gets the list of bases and members that could possibly be initialized, in
215 // order as they appear in the class declaration.
216 void getInitializationsInOrder(const CXXRecordDecl &ClassDecl,
217 SmallVectorImpl<const NamedDecl *> &Decls) {
218 Decls.clear();
219 for (const auto &Base : ClassDecl.bases()) {
220 // Decl may be null if the base class is a template parameter.
221 if (const NamedDecl *Decl = getCanonicalRecordDecl(Base.getType())) {
222 Decls.emplace_back(Decl);
223 }
224 }
225 forEachField(ClassDecl, ClassDecl.fields(),
226 [&](const FieldDecl *F) { Decls.push_back(F); });
227 }
228
229 template <typename T>
230 void fixInitializerList(const ASTContext &Context, DiagnosticBuilder &Diag,
231 const CXXConstructorDecl *Ctor,
232 const SmallPtrSetImpl<const T *> &DeclsToInit) {
233 // Do not propose fixes in macros since we cannot place them correctly.
234 if (Ctor->getBeginLoc().isMacroID())
235 return;
236
237 SmallVector<const NamedDecl *, 16> OrderedDecls;
238 getInitializationsInOrder(*Ctor->getParent(), OrderedDecls);
239
240 for (const auto &Insertion :
241 computeInsertions(Ctor->inits(), OrderedDecls, DeclsToInit)) {
242 if (!Insertion.Initializers.empty())
243 Diag << FixItHint::CreateInsertion(Insertion.getLocation(Context, *Ctor),
244 Insertion.codeToInsert());
245 }
246 }
247
248 } // anonymous namespace
249
250 ProTypeMemberInitCheck::ProTypeMemberInitCheck(StringRef Name,
251 ClangTidyContext *Context)
252 : ClangTidyCheck(Name, Context),
253 IgnoreArrays(Options.get("IgnoreArrays", false)),
254 UseAssignment(Options.getLocalOrGlobal("UseAssignment", false)) {}
255
256 void ProTypeMemberInitCheck::registerMatchers(MatchFinder *Finder) {
257 if (!getLangOpts().CPlusPlus)
258 return;
259
260 auto IsUserProvidedNonDelegatingConstructor =
261 allOf(isUserProvided(),
262 unless(anyOf(isInstantiated(), isDelegatingConstructor())));
263 auto IsNonTrivialDefaultConstructor = allOf(
264 isDefaultConstructor(), unless(isUserProvided()),
265 hasParent(cxxRecordDecl(unless(isTriviallyDefaultConstructible()))));
266 Finder->addMatcher(
267 cxxConstructorDecl(isDefinition(),
268 anyOf(IsUserProvidedNonDelegatingConstructor,
269 IsNonTrivialDefaultConstructor))
270 .bind("ctor"),
271 this);
272
273 // Match classes with a default constructor that is defaulted or is not in the
274 // AST.
275 Finder->addMatcher(
276 cxxRecordDecl(
277 isDefinition(), unless(isInstantiated()), hasDefaultConstructor(),
278 anyOf(has(cxxConstructorDecl(isDefaultConstructor(), isDefaulted(),
279 unless(isImplicit()))),
280 unless(has(cxxConstructorDecl()))),
281 unless(isTriviallyDefaultConstructible()))
282 .bind("record"),
283 this);
284
285 auto HasDefaultConstructor = hasInitializer(
286 cxxConstructExpr(unless(requiresZeroInitialization()),
287 hasDeclaration(cxxConstructorDecl(
288 isDefaultConstructor(), unless(isUserProvided())))));
289 Finder->addMatcher(
290 varDecl(isDefinition(), HasDefaultConstructor,
291 hasAutomaticStorageDuration(),
292 hasType(recordDecl(has(fieldDecl()),
293 isTriviallyDefaultConstructible())))
294 .bind("var"),
295 this);
296 }
297
298 void ProTypeMemberInitCheck::check(const MatchFinder::MatchResult &Result) {
299 if (const auto *Ctor = Result.Nodes.getNodeAs<CXXConstructorDecl>("ctor")) {
300 // Skip declarations delayed by late template parsing without a body.
301 if (!Ctor->getBody())
302 return;
303 checkMissingMemberInitializer(*Result.Context, *Ctor->getParent(), Ctor);
304 checkMissingBaseClassInitializer(*Result.Context, *Ctor->getParent(), Ctor);
305 } else if (const auto *Record =
306 Result.Nodes.getNodeAs<CXXRecordDecl>("record")) {
307 assert(Record->hasDefaultConstructor() &&
308 "Matched record should have a default constructor");
309 checkMissingMemberInitializer(*Result.Context, *Record, nullptr);
310 checkMissingBaseClassInitializer(*Result.Context, *Record, nullptr);
311 } else if (const auto *Var = Result.Nodes.getNodeAs<VarDecl>("var")) {
312 checkUninitializedTrivialType(*Result.Context, Var);
313 }
314 }
315
316 void ProTypeMemberInitCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
317 Options.store(Opts, "IgnoreArrays", IgnoreArrays);
318 Options.store(Opts, "UseAssignment", UseAssignment);
319 }
320
321 // FIXME: Copied from clang/lib/Sema/SemaDeclCXX.cpp.
322 static bool isIncompleteOrZeroLengthArrayType(ASTContext &Context, QualType T) {
323 if (T->isIncompleteArrayType())
324 return true;
325
326 while (const ConstantArrayType *ArrayT = Context.getAsConstantArrayType(T)) {
327 if (!ArrayT->getSize())
328 return true;
329
330 T = ArrayT->getElementType();
331 }
332
333 return false;
334 }
335
336 static bool isEmpty(ASTContext &Context, const QualType &Type) {
337 if (const CXXRecordDecl *ClassDecl = Type->getAsCXXRecordDecl()) {
338 return ClassDecl->isEmpty();
339 }
340 return isIncompleteOrZeroLengthArrayType(Context, Type);
341 }
342
343 static const char *getInitializer(QualType QT, bool UseAssignment) {
344 const char *DefaultInitializer = "{}";
345 if (!UseAssignment)
346 return DefaultInitializer;
347
348 if (QT->isPointerType())
349 return " = nullptr";
350
351 const BuiltinType *BT =
352 dyn_cast<BuiltinType>(QT.getCanonicalType().getTypePtr());
353 if (!BT)
354 return DefaultInitializer;
355
356 switch (BT->getKind()) {
357 case BuiltinType::Bool:
358 return " = false";
359 case BuiltinType::Float:
360 return " = 0.0F";
361 case BuiltinType::Double:
362 return " = 0.0";
363 case BuiltinType::LongDouble:
364 return " = 0.0L";
365 case BuiltinType::SChar:
366 case BuiltinType::Char_S:
367 case BuiltinType::WChar_S:
368 case BuiltinType::Char16:
369 case BuiltinType::Char32:
370 case BuiltinType::Short:
371 case BuiltinType::Int:
372 return " = 0";
373 case BuiltinType::UChar:
374 case BuiltinType::Char_U:
375 case BuiltinType::WChar_U:
376 case BuiltinType::UShort:
377 case BuiltinType::UInt:
378 return " = 0U";
379 case BuiltinType::Long:
380 return " = 0L";
381 case BuiltinType::ULong:
382 return " = 0UL";
383 case BuiltinType::LongLong:
384 return " = 0LL";
385 case BuiltinType::ULongLong:
386 return " = 0ULL";
387
388 default:
389 return DefaultInitializer;
390 }
391 }
392
393 void ProTypeMemberInitCheck::checkMissingMemberInitializer(
394 ASTContext &Context, const CXXRecordDecl &ClassDecl,
395 const CXXConstructorDecl *Ctor) {
396 bool IsUnion = ClassDecl.isUnion();
397
398 if (IsUnion && ClassDecl.hasInClassInitializer())
399 return;
400
401 // Gather all fields (direct and indirect) that need to be initialized.
402 SmallPtrSet<const FieldDecl *, 16> FieldsToInit;
403 forEachField(ClassDecl, ClassDecl.fields(), [&](const FieldDecl *F) {
404 if (!F->hasInClassInitializer() &&
405 utils::type_traits::isTriviallyDefaultConstructible(F->getType(),
406 Context) &&
407 !isEmpty(Context, F->getType()) && !F->isUnnamedBitfield())
408 FieldsToInit.insert(F);
409 });
410 if (FieldsToInit.empty())
411 return;
412
413 if (Ctor) {
414 for (const CXXCtorInitializer *Init : Ctor->inits()) {
415 // Remove any fields that were explicitly written in the initializer list
416 // or in-class.
417 if (Init->isAnyMemberInitializer() && Init->isWritten()) {
418 if (IsUnion)
419 return; // We can only initialize one member of a union.
420 FieldsToInit.erase(Init->getAnyMember());
421 }
422 }
423 removeFieldsInitializedInBody(*Ctor->getBody(), Context, FieldsToInit);
424 }
425
426 // Collect all fields in order, both direct fields and indirect fields from
427 // anonymous record types.
428 SmallVector<const FieldDecl *, 16> OrderedFields;
429 forEachField(ClassDecl, ClassDecl.fields(),
430 [&](const FieldDecl *F) { OrderedFields.push_back(F); });
431
432 // Collect all the fields we need to initialize, including indirect fields.
433 SmallPtrSet<const FieldDecl *, 16> AllFieldsToInit;
434 forEachField(ClassDecl, FieldsToInit,
435 [&](const FieldDecl *F) { AllFieldsToInit.insert(F); });
436 if (AllFieldsToInit.empty())
437 return;
438
439 DiagnosticBuilder Diag =
440 diag(Ctor ? Ctor->getBeginLoc() : ClassDecl.getLocation(),
441 IsUnion
442 ? "union constructor should initialize one of these fields: %0"
443 : "constructor does not initialize these fields: %0")
444 << toCommaSeparatedString(OrderedFields, AllFieldsToInit);
445
446 // Do not propose fixes for constructors in macros since we cannot place them
447 // correctly.
448 if (Ctor && Ctor->getBeginLoc().isMacroID())
449 return;
450
451 // Collect all fields but only suggest a fix for the first member of unions,
452 // as initializing more than one union member is an error.
453 SmallPtrSet<const FieldDecl *, 16> FieldsToFix;
454 SmallPtrSet<const RecordDecl *, 4> UnionsSeen;
455 forEachField(ClassDecl, OrderedFields, [&](const FieldDecl *F) {
456 if (!FieldsToInit.count(F))
457 return;
458 // Don't suggest fixes for enums because we don't know a good default.
459 // Don't suggest fixes for bitfields because in-class initialization is not
460 // possible until C++2a.
461 if (F->getType()->isEnumeralType() ||
462 (!getLangOpts().CPlusPlus2a && F->isBitField()))
463 return;
464 if (!F->getParent()->isUnion() || UnionsSeen.insert(F->getParent()).second)
465 FieldsToFix.insert(F);
466 });
467 if (FieldsToFix.empty())
468 return;
469
470 // Use in-class initialization if possible.
471 if (Context.getLangOpts().CPlusPlus11) {
472 for (const FieldDecl *Field : FieldsToFix) {
473 Diag << FixItHint::CreateInsertion(
474 getLocationForEndOfToken(Context, Field->getSourceRange().getEnd()),
475 getInitializer(Field->getType(), UseAssignment));
476 }
477 } else if (Ctor) {
478 // Otherwise, rewrite the constructor's initializer list.
479 fixInitializerList(Context, Diag, Ctor, FieldsToFix);
480 }
481 }
482
483 void ProTypeMemberInitCheck::checkMissingBaseClassInitializer(
484 const ASTContext &Context, const CXXRecordDecl &ClassDecl,
485 const CXXConstructorDecl *Ctor) {
486
487 // Gather any base classes that need to be initialized.
488 SmallVector<const RecordDecl *, 4> AllBases;
489 SmallPtrSet<const RecordDecl *, 4> BasesToInit;
490 for (const CXXBaseSpecifier &Base : ClassDecl.bases()) {
491 if (const auto *BaseClassDecl = getCanonicalRecordDecl(Base.getType())) {
492 AllBases.emplace_back(BaseClassDecl);
493 if (!BaseClassDecl->field_empty() &&
494 utils::type_traits::isTriviallyDefaultConstructible(Base.getType(),
495 Context))
496 BasesToInit.insert(BaseClassDecl);
497 }
498 }
499
500 if (BasesToInit.empty())
501 return;
502
503 // Remove any bases that were explicitly written in the initializer list.
504 if (Ctor) {
505 if (Ctor->isImplicit())
506 return;
507
508 for (const CXXCtorInitializer *Init : Ctor->inits()) {
509 if (Init->isBaseInitializer() && Init->isWritten())
510 BasesToInit.erase(Init->getBaseClass()->getAsCXXRecordDecl());
511 }
512 }
513
514 if (BasesToInit.empty())
515 return;
516
517 DiagnosticBuilder Diag =
518 diag(Ctor ? Ctor->getBeginLoc() : ClassDecl.getLocation(),
519 "constructor does not initialize these bases: %0")
520 << toCommaSeparatedString(AllBases, BasesToInit);
521
522 if (Ctor)
523 fixInitializerList(Context, Diag, Ctor, BasesToInit);
524 }
525
526 void ProTypeMemberInitCheck::checkUninitializedTrivialType(
527 const ASTContext &Context, const VarDecl *Var) {
528 DiagnosticBuilder Diag =
529 diag(Var->getBeginLoc(), "uninitialized record type: %0") << Var;
530
531 Diag << FixItHint::CreateInsertion(
532 getLocationForEndOfToken(Context, Var->getSourceRange().getEnd()),
533 Context.getLangOpts().CPlusPlus11 ? "{}" : " = {}");
534 }
535
536 } // namespace cppcoreguidelines
537 } // namespace tidy
538 } // namespace clang
clang::ast_matchers
Definition: AbseilMatcher.h:14
Code
std::string Code
Definition: FindTargetTests.cpp:67
Decl
const FunctionDecl * Decl
Definition: AvoidBindCheck.cpp:93
clang::tidy::cppcoreguidelines::isIncompleteOrZeroLengthArrayType
static bool isIncompleteOrZeroLengthArrayType(ASTContext &Context, QualType T)
Definition: ProTypeMemberInitCheck.cpp:322
clang::tidy::utils::lexer::getPreviousToken
Token getPreviousToken(SourceLocation Location, const SourceManager &SM, const LangOptions &LangOpts, bool SkipComments)
Returns previous token or tok::unknown if not found.
Definition: LexerUtils.cpp:16
clang::doc::Record
llvm::SmallVector< uint64_t, 1024 > Record
Definition: BitcodeReader.cpp:18
clang::tidy::cppcoreguidelines::ProTypeMemberInitCheck::check
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
Definition: ProTypeMemberInitCheck.cpp:298
clang::ast_matchers::AST_MATCHER
AST_MATCHER(Expr, isMacroID)
Definition: PreferIsaOrDynCastInConditionalsCheck.cpp:18
clang::tidy::matchers
Definition: clang-tidy/utils/Matchers.h:17
clang::clangd::HighlightingKind::Typedef
clang::tidy::cppcoreguidelines::isEmpty
static bool isEmpty(ASTContext &Context, const QualType &Type)
Definition: ProTypeMemberInitCheck.cpp:336
clang::tidy::ClangTidyCheck
Base class for all clang-tidy checks.
Definition: ClangTidyCheck.h:47
clang::tidy::ClangTidyCheck::getLangOpts
const LangOptions & getLangOpts() const
Returns the language options from the context.
Definition: ClangTidyCheck.h:188
Initializers
SmallVector< std::string, 4 > Initializers
Definition: ProTypeMemberInitCheck.cpp:161
clang::tidy::ClangTidyCheck::Options
OptionsView Options
Definition: ClangTidyCheck.h:184
clang::tidy::cppcoreguidelines::ProTypeMemberInitCheck::storeOptions
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
Should store all options supported by this check with their current values or default values for opti...
Definition: ProTypeMemberInitCheck.cpp:316
clang::tidy::cppcoreguidelines::getInitializer
static const char * getInitializer(QualType QT, bool UseAssignment)
Definition: ProTypeMemberInitCheck.cpp:343
clang::clangd::match
std::vector< std::string > match(const SymbolIndex &I, const FuzzyFindRequest &Req, bool *Incomplete)
Definition: TestIndex.cpp:94
clang::tidy::ClangTidyCheck::OptionsView::store
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.
Definition: ClangTidyCheck.cpp:58
clang::tidy::utils::type_traits::isTriviallyDefaultConstructible
bool isTriviallyDefaultConstructible(QualType Type, const ASTContext &Context)
Returns true if Type is trivially default constructible.
Definition: TypeTraits.cpp:92
Where
const CXXCtorInitializer * Where
Definition: ProTypeMemberInitCheck.cpp:160
Name
static constexpr llvm::StringLiteral Name
Definition: UppercaseLiteralSuffixCheck.cpp:27
clang::tidy::ClangTidyOptions::OptionMap
std::map< std::string, std::string > OptionMap
Definition: ClangTidyOptions.h:97
clang::tidy::cppcoreguidelines::@272::InitializerPlacement
InitializerPlacement
Definition: ProTypeMemberInitCheck.cpp:89
clang::tidy::cppcoreguidelines::ProTypeMemberInitCheck::registerMatchers
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
Definition: ProTypeMemberInitCheck.cpp:256
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
ProTypeMemberInitCheck.h
clang::tidy::ClangTidyContext
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
Definition: ClangTidyDiagnosticConsumer.h:77
Placement
InitializerPlacement Placement
Definition: ProTypeMemberInitCheck.cpp:159
clang::tidy::cppcoreguidelines::join
static std::string join(ArrayRef< SpecialMemberFunctionsCheck::SpecialMemberFunctionKind > SMFS, llvm::StringRef AndOr)
Definition: SpecialMemberFunctionsCheck.cpp:81
Base
std::unique_ptr< GlobalCompilationDatabase > Base
Definition: GlobalCompilationDatabaseTests.cpp:83
Type
NodeType Type
Definition: HTMLGenerator.cpp:73
clang::tidy::ClangTidyCheck::diag
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check&#39;s name.
Definition: ClangTidyCheck.cpp:21
Location
Definition: Modularize.cpp:383