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