@@ -133,14 +133,14 @@ ClangdServer::Options::operator TUScheduler::Options() const {
133
133
Opts.StorePreamblesInMemory = StorePreamblesInMemory;
134
134
Opts.UpdateDebounce = UpdateDebounce;
135
135
Opts.AsyncPreambleBuilds = AsyncPreambleBuilds;
136
+ Opts.ContextProvider = ContextProvider;
136
137
return Opts;
137
138
}
138
139
139
140
ClangdServer::ClangdServer (const GlobalCompilationDatabase &CDB,
140
141
const ThreadsafeFS &TFS, const Options &Opts,
141
142
Callbacks *Callbacks)
142
- : ConfigProvider(Opts.ConfigProvider), CDB(CDB), TFS(TFS),
143
- ServerCallbacks(Callbacks),
143
+ : CDB(CDB), TFS(TFS),
144
144
DynamicIdx(Opts.BuildDynamicSymbolIndex
145
145
? new FileIndex(Opts.HeavyweightDynamicSymbolIndex,
146
146
Opts.CollectMainFileRefs)
@@ -153,14 +153,7 @@ ClangdServer::ClangdServer(const GlobalCompilationDatabase &CDB,
153
153
// FIXME(ioeric): this can be slow and we may be able to index on less
154
154
// critical paths.
155
155
WorkScheduler(
156
- CDB,
157
- [&, this ] {
158
- TUScheduler::Options O (Opts);
159
- O.ContextProvider = [this ](PathRef P) {
160
- return createProcessingContext (P);
161
- };
162
- return O;
163
- }(),
156
+ CDB, TUScheduler::Options(Opts),
164
157
std::make_unique<UpdateIndexCallbacks>(
165
158
DynamicIdx.get(), Callbacks, Opts.TheiaSemanticHighlighting)) {
166
159
// Adds an index to the stack, at higher priority than existing indexes.
@@ -181,9 +174,7 @@ ClangdServer::ClangdServer(const GlobalCompilationDatabase &CDB,
181
174
if (Callbacks)
182
175
Callbacks->onBackgroundIndexProgress (S);
183
176
};
184
- BGOpts.ContextProvider = [this ](PathRef P) {
185
- return createProcessingContext (P);
186
- };
177
+ BGOpts.ContextProvider = Opts.ContextProvider ;
187
178
BGOpts.CollectMainFileRefs = Opts.CollectMainFileRefs ;
188
179
BackgroundIdx = std::make_unique<BackgroundIndex>(
189
180
TFS, CDB,
@@ -216,6 +207,83 @@ void ClangdServer::addDocument(PathRef File, llvm::StringRef Contents,
216
207
BackgroundIdx->boostRelated (File);
217
208
}
218
209
210
+ std::function<Context(PathRef)>
211
+ ClangdServer::createConfiguredContextProvider (const config::Provider *Provider,
212
+ Callbacks *Publish) {
213
+ if (!Provider)
214
+ return [](llvm::StringRef) { return Context::current ().clone (); };
215
+
216
+ struct Impl {
217
+ const config::Provider *Provider;
218
+ ClangdServer::Callbacks *Publish;
219
+ std::mutex PublishMu;
220
+
221
+ Impl (const config::Provider *Provider, ClangdServer::Callbacks *Publish)
222
+ : Provider(Provider), Publish(Publish) {}
223
+
224
+ Context operator ()(llvm::StringRef File) {
225
+ config::Params Params;
226
+ // Don't reread config files excessively often.
227
+ // FIXME: when we see a config file change event, use the event timestamp?
228
+ Params.FreshTime =
229
+ std::chrono::steady_clock::now () - std::chrono::seconds (5 );
230
+ llvm::SmallString<256 > PosixPath;
231
+ if (!File.empty ()) {
232
+ assert (llvm::sys::path::is_absolute (File));
233
+ llvm::sys::path::native (File, PosixPath, llvm::sys::path::Style::posix);
234
+ Params.Path = PosixPath.str ();
235
+ }
236
+
237
+ llvm::StringMap<std::vector<Diag>> ReportableDiagnostics;
238
+ Config C = Provider->getConfig (Params, [&](const llvm::SMDiagnostic &D) {
239
+ // Create the map entry even for note diagnostics we don't report.
240
+ // This means that when the file is parsed with no warnings, we
241
+ // publish an empty set of diagnostics, clearing any the client has.
242
+ handleDiagnostic (D, !Publish || D.getFilename ().empty ()
243
+ ? nullptr
244
+ : &ReportableDiagnostics[D.getFilename ()]);
245
+ });
246
+ // Blindly publish diagnostics for the (unopened) parsed config files.
247
+ // We must avoid reporting diagnostics for *the same file* concurrently.
248
+ // Source diags are published elsewhere, but those are different files.
249
+ if (!ReportableDiagnostics.empty ()) {
250
+ std::lock_guard<std::mutex> Lock (PublishMu);
251
+ for (auto &Entry : ReportableDiagnostics)
252
+ Publish->onDiagnosticsReady (Entry.first (), /* Version=*/ " " ,
253
+ std::move (Entry.second ));
254
+ }
255
+ return Context::current ().derive (Config::Key, std::move (C));
256
+ }
257
+
258
+ void handleDiagnostic (const llvm::SMDiagnostic &D,
259
+ std::vector<Diag> *ClientDiagnostics) {
260
+ switch (D.getKind ()) {
261
+ case llvm::SourceMgr::DK_Error:
262
+ elog (" config error at {0}:{1}:{2}: {3}" , D.getFilename (), D.getLineNo (),
263
+ D.getColumnNo (), D.getMessage ());
264
+ break ;
265
+ case llvm::SourceMgr::DK_Warning:
266
+ log (" config warning at {0}:{1}:{2}: {3}" , D.getFilename (),
267
+ D.getLineNo (), D.getColumnNo (), D.getMessage ());
268
+ break ;
269
+ case llvm::SourceMgr::DK_Note:
270
+ case llvm::SourceMgr::DK_Remark:
271
+ vlog (" config note at {0}:{1}:{2}: {3}" , D.getFilename (), D.getLineNo (),
272
+ D.getColumnNo (), D.getMessage ());
273
+ ClientDiagnostics = nullptr ; // Don't emit notes as LSP diagnostics.
274
+ break ;
275
+ }
276
+ if (ClientDiagnostics)
277
+ ClientDiagnostics->push_back (toDiag (D, Diag::ClangdConfig));
278
+ }
279
+ };
280
+
281
+ // Copyable wrapper.
282
+ return [I (std::make_shared<Impl>(Provider, Publish))](llvm::StringRef Path) {
283
+ return (*I)(Path);
284
+ };
285
+ }
286
+
219
287
void ClangdServer::removeDocument (PathRef File) { WorkScheduler.remove (File); }
220
288
221
289
void ClangdServer::codeComplete (PathRef File, Position Pos,
@@ -802,62 +870,6 @@ llvm::StringMap<TUScheduler::FileStats> ClangdServer::fileStats() const {
802
870
return WorkScheduler.fileStats ();
803
871
}
804
872
805
- Context ClangdServer::createProcessingContext (PathRef File) const {
806
- if (!ConfigProvider)
807
- return Context::current ().clone ();
808
-
809
- config::Params Params;
810
- // Don't reread config files excessively often.
811
- // FIXME: when we see a config file change event, use the event timestamp.
812
- Params.FreshTime = std::chrono::steady_clock::now () - std::chrono::seconds (5 );
813
- llvm::SmallString<256 > PosixPath;
814
- if (!File.empty ()) {
815
- assert (llvm::sys::path::is_absolute (File));
816
- llvm::sys::path::native (File, PosixPath, llvm::sys::path::Style::posix);
817
- Params.Path = PosixPath.str ();
818
- }
819
-
820
- llvm::StringMap<std::vector<Diag>> ReportableDiagnostics;
821
- auto ConfigDiagnosticHandler = [&](const llvm::SMDiagnostic &D) {
822
- // Ensure we create the map entry even for note diagnostics we don't report.
823
- // This means that when the file is parsed with no warnings, we'll
824
- // publish an empty set of diagnostics, clearing any the client has.
825
- auto *Reportable = D.getFilename ().empty ()
826
- ? nullptr
827
- : &ReportableDiagnostics[D.getFilename ()];
828
- switch (D.getKind ()) {
829
- case llvm::SourceMgr::DK_Error:
830
- elog (" config error at {0}:{1}:{2}: {3}" , D.getFilename (), D.getLineNo (),
831
- D.getColumnNo (), D.getMessage ());
832
- if (Reportable)
833
- Reportable->push_back (toDiag (D, Diag::ClangdConfig));
834
- break ;
835
- case llvm::SourceMgr::DK_Warning:
836
- log (" config warning at {0}:{1}:{2}: {3}" , D.getFilename (), D.getLineNo (),
837
- D.getColumnNo (), D.getMessage ());
838
- if (Reportable)
839
- Reportable->push_back (toDiag (D, Diag::ClangdConfig));
840
- break ;
841
- case llvm::SourceMgr::DK_Note:
842
- case llvm::SourceMgr::DK_Remark:
843
- vlog (" config note at {0}:{1}:{2}: {3}" , D.getFilename (), D.getLineNo (),
844
- D.getColumnNo (), D.getMessage ());
845
- break ;
846
- }
847
- };
848
- Config C = ConfigProvider->getConfig (Params, ConfigDiagnosticHandler);
849
- // Blindly publish diagnostics for the (unopened) parsed config files.
850
- // We must avoid reporting diagnostics for *the same file* concurrently.
851
- // Source file diags are published elsewhere, but those are different files.
852
- if (!ReportableDiagnostics.empty ()) {
853
- std::lock_guard<std::mutex> Lock (ConfigDiagnosticsMu);
854
- for (auto &Entry : ReportableDiagnostics)
855
- ServerCallbacks->onDiagnosticsReady (Entry.first (), /* Version=*/ " " ,
856
- std::move (Entry.second ));
857
- }
858
- return Context::current ().derive (Config::Key, std::move (C));
859
- }
860
-
861
873
LLVM_NODISCARD bool
862
874
ClangdServer::blockUntilIdleForTest (llvm::Optional<double > TimeoutSeconds) {
863
875
return WorkScheduler.blockUntilIdle (timeoutSeconds (TimeoutSeconds)) &&
0 commit comments