1defmodule Module do 2 @moduledoc ~S''' 3 Provides functions to deal with modules during compilation time. 4 5 It allows a developer to dynamically add, delete and register 6 attributes, attach documentation and so forth. 7 8 After a module is compiled, using many of the functions in 9 this module will raise errors, since it is out of their scope 10 to inspect runtime data. Most of the runtime data can be inspected 11 via the [`__info__/1`](`c:Module.__info__/1`) function attached to 12 each compiled module. 13 14 ## Module attributes 15 16 Each module can be decorated with one or more attributes. The following ones 17 are currently defined by Elixir: 18 19 ### `@after_compile` 20 21 A hook that will be invoked right after the current module is compiled. 22 Accepts a module or a `{module, function_name}`. See the "Compile callbacks" 23 section below. 24 25 ### `@before_compile` 26 27 A hook that will be invoked before the module is compiled. 28 Accepts a module or a `{module, function_or_macro_name}` tuple. 29 See the "Compile callbacks" section below. 30 31 ### `@behaviour` 32 33 Note the British spelling! 34 35 Behaviours can be referenced by modules to ensure they implement 36 required specific function signatures defined by `@callback`. 37 38 For example, you could specify a `URI.Parser` behaviour as follows: 39 40 defmodule URI.Parser do 41 @doc "Defines a default port" 42 @callback default_port() :: integer 43 44 @doc "Parses the given URL" 45 @callback parse(uri_info :: URI.t()) :: URI.t() 46 end 47 48 And then a module may use it as: 49 50 defmodule URI.HTTP do 51 @behaviour URI.Parser 52 def default_port(), do: 80 53 def parse(info), do: info 54 end 55 56 If the behaviour changes or `URI.HTTP` does not implement 57 one of the callbacks, a warning will be raised. 58 59 For detailed documentation, see the 60 [behaviour typespec documentation](typespecs.md#behaviours). 61 62 ### `@impl` 63 64 To aid in the correct implementation of behaviours, you may optionally declare 65 `@impl` for implemented callbacks of a behaviour. This makes callbacks 66 explicit and can help you to catch errors in your code. The compiler will warn 67 in these cases: 68 69 * if you mark a function with `@impl` when that function is not a callback. 70 71 * if you don't mark a function with `@impl` when other functions are marked 72 with `@impl`. If you mark one function with `@impl`, you must mark all 73 other callbacks for that behaviour as `@impl`. 74 75 `@impl` works on a per-context basis. If you generate a function through a macro 76 and mark it with `@impl`, that won't affect the module where that function is 77 generated in. 78 79 `@impl` also helps with maintainability by making it clear to other developers 80 that the function is implementing a callback. 81 82 Using `@impl`, the example above can be rewritten as: 83 84 defmodule URI.HTTP do 85 @behaviour URI.Parser 86 87 @impl true 88 def default_port(), do: 80 89 90 @impl true 91 def parse(info), do: info 92 end 93 94 You may pass either `false`, `true`, or a specific behaviour to `@impl`. 95 96 defmodule Foo do 97 @behaviour Bar 98 @behaviour Baz 99 100 # Will warn if neither Bar nor Baz specify a callback named bar/0. 101 @impl true 102 def bar(), do: :ok 103 104 # Will warn if Baz does not specify a callback named baz/0. 105 @impl Baz 106 def baz(), do: :ok 107 end 108 109 The code is now more readable, as it is now clear which functions are 110 part of your API and which ones are callback implementations. To reinforce this 111 idea, `@impl true` automatically marks the function as `@doc false`, disabling 112 documentation unless `@doc` is explicitly set. 113 114 ### `@compile` 115 116 Defines options for module compilation. This is used to configure 117 both Elixir and Erlang compilers, as any other compilation pass 118 added by external tools. For example: 119 120 defmodule MyModule do 121 @compile {:inline, my_fun: 1} 122 123 def my_fun(arg) do 124 to_string(arg) 125 end 126 end 127 128 Multiple uses of `@compile` will accumulate instead of overriding 129 previous ones. See the "Compile options" section below. 130 131 ### `@deprecated` 132 133 Provides the deprecation reason for a function. For example: 134 135 defmodule Keyword do 136 @deprecated "Use Kernel.length/1 instead" 137 def size(keyword) do 138 length(keyword) 139 end 140 end 141 142 The Mix compiler automatically looks for calls to deprecated modules 143 and emit warnings during compilation. 144 145 Using the `@deprecated` attribute will also be reflected in the 146 documentation of the given function and macro. You can choose between 147 the `@deprecated` attribute and the documentation metadata to provide 148 hard-deprecations (with warnings) and soft-deprecations (without warnings): 149 150 This is a soft-deprecation as it simply annotates the documentation 151 as deprecated: 152 153 @doc deprecated: "Use Kernel.length/1 instead" 154 def size(keyword) 155 156 This is a hard-deprecation as it emits warnings and annotates the 157 documentation as deprecated: 158 159 @deprecated "Use Kernel.length/1 instead" 160 def size(keyword) 161 162 Currently `@deprecated` only supports functions and macros. However 163 you can use the `:deprecated` key in the annotation metadata to 164 annotate the docs of modules, types and callbacks too. 165 166 We recommend using this feature with care, especially library authors. 167 Deprecating code always pushes the burden towards library users. We 168 also recommend for deprecated functionality to be maintained for long 169 periods of time, even after deprecation, giving developers plenty of 170 time to update (except for cases where keeping the deprecated API is 171 undesired, such as in the presence of security issues). 172 173 ### `@doc` and `@typedoc` 174 175 Provides documentation for the entity that follows the attribute. 176 `@doc` is to be used with a function, macro, callback, or 177 macrocallback, while `@typedoc` with a type (public or opaque). 178 179 Accepts a string (often a heredoc) or `false` where `@doc false` will 180 make the entity invisible to documentation extraction tools like 181 [`ExDoc`](https://hexdocs.pm/ex_doc/). For example: 182 183 defmodule MyModule do 184 @typedoc "This type" 185 @typedoc since: "1.1.0" 186 @type t :: term 187 188 @doc "Hello world" 189 @doc since: "1.1.0" 190 def hello do 191 "world" 192 end 193 194 @doc """ 195 Sums `a` to `b`. 196 """ 197 def sum(a, b) do 198 a + b 199 end 200 end 201 202 As can be seen in the example above, `@doc` and `@typedoc` also accept 203 a keyword list that serves as a way to provide arbitrary metadata 204 about the entity. Tools like [`ExDoc`](https://hexdocs.pm/ex_doc/) and 205 `IEx` may use this information to display annotations. A common use 206 case is `since` that may be used to annotate in which version the 207 function was introduced. 208 209 As illustrated in the example, it is possible to use these attributes 210 more than once before an entity. However, the compiler will warn if 211 used twice with binaries as that replaces the documentation text from 212 the preceding use. Multiple uses with keyword lists will merge the 213 lists into one. 214 215 Note that since the compiler also defines some additional metadata, 216 there are a few reserved keys that will be ignored and warned if used. 217 Currently these are: `:opaque` and `:defaults`. 218 219 Once this module is compiled, this information becomes available via 220 the `Code.fetch_docs/1` function. 221 222 ### `@dialyzer` 223 224 Defines warnings to request or suppress when using a version of 225 `:dialyzer` that supports module attributes. 226 227 Accepts an atom, a tuple, or a list of atoms and tuples. For example: 228 229 defmodule MyModule do 230 @dialyzer {:nowarn_function, my_fun: 1} 231 232 def my_fun(arg) do 233 M.not_a_function(arg) 234 end 235 end 236 237 For the list of supported warnings, see 238 [`:dialyzer` module](`:dialyzer`). 239 240 Multiple uses of `@dialyzer` will accumulate instead of overriding 241 previous ones. 242 243 ### `@external_resource` 244 245 Specifies an external resource for the current module. 246 247 Sometimes a module embeds information from an external file. This 248 attribute allows the module to annotate which external resources 249 have been used. 250 251 Tools may use this information to ensure the module is recompiled 252 in case any of the external resources change, see for example: 253 [`mix compile.elixir`](https://hexdocs.pm/mix/Mix.Tasks.Compile.Elixir.html). 254 255 If the external resource does not exist, the module still has 256 a dependency on it, causing the module to be recompiled as soon 257 as the file is added. 258 259 ### `@file` 260 261 Changes the filename used in stacktraces for the function or macro that 262 follows the attribute, such as: 263 264 defmodule MyModule do 265 @doc "Hello world" 266 @file "hello.ex" 267 def hello do 268 "world" 269 end 270 end 271 272 ### `@moduledoc` 273 274 Provides documentation for the current module. 275 276 defmodule MyModule do 277 @moduledoc """ 278 A very useful module. 279 """ 280 @moduledoc authors: ["Alice", "Bob"] 281 end 282 283 Accepts a string (often a heredoc) or `false` where `@moduledoc false` 284 will make the module invisible to documentation extraction tools like 285 [`ExDoc`](https://hexdocs.pm/ex_doc/). 286 287 Similarly to `@doc` also accepts a keyword list to provide metadata 288 about the module. For more details, see the documentation of `@doc` 289 above. 290 291 Once this module is compiled, this information becomes available via 292 the `Code.fetch_docs/1` function. 293 294 ### `@on_definition` 295 296 A hook that will be invoked when each function or macro in the current 297 module is defined. Useful when annotating functions. 298 299 Accepts a module or a `{module, function_name}` tuple. See the 300 "Compile callbacks" section below. 301 302 ### `@on_load` 303 304 A hook that will be invoked whenever the module is loaded. 305 306 Accepts the function name (as an atom) of a function in the current module or 307 `{function_name, 0}` tuple where `function_name` is the name of a function in 308 the current module. The function must have an arity of 0 (no arguments). If 309 the function does not return `:ok`, the loading of the module will be aborted. 310 For example: 311 312 defmodule MyModule do 313 @on_load :load_check 314 315 def load_check do 316 if some_condition() do 317 :ok 318 else 319 :abort 320 end 321 end 322 323 def some_condition do 324 false 325 end 326 end 327 328 Modules compiled with HiPE would not call this hook. 329 330 ### `@vsn` 331 332 Specify the module version. Accepts any valid Elixir value, for example: 333 334 defmodule MyModule do 335 @vsn "1.0" 336 end 337 338 ### Struct attributes 339 340 * `@derive` - derives an implementation for the given protocol for the 341 struct defined in the current module 342 343 * `@enforce_keys` - ensures the given keys are always set when building 344 the struct defined in the current module 345 346 See `Kernel.defstruct/1` for more information on building and using structs. 347 348 ### Typespec attributes 349 350 The following attributes are part of typespecs and are also built-in in 351 Elixir: 352 353 * `@type` - defines a type to be used in `@spec` 354 * `@typep` - defines a private type to be used in `@spec` 355 * `@opaque` - defines an opaque type to be used in `@spec` 356 * `@spec` - provides a specification for a function 357 * `@callback` - provides a specification for a behaviour callback 358 * `@macrocallback` - provides a specification for a macro behaviour callback 359 * `@optional_callbacks` - specifies which behaviour callbacks and macro 360 behaviour callbacks are optional 361 * `@impl` - declares an implementation of a callback function or macro 362 363 For detailed documentation, see the [typespec documentation](typespecs.md). 364 365 ### Custom attributes 366 367 In addition to the built-in attributes outlined above, custom attributes may 368 also be added. Custom attributes are expressed using the `@/1` operator followed 369 by a valid variable name. The value given to the custom attribute must be a valid 370 Elixir value: 371 372 defmodule MyModule do 373 @custom_attr [some: "stuff"] 374 end 375 376 For more advanced options available when defining custom attributes, see 377 `register_attribute/3`. 378 379 ## Compile callbacks 380 381 There are three callbacks that are invoked when functions are defined, 382 as well as before and immediately after the module bytecode is generated. 383 384 ### `@after_compile` 385 386 A hook that will be invoked right after the current module is compiled. 387 388 Accepts a module or a `{module, function_name}` tuple. The function 389 must take two arguments: the module environment and its bytecode. 390 When just a module is provided, the function is assumed to be 391 `__after_compile__/2`. 392 393 Callbacks will run in the order they are registered. 394 395 #### Example 396 397 defmodule MyModule do 398 @after_compile __MODULE__ 399 400 def __after_compile__(env, _bytecode) do 401 IO.inspect(env) 402 end 403 end 404 405 ### `@before_compile` 406 407 A hook that will be invoked before the module is compiled. 408 409 Accepts a module or a `{module, function_or_macro_name}` tuple. The 410 function/macro must take one argument: the module environment. If 411 it's a macro, its returned value will be injected at the end of the 412 module definition before the compilation starts. 413 414 When just a module is provided, the function/macro is assumed to be 415 `__before_compile__/1`. 416 417 Callbacks will run in the order they are registered. Any overridable 418 definition will be made concrete before the first callback runs. 419 A definition may be made overridable again in another before compile 420 callback and it will be made concrete one last time after all callbacks 421 run. 422 423 *Note*: unlike `@after_compile`, the callback function/macro must 424 be placed in a separate module (because when the callback is invoked, 425 the current module does not yet exist). 426 427 #### Example 428 429 defmodule A do 430 defmacro __before_compile__(_env) do 431 quote do 432 def hello, do: "world" 433 end 434 end 435 end 436 437 defmodule B do 438 @before_compile A 439 end 440 441 B.hello() 442 #=> "world" 443 444 ### `@on_definition` 445 446 A hook that will be invoked when each function or macro in the current 447 module is defined. Useful when annotating functions. 448 449 Accepts a module or a `{module, function_name}` tuple. The function 450 must take 6 arguments: 451 452 * the module environment 453 * the kind of the function/macro: `:def`, `:defp`, `:defmacro`, or `:defmacrop` 454 * the function/macro name 455 * the list of quoted arguments 456 * the list of quoted guards 457 * the quoted function body 458 459 If the function/macro being defined has multiple clauses, the hook will 460 be called for each clause. 461 462 Unlike other hooks, `@on_definition` will only invoke functions and 463 never macros. This is to avoid `@on_definition` callbacks from 464 redefining functions that have just been defined in favor of more 465 explicit approaches. 466 467 When just a module is provided, the function is assumed to be 468 `__on_definition__/6`. 469 470 #### Example 471 472 defmodule Hooks do 473 def on_def(_env, kind, name, args, guards, body) do 474 IO.puts("Defining #{kind} named #{name} with args:") 475 IO.inspect(args) 476 IO.puts("and guards") 477 IO.inspect(guards) 478 IO.puts("and body") 479 IO.puts(Macro.to_string(body)) 480 end 481 end 482 483 defmodule MyModule do 484 @on_definition {Hooks, :on_def} 485 486 def hello(arg) when is_binary(arg) or is_list(arg) do 487 "Hello" <> to_string(arg) 488 end 489 490 def hello(_) do 491 :ok 492 end 493 end 494 495 ## Compile options 496 497 The `@compile` attribute accepts different options that are used by both 498 Elixir and Erlang compilers. Some of the common use cases are documented 499 below: 500 501 * `@compile :debug_info` - includes `:debug_info` regardless of the 502 corresponding setting in `Code.get_compiler_option/1` 503 504 * `@compile {:debug_info, false}` - disables `:debug_info` regardless 505 of the corresponding setting in `Code.get_compiler_option/1` 506 507 * `@compile {:inline, some_fun: 2, other_fun: 3}` - inlines the given 508 name/arity pairs. Inlining is applied locally, calls from another 509 module are not affected by this option 510 511 * `@compile {:autoload, false}` - disables automatic loading of 512 modules after compilation. Instead, the module will be loaded after 513 it is dispatched to 514 515 * `@compile {:no_warn_undefined, Mod}` or 516 `@compile {:no_warn_undefined, {Mod, fun, arity}}` - does not warn if 517 the given module or the given `Mod.fun/arity` are not defined 518 519 ''' 520 521 @typep definition :: {atom, arity} 522 @typep def_kind :: :def | :defp | :defmacro | :defmacrop 523 524 @extra_error_msg_defines? "Use Kernel.function_exported?/3 and Kernel.macro_exported?/3 " <> 525 "to check for public functions and macros instead" 526 527 @extra_error_msg_definitions_in "Use the Module.__info__/1 callback to get public functions and macros instead" 528 529 @doc """ 530 Provides runtime information about functions, macros, and other information 531 defined by the module. 532 533 Each module gets an `__info__/1` function when it's compiled. The function 534 takes one of the following items: 535 536 * `:attributes` - a keyword list with all persisted attributes 537 538 * `:compile` - a list with compiler metadata 539 540 * `:functions` - a keyword list of public functions and their arities 541 542 * `:macros` - a keyword list of public macros and their arities 543 544 * `:md5` - the MD5 of the module 545 546 * `:module` - the module atom name 547 548 """ 549 @callback __info__(:attributes) :: keyword() 550 @callback __info__(:compile) :: [term()] 551 @callback __info__(:functions) :: keyword() 552 @callback __info__(:macros) :: keyword() 553 @callback __info__(:md5) :: binary() 554 @callback __info__(:module) :: module() 555 556 @doc """ 557 Returns information about module attributes used by Elixir. 558 559 See the "Module attributes" section in the module documentation for more 560 information on each attribute. 561 562 ## Examples 563 564 iex> map = Module.reserved_attributes() 565 iex> Map.has_key?(map, :moduledoc) 566 true 567 iex> Map.has_key?(map, :doc) 568 true 569 570 """ 571 @doc since: "1.12.0" 572 def reserved_attributes() do 573 %{ 574 after_compile: %{ 575 doc: "A hook that will be invoked right after the current module is compiled." 576 }, 577 before_compile: %{ 578 doc: "A hook that will be invoked before the module is compiled." 579 }, 580 behaviour: %{ 581 doc: "Specifies that the current module implements a given behaviour." 582 }, 583 on_definition: %{ 584 doc: 585 "A hook that will be invoked when each function or macro in the current module is defined." 586 }, 587 impl: %{ 588 doc: "Declares an implementation of a callback function or macro." 589 }, 590 compile: %{ 591 doc: "Defines options for module compilation." 592 }, 593 deprecated: %{ 594 doc: "Provides the deprecation reason for a function." 595 }, 596 moduledoc: %{ 597 doc: "Provides documentation for the current module." 598 }, 599 doc: %{ 600 doc: "Provides documentation for a function/macro/callback." 601 }, 602 typedoc: %{ 603 doc: "Provides documentation for a type." 604 }, 605 dialyzer: %{ 606 doc: "Defines Dialyzer warnings to request or suppress." 607 }, 608 external_resource: %{ 609 doc: "Specifies an external resource for the current module." 610 }, 611 file: %{ 612 doc: 613 "Changes the filename used in stacktraces for the function or macro that follows the attribute." 614 }, 615 on_load: %{ 616 doc: "A hook that will be invoked whenever the module is loaded." 617 }, 618 vsn: %{ 619 doc: "Specify the module version." 620 }, 621 type: %{ 622 doc: "Defines a type to be used in `@spec`." 623 }, 624 typep: %{ 625 doc: "Defines a private type to be used in `@spec`." 626 }, 627 opaque: %{ 628 doc: "Defines an opaque type to be used in `@spec`." 629 }, 630 spec: %{ 631 doc: "Provides a specification for a function." 632 }, 633 callback: %{ 634 doc: "Provides a specification for a behaviour callback." 635 }, 636 macrocallback: %{ 637 doc: "Provides a specification for a macro behaviour callback." 638 }, 639 optional_callbacks: %{ 640 doc: "Specifies which behaviour callbacks and macro behaviour callbacks are optional." 641 }, 642 derive: %{ 643 doc: 644 "Derives an implementation for the given protocol for the struct defined in the current module." 645 }, 646 enforce_keys: %{ 647 doc: 648 "Ensures the given keys are always set when building the struct defined in the current module." 649 } 650 } 651 end 652 653 @doc """ 654 Checks if a module is open. 655 656 A module is "open" if it is currently being defined and its attributes and 657 functions can be modified. 658 """ 659 @spec open?(module) :: boolean 660 def open?(module) when is_atom(module) do 661 :elixir_module.is_open(module) 662 end 663 664 @doc """ 665 Evaluates the quoted contents in the given module's context. 666 667 A list of environment options can also be given as argument. 668 See `Code.eval_string/3` for more information. 669 670 Raises an error if the module was already compiled. 671 672 ## Examples 673 674 defmodule Foo do 675 contents = 676 quote do 677 def sum(a, b), do: a + b 678 end 679 680 Module.eval_quoted(__MODULE__, contents) 681 end 682 683 Foo.sum(1, 2) 684 #=> 3 685 686 For convenience, you can pass any `Macro.Env` struct, such 687 as `__ENV__/0`, as the first argument or as options. Both 688 the module and all options will be automatically extracted 689 from the environment: 690 691 defmodule Foo do 692 contents = 693 quote do 694 def sum(a, b), do: a + b 695 end 696 697 Module.eval_quoted(__ENV__, contents) 698 end 699 700 Foo.sum(1, 2) 701 #=> 3 702 703 Note that if you pass a `Macro.Env` struct as first argument 704 while also passing `opts`, they will be merged with `opts` 705 having precedence. 706 """ 707 @spec eval_quoted(module | Macro.Env.t(), Macro.t(), list, keyword | Macro.Env.t()) :: term 708 def eval_quoted(module_or_env, quoted, binding \\ [], opts \\ []) 709 710 def eval_quoted(%Macro.Env{} = env, quoted, binding, opts) 711 when is_list(binding) and is_list(opts) do 712 validated_eval_quoted(env.module, quoted, binding, struct!(env, opts)) 713 end 714 715 def eval_quoted(module, quoted, binding, %Macro.Env{} = env) 716 when is_atom(module) and is_list(binding) do 717 validated_eval_quoted(module, quoted, binding, env) 718 end 719 720 def eval_quoted(module, quoted, binding, opts) 721 when is_atom(module) and is_list(binding) and is_list(opts) do 722 validated_eval_quoted(module, quoted, binding, opts) 723 end 724 725 defp validated_eval_quoted(module, quoted, binding, env_or_opts) do 726 assert_not_compiled!({:eval_quoted, 4}, module) 727 :elixir_def.reset_last(module) 728 env = :elixir.env_for_eval(env_or_opts) 729 {value, binding, _env} = :elixir.eval_quoted(quoted, binding, %{env | module: module}) 730 {value, binding} 731 end 732 733 @doc """ 734 Creates a module with the given name and defined by 735 the given quoted expressions. 736 737 The line where the module is defined and its file **must** 738 be passed as options. 739 740 It returns a tuple of shape `{:module, module, binary, term}` 741 where `module` is the module name, `binary` is the module 742 bytecode and `term` is the result of the last expression in 743 `quoted`. 744 745 Similar to `Kernel.defmodule/2`, the binary will only be 746 written to disk as a `.beam` file if `Module.create/3` is 747 invoked in a file that is currently being compiled. 748 749 ## Examples 750 751 contents = 752 quote do 753 def world, do: true 754 end 755 756 Module.create(Hello, contents, Macro.Env.location(__ENV__)) 757 758 Hello.world() 759 #=> true 760 761 ## Differences from `defmodule` 762 763 `Module.create/3` works similarly to `Kernel.defmodule/2` 764 and return the same results. While one could also use 765 `defmodule` to define modules dynamically, this function 766 is preferred when the module body is given by a quoted 767 expression. 768 769 Another important distinction is that `Module.create/3` 770 allows you to control the environment variables used 771 when defining the module, while `Kernel.defmodule/2` 772 automatically uses the environment it is invoked at. 773 """ 774 @spec create(module, Macro.t(), Macro.Env.t() | keyword) :: {:module, module, binary, term} 775 def create(module, quoted, opts) 776 777 def create(module, quoted, %Macro.Env{} = env) when is_atom(module) do 778 create(module, quoted, Map.to_list(env)) 779 end 780 781 def create(module, quoted, opts) when is_atom(module) and is_list(opts) do 782 unless Keyword.has_key?(opts, :file) do 783 raise ArgumentError, "expected :file to be given as option" 784 end 785 786 next = :elixir_module.next_counter(nil) 787 line = Keyword.get(opts, :line, 0) 788 quoted = :elixir_quote.linify_with_context_counter(line, {module, next}, quoted) 789 :elixir_module.compile(module, quoted, [], :elixir.env_for_eval(opts)) 790 end 791 792 @doc """ 793 Concatenates a list of aliases and returns a new alias. 794 795 It handles binaries and atoms. 796 797 ## Examples 798 799 iex> Module.concat([Foo, Bar]) 800 Foo.Bar 801 802 iex> Module.concat([Foo, "Bar"]) 803 Foo.Bar 804 805 """ 806 @spec concat([binary | atom]) :: atom 807 def concat(list) when is_list(list) do 808 :elixir_aliases.concat(list) 809 end 810 811 @doc """ 812 Concatenates two aliases and returns a new alias. 813 814 It handles binaries and atoms. 815 816 ## Examples 817 818 iex> Module.concat(Foo, Bar) 819 Foo.Bar 820 821 iex> Module.concat(Foo, "Bar") 822 Foo.Bar 823 824 """ 825 @spec concat(binary | atom, binary | atom) :: atom 826 def concat(left, right) 827 when (is_binary(left) or is_atom(left)) and (is_binary(right) or is_atom(right)) do 828 :elixir_aliases.concat([left, right]) 829 end 830 831 @doc """ 832 Concatenates a list of aliases and returns a new alias only if the alias 833 was already referenced. 834 835 If the alias was not referenced yet, fails with `ArgumentError`. 836 It handles binaries and atoms. 837 838 ## Examples 839 840 iex> Module.safe_concat([List, Chars]) 841 List.Chars 842 843 """ 844 @spec safe_concat([binary | atom]) :: atom 845 def safe_concat(list) when is_list(list) do 846 :elixir_aliases.safe_concat(list) 847 end 848 849 @doc """ 850 Concatenates two aliases and returns a new alias only if the alias was 851 already referenced. 852 853 If the alias was not referenced yet, fails with `ArgumentError`. 854 It handles binaries and atoms. 855 856 ## Examples 857 858 iex> Module.safe_concat(List, Chars) 859 List.Chars 860 861 """ 862 @spec safe_concat(binary | atom, binary | atom) :: atom 863 def safe_concat(left, right) 864 when (is_binary(left) or is_atom(left)) and (is_binary(right) or is_atom(right)) do 865 :elixir_aliases.safe_concat([left, right]) 866 end 867 868 # Build signatures to be stored in docs 869 870 defp build_signature(args, env) do 871 {reverse_args, counters} = simplify_args(args, %{}, [], env) 872 expand_keys(reverse_args, counters, []) 873 end 874 875 defp simplify_args([arg | args], counters, acc, env) do 876 {arg, counters} = simplify_arg(arg, counters, env) 877 simplify_args(args, counters, [arg | acc], env) 878 end 879 880 defp simplify_args([], counters, reverse_args, _env) do 881 {reverse_args, counters} 882 end 883 884 defp simplify_arg({:\\, _, [left, right]}, counters, env) do 885 {left, counters} = simplify_arg(left, counters, env) 886 887 right = 888 Macro.prewalk(right, fn 889 {:@, _, _} = attr -> Macro.expand_once(attr, env) 890 other -> other 891 end) 892 893 {{:\\, [], [left, right]}, counters} 894 end 895 896 # If the variable is being used explicitly for naming, 897 # we always give it a higher priority (nil) even if it 898 # starts with underscore. 899 defp simplify_arg({:=, _, [{var, _, atom}, _]}, counters, _env) when is_atom(atom) do 900 {simplify_var(var, nil), counters} 901 end 902 903 defp simplify_arg({:=, _, [_, {var, _, atom}]}, counters, _env) when is_atom(atom) do 904 {simplify_var(var, nil), counters} 905 end 906 907 # If we have only the variable as argument, it also gets 908 # higher priority. However, if the variable starts with an 909 # underscore, we give it a secondary context (Elixir) with 910 # lower priority. 911 defp simplify_arg({var, _, atom}, counters, _env) when is_atom(atom) do 912 {simplify_var(var, Elixir), counters} 913 end 914 915 defp simplify_arg({:%, _, [left, _]}, counters, env) do 916 case Macro.expand_once(left, env) do 917 module when is_atom(module) -> autogenerated_key(counters, simplify_module_name(module)) 918 _ -> autogenerated_key(counters, :struct) 919 end 920 end 921 922 defp simplify_arg({:%{}, _, _}, counters, _env) do 923 autogenerated_key(counters, :map) 924 end 925 926 defp simplify_arg({:@, _, _} = attr, counters, env) do 927 simplify_arg(Macro.expand_once(attr, env), counters, env) 928 end 929 930 defp simplify_arg(other, counters, _env) when is_integer(other), 931 do: autogenerated_key(counters, :int) 932 933 defp simplify_arg(other, counters, _env) when is_boolean(other), 934 do: autogenerated_key(counters, :bool) 935 936 defp simplify_arg(other, counters, _env) when is_atom(other), 937 do: autogenerated_key(counters, :atom) 938 939 defp simplify_arg(other, counters, _env) when is_list(other), 940 do: autogenerated_key(counters, :list) 941 942 defp simplify_arg(other, counters, _env) when is_float(other), 943 do: autogenerated_key(counters, :float) 944 945 defp simplify_arg(other, counters, _env) when is_binary(other), 946 do: autogenerated_key(counters, :binary) 947 948 defp simplify_arg(_, counters, _env), do: autogenerated_key(counters, :arg) 949 950 defp simplify_var(var, guess_priority) do 951 case Atom.to_string(var) do 952 "_" -> {:_, [], guess_priority} 953 "_" <> rest -> {String.to_atom(rest), [], guess_priority} 954 _ -> {var, [], nil} 955 end 956 end 957 958 defp simplify_module_name(module) when is_atom(module) do 959 try do 960 split(module) 961 rescue 962 ArgumentError -> module 963 else 964 module_name -> String.to_atom(Macro.underscore(List.last(module_name))) 965 end 966 end 967 968 defp autogenerated_key(counters, key) do 969 case counters do 970 %{^key => :once} -> {key, %{counters | key => 2}} 971 %{^key => value} -> {key, %{counters | key => value + 1}} 972 %{} -> {key, Map.put(counters, key, :once)} 973 end 974 end 975 976 defp expand_keys([{:\\, meta, [key, default]} | keys], counters, acc) when is_atom(key) do 977 {var, counters} = expand_key(key, counters) 978 expand_keys(keys, counters, [{:\\, meta, [var, default]} | acc]) 979 end 980 981 defp expand_keys([key | keys], counters, acc) when is_atom(key) do 982 {var, counters} = expand_key(key, counters) 983 expand_keys(keys, counters, [var | acc]) 984 end 985 986 defp expand_keys([arg | args], counters, acc) do 987 expand_keys(args, counters, [arg | acc]) 988 end 989 990 defp expand_keys([], _counters, acc) do 991 acc 992 end 993 994 defp expand_key(key, counters) do 995 case counters do 996 %{^key => count} when is_integer(count) and count >= 1 -> 997 {{:"#{key}#{count}", [], Elixir}, Map.put(counters, key, count - 1)} 998 999 _ -> 1000 {{key, [], Elixir}, counters} 1001 end 1002 end 1003 1004 # Merge 1005 1006 defp merge_signatures([h1 | t1], [h2 | t2], i) do 1007 [merge_signature(h1, h2, i) | merge_signatures(t1, t2, i + 1)] 1008 end 1009 1010 defp merge_signatures([], [], _) do 1011 [] 1012 end 1013 1014 defp merge_signature({:\\, meta, [left, right]}, newer, i) do 1015 {:\\, meta, [merge_signature(left, newer, i), right]} 1016 end 1017 1018 defp merge_signature(older, {:\\, _, [left, _]}, i) do 1019 merge_signature(older, left, i) 1020 end 1021 1022 # The older signature, when given, always have higher precedence 1023 defp merge_signature({_, _, nil} = older, _newer, _), do: older 1024 defp merge_signature(_older, {_, _, nil} = newer, _), do: newer 1025 1026 # Both are a guess, so check if they are the same guess 1027 defp merge_signature({var, _, _} = older, {var, _, _}, _), do: older 1028 1029 # Otherwise, returns a generic guess 1030 defp merge_signature({_, meta, _}, _newer, i), do: {:"arg#{i}", meta, Elixir} 1031 1032 @doc """ 1033 Checks if the module defines the given function or macro. 1034 1035 Use `defines?/3` to assert for a specific type. 1036 1037 This function can only be used on modules that have not yet been compiled. 1038 Use `Kernel.function_exported?/3` and `Kernel.macro_exported?/3` to check for 1039 public functions and macros respectively in compiled modules. 1040 1041 Note that `defines?` returns false for functions and macros that have 1042 been defined but then marked as overridable and no other implementation 1043 has been provided. You can check the overridable status by calling 1044 `overridable?/2`. 1045 1046 ## Examples 1047 1048 defmodule Example do 1049 Module.defines?(__MODULE__, {:version, 0}) #=> false 1050 def version, do: 1 1051 Module.defines?(__MODULE__, {:version, 0}) #=> true 1052 end 1053 1054 """ 1055 @spec defines?(module, definition) :: boolean 1056 def defines?(module, {name, arity} = tuple) 1057 when is_atom(module) and is_atom(name) and is_integer(arity) and arity >= 0 and arity <= 255 do 1058 assert_not_compiled!(__ENV__.function, module, @extra_error_msg_defines?) 1059 {set, _bag} = data_tables_for(module) 1060 :ets.member(set, {:def, tuple}) 1061 end 1062 1063 @doc """ 1064 Checks if the module defines a function or macro of the 1065 given `kind`. 1066 1067 `kind` can be any of `:def`, `:defp`, `:defmacro`, or `:defmacrop`. 1068 1069 This function can only be used on modules that have not yet been compiled. 1070 Use `Kernel.function_exported?/3` and `Kernel.macro_exported?/3` to check for 1071 public functions and macros respectively in compiled modules. 1072 1073 ## Examples 1074 1075 defmodule Example do 1076 Module.defines?(__MODULE__, {:version, 0}, :def) #=> false 1077 def version, do: 1 1078 Module.defines?(__MODULE__, {:version, 0}, :def) #=> true 1079 end 1080 1081 """ 1082 @spec defines?(module, definition, def_kind) :: boolean 1083 def defines?(module, {name, arity} = tuple, def_kind) 1084 when is_atom(module) and is_atom(name) and is_integer(arity) and arity >= 0 and arity <= 255 and 1085 def_kind in [:def, :defp, :defmacro, :defmacrop] do 1086 assert_not_compiled!(__ENV__.function, module, @extra_error_msg_defines?) 1087 1088 {set, _bag} = data_tables_for(module) 1089 1090 case :ets.lookup(set, {:def, tuple}) do 1091 [{_, ^def_kind, _, _, _, _}] -> true 1092 _ -> false 1093 end 1094 end 1095 1096 @doc """ 1097 Checks if the current module defines the given type (private, opaque or not). 1098 1099 This function is only available for modules being compiled. 1100 """ 1101 @doc since: "1.7.0" 1102 @spec defines_type?(module, definition) :: boolean 1103 def defines_type?(module, definition) do 1104 Kernel.Typespec.defines_type?(module, definition) 1105 end 1106 1107 @doc """ 1108 Copies the given spec as a callback. 1109 1110 Returns `true` if there is such a spec and it was copied as a callback. 1111 If the function associated to the spec has documentation defined prior to 1112 invoking this function, the docs are copied too. 1113 """ 1114 @doc since: "1.7.0" 1115 @spec spec_to_callback(module, definition) :: boolean 1116 def spec_to_callback(module, definition) do 1117 Kernel.Typespec.spec_to_callback(module, definition) 1118 end 1119 1120 @doc """ 1121 Returns all module attributes names defined in `module`. 1122 1123 This function can only be used on modules that have not yet been compiled. 1124 1125 ## Examples 1126 1127 defmodule Example do 1128 @foo 1 1129 Module.register_attribute(__MODULE__, :bar, accumulate: true) 1130 1131 :foo in Module.attributes_in(__MODULE__) 1132 #=> true 1133 1134 :bar in Module.attributes_in(__MODULE__) 1135 #=> true 1136 end 1137 1138 """ 1139 @doc since: "1.13.0" 1140 @spec attributes_in(module) :: [atom] 1141 def attributes_in(module) when is_atom(module) do 1142 assert_not_compiled!(__ENV__.function, module) 1143 {set, _} = data_tables_for(module) 1144 :ets.select(set, [{{:"$1", :_, :_}, [{:is_atom, :"$1"}], [:"$1"]}]) 1145 end 1146 1147 @doc """ 1148 Returns all overridable definitions in `module`. 1149 1150 Note a definition is included even if it was was already overridden. 1151 You can use `defines?/2` to see if a definition exists or one is pending. 1152 1153 This function can only be used on modules that have not yet been compiled. 1154 1155 ## Examples 1156 1157 defmodule Example do 1158 def foo, do: 1 1159 def bar, do: 2 1160 1161 defoverridable foo: 1, bar: 1 1162 def foo, do: 3 1163 1164 [:bar, :foo] = Module.overridables_in(__MODULE__) |> Enum.sort() 1165 end 1166 1167 """ 1168 @doc since: "1.13.0" 1169 @spec overridables_in(module) :: [atom] 1170 def overridables_in(module) when is_atom(module) do 1171 assert_not_compiled!(__ENV__.function, module) 1172 :elixir_overridable.overridables_for(module) 1173 end 1174 1175 @doc """ 1176 Returns all functions and macros defined in `module`. 1177 1178 It returns a list with all defined functions and macros, public and private, 1179 in the shape of `[{name, arity}, ...]`. 1180 1181 This function can only be used on modules that have not yet been compiled. 1182 Use the `c:Module.__info__/1` callback to get the public functions and macros in 1183 compiled modules. 1184 1185 ## Examples 1186 1187 defmodule Example do 1188 def version, do: 1 1189 defmacrop test(arg), do: arg 1190 Module.definitions_in(__MODULE__) #=> [{:version, 0}, {:test, 1}] 1191 end 1192 1193 """ 1194 @spec definitions_in(module) :: [definition] 1195 def definitions_in(module) when is_atom(module) do 1196 assert_not_compiled!(__ENV__.function, module, @extra_error_msg_definitions_in) 1197 {_, bag} = data_tables_for(module) 1198 bag_lookup_element(bag, :defs, 2) 1199 end 1200 1201 @doc """ 1202 Returns all functions defined in `module`, according 1203 to its kind. 1204 1205 This function can only be used on modules that have not yet been compiled. 1206 Use the `c:Module.__info__/1` callback to get the public functions and macros in 1207 compiled modules. 1208 1209 ## Examples 1210 1211 defmodule Example do 1212 def version, do: 1 1213 Module.definitions_in(__MODULE__, :def) #=> [{:version, 0}] 1214 Module.definitions_in(__MODULE__, :defp) #=> [] 1215 end 1216 1217 """ 1218 @spec definitions_in(module, def_kind) :: [definition] 1219 def definitions_in(module, kind) 1220 when is_atom(module) and kind in [:def, :defp, :defmacro, :defmacrop] do 1221 assert_not_compiled!(__ENV__.function, module, @extra_error_msg_definitions_in) 1222 {set, _} = data_tables_for(module) 1223 :ets.select(set, [{{{:def, :"$1"}, kind, :_, :_, :_, :_}, [], [:"$1"]}]) 1224 end 1225 1226 @doc """ 1227 Returns the definition for the given name-arity pair. 1228 1229 It returns a tuple with the `version`, the `kind`, 1230 the definition `metadata`, and a list with each clause. 1231 Each clause is a four-element tuple with metadata, 1232 the arguments, the guards, and the clause AST. 1233 1234 The clauses are returned in the Elixir AST but a subset 1235 that has already been expanded and normalized. This makes 1236 it useful for analyzing code but it cannot be reinjected 1237 into the module as it will have lost some of its original 1238 context. Given this AST representation is mostly internal, 1239 it is versioned and it may change at any time. Therefore, 1240 **use this API with caution**. 1241 1242 ## Options 1243 1244 * `:nillify_clauses` (since v1.13.0) - returns `nil` instead 1245 of returning the clauses. This is useful when there is 1246 only an interest in fetching the kind and metadata 1247 1248 """ 1249 @spec get_definition(module, definition, keyword) :: 1250 {:v1, def_kind, meta :: keyword, 1251 [{meta :: keyword, arguments :: [Macro.t()], guards :: [Macro.t()], Macro.t()}] | nil} 1252 @doc since: "1.12.0" 1253 def get_definition(module, {name, arity}, options \\ []) 1254 when is_atom(module) and is_atom(name) and is_integer(arity) and is_list(options) do 1255 assert_not_compiled!(__ENV__.function, module, "") 1256 {set, bag} = data_tables_for(module) 1257 1258 case :ets.lookup(set, {:def, {name, arity}}) do 1259 [{_key, kind, meta, _, _, _}] -> 1260 clauses = 1261 if options[:nillify_clauses], 1262 do: nil, 1263 else: bag_lookup_element(bag, {:clauses, {name, arity}}, 2) 1264 1265 {:v1, kind, meta, clauses} 1266 1267 [] -> 1268 nil 1269 end 1270 end 1271 1272 @doc """ 1273 Deletes a definition from a module. 1274 1275 It returns true if the definition exists and it was removed, 1276 otherwise it returns false. 1277 """ 1278 @doc since: "1.12.0" 1279 @spec delete_definition(module, definition) :: boolean() 1280 def delete_definition(module, {name, arity}) 1281 when is_atom(module) and is_atom(name) and is_integer(arity) do 1282 assert_not_readonly!(__ENV__.function, module) 1283 1284 case :elixir_def.take_definition(module, {name, arity}) do 1285 false -> 1286 false 1287 1288 _ -> 1289 :elixir_locals.yank({name, arity}, module) 1290 true 1291 end 1292 end 1293 1294 @doc """ 1295 Makes the given functions in `module` overridable. 1296 1297 An overridable function is lazily defined, allowing a 1298 developer to customize it. See `Kernel.defoverridable/1` for 1299 more information and documentation. 1300 1301 Once a function or a macro is marked as overridable, it will 1302 no longer be listed under `definitions_in/1` or return true 1303 when given to `defines?/2` until another implementation is 1304 given. 1305 """ 1306 @spec make_overridable(module, [definition]) :: :ok 1307 def make_overridable(module, tuples) when is_atom(module) and is_list(tuples) do 1308 assert_not_readonly!(__ENV__.function, module) 1309 1310 func = fn 1311 {function_name, arity} = tuple 1312 when is_atom(function_name) and is_integer(arity) and arity >= 0 and arity <= 255 -> 1313 case :elixir_def.take_definition(module, tuple) do 1314 false -> 1315 raise ArgumentError, 1316 "cannot make function #{function_name}/#{arity} " <> 1317 "overridable because it was not defined" 1318 1319 clause -> 1320 neighbours = :elixir_locals.yank(tuple, module) 1321 :elixir_overridable.record_overridable(module, tuple, clause, neighbours) 1322 end 1323 1324 other -> 1325 raise ArgumentError, 1326 "each element in tuple list has to be a " <> 1327 "{function_name :: atom, arity :: 0..255} tuple, got: #{inspect(other)}" 1328 end 1329 1330 :lists.foreach(func, tuples) 1331 end 1332 1333 @spec make_overridable(module, module) :: :ok 1334 def make_overridable(module, behaviour) when is_atom(module) and is_atom(behaviour) do 1335 case check_module_for_overridable(module, behaviour) do 1336 :ok -> 1337 :ok 1338 1339 {:error, error_explanation} -> 1340 raise ArgumentError, 1341 "cannot pass module #{inspect(behaviour)} as argument " <> 1342 "to defoverridable/1 because #{error_explanation}" 1343 end 1344 1345 behaviour_callbacks = 1346 for callback <- behaviour_info(behaviour, :callbacks) do 1347 {pair, _kind} = normalize_macro_or_function_callback(callback) 1348 pair 1349 end 1350 1351 tuples = 1352 for definition <- definitions_in(module), 1353 definition in behaviour_callbacks, 1354 do: definition 1355 1356 make_overridable(module, tuples) 1357 end 1358 1359 defp check_module_for_overridable(module, behaviour) do 1360 {_, bag} = data_tables_for(module) 1361 behaviour_definitions = bag_lookup_element(bag, {:accumulate, :behaviour}, 2) 1362 1363 cond do 1364 not Code.ensure_loaded?(behaviour) -> 1365 {:error, "it was not defined"} 1366 1367 not function_exported?(behaviour, :behaviour_info, 1) -> 1368 {:error, "it does not define any callbacks"} 1369 1370 behaviour not in behaviour_definitions -> 1371 error_message = 1372 "its corresponding behaviour is missing. Did you forget to " <> 1373 "add @behaviour #{inspect(behaviour)}?" 1374 1375 {:error, error_message} 1376 1377 true -> 1378 :ok 1379 end 1380 end 1381 1382 defp normalize_macro_or_function_callback({function_name, arity}) do 1383 case :erlang.atom_to_list(function_name) do 1384 # Macros are always provided one extra argument in behaviour_info/1 1385 'MACRO-' ++ tail -> 1386 {{:erlang.list_to_atom(tail), arity - 1}, :defmacro} 1387 1388 _ -> 1389 {{function_name, arity}, :def} 1390 end 1391 end 1392 1393 defp behaviour_info(module, key) do 1394 case module.behaviour_info(key) do 1395 list when is_list(list) -> list 1396 :undefined -> [] 1397 end 1398 end 1399 1400 @doc """ 1401 Returns `true` if `tuple` in `module` was marked as overridable 1402 at some point. 1403 1404 Note `overridable?/2` returns true even if the definition was 1405 already overridden. You can use `defines?/2` to see if a definition 1406 exists or one is pending. 1407 """ 1408 @spec overridable?(module, definition) :: boolean 1409 def overridable?(module, {function_name, arity} = tuple) 1410 when is_atom(function_name) and is_integer(arity) and arity >= 0 and arity <= 255 do 1411 :elixir_overridable.overridable_for(module, tuple) != :not_overridable 1412 end 1413 1414 @doc """ 1415 Puts a module attribute with `key` and `value` in the given `module`. 1416 1417 ## Examples 1418 1419 defmodule MyModule do 1420 Module.put_attribute(__MODULE__, :custom_threshold_for_lib, 10) 1421 end 1422 1423 """ 1424 @spec put_attribute(module, atom, term) :: :ok 1425 def put_attribute(module, key, value) when is_atom(module) and is_atom(key) do 1426 __put_attribute__(module, key, value, nil) 1427 end 1428 1429 @doc """ 1430 Gets the given attribute from a module. 1431 1432 If the attribute was marked with `accumulate` with 1433 `Module.register_attribute/3`, a list is always returned. 1434 `nil` is returned if the attribute has not been marked with 1435 `accumulate` and has not been set to any value. 1436 1437 The `@` macro compiles to a call to this function. For example, 1438 the following code: 1439 1440 @foo 1441 1442 Expands to something akin to: 1443 1444 Module.get_attribute(__MODULE__, :foo) 1445 1446 This function can only be used on modules that have not yet been compiled. 1447 Use the `c:Module.__info__/1` callback to get all persisted attributes, or 1448 `Code.fetch_docs/1` to retrieve all documentation related attributes in 1449 compiled modules. 1450 1451 ## Examples 1452 1453 defmodule Foo do 1454 Module.put_attribute(__MODULE__, :value, 1) 1455 Module.get_attribute(__MODULE__, :value) #=> 1 1456 1457 Module.get_attribute(__MODULE__, :value, :default) #=> 1 1458 Module.get_attribute(__MODULE__, :not_found, :default) #=> :default 1459 1460 Module.register_attribute(__MODULE__, :value, accumulate: true) 1461 Module.put_attribute(__MODULE__, :value, 1) 1462 Module.get_attribute(__MODULE__, :value) #=> [1] 1463 end 1464 1465 """ 1466 @spec get_attribute(module, atom, term) :: term 1467 def get_attribute(module, key, default \\ nil) when is_atom(module) and is_atom(key) do 1468 case __get_attribute__(module, key, nil) do 1469 nil -> default 1470 value -> value 1471 end 1472 end 1473 1474 @doc """ 1475 Checks if the given attribute has been defined. 1476 1477 An attribute is defined if it has been registered with `register_attribute/3` 1478 or assigned a value. If an attribute has been deleted with `delete_attribute/2` 1479 it is no longer considered defined. 1480 1481 This function can only be used on modules that have not yet been compiled. 1482 1483 ## Examples 1484 1485 defmodule MyModule do 1486 @value 1 1487 Module.register_attribute(__MODULE__, :other_value) 1488 Module.put_attribute(__MODULE__, :another_value, 1) 1489 1490 Module.has_attribute?(__MODULE__, :value) #=> true 1491 Module.has_attribute?(__MODULE__, :other_value) #=> true 1492 Module.has_attribute?(__MODULE__, :another_value) #=> true 1493 1494 Module.has_attribute?(__MODULE__, :undefined) #=> false 1495 1496 Module.delete_attribute(__MODULE__, :value) 1497 Module.has_attribute?(__MODULE__, :value) #=> false 1498 end 1499 1500 """ 1501 @doc since: "1.10.0" 1502 @spec has_attribute?(module, atom) :: boolean 1503 def has_attribute?(module, key) when is_atom(module) and is_atom(key) do 1504 assert_not_compiled!(__ENV__.function, module) 1505 {set, _bag} = data_tables_for(module) 1506 1507 :ets.member(set, key) 1508 end 1509 1510 @doc """ 1511 Deletes the module attribute that matches the given key. 1512 1513 It returns the deleted attribute value (or `nil` if nothing was set). 1514 1515 ## Examples 1516 1517 defmodule MyModule do 1518 Module.put_attribute(__MODULE__, :custom_threshold_for_lib, 10) 1519 Module.delete_attribute(__MODULE__, :custom_threshold_for_lib) 1520 end 1521 1522 """ 1523 @spec delete_attribute(module, atom) :: term 1524 def delete_attribute(module, key) when is_atom(module) and is_atom(key) do 1525 assert_not_readonly!(__ENV__.function, module) 1526 {set, bag} = data_tables_for(module) 1527 1528 case :ets.lookup(set, key) do 1529 [{_, _, :accumulate}] -> 1530 reverse_values(:ets.take(bag, {:accumulate, key}), []) 1531 1532 [{_, value, _}] -> 1533 :ets.delete(set, key) 1534 value 1535 1536 [] -> 1537 nil 1538 end 1539 end 1540 1541 defp reverse_values([{_, value} | tail], acc), do: reverse_values(tail, [value | acc]) 1542 defp reverse_values([], acc), do: acc 1543 1544 @doc """ 1545 Registers an attribute. 1546 1547 By registering an attribute, a developer is able to customize 1548 how Elixir will store and accumulate the attribute values. 1549 1550 ## Options 1551 1552 When registering an attribute, two options can be given: 1553 1554 * `:accumulate` - several calls to the same attribute will 1555 accumulate instead of overriding the previous one. New attributes 1556 are always added to the top of the accumulated list. 1557 1558 * `:persist` - the attribute will be persisted in the Erlang 1559 Abstract Format. Useful when interfacing with Erlang libraries. 1560 1561 By default, both options are `false`. 1562 1563 ## Examples 1564 1565 defmodule MyModule do 1566 Module.register_attribute(__MODULE__, :custom_threshold_for_lib, accumulate: true) 1567 1568 @custom_threshold_for_lib 10 1569 @custom_threshold_for_lib 20 1570 @custom_threshold_for_lib #=> [20, 10] 1571 end 1572 1573 """ 1574 @spec register_attribute(module, atom, [{:accumulate, boolean}, {:persist, boolean}]) :: :ok 1575 def register_attribute(module, attribute, options) 1576 when is_atom(module) and is_atom(attribute) and is_list(options) do 1577 assert_not_readonly!(__ENV__.function, module) 1578 {set, bag} = data_tables_for(module) 1579 1580 if Keyword.get(options, :persist) do 1581 :ets.insert(bag, {:persisted_attributes, attribute}) 1582 end 1583 1584 if Keyword.get(options, :accumulate) do 1585 :ets.insert_new(set, {attribute, [], :accumulate}) || 1586 :ets.update_element(set, attribute, {3, :accumulate}) 1587 else 1588 :ets.insert_new(bag, {:warn_attributes, attribute}) 1589 :ets.insert_new(set, {attribute, nil, :unset}) 1590 end 1591 1592 :ok 1593 end 1594 1595 @doc """ 1596 Splits the given module name into binary parts. 1597 1598 `module` has to be an Elixir module, as `split/1` won't work with Erlang-style 1599 modules (for example, `split(:lists)` raises an error). 1600 1601 `split/1` also supports splitting the string representation of Elixir modules 1602 (that is, the result of calling `Atom.to_string/1` with the module name). 1603 1604 ## Examples 1605 1606 iex> Module.split(Very.Long.Module.Name.And.Even.Longer) 1607 ["Very", "Long", "Module", "Name", "And", "Even", "Longer"] 1608 iex> Module.split("Elixir.String.Chars") 1609 ["String", "Chars"] 1610 1611 """ 1612 @spec split(module | String.t()) :: [String.t(), ...] 1613 def split(module) 1614 1615 def split(module) when is_atom(module) do 1616 split(Atom.to_string(module), _original = module) 1617 end 1618 1619 def split(module) when is_binary(module) do 1620 split(module, _original = module) 1621 end 1622 1623 defp split("Elixir." <> name, _original) do 1624 String.split(name, ".") 1625 end 1626 1627 defp split(_module, original) do 1628 raise ArgumentError, "expected an Elixir module, got: #{inspect(original)}" 1629 end 1630 1631 @doc false 1632 @deprecated "Use @doc instead" 1633 def add_doc(module, line, kind, {name, arity}, signature \\ [], doc) do 1634 assert_not_compiled!(__ENV__.function, module) 1635 1636 if kind in [:defp, :defmacrop, :typep] do 1637 if doc, do: {:error, :private_doc}, else: :ok 1638 else 1639 {set, _bag} = data_tables_for(module) 1640 compile_doc(set, nil, line, kind, name, arity, signature, nil, doc, %{}, __ENV__, false) 1641 :ok 1642 end 1643 end 1644 1645 @doc false 1646 # Used internally to compile documentation. 1647 # This function is private and must be used only internally. 1648 def compile_definition_attributes(env, kind, name, args, _guards, body) do 1649 %{module: module} = env 1650 {set, bag} = data_tables_for(module) 1651 {arity, defaults} = args_count(args, 0, 0) 1652 1653 context = Keyword.get(:ets.lookup_element(set, {:def, {name, arity}}, 3), :context) 1654 impl = compile_impl(set, bag, context, name, env, kind, arity, defaults) 1655 doc_meta = compile_doc_meta(set, bag, name, arity, defaults) 1656 1657 {line, doc} = get_doc_info(set, env) 1658 compile_doc(set, context, line, kind, name, arity, args, body, doc, doc_meta, env, impl) 1659 1660 :ok 1661 end 1662 1663 defp compile_doc(_table, _ctx, line, kind, name, arity, _args, _body, doc, _meta, env, _impl) 1664 when kind in [:defp, :defmacrop] do 1665 if doc do 1666 message = 1667 "#{kind} #{name}/#{arity} is private, " <> 1668 "@doc attribute is always discarded for private functions/macros/types" 1669 1670 IO.warn(message, Macro.Env.stacktrace(%{env | line: line})) 1671 end 1672 end 1673 1674 defp compile_doc(table, ctx, line, kind, name, arity, args, body, doc, doc_meta, env, impl) do 1675 key = {doc_key(kind), name, arity} 1676 signature = build_signature(args, env) 1677 1678 case :ets.lookup(table, key) do 1679 [] -> 1680 doc = if is_nil(doc) && impl, do: false, else: doc 1681 :ets.insert(table, {key, ctx, line, signature, doc, doc_meta}) 1682 1683 [{_, current_ctx, current_line, current_sign, current_doc, current_doc_meta}] -> 1684 if is_binary(current_doc) and is_binary(doc) and body != nil and is_nil(current_ctx) do 1685 message = ~s''' 1686 redefining @doc attribute previously set at line #{current_line}. 1687 1688 Please remove the duplicate docs. If instead you want to override a \ 1689 previously defined @doc, attach the @doc attribute to a function head \ 1690 (the function signature not followed by any do-block). For example: 1691 1692 @doc """ 1693 new docs 1694 """ 1695 def #{name}(...) 1696 ''' 1697 1698 IO.warn(message, Macro.Env.stacktrace(%{env | line: line})) 1699 end 1700 1701 signature = merge_signatures(current_sign, signature, 1) 1702 doc = if is_nil(doc), do: current_doc, else: doc 1703 doc = if is_nil(doc) && impl, do: false, else: doc 1704 doc_meta = Map.merge(current_doc_meta, doc_meta) 1705 :ets.insert(table, {key, ctx, current_line, signature, doc, doc_meta}) 1706 end 1707 end 1708 1709 defp doc_key(:def), do: :function 1710 defp doc_key(:defmacro), do: :macro 1711 1712 defp compile_doc_meta(set, bag, name, arity, defaults) do 1713 doc_meta = compile_deprecated(%{}, set, bag, name, arity, defaults) 1714 doc_meta = get_doc_meta(doc_meta, set) 1715 add_defaults_count(doc_meta, defaults) 1716 end 1717 1718 defp get_doc_meta(existing_meta, set) do 1719 case :ets.take(set, {:doc, :meta}) do 1720 [{{:doc, :meta}, metadata, _}] -> Map.merge(existing_meta, metadata) 1721 [] -> existing_meta 1722 end 1723 end 1724 1725 defp compile_deprecated(doc_meta, set, bag, name, arity, defaults) do 1726 case :ets.take(set, :deprecated) do 1727 [{:deprecated, reason, _}] when is_binary(reason) -> 1728 :ets.insert(bag, deprecated_reasons(defaults, name, arity, reason)) 1729 Map.put(doc_meta, :deprecated, reason) 1730 1731 _ -> 1732 doc_meta 1733 end 1734 end 1735 1736 defp add_defaults_count(doc_meta, 0), do: doc_meta 1737 defp add_defaults_count(doc_meta, n), do: Map.put(doc_meta, :defaults, n) 1738 1739 defp deprecated_reasons(0, name, arity, reason) do 1740 [deprecated_reason(name, arity, reason)] 1741 end 1742 1743 defp deprecated_reasons(defaults, name, arity, reason) do 1744 [ 1745 deprecated_reason(name, arity - defaults, reason) 1746 | deprecated_reasons(defaults - 1, name, arity, reason) 1747 ] 1748 end 1749 1750 defp deprecated_reason(name, arity, reason), 1751 do: {:deprecated, {{name, arity}, reason}} 1752 1753 defp compile_impl(set, bag, context, name, env, kind, arity, defaults) do 1754 %{line: line, file: file} = env 1755 1756 case :ets.take(set, :impl) do 1757 [{:impl, value, _}] -> 1758 impl = {{name, arity}, context, defaults, kind, line, file, value} 1759 :ets.insert(bag, {:impls, impl}) 1760 value 1761 1762 [] -> 1763 false 1764 end 1765 end 1766 1767 defp args_count([{:\\, _, _} | tail], total, defaults) do 1768 args_count(tail, total + 1, defaults + 1) 1769 end 1770 1771 defp args_count([_head | tail], total, defaults) do 1772 args_count(tail, total + 1, defaults) 1773 end 1774 1775 defp args_count([], total, defaults), do: {total, defaults} 1776 1777 @doc false 1778 def check_behaviours_and_impls(env, _set, bag, all_definitions) do 1779 behaviours = bag_lookup_element(bag, {:accumulate, :behaviour}, 2) 1780 impls = bag_lookup_element(bag, :impls, 2) 1781 callbacks = check_behaviours(env, behaviours) 1782 1783 pending_callbacks = 1784 if impls != [] do 1785 {non_implemented_callbacks, contexts} = check_impls(env, behaviours, callbacks, impls) 1786 warn_missing_impls(env, non_implemented_callbacks, contexts, all_definitions) 1787 non_implemented_callbacks 1788 else 1789 callbacks 1790 end 1791 1792 check_callbacks(env, pending_callbacks, all_definitions) 1793 :ok 1794 end 1795 1796 defp check_behaviours(env, behaviours) do 1797 Enum.reduce(behaviours, %{}, fn behaviour, acc -> 1798 cond do 1799 not Code.ensure_loaded?(behaviour) -> 1800 message = 1801 "@behaviour #{inspect(behaviour)} does not exist (in module #{inspect(env.module)})" 1802 1803 IO.warn(message, Macro.Env.stacktrace(env)) 1804 acc 1805 1806 not function_exported?(behaviour, :behaviour_info, 1) -> 1807 message = 1808 "module #{inspect(behaviour)} is not a behaviour (in module #{inspect(env.module)})" 1809 1810 IO.warn(message, Macro.Env.stacktrace(env)) 1811 acc 1812 1813 true -> 1814 :elixir_env.trace({:require, [], behaviour, []}, env) 1815 optional_callbacks = behaviour_info(behaviour, :optional_callbacks) 1816 callbacks = behaviour_info(behaviour, :callbacks) 1817 Enum.reduce(callbacks, acc, &add_callback(&1, behaviour, env, optional_callbacks, &2)) 1818 end 1819 end) 1820 end 1821 1822 defp add_callback(original, behaviour, env, optional_callbacks, acc) do 1823 {callback, kind} = normalize_macro_or_function_callback(original) 1824 1825 case acc do 1826 %{^callback => {_kind, conflict, _optional?}} -> 1827 message = 1828 if conflict == behaviour do 1829 "the behavior #{inspect(conflict)} has been declared twice " <> 1830 "(conflict in #{format_definition(kind, callback)} in module #{inspect(env.module)})" 1831 else 1832 "conflicting behaviours found. #{format_definition(kind, callback)} is required by " <> 1833 "#{inspect(conflict)} and #{inspect(behaviour)} (in module #{inspect(env.module)})" 1834 end 1835 1836 IO.warn(message, Macro.Env.stacktrace(env)) 1837 1838 %{} -> 1839 :ok 1840 end 1841 1842 Map.put(acc, callback, {kind, behaviour, original in optional_callbacks}) 1843 end 1844 1845 defp check_callbacks(env, callbacks, all_definitions) do 1846 for {callback, {kind, behaviour, optional?}} <- callbacks do 1847 case :lists.keyfind(callback, 1, all_definitions) do 1848 false when not optional? -> 1849 message = 1850 format_callback(callback, kind, behaviour) <> 1851 " is not implemented (in module #{inspect(env.module)})" 1852 1853 IO.warn(message, Macro.Env.stacktrace(env)) 1854 1855 {_, wrong_kind, _, _} when kind != wrong_kind -> 1856 message = 1857 format_callback(callback, kind, behaviour) <> 1858 " was implemented as \"#{wrong_kind}\" but should have been \"#{kind}\" " <> 1859 "(in module #{inspect(env.module)})" 1860 1861 IO.warn(message, Macro.Env.stacktrace(env)) 1862 1863 _ -> 1864 :ok 1865 end 1866 end 1867 1868 :ok 1869 end 1870 1871 defp format_callback(callback, kind, module) do 1872 protocol_or_behaviour = if protocol?(module), do: "protocol ", else: "behaviour " 1873 1874 format_definition(kind, callback) <> 1875 " required by " <> protocol_or_behaviour <> inspect(module) 1876 end 1877 1878 defp protocol?(module) do 1879 Code.ensure_loaded?(module) and function_exported?(module, :__protocol__, 1) and 1880 module.__protocol__(:module) == module 1881 end 1882 1883 defp check_impls(env, behaviours, callbacks, impls) do 1884 acc = {callbacks, %{}} 1885 1886 Enum.reduce(impls, acc, fn {fa, context, defaults, kind, line, file, value}, acc -> 1887 case impl_behaviours(fa, defaults, kind, value, behaviours, callbacks) do 1888 {:ok, impl_behaviours} -> 1889 Enum.reduce(impl_behaviours, acc, fn {fa, behaviour}, {callbacks, contexts} -> 1890 callbacks = Map.delete(callbacks, fa) 1891 contexts = Map.update(contexts, behaviour, [context], &[context | &1]) 1892 {callbacks, contexts} 1893 end) 1894 1895 {:error, message} -> 1896 formatted = format_impl_warning(fa, kind, message) 1897 IO.warn(formatted, Macro.Env.stacktrace(%{env | line: line, file: file})) 1898 acc 1899 end 1900 end) 1901 end 1902 1903 defp impl_behaviours({function, arity}, defaults, kind, value, behaviours, callbacks) do 1904 impls = for n <- arity..(arity - defaults), do: {function, n} 1905 impl_behaviours(impls, kind, value, behaviours, callbacks) 1906 end 1907 1908 defp impl_behaviours(_, kind, _, _, _) when kind in [:defp, :defmacrop] do 1909 {:error, :private_function} 1910 end 1911 1912 defp impl_behaviours(_, _, value, [], _) do 1913 {:error, {:no_behaviours, value}} 1914 end 1915 1916 defp impl_behaviours(impls, _, false, _, callbacks) do 1917 case callbacks_for_impls(impls, callbacks) do 1918 [] -> {:ok, []} 1919 [impl | _] -> {:error, {:impl_not_defined, impl}} 1920 end 1921 end 1922 1923 defp impl_behaviours(impls, _, true, _, callbacks) do 1924 case callbacks_for_impls(impls, callbacks) do 1925 [] -> {:error, {:impl_defined, callbacks}} 1926 impls -> {:ok, impls} 1927 end 1928 end 1929 1930 defp impl_behaviours(impls, _, behaviour, behaviours, callbacks) do 1931 filtered = behaviour_callbacks_for_impls(impls, behaviour, callbacks) 1932 1933 cond do 1934 filtered != [] -> 1935 {:ok, filtered} 1936 1937 behaviour not in behaviours -> 1938 {:error, {:behaviour_not_declared, behaviour}} 1939 1940 true -> 1941 {:error, {:behaviour_not_defined, behaviour, callbacks}} 1942 end 1943 end 1944 1945 defp behaviour_callbacks_for_impls([], _behaviour, _callbacks) do 1946 [] 1947 end 1948 1949 defp behaviour_callbacks_for_impls([fa | tail], behaviour, callbacks) do 1950 case callbacks[fa] do 1951 {_, ^behaviour, _} -> 1952 [{fa, behaviour} | behaviour_callbacks_for_impls(tail, behaviour, callbacks)] 1953 1954 _ -> 1955 behaviour_callbacks_for_impls(tail, behaviour, callbacks) 1956 end 1957 end 1958 1959 defp callbacks_for_impls([], _) do 1960 [] 1961 end 1962 1963 defp callbacks_for_impls([fa | tail], callbacks) do 1964 case callbacks[fa] do 1965 {_, behaviour, _} -> [{fa, behaviour} | callbacks_for_impls(tail, callbacks)] 1966 nil -> callbacks_for_impls(tail, callbacks) 1967 end 1968 end 1969 1970 defp format_impl_warning(fa, kind, :private_function) do 1971 "#{format_definition(kind, fa)} is private, @impl attribute is always discarded for private functions/macros" 1972 end 1973 1974 defp format_impl_warning(fa, kind, {:no_behaviours, value}) do 1975 "got \"@impl #{inspect(value)}\" for #{format_definition(kind, fa)} but no behaviour was declared" 1976 end 1977 1978 defp format_impl_warning(_, kind, {:impl_not_defined, {fa, behaviour}}) do 1979 "got \"@impl false\" for #{format_definition(kind, fa)} " <> 1980 "but it is a callback specified in #{inspect(behaviour)}" 1981 end 1982 1983 defp format_impl_warning(fa, kind, {:impl_defined, callbacks}) do 1984 "got \"@impl true\" for #{format_definition(kind, fa)} " <> 1985 "but no behaviour specifies such callback#{known_callbacks(callbacks)}" 1986 end 1987 1988 defp format_impl_warning(fa, kind, {:behaviour_not_declared, behaviour}) do 1989 "got \"@impl #{inspect(behaviour)}\" for #{format_definition(kind, fa)} " <> 1990 "but this behaviour was not declared with @behaviour" 1991 end 1992 1993 defp format_impl_warning(fa, kind, {:behaviour_not_defined, behaviour, callbacks}) do 1994 "got \"@impl #{inspect(behaviour)}\" for #{format_definition(kind, fa)} " <> 1995 "but this behaviour does not specify such callback#{known_callbacks(callbacks)}" 1996 end 1997 1998 defp warn_missing_impls(_env, callbacks, _contexts, _defs) when map_size(callbacks) == 0 do 1999 :ok 2000 end 2001 2002 defp warn_missing_impls(env, non_implemented_callbacks, contexts, defs) do 2003 for {pair, kind, meta, _clauses} <- defs, 2004 kind in [:def, :defmacro] do 2005 with {:ok, {_, behaviour, _}} <- Map.fetch(non_implemented_callbacks, pair), 2006 true <- missing_impl_in_context?(meta, behaviour, contexts) do 2007 message = 2008 "module attribute @impl was not set for #{format_definition(kind, pair)} " <> 2009 "callback (specified in #{inspect(behaviour)}). " <> 2010 "This either means you forgot to add the \"@impl true\" annotation before the " <> 2011 "definition or that you are accidentally overriding this callback" 2012 2013 IO.warn(message, Macro.Env.stacktrace(%{env | line: :elixir_utils.get_line(meta)})) 2014 end 2015 end 2016 2017 :ok 2018 end 2019 2020 defp missing_impl_in_context?(meta, behaviour, contexts) do 2021 case contexts do 2022 %{^behaviour => known} -> Keyword.get(meta, :context) in known 2023 %{} -> not Keyword.has_key?(meta, :context) 2024 end 2025 end 2026 2027 defp format_definition(kind, {name, arity}) do 2028 format_definition(kind) <> " #{name}/#{arity}" 2029 end 2030 2031 defp format_definition(:defmacro), do: "macro" 2032 defp format_definition(:defmacrop), do: "macro" 2033 defp format_definition(:def), do: "function" 2034 defp format_definition(:defp), do: "function" 2035 2036 defp known_callbacks(callbacks) when map_size(callbacks) == 0 do 2037 ". There are no known callbacks, please specify the proper @behaviour " <> 2038 "and make sure it defines callbacks" 2039 end 2040 2041 defp known_callbacks(callbacks) do 2042 formatted_callbacks = 2043 for {{name, arity}, {kind, module, _}} <- callbacks do 2044 "\n * " <> Exception.format_mfa(module, name, arity) <> " (#{format_definition(kind)})" 2045 end 2046 2047 ". The known callbacks are:\n#{formatted_callbacks}\n" 2048 end 2049 2050 @doc false 2051 # Used internally by Kernel's @. 2052 # This function is private and must be used only internally. 2053 def __get_attribute__(module, key, line) when is_atom(key) do 2054 assert_not_compiled!( 2055 {:get_attribute, 2}, 2056 module, 2057 "Use the Module.__info__/1 callback or Code.fetch_docs/1 instead" 2058 ) 2059 2060 {set, bag} = data_tables_for(module) 2061 2062 case :ets.lookup(set, key) do 2063 [{_, _, :accumulate}] -> 2064 :lists.reverse(bag_lookup_element(bag, {:accumulate, key}, 2)) 2065 2066 [{_, val, line}] when is_integer(line) -> 2067 :ets.update_element(set, key, {3, :used}) 2068 val 2069 2070 [{_, val, _}] -> 2071 val 2072 2073 [] when is_integer(line) -> 2074 # TODO: Consider raising instead of warning on v2.0 as it usually cascades 2075 error_message = 2076 "undefined module attribute @#{key}, " <> 2077 "please remove access to @#{key} or explicitly set it before access" 2078 2079 IO.warn(error_message, attribute_stack(module, line)) 2080 nil 2081 2082 [] -> 2083 nil 2084 end 2085 end 2086 2087 @doc false 2088 # Used internally by Kernel's @. 2089 # This function is private and must be used only internally. 2090 def __put_attribute__(module, key, value, line) when is_atom(key) do 2091 assert_not_readonly!(__ENV__.function, module) 2092 {set, bag} = data_tables_for(module) 2093 value = preprocess_attribute(key, value) 2094 put_attribute(module, key, value, line, set, bag) 2095 :ok 2096 end 2097 2098 # If any of the doc attributes are called with a keyword list that 2099 # will become documentation metadata. Multiple calls will be merged 2100 # into the same map overriding duplicate keys. 2101 defp put_attribute(module, key, {_, metadata}, line, set, _bag) 2102 when key in [:doc, :typedoc, :moduledoc] and is_list(metadata) do 2103 metadata_map = preprocess_doc_meta(metadata, module, line, %{}) 2104 2105 case :ets.insert_new(set, {{key, :meta}, metadata_map, line}) do 2106 true -> 2107 :ok 2108 2109 false -> 2110 current_metadata = :ets.lookup_element(set, {key, :meta}, 2) 2111 :ets.update_element(set, {key, :meta}, {2, Map.merge(current_metadata, metadata_map)}) 2112 end 2113 end 2114 2115 # Optimize some attributes by avoiding writing to the attributes key 2116 # in the bag table since we handle them internally. 2117 defp put_attribute(module, key, value, line, set, _bag) 2118 when key in [:doc, :typedoc, :moduledoc, :impl, :deprecated] do 2119 try do 2120 :ets.lookup_element(set, key, 3) 2121 catch 2122 :error, :badarg -> :ok 2123 else 2124 unread_line when is_integer(line) and is_integer(unread_line) -> 2125 message = "redefining @#{key} attribute previously set at line #{unread_line}" 2126 IO.warn(message, attribute_stack(module, line)) 2127 2128 _ -> 2129 :ok 2130 end 2131 2132 :ets.insert(set, {key, value, line}) 2133 end 2134 2135 defp put_attribute(_module, :on_load, value, line, set, bag) do 2136 try do 2137 :ets.lookup_element(set, :on_load, 3) 2138 catch 2139 :error, :badarg -> 2140 :ets.insert(set, {:on_load, value, line}) 2141 :ets.insert(bag, {:warn_attributes, :on_load}) 2142 else 2143 _ -> raise ArgumentError, "the @on_load attribute can only be set once per module" 2144 end 2145 end 2146 2147 defp put_attribute(_module, key, value, line, set, bag) do 2148 try do 2149 :ets.lookup_element(set, key, 3) 2150 catch 2151 :error, :badarg -> 2152 :ets.insert(set, {key, value, line}) 2153 :ets.insert(bag, {:warn_attributes, key}) 2154 else 2155 :accumulate -> :ets.insert(bag, {{:accumulate, key}, value}) 2156 _ -> :ets.insert(set, {key, value, line}) 2157 end 2158 end 2159 2160 defp attribute_stack(module, line) do 2161 file = String.to_charlist(Path.relative_to_cwd(:elixir_module.file(module))) 2162 [{module, :__MODULE__, 0, file: file, line: line}] 2163 end 2164 2165 ## Helpers 2166 2167 defp preprocess_attribute(key, value) when key in [:moduledoc, :typedoc, :doc] do 2168 case value do 2169 {line, doc} when is_integer(line) and (is_binary(doc) or doc == false or is_nil(doc)) -> 2170 value 2171 2172 {line, [{key, _} | _]} when is_integer(line) and is_atom(key) -> 2173 value 2174 2175 {line, doc} when is_integer(line) -> 2176 raise ArgumentError, 2177 "@#{key} is a built-in module attribute for documentation. It should be either " <> 2178 "false, nil, a string, or a keyword list, got: #{inspect(doc)}" 2179 2180 _other -> 2181 raise ArgumentError, 2182 "@#{key} is a built-in module attribute for documentation. When set dynamically, " <> 2183 "it should be {line, doc} (where \"doc\" is either false, nil, a string, or a keyword list), " <> 2184 "got: #{inspect(value)}" 2185 end 2186 end 2187 2188 defp preprocess_attribute(:behaviour, value) do 2189 if is_atom(value) do 2190 Code.ensure_compiled(value) 2191 value 2192 else 2193 raise ArgumentError, "@behaviour expects a module, got: #{inspect(value)}" 2194 end 2195 end 2196 2197 defp preprocess_attribute(:on_load, value) do 2198 case value do 2199 _ when is_atom(value) -> 2200 {value, 0} 2201 2202 {atom, 0} = tuple when is_atom(atom) -> 2203 tuple 2204 2205 _ -> 2206 raise ArgumentError, 2207 "@on_load is a built-in module attribute that annotates a function to be invoked " <> 2208 "when the module is loaded. It should be an atom or a {atom, 0} tuple, " <> 2209 "got: #{inspect(value)}" 2210 end 2211 end 2212 2213 defp preprocess_attribute(:impl, value) do 2214 if is_boolean(value) or (is_atom(value) and value != nil) do 2215 value 2216 else 2217 raise ArgumentError, 2218 "@impl is a built-in module attribute that marks the next definition " <> 2219 "as a callback implementation. It should be a module or a boolean, " <> 2220 "got: #{inspect(value)}" 2221 end 2222 end 2223 2224 defp preprocess_attribute(:before_compile, atom) when is_atom(atom), 2225 do: {atom, :__before_compile__} 2226 2227 defp preprocess_attribute(:after_compile, atom) when is_atom(atom), 2228 do: {atom, :__after_compile__} 2229 2230 defp preprocess_attribute(:on_definition, atom) when is_atom(atom), 2231 do: {atom, :__on_definition__} 2232 2233 defp preprocess_attribute(key, _value) 2234 when key in [:type, :typep, :opaque, :spec, :callback, :macrocallback] do 2235 raise ArgumentError, 2236 "attributes type, typep, opaque, spec, callback, and macrocallback " <> 2237 "must be set directly via the @ notation" 2238 end 2239 2240 defp preprocess_attribute(:external_resource, value) when not is_binary(value) do 2241 raise ArgumentError, 2242 "@external_resource is a built-in module attribute used for specifying file " <> 2243 "dependencies. It should be a string path to a file, got: #{inspect(value)}" 2244 end 2245 2246 defp preprocess_attribute(:deprecated, value) when not is_binary(value) do 2247 raise ArgumentError, 2248 "@deprecated is a built-in module attribute that annotates a definition as deprecated. " <> 2249 "It should be a string with the reason for the deprecation, got: #{inspect(value)}" 2250 end 2251 2252 defp preprocess_attribute(:file, value) do 2253 case value do 2254 _ when is_binary(value) -> 2255 value 2256 2257 {file, line} when is_binary(file) and is_integer(line) -> 2258 value 2259 2260 _ -> 2261 raise ArgumentError, 2262 "@file is a built-in module attribute that annotates the file and line the next " <> 2263 "definition comes from. It should be a string or {string, line} tuple as value, " <> 2264 "got: #{inspect(value)}" 2265 end 2266 end 2267 2268 defp preprocess_attribute(:dialyzer, value) do 2269 # From https://github.com/erlang/otp/blob/master/lib/stdlib/src/erl_lint.erl 2270 :lists.foreach( 2271 fn attr -> 2272 if not valid_dialyzer_attribute?(attr) do 2273 raise ArgumentError, "invalid value for @dialyzer attribute: #{inspect(attr)}" 2274 end 2275 end, 2276 List.wrap(value) 2277 ) 2278 2279 value 2280 end 2281 2282 defp preprocess_attribute(_key, value) do 2283 value 2284 end 2285 2286 defp valid_dialyzer_attribute?({key, fun_arities}) when is_atom(key) do 2287 (key == :nowarn_function or valid_dialyzer_attribute?(key)) and 2288 :lists.all( 2289 fn 2290 {fun, arity} when is_atom(fun) and is_integer(arity) -> true 2291 _ -> false 2292 end, 2293 List.wrap(fun_arities) 2294 ) 2295 end 2296 2297 defp valid_dialyzer_attribute?(attr) do 2298 :lists.member( 2299 attr, 2300 [:no_return, :no_unused, :no_improper_lists, :no_fun_app] ++ 2301 [:no_match, :no_opaque, :no_fail_call, :no_contracts] ++ 2302 [:no_behaviours, :no_undefined_callbacks, :unmatched_returns] ++ 2303 [:error_handling, :race_conditions, :no_missing_calls] ++ 2304 [:specdiffs, :overspecs, :underspecs, :unknown, :no_underspecs] 2305 ) 2306 end 2307 2308 defp preprocess_doc_meta([], _module, _line, map), do: map 2309 2310 defp preprocess_doc_meta([{key, _} | tail], module, line, map) 2311 when key in [:opaque, :defaults] do 2312 message = "ignoring reserved documentation metadata key: #{inspect(key)}" 2313 IO.warn(message, attribute_stack(module, line)) 2314 preprocess_doc_meta(tail, module, line, map) 2315 end 2316 2317 defp preprocess_doc_meta([{key, value} | tail], module, line, map) when is_atom(key) do 2318 validate_doc_meta(key, value) 2319 preprocess_doc_meta(tail, module, line, Map.put(map, key, value)) 2320 end 2321 2322 defp validate_doc_meta(:since, value) when not is_binary(value) do 2323 raise ArgumentError, 2324 ":since is a built-in documentation metadata key. It should be a string representing " <> 2325 "the version in which the documented entity was added, got: #{inspect(value)}" 2326 end 2327 2328 defp validate_doc_meta(:deprecated, value) when not is_binary(value) do 2329 raise ArgumentError, 2330 ":deprecated is a built-in documentation metadata key. It should be a string " <> 2331 "representing the replacement for the deprecated entity, got: #{inspect(value)}" 2332 end 2333 2334 defp validate_doc_meta(:delegate_to, value) do 2335 case value do 2336 {m, f, a} when is_atom(m) and is_atom(f) and is_integer(a) and a >= 0 -> 2337 :ok 2338 2339 _ -> 2340 raise ArgumentError, 2341 ":delegate_to is a built-in documentation metadata key. It should be a three-element " <> 2342 "tuple in the form of {module, function, arity}, got: #{inspect(value)}" 2343 end 2344 end 2345 2346 defp validate_doc_meta(_, _), do: :ok 2347 2348 defp get_doc_info(table, env) do 2349 case :ets.take(table, :doc) do 2350 [{:doc, {_, _} = pair, _}] -> 2351 pair 2352 2353 [] -> 2354 {env.line, nil} 2355 end 2356 end 2357 2358 defp data_tables_for(module) do 2359 :elixir_module.data_tables(module) 2360 end 2361 2362 defp bag_lookup_element(table, key, pos) do 2363 :ets.lookup_element(table, key, pos) 2364 catch 2365 :error, :badarg -> [] 2366 end 2367 2368 defp assert_not_compiled!(function_name_arity, module, extra_msg \\ "") do 2369 open?(module) || 2370 raise ArgumentError, 2371 assert_not_compiled_message(function_name_arity, module, extra_msg) 2372 end 2373 2374 defp assert_not_readonly!({function_name, arity}, module) do 2375 case :elixir_module.mode(module) do 2376 :all -> 2377 :ok 2378 2379 :readonly -> 2380 raise ArgumentError, 2381 "could not call Module.#{function_name}/#{arity} because the module " <> 2382 "#{inspect(module)} is in read-only mode (@after_compile)" 2383 2384 :closed -> 2385 raise ArgumentError, 2386 assert_not_compiled_message({function_name, arity}, module, "") 2387 end 2388 end 2389 2390 defp assert_not_compiled_message({function_name, arity}, module, extra_msg) do 2391 mfa = "Module.#{function_name}/#{arity}" 2392 2393 "could not call #{mfa} because the module #{inspect(module)} is already compiled" <> 2394 case extra_msg do 2395 "" -> "" 2396 _ -> ". " <> extra_msg 2397 end 2398 end 2399end 2400