@@ -28,6 +28,80 @@ static bool isNumericLiteralExpression(const Expr *E) {
28
28
isa<CXXBoolLiteralExpr>(E);
29
29
}
30
30
31
+ // / Write information about the type state change to {@code os},
32
+ // / return whether the note should be generated.
33
+ static bool shouldGenerateNote (llvm::raw_string_ostream &os,
34
+ const RefVal *PrevT, const RefVal &CurrV,
35
+ SmallVector<ArgEffect, 2 > &AEffects) {
36
+ // Get the previous type state.
37
+ RefVal PrevV = *PrevT;
38
+
39
+ // Specially handle -dealloc.
40
+ if (std::find (AEffects.begin (), AEffects.end (), Dealloc) != AEffects.end ()) {
41
+ // Determine if the object's reference count was pushed to zero.
42
+ assert (!PrevV.hasSameState (CurrV) && " The state should have changed." );
43
+ // We may not have transitioned to 'release' if we hit an error.
44
+ // This case is handled elsewhere.
45
+ if (CurrV.getKind () == RefVal::Released) {
46
+ assert (CurrV.getCombinedCounts () == 0 );
47
+ os << " Object released by directly sending the '-dealloc' message" ;
48
+ return true ;
49
+ }
50
+ }
51
+
52
+ // Determine if the typestate has changed.
53
+ if (!PrevV.hasSameState (CurrV))
54
+ switch (CurrV.getKind ()) {
55
+ case RefVal::Owned:
56
+ case RefVal::NotOwned:
57
+ if (PrevV.getCount () == CurrV.getCount ()) {
58
+ // Did an autorelease message get sent?
59
+ if (PrevV.getAutoreleaseCount () == CurrV.getAutoreleaseCount ())
60
+ return false ;
61
+
62
+ assert (PrevV.getAutoreleaseCount () < CurrV.getAutoreleaseCount ());
63
+ os << " Object autoreleased" ;
64
+ return true ;
65
+ }
66
+
67
+ if (PrevV.getCount () > CurrV.getCount ())
68
+ os << " Reference count decremented." ;
69
+ else
70
+ os << " Reference count incremented." ;
71
+
72
+ if (unsigned Count = CurrV.getCount ())
73
+ os << " The object now has a +" << Count << " retain count." ;
74
+
75
+ return true ;
76
+
77
+ case RefVal::Released:
78
+ if (CurrV.getIvarAccessHistory () ==
79
+ RefVal::IvarAccessHistory::ReleasedAfterDirectAccess &&
80
+ CurrV.getIvarAccessHistory () != PrevV.getIvarAccessHistory ()) {
81
+ os << " Strong instance variable relinquished. " ;
82
+ }
83
+ os << " Object released." ;
84
+ return true ;
85
+
86
+ case RefVal::ReturnedOwned:
87
+ // Autoreleases can be applied after marking a node ReturnedOwned.
88
+ if (CurrV.getAutoreleaseCount ())
89
+ return false ;
90
+
91
+ os << " Object returned to caller as an owning reference (single "
92
+ " retain count transferred to caller)" ;
93
+ return true ;
94
+
95
+ case RefVal::ReturnedNotOwned:
96
+ os << " Object returned to caller with a +0 retain count" ;
97
+ return true ;
98
+
99
+ default :
100
+ return false ;
101
+ }
102
+ return true ;
103
+ }
104
+
31
105
std::shared_ptr<PathDiagnosticPiece>
32
106
CFRefReportVisitor::VisitNode (const ExplodedNode *N,
33
107
BugReporterContext &BRC, BugReport &BR) {
@@ -64,11 +138,9 @@ CFRefReportVisitor::VisitNode(const ExplodedNode *N,
64
138
65
139
if (isa<ObjCArrayLiteral>(S)) {
66
140
os << " NSArray literal is an object with a +0 retain count" ;
67
- }
68
- else if (isa<ObjCDictionaryLiteral>(S)) {
141
+ } else if (isa<ObjCDictionaryLiteral>(S)) {
69
142
os << " NSDictionary literal is an object with a +0 retain count" ;
70
- }
71
- else if (const ObjCBoxedExpr *BL = dyn_cast<ObjCBoxedExpr>(S)) {
143
+ } else if (const ObjCBoxedExpr *BL = dyn_cast<ObjCBoxedExpr>(S)) {
72
144
if (isNumericLiteralExpression (BL->getSubExpr ()))
73
145
os << " NSNumber literal is an object with a +0 retain count" ;
74
146
else {
@@ -78,27 +150,26 @@ CFRefReportVisitor::VisitNode(const ExplodedNode *N,
78
150
79
151
// We should always be able to find the boxing class interface,
80
152
// but consider this future-proofing.
81
- if (BoxClass)
153
+ if (BoxClass) {
82
154
os << *BoxClass << " b" ;
83
- else
155
+ } else {
84
156
os << " B" ;
157
+ }
85
158
86
159
os << " oxed expression produces an object with a +0 retain count" ;
87
160
}
88
- }
89
- else if (isa<ObjCIvarRefExpr>(S)) {
161
+ } else if (isa<ObjCIvarRefExpr>(S)) {
90
162
os << " Object loaded from instance variable" ;
91
- }
92
- else {
163
+ } else {
93
164
if (const CallExpr *CE = dyn_cast<CallExpr>(S)) {
94
165
// Get the name of the callee (if it is available).
95
166
SVal X = CurrSt->getSValAsScalarOrLoc (CE->getCallee (), LCtx);
96
- if (const FunctionDecl *FD = X.getAsFunctionDecl ())
167
+ if (const FunctionDecl *FD = X.getAsFunctionDecl ()) {
97
168
os << " Call to function '" << *FD << ' \' ' ;
98
- else
169
+ } else {
99
170
os << " function call" ;
100
- }
101
- else {
171
+ }
172
+ } else {
102
173
assert (isa<ObjCMessageExpr>(S));
103
174
CallEventManager &Mgr = CurrSt->getStateManager ().getCallEventManager ();
104
175
CallEventRef<ObjCMethodCall> Call
@@ -166,8 +237,7 @@ CFRefReportVisitor::VisitNode(const ExplodedNode *N,
166
237
// was ever passed as an argument.
167
238
unsigned i = 0 ;
168
239
169
- for (CallExpr::const_arg_iterator AI=CE->arg_begin (), AE=CE->arg_end ();
170
- AI!=AE; ++AI, ++i) {
240
+ for (auto AI=CE->arg_begin (), AE=CE->arg_end (); AI!=AE; ++AI, ++i) {
171
241
172
242
// Retrieve the value of the argument. Is it the symbol
173
243
// we are interested in?
@@ -188,75 +258,8 @@ CFRefReportVisitor::VisitNode(const ExplodedNode *N,
188
258
}
189
259
}
190
260
191
- do {
192
- // Get the previous type state.
193
- RefVal PrevV = *PrevT;
194
-
195
- // Specially handle -dealloc.
196
- if (std::find (AEffects.begin (), AEffects.end (), Dealloc) !=
197
- AEffects.end ()) {
198
- // Determine if the object's reference count was pushed to zero.
199
- assert (!PrevV.hasSameState (CurrV) && " The state should have changed." );
200
- // We may not have transitioned to 'release' if we hit an error.
201
- // This case is handled elsewhere.
202
- if (CurrV.getKind () == RefVal::Released) {
203
- assert (CurrV.getCombinedCounts () == 0 );
204
- os << " Object released by directly sending the '-dealloc' message" ;
205
- break ;
206
- }
207
- }
208
-
209
- // Determine if the typestate has changed.
210
- if (!PrevV.hasSameState (CurrV))
211
- switch (CurrV.getKind ()) {
212
- case RefVal::Owned:
213
- case RefVal::NotOwned:
214
- if (PrevV.getCount () == CurrV.getCount ()) {
215
- // Did an autorelease message get sent?
216
- if (PrevV.getAutoreleaseCount () == CurrV.getAutoreleaseCount ())
217
- return nullptr ;
218
-
219
- assert (PrevV.getAutoreleaseCount () < CurrV.getAutoreleaseCount ());
220
- os << " Object autoreleased" ;
221
- break ;
222
- }
223
-
224
- if (PrevV.getCount () > CurrV.getCount ())
225
- os << " Reference count decremented." ;
226
- else
227
- os << " Reference count incremented." ;
228
-
229
- if (unsigned Count = CurrV.getCount ())
230
- os << " The object now has a +" << Count << " retain count." ;
231
-
232
- break ;
233
-
234
- case RefVal::Released:
235
- if (CurrV.getIvarAccessHistory () ==
236
- RefVal::IvarAccessHistory::ReleasedAfterDirectAccess &&
237
- CurrV.getIvarAccessHistory () != PrevV.getIvarAccessHistory ()) {
238
- os << " Strong instance variable relinquished. " ;
239
- }
240
- os << " Object released." ;
241
- break ;
242
-
243
- case RefVal::ReturnedOwned:
244
- // Autoreleases can be applied after marking a node ReturnedOwned.
245
- if (CurrV.getAutoreleaseCount ())
246
- return nullptr ;
247
-
248
- os << " Object returned to caller as an owning reference (single "
249
- " retain count transferred to caller)" ;
250
- break ;
251
-
252
- case RefVal::ReturnedNotOwned:
253
- os << " Object returned to caller with a +0 retain count" ;
254
- break ;
255
-
256
- default :
257
- return nullptr ;
258
- }
259
- } while (0 );
261
+ if (!shouldGenerateNote (os, PrevT, CurrV, AEffects))
262
+ return nullptr ;
260
263
261
264
if (os.str ().empty ())
262
265
return nullptr ; // We have nothing to say!
@@ -428,9 +431,9 @@ CFRefLeakReportVisitor::getEndPath(BugReporterContext &BRC,
428
431
Optional<std::string> RegionDescription = describeRegion (FirstBinding);
429
432
if (RegionDescription) {
430
433
os << " object allocated and stored into '" << *RegionDescription << ' \' ' ;
431
- }
432
- else
434
+ } else {
433
435
os << " allocated object" ;
436
+ }
434
437
435
438
// Get the retain count.
436
439
const RefVal* RV = getRefBinding (EndN->getState (), Sym);
0 commit comments