11import sys
22import re
3+ import argparse
34
45"""
56 Pipe output from clang's -verify into this script to have the test case updated to expect the actual diagnostic output.
1011 diffs. If inaccurate their count will be updated, or the check removed entirely.
1112
1213 Missing features:
13- - custom prefix support (-verify=my-prefix)
1414 - multiple prefixes on the same line (-verify=my-prefix,my-other-prefix)
1515 - multiple prefixes on separate RUN lines (RUN: -verify=my-prefix\n RUN: -verify my-other-prefix)
1616 - 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):
2727 pass
2828
2929
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 :
3232 return None
3333 parts = s .split ("diagnostics" )
3434 diag_category = parts [0 ]
3535 category_parts = parts [0 ].strip ().strip ("'" ).split ("-" )
3636 expected = category_parts [0 ]
37- if expected != "expected" :
37+ if expected != prefix :
3838 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."
4040 )
4141 diag_category = category_parts [1 ]
4242 if "seen but not expected" in parts [1 ]:
@@ -84,6 +84,7 @@ def render(self):
8484class Diag :
8585 def __init__ (
8686 self ,
87+ prefix ,
8788 diag_content ,
8889 category ,
8990 parsed_target_line_n ,
@@ -94,6 +95,7 @@ def __init__(
9495 whitespace_strings ,
9596 is_from_source_file ,
9697 ):
98+ self .prefix = prefix
9799 self .diag_content = diag_content
98100 self .category = category
99101 self .parsed_target_line_n = parsed_target_line_n
@@ -183,14 +185,14 @@ def render(self):
183185 been parsed as whitespace3_s.
184186 """
185187 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 } }}}}"
187189
188190expected_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*)\{\{(.*)\}\}"
190192)
191193
192194
193- def parse_diag (line , filename , lines ):
195+ def parse_diag (line , filename , lines , prefix ):
194196 s = line .content
195197 ms = expected_diag_re .findall (s )
196198 if not ms :
@@ -201,6 +203,7 @@ def parse_diag(line, filename, lines):
201203 )
202204 [
203205 whitespace1_s ,
206+ check_prefix ,
204207 category_s ,
205208 re_s ,
206209 target_line_s ,
@@ -209,6 +212,8 @@ def parse_diag(line, filename, lines):
209212 whitespace3_s ,
210213 diag_s ,
211214 ] = ms [0 ]
215+ if check_prefix != prefix :
216+ return None
212217 if not target_line_s :
213218 target_line_n = 0
214219 is_absolute = False
@@ -225,6 +230,7 @@ def parse_diag(line, filename, lines):
225230 line .content = expected_diag_re .sub ("{{DIAG}}" , s )
226231
227232 return Diag (
233+ prefix ,
228234 diag_s ,
229235 category_s ,
230236 target_line_n ,
@@ -263,7 +269,7 @@ def get_indent(s):
263269def orig_line_n_to_new_line_n (line_n , orig_lines ):
264270 return orig_lines [line_n - 1 ].line_n
265271
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 ):
267273 line_n = orig_line_n_to_new_line_n (orig_line_n , orig_lines )
268274 target = lines [line_n - 1 ]
269275 for other in target .targeting_diags :
@@ -301,7 +307,7 @@ def add_diag(orig_line_n, diag_s, diag_category, lines, orig_lines):
301307
302308 whitespace_strings = prev_line .diag .whitespace_strings if prev_line .diag else None
303309 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 ,
305311 )
306312 new_line .diag = new_diag
307313 new_diag .set_target (target )
@@ -328,16 +334,16 @@ def has_live_diags(lines):
328334 return True
329335 return False
330336
331- def get_expected_no_diags_line_n (lines ):
337+ def get_expected_no_diags_line_n (lines , prefix ):
332338 for line in lines :
333- if "expected -no-diagnostics" in line .content :
339+ if f" { prefix } -no-diagnostics" in line .content :
334340 return line .line_n
335341 return None
336342
337343updated_test_files = set ()
338344
339345
340- def update_test_file (filename , diag_errors ):
346+ def update_test_file (filename , diag_errors , prefix ):
341347 print (f"updating test file { filename } " )
342348 if filename in updated_test_files :
343349 print (
@@ -348,10 +354,10 @@ def update_test_file(filename, diag_errors):
348354 with open (filename , "r" ) as f :
349355 lines = [Line (line , i + 1 ) for i , line in enumerate (f .readlines ())]
350356 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 )
352358
353359 for line in lines :
354- diag = parse_diag (line , filename , lines )
360+ diag = parse_diag (line , filename , lines , prefix )
355361 if diag :
356362 line .diag = diag
357363 diag .set_target (lines [diag .absolute_target () - 1 ])
@@ -385,7 +391,7 @@ def update_test_file(filename, diag_errors):
385391 if other_diag :
386392 other_diag .increment_count ()
387393 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 )
389395 remove_dead_diags (lines )
390396 has_diags = has_live_diags (lines )
391397 with open (filename , "w" ) as f :
@@ -397,71 +403,80 @@ def update_test_file(filename, diag_errors):
397403 f .write (line .render ())
398404
399405
400- def update_test_files (errors ):
406+ def update_test_files (errors , prefix ):
401407 errors_by_file = {}
402408 for (filename , line , diag_s ), (diag_category , seen ) in errors :
403409 if filename not in errors_by_file :
404410 errors_by_file [filename ] = []
405411 errors_by_file [filename ].append ((line , diag_s , diag_category , seen ))
406412 for filename , diag_errors in errors_by_file .items ():
407413 try :
408- update_test_file (filename , diag_errors )
414+ update_test_file (filename , diag_errors , prefix )
409415 except KnownException as e :
410416 print (f"{ filename } - ERROR: { e } " )
411417 print ("continuing..." )
412418
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" )
425455 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 :
455470 for line in lines_since_run :
456471 print (line , end = "" )
457472 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