10b57cec5SDimitry Andric //===- ArgumentsAdjusters.cpp - Command line arguments adjuster -----------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file contains definitions of classes which implement ArgumentsAdjuster 100b57cec5SDimitry Andric // interface. 110b57cec5SDimitry Andric // 120b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #include "clang/Tooling/ArgumentsAdjusters.h" 150b57cec5SDimitry Andric #include "clang/Basic/LLVM.h" 16480093f4SDimitry Andric #include "llvm/ADT/STLExtras.h" 170b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h" 180b57cec5SDimitry Andric #include <cstddef> 19480093f4SDimitry Andric #include <vector> 200b57cec5SDimitry Andric 210b57cec5SDimitry Andric namespace clang { 220b57cec5SDimitry Andric namespace tooling { 230b57cec5SDimitry Andric 24e8d8bef9SDimitry Andric static StringRef getDriverMode(const CommandLineArguments &Args) { 25e8d8bef9SDimitry Andric for (const auto &Arg : Args) { 26e8d8bef9SDimitry Andric StringRef ArgRef = Arg; 27e8d8bef9SDimitry Andric if (ArgRef.consume_front("--driver-mode=")) { 28e8d8bef9SDimitry Andric return ArgRef; 29e8d8bef9SDimitry Andric } 30e8d8bef9SDimitry Andric } 31e8d8bef9SDimitry Andric return StringRef(); 32e8d8bef9SDimitry Andric } 33e8d8bef9SDimitry Andric 34480093f4SDimitry Andric /// Add -fsyntax-only option and drop options that triggers output generation. 350b57cec5SDimitry Andric ArgumentsAdjuster getClangSyntaxOnlyAdjuster() { 360b57cec5SDimitry Andric return [](const CommandLineArguments &Args, StringRef /*unused*/) { 370b57cec5SDimitry Andric CommandLineArguments AdjustedArgs; 380b57cec5SDimitry Andric bool HasSyntaxOnly = false; 395ffd83dbSDimitry Andric constexpr llvm::StringRef OutputCommands[] = { 40480093f4SDimitry Andric // FIXME: Add other options that generate output. 41480093f4SDimitry Andric "-save-temps", 42480093f4SDimitry Andric "--save-temps", 43480093f4SDimitry Andric }; 440b57cec5SDimitry Andric for (size_t i = 0, e = Args.size(); i < e; ++i) { 450b57cec5SDimitry Andric StringRef Arg = Args[i]; 46480093f4SDimitry Andric // Skip output commands. 47480093f4SDimitry Andric if (llvm::any_of(OutputCommands, [&Arg](llvm::StringRef OutputCommand) { 48*5f757f3fSDimitry Andric return Arg.starts_with(OutputCommand); 49480093f4SDimitry Andric })) 50480093f4SDimitry Andric continue; 51480093f4SDimitry Andric 52*5f757f3fSDimitry Andric if (!Arg.starts_with("-fcolor-diagnostics") && 53*5f757f3fSDimitry Andric !Arg.starts_with("-fdiagnostics-color")) 540b57cec5SDimitry Andric AdjustedArgs.push_back(Args[i]); 5547395794SDimitry Andric // If we strip a color option, make sure we strip any preceeding `-Xclang` 5647395794SDimitry Andric // option as well. 5747395794SDimitry Andric // FIXME: This should be added to most argument adjusters! 5847395794SDimitry Andric else if (!AdjustedArgs.empty() && AdjustedArgs.back() == "-Xclang") 5947395794SDimitry Andric AdjustedArgs.pop_back(); 6047395794SDimitry Andric 610b57cec5SDimitry Andric if (Arg == "-fsyntax-only") 620b57cec5SDimitry Andric HasSyntaxOnly = true; 630b57cec5SDimitry Andric } 640b57cec5SDimitry Andric if (!HasSyntaxOnly) 65fe6060f1SDimitry Andric AdjustedArgs = 66fe6060f1SDimitry Andric getInsertArgumentAdjuster("-fsyntax-only")(AdjustedArgs, ""); 670b57cec5SDimitry Andric return AdjustedArgs; 680b57cec5SDimitry Andric }; 690b57cec5SDimitry Andric } 700b57cec5SDimitry Andric 710b57cec5SDimitry Andric ArgumentsAdjuster getClangStripOutputAdjuster() { 720b57cec5SDimitry Andric return [](const CommandLineArguments &Args, StringRef /*unused*/) { 730b57cec5SDimitry Andric CommandLineArguments AdjustedArgs; 740b57cec5SDimitry Andric for (size_t i = 0, e = Args.size(); i < e; ++i) { 750b57cec5SDimitry Andric StringRef Arg = Args[i]; 76*5f757f3fSDimitry Andric if (!Arg.starts_with("-o")) 770b57cec5SDimitry Andric AdjustedArgs.push_back(Args[i]); 780b57cec5SDimitry Andric 790b57cec5SDimitry Andric if (Arg == "-o") { 800b57cec5SDimitry Andric // Output is specified as -o foo. Skip the next argument too. 810b57cec5SDimitry Andric ++i; 820b57cec5SDimitry Andric } 830b57cec5SDimitry Andric // Else, the output is specified as -ofoo. Just do nothing. 840b57cec5SDimitry Andric } 850b57cec5SDimitry Andric return AdjustedArgs; 860b57cec5SDimitry Andric }; 870b57cec5SDimitry Andric } 880b57cec5SDimitry Andric 890b57cec5SDimitry Andric ArgumentsAdjuster getClangStripDependencyFileAdjuster() { 900b57cec5SDimitry Andric return [](const CommandLineArguments &Args, StringRef /*unused*/) { 91e8d8bef9SDimitry Andric auto UsingClDriver = (getDriverMode(Args) == "cl"); 92e8d8bef9SDimitry Andric 930b57cec5SDimitry Andric CommandLineArguments AdjustedArgs; 940b57cec5SDimitry Andric for (size_t i = 0, e = Args.size(); i < e; ++i) { 950b57cec5SDimitry Andric StringRef Arg = Args[i]; 96e8d8bef9SDimitry Andric 97e8d8bef9SDimitry Andric // These flags take an argument: -MX foo. Skip the next argument also. 98e8d8bef9SDimitry Andric if (!UsingClDriver && (Arg == "-MF" || Arg == "-MT" || Arg == "-MQ")) { 99e8d8bef9SDimitry Andric ++i; 1000b57cec5SDimitry Andric continue; 1010b57cec5SDimitry Andric } 102e8d8bef9SDimitry Andric // When not using the cl driver mode, dependency file generation options 103e8d8bef9SDimitry Andric // begin with -M. These include -MM, -MF, -MG, -MP, -MT, -MQ, -MD, and 104e8d8bef9SDimitry Andric // -MMD. 105*5f757f3fSDimitry Andric if (!UsingClDriver && Arg.starts_with("-M")) 106e8d8bef9SDimitry Andric continue; 107e8d8bef9SDimitry Andric // Under MSVC's cl driver mode, dependency file generation is controlled 108e8d8bef9SDimitry Andric // using /showIncludes 109*5f757f3fSDimitry Andric if (Arg.starts_with("/showIncludes") || Arg.starts_with("-showIncludes")) 110e8d8bef9SDimitry Andric continue; 1110b57cec5SDimitry Andric 112e8d8bef9SDimitry Andric AdjustedArgs.push_back(Args[i]); 1130b57cec5SDimitry Andric } 1140b57cec5SDimitry Andric return AdjustedArgs; 1150b57cec5SDimitry Andric }; 1160b57cec5SDimitry Andric } 1170b57cec5SDimitry Andric 1180b57cec5SDimitry Andric ArgumentsAdjuster getInsertArgumentAdjuster(const CommandLineArguments &Extra, 1190b57cec5SDimitry Andric ArgumentInsertPosition Pos) { 1200b57cec5SDimitry Andric return [Extra, Pos](const CommandLineArguments &Args, StringRef /*unused*/) { 1210b57cec5SDimitry Andric CommandLineArguments Return(Args); 1220b57cec5SDimitry Andric 1230b57cec5SDimitry Andric CommandLineArguments::iterator I; 1240b57cec5SDimitry Andric if (Pos == ArgumentInsertPosition::END) { 125bdd1243dSDimitry Andric I = llvm::find(Return, "--"); 1260b57cec5SDimitry Andric } else { 1270b57cec5SDimitry Andric I = Return.begin(); 1280b57cec5SDimitry Andric ++I; // To leave the program name in place 1290b57cec5SDimitry Andric } 1300b57cec5SDimitry Andric 1310b57cec5SDimitry Andric Return.insert(I, Extra.begin(), Extra.end()); 1320b57cec5SDimitry Andric return Return; 1330b57cec5SDimitry Andric }; 1340b57cec5SDimitry Andric } 1350b57cec5SDimitry Andric 1360b57cec5SDimitry Andric ArgumentsAdjuster getInsertArgumentAdjuster(const char *Extra, 1370b57cec5SDimitry Andric ArgumentInsertPosition Pos) { 1380b57cec5SDimitry Andric return getInsertArgumentAdjuster(CommandLineArguments(1, Extra), Pos); 1390b57cec5SDimitry Andric } 1400b57cec5SDimitry Andric 1410b57cec5SDimitry Andric ArgumentsAdjuster combineAdjusters(ArgumentsAdjuster First, 1420b57cec5SDimitry Andric ArgumentsAdjuster Second) { 1430b57cec5SDimitry Andric if (!First) 1440b57cec5SDimitry Andric return Second; 1450b57cec5SDimitry Andric if (!Second) 1460b57cec5SDimitry Andric return First; 1470b57cec5SDimitry Andric return [First, Second](const CommandLineArguments &Args, StringRef File) { 1480b57cec5SDimitry Andric return Second(First(Args, File), File); 1490b57cec5SDimitry Andric }; 1500b57cec5SDimitry Andric } 1510b57cec5SDimitry Andric 1520b57cec5SDimitry Andric ArgumentsAdjuster getStripPluginsAdjuster() { 1530b57cec5SDimitry Andric return [](const CommandLineArguments &Args, StringRef /*unused*/) { 1540b57cec5SDimitry Andric CommandLineArguments AdjustedArgs; 1550b57cec5SDimitry Andric for (size_t I = 0, E = Args.size(); I != E; I++) { 1560b57cec5SDimitry Andric // According to https://clang.llvm.org/docs/ClangPlugins.html 1570b57cec5SDimitry Andric // plugin arguments are in the form: 1580b57cec5SDimitry Andric // -Xclang {-load, -plugin, -plugin-arg-<plugin-name>, -add-plugin} 1590b57cec5SDimitry Andric // -Xclang <arbitrary-argument> 1600b57cec5SDimitry Andric if (I + 4 < E && Args[I] == "-Xclang" && 1610b57cec5SDimitry Andric (Args[I + 1] == "-load" || Args[I + 1] == "-plugin" || 162*5f757f3fSDimitry Andric llvm::StringRef(Args[I + 1]).starts_with("-plugin-arg-") || 1630b57cec5SDimitry Andric Args[I + 1] == "-add-plugin") && 1640b57cec5SDimitry Andric Args[I + 2] == "-Xclang") { 1650b57cec5SDimitry Andric I += 3; 1660b57cec5SDimitry Andric continue; 1670b57cec5SDimitry Andric } 1680b57cec5SDimitry Andric AdjustedArgs.push_back(Args[I]); 1690b57cec5SDimitry Andric } 1700b57cec5SDimitry Andric return AdjustedArgs; 1710b57cec5SDimitry Andric }; 1720b57cec5SDimitry Andric } 1730b57cec5SDimitry Andric 1740b57cec5SDimitry Andric } // end namespace tooling 1750b57cec5SDimitry Andric } // end namespace clang 176