[vala/wip/x-version: 1/24] Introduce [Version (...)]



commit b1cb07d5d80bd713cffc8c2a92f2329c85ee326f
Author: Florian Brosch <flo brosch gmail com>
Date:   Thu Jul 10 20:35:22 2014 +0200

    Introduce [Version (...)]
    
    Parameters:
     since: string, version number
     experimental: bool (was: [Experimental])
     experimental_until: string, version number
     deprecated_since: string, version number (was: [Deprecated (since="")])
     replacement: string, symbol name (was: [Deprecated (replacement="")])
     deprecated: bool (was: [Deprecated])
    
    Used symbols labeled with [Version (since = "")] are checked
    against the locally installed package version.
    
    Use --disable-since-check to avoid this behaviour.
    
    Fixes bug 678912.

 codegen/valaccodebasemodule.vala       |    6 +-
 codegen/valaccodedelegatemodule.vala   |    2 +-
 codegen/valaccodemethodmodule.vala     |    2 +-
 codegen/valaccodestructmodule.vala     |    4 +-
 codegen/valagirwriter.vala             |   11 +-
 compiler/valacompiler.vala             |    3 +
 vala/Makefile.am                       |    1 +
 vala/valaclass.vala                    |    6 +-
 vala/valacodecontext.vala              |    5 +
 vala/valacodewriter.vala               |   20 +++
 vala/valagirparser.vala                |   17 ++-
 vala/valalambdaexpression.vala         |    3 +-
 vala/valamemberaccess.vala             |    3 +-
 vala/valaobjectcreationexpression.vala |    2 +-
 vala/valasourcefile.vala               |   64 +++++++++
 vala/valasymbol.vala                   |  104 +++------------
 vala/valaversionattribute.vala         |  231 ++++++++++++++++++++++++++++++++
 vapigen/valagidlparser.vala            |  116 ++++++++--------
 18 files changed, 430 insertions(+), 170 deletions(-)
---
diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala
index e1c6a63..f22b626 100644
--- a/codegen/valaccodebasemodule.vala
+++ b/codegen/valaccodebasemodule.vala
@@ -788,7 +788,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
 
                var cenum = new CCodeEnum (get_ccode_name (en));
 
-               cenum.deprecated = en.deprecated;
+               cenum.deprecated = en.version.deprecated;
 
                int flag_shift = 0;
                foreach (EnumValue ev in en.get_values ()) {
@@ -803,7 +803,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                                ev.value.emit (this);
                                c_ev = new CCodeEnumValue (get_ccode_name (ev), get_cvalue (ev.value));
                        }
-                       c_ev.deprecated = ev.deprecated;
+                       c_ev.deprecated = ev.version.deprecated;
                        cenum.add_value (c_ev);
                }
 
@@ -1003,7 +1003,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                } else {
                        cdecl.modifiers = CCodeModifiers.EXTERN;
                }
-               if (f.deprecated) {
+               if (f.version.deprecated) {
                        cdecl.modifiers |= CCodeModifiers.DEPRECATED;
                }
                decl_space.add_type_member_declaration (cdecl);
diff --git a/codegen/valaccodedelegatemodule.vala b/codegen/valaccodedelegatemodule.vala
index 744f63a..346f0a2 100644
--- a/codegen/valaccodedelegatemodule.vala
+++ b/codegen/valaccodedelegatemodule.vala
@@ -116,7 +116,7 @@ public class Vala.CCodeDelegateModule : CCodeArrayModule {
                }
 
                var ctypedef = new CCodeTypeDefinition (return_type_cname, cfundecl);
-               ctypedef.deprecated = d.deprecated;
+               ctypedef.deprecated = d.version.deprecated;
 
                decl_space.add_type_definition (ctypedef);
        }
diff --git a/codegen/valaccodemethodmodule.vala b/codegen/valaccodemethodmodule.vala
index dc70a58..49f99cc 100644
--- a/codegen/valaccodemethodmodule.vala
+++ b/codegen/valaccodemethodmodule.vala
@@ -169,7 +169,7 @@ public abstract class Vala.CCodeMethodModule : CCodeStructModule {
                        function.modifiers |= CCodeModifiers.INTERNAL;
                }
 
