Do not free values returned via g_object_get prematurely, require
[vala-lang.git] / vala / valainterface.vala
blob1b5be99a0dbb5fc3aa8a13999b58bb61749397bd
1 /* valainterface.vala
3 * Copyright (C) 2006-2008 Jürg Billeter
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 * Jürg Billeter <j@bitron.ch>
23 using GLib;
24 using Gee;
26 /**
27 * Represents a class declaration in the source code.
29 public class Vala.Interface : ObjectTypeSymbol {
30 private Gee.List<DataType> prerequisites = new ArrayList<DataType> ();
32 private Gee.List<Method> methods = new ArrayList<Method> ();
33 private Gee.List<Field> fields = new ArrayList<Field> ();
34 private Gee.List<Property> properties = new ArrayList<Property> ();
35 private Gee.List<Signal> signals = new ArrayList<Signal> ();
37 // inner types
38 private Gee.List<Class> classes = new ArrayList<Class> ();
39 private Gee.List<Struct> structs = new ArrayList<Struct> ();
40 private Gee.List<Enum> enums = new ArrayList<Enum> ();
41 private Gee.List<Delegate> delegates = new ArrayList<Delegate> ();
43 private string cname;
44 private string lower_case_csuffix;
45 private string type_cname;
46 private string type_id;
48 /**
49 * Returns a copy of the list of classes.
51 * @return list of classes
53 public Gee.List<Class> get_classes () {
54 return new ReadOnlyList<Class> (classes);
57 /**
58 * Returns a copy of the list of structs.
60 * @return list of structs
62 public Gee.List<Struct> get_structs () {
63 return new ReadOnlyList<Struct> (structs);
66 /**
67 * Returns a copy of the list of enums.
69 * @return list of enums
71 public Gee.List<Enum> get_enums () {
72 return new ReadOnlyList<Enum> (enums);
75 /**
76 * Returns a copy of the list of delegates.
78 * @return list of delegates
80 public Gee.List<Delegate> get_delegates () {
81 return new ReadOnlyList<Delegate> (delegates);
84 /**
85 * Creates a new interface.
87 * @param name type name
88 * @param source reference to source code
89 * @return newly created interface
91 public Interface (string name, SourceReference? source_reference = null) {
92 base (name, source_reference);
95 /**
96 * Adds the specified interface or class to the list of prerequisites of
97 * this interface.
99 * @param type an interface or class reference
101 public void add_prerequisite (DataType type) {
102 prerequisites.add (type);
103 type.parent_node = this;
107 * Prepends the specified interface or class to the list of
108 * prerequisites of this interface.
110 * @param type an interface or class reference
112 public void prepend_prerequisite (DataType type) {
113 prerequisites.insert (0, type);
117 * Returns a copy of the base type list.
119 * @return list of base types
121 public Gee.List<DataType> get_prerequisites () {
122 return new ReadOnlyList<DataType> (prerequisites);
126 * Adds the specified method as a member to this interface.
128 * @param m a method
130 public void add_method (Method m) {
131 if (m is CreationMethod) {
132 Report.error (m.source_reference, "construction methods may only be declared within classes and structs");
134 m.error = true;
135 return;
137 if (m.binding == MemberBinding.INSTANCE) {
138 m.this_parameter = new FormalParameter ("this", new ObjectType (this));
139 m.scope.add (m.this_parameter.name, m.this_parameter);
141 if (!(m.return_type is VoidType) && m.get_postconditions ().size > 0) {
142 m.result_var = new LocalVariable (m.return_type.copy (), "result");
143 m.scope.add (m.result_var.name, m.result_var);
146 methods.add (m);
147 scope.add (m.name, m);
151 * Returns a copy of the list of methods.
153 * @return list of methods
155 public override Gee.List<Method> get_methods () {
156 return new ReadOnlyList<Method> (methods);
160 * Adds the specified field as a member to this interface. The field
161 * must be private and static.
163 * @param f a field
165 public void add_field (Field f) {
166 fields.add (f);
167 scope.add (f.name, f);
171 * Returns a copy of the list of fields.
173 * @return list of fields
175 public Gee.List<Field> get_fields () {
176 return new ReadOnlyList<Field> (fields);
180 * Adds the specified property as a member to this interface.
182 * @param prop a property
184 public void add_property (Property prop) {
185 properties.add (prop);
186 scope.add (prop.name, prop);
188 prop.this_parameter = new FormalParameter ("this", new ObjectType (this));
189 prop.scope.add (prop.this_parameter.name, prop.this_parameter);
193 * Returns a copy of the list of properties.
195 * @return list of properties
197 public override Gee.List<Property> get_properties () {
198 return new ReadOnlyList<Property> (properties);
202 * Adds the specified signal as a member to this interface.
204 * @param sig a signal
206 public void add_signal (Signal sig) {
207 signals.add (sig);
208 scope.add (sig.name, sig);
212 * Returns a copy of the list of signals.
214 * @return list of signals
216 public override Gee.List<Signal> get_signals () {
217 return new ReadOnlyList<Signal> (signals);
221 * Adds the specified class as an inner class.
223 * @param cl a class
225 public void add_class (Class cl) {
226 classes.add (cl);
227 scope.add (cl.name, cl);
231 * Adds the specified struct as an inner struct.
233 * @param st a struct
235 public void add_struct (Struct st) {
236 structs.add (st);
237 scope.add (st.name, st);
241 * Adds the specified enum as an inner enum.
243 * @param en an enum
245 public void add_enum (Enum en) {
246 enums.add (en);
247 scope.add (en.name, en);
251 * Adds the specified delegate as an inner delegate.
253 * @param d a delegate
255 public void add_delegate (Delegate d) {
256 delegates.add (d);
257 scope.add (d.name, d);
260 public override string get_cname (bool const_type = false) {
261 if (cname == null) {
262 cname = "%s%s".printf (parent_symbol.get_cprefix (), name);
264 return cname;
268 * Returns the string to be prepended to the name of members of this
269 * interface when used in C code.
271 * @return the suffix to be used in C code
273 public string get_lower_case_csuffix () {
274 if (lower_case_csuffix == null) {
275 lower_case_csuffix = get_default_lower_case_csuffix ();
277 return lower_case_csuffix;
281 * Returns default string to be prepended to the name of members of this
282 * interface when used in C code.
284 * @return the suffix to be used in C code
286 public string get_default_lower_case_csuffix () {
287 string result = camel_case_to_lower_case (name);
289 // remove underscores in some cases to avoid conflicts of type macros
290 if (result.has_prefix ("type_")) {
291 result = "type" + result.offset ("type_".len ());
292 } else if (result.has_prefix ("is_")) {
293 result = "is" + result.offset ("is_".len ());
295 if (result.has_suffix ("_class")) {
296 result = result.substring (0, result.len () - "_class".len ()) + "class";
299 return result;
303 * Sets the string to be prepended to the name of members of this
304 * interface when used in C code.
306 * @param csuffix the suffix to be used in C code
308 public void set_lower_case_csuffix (string csuffix) {
309 this.lower_case_csuffix = csuffix;
312 public override string? get_lower_case_cname (string? infix) {
313 if (infix == null) {
314 infix = "";
316 return "%s%s%s".printf (parent_symbol.get_lower_case_cprefix (), infix, get_lower_case_csuffix ());
319 public override string get_lower_case_cprefix () {
320 return "%s_".printf (get_lower_case_cname (null));
323 public override string? get_upper_case_cname (string? infix) {
324 return get_lower_case_cname (infix).up ();
327 public override void accept (CodeVisitor visitor) {
328 visitor.visit_interface (this);
331 public override void accept_children (CodeVisitor visitor) {
332 foreach (DataType type in prerequisites) {
333 type.accept (visitor);
336 foreach (TypeParameter p in get_type_parameters ()) {
337 p.accept (visitor);
340 /* process enums first to avoid order problems in C code */
341 foreach (Enum en in enums) {
342 en.accept (visitor);
345 foreach (Method m in methods) {
346 m.accept (visitor);
349 foreach (Field f in fields) {
350 f.accept (visitor);
353 foreach (Property prop in properties) {
354 prop.accept (visitor);
357 foreach (Signal sig in signals) {
358 sig.accept (visitor);
361 foreach (Class cl in classes) {
362 cl.accept (visitor);
365 foreach (Struct st in structs) {
366 st.accept (visitor);
369 foreach (Delegate d in delegates) {
370 d.accept (visitor);
374 public override bool is_reference_type () {
375 return true;
378 public override bool is_reference_counting () {
379 return true;
382 public override string? get_ref_function () {
383 foreach (DataType prerequisite in prerequisites) {
384 string ref_func = prerequisite.data_type.get_ref_function ();
385 if (ref_func != null) {
386 return ref_func;
389 return null;
392 public override string? get_unref_function () {
393 foreach (DataType prerequisite in prerequisites) {
394 string unref_func = prerequisite.data_type.get_unref_function ();
395 if (unref_func != null) {
396 return unref_func;
399 return null;
402 public override bool is_subtype_of (TypeSymbol t) {
403 if (this == t) {
404 return true;
407 foreach (DataType prerequisite in prerequisites) {
408 if (prerequisite.data_type != null && prerequisite.data_type.is_subtype_of (t)) {
409 return true;
413 return false;
416 private void process_ccode_attribute (Attribute a) {
417 if (a.has_argument ("type_cname")) {
418 set_type_cname (a.get_string ("type_cname"));
420 if (a.has_argument ("cheader_filename")) {
421 var val = a.get_string ("cheader_filename");
422 foreach (string filename in val.split (",")) {
423 add_cheader_filename (filename);
426 if (a.has_argument ("lower_case_csuffix")) {
427 lower_case_csuffix = a.get_string ("lower_case_csuffix");
432 * Process all associated attributes.
434 public void process_attributes () {
435 foreach (Attribute a in attributes) {
436 if (a.name == "CCode") {
437 process_ccode_attribute (a);
443 * Returns the name of the type struct as it is used in C code.
445 * @return the type struct name to be used in C code
447 public string get_type_cname () {
448 if (type_cname == null) {
449 type_cname = "%sIface".printf (get_cname ());
451 return type_cname;
455 * Sets the name of the type struct as it is used in C code.
457 * @param type_cname the type struct name to be used in C code
459 public void set_type_cname (string type_cname) {
460 this.type_cname = type_cname;
463 public override string? get_marshaller_type_name () {
464 return "OBJECT";
467 public override string? get_get_value_function () {
468 return "g_value_get_object";
471 public override string? get_set_value_function () {
472 return "g_value_set_object";
475 public override string? get_type_id () {
476 if (type_id == null) {
477 type_id = get_upper_case_cname ("TYPE_");
480 return type_id;
483 public override void replace_type (DataType old_type, DataType new_type) {
484 for (int i = 0; i < prerequisites.size; i++) {
485 if (prerequisites[i] == old_type) {
486 prerequisites[i] = new_type;
487 return;
492 public override string? get_param_spec_function () {
493 foreach (DataType prerequisite in prerequisites) {
494 var prereq = prerequisite as ObjectType;
495 var cl = prereq.type_symbol as Class;
496 if (cl != null) {
497 return cl.get_param_spec_function ();
499 var interf = prereq.type_symbol as Interface;
500 if (interf != null) {
501 var param_spec_function = interf.get_param_spec_function ();
502 if (param_spec_function != null) {
503 return param_spec_function;
508 return null;
511 public override bool check (SemanticAnalyzer analyzer) {
512 if (checked) {
513 return !error;
516 checked = true;
518 process_attributes ();
520 var old_source_file = analyzer.current_source_file;
521 var old_symbol = analyzer.current_symbol;
523 if (source_reference != null) {
524 analyzer.current_source_file = source_reference.file;
526 analyzer.current_symbol = this;
528 foreach (DataType prerequisite_reference in get_prerequisites ()) {
529 // check whether prerequisite is at least as accessible as the interface
530 if (!analyzer.is_type_accessible (this, prerequisite_reference)) {
531 error = true;
532 Report.error (source_reference, "prerequisite `%s` is less accessible than interface `%s`".printf (prerequisite_reference.to_string (), get_full_name ()));
533 return false;
536 analyzer.current_source_file.add_type_dependency (prerequisite_reference, SourceFileDependencyType.HEADER_FULL);
539 /* check prerequisites */
540 Class prereq_class = null;
541 foreach (DataType prereq in get_prerequisites ()) {
542 TypeSymbol class_or_interface = prereq.data_type;
543 /* skip on previous errors */
544 if (class_or_interface == null) {
545 error = true;
546 continue;
549 if (!(class_or_interface is ObjectTypeSymbol)) {
550 error = true;
551 Report.error (source_reference, "Prerequisite `%s` of interface `%s` is not a class or interface".printf (get_full_name (), class_or_interface.to_string ()));
552 return false;
555 /* interfaces are not allowed to have multiple instantiable prerequisites */
556 if (class_or_interface is Class) {
557 if (prereq_class != null) {
558 error = true;
559 Report.error (source_reference, "%s: Interfaces cannot have multiple instantiable prerequisites (`%s' and `%s')".printf (get_full_name (), class_or_interface.get_full_name (), prereq_class.get_full_name ()));
560 return false;
563 prereq_class = (Class) class_or_interface;
567 foreach (DataType type in prerequisites) {
568 type.check (analyzer);
571 foreach (TypeParameter p in get_type_parameters ()) {
572 p.check (analyzer);
575 foreach (Enum en in enums) {
576 en.check (analyzer);
579 foreach (Method m in methods) {
580 m.check (analyzer);
583 foreach (Field f in fields) {
584 f.check (analyzer);
587 foreach (Property prop in properties) {
588 prop.check (analyzer);
591 foreach (Signal sig in signals) {
592 sig.check (analyzer);
595 foreach (Class cl in classes) {
596 cl.check (analyzer);
599 foreach (Struct st in structs) {
600 st.check (analyzer);
603 foreach (Delegate d in delegates) {
604 d.check (analyzer);
607 analyzer.current_source_file = old_source_file;
608 analyzer.current_symbol = old_symbol;
610 return !error;