35#include "slang/syntax/AllSyntax.h"
36#include "slang/syntax/SyntaxTree.h"
38#include "mlir/IR/Attributes.h"
39#include "mlir/IR/BuiltinAttributes.h"
40#include "mlir/IR/Location.h"
41#include "mlir/Support/FileUtilities.h"
43#include "llvm/Support/ConvertUTF.h"
44#include "llvm/Support/FileSystem.h"
45#include "llvm/Support/LineIterator.h"
46#include "llvm/Support/Path.h"
48#include "../Utils/LSPUtils.h"
56using namespace llvm::lsp;
60 if (!driver.parseAllSources()) {
65 std::vector<std::string> topModules;
66 for (
auto &t : driver.syntaxTrees) {
68 t->root().as_if<slang::syntax::CompilationUnitSyntax>()) {
69 for (
auto *member : compUnit->members) {
72 if (
auto *moduleDecl =
73 member->as_if<slang::syntax::ModuleDeclarationSyntax>()) {
74 topModules.emplace_back(moduleDecl->header->name.valueText());
79 driver.options.topModules = std::move(topModules);
84 const slang::driver::Driver *
const projectDriver,
85 const llvm::SmallString<256> &mainBufferFileName) {
86 for (
auto bId : projectDriver->sourceManager.getAllBuffers()) {
87 std::string_view slangRawPath =
88 projectDriver->sourceManager.getRawFileName(bId);
90 llvm::SmallString<256> slangCanonPath;
91 if (llvm::sys::fs::real_path(slangRawPath, slangCanonPath))
98 bool alreadyLoaded =
false;
99 for (
auto id : driver.sourceManager.getAllBuffers()) {
100 if (driver.sourceManager.getFullPath(
id).string() ==
101 slangCanonPath.str()) {
102 alreadyLoaded =
true;
109 auto buffer = driver.sourceManager.assignText(
110 slangCanonPath.str(), projectDriver->sourceManager.getSourceText(bId));
111 driver.sourceLoader.addBuffer(buffer);
117 StringRef contents, std::vector<llvm::lsp::Diagnostic> &diagnostics,
118 const slang::driver::Driver *
const projectDriver,
119 const std::vector<std::string> &projectIncludeDirectories)
120 : globalContext(context), uri(uri) {
122 llvm::SmallString<256> canonPath(uri.file());
123 if (std::error_code ec = llvm::sys::fs::real_path(uri.file(), canonPath))
124 canonPath = uri.file();
127 llvm::SmallString<32> uriDirectory(uri.file());
128 llvm::sys::path::remove_filename(uriDirectory);
130 std::vector<std::string> libDirs;
131 libDirs.push_back(uriDirectory.str().str());
135 for (
const auto &libDir : libDirs)
136 driver.sourceLoader.addSearchDirectories(libDir);
138 auto memBuffer = llvm::MemoryBuffer::getMemBufferCopy(contents, uri.file());
141 Twine(
"Failed to create memory buffer for file ") + uri.file());
145 auto topSlangBuffer =
146 driver.sourceManager.assignText(uri.file(), memBuffer->getBuffer());
147 driver.sourceLoader.addBuffer(topSlangBuffer);
148 mainBufferId = topSlangBuffer.id;
150 auto diagClient = std::make_shared<LSPDiagnosticClient>(*
this, diagnostics);
151 driver.diagEngine.addClient(diagClient);
153 driver.options.compilationFlags.emplace(
154 slang::ast::CompilationFlags::LintMode,
false);
155 driver.options.compilationFlags.emplace(
156 slang::ast::CompilationFlags::DisableInstanceCaching,
false);
158 for (
auto &dir : projectIncludeDirectories)
159 (void)driver.sourceManager.addUserDirectories(dir);
161 if (!driver.processOptions()) {
166 driver.diagEngine.setIgnoreAllWarnings(
false);
171 driver.options = projectDriver->options;
178 if (!driver.parseAllSources()) {
184 compilation = driver.createCompilation();
185 if (failed(compilation)) {
191 for (
auto &diag : (*compilation)->getAllDiagnostics())
192 driver.diagEngine.issue(diag);
194 computeLineOffsets(driver.sourceManager.getSourceText(mainBufferId));
196 index = std::make_unique<VerilogIndex>(mainBufferId, driver.sourceManager);
198 index->initialize(**compilation);
203 if (loc && loc.buffer() != slang::SourceLocation::NoLocation.buffer()) {
205 auto line = slangSourceManager.getLineNumber(loc) - 1;
206 auto column = slangSourceManager.getColumnNumber(loc) - 1;
207 auto it = loc.buffer();
209 return llvm::lsp::Location(
uri, llvm::lsp::Range(Position(line, column)));
211 llvm::StringRef fileName = slangSourceManager.getFileName(loc);
213 llvm::SmallString<256> abs(fileName);
214 if (!llvm::sys::path::is_absolute(abs)) {
216 if (std::error_code ec = llvm::sys::fs::real_path(fileName, abs)) {
218 llvm::sys::fs::current_path(abs);
219 llvm::sys::path::append(abs, fileName);
223 if (
auto uriOrErr = llvm::lsp::URIForFile::fromFile(abs)) {
224 if (
auto e = uriOrErr.takeError())
225 return llvm::lsp::Location();
226 return llvm::lsp::Location(*uriOrErr,
227 llvm::lsp::Range(Position(line, column)));
229 return llvm::lsp::Location();
231 return llvm::lsp::Location();
240 if (start.uri != end.uri)
241 return llvm::lsp::Location();
243 return llvm::lsp::Location(
244 start.uri, llvm::lsp::Range(start.range.start, end.range.end));
247std::optional<std::pair<slang::BufferID, SmallString<128>>>
252 return fileInfo->second;
254 auto getIfExist = [&](StringRef path)
255 -> std::optional<std::pair<slang::BufferID, SmallString<128>>> {
256 if (llvm::sys::fs::exists(path)) {
257 auto memoryBuffer = llvm::MemoryBuffer::getFile(path);
262 auto newSlangBuffer =
driver.sourceManager.assignText(
263 path.str(), memoryBuffer.get()->getBufferStart());
264 driver.sourceLoader.addBuffer(newSlangBuffer);
267 .insert(std::make_pair(
268 filePath, std::make_pair(newSlangBuffer.id, path)))
271 return fileInfo->second;
276 if (llvm::sys::path::is_absolute(filePath))
277 return getIfExist(filePath);
281 SmallString<128> lib(libRoot);
282 llvm::sys::path::append(lib, filePath);
283 if (
auto fileInfo = getIfExist(lib))
290static llvm::lsp::Range
getRange(
const mlir::FileLineColRange &fileLoc) {
291 return llvm::lsp::Range(
292 llvm::lsp::Position(fileLoc.getStartLine(), fileLoc.getStartColumn()),
293 llvm::lsp::Position(fileLoc.getEndLine(), fileLoc.getEndColumn()));
301 for (
size_t i = 0; i < text.size(); ++i) {
302 if (text[i] ==
'\n') {
303 lineOffsets.push_back(
static_cast<uint32_t
>(i + 1));
309std::optional<uint32_t>
321 size_t lineEnd = ((unsigned)(pos.line + 1) <
lineOffsets.size())
325 const llvm::UTF8 *src =
326 reinterpret_cast<const llvm::UTF8 *
>(text.data() + lineStart);
327 const llvm::UTF8 *srcEnd =
328 reinterpret_cast<const llvm::UTF8 *
>(text.data() + lineEnd);
331 const uint32_t target = pos.character;
333 return static_cast<uint32_t
>(
334 src -
reinterpret_cast<const llvm::UTF8 *
>(text.data()));
336 std::vector<llvm::UTF16> sink(target);
337 llvm::UTF16 *out = sink.data();
338 llvm::UTF16 *outEnd = out + sink.size();
340 (void)llvm::ConvertUTF8toUTF16(&src, srcEnd, &out, outEnd,
341 llvm::lenientConversion);
343 return static_cast<uint32_t
>(
reinterpret_cast<const char *
>(src) -
351 if (!slangBufferOffset.has_value())
354 uint32_t offset = slangBufferOffset.value();
359 const llvm::lsp::URIForFile &uri,
const llvm::lsp::Position &defPos,
360 std::vector<llvm::lsp::Location> &locations) {
367 const auto &intervalMap =
index->getIntervalMap();
368 auto it = intervalMap.find(slangBufferPointer);
371 if (!it.valid() || slangBufferPointer < it.start())
374 auto element = it.value();
375 if (
auto attr = dyn_cast<Attribute>(element)) {
378 if (
auto fileLoc = dyn_cast<mlir::FileLineColRange>(attr)) {
381 auto fileInfo =
getOrOpenFile(fileLoc.getFilename().getValue());
384 const auto &[bufferId, filePath] = *fileInfo;
385 auto uri = llvm::lsp::URIForFile::fromFile(filePath);
386 if (
auto e =
uri.takeError()) {
390 locations.emplace_back(
uri.get(),
getRange(fileLoc));
397 const auto *symbol = cast<const slang::ast::Symbol *>(element);
399 slang::SourceRange range(symbol->location,
401 (symbol->name.size() ? symbol->name.size() : 1));
406 const llvm::lsp::URIForFile &uri,
const llvm::lsp::Position &pos,
407 std::vector<llvm::lsp::Location> &references) {
413 const auto &intervalMap =
index->getIntervalMap();
414 auto intervalIt = intervalMap.find(slangBufferPointer);
416 if (!intervalIt.valid() || slangBufferPointer < intervalIt.start())
419 const auto *symbol = dyn_cast<const slang::ast::Symbol *>(intervalIt.value());
423 auto it =
index->getReferences().find(symbol);
424 if (it ==
index->getReferences().end())
426 for (
auto referenceRange : it->second)
static llvm::lsp::Range getRange(const mlir::FileLineColRange &fileLoc)
static void copyBuffers(slang::driver::Driver &driver, const slang::driver::Driver *const projectDriver, const llvm::SmallString< 256 > &mainBufferFileName)
static void setTopModules(slang::driver::Driver &driver)
std::unique_ptr< circt::lsp::VerilogIndex > index
The index of the parsed module.
slang::BufferID mainBufferId
const char * getPointerFor(const llvm::lsp::Position &pos)
slang::driver::Driver driver
VerilogDocument(VerilogServerContext &globalContext, const llvm::lsp::URIForFile &uri, llvm::StringRef contents, std::vector< llvm::lsp::Diagnostic > &diagnostics, const slang::driver::Driver *projectDriver=nullptr, const std::vector< std::string > &projectIncludeDirectories={})
VerilogServerContext & globalContext
llvm::lsp::URIForFile uri
void getLocationsOf(const llvm::lsp::URIForFile &uri, const llvm::lsp::Position &defPos, std::vector< llvm::lsp::Location > &locations)
void computeLineOffsets(std::string_view text)
Build a vector of line start offsets (0-based).
std::optional< std::pair< slang::BufferID, llvm::SmallString< 128 > > > getOrOpenFile(llvm::StringRef filePath)
void findReferencesOf(const llvm::lsp::URIForFile &uri, const llvm::lsp::Position &pos, std::vector< llvm::lsp::Location > &references)
std::optional< uint32_t > lspPositionToOffset(const llvm::lsp::Position &pos)
const slang::SourceManager & getSlangSourceManager() const
llvm::StringMap< std::pair< slang::BufferID, llvm::SmallString< 128 > > > filePathMap
std::vector< uint32_t > lineOffsets
The precomputed line offsets for faster lookups.
llvm::lsp::Location getLspLocation(slang::SourceLocation loc) const
void error(Twine message)
const circt::lsp::VerilogServerOptions & options
const std::vector< std::string > & libDirs
Additional list of RTL directories to search.
const std::vector< std::string > & extraSourceLocationDirs
Additional list of external source directories to search.