summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/clangd/ClangdServer.h
blob: 72b6bd57540e7787571bced2c6dd537264af0cda (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
//===--- ClangdServer.h - Main clangd server code ----------------*- 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_CLANGDSERVER_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_CLANGDSERVER_H

#include "ClangdUnitStore.h"
#include "DraftStore.h"
#include "GlobalCompilationDatabase.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Tooling/CompilationDatabase.h"
#include "clang/Tooling/Core/Replacement.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringRef.h"

#include "ClangdUnit.h"
#include "Protocol.h"

#include <condition_variable>
#include <mutex>
#include <string>
#include <thread>
#include <utility>

namespace clang {
class PCHContainerOperations;

namespace clangd {

class DiagnosticsConsumer {
public:
  virtual ~DiagnosticsConsumer() = default;

  /// Called by ClangdServer when \p Diagnostics for \p File are ready.
  virtual void onDiagnosticsReady(PathRef File,
                                  std::vector<DiagWithFixIts> Diagnostics) = 0;
};

enum class WorkerRequestKind { ParseAndPublishDiagnostics, RemoveDocData };

/// A request to the worker thread
class WorkerRequest {
public:
  WorkerRequest() = default;
  WorkerRequest(WorkerRequestKind Kind, Path File, DocVersion Version);

  WorkerRequestKind Kind;
  Path File;
  DocVersion Version;
};

class ClangdServer;

/// Handles running WorkerRequests of ClangdServer on a separate threads.
/// Currently runs only one worker thread.
class ClangdScheduler {
public:
  ClangdScheduler(ClangdServer &Server, bool RunSynchronously);
  ~ClangdScheduler();

  /// Enqueue WorkerRequest to be run on a worker thread
  void enqueue(ClangdServer &Server, WorkerRequest Request);

private:
  bool RunSynchronously;
  std::mutex Mutex;
  /// We run some tasks on a separate thread(parsing, ClangdUnit cleanup).
  /// This thread looks into RequestQueue to find requests to handle and
  /// terminates when Done is set to true.
  std::thread Worker;
  /// Setting Done to true will make the worker thread terminate.
  bool Done = false;
  /// A LIFO queue of requests. Note that requests are discarded if the
  /// `version` field is not equal to the one stored inside DraftStore.
  /// FIXME(krasimir): code completion should always have priority over parsing
  /// for diagnostics.
  std::deque<WorkerRequest> RequestQueue;
  /// Condition variable to wake up the worker thread.
  std::condition_variable RequestCV;
};

/// Provides API to manage ASTs for a collection of C++ files and request
/// various language features(currently, only codeCompletion and async
/// diagnostics for tracked files).
class ClangdServer {
public:
  ClangdServer(std::unique_ptr<GlobalCompilationDatabase> CDB,
               std::unique_ptr<DiagnosticsConsumer> DiagConsumer,
               bool RunSynchronously);

  /// 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);

  /// Remove \p File from list of tracked files, schedule a request to free
  /// resources associated with it.
  void removeDocument(PathRef File);

  /// Run code completion for \p File at \p Pos.
  std::vector<CompletionItem> codeComplete(PathRef File, Position Pos);

  /// Gets current document contents for \p File. \p File must point to a
  /// currently tracked file.
  /// FIXME(ibiryukov): This function is here to allow implementation of
  /// formatCode from ProtocolHandlers.cpp. We should move formatCode to this
  /// class and remove this function from public interface.
  std::string getDocument(PathRef File);

private:
  friend class ClangdScheduler;

  /// This function is called on a worker thread.
  void handleRequest(WorkerRequest Request);

  std::unique_ptr<GlobalCompilationDatabase> CDB;
  std::unique_ptr<DiagnosticsConsumer> DiagConsumer;
  DraftStore DraftMgr;
  ClangdUnitStore Units;
  std::shared_ptr<PCHContainerOperations> PCHs;
  // 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
  ClangdScheduler WorkScheduler;
};

} // namespace clangd
} // namespace clang

#endif
OpenPOWER on IntegriCloud