# Buggy code
def find_variable(var_name, caller_context, referenced_declaration=None):
    if isinstance(caller_context, Contract):
        function = None
        contract = caller_context
    elif isinstance(caller_context, Function):
        function = caller_context
        contract = function.contract
    else:
        logger.error("Incorrect caller context")
        exit(-1)

    if function:
        func_variables = function.variables_as_dict()
        if var_name in func_variables:
            return func_variables[var_name]
        # A local variable can be a pointer
        # for example
        # function test(function(uint) internal returns(bool) t) interna{
        # Will have a local variable t which will match the signature
        # t(uint256)
        func_variables_ptr = {get_pointer_name(f): f for f in function.variables}
        if var_name and var_name in func_variables_ptr:
            return func_variables_ptr[var_name]

    contract_variables = contract.variables_as_dict()
    if var_name in contract_variables:
        return contract_variables[var_name]

    # A state variable can be a pointer
    conc_variables_ptr = {get_pointer_name(f): f for f in contract.variables}
    if var_name and var_name in conc_variables_ptr:
        return conc_variables_ptr[var_name]

    functions = contract.functions_as_dict()
    if var_name in functions:
        return functions[var_name]

    modifiers = contract.modifiers_as_dict()
    if var_name in modifiers:
        return modifiers[var_name]

    structures = contract.structures_as_dict()
    if var_name in structures:
        return structures[var_name]

    events = contract.events_as_dict()
    if var_name in events:
        return events[var_name]

    enums = contract.enums_as_dict()
    if var_name in enums:
        return enums[var_name]

    # If the enum is refered as its name rather than its canonicalName
    enums = {e.name: e for e in contract.enums}
    if var_name in enums:
        return enums[var_name]

    # Could refer to any enum
    all_enums = [c.enums_as_dict() for c in contract.slither.contracts]
    all_enums = {k: v for d in all_enums for k, v in d.items()}
    if var_name in all_enums:
        return all_enums[var_name]

    if var_name in SOLIDITY_VARIABLES:
        return SolidityVariable(var_name)

    if var_name in SOLIDITY_FUNCTIONS:
        return SolidityFunction(var_name)

    contracts = contract.slither.contracts_as_dict()
    if var_name in contracts:
        return contracts[var_name]

    if referenced_declaration:
        for contract in contract.slither.contracts:
            if contract.id == referenced_declaration:
                return contract

    raise VariableNotFound("Variable not found: {}".format(var_name))


# Traceback (AssertionError)
ERROR:root:Error in test.sol
ERROR:root:Traceback (most recent call last):
File "/Users/matt/anaconda3/lib/python3.7/site-packages/slither_analyzer-0.5.0-py3.7.egg/slither/__main__.py", line 250, in main_impl
(results, number_contracts) = process(filename, args, detector_classes, printer_classes)
File "/Users/matt/anaconda3/lib/python3.7/site-packages/slither_analyzer-0.5.0-py3.7.egg/slither/__main__.py", line 35, in process
slither = Slither(filename, args.solc, args.disable_solc_warnings, args.solc_args, ast)
File "/Users/matt/anaconda3/lib/python3.7/site-packages/slither_analyzer-0.5.0-py3.7.egg/slither/slither.py", line 41, in __init__
self._analyze_contracts()
File "/Users/matt/anaconda3/lib/python3.7/site-packages/slither_analyzer-0.5.0-py3.7.egg/slither/solc_parsing/slitherSolc.py", line 201, in _analyze_contracts
self._convert_to_slithir()
File "/Users/matt/anaconda3/lib/python3.7/site-packages/slither_analyzer-0.5.0-py3.7.egg/slither/solc_parsing/slitherSolc.py", line 327, in _convert_to_slithir
contract.convert_expression_to_slithir()
File "/Users/matt/anaconda3/lib/python3.7/site-packages/slither_analyzer-0.5.0-py3.7.egg/slither/solc_parsing/declarations/contract.py", line 374, in convert_expression_to_slithir
func.generate_slithir_ssa(all_ssa_state_variables_instances)
File "/Users/matt/anaconda3/lib/python3.7/site-packages/slither_analyzer-0.5.0-py3.7.egg/slither/solc_parsing/declarations/function.py", line 935, in generate_slithir_ssa
add_ssa_ir(self, all_ssa_state_variables_instances)
File "/Users/matt/anaconda3/lib/python3.7/site-packages/slither_analyzer-0.5.0-py3.7.egg/slither/slithir/utils/ssa.py", line 69, in add_ssa_ir
add_phi_origins(function.entry_point, init_definition, dict())
File "/Users/matt/anaconda3/lib/python3.7/site-packages/slither_analyzer-0.5.0-py3.7.egg/slither/slithir/utils/ssa.py", line 363, in add_phi_origins
add_phi_origins(succ, local_variables_definition, state_variables_definition)
File "/Users/matt/anaconda3/lib/python3.7/site-packages/slither_analyzer-0.5.0-py3.7.egg/slither/slithir/utils/ssa.py", line 363, in add_phi_origins
add_phi_origins(succ, local_variables_definition, state_variables_definition)
File "/Users/matt/anaconda3/lib/python3.7/site-packages/slither_analyzer-0.5.0-py3.7.egg/slither/slithir/utils/ssa.py", line 363, in add_phi_origins
add_phi_origins(succ, local_variables_definition, state_variables_definition)
[Previous line repeated 2 more times]
File "/Users/matt/anaconda3/lib/python3.7/site-packages/slither_analyzer-0.5.0-py3.7.egg/slither/slithir/utils/ssa.py", line 356, in add_phi_origins
phi_node.add_phi_origin_local_variable(variable, n)
File "/Users/matt/anaconda3/lib/python3.7/site-packages/slither_analyzer-0.5.0-py3.7.egg/slither/core/cfg/node.py", line 215, in add_phi_origin_local_variable
assert v == variable
AssertionError

