xref: /llvm-project/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp (revision 7e3016dec4abd700e8e0828f1e20c86b0a04510b)
1 // RetainCountDiagnostics.cpp - Checks for leaks and other issues -*- 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 diagnostics for RetainCountChecker, which implements
11 //  a reference count checker for Core Foundation and Cocoa on (Mac OS X).
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "RetainCountDiagnostics.h"
16 #include "RetainCountChecker.h"
17 
18 using namespace clang;
19 using namespace ento;
20 using namespace retaincountchecker;
21 
22 static bool isNumericLiteralExpression(const Expr *E) {
23   // FIXME: This set of cases was copied from SemaExprObjC.
24   return isa<IntegerLiteral>(E) ||
25          isa<CharacterLiteral>(E) ||
26          isa<FloatingLiteral>(E) ||
27          isa<ObjCBoolLiteralExpr>(E) ||
28          isa<CXXBoolLiteralExpr>(E);
29 }
30 
31 /// If type represents a pointer to CXXRecordDecl,
32 /// and is not a typedef, return the decl name.
33 /// Otherwise, return the serialization of type.
34 static std::string getPrettyTypeName(QualType QT) {
35   QualType PT = QT->getPointeeType();
36   if (!PT.isNull() && !QT->getAs<TypedefType>())
37     if (const auto *RD = PT->getAsCXXRecordDecl())
38       return RD->getName();
39   return QT.getAsString();
40 }
41 
42 /// Write information about the type state change to {@code os},
43 /// return whether the note should be generated.
44 static bool shouldGenerateNote(llvm::raw_string_ostream &os,
45                                const RefVal *PrevT, const RefVal &CurrV,
46                                SmallVector<ArgEffect, 2> &AEffects) {
47   // Get the previous type state.
48   RefVal PrevV = *PrevT;
49 
50   // Specially handle -dealloc.
51   if (std::find(AEffects.begin(), AEffects.end(), Dealloc) != AEffects.end()) {
52     // Determine if the object's reference count was pushed to zero.
53     assert(!PrevV.hasSameState(CurrV) && "The state should have changed.");
54     // We may not have transitioned to 'release' if we hit an error.
55     // This case is handled elsewhere.
56     if (CurrV.getKind() == RefVal::Released) {
57       assert(CurrV.getCombinedCounts() == 0);
58       os << "Object released by directly sending the '-dealloc' message";
59       return true;
60     }
61   }
62 
63   // Determine if the typestate has changed.
64   if (!PrevV.hasSameState(CurrV))
65     switch (CurrV.getKind()) {
66     case RefVal::Owned:
67     case RefVal::NotOwned:
68       if (PrevV.getCount() == CurrV.getCount()) {
69         // Did an autorelease message get sent?
70         if (PrevV.getAutoreleaseCount() == CurrV.getAutoreleaseCount())
71           return false;
72 
73         assert(PrevV.getAutoreleaseCount() < CurrV.getAutoreleaseCount());
74         os << "Object autoreleased";
75         return true;
76       }
77 
78       if (PrevV.getCount() > CurrV.getCount())
79         os << "Reference count decremented.";
80       else
81         os << "Reference count incremented.";
82 
83       if (unsigned Count = CurrV.getCount())
84         os << " The object now has a +" << Count << " retain count.";
85 
86       return true;
87 
88     case RefVal::Released:
89       if (CurrV.getIvarAccessHistory() ==
90               RefVal::IvarAccessHistory::ReleasedAfterDirectAccess &&
91           CurrV.getIvarAccessHistory() != PrevV.getIvarAccessHistory()) {
92         os << "Strong instance variable relinquished. ";
93       }
94       os << "Object released.";
95       return true;
96 
97     case RefVal::ReturnedOwned:
98       // Autoreleases can be applied after marking a node ReturnedOwned.
99       if (CurrV.getAutoreleaseCount())
100         return false;
101 
102       os << "Object returned to caller as an owning reference (single "
103             "retain count transferred to caller)";
104       return true;
105 
106     case RefVal::ReturnedNotOwned:
107       os << "Object returned to caller with a +0 retain count";
108       return true;
109 
110     default:
111       return false;
112     }
113   return true;
114 }
115 
116 static void generateDiagnosticsForCallLike(ProgramStateRef CurrSt,
117                                            const LocationContext *LCtx,
118                                            const RefVal &CurrV, SymbolRef &Sym,
119                                            const Stmt *S,
120                                            llvm::raw_string_ostream &os) {
121   if (const CallExpr *CE = dyn_cast<CallExpr>(S)) {
122     // Get the name of the callee (if it is available)
123     // from the tracked SVal.
124     SVal X = CurrSt->getSValAsScalarOrLoc(CE->getCallee(), LCtx);
125     const FunctionDecl *FD = X.getAsFunctionDecl();
126 
127     // If failed, try to get it from AST.
128     if (!FD)
129       FD = dyn_cast<FunctionDecl>(CE->getCalleeDecl());
130 
131     if (const auto *MD = dyn_cast<CXXMethodDecl>(CE->getCalleeDecl())) {
132       os << "Call to method '" << MD->getQualifiedNameAsString() << '\'';
133     } else if (FD) {
134       os << "Call to function '" << FD->getQualifiedNameAsString() << '\'';
135     } else {
136       os << "function call";
137     }
138   } else if (isa<CXXNewExpr>(S)) {
139     os << "Operator 'new'";
140   } else {
141     assert(isa<ObjCMessageExpr>(S));
142     CallEventManager &Mgr = CurrSt->getStateManager().getCallEventManager();
143     CallEventRef<ObjCMethodCall> Call =
144         Mgr.getObjCMethodCall(cast<ObjCMessageExpr>(S), CurrSt, LCtx);
145 
146     switch (Call->getMessageKind()) {
147     case OCM_Message:
148       os << "Method";
149       break;
150     case OCM_PropertyAccess:
151       os << "Property";
152       break;
153     case OCM_Subscript:
154       os << "Subscript";
155       break;
156     }
157   }
158 
159   if (CurrV.getObjKind() == ObjKind::CF) {
160     os << " returns a Core Foundation object of type "
161        << Sym->getType().getAsString() << " with a ";
162   } else if (CurrV.getObjKind() == ObjKind::OS) {
163     os << " returns an OSObject of type " << getPrettyTypeName(Sym->getType())
164        << " with a ";
165   } else if (CurrV.getObjKind() == ObjKind::Generalized) {
166     os << " returns an object of type " << Sym->getType().getAsString()
167        << " with a ";
168   } else {
169     assert(CurrV.getObjKind() == ObjKind::ObjC);
170     QualType T = Sym->getType();
171     if (!isa<ObjCObjectPointerType>(T)) {
172       os << " returns an Objective-C object with a ";
173     } else {
174       const ObjCObjectPointerType *PT = cast<ObjCObjectPointerType>(T);
175       os << " returns an instance of " << PT->getPointeeType().getAsString()
176          << " with a ";
177     }
178   }
179 
180   if (CurrV.isOwned()) {
181     os << "+1 retain count";
182   } else {
183     assert(CurrV.isNotOwned());
184     os << "+0 retain count";
185   }
186 }
187 
188 namespace clang {
189 namespace ento {
190 namespace retaincountchecker {
191 
192 class CFRefReportVisitor : public BugReporterVisitor {
193 protected:
194   SymbolRef Sym;
195   const SummaryLogTy &SummaryLog;
196 
197 public:
198   CFRefReportVisitor(SymbolRef sym, const SummaryLogTy &log)
199       : Sym(sym), SummaryLog(log) {}
200 
201   void Profile(llvm::FoldingSetNodeID &ID) const override {
202     static int x = 0;
203     ID.AddPointer(&x);
204     ID.AddPointer(Sym);
205   }
206 
207   std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
208                                                  BugReporterContext &BRC,
209                                                  BugReport &BR) override;
210 
211   std::shared_ptr<PathDiagnosticPiece> getEndPath(BugReporterContext &BRC,
212                                                   const ExplodedNode *N,
213                                                   BugReport &BR) override;
214 };
215 
216 class CFRefLeakReportVisitor : public CFRefReportVisitor {
217 public:
218   CFRefLeakReportVisitor(SymbolRef sym,
219                          const SummaryLogTy &log)
220      : CFRefReportVisitor(sym, log) {}
221 
222   std::shared_ptr<PathDiagnosticPiece> getEndPath(BugReporterContext &BRC,
223                                                   const ExplodedNode *N,
224                                                   BugReport &BR) override;
225 };
226 
227 } // end namespace retaincountchecker
228 } // end namespace ento
229 } // end namespace clang
230 
231 
232 /// Find the first node with the parent stack frame.
233 static const ExplodedNode *getCalleeNode(const ExplodedNode *Pred) {
234   const StackFrameContext *SC = Pred->getStackFrame();
235   if (SC->inTopFrame())
236     return nullptr;
237   const StackFrameContext *PC = SC->getParent()->getStackFrame();
238   if (!PC)
239     return nullptr;
240 
241   const ExplodedNode *N = Pred;
242   while (N && N->getStackFrame() != PC) {
243     N = N->getFirstPred();
244   }
245   return N;
246 }
247 
248 
249 /// Insert a diagnostic piece at function exit
250 /// if a function parameter is annotated as "os_consumed",
251 /// but it does not actually consume the reference.
252 static std::shared_ptr<PathDiagnosticEventPiece>
253 annotateConsumedSummaryMismatch(const ExplodedNode *N,
254                                 CallExitBegin &CallExitLoc,
255                                 const SourceManager &SM,
256                                 CallEventManager &CEMgr) {
257 
258   const ExplodedNode *CN = getCalleeNode(N);
259   if (!CN)
260     return nullptr;
261 
262   CallEventRef<> Call = CEMgr.getCaller(N->getStackFrame(), N->getState());
263 
264   std::string sbuf;
265   llvm::raw_string_ostream os(sbuf);
266   ArrayRef<const ParmVarDecl *> Parameters = Call->parameters();
267   for (unsigned I=0; I < Call->getNumArgs() && I < Parameters.size(); ++I) {
268     const ParmVarDecl *PVD = Parameters[I];
269 
270     if (!PVD->hasAttr<OSConsumedAttr>())
271       continue;
272 
273     if (SymbolRef SR = Call->getArgSVal(I).getAsLocSymbol()) {
274       const RefVal *CountBeforeCall = getRefBinding(CN->getState(), SR);
275       const RefVal *CountAtExit = getRefBinding(N->getState(), SR);
276 
277       if (!CountBeforeCall || !CountAtExit)
278         continue;
279 
280       unsigned CountBefore = CountBeforeCall->getCount();
281       unsigned CountAfter = CountAtExit->getCount();
282 
283       bool AsExpected = CountBefore > 0 && CountAfter == CountBefore - 1;
284       if (!AsExpected) {
285         os << "Parameter '";
286         PVD->getNameForDiagnostic(os, PVD->getASTContext().getPrintingPolicy(),
287                                   /*Qualified=*/false);
288         os << "' is marked as consuming, but the function did not consume "
289            << "the reference\n";
290       }
291     }
292   }
293 
294   if (os.str().empty())
295     return nullptr;
296 
297   // FIXME: remove the code duplication with NoStoreFuncVisitor.
298   PathDiagnosticLocation L;
299   if (const ReturnStmt *RS = CallExitLoc.getReturnStmt()) {
300     L = PathDiagnosticLocation::createBegin(RS, SM, N->getLocationContext());
301   } else {
302     L = PathDiagnosticLocation(
303         Call->getRuntimeDefinition().getDecl()->getSourceRange().getEnd(), SM);
304   }
305 
306   return std::make_shared<PathDiagnosticEventPiece>(L, os.str());
307 }
308 
309 std::shared_ptr<PathDiagnosticPiece>
310 CFRefReportVisitor::VisitNode(const ExplodedNode *N,
311                               BugReporterContext &BRC, BugReport &BR) {
312   const SourceManager &SM = BRC.getSourceManager();
313   CallEventManager &CEMgr = BRC.getStateManager().getCallEventManager();
314   if (auto CE = N->getLocationAs<CallExitBegin>())
315     if (auto PD = annotateConsumedSummaryMismatch(N, *CE, SM, CEMgr))
316       return PD;
317 
318   // FIXME: We will eventually need to handle non-statement-based events
319   // (__attribute__((cleanup))).
320   if (!N->getLocation().getAs<StmtPoint>())
321     return nullptr;
322 
323   // Check if the type state has changed.
324   const ExplodedNode *PrevNode = N->getFirstPred();
325   ProgramStateRef PrevSt = PrevNode->getState();
326   ProgramStateRef CurrSt = N->getState();
327   const LocationContext *LCtx = N->getLocationContext();
328 
329   const RefVal* CurrT = getRefBinding(CurrSt, Sym);
330   if (!CurrT) return nullptr;
331 
332   const RefVal &CurrV = *CurrT;
333   const RefVal *PrevT = getRefBinding(PrevSt, Sym);
334 
335   // Create a string buffer to constain all the useful things we want
336   // to tell the user.
337   std::string sbuf;
338   llvm::raw_string_ostream os(sbuf);
339 
340   // This is the allocation site since the previous node had no bindings
341   // for this symbol.
342   if (!PrevT) {
343     const Stmt *S = N->getLocation().castAs<StmtPoint>().getStmt();
344 
345     if (isa<ObjCIvarRefExpr>(S) &&
346         isSynthesizedAccessor(LCtx->getStackFrame())) {
347       S = LCtx->getStackFrame()->getCallSite();
348     }
349 
350     if (isa<ObjCArrayLiteral>(S)) {
351       os << "NSArray literal is an object with a +0 retain count";
352     } else if (isa<ObjCDictionaryLiteral>(S)) {
353       os << "NSDictionary literal is an object with a +0 retain count";
354     } else if (const ObjCBoxedExpr *BL = dyn_cast<ObjCBoxedExpr>(S)) {
355       if (isNumericLiteralExpression(BL->getSubExpr()))
356         os << "NSNumber literal is an object with a +0 retain count";
357       else {
358         const ObjCInterfaceDecl *BoxClass = nullptr;
359         if (const ObjCMethodDecl *Method = BL->getBoxingMethod())
360           BoxClass = Method->getClassInterface();
361 
362         // We should always be able to find the boxing class interface,
363         // but consider this future-proofing.
364         if (BoxClass) {
365           os << *BoxClass << " b";
366         } else {
367           os << "B";
368         }
369 
370         os << "oxed expression produces an object with a +0 retain count";
371       }
372     } else if (isa<ObjCIvarRefExpr>(S)) {
373       os << "Object loaded from instance variable";
374     } else {
375       generateDiagnosticsForCallLike(CurrSt, LCtx, CurrV, Sym, S, os);
376     }
377 
378     PathDiagnosticLocation Pos(S, SM, N->getLocationContext());
379     return std::make_shared<PathDiagnosticEventPiece>(Pos, os.str());
380   }
381 
382   // Gather up the effects that were performed on the object at this
383   // program point
384   SmallVector<ArgEffect, 2> AEffects;
385   const ExplodedNode *OrigNode = BRC.getNodeResolver().getOriginalNode(N);
386   if (const RetainSummary *Summ = SummaryLog.lookup(OrigNode)) {
387     // We only have summaries attached to nodes after evaluating CallExpr and
388     // ObjCMessageExprs.
389     const Stmt *S = N->getLocation().castAs<StmtPoint>().getStmt();
390 
391     if (const CallExpr *CE = dyn_cast<CallExpr>(S)) {
392       // Iterate through the parameter expressions and see if the symbol
393       // was ever passed as an argument.
394       unsigned i = 0;
395 
396       for (auto AI=CE->arg_begin(), AE=CE->arg_end(); AI!=AE; ++AI, ++i) {
397 
398         // Retrieve the value of the argument.  Is it the symbol
399         // we are interested in?
400         if (CurrSt->getSValAsScalarOrLoc(*AI, LCtx).getAsLocSymbol() != Sym)
401           continue;
402 
403         // We have an argument.  Get the effect!
404         AEffects.push_back(Summ->getArg(i));
405       }
406     } else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S)) {
407       if (const Expr *receiver = ME->getInstanceReceiver()) {
408         if (CurrSt->getSValAsScalarOrLoc(receiver, LCtx)
409               .getAsLocSymbol() == Sym) {
410           // The symbol we are tracking is the receiver.
411           AEffects.push_back(Summ->getReceiverEffect());
412         }
413       }
414     }
415   }
416 
417   if (!shouldGenerateNote(os, PrevT, CurrV, AEffects))
418     return nullptr;
419 
420   if (os.str().empty())
421     return nullptr; // We have nothing to say!
422 
423   const Stmt *S = N->getLocation().castAs<StmtPoint>().getStmt();
424   PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
425                                 N->getLocationContext());
426   auto P = std::make_shared<PathDiagnosticEventPiece>(Pos, os.str());
427 
428   // Add the range by scanning the children of the statement for any bindings
429   // to Sym.
430   for (const Stmt *Child : S->children())
431     if (const Expr *Exp = dyn_cast_or_null<Expr>(Child))
432       if (CurrSt->getSValAsScalarOrLoc(Exp, LCtx).getAsLocSymbol() == Sym) {
433         P->addRange(Exp->getSourceRange());
434         break;
435       }
436 
437   return std::move(P);
438 }
439 
440 static Optional<std::string> describeRegion(const MemRegion *MR) {
441   if (const auto *VR = dyn_cast_or_null<VarRegion>(MR))
442     return std::string(VR->getDecl()->getName());
443   // Once we support more storage locations for bindings,
444   // this would need to be improved.
445   return None;
446 }
447 
448 namespace {
449 // Find the first node in the current function context that referred to the
450 // tracked symbol and the memory location that value was stored to. Note, the
451 // value is only reported if the allocation occurred in the same function as
452 // the leak. The function can also return a location context, which should be
453 // treated as interesting.
454 struct AllocationInfo {
455   const ExplodedNode* N;
456   const MemRegion *R;
457   const LocationContext *InterestingMethodContext;
458   AllocationInfo(const ExplodedNode *InN,
459                  const MemRegion *InR,
460                  const LocationContext *InInterestingMethodContext) :
461     N(InN), R(InR), InterestingMethodContext(InInterestingMethodContext) {}
462 };
463 } // end anonymous namespace
464 
465 static AllocationInfo GetAllocationSite(ProgramStateManager &StateMgr,
466                                         const ExplodedNode *N, SymbolRef Sym) {
467   const ExplodedNode *AllocationNode = N;
468   const ExplodedNode *AllocationNodeInCurrentOrParentContext = N;
469   const MemRegion *FirstBinding = nullptr;
470   const LocationContext *LeakContext = N->getLocationContext();
471 
472   // The location context of the init method called on the leaked object, if
473   // available.
474   const LocationContext *InitMethodContext = nullptr;
475 
476   while (N) {
477     ProgramStateRef St = N->getState();
478     const LocationContext *NContext = N->getLocationContext();
479 
480     if (!getRefBinding(St, Sym))
481       break;
482 
483     StoreManager::FindUniqueBinding FB(Sym);
484     StateMgr.iterBindings(St, FB);
485 
486     if (FB) {
487       const MemRegion *R = FB.getRegion();
488       // Do not show local variables belonging to a function other than
489       // where the error is reported.
490       if (auto MR = dyn_cast<StackSpaceRegion>(R->getMemorySpace()))
491         if (MR->getStackFrame() == LeakContext->getStackFrame())
492           FirstBinding = R;
493     }
494 
495     // AllocationNode is the last node in which the symbol was tracked.
496     AllocationNode = N;
497 
498     // AllocationNodeInCurrentContext, is the last node in the current or
499     // parent context in which the symbol was tracked.
500     //
501     // Note that the allocation site might be in the parent context. For example,
502     // the case where an allocation happens in a block that captures a reference
503     // to it and that reference is overwritten/dropped by another call to
504     // the block.
505     if (NContext == LeakContext || NContext->isParentOf(LeakContext))
506       AllocationNodeInCurrentOrParentContext = N;
507 
508     // Find the last init that was called on the given symbol and store the
509     // init method's location context.
510     if (!InitMethodContext)
511       if (auto CEP = N->getLocation().getAs<CallEnter>()) {
512         const Stmt *CE = CEP->getCallExpr();
513         if (const auto *ME = dyn_cast_or_null<ObjCMessageExpr>(CE)) {
514           const Stmt *RecExpr = ME->getInstanceReceiver();
515           if (RecExpr) {
516             SVal RecV = St->getSVal(RecExpr, NContext);
517             if (ME->getMethodFamily() == OMF_init && RecV.getAsSymbol() == Sym)
518               InitMethodContext = CEP->getCalleeContext();
519           }
520         }
521       }
522 
523     N = N->getFirstPred();
524   }
525 
526   // If we are reporting a leak of the object that was allocated with alloc,
527   // mark its init method as interesting.
528   const LocationContext *InterestingMethodContext = nullptr;
529   if (InitMethodContext) {
530     const ProgramPoint AllocPP = AllocationNode->getLocation();
531     if (Optional<StmtPoint> SP = AllocPP.getAs<StmtPoint>())
532       if (const ObjCMessageExpr *ME = SP->getStmtAs<ObjCMessageExpr>())
533         if (ME->getMethodFamily() == OMF_alloc)
534           InterestingMethodContext = InitMethodContext;
535   }
536 
537   // If allocation happened in a function different from the leak node context,
538   // do not report the binding.
539   assert(N && "Could not find allocation node");
540 
541   if (AllocationNodeInCurrentOrParentContext &&
542       AllocationNodeInCurrentOrParentContext->getLocationContext() !=
543           LeakContext)
544     FirstBinding = nullptr;
545 
546   return AllocationInfo(AllocationNodeInCurrentOrParentContext,
547                         FirstBinding,
548                         InterestingMethodContext);
549 }
550 
551 std::shared_ptr<PathDiagnosticPiece>
552 CFRefReportVisitor::getEndPath(BugReporterContext &BRC,
553                                const ExplodedNode *EndN, BugReport &BR) {
554   BR.markInteresting(Sym);
555   return BugReporterVisitor::getDefaultEndPath(BRC, EndN, BR);
556 }
557 
558 std::shared_ptr<PathDiagnosticPiece>
559 CFRefLeakReportVisitor::getEndPath(BugReporterContext &BRC,
560                                    const ExplodedNode *EndN, BugReport &BR) {
561 
562   // Tell the BugReporterContext to report cases when the tracked symbol is
563   // assigned to different variables, etc.
564   BR.markInteresting(Sym);
565 
566   // We are reporting a leak.  Walk up the graph to get to the first node where
567   // the symbol appeared, and also get the first VarDecl that tracked object
568   // is stored to.
569   AllocationInfo AllocI = GetAllocationSite(BRC.getStateManager(), EndN, Sym);
570 
571   const MemRegion* FirstBinding = AllocI.R;
572   BR.markInteresting(AllocI.InterestingMethodContext);
573 
574   SourceManager& SM = BRC.getSourceManager();
575 
576   // Compute an actual location for the leak.  Sometimes a leak doesn't
577   // occur at an actual statement (e.g., transition between blocks; end
578   // of function) so we need to walk the graph and compute a real location.
579   const ExplodedNode *LeakN = EndN;
580   PathDiagnosticLocation L = PathDiagnosticLocation::createEndOfPath(LeakN, SM);
581 
582   std::string sbuf;
583   llvm::raw_string_ostream os(sbuf);
584 
585   os << "Object leaked: ";
586 
587   Optional<std::string> RegionDescription = describeRegion(FirstBinding);
588   if (RegionDescription) {
589     os << "object allocated and stored into '" << *RegionDescription << '\'';
590   } else {
591     os << "allocated object of type " << getPrettyTypeName(Sym->getType());
592   }
593 
594   // Get the retain count.
595   const RefVal* RV = getRefBinding(EndN->getState(), Sym);
596   assert(RV);
597 
598   if (RV->getKind() == RefVal::ErrorLeakReturned) {
599     // FIXME: Per comments in rdar://6320065, "create" only applies to CF
600     // objects.  Only "copy", "alloc", "retain" and "new" transfer ownership
601     // to the caller for NS objects.
602     const Decl *D = &EndN->getCodeDecl();
603 
604     os << (isa<ObjCMethodDecl>(D) ? " is returned from a method "
605                                   : " is returned from a function ");
606 
607     if (D->hasAttr<CFReturnsNotRetainedAttr>()) {
608       os << "that is annotated as CF_RETURNS_NOT_RETAINED";
609     } else if (D->hasAttr<NSReturnsNotRetainedAttr>()) {
610       os << "that is annotated as NS_RETURNS_NOT_RETAINED";
611     } else if (D->hasAttr<OSReturnsNotRetainedAttr>()) {
612       os << "that is annotated as OS_RETURNS_NOT_RETAINED";
613     } else {
614       if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
615         if (BRC.getASTContext().getLangOpts().ObjCAutoRefCount) {
616           os << "managed by Automatic Reference Counting";
617         } else {
618           os << "whose name ('" << MD->getSelector().getAsString()
619              << "') does not start with "
620                 "'copy', 'mutableCopy', 'alloc' or 'new'."
621                 "  This violates the naming convention rules"
622                 " given in the Memory Management Guide for Cocoa";
623         }
624       } else {
625         const FunctionDecl *FD = cast<FunctionDecl>(D);
626         os << "whose name ('" << *FD
627            << "') does not contain 'Copy' or 'Create'.  This violates the naming"
628               " convention rules given in the Memory Management Guide for Core"
629               " Foundation";
630       }
631     }
632   } else {
633     os << " is not referenced later in this execution path and has a retain "
634           "count of +" << RV->getCount();
635   }
636 
637   return std::make_shared<PathDiagnosticEventPiece>(L, os.str());
638 }
639 
640 CFRefReport::CFRefReport(CFRefBug &D, const LangOptions &LOpts,
641                          const SummaryLogTy &Log, ExplodedNode *n,
642                          SymbolRef sym, bool registerVisitor)
643     : BugReport(D, D.getDescription(), n), Sym(sym) {
644   if (registerVisitor)
645     addVisitor(llvm::make_unique<CFRefReportVisitor>(sym, Log));
646 }
647 
648 CFRefReport::CFRefReport(CFRefBug &D, const LangOptions &LOpts,
649                          const SummaryLogTy &Log, ExplodedNode *n,
650                          SymbolRef sym, StringRef endText)
651     : BugReport(D, D.getDescription(), endText, n) {
652 
653   addVisitor(llvm::make_unique<CFRefReportVisitor>(sym, Log));
654 }
655 
656 void CFRefLeakReport::deriveParamLocation(CheckerContext &Ctx, SymbolRef sym) {
657   const SourceManager& SMgr = Ctx.getSourceManager();
658 
659   if (!sym->getOriginRegion())
660     return;
661 
662   auto *Region = dyn_cast<DeclRegion>(sym->getOriginRegion());
663   if (Region) {
664     const Decl *PDecl = Region->getDecl();
665     if (PDecl && isa<ParmVarDecl>(PDecl)) {
666       PathDiagnosticLocation ParamLocation = PathDiagnosticLocation::create(PDecl, SMgr);
667       Location = ParamLocation;
668       UniqueingLocation = ParamLocation;
669       UniqueingDecl = Ctx.getLocationContext()->getDecl();
670     }
671   }
672 }
673 
674 void CFRefLeakReport::deriveAllocLocation(CheckerContext &Ctx,
675                                           SymbolRef sym) {
676   // Most bug reports are cached at the location where they occurred.
677   // With leaks, we want to unique them by the location where they were
678   // allocated, and only report a single path.  To do this, we need to find
679   // the allocation site of a piece of tracked memory, which we do via a
680   // call to GetAllocationSite.  This will walk the ExplodedGraph backwards.
681   // Note that this is *not* the trimmed graph; we are guaranteed, however,
682   // that all ancestor nodes that represent the allocation site have the
683   // same SourceLocation.
684   const ExplodedNode *AllocNode = nullptr;
685 
686   const SourceManager& SMgr = Ctx.getSourceManager();
687 
688   AllocationInfo AllocI =
689       GetAllocationSite(Ctx.getStateManager(), getErrorNode(), sym);
690 
691   AllocNode = AllocI.N;
692   AllocBinding = AllocI.R;
693   markInteresting(AllocI.InterestingMethodContext);
694 
695   // Get the SourceLocation for the allocation site.
696   // FIXME: This will crash the analyzer if an allocation comes from an
697   // implicit call (ex: a destructor call).
698   // (Currently there are no such allocations in Cocoa, though.)
699   AllocStmt = PathDiagnosticLocation::getStmt(AllocNode);
700 
701   if (!AllocStmt) {
702     AllocBinding = nullptr;
703     return;
704   }
705 
706   PathDiagnosticLocation AllocLocation =
707     PathDiagnosticLocation::createBegin(AllocStmt, SMgr,
708                                         AllocNode->getLocationContext());
709   Location = AllocLocation;
710 
711   // Set uniqieing info, which will be used for unique the bug reports. The
712   // leaks should be uniqued on the allocation site.
713   UniqueingLocation = AllocLocation;
714   UniqueingDecl = AllocNode->getLocationContext()->getDecl();
715 }
716 
717 void CFRefLeakReport::createDescription(CheckerContext &Ctx) {
718   assert(Location.isValid() && UniqueingDecl && UniqueingLocation.isValid());
719   Description.clear();
720   llvm::raw_string_ostream os(Description);
721   os << "Potential leak of an object";
722 
723   Optional<std::string> RegionDescription = describeRegion(AllocBinding);
724   if (RegionDescription) {
725     os << " stored into '" << *RegionDescription << '\'';
726   } else {
727 
728     // If we can't figure out the name, just supply the type information.
729     os << " of type " << getPrettyTypeName(Sym->getType());
730   }
731 }
732 
733 CFRefLeakReport::CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts,
734                                  const SummaryLogTy &Log,
735                                  ExplodedNode *n, SymbolRef sym,
736                                  CheckerContext &Ctx)
737   : CFRefReport(D, LOpts, Log, n, sym, false) {
738 
739   deriveAllocLocation(Ctx, sym);
740   if (!AllocBinding)
741     deriveParamLocation(Ctx, sym);
742 
743   createDescription(Ctx);
744 
745   addVisitor(llvm::make_unique<CFRefLeakReportVisitor>(sym, Log));
746 }
747