<commit_before>% Holds the logic responsible for function definitions (def(p) and defmacro(p)).
-module(elixir_def).
-export([setup/1, reset_last/1, local_for/4,
  take_definition/2, store_definition/6, store_definition/9,
  fetch_definitions/2, format_error/1]).
-include("elixir.hrl").
-define(last_def, {elixir, last_def}).

setup(Module) ->
  reset_last(Module),
  ok.

reset_last(Module) ->
  ets:insert(elixir_module:data_table(Module), {?last_def, []}).

local_for(Module, Name, Arity, Kinds) ->
  Tuple = {Name, Arity},

  try
    T = elixir_module:defs_table(Module),
    {T, ets:lookup(T, {def, Tuple})}
  of
    {Table, [{_, Kind, Meta, File, _, _}]} ->
      case (Kinds == all) orelse (lists:member(Kind, Kinds)) of
        true ->
          Clauses = [Clause || {_, Clause} <- ets:lookup(Table, {clauses, Tuple})],
          elixir_erl:definition_to_anonymous(File, Module, Tuple, Kind, Meta, Clauses);
        false ->
          false
      end;
    {_Table, []} ->
      false
  catch
    error:badarg -> false
  end.

%% Take a definition out of the table

take_definition(Module, Tuple) ->
  Table = elixir_module:defs_table(Module),
  case ets:take(Table, {def, Tuple}) of
    [Result] ->
      {Result, [Clause || {_, Clause} <- ets:take(Table, {clauses, Tuple})]};
    [] ->
      false
  end.

%% Fetch all available definitions

fetch_definitions(File, Module) ->
  Table = elixir_module:defs_table(Module),
  Entries = ets:match(Table, {{def, '$1'}, '_', '_', '_', '_', '_'}),
  {All, Private} = fetch_definition(lists:sort(Entries), File, Module, Table, [], []),
  Unreachable = elixir_locals:warn_unused_local(File, Module, Private),
  elixir_locals:ensure_no_import_conflict(File, Module, All),
  {All, Unreachable}.

fetch_definition([[Tuple] | T], File, Module, Table, All, Private) ->
  [{_, Kind, Meta, _, Check, {Defaults, _, _}}] = ets:lookup(Table, {def, Tuple}),

  try ets:lookup_element(Table, {clauses, Tuple}, 2) of
    Clauses ->
      Unwrapped =
        {Tuple, Kind, Meta, Clauses},
      NewPrivate =
        case (Kind == defp) orelse (Kind == defmacrop) of
          true ->
            WarnMeta = case Check of true -> Meta; false -> false end,
            [{Tuple, Kind, WarnMeta, Defaults} | Private];
          false ->
            Private
        end,
      fetch_definition(T, File, Module, Table, [Unwrapped | All], NewPrivate)
  catch
    error:badarg ->
      warn_bodyless_function(Check, Meta, File, Module, Kind, Tuple),
      fetch_definition(T, File, Module, Table, All, Private)
  end;

fetch_definition([], _File, _Module, _Table, All, Private) ->
  {All, Private}.

%% Section for storing definitions

