Merge branch 'master' into merge

This commit is contained in:
Arseny Kapoulkine 2022-05-19 16:47:10 -07:00
commit 8c52852592
5 changed files with 117 additions and 4 deletions

View File

@ -28,6 +28,7 @@ struct ToStringOptions
bool functionTypeArguments = false; // If true, output function type argument names when they are available
bool hideTableKind = false; // If true, all tables will be surrounded with plain '{}'
bool hideNamedFunctionTypeParameters = false; // If true, type parameters of functions will be hidden at top-level.
bool hideFunctionSelfArgument = false; // If true, `self: X` will be omitted from the function signature if the function has self
bool indent = false;
size_t maxTableLength = size_t(FInt::LuauTableTypeMaximumStringifierLength); // Only applied to TableTypeVars
size_t maxTypeLength = size_t(FInt::LuauTypeMaximumStringifierLength);

View File

@ -71,9 +71,11 @@ struct FindFullAncestry final : public AstVisitor
{
std::vector<AstNode*> nodes;
Position pos;
Position documentEnd;
explicit FindFullAncestry(Position pos)
explicit FindFullAncestry(Position pos, Position documentEnd)
: pos(pos)
, documentEnd(documentEnd)
{
}
@ -84,6 +86,16 @@ struct FindFullAncestry final : public AstVisitor
nodes.push_back(node);
return true;
}
// Edge case: If we ask for the node at the position that is the very end of the document
// return the innermost AST element that ends at that position.
if (node->location.end == documentEnd && pos >= documentEnd)
{
nodes.push_back(node);
return true;
}
return false;
}
};
@ -92,7 +104,11 @@ struct FindFullAncestry final : public AstVisitor
std::vector<AstNode*> findAstAncestryOfPosition(const SourceModule& source, Position pos)
{
FindFullAncestry finder(pos);
const Position end = source.root->location.end;
if (pos > end)
pos = end;
FindFullAncestry finder(pos, end);
source.root->visit(&finder);
return std::move(finder.nodes);
}

View File

@ -745,7 +745,10 @@ struct TypeVarStringifier
for (std::string& ss : results)
{
if (!first)
state.emit(" | ");
{
state.newline();
state.emit("| ");
}
state.emit(ss);
first = false;
}
@ -798,7 +801,10 @@ struct TypeVarStringifier
for (std::string& ss : results)
{
if (!first)
state.emit(" & ");
{
state.newline();
state.emit("& ");
}
state.emit(ss);
first = false;
}
@ -1230,6 +1236,14 @@ std::string toStringNamedFunction(const std::string& funcName, const FunctionTyp
size_t idx = 0;
while (argPackIter != end(ftv.argTypes))
{
// ftv takes a self parameter as the first argument, skip it if specified in option
if (idx == 0 && ftv.hasSelf && opts.hideFunctionSelfArgument)
{
++argPackIter;
++idx;
continue;
}
if (!first)
state.emit(", ");
first = false;

View File

@ -92,4 +92,17 @@ bar(foo())
CHECK_EQ("number", toString(*expectedOty));
}
TEST_CASE_FIXTURE(Fixture, "ast_ancestry_at_eof")
{
check(R"(
if true then
)");
std::vector<AstNode*> ancestry = findAstAncestryOfPosition(*getMainSourceModule(), Position(2, 4));
REQUIRE_GE(ancestry.size(), 2);
AstStat* parentStat = ancestry[ancestry.size() - 2]->asStat();
REQUIRE(bool(parentStat));
REQUIRE(parentStat->is<AstStatIf>());
}
TEST_SUITE_END();

View File

@ -126,6 +126,39 @@ TEST_CASE_FIXTURE(Fixture, "functions_are_always_parenthesized_in_unions_or_inte
CHECK_EQ(toString(&itv), "((number, string) -> (string, number)) & ((string, number) -> (number, string))");
}
TEST_CASE_FIXTURE(Fixture, "intersections_respects_use_line_breaks")
{
CheckResult result = check(R"(
local a: ((string) -> string) & ((number) -> number)
)");
ToStringOptions opts;
opts.useLineBreaks = true;
//clang-format off
CHECK_EQ("((number) -> number)\n"
"& ((string) -> string)",
toString(requireType("a"), opts));
//clang-format on
}
TEST_CASE_FIXTURE(Fixture, "unions_respects_use_line_breaks")
{
CheckResult result = check(R"(
local a: string | number | boolean
)");
ToStringOptions opts;
opts.useLineBreaks = true;
//clang-format off
CHECK_EQ("boolean\n"
"| number\n"
"| string",
toString(requireType("a"), opts));
//clang-format on
}
TEST_CASE_FIXTURE(Fixture, "quit_stringifying_table_type_when_length_is_exceeded")
{
TableTypeVar ttv{};
@ -617,4 +650,40 @@ TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_overrides_param_names")
CHECK_EQ("test<a>(first: a, second: string, ...: number): a", toStringNamedFunction("test", *ftv, opts));
}
TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_include_self_param")
{
ScopedFastFlag flag{"LuauDocFuncParameters", true};
CheckResult result = check(R"(
local foo = {}
function foo:method(arg: string): ()
end
)");
TypeId parentTy = requireType("foo");
auto ttv = get<TableTypeVar>(follow(parentTy));
auto ftv = get<FunctionTypeVar>(ttv->props.at("method").type);
CHECK_EQ("foo:method<a>(self: a, arg: string): ()", toStringNamedFunction("foo:method", *ftv));
}
TEST_CASE_FIXTURE(Fixture, "toStringNamedFunction_hide_self_param")
{
ScopedFastFlag flag{"LuauDocFuncParameters", true};
CheckResult result = check(R"(
local foo = {}
function foo:method(arg: string): ()
end
)");
TypeId parentTy = requireType("foo");
auto ttv = get<TableTypeVar>(follow(parentTy));
auto ftv = get<FunctionTypeVar>(ttv->props.at("method").type);
ToStringOptions opts;
opts.hideFunctionSelfArgument = true;
CHECK_EQ("foo:method<a>(arg: string): ()", toStringNamedFunction("foo:method", *ftv, opts));
}
TEST_SUITE_END();