<commit_before># frozen_string_literal: true

require 'weakref'

# TODO: if a constant is removed, AutoloadEntries should be removed

module DeepCover
  class AutoloadTracker
    AutoloadEntry = Struct.new(:weak_mod, :name, :target_path, :interceptor_path) do
      # If the ref is dead, will return nil, otherwise the target
      def mod
        weak_mod.__getobj__
      rescue RefError
        nil
      end
    end

    attr_reader :autoloads_by_basename, :interceptor_files_by_path
    def initialize
      @autoloads_by_basename = {}
      @interceptor_files_by_path = {}
    end

    def autoload_path_for(mod, name, path)
      interceptor_path = setup_interceptor_for(mod, name, path)

      if DeepCover.custom_requirer.is_being_required?(path)
        $LOADED_FEATURES.first
      else
        interceptor_path
      end
    end

    def possible_autoload_target?(requested_path)
      basename = basename_without_extension(requested_path)
      autoloads = @autoloads_by_basename[basename]
      autoloads && !autoloads.empty?
    end

    def wrap_require(requested_path, absolute_path_found, &block)
      entries = entries_for_target(requested_path, absolute_path_found)

      begin
        entries.each do |entry|
          mod = entry.mod
          next unless mod
          if mod.frozen?
            warn_frozen_module(mod)
            next
          end
          # We set the autoload to a file that is already loaded, this makes ruby happy
          mod.autoload_without_deep_cover(entry.name, $LOADED_FEATURES.first)
        end

        yield
      ensure
        entries = entries_for_target(requested_path, absolute_path_found)
        entries.each do |entry|
          mod = entry.mod
          next unless mod
          if mod.frozen?
            warn_frozen_module(mod)
            next
          end
          # Putting the autoloads back back since we couldn't complete the require
          mod.autoload_without_deep_cover(entry.name, entry.interceptor_path)
        end
      end
    end

    # This is only used on MRI, so ObjectSpace is alright.
    def initialize_autoloaded_paths(mods = ObjectSpace.each_object(Module), &do_autoload_block)
      mods.each do |mod|
        # Module's constants are shared with Object. But if you set autoloads directly on Module, they
        # appear on multiple classes. So just skip, Object will take care of those.
        next if mod == Module

        if mod.frozen?
          if mod.constants.any? { |name| mod.autoload?(name) }
            warn_frozen_module(mod)
          end
          next
        end

        mod.constants.each do |name|
          path = mod.autoload?(name)
          next unless path
          interceptor_path = setup_interceptor_for(mod, name, path)
          yield mod, name, interceptor_path
        end
      end
    end

    # We need to remove the interceptor hooks, otherwise, the problem if manually requiring
    # something that is autoloaded will cause issues.
    def remove_interceptors(&do_autoload_block)
      @autoloads_by_basename.each do |basename, entries|
        entries.each do |entry|
          mod = entry.mod
          next unless mod
          # Module's constants are shared with Object. But if you set autoloads directly on Module, they
          # appear on multiple classes. So just skip, Object will take care of those.
          next if mod == Module
          if mod.frozen?
            warn_frozen_module(mod)<commit_msg>#mod => #mod_if_available<commit_after># frozen_string_literal: true

require 'weakref'

# TODO: if a constant is removed, AutoloadEntries should be removed

module DeepCover
  class AutoloadTracker
    AutoloadEntry = Struct.new(:weak_mod, :name, :target_path, :interceptor_path) do
      # If the ref is dead, will return nil, otherwise the target
      def mod_if_available
        weak_mod.__getobj__
      rescue RefError
        nil
      end
    end

    attr_reader :autoloads_by_basename, :interceptor_files_by_path
    def initialize
      @autoloads_by_basename = {}
      @interceptor_files_by_path = {}
    end

    def autoload_path_for(mod, name, path)
      interceptor_path = setup_interceptor_for(mod, name, path)

      if DeepCover.custom_requirer.is_being_required?(path)
        $LOADED_FEATURES.first
      else
        interceptor_path
      end
    end

    def possible_autoload_target?(requested_path)
      basename = basename_without_extension(requested_path)
      autoloads = @autoloads_by_basename[basename]
      autoloads && !autoloads.empty?
    end

    def wrap_require(requested_path, absolute_path_found, &block)
      entries = entries_for_target(requested_path, absolute_path_found)

      begin
        entries.each do |entry|
          mod = entry.mod_if_available
          next unless mod
          if mod.frozen?
            warn_frozen_module(mod)
            next
          end
          # We set the autoload to a file that is already loaded, this makes ruby happy
          mod.autoload_without_deep_cover(entry.name, $LOADED_FEATURES.first)
        end

        yield
      ensure
        entries = entries_for_target(requested_path, absolute_path_found)
        entries.each do |entry|
          mod = entry.mod_if_available
          next unless mod
          if mod.frozen?
            warn_frozen_module(mod)
            next
          end
          # Putting the autoloads back back since we couldn't complete the require
          mod.autoload_without_deep_cover(entry.name, entry.interceptor_path)
        end
      end
    end

    # This is only used on MRI, so ObjectSpace is alright.
    def initialize_autoloaded_paths(mods = ObjectSpace.each_object(Module), &do_autoload_block)
      mods.each do |mod|
        # Module's constants are shared with Object. But if you set autoloads directly on Module, they
        # appear on multiple classes. So just skip, Object will take care of those.
        next if mod == Module

        if mod.frozen?
          if mod.constants.any? { |name| mod.autoload?(name) }
            warn_frozen_module(mod)
          end
          next
        end

        mod.constants.each do |name|
          path = mod.autoload?(name)
          next unless path
          interceptor_path = setup_interceptor_for(mod, name, path)
          yield mod, name, interceptor_path
        end
      end
    end

    # We need to remove the interceptor hooks, otherwise, the problem if manually requiring
    # something that is autoloaded will cause issues.
    def remove_interceptors(&do_autoload_block)
      @autoloads_by_basename.each do |basename, entries|
        entries.each do |entry|
          mod = entry.mod_if_available
          next unless mod
          # Module's constants are shared with Object. But if you set autoloads directly on Module, they
          # appear on multiple classes. So just skip, Object will take care of those.
          next if mod == Module
          if mod.frozen?
            warn_frozen_module(mod)
{'fraction_non_alphanumeric': 0.058419243986254296, 'fraction_numerical': 0.0, 'mean_word_length': 2.366265060240964, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 4, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3609728', 'n_tokens_mistral': 2073, 'n_tokens_neox': 2027, 'n_words': 592}