store_definition(Line, Kind, CheckClauses, Call, Body, Pos) when is_integer(Line) ->
  E = (elixir_locals:get_cached_env(Pos))#{line := Line},
  {NameAndArgs, Guards} = elixir_utils:extract_guards(Call),

  {Name, Args} = case NameAndArgs of
    {N, _, A} when is_atom(N), is_atom(A) -> {N, []};
    {N, _, A} when is_atom(N), is_list(A) -> {N, A};
    _ -> elixir_errors:form_error([{line, Line}], ?key(E, file), ?MODULE,
                                  {invalid_def, Kind, NameAndArgs})
  end,

  %% Now that we have verified the call format,
  %% extract meta information like file and context.
  {_, Meta, _} = Call,
  DoCheckClauses = (not lists:keymember(context, 1, Meta)) andalso (CheckClauses),

  %% Check if there is a file information in the definition.
  %% If so, we assume this come from another source and
  %% we need to linify taking into account keep line numbers.
  %%
  %% Line and File will always point to the caller. __ENV__.line
  %% will always point to the quoted one and __ENV__.file will
  %% always point to the one at @file or the quoted one.
  {Location, Key} =
    case elixir_utils:meta_location(Meta) of
      {_, _} = Keep -> {Keep, keep};
      nil -> {nil, line}
    end,

  Arity        = length(Args),
  LinifyArgs   = elixir_quote:linify(Line, Key, Args),
  LinifyGuards = elixir_quote:linify(Line, Key, Guards),
  LinifyBody   = elixir_quote:linify(Line, Key, Body),
  Generated    = case DoCheckClauses of true -> []; false -> [{generated, true}] end,

  {EL, MetaLocation} =
    case retrieve_location(Location, ?key(E, module)) of
      {F, L} ->
        {E#{file := F}, [{line, Line}, {location, {F, L}} | Generated]};
      nil ->
        {E, [{line, Line} | Generated]}
    end,

  assert_no_aliases_name(MetaLocation, Name, Args, EL),
  assert_valid_name(MetaLocation, Kind, Name, Args, EL),
  store_definition(MetaLocation, Kind, DoCheckClauses, Name, Arity,
                   LinifyArgs, LinifyGuards, LinifyBody, ?key(E, file), EL).

store_definition(Meta, Kind, CheckClauses, Name, Arity, DefaultsArgs, Guards, Body, File, ER) ->
  Module = ?key(ER, module),
  Tuple = {Name, Arity},
  E = ER#{function := Tuple},
<commit_msg>Use generated/1 helper macro in elixir_def<commit_after>% Holds the logic responsible for function definitions (def(p) and defmacro(p)).
-module(elixir_def).
-export([setup/1, reset_last/1, local_for/4,
  take_definition/2, store_definition/6, store_definition/9,
  fetch_definitions/2, format_error/1]).
-include("elixir.hrl").
-define(last_def, {elixir, last_def}).

setup(Module) ->
  reset_last(Module),
  ok.

reset_last(Module) ->
  ets:insert(elixir_module:data_table(Module), {?last_def, []}).

local_for(Module, Name, Arity, Kinds) ->
  Tuple = {Name, Arity},

  try
    T = elixir_module:defs_table(Module),
    {T, ets:lookup(T, {def, Tuple})}
  of
    {Table, [{_, Kind, Meta, File, _, _}]} ->
      case (Kinds == all) orelse (lists:member(Kind, Kinds)) of
        true ->
          Clauses = [Clause || {_, Clause} <- ets:lookup(Table, {clauses, Tuple})],
          elixir_erl:definition_to_anonymous(File, Module, Tuple, Kind, Meta, Clauses);
        false ->
          false
      end;
    {_Table, []} ->
      false
  catch
    error:badarg -> false
  end.

%% Take a definition out of the table

take_definition(Module, Tuple) ->
  Table = elixir_module:defs_table(Module),
  case ets:take(Table, {def, Tuple}) of
    [Result] ->
      {Result, [Clause || {_, Clause} <- ets:take(Table, {clauses, Tuple})]};
    [] ->
      false
  end.

%% Fetch all available definitions

fetch_definitions(File, Module) ->
  Table = elixir_module:defs_table(Module),
  Entries = ets:match(Table, {{def, '$1'}, '_', '_', '_', '_', '_'}),
  {All, Private} = fetch_definition(lists:sort(Entries), File, Module, Table, [], []),
  Unreachable = elixir_locals:warn_unused_local(File, Module, Private),
  elixir_locals:ensure_no_import_conflict(File, Module, All),
  {All, Unreachable}.

fetch_definition([[Tuple] | T], File, Module, Table, All, Private) ->
  [{_, Kind, Meta, _, Check, {Defaults, _, _}}] = ets:lookup(Table, {def, Tuple}),

  try ets:lookup_element(Table, {clauses, Tuple}, 2) of
    Clauses ->
      Unwrapped =
        {Tuple, Kind, Meta, Clauses},
      NewPrivate =
        case (Kind == defp) orelse (Kind == defmacrop) of
          true ->
            WarnMeta = case Check of true -> Meta; false -> false end,
            [{Tuple, Kind, WarnMeta, Defaults} | Private];
          false ->
            Private
        end,
      fetch_definition(T, File, Module, Table, [Unwrapped | All], NewPrivate)
  catch
    error:badarg ->
      warn_bodyless_function(Check, Meta, File, Module, Kind, Tuple),
      fetch_definition(T, File, Module, Table, All, Private)
  end;

fetch_definition([], _File, _Module, _Table, All, Private) ->
  {All, Private}.

%% Section for storing definitions

store_definition(Line, Kind, CheckClauses, Call, Body, Pos) when is_integer(Line) ->
  E = (elixir_locals:get_cached_env(Pos))#{line := Line},
  {NameAndArgs, Guards} = elixir_utils:extract_guards(Call),

  {Name, Args} = case NameAndArgs of
    {N, _, A} when is_atom(N), is_atom(A) -> {N, []};
    {N, _, A} when is_atom(N), is_list(A) -> {N, A};
    _ -> elixir_errors:form_error([{line, Line}], ?key(E, file), ?MODULE,
                                  {invalid_def, Kind, NameAndArgs})
  end,

  %% Now that we have verified the call format,
  %% extract meta information like file and context.
  {_, Meta, _} = Call,
  DoCheckClauses = (not lists:keymember(context, 1, Meta)) andalso (CheckClauses),

  %% Check if there is a file information in the definition.
  %% If so, we assume this come from another source and
  %% we need to linify taking into account keep line numbers.
  %%
  %% Line and File will always point to the caller. __ENV__.line
  %% will always point to the quoted one and __ENV__.file will
  %% always point to the one at @file or the quoted one.
  {Location, Key} =
    case elixir_utils:meta_location(Meta) of
      {_, _} = Keep -> {Keep, keep};
      nil -> {nil, line}
    end,

  Arity        = length(Args),
  LinifyArgs   = elixir_quote:linify(Line, Key, Args),
  LinifyGuards = elixir_quote:linify(Line, Key, Guards),
  LinifyBody   = elixir_quote:linify(Line, Key, Body),
  Generated    = case DoCheckClauses of true -> []; false -> ?generated([]) end,

  {EL, MetaLocation} =
    case retrieve_location(Location, ?key(E, module)) of
      {F, L} ->
        {E#{file := F}, [{line, Line}, {location, {F, L}} | Generated]};
      nil ->
        {E, [{line, Line} | Generated]}
    end,

  assert_no_aliases_name(MetaLocation, Name, Args, EL),
  assert_valid_name(MetaLocation, Kind, Name, Args, EL),
  store_definition(MetaLocation, Kind, DoCheckClauses, Name, Arity,
                   LinifyArgs, LinifyGuards, LinifyBody, ?key(E, file), EL).

store_definition(Meta, Kind, CheckClauses, Name, Arity, DefaultsArgs, Guards, Body, File, ER) ->
  Module = ?key(ER, module),
  Tuple = {Name, Arity},
  E = ER#{function := Tuple},

{'fraction_non_alphanumeric': 0.150751183371064, 'fraction_numerical': 0.0023667421280098785, 'mean_word_length': 3.409709618874773, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 65, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3840867', 'n_tokens_mistral': 3389, 'n_tokens_neox': 3332, 'n_words': 882}