2017-05-16 17:38:59 +08:00
|
|
|
//===--- ClangdUnit.h -------------------------------------------*- C++-*-===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===---------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDUNIT_H
|
|
|
|
#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDUNIT_H
|
|
|
|
|
|
|
|
#include "Path.h"
|
2017-05-26 20:26:51 +08:00
|
|
|
#include "Protocol.h"
|
2017-09-30 00:41:23 +08:00
|
|
|
#include "clang/Frontend/FrontendAction.h"
|
2017-07-21 21:29:29 +08:00
|
|
|
#include "clang/Frontend/PrecompiledPreamble.h"
|
|
|
|
#include "clang/Serialization/ASTBitCodes.h"
|
|
|
|
#include "clang/Tooling/CompilationDatabase.h"
|
2017-05-16 17:38:59 +08:00
|
|
|
#include "clang/Tooling/Core/Replacement.h"
|
2017-08-01 23:51:38 +08:00
|
|
|
#include <atomic>
|
|
|
|
#include <future>
|
2017-05-16 17:38:59 +08:00
|
|
|
#include <memory>
|
2017-08-01 23:51:38 +08:00
|
|
|
#include <mutex>
|
2017-05-16 17:38:59 +08:00
|
|
|
|
2017-05-23 21:42:59 +08:00
|
|
|
namespace llvm {
|
|
|
|
class raw_ostream;
|
|
|
|
}
|
|
|
|
|
2017-05-16 17:38:59 +08:00
|
|
|
namespace clang {
|
|
|
|
class PCHContainerOperations;
|
|
|
|
|
2017-05-26 20:26:51 +08:00
|
|
|
namespace vfs {
|
|
|
|
class FileSystem;
|
|
|
|
}
|
|
|
|
|
2017-05-16 17:38:59 +08:00
|
|
|
namespace tooling {
|
|
|
|
struct CompileCommand;
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace clangd {
|
|
|
|
|
2017-09-20 15:24:15 +08:00
|
|
|
class Logger;
|
|
|
|
|
2017-05-16 17:38:59 +08:00
|
|
|
/// A diagnostic with its FixIts.
|
|
|
|
struct DiagWithFixIts {
|
|
|
|
clangd::Diagnostic Diag;
|
|
|
|
llvm::SmallVector<tooling::Replacement, 1> FixIts;
|
|
|
|
};
|
|
|
|
|
2017-08-01 23:51:38 +08:00
|
|
|
/// Stores and provides access to parsed AST.
|
|
|
|
class ParsedAST {
|
2017-05-16 17:38:59 +08:00
|
|
|
public:
|
2017-08-01 23:51:38 +08:00
|
|
|
/// Attempts to run Clang and store parsed AST. If \p Preamble is non-null
|
|
|
|
/// it is reused during parsing.
|
|
|
|
static llvm::Optional<ParsedAST>
|
|
|
|
Build(std::unique_ptr<clang::CompilerInvocation> CI,
|
|
|
|
const PrecompiledPreamble *Preamble,
|
|
|
|
ArrayRef<serialization::DeclID> PreambleDeclIDs,
|
|
|
|
std::unique_ptr<llvm::MemoryBuffer> Buffer,
|
|
|
|
std::shared_ptr<PCHContainerOperations> PCHs,
|
2017-09-20 15:24:15 +08:00
|
|
|
IntrusiveRefCntPtr<vfs::FileSystem> VFS, clangd::Logger &Logger);
|
2017-08-01 23:51:38 +08:00
|
|
|
|
|
|
|
ParsedAST(ParsedAST &&Other);
|
|
|
|
ParsedAST &operator=(ParsedAST &&Other);
|
|
|
|
|
|
|
|
~ParsedAST();
|
|
|
|
|
|
|
|
ASTContext &getASTContext();
|
|
|
|
const ASTContext &getASTContext() const;
|
|
|
|
|
|
|
|
Preprocessor &getPreprocessor();
|
|
|
|
const Preprocessor &getPreprocessor() const;
|
|
|
|
|
|
|
|
/// This function returns all top-level decls, including those that come
|
|
|
|
/// from Preamble. Decls, coming from Preamble, have to be deserialized, so
|
|
|
|
/// this call might be expensive.
|
|
|
|
ArrayRef<const Decl *> getTopLevelDecls();
|
|
|
|
|
|
|
|
const std::vector<DiagWithFixIts> &getDiagnostics() const;
|
2017-05-23 21:42:59 +08:00
|
|
|
|
2017-05-16 17:38:59 +08:00
|
|
|
private:
|
2017-08-01 23:51:38 +08:00
|
|
|
ParsedAST(std::unique_ptr<CompilerInstance> Clang,
|
|
|
|
std::unique_ptr<FrontendAction> Action,
|
|
|
|
std::vector<const Decl *> TopLevelDecls,
|
|
|
|
std::vector<serialization::DeclID> PendingTopLevelDecls,
|
|
|
|
std::vector<DiagWithFixIts> Diags);
|
2017-07-21 21:29:29 +08:00
|
|
|
|
2017-08-01 23:51:38 +08:00
|
|
|
private:
|
|
|
|
void ensurePreambleDeclsDeserialized();
|
|
|
|
|
|
|
|
// We store an "incomplete" FrontendAction (i.e. no EndSourceFile was called
|
|
|
|
// on it) and CompilerInstance used to run it. That way we don't have to do
|
|
|
|
// complex memory management of all Clang structures on our own. (They are
|
|
|
|
// stored in CompilerInstance and cleaned up by
|
|
|
|
// FrontendAction.EndSourceFile).
|
|
|
|
std::unique_ptr<CompilerInstance> Clang;
|
|
|
|
std::unique_ptr<FrontendAction> Action;
|
|
|
|
|
|
|
|
// Data, stored after parsing.
|
|
|
|
std::vector<DiagWithFixIts> Diags;
|
|
|
|
std::vector<const Decl *> TopLevelDecls;
|
|
|
|
std::vector<serialization::DeclID> PendingTopLevelDecls;
|
|
|
|
};
|
2017-07-21 21:29:29 +08:00
|
|
|
|
2017-08-01 23:51:38 +08:00
|
|
|
// Provides thread-safe access to ParsedAST.
|
|
|
|
class ParsedASTWrapper {
|
|
|
|
public:
|
|
|
|
ParsedASTWrapper(ParsedASTWrapper &&Wrapper);
|
|
|
|
ParsedASTWrapper(llvm::Optional<ParsedAST> AST);
|
2017-07-21 21:29:29 +08:00
|
|
|
|
2017-08-01 23:51:38 +08:00
|
|
|
/// Runs \p F on wrapped ParsedAST under lock. Ensures it is not accessed
|
|
|
|
/// concurrently.
|
|
|
|
template <class Func> void runUnderLock(Func F) const {
|
|
|
|
std::lock_guard<std::mutex> Lock(Mutex);
|
|
|
|
F(AST ? AST.getPointer() : nullptr);
|
|
|
|
}
|
2017-07-21 21:29:29 +08:00
|
|
|
|
2017-08-01 23:51:38 +08:00
|
|
|
private:
|
|
|
|
// This wrapper is used as an argument to std::shared_future (and it returns a
|
|
|
|
// const ref in get()), but we need to have non-const ref in order to
|
|
|
|
// implement some features.
|
|
|
|
mutable std::mutex Mutex;
|
|
|
|
mutable llvm::Optional<ParsedAST> AST;
|
|
|
|
};
|
2017-07-21 21:29:29 +08:00
|
|
|
|
2017-08-01 23:51:38 +08:00
|
|
|
// Stores Preamble and associated data.
|
|
|
|
struct PreambleData {
|
|
|
|
PreambleData(PrecompiledPreamble Preamble,
|
|
|
|
std::vector<serialization::DeclID> TopLevelDeclIDs,
|
|
|
|
std::vector<DiagWithFixIts> Diags);
|
2017-07-21 21:29:29 +08:00
|
|
|
|
2017-08-01 23:51:38 +08:00
|
|
|
PrecompiledPreamble Preamble;
|
|
|
|
std::vector<serialization::DeclID> TopLevelDeclIDs;
|
|
|
|
std::vector<DiagWithFixIts> Diags;
|
|
|
|
};
|
2017-07-21 21:29:29 +08:00
|
|
|
|
2017-08-01 23:51:38 +08:00
|
|
|
/// Manages resources, required by clangd. Allows to rebuild file with new
|
|
|
|
/// contents, and provides AST and Preamble for it.
|
|
|
|
class CppFile : public std::enable_shared_from_this<CppFile> {
|
|
|
|
public:
|
|
|
|
// 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,
|
2017-09-20 15:24:15 +08:00
|
|
|
std::shared_ptr<PCHContainerOperations> PCHs, clangd::Logger &Logger);
|
2017-07-21 21:29:29 +08:00
|
|
|
|
2017-08-01 23:51:38 +08:00
|
|
|
private:
|
|
|
|
CppFile(PathRef FileName, tooling::CompileCommand Command,
|
2017-09-20 15:24:15 +08:00
|
|
|
std::shared_ptr<PCHContainerOperations> PCHs, clangd::Logger &Logger);
|
2017-07-21 21:29:29 +08:00
|
|
|
|
2017-08-01 23:51:38 +08:00
|
|
|
public:
|
|
|
|
CppFile(CppFile const &) = delete;
|
|
|
|
CppFile(CppFile &&) = delete;
|
|
|
|
|
2017-08-14 16:17:24 +08:00
|
|
|
/// Cancels a scheduled rebuild, if any, and sets AST and Preamble to nulls.
|
2017-08-01 23:51:38 +08:00
|
|
|
/// If a rebuild is in progress, will wait for it to finish.
|
2017-08-14 16:17:24 +08:00
|
|
|
void cancelRebuild();
|
|
|
|
|
|
|
|
/// Similar to deferRebuild, but sets both Preamble and AST to nulls instead
|
|
|
|
/// of doing an actual parsing. Returned future is a deferred computation that
|
|
|
|
/// will wait for any ongoing rebuilds to finish and actually set the AST and
|
|
|
|
/// Preamble to nulls. It can be run on a different thread.
|
|
|
|
/// This function is useful to cancel ongoing rebuilds, if any, before
|
|
|
|
/// removing CppFile.
|
|
|
|
std::future<void> deferCancelRebuild();
|
2017-08-01 23:51:38 +08:00
|
|
|
|
|
|
|
/// Rebuild AST and Preamble synchronously on the calling thread.
|
|
|
|
/// 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(StringRef NewContents, IntrusiveRefCntPtr<vfs::FileSystem> VFS);
|
|
|
|
|
|
|
|
/// Schedule a rebuild and return a deferred computation that will finish the
|
|
|
|
/// rebuild, that can be called on a different thread.
|
|
|
|
/// After calling this method, resources, available via futures returned by
|
|
|
|
/// getPreamble() and getAST(), will be waiting for rebuild to finish. A
|
|
|
|
/// future fininshing rebuild, returned by this function, must be
|
|
|
|
/// computed(i.e. get() should be called on it) in order to make those
|
|
|
|
/// resources ready. If deferRebuild is called again before the rebuild is
|
|
|
|
/// finished (either because returned future had not been called or because it
|
|
|
|
/// had not returned yet), the previous rebuild request is cancelled and the
|
|
|
|
/// resource futures (returned by getPreamble() or getAST()) that were not
|
|
|
|
/// ready will be waiting for the last rebuild to finish instead.
|
|
|
|
/// The future to finish rebuild returns a list of diagnostics built during
|
|
|
|
/// reparse, or None, if another deferRebuild was called before this
|
|
|
|
/// rebuild was finished.
|
|
|
|
std::future<llvm::Optional<std::vector<DiagWithFixIts>>>
|
|
|
|
deferRebuild(StringRef NewContents, IntrusiveRefCntPtr<vfs::FileSystem> VFS);
|
|
|
|
|
|
|
|
/// Returns a future to get the most fresh PreambleData for a file. The
|
|
|
|
/// future will wait until the Preamble is rebuilt.
|
|
|
|
std::shared_future<std::shared_ptr<const PreambleData>> getPreamble() const;
|
|
|
|
/// Return some preamble for a file. It might be stale, but won't wait for
|
|
|
|
/// rebuild to finish.
|
|
|
|
std::shared_ptr<const PreambleData> getPossiblyStalePreamble() const;
|
|
|
|
|
|
|
|
/// Returns a future to get the most fresh AST for a file. Returned AST is
|
|
|
|
/// wrapped to prevent concurrent accesses.
|
2017-08-02 02:27:58 +08:00
|
|
|
/// We use std::shared_ptr here because MVSC fails to compile non-copyable
|
|
|
|
/// classes as template arguments of promise/future. It is guaranteed to
|
|
|
|
/// always be non-null.
|
|
|
|
std::shared_future<std::shared_ptr<ParsedASTWrapper>> getAST() const;
|
2017-08-01 23:51:38 +08:00
|
|
|
|
|
|
|
/// Get CompileCommand used to build this CppFile.
|
|
|
|
tooling::CompileCommand const &getCompileCommand() const;
|
2017-07-21 21:29:29 +08:00
|
|
|
|
2017-08-01 23:51:38 +08:00
|
|
|
private:
|
|
|
|
/// A helper guard that manages the state of CppFile during rebuild.
|
|
|
|
class RebuildGuard {
|
|
|
|
public:
|
|
|
|
RebuildGuard(CppFile &File, unsigned RequestRebuildCounter);
|
|
|
|
~RebuildGuard();
|
2017-07-21 21:29:29 +08:00
|
|
|
|
2017-08-01 23:51:38 +08:00
|
|
|
bool wasCancelledBeforeConstruction() const;
|
|
|
|
|
|
|
|
private:
|
|
|
|
CppFile &File;
|
|
|
|
unsigned RequestRebuildCounter;
|
|
|
|
bool WasCancelledBeforeConstruction;
|
|
|
|
};
|
2017-07-21 21:29:29 +08:00
|
|
|
|
2017-05-16 17:38:59 +08:00
|
|
|
Path FileName;
|
2017-07-21 21:29:29 +08:00
|
|
|
tooling::CompileCommand Command;
|
2017-06-29 00:12:10 +08:00
|
|
|
|
2017-08-01 23:51:38 +08:00
|
|
|
/// Mutex protects all fields, declared below it, FileName and Command are not
|
|
|
|
/// mutated.
|
|
|
|
mutable std::mutex Mutex;
|
|
|
|
/// A counter to cancel old rebuilds.
|
|
|
|
unsigned RebuildCounter;
|
|
|
|
/// Used to wait when rebuild is finished before starting another one.
|
|
|
|
bool RebuildInProgress;
|
|
|
|
/// Condition variable to indicate changes to RebuildInProgress.
|
|
|
|
std::condition_variable RebuildCond;
|
|
|
|
|
|
|
|
/// Promise and future for the latests AST. Fulfilled during rebuild.
|
2017-08-02 02:27:58 +08:00
|
|
|
/// We use std::shared_ptr here because MVSC fails to compile non-copyable
|
|
|
|
/// classes as template arguments of promise/future.
|
|
|
|
std::promise<std::shared_ptr<ParsedASTWrapper>> ASTPromise;
|
|
|
|
std::shared_future<std::shared_ptr<ParsedASTWrapper>> ASTFuture;
|
2017-08-01 23:51:38 +08:00
|
|
|
|
|
|
|
/// Promise and future for the latests Preamble. Fulfilled during rebuild.
|
|
|
|
std::promise<std::shared_ptr<const PreambleData>> PreamblePromise;
|
|
|
|
std::shared_future<std::shared_ptr<const PreambleData>> PreambleFuture;
|
|
|
|
/// Latest preamble that was built. May be stale, but always available without
|
|
|
|
/// waiting for rebuild to finish.
|
|
|
|
std::shared_ptr<const PreambleData> LatestAvailablePreamble;
|
|
|
|
/// Utility class, required by clang.
|
2017-07-21 21:29:29 +08:00
|
|
|
std::shared_ptr<PCHContainerOperations> PCHs;
|
2017-09-20 15:24:15 +08:00
|
|
|
/// Used for logging various messages.
|
|
|
|
clangd::Logger &Logger;
|
2017-05-16 17:38:59 +08:00
|
|
|
};
|
|
|
|
|
2017-08-01 23:51:38 +08:00
|
|
|
/// Get code completions at a specified \p Pos in \p FileName.
|
|
|
|
std::vector<CompletionItem>
|
|
|
|
codeComplete(PathRef FileName, tooling::CompileCommand Command,
|
|
|
|
PrecompiledPreamble const *Preamble, StringRef Contents,
|
|
|
|
Position Pos, IntrusiveRefCntPtr<vfs::FileSystem> VFS,
|
2017-09-12 21:57:14 +08:00
|
|
|
std::shared_ptr<PCHContainerOperations> PCHs,
|
2017-09-20 15:24:15 +08:00
|
|
|
bool SnippetCompletions, clangd::Logger &Logger);
|
2017-08-01 23:51:38 +08:00
|
|
|
|
2017-10-06 19:54:17 +08:00
|
|
|
/// Get signature help at a specified \p Pos in \p FileName.
|
|
|
|
SignatureHelp signatureHelp(PathRef FileName, tooling::CompileCommand Command,
|
|
|
|
PrecompiledPreamble const *Preamble,
|
|
|
|
StringRef Contents, Position Pos,
|
|
|
|
IntrusiveRefCntPtr<vfs::FileSystem> VFS,
|
|
|
|
std::shared_ptr<PCHContainerOperations> PCHs,
|
|
|
|
clangd::Logger &Logger);
|
|
|
|
|
2017-08-01 23:51:38 +08:00
|
|
|
/// Get definition of symbol at a specified \p Pos.
|
2017-09-20 15:24:15 +08:00
|
|
|
std::vector<Location> findDefinitions(ParsedAST &AST, Position Pos,
|
|
|
|
clangd::Logger &Logger);
|
2017-08-01 23:51:38 +08:00
|
|
|
|
|
|
|
/// For testing/debugging purposes. Note that this method deserializes all
|
|
|
|
/// unserialized Decls, so use with care.
|
|
|
|
void dumpAST(ParsedAST &AST, llvm::raw_ostream &OS);
|
|
|
|
|
2017-05-16 17:38:59 +08:00
|
|
|
} // namespace clangd
|
|
|
|
} // namespace clang
|
|
|
|
#endif
|