clang  9.0.0svn
TransGCAttrs.cpp
Go to the documentation of this file.
1 //===--- TransGCAttrs.cpp - Transformations to ARC mode --------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "Transforms.h"
10 #include "Internals.h"
11 #include "clang/AST/ASTContext.h"
13 #include "clang/Lex/Lexer.h"
15 #include "llvm/ADT/SmallString.h"
16 #include "llvm/ADT/TinyPtrVector.h"
17 #include "llvm/Support/SaveAndRestore.h"
18 
19 using namespace clang;
20 using namespace arcmt;
21 using namespace trans;
22 
23 namespace {
24 
25 /// Collects all the places where GC attributes __strong/__weak occur.
26 class GCAttrsCollector : public RecursiveASTVisitor<GCAttrsCollector> {
27  MigrationContext &MigrateCtx;
28  bool FullyMigratable;
29  std::vector<ObjCPropertyDecl *> &AllProps;
30 
32 public:
33  GCAttrsCollector(MigrationContext &ctx,
34  std::vector<ObjCPropertyDecl *> &AllProps)
35  : MigrateCtx(ctx), FullyMigratable(false),
36  AllProps(AllProps) { }
37 
38  bool shouldWalkTypesOfTypeLocs() const { return false; }
39 
40  bool VisitAttributedTypeLoc(AttributedTypeLoc TL) {
41  handleAttr(TL);
42  return true;
43  }
44 
45  bool TraverseDecl(Decl *D) {
46  if (!D || D->isImplicit())
47  return true;
48 
49  SaveAndRestore<bool> Save(FullyMigratable, isMigratable(D));
50 
51  if (ObjCPropertyDecl *PropD = dyn_cast<ObjCPropertyDecl>(D)) {
52  lookForAttribute(PropD, PropD->getTypeSourceInfo());
53  AllProps.push_back(PropD);
54  } else if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) {
55  lookForAttribute(DD, DD->getTypeSourceInfo());
56  }
57  return base::TraverseDecl(D);
58  }
59 
60  void lookForAttribute(Decl *D, TypeSourceInfo *TInfo) {
61  if (!TInfo)
62  return;
63  TypeLoc TL = TInfo->getTypeLoc();
64  while (TL) {
65  if (QualifiedTypeLoc QL = TL.getAs<QualifiedTypeLoc>()) {
66  TL = QL.getUnqualifiedLoc();
67  } else if (AttributedTypeLoc Attr = TL.getAs<AttributedTypeLoc>()) {
68  if (handleAttr(Attr, D))
69  break;
70  TL = Attr.getModifiedLoc();
71  } else if (ArrayTypeLoc Arr = TL.getAs<ArrayTypeLoc>()) {
72  TL = Arr.getElementLoc();
73  } else if (PointerTypeLoc PT = TL.getAs<PointerTypeLoc>()) {
74  TL = PT.getPointeeLoc();
75  } else if (ReferenceTypeLoc RT = TL.getAs<ReferenceTypeLoc>())
76  TL = RT.getPointeeLoc();
77  else
78  break;
79  }
80  }
81 
82  bool handleAttr(AttributedTypeLoc TL, Decl *D = nullptr) {
83  auto *OwnershipAttr = TL.getAttrAs<ObjCOwnershipAttr>();
84  if (!OwnershipAttr)
85  return false;
86 
87  SourceLocation Loc = OwnershipAttr->getLocation();
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).getBegin();
96  StringRef Spell = OwnershipAttr->getKind()->getName();
98  if (Spell == "strong")
100  else if (Spell == "weak")
102  else
103  return false;
104 
105  MigrateCtx.AttrSet.insert(RawLoc);
106  MigrateCtx.GCAttrs.push_back(MigrationContext::GCAttrOccurrence());
107  MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs.back();
108 
109  Attr.Kind = Kind;
110  Attr.Loc = Loc;
111  Attr.ModifiedType = TL.getModifiedLoc().getType();
112  Attr.Dcl = D;
113  Attr.FullyMigratable = FullyMigratable;
114  return true;
115  }
116 
117  bool isMigratable(Decl *D) {
118  if (isa<TranslationUnitDecl>(D))
119  return false;
120 
121  if (isInMainFile(D))
122  return true;
123 
124  if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
125  return FD->hasBody();
126 
127  if (ObjCContainerDecl *ContD = dyn_cast<ObjCContainerDecl>(D))
128  return hasObjCImpl(ContD);
129 
130  if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
131  for (const auto *MI : RD->methods()) {
132  if (MI->isOutOfLine())
133  return true;
134  }
135  return false;
136  }
137 
138  return isMigratable(cast<Decl>(D->getDeclContext()));
139  }
140 
141  static bool hasObjCImpl(Decl *D) {
142  if (!D)
143  return false;
144  if (ObjCContainerDecl *ContD = dyn_cast<ObjCContainerDecl>(D)) {
145  if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(ContD))
146  return ID->getImplementation() != nullptr;
147  if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(ContD))
148  return CD->getImplementation() != nullptr;
149  return isa<ObjCImplDecl>(ContD);
150  }
151  return false;
152  }
153 
154  bool isInMainFile(Decl *D) {
155  if (!D)
156  return false;
157 
158  for (auto I : D->redecls())
159  if (!isInMainFile(I->getLocation()))
160  return false;
161 
162  return true;
163  }
164 
165  bool isInMainFile(SourceLocation Loc) {
166  if (Loc.isInvalid())
167  return false;
168 
169  SourceManager &SM = MigrateCtx.Pass.Ctx.getSourceManager();
170  return SM.isInFileID(SM.getExpansionLoc(Loc), SM.getMainFileID());
171  }
172 };
173 
174 } // anonymous namespace
175 
176 static void errorForGCAttrsOnNonObjC(MigrationContext &MigrateCtx) {
177  TransformActions &TA = MigrateCtx.Pass.TA;
178 
179  for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) {
180  MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i];
181  if (Attr.FullyMigratable && Attr.Dcl) {
182  if (Attr.ModifiedType.isNull())
183  continue;
184  if (!Attr.ModifiedType->isObjCRetainableType()) {
185  TA.reportError("GC managed memory will become unmanaged in ARC",
186  Attr.Loc);
187  }
188  }
189  }
190 }
191 
192 static void checkWeakGCAttrs(MigrationContext &MigrateCtx) {
193  TransformActions &TA = MigrateCtx.Pass.TA;
194 
195  for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) {
196  MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i];
198  if (Attr.ModifiedType.isNull() ||
200  continue;
201  if (!canApplyWeak(MigrateCtx.Pass.Ctx, Attr.ModifiedType,
202  /*AllowOnUnknownClass=*/true)) {
203  Transaction Trans(TA);
204  if (!MigrateCtx.RemovedAttrSet.count(Attr.Loc.getRawEncoding()))
205  TA.replaceText(Attr.Loc, "__weak", "__unsafe_unretained");
206  TA.clearDiagnostic(diag::err_arc_weak_no_runtime,
207  diag::err_arc_unsupported_weak_class,
208  Attr.Loc);
209  }
210  }
211  }
212 }
213 
214 typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy;
215 
216 static void checkAllAtProps(MigrationContext &MigrateCtx,
217  SourceLocation AtLoc,
218  IndivPropsTy &IndProps) {
219  if (IndProps.empty())
220  return;
221 
222  for (IndivPropsTy::iterator
223  PI = IndProps.begin(), PE = IndProps.end(); PI != PE; ++PI) {
224  QualType T = (*PI)->getType();
225  if (T.isNull() || !T->isObjCRetainableType())
226  return;
227  }
228 
230  bool hasWeak = false, hasStrong = false;
233  for (IndivPropsTy::iterator
234  PI = IndProps.begin(), PE = IndProps.end(); PI != PE; ++PI) {
235  ObjCPropertyDecl *PD = *PI;
236  Attrs = PD->getPropertyAttributesAsWritten();
237  TypeSourceInfo *TInfo = PD->getTypeSourceInfo();
238  if (!TInfo)
239  return;
240  TypeLoc TL = TInfo->getTypeLoc();
241  if (AttributedTypeLoc ATL =
242  TL.getAs<AttributedTypeLoc>()) {
243  ATLs.push_back(std::make_pair(ATL, PD));
244  if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {
245  hasWeak = true;
246  } else if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Strong)
247  hasStrong = true;
248  else
249  return;
250  }
251  }
252  if (ATLs.empty())
253  return;
254  if (hasWeak && hasStrong)
255  return;
256 
257  TransformActions &TA = MigrateCtx.Pass.TA;
258  Transaction Trans(TA);
259 
260  if (GCAttrsCollector::hasObjCImpl(
261  cast<Decl>(IndProps.front()->getDeclContext()))) {
262  if (hasWeak)
263  MigrateCtx.AtPropsWeak.insert(AtLoc.getRawEncoding());
264 
265  } else {
266  StringRef toAttr = "strong";
267  if (hasWeak) {
268  if (canApplyWeak(MigrateCtx.Pass.Ctx, IndProps.front()->getType(),
269  /*AllowOnUnkwownClass=*/true))
270  toAttr = "weak";
271  else
272  toAttr = "unsafe_unretained";
273  }
275  MigrateCtx.rewritePropertyAttribute("assign", toAttr, AtLoc);
276  else
277  MigrateCtx.addPropertyAttribute(toAttr, AtLoc);
278  }
279 
280  for (unsigned i = 0, e = ATLs.size(); i != e; ++i) {
281  SourceLocation Loc = ATLs[i].first.getAttr()->getLocation();
282  if (Loc.isMacroID())
283  Loc = MigrateCtx.Pass.Ctx.getSourceManager()
285  .getBegin();
286  TA.remove(Loc);
287  TA.clearDiagnostic(diag::err_objc_property_attr_mutually_exclusive, AtLoc);
288  TA.clearDiagnostic(diag::err_arc_inconsistent_property_ownership,
289  ATLs[i].second->getLocation());
290  MigrateCtx.RemovedAttrSet.insert(Loc.getRawEncoding());
291  }
292 }
293 
294 static void checkAllProps(MigrationContext &MigrateCtx,
295  std::vector<ObjCPropertyDecl *> &AllProps) {
296  typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy;
297  llvm::DenseMap<unsigned, IndivPropsTy> AtProps;
298 
299  for (unsigned i = 0, e = AllProps.size(); i != e; ++i) {
300  ObjCPropertyDecl *PD = AllProps[i];
304  SourceLocation AtLoc = PD->getAtLoc();
305  if (AtLoc.isInvalid())
306  continue;
307  unsigned RawAt = AtLoc.getRawEncoding();
308  AtProps[RawAt].push_back(PD);
309  }
310  }
311 
312  for (llvm::DenseMap<unsigned, IndivPropsTy>::iterator
313  I = AtProps.begin(), E = AtProps.end(); I != E; ++I) {
315  IndivPropsTy &IndProps = I->second;
316  checkAllAtProps(MigrateCtx, AtLoc, IndProps);
317  }
318 }
319 
321  std::vector<ObjCPropertyDecl *> AllProps;
322  GCAttrsCollector(MigrateCtx, AllProps).TraverseDecl(
323  MigrateCtx.Pass.Ctx.getTranslationUnitDecl());
324 
325  errorForGCAttrsOnNonObjC(MigrateCtx);
326  checkAllProps(MigrateCtx, AllProps);
327  checkWeakGCAttrs(MigrateCtx);
328 }
329 
331  llvm::errs() << "\n################\n";
332  for (unsigned i = 0, e = GCAttrs.size(); i != e; ++i) {
333  GCAttrOccurrence &Attr = GCAttrs[i];
334  llvm::errs() << "KIND: "
335  << (Attr.Kind == GCAttrOccurrence::Strong ? "strong" : "weak");
336  llvm::errs() << "\nLOC: ";
337  Attr.Loc.print(llvm::errs(), Pass.Ctx.getSourceManager());
338  llvm::errs() << "\nTYPE: ";
339  Attr.ModifiedType.dump();
340  if (Attr.Dcl) {
341  llvm::errs() << "DECL:\n";
342  Attr.Dcl->dump();
343  } else {
344  llvm::errs() << "DECL: NONE";
345  }
346  llvm::errs() << "\nMIGRATABLE: " << Attr.FullyMigratable;
347  llvm::errs() << "\n----------------\n";
348  }
349  llvm::errs() << "\n################\n";
350 }
Defines the clang::ASTContext interface.
Represents a function declaration or definition.
Definition: Decl.h:1737
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:639
Defines the SourceManager interface.
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:87
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:270
std::vector< GCAttrOccurrence > GCAttrs
Definition: Transforms.h:95
Base wrapper for a particular "section" of type source info.
Definition: TypeLoc.h:56
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:93
void reportError(StringRef error, SourceLocation loc, SourceRange range=SourceRange())
ObjCContainerDecl - Represents a container for method declarations.
Definition: DeclObjC.h:968
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:1171
llvm::DenseSet< unsigned > RemovedAttrSet
Definition: Transforms.h:97
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:848
TypeSourceInfo * getTypeSourceInfo() const
Definition: DeclObjC.h:826
UnqualTypeLoc getUnqualifiedLoc() const
Skips past any qualifiers, if this is qualified.
Definition: TypeLoc.h:319
bool isObjCRetainableType() const
Definition: Type.cpp:4000
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:550
DeclContext * getDeclContext()
Definition: DeclBase.h:430
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:704
const SourceManager & SM
Definition: Format.cpp:1568
bool canApplyWeak(ASTContext &Ctx, QualType type, bool AllowOnUnknownClass=false)
Determine whether we can add weak to the given type.
Definition: Transforms.cpp:37
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:1459
#define false
Definition: stdbool.h:17
Assigning into this object requires the old value to be released and the new value to be retained...
Definition: Type.h:165
Kind
llvm::DenseSet< unsigned > AttrSet
Definition: Transforms.h:96
Encodes a location in the source.
void traverseTU(MigrationContext &MigrateCtx) override
const T * getAttrAs()
Definition: TypeLoc.h:877
ObjCCategoryDecl - Represents a category declaration.
Definition: DeclObjC.h:2279
Represents one property declaration in an Objective-C interface.
Definition: DeclObjC.h:728
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:940
Dataflow Directional Tag Classes.
PropertyAttributeKind getPropertyAttributesAsWritten() const
Definition: DeclObjC.h:851
QualType getType() const
Get the type for which this source info wrapper provides information.
Definition: TypeLoc.h:130
SourceLocation getAtLoc() const
Definition: DeclObjC.h:820
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:865
bool isMacroID() const
SourceManager & getSourceManager()
Definition: ASTContext.h:661
TypeLoc getTypeLoc() const
Return the TypeLoc wrapper for the type source info.
Definition: TypeLoc.h:237
Reading or writing from this object requires a barrier call.
Definition: Type.h:168
TranslationUnitDecl * getTranslationUnitDecl() const
Definition: ASTContext.h:1008
TransformActions & TA
Definition: Internals.h:150
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:200
void dump() const
Definition: ASTDumper.cpp:223
Wrapper for source info for pointers.
Definition: TypeLoc.h:1201
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:1059
llvm::DenseSet< unsigned > AtPropsWeak
Set of raw &#39;@&#39; locations for &#39;assign&#39; properties group that contain GC __weak.
Definition: Transforms.h:101