valasourcefile.vala 9.74 KB
Newer Older
1 2
/* valasourcefile.vala
 *
3
 * Copyright (C) 2006-2007  Jürg Billeter
4 5 6 7
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
8
 * version 2.1 of the License, or (at your option) any later version.
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23

 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.

 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
 *
 * Author:
 * 	Jürg Billeter <j@bitron.ch>
 */

using GLib;
24
using Gee;
25

26 27 28
/**
 * Represents a Vala source or VAPI package file.
 */
29
public class Vala.SourceFile : Object {
30 31 32
	/**
	 * The name of this source file.
	 */
33
	public string! filename { get; set; }
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
	
	/**
	 * The header comment of this source file.
	 */
	public string comment { get; set; }
	
	/**
	 * Specifies whether this file is a VAPI package file.
	 */
	public bool pkg { get; set; }
	
	/**
	 * Specifies the dependency cycle this source file is member of. If this
	 * source file is in a cycle, all type definitions of that cycle will
	 * only be written to the C header file of the cycle head.
	 */
	public SourceFileCycle cycle { get; set; }
	
	/**
	 * Specifies whether this source file is the head of the cycle, if it is
	 * in a cycle at all.
	 */
	public bool is_cycle_head { get; set; }
	
	/**
	 * Mark used for cycle detection.
	 *
	 * 0: not yet visited
	 * 1: currently visiting
	 * 2: already visited
	 */
	public int mark { get; set; }
	
67 68 69 70
	/**
	 * The context this source file belongs to.
	 */
	public weak CodeContext context { get; set; }
71

72
	private Gee.List<NamespaceReference> using_directives = new ArrayList<NamespaceReference> ();
73

74
	private Gee.List<CodeNode> nodes = new ArrayList<CodeNode> ();
75 76 77
	
	private string cheader_filename = null;
	private string csource_filename = null;
78
	private string cinclude_filename = null;
79
	
80 81 82 83
	private Gee.List<string> header_external_includes = new ArrayList<string> ();
	private Gee.List<string> header_internal_includes = new ArrayList<string> ();
	private Gee.List<string> source_external_includes = new ArrayList<string> ();
	private Gee.List<string> source_internal_includes = new ArrayList<string> ();
84
	
85 86
	private Gee.List<weak SourceFile> header_internal_full_dependencies = new ArrayList<weak SourceFile> ();
	private Gee.List<weak SourceFile> header_internal_dependencies = new ArrayList<weak SourceFile> ();
87
	
88 89 90 91 92 93 94
	/**
	 * Creates a new source file.
	 *
	 * @param filename source file name
	 * @param pkg      true if this is a VAPI package file
	 * @return         newly created source file
	 */
95
	public SourceFile (construct CodeContext! context, construct string! filename, construct bool pkg = false) {
96 97
	}
	
98 99 100 101 102 103
	/**
	 * Adds a new using directive with the specified namespace.
	 *
	 * @param ns reference to namespace
	 */
	public void add_using_directive (NamespaceReference! ns) {
104
		using_directives.add (ns);
105 106 107 108 109 110 111
	}
	
	/**
	 * Returns a copy of the list of using directives.
	 *
	 * @return using directive list
	 */
112 113
	public Collection<NamespaceReference> get_using_directives () {
		return new ReadOnlyCollection<NamespaceReference> (using_directives);
114 115 116
	}
	
	/**
117
	 * Adds the specified code node to this source file.
118
	 *
119
	 * @param node a code node
120
	 */
121
	public void add_node (CodeNode! node) {
122
		nodes.add (node);
123
	}
124

125
	/**
126
	 * Returns a copy of the list of code nodes.
127
	 *
128
	 * @return code node list
129
	 */
130 131
	public Collection<CodeNode> get_nodes () {
		return new ReadOnlyCollection<CodeNode> (nodes);
132
	}
133

134
	public void accept (CodeVisitor! visitor) {
135 136
		visitor.visit_source_file (this);
	}
137

138
	public void accept_children (CodeVisitor! visitor) {
139 140
		foreach (NamespaceReference ns_ref in using_directives) {
			ns_ref.accept (visitor);
141 142
		}
		
143 144
		foreach (CodeNode node in nodes) {
			node.accept (visitor);
145
		}
146
	}
147

148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
	private string! get_subdir () {
		if (context.basedir == null) {
			return "";
		}

		// filename and basedir are already canonicalized
		if (filename.has_prefix (context.basedir)) {
			var basename = Path.get_basename (filename);
			var subdir = filename.substring (context.basedir.len (), filename.len () - context.basedir.len () - basename.len ());
			while (subdir[0] == '/') {
				subdir = subdir.offset (1);
			}
			return subdir;
		}
		return "";
	}

	private string! get_destination_directory () {
		if (context.directory == null) {
			return get_subdir ();
		}
		return "%s/%s".printf (context.directory, get_subdir ());
	}

172 173 174 175 176 177 178 179
	/**
	 * Returns the filename to use when generating C header files.
	 *
	 * @return generated C header filename
	 */
	public string! get_cheader_filename () {
		if (cheader_filename == null) {
			var basename = filename.ndup ((uint) (filename.len () - ".vala".len ()));
180
			basename = Path.get_basename (basename);
181
			cheader_filename = "%s%s.h".printf (get_destination_directory (), basename);
182
		}
183 184 185 186 187 188 189 190 191 192 193
		return cheader_filename;
	}
	
