Skip to content
Open
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
1 change: 1 addition & 0 deletions clang-tools-extra/clangd/ClangdServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ ClangdServer::Options::operator TUScheduler::Options() const {
Opts.UpdateDebounce = UpdateDebounce;
Opts.ContextProvider = ContextProvider;
Opts.PreambleThrottler = PreambleThrottler;
Opts.FallbackProjectRoot = FallbackProjectRoot;
return Opts;
}

Expand Down
4 changes: 4 additions & 0 deletions clang-tools-extra/clangd/ClangdServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,10 @@ class ClangdServer {
/// FIXME: If not set, should use the current working directory.
std::optional<std::string> WorkspaceRoot;

/// If set, fallback command uses this path as its current working directory
/// instead of the file's parent path.
std::optional<std::string> FallbackProjectRoot;

/// The resource directory is used to find internal headers, overriding
/// defaults and -resource-dir compiler flag).
/// If std::nullopt, ClangdServer calls
Expand Down
14 changes: 7 additions & 7 deletions clang-tools-extra/clangd/GlobalCompilationDatabase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ void actOnAllParentDirectories(PathRef FileName,
} // namespace

tooling::CompileCommand
GlobalCompilationDatabase::getFallbackCommand(PathRef File) const {
GlobalCompilationDatabase::getFallbackCommand(PathRef File, std::optional<std::string> ProjectRoot) const {
std::vector<std::string> Argv = {"clang"};
// Clang treats .h files as C by default and files without extension as linker
// input, resulting in unhelpful diagnostics.
Expand All @@ -64,7 +64,7 @@ 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(ProjectRoot ? *ProjectRoot : llvm::sys::path::parent_path(File),
llvm::sys::path::filename(File), std::move(Argv),
/*Output=*/"");
Cmd.Heuristic = "clangd fallback";
Expand Down Expand Up @@ -797,8 +797,8 @@ OverlayCDB::getCompileCommand(PathRef File) const {
return Cmd;
}

tooling::CompileCommand OverlayCDB::getFallbackCommand(PathRef File) const {
auto Cmd = DelegatingCDB::getFallbackCommand(File);
tooling::CompileCommand OverlayCDB::getFallbackCommand(PathRef File, std::optional<std::string> ProjectRoot) const {
auto Cmd = DelegatingCDB::getFallbackCommand(File, ProjectRoot);
std::lock_guard<std::mutex> Lock(Mutex);
Cmd.CommandLine.insert(Cmd.CommandLine.end(), FallbackFlags.begin(),
FallbackFlags.end());
Expand Down Expand Up @@ -877,10 +877,10 @@ DelegatingCDB::getProjectModules(PathRef File) const {
return Base->getProjectModules(File);
}

tooling::CompileCommand DelegatingCDB::getFallbackCommand(PathRef File) const {
tooling::CompileCommand DelegatingCDB::getFallbackCommand(PathRef File, std::optional<std::string> ProjectRoot) const {
if (!Base)
return GlobalCompilationDatabase::getFallbackCommand(File);
return Base->getFallbackCommand(File);
return GlobalCompilationDatabase::getFallbackCommand(File, ProjectRoot);
return Base->getFallbackCommand(File, ProjectRoot);
}

bool DelegatingCDB::blockUntilIdle(Deadline D) const {
Expand Down
6 changes: 3 additions & 3 deletions clang-tools-extra/clangd/GlobalCompilationDatabase.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ class GlobalCompilationDatabase {
/// Makes a guess at how to build a file.
/// The default implementation just runs clang on the file.
/// Clangd should treat the results as unreliable.
virtual tooling::CompileCommand getFallbackCommand(PathRef File) const;
virtual tooling::CompileCommand getFallbackCommand(PathRef File, std::optional<std::string> ProjectRoot = std::nullopt) const;

/// If the CDB does any asynchronous work, wait for it to complete.
/// For use in tests.
Expand Down Expand Up @@ -86,7 +86,7 @@ class DelegatingCDB : public GlobalCompilationDatabase {
std::unique_ptr<ProjectModules>
getProjectModules(PathRef File) const override;

tooling::CompileCommand getFallbackCommand(PathRef File) const override;
tooling::CompileCommand getFallbackCommand(PathRef File, std::optional<std::string> ProjectRoot = std::nullopt) const override;

bool blockUntilIdle(Deadline D) const override;

Expand Down Expand Up @@ -200,7 +200,7 @@ class OverlayCDB : public DelegatingCDB {

std::optional<tooling::CompileCommand>
getCompileCommand(PathRef File) const override;
tooling::CompileCommand getFallbackCommand(PathRef File) const override;
tooling::CompileCommand getFallbackCommand(PathRef File, std::optional<std::string> ProjectRoot = std::nullopt) const override;

/// Sets or clears the compilation command for a particular file.
/// Returns true if the command was changed (including insertion and removal),
Expand Down
6 changes: 4 additions & 2 deletions clang-tools-extra/clangd/TUScheduler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -723,6 +723,7 @@ class ASTWorker {
const GlobalCompilationDatabase &CDB;
/// Callback invoked when preamble or main file AST is built.
ParsingCallbacks &Callbacks;
std::optional<std::string> FallbackProjectRoot;

Semaphore &Barrier;
/// Whether the 'onMainAST' callback ran for the current FileInputs.
Expand Down Expand Up @@ -840,13 +841,14 @@ ASTWorker::ASTWorker(PathRef FileName, const GlobalCompilationDatabase &CDB,
: IdleASTs(LRUCache), HeaderIncluders(HeaderIncluders), RunSync(RunSync),
UpdateDebounce(Opts.UpdateDebounce), FileName(FileName),
ContextProvider(Opts.ContextProvider), CDB(CDB), Callbacks(Callbacks),
FallbackProjectRoot(Opts.FallbackProjectRoot),
Barrier(Barrier), Done(false), Status(FileName, Callbacks),
PreamblePeer(FileName, Callbacks, Opts.StorePreamblesInMemory, RunSync,
Opts.PreambleThrottler, Status, HeaderIncluders, *this) {
// Set a fallback command because compile command can be accessed before
// `Inputs` is initialized. Other fields are only used after initialization
// from client inputs.
FileInputs.CompileCommand = CDB.getFallbackCommand(FileName);
FileInputs.CompileCommand = CDB.getFallbackCommand(FileName, FallbackProjectRoot);
}

ASTWorker::~ASTWorker() {
Expand Down Expand Up @@ -888,7 +890,7 @@ void ASTWorker::update(ParseInputs Inputs, WantDiagnostics WantDiags,
if (Cmd)
Inputs.CompileCommand = std::move(*Cmd);
else
Inputs.CompileCommand = CDB.getFallbackCommand(FileName);
Inputs.CompileCommand = CDB.getFallbackCommand(FileName, FallbackProjectRoot);

bool InputsAreTheSame =
std::tie(FileInputs.CompileCommand, FileInputs.Contents) ==
Expand Down
4 changes: 4 additions & 0 deletions clang-tools-extra/clangd/TUScheduler.h
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,10 @@ class TUScheduler {
/// Typically to inject per-file configuration.
/// If the path is empty, context sholud be "generic".
std::function<Context(PathRef)> ContextProvider;

/// If set, fallback command uses this path as its current working directory
/// instead of the file's parent path.
std::optional<std::string> FallbackProjectRoot;
};

TUScheduler(const GlobalCompilationDatabase &CDB, const Options &Opts,
Expand Down
4 changes: 2 additions & 2 deletions clang-tools-extra/clangd/tool/Check.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ class Checker {
Cmd.Heuristic.empty() ? "from CDB" : Cmd.Heuristic, Cmd.Directory,
printArgv(Cmd.CommandLine));
} else {
Cmd = CDB->getFallbackCommand(File);
Cmd = CDB->getFallbackCommand(File, Opts.FallbackProjectRoot);
log("Generic fallback command is: [{0}] {1}", Cmd.Directory,
printArgv(Cmd.CommandLine));
}
Expand Down Expand Up @@ -502,7 +502,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
10 changes: 10 additions & 0 deletions clang-tools-extra/clangd/tool/ClangdMain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,14 @@ opt<bool> EnableConfig{
init(true),
};

opt<Path> ProjectRoot{
"project-root",
cat(Misc),
desc("Path to use as the current working directory for fallback commands."),
init(""),
ValueOptional,
};

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 @@ -906,6 +914,8 @@ clangd accepts flags on the commandline, and in the CLANGD_FLAGS environment var
}
if (!ResourceDir.empty())
Opts.ResourceDir = ResourceDir;
if (!ProjectRoot.empty())
Opts.FallbackProjectRoot = ProjectRoot;
Opts.BuildDynamicSymbolIndex = true;
#if CLANGD_ENABLE_REMOTE
if (RemoteIndexAddress.empty() != ProjectRoot.empty()) {
Expand Down