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 24*e8d8bef9SDimitry Andric static StringRef getDriverMode(const CommandLineArguments &Args) { 25*e8d8bef9SDimitry Andric for (const auto &Arg : Args) { 26*e8d8bef9SDimitry Andric StringRef ArgRef = Arg; 27*e8d8bef9SDimitry Andric if (ArgRef.consume_front("--driver-mode=")) { 28*e8d8bef9SDimitry Andric return ArgRef; 29*e8d8bef9SDimitry Andric } 30*e8d8bef9SDimitry Andric } 31*e8d8bef9SDimitry Andric return StringRef(); 32*e8d8bef9SDimitry Andric } 33*e8d8bef9SDimitry 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) { 48480093f4SDimitry Andric return Arg.startswith(OutputCommand); 49480093f4SDimitry Andric })) 50480093f4SDimitry Andric continue; 51480093f4SDimitry Andric 520b57cec5SDimitry Andric if (!Arg.startswith("-fcolor-diagnostics") && 530b57cec5SDimitry Andric !Arg.startswith("-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) 650b57cec5SDimitry Andric AdjustedArgs.push_back("-fsyntax-only"); 660b57cec5SDimitry Andric return AdjustedArgs; 670b57cec5SDimitry Andric }; 680b57cec5SDimitry Andric } 690b57cec5SDimitry Andric 700b57cec5SDimitry Andric ArgumentsAdjuster getClangStripOutputAdjuster() { 710b57cec5SDimitry Andric return [](const CommandLineArguments &Args, StringRef /*unused*/) { 720b57cec5SDimitry Andric CommandLineArguments AdjustedArgs; 730b57cec5SDimitry Andric for (size_t i = 0, e = Args.size(); i < e; ++i) { 740b57cec5SDimitry Andric StringRef Arg = Args[i]; 750b57cec5SDimitry Andric if (!Arg.startswith("-o")) 760b57cec5SDimitry Andric AdjustedArgs.push_back(Args[i]); 770b57cec5SDimitry Andric 780b57cec5SDimitry Andric if (Arg == "-o") { 790b57cec5SDimitry Andric // Output is specified as -o foo. Skip the next argument too. 800b57cec5SDimitry Andric ++i; 810b57cec5SDimitry Andric } 820b57cec5SDimitry Andric // Else, the output is specified as -ofoo. Just do nothing. 830b57cec5SDimitry Andric } 840b57cec5SDimitry Andric return AdjustedArgs; 850b57cec5SDimitry Andric }; 860b57cec5SDimitry Andric } 870b57cec5SDimitry Andric 88a7dea167SDimitry Andric ArgumentsAdjuster getClangStripSerializeDiagnosticAdjuster() { 89a7dea167SDimitry Andric return [](const CommandLineArguments &Args, StringRef /*unused*/) { 90a7dea167SDimitry Andric CommandLineArguments AdjustedArgs; 91a7dea167SDimitry Andric for (size_t i = 0, e = Args.size(); i < e; ++i) { 92a7dea167SDimitry Andric StringRef Arg = Args[i]; 93a7dea167SDimitry Andric if (Arg == "--serialize-diagnostics") { 94a7dea167SDimitry Andric // Skip the diagnostic output argument. 95a7dea167SDimitry Andric ++i; 96a7dea167SDimitry Andric continue; 97a7dea167SDimitry Andric } 98a7dea167SDimitry Andric AdjustedArgs.push_back(Args[i]); 99a7dea167SDimitry Andric } 100a7dea167SDimitry Andric return AdjustedArgs; 101a7dea167SDimitry Andric }; 102a7dea167SDimitry Andric } 103a7dea167SDimitry Andric 1040b57cec5SDimitry Andric ArgumentsAdjuster getClangStripDependencyFileAdjuster() { 1050b57cec5SDimitry Andric return [](const CommandLineArguments &Args, StringRef /*unused*/) { 106*e8d8bef9SDimitry Andric auto UsingClDriver = (getDriverMode(Args) == "cl"); 107*e8d8bef9SDimitry Andric 1080b57cec5SDimitry Andric CommandLineArguments AdjustedArgs; 1090b57cec5SDimitry Andric for (size_t i = 0, e = Args.size(); i < e; ++i) { 1100b57cec5SDimitry Andric StringRef Arg = Args[i]; 111*e8d8bef9SDimitry Andric 112*e8d8bef9SDimitry Andric // These flags take an argument: -MX foo. Skip the next argument also. 113*e8d8bef9SDimitry Andric if (!UsingClDriver && (Arg == "-MF" || Arg == "-MT" || Arg == "-MQ")) { 114*e8d8bef9SDimitry Andric ++i; 1150b57cec5SDimitry Andric continue; 1160b57cec5SDimitry Andric } 117*e8d8bef9SDimitry Andric // When not using the cl driver mode, dependency file generation options 118*e8d8bef9SDimitry Andric // begin with -M. These include -MM, -MF, -MG, -MP, -MT, -MQ, -MD, and 119*e8d8bef9SDimitry Andric // -MMD. 120*e8d8bef9SDimitry Andric if (!UsingClDriver && Arg.startswith("-M")) 121*e8d8bef9SDimitry Andric continue; 122*e8d8bef9SDimitry Andric // Under MSVC's cl driver mode, dependency file generation is controlled 123*e8d8bef9SDimitry Andric // using /showIncludes 124*e8d8bef9SDimitry Andric if (Arg.startswith("/showIncludes") || Arg.startswith("-showIncludes")) 125*e8d8bef9SDimitry Andric continue; 1260b57cec5SDimitry Andric 127*e8d8bef9SDimitry Andric AdjustedArgs.push_back(Args[i]); 1280b57cec5SDimitry Andric } 1290b57cec5SDimitry Andric return AdjustedArgs; 1300b57cec5SDimitry Andric }; 1310b57cec5SDimitry Andric } 1320b57cec5SDimitry Andric 1330b57cec5SDimitry Andric ArgumentsAdjuster getInsertArgumentAdjuster(const CommandLineArguments &Extra, 1340b57cec5SDimitry Andric ArgumentInsertPosition Pos) { 1350b57cec5SDimitry Andric return [Extra, Pos](const CommandLineArguments &Args, StringRef /*unused*/) { 1360b57cec5SDimitry Andric CommandLineArguments Return(Args); 1370b57cec5SDimitry Andric 1380b57cec5SDimitry Andric CommandLineArguments::iterator I; 1390b57cec5SDimitry Andric if (Pos == ArgumentInsertPosition::END) { 1400b57cec5SDimitry Andric I = Return.end(); 1410b57cec5SDimitry Andric } else { 1420b57cec5SDimitry Andric I = Return.begin(); 1430b57cec5SDimitry Andric ++I; // To leave the program name in place 1440b57cec5SDimitry Andric } 1450b57cec5SDimitry Andric 1460b57cec5SDimitry Andric Return.insert(I, Extra.begin(), Extra.end()); 1470b57cec5SDimitry Andric return Return; 1480b57cec5SDimitry Andric }; 1490b57cec5SDimitry Andric } 1500b57cec5SDimitry Andric 1510b57cec5SDimitry Andric ArgumentsAdjuster getInsertArgumentAdjuster(const char *Extra, 1520b57cec5SDimitry Andric ArgumentInsertPosition Pos) { 1530b57cec5SDimitry Andric return getInsertArgumentAdjuster(CommandLineArguments(1, Extra), Pos); 1540b57cec5SDimitry Andric } 1550b57cec5SDimitry Andric 1560b57cec5SDimitry Andric ArgumentsAdjuster combineAdjusters(ArgumentsAdjuster First, 1570b57cec5SDimitry Andric ArgumentsAdjuster Second) { 1580b57cec5SDimitry Andric if (!First) 1590b57cec5SDimitry Andric return Second; 1600b57cec5SDimitry Andric if (!Second) 1610b57cec5SDimitry Andric return First; 1620b57cec5SDimitry Andric return [First, Second](const CommandLineArguments &Args, StringRef File) { 1630b57cec5SDimitry Andric return Second(First(Args, File), File); 1640b57cec5SDimitry Andric }; 1650b57cec5SDimitry Andric } 1660b57cec5SDimitry Andric 1670b57cec5SDimitry Andric ArgumentsAdjuster getStripPluginsAdjuster() { 1680b57cec5SDimitry Andric return [](const CommandLineArguments &Args, StringRef /*unused*/) { 1690b57cec5SDimitry Andric CommandLineArguments AdjustedArgs; 1700b57cec5SDimitry Andric for (size_t I = 0, E = Args.size(); I != E; I++) { 1710b57cec5SDimitry Andric // According to https://clang.llvm.org/docs/ClangPlugins.html 1720b57cec5SDimitry Andric // plugin arguments are in the form: 1730b57cec5SDimitry Andric // -Xclang {-load, -plugin, -plugin-arg-<plugin-name>, -add-plugin} 1740b57cec5SDimitry Andric // -Xclang <arbitrary-argument> 1750b57cec5SDimitry Andric if (I + 4 < E && Args[I] == "-Xclang" && 1760b57cec5SDimitry Andric (Args[I + 1] == "-load" || Args[I + 1] == "-plugin" || 1770b57cec5SDimitry Andric llvm::StringRef(Args[I + 1]).startswith("-plugin-arg-") || 1780b57cec5SDimitry Andric Args[I + 1] == "-add-plugin") && 1790b57cec5SDimitry Andric Args[I + 2] == "-Xclang") { 1800b57cec5SDimitry Andric I += 3; 1810b57cec5SDimitry Andric continue; 1820b57cec5SDimitry Andric } 1830b57cec5SDimitry Andric AdjustedArgs.push_back(Args[I]); 1840b57cec5SDimitry Andric } 1850b57cec5SDimitry Andric return AdjustedArgs; 1860b57cec5SDimitry Andric }; 1870b57cec5SDimitry Andric } 1880b57cec5SDimitry Andric 1890b57cec5SDimitry Andric } // end namespace tooling 1900b57cec5SDimitry Andric } // end namespace clang 191