clang API Documentation

TransGCAttrs.cpp
Go to the documentation of this file.
00001 //===--- TransGCAttrs.cpp - Transformations to ARC mode --------------------===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 
00010 #include "Transforms.h"
00011 #include "Internals.h"
00012 #include "clang/Lex/Lexer.h"
00013 #include "clang/Basic/SourceManager.h"
00014 #include "llvm/Support/SaveAndRestore.h"
00015 #include "clang/Sema/SemaDiagnostic.h"
00016 #include "llvm/ADT/SmallString.h"
00017 #include "llvm/ADT/TinyPtrVector.h"
00018 
00019 using namespace clang;
00020 using namespace arcmt;
00021 using namespace trans;
00022 
00023 namespace {
00024 
00025 /// \brief Collects all the places where GC attributes __strong/__weak occur.
00026 class GCAttrsCollector : public RecursiveASTVisitor<GCAttrsCollector> {
00027   MigrationContext &MigrateCtx;
00028   bool FullyMigratable;
00029   std::vector<ObjCPropertyDecl *> &AllProps;
00030 
00031   typedef RecursiveASTVisitor<GCAttrsCollector> base;
00032 public:
00033   GCAttrsCollector(MigrationContext &ctx,
00034                    std::vector<ObjCPropertyDecl *> &AllProps)
00035     : MigrateCtx(ctx), FullyMigratable(false),
00036       AllProps(AllProps) { }
00037 
00038   bool shouldWalkTypesOfTypeLocs() const { return false; }
00039 
00040   bool VisitAttributedTypeLoc(AttributedTypeLoc TL) {
00041     handleAttr(TL);
00042     return true;
00043   }
00044 
00045   bool TraverseDecl(Decl *D) {
00046     if (!D || D->isImplicit())
00047       return true;
00048 
00049     SaveAndRestore<bool> Save(FullyMigratable, isMigratable(D));
00050     
00051     if (ObjCPropertyDecl *PropD = dyn_cast<ObjCPropertyDecl>(D)) {
00052       lookForAttribute(PropD, PropD->getTypeSourceInfo());
00053       AllProps.push_back(PropD);
00054     } else if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) {
00055       lookForAttribute(DD, DD->getTypeSourceInfo());
00056     }
00057     return base::TraverseDecl(D);
00058   }
00059 
00060   void lookForAttribute(Decl *D, TypeSourceInfo *TInfo) {
00061     if (!TInfo)
00062       return;
00063     TypeLoc TL = TInfo->getTypeLoc();
00064     while (TL) {
00065       if (const QualifiedTypeLoc *QL = dyn_cast<QualifiedTypeLoc>(&TL)) {
00066         TL = QL->getUnqualifiedLoc();
00067       } else if (const AttributedTypeLoc *
00068                    Attr = dyn_cast<AttributedTypeLoc>(&TL)) {
00069         if (handleAttr(*Attr, D))
00070           break;
00071         TL = Attr->getModifiedLoc();
00072       } else if (const ArrayTypeLoc *Arr = dyn_cast<ArrayTypeLoc>(&TL)) {
00073         TL = Arr->getElementLoc();
00074       } else if (const PointerTypeLoc *PT = dyn_cast<PointerTypeLoc>(&TL)) {
00075         TL = PT->getPointeeLoc();
00076       } else if (const ReferenceTypeLoc *RT = dyn_cast<ReferenceTypeLoc>(&TL))
00077         TL = RT->getPointeeLoc();
00078       else
00079         break;
00080     }
00081   }
00082 
00083   bool handleAttr(AttributedTypeLoc TL, Decl *D = 0) {
00084     if (TL.getAttrKind() != AttributedType::attr_objc_ownership)
00085       return false;
00086 
00087     SourceLocation Loc = TL.getAttrNameLoc();
00088     unsigned RawLoc = Loc.getRawEncoding();
00089     if (MigrateCtx.AttrSet.count(RawLoc))
00090       return true;
00091 
00092     ASTContext &Ctx = MigrateCtx.Pass.Ctx;
00093     SourceManager &SM = Ctx.getSourceManager();
00094     if (Loc.isMacroID())
00095       Loc = SM.getImmediateExpansionRange(Loc).first;
00096     SmallString<32> Buf;
00097     bool Invalid = false;
00098     StringRef Spell = Lexer::getSpelling(
00099                                   SM.getSpellingLoc(TL.getAttrEnumOperandLoc()),
00100                                   Buf, SM, Ctx.getLangOpts(), &Invalid);
00101     if (Invalid)
00102       return false;
00103     MigrationContext::GCAttrOccurrence::AttrKind Kind;
00104     if (Spell == "strong")
00105       Kind = MigrationContext::GCAttrOccurrence::Strong;
00106     else if (Spell == "weak")
00107       Kind = MigrationContext::GCAttrOccurrence::Weak;
00108     else
00109       return false;
00110  
00111     MigrateCtx.AttrSet.insert(RawLoc);
00112     MigrateCtx.GCAttrs.push_back(MigrationContext::GCAttrOccurrence());
00113     MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs.back();
00114 
00115     Attr.Kind = Kind;
00116     Attr.Loc = Loc;
00117     Attr.ModifiedType = TL.getModifiedLoc().getType();
00118     Attr.Dcl = D;
00119     Attr.FullyMigratable = FullyMigratable;
00120     return true;
00121   }
00122 
00123   bool isMigratable(Decl *D) {
00124     if (isa<TranslationUnitDecl>(D))
00125       return false;
00126 
00127     if (isInMainFile(D))
00128       return true;
00129 
00130     if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
00131       return FD->hasBody();
00132 
00133     if (ObjCContainerDecl *ContD = dyn_cast<ObjCContainerDecl>(D))
00134       return hasObjCImpl(ContD);
00135 
00136     if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
00137       for (CXXRecordDecl::method_iterator
00138              MI = RD->method_begin(), ME = RD->method_end(); MI != ME; ++MI) {
00139         if (MI->isOutOfLine())
00140           return true;
00141       }
00142       return false;
00143     }
00144 
00145     return isMigratable(cast<Decl>(D->getDeclContext()));
00146   }
00147 
00148   static bool hasObjCImpl(Decl *D) {
00149     if (!D)
00150       return false;
00151     if (ObjCContainerDecl *ContD = dyn_cast<ObjCContainerDecl>(D)) {
00152       if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(ContD))
00153         return ID->getImplementation() != 0;
00154       if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(ContD))
00155         return CD->getImplementation() != 0;
00156       if (isa<ObjCImplDecl>(ContD))
00157         return true;
00158       return false;
00159     }
00160     return false;
00161   }
00162 
00163   bool isInMainFile(Decl *D) {
00164     if (!D)
00165       return false;
00166 
00167     for (Decl::redecl_iterator
00168            I = D->redecls_begin(), E = D->redecls_end(); I != E; ++I)
00169       if (!isInMainFile(I->getLocation()))
00170         return false;
00171     
00172     return true;
00173   }
00174 
00175   bool isInMainFile(SourceLocation Loc) {
00176     if (Loc.isInvalid())
00177       return false;
00178 
00179     SourceManager &SM = MigrateCtx.Pass.Ctx.getSourceManager();
00180     return SM.isInFileID(SM.getExpansionLoc(Loc), SM.getMainFileID());
00181   }
00182 };
00183 
00184 } // anonymous namespace
00185 
00186 static void errorForGCAttrsOnNonObjC(MigrationContext &MigrateCtx) {
00187   TransformActions &TA = MigrateCtx.Pass.TA;
00188 
00189   for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) {
00190     MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i];
00191     if (Attr.FullyMigratable && Attr.Dcl) {
00192       if (Attr.ModifiedType.isNull())
00193         continue;
00194       if (!Attr.ModifiedType->isObjCRetainableType()) {
00195         TA.reportError("GC managed memory will become unmanaged in ARC",
00196                        Attr.Loc);
00197       }
00198     }
00199   }
00200 }
00201 
00202 static void checkWeakGCAttrs(MigrationContext &MigrateCtx) {
00203   TransformActions &TA = MigrateCtx.Pass.TA;
00204 
00205   for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) {
00206     MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i];
00207     if (Attr.Kind == MigrationContext::GCAttrOccurrence::Weak) {
00208       if (Attr.ModifiedType.isNull() ||
00209           !Attr.ModifiedType->isObjCRetainableType())
00210         continue;
00211       if (!canApplyWeak(MigrateCtx.Pass.Ctx, Attr.ModifiedType,
00212                         /*AllowOnUnknownClass=*/true)) {
00213         Transaction Trans(TA);
00214         if (!MigrateCtx.RemovedAttrSet.count(Attr.Loc.getRawEncoding()))
00215           TA.replaceText(Attr.Loc, "__weak", "__unsafe_unretained");
00216         TA.clearDiagnostic(diag::err_arc_weak_no_runtime,
00217                            diag::err_arc_unsupported_weak_class,
00218                            Attr.Loc);
00219       }
00220     }
00221   }
00222 }
00223 
00224 typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy;
00225 
00226 static void checkAllAtProps(MigrationContext &MigrateCtx,
00227                             SourceLocation AtLoc,
00228                             IndivPropsTy &IndProps) {
00229   if (IndProps.empty())
00230     return;
00231 
00232   for (IndivPropsTy::iterator
00233          PI = IndProps.begin(), PE = IndProps.end(); PI != PE; ++PI) {
00234     QualType T = (*PI)->getType();
00235     if (T.isNull() || !T->isObjCRetainableType())
00236       return;
00237   }
00238 
00239   SmallVector<std::pair<AttributedTypeLoc, ObjCPropertyDecl *>, 4> ATLs;
00240   bool hasWeak = false, hasStrong = false;
00241   ObjCPropertyDecl::PropertyAttributeKind
00242     Attrs = ObjCPropertyDecl::OBJC_PR_noattr;
00243   for (IndivPropsTy::iterator
00244          PI = IndProps.begin(), PE = IndProps.end(); PI != PE; ++PI) {
00245     ObjCPropertyDecl *PD = *PI;
00246     Attrs = PD->getPropertyAttributesAsWritten();
00247     TypeSourceInfo *TInfo = PD->getTypeSourceInfo();
00248     if (!TInfo)
00249       return;
00250     TypeLoc TL = TInfo->getTypeLoc();
00251     if (AttributedTypeLoc *ATL = dyn_cast<AttributedTypeLoc>(&TL)) {
00252       ATLs.push_back(std::make_pair(*ATL, PD));
00253       if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {
00254         hasWeak = true;
00255       } else if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Strong)
00256         hasStrong = true;
00257       else
00258         return;
00259     }
00260   }
00261   if (ATLs.empty())
00262     return;
00263   if (hasWeak && hasStrong)
00264     return;
00265 
00266   TransformActions &TA = MigrateCtx.Pass.TA;
00267   Transaction Trans(TA);
00268 
00269   if (GCAttrsCollector::hasObjCImpl(
00270                               cast<Decl>(IndProps.front()->getDeclContext()))) {
00271     if (hasWeak)
00272       MigrateCtx.AtPropsWeak.insert(AtLoc.getRawEncoding());
00273 
00274   } else {
00275     StringRef toAttr = "strong";
00276     if (hasWeak) {
00277       if (canApplyWeak(MigrateCtx.Pass.Ctx, IndProps.front()->getType(),
00278                        /*AllowOnUnkwownClass=*/true))
00279         toAttr = "weak";
00280       else
00281         toAttr = "unsafe_unretained";
00282     }
00283     if (Attrs & ObjCPropertyDecl::OBJC_PR_assign)
00284       MigrateCtx.rewritePropertyAttribute("assign", toAttr, AtLoc);
00285     else
00286       MigrateCtx.addPropertyAttribute(toAttr, AtLoc);
00287   }
00288 
00289   for (unsigned i = 0, e = ATLs.size(); i != e; ++i) {
00290     SourceLocation Loc = ATLs[i].first.getAttrNameLoc();
00291     if (Loc.isMacroID())
00292       Loc = MigrateCtx.Pass.Ctx.getSourceManager()
00293                                          .getImmediateExpansionRange(Loc).first;
00294     TA.remove(Loc);
00295     TA.clearDiagnostic(diag::err_objc_property_attr_mutually_exclusive, AtLoc);
00296     TA.clearDiagnostic(diag::err_arc_inconsistent_property_ownership,
00297                        ATLs[i].second->getLocation());
00298     MigrateCtx.RemovedAttrSet.insert(Loc.getRawEncoding());
00299   }
00300 }
00301 
00302 static void checkAllProps(MigrationContext &MigrateCtx,
00303                           std::vector<ObjCPropertyDecl *> &AllProps) {
00304   typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy;
00305   llvm::DenseMap<unsigned, IndivPropsTy> AtProps;
00306 
00307   for (unsigned i = 0, e = AllProps.size(); i != e; ++i) {
00308     ObjCPropertyDecl *PD = AllProps[i];
00309     if (PD->getPropertyAttributesAsWritten() &
00310           (ObjCPropertyDecl::OBJC_PR_assign |
00311            ObjCPropertyDecl::OBJC_PR_readonly)) {
00312       SourceLocation AtLoc = PD->getAtLoc();
00313       if (AtLoc.isInvalid())
00314         continue;
00315       unsigned RawAt = AtLoc.getRawEncoding();
00316       AtProps[RawAt].push_back(PD);
00317     }
00318   }
00319 
00320   for (llvm::DenseMap<unsigned, IndivPropsTy>::iterator
00321          I = AtProps.begin(), E = AtProps.end(); I != E; ++I) {
00322     SourceLocation AtLoc = SourceLocation::getFromRawEncoding(I->first);
00323     IndivPropsTy &IndProps = I->second;
00324     checkAllAtProps(MigrateCtx, AtLoc, IndProps);
00325   }
00326 }
00327 
00328 void GCAttrsTraverser::traverseTU(MigrationContext &MigrateCtx) {
00329   std::vector<ObjCPropertyDecl *> AllProps;
00330   GCAttrsCollector(MigrateCtx, AllProps).TraverseDecl(
00331                                   MigrateCtx.Pass.Ctx.getTranslationUnitDecl());
00332 
00333   errorForGCAttrsOnNonObjC(MigrateCtx);
00334   checkAllProps(MigrateCtx, AllProps);
00335   checkWeakGCAttrs(MigrateCtx);
00336 }
00337 
00338 void MigrationContext::dumpGCAttrs() {
00339   llvm::errs() << "\n################\n";
00340   for (unsigned i = 0, e = GCAttrs.size(); i != e; ++i) {
00341     GCAttrOccurrence &Attr = GCAttrs[i];
00342     llvm::errs() << "KIND: "
00343         << (Attr.Kind == GCAttrOccurrence::Strong ? "strong" : "weak");
00344     llvm::errs() << "\nLOC: ";
00345     Attr.Loc.dump(Pass.Ctx.getSourceManager());
00346     llvm::errs() << "\nTYPE: ";
00347     Attr.ModifiedType.dump();
00348     if (Attr.Dcl) {
00349       llvm::errs() << "DECL:\n";
00350       Attr.Dcl->dump();
00351     } else {
00352       llvm::errs() << "DECL: NONE";
00353     }
00354     llvm::errs() << "\nMIGRATABLE: " << Attr.FullyMigratable;
00355     llvm::errs() << "\n----------------\n";
00356   }
00357   llvm::errs() << "\n################\n";
00358 }