[clangd] Command line arg to specify compile_commands.json path

Summary: Adds compileCommands command line argument to specify an absolute path directly to the requested compile_commands.json for flags.

Reviewed By: ilya-biryukov

Differential Revision: https://reviews.llvm.org/D37150

llvm-svn: 314678
diff --git a/clang-tools-extra/clangd/tool/ClangdMain.cpp b/clang-tools-extra/clangd/tool/ClangdMain.cpp
index 9632e44..0634c94 100644
--- a/clang-tools-extra/clangd/tool/ClangdMain.cpp
+++ b/clang-tools-extra/clangd/tool/ClangdMain.cpp
@@ -11,8 +11,8 @@
 #include "JSONRPCDispatcher.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
 #include "llvm/Support/Program.h"
-
 #include <iostream>
 #include <memory>
 #include <string>
@@ -21,6 +21,12 @@
 using namespace clang;
 using namespace clang::clangd;
 
+static llvm::cl::opt<Path> CompileCommandsDir(
+    "compile-commands-dir",
+    llvm::cl::desc("Specify a path to look for compile_commands.json. If path "
+                   "is invalid, clangd will look in the current directory and "
+                   "parent paths of each source file."));
+
 static llvm::cl::opt<unsigned>
     WorkerThreadsCount("j",
                        llvm::cl::desc("Number of async workers used by clangd"),
@@ -56,18 +62,37 @@
   if (RunSynchronously)
     WorkerThreadsCount = 0;
 
+  /// Validate command line arguments.
   llvm::raw_ostream &Outs = llvm::outs();
   llvm::raw_ostream &Logs = llvm::errs();
   JSONOutput Out(Outs, Logs);
 
-  // Change stdin to binary to not lose \r\n on windows.
-  llvm::sys::ChangeStdinToBinary();
+  // If --compile-commands-dir arg was invoked, check value and override default
+  // path.
+  namespace path = llvm::sys::path;
+  llvm::Optional<Path> CompileCommandsDirPath;
+
+  if (CompileCommandsDir.empty()) {
+    CompileCommandsDirPath = llvm::None;
+  } else if (!llvm::sys::path::is_absolute(CompileCommandsDir) ||
+             !llvm::sys::fs::exists(CompileCommandsDir)) {
+    llvm::errs() << "Path specified by --compile-commands-dir either does not "
+                    "exist or is not an absolute "
+                    "path. The argument will be ignored.\n";
+    CompileCommandsDirPath = llvm::None;
+  } else {
+    CompileCommandsDirPath = CompileCommandsDir;
+  }
 
   llvm::Optional<StringRef> ResourceDirRef = None;
   if (!ResourceDir.empty())
     ResourceDirRef = ResourceDir;
 
+  /// Change stdin to binary to not lose \r\n on windows.
+  llvm::sys::ChangeStdinToBinary();
+
+  /// Initialize and run ClangdLSPServer.
   ClangdLSPServer LSPServer(Out, WorkerThreadsCount, EnableSnippets,
-                            ResourceDirRef);
+                            ResourceDirRef, CompileCommandsDirPath);
   LSPServer.run(std::cin);
 }