Insert "%s" argument in printf calls with non-literal format string
[vala-lang.git] / vala / valasymbol.vala
blob36d32c5844d06d0fd4a6d745682d76bb820a4a38
1 /* valasymbol.vala
3 * Copyright (C) 2006-2009 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 node in the symbol tree.
29 public abstract class Vala.Symbol : CodeNode {
30 /**
31 * The parent of this symbol.
33 public weak Symbol? parent_symbol {
34 get {
35 if (owner == null) {
36 return null;
37 } else {
38 return owner.owner;
43 /**
44 * The scope this symbol opens.
46 public weak Scope owner {
47 get {
48 return _owner;
50 set {
51 _owner = value;
52 _scope.parent_scope = value;
56 /**
57 * The symbol name.
59 public string? name { get; set; }
61 /**
62 * Specifies whether this symbol is active.
64 * Symbols may become inactive when they only apply to a part of a
65 * scope. This is used for local variables not declared at the beginning
66 * of the block to determine which variables need to be freed before
67 * jump statements.
69 public bool active { get; set; default = true; }
71 /**
72 * Specifies whether this symbol has been accessed.
74 public bool used { get; set; }
76 /**
77 * Specifies the accessibility of this symbol. Public accessibility
78 * doesn't limit access. Default accessibility limits access to this
79 * program or library. Private accessibility limits access to instances
80 * of the contained type.
82 public SymbolAccessibility access { get; set; }
84 /**
85 * Check if this symbol is just internal API (and therefore doesn't need
86 * to be listed in header files for instance) by traversing parent symbols
87 * and checking their accessibility.
89 public bool is_internal_symbol () {
90 if (!external && external_package) {
91 // non-external symbols in VAPI files are internal symbols
92 return true;
95 for (Symbol sym = this; null != sym; sym = sym.parent_symbol) {
96 if (sym.access == SymbolAccessibility.PRIVATE
97 || sym.access == SymbolAccessibility.INTERNAL) {
98 return true;
102 return false;
105 public bool is_private_symbol () {
106 if (!external && external_package) {
107 // non-external symbols in VAPI files are private symbols
108 return true;
111 for (Symbol sym = this; null != sym; sym = sym.parent_symbol) {
112 if (sym.access == SymbolAccessibility.PRIVATE) {
113 return true;
117 return false;
120 public Scope scope {
121 get { return _scope; }
125 * Specifies whether the implementation is external, for example in
126 * a separate C source file or in an external library.
128 public bool external { get; set; }
131 * Specifies whether the implementation is in an external library.
133 public bool external_package {
134 get {
135 return (source_reference != null && source_reference.file.external_package);
139 private weak Scope _owner;
140 private Scope _scope;
142 public Symbol (string? name, SourceReference? source_reference) {
143 this.name = name;
144 this.source_reference = source_reference;
145 _scope = new Scope (this);
149 * Returns the fully expanded name of this symbol for use in
150 * human-readable messages.
152 * @return full name
154 public string get_full_name () {
155 if (parent_symbol == null) {
156 return name;
159 if (name == null) {
160 return parent_symbol.get_full_name ();
163 if (parent_symbol.get_full_name () == null) {
164 return name;
167 return "%s.%s".printf (parent_symbol.get_full_name (), name);
171 * Returns the camel case string to be prepended to the name of members
172 * of this symbol when used in C code.
174 * @return the camel case prefix to be used in C code
176 public virtual string get_cprefix () {
177 if (name == null) {
178 return "";
179 } else {
180 return name;
185 * Returns the C name of this symbol in lower case. Words are
186 * separated by underscores. The lower case C name of the parent symbol
187 * is prefix of the result, if there is one.
189 * @param infix a string to be placed between namespace and data type
190 * name or null
191 * @return the lower case name to be used in C code
193 public virtual string? get_lower_case_cname (string? infix = null) {
194 return null;
198 * Returns the string to be prefixed to members of this symbol in
199 * lower case when used in C code.
201 * @return the lower case prefix to be used in C code
203 public virtual string get_lower_case_cprefix () {
204 return "";
208 * Returns a list of C header filenames users of this symbol must
209 * include.
211 * @return list of C header filenames for this symbol
213 public virtual Gee.List<string> get_cheader_filenames () {
214 return new ArrayList<string> ();
218 * Converts a string from CamelCase to lower_case.
220 * @param camel_case a string in camel case
221 * @return the specified string converted to lower case
223 public static string camel_case_to_lower_case (string camel_case) {
224 if ("_" in camel_case) {
225 // do not insert additional underscores if input is not real camel case
226 return camel_case.down ();
229 var result_builder = new StringBuilder ("");
231 weak string i = camel_case;
233 bool first = true;
234 while (i.len () > 0) {
235 unichar c = i.get_char ();
236 if (c.isupper () && !first) {
237 /* current character is upper case and
238 * we're not at the beginning */
239 weak string t = i.prev_char ();
240 bool prev_upper = t.get_char ().isupper ();
241 t = i.next_char ();
242 bool next_upper = t.get_char ().isupper ();
243 if (!prev_upper || (i.len () >= 2 && !next_upper)) {
244 /* previous character wasn't upper case or
245 * next character isn't upper case*/
246 long len = result_builder.str.len ();
247 if (len != 1 && result_builder.str.offset (len - 2).get_char () != '_') {
248 /* we're not creating 1 character words */
249 result_builder.append_c ('_');
254 result_builder.append_unichar (c.tolower ());
256 first = false;
257 i = i.next_char ();
260 return result_builder.str;
264 * Converts a string from lower_case to CamelCase.
266 * @param lower_case a string in lower case
267 * @return the specified string converted to camel case
269 public static string lower_case_to_camel_case (string lower_case) {
270 var result_builder = new StringBuilder ("");
272 weak string i = lower_case;
274 bool last_underscore = true;
275 while (i.len () > 0) {
276 unichar c = i.get_char ();
277 if (c == '_') {
278 last_underscore = true;
279 } else if (c.isupper ()) {
280 // original string is not lower_case, don't apply transformation
281 return lower_case;
282 } else if (last_underscore) {
283 result_builder.append_unichar (c.toupper ());
284 last_underscore = false;
285 } else {
286 result_builder.append_unichar (c);
289 i = i.next_char ();
292 return result_builder.str;
295 // get the top scope from where this symbol is still accessible
296 public Scope? get_top_accessible_scope (bool is_internal = false) {
297 if (access == SymbolAccessibility.PRIVATE) {
298 // private symbols are accessible within the scope where the symbol has been declared
299 return owner;
302 if (access == SymbolAccessibility.INTERNAL) {
303 is_internal = true;
306 if (parent_symbol == null) {
307 // this is the root symbol
308 if (is_internal) {
309 // only accessible within the same library
310 // return root scope
311 return scope;
312 } else {
313 // unlimited access
314 return null;
318 // if this is a public symbol, it's equally accessible as the parent symbol
319 return parent_symbol.get_top_accessible_scope (is_internal);
322 public virtual bool is_instance_member () {
323 bool instance = true;
324 if (this is Field) {
325 var f = (Field) this;
326 instance = (f.binding == MemberBinding.INSTANCE);
327 } else if (this is Method) {
328 var m = (Method) this;
329 if (!(m is CreationMethod)) {
330 instance = (m.binding == MemberBinding.INSTANCE);
332 } else if (this is Property) {
333 var prop = (Property) this;
334 instance = (prop.binding == MemberBinding.INSTANCE);
335 } else if (this is EnumValue) {
336 instance = false;
337 } else if (this is ErrorCode) {
338 instance = false;
341 return instance;
344 public virtual bool is_class_member () {
345 bool isclass = true;
346 if (this is Field) {
347 var f = (Field) this;
348 isclass = (f.binding == MemberBinding.CLASS);
349 } else if (this is Method) {
350 var m = (Method) this;
351 if (!(m is CreationMethod)) {
352 isclass = (m.binding == MemberBinding.CLASS);
354 } else if (this is Property) {
355 var prop = (Property) this;
356 isclass = (prop.binding == MemberBinding.CLASS);
357 } else if (this is EnumValue) {
358 isclass = false;
359 } else if (this is ErrorCode) {
360 isclass = false;
363 return isclass;
367 public enum Vala.SymbolAccessibility {
368 PRIVATE,
369 INTERNAL,
370 PROTECTED,
371 PUBLIC