diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index e9c9cd501d..0ec94c72df 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -1669,6 +1669,9 @@ bool GDScriptInstance::set(const StringName &p_name, const Variant &p_value) { const GDScript::MemberInfo *member = &E->value; Variant value = p_value; if (member->data_type.has_type && !member->data_type.is_type(value)) { + if (!execute_access_restriction(p_name, script, script->member_access_restrictions[p_name])) { + return false; + } const Variant *args = &p_value; Callable::CallError err; Variant::construct(member->data_type.builtin_type, value, &args, 1, err); @@ -1677,10 +1680,15 @@ bool GDScriptInstance::set(const StringName &p_name, const Variant &p_value) { } } if (likely(script->valid) && member->setter) { + if (!execute_access_restriction(member->setter, script, script->member_access_restrictions[p_name])) { + return false; + } const Variant *args = &value; Callable::CallError err; callp(member->setter, &args, 1, err); return err.error == Callable::CallError::CALL_OK; + } else if (!execute_access_restriction(member->setter, script, script->member_access_restrictions[p_name])) { + return false; } else { members.write[member->index] = value; return true; @@ -1696,15 +1704,15 @@ bool GDScriptInstance::set(const StringName &p_name, const Variant &p_value) { const GDScript::MemberInfo *member = &E->value; Variant value = p_value; if (member->data_type.has_type && !member->data_type.is_type(value)) { + if (!execute_access_restriction(p_name, script, sptr->member_access_restrictions[p_name])) { + return false; + } const Variant *args = &p_value; Callable::CallError err; Variant::construct(member->data_type.builtin_type, value, &args, 1, err); if (err.error != Callable::CallError::CALL_OK || !member->data_type.is_type(value)) { return false; } - if (!execute_access_restriction(p_name, script, sptr->member_access_restrictions[p_name])) { - return false; - } } if (likely(sptr->valid) && member->setter) { if (!execute_access_restriction(member->setter, script, sptr->member_access_restrictions[p_name])) { @@ -1714,9 +1722,11 @@ bool GDScriptInstance::set(const StringName &p_name, const Variant &p_value) { Callable::CallError err; callp(member->setter, &args, 1, err); return err.error == Callable::CallError::CALL_OK; + } else if (!execute_access_restriction(member->setter, script, script->member_access_restrictions[p_name])) { + return false; } else { sptr->static_variables.write[member->index] = value; - return true; + return execute_access_restriction(member->setter, script, script->member_access_restrictions[p_name]); } } } diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index 57fd50e275..64a5ce8a43 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -296,7 +296,7 @@ Error GDScriptAnalyzer::check_class_member_name_conflict(const GDScriptParser::C return OK; } -bool GDScriptAnalyzer::execute_access_protection(const GDScriptParser::ClassNode *p_derived_class, const GDScriptParser::Node *p_protected_member, const Vector &p_super_classes, const GDScriptParser::Node *p_node) { +bool GDScriptAnalyzer::execute_access_protection(const GDScriptParser::ClassNode *p_derived_class, const GDScriptParser::Node *p_protected_member, const Vector &p_super_classes, const GDScriptParser::Node *p_node, const bool p_is_call) { if (p_protected_member->access_restriction == GDScriptParser::Node::ACCESS_RESTRICTION_PUBLIC) { return true; } @@ -304,9 +304,8 @@ bool GDScriptAnalyzer::execute_access_protection(const GDScriptParser::ClassNode ERR_FAIL_COND_V_MSG(!p_derived_class, false, R"(Could not resolve the null derived class node...)"); ERR_FAIL_COND_V_MSG(!p_protected_member, false, R"(Could not resolve the null member node...)"); - const bool is_call = p_protected_member->type == GDScriptParser::Node::CALL; - const String member_type = (is_call || p_protected_member->type == GDScriptParser::Node::FUNCTION) ? "method" : (p_protected_member->type == GDScriptParser::Node::Type::SIGNAL ? "signal" : "property"); - const String action = is_call ? "call" : "access"; + const String member_type = p_protected_member->type == GDScriptParser::Node::FUNCTION ? "method" : (p_protected_member->type == GDScriptParser::Node::Type::SIGNAL ? "signal" : "property"); + const String action = p_is_call ? "call" : "access"; const bool is_from_non_derived = !p_super_classes.has(p_derived_class->identifier->name); @@ -315,10 +314,10 @@ bool GDScriptAnalyzer::execute_access_protection(const GDScriptParser::ClassNode switch (execute_access_protection_global(p_derived_class->identifier->name, p_protected_member, p_super_classes, p_node)) { case GDScriptAnalyzer::AccessRestrictionError::ACCESS_PRIVATE: - push_error(vformat(R"*(Could not %s %s "%s%s" in %s class, because it is private.)*", action, member_type, member_name, is_call ? "()" : "", is_from_non_derived ? "external" : "super"), p_node); + push_error(vformat(R"*(Could not %s %s "%s%s" in %s class, because it is private.)*", action, member_type, member_name, p_is_call ? "()" : "", is_from_non_derived ? "external" : "super"), p_node); return false; case GDScriptAnalyzer::AccessRestrictionError::ACCESS_PROTECTED: - push_error(vformat(R"*(Could not %s %s "%s%s" in external class, because it is protected by class "%s".)*", action, member_type, member_name, is_call ? "()" : "", p_protected_member->access_member_owner), p_node); + push_error(vformat(R"*(Could not %s %s "%s%s" in external class, because it is protected by class "%s".)*", action, member_type, member_name, p_is_call ? "()" : "", p_protected_member->access_member_owner), p_node); return false; default: break; // GDScriptAnalyzer::AccessRestrictionError::ACCESS_OTHER_ERR was thrown, so skip this here. @@ -3577,30 +3576,28 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a } // Access protection for calling a method - // It's very tricky to do so in this method - GDScriptParser::ClassNode *base_class = base_type.class_type; - if (base_class) { - GDScriptParser::FunctionNode *method = nullptr; - // For calling an external method, including ClassName.method(), or super.method(). - if (base_class->has_member(p_call->function_name)) { - method = static_cast(base_class->get_member(p_call->function_name).get_source_node()); - } else { - // For calling a method that is declared in the super class of the base class. - for (GDScriptParser::IdentifierNode *E : base_class->extends) { - if (!ScriptServer::is_global_class(E->name)) { - continue; // Skip because it is native or undefined. - } - GDScriptParser::ClassNode *super_class = make_global_class_meta_type(E->name, E).class_type; - if (super_class->has_member(p_call->function_name)) { - resolve_class_member(super_class, p_call->function_name, p_call); - method = static_cast(super_class->get_member(p_call->function_name).get_source_node()); - break; - } + // It's very hacky to do so in this method + // TODO: Performance boost + GDScriptParser::FunctionNode *method = nullptr; + // For calling an external method, including ClassName.method(), or super.method(). + if (parser->current_class->has_member(p_call->function_name)) { + method = static_cast(parser->current_class->get_member(p_call->function_name).get_source_node()); + } else { + // For calling a method that is declared in the super class of the base class. + const GDScriptParser::ClassNode *current_super_class = base_type.class_type; + while (current_super_class) { + if (!ScriptServer::is_global_class(current_super_class->identifier->name)) { + continue; + } else if (current_super_class->has_member(p_call->function_name)) { + method = static_cast(current_super_class->get_member(p_call->function_name).get_source_node()); + break; } + current_super_class = current_super_class->base_type.class_type; } - if (method) { - execute_access_protection(parser->current_class, method, parser->current_class->get_access_member_owner_extends_names(), p_call); - } + print_line(vformat(R"(Method: %s, owner: %s)", method->identifier->name, method->access_member_owner)); + } + if (method) { + execute_access_protection(parser->current_class, method, parser->current_class->get_access_member_owner_extends_names(), p_call, true); } int default_arg_count = 0; diff --git a/modules/gdscript/gdscript_analyzer.h b/modules/gdscript/gdscript_analyzer.h index ae12554da9..a2bd21e7e8 100644 --- a/modules/gdscript/gdscript_analyzer.h +++ b/modules/gdscript/gdscript_analyzer.h @@ -67,7 +67,7 @@ class GDScriptAnalyzer { Error check_native_member_name_conflict(const StringName &p_member_name, const GDScriptParser::Node *p_member_node, const StringName &p_native_type_string); Error check_class_member_name_conflict(const GDScriptParser::ClassNode *p_class_node, const StringName &p_member_name, const GDScriptParser::Node *p_member_node); - bool execute_access_protection(const GDScriptParser::ClassNode *p_derived_class, const GDScriptParser::Node *p_protected_member, const Vector &p_super_classes, const GDScriptParser::Node *p_node); + bool execute_access_protection(const GDScriptParser::ClassNode *p_derived_class, const GDScriptParser::Node *p_protected_member, const Vector &p_super_classes, const GDScriptParser::Node *p_node, const bool p_is_call = false); void get_class_node_current_scope_classes(GDScriptParser::ClassNode *p_node, List *p_list, GDScriptParser::Node *p_source); diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 49413f2f8f..ce4273e3ba 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -2822,12 +2822,14 @@ Error GDScriptCompiler::_prepare_compilation(GDScript *p_script, const GDScriptP if (variable->is_static) { minfo.index = p_script->static_variables_indices.size(); p_script->static_variables_indices[name] = minfo; + GDScript::MemberAccessRestriction::AccessRestriction access_restriction = GDScript::MemberAccessRestriction::AccessRestriction(variable->access_restriction); p_script->script_static_access_restrictions[name] = GDScript::MemberAccessRestriction(access_restriction, variable->access_member_owner); } else { minfo.index = p_script->member_indices.size(); p_script->member_indices[name] = minfo; p_script->members.insert(name); + GDScript::MemberAccessRestriction::AccessRestriction access_restriction = GDScript::MemberAccessRestriction::AccessRestriction(variable->access_restriction); p_script->member_access_restrictions[name] = GDScript::MemberAccessRestriction(access_restriction, variable->access_member_owner); } diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index a1e0a22177..2caa2f166c 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -989,6 +989,7 @@ void GDScriptParser::parse_class_body(bool p_is_multiline) { while (!class_end && !is_at_end()) { GDScriptTokenizer::Token token = current; + // Token functions switch (token.type) { case GDScriptTokenizer::Token::VAR: parse_class_member(&GDScriptParser::parse_variable, AnnotationInfo::VARIABLE, "variable", next_is_static, next_is_access_restricted); @@ -997,10 +998,10 @@ void GDScriptParser::parse_class_body(bool p_is_multiline) { } break; case GDScriptTokenizer::Token::CONST: - parse_class_member(&GDScriptParser::parse_constant, AnnotationInfo::CONSTANT, "constant"); + parse_class_member(&GDScriptParser::parse_constant, AnnotationInfo::CONSTANT, "constant", false, next_is_access_restricted); // Static-not-modifiable break; case GDScriptTokenizer::Token::SIGNAL: - parse_class_member(&GDScriptParser::parse_signal, AnnotationInfo::SIGNAL, "signal"); // Static-not-modifiable + parse_class_member(&GDScriptParser::parse_signal, AnnotationInfo::SIGNAL, "signal", false, next_is_access_restricted); // Static-not-modifiable break; case GDScriptTokenizer::Token::FUNC: parse_class_member(&GDScriptParser::parse_function, AnnotationInfo::FUNCTION, "function", next_is_static, next_is_access_restricted); @@ -1090,9 +1091,14 @@ void GDScriptParser::parse_class_body(bool p_is_multiline) { advance(); break; } + // Clear modifier status if (token.type != GDScriptTokenizer::Token::STATIC) { next_is_static = false; } + if (token.type != GDScriptTokenizer::Token::PRIVATE && token.type != GDScriptTokenizer::Token::PROTECTED) { + next_is_access_restricted = GDScriptParser::Node::ACCESS_RESTRICTION_PUBLIC; + } + // Others if (panic_mode) { synchronize(); }