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