From: Rico Tzschichholz Date: Fri, 29 Mar 2019 13:27:14 +0000 (+0100) Subject: vala: Check coverage of switch on enum-type and issue warnings if needed X-Git-Tag: 0.49.1~148 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cd3ea493df12806b55a9725bf8714111f69b7c87;p=thirdparty%2Fvala.git vala: Check coverage of switch on enum-type and issue warnings if needed See https://gitlab.gnome.org/GNOME/vala/issues/777 --- diff --git a/tests/Makefile.am b/tests/Makefile.am index 2f3906f38..af8fe4d74 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -207,6 +207,7 @@ TESTS = \ control-flow/missing-return.test \ control-flow/nested-conditional.vala \ control-flow/switch.vala \ + control-flow/switch-enum.vala \ control-flow/sideeffects.vala \ control-flow/unassigned-captured-local-variable.test \ control-flow/unassigned-local-block-variable.test \ diff --git a/tests/control-flow/switch-enum.vala b/tests/control-flow/switch-enum.vala new file mode 100644 index 000000000..fa6b39991 --- /dev/null +++ b/tests/control-flow/switch-enum.vala @@ -0,0 +1,21 @@ +enum Foo { + FOO, + BAR, + MANAM +} + +Foo foo () { + Foo foo = Foo.BAR; + + switch (foo) { + case Foo.FOO: + case Foo.BAR: + break; + } + + return foo; +} + +void main () { + assert (foo () == Foo.BAR); +} diff --git a/vala/valaflowanalyzer.vala b/vala/valaflowanalyzer.vala index ea0df7a83..6f58dd3a0 100644 --- a/vala/valaflowanalyzer.vala +++ b/vala/valaflowanalyzer.vala @@ -664,6 +664,14 @@ public class Vala.FlowAnalyzer : CodeVisitor { handle_errors (stmt.expression); bool has_default_label = false; + bool is_enum_typed = stmt.expression.value_type is EnumValueType; + + unowned Enum? en = null; + HashSet? enum_values = null; + if (is_enum_typed) { + en = (Enum) ((EnumValueType) stmt.expression.value_type).type_symbol; + enum_values = new HashSet (direct_hash, direct_equal); + } foreach (SwitchSection section in stmt.get_sections ()) { current_block = new BasicBlock (); @@ -673,6 +681,17 @@ public class Vala.FlowAnalyzer : CodeVisitor { section_stmt.accept (this); } + if (is_enum_typed) { + foreach (SwitchLabel label in section.get_labels ()) { + if (label.expression != null) { + unowned EnumValue? val = label.expression.symbol_reference as EnumValue; + if (val != null) { + enum_values.add (val); + } + } + } + } + if (section.has_default_label ()) { has_default_label = true; } @@ -688,6 +707,24 @@ public class Vala.FlowAnalyzer : CodeVisitor { } } + if (!has_default_label && is_enum_typed) { + // Check if enum-based switching as fully covered, and if so, + // handle it like there was a default-label given + + HashSet remaining_values = new HashSet (); + remaining_values.add_all (en.get_values ()); + foreach (unowned EnumValue val in enum_values) { + remaining_values.remove (val); + } + if (remaining_values.size > 0) { + string[] missing_vals = {}; + foreach (var val in remaining_values) { + missing_vals += val.name; + } + Report.warning (stmt.source_reference, "switch does not handle `%s' of enum `%s'".printf (string.joinv ("', `", missing_vals), en.get_full_name ())); + } + } + if (!has_default_label) { condition_block.connect (after_switch_block); }