mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-28 18:54:55 +00:00
[clangd] Change FSProvider::getFileSystem to take CurrentWorkingDirectory
Summary: We've faced a couple of problems when the returned FS didn't have the proper working directory. New signature makes the API safer against such problems. Reviewers: sammccall Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, usaxena95, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D81920
This commit is contained in:
parent
0e1bdeafc9
commit
2dc2e47e3c
@ -183,7 +183,8 @@ void ClangdServer::addDocument(PathRef File, llvm::StringRef Contents,
|
||||
Opts.ClangTidyOpts = tidy::ClangTidyOptions::getDefaults();
|
||||
// FIXME: call tidy options builder on the worker thread, it can do IO.
|
||||
if (GetClangTidyOptions)
|
||||
Opts.ClangTidyOpts = GetClangTidyOptions(*FSProvider.getFileSystem(), File);
|
||||
Opts.ClangTidyOpts = GetClangTidyOptions(
|
||||
*FSProvider.getFileSystem(/*CWD=*/llvm::None), File);
|
||||
Opts.SuggestMissingIncludes = SuggestMissingIncludes;
|
||||
|
||||
// Compile command is set asynchronously during update, as it can be slow.
|
||||
@ -317,9 +318,9 @@ ClangdServer::formatOnType(llvm::StringRef Code, PathRef File, Position Pos,
|
||||
llvm::Expected<size_t> CursorPos = positionToOffset(Code, Pos);
|
||||
if (!CursorPos)
|
||||
return CursorPos.takeError();
|
||||
auto FS = FSProvider.getFileSystem();
|
||||
auto Style = format::getStyle(format::DefaultFormatStyle, File,
|
||||
format::DefaultFallbackStyle, Code, FS.get());
|
||||
auto Style = format::getStyle(
|
||||
format::DefaultFormatStyle, File, format::DefaultFallbackStyle, Code,
|
||||
FSProvider.getFileSystem(/*CWD=*/llvm::None).get());
|
||||
if (!Style)
|
||||
return Style.takeError();
|
||||
|
||||
@ -395,9 +396,8 @@ void ClangdServer::rename(PathRef File, Position Pos, llvm::StringRef NewName,
|
||||
return CB(Edits.takeError());
|
||||
|
||||
if (Opts.WantFormat) {
|
||||
auto Style = getFormatStyleForFile(
|
||||
File, InpAST->Inputs.Contents,
|
||||
InpAST->Inputs.FSProvider->getFileSystem().get());
|
||||
auto Style = getFormatStyleForFile(File, InpAST->Inputs.Contents,
|
||||
*InpAST->Inputs.FSProvider);
|
||||
llvm::Error Err = llvm::Error::success();
|
||||
for (auto &E : *Edits)
|
||||
Err =
|
||||
@ -473,38 +473,38 @@ void ClangdServer::applyTweak(PathRef File, Range Sel, StringRef TweakID,
|
||||
static constexpr trace::Metric TweakAttempt(
|
||||
"tweak_attempt", trace::Metric::Counter, "tweak_id");
|
||||
TweakAttempt.record(1, TweakID);
|
||||
auto Action =
|
||||
[File = File.str(), Sel, TweakID = TweakID.str(), CB = std::move(CB),
|
||||
FS = FSProvider.getFileSystem()](Expected<InputsAndAST> InpAST) mutable {
|
||||
if (!InpAST)
|
||||
return CB(InpAST.takeError());
|
||||
auto Selections = tweakSelection(Sel, *InpAST);
|
||||
if (!Selections)
|
||||
return CB(Selections.takeError());
|
||||
llvm::Optional<llvm::Expected<Tweak::Effect>> Effect;
|
||||
// Try each selection, take the first one that prepare()s.
|
||||
// If they all fail, Effect will hold get the last error.
|
||||
for (const auto &Selection : *Selections) {
|
||||
auto T = prepareTweak(TweakID, *Selection);
|
||||
if (T) {
|
||||
Effect = (*T)->apply(*Selection);
|
||||
break;
|
||||
}
|
||||
Effect = T.takeError();
|
||||
}
|
||||
assert(Effect.hasValue() && "Expected at least one selection");
|
||||
if (*Effect) {
|
||||
// Tweaks don't apply clang-format, do that centrally here.
|
||||
for (auto &It : (*Effect)->ApplyEdits) {
|
||||
Edit &E = It.second;
|
||||
format::FormatStyle Style =
|
||||
getFormatStyleForFile(File, E.InitialCode, FS.get());
|
||||
if (llvm::Error Err = reformatEdit(E, Style))
|
||||
elog("Failed to format {0}: {1}", It.first(), std::move(Err));
|
||||
}
|
||||
}
|
||||
return CB(std::move(*Effect));
|
||||
};
|
||||
auto Action = [File = File.str(), Sel, TweakID = TweakID.str(),
|
||||
CB = std::move(CB),
|
||||
this](Expected<InputsAndAST> InpAST) mutable {
|
||||
if (!InpAST)
|
||||
return CB(InpAST.takeError());
|
||||
auto Selections = tweakSelection(Sel, *InpAST);
|
||||
if (!Selections)
|
||||
return CB(Selections.takeError());
|
||||
llvm::Optional<llvm::Expected<Tweak::Effect>> Effect;
|
||||
// Try each selection, take the first one that prepare()s.
|
||||
// If they all fail, Effect will hold get the last error.
|
||||
for (const auto &Selection : *Selections) {
|
||||
auto T = prepareTweak(TweakID, *Selection);
|
||||
if (T) {
|
||||
Effect = (*T)->apply(*Selection);
|
||||
break;
|
||||
}
|
||||
Effect = T.takeError();
|
||||
}
|
||||
assert(Effect.hasValue() && "Expected at least one selection");
|
||||
if (*Effect) {
|
||||
// Tweaks don't apply clang-format, do that centrally here.
|
||||
for (auto &It : (*Effect)->ApplyEdits) {
|
||||
Edit &E = It.second;
|
||||
format::FormatStyle Style =
|
||||
getFormatStyleForFile(File, E.InitialCode, FSProvider);
|
||||
if (llvm::Error Err = reformatEdit(E, Style))
|
||||
elog("Failed to format {0}: {1}", It.first(), std::move(Err));
|
||||
}
|
||||
}
|
||||
return CB(std::move(*Effect));
|
||||
};
|
||||
WorkScheduler.runWithAST("ApplyTweak", File, std::move(Action));
|
||||
}
|
||||
|
||||
@ -549,7 +549,7 @@ void ClangdServer::switchSourceHeader(
|
||||
// 2) if 1) fails, we use the AST&Index approach, it is slower but supports
|
||||
// different code layout.
|
||||
if (auto CorrespondingFile = getCorrespondingHeaderOrSource(
|
||||
std::string(Path), FSProvider.getFileSystem()))
|
||||
std::string(Path), FSProvider.getFileSystem(llvm::None)))
|
||||
return CB(std::move(CorrespondingFile));
|
||||
auto Action = [Path = Path.str(), CB = std::move(CB),
|
||||
this](llvm::Expected<InputsAndAST> InpAST) mutable {
|
||||
@ -564,8 +564,7 @@ llvm::Expected<tooling::Replacements>
|
||||
ClangdServer::formatCode(llvm::StringRef Code, PathRef File,
|
||||
llvm::ArrayRef<tooling::Range> Ranges) {
|
||||
// Call clang-format.
|
||||
format::FormatStyle Style =
|
||||
getFormatStyleForFile(File, Code, FSProvider.getFileSystem().get());
|
||||
format::FormatStyle Style = getFormatStyleForFile(File, Code, FSProvider);
|
||||
tooling::Replacements IncludeReplaces =
|
||||
format::sortIncludes(Style, Code, Ranges, File);
|
||||
auto Changed = tooling::applyAllReplacements(Code, IncludeReplaces);
|
||||
@ -597,9 +596,8 @@ void ClangdServer::findHover(PathRef File, Position Pos,
|
||||
this](llvm::Expected<InputsAndAST> InpAST) mutable {
|
||||
if (!InpAST)
|
||||
return CB(InpAST.takeError());
|
||||
format::FormatStyle Style =
|
||||
getFormatStyleForFile(File, InpAST->Inputs.Contents,
|
||||
InpAST->Inputs.FSProvider->getFileSystem().get());
|
||||
format::FormatStyle Style = getFormatStyleForFile(
|
||||
File, InpAST->Inputs.Contents, *InpAST->Inputs.FSProvider);
|
||||
CB(clangd::getHover(InpAST->AST, Pos, std::move(Style), Index));
|
||||
};
|
||||
|
||||
|
@ -1113,12 +1113,10 @@ bool semaCodeComplete(std::unique_ptr<CodeCompleteConsumer> Consumer,
|
||||
// NOTE: we must call BeginSourceFile after prepareCompilerInstance. Otherwise
|
||||
// the remapped buffers do not get freed.
|
||||
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS =
|
||||
Input.ParseInput.FSProvider->getFileSystem();
|
||||
Input.ParseInput.FSProvider->getFileSystem(
|
||||
Input.ParseInput.CompileCommand.Directory);
|
||||
if (Input.Preamble.StatCache)
|
||||
VFS = Input.Preamble.StatCache->getConsumingFS(std::move(VFS));
|
||||
if (VFS->setCurrentWorkingDirectory(
|
||||
Input.ParseInput.CompileCommand.Directory))
|
||||
elog("Couldn't set working directory during code completion");
|
||||
auto Clang = prepareCompilerInstance(
|
||||
std::move(CI), !CompletingInPreamble ? &Input.Preamble.Preamble : nullptr,
|
||||
std::move(ContentsBuffer), std::move(VFS), IgnoreDiags);
|
||||
@ -1292,9 +1290,9 @@ public:
|
||||
assert(Recorder && "Recorder is not set");
|
||||
CCContextKind = Recorder->CCContext.getKind();
|
||||
IsUsingDeclaration = Recorder->CCContext.isUsingDeclaration();
|
||||
auto Style = getFormatStyleForFile(
|
||||
SemaCCInput.FileName, SemaCCInput.ParseInput.Contents,
|
||||
SemaCCInput.ParseInput.FSProvider->getFileSystem().get());
|
||||
auto Style = getFormatStyleForFile(SemaCCInput.FileName,
|
||||
SemaCCInput.ParseInput.Contents,
|
||||
*SemaCCInput.ParseInput.FSProvider);
|
||||
const auto NextToken = Lexer::findNextToken(
|
||||
Recorder->CCSema->getPreprocessor().getCodeCompletionLoc(),
|
||||
Recorder->CCSema->getSourceManager(), Recorder->CCSema->LangOpts);
|
||||
@ -1365,9 +1363,8 @@ public:
|
||||
// Indexes may choose to impose their own limits even if we don't have one.
|
||||
}
|
||||
|
||||
CodeCompleteResult
|
||||
runWithoutSema(llvm::StringRef Content, size_t Offset,
|
||||
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS) && {
|
||||
CodeCompleteResult runWithoutSema(llvm::StringRef Content, size_t Offset,
|
||||
const FileSystemProvider &FSProvider) && {
|
||||
trace::Span Tracer("CodeCompleteWithoutSema");
|
||||
// Fill in fields normally set by runWithSema()
|
||||
HeuristicPrefix = guessCompletionPrefix(Content, Offset);
|
||||
@ -1383,7 +1380,7 @@ public:
|
||||
ProxSources[FileName].Cost = 0;
|
||||
FileProximity.emplace(ProxSources);
|
||||
|
||||
auto Style = getFormatStyleForFile(FileName, Content, VFS.get());
|
||||
auto Style = getFormatStyleForFile(FileName, Content, FSProvider);
|
||||
// This will only insert verbatim headers.
|
||||
Inserter.emplace(FileName, Content, Style,
|
||||
/*BuildDir=*/"", /*HeaderSearchInfo=*/nullptr);
|
||||
@ -1783,9 +1780,8 @@ CodeCompleteResult codeComplete(PathRef FileName, Position Pos,
|
||||
FileName, Preamble ? Preamble->Includes : IncludeStructure(),
|
||||
SpecFuzzyFind, Opts);
|
||||
return (!Preamble || Opts.RunParser == CodeCompleteOptions::NeverParse)
|
||||
? std::move(Flow).runWithoutSema(
|
||||
ParseInput.Contents, *Offset,
|
||||
ParseInput.FSProvider->getFileSystem())
|
||||
? std::move(Flow).runWithoutSema(ParseInput.Contents, *Offset,
|
||||
*ParseInput.FSProvider)
|
||||
: std::move(Flow).run({FileName, *Offset, *Preamble,
|
||||
// We want to serve code completions with
|
||||
// low latency, so don't bother patching.
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "clang/Basic/TargetInfo.h"
|
||||
#include "clang/Lex/PreprocessorOptions.h"
|
||||
#include "clang/Serialization/PCHContainerOperations.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/Format.h"
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
|
||||
@ -47,13 +48,7 @@ buildCompilerInvocation(const ParseInputs &Inputs, clang::DiagnosticConsumer &D,
|
||||
for (const auto &S : Inputs.CompileCommand.CommandLine)
|
||||
ArgStrs.push_back(S.c_str());
|
||||
|
||||
auto VFS = Inputs.FSProvider->getFileSystem();
|
||||
if (VFS->setCurrentWorkingDirectory(Inputs.CompileCommand.Directory)) {
|
||||
log("Couldn't set working directory when creating compiler invocation.");
|
||||
// We proceed anyway, our lit-tests rely on results for non-existing working
|
||||
// dirs.
|
||||
}
|
||||
|
||||
auto VFS = Inputs.FSProvider->getFileSystem(Inputs.CompileCommand.Directory);
|
||||
llvm::IntrusiveRefCntPtr<DiagnosticsEngine> CommandLineDiagsEngine =
|
||||
CompilerInstance::createDiagnostics(new DiagnosticOptions, &D, false);
|
||||
std::unique_ptr<CompilerInvocation> CI = createInvocationFromCommandLine(
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
@ -248,14 +249,9 @@ ParsedAST::build(llvm::StringRef Filename, const ParseInputs &Inputs,
|
||||
trace::Span Tracer("BuildAST");
|
||||
SPAN_ATTACH(Tracer, "File", Filename);
|
||||
|
||||
auto VFS = Inputs.FSProvider->getFileSystem();
|
||||
auto VFS = Inputs.FSProvider->getFileSystem(Inputs.CompileCommand.Directory);
|
||||
if (Preamble && Preamble->StatCache)
|
||||
VFS = Preamble->StatCache->getConsumingFS(std::move(VFS));
|
||||
if (VFS->setCurrentWorkingDirectory(Inputs.CompileCommand.Directory)) {
|
||||
log("Couldn't set working directory when building the preamble.");
|
||||
// We proceed anyway, our lit-tests rely on results for non-existing working
|
||||
// dirs.
|
||||
}
|
||||
|
||||
assert(CI);
|
||||
// Command-line parsing sets DisableFree to true by default, but we don't want
|
||||
@ -359,7 +355,8 @@ ParsedAST::build(llvm::StringRef Filename, const ParseInputs &Inputs,
|
||||
auto BuildDir = VFS->getCurrentWorkingDirectory();
|
||||
if (Inputs.Opts.SuggestMissingIncludes && Inputs.Index &&
|
||||
!BuildDir.getError()) {
|
||||
auto Style = getFormatStyleForFile(Filename, Inputs.Contents, VFS.get());
|
||||
auto Style =
|
||||
getFormatStyleForFile(Filename, Inputs.Contents, *Inputs.FSProvider);
|
||||
auto Inserter = std::make_shared<IncludeInserter>(
|
||||
Filename, Inputs.Contents, Style, BuildDir.get(),
|
||||
&Clang->getPreprocessor().getHeaderSearchInfo());
|
||||
|
@ -30,6 +30,8 @@
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/ADT/IntrusiveRefCntPtr.h"
|
||||
#include "llvm/ADT/None.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
@ -237,7 +239,7 @@ scanPreamble(llvm::StringRef Contents,
|
||||
VFSProvider(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS)
|
||||
: VFS(std::move(FS)) {}
|
||||
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>
|
||||
getFileSystem() const override {
|
||||
getFileSystem(llvm::NoneType) const override {
|
||||
return VFS;
|
||||
}
|
||||
|
||||
@ -356,13 +358,7 @@ buildPreamble(PathRef FileName, CompilerInvocation CI,
|
||||
CI.getPreprocessorOpts().WriteCommentListToPCH = false;
|
||||
|
||||
CppFilePreambleCallbacks SerializedDeclsCollector(FileName, PreambleCallback);
|
||||
auto VFS = Inputs.FSProvider->getFileSystem();
|
||||
if (VFS->setCurrentWorkingDirectory(Inputs.CompileCommand.Directory)) {
|
||||
log("Couldn't set working directory when building the preamble.");
|
||||
// We proceed anyway, our lit-tests rely on results for non-existing working
|
||||
// dirs.
|
||||
}
|
||||
|
||||
auto VFS = Inputs.FSProvider->getFileSystem(Inputs.CompileCommand.Directory);
|
||||
llvm::SmallString<32> AbsFileName(FileName);
|
||||
VFS->makeAbsolute(AbsFileName);
|
||||
auto StatCache = std::make_unique<PreambleFileStatusCache>(AbsFileName);
|
||||
@ -399,8 +395,7 @@ bool isPreambleCompatible(const PreambleData &Preamble,
|
||||
llvm::MemoryBuffer::getMemBuffer(Inputs.Contents, FileName);
|
||||
auto Bounds =
|
||||
ComputePreambleBounds(*CI.getLangOpts(), ContentsBuffer.get(), 0);
|
||||
auto VFS = Inputs.FSProvider->getFileSystem();
|
||||
VFS->setCurrentWorkingDirectory(Inputs.CompileCommand.Directory);
|
||||
auto VFS = Inputs.FSProvider->getFileSystem(Inputs.CompileCommand.Directory);
|
||||
return compileCommandsAreEqual(Inputs.CompileCommand,
|
||||
Preamble.CompileCommand) &&
|
||||
Preamble.Preamble.CanReuse(CI, ContentsBuffer.get(), Bounds,
|
||||
@ -427,8 +422,8 @@ PreamblePatch PreamblePatch::create(llvm::StringRef FileName,
|
||||
trace::Span Tracer("CreatePreamblePatch");
|
||||
SPAN_ATTACH(Tracer, "File", FileName);
|
||||
assert(llvm::sys::path::is_absolute(FileName) && "relative FileName!");
|
||||
auto VFS =
|
||||
Baseline.StatCache->getConsumingFS(Modified.FSProvider->getFileSystem());
|
||||
auto VFS = Baseline.StatCache->getConsumingFS(
|
||||
Modified.FSProvider->getFileSystem(/*CWD=*/llvm::None));
|
||||
// First scan preprocessor directives in Baseline and Modified. These will be
|
||||
// used to figure out newly added directives in Modified. Scanning can fail,
|
||||
// the code just bails out and creates an empty patch in such cases, as:
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "Protocol.h"
|
||||
#include "refactor/Tweak.h"
|
||||
#include "support/Context.h"
|
||||
#include "support/FSProvider.h"
|
||||
#include "support/Logger.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/Basic/LangOptions.h"
|
||||
@ -574,11 +575,12 @@ llvm::Optional<FileDigest> digestFile(const SourceManager &SM, FileID FID) {
|
||||
return digest(Content);
|
||||
}
|
||||
|
||||
format::FormatStyle getFormatStyleForFile(llvm::StringRef File,
|
||||
llvm::StringRef Content,
|
||||
llvm::vfs::FileSystem *FS) {
|
||||
auto Style = format::getStyle(format::DefaultFormatStyle, File,
|
||||
format::DefaultFallbackStyle, Content, FS);
|
||||
format::FormatStyle
|
||||
getFormatStyleForFile(llvm::StringRef File, llvm::StringRef Content,
|
||||
const FileSystemProvider &FSProvider) {
|
||||
auto Style = format::getStyle(
|
||||
format::DefaultFormatStyle, File, format::DefaultFallbackStyle, Content,
|
||||
FSProvider.getFileSystem(/*CWD=*/llvm::None).get());
|
||||
if (!Style) {
|
||||
log("getStyle() failed for file {0}: {1}. Fallback is LLVM style.", File,
|
||||
Style.takeError());
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
#include "Protocol.h"
|
||||
#include "support/Context.h"
|
||||
#include "support/FSProvider.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/Basic/LangOptions.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
@ -167,7 +168,7 @@ llvm::Optional<std::string> getCanonicalPath(const FileEntry *F,
|
||||
/// though the latter may have been overridden in main()!
|
||||
format::FormatStyle getFormatStyleForFile(llvm::StringRef File,
|
||||
llvm::StringRef Content,
|
||||
llvm::vfs::FileSystem *FS);
|
||||
const FileSystemProvider &FSProvider);
|
||||
|
||||
/// Cleanup and format the given replacements.
|
||||
llvm::Expected<tooling::Replacements>
|
||||
|
@ -244,8 +244,7 @@ llvm::Error BackgroundIndex::index(tooling::CompileCommand Cmd) {
|
||||
SPAN_ATTACH(Tracer, "file", Cmd.Filename);
|
||||
auto AbsolutePath = getAbsolutePath(Cmd);
|
||||
|
||||
auto FS = FSProvider.getFileSystem();
|
||||
FS->setCurrentWorkingDirectory(Cmd.Directory);
|
||||
auto FS = FSProvider.getFileSystem(Cmd.Directory);
|
||||
auto Buf = FS->getBufferForFile(AbsolutePath);
|
||||
if (!Buf)
|
||||
return llvm::errorCodeToError(Buf.getError());
|
||||
@ -382,7 +381,7 @@ BackgroundIndex::loadProject(std::vector<std::string> MainFiles) {
|
||||
Rebuilder.loadedShard(LoadedShards);
|
||||
Rebuilder.doneLoading();
|
||||
|
||||
auto FS = FSProvider.getFileSystem();
|
||||
auto FS = FSProvider.getFileSystem(/*CWD=*/llvm::None);
|
||||
llvm::DenseSet<PathRef> TUsToIndex;
|
||||
// We'll accept data from stale shards, but ensure the files get reindexed
|
||||
// soon.
|
||||
|
@ -424,10 +424,8 @@ public:
|
||||
return llvm::createStringError(Buffer.getError(),
|
||||
Buffer.getError().message());
|
||||
auto Contents = Buffer->get()->getBuffer();
|
||||
auto LangOpts = format::getFormattingLangOpts(
|
||||
getFormatStyleForFile(*CCFile, Contents, &FS));
|
||||
auto InsertionPoint = getInsertionPoint(
|
||||
Contents, Source->getQualifiedNameAsString(), LangOpts);
|
||||
Contents, Source->getQualifiedNameAsString(), Sel.AST->getLangOpts());
|
||||
if (!InsertionPoint)
|
||||
return InsertionPoint.takeError();
|
||||
|
||||
|
@ -7,6 +7,9 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "support/FSProvider.h"
|
||||
#include "Logger.h"
|
||||
#include "llvm/ADT/None.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
@ -72,7 +75,15 @@ private:
|
||||
} // namespace
|
||||
|
||||
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>
|
||||
clang::clangd::RealFileSystemProvider::getFileSystem() const {
|
||||
FileSystemProvider::getFileSystem(PathRef CWD) const {
|
||||
auto FS = getFileSystem(/*CWD=*/llvm::None);
|
||||
if (auto EC = FS->setCurrentWorkingDirectory(CWD))
|
||||
elog("VFS: failed to set CWD to {0}: {1}", CWD, EC.message());
|
||||
return FS;
|
||||
}
|
||||
|
||||
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>
|
||||
clang::clangd::RealFileSystemProvider::getFileSystem(llvm::NoneType) const {
|
||||
// Avoid using memory-mapped files.
|
||||
// FIXME: Try to use a similar approach in Sema instead of relying on
|
||||
// propagation of the 'isVolatile' flag through all layers.
|
||||
|
@ -9,7 +9,10 @@
|
||||
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_SUPPORT_FSPROVIDER_H
|
||||
#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_SUPPORT_FSPROVIDER_H
|
||||
|
||||
#include "Path.h"
|
||||
#include "llvm/ADT/IntrusiveRefCntPtr.h"
|
||||
#include "llvm/ADT/None.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/Support/VirtualFileSystem.h"
|
||||
#include <memory>
|
||||
|
||||
@ -25,14 +28,21 @@ public:
|
||||
/// Context::current() will be the context passed to the clang entrypoint,
|
||||
/// such as addDocument(), and will also be propagated to result callbacks.
|
||||
/// Embedders may use this to isolate filesystem accesses.
|
||||
/// Initial working directory is arbitrary.
|
||||
virtual llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>
|
||||
getFileSystem() const = 0;
|
||||
getFileSystem(llvm::NoneType CWD) const = 0;
|
||||
|
||||
/// As above, except it will try to set current working directory to \p CWD.
|
||||
/// This is an overload instead of an optional to make implicit string ->
|
||||
/// StringRef conversion possible.
|
||||
virtual llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>
|
||||
getFileSystem(PathRef CWD) const;
|
||||
};
|
||||
|
||||
class RealFileSystemProvider : public FileSystemProvider {
|
||||
public:
|
||||
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>
|
||||
getFileSystem() const override;
|
||||
getFileSystem(llvm::NoneType) const override;
|
||||
};
|
||||
|
||||
} // namespace clangd
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "clang/Basic/Version.h"
|
||||
#include "clang/Format/Format.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
@ -717,7 +718,8 @@ clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment var
|
||||
ClangTidyOptProvider = std::make_unique<tidy::FileOptionsProvider>(
|
||||
tidy::ClangTidyGlobalOptions(),
|
||||
/* Default */ EmptyDefaults,
|
||||
/* Override */ OverrideClangTidyOptions, FSProvider.getFileSystem());
|
||||
/* Override */ OverrideClangTidyOptions,
|
||||
FSProvider.getFileSystem(/*CWD=*/llvm::None));
|
||||
Opts.GetClangTidyOptions = [&](llvm::vfs::FileSystem &,
|
||||
llvm::StringRef File) {
|
||||
// This function must be thread-safe and tidy option providers are not.
|
||||
|
@ -15,9 +15,12 @@
|
||||
#include "SyncAPI.h"
|
||||
#include "TestFS.h"
|
||||
#include "URI.h"
|
||||
#include "support/Path.h"
|
||||
#include "support/Threading.h"
|
||||
#include "clang/Config/config.h"
|
||||
#include "clang/Sema/CodeCompleteConsumer.h"
|
||||
#include "llvm/ADT/None.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/Support/Errc.h"
|
||||
@ -270,7 +273,8 @@ int b = a;
|
||||
TEST_F(ClangdVFSTest, PropagatesContexts) {
|
||||
static Key<int> Secret;
|
||||
struct FSProvider : public FileSystemProvider {
|
||||
IntrusiveRefCntPtr<llvm::vfs::FileSystem> getFileSystem() const override {
|
||||
IntrusiveRefCntPtr<llvm::vfs::FileSystem>
|
||||
getFileSystem(llvm::NoneType) const override {
|
||||
Got = Context::current().getExisting(Secret);
|
||||
return buildTestFS({});
|
||||
}
|
||||
@ -925,7 +929,8 @@ TEST(ClangdTests, PreambleVFSStatCache) {
|
||||
ListenStatsFSProvider(llvm::StringMap<unsigned> &CountStats)
|
||||
: CountStats(CountStats) {}
|
||||
|
||||
IntrusiveRefCntPtr<llvm::vfs::FileSystem> getFileSystem() const override {
|
||||
IntrusiveRefCntPtr<llvm::vfs::FileSystem>
|
||||
getFileSystem(llvm::NoneType) const override {
|
||||
class ListenStatVFS : public llvm::vfs::ProxyFileSystem {
|
||||
public:
|
||||
ListenStatVFS(IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
|
||||
|
@ -21,7 +21,6 @@ TEST(FSTests, PreambleStatusCache) {
|
||||
Files["y"] = "";
|
||||
Files["main"] = "";
|
||||
auto FS = buildTestFS(Files);
|
||||
FS->setCurrentWorkingDirectory(testRoot());
|
||||
|
||||
PreambleFileStatusCache StatCache(testPath("main"));
|
||||
auto ProduceFS = StatCache.getProducingFS(FS);
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "clang/Frontend/CompilerInvocation.h"
|
||||
#include "clang/Frontend/FrontendActions.h"
|
||||
#include "clang/Lex/PreprocessorOptions.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Support/FormatVariadic.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include "gmock/gmock.h"
|
||||
@ -52,8 +53,7 @@ private:
|
||||
EXPECT_TRUE(static_cast<bool>(CI));
|
||||
// The diagnostic options must be set before creating a CompilerInstance.
|
||||
CI->getDiagnosticOpts().IgnoreWarnings = true;
|
||||
auto VFS = FS.getFileSystem();
|
||||
VFS->setCurrentWorkingDirectory(Cmd->Directory);
|
||||
auto VFS = PI.FSProvider->getFileSystem(Cmd->Directory);
|
||||
auto Clang = prepareCompilerInstance(
|
||||
std::move(CI), /*Preamble=*/nullptr,
|
||||
llvm::MemoryBuffer::getMemBuffer(FS.Files[MainFile], MainFile),
|
||||
|
@ -70,11 +70,11 @@ collectPatchedIncludes(llvm::StringRef ModifiedContents,
|
||||
// We don't run PP directly over the patch cotents to test production
|
||||
// behaviour.
|
||||
auto Bounds = Lexer::ComputePreamble(ModifiedContents, *CI->getLangOpts());
|
||||
auto Clang =
|
||||
prepareCompilerInstance(std::move(CI), &BaselinePreamble->Preamble,
|
||||
llvm::MemoryBuffer::getMemBufferCopy(
|
||||
ModifiedContents.slice(0, Bounds.Size).str()),
|
||||
PI.FSProvider->getFileSystem(), Diags);
|
||||
auto Clang = prepareCompilerInstance(
|
||||
std::move(CI), &BaselinePreamble->Preamble,
|
||||
llvm::MemoryBuffer::getMemBufferCopy(
|
||||
ModifiedContents.slice(0, Bounds.Size).str()),
|
||||
PI.FSProvider->getFileSystem(PI.CompileCommand.Directory), Diags);
|
||||
PreprocessOnlyAction Action;
|
||||
if (!Action.BeginSourceFile(*Clang, Clang->getFrontendOpts().Inputs[0])) {
|
||||
ADD_FAILURE() << "failed begin source file";
|
||||
|
@ -13,8 +13,11 @@
|
||||
#define LLVM_CLANG_TOOLS_EXTRA_UNITTESTS_CLANGD_TESTFS_H
|
||||
#include "ClangdServer.h"
|
||||
#include "GlobalCompilationDatabase.h"
|
||||
#include "support/FSProvider.h"
|
||||
#include "support/Path.h"
|
||||
#include "llvm/ADT/IntrusiveRefCntPtr.h"
|
||||
#include "llvm/ADT/None.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include "llvm/Support/VirtualFileSystem.h"
|
||||
|
||||
@ -30,10 +33,18 @@ buildTestFS(llvm::StringMap<std::string> const &Files,
|
||||
// A VFS provider that returns TestFSes containing a provided set of files.
|
||||
class MockFSProvider : public FileSystemProvider {
|
||||
public:
|
||||
IntrusiveRefCntPtr<llvm::vfs::FileSystem> getFileSystem() const override {
|
||||
// Prevent name hiding caused by the overload below.
|
||||
using FileSystemProvider::getFileSystem;
|
||||
|
||||
IntrusiveRefCntPtr<llvm::vfs::FileSystem> getFileSystem() const {
|
||||
return buildTestFS(Files, Timestamps);
|
||||
}
|
||||
|
||||
IntrusiveRefCntPtr<llvm::vfs::FileSystem>
|
||||
getFileSystem(llvm::NoneType) const override {
|
||||
return getFileSystem();
|
||||
}
|
||||
|
||||
// If relative paths are used, they are resolved with testPath().
|
||||
llvm::StringMap<std::string> Files;
|
||||
llvm::StringMap<time_t> Timestamps;
|
||||
|
Loading…
Reference in New Issue
Block a user