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 24480093f4SDimitry Andric /// Add -fsyntax-only option and drop options that triggers output generation. 250b57cec5SDimitry Andric ArgumentsAdjuster getClangSyntaxOnlyAdjuster() { 260b57cec5SDimitry Andric return [](const CommandLineArguments &Args, StringRef /*unused*/) { 270b57cec5SDimitry Andric CommandLineArguments AdjustedArgs; 280b57cec5SDimitry Andric bool HasSyntaxOnly = false; 29480093f4SDimitry Andric const std::vector<llvm::StringRef> OutputCommands = { 30480093f4SDimitry Andric // FIXME: Add other options that generate output. 31480093f4SDimitry Andric "-save-temps", 32480093f4SDimitry Andric "--save-temps", 33480093f4SDimitry Andric }; 340b57cec5SDimitry Andric for (size_t i = 0, e = Args.size(); i < e; ++i) { 350b57cec5SDimitry Andric StringRef Arg = Args[i]; 36480093f4SDimitry Andric // Skip output commands. 37480093f4SDimitry Andric if (llvm::any_of(OutputCommands, [&Arg](llvm::StringRef OutputCommand) { 38480093f4SDimitry Andric return Arg.startswith(OutputCommand); 39480093f4SDimitry Andric })) 40480093f4SDimitry Andric continue; 41480093f4SDimitry Andric 420b57cec5SDimitry Andric if (!Arg.startswith("-fcolor-diagnostics") && 430b57cec5SDimitry Andric !Arg.startswith("-fdiagnostics-color")) 440b57cec5SDimitry Andric AdjustedArgs.push_back(Args[i]); 45*47395794SDimitry Andric // If we strip a color option, make sure we strip any preceeding `-Xclang` 46*47395794SDimitry Andric // option as well. 47*47395794SDimitry Andric // FIXME: This should be added to most argument adjusters! 48*47395794SDimitry Andric else if (!AdjustedArgs.empty() && AdjustedArgs.back() == "-Xclang") 49*47395794SDimitry Andric AdjustedArgs.pop_back(); 50*47395794SDimitry Andric 510b57cec5SDimitry Andric if (Arg == "-fsyntax-only") 520b57cec5SDimitry Andric HasSyntaxOnly = true; 530b57cec5SDimitry Andric } 540b57cec5SDimitry Andric if (!HasSyntaxOnly) 550b57cec5SDimitry Andric AdjustedArgs.push_back("-fsyntax-only"); 560b57cec5SDimitry Andric return AdjustedArgs; 570b57cec5SDimitry Andric }; 580b57cec5SDimitry Andric } 590b57cec5SDimitry Andric 600b57cec5SDimitry Andric ArgumentsAdjuster getClangStripOutputAdjuster() { 610b57cec5SDimitry Andric return [](const CommandLineArguments &Args, StringRef /*unused*/) { 620b57cec5SDimitry Andric CommandLineArguments AdjustedArgs; 630b57cec5SDimitry Andric for (size_t i = 0, e = Args.size(); i < e; ++i) { 640b57cec5SDimitry Andric StringRef Arg = Args[i]; 650b57cec5SDimitry Andric if (!Arg.startswith("-o")) 660b57cec5SDimitry Andric AdjustedArgs.push_back(Args[i]); 670b57cec5SDimitry Andric 680b57cec5SDimitry Andric if (Arg == "-o") { 690b57cec5SDimitry Andric // Output is specified as -o foo. Skip the next argument too. 700b57cec5SDimitry Andric ++i; 710b57cec5SDimitry Andric } 720b57cec5SDimitry Andric // Else, the output is specified as -ofoo. Just do nothing. 730b57cec5SDimitry Andric } 740b57cec5SDimitry Andric return AdjustedArgs; 750b57cec5SDimitry Andric }; 760b57cec5SDimitry Andric } 770b57cec5SDimitry Andric 78a7dea167SDimitry Andric ArgumentsAdjuster getClangStripSerializeDiagnosticAdjuster() { 79a7dea167SDimitry Andric return [](const CommandLineArguments &Args, StringRef /*unused*/) { 80a7dea167SDimitry Andric CommandLineArguments AdjustedArgs; 81a7dea167SDimitry Andric for (size_t i = 0, e = Args.size(); i < e; ++i) { 82a7dea167SDimitry Andric StringRef Arg = Args[i]; 83a7dea167SDimitry Andric if (Arg == "--serialize-diagnostics") { 84a7dea167SDimitry Andric // Skip the diagnostic output argument. 85a7dea167SDimitry Andric ++i; 86a7dea167SDimitry Andric continue; 87a7dea167SDimitry Andric } 88a7dea167SDimitry Andric AdjustedArgs.push_back(Args[i]); 89a7dea167SDimitry Andric } 90a7dea167SDimitry Andric return AdjustedArgs; 91a7dea167SDimitry Andric }; 92a7dea167SDimitry Andric } 93a7dea167SDimitry Andric 940b57cec5SDimitry Andric ArgumentsAdjuster getClangStripDependencyFileAdjuster() { 950b57cec5SDimitry Andric return [](const CommandLineArguments &Args, StringRef /*unused*/) { 960b57cec5SDimitry Andric CommandLineArguments AdjustedArgs; 970b57cec5SDimitry Andric for (size_t i = 0, e = Args.size(); i < e; ++i) { 980b57cec5SDimitry Andric StringRef Arg = Args[i]; 990b57cec5SDimitry Andric // All dependency-file options begin with -M. These include -MM, 1000b57cec5SDimitry Andric // -MF, -MG, -MP, -MT, -MQ, -MD, and -MMD. 1010b57cec5SDimitry Andric if (!Arg.startswith("-M")) { 1020b57cec5SDimitry Andric AdjustedArgs.push_back(Args[i]); 1030b57cec5SDimitry Andric continue; 1040b57cec5SDimitry Andric } 1050b57cec5SDimitry Andric 1060b57cec5SDimitry Andric if (Arg == "-MF" || Arg == "-MT" || Arg == "-MQ") 1070b57cec5SDimitry Andric // These flags take an argument: -MX foo. Skip the next argument also. 1080b57cec5SDimitry Andric ++i; 1090b57cec5SDimitry Andric } 1100b57cec5SDimitry Andric return AdjustedArgs; 1110b57cec5SDimitry Andric }; 1120b57cec5SDimitry Andric } 1130b57cec5SDimitry Andric 1140b57cec5SDimitry Andric ArgumentsAdjuster getInsertArgumentAdjuster(const CommandLineArguments &Extra, 1150b57cec5SDimitry Andric ArgumentInsertPosition Pos) { 1160b57cec5SDimitry Andric return [Extra, Pos](const CommandLineArguments &Args, StringRef /*unused*/) { 1170b57cec5SDimitry Andric CommandLineArguments Return(Args); 1180b57cec5SDimitry Andric 1190b57cec5SDimitry Andric CommandLineArguments::iterator I; 1200b57cec5SDimitry Andric if (Pos == ArgumentInsertPosition::END) { 1210b57cec5SDimitry Andric I = Return.end(); 1220b57cec5SDimitry Andric } else { 1230b57cec5SDimitry Andric I = Return.begin(); 1240b57cec5SDimitry Andric ++I; // To leave the program name in place 1250b57cec5SDimitry Andric } 1260b57cec5SDimitry Andric 1270b57cec5SDimitry Andric Return.insert(I, Extra.begin(), Extra.end()); 1280b57cec5SDimitry Andric return Return; 1290b57cec5SDimitry Andric }; 1300b57cec5SDimitry Andric } 1310b57cec5SDimitry Andric 1320b57cec5SDimitry Andric ArgumentsAdjuster getInsertArgumentAdjuster(const char *Extra, 1330b57cec5SDimitry Andric ArgumentInsertPosition Pos) { 1340b57cec5SDimitry Andric return getInsertArgumentAdjuster(CommandLineArguments(1, Extra), Pos); 1350b57cec5SDimitry Andric } 1360b57cec5SDimitry Andric 1370b57cec5SDimitry Andric ArgumentsAdjuster combineAdjusters(ArgumentsAdjuster First, 1380b57cec5SDimitry Andric ArgumentsAdjuster Second) { 1390b57cec5SDimitry Andric if (!First) 1400b57cec5SDimitry Andric return Second; 1410b57cec5SDimitry Andric if (!Second) 1420b57cec5SDimitry Andric return First; 1430b57cec5SDimitry Andric return [First, Second](const CommandLineArguments &Args, StringRef File) { 1440b57cec5SDimitry Andric return Second(First(Args, File), File); 1450b57cec5SDimitry Andric }; 1460b57cec5SDimitry Andric } 1470b57cec5SDimitry Andric 1480b57cec5SDimitry Andric ArgumentsAdjuster getStripPluginsAdjuster() { 1490b57cec5SDimitry Andric return [](const CommandLineArguments &Args, StringRef /*unused*/) { 1500b57cec5SDimitry Andric CommandLineArguments AdjustedArgs; 1510b57cec5SDimitry Andric for (size_t I = 0, E = Args.size(); I != E; I++) { 1520b57cec5SDimitry Andric // According to https://clang.llvm.org/docs/ClangPlugins.html 1530b57cec5SDimitry Andric // plugin arguments are in the form: 1540b57cec5SDimitry Andric // -Xclang {-load, -plugin, -plugin-arg-<plugin-name>, -add-plugin} 1550b57cec5SDimitry Andric // -Xclang <arbitrary-argument> 1560b57cec5SDimitry Andric if (I + 4 < E && Args[I] == "-Xclang" && 1570b57cec5SDimitry Andric (Args[I + 1] == "-load" || Args[I + 1] == "-plugin" || 1580b57cec5SDimitry Andric llvm::StringRef(Args[I + 1]).startswith("-plugin-arg-") || 1590b57cec5SDimitry Andric Args[I + 1] == "-add-plugin") && 1600b57cec5SDimitry Andric Args[I + 2] == "-Xclang") { 1610b57cec5SDimitry Andric I += 3; 1620b57cec5SDimitry Andric continue; 1630b57cec5SDimitry Andric } 1640b57cec5SDimitry Andric AdjustedArgs.push_back(Args[I]); 1650b57cec5SDimitry Andric } 1660b57cec5SDimitry Andric return AdjustedArgs; 1670b57cec5SDimitry Andric }; 1680b57cec5SDimitry Andric } 1690b57cec5SDimitry Andric 1700b57cec5SDimitry Andric } // end namespace tooling 1710b57cec5SDimitry Andric } // end namespace clang 172