def combine_states(self, left, right): state = State(left.name, [left], left.type, 'branch', self.locate(), read=left.read, set=left.set, over=left.over, over_position=left.over_position) if right is None: state.read = 'no' if left.read == 'no' else 'maybe' state.set = 'no' if left.set == 'no' else 'maybe' state.over = 'no' if left.over == 'no' else 'maybe' else: if not are_types_equal(left.type, right.type): self.report_issue("Type changes", { 'name': left.name, 'old': left.type, 'new': right.type }) state.read = Tifa.match_rso(left.read, right.read) state.set = Tifa.match_rso(left.set, right.set) state.over = Tifa.match_rso(left.over, right.over) if left.over == 'no': state.over_position = right.over_position state.trace.append(right) return state
def store_variable(self, name, type, position=None): """ Update the variable with the given name to now have the new type. Args: name (str): The unqualified name of the variable. The variable will be assumed to be in the current scope. type (Type): The new type of this variable. Returns: State: The new state of the variable. """ if position is None: position = self.locate() full_name = self._scope_chain_str(name) current_path = self.path_chain[0] variable = self.find_variable_scope(name) if not variable.exists: # Create a new instance of the variable on the current path new_state = State(name, [], type, 'store', position, read='no', set='yes', over='no') self.name_map[current_path][full_name] = new_state else: new_state = self.trace_state(variable.state, "store", position) if not variable.in_scope: self.report_issue("Write out of scope", {'name': name}) # Type change? if not are_types_equal(type, variable.state.type): self.report_issue( "Type changes", { 'name': name, 'old': variable.state.type, 'new': type, 'position': position }) new_state.type = type # Overwritten? if variable.state.set == 'yes' and variable.state.read == 'no': new_state.over_position = position new_state.over = 'yes' else: new_state.set = 'yes' new_state.read = 'no' self.name_map[current_path][full_name] = new_state # If this is a class scope... current_scope = self.scope_chain[0] if current_scope in self.class_scopes: self.class_scopes[current_scope].add_attr(name, new_state.type) return new_state
def visit_IfExp(self, node): # Visit the conditional self.visit(node.test) # Visit the body body = self.visit(node.body) # Visit the orelse orelse = self.visit(node.orelse) if are_types_equal(body, orelse): return body # TODO: Union type? return UnknownType()
def visit_IfExp(self, node): # Visit the conditional self.visit(node.test) # Visit the body body = self.visit(node.body) # Visit the orelse orelse = self.visit(node.orelse) if are_types_equal(body, orelse): return body # TODO: Union type? return UnknownType()
def store_variable(self, name, type, position=None): """ Update the variable with the given name to now have the new type. Args: name (str): The unqualified name of the variable. The variable will be assumed to be in the current scope. type (Type): The new type of this variable. Returns: State: The new state of the variable. """ if position is None: position = self.locate() full_name = self._scope_chain_str(name) current_path = self.path_chain[0] variable = self.find_variable_scope(name) if not variable.exists: # Create a new instance of the variable on the current path new_state = State(name, [], type, 'store', position, read='no', set='yes', over='no') self.name_map[current_path][full_name] = new_state else: new_state = self.trace_state(variable.state, "store", position) if not variable.in_scope: self.report_issue("Write out of scope", {'name': name}) # Type change? if not are_types_equal(type, variable.state.type): self.report_issue("Type changes", {'name': name, 'old': variable.state.type, 'new': type, 'position': position}) new_state.type = type # Overwritten? if variable.state.set == 'yes' and variable.state.read == 'no': new_state.over_position = position new_state.over = 'yes' else: new_state.set = 'yes' new_state.read = 'no' self.name_map[current_path][full_name] = new_state # If this is a class scope... current_scope = self.scope_chain[0] if current_scope in self.class_scopes: self.class_scopes[current_scope].add_attr(name, new_state.type) return new_state
def visit_Compare(self, node): # Handle left and right left = self.visit(node.left) comparators = [self.visit(compare) for compare in node.comparators] # Handle ops for op, right in zip(node.ops, comparators): if isinstance(op, (ast.Eq, ast.NotEq, ast.Is, ast.IsNot)): continue elif isinstance(op, (ast.Lt, ast.LtE, ast.GtE, ast.Gt)): if are_types_equal(left, right): if isinstance(left, ORDERABLE_TYPES): continue elif isinstance(op, (ast.In, ast.NotIn)): if isinstance(right, INDEXABLE_TYPES): continue self.report_issue("Incompatible types", {"left": left, "right": right, "operation": op}) return BoolType()
def combine_states(self, left, right): state = State(left.name, [left], left.type, 'branch', self.locate(), read=left.read, set=left.set, over=left.over, over_position=left.over_position) if right is None: state.read = 'no' if left.read == 'no' else 'maybe' state.set = 'no' if left.set == 'no' else 'maybe' state.over = 'no' if left.over == 'no' else 'maybe' else: if not are_types_equal(left.type, right.type): self.report_issue("Type changes", {'name': left.name, 'old': left.type, 'new': right.type}) state.read = Tifa.match_rso(left.read, right.read) state.set = Tifa.match_rso(left.set, right.set) state.over = Tifa.match_rso(left.over, right.over) if left.over == 'no': state.over_position = right.over_position state.trace.append(right) return state
def visit_Compare(self, node): # Handle left and right left = self.visit(node.left) comparators = [self.visit(compare) for compare in node.comparators] # Handle ops for op, right in zip(node.ops, comparators): if isinstance(op, (ast.Eq, ast.NotEq, ast.Is, ast.IsNot)): continue elif isinstance(op, (ast.Lt, ast.LtE, ast.GtE, ast.Gt)): if are_types_equal(left, right): if isinstance(left, ORDERABLE_TYPES): continue elif isinstance(op, (ast.In, ast.NotIn)): if isinstance(right, INDEXABLE_TYPES): continue self.report_issue("Incompatible types", { "left": left, "right": right, "operation": op }) return BoolType()