1 //===--- Compiler.cpp --------------------------------------------*- C++-*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
10 #include "support/Logger.h"
11 #include "clang/Basic/TargetInfo.h"
12 #include "clang/Frontend/CompilerInvocation.h"
13 #include "clang/Lex/PreprocessorOptions.h"
14 #include "clang/Serialization/PCHContainerOperations.h"
15 #include "llvm/ADT/StringRef.h"
20 void IgnoreDiagnostics::log(DiagnosticsEngine::Level DiagLevel
,
21 const clang::Diagnostic
&Info
) {
22 // FIXME: format lazily, in case vlog is off.
23 llvm::SmallString
<64> Message
;
24 Info
.FormatDiagnostic(Message
);
26 llvm::SmallString
<64> Location
;
27 if (Info
.hasSourceManager() && Info
.getLocation().isValid()) {
28 auto &SourceMgr
= Info
.getSourceManager();
29 auto Loc
= SourceMgr
.getFileLoc(Info
.getLocation());
30 llvm::raw_svector_ostream
OS(Location
);
31 Loc
.print(OS
, SourceMgr
);
35 clangd::vlog("Ignored diagnostic. {0}{1}", Location
, Message
);
38 void IgnoreDiagnostics::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel
,
39 const clang::Diagnostic
&Info
) {
40 IgnoreDiagnostics::log(DiagLevel
, Info
);
43 static bool AllowCrashPragmasForTest
= false;
44 void allowCrashPragmasForTest() { AllowCrashPragmasForTest
= true; }
46 void disableUnsupportedOptions(CompilerInvocation
&CI
) {
47 // Disable "clang -verify" diagnostics, they are rarely useful in clangd, and
48 // our compiler invocation set-up doesn't seem to work with it (leading
49 // assertions in VerifyDiagnosticConsumer).
50 CI
.getDiagnosticOpts().VerifyDiagnostics
= false;
51 CI
.getDiagnosticOpts().ShowColors
= false;
53 // Disable any dependency outputting, we don't want to generate files or write
55 CI
.getDependencyOutputOpts().ShowIncludesDest
= ShowIncludesDestination::None
;
56 CI
.getDependencyOutputOpts().OutputFile
.clear();
57 CI
.getDependencyOutputOpts().HeaderIncludeOutputFile
.clear();
58 CI
.getDependencyOutputOpts().DOTOutputFile
.clear();
59 CI
.getDependencyOutputOpts().ModuleDependencyOutputDir
.clear();
61 // Disable any pch generation/usage operations. Since serialized preamble
62 // format is unstable, using an incompatible one might result in unexpected
63 // behaviours, including crashes.
64 CI
.getPreprocessorOpts().ImplicitPCHInclude
.clear();
65 CI
.getPreprocessorOpts().PrecompiledPreambleBytes
= {0, false};
66 CI
.getPreprocessorOpts().PCHThroughHeader
.clear();
67 CI
.getPreprocessorOpts().PCHWithHdrStop
= false;
68 CI
.getPreprocessorOpts().PCHWithHdrStopCreate
= false;
69 // Don't crash on `#pragma clang __debug parser_crash`
70 if (!AllowCrashPragmasForTest
)
71 CI
.getPreprocessorOpts().DisablePragmaDebugCrash
= true;
73 // Always default to raw container format as clangd doesn't registry any other
74 // and clang dies when faced with unknown formats.
75 CI
.getHeaderSearchOpts().ModuleFormat
=
76 PCHContainerOperations().getRawReader().getFormats().front().str();
78 CI
.getFrontendOpts().Plugins
.clear();
79 CI
.getFrontendOpts().AddPluginActions
.clear();
80 CI
.getFrontendOpts().PluginArgs
.clear();
81 CI
.getFrontendOpts().ProgramAction
= frontend::ParseSyntaxOnly
;
82 CI
.getFrontendOpts().ActionName
.clear();
84 // These options mostly affect codegen, and aren't relevant to clangd. And
85 // clang will die immediately when these files are not existed.
86 // Disable these uninteresting options to make clangd more robust.
87 CI
.getLangOpts().NoSanitizeFiles
.clear();
88 CI
.getLangOpts().XRayAttrListFiles
.clear();
89 CI
.getLangOpts().ProfileListFiles
.clear();
90 CI
.getLangOpts().XRayAlwaysInstrumentFiles
.clear();
91 CI
.getLangOpts().XRayNeverInstrumentFiles
.clear();
94 std::unique_ptr
<CompilerInvocation
>
95 buildCompilerInvocation(const ParseInputs
&Inputs
, clang::DiagnosticConsumer
&D
,
96 std::vector
<std::string
> *CC1Args
) {
97 llvm::ArrayRef
<std::string
> Argv
= Inputs
.CompileCommand
.CommandLine
;
100 std::vector
<const char *> ArgStrs
;
101 ArgStrs
.reserve(Argv
.size() + 1);
102 // In asserts builds, CompilerInvocation redundantly reads/parses cc1 args as
103 // a sanity test. This is not useful to clangd, and costs 10% of test time.
104 // To avoid mismatches between assert/production builds, disable it always.
105 ArgStrs
= {Argv
.front().c_str(), "-Xclang", "-no-round-trip-args"};
106 for (const auto &S
: Argv
.drop_front())
107 ArgStrs
.push_back(S
.c_str());
109 CreateInvocationOptions CIOpts
;
110 CIOpts
.VFS
= Inputs
.TFS
->view(Inputs
.CompileCommand
.Directory
);
111 CIOpts
.CC1Args
= CC1Args
;
112 CIOpts
.RecoverOnError
= true;
114 CompilerInstance::createDiagnostics(new DiagnosticOptions
, &D
, false);
115 CIOpts
.ProbePrecompiled
= false;
116 std::unique_ptr
<CompilerInvocation
> CI
= createInvocation(ArgStrs
, CIOpts
);
119 // createInvocationFromCommandLine sets DisableFree.
120 CI
->getFrontendOpts().DisableFree
= false;
121 CI
->getLangOpts().CommentOpts
.ParseAllComments
= true;
122 CI
->getLangOpts().RetainCommentsFromSystemHeaders
= true;
124 disableUnsupportedOptions(*CI
);
128 std::unique_ptr
<CompilerInstance
>
129 prepareCompilerInstance(std::unique_ptr
<clang::CompilerInvocation
> CI
,
130 const PrecompiledPreamble
*Preamble
,
131 std::unique_ptr
<llvm::MemoryBuffer
> Buffer
,
132 llvm::IntrusiveRefCntPtr
<llvm::vfs::FileSystem
> VFS
,
133 DiagnosticConsumer
&DiagsClient
) {
134 assert(VFS
&& "VFS is null");
135 assert(!CI
->getPreprocessorOpts().RetainRemappedFileBuffers
&&
136 "Setting RetainRemappedFileBuffers to true will cause a memory leak "
137 "of ContentsBuffer");
139 // NOTE: we use Buffer.get() when adding remapped files, so we have to make
140 // sure it will be released if no error is emitted.
142 Preamble
->OverridePreamble(*CI
, VFS
, Buffer
.get());
144 CI
->getPreprocessorOpts().addRemappedFile(
145 CI
->getFrontendOpts().Inputs
[0].getFile(), Buffer
.get());
148 auto Clang
= std::make_unique
<CompilerInstance
>(
149 std::make_shared
<PCHContainerOperations
>());
150 Clang
->setInvocation(std::move(CI
));
151 Clang
->createDiagnostics(&DiagsClient
, false);
153 if (auto VFSWithRemapping
= createVFSFromCompilerInvocation(
154 Clang
->getInvocation(), Clang
->getDiagnostics(), VFS
))
155 VFS
= VFSWithRemapping
;
156 Clang
->createFileManager(VFS
);
158 if (!Clang
->createTarget())
161 // RemappedFileBuffers will handle the lifetime of the Buffer pointer,
167 } // namespace clangd