]> git.ipfire.org Git - thirdparty/vala.git/commitdiff
WIP vala: Check coverage of switch on enum-type and issue warnings if needed wip/issue/777 90fc5b11e9a3b2c2fdbf7caf53a5ffb0fafd5545 58/head
authorRico Tzschichholz <ricotz@ubuntu.com>
Fri, 29 Mar 2019 13:27:14 +0000 (14:27 +0100)
committerRico Tzschichholz <ricotz@ubuntu.com>
Fri, 24 Apr 2020 06:50:08 +0000 (08:50 +0200)
Also don't emit implicit default label.

Fixes https://gitlab.gnome.org/GNOME/vala/issues/777

codegen/valaccodecontrolflowmodule.vala
tests/Makefile.am
tests/control-flow/switch-enum.vala [new file with mode: 0644]
vala/valaflowanalyzer.vala

index df31fcef31b8d591d794e40aaa5278839007baaa..a61b3d9fea20b4f1ffcd845c2e07060e775adf9f 100644 (file)
@@ -182,7 +182,7 @@ public abstract class Vala.CCodeControlFlowModule : CCodeMethodModule {
                        section.emit (this);
                }
 
-               if (!has_default) {
+               if (!has_default && !(stmt.expression.value_type is EnumValueType)) {
                        // silence C compiler
                        ccode.add_default ();
                        ccode.add_break ();
index 2f3906f38b7a6868f3e775dcbe4d83a8d31ae627..af8fe4d745ae1cc96969b10bd9f82d8a380b53ce 100644 (file)
@@ -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 (file)
index 0000000..51aaaba
--- /dev/null
@@ -0,0 +1,20 @@
+enum Foo {
+       FOO,
+       BAR,
+       MANAM
+}
+
+Foo foo () {
+       Foo foo = Foo.BAR;
+
+       switch (foo) {
+       case Foo.MANAM:
+       case Foo.FOO:
+       case Foo.BAR:
+               return foo;
+       }
+}
+
+void main () {
+       assert (foo () == Foo.BAR);
+}
index ea0df7a83c150d7ce01201eb55d98d3604329e68..07ba88998aa707f1df58825dbe34814763ccd555 100644 (file)
@@ -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<unowned EnumValue>? enum_values = null;
+               if (is_enum_typed) {
+                       en = (Enum) ((EnumValueType) stmt.expression.value_type).type_symbol;
+                       enum_values = new HashSet<unowned EnumValue> (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,26 @@ public class Vala.FlowAnalyzer : CodeVisitor {
                        }
                }
 
+               if (is_enum_typed) {
+                       // Check if enum-based switching as fully covered, and if so,
+                       // handle it like there was a default-label given
+
+                       HashSet<EnumValue> remaining_values = new HashSet<EnumValue> ();
+                       remaining_values.add_all (en.get_values ());
+                       foreach (var val in enum_values) {
+                               remaining_values.remove (val);
+                       }
+                       if (remaining_values.size == 0) {
+                               has_default_label = true;
+                       } else if (!has_default_label) {
+                               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);
                }