[vala/staging: 2/2] gtkmodule: Improve UI parsing and handling of nested objects and properties
- From: Rico Tzschichholz <ricotz src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [vala/staging: 2/2] gtkmodule: Improve UI parsing and handling of nested objects and properties
- Date: Wed, 9 Feb 2022 07:49:58 +0000 (UTC)
commit 0d3ff97a2832f1d35d2d8eb488ecede4c7d7ca65
Author: Rico Tzschichholz <ricotz ubuntu com>
Date: Wed Feb 9 00:05:24 2022 +0100
gtkmodule: Improve UI parsing and handling of nested objects and properties
Don't restrict GtkCallback to instance methods
codegen/valagtkmodule.vala | 134 ++++++++++++++++-----
tests/Makefile.am | 1 +
.../gtktemplate/gtktemplate-unknown-template.test | 8 ++
3 files changed, 111 insertions(+), 32 deletions(-)
---
diff --git a/codegen/valagtkmodule.vala b/codegen/valagtkmodule.vala
index c0d98631c..ae316cada 100644
--- a/codegen/valagtkmodule.vala
+++ b/codegen/valagtkmodule.vala
@@ -23,6 +23,27 @@
public class Vala.GtkModule : GSignalModule {
+
+ class InvalidClass : Class {
+ public InvalidClass (string name) {
+ base (name, null, null);
+ error = true;
+ }
+ public override bool check (CodeContext context) {
+ return false;
+ }
+ }
+
+ class InvalidProperty : Property {
+ public InvalidProperty (string name) {
+ base (name, null, null, null);
+ error = true;
+ }
+ public override bool check (CodeContext context) {
+ return false;
+ }
+ }
+
/* C type-func name to Vala class mapping */
private HashMap<string, Class> type_id_to_vala_map = null;
/* C class name to Vala class mapping */
@@ -31,7 +52,7 @@ public class Vala.GtkModule : GSignalModule {
private HashMap<string, string> gresource_to_file_map = null;
/* GtkBuilder xml handler set */
private HashMap<string, string> handler_map = new HashMap<string, string>(str_hash, str_equal);
- /* GtkBuilder xml handler to Vala signal mapping */
+ /* GtkBuilder xml handler to Vala property mapping */
private HashMap<string, Property> current_handler_to_property_map = new HashMap<string,
Property>(str_hash, str_equal);
/* GtkBuilder xml handler to Vala signal mapping */
private HashMap<string, Signal> current_handler_to_signal_map = new HashMap<string, Signal>(str_hash,
str_equal);
@@ -40,6 +61,32 @@ public class Vala.GtkModule : GSignalModule {
/* Required custom application-specific gtype classes to be ref'd before initializing the template */
private List<Class> current_required_app_classes = new ArrayList<Class>();
+ /* Stack of occuring object elements in the template */
+ List<Class> current_object_stack = new ArrayList<Class> ();
+ Class? current_object;
+
+ void push_object (Class cl) {
+ current_object_stack.add (current_object);
+ current_object = cl;
+ }
+
+ void pop_object () {
+ current_object = current_object_stack.remove_at (current_object_stack.size - 1);
+ }
+
+ /* Stack of occuring property elements in the template */
+ List<Property> current_property_stack = new ArrayList<Property> ();
+ Property? current_property;
+
+ void push_property (Property prop) {
+ current_property_stack.add (current_property);
+ current_property = prop;
+ }
+
+ void pop_property () {
+ current_property = current_property_stack.remove_at (current_property_stack.size - 1);
+ }
+
private void ensure_type_id_to_vala_map () {
// map C type-func name of gtypeinstance classes to Vala classes
if (type_id_to_vala_map != null) {
@@ -156,10 +203,10 @@ public class Vala.GtkModule : GSignalModule {
handler_map = new HashMap<string, string>(str_hash, str_equal);
current_handler_to_signal_map = new HashMap<string, Signal>(str_hash, str_equal);
current_child_to_class_map = new HashMap<string, Class>(str_hash, str_equal);
+ current_object_stack = new ArrayList<Class> ();
+ current_property_stack = new ArrayList<Property> ();
MarkupReader reader = new MarkupReader (ui_file);
- Class current_class = null;
- Property? current_property = null;
string? current_handler = null;
bool template_tag_found = false;
@@ -167,7 +214,7 @@ public class Vala.GtkModule : GSignalModule {
while (current_token != MarkupTokenType.EOF) {
unowned string current_name = reader.name;
if (current_token == MarkupTokenType.START_ELEMENT && (current_name == "object" ||
current_name == "template")) {
- current_class = null;
+ Class? current_class = null;
if (current_name == "object") {
var type_id = reader.get_attribute ("type-func");
@@ -186,6 +233,15 @@ public class Vala.GtkModule : GSignalModule {
continue;
}
current_class = cclass_to_vala_map.get (class_name);
+
+ if (current_class == null) {
+ push_object (new InvalidClass (class_name));
+ if (current_name == "template") {
+ Report.error (node.source_reference, "Unknown
template `%s' in ui file `%s'", class_name, ui_file);
+ } else {
+ Report.warning (node.source_reference, "Unknown
object `%s' in ui file `%s'", class_name, ui_file);
+ }
+ }
}
if (current_class != null) {
@@ -193,35 +249,40 @@ public class Vala.GtkModule : GSignalModule {
if (child_name != null) {
current_child_to_class_map.set (child_name, current_class);
}
+ push_object (current_class);
}
- } else if (current_class != null && current_token == MarkupTokenType.START_ELEMENT &&
current_name == "signal") {
+ } else if (current_token == MarkupTokenType.END_ELEMENT && (current_name == "object"
|| current_name == "template")) {
+ pop_object ();
+ } else if (current_object != null && current_token == MarkupTokenType.START_ELEMENT
&& current_name == "signal") {
var signal_name = reader.get_attribute ("name");
var handler_name = reader.get_attribute ("handler");
- if (current_class != null) {
- if (signal_name == null || handler_name == null) {
- if (signal_name != null) {
- Report.error (node.source_reference, "Invalid signal
`%s' without handler in ui file `%s'", signal_name, ui_file);
- } else if (handler_name != null) {
- Report.error (node.source_reference, "Invalid signal
without name in ui file `%s'", ui_file);
- } else {
- Report.error (node.source_reference, "Invalid signal
without name and handler in ui file `%s'", ui_file);
- }
- current_token = reader.read_token (null, null);
- continue;
- }
- var sep_idx = signal_name.index_of ("::");
- if (sep_idx >= 0) {
- // detailed signal, we don't care about the detail
- signal_name = signal_name.substring (0, sep_idx);
+ if (signal_name == null || handler_name == null) {
+ if (signal_name != null) {
+ Report.error (node.source_reference, "Invalid signal `%s'
without handler in ui file `%s'", signal_name, ui_file);
+ } else if (handler_name != null) {
+ Report.error (node.source_reference, "Invalid signal without
name in ui file `%s'", ui_file);
+ } else {
+ Report.error (node.source_reference, "Invalid signal without
name and handler in ui file `%s'", ui_file);
}
+ current_token = reader.read_token (null, null);
+ continue;
+ }
+ var sep_idx = signal_name.index_of ("::");
+ if (sep_idx >= 0) {
+ // detailed signal, we don't care about the detail
+ signal_name = signal_name.substring (0, sep_idx);
+ }
- var sig = SemanticAnalyzer.symbol_lookup_inherited (current_class,
signal_name.replace ("-", "_")) as Signal;
- if (sig != null) {
- current_handler_to_signal_map.set (handler_name, sig);
- }
+ var sig = SemanticAnalyzer.symbol_lookup_inherited (current_object,
signal_name.replace ("-", "_")) as Signal;
+ if (sig != null) {
+ current_handler_to_signal_map.set (handler_name, sig);
+ } else {
+ Report.error (node.source_reference, "Unknown signal `%s::%s' in ui
file `%s'", current_object.get_full_name (), signal_name, ui_file);
+ current_token = reader.read_token (null, null);
+ continue;
}
- } else if (current_class != null && current_token == MarkupTokenType.START_ELEMENT &&
current_name == "binding") {
+ } else if (current_object != null && current_token == MarkupTokenType.START_ELEMENT
&& (current_name == "property" || current_name == "binding")) {
var property_name = reader.get_attribute ("name");
if (property_name == null) {
Report.error (node.source_reference, "Invalid binding in ui file
`%s'", ui_file);
@@ -230,13 +291,20 @@ public class Vala.GtkModule : GSignalModule {
}
property_name = property_name.replace ("-", "_");
- current_property = SemanticAnalyzer.symbol_lookup_inherited (current_class,
property_name) as Property;
- if (current_property == null) {
- Report.error (node.source_reference, "Unknown property `%s:%s' for
binding in ui file `%s'", current_class.get_full_name (), property_name, ui_file);
+ var property = SemanticAnalyzer.symbol_lookup_inherited (current_object,
property_name) as Property;
+ if (property != null) {
+ push_property (property);
+ } else {
+ push_property (new InvalidProperty (property_name));
+ if (current_name == "binding") {
+ Report.error (node.source_reference, "Unknown property
`%s:%s' for binding in ui file `%s'", current_object.get_full_name (), property_name, ui_file);
+ }
current_token = reader.read_token (null, null);
continue;
}
- } else if (current_class != null && current_token == MarkupTokenType.START_ELEMENT &&
current_name == "closure") {
+ } else if (current_token == MarkupTokenType.END_ELEMENT && (current_name ==
"property" || current_name == "binding")) {
+ pop_property ();
+ } else if (current_object != null && current_token == MarkupTokenType.START_ELEMENT
&& current_name == "closure") {
var handler_name = reader.get_attribute ("function");
if (current_property != null) {
@@ -245,11 +313,13 @@ public class Vala.GtkModule : GSignalModule {
current_token = reader.read_token (null, null);
continue;
}
+ if (current_property is InvalidProperty) {
+ Report.error (node.source_reference, "Unknown property
`%s:%s' for binding in ui file `%s'", current_object.get_full_name (), current_property.name, ui_file);
+ }
//TODO Retrieve signature declaration? c-type to vala-type?
current_handler_to_property_map.set (handler_name, current_property);
current_handler = handler_name;
- current_property = null;
} else if (current_handler != null) {
// Track nested closure elements
handler_map.set (handler_name, current_handler);
@@ -386,7 +456,7 @@ public class Vala.GtkModule : GSignalModule {
return;
}
- if (m.binding != MemberBinding.INSTANCE || m.get_attribute ("GtkCallback") == null) {
+ if (m.get_attribute ("GtkCallback") == null) {
return;
}
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 4190a0de1..b70914b67 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -860,6 +860,7 @@ TESTS = \
gtktemplate/gtkchild-property-unknown.test \
gtktemplate/gtkchild-without-gtktemplate.test \
gtktemplate/gtktemplate-gtkwidget-subclass.test \
+ gtktemplate/gtktemplate-unknown-template.test \
annotations/deprecated.vala \
annotations/deprecated-delegate-minimal.vala \
annotations/deprecated-enum-minimal.vala \
diff --git a/tests/gtktemplate/gtktemplate-unknown-template.test
b/tests/gtktemplate/gtktemplate-unknown-template.test
new file mode 100644
index 000000000..9c1549be7
--- /dev/null
+++ b/tests/gtktemplate/gtktemplate-unknown-template.test
@@ -0,0 +1,8 @@
+Invalid Code
+
+[GtkTemplate (ui = "/org/example/gtktemplate.ui")]
+public class GtkTemplate : Gtk.ApplicationWindow {
+}
+
+void main () {
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]