1 //===--- TransGCCalls.cpp - Tranformations 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 #include "Transforms.h"
11 #include "Internals.h"
12 #include "clang/Sema/SemaDiagnostic.h"
13 
14 using namespace clang;
15 using namespace arcmt;
16 using namespace trans;
17 
18 namespace {
19 
20 class GCCollectableCallsChecker :
21                          public RecursiveASTVisitor<GCCollectableCallsChecker> {
22   MigrationContext &MigrateCtx;
23   ParentMap &PMap;
24   IdentifierInfo *NSMakeCollectableII;
25   IdentifierInfo *CFMakeCollectableII;
26 
27 public:
28   GCCollectableCallsChecker(MigrationContext &ctx, ParentMap &map)
29     : MigrateCtx(ctx), PMap(map) {
30     IdentifierTable &Ids = MigrateCtx.Pass.Ctx.Idents;
31     NSMakeCollectableII = &Ids.get("NSMakeCollectable");
32     CFMakeCollectableII = &Ids.get("CFMakeCollectable");
33   }
34 
35   bool shouldWalkTypesOfTypeLocs() const { return false; }
36 
37   bool VisitCallExpr(CallExpr *E) {
38     TransformActions &TA = MigrateCtx.Pass.TA;
39 
40     if (MigrateCtx.isGCOwnedNonObjC(E->getType())) {
41       TA.reportError("call returns pointer to GC managed memory; "
42                      "it will become unmanaged in ARC",
43                      E->getLocStart(), E->getSourceRange());
44       return true;
45     }
46 
47     Expr *CEE = E->getCallee()->IgnoreParenImpCasts();
48     if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) {
49       if (FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(DRE->getDecl())) {
50         if (!FD->getDeclContext()->getRedeclContext()->isFileContext())
51           return true;
52 
53         if (FD->getIdentifier() == NSMakeCollectableII) {
54           Transaction Trans(TA);
55           TA.clearDiagnostic(diag::err_unavailable,
56                              diag::err_unavailable_message,
57                              diag::err_ovl_deleted_call, // ObjC++
58                              DRE->getSourceRange());
59           TA.replace(DRE->getSourceRange(), "CFBridgingRelease");
60 
61         } else if (FD->getIdentifier() == CFMakeCollectableII) {
62           TA.reportError("CFMakeCollectable will leak the object that it "
63                          "receives in ARC", DRE->getLocation(),
64                          DRE->getSourceRange());
65         }
66       }
67     }
68 
69     return true;
70   }
71 };
72 
73 } // anonymous namespace
74 
75 void GCCollectableCallsTraverser::traverseBody(BodyContext &BodyCtx) {
76   GCCollectableCallsChecker(BodyCtx.getMigrationContext(),
77                             BodyCtx.getParentMap())
78                                             .TraverseStmt(BodyCtx.getTopStmt());
79 }
80