girparser: Guess virtual method wrapper variant when possible
[vala-lang.git] / vala / valasourcefile.vala
blob931f02010385be5b2c9fb76bfb40c24df44fdd7e
1 /* valasourcefile.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;
25 /**
26 * Represents a Vala source or VAPI package file.
28 public class Vala.SourceFile {
29 /**
30 * The name of this source file.
32 public string filename { get; set; }
34 public string? relative_filename {
35 set {
36 this._relative_filename = value;
40 /**
41 * Specifies whether this file is a VAPI package file.
43 public SourceFileType file_type { get; set; }
45 /**
46 * GIR Namespace for this source file, if it's a VAPI package
49 public string gir_namespace { get; set; }
51 /**
52 * GIR Namespace version for this source file, if it's a VAPI package
55 public string gir_version { get; set; }
57 /**
58 * The context this source file belongs to.
60 public weak CodeContext context { get; set; }
62 public string? content {
63 get { return this._content; }
64 set {
65 this._content = value;
66 this.source_array = null;
70 /**
71 * If the file has been used (ie: if anything in the file has
72 * been emitted into C code as a definition or declaration).
74 public bool used { get; set; }
76 private ArrayList<Comment> comments = new ArrayList<Comment> ();
78 public List<UsingDirective> current_using_directives { get; set; default = new ArrayList<UsingDirective> (); }
80 private List<CodeNode> nodes = new ArrayList<CodeNode> ();
82 string? _relative_filename;
84 private string csource_filename = null;
85 private string cinclude_filename = null;
87 private ArrayList<string> source_array = null;
89 private MappedFile mapped_file = null;
91 private string? _content = null;
93 /**
94 * Creates a new source file.
96 * @param filename source file name
97 * @param pkg true if this is a VAPI package file
98 * @return newly created source file
100 public SourceFile (CodeContext context, SourceFileType type, string filename, string? content = null) {
101 this.context = context;
102 this.file_type = type;
103 this.filename = filename;
104 this.content = content;
108 * Adds a header comment to this source file.
110 public void add_comment (Comment comment) {
111 comments.add (comment);
115 * Returns a copy of the list of header comments.
117 * @return list of comments
119 public List<Comment> get_comments () {
120 return comments;
124 * Adds a new using directive with the specified namespace.
126 * @param ns reference to namespace
128 public void add_using_directive (UsingDirective ns) {
129 // do not modify current_using_directives, it should be considered immutable
130 // for correct symbol resolving
131 var old_using_directives = current_using_directives;
132 current_using_directives = new ArrayList<UsingDirective> ();
133 foreach (var using_directive in old_using_directives) {
134 current_using_directives.add (using_directive);
136 current_using_directives.add (ns);
140 * Adds the specified code node to this source file.
142 * @param node a code node
144 public void add_node (CodeNode node) {
145 nodes.add (node);
148 public void remove_node (CodeNode node) {
149 nodes.remove (node);
153 * Returns a copy of the list of code nodes.
155 * @return code node list
157 public List<CodeNode> get_nodes () {
158 return nodes;
161 public void accept (CodeVisitor visitor) {
162 visitor.visit_source_file (this);
165 public void accept_children (CodeVisitor visitor) {
166 foreach (CodeNode node in nodes) {
167 node.accept (visitor);
171 private string get_subdir () {
172 if (context.basedir == null) {
173 return "";
176 // filename and basedir are already canonicalized
177 if (filename.has_prefix (context.basedir + "/")) {
178 var basename = Path.get_basename (filename);
179 var subdir = filename.substring (context.basedir.length, filename.length - context.basedir.length - basename.length);
180 while (subdir[0] == '/') {
181 subdir = subdir.offset (1);
183 return subdir;
185 return "";
188 private string get_destination_directory () {
189 if (context.directory == null) {
190 return get_subdir ();
192 return "%s/%s".printf (context.directory, get_subdir ());
195 private string get_basename () {
196 long dot = filename.pointer_to_offset (filename.rchr (-1, '.'));
197 return Path.get_basename (filename.substring (0, dot));
200 public string get_relative_filename () {
201 if (_relative_filename != null) {
202 return _relative_filename;
203 } else {
204 return Path.get_basename (filename);
209 * Returns the filename to use when generating C source files.
211 * @return generated C source filename
213 public string get_csource_filename () {
214 if (csource_filename == null) {
215 if (context.run_output) {
216 csource_filename = context.output + ".c";
217 } else if (context.ccode_only || context.save_csources) {
218 csource_filename = "%s%s.c".printf (get_destination_directory (), get_basename ());
219 } else {
220 // temporary file
221 csource_filename = "%s%s.vala.c".printf (get_destination_directory (), get_basename ());
224 return csource_filename;
228 * Returns the filename to use when including the generated C header
229 * file.
231 * @return C header filename to include
233 public string get_cinclude_filename () {
234 if (cinclude_filename == null) {
235 if (context.header_filename != null) {
236 cinclude_filename = Path.get_basename (context.header_filename);
237 if (context.includedir != null) {
238 cinclude_filename = "%s/%s".printf (context.includedir, cinclude_filename);
240 } else {
241 cinclude_filename = "%s%s.h".printf (get_subdir (), get_basename ());
244 return cinclude_filename;
248 * Returns the requested line from this file, loading it if needed.
250 * @param lineno 1-based line number
251 * @return the specified source line
253 public string? get_source_line (int lineno) {
254 if (source_array == null) {
255 if (content != null) {
256 read_source_lines (content);
257 } else {
258 read_source_file ();
261 if (lineno < 1 || lineno > source_array.size) {
262 return null;
264 return source_array.get (lineno - 1);
268 * Parses the input file into ::source_array.
270 private void read_source_file () {
271 string cont;
272 try {
273 FileUtils.get_contents (filename, out cont);
274 } catch (FileError fe) {
275 return;
277 read_source_lines (cont);
280 private void read_source_lines (string cont)
282 source_array = new ArrayList<string> ();
283 string[] lines = cont.split ("\n", 0);
284 int idx;
285 for (idx = 0; lines[idx] != null; ++idx) {
286 source_array.add (lines[idx]);
290 public char* get_mapped_contents () {
291 if (content != null) {
292 return (char*) content;
295 if (mapped_file == null) {
296 try {
297 mapped_file = new MappedFile (filename, false);
298 } catch (FileError e) {
299 Report.error (null, "Unable to map file `%s': %s".printf (filename, e.message));
300 return null;
304 return mapped_file.get_contents ();
307 public size_t get_mapped_length () {
308 if (content != null) {
309 return content.length;
312 return mapped_file.get_length ();
315 public bool check (CodeContext context) {
316 foreach (CodeNode node in nodes) {
317 node.check (context);
319 return true;
323 public enum Vala.SourceFileType {
324 NONE,
325 SOURCE,
326 PACKAGE,
327 FAST