clang API Documentation

TransGCCalls.cpp
Go to the documentation of this file.
00001 //===--- TransGCCalls.cpp - Tranformations to ARC mode --------------------===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 
00010 #include "Transforms.h"
00011 #include "Internals.h"
00012 #include "clang/Sema/SemaDiagnostic.h"
00013 
00014 using namespace clang;
00015 using namespace arcmt;
00016 using namespace trans;
00017 
00018 namespace {
00019 
00020 class GCCollectableCallsChecker :
00021                          public RecursiveASTVisitor<GCCollectableCallsChecker> {
00022   MigrationContext &MigrateCtx;
00023   ParentMap &PMap;
00024   IdentifierInfo *NSMakeCollectableII;
00025   IdentifierInfo *CFMakeCollectableII;
00026 
00027 public:
00028   GCCollectableCallsChecker(MigrationContext &ctx, ParentMap &map)
00029     : MigrateCtx(ctx), PMap(map) {
00030     IdentifierTable &Ids = MigrateCtx.Pass.Ctx.Idents;
00031     NSMakeCollectableII = &Ids.get("NSMakeCollectable");
00032     CFMakeCollectableII = &Ids.get("CFMakeCollectable");
00033   }
00034 
00035   bool shouldWalkTypesOfTypeLocs() const { return false; }
00036 
00037   bool VisitCallExpr(CallExpr *E) {
00038     TransformActions &TA = MigrateCtx.Pass.TA;
00039 
00040     if (MigrateCtx.isGCOwnedNonObjC(E->getType())) {
00041       if (MigrateCtx.Pass.noNSAllocReallocError())
00042         TA.reportWarning("call returns pointer to GC managed memory; "
00043                        "it will become unmanaged in ARC",
00044                        E->getLocStart(), E->getSourceRange());
00045       else 
00046         TA.reportError("call returns pointer to GC managed memory; "
00047                        "it will become unmanaged in ARC",
00048                        E->getLocStart(), E->getSourceRange());
00049       return true;
00050     }
00051 
00052     Expr *CEE = E->getCallee()->IgnoreParenImpCasts();
00053     if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) {
00054       if (FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(DRE->getDecl())) {
00055         if (!FD->getDeclContext()->getRedeclContext()->isFileContext())
00056           return true;
00057 
00058         if (FD->getIdentifier() == NSMakeCollectableII) {
00059           Transaction Trans(TA);
00060           TA.clearDiagnostic(diag::err_unavailable,
00061                              diag::err_unavailable_message,
00062                              diag::err_ovl_deleted_call, // ObjC++
00063                              DRE->getSourceRange());
00064           TA.replace(DRE->getSourceRange(), "CFBridgingRelease");
00065 
00066         } else if (FD->getIdentifier() == CFMakeCollectableII) {
00067           TA.reportError("CFMakeCollectable will leak the object that it "
00068                          "receives in ARC", DRE->getLocation(),
00069                          DRE->getSourceRange());
00070         }
00071       }
00072     }
00073 
00074     return true;
00075   }
00076 };
00077 
00078 } // anonymous namespace
00079 
00080 void GCCollectableCallsTraverser::traverseBody(BodyContext &BodyCtx) {
00081   GCCollectableCallsChecker(BodyCtx.getMigrationContext(),
00082                             BodyCtx.getParentMap())
00083                                             .TraverseStmt(BodyCtx.getTopStmt());
00084 }