Skip to content

Incorrectly identified unused_record_fields in KAZOO #136

@jamesaimonetti

Description

@jamesaimonetti

Bug Description

Record fields that appear "obviously in use" in the code are detected as unused.

To Reproduce

Well, this is the tricky bit as we don't use rebar3 in KAZOO. Hooked into hank:analze/5 directly.

Here's the basic escript:

#!/usr/bin/env escript
%%! +A0 -sname kazoo_hank
%% -*- coding: utf-8 -*-

-mode('compile').

-export([main/1]).

%% API

main([]) ->
    AppFiles = lists:foldl(fun add_app_path/2, [], kz_ast_util:project_apps()),
    main(AppFiles);
main(Files) ->
    #{results := Results
     ,stats := Stats
     } = hank:analyze(Files
                     ,hank_ignores()
                     ,hank_rules()
                     ,parsing_style()
                     ,hank_context()
                     ),
    print_stats(Stats),
    io:format("results(~p):~n", [length(Results)]),
    {_LastRule, Counts} = lists:foldl(fun print_result/2, {'undefined', #{}}, Results),
    io:format("rule violations: ~p~n", [Counts]).

add_app_path(App, Acc) ->
    filelib:wildcard(
      filename:join([code:lib_dir(App), "**/*.[e|h]rl"])
     ) ++ Acc.

print_stats(#{ignored := Ignored
             ,parsing := ParsingMs
             ,analyzing := AnalysisMs
             ,total := TotalMs
             }) ->
    io:format("analysis took ~pms parsing, ~pms analyzing, ~pms total, ignore ~p files~n"
             ,[ParsingMs, AnalysisMs, TotalMs, Ignored]
             ).

print_result(#{file := File
              ,line := Line
              ,pattern := Pattern
              ,rule := Rule
              ,text := Text
              }
            ,{Rule, RuleCounts}
            ) ->
    io:format("~s:~p: ~s~n~n"
             ,[File, Line, rule_text(Rule, Text, Pattern)]
             ),
    {Rule, maps:update_with(Rule, fun(V) -> V+1 end, 1, RuleCounts)};
print_result(#{rule := NewRule}=Result
            ,{_OldRule, RuleCounts}
            ) ->
    io:format("rule violations for ~s:~n", [NewRule]),
    print_result(Result, {NewRule, RuleCounts}).

rule_text(_Rule, Text, _Pattern) ->
    Text.

-spec hank_ignores() -> [hank_rule:ignore_spec()].
hank_ignores() -> [].

hank_rules() ->
    hank_rule:default_rules().

parsing_style() ->
    'sequential'. % or parallel

hank_context() ->
    Apps = [{App, code:lib_dir(App)}
            || App <- kz_ast_util:project_apps()
           ],
    hank_context:new(maps:from_list(Apps), []).

Here's an example of the output:

src/omnip_subscriptions.erl:52: Field ready in record state is unused

src/omnip_subscriptions.erl:54: Field other_nodes_count in record state is unused

The record in question: https://github.com/2600hz/kazoo/blob/master/applications/omnipresence/src/omnip_subscriptions.erl#L51
The record fields being used: https://github.com/2600hz/kazoo/blob/master/applications/omnipresence/src/omnip_subscriptions.erl#L164

This is all very much first pass, quick hack to correct low-hanging fruit; fully expect there are better ways to call into hank or provide it more context.

Expected Behavior

Not detect record fields as unused

Additional Context

  • OS: Debian
  • Erlang version 23.1
  • rebar3 NA

I will say this: just on unused_record_fields, the first pass of hank detected 133 instances, of which it appears 7 are false positives. The above represents 2 of the 7. So I think that is phenomenal and really fun to dig through KAZOO's cobwebs and oxtail code (love that btw!).

@elbrujohalcon great preso on hank and thanks for poking at KAZOO. Hope we can get hank integrated into CI after this initial pass.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions