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