[torque-ls] Add basic "goto definition" support for labels

This CL adds navigation support for labels listed in the "otherwise"
part of a call expression. There are two places where a definition for
such a label can be found:
  - The signature of the current macro (caller)
  - A label block of a "try" statement that surrounds the call
    expression.

R=tebbi@chromium.org

Bug: v8:8880
Change-Id: If8849ad29abcf94f301d7a51e3e52c5517601bc0
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1593295
Commit-Queue: Simon Zünd <szuend@chromium.org>
Reviewed-by: Tobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/master@{#61228}
This commit is contained in:
Simon Zünd 2019-05-06 07:50:17 +02:00 committed by Commit Bot
parent 28df7e8036
commit b452a9ec99
6 changed files with 90 additions and 36 deletions

View File

@ -241,7 +241,7 @@ struct CallMethodExpression : Expression {
CallMethodExpression(SourcePosition pos, Expression* target,
IdentifierExpression* method,
std::vector<Expression*> arguments,
std::vector<std::string> labels)
std::vector<Identifier*> labels)
: Expression(kKind, pos),
target(target),
method(method),
@ -250,21 +250,21 @@ struct CallMethodExpression : Expression {
Expression* target;
IdentifierExpression* method;
std::vector<Expression*> arguments;
std::vector<std::string> labels;
std::vector<Identifier*> labels;
};
struct CallExpression : Expression {
DEFINE_AST_NODE_LEAF_BOILERPLATE(CallExpression)
CallExpression(SourcePosition pos, IdentifierExpression* callee,
std::vector<Expression*> arguments,
std::vector<std::string> labels)
std::vector<Identifier*> labels)
: Expression(kKind, pos),
callee(callee),
arguments(std::move(arguments)),
labels(std::move(labels)) {}
IdentifierExpression* callee;
std::vector<Expression*> arguments;
std::vector<std::string> labels;
std::vector<Identifier*> labels;
};
struct NameAndExpression {
@ -624,13 +624,13 @@ struct ForOfLoopStatement : Statement {
struct LabelBlock : AstNode {
DEFINE_AST_NODE_LEAF_BOILERPLATE(LabelBlock)
LabelBlock(SourcePosition pos, std::string label,
LabelBlock(SourcePosition pos, Identifier* label,
const ParameterList& parameters, Statement* body)
: AstNode(kKind, pos),
label(std::move(label)),
label(label),
parameters(parameters),
body(std::move(body)) {}
std::string label;
Identifier* label;
ParameterList parameters;
Statement* body;
};
@ -712,7 +712,7 @@ struct ClassFieldExpression {
};
struct LabelAndTypes {
std::string name;
Identifier* name;
std::vector<TypeExpression*> types;
};

View File

@ -408,11 +408,11 @@ void ImplementationVisitor::VisitMacroCommon(Macro* macro) {
std::vector<std::string> label_parameter_variables;
for (size_t i = 0; i < label_info.types.size(); ++i) {
LowerLabelParameter(label_info.types[i],
ExternalLabelParameterName(label_info.name, i),
ExternalLabelParameterName(label_info.name->value, i),
&label_parameter_variables);
}
assembler().Emit(GotoExternalInstruction{ExternalLabelName(label_info.name),
label_parameter_variables});
assembler().Emit(GotoExternalInstruction{
ExternalLabelName(label_info.name->value), label_parameter_variables});
}
if (return_type != TypeOracle::GetNeverType()) {
@ -1621,7 +1621,8 @@ void ImplementationVisitor::GenerateFunctionDeclaration(
if (!first) {
o << ", ";
}
o << "compiler::CodeAssemblerLabel* " << ExternalLabelName(label_info.name);
o << "compiler::CodeAssemblerLabel* "
<< ExternalLabelName(label_info.name->value);
size_t i = 0;
for (const Type* type : label_info.types) {
std::string generated_type_name;
@ -1634,7 +1635,7 @@ void ImplementationVisitor::GenerateFunctionDeclaration(
}
o << ", ";
o << generated_type_name << " "
<< ExternalLabelParameterName(label_info.name, i);
<< ExternalLabelParameterName(label_info.name->value, i);
++i;
}
}
@ -2553,11 +2554,20 @@ StackRange ImplementationVisitor::GenerateLabelGoto(
}
std::vector<Binding<LocalLabel>*> ImplementationVisitor::LabelsFromIdentifiers(
const std::vector<std::string>& names) {
const std::vector<Identifier*>& names) {
std::vector<Binding<LocalLabel>*> result;
result.reserve(names.size());
for (const auto& name : names) {
result.push_back(LookupLabel(name));
Binding<LocalLabel>* label = LookupLabel(name->value);
result.push_back(label);
// Link up labels in "otherwise" part of the call expression with
// either the label in the signature of the calling macro or the label
// block ofa surrounding "try".
if (GlobalContext::collect_language_server_data()) {
LanguageServerData::AddDefinition(name->pos,
label->declaration_position());
}
}
return result;
}

View File

@ -548,7 +548,7 @@ class ImplementationVisitor : public FileVisitor {
base::Optional<StackRange> arguments = {});
std::vector<Binding<LocalLabel>*> LabelsFromIdentifiers(
const std::vector<std::string>& names);
const std::vector<Identifier*>& names);
StackRange LowerParameter(const Type* type, const std::string& parameter_name,
Stack<std::string>* lowered_parameters);

View File

@ -208,7 +208,7 @@ Expression* MakeCall(IdentifierExpression* callee,
base::Optional<Expression*> target,
std::vector<Expression*> arguments,
const std::vector<Statement*>& otherwise) {
std::vector<std::string> labels;
std::vector<Identifier*> labels;
// All IdentifierExpressions are treated as label names and can be directly
// used as labels identifiers. All other statements in a call's otherwise
@ -221,14 +221,16 @@ Expression* MakeCall(IdentifierExpression* callee,
if (id->generic_arguments.size() != 0) {
ReportError("An otherwise label cannot have generic parameters");
}
labels.push_back(id->name->value);
labels.push_back(id->name);
continue;
}
}
auto label_name = std::string("_label") + std::to_string(label_id++);
labels.push_back(label_name);
auto label_id = MakeNode<Identifier>(label_name);
label_id->pos = SourcePosition::Invalid();
labels.push_back(label_id);
auto* label_block =
MakeNode<LabelBlock>(label_name, ParameterList::Empty(), statement);
MakeNode<LabelBlock>(label_id, ParameterList::Empty(), statement);
temp_labels.push_back(label_block);
}
@ -809,8 +811,8 @@ base::Optional<ParseResult> MakeTypeswitchStatement(
current_block->statements.push_back(
MakeNode<ExpressionStatement>(MakeNode<TryLabelExpression>(
false, MakeNode<StatementExpression>(case_block),
MakeNode<LabelBlock>("_NextCase", ParameterList::Empty(),
next_block))));
MakeNode<LabelBlock>(MakeNode<Identifier>("_NextCase"),
ParameterList::Empty(), next_block))));
current_block = next_block;
}
accumulated_types =
@ -952,14 +954,13 @@ base::Optional<ParseResult> MakeForLoopStatement(
}
base::Optional<ParseResult> MakeLabelBlock(ParseResultIterator* child_results) {
auto label = child_results->NextAs<std::string>();
if (!IsUpperCamelCase(label)) {
NamingConventionError("Label", label, "UpperCamelCase");
auto label = child_results->NextAs<Identifier*>();
if (!IsUpperCamelCase(label->value)) {
NamingConventionError("Label", label->value, "UpperCamelCase");
}
auto parameters = child_results->NextAs<ParameterList>();
auto body = child_results->NextAs<Statement*>();
LabelBlock* result =
MakeNode<LabelBlock>(std::move(label), std::move(parameters), body);
LabelBlock* result = MakeNode<LabelBlock>(label, std::move(parameters), body);
return ParseResult{result};
}
@ -974,8 +975,8 @@ base::Optional<ParseResult> MakeCatchBlock(ParseResultIterator* child_results) {
parameters.types.push_back(MakeNode<BasicTypeExpression>(
std::vector<std::string>{}, false, "Object"));
parameters.has_varargs = false;
LabelBlock* result =
MakeNode<LabelBlock>("_catch", std::move(parameters), body);
LabelBlock* result = MakeNode<LabelBlock>(MakeNode<Identifier>("_catch"),
std::move(parameters), body);
return ParseResult{result};
}
@ -1114,12 +1115,12 @@ base::Optional<ParseResult> MakeConditionalExpression(
base::Optional<ParseResult> MakeLabelAndTypes(
ParseResultIterator* child_results) {
auto name = child_results->NextAs<std::string>();
if (!IsUpperCamelCase(name)) {
NamingConventionError("Label", name, "UpperCamelCase");
auto name = child_results->NextAs<Identifier*>();
if (!IsUpperCamelCase(name->value)) {
NamingConventionError("Label", name->value, "UpperCamelCase");
}
auto types = child_results->NextAs<std::vector<TypeExpression*>>();
return ParseResult{LabelAndTypes{std::move(name), std::move(types)}};
return ParseResult{LabelAndTypes{name, std::move(types)}};
}
base::Optional<ParseResult> MakeNameAndType(
@ -1335,7 +1336,7 @@ struct TorqueGrammar : Grammar {
// Result: LabelAndTypes
Symbol labelParameter = {Rule(
{&identifier,
{&name,
TryOrDefault<TypeList>(Sequence({Token("("), typeList, Token(")")}))},
MakeLabelAndTypes)};
@ -1542,7 +1543,7 @@ struct TorqueGrammar : Grammar {
// Result: LabelBlock*
Symbol labelBlock = {
Rule({Token("label"), &identifier,
Rule({Token("label"), &name,
TryOrDefault<ParameterList>(&parameterListNoVararg), &block},
MakeLabelBlock)};

View File

@ -595,7 +595,7 @@ struct LabelDefinition {
typedef std::vector<LabelDefinition> LabelDefinitionVector;
struct LabelDeclaration {
std::string name;
Identifier* name;
TypeVector types;
};

View File

@ -79,6 +79,49 @@ TEST(LanguageServer, GotoTypeDefinitionNoDataForFile) {
EXPECT_FALSE(LanguageServerData::FindDefinition(test_id, {0, 0}));
}
TEST(LanguageServer, GotoLabelDefinitionInSignature) {
const std::string source =
"type void;\n"
"type never;\n"
"macro Foo(): never labels Fail {\n"
" goto Fail;\n"
"}\n"
"macro Bar() labels Bailout {\n"
" Foo() otherwise 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, 18});
ASSERT_TRUE(maybe_position.has_value());
EXPECT_EQ(*maybe_position, (SourcePosition{id, {5, 19}, {5, 26}}));
}
TEST(LanguageServer, GotoLabelDefinitionInTryBlock) {
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 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, 25});
ASSERT_TRUE(maybe_position.has_value());
EXPECT_EQ(*maybe_position, (SourcePosition{id, {7, 8}, {7, 15}}));
}
TEST(LanguageServer, GotoDefinitionClassSuperType) {
const std::string source =
"type void;\n"