Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/clang/lib/ARCMigrate/TransGCAttrs.cpp
Line
Count
Source (jump to first uncovered line)
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"
12
#include "clang/Basic/SourceManager.h"
13
#include "clang/Lex/Lexer.h"
14
#include "clang/Sema/SemaDiagnostic.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
31
  typedef RecursiveASTVisitor<GCAttrsCollector> base;
32
public:
33
  GCAttrsCollector(MigrationContext &ctx,
34
                   std::vector<ObjCPropertyDecl *> &AllProps)
35
    : MigrateCtx(ctx), FullyMigratable(false),
36
13
      AllProps(AllProps) { }
37
38
1.51k
  bool shouldWalkTypesOfTypeLocs() const { return false; }
39
40
172
  bool VisitAttributedTypeLoc(AttributedTypeLoc TL) {
41
172
    handleAttr(TL);
42
172
    return true;
43
172
  }
44
45
1.59k
  bool TraverseDecl(Decl *D) {
46
1.59k
    if (!D || D->isImplicit())
47
386
      return true;
48
1.20k
49
1.20k
    SaveAndRestore<bool> Save(FullyMigratable, isMigratable(D));
50
1.20k
51
1.20k
    if (ObjCPropertyDecl *PropD = dyn_cast<ObjCPropertyDecl>(D)) {
52
147
      lookForAttribute(PropD, PropD->getTypeSourceInfo());
53
147
      AllProps.push_back(PropD);
54
1.05k
    } else if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) {
55
513
      lookForAttribute(DD, DD->getTypeSourceInfo());
56
513
    }
57
1.20k
    return base::TraverseDecl(D);
58
1.20k
  }
59
60
660
  void lookForAttribute(Decl *D, TypeSourceInfo *TInfo) {
61
660
    if (!TInfo)
62
77
      return;
63
583
    TypeLoc TL = TInfo->getTypeLoc();
64
706
    while (TL) {
65
706
      if (QualifiedTypeLoc QL = TL.getAs<QualifiedTypeLoc>()) {
66
18
        TL = QL.getUnqualifiedLoc();
67
688
      } else if (AttributedTypeLoc Attr = TL.getAs<AttributedTypeLoc>()) {
68
168
        if (handleAttr(Attr, D))
69
150
          break;
70
18
        TL = Attr.getModifiedLoc();
71
520
      } else if (MacroQualifiedTypeLoc MDTL =
72
9
                     TL.getAs<MacroQualifiedTypeLoc>()) {
73
9
        TL = MDTL.getInnerLoc();
74
511
      } else if (ArrayTypeLoc Arr = TL.getAs<ArrayTypeLoc>()) {
75
4
        TL = Arr.getElementLoc();
76
507
      } else if (PointerTypeLoc PT = TL.getAs<PointerTypeLoc>()) {
77
74
        TL = PT.getPointeeLoc();
78
433
      } else if (ReferenceTypeLoc RT = TL.getAs<ReferenceTypeLoc>())
79
0
        TL = RT.getPointeeLoc();
80
433
      else
81
433
        break;
82
706
    }
83
583
  }
84
85
340
  bool handleAttr(AttributedTypeLoc TL, Decl *D = nullptr) {
86
340
    auto *OwnershipAttr = TL.getAttrAs<ObjCOwnershipAttr>();
87
340
    if (!OwnershipAttr)
88
36
      return false;
89
304
90
304
    SourceLocation Loc = OwnershipAttr->getLocation();
91
304
    unsigned RawLoc = Loc.getRawEncoding();
92
304
    if (MigrateCtx.AttrSet.count(RawLoc))
93
150
      return true;
94
154
95
154
    ASTContext &Ctx = MigrateCtx.Pass.Ctx;
96
154
    SourceManager &SM = Ctx.getSourceManager();
97
154
    if (Loc.isMacroID())
98
154
      Loc = SM.getImmediateExpansionRange(Loc).getBegin();
99
154
    StringRef Spell = OwnershipAttr->getKind()->getName();
100
154
    MigrationContext::GCAttrOccurrence::AttrKind Kind;
101
154
    if (Spell == "strong")
102
58
      Kind = MigrationContext::GCAttrOccurrence::Strong;
103
96
    else if (Spell == "weak")
104
96
      Kind = MigrationContext::GCAttrOccurrence::Weak;
105
0
    else
106
0
      return false;
107
154
108
154
    MigrateCtx.AttrSet.insert(RawLoc);
109
154
    MigrateCtx.GCAttrs.push_back(MigrationContext::GCAttrOccurrence());
110
154
    MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs.back();
111
154
112
154
    Attr.Kind = Kind;
113
154
    Attr.Loc = Loc;
114
154
    Attr.ModifiedType = TL.getModifiedLoc().getType();
115
154
    Attr.Dcl = D;
116
154
    Attr.FullyMigratable = FullyMigratable;
117
154
    return true;
118
154
  }
