Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions clang-tools-extra/clangd/ClangdLSPServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,8 @@ void ClangdLSPServer::onInitialize(const InitializeParams &Params,
if (const auto &Dir = Params.initializationOptions.compilationDatabasePath)
CDBOpts.CompileCommandsDir = Dir;
CDBOpts.ContextProvider = Opts.ContextProvider;
if (Opts.StrongWorkspaceMode)
CDBOpts.applyFallbackWorkingDirectory(Opts.WorkspaceRoot);
BaseCDB =
std::make_unique<DirectoryBasedGlobalCompilationDatabase>(CDBOpts);
}
Expand Down
5 changes: 5 additions & 0 deletions clang-tools-extra/clangd/ClangdServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,11 @@ class ClangdServer {
/// FIXME: If not set, should use the current working directory.
std::optional<std::string> WorkspaceRoot;

/// Sets an alternate mode of operation. Current effects are:
/// - Using the current working directory as the working directory for
/// fallback commands
bool StrongWorkspaceMode = false;

/// The resource directory is used to find internal headers, overriding
/// defaults and -resource-dir compiler flag).
/// If std::nullopt, ClangdServer calls
Expand Down
41 changes: 32 additions & 9 deletions clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,9 @@ GlobalCompilationDatabase::getFallbackCommand(PathRef File) const {
if (FileExtension.empty() || FileExtension == ".h")
Argv.push_back("-xobjective-c++-header");
Argv.push_back(std::string(File));
tooling::CompileCommand Cmd(llvm::sys::path::parent_path(File),
tooling::CompileCommand Cmd(FallbackWorkingDirectory
? *FallbackWorkingDirectory
: llvm::sys::path::parent_path(File),
llvm::sys::path::filename(File), std::move(Argv),
/*Output=*/"");
Cmd.Heuristic = "clangd fallback";
Expand Down Expand Up @@ -349,7 +351,8 @@ bool DirectoryBasedGlobalCompilationDatabase::DirectoryCache::load(

DirectoryBasedGlobalCompilationDatabase::
DirectoryBasedGlobalCompilationDatabase(const Options &Opts)
: Opts(Opts), Broadcaster(std::make_unique<BroadcastThread>(*this)) {
: GlobalCompilationDatabase(Opts.FallbackWorkingDirectory), Opts(Opts),
Broadcaster(std::make_unique<BroadcastThread>(*this)) {
if (!this->Opts.ContextProvider)
this->Opts.ContextProvider = [](llvm::StringRef) {
return Context::current().clone();
Expand Down Expand Up @@ -460,6 +463,21 @@ DirectoryBasedGlobalCompilationDatabase::lookupCDB(
return Result;
}

void DirectoryBasedGlobalCompilationDatabase::Options::
applyFallbackWorkingDirectory(
std::optional<std::string> FallbackWorkingDirectory) {
if (FallbackWorkingDirectory)
this->FallbackWorkingDirectory = *FallbackWorkingDirectory;
else {
// Clangd is running in strong workspace mode but the client didn't
// specify a workspace path in the `initialize` request.
// Fallback to current working directory.
SmallString<256> CWD;
llvm::sys::fs::current_path(CWD);
this->FallbackWorkingDirectory = std::string(CWD);
}
}

// The broadcast thread announces files with new compile commands to the world.
// Primarily this is used to enqueue them for background indexing.
//
Expand Down Expand Up @@ -759,9 +777,10 @@ DirectoryBasedGlobalCompilationDatabase::getProjectModules(PathRef File) const {

OverlayCDB::OverlayCDB(const GlobalCompilationDatabase *Base,
std::vector<std::string> FallbackFlags,
CommandMangler Mangler)
: DelegatingCDB(Base), Mangler(std::move(Mangler)),
FallbackFlags(std::move(FallbackFlags)) {}
CommandMangler Mangler,
std::optional<std::string> FallbackWorkingDirectory)
: DelegatingCDB(Base, FallbackWorkingDirectory),
Mangler(std::move(Mangler)), FallbackFlags(std::move(FallbackFlags)) {}

std::optional<tooling::CompileCommand>
OverlayCDB::getCompileCommand(PathRef File) const {
Expand Down Expand Up @@ -844,16 +863,20 @@ OverlayCDB::getProjectModules(PathRef File) const {
return MDB;
}

DelegatingCDB::DelegatingCDB(const GlobalCompilationDatabase *Base)
: Base(Base) {
DelegatingCDB::DelegatingCDB(
const GlobalCompilationDatabase *Base,
std::optional<std::string> FallbackWorkingDirectory)
: GlobalCompilationDatabase(FallbackWorkingDirectory), Base(Base) {
if (Base)
BaseChanged = Base->watch([this](const std::vector<std::string> Changes) {
OnCommandChanged.broadcast(Changes);
});
}

DelegatingCDB::DelegatingCDB(std::unique_ptr<GlobalCompilationDatabase> Base)
: DelegatingCDB(Base.get()) {
DelegatingCDB::DelegatingCDB(
std::unique_ptr<GlobalCompilationDatabase> Base,
std::optional<std::string> FallbackWorkingDirectory)
: DelegatingCDB(Base.get(), FallbackWorkingDirectory) {
BaseOwner = std::move(Base);
}

Expand Down
26 changes: 21 additions & 5 deletions clang-tools-extra/clangd/GlobalCompilationDatabase.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ struct ProjectInfo {
/// Provides compilation arguments used for parsing C and C++ files.
class GlobalCompilationDatabase {
public:
GlobalCompilationDatabase(
std::optional<std::string> FallbackWorkingDirectory = std::nullopt)
: FallbackWorkingDirectory(FallbackWorkingDirectory) {}
virtual ~GlobalCompilationDatabase() = default;

/// If there are any known-good commands for building this file, returns one.
Expand Down Expand Up @@ -69,14 +72,19 @@ class GlobalCompilationDatabase {
}

protected:
std::optional<std::string> FallbackWorkingDirectory;
mutable CommandChanged OnCommandChanged;
};

// Helper class for implementing GlobalCompilationDatabases that wrap others.
class DelegatingCDB : public GlobalCompilationDatabase {
public:
DelegatingCDB(const GlobalCompilationDatabase *Base);
DelegatingCDB(std::unique_ptr<GlobalCompilationDatabase> Base);
DelegatingCDB(
const GlobalCompilationDatabase *Base,
std::optional<std::string> FallbackWorkingDirectory = std::nullopt);
DelegatingCDB(
std::unique_ptr<GlobalCompilationDatabase> Base,
std::optional<std::string> FallbackWorkingDirectory = std::nullopt);

std::optional<tooling::CompileCommand>
getCompileCommand(PathRef File) const override;
Expand Down Expand Up @@ -117,6 +125,12 @@ class DirectoryBasedGlobalCompilationDatabase
// Only look for a compilation database in this one fixed directory.
// FIXME: fold this into config/context mechanism.
std::optional<Path> CompileCommandsDir;
// Working directory for fallback commands
// If unset, parent directory of file should be used
std::optional<std::string> FallbackWorkingDirectory;

void applyFallbackWorkingDirectory(
std::optional<std::string> FallbackWorkingDirectory);
};

DirectoryBasedGlobalCompilationDatabase(const Options &Opts);
Expand Down Expand Up @@ -194,9 +208,11 @@ class OverlayCDB : public DelegatingCDB {
// Base may be null, in which case no entries are inherited.
// FallbackFlags are added to the fallback compile command.
// Adjuster is applied to all commands, fallback or not.
OverlayCDB(const GlobalCompilationDatabase *Base,
std::vector<std::string> FallbackFlags = {},
CommandMangler Mangler = nullptr);
OverlayCDB(
const GlobalCompilationDatabase *Base,
std::vector<std::string> FallbackFlags = {},
CommandMangler Mangler = nullptr,
std::optional<std::string> FallbackWorkingDirectory = std::nullopt);

std::optional<tooling::CompileCommand>
getCompileCommand(PathRef File) const override;
Expand Down
8 changes: 6 additions & 2 deletions clang-tools-extra/clangd/tool/Check.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,8 @@ class Checker {
bool buildCommand(const ThreadsafeFS &TFS) {
log("Loading compilation database...");
DirectoryBasedGlobalCompilationDatabase::Options CDBOpts(TFS);
if (Opts.StrongWorkspaceMode)
CDBOpts.applyFallbackWorkingDirectory(Opts.WorkspaceRoot);
CDBOpts.CompileCommandsDir =
Config::current().CompileFlags.CDBSearch.FixedCDBPath;
BaseCDB =
Expand All @@ -178,8 +180,10 @@ class Checker {
getSystemIncludeExtractor(llvm::ArrayRef(Opts.QueryDriverGlobs));
if (Opts.ResourceDir)
Mangler.ResourceDir = *Opts.ResourceDir;

CDB = std::make_unique<OverlayCDB>(
BaseCDB.get(), std::vector<std::string>{}, std::move(Mangler));
BaseCDB.get(), std::vector<std::string>{}, std::move(Mangler),
CDBOpts.FallbackWorkingDirectory);

if (auto TrueCmd = CDB->getCompileCommand(File)) {
Cmd = std::move(*TrueCmd);
Expand Down Expand Up @@ -502,7 +506,7 @@ bool check(llvm::StringRef File, const ThreadsafeFS &TFS,
config::DiagnosticCallback Diag) const override {
config::Fragment F;
// If we're timing clang-tidy checks, implicitly disabling the slow ones
// is counterproductive!
// is counterproductive!
if (CheckTidyTime.getNumOccurrences())
F.Diagnostics.ClangTidy.FastCheckFilter.emplace("None");
return {std::move(F).compile(Diag)};
Expand Down
12 changes: 12 additions & 0 deletions clang-tools-extra/clangd/tool/ClangdMain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,17 @@ opt<bool> EnableConfig{
init(true),
};

opt<bool> StrongWorkspaceMode{
"strong-workspace-mode",
cat(Features),
desc("An alternate mode of operation for clangd, where the clangd instance "
"is used to edit a single workspace.\n"
"When enabled, fallback commands use the workspace directory as their "
"working directory instead of the parent folder."),
init(false),
Hidden,
};

opt<bool> UseDirtyHeaders{"use-dirty-headers", cat(Misc),
desc("Use files open in the editor when parsing "
"headers instead of reading from the disk"),
Expand Down Expand Up @@ -907,6 +918,7 @@ clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment var
}
if (!ResourceDir.empty())
Opts.ResourceDir = ResourceDir;
Opts.StrongWorkspaceMode = StrongWorkspaceMode;
Opts.BuildDynamicSymbolIndex = true;
#if CLANGD_ENABLE_REMOTE
if (RemoteIndexAddress.empty() != ProjectRoot.empty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,20 @@ TEST(GlobalCompilationDatabaseTest, FallbackCommand) {
testPath("foo/bar")));
}

TEST(GlobalCompilationDatabaseTest, FallbackWorkingDirectory) {
MockFS TFS;
DirectoryBasedGlobalCompilationDatabase::Options CDBOpts(TFS);
CDBOpts.applyFallbackWorkingDirectory(testPath("foo"));
EXPECT_EQ(CDBOpts.FallbackWorkingDirectory, testPath("foo"));

DirectoryBasedGlobalCompilationDatabase DB(CDBOpts);
auto Cmd = DB.getFallbackCommand(testPath("foo/src/bar.cc"));
EXPECT_EQ(Cmd.Directory, testPath("foo"));
EXPECT_THAT(Cmd.CommandLine,
ElementsAre("clang", testPath("foo/src/bar.cc")));
EXPECT_EQ(Cmd.Output, "");
}

static tooling::CompileCommand cmd(llvm::StringRef File, llvm::StringRef Arg) {
return tooling::CompileCommand(
testRoot(), File, {"clang", std::string(Arg), std::string(File)}, "");
Expand Down