2
2
//
3
3
// This source file is part of the Swift.org open source project
4
4
//
5
- // Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
5
+ // Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors
6
6
// Licensed under Apache License v2.0 with Runtime Library Exception
7
7
//
8
8
// See https://swift.org/LICENSE.txt for license information
@@ -13,231 +13,6 @@ import SwiftDiagnostics
13
13
import SwiftOperators
14
14
import SwiftSyntax
15
15
16
- enum IfConfigError : Error , CustomStringConvertible {
17
- case unknownExpression( ExprSyntax )
18
- case unhandledFunction( name: String , syntax: ExprSyntax )
19
- case requiresUnlabeledArgument( name: String , role: String , syntax: ExprSyntax )
20
- case unsupportedVersionOperator( name: String , operator: TokenSyntax )
21
- case invalidVersionOperand( name: String , syntax: ExprSyntax )
22
- case emptyVersionComponent( syntax: ExprSyntax )
23
- case compilerVersionOutOfRange( value: Int , upperLimit: Int , syntax: ExprSyntax )
24
- case compilerVersionSecondComponentNotWildcard( syntax: ExprSyntax )
25
- case compilerVersionTooManyComponents( syntax: ExprSyntax )
26
- case canImportMissingModule( syntax: ExprSyntax )
27
- case canImportLabel( syntax: ExprSyntax )
28
- case canImportTwoParameters( syntax: ExprSyntax )
29
- case ignoredTrailingComponents( version: VersionTuple , syntax: ExprSyntax )
30
- case integerLiteralCondition( syntax: ExprSyntax , replacement: Bool )
31
-
32
- var description : String {
33
- switch self {
34
- case . unknownExpression:
35
- return " invalid conditional compilation expression "
36
-
37
- case . unhandledFunction( name: let name, syntax: _) :
38
- return " build configuration cannot handle ' \( name) ' "
39
-
40
- case . requiresUnlabeledArgument( name: let name, role: let role, syntax: _) :
41
- return " \( name) requires a single unlabeled argument for the \( role) "
42
-
43
- case . unsupportedVersionOperator( name: let name, operator: let op) :
44
- return " ' \( name) ' version check does not support operator ' \( op. trimmedDescription) ' "
45
-
46
- case . invalidVersionOperand( name: let name, syntax: let version) :
47
- return " ' \( name) ' version check has invalid version ' \( version. trimmedDescription) ' "
48
-
49
- case . emptyVersionComponent( syntax: _) :
50
- return " found empty version component "
51
-
52
- case . compilerVersionOutOfRange( value: _, upperLimit: let upperLimit, syntax: _) :
53
- // FIXME: This matches the C++ implementation, but it would be more useful to
54
- // provide the actual value as-written and avoid the mathy [0, N] syntax.
55
- return " compiler version component out of range: must be in [0, \( upperLimit) ] "
56
-
57
- case . compilerVersionSecondComponentNotWildcard( syntax: _) :
58
- return " the second version component is not used for comparison in legacy compiler versions "
59
-
60
- case . compilerVersionTooManyComponents( syntax: _) :
61
- return " compiler version must not have more than five components "
62
-
63
- case . canImportMissingModule( syntax: _) :
64
- return " canImport requires a module name "
65
-
66
- case . canImportLabel( syntax: _) :
67
- return " 2nd parameter of canImport should be labeled as _version or _underlyingVersion "
68
-
69
- case . canImportTwoParameters( syntax: _) :
70
- return " canImport can take only two parameters "
71
-
72
- case . ignoredTrailingComponents( version: let version, syntax: _) :
73
- return " trailing components of version ' \( version. description) ' are ignored "
74
-
75
- case . integerLiteralCondition( syntax: let syntax, replacement: let replacement) :
76
- return " ' \( syntax. trimmedDescription) ' is not a valid conditional compilation expression, use ' \( replacement) ' "
77
- }
78
- }
79
-
80
- /// Retrieve the syntax node associated with this error.
81
- var syntax : Syntax {
82
- switch self {
83
- case . unknownExpression( let syntax) ,
84
- . unhandledFunction( name: _, syntax: let syntax) ,
85
- . requiresUnlabeledArgument( name: _, role: _, syntax: let syntax) ,
86
- . invalidVersionOperand( name: _, syntax: let syntax) ,
87
- . emptyVersionComponent( syntax: let syntax) ,
88
- . compilerVersionOutOfRange( value: _, upperLimit: _, syntax: let syntax) ,
89
- . compilerVersionTooManyComponents( syntax: let syntax) ,
90
- . compilerVersionSecondComponentNotWildcard( syntax: let syntax) ,
91
- . canImportMissingModule( syntax: let syntax) ,
92
- . canImportLabel( syntax: let syntax) ,
93
- . canImportTwoParameters( syntax: let syntax) ,
94
- . ignoredTrailingComponents( version: _, syntax: let syntax) ,
95
- . integerLiteralCondition( syntax: let syntax, replacement: _) :
96
- return Syntax ( syntax)
97
-
98
- case . unsupportedVersionOperator( name: _, operator: let op) :
99
- return Syntax ( op)
100
- }
101
- }
102
- }
103
-
104
- extension IfConfigError : DiagnosticMessage {
105
- var message : String { description }
106
-
107
- var diagnosticID : MessageID {
108
- . init( domain: " SwiftIfConfig " , id: " IfConfigError " )
109
- }
110
-
111
- var severity : SwiftDiagnostics . DiagnosticSeverity {
112
- switch self {
113
- case . ignoredTrailingComponents: return . warning
114
- default : return . error
115
- }
116
- }
117
-
118
- private struct SimpleFixItMessage : FixItMessage {
119
- var message : String
120
-
121
- var fixItID : MessageID {
122
- . init( domain: " SwiftIfConfig " , id: " IfConfigFixIt " )
123
- }
124
- }
125
-
126
- var asDiagnostic : Diagnostic {
127
- // For the integer literal condition we have a Fix-It.
128
- if case . integerLiteralCondition( let syntax, let replacement) = self {
129
- return Diagnostic (
130
- node: syntax,
131
- message: self ,
132
- fixIt: . replace(
133
- message: SimpleFixItMessage (
134
- message: " replace with Boolean literal ' \( replacement) ' "
135
- ) ,
136
- oldNode: syntax,
137
- newNode: BooleanLiteralExprSyntax (
138
- literal: . keyword( replacement ? . true : . false )
139
- )
140
- )
141
- )
142
- }
143
-
144
- return Diagnostic ( node: syntax, message: self )
145
- }
146
- }
147
-
148
- extension VersionTuple {
149
- /// Parse a compiler build version of the form "5007.*.1.2.3*", which is
150
- /// used by an older if configuration form `_compiler_version("...")`.
151
- /// - Parameters:
152
- /// - versionString: The version string for the compiler build version that
153
- /// we are parsing.
154
- /// - versionSyntax: The syntax node that contains the version string, used
155
- /// only for diagnostic purposes.
156
- fileprivate init (
157
- parsingCompilerBuildVersion versionString: String ,
158
- _ versionSyntax: ExprSyntax
159
- ) throws {
160
- components = [ ]
161
-
162
- // Version value are separated by periods.
163
- let componentStrings = versionString. split ( separator: " . " )
164
-
165
- /// Record a component after checking its value.
166
- func recordComponent( _ value: Int ) throws {
167
- let limit = components. isEmpty ? 9223371 : 999
168
- if value < 0 || value > limit {
169
- throw IfConfigError . compilerVersionOutOfRange ( value: value, upperLimit: limit, syntax: versionSyntax)
170
- }
171
-
172
- components. append ( value)
173
- }
174
-
175
- // Parse the components into version values.
176
- for (index, componentString) in componentStrings. enumerated ( ) {
177
- // Check ahead of time for empty version components
178
- if componentString. isEmpty {
179
- throw IfConfigError . emptyVersionComponent ( syntax: versionSyntax)
180
- }
181
-
182
- // The second component is always "*", and is never used for comparison.
183
- if index == 1 {
184
- if componentString != " * " {
185
- throw IfConfigError . compilerVersionSecondComponentNotWildcard ( syntax: versionSyntax)
186
- }
187
- try recordComponent ( 0 )
188
- continue
189
- }
190
-
191
- // Every other component must be an integer value.
192
- guard let component = Int ( componentString) else {
193
- throw IfConfigError . invalidVersionOperand ( name: " _compiler_version " , syntax: versionSyntax)
194
- }
195
-
196
- try recordComponent ( component)
197
- }
198
-
199
- // Only allowed to specify up to 5 version components.
200
- if components. count > 5 {
201
- throw IfConfigError . compilerVersionTooManyComponents ( syntax: versionSyntax)
202
- }
203
-
204
- // In the beginning, '_compiler_version(string-literal)' was designed for a
205
- // different version scheme where the major was fairly large and the minor
206
- // was ignored; now we use one where the minor is significant and major and
207
- // minor match the Swift language version. Specifically, majors 600-1300
208
- // were used for Swift 1.0-5.5 (based on clang versions), but then we reset
209
- // the numbering based on Swift versions, so 5.6 had major 5. We assume
210
- // that majors below 600 use the new scheme and equal/above it use the old
211
- // scheme.
212
- //
213
- // However, we want the string literal variant of '_compiler_version' to
214
- // maintain source compatibility with old checks; that means checks for new
215
- // versions have to be written so that old compilers will think they represent
216
- // newer versions, while new compilers have to interpret old version number
217
- // strings in a way that will compare correctly to the new versions compiled
218
- // into them.
219
- //
220
- // To achieve this, modern compilers divide the major by 1000 and overwrite
221
- // the wildcard component with the remainder, effectively shifting the last
222
- // three digits of the major into the minor, before comparing it to the
223
- // compiler version:
224
- //
225
- // _compiler_version("5007.*.1.2.3") -> 5.7.1.2.3
226
- // _compiler_version("1300.*.1.2.3") -> 1.300.1.2.3 (smaller than 5.6)
227
- // _compiler_version( "600.*.1.2.3") -> 0.600.1.2.3 (smaller than 5.6)
228
- //
229
- // So if you want to specify a 5.7.z.a.b version, we ask users to either
230
- // write it as 5007.*.z.a.b, or to use the new 'compiler(>= version)'
231
- // syntax instead, which does not perform this conversion.
232
- if !components. isEmpty {
233
- if components. count > 1 {
234
- components [ 1 ] = components [ 0 ] % 1000
235
- }
236
- components [ 0 ] = components [ 0 ] / 1000
237
- }
238
- }
239
- }
240
-
241
16
/// Evaluate the condition of an `#if`.
242
17
/// - Parameters:
243
18
/// - condition: The condition to evaluate, which we assume has already been
@@ -247,7 +22,8 @@ extension VersionTuple {
247
22
/// - diagnosticHandler: Receives any diagnostics that are produced by the
248
23
/// evaluation, whether from errors in the source code or produced by the
249
24
/// build configuration itself.
250
- /// - Throws: Throws if an error occurs occur during evaluation. The error will
25
+ /// - Throws: Throws if an error occurs occur during evaluation that prevents
26
+ /// this function from forming a valid result. The error will
251
27
/// also be provided to the diagnostic handler before doing so.
252
28
/// - Returns: A pair of Boolean values. The first describes whether the
253
29
/// condition holds with the given build configuration. The second whether
0 commit comments