xref: /netbsd-src/external/apache2/llvm/dist/clang/lib/Tooling/CommonOptionsParser.cpp (revision e038c9c4676b0f19b1b7dd08a940c6ed64a6d5ae)
17330f729Sjoerg //===--- CommonOptionsParser.cpp - common options for clang tools ---------===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg //  This file implements the CommonOptionsParser class used to parse common
107330f729Sjoerg //  command-line options for clang tools, so that they can be run as separate
117330f729Sjoerg //  command-line applications with a consistent common interface for handling
127330f729Sjoerg //  compilation database and input files.
137330f729Sjoerg //
147330f729Sjoerg //  It provides a common subset of command-line options, common algorithm
157330f729Sjoerg //  for locating a compilation database and source files, and help messages
167330f729Sjoerg //  for the basic command-line interface.
177330f729Sjoerg //
187330f729Sjoerg //  It creates a CompilationDatabase and reads common command-line options.
197330f729Sjoerg //
207330f729Sjoerg //  This class uses the Clang Tooling infrastructure, see
217330f729Sjoerg //    http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
227330f729Sjoerg //  for details on setting it up with LLVM source tree.
237330f729Sjoerg //
247330f729Sjoerg //===----------------------------------------------------------------------===//
257330f729Sjoerg 
267330f729Sjoerg #include "clang/Tooling/CommonOptionsParser.h"
277330f729Sjoerg #include "clang/Tooling/Tooling.h"
287330f729Sjoerg #include "llvm/Support/CommandLine.h"
297330f729Sjoerg 
307330f729Sjoerg using namespace clang::tooling;
317330f729Sjoerg using namespace llvm;
327330f729Sjoerg 
337330f729Sjoerg const char *const CommonOptionsParser::HelpMessage =
347330f729Sjoerg     "\n"
357330f729Sjoerg     "-p <build-path> is used to read a compile command database.\n"
367330f729Sjoerg     "\n"
377330f729Sjoerg     "\tFor example, it can be a CMake build directory in which a file named\n"
387330f729Sjoerg     "\tcompile_commands.json exists (use -DCMAKE_EXPORT_COMPILE_COMMANDS=ON\n"
397330f729Sjoerg     "\tCMake option to get this output). When no build path is specified,\n"
407330f729Sjoerg     "\ta search for compile_commands.json will be attempted through all\n"
417330f729Sjoerg     "\tparent paths of the first input file . See:\n"
427330f729Sjoerg     "\thttps://clang.llvm.org/docs/HowToSetupToolingForLLVM.html for an\n"
437330f729Sjoerg     "\texample of setting up Clang Tooling on a source tree.\n"
447330f729Sjoerg     "\n"
457330f729Sjoerg     "<source0> ... specify the paths of source files. These paths are\n"
467330f729Sjoerg     "\tlooked up in the compile command database. If the path of a file is\n"
477330f729Sjoerg     "\tabsolute, it needs to point into CMake's source tree. If the path is\n"
487330f729Sjoerg     "\trelative, the current working directory needs to be in the CMake\n"
497330f729Sjoerg     "\tsource tree and the file must be in a subdirectory of the current\n"
507330f729Sjoerg     "\tworking directory. \"./\" prefixes in the relative files will be\n"
517330f729Sjoerg     "\tautomatically removed, but the rest of a relative path must be a\n"
527330f729Sjoerg     "\tsuffix of a path in the compile command database.\n"
537330f729Sjoerg     "\n";
547330f729Sjoerg 
appendArgumentsAdjuster(ArgumentsAdjuster Adjuster)557330f729Sjoerg void ArgumentsAdjustingCompilations::appendArgumentsAdjuster(
567330f729Sjoerg     ArgumentsAdjuster Adjuster) {
577330f729Sjoerg   Adjusters.push_back(std::move(Adjuster));
587330f729Sjoerg }
597330f729Sjoerg 
getCompileCommands(StringRef FilePath) const607330f729Sjoerg std::vector<CompileCommand> ArgumentsAdjustingCompilations::getCompileCommands(
617330f729Sjoerg     StringRef FilePath) const {
627330f729Sjoerg   return adjustCommands(Compilations->getCompileCommands(FilePath));
637330f729Sjoerg }
647330f729Sjoerg 
657330f729Sjoerg std::vector<std::string>
getAllFiles() const667330f729Sjoerg ArgumentsAdjustingCompilations::getAllFiles() const {
677330f729Sjoerg   return Compilations->getAllFiles();
687330f729Sjoerg }
697330f729Sjoerg 
707330f729Sjoerg std::vector<CompileCommand>
getAllCompileCommands() const717330f729Sjoerg ArgumentsAdjustingCompilations::getAllCompileCommands() const {
727330f729Sjoerg   return adjustCommands(Compilations->getAllCompileCommands());
737330f729Sjoerg }
747330f729Sjoerg 
adjustCommands(std::vector<CompileCommand> Commands) const757330f729Sjoerg std::vector<CompileCommand> ArgumentsAdjustingCompilations::adjustCommands(
767330f729Sjoerg     std::vector<CompileCommand> Commands) const {
777330f729Sjoerg   for (CompileCommand &Command : Commands)
787330f729Sjoerg     for (const auto &Adjuster : Adjusters)
797330f729Sjoerg       Command.CommandLine = Adjuster(Command.CommandLine, Command.Filename);
807330f729Sjoerg   return Commands;
817330f729Sjoerg }
827330f729Sjoerg 
init(int & argc,const char ** argv,cl::OptionCategory & Category,llvm::cl::NumOccurrencesFlag OccurrencesFlag,const char * Overview)837330f729Sjoerg llvm::Error CommonOptionsParser::init(
847330f729Sjoerg     int &argc, const char **argv, cl::OptionCategory &Category,
857330f729Sjoerg     llvm::cl::NumOccurrencesFlag OccurrencesFlag, const char *Overview) {
867330f729Sjoerg 
877330f729Sjoerg   static cl::opt<std::string> BuildPath("p", cl::desc("Build path"),
887330f729Sjoerg                                         cl::Optional, cl::cat(Category),
897330f729Sjoerg                                         cl::sub(*cl::AllSubCommands));
907330f729Sjoerg 
917330f729Sjoerg   static cl::list<std::string> SourcePaths(
927330f729Sjoerg       cl::Positional, cl::desc("<source0> [... <sourceN>]"), OccurrencesFlag,
937330f729Sjoerg       cl::cat(Category), cl::sub(*cl::AllSubCommands));
947330f729Sjoerg 
957330f729Sjoerg   static cl::list<std::string> ArgsAfter(
967330f729Sjoerg       "extra-arg",
977330f729Sjoerg       cl::desc("Additional argument to append to the compiler command line"),
987330f729Sjoerg       cl::cat(Category), cl::sub(*cl::AllSubCommands));
997330f729Sjoerg 
1007330f729Sjoerg   static cl::list<std::string> ArgsBefore(
1017330f729Sjoerg       "extra-arg-before",
1027330f729Sjoerg       cl::desc("Additional argument to prepend to the compiler command line"),
1037330f729Sjoerg       cl::cat(Category), cl::sub(*cl::AllSubCommands));
1047330f729Sjoerg 
1057330f729Sjoerg   cl::ResetAllOptionOccurrences();
1067330f729Sjoerg 
1077330f729Sjoerg   cl::HideUnrelatedOptions(Category);
1087330f729Sjoerg 
1097330f729Sjoerg   std::string ErrorMessage;
1107330f729Sjoerg   Compilations =
1117330f729Sjoerg       FixedCompilationDatabase::loadFromCommandLine(argc, argv, ErrorMessage);
1127330f729Sjoerg   if (!ErrorMessage.empty())
1137330f729Sjoerg     ErrorMessage.append("\n");
1147330f729Sjoerg   llvm::raw_string_ostream OS(ErrorMessage);
1157330f729Sjoerg   // Stop initializing if command-line option parsing failed.
1167330f729Sjoerg   if (!cl::ParseCommandLineOptions(argc, argv, Overview, &OS)) {
1177330f729Sjoerg     OS.flush();
118*e038c9c4Sjoerg     return llvm::make_error<llvm::StringError>(ErrorMessage,
1197330f729Sjoerg                                                llvm::inconvertibleErrorCode());
1207330f729Sjoerg   }
1217330f729Sjoerg 
1227330f729Sjoerg   cl::PrintOptionValues();
1237330f729Sjoerg 
1247330f729Sjoerg   SourcePathList = SourcePaths;
1257330f729Sjoerg   if ((OccurrencesFlag == cl::ZeroOrMore || OccurrencesFlag == cl::Optional) &&
1267330f729Sjoerg       SourcePathList.empty())
1277330f729Sjoerg     return llvm::Error::success();
1287330f729Sjoerg   if (!Compilations) {
1297330f729Sjoerg     if (!BuildPath.empty()) {
1307330f729Sjoerg       Compilations =
1317330f729Sjoerg           CompilationDatabase::autoDetectFromDirectory(BuildPath, ErrorMessage);
1327330f729Sjoerg     } else {
1337330f729Sjoerg       Compilations = CompilationDatabase::autoDetectFromSource(SourcePaths[0],
1347330f729Sjoerg                                                                ErrorMessage);
1357330f729Sjoerg     }
1367330f729Sjoerg     if (!Compilations) {
1377330f729Sjoerg       llvm::errs() << "Error while trying to load a compilation database:\n"
1387330f729Sjoerg                    << ErrorMessage << "Running without flags.\n";
1397330f729Sjoerg       Compilations.reset(
1407330f729Sjoerg           new FixedCompilationDatabase(".", std::vector<std::string>()));
1417330f729Sjoerg     }
1427330f729Sjoerg   }
1437330f729Sjoerg   auto AdjustingCompilations =
1447330f729Sjoerg       std::make_unique<ArgumentsAdjustingCompilations>(
1457330f729Sjoerg           std::move(Compilations));
1467330f729Sjoerg   Adjuster =
1477330f729Sjoerg       getInsertArgumentAdjuster(ArgsBefore, ArgumentInsertPosition::BEGIN);
1487330f729Sjoerg   Adjuster = combineAdjusters(
1497330f729Sjoerg       std::move(Adjuster),
1507330f729Sjoerg       getInsertArgumentAdjuster(ArgsAfter, ArgumentInsertPosition::END));
1517330f729Sjoerg   AdjustingCompilations->appendArgumentsAdjuster(Adjuster);
1527330f729Sjoerg   Compilations = std::move(AdjustingCompilations);
1537330f729Sjoerg   return llvm::Error::success();
1547330f729Sjoerg }
1557330f729Sjoerg 
create(int & argc,const char ** argv,llvm::cl::OptionCategory & Category,llvm::cl::NumOccurrencesFlag OccurrencesFlag,const char * Overview)1567330f729Sjoerg llvm::Expected<CommonOptionsParser> CommonOptionsParser::create(
1577330f729Sjoerg     int &argc, const char **argv, llvm::cl::OptionCategory &Category,
1587330f729Sjoerg     llvm::cl::NumOccurrencesFlag OccurrencesFlag, const char *Overview) {
1597330f729Sjoerg   CommonOptionsParser Parser;
1607330f729Sjoerg   llvm::Error Err =
1617330f729Sjoerg       Parser.init(argc, argv, Category, OccurrencesFlag, Overview);
1627330f729Sjoerg   if (Err)
1637330f729Sjoerg     return std::move(Err);
1647330f729Sjoerg   return std::move(Parser);
1657330f729Sjoerg }
1667330f729Sjoerg 
CommonOptionsParser(int & argc,const char ** argv,cl::OptionCategory & Category,llvm::cl::NumOccurrencesFlag OccurrencesFlag,const char * Overview)1677330f729Sjoerg CommonOptionsParser::CommonOptionsParser(
1687330f729Sjoerg     int &argc, const char **argv, cl::OptionCategory &Category,
1697330f729Sjoerg     llvm::cl::NumOccurrencesFlag OccurrencesFlag, const char *Overview) {
1707330f729Sjoerg   llvm::Error Err = init(argc, argv, Category, OccurrencesFlag, Overview);
1717330f729Sjoerg   if (Err) {
1727330f729Sjoerg     llvm::report_fatal_error(
1737330f729Sjoerg         "CommonOptionsParser: failed to parse command-line arguments. " +
1747330f729Sjoerg         llvm::toString(std::move(Err)));
1757330f729Sjoerg   }
1767330f729Sjoerg }
177