2016-03-28 00:10:01 +08:00
|
|
|
"""
|
2017-06-09 15:26:31 +08:00
|
|
|
:class:`ConstnessValidator` checks that no attribute marked
|
2016-03-28 00:10:01 +08:00
|
|
|
as constant is ever set.
|
|
|
|
"""
|
|
|
|
|
|
|
|
from pythonparser import algorithm, diagnostic
|
2017-06-09 15:24:57 +08:00
|
|
|
from .. import types, builtins
|
2016-03-28 00:10:01 +08:00
|
|
|
|
2017-06-09 15:26:31 +08:00
|
|
|
class ConstnessValidator(algorithm.Visitor):
|
2016-03-28 00:10:01 +08:00
|
|
|
def __init__(self, engine):
|
|
|
|
self.engine = engine
|
|
|
|
self.in_assign = False
|
|
|
|
|
|
|
|
def visit_Assign(self, node):
|
|
|
|
self.visit(node.value)
|
|
|
|
self.in_assign = True
|
|
|
|
self.visit(node.targets)
|
|
|
|
self.in_assign = False
|
|
|
|
|
2017-06-09 15:31:08 +08:00
|
|
|
def visit_AugAssign(self, node):
|
|
|
|
self.visit(node.value)
|
|
|
|
self.in_assign = True
|
|
|
|
self.visit(node.target)
|
|
|
|
self.in_assign = False
|
|
|
|
|
2016-11-21 21:21:32 +08:00
|
|
|
def visit_SubscriptT(self, node):
|
|
|
|
old_in_assign, self.in_assign = self.in_assign, False
|
|
|
|
self.visit(node.value)
|
|
|
|
self.visit(node.slice)
|
|
|
|
self.in_assign = old_in_assign
|
|
|
|
|
2017-06-09 15:24:57 +08:00
|
|
|
if self.in_assign and builtins.is_bytes(node.value.type):
|
|
|
|
diag = diagnostic.Diagnostic("error",
|
|
|
|
"type {typ} is not mutable",
|
|
|
|
{"typ": "bytes"},
|
|
|
|
node.loc)
|
|
|
|
self.engine.process(diag)
|
|
|
|
|
2016-03-28 00:10:01 +08:00
|
|
|
def visit_AttributeT(self, node):
|
2017-02-26 09:58:21 +08:00
|
|
|
old_in_assign, self.in_assign = self.in_assign, False
|
|
|
|
self.visit(node.value)
|
|
|
|
self.in_assign = old_in_assign
|
|
|
|
|
2016-03-28 00:10:01 +08:00
|
|
|
if self.in_assign:
|
|
|
|
typ = node.value.type.find()
|
|
|
|
if types.is_instance(typ) and node.attr in typ.constant_attributes:
|
|
|
|
diag = diagnostic.Diagnostic("error",
|
|
|
|
"cannot assign to constant attribute '{attr}' of class '{class}'",
|
|
|
|
{"attr": node.attr, "class": typ.name},
|
|
|
|
node.loc)
|
|
|
|
self.engine.process(diag)
|
|
|
|
return
|