Home | History | Annotate | Download | only in ARCMigrate
      1 //===--- TransGCAttrs.cpp - Transformations to ARC mode --------------------===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #include "Transforms.h"
     11 #include "Internals.h"
     12 #include "clang/Lex/Lexer.h"
     13 #include "clang/Basic/SourceManager.h"
     14 #include "llvm/Support/SaveAndRestore.h"
     15 #include "clang/Sema/SemaDiagnostic.h"
     16 #include "llvm/ADT/SmallString.h"
     17 #include "llvm/ADT/TinyPtrVector.h"
     18 
     19 using namespace clang;
     20 using namespace arcmt;
     21 using namespace trans;
     22 
     23 namespace {
     24 
     25 /// \brief Collects all the places where GC attributes __strong/__weak occur.
     26 class GCAttrsCollector : public RecursiveASTVisitor<GCAttrsCollector> {
     27   MigrationContext &MigrateCtx;
     28   bool FullyMigratable;
     29   std::vector<ObjCPropertyDecl *> &AllProps;
     30 
     31   typedef RecursiveASTVisitor<GCAttrsCollector> base;
     32 public:
     33   GCAttrsCollector(MigrationContext &ctx,
     34                    std::vector<ObjCPropertyDecl *> &AllProps)
     35     : MigrateCtx(ctx), FullyMigratable(false),
     36       AllProps(AllProps) { }
     37 
     38   bool shouldWalkTypesOfTypeLocs() const { return false; }
     39 
     40   bool VisitAttributedTypeLoc(AttributedTypeLoc TL) {
     41     handleAttr(TL);
     42     return true;
     43   }
     44 
     45   bool TraverseDecl(Decl *D) {
     46     if (!D || D->isImplicit())
     47       return true;
     48 
     49     SaveAndRestore<bool> Save(FullyMigratable, isMigratable(D));
     50 
     51     if (ObjCPropertyDecl *PropD = dyn_cast<ObjCPropertyDecl>(D)) {
     52       lookForAttribute(PropD, PropD->getTypeSourceInfo());
     53       AllProps.push_back(PropD);
     54     } else if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) {
     55       lookForAttribute(DD, DD->getTypeSourceInfo());
     56     }
     57     return base::TraverseDecl(D);
     58   }
     59 
     60   void lookForAttribute(Decl *D, TypeSourceInfo *TInfo) {
     61     if (!TInfo)
     62       return;
     63     TypeLoc TL = TInfo->getTypeLoc();
     64     while (TL) {
     65       if (const QualifiedTypeLoc *QL = dyn_cast<QualifiedTypeLoc>(&TL)) {
     66         TL = QL->getUnqualifiedLoc();
     67       } else if (const AttributedTypeLoc *
     68                    Attr = dyn_cast<AttributedTypeLoc>(&TL)) {
     69         if (handleAttr(*Attr, D))
     70           break;
     71         TL = Attr->getModifiedLoc();
     72       } else if (const ArrayTypeLoc *Arr = dyn_cast<ArrayTypeLoc>(&TL)) {
     73         TL = Arr->getElementLoc();
     74       } else if (const PointerTypeLoc *PT = dyn_cast<PointerTypeLoc>(&TL)) {
     75         TL = PT->getPointeeLoc();
     76       } else if (const ReferenceTypeLoc *RT = dyn_cast<ReferenceTypeLoc>(&TL))
     77         TL = RT->getPointeeLoc();
     78       else
     79         break;
     80     }
     81   }
     82 
     83   bool handleAttr(AttributedTypeLoc TL, Decl *D = 0) {
     84     if (TL.getAttrKind() != AttributedType::attr_objc_ownership)
     85       return false;
     86 
     87     SourceLocation Loc = TL.getAttrNameLoc();
     88     unsigned RawLoc = Loc.getRawEncoding();
     89     if (MigrateCtx.AttrSet.count(RawLoc))
     90       return true;
     91 
     92     ASTContext &Ctx = MigrateCtx.Pass.Ctx;
     93     SourceManager &SM = Ctx.getSourceManager();
     94     if (Loc.isMacroID())
     95       Loc = SM.getImmediateExpansionRange(Loc).first;
     96     SmallString<32> Buf;
     97     bool Invalid = false;
     98     StringRef Spell = Lexer::getSpelling(
     99                                   SM.getSpellingLoc(TL.getAttrEnumOperandLoc()),
    100                                   Buf, SM, Ctx.getLangOpts(), &Invalid);
    101     if (Invalid)
    102       return false;
    103     MigrationContext::GCAttrOccurrence::AttrKind Kind;
    104     if (Spell == "strong")
    105       Kind = MigrationContext::GCAttrOccurrence::Strong;
    106     else if (Spell == "weak")
    107       Kind = MigrationContext::GCAttrOccurrence::Weak;
    108     else
    109       return false;
    110 
    111     MigrateCtx.AttrSet.insert(RawLoc);
    112     MigrateCtx.GCAttrs.push_back(MigrationContext::GCAttrOccurrence());
    113     MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs.back();
    114 
    115     Attr.Kind = Kind;
    116     Attr.Loc = Loc;
    117     Attr.ModifiedType = TL.getModifiedLoc().getType();
    118     Attr.Dcl = D;
    119     Attr.FullyMigratable = FullyMigratable;
    120     return true;
    121   }
    122 
    123   bool isMigratable(Decl *D) {
    124     if (isa<TranslationUnitDecl>(D))
    125       return false;
    126 
    127     if (isInMainFile(D))
    128       return true;
    129 
    130     if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
    131       return FD->hasBody();
    132 
    133     if (ObjCContainerDecl *ContD = dyn_cast<ObjCContainerDecl>(D))
    134       return hasObjCImpl(ContD);
    135 
    136     if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
    137       for (CXXRecordDecl::method_iterator
    138              MI = RD->method_begin(), ME = RD->method_end(); MI != ME; ++MI) {
    139         if ((*MI)->isOutOfLine())
    140           return true;
    141       }
    142       return false;
    143     }
    144 
    145     return isMigratable(cast<Decl>(D->getDeclContext()));
    146   }
    147 
    148   static bool hasObjCImpl(Decl *D) {
    149     if (!D)
    150       return false;
    151     if (ObjCContainerDecl *ContD = dyn_cast<ObjCContainerDecl>(D)) {
    152       if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(ContD))
    153         return ID->getImplementation() != 0;
    154       if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(ContD))
    155         return CD->getImplementation() != 0;
    156       if (isa<ObjCImplDecl>(ContD))
    157         return true;
    158       return false;
    159     }
    160     return false;
    161   }
    162 
    163   bool isInMainFile(Decl *D) {
    164     if (!D)
    165       return false;
    166 
    167     for (Decl::redecl_iterator
    168            I = D->redecls_begin(), E = D->redecls_end(); I != E; ++I)
    169       if (!isInMainFile((*I)->getLocation()))
    170         return false;
    171 
    172     return true;
    173   }
    174 
    175   bool isInMainFile(SourceLocation Loc) {
    176     if (Loc.isInvalid())
    177       return false;
    178 
    179     SourceManager &SM = MigrateCtx.Pass.Ctx.getSourceManager();
    180     return SM.isInFileID(SM.getExpansionLoc(Loc), SM.getMainFileID());
    181   }
    182 };
    183 
    184 } // anonymous namespace
    185 
    186 static void errorForGCAttrsOnNonObjC(MigrationContext &MigrateCtx) {
    187   TransformActions &TA = MigrateCtx.Pass.TA;
    188 
    189   for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) {
    190     MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i];
    191     if (Attr.FullyMigratable && Attr.Dcl) {
    192       if (Attr.ModifiedType.isNull())
    193         continue;
    194       if (!Attr.ModifiedType->isObjCRetainableType()) {
    195         TA.reportError("GC managed memory will become unmanaged in ARC",
    196                        Attr.Loc);
    197       }
    198     }
    199   }
    200 }
    201 
    202 static void checkWeakGCAttrs(MigrationContext &MigrateCtx) {
    203   TransformActions &TA = MigrateCtx.Pass.TA;
    204 
    205   for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) {
    206     MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i];
    207     if (Attr.Kind == MigrationContext::GCAttrOccurrence::Weak) {
    208       if (Attr.ModifiedType.isNull() ||
    209           !Attr.ModifiedType->isObjCRetainableType())
    210         continue;
    211       if (!canApplyWeak(MigrateCtx.Pass.Ctx, Attr.ModifiedType,
    212                         /*AllowOnUnknownClass=*/true)) {
    213         Transaction Trans(TA);
    214         if (!MigrateCtx.RemovedAttrSet.count(Attr.Loc.getRawEncoding()))
    215           TA.replaceText(Attr.Loc, "__weak", "__unsafe_unretained");
    216         TA.clearDiagnostic(diag::err_arc_weak_no_runtime,
    217                            diag::err_arc_unsupported_weak_class,
    218                            Attr.Loc);
    219       }
    220     }
    221   }
    222 }
    223 
    224 typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy;
    225 
    226 static void checkAllAtProps(MigrationContext &MigrateCtx,
    227                             SourceLocation AtLoc,
    228                             IndivPropsTy &IndProps) {
    229   if (IndProps.empty())
    230     return;
    231 
    232   for (IndivPropsTy::iterator
    233          PI = IndProps.begin(), PE = IndProps.end(); PI != PE; ++PI) {
    234     QualType T = (*PI)->getType();
    235     if (T.isNull() || !T->isObjCRetainableType())
    236       return;
    237   }
    238 
    239   SmallVector<std::pair<AttributedTypeLoc, ObjCPropertyDecl *>, 4> ATLs;
    240   bool hasWeak = false, hasStrong = false;
    241   ObjCPropertyDecl::PropertyAttributeKind
    242     Attrs = ObjCPropertyDecl::OBJC_PR_noattr;
    243   for (IndivPropsTy::iterator
    244          PI = IndProps.begin(), PE = IndProps.end(); PI != PE; ++PI) {
    245     ObjCPropertyDecl *PD = *PI;
    246     Attrs = PD->getPropertyAttributesAsWritten();
    247     TypeSourceInfo *TInfo = PD->getTypeSourceInfo();
    248     if (!TInfo)
    249       return;
    250     TypeLoc TL = TInfo->getTypeLoc();
    251     if (AttributedTypeLoc *ATL = dyn_cast<AttributedTypeLoc>(&TL)) {
    252       ATLs.push_back(std::make_pair(*ATL, PD));
    253       if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {
    254         hasWeak = true;
    255       } else if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Strong)
    256         hasStrong = true;
    257       else
    258         return;
    259     }
    260   }
    261   if (ATLs.empty())
    262     return;
    263   if (hasWeak && hasStrong)
    264     return;
    265 
    266   TransformActions &TA = MigrateCtx.Pass.TA;
    267   Transaction Trans(TA);
    268 
    269   if (GCAttrsCollector::hasObjCImpl(
    270                               cast<Decl>(IndProps.front()->getDeclContext()))) {
    271     if (hasWeak)
    272       MigrateCtx.AtPropsWeak.insert(AtLoc.getRawEncoding());
    273 
    274   } else {
    275     StringRef toAttr = "strong";
    276     if (hasWeak) {
    277       if (canApplyWeak(MigrateCtx.Pass.Ctx, IndProps.front()->getType(),
    278                        /*AllowOnUnkwownClass=*/true))
    279         toAttr = "weak";
    280       else
    281         toAttr = "unsafe_unretained";
    282     }
    283     if (Attrs & ObjCPropertyDecl::OBJC_PR_assign)
    284       MigrateCtx.rewritePropertyAttribute("assign", toAttr, AtLoc);
    285     else
    286       MigrateCtx.addPropertyAttribute(toAttr, AtLoc);
    287   }
    288 
    289   for (unsigned i = 0, e = ATLs.size(); i != e; ++i) {
    290     SourceLocation Loc = ATLs[i].first.getAttrNameLoc();
    291     if (Loc.isMacroID())
    292       Loc = MigrateCtx.Pass.Ctx.getSourceManager()
    293                                          .getImmediateExpansionRange(Loc).first;
    294     TA.remove(Loc);
    295     TA.clearDiagnostic(diag::err_objc_property_attr_mutually_exclusive, AtLoc);
    296     TA.clearDiagnostic(diag::err_arc_inconsistent_property_ownership,
    297                        ATLs[i].second->getLocation());
    298     MigrateCtx.RemovedAttrSet.insert(Loc.getRawEncoding());
    299   }
    300 }
    301 
    302 static void checkAllProps(MigrationContext &MigrateCtx,
    303                           std::vector<ObjCPropertyDecl *> &AllProps) {
    304   typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy;
    305   llvm::DenseMap<unsigned, IndivPropsTy> AtProps;
    306 
    307   for (unsigned i = 0, e = AllProps.size(); i != e; ++i) {
    308     ObjCPropertyDecl *PD = AllProps[i];
    309     if (PD->getPropertyAttributesAsWritten() &
    310           (ObjCPropertyDecl::OBJC_PR_assign |
    311            ObjCPropertyDecl::OBJC_PR_readonly)) {
    312       SourceLocation AtLoc = PD->getAtLoc();
    313       if (AtLoc.isInvalid())
    314         continue;
    315       unsigned RawAt = AtLoc.getRawEncoding();
    316       AtProps[RawAt].push_back(PD);
    317     }
    318   }
    319 
    320   for (llvm::DenseMap<unsigned, IndivPropsTy>::iterator
    321          I = AtProps.begin(), E = AtProps.end(); I != E; ++I) {
    322     SourceLocation AtLoc = SourceLocation::getFromRawEncoding(I->first);
    323     IndivPropsTy &IndProps = I->second;
    324     checkAllAtProps(MigrateCtx, AtLoc, IndProps);
    325   }
    326 }
    327 
    328 void GCAttrsTraverser::traverseTU(MigrationContext &MigrateCtx) {
    329   std::vector<ObjCPropertyDecl *> AllProps;
    330   GCAttrsCollector(MigrateCtx, AllProps).TraverseDecl(
    331                                   MigrateCtx.Pass.Ctx.getTranslationUnitDecl());
    332 
    333   errorForGCAttrsOnNonObjC(MigrateCtx);
    334   checkAllProps(MigrateCtx, AllProps);
    335   checkWeakGCAttrs(MigrateCtx);
    336 }
    337 
    338 void MigrationContext::dumpGCAttrs() {
    339   llvm::errs() << "\n################\n";
    340   for (unsigned i = 0, e = GCAttrs.size(); i != e; ++i) {
    341     GCAttrOccurrence &Attr = GCAttrs[i];
    342     llvm::errs() << "KIND: "
    343         << (Attr.Kind == GCAttrOccurrence::Strong ? "strong" : "weak");
    344     llvm::errs() << "\nLOC: ";
    345     Attr.Loc.dump(Pass.Ctx.getSourceManager());
    346     llvm::errs() << "\nTYPE: ";
    347     Attr.ModifiedType.dump();
    348     if (Attr.Dcl) {
    349       llvm::errs() << "DECL:\n";
    350       Attr.Dcl->dump();
    351     } else {
    352       llvm::errs() << "DECL: NONE";
    353     }
    354     llvm::errs() << "\nMIGRATABLE: " << Attr.FullyMigratable;
    355     llvm::errs() << "\n----------------\n";
    356   }
    357   llvm::errs() << "\n################\n";
    358 }
    359