# `mix xref`
[🔗](https://github.com/elixir-lang/elixir/blob/7ff272706afc522e74121493b7166719985cb099/lib/mix/lib/mix/tasks/xref.ex#L5)

Prints cross reference information between modules.

The `xref` task expects a mode as first argument:

    $ mix xref MODE

All available modes are discussed below, after a brief
introduction to xref.

This task is automatically re-enabled, so you can print
information multiple times in the same Mix invocation.

## A brief introduction to xref

The goal of `xref` is to analyze the dependencies between modules
and files. It is most commonly used to find problematic areas where
touching one file in a project causes a large subset of the project
to recompile. The most common cause of these problems are the so-called
"compile-connected" files. Those are files you depend on at compile-time
(for example, by invoking its macro or using it in the body of a module)
which also have their own dependencies.

The most harmful form of compile-connected dependencies are the ones
that are also in a cycle. Imagine you have files `lib/a.ex`, `lib/b.ex`,
and `lib/c.ex` with the following dependencies:

    lib/a.ex
    └── lib/b.ex (compile)
          └── lib/c.ex
                └── lib/a.ex

Because you have a compile-time dependency, any of the files `lib/a.ex`,
`lib/b.ex`, and `lib/c.ex` depend on will cause `lib/a.ex` to recompile.
In other words, whenever you have a cycle, **a change to any file in the
cycle will cause all compile-time deps to recompile**. Therefore, your
first priority to reduce constant recompilations is to remove them.
You can spot them by running:

    $ mix xref graph --format cycles --label compile-connected

> #### Use the --label option
>
> The job of `mix xref` is to explore relationships between files
> and it is expected that most of your files are either directly
> or indirectly connected. For this reason, it is strongly advised
> to pass the `--label` option to filter the amount of data,
> specifically with `compile-connected` (or `compile`) as values.

Whenever you find a compile-time dependency, such as `lib/a.ex` pointing
to `lib/b.ex`, there are two ways to remove them:

  1. Run `mix xref trace lib/a.ex` to understand where and how `lib/a.ex`
     depends on `lib/b.ex` at compile time and address it

  2. Or run `mix xref trace lib/b.ex` and make sure it does not depend on
     any other module in your project because a compile dependency makes
     those runtime dependencies also compile time by transitivity

We outline all options for `mix xref trace` and the types of dependencies
over the following sections.

If you don't have compile cycles in your project, that's a good beginning,
but you want to avoid any compile-connected dependencies in general, as they
may become cycles in the future. To verify the general health of your project,
you may run:

    $ mix xref graph --format stats --label compile-connected

This command will show general information about the project, but focus on
compile-connected dependencies. In the stats, you will see the following report:

    Top 10 files with most incoming dependencies:
      * lib/livebook_web.ex (97)
      * lib/livebook/config.ex (3)
      * proto/lib/livebook_proto/deployment_group.pb.ex (2)
      * lib/livebook_web/plugs/memory_provider.ex (2)
      * proto/lib/livebook_proto/user_connected.pb.ex (1)

You can see the first file, "lib/livebook_web.ex", is depended on by 97
other files and, because we are using compile-connected, it also means
that "lib/livebook_web.ex" itself has its own dependencies. We can find
which files depend on "lib/livebook_web.ex" at compile time like this:

    $ mix xref graph --sink lib/livebook_web.ex --label compile --only-nodes

And you can find the files lib/livebook_web.ex depends on like this:

    $ mix xref graph --source lib/livebook_web.ex --only-nodes

The trouble here is precisely that, if any of the files in the latter
command changes, all of the files in the first command will be recompiled,
because compile time dependencies are transitive. As we did with cycles,
you can use `mix xref trace` to understand why and how these dependencies
exist.

### Dependency types

Elixir tracks three types of dependencies between modules: compile,
exports, and runtime. If a module has a compile time dependency on
another module, the caller module has to be recompiled whenever the
callee changes (or any dependency of the callee changes).
Let's see an example:

    # lib/a.ex
    defmodule A do
      @hello B.hello()
      def hello, do: @hello
    end

    # lib/b.ex
    defmodule B do
      def hello, do: "hello"
      def world, do: C.world()
    end

    # lib/c.ex
    defmodule C do
      def world, do: "world"
    end

If `C.world/0` changes, `B` is marked as stale. `B` does not need to
be recompiled, because it depends on `C` at runtime, but anything that
depends on `B` at compile-time has to recompile, and that includes `A`.

Compile-time dependencies are typically added when using macros or
when invoking functions in the module body (outside of functions).
This type of transitive compile-time dependencies, such as `A`
depending on `C` at compile-time through `B`, are called compile-connected.

Export dependencies are compile time dependencies on the module API,
namely structs and its public definitions. For example, if you import
a module but only use its functions, it is an export dependency. If
you use a struct, it is an export dependency too. Export dependencies
are only recompiled if the module API changes. Note, however, that compile
time dependencies have higher precedence than exports. Therefore if
you import a module and use its macros, it is a compile time dependency.

Runtime dependencies are added whenever you invoke another module
inside a function. Modules with runtime dependencies do not have
to be compiled when the callee changes, unless there is a transitive
compile or an outdated export time dependency between them.

Over the next sections, we will explain what which `mix xref` command
does in detail.

## mix xref trace FILE

Compiles the given file listing all dependencies within the same app.
It includes the type and line for each one. Example:

    $ mix xref trace lib/my_app/router.ex

The `--label` option may be given to keep only certain traces
(compile, runtime or export):

    $ mix xref trace lib/my_app/router.ex --label compile

If you have an umbrella application, we also recommend using the
`--include-siblings` flag to see the dependencies from sibling
applications. The `trace` command is not currently supported at the
umbrella root.

### Example

Imagine the given file lib/b.ex:

    defmodule B do
      import A
      A.macro()
      macro()
      A.fun()
      fun()
      def calls_macro, do: A.macro()
      def calls_fun, do: A.fun()
      def calls_struct, do: %A{}
    end

`mix xref trace` will print:

    lib/b.ex:2: require A (export)
    lib/b.ex:3: call A.macro/0 (compile)
    lib/b.ex:4: import call A.macro/0 (compile)
    lib/b.ex:5: call A.fun/0 (compile)
    lib/b.ex:6: import call A.fun/0 (compile)
    lib/b.ex:7: call A.macro/0 (compile)
    lib/b.ex:8: call A.fun/0 (runtime)
    lib/b.ex:9: struct A (export)

## mix xref graph

Emits a file dependency graph where an edge from `A` to `B` indicates
that `A` (source) depends on `B` (sink).

    $ mix xref graph --format stats

For any non-small project, the output of `mix xref graph` itself, without
any additional flags, is not useful: once your project grows, it is hard
to gather actionable feedback by looking at the graph as a whole. Instead,
`mix xref graph` is better used as a "database", which can help you answer
queries about your project.

The following options are accepted:

  * `--exclude` - path to exclude. Can be repeated to exclude multiple paths.

  * `--label` - only shows relationships with the given label.
    The labels are "compile-connected", "compile", "export" and "runtime".
    By default, the `--label` option does not change how the graph is computed,
    it simply filters the printed graph to show only relationships with the given
    label. However, you can pass `--only-direct` to trim the graph to only the
    nodes that have the direct relationship given by label.

  * `--group` - provide comma-separated paths to consider as a group. Dependencies
    from and into multiple files of the group are considered a single dependency.
    Dependencies between the group elements are ignored. This is useful when you
    are computing compile and compile-connected dependencies and you want a
    series of files to be treated as one. The group is printed using the first path,
    with a `+` suffix. Can be repeated to create multiple groups.

  * `--only-direct` - keeps only files with the direct relationship
    given by `--label`

  * `--only-nodes` - only shows the node names (no edges).
    Generally useful with the `--sink` flag

  * `--source` - displays all files that the given source file
    references (directly or indirectly). Can be repeated to display
    references from multiple sources.

  * `--sink` - displays all files that reference the given file
    (directly or indirectly). Can be repeated.

  * `--min-cycle-size` - controls the minimum cycle size on formats
    like `stats` and `cycles`

  * `--min-cycle-label` - controls the minimum number of dependencies
    with the given `--label` on a cycle

  * `--format` - can be set to one of:

    * `pretty` - prints the graph to the terminal using Unicode characters.
      Each prints each file followed by the files it depends on. This is the
      default except on Windows;

    * `plain` - the same as pretty except ASCII characters are used instead of
      Unicode characters. This is the default on Windows;

    * `stats` - prints general statistics about the graph;

    * `cycles` - prints all strongly connected cycles in the graph;

    * `dot` - produces a DOT graph description, by default written to `xref_graph.dot`
      in the current directory.  See the documentation for the `--output` option to
      learn how to control where the file is written and other related details.

    * `json` *(since v1.19.0)* - produces a JSON file, by default written to
      `xref_graph.json` in the current directory.  See the documentation for the
      `--output` option to learn how to control where the file is written and other
      related details.

      The JSON format is always a two level map of maps. The top level keys
      specify source files, with their values containing maps whose keys specify
      sink files and whose values specify the type of relationship, which will
      be one of `compile`, `export` or `runtime`. Files which have no dependencies
      will be present in the top level map, and will have empty maps for values.

  * `--output` *(since v1.15.0)* - can be used to override the location of
    the files created by the `dot` and `json` formats. It can be set to

    * `-` - prints the output to standard output;

    * a path - writes the output graph to the given path

    If the output file already exists then it will be renamed in place
    to have a `.bak` suffix, possibly overwriting any existing `.bak` file.
    If this rename fails a fatal exception will be thrown.

The `--source` and `--sink` options are particularly useful when trying to understand
how the modules in a particular file interact with the whole system. You can combine
those options with `--label` and `--only-nodes` to get all files that exhibit a certain
property, for example:

    # To show all compile-connected relationships
    $ mix xref graph --label compile-connected

    # To get the tree that depend on lib/foo.ex at compile time
    $ mix xref graph --label compile --sink lib/foo.ex

    # To get all files that depend on lib/foo.ex at compile time
    $ mix xref graph --label compile --sink lib/foo.ex --only-nodes

    # To get all paths between two files
    $ mix xref graph --source lib/foo.ex --sink lib/bar.ex

    # To show general statistics about the graph
    $ mix xref graph --format stats

    # To show all cycles with at least one compile-time dependency
    $ mix xref graph --format cycles --label compile-connected

### Understanding the printed graph

When `mix xref graph` runs, it will print a tree of the following
format. Imagine the following code:

    # lib/a.ex
    defmodule A do
      IO.puts B.hello()
    end

    # lib/b.ex
    defmodule B do
      def hello, do: C.world()
    end

    # lib/c.ex
    defmodule C do
      def world, do: "hello world"
    end

It will print:

    $ mix xref graph
    lib/a.ex
    └── lib/b.ex (compile)
    lib/b.ex
    └── lib/c.ex
    lib/c.ex

This tree means that `lib/a.ex` depends on `lib/b.ex` at compile
time. And `lib/b.ex` depends on `lib/c.ex` at runtime. This is often
problematic because if `lib/c.ex` changes, `lib/a.ex` also has to
recompile due to this indirect compile time dependency. When you pass
`--label compile`, the graph shows only the compile-time dependencies:

    $ mix xref graph --label compile
    lib/a.ex
    └── lib/b.ex (compile)

The `--label compile` flag removes all non-compile dependencies. However,
this can be misleading because having direct compile time dependencies is
not necessarily an issue. The biggest concern are the transitive compile
time dependencies. You can get all compile time dependencies that cause
transitive compile time dependencies by using `--label compile-connected`:

    $ mix xref graph --label compile-connected
    lib/a.ex
    └── lib/b.ex (compile)

The above says `lib/a.ex` depends on `lib/b.ex` and that causes transitive
compile time dependencies - as we know, `lib/a.ex` also depends on `lib/c.ex`.
We can retrieve those transitive dependencies by passing `lib/b.ex` as
`--source` to `mix xref graph`:

    $ mix xref graph --source lib/b.ex
    lib/b.ex
    └── lib/c.ex

Similarly, you can use the `--label compile` and the `--sink` flag to find
all compile time dependencies that will recompile once the sink changes:

    $ mix xref graph --label compile --sink lib/c.ex
    lib/a.ex
    └── lib/b.ex (compile)

If you have an umbrella application, we also recommend using the
`--include-siblings` flag to see the dependencies from sibling
applications. When invoked at the umbrella root, the `graph`
command will list all files from all umbrella children, without
any namespacing.

### Understanding the printed cycle

If you run `mix xref graph --format cycles`, Elixir will print cycles
of shape:

    Cycle of length 3:

        lib/c.ex
        lib/b.ex
        lib/a.ex (compile)

More precisely, `xref` is printing the [strongly connected components](https://en.wikipedia.org/wiki/Strongly_connected_component)
in the dependency graph, which is (roughly speaking) the largest set of
files which are part of a dependency cycle involving these files.

For this reason, files may have multiple relationships between them, and
therefore the cycles are not printed in order. The label reflects the
highest type of relationship between the given file and any other file in
the cycle. In the example above, it means `lib/a.ex` depends on something
else in the cycle at compile-time.  Those are exactly the type of dependencies
we want to avoid, and you can ask `mix xref` to only print graphs with
with compile dependencies in them by passing the `--label` flag:

    $ mix xref graph --format cycles --label compile-connected

## Shared options

Those options are shared across all modes:

  * `--fail-above` - generates a failure if the relevant metric is above the
    given threshold. Applies to all modes except `mix xref graph --format stats`.

  * `--include-siblings` - includes dependencies that have `:in_umbrella` set
    to true in the current project in the reports. This can be used to find
    callers or to analyze graphs between projects (it applies only to `trace`
    subcommand)

  * `--no-compile` - does not compile even if files require compilation

  * `--no-deps-check` - does not check dependencies

  * `--no-archives-check` - does not check archives

  * `--no-elixir-version-check` - does not check the Elixir version from mix.exs

# `calls`

> This function is deprecated. Use compilation tracers described in the Code module.

```elixir
@spec calls(keyword()) :: [
  %{callee: {module(), atom(), arity()}, line: integer(), file: String.t()}
]
```

Returns a list of information of all the runtime function calls in the project.

Each item in the list is a map with the following keys:

  * `:callee` - a tuple containing the module, function, and arity of the call
  * `:line` - an integer representing the line where the function is called
  * `:file` - a binary representing the file where the function is called
  * `:caller_module` - the module where the function is called

This function returns an empty list when used at the root of an umbrella
project because there is no compile manifest to extract the function call
information from. To get the function calls of each child in an umbrella,
execute the function at the root of each individual application.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
