/* valavapicheck.vala * * Copyright (C) 2007 Mathias Hasselmann * * 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: * Mathias Hasselmann */ using GLib; class Vala.VAPICheck { public VAPICheck (string gidlname, CodeContext context = new CodeContext ()) { gidl = new SourceFile (context, SourceFileType.SOURCE, gidlname); metadata = new SourceFile (context, SourceFileType.SOURCE, gidlname.substring (0, gidlname.length - 5) + ".metadata"); this.context = context; } public CodeContext context { get; private set; } public SourceFile gidl { get; private set; } public SourceFile metadata { get; private set; } private List _scope; private Set _symbols; private void parse_gidl () { _scope = new ArrayList (); _symbols = new HashSet (str_hash, str_equal); try { foreach (weak IdlModule module in Idl.parse_file (gidl.filename)) { parse_members (module.name, module.entries); } } catch (MarkupError e) { printerr ("%s: %s\n", gidl.filename, e.message); } } private void add_symbol (string name, string? separator = null) { if (null != separator) { string fullname = get_scope () + separator + name; _symbols.add (fullname); } else { _symbols.add (name); } } private string get_scope () { return _scope[_scope.size - 1]; } private void enter_scope (string name) { _scope.add (name); add_symbol (name); } private void leave_scope () { _scope.remove_at (_scope.size - 1); } private void parse_members (string name, GLib.List members) { enter_scope (name); foreach (weak IdlNode node in members) { switch (node.type) { case IdlNodeTypeId.ENUM: parse_members (((IdlNodeEnum) node).gtype_name, ((IdlNodeEnum) node).values); break; case IdlNodeTypeId.FUNCTION: parse_members (((IdlNodeFunction) node).symbol, (GLib.List) ((IdlNodeFunction) node).parameters); break; case IdlNodeTypeId.BOXED: parse_members (((IdlNodeBoxed) node).gtype_name, ((IdlNodeBoxed) node).members); break; case IdlNodeTypeId.INTERFACE: case IdlNodeTypeId.OBJECT: parse_members (((IdlNodeInterface) node).gtype_name, ((IdlNodeInterface) node).members); break; case IdlNodeTypeId.FIELD: case IdlNodeTypeId.PARAM: add_symbol (node.name, "."); break; case IdlNodeTypeId.PROPERTY: case IdlNodeTypeId.SIGNAL: add_symbol (node.name, "::"); break; case IdlNodeTypeId.STRUCT: parse_members (node.name, ((IdlNodeStruct) node).members); break; case IdlNodeTypeId.VALUE: case IdlNodeTypeId.VFUNC: // Not applicable? break; default: warning ("TODO: %s: Implement support for type %d nodes", node.name, node.type); break; } } leave_scope (); } private int check_metadata () { try { var metafile = new IOChannel.file (metadata.filename, "r"); string line; int lineno = 1; while (IOStatus.NORMAL == metafile.read_line (out line, null, null)) { var tokens = line.split (" ", 2); var symbol = tokens[0]; if (symbol.length > 0 && !_symbols.contains (symbol)) { var src = new SourceReference (metadata, SourceLocation (null, lineno, 1), SourceLocation (null, lineno, (int)symbol.length)); Report.error (src, "Symbol `%s' not found", symbol); } lineno += 1; } return 0; } catch (Error error) { Report.error (null, "%s: %s", metadata.filename, error.message); return 1; } } public int run () { if (!FileUtils.test (gidl.filename, FileTest.IS_REGULAR)) { Report.error (null, "%s not found", gidl.filename); return 2; } if (!FileUtils.test (metadata.filename, FileTest.IS_REGULAR)) { Report.error (null, "%s not found", metadata.filename); return 2; } parse_gidl (); return check_metadata (); } static int main (string[] args) { if (2 != args.length || !args[1].has_suffix (".gidl")) { print ("Usage: %s library.gidl\n", Path.get_basename (args[0])); return 2; } var vapicheck = new VAPICheck (args[1]); return vapicheck.run (); } }