Release 0.41.92
[vala-gnome.git] / libvaladoc / ctyperesolver.vala
blobe6444e0aefeee2b0d78432716dff35e043c51767
1 /* ctyperesolver.vala
3 * Copyright (C) 2010 Florian Brosch
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 * Author:
20 * Florian Brosch <flo.brosch@gmail.com>
24 using Valadoc.Api;
26 /**
27 * Resolves symbols by C-names
29 public class Valadoc.CTypeResolver : Visitor {
30 private Vala.Map<string, Api.TypeSymbol> types = new Vala.HashMap<string, Api.TypeSymbol> (str_hash, str_equal);
31 private Vala.Map<string, Api.Node> nodes = new Vala.HashMap<string, Api.Node> (str_hash, str_equal);
32 private Api.Tree tree;
34 public CTypeResolver (Api.Tree tree) {
35 tree.accept (this);
36 this.tree = tree;
39 private string convert_array_to_camelcase (string[] elements) {
40 StringBuilder builder = new StringBuilder ();
42 foreach (string element in elements) {
43 builder.append_c (((char[])element)[0].toupper ());
44 builder.append (element.next_char ().down ());
47 return (owned) builder.str;
50 private bool is_capitalized_and_underscored (string name) {
51 unowned string pos;
53 unichar c = name.get_char ();
56 if (c < 'A' || c > 'Z') {
57 return false;
60 bool last_was_underscore = false;
61 for (c = (pos = name).get_char (); c != '\0' ; c = (pos = pos.next_char ()).get_char ()) {
62 if ((c != '_' && !(c >= 'A' && c <= 'Z')) || (last_was_underscore && c == '_')) {
63 return false;
66 last_was_underscore = (c == '_');
69 return !last_was_underscore;
72 private string? translate_cname_to_g (string name) {
73 if (is_capitalized_and_underscored (name)) {
74 string[] segments = name.split ("_");
75 unowned string last_segment = segments[segments.length - 1];
76 if (last_segment != "ERROR") {
77 return null;
80 return convert_array_to_camelcase (segments);
83 int length = name.length;
84 if (length > 5 && name.has_suffix ("Iface")) {
85 return name.substring (0, length - 5);
86 } else if (length > 5 && name.has_suffix ("Class")) {
87 return name.substring (0, length - 5);
90 return null;
93 public Api.TypeSymbol? resolve_symbol_type (string name) {
94 TypeSymbol? symbol = types.get (name);
95 if (symbol != null) {
96 return symbol;
99 if (is_capitalized_and_underscored (name)) {
100 string[] segments = name.split ("_");
102 if (segments[segments.length - 1] == "TYPE") {
103 segments.resize (segments.length - 1);
104 return types.get (convert_array_to_camelcase (segments));
105 } else if (segments.length > 2 && segments[1] == "TYPE") {
106 string[] _segments = segments[1:segments.length];
107 _segments[0] = segments[0];
108 return types.get (convert_array_to_camelcase (_segments));
112 return null;
116 * Resolves symbols by C-names
118 * @param _name a C-name
119 * @return the resolved node or null
121 public Api.Node? resolve_symbol (Api.Node? element, string _name) {
122 string name = _name.replace ("->", ".").replace ("-", "_");
124 if (element != null && name.has_prefix (":")) {
125 Item parent = element;
126 while (parent != null && !(parent is Class || parent is Interface)) {
127 parent = parent.parent;
130 if (parent is Class && ((Class) parent).get_cname () != null) {
131 name = ((Class) parent).get_cname () + name;
132 } else if (parent is Interface && ((Interface) parent).get_cname () != null) {
133 name = ((Interface) parent).get_cname () + name;
134 } else {
135 return null;
140 Api.Node? node = nodes.get (name);
141 if (node != null) {
142 return node;
145 string? alternative = translate_cname_to_g (name);
146 if (alternative != null) {
147 return nodes.get (alternative);
150 if (element != null && name.has_prefix (":")) {
151 if (element is Class && ((Class) element).get_cname () != null) {
152 return nodes.get (((Class) element).get_cname () + "." + name);
153 } else if (element is Struct && ((Struct) element).get_cname () != null) {
154 return nodes.get (((Struct) element).get_cname () + "." + name);
158 if (name == "dgettext") {
159 return nodes.get ("g_dgettext");
160 } else if (name == "printf") {
161 return this.tree.search_symbol_str (null, "GLib.FileStream.printf");
164 int dotpos = name.index_of_char ('.');
165 if (dotpos > 0) {
166 string fst = name.substring (0, dotpos);
167 string snd = name.substring (dotpos + 1);
168 return nodes.get (fst + ":" + snd);
171 return null;
174 private void register_symbol_type (string? name, Api.TypeSymbol symbol) {
175 if (name != null) {
176 types.set (name, symbol);
180 private void register_symbol (string? name, Api.Node node) {
181 if (name != null) {
182 nodes.set (name.replace ("-", "_"), node);
186 private string? get_parent_type_cname (Item item) {
187 string parent_cname = null;
188 if (item.parent is Class) {
189 parent_cname = ((Class) item.parent).get_cname ();
190 } else if (item.parent is Interface) {
191 parent_cname = ((Interface) item.parent).get_cname ();
192 } else if (item.parent is Struct) {
193 parent_cname = ((Struct) item.parent).get_cname ();
194 } else if (item.parent is ErrorDomain) {
195 parent_cname = ((ErrorDomain) item.parent).get_cname ();
196 } else if (item.parent is Api.Enum) {
197 parent_cname = ((Api.Enum) item.parent).get_cname ();
198 } else {
199 assert (true);
201 return parent_cname;
205 * {@inheritDoc}
207 public override void visit_tree (Api.Tree item) {
208 item.accept_children (this);
212 * {@inheritDoc}
214 public override void visit_package (Package item) {
215 item.accept_all_children (this, false);
219 * {@inheritDoc}
221 public override void visit_namespace (Namespace item) {
222 item.accept_all_children (this, false);
226 * {@inheritDoc}
228 public override void visit_interface (Interface item) {
229 register_symbol (item.get_cname (), item);
230 item.accept_all_children (this, false);
234 * {@inheritDoc}
236 public override void visit_class (Class item) {
237 register_symbol_type (item.get_type_id (), item);
238 register_symbol (item.get_cname (), item);
239 item.accept_all_children (this, false);
243 * {@inheritDoc}
245 public override void visit_struct (Struct item) {
246 register_symbol_type (item.get_type_id (), item);
247 register_symbol (item.get_cname (), item);
248 item.accept_all_children (this, false);
252 * {@inheritDoc}
254 public override void visit_property (Property item) {
255 string parent_cname = get_parent_type_cname (item);
256 assert (parent_cname != null);
258 string cname = item.get_cname ();
259 register_symbol (parent_cname+":"+cname, item);
262 Vala.Collection<Interface> interfaces;
263 Vala.Collection<Class> classes;
265 if (item.parent is Interface) {
266 interfaces = ((Api.Interface) item.parent).get_known_related_interfaces ();
267 classes = ((Api.Interface) item.parent).get_known_implementations ();
268 } else if (item.parent is Class) {
269 interfaces = ((Api.Class) item.parent).get_known_derived_interfaces ();
270 classes = ((Api.Class) item.parent).get_known_child_classes ();
271 } else if (item.parent is Struct) {
272 // Properties are allowed here, similar to compact classes
273 return;
274 } else {
275 assert_not_reached ();
278 foreach (Interface iface in interfaces) {
279 register_symbol (iface.get_cname () + ":" + cname, item);
282 foreach (Class cl in classes) {
283 register_symbol (cl.get_cname () + ":" + cname, item);
288 * {@inheritDoc}
290 public override void visit_field (Field item) {
291 if (item.parent is Namespace || item.is_static) {
292 register_symbol (item.get_cname (), item);
293 } else {
294 string parent_cname = get_parent_type_cname (item);
295 if (parent_cname != null) {
296 register_symbol (parent_cname + "." + item.get_cname (), item);
302 * {@inheritDoc}
304 public override void visit_constant (Constant item) {
305 register_symbol (item.get_cname (), item);
309 * {@inheritDoc}
311 public override void visit_delegate (Delegate item) {
312 register_symbol (item.get_cname (), item);
316 * {@inheritDoc}
318 public override void visit_signal (Api.Signal item) {
319 string parent_cname = get_parent_type_cname (item);
320 assert (parent_cname != null);
322 string? default_impl_cname = item.get_default_impl_cname ();
323 string cname = item.get_cname ();
324 register_symbol (parent_cname+"::"+cname, item);
326 if (item.is_virtual) {
327 // only supported by classes
328 register_symbol (parent_cname + "Class." + item.name, item);
331 Vala.Collection<Interface> interfaces = null;
332 Vala.Collection<Class> classes = null;
334 if (item.parent is Interface) {
335 interfaces = ((Api.Interface) item.parent).get_known_related_interfaces ();
336 classes = ((Api.Interface) item.parent).get_known_implementations ();
337 } else if (item.parent is Class) {
338 interfaces = ((Api.Class) item.parent).get_known_derived_interfaces ();
339 classes = ((Api.Class) item.parent).get_known_child_classes ();
342 foreach (Interface iface in interfaces) {
343 register_symbol (iface.get_cname () + "::" + cname, item);
346 foreach (Class cl in classes) {
347 register_symbol (cl.get_cname () + "::" + cname, item);
350 if (default_impl_cname != null) {
351 register_symbol (default_impl_cname, item);
356 * {@inheritDoc}
358 public override void visit_method (Method item) {
359 if (item.is_abstract || item.is_virtual || item.is_override) {
360 string parent_cname = get_parent_type_cname (item);
362 if (item.parent is Class) {
363 register_symbol (parent_cname + "Class." + item.name, item);
364 } else {
365 register_symbol (parent_cname + "Iface." + item.name, item);
368 // Allow to resolve invalid links:
369 register_symbol (parent_cname + "." + item.name, item);
372 register_symbol (item.get_cname (), item);
376 * {@inheritDoc}
378 public override void visit_error_domain (ErrorDomain item) {
379 register_symbol (item.get_cname (), item);
380 item.accept_all_children (this, false);
384 * {@inheritDoc}
386 public override void visit_error_code (ErrorCode item) {
387 register_symbol (item.get_cname (), item);
391 * {@inheritDoc}
393 public override void visit_enum (Api.Enum item) {
394 register_symbol (item.get_cname (), item);
395 item.accept_all_children (this, false);
399 * {@inheritDoc}
401 public override void visit_enum_value (Api.EnumValue item) {
402 register_symbol (item.get_cname (), item);