clang API Documentation
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 }