# HG changeset patch # User Paul Boddie # Date 1389653936 -3600 # Node ID 3f0fd4b7137784afcb9de63695a3c208c5f8a282 # Parent fd113b9d829c2c5505e4bff9849cf5ee1f874eea Added support for detecting accesses of potentially unassigned locals. diff -r fd113b9d829c -r 3f0fd4b71377 micropython/branch.py --- a/micropython/branch.py Mon Jan 13 23:58:23 2014 +0100 +++ b/micropython/branch.py Mon Jan 13 23:58:56 2014 +0100 @@ -1,7 +1,7 @@ #!/usr/bin/env python """ -Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013 Paul Boddie +Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Paul Boddie This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -414,6 +414,13 @@ self.scope_usage[-1][name] = scope + def defined_as_local(self, name): + + "Return the scope defined for 'name' or None if it is not yet defined." + + scope = self.scope_usage[-1].get(name) + return scope and (scope == "local" or isinstance(scope, ScopeConflict) and scope.is_benign()) + def note_scope(self, name, scope): """ @@ -426,8 +433,11 @@ if scope_usage.has_key(name): found_scope = scope_usage[name] if isinstance(found_scope, ScopeConflict): - raise InspectError("Scope conflict for %r: defined as %s." % ( - name, ", ".join(found_scope.scopes))) + if not found_scope.is_benign(): + raise InspectError("Scope conflict for %r: defined as %s." % ( + name, ", ".join(found_scope.scopes))) + else: + print >>sys.stderr, "Warning: name %r in %s may not be defined in all cases." % (name, self.full_name()) scope_usage[name] = scope @@ -645,6 +655,8 @@ else: attr, scope, full_name = self._get_with_scope(name, external=1) + if not attr: + scope = "unset" # Attempt to record the scope, testing for conflicts. @@ -748,13 +760,21 @@ class ScopeConflict: """ - A scope conflict caused when different code branches contribute different - sources of names. + A class whose instances provide a collection of scope alternatives, either + potentially benign or indicating a serious problem. + + A scope conflict is caused when different code branches contribute different + sources of names or where branches neglect to contribute names at all. Where + the sources (scopes) indicated are different, a serious problem exists + because the name has no single way of being accessed. """ def __init__(self, scopes): self.scopes = scopes + def is_benign(self): + return len(self.scopes) == 2 and "unset" in self.scopes + class UnsetType: "A None-like value." diff -r fd113b9d829c -r 3f0fd4b71377 micropython/data.py --- a/micropython/data.py Mon Jan 13 23:58:23 2014 +0100 +++ b/micropython/data.py Mon Jan 13 23:58:56 2014 +0100 @@ -221,7 +221,7 @@ # Locals. - if not external and self.has_key(name): + if not external and self.defined_as_local(name) and self.has_key(name): return self[name], "local", self.full_name() # Outer scopes. diff -r fd113b9d829c -r 3f0fd4b71377 tests/local_potentially_unassigned.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/local_potentially_unassigned.py Mon Jan 13 23:58:56 2014 +0100 @@ -0,0 +1,10 @@ +#!/usr/bin/env python + +def f(a): + if a: + x = 1 + return x + +result_1 = f(1) + +# vim: tabstop=4 expandtab shiftwidth=4