-               if (m.deprecated) {
+               if (m.version.deprecated) {
                        function.modifiers |= CCodeModifiers.DEPRECATED;
                }
 
diff --git a/codegen/valaccodestructmodule.vala b/codegen/valaccodestructmodule.vala
index fe2a7c2..3f226d5 100644
--- a/codegen/valaccodestructmodule.vala
+++ b/codegen/valaccodestructmodule.vala
@@ -64,7 +64,7 @@ public abstract class Vala.CCodeStructModule : CCodeBaseModule {
                }
 
                var instance_struct = new CCodeStruct ("_%s".printf (get_ccode_name (st)));
-               instance_struct.deprecated = st.deprecated;
+               instance_struct.deprecated = st.version.deprecated;
 
                foreach (Field f in st.get_fields ()) {
                        string field_ctype = get_ccode_name (f.variable_type);
@@ -77,7 +77,7 @@ public abstract class Vala.CCodeStructModule : CCodeBaseModule {
 
                                var suffix = get_ccode_declarator_suffix (f.variable_type);
                                if (suffix != null) {
-                                       suffix.deprecated = f.deprecated;
+                                       suffix.deprecated = f.version.deprecated;
                                }
 
                                instance_struct.add_field (field_ctype, get_ccode_name (f), suffix);
diff --git a/codegen/valagirwriter.vala b/codegen/valagirwriter.vala
index f0a75e2..258f910 100644
--- a/codegen/valagirwriter.vala
+++ b/codegen/valagirwriter.vala
@@ -277,12 +277,15 @@ public class Vala.GIRWriter : CodeVisitor {
        }
 
        private void write_symbol_attributes (Symbol symbol) {
-               if (symbol.deprecated) {
-                       buffer.append_printf (" deprecated=\"%s\"", (symbol.replacement == null) ? "" : "Use 
%s".printf (symbol.replacement));
-                       if (symbol.deprecated_since != null) {
-                               buffer.append_printf (" deprecated-version=\"%s\"", symbol.deprecated_since);
+               if (symbol.version.deprecated) {
+                       buffer.append_printf (" deprecated=\"%s\"", (symbol.version.replacement == null) ? "" 
: "Use %s".printf (symbol.version.replacement));
+                       if (symbol.version.deprecated_since != null) {
+                               buffer.append_printf (" deprecated-version=\"%s\"", 
symbol.version.deprecated_since);
                        }
                }
+               if (symbol.version.since != null) {
+                       buffer.append_printf (" version=\"%s\"", symbol.version.since);
+               }
        }
 
        public override void visit_class (Class cl) {
diff --git a/compiler/valacompiler.vala b/compiler/valacompiler.vala
index fe0fdb9..3c008d3 100644
--- a/compiler/valacompiler.vala
+++ b/compiler/valacompiler.vala
@@ -70,6 +70,7 @@ class Vala.Compiler {
        static bool experimental;
        static bool experimental_non_null;
        static bool gobject_tracing;
+       static bool disable_since_check;
        static bool disable_warnings;
        static string cc_command;
        [CCode (array_length = false, array_null_terminated = true)]
@@ -133,6 +134,7 @@ class Vala.Compiler {
                { "enable-experimental", 0, 0, OptionArg.NONE, ref experimental, "Enable experimental 
features", null },
                { "disable-warnings", 0, 0, OptionArg.NONE, ref disable_warnings, "Disable warnings", null },
                { "fatal-warnings", 0, 0, OptionArg.NONE, ref fatal_warnings, "Treat warnings as fatal", null 
},
+               { "disable-since-check", 0, 0, OptionArg.NONE, ref disable_since_check, "Do not check whether 
used symbols exist in local packages", null },
                { "enable-experimental-non-null", 0, 0, OptionArg.NONE, ref experimental_non_null, "Enable 
experimental enhancements for non-null types", null },
                { "enable-gobject-tracing", 0, 0, OptionArg.NONE, ref gobject_tracing, "Enable GObject 
creation tracing", null },
                { "cc", 0, 0, OptionArg.STRING, ref cc_command, "Use COMMAND as C compiler command", 
"COMMAND" },
@@ -197,6 +199,7 @@ class Vala.Compiler {
                context.assert = !disable_assert;
                context.checking = enable_checking;
                context.deprecated = deprecated;
+               context.since_check = !disable_since_check;
                context.hide_internal = hide_internal;
                context.experimental = experimental;
                context.experimental_non_null = experimental_non_null;
diff --git a/vala/Makefile.am b/vala/Makefile.am
index a5a99d1..bd16142 100644
--- a/vala/Makefile.am
+++ b/vala/Makefile.am
@@ -160,6 +160,7 @@ libvalacore_la_VALASOURCES = \
        valausingdirective.vala \
        valavaluetype.vala \
        valavariable.vala \
+       valaversionattribute.vala \
        valavoidtype.vala \
        valawhilestatement.vala \
        valayieldstatement.vala \
diff --git a/vala/valaclass.vala b/vala/valaclass.vala
index 12a82af..61a02ac 100644
--- a/vala/valaclass.vala
+++ b/vala/valaclass.vala
@@ -793,8 +793,7 @@ public class Vala.Class : ObjectTypeSymbol {
                                                                foreach (var impl in base_class.get_methods 
()) {
                                                                        if (impl.name == m.name && 
(impl.base_interface_type == null || impl.base_interface_type.data_type == iface)) {
                                                                                // method is used as 
interface implementation, so it is not unused
-                                                                               impl.check_deprecated 
(source_reference);
-                                                                               impl.check_experimental 
(source_reference);
+                                                                               impl.version.check 
(source_reference);
                                                                                impl.used = true;
                                                                                implemented = true;
                                                                                break;
@@ -820,8 +819,7 @@ public class Vala.Class : ObjectTypeSymbol {
                                                        }
                                                        if (sym is Property) {
                                                                // property is used as interface 
implementation, so it is not unused
-                                                               sym.check_deprecated (source_reference);
-                                                               sym.check_experimental (source_reference);
+                                                               sym.version.check (source_reference);
                                                                sym.used = true;
                                                        } else {
                                                                error = true;
diff --git a/vala/valacodecontext.vala b/vala/valacodecontext.vala
index b9ac824..0906b48 100644
--- a/vala/valacodecontext.vala
+++ b/vala/valacodecontext.vala
@@ -47,6 +47,11 @@ public class Vala.CodeContext {
        public bool hide_internal { get; set; }
 
        /**
+        * Do not check whether used symbols exist in local packages.
+        */
+       public bool since_check { get; set; }
+
+       /**
         * Do not warn when using experimental features.
         */
        public bool experimental { get; set; }
diff --git a/vala/valacodewriter.vala b/vala/valacodewriter.vala
index 2fce86f..ec48ed0 100644
--- a/vala/valacodewriter.vala
+++ b/vala/valacodewriter.vala
@@ -1615,6 +1615,19 @@ public class Vala.CodeWriter : CodeVisitor {
                }
        }
 
+       private bool skip_since_tag_check (Symbol sym, string since_val) {
+               Symbol parent_symbol = sym;
+
+               while (parent_symbol.parent_symbol != null) {
+                       parent_symbol = parent_symbol.parent_symbol;
+                       if (parent_symbol.version.since == since_val) {
+                               return true;
+                       }
+               }
+
+               return false;
+       }
+
        private void write_attributes (CodeNode node) {
                var sym = node as Symbol;
 
@@ -1649,6 +1662,13 @@ public class Vala.CodeWriter : CodeVisitor {
                                continue;
                        }
 
+                       if (sym != null && attr.args.size == 1 && attr.name == "Version") {
+                               string since_val = attr.get_string ("since");
+                               if (since_val != null && skip_since_tag_check (sym, since_val)) {
+                                       continue;
+                               }
+                       }
+
                        if (!(node is Parameter) && !(node is PropertyAccessor)) {
                                write_indent ();
                        }
diff --git a/vala/valagirparser.vala b/vala/valagirparser.vala
index 9d8ef15..b50a16c 100644
--- a/vala/valagirparser.vala
+++ b/vala/valagirparser.vala
@@ -52,6 +52,7 @@ public class Vala.GirParser : CodeVisitor {
                DEPRECATED,
                REPLACEMENT,
                DEPRECATED_SINCE,
+               SINCE,
                ARRAY,
                ARRAY_LENGTH_IDX,
                ARRAY_NULL_TERMINATED,
@@ -1138,7 +1139,14 @@ public class Vala.GirParser : CodeVisitor {
 
                                // experimental
                                if (metadata.has_argument (ArgumentType.EXPERIMENTAL)) {
-                                       symbol.set_attribute ("Experimental", metadata.get_bool 
(ArgumentType.EXPERIMENTAL));
+                                       symbol.set_attribute_bool ("Version", "experimental", 
metadata.get_bool (ArgumentType.EXPERIMENTAL));
+                               }
+
+                               // since
+                               if (metadata.has_argument (ArgumentType.SINCE)) {
+                                       symbol.version.since = metadata.get_string (ArgumentType.SINCE);
+                               } else if (symbol is Namespace == false && girdata["version"] != null) {
+                                       symbol.version.since = girdata.get ("version");
                                }
 
                                if (parent.symbol is Namespace) {
@@ -1178,13 +1186,13 @@ public class Vala.GirParser : CodeVisitor {
                                                }
                                        }
                                        if (node.deprecated) {
-                                               node.symbol.set_attribute ("Deprecated", true);
+                                               node.symbol.version.deprecated = true;
                                        }
                                        if (node.deprecated_since != null) {
-                                               node.symbol.set_attribute_string ("Deprecated", "since", 
node.deprecated_since);
+                                               node.symbol.version.deprecated_since = node.deprecated_since;
                                        }
                                        if (node.deprecated_replacement != null) {
-                                               node.symbol.set_attribute_string ("Deprecated", 
"replacement", node.deprecated_replacement);
+                                               node.symbol.version.replacement = node.deprecated_replacement;
                                        }
 
                                        if (node.new_symbol && !node.merged && !metadata.get_bool 
(ArgumentType.HIDDEN)) {
@@ -1829,6 +1837,7 @@ public class Vala.GirParser : CodeVisitor {
                                parse_include ();
                        } else if (reader.name == "package") {
                                var pkg = parse_package ();
+                               this.current_source_file.package_name = pkg;
                                if (context.has_package (pkg)) {
                                        // package already provided elsewhere, stop parsing this GIR
                                        return;
diff --git a/vala/valalambdaexpression.vala b/vala/valalambdaexpression.vala
index 6918710..1d6f957 100644
--- a/vala/valalambdaexpression.vala
+++ b/vala/valalambdaexpression.vala
@@ -137,8 +137,7 @@ public class Vala.LambdaExpression : Expression {
                method = new Method (get_lambda_name (context), return_type, source_reference);
                // track usage for flow analyzer
                method.used = true;
-               method.check_deprecated (source_reference);
-               method.check_experimental (source_reference);
+               method.version.check (source_reference);
 
                if (!cb.has_target || !context.analyzer.is_in_instance_method ()) {
                        method.binding = MemberBinding.STATIC;
diff --git a/vala/valamemberaccess.vala b/vala/valamemberaccess.vala
index 26a413c..2bab0b0 100644
--- a/vala/valamemberaccess.vala
+++ b/vala/valamemberaccess.vala
@@ -694,8 +694,7 @@ public class Vala.MemberAccess : Expression {
                }
 
                member.used = true;
-               member.check_deprecated (source_reference);
-               member.check_experimental (source_reference);
+               member.version.check (source_reference);
 
                if (access == SymbolAccessibility.PROTECTED) {
                        var target_type = (TypeSymbol) member.parent_symbol;
diff --git a/vala/valaobjectcreationexpression.vala b/vala/valaobjectcreationexpression.vala
index 6b18efd..954f77c 100644
--- a/vala/valaobjectcreationexpression.vala
+++ b/vala/valaobjectcreationexpression.vala
@@ -257,7 +257,7 @@ public class Vala.ObjectCreationExpression : Expression {
 
                                // track usage for flow analyzer
                                symbol_reference.used = true;
-                               symbol_reference.check_deprecated (source_reference);
+                               symbol_reference.version.check (source_reference);
                        }
 
                        if (symbol_reference != null && symbol_reference.access == 
SymbolAccessibility.PRIVATE) {
diff --git a/vala/valasourcefile.vala b/vala/valasourcefile.vala
index e925a6b..f02d844 100644
--- a/vala/valasourcefile.vala
+++ b/vala/valasourcefile.vala
@@ -37,6 +37,70 @@ public class Vala.SourceFile {
                }
        }
 
+       private string _package_name;
+
+       public string? package_name {
+               get {
+                       if (file_type != SourceFileType.PACKAGE) {
+                               return null;
+                       }
+
+                       if (_package_name == null) {
+                               _package_name = Path.get_basename (filename[0:filename.last_index_of_char 
('.')]);
+                       }
+
+                       return _package_name;
+               }
+               set {
+                       _package_name = value;
+               }
+       }
+
+       private string? _installed_version = null;
+       private bool _version_requested = false;
+
+       /**
+        * The installed package version or null
+        */
+       public string? installed_version {
+               get {
+                       if (_version_requested) {
+                               return _installed_version;
+                       }
+
+                       _version_requested = true;
+
+                       string pkg_config_name = package_name;
+                       if (pkg_config_name == null) {
+                               return null;
+                       }
+
+                       string? standard_output;
+                       int exit_status;
+
+                       try {
+                               Process.spawn_command_line_sync ("pkg-config --silence-errors --modversion 
%s".printf (pkg_config_name), out standard_output, null, out exit_status);
+                               if (exit_status != 0) {
+                                       return null;
+                               }
+                       } catch (GLib.SpawnError err) {
+                               return null;
+                       }
+
+                       standard_output = standard_output[0:-1];
+                       if (standard_output != "") {
+                               _installed_version = standard_output;
+                       }
+
+                       return _installed_version;
+               }
+               set {
+                       _version_requested = value != null;
+                       _installed_version = value;
+               }
+       }
+
+
        /**
         * Specifies whether this file is a VAPI package file.
         */
diff --git a/vala/valasymbol.vala b/vala/valasymbol.vala
index cc92116..6d0c963 100644
--- a/vala/valasymbol.vala
+++ b/vala/valasymbol.vala
@@ -68,62 +68,6 @@ public abstract class Vala.Symbol : CodeNode {
        public bool active { get; set; default = true; }
 
        /**
-        * Specifies whether this symbol has been deprecated.
-        */
-       public bool deprecated {
-               get {
-                       if (_deprecated == null) {
-                               _deprecated = get_attribute ("Deprecated") != null;
-                       }
-                       return _deprecated;
-               }
-               set {
-                       _deprecated = value;
-                       set_attribute ("Deprecated", _deprecated);
-               }
-       }
-
-       /**
-        * Specifies what version this symbol has been deprecated since.
-        */
-       public string? deprecated_since {
-               owned get {
-                       return get_attribute_string ("Deprecated", "since");
-               }
-               set {
-                       set_attribute_string ("Deprecated", "since", value);
-               }
-       }
-
-       /**
-        * Specifies the replacement if this symbol has been deprecated.
-        */
-       public string? replacement {
-               owned get {
-                       return get_attribute_string ("Deprecated", "replacement");
-               }
-               set {
-                       set_attribute_string ("Deprecated", "replacement", value);
-               }
-       }
-
-       /**
-        * Specifies whether this symbol is experimental.
-        */
-       public bool experimental {
-               get {
-                       if (_experimental == null) {
-                               _experimental = get_attribute ("Experimental") != null;
-                       }
-                       return _experimental;
-               }
-               set {
-                       _experimental = value;
-                       set_attribute ("Experimental", value);
-               }
-       }
-
-       /**
         * Specifies whether this symbol has been accessed.
         */
        public bool used { get; set; }
@@ -138,6 +82,22 @@ public abstract class Vala.Symbol : CodeNode {
 
        public Comment? comment { get; set; }
 
+
+       private VersionAttribute _version;
+
+       /**
+        * The associated [Version] attribute
+        */
+       public VersionAttribute version {
+               get {
+                       if (_version == null) {
+                               _version = new VersionAttribute (this);
+                       }
+
+                       return _version;
+               }
+       }
+
        /**
         * Specifies whether this method explicitly hides a member of a base
         * type.
@@ -228,8 +188,6 @@ public abstract class Vala.Symbol : CodeNode {
 
        private weak Scope _owner;
        private Scope _scope;
-       private bool? _deprecated;
-       private bool? _experimental;
 
        public Symbol (string? name, SourceReference? source_reference, Comment? comment = null) {
                this.name = name;
@@ -413,36 +371,6 @@ public abstract class Vala.Symbol : CodeNode {
                return isclass;
        }
 
-       /**
-        * Check to see if the symbol has been deprecated, and emit a warning
-        * if it has.
-        */
-       public bool check_deprecated (SourceReference? source_ref = null) {
-               if (external_package && deprecated) {
-                       if (!CodeContext.get ().deprecated) {
-                               Report.deprecated (source_ref, "%s %s%s".printf (get_full_name (), 
(deprecated_since == null) ? "is deprecated" : "has been deprecated since %s".printf (deprecated_since), 
(replacement == null) ? "" : ". Use %s".printf (replacement)));
-                       }
-                       return true;
-               } else {
-                       return false;
-               }
-       }
-
-       /**
-        * Check to see if the symbol is experimental, and emit a warning
-        * if it is.
-        */
-       public bool check_experimental (SourceReference? source_ref = null) {
-               if (external_package && experimental) {
-                       if (!CodeContext.get ().experimental) {
-                               Report.experimental (source_ref, "%s is experimental".printf (get_full_name 
()));
-                       }
-                       return true;
-               } else {
-                       return false;
-               }
-       }
-
        public Symbol? get_hidden_member () {
                Symbol sym = null;
 
diff --git a/vala/valaversionattribute.vala b/vala/valaversionattribute.vala
new file mode 100644
index 0000000..9c3df39
--- /dev/null
+++ b/vala/valaversionattribute.vala
@@ -0,0 +1,231 @@
+/* valaversionattribute.vala
+ *
+ * Copyright (C) 2013  Florian Brosch
+ *
+ * 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:
+ *     Florian Brosch <flo brosch gmail com>
+ */
+
+using GLib;
+
+
+/**
+ * Represents a [Version] attribute
+ */
+public class Vala.VersionAttribute {
+       private weak Symbol symbol;
+
+       private bool? _deprecated;
+       private bool? _experimental;
+
+       /**
+        * Constructs a new VersionAttribute.
+        *
+        * @param symbol the owner
+        * @return a new VersionAttribute
+        * @see Vala.Symbol
+        */
+       public VersionAttribute (Symbol symbol) {
+               this.symbol = symbol;
+       }
+
+
+
+       /**
+        * Specifies whether this symbol has been deprecated.
+        */
+       public bool deprecated {
+               get {
+                       if (_deprecated == null) {
+                               _deprecated = symbol.get_attribute_bool ("Version", "deprecated", false)
+                                       || symbol.get_attribute_string ("Version", "deprecated_since") != null
+                                       || symbol.get_attribute_string ("Version", "replacement") != null
+                                       // [Deprecated] is deprecated
+                                       || symbol.get_attribute ("Deprecated") != null;
+                       }
+                       return _deprecated;
+               }
+               set {
+                       _deprecated = value;
+                       symbol.set_attribute_bool ("Version", "deprecated", _deprecated);
+               }
+       }
+
+       /**
+        * Specifies what version this symbol has been deprecated since.
+        */
+       public string? deprecated_since {
+               owned get {
+                       return symbol.get_attribute_string ("Version", "deprecated_since")
+                               // [Deprecated] is deprecated
+                               ?? symbol.get_attribute_string ("Deprecated", "since");
+               }
+               set {
+                       symbol.set_attribute_string ("Version", "deprecated_since", value);
+               }
+       }
+
+       /**
+        * Specifies the replacement if this symbol has been deprecated.
+        */
+       public string? replacement {
+               owned get {
+                       return symbol.get_attribute_string ("Version", "replacement")
+                               // [Deprecated] is deprecated
+                               ?? symbol.get_attribute_string ("Deprecated", "replacement");
+               }
+               set {
+                       symbol.set_attribute_string ("Version", "replacement", value);
+               }
+       }
+
+
+
+       /**
+        * Specifies whether this symbol is experimental.
+        */
+       public bool experimental {
+               get {
+                       if (_experimental == null) {
+                               _experimental = symbol.get_attribute_bool ("Version", "experimental", false)
+                                       || symbol.get_attribute_string ("Version", "experimental_until") != 
null
+                                       || symbol.get_attribute ("Experimental") != null;
+                       }
+                       return _experimental;
+               }
+               set {
+                       _experimental = value;
+                       symbol.set_attribute_bool ("Version", "experimental", value);
+               }
+       }
+
+       /**
+        * Specifies until which version this symbol is experimental.
+        */
+       public string? experimental_until {
+               owned get {
+                       return symbol.get_attribute_string ("Version", "experimental_until");
+               }
+               set {
+                       symbol.set_attribute_string ("Version", "experimental_until", value);
+               }
+       }
+
+
+
+       /**
+        * The minimum version for { link Vala.VersionAttribute.symbol}
+        */
+       public string? since {
+               owned get {
+                       return symbol.get_attribute_string ("Version", "since");
+               }
+               set {
+                       symbol.set_attribute_string ("Version", "since", value);
+               }
+       }
+
+
+
+       /**
+        * Check to see if the symbol is experimental, deprecated or not available
+        * and emit a warning if it is.
+        */
+       public bool check (SourceReference? source_ref = null) {
+               bool result = false;
+
+               // deprecation:
+               if (symbol.external_package && deprecated) {
+                       if (!CodeContext.get ().deprecated) {
+                               Report.deprecated (source_ref, "%s %s%s".printf (symbol.get_full_name (), 
(deprecated_since == null) ? "is deprecated" : "has been deprecated since %s".printf (deprecated_since), 
(replacement == null) ? "" : ". Use %s".printf (replacement)));
+                       }
+                       result = true;
+               }
+
+               // availability:
+               if (symbol.external_package && since != null) {
+                       string? package_version = symbol.source_reference.file.installed_version;
+
+                       if (CodeContext.get ().since_check && package_version != null && 
VersionAttribute.cmp_versions (package_version, since) < 0) {
+                               unowned string filename = symbol.source_reference.file.filename;
+                               string pkg = Path.get_basename (filename[0:filename.last_index_of_char 
('.')]);
+                               Report.error (source_ref, "%s is not available in %s %s. Use %s >= %s".printf 
(symbol.get_full_name (), pkg, package_version, pkg, since));
+                       }
+                       result = true;
+               }
+
+               // experimental:
+               if (symbol.external_package && experimental) {
+                       if (!CodeContext.get ().experimental) {
+                               string? package_version = symbol.source_reference.file.installed_version;
+                               string? experimental_until = this.experimental_until;
+
+                               if (experimental_until == null || package_version == null || 
VersionAttribute.cmp_versions (package_version, experimental_until) < 0) {
+                                       Report.experimental (source_ref, "%s is experimental%s".printf 
(symbol.get_full_name (), (experimental_until != null) ? " until %s".printf (experimental_until) : ""));
+                               }
+                       }
+                       result = true;
+               }
+
+               return result;
+       }
+
+
+       /**
+        * A simple version comparison function.
+        *
+        * @param v1str a version number
+        * @param v2str a version number
+        * @return an integer less than, equal to, or greater than zero, if v1str is <, == or > than v2str
+        * @see GLib.CompareFunc
+        */
+       public static int cmp_versions (string v1str, string v2str) {
+               string[] v1arr = v1str.split (".");
+               string[] v2arr = v2str.split (".");
+               int i = 0;
+
+               while (v1arr[i] != null && v2arr[i] != null) {
+                       int v1num = int.parse (v1arr[i]);
+                       int v2num = int.parse (v2arr[i]);
+
+                       if (v1num < 0 || v2num < 0) {
+                               // invalid format
+                               return 0;
+                       }
+
+                       if (v1num > v2num) {
+                               return 1;
+                       }
+
+                       if (v1num < v2num) {
+                               return -1;
+                       }
+
+                       i++;
+               }
+
+               if (v1arr[i] != null && v2arr[i] == null) {
+                       return 1;
+               }
+
+               if (v1arr[i] == null && v2arr[i] != null) {
+                       return -1;
+               }
+
+               return 0;
+       }
+}
diff --git a/vapigen/valagidlparser.vala b/vapigen/valagidlparser.vala
index 0dc7fe7..6b78d27 100644
--- a/vapigen/valagidlparser.vala
+++ b/vapigen/valagidlparser.vala
@@ -507,12 +507,12 @@ public class Vala.GIdlParser : CodeVisitor {
                                        ns.set_attribute_string ("CCode", "gir_version", eval (nv[1]));
                                } else if (nv[0] == "deprecated") {
                                        if (eval (nv[1]) == "1") {
-                                               ns.set_attribute ("Deprecated", true);
+                                               ns.set_attribute_bool ("Version", "deprecated", true);
                                        }
                                } else if (nv[0] == "replacement") {
-                                       ns.set_attribute_string ("Deprecated", "replacement", eval (nv[1]));
+                                       ns.set_attribute_string ("Version", "replacement", eval (nv[1]));
                                } else if (nv[0] == "deprecated_since") {
-                                       ns.set_attribute_string ("Deprecated", "since", eval (nv[1]));
+                                       ns.set_attribute_string ("Version", "deprecated_since", eval (nv[1]));
                                }
                        }
                }
@@ -618,12 +618,12 @@ public class Vala.GIdlParser : CodeVisitor {
                                        cb.return_type = return_type = parse_type_from_string (eval (nv[1]), 
return_type.value_owned);
                                } else if (nv[0] == "deprecated") {
                                        if (eval (nv[1]) == "1") {
-                                               cb.set_attribute ("Deprecated", true);
+                                               cb.set_attribute_bool ("Version", "deprecated", true);
                                        }
                                } else if (nv[0] == "replacement") {
-                                       cb.set_attribute_string ("Deprecated", "replacement", eval (nv[1]));
+                                       cb.set_attribute_string ("Version", "replacement", eval (nv[1]));
                                } else if (nv[0] == "deprecated_since") {
-                                       cb.set_attribute_string ("Deprecated", "since", eval (nv[1]));
+                                       cb.set_attribute_string ("Version", "deprecated_since", eval (nv[1]));
                                } else if (nv[0] == "type_arguments") {
                                        parse_type_arguments_from_string (return_type, eval (nv[1]));
                                } else if (nv[0] == "instance_pos") {
@@ -634,7 +634,7 @@ public class Vala.GIdlParser : CodeVisitor {
                                        }
                                } else if (nv[0] == "experimental") {
                                        if (eval (nv[1]) == "1") {
-                                               cb.set_attribute ("Experimental", true);
+                                               cb.set_attribute_bool ("Version", "experimental", true);
                                        }
                                }
                        }
@@ -820,19 +820,19 @@ public class Vala.GIdlParser : CodeVisitor {
                                                        }
                                                } else if (nv[0] == "deprecated") {
                                                        if (eval (nv[1]) == "1") {
-                                                               st.set_attribute ("Deprecated", true);
+                                                               st.set_attribute_bool ("Version", 
"deprecated", true);
                                                        }
                                                } else if (nv[0] == "replacement") {
-                                                       st.set_attribute_string ("Deprecated", "replacement", 
eval (nv[1]));
+                                                       st.set_attribute_string ("Version", "replacement", 
eval (nv[1]));
                                                } else if (nv[0] == "deprecated_since") {
-                                                       st.set_attribute_string ("Deprecated", "since", eval 
(nv[1]));
+                                                       st.set_attribute_string ("Version", 
"deprecated_since", eval (nv[1]));
                                                } else if (nv[0] == "has_destroy_function") {
                                                        if (eval (nv[1]) == "0") {
                                                                st.set_attribute_bool ("CCode", 
"has_destroy_function", false);
                                                        }
                                                } else if (nv[0] == "experimental") {
                                                        if (eval (nv[1]) == "1") {
-                                                               st.set_attribute ("Experimental", true);
+                                                               st.set_attribute_bool ("Version", 
"experimental", true);
                                                        }
                                                }
                                        }
@@ -914,19 +914,19 @@ public class Vala.GIdlParser : CodeVisitor {
                                                        }
                                                } else if (nv[0] == "deprecated") {
                                                        if (eval (nv[1]) == "1") {
-                                                               cl.set_attribute ("Deprecated", true);
+                                                               cl.set_attribute_bool ("Version", 
"deprecated", true);
                                                        }
                                                } else if (nv[0] == "replacement") {
-                                                       cl.set_attribute_string ("Deprecated", "replacement", 
eval (nv[1]));
+                                                       cl.set_attribute_string ("Version", "replacement", 
eval (nv[1]));
                                                } else if (nv[0] == "deprecated_since") {
-                                                       cl.set_attribute_string ("Deprecated", "since", eval 
(nv[1]));
+                                                       cl.set_attribute_string ("Version", 
"deprecated_since", eval (nv[1]));
                                                } else if (nv[0] == "type_parameters") {
                                                        foreach (string type_param_name in eval (nv[1]).split 
(",")) {
                                                                cl.add_type_parameter (new TypeParameter 
(type_param_name, current_source_reference));
                                                        }
                                                } else if (nv[0] == "experimental") {
                                                        if (eval (nv[1]) == "1") {
-                                                               cl.set_attribute ("Experimental", true);
+                                                               cl.set_attribute_bool ("Version", 
"experimental", true);
                                                        }
                                                } else if (nv[0] == "delegate_target_cname") {
                                                        cl.set_attribute_string ("CCode", 
"delegate_target_cname", eval (nv[1]));
@@ -1015,19 +1015,19 @@ public class Vala.GIdlParser : CodeVisitor {
                                                        st.set_attribute_string ("CCode", "cheader_filename", 
eval (nv[1]));
                                                } else if (nv[0] == "deprecated") {
                                                        if (eval (nv[1]) == "1") {
-                                                               st.set_attribute ("Deprecated", true);
+                                                               st.set_attribute_bool ("Version", 
"deprecated", true);
                                                        }
                                                } else if (nv[0] == "replacement") {
-                                                       st.set_attribute_string ("Deprecated", "replacement", 
eval (nv[1]));
+                                                       st.set_attribute_string ("Version", "replacement", 
eval (nv[1]));
                                                } else if (nv[0] == "deprecated_since") {
-                                                       st.set_attribute_string ("Deprecated", "since", eval 
(nv[1]));
+                                                       st.set_attribute_string ("Version", 
"deprecated_since", eval (nv[1]));
                                                } else if (nv[0] == "hidden") {
                                                        if (eval (nv[1]) == "1") {
                                                                return;
                                                        }
                                                } else if (nv[0] == "experimental") {
                                                        if (eval (nv[1]) == "1") {
-                                                               st.set_attribute ("Experimental", true);
+                                                               st.set_attribute_bool ("Version", 
"experimental", true);
                                                        }
                                                }
                                        }
@@ -1160,12 +1160,12 @@ public class Vala.GIdlParser : CodeVisitor {
                                                        st.set_attribute_string ("CCode", "cheader_filename", 
eval (nv[1]));
                                                } else if (nv[0] == "deprecated") {
                                                        if (eval (nv[1]) == "1") {
-                                                               st.set_attribute ("Deprecated", true);
+                                                               st.set_attribute_bool ("Version", 
"deprecated", true);
                                                        }
                                                } else if (nv[0] == "replacement") {
-                                                       st.set_attribute_string ("Deprecated", "replacement", 
eval (nv[1]));
+                                                       st.set_attribute_string ("Version", "replacement", 
eval (nv[1]));
                                                } else if (nv[0] == "deprecated_since") {
-                                                       st.set_attribute_string ("Deprecated", "since", eval 
(nv[1]));
+                                                       st.set_attribute_string ("Version", 
"deprecated_since", eval (nv[1]));
                                                } else if (nv[0] == "immutable") {
                                                        if (eval (nv[1]) == "1") {
                                                                st.set_attribute ("Immutable", true);
@@ -1180,7 +1180,7 @@ public class Vala.GIdlParser : CodeVisitor {
                                                        }
                                                } else if (nv[0] == "experimental") {
                                                        if (eval (nv[1]) == "1") {
-                                                               st.set_attribute ("Experimental", true);
+                                                               st.set_attribute_bool ("Version", 
"experimental", true);
                                                        }
                                                }
                                        }
@@ -1239,12 +1239,12 @@ public class Vala.GIdlParser : CodeVisitor {
                                                        }
                                                } else if (nv[0] == "deprecated") {
                                                        if (eval (nv[1]) == "1") {
-                                                               cl.set_attribute ("Deprecated", true);
+                                                               cl.set_attribute_bool ("Version", 
"deprecated", true);
                                                        }
                                                } else if (nv[0] == "replacement") {
-                                                       cl.set_attribute_string ("Deprecated", "replacement", 
eval (nv[1]));
+                                                       cl.set_attribute_string ("Version", "replacement", 
eval (nv[1]));
                                                } else if (nv[0] == "deprecated_since") {
-                                                       cl.set_attribute_string ("Deprecated", "since", eval 
(nv[1]));
+                                                       cl.set_attribute_string ("Version", 
"deprecated_since", eval (nv[1]));
                                                } else if (nv[0] == "const_cname") {
                                                        cl.set_attribute_string ("CCode", "const_cname", eval 
(nv[1]));
                                                } else if (nv[0] == "free_function") {
@@ -1261,7 +1261,7 @@ public class Vala.GIdlParser : CodeVisitor {
                                                        }
                                                } else if (nv[0] == "experimental") {
                                                        if (eval (nv[1]) == "1") {
-                                                               cl.set_attribute ("Experimental", true);
+                                                               cl.set_attribute_bool ("Version", 
"experimental", true);
                                                        }
                                                }
                                        }
@@ -1401,14 +1401,14 @@ public class Vala.GIdlParser : CodeVisitor {
                                        }
                                } else if (nv[0] == "deprecated") {
                                        if (eval (nv[1]) == "1") {
-                                               en.set_attribute ("Deprecated", true);
+                                               en.set_attribute_bool ("Version", "deprecated", true);
                                        }
                                } else if (nv[0] == "default_value") {
                                        en.set_attribute_string ("CCode", "default_value", eval (nv[1]));
                                } else if (nv[0] == "replacement") {
-                                       en.set_attribute_string ("Deprecated", "replacement", eval (nv[1]));
+                                       en.set_attribute_string ("Version", "replacement", eval (nv[1]));
                                } else if (nv[0] == "deprecated_since") {
-                                       en.set_attribute_string ("Deprecated", "since", eval (nv[1]));
+                                       en.set_attribute_string ("Version", "deprecated_since", eval (nv[1]));
                                } else if (nv[0] == "rename_to") {
                                        en.name = eval (nv[1]);
                                } else if (nv[0] == "errordomain") {
@@ -1425,7 +1425,7 @@ public class Vala.GIdlParser : CodeVisitor {
                                        en.add_method (m);
                                } else if (nv[0] == "experimental") {
                                        if (eval (nv[1]) == "1") {
-                                               en.set_attribute ("Experimental", true);
+                                               en.set_attribute_bool ("Version", "experimental", true);
                                        }
                                }
                        }
@@ -1445,12 +1445,12 @@ public class Vala.GIdlParser : CodeVisitor {
                                                is_hidden = true;
                                        } else if (nv[0] == "deprecated") {
                                                if (eval (nv[1]) == "1") {
-                                                       ev.set_attribute ("Deprecated", true);
+                                                       ev.set_attribute_bool ("Version", "deprecated", true);
                                                }
                                        }  else if (nv[0] == "replacement") {
-                                               ev.set_attribute_string ("Deprecated", "replacement", eval 
(nv[1]));
+                                               ev.set_attribute_string ("Version", "replacement", eval 
(nv[1]));
                                        } else if (nv[0] == "deprecated_since") {
-                                               ev.set_attribute_string ("Deprecated", "since", eval (nv[1]));
+                                               ev.set_attribute_string ("Version", "deprecated_since", eval 
(nv[1]));
                                        }
                                }
                        }
@@ -1512,12 +1512,12 @@ public class Vala.GIdlParser : CodeVisitor {
                                                cl.set_attribute_string ("CCode", "type_check_function", eval 
(nv[1]));
                                        } else if (nv[0] == "deprecated") {
                                                if (eval (nv[1]) == "1") {
-                                                       cl.set_attribute ("Deprecated", true);
+                                                       cl.set_attribute_bool ("Version", "deprecated", true);
                                                }
                                        } else if (nv[0] == "replacement") {
-                                               cl.set_attribute_string ("Deprecated", "replacement", eval 
(nv[1]));
+                                               cl.set_attribute_string ("Version", "replacement", eval 
(nv[1]));
                                        } else if (nv[0] == "deprecated_since") {
-                                               cl.set_attribute_string ("Deprecated", "since", eval (nv[1]));
+                                               cl.set_attribute_string ("Version", "deprecated_since", eval 
(nv[1]));
                                        } else if (nv[0] == "type_id") {
                                                cl.set_attribute_string ("CCode", "type_id", eval (nv[1]));
                                        } else if (nv[0] == "abstract") {
@@ -1526,7 +1526,7 @@ public class Vala.GIdlParser : CodeVisitor {
                                                }
                                        } else if (nv[0] == "experimental") {
                                                if (eval (nv[1]) == "1") {
-                                                       cl.set_attribute ("Experimental", true);
+                                                       cl.set_attribute_bool ("Version", "experimental", 
true);
                                                }
                                        } else if (nv[0] == "compact") {
                                                if (eval (nv[1]) == "1") {
@@ -2307,12 +2307,12 @@ public class Vala.GIdlParser : CodeVisitor {
                                        parse_type_arguments_from_string (return_type, eval (nv[1]));
                                } else if (nv[0] == "deprecated") {
                                        if (eval (nv[1]) == "1") {
-                                               m.set_attribute ("Deprecated", true);
+                                               m.set_attribute_bool ("Version", "deprecated", true);
                                        }
                                } else if (nv[0] == "replacement") {
-                                       m.set_attribute_string ("Deprecated", "replacement", eval (nv[1]));
+                                       m.set_attribute_string ("Version", "replacement", eval (nv[1]));
                                } else if (nv[0] == "deprecated_since") {
-                                       m.set_attribute_string ("Deprecated", "since", eval (nv[1]));
+                                       m.set_attribute_string ("Version", "deprecated_since", eval (nv[1]));
                                } else if (nv[0] == "cheader_filename") {
                                        m.set_attribute_string ("CCode", "cheader_filename", eval (nv[1]));
                                } else if (nv[0] == "abstract") {
@@ -2340,7 +2340,7 @@ public class Vala.GIdlParser : CodeVisitor {
                                        }
                                } else if (nv[0] == "experimental") {
                                        if (eval (nv[1]) == "1") {
-                                               m.set_attribute ("Experimental", true);
+                                               m.set_attribute_bool ("Version", "experimental", true);
                                        }
                                } else if (nv[0] == "simple_generics") {
                                        if (eval (nv[1]) == "1") {
@@ -2723,12 +2723,12 @@ public class Vala.GIdlParser : CodeVisitor {
                                        parse_type_arguments_from_string (prop.property_type, eval (nv[1]));
                                } else if (nv[0] == "deprecated") {
                                        if (eval (nv[1]) == "1") {
-                                               prop.set_attribute ("Deprecated", true);
+                                               prop.set_attribute_bool ("Version", "deprecated", true);
                                        }
                                } else if (nv[0] == "replacement") {
-                                       prop.set_attribute_string ("Deprecated", "replacement", eval (nv[1]));
+                                       prop.set_attribute_string ("Version", "replacement", eval (nv[1]));
                                } else if (nv[0] == "deprecated_since") {
-                                       prop.set_attribute_string ("Deprecated", "since", eval (nv[1]));
+                                       prop.set_attribute_string ("Version", "deprecated_since", eval 
(nv[1]));
                                } else if (nv[0] == "accessor_method") {
                                        if (eval (nv[1]) == "0") {
                                                prop.set_attribute ("NoAccessorMethod", true);
@@ -2741,7 +2741,7 @@ public class Vala.GIdlParser : CodeVisitor {
                                        prop.property_type = parse_type_from_string (eval (nv[1]), false);
                                } else if (nv[0] == "experimental") {
                                        if (eval (nv[1]) == "1") {
-                                               prop.set_attribute ("Experimental", true);
+                                               prop.set_attribute_bool ("Version", "experimental", true);
                                        }
                                } else if (nv[0] == "nullable") {
                                        if (eval (nv[1]) == "1" && !(prop.property_type is VoidType)) {
@@ -2781,19 +2781,19 @@ public class Vala.GIdlParser : CodeVisitor {
                                        c.set_attribute_string ("CCode", "cheader_filename", eval (nv[1]));
                                } else if (nv[0] == "deprecated") {
                                        if (eval (nv[1]) == "1") {
-                                               c.set_attribute ("Deprecated", true);
+                                               c.set_attribute_bool ("Version", "deprecated", true);
                                        }
                                } else if (nv[0] == "replacement") {
-                                       c.set_attribute_string ("Deprecated", "replacement", eval (nv[1]));
+                                       c.set_attribute_string ("Version", "replacement", eval (nv[1]));
                                } else if (nv[0] == "deprecated_since") {
-                                       c.set_attribute_string ("Deprecated", "since", eval (nv[1]));
+                                       c.set_attribute_string ("Version", "deprecated_since", eval (nv[1]));
                                } else if (nv[0] == "hidden") {
                                        if (eval (nv[1]) == "1") {
                                                return null;
                                        }
                                } else if (nv[0] == "experimental") {
                                        if (eval (nv[1]) == "1") {
-                                               c.set_attribute ("Experimental", true);
+                                               c.set_attribute_bool ("Version", "experimental", true);
                                        }
                                }
                        }
@@ -2907,19 +2907,19 @@ public class Vala.GIdlParser : CodeVisitor {
                }
 
                if (deprecated) {
-                       field.set_attribute ("Deprecated", true);
+                       field.set_attribute_bool ("Version", "deprecated", true);
 
                        if (deprecated_since != null) {
-                               field.set_attribute_string ("Deprecated", "since", deprecated_since);
+                               field.set_attribute_string ("Version", "deprecated_since", deprecated_since);
                        }
 
                        if (replacement != null) {
-                               field.set_attribute_string ("Deprecated", "replacement", replacement);
+                               field.set_attribute_string ("Version", "replacement", replacement);
                        }
                }
 
                if (experimental) {
-                       field.set_attribute ("Experimental", true);
+                       field.set_attribute_bool ("Version", "experimental", true);
                }
 
                if (ctype != null) {
@@ -3049,12 +3049,12 @@ public class Vala.GIdlParser : CodeVisitor {
                                        }
                                } else if (nv[0] == "deprecated") {
                                        if (eval (nv[1]) == "1") {
-                                               sig.set_attribute ("Deprecated", true);
+                                               sig.set_attribute_bool ("Version", "deprecated", true);
                                        }
                                } else if (nv[0] == "replacement") {
-                                       sig.set_attribute_string ("Deprecated", "replacement", eval (nv[1]));
+                                       sig.set_attribute_string ("Version", "replacement", eval (nv[1]));
                                } else if (nv[0] == "deprecated_since") {
-                                       sig.set_attribute_string ("Deprecated", "since", eval (nv[1]));
+                                       sig.set_attribute_string ("Version", "deprecated_since", eval 
(nv[1]));
                                } else if (nv[0] == "transfer_ownership") {
                                        if (eval (nv[1]) == "1") {
                                                sig.return_type.value_owned = true;
@@ -3067,7 +3067,7 @@ public class Vala.GIdlParser : CodeVisitor {
                                        parse_type_arguments_from_string (sig.return_type, eval (nv[1]));
                                } else if (nv[0] == "experimental") {
                                        if (eval (nv[1]) == "1") {
-                                               sig.set_attribute ("Experimental", true);
+                                               sig.set_attribute_bool ("Version", "experimental", true);
                                        }
                                }
                        }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]