clang  8.0.0svn
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 /// 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) {
84  auto *OwnershipAttr = TL.getAttrAs<ObjCOwnershipAttr>();
85  if (!OwnershipAttr)
86  return false;
87 
88  SourceLocation Loc = OwnershipAttr->getLocation();
89  unsigned RawLoc = Loc.getRawEncoding();
90  if (MigrateCtx.AttrSet.count(RawLoc))
91  return true;
92 
93  ASTContext &Ctx = MigrateCtx.Pass.Ctx;
95  if (Loc.isMacroID())
96  Loc = SM.getImmediateExpansionRange(Loc).getBegin();
97  StringRef Spell = OwnershipAttr->getKind()->getName();
99  if (Spell == "strong")
101  else if (Spell == "weak")
103  else
104  return false;
105 
106  MigrateCtx.AttrSet.insert(RawLoc);
107  MigrateCtx.GCAttrs.push_back(MigrationContext::GCAttrOccurrence());
108  MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs.back();
109 
110  Attr.Kind = Kind;
111  Attr.Loc = Loc;
112  Attr.ModifiedType = TL.getModifiedLoc().getType();
113  Attr.Dcl = D;
114  Attr.FullyMigratable = FullyMigratable;
115  return true;
116  }
117 
118  bool isMigratable(Decl *D) {
119  if (isa<TranslationUnitDecl>(D))
120  return false;
121 
122  if (isInMainFile(D))
123  return true;
124 
125  if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
126  return FD->hasBody();
127 
128  if (ObjCContainerDecl *ContD = dyn_cast<ObjCContainerDecl>(D))
129  return hasObjCImpl(ContD);
130 
131  if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
132  for (const auto *MI : RD->methods()) {
133  if (MI->isOutOfLine())
134  return true;
135  }
136  return false;
137  }
138 
139  return isMigratable(cast<Decl>(D->getDeclContext()));
140  }
141 
142  static bool hasObjCImpl(Decl *D) {
143  if (!D)
144  return false;
145  if (ObjCContainerDecl *ContD = dyn_cast<ObjCContainerDecl>(D)) {
146  if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(ContD))
147  return ID->getImplementation() != nullptr;
148  if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(ContD))
149  return CD->getImplementation() != nullptr;
150  return isa<ObjCImplDecl>(ContD);
151  }
152  return false;
153  }
154 
155  bool isInMainFile(Decl *D) {
156  if (!D)
157  return false;
158 
159  for (auto I : D->redecls())
160  if (!isInMainFile(I->getLocation()))
161  return false;
162 
163  return true;
164  }
165 
166  bool isInMainFile(SourceLocation Loc) {
167  if (Loc.isInvalid())
168  return false;
169 
170  SourceManager &SM = MigrateCtx.Pass.Ctx.getSourceManager();
171  return SM.isInFileID(SM.getExpansionLoc(Loc), SM.getMainFileID());
172  }
173 };
174 
175 } // anonymous namespace
176 
177 static void errorForGCAttrsOnNonObjC(MigrationContext &MigrateCtx) {
178  TransformActions &TA = MigrateCtx.Pass.TA;
179 
180  for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) {
181  MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i];
182  if (Attr.FullyMigratable && Attr.Dcl) {
183  if (Attr.ModifiedType.isNull())
184  continue;
185  if (!Attr.ModifiedType->isObjCRetainableType()) {
186  TA.reportError("GC managed memory will become unmanaged in ARC",
187  Attr.Loc);
188  }
189  }
190  }
191 }
192 
193 static void checkWeakGCAttrs(MigrationContext &MigrateCtx) {
194  TransformActions &TA = MigrateCtx.Pass.TA;
195 
196  for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) {
197  MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i];
199  if (Attr.ModifiedType.isNull() ||
201  continue;
202  if (!canApplyWeak(MigrateCtx.Pass.Ctx, Attr.ModifiedType,
203  /*AllowOnUnknownClass=*/true)) {
204  Transaction Trans(TA);
205  if (!MigrateCtx.RemovedAttrSet.count(Attr.Loc.getRawEncoding()))
206  TA.replaceText(Attr.Loc, "__weak", "__unsafe_unretained");
207  TA.clearDiagnostic(diag::err_arc_weak_no_runtime,
208  diag::err_arc_unsupported_weak_class,
209  Attr.Loc);
210  }
211  }
212  }
213 }
214 
215 typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy;
216 
217 static void checkAllAtProps(MigrationContext &MigrateCtx,
218  SourceLocation AtLoc,
219  IndivPropsTy &IndProps) {
220  if (IndProps.empty())
221  return;
222 
223  for (IndivPropsTy::iterator
224  PI = IndProps.begin(), PE = IndProps.end(); PI != PE; ++PI) {
225  QualType T = (*PI)->getType();
226  if (T.isNull() || !T->isObjCRetainableType())
227  return;
228  }
229 
231  bool hasWeak = false, hasStrong = false;
234  for (IndivPropsTy::iterator
235  PI = IndProps.begin(), PE = IndProps.end(); PI != PE; ++PI) {
236  ObjCPropertyDecl *PD = *PI;
237  Attrs = PD->getPropertyAttributesAsWritten();
238  TypeSourceInfo *TInfo = PD->getTypeSourceInfo();
239  if (!TInfo)
240  return;
241  TypeLoc TL = TInfo->getTypeLoc();
242  if (AttributedTypeLoc ATL =
243  TL.getAs<AttributedTypeLoc>()) {
244  ATLs.push_back(std::make_pair(ATL, PD));
245  if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {
246  hasWeak = true;
247  } else if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Strong)
248  hasStrong = true;
249  else
250  return;
251  }
252  }
253  if (ATLs.empty())
254  return;
255  if (hasWeak && hasStrong)
256  return;
257 
258  TransformActions &TA = MigrateCtx.Pass.TA;
259  Transaction Trans(TA);
260 
261  if (GCAttrsCollector::hasObjCImpl(
262  cast<Decl>(IndProps.front()->getDeclContext()))) {
263  if (hasWeak)
264  MigrateCtx.AtPropsWeak.insert(AtLoc.getRawEncoding());
265 
266  } else {
267  StringRef toAttr = "strong";
268  if (hasWeak) {
269  if (canApplyWeak(MigrateCtx.Pass.Ctx, IndProps.front()->getType(),
270  /*AllowOnUnkwownClass=*/true))
271  toAttr = "weak";
272  else
273  toAttr = "unsafe_unretained";
274  }
276  MigrateCtx.rewritePropertyAttribute("assign", toAttr, AtLoc);
277  else
278  MigrateCtx.addPropertyAttribute(toAttr, AtLoc);
279  }
280 
281  for (unsigned i = 0, e = ATLs.size(); i != e; ++i) {
282  SourceLocation Loc = ATLs[i].first.getAttr()->getLocation();
283  if (Loc.isMacroID())
284  Loc = MigrateCtx.Pass.Ctx.getSourceManager()
286  .getBegin();
287  TA.remove(Loc);
288  TA.clearDiagnostic(diag::err_objc_property_attr_mutually_exclusive, AtLoc);
289  TA.clearDiagnostic(diag::err_arc_inconsistent_property_ownership,
290  ATLs[i].second->getLocation());
291  MigrateCtx.RemovedAttrSet.insert(Loc.getRawEncoding());
292  }
293 }
294 
295 static void checkAllProps(MigrationContext &MigrateCtx,
296  std::vector<ObjCPropertyDecl *> &AllProps) {
297  typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy;
298  llvm::DenseMap<unsigned, IndivPropsTy> AtProps;
299 
300  for (unsigned i = 0, e = AllProps.size(); i != e; ++i) {
301  ObjCPropertyDecl *PD = AllProps[i];
305  SourceLocation AtLoc = PD->getAtLoc();
306  if (AtLoc.isInvalid())
307  continue;
308  unsigned RawAt = AtLoc.getRawEncoding();
309  AtProps[RawAt].push_back(PD);
310  }
311  }
312 
313  for (llvm::DenseMap<unsigned, IndivPropsTy>::iterator
314  I = AtProps.begin(), E = AtProps.end(); I != E; ++I) {
316  IndivPropsTy &IndProps = I->second;
317  checkAllAtProps(MigrateCtx, AtLoc, IndProps);
318  }
319 }
320 
322  std::vector<ObjCPropertyDecl *> AllProps;
323  GCAttrsCollector(MigrateCtx, AllProps).TraverseDecl(
324  MigrateCtx.Pass.Ctx.getTranslationUnitDecl());
325 
326  errorForGCAttrsOnNonObjC(MigrateCtx);
327  checkAllProps(MigrateCtx, AllProps);
328  checkWeakGCAttrs(MigrateCtx);
329 }
330 
332  llvm::errs() << "\n################\n";
333  for (unsigned i = 0, e = GCAttrs.size(); i != e; ++i) {
334  GCAttrOccurrence &Attr = GCAttrs[i];
335  llvm::errs() << "KIND: "
336  << (Attr.Kind == GCAttrOccurrence::Strong ? "strong" : "weak");
337  llvm::errs() << "\nLOC: ";
338  Attr.Loc.print(llvm::errs(), Pass.Ctx.getSourceManager());
339  llvm::errs() << "\nTYPE: ";
340  Attr.ModifiedType.dump();
341  if (Attr.Dcl) {
342  llvm::errs() << "DECL:\n";
343  Attr.Dcl->dump();
344  } else {
345  llvm::errs() << "DECL: NONE";
346  }
347  llvm::errs() << "\nMIGRATABLE: " << Attr.FullyMigratable;
348  llvm::errs() << "\n----------------\n";
349  }
350  llvm::errs() << "\n################\n";
351 }
Defines the clang::ASTContext interface.
Represents a function declaration or definition.
Definition: Decl.h:1717
unsigned getRawEncoding() const
When a SourceLocation itself cannot be used, this returns an (opaque) 32-bit integer encoding for it...
A (possibly-)qualified type.
Definition: Type.h:642
Defines the SourceManager interface.
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
A container of type source information.
Definition: Decl.h:86
bool rewritePropertyAttribute(StringRef fromAttr, StringRef toAttr, SourceLocation atLoc)
Definition: Transforms.cpp:379
static void checkWeakGCAttrs(MigrationContext &MigrateCtx)
Wrapper of type source information for a type with non-trivial direct qualifiers. ...
Definition: TypeLoc.h:271
std::vector< GCAttrOccurrence > GCAttrs
Definition: Transforms.h:96
Base wrapper for a particular "section" of type source info.
Definition: TypeLoc.h:57
SourceLocation getBegin() const
void print(raw_ostream &OS, const SourceManager &SM) const
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:154
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.
Definition: Transforms.h:94
void reportError(StringRef error, SourceLocation loc, SourceRange range=SourceRange())
ObjCContainerDecl - Represents a container for method declarations.
Definition: DeclObjC.h:961
SourceLocation getExpansionLoc(SourceLocation Loc) const
Given a SourceLocation object Loc, return the expansion location referenced by the ID...
A class that does preorder or postorder depth-first traversal on the entire Clang AST and visits each...
Represents an ObjC class declaration.
Definition: DeclObjC.h:1164
llvm::DenseSet< unsigned > RemovedAttrSet
Definition: Transforms.h:98
Represents a ValueDecl that came out of a declarator.
Definition: Decl.h:688
bool clearDiagnostic(ArrayRef< unsigned > IDs, SourceRange range)
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:849
TypeSourceInfo * getTypeSourceInfo() const
Definition: DeclObjC.h:819
UnqualTypeLoc getUnqualifiedLoc() const
Skips past any qualifiers, if this is qualified.
Definition: TypeLoc.h:320
bool isObjCRetainableType() const
Definition: Type.cpp:3879
T getAs() const
Convert to the specified TypeLoc type, returning a null TypeLoc if this TypeLoc is not of the desired...
Definition: TypeLoc.h:87
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
Definition: DeclBase.h:552
DeclContext * getDeclContext()
Definition: DeclBase.h:426
CharSourceRange getImmediateExpansionRange(SourceLocation Loc) const
Return the start/end of the expansion information for an expansion location.
bool addPropertyAttribute(StringRef attr, SourceLocation atLoc)
Definition: Transforms.cpp:461
bool isNull() const
Return true if this QualType doesn&#39;t point to a type yet.
Definition: Type.h:707
const SourceManager & SM
Definition: Format.cpp:1472
bool canApplyWeak(ASTContext &Ctx, QualType type, bool AllowOnUnknownClass=false)
Determine whether we can add weak to the given type.
Definition: Transforms.cpp:38
static void checkAllProps(MigrationContext &MigrateCtx, std::vector< ObjCPropertyDecl *> &AllProps)
llvm::TinyPtrVector< ObjCPropertyDecl * > IndivPropsTy
static void errorForGCAttrsOnNonObjC(MigrationContext &MigrateCtx)
Wrapper for source info for arrays.
Definition: TypeLoc.h:1460
#define false
Definition: stdbool.h:33
Assigning into this object requires the old value to be released and the new value to be retained...
Definition: Type.h:169
Kind
llvm::DenseSet< unsigned > AttrSet
Definition: Transforms.h:97
Encodes a location in the source.
void traverseTU(MigrationContext &MigrateCtx) override
const T * getAttrAs()
Definition: TypeLoc.h:878
ObjCCategoryDecl - Represents a category declaration.
Definition: DeclObjC.h:2272
Represents one property declaration in an Objective-C interface.
Definition: DeclObjC.h:721
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.
Definition: DeclBase.h:946
Dataflow Directional Tag Classes.
PropertyAttributeKind getPropertyAttributesAsWritten() const
Definition: DeclObjC.h:844
QualType getType() const
Get the type for which this source info wrapper provides information.
Definition: TypeLoc.h:131
SourceLocation getAtLoc() const
Definition: DeclObjC.h:813
FileID getMainFileID() const
Returns the FileID of the main source file.
void replaceText(SourceLocation loc, StringRef text, StringRef replacementText)
TypeLoc getModifiedLoc() const
The modified type, which is generally canonically different from the attribute type.
Definition: TypeLoc.h:866
SourceManager & getSourceManager()
Definition: ASTContext.h:671
TypeLoc getTypeLoc() const
Return the TypeLoc wrapper for the type source info.
Definition: TypeLoc.h:238
Reading or writing from this object requires a barrier call.
Definition: Type.h:172
TranslationUnitDecl * getTranslationUnitDecl() const
Definition: ASTContext.h:1018
TransformActions & TA
Definition: Internals.h:151
void remove(SourceRange range)
Represents a C++ struct/union/class.
Definition: DeclCXX.h:300
enum clang::arcmt::trans::MigrationContext::GCAttrOccurrence::AttrKind Kind
void dump(const char *s) const
Definition: ASTDumper.cpp:2724
void dump() const
Definition: ASTDumper.cpp:2747
Wrapper for source info for pointers.
Definition: TypeLoc.h:1202
This class handles loading and caching of source files into memory.
Attr - This represents one attribute.
Definition: Attr.h:43
QualType getType() const
Return the type wrapped by this type source info.
Definition: Decl.h:97
Qualifiers::ObjCLifetime getObjCLifetime() const
Returns lifetime attribute of this type.
Definition: Type.h:1066
llvm::DenseSet< unsigned > AtPropsWeak
Set of raw &#39;@&#39; locations for &#39;assign&#39; properties group that contain GC __weak.
Definition: Transforms.h:102