]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/UninitializedObjectChecker.cpp
Merge clang 7.0.1 and several follow-up changes
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / clang / lib / StaticAnalyzer / Checkers / UninitializedObjectChecker.cpp
1 //===----- UninitializedObjectChecker.cpp ------------------------*- C++ -*-==//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file defines a checker that reports uninitialized fields in objects
11 // created after a constructor call.
12 //
13 // This checker has two options:
14 //   - "Pedantic" (boolean). If its not set or is set to false, the checker
15 //     won't emit warnings for objects that don't have at least one initialized
16 //     field. This may be set with
17 //
18 //  `-analyzer-config alpha.cplusplus.UninitializedObject:Pedantic=true`.
19 //
20 //   - "NotesAsWarnings" (boolean). If set to true, the checker will emit a
21 //     warning for each uninitalized field, as opposed to emitting one warning
22 //     per constructor call, and listing the uninitialized fields that belongs
23 //     to it in notes. Defaults to false.
24 //
25 //  `-analyzer-config alpha.cplusplus.UninitializedObject:NotesAsWarnings=true`.
26 //
27 //===----------------------------------------------------------------------===//
28
29 #include "ClangSACheckers.h"
30 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
31 #include "clang/StaticAnalyzer/Core/Checker.h"
32 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
33 #include <algorithm>
34
35 using namespace clang;
36 using namespace clang::ento;
37
38 namespace {
39
40 class UninitializedObjectChecker : public Checker<check::EndFunction> {
41   std::unique_ptr<BuiltinBug> BT_uninitField;
42
43 public:
44   // These fields will be initialized when registering the checker.
45   bool IsPedantic;
46   bool ShouldConvertNotesToWarnings;
47
48   UninitializedObjectChecker()
49       : BT_uninitField(new BuiltinBug(this, "Uninitialized fields")) {}
50   void checkEndFunction(const ReturnStmt *RS, CheckerContext &C) const;
51 };
52
53 /// Represents a field chain. A field chain is a vector of fields where the
54 /// first element of the chain is the object under checking (not stored), and
55 /// every other element is a field, and the element that precedes it is the
56 /// object that contains it.
57 ///
58 /// Note that this class is immutable, and new fields may only be added through
59 /// constructor calls.
60 class FieldChainInfo {
61   using FieldChain = llvm::ImmutableList<const FieldRegion *>;
62
63   FieldChain Chain;
64
65   const bool IsDereferenced = false;
66
67 public:
68   FieldChainInfo() = default;
69
70   FieldChainInfo(const FieldChainInfo &Other, const bool IsDereferenced)
71       : Chain(Other.Chain), IsDereferenced(IsDereferenced) {}
72
73   FieldChainInfo(const FieldChainInfo &Other, const FieldRegion *FR,
74                  const bool IsDereferenced = false);
75
76   bool contains(const FieldRegion *FR) const { return Chain.contains(FR); }
77   bool isPointer() const;
78
79   /// If this is a fieldchain whose last element is an uninitialized region of a
80   /// pointer type, `IsDereferenced` will store whether the pointer itself or
81   /// the pointee is uninitialized.
82   bool isDereferenced() const;
83   const FieldDecl *getEndOfChain() const;
84   void print(llvm::raw_ostream &Out) const;
85
86 private:
87   /// Prints every element except the last to `Out`. Since ImmutableLists store
88   /// elements in reverse order, and have no reverse iterators, we use a
89   /// recursive function to print the fieldchain correctly. The last element in
90   /// the chain is to be printed by `print`.
91   static void printTail(llvm::raw_ostream &Out,
92                         const llvm::ImmutableListImpl<const FieldRegion *> *L);
93   friend struct FieldChainInfoComparator;
94 };
95
96 struct FieldChainInfoComparator {
97   bool operator()(const FieldChainInfo &lhs, const FieldChainInfo &rhs) const {
98     assert(!lhs.Chain.isEmpty() && !rhs.Chain.isEmpty() &&
99            "Attempted to store an empty fieldchain!");
100     return *lhs.Chain.begin() < *rhs.Chain.begin();
101   }
102 };
103
104 using UninitFieldSet = std::set<FieldChainInfo, FieldChainInfoComparator>;
105
106 /// Searches for and stores uninitialized fields in a non-union object.
107 class FindUninitializedFields {
108   ProgramStateRef State;
109   const TypedValueRegion *const ObjectR;
110
111   const bool IsPedantic;
112   bool IsAnyFieldInitialized = false;
113
114   UninitFieldSet UninitFields;
115
116 public:
117   FindUninitializedFields(ProgramStateRef State,
118                           const TypedValueRegion *const R, bool IsPedantic);
119   const UninitFieldSet &getUninitFields();
120
121 private:
122   /// Adds a FieldChainInfo object to UninitFields. Return true if an insertion
123   /// took place.
124   bool addFieldToUninits(FieldChainInfo LocalChain);
125
126   // For the purposes of this checker, we'll regard the object under checking as
127   // a directed tree, where
128   //   * the root is the object under checking
129   //   * every node is an object that is
130   //     - a union
131   //     - a non-union record
132   //     - a pointer/reference
133   //     - an array
134   //     - of a primitive type, which we'll define later in a helper function.
135   //   * the parent of each node is the object that contains it
136   //   * every leaf is an array, a primitive object, a nullptr or an undefined
137   //   pointer.
138   //
139   // Example:
140   //
141   //   struct A {
142   //      struct B {
143   //        int x, y = 0;
144   //      };
145   //      B b;
146   //      int *iptr = new int;
147   //      B* bptr;
148   //
149   //      A() {}
150   //   };
151   //
152   // The directed tree:
153   //
154   //           ->x
155   //          /
156   //      ->b--->y
157   //     /
158   //    A-->iptr->(int value)
159   //     \
160   //      ->bptr
161   //
162   // From this we'll construct a vector of fieldchains, where each fieldchain
163   // represents an uninitialized field. An uninitialized field may be a
164   // primitive object, a pointer, a pointee or a union without a single
165   // initialized field.
166   // In the above example, for the default constructor call we'll end up with
167   // these fieldchains:
168   //
169   //   this->b.x
170   //   this->iptr (pointee uninit)
171   //   this->bptr (pointer uninit)
172   //
173   // We'll traverse each node of the above graph with the appropiate one of
174   // these methods:
175
176   /// This method checks a region of a union object, and returns true if no
177   /// field is initialized within the region.
178   bool isUnionUninit(const TypedValueRegion *R);
179
180   /// This method checks a region of a non-union object, and returns true if
181   /// an uninitialized field is found within the region.
182   bool isNonUnionUninit(const TypedValueRegion *R, FieldChainInfo LocalChain);
183
184   /// This method checks a region of a pointer or reference object, and returns
185   /// true if the ptr/ref object itself or any field within the pointee's region
186   /// is uninitialized.
187   bool isPointerOrReferenceUninit(const FieldRegion *FR,
188                                   FieldChainInfo LocalChain);
189
190   /// This method returns true if the value of a primitive object is
191   /// uninitialized.
192   bool isPrimitiveUninit(const SVal &V);
193
194   // Note that we don't have a method for arrays -- the elements of an array are
195   // often left uninitialized intentionally even when it is of a C++ record
196   // type, so we'll assume that an array is always initialized.
197   // TODO: Add a support for nonloc::LocAsInteger.
198 };
199
200 } // end of anonymous namespace
201
202 // Static variable instantionations.
203
204 static llvm::ImmutableListFactory<const FieldRegion *> Factory;
205
206 // Utility function declarations.
207
208 /// Returns the object that was constructed by CtorDecl, or None if that isn't
209 /// possible.
210 static Optional<nonloc::LazyCompoundVal>
211 getObjectVal(const CXXConstructorDecl *CtorDecl, CheckerContext &Context);
212
213 /// Checks whether the constructor under checking is called by another
214 /// constructor.
215 static bool isCalledByConstructor(const CheckerContext &Context);
216
217 /// Returns whether FD can be (transitively) dereferenced to a void pointer type
218 /// (void*, void**, ...). The type of the region behind a void pointer isn't
219 /// known, and thus FD can not be analyzed.
220 static bool isVoidPointer(const FieldDecl *FD);
221
222 /// Returns true if T is a primitive type. We defined this type so that for
223 /// objects that we'd only like analyze as much as checking whether their
224 /// value is undefined or not, such as ints and doubles, can be analyzed with
225 /// ease. This also helps ensuring that every special field type is handled
226 /// correctly.
227 static bool isPrimitiveType(const QualType &T) {
228   return T->isBuiltinType() || T->isEnumeralType() || T->isMemberPointerType();
229 }
230
231 /// Constructs a note message for a given FieldChainInfo object.
232 static void printNoteMessage(llvm::raw_ostream &Out,
233                              const FieldChainInfo &Chain);
234
235 /// Returns with Field's name. This is a helper function to get the correct name
236 /// even if Field is a captured lambda variable.
237 static StringRef getVariableName(const FieldDecl *Field);
238
239 //===----------------------------------------------------------------------===//
240 //                  Methods for UninitializedObjectChecker.
241 //===----------------------------------------------------------------------===//
242
243 void UninitializedObjectChecker::checkEndFunction(
244     const ReturnStmt *RS, CheckerContext &Context) const {
245
246   const auto *CtorDecl = dyn_cast_or_null<CXXConstructorDecl>(
247       Context.getLocationContext()->getDecl());
248   if (!CtorDecl)
249     return;
250
251   if (!CtorDecl->isUserProvided())
252     return;
253
254   if (CtorDecl->getParent()->isUnion())
255     return;
256
257   // This avoids essentially the same error being reported multiple times.
258   if (isCalledByConstructor(Context))
259     return;
260
261   Optional<nonloc::LazyCompoundVal> Object = getObjectVal(CtorDecl, Context);
262   if (!Object)
263     return;
264
265   FindUninitializedFields F(Context.getState(), Object->getRegion(),
266                             IsPedantic);
267
268   const UninitFieldSet &UninitFields = F.getUninitFields();
269
270   if (UninitFields.empty())
271     return;
272
273   // There are uninitialized fields in the record.
274
275   ExplodedNode *Node = Context.generateNonFatalErrorNode(Context.getState());
276   if (!Node)
277     return;
278
279   PathDiagnosticLocation LocUsedForUniqueing;
280   const Stmt *CallSite = Context.getStackFrame()->getCallSite();
281   if (CallSite)
282     LocUsedForUniqueing = PathDiagnosticLocation::createBegin(
283         CallSite, Context.getSourceManager(), Node->getLocationContext());
284
285   // For Plist consumers that don't support notes just yet, we'll convert notes
286   // to warnings.
287   if (ShouldConvertNotesToWarnings) {
288     for (const auto &Chain : UninitFields) {
289       SmallString<100> WarningBuf;
290       llvm::raw_svector_ostream WarningOS(WarningBuf);
291
292       printNoteMessage(WarningOS, Chain);
293
294       auto Report = llvm::make_unique<BugReport>(
295           *BT_uninitField, WarningOS.str(), Node, LocUsedForUniqueing,
296           Node->getLocationContext()->getDecl());
297       Context.emitReport(std::move(Report));
298     }
299     return;
300   }
301
302   SmallString<100> WarningBuf;
303   llvm::raw_svector_ostream WarningOS(WarningBuf);
304   WarningOS << UninitFields.size() << " uninitialized field"
305             << (UninitFields.size() == 1 ? "" : "s")
306             << " at the end of the constructor call";
307
308   auto Report = llvm::make_unique<BugReport>(
309       *BT_uninitField, WarningOS.str(), Node, LocUsedForUniqueing,
310       Node->getLocationContext()->getDecl());
311
312   for (const auto &Chain : UninitFields) {
313     SmallString<200> NoteBuf;
314     llvm::raw_svector_ostream NoteOS(NoteBuf);
315
316     printNoteMessage(NoteOS, Chain);
317
318     Report->addNote(NoteOS.str(),
319                     PathDiagnosticLocation::create(Chain.getEndOfChain(),
320                                                    Context.getSourceManager()));
321   }
322   Context.emitReport(std::move(Report));
323 }
324
325 //===----------------------------------------------------------------------===//
326 //                   Methods for FindUninitializedFields.
327 //===----------------------------------------------------------------------===//
328
329 FindUninitializedFields::FindUninitializedFields(
330     ProgramStateRef State, const TypedValueRegion *const R, bool IsPedantic)
331     : State(State), ObjectR(R), IsPedantic(IsPedantic) {}
332
333 const UninitFieldSet &FindUninitializedFields::getUninitFields() {
334   isNonUnionUninit(ObjectR, FieldChainInfo());
335
336   if (!IsPedantic && !IsAnyFieldInitialized)
337     UninitFields.clear();
338
339   return UninitFields;
340 }
341
342 bool FindUninitializedFields::addFieldToUninits(FieldChainInfo Chain) {
343   if (State->getStateManager().getContext().getSourceManager().isInSystemHeader(
344           Chain.getEndOfChain()->getLocation()))
345     return false;
346
347   return UninitFields.insert(Chain).second;
348 }
349
350 bool FindUninitializedFields::isNonUnionUninit(const TypedValueRegion *R,
351                                                FieldChainInfo LocalChain) {
352   assert(R->getValueType()->isRecordType() &&
353          !R->getValueType()->isUnionType() &&
354          "This method only checks non-union record objects!");
355
356   const RecordDecl *RD =
357       R->getValueType()->getAs<RecordType>()->getDecl()->getDefinition();
358   assert(RD && "Referred record has no definition");
359
360   bool ContainsUninitField = false;
361
362   // Are all of this non-union's fields initialized?
363   for (const FieldDecl *I : RD->fields()) {
364
365     const auto FieldVal =
366         State->getLValue(I, loc::MemRegionVal(R)).castAs<loc::MemRegionVal>();
367     const auto *FR = FieldVal.getRegionAs<FieldRegion>();
368     QualType T = I->getType();
369
370     // If LocalChain already contains FR, then we encountered a cyclic
371     // reference. In this case, region FR is already under checking at an
372     // earlier node in the directed tree.
373     if (LocalChain.contains(FR))
374       return false;
375
376     if (T->isStructureOrClassType()) {
377       if (isNonUnionUninit(FR, {LocalChain, FR}))
378         ContainsUninitField = true;
379       continue;
380     }
381
382     if (T->isUnionType()) {
383       if (isUnionUninit(FR)) {
384         if (addFieldToUninits({LocalChain, FR}))
385           ContainsUninitField = true;
386       } else
387         IsAnyFieldInitialized = true;
388       continue;
389     }
390
391     if (T->isArrayType()) {
392       IsAnyFieldInitialized = true;
393       continue;
394     }
395
396     if (T->isPointerType() || T->isReferenceType()) {
397       if (isPointerOrReferenceUninit(FR, LocalChain))
398         ContainsUninitField = true;
399       continue;
400     }
401
402     if (isPrimitiveType(T)) {
403       SVal V = State->getSVal(FieldVal);
404
405       if (isPrimitiveUninit(V)) {
406         if (addFieldToUninits({LocalChain, FR}))
407           ContainsUninitField = true;
408       }
409       continue;
410     }
411
412     llvm_unreachable("All cases are handled!");
413   }
414
415   // Checking bases.
416   // FIXME: As of now, because of `isCalledByConstructor`, objects whose type
417   // is a descendant of another type will emit warnings for uninitalized
418   // inherited members.
419   // This is not the only way to analyze bases of an object -- if we didn't
420   // filter them out, and didn't analyze the bases, this checker would run for
421   // each base of the object in order of base initailization and in theory would
422   // find every uninitalized field. This approach could also make handling
423   // diamond inheritances more easily.
424   //
425   // This rule (that a descendant type's cunstructor is responsible for
426   // initializing inherited data members) is not obvious, and should it should
427   // be.
428   const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD);
429   if (!CXXRD)
430     return ContainsUninitField;
431
432   for (const CXXBaseSpecifier &BaseSpec : CXXRD->bases()) {
433     const auto *BaseRegion = State->getLValue(BaseSpec, R)
434                                  .castAs<loc::MemRegionVal>()
435                                  .getRegionAs<TypedValueRegion>();
436
437     if (isNonUnionUninit(BaseRegion, LocalChain))
438       ContainsUninitField = true;
439   }
440
441   return ContainsUninitField;
442 }
443
444 bool FindUninitializedFields::isUnionUninit(const TypedValueRegion *R) {
445   assert(R->getValueType()->isUnionType() &&
446          "This method only checks union objects!");
447   // TODO: Implement support for union fields.
448   return false;
449 }
450
451 // Note that pointers/references don't contain fields themselves, so in this
452 // function we won't add anything to LocalChain.
453 bool FindUninitializedFields::isPointerOrReferenceUninit(
454     const FieldRegion *FR, FieldChainInfo LocalChain) {
455
456   assert((FR->getDecl()->getType()->isPointerType() ||
457           FR->getDecl()->getType()->isReferenceType()) &&
458          "This method only checks pointer/reference objects!");
459
460   SVal V = State->getSVal(FR);
461
462   if (V.isUnknown() || V.isZeroConstant()) {
463     IsAnyFieldInitialized = true;
464     return false;
465   }
466
467   if (V.isUndef()) {
468     return addFieldToUninits({LocalChain, FR});
469   }
470
471   const FieldDecl *FD = FR->getDecl();
472
473   // TODO: The dynamic type of a void pointer may be retrieved with
474   // `getDynamicTypeInfo`.
475   if (isVoidPointer(FD)) {
476     IsAnyFieldInitialized = true;
477     return false;
478   }
479
480   assert(V.getAs<Loc>() && "V should be Loc at this point!");
481
482   // At this point the pointer itself is initialized and points to a valid
483   // location, we'll now check the pointee.
484   SVal DerefdV = State->getSVal(V.castAs<Loc>());
485
486   // TODO: Dereferencing should be done according to the dynamic type.
487   while (Optional<Loc> L = DerefdV.getAs<Loc>()) {
488     DerefdV = State->getSVal(*L);
489   }
490
491   // If V is a pointer pointing to a record type.
492   if (Optional<nonloc::LazyCompoundVal> RecordV =
493           DerefdV.getAs<nonloc::LazyCompoundVal>()) {
494
495     const TypedValueRegion *R = RecordV->getRegion();
496
497     // We can't reason about symbolic regions, assume its initialized.
498     // Note that this also avoids a potential infinite recursion, because
499     // constructors for list-like classes are checked without being called, and
500     // the Static Analyzer will construct a symbolic region for Node *next; or
501     // similar code snippets.
502     if (R->getSymbolicBase()) {
503       IsAnyFieldInitialized = true;
504       return false;
505     }
506
507     const QualType T = R->getValueType();
508
509     if (T->isStructureOrClassType())
510       return isNonUnionUninit(R, {LocalChain, FR});
511
512     if (T->isUnionType()) {
513       if (isUnionUninit(R)) {
514         return addFieldToUninits({LocalChain, FR, /*IsDereferenced*/ true});
515       } else {
516         IsAnyFieldInitialized = true;
517         return false;
518       }
519     }
520
521     if (T->isArrayType()) {
522       IsAnyFieldInitialized = true;
523       return false;
524     }
525
526     llvm_unreachable("All cases are handled!");
527   }
528
529   // TODO: If possible, it should be asserted that the DerefdV at this point is
530   // primitive.
531
532   if (isPrimitiveUninit(DerefdV))
533     return addFieldToUninits({LocalChain, FR, /*IsDereferenced*/ true});
534
535   IsAnyFieldInitialized = true;
536   return false;
537 }
538
539 bool FindUninitializedFields::isPrimitiveUninit(const SVal &V) {
540   if (V.isUndef())
541     return true;
542
543   IsAnyFieldInitialized = true;
544   return false;
545 }
546
547 //===----------------------------------------------------------------------===//
548 //                       Methods for FieldChainInfo.
549 //===----------------------------------------------------------------------===//
550
551 FieldChainInfo::FieldChainInfo(const FieldChainInfo &Other,
552                                const FieldRegion *FR, const bool IsDereferenced)
553     : FieldChainInfo(Other, IsDereferenced) {
554   assert(!contains(FR) && "Can't add a field that is already a part of the "
555                           "fieldchain! Is this a cyclic reference?");
556   Chain = Factory.add(FR, Other.Chain);
557 }
558
559 bool FieldChainInfo::isPointer() const {
560   assert(!Chain.isEmpty() && "Empty fieldchain!");
561   return (*Chain.begin())->getDecl()->getType()->isPointerType();
562 }
563
564 bool FieldChainInfo::isDereferenced() const {
565   assert(isPointer() && "Only pointers may or may not be dereferenced!");
566   return IsDereferenced;
567 }
568
569 const FieldDecl *FieldChainInfo::getEndOfChain() const {
570   assert(!Chain.isEmpty() && "Empty fieldchain!");
571   return (*Chain.begin())->getDecl();
572 }
573
574 // TODO: This function constructs an incorrect fieldchain string in the
575 // following case:
576 //
577 //   struct Base { int x; };
578 //   struct D1 : Base {}; struct D2 : Base {};
579 //
580 //   struct MostDerived : D1, D2 {
581 //     MostDerived() {}
582 //   }
583 //
584 // A call to MostDerived::MostDerived() will cause two notes that say
585 // "uninitialized field 'this->x'", but we can't refer to 'x' directly,
586 // we need an explicit namespace resolution whether the uninit field was
587 // 'D1::x' or 'D2::x'.
588 void FieldChainInfo::print(llvm::raw_ostream &Out) const {
589   if (Chain.isEmpty())
590     return;
591
592   const llvm::ImmutableListImpl<const FieldRegion *> *L =
593       Chain.getInternalPointer();
594   printTail(Out, L->getTail());
595   Out << getVariableName(L->getHead()->getDecl());
596 }
597
598 void FieldChainInfo::printTail(
599     llvm::raw_ostream &Out,
600     const llvm::ImmutableListImpl<const FieldRegion *> *L) {
601   if (!L)
602     return;
603
604   printTail(Out, L->getTail());
605   const FieldDecl *Field = L->getHead()->getDecl();
606   Out << getVariableName(Field);
607   Out << (Field->getType()->isPointerType() ? "->" : ".");
608 }
609
610 //===----------------------------------------------------------------------===//
611 //                           Utility functions.
612 //===----------------------------------------------------------------------===//
613
614 static bool isVoidPointer(const FieldDecl *FD) {
615   QualType T = FD->getType();
616
617   while (!T.isNull()) {
618     if (T->isVoidPointerType())
619       return true;
620     T = T->getPointeeType();
621   }
622   return false;
623 }
624
625 static Optional<nonloc::LazyCompoundVal>
626 getObjectVal(const CXXConstructorDecl *CtorDecl, CheckerContext &Context) {
627
628   Loc ThisLoc = Context.getSValBuilder().getCXXThis(CtorDecl->getParent(),
629                                                     Context.getStackFrame());
630   // Getting the value for 'this'.
631   SVal This = Context.getState()->getSVal(ThisLoc);
632
633   // Getting the value for '*this'.
634   SVal Object = Context.getState()->getSVal(This.castAs<Loc>());
635
636   return Object.getAs<nonloc::LazyCompoundVal>();
637 }
638
639 // TODO: We should also check that if the constructor was called by another
640 // constructor, whether those two are in any relation to one another. In it's
641 // current state, this introduces some false negatives.
642 static bool isCalledByConstructor(const CheckerContext &Context) {
643   const LocationContext *LC = Context.getLocationContext()->getParent();
644
645   while (LC) {
646     if (isa<CXXConstructorDecl>(LC->getDecl()))
647       return true;
648
649     LC = LC->getParent();
650   }
651   return false;
652 }
653
654 static void printNoteMessage(llvm::raw_ostream &Out,
655                              const FieldChainInfo &Chain) {
656   if (Chain.isPointer()) {
657     if (Chain.isDereferenced())
658       Out << "uninitialized pointee 'this->";
659     else
660       Out << "uninitialized pointer 'this->";
661   } else
662     Out << "uninitialized field 'this->";
663   Chain.print(Out);
664   Out << "'";
665 }
666
667 static StringRef getVariableName(const FieldDecl *Field) {
668   // If Field is a captured lambda variable, Field->getName() will return with
669   // an empty string. We can however acquire it's name from the lambda's
670   // captures.
671   const auto *CXXParent = dyn_cast<CXXRecordDecl>(Field->getParent());
672
673   if (CXXParent && CXXParent->isLambda()) {
674     assert(CXXParent->captures_begin());
675     auto It = CXXParent->captures_begin() + Field->getFieldIndex();
676     return It->getCapturedVar()->getName();
677   }
678
679   return Field->getName();
680 }
681
682 void ento::registerUninitializedObjectChecker(CheckerManager &Mgr) {
683   auto Chk = Mgr.registerChecker<UninitializedObjectChecker>();
684   Chk->IsPedantic = Mgr.getAnalyzerOptions().getBooleanOption(
685       "Pedantic", /*DefaultVal*/ false, Chk);
686   Chk->ShouldConvertNotesToWarnings = Mgr.getAnalyzerOptions().getBooleanOption(
687       "NotesAsWarnings", /*DefaultVal*/ false, Chk);
688 }