52 #include "llvm/ADT/SmallString.h"
54 using namespace clang;
55 using namespace arcmt;
56 using namespace trans;
63 std::unique_ptr<ParentMap> StmtMap;
66 mutable std::unique_ptr<ExprSet> Removables;
70 : Pass(pass), ParentD(nullptr), Body(nullptr) {
71 SelfII = &Pass.Ctx.Idents.get(
"self");
74 void transformBody(
Stmt *body,
Decl *ParentD) {
75 this->ParentD = ParentD;
84 UnbridgedCastRewriter(Pass).transformBody(D->
getBody(), D);
103 if (exprRetainable == castRetainable)
return true;
110 if (loc.
isValid() && Pass.Ctx.getSourceManager().isInSystemHeader(loc))
114 transformNonObjCToObjCCast(E);
116 transformObjCToNonObjCCast(E);
122 void transformNonObjCToObjCCast(
CastExpr *E) {
128 castToObjCObject(E,
false);
135 if (
CallExpr *callE = dyn_cast<CallExpr>(inner)) {
137 if (FD->hasAttr<CFReturnsRetainedAttr>()) {
138 castToObjCObject(E,
true);
141 if (FD->hasAttr<CFReturnsNotRetainedAttr>()) {
142 castToObjCObject(E,
false);
145 if (FD->isGlobal() &&
146 FD->getIdentifier() &&
148 FD->getIdentifier()->getName())) {
149 StringRef fname = FD->getIdentifier()->getName();
150 if (fname.endswith(
"Retain") ||
151 fname.find(
"Create") != StringRef::npos ||
152 fname.find(
"Copy") != StringRef::npos) {
156 if (FD->getName() ==
"CFRetain" &&
157 FD->getNumParams() == 1 &&
158 FD->getParent()->isTranslationUnit() &&
159 FD->isExternallyVisible()) {
160 Expr *Arg = callE->getArg(0);
162 const Expr *sub = ICE->getSubExpr();
168 castToObjCObject(E,
true);
172 if (fname.find(
"Get") != StringRef::npos) {
173 castToObjCObject(E,
false);
183 while (isa<MemberExpr>(base))
185 if (isa<ObjCIvarRefExpr>(base) &&
186 isa<ReturnStmt>(StmtMap->getParentIgnoreParenCasts(E))) {
187 if (
ObjCMethodDecl *method = dyn_cast_or_null<ObjCMethodDecl>(ParentD)) {
188 if (!method->hasAttr<NSReturnsRetainedAttr>()) {
189 castToObjCObject(E,
false);
196 void castToObjCObject(
CastExpr *E,
bool retained) {
202 rewriteToBridgedCast(E, Kind, Trans);
211 diag::err_arc_cast_requires_bridge,
220 bridge =
"__bridge ";
break;
222 bridge =
"__bridge_transfer ";
break;
224 bridge =
"__bridge_retained ";
break;
228 diag::err_arc_cast_requires_bridge,
230 if (Kind ==
OBC_Bridge || !Pass.CFBridgingFunctionsDefined()) {
242 TA.
insert(insertLoc, newCast.str());
245 TA.
insert(insertLoc, newCast.str());
262 BridgeCall +=
"CFBridgingRelease";
264 BridgeCall +=
"CFBridgingRetain";
266 if (isa<ParenExpr>(WrapE)) {
267 TA.
insert(InsertLoc, BridgeCall);
270 TA.
insert(InsertLoc, BridgeCall);
278 Pass.TA.replace(callE->getSourceRange(), callE->
getArg(0)->getSourceRange());
296 void rewriteBlockCopyMacro(
CastExpr *E) {
298 getBlockMacroRanges(E, OuterRange, InnerRange);
301 Pass.TA.replace(OuterRange, InnerRange);
302 Pass.TA.insert(InnerRange.
getBegin(),
"[");
303 Pass.TA.insertAfterToken(InnerRange.
getEnd(),
" copy]");
304 Pass.TA.clearDiagnostic(diag::err_arc_mismatched_cast,
305 diag::err_arc_cast_requires_bridge,
309 void removeBlockReleaseMacro(
CastExpr *E) {
311 getBlockMacroRanges(E, OuterRange, InnerRange);
314 Pass.TA.clearDiagnostic(diag::err_arc_mismatched_cast,
315 diag::err_arc_cast_requires_bridge,
318 if (tryRemoving(cast<Expr>(StmtMap->getParentIgnoreParenCasts(E))))
321 Pass.TA.replace(OuterRange, InnerRange);
324 bool tryRemoving(
Expr *E)
const {
330 if (Removables->count(E)) {
331 Pass.TA.removeStmt(E);
338 void transformObjCToNonObjCCast(
CastExpr *E) {
342 Pass.Ctx.getSourceManager(),
343 Pass.Ctx.getLangOpts());
344 if (MacroName ==
"Block_copy") {
345 rewriteBlockCopyMacro(E);
348 if (MacroName ==
"Block_release") {
349 removeBlockReleaseMacro(E);
358 if (isPassedToCFRetain(E, callE))
359 return rewriteCastForCFRetain(E, callE);
366 std::string err =
"it is not safe to cast to '";
368 err +=
"' the result of '";
370 err +=
"' message; a __bridge cast may result in a pointer to a "
371 "destroyed object and a __bridge_retained may leak the object";
372 Pass.TA.reportError(err, E->getLocStart(),
376 parent = StmtMap->getParentIgnoreParenImpCasts(parent);
377 }
while (parent && isa<ExprWithCleanups>(parent));
379 if (
ReturnStmt *retS = dyn_cast_or_null<ReturnStmt>(parent)) {
380 std::string note =
"remove the cast and change return type of function "
383 note +=
"' to have the object automatically autoreleased";
384 Pass.TA.reportNote(note, retS->getLocStart());
392 subExpr = pseudo->getResultExpr();
393 assert(subExpr &&
"no result for pseudo-object of non-void type?");
403 bool isConsumed =
false;
404 if (isPassedToCParamWithKnownOwnership(E, isConsumed))
412 return ME->getMethodFamily();
417 bool isPassedToCFRetain(
Expr *E,
CallExpr *&callE)
const {
418 if ((callE = dyn_cast_or_null<CallExpr>(
419 StmtMap->getParentIgnoreParenImpCasts(E))))
422 if (FD->getName() ==
"CFRetain" && FD->getNumParams() == 1 &&
423 FD->getParent()->isTranslationUnit() &&
424 FD->isExternallyVisible())
430 bool isPassedToCParamWithKnownOwnership(
Expr *E,
bool &isConsumed)
const {
431 if (
CallExpr *callE = dyn_cast_or_null<CallExpr>(
432 StmtMap->getParentIgnoreParenImpCasts(E)))
434 FD = dyn_cast_or_null<FunctionDecl>(callE->
getCalleeDecl())) {
436 for (
unsigned e = callE->
getNumArgs(); i != e; ++i) {
441 if (i < callE->getNumArgs() && i < FD->getNumParams()) {
443 if (PD->
hasAttr<CFConsumedAttr>()) {
453 bool isSelf(
Expr *E)
const {
457 if (IPD->getIdentifier() == SelfII)
Defines the clang::ASTContext interface.
SourceLocation getEnd() const
CastKind getCastKind() const
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
ObjCBridgeCastKind
The kind of bridging performed by the Objective-C bridge cast.
Bridging via __bridge, which does nothing but reinterpret the bits.
Defines the SourceManager interface.
const char * getCharacterData(SourceLocation SL, bool *Invalid=nullptr) const
Return a pointer to the start of the specified location in the appropriate spelling MemoryBuffer...
std::string getAsString() const
[ARC] Consumes a retainable object pointer that has just been produced, e.g. as the return value of a...
ParmVarDecl - Represents a parameter to a function.
bool isObjCRetainableType() const
NullPointerConstantKind isNullPointerConstant(ASTContext &Ctx, NullPointerConstantValueDependence NPC) const
bool TraverseDecl(Decl *D)
Recursively visit a declaration, by dispatching to Traverse*Decl() based on the argument's dynamic ty...
ObjCMethodFamily
A family of Objective-C methods.
bool isGlobalVar(Expr *E)
Stmt * getBody() const override
SourceLocation getLocWithOffset(int Offset) const
Return a source location with the specified offset from this SourceLocation.
SourceLocation getImmediateMacroCallerLoc(SourceLocation Loc) const
Expr * IgnoreParenCasts() LLVM_READONLY
A class that does preorder depth-first traversal on the entire Clang AST and visits each node...
Bridging via __bridge_transfer, which transfers ownership of an Objective-C pointer into ARC...
void collectRemovables(Stmt *S, ExprSet &exprs)
TranslationUnitDecl * getTranslationUnitDecl() const
Specifies that a value-dependent expression of integral or dependent type should be considered a null...
An expression that sends a message to the given Objective-C object or class.
void rewriteUnbridgedCasts(MigrationPass &pass)
Encodes a location in the source. The SourceManager can decode this to get at the full include stack...
bool isValid() const
Return true if this is a valid SourceLocation object.
SourceLocation getBegin() const
static StringRef getImmediateMacroName(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts)
Retrieve the name of the immediate macro expansion.
SourceLocation getExprLoc() const LLVM_READONLY
bool isRefType(QualType RetTy, StringRef Prefix, StringRef Name=StringRef())
bool hasSideEffects(Expr *E, ASTContext &Ctx)
std::pair< SourceLocation, SourceLocation > getImmediateExpansionRange(SourceLocation Loc) const
Return the start/end of the expansion information for an expansion location.
unsigned getNumArgs() const
Bridging via __bridge_retain, which makes an ARC object available as a +1 C pointer.
[ARC] Reclaim a retainable object pointer object that may have been produced and autoreleased as part...
Expr * IgnoreParenImpCasts() LLVM_READONLY
Expr * IgnoreParenLValueCasts() LLVM_READONLY
static bool isIdentifierBodyChar(char c, const LangOptions &LangOpts)
Returns true if the given character could appear in an identifier.
No particular method family.
const internal::VariadicDynCastAllOfMatcher< Stmt, CastExpr > castExpr
Matches any cast nodes of Clang's AST.
bool isObjCObjectPointerType() const
bool isObjCIndirectLifetimeType() const
A reference to a declared variable, function, enum, etc. [C99 6.5.1p2].
A trivial tuple used to represent a source range.
This class handles loading and caching of source files into memory.
bool isPointerType() const