1From 7b2d3699ad117199bc316c7007cc5984c3b09368 Mon Sep 17 00:00:00 2001
2From: Maximiliano Sandoval <msandova@gnome.org>
3Date: Thu, 20 Mar 2025 22:52:54 +0100
4Subject: [PATCH] scanner: Prefer some getters over others
5
6At the moment the current set of heuristics to determine a getter for a
7property is good for finding *a* getter. However, if there are multiple
8candidates we might declare the wrong method as a getter.
9
10We introduce a priority system to determine which getter candidate is
11the most appropriate as the getter. The weight were chosen with gaps in
12between so that new and better heuristics have space to thrive.
13
14For a property named `p`, these are the possible getter candidates:
15
16 - A method declared via the `(getter p)` annotation
17 - The method `get_p`
18 - The method `is_p`
19 - The method `p`
20
21we declare the getter to be the first candidate in the list for which a
22method of the same name is available.
23
24See https://gitlab.gnome.org/GNOME/gjs/-/issues/681.
25---
26 giscanner/maintransformer.py | 22 +++++++++++++++-------
27 1 file changed, 15 insertions(+), 7 deletions(-)
28
29diff --git a/giscanner/maintransformer.py b/giscanner/maintransformer.py
30index a81b1777..9aaf2578 100644
31--- a/giscanner/maintransformer.py
32+++ b/giscanner/maintransformer.py
33@@ -1612,7 +1612,10 @@ method or constructor of some type."""
34 if not prop.introspectable:
35 continue
36 setter = None
37- getter = []
38+ # They keys are method names of candidates for getters. The values
39+ # are priority weights that measure how tasteful was the heuristic
40+ # used to propose their candidate.
41+ getter = {}
42 if prop.setter is None:
43 if prop.writable and not prop.construct_only:
44 setter = 'set_' + normalized_name
45@@ -1620,17 +1623,17 @@ method or constructor of some type."""
46 setter = prop.setter
47 if prop.getter is None:
48 if prop.readable:
49- getter = ['get_' + normalized_name]
50+ getter[f"get_{normalized_name}"] = 50
51 # Heuristic: boolean properties can have getters that are
52 # prefixed by is_property_name, like: gtk_window_is_maximized()
53 if prop.type.is_equiv(ast.TYPE_BOOLEAN) and not normalized_name.startswith("is_"):
54- getter.append(f"is_{normalized_name}")
55+ getter[f"is_{normalized_name}"] = 25
56 # Heuristic: read-only properties can have getters that are
57 # just the property name, like: gtk_widget_has_focus()
58 if not prop.writable and prop.type.is_equiv(ast.TYPE_BOOLEAN):
59- getter.append(normalized_name)
60+ getter[normalized_name] = 10
61 else:
62- getter = [prop.getter]
63+ getter[prop.getter] = 99
64 for method in node.methods:
65 if not method.introspectable:
66 continue
67@@ -1645,7 +1648,7 @@ method or constructor of some type."""
68 method.set_property = prop.name
69 prop.setter = method.name
70 continue
71- if getter is not [] and method.name in getter:
72+ if getter is not {} and method.name in getter:
73 if method.get_property is None:
74 method.get_property = prop.name
75 elif method.get_property != prop.name:
76@@ -1654,7 +1657,12 @@ method or constructor of some type."""
77 "mismatched '(get-property %s)' annotation" %
78 (method.symbol, prop.name, method.get_property))
79 method.get_property = prop.name
80- prop.getter = method.name
81+ # Check the priority of the last matching getter
82+ current_priority = -1
83+ if current_getter := prop.getter:
84+ current_priority = getter.get(current_getter, -1)
85+ if getter[method.name] >= current_priority:
86+ prop.getter = method.name
87 continue
88
89 def _pass_member_numeric_name(self, node):
90--
912.48.1
92