mirror of
https://github.com/godotengine/godot.git
synced 2025-01-12 20:22:49 +08:00
Autocompletion: reintroduce enum options on assignment
This commit is contained in:
parent
a5830f6eb9
commit
171c522290
@ -2112,7 +2112,7 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context,
|
|||||||
// Look in blocks first.
|
// Look in blocks first.
|
||||||
int last_assign_line = -1;
|
int last_assign_line = -1;
|
||||||
const GDScriptParser::ExpressionNode *last_assigned_expression = nullptr;
|
const GDScriptParser::ExpressionNode *last_assigned_expression = nullptr;
|
||||||
GDScriptParser::DataType id_type;
|
GDScriptCompletionIdentifier id_type;
|
||||||
GDScriptParser::SuiteNode *suite = p_context.current_suite;
|
GDScriptParser::SuiteNode *suite = p_context.current_suite;
|
||||||
bool is_function_parameter = false;
|
bool is_function_parameter = false;
|
||||||
|
|
||||||
@ -2134,7 +2134,7 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context,
|
|||||||
if (can_be_local && suite && suite->has_local(p_identifier->name)) {
|
if (can_be_local && suite && suite->has_local(p_identifier->name)) {
|
||||||
const GDScriptParser::SuiteNode::Local &local = suite->get_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.
|
// Check initializer as the first assignment.
|
||||||
switch (local.type) {
|
switch (local.type) {
|
||||||
@ -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;
|
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)) {
|
if (_guess_identifier_type_from_base(p_context, base, p_identifier->name, base_identifier)) {
|
||||||
id_type = base_identifier.type;
|
id_type = base_identifier;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2212,7 +2212,7 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context,
|
|||||||
c.current_line = type_test->operand->start_line;
|
c.current_line = type_test->operand->start_line;
|
||||||
c.current_suite = suite;
|
c.current_suite = suite;
|
||||||
if (type_test->test_datatype.is_hard_type()) {
|
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) {
|
if (last_assign_line < c.current_line) {
|
||||||
// Override last assignment.
|
// Override last assignment.
|
||||||
last_assign_line = c.current_line;
|
last_assign_line = c.current_line;
|
||||||
@ -2230,10 +2230,10 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context,
|
|||||||
c.current_line = last_assign_line;
|
c.current_line = last_assign_line;
|
||||||
GDScriptCompletionIdentifier assigned_type;
|
GDScriptCompletionIdentifier assigned_type;
|
||||||
if (_guess_expression_type(c, last_assigned_expression, 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.
|
// The assigned type is incompatible. The annotated type takes priority.
|
||||||
|
r_type = id_type;
|
||||||
r_type.assigned_expression = last_assigned_expression;
|
r_type.assigned_expression = last_assigned_expression;
|
||||||
r_type.type = id_type;
|
|
||||||
} else {
|
} else {
|
||||||
r_type = assigned_type;
|
r_type = assigned_type;
|
||||||
}
|
}
|
||||||
@ -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;
|
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)) {
|
if (parent_function->parameters_indices.has(p_identifier->name)) {
|
||||||
const GDScriptParser::ParameterNode *parameter = parent_function->parameters[parent_function->parameters_indices[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()) {
|
if ((!id_type.type.is_set() || id_type.type.is_variant()) && parameter->get_datatype().is_hard_type()) {
|
||||||
id_type = parameter->get_datatype();
|
id_type.type = parameter->get_datatype();
|
||||||
}
|
}
|
||||||
if (parameter->initializer) {
|
if (parameter->initializer) {
|
||||||
GDScriptParser::CompletionContext c = p_context;
|
GDScriptParser::CompletionContext c = p_context;
|
||||||
@ -2268,7 +2268,7 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context,
|
|||||||
base_type = base_type.class_type->base_type;
|
base_type = base_type.class_type->base_type;
|
||||||
break;
|
break;
|
||||||
case GDScriptParser::DataType::NATIVE: {
|
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();
|
base_type = GDScriptParser::DataType();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2289,8 +2289,8 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (id_type.is_set() && !id_type.is_variant()) {
|
if (id_type.type.is_set() && !id_type.type.is_variant()) {
|
||||||
r_type.type = id_type;
|
r_type = id_type;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,7 +249,7 @@ void GDScriptParser::override_completion_context(const Node *p_for_node, Complet
|
|||||||
if (!for_completion) {
|
if (!for_completion) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (completion_context.node != p_for_node) {
|
if (p_for_node == nullptr || completion_context.node != p_for_node) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
CompletionContext context;
|
CompletionContext context;
|
||||||
@ -264,8 +264,8 @@ void GDScriptParser::override_completion_context(const Node *p_for_node, Complet
|
|||||||
completion_context = context;
|
completion_context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GDScriptParser::make_completion_context(CompletionType p_type, Node *p_node, int p_argument) {
|
void GDScriptParser::make_completion_context(CompletionType p_type, Node *p_node, int p_argument, bool p_force) {
|
||||||
if (!for_completion) {
|
if (!for_completion || (!p_force && completion_context.type != COMPLETION_NONE)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (previous.cursor_place != GDScriptTokenizerText::CURSOR_MIDDLE && previous.cursor_place != GDScriptTokenizerText::CURSOR_END && current.cursor_place == GDScriptTokenizerText::CURSOR_NONE) {
|
if (previous.cursor_place != GDScriptTokenizerText::CURSOR_MIDDLE && previous.cursor_place != GDScriptTokenizerText::CURSOR_END && current.cursor_place == GDScriptTokenizerText::CURSOR_NONE) {
|
||||||
@ -283,8 +283,8 @@ void GDScriptParser::make_completion_context(CompletionType p_type, Node *p_node
|
|||||||
completion_context = context;
|
completion_context = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GDScriptParser::make_completion_context(CompletionType p_type, Variant::Type p_builtin_type) {
|
void GDScriptParser::make_completion_context(CompletionType p_type, Variant::Type p_builtin_type, bool p_force) {
|
||||||
if (!for_completion) {
|
if (!for_completion || (!p_force && completion_context.type != COMPLETION_NONE)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (previous.cursor_place != GDScriptTokenizerText::CURSOR_MIDDLE && previous.cursor_place != GDScriptTokenizerText::CURSOR_END && current.cursor_place == GDScriptTokenizerText::CURSOR_NONE) {
|
if (previous.cursor_place != GDScriptTokenizerText::CURSOR_MIDDLE && previous.cursor_place != GDScriptTokenizerText::CURSOR_END && current.cursor_place == GDScriptTokenizerText::CURSOR_NONE) {
|
||||||
@ -2471,7 +2471,7 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_precedence(Precedence p_pr
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Completion can appear whenever an expression is expected.
|
// 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 token = current;
|
||||||
GDScriptTokenizer::Token::Type token_type = token.type;
|
GDScriptTokenizer::Token::Type token_type = token.type;
|
||||||
@ -2488,8 +2488,17 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_precedence(Precedence p_pr
|
|||||||
|
|
||||||
advance(); // Only consume the token if there's a valid rule.
|
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);
|
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) {
|
while (p_precedence <= get_rule(current.type)->precedence) {
|
||||||
if (previous_operand == nullptr || (p_stop_on_assign && current.type == GDScriptTokenizer::Token::EQUAL) || lambda_ended) {
|
if (previous_operand == nullptr || (p_stop_on_assign && current.type == GDScriptTokenizer::Token::EQUAL) || lambda_ended) {
|
||||||
return previous_operand;
|
return previous_operand;
|
||||||
@ -2924,6 +2933,11 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_assignment(ExpressionNode
|
|||||||
}
|
}
|
||||||
assignment->assignee = p_previous_operand;
|
assignment->assignee = p_previous_operand;
|
||||||
assignment->assigned_value = parse_expression(false);
|
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) {
|
if (assignment->assigned_value == nullptr) {
|
||||||
push_error(R"(Expected an expression after "=".)");
|
push_error(R"(Expected an expression after "=".)");
|
||||||
}
|
}
|
||||||
|
@ -1455,8 +1455,11 @@ private:
|
|||||||
}
|
}
|
||||||
void apply_pending_warnings();
|
void apply_pending_warnings();
|
||||||
#endif
|
#endif
|
||||||
void make_completion_context(CompletionType p_type, Node *p_node, int p_argument = -1);
|
// Setting p_force to false will prevent the completion context from being update if a context was already set before.
|
||||||
void make_completion_context(CompletionType p_type, Variant::Type p_builtin_type);
|
// 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.
|
// 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.
|
// 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);
|
void override_completion_context(const Node *p_for_node, CompletionType p_type, Node *p_node, int p_argument = -1);
|
||||||
|
@ -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"}
|
||||||
|
]
|
@ -0,0 +1,7 @@
|
|||||||
|
extends Control
|
||||||
|
|
||||||
|
var contro_var
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
size_flags_horizontal = Control.➡
|
||||||
|
pass
|
@ -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"}
|
||||||
|
]
|
@ -0,0 +1,7 @@
|
|||||||
|
extends Control
|
||||||
|
|
||||||
|
var contro_var
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
size_flags_horizontal = Control.SIZE➡
|
||||||
|
pass
|
@ -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"}
|
||||||
|
]
|
@ -0,0 +1,7 @@
|
|||||||
|
extends Control
|
||||||
|
|
||||||
|
var contro_var
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
size_flags_horizontal = Con➡
|
||||||
|
pass
|
@ -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"}
|
||||||
|
]
|
@ -0,0 +1,7 @@
|
|||||||
|
extends Control
|
||||||
|
|
||||||
|
var contro_var
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
size_flags_horizontal = ➡
|
||||||
|
pass
|
Loading…
Reference in New Issue
Block a user