@@ -2297,10 +2297,44 @@ static AccessLevel getTestableAccess(const ValueDecl *decl) {
2297
2297
return AccessLevel::Public;
2298
2298
}
2299
2299
2300
+ // / Adjust \p access based on whether \p VD is \@usableFromInline or has been
2301
+ // / testably imported from \p useDC.
2302
+ // /
2303
+ // / \p access isn't always just `VD->getFormalAccess()` because this adjustment
2304
+ // / may be for a write, in which case the setter's access might be used instead.
2305
+ static AccessLevel getAdjustedFormalAccess (const ValueDecl *VD,
2306
+ AccessLevel access,
2307
+ const DeclContext *useDC,
2308
+ bool treatUsableFromInlineAsPublic) {
2309
+ if (treatUsableFromInlineAsPublic &&
2310
+ access == AccessLevel::Internal &&
2311
+ VD->isUsableFromInline ()) {
2312
+ return AccessLevel::Public;
2313
+ }
2314
+
2315
+ if (useDC && (access == AccessLevel::Internal ||
2316
+ access == AccessLevel::Public)) {
2317
+ if (auto *useSF = dyn_cast<SourceFile>(useDC->getModuleScopeContext ()))
2318
+ if (useSF->hasTestableImport (VD->getModuleContext ()))
2319
+ return getTestableAccess (VD);
2320
+ }
2321
+
2322
+ return access;
2323
+ }
2324
+
2325
+ // / Convenience overload that uses `VD->getFormalAccess()` as the access to
2326
+ // / adjust.
2327
+ static AccessLevel
2328
+ getAdjustedFormalAccess (const ValueDecl *VD, const DeclContext *useDC,
2329
+ bool treatUsableFromInlineAsPublic) {
2330
+ return getAdjustedFormalAccess (VD, VD->getFormalAccess (), useDC,
2331
+ treatUsableFromInlineAsPublic);
2332
+ }
2333
+
2300
2334
AccessLevel ValueDecl::getEffectiveAccess () const {
2301
2335
auto effectiveAccess =
2302
- getFormalAccess ( /* useDC=*/ nullptr ,
2303
- /* treatUsableFromInlineAsPublic=*/ true );
2336
+ getAdjustedFormalAccess ( this , /* useDC=*/ nullptr ,
2337
+ /* treatUsableFromInlineAsPublic=*/ true );
2304
2338
2305
2339
// Handle @testable.
2306
2340
switch (effectiveAccess) {
@@ -2352,48 +2386,54 @@ AccessLevel ValueDecl::getEffectiveAccess() const {
2352
2386
return effectiveAccess;
2353
2387
}
2354
2388
2355
- AccessLevel ValueDecl::getFormalAccess (const DeclContext *useDC,
2356
- bool treatUsableFromInlineAsPublic) const {
2389
+ AccessLevel ValueDecl::getFormalAccess () const {
2357
2390
ASTContext &ctx = getASTContext ();
2358
- AccessLevel result = ctx.evaluator (AccessLevelRequest{const_cast <ValueDecl *>(this )});
2359
- if (treatUsableFromInlineAsPublic &&
2360
- result == AccessLevel::Internal &&
2361
- isUsableFromInline ()) {
2362
- return AccessLevel::Public;
2363
- }
2364
- if (useDC && (result == AccessLevel::Internal ||
2365
- result == AccessLevel::Public)) {
2366
- if (auto *useSF = dyn_cast<SourceFile>(useDC->getModuleScopeContext ()))
2367
- if (useSF->hasTestableImport (getModuleContext ()))
2368
- return getTestableAccess (this );
2369
- }
2370
- return result;
2391
+ return ctx.evaluator (AccessLevelRequest{const_cast <ValueDecl *>(this )});
2371
2392
}
2372
2393
2373
- AccessScope
2374
- ValueDecl::getFormalAccessScope (const DeclContext *useDC,
2375
- bool treatUsableFromInlineAsPublic) const {
2376
- const DeclContext *result = getDeclContext ();
2377
- AccessLevel access = getFormalAccess (useDC, treatUsableFromInlineAsPublic);
2394
+ bool ValueDecl::hasOpenAccess (const DeclContext *useDC) const {
2395
+ assert (isa<ClassDecl>(this ) || isa<ConstructorDecl>(this ) ||
2396
+ isPotentiallyOverridable ());
2378
2397
2379
- while (!result->isModuleScopeContext ()) {
2380
- if (result->isLocalContext () || access == AccessLevel::Private)
2381
- return AccessScope (result, true );
2398
+ AccessLevel access =
2399
+ getAdjustedFormalAccess (this , useDC,
2400
+ /* treatUsableFromInlineAsPublic*/ false );
2401
+ return access == AccessLevel::Open;
2402
+ }
2382
2403
2383
- if (auto enclosingNominal = dyn_cast<NominalTypeDecl>(result)) {
2404
+ // / Given the formal access level for using \p VD, compute the scope where
2405
+ // / \p VD may be accessed, taking \@usableFromInline, \@testable imports,
2406
+ // / and enclosing access levels into account.
2407
+ // /
2408
+ // / \p access isn't always just `VD->getFormalAccess()` because this adjustment
2409
+ // / may be for a write, in which case the setter's access might be used instead.
2410
+ static AccessScope
2411
+ getAccessScopeForFormalAccess (const ValueDecl *VD,
2412
+ AccessLevel formalAccess,
2413
+ const DeclContext *useDC,
2414
+ bool treatUsableFromInlineAsPublic) {
2415
+ AccessLevel access = getAdjustedFormalAccess (VD, formalAccess, useDC,
2416
+ treatUsableFromInlineAsPublic);
2417
+ const DeclContext *resultDC = VD->getDeclContext ();
2418
+
2419
+ while (!resultDC->isModuleScopeContext ()) {
2420
+ if (resultDC->isLocalContext () || access == AccessLevel::Private)
2421
+ return AccessScope (resultDC, /* private*/ true );
2422
+
2423
+ if (auto enclosingNominal = dyn_cast<NominalTypeDecl>(resultDC)) {
2384
2424
auto enclosingAccess =
2385
- enclosingNominal-> getFormalAccess ( useDC,
2386
- treatUsableFromInlineAsPublic);
2425
+ getAdjustedFormalAccess (enclosingNominal, useDC,
2426
+ treatUsableFromInlineAsPublic);
2387
2427
access = std::min (access, enclosingAccess);
2388
2428
2389
- } else if (auto enclosingExt = dyn_cast<ExtensionDecl>(result )) {
2429
+ } else if (auto enclosingExt = dyn_cast<ExtensionDecl>(resultDC )) {
2390
2430
// Just check the base type. If it's a constrained extension, Sema should
2391
2431
// have already enforced access more strictly.
2392
2432
if (auto extendedTy = enclosingExt->getExtendedType ()) {
2393
2433
if (auto nominal = extendedTy->getAnyNominal ()) {
2394
2434
auto nominalAccess =
2395
- nominal-> getFormalAccess ( useDC,
2396
- treatUsableFromInlineAsPublic);
2435
+ getAdjustedFormalAccess (nominal, useDC,
2436
+ treatUsableFromInlineAsPublic);
2397
2437
access = std::min (access, nominalAccess);
2398
2438
}
2399
2439
}
@@ -2402,16 +2442,16 @@ ValueDecl::getFormalAccessScope(const DeclContext *useDC,
2402
2442
llvm_unreachable (" unknown DeclContext kind" );
2403
2443
}
2404
2444
2405
- result = result ->getParent ();
2445
+ resultDC = resultDC ->getParent ();
2406
2446
}
2407
2447
2408
2448
switch (access) {
2409
2449
case AccessLevel::Private:
2410
2450
case AccessLevel::FilePrivate:
2411
- assert (result ->isModuleScopeContext ());
2412
- return AccessScope (result , access == AccessLevel::Private);
2451
+ assert (resultDC ->isModuleScopeContext ());
2452
+ return AccessScope (resultDC , access == AccessLevel::Private);
2413
2453
case AccessLevel::Internal:
2414
- return AccessScope (result ->getParentModule ());
2454
+ return AccessScope (resultDC ->getParentModule ());
2415
2455
case AccessLevel::Public:
2416
2456
case AccessLevel::Open:
2417
2457
return AccessScope::getPublic ();
@@ -2420,6 +2460,128 @@ ValueDecl::getFormalAccessScope(const DeclContext *useDC,
2420
2460
llvm_unreachable (" unknown access level" );
2421
2461
}
2422
2462
2463
+ AccessScope
2464
+ ValueDecl::getFormalAccessScope (const DeclContext *useDC,
2465
+ bool treatUsableFromInlineAsPublic) const {
2466
+ return getAccessScopeForFormalAccess (this , getFormalAccess (), useDC,
2467
+ treatUsableFromInlineAsPublic);
2468
+ }
2469
+
2470
+ // / Checks if \p VD may be used from \p useDC, taking \@testable imports into
2471
+ // / account.
2472
+ // /
2473
+ // / Whenever the enclosing context of \p VD is usable from \p useDC, this
2474
+ // / should compute the same result as checkAccess, below, but more slowly.
2475
+ // /
2476
+ // / See ValueDecl::isAccessibleFrom for a description of \p forConformance.
2477
+ static bool checkAccessUsingAccessScopes (const DeclContext *useDC,
2478
+ const ValueDecl *VD,
2479
+ AccessLevel access) {
2480
+ AccessScope accessScope =
2481
+ getAccessScopeForFormalAccess (VD, access, useDC,
2482
+ /* treatUsableFromInlineAsPublic*/ false );
2483
+ return accessScope.getDeclContext () == useDC ||
2484
+ AccessScope (useDC).isChildOf (accessScope);
2485
+ }
2486
+
2487
+ // / Checks if \p VD may be used from \p useDC, taking \@testable imports into
2488
+ // / account.
2489
+ // /
2490
+ // / When \p access is the same as `VD->getFormalAccess()` and the enclosing
2491
+ // / context of \p VD is usable from \p useDC, this ought to be the same as
2492
+ // / getting the AccessScope for `VD` and checking if \p useDC is within it.
2493
+ // / However, there's a source compatibility hack around protocol extensions
2494
+ // / that makes it not quite the same.
2495
+ // /
2496
+ // / See ValueDecl::isAccessibleFrom for a description of \p forConformance.
2497
+ static bool checkAccess (const DeclContext *useDC, const ValueDecl *VD,
2498
+ AccessLevel access, bool forConformance) {
2499
+ auto *sourceDC = VD->getDeclContext ();
2500
+
2501
+ if (!forConformance) {
2502
+ if (auto *proto = sourceDC->getAsProtocolOrProtocolExtensionContext ()) {
2503
+ // FIXME: Swift 4.1 allowed accessing protocol extension methods that were
2504
+ // marked 'public' if the protocol was '@_versioned' (now
2505
+ // '@usableFromInline'). Which works at the ABI level, so let's keep
2506
+ // supporting that here by explicitly checking for it.
2507
+ if (access == AccessLevel::Public) {
2508
+ assert (proto->getDeclContext ()->isModuleScopeContext () &&
2509
+ " if we get nested protocols, this should not apply to them" );
2510
+ if (proto->getFormalAccess () == AccessLevel::Internal &&
2511
+ proto->isUsableFromInline ()) {
2512
+ return true ;
2513
+ }
2514
+ }
2515
+
2516
+ // Skip the fast path below and just compare access scopes.
2517
+ return checkAccessUsingAccessScopes (useDC, VD, access);
2518
+ }
2519
+ }
2520
+
2521
+ // Fast path: assume that the client context already has access to our parent
2522
+ // DeclContext, and only check what might be different about this declaration.
2523
+ if (!useDC)
2524
+ return access >= AccessLevel::Public;
2525
+
2526
+ switch (access) {
2527
+ case AccessLevel::Private:
2528
+ return (useDC == sourceDC ||
2529
+ AccessScope::allowsPrivateAccess (useDC, sourceDC));
2530
+ case AccessLevel::FilePrivate:
2531
+ return useDC->getModuleScopeContext () == sourceDC->getModuleScopeContext ();
2532
+ case AccessLevel::Internal: {
2533
+ const ModuleDecl *sourceModule = sourceDC->getParentModule ();
2534
+ const DeclContext *useFile = useDC->getModuleScopeContext ();
2535
+ if (useFile->getParentModule () == sourceModule)
2536
+ return true ;
2537
+ if (auto *useSF = dyn_cast<SourceFile>(useFile))
2538
+ if (useSF->hasTestableImport (sourceModule))
2539
+ return true ;
2540
+ return false ;
2541
+ }
2542
+ case AccessLevel::Public:
2543
+ case AccessLevel::Open:
2544
+ return true ;
2545
+ }
2546
+ llvm_unreachable (" bad access level" );
2547
+ }
2548
+
2549
+ bool ValueDecl::isAccessibleFrom (const DeclContext *useDC,
2550
+ bool forConformance) const {
2551
+ auto access = getFormalAccess ();
2552
+ bool result = checkAccess (useDC, this , access, forConformance);
2553
+
2554
+ // For everything outside of protocols and operators, we should get the same
2555
+ // result using either implementation of checkAccess, because useDC must
2556
+ // already have access to this declaration's DeclContext.
2557
+ // FIXME: Arguably, we're doing the wrong thing for operators here too,
2558
+ // because we're finding internal operators within private types. Fortunately
2559
+ // we have a requirement that a member operator take the enclosing type as an
2560
+ // argument, so it won't ever match.
2561
+ assert (getDeclContext ()->getAsProtocolOrProtocolExtensionContext () ||
2562
+ isOperator () ||
2563
+ result == checkAccessUsingAccessScopes (useDC, this , access));
2564
+
2565
+ return result;
2566
+ }
2567
+
2568
+ bool AbstractStorageDecl::isSetterAccessibleFrom (const DeclContext *DC,
2569
+ bool forConformance) const {
2570
+ assert (isSettable (DC));
2571
+
2572
+ // If a stored property does not have a setter, it is still settable from the
2573
+ // designated initializer constructor. In this case, don't check setter
2574
+ // access; it is not set.
2575
+ if (hasStorage () && !isSettable (nullptr ))
2576
+ return true ;
2577
+
2578
+ if (isa<ParamDecl>(this ))
2579
+ return true ;
2580
+
2581
+ auto access = getSetterFormalAccess ();
2582
+ return checkAccess (DC, this , access, forConformance);
2583
+ }
2584
+
2423
2585
void ValueDecl::copyFormalAccessFrom (const ValueDecl *source,
2424
2586
bool sourceIsParentContext) {
2425
2587
if (!hasAccess ()) {
0 commit comments