-
Notifications
You must be signed in to change notification settings - Fork 33
/
iwyu_helper.py
158 lines (146 loc) · 4.73 KB
/
iwyu_helper.py
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
import argparse
import subprocess
import sys
import json
import shutil
import os
import pathlib
def does_src_file_have_local_changes(source_file_path: str):
additional_file_types = [".hpp", ".h", ".inl"]
files = [source_file_path] + [
str(pathlib.Path(source_file_path).with_suffix(ext))
for ext in additional_file_types
]
git_diff_command = [
"git",
"diff",
"--exit-code",
] + files
git_diff_staged_command = [
"git",
"diff",
"--cached",
"--exit-code",
] + files
with open(os.devnull, "w") as nul:
return (
subprocess.call(git_diff_command, stdout=nul, stderr=nul) != 0
or subprocess.call(git_diff_staged_command, stdout=nul, stderr=nul) != 0
)
def main():
parser: argparse.ArgumentParser = argparse.ArgumentParser(
description="IWYU helper script, calls iwyu_tool.py and passes output to fix_includes.py"
)
parser.add_argument(
"--iwyu_exe",
"-i",
default=None,
help="Path to include-what-you-use executable. Must be passed if --iwyu_tool is passed.",
)
parser.add_argument(
"--iwyu_tool",
"-t",
default=None,
help="Path to iwyu_tool.py to execute.",
)
parser.add_argument(
"--iwyu_tool_output",
"-o",
default=None,
help="Path to iwyu_tool output, pass instead of --iwyu_tool to avoid running the tool.",
)
parser.add_argument(
"--compile_commands",
"-c",
default=None,
help="Path to compile_commands.json file to pass to IWYU.",
)
parser.add_argument(
"--extra_args",
"-e",
default=[],
action="append",
help="Extra arguments to pass to IWYU.",
)
parser.add_argument(
"--fix_includes",
"-f",
default=None,
required=True,
help="Path to fix_includes.py to execute.",
)
parser.add_argument(
"--skip_unchanged",
"-s",
default=None,
action="store_true",
help="Only touch changed files, including staged files.",
)
args = parser.parse_args()
if args.iwyu_tool:
# Create a temp folder
tmp_dir: str = "iwyu_tmp"
if os.path.exists(tmp_dir):
if os.path.isdir(tmp_dir):
shutil.rmtree(tmp_dir, ignore_errors=False, onerror=None)
else:
os.remove(tmp_dir)
os.makedirs(tmp_dir)
if not args.compile_commands:
parser.error("--iwyu_tool requires --compile_commands")
if not args.iwyu_exe:
parser.error("--iwyu_tool requires --iwyu_exe")
# Fix up compile_commands.json
with open(args.compile_commands, "r", encoding="utf-8") as cc_file:
compile_commands = json.load(cc_file)
# Strip PCH compiles
compile_commands = [
compile_command
for compile_command in compile_commands
if not compile_command["command"].endswith("cmake_pch.hxx.cxx")
]
if args.skip_unchanged:
# Strip unchanged files
compile_commands = [
compile_command
for compile_command in compile_commands
if does_src_file_have_local_changes(compile_command["file"])
]
# Append extra agrs
if args.extra_args:
for compile_command in compile_commands:
compile_command["command"] += " " + " ".join(args.extra_args)
# Dump fixed file
with open(
"iwyu_tmp/compile_commands.json", "w", encoding="utf-8"
) as cc_file_out:
json.dump(compile_commands, cc_file_out, indent=2)
# Call iwyu_tool.py
iwyu_tool_args = [
"python",
args.iwyu_tool,
"-p",
tmp_dir,
"-v",
]
os.environ["IWYU_BINARY"] = args.iwyu_exe
iwyu_out = os.path.join(tmp_dir, "iwyu_tool_out")
with open(iwyu_out, "w") as iwyu_out_file:
subprocess.call(iwyu_tool_args, stdout=iwyu_out_file)
elif args.iwyu_tool_output:
iwyu_out = args.iwyu_tool_output
else:
parser.error("either --iwyu_tool or --iwyu_tool_output required")
# Call fix_includes.py with the output from iwyu_tool.py
fix_includes_args = [
"python",
args.fix_includes,
"--comments",
"--update_comments",
"--nosafe_headers",
"--noreorder",
]
with open(iwyu_out, "r") as fix_includes_in_file:
subprocess.call(fix_includes_args, stdin=fix_includes_in_file)
if __name__ == "__main__":
sys.exit(main())