mirror of
				https://github.com/godotengine/godot.git
				synced 2025-11-04 07:31:16 +00:00 
			
		
		
		
	GDScript: Add error when exporting node in non [Node]-derived classes
This commit is contained in:
		
							parent
							
								
									c7ed5d795e
								
							
						
					
					
						commit
						9e2273abc7
					
				
					 12 changed files with 119 additions and 50 deletions
				
			
		| 
						 | 
				
			
			@ -519,7 +519,7 @@ void GDScriptParser::parse_program() {
 | 
			
		|||
				if (annotation->applies_to(AnnotationInfo::SCRIPT)) {
 | 
			
		||||
					// `@icon` needs to be applied in the parser. See GH-72444.
 | 
			
		||||
					if (annotation->name == SNAME("@icon")) {
 | 
			
		||||
						annotation->apply(this, head);
 | 
			
		||||
						annotation->apply(this, head, nullptr);
 | 
			
		||||
					} else {
 | 
			
		||||
						head->annotations.push_back(annotation);
 | 
			
		||||
					}
 | 
			
		||||
| 
						 | 
				
			
			@ -3795,12 +3795,12 @@ const GDScriptParser::SuiteNode::Local &GDScriptParser::SuiteNode::get_local(con
 | 
			
		|||
	return empty;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool GDScriptParser::AnnotationNode::apply(GDScriptParser *p_this, Node *p_target) {
 | 
			
		||||
bool GDScriptParser::AnnotationNode::apply(GDScriptParser *p_this, Node *p_target, ClassNode *p_class) {
 | 
			
		||||
	if (is_applied) {
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
	is_applied = true;
 | 
			
		||||
	return (p_this->*(p_this->valid_annotations[name].apply))(this, p_target);
 | 
			
		||||
	return (p_this->*(p_this->valid_annotations[name].apply))(this, p_target, p_class);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool GDScriptParser::AnnotationNode::applies_to(uint32_t p_target_kinds) const {
 | 
			
		||||
| 
						 | 
				
			
			@ -3846,7 +3846,7 @@ bool GDScriptParser::validate_annotation_arguments(AnnotationNode *p_annotation)
 | 
			
		|||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool GDScriptParser::tool_annotation(const AnnotationNode *p_annotation, Node *p_node) {
 | 
			
		||||
bool GDScriptParser::tool_annotation(const AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class) {
 | 
			
		||||
#ifdef DEBUG_ENABLED
 | 
			
		||||
	if (this->_is_tool) {
 | 
			
		||||
		push_error(R"("@tool" annotation can only be used once.)", p_annotation);
 | 
			
		||||
| 
						 | 
				
			
			@ -3857,15 +3857,15 @@ bool GDScriptParser::tool_annotation(const AnnotationNode *p_annotation, Node *p
 | 
			
		|||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool GDScriptParser::icon_annotation(const AnnotationNode *p_annotation, Node *p_node) {
 | 
			
		||||
	ERR_FAIL_COND_V_MSG(p_node->type != Node::CLASS, false, R"("@icon" annotation can only be applied to classes.)");
 | 
			
		||||
bool GDScriptParser::icon_annotation(const AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class) {
 | 
			
		||||
	ERR_FAIL_COND_V_MSG(p_target->type != Node::CLASS, false, R"("@icon" annotation can only be applied to classes.)");
 | 
			
		||||
	ERR_FAIL_COND_V(p_annotation->resolved_arguments.is_empty(), false);
 | 
			
		||||
 | 
			
		||||
	ClassNode *p_class = static_cast<ClassNode *>(p_node);
 | 
			
		||||
	ClassNode *class_node = static_cast<ClassNode *>(p_target);
 | 
			
		||||
	String path = p_annotation->resolved_arguments[0];
 | 
			
		||||
 | 
			
		||||
#ifdef DEBUG_ENABLED
 | 
			
		||||
	if (!p_class->icon_path.is_empty()) {
 | 
			
		||||
	if (!class_node->icon_path.is_empty()) {
 | 
			
		||||
		push_error(R"("@icon" annotation can only be used once.)", p_annotation);
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -3875,27 +3875,27 @@ bool GDScriptParser::icon_annotation(const AnnotationNode *p_annotation, Node *p
 | 
			
		|||
	}
 | 
			
		||||
#endif // DEBUG_ENABLED
 | 
			
		||||
 | 
			
		||||
	p_class->icon_path = path;
 | 
			
		||||
	class_node->icon_path = path;
 | 
			
		||||
 | 
			
		||||
	if (path.is_empty() || path.is_absolute_path()) {
 | 
			
		||||
		p_class->simplified_icon_path = path.simplify_path();
 | 
			
		||||
		class_node->simplified_icon_path = path.simplify_path();
 | 
			
		||||
	} else if (path.is_relative_path()) {
 | 
			
		||||
		p_class->simplified_icon_path = script_path.get_base_dir().path_join(path).simplify_path();
 | 
			
		||||
		class_node->simplified_icon_path = script_path.get_base_dir().path_join(path).simplify_path();
 | 
			
		||||
	} else {
 | 
			
		||||
		p_class->simplified_icon_path = path;
 | 
			
		||||
		class_node->simplified_icon_path = path;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool GDScriptParser::onready_annotation(const AnnotationNode *p_annotation, Node *p_node) {
 | 
			
		||||
	ERR_FAIL_COND_V_MSG(p_node->type != Node::VARIABLE, false, R"("@onready" annotation can only be applied to class variables.)");
 | 
			
		||||
bool GDScriptParser::onready_annotation(const AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class) {
 | 
			
		||||
	ERR_FAIL_COND_V_MSG(p_target->type != Node::VARIABLE, false, R"("@onready" annotation can only be applied to class variables.)");
 | 
			
		||||
 | 
			
		||||
	if (current_class && !ClassDB::is_parent_class(current_class->get_datatype().native_type, SNAME("Node"))) {
 | 
			
		||||
		push_error(R"("@onready" can only be used in classes that inherit "Node".)", p_annotation);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	VariableNode *variable = static_cast<VariableNode *>(p_node);
 | 
			
		||||
	VariableNode *variable = static_cast<VariableNode *>(p_target);
 | 
			
		||||
	if (variable->is_static) {
 | 
			
		||||
		push_error(R"("@onready" annotation cannot be applied to a static variable.)", p_annotation);
 | 
			
		||||
		return false;
 | 
			
		||||
| 
						 | 
				
			
			@ -3910,10 +3910,11 @@ bool GDScriptParser::onready_annotation(const AnnotationNode *p_annotation, Node
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
template <PropertyHint t_hint, Variant::Type t_type>
 | 
			
		||||
bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node *p_node) {
 | 
			
		||||
	ERR_FAIL_COND_V_MSG(p_node->type != Node::VARIABLE, false, vformat(R"("%s" annotation can only be applied to variables.)", p_annotation->name));
 | 
			
		||||
bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class) {
 | 
			
		||||
	ERR_FAIL_COND_V_MSG(p_target->type != Node::VARIABLE, false, vformat(R"("%s" annotation can only be applied to variables.)", p_annotation->name));
 | 
			
		||||
	ERR_FAIL_NULL_V(p_class, false);
 | 
			
		||||
 | 
			
		||||
	VariableNode *variable = static_cast<VariableNode *>(p_node);
 | 
			
		||||
	VariableNode *variable = static_cast<VariableNode *>(p_target);
 | 
			
		||||
	if (variable->is_static) {
 | 
			
		||||
		push_error(vformat(R"(Annotation "%s" cannot be applied to a static variable.)", p_annotation->name), p_annotation);
 | 
			
		||||
		return false;
 | 
			
		||||
| 
						 | 
				
			
			@ -4128,7 +4129,12 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node
 | 
			
		|||
			} break;
 | 
			
		||||
			default:
 | 
			
		||||
				push_error(R"(Export type can only be built-in, a resource, a node, or an enum.)", variable);
 | 
			
		||||
				break;
 | 
			
		||||
				return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (variable->export_info.hint == PROPERTY_HINT_NODE_TYPE && !ClassDB::is_parent_class(p_class->base_type.native_type, SNAME("Node"))) {
 | 
			
		||||
			push_error(vformat(R"(Node export is only supported in Node-derived classes, but the current class inherits "%s".)", p_class->base_type.to_string()), variable);
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (is_array) {
 | 
			
		||||
| 
						 | 
				
			
			@ -4173,7 +4179,7 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
template <PropertyUsageFlags t_usage>
 | 
			
		||||
bool GDScriptParser::export_group_annotations(const AnnotationNode *p_annotation, Node *p_node) {
 | 
			
		||||
bool GDScriptParser::export_group_annotations(const AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class) {
 | 
			
		||||
	AnnotationNode *annotation = const_cast<AnnotationNode *>(p_annotation);
 | 
			
		||||
 | 
			
		||||
	if (annotation->resolved_arguments.is_empty()) {
 | 
			
		||||
| 
						 | 
				
			
			@ -4205,7 +4211,7 @@ bool GDScriptParser::export_group_annotations(const AnnotationNode *p_annotation
 | 
			
		|||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool GDScriptParser::warning_annotations(const AnnotationNode *p_annotation, Node *p_node) {
 | 
			
		||||
bool GDScriptParser::warning_annotations(const AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class) {
 | 
			
		||||
#ifdef DEBUG_ENABLED
 | 
			
		||||
	bool has_error = false;
 | 
			
		||||
	for (const Variant &warning_name : p_annotation->resolved_arguments) {
 | 
			
		||||
| 
						 | 
				
			
			@ -4214,7 +4220,7 @@ bool GDScriptParser::warning_annotations(const AnnotationNode *p_annotation, Nod
 | 
			
		|||
			push_error(vformat(R"(Invalid warning name: "%s".)", warning_name), p_annotation);
 | 
			
		||||
			has_error = true;
 | 
			
		||||
		} else {
 | 
			
		||||
			p_node->ignored_warnings.push_back(warning);
 | 
			
		||||
			p_target->ignored_warnings.push_back(warning);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -4226,10 +4232,10 @@ bool GDScriptParser::warning_annotations(const AnnotationNode *p_annotation, Nod
 | 
			
		|||
#endif // DEBUG_ENABLED
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool GDScriptParser::rpc_annotation(const AnnotationNode *p_annotation, Node *p_node) {
 | 
			
		||||
	ERR_FAIL_COND_V_MSG(p_node->type != Node::FUNCTION, false, vformat(R"("%s" annotation can only be applied to functions.)", p_annotation->name));
 | 
			
		||||
bool GDScriptParser::rpc_annotation(const AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class) {
 | 
			
		||||
	ERR_FAIL_COND_V_MSG(p_target->type != Node::FUNCTION, false, vformat(R"("%s" annotation can only be applied to functions.)", p_annotation->name));
 | 
			
		||||
 | 
			
		||||
	FunctionNode *function = static_cast<FunctionNode *>(p_node);
 | 
			
		||||
	FunctionNode *function = static_cast<FunctionNode *>(p_target);
 | 
			
		||||
	if (function->rpc_config.get_type() != Variant::NIL) {
 | 
			
		||||
		push_error(R"(RPC annotations can only be used once per function.)", p_annotation);
 | 
			
		||||
		return false;
 | 
			
		||||
| 
						 | 
				
			
			@ -4287,14 +4293,14 @@ bool GDScriptParser::rpc_annotation(const AnnotationNode *p_annotation, Node *p_
 | 
			
		|||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool GDScriptParser::static_unload_annotation(const AnnotationNode *p_annotation, Node *p_target) {
 | 
			
		||||
bool GDScriptParser::static_unload_annotation(const AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class) {
 | 
			
		||||
	ERR_FAIL_COND_V_MSG(p_target->type != Node::CLASS, false, vformat(R"("%s" annotation can only be applied to classes.)", p_annotation->name));
 | 
			
		||||
	ClassNode *p_class = static_cast<ClassNode *>(p_target);
 | 
			
		||||
	if (p_class->annotated_static_unload) {
 | 
			
		||||
	ClassNode *class_node = static_cast<ClassNode *>(p_target);
 | 
			
		||||
	if (class_node->annotated_static_unload) {
 | 
			
		||||
		push_error(vformat(R"("%s" annotation can only be used once per script.)", p_annotation->name), p_annotation);
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
	p_class->annotated_static_unload = true;
 | 
			
		||||
	class_node->annotated_static_unload = true;
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue