summaryrefslogtreecommitdiffstats
path: root/modules/gdscript/gdscript_analyzer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'modules/gdscript/gdscript_analyzer.cpp')
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp175
1 files changed, 111 insertions, 64 deletions
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index 13fd115c43..01e94ebb22 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -30,6 +30,9 @@
#include "gdscript_analyzer.h"
+#include "gdscript.h"
+#include "gdscript_utility_functions.h"
+
#include "core/config/engine.h"
#include "core/config/project_settings.h"
#include "core/core_constants.h"
@@ -39,8 +42,6 @@
#include "core/object/class_db.h"
#include "core/object/script_language.h"
#include "core/templates/hash_map.h"
-#include "gdscript.h"
-#include "gdscript_utility_functions.h"
#include "scene/resources/packed_scene.h"
#if defined(TOOLS_ENABLED) && !defined(DISABLE_DEPRECATED)
@@ -1552,7 +1553,7 @@ void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode *
}
parser->push_warning(p_function->parameters[i]->identifier, GDScriptWarning::UNUSED_PARAMETER, visible_name, p_function->parameters[i]->identifier->name);
}
- is_shadowing(p_function->parameters[i]->identifier, "function parameter");
+ is_shadowing(p_function->parameters[i]->identifier, "function parameter", true);
#endif // DEBUG_ENABLED
#ifdef TOOLS_ENABLED
if (p_function->parameters[i]->initializer) {
@@ -1610,11 +1611,10 @@ void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode *
GDScriptParser::DataType parent_return_type;
List<GDScriptParser::DataType> parameters_types;
int default_par_count = 0;
- bool is_static = false;
- bool is_vararg = false;
+ BitField<MethodFlags> method_flags;
StringName native_base;
- if (!p_is_lambda && get_function_signature(p_function, false, base_type, function_name, parent_return_type, parameters_types, default_par_count, is_static, is_vararg, &native_base)) {
- bool valid = p_function->is_static == is_static;
+ if (!p_is_lambda && get_function_signature(p_function, false, base_type, function_name, parent_return_type, parameters_types, default_par_count, method_flags, &native_base)) {
+ bool valid = p_function->is_static == method_flags.has_flag(METHOD_FLAG_STATIC);
valid = valid && parent_return_type == p_function->get_datatype();
int par_count_diff = p_function->parameters.size() - parameters_types.size();
@@ -1874,9 +1874,8 @@ void GDScriptAnalyzer::resolve_variable(GDScriptParser::VariableNode *p_variable
} else if (p_variable->assignments == 0) {
parser->push_warning(p_variable, GDScriptWarning::UNASSIGNED_VARIABLE, p_variable->identifier->name);
}
-
- is_shadowing(p_variable->identifier, kind);
}
+ is_shadowing(p_variable->identifier, kind, p_is_local);
#endif
}
@@ -1889,9 +1888,8 @@ void GDScriptAnalyzer::resolve_constant(GDScriptParser::ConstantNode *p_constant
if (p_constant->usages == 0) {
parser->push_warning(p_constant, GDScriptWarning::UNUSED_LOCAL_CONSTANT, p_constant->identifier->name);
}
-
- is_shadowing(p_constant->identifier, kind);
}
+ is_shadowing(p_constant->identifier, kind, p_is_local);
#endif
}
@@ -2029,9 +2027,8 @@ void GDScriptAnalyzer::resolve_for(GDScriptParser::ForNode *p_for) {
GDScriptParser::DataType return_type;
List<GDScriptParser::DataType> par_types;
int default_arg_count = 0;
- bool is_static = false;
- bool is_vararg = false;
- if (get_function_signature(p_for->list, false, list_type, CoreStringNames::get_singleton()->_iter_get, return_type, par_types, default_arg_count, is_static, is_vararg)) {
+ BitField<MethodFlags> method_flags;
+ if (get_function_signature(p_for->list, false, list_type, CoreStringNames::get_singleton()->_iter_get, return_type, par_types, default_arg_count, method_flags)) {
variable_type = return_type;
variable_type.type_source = list_type.type_source;
} else if (!list_type.is_hard_type()) {
@@ -2053,7 +2050,7 @@ void GDScriptAnalyzer::resolve_for(GDScriptParser::ForNode *p_for) {
p_for->set_datatype(p_for->loop->get_datatype());
#ifdef DEBUG_ENABLED
if (p_for->variable) {
- is_shadowing(p_for->variable, R"("for" iterator variable)");
+ is_shadowing(p_for->variable, R"("for" iterator variable)", true);
}
#endif
}
@@ -2149,7 +2146,7 @@ void GDScriptAnalyzer::resolve_match_pattern(GDScriptParser::PatternNode *p_matc
}
p_match_pattern->bind->set_datatype(result);
#ifdef DEBUG_ENABLED
- is_shadowing(p_match_pattern->bind, "pattern bind");
+ is_shadowing(p_match_pattern->bind, "pattern bind", true);
if (p_match_pattern->bind->usages == 0 && !String(p_match_pattern->bind->name).begins_with("_")) {
parser->push_warning(p_match_pattern->bind, GDScriptWarning::UNUSED_VARIABLE, p_match_pattern->bind->name);
}
@@ -2470,9 +2467,15 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig
GDScriptParser::DataType assignee_type = p_assignment->assignee->get_datatype();
- if (assignee_type.is_constant || (p_assignment->assignee->type == GDScriptParser::Node::SUBSCRIPT && static_cast<GDScriptParser::SubscriptNode *>(p_assignment->assignee)->base->is_constant)) {
+ if (assignee_type.is_constant) {
push_error("Cannot assign a new value to a constant.", p_assignment->assignee);
return;
+ } else if (p_assignment->assignee->type == GDScriptParser::Node::SUBSCRIPT && static_cast<GDScriptParser::SubscriptNode *>(p_assignment->assignee)->base->is_constant) {
+ const GDScriptParser::DataType &base_type = static_cast<GDScriptParser::SubscriptNode *>(p_assignment->assignee)->base->datatype;
+ if (base_type.kind != GDScriptParser::DataType::SCRIPT && base_type.kind != GDScriptParser::DataType::CLASS) { // Static variables.
+ push_error("Cannot assign a new value to a constant.", p_assignment->assignee);
+ return;
+ }
} else if (assignee_type.is_read_only) {
push_error("Cannot assign a new value to a read-only property.", p_assignment->assignee);
return;
@@ -3084,15 +3087,14 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
return;
}
- bool is_static = false;
- bool is_vararg = false;
int default_arg_count = 0;
+ BitField<MethodFlags> method_flags;
GDScriptParser::DataType return_type;
List<GDScriptParser::DataType> par_types;
bool is_constructor = (base_type.is_meta_type || (p_call->callee && p_call->callee->type == GDScriptParser::Node::IDENTIFIER)) && p_call->function_name == SNAME("new");
- if (get_function_signature(p_call, is_constructor, base_type, p_call->function_name, return_type, par_types, default_arg_count, is_static, is_vararg)) {
+ if (get_function_signature(p_call, is_constructor, base_type, p_call->function_name, return_type, par_types, default_arg_count, method_flags)) {
// If the function require typed arrays we must make literals be typed.
for (const KeyValue<int, GDScriptParser::ArrayNode *> &E : arrays) {
int index = E.key;
@@ -3100,14 +3102,14 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
update_array_literal_element_type(E.value, par_types[index].get_container_element_type());
}
}
- validate_call_arg(par_types, default_arg_count, is_vararg, p_call);
+ validate_call_arg(par_types, default_arg_count, method_flags.has_flag(METHOD_FLAG_VARARG), p_call);
if (base_type.kind == GDScriptParser::DataType::ENUM && base_type.is_meta_type) {
// Enum type is treated as a dictionary value for function calls.
base_type.is_meta_type = false;
}
- if (is_self && static_context && !is_static) {
+ if (is_self && static_context && !method_flags.has_flag(METHOD_FLAG_STATIC)) {
if (parser->current_function) {
// Get the parent function above any lambda.
GDScriptParser::FunctionNode *parent_function = parser->current_function;
@@ -3118,10 +3120,10 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
} else {
push_error(vformat(R"*(Cannot call non-static function "%s()" for static variable initializer.)*", p_call->function_name), p_call);
}
- } else if (!is_self && base_type.is_meta_type && !is_static) {
+ } else if (!is_self && base_type.is_meta_type && !method_flags.has_flag(METHOD_FLAG_STATIC)) {
base_type.is_meta_type = false; // For `to_string()`.
push_error(vformat(R"*(Cannot call non-static function "%s()" on the class "%s" directly. Make an instance instead.)*", p_call->function_name, base_type.to_string()), p_call);
- } else if (is_self && !is_static) {
+ } else if (is_self && !method_flags.has_flag(METHOD_FLAG_STATIC)) {
mark_lambda_use_self();
}
@@ -3130,11 +3132,12 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
}
#ifdef DEBUG_ENABLED
- if (p_is_root && return_type.kind != GDScriptParser::DataType::UNRESOLVED && return_type.builtin_type != Variant::NIL) {
+ if (p_is_root && return_type.kind != GDScriptParser::DataType::UNRESOLVED && return_type.builtin_type != Variant::NIL &&
+ !(p_call->is_super && p_call->function_name == GDScriptLanguage::get_singleton()->strings._init)) {
parser->push_warning(p_call, GDScriptWarning::RETURN_VALUE_DISCARDED, p_call->function_name);
}
- if (is_static && !is_constructor && !base_type.is_meta_type && !(is_self && static_context)) {
+ if (method_flags.has_flag(METHOD_FLAG_STATIC) && !is_constructor && !base_type.is_meta_type && !(is_self && static_context)) {
String caller_type = String(base_type.native_type);
if (caller_type.is_empty()) {
@@ -3357,7 +3360,7 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
base = *p_base;
}
- const StringName &name = p_identifier->name;
+ StringName name = p_identifier->name;
if (base.kind == GDScriptParser::DataType::ENUM) {
if (base.is_meta_type) {
@@ -3452,12 +3455,18 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
get_class_node_current_scope_classes(base_class, &script_classes);
}
+ bool is_constructor = base.is_meta_type && p_identifier->name == SNAME("new");
+
for (GDScriptParser::ClassNode *script_class : script_classes) {
if (p_base == nullptr && script_class->identifier && script_class->identifier->name == name) {
reduce_identifier_from_base_set_class(p_identifier, script_class->get_datatype());
return;
}
+ if (is_constructor) {
+ name = "_init";
+ }
+
if (script_class->has_member(name)) {
resolve_class_member(script_class, name, p_identifier);
@@ -3507,7 +3516,7 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
} break;
case GDScriptParser::ClassNode::Member::FUNCTION: {
- if (is_base && !base.is_meta_type) {
+ if (is_base && (!base.is_meta_type || member.function->is_static)) {
p_identifier->set_datatype(make_callable_type(member.function->info));
return;
}
@@ -3536,6 +3545,10 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
const StringName &native = base.native_type;
if (class_exists(native)) {
+ if (is_constructor) {
+ name = "_init";
+ }
+
MethodInfo method_info;
if (ClassDB::has_property(native, name)) {
StringName getter_name = ClassDB::get_property_getter(native, name);
@@ -4502,6 +4515,10 @@ Variant GDScriptAnalyzer::make_variable_default_value(GDScriptParser::VariableNo
return result;
}
+const HashMap<String, Ref<GDScriptParserRef>> &GDScriptAnalyzer::get_depended_parsers() {
+ return depended_parsers;
+}
+
GDScriptParser::DataType GDScriptAnalyzer::type_from_variant(const Variant &p_value, const GDScriptParser::Node *p_source) {
GDScriptParser::DataType result;
result.is_constant = true;
@@ -4509,7 +4526,16 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_variant(const Variant &p_va
result.builtin_type = p_value.get_type();
result.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; // Constant has explicit type.
- if (p_value.get_type() == Variant::OBJECT) {
+ if (p_value.get_type() == Variant::ARRAY) {
+ const Array &array = p_value;
+ if (array.get_typed_script()) {
+ result.set_container_element_type(type_from_metatype(make_script_meta_type(array.get_typed_script())));
+ } else if (array.get_typed_class_name()) {
+ result.set_container_element_type(type_from_metatype(make_native_meta_type(array.get_typed_class_name())));
+ } else if (array.get_typed_builtin() != Variant::NIL) {
+ result.set_container_element_type(type_from_metatype(make_builtin_meta_type((Variant::Type)array.get_typed_builtin())));
+ }
+ } else if (p_value.get_type() == Variant::OBJECT) {
// Object is treated as a native type, not a builtin type.
result.kind = GDScriptParser::DataType::NATIVE;
@@ -4650,9 +4676,8 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_property(const PropertyInfo
return result;
}
-bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, bool p_is_constructor, GDScriptParser::DataType p_base_type, const StringName &p_function, GDScriptParser::DataType &r_return_type, List<GDScriptParser::DataType> &r_par_types, int &r_default_arg_count, bool &r_static, bool &r_vararg, StringName *r_native_class) {
- r_static = false;
- r_vararg = false;
+bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, bool p_is_constructor, GDScriptParser::DataType p_base_type, const StringName &p_function, GDScriptParser::DataType &r_return_type, List<GDScriptParser::DataType> &r_par_types, int &r_default_arg_count, BitField<MethodFlags> &r_method_flags, StringName *r_native_class) {
+ r_method_flags = METHOD_FLAGS_DEFAULT;
r_default_arg_count = 0;
if (r_native_class) {
*r_native_class = StringName();
@@ -4685,10 +4710,9 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, bo
for (const MethodInfo &E : methods) {
if (E.name == p_function) {
- function_signature_from_info(E, r_return_type, r_par_types, r_default_arg_count, r_static, r_vararg);
- r_static = Variant::is_builtin_method_static(p_base_type.builtin_type, function_name);
+ function_signature_from_info(E, r_return_type, r_par_types, r_default_arg_count, r_method_flags);
// Cannot use non-const methods on enums.
- if (!r_static && was_enum && !(E.flags & METHOD_FLAG_CONST)) {
+ if (!r_method_flags.has_flag(METHOD_FLAG_STATIC) && was_enum && !(E.flags & METHOD_FLAG_CONST)) {
push_error(vformat(R"*(Cannot call non-const Dictionary function "%s()" on enum "%s".)*", p_function, p_base_type.enum_type), p_source);
}
return true;
@@ -4718,8 +4742,8 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, bo
}
if (p_is_constructor) {
- function_name = "_init";
- r_static = true;
+ function_name = GDScriptLanguage::get_singleton()->strings._init;
+ r_method_flags.set_flag(METHOD_FLAG_STATIC);
}
GDScriptParser::ClassNode *base_class = p_base_type.class_type;
@@ -4742,7 +4766,9 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, bo
}
if (found_function != nullptr) {
- r_static = p_is_constructor || found_function->is_static;
+ if (p_is_constructor || found_function->is_static) {
+ r_method_flags.set_flag(METHOD_FLAG_STATIC);
+ }
for (int i = 0; i < found_function->parameters.size(); i++) {
r_par_types.push_back(found_function->parameters[i]->get_datatype());
if (found_function->parameters[i]->initializer != nullptr) {
@@ -4762,7 +4788,7 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, bo
MethodInfo info = base_script->get_method_info(function_name);
if (!(info == MethodInfo())) {
- return function_signature_from_info(info, r_return_type, r_par_types, r_default_arg_count, r_static, r_vararg);
+ return function_signature_from_info(info, r_return_type, r_par_types, r_default_arg_count, r_method_flags);
}
base_script = base_script->get_base_script();
}
@@ -4773,7 +4799,7 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, bo
StringName script_class = p_base_type.kind == GDScriptParser::DataType::SCRIPT ? p_base_type.script_type->get_class_name() : StringName(GDScript::get_class_static());
if (ClassDB::get_method_info(script_class, function_name, &info)) {
- return function_signature_from_info(info, r_return_type, r_par_types, r_default_arg_count, r_static, r_vararg);
+ return function_signature_from_info(info, r_return_type, r_par_types, r_default_arg_count, r_method_flags);
}
}
@@ -4787,9 +4813,9 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, bo
MethodInfo info;
if (ClassDB::get_method_info(base_native, function_name, &info)) {
- bool valid = function_signature_from_info(info, r_return_type, r_par_types, r_default_arg_count, r_static, r_vararg);
+ bool valid = function_signature_from_info(info, r_return_type, r_par_types, r_default_arg_count, r_method_flags);
if (valid && Engine::get_singleton()->has_singleton(base_native)) {
- r_static = true;
+ r_method_flags.set_flag(METHOD_FLAG_STATIC);
}
#ifdef DEBUG_ENABLED
MethodBind *native_method = ClassDB::get_method(base_native, function_name);
@@ -4803,11 +4829,10 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, bo
return false;
}
-bool GDScriptAnalyzer::function_signature_from_info(const MethodInfo &p_info, GDScriptParser::DataType &r_return_type, List<GDScriptParser::DataType> &r_par_types, int &r_default_arg_count, bool &r_static, bool &r_vararg) {
+bool GDScriptAnalyzer::function_signature_from_info(const MethodInfo &p_info, GDScriptParser::DataType &r_return_type, List<GDScriptParser::DataType> &r_par_types, int &r_default_arg_count, BitField<MethodFlags> &r_method_flags) {
r_return_type = type_from_property(p_info.return_val);
r_default_arg_count = p_info.default_arguments.size();
- r_vararg = (p_info.flags & METHOD_FLAG_VARARG) != 0;
- r_static = (p_info.flags & METHOD_FLAG_STATIC) != 0;
+ r_method_flags = p_info.flags;
for (const PropertyInfo &E : p_info.arguments) {
r_par_types.push_back(type_from_property(E, true));
@@ -4867,8 +4892,8 @@ void GDScriptAnalyzer::validate_call_arg(const List<GDScriptParser::DataType> &p
}
#ifdef DEBUG_ENABLED
-void GDScriptAnalyzer::is_shadowing(GDScriptParser::IdentifierNode *p_local, const String &p_context) {
- const StringName &name = p_local->name;
+void GDScriptAnalyzer::is_shadowing(GDScriptParser::IdentifierNode *p_identifier, const String &p_context, const bool p_in_local_scope) {
+ const StringName &name = p_identifier->name;
GDScriptParser::DataType base = parser->current_class->get_datatype();
GDScriptParser::ClassNode *base_class = base.class_type;
@@ -4878,29 +4903,30 @@ void GDScriptAnalyzer::is_shadowing(GDScriptParser::IdentifierNode *p_local, con
for (MethodInfo &info : gdscript_funcs) {
if (info.name == name) {
- parser->push_warning(p_local, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, p_context, name, "built-in function");
+ parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, p_context, name, "built-in function");
return;
}
}
-
if (Variant::has_utility_function(name)) {
- parser->push_warning(p_local, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, p_context, name, "built-in function");
+ parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, p_context, name, "built-in function");
return;
} else if (ClassDB::class_exists(name)) {
- parser->push_warning(p_local, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, p_context, name, "global class");
+ parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, p_context, name, "global class");
return;
} else if (GDScriptParser::get_builtin_type(name) != Variant::VARIANT_MAX) {
- parser->push_warning(p_local, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, p_context, name, "built-in type");
+ parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, p_context, name, "built-in type");
return;
}
}
- while (base_class != nullptr) {
- if (base_class->has_member(name)) {
- parser->push_warning(p_local, GDScriptWarning::SHADOWED_VARIABLE, p_context, p_local->name, base_class->get_member(name).get_type_name(), itos(base_class->get_member(name).get_line()));
- return;
+ if (p_in_local_scope) {
+ while (base_class != nullptr) {
+ if (base_class->has_member(name)) {
+ parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE, p_context, p_identifier->name, base_class->get_member(name).get_type_name(), itos(base_class->get_member(name).get_line()));
+ return;
+ }
+ base_class = base_class->base_type.class_type;
}
- base_class = base_class->base_type.class_type;
}
StringName parent = base.native_type;
@@ -4908,19 +4934,19 @@ void GDScriptAnalyzer::is_shadowing(GDScriptParser::IdentifierNode *p_local, con
ERR_FAIL_COND_MSG(!class_exists(parent), "Non-existent native base class.");
if (ClassDB::has_method(parent, name, true)) {
- parser->push_warning(p_local, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_local->name, "method", parent);
+ parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_identifier->name, "method", parent);
return;
} else if (ClassDB::has_signal(parent, name, true)) {
- parser->push_warning(p_local, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_local->name, "signal", parent);
+ parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_identifier->name, "signal", parent);
return;
} else if (ClassDB::has_property(parent, name, true)) {
- parser->push_warning(p_local, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_local->name, "property", parent);
+ parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_identifier->name, "property", parent);
return;
} else if (ClassDB::has_integer_constant(parent, name, true)) {
- parser->push_warning(p_local, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_local->name, "constant", parent);
+ parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_identifier->name, "constant", parent);
return;
} else if (ClassDB::has_enum(parent, name, true)) {
- parser->push_warning(p_local, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_local->name, "enum", parent);
+ parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_identifier->name, "enum", parent);
return;
}
parent = ClassDB::get_parent_class(parent);
@@ -4937,6 +4963,17 @@ GDScriptParser::DataType GDScriptAnalyzer::get_operation_type(Variant::Operator
}
GDScriptParser::DataType GDScriptAnalyzer::get_operation_type(Variant::Operator p_operation, const GDScriptParser::DataType &p_a, const GDScriptParser::DataType &p_b, bool &r_valid, const GDScriptParser::Node *p_source) {
+ if (p_operation == Variant::OP_AND || p_operation == Variant::OP_OR) {
+ // Those work for any type of argument and always return a boolean.
+ // They don't use the Variant operator since they have short-circuit semantics.
+ r_valid = true;
+ GDScriptParser::DataType result;
+ result.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED;
+ result.kind = GDScriptParser::DataType::BUILTIN;
+ result.builtin_type = Variant::BOOL;
+ return result;
+ }
+
Variant::Type a_type = p_a.builtin_type;
Variant::Type b_type = p_b.builtin_type;
@@ -4955,11 +4992,21 @@ GDScriptParser::DataType GDScriptAnalyzer::get_operation_type(Variant::Operator
}
}
- Variant::ValidatedOperatorEvaluator op_eval = Variant::get_validated_operator_evaluator(p_operation, a_type, b_type);
+ GDScriptParser::DataType result;
bool hard_operation = p_a.is_hard_type() && p_b.is_hard_type();
+
+ if (p_operation == Variant::OP_ADD && a_type == Variant::ARRAY && b_type == Variant::ARRAY) {
+ if (p_a.has_container_element_type() && p_b.has_container_element_type() && p_a.get_container_element_type() == p_b.get_container_element_type()) {
+ r_valid = true;
+ result = p_a;
+ result.type_source = hard_operation ? GDScriptParser::DataType::ANNOTATED_INFERRED : GDScriptParser::DataType::INFERRED;
+ return result;
+ }
+ }
+
+ Variant::ValidatedOperatorEvaluator op_eval = Variant::get_validated_operator_evaluator(p_operation, a_type, b_type);
bool validated = op_eval != nullptr;
- GDScriptParser::DataType result;
if (validated) {
r_valid = true;
result.type_source = hard_operation ? GDScriptParser::DataType::ANNOTATED_INFERRED : GDScriptParser::DataType::INFERRED;