Giter VIP home page Giter VIP logo

xref_runner's Introduction

Xref Runner

Erlang Xref Runner (inspired by rebar's rebar_xref)

Contact Us

If you find any bugs or have a problem while using this library, please open an issue in this repo (or a pull request :)).

And you can check all of our open-source projects at inaka.github.io.

Why Xref Runner?

So, Erlang/OTP comes with an excellent tool to check your code and detect bugs: Xref. The problem lies in its not-extremely-simple interface. Using xref out of the box requires you to start a process, set up parameters, add directories, etc. before you can actually just run the checks you want to run. To mitigate that, rebar comes with a handy command line tool (rebar xref) that prints xref generated warnings on your console. But, sometimes, you don't want to use rebar or you want to get the warnings as erlang terms and not just printed out in the console. That's when xref_runner comes along.

Script

xref_runner can be turned into a script by executing rebar3 escriptize. This will generate a self-contained executable script in _build/default/bin/xrefr, from which you can get help by typing xrefr -h.

Use xrefr command to run from the terminal (i.e. xrefr). There's no need to specify a configuration file path if you have an xref.config file in the same location where you are executing the script, otherwise a configuration file can be specified through the use of the --config (or just -c) option.

xrefr --config xref.config

How to Use it?

Just make sure it's in your code path and call xref_runner:check/2 with the proper parameters.

The first parameter is one of the available checks provided by xref:

-type check() :: undefined_function_calls
               | undefined_functions
               | locals_not_used
               | exports_not_used
               | deprecated_function_calls
               | deprecated_functions.

The second paramter is a configuration map. All of its fields are optional. The allowed fields are:

  • extra_paths: Directories to be added to the xref code path. default value: []
  • xref_defaults: Default values to configure xref (check xref:set_default). default value: []
  • dirs: Directories to be scanned with xref. default value: ["ebin"]

Also you can use xref_runner:check/0 without parameters to run the whole check list. In this case, the configuration will be taken from xref.config from the root dir, that should look like this:

[
   {xref, [
            {config, #{dirs => ["test"]}},
            {checks, [ undefined_function_calls
                     , undefined_functions
                     , locals_not_used
                     , exports_not_used
                     , deprecated_function_calls
                     , deprecated_functions
                     ]}
          ]
   }
].

Using that function will give you a list of warnings as its result. Warnings are also maps with the following fields:

  • filename: The name of the file for which the warning is reported
  • line: The line number where the warning is reported. 0 means it's a module-level warning (like an undefined function). Note: In case of warnings with source and target, line numbers refer to the line in which the source function is defined, not the line where the target function is used.
  • source: Module, function and argument number where the warning is found
  • target (optional): For undefined_function_calls and deprecated_function_calls, function call that generates the warning.

Examples

Using the modules in the examples folder, these are some of the results generated by the tests:

> xref_runner:check(undefined_function_calls, #{dirs => ["test"]}).
[#{check => undefined_function_calls,
   filename => "test/examples/undefined_function_calls.erl",
   line => 5,
   source => {undefined_function_calls,bad,0},
   target => {undefined_function_calls,undefined_here,0}},
 #{check => undefined_function_calls,
   filename => "test/examples/undefined_function_calls.erl",
   line => 9,
   source => {undefined_function_calls,bad,1},
   target => {other_module,undefined_somewhere_else,1}},
 #{check => undefined_function_calls,
   filename => "test/examples/undefined_function_calls.erl",
   line => 9,
   source => {undefined_function_calls,bad,1},
   target => {undefined_functions,undefined_there,0}},
 …
]
> xref_runner:check(undefined_functions, #{dirs => ["test"],
                                           xref_defaults => []}).
[#{check => undefined_functions,
   filename => [],
   line => 0,
   source => {other_module,undefined_somewhere_else,0}},
 #{check => undefined_functions,
   filename => [],
   line => 0,
   source => {other_module,undefined_somewhere_else,1}},
 #{check => undefined_functions,
   filename => "test/examples/undefined_function_calls.erl",
   line => 0,
   source => {undefined_function_calls,undefined_here,0}},
 …
]
> xref_runner:check(locals_not_used, #{dirs => ["test"]}).
[#{check => locals_not_used,
   filename => "test/examples/locals_not_used.erl",
   line => 9,
   source => {locals_not_used,local_not,1}}]
> xref_runner:check(exports_not_used, #{dirs => ["test"]}).
[#{check => exports_not_used,
   filename => "test/examples/deprecated_function_calls.erl",
   line => 7,
   source => {deprecated_function_calls,bad,0}},
 #{check => exports_not_used,
   filename => "test/examples/deprecated_function_calls.erl",
   line => 10,
   source => {deprecated_function_calls,bad,1}},
 #{check => exports_not_used,
   filename => "test/examples/deprecated_function_calls.erl",
   line => 14,
   source => {deprecated_function_calls,good,0}},
