1.1 --- a/deducer.py Sat Sep 24 22:44:45 2016 +0200
1.2 +++ b/deducer.py Sun Sep 25 22:44:04 2016 +0200
1.3 @@ -19,7 +19,7 @@
1.4 this program. If not, see <http://www.gnu.org/licenses/>.
1.5 """
1.6
1.7 -from common import get_attrname_from_location, get_attrnames, \
1.8 +from common import first, get_attrname_from_location, get_attrnames, \
1.9 init_item, make_key, sorted_output, \
1.10 CommonOutput
1.11 from encoders import encode_attrnames, encode_access_location, \
1.12 @@ -136,6 +136,7 @@
1.13 self.write_mutations()
1.14 self.write_accessors()
1.15 self.write_accesses()
1.16 + self.write_access_plans()
1.17
1.18 def write_mutations(self):
1.19
1.20 @@ -437,6 +438,26 @@
1.21
1.22 # Otherwise, no convenient guard can be defined.
1.23
1.24 + def write_access_plans(self):
1.25 +
1.26 + "Each attribute access is written out as a plan."
1.27 +
1.28 + f_attrs = open(join(self.output, "attribute_plans"), "w")
1.29 +
1.30 + try:
1.31 + locations = self.referenced_attrs.keys()
1.32 + locations.sort()
1.33 +
1.34 + for location in locations:
1.35 + base, traversed, attrnames, attr = self.get_access(location)
1.36 + print >>f_attrs, encode_access_location(location), base, \
1.37 + ".".join(traversed) or "{}", \
1.38 + ".".join(attrnames) or "{}", \
1.39 + attr or "{}"
1.40 +
1.41 + finally:
1.42 + f_attrs.close()
1.43 +
1.44 def classify_accesses(self):
1.45
1.46 "For each program location, classify accesses."
1.47 @@ -1615,4 +1636,59 @@
1.48
1.49 return attrs
1.50
1.51 + def get_access(self, location):
1.52 +
1.53 + "Return details of the access at the given 'location'."
1.54 +
1.55 + const_access = self.const_accesses.has_key(location)
1.56 + if const_access:
1.57 + location = self.const_accesses[location]
1.58 +
1.59 + path, name, attrname_str, version = location
1.60 + attrnames = attrname_str.split(".")
1.61 + attrname = attrnames[0]
1.62 +
1.63 + # Obtain only reference information.
1.64 +
1.65 + attrs = []
1.66 + objtypes = []
1.67 + for attrtype, objtype, attr in self.referenced_attrs[location]:
1.68 + attrs.append(attr)
1.69 + objtypes.append(objtype)
1.70 +
1.71 + # Identify the last static attribute.
1.72 +
1.73 + if const_access:
1.74 + base = len(objtypes) == 1 and first(objtypes)
1.75 + else:
1.76 + ref = self.importer.identify("%s.%s" % (path, name))
1.77 + if not ref:
1.78 + base = name
1.79 + else:
1.80 + base = ref.get_origin()
1.81 +
1.82 + traversed = []
1.83 +
1.84 + # Traverse remaining attributes.
1.85 +
1.86 + while len(attrs) == 1:
1.87 + attr = first(attrs)
1.88 +
1.89 + traversed.append(attrname)
1.90 + del attrnames[0]
1.91 +
1.92 + if not attrnames:
1.93 + break
1.94 +
1.95 + if attr.static():
1.96 + base = attr.get_origin()
1.97 + traversed = []
1.98 +
1.99 + attrname = attrnames[0]
1.100 + attrs = self.importer.get_attributes(attr, attrname)
1.101 + else:
1.102 + attr = None
1.103 +
1.104 + return base, traversed, attrnames, attr and attr.get_name()
1.105 +
1.106 # vim: tabstop=4 expandtab shiftwidth=4
2.1 --- a/tests/chain.py Sat Sep 24 22:44:45 2016 +0200
2.2 +++ b/tests/chain.py Sun Sep 25 22:44:04 2016 +0200
2.3 @@ -2,7 +2,8 @@
2.4 class D:
2.5 class E:
2.6 def m(self, x):
2.7 - return x
2.8 + self.x = x
2.9 + return self.x.__len__
2.10 n = 123
2.11 p = "456"
2.12
2.13 @@ -16,7 +17,7 @@
2.14 i = C.D.p.__len__
2.15 inst = e()
2.16 method = inst.m
2.17 - return method(5)
2.18 + return method("5")
2.19
2.20 result1 = main()
2.21 c = C
2.22 @@ -28,4 +29,4 @@
2.23 i = C.D.p.__len__
2.24 inst = e()
2.25 method = inst.m
2.26 -result2 = method(5)
2.27 +result2 = method("5")