Bump version suffix
[vala-lang.git] / vala / valasymbol.vala
blob5b1ef12a979b0e7e88383c3a99849886e3d8018e
1 /* valasymbol.vala
3 * Copyright (C) 2006-2010 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;
25 /**
26 * Represents a node in the symbol tree.
28 public abstract class Vala.Symbol : CodeNode {
29 /**
30 * The parent of this symbol.
32 public weak Symbol? parent_symbol {
33 get {
34 if (owner == null) {
35 return null;
36 } else {
37 return owner.owner;
42 /**
43 * The scope this symbol opens.
45 public weak Scope owner {
46 get {
47 return _owner;
49 set {
50 _owner = value;
51 _scope.parent_scope = value;
55 /**
56 * The GIR name.
58 public string? gir_name {
59 get {
60 return _gir_name == null ? name : _gir_name;
62 set {
63 _gir_name = value;
67 /**
68 * The symbol name.
70 public string? name { get; set; }
72 /**
73 * Specifies whether this symbol is active.
75 * Symbols may become inactive when they only apply to a part of a
76 * scope. This is used for local variables not declared at the beginning
77 * of the block to determine which variables need to be freed before
78 * jump statements.
80 public bool active { get; set; default = true; }
82 /**
83 * Specifies whether this symbol has been deprecated.
85 public bool deprecated { get; set; default = false; }
87 /**
88 * Specifies what version this symbol has been deprecated since.
90 public string? deprecated_since { get; set; default = null; }
92 /**
93 * Specifies the replacement if this symbol has been deprecated.
95 public string? replacement { get; set; default = null; }
97 /**
98 * Specifies whether this symbol is experimental.
100 public bool experimental { get; set; default = false; }
103 * Specifies whether this symbol has been accessed.
105 public bool used { get; set; }
108 * Specifies the accessibility of this symbol. Public accessibility
109 * doesn't limit access. Default accessibility limits access to this
110 * program or library. Private accessibility limits access to instances
111 * of the contained type.
113 public SymbolAccessibility access { get; set; }
115 public Comment? comment { get; set; }
117 private List<string> cheader_filenames;
120 * Specifies whether this method explicitly hides a member of a base
121 * type.
123 public bool hides { get; set; }
126 * Check if this symbol is just internal API (and therefore doesn't need
127 * to be listed in header files for instance) by traversing parent symbols
128 * and checking their accessibility.
130 public bool is_internal_symbol () {
131 if (!external && external_package) {
132 // non-external symbols in VAPI files are internal symbols
133 return true;
136 for (Symbol sym = this; null != sym; sym = sym.parent_symbol) {
137 if (sym.access == SymbolAccessibility.PRIVATE
138 || sym.access == SymbolAccessibility.INTERNAL) {
139 return true;
143 return false;
146 public bool is_private_symbol () {
147 if (!external && external_package) {
148 // non-external symbols in VAPI files are private symbols
149 return true;
152 for (Symbol sym = this; null != sym; sym = sym.parent_symbol) {
153 if (sym.access == SymbolAccessibility.PRIVATE) {
154 return true;
158 return false;
161 public Scope scope {
162 get { return _scope; }
166 * Specifies whether the implementation is external, for example in
167 * a separate C source file or in an external library.
169 public bool external { get; set; }
172 * Specifies whether the implementation is in an external library.
174 public bool external_package {
175 get {
176 return source_type == SourceFileType.PACKAGE;
181 * Gets the SourceFileType of the source file that this symbol
182 * came from, or SourceFileType.NONE.
184 public SourceFileType source_type {
185 get {
186 if (source_reference != null) {
187 return source_reference.file.file_type;
188 } else {
189 return SourceFileType.NONE;
194 private weak Scope _owner;
195 private Scope _scope;
196 private string? _gir_name = null;
198 public Symbol (string? name, SourceReference? source_reference, Comment? comment = null) {
199 this.name = name;
200 this.source_reference = source_reference;
201 this.comment = comment;
202 _scope = new Scope (this);
206 * Returns the fully expanded GIR name of this symbol
208 * @return full GIR name
210 public string get_full_gir_name () {
211 if (parent_symbol == null) {
212 return gir_name;
215 if (name == null) {
216 return parent_symbol.get_full_gir_name ();
219 if (parent_symbol.get_full_gir_name () == null) {
220 return gir_name;
223 string parent_gir_name = parent_symbol.get_full_gir_name ();
224 string self_gir_name = gir_name.has_prefix (".") ? gir_name.substring (1) : gir_name;
225 if ("." in parent_gir_name) {
226 return "%s%s".printf (parent_gir_name, self_gir_name);
227 } else {
228 return "%s.%s".printf (parent_gir_name, self_gir_name);
233 * Returns the fully expanded name of this symbol for use in
234 * human-readable messages.
236 * @return full name
238 public string get_full_name () {
239 if (parent_symbol == null) {
240 return name;
243 if (name == null) {
244 return parent_symbol.get_full_name ();
247 if (parent_symbol.get_full_name () == null) {
248 return name;
251 if (name.has_prefix (".")) {
252 return "%s%s".printf (parent_symbol.get_full_name (), name);
253 } else {
254 return "%s.%s".printf (parent_symbol.get_full_name (), name);
259 * Returns the camel case string to be prepended to the name of members
260 * of this symbol when used in C code.
262 * @return the camel case prefix to be used in C code
264 public virtual string get_cprefix () {
265 if (name == null) {
266 return "";
267 } else {
268 return name;
273 * Returns the C name of this symbol in lower case. Words are
274 * separated by underscores. The lower case C name of the parent symbol
275 * is prefix of the result, if there is one.
277 * @param infix a string to be placed between namespace and data type
278 * name or null
279 * @return the lower case name to be used in C code
281 public virtual string? get_lower_case_cname (string? infix = null) {
282 return null;
286 * Returns the string to be prefixed to members of this symbol in
287 * lower case when used in C code.
289 * @return the lower case prefix to be used in C code
291 public virtual string get_lower_case_cprefix () {
292 return "";
295 static List<string> _empty_string_list;
298 * Returns a list of C header filenames users of this symbol must
299 * include.
301 * @return list of C header filenames for this symbol
303 public virtual List<string> get_cheader_filenames () {
304 if (cheader_filenames == null || cheader_filenames.size == 0) {
305 // parent_symbol can be null on incremental parsing
306 if (parent_symbol != null) {
307 /* default to header filenames of the namespace */
308 var parent_header_filenames = parent_symbol.get_cheader_filenames ();
309 if (parent_header_filenames.size > 0) {
310 return parent_header_filenames;
314 if (source_reference != null && !external_package) {
315 // don't add default include directives for VAPI files
316 add_cheader_filename (source_reference.file.get_cinclude_filename ());
317 } else {
318 if (_empty_string_list == null) {
319 _empty_string_list = new ArrayList<string> ();
321 return _empty_string_list;
324 return cheader_filenames;
328 * Converts a string from CamelCase to lower_case.
330 * @param camel_case a string in camel case
331 * @return the specified string converted to lower case
333 public static string camel_case_to_lower_case (string camel_case) {
334 if ("_" in camel_case) {
335 // do not insert additional underscores if input is not real camel case
336 return camel_case.down ();
339 var result_builder = new StringBuilder ("");
341 weak string i = camel_case;
343 bool first = true;
344 while (i.length > 0) {
345 unichar c = i.get_char ();
346 if (c.isupper () && !first) {
347 /* current character is upper case and
348 * we're not at the beginning */
349 weak string t = i.prev_char ();
350 bool prev_upper = t.get_char ().isupper ();
351 t = i.next_char ();
352 bool next_upper = t.get_char ().isupper ();
353 if (!prev_upper || (i.length >= 2 && !next_upper)) {
354 /* previous character wasn't upper case or
355 * next character isn't upper case*/
356 long len = result_builder.str.length;
357 if (len != 1 && result_builder.str.get_char (len - 2) != '_') {
358 /* we're not creating 1 character words */
359 result_builder.append_c ('_');
364 result_builder.append_unichar (c.tolower ());
366 first = false;
367 i = i.next_char ();
370 return result_builder.str;
374 * Converts a string from lower_case to CamelCase.
376 * @param lower_case a string in lower case
377 * @return the specified string converted to camel case
379 public static string lower_case_to_camel_case (string lower_case) {
380 var result_builder = new StringBuilder ("");
382 weak string i = lower_case;
384 bool last_underscore = true;
385 while (i.length > 0) {
386 unichar c = i.get_char ();
387 if (c == '_') {
388 last_underscore = true;
389 } else if (c.isupper ()) {
390 // original string is not lower_case, don't apply transformation
391 return lower_case;
392 } else if (last_underscore) {
393 result_builder.append_unichar (c.toupper ());
394 last_underscore = false;
395 } else {
396 result_builder.append_unichar (c);
399 i = i.next_char ();
402 return result_builder.str;
405 // get the top scope from where this symbol is still accessible
406 public Scope? get_top_accessible_scope (bool is_internal = false) {
407 if (access == SymbolAccessibility.PRIVATE) {
408 // private symbols are accessible within the scope where the symbol has been declared
409 return owner;
412 if (access == SymbolAccessibility.INTERNAL) {
413 is_internal = true;
416 if (parent_symbol == null) {
417 // this is the root symbol
418 if (is_internal) {
419 // only accessible within the same library
420 // return root scope
421 return scope;
422 } else {
423 // unlimited access
424 return null;
428 // if this is a public symbol, it's equally accessible as the parent symbol
429 return parent_symbol.get_top_accessible_scope (is_internal);
432 public virtual bool is_instance_member () {
433 bool instance = true;
434 if (this is Field) {
435 var f = (Field) this;
436 instance = (f.binding == MemberBinding.INSTANCE);
437 } else if (this is Method) {
438 var m = (Method) this;
439 if (!(m is CreationMethod)) {
440 instance = (m.binding == MemberBinding.INSTANCE);
442 } else if (this is Property) {
443 var prop = (Property) this;
444 instance = (prop.binding == MemberBinding.INSTANCE);
445 } else if (this is EnumValue) {
446 instance = false;
447 } else if (this is ErrorCode) {
448 instance = false;
451 return instance;
454 public virtual bool is_class_member () {
455 bool isclass = true;
456 if (this is Field) {
457 var f = (Field) this;
458 isclass = (f.binding == MemberBinding.CLASS);
459 } else if (this is Method) {
460 var m = (Method) this;
461 if (!(m is CreationMethod)) {
462 isclass = (m.binding == MemberBinding.CLASS);
464 } else if (this is Property) {
465 var prop = (Property) this;
466 isclass = (prop.binding == MemberBinding.CLASS);
467 } else if (this is EnumValue) {
468 isclass = false;
469 } else if (this is ErrorCode) {
470 isclass = false;
473 return isclass;
477 * Process a [Deprecated] attribute
479 public virtual void process_deprecated_attribute (Attribute attr) {
480 if (attr.name != "Deprecated") {
481 return;
484 deprecated = true;
486 if (attr.has_argument ("since")) {
487 deprecated_since = attr.get_string ("since");
489 if (attr.has_argument ("replacement")) {
490 replacement = attr.get_string ("replacement");
495 * Check to see if the symbol has been deprecated, and emit a warning
496 * if it has.
498 public bool check_deprecated (SourceReference? source_ref = null) {
499 if (deprecated) {
500 if (!CodeContext.get ().deprecated) {
501 Report.deprecated (source_ref, "%s %s%s".printf (get_full_name (), (deprecated_since == null) ? "is deprecated" : "has been deprecated since %s".printf (deprecated_since), (replacement == null) ? "" : ". Use %s".printf (replacement)));
503 return true;
504 } else {
505 return false;
510 * Process a [Experimental] attribute
512 public virtual void process_experimental_attribute (Attribute attr) {
513 if (attr.name != "Experimental") {
514 return;
517 experimental = true;
521 * Check to see if the symbol is experimental, and emit a warning
522 * if it is.
524 public bool check_experimental (SourceReference? source_ref = null) {
525 if (experimental) {
526 if (!CodeContext.get ().experimental) {
527 Report.experimental (source_ref, "%s is experimental".printf (get_full_name ()));
529 return true;
530 } else {
531 return false;
536 * Sets the C header filename of this namespace to the specified
537 * filename.
539 * @param cheader_filename header filename
541 public void set_cheader_filename (string cheader_filename) {
542 cheader_filenames = new ArrayList<string> ();
543 cheader_filenames.add (cheader_filename);
547 * Adds a filename to the list of C header filenames users of this data
548 * type must include.
550 * @param filename a C header filename
552 public void add_cheader_filename (string filename) {
553 if (cheader_filenames == null) {
554 cheader_filenames = new ArrayList<string> ();
556 cheader_filenames.add (filename);
559 public Symbol? get_hidden_member () {
560 Symbol sym = null;
562 if (parent_symbol is Class) {
563 var cl = ((Class) parent_symbol).base_class;
564 while (cl != null) {
565 sym = cl.scope.lookup (name);
566 if (sym != null && sym.access != SymbolAccessibility.PRIVATE) {
567 return sym;
569 cl = cl.base_class;
571 } else if (parent_symbol is Struct) {
572 var st = ((Struct) parent_symbol).base_struct;
573 while (st != null) {
574 sym = st.scope.lookup (name);
575 if (sym != null && sym.access != SymbolAccessibility.PRIVATE) {
576 return sym;
578 st = st.base_struct;
582 return null;
585 // check whether this symbol is at least as accessible as the specified symbol
586 public bool is_accessible (Symbol sym) {
587 Scope sym_scope = sym.get_top_accessible_scope ();
588 Scope this_scope = this.get_top_accessible_scope ();
589 if ((sym_scope == null && this_scope != null)
590 || (sym_scope != null && !sym_scope.is_subscope_of (this_scope))) {
591 return false;
594 return true;
597 public virtual void add_namespace (Namespace ns) {
598 Report.error (ns.source_reference, "unexpected declaration");
601 public virtual void add_class (Class cl) {
602 Report.error (cl.source_reference, "unexpected declaration");
605 public virtual void add_interface (Interface iface) {
606 Report.error (iface.source_reference, "unexpected declaration");
609 public virtual void add_struct (Struct st) {
610 Report.error (st.source_reference, "unexpected declaration");
613 public virtual void add_enum (Enum en) {
614 Report.error (en.source_reference, "unexpected declaration");
617 public virtual void add_error_domain (ErrorDomain edomain) {
618 Report.error (edomain.source_reference, "unexpected declaration");
621 public virtual void add_delegate (Delegate d) {
622 Report.error (d.source_reference, "unexpected declaration");
625 public virtual void add_constant (Constant constant) {
626 Report.error (constant.source_reference, "unexpected declaration");
629 public virtual void add_field (Field f) {
630 Report.error (f.source_reference, "unexpected declaration");
633 public virtual void add_method (Method m) {
634 Report.error (m.source_reference, "unexpected declaration");
637 public virtual void add_property (Property prop) {
638 Report.error (prop.source_reference, "unexpected declaration");
641 public virtual void add_signal (Signal sig) {
642 Report.error (sig.source_reference, "unexpected declaration");
645 public virtual void add_constructor (Constructor c) {
646 Report.error (c.source_reference, "unexpected declaration");
649 public virtual void add_destructor (Destructor d) {
650 Report.error (d.source_reference, "unexpected declaration");
654 public enum Vala.SymbolAccessibility {
655 PRIVATE,
656 INTERNAL,
657 PROTECTED,
658 PUBLIC
661 public enum Vala.MemberBinding {
662 INSTANCE,
663 CLASS,
664 STATIC