@@ -27,25 +27,27 @@ EXCEPTIONAL_FILES = [
27
27
pathlib .Path ("test/IDE/complete_decl_attribute_feature_requirement.swift" ),
28
28
]
29
29
30
- FEATURE_USAGE_RE = re .compile (
31
- r"-enable-(?:experimental|upcoming)-feature (?:-Xfrontend )? ([A-Za-z0-9]*)"
30
+ ENABLE_FEATURE_RE = re .compile (
31
+ r"-enable-(?:experimental|upcoming)-feature(?:\s+ -Xfrontend)?\s* ([A-Za-z0-9]*)"
32
32
)
33
- # Be careful of not using REQUIRES or RUN with a colon after them or Lit will
34
- # pick them up.
35
33
FEATURE_LIT_MARKER_RE = re .compile (r"swift_feature_([A-Za-z0-9]*)" )
36
34
37
35
38
- def find_test_files_with_features_usage (swift_src_root ):
36
+ def find_test_files (swift_src_root ):
37
+ # Look for every test file in the test directories with `REQUIRES` lines
38
+ # that mention `swift_feature_`.
39
39
# Look for every test file in the test directories with `RUN` lines that
40
40
# mention `-enable-experimental-feature` or `-enable-upcoming-feature`.
41
- # Be careful of not using REQUIRES or RUN with a colon after them or Lit will
41
+ # Be careful to not use RUN or REQUIRES with a colon after them or Lit will
42
42
# pick them up.
43
43
output = subprocess .check_output (
44
44
[
45
45
"grep" ,
46
46
"--extended-regexp" ,
47
47
"--recursive" ,
48
48
"-e" ,
49
+ "REQUIRES[:].*swift_feature_" ,
50
+ "-e" ,
49
51
"RUN[:].*-enable-(experimental|upcoming)-feature" ,
50
52
"--files-with-matches" ,
51
53
str (swift_src_root / "test" ),
@@ -56,154 +58,83 @@ def find_test_files_with_features_usage(swift_src_root):
56
58
return output .splitlines ()
57
59
58
60
59
- def find_test_files_with_marker_usage (swift_src_root ):
60
- # Look for every test file in the test directories with `REQUIRES` lines
61
- # that mention `swift_feature_`.
62
- # Be careful of not using REQUIRES with a colon after them or Lit will
61
+ def find_run_and_requires_lines (test_file ):
62
+ # Be careful to not use RUN or REQUIRES with a colon after them or Lit will
63
63
# pick them up.
64
- output = subprocess .check_output (
65
- [
66
- "grep" ,
67
- "--extended-regexp" ,
68
- "--recursive" ,
69
- "-e" ,
70
- "REQUIRES[:].*swift_feature_" ,
71
- "--files-with-matches" ,
72
- str (swift_src_root / "test" ),
73
- str (swift_src_root / "validation-test" ),
74
- ],
75
- text = True ,
76
- )
77
- return output .splitlines ()
78
-
79
-
80
- def find_run_lines (test_file ):
81
64
output = subprocess .check_output (
82
65
[
83
66
"grep" ,
84
67
"--extended-regexp" ,
85
68
"--no-filename" ,
86
69
"-e" ,
87
70
"RUN[:]" ,
88
- str (test_file ),
89
- ],
90
- text = True ,
91
- )
92
- return output .splitlines ()
93
-
94
-
95
- def find_requires_lines (test_file ):
96
- output = subprocess .check_output (
97
- [
98
- "grep" ,
99
- "--extended-regexp" ,
100
- "--no-filename" ,
101
71
"-e" ,
102
72
"REQUIRES[:]" ,
103
- str ( test_file ) ,
73
+ test_file ,
104
74
],
105
75
text = True ,
106
76
)
107
77
return output .splitlines ()
108
78
109
79
110
- def check_existing_requires (test_file , feature ):
111
- returncode = subprocess .call (
112
- [
113
- "grep" ,
114
- "--extended-regexp" ,
115
- "--quiet" ,
116
- "-e" ,
117
- "REQUIRES[:].*swift_feature_" + feature ,
118
- str (test_file ),
119
- ]
120
- )
121
- return returncode != 0
80
+ def check_test_file (test_file , existing_swift_features ):
81
+ enabled_features = set ()
82
+ required_features = set ()
122
83
84
+ for line in find_run_and_requires_lines (test_file ):
85
+ enabled_features .update (feature for feature in ENABLE_FEATURE_RE .findall (line ))
86
+ required_features .update (
87
+ feature for feature in FEATURE_LIT_MARKER_RE .findall (line )
88
+ )
123
89
124
- def check_existing_feature_usage (test_file , feature ):
125
- returncode = subprocess .call (
126
- [
127
- "grep" ,
128
- "--extended-regexp" ,
129
- "--quiet" ,
130
- "-e" ,
131
- (
132
- "RUN[:].*-enable-(experimental|upcoming)-feature (-Xfrontend )?"
133
- + re .escape (feature )
134
- ),
135
- str (test_file ),
136
- ]
137
- )
138
- return returncode != 0
139
-
90
+ had_error = False
140
91
141
- def check_existing_error_message_checks (test_file , feature ):
142
- returncode = subprocess .call (
143
- [
144
- "grep" ,
145
- "--extended-regexp" ,
146
- "--quiet" ,
147
- "-e" ,
148
- "requires '-enable-(experimental|upcoming)-feature " + feature + "'" ,
149
- str (test_file ),
150
- ]
151
- )
152
- return returncode != 0
92
+ # First check for unknown features.
153
93
94
+ for feature in enabled_features .difference (existing_swift_features ):
95
+ enabled_features .remove (feature )
154
96
155
- def check_test_file_feature_usage (test_file , existing_swift_features ):
156
- run_lines = find_run_lines (test_file )
157
- features = set (
158
- feature for line in run_lines for feature in FEATURE_USAGE_RE .findall (line )
159
- )
160
- num_failures = 0
161
- for feature in features :
162
- # First, check this is a valid feature
163
- if feature not in existing_swift_features :
164
- print ("error: {}: Unknown feature: {}" .format (str (test_file ), feature ))
165
- num_failures += 1
166
- continue
167
-
168
- # No warning if the necessary `REQUIRES` is already there
169
- if not check_existing_requires (test_file , feature ):
170
- continue
97
+ # Be careful to not use RUN with a colon after it or Lit will pick
98
+ # it up.
99
+ print (
100
+ f"{ test_file } : error: unknown feature '{ feature } ' enabled in 'RUN"
101
+ + ":' line"
102
+ )
103
+ had_error = True
171
104
172
- # Some tests check for the errors themselves, so we can skip them as well
173
- if not check_existing_error_message_checks (test_file , feature ):
174
- continue
105
+ for feature in required_features .difference (existing_swift_features ):
106
+ required_features .remove (feature )
175
107
176
- # For everything else, print a warning and add to the invalid exit code
108
+ # Be careful to not use REQUIRES with a colon after it or Lit will pick
109
+ # it up.
177
110
print (
178
- "error: {}: Missing '{}: swift_feature_{}'" .format (
179
- str (test_file ), "REQUIRES" , feature
180
- )
111
+ f"{ test_file } : error: unknown feature '{ feature } ' in 'REQUIRES"
112
+ + f":' line: swift_feature_{ feature } "
181
113
)
182
- num_failures += 1
183
- return num_failures == 0
114
+ had_error = True
184
115
116
+ # If the sets are equal, we're fine.
117
+ if enabled_features == required_features :
118
+ return had_error
185
119
186
- def check_test_file_marker_usage (test_file ):
187
- require_lines = find_requires_lines (test_file )
188
- features = set (
189
- feature
190
- for line in require_lines
191
- for feature in FEATURE_LIT_MARKER_RE .findall (line )
192
- )
193
- num_failures = 0
194
- for feature in features :
195
- # No warning if -enable-experimental/upcoming-feature is there
196
- if not check_existing_feature_usage (test_file , feature ):
197
- continue
120
+ # Then check for imbalances between required and enabled features.
121
+
122
+ for feature in enabled_features .difference (required_features ):
123
+ # Be careful to not use REQUIRES with a colon after it or Lit will pick
124
+ # it up.
125
+ print (
126
+ f"{ test_file } : error: file enables '{ feature } ' but is missing '// REQUIRES"
127
+ + f": swift_feature_{ feature } '"
128
+ )
129
+ had_error = True
198
130
199
- # For everything else, print a warning and add to the invalid exit code
131
+ for feature in required_features . difference ( enabled_features ):
200
132
print (
201
- "error: {}: Missing '-enable-experimental/upcoming-feature: {}'" .format (
202
- str (test_file ), feature
203
- )
133
+ f"{ test_file } : error: file requires 'swift_feature_{ feature } ' but does not enable '{ feature } '"
204
134
)
205
- num_failures += 1
206
- return num_failures == 0
135
+ had_error = True
136
+
137
+ return had_error
207
138
208
139
209
140
def main ():
@@ -214,29 +145,17 @@ def main():
214
145
swift_src_root = pathlib .Path (sys .argv [1 ])
215
146
existing_swift_features = set (json .loads (sys .argv [2 ]))
216
147
217
- num_failures = 0
218
- test_files_with_features_usage = find_test_files_with_features_usage (swift_src_root )
219
- for test_file in test_files_with_features_usage :
220
- test_file = pathlib .Path (test_file )
221
- # First lets check this is not one of the exceptional files
222
- if test_file .relative_to (swift_src_root ) in EXCEPTIONAL_FILES :
223
- continue
224
-
225
- if not check_test_file_feature_usage (test_file , existing_swift_features ):
226
- num_failures += 1
227
-
228
- test_files_with_marker_usage = find_test_files_with_marker_usage (swift_src_root )
229
- for test_file in test_files_with_marker_usage :
230
- test_file = pathlib .Path (test_file )
148
+ had_error = False
231
149
232
- # First lets check this is not one of the exceptional files
233
- if test_file .relative_to (swift_src_root ) in EXCEPTIONAL_FILES :
150
+ for test_file in find_test_files (swift_src_root ):
151
+ # Skip if this is one of the exceptional files.
152
+ if pathlib .Path (test_file ).relative_to (swift_src_root ) in EXCEPTIONAL_FILES :
234
153
continue
235
154
236
- if not check_test_file_marker_usage (test_file ):
237
- num_failures += 1
155
+ if check_test_file (test_file , existing_swift_features ):
156
+ had_error = True
238
157
239
- if num_failures > 0 :
158
+ if had_error :
240
159
sys .exit (1 )
241
160
242
161
0 commit comments