@@ -2250,13 +2250,10 @@ class VarDeclUsageChecker : public ASTWalker {
2250
2250
2251
2251
// / This is a mapping from an OpaqueValue to the expression that initialized
2252
2252
// / it.
2253
- llvm::SmallDenseMap<OpaqueValueExpr*, Expr*> OpaqueValueMap;
2253
+ llvm::SmallDenseMap<OpaqueValueExpr *, Expr *> OpaqueValueMap;
2254
2254
2255
- // / The getter associated with a setter function declaration.
2256
- const VarDecl *AssociatedGetter = nullptr ;
2257
-
2258
- // / The first reference to the associated getter.
2259
- const Expr *AssociatedGetterRefExpr = nullptr ;
2255
+ // / The first reference to the given property.
2256
+ llvm::SmallDenseMap<VarDecl *, Expr *> AssociatedGetterRefExpr;
2260
2257
2261
2258
// / This is a mapping from VarDecls to the if/while/guard statement that they
2262
2259
// / occur in, when they are in a pattern in a StmtCondition.
@@ -2272,36 +2269,8 @@ class VarDeclUsageChecker : public ASTWalker {
2272
2269
void operator =(const VarDeclUsageChecker &) = delete ;
2273
2270
2274
2271
public:
2275
- VarDeclUsageChecker (AbstractFunctionDecl *AFD)
2276
- : Diags(AFD->getASTContext ().Diags) {
2277
- // If this AFD is a setter, track the parameter and the getter for
2278
- // the containing property so if newValue isn't used but the getter is used
2279
- // an error can be reported.
2280
- if (auto FD = dyn_cast<AccessorDecl>(AFD)) {
2281
- if (FD->getAccessorKind () == AccessorKind::Set) {
2282
- if (auto getter = dyn_cast<VarDecl>(FD->getStorage ())) {
2283
- auto arguments = FD->getParameters ();
2284
- VarDecls[arguments->get (0 )] = RK_Defined;
2285
- AssociatedGetter = getter;
2286
- }
2287
- }
2288
- }
2289
- }
2290
-
2291
2272
VarDeclUsageChecker (DiagnosticEngine &Diags) : Diags(Diags) {}
2292
2273
2293
- VarDeclUsageChecker (VarDecl *vd) : Diags(vd->getASTContext ().Diags) {
2294
- // Track a specific VarDecl
2295
- VarDecls[vd] = RK_Defined;
2296
- if (auto *childVd = vd->getCorrespondingCaseBodyVariable ().getPtrOrNull ()) {
2297
- VarDecls[childVd] = RK_Defined;
2298
- }
2299
- }
2300
-
2301
- void suppressDiagnostics () {
2302
- sawError = true ; // set this flag so that no diagnostics will be emitted on delete.
2303
- }
2304
-
2305
2274
// After we have scanned the entire region, diagnose variables that could be
2306
2275
// declared with a narrower usage kind.
2307
2276
~VarDeclUsageChecker () override ;
@@ -2404,23 +2373,31 @@ class VarDeclUsageChecker : public ASTWalker {
2404
2373
return false ;
2405
2374
2406
2375
if (auto *afd = dyn_cast<AbstractFunctionDecl>(D)) {
2407
- // If this is a nested function with a capture list, mark any captured
2408
- // variables.
2376
+ // If this AFD is a setter, track the parameter and the getter for
2377
+ // the containing property so if newValue isn't used but the getter is used
2378
+ // an error can be reported.
2379
+ if (auto FD = dyn_cast<AccessorDecl>(afd)) {
2380
+ if (FD->getAccessorKind () == AccessorKind::Set) {
2381
+ if (isa<VarDecl>(FD->getStorage ())) {
2382
+ auto arguments = FD->getParameters ();
2383
+ VarDecls[arguments->get (0 )] = RK_Defined;
2384
+ }
2385
+ }
2386
+ }
2387
+
2409
2388
if (afd->isBodyTypeChecked ()) {
2389
+ // FIXME: We don't actually need captures here anymore, but this happens
2390
+ // to be the place where they get computed. Move this somewhere else.
2410
2391
TypeChecker::computeCaptures (afd);
2411
- for (const auto &capture : afd->getCaptureInfo ().getCaptures ())
2412
- addMark (capture.getDecl (), RK_Read|RK_Written);
2413
- } else {
2414
- // If the body hasn't been type checked yet, be super-conservative and
2415
- // mark all variables as used. This can be improved later, e.g. by
2416
- // walking the untype-checked body to look for things that could
2417
- // possibly be used.
2418
- VarDecls.clear ();
2392
+ return true ;
2419
2393
}
2420
-
2421
- // Don't walk into it though, it may not even be type checked yet.
2394
+
2395
+ // Don't walk into a body that has not yet been type checked. This should
2396
+ // only occur for top-level code.
2397
+ VarDecls.clear ();
2422
2398
return false ;
2423
2399
}
2400
+
2424
2401
if (auto *TLCD = dyn_cast<TopLevelCodeDecl>(D)) {
2425
2402
// If this is a TopLevelCodeDecl, scan for global variables
2426
2403
auto *body = TLCD->getBody ();
@@ -2682,9 +2659,11 @@ VarDeclUsageChecker::~VarDeclUsageChecker() {
2682
2659
if (auto param = dyn_cast<ParamDecl>(var)) {
2683
2660
auto FD = dyn_cast<AccessorDecl>(param->getDeclContext ());
2684
2661
if (FD && FD->getAccessorKind () == AccessorKind::Set) {
2685
- auto getter = dyn_cast<VarDecl>(FD->getStorage ());
2686
- if ((access & RK_Read) == 0 && AssociatedGetter == getter) {
2687
- if (auto DRE = AssociatedGetterRefExpr) {
2662
+ auto VD = dyn_cast<VarDecl>(FD->getStorage ());
2663
+ if ((access & RK_Read) == 0 ) {
2664
+ auto found = AssociatedGetterRefExpr.find (VD);
2665
+ if (found != AssociatedGetterRefExpr.end ()) {
2666
+ auto *DRE = found->second ;
2688
2667
Diags.diagnose (DRE->getLoc (), diag::unused_setter_parameter,
2689
2668
var->getName ());
2690
2669
Diags.diagnose (DRE->getLoc (), diag::fixit_for_unused_setter_parameter,
@@ -3028,16 +3007,14 @@ std::pair<bool, Expr *> VarDeclUsageChecker::walkToExprPre(Expr *E) {
3028
3007
3029
3008
// If the Expression is a read of a getter, track for diagnostics
3030
3009
if (auto VD = dyn_cast<VarDecl>(DRE->getDecl ())) {
3031
- if (AssociatedGetter == VD && AssociatedGetterRefExpr == nullptr )
3032
- AssociatedGetterRefExpr = DRE;
3010
+ AssociatedGetterRefExpr.insert (std::make_pair (VD, DRE));
3033
3011
}
3034
3012
}
3035
3013
// If the Expression is a member reference, see if it is a read of the getter
3036
3014
// to track for diagnostics.
3037
3015
if (auto *MRE = dyn_cast<MemberRefExpr>(E)) {
3038
3016
if (auto VD = dyn_cast<VarDecl>(MRE->getMember ().getDecl ())) {
3039
- if (AssociatedGetter == VD && AssociatedGetterRefExpr == nullptr )
3040
- AssociatedGetterRefExpr = MRE;
3017
+ AssociatedGetterRefExpr.insert (std::make_pair (VD, MRE));
3041
3018
markBaseOfStorageUse (MRE->getBase (), MRE->getMember (), RK_Read);
3042
3019
return { false , E };
3043
3020
}
@@ -3124,18 +3101,22 @@ performTopLevelDeclDiagnostics(TopLevelCodeDecl *TLCD) {
3124
3101
}
3125
3102
3126
3103
// / Perform diagnostics for func/init/deinit declarations.
3127
- void swift::performAbstractFuncDeclDiagnostics (AbstractFunctionDecl *AFD,
3128
- BraceStmt *body) {
3129
- assert (body && " Need a body to check" );
3130
-
3104
+ void swift::performAbstractFuncDeclDiagnostics (AbstractFunctionDecl *AFD) {
3131
3105
// Don't produce these diagnostics for implicitly generated code.
3132
3106
if (AFD->getLoc ().isInvalid () || AFD->isImplicit () || AFD->isInvalid ())
3133
3107
return ;
3134
3108
3135
3109
// Check for unused variables, as well as variables that are could be
3136
- // declared as constants.
3137
- body->walk (VarDeclUsageChecker (AFD));
3138
-
3110
+ // declared as constants. Skip local functions though, since they will
3111
+ // be checked as part of their parent function or TopLevelCodeDecl.
3112
+ if (!AFD->getDeclContext ()->isLocalContext ()) {
3113
+ auto &ctx = AFD->getDeclContext ()->getASTContext ();
3114
+ VarDeclUsageChecker checker (ctx.Diags );
3115
+ AFD->walk (checker);
3116
+ }
3117
+
3118
+ auto *body = AFD->getBody ();
3119
+
3139
3120
// If the function has an opaque return type, check the return expressions
3140
3121
// to determine the underlying type.
3141
3122
if (auto opaqueResultTy = AFD->getOpaqueResultTypeDecl ()) {
0 commit comments