diff options
author | Jiří Zárevúcky <zarevucky.jiri@gmail.com> | 2010-03-24 08:36:37 +0100 |
---|---|---|
committer | Jürg Billeter <j@bitron.ch> | 2010-03-24 08:36:37 +0100 |
commit | 40c1dbfbfedb6c4a6b88df045eb1c2e7bdd38d93 (patch) | |
tree | 7b3ad670a285f3a4c5687686e23c3ffdc0f06883 /vala | |
parent | 30f3bdf5503071f6a4cf6780494f5bddf49d68ed (diff) | |
download | vala-40c1dbfbfedb6c4a6b88df045eb1c2e7bdd38d93.tar.gz |
Fix lock statement
This patch converts lock statements into try finally statements to
ensure that unlock is always called.
Fixes bug 582553.
Diffstat (limited to 'vala')
-rw-r--r-- | vala/Makefile.am | 1 | ||||
-rw-r--r-- | vala/valacodevisitor.vala | 8 | ||||
-rw-r--r-- | vala/valaflowanalyzer.vala | 6 | ||||
-rw-r--r-- | vala/valalockstatement.vala | 39 | ||||
-rw-r--r-- | vala/valaunlockstatement.vala | 70 |
5 files changed, 115 insertions, 9 deletions
diff --git a/vala/Makefile.am b/vala/Makefile.am index 69f0d0ac6..aa0b861f4 100644 --- a/vala/Makefile.am +++ b/vala/Makefile.am @@ -151,6 +151,7 @@ libvalacore_la_VALASOURCES = \ valatypeparameter.vala \ valatypesymbol.vala \ valaunaryexpression.vala \ + valaunlockstatement.vala \ valaunresolvedsymbol.vala \ valaunresolvedtype.vala \ valausingdirective.vala \ diff --git a/vala/valacodevisitor.vala b/vala/valacodevisitor.vala index f11a3ef43..55f87d7cc 100644 --- a/vala/valacodevisitor.vala +++ b/vala/valacodevisitor.vala @@ -405,6 +405,14 @@ public abstract class Vala.CodeVisitor { } /** + * Visit operation called for unlock statements. + * + * @param stmt an unlock statement + */ + public virtual void visit_unlock_statement (UnlockStatement stmt) { + } + + /** * Visit operation called for delete statements. * * @param stmt a delete statement diff --git a/vala/valaflowanalyzer.vala b/vala/valaflowanalyzer.vala index ff5f255db..193f6103a 100644 --- a/vala/valaflowanalyzer.vala +++ b/vala/valaflowanalyzer.vala @@ -1010,8 +1010,12 @@ public class Vala.FlowAnalyzer : CodeVisitor { if (unreachable (stmt)) { return; } + } - stmt.body.accept (this); + public override void visit_unlock_statement (UnlockStatement stmt) { + if (unreachable (stmt)) { + return; + } } public override void visit_expression (Expression expr) { diff --git a/vala/valalockstatement.vala b/vala/valalockstatement.vala index 9ad5dfbdd..da9a0be94 100644 --- a/vala/valalockstatement.vala +++ b/vala/valalockstatement.vala @@ -1,5 +1,6 @@ /* valalockstatement.vala * + * Copyright (C) 2009 Jiří Zárevúcky * Copyright (C) 2006-2007 Raffaele Sandrini, Jürg Billeter * * This library is free software; you can redistribute it and/or @@ -16,14 +17,19 @@ * 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: + * Authors: * Raffaele Sandrini <raffaele@sandrini.ch> + * Jiří Zárevúcky <zarevucky.jiri@gmail.com> */ using GLib; /** - * Represents a lock statement e.g. {{{ lock (a) { f(a) } }}}. + * Represents a lock statement e.g. {{{ lock (a); }}} or {{{ lock (a) { f(a); } }}}. + * + * If the statement is empty, the mutex remains locked until a corresponding UnlockStatement + * occurs. Otherwise it's translated into a try/finally statement which unlocks the mutex + * after the block is finished. */ public class Vala.LockStatement : CodeNode, Statement { /** @@ -34,9 +40,9 @@ public class Vala.LockStatement : CodeNode, Statement { /** * The statement during its execution the resource is locked. */ - public Block body { get; set; } + public Block? body { get; set; } - public LockStatement (Expression resource, Block body, SourceReference? source_reference = null) { + public LockStatement (Expression resource, Block? body, SourceReference? source_reference = null) { this.body = body; this.source_reference = source_reference; this.resource = resource; @@ -44,11 +50,29 @@ public class Vala.LockStatement : CodeNode, Statement { public override void accept (CodeVisitor visitor) { resource.accept (visitor); - body.accept (visitor); + if (body != null) { + body.accept (visitor); + } visitor.visit_lock_statement (this); } public override bool check (SemanticAnalyzer analyzer) { + if (body != null) { + // if the statement isn't empty, it is converted into a try statement + + var fin_body = new Block (source_reference); + fin_body.add_statement (new UnlockStatement (resource, source_reference)); + + var block = new Block (source_reference); + block.add_statement (new LockStatement (resource, null, source_reference)); + block.add_statement (new TryStatement (body, fin_body, source_reference)); + + var parent_block = (Block) parent_node; + parent_block.replace_statement (this, block); + + return block.check (analyzer); + } + if (checked) { return !error; } @@ -56,11 +80,10 @@ public class Vala.LockStatement : CodeNode, Statement { checked = true; resource.check (analyzer); - body.check (analyzer); /* resource must be a member access and denote a Lockable */ if (!(resource is MemberAccess && resource.symbol_reference is Lockable)) { - error = true; + error = true; resource.error = true; Report.error (resource.source_reference, "Expression is either not a member access or does not denote a lockable member"); return false; @@ -68,7 +91,7 @@ public class Vala.LockStatement : CodeNode, Statement { /* parent symbol must be the current class */ if (resource.symbol_reference.parent_symbol != analyzer.current_class) { - error = true; + error = true; resource.error = true; Report.error (resource.source_reference, "Only members of the current class are lockable"); } diff --git a/vala/valaunlockstatement.vala b/vala/valaunlockstatement.vala new file mode 100644 index 000000000..e0ae1a034 --- /dev/null +++ b/vala/valaunlockstatement.vala @@ -0,0 +1,70 @@ +/* valaunlockstatement.vala + * + * Copyright (C) 2009 Jiří Zárevúcky, 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: + * Jiří Zárevúcky <zarevucky.jiri@gmail.com> + */ + +/** + * Represents an unlock statement e.g. {{{ unlock (a); }}}. + */ +public class Vala.UnlockStatement : CodeNode, Statement { + /** + * Expression representing the resource to be unlocked. + */ + public Expression resource { get; set; } + + public UnlockStatement (Expression resource, SourceReference? source_reference = null) { + this.source_reference = source_reference; + this.resource = resource; + } + + public override void accept (CodeVisitor visitor) { + resource.accept (visitor); + visitor.visit_unlock_statement (this); + } + + public override bool check (SemanticAnalyzer analyzer) { + if (checked) { + return !error; + } + + checked = true; + + resource.check (analyzer); + + /* resource must be a member access and denote a Lockable */ + if (!(resource is MemberAccess && resource.symbol_reference is Lockable)) { + error = true; + resource.error = true; + Report.error (resource.source_reference, "Expression is either not a member access or does not denote a lockable member"); + return false; + } + + /* parent symbol must be the current class */ + if (resource.symbol_reference.parent_symbol != analyzer.current_class) { + error = true; + resource.error = true; + Report.error (resource.source_reference, "Only members of the current class are lockable"); + } + + ((Lockable) resource.symbol_reference).set_lock_used (true); + + return !error; + } +} |