from typing import Callable, Dict, List
from typing import Generator
from clang.cindex import CursorKind

from excal.astNode import AstNode
from excal.pluginManager import PluginManager
from excal.offence import Offence


class CXXAstNodeVisitor():
    """This class will run through the AST, and call all Plugins on each node, they wish to be called at."""
    def __init__(self, ast, pm: PluginManager):
        self.ast = ast
        self.visitors: List[NodeVisitor] = pm.getPluginList()
        self.exceptions: List[Offence] = []

    def visitRec(self, node: AstNode) -> None:
        for visitor in self.visitors:
            exepts = visitor.visit(node)
            if exepts is not None:
                self.exceptions.extend([e for e in exepts])
        for node_child in node.children:
            self.visitRec(node_child)

    def visit(self) -> None:
        self.visitRec(self.ast)
        for visitor in self.visitors:
            exepts = visitor.final_call()
            if exepts is not None:
                self.exceptions.extend([e for e in exepts])

    def getExceptions(self) -> List[Offence]:
        return self.exceptions


class NodeVisitor():
    """Visitor class. Plugins will inherit from it."""
    def __init__(self):
        self._jumpTable: Dict[str, Callable[AstNode, Generator[Offence, None, None]]] = {}
        self._jumpTable[str(CursorKind.TRANSLATION_UNIT)] = self.visit_translation_unit
        self._jumpTable[str(CursorKind.UNEXPOSED_DECL)] = self.visit_unexposed_decl
        self._jumpTable[str(CursorKind.STRUCT_DECL)] = self.visit_struct_decl
        self._jumpTable[str(CursorKind.UNION_DECL)] = self.visit_union_decl
        self._jumpTable[str(CursorKind.CLASS_DECL)] = self.visit_class_decl
        self._jumpTable[str(CursorKind.ENUM_DECL)] = self.visit_enum_decl
        self._jumpTable[str(CursorKind.FIELD_DECL)] = self.visit_field_decl
        self._jumpTable[str(CursorKind.ENUM_CONSTANT_DECL)] = self.visit_enum_constant_decl
        self._jumpTable[str(CursorKind.FUNCTION_DECL)] = self.visit_function_decl
        self._jumpTable[str(CursorKind.VAR_DECL)] = self.visit_var_decl
        self._jumpTable[str(CursorKind.PARM_DECL)] = self.visit_param_decl
        self._jumpTable[str(CursorKind.OBJC_INTERFACE_DECL)] = self.visit_objc_interface_decl
        # TODO objective C parameter vowegelassen
        self._jumpTable[str(CursorKind.TYPEDEF_DECL)] = self.visit_typedef_decl
        self._jumpTable[str(CursorKind.CXX_METHOD)] = self.visit_cxx_method
        self._jumpTable[str(CursorKind.NAMESPACE)] = self.visit_namespace
        self._jumpTable[str(CursorKind.CXX_BASE_SPECIFIER)] = self.visit_cxx_base_specifier
        # from here autogenerated, may contain errors

        self._jumpTable[str(CursorKind.LINKAGE_SPEC)] = self.visit_linkage_spec
        self._jumpTable[str(CursorKind.CONSTRUCTOR)] = self.visit_constructor
        self._jumpTable[str(CursorKind.DESTRUCTOR)] = self.visit_destructor
        self._jumpTable[str(CursorKind.CONVERSION_FUNCTION)] = self.visit_conversion_function
        self._jumpTable[str(CursorKind.TEMPLATE_TYPE_PARAMETER)] = self.visit_template_type_parameter
        self._jumpTable[str(CursorKind.TEMPLATE_NON_TYPE_PARAMETER)] = self.visit_template_non_type_parameter
        self._jumpTable[str(CursorKind.TEMPLATE_TEMPLATE_PARAMETER)] = self.visit_template_template_parameter
        self._jumpTable[str(CursorKind.FUNCTION_TEMPLATE)] = self.visit_function_template
        self._jumpTable[str(CursorKind.CLASS_TEMPLATE)] = self.visit_class_template
        self._jumpTable[str(CursorKind.CLASS_TEMPLATE_PARTIAL_SPECIALIZATION)] = \
            self.visit_class_template_partial_specialization
        self._jumpTable[str(CursorKind.NAMESPACE_ALIAS)] = self.visit_namespace_alias
        self._jumpTable[str(CursorKind.USING_DIRECTIVE)] = self.visit_using_directive
        self._jumpTable[str(CursorKind.USING_DECLARATION)] = self.visit_using_declaration
        self._jumpTable[str(CursorKind.TYPE_ALIAS_DECL)] = self.visit_type_alias_decl
        self._jumpTable[str(CursorKind.OBJC_SYNTHESIZE_DECL)] = self.visit_objc_synthesize_decl
        self._jumpTable[str(CursorKind.OBJC_DYNAMIC_DECL)] = self.visit_objc_dynamic_decl
        self._jumpTable[str(CursorKind.CXX_ACCESS_SPEC_DECL)] = self.visit_cxx_access_spec_decl
        self._jumpTable[str(CursorKind.OBJC_SUPER_CLASS_REF)] = self.visit_objc_super_class_ref
        self._jumpTable[str(CursorKind.OBJC_PROTOCOL_REF)] = self.visit_objc_protocol_ref
        self._jumpTable[str(CursorKind.OBJC_CLASS_REF)] = self.visit_objc_class_ref
        self._jumpTable[str(CursorKind.TYPE_REF)] = self.visit_type_ref
        self._jumpTable[str(CursorKind.TEMPLATE_REF)] = self.visit_template_ref
        self._jumpTable[str(CursorKind.NAMESPACE_REF)] = self.visit_namespace_ref
        self._jumpTable[str(CursorKind.MEMBER_REF)] = self.visit_member_ref
        self._jumpTable[str(CursorKind.LABEL_REF)] = self.visit_label_ref
        self._jumpTable[str(CursorKind.OVERLOADED_DECL_REF)] = self.visit_overloaded_decl_ref
        self._jumpTable[str(CursorKind.VARIABLE_REF)] = self.visit_variable_ref
        self._jumpTable[str(CursorKind.INVALID_FILE)] = self.visit_invalid_file
        self._jumpTable[str(CursorKind.NO_DECL_FOUND)] = self.visit_no_decl_found
        self._jumpTable[str(CursorKind.NOT_IMPLEMENTED)] = self.visit_not_implemented
        self._jumpTable[str(CursorKind.INVALID_CODE)] = self.visit_invalid_code
        self._jumpTable[str(CursorKind.UNEXPOSED_EXPR)] = self.visit_unexposed_expr
        self._jumpTable[str(CursorKind.DECL_REF_EXPR)] = self.visit_decl_ref_expr
        self._jumpTable[str(CursorKind.MEMBER_REF_EXPR)] = self.visit_member_ref_expr
        self._jumpTable[str(CursorKind.CALL_EXPR)] = self.visit_call_expr
        self._jumpTable[str(CursorKind.OBJC_MESSAGE_EXPR)] = self.visit_objc_message_expr
        self._jumpTable[str(CursorKind.BLOCK_EXPR)] = self.visit_block_expr
        self._jumpTable[str(CursorKind.INTEGER_LITERAL)] = self.visit_integer_literal
        self._jumpTable[str(CursorKind.FLOATING_LITERAL)] = self.visit_floating_literal
        self._jumpTable[str(CursorKind.IMAGINARY_LITERAL)] = self.visit_imaginary_literal
        self._jumpTable[str(CursorKind.STRING_LITERAL)] = self.visit_string_literal
        self._jumpTable[str(CursorKind.CHARACTER_LITERAL)] = self.visit_character_literal
        self._jumpTable[str(CursorKind.PAREN_EXPR)] = self.visit_paren_expr
        self._jumpTable[str(CursorKind.UNARY_OPERATOR)] = self.visit_unary_operator
        self._jumpTable[str(CursorKind.ARRAY_SUBSCRIPT_EXPR)] = self.visit_array_subscript_expr
        self._jumpTable[str(CursorKind.BINARY_OPERATOR)] = self.visit_binary_operator
        self._jumpTable[str(CursorKind.COMPOUND_ASSIGNMENT_OPERATOR)] = self.visit_compound_assignment_operator
        self._jumpTable[str(CursorKind.CONDITIONAL_OPERATOR)] = self.visit_conditional_operator
        self._jumpTable[str(CursorKind.CSTYLE_CAST_EXPR)] = self.visit_cstyle_cast_expr
        self._jumpTable[str(CursorKind.COMPOUND_LITERAL_EXPR)] = self.visit_compound_literal_expr
        self._jumpTable[str(CursorKind.INIT_LIST_EXPR)] = self.visit_init_list_expr
        self._jumpTable[str(CursorKind.ADDR_LABEL_EXPR)] = self.visit_addr_label_expr
        self._jumpTable[str(CursorKind.StmtExpr)] = self.visit_stmtexpr
        self._jumpTable[str(CursorKind.GENERIC_SELECTION_EXPR)] = self.visit_generic_selection_expr
        self._jumpTable[str(CursorKind.GNU_NULL_EXPR)] = self.visit_gnu_null_expr
        self._jumpTable[str(CursorKind.CXX_STATIC_CAST_EXPR)] = self.visit_cxx_static_cast_expr
        self._jumpTable[str(CursorKind.CXX_DYNAMIC_CAST_EXPR)] = self.visit_cxx_dynamic_cast_expr
        self._jumpTable[str(CursorKind.CXX_REINTERPRET_CAST_EXPR)] = self.visit_cxx_reinterpret_cast_expr
        self._jumpTable[str(CursorKind.CXX_CONST_CAST_EXPR)] = self.visit_cxx_const_cast_expr
        self._jumpTable[str(CursorKind.CXX_FUNCTIONAL_CAST_EXPR)] = self.visit_cxx_functional_cast_expr
        self._jumpTable[str(CursorKind.CXX_TYPEID_EXPR)] = self.visit_cxx_typeid_expr
        self._jumpTable[str(CursorKind.CXX_BOOL_LITERAL_EXPR)] = self.visit_cxx_bool_literal_expr
        self._jumpTable[str(CursorKind.CXX_NULL_PTR_LITERAL_EXPR)] = self.visit_cxx_null_ptr_literal_expr
        self._jumpTable[str(CursorKind.CXX_THIS_EXPR)] = self.visit_cxx_this_expr
        self._jumpTable[str(CursorKind.CXX_THROW_EXPR)] = self.visit_cxx_throw_expr
        self._jumpTable[str(CursorKind.CXX_NEW_EXPR)] = self.visit_cxx_new_expr
        self._jumpTable[str(CursorKind.CXX_DELETE_EXPR)] = self.visit_cxx_delete_expr
        self._jumpTable[str(CursorKind.CXX_UNARY_EXPR)] = self.visit_cxx_unary_expr
        self._jumpTable[str(CursorKind.OBJC_STRING_LITERAL)] = self.visit_objc_string_literal
        self._jumpTable[str(CursorKind.OBJC_ENCODE_EXPR)] = self.visit_objc_encode_expr
        self._jumpTable[str(CursorKind.OBJC_SELECTOR_EXPR)] = self.visit_objc_selector_expr
        self._jumpTable[str(CursorKind.OBJC_PROTOCOL_EXPR)] = self.visit_objc_protocol_expr
        self._jumpTable[str(CursorKind.OBJC_BRIDGE_CAST_EXPR)] = self.visit_objc_bridge_cast_expr
        self._jumpTable[str(CursorKind.PACK_EXPANSION_EXPR)] = self.visit_pack_expansion_expr
        self._jumpTable[str(CursorKind.SIZE_OF_PACK_EXPR)] = self.visit_size_of_pack_expr
        self._jumpTable[str(CursorKind.LAMBDA_EXPR)] = self.visit_lambda_expr
        self._jumpTable[str(CursorKind.OBJ_BOOL_LITERAL_EXPR)] = self.visit_obj_bool_literal_expr
        self._jumpTable[str(CursorKind.OBJ_SELF_EXPR)] = self.visit_obj_self_expr
        self._jumpTable[str(CursorKind.OMP_ARRAY_SECTION_EXPR)] = self.visit_omp_array_section_expr
        self._jumpTable[str(CursorKind.OBJC_AVAILABILITY_CHECK_EXPR)] = self.visit_objc_availability_check_expr
        self._jumpTable[str(CursorKind.UNEXPOSED_STMT)] = self.visit_unexposed_stmt
        self._jumpTable[str(CursorKind.LABEL_STMT)] = self.visit_label_stmt
        self._jumpTable[str(CursorKind.COMPOUND_STMT)] = self.visit_compound_stmt
        self._jumpTable[str(CursorKind.CASE_STMT)] = self.visit_case_stmt
        self._jumpTable[str(CursorKind.DEFAULT_STMT)] = self.visit_default_stmt
        self._jumpTable[str(CursorKind.IF_STMT)] = self.visit_if_stmt
        self._jumpTable[str(CursorKind.SWITCH_STMT)] = self.visit_switch_stmt
        self._jumpTable[str(CursorKind.WHILE_STMT)] = self.visit_while_stmt
        self._jumpTable[str(CursorKind.DO_STMT)] = self.visit_do_stmt
        self._jumpTable[str(CursorKind.FOR_STMT)] = self.visit_for_stmt
        self._jumpTable[str(CursorKind.GOTO_STMT)] = self.visit_goto_stmt
        self._jumpTable[str(CursorKind.INDIRECT_GOTO_STMT)] = self.visit_indirect_goto_stmt
        self._jumpTable[str(CursorKind.CONTINUE_STMT)] = self.visit_continue_stmt
        self._jumpTable[str(CursorKind.BREAK_STMT)] = self.visit_break_stmt
        self._jumpTable[str(CursorKind.RETURN_STMT)] = self.visit_return_stmt
        self._jumpTable[str(CursorKind.ASM_STMT)] = self.visit_asm_stmt
        self._jumpTable[str(CursorKind.OBJC_AT_TRY_STMT)] = self.visit_objc_at_try_stmt
        self._jumpTable[str(CursorKind.OBJC_AT_CATCH_STMT)] = self.visit_objc_at_catch_stmt
        self._jumpTable[str(CursorKind.OBJC_AT_FINALLY_STMT)] = self.visit_objc_at_finally_stmt
        self._jumpTable[str(CursorKind.OBJC_AT_THROW_STMT)] = self.visit_objc_at_throw_stmt
        self._jumpTable[str(CursorKind.OBJC_AT_SYNCHRONIZED_STMT)] = self.visit_objc_at_synchronized_stmt
        self._jumpTable[str(CursorKind.OBJC_AUTORELEASE_POOL_STMT)] = self.visit_objc_autorelease_pool_stmt
        self._jumpTable[str(CursorKind.OBJC_FOR_COLLECTION_STMT)] = self.visit_objc_for_collection_stmt
        self._jumpTable[str(CursorKind.CXX_CATCH_STMT)] = self.visit_cxx_catch_stmt
        self._jumpTable[str(CursorKind.CXX_TRY_STMT)] = self.visit_cxx_try_stmt
        self._jumpTable[str(CursorKind.CXX_FOR_RANGE_STMT)] = self.visit_cxx_for_range_stmt
        self._jumpTable[str(CursorKind.SEH_TRY_STMT)] = self.visit_seh_try_stmt
        self._jumpTable[str(CursorKind.SEH_EXCEPT_STMT)] = self.visit_seh_except_stmt
        self._jumpTable[str(CursorKind.SEH_FINALLY_STMT)] = self.visit_seh_finally_stmt
        self._jumpTable[str(CursorKind.MS_ASM_STMT)] = self.visit_ms_asm_stmt
        self._jumpTable[str(CursorKind.NULL_STMT)] = self.visit_null_stmt
        self._jumpTable[str(CursorKind.DECL_STMT)] = self.visit_decl_stmt
        self._jumpTable[str(CursorKind.OMP_PARALLEL_DIRECTIVE)] = self.visit_omp_parallel_directive
        self._jumpTable[str(CursorKind.OMP_SIMD_DIRECTIVE)] = self.visit_omp_simd_directive
        self._jumpTable[str(CursorKind.OMP_FOR_DIRECTIVE)] = self.visit_omp_for_directive
        self._jumpTable[str(CursorKind.OMP_SECTIONS_DIRECTIVE)] = self.visit_omp_sections_directive
        self._jumpTable[str(CursorKind.OMP_SECTION_DIRECTIVE)] = self.visit_omp_section_directive
        self._jumpTable[str(CursorKind.OMP_SINGLE_DIRECTIVE)] = self.visit_omp_single_directive
        self._jumpTable[str(CursorKind.OMP_PARALLEL_FOR_DIRECTIVE)] = self.visit_omp_parallel_for_directive
        self._jumpTable[str(CursorKind.OMP_PARALLEL_SECTIONS_DIRECTIVE)] = self.visit_omp_parallel_sections_directive
        self._jumpTable[str(CursorKind.OMP_TASK_DIRECTIVE)] = self.visit_omp_task_directive
        self._jumpTable[str(CursorKind.OMP_MASTER_DIRECTIVE)] = self.visit_omp_master_directive
        self._jumpTable[str(CursorKind.OMP_CRITICAL_DIRECTIVE)] = self.visit_omp_critical_directive
        self._jumpTable[str(CursorKind.OMP_TASKYIELD_DIRECTIVE)] = self.visit_omp_taskyield_directive
        self._jumpTable[str(CursorKind.OMP_BARRIER_DIRECTIVE)] = self.visit_omp_barrier_directive
        self._jumpTable[str(CursorKind.OMP_TASKWAIT_DIRECTIVE)] = self.visit_omp_taskwait_directive
        self._jumpTable[str(CursorKind.OMP_FLUSH_DIRECTIVE)] = self.visit_omp_flush_directive
        self._jumpTable[str(CursorKind.SEH_LEAVE_STMT)] = self.visit_seh_leave_stmt
        self._jumpTable[str(CursorKind.OMP_ORDERED_DIRECTIVE)] = self.visit_omp_ordered_directive
        self._jumpTable[str(CursorKind.OMP_ATOMIC_DIRECTIVE)] = self.visit_omp_atomic_directive
        self._jumpTable[str(CursorKind.OMP_FOR_SIMD_DIRECTIVE)] = self.visit_omp_for_simd_directive
        self._jumpTable[str(CursorKind.OMP_PARALLELFORSIMD_DIRECTIVE)] = self.visit_omp_parallelforsimd_directive
        self._jumpTable[str(CursorKind.OMP_TARGET_DIRECTIVE)] = self.visit_omp_target_directive
        self._jumpTable[str(CursorKind.OMP_TEAMS_DIRECTIVE)] = self.visit_omp_teams_directive
        self._jumpTable[str(CursorKind.OMP_TASKGROUP_DIRECTIVE)] = self.visit_omp_taskgroup_directive
        self._jumpTable[str(CursorKind.OMP_CANCELLATION_POINT_DIRECTIVE)] = self.visit_omp_cancellation_point_directive
        self._jumpTable[str(CursorKind.OMP_CANCEL_DIRECTIVE)] = self.visit_omp_cancel_directive
        self._jumpTable[str(CursorKind.OMP_TARGET_DATA_DIRECTIVE)] = self.visit_omp_target_data_directive
        self._jumpTable[str(CursorKind.OMP_TASK_LOOP_DIRECTIVE)] = self.visit_omp_task_loop_directive
        self._jumpTable[str(CursorKind.OMP_TASK_LOOP_SIMD_DIRECTIVE)] = self.visit_omp_task_loop_simd_directive
        self._jumpTable[str(CursorKind.OMP_DISTRIBUTE_DIRECTIVE)] = self.visit_omp_distribute_directive
        self._jumpTable[str(CursorKind.OMP_TARGET_ENTER_DATA_DIRECTIVE)] = self.visit_omp_target_enter_data_directive
        self._jumpTable[str(CursorKind.OMP_TARGET_EXIT_DATA_DIRECTIVE)] = self.visit_omp_target_exit_data_directive
        self._jumpTable[str(CursorKind.OMP_TARGET_PARALLEL_DIRECTIVE)] = self.visit_omp_target_parallel_directive
        self._jumpTable[str(CursorKind.OMP_TARGET_PARALLELFOR_DIRECTIVE)] = self.visit_omp_target_parallelfor_directive
        self._jumpTable[str(CursorKind.OMP_TARGET_UPDATE_DIRECTIVE)] = self.visit_omp_target_update_directive
        self._jumpTable[str(CursorKind.OMP_DISTRIBUTE_PARALLELFOR_DIRECTIVE)] = \
            self.visit_omp_distribute_parallelfor_directive
        self._jumpTable[str(CursorKind.OMP_DISTRIBUTE_PARALLEL_FOR_SIMD_DIRECTIVE)] = \
            self.visit_omp_distribute_parallel_for_simd_directive
        self._jumpTable[str(CursorKind.OMP_DISTRIBUTE_SIMD_DIRECTIVE)] = self.visit_omp_distribute_simd_directive
        self._jumpTable[str(CursorKind.OMP_TARGET_PARALLEL_FOR_SIMD_DIRECTIVE)] = \
            self.visit_omp_target_parallel_for_simd_directive
        self._jumpTable[str(CursorKind.OMP_TARGET_SIMD_DIRECTIVE)] = self.visit_omp_target_simd_directive
        self._jumpTable[str(CursorKind.OMP_TEAMS_DISTRIBUTE_DIRECTIVE)] = self.visit_omp_teams_distribute_directive
        self._jumpTable[str(CursorKind.UNEXPOSED_ATTR)] = self.visit_unexposed_attr
        self._jumpTable[str(CursorKind.IB_ACTION_ATTR)] = self.visit_ib_action_attr
        self._jumpTable[str(CursorKind.IB_OUTLET_ATTR)] = self.visit_ib_outlet_attr
        self._jumpTable[str(CursorKind.IB_OUTLET_COLLECTION_ATTR)] = self.visit_ib_outlet_collection_attr
        self._jumpTable[str(CursorKind.CXX_FINAL_ATTR)] = self.visit_cxx_final_attr
        self._jumpTable[str(CursorKind.CXX_OVERRIDE_ATTR)] = self.visit_cxx_override_attr
        self._jumpTable[str(CursorKind.ANNOTATE_ATTR)] = self.visit_annotate_attr
        self._jumpTable[str(CursorKind.ASM_LABEL_ATTR)] = self.visit_asm_label_attr
        self._jumpTable[str(CursorKind.PACKED_ATTR)] = self.visit_packed_attr
        self._jumpTable[str(CursorKind.PURE_ATTR)] = self.visit_pure_attr
        self._jumpTable[str(CursorKind.CONST_ATTR)] = self.visit_const_attr
        self._jumpTable[str(CursorKind.NODUPLICATE_ATTR)] = self.visit_noduplicate_attr
        self._jumpTable[str(CursorKind.CUDACONSTANT_ATTR)] = self.visit_cudaconstant_attr
        self._jumpTable[str(CursorKind.CUDADEVICE_ATTR)] = self.visit_cudadevice_attr
        self._jumpTable[str(CursorKind.CUDAGLOBAL_ATTR)] = self.visit_cudaglobal_attr
        self._jumpTable[str(CursorKind.CUDAHOST_ATTR)] = self.visit_cudahost_attr
        self._jumpTable[str(CursorKind.CUDASHARED_ATTR)] = self.visit_cudashared_attr
        self._jumpTable[str(CursorKind.VISIBILITY_ATTR)] = self.visit_visibility_attr
        self._jumpTable[str(CursorKind.DLLEXPORT_ATTR)] = self.visit_dllexport_attr
        self._jumpTable[str(CursorKind.DLLIMPORT_ATTR)] = self.visit_dllimport_attr
        self._jumpTable[str(CursorKind.CONVERGENT_ATTR)] = self.visit_convergent_attr
        self._jumpTable[str(CursorKind.WARN_UNUSED_ATTR)] = self.visit_warn_unused_attr
        self._jumpTable[str(CursorKind.WARN_UNUSED_RESULT_ATTR)] = self.visit_warn_unused_result_attr
        self._jumpTable[str(CursorKind.ALIGNED_ATTR)] = self.visit_aligned_attr
        self._jumpTable[str(CursorKind.PREPROCESSING_DIRECTIVE)] = self.visit_preprocessing_directive
        self._jumpTable[str(CursorKind.MACRO_DEFINITION)] = self.visit_macro_definition
        self._jumpTable[str(CursorKind.MACRO_INSTANTIATION)] = self.visit_macro_instantiation
        self._jumpTable[str(CursorKind.INCLUSION_DIRECTIVE)] = self.visit_inclusion_directive
        self._jumpTable[str(CursorKind.MODULE_IMPORT_DECL)] = self.visit_module_import_decl
        self._jumpTable[str(CursorKind.TYPE_ALIAS_TEMPLATE_DECL)] = self.visit_type_alias_template_decl
        self._jumpTable[str(CursorKind.STATIC_ASSERT)] = self.visit_static_assert
        self._jumpTable[str(CursorKind.FRIEND_DECL)] = self.visit_friend_decl
        self._jumpTable[str(CursorKind.OVERLOAD_CANDIDATE)] = self.visit_overload_candidate

    def visit(self, node: AstNode) -> Generator[Offence, None, None]:
        if node.kind in self._jumpTable:
            return self._jumpTable[node.kind](node)
        else:
            return self.visit_default(node)

    def visit_translation_unit(self, node: AstNode) -> None:
        return

    def visit_unexposed_decl(self, node: AstNode) -> None:
        """A declaration whose specific kind is not exposed via this interface."""
        return

    def visit_struct_decl(self, node: AstNode) -> None:
        """A C or C++ struct."""
        return

    def visit_union_decl(self, node: AstNode) -> None:
        """A C or C++ union."""
        return

    def visit_class_decl(self, node: AstNode) -> None:
        """A C++ class."""
        return

    def visit_enum_decl(self, node: AstNode) -> None:
        """A C or C++ enum."""
        return

    def visit_field_decl(self, node: AstNode) -> None:
        """A field (in C) or non-static data member (in C++) in a struct, union, or C++ class."""
        return

    def visit_enum_constant_decl(self, node: AstNode) -> None:
        """An enumerator constant"""
        return

    def visit_function_decl(self, node: AstNode) -> None:
        """A function"""
        return

    def visit_var_decl(self, node: AstNode) -> None:
        """A variable"""
        return

    def visit_param_decl(self, node: AstNode) -> None:
        """A funtion or method parameter"""
        return

    def visit_objc_interface_decl(self, node: AstNode) -> None:
        """An Objective-C @interface."""
        return

    def visit_typedef_decl(self, node: AstNode) -> None:
        """A typedef"""
        return

    def visit_cxx_method(self, node: AstNode) -> None:
        """A C++ class method"""
        return

    def visit_namespace(self, node: AstNode) -> None:
        """A C++ namespace"""
        return

    def visit_cxx_base_specifier(self, node: AstNode) -> None:
        return

    def visit_linkage_spec(self, node: AstNode) -> None:
        return

    def visit_constructor(self, node: AstNode) -> None:
        return

    def visit_destructor(self, node: AstNode) -> None:
        return

    def visit_conversion_function(self, node: AstNode) -> None:
        return

    def visit_template_type_parameter(self, node: AstNode) -> None:
        return

    def visit_template_non_type_parameter(self, node: AstNode) -> None:
        return

    def visit_template_template_parameter(self, node: AstNode) -> None:
        return

    def visit_function_template(self, node: AstNode) -> None:
        return

    def visit_class_template(self, node: AstNode) -> None:
        return

    def visit_class_template_partial_specialization(self, node: AstNode) -> None:
        return

    def visit_namespace_alias(self, node: AstNode) -> None:
        return

    def visit_using_directive(self, node: AstNode) -> None:
        return

    def visit_using_declaration(self, node: AstNode) -> None:
        return

    def visit_type_alias_decl(self, node: AstNode) -> None:
        return

    def visit_objc_synthesize_decl(self, node: AstNode) -> None:
        return

    def visit_objc_dynamic_decl(self, node: AstNode) -> None:
        return

    def visit_cxx_access_spec_decl(self, node: AstNode) -> None:
        return

    def visit_objc_super_class_ref(self, node: AstNode) -> None:
        return

    def visit_objc_protocol_ref(self, node: AstNode) -> None:
        return

    def visit_objc_class_ref(self, node: AstNode) -> None:
        return

    def visit_type_ref(self, node: AstNode) -> None:
        return

    def visit_template_ref(self, node: AstNode) -> None:
        return

    def visit_namespace_ref(self, node: AstNode) -> None:
        return

    def visit_member_ref(self, node: AstNode) -> None:
        return

    def visit_label_ref(self, node: AstNode) -> None:
        return

    def visit_overloaded_decl_ref(self, node: AstNode) -> None:
        return

    def visit_variable_ref(self, node: AstNode) -> None:
        return

    def visit_invalid_file(self, node: AstNode) -> None:
        return

    def visit_no_decl_found(self, node: AstNode) -> None:
        return

    def visit_not_implemented(self, node: AstNode) -> None:
        return

    def visit_invalid_code(self, node: AstNode) -> None:
        return

    def visit_unexposed_expr(self, node: AstNode) -> None:
        return

    def visit_decl_ref_expr(self, node: AstNode) -> None:
        return

    def visit_member_ref_expr(self, node: AstNode) -> None:
        return

    def visit_call_expr(self, node: AstNode) -> None:
        return

    def visit_objc_message_expr(self, node: AstNode) -> None:
        return

    def visit_block_expr(self, node: AstNode) -> None:
        return

    def visit_integer_literal(self, node: AstNode) -> None:
        return

    def visit_floating_literal(self, node: AstNode) -> None:
        return

    def visit_imaginary_literal(self, node: AstNode) -> None:
        return

    def visit_string_literal(self, node: AstNode) -> None:
        return

    def visit_character_literal(self, node: AstNode) -> None:
        return

    def visit_paren_expr(self, node: AstNode) -> None:
        return

    def visit_unary_operator(self, node: AstNode) -> None:
        return

    def visit_array_subscript_expr(self, node: AstNode) -> None:
        return

    def visit_binary_operator(self, node: AstNode) -> None:
        return

    def visit_compound_assignment_operator(self, node: AstNode) -> None:
        return

    def visit_conditional_operator(self, node: AstNode) -> None:
        return

    def visit_cstyle_cast_expr(self, node: AstNode) -> None:
        return

    def visit_compound_literal_expr(self, node: AstNode) -> None:
        return

    def visit_init_list_expr(self, node: AstNode) -> None:
        return

    def visit_addr_label_expr(self, node: AstNode) -> None:
        return

    def visit_stmtexpr(self, node: AstNode) -> None:
        return

    def visit_generic_selection_expr(self, node: AstNode) -> None:
        return

    def visit_gnu_null_expr(self, node: AstNode) -> None:
        return

    def visit_cxx_static_cast_expr(self, node: AstNode) -> None:
        return

    def visit_cxx_dynamic_cast_expr(self, node: AstNode) -> None:
        return

    def visit_cxx_reinterpret_cast_expr(self, node: AstNode) -> None:
        return

    def visit_cxx_const_cast_expr(self, node: AstNode) -> None:
        return

    def visit_cxx_functional_cast_expr(self, node: AstNode) -> None:
        return

    def visit_cxx_typeid_expr(self, node: AstNode) -> None:
        return

    def visit_cxx_bool_literal_expr(self, node: AstNode) -> None:
        return

    def visit_cxx_null_ptr_literal_expr(self, node: AstNode) -> None:
        return

    def visit_cxx_this_expr(self, node: AstNode) -> None:
        return

    def visit_cxx_throw_expr(self, node: AstNode) -> None:
        return

    def visit_cxx_new_expr(self, node: AstNode) -> None:
        return

    def visit_cxx_delete_expr(self, node: AstNode) -> None:
        return

    def visit_cxx_unary_expr(self, node: AstNode) -> None:
        return

    def visit_objc_string_literal(self, node: AstNode) -> None:
        return

    def visit_objc_encode_expr(self, node: AstNode) -> None:
        return

    def visit_objc_selector_expr(self, node: AstNode) -> None:
        return

    def visit_objc_protocol_expr(self, node: AstNode) -> None:
        return

    def visit_objc_bridge_cast_expr(self, node: AstNode) -> None:
        return

    def visit_pack_expansion_expr(self, node: AstNode) -> None:
        return

    def visit_size_of_pack_expr(self, node: AstNode) -> None:
        return

    def visit_lambda_expr(self, node: AstNode) -> None:
        return

    def visit_obj_bool_literal_expr(self, node: AstNode) -> None:
        return

    def visit_obj_self_expr(self, node: AstNode) -> None:
        return

    def visit_omp_array_section_expr(self, node: AstNode) -> None:
        return

    def visit_objc_availability_check_expr(self, node: AstNode) -> None:
        return

    def visit_unexposed_stmt(self, node: AstNode) -> None:
        return

    def visit_label_stmt(self, node: AstNode) -> None:
        return

    def visit_compound_stmt(self, node: AstNode) -> None:
        return

    def visit_case_stmt(self, node: AstNode) -> None:
        return

    def visit_default_stmt(self, node: AstNode) -> None:
        return

    def visit_if_stmt(self, node: AstNode) -> None:
        return

    def visit_switch_stmt(self, node: AstNode) -> None:
        return

    def visit_while_stmt(self, node: AstNode) -> None:
        return

    def visit_do_stmt(self, node: AstNode) -> None:
        return

    def visit_for_stmt(self, node: AstNode) -> None:
        return

    def visit_goto_stmt(self, node: AstNode) -> None:
        return

    def visit_indirect_goto_stmt(self, node: AstNode) -> None:
        return

    def visit_continue_stmt(self, node: AstNode) -> None:
        return

    def visit_break_stmt(self, node: AstNode) -> None:
        return

    def visit_return_stmt(self, node: AstNode) -> None:
        return

    def visit_asm_stmt(self, node: AstNode) -> None:
        return

    def visit_objc_at_try_stmt(self, node: AstNode) -> None:
        return

    def visit_objc_at_catch_stmt(self, node: AstNode) -> None:
        return

    def visit_objc_at_finally_stmt(self, node: AstNode) -> None:
        return

    def visit_objc_at_throw_stmt(self, node: AstNode) -> None:
        return

    def visit_objc_at_synchronized_stmt(self, node: AstNode) -> None:
        return

    def visit_objc_autorelease_pool_stmt(self, node: AstNode) -> None:
        return

    def visit_objc_for_collection_stmt(self, node: AstNode) -> None:
        return

    def visit_cxx_catch_stmt(self, node: AstNode) -> None:
        return

    def visit_cxx_try_stmt(self, node: AstNode) -> None:
        return

    def visit_cxx_for_range_stmt(self, node: AstNode) -> None:
        return

    def visit_seh_try_stmt(self, node: AstNode) -> None:
        return

    def visit_seh_except_stmt(self, node: AstNode) -> None:
        return

    def visit_seh_finally_stmt(self, node: AstNode) -> None:
        return

    def visit_ms_asm_stmt(self, node: AstNode) -> None:
        return

    def visit_null_stmt(self, node: AstNode) -> None:
        return

    def visit_decl_stmt(self, node: AstNode) -> None:
        return

    def visit_omp_parallel_directive(self, node: AstNode) -> None:
        return

    def visit_omp_simd_directive(self, node: AstNode) -> None:
        return

    def visit_omp_for_directive(self, node: AstNode) -> None:
        return

    def visit_omp_sections_directive(self, node: AstNode) -> None:
        return

    def visit_omp_section_directive(self, node: AstNode) -> None:
        return

    def visit_omp_single_directive(self, node: AstNode) -> None:
        return

    def visit_omp_parallel_for_directive(self, node: AstNode) -> None:
        return

    def visit_omp_parallel_sections_directive(self, node: AstNode) -> None:
        return

    def visit_omp_task_directive(self, node: AstNode) -> None:
        return

    def visit_omp_master_directive(self, node: AstNode) -> None:
        return

    def visit_omp_critical_directive(self, node: AstNode) -> None:
        return

    def visit_omp_taskyield_directive(self, node: AstNode) -> None:
        return

    def visit_omp_barrier_directive(self, node: AstNode) -> None:
        return

    def visit_omp_taskwait_directive(self, node: AstNode) -> None:
        return

    def visit_omp_flush_directive(self, node: AstNode) -> None:
        return

    def visit_seh_leave_stmt(self, node: AstNode) -> None:
        return

    def visit_omp_ordered_directive(self, node: AstNode) -> None:
        return

    def visit_omp_atomic_directive(self, node: AstNode) -> None:
        return

    def visit_omp_for_simd_directive(self, node: AstNode) -> None:
        return

    def visit_omp_parallelforsimd_directive(self, node: AstNode) -> None:
        return

    def visit_omp_target_directive(self, node: AstNode) -> None:
        return

    def visit_omp_teams_directive(self, node: AstNode) -> None:
        return

    def visit_omp_taskgroup_directive(self, node: AstNode) -> None:
        return

    def visit_omp_cancellation_point_directive(self, node: AstNode) -> None:
        return

    def visit_omp_cancel_directive(self, node: AstNode) -> None:
        return

    def visit_omp_target_data_directive(self, node: AstNode) -> None:
        return

    def visit_omp_task_loop_directive(self, node: AstNode) -> None:
        return

    def visit_omp_task_loop_simd_directive(self, node: AstNode) -> None:
        return

    def visit_omp_distribute_directive(self, node: AstNode) -> None:
        return

    def visit_omp_target_enter_data_directive(self, node: AstNode) -> None:
        return

    def visit_omp_target_exit_data_directive(self, node: AstNode) -> None:
        return

    def visit_omp_target_parallel_directive(self, node: AstNode) -> None:
        return

    def visit_omp_target_parallelfor_directive(self, node: AstNode) -> None:
        return

    def visit_omp_target_update_directive(self, node: AstNode) -> None:
        return

    def visit_omp_distribute_parallelfor_directive(self, node: AstNode) -> None:
        return

    def visit_omp_distribute_parallel_for_simd_directive(self, node: AstNode) -> None:
        return

    def visit_omp_distribute_simd_directive(self, node: AstNode) -> None:
        return

    def visit_omp_target_parallel_for_simd_directive(self, node: AstNode) -> None:
        return

    def visit_omp_target_simd_directive(self, node: AstNode) -> None:
        return

    def visit_omp_teams_distribute_directive(self, node: AstNode) -> None:
        return

    def visit_unexposed_attr(self, node: AstNode) -> None:
        return

    def visit_ib_action_attr(self, node: AstNode) -> None:
        return

    def visit_ib_outlet_attr(self, node: AstNode) -> None:
        return

    def visit_ib_outlet_collection_attr(self, node: AstNode) -> None:
        return

    def visit_cxx_final_attr(self, node: AstNode) -> None:
        return

    def visit_cxx_override_attr(self, node: AstNode) -> None:
        return

    def visit_annotate_attr(self, node: AstNode) -> None:
        return

    def visit_asm_label_attr(self, node: AstNode) -> None:
        return

    def visit_packed_attr(self, node: AstNode) -> None:
        return

    def visit_pure_attr(self, node: AstNode) -> None:
        return

    def visit_const_attr(self, node: AstNode) -> None:
        return

    def visit_noduplicate_attr(self, node: AstNode) -> None:
        return

    def visit_cudaconstant_attr(self, node: AstNode) -> None:
        return

    def visit_cudadevice_attr(self, node: AstNode) -> None:
        return

    def visit_cudaglobal_attr(self, node: AstNode) -> None:
        return

    def visit_cudahost_attr(self, node: AstNode) -> None:
        return

    def visit_cudashared_attr(self, node: AstNode) -> None:
        return

    def visit_visibility_attr(self, node: AstNode) -> None:
        return

    def visit_dllexport_attr(self, node: AstNode) -> None:
        return

    def visit_dllimport_attr(self, node: AstNode) -> None:
        return

    def visit_convergent_attr(self, node: AstNode) -> None:
        return

    def visit_warn_unused_attr(self, node: AstNode) -> None:
        return

    def visit_warn_unused_result_attr(self, node: AstNode) -> None:
        return

    def visit_aligned_attr(self, node: AstNode) -> None:
        return

    def visit_preprocessing_directive(self, node: AstNode) -> None:
        return

    def visit_macro_definition(self, node: AstNode) -> None:
        return

    def visit_macro_instantiation(self, node: AstNode) -> None:
        return

    def visit_inclusion_directive(self, node: AstNode) -> None:
        return

    def visit_module_import_decl(self, node: AstNode) -> None:
        return

    def visit_type_alias_template_decl(self, node: AstNode) -> None:
        return

    def visit_static_assert(self, node: AstNode) -> None:
        return

    def visit_friend_decl(self, node: AstNode) -> None:
        return

    def visit_overload_candidate(self, node: AstNode) -> None:
        return

    def visit_default(self, node: AstNode) -> None:
        return

    def final_call(self) -> None:
        """This method will be called after the Tree has been searched."""
        return
