/* valasourcefile.vala * * Copyright (C) 2006-2007 Jürg Billeter * * 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 * version 2.1 of the License, or (at your option) any later version. * 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 */ using GLib; using Gee; /** * Represents a Vala source or VAPI package file. */ public class Vala.SourceFile : Object { /** * The name of this source file. */ public string! filename { get; set; } /** * 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; } /** * The context this source file belongs to. */ public weak CodeContext context { get; set; } private Gee.List using_directives = new ArrayList (); private Gee.List nodes = new ArrayList (); private string cheader_filename = null; private string csource_filename = null; private string cinclude_filename = null; private Gee.List header_external_includes = new ArrayList (); private Gee.List header_internal_includes = new ArrayList (); private Gee.List source_external_includes = new ArrayList (); private Gee.List source_internal_includes = new ArrayList (); private Gee.List header_internal_full_dependencies = new ArrayList (); private Gee.List header_internal_dependencies = new ArrayList (); /** * 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 */ public SourceFile (construct CodeContext! context, construct string! filename, construct bool pkg = false) { } /** * Adds a new using directive with the specified namespace. * * @param ns reference to namespace */ public void add_using_directive (NamespaceReference! ns) { using_directives.add (ns); } /** * Returns a copy of the list of using directives. * * @return using directive list */ public Collection get_using_directives () { return new ReadOnlyCollection (using_directives); } /** * Adds the specified code node to this source file. * * @param node a code node */ public void add_node (CodeNode! node) { nodes.add (node); } /** * Returns a copy of the list of code nodes. * * @return code node list */ public Collection get_nodes () { return new ReadOnlyCollection (nodes); } public void accept (CodeVisitor! visitor) { visitor.visit_source_file (this); } public void accept_children (CodeVisitor! visitor) { foreach (NamespaceReference ns_ref in using_directives) { ns_ref.accept (visitor); } foreach (CodeNode node in nodes) { node.accept (visitor); } } 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 ()); } /** * 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 ())); basename = Path.get_basename (basename); cheader_filename = "%s%s.h".printf (get_destination_directory (), basename); } 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 ())); basename = Path.get_basename (basename); csource_filename = "%s%s.c".printf (get_destination_directory (), basename); } return csource_filename; } /** * 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 ())); basename = Path.get_basename (basename); if (context.basedir == null && context.library != null) { // backward-compatibility cinclude_filename = "%s/%s.h".printf (context.library, basename); } else { cinclude_filename = "%s%s.h".printf (get_subdir (), basename); } } return cinclude_filename; } /** * 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) { if (pkg) { return; } Symbol s; if (sym is Typesymbol || sym is Method || sym is Field || sym is Property || sym is Constant) { s = sym; } else if (sym is FormalParameter) { var fp = (FormalParameter) sym; s = fp.type_reference.data_type; if (s == null) { /* generic type parameter */ return; } } else { return; } if (dep_type == SourceFileDependencyType.SOURCE) { if (s.source_reference.file.pkg) { foreach (string fn in s.get_cheader_filenames ()) { source_external_includes.add (fn); } } else { foreach (string fn in s.get_cheader_filenames ()) { source_internal_includes.add (fn); } } return; } if (s.source_reference.file.pkg) { /* external package */ foreach (string fn in s.get_cheader_filenames ()) { header_external_includes.add (fn); } return; } if (dep_type == SourceFileDependencyType.HEADER_FULL || (s is Typesymbol && !((Typesymbol)s).is_reference_type ())) { foreach (string fn in s.get_cheader_filenames ()) { header_internal_includes.add (fn); } header_internal_full_dependencies.add (s.source_reference.file); } header_internal_dependencies.add (s.source_reference.file); } /** * Returns the list of external includes the generated C header file * requires. * * @return external include list for C header file */ public Collection get_header_external_includes () { return new ReadOnlyCollection (header_external_includes); } /** * 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) { /* skip includes to self */ if (include != get_cinclude_filename ()) { header_internal_includes.add (include); } } /** * Returns the list of package-internal includes the generated C header * file requires. * * @return internal include list for C header file */ public Collection get_header_internal_includes () { return new ReadOnlyCollection (header_internal_includes); } /** * Returns the list of external includes the generated C source file * requires. * * @return include list for C source file */ public Collection get_source_external_includes () { return new ReadOnlyCollection (source_external_includes); } /** * Returns the list of package-internal includes the generated C source * file requires. * * @return include list for C source file */ public Collection get_source_internal_includes () { return new ReadOnlyCollection (source_internal_includes); } /** * Returns the list of source files the generated C header file requires * definitely. * * @return definite source file dependencies */ public Collection get_header_internal_full_dependencies () { return new ReadOnlyCollection (header_internal_full_dependencies); } /** * Returns the list of source files the generated C header file loosely * depends on. * * @return loose source file dependencies */ public Collection get_header_internal_dependencies () { return new ReadOnlyCollection (header_internal_dependencies); } } public enum Vala.SourceFileDependencyType { HEADER_FULL, HEADER_SHALLOW, SOURCE }