Skip to content

Commit a005567

Browse files
authored
Attach documentation comments to type alias definitions (#956)
1 parent 0effc1f commit a005567

File tree

5 files changed

+130
-0
lines changed

5 files changed

+130
-0
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
66

77
## [Unreleased]
88

9+
### Added
10+
11+
- Documentation comments now attach to type alias definitions ([#956](https://github.com/JohnnyMorganz/luau-lsp/pull/956))
12+
913
### Changed
1014

1115
- Sync to upstream Luau 0.664

src/DocumentationParser.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,3 +469,35 @@ std::optional<std::string> WorkspaceFolder::getDocumentationForType(const Luau::
469469
}
470470
return std::nullopt;
471471
}
472+
473+
std::optional<std::string> WorkspaceFolder::getDocumentationForAstNode(const Luau::ModuleName& moduleName, const Luau::AstNode* node, const Luau::ScopePtr scope)
474+
{
475+
if (auto ref = node->as<Luau::AstTypeReference>())
476+
{
477+
if (ref->prefix)
478+
{
479+
auto importedModuleName = lookupImportedModule(*scope, ref->prefix->value);
480+
if (!importedModuleName)
481+
return std::nullopt;
482+
auto importedModule = getModule(*importedModuleName);
483+
if (!importedModule)
484+
return std::nullopt;
485+
auto typeLocation = lookupTypeLocation(*importedModule->getModuleScope(), ref->name.value);
486+
if (!typeLocation)
487+
return std::nullopt;
488+
return printMoonwaveDocumentation(getComments(*importedModuleName, *typeLocation));
489+
}
490+
else
491+
{
492+
auto typeLocation = lookupTypeLocation(*scope, ref->name.value);
493+
if (!typeLocation)
494+
return std::nullopt;
495+
return printMoonwaveDocumentation(getComments(moduleName, *typeLocation));
496+
}
497+
}
498+
else if (auto alias = node->as<Luau::AstStatTypeAlias>())
499+
{
500+
return printMoonwaveDocumentation(getComments(moduleName, alias->location));
501+
}
502+
return std::nullopt;
503+
}

src/include/LSP/Workspace.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ class WorkspaceFolder
9595
public:
9696
std::vector<std::string> getComments(const Luau::ModuleName& moduleName, const Luau::Location& node);
9797
std::optional<std::string> getDocumentationForType(const Luau::TypeId ty);
98+
std::optional<std::string> getDocumentationForAstNode(const Luau::ModuleName& moduleName, const Luau::AstNode* node, const Luau::ScopePtr scope);
9899
std::optional<std::string> getDocumentationForAutocompleteEntry(const std::string& name, const Luau::AutocompleteEntry& entry,
99100
const std::vector<Luau::AstNode*>& ancestry, const Luau::ModulePtr& localModule);
100101
std::vector<Reference> findAllTableReferences(const Luau::TypeId ty, std::optional<Luau::Name> property = std::nullopt);

src/operations/Hover.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,11 @@ std::optional<lsp::Hover> WorkspaceFolder::hover(const lsp::HoverParams& params)
350350
typeString += kDocumentationBreaker;
351351
typeString += *documentation;
352352
}
353+
else if (auto documentation = getDocumentationForAstNode(moduleName, node, scope); documentation && !documentation->empty())
354+
{
355+
typeString += kDocumentationBreaker;
356+
typeString += *documentation;
357+
}
353358
else if (documentationLocation)
354359
{
355360
if (auto text = printMoonwaveDocumentation(getComments(documentationLocation->moduleName, documentationLocation->location)); !text.empty())

tests/Hover.test.cpp

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,4 +307,92 @@ TEST_CASE_FIXTURE(Fixture, "includes_documentation_for_a_function_call")
307307
CHECK_EQ(result->contents.value, codeBlock("luau", "function foo(): ()") + kDocumentationBreaker + "This is documentation for Foo\n");
308308
}
309309

310+
TEST_CASE_FIXTURE(Fixture, "includes_documentation_for_type_alias_declarations")
311+
{
312+
auto source = R"(
313+
--- The metre (or meter in [US spelling]; symbol: m) is the [base unit] of [length]
314+
--- in the [International System of Units] (SI)
315+
export type Meters = number
316+
)";
317+
318+
auto uri = newDocument("meters.luau", source);
319+
320+
lsp::HoverParams params;
321+
params.textDocument = lsp::TextDocumentIdentifier{uri};
322+
params.position = lsp::Position{3, 21};
323+
324+
auto result = workspace.hover(params);
325+
REQUIRE(result);
326+
CHECK_EQ(
327+
result->contents.value,
328+
codeBlock("luau", "type Meters = number") +
329+
kDocumentationBreaker +
330+
"The metre (or meter in [US spelling]; symbol: m) is the [base unit] of [length]\n" +
331+
"in the [International System of Units] (SI)\n"
332+
);
333+
}
334+
335+
TEST_CASE_FIXTURE(Fixture, "includes_documentation_for_type_alias_declarations_of_intersected_tables")
336+
{
337+
auto source = R"(
338+
type Foo = {
339+
foo: "Foo",
340+
}
341+
342+
type Bar = {
343+
bar: "Bar",
344+
}
345+
346+
--- The terms foobar (/ˈfuːbɑːr/), foo, bar, baz, qux, quux, and others are used as
347+
--- metasyntactic variables and placeholder names in computer programming or computer-related documentation
348+
export type Foobar = Foo & Bar
349+
)";
350+
351+
auto uri = newDocument("meters.luau", source);
352+
353+
lsp::HoverParams params;
354+
params.textDocument = lsp::TextDocumentIdentifier{uri};
355+
params.position = lsp::Position{11, 21};
356+
357+
auto result = workspace.hover(params);
358+
REQUIRE(result);
359+
CHECK_EQ(
360+
result->contents.value,
361+
codeBlock("luau", "type Foobar = {\n bar: \"Bar\"\n} & {\n foo: \"Foo\"\n}") +
362+
kDocumentationBreaker +
363+
"The terms foobar (/ˈfuːbɑːr/), foo, bar, baz, qux, quux, and others are used as\n" +
364+
"metasyntactic variables and placeholder names in computer programming or computer-related documentation\n"
365+
);
366+
}
367+
368+
TEST_CASE_FIXTURE(Fixture, "includes_documentation_for_type_references")
369+
{
370+
auto source = R"(
371+
type Foo = {
372+
foo: "Foo",
373+
}
374+
375+
type Bar = {
376+
bar: "Bar",
377+
}
378+
379+
--- This is the intersection of two types
380+
export type Foobar = Foo & Bar
381+
382+
function consumer(value: Foobar)
383+
end
384+
)";
385+
386+
auto uri = newDocument("meters.luau", source);
387+
388+
lsp::HoverParams params;
389+
params.textDocument = lsp::TextDocumentIdentifier{uri};
390+
params.position = lsp::Position{12, 36};
391+
392+
auto result = workspace.hover(params);
393+
REQUIRE(result);
394+
CHECK_EQ(result->contents.value, codeBlock("luau", "type Foobar = {\n bar: \"Bar\"\n} & {\n foo: \"Foo\"\n}") + kDocumentationBreaker +
395+
"This is the intersection of two types\n");
396+
}
397+
310398
TEST_SUITE_END();

0 commit comments

Comments
 (0)