1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
|
# coding: utf8
# SPDX-License-Identifier: MIT OR LGPL-2.0-or-later
# SPDX-FileCopyrightText: 2020 Philip Chimento <philip.chimento@gmail.com>
# IWYU is missing the feature to designate a certain header as a "forward-decls
# header". In the case of SpiderMonkey, there are certain commonly used forward
# declarations that are all gathered in js/TypeDecls.h.
# We postprocess the IWYU output to fix this, and also fix the output format
# which is quite verbose, making it tedious to scroll through for 60 files.
import re
import sys
class Colors:
NORMAL = '\33[0m'
RED = '\33[31m'
GREEN = '\33[32m'
ADD, REMOVE, FULL = range(3)
state = None
file = None
add = {}
remove = {}
all_includes = {}
there_were_errors = False
# When encountering one of these lines, move to a different state
MATCHERS = {
r'\.\./(.*) should add these lines:': ADD,
r'\.\./(.*) should remove these lines:': REMOVE,
r'The full include-list for \.\./(.*):': FULL,
r'\(\.\./(.*) has correct #includes/fwd-decls\)': None
}
FWD_HEADER = '#include <js/TypeDecls.h>'
FWD_DECLS_IN_HEADER = (
'class JSAtom;',
'struct JSContext;',
'struct JSClass;',
'class JSFunction;',
'class JSObject;',
'struct JSRuntime;',
'class JSScript;',
'class JSString;',
'struct JSPrincipals;',
'namespace js { class TempAllocPolicy; }',
'namespace JS { class GCContext; }',
'namespace JS { class PropertyKey; }',
'namespace JS { class Symbol; }',
'namespace JS { class BigInt; }',
'namespace JS { class Value; }',
'namespace JS { class Compartment; }',
'namespace JS { class Realm; }',
'namespace JS { struct Runtime; }',
'namespace JS { class Zone; }',
)
add_fwd_header = False
CPP20_VERSION = '#include <version>'
CSTDDEF = '#include <cstddef>'
FALSE_POSITIVES = (
# The bodies of these structs already come before their usage,
# we don't need to have forward declarations of them as well
('gjs/atoms.h', 'class GjsAtoms;', ''),
('gjs/atoms.h', 'struct GjsSymbolAtom;', ''),
('gjs/mem-private.h', 'namespace Gjs { namespace Memory { struct Counter; } }', ''),
# https://github.com/include-what-you-use/include-what-you-use/issues/1685
# False positive when constructing JS::GCHashMap
('gi/object.h', '#include <utility>', 'for move'),
('gjs/jsapi-util-error.cpp', '#include <utility>', 'for forward, move'),
# False positive when using JS::WeakCache::put
('gi/fundamental.cpp', '#include <utility>', 'for forward'),
('gi/gtype.cpp', '#include <utility>', 'for forward'),
# Same underlying problem, false positive due to inlined methods from
# gi/info.h and gi/auto.h
('gi/interface.cpp', '#include <girepository/girepository.h>', 'for gi_base_info_ref'),
('gjs/byteArray.cpp', '#include <girepository/girepository.h>', 'for gi_base_info_get_name, gi_bas...'),
('modules/console.cpp', '#include <glib-object.h>', 'for g_object_unref'),
# For some reason IWYU wants these with angle brackets when they are
# already present with quotes
# https://github.com/include-what-you-use/include-what-you-use/issues/1087
('gjs/profiler.cpp', '#include <gjs/profiler.h>', ''),
# IWYU is not sure whether <utility> or <iterator> is for pair
# https://github.com/include-what-you-use/include-what-you-use/issues/1616
('gi/object.cpp', '#include <iterator>', 'for pair'),
('gi/toggle.h', '#include <iterator>', 'for pair'),
('test/gjs-test-utils.h', '#include <iterator>', 'for pair'),
('test/gjs-test-toggle-queue.cpp', '#include <iterator>', 'for pair'),
# https://github.com/include-what-you-use/include-what-you-use/issues/1808
('gi/value.h', 'class ObjectBox;', ''),
)
def output():
global file, state, add_fwd_header, there_were_errors
if add_fwd_header:
if FWD_HEADER not in all_includes:
if FWD_HEADER in remove:
remove.pop(FWD_HEADER, None)
else:
add[FWD_HEADER] = ''
# https://github.com/include-what-you-use/include-what-you-use/issues/1791
if add.pop(CPP20_VERSION, None) is not None and CSTDDEF not in all_includes:
if CSTDDEF in remove:
remove.pop(CSTDDEF, None)
else:
add[CSTDDEF] = 'for nullptr_t'
if add or remove:
print(f'\n== {file} ==')
for line, why in add.items():
if why:
why = ' // ' + why
print(f'{Colors.GREEN}+{line}{Colors.NORMAL}{why}')
for line, why in remove.items():
if why:
why = ' // ' + why
print(f'{Colors.RED}-{line}{Colors.NORMAL}{why}')
there_were_errors = True
add.clear()
remove.clear()
all_includes.clear()
add_fwd_header = False
for line in sys.stdin:
line = line.strip()
if not line:
continue
if 'fatal error:' in line:
print(line)
there_were_errors = True
continue
# filter out errors having to do with compiler arguments unknown to IWYU
if line.startswith('error:'):
continue
if line == '---':
output()
continue
state_changed = False
file_changed = False
for matcher, newstate in MATCHERS.items():
match = re.match(matcher, line)
if match:
state = newstate
if match.group(1) != file:
if file is not None:
file_changed = True
file = match.group(1)
state_changed = True
break
if file_changed:
output()
continue
if state_changed:
continue
line, _, why = line.partition(' // ')
line = line.strip()
if state == ADD:
if line in FWD_DECLS_IN_HEADER:
add_fwd_header = True
continue
if (file, line, why) in FALSE_POSITIVES:
continue
add[line] = why
elif state == REMOVE:
if line.startswith('- '):
line = line[2:]
remove[line] = why
elif state == FULL:
all_includes[line] = why
if there_were_errors:
sys.exit(1)
|