summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRico Tzschichholz <ricotz@ubuntu.com>2019-03-29 14:27:14 +0100
committerRico Tzschichholz <ricotz@ubuntu.com>2020-04-24 08:50:08 +0200
commit90fc5b11e9a3b2c2fdbf7caf53a5ffb0fafd5545 (patch)
treedc25b14eebec4a68947fb27319f307db698a9308
parent71af8d680d1277a1d0b187ce425b75375df7bf85 (diff)
downloadvala-wip/issue/777.tar.gz
WIP vala: Check coverage of switch on enum-type and issue warnings if neededwip/issue/777
Also don't emit implicit default label. Fixes https://gitlab.gnome.org/GNOME/vala/issues/777
-rw-r--r--codegen/valaccodecontrolflowmodule.vala2
-rw-r--r--tests/Makefile.am1
-rw-r--r--tests/control-flow/switch-enum.vala20
-rw-r--r--vala/valaflowanalyzer.vala39
4 files changed, 61 insertions, 1 deletions
diff --git a/codegen/valaccodecontrolflowmodule.vala b/codegen/valaccodecontrolflowmodule.vala
index df31fcef3..a61b3d9fe 100644
--- a/codegen/valaccodecontrolflowmodule.vala
+++ b/codegen/valaccodecontrolflowmodule.vala
@@ -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 ();
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..51aaaba4c
--- /dev/null
+++ b/tests/control-flow/switch-enum.vala
@@ -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);
+}
diff --git a/vala/valaflowanalyzer.vala b/vala/valaflowanalyzer.vala
index ea0df7a83..07ba88998 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<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);
}