clang-tools  11.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 
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:
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)
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:
122  Constructor.getBody()->getBeginLoc(),
123  Context.getSourceManager(), Context.getLangOpts())
124  .getLocation();
125  break;
126  case InitializerPlacement::Before:
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 initializer.
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  auto IsUserProvidedNonDelegatingConstructor =
258  allOf(isUserProvided(),
259  unless(anyOf(isInstantiated(), isDelegatingConstructor())));
260  auto IsNonTrivialDefaultConstructor = allOf(
261  isDefaultConstructor(), unless(isUserProvided()),
262  hasParent(cxxRecordDecl(unless(isTriviallyDefaultConstructible()))));
263  Finder->addMatcher(
264  cxxConstructorDecl(isDefinition(),
265  anyOf(IsUserProvidedNonDelegatingConstructor,
266  IsNonTrivialDefaultConstructor))
267  .bind("ctor"),
268  this);
269 
270  // Match classes with a default constructor that is defaulted or is not in the
271  // AST.
272  Finder->addMatcher(
273  cxxRecordDecl(
274  isDefinition(), unless(isInstantiated()), hasDefaultConstructor(),
275  anyOf(has(cxxConstructorDecl(isDefaultConstructor(), isDefaulted(),
276  unless(isImplicit()))),
277  unless(has(cxxConstructorDecl()))),
279  .bind("record"),
280  this);
281 
282  auto HasDefaultConstructor = hasInitializer(
283  cxxConstructExpr(unless(requiresZeroInitialization()),
284  hasDeclaration(cxxConstructorDecl(
285  isDefaultConstructor(), unless(isUserProvided())))));
286  Finder->addMatcher(
287  varDecl(isDefinition(), HasDefaultConstructor,
288  hasAutomaticStorageDuration(),
289  hasType(recordDecl(has(fieldDecl()),
291  .bind("var"),
292  this);
293 }
294 
295 void ProTypeMemberInitCheck::check(const MatchFinder::MatchResult &Result) {
296  if (const auto *Ctor = Result.Nodes.getNodeAs<CXXConstructorDecl>("ctor")) {
297  // Skip declarations delayed by late template parsing without a body.
298  if (!Ctor->getBody())
299  return;
300  checkMissingMemberInitializer(*Result.Context, *Ctor->getParent(), Ctor);
301  checkMissingBaseClassInitializer(*Result.Context, *Ctor->getParent(), Ctor);
302  } else if (const auto *Record =
303  Result.Nodes.getNodeAs<CXXRecordDecl>("record")) {
304  assert(Record->hasDefaultConstructor() &&
305  "Matched record should have a default constructor");
306  checkMissingMemberInitializer(*Result.Context, *Record, nullptr);
307  checkMissingBaseClassInitializer(*Result.Context, *Record, nullptr);
308  } else if (const auto *Var = Result.Nodes.getNodeAs<VarDecl>("var")) {
309  checkUninitializedTrivialType(*Result.Context, Var);
310  }
311 }
312 
314  Options.store(Opts, "IgnoreArrays", IgnoreArrays);
315  Options.store(Opts, "UseAssignment", UseAssignment);
316 }
317 
318 // FIXME: Copied from clang/lib/Sema/SemaDeclCXX.cpp.
319 static bool isIncompleteOrZeroLengthArrayType(ASTContext &Context, QualType T) {
320  if (T->isIncompleteArrayType())
321  return true;
322 
323  while (const ConstantArrayType *ArrayT = Context.getAsConstantArrayType(T)) {
324  if (!ArrayT->getSize())
325  return true;
326 
327  T = ArrayT->getElementType();
328  }
329 
330  return false;
331 }
332 
333 static bool isEmpty(ASTContext &Context, const QualType &Type) {
334  if (const CXXRecordDecl *ClassDecl = Type->getAsCXXRecordDecl()) {
335  return ClassDecl->isEmpty();
336  }
337  return isIncompleteOrZeroLengthArrayType(Context, Type);
338 }
339 
340 static const char *getInitializer(QualType QT, bool UseAssignment) {
341  const char *DefaultInitializer = "{}";
342  if (!UseAssignment)
343  return DefaultInitializer;
344 
345  if (QT->isPointerType())
346  return " = nullptr";
347 
348  const BuiltinType *BT =
349  dyn_cast<BuiltinType>(QT.getCanonicalType().getTypePtr());
350  if (!BT)
351  return DefaultInitializer;
352 
353  switch (BT->getKind()) {
354  case BuiltinType::Bool:
355  return " = false";
356  case BuiltinType::Float:
357  return " = 0.0F";
358  case BuiltinType::Double:
359  return " = 0.0";
360  case BuiltinType::LongDouble:
361  return " = 0.0L";
362  case BuiltinType::SChar:
363  case BuiltinType::Char_S:
364  case BuiltinType::WChar_S:
365  case BuiltinType::Char16:
366  case BuiltinType::Char32:
367  case BuiltinType::Short:
368  case BuiltinType::Int:
369  return " = 0";
370  case BuiltinType::UChar:
371  case BuiltinType::Char_U:
372  case BuiltinType::WChar_U:
373  case BuiltinType::UShort:
374  case BuiltinType::UInt:
375  return " = 0U";
376  case BuiltinType::Long:
377  return " = 0L";
378  case BuiltinType::ULong:
379  return " = 0UL";
380  case BuiltinType::LongLong:
381  return " = 0LL";
382  case BuiltinType::ULongLong:
383  return " = 0ULL";
384 
385  default:
386  return DefaultInitializer;
387  }
388 }
389 
390 void ProTypeMemberInitCheck::checkMissingMemberInitializer(
391  ASTContext &Context, const CXXRecordDecl &ClassDecl,
392  const CXXConstructorDecl *Ctor) {
393  bool IsUnion = ClassDecl.isUnion();
394 
395  if (IsUnion && ClassDecl.hasInClassInitializer())
396  return;
397 
398  // Gather all fields (direct and indirect) that need to be initialized.
399  SmallPtrSet<const FieldDecl *, 16> FieldsToInit;
400  forEachField(ClassDecl, ClassDecl.fields(), [&](const FieldDecl *F) {
401  if (!F->hasInClassInitializer() &&
403  Context) &&
404  !isEmpty(Context, F->getType()) && !F->isUnnamedBitfield())
405  FieldsToInit.insert(F);
406  });
407  if (FieldsToInit.empty())
408  return;
409 
410  if (Ctor) {
411  for (const CXXCtorInitializer *Init : Ctor->inits()) {
412  // Remove any fields that were explicitly written in the initializer list
413  // or in-class.
414  if (Init->isAnyMemberInitializer() && Init->isWritten()) {
415  if (IsUnion)
416  return; // We can only initialize one member of a union.
417  FieldsToInit.erase(Init->getAnyMember());
418  }
419  }
420  removeFieldsInitializedInBody(*Ctor->getBody(), Context, FieldsToInit);
421  }
422 
423  // Collect all fields in order, both direct fields and indirect fields from
424  // anonymous record types.
425  SmallVector<const FieldDecl *, 16> OrderedFields;
426  forEachField(ClassDecl, ClassDecl.fields(),
427  [&](const FieldDecl *F) { OrderedFields.push_back(F); });
428 
429  // Collect all the fields we need to initialize, including indirect fields.
430  SmallPtrSet<const FieldDecl *, 16> AllFieldsToInit;
431  forEachField(ClassDecl, FieldsToInit,
432  [&](const FieldDecl *F) { AllFieldsToInit.insert(F); });
433  if (AllFieldsToInit.empty())
434  return;
435 
436  DiagnosticBuilder Diag =
437  diag(Ctor ? Ctor->getBeginLoc() : ClassDecl.getLocation(),
438  IsUnion
439  ? "union constructor should initialize one of these fields: %0"
440  : "constructor does not initialize these fields: %0")
441  << toCommaSeparatedString(OrderedFields, AllFieldsToInit);
442 
443  // Do not propose fixes for constructors in macros since we cannot place them
444  // correctly.
445  if (Ctor && Ctor->getBeginLoc().isMacroID())
446  return;
447 
448  // Collect all fields but only suggest a fix for the first member of unions,
449  // as initializing more than one union member is an error.
450  SmallPtrSet<const FieldDecl *, 16> FieldsToFix;
451  SmallPtrSet<const RecordDecl *, 4> UnionsSeen;
452  forEachField(ClassDecl, OrderedFields, [&](const FieldDecl *F) {
453  if (!FieldsToInit.count(F))
454  return;
455  // Don't suggest fixes for enums because we don't know a good default.
456  // Don't suggest fixes for bitfields because in-class initialization is not
457  // possible until C++20.
458  if (F->getType()->isEnumeralType() ||
459  (!getLangOpts().CPlusPlus20 && F->isBitField()))
460  return;
461  if (!F->getParent()->isUnion() || UnionsSeen.insert(F->getParent()).second)
462  FieldsToFix.insert(F);
463  });
464  if (FieldsToFix.empty())
465  return;
466 
467  // Use in-class initialization if possible.
468  if (Context.getLangOpts().CPlusPlus11) {
469  for (const FieldDecl *Field : FieldsToFix) {
470  Diag << FixItHint::CreateInsertion(
471  getLocationForEndOfToken(Context, Field->getSourceRange().getEnd()),
472  getInitializer(Field->getType(), UseAssignment));
473  }
474  } else if (Ctor) {
475  // Otherwise, rewrite the constructor's initializer list.
476  fixInitializerList(Context, Diag, Ctor, FieldsToFix);
477  }
478 }
479 
480 void ProTypeMemberInitCheck::checkMissingBaseClassInitializer(
481  const ASTContext &Context, const CXXRecordDecl &ClassDecl,
482  const CXXConstructorDecl *Ctor) {
483 
484  // Gather any base classes that need to be initialized.
485  SmallVector<const RecordDecl *, 4> AllBases;
486  SmallPtrSet<const RecordDecl *, 4> BasesToInit;
487  for (const CXXBaseSpecifier &Base : ClassDecl.bases()) {
488  if (const auto *BaseClassDecl = getCanonicalRecordDecl(Base.getType())) {
489  AllBases.emplace_back(BaseClassDecl);
490  if (!BaseClassDecl->field_empty() &&
492  Context))
493  BasesToInit.insert(BaseClassDecl);
494  }
495  }
496 
497  if (BasesToInit.empty())
498  return;
499 
500  // Remove any bases that were explicitly written in the initializer list.
501  if (Ctor) {
502  if (Ctor->isImplicit())
503  return;
504 
505  for (const CXXCtorInitializer *Init : Ctor->inits()) {
506  if (Init->isBaseInitializer() && Init->isWritten())
507  BasesToInit.erase(Init->getBaseClass()->getAsCXXRecordDecl());
508  }
509  }
510 
511  if (BasesToInit.empty())
512  return;
513 
514  DiagnosticBuilder Diag =
515  diag(Ctor ? Ctor->getBeginLoc() : ClassDecl.getLocation(),
516  "constructor does not initialize these bases: %0")
517  << toCommaSeparatedString(AllBases, BasesToInit);
518 
519  if (Ctor)
520  fixInitializerList(Context, Diag, Ctor, BasesToInit);
521 }
522 
523 void ProTypeMemberInitCheck::checkUninitializedTrivialType(
524  const ASTContext &Context, const VarDecl *Var) {
525  DiagnosticBuilder Diag =
526  diag(Var->getBeginLoc(), "uninitialized record type: %0") << Var;
527 
528  Diag << FixItHint::CreateInsertion(
529  getLocationForEndOfToken(Context, Var->getSourceRange().getEnd()),
530  Context.getLangOpts().CPlusPlus11 ? "{}" : " = {}");
531 }
532 
533 } // namespace cppcoreguidelines
534 } // namespace tidy
535 } // namespace clang
Base
std::unique_ptr< GlobalCompilationDatabase > Base
Definition: GlobalCompilationDatabaseTests.cpp:85
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:313
Type
NodeType Type
Definition: HTMLGenerator.cpp:73
Location
Definition: Modularize.cpp:383
clang::clangd::CompletionItemKind::Field
clang::tidy::ClangTidyCheck
Base class for all clang-tidy checks.
Definition: ClangTidyCheck.h:114
clang::clangd::HighlightingKind::Typedef
clang::tidy::cppcoreguidelines::join
static std::string join(ArrayRef< SpecialMemberFunctionsCheck::SpecialMemberFunctionKind > SMFS, llvm::StringRef AndOr)
Definition: SpecialMemberFunctionsCheck.cpp:83
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:295
Placement
InitializerPlacement Placement
Definition: ProTypeMemberInitCheck.cpp:159
clang::tidy::cppcoreguidelines::isIncompleteOrZeroLengthArrayType
static bool isIncompleteOrZeroLengthArrayType(ASTContext &Context, QualType T)
Definition: ProTypeMemberInitCheck.cpp:319
clang::tidy::ClangTidyCheck::getLangOpts
const LangOptions & getLangOpts() const
Returns the language options from the context.
Definition: ClangTidyCheck.h:475
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:17
Code
std::string Code
Definition: FindTargetTests.cpp:67
ProTypeMemberInitCheck.h
Decl
const FunctionDecl * Decl
Definition: AvoidBindCheck.cpp:100
clang::tidy::cppcoreguidelines::isEmpty
static bool isEmpty(ASTContext &Context, const QualType &Type)
Definition: ProTypeMemberInitCheck.cpp:333
clang::tidy::ClangTidyCheck::Options
OptionsView Options
Definition: ClangTidyCheck.h:471
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:27
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:55
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:340
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
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:152
clang::tidy::cppcoreguidelines::@288::InitializerPlacement
InitializerPlacement
Definition: ProTypeMemberInitCheck.cpp:89
Initializers
SmallVector< std::string, 4 > Initializers
Definition: ProTypeMemberInitCheck.cpp:161
clang::tidy::ClangTidyOptions::OptionMap
std::map< std::string, ClangTidyValue > OptionMap
Definition: ClangTidyOptions.h:111
Where
const CXXCtorInitializer * Where
Definition: ProTypeMemberInitCheck.cpp:160