Repository: godotengine/godot
File: core/object/object.cpp (C++)

Code before:
	const SignalData *s = signal_map.getptr(p_signal);
	if (!s) {
		return; //nothing
	}

	for (const KeyValue<Callable, SignalData::Slot> &slot_kv : s->slot_map) {
		p_connections->push_back(slot_kv.value.conn);
	}
}

int Object::get_persistent_signal_connection_count() const {
	int count = 0;

	for (const KeyValue<StringName, SignalData> &E : signal_map) {
		const SignalData *s = &E.value;

		for (const KeyValue<Callable, SignalData::Slot> &slot_kv : s->slot_map) {
			if (slot_kv.value.conn.flags & CONNECT_PERSIST) {
				count += 1;
			}
		}
	}

	return count;
}

void Object::get_signals_connected_to_this(List<Connection> *p_connections) const {
	for (const Connection &E : connections) {
		p_connections->push_back(E);
	}
}

Error Object::connect(const StringName &p_signal, const Callable &p_callable, uint32_t p_flags) {
	ERR_FAIL_COND_V_MSG(p_callable.is_null(), ERR_INVALID_PARAMETER, "Cannot connect to '" + p_signal + "': the provided callable is null.");

	Object *target_object = p_callable.get_object();
	ERR_FAIL_NULL_V_MSG(target_object, ERR_INVALID_PARAMETER, "Cannot connect to '" + p_signal + "' to callable '" + p_callable + "': the callable object is null.");

	SignalData *s = signal_map.getptr(p_signal);
	if (!s) {
		bool signal_is_valid = ClassDB::has_signal(get_class_name(), p_signal);
		//check in script
		if (!signal_is_valid && !script.is_null()) {
			if (Ref<Script>(script)->has_script_signal(p_signal)) {
				signal_is_valid = true;
			}
#ifdef TOOLS_ENABLED
			else {
				//allow connecting signals anyway if script is invalid, see issue #17070
				if (!Ref<Script>(script)->is_valid()) {
					signal_is_valid = true;

Review comment (suggestion):
`is_valid()` may be too strong here. If you look at the changes in `editor/plugins` you can see there are callables being created in a constructor that refer to `this`. It seems during the constructor the object isn't fully registered, meaning these callables aren't yet valid, and will be rejected by this line here.

I'm not sure how I like connecting invalid callables, but it was previous behavior to do so, so I'll probably change this line back to use `is_null()`, rather than try to chase down all the not-yet-valid-callables in Godot.

Code after:
	const SignalData *s = signal_map.getptr(p_signal);
	if (!s) {
		return; //nothing
	}

	for (const KeyValue<Callable, SignalData::Slot> &slot_kv : s->slot_map) {
		p_connections->push_back(slot_kv.value.conn);
	}
}

int Object::get_persistent_signal_connection_count() const {
	int count = 0;

	for (const KeyValue<StringName, SignalData> &E : signal_map) {
		const SignalData *s = &E.value;

		for (const KeyValue<Callable, SignalData::Slot> &slot_kv : s->slot_map) {
			if (slot_kv.value.conn.flags & CONNECT_PERSIST) {
				count += 1;
			}
		}
	}

	return count;
}

void Object::get_signals_connected_to_this(List<Connection> *p_connections) const {
	for (const Connection &E : connections) {
		p_connections->push_back(E);
	}
}

Error Object::connect(const StringName &p_signal, const Callable &p_callable, uint32_t p_flags) {
	ERR_FAIL_COND_V_MSG(p_callable.is_null(), ERR_INVALID_PARAMETER, "Cannot connect to '" + p_signal + "': the provided callable is null.");

	if (p_callable.is_standard()) {
		// FIXME: This branch should probably removed in favor of the `is_valid()` branch, but there exist some classes
		// that call `connect()` before they are fully registered with ClassDB. Until all such classes can be found
		// and registered soon enough this branch is needed to allow `connect()` to succeed.
		ERR_FAIL_NULL_V_MSG(p_callable.get_object(), ERR_INVALID_PARAMETER, "Cannot connect to '" + p_signal + "' to callable '" + p_callable + "': the callable object is null.");
	} else {
		ERR_FAIL_COND_V_MSG(!p_callable.is_valid(), ERR_INVALID_PARAMETER, "Cannot connect to '" + p_signal + "': the provided callable is not valid: " + p_callable);
	}

	SignalData *s = signal_map.getptr(p_signal);
	if (!s) {
		bool signal_is_valid = ClassDB::has_signal(get_class_name(), p_signal);
		//check in script
		if (!signal_is_valid && !script.is_null()) {
			if (Ref<Script>(script)->has_script_signal(p_signal)) {
				signal_is_valid = true;