clang  14.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  SourceLocation OrigLoc = Loc;
92  if (MigrateCtx.AttrSet.count(OrigLoc))
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(OrigLoc);
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) {
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) {
201  if (Attr.ModifiedType.isNull() ||
202  !Attr.ModifiedType->isObjCRetainableType())
203  continue;
204  if (!canApplyWeak(MigrateCtx.Pass.Ctx, Attr.ModifiedType,
205  /*AllowOnUnknownClass=*/true)) {
206  Transaction Trans(TA);
207  if (!MigrateCtx.RemovedAttrSet.count(Attr.Loc))
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);
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);
293  }
294 }
295 
296 static void checkAllProps(MigrationContext &MigrateCtx,
297  std::vector<ObjCPropertyDecl *> &AllProps) {
298  typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy;
299  llvm::DenseMap<SourceLocation, 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  AtProps[AtLoc].push_back(PD);
310  }
311  }
312 
313  for (auto I = AtProps.begin(), E = AtProps.end(); I != E; ++I) {
314  SourceLocation AtLoc = I->first;
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) {
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 }
isInMainFile
static bool isInMainFile(const clang::Diagnostic &D)
Definition: ASTUnit.cpp:679
clang::ObjCInterfaceDecl
Represents an ObjC class declaration.
Definition: DeclObjC.h:1151
clang::QualType::getObjCLifetime
Qualifiers::ObjCLifetime getObjCLifetime() const
Returns lifetime attribute of this type.
Definition: Type.h:1120
clang::arcmt::trans::MigrationContext::dumpGCAttrs
void dumpGCAttrs()
Definition: TransGCAttrs.cpp:330
clang::TypeSourceInfo::getType
QualType getType() const
Return the type wrapped by this type source info.
Definition: Type.h:6406
clang::AttributeCommonInfo::Kind
Kind
Definition: AttributeCommonInfo.h:52
clang::CharSourceRange::getBegin
SourceLocation getBegin() const
Definition: SourceLocation.h:285
clang::Type::isObjCRetainableType
bool isObjCRetainableType() const
Definition: Type.cpp:4284
clang::PointerTypeLoc
Wrapper for source info for pointers.
Definition: TypeLoc.h:1225
clang::ReferenceTypeLoc
Definition: TypeLoc.h:1306
Transforms.h
clang::Qualifiers::OCL_Weak
@ OCL_Weak
Reading or writing from this object requires a barrier call.
Definition: Type.h:176
llvm::SmallVector
Definition: LLVM.h:38
clang::SourceLocation
Encodes a location in the source.
Definition: SourceLocation.h:88
clang::AttributedTypeLoc::getAttrAs
const T * getAttrAs()
Definition: TypeLoc.h:879
clang::arcmt::TransformActions
Definition: Internals.h:49
clang::QualType
A (possibly-)qualified type.
Definition: Type.h:673
clang::SourceManager::getImmediateExpansionRange
CharSourceRange getImmediateExpansionRange(SourceLocation Loc) const
Return the start/end of the expansion information for an expansion location.
Definition: SourceManager.cpp:1027
Internals.h
SourceManager.h
clang::arcmt::trans::GCAttrsTraverser::traverseTU
void traverseTU(MigrationContext &MigrateCtx) override
Definition: TransGCAttrs.cpp:320
clang::arcmt::MigrationPass::TA
TransformActions & TA
Definition: Internals.h:152
clang::ASTContext::getSourceManager
SourceManager & getSourceManager()
Definition: ASTContext.h:695
clang::ASTContext::getTranslationUnitDecl
TranslationUnitDecl * getTranslationUnitDecl() const
Definition: ASTContext.h:1057
clang::arcmt::trans::MigrationContext::RemovedAttrSet
llvm::DenseSet< SourceLocation > RemovedAttrSet
Definition: Transforms.h:97
clang::SourceManager
This class handles loading and caching of source files into memory.
Definition: SourceManager.h:626
clang::arcmt::trans::MigrationContext::AttrSet
llvm::DenseSet< SourceLocation > AttrSet
Definition: Transforms.h:96
clang::arcmt::TransformActions::replaceText
void replaceText(SourceLocation loc, StringRef text, StringRef replacementText)
Definition: TransformActions.cpp:659
clang::QualifiedTypeLoc
Wrapper of type source information for a type with non-trivial direct qualifiers.
Definition: TypeLoc.h:277
clang::arcmt::Transaction
Definition: Internals.h:124
clang::Qualifiers::OCL_Strong
@ OCL_Strong
Assigning into this object requires the old value to be released and the new value to be retained.
Definition: Type.h:173
clang::arcmt::TransformActions::remove
void remove(SourceRange range)
Definition: TransformActions.cpp:638
clang::ASTContext
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:212
clang::arcmt::trans::MigrationContext
Definition: Transforms.h:80
clang::RecursiveASTVisitor
A class that does preorder or postorder depth-first traversal on the entire Clang AST and visits each...
Definition: RecursiveASTVisitor.h:164
clang::arcmt::trans::MigrationContext::addPropertyAttribute
bool addPropertyAttribute(StringRef attr, SourceLocation atLoc)
Definition: Transforms.cpp:460
ASTContext.h
clang::arcmt::trans::MigrationContext::GCAttrOccurrence
Definition: Transforms.h:86
clang::Decl::redecls
redecl_range redecls() const
Returns an iterator range for all the redeclarations of the same decl.
Definition: DeclBase.h:972
clang::ObjCPropertyAttribute::kind_readonly
@ kind_readonly
Definition: DeclObjCCommon.h:24
clang::AttributedTypeLoc
Type source information for an attributed type.
Definition: TypeLoc.h:850
clang::arcmt::MigrationPass::Ctx
ASTContext & Ctx
Definition: Internals.h:148
clang::Decl::isImplicit
bool isImplicit() const
isImplicit - Indicates whether the declaration was implicitly generated by the implementation.
Definition: DeclBase.h:563
clang::arcmt::trans::MigrationContext::GCAttrOccurrence::Weak
@ Weak
Definition: Transforms.h:87
clang::AttributedTypeLoc::getModifiedLoc
TypeLoc getModifiedLoc() const
The modified type, which is generally canonically different from the attribute type.
Definition: TypeLoc.h:867
clang::ObjCCategoryDecl
ObjCCategoryDecl - Represents a category declaration.
Definition: DeclObjC.h:2274
clang::CXXRecordDecl
Represents a C++ struct/union/class.
Definition: DeclCXX.h:255
clang::arcmt::trans::MigrationContext::GCAttrOccurrence::Strong
@ Strong
Definition: Transforms.h:87
checkAllProps
static void checkAllProps(MigrationContext &MigrateCtx, std::vector< ObjCPropertyDecl * > &AllProps)
Definition: TransGCAttrs.cpp:296
false
#define false
Definition: stdbool.h:17
clang::ObjCPropertyAttribute::kind_noattr
@ kind_noattr
Definition: DeclObjCCommon.h:23
clang::TypeLoc::getUnqualifiedLoc
UnqualTypeLoc getUnqualifiedLoc() const
Skips past any qualifiers, if this is qualified.
Definition: TypeLoc.h:326
SemaDiagnostic.h
clang::TypeLoc::getAs
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
clang::QualType::isNull
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition: Type.h:738
Lexer.h
clang::Decl
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:89
clang::DeclaratorDecl
Represents a ValueDecl that came out of a declarator.
Definition: Decl.h:728
clang::TypeLoc
Base wrapper for a particular "section" of type source info.
Definition: TypeLoc.h:58
clang::ObjCPropertyDecl
Represents one property declaration in an Objective-C interface.
Definition: DeclObjC.h:732
clang::ObjCPropertyAttribute::kind_assign
@ kind_assign
Definition: DeclObjCCommon.h:26
clang::TypeLoc::getType
QualType getType() const
Get the type for which this source info wrapper provides information.
Definition: TypeLoc.h:132
llvm::SaveAndRestore< bool >
clang::SourceLocation::isMacroID
bool isMacroID() const
Definition: SourceLocation.h:105
clang::ObjCPropertyDecl::getPropertyAttributesAsWritten
ObjCPropertyAttribute::Kind getPropertyAttributesAsWritten() const
Definition: DeclObjC.h:827
clang::ObjCPropertyAttribute::Kind
Kind
Definition: DeclObjCCommon.h:22
clang::ArrayTypeLoc
Wrapper for source info for arrays.
Definition: TypeLoc.h:1483
clang::Builtin::ID
ID
Definition: Builtins.h:48
clang::SourceLocation::isInvalid
bool isInvalid() const
Definition: SourceLocation.h:113
clang::arcmt::TransformActions::reportError
void reportError(StringRef error, SourceLocation loc, SourceRange range=SourceRange())
Definition: TransformActions.cpp:687
IndivPropsTy
llvm::TinyPtrVector< ObjCPropertyDecl * > IndivPropsTy
Definition: TransGCAttrs.cpp:217
clang
Definition: CalledOnceCheck.h:17
errorForGCAttrsOnNonObjC
static void errorForGCAttrsOnNonObjC(MigrationContext &MigrateCtx)
Definition: TransGCAttrs.cpp:179
clang::ObjCPropertyDecl::getTypeSourceInfo
TypeSourceInfo * getTypeSourceInfo() const
Definition: DeclObjC.h:802
clang::arcmt::trans::MigrationContext::Pass
MigrationPass & Pass
Definition: Transforms.h:84
clang::Attr
Attr - This represents one attribute.
Definition: Attr.h:46
clang::TypeSourceInfo
A container of type source information.
Definition: Type.h:6395
clang::arcmt::trans::canApplyWeak
bool canApplyWeak(ASTContext &Ctx, QualType type, bool AllowOnUnknownClass=false)
Determine whether we can add weak to the given type.
Definition: Transforms.cpp:38
clang::arcmt::trans::MigrationContext::AtPropsWeak
llvm::DenseSet< SourceLocation > AtPropsWeak
Set of raw '@' locations for 'assign' properties group that contain GC __weak.
Definition: Transforms.h:101
clang::ObjCContainerDecl
ObjCContainerDecl - Represents a container for method declarations.
Definition: DeclObjC.h:948
clang::ObjCPropertyDecl::getAtLoc
SourceLocation getAtLoc() const
Definition: DeclObjC.h:796
clang::arcmt::TransformActions::clearDiagnostic
bool clearDiagnostic(ArrayRef< unsigned > IDs, SourceRange range)
Definition: TransformActions.cpp:671
clang::arcmt::trans::MigrationContext::GCAttrOccurrence::AttrKind
AttrKind
Definition: Transforms.h:87
clang::arcmt::trans::MigrationContext::rewritePropertyAttribute
bool rewritePropertyAttribute(StringRef fromAttr, StringRef toAttr, SourceLocation atLoc)
Definition: Transforms.cpp:378
SM
#define SM(sm)
Definition: Cuda.cpp:78
checkAllAtProps
static void checkAllAtProps(MigrationContext &MigrateCtx, SourceLocation AtLoc, IndivPropsTy &IndProps)
Definition: TransGCAttrs.cpp:219
clang::FunctionDecl
Represents a function declaration or definition.
Definition: Decl.h:1856
clang::arcmt::trans::MigrationContext::GCAttrs
std::vector< GCAttrOccurrence > GCAttrs
Definition: Transforms.h:95
clang::MacroQualifiedTypeLoc
Definition: TypeLoc.h:1078
clang::TypeSourceInfo::getTypeLoc
TypeLoc getTypeLoc() const
Return the TypeLoc wrapper for the type source info.
Definition: TypeLoc.h:244
clang::Decl::getDeclContext
DeclContext * getDeclContext()
Definition: DeclBase.h:439
checkWeakGCAttrs
static void checkWeakGCAttrs(MigrationContext &MigrateCtx)
Definition: TransGCAttrs.cpp:195