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" 16*480093f4SDimitry Andric #include "llvm/ADT/STLExtras.h" 170b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h" 180b57cec5SDimitry Andric #include <cstddef> 19*480093f4SDimitry Andric #include <vector> 200b57cec5SDimitry Andric 210b57cec5SDimitry Andric namespace clang { 220b57cec5SDimitry Andric namespace tooling { 230b57cec5SDimitry Andric 24*480093f4SDimitry 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; 29*480093f4SDimitry Andric const std::vector<llvm::StringRef> OutputCommands = { 30*480093f4SDimitry Andric // FIXME: Add other options that generate output. 31*480093f4SDimitry Andric "-save-temps", 32*480093f4SDimitry Andric "--save-temps", 33*480093f4SDimitry Andric }; 340b57cec5SDimitry Andric for (size_t i = 0, e = Args.size(); i < e; ++i) { 350b57cec5SDimitry Andric StringRef Arg = Args[i]; 36*480093f4SDimitry Andric // Skip output commands. 37*480093f4SDimitry Andric if (llvm::any_of(OutputCommands, [&Arg](llvm::StringRef OutputCommand) { 38*480093f4SDimitry Andric return Arg.startswith(OutputCommand); 39*480093f4SDimitry Andric })) 40*480093f4SDimitry Andric continue; 41*480093f4SDimitry Andric 420b57cec5SDimitry Andric if (!Arg.startswith("-fcolor-diagnostics") && 430b57cec5SDimitry Andric !Arg.startswith("-fdiagnostics-color")) 440b57cec5SDimitry Andric AdjustedArgs.push_back(Args[i]); 450b57cec5SDimitry Andric if (Arg == "-fsyntax-only") 460b57cec5SDimitry Andric HasSyntaxOnly = true; 470b57cec5SDimitry Andric } 480b57cec5SDimitry Andric if (!HasSyntaxOnly) 490b57cec5SDimitry Andric AdjustedArgs.push_back("-fsyntax-only"); 500b57cec5SDimitry Andric return AdjustedArgs; 510b57cec5SDimitry Andric }; 520b57cec5SDimitry Andric } 530b57cec5SDimitry Andric 540b57cec5SDimitry Andric ArgumentsAdjuster getClangStripOutputAdjuster() { 550b57cec5SDimitry Andric return [](const CommandLineArguments &Args, StringRef /*unused*/) { 560b57cec5SDimitry Andric CommandLineArguments AdjustedArgs; 570b57cec5SDimitry Andric for (size_t i = 0, e = Args.size(); i < e; ++i) { 580b57cec5SDimitry Andric StringRef Arg = Args[i]; 590b57cec5SDimitry Andric if (!Arg.startswith("-o")) 600b57cec5SDimitry Andric AdjustedArgs.push_back(Args[i]); 610b57cec5SDimitry Andric 620b57cec5SDimitry Andric if (Arg == "-o") { 630b57cec5SDimitry Andric // Output is specified as -o foo. Skip the next argument too. 640b57cec5SDimitry Andric ++i; 650b57cec5SDimitry Andric } 660b57cec5SDimitry Andric // Else, the output is specified as -ofoo. Just do nothing. 670b57cec5SDimitry Andric } 680b57cec5SDimitry Andric return AdjustedArgs; 690b57cec5SDimitry Andric }; 700b57cec5SDimitry Andric } 710b57cec5SDimitry Andric 72a7dea167SDimitry Andric ArgumentsAdjuster getClangStripSerializeDiagnosticAdjuster() { 73a7dea167SDimitry Andric return [](const CommandLineArguments &Args, StringRef /*unused*/) { 74a7dea167SDimitry Andric CommandLineArguments AdjustedArgs; 75a7dea167SDimitry Andric for (size_t i = 0, e = Args.size(); i < e; ++i) { 76a7dea167SDimitry Andric StringRef Arg = Args[i]; 77a7dea167SDimitry Andric if (Arg == "--serialize-diagnostics") { 78a7dea167SDimitry Andric // Skip the diagnostic output argument. 79a7dea167SDimitry Andric ++i; 80a7dea167SDimitry Andric continue; 81a7dea167SDimitry Andric } 82a7dea167SDimitry Andric AdjustedArgs.push_back(Args[i]); 83a7dea167SDimitry Andric } 84a7dea167SDimitry Andric return AdjustedArgs; 85a7dea167SDimitry Andric }; 86a7dea167SDimitry Andric } 87a7dea167SDimitry Andric 880b57cec5SDimitry Andric ArgumentsAdjuster getClangStripDependencyFileAdjuster() { 890b57cec5SDimitry Andric return [](const CommandLineArguments &Args, StringRef /*unused*/) { 900b57cec5SDimitry Andric CommandLineArguments AdjustedArgs; 910b57cec5SDimitry Andric for (size_t i = 0, e = Args.size(); i < e; ++i) { 920b57cec5SDimitry Andric StringRef Arg = Args[i]; 930b57cec5SDimitry Andric // All dependency-file options begin with -M. These include -MM, 940b57cec5SDimitry Andric // -MF, -MG, -MP, -MT, -MQ, -MD, and -MMD. 950b57cec5SDimitry Andric if (!Arg.startswith("-M")) { 960b57cec5SDimitry Andric AdjustedArgs.push_back(Args[i]); 970b57cec5SDimitry Andric continue; 980b57cec5SDimitry Andric } 990b57cec5SDimitry Andric 1000b57cec5SDimitry Andric if (Arg == "-MF" || Arg == "-MT" || Arg == "-MQ") 1010b57cec5SDimitry Andric // These flags take an argument: -MX foo. Skip the next argument also. 1020b57cec5SDimitry Andric ++i; 1030b57cec5SDimitry Andric } 1040b57cec5SDimitry Andric return AdjustedArgs; 1050b57cec5SDimitry Andric }; 1060b57cec5SDimitry Andric } 1070b57cec5SDimitry Andric 1080b57cec5SDimitry Andric ArgumentsAdjuster getInsertArgumentAdjuster(const CommandLineArguments &Extra, 1090b57cec5SDimitry Andric ArgumentInsertPosition Pos) { 1100b57cec5SDimitry Andric return [Extra, Pos](const CommandLineArguments &Args, StringRef /*unused*/) { 1110b57cec5SDimitry Andric CommandLineArguments Return(Args); 1120b57cec5SDimitry Andric 1130b57cec5SDimitry Andric CommandLineArguments::iterator I; 1140b57cec5SDimitry Andric if (Pos == ArgumentInsertPosition::END) { 1150b57cec5SDimitry Andric I = Return.end(); 1160b57cec5SDimitry Andric } else { 1170b57cec5SDimitry Andric I = Return.begin(); 1180b57cec5SDimitry Andric ++I; // To leave the program name in place 1190b57cec5SDimitry Andric } 1200b57cec5SDimitry Andric 1210b57cec5SDimitry Andric Return.insert(I, Extra.begin(), Extra.end()); 1220b57cec5SDimitry Andric return Return; 1230b57cec5SDimitry Andric }; 1240b57cec5SDimitry Andric } 1250b57cec5SDimitry Andric 1260b57cec5SDimitry Andric ArgumentsAdjuster getInsertArgumentAdjuster(const char *Extra, 1270b57cec5SDimitry Andric ArgumentInsertPosition Pos) { 1280b57cec5SDimitry Andric return getInsertArgumentAdjuster(CommandLineArguments(1, Extra), Pos); 1290b57cec5SDimitry Andric } 1300b57cec5SDimitry Andric 1310b57cec5SDimitry Andric ArgumentsAdjuster combineAdjusters(ArgumentsAdjuster First, 1320b57cec5SDimitry Andric ArgumentsAdjuster Second) { 1330b57cec5SDimitry Andric if (!First) 1340b57cec5SDimitry Andric return Second; 1350b57cec5SDimitry Andric if (!Second) 1360b57cec5SDimitry Andric return First; 1370b57cec5SDimitry Andric return [First, Second](const CommandLineArguments &Args, StringRef File) { 1380b57cec5SDimitry Andric return Second(First(Args, File), File); 1390b57cec5SDimitry Andric }; 1400b57cec5SDimitry Andric } 1410b57cec5SDimitry Andric 1420b57cec5SDimitry Andric ArgumentsAdjuster getStripPluginsAdjuster() { 1430b57cec5SDimitry Andric return [](const CommandLineArguments &Args, StringRef /*unused*/) { 1440b57cec5SDimitry Andric CommandLineArguments AdjustedArgs; 1450b57cec5SDimitry Andric for (size_t I = 0, E = Args.size(); I != E; I++) { 1460b57cec5SDimitry Andric // According to https://clang.llvm.org/docs/ClangPlugins.html 1470b57cec5SDimitry Andric // plugin arguments are in the form: 1480b57cec5SDimitry Andric // -Xclang {-load, -plugin, -plugin-arg-<plugin-name>, -add-plugin} 1490b57cec5SDimitry Andric // -Xclang <arbitrary-argument> 1500b57cec5SDimitry Andric if (I + 4 < E && Args[I] == "-Xclang" && 1510b57cec5SDimitry Andric (Args[I + 1] == "-load" || Args[I + 1] == "-plugin" || 1520b57cec5SDimitry Andric llvm::StringRef(Args[I + 1]).startswith("-plugin-arg-") || 1530b57cec5SDimitry Andric Args[I + 1] == "-add-plugin") && 1540b57cec5SDimitry Andric Args[I + 2] == "-Xclang") { 1550b57cec5SDimitry Andric I += 3; 1560b57cec5SDimitry Andric continue; 1570b57cec5SDimitry Andric } 1580b57cec5SDimitry Andric AdjustedArgs.push_back(Args[I]); 1590b57cec5SDimitry Andric } 1600b57cec5SDimitry Andric return AdjustedArgs; 1610b57cec5SDimitry Andric }; 1620b57cec5SDimitry Andric } 1630b57cec5SDimitry Andric 1640b57cec5SDimitry Andric } // end namespace tooling 1650b57cec5SDimitry Andric } // end namespace clang 166