@@ -27,25 +27,27 @@ EXCEPTIONAL_FILES = [
2727 pathlib .Path ("test/IDE/complete_decl_attribute_feature_requirement.swift" ),
2828]
2929
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]*)"
3232)
33- # Be careful of not using REQUIRES or RUN with a colon after them or Lit will
34- # pick them up.
3533FEATURE_LIT_MARKER_RE = re .compile (r"swift_feature_([A-Za-z0-9]*)" )
3634
3735
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_`.
3939 # Look for every test file in the test directories with `RUN` lines that
4040 # 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
4242 # pick them up.
4343 output = subprocess .check_output (
4444 [
4545 "grep" ,
4646 "--extended-regexp" ,
4747 "--recursive" ,
4848 "-e" ,
49+ "REQUIRES[:].*swift_feature_" ,
50+ "-e" ,
4951 "RUN[:].*-enable-(experimental|upcoming)-feature" ,
5052 "--files-with-matches" ,
5153 str (swift_src_root / "test" ),
@@ -56,154 +58,83 @@ def find_test_files_with_features_usage(swift_src_root):
5658 return output .splitlines ()
5759
5860
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
6363 # 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 ):
8164 output = subprocess .check_output (
8265 [
8366 "grep" ,
8467 "--extended-regexp" ,
8568 "--no-filename" ,
8669 "-e" ,
8770 "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" ,
10171 "-e" ,
10272 "REQUIRES[:]" ,
103- str ( test_file ) ,
73+ test_file ,
10474 ],
10575 text = True ,
10676 )
10777 return output .splitlines ()
10878
10979
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 ()
12283
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+ )
12389
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
14091
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.
15393
94+ for feature in enabled_features .difference (existing_swift_features ):
95+ enabled_features .remove (feature )
15496
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
171104
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 )
175107
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.
177110 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 } "
181113 )
182- num_failures += 1
183- return num_failures == 0
114+ had_error = True
184115
116+ # If the sets are equal, we're fine.
117+ if enabled_features == required_features :
118+ return had_error
185119
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
198130
199- # For everything else, print a warning and add to the invalid exit code
131+ for feature in required_features . difference ( enabled_features ):
200132 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 } '"
204134 )
205- num_failures += 1
206- return num_failures == 0
135+ had_error = True
136+
137+ return had_error
207138
208139
209140def main ():
@@ -214,29 +145,17 @@ def main():
214145 swift_src_root = pathlib .Path (sys .argv [1 ])
215146 existing_swift_features = set (json .loads (sys .argv [2 ]))
216147
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
231149
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 :
234153 continue
235154
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
238157
239- if num_failures > 0 :
158+ if had_error :
240159 sys .exit (1 )
241160
242161
0 commit comments