clang API Documentation
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 }