[Mlir-commits] [mlir] fb5a59f - [mlir][PDLL] Add initial support for a PDLL compilation database

River Riddle llvmlistbot at llvm.org
Tue Apr 26 18:34:15 PDT 2022


Author: River Riddle
Date: 2022-04-26T18:33:17-07:00
New Revision: fb5a59f6e1b9ec3192ecdc14b69ab83dafcf90f2

URL: https://github.com/llvm/llvm-project/commit/fb5a59f6e1b9ec3192ecdc14b69ab83dafcf90f2
DIFF: https://github.com/llvm/llvm-project/commit/fb5a59f6e1b9ec3192ecdc14b69ab83dafcf90f2.diff

LOG: [mlir][PDLL] Add initial support for a PDLL compilation database

The compilation database acts in a similar way to the compilation database
(compile_commands.json) used by clang-tidy, i.e. it provides additional
information about the compilation of project files to help the language
server. The main piece of information provided by the PDLL compilation
database in this commit is the set of include directories used when processing
the input .pdll file. This allows for the server to properly process .pdll files
that use includes anchored by the include directories set up in the build system.

The structure of the textual form of a compilation database is a yaml file
containing documents of the following form:

```
--- !FileInfo:
  filepath: <string> - Absolute file path of the file.
  includes: <string> - Semi-colon delimited list of include directories.
```

This commit also adds support to cmake for automatically generating
a `pdll_compile_commands.yml` file at the top-level of the build
directory.

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

Added: 
    mlir/lib/Tools/mlir-pdll-lsp-server/CompilationDatabase.cpp
    mlir/lib/Tools/mlir-pdll-lsp-server/CompilationDatabase.h
    mlir/test/mlir-pdll-lsp-server/compilation_database.test
    mlir/test/mlir-pdll-lsp-server/include/included.pdll
    mlir/test/mlir-pdll-lsp-server/include/included.td
    mlir/test/mlir-pdll-lsp-server/lit.local.cfg

Modified: 
    mlir/cmake/modules/AddMLIR.cmake
    mlir/lib/Tools/mlir-pdll-lsp-server/CMakeLists.txt
    mlir/lib/Tools/mlir-pdll-lsp-server/MlirPdllLspServerMain.cpp
    mlir/lib/Tools/mlir-pdll-lsp-server/PDLLServer.cpp
    mlir/lib/Tools/mlir-pdll-lsp-server/PDLLServer.h
    mlir/utils/vscode/package.json
    mlir/utils/vscode/src/configWatcher.ts
    mlir/utils/vscode/src/mlirContext.ts

Removed: 
    


################################################################################
diff  --git a/mlir/cmake/modules/AddMLIR.cmake b/mlir/cmake/modules/AddMLIR.cmake
index d425f5865331c..a372832e39d3d 100644
--- a/mlir/cmake/modules/AddMLIR.cmake
+++ b/mlir/cmake/modules/AddMLIR.cmake
@@ -7,6 +7,10 @@ function(mlir_tablegen ofn)
       PARENT_SCOPE)
 endfunction()
 
+# Clear out any pre-existing compile_commands file before processing. This
+# allows for generating a clean compile_commands on each configure.
+file(REMOVE ${CMAKE_BINARY_DIR}/pdll_compile_commands.yml)
+
 # Declare a PDLL library in the current directory.
 function(add_mlir_pdll_library target inputFile ofn)
   set(LLVM_TARGET_DEFINITIONS ${inputFile})
@@ -15,6 +19,28 @@ function(add_mlir_pdll_library target inputFile ofn)
   set(TABLEGEN_OUTPUT ${TABLEGEN_OUTPUT} ${CMAKE_CURRENT_BINARY_DIR}/${ofn}
       PARENT_SCOPE)
 
