Skip to content

Commit 7b41ff3

Browse files
author
José Valim
committed
Merge pull request #1026 from elixir-lang/jv-no-warn-unused-imports
Warn on unused imports
2 parents 132ea15 + 7bae002 commit 7b41ff3

File tree

6 files changed

+34
-10
lines changed

6 files changed

+34
-10
lines changed

lib/elixir/src/elixir_import.erl

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
-module(elixir_import).
55
-export([import/5, recorded_locals/1, format_error/1,
66
ensure_no_import_conflict/4, ensure_no_local_conflict/4,
7+
ensure_all_imports_used/3,
78
build_table/1, delete_table/1, record/3]).
89
-include("elixir.hrl").
910

@@ -25,6 +26,21 @@ record(Tuple, Receiver, Module) ->
2526
error:badarg -> false
2627
end.
2728

29+
record_warn(_Meta, _Ref, _Opts, #elixir_scope{module=nil}) -> false;
30+
31+
record_warn(Meta, Ref, Opts, S) ->
32+
Table = table(S#elixir_scope.module),
33+
ets:delete(Table, Ref),
34+
35+
Warn =
36+
case keyfind(warn, Opts) of
37+
{ warn, false } -> false;
38+
{ warn, true } -> true;
39+
false -> S#elixir_scope.check_clauses
40+
end,
41+
42+
Warn andalso ets:insert(Table, { Ref, ?line(Meta) }).
43+
2844
recorded_locals(Module) ->
2945
Table = table(Module),
3046
Match = { '$1', Module },
@@ -61,6 +77,7 @@ import(Meta, Ref, Opts, Selector, S) ->
6177
SF#elixir_scope{macros=Macros, macro_macros=TempM}
6278
end,
6379

80+
record_warn(Meta, Ref, Opts, S),
6481
SM.
6582

6683
%% IMPORT FUNCTION RELATED HELPERS
@@ -188,6 +205,16 @@ ensure_no_import_conflict(Meta, File, Module, AllDefined) ->
188205
ok
189206
end.
190207

208+
ensure_all_imports_used(_Line, File, Module) ->
209+
Table = table(Module),
210+
[begin
211+
elixir_errors:handle_file_warning(File, { L, ?MODULE, { unused_import, M } })
212+
end || [M, L] <- ets:select(Table, module_line_spec()),
213+
ets:match(Table, { '$1', M }) == []].
214+
215+
module_line_spec() ->
216+
[{ { '$1', '$2' }, [{ is_integer, '$2' }], ['$$'] }].
217+
191218
%% Ensure the given functions don't clash with any
192219
%% of Elixir non overridable macros.
193220

@@ -225,6 +252,9 @@ format_error({internal_conflict,{Receiver, Name, Arity}}) ->
225252
io_lib:format("cannot import ~ts.~ts/~B because it conflicts with Elixir special forms",
226253
[elixir_errors:inspect(Receiver), Name, Arity]);
227254

255+
format_error({ unused_import, Module }) ->
256+
io_lib:format("unused import ~ts", [elixir_errors:inspect(Module)]);
257+
228258
format_error({ no_macros, Module }) ->
229259
io_lib:format("could not load macros from module ~ts", [elixir_errors:inspect(Module)]).
230260

lib/elixir/src/elixir_macros.erl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ translate({defmodule, Meta, [Ref, KV]}, S) ->
213213
{ TRef, S }
214214
end,
215215

216-
MS = FS#elixir_scope{check_clauses=true,local=nil},
216+
MS = FS#elixir_scope{local=nil},
217217
{ elixir_module:translate(Meta, FRef, Block, MS), FS };
218218

219219
translate({Kind, Meta, [Call]}, S) when ?FUNS(Kind) ->

lib/elixir/src/elixir_module.erl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ compile(Line, Module, Block, Vars, #elixir_scope{} = S) when is_atom(Module) ->
6666
Forms1 = specs_form(Line, Module, Private, Defmacro, Forms0, C),
6767
Forms2 = attributes_form(Line, File, Module, Forms1),
6868

69+
elixir_import:ensure_all_imports_used(Line, File, Module),
6970
elixir_import:ensure_no_local_conflict(Line, File, Module, All),
7071
elixir_import:ensure_no_import_conflict(Line, File, Module, All),
7172

lib/elixir/src/elixir_translator.erl

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,10 @@ translate(Forms, S) ->
3535
%% Those macros are "low-level". They are the basic mechanism
3636
%% that makes the language work and cannot be partially applied
3737
%% nor overwritten.
38-
%%
39-
%% =, ^, import, require and alias could be made non-special
40-
%% forms without causing any side effects.
4138

4239
%% Assignment operator
4340

44-
translate_each({'=', Meta, [Left, Right]}, S) ->
41+
translate_each({ '=', Meta, [Left, Right] }, S) ->
4542
assert_no_guard_scope(Meta, '=', S),
4643
{ TRight, SR } = translate_each(Right, S),
4744
{ TLeft, SL } = elixir_clauses:assigns(fun translate_each/2, Left, SR),
@@ -190,7 +187,7 @@ translate_each({ import, Meta, [Left, Right, Opts] }, S) ->
190187
_ -> syntax_error(Meta, S#elixir_scope.file, "invalid name for import, expected an atom or alias")
191188
end,
192189

193-
validate_opts(Meta, import, [as, only, except], Opts, S),
190+
validate_opts(Meta, import, [as, only, except, warn], Opts, S),
194191

195192
As = case lists:keyfind(as, 1, Opts) of
196193
false -> false;

lib/mix/lib/mix/tasks/app.start.ex

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
defmodule Mix.Tasks.App.Start do
22
use Mix.Task
33

4-
import Mix.Deps, only: [all: 0, ok?: 1]
5-
64
@hidden true
75
@shortdoc "Start registered apps"
86
@recursive true

lib/mix/lib/mix/tasks/deps.unlock.ex

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ defmodule Mix.Tasks.Deps.Unlock do
99
are given, unlock all.
1010
"""
1111

12-
import Mix.Deps, only: [all: 0, by_name!: 1]
13-
1412
def run([]) do
1513
Mix.Deps.Lock.write([])
1614
end

0 commit comments

Comments
 (0)