LCOV - code coverage report
Current view: top level - clang/tools/extra/clangd - ClangdServer.h (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 0 6 0.0 %
Date: 2017-09-14 15:23:50 Functions: 0 5 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //===--- ClangdServer.h - Main clangd server code ----------------*- C++-*-===//
       2             : //
       3             : //                     The LLVM Compiler Infrastructure
       4             : //
       5             : // This file is distributed under the University of Illinois Open Source
       6             : // License. See LICENSE.TXT for details.
       7             : //
       8             : //===----------------------------------------------------------------------===//
       9             : 
      10             : #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDSERVER_H
      11             : #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDSERVER_H
      12             : 
      13             : #include "ClangdUnitStore.h"
      14             : #include "DraftStore.h"
      15             : #include "GlobalCompilationDatabase.h"
      16             : #include "clang/Frontend/ASTUnit.h"
      17             : #include "clang/Tooling/CompilationDatabase.h"
      18             : #include "clang/Tooling/Core/Replacement.h"
      19             : #include "llvm/ADT/IntrusiveRefCntPtr.h"
      20             : #include "llvm/ADT/Optional.h"
      21             : #include "llvm/ADT/StringRef.h"
      22             : 
      23             : #include "ClangdUnit.h"
      24             : #include "Protocol.h"
      25             : 
      26             : #include <condition_variable>
      27             : #include <functional>
      28             : #include <mutex>
      29             : #include <string>
      30             : #include <thread>
      31             : #include <type_traits>
      32             : #include <utility>
      33             : 
      34             : namespace clang {
      35             : class PCHContainerOperations;
      36             : 
      37             : namespace clangd {
      38             : 
      39             : /// Turn a [line, column] pair into an offset in Code.
      40             : size_t positionToOffset(StringRef Code, Position P);
      41             : 
      42             : /// Turn an offset in Code into a [line, column] pair.
      43             : Position offsetToPosition(StringRef Code, size_t Offset);
      44             : 
      45             : /// A tag supplied by the FileSytemProvider.
      46             : typedef std::string VFSTag;
      47             : 
      48             : /// A value of an arbitrary type and VFSTag that was supplied by the
      49             : /// FileSystemProvider when this value was computed.
      50           0 : template <class T> class Tagged {
      51             : public:
      52             :   template <class U>
      53           0 :   Tagged(U &&Value, VFSTag Tag)
      54           0 :       : Value(std::forward<U>(Value)), Tag(std::move(Tag)) {}
      55             : 
      56             :   template <class U>
      57             :   Tagged(const Tagged<U> &Other) : Value(Other.Value), Tag(Other.Tag) {}
      58             : 
      59             :   template <class U>
      60             :   Tagged(Tagged<U> &&Other)
      61             :       : Value(std::move(Other.Value)), Tag(std::move(Other.Tag)) {}
      62             : 
      63             :   T Value;
      64             :   VFSTag Tag;
      65             : };
      66             : 
      67             : template <class T>
      68           0 : Tagged<typename std::decay<T>::type> make_tagged(T &&Value, VFSTag Tag) {
      69           0 :   return Tagged<typename std::decay<T>::type>(std::forward<T>(Value), Tag);
      70             : }
      71             : 
      72             : class DiagnosticsConsumer {
      73             : public:
      74             :   virtual ~DiagnosticsConsumer() = default;
      75             : 
      76             :   /// Called by ClangdServer when \p Diagnostics for \p File are ready.
      77             :   virtual void
      78             :   onDiagnosticsReady(PathRef File,
      79             :                      Tagged<std::vector<DiagWithFixIts>> Diagnostics) = 0;
      80             : };
      81             : 
      82             : class FileSystemProvider {
      83             : public:
      84             :   virtual ~FileSystemProvider() = default;
      85             :   /// Called by ClangdServer to obtain a vfs::FileSystem to be used for parsing.
      86             :   /// Name of the file that will be parsed is passed in \p File.
      87             :   ///
      88             :   /// \return A filesystem that will be used for all file accesses in clangd.
      89             :   /// A Tag returned by this method will be propagated to all results of clangd
      90             :   /// that will use this filesystem.
      91             :   virtual Tagged<IntrusiveRefCntPtr<vfs::FileSystem>>
      92             :   getTaggedFileSystem(PathRef File) = 0;
      93             : };
      94             : 
      95             : class RealFileSystemProvider : public FileSystemProvider {
      96             : public:
      97             :   /// \return getRealFileSystem() tagged with default tag, i.e. VFSTag()
      98             :   Tagged<IntrusiveRefCntPtr<vfs::FileSystem>>
      99             :   getTaggedFileSystem(PathRef File) override;
     100             : };
     101             : 
     102             : class ClangdServer;
     103             : 
     104             : /// Returns a number of a default async threads to use for ClangdScheduler.
     105             : /// Returned value is always >= 1 (i.e. will not cause requests to be processed
     106             : /// synchronously).
     107             : unsigned getDefaultAsyncThreadsCount();
     108             : 
     109             : /// Handles running WorkerRequests of ClangdServer on a number of worker
     110             : /// threads.
     111             : class ClangdScheduler {
     112             : public:
     113             :   /// If \p AsyncThreadsCount is 0, requests added using addToFront and addToEnd
     114             :   /// will be processed synchronously on the calling thread.
     115             :   // Otherwise, \p AsyncThreadsCount threads will be created to schedule the
     116             :   // requests.
     117             :   ClangdScheduler(unsigned AsyncThreadsCount);
     118             :   ~ClangdScheduler();
     119             : 
     120             :   /// Add a new request to run function \p F with args \p As to the start of the
     121             :   /// queue. The request will be run on a separate thread.
     122             :   template <class Func, class... Args>
     123             :   void addToFront(Func &&F, Args &&... As) {
     124             :     if (RunSynchronously) {
     125             :       std::forward<Func>(F)(std::forward<Args>(As)...);
     126             :       return;
     127             :     }
     128             : 
     129             :     {
     130             :       std::lock_guard<std::mutex> Lock(Mutex);
     131             :       RequestQueue.push_front(std::async(std::launch::deferred,
     132             :                                          std::forward<Func>(F),
     133             :                                          std::forward<Args>(As)...));
     134             :     }
     135             :     RequestCV.notify_one();
     136             :   }
     137             : 
     138             :   /// Add a new request to run function \p F with args \p As to the end of the
     139             :   /// queue. The request will be run on a separate thread.
     140             :   template <class Func, class... Args> void addToEnd(Func &&F, Args &&... As) {
     141             :     if (RunSynchronously) {
     142             :       std::forward<Func>(F)(std::forward<Args>(As)...);
     143             :       return;
     144             :     }
     145             : 
     146             :     {
     147             :       std::lock_guard<std::mutex> Lock(Mutex);
     148             :       RequestQueue.push_back(std::async(std::launch::deferred,
     149             :                                         std::forward<Func>(F),
     150             :                                         std::forward<Args>(As)...));
     151             :     }
     152             :     RequestCV.notify_one();
     153             :   }
     154             : 
     155             : private:
     156             :   bool RunSynchronously;
     157             :   std::mutex Mutex;
     158             :   /// We run some tasks on separate threads(parsing, CppFile cleanup).
     159             :   /// These threads looks into RequestQueue to find requests to handle and
     160             :   /// terminate when Done is set to true.
     161             :   std::vector<std::thread> Workers;
     162             :   /// Setting Done to true will make the worker threads terminate.
     163             :   bool Done = false;
     164             :   /// A queue of requests. Elements of this vector are async computations (i.e.
     165             :   /// results of calling std::async(std::launch::deferred, ...)).
     166             :   std::deque<std::future<void>> RequestQueue;
     167             :   /// Condition variable to wake up worker threads.
     168             :   std::condition_variable RequestCV;
     169             : };
     170             : 
     171             : /// Provides API to manage ASTs for a collection of C++ files and request
     172             : /// various language features.
     173             : /// Currently supports async diagnostics, code completion, formatting and goto
     174             : /// definition.
     175           0 : class ClangdServer {
     176             : public:
     177             :   /// Creates a new ClangdServer instance.
     178             :   /// To process parsing requests asynchronously, ClangdServer will spawn \p
     179             :   /// AsyncThreadsCount worker threads. However, if \p AsyncThreadsCount is 0,
     180             :   /// all requests will be processed on the calling thread.
     181             :   ///
     182             :   /// When \p SnippetCompletions is true, completion items will be presented
     183             :   /// with embedded snippets. Otherwise, plaintext items will be presented.
     184             :   ///
     185             :   /// ClangdServer uses \p FSProvider to get an instance of vfs::FileSystem for
     186             :   /// each parsing request. Results of code completion and diagnostics also
     187             :   /// include a tag, that \p FSProvider returns along with the vfs::FileSystem.
     188             :   ///
     189             :   /// The value of \p ResourceDir will be used to search for internal headers
     190             :   /// (overriding defaults and -resource-dir compiler flag). If \p ResourceDir
     191             :   /// is None, ClangdServer will call CompilerInvocation::GetResourcePath() to
     192             :   /// obtain the standard resource directory.
     193             :   ///
     194             :   /// ClangdServer uses \p CDB to obtain compilation arguments for parsing. Note
     195             :   /// that ClangdServer only obtains compilation arguments once for each newly
     196             :   /// added file (i.e., when processing a first call to addDocument) and reuses
     197             :   /// those arguments for subsequent reparses. However, ClangdServer will check
     198             :   /// if compilation arguments changed on calls to forceReparse().
     199             :   ///
     200             :   /// After each parsing request finishes, ClangdServer reports diagnostics to
     201             :   /// \p DiagConsumer. Note that a callback to \p DiagConsumer happens on a
     202             :   /// worker thread. Therefore, instances of \p DiagConsumer must properly
     203             :   /// synchronize access to shared state.
     204             :   ClangdServer(GlobalCompilationDatabase &CDB,
     205             :                DiagnosticsConsumer &DiagConsumer,
     206             :                FileSystemProvider &FSProvider, unsigned AsyncThreadsCount,
     207             :                bool SnippetCompletions,
     208             :                llvm::Optional<StringRef> ResourceDir = llvm::None);
     209             : 
     210             :   /// Add a \p File to the list of tracked C++ files or update the contents if
     211             :   /// \p File is already tracked. Also schedules parsing of the AST for it on a
     212             :   /// separate thread. When the parsing is complete, DiagConsumer passed in
     213             :   /// constructor will receive onDiagnosticsReady callback.
     214             :   /// \return A future that will become ready when the rebuild (including
     215             :   /// diagnostics) is finished.
     216             :   std::future<void> addDocument(PathRef File, StringRef Contents);
     217             :   /// Remove \p File from list of tracked files, schedule a request to free
     218             :   /// resources associated with it.
     219             :   /// \return A future that will become ready when the file is removed and all
     220             :   /// associated resources are freed.
     221             :   std::future<void> removeDocument(PathRef File);
     222             :   /// Force \p File to be reparsed using the latest contents.
     223             :   /// Will also check if CompileCommand, provided by GlobalCompilationDatabase
     224             :   /// for \p File has changed. If it has, will remove currently stored Preamble
     225             :   /// and AST and rebuild them from scratch.
     226             :   std::future<void> forceReparse(PathRef File);
     227             : 
     228             :   /// Run code completion for \p File at \p Pos. If \p OverridenContents is not
     229             :   /// None, they will used only for code completion, i.e. no diagnostics update
     230             :   /// will be scheduled and a draft for \p File will not be updated.
     231             :   /// If \p OverridenContents is None, contents of the current draft for \p File
     232             :   /// will be used.
     233             :   /// If \p UsedFS is non-null, it will be overwritten by vfs::FileSystem used
     234             :   /// for completion.
     235             :   /// This method should only be called for currently tracked
     236             :   /// files.
     237             :   Tagged<std::vector<CompletionItem>>
     238             :   codeComplete(PathRef File, Position Pos,
     239             :                llvm::Optional<StringRef> OverridenContents = llvm::None,
     240             :                IntrusiveRefCntPtr<vfs::FileSystem> *UsedFS = nullptr);
     241             :   /// Get definition of symbol at a specified \p Line and \p Column in \p File.
     242             :   Tagged<std::vector<Location>> findDefinitions(PathRef File, Position Pos);
     243             : 
     244             :   /// Run formatting for \p Rng inside \p File.
     245             :   std::vector<tooling::Replacement> formatRange(PathRef File, Range Rng);
     246             :   /// Run formatting for the whole \p File.
     247             :   std::vector<tooling::Replacement> formatFile(PathRef File);
     248             :   /// Run formatting after a character was typed at \p Pos in \p File.
     249             :   std::vector<tooling::Replacement> formatOnType(PathRef File, Position Pos);
     250             : 
     251             :   /// Gets current document contents for \p File. \p File must point to a
     252             :   /// currently tracked file.
     253             :   /// FIXME(ibiryukov): This function is here to allow offset-to-Position
     254             :   /// conversions in outside code, maybe there's a way to get rid of it.
     255             :   std::string getDocument(PathRef File);
     256             : 
     257             :   /// Only for testing purposes.
     258             :   /// Waits until all requests to worker thread are finished and dumps AST for
     259             :   /// \p File. \p File must be in the list of added documents.
     260             :   std::string dumpAST(PathRef File);
     261             : 
     262             : private:
     263             :   std::future<void>
     264             :   scheduleReparseAndDiags(PathRef File, VersionedDraft Contents,
     265             :                           std::shared_ptr<CppFile> Resources,
     266             :                           Tagged<IntrusiveRefCntPtr<vfs::FileSystem>> TaggedFS);
     267             : 
     268             :   std::future<void> scheduleCancelRebuild(std::shared_ptr<CppFile> Resources);
     269             : 
     270             :   GlobalCompilationDatabase &CDB;
     271             :   DiagnosticsConsumer &DiagConsumer;
     272             :   FileSystemProvider &FSProvider;
     273             :   DraftStore DraftMgr;
     274             :   CppFileCollection Units;
     275             :   std::string ResourceDir;
     276             :   std::shared_ptr<PCHContainerOperations> PCHs;
     277             :   // WorkScheduler has to be the last member, because its destructor has to be
     278             :   // called before all other members to stop the worker thread that references
     279             :   // ClangdServer
     280             :   ClangdScheduler WorkScheduler;
     281             :   bool SnippetCompletions;
     282             : };
     283             : 
     284             : } // namespace clangd
     285             : } // namespace clang
     286             : 
     287             : #endif

Generated by: LCOV version 1.13