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