TransGCAttrs.cpp 11 KB

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