File tree Expand file tree Collapse file tree 4 files changed +91
-2
lines changed Expand file tree Collapse file tree 4 files changed +91
-2
lines changed Original file line number Diff line number Diff line change 14
14
15
15
extension Parser {
16
16
mutating func parseAttributeList( ) -> RawAttributeListSyntax ? {
17
- guard self . at ( . atSign) else {
17
+ guard self . at ( any : [ . atSign, . poundIfKeyword ] ) else {
18
18
return nil
19
19
}
20
20
@@ -23,13 +23,21 @@ extension Parser {
23
23
repeat {
24
24
let attribute = self . parseAttribute ( )
25
25
elements. append ( attribute)
26
- } while self . at ( . atSign) && loopProgress. evaluate ( currentToken)
26
+ } while self . at ( any : [ . atSign, . poundIfKeyword ] ) && loopProgress. evaluate ( currentToken)
27
27
return RawAttributeListSyntax ( elements: elements, arena: self . arena)
28
28
}
29
29
}
30
30
31
31
extension Parser {
32
32
mutating func parseAttribute( ) -> RawSyntax {
33
+ if self . at ( . poundIfKeyword) {
34
+ return RawSyntax ( self . parsePoundIfDirective { parser -> RawSyntax in
35
+ return parser. parseAttribute ( )
36
+ } syntax: { parser, attributes in
37
+ return RawSyntax ( RawAttributeListSyntax ( elements: attributes, arena: parser. arena) )
38
+ } )
39
+ }
40
+
33
41
guard let declAttr = DeclarationAttribute ( rawValue: self . peek ( ) . tokenText) else {
34
42
return RawSyntax ( self . parseCustomAttribute ( ) )
35
43
}
Original file line number Diff line number Diff line change @@ -47,6 +47,11 @@ extension TokenConsumer {
47
47
}
48
48
}
49
49
50
+ if subparser. at ( . poundIfKeyword) {
51
+ var attrLookahead = subparser. lookahead ( )
52
+ return attrLookahead. consumeIfConfigOfAttributes ( )
53
+ }
54
+
50
55
let declStartKeyword : DeclarationStart ?
51
56
if allowRecovery {
52
57
declStartKeyword = subparser. canRecoverTo (
Original file line number Diff line number Diff line change @@ -197,6 +197,44 @@ extension Parser.Lookahead {
197
197
}
198
198
return true
199
199
}
200
+
201
+ mutating func consumeIfConfigOfAttributes( ) -> Bool {
202
+ while true {
203
+ // #if / #else / #elseif
204
+ self . consumeAnyToken ( )
205
+
206
+ // <expression>
207
+ self . skipUntilEndOfLine ( )
208
+
209
+ while true {
210
+ if self . at ( . atSign) {
211
+ _ = self . consumeAttributeList ( )
212
+ continue
213
+ }
214
+
215
+ if self . at ( . poundIfKeyword) {
216
+ _ = self . consumeIfConfigOfAttributes ( )
217
+ continue
218
+ }
219
+
220
+ break
221
+ }
222
+
223
+ guard self . at ( any: [ . poundElseifKeyword, . poundElseKeyword ] ) else {
224
+ break
225
+ }
226
+ }
227
+
228
+ // If we ran out of tokens, say we consumed the rest.
229
+ if self . at ( . eof) {
230
+ return true
231
+ }
232
+
233
+ guard self . currentToken. isAtStartOfLine else {
234
+ return false
235
+ }
236
+ return self . consume ( if: . poundEndifKeyword) != nil
237
+ }
200
238
}
201
239
202
240
// MARK: Lookahead
Original file line number Diff line number Diff line change @@ -111,4 +111,42 @@ final class DirectiveTests: XCTestCase {
111
111
)
112
112
}
113
113
114
+ func testHasAttribute( ) {
115
+ AssertParse (
116
+ """
117
+ @frozen
118
+ #if hasAttribute(foo)
119
+ @foo
120
+ #endif
121
+ public struct S2 { }
122
+ """ )
123
+
124
+ AssertParse (
125
+ """
126
+ struct Inner {
127
+ @frozen
128
+ #if hasAttribute(foo)
129
+ #if hasAttribute(bar)
130
+ @foo @bar
131
+ #endif
132
+ #endif
133
+ public struct S2 { }
134
+
135
+ #if hasAttribute(foo)
136
+ @foo
137
+ #endif
138
+ @inlinable
139
+ func f1() { }
140
+
141
+ #if hasAttribute(foo)
142
+ @foo
143
+ #else
144
+ @available(*, deprecated, message: " nope " )
145
+ @frozen
146
+ #endif
147
+ public struct S3 { }
148
+ }
149
+ """ )
150
+ }
151
+
114
152
}
You can’t perform that action at this time.
0 commit comments