# Fixed code
def find_variable(var_name, caller_context, referenced_declaration=None):
    if isinstance(caller_context, Contract):
        function = None
        contract = caller_context
    elif isinstance(caller_context, Function):
        function = caller_context
        contract = function.contract
    else:
        logger.error("Incorrect caller context")
        exit(-1)

    if function:
        # We look for variable declared with the referencedDeclaration attr
        func_variables = function.variables_renamed
        if referenced_declaration and referenced_declaration in func_variables:
            return func_variables[referenced_declaration]
        # If not found, check for name
        func_variables = function.variables_as_dict()
        if var_name in func_variables:
            return func_variables[var_name]
        # A local variable can be a pointer
        # for example
        # function test(function(uint) internal returns(bool) t) interna{
        # Will have a local variable t which will match the signature
        # t(uint256)
        func_variables_ptr = {get_pointer_name(f): f for f in function.variables}
        if var_name and var_name in func_variables_ptr:
            return func_variables_ptr[var_name]

    contract_variables = contract.variables_as_dict()
    if var_name in contract_variables:
        return contract_variables[var_name]

    # A state variable can be a pointer
    conc_variables_ptr = {get_pointer_name(f): f for f in contract.variables}
    if var_name and var_name in conc_variables_ptr:
        return conc_variables_ptr[var_name]

    functions = contract.functions_as_dict()
    if var_name in functions:
        return functions[var_name]

    modifiers = contract.modifiers_as_dict()
    if var_name in modifiers:
        return modifiers[var_name]

    structures = contract.structures_as_dict()
    if var_name in structures:
        return structures[var_name]

    events = contract.events_as_dict()
    if var_name in events:
        return events[var_name]

    enums = contract.enums_as_dict()
    if var_name in enums:
        return enums[var_name]

    # If the enum is refered as its name rather than its canonicalName
    enums = {e.name: e for e in contract.enums}
    if var_name in enums:
        return enums[var_name]

    # Could refer to any enum
    all_enums = [c.enums_as_dict() for c in contract.slither.contracts]
    all_enums = {k: v for d in all_enums for k, v in d.items()}
    if var_name in all_enums:
        return all_enums[var_name]

    if var_name in SOLIDITY_VARIABLES:
        return SolidityVariable(var_name)

    if var_name in SOLIDITY_FUNCTIONS:
        return SolidityFunction(var_name)

    contracts = contract.slither.contracts_as_dict()
    if var_name in contracts:
        return contracts[var_name]

    if referenced_declaration:
        for contract in contract.slither.contracts:
            if contract.id == referenced_declaration:
                return contract

    raise VariableNotFound("Variable not found: {}".format(var_name))