1
1
import sys
2
2
import re
3
+ import argparse
3
4
4
5
"""
5
6
Pipe output from clang's -verify into this script to have the test case updated to expect the actual diagnostic output.
10
11
diffs. If inaccurate their count will be updated, or the check removed entirely.
11
12
12
13
Missing features:
13
- - custom prefix support (-verify=my-prefix)
14
14
- multiple prefixes on the same line (-verify=my-prefix,my-other-prefix)
15
15
- multiple prefixes on separate RUN lines (RUN: -verify=my-prefix\n RUN: -verify my-other-prefix)
16
16
- regexes with expected-*-re: existing ones will be left untouched if accurate, but the script will abort if there are any
@@ -27,16 +27,16 @@ class KnownException(Exception):
27
27
pass
28
28
29
29
30
- def parse_error_category (s ):
31
- if "no expected directives found" in line :
30
+ def parse_error_category (s , prefix ):
31
+ if "no expected directives found" in s :
32
32
return None
33
33
parts = s .split ("diagnostics" )
34
34
diag_category = parts [0 ]
35
35
category_parts = parts [0 ].strip ().strip ("'" ).split ("-" )
36
36
expected = category_parts [0 ]
37
- if expected != "expected" :
37
+ if expected != prefix :
38
38
raise Exception (
39
- f"expected 'expected ', but found '{ expected } '. Custom verify prefixes are not supported."
39
+ f"expected prefix ' { prefix } ', but found '{ expected } '. Multiple verify prefixes are not supported."
40
40
)
41
41
diag_category = category_parts [1 ]
42
42
if "seen but not expected" in parts [1 ]:
@@ -84,6 +84,7 @@ def render(self):
84
84
class Diag :
85
85
def __init__ (
86
86
self ,
87
+ prefix ,
87
88
diag_content ,
88
89
category ,
89
90
parsed_target_line_n ,
@@ -94,6 +95,7 @@ def __init__(
94
95
whitespace_strings ,
95
96
is_from_source_file ,
96
97
):
98
+ self .prefix = prefix
97
99
self .diag_content = diag_content
98
100
self .category = category
99
101
self .parsed_target_line_n = parsed_target_line_n
@@ -183,14 +185,14 @@ def render(self):
183
185
been parsed as whitespace3_s.
184
186
"""
185
187
whitespace2_s = ""
186
- return f"//{ whitespace1_s } expected -{ self .category } { re_s } { line_location_s } { whitespace2_s } { count_s } { whitespace3_s } {{{{{ self .diag_content } }}}}"
188
+ return f"//{ whitespace1_s } { self . prefix } -{ self .category } { re_s } { line_location_s } { whitespace2_s } { count_s } { whitespace3_s } {{{{{ self .diag_content } }}}}"
187
189
188
190
expected_diag_re = re .compile (
189
- r"//(\s*)expected -(note|warning|error)(-re)?(@[+-]?\d+)?(?:(\s*)(\d+))?(\s*)\{\{(.*)\}\}"
191
+ r"//(\s*)([a-zA-Z]+) -(note|warning|error)(-re)?(@[+-]?\d+)?(?:(\s*)(\d+))?(\s*)\{\{(.*)\}\}"
190
192
)
191
193
192
194
193
- def parse_diag (line , filename , lines ):
195
+ def parse_diag (line , filename , lines , prefix ):
194
196
s = line .content
195
197
ms = expected_diag_re .findall (s )
196
198
if not ms :
@@ -201,6 +203,7 @@ def parse_diag(line, filename, lines):
201
203
)
202
204
[
203
205
whitespace1_s ,
206
+ check_prefix ,
204
207
category_s ,
205
208
re_s ,
206
209
target_line_s ,
@@ -209,6 +212,8 @@ def parse_diag(line, filename, lines):
209
212
whitespace3_s ,
210
213
diag_s ,
211
214
] = ms [0 ]
215
+ if check_prefix != prefix :
216
+ return None
212
217
if not target_line_s :
213
218
target_line_n = 0
214
219
is_absolute = False
@@ -225,6 +230,7 @@ def parse_diag(line, filename, lines):
225
230
line .content = expected_diag_re .sub ("{{DIAG}}" , s )
226
231
227
232
return Diag (
233
+ prefix ,
228
234
diag_s ,
229
235
category_s ,
230
236
target_line_n ,
@@ -263,7 +269,7 @@ def get_indent(s):
263
269
def orig_line_n_to_new_line_n (line_n , orig_lines ):
264
270
return orig_lines [line_n - 1 ].line_n
265
271
266
- def add_diag (orig_line_n , diag_s , diag_category , lines , orig_lines ):
272
+ def add_diag (orig_line_n , diag_s , diag_category , lines , orig_lines , prefix ):
267
273
line_n = orig_line_n_to_new_line_n (orig_line_n , orig_lines )
268
274
target = lines [line_n - 1 ]
269
275
for other in target .targeting_diags :
@@ -301,7 +307,7 @@ def add_diag(orig_line_n, diag_s, diag_category, lines, orig_lines):
301
307
302
308
whitespace_strings = prev_line .diag .whitespace_strings if prev_line .diag else None
303
309
new_diag = Diag (
304
- diag_s , diag_category , total_offset , False , 1 , new_line , False , whitespace_strings , False ,
310
+ prefix , diag_s , diag_category , total_offset , False , 1 , new_line , False , whitespace_strings , False ,
305
311
)
306
312
new_line .diag = new_diag
307
313
new_diag .set_target (target )
@@ -328,16 +334,16 @@ def has_live_diags(lines):
328
334
return True
329
335
return False
330
336
331
- def get_expected_no_diags_line_n (lines ):
337
+ def get_expected_no_diags_line_n (lines , prefix ):
332
338
for line in lines :
333
- if "expected -no-diagnostics" in line .content :
339
+ if f" { prefix } -no-diagnostics" in line .content :
334
340
return line .line_n
335
341
return None
336
342
337
343
updated_test_files = set ()
338
344
339
345
340
- def update_test_file (filename , diag_errors ):
346
+ def update_test_file (filename , diag_errors , prefix ):
341
347
print (f"updating test file { filename } " )
342
348
if filename in updated_test_files :
343
349
print (
@@ -348,10 +354,10 @@ def update_test_file(filename, diag_errors):
348
354
with open (filename , "r" ) as f :
349
355
lines = [Line (line , i + 1 ) for i , line in enumerate (f .readlines ())]
350
356
orig_lines = list (lines )
351
- expected_no_diags_line_n = get_expected_no_diags_line_n (orig_lines )
357
+ expected_no_diags_line_n = get_expected_no_diags_line_n (orig_lines , prefix )
352
358
353
359
for line in lines :
354
- diag = parse_diag (line , filename , lines )
360
+ diag = parse_diag (line , filename , lines , prefix )
355
361
if diag :
356
362
line .diag = diag
357
363
diag .set_target (lines [diag .absolute_target () - 1 ])
@@ -385,7 +391,7 @@ def update_test_file(filename, diag_errors):
385
391
if other_diag :
386
392
other_diag .increment_count ()
387
393
else :
388
- add_diag (line_n , diag_s , diag_category , lines , orig_lines )
394
+ add_diag (line_n , diag_s , diag_category , lines , orig_lines , prefix )
389
395
remove_dead_diags (lines )
390
396
has_diags = has_live_diags (lines )
391
397
with open (filename , "w" ) as f :
@@ -397,71 +403,80 @@ def update_test_file(filename, diag_errors):
397
403
f .write (line .render ())
398
404
399
405
400
- def update_test_files (errors ):
406
+ def update_test_files (errors , prefix ):
401
407
errors_by_file = {}
402
408
for (filename , line , diag_s ), (diag_category , seen ) in errors :
403
409
if filename not in errors_by_file :
404
410
errors_by_file [filename ] = []
405
411
errors_by_file [filename ].append ((line , diag_s , diag_category , seen ))
406
412
for filename , diag_errors in errors_by_file .items ():
407
413
try :
408
- update_test_file (filename , diag_errors )
414
+ update_test_file (filename , diag_errors , prefix )
409
415
except KnownException as e :
410
416
print (f"{ filename } - ERROR: { e } " )
411
417
print ("continuing..." )
412
418
413
-
414
- curr = []
415
- curr_category = None
416
- curr_run_line = None
417
- lines_since_run = []
418
- skip_to_next_file = False
419
- for line in sys .stdin .readlines ():
420
- lines_since_run .append (line )
421
- try :
422
- if line .startswith ("RUN:" ):
423
- if curr :
424
- update_test_files (curr )
419
+ def check_expectations (tool_output , prefix ):
420
+ curr = []
421
+ curr_category = None
422
+ curr_run_line = None
423
+ lines_since_run = []
424
+ skip_to_next_file = False
425
+ for line in tool_output :
426
+ lines_since_run .append (line )
427
+ try :
428
+ if line .startswith ("RUN:" ):
429
+ if curr :
430
+ update_test_files (curr , prefix )
431
+ curr = []
432
+ lines_since_run = [line ]
433
+ curr_run_line = line
434
+ else :
435
+ for line in lines_since_run :
436
+ print (line , end = "" )
437
+ print ("====================" )
438
+ if lines_since_run :
439
+ print ("no mismatching diagnostics found since last RUN line" )
440
+ skip_to_next_file = False
441
+ continue
442
+ if skip_to_next_file :
443
+ continue
444
+ if line .startswith ("error: " ):
445
+ curr_category = parse_error_category (line [len ("error: " ) :], prefix )
446
+ continue
447
+
448
+ diag_error = parse_diag_error (line .strip ())
449
+ if diag_error :
450
+ curr .append ((diag_error , curr_category ))
451
+ except KnownException as e :
452
+ print (f"Error while parsing: { e } " )
453
+ if curr :
454
+ print ("skipping to next file" )
425
455
curr = []
426
- lines_since_run = [line ]
427
- curr_run_line = line
428
- else :
429
- for line in lines_since_run :
430
- print (line , end = "" )
431
- print ("====================" )
432
- if lines_since_run :
433
- print ("no mismatching diagnostics found since last RUN line" )
434
- skip_to_next_file = False
435
- continue
436
- if skip_to_next_file :
437
- continue
438
- if line .startswith ("error: " ):
439
- curr_category = parse_error_category (line [len ("error: " ) :])
440
- continue
441
-
442
- diag_error = parse_diag_error (line .strip ())
443
- if diag_error :
444
- curr .append ((diag_error , curr_category ))
445
- except KnownException as e :
446
- print (f"Error while parsing: { e } " )
447
- if curr :
448
- print ("skipping to next file" )
449
- curr = []
450
- curr_category = None
451
- curr_run_line = None
452
- lines_since_run = []
453
- skip_to_next_file = True
454
- except Exception as e :
456
+ curr_category = None
457
+ curr_run_line = None
458
+ lines_since_run = []
459
+ skip_to_next_file = True
460
+ except Exception as e :
461
+ for line in lines_since_run :
462
+ print (line , end = "" )
463
+ print ("====================" )
464
+ print (e )
465
+ sys .exit (1 )
466
+ if curr :
467
+ update_test_files (curr , prefix )
468
+ print ("done!" )
469
+ else :
455
470
for line in lines_since_run :
456
471
print (line , end = "" )
457
472
print ("====================" )
458
- print ( e )
459
- sys . exit ( 1 )
460
- if curr :
461
- update_test_files ( curr )
462
- print ( "done! " )
463
- else :
464
- for line in lines_since_run :
465
- print ( line , end = "" )
466
- print ( "====================" )
467
- print ( "no mismatching diagnostics found" )
473
+ print ( "no mismatching diagnostics found" )
474
+
475
+ def main () :
476
+ parser = argparse . ArgumentParser ( description = __doc__ )
477
+ parser . add_argument ( "--prefix" , default = "expected" , help = "The prefix passed to -verify " )
478
+ args = parser . parse_args ()
479
+ check_expectations ( sys . stdin . readlines (), args . prefix )
480
+
481
+ if __name__ == "__main__" :
482
+ main ( )
0 commit comments