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 driver.options.libDirs = libDirs;
182 driver.sourceManager.assignText(uri.file(), memBuffer->getBuffer());
183 driver.buffers.push_back(slangBuffer);
184 bufferIDMap[slangBuffer.id.getId()] = bufferId;
186 auto diagClient = std::make_shared<LSPDiagnosticClient>(*
this, diagnostics);
187 driver.diagEngine.addClient(diagClient);
189 if (!driver.parseAllSources()) {
195 compilation = driver.createCompilation();
196 for (
auto &diag : (*compilation)->getAllDiagnostics())
197 driver.diagEngine.issue(diag);
201VerilogDocument::getLspLocation(slang::SourceLocation loc)
const {
202 if (loc && loc.buffer() != slang::SourceLocation::NoLocation.buffer()) {
203 const auto &slangSourceManager = getSlangSourceManager();
204 auto line = slangSourceManager.getLineNumber(loc) - 1;
205 auto column = slangSourceManager.getColumnNumber(loc) - 1;
206 auto it = bufferIDMap.find(loc.buffer().getId());
208 if (it != bufferIDMap.end() && it->second == sourceMgr.getMainFileID())
209 return mlir::lsp::Location(uri, mlir::lsp::Range(Position(line, column)));
212 auto fileName = slangSourceManager.getFileName(loc);
213 auto loc = mlir::lsp::URIForFile::fromFile(
214 slangSourceManager.makeAbsolutePath(fileName));
215 if (
auto e = loc.takeError())
216 return mlir::lsp::Location();
217 return mlir::lsp::Location(loc.get(),
218 mlir::lsp::Range(Position(line, column)));
221 return mlir::lsp::Location();
231class VerilogTextFile {
233 VerilogTextFile(VerilogServerContext &globalContext,
234 const mlir::lsp::URIForFile &uri, StringRef fileContents,
236 std::vector<mlir::lsp::Diagnostic> &diagnostics);
239 int64_t getVersion()
const {
return version; }
244 update(
const mlir::lsp::URIForFile &uri, int64_t newVersion,
245 ArrayRef<mlir::lsp::TextDocumentContentChangeEvent> changes,
246 std::vector<mlir::lsp::Diagnostic> &diagnostics);
250 void initialize(
const mlir::lsp::URIForFile &uri, int64_t newVersion,
251 std::vector<mlir::lsp::Diagnostic> &diagnostics);
253 VerilogServerContext &context;
256 std::string contents;
263 std::unique_ptr<VerilogDocument> document;
267VerilogTextFile::VerilogTextFile(
268 VerilogServerContext &context,
const mlir::lsp::URIForFile &uri,
269 StringRef fileContents, int64_t version,
270 std::vector<mlir::lsp::Diagnostic> &diagnostics)
271 : context(context), contents(fileContents.str()) {
272 initialize(uri, version, diagnostics);
275LogicalResult VerilogTextFile::update(
276 const mlir::lsp::URIForFile &uri, int64_t newVersion,
277 ArrayRef<mlir::lsp::TextDocumentContentChangeEvent> changes,
278 std::vector<mlir::lsp::Diagnostic> &diagnostics) {
279 if (failed(mlir::lsp::TextDocumentContentChangeEvent::applyTo(changes,
287 initialize(uri, newVersion, diagnostics);
291void VerilogTextFile::initialize(
292 const mlir::lsp::URIForFile &uri, int64_t newVersion,
293 std::vector<mlir::lsp::Diagnostic> &diagnostics) {
294 version = newVersion;
296 std::make_unique<VerilogDocument>(context, uri, contents, diagnostics);
307 llvm::StringMap<std::unique_ptr<VerilogTextFile>>
files;
317 : impl(std::make_unique<
Impl>(options)) {}
321 const URIForFile &uri, StringRef contents, int64_t version,
322 std::vector<mlir::lsp::Diagnostic> &diagnostics) {
323 impl->files[uri.file()] = std::make_unique<VerilogTextFile>(
324 impl->context, uri, contents, version, diagnostics);
329 ArrayRef<mlir::lsp::TextDocumentContentChangeEvent> changes,
330 int64_t version, std::vector<mlir::lsp::Diagnostic> &diagnostics) {
332 auto it = impl->files.find(uri.file());
333 if (it == impl->files.end())
338 if (failed(it->second->update(uri, version, changes, diagnostics)))
339 impl->files.erase(it);
342std::optional<int64_t>
344 auto it = impl->files.find(uri.file());
345 if (it == impl->files.end())
348 int64_t version = it->second->getVersion();
349 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)