diff options
Diffstat (limited to 'modules/gdscript/gdscript_analyzer.cpp')
-rw-r--r-- | modules/gdscript/gdscript_analyzer.cpp | 94 |
1 files changed, 64 insertions, 30 deletions
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index d3445b8cc0..9f9accf507 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -1553,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) { @@ -1772,6 +1772,15 @@ void GDScriptAnalyzer::resolve_assignable(GDScriptParser::AssignableNode *p_assi bool is_constant = p_assignable->type == GDScriptParser::Node::CONSTANT; +#ifdef DEBUG_ENABLED + if (p_assignable->identifier != nullptr && p_assignable->identifier->suite != nullptr && p_assignable->identifier->suite->parent_block != nullptr) { + if (p_assignable->identifier->suite->parent_block->has_local(p_assignable->identifier->name)) { + const GDScriptParser::SuiteNode::Local &local = p_assignable->identifier->suite->parent_block->get_local(p_assignable->identifier->name); + parser->push_warning(p_assignable->identifier, GDScriptWarning::CONFUSABLE_LOCAL_DECLARATION, local.get_name(), p_assignable->identifier->name); + } + } +#endif + GDScriptParser::DataType specified_type; bool has_specified_type = p_assignable->datatype_specifier != nullptr; if (has_specified_type) { @@ -1874,9 +1883,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 +1897,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 } @@ -2052,7 +2059,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 } @@ -2148,7 +2155,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); } @@ -3294,17 +3301,26 @@ void GDScriptAnalyzer::reduce_dictionary(GDScriptParser::DictionaryNode *p_dicti void GDScriptAnalyzer::reduce_get_node(GDScriptParser::GetNodeNode *p_get_node) { GDScriptParser::DataType result; - result.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; - result.kind = GDScriptParser::DataType::NATIVE; - result.native_type = SNAME("Node"); - result.builtin_type = Variant::OBJECT; + result.kind = GDScriptParser::DataType::VARIANT; + + if (!ClassDB::is_parent_class(parser->current_class->base_type.native_type, SNAME("Node"))) { + push_error(vformat(R"*(Cannot use shorthand "get_node()" notation ("%c") on a class that isn't a node.)*", p_get_node->use_dollar ? '$' : '%'), p_get_node); + p_get_node->set_datatype(result); + return; + } - if (!ClassDB::is_parent_class(parser->current_class->base_type.native_type, result.native_type)) { - push_error(R"*(Cannot use shorthand "get_node()" notation ("$") on a class that isn't a node.)*", p_get_node); + if (static_context) { + push_error(vformat(R"*(Cannot use shorthand "get_node()" notation ("%c") in a static function.)*", p_get_node->use_dollar ? '$' : '%'), p_get_node); + p_get_node->set_datatype(result); + return; } mark_lambda_use_self(); + result.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT; + result.kind = GDScriptParser::DataType::NATIVE; + result.builtin_type = Variant::OBJECT; + result.native_type = SNAME("Node"); p_get_node->set_datatype(result); } @@ -3462,6 +3478,9 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod 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()); + if (script_class->outer != nullptr) { + p_identifier->source = GDScriptParser::IdentifierNode::MEMBER_CLASS; + } return; } @@ -3520,12 +3539,14 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod case GDScriptParser::ClassNode::Member::FUNCTION: { if (is_base && (!base.is_meta_type || member.function->is_static)) { p_identifier->set_datatype(make_callable_type(member.function->info)); + p_identifier->source = GDScriptParser::IdentifierNode::MEMBER_FUNCTION; return; } } break; case GDScriptParser::ClassNode::Member::CLASS: { reduce_identifier_from_base_set_class(p_identifier, member.get_datatype()); + p_identifier->source = GDScriptParser::IdentifierNode::MEMBER_CLASS; return; } @@ -3664,9 +3685,17 @@ void GDScriptAnalyzer::reduce_identifier(GDScriptParser::IdentifierNode *p_ident found_source = true; } break; case GDScriptParser::IdentifierNode::UNDEFINED_SOURCE: + case GDScriptParser::IdentifierNode::MEMBER_FUNCTION: + case GDScriptParser::IdentifierNode::MEMBER_CLASS: break; } +#ifdef DEBUG_ENABLED + if (!found_source && p_identifier->suite != nullptr && p_identifier->suite->has_local(p_identifier->name)) { + parser->push_warning(p_identifier, GDScriptWarning::CONFUSABLE_LOCAL_USAGE, p_identifier->name); + } +#endif + // Not a local, so check members. if (!found_source) { reduce_identifier_from_base(p_identifier); @@ -4517,6 +4546,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; @@ -4890,8 +4923,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; @@ -4901,29 +4934,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; @@ -4931,19 +4965,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); |