@ -39,40 +39,6 @@
# include "gdscript.h"
# include "gdscript_utility_functions.h"
// TODO: Move this to a central location (maybe core?).
static HashMap < StringName , StringName > underscore_map ;
static const char * underscore_classes [ ] = {
" ClassDB " ,
" Directory " ,
" Engine " ,
" File " ,
" Geometry " ,
" GodotSharp " ,
" JSON " ,
" Marshalls " ,
" Mutex " ,
" OS " ,
" ResourceLoader " ,
" ResourceSaver " ,
" Semaphore " ,
" Thread " ,
" VisualScriptEditor " ,
nullptr ,
} ;
static StringName get_real_class_name ( const StringName & p_source ) {
if ( underscore_map . is_empty ( ) ) {
const char * * class_name = underscore_classes ;
while ( * class_name ! = nullptr ) {
underscore_map [ * class_name ] = String ( " _ " ) + * class_name ;
class_name + + ;
}
}
if ( underscore_map . has ( p_source ) ) {
return underscore_map [ p_source ] ;
}
return p_source ;
}
static MethodInfo info_from_utility_func ( const StringName & p_function ) {
ERR_FAIL_COND_V ( ! Variant : : has_utility_function ( p_function ) , MethodInfo ( ) ) ;
@ -106,10 +72,6 @@ static MethodInfo info_from_utility_func(const StringName &p_function) {
return info ;
}
void GDScriptAnalyzer : : cleanup ( ) {
underscore_map . clear ( ) ;
}
static GDScriptParser : : DataType make_callable_type ( const MethodInfo & p_info ) {
GDScriptParser : : DataType type ;
type . type_source = GDScriptParser : : DataType : : ANNOTATED_EXPLICIT ;
@ -150,7 +112,7 @@ static GDScriptParser::DataType make_native_enum_type(const StringName &p_native
type . is_meta_type = true ;
List < StringName > enum_values ;
StringName real_native_name = get_real_class_name( p_native_class ) ;
StringName real_native_name = GDScriptParser: : get_real_class_name( p_native_class ) ;
ClassDB : : get_enum_constants ( real_native_name , p_enum_name , & enum_values ) ;
for ( const List < StringName > : : Element * E = enum_values . front ( ) ; E ! = nullptr ; E = E - > next ( ) ) {
@ -267,7 +229,7 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class,
push_error ( vformat ( R " (Could not resolve super class inheritance from " % s " .) " , name ) , p_class ) ;
return err ;
}
} else if ( class_exists ( name ) & & ClassDB : : can_instance ( get_real_class_name( name ) ) ) {
} else if ( class_exists ( name ) & & ClassDB : : can_instance ( GDScriptParser: : get_real_class_name( name ) ) ) {
base . kind = GDScriptParser : : DataType : : NATIVE ;
base . native_type = name ;
} else {
@ -444,7 +406,7 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
return GDScriptParser : : DataType ( ) ;
}
result = ref - > get_parser ( ) - > head - > get_datatype ( ) ;
} else if ( ClassDB : : has_enum ( get_real_class_name( parser - > current_class - > base_type . native_type ) , first ) ) {
} else if ( ClassDB : : has_enum ( GDScriptParser: : get_real_class_name( parser - > current_class - > base_type . native_type ) , first ) ) {
// Native enum in current class.
result = make_native_enum_type ( parser - > current_class - > base_type . native_type , first ) ;
} else {
@ -507,7 +469,7 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
}
} else if ( result . kind = = GDScriptParser : : DataType : : NATIVE ) {
// Only enums allowed for native.
if ( ClassDB : : has_enum ( get_real_class_name( result . native_type ) , p_type - > type_chain [ 1 ] - > name ) ) {
if ( ClassDB : : has_enum ( GDScriptParser: : get_real_class_name( result . native_type ) , p_type - > type_chain [ 1 ] - > name ) ) {
if ( p_type - > type_chain . size ( ) > 2 ) {
push_error ( R " (Enums cannot contain nested types.) " , p_type - > type_chain [ 2 ] ) ;
} else {
@ -607,28 +569,10 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
datatype . is_constant = false ;
member . variable - > set_datatype ( datatype ) ;
if ( ! datatype . has_no_type ( ) ) {
// TODO: Move this out into a routine specific to validate annotations.
if ( member . variable - > export_info . hint = = PROPERTY_HINT_TYPE_STRING ) {
// @export annotation.
switch ( datatype . kind ) {
case GDScriptParser : : DataType : : BUILTIN :
member . variable - > export_info . hint_string = Variant : : get_type_name ( datatype . builtin_type ) ;
break ;
case GDScriptParser : : DataType : : NATIVE :
if ( ClassDB : : is_parent_class ( get_real_class_name ( datatype . native_type ) , " Resource " ) ) {
member . variable - > export_info . hint = PROPERTY_HINT_RESOURCE_TYPE ;
member . variable - > export_info . hint_string = get_real_class_name ( datatype . native_type ) ;
} else {
push_error ( R " (Export type can only be built-in or a resource.) " , member . variable ) ;
}
break ;
default :
// TODO: Allow custom user resources.
push_error ( R " (Export type can only be built-in or a resource.) " , member . variable ) ;
break ;
}
}
// Apply annotations.
for ( List < GDScriptParser : : AnnotationNode * > : : Element * E = member . variable - > annotations . front ( ) ; E ; E = E - > next ( ) ) {
E - > get ( ) - > apply ( parser , member . variable ) ;
}
} break ;
case GDScriptParser : : ClassNode : : Member : : CONSTANT : {
@ -674,6 +618,11 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
datatype . is_constant = true ;
member . constant - > set_datatype ( datatype ) ;
// Apply annotations.
for ( List < GDScriptParser : : AnnotationNode * > : : Element * E = member . constant - > annotations . front ( ) ; E ; E = E - > next ( ) ) {
E - > get ( ) - > apply ( parser , member . constant ) ;
}
} break ;
case GDScriptParser : : ClassNode : : Member : : SIGNAL : {
for ( int j = 0 ; j < member . signal - > parameters . size ( ) ; j + + ) {
@ -688,6 +637,11 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
signal_type . builtin_type = Variant : : SIGNAL ;
member . signal - > set_datatype ( signal_type ) ;
// Apply annotations.
for ( List < GDScriptParser : : AnnotationNode * > : : Element * E = member . signal - > annotations . front ( ) ; E ; E = E - > next ( ) ) {
E - > get ( ) - > apply ( parser , member . signal ) ;
}
} break ;
case GDScriptParser : : ClassNode : : Member : : ENUM : {
GDScriptParser : : DataType enum_type ;
@ -730,6 +684,11 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
current_enum = nullptr ;
member . m_enum - > set_datatype ( enum_type ) ;
// Apply annotations.
for ( List < GDScriptParser : : AnnotationNode * > : : Element * E = member . m_enum - > annotations . front ( ) ; E ; E = E - > next ( ) ) {
E - > get ( ) - > apply ( parser , member . m_enum ) ;
}
} break ;
case GDScriptParser : : ClassNode : : Member : : FUNCTION :
resolve_function_signature ( member . function ) ;
@ -798,6 +757,11 @@ void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class) {
}
resolve_function_body ( member . function ) ;
// Apply annotations.
for ( List < GDScriptParser : : AnnotationNode * > : : Element * E = member . function - > annotations . front ( ) ; E ; E = E - > next ( ) ) {
E - > get ( ) - > apply ( parser , member . function ) ;
}
}
parser - > current_class = previous_class ;
@ -2253,7 +2217,7 @@ void GDScriptAnalyzer::reduce_get_node(GDScriptParser::GetNodeNode *p_get_node)
result . native_type = " Node " ;
result . builtin_type = Variant : : OBJECT ;
if ( ! ClassDB : : is_parent_class ( get_real_class_name( parser - > current_class - > base_type . native_type ) , result . native_type ) ) {
if ( ! ClassDB : : is_parent_class ( GDScriptParser: : get_real_class_name( parser - > current_class - > base_type . native_type ) , result . native_type ) ) {
push_error ( R " *(Cannot use shorthand " get_node ( ) " notation ( " $ " ) on a class that isn't a node.)* " , p_get_node ) ;
}
@ -2419,7 +2383,7 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
}
// Check native members.
const StringName & native = get_real_class_name( base . native_type ) ;
const StringName & native = GDScriptParser: : get_real_class_name( base . native_type ) ;
if ( class_exists ( native ) ) {
PropertyInfo prop_info ;
@ -3243,7 +3207,7 @@ bool GDScriptAnalyzer::get_function_signature(GDScriptParser::Node *p_source, GD
return true ;
}
StringName real_native = get_real_class_name( base_native ) ;
StringName real_native = GDScriptParser: : get_real_class_name( base_native ) ;
MethodInfo info ;
if ( ClassDB : : get_method_info ( real_native , function_name , & info ) ) {
@ -3338,7 +3302,7 @@ bool GDScriptAnalyzer::is_shadowing(GDScriptParser::IdentifierNode *p_local, con
StringName parent = base_native ;
while ( parent ! = StringName ( ) ) {
StringName real_class_name = get_real_class_name( parent ) ;
StringName real_class_name = GDScriptParser: : get_real_class_name( parent ) ;
if ( ClassDB : : has_method ( real_class_name , name , true ) ) {
parser - > push_warning ( p_local , GDScriptWarning : : SHADOWED_VARIABLE_BASE_CLASS , p_context , p_local - > name , " method " , parent ) ;
return true ;
@ -3500,14 +3464,14 @@ bool GDScriptAnalyzer::is_type_compatible(const GDScriptParser::DataType &p_targ
}
// Get underscore-prefixed version for some classes.
src_native = get_real_class_name( src_native ) ;
src_native = GDScriptParser: : get_real_class_name( src_native ) ;
switch ( p_target . kind ) {
case GDScriptParser : : DataType : : NATIVE : {
if ( p_target . is_meta_type ) {
return ClassDB : : is_parent_class ( src_native , GDScriptNativeClass : : get_class_static ( ) ) ;
}
StringName tgt_native = get_real_class_name( p_target . native_type ) ;
StringName tgt_native = GDScriptParser: : get_real_class_name( p_target . native_type ) ;
return ClassDB : : is_parent_class ( src_native , tgt_native ) ;
}
case GDScriptParser : : DataType : : SCRIPT :
@ -3557,7 +3521,7 @@ void GDScriptAnalyzer::mark_node_unsafe(const GDScriptParser::Node *p_node) {
}
bool GDScriptAnalyzer : : class_exists ( const StringName & p_class ) const {
StringName real_name = get_real_class_name( p_class ) ;
StringName real_name = GDScriptParser: : get_real_class_name( p_class ) ;
return ClassDB : : class_exists ( real_name ) & & ClassDB : : is_class_exposed ( real_name ) ;
}