-
Notifications
You must be signed in to change notification settings - Fork 9
/
unused_hrls.erl
75 lines (65 loc) · 2.63 KB
/
unused_hrls.erl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
%% @doc A rule to detect unused header files.
%% <p>To avoid this warning, remove the unused header files.</p>
%%
%% <h3>Note</h3>
%% <blockquote>
%% This rule assumes that hrl files will not be used outside your project.
%% If you are writing a library that requires your clients to use some of
%% your header files, you can add an ignore rule in rebar.config for it.
%% </blockquote>
%% @todo Figure out the absname of IncludePath
%% [https://github.com/AdRoll/rebar3_hank/issues/31]
-module(unused_hrls).
-behaviour(hank_rule).
-export([analyze/2, ignored/2]).
%% @private
-spec analyze(hank_rule:asts(), hank_context:t()) -> [hank_rule:result()].
analyze(FilesAndASTs, Context) ->
{Files, ASTs} = lists:unzip(FilesAndASTs),
IncludePaths = [IncludePath || AST <- ASTs, IncludePath <- include_paths(AST)],
IncludeLibPaths =
[expand_lib_dir(IncludeLibPath, Context)
|| AST <- ASTs, IncludeLibPath <- include_lib_paths(AST)],
[#{file => File,
line => 0,
text => "This file is unused",
pattern => undefined}
|| File <- Files,
filename:extension(File) == ".hrl",
is_unused_local(File, IncludePaths),
is_unused_lib(File, IncludeLibPaths)].
include_paths(AST) ->
[erl_syntax:concrete(IncludedFile)
|| Node <- AST,
% Yeah, include_lib can also be used as include ¯\_(ツ)_/¯ (check epp's code)
hank_utils:node_has_attrs(Node, [include, include_lib]),
IncludedFile <- erl_syntax:attribute_arguments(Node)].
include_lib_paths(AST) ->
hank_utils:attr_args_concrete(AST, include_lib).
is_unused_local(FilePath, IncludePaths) ->
not
lists:any(fun(IncludePath) -> hank_utils:paths_match(IncludePath, FilePath) end,
IncludePaths).
is_unused_lib(File, IncludeLibPaths) ->
% Note that IncludeLibPaths here are absolute paths, not relative ones.
not
lists:member(
filename:absname(File), IncludeLibPaths).
expand_lib_dir(IncludeLibPath, Context) ->
[App | Path] = filename:split(IncludeLibPath),
case hank_context:app_dir(list_to_atom(App), Context) of
undefined ->
IncludeLibPath;
AppDir ->
fname_join([AppDir | Path])
end.
%% @doc Copied verbatim from epp:fname_join(Name).
fname_join(["." | [_ | _] = Rest]) ->
fname_join(Rest);
fname_join(Components) ->
filename:join(Components).
%% @doc It doesn't make sense to provide individual ignore spec support here.
%% The rule's basic unit is already a file.
-spec ignored(hank_rule:ignore_pattern(), term()) -> false.
ignored(undefined, _IgnoreSpec) ->
false.