From 971088a08a186e2a956a69cf7a05c90be78c29be Mon Sep 17 00:00:00 2001 From: Kampfkarren Date: Tue, 15 Nov 2022 13:50:52 -0800 Subject: [PATCH] Handle formatting of parts of formatted interpolated string --- Analysis/src/Autocomplete.cpp | 19 +++++++++++++++++-- Ast/src/Parser.cpp | 9 +++++++++ tests/Autocomplete.test.cpp | 21 +++++++++++++++++++++ 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/Analysis/src/Autocomplete.cpp b/Analysis/src/Autocomplete.cpp index 938cbf49..6ec53490 100644 --- a/Analysis/src/Autocomplete.cpp +++ b/Analysis/src/Autocomplete.cpp @@ -1,6 +1,7 @@ // This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details #include "Luau/Autocomplete.h" +#include "Luau/Ast.h" #include "Luau/AstQuery.h" #include "Luau/BuiltinDefinitions.h" #include "Luau/Frontend.h" @@ -1238,6 +1239,12 @@ static bool stringPartOfInterpString(const AstNode* node, Position position) return true; } +static bool isSimpleInterpolatedString(const AstNode* node) +{ + const AstExprInterpString* interpString = node->as(); + return interpString != nullptr && interpString->expressions.size == 0; +} + static std::optional autocompleteStringParams(const SourceModule& sourceModule, const ModulePtr& module, const std::vector& nodes, Position position, StringCompletionCallback callback) { @@ -1246,7 +1253,8 @@ static std::optional autocompleteStringParams(const Source return std::nullopt; } - if (!nodes.back()->is() && !stringPartOfInterpString(nodes.back(), position) && !nodes.back()->is()) + if (!nodes.back()->is() && !isSimpleInterpolatedString(nodes.back()) && !nodes.back()->is() && + !nodes.back()->is()) { return std::nullopt; } @@ -1490,7 +1498,7 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M { return {*ret, ancestry, AutocompleteContext::String}; } - else if (node->is() || stringPartOfInterpString(node, position)) + else if (node->is() || isSimpleInterpolatedString(node)) { AutocompleteEntryMap result; @@ -1516,6 +1524,13 @@ static AutocompleteResult autocomplete(const SourceModule& sourceModule, const M return {result, ancestry, AutocompleteContext::String}; } + else if (stringPartOfInterpString(node, position)) + { + // We're not a simple interpolated string, we're something like `a{"b"}@1`, and we + // can't know what to format to + AutocompleteEntryMap map; + return {map, ancestry, AutocompleteContext::String}; + } if (node->is()) return {}; diff --git a/Ast/src/Parser.cpp b/Ast/src/Parser.cpp index 52845956..85b0d31a 100644 --- a/Ast/src/Parser.cpp +++ b/Ast/src/Parser.cpp @@ -2692,17 +2692,21 @@ AstExpr* Parser::parseInterpString() break; } + bool errorWhileChecking = false; + switch (lexer.current().type) { case Lexeme::InterpStringMid: case Lexeme::InterpStringEnd: { + errorWhileChecking = true; nextLexeme(); expressions.push_back(reportExprError(endLocation, {}, "Malformed interpolated string, expected expression inside '{}'")); break; } case Lexeme::BrokenString: { + errorWhileChecking = true; nextLexeme(); expressions.push_back(reportExprError(endLocation, {}, "Malformed interpolated string, did you forget to add a '`'?")); break; @@ -2711,6 +2715,11 @@ AstExpr* Parser::parseInterpString() expressions.push_back(parseExpr()); } + if (errorWhileChecking) + { + break; + } + switch (lexer.current().type) { case Lexeme::InterpStringBegin: diff --git a/tests/Autocomplete.test.cpp b/tests/Autocomplete.test.cpp index 6149775d..45baec2c 100644 --- a/tests/Autocomplete.test.cpp +++ b/tests/Autocomplete.test.cpp @@ -2761,6 +2761,27 @@ TEST_CASE_FIXTURE(ACFixture, "autocomplete_interpolated_string_expression_with_c CHECK_EQ(ac.context, AutocompleteContext::Expression); } +TEST_CASE_FIXTURE(ACFixture, "autocomplete_interpolated_string_as_singleton") +{ + ScopedFastFlag sff{"LuauInterpolatedStringBaseSupport", true}; + + check(R"( + --!strict + local function f(a: "cat" | "dog") end + + f(`@1`) + f(`uhhh{'try'}@2`) + )"); + + auto ac = autocomplete('1'); + CHECK(ac.entryMap.count("cat")); + CHECK_EQ(ac.context, AutocompleteContext::String); + + ac = autocomplete('2'); + CHECK(ac.entryMap.empty()); + CHECK_EQ(ac.context, AutocompleteContext::String); +} + TEST_CASE_FIXTURE(ACFixture, "autocomplete_explicit_type_pack") { check(R"(