1249423Sdim//===--- TransGCCalls.cpp - Transformations to ARC mode -------------------===//
2234287Sdim//
3234287Sdim//                     The LLVM Compiler Infrastructure
4234287Sdim//
5234287Sdim// This file is distributed under the University of Illinois Open Source
6234287Sdim// License. See LICENSE.TXT for details.
7234287Sdim//
8234287Sdim//===----------------------------------------------------------------------===//
9234287Sdim
10234287Sdim#include "Transforms.h"
11234287Sdim#include "Internals.h"
12239462Sdim#include "clang/AST/ASTContext.h"
13234287Sdim#include "clang/Sema/SemaDiagnostic.h"
14234287Sdim
15234287Sdimusing namespace clang;
16234287Sdimusing namespace arcmt;
17234287Sdimusing namespace trans;
18234287Sdim
19234287Sdimnamespace {
20234287Sdim
21234287Sdimclass GCCollectableCallsChecker :
22234287Sdim                         public RecursiveASTVisitor<GCCollectableCallsChecker> {
23234287Sdim  MigrationContext &MigrateCtx;
24234287Sdim  IdentifierInfo *NSMakeCollectableII;
25234287Sdim  IdentifierInfo *CFMakeCollectableII;
26234287Sdim
27234287Sdimpublic:
28239462Sdim  GCCollectableCallsChecker(MigrationContext &ctx)
29239462Sdim    : MigrateCtx(ctx) {
30234287Sdim    IdentifierTable &Ids = MigrateCtx.Pass.Ctx.Idents;
31234287Sdim    NSMakeCollectableII = &Ids.get("NSMakeCollectable");
32234287Sdim    CFMakeCollectableII = &Ids.get("CFMakeCollectable");
33234287Sdim  }
34234287Sdim
35234287Sdim  bool shouldWalkTypesOfTypeLocs() const { return false; }
36234287Sdim
37234287Sdim  bool VisitCallExpr(CallExpr *E) {
38234287Sdim    TransformActions &TA = MigrateCtx.Pass.TA;
39234287Sdim
40234287Sdim    if (MigrateCtx.isGCOwnedNonObjC(E->getType())) {
41234287Sdim      if (MigrateCtx.Pass.noNSAllocReallocError())
42234287Sdim        TA.reportWarning("call returns pointer to GC managed memory; "
43234287Sdim                       "it will become unmanaged in ARC",
44234287Sdim                       E->getLocStart(), E->getSourceRange());
45234287Sdim      else
46234287Sdim        TA.reportError("call returns pointer to GC managed memory; "
47234287Sdim                       "it will become unmanaged in ARC",
48234287Sdim                       E->getLocStart(), E->getSourceRange());
49234287Sdim      return true;
50234287Sdim    }
51234287Sdim
52234287Sdim    Expr *CEE = E->getCallee()->IgnoreParenImpCasts();
53234287Sdim    if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) {
54234287Sdim      if (FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(DRE->getDecl())) {
55234287Sdim        if (!FD->getDeclContext()->getRedeclContext()->isFileContext())
56234287Sdim          return true;
57234287Sdim
58234287Sdim        if (FD->getIdentifier() == NSMakeCollectableII) {
59234287Sdim          Transaction Trans(TA);
60234287Sdim          TA.clearDiagnostic(diag::err_unavailable,
61234287Sdim                             diag::err_unavailable_message,
62234287Sdim                             diag::err_ovl_deleted_call, // ObjC++
63234287Sdim                             DRE->getSourceRange());
64234287Sdim          TA.replace(DRE->getSourceRange(), "CFBridgingRelease");
65234287Sdim
66234287Sdim        } else if (FD->getIdentifier() == CFMakeCollectableII) {
67234287Sdim          TA.reportError("CFMakeCollectable will leak the object that it "
68234287Sdim                         "receives in ARC", DRE->getLocation(),
69234287Sdim                         DRE->getSourceRange());
70234287Sdim        }
71234287Sdim      }
72234287Sdim    }
73234287Sdim
74234287Sdim    return true;
75234287Sdim  }
76234287Sdim};
77234287Sdim
78234287Sdim} // anonymous namespace
79234287Sdim
80234287Sdimvoid GCCollectableCallsTraverser::traverseBody(BodyContext &BodyCtx) {
81239462Sdim  GCCollectableCallsChecker(BodyCtx.getMigrationContext())
82234287Sdim                                            .TraverseStmt(BodyCtx.getTopStmt());
83234287Sdim}
84