Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Autocompletion: Reintroduce enum options on assignment #96326

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions modules/gdscript/gdscript_editor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2112,7 +2112,7 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context,
// Look in blocks first.
int last_assign_line = -1;
const GDScriptParser::ExpressionNode *last_assigned_expression = nullptr;
GDScriptParser::DataType id_type;
GDScriptCompletionIdentifier id_type;
GDScriptParser::SuiteNode *suite = p_context.current_suite;
bool is_function_parameter = false;

Expand All @@ -2134,7 +2134,7 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context,
if (can_be_local && suite && suite->has_local(p_identifier->name)) {
const GDScriptParser::SuiteNode::Local &local = suite->get_local(p_identifier->name);

id_type = local.get_datatype();
id_type.type = local.get_datatype();

// Check initializer as the first assignment.
switch (local.type) {
Expand Down Expand Up @@ -2172,7 +2172,7 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context,
base.type.is_meta_type = p_context.current_function && p_context.current_function->is_static;

if (_guess_identifier_type_from_base(p_context, base, p_identifier->name, base_identifier)) {
id_type = base_identifier.type;
id_type = base_identifier;
}
}
}
Expand Down Expand Up @@ -2212,7 +2212,7 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context,
c.current_line = type_test->operand->start_line;
c.current_suite = suite;
if (type_test->test_datatype.is_hard_type()) {
id_type = type_test->test_datatype;
id_type.type = type_test->test_datatype;
if (last_assign_line < c.current_line) {
// Override last assignment.
last_assign_line = c.current_line;
Expand All @@ -2230,10 +2230,10 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context,
c.current_line = last_assign_line;
GDScriptCompletionIdentifier assigned_type;
if (_guess_expression_type(c, last_assigned_expression, assigned_type)) {
if (id_type.is_set() && assigned_type.type.is_set() && !GDScriptAnalyzer::check_type_compatibility(id_type, assigned_type.type)) {
if (id_type.type.is_set() && assigned_type.type.is_set() && !GDScriptAnalyzer::check_type_compatibility(id_type.type, assigned_type.type)) {
// The assigned type is incompatible. The annotated type takes priority.
r_type = id_type;
r_type.assigned_expression = last_assigned_expression;
r_type.type = id_type;
} else {
r_type = assigned_type;
}
Expand All @@ -2251,8 +2251,8 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context,
GDScriptParser::FunctionNode *parent_function = base_type.class_type->get_member(p_context.current_function->identifier->name).function;
if (parent_function->parameters_indices.has(p_identifier->name)) {
const GDScriptParser::ParameterNode *parameter = parent_function->parameters[parent_function->parameters_indices[p_identifier->name]];
if ((!id_type.is_set() || id_type.is_variant()) && parameter->get_datatype().is_hard_type()) {
id_type = parameter->get_datatype();
if ((!id_type.type.is_set() || id_type.type.is_variant()) && parameter->get_datatype().is_hard_type()) {
id_type.type = parameter->get_datatype();
}
if (parameter->initializer) {
GDScriptParser::CompletionContext c = p_context;
Expand All @@ -2268,7 +2268,7 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context,
base_type = base_type.class_type->base_type;
break;
case GDScriptParser::DataType::NATIVE: {
if (id_type.is_set() && !id_type.is_variant()) {
if (id_type.type.is_set() && !id_type.type.is_variant()) {
base_type = GDScriptParser::DataType();
break;
}
Expand All @@ -2289,8 +2289,8 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context,
}
}

if (id_type.is_set() && !id_type.is_variant()) {
r_type.type = id_type;
if (id_type.type.is_set() && !id_type.type.is_variant()) {
r_type = id_type;
return true;
}

Expand Down
26 changes: 20 additions & 6 deletions modules/gdscript/gdscript_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ void GDScriptParser::override_completion_context(const Node *p_for_node, Complet
if (!for_completion) {
return;
}
if (completion_context.node != p_for_node) {
if (p_for_node == nullptr || completion_context.node != p_for_node) {
return;
}
CompletionContext context;
Expand All @@ -264,8 +264,8 @@ void GDScriptParser::override_completion_context(const Node *p_for_node, Complet
completion_context = context;
}

void GDScriptParser::make_completion_context(CompletionType p_type, Node *p_node, int p_argument) {
if (!for_completion) {
void GDScriptParser::make_completion_context(CompletionType p_type, Node *p_node, int p_argument, bool p_force) {
if (!for_completion || (!p_force && completion_context.type != COMPLETION_NONE)) {
return;
}
if (previous.cursor_place != GDScriptTokenizerText::CURSOR_MIDDLE && previous.cursor_place != GDScriptTokenizerText::CURSOR_END && current.cursor_place == GDScriptTokenizerText::CURSOR_NONE) {
Expand All @@ -283,8 +283,8 @@ void GDScriptParser::make_completion_context(CompletionType p_type, Node *p_node
completion_context = context;
}

void GDScriptParser::make_completion_context(CompletionType p_type, Variant::Type p_builtin_type) {
if (!for_completion) {
void GDScriptParser::make_completion_context(CompletionType p_type, Variant::Type p_builtin_type, bool p_force) {
if (!for_completion || (!p_force && completion_context.type != COMPLETION_NONE)) {
return;
}
if (previous.cursor_place != GDScriptTokenizerText::CURSOR_MIDDLE && previous.cursor_place != GDScriptTokenizerText::CURSOR_END && current.cursor_place == GDScriptTokenizerText::CURSOR_NONE) {
Expand Down Expand Up @@ -2471,7 +2471,7 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_precedence(Precedence p_pr
}

// Completion can appear whenever an expression is expected.
make_completion_context(COMPLETION_IDENTIFIER, nullptr);
make_completion_context(COMPLETION_IDENTIFIER, nullptr, -1, false);

GDScriptTokenizer::Token token = current;
GDScriptTokenizer::Token::Type token_type = token.type;
Expand All @@ -2488,8 +2488,17 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_precedence(Precedence p_pr

advance(); // Only consume the token if there's a valid rule.

// After a token was consumed, update the completion context regardless of a previously set context.

ExpressionNode *previous_operand = (this->*prefix_rule)(nullptr, p_can_assign);

#ifdef TOOLS_ENABLED
// HACK: We can't create a context in parse_identifier since it is used in places were we don't want completion.
if (previous_operand != nullptr && previous_operand->type == GDScriptParser::Node::IDENTIFIER && prefix_rule == static_cast<ParseFunction>(&GDScriptParser::parse_identifier)) {
make_completion_context(COMPLETION_IDENTIFIER, previous_operand);
}
#endif

while (p_precedence <= get_rule(current.type)->precedence) {
if (previous_operand == nullptr || (p_stop_on_assign && current.type == GDScriptTokenizer::Token::EQUAL) || lambda_ended) {
return previous_operand;
Expand Down Expand Up @@ -2924,6 +2933,11 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_assignment(ExpressionNode
}
assignment->assignee = p_previous_operand;
assignment->assigned_value = parse_expression(false);
#ifdef TOOLS_ENABLED
if (assignment->assigned_value != nullptr && assignment->assigned_value->type == GDScriptParser::Node::IDENTIFIER) {
override_completion_context(assignment->assigned_value, COMPLETION_ASSIGN, assignment);
}
#endif
if (assignment->assigned_value == nullptr) {
push_error(R"(Expected an expression after "=".)");
}
Expand Down
7 changes: 5 additions & 2 deletions modules/gdscript/gdscript_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -1455,8 +1455,11 @@ class GDScriptParser {
}
void apply_pending_warnings();
#endif
void make_completion_context(CompletionType p_type, Node *p_node, int p_argument = -1);
void make_completion_context(CompletionType p_type, Variant::Type p_builtin_type);
// Setting p_force to false will prevent the completion context from being update if a context was already set before.
// This should only be done when we push context before we consumed any tokens for the corresponding structure.
// See parse_precedence for an example.
void make_completion_context(CompletionType p_type, Node *p_node, int p_argument = -1, bool p_force = true);
void make_completion_context(CompletionType p_type, Variant::Type p_builtin_type, bool p_force = true);
// In some cases it might become necessary to alter the completion context after parsing a subexpression.
// For example to not override COMPLETE_CALL_ARGUMENTS with COMPLETION_NONE from string literals.
void override_completion_context(const Node *p_for_node, CompletionType p_type, Node *p_node, int p_argument = -1);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[output]
include=[
{"display": "new"},
{"display": "SIZE_EXPAND"},
{"display": "SIZE_EXPAND_FILL"},
{"display": "SIZE_FILL"},
{"display": "SIZE_SHRINK_BEGIN"},
{"display": "SIZE_SHRINK_CENTER"},
{"display": "SIZE_SHRINK_END"},
]
exclude=[
{"display": "Control.SIZE_EXPAND"},
{"display": "Control.SIZE_EXPAND_FILL"},
{"display": "Control.SIZE_FILL"},
{"display": "Control.SIZE_SHRINK_BEGIN"},
{"display": "Control.SIZE_SHRINK_CENTER"},
{"display": "Control.SIZE_SHRINK_END"},
{"display": "contro_var"}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
extends Control

var contro_var

func _ready():
size_flags_horizontal = Control.➡
pass
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[output]
include=[
{"display": "new"},
{"display": "SIZE_EXPAND"},
{"display": "SIZE_EXPAND_FILL"},
{"display": "SIZE_FILL"},
{"display": "SIZE_SHRINK_BEGIN"},
{"display": "SIZE_SHRINK_CENTER"},
{"display": "SIZE_SHRINK_END"},
]
exclude=[
{"display": "Control.SIZE_EXPAND"},
{"display": "Control.SIZE_EXPAND_FILL"},
{"display": "Control.SIZE_FILL"},
{"display": "Control.SIZE_SHRINK_BEGIN"},
{"display": "Control.SIZE_SHRINK_CENTER"},
{"display": "Control.SIZE_SHRINK_END"},
{"display": "contro_var"}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
extends Control

var contro_var

func _ready():
size_flags_horizontal = Control.SIZE➡
pass
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[output]
include=[
{"display": "Control.SIZE_EXPAND"},
{"display": "Control.SIZE_EXPAND_FILL"},
{"display": "Control.SIZE_FILL"},
{"display": "Control.SIZE_SHRINK_BEGIN"},
{"display": "Control.SIZE_SHRINK_CENTER"},
{"display": "Control.SIZE_SHRINK_END"},
]
exclude=[
{"display": "contro_var"}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
extends Control

var contro_var

func _ready():
size_flags_horizontal = Con➡
pass
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[output]
include=[
{"display": "Control.SIZE_EXPAND"},
{"display": "Control.SIZE_EXPAND_FILL"},
{"display": "Control.SIZE_FILL"},
{"display": "Control.SIZE_SHRINK_BEGIN"},
{"display": "Control.SIZE_SHRINK_CENTER"},
{"display": "Control.SIZE_SHRINK_END"},
]
exclude=[
{"display": "contro_var"}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
extends Control

var contro_var

func _ready():
size_flags_horizontal = ➡
pass
Loading