Commit 7d17fd46 authored by Simon Zünd's avatar Simon Zünd Committed by Commit Bot

[torque-ls] Add "goto Definition" support for labels of goto statements

This CL adds navigation support for labels in "goto" statements.
Similar to labels listed in the "otherwise" clause of call expression,
definitions of such a label can be found in two places:
  - The signature of the current macro.
  - A label block of a "try" statement that surrounds the "goto".

R=sigurds@chromium.org

Bug: v8:8880
Change-Id: I6c5ebea0b0f80b1882e6672bbb0f45196a7201ba
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1594433
Commit-Queue: Simon Zünd <szuend@chromium.org>
Reviewed-by: 's avatarSigurd Schneider <sigurds@chromium.org>
Cr-Commit-Position: refs/heads/master@{#61229}
parent b452a9ec
......@@ -569,12 +569,10 @@ struct ContinueStatement : Statement {
struct GotoStatement : Statement {
DEFINE_AST_NODE_LEAF_BOILERPLATE(GotoStatement)
GotoStatement(SourcePosition pos, std::string label,
GotoStatement(SourcePosition pos, Identifier* label,
const std::vector<Expression*>& arguments)
: Statement(kKind, pos),
label(std::move(label)),
arguments(std::move(arguments)) {}
std::string label;
: Statement(kKind, pos), label(label), arguments(std::move(arguments)) {}
Identifier* label;
std::vector<Expression*> arguments;
};
......
......@@ -811,13 +811,18 @@ VisitResult ImplementationVisitor::Visit(LocationExpression* expr) {
}
const Type* ImplementationVisitor::Visit(GotoStatement* stmt) {
LocalLabel* label = LookupLabel(stmt->label);
Binding<LocalLabel>* label = LookupLabel(stmt->label->value);
size_t parameter_count = label->parameter_types.size();
if (stmt->arguments.size() != parameter_count) {
ReportError("goto to label has incorrect number of parameters (expected ",
parameter_count, " found ", stmt->arguments.size(), ")");
}
if (GlobalContext::collect_language_server_data()) {
LanguageServerData::AddDefinition(stmt->label->pos,
label->declaration_position());
}
size_t i = 0;
StackRange arguments = assembler().TopRange(0);
for (Expression* e : stmt->arguments) {
......
......@@ -890,10 +890,9 @@ base::Optional<ParseResult> MakeContinueStatement(
base::Optional<ParseResult> MakeGotoStatement(
ParseResultIterator* child_results) {
auto label = child_results->NextAs<std::string>();
auto label = child_results->NextAs<Identifier*>();
auto arguments = child_results->NextAs<std::vector<Expression*>>();
Statement* result =
MakeNode<GotoStatement>(std::move(label), std::move(arguments));
Statement* result = MakeNode<GotoStatement>(label, std::move(arguments));
return ParseResult{result};
}
......@@ -1582,7 +1581,7 @@ struct TorqueGrammar : Grammar {
Rule({Token("tail"), &callExpression}, MakeTailCallStatement),
Rule({Token("break")}, MakeBreakStatement),
Rule({Token("continue")}, MakeContinueStatement),
Rule({Token("goto"), &identifier,
Rule({Token("goto"), &name,
TryOrDefault<std::vector<Expression*>>(&argumentList)},
MakeGotoStatement),
Rule({OneOf({"debug", "unreachable"})}, MakeDebugStatement)};
......
......@@ -139,6 +139,65 @@ TEST(LanguageServer, GotoDefinitionClassSuperType) {
EXPECT_EQ(*maybe_position, (SourcePosition{id, {2, 5}, {2, 11}}));
}
TEST(LanguageServer, GotoLabelDefinitionInSignatureGotoStmt) {
const std::string source =
"type void;\n"
"type never;\n"
"macro Foo(): never labels Fail {\n"
" goto Fail;\n"
"}\n";
TestCompiler compiler;
compiler.Compile(source);
// Find the definition for 'Fail' of the goto statement on line 3.
const SourceId id = SourceFileMap::GetSourceId("<torque>");
auto maybe_position = LanguageServerData::FindDefinition(id, {3, 7});
ASSERT_TRUE(maybe_position.has_value());
EXPECT_EQ(*maybe_position, (SourcePosition{id, {2, 26}, {2, 30}}));
}
TEST(LanguageServer, GotoLabelDefinitionInTryBlockGoto) {
const std::string source =
"type void;\n"
"type never;\n"
"macro Bar() {\n"
" try { goto Bailout; }\n"
" label Bailout {}\n"
"}\n";
TestCompiler compiler;
compiler.Compile(source);
// Find the definition for 'Bailout' of the goto statement on line 3.
const SourceId id = SourceFileMap::GetSourceId("<torque>");
auto maybe_position = LanguageServerData::FindDefinition(id, {3, 13});
ASSERT_TRUE(maybe_position.has_value());
EXPECT_EQ(*maybe_position, (SourcePosition{id, {4, 8}, {4, 15}}));
}
TEST(LanguageServer, GotoLabelDefinitionGotoInOtherwise) {
const std::string source =
"type void;\n"
"type never;\n"
"macro Foo(): never labels Fail {\n"
" goto Fail;\n"
"}\n"
"macro Bar() {\n"
" try { Foo() otherwise goto Bailout; }\n"
" label Bailout {}\n"
"}\n";
TestCompiler compiler;
compiler.Compile(source);
// Find the definition for 'Bailout' of the otherwise clause on line 6.
const SourceId id = SourceFileMap::GetSourceId("<torque>");
auto maybe_position = LanguageServerData::FindDefinition(id, {6, 30});
ASSERT_TRUE(maybe_position.has_value());
EXPECT_EQ(*maybe_position, (SourcePosition{id, {7, 8}, {7, 15}}));
}
} // namespace torque
} // namespace internal
} // namespace v8
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment