diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/ARCMigrate/TransProperties.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/ARCMigrate/TransProperties.cpp | 328 |
1 files changed, 154 insertions, 174 deletions
diff --git a/contrib/llvm/tools/clang/lib/ARCMigrate/TransProperties.cpp b/contrib/llvm/tools/clang/lib/ARCMigrate/TransProperties.cpp index ca845b6..cc85fe2 100644 --- a/contrib/llvm/tools/clang/lib/ARCMigrate/TransProperties.cpp +++ b/contrib/llvm/tools/clang/lib/ARCMigrate/TransProperties.cpp @@ -44,8 +44,17 @@ using namespace trans; namespace { class PropertiesRewriter { + MigrationContext &MigrateCtx; MigrationPass &Pass; ObjCImplementationDecl *CurImplD; + + enum PropActionKind { + PropAction_None, + PropAction_RetainReplacedWithStrong, + PropAction_AssignRemoved, + PropAction_AssignRewritten, + PropAction_MaybeAddWeakOrUnsafe + }; struct PropData { ObjCPropertyDecl *PropD; @@ -58,9 +67,27 @@ class PropertiesRewriter { typedef SmallVector<PropData, 2> PropsTy; typedef std::map<unsigned, PropsTy> AtPropDeclsTy; AtPropDeclsTy AtProps; + llvm::DenseMap<IdentifierInfo *, PropActionKind> ActionOnProp; public: - PropertiesRewriter(MigrationPass &pass) : Pass(pass) { } + explicit PropertiesRewriter(MigrationContext &MigrateCtx) + : MigrateCtx(MigrateCtx), Pass(MigrateCtx.Pass) { } + + static void collectProperties(ObjCContainerDecl *D, AtPropDeclsTy &AtProps, + AtPropDeclsTy *PrevAtProps = 0) { + for (ObjCInterfaceDecl::prop_iterator + propI = D->prop_begin(), + propE = D->prop_end(); propI != propE; ++propI) { + if (propI->getAtLoc().isInvalid()) + continue; + unsigned RawLoc = propI->getAtLoc().getRawEncoding(); + if (PrevAtProps) + if (PrevAtProps->find(RawLoc) != PrevAtProps->end()) + continue; + PropsTy &props = AtProps[RawLoc]; + props.push_back(*propI); + } + } void doTransform(ObjCImplementationDecl *D) { CurImplD = D; @@ -68,14 +95,7 @@ public: if (!iface) return; - for (ObjCInterfaceDecl::prop_iterator - propI = iface->prop_begin(), - propE = iface->prop_end(); propI != propE; ++propI) { - if (propI->getAtLoc().isInvalid()) - continue; - PropsTy &props = AtProps[propI->getAtLoc().getRawEncoding()]; - props.push_back(*propI); - } + collectProperties(iface, AtProps); typedef DeclContext::specific_decl_iterator<ObjCPropertyImplDecl> prop_impl_iterator; @@ -110,19 +130,66 @@ public: I = AtProps.begin(), E = AtProps.end(); I != E; ++I) { SourceLocation atLoc = SourceLocation::getFromRawEncoding(I->first); PropsTy &props = I->second; - QualType ty = getPropertyType(props); - if (!ty->isObjCRetainableType()) + if (!getPropertyType(props)->isObjCRetainableType()) continue; - if (hasIvarWithExplicitOwnership(props)) + if (hasIvarWithExplicitARCOwnership(props)) continue; Transaction Trans(Pass.TA); rewriteProperty(props, atLoc); } + + AtPropDeclsTy AtExtProps; + // Look through extensions. + for (ObjCCategoryDecl *Cat = iface->getCategoryList(); + Cat; Cat = Cat->getNextClassCategory()) + if (Cat->IsClassExtension()) + collectProperties(Cat, AtExtProps, &AtProps); + + for (AtPropDeclsTy::iterator + I = AtExtProps.begin(), E = AtExtProps.end(); I != E; ++I) { + SourceLocation atLoc = SourceLocation::getFromRawEncoding(I->first); + PropsTy &props = I->second; + Transaction Trans(Pass.TA); + doActionForExtensionProp(props, atLoc); + } } private: - void rewriteProperty(PropsTy &props, SourceLocation atLoc) const { + 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; + case PropAction_RetainReplacedWithStrong: { + StringRef toAttr = "strong"; + MigrateCtx.rewritePropertyAttribute("retain", toAttr, atLoc); + return; + } + case PropAction_AssignRemoved: + return removeAssignForDefaultStrong(props, atLoc); + case PropAction_AssignRewritten: + return rewriteAssign(props, atLoc); + case PropAction_MaybeAddWeakOrUnsafe: + return maybeAddWeakOrUnsafeUnretainedAttr(props, atLoc); + } + } + + void doActionForExtensionProp(PropsTy &props, SourceLocation atLoc) { + llvm::DenseMap<IdentifierInfo *, PropActionKind>::iterator I; + I = ActionOnProp.find(props[0].PropD->getIdentifier()); + if (I == ActionOnProp.end()) + return; + + doPropAction(I->second, props, atLoc, false); + } + + void rewriteProperty(PropsTy &props, SourceLocation atLoc) { ObjCPropertyDecl::PropertyAttributeKind propAttrs = getPropertyAttrs(props); if (propAttrs & (ObjCPropertyDecl::OBJC_PR_copy | @@ -132,79 +199,82 @@ private: return; if (propAttrs & ObjCPropertyDecl::OBJC_PR_retain) { - rewriteAttribute("retain", "strong", atLoc); - return; + // strong is the default. + return doPropAction(PropAction_RetainReplacedWithStrong, props, atLoc); } + bool HasIvarAssignedAPlusOneObject = hasIvarAssignedAPlusOneObject(props); + if (propAttrs & ObjCPropertyDecl::OBJC_PR_assign) { - if (hasIvarAssignedAPlusOneObject(props)) { - rewriteAttribute("assign", "strong", atLoc); - return; - } - return rewriteAssign(props, atLoc); + if (HasIvarAssignedAPlusOneObject) + return doPropAction(PropAction_AssignRemoved, props, atLoc); + return doPropAction(PropAction_AssignRewritten, props, atLoc); } - if (hasIvarAssignedAPlusOneObject(props)) - return maybeAddStrongAttr(props, atLoc); + if (HasIvarAssignedAPlusOneObject || + (Pass.isGCMigration() && !hasGCWeak(props, atLoc))) + return; // 'strong' by default. - return maybeAddWeakOrUnsafeUnretainedAttr(props, atLoc); + return doPropAction(PropAction_MaybeAddWeakOrUnsafe, props, atLoc); } - void rewriteAssign(PropsTy &props, SourceLocation atLoc) const { - bool canUseWeak = canApplyWeak(Pass.Ctx, getPropertyType(props)); - - bool rewroteAttr = rewriteAttribute("assign", - canUseWeak ? "weak" : "unsafe_unretained", - atLoc); - if (!rewroteAttr) - canUseWeak = false; + 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 (isUserDeclared(I->IvarD)) - Pass.TA.insert(I->IvarD->getLocation(), - canUseWeak ? "__weak " : "__unsafe_unretained "); if (I->ImplD) Pass.TA.clearDiagnostic(diag::err_arc_assign_property_ownership, I->ImplD->getLocation()); } } - void maybeAddWeakOrUnsafeUnretainedAttr(PropsTy &props, - SourceLocation atLoc) const { - ObjCPropertyDecl::PropertyAttributeKind propAttrs = getPropertyAttrs(props); + void rewriteAssign(PropsTy &props, SourceLocation atLoc) const { + bool canUseWeak = canApplyWeak(Pass.Ctx, getPropertyType(props), + /*AllowOnUnknownClass=*/Pass.isGCMigration()); + const char *toWhich = + (Pass.isGCMigration() && !hasGCWeak(props, atLoc)) ? "strong" : + (canUseWeak ? "weak" : "unsafe_unretained"); - bool canUseWeak = canApplyWeak(Pass.Ctx, getPropertyType(props)); - if (!(propAttrs & ObjCPropertyDecl::OBJC_PR_readonly) || - !hasAllIvarsBacked(props)) { - bool addedAttr = addAttribute(canUseWeak ? "weak" : "unsafe_unretained", - atLoc); - if (!addedAttr) - canUseWeak = false; - } + bool rewroteAttr = rewriteAttribute("assign", toWhich, atLoc); + if (!rewroteAttr) + canUseWeak = false; for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) { - if (isUserDeclared(I->IvarD)) - Pass.TA.insert(I->IvarD->getLocation(), - canUseWeak ? "__weak " : "__unsafe_unretained "); - if (I->ImplD) { + if (isUserDeclared(I->IvarD)) { + if (I->IvarD && + I->IvarD->getType().getObjCLifetime() != Qualifiers::OCL_Weak) { + const char *toWhich = + (Pass.isGCMigration() && !hasGCWeak(props, atLoc)) ? "__strong " : + (canUseWeak ? "__weak " : "__unsafe_unretained "); + Pass.TA.insert(I->IvarD->getLocation(), toWhich); + } + } + if (I->ImplD) Pass.TA.clearDiagnostic(diag::err_arc_assign_property_ownership, I->ImplD->getLocation()); - Pass.TA.clearDiagnostic( - diag::err_arc_objc_property_default_assign_on_object, - I->ImplD->getLocation()); - } } } - void maybeAddStrongAttr(PropsTy &props, SourceLocation atLoc) const { - ObjCPropertyDecl::PropertyAttributeKind propAttrs = getPropertyAttrs(props); + void maybeAddWeakOrUnsafeUnretainedAttr(PropsTy &props, + SourceLocation atLoc) const { + bool canUseWeak = canApplyWeak(Pass.Ctx, getPropertyType(props), + /*AllowOnUnknownClass=*/Pass.isGCMigration()); - if (!(propAttrs & ObjCPropertyDecl::OBJC_PR_readonly) || - !hasAllIvarsBacked(props)) { - addAttribute("strong", atLoc); - } + bool addedAttr = addAttribute(canUseWeak ? "weak" : "unsafe_unretained", + atLoc); + if (!addedAttr) + canUseWeak = false; for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) { + if (isUserDeclared(I->IvarD)) { + if (I->IvarD && + I->IvarD->getType().getObjCLifetime() != Qualifiers::OCL_Weak) + Pass.TA.insert(I->IvarD->getLocation(), + canUseWeak ? "__weak " : "__unsafe_unretained "); + } if (I->ImplD) { Pass.TA.clearDiagnostic(diag::err_arc_assign_property_ownership, I->ImplD->getLocation()); @@ -215,108 +285,17 @@ private: } } + bool removeAttribute(StringRef fromAttr, SourceLocation atLoc) const { + return MigrateCtx.removePropertyAttribute(fromAttr, atLoc); + } + bool rewriteAttribute(StringRef fromAttr, StringRef toAttr, SourceLocation atLoc) const { - if (atLoc.isMacroID()) - return false; - - SourceManager &SM = Pass.Ctx.getSourceManager(); - - // Break down the source location. - std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(atLoc); - - // Try to load the file buffer. - bool invalidTemp = false; - StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); - if (invalidTemp) - return false; - - const char *tokenBegin = file.data() + locInfo.second; - - // Lex from the start of the given location. - Lexer lexer(SM.getLocForStartOfFile(locInfo.first), - Pass.Ctx.getLangOptions(), - file.begin(), tokenBegin, file.end()); - Token tok; - lexer.LexFromRawLexer(tok); - if (tok.isNot(tok::at)) return false; - lexer.LexFromRawLexer(tok); - if (tok.isNot(tok::raw_identifier)) return false; - if (StringRef(tok.getRawIdentifierData(), tok.getLength()) - != "property") - return false; - lexer.LexFromRawLexer(tok); - if (tok.isNot(tok::l_paren)) return false; - - lexer.LexFromRawLexer(tok); - if (tok.is(tok::r_paren)) - return false; - - while (1) { - if (tok.isNot(tok::raw_identifier)) return false; - StringRef ident(tok.getRawIdentifierData(), tok.getLength()); - if (ident == fromAttr) { - Pass.TA.replaceText(tok.getLocation(), fromAttr, toAttr); - return true; - } - - do { - lexer.LexFromRawLexer(tok); - } while (tok.isNot(tok::comma) && tok.isNot(tok::r_paren)); - if (tok.is(tok::r_paren)) - break; - lexer.LexFromRawLexer(tok); - } - - return false; + return MigrateCtx.rewritePropertyAttribute(fromAttr, toAttr, atLoc); } bool addAttribute(StringRef attr, SourceLocation atLoc) const { - if (atLoc.isMacroID()) - return false; - - SourceManager &SM = Pass.Ctx.getSourceManager(); - - // Break down the source location. - std::pair<FileID, unsigned> locInfo = SM.getDecomposedLoc(atLoc); - - // Try to load the file buffer. - bool invalidTemp = false; - StringRef file = SM.getBufferData(locInfo.first, &invalidTemp); - if (invalidTemp) - return false; - - const char *tokenBegin = file.data() + locInfo.second; - - // Lex from the start of the given location. - Lexer lexer(SM.getLocForStartOfFile(locInfo.first), - Pass.Ctx.getLangOptions(), - file.begin(), tokenBegin, file.end()); - Token tok; - lexer.LexFromRawLexer(tok); - if (tok.isNot(tok::at)) return false; - lexer.LexFromRawLexer(tok); - if (tok.isNot(tok::raw_identifier)) return false; - if (StringRef(tok.getRawIdentifierData(), tok.getLength()) - != "property") - return false; - lexer.LexFromRawLexer(tok); - - if (tok.isNot(tok::l_paren)) { - Pass.TA.insert(tok.getLocation(), std::string("(") + attr.str() + ") "); - return true; - } - - lexer.LexFromRawLexer(tok); - if (tok.is(tok::r_paren)) { - Pass.TA.insert(tok.getLocation(), attr); - return true; - } - - if (tok.isNot(tok::raw_identifier)) return false; - - Pass.TA.insert(tok.getLocation(), std::string(attr) + ", "); - return true; + return MigrateCtx.addPropertyAttribute(attr, atLoc); } class PlusOneAssign : public RecursiveASTVisitor<PlusOneAssign> { @@ -358,7 +337,10 @@ private: return false; } - bool hasIvarWithExplicitOwnership(PropsTy &props) const { + bool hasIvarWithExplicitARCOwnership(PropsTy &props) const { + if (Pass.isGCMigration()) + return false; + for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) { if (isUserDeclared(I->IvarD)) { if (isa<AttributedType>(I->IvarD->getType())) @@ -380,17 +362,26 @@ private: return true; } + // \brief Returns true if all declarations in the @property have GC __weak. + bool hasGCWeak(PropsTy &props, SourceLocation atLoc) const { + if (!Pass.isGCMigration()) + return false; + if (props.empty()) + return false; + return MigrateCtx.AtPropsWeak.count(atLoc.getRawEncoding()); + } + bool isUserDeclared(ObjCIvarDecl *ivarD) const { return ivarD && !ivarD->getSynthesize(); } QualType getPropertyType(PropsTy &props) const { assert(!props.empty()); - QualType ty = props[0].PropD->getType(); + QualType ty = props[0].PropD->getType().getUnqualifiedType(); #ifndef NDEBUG for (PropsTy::iterator I = props.begin(), E = props.end(); I != E; ++I) - assert(ty == I->PropD->getType()); + assert(ty == I->PropD->getType().getUnqualifiedType()); #endif return ty; @@ -411,21 +402,10 @@ private: } }; -class ImplementationChecker : - public RecursiveASTVisitor<ImplementationChecker> { - MigrationPass &Pass; - -public: - ImplementationChecker(MigrationPass &pass) : Pass(pass) { } - - bool TraverseObjCImplementationDecl(ObjCImplementationDecl *D) { - PropertiesRewriter(Pass).doTransform(D); - return true; - } -}; - } // anonymous namespace -void trans::rewriteProperties(MigrationPass &pass) { - ImplementationChecker(pass).TraverseDecl(pass.Ctx.getTranslationUnitDecl()); +void PropertyRewriteTraverser::traverseObjCImplementation( + ObjCImplementationContext &ImplCtx) { + PropertiesRewriter(ImplCtx.getMigrationContext()) + .doTransform(ImplCtx.getImplementationDecl()); } |