+  # Get the current set of include paths for this pdll file.
+  cmake_parse_arguments(ARG "" "" "DEPENDS;EXTRA_INCLUDES" ${ARGN})
+  get_directory_property(tblgen_includes INCLUDE_DIRECTORIES)
+  list(APPEND tblgen_includes ${ARG_EXTRA_INCLUDES})
+  # Filter out any empty include items.
+  list(REMOVE_ITEM tblgen_includes "")
+
+  # Build the absolute path for the current input file.
+  if (IS_ABSOLUTE ${LLVM_TARGET_DEFINITIONS})
+    set(LLVM_TARGET_DEFINITIONS_ABSOLUTE ${inputFile})
+  else()
+    set(LLVM_TARGET_DEFINITIONS_ABSOLUTE ${CMAKE_CURRENT_SOURCE_DIR}/${inputFile})
+  endif()
+
+  # Append the includes used for this file to the pdll_compilation_commands
+  # file.
+  file(APPEND ${CMAKE_BINARY_DIR}/pdll_compile_commands.yml
+      "--- !FileInfo:\n"
+      "  filepath: \"${LLVM_TARGET_DEFINITIONS_ABSOLUTE}\"\n"
+      "  includes: \"${CMAKE_CURRENT_SOURCE_DIR};${tblgen_includes}\"\n"
+  )
+  
   add_public_tablegen_target(${target})
 endfunction()
 

