16#include "../Utils/LSPUtils.h"
20#include "mlir/Tools/lsp-server-support/Logging.h"
21#include "mlir/Tools/lsp-server-support/Protocol.h"
22#include "slang/ast/Compilation.h"
23#include "slang/diagnostics/DiagnosticClient.h"
24#include "slang/diagnostics/Diagnostics.h"
25#include "slang/driver/Driver.h"
26#include "slang/syntax/SyntaxTree.h"
27#include "slang/text/SourceLocation.h"
28#include "slang/text/SourceManager.h"
29#include "llvm/ADT/SmallString.h"
30#include "llvm/ADT/StringMap.h"
31#include "llvm/Support/MemoryBuffer.h"
32#include "llvm/Support/Path.h"
33#include "llvm/Support/SourceMgr.h"
44static mlir::lsp::DiagnosticSeverity
47 case slang::DiagnosticSeverity::Fatal:
48 case slang::DiagnosticSeverity::Error:
49 return mlir::lsp::DiagnosticSeverity::Error;
50 case slang::DiagnosticSeverity::Warning:
51 return mlir::lsp::DiagnosticSeverity::Warning;
52 case slang::DiagnosticSeverity::Ignored:
53 case slang::DiagnosticSeverity::Note:
54 return mlir::lsp::DiagnosticSeverity::Information;
56 llvm_unreachable(
"all slang diagnostic severities should be handled");
57 return mlir::lsp::DiagnosticSeverity::Error;
62struct VerilogServerContext {
74class LSPDiagnosticClient;
75struct VerilogDocument {
76 VerilogDocument(VerilogServerContext &globalContext,
77 const mlir::lsp::URIForFile &uri, StringRef contents,
78 std::vector<mlir::lsp::Diagnostic> &diagnostics);
79 VerilogDocument(
const VerilogDocument &) =
delete;
80 VerilogDocument &operator=(
const VerilogDocument &) =
delete;
82 const mlir::lsp::URIForFile &getURI()
const {
return uri; }
84 llvm::SourceMgr &getSourceMgr() {
return sourceMgr; }
89 const slang::SourceManager &getSlangSourceManager()
const {
90 return driver.sourceManager;
94 mlir::lsp::Location getLspLocation(slang::SourceLocation loc)
const;
102 FailureOr<std::unique_ptr<slang::ast::Compilation>> compilation;
105 slang::driver::Driver driver;
108 llvm::SourceMgr sourceMgr;
111 mlir::lsp::URIForFile uri;
123class LSPDiagnosticClient :
public slang::DiagnosticClient {
124 const VerilogDocument &document;
125 std::vector<mlir::lsp::Diagnostic> &diags;
128 LSPDiagnosticClient(
const VerilogDocument &document,
129 std::vector<mlir::lsp::Diagnostic> &diags)
130 : document(document), diags(diags) {}
132 void report(
const slang::ReportedDiagnostic &slangDiag)
override;
136void LSPDiagnosticClient::report(
const slang::ReportedDiagnostic &slangDiag) {
137 auto loc = document.getLspLocation(slangDiag.location);
139 if (loc.uri != document.getURI())
141 auto &mlirDiag = diags.emplace_back();
142 mlirDiag.severity =
getSeverity(slangDiag.severity);
143 mlirDiag.range = loc.range;
144 mlirDiag.source =
"slang";
145 mlirDiag.message = slangDiag.formattedMessage;
152VerilogDocument::VerilogDocument(
153 VerilogServerContext &context,
const mlir::lsp::URIForFile &uri,
154 StringRef contents, std::vector<mlir::lsp::Diagnostic> &diagnostics)
156 unsigned int bufferId;
157 if (
auto memBufferOwn =
158 llvm::MemoryBuffer::getMemBufferCopy(contents, uri.file())) {
160 bufferId = sourceMgr.AddNewSourceBuffer(std::move(memBufferOwn), SMLoc());
163 Twine(
"Failed to create memory buffer for file ") + uri.file());
168 llvm::SmallString<32> uriDirectory(uri.file());
169 llvm::sys::path::remove_filename(uriDirectory);
171 std::vector<std::string> libDirs;
172 libDirs.push_back(uriDirectory.str().str());
173 libDirs.insert(libDirs.end(), context.options.libDirs.begin(),
174 context.options.libDirs.end());
177 const llvm::MemoryBuffer *memBuffer = sourceMgr.getMemoryBuffer(bufferId);
179 for (
const auto &libDir : libDirs) {
180 driver.sourceLoader.addSearchDirectories(libDir);
185 driver.sourceManager.assignText(uri.file(), memBuffer->getBuffer());
186 driver.sourceLoader.addBuffer(slangBuffer);
187 bufferIDMap[slangBuffer.id.getId()] = bufferId;
189 auto diagClient = std::make_shared<LSPDiagnosticClient>(*
this, diagnostics);
190 driver.diagEngine.addClient(diagClient);
192 driver.options.compilationFlags.emplace(
193 slang::ast::CompilationFlags::LintMode,
false);
194 driver.options.compilationFlags.emplace(
195 slang::ast::CompilationFlags::DisableInstanceCaching,
false);
197 if (!driver.processOptions()) {
201 driver.diagEngine.setIgnoreAllWarnings(
false);
203 if (!driver.parseAllSources()) {
209 compilation = driver.createCompilation();
210 for (
auto &diag : (*compilation)->getAllDiagnostics())
211 driver.diagEngine.issue(diag);
215VerilogDocument::getLspLocation(slang::SourceLocation loc)
const {
216 if (loc && loc.buffer() != slang::SourceLocation::NoLocation.buffer()) {
217 const auto &slangSourceManager = getSlangSourceManager();
218 auto line = slangSourceManager.getLineNumber(loc) - 1;
219 auto column = slangSourceManager.getColumnNumber(loc) - 1;
220 auto it = bufferIDMap.find(loc.buffer().getId());
222 if (it != bufferIDMap.end() && it->second == sourceMgr.getMainFileID())
223 return mlir::lsp::Location(uri, mlir::lsp::Range(Position(line, column)));
226 auto fileName = slangSourceManager.getFileName(loc);
227 auto loc = mlir::lsp::URIForFile::fromFile(fileName);
228 if (
auto e = loc.takeError())
229 return mlir::lsp::Location();
230 return mlir::lsp::Location(loc.get(),
231 mlir::lsp::Range(Position(line, column)));
234 return mlir::lsp::Location();
244class VerilogTextFile {
246 VerilogTextFile(VerilogServerContext &globalContext,
247 const mlir::lsp::URIForFile &uri, StringRef fileContents,
249 std::vector<mlir::lsp::Diagnostic> &diagnostics);
252 int64_t getVersion()
const {
return version; }
257 update(
const mlir::lsp::URIForFile &uri, int64_t newVersion,
258 ArrayRef<mlir::lsp::TextDocumentContentChangeEvent> changes,
259 std::vector<mlir::lsp::Diagnostic> &diagnostics);
263 void initialize(
const mlir::lsp::URIForFile &uri, int64_t newVersion,
264 std::vector<mlir::lsp::Diagnostic> &diagnostics);
266 VerilogServerContext &context;
269 std::string contents;
276 std::unique_ptr<VerilogDocument> document;
280VerilogTextFile::VerilogTextFile(
281 VerilogServerContext &context,
const mlir::lsp::URIForFile &uri,
282 StringRef fileContents, int64_t version,
283 std::vector<mlir::lsp::Diagnostic> &diagnostics)
284 : context(context), contents(fileContents.str()) {
285 initialize(uri, version, diagnostics);
288LogicalResult VerilogTextFile::update(
289 const mlir::lsp::URIForFile &uri, int64_t newVersion,
290 ArrayRef<mlir::lsp::TextDocumentContentChangeEvent> changes,
291 std::vector<mlir::lsp::Diagnostic> &diagnostics) {
292 if (failed(mlir::lsp::TextDocumentContentChangeEvent::applyTo(changes,
300 initialize(uri, newVersion, diagnostics);
304void VerilogTextFile::initialize(
305 const mlir::lsp::URIForFile &uri, int64_t newVersion,
306 std::vector<mlir::lsp::Diagnostic> &diagnostics) {
307 version = newVersion;
309 std::make_unique<VerilogDocument>(context, uri, contents, diagnostics);
320 llvm::StringMap<std::unique_ptr<VerilogTextFile>>
files;
330 : impl(std::make_unique<
Impl>(options)) {}
334 const URIForFile &uri, StringRef contents, int64_t version,
335 std::vector<mlir::lsp::Diagnostic> &diagnostics) {
336 impl->files[uri.file()] = std::make_unique<VerilogTextFile>(
337 impl->context, uri, contents, version, diagnostics);
342 ArrayRef<mlir::lsp::TextDocumentContentChangeEvent> changes,
343 int64_t version, std::vector<mlir::lsp::Diagnostic> &diagnostics) {
345 auto it = impl->files.find(uri.file());
346 if (it == impl->files.end())
351 if (failed(it->second->update(uri, version, changes, diagnostics)))
352 impl->files.erase(it);
355std::optional<int64_t>
357 auto it = impl->files.find(uri.file());
358 if (it == impl->files.end())
361 int64_t version = it->second->getVersion();
362 impl->files.erase(it);
static mlir::lsp::DiagnosticSeverity getSeverity(slang::DiagnosticSeverity severity)
std::optional< int64_t > removeDocument(const URIForFile &uri)
Remove the document with the given uri.
void updateDocument(const URIForFile &uri, llvm::ArrayRef< TextDocumentContentChangeEvent > changes, int64_t version, std::vector< Diagnostic > &diagnostics)
Update the document, with the provided version, at the given URI.
VerilogServer(const circt::lsp::VerilogServerOptions &options)
void addDocument(const URIForFile &uri, llvm::StringRef contents, int64_t version, std::vector< Diagnostic > &diagnostics)
Add the document, with the provided version, at the given URI.
void error(Twine message)
mlir::lsp::URIForFile URIForFile
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
llvm::StringMap< std::unique_ptr< VerilogTextFile > > files
The files held by the server, mapped by their URI file name.
VerilogServerContext context
Impl(const VerilogServerOptions &options)