vala: Report error for error-domains without any code
[vala-gnome.git] / valadoc / treebuilder.vala
blob0b81481c0491b9a821d9767b258da368a5d6b157
1 /* treebuilder.vala
3 * Copyright (C) 2011 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 * Creates an simpler, minimized, more abstract AST for valacs AST.
29 public class Valadoc.Drivers.TreeBuilder : Vala.CodeVisitor {
30 private Vala.ArrayList<PackageMetaData> packages = new Vala.ArrayList<PackageMetaData> ();
31 private PackageMetaData source_package;
33 private Vala.HashMap<Vala.SourceFile, SourceFile> files = new Vala.HashMap<Vala.SourceFile, SourceFile> ();
34 private Vala.HashMap<Vala.Symbol, Symbol> symbol_map = new Vala.HashMap<Vala.Symbol, Symbol> ();
36 private ErrorReporter reporter;
37 private Settings settings;
39 private Api.Node current_node;
40 private Api.Tree tree;
42 private Valadoc.Api.Class glib_error = null;
46 // Accessors
49 public Api.Class get_glib_error () {
50 return glib_error;
53 public Vala.HashMap<Vala.Symbol, Symbol> get_symbol_map () {
54 return symbol_map;
62 private class PackageMetaData {
63 public Package package;
64 public Vala.HashMap<Vala.Namespace, Namespace> namespaces = new Vala.HashMap<Vala.Namespace, Namespace> ();
65 public Vala.ArrayList<Vala.SourceFile> files = new Vala.ArrayList<Vala.SourceFile> ();
67 public PackageMetaData (Package package) {
68 this.package = package;
71 public Namespace get_namespace (Vala.Namespace vns, SourceFile file) {
72 Namespace? ns = namespaces.get (vns);
73 if (ns != null) {
74 return ns;
77 // find documentation comment if existing:
78 SourceComment? comment = null;
79 if (vns.source_reference != null) {
80 foreach (Vala.Comment c in vns.get_comments()) {
81 if (c.source_reference.file == file.data ||
82 (c.source_reference.file.file_type == Vala.SourceFileType.SOURCE
83 && ((Vala.SourceFile) file.data).file_type == Vala.SourceFileType.SOURCE)
84 ) {
85 Vala.SourceReference pos = c.source_reference;
86 if (c is Vala.GirComment) {
87 comment = new GirSourceComment (c.content,
88 file,
89 pos.begin.line,
90 pos.begin.column,
91 pos.end.line,
92 pos.end.column);
93 } else {
94 comment = new SourceComment (c.content,
95 file,
96 pos.begin.line,
97 pos.begin.column,
98 pos.end.line,
99 pos.end.column);
101 break;
106 // find parent if existing
107 var parent_vns = vns.parent_symbol;
109 if (parent_vns == null) {
110 ns = new Namespace (package, file, vns.name, comment, vns);
111 package.add_child (ns);
112 } else {
113 Namespace parent_ns = get_namespace ((Vala.Namespace) parent_vns, file);
114 ns = new Namespace (parent_ns, file, vns.name, comment, vns);
115 parent_ns.add_child (ns);
118 namespaces.set (vns, ns);
119 return ns;
122 public void register_source_file (Vala.SourceFile file) {
123 files.add (file);
126 public bool is_package_for_file (Vala.SourceFile source_file) {
127 if (source_file.file_type == Vala.SourceFileType.SOURCE && !package.is_package) {
128 return true;
131 return files.contains (source_file);
137 // Type constructor translation helpers:
140 private Pointer create_pointer (Vala.PointerType vtyperef, Item parent, Api.Node caller) {
141 Pointer ptr = new Pointer (parent, vtyperef);
143 Vala.DataType vntype = vtyperef.base_type;
144 if (vntype is Vala.PointerType) {
145 ptr.data_type = create_pointer ((Vala.PointerType) vntype, ptr, caller);
146 } else if (vntype is Vala.ArrayType) {
147 ptr.data_type = create_array ((Vala.ArrayType) vntype, ptr, caller);
148 } else {
149 ptr.data_type = create_type_reference (vntype, ptr, caller);
152 return ptr;
155 private Api.Array create_array (Vala.ArrayType vtyperef, Item parent, Api.Node caller) {
156 Api.Array arr = new Api.Array (parent, vtyperef);
158 Vala.DataType vntype = vtyperef.element_type;
159 if (vntype is Vala.ArrayType) {
160 arr.data_type = create_array ((Vala.ArrayType) vntype, arr, caller);
161 } else {
162 arr.data_type = create_type_reference (vntype, arr, caller);
165 return arr;
168 private TypeReference create_type_reference (Vala.DataType? vtyperef, Item parent, Api.Node caller) {
169 bool is_nullable = vtyperef != null
170 && vtyperef.nullable
171 && !(vtyperef is Vala.GenericType)
172 && !(vtyperef is Vala.PointerType);
173 string? signature = (vtyperef != null
174 && vtyperef.data_type != null)? Vala.GVariantModule.get_dbus_signature (vtyperef.data_type) : null;
175 bool pass_ownership = type_reference_pass_ownership (vtyperef);
176 Ownership ownership = get_type_reference_ownership (vtyperef);
177 bool is_dynamic = vtyperef != null && vtyperef.is_dynamic;
179 TypeReference type_ref = new TypeReference (parent,
180 ownership,
181 pass_ownership,
182 is_dynamic,
183 is_nullable,
184 signature,
185 vtyperef);
187 if (vtyperef is Vala.PointerType) {
188 type_ref.data_type = create_pointer ((Vala.PointerType) vtyperef, type_ref, caller);
189 } else if (vtyperef is Vala.ArrayType) {
190 type_ref.data_type = create_array ((Vala.ArrayType) vtyperef, type_ref, caller);
191 //} else if (vtyperef is Vala.GenericType) {
192 // type_ref.data_type = new TypeParameter (caller,
193 // caller.get_source_file (),
194 // ((Vala.GenericType) vtyperef).type_parameter.name,
195 // vtyperef);
198 // type parameters:
199 if (vtyperef != null) {
200 foreach (Vala.DataType vdtype in vtyperef.get_type_arguments ()) {
201 var type_param = create_type_reference (vdtype, type_ref, caller);
202 type_ref.add_type_argument (type_param);
206 return type_ref;
212 // Translation helpers:
215 private void process_attributes (Api.Symbol parent, GLib.List<Vala.Attribute> lst) {
216 // attributes without arguments:
217 string[] attributes = {
218 "ReturnsModifiedPointer",
219 "DestroysInstance",
220 "GenericAccessors",
221 "NoAccessorMethod",
222 "NoArrayLength",
223 "Experimental",
224 "Diagnostics",
225 "PrintfFormat",
226 "PointerType",
227 "ScanfFormat",
228 "ThreadLocal",
229 "SimpleType",
230 "HasEmitter",
231 "ModuleInit",
232 "NoWrapper",
233 "Immutable",
234 "ErrorBase",
235 "NoReturn",
236 "NoThrow",
237 "Compact",
238 "Assert",
239 "Flags"
242 string? tmp = "";
244 foreach (Vala.Attribute att in lst) {
245 if (att.name == "CCode" && (tmp = att.args.get ("has_target")) != null && tmp == "false") {
246 Attribute new_attribute = new Attribute (parent, parent.get_source_file (), att.name, att);
247 new_attribute.add_boolean ("has_target", false, att);
248 parent.add_attribute (new_attribute);
249 } else if (att.name == "Version") {
250 Attribute new_attribute = new Attribute (parent, parent.get_source_file (), att.name, att);
251 if ((tmp = att.args.get ("deprecated")) != null) {
252 new_attribute.add_boolean ("deprecated", bool.parse (tmp), att);
254 if ((tmp = att.args.get ("since")) != null) {
255 new_attribute.add_string ("since", tmp, att);
257 if ((tmp = att.args.get ("deprecated_since")) != null) {
258 new_attribute.add_string ("deprecated_since", tmp, att);
259 if (att.args.get ("deprecated") == null) {
260 new_attribute.add_boolean ("deprecated", true, att);
263 if ((tmp = att.args.get ("replacement")) != null) {
264 new_attribute.add_string ("replacement", tmp, att);
266 parent.add_attribute (new_attribute);
267 } else if (att.name == "Deprecated") {
268 Attribute new_attribute = new Attribute (parent, parent.get_source_file (), att.name, att);
269 if ((tmp = att.args.get ("since")) != null) {
270 new_attribute.add_string ("since", tmp, att);
272 if ((tmp = att.args.get ("replacement")) != null) {
273 new_attribute.add_string ("replacement", tmp, att);
275 parent.add_attribute (new_attribute);
276 } else if (att.name in attributes) {
277 Attribute new_attribute = new Attribute (parent, parent.get_source_file (), att.name, att);
278 parent.add_attribute (new_attribute);
283 private string? get_ccode_type_id (Vala.CodeNode node) {
284 return Vala.get_ccode_type_id (node);
287 private bool is_reference_counting (Vala.TypeSymbol sym) {
288 return Vala.is_reference_counting (sym);
291 private string? get_ref_function (Vala.Class sym) {
292 return Vala.get_ccode_ref_function (sym);
295 private string? get_unref_function (Vala.Class sym) {
296 return Vala.get_ccode_unref_function (sym);
299 private string? get_finalize_function_name (Vala.Class element) {
300 if (!element.is_fundamental ()) {
301 return null;
304 return "%s_finalize".printf (Vala.get_ccode_lower_case_name (element, null));
307 private string? get_free_function_name (Vala.Class element) {
308 if (!element.is_compact) {
309 return null;
312 return Vala.get_ccode_free_function (element);
315 private string? get_finish_name (Vala.Method m) {
316 return Vala.get_ccode_finish_name (m);
319 private string? get_take_value_function (Vala.Class sym) {
320 return Vala.get_ccode_take_value_function (sym);
323 private string? get_get_value_function (Vala.Class sym) {
324 return Vala.get_ccode_get_value_function (sym);
327 private string? get_set_value_function (Vala.Class sym) {
328 return Vala.get_ccode_set_value_function (sym);
332 private string? get_param_spec_function (Vala.CodeNode sym) {
333 return Vala.get_ccode_param_spec_function (sym);
336 private string? get_dup_function (Vala.TypeSymbol sym) {
337 return Vala.get_ccode_dup_function (sym);
340 private string? get_copy_function (Vala.TypeSymbol sym) {
341 return Vala.get_ccode_copy_function (sym);
344 private string? get_destroy_function (Vala.TypeSymbol sym) {
345 return Vala.get_ccode_destroy_function (sym);
348 private string? get_free_function (Vala.TypeSymbol sym) {
349 return Vala.get_ccode_free_function (sym);
352 private string? get_cname (Vala.Symbol symbol) {
353 return Vala.get_ccode_name (symbol);
356 private SourceComment? create_comment (Vala.Comment? comment) {
357 if (comment != null) {
358 Vala.SourceReference pos = comment.source_reference;
359 SourceFile file = files.get (pos.file);
360 if (comment is Vala.GirComment) {
361 var tmp = new GirSourceComment (comment.content,
362 file,
363 pos.begin.line,
364 pos.begin.column,
365 pos.end.line,
366 pos.end.column);
367 if (((Vala.GirComment) comment).return_content != null) {
368 Vala.SourceReference return_pos = ((Vala.GirComment) comment).return_content.source_reference;
369 tmp.return_comment = new SourceComment (((Vala.GirComment) comment).return_content.content,
370 file,
371 return_pos.begin.line,
372 return_pos.begin.column,
373 return_pos.end.line,
374 return_pos.end.column);
377 Vala.MapIterator<string, Vala.Comment> it = ((Vala.GirComment) comment).parameter_iterator ();
378 while (it.next ()) {
379 Vala.Comment vala_param = it.get_value ();
380 Vala.SourceReference param_pos = vala_param.source_reference;
381 var param_comment = new SourceComment (vala_param.content,
382 file,
383 param_pos.begin.line,
384 param_pos.begin.column,
385 param_pos.end.line,
386 param_pos.end.column);
387 tmp.add_parameter_content (it.get_key (), param_comment);
389 return tmp;
390 } else {
391 return new SourceComment (comment.content,
392 file,
393 pos.begin.line,
394 pos.begin.column,
395 pos.end.line,
396 pos.end.column);
400 return null;
403 private string get_method_name (Vala.Method element) {
404 if (element is Vala.CreationMethod) {
405 if (element.name == ".new") {
406 return element.parent_symbol.name;
407 } else {
408 return element.parent_symbol.name + "." + element.name;
412 return element.name;
415 private string? get_quark_macro_name (Vala.ErrorDomain element) {
416 return Vala.get_ccode_upper_case_name (element, null);
419 private string? get_private_cname (Vala.Class element) {
420 if (element.is_compact) {
421 return null;
424 string? cname = get_cname (element);
425 return (cname != null)? cname + "Private" : null;
428 private string? get_class_macro_name (Vala.Class element) {
429 if (element.is_compact) {
430 return null;
433 return "%s_GET_CLASS".printf (Vala.get_ccode_upper_case_name (element, null));
436 private string? get_class_type_macro_name (Vala.Class element) {
437 if (element.is_compact) {
438 return null;
441 return "%s_CLASS".printf (Vala.get_ccode_upper_case_name (element, null));
444 private string? get_is_type_macro_name (Vala.TypeSymbol element) {
445 string? name = Vala.get_ccode_type_check_function (element);
446 return (name != null && name != "")? name : null;
449 private string? get_is_class_type_macro_name (Vala.TypeSymbol element) {
450 string? name = get_is_type_macro_name (element);
451 return (name != null)? name + "_CLASS" : null;
454 private string? get_type_function_name (Vala.TypeSymbol element) {
455 if ((element is Vala.Class
456 && ((Vala.Class) element).is_compact)
457 || element is Vala.ErrorDomain
458 || element is Vala.Delegate)
460 return null;
463 return "%s_get_type".printf (Vala.get_ccode_lower_case_name (element, null));
466 private string? get_type_macro_name (Vala.TypeSymbol element) {
467 if ((element is Vala.Class
468 && ((Vala.Class) element).is_compact)
469 || element is Vala.ErrorDomain
470 || element is Vala.Delegate)
472 return null;
475 return Vala.get_ccode_type_id (element);
478 private string? get_type_cast_macro_name (Vala.TypeSymbol element) {
479 if ((element is Vala.Class
480 && !((Vala.Class) element).is_compact)
481 || element is Vala.Interface)
483 return Vala.get_ccode_upper_case_name (element, null);
484 } else {
485 return null;
489 private string? get_interface_macro_name (Vala.Interface element) {
490 return "%s_GET_INTERFACE".printf (Vala.get_ccode_upper_case_name (element, null));
493 private string get_quark_function_name (Vala.ErrorDomain element) {
494 return Vala.get_ccode_lower_case_prefix (element) + "quark";
497 private PackageMetaData? get_package_meta_data (Package pkg) {
498 foreach (PackageMetaData data in packages) {
499 if (data.package == pkg) {
500 return data;
504 return null;
507 private PackageMetaData register_package (Package package) {
508 PackageMetaData meta_data = new PackageMetaData (package);
509 tree.add_package (package);
510 packages.add (meta_data);
511 return meta_data;
514 private SourceFile register_source_file (PackageMetaData meta_data, Vala.SourceFile source_file) {
515 SourceFile file = new SourceFile (meta_data.package,
516 source_file.get_relative_filename (),
517 source_file.get_csource_filename (),
518 source_file);
519 files.set (source_file, file);
521 meta_data.register_source_file (source_file);
522 return file;
525 private SourceFile? get_source_file (Vala.Symbol symbol) {
526 Vala.SourceReference source_ref = symbol.source_reference;
527 if (source_ref == null) {
528 return null;
531 SourceFile? file = files.get (source_ref.file);
532 assert (file != null);
533 return file;
536 private Package? find_package_for_file (Vala.SourceFile source_file) {
537 foreach (PackageMetaData pkg in this.packages) {
538 if (pkg.is_package_for_file (source_file)) {
539 return pkg.package;
543 return null;
547 private Namespace get_namespace (Package pkg, Vala.Symbol symbol, SourceFile? file) {
548 // Find the closest namespace in our vala-tree
549 Vala.Symbol namespace_symbol = symbol;
550 while (!(namespace_symbol is Vala.Namespace)) {
551 namespace_symbol = namespace_symbol.parent_symbol;
554 PackageMetaData? meta_data = get_package_meta_data (pkg);
555 assert (meta_data != null);
557 return meta_data.get_namespace ((Vala.Namespace) namespace_symbol, file);
560 private MethodBindingType get_method_binding_type (Vala.Method element) {
561 if (element.is_inline) {
562 return MethodBindingType.INLINE;
563 } else if (element.is_abstract) {
564 return MethodBindingType.ABSTRACT;
565 } else if (element.is_virtual) {
566 return MethodBindingType.VIRTUAL;
567 } else if (element.overrides) {
568 return MethodBindingType.OVERRIDE;
569 } else if (element.is_inline) {
570 return MethodBindingType.INLINE;
571 } else if (element.binding != Vala.MemberBinding.INSTANCE) {
572 return MethodBindingType.STATIC;
574 return MethodBindingType.UNMODIFIED;
578 private SymbolAccessibility get_access_modifier(Vala.Symbol symbol) {
579 switch (symbol.access) {
580 case Vala.SymbolAccessibility.PROTECTED:
581 return SymbolAccessibility.PROTECTED;
583 case Vala.SymbolAccessibility.INTERNAL:
584 return SymbolAccessibility.INTERNAL;
586 case Vala.SymbolAccessibility.PRIVATE:
587 return SymbolAccessibility.PRIVATE;
589 case Vala.SymbolAccessibility.PUBLIC:
590 return SymbolAccessibility.PUBLIC;
592 default:
593 error ("Unknown symbol accessibility modifier found");
597 private PropertyAccessorType get_property_accessor_type (Vala.PropertyAccessor element) {
598 if (element.construction) {
599 if (element.writable) {
600 return (PropertyAccessorType.CONSTRUCT | PropertyAccessorType.SET);
602 return PropertyAccessorType.CONSTRUCT;
603 } else if (element.writable) {
604 return PropertyAccessorType.SET;
605 } else if (element.readable) {
606 return PropertyAccessorType.GET;
609 error ("Unknown symbol accessibility type");
612 private bool type_reference_pass_ownership (Vala.DataType? element) {
613 if (element == null) {
614 return false;
617 weak Vala.CodeNode? node = element.parent_node;
618 if (node == null) {
619 return false;
621 if (node is Vala.Parameter) {
622 return (((Vala.Parameter)node).direction == Vala.ParameterDirection.IN &&
623 ((Vala.Parameter)node).variable_type.value_owned);
625 if (node is Vala.Property) {
626 return ((Vala.Property)node).property_type.value_owned;
629 return false;
632 private bool is_type_reference_unowned (Vala.DataType? element) {
633 if (element == null) {
634 return false;
637 // non ref counted types are weak, not unowned
638 if (element.data_type is Vala.TypeSymbol
639 && is_reference_counting ((Vala.TypeSymbol) element.data_type) == true)
641 return false;
644 // FormalParameters are weak by default
645 return (element.parent_node is Vala.Parameter == false)
646 ? element.is_weak ()
647 : false;
650 private bool is_type_reference_owned (Vala.DataType? element) {
651 if (element == null) {
652 return false;
655 weak Vala.CodeNode parent = element.parent_node;
657 // parameter:
658 if (parent is Vala.Parameter) {
659 if (((Vala.Parameter)parent).direction != Vala.ParameterDirection.IN) {
660 return false;
662 return ((Vala.Parameter)parent).variable_type.value_owned;
665 return false;
668 private bool is_type_reference_weak (Vala.DataType? element) {
669 if (element == null) {
670 return false;
673 // non ref counted types are unowned, not weak
674 if (element.data_type is Vala.TypeSymbol
675 && is_reference_counting ((Vala.TypeSymbol) element.data_type) == false)
677 return false;
680 // arrays are unowned, not weak
681 if (element is Vala.ArrayType) {
682 return false;
685 // FormalParameters are weak by default
686 return (element.parent_node is Vala.Parameter == false)? element.is_weak () : false;
689 private Ownership get_type_reference_ownership (Vala.DataType? element) {
690 if (is_type_reference_owned (element)) {
691 return Ownership.OWNED;
692 } else if (is_type_reference_weak (element)) {
693 return Ownership.WEAK;
694 } else if (is_type_reference_unowned (element)) {
695 return Ownership.UNOWNED;
698 return Ownership.DEFAULT;
701 private Ownership get_property_ownership (Vala.PropertyAccessor element) {
702 if (element.value_type.value_owned) {
703 return Ownership.OWNED;
706 // the exact type (weak, unowned) does not matter
707 return Ownership.UNOWNED;
710 private PropertyBindingType get_property_binding_type (Vala.Property element) {
711 if (element.is_abstract) {
712 return PropertyBindingType.ABSTRACT;
713 } else if (element.is_virtual) {
714 return PropertyBindingType.VIRTUAL;
715 } else if (element.overrides) {
716 return PropertyBindingType.OVERRIDE;
719 return PropertyBindingType.UNMODIFIED;
722 private FormalParameterType get_formal_parameter_type (Vala.Parameter element) {
723 if (element.direction == Vala.ParameterDirection.OUT) {
724 return FormalParameterType.OUT;
725 } else if (element.direction == Vala.ParameterDirection.REF) {
726 return FormalParameterType.REF;
727 } else if (element.direction == Vala.ParameterDirection.IN) {
728 return FormalParameterType.IN;
731 error ("Unknown formal parameter type");
736 // Vala tree creation:
739 private string get_package_name (string path) {
740 string file_name = Path.get_basename (path);
741 return file_name.substring (0, file_name.last_index_of_char ('.'));
744 private bool add_package (Vala.CodeContext context, string pkg) {
745 // ignore multiple occurences of the same package
746 if (context.has_package (pkg)) {
747 return true;
750 string vapi_name = pkg + ".vapi";
751 string gir_name = pkg + ".gir";
752 foreach (string source_file in settings.source_files) {
753 string basename = Path.get_basename (source_file);
754 if (basename == vapi_name || basename == gir_name) {
755 return true;
760 var package_path = context.get_vapi_path (pkg) ?? context.get_gir_path (pkg);
761 if (package_path == null) {
762 Vala.Report.error (null, "Package `%s' not found in specified Vala API directories or GObject-Introspection GIR directories".printf (pkg));
763 return false;
766 context.add_package (pkg);
768 var vfile = new Vala.SourceFile (context, Vala.SourceFileType.PACKAGE, package_path);
769 context.add_source_file (vfile);
770 Package vdpkg = new Package (pkg, true, null);
771 register_source_file (register_package (vdpkg), vfile);
773 add_deps (context, Path.build_filename (Path.get_dirname (package_path), "%s.deps".printf (pkg)), pkg);
774 return true;
777 private void add_deps (Vala.CodeContext context, string file_path, string pkg_name) {
778 if (FileUtils.test (file_path, FileTest.EXISTS)) {
779 try {
780 string deps_content;
781 ulong deps_len;
782 FileUtils.get_contents (file_path, out deps_content, out deps_len);
783 foreach (string dep in deps_content.split ("\n")) {
784 dep = dep.strip ();
785 if (dep != "") {
786 if (!add_package (context, dep)) {
787 Vala.Report.error (null, "%s, dependency of %s, not found in specified Vala API directories".printf (dep, pkg_name));
791 } catch (FileError e) {
792 Vala.Report.error (null, "Unable to read dependency file: %s".printf (e.message));
798 * Adds the specified packages to the list of used packages.
800 * @param context The code context
801 * @param packages a list of package names
803 private void add_depencies (Vala.CodeContext context, string[] packages) {
804 foreach (string package in packages) {
805 if (!add_package (context, package)) {
806 Vala.Report.error (null, "Package `%s' not found in specified Vala API directories or GObject-Introspection GIR directories".printf (package));
812 * Add the specified source file to the context. Only .vala, .vapi, .gs,
813 * and .c files are supported.
815 private void add_documented_files (Vala.CodeContext context, string[] sources) {
816 if (sources == null) {
817 return;
820 foreach (string source in sources) {
821 if (FileUtils.test (source, FileTest.EXISTS)) {
822 var rpath = Vala.CodeContext.realpath (source);
823 if (source.has_suffix (".vala") || source.has_suffix (".gs")) {
824 var source_file = new Vala.SourceFile (context, Vala.SourceFileType.SOURCE, rpath);
826 if (source_package == null) {
827 source_package = register_package (new Package (settings.pkg_name, false, null));
830 register_source_file (source_package, source_file);
832 if (context.profile == Vala.Profile.GOBJECT) {
833 // import the GLib namespace by default (namespace of backend-specific standard library)
834 var ns_ref = new Vala.UsingDirective (new Vala.UnresolvedSymbol (null, "GLib", null));
835 source_file.add_using_directive (ns_ref);
836 context.root.add_using_directive (ns_ref);
839 context.add_source_file (source_file);
840 } else if (source.has_suffix (".vapi") || source.has_suffix (".gir")) {
841 string file_name = get_package_name (source);
843 var vfile = new Vala.SourceFile (context, Vala.SourceFileType.PACKAGE, rpath);
844 context.add_source_file (vfile);
846 if (source_package == null) {
847 source_package = register_package (new Package (settings.pkg_name, false, null));
850 register_source_file (source_package, vfile);
852 add_deps (context, Path.build_filename (Path.get_dirname (source), "%s.deps".printf (file_name)), file_name);
853 } else if (source.has_suffix (".c")) {
854 context.add_c_source_file (rpath);
855 tree.add_external_c_files (rpath);
856 } else {
857 Vala.Report.error (null, "%s is not a supported source file type. Only .vala, .vapi, .gs, and .c files are supported.".printf (source));
859 } else {
860 Vala.Report.error (null, "%s not found".printf (source));
865 private void create_valac_tree (Vala.CodeContext context, Settings settings) {
866 // settings:
867 context.experimental = settings.experimental;
868 context.experimental_non_null = settings.experimental || settings.experimental_non_null;
869 context.vapi_directories = settings.vapi_directories;
870 context.report.enable_warnings = settings.verbose;
871 context.metadata_directories = settings.metadata_directories;
872 context.gir_directories = settings.gir_directories;
874 if (settings.basedir == null) {
875 context.basedir = Vala.CodeContext.realpath (".");
876 } else {
877 context.basedir = Vala.CodeContext.realpath (settings.basedir);
880 if (settings.directory != null) {
881 context.directory = Vala.CodeContext.realpath (settings.directory);
882 } else {
883 context.directory = context.basedir;
887 // add default packages:
888 if (settings.profile == "gobject-2.0" || settings.profile == "gobject" || settings.profile == null) {
889 context.profile = Vala.Profile.GOBJECT;
890 context.add_define ("GOBJECT");
894 if (settings.defines != null) {
895 foreach (string define in settings.defines) {
896 context.add_define (define);
900 for (int i = 2; i <= 42; i += 2) {
901 context.add_define ("VALA_0_%d".printf (i));
904 if (context.profile == Vala.Profile.GOBJECT) {
905 int glib_major = 2;
906 int glib_minor = 40;
908 context.target_glib_major = glib_major;
909 context.target_glib_minor = glib_minor;
910 if (context.target_glib_major != 2) {
911 Vala.Report.error (null, "This version of valac only supports GLib 2");
914 if (settings.target_glib != null && settings.target_glib.scanf ("%d.%d", out glib_major, out glib_minor) != 2) {
915 Vala.Report.error (null, "Invalid format for --target-glib");
918 context.target_glib_major = glib_major;
919 context.target_glib_minor = glib_minor;
920 if (context.target_glib_major != 2) {
921 Vala.Report.error (null, "This version of valac only supports GLib 2");
924 for (int i = 16; i <= glib_minor; i += 2) {
925 context.add_define ("GLIB_2_%d".printf (i));
928 // default packages
929 if (!this.add_package (context, "glib-2.0")) { //
930 Vala.Report.error (null, "glib-2.0 not found in specified Vala API directories");
933 if (!this.add_package (context, "gobject-2.0")) { //
934 Vala.Report.error (null, "gobject-2.0 not found in specified Vala API directories");
938 // add user defined files:
939 add_depencies (context, settings.packages);
940 if (reporter.errors > 0) {
941 return;
944 add_documented_files (context, settings.source_files);
945 if (reporter.errors > 0) {
946 return;
949 // parse vala-code:
950 Vala.Parser parser = new Vala.Parser ();
952 parser.parse (context);
953 if (context.report.get_errors () > 0) {
954 return;
957 // parse gir:
958 Vala.GirParser gir_parser = new Vala.GirParser ();
960 gir_parser.parse (context);
961 if (context.report.get_errors () > 0) {
962 return;
965 // check context:
966 context.check ();
967 if (context.report.get_errors () > 0) {
968 return;
975 // Valadoc tree creation:
978 private void process_children (Api.Node node, Vala.CodeNode element) {
979 Api.Node old_node = current_node;
980 current_node = node;
981 element.accept_children (this);
982 current_node = old_node;
985 private Api.Node get_parent_node_for (Vala.Symbol element) {
986 if (current_node != null) {
987 return current_node;
990 Vala.SourceFile vala_source_file = element.source_reference.file;
991 Package package = find_package_for_file (vala_source_file);
992 SourceFile? source_file = get_source_file (element);
994 return get_namespace (package, element, source_file);
998 * {@inheritDoc}
1000 public override void visit_namespace (Vala.Namespace element) {
1001 element.accept_children (this);
1005 * {@inheritDoc}
1007 public override void visit_class (Vala.Class element) {
1008 Api.Node parent = get_parent_node_for (element);
1009 SourceFile? file = get_source_file (element);
1010 SourceComment? comment = create_comment (element.comment);
1012 bool is_basic_type = element.base_class == null && element.name == "string";
1014 Class node = new Class (parent,
1015 file,
1016 element.name,
1017 get_access_modifier (element),
1018 comment,
1019 get_cname (element),
1020 get_private_cname (element),
1021 get_class_macro_name (element),
1022 get_type_macro_name (element),
1023 get_is_type_macro_name (element),
1024 get_type_cast_macro_name (element),
1025 get_type_function_name (element),
1026 get_class_type_macro_name (element),
1027 get_is_class_type_macro_name (element),
1028 Vala.GDBusModule.get_dbus_name (element),
1029 get_ccode_type_id (element),
1030 get_param_spec_function (element),
1031 get_ref_function (element),
1032 get_unref_function (element),
1033 get_free_function_name (element),
1034 get_finalize_function_name (element),
1035 get_take_value_function (element),
1036 get_get_value_function (element),
1037 get_set_value_function (element),
1038 element.is_fundamental (),
1039 element.is_abstract,
1040 is_basic_type,
1041 element);
1042 symbol_map.set (element, node);
1043 parent.add_child (node);
1045 // relations
1046 foreach (Vala.DataType vala_type_ref in element.get_base_types ()) {
1047 var type_ref = create_type_reference (vala_type_ref, node, node);
1049 if (vala_type_ref.data_type is Vala.Interface) {
1050 node.add_interface (type_ref);
1051 } else if (vala_type_ref.data_type is Vala.Class) {
1052 node.base_type = type_ref;
1056 process_attributes (node, element.attributes);
1057 process_children (node, element);
1059 // save GLib.Error
1060 if (glib_error == null && node.get_full_name () == "GLib.Error") {
1061 glib_error = node;
1066 * {@inheritDoc}
1068 public override void visit_interface (Vala.Interface element) {
1069 Api.Node parent = get_parent_node_for (element);
1070 SourceFile? file = get_source_file (element);
1071 SourceComment? comment = create_comment (element.comment);
1073 Interface node = new Interface (parent,
1074 file,
1075 element.name,
1076 get_access_modifier (element),
1077 comment,
1078 get_cname (element),
1079 get_type_macro_name (element),
1080 get_is_type_macro_name (element),
1081 get_type_cast_macro_name (element),
1082 get_type_function_name (element),
1083 get_interface_macro_name (element),
1084 Vala.GDBusModule.get_dbus_name (element),
1085 element);
1086 symbol_map.set (element, node);
1087 parent.add_child (node);
1089 // prerequisites:
1090 foreach (Vala.DataType vala_type_ref in element.get_prerequisites ()) {
1091 TypeReference type_ref = create_type_reference (vala_type_ref, node, node);
1092 if (vala_type_ref.data_type is Vala.Interface) {
1093 node.add_interface (type_ref);
1094 } else {
1095 node.base_type = type_ref;
1099 process_attributes (node, element.attributes);
1100 process_children (node, element);
1104 * {@inheritDoc}
1106 public override void visit_struct (Vala.Struct element) {
1107 Api.Node parent = get_parent_node_for (element);
1108 SourceFile? file = get_source_file (element);
1109 SourceComment? comment = create_comment (element.comment);
1111 bool is_basic_type = element.base_type == null
1112 && (element.is_boolean_type ()
1113 || element.is_floating_type ()
1114 || element.is_integer_type ());
1116 Struct node = new Struct (parent,
1117 file,
1118 element.name,
1119 get_access_modifier (element),
1120 comment,
1121 get_cname (element),
1122 get_type_macro_name (element),
1123 get_type_function_name (element),
1124 get_ccode_type_id (element),
1125 get_dup_function (element),
1126 get_copy_function (element),
1127 get_destroy_function (element),
1128 get_free_function (element),
1129 is_basic_type,
1130 element);
1131 symbol_map.set (element, node);
1132 parent.add_child (node);
1134 // parent type:
1135 Vala.ValueType? basetype = element.base_type as Vala.ValueType;
1136 if (basetype != null) {
1137 node.base_type = create_type_reference (basetype, node, node);
1140 process_attributes (node, element.attributes);
1141 process_children (node, element);
1145 * {@inheritDoc}
1147 public override void visit_field (Vala.Field element) {
1148 Api.Node parent = get_parent_node_for (element);
1149 SourceFile? file = get_source_file (element);
1150 SourceComment? comment = create_comment (element.comment);
1152 Field node = new Field (parent,
1153 file,
1154 element.name,
1155 get_access_modifier (element),
1156 comment,
1157 get_cname (element),
1158 element.binding == Vala.MemberBinding.STATIC,
1159 element.is_volatile,
1160 element);
1161 node.field_type = create_type_reference (element.variable_type, node, node);
1162 symbol_map.set (element, node);
1163 parent.add_child (node);
1165 process_attributes (node, element.attributes);
1166 process_children (node, element);
1170 * {@inheritDoc}
1172 public override void visit_property (Vala.Property element) {
1173 Api.Node parent = get_parent_node_for (element);
1174 SourceFile? file = get_source_file (element);
1175 SourceComment? comment = create_comment (element.comment);
1177 Property node = new Property (parent,
1178 file,
1179 element.name,
1180 get_access_modifier (element),
1181 comment,
1182 element.nick,
1183 Vala.GDBusModule.get_dbus_name_for_member (element),
1184 Vala.GDBusModule.is_dbus_visible (element),
1185 get_property_binding_type (element),
1186 element);
1187 node.property_type = create_type_reference (element.property_type, node, node);
1188 symbol_map.set (element, node);
1189 parent.add_child (node);
1191 // Process property type
1192 if (element.get_accessor != null) {
1193 var accessor = element.get_accessor;
1194 node.getter = new PropertyAccessor (node,
1195 file,
1196 element.name,
1197 get_access_modifier (accessor),
1198 get_cname (accessor),
1199 get_property_accessor_type (accessor),
1200 get_property_ownership (accessor),
1201 accessor);
1204 if (element.set_accessor != null) {
1205 var accessor = element.set_accessor;
1206 node.setter = new PropertyAccessor (node,
1207 file,
1208 element.name,
1209 get_access_modifier (accessor),
1210 get_cname (accessor),
1211 get_property_accessor_type (accessor),
1212 get_property_ownership (accessor),
1213 accessor);
1216 process_attributes (node, element.attributes);
1217 process_children (node, element);
1221 * {@inheritDoc}
1223 public override void visit_creation_method (Vala.CreationMethod element) {
1224 Api.Node parent = get_parent_node_for (element);
1225 SourceFile? file = get_source_file (element);
1226 SourceComment? comment = create_comment (element.comment);
1228 Method node = new Method (parent,
1229 file,
1230 get_method_name (element),
1231 get_access_modifier (element),
1232 comment,
1233 get_cname (element),
1234 Vala.GDBusModule.get_dbus_name_for_member (element),
1235 Vala.GDBusModule.dbus_result_name (element),
1236 (element.coroutine)? get_finish_name (element) : null,
1237 get_method_binding_type (element),
1238 element.coroutine,
1239 Vala.GDBusModule.is_dbus_visible (element),
1240 element is Vala.CreationMethod,
1241 element);
1242 node.return_type = create_type_reference (element.return_type, node, node);
1243 symbol_map.set (element, node);
1244 parent.add_child (node);
1246 process_attributes (node, element.attributes);
1247 process_children (node, element);
1251 * {@inheritDoc}
1253 public override void visit_method (Vala.Method element) {
1254 Api.Node parent = get_parent_node_for (element);
1255 SourceFile? file = get_source_file (element);
1256 SourceComment? comment = create_comment (element.comment);
1258 Method node = new Method (parent,
1259 file,
1260 get_method_name (element),
1261 get_access_modifier (element),
1262 comment,
1263 get_cname (element),
1264 Vala.GDBusModule.get_dbus_name_for_member (element),
1265 Vala.GDBusModule.dbus_result_name (element),
1266 (element.coroutine)? get_finish_name (element) : null,
1267 get_method_binding_type (element),
1268 element.coroutine,
1269 Vala.GDBusModule.is_dbus_visible (element),
1270 element is Vala.CreationMethod,
1271 element);
1272 node.return_type = create_type_reference (element.return_type, node, node);
1273 symbol_map.set (element, node);
1274 parent.add_child (node);
1276 process_attributes (node, element.attributes);
1277 process_children (node, element);
1281 * {@inheritDoc}
1283 public override void visit_signal (Vala.Signal element) {
1284 Api.Node parent = get_parent_node_for (element);
1285 SourceFile? file = get_source_file (element);
1286 SourceComment? comment = create_comment (element.comment);
1288 Api.Signal node = new Api.Signal (parent,
1289 file,
1290 element.name,
1291 get_access_modifier (element),
1292 comment,
1293 get_cname (element),
1294 (element.default_handler != null)? get_cname (element.default_handler) : null,
1295 Vala.GDBusModule.get_dbus_name_for_member (element),
1296 Vala.GDBusModule.is_dbus_visible (element),
1297 element.is_virtual,
1298 element);
1299 node.return_type = create_type_reference (element.return_type, node, node);
1300 symbol_map.set (element, node);
1301 parent.add_child (node);
1303 process_attributes (node, element.attributes);
1304 process_children (node, element);
1308 * {@inheritDoc}
1310 public override void visit_delegate (Vala.Delegate element) {
1311 Api.Node parent = get_parent_node_for (element);
1312 SourceFile? file = get_source_file (element);
1313 SourceComment? comment = create_comment (element.comment);
1315 Delegate node = new Delegate (parent,
1316 file,
1317 element.name,
1318 get_access_modifier (element),
1319 comment,
1320 get_cname (element),
1321 !element.has_target,
1322 element);
1323 node.return_type = create_type_reference (element.return_type, node, node);
1324 symbol_map.set (element, node);
1325 parent.add_child (node);
1327 process_attributes (node, element.attributes);
1328 process_children (node, element);
1332 * {@inheritDoc}
1334 public override void visit_enum (Vala.Enum element) {
1335 Api.Node parent = get_parent_node_for (element);
1336 SourceFile? file = get_source_file (element);
1337 SourceComment? comment = create_comment (element.comment);
1339 Symbol node = new Enum (parent,
1340 file,
1341 element.name,
1342 get_access_modifier (element),
1343 comment,
1344 get_cname (element),
1345 get_type_macro_name (element),
1346 get_type_function_name (element),
1347 element);
1348 symbol_map.set (element, node);
1349 parent.add_child (node);
1351 process_attributes (node, element.attributes);
1352 process_children (node, element);
1356 * {@inheritDoc}
1358 public override void visit_enum_value (Vala.EnumValue element) {
1359 Api.Enum parent = (Enum) get_parent_node_for (element);
1360 SourceFile? file = get_source_file (element);
1361 SourceComment? comment = create_comment (element.comment);
1363 Symbol node = new Api.EnumValue (parent,
1364 file,
1365 element.name,
1366 comment,
1367 get_cname (element),
1368 element);
1369 symbol_map.set (element, node);
1370 parent.add_child (node);
1372 process_attributes (node, element.attributes);
1373 process_children (node, element);
1377 * {@inheritDoc}
1379 public override void visit_constant (Vala.Constant element) {
1380 Api.Node parent = get_parent_node_for (element);
1381 SourceFile? file = get_source_file (element);
1382 SourceComment? comment = create_comment (element.comment);
1384 Constant node = new Constant (parent,
1385 file,
1386 element.name,
1387 get_access_modifier (element),
1388 comment,
1389 get_cname (element),
1390 element);
1391 node.constant_type = create_type_reference (element.type_reference, node, node);
1392 symbol_map.set (element, node);
1393 parent.add_child (node);
1395 process_attributes (node, element.attributes);
1396 process_children (node, element);
1400 * {@inheritDoc}
1402 public override void visit_error_domain (Vala.ErrorDomain element) {
1403 Api.Node parent = get_parent_node_for (element);
1404 SourceFile? file = get_source_file (element);
1405 SourceComment? comment = create_comment (element.comment);
1407 Symbol node = new ErrorDomain (parent,
1408 file,
1409 element.name,
1410 get_access_modifier (element),
1411 comment,
1412 get_cname (element),
1413 get_quark_macro_name (element),
1414 get_quark_function_name (element),
1415 Vala.GDBusModule.get_dbus_name (element),
1416 element);
1417 symbol_map.set (element, node);
1418 parent.add_child (node);
1420 process_attributes (node, element.attributes);
1421 process_children (node, element);
1425 * {@inheritDoc}
1427 public override void visit_error_code (Vala.ErrorCode element) {
1428 Api.ErrorDomain parent = (ErrorDomain) get_parent_node_for (element);
1429 SourceFile? file = get_source_file (element);
1430 if (file == null) {
1431 file = parent.get_source_file ();
1434 SourceComment? comment = create_comment (element.comment);
1436 Symbol node = new Api.ErrorCode (parent,
1437 file,
1438 element.name,
1439 comment,
1440 get_cname (element),
1441 Vala.GDBusModule.get_dbus_name_for_member (element),
1442 element);
1443 symbol_map.set (element, node);
1444 parent.add_child (node);
1446 process_attributes (node, element.attributes);
1447 process_children (node, element);
1451 * {@inheritDoc}
1453 public override void visit_type_parameter (Vala.TypeParameter element) {
1454 Api.Node parent = get_parent_node_for (element);
1455 SourceFile? file = get_source_file (element);
1457 Symbol node = new TypeParameter (parent,
1458 file,
1459 element.name,
1460 element);
1461 symbol_map.set (element, node);
1462 parent.add_child (node);
1464 process_children (node, element);
1468 * {@inheritDoc}
1470 public override void visit_formal_parameter (Vala.Parameter element) {
1471 Api.Node parent = get_parent_node_for (element);
1472 SourceFile? file = get_source_file (element);
1474 FormalParameter node = new FormalParameter (parent,
1475 file,
1476 element.name,
1477 get_access_modifier(element),
1478 get_formal_parameter_type (element),
1479 element.ellipsis,
1480 element);
1481 node.parameter_type = create_type_reference (element.variable_type, node, node);
1482 parent.add_child (node);
1484 process_children (node, element);
1489 // startpoint:
1492 public Api.Tree? build (Settings settings, ErrorReporter reporter) {
1493 this.settings = settings;
1494 this.reporter = reporter;
1496 var context = new Vala.CodeContext ();
1497 Vala.CodeContext.push (context);
1499 this.tree = new Api.Tree (reporter, settings, context);
1500 create_valac_tree (context, settings);
1502 reporter.warnings_offset = context.report.get_warnings ();
1503 reporter.errors_offset = context.report.get_errors ();
1505 // TODO: Register all packages here
1506 // register packages included by gir-files
1507 foreach (Vala.SourceFile vfile in context.get_source_files ()) {
1508 if (vfile.file_type == Vala.SourceFileType.PACKAGE
1509 && vfile.get_nodes ().size > 0
1510 && files.contains (vfile) == false)
1512 Package vdpkg = new Package (get_package_name (vfile.filename), true, null);
1513 register_source_file (register_package (vdpkg), vfile);
1517 context.accept(this);
1519 return (reporter.errors == 0)? tree : null;