2023-01-05 13:25:55 +01: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. */
/**************************************************************************/
2020-05-02 00:14:56 +02:00
# include "gdscript_warning.h"
2020-11-07 23:33:38 +01:00
# include "core/variant/variant.h"
2020-06-12 00:31:28 +02:00
2020-05-02 00:14:56 +02: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 17:20:41 +02:00
case UNASSIGNED_VARIABLE :
2020-05-02 00:14:56 +02:00
CHECK_SYMBOLS ( 1 ) ;
2024-04-09 19:15:51 +02:00
return vformat ( R " (The variable " % s " was used before being assigned a value.) " , symbols[0]) ;
2023-04-28 17:20:41 +02:00
case UNASSIGNED_VARIABLE_OP_ASSIGN :
2020-05-02 00:14:56 +02:00
CHECK_SYMBOLS ( 1 ) ;
2023-04-28 17:20:41 +02:00
return vformat ( R " (Using assignment with operation but the variable " % s " was not previously assigned a value.) " , symbols[0]) ;
case UNUSED_VARIABLE :
2020-05-02 00:14:56 +02:00
CHECK_SYMBOLS ( 1 ) ;
2023-04-28 17:20:41 +02: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-12 00:31:28 +02:00
CHECK_SYMBOLS ( 1 ) ;
2023-04-28 17:20:41 +02: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 15:23:11 +01:00
return vformat ( R " (The class variable " % s " is declared but never used in the class.) " , symbols[0]) ;
2023-04-28 17:20:41 +02: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 15:23:11 +01:00
return vformat ( R " (The signal " % s " is declared but never explicitly used in the class.) " , symbols[0]) ;
2023-04-28 17:20:41 +02:00
case SHADOWED_VARIABLE :
2020-06-12 00:31:28 +02:00
CHECK_SYMBOLS ( 4 ) ;
return vformat ( R " (The local %s " % s " is shadowing an already-declared %s at line %s.) " , symbols[0], symbols[1], symbols[2], symbols[3]) ;
2023-04-28 17:20:41 +02:00
case SHADOWED_VARIABLE_BASE_CLASS :
2020-06-12 00:31:28 +02:00
CHECK_SYMBOLS ( 4 ) ;
return vformat ( R " (The local %s " % s " is shadowing an already-declared %s at the base class " % s " .) " , symbols[0], symbols[1], symbols[2], symbols[3]) ;
2023-04-28 17:20:41 +02: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-02 00:14:56 +02:00
CHECK_SYMBOLS ( 1 ) ;
2023-04-28 17:20:41 +02:00
return vformat ( R " *(Unreachable code (statement after return) in function " %s() " . ) * " , symbols[0]) ;
case UNREACHABLE_PATTERN :
2020-06-12 00:31:28 +02:00
return " Unreachable pattern (pattern after wildcard or bind). " ;
2023-04-28 17:20:41 +02:00
case STANDALONE_EXPRESSION :
2020-05-02 00:14:56 +02:00
return " Standalone expression (the line has no effect). " ;
2023-04-28 17:20:41 +02:00
case STANDALONE_TERNARY :
2024-02-28 15:23:11 +01:00
return " Standalone ternary operator: the return value is being discarded. " ;
2023-04-28 17:20:41 +02:00
case INCOMPATIBLE_TERNARY :
2024-02-28 15:23:11 +01:00
return " Values of the ternary operator are not mutually compatible. " ;
2023-09-05 19:56:37 +02: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 19:57:24 +02: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 17:20:41 +02:00
case UNSAFE_PROPERTY_ACCESS :
2020-05-02 00:14:56 +02:00
CHECK_SYMBOLS ( 2 ) ;
2023-04-28 17:20:41 +02: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-02 00:14:56 +02:00
CHECK_SYMBOLS ( 2 ) ;
2023-04-28 17:20:41 +02: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-02 00:14:56 +02:00
CHECK_SYMBOLS ( 1 ) ;
2023-10-27 10:08:54 +02:00
return vformat ( R " (Casting " Variant " to " % s " is unsafe.) " , symbols[0]) ;
2023-04-28 17:20:41 +02:00
case UNSAFE_CALL_ARGUMENT :
2023-09-29 21:43:56 +02: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 17:20:41 +02:00
case UNSAFE_VOID_RETURN :
2023-01-27 21:54:07 +01:00
CHECK_SYMBOLS ( 2 ) ;
2023-04-28 17:20:41 +02: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-02 00:14:56 +02:00
CHECK_SYMBOLS ( 2 ) ;
2023-04-28 17:20:41 +02: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 ] ) ;
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 :
return R " ( " await " keyword not needed in this case, because the expression isn't a coroutine nor a signal.) " ;
case ASSERT_ALWAYS_TRUE :
2020-06-12 00:31:28 +02:00
return " Assert statement is redundant because the expression is always true. " ;
2023-04-28 17:20:41 +02:00
case ASSERT_ALWAYS_FALSE :
2020-06-12 00:31:28 +02:00
return " Assert statement will raise an error because the expression is always false. " ;
2023-04-28 17:20:41 +02:00
case INTEGER_DIVISION :
return " Integer division, decimal part will be discarded. " ;
case NARROWING_CONVERSION :
return " Narrowing conversion (float is converted to int and loses precision). " ;
case INT_AS_ENUM_WITHOUT_CAST :
2022-01-27 15:34:33 +01:00
return " Integer used when an enum value is expected. If this is intended cast the integer to the enum type. " ;
2023-04-28 17:20:41 +02:00
case INT_AS_ENUM_WITHOUT_MATCH :
2023-01-22 09:32:05 +01: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 16:16:36 +02: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 17:20:41 +02:00
case EMPTY_FILE :
return " Empty script file. " ;
case DEPRECATED_KEYWORD :
2022-10-13 21:42:11 +02:00
CHECK_SYMBOLS ( 2 ) ;
2023-04-28 17:20:41 +02:00
return vformat ( R " (The " % s " keyword is deprecated and will be removed in a future release, please replace its uses by " % s " .) " , symbols[0], symbols[1]) ;
case RENAMED_IN_GODOT_4_HINT :
break ; // Renamed identifier hint is taken care of by the GDScriptAnalyzer. No message needed here.
case CONFUSABLE_IDENTIFIER :
2023-01-19 02:56:00 +01: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 13:21:49 +02: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]) ;
2023-04-28 17:20:41 +02:00
case INFERENCE_ON_VARIANT :
2023-02-02 15:57:22 +01: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 17:20:41 +02:00
case NATIVE_METHOD_OVERRIDE :
2023-02-02 15:57:22 +01:00
CHECK_SYMBOLS ( 2 ) ;
2023-04-28 17:20:41 +02: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 15:57:22 +01:00
CHECK_SYMBOLS ( 1 ) ;
return vformat ( R " *(The default value is using " % 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 17:20:41 +02: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 15:23:11 +01: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-02 00:14:56 +02:00
case WARNING_MAX :
2024-02-28 15:23:11 +01:00
break ; // Can't happen, but silences warning.
2020-05-02 00:14:56 +02:00
}
2024-02-28 15:23:11 +01:00
ERR_FAIL_V_MSG ( String ( ) , vformat ( R " (Invalid GDScript warning " % s " .) " , get_name_from_code ( code ) ) ) ;
2020-05-02 00:14:56 +02:00
# undef CHECK_SYMBOLS
}
2022-03-23 03:44:30 +01:00
int GDScriptWarning : : get_default_value ( Code p_code ) {
2023-02-02 15:57:22 +01: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-23 03:44:30 +01:00
}
PropertyInfo GDScriptWarning : : get_property_info ( Code p_code ) {
// Making this a separate function in case a warning needs different PropertyInfo in the future.
2023-04-28 17:20:41 +02:00
if ( p_code = = Code : : RENAMED_IN_GODOT_4_HINT ) {
2022-03-23 18:54:41 +01:00
return PropertyInfo ( Variant : : BOOL , get_settings_path_from_code ( p_code ) ) ;
}
2022-03-23 03:44:30 +01:00
return PropertyInfo ( Variant : : INT , get_settings_path_from_code ( p_code ) , PROPERTY_HINT_ENUM , " Ignore,Warn,Error " ) ;
}
2020-05-02 00:14:56 +02: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 [ ] = {
" UNASSIGNED_VARIABLE " ,
" UNASSIGNED_VARIABLE_OP_ASSIGN " ,
" UNUSED_VARIABLE " ,
2020-06-12 00:31:28 +02:00
" UNUSED_LOCAL_CONSTANT " ,
" UNUSED_PRIVATE_CLASS_VARIABLE " ,
" UNUSED_PARAMETER " ,
2023-04-28 17:20:41 +02:00
" UNUSED_SIGNAL " ,
" SHADOWED_VARIABLE " ,
" SHADOWED_VARIABLE_BASE_CLASS " ,
" SHADOWED_GLOBAL_IDENTIFIER " ,
2020-05-02 00:14:56 +02:00
" UNREACHABLE_CODE " ,
2020-06-12 00:31:28 +02:00
" UNREACHABLE_PATTERN " ,
2020-05-02 00:14:56 +02:00
" STANDALONE_EXPRESSION " ,
2023-04-28 17:20:41 +02:00
" STANDALONE_TERNARY " ,
2020-05-02 00:14:56 +02:00
" INCOMPATIBLE_TERNARY " ,
2023-09-05 19:56:37 +02:00
" UNTYPED_DECLARATION " ,
2023-09-22 19:57:24 +02:00
" INFERRED_DECLARATION " ,
2020-05-02 00:14:56 +02:00
" UNSAFE_PROPERTY_ACCESS " ,
" UNSAFE_METHOD_ACCESS " ,
" UNSAFE_CAST " ,
" UNSAFE_CALL_ARGUMENT " ,
2023-01-27 21:54:07 +01:00
" UNSAFE_VOID_RETURN " ,
2023-04-28 17:20:41 +02:00
" RETURN_VALUE_DISCARDED " ,
" STATIC_CALLED_ON_INSTANCE " ,
" REDUNDANT_STATIC_UNLOAD " ,
" REDUNDANT_AWAIT " ,
2020-06-12 00:31:28 +02:00
" ASSERT_ALWAYS_TRUE " ,
" ASSERT_ALWAYS_FALSE " ,
2023-04-28 17:20:41 +02:00
" INTEGER_DIVISION " ,
" NARROWING_CONVERSION " ,
2023-01-22 09:32:05 +01:00
" INT_AS_ENUM_WITHOUT_CAST " ,
" INT_AS_ENUM_WITHOUT_MATCH " ,
2024-04-16 16:16:36 +02:00
" ENUM_VARIABLE_WITHOUT_DEFAULT " ,
2023-04-28 17:20:41 +02:00
" EMPTY_FILE " ,
" DEPRECATED_KEYWORD " ,
2023-02-02 15:57:22 +01:00
" RENAMED_IN_GODOT_4_HINT " ,
2023-04-28 17:20:41 +02:00
" CONFUSABLE_IDENTIFIER " ,
2023-07-25 13:21:49 +02:00
" CONFUSABLE_LOCAL_DECLARATION " ,
" CONFUSABLE_LOCAL_USAGE " ,
2023-02-02 15:57:22 +01:00
" INFERENCE_ON_VARIANT " ,
" NATIVE_METHOD_OVERRIDE " ,
" GET_NODE_DEFAULT_WITHOUT_ONREADY " ,
" ONREADY_WITH_EXPORT " ,
2024-02-28 15:23:11 +01:00
# ifndef DISABLE_DEPRECATED
" PROPERTY_USED_AS_FUNCTION " ,
" CONSTANT_USED_AS_FUNCTION " ,
" FUNCTION_USED_AS_PROPERTY " ,
# endif
2020-05-02 00:14:56 +02:00
} ;
2020-06-12 00:31:28 +02:00
static_assert ( ( sizeof ( names ) / sizeof ( * names ) ) = = WARNING_MAX , " Amount of warning types don't match the amount of warning names. " ) ;
2020-05-02 00:14:56 +02:00
return names [ ( int ) p_code ] ;
}
2022-03-23 03:44:30 +01: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-02 00:14:56 +02: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 13:32:43 +01:00
return WARNING_MAX ;
2020-05-02 00:14:56 +02:00
}
# endif // DEBUG_ENABLED