clang  3.7.0
TransGCAttrs.cpp
Go to the documentation of this file.
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"
14 #include "clang/Lex/Lexer.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 
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 (QualifiedTypeLoc QL = TL.getAs<QualifiedTypeLoc>()) {
67  TL = QL.getUnqualifiedLoc();
68  } else if (AttributedTypeLoc Attr = TL.getAs<AttributedTypeLoc>()) {
69  if (handleAttr(Attr, D))
70  break;
71  TL = Attr.getModifiedLoc();
72  } else if (ArrayTypeLoc Arr = TL.getAs<ArrayTypeLoc>()) {
73  TL = Arr.getElementLoc();
74  } else if (PointerTypeLoc PT = TL.getAs<PointerTypeLoc>()) {
75  TL = PT.getPointeeLoc();
76  } else if (ReferenceTypeLoc RT = TL.getAs<ReferenceTypeLoc>())
77  TL = RT.getPointeeLoc();
78  else
79  break;
80  }
81  }
82 
83  bool handleAttr(AttributedTypeLoc TL, Decl *D = nullptr) {
85  return false;
86 
87  SourceLocation Loc = TL.getAttrNameLoc();
88  unsigned RawLoc = Loc.getRawEncoding();
89  if (MigrateCtx.AttrSet.count(RawLoc))
90  return true;
91 
92  ASTContext &Ctx = MigrateCtx.Pass.Ctx;
94  if (Loc.isMacroID())
95  Loc = SM.getImmediateExpansionRange(Loc).first;
96  SmallString<32> Buf;
97  bool Invalid = false;
98  StringRef Spell = Lexer::getSpelling(
100  Buf, SM, Ctx.getLangOpts(), &Invalid);
101  if (Invalid)
102  return false;
104  if (Spell == "strong")
106  else if (Spell == "weak")
108  else
109  return false;
110 
111  MigrateCtx.AttrSet.insert(RawLoc);
112  MigrateCtx.GCAttrs.push_back(MigrationContext::GCAttrOccurrence());
113  MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs.back();
114 
115  Attr.Kind = Kind;
116  Attr.Loc = Loc;
117  Attr.ModifiedType = TL.getModifiedLoc().getType();
118  Attr.Dcl = D;
119  Attr.FullyMigratable = FullyMigratable;
120  return true;
121  }
122 
123  bool isMigratable(Decl *D) {
124  if (isa<TranslationUnitDecl>(D))
125  return false;
126 
127  if (isInMainFile(D))
128  return true;
129 
130  if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
131  return FD->hasBody();
132 
133  if (ObjCContainerDecl *ContD = dyn_cast<ObjCContainerDecl>(D))
134  return hasObjCImpl(ContD);
135 
136  if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
137  for (const auto *MI : RD->methods()) {
138  if (MI->isOutOfLine())
139  return true;
140  }
141  return false;
142  }
143 
144  return isMigratable(cast<Decl>(D->getDeclContext()));
145  }
146 
147  static bool hasObjCImpl(Decl *D) {
148  if (!D)
149  return false;
150  if (ObjCContainerDecl *ContD = dyn_cast<ObjCContainerDecl>(D)) {
151  if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(ContD))
152  return ID->getImplementation() != nullptr;
153  if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(ContD))
154  return CD->getImplementation() != nullptr;
155  if (isa<ObjCImplDecl>(ContD))
156  return true;
157  return false;
158  }
159  return false;
160  }
161 
162  bool isInMainFile(Decl *D) {
163  if (!D)
164  return false;
165 
166  for (auto I : D->redecls())
167  if (!isInMainFile(I->getLocation()))
168  return false;
169 
170  return true;
171  }
172 
173  bool isInMainFile(SourceLocation Loc) {
174  if (Loc.isInvalid())
175  return false;
176 
177  SourceManager &SM = MigrateCtx.Pass.Ctx.getSourceManager();
178  return SM.isInFileID(SM.getExpansionLoc(Loc), SM.getMainFileID());
179  }
180 };
181 
182 } // anonymous namespace
183 
184 static void errorForGCAttrsOnNonObjC(MigrationContext &MigrateCtx) {
185  TransformActions &TA = MigrateCtx.Pass.TA;
186 
187  for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) {
188  MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i];
189  if (Attr.FullyMigratable && Attr.Dcl) {
190  if (Attr.ModifiedType.isNull())
191  continue;
192  if (!Attr.ModifiedType->isObjCRetainableType()) {
193  TA.reportError("GC managed memory will become unmanaged in ARC",
194  Attr.Loc);
195  }
196  }
197  }
198 }
199 
200 static void checkWeakGCAttrs(MigrationContext &MigrateCtx) {
201  TransformActions &TA = MigrateCtx.Pass.TA;
202 
203  for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) {
204  MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i];
206  if (Attr.ModifiedType.isNull() ||
208  continue;
209  if (!canApplyWeak(MigrateCtx.Pass.Ctx, Attr.ModifiedType,
210  /*AllowOnUnknownClass=*/true)) {
211  Transaction Trans(TA);
212  if (!MigrateCtx.RemovedAttrSet.count(Attr.Loc.getRawEncoding()))
213  TA.replaceText(Attr.Loc, "__weak", "__unsafe_unretained");
214  TA.clearDiagnostic(diag::err_arc_weak_no_runtime,
215  diag::err_arc_unsupported_weak_class,
216  Attr.Loc);
217  }
218  }
219  }
220 }
221 
222 typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy;
223 
224 static void checkAllAtProps(MigrationContext &MigrateCtx,
225  SourceLocation AtLoc,
226  IndivPropsTy &IndProps) {
227  if (IndProps.empty())
228  return;
229 
230  for (IndivPropsTy::iterator
231  PI = IndProps.begin(), PE = IndProps.end(); PI != PE; ++PI) {
232  QualType T = (*PI)->getType();
233  if (T.isNull() || !T->isObjCRetainableType())
234  return;
235  }
236 
238  bool hasWeak = false, hasStrong = false;
241  for (IndivPropsTy::iterator
242  PI = IndProps.begin(), PE = IndProps.end(); PI != PE; ++PI) {
243  ObjCPropertyDecl *PD = *PI;
244  Attrs = PD->getPropertyAttributesAsWritten();
245  TypeSourceInfo *TInfo = PD->getTypeSourceInfo();
246  if (!TInfo)
247  return;
248  TypeLoc TL = TInfo->getTypeLoc();
249  if (AttributedTypeLoc ATL =
250  TL.getAs<AttributedTypeLoc>()) {
251  ATLs.push_back(std::make_pair(ATL, PD));
252  if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {
253  hasWeak = true;
254  } else if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Strong)
255  hasStrong = true;
256  else
257  return;
258  }
259  }
260  if (ATLs.empty())
261  return;
262  if (hasWeak && hasStrong)
263  return;
264 
265  TransformActions &TA = MigrateCtx.Pass.TA;
266  Transaction Trans(TA);
267 
268  if (GCAttrsCollector::hasObjCImpl(
269  cast<Decl>(IndProps.front()->getDeclContext()))) {
270  if (hasWeak)
271  MigrateCtx.AtPropsWeak.insert(AtLoc.getRawEncoding());
272 
273  } else {
274  StringRef toAttr = "strong";
275  if (hasWeak) {
276  if (canApplyWeak(MigrateCtx.Pass.Ctx, IndProps.front()->getType(),
277  /*AllowOnUnkwownClass=*/true))
278  toAttr = "weak";
279  else
280  toAttr = "unsafe_unretained";
281  }
283  MigrateCtx.rewritePropertyAttribute("assign", toAttr, AtLoc);
284  else
285  MigrateCtx.addPropertyAttribute(toAttr, AtLoc);
286  }
287 
288  for (unsigned i = 0, e = ATLs.size(); i != e; ++i) {
289  SourceLocation Loc = ATLs[i].first.getAttrNameLoc();
290  if (Loc.isMacroID())
291  Loc = MigrateCtx.Pass.Ctx.getSourceManager()
292  .getImmediateExpansionRange(Loc).first;
293  TA.remove(Loc);
294  TA.clearDiagnostic(diag::err_objc_property_attr_mutually_exclusive, AtLoc);
295  TA.clearDiagnostic(diag::err_arc_inconsistent_property_ownership,
296  ATLs[i].second->getLocation());
297  MigrateCtx.RemovedAttrSet.insert(Loc.getRawEncoding());
298  }
299 }
300 
301 static void checkAllProps(MigrationContext &MigrateCtx,
302  std::vector<ObjCPropertyDecl *> &AllProps) {
303  typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy;
304  llvm::DenseMap<unsigned, IndivPropsTy> AtProps;
305 
306  for (unsigned i = 0, e = AllProps.size(); i != e; ++i) {
307  ObjCPropertyDecl *PD = AllProps[i];
311  SourceLocation AtLoc = PD->getAtLoc();
312  if (AtLoc.isInvalid())
313  continue;
314  unsigned RawAt = AtLoc.getRawEncoding();
315  AtProps[RawAt].push_back(PD);
316  }
317  }
318 
319  for (llvm::DenseMap<unsigned, IndivPropsTy>::iterator
320  I = AtProps.begin(), E = AtProps.end(); I != E; ++I) {
322  IndivPropsTy &IndProps = I->second;
323  checkAllAtProps(MigrateCtx, AtLoc, IndProps);
324  }
325 }
326 
328  std::vector<ObjCPropertyDecl *> AllProps;
329  GCAttrsCollector(MigrateCtx, AllProps).TraverseDecl(
330  MigrateCtx.Pass.Ctx.getTranslationUnitDecl());
331 
332  errorForGCAttrsOnNonObjC(MigrateCtx);
333  checkAllProps(MigrateCtx, AllProps);
334  checkWeakGCAttrs(MigrateCtx);
335 }
336 
338  llvm::errs() << "\n################\n";
339  for (unsigned i = 0, e = GCAttrs.size(); i != e; ++i) {
340  GCAttrOccurrence &Attr = GCAttrs[i];
341  llvm::errs() << "KIND: "
342  << (Attr.Kind == GCAttrOccurrence::Strong ? "strong" : "weak");
343  llvm::errs() << "\nLOC: ";
344  Attr.Loc.dump(Pass.Ctx.getSourceManager());
345  llvm::errs() << "\nTYPE: ";
346  Attr.ModifiedType.dump();
347  if (Attr.Dcl) {
348  llvm::errs() << "DECL:\n";
349  Attr.Dcl->dump();
350  } else {
351  llvm::errs() << "DECL: NONE";
352  }
353  llvm::errs() << "\nMIGRATABLE: " << Attr.FullyMigratable;
354  llvm::errs() << "\n----------------\n";
355  }
356  llvm::errs() << "\n################\n";
357 }
Defines the clang::ASTContext interface.
static unsigned getSpelling(const Token &Tok, const char *&Buffer, const SourceManager &SourceMgr, const LangOptions &LangOpts, bool *Invalid=nullptr)
Definition: Lexer.cpp:358
T getAs() const
Convert to the specified TypeLoc type, returning a null TypeLoc if this TypeLoc is not of the desired...
Definition: TypeLoc.h:64
bool isMacroID() const
SourceLocation getSpellingLoc(SourceLocation Loc) const
Given a SourceLocation object, return the spelling location referenced by the ID. ...
Defines the SourceManager interface.
A container of type source information.
Definition: Decl.h:60
unsigned getRawEncoding() const
When a SourceLocation itself cannot be used, this returns an (opaque) 32-bit integer encoding for it...
bool rewritePropertyAttribute(StringRef fromAttr, StringRef toAttr, SourceLocation atLoc)
Definition: Transforms.cpp:386
static void checkWeakGCAttrs(MigrationContext &MigrateCtx)
Wrapper of type source information for a type with non-trivial direct qualifiers. ...
Definition: TypeLoc.h:239
std::vector< GCAttrOccurrence > GCAttrs
Definition: Transforms.h:96
bool isObjCRetainableType() const
Definition: Type.cpp:3542
void dump(const char *s) const
Definition: ASTDumper.cpp:2286
TypeSourceInfo * getTypeSourceInfo() const
Definition: DeclObjC.h:2503
Base wrapper for a particular "section" of type source info.
Definition: TypeLoc.h:40
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:89
static SourceLocation getFromRawEncoding(unsigned Encoding)
Turn a raw encoding of a SourceLocation object into a real SourceLocation.
bool FullyMigratable
true if the attribute is owned, e.g. it is in a body and not just in an interface.
Definition: Transforms.h:94
void reportError(StringRef error, SourceLocation loc, SourceRange range=SourceRange())
const LangOptions & getLangOpts() const
Definition: ASTContext.h:533
bool isImplicit() const
Definition: DeclBase.h:503
void dump(const SourceManager &SM) const
A class that does preorder depth-first traversal on the entire Clang AST and visits each node...
Represents an ObjC class declaration.
Definition: DeclObjC.h:851
bool isInvalid() const
SourceLocation getAtLoc() const
Definition: DeclObjC.h:2497
AttributedType::Kind getAttrKind() const
Definition: TypeLoc.h:721
llvm::DenseSet< unsigned > RemovedAttrSet
Definition: Transforms.h:98
Qualifiers::ObjCLifetime getObjCLifetime() const
getObjCLifetime - Returns lifetime attribute of this type.
Definition: Type.h:976
Represents a ValueDecl that came out of a declarator. Contains type source information through TypeSo...
Definition: Decl.h:586
bool clearDiagnostic(ArrayRef< unsigned > IDs, SourceRange range)
SourceLocation getAttrEnumOperandLoc() const
Definition: TypeLoc.h:772
ID
Defines the set of possible language-specific address spaces.
Definition: AddressSpaces.h:27
SourceManager & SM
bool isInFileID(SourceLocation Loc, FileID FID, unsigned *RelativeOffset=nullptr) const
Given a specific FileID, returns true if Loc is inside that FileID chunk and sets relative offset (of...
Type source information for an attributed type.
Definition: TypeLoc.h:716
TranslationUnitDecl * getTranslationUnitDecl() const
Definition: ASTContext.h:812
DeclContext * getDeclContext()
Definition: DeclBase.h:381
QualType getType() const
Get the type for which this source info wrapper provides information.
Definition: TypeLoc.h:107
bool addPropertyAttribute(StringRef attr, SourceLocation atLoc)
Definition: Transforms.cpp:468
bool canApplyWeak(ASTContext &Ctx, QualType type, bool AllowOnUnknownClass=false)
Determine whether we can add weak to the given type.
Definition: Transforms.cpp:43
void dump() const
Definition: ASTDumper.cpp:2303
llvm::TinyPtrVector< ObjCPropertyDecl * > IndivPropsTy
static void errorForGCAttrsOnNonObjC(MigrationContext &MigrateCtx)
Wrapper for source info for arrays.
Definition: TypeLoc.h:1346
TypeLoc getTypeLoc() const
Return the TypeLoc wrapper for the type source info.
Definition: TypeLoc.h:208
#define false
Definition: stdbool.h:33
Kind
Encodes a location in the source. The SourceManager can decode this to get at the full include stack...
void traverseTU(MigrationContext &MigrateCtx) override
Represents one property declaration in an Objective-C interface.
Definition: DeclObjC.h:2424
FileID getMainFileID() const
Returns the FileID of the main source file.
QualType getType() const
Return the type wrapped by this type source info.
Definition: Decl.h:68
static void checkAllAtProps(MigrationContext &MigrateCtx, SourceLocation AtLoc, IndivPropsTy &IndProps)
redecl_range redecls() const
Returns an iterator range for all the redeclarations of the same decl. It will iterate at least once ...
Definition: DeclBase.h:803
std::pair< SourceLocation, SourceLocation > getImmediateExpansionRange(SourceLocation Loc) const
Return the start/end of the expansion information for an expansion location.
static void checkAllProps(MigrationContext &MigrateCtx, std::vector< ObjCPropertyDecl * > &AllProps)
void replaceText(SourceLocation loc, StringRef text, StringRef replacementText)
SourceManager & getSourceManager()
Definition: ASTContext.h:494
Reading or writing from this object requires a barrier call.
Definition: Type.h:144
TransformActions & TA
Definition: Internals.h:151
void remove(SourceRange range)
Represents a C++ struct/union/class.
Definition: DeclCXX.h:285
enum clang::arcmt::trans::MigrationContext::GCAttrOccurrence::AttrKind Kind
PropertyAttributeKind getPropertyAttributesAsWritten() const
Definition: DeclObjC.h:2523
UnqualTypeLoc getUnqualifiedLoc() const
Skips past any qualifiers, if this is qualified.
Definition: TypeLoc.h:289
SourceLocation getExpansionLoc(SourceLocation Loc) const
Given a SourceLocation object Loc, return the expansion location referenced by the ID...
bool isNull() const
isNull - Return true if this QualType doesn't point to a type yet.
Definition: Type.h:633
Wrapper for source info for pointers.
Definition: TypeLoc.h:1122
This class handles loading and caching of source files into memory.
Attr - This represents one attribute.
Definition: Attr.h:44
llvm::DenseSet< unsigned > AtPropsWeak
Set of raw '@' locations for 'assign' properties group that contain GC __weak.
Definition: Transforms.h:102