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);
89 if (E->
getCastKind() != CK_CPointerToObjCPointerCast &&
91 E->
getCastKind() != CK_AnyPointerToBlockPointerCast)
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?");
397 if (implCE->getCastKind() == CK_ARCConsumeObject)
399 if (implCE->getCastKind() == CK_ARCReclaimReturnedObject)
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
FunctionDecl - An instance of this class is created to represent a function declaration or definition...
A (possibly-)qualified type.
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
ObjCMethodDecl - Represents an instance or class method declaration.
ParmVarDecl - Represents a parameter to a function.
bool isObjCRetainableType() const
NullPointerConstantKind isNullPointerConstant(ASTContext &Ctx, NullPointerConstantValueDependence NPC) const
isNullPointerConstant - C99 6.3.2.3p3 - Test if this reduces down to a Null pointer constant...
bool TraverseDecl(Decl *D)
Recursively visit a declaration, by dispatching to Traverse*Decl() based on the argument's dynamic ty...
One of these records is kept for each identifier that is lexed.
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
Gets the location of the immediate macro caller, one level up the stack toward the initial macro type...
Expr * IgnoreParenCasts() LLVM_READONLY
IgnoreParenCasts - Ignore parentheses and casts.
CastExpr - Base class for type casts, including both implicit casts (ImplicitCastExpr) and explicit c...
A class that does preordor or postorder depth-first traversal on the entire Clang AST and visits each...
Bridging via __bridge_transfer, which transfers ownership of an Objective-C pointer into ARC...
void collectRemovables(Stmt *S, ExprSet &exprs)
BlockDecl - This represents a block literal declaration, which is like an unnamed FunctionDecl...
Expr - This represents one expression.
TranslationUnitDecl * getTranslationUnitDecl() const
Specifies that a value-dependent expression of integral or dependent type should be considered a null...
ReturnStmt - This represents a return, optionally of an expression: return; return 4;...
An expression that sends a message to the given Objective-C object or class.
CStyleCastExpr - An explicit cast in C (C99 6.5.4) or a C-style cast in C++ (C++ [expr.cast]), which uses the syntax (Type)expr.
void rewriteUnbridgedCasts(MigrationPass &pass)
PseudoObjectExpr - An expression which accesses a pseudo-object l-value.
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
ImplicitCastExpr - Allows us to explicitly represent implicit type conversions, which have no direct ...
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
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
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.
detail::InMemoryDirectory::const_iterator E
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Bridging via __bridge_retain, which makes an ARC object available as a +1 C pointer.
Expr * IgnoreParenImpCasts() LLVM_READONLY
IgnoreParenImpCasts - Ignore parentheses and implicit casts.
Expr * IgnoreParenLValueCasts() LLVM_READONLY
Ignore parentheses and lvalue casts.
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
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
bool isObjCIndirectLifetimeType() const
A reference to a declared variable, function, enum, etc.
A trivial tuple used to represent a source range.
This class handles loading and caching of source files into memory.
unsigned getNumArgs() const
Retrieve the number of template arguments.
bool isPointerType() const