Skip to content

Commit e86702b

Browse files
committed
Fix expand-availability syntax not to interfere with doc comment parsing
This was our previous convention: /// Fiddle with the thing. /*System 0.0.2*/ public func foo() /// Fiddle with the thing. /*System 0.0.2, @available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *)*/ public func foo() /// Fiddle with the thing. /*System 0.0.2*/@available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) public func foo() Unfortunately, regular comments in between a declaration and its preceding doc comments interfere with documentation tools. Change things to the style below instead: /// Fiddle with the thing. @available(/*System 0.0.2*/macOS 10, *) public func foo() /// Fiddle with the thing. @available(/*SwiftSystem 0.0.2: macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0*/macOS 10, *) public func foo() /// Fiddle with the thing. @available(/*SwiftSystem 0.0.2*/macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) public func foo() Unfortunately, `@available(*)` isn’t valid syntax, so we have to add a dummy “macOS 10” version spec. It should have no actual effect.
1 parent f572e4b commit e86702b

File tree

1 file changed

+44
-15
lines changed

1 file changed

+44
-15
lines changed

Utilities/expand-availability.py

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,18 @@
66
# In order for this to work, ABI-impacting declarations need to be annotated
77
# with special comments in the following format:
88
#
9-
# /*System 0.0.2*/
9+
# @available(/*System 0.0.2*/iOS 8, *)
1010
# public func greeting() -> String {
1111
# "Hello"
1212
# }
1313
#
14+
# (The iOS 8 availability is a dummy no-op declaration -- it only has to be there because
15+
# `@available(*)` isn't valid syntax, and commenting out the entire `@available` attribute
16+
# would interfere with parser tools for doc comments. `iOS 8` is the shortest version string that
17+
# matches the minimum possible deployment target for Swift code, so we use that as our dummy
18+
# availability version. `@available(iOS 8, *)` is functionally equivalent to not having an
19+
# `@available` attribute at all.)
20+
#
1421
# The script adds full availability incantations to these comments. It can run
1522
# in one of two modes:
1623
#
@@ -19,16 +26,16 @@
1926
# availability across `SystemPackage` and the ABI-stable `System` module that
2027
# ships in Apple's OS releases:
2128
#
22-
# /*System 0.0.2, @available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *)*/
29+
# @available(/*System 0.0.2: macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0*/iOS 8, *)
2330
# public func greeting() -> String {
2431
# "Hello"
2532
# }
2633
#
27-
# `expand-availability.py --attributes` adds actual availability attributes.
34+
# `expand-availability.py --attributes` adds actual availability declarations.
2835
# This is used by maintainers to build ABI stable releases of System on Apple's
2936
# platforms:
3037
#
31-
# /*System 0.0.2*/@available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *)
38+
# @available(/*System 0.0.2: */macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *)
3239
# public func greeting() -> String {
3340
# "Hello"
3441
# }
@@ -65,22 +72,44 @@ def swift_sources_in(path):
6572
result.append(os.path.join(dir, file))
6673
return result
6774

68-
macro_pattern = re.compile(
75+
# Old-style syntax:
76+
# /*System 0.0.2*/
77+
# /*System 0.0.2, @available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *)*/
78+
# /*System 0.0.2*/@available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *)
79+
old_macro_pattern = re.compile(
6980
r"/\*(System [^ *]+)(, @available\([^)]*\))?\*/(@available\([^)]*\))?")
7081

82+
# New-style comments:
83+
# @available(/*SwiftSystem 0.0.2*/macOS 10, *)
84+
# @available(/*SwiftSystem 0.0.2: macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0*/iOS 8, *)
85+
# @available(/*SwiftSystem 0.0.2*/macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *)
86+
#
87+
# These do not interfere with our tools' ability to find doc comments.
88+
macro_pattern = re.compile(
89+
r"@available\(/\*(System [^ *:]+)[^*/)]*\*/([^)]*)\*\)")
90+
91+
def available_attribute(filename, lineno, symbolic_version):
92+
expansion = versions[symbolic_version]
93+
if expansion is None:
94+
raise ValueError("{0}:{1}: error: Unknown System version '{0}'"
95+
.format(fileinput.filename(), fileinput.lineno(), symbolic_version))
96+
if args.attributes:
97+
attribute = "@available(/*{0}*/{1}, *)".format(symbolic_version, expansion)
98+
else:
99+
# Sadly `@available(*)` is not valid syntax, so we have to mention at least one actual
100+
# platform here.
101+
attribute = "@available(/*{0}: {1}*/iOS 8, *)".format(symbolic_version, expansion)
102+
return attribute
103+
104+
71105
sources = swift_sources_in("Sources") + swift_sources_in("Tests")
72106
for line in fileinput.input(files=sources, inplace=True):
73107
match = re.search(macro_pattern, line)
108+
if match is None:
109+
match = re.search(old_macro_pattern, line)
74110
if match:
75-
system_version = match.group(1)
76-
expansion = versions[system_version]
77-
if expansion is None:
78-
raise ValueError("{0}:{1}: error: Unknown System version '{0}'"
79-
.format(fileinput.filename(), fileinput.lineno(),
80-
system_version))
81-
if args.attributes:
82-
replacement = "/*{0}*/@available({1}, *)".format(system_version, expansion)
83-
else:
84-
replacement = "/*{0}, @available({1}, *)*/".format(system_version, expansion)
111+
symbolic_version = match.group(1)
112+
replacement = available_attribute(
113+
fileinput.filename(), fileinput.lineno(), symbolic_version)
85114
line = line[:match.start()] + replacement + line[match.end():]
86115
print(line, end="")

0 commit comments

Comments
 (0)