xref: /llvm-project/libcxx/utils/generate_iwyu_mapping.py (revision c847b8e24cfdc85316b17f173019f9de1b1050ea)
1#!/usr/bin/env python
2
3import os, pathlib, sys
4
5def generate(private, public):
6    return f'{{ include: [ "{private}", "private", "<{public}>", "public" ] }}'
7
8
9def panic(file):
10    print(f'========== {__file__} error ==========', file=sys.stderr)
11    print(f'\tFile \'{file}\' is a top-level detail header without a mapping', file=sys.stderr)
12    sys.exit(1)
13
14
15def generate_map(include):
16    detail_files = []
17    detail_directories = []
18    c_headers = []
19
20    for i in include.iterdir():
21        if i.is_dir() and i.name.startswith('__'):
22            detail_directories.append(f'{i.name}')
23            continue
24
25        if i.name.startswith('__'):
26            detail_files.append(i.name)
27            continue
28
29        if i.name.endswith('.h'):
30            c_headers.append(i.name)
31
32    result = []
33    temporary_mappings = {'__locale_dir' : 'locale'}
34    for i in detail_directories:
35        public_header = temporary_mappings.get(i, i.lstrip('_'))
36        result.append(f'{generate(f"@<{i}/.*>", public_header)},')
37
38    for i in detail_files:
39        public = []
40        if   i == '__assert': continue
41        elif i == '__availability': continue
42        elif i == '__bit_reference': continue
43        elif i == '__bits': public = ['bits']
44        elif i == '__config_site.in': continue
45        elif i == '__config': continue
46        elif i == '__debug': continue
47        elif i == '__errc': continue
48        elif i == '__hash_table': public = ['unordered_map', 'unordered_set']
49        elif i == '__locale': public = ['locale']
50        elif i == '__mbstate_t.h': continue
51        elif i == '__mutex_base': continue
52        elif i == '__node_handle': public = ['map', 'set', 'unordered_map', 'unordered_set']
53        elif i == '__split_buffer': public = ['deque', 'vector']
54        elif i == '__threading_support': public = ['atomic', 'mutex', 'semaphore', 'thread']
55        elif i == '__tree': public = ['map', 'set']
56        elif i == '__undef_macros': continue
57        elif i == '__verbose_abort': continue
58        else: panic()
59
60        for p in public:
61            result.append(f'{generate(f"<{i}>", p)},')
62
63    result.sort()
64    return result
65
66def main():
67    monorepo_root = pathlib.Path(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
68    assert(monorepo_root.exists())
69    include = pathlib.Path(os.path.join(monorepo_root, 'libcxx', 'include'))
70
71    mapping = generate_map(include)
72    data = '[\n  ' + '\n  '.join(mapping) + '\n]\n'
73    with open(f'{include}/libcxx.imp', 'w') as f:
74        f.write(data)
75
76
77if __name__ == '__main__':
78    main()
79