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