Skip to content

Commit f1cf6d0

Browse files
committed
Support go to definition on imported type references
1 parent f54c946 commit f1cf6d0

File tree

4 files changed

+78
-4
lines changed

4 files changed

+78
-4
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ type Contents = {
2828
- Added `luau-lsp.diagnostics.strictDatamodelTypes` (default: `false`) which configures whether we use expressive DataModel types to power diagnostics.
2929
When off, `game` / `script` / `workspace` (and all their members) are typed as `any`, which helps to prevent false positives, but may lead to false negatives.
3030
- Added CLI option `--base-luaurc=PATH` for both LSP and Analyze mode to provide a path to a `.luaurc` file which is used as the default configuration
31+
- Added support for Go To Definition / Type Definition on imported type references `module.Type` (gated behind FFlag `SupportTypeAliasGoToDeclaration`)
3132

3233
### Changed
3334

src/LuauExt.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,22 @@ std::optional<Luau::Property> lookupProp(const Luau::TypeId& parentType, const L
746746
return std::nullopt;
747747
}
748748

749+
std::optional<Luau::ModuleName> lookupImportedModule(const Luau::Scope& deepScope, const Luau::Name& name)
750+
{
751+
const Luau::Scope* scope = &deepScope;
752+
while (true)
753+
{
754+
auto it = scope->importedModules.find(name);
755+
if (it != scope->importedModules.end())
756+
return it->second;
757+
758+
if (scope->parent)
759+
scope = scope->parent.get();
760+
else
761+
return std::nullopt;
762+
}
763+
}
764+
749765
bool types::isMetamethod(const Luau::Name& name)
750766
{
751767
return name == "__index" || name == "__newindex" || name == "__call" || name == "__concat" || name == "__unm" || name == "__add" ||

src/include/LSP/LuauExt.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ std::optional<Luau::Location> getLocation(Luau::TypeId type);
119119

120120
std::optional<Luau::Location> lookupTypeLocation(const Luau::Scope& deepScope, const Luau::Name& name);
121121
std::optional<Luau::Property> lookupProp(const Luau::TypeId& parentType, const Luau::Name& name);
122+
std::optional<Luau::ModuleName> lookupImportedModule(const Luau::Scope& deepScope, const Luau::Name& name);
122123

123124
// Converts a UTF-8 position to a UTF-16 position, using the provided text document if available
124125
// NOTE: if the text document doesn't exist, we perform no conversion, so the positioning may be

src/operations/GotoDefinition.cpp

Lines changed: 60 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
#include "Luau/AstQuery.h"
55
#include "LSP/LuauExt.hpp"
66

7+
LUAU_FASTFLAG(SupportTypeAliasGoToDeclaration)
8+
79
lsp::DefinitionResult WorkspaceFolder::gotoDefinition(const lsp::DefinitionParams& params)
810
{
911
lsp::DefinitionResult result;
@@ -114,20 +116,65 @@ lsp::DefinitionResult WorkspaceFolder::gotoDefinition(const lsp::DefinitionParam
114116
}
115117
else if (auto reference = node->as<Luau::AstTypeReference>())
116118
{
119+
auto uri = params.textDocument.uri;
120+
auto referenceTextDocument = textDocument;
121+
bool tempDocument = false; // NOTE: need to be EXTREMELY CAREFUL on deleting the ptr
122+
117123
auto scope = Luau::findScopeAtPosition(*module, position);
118124
if (!scope)
119125
return result;
120126

121-
// TODO: we currently can't handle if its imported from a module
122127
if (reference->prefix)
123-
return result;
128+
{
129+
if (FFlag::SupportTypeAliasGoToDeclaration)
130+
{
131+
if (auto importedName = lookupImportedModule(*scope, reference->prefix.value().value))
132+
{
133+
auto fileName = fileResolver.resolveToRealPath(*importedName);
134+
if (!fileName)
135+
return result;
136+
uri = Uri::file(*fileName);
137+
138+
// TODO: fix "forAutocomplete"
139+
if (auto importedModule = frontend.moduleResolverForAutocomplete.getModule(*importedName);
140+
importedModule && importedModule->hasModuleScope())
141+
scope = importedModule->getModuleScope();
142+
else
143+
return result;
144+
145+
referenceTextDocument = fileResolver.getTextDocument(*importedName);
146+
if (!referenceTextDocument)
147+
{
148+
// Open a temporary text document so we can perform operations on it
149+
if (auto source = fileResolver.readSource(*importedName))
150+
{
151+
tempDocument = true;
152+
referenceTextDocument = new TextDocument{uri, "luau", 0, source->source};
153+
}
154+
else
155+
return result;
156+
}
157+
}
158+
else
159+
return result;
160+
}
161+
else
162+
return result;
163+
}
124164

125165
auto location = lookupTypeLocation(*scope, reference->name.value);
126166
if (!location)
167+
{
168+
if (tempDocument)
169+
delete referenceTextDocument;
127170
return result;
171+
}
128172

129173
result.emplace_back(lsp::Location{
130-
params.textDocument.uri, lsp::Range{textDocument->convertPosition(location->begin), textDocument->convertPosition(location->end)}});
174+
uri, lsp::Range{referenceTextDocument->convertPosition(location->begin), referenceTextDocument->convertPosition(location->end)}});
175+
176+
if (tempDocument)
177+
delete referenceTextDocument;
131178
}
132179

133180
return result;
@@ -162,7 +209,7 @@ std::optional<lsp::Location> WorkspaceFolder::gotoTypeDefinition(const lsp::Type
162209
if (!node)
163210
return std::nullopt;
164211

165-
auto findTypeLocation = [textDocument, &module, &position, &params](Luau::AstType* type) -> std::optional<lsp::Location>
212+
auto findTypeLocation = [this, textDocument, &module, &position, &params](Luau::AstType* type) -> std::optional<lsp::Location>
166213
{
167214
// TODO: should we only handle references here? what if its an actual type
168215
if (auto reference = type->as<Luau::AstTypeReference>())
@@ -173,7 +220,16 @@ std::optional<lsp::Location> WorkspaceFolder::gotoTypeDefinition(const lsp::Type
173220

174221
// TODO: we currently can't handle if its imported from a module
175222
if (reference->prefix)
223+
{
224+
if (FFlag::SupportTypeAliasGoToDeclaration)
225+
if (auto importedName = scope->importedModules.find(reference->prefix.value().value);
226+
importedName != scope->importedModules.end())
227+
// TODO: fix "forAutocomplete"
228+
if (auto importedModule = frontend.moduleResolverForAutocomplete.getModule(importedName->second);
229+
importedModule && importedModule->hasModuleScope())
230+
scope = importedModule->getModuleScope();
176231
return std::nullopt;
232+
}
177233

178234
auto location = lookupTypeLocation(*scope, reference->name.value);
179235
if (!location)

0 commit comments

Comments
 (0)