2012-11-14 23:08:31 +08:00
|
|
|
//===--- TransProperties.cpp - Transformations to ARC mode ----------------===//
|
2011-06-22 04:20:39 +08:00
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2011-06-22 04:20:39 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
2011-07-14 03:22:00 +08:00
|
|
|
// rewriteProperties:
|
2011-06-22 04:20:39 +08:00
|
|
|
//
|
2011-07-14 03:22:00 +08:00
|
|
|
// - Adds strong/weak/unsafe_unretained ownership specifier to properties that
|
|
|
|
// are missing one.
|
|
|
|
// - Migrates properties from (retain) to (strong) and (assign) to
|
|
|
|
// (unsafe_unretained/weak).
|
|
|
|
// - If a property is synthesized, adds the ownership specifier in the ivar
|
|
|
|
// backing the property.
|
2011-06-22 04:20:39 +08:00
|
|
|
//
|
|
|
|
// @interface Foo : NSObject {
|
|
|
|
// NSObject *x;
|
|
|
|
// }
|
|
|
|
// @property (assign) id x;
|
|
|
|
// @end
|
|
|
|
// ---->
|
|
|
|
// @interface Foo : NSObject {
|
|
|
|
// NSObject *__weak x;
|
|
|
|
// }
|
|
|
|
// @property (weak) id x;
|
|
|
|
// @end
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "Transforms.h"
|
|
|
|
#include "Internals.h"
|
|
|
|
#include "clang/Basic/SourceManager.h"
|
|
|
|
#include "clang/Lex/Lexer.h"
|
2012-12-04 17:13:33 +08:00
|
|
|
#include "clang/Sema/SemaDiagnostic.h"
|
2011-07-14 03:22:00 +08:00
|
|
|
#include <map>
|
2011-06-22 04:20:39 +08:00
|
|
|
|
|
|
|
using namespace clang;
|
|
|
|
using namespace arcmt;
|
|
|
|
using namespace trans;
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2011-07-14 03:22:00 +08:00
|
|
|
class PropertiesRewriter {
|
2011-11-08 02:46:46 +08:00
|
|
|
MigrationContext &MigrateCtx;
|
2011-06-22 04:20:39 +08:00
|
|
|
MigrationPass &Pass;
|
2011-07-27 13:28:18 +08:00
|
|
|
ObjCImplementationDecl *CurImplD;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-10-19 03:49:19 +08:00
|
|
|
enum PropActionKind {
|
|
|
|
PropAction_None,
|
2012-01-21 03:15:02 +08:00
|
|
|
PropAction_RetainReplacedWithStrong,
|
2011-11-08 02:46:46 +08:00
|
|
|
PropAction_AssignRemoved,
|
2011-10-19 03:49:19 +08:00
|
|
|
PropAction_AssignRewritten,
|
|
|
|
PropAction_MaybeAddWeakOrUnsafe
|
|
|
|
};
|
2011-07-14 03:22:00 +08:00
|
|
|
|
2011-06-22 04:20:39 +08:00
|
|
|
struct PropData {
|
|
|
|
ObjCPropertyDecl *PropD;
|
|
|
|
ObjCIvarDecl *IvarD;
|
2011-07-14 03:22:00 +08:00
|
|
|
ObjCPropertyImplDecl *ImplD;
|
|
|
|
|
2014-05-07 14:21:57 +08:00
|
|
|
PropData(ObjCPropertyDecl *propD)
|
|
|
|
: PropD(propD), IvarD(nullptr), ImplD(nullptr) {}
|
2011-06-22 04:20:39 +08:00
|
|
|
};
|
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
typedef SmallVector<PropData, 2> PropsTy;
|
2020-10-20 01:30:51 +08:00
|
|
|
typedef std::map<SourceLocation, PropsTy> AtPropDeclsTy;
|
2011-07-14 03:22:00 +08:00
|
|
|
AtPropDeclsTy AtProps;
|
2011-10-19 03:49:19 +08:00
|
|
|
llvm::DenseMap<IdentifierInfo *, PropActionKind> ActionOnProp;
|
2011-06-22 04:20:39 +08:00
|
|
|
|
|
|
|
public:
|
2011-11-08 02:46:46 +08:00
|
|
|
explicit PropertiesRewriter(MigrationContext &MigrateCtx)
|
|
|
|
: MigrateCtx(MigrateCtx), Pass(MigrateCtx.Pass) { }
|
2011-06-22 04:20:39 +08:00
|
|
|
|
2012-03-29 09:10:31 +08:00
|
|
|
static void collectProperties(ObjCContainerDecl *D, AtPropDeclsTy &AtProps,
|
2014-05-07 14:21:57 +08:00
|
|
|
AtPropDeclsTy *PrevAtProps = nullptr) {
|
2016-01-27 02:05:23 +08:00
|
|
|
for (auto *Prop : D->instance_properties()) {
|
2020-10-20 01:30:51 +08:00
|
|
|
SourceLocation Loc = Prop->getAtLoc();
|
|
|
|
if (Loc.isInvalid())
|
2011-07-14 03:22:00 +08:00
|
|
|
continue;
|
2012-03-29 09:10:31 +08:00
|
|
|
if (PrevAtProps)
|
2020-10-20 01:30:51 +08:00
|
|
|
if (PrevAtProps->find(Loc) != PrevAtProps->end())
|
2012-03-29 09:10:31 +08:00
|
|
|
continue;
|
2020-10-20 01:30:51 +08:00
|
|
|
PropsTy &props = AtProps[Loc];
|
2014-03-14 02:47:37 +08:00
|
|
|
props.push_back(Prop);
|
2011-06-22 04:20:39 +08:00
|
|
|
}
|
2011-10-19 03:49:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void doTransform(ObjCImplementationDecl *D) {
|
|
|
|
CurImplD = D;
|
|
|
|
ObjCInterfaceDecl *iface = D->getClassInterface();
|
|
|
|
if (!iface)
|
|
|
|
return;
|
|
|
|
|
|
|
|
collectProperties(iface, AtProps);
|
2011-06-22 04:20:39 +08:00
|
|
|
|
Stop back-patching 'readonly' Objective-C properties with 'readwrite' ones.
A 'readonly' Objective-C property declared in the primary class can
effectively be shadowed by a 'readwrite' property declared within an
extension of that class, so long as the types and attributes of the
two property declarations are compatible.
Previously, this functionality was implemented by back-patching the
original 'readonly' property to make it 'readwrite', destroying source
information and causing some hideously redundant, incorrect
code. Simplify the implementation to express how this should actually
be modeled: as a separate property declaration in the extension that
shadows (via the name lookup rules) the declaration in the primary
class. While here, correct some broken Fix-Its, eliminate a pile of
redundant code, clean up the ARC migrator's handling of properties
declared in extensions, and fix debug info's naming of methods that
come from categories.
A wonderous side effect of doing this write is that it eliminates the
"AddedObjCPropertyInClassExtension" method from the AST mutation
listener, which in turn eliminates the last place where we rewrite
entire declarations in a chained PCH file or a module file. This
change (which fixes rdar://problem/18475765) will allow us to
eliminate the rewritten-decls logic from the serialization library,
and fixes a crash (rdar://problem/23247794) illustrated by the
test/PCH/chain-categories.m example.
llvm-svn: 251874
2015-11-03 09:15:46 +08:00
|
|
|
// Look through extensions.
|
|
|
|
for (auto *Ext : iface->visible_extensions())
|
|
|
|
collectProperties(Ext, AtProps);
|
|
|
|
|
2011-06-22 04:20:39 +08:00
|
|
|
typedef DeclContext::specific_decl_iterator<ObjCPropertyImplDecl>
|
|
|
|
prop_impl_iterator;
|
|
|
|
for (prop_impl_iterator
|
|
|
|
I = prop_impl_iterator(D->decls_begin()),
|
|
|
|
E = prop_impl_iterator(D->decls_end()); I != E; ++I) {
|
2012-06-07 04:45:41 +08:00
|
|
|
ObjCPropertyImplDecl *implD = *I;
|
2011-07-14 03:22:00 +08:00
|
|
|
if (implD->getPropertyImplementation() != ObjCPropertyImplDecl::Synthesize)
|
|
|
|
continue;
|
|
|
|
ObjCPropertyDecl *propD = implD->getPropertyDecl();
|
|
|
|
if (!propD || propD->isInvalidDecl())
|
|
|
|
continue;
|
|
|
|
ObjCIvarDecl *ivarD = implD->getPropertyIvarDecl();
|
|
|
|
if (!ivarD || ivarD->isInvalidDecl())
|
|
|
|
continue;
|
2020-10-20 01:30:51 +08:00
|
|
|
AtPropDeclsTy::iterator findAtLoc = AtProps.find(propD->getAtLoc());
|
2011-07-14 03:22:00 +08:00
|
|
|
if (findAtLoc == AtProps.end())
|
|
|
|
continue;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-07-14 03:22:00 +08:00
|
|
|
PropsTy &props = findAtLoc->second;
|
|
|
|
for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
|
|
|
|
if (I->PropD == propD) {
|
|
|
|
I->IvarD = ivarD;
|
|
|
|
I->ImplD = implD;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2011-06-22 04:20:39 +08:00
|
|
|
}
|
|
|
|
|
2011-07-14 03:22:00 +08:00
|
|
|
for (AtPropDeclsTy::iterator
|
|
|
|
I = AtProps.begin(), E = AtProps.end(); I != E; ++I) {
|
2020-10-20 01:30:51 +08:00
|
|
|
SourceLocation atLoc = I->first;
|
2011-06-22 04:20:39 +08:00
|
|
|
PropsTy &props = I->second;
|
2011-11-07 02:58:07 +08:00
|
|
|
if (!getPropertyType(props)->isObjCRetainableType())
|
2011-07-14 03:22:00 +08:00
|
|
|
continue;
|
2011-11-08 02:40:32 +08:00
|
|
|
if (hasIvarWithExplicitARCOwnership(props))
|
2011-07-14 03:22:00 +08:00
|
|
|
continue;
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2011-07-14 03:22:00 +08:00
|
|
|
Transaction Trans(Pass.TA);
|
|
|
|
rewriteProperty(props, atLoc);
|
2011-06-22 04:20:39 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-14 03:22:00 +08:00
|
|
|
private:
|
2011-10-19 03:49:19 +08:00
|
|
|
void doPropAction(PropActionKind kind,
|
|
|
|
PropsTy &props, SourceLocation atLoc,
|
|
|
|
bool markAction = true) {
|
|
|
|
if (markAction)
|
|
|
|
for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I)
|
|
|
|
ActionOnProp[I->PropD->getIdentifier()] = kind;
|
|
|
|
|
|
|
|
switch (kind) {
|
|
|
|
case PropAction_None:
|
|
|
|
return;
|
2012-01-21 03:15:02 +08:00
|
|
|
case PropAction_RetainReplacedWithStrong: {
|
|
|
|
StringRef toAttr = "strong";
|
|
|
|
MigrateCtx.rewritePropertyAttribute("retain", toAttr, atLoc);
|
2011-10-19 03:49:19 +08:00
|
|
|
return;
|
2012-01-21 03:15:02 +08:00
|
|
|
}
|
2011-11-08 02:46:46 +08:00
|
|
|
case PropAction_AssignRemoved:
|
|
|
|
return removeAssignForDefaultStrong(props, atLoc);
|
2011-10-19 03:49:19 +08:00
|
|
|
case PropAction_AssignRewritten:
|
|
|
|
return rewriteAssign(props, atLoc);
|
|
|
|
case PropAction_MaybeAddWeakOrUnsafe:
|
|
|
|
return maybeAddWeakOrUnsafeUnretainedAttr(props, atLoc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void rewriteProperty(PropsTy &props, SourceLocation atLoc) {
|
2020-04-23 14:20:56 +08:00
|
|
|
ObjCPropertyAttribute::Kind propAttrs = getPropertyAttrs(props);
|
2018-07-31 03:24:48 +08:00
|
|
|
|
2020-04-23 14:20:56 +08:00
|
|
|
if (propAttrs &
|
|
|
|
(ObjCPropertyAttribute::kind_copy |
|
|
|
|
ObjCPropertyAttribute::kind_unsafe_unretained |
|
|
|
|
ObjCPropertyAttribute::kind_strong | ObjCPropertyAttribute::kind_weak))
|
2011-07-14 03:22:00 +08:00
|
|
|
return;
|
|
|
|
|
2020-04-23 14:20:56 +08:00
|
|
|
if (propAttrs & ObjCPropertyAttribute::kind_retain) {
|
2011-11-09 07:09:34 +08:00
|
|
|
// strong is the default.
|
2012-01-21 03:15:02 +08:00
|
|
|
return doPropAction(PropAction_RetainReplacedWithStrong, props, atLoc);
|
2011-06-22 04:20:39 +08:00
|
|
|
}
|
2011-07-14 03:22:00 +08:00
|
|
|
|
2011-11-08 02:46:46 +08:00
|
|
|
bool HasIvarAssignedAPlusOneObject = hasIvarAssignedAPlusOneObject(props);
|
|
|
|
|
2020-04-23 14:20:56 +08:00
|
|
|
if (propAttrs & ObjCPropertyAttribute::kind_assign) {
|
2012-01-21 08:43:53 +08:00
|
|
|
if (HasIvarAssignedAPlusOneObject)
|
2011-11-08 02:46:46 +08:00
|
|
|
return doPropAction(PropAction_AssignRemoved, props, atLoc);
|
2011-10-19 03:49:19 +08:00
|
|
|
return doPropAction(PropAction_AssignRewritten, props, atLoc);
|
2011-07-27 13:28:18 +08:00
|
|
|
}
|
|
|
|
|
2011-11-08 02:46:46 +08:00
|
|
|
if (HasIvarAssignedAPlusOneObject ||
|
|
|
|
(Pass.isGCMigration() && !hasGCWeak(props, atLoc)))
|
2011-11-09 06:10:58 +08:00
|
|
|
return; // 'strong' by default.
|
2011-07-14 03:22:00 +08:00
|
|
|
|
2011-10-19 03:49:19 +08:00
|
|
|
return doPropAction(PropAction_MaybeAddWeakOrUnsafe, props, atLoc);
|
2011-06-22 04:20:39 +08:00
|
|
|
}
|
|
|
|
|
2011-11-08 02:46:46 +08:00
|
|
|
void removeAssignForDefaultStrong(PropsTy &props,
|
|
|
|
SourceLocation atLoc) const {
|
|
|
|
removeAttribute("retain", atLoc);
|
|
|
|
if (!removeAttribute("assign", atLoc))
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
|
|
|
|
if (I->ImplD)
|
2012-12-13 06:48:25 +08:00
|
|
|
Pass.TA.clearDiagnostic(diag::err_arc_strong_property_ownership,
|
|
|
|
diag::err_arc_assign_property_ownership,
|
|
|
|
diag::err_arc_inconsistent_property_ownership,
|
|
|
|
I->IvarD->getLocation());
|
2011-11-08 02:46:46 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-14 03:22:00 +08:00
|
|
|
void rewriteAssign(PropsTy &props, SourceLocation atLoc) const {
|
2011-11-08 02:46:46 +08:00
|
|
|
bool canUseWeak = canApplyWeak(Pass.Ctx, getPropertyType(props),
|
|
|
|
/*AllowOnUnknownClass=*/Pass.isGCMigration());
|
2018-07-31 03:24:48 +08:00
|
|
|
const char *toWhich =
|
2012-01-21 08:43:53 +08:00
|
|
|
(Pass.isGCMigration() && !hasGCWeak(props, atLoc)) ? "strong" :
|
|
|
|
(canUseWeak ? "weak" : "unsafe_unretained");
|
2011-07-14 03:22:00 +08:00
|
|
|
|
2012-01-21 08:43:53 +08:00
|
|
|
bool rewroteAttr = rewriteAttribute("assign", toWhich, atLoc);
|
2011-07-14 03:22:00 +08:00
|
|
|
if (!rewroteAttr)
|
|
|
|
canUseWeak = false;
|
2011-06-22 04:20:39 +08:00
|
|
|
|
2011-07-14 03:22:00 +08:00
|
|
|
for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
|
2011-11-28 08:23:12 +08:00
|
|
|
if (isUserDeclared(I->IvarD)) {
|
|
|
|
if (I->IvarD &&
|
2012-01-21 08:43:53 +08:00
|
|
|
I->IvarD->getType().getObjCLifetime() != Qualifiers::OCL_Weak) {
|
2018-07-31 03:24:48 +08:00
|
|
|
const char *toWhich =
|
2012-01-21 08:43:53 +08:00
|
|
|
(Pass.isGCMigration() && !hasGCWeak(props, atLoc)) ? "__strong " :
|
|
|
|
(canUseWeak ? "__weak " : "__unsafe_unretained ");
|
|
|
|
Pass.TA.insert(I->IvarD->getLocation(), toWhich);
|
|
|
|
}
|
2011-11-28 08:23:12 +08:00
|
|
|
}
|
2011-07-14 03:22:00 +08:00
|
|
|
if (I->ImplD)
|
2012-12-13 06:48:25 +08:00
|
|
|
Pass.TA.clearDiagnostic(diag::err_arc_strong_property_ownership,
|
|
|
|
diag::err_arc_assign_property_ownership,
|
|
|
|
diag::err_arc_inconsistent_property_ownership,
|
|
|
|
I->IvarD->getLocation());
|
2011-07-14 03:22:00 +08:00
|
|
|
}
|
2011-06-22 04:20:39 +08:00
|
|
|
}
|
|
|
|
|
2011-07-14 03:22:00 +08:00
|
|
|
void maybeAddWeakOrUnsafeUnretainedAttr(PropsTy &props,
|
|
|
|
SourceLocation atLoc) const {
|
2011-11-08 02:46:46 +08:00
|
|
|
bool canUseWeak = canApplyWeak(Pass.Ctx, getPropertyType(props),
|
|
|
|
/*AllowOnUnknownClass=*/Pass.isGCMigration());
|
2011-11-09 07:09:34 +08:00
|
|
|
|
|
|
|
bool addedAttr = addAttribute(canUseWeak ? "weak" : "unsafe_unretained",
|
|
|
|
atLoc);
|
|
|
|
if (!addedAttr)
|
|
|
|
canUseWeak = false;
|
2011-07-14 03:22:00 +08:00
|
|
|
|
|
|
|
for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
|
2011-11-28 08:23:12 +08:00
|
|
|
if (isUserDeclared(I->IvarD)) {
|
|
|
|
if (I->IvarD &&
|
|
|
|
I->IvarD->getType().getObjCLifetime() != Qualifiers::OCL_Weak)
|
|
|
|
Pass.TA.insert(I->IvarD->getLocation(),
|
|
|
|
canUseWeak ? "__weak " : "__unsafe_unretained ");
|
|
|
|
}
|
2011-07-14 03:22:00 +08:00
|
|
|
if (I->ImplD) {
|
2012-12-13 06:48:25 +08:00
|
|
|
Pass.TA.clearDiagnostic(diag::err_arc_strong_property_ownership,
|
|
|
|
diag::err_arc_assign_property_ownership,
|
|
|
|
diag::err_arc_inconsistent_property_ownership,
|
|
|
|
I->IvarD->getLocation());
|
2011-07-14 03:22:00 +08:00
|
|
|
Pass.TA.clearDiagnostic(
|
|
|
|
diag::err_arc_objc_property_default_assign_on_object,
|
|
|
|
I->ImplD->getLocation());
|
2011-06-22 04:20:39 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-18 07:14:16 +08:00
|
|
|
bool removeAttribute(StringRef fromAttr, SourceLocation atLoc) const {
|
2011-11-28 10:04:36 +08:00
|
|
|
return MigrateCtx.removePropertyAttribute(fromAttr, atLoc);
|
2011-10-18 07:14:16 +08:00
|
|
|
}
|
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
bool rewriteAttribute(StringRef fromAttr, StringRef toAttr,
|
2011-07-14 03:22:00 +08:00
|
|
|
SourceLocation atLoc) const {
|
2011-11-08 02:46:46 +08:00
|
|
|
return MigrateCtx.rewritePropertyAttribute(fromAttr, toAttr, atLoc);
|
2011-06-22 04:20:39 +08:00
|
|
|
}
|
|
|
|
|
2011-07-23 18:55:15 +08:00
|
|
|
bool addAttribute(StringRef attr, SourceLocation atLoc) const {
|
2011-11-28 10:04:36 +08:00
|
|
|
return MigrateCtx.addPropertyAttribute(attr, atLoc);
|
2011-07-14 03:22:00 +08:00
|
|
|
}
|
|
|
|
|
2011-07-27 13:28:18 +08:00
|
|
|
class PlusOneAssign : public RecursiveASTVisitor<PlusOneAssign> {
|
|
|
|
ObjCIvarDecl *Ivar;
|
|
|
|
public:
|
|
|
|
PlusOneAssign(ObjCIvarDecl *D) : Ivar(D) {}
|
|
|
|
|
Removed a RecursiveASTVisitor feature to visit operator kinds with different methods
Summary:
This feature was only used in two places, but contributed a non-trivial
amount to the complexity of RecursiveASTVisitor, and was buggy (see my
recent patches where I was fixing the bugs that I noticed). I don't
think the convenience benefit of this feature is worth the complexity.
Besides complexity, another issue with the current state of
RecursiveASTVisitor is the non-uniformity in how it handles different
AST nodes. All AST nodes follow a regular pattern, but operators are
special -- and this special behavior not documented. Correct usage of
RecursiveASTVisitor relies on shadowing member functions with specific
names and signatures. Near misses don't cause any compile-time errors,
incorrectly named or typed methods are just silently ignored. Therefore,
predictability of RecursiveASTVisitor API is quite important.
This change reduces the size of the `clang` binary by 38 KB (0.2%) in
release mode, and by 7 MB (0.3%) in debug mode. The `clang-tidy` binary
is reduced by 205 KB (0.3%) in release mode, and by 5 MB (0.4%) in debug
mode. I don't think these code size improvements are significant enough
to justify this change on its own (for me, the primary motivation is
reducing code complexity), but they I think are a nice side-effect.
Reviewers: rsmith, sammccall, ymandel, aaron.ballman
Reviewed By: rsmith, sammccall, ymandel, aaron.ballman
Subscribers: cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D82921
2020-07-03 23:01:01 +08:00
|
|
|
bool VisitBinaryOperator(BinaryOperator *E) {
|
|
|
|
if (E->getOpcode() != BO_Assign)
|
|
|
|
return true;
|
|
|
|
|
2011-07-27 13:28:18 +08:00
|
|
|
Expr *lhs = E->getLHS()->IgnoreParenImpCasts();
|
|
|
|
if (ObjCIvarRefExpr *RE = dyn_cast<ObjCIvarRefExpr>(lhs)) {
|
|
|
|
if (RE->getDecl() != Ivar)
|
|
|
|
return true;
|
|
|
|
|
2012-05-24 05:50:04 +08:00
|
|
|
if (isPlusOneAssign(E))
|
2011-08-11 05:46:48 +08:00
|
|
|
return false;
|
2011-07-27 13:28:18 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
bool hasIvarAssignedAPlusOneObject(PropsTy &props) const {
|
|
|
|
for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
|
|
|
|
PlusOneAssign oneAssign(I->IvarD);
|
|
|
|
bool notFound = oneAssign.TraverseDecl(CurImplD);
|
|
|
|
if (!notFound)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2011-11-08 02:40:32 +08:00
|
|
|
bool hasIvarWithExplicitARCOwnership(PropsTy &props) const {
|
|
|
|
if (Pass.isGCMigration())
|
|
|
|
return false;
|
|
|
|
|
2011-07-14 03:22:00 +08:00
|
|
|
for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) {
|
|
|
|
if (isUserDeclared(I->IvarD)) {
|
|
|
|
if (isa<AttributedType>(I->IvarD->getType()))
|
|
|
|
return true;
|
|
|
|
if (I->IvarD->getType().getLocalQualifiers().getObjCLifetime()
|
|
|
|
!= Qualifiers::OCL_Strong)
|
|
|
|
return true;
|
2011-06-22 04:20:39 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-31 03:24:48 +08:00
|
|
|
return false;
|
2011-07-14 03:22:00 +08:00
|
|
|
}
|
|
|
|
|
2018-05-09 09:00:01 +08:00
|
|
|
// Returns true if all declarations in the @property have GC __weak.
|
2011-11-08 02:46:46 +08:00
|
|
|
bool hasGCWeak(PropsTy &props, SourceLocation atLoc) const {
|
|
|
|
if (!Pass.isGCMigration())
|
|
|
|
return false;
|
|
|
|
if (props.empty())
|
|
|
|
return false;
|
2020-10-20 23:21:38 +08:00
|
|
|
return MigrateCtx.AtPropsWeak.count(atLoc);
|
2011-11-08 02:46:46 +08:00
|
|
|
}
|
|
|
|
|
2011-07-14 03:22:00 +08:00
|
|
|
bool isUserDeclared(ObjCIvarDecl *ivarD) const {
|
|
|
|
return ivarD && !ivarD->getSynthesize();
|
|
|
|
}
|
|
|
|
|
|
|
|
QualType getPropertyType(PropsTy &props) const {
|
|
|
|
assert(!props.empty());
|
2011-11-07 02:58:07 +08:00
|
|
|
QualType ty = props[0].PropD->getType().getUnqualifiedType();
|
2011-07-14 03:22:00 +08:00
|
|
|
|
|
|
|
#ifndef NDEBUG
|
|
|
|
for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I)
|
2011-11-07 02:58:07 +08:00
|
|
|
assert(ty == I->PropD->getType().getUnqualifiedType());
|
2011-07-14 03:22:00 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
return ty;
|
|
|
|
}
|
|
|
|
|
2020-04-23 14:20:56 +08:00
|
|
|
ObjCPropertyAttribute::Kind getPropertyAttrs(PropsTy &props) const {
|
2011-07-14 03:22:00 +08:00
|
|
|
assert(!props.empty());
|
2020-04-23 14:20:56 +08:00
|
|
|
ObjCPropertyAttribute::Kind attrs =
|
|
|
|
props[0].PropD->getPropertyAttributesAsWritten();
|
2011-07-14 03:22:00 +08:00
|
|
|
|
|
|
|
#ifndef NDEBUG
|
|
|
|
for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I)
|
|
|
|
assert(attrs == I->PropD->getPropertyAttributesAsWritten());
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return attrs;
|
2011-06-22 04:20:39 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
} // anonymous namespace
|
|
|
|
|
2011-11-07 02:57:57 +08:00
|
|
|
void PropertyRewriteTraverser::traverseObjCImplementation(
|
|
|
|
ObjCImplementationContext &ImplCtx) {
|
2011-11-08 02:46:46 +08:00
|
|
|
PropertiesRewriter(ImplCtx.getMigrationContext())
|
2011-11-07 02:57:57 +08:00
|
|
|
.doTransform(ImplCtx.getImplementationDecl());
|
2011-06-22 04:20:39 +08:00
|
|
|
}
|