libxml-2.0: Make Doc.save_format_file return an int
[vala-lang.git] / vala / valasymbol.vala
blob2fb6c3a9bb93771a04ef3cea2d8ff925a77482fa
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 symbol name.
58 public string? name { get; set; }
60 /**
61 * Specifies whether this symbol is active.
63 * Symbols may become inactive when they only apply to a part of a
64 * scope. This is used for local variables not declared at the beginning
65 * of the block to determine which variables need to be freed before
66 * jump statements.
68 public bool active { get; set; default = true; }
70 /**
71 * Specifies whether this symbol has been deprecated.
73 public bool deprecated { get; set; default = false; }
75 /**
76 * Specifies what version this symbol has been deprecated since.
78 public string? deprecated_since { get; set; default = null; }
80 /**
81 * Specifies the replacement if this symbol has been deprecated.
83 public string? replacement { get; set; default = null; }
85 /**
86 * Specifies whether this symbol has been accessed.
88 public bool used { get; set; }
90 /**
91 * Specifies the accessibility of this symbol. Public accessibility
92 * doesn't limit access. Default accessibility limits access to this
93 * program or library. Private accessibility limits access to instances
94 * of the contained type.
96 public SymbolAccessibility access { get; set; }
98 public Comment? comment { get; set; }
100 private List<string> cheader_filenames = new ArrayList<string> ();
103 * Specifies whether this method explicitly hides a member of a base
104 * type.
106 public bool hides { get; set; }
109 * Check if this symbol is just internal API (and therefore doesn't need
110 * to be listed in header files for instance) by traversing parent symbols
111 * and checking their accessibility.
113 public bool is_internal_symbol () {
114 if (!external && external_package) {
115 // non-external symbols in VAPI files are internal symbols
116 return true;
119 for (Symbol sym = this; null != sym; sym = sym.parent_symbol) {
120 if (sym.access == SymbolAccessibility.PRIVATE
121 || sym.access == SymbolAccessibility.INTERNAL) {
122 return true;
126 return false;
129 public bool is_private_symbol () {
130 if (!external && external_package) {
131 // non-external symbols in VAPI files are private symbols
132 return true;
135 for (Symbol sym = this; null != sym; sym = sym.parent_symbol) {
136 if (sym.access == SymbolAccessibility.PRIVATE) {
137 return true;
141 return false;
144 public Scope scope {
145 get { return _scope; }
149 * Specifies whether the implementation is external, for example in
150 * a separate C source file or in an external library.
152 public bool external { get; set; }
155 * Specifies whether the implementation is in an external library.
157 public bool external_package {
158 get {
159 return (source_reference != null && source_reference.file.external_package);
163 private weak Scope _owner;
164 private Scope _scope;
166 public Symbol (string? name, SourceReference? source_reference, Comment? comment = null) {
167 this.name = name;
168 this.source_reference = source_reference;
169 this.comment = comment;
170 _scope = new Scope (this);
174 * Returns the fully expanded name of this symbol for use in
175 * human-readable messages.
177 * @return full name
179 public string get_full_name () {
180 if (parent_symbol == null) {
181 return name;
184 if (name == null) {
185 return parent_symbol.get_full_name ();
188 if (parent_symbol.get_full_name () == null) {
189 return name;
192 if (name.has_prefix (".")) {
193 return "%s%s".printf (parent_symbol.get_full_name (), name);
194 } else {
195 return "%s.%s".printf (parent_symbol.get_full_name (), name);
200 * Returns the camel case string to be prepended to the name of members
201 * of this symbol when used in C code.
203 * @return the camel case prefix to be used in C code
205 public virtual string get_cprefix () {
206 if (name == null) {
207 return "";
208 } else {
209 return name;
214 * Returns the C name of this symbol in lower case. Words are
215 * separated by underscores. The lower case C name of the parent symbol
216 * is prefix of the result, if there is one.
218 * @param infix a string to be placed between namespace and data type
219 * name or null
220 * @return the lower case name to be used in C code
222 public virtual string? get_lower_case_cname (string? infix = null) {
223 return null;
227 * Returns the string to be prefixed to members of this symbol in
228 * lower case when used in C code.
230 * @return the lower case prefix to be used in C code
232 public virtual string get_lower_case_cprefix () {
233 return "";
237 * Returns a list of C header filenames users of this symbol must
238 * include.
240 * @return list of C header filenames for this symbol
242 public virtual List<string> get_cheader_filenames () {
243 // parent_symbol can be null on incremental parsing
244 if (cheader_filenames.size == 0 && parent_symbol != null) {
245 /* default to header filenames of the namespace */
246 foreach (string filename in parent_symbol.get_cheader_filenames ()) {
247 add_cheader_filename (filename);
250 if (cheader_filenames.size == 0 && source_reference != null && !external_package) {
251 // don't add default include directives for VAPI files
252 cheader_filenames.add (source_reference.file.get_cinclude_filename ());
255 return cheader_filenames;
259 * Converts a string from CamelCase to lower_case.
261 * @param camel_case a string in camel case
262 * @return the specified string converted to lower case
264 public static string camel_case_to_lower_case (string camel_case) {
265 if ("_" in camel_case) {
266 // do not insert additional underscores if input is not real camel case
267 return camel_case.down ();
270 var result_builder = new StringBuilder ("");
272 weak string i = camel_case;
274 bool first = true;
275 while (i.len () > 0) {
276 unichar c = i.get_char ();
277 if (c.isupper () && !first) {
278 /* current character is upper case and
279 * we're not at the beginning */
280 weak string t = i.prev_char ();
281 bool prev_upper = t.get_char ().isupper ();
282 t = i.next_char ();
283 bool next_upper = t.get_char ().isupper ();
284 if (!prev_upper || (i.len () >= 2 && !next_upper)) {
285 /* previous character wasn't upper case or
286 * next character isn't upper case*/
287 long len = result_builder.str.len ();
288 if (len != 1 && result_builder.str.offset (len - 2).get_char () != '_') {
289 /* we're not creating 1 character words */
290 result_builder.append_c ('_');
295 result_builder.append_unichar (c.tolower ());
297 first = false;
298 i = i.next_char ();
301 return result_builder.str;
305 * Converts a string from lower_case to CamelCase.
307 * @param lower_case a string in lower case
308 * @return the specified string converted to camel case
310 public static string lower_case_to_camel_case (string lower_case) {
311 var result_builder = new StringBuilder ("");
313 weak string i = lower_case;
315 bool last_underscore = true;
316 while (i.len () > 0) {
317 unichar c = i.get_char ();
318 if (c == '_') {
319 last_underscore = true;
320 } else if (c.isupper ()) {
321 // original string is not lower_case, don't apply transformation
322 return lower_case;
323 } else if (last_underscore) {
324 result_builder.append_unichar (c.toupper ());
325 last_underscore = false;
326 } else {
327 result_builder.append_unichar (c);
330 i = i.next_char ();
333 return result_builder.str;
336 // get the top scope from where this symbol is still accessible
337 public Scope? get_top_accessible_scope (bool is_internal = false) {
338 if (access == SymbolAccessibility.PRIVATE) {
339 // private symbols are accessible within the scope where the symbol has been declared
340 return owner;
343 if (access == SymbolAccessibility.INTERNAL) {
344 is_internal = true;
347 if (parent_symbol == null) {
348 // this is the root symbol
349 if (is_internal) {
350 // only accessible within the same library
351 // return root scope
352 return scope;
353 } else {
354 // unlimited access
355 return null;
359 // if this is a public symbol, it's equally accessible as the parent symbol
360 return parent_symbol.get_top_accessible_scope (is_internal);
363 public virtual bool is_instance_member () {
364 bool instance = true;
365 if (this is Field) {
366 var f = (Field) this;
367 instance = (f.binding == MemberBinding.INSTANCE);
368 } else if (this is Method) {
369 var m = (Method) this;
370 if (!(m is CreationMethod)) {
371 instance = (m.binding == MemberBinding.INSTANCE);
373 } else if (this is Property) {
374 var prop = (Property) this;
375 instance = (prop.binding == MemberBinding.INSTANCE);
376 } else if (this is EnumValue) {
377 instance = false;
378 } else if (this is ErrorCode) {
379 instance = false;
382 return instance;
385 public virtual bool is_class_member () {
386 bool isclass = true;
387 if (this is Field) {
388 var f = (Field) this;
389 isclass = (f.binding == MemberBinding.CLASS);
390 } else if (this is Method) {
391 var m = (Method) this;
392 if (!(m is CreationMethod)) {
393 isclass = (m.binding == MemberBinding.CLASS);
395 } else if (this is Property) {
396 var prop = (Property) this;
397 isclass = (prop.binding == MemberBinding.CLASS);
398 } else if (this is EnumValue) {
399 isclass = false;
400 } else if (this is ErrorCode) {
401 isclass = false;
404 return isclass;
408 * Process a [Deprecated] attribute
410 public virtual void process_deprecated_attribute (Attribute attr) {
411 if (attr.name != "Deprecated") {
412 return;
415 deprecated = true;
417 if (attr.has_argument ("since")) {
418 deprecated_since = attr.get_string ("since");
420 if (attr.has_argument ("replacement")) {
421 replacement = attr.get_string ("replacement");
426 * Check to see if the symbol has been deprecated, and emit a warning
427 * if it has.
429 public bool check_deprecated (SourceReference? source_ref = null) {
430 if (deprecated) {
431 if (!CodeContext.get ().deprecated) {
432 Report.warning (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)));
434 return true;
435 } else {
436 return false;
441 * Sets the C header filename of this namespace to the specified
442 * filename.
444 * @param cheader_filename header filename
446 public void set_cheader_filename (string cheader_filename) {
447 cheader_filenames = new ArrayList<string> ();
448 cheader_filenames.add (cheader_filename);
452 * Adds a filename to the list of C header filenames users of this data
453 * type must include.
455 * @param filename a C header filename
457 public void add_cheader_filename (string filename) {
458 cheader_filenames.add (filename);
461 public Symbol? get_hidden_member () {
462 Symbol sym = null;
464 if (parent_symbol is Class) {
465 var cl = ((Class) parent_symbol).base_class;
466 while (cl != null) {
467 sym = cl.scope.lookup (name);
468 if (sym != null && sym.access != SymbolAccessibility.PRIVATE) {
469 return sym;
471 cl = cl.base_class;
473 } else if (parent_symbol is Struct) {
474 var st = ((Struct) parent_symbol).base_struct;
475 while (st != null) {
476 sym = st.scope.lookup (name);
477 if (sym != null && sym.access != SymbolAccessibility.PRIVATE) {
478 return sym;
480 st = st.base_struct;
484 return null;
488 public enum Vala.SymbolAccessibility {
489 PRIVATE,
490 INTERNAL,
491 PROTECTED,
492 PUBLIC
495 public enum MemberBinding {
496 INSTANCE,
497 CLASS,
498 STATIC