link issues for TODO comments, lint

pull/2099/head
alpharush 1 year ago
parent 961db4563f
commit 404914cdfa
  1. 2
      slither/vyper_parsing/declarations/function.py
  2. 11
      slither/vyper_parsing/expressions/expression_parsing.py
  3. 46
      slither/vyper_parsing/type_parsing.py
  4. 9
      slither/vyper_parsing/variables/local_variable.py
  5. 5
      tests/unit/core/test_function_declaration.py

@ -282,7 +282,7 @@ class FunctionVyper: # pylint: disable=too-many-instance-attributes
curr_node = new_node
elif isinstance(expr, Expr):
# TODO This is a workaround to handle Vyper putting payable/view in the function body...
# TODO This is a workaround to handle Vyper putting payable/view in the function body... https://github.com/vyperlang/vyper/issues/3578
if not isinstance(expr.value, Name):
new_node = self._new_node(NodeType.EXPRESSION, expr.src, scope)
new_node.add_unparsed_expression(expr.value)

@ -83,7 +83,7 @@ def parse_expression(
return literal
if isinstance(expression, Hex):
# TODO this is an implicit conversion and could potentially be bytes20 or other?
# TODO this is an implicit conversion and could potentially be bytes20 or other? https://github.com/vyperlang/vyper/issues/3580
literal = Literal(str(expression.value), ElementaryType("address"))
literal.set_offset(expression.src, caller_context.compilation_unit)
return literal
@ -191,7 +191,7 @@ def parse_expression(
arguments = [parse_expression(a, caller_context) for a in expression.args]
rets = None
# Since the AST lacks the type of the return values, we recover it.
# Since the AST lacks the type of the return values, we recover it. https://github.com/vyperlang/vyper/issues/3581
if isinstance(called, Identifier):
if isinstance(called.value, FunctionContract):
rets = called.value.returns
@ -212,7 +212,7 @@ def parse_expression(
elif isinstance(called.value, Contract):
# Type conversions are not explicitly represented in the AST e.g. converting address to contract/ interface,
# so we infer that a type conversion is occurring if `called` is a `Contract` type.
# so we infer that a type conversion is occurring if `called` is a `Contract` type. https://github.com/vyperlang/vyper/issues/3580
type_to = parse_type(expression.func, caller_context)
parsed_expr = TypeConversion(arguments[0], type_to)
parsed_expr.set_offset(expression.src, caller_context.compilation_unit)
@ -231,7 +231,7 @@ def parse_expression(
if isinstance(expression, Attribute):
member_name = expression.attr
if isinstance(expression.value, Name):
# TODO this is ambiguous because it could be a state variable or a call to balance
# TODO this is ambiguous because it could be a state variable or a call to balance https://github.com/vyperlang/vyper/issues/3582
if expression.value.id == "self" and member_name != "balance":
var = find_variable(member_name, caller_context, is_self=True)
parsed_expr = SelfIdentifier(var)
@ -241,6 +241,7 @@ def parse_expression(
expr = parse_expression(expression.value, caller_context)
# TODO this is ambiguous because it could be a type conversion of an interface or a member access
# see https://github.com/vyperlang/vyper/issues/3580 and ttps://github.com/vyperlang/vyper/issues/3582
if expression.attr == "address":
parsed_expr = TypeConversion(expr, ElementaryType("address"))
parsed_expr.set_offset(expression.src, caller_context.compilation_unit)
@ -258,7 +259,7 @@ def parse_expression(
member_name_ret_type = None
# (recover_type_1) This may be a call to an interface and we don't have the return types,
# so we see if there's a function identifier with `member_name` and propagate the type to
# its enclosing `CallExpression`
# its enclosing `CallExpression`. https://github.com/vyperlang/vyper/issues/3581
if (
isinstance(expr, Identifier)
and isinstance(expr.value, StateVariable)

@ -5,9 +5,10 @@ from slither.core.solidity_types.elementary_type import (
) # TODO rename solidity type
from slither.core.solidity_types.array_type import ArrayType
from slither.core.solidity_types.mapping_type import MappingType
from slither.vyper_parsing.ast.types import Name, Subscript, Call, Index, Tuple
from slither.core.solidity_types.user_defined_type import UserDefinedType
from slither.core.declarations import FunctionContract, Contract
from slither.vyper_parsing.ast.types import Name, Subscript, Call, Index, Tuple
from slither.solc_parsing.exceptions import ParsingError
# pylint: disable=too-many-branches,too-many-return-statements,import-outside-toplevel,too-many-locals
def parse_type(
@ -25,9 +26,24 @@ def parse_type(
if isinstance(annotation, Name):
name = annotation.id
lname = name.lower() # map `String` to string
if lname in ElementaryTypeName:
return ElementaryType(lname)
if name in contract.structures_as_dict:
return UserDefinedType(contract.structures_as_dict[name])
if name in contract.enums_as_dict:
return UserDefinedType(contract.enums_as_dict[name])
if name in contract.file_scope.contracts:
return UserDefinedType(contract.file_scope.contracts[name])
if name in contract.file_scope.structures:
return UserDefinedType(contract.file_scope.structures[name])
elif isinstance(annotation, Subscript):
assert isinstance(annotation.slice, Index)
# This is also a strange construct...
# This is also a strange construct... https://github.com/vyperlang/vyper/issues/3577
if isinstance(annotation.slice.value, Tuple):
assert isinstance(annotation.value, Name)
if annotation.value.id == "DynArray":
@ -44,17 +60,17 @@ def parse_type(
type_ = parse_type(annotation.value, caller_context)
elif isinstance(annotation.value, Name):
# TODO it is weird that the ast_type is `Index` when it's a type annotation and not an expression, so we grab the value.
# Subscript(src='13:10:0', node_id=7, value=Name(src='13:6:0', node_id=8, id='String'), slice=Index(src='13:10:0', node_id=12, value=Int(src='20:2:0', node_id=10, value=64)))
# TODO it is weird that the ast_type is `Index` when it's a type annotation and not an expression, so we grab the value. https://github.com/vyperlang/vyper/issues/3577
type_ = parse_type(annotation.value, caller_context)
if annotation.value.id == "String":
# This is an elementary type
return type_
length = parse_expression(annotation.slice.value, caller_context)
return ArrayType(type_, length)
elif isinstance(annotation, Call):
# TODO event variable represented as Call
# TODO event variable represented as Call https://github.com/vyperlang/vyper/issues/3579
return parse_type(annotation.args[0], caller_context)
elif isinstance(annotation, Tuple):
@ -80,22 +96,4 @@ def parse_type(
return UserDefinedType(st)
else:
assert False
lname = name.lower() # TODO map String to string
if lname in ElementaryTypeName:
return ElementaryType(lname)
if name in contract.structures_as_dict:
return UserDefinedType(contract.structures_as_dict[name])
if name in contract.enums_as_dict:
return UserDefinedType(contract.enums_as_dict[name])
if name in contract.file_scope.contracts:
return UserDefinedType(contract.file_scope.contracts[name])
if name in contract.file_scope.structures:
return UserDefinedType(contract.file_scope.structures[name])
assert False
raise ParsingError(f"Type name not found {name} context {caller_context}")

@ -6,7 +6,7 @@ from slither.vyper_parsing.type_parsing import parse_type
class LocalVariableVyper:
def __init__(self, variable: LocalVariable, variable_data: Union[Arg, Name]) -> None:
def __init__(self, variable: LocalVariable, variable_data: Union[Arg, AnnAssign, Name]) -> None:
self._variable: LocalVariable = variable
if isinstance(variable_data, Arg):
@ -15,12 +15,9 @@ class LocalVariableVyper:
elif isinstance(variable_data, AnnAssign):
self._variable.name = variable_data.target.id
self._elem_to_parse = variable_data.annotation
elif isinstance(variable_data, Name):
self._variable.name = variable_data.id
self._elem_to_parse = variable_data
else:
# param Subscript
self._variable.name = ""
assert isinstance(variable_data, Name)
self._variable.name = variable_data.id
self._elem_to_parse = variable_data
assert isinstance(self._elem_to_parse, (Name, Subscript, Call, Tuple))

@ -305,6 +305,7 @@ def test_public_variable(solc_binary_path) -> None:
assert var.type == ElementaryType("bytes32")
# pylint: disable=too-many-statements
def test_vyper_functions(slither_from_vyper_source) -> None:
with slither_from_vyper_source(
"""
@ -352,6 +353,7 @@ def __default__():
assert not f.view
assert not f.pure
assert not f.is_implemented
assert f.is_empty
f = functions["__default__()"]
assert f.function_type == FunctionType.FALLBACK
@ -360,6 +362,7 @@ def __default__():
assert not f.view
assert not f.pure
assert not f.is_implemented
assert f.is_empty
f = functions["withdraw()"]
assert f.function_type == FunctionType.NORMAL
@ -370,10 +373,12 @@ def __default__():
assert f.can_send_eth()
assert f.can_reenter()
assert f.is_implemented
assert not f.is_empty
f = functions["withdraw_locked()"]
assert not f.is_reentrant
assert f.is_implemented
assert not f.is_empty
var = contract.get_state_variable_from_name("balances")
assert var

Loading…
Cancel
Save