/Users/buildslave/jenkins/sharedspace/clang-stage2-coverage-R@2/llvm/tools/clang/lib/ARCMigrate/TransUnbridgedCasts.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===--- TransUnbridgedCasts.cpp - Transformations to ARC mode ------------===// |
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 | | // rewriteUnbridgedCasts: |
11 | | // |
12 | | // A cast of non-objc pointer to an objc one is checked. If the non-objc pointer |
13 | | // is from a file-level variable, __bridge cast is used to convert it. |
14 | | // For the result of a function call that we know is +1/+0, |
15 | | // __bridge/CFBridgingRelease is used. |
16 | | // |
17 | | // NSString *str = (NSString *)kUTTypePlainText; |
18 | | // str = b ? kUTTypeRTF : kUTTypePlainText; |
19 | | // NSString *_uuidString = (NSString *)CFUUIDCreateString(kCFAllocatorDefault, |
20 | | // _uuid); |
21 | | // ----> |
22 | | // NSString *str = (__bridge NSString *)kUTTypePlainText; |
23 | | // str = (__bridge NSString *)(b ? kUTTypeRTF : kUTTypePlainText); |
24 | | // NSString *_uuidString = (NSString *) |
25 | | // CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, _uuid)); |
26 | | // |
27 | | // For a C pointer to ObjC, for casting 'self', __bridge is used. |
28 | | // |
29 | | // CFStringRef str = (CFStringRef)self; |
30 | | // ----> |
31 | | // CFStringRef str = (__bridge CFStringRef)self; |
32 | | // |
33 | | // Uses of Block_copy/Block_release macros are rewritten: |
34 | | // |
35 | | // c = Block_copy(b); |
36 | | // Block_release(c); |
37 | | // ----> |
38 | | // c = [b copy]; |
39 | | // <removed> |
40 | | // |
41 | | //===----------------------------------------------------------------------===// |
42 | | |
43 | | #include "Transforms.h" |
44 | | #include "Internals.h" |
45 | | #include "clang/AST/ASTContext.h" |
46 | | #include "clang/AST/Attr.h" |
47 | | #include "clang/AST/ParentMap.h" |
48 | | #include "clang/Analysis/DomainSpecific/CocoaConventions.h" |
49 | | #include "clang/Basic/SourceManager.h" |
50 | | #include "clang/Lex/Lexer.h" |
51 | | #include "clang/Sema/SemaDiagnostic.h" |
52 | | #include "llvm/ADT/SmallString.h" |
53 | | |
54 | | using namespace clang; |
55 | | using namespace arcmt; |
56 | | using namespace trans; |
57 | | |
58 | | namespace { |
59 | | |
60 | | class UnbridgedCastRewriter : public RecursiveASTVisitor<UnbridgedCastRewriter>{ |
61 | | MigrationPass &Pass; |
62 | | IdentifierInfo *SelfII; |
63 | | std::unique_ptr<ParentMap> StmtMap; |
64 | | Decl *ParentD; |
65 | | Stmt *Body; |
66 | | mutable std::unique_ptr<ExprSet> Removables; |
67 | | |
68 | | public: |
69 | | UnbridgedCastRewriter(MigrationPass &pass) |
70 | 425 | : Pass(pass), ParentD(nullptr), Body(nullptr) { |
71 | 425 | SelfII = &Pass.Ctx.Idents.get("self"); |
72 | 425 | } |
73 | | |
74 | 425 | void transformBody(Stmt *body, Decl *ParentD) { |
75 | 425 | this->ParentD = ParentD; |
76 | 425 | Body = body; |
77 | 425 | StmtMap.reset(new ParentMap(body)); |
78 | 425 | TraverseStmt(body); |
79 | 425 | } |
80 | | |
81 | 22 | bool TraverseBlockDecl(BlockDecl *D) { |
82 | 22 | // ParentMap does not enter into a BlockDecl to record its stmts, so use a |
83 | 22 | // new UnbridgedCastRewriter to handle the block. |
84 | 22 | UnbridgedCastRewriter(Pass).transformBody(D->getBody(), D); |
85 | 22 | return true; |
86 | 22 | } |
87 | | |
88 | 1.87k | bool VisitCastExpr(CastExpr *E) { |
89 | 1.87k | if (E->getCastKind() != CK_CPointerToObjCPointerCast && |
90 | 1.79k | E->getCastKind() != CK_BitCast && |
91 | 1.57k | E->getCastKind() != CK_AnyPointerToBlockPointerCast) |
92 | 1.56k | return true; |
93 | 308 | |
94 | 308 | QualType castType = E->getType(); |
95 | 308 | Expr *castExpr = E->getSubExpr(); |
96 | 308 | QualType castExprType = castExpr->getType(); |
97 | 308 | |
98 | 308 | if (castType->isObjCRetainableType() == castExprType->isObjCRetainableType()) |
99 | 128 | return true; |
100 | 180 | |
101 | 180 | bool exprRetainable = castExprType->isObjCIndirectLifetimeType(); |
102 | 180 | bool castRetainable = castType->isObjCIndirectLifetimeType(); |
103 | 180 | if (exprRetainable == castRetainable180 ) return true2 ; |
104 | 178 | |
105 | 178 | if (178 castExpr->isNullPointerConstant(Pass.Ctx, |
106 | 178 | Expr::NPC_ValueDependentIsNull)) |
107 | 0 | return true; |
108 | 178 | |
109 | 178 | SourceLocation loc = castExpr->getExprLoc(); |
110 | 178 | if (loc.isValid() && 178 Pass.Ctx.getSourceManager().isInSystemHeader(loc)178 ) |
111 | 0 | return true; |
112 | 178 | |
113 | 178 | if (178 castType->isObjCRetainableType()178 ) |
114 | 85 | transformNonObjCToObjCCast(E); |
115 | 178 | else |
116 | 93 | transformObjCToNonObjCCast(E); |
117 | 1.87k | |
118 | 1.87k | return true; |
119 | 1.87k | } |
120 | | |
121 | | private: |
122 | 85 | void transformNonObjCToObjCCast(CastExpr *E) { |
123 | 85 | if (!E85 ) return0 ; |
124 | 85 | |
125 | 85 | // Global vars are assumed that are cast as unretained. |
126 | 85 | if (85 isGlobalVar(E)85 ) |
127 | 14 | if (14 E->getSubExpr()->getType()->isPointerType()14 ) { |
128 | 14 | castToObjCObject(E, /*retained=*/false); |
129 | 14 | return; |
130 | 14 | } |
131 | 71 | |
132 | 71 | // If the cast is directly over the result of a Core Foundation function |
133 | 71 | // try to figure out whether it should be cast as retained or unretained. |
134 | 71 | Expr *inner = E->IgnoreParenCasts(); |
135 | 71 | if (CallExpr *callE71 = dyn_cast<CallExpr>(inner)) { |
136 | 17 | if (FunctionDecl *FD17 = callE->getDirectCallee()) { |
137 | 17 | if (FD->hasAttr<CFReturnsRetainedAttr>()17 ) { |
138 | 0 | castToObjCObject(E, /*retained=*/true); |
139 | 0 | return; |
140 | 0 | } |
141 | 17 | if (17 FD->hasAttr<CFReturnsNotRetainedAttr>()17 ) { |
142 | 0 | castToObjCObject(E, /*retained=*/false); |
143 | 0 | return; |
144 | 0 | } |
145 | 17 | if (17 FD->isGlobal() && |
146 | 17 | FD->getIdentifier() && |
147 | 17 | ento::cocoa::isRefType(E->getSubExpr()->getType(), "CF", |
148 | 17 | FD->getIdentifier()->getName())) { |
149 | 13 | StringRef fname = FD->getIdentifier()->getName(); |
150 | 13 | if (fname.endswith("Retain") || |
151 | 4 | fname.find("Create") != StringRef::npos || |
152 | 13 | fname.find("Copy") != StringRef::npos0 ) { |
153 | 13 | // Do not migrate to couple of bridge transfer casts which |
154 | 13 | // cancel each other out. Leave it unchanged so error gets user |
155 | 13 | // attention instead. |
156 | 13 | if (FD->getName() == "CFRetain" && |
157 | 9 | FD->getNumParams() == 1 && |
158 | 9 | FD->getParent()->isTranslationUnit() && |
159 | 13 | FD->isExternallyVisible()9 ) { |
160 | 9 | Expr *Arg = callE->getArg(0); |
161 | 9 | if (const ImplicitCastExpr *ICE9 = dyn_cast<ImplicitCastExpr>(Arg)) { |
162 | 8 | const Expr *sub = ICE->getSubExpr(); |
163 | 8 | QualType T = sub->getType(); |
164 | 8 | if (T->isObjCObjectPointerType()) |
165 | 3 | return; |
166 | 10 | } |
167 | 9 | } |
168 | 10 | castToObjCObject(E, /*retained=*/true); |
169 | 10 | return; |
170 | 10 | } |
171 | 0 |
|
172 | 0 | if (0 fname.find("Get") != StringRef::npos0 ) { |
173 | 0 | castToObjCObject(E, /*retained=*/false); |
174 | 0 | return; |
175 | 0 | } |
176 | 58 | } |
177 | 17 | } |
178 | 17 | } |
179 | 58 | |
180 | 58 | // If returning an ivar or a member of an ivar from a +0 method, use |
181 | 58 | // a __bridge cast. |
182 | 58 | Expr *base = inner->IgnoreParenImpCasts(); |
183 | 61 | while (isa<MemberExpr>(base)) |
184 | 3 | base = cast<MemberExpr>(base)->getBase()->IgnoreParenImpCasts(); |
185 | 58 | if (isa<ObjCIvarRefExpr>(base) && |
186 | 58 | isa<ReturnStmt>(StmtMap->getParentIgnoreParenCasts(E))9 ) { |
187 | 7 | if (ObjCMethodDecl *method7 = dyn_cast_or_null<ObjCMethodDecl>(ParentD)) { |
188 | 7 | if (!method->hasAttr<NSReturnsRetainedAttr>()7 ) { |
189 | 6 | castToObjCObject(E, /*retained=*/false); |
190 | 6 | return; |
191 | 6 | } |
192 | 52 | } |
193 | 7 | } |
194 | 85 | } |
195 | | |
196 | 30 | void castToObjCObject(CastExpr *E, bool retained) { |
197 | 30 | rewriteToBridgedCast(E, retained ? OBC_BridgeTransfer10 : OBC_Bridge20 ); |
198 | 30 | } |
199 | | |
200 | 57 | void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind) { |
201 | 57 | Transaction Trans(Pass.TA); |
202 | 57 | rewriteToBridgedCast(E, Kind, Trans); |
203 | 57 | } |
204 | | |
205 | | void rewriteToBridgedCast(CastExpr *E, ObjCBridgeCastKind Kind, |
206 | 67 | Transaction &Trans) { |
207 | 67 | TransformActions &TA = Pass.TA; |
208 | 67 | |
209 | 67 | // We will remove the compiler diagnostic. |
210 | 67 | if (!TA.hasDiagnostic(diag::err_arc_mismatched_cast, |
211 | 67 | diag::err_arc_cast_requires_bridge, |
212 | 67 | E->getLocStart())) { |
213 | 8 | Trans.abort(); |
214 | 8 | return; |
215 | 8 | } |
216 | 59 | |
217 | 59 | StringRef bridge; |
218 | 59 | switch(Kind) { |
219 | 23 | case OBC_Bridge: |
220 | 23 | bridge = "__bridge "; break; |
221 | 10 | case OBC_BridgeTransfer: |
222 | 10 | bridge = "__bridge_transfer "; break; |
223 | 26 | case OBC_BridgeRetained: |
224 | 26 | bridge = "__bridge_retained "; break; |
225 | 59 | } |
226 | 59 | |
227 | 59 | TA.clearDiagnostic(diag::err_arc_mismatched_cast, |
228 | 59 | diag::err_arc_cast_requires_bridge, |
229 | 59 | E->getLocStart()); |
230 | 59 | if (Kind == OBC_Bridge || 59 !Pass.CFBridgingFunctionsDefined()36 ) { |
231 | 23 | if (CStyleCastExpr *CCE23 = dyn_cast<CStyleCastExpr>(E)) { |
232 | 9 | TA.insertAfterToken(CCE->getLParenLoc(), bridge); |
233 | 23 | } else { |
234 | 14 | SourceLocation insertLoc = E->getSubExpr()->getLocStart(); |
235 | 14 | SmallString<128> newCast; |
236 | 14 | newCast += '('; |
237 | 14 | newCast += bridge; |
238 | 14 | newCast += E->getType().getAsString(Pass.Ctx.getPrintingPolicy()); |
239 | 14 | newCast += ')'; |
240 | 14 | |
241 | 14 | if (isa<ParenExpr>(E->getSubExpr())14 ) { |
242 | 0 | TA.insert(insertLoc, newCast.str()); |
243 | 14 | } else { |
244 | 14 | newCast += '('; |
245 | 14 | TA.insert(insertLoc, newCast.str()); |
246 | 14 | TA.insertAfterToken(E->getLocEnd(), ")"); |
247 | 14 | } |
248 | 14 | } |
249 | 59 | } else { |
250 | 36 | assert(Kind == OBC_BridgeTransfer || Kind == OBC_BridgeRetained); |
251 | 36 | SmallString<32> BridgeCall; |
252 | 36 | |
253 | 36 | Expr *WrapE = E->getSubExpr(); |
254 | 36 | SourceLocation InsertLoc = WrapE->getLocStart(); |
255 | 36 | |
256 | 36 | SourceManager &SM = Pass.Ctx.getSourceManager(); |
257 | 36 | char PrevChar = *SM.getCharacterData(InsertLoc.getLocWithOffset(-1)); |
258 | 36 | if (Lexer::isIdentifierBodyChar(PrevChar, Pass.Ctx.getLangOpts())) |
259 | 0 | BridgeCall += ' '; |
260 | 36 | |
261 | 36 | if (Kind == OBC_BridgeTransfer) |
262 | 10 | BridgeCall += "CFBridgingRelease"; |
263 | 36 | else |
264 | 26 | BridgeCall += "CFBridgingRetain"; |
265 | 36 | |
266 | 36 | if (isa<ParenExpr>(WrapE)36 ) { |
267 | 0 | TA.insert(InsertLoc, BridgeCall); |
268 | 36 | } else { |
269 | 36 | BridgeCall += '('; |
270 | 36 | TA.insert(InsertLoc, BridgeCall); |
271 | 36 | TA.insertAfterToken(WrapE->getLocEnd(), ")"); |
272 | 36 | } |
273 | 36 | } |
274 | 67 | } |
275 | | |
276 | 10 | void rewriteCastForCFRetain(CastExpr *castE, CallExpr *callE) { |
277 | 10 | Transaction Trans(Pass.TA); |
278 | 10 | Pass.TA.replace(callE->getSourceRange(), callE->getArg(0)->getSourceRange()); |
279 | 10 | rewriteToBridgedCast(castE, OBC_BridgeRetained, Trans); |
280 | 10 | } |
281 | | |
282 | 8 | void getBlockMacroRanges(CastExpr *E, SourceRange &Outer, SourceRange &Inner) { |
283 | 8 | SourceManager &SM = Pass.Ctx.getSourceManager(); |
284 | 8 | SourceLocation Loc = E->getExprLoc(); |
285 | 8 | assert(Loc.isMacroID()); |
286 | 8 | SourceLocation MacroBegin, MacroEnd; |
287 | 8 | std::tie(MacroBegin, MacroEnd) = SM.getImmediateExpansionRange(Loc); |
288 | 8 | SourceRange SubRange = E->getSubExpr()->IgnoreParenImpCasts()->getSourceRange(); |
289 | 8 | SourceLocation InnerBegin = SM.getImmediateMacroCallerLoc(SubRange.getBegin()); |
290 | 8 | SourceLocation InnerEnd = SM.getImmediateMacroCallerLoc(SubRange.getEnd()); |
291 | 8 | |
292 | 8 | Outer = SourceRange(MacroBegin, MacroEnd); |
293 | 8 | Inner = SourceRange(InnerBegin, InnerEnd); |
294 | 8 | } |
295 | | |
296 | 4 | void rewriteBlockCopyMacro(CastExpr *E) { |
297 | 4 | SourceRange OuterRange, InnerRange; |
298 | 4 | getBlockMacroRanges(E, OuterRange, InnerRange); |
299 | 4 | |
300 | 4 | Transaction Trans(Pass.TA); |
301 | 4 | Pass.TA.replace(OuterRange, InnerRange); |
302 | 4 | Pass.TA.insert(InnerRange.getBegin(), "["); |
303 | 4 | Pass.TA.insertAfterToken(InnerRange.getEnd(), " copy]"); |
304 | 4 | Pass.TA.clearDiagnostic(diag::err_arc_mismatched_cast, |
305 | 4 | diag::err_arc_cast_requires_bridge, |
306 | 4 | OuterRange); |
307 | 4 | } |
308 | | |
309 | 4 | void removeBlockReleaseMacro(CastExpr *E) { |
310 | 4 | SourceRange OuterRange, InnerRange; |
311 | 4 | getBlockMacroRanges(E, OuterRange, InnerRange); |
312 | 4 | |
313 | 4 | Transaction Trans(Pass.TA); |
314 | 4 | Pass.TA.clearDiagnostic(diag::err_arc_mismatched_cast, |
315 | 4 | diag::err_arc_cast_requires_bridge, |
316 | 4 | OuterRange); |
317 | 4 | if (!hasSideEffects(E, Pass.Ctx)4 ) { |
318 | 4 | if (tryRemoving(cast<Expr>(StmtMap->getParentIgnoreParenCasts(E)))) |
319 | 4 | return; |
320 | 0 | } |
321 | 0 | Pass.TA.replace(OuterRange, InnerRange); |
322 | 0 | } |
323 | | |
324 | 4 | bool tryRemoving(Expr *E) const { |
325 | 4 | if (!Removables4 ) { |
326 | 4 | Removables.reset(new ExprSet); |
327 | 4 | collectRemovables(Body, *Removables); |
328 | 4 | } |
329 | 4 | |
330 | 4 | if (Removables->count(E)4 ) { |
331 | 4 | Pass.TA.removeStmt(E); |
332 | 4 | return true; |
333 | 4 | } |
334 | 0 |
|
335 | 0 | return false; |
336 | 0 | } |
337 | | |
338 | 93 | void transformObjCToNonObjCCast(CastExpr *E) { |
339 | 93 | SourceLocation CastLoc = E->getExprLoc(); |
340 | 93 | if (CastLoc.isMacroID()93 ) { |
341 | 8 | StringRef MacroName = Lexer::getImmediateMacroName(CastLoc, |
342 | 8 | Pass.Ctx.getSourceManager(), |
343 | 8 | Pass.Ctx.getLangOpts()); |
344 | 8 | if (MacroName == "Block_copy"8 ) { |
345 | 4 | rewriteBlockCopyMacro(E); |
346 | 4 | return; |
347 | 4 | } |
348 | 4 | if (4 MacroName == "Block_release"4 ) { |
349 | 4 | removeBlockReleaseMacro(E); |
350 | 4 | return; |
351 | 4 | } |
352 | 85 | } |
353 | 85 | |
354 | 85 | if (85 isSelf(E->getSubExpr())85 ) |
355 | 4 | return rewriteToBridgedCast(E, OBC_Bridge); |
356 | 81 | |
357 | 81 | CallExpr *callE; |
358 | 81 | if (isPassedToCFRetain(E, callE)) |
359 | 10 | return rewriteCastForCFRetain(E, callE); |
360 | 71 | |
361 | 71 | ObjCMethodFamily family = getFamilyOfMessage(E->getSubExpr()); |
362 | 71 | if (family == OMF_retain) |
363 | 4 | return rewriteToBridgedCast(E, OBC_BridgeRetained); |
364 | 67 | |
365 | 67 | if (67 family == OMF_autorelease || 67 family == OMF_release66 ) { |
366 | 1 | std::string err = "it is not safe to cast to '"; |
367 | 1 | err += E->getType().getAsString(Pass.Ctx.getPrintingPolicy()); |
368 | 1 | err += "' the result of '"; |
369 | 1 | err += family == OMF_autorelease ? "autorelease"1 : "release"0 ; |
370 | 1 | err += "' message; a __bridge cast may result in a pointer to a " |
371 | 1 | "destroyed object and a __bridge_retained may leak the object"; |
372 | 1 | Pass.TA.reportError(err, E->getLocStart(), |
373 | 1 | E->getSubExpr()->getSourceRange()); |
374 | 1 | Stmt *parent = E; |
375 | 2 | do { |
376 | 2 | parent = StmtMap->getParentIgnoreParenImpCasts(parent); |
377 | 2 | } while (parent && 2 isa<ExprWithCleanups>(parent)2 ); |
378 | 1 | |
379 | 1 | if (ReturnStmt *retS1 = dyn_cast_or_null<ReturnStmt>(parent)) { |
380 | 1 | std::string note = "remove the cast and change return type of function " |
381 | 1 | "to '"; |
382 | 1 | note += E->getSubExpr()->getType().getAsString(Pass.Ctx.getPrintingPolicy()); |
383 | 1 | note += "' to have the object automatically autoreleased"; |
384 | 1 | Pass.TA.reportNote(note, retS->getLocStart()); |
385 | 1 | } |
386 | 1 | } |
387 | 67 | |
388 | 67 | Expr *subExpr = E->getSubExpr(); |
389 | 67 | |
390 | 67 | // Look through pseudo-object expressions. |
391 | 67 | if (PseudoObjectExpr *pseudo67 = dyn_cast<PseudoObjectExpr>(subExpr)) { |
392 | 2 | subExpr = pseudo->getResultExpr(); |
393 | 2 | assert(subExpr && "no result for pseudo-object of non-void type?"); |
394 | 2 | } |
395 | 67 | |
396 | 67 | if (ImplicitCastExpr *implCE67 = dyn_cast<ImplicitCastExpr>(subExpr)) { |
397 | 67 | if (implCE->getCastKind() == CK_ARCConsumeObject) |
398 | 8 | return rewriteToBridgedCast(E, OBC_BridgeRetained); |
399 | 59 | if (59 implCE->getCastKind() == CK_ARCReclaimReturnedObject59 ) |
400 | 7 | return rewriteToBridgedCast(E, OBC_Bridge); |
401 | 52 | } |
402 | 52 | |
403 | 52 | bool isConsumed = false; |
404 | 52 | if (isPassedToCParamWithKnownOwnership(E, isConsumed)) |
405 | 4 | return rewriteToBridgedCast(E, isConsumed ? 4 OBC_BridgeRetained4 |
406 | 4 | : OBC_Bridge); |
407 | 48 | } |
408 | | |
409 | 71 | static ObjCMethodFamily getFamilyOfMessage(Expr *E) { |
410 | 71 | E = E->IgnoreParenCasts(); |
411 | 71 | if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(E)) |
412 | 17 | return ME->getMethodFamily(); |
413 | 54 | |
414 | 54 | return OMF_None; |
415 | 54 | } |
416 | | |
417 | 81 | bool isPassedToCFRetain(Expr *E, CallExpr *&callE) const { |
418 | 81 | if ((callE = dyn_cast_or_null<CallExpr>( |
419 | 81 | StmtMap->getParentIgnoreParenImpCasts(E)))) |
420 | 16 | if (FunctionDecl * |
421 | 16 | FD = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl())) |
422 | 16 | if (16 FD->getName() == "CFRetain" && 16 FD->getNumParams() == 110 && |
423 | 10 | FD->getParent()->isTranslationUnit() && |
424 | 10 | FD->isExternallyVisible()) |
425 | 10 | return true; |
426 | 71 | |
427 | 71 | return false; |
428 | 71 | } |
429 | | |
430 | 52 | bool isPassedToCParamWithKnownOwnership(Expr *E, bool &isConsumed) const { |
431 | 52 | if (CallExpr *callE = dyn_cast_or_null<CallExpr>( |
432 | 52 | StmtMap->getParentIgnoreParenImpCasts(E))) |
433 | 6 | if (FunctionDecl * |
434 | 6 | FD6 = dyn_cast_or_null<FunctionDecl>(callE->getCalleeDecl())) { |
435 | 6 | unsigned i = 0; |
436 | 7 | for (unsigned e = callE->getNumArgs(); i != e7 ; ++i1 ) { |
437 | 7 | Expr *arg = callE->getArg(i); |
438 | 7 | if (arg == E || 7 arg->IgnoreParenImpCasts() == E2 ) |
439 | 6 | break; |
440 | 7 | } |
441 | 6 | if (i < callE->getNumArgs() && 6 i < FD->getNumParams()6 ) { |
442 | 5 | ParmVarDecl *PD = FD->getParamDecl(i); |
443 | 5 | if (PD->hasAttr<CFConsumedAttr>()5 ) { |
444 | 4 | isConsumed = true; |
445 | 4 | return true; |
446 | 4 | } |
447 | 48 | } |
448 | 6 | } |
449 | 48 | |
450 | 48 | return false; |
451 | 48 | } |
452 | | |
453 | 85 | bool isSelf(Expr *E) const { |
454 | 85 | E = E->IgnoreParenLValueCasts(); |
455 | 85 | if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) |
456 | 16 | if (ImplicitParamDecl *16 IPD16 = dyn_cast<ImplicitParamDecl>(DRE->getDecl())) |
457 | 4 | if (4 IPD->getIdentifier() == SelfII4 ) |
458 | 4 | return true; |
459 | 81 | |
460 | 81 | return false; |
461 | 81 | } |
462 | | }; |
463 | | |
464 | | } // end anonymous namespace |
465 | | |
466 | 85 | void trans::rewriteUnbridgedCasts(MigrationPass &pass) { |
467 | 85 | BodyTransform<UnbridgedCastRewriter> trans(pass); |
468 | 85 | trans.TraverseDecl(pass.Ctx.getTranslationUnitDecl()); |
469 | 85 | } |