9#include "slang/ast/ASTVisitor.h"
10#include "slang/ast/Expression.h"
11#include "slang/ast/statements/MiscStatements.h"
12#include "slang/ast/symbols/CompilationUnitSymbols.h"
13#include "slang/ast/symbols/InstanceSymbols.h"
14#include "slang/ast/symbols/MemberSymbols.h"
15#include "slang/ast/symbols/VariableSymbols.h"
16#include "slang/syntax/AllSyntax.h"
17#include "slang/text/SourceManager.h"
19#include "mlir/IR/Location.h"
20#include "mlir/Support/FileUtilities.h"
22#include "llvm/ADT/StringExtras.h"
24#include "../Utils/LSPUtils.h"
35inline bool definitelyOutsideMainBuffer(
const T &t, slang::BufferID bufferId) {
36 if constexpr (
requires {
41 return r.buffer() != bufferId;
44 if constexpr (
requires {
47 auto r = t.sourceRange;
48 if (r.start().valid() && r.end().valid())
49 return r.start().buffer() != bufferId && r.end().buffer() != bufferId;
52 if constexpr (
requires { t.getSyntax(); }) {
53 if (
auto *syn = t.getSyntax()) {
54 auto r = syn->sourceRange();
55 if (r.start().valid() && r.end().valid())
56 return r.start().buffer() != bufferId && r.end().buffer() != bufferId;
63struct VerilogIndexer : slang::ast::ASTVisitor<VerilogIndexer, true, true> {
64 using ASTBase = slang::ast::ASTVisitor<VerilogIndexer, true, true>;
69 void recurseIfInMainBuffer(
const T &node) {
70 if (definitelyOutsideMainBuffer(node, index.
getBufferId()))
75 void insertSymbol(
const slang::ast::Symbol *symbol, slang::SourceRange range,
76 bool isDefinition =
true) {
77 if (symbol->name.empty())
79 assert(range.start().valid() && range.end().valid() &&
80 "range must be valid");
84 if (range.start().offset() >= range.end().offset()) {
91 void insertSymbol(
const slang::ast::Symbol *symbol,
92 slang::SourceLocation from,
bool isDefinition =
false) {
93 if (symbol->name.empty())
95 assert(from.valid() &&
"location must be valid");
96 insertSymbol(symbol, slang::SourceRange(from, from + symbol->name.size()),
101 void visitExpression(
const slang::ast::Expression &expr) {
102 auto *symbol = expr.getSymbolReference(
true);
105 insertSymbol(symbol, expr.sourceRange,
false);
108 void visitSymbol(
const slang::ast::Symbol &symbol) {
109 insertSymbol(&symbol, symbol.location,
true);
112 void visit(
const slang::ast::NetSymbol &expr) {
113 insertSymbol(&expr, expr.location,
true);
114 recurseIfInMainBuffer(expr);
117 void visit(
const slang::ast::VariableSymbol &expr) {
118 insertSymbol(&expr, expr.location,
true);
119 recurseIfInMainBuffer(expr);
122 void visit(
const slang::ast::ExplicitImportSymbol &expr) {
123 auto *def = expr.package();
127 if (
auto *syn = expr.getSyntax()) {
128 if (
auto *item = syn->as_if<slang::syntax::PackageImportItemSyntax>()) {
129 insertSymbol(def, item->package.location(),
false);
132 recurseIfInMainBuffer(expr);
135 void visit(
const slang::ast::WildcardImportSymbol &expr) {
136 auto *def = expr.getPackage();
140 if (
auto *syn = expr.getSyntax()) {
141 if (
auto *item = syn->as_if<slang::syntax::PackageImportItemSyntax>()) {
142 insertSymbol(def, item->package.location(),
false);
145 recurseIfInMainBuffer(expr);
148 void visit(
const slang::ast::InstanceBodySymbol &expr) {
151 index.insertSymbolDefinition(symbol);
152 recurseIfInMainBuffer(expr);
155 void visit(
const slang::ast::InstanceSymbol &expr) {
156 auto *def = &expr.getDefinition();
161 insertSymbol(def, def->location,
true);
167 ->as_if<slang::syntax::HierarchicalInstanceSyntax>())
170 ->as_if<slang::syntax::HierarchyInstantiationSyntax>())
172 insertSymbol(def, modInst->type.location(),
false);
175 insertSymbol(def, expr.location,
false);
176 recurseIfInMainBuffer(expr);
179 void visit(
const slang::ast::VariableDeclStatement &expr) {
180 insertSymbol(&expr.symbol, expr.sourceRange,
true);
181 recurseIfInMainBuffer(expr);
184 template <
typename T>
185 void visit(
const T &node) {
186 if constexpr (std::is_base_of_v<slang::ast::Expression, T>)
187 visitExpression(node);
188 if constexpr (std::is_base_of_v<slang::ast::Symbol, T>)
191 recurseIfInMainBuffer(node);
194 template <
typename T>
195 void visitInvalid(
const T &t) {}
200 const auto &root = compilation.getRoot();
201 VerilogIndexer visitor(*
this);
204 for (
auto *package : compilation.getPackages()) {
208 package->visit(visitor);
212 for (
auto *inst : root.topInstances) {
216 inst->body.visit(visitor);
225 if (toParse.contains(
'\n'))
229 SmallVector<StringRef, 3> fileLineColStrs;
233 for (
auto chunk :
llvm::split(toParse,
", ")) {
234 fileLineColStrs.clear();
235 chunk.split(fileLineColStrs,
':');
236 if (fileLineColStrs.size() != 3)
239 auto filePathMaybeEmpty = fileLineColStrs[0].trim();
241 if (!filePathMaybeEmpty.empty())
242 filePath = filePathMaybeEmpty;
244 auto line = fileLineColStrs[1].trim();
245 auto column = fileLineColStrs[2].trim();
249 if (line.getAsInteger(10, lineInt))
254 SmallVector<std::pair<StringRef, const char *>> columns;
257 if (column.starts_with(
'{') && column.ends_with(
'}')) {
259 for (
auto str :
llvm::split(column.drop_back().drop_front(),
',')) {
260 columns.emplace_back(str,
261 first ? filePathMaybeEmpty.data() : str.data());
265 columns.push_back({column, filePathMaybeEmpty.data()});
269 for (
auto [column, start] : columns) {
271 if (column.getAsInteger(10, columnInt))
273 auto loc = mlir::FileLineColRange::get(&
mlirContext, filePath,
274 lineInt - 1, columnInt - 1,
275 lineInt - 1, columnInt - 1);
276 const char *
end = column.end();
285 auto getMainBuffer = sourceMgr.getSourceText(
getBufferId());
286 StringRef text(getMainBuffer);
293 StringRef start =
"// @[";
294 auto loc = text.find(start);
295 if (loc == StringRef::npos)
298 text = text.drop_front(loc + start.size());
299 auto endPos = text.find_first_of(
"]\n");
300 if (endPos == StringRef::npos)
302 auto toParse = text.take_front(endPos);
309 slang::SourceRange from,
bool isDefinition) {
310 assert(from.start().valid() && from.end().valid());
313 if (from.start().offset() >= from.end().offset())
316 auto lhsBufferId = from.start().buffer();
317 auto rhsBufferId = from.end().buffer();
318 if (lhsBufferId.getId() != rhsBufferId.getId() || !rhsBufferId.valid() ||
319 !lhsBufferId.valid())
324 const auto *lhsBound = buffer.data() + from.start().offset();
325 const auto *rhsBound = buffer.data() + from.end().offset();
327 if (lhsBound >= rhsBound)
338 if (!symbol->location)
340 auto size = symbol->name.size() ? symbol->name.size() : 1;
341 auto range = slang::SourceRange(symbol->location, symbol->location + size);
assert(baseType &&"element must be base type")
static SmallVector< PortInfo > getPortList(ModuleTy &mod)
ReferenceMap references
References of symbols.
void parseSourceLocation()
Parse source location emitted by ExportVerilog.
void insertSymbolDefinition(const slang::ast::Symbol *symbol)
mlir::MLIRContext mlirContext
void insertSymbol(const slang::ast::Symbol *symbol, slang::SourceRange from, bool isDefinition=false)
Register a reference to a symbol symbol from from.
const slang::BufferID & getBufferId() const
MapT intervalMap
An interval map containing a corresponding definition mapped to a source interval.
void initialize(slang::ast::Compilation &compilation)
Initialize the index with the given compilation unit.
const slang::SourceManager & getSlangSourceManager() const