Repository: godotengine/godot
File: modules/gdscript/gdscript_parser.cpp (C++)

Code before:
}

void GDScriptParser::get_annotation_list(List<MethodInfo> *r_annotations) const {
	for (const KeyValue<StringName, AnnotationInfo> &E : valid_annotations) {
		r_annotations->push_back(E.value.info);
	}
}

bool GDScriptParser::annotation_exists(const String &p_annotation_name) const {
	return valid_annotations.has(p_annotation_name);
}

#ifdef DEBUG_ENABLED
void GDScriptParser::update_project_settings() {
	is_ignoring_warnings = !GLOBAL_GET("debug/gdscript/warnings/enable").booleanize();

	for (int i = 0; i < GDScriptWarning::WARNING_MAX; i++) {
		const String setting_path = GDScriptWarning::get_setting_path_from_code((GDScriptWarning::Code)i);
		warning_levels[i] = (GDScriptWarning::WarnLevel)(int)GLOBAL_GET(setting_path);
	}

#ifndef DISABLE_DEPRECATED
	// We do not use `GLOBAL_GET`, since we check without taking overrides into account. We leave the migration of non-trivial configurations to the user.
	const bool is_excluding_addons = ProjectSettings::get_singleton()->get_setting("debug/gdscript/warnings/exclude_addons", true).booleanize();
	if (unlikely(!is_excluding_addons)) {
		ProjectSettings::get_singleton()->set_setting("debug/gdscript/warnings/exclude_addons", Variant());
		Dictionary rules = ProjectSettings::get_singleton()->get_setting("debug/gdscript/warnings/directory_rules");
		rules["res://addons"] = WarningDirectoryRule::INCLUDE;
		ProjectSettings::get_singleton()->set_setting("debug/gdscript/warnings/directory_rules", rules);
	}
#endif // DISABLE_DEPRECATED

	warning_directory_rules.clear();

	const Dictionary rules = GLOBAL_GET("debug/gdscript/warnings/directory_rules");
	for (const KeyValue<Variant, Variant> &kv : rules) {
		String dir = kv.key.operator String().simplify_path();
		ERR_CONTINUE(!dir.begins_with("res://"));
		if (!dir.ends_with("/")) {
			dir += '/';
		}

		const int decision = kv.value;
		ERR_CONTINUE(decision < 0 || decision >= WarningDirectoryRule::DECISION_COUNT);

		warning_directory_rules.push_back({ dir, (WarningDirectoryRule::Decision)decision, dir.count("/") });
	}

	struct RuleSort {
		bool operator()(const WarningDirectoryRule &p_a, const WarningDirectoryRule &p_b) const {
			return p_a.specificity > p_b.specificity;

Review comment (suggestion):
On the off-chance that somebody manually edited their `project.godot` file with `gdscript/warnings/exclude_addons=true`, you might want to do what other settings migrations do instead, and check if the setting is explicitly set at all using `ProjectSettings::has_setting`.

I believe you can replace the `set_setting(..., Variant())` with `ProjectSettings::clear` as well.

Code after:
}

void GDScriptParser::get_annotation_list(List<MethodInfo> *r_annotations) const {
	for (const KeyValue<StringName, AnnotationInfo> &E : valid_annotations) {
		r_annotations->push_back(E.value.info);
	}
}

bool GDScriptParser::annotation_exists(const String &p_annotation_name) const {
	return valid_annotations.has(p_annotation_name);
}

#ifdef DEBUG_ENABLED
void GDScriptParser::update_project_settings() {
	is_project_ignoring_warnings = !GLOBAL_GET("debug/gdscript/warnings/enable").booleanize();

	for (int i = 0; i < GDScriptWarning::WARNING_MAX; i++) {
		const String setting_path = GDScriptWarning::get_setting_path_from_code((GDScriptWarning::Code)i);
		warning_levels[i] = (GDScriptWarning::WarnLevel)(int)GLOBAL_GET(setting_path);
	}

#ifndef DISABLE_DEPRECATED
	// We do not use `GLOBAL_GET`, since we check without taking overrides into account. We leave the migration of non-trivial configurations to the user.
	if (unlikely(ProjectSettings::get_singleton()->has_setting("debug/gdscript/warnings/exclude_addons"))) {
		const bool is_excluding_addons = ProjectSettings::get_singleton()->get_setting("debug/gdscript/warnings/exclude_addons", true).booleanize();
		ProjectSettings::get_singleton()->clear("debug/gdscript/warnings/exclude_addons");

		Dictionary rules = ProjectSettings::get_singleton()->get_setting("debug/gdscript/warnings/directory_rules");
		rules["res://addons"] = is_excluding_addons ? WarningDirectoryRule::DECISION_EXCLUDE : WarningDirectoryRule::DECISION_INCLUDE;
		ProjectSettings::get_singleton()->set_setting("debug/gdscript/warnings/directory_rules", rules);
	}
#endif // DISABLE_DEPRECATED

	warning_directory_rules.clear();

	const Dictionary rules = GLOBAL_GET("debug/gdscript/warnings/directory_rules");
	for (const KeyValue<Variant, Variant> &kv : rules) {
		String dir = kv.key.operator String().simplify_path();
		ERR_CONTINUE_MSG(!dir.begins_with("res://"), R"(Paths in the project setting "debug/gdscript/warnings/directory_rules" keys must start with the "res://" prefix.)");
		if (!dir.ends_with("/")) {
			dir += '/';
		}

		const int decision = kv.value;
		ERR_CONTINUE(decision < 0 || decision >= WarningDirectoryRule::DECISION_MAX);

		warning_directory_rules.push_back({ dir, (WarningDirectoryRule::Decision)decision });
	}

	struct RuleSort {
		bool operator()(const WarningDirectoryRule &p_a, const WarningDirectoryRule &p_b) const {