diff  --git a/mlir/lib/Tools/mlir-pdll-lsp-server/CMakeLists.txt b/mlir/lib/Tools/mlir-pdll-lsp-server/CMakeLists.txt
index f9ff5470eca0e..125b62325fedb 100644
--- a/mlir/lib/Tools/mlir-pdll-lsp-server/CMakeLists.txt
+++ b/mlir/lib/Tools/mlir-pdll-lsp-server/CMakeLists.txt
@@ -1,4 +1,5 @@
 llvm_add_library(MLIRPdllLspServerLib
+  CompilationDatabase.cpp
   LSPServer.cpp
   PDLLServer.cpp
   MlirPdllLspServerMain.cpp

diff  --git a/mlir/lib/Tools/mlir-pdll-lsp-server/CompilationDatabase.cpp b/mlir/lib/Tools/mlir-pdll-lsp-server/CompilationDatabase.cpp
new file mode 100644
index 0000000000000..ceb5e1a592ab7
--- /dev/null
+++ b/mlir/lib/Tools/mlir-pdll-lsp-server/CompilationDatabase.cpp
@@ -0,0 +1,81 @@
+//===- CompilationDatabase.cpp - PDLL Compilation Database ----------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "CompilationDatabase.h"
+#include "../lsp-server-support/Logging.h"
+#include "mlir/Support/FileUtilities.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/YAMLTraits.h"
+
+using namespace mlir;
+using namespace mlir::lsp;
+
+//===----------------------------------------------------------------------===//
+// CompilationDatabase
+//===----------------------------------------------------------------------===//
+
+LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(CompilationDatabase::FileInfo)
+
+namespace llvm {
+namespace yaml {
+template <>
+struct MappingTraits<CompilationDatabase::FileInfo> {
+  static void mapping(IO &io, CompilationDatabase::FileInfo &info) {
+    io.mapRequired("filepath", info.filename);
+
+    // Parse the includes from the yaml stream. These are in the form of a
+    // semi-colon delimited list.
+    std::string combinedIncludes;
+    io.mapRequired("includes", combinedIncludes);
+    for (StringRef include : llvm::split(combinedIncludes, ";")) {
+      if (!include.empty())
+        info.includeDirs.push_back(include.str());
+    }
+  }
+};
+} // end namespace yaml
+} // end namespace llvm
+
+CompilationDatabase::CompilationDatabase(ArrayRef<std::string> databases) {
+  for (StringRef filename : databases)
+    loadDatabase(filename);
+}
+
+const CompilationDatabase::FileInfo *
+CompilationDatabase::getFileInfo(StringRef filename) const {
+  auto it = files.find(filename);
+  return it == files.end() ? nullptr : &it->second;
+}
+
+void CompilationDatabase::loadDatabase(StringRef filename) {
+  if (filename.empty())
+    return;
+
+  // Set up the input file.
+  std::string errorMessage;
+  std::unique_ptr<llvm::MemoryBuffer> inputFile =
+      openInputFile(filename, &errorMessage);
+  if (!inputFile) {
+    Logger::error("Failed to open compilation database: {0}", errorMessage);
+    return;
+  }
+  llvm::yaml::Input yaml(inputFile->getBuffer());
+
+  // Parse the yaml description and add any new files to the database.
+  std::vector<FileInfo> parsedFiles;
+  yaml >> parsedFiles;
+  for (auto &file : parsedFiles) {
+    auto it = files.try_emplace(file.filename, std::move(file));
+
+    // If we encounter a duplicate file, log a warning and ignore it.
+    if (!it.second) {
+      Logger::info("Duplicate .pdll file in compilation database: {0}",
+                   file.filename);
+    }
+  }
+}

diff  --git a/mlir/lib/Tools/mlir-pdll-lsp-server/CompilationDatabase.h b/mlir/lib/Tools/mlir-pdll-lsp-server/CompilationDatabase.h
new file mode 100644
index 0000000000000..13a5f13c977f6
--- /dev/null
+++ b/mlir/lib/Tools/mlir-pdll-lsp-server/CompilationDatabase.h
@@ -0,0 +1,58 @@
+//===- CompilationDatabase.h - PDLL Compilation Database --------*- 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 LIB_MLIR_TOOLS_MLIRPDLLSPSERVER_COMPILATIONDATABASE_H_
+#define LIB_MLIR_TOOLS_MLIRPDLLSPSERVER_COMPILATIONDATABASE_H_
+
+#include "mlir/Support/LLVM.h"
+#include "llvm/ADT/StringMap.h"
+#include <memory>
+#include <string>
+
+namespace mlir {
+namespace lsp {
+/// This class contains a collection of compilation information for files
+/// provided to the language server, such as the available include directories.
+/// This database acts as an aggregate in-memory form of compilation databases
+/// used by the current language client. The textual form of a compilation
+/// database is a YAML file containing documents of the following form:
+///
+/// --- !FileInfo:
+///   filepath: <string> - Absolute file path of the file.
+///   includes: <string> - Semi-colon delimited list of include directories.
+///
+class CompilationDatabase {
+public:
+  /// Compilation information for a specific file within the database.
+  struct FileInfo {
+    /// The absolute path to the file.
+    std::string filename;
+    /// The include directories available for the file.
+    std::vector<std::string> includeDirs;
+  };
+
+  /// Construct a compilation database from the provided files containing YAML
+  /// descriptions of the database.
+  CompilationDatabase(ArrayRef<std::string> databases);
+
+  /// Get the compilation information for the provided file, or nullptr if the
+  /// database doesn't include information for `filename`.
+  const FileInfo *getFileInfo(StringRef filename) const;
+
+private:
+  /// Load the given database file into this database.
+  void loadDatabase(StringRef filename);
+
+  /// A map of filename to file information for each known file within the
+  /// databases.
+  llvm::StringMap<FileInfo> files;
+};
+} // namespace lsp
+} // namespace mlir
+
+#endif // LIB_MLIR_TOOLS_MLIRPDLLSPSERVER_COMPILATIONDATABASE_H_

diff  --git a/mlir/lib/Tools/mlir-pdll-lsp-server/MlirPdllLspServerMain.cpp b/mlir/lib/Tools/mlir-pdll-lsp-server/MlirPdllLspServerMain.cpp
index 95b145c4bc19d..8c483b9228aa6 100644
--- a/mlir/lib/Tools/mlir-pdll-lsp-server/MlirPdllLspServerMain.cpp
+++ b/mlir/lib/Tools/mlir-pdll-lsp-server/MlirPdllLspServerMain.cpp
@@ -54,6 +54,10 @@ LogicalResult mlir::MlirPdllLspServerMain(int argc, char **argv) {
   llvm::cl::list<std::string> extraIncludeDirs(
       "pdll-extra-dir", llvm::cl::desc("Extra directory of include files"),
       llvm::cl::value_desc("directory"), llvm::cl::Prefix);
+  llvm::cl::list<std::string> compilationDatabases(
+      "pdll-compilation-database",
+      llvm::cl::desc("Compilation YAML databases containing additional "
+                     "compilation information for .pdll files"));
 
   llvm::cl::ParseCommandLineOptions(argc, argv, "PDLL LSP Language Server");
 
@@ -71,7 +75,7 @@ LogicalResult mlir::MlirPdllLspServerMain(int argc, char **argv) {
   JSONTransport transport(stdin, llvm::outs(), inputStyle, prettyPrint);
 
   // Configure the servers and start the main language server.
-  PDLLServer::Options options(extraIncludeDirs);
+  PDLLServer::Options options(compilationDatabases, extraIncludeDirs);
   PDLLServer server(options);
   return runPdllLSPServer(server, transport);
 }

diff  --git a/mlir/lib/Tools/mlir-pdll-lsp-server/PDLLServer.cpp b/mlir/lib/Tools/mlir-pdll-lsp-server/PDLLServer.cpp
index f588439e9b79b..2ed24dd51a16e 100644
--- a/mlir/lib/Tools/mlir-pdll-lsp-server/PDLLServer.cpp
+++ b/mlir/lib/Tools/mlir-pdll-lsp-server/PDLLServer.cpp
@@ -10,6 +10,7 @@
 
 #include "../lsp-server-support/Logging.h"
 #include "../lsp-server-support/Protocol.h"
+#include "CompilationDatabase.h"
 #include "mlir/Tools/PDLL/AST/Context.h"
 #include "mlir/Tools/PDLL/AST/Nodes.h"
 #include "mlir/Tools/PDLL/AST/Types.h"
@@ -325,7 +326,7 @@ PDLDocument::PDLDocument(const lsp::URIForFile &uri, StringRef contents,
     return;
   }
 
-  // TODO: Properly provide include directories from the client.
+  // Build the set of include directories for this file.
   llvm::SmallString<32> uriDirectory(uri.file());
   llvm::sys::path::remove_filename(uriDirectory);
   includeDirs.push_back(uriDirectory.str().str());
@@ -1225,11 +1226,16 @@ PDLTextFileChunk &PDLTextFile::getChunkFor(lsp::Position &pos) {
 //===----------------------------------------------------------------------===//
 
 struct lsp::PDLLServer::Impl {
-  explicit Impl(const Options &options) : options(options) {}
+  explicit Impl(const Options &options)
+      : options(options), compilationDatabase(options.compilationDatabases) {}
 
   /// PDLL LSP options.
   const Options &options;
 
+  /// The compilation database containing additional information for files
+  /// passed to the server.
+  lsp::CompilationDatabase compilationDatabase;
+
   /// The files held by the server, mapped by their URI file name.
   llvm::StringMap<std::unique_ptr<PDLTextFile>> files;
 };
@@ -1245,8 +1251,12 @@ lsp::PDLLServer::~PDLLServer() = default;
 void lsp::PDLLServer::addOrUpdateDocument(
     const URIForFile &uri, StringRef contents, int64_t version,
     std::vector<Diagnostic> &diagnostics) {
+  std::vector<std::string> additionalIncludeDirs = impl->options.extraDirs;
+  if (auto *fileInfo = impl->compilationDatabase.getFileInfo(uri.file()))
+    llvm::append_range(additionalIncludeDirs, fileInfo->includeDirs);
+
   impl->files[uri.file()] = std::make_unique<PDLTextFile>(
-      uri, contents, version, impl->options.extraDirs, diagnostics);
+      uri, contents, version, additionalIncludeDirs, diagnostics);
 }
 
 Optional<int64_t> lsp::PDLLServer::removeDocument(const URIForFile &uri) {

diff  --git a/mlir/lib/Tools/mlir-pdll-lsp-server/PDLLServer.h b/mlir/lib/Tools/mlir-pdll-lsp-server/PDLLServer.h
index d01697bcad97b..76fd756ae564a 100644
--- a/mlir/lib/Tools/mlir-pdll-lsp-server/PDLLServer.h
+++ b/mlir/lib/Tools/mlir-pdll-lsp-server/PDLLServer.h
@@ -10,12 +10,14 @@
 #define LIB_MLIR_TOOLS_MLIRPDLLSPSERVER_SERVER_H_
 
 #include "mlir/Support/LLVM.h"
+#include "llvm/ADT/StringRef.h"
 #include <memory>
 #include <string>
 
 namespace mlir {
 namespace lsp {
 struct Diagnostic;
+class CompilationDatabase;
 struct CompletionList;
 struct DocumentSymbol;
 struct Hover;
@@ -30,7 +32,13 @@ class URIForFile;
 class PDLLServer {
 public:
   struct Options {
-    Options(const std::vector<std::string> &extraDirs) : extraDirs(extraDirs){};
+    Options(const std::vector<std::string> &compilationDatabases,
+            const std::vector<std::string> &extraDirs)
+        : compilationDatabases(compilationDatabases), extraDirs(extraDirs) {}
+
+    /// The filenames for databases containing compilation commands for PDLL
+    /// files passed to the server.
+    const std::vector<std::string> &compilationDatabases;
 
     /// Additional list of include directories to search.
     const std::vector<std::string> &extraDirs;

diff  --git a/mlir/test/mlir-pdll-lsp-server/compilation_database.test b/mlir/test/mlir-pdll-lsp-server/compilation_database.test
new file mode 100644
index 0000000000000..1ac999bba38c0
--- /dev/null
+++ b/mlir/test/mlir-pdll-lsp-server/compilation_database.test
@@ -0,0 +1,21 @@
+// RUN: echo -e '--- !FileInfo:\n  filepath: "/foo.pdll"\n  includes: "%S;%S/../../include"' > %t.yml
+// RUN: mlir-pdll-lsp-server -pdll-compilation-database=%t.yml -lit-test < %s | FileCheck %s
+{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"pdll","capabilities":{},"trace":"off"}}
+// -----
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{
+  "uri":"test:///foo.pdll",
+  "languageId":"pdll",
+  "version":1,
+  "text":"#include \"include/included.td\"\n#include \"include/included.pdll\""
+}}}
+// Check that we can properly process the includes without errors.
+// CHECK: "method": "textDocument/publishDiagnostics",
+// CHECK-NEXT: "params": {
+// CHECK-NEXT:     "diagnostics": [],
+// CHECK-NEXT:     "uri": "test:///foo.pdll",
+// CHECK-NEXT:     "version": 1
+// CHECK-NEXT:   }
+// -----
+{"jsonrpc":"2.0","id":7,"method":"shutdown"}
+// -----
+{"jsonrpc":"2.0","method":"exit"}

diff  --git a/mlir/test/mlir-pdll-lsp-server/include/included.pdll b/mlir/test/mlir-pdll-lsp-server/include/included.pdll
new file mode 100644
index 0000000000000..dee1df0d080ac
--- /dev/null
+++ b/mlir/test/mlir-pdll-lsp-server/include/included.pdll
@@ -0,0 +1,2 @@
+// This file is merely to test the processing of includes, it has
+// no other purpose or contents.

diff  --git a/mlir/test/mlir-pdll-lsp-server/include/included.td b/mlir/test/mlir-pdll-lsp-server/include/included.td
new file mode 100644
index 0000000000000..881abd0ba9593
--- /dev/null
+++ b/mlir/test/mlir-pdll-lsp-server/include/included.td
@@ -0,0 +1,4 @@
+include "mlir/IR/OpBase.td"
+
+// This file is merely to test the processing of includes, it has
+// no other purpose or contents.

diff  --git a/mlir/test/mlir-pdll-lsp-server/lit.local.cfg b/mlir/test/mlir-pdll-lsp-server/lit.local.cfg
new file mode 100644
index 0000000000000..25d08c7aba306
--- /dev/null
+++ b/mlir/test/mlir-pdll-lsp-server/lit.local.cfg
@@ -0,0 +1 @@
+config.excludes = ['include']

diff  --git a/mlir/utils/vscode/package.json b/mlir/utils/vscode/package.json
index 230124a6a6297..9b4de106991b6 100644
--- a/mlir/utils/vscode/package.json
+++ b/mlir/utils/vscode/package.json
@@ -124,6 +124,11 @@
           "type": "string",
           "description": "The file path of the mlir-pdll-lsp-server executable."
         },
+        "mlir.pdll_compilation_databases": {
+          "scope": "resource",
+          "type": "array",
+          "description": "A list of `pdll_compile_commands.yml` database files containing information about .pdll files processed by the server."
+        },
         "mlir.onSettingsChanged": {
           "type": "string",
           "default": "prompt",

diff  --git a/mlir/utils/vscode/src/configWatcher.ts b/mlir/utils/vscode/src/configWatcher.ts
index 82b202d9c3c97..68426873c18e6 100644
--- a/mlir/utils/vscode/src/configWatcher.ts
+++ b/mlir/utils/vscode/src/configWatcher.ts
@@ -41,41 +41,45 @@ async function promptRestart(settingName: string, promptMessage: string) {
  *  Activate watchers that track configuration changes for the given workspace
  *  folder, or null if the workspace is top-level.
  */
-export async function activate(mlirContext: MLIRContext,
-                               workspaceFolder: vscode.WorkspaceFolder,
-                               serverSetting: string, serverPath: string) {
+export async function activate(
+    mlirContext: MLIRContext, workspaceFolder: vscode.WorkspaceFolder,
+    serverSettings: string[], serverPaths: string[]) {
   // When a configuration change happens, check to see if we should restart the
   // server.
   mlirContext.subscriptions.push(vscode.workspace.onDidChangeConfiguration(event => {
-    const expandedSetting = `mlir.${serverSetting}`;
-    if (event.affectsConfiguration(expandedSetting, workspaceFolder)) {
-      promptRestart(
-          'onSettingsChanged',
-          `setting '${
-              expandedSetting}' has changed. Do you want to reload the server?`);
+    for (const serverSetting of serverSettings) {
+      const expandedSetting = `mlir.${serverSetting}`;
+      if (event.affectsConfiguration(expandedSetting, workspaceFolder)) {
+        promptRestart(
+            'onSettingsChanged',
+            `setting '${
+                expandedSetting}' has changed. Do you want to reload the server?`);
+      }
     }
   }));
 
-  // If the server path actually exists, track it in case it changes. Check that
-  // the path actually exists.
-  if (serverPath === '') {
-    return;
-  }
-
+  // Setup watchers for the provided server paths.
   const fileWatcherConfig = {
     disableGlobbing : true,
     followSymlinks : true,
     ignoreInitial : true,
     awaitWriteFinish : true,
   };
-  const fileWatcher = chokidar.watch(serverPath, fileWatcherConfig);
-  fileWatcher.on('all', (event, _filename, _details) => {
-    if (event != 'unlink') {
-      promptRestart(
-          'onSettingsChanged',
-          'MLIR language server binary has changed. Do you want to reload the server?');
+  for (const serverPath of serverPaths) {
+    if (serverPath === '') {
+      return;
     }
-  });
-  mlirContext.subscriptions.push(
-      new vscode.Disposable(() => { fileWatcher.close(); }));
+
+    // If the server path actually exists, track it in case it changes.
+    const fileWatcher = chokidar.watch(serverPath, fileWatcherConfig);
+    fileWatcher.on('all', (event, _filename, _details) => {
+      if (event != 'unlink') {
+        promptRestart(
+            'onSettingsChanged',
+            'MLIR language server file has changed. Do you want to reload the server?');
+      }
+    });
+    mlirContext.subscriptions.push(
+        new vscode.Disposable(() => { fileWatcher.close(); }));
+  }
 }

diff  --git a/mlir/utils/vscode/src/mlirContext.ts b/mlir/utils/vscode/src/mlirContext.ts
index 3827fcc86d331..76a990c87b6c2 100644
--- a/mlir/utils/vscode/src/mlirContext.ts
+++ b/mlir/utils/vscode/src/mlirContext.ts
@@ -85,6 +85,43 @@ export class MLIRContext implements vscode.Disposable {
         }));
   }
 
+  /**
+   *  Prepare the server options for a PDLL server, e.g. populating any
+   *  accessible compilation databases.
+   */
+  async preparePDLLServerOptions(workspaceFolder: vscode.WorkspaceFolder,
+                                 configsToWatch: string[],
+                                 pathsToWatch: string[],
+                                 additionalServerArgs: string[]) {
+    // Process the compilation databases attached for the workspace folder.
+    let databases =
+        config.get<string[]>('pdll_compilation_databases', workspaceFolder);
+
+    // If no databases were explicitly specified, default to a database in the
+    // 'build' directory within the current workspace.
+    if (databases.length === 0) {
+      if (workspaceFolder) {
+        databases.push(workspaceFolder.uri.fsPath +
+                       '/build/pdll_compile_commands.yml');
+      }
+
+      // Otherwise, try to resolve each of the paths.
+    } else {
+      for await (let database of databases) {
+        database = await this.resolvePath(database, '', workspaceFolder);
+      }
+    }
+
+    configsToWatch.push('pdll_compilation_databases');
+    pathsToWatch.push(...databases);
+
+    // Setup the compilation databases as additional arguments to pass to the
+    // server.
+    databases.filter(database => database !== '');
+    additionalServerArgs.push(...databases.map(
+        (database) => `--pdll-compilation-database=${database}`));
+  }
+
   /**
    *  Activate the language client for the given language in the given workspace
    *  folder.
@@ -93,12 +130,27 @@ export class MLIRContext implements vscode.Disposable {
                                 serverSettingName: string, languageName: string,
                                 outputChannel: vscode.OutputChannel):
       Promise<vscodelc.LanguageClient> {
+    let configsToWatch: string[] = [];
+    let filepathsToWatch: string[] = [];
+    let additionalServerArgs: string[] = [];
+
+    // Initialize additional configurations for this server.
+    if (languageName === 'pdll') {
+      await this.preparePDLLServerOptions(workspaceFolder, configsToWatch,
+                                          filepathsToWatch,
+                                          additionalServerArgs);
+    }
+
+    // Try to activate the language client.
     const [server, serverPath] = await this.startLanguageClient(
-        workspaceFolder, outputChannel, serverSettingName, languageName);
+        workspaceFolder, outputChannel, serverSettingName, languageName,
+        additionalServerArgs);
+    configsToWatch.push(serverSettingName);
+    filepathsToWatch.push(serverPath);
 
     // Watch for configuration changes on this folder.
-    await configWatcher.activate(this, workspaceFolder, serverSettingName,
-                                 serverPath);
+    await configWatcher.activate(this, workspaceFolder, configsToWatch,
+                                 filepathsToWatch);
     return server;
   }
 
@@ -109,7 +161,8 @@ export class MLIRContext implements vscode.Disposable {
    */
   async startLanguageClient(workspaceFolder: vscode.WorkspaceFolder,
                             outputChannel: vscode.OutputChannel,
-                            serverSettingName: string, languageName: string):
+                            serverSettingName: string, languageName: string,
+                            additionalServerArgs: string[]):
       Promise<[ vscodelc.LanguageClient, string ]> {
     const clientTitle = languageName.toUpperCase() + ' Language Client';
 
@@ -146,12 +199,12 @@ export class MLIRContext implements vscode.Disposable {
       run : {
         command : serverPath,
         transport : vscodelc.TransportKind.stdio,
-        args : []
+        args : additionalServerArgs
       },
       debug : {
         command : serverPath,
         transport : vscodelc.TransportKind.stdio,
-        args : []
+        args : additionalServerArgs
       }
     };
 
@@ -217,45 +270,56 @@ export class MLIRContext implements vscode.Disposable {
   }
 
   /**
-   * Try to resolve the path for the given server setting, with an optional
-   * workspace folder.
+   * Try to resolve the given path, or the default path, with an optional
+   * workspace folder. If a path could not be resolved, just returns the
+   * input filePath.
    */
-  async resolveServerPath(serverSettingName: string,
-                          workspaceFolder: vscode.WorkspaceFolder):
-      Promise<string> {
-    const configServerPath =
-        config.get<string>(serverSettingName, workspaceFolder);
-    let serverPath = configServerPath;
+  async resolvePath(filePath: string, defaultPath: string,
+                    workspaceFolder: vscode.WorkspaceFolder): Promise<string> {
+    const configPath = filePath;
 
     // If the path is already fully resolved, there is nothing to do.
-    if (path.isAbsolute(serverPath)) {
-      return serverPath;
+    if (path.isAbsolute(filePath)) {
+      return filePath;
     }
 
     // If a path hasn't been set, try to use the default path.
-    if (serverPath === '') {
-      serverPath = MLIRContext.getDefaultServerFilename(serverSettingName);
-      if (serverPath === '') {
-        return serverPath;
+    if (filePath === '') {
+      if (defaultPath === '') {
+        return filePath;
       }
+      filePath = defaultPath;
+
       // Fallthrough to try resolving the default path.
     }
 
     // Try to resolve the path relative to the workspace.
-    let filePattern: vscode.GlobPattern = '**/' + serverPath;
+    let filePattern: vscode.GlobPattern = '**/' + filePath;
     if (workspaceFolder) {
       filePattern = new vscode.RelativePattern(workspaceFolder, filePattern);
     }
     let foundUris = await vscode.workspace.findFiles(filePattern, null, 1);
     if (foundUris.length === 0) {
-      // If we couldn't resolve it, just return the current configuration path
-      // anyways. The file might not exist yet.
-      return configServerPath;
+      // If we couldn't resolve it, just return the original path anyways. The
+      // file might not exist yet.
+      return configPath;
     }
     // Otherwise, return the resolved path.
     return foundUris[0].fsPath;
   }
 
+  /**
+   * Try to resolve the path for the given server setting, with an optional
+   * workspace folder.
+   */
+  async resolveServerPath(serverSettingName: string,
+                          workspaceFolder: vscode.WorkspaceFolder):
+      Promise<string> {
+    const serverPath = config.get<string>(serverSettingName, workspaceFolder);
+    const defaultPath = MLIRContext.getDefaultServerFilename(serverSettingName);
+    return this.resolvePath(serverPath, defaultPath, workspaceFolder);
+  }
+
   dispose() {
     this.subscriptions.forEach((d) => { d.dispose(); });
     this.subscriptions = [];


        


More information about the Mlir-commits mailing list