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