16#include "../Utils/LSPUtils.h"
20#include "mlir/IR/Attributes.h"
21#include "mlir/IR/BuiltinAttributes.h"
22#include "mlir/IR/Location.h"
23#include "mlir/IR/MLIRContext.h"
24#include "mlir/Support/FileUtilities.h"
25#include "slang/ast/ASTVisitor.h"
26#include "slang/ast/Compilation.h"
27#include "slang/ast/Scope.h"
28#include "slang/ast/symbols/CompilationUnitSymbols.h"
29#include "slang/diagnostics/DiagnosticClient.h"
30#include "slang/diagnostics/Diagnostics.h"
31#include "slang/driver/Driver.h"
32#include "slang/syntax/AllSyntax.h"
33#include "slang/syntax/SyntaxTree.h"
34#include "slang/text/SourceLocation.h"
35#include "slang/text/SourceManager.h"
36#include "llvm/ADT/IntervalMap.h"
37#include "llvm/ADT/PointerUnion.h"
38#include "llvm/ADT/SmallString.h"
39#include "llvm/ADT/StringExtras.h"
40#include "llvm/ADT/StringMap.h"
41#include "llvm/Support/FileSystem.h"
42#include "llvm/Support/LSP/Logging.h"
43#include "llvm/Support/LSP/Protocol.h"
44#include "llvm/Support/LineIterator.h"
45#include "llvm/Support/MemoryBuffer.h"
46#include "llvm/Support/Path.h"
47#include "llvm/Support/SMLoc.h"
48#include "llvm/Support/SourceMgr.h"
56using namespace llvm::lsp;
63static llvm::lsp::DiagnosticSeverity
66 case slang::DiagnosticSeverity::Fatal:
67 case slang::DiagnosticSeverity::Error:
68 return llvm::lsp::DiagnosticSeverity::Error;
69 case slang::DiagnosticSeverity::Warning:
70 return llvm::lsp::DiagnosticSeverity::Warning;
71 case slang::DiagnosticSeverity::Ignored:
72 case slang::DiagnosticSeverity::Note:
73 return llvm::lsp::DiagnosticSeverity::Information;
75 llvm_unreachable(
"all slang diagnostic severities should be handled");
76 return llvm::lsp::DiagnosticSeverity::Error;
81struct VerilogServerContext {
88using VerilogIndexSymbol =
89 llvm::PointerUnion<const slang::ast::Symbol *, mlir::Attribute>;
93 VerilogIndex(VerilogDocument &document)
94 : mlirContext(
mlir::MLIRContext::Threading::DISABLED),
95 intervalMap(allocator), document(document) {}
98 void initialize(slang::ast::Compilation &compilation);
101 void insertSymbol(
const slang::ast::Symbol *symbol, slang::SourceRange from,
102 bool isDefinition =
false);
103 void insertSymbolDefinition(
const slang::ast::Symbol *symbol);
105 VerilogDocument &getDocument() {
return document; }
110 llvm::IntervalMap<
const char *, VerilogIndexSymbol,
111 llvm::IntervalMapImpl::NodeSizer<
112 const char *, VerilogIndexSymbol>::LeafSize,
113 llvm::IntervalMapHalfOpenInfo<const char *>>;
115 MapT &getIntervalMap() {
return intervalMap; }
118 using ReferenceMap =
SmallDenseMap<
const slang::ast::Symbol *,
119 SmallVector<slang::SourceRange>>;
120 const ReferenceMap &getReferences()
const {
return references; }
124 void parseSourceLocation();
125 void parseSourceLocation(StringRef toParse);
128 mlir::MLIRContext mlirContext;
131 MapT::Allocator allocator;
138 ReferenceMap references;
141 VerilogDocument &document;
150class LSPDiagnosticClient;
151class VerilogDocument {
153 VerilogDocument(VerilogServerContext &globalContext,
154 const llvm::lsp::URIForFile &uri, StringRef contents,
155 std::vector<llvm::lsp::Diagnostic> &diagnostics);
156 VerilogDocument(
const VerilogDocument &) =
delete;
157 VerilogDocument &operator=(
const VerilogDocument &) =
delete;
159 const llvm::lsp::URIForFile &getURI()
const {
return uri; }
161 llvm::SourceMgr &getSourceMgr() {
return sourceMgr; }
166 const slang::SourceManager &getSlangSourceManager()
const {
167 return driver.sourceManager;
171 llvm::lsp::Location getLspLocation(slang::SourceLocation loc)
const;
172 llvm::lsp::Location getLspLocation(slang::SourceRange range)
const;
175 llvm::SMLoc getSMLoc(slang::SourceLocation loc);
181 void getLocationsOf(
const llvm::lsp::URIForFile &uri,
182 const llvm::lsp::Position &defPos,
183 std::vector<llvm::lsp::Location> &locations);
185 void findReferencesOf(
const llvm::lsp::URIForFile &uri,
186 const llvm::lsp::Position &pos,
187 std::vector<llvm::lsp::Location> &references);
190 std::optional<std::pair<uint32_t, SmallString<128>>>
191 getOrOpenFile(StringRef filePath);
193 VerilogServerContext &globalContext;
201 llvm::StringMap<std::pair<uint32_t, SmallString<128>>> filePathMap;
204 FailureOr<std::unique_ptr<slang::ast::Compilation>> compilation;
207 slang::driver::Driver driver;
210 llvm::SourceMgr sourceMgr;
216 llvm::lsp::URIForFile uri;
228class LSPDiagnosticClient :
public slang::DiagnosticClient {
229 const VerilogDocument &document;
230 std::vector<llvm::lsp::Diagnostic> &diags;
233 LSPDiagnosticClient(
const VerilogDocument &document,
234 std::vector<llvm::lsp::Diagnostic> &diags)
235 : document(document), diags(diags) {}
237 void report(
const slang::ReportedDiagnostic &slangDiag)
override;
241void LSPDiagnosticClient::report(
const slang::ReportedDiagnostic &slangDiag) {
242 auto loc = document.getLspLocation(slangDiag.location);
244 if (loc.uri != document.getURI())
246 auto &mlirDiag = diags.emplace_back();
247 mlirDiag.severity =
getSeverity(slangDiag.severity);
248 mlirDiag.range = loc.range;
249 mlirDiag.source =
"slang";
250 mlirDiag.message = slangDiag.formattedMessage;
257static std::filesystem::path
260 std::filesystem::path path = std::filesystem::weakly_canonical(file, ec);
262 path = std::filesystem::absolute(file).lexically_normal();
270 const std::string &targetAbsStr) {
271 const std::filesystem::path targetAbs =
275 auto cmdFile = mlir::openInputFile(cmdfileStr, &error);
278 cmdfileStr +
": " + error);
282 const std::filesystem::path base =
283 std::filesystem::path(cmdFile->getBufferIdentifier().str()).parent_path();
286 for (llvm::line_iterator i(*cmdFile); !i.is_at_eof(); ++i) {
287 llvm::StringRef line = i->trim();
292 static constexpr llvm::StringRef commandPrefixes[] = {
"+",
"-"};
293 auto isCommand = [&line](llvm::StringRef s) {
return line.starts_with(s); };
294 if (llvm::any_of(commandPrefixes, isCommand))
297 auto candRel = std::filesystem::path(line.str());
299 candRel.is_absolute() ? candRel : (base / candRel));
301 if (candAbs == targetAbs)
307VerilogDocument::VerilogDocument(
308 VerilogServerContext &context,
const llvm::lsp::URIForFile &uri,
309 StringRef contents, std::vector<llvm::lsp::Diagnostic> &diagnostics)
310 : globalContext(context), index(*this), uri(uri) {
311 bool skipMainBufferSlangImport =
false;
313 llvm::SmallString<256> canonPath(uri.file());
314 if (std::error_code ec = llvm::sys::fs::real_path(uri.file(), canonPath))
315 canonPath = uri.file();
318 for (
const std::string &cmdFile : context.options.commandFiles) {
319 if (!driver.processCommandFiles(cmdFile,
false,
true)) {
323 skipMainBufferSlangImport |=
328 llvm::MemoryBuffer::getMemBufferCopy(contents, uri.file());
331 Twine(
"Failed to create memory buffer for file ") + uri.file());
335 const unsigned int mainBufferId =
336 sourceMgr.AddNewSourceBuffer(std::move(memBufferOwn), SMLoc());
339 llvm::SmallString<32> uriDirectory(uri.file());
340 llvm::sys::path::remove_filename(uriDirectory);
342 std::vector<std::string> libDirs;
343 libDirs.push_back(uriDirectory.str().str());
344 libDirs.insert(libDirs.end(), context.options.libDirs.begin(),
345 context.options.libDirs.end());
348 const llvm::MemoryBuffer *memBuffer = sourceMgr.getMemoryBuffer(mainBufferId);
354 slang::driver::Driver topDriver;
356 auto topSlangBuffer =
357 topDriver.sourceManager.assignText(uri.file(), memBuffer->getBuffer());
358 topDriver.sourceLoader.addBuffer(topSlangBuffer);
360 topDriver.options.compilationFlags.emplace(
361 slang::ast::CompilationFlags::LintMode,
false);
362 topDriver.options.compilationFlags.emplace(
363 slang::ast::CompilationFlags::DisableInstanceCaching,
false);
365 if (!topDriver.processOptions()) {
369 if (!topDriver.parseAllSources()) {
375 FailureOr<std::unique_ptr<slang::ast::Compilation>> topCompilation =
376 topDriver.createCompilation();
377 if (failed(topCompilation))
380 std::vector<std::string> topModules;
381 for (
const auto *defs : (*topCompilation)->getDefinitions())
382 topModules.emplace_back(defs->name);
386 driver.options.topModules = std::move(topModules);
389 for (
const auto &libDir : libDirs) {
390 driver.sourceLoader.addSearchDirectories(libDir);
395 if (!skipMainBufferSlangImport) {
397 driver.sourceManager.assignText(uri.file(), memBuffer->getBuffer());
398 driver.sourceLoader.addBuffer(slangBuffer);
399 bufferIDMap[slangBuffer.id.getId()] = mainBufferId;
402 auto diagClient = std::make_shared<LSPDiagnosticClient>(*
this, diagnostics);
403 driver.diagEngine.addClient(diagClient);
405 driver.options.compilationFlags.emplace(
406 slang::ast::CompilationFlags::LintMode,
false);
407 driver.options.compilationFlags.emplace(
408 slang::ast::CompilationFlags::DisableInstanceCaching,
false);
410 if (!driver.processOptions()) {
414 driver.diagEngine.setIgnoreAllWarnings(
false);
416 if (!driver.parseAllSources()) {
422 compilation = driver.createCompilation();
423 if (failed(compilation))
429 llvm::SmallString<256> slangCanonPath;
430 std::unique_ptr<llvm::MemoryBuffer> newBuffer;
431 uint32_t newBufferId;
435 auto *sourceManager = (**compilation).getSourceManager();
436 for (
auto slangBuffer : sourceManager->getAllBuffers()) {
437 std::string_view slangRawPath = sourceManager->getRawFileName(slangBuffer);
438 if (std::error_code ec =
439 llvm::sys::fs::real_path(slangRawPath, slangCanonPath))
442 if (slangCanonPath == canonPath && skipMainBufferSlangImport) {
443 bufferIDMap[slangBuffer.getId()] = mainBufferId;
447 if (slangCanonPath == canonPath && !skipMainBufferSlangImport) {
451 if (!bufferIDMap.contains(slangBuffer.getId())) {
453 auto uriOrError = llvm::lsp::URIForFile::fromFile(slangCanonPath);
454 if (
auto e = uriOrError.takeError()) {
456 Twine(
"Failed to get URI from file " + slangCanonPath));
460 newBuffer = llvm::MemoryBuffer::getMemBufferCopy(
461 sourceManager->getSourceText(slangBuffer), uriOrError->file());
462 newBufferId = sourceMgr.AddNewSourceBuffer(std::move(newBuffer), SMLoc());
463 bufferIDMap[slangBuffer.getId()] = newBufferId;
469 for (
auto &diag : (*compilation)->getAllDiagnostics())
470 driver.diagEngine.issue(diag);
473 index.initialize(**compilation);
477VerilogDocument::getLspLocation(slang::SourceLocation loc)
const {
478 if (loc && loc.buffer() != slang::SourceLocation::NoLocation.buffer()) {
479 const auto &slangSourceManager = getSlangSourceManager();
480 auto line = slangSourceManager.getLineNumber(loc) - 1;
481 auto column = slangSourceManager.getColumnNumber(loc) - 1;
482 auto it = bufferIDMap.find(loc.buffer().getId());
483 if (it != bufferIDMap.end() && it->second == sourceMgr.getMainFileID())
484 return llvm::lsp::Location(uri, llvm::lsp::Range(Position(line, column)));
486 llvm::StringRef fileName = slangSourceManager.getFileName(loc);
488 llvm::SmallString<256> abs(fileName);
489 if (!llvm::sys::path::is_absolute(abs)) {
491 if (std::error_code ec = llvm::sys::fs::real_path(fileName, abs)) {
493 llvm::sys::fs::current_path(abs);
494 llvm::sys::path::append(abs, fileName);
498 if (
auto uriOrErr = llvm::lsp::URIForFile::fromFile(abs)) {
499 if (
auto e = uriOrErr.takeError())
500 return llvm::lsp::Location();
501 return llvm::lsp::Location(*uriOrErr,
502 llvm::lsp::Range(Position(line, column)));
504 return llvm::lsp::Location();
506 return llvm::lsp::Location();
510VerilogDocument::getLspLocation(slang::SourceRange range)
const {
512 auto start = getLspLocation(range.start());
513 auto end = getLspLocation(range.end());
515 if (start.uri !=
end.uri)
516 return llvm::lsp::Location();
518 return llvm::lsp::Location(
519 start.uri, llvm::lsp::Range(start.range.start,
end.range.end));
522llvm::SMLoc VerilogDocument::getSMLoc(slang::SourceLocation loc) {
523 auto bufferID = loc.buffer().getId();
524 llvm::SmallString<256> slangCanonPath(
"");
527 auto bufferIDMapIt = bufferIDMap.find(bufferID);
528 if (bufferIDMapIt == bufferIDMap.end()) {
530 auto path = getSlangSourceManager().getFullPath(loc.buffer());
533 if (std::error_code ec =
534 llvm::sys::fs::real_path(path.string(), slangCanonPath))
535 return llvm::SMLoc();
537 auto memBuffer = llvm::MemoryBuffer::getFile(slangCanonPath);
540 "Failed to open file: " + path.filename().string() +
541 memBuffer.getError().message());
542 return llvm::SMLoc();
545 auto id = sourceMgr.AddNewSourceBuffer(std::move(memBuffer.get()), SMLoc());
547 bufferIDMap.insert({bufferID,
static_cast<uint32_t
>(id)}).first;
550 const auto *buffer = sourceMgr.getMemoryBuffer(bufferIDMapIt->second);
552 return llvm::SMLoc::getFromPointer(buffer->getBufferStart() + loc.offset());
555std::optional<std::pair<uint32_t, SmallString<128>>>
556VerilogDocument::getOrOpenFile(StringRef filePath) {
558 auto fileInfo = filePathMap.find(filePath);
559 if (fileInfo != filePathMap.end())
560 return fileInfo->second;
562 auto getIfExist = [&](StringRef path)
563 -> std::optional<std::pair<uint32_t, SmallString<128>>> {
564 if (llvm::sys::fs::exists(path)) {
565 auto memoryBuffer = llvm::MemoryBuffer::getFile(path);
569 auto id = sourceMgr.AddNewSourceBuffer(std::move(*memoryBuffer), SMLoc());
572 filePathMap.insert(std::make_pair(filePath, std::make_pair(
id, path)))
575 return fileInfo->second;
580 if (llvm::sys::path::is_absolute(filePath))
581 return getIfExist(filePath);
584 for (
auto &libRoot : globalContext.options.extraSourceLocationDirs) {
585 SmallString<128> lib(libRoot);
586 llvm::sys::path::append(lib, filePath);
587 if (
auto fileInfo = getIfExist(lib))
601class VerilogTextFile {
603 VerilogTextFile(VerilogServerContext &globalContext,
604 const llvm::lsp::URIForFile &uri, StringRef fileContents,
606 std::vector<llvm::lsp::Diagnostic> &diagnostics);
609 int64_t getVersion()
const {
return version; }
614 update(
const llvm::lsp::URIForFile &uri, int64_t newVersion,
615 ArrayRef<llvm::lsp::TextDocumentContentChangeEvent> changes,
616 std::vector<llvm::lsp::Diagnostic> &diagnostics);
618 void getLocationsOf(
const llvm::lsp::URIForFile &uri,
619 llvm::lsp::Position defPos,
620 std::vector<llvm::lsp::Location> &locations);
622 void findReferencesOf(
const llvm::lsp::URIForFile &uri,
623 llvm::lsp::Position pos,
624 std::vector<llvm::lsp::Location> &references);
628 void initialize(
const llvm::lsp::URIForFile &uri, int64_t newVersion,
629 std::vector<llvm::lsp::Diagnostic> &diagnostics);
631 VerilogServerContext &context;
634 std::string contents;
641 std::unique_ptr<VerilogDocument> document;
645VerilogTextFile::VerilogTextFile(
646 VerilogServerContext &context,
const llvm::lsp::URIForFile &uri,
647 StringRef fileContents, int64_t version,
648 std::vector<llvm::lsp::Diagnostic> &diagnostics)
649 : context(context), contents(fileContents.str()) {
650 initialize(uri, version, diagnostics);
653LogicalResult VerilogTextFile::update(
654 const llvm::lsp::URIForFile &uri, int64_t newVersion,
655 ArrayRef<llvm::lsp::TextDocumentContentChangeEvent> changes,
656 std::vector<llvm::lsp::Diagnostic> &diagnostics) {
657 if (failed(llvm::lsp::TextDocumentContentChangeEvent::applyTo(changes,
665 initialize(uri, newVersion, diagnostics);
669void VerilogTextFile::initialize(
670 const llvm::lsp::URIForFile &uri, int64_t newVersion,
671 std::vector<llvm::lsp::Diagnostic> &diagnostics) {
672 version = newVersion;
674 std::make_unique<VerilogDocument>(context, uri, contents, diagnostics);
677void VerilogTextFile::getLocationsOf(
678 const llvm::lsp::URIForFile &uri, llvm::lsp::Position defPos,
679 std::vector<llvm::lsp::Location> &locations) {
680 document->getLocationsOf(uri, defPos, locations);
683void VerilogTextFile::findReferencesOf(
684 const llvm::lsp::URIForFile &uri, llvm::lsp::Position pos,
685 std::vector<llvm::lsp::Location> &references) {
686 document->findReferencesOf(uri, pos, references);
692struct VerilogIndexer : slang::ast::ASTVisitor<VerilogIndexer, true, true> {
693 VerilogIndexer(VerilogIndex &index) : index(index) {}
696 void insertSymbol(
const slang::ast::Symbol *symbol, slang::SourceRange range,
697 bool isDefinition =
true) {
698 if (symbol->name.empty())
700 assert(range.start().valid() && range.end().valid() &&
701 "range must be valid");
705 if (range.start() >= range.end()) {
709 index.insertSymbol(symbol, range, isDefinition);
712 void insertSymbol(
const slang::ast::Symbol *symbol,
713 slang::SourceLocation from,
bool isDefinition =
false) {
714 if (symbol->name.empty())
716 assert(from.valid() &&
"location must be valid");
717 insertSymbol(symbol, slang::SourceRange(from, from + symbol->name.size()),
722 void visitExpression(
const slang::ast::Expression &expr) {
723 auto *symbol = expr.getSymbolReference(
true);
726 insertSymbol(symbol, expr.sourceRange,
false);
729 void visitSymbol(
const slang::ast::Symbol &symbol) {
730 insertSymbol(&symbol, symbol.location,
true);
733 void visit(
const slang::ast::NetSymbol &expr) {
734 insertSymbol(&expr, expr.location,
true);
738 void visit(
const slang::ast::VariableSymbol &expr) {
739 insertSymbol(&expr, expr.location,
true);
743 void visit(
const slang::ast::ExplicitImportSymbol &expr) {
744 auto *def = expr.package();
748 if (
auto *syn = expr.getSyntax()) {
749 if (
auto *item = syn->as_if<slang::syntax::PackageImportItemSyntax>()) {
750 insertSymbol(def, item->package.location(),
false);
756 void visit(
const slang::ast::WildcardImportSymbol &expr) {
757 auto *def = expr.getPackage();
761 if (
auto *syn = expr.getSyntax()) {
762 if (
auto *item = syn->as_if<slang::syntax::PackageImportItemSyntax>()) {
763 insertSymbol(def, item->package.location(),
false);
769 void visit(
const slang::ast::InstanceSymbol &expr) {
770 auto *def = &expr.getDefinition();
775 insertSymbol(def, def->location,
true);
781 ->as_if<slang::syntax::HierarchicalInstanceSyntax>())
784 ->as_if<slang::syntax::HierarchyInstantiationSyntax>())
786 insertSymbol(def, modInst->type.location(),
false);
789 insertSymbol(def, expr.location,
false);
793 void visit(
const slang::ast::VariableDeclStatement &expr) {
794 insertSymbol(&expr.symbol, expr.sourceRange,
true);
798 template <
typename T>
799 void visit(
const T &t) {
800 if constexpr (std::is_base_of_v<slang::ast::Expression, T>)
802 if constexpr (std::is_base_of_v<slang::ast::Symbol, T>)
808 template <
typename T>
809 void visitInvalid(
const T &t) {}
813void VerilogIndex::initialize(slang::ast::Compilation &compilation) {
814 const auto &root = compilation.getRoot();
815 VerilogIndexer visitor(*
this);
817 for (
auto *inst : root.topInstances) {
820 if (!(document.getLspLocation(inst->location).uri == document.getURI()))
824 inst->body.visit(visitor);
827 for (
const auto *symbol : inst->body.
getPortList())
828 insertSymbolDefinition(symbol);
832 parseSourceLocation();
835void VerilogIndex::parseSourceLocation(StringRef toParse) {
837 if (toParse.contains(
'\n'))
841 SmallVector<StringRef, 3> fileLineColStrs;
845 for (
auto chunk :
llvm::split(toParse,
", ")) {
846 fileLineColStrs.clear();
847 chunk.split(fileLineColStrs,
':');
848 if (fileLineColStrs.size() != 3)
851 auto filePathMaybeEmpty = fileLineColStrs[0].trim();
853 if (!filePathMaybeEmpty.empty())
854 filePath = filePathMaybeEmpty;
856 auto line = fileLineColStrs[1].trim();
857 auto column = fileLineColStrs[2].trim();
861 if (line.getAsInteger(10, lineInt))
866 SmallVector<std::pair<StringRef, const char *>> columns;
869 if (column.starts_with(
'{') && column.ends_with(
'}')) {
871 for (
auto str :
llvm::split(column.drop_back().drop_front(),
',')) {
872 columns.emplace_back(str,
873 first ? filePathMaybeEmpty.data() : str.
data());
877 columns.push_back({column, filePathMaybeEmpty.data()});
881 for (
auto [column, start] : columns) {
883 if (column.getAsInteger(10, columnInt))
885 auto loc = mlir::FileLineColRange::get(&mlirContext, filePath,
886 lineInt - 1, columnInt - 1,
887 lineInt - 1, columnInt - 1);
888 const char *
end = column.end();
889 if (!intervalMap.overlaps(start, end))
890 intervalMap.insert(start, end, loc);
895void VerilogIndex::parseSourceLocation() {
896 auto &sourceMgr = getDocument().getSourceMgr();
897 auto *getMainBuffer = sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID());
898 StringRef text(getMainBuffer->getBufferStart(),
899 getMainBuffer->getBufferSize());
906 StringRef start =
"// @[";
907 auto loc = text.find(start);
908 if (loc == StringRef::npos)
911 text = text.drop_front(loc + start.size());
912 auto endPos = text.find_first_of(
"]\n");
913 if (endPos == StringRef::npos)
915 auto toParse = text.take_front(endPos);
917 parseSourceLocation(toParse);
929 llvm::StringMap<std::unique_ptr<VerilogTextFile>>
files;
939 : impl(std::make_unique<
Impl>(options)) {}
943 const URIForFile &uri, StringRef contents, int64_t version,
944 std::vector<llvm::lsp::Diagnostic> &diagnostics) {
945 impl->files[uri.file()] = std::make_unique<VerilogTextFile>(
946 impl->context, uri, contents, version, diagnostics);
951 ArrayRef<llvm::lsp::TextDocumentContentChangeEvent> changes,
952 int64_t version, std::vector<llvm::lsp::Diagnostic> &diagnostics) {
954 auto it = impl->files.find(uri.file());
955 if (it == impl->files.end())
960 if (failed(it->second->update(uri, version, changes, diagnostics)))
961 impl->files.erase(it);
964std::optional<int64_t>
966 auto it = impl->files.find(uri.file());
967 if (it == impl->files.end())
970 int64_t version = it->second->getVersion();
971 impl->files.erase(it);
976 const URIForFile &uri,
const Position &defPos,
977 std::vector<llvm::lsp::Location> &locations) {
978 auto fileIt = impl->files.find(uri.file());
979 if (fileIt != impl->files.end())
980 fileIt->second->getLocationsOf(uri, defPos, locations);
985 std::vector<llvm::lsp::Location> &references) {
986 auto fileIt = impl->files.find(uri.file());
987 if (fileIt != impl->files.end())
988 fileIt->second->findReferencesOf(uri, pos, references);
991void VerilogIndex::insertSymbol(
const slang::ast::Symbol *symbol,
992 slang::SourceRange from,
bool isDefinition) {
993 assert(from.start().valid() && from.end().valid());
996 if (!from.start().valid() || !from.end().valid() ||
997 from.start() >= from.end())
1000 const char *startLoc = getDocument().getSMLoc(from.start()).getPointer();
1001 const char *endLoc = getDocument().getSMLoc(from.end()).getPointer() + 1;
1002 if (!startLoc || !endLoc || startLoc >= endLoc)
1005 assert(startLoc && endLoc);
1007 if (startLoc != endLoc && !intervalMap.overlaps(startLoc, endLoc)) {
1008 intervalMap.insert(startLoc, endLoc, symbol);
1010 references[symbol].push_back(from);
1014void VerilogIndex::insertSymbolDefinition(
const slang::ast::Symbol *symbol) {
1015 if (!symbol->location)
1017 auto size = symbol->name.size() ? symbol->name.size() : 1;
1018 insertSymbol(symbol,
1019 slang::SourceRange(symbol->location, symbol->location + size),
1027static llvm::lsp::Range
getRange(
const mlir::FileLineColRange &fileLoc) {
1028 return llvm::lsp::Range(
1029 llvm::lsp::Position(fileLoc.getStartLine(), fileLoc.getStartColumn()),
1030 llvm::lsp::Position(fileLoc.getEndLine(), fileLoc.getEndColumn()));
1033void VerilogDocument::getLocationsOf(
1034 const llvm::lsp::URIForFile &uri,
const llvm::lsp::Position &defPos,
1035 std::vector<llvm::lsp::Location> &locations) {
1036 SMLoc posLoc = defPos.getAsSMLoc(sourceMgr);
1037 const auto &intervalMap = index.getIntervalMap();
1038 auto it = intervalMap.find(posLoc.getPointer());
1041 if (!it.valid() || posLoc.getPointer() < it.start())
1044 auto element = it.value();
1045 if (
auto attr = dyn_cast<Attribute>(element)) {
1048 if (
auto fileLoc = dyn_cast<mlir::FileLineColRange>(attr)) {
1051 auto fileInfo = getOrOpenFile(fileLoc.getFilename().getValue());
1054 const auto &[bufferId, filePath] = *fileInfo;
1055 auto uri = llvm::lsp::URIForFile::fromFile(filePath);
1056 if (
auto e = uri.takeError()) {
1061 locations.emplace_back(uri.get(),
getRange(fileLoc));
1068 const auto *symbol = cast<const slang::ast::Symbol *>(element);
1070 slang::SourceRange range(symbol->location,
1072 (symbol->name.size() ? symbol->name.size() : 1));
1073 locations.push_back(getLspLocation(range));
1076void VerilogDocument::findReferencesOf(
1077 const llvm::lsp::URIForFile &uri,
const llvm::lsp::Position &pos,
1078 std::vector<llvm::lsp::Location> &references) {
1079 SMLoc posLoc = pos.getAsSMLoc(sourceMgr);
1080 const auto &intervalMap = index.getIntervalMap();
1081 auto intervalIt = intervalMap.find(posLoc.getPointer());
1082 if (!intervalIt.valid() || posLoc.getPointer() < intervalIt.start())
1085 const auto *symbol = dyn_cast<const slang::ast::Symbol *>(intervalIt.value());
1089 auto it = index.getReferences().find(symbol);
1090 if (it == index.getReferences().end())
1092 for (
auto referenceRange : it->second)
1093 references.push_back(getLspLocation(referenceRange));
assert(baseType &&"element must be base type")
static SmallVector< PortInfo > getPortList(ModuleTy &mod)
static llvm::lsp::Range getRange(const mlir::FileLineColRange &fileLoc)
static bool mainBufferFileInCommandFileList(const std::string &cmdfileStr, const std::string &targetAbsStr)
static std::filesystem::path canonicalizeFileName(const std::filesystem::path &file)
static llvm::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 getLocationsOf(const URIForFile &uri, const llvm::lsp::Position &defPos, std::vector< llvm::lsp::Location > &locations)
Return the locations of the object pointed at by the given position.
void findReferencesOf(const URIForFile &uri, const llvm::lsp::Position &pos, std::vector< llvm::lsp::Location > &references)
Find all references of the object pointed at by the given position.
void error(Twine message)
llvm::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)