1818#include " slang/ast/Lookup.h"
1919#include " slang/ast/Scope.h"
2020#include " slang/ast/Symbol.h"
21+ #include " slang/ast/symbols/CompilationUnitSymbols.h"
2122#include " slang/diagnostics/Diagnostics.h"
2223#include " slang/syntax/AllSyntax.h"
24+ #include " slang/syntax/SyntaxFacts.h"
2325#include " slang/syntax/SyntaxKind.h"
26+ #include " slang/syntax/SyntaxNode.h"
2427#include " slang/syntax/SyntaxTree.h"
2528#include " slang/syntax/SyntaxVisitor.h"
2629#include " slang/text/SourceLocation.h"
2730#include " slang/text/SourceManager.h"
2831#include " llvm/Support/LSP/Protocol.h"
29- #include " llvm/Support/SourceMgr.h"
3032
33+ using namespace slang ;
3134using namespace slang ::syntax;
35+ using namespace slang ::ast;
36+
37+ struct DefIndex {
38+ // For now: name -> location (first hit wins). Upgrade to multimap if needed.
39+ std::unordered_map<std::string, slang::SourceLocation> byName;
40+ };
41+
42+
43+ static void indexDeclarators (const slang::syntax::SyntaxNode &node,
44+ DefIndex &out) {
45+ using namespace slang ::syntax;
46+
47+ switch (node.kind ) {
48+ case SyntaxKind::Declarator:
49+ if (auto *decl = node.as_if <DeclaratorSyntax>()) {
50+ auto nameText = decl->name .valueText (); // strips trivia
51+ auto loc = decl->name .location ();
52+ if (!nameText.empty () && loc)
53+ out.byName .emplace (std::string (nameText), loc);
54+ }
55+ break ;
56+ default :
57+ break ;
58+ }
59+ }
60+
61+ // / Walk the syntax tree from its root down to collect all declarators;
62+ // / declarators contain symbol definitions we can lookup later.
63+ static void walk (const slang::syntax::SyntaxNode &node, DefIndex &out) {
64+ indexDeclarators (node, out);
65+
66+ for (size_t i = 0 , e = node.getChildCount (); i < e; ++i)
67+ if (auto *c = node.childNode (i))
68+ walk (*c, out);
69+ }
3270
3371static bool isLocationInRange (slang::SourceRange r, slang::SourceLocation loc) {
3472 if (!r.start () || !r.end ())
@@ -37,6 +75,65 @@ static bool isLocationInRange(slang::SourceRange r, slang::SourceLocation loc) {
3775 return r.start ().offset () <= o && o < r.end ().offset ();
3876}
3977
78+ namespace {
79+ // / Visitor that tries to produce a definition `SourceLocation` for a node.
80+ struct DefinitionVisitor : public slang ::syntax::SyntaxVisitor<
81+ std::optional<slang::SourceLocation>> {
82+ using Base = SyntaxVisitor<std::optional<slang::SourceLocation>>;
83+ using Base::visit;
84+
85+ DefinitionVisitor (const slang::ast::Compilation &comp,
86+ const slang::ast::Scope &rootScope,
87+ slang::SourceLocation queryLoc, DefIndex &defIndex)
88+ : comp(comp), rootScope(rootScope), queryLoc(queryLoc),
89+ defIndex (defIndex) {}
90+
91+ // Hierarchy instantiation -> resolve the *type* globally.
92+ std::optional<slang::SourceLocation>
93+ visit (const HierarchyInstantiationSyntax &n) {
94+ auto res = comp.tryGetDefinition (n.type .valueText (), rootScope);
95+ if (res.definition )
96+ return res.definition ->location ;
97+ return std::nullopt ;
98+ }
99+
100+ // Declaration name (e.g., "logic x;") — treat cursor as the def.
101+ std::optional<slang::SourceLocation> visit (const DeclaratorSyntax &) {
102+ return queryLoc;
103+ }
104+
105+ // Module header (cursor on module name) — treat cursor as the def.
106+ std::optional<slang::SourceLocation> visit (const ModuleHeaderSyntax &) {
107+ return queryLoc;
108+ }
109+
110+ // Instance name (u0) — TODO (not implemented).
111+ std::optional<slang::SourceLocation> visit (const InstanceNameSyntax &) {
112+ return std::nullopt ;
113+ }
114+
115+ // Generic name — TODO: local scope lookup.
116+ std::optional<slang::SourceLocation> visit (const IdentifierNameSyntax &node) {
117+ auto it = defIndex.byName .find (std::string (node.identifier .valueText ()));
118+ if (it == defIndex.byName .end ())
119+ return std::nullopt ;
120+ return it->second ;
121+ }
122+
123+ // Fallback for all other node kinds.
124+ template <typename T>
125+ std::optional<slang::SourceLocation> visit (const T &) {
126+ return std::nullopt ;
127+ }
128+
129+ const slang::ast::Compilation ∁
130+ const slang::ast::Scope &rootScope;
131+ slang::SourceLocation queryLoc;
132+ DefIndex &defIndex;
133+ };
134+
135+ } // namespace
136+
40137slang::SourceLocation
41138SlangProjectLookup::lspPositionToSlangLocation (slang::BufferID buf,
42139 const llvm::lsp::Position &pos) {
@@ -123,79 +220,33 @@ SlangProjectLookup::getSyntaxNodeAt(slang::BufferID mainBufferId,
123220 return findSmallestNodeAt (root, loc);
124221}
125222
126- namespace {
127- // / Visitor that tries to produce a definition `SourceLocation` for a node.
128- struct DefinitionVisitor
129- : public slang::syntax::SyntaxVisitor<std::optional<slang::SourceLocation>> {
130- using Base = SyntaxVisitor<std::optional<slang::SourceLocation>>;
131- using Base::visit;
132-
133- DefinitionVisitor (const slang::ast::Compilation &comp, const slang::ast::Scope &rootScope,
134- slang::SourceLocation queryLoc)
135- : comp(comp), rootScope(rootScope), queryLoc(queryLoc) {}
136-
137- // Hierarchy instantiation -> resolve the *type* globally.
138- std::optional<slang::SourceLocation>
139- visit (const HierarchyInstantiationSyntax &n) {
140- llvm::dbgs () << " valueText: " << n.type .valueText () << " \n " ;
141- auto res = comp.tryGetDefinition (n.type .valueText (), rootScope);
142- if (res.definition )
143- return res.definition ->location ;
144- return std::nullopt ;
145- }
146-
147- // Declaration name (e.g., "logic x;") — treat cursor as the def.
148- std::optional<slang::SourceLocation> visit (const DeclaratorSyntax &) {
149- return queryLoc;
150- }
151-
152- // Module header (cursor on module name) — treat cursor as the def.
153- std::optional<slang::SourceLocation> visit (const ModuleHeaderSyntax &) {
154- return queryLoc;
155- }
156-
157- // Instance name (u0) — TODO (not implemented).
158- std::optional<slang::SourceLocation> visit (const InstanceNameSyntax &) {
159- return std::nullopt ;
160- }
161-
162- // Generic name — TODO: local scope lookup.
163- std::optional<slang::SourceLocation> visit (const NameSyntax &) {
164- return std::nullopt ;
165- }
166-
167- // Fallback for all other node kinds.
168- template <typename T>
169- std::optional<slang::SourceLocation> visit (const T &) {
170- return std::nullopt ;
171- }
172-
173- const slang::ast::Compilation ∁
174- const slang::ast::Scope &rootScope;
175- slang::SourceLocation queryLoc;
176- };
177-
178- } // namespace
179-
180223llvm::FailureOr<const slang::SourceLocation>
181224SlangProjectLookup::tryFindDefinitionAt (slang::BufferID mainBufferId,
182225 slang::SourceLocation loc) {
183226
184227 const SyntaxNode *node;
185228 llvm::FailureOr<const SyntaxNode *> n = getSyntaxNodeAt (mainBufferId, loc);
229+
186230 if (failed (n))
187231 return llvm::failure ();
188232 node = n.value ();
189233
234+ // Find the root (topmost) syntax node of this tree.
235+ const SyntaxNode *root = node;
236+ for (const SyntaxNode *cur = node; cur; cur = cur->parent )
237+ root = cur; // root ends up as the last non-null
238+
239+ DefIndex d;
240+ walk (*root, d);
190241
191- DefinitionVisitor v{compilation, rootSymbol, loc};
242+ DefinitionVisitor v{compilation, rootSymbol, loc, d };
192243
193244 // Try at the node first…
194245 if (auto hit = node->visit (v))
195246 return *hit;
196247
197248 // …then walk up parents to broaden the context.
198- for (const SyntaxNode* p = node->parent ; p; p = p->parent ) {
249+ for (const SyntaxNode * p = node->parent ; p; p = p->parent ) {
199250 if (auto hit = p->visit (v))
200251 return *hit;
201252 }
0 commit comments