[clangd] Add option to use dirty file contents when building preambles.

Adds a option `use-dirty-preambles` to enable using unsaved in editor contents when building pre-ambles.
This enables a more seamless user experience when switching between header and implementation files and forgetting to save inbetween.
It's also in line with the LSP spec that states open files in the editor should be used instead of on the contents on disk - https://microsoft.github.io/language-server-protocol/overviews/lsp/overview/
For now the option is defaulted to off and hidden, Though I have a feeling it should be moved into the `.clangd` config and possibly defaulted to true.

Addresses https://github.com/clangd/clangd/issues/488

Reviewed By: sammccall

Differential Revision: https://reviews.llvm.org/D95046
This commit is contained in:
Nathan James 2022-01-17 10:55:35 +00:00
parent ca2ac2bb14
commit 8b88ff0803
No known key found for this signature in database
GPG Key ID: CC007AFCDA90AA5F
3 changed files with 18 additions and 4 deletions

View File

@ -156,7 +156,7 @@ ClangdServer::ClangdServer(const GlobalCompilationDatabase &CDB,
: FeatureModules(Opts.FeatureModules), CDB(CDB), TFS(TFS),
DynamicIdx(Opts.BuildDynamicSymbolIndex ? new FileIndex() : nullptr),
ClangTidyProvider(Opts.ClangTidyProvider),
WorkspaceRoot(Opts.WorkspaceRoot),
UseDirtyHeaders(Opts.UseDirtyHeaders), WorkspaceRoot(Opts.WorkspaceRoot),
Transient(Opts.ImplicitCancellation ? TUScheduler::InvalidateOnUpdate
: TUScheduler::NoInvalidation),
DirtyFS(std::make_unique<DraftStoreFS>(TFS, DraftMgr)) {
@ -228,7 +228,7 @@ void ClangdServer::addDocument(PathRef File, llvm::StringRef Contents,
// Compile command is set asynchronously during update, as it can be slow.
ParseInputs Inputs;
Inputs.TFS = &TFS;
Inputs.TFS = &getHeaderFS();
Inputs.Contents = std::string(Contents);
Inputs.Version = std::move(ActualVersion);
Inputs.ForceRebuild = ForceRebuild;
@ -368,7 +368,7 @@ void ClangdServer::codeComplete(PathRef File, Position Pos,
SpecFuzzyFind->CachedReq = CachedCompletionFuzzyFindRequestByFile[File];
}
}
ParseInputs ParseInput{IP->Command, &TFS, IP->Contents.str()};
ParseInputs ParseInput{IP->Command, &getHeaderFS(), IP->Contents.str()};
// FIXME: Add traling new line if there is none at eof, workaround a crash,
// see https://github.com/clangd/clangd/issues/332
if (!IP->Contents.endswith("\n"))
@ -420,7 +420,7 @@ void ClangdServer::signatureHelp(PathRef File, Position Pos,
if (!PreambleData)
return CB(error("Failed to parse includes"));
ParseInputs ParseInput{IP->Command, &TFS, IP->Contents.str()};
ParseInputs ParseInput{IP->Command, &getHeaderFS(), IP->Contents.str()};
// FIXME: Add traling new line if there is none at eof, workaround a crash,
// see https://github.com/clangd/clangd/issues/332
if (!IP->Contents.endswith("\n"))

View File

@ -165,6 +165,8 @@ public:
bool FoldingRanges = false;
FeatureModuleSet *FeatureModules = nullptr;
/// If true, use the dirty buffer contents when building Preambles.
bool UseDirtyHeaders = false;
explicit operator TUScheduler::Options() const;
};
@ -394,6 +396,9 @@ public:
private:
FeatureModuleSet *FeatureModules;
const GlobalCompilationDatabase &CDB;
const ThreadsafeFS &getHeaderFS() const {
return UseDirtyHeaders ? *DirtyFS : TFS;
}
const ThreadsafeFS &TFS;
Path ResourceDir;
@ -413,6 +418,8 @@ private:
// When set, provides clang-tidy options for a specific file.
TidyProviderRef ClangTidyProvider;
bool UseDirtyHeaders = false;
// GUARDED_BY(CachedCompletionFuzzyFindRequestMutex)
llvm::StringMap<llvm::Optional<FuzzyFindRequest>>
CachedCompletionFuzzyFindRequestByFile;

View File

@ -492,6 +492,12 @@ opt<bool> EnableConfig{
init(true),
};
opt<bool> UseDirtyHeaders{"use-dirty-headers", cat(Misc),
desc("Use files open in the editor when parsing "
"headers instead of reading from the disk"),
Hidden,
init(ClangdServer::Options().UseDirtyHeaders)};
#if defined(__GLIBC__) && CLANGD_MALLOC_TRIM
opt<bool> EnableMallocTrim{
"malloc-trim",
@ -928,6 +934,7 @@ clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment var
ClangTidyOptProvider = combine(std::move(Providers));
Opts.ClangTidyProvider = ClangTidyOptProvider;
}
Opts.UseDirtyHeaders = UseDirtyHeaders;
Opts.QueryDriverGlobs = std::move(QueryDriverGlobs);
Opts.TweakFilter = [&](const Tweak &T) {
if (T.hidden() && !HiddenFeatures)