clang  10.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 (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;
236  for (IndivPropsTy::iterator
237  PI = IndProps.begin(), PE = IndProps.end(); PI != PE; ++PI) {
238  ObjCPropertyDecl *PD = *PI;
239  Attrs = PD->getPropertyAttributesAsWritten();
240  TypeSourceInfo *TInfo = PD->getTypeSourceInfo();
241  if (!TInfo)
242  return;
243  TypeLoc TL = TInfo->getTypeLoc();
244  if (AttributedTypeLoc ATL =
245  TL.getAs<AttributedTypeLoc>()) {
246  ATLs.push_back(std::make_pair(ATL, PD));
247  if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {
248  hasWeak = true;
249  } else if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Strong)
250  hasStrong = true;
251  else
252  return;
253  }
254  }
255  if (ATLs.empty())
256  return;
257  if (hasWeak && hasStrong)
258  return;
259 
260  TransformActions &TA = MigrateCtx.Pass.TA;
261  Transaction Trans(TA);
262 
263  if (GCAttrsCollector::hasObjCImpl(
264  cast<Decl>(IndProps.front()->getDeclContext()))) {
265  if (hasWeak)
266  MigrateCtx.AtPropsWeak.insert(AtLoc.getRawEncoding());
267 
268  } else {
269  StringRef toAttr = "strong";
270  if (hasWeak) {
271  if (canApplyWeak(MigrateCtx.Pass.Ctx, IndProps.front()->getType(),
272  /*AllowOnUnknownClass=*/true))
273  toAttr = "weak";
274  else
275  toAttr = "unsafe_unretained";
276  }
278  MigrateCtx.rewritePropertyAttribute("assign", toAttr, AtLoc);
279  else
280  MigrateCtx.addPropertyAttribute(toAttr, AtLoc);
281  }
282 
283  for (unsigned i = 0, e = ATLs.size(); i != e; ++i) {
284  SourceLocation Loc = ATLs[i].first.getAttr()->getLocation();
285  if (Loc.isMacroID())
286  Loc = MigrateCtx.Pass.Ctx.getSourceManager()
288  .getBegin();
289  TA.remove(Loc);
290  TA.clearDiagnostic(diag::err_objc_property_attr_mutually_exclusive, AtLoc);
291  TA.clearDiagnostic(diag::err_arc_inconsistent_property_ownership,
292  ATLs[i].second->getLocation());
293  MigrateCtx.RemovedAttrSet.insert(Loc.getRawEncoding());
294  }
295 }
296 
297 static void checkAllProps(MigrationContext &MigrateCtx,
298  std::vector<ObjCPropertyDecl *> &AllProps) {
299  typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy;
300  llvm::DenseMap<unsigned, IndivPropsTy> AtProps;
301 
302  for (unsigned i = 0, e = AllProps.size(); i != e; ++i) {
303  ObjCPropertyDecl *PD = AllProps[i];
307  SourceLocation AtLoc = PD->getAtLoc();
308  if (AtLoc.isInvalid())
309  continue;
310  unsigned RawAt = AtLoc.getRawEncoding();
311  AtProps[RawAt].push_back(PD);
312  }
313  }
314 
315  for (llvm::DenseMap<unsigned, IndivPropsTy>::iterator
316  I = AtProps.begin(), E = AtProps.end(); I != E; ++I) {
318  IndivPropsTy &IndProps = I->second;
319  checkAllAtProps(MigrateCtx, AtLoc, IndProps);
320  }
321 }
322 
324  std::vector<ObjCPropertyDecl *> AllProps;
325  GCAttrsCollector(MigrateCtx, AllProps).TraverseDecl(
326  MigrateCtx.Pass.Ctx.getTranslationUnitDecl());
327 
328  errorForGCAttrsOnNonObjC(MigrateCtx);
329  checkAllProps(MigrateCtx, AllProps);
330  checkWeakGCAttrs(MigrateCtx);
331 }
332 
334  llvm::errs() << "\n################\n";
335  for (unsigned i = 0, e = GCAttrs.size(); i != e; ++i) {
336  GCAttrOccurrence &Attr = GCAttrs[i];
337  llvm::errs() << "KIND: "
338  << (Attr.Kind == GCAttrOccurrence::Strong ? "strong" : "weak");
339  llvm::errs() << "\nLOC: ";
340  Attr.Loc.print(llvm::errs(), Pass.Ctx.getSourceManager());
341  llvm::errs() << "\nTYPE: ";
342  Attr.ModifiedType.dump();
343  if (Attr.Dcl) {
344  llvm::errs() << "DECL:\n";
345  Attr.Dcl->dump();
346  } else {
347  llvm::errs() << "DECL: NONE";
348  }
349  llvm::errs() << "\nMIGRATABLE: " << Attr.FullyMigratable;
350  llvm::errs() << "\n----------------\n";
351  }
352  llvm::errs() << "\n################\n";
353 }
Defines the clang::ASTContext interface.
Represents a function declaration or definition.
Definition: Decl.h:1756
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:643
Defines the SourceManager interface.
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:88
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:273
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:160
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:851
TypeSourceInfo * getTypeSourceInfo() const
Definition: DeclObjC.h:826
UnqualTypeLoc getUnqualifiedLoc() const
Skips past any qualifiers, if this is qualified.
Definition: TypeLoc.h:322
bool isObjCRetainableType() const
Definition: Type.cpp:4004
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:558
DeclContext * getDeclContext()
Definition: DeclBase.h:438
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:708
const SourceManager & SM
Definition: Format.cpp:1609
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:1495
#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:880
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:948
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:868
bool isMacroID() const
SourceManager & getSourceManager()
Definition: ASTContext.h:675
TypeLoc getTypeLoc() const
Return the TypeLoc wrapper for the type source info.
Definition: TypeLoc.h:240
Reading or writing from this object requires a barrier call.
Definition: Type.h:168
TranslationUnitDecl * getTranslationUnitDecl() const
Definition: ASTContext.h:1005
TransformActions & TA
Definition: Internals.h:150
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:179
Wrapper for source info for pointers.
Definition: TypeLoc.h:1237
This class handles loading and caching of source files into memory.
Attr - This represents one attribute.
Definition: Attr.h:45
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:101