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

Code before:
		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;
		}
	};

	warning_directory_rules.sort_custom<RuleSort>();
}
#endif // DEBUG_ENABLED

GDScriptParser::GDScriptParser() {
	// Register valid annotations.
	if (unlikely(valid_annotations.is_empty())) {
		// Script annotations.
		register_annotation(MethodInfo("@tool"), AnnotationInfo::SCRIPT, &GDScriptParser::tool_annotation);
		register_annotation(MethodInfo("@icon", PropertyInfo(Variant::STRING, "icon_path")), AnnotationInfo::SCRIPT, &GDScriptParser::icon_annotation);
		register_annotation(MethodInfo("@static_unload"), AnnotationInfo::SCRIPT, &GDScriptParser::static_unload_annotation);
		register_annotation(MethodInfo("@abstract"), AnnotationInfo::SCRIPT | AnnotationInfo::CLASS | AnnotationInfo::FUNCTION, &GDScriptParser::abstract_annotation);
		// Onready annotation.
		register_annotation(MethodInfo("@onready"), AnnotationInfo::VARIABLE, &GDScriptParser::onready_annotation);
		// Export annotations.
		register_annotation(MethodInfo("@export"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_NONE, Variant::NIL>);
		register_annotation(MethodInfo("@export_enum", PropertyInfo(Variant::STRING, "names")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_ENUM, Variant::NIL>, varray(), true);
		register_annotation(MethodInfo("@export_file", PropertyInfo(Variant::STRING, "filter")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_FILE, Variant::STRING>, varray(""), true);
		register_annotation(MethodInfo("@export_file_path", PropertyInfo(Variant::STRING, "filter")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_FILE_PATH, Variant::STRING>, varray(""), true);
		register_annotation(MethodInfo("@export_dir"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_DIR, Variant::STRING>);
		register_annotation(MethodInfo("@export_global_file", PropertyInfo(Variant::STRING, "filter")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_GLOBAL_FILE, Variant::STRING>, varray(""), true);
		register_annotation(MethodInfo("@export_global_dir"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_GLOBAL_DIR, Variant::STRING>);

Review comment (suggestion):
Nitpicky, but seeing as how this is the only place we do the sorting, is it really justified to have this extra `specificity` member? You could just as well do `.count("/")` here instead.

Code after:
		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 {
			return p_a.directory_path.count("/") > p_b.directory_path.count("/");
		}
	};

	warning_directory_rules.sort_custom<RuleSort>();
}
#endif // DEBUG_ENABLED

GDScriptParser::GDScriptParser() {
	// Register valid annotations.
	if (unlikely(valid_annotations.is_empty())) {
		// Script annotations.
		register_annotation(MethodInfo("@tool"), AnnotationInfo::SCRIPT, &GDScriptParser::tool_annotation);
		register_annotation(MethodInfo("@icon", PropertyInfo(Variant::STRING, "icon_path")), AnnotationInfo::SCRIPT, &GDScriptParser::icon_annotation);
		register_annotation(MethodInfo("@static_unload"), AnnotationInfo::SCRIPT, &GDScriptParser::static_unload_annotation);
		register_annotation(MethodInfo("@abstract"), AnnotationInfo::SCRIPT | AnnotationInfo::CLASS | AnnotationInfo::FUNCTION, &GDScriptParser::abstract_annotation);
		// Onready annotation.
		register_annotation(MethodInfo("@onready"), AnnotationInfo::VARIABLE, &GDScriptParser::onready_annotation);
		// Export annotations.
		register_annotation(MethodInfo("@export"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_NONE, Variant::NIL>);
		register_annotation(MethodInfo("@export_enum", PropertyInfo(Variant::STRING, "names")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_ENUM, Variant::NIL>, varray(), true);
		register_annotation(MethodInfo("@export_file", PropertyInfo(Variant::STRING, "filter")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_FILE, Variant::STRING>, varray(""), true);
		register_annotation(MethodInfo("@export_file_path", PropertyInfo(Variant::STRING, "filter")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_FILE_PATH, Variant::STRING>, varray(""), true);
		register_annotation(MethodInfo("@export_dir"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_DIR, Variant::STRING>);
		register_annotation(MethodInfo("@export_global_file", PropertyInfo(Variant::STRING, "filter")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_GLOBAL_FILE, Variant::STRING>, varray(""), true);