@@ -68,9 +68,15 @@ Variant::Type GDScriptParser::get_builtin_type(const StringName &p_type) {
6868 return Variant::VARIANT_MAX;
6969}
7070
71+ #ifdef DEBUG_ENABLED
72+ bool GDScriptParser::is_project_ignoring_warnings = false ;
73+ GDScriptWarning::WarnLevel GDScriptParser::warning_levels[GDScriptWarning::WARNING_MAX];
74+ LocalVector<GDScriptParser::WarningDirectoryRule> GDScriptParser::warning_directory_rules;
75+ #endif // DEBUG_ENABLED
76+
7177#ifdef TOOLS_ENABLED
7278HashMap<String, String> GDScriptParser::theme_color_names;
73- #endif
79+ #endif // TOOLS_ENABLED
7480
7581HashMap<StringName, GDScriptParser::AnnotationInfo> GDScriptParser::valid_annotations;
7682
@@ -89,6 +95,53 @@ bool GDScriptParser::annotation_exists(const String &p_annotation_name) const {
8995 return valid_annotations.has (p_annotation_name);
9096}
9197
98+ #ifdef DEBUG_ENABLED
99+ void GDScriptParser::update_project_settings () {
100+ is_project_ignoring_warnings = !GLOBAL_GET (" debug/gdscript/warnings/enable" ).booleanize ();
101+
102+ for (int i = 0 ; i < GDScriptWarning::WARNING_MAX; i++) {
103+ const String setting_path = GDScriptWarning::get_setting_path_from_code ((GDScriptWarning::Code)i);
104+ warning_levels[i] = (GDScriptWarning::WarnLevel)(int )GLOBAL_GET (setting_path);
105+ }
106+
107+ #ifndef DISABLE_DEPRECATED
108+ // 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.
109+ if (unlikely (ProjectSettings::get_singleton ()->has_setting (" debug/gdscript/warnings/exclude_addons" ))) {
110+ const bool is_excluding_addons = ProjectSettings::get_singleton ()->get_setting (" debug/gdscript/warnings/exclude_addons" , true ).booleanize ();
111+ ProjectSettings::get_singleton ()->clear (" debug/gdscript/warnings/exclude_addons" );
112+
113+ Dictionary rules = ProjectSettings::get_singleton ()->get_setting (" debug/gdscript/warnings/directory_rules" );
114+ rules[" res://addons" ] = is_excluding_addons ? WarningDirectoryRule::DECISION_EXCLUDE : WarningDirectoryRule::DECISION_INCLUDE;
115+ ProjectSettings::get_singleton ()->set_setting (" debug/gdscript/warnings/directory_rules" , rules);
116+ }
117+ #endif // DISABLE_DEPRECATED
118+
119+ warning_directory_rules.clear ();
120+
121+ const Dictionary rules = GLOBAL_GET (" debug/gdscript/warnings/directory_rules" );
122+ for (const KeyValue<Variant, Variant> &kv : rules) {
123+ String dir = kv.key .operator String ().simplify_path ();
124+ 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.)" );
125+ if (!dir.ends_with (" /" )) {
126+ dir += ' /' ;
127+ }
128+
129+ const int decision = kv.value ;
130+ ERR_CONTINUE (decision < 0 || decision >= WarningDirectoryRule::DECISION_MAX);
131+
132+ warning_directory_rules.push_back ({ dir, (WarningDirectoryRule::Decision)decision });
133+ }
134+
135+ struct RuleSort {
136+ bool operator ()(const WarningDirectoryRule &p_a, const WarningDirectoryRule &p_b) const {
137+ return p_a.directory_path .count (" /" ) > p_b.directory_path .count (" /" );
138+ }
139+ };
140+
141+ warning_directory_rules.sort_custom <RuleSort>();
142+ }
143+ #endif // DEBUG_ENABLED
144+
92145GDScriptParser::GDScriptParser () {
93146 // Register valid annotations.
94147 if (unlikely (valid_annotations.is_empty ())) {
@@ -137,11 +190,10 @@ GDScriptParser::GDScriptParser() {
137190 }
138191
139192#ifdef DEBUG_ENABLED
140- is_ignoring_warnings = !(bool )GLOBAL_GET (" debug/gdscript/warnings/enable" );
141193 for (int i = 0 ; i < GDScriptWarning::WARNING_MAX; i++) {
142194 warning_ignore_start_lines[i] = INT_MAX;
143195 }
144- #endif
196+ #endif // DEBUG_ENABLED
145197
146198#ifdef TOOLS_ENABLED
147199 if (unlikely (theme_color_names.is_empty ())) {
@@ -161,7 +213,7 @@ GDScriptParser::GDScriptParser() {
161213 theme_color_names.insert (" a" , " axis_w_color" );
162214 theme_color_names.insert (" a8" , " axis_w_color" );
163215 }
164- #endif
216+ #endif // TOOLS_ENABLED
165217}
166218
167219GDScriptParser::~GDScriptParser () {
@@ -195,13 +247,11 @@ void GDScriptParser::push_warning(const Node *p_source, GDScriptWarning::Code p_
195247 ERR_FAIL_NULL (p_source);
196248 ERR_FAIL_INDEX (p_code, GDScriptWarning::WARNING_MAX);
197249
198- if (is_ignoring_warnings) {
199- return ;
200- }
201- if (GLOBAL_GET_CACHED (bool , " debug/gdscript/warnings/exclude_addons" ) && script_path.begins_with (" res://addons/" )) {
250+ if (is_project_ignoring_warnings || is_script_ignoring_warnings) {
202251 return ;
203252 }
204- GDScriptWarning::WarnLevel warn_level = (GDScriptWarning::WarnLevel)(int )GLOBAL_GET (GDScriptWarning::get_settings_path_from_code (p_code));
253+
254+ const GDScriptWarning::WarnLevel warn_level = warning_levels[p_code];
205255 if (warn_level == GDScriptWarning::IGNORE) {
206256 return ;
207257 }
@@ -251,6 +301,24 @@ void GDScriptParser::apply_pending_warnings() {
251301
252302 pending_warnings.clear ();
253303}
304+
305+ void GDScriptParser::evaluate_warning_directory_rules_for_script_path () {
306+ is_script_ignoring_warnings = false ;
307+ for (const WarningDirectoryRule &rule : warning_directory_rules) {
308+ if (script_path.begins_with (rule.directory_path )) {
309+ switch (rule.decision ) {
310+ case WarningDirectoryRule::DECISION_EXCLUDE:
311+ is_script_ignoring_warnings = true ;
312+ return ; // Stop checking rules.
313+ case WarningDirectoryRule::DECISION_INCLUDE:
314+ is_script_ignoring_warnings = false ;
315+ return ; // Stop checking rules.
316+ case WarningDirectoryRule::DECISION_MAX:
317+ return ; // Unreachable.
318+ }
319+ }
320+ }
321+ }
254322#endif // DEBUG_ENABLED
255323
256324void GDScriptParser::override_completion_context (const Node *p_for_node, CompletionType p_type, Node *p_node, int p_argument) {
@@ -391,9 +459,14 @@ Error GDScriptParser::parse(const String &p_source_code, const String &p_script_
391459 text_tokenizer->set_source_code (source);
392460
393461 tokenizer = text_tokenizer;
394-
395462 tokenizer->set_cursor_position (cursor_line, cursor_column);
463+
396464 script_path = p_script_path.simplify_path ();
465+
466+ #ifdef DEBUG_ENABLED
467+ evaluate_warning_directory_rules_for_script_path ();
468+ #endif // DEBUG_ENABLED
469+
397470 current = tokenizer->scan ();
398471 // Avoid error or newline as the first token.
399472 // The latter can mess with the parser when opening files filled exclusively with comments and newlines.
@@ -414,15 +487,15 @@ Error GDScriptParser::parse(const String &p_source_code, const String &p_script_
414487 nd->end_line = 1 ;
415488 push_warning (nd, GDScriptWarning::EMPTY_FILE);
416489 }
417- #endif
490+ #endif // DEBUG_ENABLED
418491
419492 push_multiline (false ); // Keep one for the whole parsing.
420493 parse_program ();
421494 pop_multiline ();
422495
423496#ifdef TOOLS_ENABLED
424497 comment_data = tokenizer->get_comments ();
425- #endif
498+ #endif // TOOLS_ENABLED
426499
427500 memdelete (text_tokenizer);
428501 tokenizer = nullptr ;
@@ -431,7 +504,7 @@ Error GDScriptParser::parse(const String &p_source_code, const String &p_script_
431504 if (multiline_stack.size () > 0 ) {
432505 ERR_PRINT (" Parser bug: Imbalanced multiline stack." );
433506 }
434- #endif
507+ #endif // DEBUG_ENABLED
435508
436509 if (errors.is_empty ()) {
437510 return OK;
@@ -450,7 +523,13 @@ Error GDScriptParser::parse_binary(const Vector<uint8_t> &p_binary, const String
450523 }
451524
452525 tokenizer = buffer_tokenizer;
526+
453527 script_path = p_script_path.simplify_path ();
528+
529+ #ifdef DEBUG_ENABLED
530+ evaluate_warning_directory_rules_for_script_path ();
531+ #endif // DEBUG_ENABLED
532+
454533 current = tokenizer->scan ();
455534 // Avoid error or newline as the first token.
456535 // The latter can mess with the parser when opening files filled exclusively with comments and newlines.
@@ -4997,10 +5076,6 @@ bool GDScriptParser::export_group_annotations(AnnotationNode *p_annotation, Node
49975076
49985077bool GDScriptParser::warning_ignore_annotation (AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class) {
49995078#ifdef DEBUG_ENABLED
5000- if (is_ignoring_warnings) {
5001- return true ; // We already ignore all warnings, let's optimize it.
5002- }
5003-
50045079 bool has_error = false ;
50055080 for (const Variant &warning_name : p_annotation->resolved_arguments ) {
50065081 GDScriptWarning::Code warning_code = GDScriptWarning::get_code_from_name (String (warning_name).to_upper ());
0 commit comments