…
]
> xref_runner:check(deprecated_function_calls, #{dirs => ["test"]}).
[#{check => deprecated_function_calls,
   filename => "test/examples/deprecated_function_calls.erl",
   line => 7,
   source => {deprecated_function_calls,bad,0},
   target => {deprecated_functions,deprecated,0}},
 #{check => deprecated_function_calls,
   filename => "test/examples/deprecated_function_calls.erl",
   line => 10,
   source => {deprecated_function_calls,bad,1},
   target => {deprecated_function_calls,internal,0}},
 #{check => deprecated_function_calls,
   filename => "test/examples/deprecated_function_calls.erl",
   line => 10,
   source => {deprecated_function_calls,bad,1},
   target => {deprecated_functions,deprecated,1}},
 …
]
> xref_runner:check(deprecated_functions, #{dirs => ["test"]}).
[#{check => deprecated_functions,
   filename => "test/examples/deprecated_function_calls.erl",
   line => 17,
   source => {deprecated_function_calls,internal,0}},
 #{check => deprecated_functions,
   filename => "test/examples/deprecated_functions.erl",
   line => 8,
   source => {deprecated_functions,deprecated,0}},
 #{check => deprecated_functions,
   filename => "test/examples/deprecated_functions.erl",
   line => 10,
   source => {deprecated_functions,deprecated,1}},
 #{check => deprecated_functions,
   filename => "test/examples/ignore_xref.erl",
   line => 19,
   source => {ignore_xref,internal,0}}]
> xref_runner:check(deprecated_function_calls, #{dirs => ["test"]}).
[#{check => deprecated_function_calls,
   filename => "test/examples/deprecated_function_calls.erl",
   line => 7,
   source => {deprecated_function_calls,bad,0},
   target => {deprecated_functions,deprecated,0}},
 #{check => deprecated_function_calls,
   filename => "test/examples/deprecated_function_calls.erl",
   line => 10,
   source => {deprecated_function_calls,bad,1},
   target => {deprecated_function_calls,internal,0}},
 #{check => deprecated_function_calls,
   filename => "test/examples/deprecated_function_calls.erl",
   line => 10,
   source => {deprecated_function_calls,bad,1},
   target => {deprecated_functions,deprecated,1}},
 …
]
> xref_runner:check().
[#{check => undefined_function_calls,
   filename => "test/examples/undefined_function_calls.erl",
   line => 5,
   source => {undefined_function_calls,bad,0},
   target => {undefined_function_calls,undefined_here,0}},
 #{check => undefined_function_calls,
   filename => "test/examples/undefined_function_calls.erl",
   line => 9,
   source => {undefined_function_calls,bad,1},
   target => {other_module,undefined_somewhere_else,1}},
 #{check => undefined_function_calls,
   filename => "test/examples/undefined_function_calls.erl",
   line => 9,
   source => {undefined_function_calls,bad,1},
   target => {undefined_functions,undefined_there,0}},
…
]

xref_runner's People

Contributors

amilkr avatar cabol avatar dumbbell avatar elbrujohalcon avatar euen avatar harenson avatar igaray avatar jfacorro avatar l33tlumberjack avatar nomorecoffee avatar richmorin avatar spike886 avatar srenatus avatar x4lldux avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

xref_runner's Issues

Error when xref'd code depends on a behavior in deps

For example when running xrefr without a config file in elvis the result is the following:

elvis: 1 unresolved call
elvis_code: 1 unresolved call
elvis_utils: 2 unresolved calls
elvis: 1 unresolved call
elvis_code: 1 unresolved call
elvis_utils: 2 unresolved calls
elvis: 1 unresolved call
elvis_code: 1 unresolved call
elvis_utils: 2 unresolved calls
elvis: 1 unresolved call
elvis_code: 1 unresolved call
elvis_utils: 2 unresolved calls
escript: exception error: undefined function egithub_webhook:behaviour_info/1
  in function  xref_runner:'-get_behaviour_callbacks/3-lc$^2/1-2-'/2 (src/xref_runner.erl, line 155)
  in call from xref_runner:get_ignorelist/2 (src/xref_runner.erl, line 147)
  in call from lists:flatmap/2 (lists.erl, line 1248)
  in call from lists:flatmap/2 (lists.erl, line 1248)
  in call from xref_runner:filter_xref_results/2 (src/xref_runner.erl, line 121)
  in call from xref_runner:check/2 (src/xref_runner.erl, line 86)
  in call from xref_runner:'-check/1-lc$^0/1-0-'/2 (src/xref_runner.erl, line 63)

We should check what does rebar xref does in these cases.

escriptize

Let the module functions be accessible through a command line escript.

Tests

Get make tests to work and ensure 100% code coverage.

Make that xref_runner supports rebar3 compilation

When you don't have xref.config xref takes the compiled file form ebin/ directory as default

-spec check(check(), config()) -> [warning()].
check(Check, Config) ->
  XrefDefaults = maps:get(xref_defaults, Config, []),
  ConfigDirs = maps:get(dirs, Config, [ebin()]),
  ...

ebin() ->
  case filelib:is_dir("ebin") of
    true -> filename:absname("ebin");
    false -> filename:absname(".")
  end.

It's needed to support the rebar3 compilation without ebin/ directory

Broken for modules created with Elixir

Running check on any Elixir module throws:

** (MatchError) no match of right hand side value: [{:attribute, 0, :compile, :no_auto_import}, {:attribute,....

By the looks of it, every Elixir module AST starts with {:attribute, 0, :compile, :no_auto_import} and also the first file attribute is not necessarily at 1st line.

Remove white-box testing

Since #30 we have a test suite (wildcard_SUITE) that calls a function that should not be exported at all: xref_runner:find_dirs/1.

That function was intended to be private and it's only exported to be used by the test. That's not right. If the function is not used by production code, it shouldn't be exported.

We need to redefine the tests in order to actually execute/cover all the paths relative to the function without actually calling the function itself.

And, now that we are on it, we should as well rename that SUITE (if we're not removing it) with the proper prefix: xref_wildcard_SUITE

Hex Package

Make sure the repo is rebar3-compatible and its deps are also hex.pm packages, then publish it on hex.pm using inaka's hex.pm account.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.