[clang-tools-extra] 15a60fe - [clangd] Config: compute config in TUScheduler and BackgroundIndex
Sam McCall via cfe-commits
cfe-commits at lists.llvm.org
Sat Jul 4 02:19:31 PDT 2020
Author: Sam McCall
Date: 2020-07-04T11:18:14+02:00
New Revision: 15a60fe09f4618a7fb451f37aebfd1a671f83713
URL: https://github.com/llvm/llvm-project/commit/15a60fe09f4618a7fb451f37aebfd1a671f83713
DIFF: https://github.com/llvm/llvm-project/commit/15a60fe09f4618a7fb451f37aebfd1a671f83713.diff
LOG: [clangd] Config: compute config in TUScheduler and BackgroundIndex
Summary:
ClangdServer owns the question of exactly which config to create, but
TUScheduler/BackgroundIndex control threads and so decide at which point
to inject it.
Reviewers: kadircet
Subscribers: ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, usaxena95, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D83095
Added:
Modified:
clang-tools-extra/clangd/ClangdServer.cpp
clang-tools-extra/clangd/ClangdServer.h
clang-tools-extra/clangd/TUScheduler.cpp
clang-tools-extra/clangd/TUScheduler.h
clang-tools-extra/clangd/index/Background.cpp
clang-tools-extra/clangd/index/Background.h
clang-tools-extra/clangd/unittests/BackgroundIndexTests.cpp
clang-tools-extra/clangd/unittests/ClangdTests.cpp
clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp
Removed:
################################################################################
diff --git a/clang-tools-extra/clangd/ClangdServer.cpp b/clang-tools-extra/clangd/ClangdServer.cpp
index b33d53699405..6ac2f67d55b3 100644
--- a/clang-tools-extra/clangd/ClangdServer.cpp
+++ b/clang-tools-extra/clangd/ClangdServer.cpp
@@ -8,6 +8,7 @@
#include "ClangdServer.h"
#include "CodeComplete.h"
+#include "Config.h"
#include "FindSymbols.h"
#include "Format.h"
#include "HeaderSourceSwitch.h"
@@ -132,7 +133,7 @@ ClangdServer::Options::operator TUScheduler::Options() const {
ClangdServer::ClangdServer(const GlobalCompilationDatabase &CDB,
const ThreadsafeFS &TFS, const Options &Opts,
Callbacks *Callbacks)
- : TFS(TFS),
+ : ConfigProvider(Opts.ConfigProvider), TFS(TFS),
DynamicIdx(Opts.BuildDynamicSymbolIndex
? new FileIndex(Opts.HeavyweightDynamicSymbolIndex)
: nullptr),
@@ -147,7 +148,14 @@ ClangdServer::ClangdServer(const GlobalCompilationDatabase &CDB,
// FIXME(ioeric): this can be slow and we may be able to index on less
// critical paths.
WorkScheduler(
- CDB, TUScheduler::Options(Opts),
+ CDB,
+ [&, this] {
+ TUScheduler::Options O(Opts);
+ O.ContextProvider = [this](PathRef P) {
+ return createProcessingContext(P);
+ };
+ return O;
+ }(),
std::make_unique<UpdateIndexCallbacks>(
DynamicIdx.get(), Callbacks, Opts.TheiaSemanticHighlighting)) {
// Adds an index to the stack, at higher priority than existing indexes.
@@ -170,7 +178,8 @@ ClangdServer::ClangdServer(const GlobalCompilationDatabase &CDB,
[Callbacks](BackgroundQueue::Stats S) {
if (Callbacks)
Callbacks->onBackgroundIndexProgress(S);
- });
+ },
+ [this](PathRef P) { return createProcessingContext(P); });
AddIndex(BackgroundIdx.get());
}
if (DynamicIdx)
@@ -335,7 +344,7 @@ void ClangdServer::formatOnType(PathRef File, llvm::StringRef Code,
Result.push_back(replacementToEdit(Code, R));
return CB(Result);
};
- WorkScheduler.run("FormatOnType", std::move(Action));
+ WorkScheduler.run("FormatOnType", File, std::move(Action));
}
void ClangdServer::prepareRename(PathRef File, Position Pos,
@@ -585,7 +594,7 @@ void ClangdServer::formatCode(PathRef File, llvm::StringRef Code,
tooling::calculateRangesAfterReplacements(IncludeReplaces, Ranges),
File)));
};
- WorkScheduler.run("Format", std::move(Action));
+ WorkScheduler.run("Format", File, std::move(Action));
}
void ClangdServer::findDocumentHighlights(
@@ -646,7 +655,7 @@ void ClangdServer::workspaceSymbols(
llvm::StringRef Query, int Limit,
Callback<std::vector<SymbolInformation>> CB) {
WorkScheduler.run(
- "getWorkspaceSymbols",
+ "getWorkspaceSymbols", /*Path=*/"",
[Query = Query.str(), Limit, CB = std::move(CB), this]() mutable {
CB(clangd::getWorkspaceSymbols(Query, Limit, Index,
WorkspaceRoot.getValueOr("")));
@@ -736,6 +745,31 @@ llvm::StringMap<TUScheduler::FileStats> ClangdServer::fileStats() const {
return WorkScheduler.fileStats();
}
+Context ClangdServer::createProcessingContext(PathRef File) const {
+ if (!ConfigProvider)
+ return Context::current().clone();
+
+ config::Params Params;
+ if (!File.empty()) {
+ assert(llvm::sys::path::is_absolute(File));
+ llvm::SmallString<256> PosixPath = File;
+ llvm::sys::path::native(PosixPath, llvm::sys::path::Style::posix);
+ Params.Path = PosixPath.str();
+ }
+
+ auto DiagnosticHandler = [](const llvm::SMDiagnostic &Diag) {
+ if (Diag.getKind() == llvm::SourceMgr::DK_Error) {
+ elog("config error at {0}:{1}:{2}: {3}", Diag.getFilename(),
+ Diag.getLineNo(), Diag.getColumnNo(), Diag.getMessage());
+ } else {
+ log("config warning at {0}:{1}:{2}: {3}", Diag.getFilename(),
+ Diag.getLineNo(), Diag.getColumnNo(), Diag.getMessage());
+ }
+ };
+ Config C = ConfigProvider->getConfig(Params, DiagnosticHandler);
+ return Context::current().derive(Config::Key, std::move(C));
+}
+
LLVM_NODISCARD bool
ClangdServer::blockUntilIdleForTest(llvm::Optional<double> TimeoutSeconds) {
return WorkScheduler.blockUntilIdle(timeoutSeconds(TimeoutSeconds)) &&
diff --git a/clang-tools-extra/clangd/ClangdServer.h b/clang-tools-extra/clangd/ClangdServer.h
index c2a5c98fc458..faeec2e88848 100644
--- a/clang-tools-extra/clangd/ClangdServer.h
+++ b/clang-tools-extra/clangd/ClangdServer.h
@@ -11,6 +11,7 @@
#include "../clang-tidy/ClangTidyOptions.h"
#include "CodeComplete.h"
+#include "ConfigProvider.h"
#include "GlobalCompilationDatabase.h"
#include "Hover.h"
#include "Protocol.h"
@@ -113,6 +114,9 @@ class ClangdServer {
/// If set, use this index to augment code completion results.
SymbolIndex *StaticIndex = nullptr;
+ /// If set, queried to obtain the configuration to handle each request.
+ config::Provider *ConfigProvider = nullptr;
+
/// If set, enable clang-tidy in clangd and use to it get clang-tidy
/// configurations for a particular file.
/// Clangd supports only a small subset of ClangTidyOptions, these options
@@ -326,6 +330,15 @@ class ClangdServer {
ArrayRef<tooling::Range> Ranges,
Callback<tooling::Replacements> CB);
+ /// Derives a context for a task processing the specified source file.
+ /// This includes the current configuration (see Options::ConfigProvider).
+ /// The empty string means no particular file is the target.
+ /// Rather than called by each feature, this is exposed to the components
+ /// that control worker threads, like TUScheduler and BackgroundIndex.
+ /// This means it's OK to do some IO here, and it cuts across all features.
+ Context createProcessingContext(PathRef) const;
+ config::Provider *ConfigProvider = nullptr;
+
const ThreadsafeFS &TFS;
Path ResourceDir;
diff --git a/clang-tools-extra/clangd/TUScheduler.cpp b/clang-tools-extra/clangd/TUScheduler.cpp
index 7f15d44134a0..5454b1c92c8a 100644
--- a/clang-tools-extra/clangd/TUScheduler.cpp
+++ b/clang-tools-extra/clangd/TUScheduler.cpp
@@ -270,6 +270,10 @@ class PreambleThread {
{
WithContext Guard(std::move(CurrentReq->Ctx));
+ // Note that we don't make use of the ContextProvider here.
+ // Preamble tasks are always scheduled by ASTWorker tasks, and we
+ // reuse the context/config that was created at that level.
+
// Build the preamble and let the waiters know about it.
build(std::move(*CurrentReq));
}
@@ -456,6 +460,8 @@ class ASTWorker {
const DebouncePolicy UpdateDebounce;
/// File that ASTWorker is responsible for.
const Path FileName;
+ /// Callback to create processing contexts for tasks.
+ const std::function<Context(llvm::StringRef)> ContextProvider;
const GlobalCompilationDatabase &CDB;
/// Callback invoked when preamble or main file AST is built.
ParsingCallbacks &Callbacks;
@@ -569,8 +575,9 @@ ASTWorker::ASTWorker(PathRef FileName, const GlobalCompilationDatabase &CDB,
bool RunSync, const TUScheduler::Options &Opts,
ParsingCallbacks &Callbacks)
: IdleASTs(LRUCache), RunSync(RunSync), UpdateDebounce(Opts.UpdateDebounce),
- FileName(FileName), CDB(CDB), Callbacks(Callbacks), Barrier(Barrier),
- Done(false), Status(FileName, Callbacks),
+ FileName(FileName), ContextProvider(Opts.ContextProvider), CDB(CDB),
+ Callbacks(Callbacks), Barrier(Barrier), Done(false),
+ Status(FileName, Callbacks),
PreamblePeer(FileName, Callbacks, Opts.StorePreamblesInMemory,
RunSync || !Opts.AsyncPreambleBuilds, Status, *this) {
// Set a fallback command because compile command can be accessed before
@@ -1055,6 +1062,9 @@ void ASTWorker::run() {
Status.ASTActivity.K = ASTAction::RunningAction;
Status.ASTActivity.Name = CurrentRequest->Name;
});
+ llvm::Optional<WithContext> WithProvidedContext;
+ if (ContextProvider)
+ WithProvidedContext.emplace(ContextProvider(FileName));
CurrentRequest->Action();
}
@@ -1288,14 +1298,18 @@ llvm::StringMap<std::string> TUScheduler::getAllFileContents() const {
return Results;
}
-void TUScheduler::run(llvm::StringRef Name,
+void TUScheduler::run(llvm::StringRef Name, llvm::StringRef Path,
llvm::unique_function<void()> Action) {
if (!PreambleTasks)
return Action();
PreambleTasks->runAsync(Name, [this, Ctx = Context::current().clone(),
+ Path(Path.str()),
Action = std::move(Action)]() mutable {
std::lock_guard<Semaphore> BarrierLock(Barrier);
WithContext WC(std::move(Ctx));
+ llvm::Optional<WithContext> WithProvidedContext;
+ if (Opts.ContextProvider)
+ WithProvidedContext.emplace(Opts.ContextProvider(Path));
Action();
});
}
@@ -1356,6 +1370,9 @@ void TUScheduler::runWithPreamble(llvm::StringRef Name, PathRef File,
WithContext Guard(std::move(Ctx));
trace::Span Tracer(Name);
SPAN_ATTACH(Tracer, "file", File);
+ llvm::Optional<WithContext> WithProvidedContext;
+ if (Opts.ContextProvider)
+ WithProvidedContext.emplace(Opts.ContextProvider(File));
Action(InputsAndPreamble{Contents, Command, Preamble.get()});
};
diff --git a/clang-tools-extra/clangd/TUScheduler.h b/clang-tools-extra/clangd/TUScheduler.h
index fb32c3b2edff..f33470f4e894 100644
--- a/clang-tools-extra/clangd/TUScheduler.h
+++ b/clang-tools-extra/clangd/TUScheduler.h
@@ -195,6 +195,11 @@ class TUScheduler {
/// Whether to run PreamblePeer asynchronously.
/// No-op if AsyncThreadsCount is 0.
bool AsyncPreambleBuilds = false;
+
+ /// Used to create a context that wraps each single operation.
+ /// Typically to inject per-file configuration.
+ /// If the path is empty, context sholud be "generic".
+ std::function<Context(PathRef)> ContextProvider;
};
TUScheduler(const GlobalCompilationDatabase &CDB, const Options &Opts,
@@ -233,7 +238,9 @@ class TUScheduler {
llvm::StringMap<std::string> getAllFileContents() const;
/// Schedule an async task with no dependencies.
- void run(llvm::StringRef Name, llvm::unique_function<void()> Action);
+ /// Path may be empty (it is used only to set the Context).
+ void run(llvm::StringRef Name, llvm::StringRef Path,
+ llvm::unique_function<void()> Action);
/// Defines how a runWithAST action is implicitly cancelled by other actions.
enum ASTActionInvalidation {
@@ -301,6 +308,7 @@ class TUScheduler {
// this inside clangd.
// FIXME: remove this when there is proper index support via build system
// integration.
+ // FIXME: move to ClangdServer via createProcessingContext.
static llvm::Optional<llvm::StringRef> getFileBeingProcessedInContext();
private:
diff --git a/clang-tools-extra/clangd/index/Background.cpp b/clang-tools-extra/clangd/index/Background.cpp
index 5aae49345b65..5024ace66b7c 100644
--- a/clang-tools-extra/clangd/index/Background.cpp
+++ b/clang-tools-extra/clangd/index/Background.cpp
@@ -93,9 +93,11 @@ BackgroundIndex::BackgroundIndex(
Context BackgroundContext, const ThreadsafeFS &TFS,
const GlobalCompilationDatabase &CDB,
BackgroundIndexStorage::Factory IndexStorageFactory, size_t ThreadPoolSize,
- std::function<void(BackgroundQueue::Stats)> OnProgress)
+ std::function<void(BackgroundQueue::Stats)> OnProgress,
+ std::function<Context(PathRef)> ContextProvider)
: SwapIndex(std::make_unique<MemIndex>()), TFS(TFS), CDB(CDB),
BackgroundContext(std::move(BackgroundContext)),
+ ContextProvider(std::move(ContextProvider)),
Rebuilder(this, &IndexedSymbols, ThreadPoolSize),
IndexStorageFactory(std::move(IndexStorageFactory)),
Queue(std::move(OnProgress)),
@@ -122,6 +124,11 @@ BackgroundQueue::Task BackgroundIndex::changedFilesTask(
const std::vector<std::string> &ChangedFiles) {
BackgroundQueue::Task T([this, ChangedFiles] {
trace::Span Tracer("BackgroundIndexEnqueue");
+
+ llvm::Optional<WithContext> WithProvidedContext;
+ if (ContextProvider)
+ WithProvidedContext.emplace(ContextProvider(/*Path=*/""));
+
// We're doing this asynchronously, because we'll read shards here too.
log("Enqueueing {0} commands for indexing", ChangedFiles.size());
SPAN_ATTACH(Tracer, "files", int64_t(ChangedFiles.size()));
@@ -147,17 +154,20 @@ static llvm::StringRef filenameWithoutExtension(llvm::StringRef Path) {
return Path.drop_back(llvm::sys::path::extension(Path).size());
}
-BackgroundQueue::Task
-BackgroundIndex::indexFileTask(tooling::CompileCommand Cmd) {
- BackgroundQueue::Task T([this, Cmd] {
- // We can't use llvm::StringRef here since we are going to
- // move from Cmd during the call below.
- const std::string FileName = Cmd.Filename;
- if (auto Error = index(std::move(Cmd)))
- elog("Indexing {0} failed: {1}", FileName, std::move(Error));
+BackgroundQueue::Task BackgroundIndex::indexFileTask(std::string Path) {
+ std::string Tag = filenameWithoutExtension(Path).str();
+ BackgroundQueue::Task T([this, Path(std::move(Path))] {
+ llvm::Optional<WithContext> WithProvidedContext;
+ if (ContextProvider)
+ WithProvidedContext.emplace(ContextProvider(Path));
+ auto Cmd = CDB.getCompileCommand(Path);
+ if (!Cmd)
+ return;
+ if (auto Error = index(std::move(*Cmd)))
+ elog("Indexing {0} failed: {1}", Path, std::move(Error));
});
T.QueuePri = IndexFile;
- T.Tag = std::string(filenameWithoutExtension(Cmd.Filename));
+ T.Tag = std::move(Tag);
return T;
}
@@ -342,10 +352,8 @@ llvm::Error BackgroundIndex::index(tooling::CompileCommand Cmd) {
// Restores shards for \p MainFiles from index storage. Then checks staleness of
// those shards and returns a list of TUs that needs to be indexed to update
// staleness.
-std::vector<tooling::CompileCommand>
+std::vector<std::string>
BackgroundIndex::loadProject(std::vector<std::string> MainFiles) {
- std::vector<tooling::CompileCommand> NeedsReIndexing;
-
Rebuilder.startLoading();
// Load shards for all of the mainfiles.
const std::vector<LoadedShard> Result =
@@ -398,14 +406,7 @@ BackgroundIndex::loadProject(std::vector<std::string> MainFiles) {
TUsToIndex.insert(TUForFile);
}
- for (PathRef TU : TUsToIndex) {
- auto Cmd = CDB.getCompileCommand(TU);
- if (!Cmd)
- continue;
- NeedsReIndexing.emplace_back(std::move(*Cmd));
- }
-
- return NeedsReIndexing;
+ return {TUsToIndex.begin(), TUsToIndex.end()};
}
} // namespace clangd
diff --git a/clang-tools-extra/clangd/index/Background.h b/clang-tools-extra/clangd/index/Background.h
index 9e6b9724af24..9f9b1b712659 100644
--- a/clang-tools-extra/clangd/index/Background.h
+++ b/clang-tools-extra/clangd/index/Background.h
@@ -138,7 +138,8 @@ class BackgroundIndex : public SwapIndex {
// Arbitrary value to ensure some concurrency in tests.
// In production an explicit value is passed.
size_t ThreadPoolSize = 4,
- std::function<void(BackgroundQueue::Stats)> OnProgress = nullptr);
+ std::function<void(BackgroundQueue::Stats)> OnProgress = nullptr,
+ std::function<Context(PathRef)> ContextProvider = nullptr);
~BackgroundIndex(); // Blocks while the current task finishes.
// Enqueue translation units for indexing.
@@ -183,6 +184,7 @@ class BackgroundIndex : public SwapIndex {
const ThreadsafeFS &TFS;
const GlobalCompilationDatabase &CDB;
Context BackgroundContext;
+ std::function<Context(PathRef)> ContextProvider;
llvm::Error index(tooling::CompileCommand);
@@ -193,12 +195,11 @@ class BackgroundIndex : public SwapIndex {
BackgroundIndexStorage::Factory IndexStorageFactory;
// Tries to load shards for the MainFiles and their dependencies.
- std::vector<tooling::CompileCommand>
- loadProject(std::vector<std::string> MainFiles);
+ std::vector<std::string> loadProject(std::vector<std::string> MainFiles);
BackgroundQueue::Task
changedFilesTask(const std::vector<std::string> &ChangedFiles);
- BackgroundQueue::Task indexFileTask(tooling::CompileCommand Cmd);
+ BackgroundQueue::Task indexFileTask(std::string Path);
// from lowest to highest priority
enum QueuePriority {
diff --git a/clang-tools-extra/clangd/unittests/BackgroundIndexTests.cpp b/clang-tools-extra/clangd/unittests/BackgroundIndexTests.cpp
index 24322e1575ab..352a58bf818e 100644
--- a/clang-tools-extra/clangd/unittests/BackgroundIndexTests.cpp
+++ b/clang-tools-extra/clangd/unittests/BackgroundIndexTests.cpp
@@ -1,3 +1,5 @@
+#include "CompileCommands.h"
+#include "Config.h"
#include "Headers.h"
#include "SyncAPI.h"
#include "TestFS.h"
@@ -5,6 +7,7 @@
#include "TestTU.h"
#include "index/Background.h"
#include "index/BackgroundRebuild.h"
+#include "clang/Tooling/ArgumentsAdjusters.h"
#include "clang/Tooling/CompilationDatabase.h"
#include "llvm/Support/ScopedPrinter.h"
#include "llvm/Support/Threading.h"
@@ -24,6 +27,7 @@ namespace clang {
namespace clangd {
MATCHER_P(Named, N, "") { return arg.Name == N; }
+MATCHER_P(QName, N, "") { return (arg.Scope + arg.Name).str() == N; }
MATCHER(Declared, "") {
return !StringRef(arg.CanonicalDeclaration.FileURI).empty();
}
@@ -104,6 +108,51 @@ TEST_F(BackgroundIndexTest, NoCrashOnErrorFile) {
ASSERT_TRUE(Idx.blockUntilIdleForTest());
}
+TEST_F(BackgroundIndexTest, Config) {
+ MockFS FS;
+ // Set up two identical TUs, foo and bar.
+ // They define foo::one and bar::one.
+ std::vector<tooling::CompileCommand> Cmds;
+ for (std::string Name : {"foo", "bar"}) {
+ std::string Filename = Name + ".cpp";
+ std::string Header = Name + ".h";
+ FS.Files[Filename] = "#include \"" + Header + "\"";
+ FS.Files[Header] = "namespace " + Name + " { int one; }";
+ tooling::CompileCommand Cmd;
+ Cmd.Filename = Filename;
+ Cmd.Directory = testRoot();
+ Cmd.CommandLine = {"clang++", Filename};
+ Cmds.push_back(std::move(Cmd));
+ }
+ // Context provider that installs a configuration mutating foo's command.
+ // This causes it to define foo::two instead of foo::one.
+ auto ContextProvider = [](PathRef P) {
+ Config C;
+ if (P.endswith("foo.cpp"))
+ C.CompileFlags.Edits.push_back(
+ [](std::vector<std::string> &Argv) { Argv.push_back("-Done=two"); });
+ return Context::current().derive(Config::Key, std::move(C));
+ };
+ // Create the background index.
+ llvm::StringMap<std::string> Storage;
+ size_t CacheHits = 0;
+ MemoryShardStorage MSS(Storage, CacheHits);
+ // We need the CommandMangler, because that applies the config we're testing.
+ OverlayCDB CDB(/*Base=*/nullptr, /*FallbackFlags=*/{},
+ tooling::ArgumentsAdjuster(CommandMangler::forTests()));
+ BackgroundIndex Idx(
+ Context::empty(), FS, CDB, [&](llvm::StringRef) { return &MSS; },
+ /*ThreadPoolSize=*/4, /*OnProgress=*/nullptr, std::move(ContextProvider));
+ // Index the two files.
+ for (auto &Cmd : Cmds)
+ CDB.setCompileCommand(testPath(Cmd.Filename), std::move(Cmd));
+ // Wait for both files to be indexed.
+ ASSERT_TRUE(Idx.blockUntilIdleForTest());
+ EXPECT_THAT(runFuzzyFind(Idx, ""),
+ UnorderedElementsAre(QName("foo"), QName("foo::two"),
+ QName("bar"), QName("bar::one")));
+}
+
TEST_F(BackgroundIndexTest, IndexTwoFiles) {
MockFS FS;
// a.h yields
diff erent symbols when included by A.cc vs B.cc.
diff --git a/clang-tools-extra/clangd/unittests/ClangdTests.cpp b/clang-tools-extra/clangd/unittests/ClangdTests.cpp
index 943a3c7925f0..c21719d58bd6 100644
--- a/clang-tools-extra/clangd/unittests/ClangdTests.cpp
+++ b/clang-tools-extra/clangd/unittests/ClangdTests.cpp
@@ -10,6 +10,7 @@
#include "ClangdLSPServer.h"
#include "ClangdServer.h"
#include "CodeComplete.h"
+#include "ConfigFragment.h"
#include "GlobalCompilationDatabase.h"
#include "Matchers.h"
#include "SyncAPI.h"
@@ -19,6 +20,7 @@
#include "support/Threading.h"
#include "clang/Config/config.h"
#include "clang/Sema/CodeCompleteConsumer.h"
+#include "clang/Tooling/ArgumentsAdjusters.h"
#include "llvm/ADT/None.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallVector.h"
@@ -47,6 +49,7 @@ using ::testing::Field;
using ::testing::Gt;
using ::testing::IsEmpty;
using ::testing::Pair;
+using ::testing::SizeIs;
using ::testing::UnorderedElementsAre;
MATCHER_P2(DeclAt, File, Range, "") {
@@ -301,6 +304,48 @@ TEST_F(ClangdVFSTest, PropagatesContexts) {
EXPECT_EQ(Callbacks.Got, 42);
}
+TEST(ClangdServerTest, RespectsConfig) {
+ // Go-to-definition will resolve as marked if FOO is defined.
+ Annotations Example(R"cpp(
+ #ifdef FOO
+ int [[x]];
+ #else
+ int x;
+ #endif
+ int y = ^x;
+ )cpp");
+ // Provide conditional config that defines FOO for foo.cc.
+ class ConfigProvider : public config::Provider {
+ std::vector<config::CompiledFragment>
+ getFragments(const config::Params &,
+ config::DiagnosticCallback DC) const override {
+ config::Fragment F;
+ F.If.PathMatch.emplace_back(".*foo.cc");
+ F.CompileFlags.Add.emplace_back("-DFOO=1");
+ return {std::move(F).compile(DC)};
+ }
+ } CfgProvider;
+
+ auto Opts = ClangdServer::optsForTest();
+ Opts.ConfigProvider = &CfgProvider;
+ OverlayCDB CDB(/*Base=*/nullptr, /*FallbackFlags=*/{},
+ tooling::ArgumentsAdjuster(CommandMangler::forTests()));
+ MockFS FS;
+ ClangdServer Server(CDB, FS, Opts);
+ // foo.cc sees the expected definition, as FOO is defined.
+ Server.addDocument(testPath("foo.cc"), Example.code());
+ auto Result = runLocateSymbolAt(Server, testPath("foo.cc"), Example.point());
+ ASSERT_TRUE(bool(Result)) << Result.takeError();
+ ASSERT_THAT(*Result, SizeIs(1));
+ EXPECT_EQ(Result->front().PreferredDeclaration.range, Example.range());
+ // bar.cc gets a
diff erent result, as FOO is not defined.
+ Server.addDocument(testPath("bar.cc"), Example.code());
+ Result = runLocateSymbolAt(Server, testPath("bar.cc"), Example.point());
+ ASSERT_TRUE(bool(Result)) << Result.takeError();
+ ASSERT_THAT(*Result, SizeIs(1));
+ EXPECT_NE(Result->front().PreferredDeclaration.range, Example.range());
+}
+
TEST_F(ClangdVFSTest, PropagatesVersion) {
MockCompilationDatabase CDB;
MockFS FS;
diff --git a/clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp b/clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp
index 53a5979c7318..f40377fd5d85 100644
--- a/clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp
+++ b/clang-tools-extra/clangd/unittests/TUSchedulerTests.cpp
@@ -65,8 +65,20 @@ MATCHER_P2(TUState, PreambleActivity, ASTActivity, "") {
return true;
}
+// Dummy ContextProvider to verify the provider is invoked & contexts are used.
+static Key<std::string> BoundPath;
+Context bindPath(PathRef F) {
+ return Context::current().derive(BoundPath, F.str());
+}
+llvm::StringRef boundPath() {
+ const std::string *V = Context::current().get(BoundPath);
+ return V ? *V : llvm::StringRef("");
+}
+
TUScheduler::Options optsForTest() {
- return TUScheduler::Options(ClangdServer::optsForTest());
+ TUScheduler::Options Opts(ClangdServer::optsForTest());
+ Opts.ContextProvider = bindPath;
+ return Opts;
}
class TUSchedulerTests : public ::testing::Test {
@@ -454,6 +466,7 @@ TEST_F(TUSchedulerTests, ManyUpdates) {
[File, Nonce, Version(Inputs.Version), &Mut, &TotalUpdates,
&LatestDiagVersion](std::vector<Diag>) {
EXPECT_THAT(Context::current().get(NonceKey), Pointee(Nonce));
+ EXPECT_EQ(File, boundPath());
std::lock_guard<std::mutex> Lock(Mut);
++TotalUpdates;
@@ -474,6 +487,7 @@ TEST_F(TUSchedulerTests, ManyUpdates) {
[File, Inputs, Nonce, &Mut,
&TotalASTReads](Expected<InputsAndAST> AST) {
EXPECT_THAT(Context::current().get(NonceKey), Pointee(Nonce));
+ EXPECT_EQ(File, boundPath());
ASSERT_TRUE((bool)AST);
EXPECT_EQ(AST->Inputs.Contents, Inputs.Contents);
@@ -493,6 +507,7 @@ TEST_F(TUSchedulerTests, ManyUpdates) {
[File, Inputs, Nonce, &Mut,
&TotalPreambleReads](Expected<InputsAndPreamble> Preamble) {
EXPECT_THAT(Context::current().get(NonceKey), Pointee(Nonce));
+ EXPECT_EQ(File, boundPath());
ASSERT_TRUE((bool)Preamble);
EXPECT_EQ(Preamble->Contents, Inputs.Contents);
@@ -849,18 +864,22 @@ TEST_F(TUSchedulerTests, NoChangeDiags) {
}
TEST_F(TUSchedulerTests, Run) {
- TUScheduler S(CDB, optsForTest());
+ auto Opts = optsForTest();
+ Opts.ContextProvider = bindPath;
+ TUScheduler S(CDB, Opts);
std::atomic<int> Counter(0);
- S.run("add 1", [&] { ++Counter; });
- S.run("add 2", [&] { Counter += 2; });
+ S.run("add 1", /*Path=*/"", [&] { ++Counter; });
+ S.run("add 2", /*Path=*/"", [&] { Counter += 2; });
ASSERT_TRUE(S.blockUntilIdle(timeoutSeconds(10)));
EXPECT_EQ(Counter.load(), 3);
Notification TaskRun;
Key<int> TestKey;
WithContextValue CtxWithKey(TestKey, 10);
- S.run("props context", [&] {
+ const char *Path = "somepath";
+ S.run("props context", Path, [&] {
EXPECT_EQ(Context::current().getExisting(TestKey), 10);
+ EXPECT_EQ(Path, boundPath());
TaskRun.notify();
});
TaskRun.wait();
More information about the cfe-commits
mailing list