ilya-biryukov created this revision.
ilya-biryukov added reviewers: sammccall, bkramer.
Herald added a subscriber: klimek.
CppFile can now change compilation arguments during rebuild. This allows
simplifying code that manages CppFiles.
Repository:
rCTE Clang Tools Extra
https://reviews.llvm.org/D42173
Files:
clangd/ClangdServer.cpp
clangd/ClangdServer.h
clangd/ClangdUnit.cpp
clangd/ClangdUnit.h
clangd/ClangdUnitStore.cpp
clangd/ClangdUnitStore.h
Index: clangd/ClangdUnitStore.h
===================================================================
--- clangd/ClangdUnitStore.h
+++ clangd/ClangdUnitStore.h
@@ -32,42 +32,19 @@
std::shared_ptr<CppFile>
getOrCreateFile(PathRef File, PathRef ResourceDir,
- GlobalCompilationDatabase &CDB, bool StorePreamblesInMemory,
+ bool StorePreamblesInMemory,
std::shared_ptr<PCHContainerOperations> PCHs) {
std::lock_guard<std::mutex> Lock(Mutex);
-
auto It = OpenedFiles.find(File);
if (It == OpenedFiles.end()) {
- auto Command = getCompileCommand(CDB, File, ResourceDir);
-
It = OpenedFiles
- .try_emplace(File, CppFile::Create(File, std::move(Command),
- StorePreamblesInMemory,
+ .try_emplace(File, CppFile::Create(File, StorePreamblesInMemory,
std::move(PCHs), ASTCallback))
.first;
}
return It->second;
}
- struct RecreateResult {
- /// A CppFile, stored in this CppFileCollection for the corresponding
- /// filepath after calling recreateFileIfCompileCommandChanged.
- std::shared_ptr<CppFile> FileInCollection;
- /// If a new CppFile had to be created to account for changed
- /// CompileCommand, a previous CppFile instance will be returned in this
- /// field.
- std::shared_ptr<CppFile> RemovedFile;
- };
-
- /// Similar to getOrCreateFile, but will replace a current CppFile for \p File
- /// with a new one if CompileCommand, provided by \p CDB has changed.
- /// If a currently stored CppFile had to be replaced, the previous instance
- /// will be returned in RecreateResult.RemovedFile.
- RecreateResult recreateFileIfCompileCommandChanged(
- PathRef File, PathRef ResourceDir, GlobalCompilationDatabase &CDB,
- bool StorePreamblesInMemory,
- std::shared_ptr<PCHContainerOperations> PCHs);
-
std::shared_ptr<CppFile> getFile(PathRef File) {
std::lock_guard<std::mutex> Lock(Mutex);
@@ -82,12 +59,6 @@
std::shared_ptr<CppFile> removeIfPresent(PathRef File);
private:
- tooling::CompileCommand getCompileCommand(GlobalCompilationDatabase &CDB,
- PathRef File, PathRef ResourceDir);
-
- bool compileCommandsAreEqual(tooling::CompileCommand const &LHS,
- tooling::CompileCommand const &RHS);
-
std::mutex Mutex;
llvm::StringMap<std::shared_ptr<CppFile>> OpenedFiles;
ASTParsedCallback ASTCallback;
Index: clangd/ClangdUnitStore.cpp
===================================================================
--- clangd/ClangdUnitStore.cpp
+++ clangd/ClangdUnitStore.cpp
@@ -25,53 +25,3 @@
OpenedFiles.erase(It);
return Result;
}
-
-CppFileCollection::RecreateResult
-CppFileCollection::recreateFileIfCompileCommandChanged(
- PathRef File, PathRef ResourceDir, GlobalCompilationDatabase &CDB,
- bool StorePreamblesInMemory, std::shared_ptr<PCHContainerOperations> PCHs) {
- auto NewCommand = getCompileCommand(CDB, File, ResourceDir);
-
- std::lock_guard<std::mutex> Lock(Mutex);
-
- RecreateResult Result;
-
- auto It = OpenedFiles.find(File);
- if (It == OpenedFiles.end()) {
- It = OpenedFiles
- .try_emplace(File, CppFile::Create(File, std::move(NewCommand),
- StorePreamblesInMemory,
- std::move(PCHs), ASTCallback))
- .first;
- } else if (!compileCommandsAreEqual(It->second->getCompileCommand(),
- NewCommand)) {
- Result.RemovedFile = std::move(It->second);
- It->second =
- CppFile::Create(File, std::move(NewCommand), StorePreamblesInMemory,
- std::move(PCHs), ASTCallback);
- }
- Result.FileInCollection = It->second;
- return Result;
-}
-
-tooling::CompileCommand
-CppFileCollection::getCompileCommand(GlobalCompilationDatabase &CDB,
- PathRef File, PathRef ResourceDir) {
- llvm::Optional<tooling::CompileCommand> C = CDB.getCompileCommand(File);
- if (!C) // FIXME: Suppress diagnostics? Let the user know?
- C = CDB.getFallbackCommand(File);
-
- // Inject the resource dir.
- // FIXME: Don't overwrite it if it's already there.
- C->CommandLine.push_back("-resource-dir=" + ResourceDir.str());
- return std::move(*C);
-}
-
-bool CppFileCollection::compileCommandsAreEqual(
- tooling::CompileCommand const &LHS, tooling::CompileCommand const &RHS) {
- // tooling::CompileCommand.Output is ignored, it's not relevant for clangd.
- return LHS.Directory == RHS.Directory &&
- LHS.CommandLine.size() == RHS.CommandLine.size() &&
- std::equal(LHS.CommandLine.begin(), LHS.CommandLine.end(),
- RHS.CommandLine.begin());
-}
Index: clangd/ClangdUnit.h
===================================================================
--- clangd/ClangdUnit.h
+++ clangd/ClangdUnit.h
@@ -58,6 +58,20 @@
std::vector<DiagWithFixIts> Diags;
};
+/// Information required to run clang (e.g., to parse AST or do code
+/// completion).
+struct ParseInputs {
+ ParseInputs(tooling::CompileCommand CompileCommand,
+ IntrusiveRefCntPtr<vfs::FileSystem> FS, std::string Contents);
+
+ /// Compilation arguments.
+ tooling::CompileCommand CompileCommand;
+ /// FileSystem.
+ IntrusiveRefCntPtr<vfs::FileSystem> FS;
+ /// Contents to parse.
+ std::string Contents;
+};
+
/// Stores and provides access to parsed AST.
class ParsedAST {
public:
@@ -147,14 +161,12 @@
// We only allow to create CppFile as shared_ptr, because a future returned by
// deferRebuild will hold references to it.
static std::shared_ptr<CppFile>
- Create(PathRef FileName, tooling::CompileCommand Command,
- bool StorePreamblesInMemory,
+ Create(PathRef FileName, bool StorePreamblesInMemory,
std::shared_ptr<PCHContainerOperations> PCHs,
ASTParsedCallback ASTCallback);
private:
- CppFile(PathRef FileName, tooling::CompileCommand Command,
- bool StorePreamblesInMemory,
+ CppFile(PathRef FileName, bool StorePreamblesInMemory,
std::shared_ptr<PCHContainerOperations> PCHs,
ASTParsedCallback ASTCallback);
@@ -177,9 +189,8 @@
/// Returns a list of diagnostics or a llvm::None, if another rebuild was
/// requested in parallel (effectively cancelling this rebuild) before
/// diagnostics were produced.
- llvm::Optional<std::vector<DiagWithFixIts>>
- rebuild(const Context &Ctx, StringRef NewContents,
- IntrusiveRefCntPtr<vfs::FileSystem> VFS);
+ llvm::Optional<std::vector<DiagWithFixIts>> rebuild(const Context &Ctx,
+ ParseInputs Inputs);
/// Schedule a rebuild and return a deferred computation that will finish the
/// rebuild, that can be called on a different thread.
@@ -196,7 +207,7 @@
/// reparse, or None, if another deferRebuild was called before this
/// rebuild was finished.
UniqueFunction<llvm::Optional<std::vector<DiagWithFixIts>>(const Context &)>
- deferRebuild(StringRef NewContents, IntrusiveRefCntPtr<vfs::FileSystem> VFS);
+ deferRebuild(ParseInputs Inputs);
/// Returns a future to get the most fresh PreambleData for a file. The
/// future will wait until the Preamble is rebuilt.
@@ -212,8 +223,10 @@
/// always be non-null.
std::shared_future<std::shared_ptr<ParsedASTWrapper>> getAST() const;
- /// Get CompileCommand used to build this CppFile.
- tooling::CompileCommand const &getCompileCommand() const;
+ /// Get the latest CompileCommand used to build this CppFile. Returns
+ /// llvm::None before first call to rebuild() or after calls to
+ /// cancelRebuild().
+ llvm::Optional<tooling::CompileCommand> getLatestCommand() const;
private:
/// A helper guard that manages the state of CppFile during rebuild.
@@ -231,7 +244,6 @@
};
Path FileName;
- tooling::CompileCommand Command;
bool StorePreamblesInMemory;
/// Mutex protects all fields, declared below it, FileName and Command are not
@@ -243,6 +255,7 @@
bool RebuildInProgress;
/// Condition variable to indicate changes to RebuildInProgress.
std::condition_variable RebuildCond;
+ llvm::Optional<tooling::CompileCommand> LatestCommand;
/// Promise and future for the latests AST. Fulfilled during rebuild.
/// We use std::shared_ptr here because MVSC fails to compile non-copyable
Index: clangd/ClangdUnit.cpp
===================================================================
--- clangd/ClangdUnit.cpp
+++ clangd/ClangdUnit.cpp
@@ -220,6 +220,12 @@
} // namespace
+ParseInputs::ParseInputs(tooling::CompileCommand CompileCommand,
+ IntrusiveRefCntPtr<vfs::FileSystem> FS,
+ std::string Contents)
+ : CompileCommand(std::move(CompileCommand)), FS(std::move(FS)),
+ Contents(std::move(Contents)) {}
+
void clangd::dumpAST(ParsedAST &AST, llvm::raw_ostream &OS) {
AST.getASTContext().getTranslationUnitDecl()->dump(OS, true);
}
@@ -273,7 +279,6 @@
return Mgr.getMacroArgExpandedLocation(InputLoc);
}
-
} // namespace
void ParsedAST::ensurePreambleDeclsDeserialized() {
@@ -359,27 +364,22 @@
: AST(std::move(AST)) {}
std::shared_ptr<CppFile>
-CppFile::Create(PathRef FileName, tooling::CompileCommand Command,
- bool StorePreamblesInMemory,
+CppFile::Create(PathRef FileName, bool StorePreamblesInMemory,
std::shared_ptr<PCHContainerOperations> PCHs,
ASTParsedCallback ASTCallback) {
- return std::shared_ptr<CppFile>(
- new CppFile(FileName, std::move(Command), StorePreamblesInMemory,
- std::move(PCHs), std::move(ASTCallback)));
+ return std::shared_ptr<CppFile>(new CppFile(FileName, StorePreamblesInMemory,
+ std::move(PCHs),
+ std::move(ASTCallback)));
}
-CppFile::CppFile(PathRef FileName, tooling::CompileCommand Command,
- bool StorePreamblesInMemory,
+CppFile::CppFile(PathRef FileName, bool StorePreamblesInMemory,
std::shared_ptr<PCHContainerOperations> PCHs,
ASTParsedCallback ASTCallback)
- : FileName(FileName), Command(std::move(Command)),
- StorePreamblesInMemory(StorePreamblesInMemory), RebuildCounter(0),
- RebuildInProgress(false), PCHs(std::move(PCHs)),
+ : FileName(FileName), StorePreamblesInMemory(StorePreamblesInMemory),
+ RebuildCounter(0), RebuildInProgress(false), PCHs(std::move(PCHs)),
ASTCallback(std::move(ASTCallback)) {
// FIXME(ibiryukov): we should pass a proper Context here.
- log(Context::empty(), "Opened file " + FileName + " with command [" +
- this->Command.Directory + "] " +
- llvm::join(this->Command.CommandLine, " "));
+ log(Context::empty(), "Created CppFile for " + FileName);
std::lock_guard<std::mutex> Lock(Mutex);
LatestAvailablePreamble = nullptr;
@@ -431,14 +431,12 @@
}
llvm::Optional<std::vector<DiagWithFixIts>>
-CppFile::rebuild(const Context &Ctx, StringRef NewContents,
- IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
- return deferRebuild(NewContents, std::move(VFS))(Ctx);
+CppFile::rebuild(const Context &Ctx, ParseInputs Inputs) {
+ return deferRebuild(std::move(Inputs))(Ctx);
}
UniqueFunction<llvm::Optional<std::vector<DiagWithFixIts>>(const Context &)>
-CppFile::deferRebuild(StringRef NewContents,
- IntrusiveRefCntPtr<vfs::FileSystem> VFS) {
+CppFile::deferRebuild(ParseInputs Inputs) {
std::shared_ptr<const PreambleData> OldPreamble;
std::shared_ptr<PCHContainerOperations> PCHs;
unsigned RequestRebuildCounter;
@@ -463,6 +461,7 @@
this->ASTPromise = std::promise<std::shared_ptr<ParsedASTWrapper>>();
this->ASTFuture = this->ASTPromise.get_future();
}
+ this->LatestCommand = Inputs.CompileCommand;
} // unlock Mutex.
// Notify about changes to RebuildCounter.
RebuildCond.notify_all();
@@ -473,22 +472,30 @@
// Don't let this CppFile die before rebuild is finished.
std::shared_ptr<CppFile> That = shared_from_this();
auto FinishRebuild =
- [OldPreamble, VFS, RequestRebuildCounter, PCHs,
- That](std::string NewContents,
+ [OldPreamble, RequestRebuildCounter, PCHs,
+ That](ParseInputs Inputs,
const Context &Ctx) mutable /* to allow changing OldPreamble. */
-> llvm::Optional<std::vector<DiagWithFixIts>> {
+ log(Context::empty(),
+ "Rebuilding file " + That->FileName + " with command [" +
+ Inputs.CompileCommand.Directory + "] " +
+ llvm::join(Inputs.CompileCommand.CommandLine, " "));
+
+ auto &VFS = Inputs.FS;
+ auto &NewContents = Inputs.Contents;
+
// Only one execution of this method is possible at a time.
// RebuildGuard will wait for any ongoing rebuilds to finish and will put us
// into a state for doing a rebuild.
RebuildGuard Rebuild(*That, RequestRebuildCounter);
if (Rebuild.wasCancelledBeforeConstruction())
return llvm::None;
std::vector<const char *> ArgStrs;
- for (const auto &S : That->Command.CommandLine)
+ for (const auto &S : Inputs.CompileCommand.CommandLine)
ArgStrs.push_back(S.c_str());
- VFS->setCurrentWorkingDirectory(That->Command.Directory);
+ VFS->setCurrentWorkingDirectory(Inputs.CompileCommand.Directory);
std::unique_ptr<CompilerInvocation> CI;
{
@@ -617,7 +624,7 @@
return Diagnostics;
};
- return BindWithForward(FinishRebuild, NewContents.str());
+ return BindWithForward(FinishRebuild, std::move(Inputs));
}
std::shared_future<std::shared_ptr<const PreambleData>>
@@ -636,8 +643,9 @@
return ASTFuture;
}
-tooling::CompileCommand const &CppFile::getCompileCommand() const {
- return Command;
+llvm::Optional<tooling::CompileCommand> CppFile::getLatestCommand() const {
+ std::lock_guard<std::mutex> Lock(Mutex);
+ return LatestCommand;
}
CppFile::RebuildGuard::RebuildGuard(CppFile &File,
Index: clangd/ClangdServer.h
===================================================================
--- clangd/ClangdServer.h
+++ clangd/ClangdServer.h
@@ -331,7 +331,8 @@
std::future<Context>
scheduleReparseAndDiags(Context Ctx, PathRef File, VersionedDraft Contents,
std::shared_ptr<CppFile> Resources,
- Tagged<IntrusiveRefCntPtr<vfs::FileSystem>> TaggedFS);
+ Tagged<IntrusiveRefCntPtr<vfs::FileSystem>> TaggedFS,
+ bool UpdateCompileCommand);
std::future<Context>
scheduleCancelRebuild(Context Ctx, std::shared_ptr<CppFile> Resources);
Index: clangd/ClangdServer.cpp
===================================================================
--- clangd/ClangdServer.cpp
+++ clangd/ClangdServer.cpp
@@ -32,6 +32,18 @@
namespace {
+tooling::CompileCommand getCompileCommand(GlobalCompilationDatabase &CDB,
+ PathRef File, PathRef ResourceDir) {
+ llvm::Optional<tooling::CompileCommand> C = CDB.getCompileCommand(File);
+ if (!C) // FIXME: Suppress diagnostics? Let the user know?
+ C = CDB.getFallbackCommand(File);
+
+ // Inject the resource dir.
+ // FIXME: Don't overwrite it if it's already there.
+ C->CommandLine.push_back("-resource-dir=" + ResourceDir.str());
+ return std::move(*C);
+}
+
std::string getStandardResourceDir() {
static int Dummy; // Just an address in this process.
return CompilerInvocation::GetResourcesPath("clangd", (void *)&Dummy);
@@ -175,11 +187,12 @@
DocVersion Version = DraftMgr.updateDraft(File, Contents);
auto TaggedFS = FSProvider.getTaggedFileSystem(File);
- std::shared_ptr<CppFile> Resources = Units.getOrCreateFile(
- File, ResourceDir, CDB, StorePreamblesInMemory, PCHs);
+ std::shared_ptr<CppFile> Resources =
+ Units.getOrCreateFile(File, ResourceDir, StorePreamblesInMemory, PCHs);
return scheduleReparseAndDiags(std::move(Ctx), File,
VersionedDraft{Version, Contents.str()},
- std::move(Resources), std::move(TaggedFS));
+ std::move(Resources), std::move(TaggedFS),
+ /*UpdateCompileCommand=*/false);
}
std::future<Context> ClangdServer::removeDocument(Context Ctx, PathRef File) {
@@ -194,15 +207,11 @@
"forceReparse() was called for non-added document");
auto TaggedFS = FSProvider.getTaggedFileSystem(File);
- auto Recreated = Units.recreateFileIfCompileCommandChanged(
- File, ResourceDir, CDB, StorePreamblesInMemory, PCHs);
-
- // Note that std::future from this cleanup action is ignored.
- scheduleCancelRebuild(Ctx.clone(), std::move(Recreated.RemovedFile));
- // Schedule a reparse.
- return scheduleReparseAndDiags(std::move(Ctx), File, std::move(FileContents),
- std::move(Recreated.FileInCollection),
- std::move(TaggedFS));
+ std::shared_ptr<CppFile> Resources =
+ Units.getOrCreateFile(File, ResourceDir, StorePreamblesInMemory, PCHs);
+ return scheduleReparseAndDiags(std::move(Ctx), File, FileContents,
+ std::move(Resources), std::move(TaggedFS),
+ /*UpdateCompileCommand=*/true);
}
std::future<std::pair<Context, Tagged<CompletionList>>>
@@ -268,20 +277,24 @@
Path FileStr = File;
// Copy PCHs to avoid accessing this->PCHs concurrently
std::shared_ptr<PCHContainerOperations> PCHs = this->PCHs;
+
+ assert(Resources->getLatestCommand() &&
+ "CppFile is in inconsistent state, missing CompileCommand");
+ tooling::CompileCommand CompileCommand = *Resources->getLatestCommand();
+
// A task that will be run asynchronously.
auto Task =
// 'mutable' to reassign Preamble variable.
[FileStr, Preamble, Resources, Contents, Pos, CodeCompleteOpts, TaggedFS,
- PCHs](Context Ctx, CallbackType Callback) mutable {
+ PCHs, CompileCommand](Context Ctx, CallbackType Callback) mutable {
if (!Preamble) {
// Maybe we built some preamble before processing this request.
Preamble = Resources->getPossiblyStalePreamble();
}
// FIXME(ibiryukov): even if Preamble is non-null, we may want to check
// both the old and the new version in case only one of them matches.
-
CompletionList Result = clangd::codeComplete(
- Ctx, FileStr, Resources->getCompileCommand(),
+ Ctx, FileStr, CompileCommand,
Preamble ? &Preamble->Preamble : nullptr, Contents, Pos,
TaggedFS.Value, PCHs, CodeCompleteOpts);
@@ -319,11 +332,14 @@
"signatureHelp is called for non-added document",
llvm::errc::invalid_argument);
+ assert(Resources->getLatestCommand() &&
+ "CppFile is in inconsistent state, missing CompileCommand");
+ tooling::CompileCommand CompileCommand = *Resources->getLatestCommand();
+
auto Preamble = Resources->getPossiblyStalePreamble();
- auto Result =
- clangd::signatureHelp(Ctx, File, Resources->getCompileCommand(),
- Preamble ? &Preamble->Preamble : nullptr,
- *OverridenContents, Pos, TaggedFS.Value, PCHs);
+ auto Result = clangd::signatureHelp(
+ Ctx, File, CompileCommand, Preamble ? &Preamble->Preamble : nullptr,
+ *OverridenContents, Pos, TaggedFS.Value, PCHs);
return make_tagged(std::move(Result), TaggedFS.Tag);
}
@@ -555,12 +571,21 @@
std::future<Context> ClangdServer::scheduleReparseAndDiags(
Context Ctx, PathRef File, VersionedDraft Contents,
std::shared_ptr<CppFile> Resources,
- Tagged<IntrusiveRefCntPtr<vfs::FileSystem>> TaggedFS) {
-
+ Tagged<IntrusiveRefCntPtr<vfs::FileSystem>> TaggedFS,
+ bool UpdateCompileCommand) {
+
+ llvm::Optional<tooling::CompileCommand> FileCmd =
+ Resources->getLatestCommand();
+ tooling::CompileCommand CompileCommand =
+ (UpdateCompileCommand || !FileCmd)
+ ? getCompileCommand(CDB, File, ResourceDir)
+ : *FileCmd;
+
+ ParseInputs Inputs(std::move(CompileCommand), std::move(TaggedFS.Value),
+ *std::move(Contents.Draft));
assert(Contents.Draft && "Draft must have contents");
UniqueFunction<llvm::Optional<std::vector<DiagWithFixIts>>(const Context &)>
- DeferredRebuild =
- Resources->deferRebuild(*Contents.Draft, TaggedFS.Value);
+ DeferredRebuild = Resources->deferRebuild(std::move(Inputs));
std::promise<Context> DonePromise;
std::future<Context> DoneFuture = DonePromise.get_future();
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits