blob: 2808d0555c2b0ba1e27b85a043128a0cb48891d2 [file] [log] [blame]
Krasimir Georgiev95ef1712017-04-12 17:13:08 +00001//===--- ClangdMain.cpp - clangd server loop ------------------------------===//
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +00002//
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
Ilya Biryukov38d79772017-05-16 09:38:59 +000010#include "ClangdLSPServer.h"
Ilya Biryukovafb55542017-05-16 14:40:30 +000011#include "JSONRPCDispatcher.h"
Ilya Biryukove6dbb582017-10-10 09:08:47 +000012#include "Path.h"
Sam McCall8567cb32017-11-02 09:21:51 +000013#include "Trace.h"
Benjamin Kramerf0af3e62017-03-01 16:16:29 +000014#include "llvm/Support/CommandLine.h"
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000015#include "llvm/Support/FileSystem.h"
Ilya Biryukov0c1ca6b2017-10-02 15:13:20 +000016#include "llvm/Support/Path.h"
Benjamin Kramer6a3d74e2017-02-07 12:40:59 +000017#include "llvm/Support/Program.h"
Ilya Biryukove6dbb582017-10-10 09:08:47 +000018#include "llvm/Support/raw_ostream.h"
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000019#include <iostream>
Ilya Biryukov38d79772017-05-16 09:38:59 +000020#include <memory>
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000021#include <string>
Ilya Biryukovdb8b2d72017-08-14 08:45:47 +000022#include <thread>
Ilya Biryukov38d79772017-05-16 09:38:59 +000023
24using namespace clang;
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000025using namespace clang::clangd;
26
Ilya Biryukov0c1ca6b2017-10-02 15:13:20 +000027static llvm::cl::opt<Path> CompileCommandsDir(
28 "compile-commands-dir",
29 llvm::cl::desc("Specify a path to look for compile_commands.json. If path "
30 "is invalid, clangd will look in the current directory and "
31 "parent paths of each source file."));
32
Ilya Biryukovdb8b2d72017-08-14 08:45:47 +000033static llvm::cl::opt<unsigned>
34 WorkerThreadsCount("j",
35 llvm::cl::desc("Number of async workers used by clangd"),
36 llvm::cl::init(getDefaultAsyncThreadsCount()));
37
Ilya Biryukovb33c1572017-09-12 13:57:14 +000038static llvm::cl::opt<bool> EnableSnippets(
39 "enable-snippets",
40 llvm::cl::desc(
41 "Present snippet completions instead of plaintext completions"),
42 llvm::cl::init(false));
43
Ilya Biryukovdb8b2d72017-08-14 08:45:47 +000044static llvm::cl::opt<bool> RunSynchronously(
45 "run-synchronously",
46 llvm::cl::desc("Parse on main thread. If set, -j is ignored"),
47 llvm::cl::init(false), llvm::cl::Hidden);
Benjamin Kramerf0af3e62017-03-01 16:16:29 +000048
Ilya Biryukove6dbb582017-10-10 09:08:47 +000049static llvm::cl::opt<Path>
Krasimir Georgiev0dcb48e2017-07-19 15:43:35 +000050 ResourceDir("resource-dir",
Ilya Biryukov4ca7d852017-08-02 08:53:48 +000051 llvm::cl::desc("Directory for system clang headers"),
Krasimir Georgiev0dcb48e2017-07-19 15:43:35 +000052 llvm::cl::init(""), llvm::cl::Hidden);
53
Ilya Biryukove6dbb582017-10-10 09:08:47 +000054static llvm::cl::opt<Path> InputMirrorFile(
55 "input-mirror-file",
56 llvm::cl::desc(
57 "Mirror all LSP input to the specified file. Useful for debugging."),
58 llvm::cl::init(""), llvm::cl::Hidden);
59
Sam McCall8567cb32017-11-02 09:21:51 +000060static llvm::cl::opt<Path> TraceFile(
61 "trace",
62 llvm::cl::desc(
63 "Trace internal events and timestamps in chrome://tracing JSON format"),
64 llvm::cl::init(""), llvm::cl::Hidden);
65
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000066int main(int argc, char *argv[]) {
Benjamin Kramerf0af3e62017-03-01 16:16:29 +000067 llvm::cl::ParseCommandLineOptions(argc, argv, "clangd");
Ilya Biryukovafb55542017-05-16 14:40:30 +000068
Ilya Biryukovdb8b2d72017-08-14 08:45:47 +000069 if (!RunSynchronously && WorkerThreadsCount == 0) {
70 llvm::errs() << "A number of worker threads cannot be 0. Did you mean to "
71 "specify -run-synchronously?";
72 return 1;
73 }
74
75 // Ignore -j option if -run-synchonously is used.
76 // FIXME: a warning should be shown here.
77 if (RunSynchronously)
78 WorkerThreadsCount = 0;
79
Benjamin Kramer74a18952017-10-26 10:07:04 +000080 // Validate command line arguments.
Ilya Biryukove6dbb582017-10-10 09:08:47 +000081 llvm::Optional<llvm::raw_fd_ostream> InputMirrorStream;
82 if (!InputMirrorFile.empty()) {
83 std::error_code EC;
84 InputMirrorStream.emplace(InputMirrorFile, /*ref*/ EC, llvm::sys::fs::F_RW);
85 if (EC) {
86 InputMirrorStream.reset();
87 llvm::errs() << "Error while opening an input mirror file: "
88 << EC.message();
89 }
90 }
Sam McCall8567cb32017-11-02 09:21:51 +000091 llvm::Optional<llvm::raw_fd_ostream> TraceStream;
92 std::unique_ptr<trace::Session> TraceSession;
93 if (!TraceFile.empty()) {
94 std::error_code EC;
95 TraceStream.emplace(TraceFile, /*ref*/ EC, llvm::sys::fs::F_RW);
96 if (EC) {
97 TraceFile.reset();
98 llvm::errs() << "Error while opening trace file: " << EC.message();
99 } else {
100 TraceSession = trace::Session::create(*TraceStream);
101 }
102 }
Ilya Biryukove6dbb582017-10-10 09:08:47 +0000103
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000104 llvm::raw_ostream &Outs = llvm::outs();
105 llvm::raw_ostream &Logs = llvm::errs();
Ilya Biryukove6dbb582017-10-10 09:08:47 +0000106 JSONOutput Out(Outs, Logs,
107 InputMirrorStream ? InputMirrorStream.getPointer() : nullptr);
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000108
Ilya Biryukov0c1ca6b2017-10-02 15:13:20 +0000109 // If --compile-commands-dir arg was invoked, check value and override default
110 // path.
Ilya Biryukov0c1ca6b2017-10-02 15:13:20 +0000111 llvm::Optional<Path> CompileCommandsDirPath;
112
113 if (CompileCommandsDir.empty()) {
114 CompileCommandsDirPath = llvm::None;
115 } else if (!llvm::sys::path::is_absolute(CompileCommandsDir) ||
116 !llvm::sys::fs::exists(CompileCommandsDir)) {
117 llvm::errs() << "Path specified by --compile-commands-dir either does not "
118 "exist or is not an absolute "
119 "path. The argument will be ignored.\n";
120 CompileCommandsDirPath = llvm::None;
121 } else {
122 CompileCommandsDirPath = CompileCommandsDir;
123 }
Benjamin Kramer6a3d74e2017-02-07 12:40:59 +0000124
Krasimir Georgiev0dcb48e2017-07-19 15:43:35 +0000125 llvm::Optional<StringRef> ResourceDirRef = None;
126 if (!ResourceDir.empty())
127 ResourceDirRef = ResourceDir;
Ilya Biryukovdb8b2d72017-08-14 08:45:47 +0000128
Benjamin Kramer74a18952017-10-26 10:07:04 +0000129 // Change stdin to binary to not lose \r\n on windows.
Ilya Biryukov0c1ca6b2017-10-02 15:13:20 +0000130 llvm::sys::ChangeStdinToBinary();
131
Benjamin Kramer74a18952017-10-26 10:07:04 +0000132 // Initialize and run ClangdLSPServer.
Ilya Biryukovb33c1572017-09-12 13:57:14 +0000133 ClangdLSPServer LSPServer(Out, WorkerThreadsCount, EnableSnippets,
Ilya Biryukov0c1ca6b2017-10-02 15:13:20 +0000134 ResourceDirRef, CompileCommandsDirPath);
Ilya Biryukov0d9b8a32017-10-25 08:45:41 +0000135 constexpr int NoShutdownRequestErrorCode = 1;
Sam McCall8567cb32017-11-02 09:21:51 +0000136 llvm::set_thread_name("clangd.main");
Ilya Biryukov0d9b8a32017-10-25 08:45:41 +0000137 return LSPServer.run(std::cin) ? 0 : NoShutdownRequestErrorCode;
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +0000138}