Skip to content

Commit 889bc31

Browse files
committed
unittests: Add tests for AvailabilityContext.
1 parent cee7fea commit 889bc31

File tree

6 files changed

+146
-12
lines changed

6 files changed

+146
-12
lines changed

include/swift/AST/AvailabilityContext.h

+8-3
Original file line numberDiff line numberDiff line change
@@ -87,13 +87,18 @@ class AvailabilityContext {
8787
/// Constrain with another `AvailabilityContext`.
8888
void constrainWithContext(const AvailabilityContext &other, ASTContext &ctx);
8989

90-
/// Constrain with the availability attributes of `decl`.
91-
void constrainWithDecl(const Decl *decl);
92-
9390
/// Constrain the platform availability range with `platformRange`.
9491
void constrainWithPlatformRange(const AvailabilityRange &platformRange,
9592
ASTContext &ctx);
9693

94+
/// Constrain the context by adding \p domain to the set of unavailable
95+
/// domains.
96+
void constrainWithUnavailableDomain(AvailabilityDomain domain,
97+
ASTContext &ctx);
98+
99+
/// Constrain with the availability attributes of `decl`.
100+
void constrainWithDecl(const Decl *decl);
101+
97102
/// Constrain with the availability attributes of `decl`, intersecting the
98103
/// platform range of `decl` with `platformRange`.
99104
void

lib/AST/AvailabilityContext.cpp

+13-4
Original file line numberDiff line numberDiff line change
@@ -155,10 +155,6 @@ void AvailabilityContext::constrainWithContext(const AvailabilityContext &other,
155155
storage = Storage::get(info, ctx);
156156
}
157157

158-
void AvailabilityContext::constrainWithDecl(const Decl *decl) {
159-
constrainWithDeclAndPlatformRange(decl, AvailabilityRange::alwaysAvailable());
160-
}
161-
162158
void AvailabilityContext::constrainWithPlatformRange(
163159
const AvailabilityRange &platformRange, ASTContext &ctx) {
164160

@@ -169,6 +165,19 @@ void AvailabilityContext::constrainWithPlatformRange(
169165
storage = Storage::get(info, ctx);
170166
}
171167

168+
void AvailabilityContext::constrainWithUnavailableDomain(
169+
AvailabilityDomain domain, ASTContext &ctx) {
170+
Info info{storage->info};
171+
if (!info.constrainUnavailability(domain))
172+
return;
173+
174+
storage = Storage::get(info, ctx);
175+
}
176+
177+
void AvailabilityContext::constrainWithDecl(const Decl *decl) {
178+
constrainWithDeclAndPlatformRange(decl, AvailabilityRange::alwaysAvailable());
179+
}
180+
172181
void AvailabilityContext::constrainWithDeclAndPlatformRange(
173182
const Decl *decl, const AvailabilityRange &platformRange) {
174183
bool isConstrained = false;
+115
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
//===--- AvailabilityContextTests.cpp - Tests for AvailabilityContext -----===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2025 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#include "TestContext.h"
14+
#include "swift/AST/AvailabilityContext.h"
15+
#include "llvm/TargetParser/Triple.h"
16+
#include "gtest/gtest.h"
17+
18+
using namespace swift;
19+
using namespace swift::unittest;
20+
21+
static llvm::VersionTuple getPlatformIntro(const AvailabilityContext &context) {
22+
return context.getPlatformRange().getRawVersionRange().getLowerEndpoint();
23+
}
24+
25+
static AvailabilityRange getAvailabilityRange(unsigned major, unsigned minor) {
26+
return AvailabilityRange(
27+
VersionRange::allGTE(llvm::VersionTuple(major, minor)));
28+
}
29+
30+
class AvailabilityContextTest : public ::testing::Test {
31+
public:
32+
const TestContext defaultTestContext{
33+
DoNotDeclareOptionalTypes, llvm::Triple("x86_64", "apple", "macosx10.9")};
34+
35+
struct {
36+
const AvailabilityDomain universal = AvailabilityDomain::forUniversal();
37+
const AvailabilityDomain macOS =
38+
AvailabilityDomain::forPlatform(PlatformKind::macOS);
39+
const AvailabilityDomain macOSAppExt = AvailabilityDomain::forPlatform(
40+
PlatformKind::macOSApplicationExtension);
41+
} domains;
42+
};
43+
44+
TEST_F(AvailabilityContextTest, PlatformIntroduction) {
45+
auto &ctx = defaultTestContext.Ctx;
46+
47+
auto macOS10_9 = AvailabilityContext::forDeploymentTarget(ctx);
48+
EXPECT_EQ(getPlatformIntro(macOS10_9), llvm::VersionTuple(10, 9));
49+
50+
// Attempt to constrain the macOS version to >= 10.8. Since the context is
51+
// already >= 10.9, this should have no effect.
52+
auto macOS10_8 = macOS10_9;
53+
macOS10_8.constrainWithPlatformRange(getAvailabilityRange(10, 8), ctx);
54+
EXPECT_EQ(macOS10_8, macOS10_9);
55+
56+
// Attempt to constrain the macOS version to >= 10.9. Since the context is
57+
// already >= 10.9, this should have no effect.
58+
auto stillMacOS10_9 = macOS10_9;
59+
stillMacOS10_9.constrainWithPlatformRange(getAvailabilityRange(10, 9), ctx);
60+
EXPECT_EQ(stillMacOS10_9, macOS10_9);
61+
62+
// Constrain the the macOS version to >= 10.10 instead. The resulting context
63+
// should be a new context that is less available than the deployment target
64+
// context (a.k.a. "contained by").
65+
auto macOS10_10 = macOS10_9;
66+
macOS10_10.constrainWithPlatformRange(getAvailabilityRange(10, 10), ctx);
67+
EXPECT_EQ(getPlatformIntro(macOS10_10), llvm::VersionTuple(10, 10));
68+
EXPECT_NE(macOS10_9, macOS10_10);
69+
EXPECT_TRUE(macOS10_10.isContainedIn(macOS10_9));
70+
EXPECT_FALSE(macOS10_9.isContainedIn(macOS10_10));
71+
}
72+
73+
TEST_F(AvailabilityContextTest, UnavailableDomains) {
74+
auto &ctx = defaultTestContext.Ctx;
75+
76+
auto macOS10_9 = AvailabilityContext::forDeploymentTarget(ctx);
77+
EXPECT_FALSE(macOS10_9.isUnavailable());
78+
79+
// Constrain the deployment target context by adding unavailability on macOS.
80+
// The resulting context should be a new context that is less available than
81+
// the deployment target context (a.k.a. "contained by").
82+
auto unavailableOnMacOS = macOS10_9;
83+
unavailableOnMacOS.constrainWithUnavailableDomain(domains.macOS, ctx);
84+
EXPECT_TRUE(unavailableOnMacOS.isUnavailable());
85+
// FIXME: [availability] query unavailable domains
86+
EXPECT_NE(unavailableOnMacOS, macOS10_9);
87+
EXPECT_TRUE(unavailableOnMacOS.isContainedIn(macOS10_9));
88+
EXPECT_FALSE(macOS10_9.isContainedIn(unavailableOnMacOS));
89+
90+
// Constraining a context that is already unavailable on macOS by adding
91+
// unavailability on macOS should have no effect.
92+
auto stillUnavailableOnMacOS = unavailableOnMacOS;
93+
stillUnavailableOnMacOS.constrainWithUnavailableDomain(domains.macOS, ctx);
94+
EXPECT_EQ(unavailableOnMacOS, stillUnavailableOnMacOS);
95+
96+
// Constraining unavailability on macOS application extensions should also
97+
// have no effect.
98+
auto unavailableInAppExt = unavailableOnMacOS;
99+
unavailableInAppExt.constrainWithUnavailableDomain(domains.macOSAppExt, ctx);
100+
EXPECT_EQ(unavailableOnMacOS, unavailableInAppExt);
101+
102+
// FIXME: [availability] Test adding unavailability for an independent domain.
103+
104+
// Constraining the context to be universally unavailable should create a
105+
// new context that contains the context that was unavailable on macOS only.
106+
auto unavailableUniversally = unavailableOnMacOS;
107+
unavailableUniversally.constrainWithUnavailableDomain(domains.universal, ctx);
108+
EXPECT_TRUE(unavailableUniversally.isUnavailable());
109+
// FIXME: [availability] query unavailable domains
110+
EXPECT_NE(unavailableUniversally, unavailableOnMacOS);
111+
EXPECT_TRUE(unavailableUniversally.isContainedIn(unavailableOnMacOS));
112+
EXPECT_TRUE(unavailableUniversally.isContainedIn(macOS10_9));
113+
EXPECT_FALSE(unavailableOnMacOS.isContainedIn(unavailableUniversally));
114+
EXPECT_FALSE(macOS10_9.isContainedIn(unavailableUniversally));
115+
}

unittests/AST/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ add_swift_unittest(SwiftASTTests
22
ArithmeticEvaluator.cpp
33
ASTDumperTests.cpp
44
ASTWalkerTests.cpp
5+
AvailabilityContextTests.cpp
56
AvailabilityDomainTests.cpp
67
IndexSubsetTests.cpp
78
DiagnosticBehaviorTests.cpp

unittests/AST/TestContext.cpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,10 @@ static Decl *createOptionalType(ASTContext &ctx, SourceFile *fileForLookups,
3333
return decl;
3434
}
3535

36-
TestContext::TestContext(ShouldDeclareOptionalTypes optionals)
37-
: Ctx(*ASTContext::get(LangOpts, TypeCheckerOpts, SILOpts, SearchPathOpts,
36+
TestContext::TestContext(ShouldDeclareOptionalTypes optionals,
37+
llvm::Triple target)
38+
: TestContextBase(target),
39+
Ctx(*ASTContext::get(LangOpts, TypeCheckerOpts, SILOpts, SearchPathOpts,
3840
ClangImporterOpts, SymbolGraphOpts, CASOpts,
3941
SerializationOpts, SourceMgr, Diags)) {
4042
registerParseRequestFunctions(Ctx.evaluator);

unittests/AST/TestContext.h

+5-3
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ class TestContextBase {
4040
SourceManager SourceMgr;
4141
DiagnosticEngine Diags;
4242

43-
TestContextBase() : Diags(SourceMgr) {
44-
LangOpts.Target = llvm::Triple(llvm::sys::getProcessTriple());
43+
TestContextBase(llvm::Triple target) : Diags(SourceMgr) {
44+
LangOpts.Target = target;
4545
}
4646
};
4747

@@ -57,7 +57,9 @@ class TestContext : public TestContextBase {
5757
public:
5858
ASTContext &Ctx;
5959

60-
TestContext(ShouldDeclareOptionalTypes optionals = DoNotDeclareOptionalTypes);
60+
TestContext(
61+
ShouldDeclareOptionalTypes optionals = DoNotDeclareOptionalTypes,
62+
llvm::Triple target = llvm::Triple(llvm::sys::getProcessTriple()));
6163

6264
template <typename Nominal>
6365
typename std::enable_if<!std::is_same<Nominal, swift::ClassDecl>::value,

0 commit comments

Comments
 (0)