clang  12.0.0git
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 (MacroQualifiedTypeLoc MDTL =
73  TL = MDTL.getInnerLoc();
74  } else if (ArrayTypeLoc Arr = TL.getAs<ArrayTypeLoc>()) {
75  TL = Arr.getElementLoc();
76  } else if (PointerTypeLoc PT = TL.getAs<PointerTypeLoc>()) {
77  TL = PT.getPointeeLoc();
78  } else if (ReferenceTypeLoc RT = TL.getAs<ReferenceTypeLoc>())
79  TL = RT.getPointeeLoc();
80  else
81  break;
82  }
83  }
84 
85  bool handleAttr(AttributedTypeLoc TL, Decl *D = nullptr) {
86  auto *OwnershipAttr = TL.getAttrAs<ObjCOwnershipAttr>();
87  if (!OwnershipAttr)
88  return false;
89 
90  SourceLocation Loc = OwnershipAttr->getLocation();
91  unsigned RawLoc = Loc.getRawEncoding();
92  if (MigrateCtx.AttrSet.count(RawLoc))
93  return true;
94 
95  ASTContext &Ctx = MigrateCtx.Pass.Ctx;
97  if (Loc.isMacroID())
98  Loc = SM.getImmediateExpansionRange(Loc).getBegin();
99  StringRef Spell = OwnershipAttr->getKind()->getName();
101  if (Spell == "strong")
103  else if (Spell == "weak")
105  else
106  return false;
107 
108  MigrateCtx.AttrSet.insert(RawLoc);
109  MigrateCtx.GCAttrs.push_back(MigrationContext::GCAttrOccurrence());
110  MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs.back();
111 
112  Attr.Kind = Kind;
113  Attr.Loc = Loc;
114  Attr.ModifiedType = TL.getModifiedLoc().getType();
115  Attr.Dcl = D;
116  Attr.FullyMigratable = FullyMigratable;
117  return true;
118  }
119 
120  bool isMigratable(Decl *D) {
121  if (isa<TranslationUnitDecl>(D))
122  return false;
123 
124  if (isInMainFile(D))
125  return true;
126 
127  if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
128  return FD->hasBody();
129 
130  if (ObjCContainerDecl *ContD = dyn_cast<ObjCContainerDecl>(D))
131  return hasObjCImpl(ContD);
132 
133  if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
134  for (const auto *MI : RD->methods()) {
135  if (MI->isOutOfLine())
136  return true;
137  }
138  return false;
139  }
140 
141  return isMigratable(cast<Decl>(D->getDeclContext()));
142  }
143 
144  static bool hasObjCImpl(Decl *D) {
145  if (!D)
146  return false;
147  if (ObjCContainerDecl *ContD = dyn_cast<ObjCContainerDecl>(D)) {
148  if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(ContD))
149  return ID->getImplementation() != nullptr;
150  if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(ContD))
151  return CD->getImplementation() != nullptr;
152  return isa<ObjCImplDecl>(ContD);
153  }
154  return false;
155  }
156 
157  bool isInMainFile(Decl *D) {
158  if (!D)
159  return false;
160 
161  for (auto I : D->redecls())
162  if (!isInMainFile(I->getLocation()))
163  return false;
164 
165  return true;
166  }
167 
168  bool isInMainFile(SourceLocation Loc) {
169  if (Loc.isInvalid())
170  return false;
171 
172  SourceManager &SM = MigrateCtx.Pass.Ctx.getSourceManager();
173  return SM.isInFileID(SM.getExpansionLoc(Loc), SM.getMainFileID());
174  }
175 };
176 
177 } // anonymous namespace
178 
179 static void errorForGCAttrsOnNonObjC(MigrationContext &MigrateCtx) {
180  TransformActions &TA = MigrateCtx.Pass.TA;
181 
182  for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) {
183  MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i];
184  if (Attr.FullyMigratable && Attr.Dcl) {
185  if (Attr.ModifiedType.isNull())
186  continue;
187  if (!Attr.ModifiedType->isObjCRetainableType()) {
188  TA.reportError("GC managed memory will become unmanaged in ARC",
189  Attr.Loc);
190  }
191  }
192  }
193 }
194 
195 static void checkWeakGCAttrs(MigrationContext &MigrateCtx) {
196  TransformActions &TA = MigrateCtx.Pass.TA;
197 
198  for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; ++i) {
199  MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i];
201  if (Attr.ModifiedType.isNull() ||
203  continue;
204  if (!canApplyWeak(MigrateCtx.Pass.Ctx, Attr.ModifiedType,
205  /*AllowOnUnknownClass=*/true)) {
206  Transaction Trans(TA);
207  if (!MigrateCtx.RemovedAttrSet.count(Attr.Loc.getRawEncoding()))
208  TA.replaceText(Attr.Loc, "__weak", "__unsafe_unretained");
209  TA.clearDiagnostic(diag::err_arc_weak_no_runtime,
210  diag::err_arc_unsupported_weak_class,
211  Attr.Loc);
212  }
213  }
214  }
215 }
216 
217 typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy;
218 
219 static void checkAllAtProps(MigrationContext &MigrateCtx,
220  SourceLocation AtLoc,
221  IndivPropsTy &IndProps) {
222  if (IndProps.empty())
223  return;
224 
225  for (IndivPropsTy::iterator
226  PI = IndProps.begin(), PE = IndProps.end(); PI != PE; ++PI) {
227  QualType T = (*PI)->getType();
228  if (T.isNull() || !T->isObjCRetainableType())
229  return;
230  }
231 
233  bool hasWeak = false, hasStrong = false;
235  for (IndivPropsTy::iterator
236  PI = IndProps.begin(), PE = IndProps.end(); PI != PE; ++PI) {
237  ObjCPropertyDecl *PD = *PI;
238  Attrs = PD->getPropertyAttributesAsWritten();
239  TypeSourceInfo *TInfo = PD->getTypeSourceInfo();
240  if (!TInfo)
241  return;
242  TypeLoc TL = TInfo->getTypeLoc();
243  if (AttributedTypeLoc ATL =
244  TL.getAs<AttributedTypeLoc>()) {
245  ATLs.push_back(std::make_pair(ATL, PD));
246  if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {
247  hasWeak = true;
248  } else if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Strong)
249  hasStrong = true;
250  else
251  return;
252  }
253  }
254  if (ATLs.empty())
255  return;
256  if (hasWeak && hasStrong)
257  return;
258 
259  TransformActions &TA = MigrateCtx.Pass.TA;
260  Transaction Trans(TA);
261 
262  if (GCAttrsCollector::hasObjCImpl(
263  cast<Decl>(IndProps.front()->getDeclContext()))) {
264  if (hasWeak)
265  MigrateCtx.AtPropsWeak.insert(AtLoc.getRawEncoding());
266 
267  } else {
268  StringRef toAttr = "strong";
269  if (hasWeak) {
270  if (canApplyWeak(MigrateCtx.Pass.Ctx, IndProps.front()->getType(),
271  /*AllowOnUnknownClass=*/true))
272  toAttr = "weak";
273  else
274  toAttr = "unsafe_unretained";
275  }
277  MigrateCtx.rewritePropertyAttribute("assign", toAttr, AtLoc);
278  else
279  MigrateCtx.addPropertyAttribute(toAttr, AtLoc);
280  }
281 
282  for (unsigned i = 0, e = ATLs.size(); i != e; ++i) {
283  SourceLocation Loc = ATLs[i].first.getAttr()->getLocation();
284  if (Loc.isMacroID())
285  Loc = MigrateCtx.Pass.Ctx.getSourceManager()
287  .getBegin();
288  TA.remove(Loc);
289  TA.clearDiagnostic(diag::err_objc_property_attr_mutually_exclusive, AtLoc);
290  TA.clearDiagnostic(diag::err_arc_inconsistent_property_ownership,
291  ATLs[i].second->getLocation());
292  MigrateCtx.RemovedAttrSet.insert(Loc.getRawEncoding());
293  }
294 }
295 
296 static void checkAllProps(MigrationContext &MigrateCtx,
297  std::vector<ObjCPropertyDecl *> &AllProps) {
298  typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy;
299  llvm::DenseMap<unsigned, IndivPropsTy> AtProps;
300 
301  for (unsigned i = 0, e = AllProps.size(); i != e; ++i) {
302  ObjCPropertyDecl *PD = AllProps[i];
306  SourceLocation AtLoc = PD->getAtLoc();
307  if (AtLoc.isInvalid())
308  continue;
309  unsigned RawAt = AtLoc.getRawEncoding();
310  AtProps[RawAt].push_back(PD);
311  }
312  }
313 
314  for (llvm::DenseMap<unsigned, IndivPropsTy>::iterator
315  I = AtProps.begin(), E = AtProps.end(); I != E; ++I) {
317  IndivPropsTy &IndProps = I->second;
318  checkAllAtProps(MigrateCtx, AtLoc, IndProps);
319  }
320 }
321 
323  std::vector<ObjCPropertyDecl *> AllProps;
324  GCAttrsCollector(MigrateCtx, AllProps).TraverseDecl(
325  MigrateCtx.Pass.Ctx.getTranslationUnitDecl());
326 
327  errorForGCAttrsOnNonObjC(MigrateCtx);
328  checkAllProps(MigrateCtx, AllProps);
329  checkWeakGCAttrs(MigrateCtx);
330 }
331 
333  llvm::errs() << "\n################\n";
334  for (unsigned i = 0, e = GCAttrs.size(); i != e; ++i) {
335  GCAttrOccurrence &Attr = GCAttrs[i];
336  llvm::errs() << "KIND: "
337  << (Attr.Kind == GCAttrOccurrence::Strong ? "strong" : "weak");
338  llvm::errs() << "\nLOC: ";
339  Attr.Loc.print(llvm::errs(), Pass.Ctx.getSourceManager());
340  llvm::errs() << "\nTYPE: ";
341  Attr.ModifiedType.dump();
342  if (Attr.Dcl) {
343  llvm::errs() << "DECL:\n";
344  Attr.Dcl->dump();
345  } else {
346  llvm::errs() << "DECL: NONE";
347  }
348  llvm::errs() << "\nMIGRATABLE: " << Attr.FullyMigratable;
349  llvm::errs() << "\n----------------\n";
350  }
351  llvm::errs() << "\n################\n";
352 }
Defines the clang::ASTContext interface.
Represents a function declaration or definition.
Definition: Decl.h:1783
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:655
ObjCPropertyAttribute::Kind getPropertyAttributesAsWritten() const
Definition: DeclObjC.h:837
Defines the SourceManager interface.
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:89
A container of type source information.
Definition: Type.h:6373
bool rewritePropertyAttribute(StringRef fromAttr, StringRef toAttr, SourceLocation atLoc)
Definition: Transforms.cpp:380
static void checkWeakGCAttrs(MigrationContext &MigrateCtx)
Wrapper of type source information for a type with non-trivial direct qualifiers. ...
Definition: TypeLoc.h:277
std::vector< GCAttrOccurrence > GCAttrs
Definition: Transforms.h:95
Base wrapper for a particular "section" of type source info.
Definition: TypeLoc.h:58
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:174
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:960
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:1163
llvm::DenseSet< unsigned > RemovedAttrSet
Definition: Transforms.h:97
Represents a ValueDecl that came out of a declarator.
Definition: Decl.h:671
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:851
TypeSourceInfo * getTypeSourceInfo() const
Definition: DeclObjC.h:812
UnqualTypeLoc getUnqualifiedLoc() const
Skips past any qualifiers, if this is qualified.
Definition: TypeLoc.h:326
bool isObjCRetainableType() const
Definition: Type.cpp:4196
T getAs() const
Convert to the specified TypeLoc type, returning a null TypeLoc if this TypeLoc is not of the desired...
Definition: TypeLoc.h:88
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
Definition: DeclBase.h:563
DeclContext * getDeclContext()
Definition: DeclBase.h:439
CharSourceRange getImmediateExpansionRange(SourceLocation Loc) const
Return the start/end of the expansion information for an expansion location.
#define SM(sm)
Definition: Cuda.cpp:62
bool addPropertyAttribute(StringRef attr, SourceLocation atLoc)
Definition: Transforms.cpp:462
bool isNull() const
Return true if this QualType doesn&#39;t point to a type yet.
Definition: Type.h:720
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:1484
#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:172
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:880
ObjCCategoryDecl - Represents a category declaration.
Definition: DeclObjC.h:2271
Represents one property declaration in an Objective-C interface.
Definition: DeclObjC.h:742
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:972
Dataflow Directional Tag Classes.
QualType getType() const
Get the type for which this source info wrapper provides information.
Definition: TypeLoc.h:132
SourceLocation getAtLoc() const
Definition: DeclObjC.h:806
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:868
bool isMacroID() const
SourceManager & getSourceManager()
Definition: ASTContext.h:619
TypeLoc getTypeLoc() const
Return the TypeLoc wrapper for the type source info.
Definition: TypeLoc.h:244
Reading or writing from this object requires a barrier call.
Definition: Type.h:175
TranslationUnitDecl * getTranslationUnitDecl() const
Definition: ASTContext.h:935
TransformActions & TA
Definition: Internals.h:152
void remove(SourceRange range)
Represents a C++ struct/union/class.
Definition: DeclCXX.h:254
static bool isInMainFile(const clang::Diagnostic &D)
Definition: ASTUnit.cpp:678
enum clang::arcmt::trans::MigrationContext::GCAttrOccurrence::AttrKind Kind
void dump(const char *s) const
Definition: ASTDumper.cpp:156
void dump() const
Definition: ASTDumper.cpp:184
Wrapper for source info for pointers.
Definition: TypeLoc.h:1226
This class handles loading and caching of source files into memory.
Attr - This represents one attribute.
Definition: Attr.h:46
QualType getType() const
Return the type wrapped by this type source info.
Definition: Type.h:6384
Qualifiers::ObjCLifetime getObjCLifetime() const
Returns lifetime attribute of this type.
Definition: Type.h:1102
llvm::DenseSet< unsigned > AtPropsWeak
Set of raw &#39;@&#39; locations for &#39;assign&#39; properties group that contain GC __weak.
Definition: Transforms.h:101