[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: Sigurd Schneider <sigurds@chromium.org>
Cr-Commit-Position: refs/heads/master@{#61229}
This commit is contained in:
Simon Zünd 2019-05-06 08:47:21 +02:00 committed by Commit Bot
parent b452a9ec99
commit 7d17fd465d
4 changed files with 71 additions and 10 deletions

View File

@ -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;
};

View File

@ -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) {

View File

@ -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)};

View File

@ -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