annotate clang/lib/Tooling/CommonOptionsParser.cpp @ 176:de4ac79aef9d

...
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 25 May 2020 17:13:11 +0900
parents 1d019706d866
children 2e18cbf3894f
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
150
anatofuz
parents:
diff changeset
1 //===--- CommonOptionsParser.cpp - common options for clang tools ---------===//
anatofuz
parents:
diff changeset
2 //
anatofuz
parents:
diff changeset
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
anatofuz
parents:
diff changeset
4 // See https://llvm.org/LICENSE.txt for license information.
anatofuz
parents:
diff changeset
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
anatofuz
parents:
diff changeset
6 //
anatofuz
parents:
diff changeset
7 //===----------------------------------------------------------------------===//
anatofuz
parents:
diff changeset
8 //
anatofuz
parents:
diff changeset
9 // This file implements the CommonOptionsParser class used to parse common
anatofuz
parents:
diff changeset
10 // command-line options for clang tools, so that they can be run as separate
anatofuz
parents:
diff changeset
11 // command-line applications with a consistent common interface for handling
anatofuz
parents:
diff changeset
12 // compilation database and input files.
anatofuz
parents:
diff changeset
13 //
anatofuz
parents:
diff changeset
14 // It provides a common subset of command-line options, common algorithm
anatofuz
parents:
diff changeset
15 // for locating a compilation database and source files, and help messages
anatofuz
parents:
diff changeset
16 // for the basic command-line interface.
anatofuz
parents:
diff changeset
17 //
anatofuz
parents:
diff changeset
18 // It creates a CompilationDatabase and reads common command-line options.
anatofuz
parents:
diff changeset
19 //
anatofuz
parents:
diff changeset
20 // This class uses the Clang Tooling infrastructure, see
anatofuz
parents:
diff changeset
21 // http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html
anatofuz
parents:
diff changeset
22 // for details on setting it up with LLVM source tree.
anatofuz
parents:
diff changeset
23 //
anatofuz
parents:
diff changeset
24 //===----------------------------------------------------------------------===//
anatofuz
parents:
diff changeset
25
anatofuz
parents:
diff changeset
26 #include "clang/Tooling/CommonOptionsParser.h"
anatofuz
parents:
diff changeset
27 #include "clang/Tooling/Tooling.h"
anatofuz
parents:
diff changeset
28 #include "llvm/Support/CommandLine.h"
anatofuz
parents:
diff changeset
29
anatofuz
parents:
diff changeset
30 using namespace clang::tooling;
anatofuz
parents:
diff changeset
31 using namespace llvm;
anatofuz
parents:
diff changeset
32
anatofuz
parents:
diff changeset
33 const char *const CommonOptionsParser::HelpMessage =
anatofuz
parents:
diff changeset
34 "\n"
anatofuz
parents:
diff changeset
35 "-p <build-path> is used to read a compile command database.\n"
anatofuz
parents:
diff changeset
36 "\n"
anatofuz
parents:
diff changeset
37 "\tFor example, it can be a CMake build directory in which a file named\n"
anatofuz
parents:
diff changeset
38 "\tcompile_commands.json exists (use -DCMAKE_EXPORT_COMPILE_COMMANDS=ON\n"
anatofuz
parents:
diff changeset
39 "\tCMake option to get this output). When no build path is specified,\n"
anatofuz
parents:
diff changeset
40 "\ta search for compile_commands.json will be attempted through all\n"
anatofuz
parents:
diff changeset
41 "\tparent paths of the first input file . See:\n"
anatofuz
parents:
diff changeset
42 "\thttps://clang.llvm.org/docs/HowToSetupToolingForLLVM.html for an\n"
anatofuz
parents:
diff changeset
43 "\texample of setting up Clang Tooling on a source tree.\n"
anatofuz
parents:
diff changeset
44 "\n"
anatofuz
parents:
diff changeset
45 "<source0> ... specify the paths of source files. These paths are\n"
anatofuz
parents:
diff changeset
46 "\tlooked up in the compile command database. If the path of a file is\n"
anatofuz
parents:
diff changeset
47 "\tabsolute, it needs to point into CMake's source tree. If the path is\n"
anatofuz
parents:
diff changeset
48 "\trelative, the current working directory needs to be in the CMake\n"
anatofuz
parents:
diff changeset
49 "\tsource tree and the file must be in a subdirectory of the current\n"
anatofuz
parents:
diff changeset
50 "\tworking directory. \"./\" prefixes in the relative files will be\n"
anatofuz
parents:
diff changeset
51 "\tautomatically removed, but the rest of a relative path must be a\n"
anatofuz
parents:
diff changeset
52 "\tsuffix of a path in the compile command database.\n"
anatofuz
parents:
diff changeset
53 "\n";
anatofuz
parents:
diff changeset
54
anatofuz
parents:
diff changeset
55 void ArgumentsAdjustingCompilations::appendArgumentsAdjuster(
anatofuz
parents:
diff changeset
56 ArgumentsAdjuster Adjuster) {
anatofuz
parents:
diff changeset
57 Adjusters.push_back(std::move(Adjuster));
anatofuz
parents:
diff changeset
58 }
anatofuz
parents:
diff changeset
59
anatofuz
parents:
diff changeset
60 std::vector<CompileCommand> ArgumentsAdjustingCompilations::getCompileCommands(
anatofuz
parents:
diff changeset
61 StringRef FilePath) const {
anatofuz
parents:
diff changeset
62 return adjustCommands(Compilations->getCompileCommands(FilePath));
anatofuz
parents:
diff changeset
63 }
anatofuz
parents:
diff changeset
64
anatofuz
parents:
diff changeset
65 std::vector<std::string>
anatofuz
parents:
diff changeset
66 ArgumentsAdjustingCompilations::getAllFiles() const {
anatofuz
parents:
diff changeset
67 return Compilations->getAllFiles();
anatofuz
parents:
diff changeset
68 }
anatofuz
parents:
diff changeset
69
anatofuz
parents:
diff changeset
70 std::vector<CompileCommand>
anatofuz
parents:
diff changeset
71 ArgumentsAdjustingCompilations::getAllCompileCommands() const {
anatofuz
parents:
diff changeset
72 return adjustCommands(Compilations->getAllCompileCommands());
anatofuz
parents:
diff changeset
73 }
anatofuz
parents:
diff changeset
74
anatofuz
parents:
diff changeset
75 std::vector<CompileCommand> ArgumentsAdjustingCompilations::adjustCommands(
anatofuz
parents:
diff changeset
76 std::vector<CompileCommand> Commands) const {
anatofuz
parents:
diff changeset
77 for (CompileCommand &Command : Commands)
anatofuz
parents:
diff changeset
78 for (const auto &Adjuster : Adjusters)
anatofuz
parents:
diff changeset
79 Command.CommandLine = Adjuster(Command.CommandLine, Command.Filename);
anatofuz
parents:
diff changeset
80 return Commands;
anatofuz
parents:
diff changeset
81 }
anatofuz
parents:
diff changeset
82
anatofuz
parents:
diff changeset
83 llvm::Error CommonOptionsParser::init(
anatofuz
parents:
diff changeset
84 int &argc, const char **argv, cl::OptionCategory &Category,
anatofuz
parents:
diff changeset
85 llvm::cl::NumOccurrencesFlag OccurrencesFlag, const char *Overview) {
anatofuz
parents:
diff changeset
86
anatofuz
parents:
diff changeset
87 static cl::opt<std::string> BuildPath("p", cl::desc("Build path"),
anatofuz
parents:
diff changeset
88 cl::Optional, cl::cat(Category),
anatofuz
parents:
diff changeset
89 cl::sub(*cl::AllSubCommands));
anatofuz
parents:
diff changeset
90
anatofuz
parents:
diff changeset
91 static cl::list<std::string> SourcePaths(
anatofuz
parents:
diff changeset
92 cl::Positional, cl::desc("<source0> [... <sourceN>]"), OccurrencesFlag,
anatofuz
parents:
diff changeset
93 cl::cat(Category), cl::sub(*cl::AllSubCommands));
anatofuz
parents:
diff changeset
94
anatofuz
parents:
diff changeset
95 static cl::list<std::string> ArgsAfter(
anatofuz
parents:
diff changeset
96 "extra-arg",
anatofuz
parents:
diff changeset
97 cl::desc("Additional argument to append to the compiler command line"),
anatofuz
parents:
diff changeset
98 cl::cat(Category), cl::sub(*cl::AllSubCommands));
anatofuz
parents:
diff changeset
99
anatofuz
parents:
diff changeset
100 static cl::list<std::string> ArgsBefore(
anatofuz
parents:
diff changeset
101 "extra-arg-before",
anatofuz
parents:
diff changeset
102 cl::desc("Additional argument to prepend to the compiler command line"),
anatofuz
parents:
diff changeset
103 cl::cat(Category), cl::sub(*cl::AllSubCommands));
anatofuz
parents:
diff changeset
104
anatofuz
parents:
diff changeset
105 cl::ResetAllOptionOccurrences();
anatofuz
parents:
diff changeset
106
anatofuz
parents:
diff changeset
107 cl::HideUnrelatedOptions(Category);
anatofuz
parents:
diff changeset
108
anatofuz
parents:
diff changeset
109 std::string ErrorMessage;
anatofuz
parents:
diff changeset
110 Compilations =
anatofuz
parents:
diff changeset
111 FixedCompilationDatabase::loadFromCommandLine(argc, argv, ErrorMessage);
anatofuz
parents:
diff changeset
112 if (!ErrorMessage.empty())
anatofuz
parents:
diff changeset
113 ErrorMessage.append("\n");
anatofuz
parents:
diff changeset
114 llvm::raw_string_ostream OS(ErrorMessage);
anatofuz
parents:
diff changeset
115 // Stop initializing if command-line option parsing failed.
anatofuz
parents:
diff changeset
116 if (!cl::ParseCommandLineOptions(argc, argv, Overview, &OS)) {
anatofuz
parents:
diff changeset
117 OS.flush();
anatofuz
parents:
diff changeset
118 return llvm::make_error<llvm::StringError>("[CommonOptionsParser]: " +
anatofuz
parents:
diff changeset
119 ErrorMessage,
anatofuz
parents:
diff changeset
120 llvm::inconvertibleErrorCode());
anatofuz
parents:
diff changeset
121 }
anatofuz
parents:
diff changeset
122
anatofuz
parents:
diff changeset
123 cl::PrintOptionValues();
anatofuz
parents:
diff changeset
124
anatofuz
parents:
diff changeset
125 SourcePathList = SourcePaths;
anatofuz
parents:
diff changeset
126 if ((OccurrencesFlag == cl::ZeroOrMore || OccurrencesFlag == cl::Optional) &&
anatofuz
parents:
diff changeset
127 SourcePathList.empty())
anatofuz
parents:
diff changeset
128 return llvm::Error::success();
anatofuz
parents:
diff changeset
129 if (!Compilations) {
anatofuz
parents:
diff changeset
130 if (!BuildPath.empty()) {
anatofuz
parents:
diff changeset
131 Compilations =
anatofuz
parents:
diff changeset
132 CompilationDatabase::autoDetectFromDirectory(BuildPath, ErrorMessage);
anatofuz
parents:
diff changeset
133 } else {
anatofuz
parents:
diff changeset
134 Compilations = CompilationDatabase::autoDetectFromSource(SourcePaths[0],
anatofuz
parents:
diff changeset
135 ErrorMessage);
anatofuz
parents:
diff changeset
136 }
anatofuz
parents:
diff changeset
137 if (!Compilations) {
anatofuz
parents:
diff changeset
138 llvm::errs() << "Error while trying to load a compilation database:\n"
anatofuz
parents:
diff changeset
139 << ErrorMessage << "Running without flags.\n";
anatofuz
parents:
diff changeset
140 Compilations.reset(
anatofuz
parents:
diff changeset
141 new FixedCompilationDatabase(".", std::vector<std::string>()));
anatofuz
parents:
diff changeset
142 }
anatofuz
parents:
diff changeset
143 }
anatofuz
parents:
diff changeset
144 auto AdjustingCompilations =
anatofuz
parents:
diff changeset
145 std::make_unique<ArgumentsAdjustingCompilations>(
anatofuz
parents:
diff changeset
146 std::move(Compilations));
anatofuz
parents:
diff changeset
147 Adjuster =
anatofuz
parents:
diff changeset
148 getInsertArgumentAdjuster(ArgsBefore, ArgumentInsertPosition::BEGIN);
anatofuz
parents:
diff changeset
149 Adjuster = combineAdjusters(
anatofuz
parents:
diff changeset
150 std::move(Adjuster),
anatofuz
parents:
diff changeset
151 getInsertArgumentAdjuster(ArgsAfter, ArgumentInsertPosition::END));
anatofuz
parents:
diff changeset
152 AdjustingCompilations->appendArgumentsAdjuster(Adjuster);
anatofuz
parents:
diff changeset
153 Compilations = std::move(AdjustingCompilations);
anatofuz
parents:
diff changeset
154 return llvm::Error::success();
anatofuz
parents:
diff changeset
155 }
anatofuz
parents:
diff changeset
156
anatofuz
parents:
diff changeset
157 llvm::Expected<CommonOptionsParser> CommonOptionsParser::create(
anatofuz
parents:
diff changeset
158 int &argc, const char **argv, llvm::cl::OptionCategory &Category,
anatofuz
parents:
diff changeset
159 llvm::cl::NumOccurrencesFlag OccurrencesFlag, const char *Overview) {
anatofuz
parents:
diff changeset
160 CommonOptionsParser Parser;
anatofuz
parents:
diff changeset
161 llvm::Error Err =
anatofuz
parents:
diff changeset
162 Parser.init(argc, argv, Category, OccurrencesFlag, Overview);
anatofuz
parents:
diff changeset
163 if (Err)
anatofuz
parents:
diff changeset
164 return std::move(Err);
anatofuz
parents:
diff changeset
165 return std::move(Parser);
anatofuz
parents:
diff changeset
166 }
anatofuz
parents:
diff changeset
167
anatofuz
parents:
diff changeset
168 CommonOptionsParser::CommonOptionsParser(
anatofuz
parents:
diff changeset
169 int &argc, const char **argv, cl::OptionCategory &Category,
anatofuz
parents:
diff changeset
170 llvm::cl::NumOccurrencesFlag OccurrencesFlag, const char *Overview) {
anatofuz
parents:
diff changeset
171 llvm::Error Err = init(argc, argv, Category, OccurrencesFlag, Overview);
anatofuz
parents:
diff changeset
172 if (Err) {
anatofuz
parents:
diff changeset
173 llvm::report_fatal_error(
anatofuz
parents:
diff changeset
174 "CommonOptionsParser: failed to parse command-line arguments. " +
anatofuz
parents:
diff changeset
175 llvm::toString(std::move(Err)));
anatofuz
parents:
diff changeset
176 }
anatofuz
parents:
diff changeset
177 }