Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Roblox
GitHub Repository: Roblox/luau
Path: blob/master/tests/Autocomplete.test.cpp
2723 views
1
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
2
#include "Luau/Autocomplete.h"
3
#include "Luau/AutocompleteTypes.h"
4
#include "Luau/BuiltinDefinitions.h"
5
#include "Luau/Common.h"
6
#include "Luau/Type.h"
7
#include "Luau/StringUtils.h"
8
9
10
#include "ClassFixture.h"
11
#include "Fixture.h"
12
#include "ScopedFlags.h"
13
14
#include "doctest.h"
15
16
#include <map>
17
18
LUAU_DYNAMIC_FASTINT(LuauSubtypingRecursionLimit)
19
20
LUAU_FASTFLAG(LuauTraceTypesInNonstrictMode2)
21
LUAU_FASTFLAG(LuauSetMetatableDoesNotTimeTravel)
22
LUAU_FASTINT(LuauTypeInferRecursionLimit)
23
LUAU_FASTFLAG(LuauAutocompleteFunctionCallArgTails2)
24
LUAU_FASTFLAG(LuauACOnMTTWriteOnlyPropNoCrash)
25
LUAU_FASTFLAG(LuauReplacerRespectsReboundGenerics)
26
LUAU_FASTFLAG(LuauOverloadGetsInstantiated)
27
28
using namespace Luau;
29
30
static std::optional<AutocompleteEntryMap> nullCallback(std::string tag, std::optional<const ExternType*> ptr, std::optional<std::string> contents)
31
{
32
return std::nullopt;
33
}
34
35
template<class BaseType>
36
struct ACFixtureImpl : BaseType
37
{
38
ACFixtureImpl()
39
: BaseType(true)
40
{
41
}
42
43
AutocompleteResult autocomplete(unsigned row, unsigned column)
44
{
45
FrontendOptions opts;
46
opts.forAutocomplete = true;
47
opts.retainFullTypeGraphs = true;
48
// NOTE: Autocomplete does *not* require strict checking, meaning we should
49
// try to check all of these examples in `--!nocheck` mode.
50
this->configResolver.defaultConfig.mode = Mode::NoCheck;
51
this->getFrontend().check("MainModule", opts);
52
53
return Luau::autocomplete(this->getFrontend(), "MainModule", Position{row, column}, nullCallback);
54
}
55
56
AutocompleteResult autocomplete(char marker, StringCompletionCallback callback = nullCallback)
57
{
58
FrontendOptions opts;
59
opts.forAutocomplete = true;
60
opts.retainFullTypeGraphs = true;
61
// NOTE: Autocomplete does *not* require strict checking, meaning we should
62
// try to check all of these examples in `--!nocheck` mode.
63
this->configResolver.defaultConfig.mode = Mode::NoCheck;
64
this->getFrontend().check("MainModule", opts);
65
66
return Luau::autocomplete(this->getFrontend(), "MainModule", getPosition(marker), callback);
67
}
68
69
AutocompleteResult autocomplete(const ModuleName& name, Position pos, StringCompletionCallback callback = nullCallback)
70
{
71
FrontendOptions opts;
72
opts.forAutocomplete = true;
73
opts.retainFullTypeGraphs = true;
74
// NOTE: Autocomplete does *not* require strict checking, meaning we should
75
// try to check all of these examples in `--!nocheck` mode.
76
this->configResolver.defaultConfig.mode = Mode::NoCheck;
77
this->getFrontend().check(name, opts);
78
79
return Luau::autocomplete(this->getFrontend(), name, pos, callback);
80
}
81
82
CheckResult check(const std::string& source)
83
{
84
this->getFrontend();
85
markerPosition.clear();
86
std::string filteredSource;
87
filteredSource.reserve(source.size());
88
89
Position curPos(0, 0);
90
char prevChar{};
91
for (char c : source)
92
{
93
if (prevChar == '@')
94
{
95
LUAU_ASSERT("Illegal marker character" && ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z')));
96
LUAU_ASSERT("Duplicate marker found" && markerPosition.count(c) == 0);
97
markerPosition.insert(std::pair{c, curPos});
98
}
99
else if (c == '@')
100
{
101
// skip the '@' character
102
if (prevChar == '\\')
103
{
104
// escaped @, prevent prevChar to be equal to '@' on next loop
105
c = '\0';
106
// replace escaping '\' with '@'
107
filteredSource.back() = '@';
108
}
109
}
110
else
111
{
112
filteredSource.push_back(c);
113
if (c == '\n')
114
{
115
curPos.line++;
116
curPos.column = 0;
117
}
118
else
119
{
120
curPos.column++;
121
}
122
}
123
prevChar = c;
124
}
125
LUAU_ASSERT("Digit expected after @ symbol" && prevChar != '@');
126
127
// NOTE: Autocomplete does *not* require strict checking, meaning we should
128
// try to check all of these examples in `--!nocheck` mode.
129
return BaseType::check(Mode::NoCheck, filteredSource, std::nullopt);
130
}
131
132
LoadDefinitionFileResult loadDefinition(const std::string& source)
133
{
134
GlobalTypes& globals = this->getFrontend().globalsForAutocomplete;
135
unfreeze(globals.globalTypes);
136
LoadDefinitionFileResult result = this->getFrontend().loadDefinitionFile(
137
globals, globals.globalScope, source, "@test", /* captureComments */ false, /* typeCheckForAutocomplete */ true
138
);
139
freeze(globals.globalTypes);
140
141
if (!FFlag::DebugLuauForceOldSolver)
142
{
143
GlobalTypes& globals = this->getFrontend().globals;
144
unfreeze(globals.globalTypes);
145
LoadDefinitionFileResult result = this->getFrontend().loadDefinitionFile(
146
globals, globals.globalScope, source, "@test", /* captureComments */ false, /* typeCheckForAutocomplete */ true
147
);
148
freeze(globals.globalTypes);
149
}
150
151
REQUIRE_MESSAGE(result.success, "loadDefinition: unable to load definition file");
152
return result;
153
}
154
155
const Position& getPosition(char marker) const
156
{
157
auto i = markerPosition.find(marker);
158
LUAU_ASSERT(i != markerPosition.end());
159
return i->second;
160
}
161
// Maps a marker character (0-9 inclusive) to a position in the source code.
162
std::map<char, Position> markerPosition;
163
};
164
165
struct ACFixture : ACFixtureImpl<Fixture>
166
{
167
ACFixture()
168
: ACFixtureImpl<Fixture>()
169
{
170
}
171
172
Frontend& getFrontend() override
173
{
174
if (frontend)
175
return *frontend;
176
177
Frontend& f = Fixture::getFrontend();
178
// TODO - move this into its own consructor
179
addGlobalBinding(f.globals, "table", Binding{getBuiltins()->anyType});
180
addGlobalBinding(f.globals, "math", Binding{getBuiltins()->anyType});
181
addGlobalBinding(f.globalsForAutocomplete, "table", Binding{getBuiltins()->anyType});
182
addGlobalBinding(f.globalsForAutocomplete, "math", Binding{getBuiltins()->anyType});
183
return *frontend;
184
}
185
};
186
187
struct ACBuiltinsFixture : ACFixtureImpl<BuiltinsFixture>
188
{
189
};
190
191
struct ACExternTypeFixture : ACFixtureImpl<ExternTypeFixture>
192
{
193
};
194
195
TEST_SUITE_BEGIN("AutocompleteTest");
196
197
TEST_CASE_FIXTURE(ACFixture, "empty_program")
198
{
199
check(" @1");
200
201
auto ac = autocomplete('1');
202
203
CHECK(!ac.entryMap.empty());
204
CHECK(ac.entryMap.count("table"));
205
CHECK(ac.entryMap.count("math"));
206
CHECK_EQ(ac.context, AutocompleteContext::Statement);
207
}
208
209
TEST_CASE_FIXTURE(ACFixture, "local_initializer")
210
{
211
check("local a = @1");
212
213
auto ac = autocomplete('1');
214
CHECK(ac.entryMap.count("table"));
215
CHECK(ac.entryMap.count("math"));
216
CHECK_EQ(ac.context, AutocompleteContext::Expression);
217
}
218
219
TEST_CASE_FIXTURE(ACFixture, "leave_numbers_alone")
220
{
221
check("local a = 3.@11");
222
223
auto ac = autocomplete('1');
224
CHECK(ac.entryMap.empty());
225
CHECK_EQ(ac.context, AutocompleteContext::Unknown);
226
}
227
228
TEST_CASE_FIXTURE(ACFixture, "user_defined_globals")
229
{
230
check("local myLocal = 4; @1");
231
232
auto ac = autocomplete('1');
233
234
CHECK(ac.entryMap.count("myLocal"));
235
CHECK(ac.entryMap.count("table"));
236
CHECK(ac.entryMap.count("math"));
237
CHECK_EQ(ac.context, AutocompleteContext::Statement);
238
}
239
240
TEST_CASE_FIXTURE(ACFixture, "dont_suggest_local_before_its_definition")
241
{
242
check(R"(
243
local myLocal = 4
244
function abc()
245
@1 local myInnerLocal = 1
246
@2
247
end
248
@3 )");
249
250
auto ac = autocomplete('1');
251
CHECK(ac.entryMap.count("myLocal"));
252
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "myInnerLocal");
253
254
ac = autocomplete('2');
255
CHECK(ac.entryMap.count("myLocal"));
256
CHECK(ac.entryMap.count("myInnerLocal"));
257
258
ac = autocomplete('3');
259
CHECK(ac.entryMap.count("myLocal"));
260
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "myInnerLocal");
261
}
262
263
TEST_CASE_FIXTURE(ACFixture, "recursive_function")
264
{
265
check(R"(
266
function foo()
267
@1 end
268
)");
269
270
auto ac = autocomplete('1');
271
CHECK(ac.entryMap.count("foo"));
272
CHECK_EQ(ac.context, AutocompleteContext::Statement);
273
}
274
275
TEST_CASE_FIXTURE(ACFixture, "nested_recursive_function")
276
{
277
check(R"(
278
local function outer()
279
local function inner()
280
@1 end
281
end
282
)");
283
284
auto ac = autocomplete('1');
285
CHECK(ac.entryMap.count("inner"));
286
CHECK(ac.entryMap.count("outer"));
287
}
288
289
TEST_CASE_FIXTURE(ACFixture, "user_defined_local_functions_in_own_definition")
290
{
291
check(R"(
292
local function abc()
293
@1
294
end
295
)");
296
297
auto ac = autocomplete('1');
298
299
CHECK(ac.entryMap.count("abc"));
300
CHECK(ac.entryMap.count("table"));
301
CHECK(ac.entryMap.count("math"));
302
303
check(R"(
304
local abc = function()
305
@1
306
end
307
)");
308
309
ac = autocomplete('1');
310
311
CHECK(ac.entryMap.count("abc")); // FIXME: This is actually incorrect!
312
CHECK(ac.entryMap.count("table"));
313
CHECK(ac.entryMap.count("math"));
314
}
315
316
TEST_CASE_FIXTURE(ACFixture, "global_functions_are_not_scoped_lexically")
317
{
318
check(R"(
319
if true then
320
function abc()
321
322
end
323
end
324
@1 )");
325
326
auto ac = autocomplete('1');
327
328
CHECK(!ac.entryMap.empty());
329
CHECK(ac.entryMap.count("abc"));
330
CHECK(ac.entryMap.count("table"));
331
CHECK(ac.entryMap.count("math"));
332
}
333
334
TEST_CASE_FIXTURE(ACFixture, "local_functions_fall_out_of_scope")
335
{
336
check(R"(
337
if true then
338
local function abc()
339
340
end
341
end
342
@1 )");
343
344
auto ac = autocomplete('1');
345
346
CHECK_NE(0, ac.entryMap.size());
347
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "abc");
348
}
349
350
TEST_CASE_FIXTURE(ACFixture, "function_parameters")
351
{
352
check(R"(
353
function abc(test)
354
355
@1 end
356
)");
357
358
auto ac = autocomplete('1');
359
360
CHECK(ac.entryMap.count("test"));
361
}
362
363
TEST_CASE_FIXTURE(ACBuiltinsFixture, "get_member_completions")
364
{
365
check(R"(
366
local a = table.@1
367
)");
368
369
auto ac = autocomplete('1');
370
371
CHECK_EQ(17, ac.entryMap.size());
372
CHECK(ac.entryMap.count("find"));
373
CHECK(ac.entryMap.count("pack"));
374
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "math");
375
CHECK_EQ(ac.context, AutocompleteContext::Property);
376
}
377
378
TEST_CASE_FIXTURE(ACFixture, "nested_member_completions")
379
{
380
check(R"(
381
local tbl = { abc = { def = 1234, egh = false } }
382
tbl.abc. @1
383
)");
384
385
auto ac = autocomplete('1');
386
CHECK_EQ(2, ac.entryMap.size());
387
CHECK(ac.entryMap.count("def"));
388
CHECK(ac.entryMap.count("egh"));
389
CHECK_EQ(ac.context, AutocompleteContext::Property);
390
}
391
392
TEST_CASE_FIXTURE(ACFixture, "unsealed_table")
393
{
394
check(R"(
395
local tbl = {}
396
tbl.prop = 5
397
tbl.@1
398
)");
399
400
auto ac = autocomplete('1');
401
CHECK_EQ(1, ac.entryMap.size());
402
CHECK(ac.entryMap.count("prop"));
403
CHECK_EQ(ac.context, AutocompleteContext::Property);
404
}
405
406
TEST_CASE_FIXTURE(ACFixture, "unsealed_table_2")
407
{
408
check(R"(
409
local tbl = {}
410
local inner = { prop = 5 }
411
tbl.inner = inner
412
tbl.inner. @1
413
)");
414
415
auto ac = autocomplete('1');
416
CHECK_EQ(1, ac.entryMap.size());
417
CHECK(ac.entryMap.count("prop"));
418
CHECK_EQ(ac.context, AutocompleteContext::Property);
419
}
420
421
TEST_CASE_FIXTURE(ACFixture, "cyclic_table")
422
{
423
check(R"(
424
local abc = {}
425
local def = { abc = abc }
426
abc.def = def
427
abc.def. @1
428
)");
429
430
auto ac = autocomplete('1');
431
CHECK(ac.entryMap.count("abc"));
432
CHECK_EQ(ac.context, AutocompleteContext::Property);
433
}
434
435
TEST_CASE_FIXTURE(ACFixture, "table_union")
436
{
437
check(R"(
438
type t1 = { a1 : string, b2 : number }
439
type t2 = { b2 : string, c3 : string }
440
function func(abc : t1 | t2)
441
abc. @1
442
end
443
)");
444
445
auto ac = autocomplete('1');
446
CHECK_EQ(1, ac.entryMap.size());
447
CHECK(ac.entryMap.count("b2"));
448
CHECK_EQ(ac.context, AutocompleteContext::Property);
449
}
450
451
TEST_CASE_FIXTURE(ACFixture, "table_intersection")
452
{
453
check(R"(
454
type t1 = { a1 : string, b2 : number }
455
type t2 = { b2 : number, c3 : string }
456
function func(abc : t1 & t2)
457
abc. @1
458
end
459
)");
460
461
auto ac = autocomplete('1');
462
CHECK_EQ(3, ac.entryMap.size());
463
CHECK(ac.entryMap.count("a1"));
464
CHECK(ac.entryMap.count("b2"));
465
CHECK(ac.entryMap.count("c3"));
466
CHECK_EQ(ac.context, AutocompleteContext::Property);
467
}
468
469
TEST_CASE_FIXTURE(ACBuiltinsFixture, "get_string_completions")
470
{
471
check(R"(
472
local a = ("foo"):@1
473
)");
474
475
auto ac = autocomplete('1');
476
477
CHECK_EQ(17, ac.entryMap.size());
478
CHECK_EQ(ac.context, AutocompleteContext::Property);
479
}
480
481
TEST_CASE_FIXTURE(ACFixture, "get_suggestions_for_new_statement")
482
{
483
check("@1");
484
485
auto ac = autocomplete('1');
486
487
CHECK_NE(0, ac.entryMap.size());
488
489
CHECK(ac.entryMap.count("table"));
490
CHECK_EQ(ac.context, AutocompleteContext::Statement);
491
}
492
493
TEST_CASE_FIXTURE(ACFixture, "get_suggestions_for_the_very_start_of_the_script")
494
{
495
check(R"(@1
496
497
function aaa() end
498
)");
499
500
auto ac = autocomplete('1');
501
502
CHECK(ac.entryMap.count("table"));
503
CHECK_EQ(ac.context, AutocompleteContext::Statement);
504
}
505
506
TEST_CASE_FIXTURE(ACFixture, "method_call_inside_function_body")
507
{
508
check(R"(
509
local game = { GetService=function(s) return 'hello' end }
510
511
function a()
512
game: @1
513
end
514
)");
515
516
auto ac = autocomplete('1');
517
518
CHECK_NE(0, ac.entryMap.size());
519
520
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "math");
521
CHECK_EQ(ac.context, AutocompleteContext::Property);
522
}
523
524
TEST_CASE_FIXTURE(ACBuiltinsFixture, "method_call_inside_if_conditional")
525
{
526
check(R"(
527
if table: @1
528
)");
529
530
auto ac = autocomplete('1');
531
532
CHECK_NE(0, ac.entryMap.size());
533
CHECK(ac.entryMap.count("concat"));
534
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "math");
535
CHECK_EQ(ac.context, AutocompleteContext::Property);
536
}
537
538
TEST_CASE_FIXTURE(ACFixture, "statement_between_two_statements")
539
{
540
check(R"(
541
function getmyscripts() end
542
543
g@1
544
545
getmyscripts()
546
)");
547
548
auto ac = autocomplete('1');
549
550
CHECK_NE(0, ac.entryMap.size());
551
552
CHECK(ac.entryMap.count("getmyscripts"));
553
554
CHECK_EQ(ac.context, AutocompleteContext::Statement);
555
}
556
557
TEST_CASE_FIXTURE(ACFixture, "bias_toward_inner_scope")
558
{
559
check(R"(
560
local A = {one=1}
561
562
function B()
563
local A = {two=2}
564
565
A @1
566
end
567
)");
568
569
auto ac = autocomplete('1');
570
571
CHECK(ac.entryMap.count("A"));
572
CHECK_EQ(ac.context, AutocompleteContext::Statement);
573
574
TypeId t = follow(*ac.entryMap["A"].type);
575
const TableType* tt = get<TableType>(t);
576
REQUIRE(tt);
577
578
CHECK(tt->props.count("two"));
579
}
580
581
TEST_CASE_FIXTURE(ACFixture, "recommend_statement_starting_keywords")
582
{
583
check("@1");
584
auto ac = autocomplete('1');
585
CHECK(ac.entryMap.count("local"));
586
CHECK_EQ(ac.context, AutocompleteContext::Statement);
587
588
check("local i = @1");
589
auto ac2 = autocomplete('1');
590
CHECK(!ac2.entryMap.count("local"));
591
CHECK_EQ(ac2.context, AutocompleteContext::Expression);
592
}
593
594
TEST_CASE_FIXTURE(ACFixture, "do_not_overwrite_context_sensitive_kws")
595
{
596
check(R"(
597
local function continue()
598
end
599
600
601
@1 )");
602
603
auto ac = autocomplete('1');
604
605
AutocompleteEntry entry = ac.entryMap["continue"];
606
CHECK(entry.kind == AutocompleteEntryKind::Binding);
607
CHECK_EQ(ac.context, AutocompleteContext::Statement);
608
}
609
610
TEST_CASE_FIXTURE(ACFixture, "dont_offer_any_suggestions_from_within_a_comment")
611
{
612
check(R"(
613
--!strict
614
local foo = {}
615
function foo:bar() end
616
617
--[[
618
foo:@1
619
]]
620
)");
621
622
auto ac = autocomplete('1');
623
624
CHECK_EQ(0, ac.entryMap.size());
625
CHECK_EQ(ac.context, AutocompleteContext::Unknown);
626
}
627
628
TEST_CASE_FIXTURE(ACFixture, "dont_offer_any_suggestions_from_within_a_broken_comment")
629
{
630
check(R"(
631
--[[ @1
632
)");
633
634
auto ac = autocomplete('1');
635
636
CHECK_EQ(0, ac.entryMap.size());
637
CHECK_EQ(ac.context, AutocompleteContext::Unknown);
638
}
639
640
TEST_CASE_FIXTURE(ACFixture, "dont_offer_any_suggestions_from_within_a_broken_comment_at_the_very_end_of_the_file")
641
{
642
check("--[[@1");
643
644
auto ac = autocomplete('1');
645
CHECK_EQ(0, ac.entryMap.size());
646
CHECK_EQ(ac.context, AutocompleteContext::Unknown);
647
}
648
649
TEST_CASE_FIXTURE(ACFixture, "autocomplete_for_middle_keywords")
650
{
651
check(R"(
652
for x @1=
653
)");
654
655
auto ac1 = autocomplete('1');
656
CHECK_EQ(ac1.entryMap.count("do"), 0);
657
CHECK_EQ(ac1.entryMap.count("end"), 0);
658
CHECK_EQ(ac1.context, AutocompleteContext::Unknown);
659
660
check(R"(
661
for x =@1 1
662
)");
663
664
auto ac2 = autocomplete('1');
665
CHECK_EQ(ac2.entryMap.count("do"), 0);
666
CHECK_EQ(ac2.entryMap.count("end"), 0);
667
CHECK_EQ(ac2.context, AutocompleteContext::Unknown);
668
669
check(R"(
670
for x = 1,@1 2
671
)");
672
673
auto ac3 = autocomplete('1');
674
CHECK_EQ(1, ac3.entryMap.size());
675
CHECK_EQ(ac3.entryMap.count("do"), 1);
676
CHECK_EQ(ac3.context, AutocompleteContext::Keyword);
677
678
check(R"(
679
for x = 1, @12,
680
)");
681
682
auto ac4 = autocomplete('1');
683
CHECK_EQ(ac4.entryMap.count("do"), 0);
684
CHECK_EQ(ac4.entryMap.count("end"), 0);
685
CHECK_EQ(ac4.context, AutocompleteContext::Expression);
686
687
check(R"(
688
for x = 1, 2, @15
689
)");
690
691
auto ac5 = autocomplete('1');
692
CHECK_EQ(ac5.entryMap.count("math"), 1);
693
CHECK_EQ(ac5.entryMap.count("do"), 0);
694
CHECK_EQ(ac5.entryMap.count("end"), 0);
695
CHECK_EQ(ac5.context, AutocompleteContext::Expression);
696
697
check(R"(
698
for x = 1, 2, 5 f@1
699
)");
700
701
auto ac6 = autocomplete('1');
702
CHECK_EQ(ac6.entryMap.size(), 1);
703
CHECK_EQ(ac6.entryMap.count("do"), 1);
704
CHECK_EQ(ac6.context, AutocompleteContext::Keyword);
705
706
check(R"(
707
for x = 1, 2, 5 do @1
708
)");
709
710
auto ac7 = autocomplete('1');
711
CHECK_EQ(ac7.entryMap.count("end"), 1);
712
CHECK_EQ(ac7.context, AutocompleteContext::Statement);
713
714
check(R"(local Foo = 1
715
for x = @11, @22, @35
716
)");
717
718
for (int i = 0; i < 3; ++i)
719
{
720
auto ac8 = autocomplete('1' + i);
721
CHECK_EQ(ac8.entryMap.count("Foo"), 1);
722
CHECK_EQ(ac8.entryMap.count("do"), 0);
723
}
724
725
check(R"(local Foo = 1
726
for x = @11, @22
727
)");
728
729
for (int i = 0; i < 2; ++i)
730
{
731
auto ac9 = autocomplete('1' + i);
732
CHECK_EQ(ac9.entryMap.count("Foo"), 1);
733
CHECK_EQ(ac9.entryMap.count("do"), 0);
734
}
735
}
736
737
TEST_CASE_FIXTURE(ACFixture, "autocomplete_for_in_middle_keywords")
738
{
739
check(R"(
740
for @1
741
)");
742
743
auto ac1 = autocomplete('1');
744
CHECK_EQ(0, ac1.entryMap.size());
745
CHECK_EQ(ac1.context, AutocompleteContext::Unknown);
746
747
check(R"(
748
for x@1 @2
749
)");
750
751
auto ac2 = autocomplete('1');
752
CHECK_EQ(0, ac2.entryMap.size());
753
CHECK_EQ(ac2.context, AutocompleteContext::Unknown);
754
755
auto ac2a = autocomplete('2');
756
CHECK_EQ(1, ac2a.entryMap.size());
757
CHECK_EQ(1, ac2a.entryMap.count("in"));
758
CHECK_EQ(ac2a.context, AutocompleteContext::Keyword);
759
760
check(R"(
761
for x in y@1
762
)");
763
764
auto ac3 = autocomplete('1');
765
CHECK_EQ(ac3.entryMap.count("table"), 1);
766
CHECK_EQ(ac3.entryMap.count("do"), 0);
767
CHECK_EQ(ac3.context, AutocompleteContext::Expression);
768
769
check(R"(
770
for x in y @1
771
)");
772
773
auto ac4 = autocomplete('1');
774
CHECK_EQ(ac4.entryMap.size(), 1);
775
CHECK_EQ(ac4.entryMap.count("do"), 1);
776
CHECK_EQ(ac4.context, AutocompleteContext::Keyword);
777
778
check(R"(
779
for x in f f@1
780
)");
781
782
auto ac5 = autocomplete('1');
783
CHECK_EQ(ac5.entryMap.size(), 1);
784
CHECK_EQ(ac5.entryMap.count("do"), 1);
785
CHECK_EQ(ac5.context, AutocompleteContext::Keyword);
786
787
check(R"(
788
for x in y do @1
789
)");
790
791
auto ac6 = autocomplete('1');
792
CHECK_EQ(ac6.entryMap.count("in"), 0);
793
CHECK_EQ(ac6.entryMap.count("table"), 1);
794
CHECK_EQ(ac6.entryMap.count("end"), 1);
795
CHECK_EQ(ac6.entryMap.count("function"), 1);
796
CHECK_EQ(ac6.context, AutocompleteContext::Statement);
797
798
check(R"(
799
for x in y do e@1
800
)");
801
802
auto ac7 = autocomplete('1');
803
CHECK_EQ(ac7.entryMap.count("in"), 0);
804
CHECK_EQ(ac7.entryMap.count("table"), 1);
805
CHECK_EQ(ac7.entryMap.count("end"), 1);
806
CHECK_EQ(ac7.entryMap.count("function"), 1);
807
CHECK_EQ(ac7.context, AutocompleteContext::Statement);
808
}
809
810
TEST_CASE_FIXTURE(ACFixture, "autocomplete_while_middle_keywords")
811
{
812
check(R"(
813
while@1
814
)");
815
816
auto ac1 = autocomplete('1');
817
CHECK_EQ(ac1.entryMap.count("do"), 0);
818
CHECK_EQ(ac1.entryMap.count("end"), 0);
819
CHECK_EQ(ac1.context, AutocompleteContext::Expression);
820
821
check(R"(
822
while true @1
823
)");
824
825
auto ac2 = autocomplete('1');
826
CHECK_EQ(3, ac2.entryMap.size());
827
CHECK_EQ(ac2.entryMap.count("do"), 1);
828
CHECK_EQ(ac2.entryMap.count("and"), 1);
829
CHECK_EQ(ac2.entryMap.count("or"), 1);
830
CHECK_EQ(ac2.context, AutocompleteContext::Keyword);
831
832
check(R"(
833
while true do @1
834
)");
835
836
auto ac3 = autocomplete('1');
837
CHECK_EQ(ac3.entryMap.count("end"), 1);
838
CHECK_EQ(ac3.context, AutocompleteContext::Statement);
839
840
check(R"(
841
while true d@1
842
)");
843
844
auto ac4 = autocomplete('1');
845
CHECK_EQ(3, ac4.entryMap.size());
846
CHECK_EQ(ac4.entryMap.count("do"), 1);
847
CHECK_EQ(ac4.entryMap.count("and"), 1);
848
CHECK_EQ(ac4.entryMap.count("or"), 1);
849
CHECK_EQ(ac4.context, AutocompleteContext::Keyword);
850
851
check(R"(
852
while t@1
853
)");
854
855
auto ac5 = autocomplete('1');
856
CHECK_EQ(ac5.entryMap.count("do"), 0);
857
CHECK_EQ(ac5.entryMap.count("true"), 1);
858
CHECK_EQ(ac5.entryMap.count("false"), 1);
859
}
860
861
TEST_CASE_FIXTURE(ACFixture, "autocomplete_if_middle_keywords")
862
{
863
check(R"(
864
if @1
865
)");
866
867
auto ac1 = autocomplete('1');
868
CHECK_EQ(ac1.entryMap.count("then"), 0);
869
CHECK_EQ(
870
ac1.entryMap.count("function"),
871
1
872
); // FIXME: This is kind of dumb. It is technically syntactically valid but you can never do anything interesting with this.
873
CHECK_EQ(ac1.entryMap.count("table"), 1);
874
CHECK_EQ(ac1.entryMap.count("else"), 0);
875
CHECK_EQ(ac1.entryMap.count("elseif"), 0);
876
CHECK_EQ(ac1.entryMap.count("end"), 0);
877
CHECK_EQ(ac1.context, AutocompleteContext::Expression);
878
879
check(R"(
880
if x @1
881
)");
882
883
auto ac2 = autocomplete('1');
884
CHECK_EQ(ac2.entryMap.count("then"), 1);
885
CHECK_EQ(ac2.entryMap.count("function"), 0);
886
CHECK_EQ(ac2.entryMap.count("else"), 0);
887
CHECK_EQ(ac2.entryMap.count("elseif"), 0);
888
CHECK_EQ(ac2.entryMap.count("end"), 0);
889
CHECK_EQ(ac2.context, AutocompleteContext::Keyword);
890
891
check(R"(
892
if x t@1
893
)");
894
895
auto ac3 = autocomplete('1');
896
CHECK_EQ(3, ac3.entryMap.size());
897
CHECK_EQ(ac3.entryMap.count("then"), 1);
898
CHECK_EQ(ac3.entryMap.count("and"), 1);
899
CHECK_EQ(ac3.entryMap.count("or"), 1);
900
CHECK_EQ(ac3.context, AutocompleteContext::Keyword);
901
902
check(R"(
903
if x then
904
@1
905
end
906
)");
907
908
auto ac4 = autocomplete('1');
909
CHECK_EQ(ac4.entryMap.count("then"), 0);
910
CHECK_EQ(ac4.entryMap.count("else"), 1);
911
CHECK_EQ(ac4.entryMap.count("function"), 1);
912
CHECK_EQ(ac4.entryMap.count("elseif"), 1);
913
CHECK_EQ(ac4.entryMap.count("end"), 0);
914
CHECK_EQ(ac4.context, AutocompleteContext::Statement);
915
916
check(R"(
917
if x then
918
t@1
919
end
920
)");
921
922
auto ac4a = autocomplete('1');
923
CHECK_EQ(ac4a.entryMap.count("then"), 0);
924
CHECK_EQ(ac4a.entryMap.count("table"), 1);
925
CHECK_EQ(ac4a.entryMap.count("else"), 1);
926
CHECK_EQ(ac4a.entryMap.count("elseif"), 1);
927
CHECK_EQ(ac4a.context, AutocompleteContext::Statement);
928
929
check(R"(
930
if x then
931
@1
932
elseif x then
933
end
934
)");
935
936
auto ac5 = autocomplete('1');
937
CHECK_EQ(ac5.entryMap.count("then"), 0);
938
CHECK_EQ(ac5.entryMap.count("function"), 1);
939
CHECK_EQ(ac5.entryMap.count("else"), 0);
940
CHECK_EQ(ac5.entryMap.count("elseif"), 0);
941
CHECK_EQ(ac5.entryMap.count("end"), 0);
942
CHECK_EQ(ac5.context, AutocompleteContext::Statement);
943
944
check(R"(
945
if t@1
946
)");
947
948
auto ac6 = autocomplete('1');
949
CHECK_EQ(ac6.entryMap.count("true"), 1);
950
CHECK_EQ(ac6.entryMap.count("false"), 1);
951
CHECK_EQ(ac6.entryMap.count("then"), 0);
952
CHECK_EQ(ac6.entryMap.count("function"), 1);
953
CHECK_EQ(ac6.entryMap.count("else"), 0);
954
CHECK_EQ(ac6.entryMap.count("elseif"), 0);
955
CHECK_EQ(ac6.entryMap.count("end"), 0);
956
CHECK_EQ(ac6.context, AutocompleteContext::Expression);
957
}
958
959
TEST_CASE_FIXTURE(ACFixture, "autocomplete_until_in_repeat")
960
{
961
check(R"(
962
repeat @1
963
)");
964
965
auto ac = autocomplete('1');
966
CHECK_EQ(ac.entryMap.count("table"), 1);
967
CHECK_EQ(ac.entryMap.count("until"), 1);
968
CHECK_EQ(ac.context, AutocompleteContext::Statement);
969
}
970
971
TEST_CASE_FIXTURE(ACFixture, "autocomplete_until_expression")
972
{
973
check(R"(
974
repeat
975
until @1
976
)");
977
978
auto ac = autocomplete('1');
979
CHECK_EQ(ac.entryMap.count("table"), 1);
980
CHECK_EQ(ac.context, AutocompleteContext::Expression);
981
}
982
983
TEST_CASE_FIXTURE(ACFixture, "local_names")
984
{
985
check(R"(
986
local ab@1
987
)");
988
989
auto ac1 = autocomplete('1');
990
CHECK_EQ(ac1.entryMap.size(), 1);
991
CHECK_EQ(ac1.entryMap.count("function"), 1);
992
CHECK_EQ(ac1.context, AutocompleteContext::Unknown);
993
994
check(R"(
995
local ab, cd@1
996
)");
997
998
auto ac2 = autocomplete('1');
999
CHECK(ac2.entryMap.empty());
1000
CHECK_EQ(ac2.context, AutocompleteContext::Unknown);
1001
}
1002
1003
TEST_CASE_FIXTURE(ACFixture, "autocomplete_end_with_fn_exprs")
1004
{
1005
check(R"(
1006
local function f() @1
1007
)");
1008
1009
auto ac = autocomplete('1');
1010
CHECK_EQ(ac.entryMap.count("end"), 1);
1011
CHECK_EQ(ac.context, AutocompleteContext::Statement);
1012
}
1013
1014
TEST_CASE_FIXTURE(ACFixture, "autocomplete_end_with_lambda")
1015
{
1016
check(R"(
1017
local a = function() local bar = foo en@1
1018
)");
1019
1020
auto ac = autocomplete('1');
1021
CHECK_EQ(ac.entryMap.count("end"), 1);
1022
CHECK_EQ(ac.context, AutocompleteContext::Statement);
1023
}
1024
1025
TEST_CASE_FIXTURE(ACFixture, "autocomplete_end_of_do_block")
1026
{
1027
check("do @1");
1028
1029
auto ac = autocomplete('1');
1030
1031
CHECK(ac.entryMap.count("end"));
1032
1033
check(R"(
1034
function f()
1035
do
1036
@1
1037
end
1038
@2
1039
)");
1040
1041
ac = autocomplete('1');
1042
1043
CHECK(ac.entryMap.count("end"));
1044
1045
ac = autocomplete('2');
1046
1047
CHECK(ac.entryMap.count("end"));
1048
}
1049
1050
TEST_CASE_FIXTURE(ACFixture, "stop_at_first_stat_when_recommending_keywords")
1051
{
1052
check(R"(
1053
repeat
1054
for x @1
1055
)");
1056
1057
auto ac1 = autocomplete('1');
1058
CHECK_EQ(ac1.entryMap.count("in"), 1);
1059
CHECK_EQ(ac1.entryMap.count("until"), 0);
1060
CHECK_EQ(ac1.context, AutocompleteContext::Keyword);
1061
}
1062
1063
TEST_CASE_FIXTURE(ACFixture, "autocomplete_repeat_middle_keyword")
1064
{
1065
check(R"(
1066
repeat @1
1067
)");
1068
1069
auto ac1 = autocomplete('1');
1070
CHECK_EQ(ac1.entryMap.count("do"), 1);
1071
CHECK_EQ(ac1.entryMap.count("function"), 1);
1072
CHECK_EQ(ac1.entryMap.count("until"), 1);
1073
1074
check(R"(
1075
repeat f f@1
1076
)");
1077
1078
auto ac2 = autocomplete('1');
1079
CHECK_EQ(ac2.entryMap.count("function"), 1);
1080
CHECK_EQ(ac2.entryMap.count("until"), 1);
1081
1082
check(R"(
1083
repeat
1084
u@1
1085
until
1086
)");
1087
1088
auto ac3 = autocomplete('1');
1089
CHECK_EQ(ac3.entryMap.count("until"), 0);
1090
}
1091
1092
TEST_CASE_FIXTURE(ACFixture, "local_function")
1093
{
1094
check(R"(
1095
local f@1
1096
)");
1097
1098
auto ac1 = autocomplete('1');
1099
CHECK_EQ(ac1.entryMap.size(), 1);
1100
CHECK_EQ(ac1.entryMap.count("function"), 1);
1101
1102
check(R"(
1103
local f@1, cd
1104
)");
1105
1106
auto ac2 = autocomplete('1');
1107
CHECK(ac2.entryMap.empty());
1108
}
1109
1110
TEST_CASE_FIXTURE(ACFixture, "local_function")
1111
{
1112
check(R"(
1113
local function @1
1114
)");
1115
1116
auto ac = autocomplete('1');
1117
CHECK(ac.entryMap.empty());
1118
1119
check(R"(
1120
local function @1s@2
1121
)");
1122
1123
ac = autocomplete('1');
1124
CHECK(ac.entryMap.empty());
1125
1126
ac = autocomplete('2');
1127
CHECK(ac.entryMap.empty());
1128
1129
check(R"(
1130
local function @1()@2
1131
)");
1132
1133
ac = autocomplete('1');
1134
CHECK(ac.entryMap.empty());
1135
1136
ac = autocomplete('2');
1137
CHECK(ac.entryMap.count("end"));
1138
1139
check(R"(
1140
local function something@1
1141
)");
1142
1143
ac = autocomplete('1');
1144
CHECK(ac.entryMap.empty());
1145
1146
check(R"(
1147
local tbl = {}
1148
function tbl.something@1() end
1149
)");
1150
1151
ac = autocomplete('1');
1152
CHECK(ac.entryMap.empty());
1153
}
1154
1155
TEST_CASE_FIXTURE(ACFixture, "local_function_params")
1156
{
1157
check(R"(
1158
local function @1a@2bc(@3d@4ef)@5 @6
1159
)");
1160
1161
CHECK(autocomplete('1').entryMap.empty());
1162
CHECK(autocomplete('2').entryMap.empty());
1163
CHECK(autocomplete('3').entryMap.empty());
1164
CHECK(autocomplete('4').entryMap.empty());
1165
CHECK(!autocomplete('5').entryMap.empty());
1166
1167
CHECK(!autocomplete('6').entryMap.empty());
1168
1169
check(R"(
1170
local function abc(def)
1171
@1 end
1172
)");
1173
1174
for (unsigned int i = 23; i < 31; ++i)
1175
{
1176
CHECK(autocomplete(1, i).entryMap.empty());
1177
}
1178
CHECK(!autocomplete(1, 32).entryMap.empty());
1179
1180
auto ac2 = autocomplete('1');
1181
CHECK_EQ(ac2.entryMap.count("abc"), 1);
1182
CHECK_EQ(ac2.entryMap.count("def"), 1);
1183
CHECK_EQ(ac2.context, AutocompleteContext::Statement);
1184
1185
check(R"(
1186
local function abc(def, ghi@1)
1187
end
1188
)");
1189
1190
auto ac3 = autocomplete('1');
1191
CHECK(ac3.entryMap.empty());
1192
CHECK_EQ(ac3.context, AutocompleteContext::Unknown);
1193
}
1194
1195
TEST_CASE_FIXTURE(ACFixture, "global_function_params")
1196
{
1197
check(R"(
1198
function abc(def)
1199
)");
1200
1201
for (unsigned int i = 17; i < 25; ++i)
1202
{
1203
CHECK(autocomplete(1, i).entryMap.empty());
1204
}
1205
CHECK(!autocomplete(1, 26).entryMap.empty());
1206
1207
check(R"(
1208
function abc(def)
1209
end
1210
)");
1211
1212
for (unsigned int i = 17; i < 25; ++i)
1213
{
1214
CHECK(autocomplete(1, i).entryMap.empty());
1215
}
1216
CHECK(!autocomplete(1, 26).entryMap.empty());
1217
1218
check(R"(
1219
function abc(def)
1220
@1
1221
end
1222
)");
1223
1224
auto ac2 = autocomplete('1');
1225
CHECK_EQ(ac2.entryMap.count("abc"), 1);
1226
CHECK_EQ(ac2.entryMap.count("def"), 1);
1227
CHECK_EQ(ac2.context, AutocompleteContext::Statement);
1228
1229
check(R"(
1230
function abc(def, ghi@1)
1231
end
1232
)");
1233
1234
auto ac3 = autocomplete('1');
1235
CHECK(ac3.entryMap.empty());
1236
CHECK_EQ(ac3.context, AutocompleteContext::Unknown);
1237
}
1238
1239
TEST_CASE_FIXTURE(ACFixture, "arguments_to_global_lambda")
1240
{
1241
check(R"(
1242
abc = function(def, ghi@1)
1243
end
1244
)");
1245
1246
auto ac = autocomplete('1');
1247
CHECK(ac.entryMap.empty());
1248
}
1249
1250
TEST_CASE_FIXTURE(ACFixture, "function_expr_params")
1251
{
1252
check(R"(
1253
abc = function(def) @1
1254
)");
1255
1256
for (unsigned int i = 20; i < 27; ++i)
1257
{
1258
CHECK(autocomplete(1, i).entryMap.empty());
1259
}
1260
CHECK(!autocomplete('1').entryMap.empty());
1261
1262
check(R"(
1263
abc = function(def) @1
1264
end
1265
)");
1266
1267
for (unsigned int i = 20; i < 27; ++i)
1268
{
1269
CHECK(autocomplete(1, i).entryMap.empty());
1270
}
1271
CHECK(!autocomplete('1').entryMap.empty());
1272
1273
check(R"(
1274
abc = function(def)
1275
@1
1276
end
1277
)");
1278
1279
auto ac2 = autocomplete('1');
1280
CHECK_EQ(ac2.entryMap.count("def"), 1);
1281
CHECK_EQ(ac2.context, AutocompleteContext::Statement);
1282
}
1283
1284
TEST_CASE_FIXTURE(ACFixture, "local_initializer")
1285
{
1286
check(R"(
1287
local a = t@1
1288
)");
1289
1290
auto ac = autocomplete('1');
1291
CHECK_EQ(ac.entryMap.count("table"), 1);
1292
CHECK_EQ(ac.entryMap.count("true"), 1);
1293
}
1294
1295
TEST_CASE_FIXTURE(ACFixture, "local_initializer_2")
1296
{
1297
check(R"(
1298
local a=@1
1299
)");
1300
1301
auto ac = autocomplete('1');
1302
CHECK(ac.entryMap.count("table"));
1303
}
1304
1305
TEST_CASE_FIXTURE(ACFixture, "get_member_completions")
1306
{
1307
check(R"(
1308
local a = 12.@13
1309
)");
1310
1311
auto ac = autocomplete('1');
1312
CHECK(ac.entryMap.empty());
1313
}
1314
1315
TEST_CASE_FIXTURE(ACFixture, "sometimes_the_metatable_is_an_error")
1316
{
1317
check(R"(
1318
local T = {}
1319
T.__index = T
1320
1321
function T.new()
1322
return setmetatable({x=6}, X) -- oops!
1323
end
1324
local t = T.new()
1325
t. @1
1326
)");
1327
1328
autocomplete('1');
1329
// Don't crash!
1330
}
1331
1332
TEST_CASE_FIXTURE(ACFixture, "local_types_builtin")
1333
{
1334
check(R"(
1335
local a: n@1
1336
local b: string = "don't trip"
1337
)");
1338
1339
auto ac = autocomplete('1');
1340
1341
CHECK(ac.entryMap.count("nil"));
1342
CHECK(ac.entryMap.count("number"));
1343
CHECK_EQ(ac.context, AutocompleteContext::Type);
1344
}
1345
1346
TEST_CASE_FIXTURE(ACFixture, "private_types")
1347
{
1348
check(R"(
1349
do
1350
type num = number
1351
local a: n@1u
1352
local b: nu@2m
1353
end
1354
local a: nu@3
1355
)");
1356
1357
auto ac = autocomplete('1');
1358
1359
CHECK(ac.entryMap.count("num"));
1360
CHECK(ac.entryMap.count("number"));
1361
1362
ac = autocomplete('2');
1363
1364
CHECK(ac.entryMap.count("num"));
1365
CHECK(ac.entryMap.count("number"));
1366
1367
ac = autocomplete('3');
1368
1369
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "num");
1370
CHECK(ac.entryMap.count("number"));
1371
}
1372
1373
TEST_CASE_FIXTURE(ACFixture, "type_scoping_easy")
1374
{
1375
check(R"(
1376
type Table = { a: number, b: number }
1377
do
1378
type Table = { x: string, y: string }
1379
local a: T@1
1380
end
1381
)");
1382
1383
auto ac = autocomplete('1');
1384
1385
REQUIRE(ac.entryMap.count("Table"));
1386
REQUIRE(ac.entryMap["Table"].type);
1387
const TableType* tv = get<TableType>(follow(*ac.entryMap["Table"].type));
1388
REQUIRE(tv);
1389
CHECK(tv->props.count("x"));
1390
}
1391
1392
TEST_CASE_FIXTURE(ACFixture, "modules_with_types")
1393
{
1394
fileResolver.source["Module/A"] = R"(
1395
export type A = { x: number, y: number }
1396
export type B = { z: number, w: number }
1397
return {}
1398
)";
1399
1400
LUAU_REQUIRE_NO_ERRORS(getFrontend().check("Module/A"));
1401
1402
fileResolver.source["Module/B"] = R"(
1403
local aaa = require(script.Parent.A)
1404
local a: aa
1405
)";
1406
1407
getFrontend().check("Module/B");
1408
1409
auto ac = autocomplete("Module/B", Position{2, 11});
1410
1411
CHECK(ac.entryMap.count("aaa"));
1412
CHECK_EQ(ac.context, AutocompleteContext::Type);
1413
}
1414
1415
TEST_CASE_FIXTURE(ACFixture, "module_type_members")
1416
{
1417
fileResolver.source["Module/A"] = R"(
1418
export type A = { x: number, y: number }
1419
export type B = { z: number, w: number }
1420
return {}
1421
)";
1422
1423
LUAU_REQUIRE_NO_ERRORS(getFrontend().check("Module/A"));
1424
1425
fileResolver.source["Module/B"] = R"(
1426
local aaa = require(script.Parent.A)
1427
local a: aaa.
1428
)";
1429
1430
getFrontend().check("Module/B");
1431
1432
auto ac = autocomplete("Module/B", Position{2, 13});
1433
1434
CHECK_EQ(2, ac.entryMap.size());
1435
CHECK(ac.entryMap.count("A"));
1436
CHECK(ac.entryMap.count("B"));
1437
CHECK_EQ(ac.context, AutocompleteContext::Type);
1438
}
1439
1440
TEST_CASE_FIXTURE(ACFixture, "argument_types")
1441
{
1442
check(R"(
1443
local function f(a: n@1
1444
local b: string = "don't trip"
1445
)");
1446
1447
auto ac = autocomplete('1');
1448
1449
CHECK(ac.entryMap.count("nil"));
1450
CHECK(ac.entryMap.count("number"));
1451
CHECK_EQ(ac.context, AutocompleteContext::Type);
1452
}
1453
1454
TEST_CASE_FIXTURE(ACFixture, "return_types")
1455
{
1456
check(R"(
1457
local function f(a: number): n@1
1458
local b: string = "don't trip"
1459
)");
1460
1461
auto ac = autocomplete('1');
1462
1463
CHECK(ac.entryMap.count("nil"));
1464
CHECK(ac.entryMap.count("number"));
1465
CHECK_EQ(ac.context, AutocompleteContext::Type);
1466
}
1467
1468
TEST_CASE_FIXTURE(ACFixture, "as_types")
1469
{
1470
check(R"(
1471
local a: any = 5
1472
local b: number = (a :: n@1
1473
)");
1474
1475
auto ac = autocomplete('1');
1476
1477
CHECK(ac.entryMap.count("nil"));
1478
CHECK(ac.entryMap.count("number"));
1479
CHECK_EQ(ac.context, AutocompleteContext::Type);
1480
}
1481
1482
TEST_CASE_FIXTURE(ACFixture, "function_type_types")
1483
{
1484
check(R"(
1485
local a: (n@1
1486
local b: (number, (n@2
1487
local c: (number, (number) -> n@3
1488
local d: (number, (number) -> (number, n@4
1489
local e: (n: n@5
1490
)");
1491
1492
auto ac = autocomplete('1');
1493
1494
CHECK(ac.entryMap.count("nil"));
1495
CHECK(ac.entryMap.count("number"));
1496
1497
ac = autocomplete('2');
1498
1499
CHECK(ac.entryMap.count("nil"));
1500
CHECK(ac.entryMap.count("number"));
1501
1502
ac = autocomplete('3');
1503
1504
CHECK(ac.entryMap.count("nil"));
1505
CHECK(ac.entryMap.count("number"));
1506
1507
ac = autocomplete('4');
1508
1509
CHECK(ac.entryMap.count("nil"));
1510
CHECK(ac.entryMap.count("number"));
1511
1512
ac = autocomplete('5');
1513
1514
CHECK(ac.entryMap.count("nil"));
1515
CHECK(ac.entryMap.count("number"));
1516
}
1517
1518
TEST_CASE_FIXTURE(ACFixture, "generic_types")
1519
{
1520
check(R"(
1521
function f<Tee, Use>(a: T@1
1522
local b: string = "don't trip"
1523
)");
1524
1525
auto ac = autocomplete('1');
1526
1527
CHECK(ac.entryMap.count("Tee"));
1528
CHECK_EQ(ac.context, AutocompleteContext::Type);
1529
}
1530
1531
TEST_CASE_FIXTURE(ACFixture, "type_correct_suggestion_in_argument")
1532
{
1533
// local
1534
check(R"(
1535
local function target(a: number, b: string) return a + #b end
1536
1537
local one = 4
1538
local two = "hello"
1539
return target(o@1
1540
)");
1541
1542
auto ac = autocomplete('1');
1543
1544
CHECK(ac.entryMap.count("one"));
1545
CHECK(ac.entryMap["one"].typeCorrect == TypeCorrectKind::Correct);
1546
CHECK(ac.entryMap["two"].typeCorrect == TypeCorrectKind::None);
1547
1548
check(R"(
1549
local function target(a: number, b: string) return a + #b end
1550
1551
local one = 4
1552
local two = "hello"
1553
return target(one, t@1
1554
)");
1555
1556
ac = autocomplete('1');
1557
1558
CHECK(ac.entryMap.count("two"));
1559
CHECK(ac.entryMap["two"].typeCorrect == TypeCorrectKind::Correct);
1560
CHECK(ac.entryMap["one"].typeCorrect == TypeCorrectKind::None);
1561
1562
// member
1563
check(R"(
1564
local function target(a: number, b: string) return a + #b end
1565
1566
local a = { one = 4, two = "hello" }
1567
return target(a.@1
1568
)");
1569
1570
ac = autocomplete('1');
1571
1572
CHECK(ac.entryMap.count("one"));
1573
CHECK(ac.entryMap["one"].typeCorrect == TypeCorrectKind::Correct);
1574
CHECK(ac.entryMap["two"].typeCorrect == TypeCorrectKind::None);
1575
1576
check(R"(
1577
local function target(a: number, b: string) return a + #b end
1578
1579
local a = { one = 4, two = "hello" }
1580
return target(a.one, a.@1
1581
)");
1582
1583
ac = autocomplete('1');
1584
1585
CHECK(ac.entryMap.count("two"));
1586
CHECK(ac.entryMap["two"].typeCorrect == TypeCorrectKind::Correct);
1587
CHECK(ac.entryMap["one"].typeCorrect == TypeCorrectKind::None);
1588
1589
// union match
1590
check(R"(
1591
local function target(a: string?) return #b end
1592
1593
local a = { one = 4, two = "hello" }
1594
return target(a.@1
1595
)");
1596
1597
ac = autocomplete('1');
1598
1599
CHECK(ac.entryMap.count("two"));
1600
CHECK(ac.entryMap["two"].typeCorrect == TypeCorrectKind::Correct);
1601
CHECK(ac.entryMap["one"].typeCorrect == TypeCorrectKind::None);
1602
}
1603
1604
TEST_CASE_FIXTURE(ACFixture, "type_correct_suggestion_in_table")
1605
{
1606
check(R"(
1607
type Foo = { a: number, b: string }
1608
local a = { one = 4, two = "hello" }
1609
local b: Foo = { a = a.@1
1610
)");
1611
1612
auto ac = autocomplete('1');
1613
1614
CHECK(ac.entryMap.count("one"));
1615
CHECK(ac.entryMap["one"].typeCorrect == TypeCorrectKind::Correct);
1616
CHECK(ac.entryMap["two"].typeCorrect == TypeCorrectKind::None);
1617
CHECK_EQ(ac.context, AutocompleteContext::Property);
1618
1619
check(R"(
1620
type Foo = { a: number, b: string }
1621
local a = { one = 4, two = "hello" }
1622
local b: Foo = { b = a.@1
1623
)");
1624
1625
ac = autocomplete('1');
1626
1627
CHECK(ac.entryMap.count("two"));
1628
CHECK(ac.entryMap["two"].typeCorrect == TypeCorrectKind::Correct);
1629
CHECK(ac.entryMap["one"].typeCorrect == TypeCorrectKind::None);
1630
CHECK_EQ(ac.context, AutocompleteContext::Property);
1631
}
1632
1633
TEST_CASE_FIXTURE(ACFixture, "type_correct_function_return_types")
1634
{
1635
check(R"(
1636
local function target(a: number, b: string) return a + #b end
1637
local function bar1(a: number) return -a end
1638
local function bar2(a: string) return a .. 'x' end
1639
1640
return target(b@1
1641
)");
1642
1643
auto ac = autocomplete('1');
1644
1645
CHECK(ac.entryMap.count("bar1"));
1646
CHECK(ac.entryMap["bar1"].typeCorrect == TypeCorrectKind::CorrectFunctionResult);
1647
CHECK(ac.entryMap["bar2"].typeCorrect == TypeCorrectKind::None);
1648
1649
check(R"(
1650
local function target(a: number, b: string) return a + #b end
1651
local function bar1(a: number) return -a end
1652
local function bar2(a: string) return a .. 'x' end
1653
1654
return target(bar1, b@1
1655
)");
1656
1657
ac = autocomplete('1');
1658
1659
CHECK(ac.entryMap.count("bar2"));
1660
CHECK(ac.entryMap["bar2"].typeCorrect == TypeCorrectKind::CorrectFunctionResult);
1661
CHECK(ac.entryMap["bar1"].typeCorrect == TypeCorrectKind::None);
1662
1663
check(R"(
1664
local function target(a: number, b: string) return a + #b end
1665
local function bar1(a: number): (...number) return -a, a end
1666
local function bar2(a: string) return a .. 'x' end
1667
1668
return target(b@1
1669
)");
1670
1671
ac = autocomplete('1');
1672
1673
CHECK(ac.entryMap.count("bar1"));
1674
CHECK(ac.entryMap["bar1"].typeCorrect == TypeCorrectKind::CorrectFunctionResult);
1675
CHECK(ac.entryMap["bar2"].typeCorrect == TypeCorrectKind::None);
1676
}
1677
1678
TEST_CASE_FIXTURE(ACFixture, "type_correct_local_type_suggestion")
1679
{
1680
check(R"(
1681
local b: s@1 = "str"
1682
)");
1683
1684
auto ac = autocomplete('1');
1685
1686
CHECK(ac.entryMap.count("string"));
1687
CHECK(ac.entryMap["string"].typeCorrect == TypeCorrectKind::Correct);
1688
1689
check(R"(
1690
local function f() return "str" end
1691
local b: s@1 = f()
1692
)");
1693
1694
ac = autocomplete('1');
1695
1696
CHECK(ac.entryMap.count("string"));
1697
CHECK(ac.entryMap["string"].typeCorrect == TypeCorrectKind::Correct);
1698
1699
check(R"(
1700
local b: s@1, c: n@2 = "str", 2
1701
)");
1702
1703
ac = autocomplete('1');
1704
1705
CHECK(ac.entryMap.count("string"));
1706
CHECK(ac.entryMap["string"].typeCorrect == TypeCorrectKind::Correct);
1707
1708
ac = autocomplete('2');
1709
1710
CHECK(ac.entryMap.count("number"));
1711
CHECK(ac.entryMap["number"].typeCorrect == TypeCorrectKind::Correct);
1712
1713
check(R"(
1714
local function f() return 1, "str", 3 end
1715
local a: b@1, b: n@2, c: s@3, d: n@4 = false, f()
1716
)");
1717
1718
ac = autocomplete('1');
1719
1720
CHECK(ac.entryMap.count("boolean"));
1721
CHECK(ac.entryMap["boolean"].typeCorrect == TypeCorrectKind::Correct);
1722
1723
ac = autocomplete('2');
1724
1725
CHECK(ac.entryMap.count("number"));
1726
CHECK(ac.entryMap["number"].typeCorrect == TypeCorrectKind::Correct);
1727
1728
ac = autocomplete('3');
1729
1730
CHECK(ac.entryMap.count("string"));
1731
CHECK(ac.entryMap["string"].typeCorrect == TypeCorrectKind::Correct);
1732
1733
ac = autocomplete('4');
1734
1735
CHECK(ac.entryMap.count("number"));
1736
CHECK(ac.entryMap["number"].typeCorrect == TypeCorrectKind::Correct);
1737
1738
check(R"(
1739
local function f(): ...number return 1, 2, 3 end
1740
local a: boolean, b: n@1 = false, f()
1741
)");
1742
1743
ac = autocomplete('1');
1744
1745
CHECK(ac.entryMap.count("number"));
1746
CHECK(ac.entryMap["number"].typeCorrect == TypeCorrectKind::Correct);
1747
}
1748
1749
TEST_CASE_FIXTURE(ACFixture, "type_correct_function_type_suggestion")
1750
{
1751
check(R"(
1752
local b: (n@1) -> number = function(a: number, b: string) return a + #b end
1753
)");
1754
1755
auto ac = autocomplete('1');
1756
1757
CHECK(ac.entryMap.count("number"));
1758
CHECK(ac.entryMap["number"].typeCorrect == TypeCorrectKind::Correct);
1759
1760
check(R"(
1761
local b: (number, s@1 = function(a: number, b: string) return a + #b end
1762
)");
1763
1764
ac = autocomplete('1');
1765
1766
CHECK(ac.entryMap.count("string"));
1767
CHECK(ac.entryMap["string"].typeCorrect == TypeCorrectKind::Correct);
1768
1769
check(R"(
1770
local b: (number, string) -> b@1 = function(a: number, b: string): boolean return a + #b == 0 end
1771
)");
1772
1773
ac = autocomplete('1');
1774
1775
CHECK(ac.entryMap.count("boolean"));
1776
CHECK(ac.entryMap["boolean"].typeCorrect == TypeCorrectKind::Correct);
1777
1778
check(R"(
1779
local b: (number, ...s@1) = function(a: number, ...: string) return a end
1780
)");
1781
1782
ac = autocomplete('1');
1783
1784
CHECK(ac.entryMap.count("string"));
1785
CHECK(ac.entryMap["string"].typeCorrect == TypeCorrectKind::Correct);
1786
1787
check(R"(
1788
local b: (number) -> ...s@1 = function(a: number): ...string return "a", "b", "c" end
1789
)");
1790
1791
ac = autocomplete('1');
1792
1793
CHECK(ac.entryMap.count("string"));
1794
CHECK(ac.entryMap["string"].typeCorrect == TypeCorrectKind::Correct);
1795
}
1796
1797
TEST_CASE_FIXTURE(ACFixture, "type_correct_full_type_suggestion")
1798
{
1799
check(R"(
1800
local b:@1 @2= "str"
1801
)");
1802
1803
auto ac = autocomplete('1');
1804
1805
CHECK(ac.entryMap.count("string"));
1806
CHECK(ac.entryMap["string"].typeCorrect == TypeCorrectKind::Correct);
1807
1808
ac = autocomplete('2');
1809
1810
CHECK(ac.entryMap.count("string"));
1811
CHECK(ac.entryMap["string"].typeCorrect == TypeCorrectKind::Correct);
1812
1813
check(R"(
1814
local b: @1= function(a: number) return -a end
1815
)");
1816
1817
ac = autocomplete('1');
1818
1819
CHECK(ac.entryMap.count("(number) -> number"));
1820
CHECK(ac.entryMap["(number) -> number"].typeCorrect == TypeCorrectKind::Correct);
1821
}
1822
1823
TEST_CASE_FIXTURE(ACFixture, "type_correct_argument_type_suggestion")
1824
{
1825
check(R"(
1826
local function target(a: number, b: string) return a + #b end
1827
1828
local function d(a: n@1, b)
1829
return target(a, b)
1830
end
1831
)");
1832
1833
auto ac = autocomplete('1');
1834
1835
CHECK(ac.entryMap.count("number"));
1836
CHECK(ac.entryMap["number"].typeCorrect == TypeCorrectKind::Correct);
1837
1838
check(R"(
1839
local function target(a: number, b: string) return a + #b end
1840
1841
local function d(a, b: s@1)
1842
return target(a, b)
1843
end
1844
)");
1845
1846
ac = autocomplete('1');
1847
1848
CHECK(ac.entryMap.count("string"));
1849
CHECK(ac.entryMap["string"].typeCorrect == TypeCorrectKind::Correct);
1850
1851
check(R"(
1852
local function target(a: number, b: string) return a + #b end
1853
1854
local function d(a:@1 @2, b)
1855
return target(a, b)
1856
end
1857
)");
1858
1859
ac = autocomplete('1');
1860
1861
CHECK(ac.entryMap.count("number"));
1862
CHECK(ac.entryMap["number"].typeCorrect == TypeCorrectKind::Correct);
1863
1864
ac = autocomplete('2');
1865
1866
CHECK(ac.entryMap.count("number"));
1867
CHECK(ac.entryMap["number"].typeCorrect == TypeCorrectKind::Correct);
1868
1869
check(R"(
1870
local function target(a: number, b: string) return a + #b end
1871
1872
local function d(a, b: @1)@2: number
1873
return target(a, b)
1874
end
1875
)");
1876
1877
ac = autocomplete('1');
1878
1879
CHECK(ac.entryMap.count("string"));
1880
CHECK(ac.entryMap["string"].typeCorrect == TypeCorrectKind::Correct);
1881
1882
ac = autocomplete('2');
1883
1884
CHECK(ac.entryMap["string"].typeCorrect == TypeCorrectKind::None);
1885
}
1886
1887
TEST_CASE_FIXTURE(ACFixture, "type_correct_expected_argument_type_suggestion")
1888
{
1889
check(R"(
1890
local function target(callback: (a: number, b: string) -> number) return callback(4, "hello") end
1891
1892
local x = target(function(a: @1
1893
)");
1894
1895
auto ac = autocomplete('1');
1896
1897
CHECK(ac.entryMap.count("number"));
1898
CHECK(ac.entryMap["number"].typeCorrect == TypeCorrectKind::Correct);
1899
1900
check(R"(
1901
local function target(callback: (a: number, b: string) -> number) return callback(4, "hello") end
1902
1903
local x = target(function(a: n@1
1904
)");
1905
1906
ac = autocomplete('1');
1907
1908
CHECK(ac.entryMap.count("number"));
1909
CHECK(ac.entryMap["number"].typeCorrect == TypeCorrectKind::Correct);
1910
1911
check(R"(
1912
local function target(callback: (a: number, b: string) -> number) return callback(4, "hello") end
1913
1914
local x = target(function(a: n@1, b: @2)
1915
return a + #b
1916
end)
1917
)");
1918
1919
ac = autocomplete('1');
1920
1921
CHECK(ac.entryMap.count("number"));
1922
CHECK(ac.entryMap["number"].typeCorrect == TypeCorrectKind::Correct);
1923
1924
ac = autocomplete('2');
1925
1926
CHECK(ac.entryMap.count("string"));
1927
CHECK(ac.entryMap["string"].typeCorrect == TypeCorrectKind::Correct);
1928
1929
check(R"(
1930
local function target(callback: (...number) -> number) return callback(1, 2, 3) end
1931
1932
local x = target(function(a: n@1)
1933
return a
1934
end
1935
)");
1936
1937
ac = autocomplete('1');
1938
1939
CHECK(ac.entryMap.count("number"));
1940
CHECK(ac.entryMap["number"].typeCorrect == TypeCorrectKind::Correct);
1941
}
1942
1943
TEST_CASE_FIXTURE(ACFixture, "type_correct_expected_argument_type_pack_suggestion")
1944
{
1945
check(R"(
1946
local function target(callback: (...number) -> number) return callback(1, 2, 3) end
1947
1948
local x = target(function(...:n@1)
1949
return a
1950
end
1951
)");
1952
1953
auto ac = autocomplete('1');
1954
1955
CHECK(ac.entryMap.count("number"));
1956
CHECK(ac.entryMap["number"].typeCorrect == TypeCorrectKind::Correct);
1957
1958
check(R"(
1959
local function target(callback: (...number) -> number) return callback(1, 2, 3) end
1960
1961
local x = target(function(a:number, b:number, ...:@1)
1962
return a + b
1963
end
1964
)");
1965
1966
ac = autocomplete('1');
1967
1968
CHECK(ac.entryMap.count("number"));
1969
CHECK(ac.entryMap["number"].typeCorrect == TypeCorrectKind::Correct);
1970
}
1971
1972
TEST_CASE_FIXTURE(ACFixture, "type_correct_expected_return_type_suggestion")
1973
{
1974
check(R"(
1975
local function target(callback: () -> number) return callback() end
1976
1977
local x = target(function(): n@1
1978
return 1
1979
end
1980
)");
1981
1982
auto ac = autocomplete('1');
1983
1984
CHECK(ac.entryMap.count("number"));
1985
CHECK(ac.entryMap["number"].typeCorrect == TypeCorrectKind::Correct);
1986
1987
check(R"(
1988
local function target(callback: () -> (number, number)) return callback() end
1989
1990
local x = target(function(): (number, n@1
1991
return 1, 2
1992
end
1993
)");
1994
1995
ac = autocomplete('1');
1996
1997
CHECK(ac.entryMap.count("number"));
1998
CHECK(ac.entryMap["number"].typeCorrect == TypeCorrectKind::Correct);
1999
}
2000
2001
TEST_CASE_FIXTURE(ACFixture, "type_correct_expected_return_type_pack_suggestion")
2002
{
2003
check(R"(
2004
local function target(callback: () -> ...number) return callback() end
2005
2006
local x = target(function(): ...n@1
2007
return 1, 2, 3
2008
end
2009
)");
2010
2011
auto ac = autocomplete('1');
2012
2013
CHECK(ac.entryMap.count("number"));
2014
CHECK(ac.entryMap["number"].typeCorrect == TypeCorrectKind::Correct);
2015
2016
check(R"(
2017
local function target(callback: () -> ...number) return callback() end
2018
2019
local x = target(function(): (number, number, ...n@1
2020
return 1, 2, 3
2021
end
2022
)");
2023
2024
ac = autocomplete('1');
2025
2026
CHECK(ac.entryMap.count("number"));
2027
CHECK(ac.entryMap["number"].typeCorrect == TypeCorrectKind::Correct);
2028
}
2029
2030
TEST_CASE_FIXTURE(ACFixture, "type_correct_expected_argument_type_suggestion_optional")
2031
{
2032
check(R"(
2033
local function target(callback: nil | (a: number, b: string) -> number) return callback(4, "hello") end
2034
2035
local x = target(function(a: @1
2036
)");
2037
2038
auto ac = autocomplete('1');
2039
2040
CHECK(ac.entryMap.count("number"));
2041
CHECK(ac.entryMap["number"].typeCorrect == TypeCorrectKind::Correct);
2042
}
2043
2044
TEST_CASE_FIXTURE(ACFixture, "type_correct_expected_argument_type_suggestion_self")
2045
{
2046
check(R"(
2047
local t = {}
2048
t.x = 5
2049
function t:target(callback: (a: number, b: string) -> number) return callback(self.x, "hello") end
2050
2051
local x = t:target(function(a: @1, b:@2 ) end)
2052
local y = t.target(t, function(a: number, b: @3) end)
2053
)");
2054
2055
auto ac = autocomplete('1');
2056
2057
CHECK(ac.entryMap.count("number"));
2058
CHECK(ac.entryMap["number"].typeCorrect == TypeCorrectKind::Correct);
2059
2060
ac = autocomplete('2');
2061
2062
CHECK(ac.entryMap.count("string"));
2063
CHECK(ac.entryMap["string"].typeCorrect == TypeCorrectKind::Correct);
2064
2065
ac = autocomplete('3');
2066
2067
CHECK(ac.entryMap.count("string"));
2068
CHECK(ac.entryMap["string"].typeCorrect == TypeCorrectKind::Correct);
2069
}
2070
2071
TEST_CASE_FIXTURE(ACFixture, "do_not_suggest_internal_module_type")
2072
{
2073
fileResolver.source["Module/A"] = R"(
2074
type done = { x: number, y: number }
2075
local function a(a: (done) -> number) return a({x=1, y=2}) end
2076
local function b(a: ((done) -> number) -> number) return a(function(done) return 1 end) end
2077
return {a = a, b = b}
2078
)";
2079
2080
LUAU_REQUIRE_NO_ERRORS(getFrontend().check("Module/A"));
2081
2082
fileResolver.source["Module/B"] = R"(
2083
local ex = require(script.Parent.A)
2084
ex.a(function(x:
2085
)";
2086
2087
getFrontend().check("Module/B");
2088
2089
auto ac = autocomplete("Module/B", Position{2, 16});
2090
2091
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "done");
2092
2093
fileResolver.source["Module/C"] = R"(
2094
local ex = require(script.Parent.A)
2095
ex.b(function(x:
2096
)";
2097
2098
getFrontend().check("Module/C");
2099
2100
ac = autocomplete("Module/C", Position{2, 16});
2101
2102
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "(done) -> number");
2103
}
2104
2105
TEST_CASE_FIXTURE(ACBuiltinsFixture, "suggest_external_module_type")
2106
{
2107
fileResolver.source["Module/A"] = R"(
2108
export type done = { x: number, y: number }
2109
local function a(a: (done) -> number) return a({x=1, y=2}) end
2110
local function b(a: ((done) -> number) -> number) return a(function(done) return 1 end) end
2111
return {a = a, b = b}
2112
)";
2113
2114
LUAU_REQUIRE_NO_ERRORS(getFrontend().check("Module/A"));
2115
2116
fileResolver.source["Module/B"] = R"(
2117
local ex = require(script.Parent.A)
2118
ex.a(function(x:
2119
)";
2120
2121
getFrontend().check("Module/B");
2122
2123
auto ac = autocomplete("Module/B", Position{2, 16});
2124
2125
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "done");
2126
CHECK(ac.entryMap.count("ex.done"));
2127
CHECK(ac.entryMap["ex.done"].typeCorrect == TypeCorrectKind::Correct);
2128
2129
fileResolver.source["Module/C"] = R"(
2130
local ex = require(script.Parent.A)
2131
ex.b(function(x:
2132
)";
2133
2134
getFrontend().check("Module/C");
2135
2136
ac = autocomplete("Module/C", Position{2, 16});
2137
2138
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "(done) -> number");
2139
CHECK(ac.entryMap.count("(ex.done) -> number"));
2140
CHECK(ac.entryMap["(ex.done) -> number"].typeCorrect == TypeCorrectKind::Correct);
2141
}
2142
2143
TEST_CASE_FIXTURE(ACFixture, "do_not_suggest_synthetic_table_name")
2144
{
2145
check(R"(
2146
local foo = { a = 1, b = 2 }
2147
local bar: @1= foo
2148
)");
2149
2150
auto ac = autocomplete('1');
2151
2152
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "foo");
2153
}
2154
2155
TEST_CASE_FIXTURE(ACFixture, "type_correct_function_no_parenthesis")
2156
{
2157
check(R"(
2158
local function target(a: (number) -> number) return a(4) end
2159
local function bar1(a: number) return -a end
2160
local function bar2(a: string) return a .. 'x' end
2161
2162
return target(b@1
2163
)");
2164
2165
auto ac = autocomplete('1');
2166
2167
CHECK(ac.entryMap.count("bar1"));
2168
CHECK(ac.entryMap["bar1"].typeCorrect == TypeCorrectKind::Correct);
2169
CHECK(ac.entryMap["bar1"].parens == ParenthesesRecommendation::None);
2170
CHECK(ac.entryMap["bar2"].typeCorrect == TypeCorrectKind::None);
2171
}
2172
2173
TEST_CASE_FIXTURE(ACFixture, "function_in_assignment_has_parentheses")
2174
{
2175
check(R"(
2176
local function bar(a: number) return -a end
2177
local abc = b@1
2178
)");
2179
2180
auto ac = autocomplete('1');
2181
2182
CHECK(ac.entryMap.count("bar"));
2183
CHECK(ac.entryMap["bar"].parens == ParenthesesRecommendation::CursorInside);
2184
}
2185
2186
TEST_CASE_FIXTURE(ACFixture, "function_result_passed_to_function_has_parentheses")
2187
{
2188
check(R"(
2189
local function foo() return 1 end
2190
local function bar(a: number) return -a end
2191
local abc = bar(@1)
2192
)");
2193
2194
auto ac = autocomplete('1');
2195
2196
CHECK(ac.entryMap.count("foo"));
2197
CHECK(ac.entryMap["foo"].parens == ParenthesesRecommendation::CursorAfter);
2198
}
2199
2200
TEST_CASE_FIXTURE(ACFixture, "type_correct_sealed_table")
2201
{
2202
2203
check(R"(
2204
local function f(a: { x: number, y: number }) return a.x + a.y end
2205
local fp: @1= f
2206
)");
2207
2208
auto ac = autocomplete('1');
2209
2210
if (!FFlag::DebugLuauForceOldSolver)
2211
REQUIRE_EQ("({ x: number, y: number }) -> number", toString(requireType("f")));
2212
else
2213
{
2214
// NOTE: All autocomplete tests occur under no-check mode.
2215
REQUIRE_EQ("({ x: number, y: number }) -> (...any)", toString(requireType("f")));
2216
}
2217
CHECK(ac.entryMap.count("({ x: number, y: number }) -> number"));
2218
}
2219
2220
TEST_CASE_FIXTURE(ACFixture, "type_correct_keywords")
2221
{
2222
check(R"(
2223
local function a(x: boolean) end
2224
local function b(x: number?) end
2225
local function c(x: (number) -> string) end
2226
local function d(x: ((number) -> string)?) end
2227
local function e(x: ((number) -> string) & ((boolean) -> number)) end
2228
2229
local tru = {}
2230
local ni = false
2231
2232
local ac = a(t@1)
2233
local bc = b(n@2)
2234
local cc = c(f@3)
2235
local dc = d(f@4)
2236
local ec = e(f@5)
2237
)");
2238
2239
auto ac = autocomplete('1');
2240
CHECK(ac.entryMap.count("tru"));
2241
CHECK(ac.entryMap["tru"].typeCorrect == TypeCorrectKind::None);
2242
CHECK(ac.entryMap["true"].typeCorrect == TypeCorrectKind::Correct);
2243
CHECK(ac.entryMap["false"].typeCorrect == TypeCorrectKind::Correct);
2244
2245
ac = autocomplete('2');
2246
CHECK(ac.entryMap.count("ni"));
2247
CHECK(ac.entryMap["ni"].typeCorrect == TypeCorrectKind::None);
2248
CHECK(ac.entryMap["nil"].typeCorrect == TypeCorrectKind::Correct);
2249
2250
ac = autocomplete('3');
2251
CHECK(ac.entryMap.count("false"));
2252
CHECK(ac.entryMap["false"].typeCorrect == TypeCorrectKind::None);
2253
CHECK(ac.entryMap["function"].typeCorrect == TypeCorrectKind::Correct);
2254
2255
ac = autocomplete('4');
2256
CHECK(ac.entryMap["function"].typeCorrect == TypeCorrectKind::Correct);
2257
2258
ac = autocomplete('5');
2259
CHECK(ac.entryMap["function"].typeCorrect == TypeCorrectKind::Correct);
2260
}
2261
2262
TEST_CASE_FIXTURE(ACFixture, "type_correct_suggestion_for_overloads")
2263
{
2264
if (!FFlag::DebugLuauForceOldSolver) // CLI-116814 Autocomplete needs to populate expected types for function arguments correctly
2265
return; // (overloads and singletons)
2266
check(R"(
2267
local target: ((number) -> string) & ((string) -> number))
2268
2269
local one = 4
2270
local two = "hello"
2271
return target(o@1)
2272
)");
2273
2274
auto ac = autocomplete('1');
2275
2276
CHECK(ac.entryMap.count("one"));
2277
CHECK(ac.entryMap["one"].typeCorrect == TypeCorrectKind::Correct);
2278
CHECK(ac.entryMap["two"].typeCorrect == TypeCorrectKind::Correct);
2279
2280
check(R"(
2281
local target: ((number) -> string) & ((number) -> number))
2282
2283
local one = 4
2284
local two = "hello"
2285
return target(o@1)
2286
)");
2287
2288
ac = autocomplete('1');
2289
2290
CHECK(ac.entryMap.count("one"));
2291
CHECK(ac.entryMap["one"].typeCorrect == TypeCorrectKind::Correct);
2292
CHECK(ac.entryMap["two"].typeCorrect == TypeCorrectKind::None);
2293
2294
check(R"(
2295
local target: ((number, number) -> string) & ((string) -> number))
2296
2297
local one = 4
2298
local two = "hello"
2299
return target(1, o@1)
2300
)");
2301
2302
ac = autocomplete('1');
2303
2304
CHECK(ac.entryMap.count("one"));
2305
CHECK(ac.entryMap["one"].typeCorrect == TypeCorrectKind::Correct);
2306
CHECK(ac.entryMap["two"].typeCorrect == TypeCorrectKind::None);
2307
}
2308
2309
TEST_CASE_FIXTURE(ACFixture, "optional_members")
2310
{
2311
check(R"(
2312
local a = { x = 2, y = 3 }
2313
type A = typeof(a)
2314
local b: A? = a
2315
return b.@1
2316
)");
2317
2318
auto ac = autocomplete('1');
2319
2320
CHECK_EQ(2, ac.entryMap.size());
2321
CHECK(ac.entryMap.count("x"));
2322
CHECK(ac.entryMap.count("y"));
2323
2324
check(R"(
2325
local a = { x = 2, y = 3 }
2326
type A = typeof(a)
2327
local b: nil | A = a
2328
return b.@1
2329
)");
2330
2331
ac = autocomplete('1');
2332
2333
CHECK_EQ(2, ac.entryMap.size());
2334
CHECK(ac.entryMap.count("x"));
2335
CHECK(ac.entryMap.count("y"));
2336
2337
check(R"(
2338
local b: nil | nil
2339
return b.@1
2340
)");
2341
2342
ac = autocomplete('1');
2343
2344
CHECK_EQ(0, ac.entryMap.size());
2345
}
2346
2347
TEST_CASE_FIXTURE(ACFixture, "no_function_name_suggestions")
2348
{
2349
check(R"(
2350
function na@1
2351
)");
2352
2353
auto ac = autocomplete('1');
2354
2355
CHECK(ac.entryMap.empty());
2356
2357
check(R"(
2358
local function @1
2359
)");
2360
2361
ac = autocomplete('1');
2362
2363
CHECK(ac.entryMap.empty());
2364
2365
check(R"(
2366
local function na@1
2367
)");
2368
2369
ac = autocomplete('1');
2370
2371
CHECK(ac.entryMap.empty());
2372
}
2373
2374
TEST_CASE_FIXTURE(ACFixture, "skip_current_local")
2375
{
2376
check(R"(
2377
local other = 1
2378
local name = na@1
2379
)");
2380
2381
auto ac = autocomplete('1');
2382
2383
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "name");
2384
CHECK(ac.entryMap.count("other"));
2385
2386
check(R"(
2387
local other = 1
2388
local name, test = na@1
2389
)");
2390
2391
ac = autocomplete('1');
2392
2393
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "name");
2394
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "test");
2395
CHECK(ac.entryMap.count("other"));
2396
}
2397
2398
TEST_CASE_FIXTURE(ACFixture, "keyword_members")
2399
{
2400
check(R"(
2401
local a = { done = 1, forever = 2 }
2402
local b = a.do@1
2403
local c = a.for@2
2404
local d = a.@3
2405
do
2406
end
2407
)");
2408
2409
auto ac = autocomplete('1');
2410
2411
CHECK_EQ(2, ac.entryMap.size());
2412
CHECK(ac.entryMap.count("done"));
2413
CHECK(ac.entryMap.count("forever"));
2414
2415
ac = autocomplete('2');
2416
2417
CHECK_EQ(2, ac.entryMap.size());
2418
CHECK(ac.entryMap.count("done"));
2419
CHECK(ac.entryMap.count("forever"));
2420
2421
ac = autocomplete('3');
2422
2423
CHECK_EQ(2, ac.entryMap.size());
2424
CHECK(ac.entryMap.count("done"));
2425
CHECK(ac.entryMap.count("forever"));
2426
}
2427
2428
TEST_CASE_FIXTURE(ACFixture, "keyword_methods")
2429
{
2430
check(R"(
2431
local a = {}
2432
function a:done() end
2433
local b = a:do@1
2434
)");
2435
2436
auto ac = autocomplete('1');
2437
2438
CHECK_EQ(1, ac.entryMap.size());
2439
CHECK(ac.entryMap.count("done"));
2440
}
2441
2442
TEST_CASE_FIXTURE(ACFixture, "keyword_types")
2443
{
2444
fileResolver.source["Module/A"] = R"(
2445
export type done = { x: number, y: number }
2446
export type other = { z: number, w: number }
2447
return {}
2448
)";
2449
2450
LUAU_REQUIRE_NO_ERRORS(getFrontend().check("Module/A"));
2451
2452
fileResolver.source["Module/B"] = R"(
2453
local aaa = require(script.Parent.A)
2454
local a: aaa.do
2455
)";
2456
2457
getFrontend().check("Module/B");
2458
2459
auto ac = autocomplete("Module/B", Position{2, 15});
2460
2461
CHECK_EQ(2, ac.entryMap.size());
2462
CHECK(ac.entryMap.count("done"));
2463
CHECK(ac.entryMap.count("other"));
2464
}
2465
2466
2467
TEST_CASE_FIXTURE(ACFixture, "comments")
2468
{
2469
fileResolver.source["Comments"] = "--foo";
2470
2471
auto ac = autocomplete("Comments", Position{0, 5});
2472
CHECK_EQ(0, ac.entryMap.size());
2473
}
2474
2475
TEST_CASE_FIXTURE(ACBuiltinsFixture, "autocompleteProp_index_function_metamethod_is_variadic")
2476
{
2477
fileResolver.source["Module/A"] = R"(
2478
type Foo = {x: number}
2479
local t = {}
2480
setmetatable(t, {
2481
__index = function(index: string): ...Foo
2482
return {x = 1}, {x = 2}
2483
end
2484
})
2485
2486
local a = t. -- Line 9
2487
-- | Column 20
2488
)";
2489
2490
auto ac = autocomplete("Module/A", Position{9, 20});
2491
REQUIRE_EQ(1, ac.entryMap.size());
2492
CHECK(ac.entryMap.count("x"));
2493
}
2494
2495
TEST_CASE_FIXTURE(ACFixture, "if_then_else_full_keywords")
2496
{
2497
check(R"(
2498
local thenceforth = false
2499
local elsewhere = false
2500
local doover = false
2501
local endurance = true
2502
2503
if 1 then@1
2504
else@2
2505
end
2506
2507
while false do@3
2508
end
2509
2510
repeat@4
2511
until
2512
)");
2513
2514
auto ac = autocomplete('1');
2515
CHECK(ac.entryMap.size() == 1);
2516
CHECK(ac.entryMap.count("then"));
2517
2518
ac = autocomplete('2');
2519
CHECK(ac.entryMap.count("else"));
2520
CHECK(ac.entryMap.count("elseif"));
2521
2522
ac = autocomplete('3');
2523
CHECK(ac.entryMap.count("do"));
2524
2525
ac = autocomplete('4');
2526
CHECK(ac.entryMap.count("do"));
2527
2528
// FIXME: ideally we want to handle start and end of all statements as well
2529
}
2530
2531
TEST_CASE_FIXTURE(ACFixture, "if_then_else_elseif_completions")
2532
{
2533
check(R"(
2534
local elsewhere = false
2535
2536
if true then
2537
return 1
2538
el@1
2539
end
2540
)");
2541
2542
auto ac = autocomplete('1');
2543
CHECK(ac.entryMap.count("else"));
2544
CHECK(ac.entryMap.count("elseif"));
2545
CHECK(ac.entryMap.count("elsewhere") == 0);
2546
2547
check(R"(
2548
local elsewhere = false
2549
2550
if true then
2551
return 1
2552
else
2553
return 2
2554
el@1
2555
end
2556
)");
2557
2558
ac = autocomplete('1');
2559
CHECK(ac.entryMap.count("else") == 0);
2560
CHECK(ac.entryMap.count("elseif") == 0);
2561
CHECK(ac.entryMap.count("elsewhere"));
2562
2563
check(R"(
2564
local elsewhere = false
2565
2566
if true then
2567
print("1")
2568
elif true then
2569
print("2")
2570
el@1
2571
end
2572
)");
2573
ac = autocomplete('1');
2574
CHECK(ac.entryMap.count("else"));
2575
CHECK(ac.entryMap.count("elseif"));
2576
CHECK(ac.entryMap.count("elsewhere"));
2577
}
2578
2579
TEST_CASE_FIXTURE(ACFixture, "not_the_var_we_are_defining")
2580
{
2581
fileResolver.source["Module/A"] = "abc,de";
2582
2583
auto ac = autocomplete("Module/A", Position{0, 6});
2584
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "de");
2585
}
2586
2587
TEST_CASE_FIXTURE(ACFixture, "recursive_function_global")
2588
{
2589
fileResolver.source["global"] = R"(function abc()
2590
2591
end
2592
)";
2593
2594
auto ac = autocomplete("global", Position{1, 0});
2595
CHECK(ac.entryMap.count("abc"));
2596
}
2597
2598
2599
2600
TEST_CASE_FIXTURE(ACFixture, "recursive_function_local")
2601
{
2602
fileResolver.source["local"] = R"(local function abc()
2603
2604
end
2605
)";
2606
2607
auto ac = autocomplete("local", Position{1, 0});
2608
CHECK(ac.entryMap.count("abc"));
2609
}
2610
2611
TEST_CASE_FIXTURE(ACFixture, "suggest_table_keys")
2612
{
2613
if (!FFlag::DebugLuauForceOldSolver) // CLI-116812 AutocompleteTest.suggest_table_keys needs to populate expected types for nested
2614
// tables without an annotation
2615
return;
2616
2617
check(R"(
2618
type Test = { first: number, second: number }
2619
local t: Test = { f@1 }
2620
)");
2621
2622
auto ac = autocomplete('1');
2623
CHECK(ac.entryMap.count("first"));
2624
CHECK(ac.entryMap.count("second"));
2625
CHECK_EQ(ac.context, AutocompleteContext::Property);
2626
2627
// Intersection
2628
check(R"(
2629
type Test = { first: number } & { second: number }
2630
local t: Test = { f@1 }
2631
)");
2632
2633
ac = autocomplete('1');
2634
CHECK(ac.entryMap.count("first"));
2635
CHECK(ac.entryMap.count("second"));
2636
CHECK_EQ(ac.context, AutocompleteContext::Property);
2637
2638
// Union
2639
check(R"(
2640
type Test = { first: number, second: number } | { second: number, third: number }
2641
local t: Test = { s@1 }
2642
)");
2643
2644
ac = autocomplete('1');
2645
CHECK(ac.entryMap.count("second"));
2646
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "first");
2647
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "third");
2648
CHECK_EQ(ac.context, AutocompleteContext::Property);
2649
2650
// No parenthesis suggestion
2651
check(R"(
2652
type Test = { first: (number) -> number, second: number }
2653
local t: Test = { f@1 }
2654
)");
2655
2656
ac = autocomplete('1');
2657
CHECK(ac.entryMap.count("first"));
2658
CHECK(ac.entryMap["first"].parens == ParenthesesRecommendation::None);
2659
CHECK_EQ(ac.context, AutocompleteContext::Property);
2660
2661
// When key is changed
2662
check(R"(
2663
type Test = { first: number, second: number }
2664
local t: Test = { f@1 = 2 }
2665
)");
2666
2667
ac = autocomplete('1');
2668
CHECK(ac.entryMap.count("first"));
2669
CHECK(ac.entryMap.count("second"));
2670
CHECK_EQ(ac.context, AutocompleteContext::Property);
2671
2672
// Alternative key syntax
2673
check(R"(
2674
type Test = { first: number, second: number }
2675
local t: Test = { ["f@1"] }
2676
)");
2677
2678
ac = autocomplete('1');
2679
CHECK(ac.entryMap.count("first"));
2680
CHECK(ac.entryMap.count("second"));
2681
CHECK_EQ(ac.context, AutocompleteContext::Property);
2682
2683
// Not an alternative key syntax
2684
check(R"(
2685
type Test = { first: number, second: number }
2686
local t: Test = { "f@1" }
2687
)");
2688
2689
ac = autocomplete('1');
2690
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "first");
2691
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "second");
2692
CHECK_EQ(ac.context, AutocompleteContext::String);
2693
2694
// Skip keys that are already defined
2695
check(R"(
2696
type Test = { first: number, second: number }
2697
local t: Test = { first = 2, s@1 }
2698
)");
2699
2700
ac = autocomplete('1');
2701
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "first");
2702
CHECK(ac.entryMap.count("second"));
2703
CHECK_EQ(ac.context, AutocompleteContext::Property);
2704
2705
// Don't skip active key
2706
check(R"(
2707
type Test = { first: number, second: number }
2708
local t: Test = { first@1 }
2709
)");
2710
2711
ac = autocomplete('1');
2712
CHECK(ac.entryMap.count("first"));
2713
CHECK(ac.entryMap.count("second"));
2714
CHECK_EQ(ac.context, AutocompleteContext::Property);
2715
2716
// Inference after first key
2717
check(R"(
2718
local t = {
2719
{ first = 5, second = 10 },
2720
{ f@1 }
2721
}
2722
)");
2723
2724
ac = autocomplete('1');
2725
CHECK(ac.entryMap.count("first"));
2726
CHECK(ac.entryMap.count("second"));
2727
CHECK_EQ(ac.context, AutocompleteContext::Property);
2728
2729
check(R"(
2730
local t = {
2731
[2] = { first = 5, second = 10 },
2732
[5] = { f@1 }
2733
}
2734
)");
2735
2736
ac = autocomplete('1');
2737
CHECK(ac.entryMap.count("first"));
2738
CHECK(ac.entryMap.count("second"));
2739
CHECK_EQ(ac.context, AutocompleteContext::Property);
2740
}
2741
2742
TEST_CASE_FIXTURE(ACFixture, "suggest_table_keys_no_initial_character")
2743
{
2744
check(R"(
2745
type Test = { first: number, second: number }
2746
local t: Test = { @1 }
2747
)");
2748
2749
auto ac = autocomplete('1');
2750
CHECK(ac.entryMap.count("first"));
2751
CHECK(ac.entryMap.count("second"));
2752
CHECK_EQ(ac.context, AutocompleteContext::Property);
2753
}
2754
2755
TEST_CASE_FIXTURE(ACFixture, "suggest_table_keys_no_initial_character_2")
2756
{
2757
check(R"(
2758
type Test = { first: number, second: number }
2759
local t: Test = { first = 1, @1 }
2760
)");
2761
2762
auto ac = autocomplete('1');
2763
CHECK_EQ(ac.entryMap.count("first"), 0);
2764
CHECK(ac.entryMap.count("second"));
2765
CHECK_EQ(ac.context, AutocompleteContext::Property);
2766
}
2767
2768
TEST_CASE_FIXTURE(ACFixture, "suggest_table_keys_no_initial_character_3")
2769
{
2770
check(R"(
2771
type Properties = { TextScaled: boolean, Text: string }
2772
local function create(props: Properties) end
2773
2774
create({ @1 })
2775
)");
2776
2777
auto ac = autocomplete('1');
2778
CHECK(ac.entryMap.size() > 0);
2779
CHECK(ac.entryMap.count("TextScaled"));
2780
CHECK(ac.entryMap.count("Text"));
2781
CHECK_EQ(ac.context, AutocompleteContext::Property);
2782
}
2783
2784
TEST_CASE_FIXTURE(ACFixture, "autocomplete_documentation_symbols")
2785
{
2786
loadDefinition(R"(
2787
declare y: {
2788
x: number,
2789
}
2790
)");
2791
2792
check(R"(
2793
local a = y.@1
2794
)");
2795
2796
auto ac = autocomplete('1');
2797
2798
REQUIRE(ac.entryMap.count("x"));
2799
CHECK_EQ(ac.entryMap["x"].documentationSymbol, "@test/global/y.x");
2800
}
2801
2802
TEST_CASE_FIXTURE(ACFixture, "autocomplete_ifelse_expressions")
2803
{
2804
check(R"(
2805
local temp = false
2806
local even = true;
2807
local a = true
2808
a = if t@1emp then t
2809
a = if temp t@2
2810
a = if temp then e@3
2811
a = if temp then even e@4
2812
a = if temp then even elseif t@5
2813
a = if temp then even elseif true t@6
2814
a = if temp then even elseif true then t@7
2815
a = if temp then even elseif true then temp e@8
2816
a = if temp then even elseif true then temp else e@9
2817
)");
2818
2819
auto ac = autocomplete('1');
2820
CHECK(ac.entryMap.count("temp"));
2821
CHECK(ac.entryMap.count("true"));
2822
CHECK(ac.entryMap.count("then") == 0);
2823
CHECK(ac.entryMap.count("else") == 0);
2824
CHECK(ac.entryMap.count("elseif") == 0);
2825
CHECK_EQ(ac.context, AutocompleteContext::Expression);
2826
2827
ac = autocomplete('2');
2828
CHECK(ac.entryMap.count("temp") == 0);
2829
CHECK(ac.entryMap.count("true") == 0);
2830
CHECK(ac.entryMap.count("then"));
2831
CHECK(ac.entryMap.count("else") == 0);
2832
CHECK(ac.entryMap.count("elseif") == 0);
2833
CHECK_EQ(ac.context, AutocompleteContext::Keyword);
2834
2835
ac = autocomplete('3');
2836
CHECK(ac.entryMap.count("even"));
2837
CHECK(ac.entryMap.count("then") == 0);
2838
CHECK(ac.entryMap.count("else") == 0);
2839
CHECK(ac.entryMap.count("elseif") == 0);
2840
CHECK_EQ(ac.context, AutocompleteContext::Expression);
2841
2842
ac = autocomplete('4');
2843
CHECK(ac.entryMap.count("even") == 0);
2844
CHECK(ac.entryMap.count("then") == 0);
2845
CHECK(ac.entryMap.count("else"));
2846
CHECK(ac.entryMap.count("elseif"));
2847
CHECK_EQ(ac.context, AutocompleteContext::Keyword);
2848
2849
ac = autocomplete('5');
2850
CHECK(ac.entryMap.count("temp"));
2851
CHECK(ac.entryMap.count("true"));
2852
CHECK(ac.entryMap.count("then") == 0);
2853
CHECK(ac.entryMap.count("else") == 0);
2854
CHECK(ac.entryMap.count("elseif") == 0);
2855
CHECK_EQ(ac.context, AutocompleteContext::Expression);
2856
2857
ac = autocomplete('6');
2858
CHECK(ac.entryMap.count("temp") == 0);
2859
CHECK(ac.entryMap.count("true") == 0);
2860
CHECK(ac.entryMap.count("then"));
2861
CHECK(ac.entryMap.count("else") == 0);
2862
CHECK(ac.entryMap.count("elseif") == 0);
2863
CHECK_EQ(ac.context, AutocompleteContext::Keyword);
2864
2865
ac = autocomplete('7');
2866
CHECK(ac.entryMap.count("temp"));
2867
CHECK(ac.entryMap.count("true"));
2868
CHECK(ac.entryMap.count("then") == 0);
2869
CHECK(ac.entryMap.count("else") == 0);
2870
CHECK(ac.entryMap.count("elseif") == 0);
2871
CHECK_EQ(ac.context, AutocompleteContext::Expression);
2872
2873
ac = autocomplete('8');
2874
CHECK(ac.entryMap.count("even") == 0);
2875
CHECK(ac.entryMap.count("then") == 0);
2876
CHECK(ac.entryMap.count("else"));
2877
CHECK(ac.entryMap.count("elseif"));
2878
CHECK_EQ(ac.context, AutocompleteContext::Keyword);
2879
2880
ac = autocomplete('9');
2881
CHECK(ac.entryMap.count("then") == 0);
2882
CHECK(ac.entryMap.count("else") == 0);
2883
CHECK(ac.entryMap.count("elseif") == 0);
2884
CHECK_EQ(ac.context, AutocompleteContext::Expression);
2885
}
2886
2887
TEST_CASE_FIXTURE(ACFixture, "autocomplete_if_else_regression")
2888
{
2889
check(R"(
2890
local abcdef = 0;
2891
local temp = false
2892
local even = true;
2893
local a
2894
a = if temp then even else@1
2895
a = if temp then even else @2
2896
a = if temp then even else abc@3
2897
)");
2898
2899
auto ac = autocomplete('1');
2900
CHECK(ac.entryMap.count("else") == 0);
2901
ac = autocomplete('2');
2902
CHECK(ac.entryMap.count("else") == 0);
2903
ac = autocomplete('3');
2904
CHECK(ac.entryMap.count("abcdef"));
2905
}
2906
2907
TEST_CASE_FIXTURE(ACFixture, "autocomplete_interpolated_string_constant")
2908
{
2909
check(R"(f(`@1`))");
2910
auto ac = autocomplete('1');
2911
CHECK(ac.entryMap.empty());
2912
CHECK_EQ(ac.context, AutocompleteContext::String);
2913
2914
check(R"(f(`@1 {"a"}`))");
2915
ac = autocomplete('1');
2916
CHECK(ac.entryMap.empty());
2917
CHECK_EQ(ac.context, AutocompleteContext::String);
2918
2919
check(R"(f(`{"a"} @1`))");
2920
ac = autocomplete('1');
2921
CHECK(ac.entryMap.empty());
2922
CHECK_EQ(ac.context, AutocompleteContext::String);
2923
2924
check(R"(f(`{"a"} @1 {"b"}`))");
2925
ac = autocomplete('1');
2926
CHECK(ac.entryMap.empty());
2927
CHECK_EQ(ac.context, AutocompleteContext::String);
2928
}
2929
2930
TEST_CASE_FIXTURE(ACFixture, "autocomplete_interpolated_string_expression")
2931
{
2932
check(R"(f(`expression = {@1}`))");
2933
auto ac = autocomplete('1');
2934
CHECK(ac.entryMap.count("table"));
2935
CHECK_EQ(ac.context, AutocompleteContext::Expression);
2936
}
2937
2938
TEST_CASE_FIXTURE(ACFixture, "autocomplete_interpolated_string_expression_with_comments")
2939
{
2940
check(R"(f(`expression = {--[[ bla bla bla ]]@1`))");
2941
2942
auto ac = autocomplete('1');
2943
CHECK(ac.entryMap.count("table"));
2944
CHECK_EQ(ac.context, AutocompleteContext::Expression);
2945
2946
check(R"(f(`expression = {@1 --[[ bla bla bla ]]`))");
2947
ac = autocomplete('1');
2948
CHECK(!ac.entryMap.empty());
2949
CHECK(ac.entryMap.count("table"));
2950
CHECK_EQ(ac.context, AutocompleteContext::Expression);
2951
}
2952
2953
TEST_CASE_FIXTURE(ACFixture, "autocomplete_interpolated_string_as_singleton")
2954
{
2955
check(R"(
2956
--!strict
2957
local function f(a: "cat" | "dog") end
2958
2959
f(`@1`)
2960
f(`uhhh{'try'}@2`)
2961
)");
2962
2963
auto ac = autocomplete('1');
2964
CHECK(ac.entryMap.count("cat"));
2965
CHECK_EQ(ac.context, AutocompleteContext::String);
2966
2967
ac = autocomplete('2');
2968
CHECK(ac.entryMap.empty());
2969
CHECK_EQ(ac.context, AutocompleteContext::String);
2970
}
2971
2972
TEST_CASE_FIXTURE(ACFixture, "autocomplete_explicit_type_pack")
2973
{
2974
check(R"(
2975
type A<T...> = () -> T...
2976
local a: A<(number, s@1>
2977
)");
2978
2979
auto ac = autocomplete('1');
2980
2981
CHECK(ac.entryMap.count("number"));
2982
CHECK(ac.entryMap.count("string"));
2983
CHECK_EQ(ac.context, AutocompleteContext::Type);
2984
}
2985
2986
TEST_CASE_FIXTURE(ACFixture, "autocomplete_first_function_arg_expected_type")
2987
{
2988
check(R"(
2989
local function foo1() return 1 end
2990
local function foo2() return "1" end
2991
2992
local function bar0() return "got" .. a end
2993
local function bar1(a: number) return "got " .. a end
2994
local function bar2(a: number, b: string) return "got " .. a .. b end
2995
2996
local t = {}
2997
function t:bar1(a: number) return "got " .. a end
2998
2999
local r1 = bar0(@1)
3000
local r2 = bar1(@2)
3001
local r3 = bar2(@3)
3002
local r4 = t:bar1(@4)
3003
)");
3004
3005
auto ac = autocomplete('1');
3006
3007
REQUIRE(ac.entryMap.count("foo1"));
3008
CHECK(ac.entryMap["foo1"].typeCorrect == TypeCorrectKind::None);
3009
REQUIRE(ac.entryMap.count("foo2"));
3010
CHECK(ac.entryMap["foo2"].typeCorrect == TypeCorrectKind::None);
3011
3012
ac = autocomplete('2');
3013
3014
REQUIRE(ac.entryMap.count("foo1"));
3015
CHECK(ac.entryMap["foo1"].typeCorrect == TypeCorrectKind::CorrectFunctionResult);
3016
REQUIRE(ac.entryMap.count("foo2"));
3017
CHECK(ac.entryMap["foo2"].typeCorrect == TypeCorrectKind::None);
3018
3019
ac = autocomplete('3');
3020
3021
REQUIRE(ac.entryMap.count("foo1"));
3022
CHECK(ac.entryMap["foo1"].typeCorrect == TypeCorrectKind::CorrectFunctionResult);
3023
REQUIRE(ac.entryMap.count("foo2"));
3024
CHECK(ac.entryMap["foo2"].typeCorrect == TypeCorrectKind::None);
3025
3026
ac = autocomplete('4');
3027
3028
REQUIRE(ac.entryMap.count("foo1"));
3029
CHECK(ac.entryMap["foo1"].typeCorrect == TypeCorrectKind::CorrectFunctionResult);
3030
REQUIRE(ac.entryMap.count("foo2"));
3031
CHECK(ac.entryMap["foo2"].typeCorrect == TypeCorrectKind::None);
3032
}
3033
3034
TEST_CASE_FIXTURE(ACFixture, "autocomplete_default_type_parameters")
3035
{
3036
check(R"(
3037
type A<T = @1> = () -> T
3038
)");
3039
3040
auto ac = autocomplete('1');
3041
3042
CHECK(ac.entryMap.count("number"));
3043
CHECK(ac.entryMap.count("string"));
3044
CHECK_EQ(ac.context, AutocompleteContext::Type);
3045
}
3046
3047
TEST_CASE_FIXTURE(ACFixture, "autocomplete_default_type_pack_parameters")
3048
{
3049
check(R"(
3050
type A<T... = ...@1> = () -> T
3051
)");
3052
3053
auto ac = autocomplete('1');
3054
3055
CHECK(ac.entryMap.count("number"));
3056
CHECK(ac.entryMap.count("string"));
3057
CHECK_EQ(ac.context, AutocompleteContext::Type);
3058
}
3059
3060
TEST_CASE_FIXTURE(ACBuiltinsFixture, "autocomplete_oop_implicit_self")
3061
{
3062
check(R"(
3063
--!strict
3064
local Class = {}
3065
Class.__index = Class
3066
type Class = typeof(setmetatable({} :: { x: number }, Class))
3067
function Class.new(x: number): Class
3068
return setmetatable({x = x}, Class)
3069
end
3070
function Class.getx(self: Class)
3071
return self.x
3072
end
3073
function test()
3074
local c = Class.new(42)
3075
local n = c:@1
3076
print(n)
3077
end
3078
)");
3079
3080
auto ac = autocomplete('1');
3081
3082
CHECK(ac.entryMap.count("getx"));
3083
}
3084
3085
TEST_CASE_FIXTURE(ACBuiltinsFixture, "autocomplete_on_string_singletons")
3086
{
3087
check(R"(
3088
--!strict
3089
local foo: "hello" | "bye" = "hello"
3090
foo:@1
3091
)");
3092
3093
auto ac = autocomplete('1');
3094
3095
CHECK(ac.entryMap.count("format"));
3096
}
3097
3098
TEST_CASE_FIXTURE(ACFixture, "autocomplete_string_singletons_in_literal")
3099
{
3100
if (!FFlag::DebugLuauForceOldSolver)
3101
return;
3102
3103
// CLI-116814: Under the new solver, we fail to properly apply the expected
3104
// type to `tag` as we fail to recognize that we can "break apart" unions
3105
// when trying to apply an expected type.
3106
3107
check(R"(
3108
type tagged = {tag:"cat", fieldx:number} | {tag:"dog", fieldy:number}
3109
local x: tagged = {tag="@1"}
3110
)");
3111
3112
auto ac = autocomplete('1');
3113
3114
CHECK(ac.entryMap.count("cat"));
3115
CHECK(ac.entryMap.count("dog"));
3116
CHECK_EQ(ac.context, AutocompleteContext::String);
3117
}
3118
3119
TEST_CASE_FIXTURE(ACFixture, "autocomplete_string_singletons")
3120
{
3121
check(R"(
3122
type tag = "cat" | "dog"
3123
local function f(a: tag) end
3124
f("@1")
3125
f(@2)
3126
local x: tag = "@3"
3127
)");
3128
3129
auto ac = autocomplete('1');
3130
3131
CHECK(ac.entryMap.count("cat"));
3132
CHECK(ac.entryMap.count("dog"));
3133
CHECK_EQ(ac.context, AutocompleteContext::String);
3134
3135
ac = autocomplete('2');
3136
3137
CHECK(ac.entryMap.count("\"cat\""));
3138
CHECK(ac.entryMap.count("\"dog\""));
3139
CHECK_EQ(ac.context, AutocompleteContext::Expression);
3140
3141
ac = autocomplete('3');
3142
3143
CHECK(ac.entryMap.count("cat"));
3144
CHECK(ac.entryMap.count("dog"));
3145
CHECK_EQ(ac.context, AutocompleteContext::String);
3146
}
3147
3148
TEST_CASE_FIXTURE(ACFixture, "string_singleton_as_table_key_iso")
3149
{
3150
check(R"(
3151
type Direction = "up" | "down"
3152
local b: {[Direction]: boolean} = {["@2"] = true}
3153
)");
3154
3155
auto ac = autocomplete('2');
3156
3157
CHECK(ac.entryMap.count("up"));
3158
CHECK(ac.entryMap.count("down"));
3159
}
3160
3161
TEST_CASE_FIXTURE(ACFixture, "string_singleton_as_table_key")
3162
{
3163
check(R"(
3164
type Direction = "up" | "down"
3165
3166
local a: {[Direction]: boolean} = {[@1] = true}
3167
local b: {[Direction]: boolean} = {["@2"] = true}
3168
local c: {[Direction]: boolean} = {u@3 = true}
3169
local d: {[Direction]: boolean} = {[u@4] = true}
3170
3171
local e: {[Direction]: boolean} = {[@5]}
3172
local f: {[Direction]: boolean} = {["@6"]}
3173
local g: {[Direction]: boolean} = {u@7}
3174
local h: {[Direction]: boolean} = {[u@8]}
3175
)");
3176
3177
auto ac = autocomplete('1');
3178
3179
CHECK(ac.entryMap.count("\"up\""));
3180
CHECK(ac.entryMap.count("\"down\""));
3181
3182
ac = autocomplete('2');
3183
3184
CHECK(ac.entryMap.count("up"));
3185
CHECK(ac.entryMap.count("down"));
3186
3187
ac = autocomplete('3');
3188
3189
CHECK(ac.entryMap.count("up"));
3190
CHECK(ac.entryMap.count("down"));
3191
3192
ac = autocomplete('4');
3193
3194
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "up");
3195
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "down");
3196
3197
CHECK(ac.entryMap.count("\"up\""));
3198
CHECK(ac.entryMap.count("\"down\""));
3199
3200
ac = autocomplete('5');
3201
3202
CHECK(ac.entryMap.count("\"up\""));
3203
CHECK(ac.entryMap.count("\"down\""));
3204
3205
ac = autocomplete('6');
3206
3207
CHECK(ac.entryMap.count("up"));
3208
CHECK(ac.entryMap.count("down"));
3209
3210
ac = autocomplete('7');
3211
3212
CHECK(ac.entryMap.count("up"));
3213
CHECK(ac.entryMap.count("down"));
3214
3215
ac = autocomplete('8');
3216
3217
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "up");
3218
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "down");
3219
3220
CHECK(ac.entryMap.count("\"up\""));
3221
CHECK(ac.entryMap.count("\"down\""));
3222
}
3223
3224
// https://github.com/Roblox/luau/issues/858
3225
TEST_CASE_FIXTURE(ACFixture, "string_singleton_in_if_statement")
3226
{
3227
ScopedFastFlag sff[]{
3228
{FFlag::DebugLuauForceOldSolver, false},
3229
};
3230
3231
check(R"(
3232
--!strict
3233
3234
type Direction = "left" | "right"
3235
3236
local dir: Direction = "left"
3237
3238
if dir == @1"@2"@3 then end
3239
local a: {[Direction]: boolean} = {[@4"@5"@6]}
3240
3241
if dir == @7`@8`@9 then end
3242
local a: {[Direction]: boolean} = {[@A`@B`@C]}
3243
)");
3244
3245
Luau::AutocompleteResult ac;
3246
3247
ac = autocomplete('1');
3248
3249
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "left");
3250
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "right");
3251
3252
ac = autocomplete('2');
3253
3254
LUAU_CHECK_HAS_KEY(ac.entryMap, "left");
3255
LUAU_CHECK_HAS_KEY(ac.entryMap, "right");
3256
3257
ac = autocomplete('3');
3258
3259
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "left");
3260
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "right");
3261
3262
ac = autocomplete('4');
3263
3264
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "left");
3265
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "right");
3266
3267
ac = autocomplete('5');
3268
3269
LUAU_CHECK_HAS_KEY(ac.entryMap, "left");
3270
LUAU_CHECK_HAS_KEY(ac.entryMap, "right");
3271
3272
ac = autocomplete('6');
3273
3274
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "left");
3275
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "right");
3276
3277
ac = autocomplete('7');
3278
3279
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "left");
3280
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "right");
3281
3282
ac = autocomplete('8');
3283
3284
LUAU_CHECK_HAS_KEY(ac.entryMap, "left");
3285
LUAU_CHECK_HAS_KEY(ac.entryMap, "right");
3286
3287
ac = autocomplete('9');
3288
3289
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "left");
3290
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "right");
3291
3292
ac = autocomplete('A');
3293
3294
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "left");
3295
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "right");
3296
3297
ac = autocomplete('B');
3298
3299
LUAU_CHECK_HAS_KEY(ac.entryMap, "left");
3300
LUAU_CHECK_HAS_KEY(ac.entryMap, "right");
3301
3302
ac = autocomplete('C');
3303
3304
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "left");
3305
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "right");
3306
}
3307
3308
// https://github.com/Roblox/luau/issues/858
3309
TEST_CASE_FIXTURE(ACFixture, "string_singleton_in_if_statement2")
3310
{
3311
// don't run this when the DCR flag isn't set
3312
if (FFlag::DebugLuauForceOldSolver)
3313
return;
3314
3315
check(R"(
3316
--!strict
3317
3318
type Direction = "left" | "right"
3319
3320
local dir: Direction
3321
-- typestate here means dir is actually typed as `"left"`
3322
dir = "left"
3323
3324
if dir == @1"@2"@3 then end
3325
local a: {[Direction]: boolean} = {[@4"@5"@6]}
3326
3327
if dir == @7`@8`@9 then end
3328
local a: {[Direction]: boolean} = {[@A`@B`@C]}
3329
)");
3330
3331
Luau::AutocompleteResult ac;
3332
3333
ac = autocomplete('1');
3334
3335
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "left");
3336
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "right");
3337
3338
ac = autocomplete('2');
3339
3340
LUAU_CHECK_HAS_KEY(ac.entryMap, "left");
3341
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "right");
3342
3343
ac = autocomplete('3');
3344
3345
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "left");
3346
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "right");
3347
3348
ac = autocomplete('4');
3349
3350
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "left");
3351
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "right");
3352
3353
ac = autocomplete('5');
3354
3355
LUAU_CHECK_HAS_KEY(ac.entryMap, "left");
3356
LUAU_CHECK_HAS_KEY(ac.entryMap, "right");
3357
3358
ac = autocomplete('6');
3359
3360
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "left");
3361
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "right");
3362
3363
ac = autocomplete('7');
3364
3365
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "left");
3366
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "right");
3367
3368
ac = autocomplete('8');
3369
3370
LUAU_CHECK_HAS_KEY(ac.entryMap, "left");
3371
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "right");
3372
3373
ac = autocomplete('9');
3374
3375
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "left");
3376
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "right");
3377
3378
ac = autocomplete('A');
3379
3380
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "left");
3381
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "right");
3382
3383
ac = autocomplete('B');
3384
3385
LUAU_CHECK_HAS_KEY(ac.entryMap, "left");
3386
LUAU_CHECK_HAS_KEY(ac.entryMap, "right");
3387
3388
ac = autocomplete('C');
3389
3390
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "left");
3391
LUAU_CHECK_HAS_NO_KEY(ac.entryMap, "right");
3392
}
3393
3394
TEST_CASE_FIXTURE(ACFixture, "autocomplete_string_singleton_equality")
3395
{
3396
check(R"(
3397
type tagged = {tag:"cat", fieldx:number} | {tag:"dog", fieldy:number}
3398
local x: tagged = {tag="cat", fieldx=2}
3399
if x.tag == "@1" or "@2" ~= x.tag then end
3400
)");
3401
3402
auto ac = autocomplete('1');
3403
3404
CHECK(ac.entryMap.count("cat"));
3405
CHECK(ac.entryMap.count("dog"));
3406
3407
ac = autocomplete('2');
3408
3409
CHECK(ac.entryMap.count("cat"));
3410
CHECK(ac.entryMap.count("dog"));
3411
3412
// CLI-48823: assignment to x.tag should also autocomplete, but union l-values are not supported yet
3413
}
3414
3415
TEST_CASE_FIXTURE(ACFixture, "autocomplete_boolean_singleton")
3416
{
3417
check(R"(
3418
local function f(x: true) end
3419
f(@1)
3420
)");
3421
3422
auto ac = autocomplete('1');
3423
3424
REQUIRE(ac.entryMap.count("true"));
3425
CHECK(ac.entryMap["true"].typeCorrect == TypeCorrectKind::Correct);
3426
REQUIRE(ac.entryMap.count("false"));
3427
CHECK(ac.entryMap["false"].typeCorrect == TypeCorrectKind::None);
3428
CHECK_EQ(ac.context, AutocompleteContext::Expression);
3429
}
3430
3431
TEST_CASE_FIXTURE(ACFixture, "autocomplete_string_singleton_escape")
3432
{
3433
check(R"(
3434
type tag = "strange\t\"cat\"" | 'nice\t"dog"'
3435
local function f(x: tag) end
3436
f(@1)
3437
f("@2")
3438
)");
3439
3440
auto ac = autocomplete('1');
3441
3442
CHECK(ac.entryMap.count("\"strange\\t\\\"cat\\\"\""));
3443
CHECK(ac.entryMap.count("\"nice\\t\\\"dog\\\"\""));
3444
3445
ac = autocomplete('2');
3446
3447
CHECK(ac.entryMap.count("strange\\t\\\"cat\\\""));
3448
CHECK(ac.entryMap.count("nice\\t\\\"dog\\\""));
3449
}
3450
3451
TEST_CASE_FIXTURE(ACFixture, "function_in_assignment_has_parentheses_2")
3452
{
3453
check(R"(
3454
local bar: ((number) -> number) & (number, number) -> number)
3455
local abc = b@1
3456
)");
3457
3458
auto ac = autocomplete('1');
3459
3460
CHECK(ac.entryMap.count("bar"));
3461
CHECK(ac.entryMap["bar"].parens == ParenthesesRecommendation::CursorInside);
3462
}
3463
3464
TEST_CASE_FIXTURE(ACFixture, "no_incompatible_self_calls_on_class")
3465
{
3466
loadDefinition(R"(
3467
declare class Foo
3468
function one(self): number
3469
two: () -> number
3470
end
3471
)");
3472
3473
{
3474
check(R"(
3475
local function f(t: Foo)
3476
t:@1
3477
end
3478
)");
3479
3480
auto ac = autocomplete('1');
3481
3482
REQUIRE(ac.entryMap.count("one"));
3483
REQUIRE(ac.entryMap.count("two"));
3484
CHECK(!ac.entryMap["one"].wrongIndexType);
3485
CHECK(ac.entryMap["two"].wrongIndexType);
3486
CHECK(ac.entryMap["one"].indexedWithSelf);
3487
CHECK(ac.entryMap["two"].indexedWithSelf);
3488
}
3489
3490
{
3491
check(R"(
3492
local function f(t: Foo)
3493
t.@1
3494
end
3495
)");
3496
3497
auto ac = autocomplete('1');
3498
3499
REQUIRE(ac.entryMap.count("one"));
3500
REQUIRE(ac.entryMap.count("two"));
3501
CHECK(ac.entryMap["one"].wrongIndexType);
3502
CHECK(!ac.entryMap["two"].wrongIndexType);
3503
CHECK(!ac.entryMap["one"].indexedWithSelf);
3504
CHECK(!ac.entryMap["two"].indexedWithSelf);
3505
}
3506
}
3507
3508
TEST_CASE_FIXTURE(ACFixture, "simple")
3509
{
3510
check(R"(
3511
local t = {}
3512
function t:m() end
3513
t:m()
3514
)");
3515
3516
// auto ac = autocomplete('1');
3517
3518
// REQUIRE(ac.entryMap.count("m"));
3519
// CHECK(!ac.entryMap["m"].wrongIndexType);
3520
}
3521
3522
TEST_CASE_FIXTURE(ACFixture, "do_compatible_self_calls")
3523
{
3524
check(R"(
3525
local t = {}
3526
function t:m() end
3527
t:@1
3528
)");
3529
3530
auto ac = autocomplete('1');
3531
3532
REQUIRE(ac.entryMap.count("m"));
3533
CHECK(!ac.entryMap["m"].wrongIndexType);
3534
CHECK(ac.entryMap["m"].indexedWithSelf);
3535
}
3536
3537
TEST_CASE_FIXTURE(ACFixture, "no_incompatible_self_calls")
3538
{
3539
check(R"(
3540
local t = {}
3541
function t.m() end
3542
t:@1
3543
)");
3544
3545
auto ac = autocomplete('1');
3546
3547
REQUIRE(ac.entryMap.count("m"));
3548
CHECK(ac.entryMap["m"].wrongIndexType);
3549
CHECK(ac.entryMap["m"].indexedWithSelf);
3550
}
3551
3552
TEST_CASE_FIXTURE(ACFixture, "no_incompatible_self_calls_2")
3553
{
3554
check(R"(
3555
local f: (() -> number) & ((number) -> number) = function(x: number?) return 2 end
3556
local t = {}
3557
t.f = f
3558
t:@1
3559
)");
3560
3561
auto ac = autocomplete('1');
3562
3563
REQUIRE(ac.entryMap.count("f"));
3564
CHECK(ac.entryMap["f"].wrongIndexType);
3565
CHECK(ac.entryMap["f"].indexedWithSelf);
3566
}
3567
3568
TEST_CASE_FIXTURE(ACFixture, "do_wrong_compatible_self_calls")
3569
{
3570
check(R"(
3571
local t = {}
3572
function t.m(x: typeof(t)) end
3573
t:@1
3574
)");
3575
3576
auto ac = autocomplete('1');
3577
3578
REQUIRE(ac.entryMap.count("m"));
3579
// We can make changes to mark this as a wrong way to call even though it's compatible
3580
CHECK(!ac.entryMap["m"].wrongIndexType);
3581
CHECK(ac.entryMap["m"].indexedWithSelf);
3582
}
3583
3584
TEST_CASE_FIXTURE(ACFixture, "do_wrong_compatible_nonself_calls")
3585
{
3586
check(R"(
3587
local t = {}
3588
function t:m(x: string) end
3589
t.@1
3590
)");
3591
3592
auto ac = autocomplete('1');
3593
3594
REQUIRE(ac.entryMap.count("m"));
3595
3596
if (!FFlag::DebugLuauForceOldSolver)
3597
CHECK(ac.entryMap["m"].wrongIndexType);
3598
else
3599
CHECK(!ac.entryMap["m"].wrongIndexType);
3600
CHECK(!ac.entryMap["m"].indexedWithSelf);
3601
}
3602
3603
TEST_CASE_FIXTURE(ACFixture, "no_wrong_compatible_self_calls_with_generics")
3604
{
3605
check(R"(
3606
local t = {}
3607
function t.m<T>(a: T) end
3608
t:@1
3609
)");
3610
3611
auto ac = autocomplete('1');
3612
3613
REQUIRE(ac.entryMap.count("m"));
3614
// While this call is compatible with the type, this requires instantiation of a generic type which we don't perform
3615
CHECK(ac.entryMap["m"].wrongIndexType);
3616
CHECK(ac.entryMap["m"].indexedWithSelf);
3617
}
3618
3619
TEST_CASE_FIXTURE(ACFixture, "string_prim_self_calls_are_fine")
3620
{
3621
check(R"(
3622
local s = "hello"
3623
s:@1
3624
)");
3625
3626
auto ac = autocomplete('1');
3627
3628
REQUIRE(ac.entryMap.count("byte"));
3629
CHECK(ac.entryMap["byte"].wrongIndexType == false);
3630
CHECK(ac.entryMap["byte"].indexedWithSelf);
3631
REQUIRE(ac.entryMap.count("char"));
3632
CHECK(ac.entryMap["char"].wrongIndexType == true);
3633
CHECK(ac.entryMap["char"].indexedWithSelf);
3634
REQUIRE(ac.entryMap.count("sub"));
3635
CHECK(ac.entryMap["sub"].wrongIndexType == false);
3636
CHECK(ac.entryMap["sub"].indexedWithSelf);
3637
}
3638
3639
TEST_CASE_FIXTURE(ACFixture, "string_prim_non_self_calls_are_avoided")
3640
{
3641
check(R"(
3642
local s = "hello"
3643
s.@1
3644
)");
3645
3646
auto ac = autocomplete('1');
3647
3648
REQUIRE(ac.entryMap.count("char"));
3649
CHECK(ac.entryMap["char"].wrongIndexType == false);
3650
CHECK(!ac.entryMap["char"].indexedWithSelf);
3651
REQUIRE(ac.entryMap.count("sub"));
3652
CHECK(ac.entryMap["sub"].wrongIndexType == true);
3653
CHECK(!ac.entryMap["sub"].indexedWithSelf);
3654
}
3655
3656
TEST_CASE_FIXTURE(ACBuiltinsFixture, "library_non_self_calls_are_fine")
3657
{
3658
check(R"(
3659
string.@1
3660
)");
3661
3662
auto ac = autocomplete('1');
3663
3664
REQUIRE(ac.entryMap.count("byte"));
3665
CHECK(ac.entryMap["byte"].wrongIndexType == false);
3666
CHECK(!ac.entryMap["byte"].indexedWithSelf);
3667
REQUIRE(ac.entryMap.count("char"));
3668
CHECK(ac.entryMap["char"].wrongIndexType == false);
3669
CHECK(!ac.entryMap["char"].indexedWithSelf);
3670
REQUIRE(ac.entryMap.count("sub"));
3671
CHECK(ac.entryMap["sub"].wrongIndexType == false);
3672
CHECK(!ac.entryMap["sub"].indexedWithSelf);
3673
3674
check(R"(
3675
table.@1
3676
)");
3677
3678
ac = autocomplete('1');
3679
3680
REQUIRE(ac.entryMap.count("remove"));
3681
CHECK(ac.entryMap["remove"].wrongIndexType == false);
3682
CHECK(!ac.entryMap["remove"].indexedWithSelf);
3683
REQUIRE(ac.entryMap.count("getn"));
3684
CHECK(ac.entryMap["getn"].wrongIndexType == false);
3685
CHECK(!ac.entryMap["getn"].indexedWithSelf);
3686
REQUIRE(ac.entryMap.count("insert"));
3687
CHECK(ac.entryMap["insert"].wrongIndexType == false);
3688
CHECK(!ac.entryMap["insert"].indexedWithSelf);
3689
}
3690
3691
TEST_CASE_FIXTURE(ACBuiltinsFixture, "library_self_calls_are_invalid")
3692
{
3693
check(R"(
3694
string:@1
3695
)");
3696
3697
auto ac = autocomplete('1');
3698
3699
REQUIRE(ac.entryMap.count("byte"));
3700
CHECK(ac.entryMap["byte"].wrongIndexType == true);
3701
CHECK(ac.entryMap["byte"].indexedWithSelf);
3702
REQUIRE(ac.entryMap.count("char"));
3703
CHECK(ac.entryMap["char"].wrongIndexType == true);
3704
CHECK(ac.entryMap["char"].indexedWithSelf);
3705
3706
// We want the next test to evaluate to 'true', but we have to allow function defined with 'self' to be callable with ':'
3707
// We may change the definition of the string metatable to not use 'self' types in the future (like byte/char/pack/unpack)
3708
REQUIRE(ac.entryMap.count("sub"));
3709
CHECK(ac.entryMap["sub"].wrongIndexType == false);
3710
CHECK(ac.entryMap["sub"].indexedWithSelf);
3711
}
3712
3713
TEST_CASE_FIXTURE(ACFixture, "source_module_preservation_and_invalidation")
3714
{
3715
check(R"(
3716
local a = { x = 2, y = 4 }
3717
a.@1
3718
)");
3719
3720
getFrontend().clear();
3721
3722
auto ac = autocomplete('1');
3723
3724
CHECK(2 == ac.entryMap.size());
3725
3726
CHECK(ac.entryMap.count("x"));
3727
CHECK(ac.entryMap.count("y"));
3728
3729
getFrontend().check("MainModule", {});
3730
3731
ac = autocomplete('1');
3732
3733
CHECK(ac.entryMap.count("x"));
3734
CHECK(ac.entryMap.count("y"));
3735
3736
getFrontend().markDirty("MainModule", nullptr);
3737
3738
ac = autocomplete('1');
3739
3740
CHECK(ac.entryMap.count("x"));
3741
CHECK(ac.entryMap.count("y"));
3742
3743
getFrontend().check("MainModule", {});
3744
3745
ac = autocomplete('1');
3746
3747
CHECK(ac.entryMap.count("x"));
3748
CHECK(ac.entryMap.count("y"));
3749
}
3750
3751
TEST_CASE_FIXTURE(ACFixture, "globals_are_order_independent")
3752
{
3753
check(R"(
3754
local myLocal = 4
3755
function abc0()
3756
local myInnerLocal = 1
3757
@1
3758
end
3759
3760
function abc1()
3761
local myInnerLocal = 1
3762
end
3763
)");
3764
3765
auto ac = autocomplete('1');
3766
CHECK(ac.entryMap.count("myLocal"));
3767
CHECK(ac.entryMap.count("myInnerLocal"));
3768
CHECK(ac.entryMap.count("abc0"));
3769
CHECK(ac.entryMap.count("abc1"));
3770
}
3771
3772
TEST_CASE_FIXTURE(ACFixture, "string_contents_is_available_to_callback")
3773
{
3774
loadDefinition(R"(
3775
declare function require(path: string): any
3776
)");
3777
3778
GlobalTypes& globals = !FFlag::DebugLuauForceOldSolver ? getFrontend().globals : getFrontend().globalsForAutocomplete;
3779
3780
std::optional<Binding> require = globals.globalScope->linearSearchForBinding("require");
3781
REQUIRE(require);
3782
Luau::unfreeze(globals.globalTypes);
3783
attachTag(require->typeId, "RequireCall");
3784
Luau::freeze(globals.globalTypes);
3785
3786
check(R"(
3787
local x = require("testing/@1")
3788
)");
3789
3790
bool isCorrect = false;
3791
auto ac1 = autocomplete(
3792
'1',
3793
[&isCorrect](std::string, std::optional<const ExternType*>, std::optional<std::string> contents) -> std::optional<AutocompleteEntryMap>
3794
{
3795
isCorrect = contents && *contents == "testing/";
3796
return std::nullopt;
3797
}
3798
);
3799
3800
CHECK(isCorrect);
3801
}
3802
3803
TEST_CASE_FIXTURE(ACBuiltinsFixture, "require_by_string")
3804
{
3805
fileResolver.source["MainModule"] = R"(
3806
local info = "MainModule serves as the root directory"
3807
)";
3808
3809
fileResolver.source["MainModule/Folder"] = R"(
3810
local info = "MainModule/Folder serves as a subdirectory"
3811
)";
3812
3813
fileResolver.source["MainModule/Folder/Requirer"] = R"(
3814
local res0 = require("@")
3815
3816
local res1 = require(".")
3817
local res2 = require("./")
3818
local res3 = require("./Sib")
3819
3820
local res4 = require("..")
3821
local res5 = require("../")
3822
local res6 = require("../Sib")
3823
)";
3824
3825
fileResolver.source["MainModule/Folder/SiblingDependency"] = R"(
3826
return {"result"}
3827
)";
3828
3829
fileResolver.source["MainModule/ParentDependency"] = R"(
3830
return {"result"}
3831
)";
3832
3833
struct RequireCompletion
3834
{
3835
std::string label;
3836
std::string insertText;
3837
};
3838
3839
auto checkEntries = [](const AutocompleteEntryMap& entryMap, const std::vector<RequireCompletion>& completions)
3840
{
3841
CHECK(completions.size() == entryMap.size());
3842
for (const auto& completion : completions)
3843
{
3844
CHECK(entryMap.count(completion.label));
3845
CHECK(entryMap.at(completion.label).insertText == completion.insertText);
3846
}
3847
};
3848
3849
AutocompleteResult acResult;
3850
acResult = autocomplete("MainModule/Folder/Requirer", Position{1, 31});
3851
checkEntries(acResult.entryMap, {{"@defaultalias", "@defaultalias"}, {"./", "./"}, {"../", "../"}});
3852
3853
acResult = autocomplete("MainModule/Folder/Requirer", Position{3, 31});
3854
checkEntries(acResult.entryMap, {{"@defaultalias", "@defaultalias"}, {"./", "./"}, {"../", "../"}});
3855
acResult = autocomplete("MainModule/Folder/Requirer", Position{4, 32});
3856
checkEntries(acResult.entryMap, {{"..", "."}, {"Requirer", "./Requirer"}, {"SiblingDependency", "./SiblingDependency"}});
3857
acResult = autocomplete("MainModule/Folder/Requirer", Position{5, 35});
3858
checkEntries(acResult.entryMap, {{"..", "."}, {"Requirer", "./Requirer"}, {"SiblingDependency", "./SiblingDependency"}});
3859
3860
acResult = autocomplete("MainModule/Folder/Requirer", Position{7, 32});
3861
checkEntries(acResult.entryMap, {{"@defaultalias", "@defaultalias"}, {"./", "./"}, {"../", "../"}});
3862
acResult = autocomplete("MainModule/Folder/Requirer", Position{8, 33});
3863
checkEntries(acResult.entryMap, {{"..", "../.."}, {"Folder", "../Folder"}, {"ParentDependency", "../ParentDependency"}});
3864
acResult = autocomplete("MainModule/Folder/Requirer", Position{9, 36});
3865
checkEntries(acResult.entryMap, {{"..", "../.."}, {"Folder", "../Folder"}, {"ParentDependency", "../ParentDependency"}});
3866
}
3867
3868
TEST_CASE_FIXTURE(ACFixture, "autocomplete_response_perf1" * doctest::timeout(0.5))
3869
{
3870
if (!FFlag::DebugLuauForceOldSolver)
3871
return; // FIXME: This test is just barely at the threshhold which makes it very flaky under the new solver
3872
3873
// Build a function type with a large overload set
3874
const int parts = 100;
3875
std::string source;
3876
3877
for (int i = 0; i < parts; i++)
3878
formatAppend(source, "type T%d = { f%d: number }\n", i, i);
3879
3880
source += "type Instance = { new: (('s0', extra: Instance?) -> T0)";
3881
3882
for (int i = 1; i < parts; i++)
3883
formatAppend(source, " & (('s%d', extra: Instance?) -> T%d)", i, i);
3884
3885
source += " }\n";
3886
3887
source += "local Instance: Instance = {} :: any\n";
3888
source += "local function c(): boolean return t@1 end\n";
3889
3890
check(source);
3891
3892
auto ac = autocomplete('1');
3893
3894
CHECK(ac.entryMap.count("true"));
3895
CHECK(ac.entryMap.count("Instance"));
3896
}
3897
3898
TEST_CASE_FIXTURE(ACFixture, "autocomplete_subtyping_recursion_limit")
3899
{
3900
// TODO: in old solver, type resolve can't handle the type in this test without a stack overflow
3901
if (FFlag::DebugLuauForceOldSolver)
3902
return;
3903
3904
ScopedFastInt luauTypeInferRecursionLimit{FInt::LuauTypeInferRecursionLimit, 10};
3905
ScopedFastInt luauSubtypingRecursionLimit{DFInt::LuauSubtypingRecursionLimit, 10};
3906
3907
const int parts = 100;
3908
std::string source;
3909
3910
source += "function f()\n";
3911
3912
std::string prefix;
3913
for (int i = 0; i < parts; i++)
3914
formatAppend(prefix, "(nil|({a%d:number}&", i);
3915
formatAppend(prefix, "(nil|{a%d:number})", parts);
3916
for (int i = 0; i < parts; i++)
3917
formatAppend(prefix, "))");
3918
3919
source += "local x1 : " + prefix + "\n";
3920
source += "local y : {a1:number} = x@1\n";
3921
3922
source += "end\n";
3923
3924
check(source);
3925
3926
auto ac = autocomplete('1');
3927
3928
CHECK(ac.entryMap.count("true"));
3929
CHECK(ac.entryMap.count("x1"));
3930
}
3931
3932
TEST_CASE_FIXTURE(ACFixture, "strict_mode_force")
3933
{
3934
check(R"(
3935
--!nonstrict
3936
local a: {x: number} = {x=1}
3937
local b = a
3938
local c = b.@1
3939
)");
3940
3941
auto ac = autocomplete('1');
3942
3943
CHECK_EQ(1, ac.entryMap.size());
3944
CHECK(ac.entryMap.count("x"));
3945
}
3946
3947
TEST_CASE_FIXTURE(ACFixture, "suggest_exported_types")
3948
{
3949
check(R"(
3950
export type Type = {a: number}
3951
local a: T@1
3952
)");
3953
3954
auto ac = autocomplete('1');
3955
3956
CHECK(ac.entryMap.count("Type"));
3957
CHECK_EQ(ac.context, AutocompleteContext::Type);
3958
}
3959
3960
TEST_CASE_FIXTURE(ACFixture, "getFrontend().use_correct_global_scope")
3961
{
3962
loadDefinition(R"(
3963
declare class Instance
3964
Name: string
3965
end
3966
)");
3967
3968
CheckResult result = check(R"(
3969
local a: unknown = nil
3970
if typeof(a) == "Instance" then
3971
local b = a.@1
3972
end
3973
)");
3974
auto ac = autocomplete('1');
3975
3976
CHECK_EQ(1, ac.entryMap.size());
3977
CHECK(ac.entryMap.count("Name"));
3978
}
3979
3980
TEST_CASE_FIXTURE(ACFixture, "string_completion_outside_quotes")
3981
{
3982
loadDefinition(R"(
3983
declare function require(path: string): any
3984
)");
3985
3986
GlobalTypes& globals = !FFlag::DebugLuauForceOldSolver ? getFrontend().globals : getFrontend().globalsForAutocomplete;
3987
3988
std::optional<Binding> require = globals.globalScope->linearSearchForBinding("require");
3989
REQUIRE(require);
3990
Luau::unfreeze(globals.globalTypes);
3991
attachTag(require->typeId, "RequireCall");
3992
Luau::freeze(globals.globalTypes);
3993
3994
check(R"(
3995
local x = require(@1"@2"@3)
3996
)");
3997
3998
StringCompletionCallback callback =
3999
[](std::string, std::optional<const ExternType*>, std::optional<std::string> contents) -> std::optional<AutocompleteEntryMap>
4000
{
4001
Luau::AutocompleteEntryMap results = {{"test", Luau::AutocompleteEntry{Luau::AutocompleteEntryKind::String, std::nullopt, false, false}}};
4002
return results;
4003
};
4004
4005
auto ac = autocomplete('2', callback);
4006
4007
CHECK_EQ(1, ac.entryMap.size());
4008
CHECK(ac.entryMap.count("test"));
4009
4010
ac = autocomplete('1', callback);
4011
4012
CHECK_EQ(0, ac.entryMap.size());
4013
4014
ac = autocomplete('3', callback);
4015
4016
CHECK_EQ(0, ac.entryMap.size());
4017
}
4018
4019
TEST_CASE_FIXTURE(ACFixture, "anonymous_autofilled_empty")
4020
{
4021
check(R"(
4022
local function foo(a: () -> ())
4023
a()
4024
end
4025
4026
foo(@1)
4027
)");
4028
4029
const std::optional<std::string> EXPECTED_INSERT = "function() end";
4030
4031
auto ac = autocomplete('1');
4032
4033
REQUIRE(ac.entryMap.count(kGeneratedAnonymousFunctionEntryName) == 1);
4034
CHECK(ac.entryMap[kGeneratedAnonymousFunctionEntryName].kind == Luau::AutocompleteEntryKind::GeneratedFunction);
4035
CHECK(ac.entryMap[kGeneratedAnonymousFunctionEntryName].typeCorrect == Luau::TypeCorrectKind::Correct);
4036
REQUIRE(ac.entryMap[kGeneratedAnonymousFunctionEntryName].insertText);
4037
CHECK_EQ(EXPECTED_INSERT, *ac.entryMap[kGeneratedAnonymousFunctionEntryName].insertText);
4038
}
4039
4040
TEST_CASE_FIXTURE(ACFixture, "anonymous_autofilled_args")
4041
{
4042
check(R"(
4043
local function foo(a: (number, string) -> ())
4044
a()
4045
end
4046
4047
foo(@1)
4048
)");
4049
4050
const std::optional<std::string> EXPECTED_INSERT = "function(a0: number, a1: string) end";
4051
4052
auto ac = autocomplete('1');
4053
4054
REQUIRE(ac.entryMap.count(kGeneratedAnonymousFunctionEntryName) == 1);
4055
CHECK(ac.entryMap[kGeneratedAnonymousFunctionEntryName].kind == Luau::AutocompleteEntryKind::GeneratedFunction);
4056
CHECK(ac.entryMap[kGeneratedAnonymousFunctionEntryName].typeCorrect == Luau::TypeCorrectKind::Correct);
4057
REQUIRE(ac.entryMap[kGeneratedAnonymousFunctionEntryName].insertText);
4058
CHECK_EQ(EXPECTED_INSERT, *ac.entryMap[kGeneratedAnonymousFunctionEntryName].insertText);
4059
}
4060
4061
TEST_CASE_FIXTURE(ACFixture, "anonymous_autofilled_args_single_return")
4062
{
4063
check(R"(
4064
local function foo(a: (number, string) -> (string))
4065
a()
4066
end
4067
4068
foo(@1)
4069
)");
4070
4071
const std::optional<std::string> EXPECTED_INSERT = "function(a0: number, a1: string): string end";
4072
4073
auto ac = autocomplete('1');
4074
4075
REQUIRE(ac.entryMap.count(kGeneratedAnonymousFunctionEntryName) == 1);
4076
CHECK(ac.entryMap[kGeneratedAnonymousFunctionEntryName].kind == Luau::AutocompleteEntryKind::GeneratedFunction);
4077
CHECK(ac.entryMap[kGeneratedAnonymousFunctionEntryName].typeCorrect == Luau::TypeCorrectKind::Correct);
4078
REQUIRE(ac.entryMap[kGeneratedAnonymousFunctionEntryName].insertText);
4079
CHECK_EQ(EXPECTED_INSERT, *ac.entryMap[kGeneratedAnonymousFunctionEntryName].insertText);
4080
}
4081
4082
TEST_CASE_FIXTURE(ACFixture, "anonymous_autofilled_args_multi_return")
4083
{
4084
check(R"(
4085
local function foo(a: (number, string) -> (string, number))
4086
a()
4087
end
4088
4089
foo(@1)
4090
)");
4091
4092
const std::optional<std::string> EXPECTED_INSERT = "function(a0: number, a1: string): (string, number) end";
4093
4094
auto ac = autocomplete('1');
4095
4096
REQUIRE(ac.entryMap.count(kGeneratedAnonymousFunctionEntryName) == 1);
4097
CHECK(ac.entryMap[kGeneratedAnonymousFunctionEntryName].kind == Luau::AutocompleteEntryKind::GeneratedFunction);
4098
CHECK(ac.entryMap[kGeneratedAnonymousFunctionEntryName].typeCorrect == Luau::TypeCorrectKind::Correct);
4099
REQUIRE(ac.entryMap[kGeneratedAnonymousFunctionEntryName].insertText);
4100
CHECK_EQ(EXPECTED_INSERT, *ac.entryMap[kGeneratedAnonymousFunctionEntryName].insertText);
4101
}
4102
4103
TEST_CASE_FIXTURE(ACFixture, "anonymous_autofilled__noargs_multi_return")
4104
{
4105
check(R"(
4106
local function foo(a: () -> (string, number))
4107
a()
4108
end
4109
4110
foo(@1)
4111
)");
4112
4113
const std::optional<std::string> EXPECTED_INSERT = "function(): (string, number) end";
4114
4115
auto ac = autocomplete('1');
4116
4117
REQUIRE(ac.entryMap.count(kGeneratedAnonymousFunctionEntryName) == 1);
4118
CHECK(ac.entryMap[kGeneratedAnonymousFunctionEntryName].kind == Luau::AutocompleteEntryKind::GeneratedFunction);
4119
CHECK(ac.entryMap[kGeneratedAnonymousFunctionEntryName].typeCorrect == Luau::TypeCorrectKind::Correct);
4120
REQUIRE(ac.entryMap[kGeneratedAnonymousFunctionEntryName].insertText);
4121
CHECK_EQ(EXPECTED_INSERT, *ac.entryMap[kGeneratedAnonymousFunctionEntryName].insertText);
4122
}
4123
4124
TEST_CASE_FIXTURE(ACFixture, "anonymous_autofilled__varargs_multi_return")
4125
{
4126
check(R"(
4127
local function foo(a: (...number) -> (string, number))
4128
a()
4129
end
4130
4131
foo(@1)
4132
)");
4133
4134
const std::optional<std::string> EXPECTED_INSERT = "function(...: number): (string, number) end";
4135
4136
auto ac = autocomplete('1');
4137
4138
REQUIRE(ac.entryMap.count(kGeneratedAnonymousFunctionEntryName) == 1);
4139
CHECK(ac.entryMap[kGeneratedAnonymousFunctionEntryName].kind == Luau::AutocompleteEntryKind::GeneratedFunction);
4140
CHECK(ac.entryMap[kGeneratedAnonymousFunctionEntryName].typeCorrect == Luau::TypeCorrectKind::Correct);
4141
REQUIRE(ac.entryMap[kGeneratedAnonymousFunctionEntryName].insertText);
4142
CHECK_EQ(EXPECTED_INSERT, *ac.entryMap[kGeneratedAnonymousFunctionEntryName].insertText);
4143
}
4144
4145
TEST_CASE_FIXTURE(ACFixture, "anonymous_autofilled_multi_varargs_multi_return")
4146
{
4147
check(R"(
4148
local function foo(a: (string, ...number) -> (string, number))
4149
a()
4150
end
4151
4152
foo(@1)
4153
)");
4154
4155
const std::optional<std::string> EXPECTED_INSERT = "function(a0: string, ...: number): (string, number) end";
4156
4157
auto ac = autocomplete('1');
4158
4159
REQUIRE(ac.entryMap.count(kGeneratedAnonymousFunctionEntryName) == 1);
4160
CHECK(ac.entryMap[kGeneratedAnonymousFunctionEntryName].kind == Luau::AutocompleteEntryKind::GeneratedFunction);
4161
CHECK(ac.entryMap[kGeneratedAnonymousFunctionEntryName].typeCorrect == Luau::TypeCorrectKind::Correct);
4162
REQUIRE(ac.entryMap[kGeneratedAnonymousFunctionEntryName].insertText);
4163
CHECK_EQ(EXPECTED_INSERT, *ac.entryMap[kGeneratedAnonymousFunctionEntryName].insertText);
4164
}
4165
4166
TEST_CASE_FIXTURE(ACFixture, "anonymous_autofilled_multi_varargs_varargs_return")
4167
{
4168
check(R"(
4169
local function foo(a: (string, ...number) -> ...number)
4170
a()
4171
end
4172
4173
foo(@1)
4174
)");
4175
4176
const std::optional<std::string> EXPECTED_INSERT = "function(a0: string, ...: number): ...number end";
4177
4178
auto ac = autocomplete('1');
4179
4180
REQUIRE(ac.entryMap.count(kGeneratedAnonymousFunctionEntryName) == 1);
4181
CHECK(ac.entryMap[kGeneratedAnonymousFunctionEntryName].kind == Luau::AutocompleteEntryKind::GeneratedFunction);
4182
CHECK(ac.entryMap[kGeneratedAnonymousFunctionEntryName].typeCorrect == Luau::TypeCorrectKind::Correct);
4183
REQUIRE(ac.entryMap[kGeneratedAnonymousFunctionEntryName].insertText);
4184
CHECK_EQ(EXPECTED_INSERT, *ac.entryMap[kGeneratedAnonymousFunctionEntryName].insertText);
4185
}
4186
4187
TEST_CASE_FIXTURE(ACFixture, "anonymous_autofilled_multi_varargs_multi_varargs_return")
4188
{
4189
check(R"(
4190
local function foo(a: (string, ...number) -> (boolean, ...number))
4191
a()
4192
end
4193
4194
foo(@1)
4195
)");
4196
4197
const std::optional<std::string> EXPECTED_INSERT = "function(a0: string, ...: number): (boolean, ...number) end";
4198
4199
auto ac = autocomplete('1');
4200
4201
REQUIRE(ac.entryMap.count(kGeneratedAnonymousFunctionEntryName) == 1);
4202
CHECK(ac.entryMap[kGeneratedAnonymousFunctionEntryName].kind == Luau::AutocompleteEntryKind::GeneratedFunction);
4203
CHECK(ac.entryMap[kGeneratedAnonymousFunctionEntryName].typeCorrect == Luau::TypeCorrectKind::Correct);
4204
REQUIRE(ac.entryMap[kGeneratedAnonymousFunctionEntryName].insertText);
4205
CHECK_EQ(EXPECTED_INSERT, *ac.entryMap[kGeneratedAnonymousFunctionEntryName].insertText);
4206
}
4207
4208
TEST_CASE_FIXTURE(ACFixture, "anonymous_autofilled_named_args")
4209
{
4210
check(R"(
4211
local function foo(a: (foo: number, bar: string) -> (string, number))
4212
a()
4213
end
4214
4215
foo(@1)
4216
)");
4217
4218
const std::optional<std::string> EXPECTED_INSERT = "function(foo: number, bar: string): (string, number) end";
4219
4220
auto ac = autocomplete('1');
4221
4222
REQUIRE(ac.entryMap.count(kGeneratedAnonymousFunctionEntryName) == 1);
4223
CHECK(ac.entryMap[kGeneratedAnonymousFunctionEntryName].kind == Luau::AutocompleteEntryKind::GeneratedFunction);
4224
CHECK(ac.entryMap[kGeneratedAnonymousFunctionEntryName].typeCorrect == Luau::TypeCorrectKind::Correct);
4225
REQUIRE(ac.entryMap[kGeneratedAnonymousFunctionEntryName].insertText);
4226
CHECK_EQ(EXPECTED_INSERT, *ac.entryMap[kGeneratedAnonymousFunctionEntryName].insertText);
4227
}
4228
4229
TEST_CASE_FIXTURE(ACFixture, "anonymous_autofilled_partially_args")
4230
{
4231
check(R"(
4232
local function foo(a: (number, bar: string) -> (string, number))
4233
a()
4234
end
4235
4236
foo(@1)
4237
)");
4238
4239
const std::optional<std::string> EXPECTED_INSERT = "function(a0: number, bar: string): (string, number) end";
4240
4241
auto ac = autocomplete('1');
4242
4243
REQUIRE(ac.entryMap.count(kGeneratedAnonymousFunctionEntryName) == 1);
4244
CHECK(ac.entryMap[kGeneratedAnonymousFunctionEntryName].kind == Luau::AutocompleteEntryKind::GeneratedFunction);
4245
CHECK(ac.entryMap[kGeneratedAnonymousFunctionEntryName].typeCorrect == Luau::TypeCorrectKind::Correct);
4246
REQUIRE(ac.entryMap[kGeneratedAnonymousFunctionEntryName].insertText);
4247
CHECK_EQ(EXPECTED_INSERT, *ac.entryMap[kGeneratedAnonymousFunctionEntryName].insertText);
4248
}
4249
4250
TEST_CASE_FIXTURE(ACFixture, "anonymous_autofilled_partially_args_last")
4251
{
4252
check(R"(
4253
local function foo(a: (foo: number, string) -> (string, number))
4254
a()
4255
end
4256
4257
foo(@1)
4258
)");
4259
4260
const std::optional<std::string> EXPECTED_INSERT = "function(foo: number, a1: string): (string, number) end";
4261
4262
auto ac = autocomplete('1');
4263
4264
REQUIRE(ac.entryMap.count(kGeneratedAnonymousFunctionEntryName) == 1);
4265
CHECK(ac.entryMap[kGeneratedAnonymousFunctionEntryName].kind == Luau::AutocompleteEntryKind::GeneratedFunction);
4266
CHECK(ac.entryMap[kGeneratedAnonymousFunctionEntryName].typeCorrect == Luau::TypeCorrectKind::Correct);
4267
REQUIRE(ac.entryMap[kGeneratedAnonymousFunctionEntryName].insertText);
4268
CHECK_EQ(EXPECTED_INSERT, *ac.entryMap[kGeneratedAnonymousFunctionEntryName].insertText);
4269
}
4270
4271
TEST_CASE_FIXTURE(ACFixture, "anonymous_autofilled_typeof_args")
4272
{
4273
check(R"(
4274
local t = { a = 1, b = 2 }
4275
4276
local function foo(a: (foo: typeof(t)) -> ())
4277
a()
4278
end
4279
4280
foo(@1)
4281
)");
4282
4283
const std::optional<std::string> EXPECTED_INSERT = "function(foo) end"; // Cannot utter this type.
4284
4285
auto ac = autocomplete('1');
4286
4287
REQUIRE(ac.entryMap.count(kGeneratedAnonymousFunctionEntryName) == 1);
4288
CHECK(ac.entryMap[kGeneratedAnonymousFunctionEntryName].kind == Luau::AutocompleteEntryKind::GeneratedFunction);
4289
CHECK(ac.entryMap[kGeneratedAnonymousFunctionEntryName].typeCorrect == Luau::TypeCorrectKind::Correct);
4290
REQUIRE(ac.entryMap[kGeneratedAnonymousFunctionEntryName].insertText);
4291
CHECK_EQ(EXPECTED_INSERT, *ac.entryMap[kGeneratedAnonymousFunctionEntryName].insertText);
4292
}
4293
4294
TEST_CASE_FIXTURE(ACFixture, "anonymous_autofilled_table_literal_args")
4295
{
4296
check(R"(
4297
local function foo(a: (tbl: { x: number, y: number }) -> number) return a({x=2, y = 3}) end
4298
foo(@1)
4299
)");
4300
4301
const std::optional<std::string> EXPECTED_INSERT = "function(tbl: { x: number, y: number }): number end";
4302
4303
auto ac = autocomplete('1');
4304
4305
REQUIRE(ac.entryMap.count(kGeneratedAnonymousFunctionEntryName) == 1);
4306
CHECK(ac.entryMap[kGeneratedAnonymousFunctionEntryName].kind == Luau::AutocompleteEntryKind::GeneratedFunction);
4307
CHECK(ac.entryMap[kGeneratedAnonymousFunctionEntryName].typeCorrect == Luau::TypeCorrectKind::Correct);
4308
REQUIRE(ac.entryMap[kGeneratedAnonymousFunctionEntryName].insertText);
4309
CHECK_EQ(EXPECTED_INSERT, *ac.entryMap[kGeneratedAnonymousFunctionEntryName].insertText);
4310
}
4311
4312
TEST_CASE_FIXTURE(ACFixture, "anonymous_autofilled_typeof_returns")
4313
{
4314
check(R"(
4315
local t = { a = 1, b = 2 }
4316
4317
local function foo(a: () -> typeof(t))
4318
a()
4319
end
4320
4321
foo(@1)
4322
)");
4323
4324
const std::optional<std::string> EXPECTED_INSERT = "function() end"; // Cannot utter this type.
4325
4326
auto ac = autocomplete('1');
4327
4328
REQUIRE(ac.entryMap.count(kGeneratedAnonymousFunctionEntryName) == 1);
4329
CHECK(ac.entryMap[kGeneratedAnonymousFunctionEntryName].kind == Luau::AutocompleteEntryKind::GeneratedFunction);
4330
CHECK(ac.entryMap[kGeneratedAnonymousFunctionEntryName].typeCorrect == Luau::TypeCorrectKind::Correct);
4331
REQUIRE(ac.entryMap[kGeneratedAnonymousFunctionEntryName].insertText);
4332
CHECK_EQ(EXPECTED_INSERT, *ac.entryMap[kGeneratedAnonymousFunctionEntryName].insertText);
4333
}
4334
4335
TEST_CASE_FIXTURE(ACFixture, "anonymous_autofilled_table_literal_args")
4336
{
4337
check(R"(
4338
local function foo(a: () -> { x: number, y: number }) return {x=2, y = 3} end
4339
foo(@1)
4340
)");
4341
4342
const std::optional<std::string> EXPECTED_INSERT = "function(): { x: number, y: number } end";
4343
4344
auto ac = autocomplete('1');
4345
4346
REQUIRE(ac.entryMap.count(kGeneratedAnonymousFunctionEntryName) == 1);
4347
CHECK(ac.entryMap[kGeneratedAnonymousFunctionEntryName].kind == Luau::AutocompleteEntryKind::GeneratedFunction);
4348
CHECK(ac.entryMap[kGeneratedAnonymousFunctionEntryName].typeCorrect == Luau::TypeCorrectKind::Correct);
4349
REQUIRE(ac.entryMap[kGeneratedAnonymousFunctionEntryName].insertText);
4350
CHECK_EQ(EXPECTED_INSERT, *ac.entryMap[kGeneratedAnonymousFunctionEntryName].insertText);
4351
}
4352
4353
TEST_CASE_FIXTURE(ACFixture, "anonymous_autofilled_typeof_vararg")
4354
{
4355
check(R"(
4356
local t = { a = 1, b = 2 }
4357
4358
local function foo(a: (...typeof(t)) -> ())
4359
a()
4360
end
4361
4362
foo(@1)
4363
)");
4364
4365
const std::optional<std::string> EXPECTED_INSERT = "function(...) end"; // Cannot utter this type.
4366
4367
auto ac = autocomplete('1');
4368
4369
REQUIRE(ac.entryMap.count(kGeneratedAnonymousFunctionEntryName) == 1);
4370
CHECK(ac.entryMap[kGeneratedAnonymousFunctionEntryName].kind == Luau::AutocompleteEntryKind::GeneratedFunction);
4371
CHECK(ac.entryMap[kGeneratedAnonymousFunctionEntryName].typeCorrect == Luau::TypeCorrectKind::Correct);
4372
REQUIRE(ac.entryMap[kGeneratedAnonymousFunctionEntryName].insertText);
4373
CHECK_EQ(EXPECTED_INSERT, *ac.entryMap[kGeneratedAnonymousFunctionEntryName].insertText);
4374
}
4375
4376
TEST_CASE_FIXTURE(ACFixture, "anonymous_autofilled_generic_type_pack_vararg")
4377
{
4378
check(R"(
4379
local function foo<A>(a: (...A) -> number, ...: A)
4380
return a(...)
4381
end
4382
4383
foo(@1)
4384
)");
4385
4386
const std::optional<std::string> EXPECTED_INSERT = "function(...): number end";
4387
4388
auto ac = autocomplete('1');
4389
4390
REQUIRE(ac.entryMap.count(kGeneratedAnonymousFunctionEntryName) == 1);
4391
CHECK(ac.entryMap[kGeneratedAnonymousFunctionEntryName].kind == Luau::AutocompleteEntryKind::GeneratedFunction);
4392
CHECK(ac.entryMap[kGeneratedAnonymousFunctionEntryName].typeCorrect == Luau::TypeCorrectKind::Correct);
4393
REQUIRE(ac.entryMap[kGeneratedAnonymousFunctionEntryName].insertText);
4394
CHECK_EQ(EXPECTED_INSERT, *ac.entryMap[kGeneratedAnonymousFunctionEntryName].insertText);
4395
}
4396
4397
TEST_CASE_FIXTURE(ACFixture, "anonymous_autofilled_generic_named_arg")
4398
{
4399
check(R"(
4400
local function foo<A>(f: (a: A) -> number, a: A)
4401
return f(a)
4402
end
4403
4404
foo(@1)
4405
)");
4406
4407
const std::optional<std::string> EXPECTED_INSERT = "function(a): number end";
4408
4409
auto ac = autocomplete('1');
4410
4411
REQUIRE(ac.entryMap.count(kGeneratedAnonymousFunctionEntryName) == 1);
4412
CHECK(ac.entryMap[kGeneratedAnonymousFunctionEntryName].kind == Luau::AutocompleteEntryKind::GeneratedFunction);
4413
CHECK(ac.entryMap[kGeneratedAnonymousFunctionEntryName].typeCorrect == Luau::TypeCorrectKind::Correct);
4414
REQUIRE(ac.entryMap[kGeneratedAnonymousFunctionEntryName].insertText);
4415
CHECK_EQ(EXPECTED_INSERT, *ac.entryMap[kGeneratedAnonymousFunctionEntryName].insertText);
4416
}
4417
4418
TEST_CASE_FIXTURE(ACFixture, "anonymous_autofilled_generic_return_type")
4419
{
4420
check(R"(
4421
local function foo<A>(f: () -> A)
4422
return f()
4423
end
4424
4425
foo(@1)
4426
)");
4427
4428
const std::optional<std::string> EXPECTED_INSERT = "function() end";
4429
4430
auto ac = autocomplete('1');
4431
4432
REQUIRE(ac.entryMap.count(kGeneratedAnonymousFunctionEntryName) == 1);
4433
CHECK(ac.entryMap[kGeneratedAnonymousFunctionEntryName].kind == Luau::AutocompleteEntryKind::GeneratedFunction);
4434
CHECK(ac.entryMap[kGeneratedAnonymousFunctionEntryName].typeCorrect == Luau::TypeCorrectKind::Correct);
4435
REQUIRE(ac.entryMap[kGeneratedAnonymousFunctionEntryName].insertText);
4436
CHECK_EQ(EXPECTED_INSERT, *ac.entryMap[kGeneratedAnonymousFunctionEntryName].insertText);
4437
}
4438
4439
TEST_CASE_FIXTURE(ACFixture, "anonymous_autofilled_generic_on_argument_type_pack_vararg")
4440
{
4441
// Caveat lector! This is actually invalid syntax!
4442
// The correct syntax would be as follows:
4443
//
4444
// local function foo(a: <T...>(T...) -> number)
4445
//
4446
// We leave it as-written here because we still expect autocomplete to
4447
// handle this code sensibly.
4448
CheckResult result = check(R"(
4449
local function foo(a: <T...>(...: T...) -> number)
4450
return a(4, 5, 6)
4451
end
4452
4453
foo(@1)
4454
)");
4455
4456
const std::optional<std::string> EXPECTED_INSERT =
4457
!FFlag::DebugLuauForceOldSolver ? "function(...: number): number end" : "function(...): number end";
4458
4459
auto ac = autocomplete('1');
4460
4461
REQUIRE(ac.entryMap.count(kGeneratedAnonymousFunctionEntryName) == 1);
4462
CHECK(ac.entryMap[kGeneratedAnonymousFunctionEntryName].kind == Luau::AutocompleteEntryKind::GeneratedFunction);
4463
CHECK(ac.entryMap[kGeneratedAnonymousFunctionEntryName].typeCorrect == Luau::TypeCorrectKind::Correct);
4464
REQUIRE(ac.entryMap[kGeneratedAnonymousFunctionEntryName].insertText);
4465
CHECK_EQ(EXPECTED_INSERT, *ac.entryMap[kGeneratedAnonymousFunctionEntryName].insertText);
4466
}
4467
4468
TEST_CASE_FIXTURE(ACFixture, "autocomplete_at_end_of_stmt_should_continue_as_part_of_stmt")
4469
{
4470
check(R"(
4471
local data = { x = 1 }
4472
local var = data.@1
4473
)");
4474
auto ac = autocomplete('1');
4475
CHECK(!ac.entryMap.empty());
4476
CHECK(ac.entryMap.count("x"));
4477
CHECK_EQ(ac.context, AutocompleteContext::Property);
4478
}
4479
4480
TEST_CASE_FIXTURE(ACFixture, "autocomplete_after_semicolon_should_complete_a_new_statement")
4481
{
4482
check(R"(
4483
local data = { x = 1 }
4484
local var = data;@1
4485
)");
4486
auto ac = autocomplete('1');
4487
CHECK(!ac.entryMap.empty());
4488
CHECK(ac.entryMap.count("table"));
4489
CHECK(ac.entryMap.count("math"));
4490
CHECK_EQ(ac.context, AutocompleteContext::Statement);
4491
}
4492
4493
TEST_CASE_FIXTURE(ACBuiltinsFixture, "require_tracing")
4494
{
4495
fileResolver.source["Module/A"] = R"(
4496
return { x = 0 }
4497
)";
4498
4499
fileResolver.source["Module/B"] = R"(
4500
local result = require(script.Parent.A)
4501
local x = 1 + result.
4502
)";
4503
4504
auto ac = autocomplete("Module/B", Position{2, 21});
4505
4506
CHECK(ac.entryMap.size() == 1);
4507
CHECK(ac.entryMap.count("x"));
4508
}
4509
4510
TEST_CASE_FIXTURE(ACExternTypeFixture, "ac_dont_overflow_on_recursive_union")
4511
{
4512
check(R"(
4513
local table1: {ChildClass} = {}
4514
local table2 = {}
4515
4516
for index, value in table2[1] do
4517
table.insert(table1, value)
4518
value.@1
4519
end
4520
)");
4521
4522
auto ac = autocomplete('1');
4523
4524
if (!FFlag::DebugLuauForceOldSolver)
4525
{
4526
CHECK(ac.entryMap.count("BaseMethod") > 0);
4527
CHECK(ac.entryMap.count("Method") > 0);
4528
}
4529
else
4530
{
4531
// Otherwise, we don't infer anything for `value`, which is _fine_.
4532
CHECK(ac.entryMap.empty());
4533
}
4534
}
4535
4536
TEST_CASE_FIXTURE(ACBuiltinsFixture, "type_function_has_types_definitions")
4537
{
4538
ScopedFastFlag newSolver{FFlag::DebugLuauForceOldSolver, false};
4539
4540
check(R"(
4541
type function foo()
4542
types.@1
4543
end
4544
)");
4545
4546
auto ac = autocomplete('1');
4547
CHECK_EQ(ac.entryMap.count("singleton"), 1);
4548
}
4549
4550
TEST_CASE_FIXTURE(ACBuiltinsFixture, "type_function_private_scope")
4551
{
4552
ScopedFastFlag newSolver{FFlag::DebugLuauForceOldSolver, false};
4553
4554
// Global scope polution by the embedder has no effect
4555
addGlobalBinding(getFrontend().globals, "thisAlsoShouldNotBeThere", Binding{getBuiltins()->anyType});
4556
addGlobalBinding(getFrontend().globalsForAutocomplete, "thisAlsoShouldNotBeThere", Binding{getBuiltins()->anyType});
4557
4558
check(R"(
4559
local function thisShouldNotBeThere() end
4560
4561
type function thisShouldBeThere() end
4562
4563
type function foo()
4564
this@1
4565
end
4566
4567
this@2
4568
)");
4569
4570
auto ac = autocomplete('1');
4571
CHECK_EQ(ac.entryMap.count("thisShouldNotBeThere"), 0);
4572
CHECK_EQ(ac.entryMap.count("thisAlsoShouldNotBeThere"), 0);
4573
CHECK_EQ(ac.entryMap.count("thisShouldBeThere"), 1);
4574
4575
ac = autocomplete('2');
4576
CHECK_EQ(ac.entryMap.count("thisShouldNotBeThere"), 1);
4577
CHECK_EQ(ac.entryMap.count("thisAlsoShouldNotBeThere"), 1);
4578
CHECK_EQ(ac.entryMap.count("thisShouldBeThere"), 0);
4579
}
4580
4581
TEST_CASE_FIXTURE(ACBuiltinsFixture, "type_function_eval_in_autocomplete")
4582
{
4583
ScopedFastFlag newSolver{FFlag::DebugLuauForceOldSolver, false};
4584
4585
check(R"(
4586
type function foo(x)
4587
local tbl = types.newtable(nil, nil, nil)
4588
tbl:setproperty(types.singleton("boolean"), x)
4589
tbl:setproperty(types.singleton("number"), types.number)
4590
return tbl
4591
end
4592
4593
local function test(a: foo<string>)
4594
return a.@1
4595
end
4596
)");
4597
4598
auto ac = autocomplete('1');
4599
CHECK_EQ(ac.entryMap.count("boolean"), 1);
4600
CHECK_EQ(ac.entryMap.count("number"), 1);
4601
}
4602
4603
TEST_CASE_FIXTURE(ACFixture, "autocomplete_for_assignment")
4604
{
4605
check(R"(
4606
local function foobar(tbl: { tag: "left" | "right" })
4607
tbl.tag = "@1"
4608
end
4609
)");
4610
4611
auto ac = autocomplete('1');
4612
CHECK_EQ(ac.entryMap.count("left"), 1);
4613
CHECK_EQ(ac.entryMap.count("right"), 1);
4614
}
4615
4616
TEST_CASE_FIXTURE(ACFixture, "autocomplete_in_local_table")
4617
{
4618
check(R"(
4619
type Entry = { field: number, prop: string }
4620
local x : {Entry} = {}
4621
x[1] = {
4622
f@1,
4623
p@2,
4624
}
4625
4626
local t : { key1: boolean, thing2: CFrame, aaa3: vector } = {
4627
k@3,
4628
th@4,
4629
}
4630
)");
4631
4632
auto ac1 = autocomplete('1');
4633
CHECK_EQ(ac1.entryMap.count("field"), 1);
4634
auto ac2 = autocomplete('2');
4635
CHECK_EQ(ac2.entryMap.count("prop"), 1);
4636
auto ac3 = autocomplete('3');
4637
CHECK_EQ(ac3.entryMap.count("key1"), 1);
4638
auto ac4 = autocomplete('4');
4639
CHECK_EQ(ac4.entryMap.count("thing2"), 1);
4640
}
4641
4642
TEST_CASE_FIXTURE(ACFixture, "autocomplete_in_type_assertion")
4643
{
4644
check(R"(
4645
type Entry = { field: number, prop: string }
4646
return ( { f@1, p@2 } :: Entry )
4647
)");
4648
4649
auto ac1 = autocomplete('1');
4650
CHECK_EQ(ac1.entryMap.count("field"), 1);
4651
auto ac2 = autocomplete('2');
4652
CHECK_EQ(ac2.entryMap.count("prop"), 1);
4653
}
4654
4655
TEST_CASE_FIXTURE(ACFixture, "autocomplete_implicit_named_index_index_expr")
4656
{
4657
// Somewhat surprisingly, the old solver didn't cover this case.
4658
ScopedFastFlag sff{FFlag::DebugLuauForceOldSolver, false};
4659
4660
check(R"(
4661
type Constraint = "A" | "B" | "C"
4662
local foo : { [Constraint]: string } = {
4663
A = "Value for A",
4664
B = "Value for B",
4665
C = "Value for C",
4666
}
4667
foo["@1"]
4668
)");
4669
4670
auto ac = autocomplete('1');
4671
CHECK_EQ(ac.entryMap.count("A"), 1);
4672
CHECK_EQ(ac.entryMap["A"].kind, AutocompleteEntryKind::String);
4673
CHECK_EQ(ac.entryMap.count("B"), 1);
4674
CHECK_EQ(ac.entryMap["B"].kind, AutocompleteEntryKind::String);
4675
CHECK_EQ(ac.entryMap.count("C"), 1);
4676
CHECK_EQ(ac.entryMap["C"].kind, AutocompleteEntryKind::String);
4677
}
4678
4679
TEST_CASE_FIXTURE(ACFixture, "autocomplete_implicit_named_index_index_expr_without_annotation")
4680
{
4681
ScopedFastFlag sffs{FFlag::DebugLuauForceOldSolver, false};
4682
4683
check(R"(
4684
local foo = {
4685
["Item/Foo"] = 42,
4686
["Item/Bar"] = "it's true",
4687
["Item/Baz"] = true,
4688
}
4689
foo["@1"]
4690
)");
4691
4692
auto ac = autocomplete('1');
4693
4694
auto checkEntry = [&](auto key, auto type)
4695
{
4696
REQUIRE_EQ(ac.entryMap.count(key), 1);
4697
auto entry = ac.entryMap.at(key);
4698
CHECK_EQ(entry.kind, AutocompleteEntryKind::Property);
4699
REQUIRE(entry.type);
4700
CHECK_EQ(type, toString(*entry.type));
4701
};
4702
4703
checkEntry("Item/Foo", "number");
4704
checkEntry("Item/Bar", "string");
4705
checkEntry("Item/Baz", "boolean");
4706
}
4707
4708
TEST_CASE_FIXTURE(ACFixture, "bidirectional_autocomplete_in_function_call")
4709
{
4710
ScopedFastFlag _{FFlag::DebugLuauForceOldSolver, false};
4711
4712
check(R"(
4713
local function take(_: { choice: "left" | "right" }) end
4714
4715
take({ choice = "@1" })
4716
)");
4717
4718
auto ac = autocomplete('1');
4719
CHECK_EQ(ac.entryMap.count("left"), 1);
4720
CHECK_EQ(ac.entryMap.count("right"), 1);
4721
}
4722
4723
TEST_CASE_FIXTURE(ACBuiltinsFixture, "autocomplete_via_bidirectional_self")
4724
{
4725
ScopedFastFlag sff{FFlag::DebugLuauForceOldSolver, false};
4726
4727
check(R"(
4728
type IAccount = {
4729
__index: IAccount,
4730
new : (string, number) -> Account,
4731
report: (self: Account) -> (),
4732
}
4733
4734
export type Account = setmetatable<{
4735
name: string,
4736
balance: number
4737
}, IAccount>;
4738
4739
local Account = {} :: IAccount
4740
Account.__index = Account
4741
4742
function Account.new(name, balance): Account
4743
local self = {}
4744
self.name = name
4745
self.balance = balance
4746
return setmetatable(self, Account)
4747
end
4748
4749
function Account:report()
4750
print("My balance is: " .. self.@1)
4751
end
4752
)");
4753
4754
auto ac = autocomplete('1');
4755
CHECK_EQ(ac.entryMap.count("name"), 1);
4756
CHECK_EQ(ac.entryMap.count("balance"), 1);
4757
}
4758
4759
TEST_CASE_FIXTURE(ACFixture, "autocomplete_include_break_continue_in_loop")
4760
{
4761
check(R"(for x in y do
4762
@1
4763
if true then
4764
@2
4765
end
4766
end)");
4767
4768
auto ac = autocomplete('1');
4769
4770
CHECK(ac.entryMap.count("break") > 0);
4771
CHECK(ac.entryMap.count("continue") > 0);
4772
4773
ac = autocomplete('2');
4774
4775
CHECK(ac.entryMap.count("break") > 0);
4776
CHECK(ac.entryMap.count("continue") > 0);
4777
}
4778
4779
TEST_CASE_FIXTURE(ACFixture, "autocomplete_exclude_break_continue_outside_loop")
4780
{
4781
check(R"(@1if true then
4782
@2
4783
end)");
4784
4785
auto ac = autocomplete('1');
4786
4787
CHECK_EQ(ac.entryMap.count("break"), 0);
4788
CHECK_EQ(ac.entryMap.count("continue"), 0);
4789
4790
ac = autocomplete('2');
4791
CHECK_EQ(ac.entryMap.count("break"), 0);
4792
CHECK_EQ(ac.entryMap.count("continue"), 0);
4793
}
4794
4795
TEST_CASE_FIXTURE(ACFixture, "autocomplete_exclude_break_continue_function_boundary")
4796
{
4797
check(R"(for i = 1, 10 do
4798
local function helper()
4799
@1
4800
end
4801
end)");
4802
4803
auto ac = autocomplete('1');
4804
4805
CHECK_EQ(ac.entryMap.count("break"), 0);
4806
CHECK_EQ(ac.entryMap.count("continue"), 0);
4807
}
4808
4809
TEST_CASE_FIXTURE(ACFixture, "autocomplete_exclude_break_continue_in_param")
4810
{
4811
check(R"(while @1 do
4812
end)");
4813
4814
auto ac = autocomplete('1');
4815
4816
CHECK_EQ(ac.entryMap.count("break"), 0);
4817
CHECK_EQ(ac.entryMap.count("continue"), 0);
4818
}
4819
4820
TEST_CASE_FIXTURE(ACFixture, "autocomplete_exclude_break_continue_incomplete_while")
4821
{
4822
check("while @1");
4823
4824
auto ac = autocomplete('1');
4825
4826
CHECK_EQ(ac.entryMap.count("break"), 0);
4827
CHECK_EQ(ac.entryMap.count("continue"), 0);
4828
}
4829
4830
TEST_CASE_FIXTURE(ACFixture, "autocomplete_exclude_break_continue_incomplete_for")
4831
{
4832
check("for @1 in @2 do");
4833
4834
auto ac = autocomplete('1');
4835
4836
ac = autocomplete('1');
4837
CHECK_EQ(ac.entryMap.count("break"), 0);
4838
CHECK_EQ(ac.entryMap.count("continue"), 0);
4839
4840
ac = autocomplete('2');
4841
CHECK_EQ(ac.entryMap.count("break"), 0);
4842
CHECK_EQ(ac.entryMap.count("continue"), 0);
4843
}
4844
4845
TEST_CASE_FIXTURE(ACFixture, "autocomplete_exclude_break_continue_expr_func")
4846
{
4847
check(R"(while true do
4848
local _ = function ()
4849
@1
4850
end
4851
end)");
4852
4853
auto ac = autocomplete('1');
4854
4855
CHECK_EQ(ac.entryMap.count("break"), 0);
4856
CHECK_EQ(ac.entryMap.count("continue"), 0);
4857
}
4858
4859
TEST_CASE_FIXTURE(ACFixture, "autocomplete_include_break_continue_in_repeat")
4860
{
4861
check(R"(repeat
4862
@1
4863
until foo())");
4864
4865
auto ac = autocomplete('1');
4866
4867
CHECK(ac.entryMap.count("break") > 0);
4868
CHECK(ac.entryMap.count("continue") > 0);
4869
}
4870
4871
TEST_CASE_FIXTURE(ACFixture, "autocomplete_include_break_continue_in_nests")
4872
{
4873
check(R"(while ((function ()
4874
while true do
4875
@1
4876
end
4877
end)()) do
4878
end)");
4879
4880
auto ac = autocomplete('1');
4881
4882
CHECK(ac.entryMap.count("break") > 0);
4883
CHECK(ac.entryMap.count("continue") > 0);
4884
}
4885
4886
TEST_CASE_FIXTURE(ACFixture, "autocomplete_exclude_break_continue_in_incomplete_loop")
4887
{
4888
check(R"(while foo() do
4889
@1)");
4890
4891
auto ac = autocomplete('1');
4892
4893
// We'd like to include break/continue here but the incomplete loop ends immediately.
4894
CHECK_EQ(ac.entryMap.count("break"), 0);
4895
CHECK_EQ(ac.entryMap.count("continue"), 0);
4896
}
4897
4898
TEST_CASE_FIXTURE(ACFixture, "autocomplete_suggest_hot_comments")
4899
{
4900
check("--!@1");
4901
4902
auto ac = autocomplete('1');
4903
4904
CHECK(!ac.entryMap.empty());
4905
CHECK(ac.entryMap.count("strict"));
4906
CHECK(ac.entryMap.count("nonstrict"));
4907
CHECK(ac.entryMap.count("nocheck"));
4908
CHECK(ac.entryMap.count("native"));
4909
CHECK(ac.entryMap.count("nolint"));
4910
CHECK(ac.entryMap.count("optimize"));
4911
}
4912
4913
TEST_CASE_FIXTURE(ACFixture, "autocomplete_method_in_unfinished_repeat_body_eof")
4914
{
4915
check(R"(local t = {}
4916
function t:Foo() end
4917
repeat
4918
t:@1)");
4919
4920
auto ac = autocomplete('1');
4921
4922
CHECK(!ac.entryMap.empty());
4923
CHECK(ac.entryMap.count("Foo"));
4924
}
4925
4926
TEST_CASE_FIXTURE(ACFixture, "autocomplete_method_in_unfinished_repeat_body_not_eof")
4927
{
4928
check(R"(local t = {}
4929
function t:Foo() end
4930
repeat
4931
t:@1
4932
)");
4933
4934
auto ac = autocomplete('1');
4935
4936
CHECK(!ac.entryMap.empty());
4937
CHECK(ac.entryMap.count("Foo"));
4938
}
4939
4940
TEST_CASE_FIXTURE(ACFixture, "autocomplete_method_in_unfinished_while_body")
4941
{
4942
check(R"(local t = {}
4943
function t:Foo() end
4944
while true do
4945
t:@1)");
4946
4947
auto ac = autocomplete('1');
4948
4949
CHECK(!ac.entryMap.empty());
4950
CHECK(ac.entryMap.count("Foo"));
4951
}
4952
4953
TEST_CASE_FIXTURE(ACBuiltinsFixture, "autocomplete_empty_attribute")
4954
{
4955
check(R"(
4956
\@@1
4957
function foo() return 42 end
4958
)");
4959
4960
auto ac = autocomplete('1');
4961
CHECK_EQ(ac.entryMap.count("deprecated"), 1);
4962
CHECK_EQ(ac.entryMap.count("checked"), 1);
4963
CHECK_EQ(ac.entryMap.count("native"), 1);
4964
}
4965
4966
TEST_CASE_FIXTURE(ACBuiltinsFixture, "autocomplete_deprecated_attribute")
4967
{
4968
check(R"(
4969
\@dep@1
4970
function foo() return 42 end
4971
)");
4972
4973
auto ac = autocomplete('1');
4974
CHECK_EQ(ac.entryMap.count("deprecated"), 1);
4975
CHECK_EQ(ac.entryMap.count("checked"), 1);
4976
CHECK_EQ(ac.entryMap.count("native"), 1);
4977
}
4978
4979
TEST_CASE_FIXTURE(ACBuiltinsFixture, "autocomplete_empty_braced_attribute")
4980
{
4981
check(R"(
4982
\@[@1]
4983
function foo() return 42 end
4984
)");
4985
4986
auto ac = autocomplete('1');
4987
CHECK_EQ(ac.entryMap.count("deprecated"), 1);
4988
CHECK_EQ(ac.entryMap.count("checked"), 1);
4989
CHECK_EQ(ac.entryMap.count("native"), 1);
4990
}
4991
4992
TEST_CASE_FIXTURE(ACBuiltinsFixture, "autocomplete_deprecated_braced_attribute")
4993
{
4994
check(R"(
4995
\@[dep@1]
4996
function foo() return 42 end
4997
)");
4998
4999
auto ac = autocomplete('1');
5000
CHECK_EQ(ac.entryMap.count("deprecated"), 1);
5001
CHECK_EQ(ac.entryMap.count("checked"), 1);
5002
CHECK_EQ(ac.entryMap.count("native"), 1);
5003
}
5004
5005
TEST_CASE_FIXTURE(ACFixture, "autocomplete_using_indexer_with_singleton_keys")
5006
{
5007
check(R"(
5008
type List = "Val1" | "Val2" | "Val3"
5009
local Table: { [List]: boolean }
5010
local _ = Table.@1
5011
)");
5012
5013
auto ac = autocomplete('1');
5014
CHECK_EQ(ac.entryMap.count("Val1"), 1);
5015
CHECK_EQ(ac.entryMap.count("Val2"), 1);
5016
CHECK_EQ(ac.entryMap.count("Val3"), 1);
5017
}
5018
5019
TEST_CASE_FIXTURE(ACFixture, "autocomplete_using_function_with_singleton_arg")
5020
{
5021
ScopedFastFlag sff{FFlag::LuauAutocompleteFunctionCallArgTails2, true};
5022
5023
check(R"(
5024
local function foo(...: "Val1") end
5025
foo(@1)
5026
)");
5027
5028
auto ac = autocomplete('1');
5029
CHECK_EQ(ac.entryMap.count("\"Val1\""), 1);
5030
}
5031
5032
TEST_CASE_FIXTURE(ACFixture, "autocomplete_using_function_with_singleton_union_arg")
5033
{
5034
ScopedFastFlag sff{FFlag::LuauAutocompleteFunctionCallArgTails2, true};
5035
5036
check(R"(
5037
local function foo(...: "Val1" | "Val2") end
5038
foo(@1)
5039
)");
5040
5041
auto ac = autocomplete('1');
5042
CHECK_EQ(ac.entryMap.count("\"Val1\""), 1);
5043
CHECK_EQ(ac.entryMap.count("\"Val2\""), 1);
5044
}
5045
5046
TEST_CASE_FIXTURE(ACBuiltinsFixture, "autocomplete_metatable_fill_writeonly_prop_no_crash")
5047
{
5048
// Due to how memory is allocated and cleaned up on the stack in noopt builds, this will not crash on certain platforms.
5049
// This can crash in optimized builds, but the test is mostly here to exercise that the branch in question gets hit
5050
ScopedFastFlag sffs[] = {
5051
{FFlag::LuauACOnMTTWriteOnlyPropNoCrash, true},
5052
{FFlag::DebugLuauForceOldSolver, false},
5053
};
5054
check(R"(
5055
5056
local t0 = { thing = 5 }
5057
5058
type function evil(x)
5059
local tbl = types.newtable(nil, nil, nil)
5060
tbl:setwriteproperty(types.singleton("__index"), types.any)
5061
return tbl
5062
end
5063
5064
type BadMTType = evil<{ thing : number}>
5065
local function foo(t : BadMTType)
5066
local t2 = setmetatable({}, t)
5067
return t2
5068
end
5069
5070
local x = foo(nil :: any)
5071
x.@1
5072
)");
5073
5074
auto ac = autocomplete('1');
5075
CHECK(ac.entryMap.empty());
5076
}
5077
5078
TEST_CASE_FIXTURE(ACBuiltinsFixture, "autocomplete_table_insert")
5079
{
5080
ScopedFastFlag sffs[] = {
5081
{FFlag::DebugLuauForceOldSolver, false},
5082
{FFlag::LuauOverloadGetsInstantiated, true},
5083
{FFlag::LuauReplacerRespectsReboundGenerics, true},
5084
};
5085
5086
check(R"(
5087
local function addToTable(t: {{ foobar: number }})
5088
table.insert(t, { f@1 })
5089
end
5090
)");
5091
5092
auto ac = autocomplete('1');
5093
CHECK(ac.entryMap.count("foobar") > 0);
5094
}
5095
5096
TEST_CASE_FIXTURE(ACFixture, "autocomplete_react")
5097
{
5098
ScopedFastFlag sffs[] = {
5099
{FFlag::DebugLuauForceOldSolver, false},
5100
{FFlag::LuauOverloadGetsInstantiated, true},
5101
{FFlag::LuauReplacerRespectsReboundGenerics, true},
5102
};
5103
5104
check(R"(
5105
type React_Node = any
5106
type ReactElement<P, T> = any
5107
5108
type React_StatelessFunctionalComponent<Props> = (props: Props, context: any) -> React_Node
5109
type React_Component<Props, State = nil> = {}
5110
type createElementFn = <P, T>(
5111
type_:
5112
| React_StatelessFunctionalComponent<P>
5113
| React_Component<P>
5114
| string,
5115
props: P?,
5116
...(React_Node | (...any) -> React_Node)
5117
) -> ReactElement<P, T>
5118
5119
local createElement: createElementFn = nil :: any
5120
5121
local function MyComponent(props: { foobar: string, barbaz: { bazquxx: string } })
5122
return nil
5123
end
5124
5125
createElement(MyComponent, { f@1 })
5126
createElement(MyComponent, { barbaz = { b@2 } })
5127
createElement(MyComponent, { foobar = {}, b@3 })
5128
)");
5129
5130
auto ac = autocomplete('1');
5131
CHECK(ac.entryMap.count("foobar") > 0);
5132
5133
ac = autocomplete('2');
5134
CHECK(ac.entryMap.count("bazquxx") > 0);
5135
5136
ac = autocomplete('3');
5137
CHECK(ac.entryMap.count("barbaz") > 0);
5138
}
5139
5140
5141
5142
TEST_SUITE_END();
5143
5144