clang  6.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 /// \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  return isa<ObjCImplDecl>(ContD);
156  }
157  return false;
158  }
159 
160  bool isInMainFile(Decl *D) {
161  if (!D)
162  return false;
163 
164  for (auto I : D->redecls())
165  if (!isInMainFile(I->getLocation()))
166  return false;
167 
168  return true;
169  }
170 
171  bool isInMainFile(SourceLocation Loc) {
172  if (Loc.isInvalid())
173  return false;
174 
175  SourceManager &SM = MigrateCtx.Pass.Ctx.getSourceManager();
176  return SM.isInFileID(SM.getExpansionLoc(Loc), SM.getMainFileID());
177  }
178 };
179 
180 } // anonymous namespace
181 
182 static void errorForGCAttrsOnNonObjC(MigrationContext &MigrateCtx) {
183  TransformActions &TA = MigrateCtx.Pass.TA;
184 
185  for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) {
186  MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i];
187  if (Attr.FullyMigratable && Attr.Dcl) {
188  if (Attr.ModifiedType.isNull())
189  continue;
190  if (!Attr.ModifiedType->isObjCRetainableType()) {
191  TA.reportError("GC managed memory will become unmanaged in ARC",
192  Attr.Loc);
193  }
194  }
195  }
196 }
197 
198 static void checkWeakGCAttrs(MigrationContext &MigrateCtx) {
199  TransformActions &TA = MigrateCtx.Pass.TA;
200 
201  for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) {
202  MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i];
204  if (Attr.ModifiedType.isNull() ||
206  continue;
207  if (!canApplyWeak(MigrateCtx.Pass.Ctx, Attr.ModifiedType,
208  /*AllowOnUnknownClass=*/true)) {
209  Transaction Trans(TA);
210  if (!MigrateCtx.RemovedAttrSet.count(Attr.Loc.getRawEncoding()))
211  TA.replaceText(Attr.Loc, "__weak", "__unsafe_unretained");
212  TA.clearDiagnostic(diag::err_arc_weak_no_runtime,
213  diag::err_arc_unsupported_weak_class,
214  Attr.Loc);
215  }
216  }
217  }
218 }
219 
220 typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy;
221 
222 static void checkAllAtProps(MigrationContext &MigrateCtx,
223  SourceLocation AtLoc,
224  IndivPropsTy &IndProps) {
225  if (IndProps.empty())
226  return;
227 
228  for (IndivPropsTy::iterator
229  PI = IndProps.begin(), PE = IndProps.end(); PI != PE; ++PI) {
230  QualType T = (*PI)->getType();
231  if (T.isNull() || !T->isObjCRetainableType())
232  return;
233  }
234 
236  bool hasWeak = false, hasStrong = false;
239  for (IndivPropsTy::iterator
240  PI = IndProps.begin(), PE = IndProps.end(); PI != PE; ++PI) {
241  ObjCPropertyDecl *PD = *PI;
242  Attrs = PD->getPropertyAttributesAsWritten();
243  TypeSourceInfo *TInfo = PD->getTypeSourceInfo();
244  if (!TInfo)
245  return;
246  TypeLoc TL = TInfo->getTypeLoc();
247  if (AttributedTypeLoc ATL =
248  TL.getAs<AttributedTypeLoc>()) {
249  ATLs.push_back(std::make_pair(ATL, PD));
250  if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {
251  hasWeak = true;
252  } else if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Strong)
253  hasStrong = true;
254  else
255  return;
256  }
257  }
258  if (ATLs.empty())
259  return;
260  if (hasWeak && hasStrong)
261  return;
262 
263  TransformActions &TA = MigrateCtx.Pass.TA;
264  Transaction Trans(TA);
265 
266  if (GCAttrsCollector::hasObjCImpl(
267  cast<Decl>(IndProps.front()->getDeclContext()))) {
268  if (hasWeak)
269  MigrateCtx.AtPropsWeak.insert(AtLoc.getRawEncoding());
270 
271  } else {
272  StringRef toAttr = "strong";
273  if (hasWeak) {
274  if (canApplyWeak(MigrateCtx.Pass.Ctx, IndProps.front()->getType(),
275  /*AllowOnUnkwownClass=*/true))
276  toAttr = "weak";
277  else
278  toAttr = "unsafe_unretained";
279  }
281  MigrateCtx.rewritePropertyAttribute("assign", toAttr, AtLoc);
282  else
283  MigrateCtx.addPropertyAttribute(toAttr, AtLoc);
284  }
285 
286  for (unsigned i = 0, e = ATLs.size(); i != e; ++i) {
287  SourceLocation Loc = ATLs[i].first.getAttrNameLoc();
288  if (Loc.isMacroID())
289  Loc = MigrateCtx.Pass.Ctx.getSourceManager()
290  .getImmediateExpansionRange(Loc).first;
291  TA.remove(Loc);
292  TA.clearDiagnostic(diag::err_objc_property_attr_mutually_exclusive, AtLoc);
293  TA.clearDiagnostic(diag::err_arc_inconsistent_property_ownership,
294  ATLs[i].second->getLocation());
295  MigrateCtx.RemovedAttrSet.insert(Loc.getRawEncoding());
296  }
297 }
298 
299 static void checkAllProps(MigrationContext &MigrateCtx,
300  std::vector<ObjCPropertyDecl *> &AllProps) {
301  typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy;
302  llvm::DenseMap<unsigned, IndivPropsTy> AtProps;
303 
304  for (unsigned i = 0, e = AllProps.size(); i != e; ++i) {
305  ObjCPropertyDecl *PD = AllProps[i];
309  SourceLocation AtLoc = PD->getAtLoc();
310  if (AtLoc.isInvalid())
311  continue;
312  unsigned RawAt = AtLoc.getRawEncoding();
313  AtProps[RawAt].push_back(PD);
314  }
315  }
316 
317  for (llvm::DenseMap<unsigned, IndivPropsTy>::iterator
318  I = AtProps.begin(), E = AtProps.end(); I != E; ++I) {
320  IndivPropsTy &IndProps = I->second;
321  checkAllAtProps(MigrateCtx, AtLoc, IndProps);
322  }
323 }
324 
326  std::vector<ObjCPropertyDecl *> AllProps;
327  GCAttrsCollector(MigrateCtx, AllProps).TraverseDecl(
328  MigrateCtx.Pass.Ctx.getTranslationUnitDecl());
329 
330  errorForGCAttrsOnNonObjC(MigrateCtx);
331  checkAllProps(MigrateCtx, AllProps);
332  checkWeakGCAttrs(MigrateCtx);
333 }
334 
336  llvm::errs() << "\n################\n";
337  for (unsigned i = 0, e = GCAttrs.size(); i != e; ++i) {
338  GCAttrOccurrence &Attr = GCAttrs[i];
339  llvm::errs() << "KIND: "
340  << (Attr.Kind == GCAttrOccurrence::Strong ? "strong" : "weak");
341  llvm::errs() << "\nLOC: ";
342  Attr.Loc.dump(Pass.Ctx.getSourceManager());
343  llvm::errs() << "\nTYPE: ";
344  Attr.ModifiedType.dump();
345  if (Attr.Dcl) {
346  llvm::errs() << "DECL:\n";
347  Attr.Dcl->dump();
348  } else {
349  llvm::errs() << "DECL: NONE";
350  }
351  llvm::errs() << "\nMIGRATABLE: " << Attr.FullyMigratable;
352  llvm::errs() << "\n----------------\n";
353  }
354  llvm::errs() << "\n################\n";
355 }
Defines the clang::ASTContext interface.
static unsigned getSpelling(const Token &Tok, const char *&Buffer, const SourceManager &SourceMgr, const LangOptions &LangOpts, bool *Invalid=nullptr)
getSpelling - This method is used to get the spelling of a token into a preallocated buffer...
Definition: Lexer.cpp:389
An instance of this class is created to represent a function declaration or definition.
Definition: Decl.h:1697
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:653
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:272
std::vector< GCAttrOccurrence > GCAttrs
Definition: Transforms.h:96
Base wrapper for a particular "section" of type source info.
Definition: TypeLoc.h:56
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:149
static SourceLocation getFromRawEncoding(unsigned Encoding)
Turn a raw encoding of a SourceLocation object into a real SourceLocation.
SourceLocation getAttrNameLoc() const
The location of the attribute name, i.e.
Definition: TypeLoc.h:897
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:986
SourceLocation getExpansionLoc(SourceLocation Loc) const
Given a SourceLocation object Loc, return the expansion location referenced by the ID...
SourceLocation getSpellingLoc(SourceLocation Loc) const
Given a SourceLocation object, return the spelling 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:1191
void dump(const SourceManager &SM) const
llvm::DenseSet< unsigned > RemovedAttrSet
Definition: Transforms.h:98
Represents a ValueDecl that came out of a declarator.
Definition: Decl.h:680
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:859
const FunctionProtoType * T
TypeSourceInfo * getTypeSourceInfo() const
Definition: DeclObjC.h:844
UnqualTypeLoc getUnqualifiedLoc() const
Skips past any qualifiers, if this is qualified.
Definition: TypeLoc.h:321
bool isObjCRetainableType() const
Definition: Type.cpp:3824
T getAs() const
Convert to the specified TypeLoc type, returning a null TypeLoc if this TypeLoc is not of the desired...
Definition: TypeLoc.h:86
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
Definition: DeclBase.h:551
DeclContext * getDeclContext()
Definition: DeclBase.h:425
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:719
const SourceManager & SM
Definition: Format.cpp:1337
bool canApplyWeak(ASTContext &Ctx, QualType type, bool AllowOnUnknownClass=false)
Determine whether we can add weak to the given type.
Definition: Transforms.cpp:38
AttributedType::Kind getAttrKind() const
Definition: TypeLoc.h:864
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:1529
#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:180
Kind
llvm::DenseSet< unsigned > AttrSet
Definition: Transforms.h:97
Encodes a location in the source.
std::pair< SourceLocation, SourceLocation > getImmediateExpansionRange(SourceLocation Loc) const
Return the start/end of the expansion information for an expansion location.
void traverseTU(MigrationContext &MigrateCtx) override
ObjCCategoryDecl - Represents a category declaration.
Definition: DeclObjC.h:2299
Represents one property declaration in an Objective-C interface.
Definition: DeclObjC.h:746
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:936
Dataflow Directional Tag Classes.
PropertyAttributeKind getPropertyAttributesAsWritten() const
Definition: DeclObjC.h:869
QualType getType() const
Get the type for which this source info wrapper provides information.
Definition: TypeLoc.h:130
SourceLocation getAtLoc() const
Definition: DeclObjC.h:838
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:890
bool isMacroID() const
SourceManager & getSourceManager()
Definition: ASTContext.h:643
TypeLoc getTypeLoc() const
Return the TypeLoc wrapper for the type source info.
Definition: TypeLoc.h:239
Reading or writing from this object requires a barrier call.
Definition: Type.h:183
TranslationUnitDecl * getTranslationUnitDecl() const
Definition: ASTContext.h:989
TransformActions & TA
Definition: Internals.h:151
void remove(SourceRange range)
Represents a C++ struct/union/class.
Definition: DeclCXX.h:299
enum clang::arcmt::trans::MigrationContext::GCAttrOccurrence::AttrKind Kind
void dump(const char *s) const
Definition: ASTDumper.cpp:2659
void dump() const
Definition: ASTDumper.cpp:2682
SourceLocation getAttrEnumOperandLoc() const
The location of the attribute&#39;s enumerated operand, if it has one.
Definition: TypeLoc.h:919
Wrapper for source info for pointers.
Definition: TypeLoc.h:1271
const LangOptions & getLangOpts() const
Definition: ASTContext.h:688
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:1072
llvm::DenseSet< unsigned > AtPropsWeak
Set of raw &#39;@&#39; locations for &#39;assign&#39; properties group that contain GC __weak.
Definition: Transforms.h:102