Commit 80c18a1d authored by Jürg Billeter's avatar Jürg Billeter

Use strict non-null types with --enable-experimental-non-null

Do not consider local variables nullable or nullable types compatible
to non-null types when using --enable-experimental-non-null.
parent 4e818c1d
......@@ -55,7 +55,7 @@ class Vala.Compiler {
static bool enable_checking;
static bool deprecated;
static bool experimental;
static bool non_null_experimental;
static bool experimental_non_null;
static bool disable_dbus_transformation;
static bool disable_warnings;
static string cc_command;
......@@ -101,7 +101,7 @@ class Vala.Compiler {
{ "enable-deprecated", 0, 0, OptionArg.NONE, ref deprecated, "Enable deprecated features", null },
{ "enable-experimental", 0, 0, OptionArg.NONE, ref experimental, "Enable experimental features", null },
{ "disable-warnings", 0, 0, OptionArg.NONE, ref disable_warnings, "Disable warnings", null },
{ "enable-non-null-experimental", 0, 0, OptionArg.NONE, ref non_null_experimental, "Enable experimental enhancements for non-null types", null },
{ "enable-experimental-non-null", 0, 0, OptionArg.NONE, ref experimental_non_null, "Enable experimental enhancements for non-null types", null },
{ "disable-dbus-transformation", 0, 0, OptionArg.NONE, ref disable_dbus_transformation, "Disable transformation of D-Bus member names", null },
{ "cc", 0, 0, OptionArg.STRING, ref cc_command, "Use COMMAND as C compiler command", "COMMAND" },
{ "Xcc", 'X', 0, OptionArg.STRING_ARRAY, ref cc_options, "Pass OPTION to the C compiler", "OPTION..." },
......@@ -188,7 +188,7 @@ class Vala.Compiler {
context.checking = enable_checking;
context.deprecated = deprecated;
context.experimental = experimental;
context.non_null_experimental = non_null_experimental;
context.experimental_non_null = experimental || experimental_non_null;
context.dbus_transformation = !disable_dbus_transformation;
context.report.enable_warnings = !disable_warnings;
context.report.set_verbose_errors (!quiet_mode);
......@@ -355,15 +355,6 @@ class Vala.Compiler {
return quit ();
}
if (context.non_null_experimental) {
var null_checker = new NullChecker ();
null_checker.check (context);
if (context.report.get_errors () > 0) {
return quit ();
}
}
context.codegen.emit (context);
if (context.report.get_errors () > 0) {
......
......@@ -98,7 +98,6 @@ libvalacore_la_VALASOURCES = \
valamethodcall.vala \
valamethodtype.vala \
valanamespace.vala \
valanullchecker.vala \
valanullliteral.vala \
valanulltype.vala \
valaobjectcreationexpression.vala \
......
......@@ -49,7 +49,7 @@ public class Vala.CodeContext {
/**
* Enable experimental enhancements for non-null types.
*/
public bool non_null_experimental { get; set; }
public bool experimental_non_null { get; set; }
/**
* Enable transformation of D-Bus member names in dynamic client support.
......
......@@ -297,6 +297,10 @@ public abstract class Vala.DataType : CodeNode {
}
public virtual bool compatible (DataType target_type) {
if (CodeContext.get ().experimental_non_null && nullable && !target_type.nullable) {
return false;
}
if (target_type.get_type_id () == "G_TYPE_VALUE" && get_type_id () != null) {
// allow implicit conversion to GValue
return true;
......
/* valanullchecker.vala
*
* Copyright (C) 2008-2009 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 <j@bitron.ch>
*/
using GLib;
/**
* Code visitor checking null references.
*/
public class Vala.NullChecker : CodeVisitor {
private CodeContext context;
DataType current_return_type;
public NullChecker () {
}
public void check (CodeContext context) {
this.context = context;
context.accept (this);
}
void check_compatible (Expression expr, DataType target_type) {
if (!target_type.nullable) {
if (expr.value_type is NullType) {
Report.error (expr.source_reference, "`null' incompatible with `%s'".printf (target_type.to_string ()));
} else if (expr.value_type.nullable) {
Report.warning (expr.source_reference, "`%s' incompatible with `%s'".printf (expr.value_type.to_string (), target_type.to_string ()));
}
}
}
void check_non_null (Expression expr) {
if (expr.value_type is NullType) {
Report.error (expr.source_reference, "null dereference");
} else if (expr.value_type.nullable) {
Report.warning (expr.source_reference, "possible null dereference");
}
}
public override void visit_source_file (SourceFile file) {
file.accept_children (this);
}
public override void visit_class (Class cl) {
cl.accept_children (this);
}
public override void visit_struct (Struct st) {
st.accept_children (this);
}
public override void visit_interface (Interface iface) {
iface.accept_children (this);
}
public override void visit_enum (Enum en) {
en.accept_children (this);
}
public override void visit_error_domain (ErrorDomain ed) {
ed.accept_children (this);
}
public override void visit_field (Field f) {
f.accept_children (this);
}
public override void visit_method (Method m) {
var old_return_type = current_return_type;
current_return_type = m.return_type;
m.accept_children (this);
current_return_type = old_return_type;
}
public override void visit_creation_method (CreationMethod m) {
m.accept_children (this);
}
public override void visit_formal_parameter (FormalParameter p) {
p.accept_children (this);
if (p.default_expression != null) {
check_compatible (p.default_expression, p.parameter_type);
}
}
public override void visit_property (Property prop) {
prop.accept_children (this);
}
public override void visit_property_accessor (PropertyAccessor acc) {
acc.accept_children (this);
}
public override void visit_constructor (Constructor c) {
c.accept_children (this);
}
public override void visit_destructor (Destructor d) {
d.accept_children (this);
}
public override void visit_block (Block b) {
b.accept_children (this);
}
public override void visit_local_variable (LocalVariable local) {
local.accept_children (this);
if (local.initializer != null) {
check_compatible (local.initializer, local.variable_type);
}
}
public override void visit_expression_statement (ExpressionStatement stmt) {
stmt.accept_children (this);
}
public override void visit_if_statement (IfStatement stmt) {
stmt.accept_children (this);
check_non_null (stmt.condition);
}
public override void visit_switch_statement (SwitchStatement stmt) {
stmt.accept_children (this);
}
public override void visit_switch_section (SwitchSection section) {
section.accept_children (this);
}
public override void visit_loop (Loop stmt) {
stmt.accept_children (this);
}
public override void visit_foreach_statement (ForeachStatement stmt) {
stmt.accept_children (this);
check_non_null (stmt.collection);
}
public override void visit_return_statement (ReturnStatement stmt) {
stmt.accept_children (this);
if (stmt.return_expression != null) {
check_compatible (stmt.return_expression, current_return_type);
}
}
public override void visit_yield_statement (YieldStatement stmt) {
stmt.accept_children (this);
}
public override void visit_throw_statement (ThrowStatement stmt) {
stmt.accept_children (this);
check_non_null (stmt.error_expression);
}
public override void visit_try_statement (TryStatement stmt) {
stmt.accept_children (this);
}
public override void visit_catch_clause (CatchClause clause) {
clause.accept_children (this);
}
public override void visit_delete_statement (DeleteStatement stmt) {
stmt.accept_children (this);
}
public override void visit_method_call (MethodCall expr) {
expr.accept_children (this);
var mtype = expr.call.value_type as MethodType;
var ma = expr.call as MemberAccess;
if (mtype != null && mtype.method_symbol.binding == MemberBinding.INSTANCE && ma != null) {
check_non_null (ma.inner);
}
}
public override void visit_element_access (ElementAccess expr) {
expr.accept_children (this);
check_non_null (expr.container);
}
public override void visit_postfix_expression (PostfixExpression expr) {
check_non_null (expr.inner);
}
public override void visit_unary_expression (UnaryExpression expr) {
switch (expr.operator) {
case UnaryOperator.PLUS:
case UnaryOperator.MINUS:
case UnaryOperator.LOGICAL_NEGATION:
case UnaryOperator.BITWISE_COMPLEMENT:
case UnaryOperator.INCREMENT:
case UnaryOperator.DECREMENT:
check_non_null (expr.inner);
break;
}
}
public override void visit_reference_transfer_expression (ReferenceTransferExpression expr) {
expr.accept_children (this);
}
public override void visit_lambda_expression (LambdaExpression l) {
l.accept_children (this);
}
public override void visit_assignment (Assignment a) {
a.accept_children (this);
check_compatible (a.right, a.left.value_type);
}
}
/* valanulltype.vala
*
* Copyright (C) 2007-2008 Jürg Billeter
* Copyright (C) 2007-2009 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
......@@ -27,10 +27,15 @@ using GLib;
*/
public class Vala.NullType : ReferenceType {
public NullType (SourceReference source_reference) {
this.nullable = true;
this.source_reference = source_reference;
}
public override bool compatible (DataType target_type) {
if (CodeContext.get ().experimental_non_null) {
return target_type.nullable;
}
if (!(target_type is PointerType) && (target_type is NullType || (target_type.data_type == null && target_type.type_parameter == null))) {
return true;
}
......@@ -64,4 +69,8 @@ public class Vala.NullType : ReferenceType {
public override bool is_disposable () {
return false;
}
public override string to_qualified_string (Scope? scope = null) {
return "null";
}
}
......@@ -28,6 +28,7 @@ using GLib;
* Code visitor resolving symbol names.
*/
public class Vala.SymbolResolver : CodeVisitor {
CodeContext context;
Symbol root_symbol;
Scope current_scope;
......@@ -37,6 +38,7 @@ public class Vala.SymbolResolver : CodeVisitor {
* @param context a code context
*/
public void resolve (CodeContext context) {
this.context = context;
root_symbol = context.root;
context.root.accept (this);
......@@ -348,12 +350,16 @@ public class Vala.SymbolResolver : CodeVisitor {
public override void visit_local_variable (LocalVariable local) {
local.accept_children (this);
if (local.variable_type is ReferenceType) {
var array_type = local.variable_type as ArrayType;
if (array_type != null && array_type.fixed_length) {
// local fixed length arrays are not nullable
} else {
local.variable_type.nullable = true;
if (!context.experimental_non_null) {
// local reference variables are considered nullable
// except when using experimental non-null enhancements
if (local.variable_type is ReferenceType) {
var array_type = local.variable_type as ArrayType;
if (array_type != null && array_type.fixed_length) {
// local fixed length arrays are not nullable
} else {
local.variable_type.nullable = true;
}
}
}
}
......
......@@ -2484,7 +2484,7 @@ namespace GLib {
public string? read_line () {
int c;
StringBuilder ret = null;
StringBuilder? ret = null;
while ((c = getc ()) != EOF) {
if (ret == null) {
ret = new StringBuilder ();
......@@ -2494,7 +2494,11 @@ namespace GLib {
}
ret.append_c ((char) c);
}
return ret == null ? null : ret.str;
if (ret == null) {
return null;
} else {
return ret.str;
}
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment