2020-05-01 19:14:56 -03:00
/**************************************************************************/
/* gdscript_warning.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
# include "gdscript_warning.h"
2020-11-07 19:33:38 -03:00
# include "core/variant/variant.h"
2020-06-11 19:31:28 -03:00
2020-05-01 19:14:56 -03:00
# ifdef DEBUG_ENABLED
String GDScriptWarning : : get_message ( ) const {
# define CHECK_SYMBOLS(m_amount) ERR_FAIL_COND_V(symbols.size() < m_amount, String());
switch ( code ) {
2023-04-28 18:20:41 +03:00
case UNASSIGNED_VARIABLE :
2020-05-01 19:14:56 -03:00
CHECK_SYMBOLS ( 1 ) ;
2025-03-28 09:47:46 -07:00
return vformat ( R " (The variable " % s " is used before being assigned a value.) " , symbols[0]) ;
2023-04-28 18:20:41 +03:00
case UNASSIGNED_VARIABLE_OP_ASSIGN :
2025-03-28 09:47:46 -07:00
CHECK_SYMBOLS ( 2 ) ;
return vformat ( R " (The variable " % s " is modified with the compound-assignment operator " % s = " but was not previously initialized.) " , symbols[0], symbols[1]) ;
2023-04-28 18:20:41 +03:00
case UNUSED_VARIABLE :
2020-05-01 19:14:56 -03:00
CHECK_SYMBOLS ( 1 ) ;
2023-04-28 18:20:41 +03:00
return vformat ( R " (The local variable " % s " is declared but never used in the block. If this is intended, prefix it with an underscore: " _ % s " .) " , symbols[0], symbols[0]) ;
case UNUSED_LOCAL_CONSTANT :
2020-06-11 19:31:28 -03:00
CHECK_SYMBOLS ( 1 ) ;
2023-04-28 18:20:41 +03:00
return vformat ( R " (The local constant " % s " is declared but never used in the block. If this is intended, prefix it with an underscore: " _ % s " .) " , symbols[0], symbols[0]) ;
case UNUSED_PRIVATE_CLASS_VARIABLE :
CHECK_SYMBOLS ( 1 ) ;
2024-02-28 17:23:11 +03:00
return vformat ( R " (The class variable " % s " is declared but never used in the class.) " , symbols[0]) ;
2023-04-28 18:20:41 +03:00
case UNUSED_PARAMETER :
CHECK_SYMBOLS ( 2 ) ;
return vformat ( R " *(The parameter " % s " is never used in the function " % s ( ) " . If this is intended, prefix it with an underscore: " _ % s " .)* " , symbols [ 1 ] , symbols [ 0 ] , symbols [ 1 ] ) ;
case UNUSED_SIGNAL :
CHECK_SYMBOLS ( 1 ) ;
2024-02-28 17:23:11 +03:00
return vformat ( R " (The signal " % s " is declared but never explicitly used in the class.) " , symbols[0]) ;
2023-04-28 18:20:41 +03:00
case SHADOWED_VARIABLE :
2020-06-11 19:31:28 -03:00
CHECK_SYMBOLS ( 4 ) ;
2024-11-06 00:37:18 +00:00
return vformat ( R " (The local %s " % s " is shadowing an already-declared %s at line %s in the current class.) " , symbols[0], symbols[1], symbols[2], symbols[3]) ;
2023-04-28 18:20:41 +03:00
case SHADOWED_VARIABLE_BASE_CLASS :
2020-06-11 19:31:28 -03:00
CHECK_SYMBOLS ( 4 ) ;
2024-11-06 00:37:18 +00:00
if ( symbols . size ( ) > 4 ) {
return vformat ( R " (The local %s " % s " is shadowing an already-declared %s at line %s in the base class " % s " .) " , symbols[0], symbols[1], symbols[2], symbols[3], symbols[4]) ;
}
return vformat ( R " (The local %s " % s " is shadowing an already-declared %s in the base class " % s " .) " , symbols[0], symbols[1], symbols[2], symbols[3]) ;
2023-04-28 18:20:41 +03:00
case SHADOWED_GLOBAL_IDENTIFIER :
CHECK_SYMBOLS ( 3 ) ;
return vformat ( R " (The %s " % s " has the same name as a %s.) " , symbols[0], symbols[1], symbols[2]) ;
case UNREACHABLE_CODE :
2020-05-01 19:14:56 -03:00
CHECK_SYMBOLS ( 1 ) ;
2023-04-28 18:20:41 +03:00
return vformat ( R " *(Unreachable code (statement after return) in function " %s() " . ) * " , symbols[0]) ;
case UNREACHABLE_PATTERN :
2020-06-11 19:31:28 -03:00
return " Unreachable pattern (pattern after wildcard or bind). " ;
2023-04-28 18:20:41 +03:00
case STANDALONE_EXPRESSION :
2024-05-16 22:11:56 +03:00
return " Standalone expression (the line may have no effect). " ;
2023-04-28 18:20:41 +03:00
case STANDALONE_TERNARY :
2025-03-28 09:47:46 -07:00
return " Standalone ternary operator (the return value is being discarded). " ;
2023-04-28 18:20:41 +03:00
case INCOMPATIBLE_TERNARY :
2024-02-28 17:23:11 +03:00
return " Values of the ternary operator are not mutually compatible. " ;
2023-09-05 12:56:37 -05:00
case UNTYPED_DECLARATION :
CHECK_SYMBOLS ( 2 ) ;
if ( symbols [ 0 ] = = " Function " ) {
return vformat ( R " *(%s " % s ( ) " has no static return type.)* " , symbols [ 0 ] , symbols [ 1 ] ) ;
}
return vformat ( R " (%s " % s " has no static type.) " , symbols[0], symbols[1]) ;
2023-09-22 20:57:24 +03:00
case INFERRED_DECLARATION :
CHECK_SYMBOLS ( 2 ) ;
return vformat ( R " (%s " % s " has an implicitly inferred static type.) " , symbols[0], symbols[1]) ;
2023-04-28 18:20:41 +03:00
case UNSAFE_PROPERTY_ACCESS :
2020-05-01 19:14:56 -03:00
CHECK_SYMBOLS ( 2 ) ;
2023-04-28 18:20:41 +03:00
return vformat ( R " (The property " % s " is not present on the inferred type " % s " (but may be present on a subtype) . ) " , symbols[0], symbols[1]) ;
case UNSAFE_METHOD_ACCESS :
2020-05-01 19:14:56 -03:00
CHECK_SYMBOLS ( 2 ) ;
2023-04-28 18:20:41 +03:00
return vformat ( R " *(The method " % s ( ) " is not present on the inferred type " % s " (but may be present on a subtype).)* " , symbols [ 0 ] , symbols [ 1 ] ) ;
case UNSAFE_CAST :
2020-05-01 19:14:56 -03:00
CHECK_SYMBOLS ( 1 ) ;
2023-10-27 11:08:54 +03:00
return vformat ( R " (Casting " Variant " to " % s " is unsafe.) " , symbols[0]) ;
2023-04-28 18:20:41 +03:00
case UNSAFE_CALL_ARGUMENT :
2023-09-29 22:43:56 +03:00
CHECK_SYMBOLS ( 5 ) ;
return vformat ( R " *(The argument %s of the %s " % s ( ) " requires the subtype " % s " but the supertype " % s " was provided.)* " , symbols [ 0 ] , symbols [ 1 ] , symbols [ 2 ] , symbols [ 3 ] , symbols [ 4 ] ) ;
2023-04-28 18:20:41 +03:00
case UNSAFE_VOID_RETURN :
2023-01-27 17:54:07 -03:00
CHECK_SYMBOLS ( 2 ) ;
2023-04-28 18:20:41 +03:00
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 ] ) ;
case RETURN_VALUE_DISCARDED :
CHECK_SYMBOLS ( 1 ) ;
return vformat ( R " *(The function " % s ( ) " returns a value that will be discarded if not used.)* " , symbols [ 0 ] ) ;
case STATIC_CALLED_ON_INSTANCE :
2020-05-01 19:14:56 -03:00
CHECK_SYMBOLS ( 2 ) ;
2023-04-28 18:20:41 +03:00
return vformat ( R " *(The function " % s ( ) " is a static function but was called from an instance. Instead, it should be directly called from the type: " % s . % s ( ) " .)* " , symbols [ 0 ] , symbols [ 1 ] , symbols [ 0 ] ) ;
2024-07-04 10:23:44 +03:00
case MISSING_TOOL :
return R " (The base class script has the " @ tool " annotation, but this script does not have it.) " ;
2023-04-28 18:20:41 +03:00
case REDUNDANT_STATIC_UNLOAD :
return R " (The " @ static_unload " annotation is redundant because the file does not have a class with static variables.) " ;
case REDUNDANT_AWAIT :
2025-03-28 09:47:46 -07:00
return R " ( " await " keyword is unnecessary because the expression isn't a coroutine nor a signal.) " ;
2025-06-24 14:43:50 +02:00
case MISSING_AWAIT :
return R " ( " await " keyword might be desired because the expression is a coroutine.) " ;
2023-04-28 18:20:41 +03:00
case ASSERT_ALWAYS_TRUE :
2020-06-11 19:31:28 -03:00
return " Assert statement is redundant because the expression is always true. " ;
2023-04-28 18:20:41 +03:00
case ASSERT_ALWAYS_FALSE :
2020-06-11 19:31:28 -03:00
return " Assert statement will raise an error because the expression is always false. " ;
2023-04-28 18:20:41 +03:00
case INTEGER_DIVISION :
2025-03-28 09:47:46 -07:00
return " Integer division. Decimal part will be discarded. " ;
2023-04-28 18:20:41 +03:00
case NARROWING_CONVERSION :
return " Narrowing conversion (float is converted to int and loses precision). " ;
case INT_AS_ENUM_WITHOUT_CAST :
2025-03-28 09:47:46 -07:00
return " Integer used when an enum value is expected. If this is intended, cast the integer to the enum type using the \" as \" keyword. " ;
2023-04-28 18:20:41 +03:00
case INT_AS_ENUM_WITHOUT_MATCH :
2023-01-22 10:32:05 +02:00
CHECK_SYMBOLS ( 3 ) ;
return vformat ( R " (Cannot %s %s as Enum " % s " : no enum member has matching value.) " , symbols[0], symbols[1], symbols[2]) ;
2024-04-16 11:16:36 -03:00
case ENUM_VARIABLE_WITHOUT_DEFAULT :
CHECK_SYMBOLS ( 1 ) ;
return vformat ( R " (The variable " % s " has an enum type and does not set an explicit default value. The default will be set to " 0 " .) " , symbols[0]) ;
2023-04-28 18:20:41 +03:00
case EMPTY_FILE :
return " Empty script file. " ;
case DEPRECATED_KEYWORD :
2022-10-13 12:42:11 -07:00
CHECK_SYMBOLS ( 2 ) ;
2025-03-28 09:47:46 -07:00
return vformat ( R " (The " % s " keyword is deprecated and will be removed in a future release. Please replace it with " % s " .) " , symbols[0], symbols[1]) ;
2023-04-28 18:20:41 +03:00
case CONFUSABLE_IDENTIFIER :
2023-01-18 22:56:00 -03:00
CHECK_SYMBOLS ( 1 ) ;
return vformat ( R " (The identifier " % s " has misleading characters and might be confused with something else.) " , symbols[0]) ;
2023-07-25 14:21:49 +03:00
case CONFUSABLE_LOCAL_DECLARATION :
CHECK_SYMBOLS ( 2 ) ;
return vformat ( R " (The %s " % s " is declared below in the parent block.) " , symbols[0], symbols[1]) ;
case CONFUSABLE_LOCAL_USAGE :
CHECK_SYMBOLS ( 1 ) ;
return vformat ( R " (The identifier " % s " will be shadowed below in the block.) " , symbols[0]) ;
2024-06-28 09:35:04 +03:00
case CONFUSABLE_CAPTURE_REASSIGNMENT :
CHECK_SYMBOLS ( 1 ) ;
return vformat ( R " (Reassigning lambda capture does not modify the outer local variable " % s " .) " , symbols[0]) ;
2023-04-28 18:20:41 +03:00
case INFERENCE_ON_VARIANT :
2023-02-02 11:57:22 -03:00
CHECK_SYMBOLS ( 1 ) ;
return vformat ( " The %s type is being inferred from a Variant value, so it will be typed as Variant. " , symbols [ 0 ] ) ;
2023-04-28 18:20:41 +03:00
case NATIVE_METHOD_OVERRIDE :
2023-02-02 11:57:22 -03:00
CHECK_SYMBOLS ( 2 ) ;
2023-04-28 18:20:41 +03:00
return vformat ( R " *(The method " % s ( ) " overrides a method from native class " % s " . This won't be called by the engine and may not work as expected.)* " , symbols [ 0 ] , symbols [ 1 ] ) ;
case GET_NODE_DEFAULT_WITHOUT_ONREADY :
2023-02-02 11:57:22 -03:00
CHECK_SYMBOLS ( 1 ) ;
2025-03-28 09:47:46 -07:00
return vformat ( R " *(The default value uses " % s " which won't return nodes in the scene tree before " _ready ( ) " is called. Use the " @ onready " annotation to solve this.)* " , symbols [ 0 ] ) ;
2023-04-28 18:20:41 +03:00
case ONREADY_WITH_EXPORT :
2023-04-06 08:04:22 +02:00
return R " ( " @ onready " will set the default value after " @ export " takes effect and will override it.) " ;
2024-02-28 17:23:11 +03:00
# ifndef DISABLE_DEPRECATED
// Never produced. These warnings migrated from 3.x by mistake.
case PROPERTY_USED_AS_FUNCTION : // There is already an error.
case CONSTANT_USED_AS_FUNCTION : // There is already an error.
case FUNCTION_USED_AS_PROPERTY : // This is valid, returns `Callable`.
break ;
# endif
2020-05-01 19:14:56 -03:00
case WARNING_MAX :
2024-02-28 17:23:11 +03:00
break ; // Can't happen, but silences warning.
2020-05-01 19:14:56 -03:00
}
2024-02-28 17:23:11 +03:00
ERR_FAIL_V_MSG ( String ( ) , vformat ( R " (Invalid GDScript warning " % s " .) " , get_name_from_code ( code ) ) ) ;
2020-05-01 19:14:56 -03:00
# undef CHECK_SYMBOLS
}
2022-03-22 21:44:30 -05:00
int GDScriptWarning : : get_default_value ( Code p_code ) {
2023-02-02 11:57:22 -03:00
ERR_FAIL_INDEX_V_MSG ( p_code , WARNING_MAX , WarnLevel : : IGNORE , " Getting default value of invalid warning code. " ) ;
return default_warning_levels [ p_code ] ;
2022-03-22 21:44:30 -05:00
}
PropertyInfo GDScriptWarning : : get_property_info ( Code p_code ) {
return PropertyInfo ( Variant : : INT , get_settings_path_from_code ( p_code ) , PROPERTY_HINT_ENUM , " Ignore,Warn,Error " ) ;
}
2020-05-01 19:14:56 -03:00
String GDScriptWarning : : get_name ( ) const {
return get_name_from_code ( code ) ;
}
String GDScriptWarning : : get_name_from_code ( Code p_code ) {
ERR_FAIL_COND_V ( p_code < 0 | | p_code > = WARNING_MAX , String ( ) ) ;
static const char * names [ ] = {
2025-06-24 18:03:52 +02:00
PNAME ( " UNASSIGNED_VARIABLE " ) ,
PNAME ( " UNASSIGNED_VARIABLE_OP_ASSIGN " ) ,
PNAME ( " UNUSED_VARIABLE " ) ,
PNAME ( " UNUSED_LOCAL_CONSTANT " ) ,
PNAME ( " UNUSED_PRIVATE_CLASS_VARIABLE " ) ,
PNAME ( " UNUSED_PARAMETER " ) ,
PNAME ( " UNUSED_SIGNAL " ) ,
PNAME ( " SHADOWED_VARIABLE " ) ,
PNAME ( " SHADOWED_VARIABLE_BASE_CLASS " ) ,
PNAME ( " SHADOWED_GLOBAL_IDENTIFIER " ) ,
PNAME ( " UNREACHABLE_CODE " ) ,
PNAME ( " UNREACHABLE_PATTERN " ) ,
PNAME ( " STANDALONE_EXPRESSION " ) ,
PNAME ( " STANDALONE_TERNARY " ) ,
PNAME ( " INCOMPATIBLE_TERNARY " ) ,
PNAME ( " UNTYPED_DECLARATION " ) ,
PNAME ( " INFERRED_DECLARATION " ) ,
PNAME ( " UNSAFE_PROPERTY_ACCESS " ) ,
PNAME ( " UNSAFE_METHOD_ACCESS " ) ,
PNAME ( " UNSAFE_CAST " ) ,
PNAME ( " UNSAFE_CALL_ARGUMENT " ) ,
PNAME ( " UNSAFE_VOID_RETURN " ) ,
PNAME ( " RETURN_VALUE_DISCARDED " ) ,
PNAME ( " STATIC_CALLED_ON_INSTANCE " ) ,
PNAME ( " MISSING_TOOL " ) ,
PNAME ( " REDUNDANT_STATIC_UNLOAD " ) ,
PNAME ( " REDUNDANT_AWAIT " ) ,
2025-06-24 14:43:50 +02:00
PNAME ( " MISSING_AWAIT " ) ,
2025-06-24 18:03:52 +02:00
PNAME ( " ASSERT_ALWAYS_TRUE " ) ,
PNAME ( " ASSERT_ALWAYS_FALSE " ) ,
PNAME ( " INTEGER_DIVISION " ) ,
PNAME ( " NARROWING_CONVERSION " ) ,
PNAME ( " INT_AS_ENUM_WITHOUT_CAST " ) ,
PNAME ( " INT_AS_ENUM_WITHOUT_MATCH " ) ,
PNAME ( " ENUM_VARIABLE_WITHOUT_DEFAULT " ) ,
PNAME ( " EMPTY_FILE " ) ,
PNAME ( " DEPRECATED_KEYWORD " ) ,
PNAME ( " CONFUSABLE_IDENTIFIER " ) ,
PNAME ( " CONFUSABLE_LOCAL_DECLARATION " ) ,
PNAME ( " CONFUSABLE_LOCAL_USAGE " ) ,
PNAME ( " CONFUSABLE_CAPTURE_REASSIGNMENT " ) ,
PNAME ( " INFERENCE_ON_VARIANT " ) ,
PNAME ( " NATIVE_METHOD_OVERRIDE " ) ,
PNAME ( " GET_NODE_DEFAULT_WITHOUT_ONREADY " ) ,
PNAME ( " ONREADY_WITH_EXPORT " ) ,
2024-02-28 17:23:11 +03:00
# ifndef DISABLE_DEPRECATED
" PROPERTY_USED_AS_FUNCTION " ,
" CONSTANT_USED_AS_FUNCTION " ,
" FUNCTION_USED_AS_PROPERTY " ,
# endif
2020-05-01 19:14:56 -03:00
} ;
2025-02-04 17:35:39 +01:00
static_assert ( std : : size ( names ) = = WARNING_MAX , " Amount of warning types don't match the amount of warning names. " ) ;
2020-06-11 19:31:28 -03:00
2020-05-01 19:14:56 -03:00
return names [ ( int ) p_code ] ;
}
2022-03-22 21:44:30 -05:00
String GDScriptWarning : : get_settings_path_from_code ( Code p_code ) {
return " debug/gdscript/warnings/ " + get_name_from_code ( p_code ) . to_lower ( ) ;
}
2020-05-01 19:14:56 -03:00
GDScriptWarning : : Code GDScriptWarning : : get_code_from_name ( const String & p_name ) {
for ( int i = 0 ; i < WARNING_MAX ; i + + ) {
if ( get_name_from_code ( ( Code ) i ) = = p_name ) {
return ( Code ) i ;
}
}
2022-01-04 09:32:43 -03:00
return WARNING_MAX ;
2020-05-01 19:14:56 -03:00
}
# endif // DEBUG_ENABLED