xref: /llvm-project/libcxx/utils/generate_iwyu_mapping.py (revision e78f53d1e8d622ee4b12dbc2ac8252b4805d5719)
1ab466480SChristopher Di Bella#!/usr/bin/env python
2ab466480SChristopher Di Bella
3e2754890SLouis Dionneimport argparse
4127c390fSLouis Dionneimport libcxx.header_information
5127c390fSLouis Dionneimport os
6127c390fSLouis Dionneimport pathlib
7127c390fSLouis Dionneimport re
8e2754890SLouis Dionneimport sys
9127c390fSLouis Dionneimport typing
10ab466480SChristopher Di Bella
11127c390fSLouis Dionnedef IWYU_mapping(header: str) -> typing.Optional[typing.List[str]]:
12127c390fSLouis Dionne    ignore = [
13*e78f53d1SNikolas Klauser        "__cxx03/.+",
14127c390fSLouis Dionne        "__debug_utils/.+",
15127c390fSLouis Dionne        "__fwd/get[.]h",
16a3ce29f7SLouis Dionne        "__pstl/.+",
17127c390fSLouis Dionne        "__support/.+",
180a131756SMark de Wever        "__utility/private_constructor_tag.h",
19127c390fSLouis Dionne    ]
20127c390fSLouis Dionne    if any(re.match(pattern, header) for pattern in ignore):
21127c390fSLouis Dionne        return None
22127c390fSLouis Dionne    elif header == "__bits":
23127c390fSLouis Dionne        return ["bits"]
24127c390fSLouis Dionne    elif header in ("__bit_reference", "__fwd/bit_reference.h"):
25127c390fSLouis Dionne        return ["bitset", "vector"]
2623e1ed65SLouis Dionne    elif re.match("__configuration/.+", header) or header == "__config":
2723e1ed65SLouis Dionne        return ["version"]
28127c390fSLouis Dionne    elif header == "__hash_table":
29127c390fSLouis Dionne        return ["unordered_map", "unordered_set"]
30127c390fSLouis Dionne    elif header == "__locale":
31127c390fSLouis Dionne        return ["locale"]
32127c390fSLouis Dionne    elif re.match("__locale_dir/.+", header):
33127c390fSLouis Dionne        return ["locale"]
34127c390fSLouis Dionne    elif re.match("__math/.+", header):
35127c390fSLouis Dionne        return ["cmath"]
36127c390fSLouis Dionne    elif header == "__node_handle":
37127c390fSLouis Dionne        return ["map", "set", "unordered_map", "unordered_set"]
38127c390fSLouis Dionne    elif header == "__split_buffer":
39127c390fSLouis Dionne        return ["deque", "vector"]
407162fd75SLouis Dionne    elif re.match("(__thread/support[.]h)|(__thread/support/.+)", header):
41127c390fSLouis Dionne        return ["atomic", "mutex", "semaphore", "thread"]
42127c390fSLouis Dionne    elif header == "__tree":
43127c390fSLouis Dionne        return ["map", "set"]
44f8350f13SLouis Dionne    elif header == "__fwd/byte.h":
45f8350f13SLouis Dionne        return ["cstddef"]
46127c390fSLouis Dionne    elif header == "__fwd/pair.h":
47127c390fSLouis Dionne        return ["utility"]
48127c390fSLouis Dionne    elif header == "__fwd/subrange.h":
49127c390fSLouis Dionne        return ["ranges"]
5058e476f7SLouis Dionne    elif re.match("__fwd/(fstream|ios|istream|ostream|sstream|streambuf)[.]h", header):
5158e476f7SLouis Dionne        return ["iosfwd"]
52127c390fSLouis Dionne    # Handle remaining forward declaration headers
53127c390fSLouis Dionne    elif re.match("__fwd/(.+)[.]h", header):
54127c390fSLouis Dionne        return [re.match("__fwd/(.+)[.]h", header).group(1)]
55127c390fSLouis Dionne    # Handle detail headers for things like <__algorithm/foo.h>
56127c390fSLouis Dionne    elif re.match("__(.+?)/.+", header):
57127c390fSLouis Dionne        return [re.match("__(.+?)/.+", header).group(1)]
587bfaa0f0STobias Hieta    else:
59127c390fSLouis Dionne        return None
607bfaa0f0STobias Hieta
61e2754890SLouis Dionne
62e2754890SLouis Dionnedef main(argv: typing.List[str]):
63e2754890SLouis Dionne    parser = argparse.ArgumentParser()
64e2754890SLouis Dionne    parser.add_argument(
65e2754890SLouis Dionne        "-o",
66e2754890SLouis Dionne        help="File to output the IWYU mappings into",
67e2754890SLouis Dionne        type=argparse.FileType("w"),
68e2754890SLouis Dionne        required=True,
69e2754890SLouis Dionne        dest="output",
70e2754890SLouis Dionne    )
71e2754890SLouis Dionne    args = parser.parse_args(argv)
72e2754890SLouis Dionne
73127c390fSLouis Dionne    mappings = []  # Pairs of (header, public_header)
74127c390fSLouis Dionne    for header in libcxx.header_information.all_headers:
75d6e714b1SLouis Dionne        public_headers = IWYU_mapping(str(header))
76127c390fSLouis Dionne        if public_headers is not None:
77127c390fSLouis Dionne            mappings.extend((header, public) for public in public_headers)
78127c390fSLouis Dionne
79127c390fSLouis Dionne    # Validate that we only have valid public header names -- otherwise the mapping above
80127c390fSLouis Dionne    # needs to be updated.
81127c390fSLouis Dionne    for header, public in mappings:
82127c390fSLouis Dionne        if public not in libcxx.header_information.public_headers:
83127c390fSLouis Dionne            raise RuntimeError(f"{header}: Header {public} is not a valid header")
84127c390fSLouis Dionne
85e2754890SLouis Dionne    args.output.write("[\n")
86127c390fSLouis Dionne    for header, public in sorted(mappings):
87e2754890SLouis Dionne        args.output.write(
88127c390fSLouis Dionne            f'  {{ include: [ "<{header}>", "private", "<{public}>", "public" ] }},\n'
897bfaa0f0STobias Hieta        )
90e2754890SLouis Dionne    args.output.write("]\n")
91ab466480SChristopher Di Bella
927bfaa0f0STobias Hietaif __name__ == "__main__":
93e2754890SLouis Dionne    main(sys.argv[1:])
94