Mercurial > hg > CbC > CbC_llvm
diff clang-tools-extra/clangd/ClangdServer.h @ 150:1d019706d866
LLVM10
author | anatofuz |
---|---|
date | Thu, 13 Feb 2020 15:10:13 +0900 |
parents | |
children | 0572611fdcc8 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/clang-tools-extra/clangd/ClangdServer.h Thu Feb 13 15:10:13 2020 +0900 @@ -0,0 +1,362 @@ +//===--- ClangdServer.h - Main clangd server code ----------------*- C++-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDSERVER_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDSERVER_H + +#include "../clang-tidy/ClangTidyOptions.h" +#include "Cancellation.h" +#include "CodeComplete.h" +#include "FSProvider.h" +#include "FormattedString.h" +#include "Function.h" +#include "GlobalCompilationDatabase.h" +#include "Hover.h" +#include "Protocol.h" +#include "SemanticHighlighting.h" +#include "TUScheduler.h" +#include "XRefs.h" +#include "index/Background.h" +#include "index/FileIndex.h" +#include "index/Index.h" +#include "refactor/Rename.h" +#include "refactor/Tweak.h" +#include "clang/Tooling/CompilationDatabase.h" +#include "clang/Tooling/Core/Replacement.h" +#include "llvm/ADT/FunctionExtras.h" +#include "llvm/ADT/IntrusiveRefCntPtr.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringRef.h" +#include <functional> +#include <future> +#include <string> +#include <type_traits> +#include <utility> + +namespace clang { +namespace clangd { + +/// When set, used by ClangdServer to get clang-tidy options for each particular +/// file. Must be thread-safe. We use this instead of ClangTidyOptionsProvider +/// to allow reading tidy configs from the VFS used for parsing. +using ClangTidyOptionsBuilder = std::function<tidy::ClangTidyOptions( + llvm::vfs::FileSystem &, llvm::StringRef /*File*/)>; + +/// Manages a collection of source files and derived data (ASTs, indexes), +/// and provides language-aware features such as code completion. +/// +/// The primary client is ClangdLSPServer which exposes these features via +/// the Language Server protocol. ClangdServer may also be embedded directly, +/// though its API is not stable over time. +/// +/// ClangdServer should be used from a single thread. Many potentially-slow +/// operations have asynchronous APIs and deliver their results on another +/// thread. +/// Such operations support cancellation: if the caller sets up a cancelable +/// context, many operations will notice cancellation and fail early. +/// (ClangdLSPServer uses this to implement $/cancelRequest). +class ClangdServer { +public: + /// Interface with hooks for users of ClangdServer to be notified of events. + class Callbacks { + public: + virtual ~Callbacks() = default; + + /// Called by ClangdServer when \p Diagnostics for \p File are ready. + /// May be called concurrently for separate files, not for a single file. + virtual void onDiagnosticsReady(PathRef File, + std::vector<Diag> Diagnostics) {} + /// Called whenever the file status is updated. + /// May be called concurrently for separate files, not for a single file. + virtual void onFileUpdated(PathRef File, const TUStatus &Status) {} + + /// Called by ClangdServer when some \p Highlightings for \p File are ready. + /// May be called concurrently for separate files, not for a single file. + virtual void + onHighlightingsReady(PathRef File, + std::vector<HighlightingToken> Highlightings) {} + + /// Called when background indexing tasks are enqueued/started/completed. + /// Not called concurrently. + virtual void + onBackgroundIndexProgress(const BackgroundQueue::Stats &Stats) {} + }; + + struct Options { + /// To process requests asynchronously, ClangdServer spawns worker threads. + /// If this is zero, no threads are spawned. All work is done on the calling + /// thread, and callbacks are invoked before "async" functions return. + unsigned AsyncThreadsCount = getDefaultAsyncThreadsCount(); + + /// AST caching policy. The default is to keep up to 3 ASTs in memory. + ASTRetentionPolicy RetentionPolicy; + + /// Cached preambles are potentially large. If false, store them on disk. + bool StorePreamblesInMemory = true; + + /// If true, ClangdServer builds a dynamic in-memory index for symbols in + /// opened files and uses the index to augment code completion results. + bool BuildDynamicSymbolIndex = false; + /// Use a heavier and faster in-memory index implementation. + bool HeavyweightDynamicSymbolIndex = true; + /// If true, ClangdServer automatically indexes files in the current project + /// on background threads. The index is stored in the project root. + bool BackgroundIndex = false; + + /// If set, use this index to augment code completion results. + SymbolIndex *StaticIndex = 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 + /// (Checks, CheckOptions) are about which clang-tidy checks will be + /// enabled. + ClangTidyOptionsBuilder GetClangTidyOptions; + + /// Clangd's workspace root. Relevant for "workspace" operations not bound + /// to a particular file. + /// FIXME: If not set, should use the current working directory. + llvm::Optional<std::string> WorkspaceRoot; + + /// The resource directory is used to find internal headers, overriding + /// defaults and -resource-dir compiler flag). + /// If None, ClangdServer calls CompilerInvocation::GetResourcePath() to + /// obtain the standard resource directory. + llvm::Optional<std::string> ResourceDir = llvm::None; + + /// Time to wait after a new file version before computing diagnostics. + DebouncePolicy UpdateDebounce = + DebouncePolicy::fixed(std::chrono::milliseconds(500)); + + bool SuggestMissingIncludes = false; + + /// Clangd will execute compiler drivers matching one of these globs to + /// fetch system include path. + std::vector<std::string> QueryDriverGlobs; + + /// Enable semantic highlighting features. + bool SemanticHighlighting = false; + + /// Enable cross-file rename feature. + bool CrossFileRename = false; + + /// Returns true if the tweak should be enabled. + std::function<bool(const Tweak &)> TweakFilter = [](const Tweak &T) { + return !T.hidden(); // only enable non-hidden tweaks. + }; + + explicit operator TUScheduler::Options() const; + }; + // Sensible default options for use in tests. + // Features like indexing must be enabled if desired. + static Options optsForTest(); + + /// Creates a new ClangdServer instance. + /// + /// ClangdServer uses \p CDB to obtain compilation arguments for parsing. Note + /// that ClangdServer only obtains compilation arguments once for each newly + /// added file (i.e., when processing a first call to addDocument) and reuses + /// those arguments for subsequent reparses. However, ClangdServer will check + /// if compilation arguments changed on calls to forceReparse(). + ClangdServer(const GlobalCompilationDatabase &CDB, + const FileSystemProvider &FSProvider, const Options &Opts, + Callbacks *Callbacks = nullptr); + + /// Add a \p File to the list of tracked C++ files or update the contents if + /// \p File is already tracked. Also schedules parsing of the AST for it on a + /// separate thread. When the parsing is complete, DiagConsumer passed in + /// constructor will receive onDiagnosticsReady callback. + void addDocument(PathRef File, StringRef Contents, + WantDiagnostics WD = WantDiagnostics::Auto, + bool ForceRebuild = false); + + /// Get the contents of \p File, which should have been added. + llvm::StringRef getDocument(PathRef File) const; + + /// Remove \p File from list of tracked files, schedule a request to free + /// resources associated with it. Pending diagnostics for closed files may not + /// be delivered, even if requested with WantDiags::Auto or WantDiags::Yes. + void removeDocument(PathRef File); + + /// Run code completion for \p File at \p Pos. + /// Request is processed asynchronously. + /// + /// This method should only be called for currently tracked files. However, it + /// is safe to call removeDocument for \p File after this method returns, even + /// while returned future is not yet ready. + /// A version of `codeComplete` that runs \p Callback on the processing thread + /// when codeComplete results become available. + void codeComplete(PathRef File, Position Pos, + const clangd::CodeCompleteOptions &Opts, + Callback<CodeCompleteResult> CB); + + /// Provide signature help for \p File at \p Pos. This method should only be + /// called for tracked files. + void signatureHelp(PathRef File, Position Pos, Callback<SignatureHelp> CB); + + /// Find declaration/definition locations of symbol at a specified position. + void locateSymbolAt(PathRef File, Position Pos, + Callback<std::vector<LocatedSymbol>> CB); + + /// Switch to a corresponding source file when given a header file, and vice + /// versa. + void switchSourceHeader(PathRef Path, + Callback<llvm::Optional<clangd::Path>> CB); + + /// Get document highlights for a given position. + void findDocumentHighlights(PathRef File, Position Pos, + Callback<std::vector<DocumentHighlight>> CB); + + /// Get code hover for a given position. + void findHover(PathRef File, Position Pos, + Callback<llvm::Optional<HoverInfo>> CB); + + /// Get information about type hierarchy for a given position. + void typeHierarchy(PathRef File, Position Pos, int Resolve, + TypeHierarchyDirection Direction, + Callback<llvm::Optional<TypeHierarchyItem>> CB); + + /// Resolve type hierarchy item in the given direction. + void resolveTypeHierarchy(TypeHierarchyItem Item, int Resolve, + TypeHierarchyDirection Direction, + Callback<llvm::Optional<TypeHierarchyItem>> CB); + + /// Retrieve the top symbols from the workspace matching a query. + void workspaceSymbols(StringRef Query, int Limit, + Callback<std::vector<SymbolInformation>> CB); + + /// Retrieve the symbols within the specified file. + void documentSymbols(StringRef File, + Callback<std::vector<DocumentSymbol>> CB); + + /// Retrieve locations for symbol references. + void findReferences(PathRef File, Position Pos, uint32_t Limit, + Callback<ReferencesResult> CB); + + /// Run formatting for \p Rng inside \p File with content \p Code. + llvm::Expected<tooling::Replacements> formatRange(StringRef Code, + PathRef File, Range Rng); + + /// Run formatting for the whole \p File with content \p Code. + llvm::Expected<tooling::Replacements> formatFile(StringRef Code, + PathRef File); + + /// Run formatting after \p TriggerText was typed at \p Pos in \p File with + /// content \p Code. + llvm::Expected<std::vector<TextEdit>> formatOnType(StringRef Code, + PathRef File, Position Pos, + StringRef TriggerText); + + /// Test the validity of a rename operation. + void prepareRename(PathRef File, Position Pos, + Callback<llvm::Optional<Range>> CB); + + /// Rename all occurrences of the symbol at the \p Pos in \p File to + /// \p NewName. + /// If WantFormat is false, the final TextEdit will be not formatted, + /// embedders could use this method to get all occurrences of the symbol (e.g. + /// highlighting them in prepare stage). + void rename(PathRef File, Position Pos, llvm::StringRef NewName, + bool WantFormat, Callback<FileEdits> CB); + + struct TweakRef { + std::string ID; /// ID to pass for applyTweak. + std::string Title; /// A single-line message to show in the UI. + Tweak::Intent Intent; + }; + /// Enumerate the code tweaks available to the user at a specified point. + void enumerateTweaks(PathRef File, Range Sel, + Callback<std::vector<TweakRef>> CB); + + /// Apply the code tweak with a specified \p ID. + void applyTweak(PathRef File, Range Sel, StringRef ID, + Callback<Tweak::Effect> CB); + + /// Only for testing purposes. + /// Waits until all requests to worker thread are finished and dumps AST for + /// \p File. \p File must be in the list of added documents. + void dumpAST(PathRef File, llvm::unique_function<void(std::string)> Callback); + /// Called when an event occurs for a watched file in the workspace. + void onFileEvent(const DidChangeWatchedFilesParams &Params); + + /// Get symbol info for given position. + /// Clangd extension - not part of official LSP. + void symbolInfo(PathRef File, Position Pos, + Callback<std::vector<SymbolDetails>> CB); + + /// Get semantic ranges around a specified position in a file. + void semanticRanges(PathRef File, Position Pos, + Callback<std::vector<Range>> CB); + + /// Get all document links in a file. + void documentLinks(PathRef File, Callback<std::vector<DocumentLink>> CB); + + /// Returns estimated memory usage for each of the currently open files. + /// The order of results is unspecified. + /// Overall memory usage of clangd may be significantly more than reported + /// here, as this metric does not account (at least) for: + /// - memory occupied by static and dynamic index, + /// - memory required for in-flight requests, + /// FIXME: those metrics might be useful too, we should add them. + std::vector<std::pair<Path, std::size_t>> getUsedBytesPerFile() const; + + // Blocks the main thread until the server is idle. Only for use in tests. + // Returns false if the timeout expires. + LLVM_NODISCARD bool + blockUntilIdleForTest(llvm::Optional<double> TimeoutSeconds = 10); + +private: + /// FIXME: This stats several files to find a .clang-format file. I/O can be + /// slow. Think of a way to cache this. + llvm::Expected<tooling::Replacements> + formatCode(llvm::StringRef Code, PathRef File, + ArrayRef<tooling::Range> Ranges); + + const FileSystemProvider &FSProvider; + + Path ResourceDir; + // The index used to look up symbols. This could be: + // - null (all index functionality is optional) + // - the dynamic index owned by ClangdServer (DynamicIdx) + // - the static index passed to the constructor + // - a merged view of a static and dynamic index (MergedIndex) + const SymbolIndex *Index = nullptr; + // If present, an index of symbols in open files. Read via *Index. + std::unique_ptr<FileIndex> DynamicIdx; + // If present, the new "auto-index" maintained in background threads. + std::unique_ptr<BackgroundIndex> BackgroundIdx; + // Storage for merged views of the various indexes. + std::vector<std::unique_ptr<SymbolIndex>> MergedIdx; + + // When set, provides clang-tidy options for a specific file. + ClangTidyOptionsBuilder GetClangTidyOptions; + + // If this is true, suggest include insertion fixes for diagnostic errors that + // can be caused by missing includes (e.g. member access in incomplete type). + bool SuggestMissingIncludes = false; + + bool CrossFileRename = false; + + std::function<bool(const Tweak &)> TweakFilter; + + // GUARDED_BY(CachedCompletionFuzzyFindRequestMutex) + llvm::StringMap<llvm::Optional<FuzzyFindRequest>> + CachedCompletionFuzzyFindRequestByFile; + mutable std::mutex CachedCompletionFuzzyFindRequestMutex; + + llvm::Optional<std::string> WorkspaceRoot; + // WorkScheduler has to be the last member, because its destructor has to be + // called before all other members to stop the worker thread that references + // ClangdServer. + TUScheduler WorkScheduler; +}; + +} // namespace clangd +} // namespace clang + +#endif