Skip to content

Commit 40c1372

Browse files
committed
[Frontend] give createInvocationFromCommandLine an options struct
It's accumulating way too many optional params (see D124970) While here, improve the name and the documentation. Differential Revision: https://reviews.llvm.org/D124971
1 parent 99f31ac commit 40c1372

File tree

4 files changed

+70
-37
lines changed

4 files changed

+70
-37
lines changed

clang-tools-extra/clangd/Compiler.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -91,12 +91,13 @@ buildCompilerInvocation(const ParseInputs &Inputs, clang::DiagnosticConsumer &D,
9191
for (const auto &S : Inputs.CompileCommand.CommandLine)
9292
ArgStrs.push_back(S.c_str());
9393

94-
auto VFS = Inputs.TFS->view(Inputs.CompileCommand.Directory);
95-
llvm::IntrusiveRefCntPtr<DiagnosticsEngine> CommandLineDiagsEngine =
94+
CreateInvocationOptions CIOpts;
95+
CIOpts.VFS = Inputs.TFS->view(Inputs.CompileCommand.Directory);
96+
CIOpts.CC1Args = CC1Args;
97+
CIOpts.RecoverOnError = true;
98+
CIOpts.Diags =
9699
CompilerInstance::createDiagnostics(new DiagnosticOptions, &D, false);
97-
std::unique_ptr<CompilerInvocation> CI = createInvocationFromCommandLine(
98-
ArgStrs, CommandLineDiagsEngine, std::move(VFS),
99-
/*ShouldRecoverOnErrors=*/true, CC1Args);
100+
std::unique_ptr<CompilerInvocation> CI = createInvocation(ArgStrs, CIOpts);
100101
if (!CI)
101102
return nullptr;
102103
// createInvocationFromCommandLine sets DisableFree.

clang/include/clang/Frontend/Utils.h

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
#include "llvm/ADT/StringMap.h"
2323
#include "llvm/ADT/StringRef.h"
2424
#include "llvm/ADT/StringSet.h"
25-
#include "llvm/Option/OptSpecifier.h"
2625
#include "llvm/Support/FileCollector.h"
2726
#include "llvm/Support/VirtualFileSystem.h"
2827
#include <cstdint>
@@ -190,18 +189,47 @@ IntrusiveRefCntPtr<ExternalSemaSource>
190189
createChainedIncludesSource(CompilerInstance &CI,
191190
IntrusiveRefCntPtr<ExternalSemaSource> &Reader);
192191

193-
/// createInvocationFromCommandLine - Construct a compiler invocation object for
194-
/// a command line argument vector.
192+
/// Optional inputs to createInvocation.
193+
struct CreateInvocationOptions {
194+
/// Receives diagnostics encountered while parsing command-line flags.
195+
/// If not provided, these are printed to stderr.
196+
IntrusiveRefCntPtr<DiagnosticsEngine> Diags = nullptr;
197+
/// Used e.g. to probe for system headers locations.
198+
/// If not provided, the real filesystem is used.
199+
/// FIXME: the driver does perform some non-virtualized IO.
200+
IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS = nullptr;
201+
/// Whether to attempt to produce a non-null (possibly incorrect) invocation
202+
/// if any errors were encountered.
203+
/// By default, always return null on errors.
204+
bool RecoverOnError = false;
205+
/// If set, the target is populated with the cc1 args produced by the driver.
206+
/// This may be populated even if createInvocation returns nullptr.
207+
std::vector<std::string> *CC1Args = nullptr;
208+
};
209+
210+
/// Interpret clang arguments in preparation to parse a file.
211+
///
212+
/// This simulates a number of steps Clang takes when its driver is invoked:
213+
/// - choosing actions (e.g compile + link) to run
214+
/// - probing the system for settings like standard library locations
215+
/// - spawning a cc1 subprocess to compile code, with more explicit arguments
216+
/// - in the cc1 process, assembling those arguments into a CompilerInvocation
217+
/// which is used to configure the parser
195218
///
196-
/// \param ShouldRecoverOnErrors - whether we should attempt to return a
197-
/// non-null (and possibly incorrect) CompilerInvocation if any errors were
198-
/// encountered. When this flag is false, always return null on errors.
219+
/// This simulation is lossy, e.g. in some situations one driver run would
220+
/// result in multiple parses. (Multi-arch, CUDA, ...).
221+
/// This function tries to select a reasonable invocation that tools should use.
199222
///
200-
/// \param CC1Args - if non-null, will be populated with the args to cc1
201-
/// expanded from \p Args. May be set even if nullptr is returned.
223+
/// Args[0] should be the driver name, such as "clang" or "/usr/bin/g++".
224+
/// Absolute path is preferred - this affects searching for system headers.
202225
///
203-
/// \return A CompilerInvocation, or nullptr if none was built for the given
204-
/// argument vector.
226+
/// May return nullptr if an invocation could not be determined.
227+
/// See CreateInvocationOptions::ShouldRecoverOnErrors to try harder!
228+
std::unique_ptr<CompilerInvocation>
229+
createInvocation(ArrayRef<const char *> Args,
230+
CreateInvocationOptions Opts = {});
231+
232+
/// Deprecated version of createInvocation with individual optional args.
205233
std::unique_ptr<CompilerInvocation> createInvocationFromCommandLine(
206234
ArrayRef<const char *> Args,
207235
IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
@@ -210,8 +238,6 @@ std::unique_ptr<CompilerInvocation> createInvocationFromCommandLine(
210238
bool ShouldRecoverOnErrors = false,
211239
std::vector<std::string> *CC1Args = nullptr);
212240

213-
// Frontend timing utils
214-
215241
} // namespace clang
216242

217243
#endif // LLVM_CLANG_FRONTEND_UTILS_H

clang/lib/Frontend/CreateInvocationFromCommandLine.cpp

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,13 @@
2626
using namespace clang;
2727
using namespace llvm::opt;
2828

29-
std::unique_ptr<CompilerInvocation> clang::createInvocationFromCommandLine(
30-
ArrayRef<const char *> ArgList, IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
31-
IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, bool ShouldRecoverOnErorrs,
32-
std::vector<std::string> *CC1Args) {
29+
std::unique_ptr<CompilerInvocation>
30+
clang::createInvocation(ArrayRef<const char *> ArgList,
31+
CreateInvocationOptions Opts) {
3332
assert(!ArgList.empty());
34-
if (!Diags.get()) {
35-
// No diagnostics engine was provided, so create our own diagnostics object
36-
// with the default options.
37-
Diags = CompilerInstance::createDiagnostics(new DiagnosticOptions);
38-
}
33+
auto Diags = Opts.Diags
34+
? std::move(Opts.Diags)
35+
: CompilerInstance::createDiagnostics(new DiagnosticOptions);
3936

4037
SmallVector<const char *, 16> Args(ArgList.begin(), ArgList.end());
4138

@@ -47,7 +44,7 @@ std::unique_ptr<CompilerInvocation> clang::createInvocationFromCommandLine(
4744

4845
// FIXME: We shouldn't have to pass in the path info.
4946
driver::Driver TheDriver(Args[0], llvm::sys::getDefaultTargetTriple(), *Diags,
50-
"clang LLVM compiler", VFS);
47+
"clang LLVM compiler", Opts.VFS);
5148

5249
// Don't check that inputs exist, they may have been remapped.
5350
TheDriver.setCheckInputsExist(false);
@@ -81,7 +78,7 @@ std::unique_ptr<CompilerInvocation> clang::createInvocationFromCommandLine(
8178
}
8279
}
8380

84-
bool PickFirstOfMany = OffloadCompilation || ShouldRecoverOnErorrs;
81+
bool PickFirstOfMany = OffloadCompilation || Opts.RecoverOnError;
8582
if (Jobs.size() == 0 || (Jobs.size() > 1 && !PickFirstOfMany)) {
8683
SmallString<256> Msg;
8784
llvm::raw_svector_ostream OS(Msg);
@@ -98,11 +95,20 @@ std::unique_ptr<CompilerInvocation> clang::createInvocationFromCommandLine(
9895
}
9996

10097
const ArgStringList &CCArgs = Cmd->getArguments();
101-
if (CC1Args)
102-
*CC1Args = {CCArgs.begin(), CCArgs.end()};
98+
if (Opts.CC1Args)
99+
*Opts.CC1Args = {CCArgs.begin(), CCArgs.end()};
103100
auto CI = std::make_unique<CompilerInvocation>();
104101
if (!CompilerInvocation::CreateFromArgs(*CI, CCArgs, *Diags, Args[0]) &&
105-
!ShouldRecoverOnErorrs)
102+
!Opts.RecoverOnError)
106103
return nullptr;
107104
return CI;
108105
}
106+
107+
std::unique_ptr<CompilerInvocation> clang::createInvocationFromCommandLine(
108+
ArrayRef<const char *> Args, IntrusiveRefCntPtr<DiagnosticsEngine> Diags,
109+
IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, bool ShouldRecoverOnErrors,
110+
std::vector<std::string> *CC1Args) {
111+
return createInvocation(
112+
Args,
113+
CreateInvocationOptions{Diags, VFS, ShouldRecoverOnErrors, CC1Args});
114+
}

clang/unittests/Frontend/UtilsTest.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,12 @@ TEST(BuildCompilerInvocationTest, RecoverMultipleJobs) {
2323
std::vector<const char *> Args = {"clang", "--target=macho", "-arch", "i386",
2424
"-arch", "x86_64", "foo.cpp"};
2525
clang::IgnoringDiagConsumer D;
26-
llvm::IntrusiveRefCntPtr<DiagnosticsEngine> CommandLineDiagsEngine =
27-
clang::CompilerInstance::createDiagnostics(new DiagnosticOptions, &D,
28-
false);
29-
std::unique_ptr<CompilerInvocation> CI = createInvocationFromCommandLine(
30-
Args, CommandLineDiagsEngine, new llvm::vfs::InMemoryFileSystem(),
31-
/*ShouldRecoverOnErrors=*/true);
26+
CreateInvocationOptions Opts;
27+
Opts.RecoverOnError = true;
28+
Opts.Diags = clang::CompilerInstance::createDiagnostics(new DiagnosticOptions,
29+
&D, false);
30+
Opts.VFS = new llvm::vfs::InMemoryFileSystem();
31+
std::unique_ptr<CompilerInvocation> CI = createInvocation(Args, Opts);
3232
ASSERT_TRUE(CI);
3333
EXPECT_THAT(CI->TargetOpts->Triple, testing::StartsWith("i386-"));
3434
}

0 commit comments

Comments
 (0)