clang API Documentation

TransGCCalls.cpp
Go to the documentation of this file.
00001 //===--- TransGCCalls.cpp - Transformations 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/AST/ASTContext.h"
00013 #include "clang/Sema/SemaDiagnostic.h"
00014 
00015 using namespace clang;
00016 using namespace arcmt;
00017 using namespace trans;
00018 
00019 namespace {
00020 
00021 class GCCollectableCallsChecker :
00022                          public RecursiveASTVisitor<GCCollectableCallsChecker> {
00023   MigrationContext &MigrateCtx;
00024   IdentifierInfo *NSMakeCollectableII;
00025   IdentifierInfo *CFMakeCollectableII;
00026 
00027 public:
00028   GCCollectableCallsChecker(MigrationContext &ctx)
00029     : MigrateCtx(ctx) {
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       TA.report(E->getLocStart(), diag::warn_arcmt_nsalloc_realloc,
00042                 E->getSourceRange());
00043       return true;
00044     }
00045 
00046     Expr *CEE = E->getCallee()->IgnoreParenImpCasts();
00047     if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) {
00048       if (FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(DRE->getDecl())) {
00049         if (!FD->getDeclContext()->getRedeclContext()->isFileContext())
00050           return true;
00051 
00052         if (FD->getIdentifier() == NSMakeCollectableII) {
00053           Transaction Trans(TA);
00054           TA.clearDiagnostic(diag::err_unavailable,
00055                              diag::err_unavailable_message,
00056                              diag::err_ovl_deleted_call, // ObjC++
00057                              DRE->getSourceRange());
00058           TA.replace(DRE->getSourceRange(), "CFBridgingRelease");
00059 
00060         } else if (FD->getIdentifier() == CFMakeCollectableII) {
00061           TA.reportError("CFMakeCollectable will leak the object that it "
00062                          "receives in ARC", DRE->getLocation(),
00063                          DRE->getSourceRange());
00064         }
00065       }
00066     }
00067 
00068     return true;
00069   }
00070 };
00071 
00072 } // anonymous namespace
00073 
00074 void GCCollectableCallsTraverser::traverseBody(BodyContext &BodyCtx) {
00075   GCCollectableCallsChecker(BodyCtx.getMigrationContext())
00076                                             .TraverseStmt(BodyCtx.getTopStmt());
00077 }