1 | //===- ArgumentsAdjusters.cpp - Command line arguments adjuster -----------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // This file contains definitions of classes which implement ArgumentsAdjuster |
10 | // interface. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "clang/Tooling/ArgumentsAdjusters.h" |
15 | #include "clang/Basic/LLVM.h" |
16 | #include "llvm/ADT/STLExtras.h" |
17 | #include "llvm/ADT/StringRef.h" |
18 | #include <cstddef> |
19 | #include <vector> |
20 | |
21 | namespace clang { |
22 | namespace tooling { |
23 | |
24 | static StringRef getDriverMode(const CommandLineArguments &Args) { |
25 | for (const auto &Arg : Args) { |
26 | StringRef ArgRef = Arg; |
27 | if (ArgRef.consume_front(Prefix: "--driver-mode=" )) { |
28 | return ArgRef; |
29 | } |
30 | } |
31 | return StringRef(); |
32 | } |
33 | |
34 | /// Add -fsyntax-only option and drop options that triggers output generation. |
35 | ArgumentsAdjuster getClangSyntaxOnlyAdjuster() { |
36 | return [](const CommandLineArguments &Args, StringRef /*unused*/) { |
37 | CommandLineArguments AdjustedArgs; |
38 | bool HasSyntaxOnly = false; |
39 | constexpr llvm::StringRef OutputCommands[] = { |
40 | // FIXME: Add other options that generate output. |
41 | "-save-temps" , |
42 | "--save-temps" , |
43 | }; |
44 | for (size_t i = 0, e = Args.size(); i < e; ++i) { |
45 | StringRef Arg = Args[i]; |
46 | // Skip output commands. |
47 | if (llvm::any_of(Range: OutputCommands, P: [&Arg](llvm::StringRef OutputCommand) { |
48 | return Arg.starts_with(Prefix: OutputCommand); |
49 | })) |
50 | continue; |
51 | |
52 | if (!Arg.starts_with(Prefix: "-fcolor-diagnostics" ) && |
53 | !Arg.starts_with(Prefix: "-fdiagnostics-color" )) |
54 | AdjustedArgs.push_back(x: Args[i]); |
55 | // If we strip a color option, make sure we strip any preceeding `-Xclang` |
56 | // option as well. |
57 | // FIXME: This should be added to most argument adjusters! |
58 | else if (!AdjustedArgs.empty() && AdjustedArgs.back() == "-Xclang" ) |
59 | AdjustedArgs.pop_back(); |
60 | |
61 | if (Arg == "-fsyntax-only" ) |
62 | HasSyntaxOnly = true; |
63 | } |
64 | if (!HasSyntaxOnly) |
65 | AdjustedArgs = |
66 | getInsertArgumentAdjuster(Extra: "-fsyntax-only" )(AdjustedArgs, "" ); |
67 | return AdjustedArgs; |
68 | }; |
69 | } |
70 | |
71 | ArgumentsAdjuster getClangStripOutputAdjuster() { |
72 | return [](const CommandLineArguments &Args, StringRef /*unused*/) { |
73 | CommandLineArguments AdjustedArgs; |
74 | for (size_t i = 0, e = Args.size(); i < e; ++i) { |
75 | StringRef Arg = Args[i]; |
76 | if (!Arg.starts_with(Prefix: "-o" )) |
77 | AdjustedArgs.push_back(x: Args[i]); |
78 | |
79 | if (Arg == "-o" ) { |
80 | // Output is specified as -o foo. Skip the next argument too. |
81 | ++i; |
82 | } |
83 | // Else, the output is specified as -ofoo. Just do nothing. |
84 | } |
85 | return AdjustedArgs; |
86 | }; |
87 | } |
88 | |
89 | ArgumentsAdjuster getClangStripDependencyFileAdjuster() { |
90 | return [](const CommandLineArguments &Args, StringRef /*unused*/) { |
91 | auto UsingClDriver = (getDriverMode(Args) == "cl" ); |
92 | |
93 | CommandLineArguments AdjustedArgs; |
94 | for (size_t i = 0, e = Args.size(); i < e; ++i) { |
95 | StringRef Arg = Args[i]; |
96 | |
97 | // These flags take an argument: -MX foo. Skip the next argument also. |
98 | if (!UsingClDriver && (Arg == "-MF" || Arg == "-MT" || Arg == "-MQ" )) { |
99 | ++i; |
100 | continue; |
101 | } |
102 | // When not using the cl driver mode, dependency file generation options |
103 | // begin with -M. These include -MM, -MF, -MG, -MP, -MT, -MQ, -MD, and |
104 | // -MMD. |
105 | if (!UsingClDriver && Arg.starts_with(Prefix: "-M" )) |
106 | continue; |
107 | // Under MSVC's cl driver mode, dependency file generation is controlled |
108 | // using /showIncludes |
109 | if (Arg.starts_with(Prefix: "/showIncludes" ) || Arg.starts_with(Prefix: "-showIncludes" )) |
110 | continue; |
111 | |
112 | AdjustedArgs.push_back(x: Args[i]); |
113 | } |
114 | return AdjustedArgs; |
115 | }; |
116 | } |
117 | |
118 | ArgumentsAdjuster getInsertArgumentAdjuster(const CommandLineArguments &, |
119 | ArgumentInsertPosition Pos) { |
120 | return [Extra, Pos](const CommandLineArguments &Args, StringRef /*unused*/) { |
121 | CommandLineArguments Return(Args); |
122 | |
123 | CommandLineArguments::iterator I; |
124 | if (Pos == ArgumentInsertPosition::END) { |
125 | I = llvm::find(Range&: Return, Val: "--" ); |
126 | } else { |
127 | I = Return.begin(); |
128 | ++I; // To leave the program name in place |
129 | } |
130 | |
131 | Return.insert(position: I, first: Extra.begin(), last: Extra.end()); |
132 | return Return; |
133 | }; |
134 | } |
135 | |
136 | ArgumentsAdjuster getInsertArgumentAdjuster(const char *, |
137 | ArgumentInsertPosition Pos) { |
138 | return getInsertArgumentAdjuster(Extra: CommandLineArguments(1, Extra), Pos); |
139 | } |
140 | |
141 | ArgumentsAdjuster combineAdjusters(ArgumentsAdjuster First, |
142 | ArgumentsAdjuster Second) { |
143 | if (!First) |
144 | return Second; |
145 | if (!Second) |
146 | return First; |
147 | return [First, Second](const CommandLineArguments &Args, StringRef File) { |
148 | return Second(First(Args, File), File); |
149 | }; |
150 | } |
151 | |
152 | ArgumentsAdjuster getStripPluginsAdjuster() { |
153 | return [](const CommandLineArguments &Args, StringRef /*unused*/) { |
154 | CommandLineArguments AdjustedArgs; |
155 | for (size_t I = 0, E = Args.size(); I != E; I++) { |
156 | // According to https://clang.llvm.org/docs/ClangPlugins.html |
157 | // plugin arguments are in the form: |
158 | // -Xclang {-load, -plugin, -plugin-arg-<plugin-name>, -add-plugin} |
159 | // -Xclang <arbitrary-argument> |
160 | if (I + 4 < E && Args[I] == "-Xclang" && |
161 | (Args[I + 1] == "-load" || Args[I + 1] == "-plugin" || |
162 | llvm::StringRef(Args[I + 1]).starts_with(Prefix: "-plugin-arg-" ) || |
163 | Args[I + 1] == "-add-plugin" ) && |
164 | Args[I + 2] == "-Xclang" ) { |
165 | I += 3; |
166 | continue; |
167 | } |
168 | AdjustedArgs.push_back(x: Args[I]); |
169 | } |
170 | return AdjustedArgs; |
171 | }; |
172 | } |
173 | |
174 | } // end namespace tooling |
175 | } // end namespace clang |
176 | |