GDScript: Improve call analysis
* Add missing `UNSAFE_CALL_ARGUMENT` warning. * Fix `Object` constructor. * Display an error for non-existent static methods.
This commit is contained in:
parent
59139df16e
commit
e8696f9961
|
@ -248,7 +248,7 @@ Error GDScriptAnalyzer::check_native_member_name_conflict(const StringName &p_me
|
|||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
|
||||
if (GDScriptParser::get_builtin_type(p_member_name) != Variant::VARIANT_MAX) {
|
||||
if (GDScriptParser::get_builtin_type(p_member_name) < Variant::VARIANT_MAX) {
|
||||
push_error(vformat(R"(The member "%s" cannot have the same name as a builtin type.)", p_member_name), p_member_node);
|
||||
return ERR_PARSE_ERROR;
|
||||
}
|
||||
|
@ -669,11 +669,6 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
|
|||
return bad_type;
|
||||
}
|
||||
result.kind = GDScriptParser::DataType::VARIANT;
|
||||
} else if (first == SNAME("Object")) {
|
||||
// Object is treated like a native type, not a built-in.
|
||||
result.kind = GDScriptParser::DataType::NATIVE;
|
||||
result.builtin_type = Variant::OBJECT;
|
||||
result.native_type = SNAME("Object");
|
||||
} else if (GDScriptParser::get_builtin_type(first) < Variant::VARIANT_MAX) {
|
||||
// Built-in types.
|
||||
if (p_type->type_chain.size() > 1) {
|
||||
|
@ -1704,7 +1699,7 @@ void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode *
|
|||
}
|
||||
parent_signature += ") -> ";
|
||||
|
||||
const String return_type = parent_return_type.is_hard_type() ? parent_return_type.to_string() : "Variant";
|
||||
const String return_type = parent_return_type.to_string_strict();
|
||||
if (return_type == "null") {
|
||||
parent_signature += "void";
|
||||
} else {
|
||||
|
@ -2888,19 +2883,20 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
|
|||
if (!p_call->is_super && callee_type == GDScriptParser::Node::IDENTIFIER) {
|
||||
// Call to name directly.
|
||||
StringName function_name = p_call->function_name;
|
||||
Variant::Type builtin_type = GDScriptParser::get_builtin_type(function_name);
|
||||
|
||||
if (function_name == SNAME("Object")) {
|
||||
push_error(R"*(Invalid constructor "Object()", use "Object.new()" instead.)*", p_call);
|
||||
p_call->set_datatype(call_type);
|
||||
return;
|
||||
}
|
||||
|
||||
Variant::Type builtin_type = GDScriptParser::get_builtin_type(function_name);
|
||||
if (builtin_type < Variant::VARIANT_MAX) {
|
||||
// Is a builtin constructor.
|
||||
call_type.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
|
||||
call_type.kind = GDScriptParser::DataType::BUILTIN;
|
||||
call_type.builtin_type = builtin_type;
|
||||
|
||||
if (builtin_type == Variant::OBJECT) {
|
||||
call_type.kind = GDScriptParser::DataType::NATIVE;
|
||||
call_type.native_type = function_name; // "Object".
|
||||
}
|
||||
|
||||
bool safe_to_fold = true;
|
||||
switch (builtin_type) {
|
||||
// Those are stored by reference so not suited for compile-time construction.
|
||||
|
@ -2936,7 +2932,7 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
|
|||
|
||||
switch (err.error) {
|
||||
case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT:
|
||||
push_error(vformat(R"(Invalid argument for %s constructor: argument %d should be "%s" but is "%s".)", Variant::get_type_name(builtin_type), err.argument + 1,
|
||||
push_error(vformat(R"*(Invalid argument for "%s()" constructor: argument %d should be "%s" but is "%s".)*", Variant::get_type_name(builtin_type), err.argument + 1,
|
||||
Variant::get_type_name(Variant::Type(err.expected)), p_call->arguments[err.argument]->get_datatype().to_string()),
|
||||
p_call->arguments[err.argument]);
|
||||
break;
|
||||
|
@ -2952,10 +2948,10 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
|
|||
push_error(vformat(R"(No constructor of "%s" matches the signature "%s".)", Variant::get_type_name(builtin_type), signature), p_call->callee);
|
||||
} break;
|
||||
case Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS:
|
||||
push_error(vformat(R"(Too many arguments for %s constructor. Received %d but expected %d.)", Variant::get_type_name(builtin_type), p_call->arguments.size(), err.expected), p_call);
|
||||
push_error(vformat(R"*(Too many arguments for "%s()" constructor. Received %d but expected %d.)*", Variant::get_type_name(builtin_type), p_call->arguments.size(), err.expected), p_call);
|
||||
break;
|
||||
case Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS:
|
||||
push_error(vformat(R"(Too few arguments for %s constructor. Received %d but expected %d.)", Variant::get_type_name(builtin_type), p_call->arguments.size(), err.expected), p_call);
|
||||
push_error(vformat(R"*(Too few arguments for "%s()" constructor. Received %d but expected %d.)*", Variant::get_type_name(builtin_type), p_call->arguments.size(), err.expected), p_call);
|
||||
break;
|
||||
case Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL:
|
||||
case Callable::CallError::CALL_ERROR_METHOD_NOT_CONST:
|
||||
|
@ -2966,21 +2962,27 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
|
|||
break;
|
||||
}
|
||||
} else {
|
||||
// TODO: Check constructors without constants.
|
||||
|
||||
// If there's one argument, try to use copy constructor (those aren't explicitly defined).
|
||||
if (p_call->arguments.size() == 1) {
|
||||
GDScriptParser::DataType arg_type = p_call->arguments[0]->get_datatype();
|
||||
if (arg_type.is_variant()) {
|
||||
mark_node_unsafe(p_call->arguments[0]);
|
||||
} else {
|
||||
if (arg_type.is_hard_type() && !arg_type.is_variant()) {
|
||||
if (arg_type.kind == GDScriptParser::DataType::BUILTIN && arg_type.builtin_type == builtin_type) {
|
||||
// Okay.
|
||||
p_call->set_datatype(call_type);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
#ifdef DEBUG_ENABLED
|
||||
mark_node_unsafe(p_call);
|
||||
// We don't know what type was expected since constructors support overloads.
|
||||
// TODO: Improve this by checking for matching candidates?
|
||||
parser->push_warning(p_call->arguments[0], GDScriptWarning::UNSAFE_CALL_ARGUMENT, "1", function_name, "<unknown type>", "Variant");
|
||||
#endif
|
||||
p_call->set_datatype(call_type);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
List<MethodInfo> constructors;
|
||||
Variant::get_constructor_list(builtin_type, &constructors);
|
||||
bool match = false;
|
||||
|
@ -2997,14 +2999,14 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
|
|||
|
||||
for (int i = 0; i < p_call->arguments.size(); i++) {
|
||||
GDScriptParser::DataType par_type = type_from_property(info.arguments[i], true);
|
||||
|
||||
if (!is_type_compatible(par_type, p_call->arguments[i]->get_datatype(), true)) {
|
||||
GDScriptParser::DataType arg_type = p_call->arguments[i]->get_datatype();
|
||||
if (!is_type_compatible(par_type, arg_type, true)) {
|
||||
types_match = false;
|
||||
break;
|
||||
#ifdef DEBUG_ENABLED
|
||||
} else {
|
||||
if (par_type.builtin_type == Variant::INT && p_call->arguments[i]->get_datatype().builtin_type == Variant::FLOAT && builtin_type != Variant::INT) {
|
||||
parser->push_warning(p_call, GDScriptWarning::NARROWING_CONVERSION, p_call->function_name);
|
||||
if (par_type.builtin_type == Variant::INT && arg_type.builtin_type == Variant::FLOAT && builtin_type != Variant::INT) {
|
||||
parser->push_warning(p_call, GDScriptWarning::NARROWING_CONVERSION, function_name);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -3012,9 +3014,19 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
|
|||
|
||||
if (types_match) {
|
||||
for (int i = 0; i < p_call->arguments.size(); i++) {
|
||||
GDScriptParser::DataType par_type = type_from_property(info.arguments[i], true);
|
||||
if (p_call->arguments[i]->is_constant) {
|
||||
update_const_expression_builtin_type(p_call->arguments[i], type_from_property(info.arguments[i], true), "pass");
|
||||
update_const_expression_builtin_type(p_call->arguments[i], par_type, "pass");
|
||||
}
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (!(par_type.is_variant() && par_type.is_hard_type())) {
|
||||
GDScriptParser::DataType arg_type = p_call->arguments[i]->get_datatype();
|
||||
if (arg_type.is_variant() || !arg_type.is_hard_type() || !is_type_compatible(arg_type, par_type, true)) {
|
||||
mark_node_unsafe(p_call);
|
||||
parser->push_warning(p_call->arguments[i], GDScriptWarning::UNSAFE_CALL_ARGUMENT, itos(i + 1), function_name, par_type.to_string(), arg_type.to_string_strict());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
match = true;
|
||||
call_type = type_from_property(info.return_val);
|
||||
|
@ -3314,8 +3326,8 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
|
|||
#else
|
||||
push_error(vformat(R"*(Function "%s()" not found in base %s.)*", p_call->function_name, base_name), p_call->is_super ? p_call : p_call->callee);
|
||||
#endif // SUGGEST_GODOT4_RENAMES
|
||||
} else if (!found && (!p_call->is_super && base_type.is_hard_type() && base_type.kind == GDScriptParser::DataType::NATIVE && base_type.is_meta_type)) {
|
||||
push_error(vformat(R"*(Static function "%s()" not found in base "%s".)*", p_call->function_name, base_type.native_type), p_call);
|
||||
} else if (!found && (!p_call->is_super && base_type.is_hard_type() && base_type.is_meta_type)) {
|
||||
push_error(vformat(R"*(Static function "%s()" not found in base "%s".)*", p_call->function_name, base_type.to_string()), p_call);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3803,6 +3815,7 @@ void GDScriptAnalyzer::reduce_identifier(GDScriptParser::IdentifierNode *p_ident
|
|||
#endif
|
||||
|
||||
// Not a local, so check members.
|
||||
|
||||
if (!found_source) {
|
||||
reduce_identifier_from_base(p_identifier);
|
||||
if (p_identifier->source != GDScriptParser::IdentifierNode::UNDEFINED_SOURCE || p_identifier->get_datatype().is_set()) {
|
||||
|
@ -3855,10 +3868,10 @@ void GDScriptAnalyzer::reduce_identifier(GDScriptParser::IdentifierNode *p_ident
|
|||
StringName name = p_identifier->name;
|
||||
p_identifier->source = GDScriptParser::IdentifierNode::UNDEFINED_SOURCE;
|
||||
|
||||
// Check globals. We make an exception for Variant::OBJECT because it's the base class for
|
||||
// non-builtin types so we allow doing e.g. Object.new()
|
||||
// Not a local or a member, so check globals.
|
||||
|
||||
Variant::Type builtin_type = GDScriptParser::get_builtin_type(name);
|
||||
if (builtin_type != Variant::OBJECT && builtin_type < Variant::VARIANT_MAX) {
|
||||
if (builtin_type < Variant::VARIANT_MAX) {
|
||||
if (can_be_builtin) {
|
||||
p_identifier->set_datatype(make_builtin_meta_type(builtin_type));
|
||||
return;
|
||||
|
@ -4986,21 +4999,28 @@ void GDScriptAnalyzer::validate_call_arg(const List<GDScriptParser::DataType> &p
|
|||
GDScriptParser::DataType arg_type = p_call->arguments[i]->get_datatype();
|
||||
|
||||
if (arg_type.is_variant() || !arg_type.is_hard_type()) {
|
||||
#ifdef DEBUG_ENABLED
|
||||
// Argument can be anything, so this is unsafe (unless the parameter is a hard variant).
|
||||
if (!(par_type.is_hard_type() && par_type.is_variant())) {
|
||||
mark_node_unsafe(p_call->arguments[i]);
|
||||
parser->push_warning(p_call->arguments[i], GDScriptWarning::UNSAFE_CALL_ARGUMENT, itos(i + 1), p_call->function_name, par_type.to_string(), arg_type.to_string_strict());
|
||||
}
|
||||
#endif
|
||||
} else if (par_type.is_hard_type() && !is_type_compatible(par_type, arg_type, true)) {
|
||||
// Supertypes are acceptable for dynamic compliance, but it's unsafe.
|
||||
mark_node_unsafe(p_call);
|
||||
if (!is_type_compatible(arg_type, par_type)) {
|
||||
push_error(vformat(R"*(Invalid argument for "%s()" function: argument %d should be "%s" but is "%s".)*",
|
||||
p_call->function_name, i + 1, par_type.to_string(), arg_type.to_string()),
|
||||
p_call->arguments[i]);
|
||||
#ifdef DEBUG_ENABLED
|
||||
} else {
|
||||
// Supertypes are acceptable for dynamic compliance, but it's unsafe.
|
||||
mark_node_unsafe(p_call);
|
||||
parser->push_warning(p_call->arguments[i], GDScriptWarning::UNSAFE_CALL_ARGUMENT, itos(i + 1), p_call->function_name, par_type.to_string(), arg_type.to_string_strict());
|
||||
#endif
|
||||
}
|
||||
#ifdef DEBUG_ENABLED
|
||||
} else if (par_type.kind == GDScriptParser::DataType::BUILTIN && par_type.builtin_type == Variant::INT && arg_type.kind == GDScriptParser::DataType::BUILTIN && arg_type.builtin_type == Variant::FLOAT) {
|
||||
parser->push_warning(p_call, GDScriptWarning::NARROWING_CONVERSION, p_call->function_name);
|
||||
parser->push_warning(p_call->arguments[i], GDScriptWarning::NARROWING_CONVERSION, p_call->function_name);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -5028,7 +5048,7 @@ void GDScriptAnalyzer::is_shadowing(GDScriptParser::IdentifierNode *p_identifier
|
|||
} else if (ClassDB::class_exists(name)) {
|
||||
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) {
|
||||
} else if (GDScriptParser::get_builtin_type(name) < Variant::VARIANT_MAX) {
|
||||
parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, p_context, name, "built-in type");
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -601,11 +601,8 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
|
|||
arguments.push_back(arg);
|
||||
}
|
||||
|
||||
if (!call->is_super && call->callee->type == GDScriptParser::Node::IDENTIFIER && GDScriptParser::get_builtin_type(call->function_name) != Variant::VARIANT_MAX) {
|
||||
// Construct a built-in type.
|
||||
Variant::Type vtype = GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(call->callee)->name);
|
||||
|
||||
gen->write_construct(result, vtype, arguments);
|
||||
if (!call->is_super && call->callee->type == GDScriptParser::Node::IDENTIFIER && GDScriptParser::get_builtin_type(call->function_name) < Variant::VARIANT_MAX) {
|
||||
gen->write_construct(result, GDScriptParser::get_builtin_type(call->function_name), arguments);
|
||||
} else if (!call->is_super && call->callee->type == GDScriptParser::Node::IDENTIFIER && Variant::has_utility_function(call->function_name)) {
|
||||
// Variant utility function.
|
||||
gen->write_call_utility(result, call->function_name, arguments);
|
||||
|
|
|
@ -52,11 +52,18 @@
|
|||
#include "editor/editor_settings.h"
|
||||
#endif
|
||||
|
||||
// This function is used to determine that a type is "built-in" as opposed to native
|
||||
// and custom classes. So `Variant::NIL` and `Variant::OBJECT` are excluded:
|
||||
// `Variant::NIL` - `null` is literal, not a type.
|
||||
// `Variant::OBJECT` - `Object` should be treated as a class, not as a built-in type.
|
||||
static HashMap<StringName, Variant::Type> builtin_types;
|
||||
Variant::Type GDScriptParser::get_builtin_type(const StringName &p_type) {
|
||||
if (builtin_types.is_empty()) {
|
||||
for (int i = 1; i < Variant::VARIANT_MAX; i++) {
|
||||
builtin_types[Variant::get_type_name((Variant::Type)i)] = (Variant::Type)i;
|
||||
if (unlikely(builtin_types.is_empty())) {
|
||||
for (int i = 0; i < Variant::VARIANT_MAX; i++) {
|
||||
Variant::Type type = (Variant::Type)i;
|
||||
if (type != Variant::NIL && type != Variant::OBJECT) {
|
||||
builtin_types[Variant::get_type_name(type)] = type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -149,6 +149,7 @@ public:
|
|||
_FORCE_INLINE_ bool is_hard_type() const { return type_source > INFERRED; }
|
||||
|
||||
String to_string() const;
|
||||
_FORCE_INLINE_ String to_string_strict() const { return is_hard_type() ? to_string() : "Variant"; }
|
||||
PropertyInfo to_property_info(const String &p_name) const;
|
||||
|
||||
_FORCE_INLINE_ void set_container_element_type(const DataType &p_type) {
|
||||
|
@ -1530,7 +1531,7 @@ public:
|
|||
bool is_tool() const { return _is_tool; }
|
||||
ClassNode *find_class(const String &p_qualified_name) const;
|
||||
bool has_class(const GDScriptParser::ClassNode *p_class) const;
|
||||
static Variant::Type get_builtin_type(const StringName &p_type);
|
||||
static Variant::Type get_builtin_type(const StringName &p_type); // Excluding `Variant::NIL` and `Variant::OBJECT`.
|
||||
|
||||
CompletionContext get_completion_context() const { return completion_context; }
|
||||
CompletionCall get_completion_call() const { return completion_call; }
|
||||
|
|
|
@ -105,7 +105,7 @@ String GDScriptWarning::get_message() const {
|
|||
return vformat(R"(The value is cast to "%s" but has an unknown type.)", symbols[0]);
|
||||
case UNSAFE_CALL_ARGUMENT:
|
||||
CHECK_SYMBOLS(4);
|
||||
return vformat(R"*(The argument %s of the function "%s()" requires a the subtype "%s" but the supertype "%s" was provided.)*", symbols[0], symbols[1], symbols[2], symbols[3]);
|
||||
return vformat(R"*(The argument %s of the function "%s()" requires the subtype "%s" but the supertype "%s" was provided.)*", symbols[0], symbols[1], symbols[2], symbols[3]);
|
||||
case UNSAFE_VOID_RETURN:
|
||||
CHECK_SYMBOLS(2);
|
||||
return vformat(R"*(The method "%s()" returns "void" but it's trying to return a call to "%s()" that can't be ensured to also be "void".)*", symbols[0], symbols[1]);
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
# GH-73283
|
||||
|
||||
class MyClass:
|
||||
pass
|
||||
|
||||
func test():
|
||||
MyClass.not_existing_method()
|
|
@ -0,0 +1,2 @@
|
|||
GDTEST_ANALYZER_ERROR
|
||||
Static function "not_existing_method()" not found in base "MyClass".
|
|
@ -0,0 +1,4 @@
|
|||
# GH-73213
|
||||
|
||||
func test():
|
||||
print(Object())
|
|
@ -0,0 +1,2 @@
|
|||
GDTEST_ANALYZER_ERROR
|
||||
Invalid constructor "Object()", use "Object.new()" instead.
|
|
@ -23,6 +23,7 @@ func test() -> void:
|
|||
typed = variant()
|
||||
inferred = variant()
|
||||
|
||||
@warning_ignore("unsafe_call_argument") # TODO: Hard vs Weak vs Unknown.
|
||||
param_weak(typed)
|
||||
param_typed(typed)
|
||||
param_inferred(typed)
|
||||
|
|
|
@ -6,10 +6,12 @@ var prop = null
|
|||
|
||||
func check_arg(arg = null) -> void:
|
||||
if arg != null:
|
||||
@warning_ignore("unsafe_call_argument")
|
||||
print(check(arg))
|
||||
|
||||
func check_recur() -> void:
|
||||
if recur != null:
|
||||
@warning_ignore("unsafe_call_argument")
|
||||
print(check(recur))
|
||||
else:
|
||||
recur = 1
|
||||
|
@ -22,11 +24,13 @@ func test() -> void:
|
|||
|
||||
if prop == null:
|
||||
set('prop', 1)
|
||||
@warning_ignore("unsafe_call_argument")
|
||||
print(check(prop))
|
||||
set('prop', null)
|
||||
|
||||
var loop = null
|
||||
while loop != 2:
|
||||
if loop != null:
|
||||
@warning_ignore("unsafe_call_argument")
|
||||
print(check(loop))
|
||||
loop = 1 if loop == null else 2
|
||||
|
|
|
@ -14,4 +14,5 @@ func test():
|
|||
func do_add_node():
|
||||
var node = Node.new()
|
||||
node.name = "Node"
|
||||
@warning_ignore("unsafe_call_argument")
|
||||
add_child(node)
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
func variant_func(x: Variant) -> void:
|
||||
print(x)
|
||||
|
||||
func int_func(x: int) -> void:
|
||||
print(x)
|
||||
|
||||
func float_func(x: float) -> void:
|
||||
print(x)
|
||||
|
||||
# We don't want to execute it because of errors, just analyze.
|
||||
func no_exec_test():
|
||||
var untyped_int = 42
|
||||
var untyped_string = "abc"
|
||||
var variant_int: Variant = 42
|
||||
var variant_string: Variant = "abc"
|
||||
var typed_int: int = 42
|
||||
|
||||
variant_func(untyped_int) # No warning.
|
||||
variant_func(untyped_string) # No warning.
|
||||
variant_func(variant_int) # No warning.
|
||||
variant_func(variant_string) # No warning.
|
||||
variant_func(typed_int) # No warning.
|
||||
|
||||
int_func(untyped_int)
|
||||
int_func(untyped_string)
|
||||
int_func(variant_int)
|
||||
int_func(variant_string)
|
||||
int_func(typed_int) # No warning.
|
||||
|
||||
float_func(untyped_int)
|
||||
float_func(untyped_string)
|
||||
float_func(variant_int)
|
||||
float_func(variant_string)
|
||||
float_func(typed_int) # No warning.
|
||||
|
||||
func test():
|
||||
pass
|
|
@ -0,0 +1,33 @@
|
|||
GDTEST_OK
|
||||
>> WARNING
|
||||
>> Line: 24
|
||||
>> UNSAFE_CALL_ARGUMENT
|
||||
>> The argument 1 of the function "int_func()" requires the subtype "int" but the supertype "Variant" was provided.
|
||||
>> WARNING
|
||||
>> Line: 25
|
||||
>> UNSAFE_CALL_ARGUMENT
|
||||
>> The argument 1 of the function "int_func()" requires the subtype "int" but the supertype "Variant" was provided.
|
||||
>> WARNING
|
||||
>> Line: 26
|
||||
>> UNSAFE_CALL_ARGUMENT
|
||||
>> The argument 1 of the function "int_func()" requires the subtype "int" but the supertype "Variant" was provided.
|
||||
>> WARNING
|
||||
>> Line: 27
|
||||
>> UNSAFE_CALL_ARGUMENT
|
||||
>> The argument 1 of the function "int_func()" requires the subtype "int" but the supertype "Variant" was provided.
|
||||
>> WARNING
|
||||
>> Line: 30
|
||||
>> UNSAFE_CALL_ARGUMENT
|
||||
>> The argument 1 of the function "float_func()" requires the subtype "float" but the supertype "Variant" was provided.
|
||||
>> WARNING
|
||||
>> Line: 31
|
||||
>> UNSAFE_CALL_ARGUMENT
|
||||
>> The argument 1 of the function "float_func()" requires the subtype "float" but the supertype "Variant" was provided.
|
||||
>> WARNING
|
||||
>> Line: 32
|
||||
>> UNSAFE_CALL_ARGUMENT
|
||||
>> The argument 1 of the function "float_func()" requires the subtype "float" but the supertype "Variant" was provided.
|
||||
>> WARNING
|
||||
>> Line: 33
|
||||
>> UNSAFE_CALL_ARGUMENT
|
||||
>> The argument 1 of the function "float_func()" requires the subtype "float" but the supertype "Variant" was provided.
|
|
@ -3,27 +3,32 @@ extends Node
|
|||
func test():
|
||||
var child = Node.new()
|
||||
child.name = "Child"
|
||||
@warning_ignore("unsafe_call_argument")
|
||||
add_child(child)
|
||||
child.owner = self
|
||||
|
||||
var hey = Node.new()
|
||||
hey.name = "Hey"
|
||||
@warning_ignore("unsafe_call_argument")
|
||||
child.add_child(hey)
|
||||
hey.owner = self
|
||||
hey.unique_name_in_owner = true
|
||||
|
||||
var fake_hey = Node.new()
|
||||
fake_hey.name = "Hey"
|
||||
@warning_ignore("unsafe_call_argument")
|
||||
add_child(fake_hey)
|
||||
fake_hey.owner = self
|
||||
|
||||
var sub_child = Node.new()
|
||||
sub_child.name = "SubChild"
|
||||
@warning_ignore("unsafe_call_argument")
|
||||
hey.add_child(sub_child)
|
||||
sub_child.owner = self
|
||||
|
||||
var howdy = Node.new()
|
||||
howdy.name = "Howdy"
|
||||
@warning_ignore("unsafe_call_argument")
|
||||
sub_child.add_child(howdy)
|
||||
howdy.owner = self
|
||||
howdy.unique_name_in_owner = true
|
||||
|
|
|
@ -5,9 +5,11 @@ func test():
|
|||
# Create the required node structure.
|
||||
var hello = Node.new()
|
||||
hello.name = "Hello"
|
||||
@warning_ignore("unsafe_call_argument")
|
||||
add_child(hello)
|
||||
var world = Node.new()
|
||||
world.name = "World"
|
||||
@warning_ignore("unsafe_call_argument")
|
||||
hello.add_child(world)
|
||||
|
||||
# All the ways of writing node paths below with the `$` operator are valid.
|
||||
|
|
|
@ -26,6 +26,7 @@ func test():
|
|||
if true: (v as Callable).call()
|
||||
print()
|
||||
|
||||
@warning_ignore("unsafe_call_argument")
|
||||
other(v)
|
||||
print()
|
||||
|
||||
|
|
|
@ -2,4 +2,5 @@ func foo(x):
|
|||
return x + 1
|
||||
|
||||
func test():
|
||||
@warning_ignore("unsafe_call_argument")
|
||||
print(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(0)))))))))))))))))))))))))
|
||||
|
|
|
@ -36,6 +36,7 @@ class SayNothing extends Say:
|
|||
print("howdy, see above")
|
||||
|
||||
func say(name):
|
||||
@warning_ignore("unsafe_call_argument")
|
||||
super(name + " super'd")
|
||||
print(prefix, " say nothing... or not? ", name)
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ func test():
|
|||
|
||||
const d = 1.1
|
||||
_process(d)
|
||||
@warning_ignore("unsafe_call_argument")
|
||||
print(is_equal_approx(ㄥ, PI + (d * PI)))
|
||||
|
||||
func _process(Δ: float) -> void:
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
# GH-73213
|
||||
|
||||
func test():
|
||||
var object := Object.new() # Not `Object()`.
|
||||
print(object.get_class())
|
||||
object.free()
|
|
@ -0,0 +1,2 @@
|
|||
GDTEST_OK
|
||||
Object
|
|
@ -12,6 +12,7 @@ func test():
|
|||
print("end")
|
||||
|
||||
func test_construct(v, f):
|
||||
@warning_ignore("unsafe_call_argument")
|
||||
Vector2(v, v) # Built-in type construct.
|
||||
assert(not f) # Test unary operator reading from `nil`.
|
||||
|
||||
|
|
|
@ -44,6 +44,7 @@ func test():
|
|||
|
||||
@warning_ignore("unsafe_method_access")
|
||||
var path = get_script().get_path().get_base_dir()
|
||||
@warning_ignore("unsafe_call_argument")
|
||||
var other = load(path + "/static_variables_load.gd")
|
||||
|
||||
prints("load.perm:", other.perm)
|
||||
|
|
|
@ -24,7 +24,8 @@ func test():
|
|||
print(StringName("hello"))
|
||||
print(NodePath("hello/world"))
|
||||
var node := Node.new()
|
||||
print(RID(node))
|
||||
@warning_ignore("unsafe_call_argument")
|
||||
print(RID(node)) # TODO: Why is the constructor (or implicit cast) not documented?
|
||||
print(node.get_name)
|
||||
print(node.property_list_changed)
|
||||
node.free()
|
||||
|
|
Loading…
Reference in New Issue