Skip to content

Commit

Permalink
GDScript: type_from_property now correctly parses global classes
Browse files Browse the repository at this point in the history
  • Loading branch information
rune-scape committed Jan 23, 2025
1 parent b0655dc commit 8863bf9
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 41 deletions.
69 changes: 33 additions & 36 deletions modules/gdscript/gdscript_analyzer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -789,8 +789,7 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
result = parser->head->get_datatype();
} else {
String path = ScriptServer::get_global_class_path(first);
String ext = path.get_extension();
if (ext == GDScriptLanguage::get_singleton()->get_extension()) {
if (ScriptServer::get_global_class_language(first) == "GDScript") {
Ref<GDScriptParserRef> ref = parser->get_depended_parser_for(path);
if (ref.is_null() || ref->raise_status(GDScriptParserRef::INHERITANCE_SOLVED) != OK) {
push_error(vformat(R"(Could not parse global class "%s" from "%s".)", first, ScriptServer::get_global_class_path(first)), p_type);
Expand Down Expand Up @@ -3321,7 +3320,7 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
{
List<PropertyInfo>::ConstIterator arg_itr = info.arguments.begin();
for (int i = 0; i < p_call->arguments.size(); ++arg_itr, ++i) {
GDScriptParser::DataType par_type = type_from_property(*arg_itr, true);
GDScriptParser::DataType par_type = type_from_property(*arg_itr, true, p_call);
GDScriptParser::DataType arg_type = p_call->arguments[i]->get_datatype();
if (!is_type_compatible(par_type, arg_type, true)) {
types_match = false;
Expand All @@ -3339,7 +3338,7 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
if (types_match) {
List<PropertyInfo>::ConstIterator arg_itr = info.arguments.begin();
for (int i = 0; i < p_call->arguments.size(); ++arg_itr, ++i) {
GDScriptParser::DataType par_type = type_from_property(*arg_itr, true);
GDScriptParser::DataType par_type = type_from_property(*arg_itr, true, p_call);
if (p_call->arguments[i]->is_constant) {
update_const_expression_builtin_type(p_call->arguments[i], par_type, "pass");
}
Expand All @@ -3354,7 +3353,7 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
#endif
}
match = true;
call_type = type_from_property(info.return_val);
call_type = type_from_property(info.return_val, false, p_call);
break;
}
}
Expand Down Expand Up @@ -3442,7 +3441,7 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
} else {
validate_call_arg(function_info, p_call);
}
p_call->set_datatype(type_from_property(function_info.return_val));
p_call->set_datatype(type_from_property(function_info.return_val, false, p_call));
return;
} else if (Variant::has_utility_function(function_name)) {
MethodInfo function_info = info_from_utility_func(function_name);
Expand Down Expand Up @@ -3493,7 +3492,7 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
} else {
validate_call_arg(function_info, p_call);
}
p_call->set_datatype(type_from_property(function_info.return_val));
p_call->set_datatype(type_from_property(function_info.return_val, false, p_call));
return;
}
}
Expand Down Expand Up @@ -3821,12 +3820,11 @@ void GDScriptAnalyzer::reduce_get_node(GDScriptParser::GetNodeNode *p_get_node)
p_get_node->set_datatype(result);
}

GDScriptParser::DataType GDScriptAnalyzer::make_global_class_meta_type(const StringName &p_class_name, const GDScriptParser::Node *p_source) {
GDScriptParser::DataType GDScriptAnalyzer::make_global_class_meta_type(const StringName &p_class_name, const GDScriptParser::Node *p_source) const {
GDScriptParser::DataType type;

String path = ScriptServer::get_global_class_path(p_class_name);
String ext = path.get_extension();
if (ext == GDScriptLanguage::get_singleton()->get_extension()) {
if (ScriptServer::get_global_class_language(p_class_name) == "GDScript") {
Ref<GDScriptParserRef> ref = parser->get_depended_parser_for(path);
if (ref.is_null()) {
push_error(vformat(R"(Could not find script for class "%s".)", p_class_name), p_source);
Expand Down Expand Up @@ -4070,7 +4068,7 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
dummy.get_property_list(&properties);
for (const PropertyInfo &prop : properties) {
if (prop.name == name) {
p_identifier->set_datatype(type_from_property(prop));
p_identifier->set_datatype(type_from_property(prop, false, p_identifier));
return;
}
}
Expand Down Expand Up @@ -4213,7 +4211,7 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
continue;
}

const GDScriptParser::DataType property_type = GDScriptAnalyzer::type_from_property(property_info, false, false);
const GDScriptParser::DataType property_type = GDScriptAnalyzer::type_from_property(property_info, false, p_identifier);

p_identifier->set_datatype(property_type);
p_identifier->source = GDScriptParser::IdentifierNode::MEMBER_VARIABLE;
Expand Down Expand Up @@ -4270,7 +4268,9 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
MethodBind *getter = ClassDB::get_method(native, getter_name);
if (getter != nullptr) {
bool has_setter = ClassDB::get_property_setter(native, name) != StringName();
p_identifier->set_datatype(type_from_property(getter->get_return_info(), false, !has_setter));
GDScriptParser::DataType ptype = type_from_property(getter->get_return_info(), false, p_identifier);
ptype.is_read_only = !has_setter;
p_identifier->set_datatype(ptype);
p_identifier->source = GDScriptParser::IdentifierNode::INHERITED_VARIABLE;
}
return;
Expand Down Expand Up @@ -5513,9 +5513,8 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_metatype(const GDScriptPars
return result;
}

GDScriptParser::DataType GDScriptAnalyzer::type_from_property(const PropertyInfo &p_property, bool p_is_arg, bool p_is_readonly) const {
GDScriptParser::DataType GDScriptAnalyzer::type_from_property(const PropertyInfo &p_property, bool p_is_arg, const GDScriptParser::Node *p_source) const {
GDScriptParser::DataType result;
result.is_read_only = p_is_readonly;
result.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
if (p_property.type == Variant::NIL && (p_is_arg || (p_property.usage & PROPERTY_USAGE_NIL_IS_VARIANT))) {
// Variant
Expand All @@ -5524,18 +5523,16 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_property(const PropertyInfo
}
result.builtin_type = p_property.type;
if (p_property.type == Variant::OBJECT) {
if (ScriptServer::is_global_class(p_property.class_name)) {
result.kind = GDScriptParser::DataType::SCRIPT;
result.script_path = ScriptServer::get_global_class_path(p_property.class_name);
result.native_type = ScriptServer::get_global_class_native_base(p_property.class_name);

Ref<Script> scr = ResourceLoader::load(ScriptServer::get_global_class_path(p_property.class_name));
if (scr.is_valid()) {
result.script_type = scr;
}
} else {
StringName class_name = p_property.class_name == StringName() ? SNAME("Object") : p_property.class_name;
if (ScriptServer::is_global_class(class_name)) {
result = make_global_class_meta_type(class_name, p_source);
result.is_meta_type = false;
} else if (class_exists(class_name)) {
result.kind = GDScriptParser::DataType::NATIVE;
result.native_type = p_property.class_name == StringName() ? "Object" : p_property.class_name;
result.native_type = class_name;
} else {
push_error(vformat("Parser Bug: Could not make datatype from class '%s'", class_name), nullptr);
result.kind = GDScriptParser::DataType::VARIANT;
}
} else {
result.kind = GDScriptParser::DataType::BUILTIN;
Expand Down Expand Up @@ -5675,7 +5672,7 @@ 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_method_flags);
function_signature_from_info(E, r_return_type, r_par_types, r_default_arg_count, r_method_flags, p_source);
// Cannot use non-const methods on enums.
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);
Expand Down Expand Up @@ -5753,7 +5750,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_method_flags);
return function_signature_from_info(info, r_return_type, r_par_types, r_default_arg_count, r_method_flags, p_source);
}
base_script = base_script->get_base_script();
}
Expand All @@ -5764,7 +5761,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_method_flags);
return function_signature_from_info(info, r_return_type, r_par_types, r_default_arg_count, r_method_flags, p_source);
}
}

Expand All @@ -5778,7 +5775,7 @@ 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_method_flags);
bool valid = function_signature_from_info(info, r_return_type, r_par_types, r_default_arg_count, r_method_flags, p_source);
if (valid && Engine::get_singleton()->has_singleton(base_native)) {
r_method_flags.set_flag(METHOD_FLAG_STATIC);
}
Expand All @@ -5794,13 +5791,13 @@ 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, BitField<MethodFlags> &r_method_flags) {
r_return_type = type_from_property(p_info.return_val);
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, const GDScriptParser::Node *p_source) {
r_return_type = type_from_property(p_info.return_val, false, p_source);
r_default_arg_count = p_info.default_arguments.size();
r_method_flags = p_info.flags;

for (const PropertyInfo &E : p_info.arguments) {
r_par_types.push_back(type_from_property(E, true));
r_par_types.push_back(type_from_property(E, true, p_source));
}
return true;
}
Expand All @@ -5809,7 +5806,7 @@ void GDScriptAnalyzer::validate_call_arg(const MethodInfo &p_method, const GDScr
List<GDScriptParser::DataType> arg_types;

for (const PropertyInfo &E : p_method.arguments) {
arg_types.push_back(type_from_property(E, true));
arg_types.push_back(type_from_property(E, true, p_call));
}

validate_call_arg(arg_types, p_method.default_arguments.size(), (p_method.flags & METHOD_FLAG_VARARG) != 0, p_call);
Expand Down Expand Up @@ -6178,12 +6175,12 @@ bool GDScriptAnalyzer::check_type_compatibility(const GDScriptParser::DataType &
return false;
}

void GDScriptAnalyzer::push_error(const String &p_message, const GDScriptParser::Node *p_origin) {
void GDScriptAnalyzer::push_error(const String &p_message, const GDScriptParser::Node *p_origin) const {
mark_node_unsafe(p_origin);
parser->push_error(p_message, p_origin);
}

void GDScriptAnalyzer::mark_node_unsafe(const GDScriptParser::Node *p_node) {
void GDScriptAnalyzer::mark_node_unsafe(const GDScriptParser::Node *p_node) const {
#ifdef DEBUG_ENABLED
if (p_node == nullptr) {
return;
Expand Down
10 changes: 5 additions & 5 deletions modules/gdscript/gdscript_analyzer.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,10 +126,10 @@ class GDScriptAnalyzer {
Array make_array_from_element_datatype(const GDScriptParser::DataType &p_element_datatype, const GDScriptParser::Node *p_source_node = nullptr);
Dictionary make_dictionary_from_element_datatype(const GDScriptParser::DataType &p_key_element_datatype, const GDScriptParser::DataType &p_value_element_datatype, const GDScriptParser::Node *p_source_node = nullptr);
GDScriptParser::DataType type_from_variant(const Variant &p_value, const GDScriptParser::Node *p_source);
GDScriptParser::DataType type_from_property(const PropertyInfo &p_property, bool p_is_arg = false, bool p_is_readonly = false) const;
GDScriptParser::DataType make_global_class_meta_type(const StringName &p_class_name, const GDScriptParser::Node *p_source);
GDScriptParser::DataType type_from_property(const PropertyInfo &p_property, bool p_is_arg, const GDScriptParser::Node *p_source) const;
GDScriptParser::DataType make_global_class_meta_type(const StringName &p_class_name, const GDScriptParser::Node *p_source) const;
bool get_function_signature(GDScriptParser::Node *p_source, bool p_is_constructor, GDScriptParser::DataType 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 = nullptr);
bool 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);
bool 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, const GDScriptParser::Node *p_source);
void validate_call_arg(const List<GDScriptParser::DataType> &p_par_types, int p_default_args_count, bool p_is_vararg, const GDScriptParser::CallNode *p_call);
void validate_call_arg(const MethodInfo &p_method, const GDScriptParser::CallNode *p_call);
GDScriptParser::DataType 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);
Expand All @@ -138,8 +138,8 @@ class GDScriptAnalyzer {
void update_array_literal_element_type(GDScriptParser::ArrayNode *p_array, const GDScriptParser::DataType &p_element_type);
void update_dictionary_literal_element_type(GDScriptParser::DictionaryNode *p_dictionary, const GDScriptParser::DataType &p_key_element_type, const GDScriptParser::DataType &p_value_element_type);
bool is_type_compatible(const GDScriptParser::DataType &p_target, const GDScriptParser::DataType &p_source, bool p_allow_implicit_conversion = false, const GDScriptParser::Node *p_source_node = nullptr);
void push_error(const String &p_message, const GDScriptParser::Node *p_origin = nullptr);
void mark_node_unsafe(const GDScriptParser::Node *p_node);
void push_error(const String &p_message, const GDScriptParser::Node *p_origin = nullptr) const;
void mark_node_unsafe(const GDScriptParser::Node *p_node) const;
void downgrade_node_type_source(GDScriptParser::Node *p_node);
void mark_lambda_use_self();
void resolve_pending_lambda_bodies();
Expand Down

0 comments on commit 8863bf9

Please sign in to comment.