| 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 (StringRef ArgRef : Args) { |
| 26 | if (ArgRef.consume_front(Prefix: "--driver-mode=" )) { |
| 27 | return ArgRef; |
| 28 | } |
| 29 | } |
| 30 | return StringRef(); |
| 31 | } |
| 32 | |
| 33 | /// Add -fsyntax-only option and drop options that triggers output generation. |
| 34 | ArgumentsAdjuster getClangSyntaxOnlyAdjuster() { |
| 35 | return [](const CommandLineArguments &Args, StringRef /*unused*/) { |
| 36 | CommandLineArguments AdjustedArgs; |
| 37 | bool HasSyntaxOnly = false; |
| 38 | constexpr llvm::StringRef OutputCommands[] = { |
| 39 | // FIXME: Add other options that generate output. |
| 40 | "-save-temps" , |
| 41 | "--save-temps" , |
| 42 | }; |
| 43 | for (size_t i = 0, e = Args.size(); i < e; ++i) { |
| 44 | StringRef Arg = Args[i]; |
| 45 | // Skip output commands. |
| 46 | if (llvm::any_of(Range: OutputCommands, P: [&Arg](llvm::StringRef OutputCommand) { |
| 47 | return Arg.starts_with(Prefix: OutputCommand); |
| 48 | })) |
| 49 | continue; |
| 50 | |
| 51 | if (Arg != "-c" && Arg != "-S" && |
| 52 | !Arg.starts_with(Prefix: "-fcolor-diagnostics" ) && |
| 53 | !Arg.starts_with(Prefix: "-fdiagnostics-color" )) |
| 54 | AdjustedArgs.push_back(x: Args[i]); |
| 55 | // If we strip an 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 | |