1# coding: utf8 2 3# IWYU is missing the feature to designate a certain header as a "forward-decls 4# header". In the case of SpiderMonkey, there are certain commonly used forward 5# declarations that are all gathered in js/TypeDecls.h. 6# We postprocess the IWYU output to fix this, and also fix the output format 7# which is quite verbose, making it tedious to scroll through for 60 files. 8 9import re 10import sys 11 12 13class Colors: 14 NORMAL = '\33[0m' 15 RED = '\33[31m' 16 GREEN = '\33[32m' 17 18 19ADD, REMOVE, FULL = range(3) 20state = None 21file = None 22add = {} 23remove = {} 24all_includes = {} 25there_were_errors = False 26 27# When encountering one of these lines, move to a different state 28MATCHERS = { 29 r'\.\./(.*) should add these lines:': ADD, 30 r'\.\./(.*) should remove these lines:': REMOVE, 31 r'The full include-list for \.\./(.*):': FULL, 32 r'\(\.\./(.*) has correct #includes/fwd-decls\)': None 33} 34 35FWD_HEADER = '#include <js/TypeDecls.h>' 36FWD_DECLS_IN_HEADER = ( 37 'class JSAtom;', 38 'struct JSContext;', 39 'struct JSClass;', 40 'class JSFunction;', 41 'class JSFreeOp;', 42 'class JSObject;', 43 'struct JSRuntime;', 44 'class JSScript;', 45 'class JSString;', 46 'namespace js { class TempAllocPolicy; }' 47 'namespace JS { struct PropertyKey; }', 48 'namespace JS { class Symbol; }', 49 'namespace JS { class BigInt; }', 50 'namespace JS { class Value; }', 51 'namespace JS { class Compartment; }', 52 'namespace JS { class Realm; }', 53 'namespace JS { struct Runtime; }', 54 'namespace JS { class Zone; }', 55) 56add_fwd_header = False 57 58FALSE_POSITIVES = ( 59 # The bodies of these structs already come before their usage, 60 # we don't need to have forward declarations of them as well 61 ('cjs/atoms.h', 'class GjsAtoms;', ''), 62 ('cjs/atoms.h', 'struct GjsSymbolAtom;', ''), 63 64 # IWYU weird false positive when using std::vector::emplace_back() or 65 # std::vector::push_back() 66 ('gi/private.cpp', '#include <algorithm>', 'for max'), 67 ('cjs/importer.cpp', '#include <algorithm>', 'for max'), 68 ('modules/cairo-context.cpp', '#include <algorithm>', 'for max'), 69 70 # Weird false positive on some versions of IWYU 71 ('gi/arg.cpp', 'struct _GHashTable;', ''), 72 ('gi/arg.cpp', 'struct _GVariant;', ''), 73) 74 75 76def output(): 77 global file, state, add_fwd_header, there_were_errors 78 79 if add_fwd_header: 80 if FWD_HEADER not in all_includes: 81 if FWD_HEADER in remove: 82 remove.pop(FWD_HEADER, None) 83 else: 84 add[FWD_HEADER] = '' 85 86 if add or remove: 87 print(f'\n== {file} ==') 88 for line, why in add.items(): 89 if why: 90 why = ' // ' + why 91 print(f'{Colors.GREEN}+{line}{Colors.NORMAL}{why}') 92 for line, why in remove.items(): 93 if why: 94 why = ' // ' + why 95 print(f'{Colors.RED}-{line}{Colors.NORMAL}{why}') 96 there_were_errors = True 97 98 state = None 99 file = None 100 add.clear() 101 remove.clear() 102 all_includes.clear() 103 add_fwd_header = False 104 105 106for line in sys.stdin: 107 line = line.strip() 108 if not line: 109 continue 110 111 # filter out errors having to do with compiler arguments unknown to IWYU 112 if line.startswith('error:'): 113 continue 114 115 if line == '---': 116 output() 117 continue 118 119 state_changed = False 120 file_changed = False 121 for matcher, newstate in MATCHERS.items(): 122 match = re.match(matcher, line) 123 if match: 124 state = newstate 125 if match.group(1) != file: 126 if file is not None: 127 file_changed = True 128 file = match.group(1) 129 state_changed = True 130 break 131 if file_changed: 132 output() 133 continue 134 if state_changed: 135 continue 136 137 line, _, why = line.partition(' // ') 138 line = line.strip() 139 if state == ADD: 140 if line in FWD_DECLS_IN_HEADER: 141 add_fwd_header = True 142 continue 143 if (file, line, why) in FALSE_POSITIVES: 144 continue 145 add[line] = why 146 elif state == REMOVE: 147 if line.startswith('- '): 148 line = line[2:] 149 remove[line] = why 150 elif state == FULL: 151 all_includes[line] = why 152 153if there_were_errors: 154 sys.exit(1) 155