	/**
	 * Returns the filename to use when generating C source files.
	 *
	 * @return generated C source filename
	 */
	public string! get_csource_filename () {
		if (csource_filename == null) {
			var basename = filename.ndup ((uint) (filename.len () - ".vala".len ()));
194
			basename = Path.get_basename (basename);
195
			csource_filename = "%s%s.c".printf (get_destination_directory (), basename);
196 197 198
		}
		return csource_filename;
	}
199

200 201 202 203 204 205 206 207 208
	/**
	 * Returns the filename to use when including the generated C header
	 * file.
	 *
	 * @return C header filename to include
	 */
	public string! get_cinclude_filename () {
		if (cinclude_filename == null) {
			var basename = filename.ndup ((uint) (filename.len () - ".vala".len ()));
209
			basename = Path.get_basename (basename);
210 211
			if (context.basedir == null && context.library != null) {
				// backward-compatibility
212 213
				cinclude_filename = "%s/%s.h".printf (context.library, basename);
			} else {
214
				cinclude_filename = "%s%s.h".printf (get_subdir (), basename);
215 216 217 218 219
			}
		}
		return cinclude_filename;
	}
	
220 221 222 223 224 225 226 227
	/**
	 * Adds the specified symbol to the list of symbols code in this source
	 * file depends on.
	 *
	 * @param sym      a symbol
	 * @param dep_type type of dependency
	 */
	public void add_symbol_dependency (Symbol! sym, SourceFileDependencyType dep_type) {
228 229 230 231
		if (pkg) {
			return;
		}

232
		Symbol s;
233
		
234 235 236 237 238 239
		if (sym is DataType ||
		    sym is Method ||
		    sym is Field ||
		    sym is Property ||
		    sym is Constant) {
			s = sym;
240 241
		} else if (sym is FormalParameter) {
			var fp = (FormalParameter) sym;
242 243
			s = fp.type_reference.data_type;
			if (s == null) {
244
				/* generic type parameter */
245 246
				return;
			}
247 248 249 250 251
		} else {
			return;
		}
		
		if (dep_type == SourceFileDependencyType.SOURCE) {
252
			if (s.source_reference.file.pkg) {
253
				foreach (string fn in s.get_cheader_filenames ()) {
254
					source_external_includes.add (fn);
255
				}
256
			} else {
257
				foreach (string fn in s.get_cheader_filenames ()) {
258
					source_internal_includes.add (fn);
259
				}
260
			}
261 262
			return;
		}
263

264
		if (s.source_reference.file.pkg) {
265
			/* external package */
266
			foreach (string fn in s.get_cheader_filenames ()) {
267
				header_external_includes.add (fn);
268
			}
269 270 271
			return;
		}
		
272
		if (dep_type == SourceFileDependencyType.HEADER_FULL || (s is DataType && !((DataType)s).is_reference_type ())) {
273
			foreach (string fn in s.get_cheader_filenames ()) {
274
				header_internal_includes.add (fn);
275
			}
276
			header_internal_full_dependencies.add (s.source_reference.file);
277
		}
278

279
		header_internal_dependencies.add (s.source_reference.file);
280 281 282
	}

	/**
283
	 * Returns the list of external includes the generated C header file
284 285 286 287
	 * requires.
	 *
	 * @return external include list for C header file
	 */
288 289
	public Collection<string> get_header_external_includes () {
		return new ReadOnlyCollection<string> (header_external_includes);
290 291 292 293 294 295 296 297 298
	}
	
	/**
	 * Adds the specified filename to the list of package-internal includes
	 * the generated C header file requires.
	 *
	 * @param include internal include for C header file
	 */
	public void add_header_internal_include (string! include) {
299 300
		/* skip includes to self */
		if (include != get_cinclude_filename ()) {
301
			header_internal_includes.add (include);
302
		}
303 304 305
	}
	
	/**
306 307
	 * Returns the list of package-internal includes the generated C header
	 * file requires.
308 309 310
	 *
	 * @return internal include list for C header file
	 */
311 312
	public Collection<string> get_header_internal_includes () {
		return new ReadOnlyCollection<string> (header_internal_includes);
313 314 315
	}
	
	/**
316 317 318 319 320
	 * Returns the list of external includes the generated C source file
	 * requires.
	 *
	 * @return include list for C source file
	 */
321 322
	public Collection<string> get_source_external_includes () {
		return new ReadOnlyCollection<string> (source_external_includes);
323 324 325 326 327
	}
	
	/**
	 * Returns the list of package-internal includes the generated C source
	 * file requires.
328 329 330
	 *
	 * @return include list for C source file
	 */
331 332
	public Collection<string> get_source_internal_includes () {
		return new ReadOnlyCollection<string> (source_internal_includes);
333
	}
334
	
335 336 337 338 339 340
	/**
	 * Returns the list of source files the generated C header file requires
	 * definitely.
	 *
	 * @return definite source file dependencies
	 */
341 342
	public Collection<weak SourceFile> get_header_internal_full_dependencies () {
		return new ReadOnlyCollection<weak SourceFile> (header_internal_full_dependencies);
343
	}
344 345 346 347 348 349 350
	
	/**
	 * Returns the list of source files the generated C header file loosely
	 * depends on.
	 *
	 * @return loose source file dependencies
	 */
351 352
	public Collection<weak SourceFile> get_header_internal_dependencies () {
		return new ReadOnlyCollection<weak SourceFile> (header_internal_dependencies);
353 354 355 356 357 358 359
	}
}

public enum Vala.SourceFileDependencyType {
	HEADER_FULL,
	HEADER_SHALLOW,
	SOURCE
360
}