119
120
1.67k
  bool isMigratable(Decl *D) {
121
1.67k
    if (isa<TranslationUnitDecl>(D))
122
117
      return false;
123
1.55k
124
1.55k
    if (isInMainFile(D))
125
608
      return true;
126
945
127
945
    if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
128
216
      return FD->hasBody();
129
729
130
729
    if (ObjCContainerDecl *ContD = dyn_cast<ObjCContainerDecl>(D))
131
261
      return hasObjCImpl(ContD);
132
468
133
468
    if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) {
134
4
      for (const auto *MI : RD->methods()) {
135
0
        if (MI->isOutOfLine())
136
0
          return true;
137
0
      }
138
4
      return false;
139
464
    }
140
464
141
464
    return isMigratable(cast<Decl>(D->getDeclContext()));
142
464
  }
143
144
330
  static bool hasObjCImpl(Decl *D) {
145
330
    if (!D)
146
0
      return false;
147
330
    if (ObjCContainerDecl *ContD = dyn_cast<ObjCContainerDecl>(D)) {
148
330
      if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(ContD))
149
258
        return ID->getImplementation() != nullptr;
150
72
      if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(ContD))
151
0
        return CD->getImplementation() != nullptr;
152
72
      return isa<ObjCImplDecl>(ContD);
153
72
    }
154
0
    return false;
155
0
  }
156
157
1.55k
  bool isInMainFile(Decl *D) {
158
1.55k
    if (!D)
159
0
      return false;
160
1.55k
161
1.55k
    for (auto I : D->redecls())
162
1.55k
      if (!isInMainFile(I->getLocation()))
163
945
        return false;
164
1.55k
165
1.55k
    
return true608
;
166
1.55k
  }
167
168
1.55k
  bool isInMainFile(SourceLocation Loc) {
169
1.55k
    if (Loc.isInvalid())
170
0
      return false;
171
1.55k
172
1.55k
    SourceManager &SM = MigrateCtx.Pass.Ctx.getSourceManager();
173
1.55k
    return SM.isInFileID(SM.getExpansionLoc(Loc), SM.getMainFileID());
174
1.55k
  }
175
};
176
177
} // anonymous namespace
178
179
13
static void errorForGCAttrsOnNonObjC(MigrationContext &MigrateCtx) {
180
13
  TransformActions &TA = MigrateCtx.Pass.TA;
181
13
182
167
  for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; 
++i154
) {
183
154
    MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i];
184
154
    if (Attr.FullyMigratable && 
Attr.Dcl136
) {
185
132
      if (Attr.ModifiedType.isNull())
186
0
        continue;
187
132
      if (!Attr.ModifiedType->isObjCRetainableType()) {
188
2
        TA.reportError("GC managed memory will become unmanaged in ARC",
189
2
                       Attr.Loc);
190
2
      }
191
132
    }
192
154
  }
193
13
}
194
195
13
static void checkWeakGCAttrs(MigrationContext &MigrateCtx) {
196
13
  TransformActions &TA = MigrateCtx.Pass.TA;
197
13
198
167
  for (unsigned i = 0, e = MigrateCtx.GCAttrs.size(); i != e; 
++i154
) {
199
154
    MigrationContext::GCAttrOccurrence &Attr = MigrateCtx.GCAttrs[i];
200
154
    if (Attr.Kind == MigrationContext::GCAttrOccurrence::Weak) {
201
96
      if (Attr.ModifiedType.isNull() ||
202
96
          !Attr.ModifiedType->isObjCRetainableType())
203
0
        continue;
204
96
      if (!canApplyWeak(MigrateCtx.Pass.Ctx, Attr.ModifiedType,
205
96
                        /*AllowOnUnknownClass=*/true)) {
206
16
        Transaction Trans(TA);
207
16
        if (!MigrateCtx.RemovedAttrSet.count(Attr.Loc.getRawEncoding()))
208
11
          TA.replaceText(Attr.Loc, "__weak", "__unsafe_unretained");
209
16
        TA.clearDiagnostic(diag::err_arc_weak_no_runtime,
210
16
                           diag::err_arc_unsupported_weak_class,
211
16
                           Attr.Loc);
212
16
      }
213
96
    }
214
154
  }
215
13
}
216
217
typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy;
218
219
static void checkAllAtProps(MigrationContext &MigrateCtx,
220
                            SourceLocation AtLoc,
221
112
                            IndivPropsTy &IndProps) {
222
112
  if (IndProps.empty())
223
0
    return;
224
112
225
112
  for (IndivPropsTy::iterator
226
242
         PI = IndProps.begin(), PE = IndProps.end(); PI != PE; 
++PI130
) {
227
130
    QualType T = (*PI)->getType();
228
130
    if (T.isNull() || !T->isObjCRetainableType())
229
0
      return;
230
130
  }
231
112
232
112
  SmallVector<std::pair<AttributedTypeLoc, ObjCPropertyDecl *>, 4> ATLs;
233
112
  bool hasWeak = false, hasStrong = false;
234
112
  ObjCPropertyDecl::PropertyAttributeKind
235
112
    Attrs = ObjCPropertyDecl::OBJC_PR_noattr;
236
112
  for (IndivPropsTy::iterator
237
242
         PI = IndProps.begin(), PE = IndProps.end(); PI != PE; 
++PI130
) {
238
130
    ObjCPropertyDecl *PD = *PI;
239
130
    Attrs = PD->getPropertyAttributesAsWritten();
240
130
    TypeSourceInfo *TInfo = PD->getTypeSourceInfo();
241
130
    if (!TInfo)
242
0
      return;
243
130
    TypeLoc TL = TInfo->getTypeLoc();
244
130
    if (AttributedTypeLoc ATL =
245
87
            TL.getAs<AttributedTypeLoc>()) {
246
87
      ATLs.push_back(std::make_pair(ATL, PD));
247
87
      if (TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Weak) {
248
61
        hasWeak = true;
249
61
      } else 
if (26
TInfo->getType().getObjCLifetime() == Qualifiers::OCL_Strong26
)
250
26
        hasStrong = true;
251
0
      else
252
0
        return;
253
87
    }
254
130
  }
255
112
  if (ATLs.empty())
256
43
    return;
257
69
  if (hasWeak && 
hasStrong43
)
258
0
    return;
259
69
260
69
  TransformActions &TA = MigrateCtx.Pass.TA;
261
69
  Transaction Trans(TA);
262
69
263
69
  if (GCAttrsCollector::hasObjCImpl(
264
69
                              cast<Decl>(IndProps.front()->getDeclContext()))) {
265
50
    if (hasWeak)
266
33
      MigrateCtx.AtPropsWeak.insert(AtLoc.getRawEncoding());
267
50
268
50
  } else {
269
19
    StringRef toAttr = "strong";
270
19
    if (hasWeak) {
271
10
      if (canApplyWeak(MigrateCtx.Pass.Ctx, IndProps.front()->getType(),
272
10
                       /*AllowOnUnknownClass=*/true))
273
8
        toAttr = "weak";
274
2
      else
275
2
        toAttr = "unsafe_unretained";
276
10
    }
277
19
    if (Attrs & ObjCPropertyDecl::OBJC_PR_assign)
278
18
      MigrateCtx.rewritePropertyAttribute("assign", toAttr, AtLoc);
279
1
    else
280
1
      MigrateCtx.addPropertyAttribute(toAttr, AtLoc);
281
19
  }
282
69
283
156
  for (unsigned i = 0, e = ATLs.size(); i != e; 
++i87
) {
284
87
    SourceLocation Loc = ATLs[i].first.getAttr()->getLocation();
285
87
    if (Loc.isMacroID())
286
87
      Loc = MigrateCtx.Pass.Ctx.getSourceManager()
287
87
                .getImmediateExpansionRange(Loc)
288
87
                .getBegin();
289
87
    TA.remove(Loc);
290
87
    TA.clearDiagnostic(diag::err_objc_property_attr_mutually_exclusive, AtLoc);
291
87
    TA.clearDiagnostic(diag::err_arc_inconsistent_property_ownership,
292
87
                       ATLs[i].second->getLocation());
293
87
    MigrateCtx.RemovedAttrSet.insert(Loc.getRawEncoding());
294
87
  }
295
69
}
296
297
static void checkAllProps(MigrationContext &MigrateCtx,
298
13
                          std::vector<ObjCPropertyDecl *> &AllProps) {
299
13
  typedef llvm::TinyPtrVector<ObjCPropertyDecl *> IndivPropsTy;
300
13
  llvm::DenseMap<unsigned, IndivPropsTy> AtProps;
301
13
302
160
  for (unsigned i = 0, e = AllProps.size(); i != e; 
++i147
) {
303
147
    ObjCPropertyDecl *PD = AllProps[i];
304
147
    if (PD->getPropertyAttributesAsWritten() &
305
147
          (ObjCPropertyDecl::OBJC_PR_assign |
306
147
           ObjCPropertyDecl::OBJC_PR_readonly)) {
307
130
      SourceLocation AtLoc = PD->getAtLoc();
308
130
      if (AtLoc.isInvalid())
309
0
        continue;
310
130
      unsigned RawAt = AtLoc.getRawEncoding();
311
130
      AtProps[RawAt].push_back(PD);
312
130
    }
313
147
  }
314
13
315
13
  for (llvm::DenseMap<unsigned, IndivPropsTy>::iterator
316
125
         I = AtProps.begin(), E = AtProps.end(); I != E; 
++I112
) {
317
112
    SourceLocation AtLoc = SourceLocation::getFromRawEncoding(I->first);
318
112
    IndivPropsTy &IndProps = I->second;
319
112
    checkAllAtProps(MigrateCtx, AtLoc, IndProps);
320
112
  }
321
13
}
322
323
13
void GCAttrsTraverser::traverseTU(MigrationContext &MigrateCtx) {
324
13
  std::vector<ObjCPropertyDecl *> AllProps;
325
13
  GCAttrsCollector(MigrateCtx, AllProps).TraverseDecl(
326
13
                                  MigrateCtx.Pass.Ctx.getTranslationUnitDecl());
327
13
328
13
  errorForGCAttrsOnNonObjC(MigrateCtx);
329
13
  checkAllProps(MigrateCtx, AllProps);
330
13
  checkWeakGCAttrs(MigrateCtx);
331
13
}
332
333
0
void MigrationContext::dumpGCAttrs() {
334
0
  llvm::errs() << "\n################\n";
335
0
  for (unsigned i = 0, e = GCAttrs.size(); i != e; ++i) {
336
0
    GCAttrOccurrence &Attr = GCAttrs[i];
337
0
    llvm::errs() << "KIND: "
338
0
        << (Attr.Kind == GCAttrOccurrence::Strong ? "strong" : "weak");
339
0
    llvm::errs() << "\nLOC: ";
340
0
    Attr.Loc.print(llvm::errs(), Pass.Ctx.getSourceManager());
341
0
    llvm::errs() << "\nTYPE: ";
342
0
    Attr.ModifiedType.dump();
343
0
    if (Attr.Dcl) {
344
0
      llvm::errs() << "DECL:\n";
345
0
      Attr.Dcl->dump();
346
0
    } else {
347
0
      llvm::errs() << "DECL: NONE";
348
0
    }
349
0
    llvm::errs() << "\nMIGRATABLE: " << Attr.FullyMigratable;
350
0
    llvm::errs() << "\n----------------\n";
351
0
  }
352
0
  llvm::errs() << "\n################\n";
353
0
}