@@ -39,12 +39,14 @@ debug_info(_, _, _, _) ->
39
39
% % Builds Erlang AST annotation.
40
40
41
41
get_ann (Opts ) when is_list (Opts ) ->
42
- get_ann (Opts , false , 0 ).
42
+ get_ann (Opts , false , 0 , undefined ).
43
43
44
- get_ann ([{generated , true } | T ], _ , Line ) -> get_ann (T , true , Line );
45
- get_ann ([{line , Line } | T ], Gen , _ ) when is_integer (Line ) -> get_ann (T , Gen , Line );
46
- get_ann ([_ | T ], Gen , Line ) -> get_ann (T , Gen , Line );
47
- get_ann ([], Gen , Line ) -> erl_anno :set_generated (Gen , erl_anno :new (Line )).
44
+ get_ann ([{generated , true } | T ], _ , Line , Column ) -> get_ann (T , true , Line , Column );
45
+ get_ann ([{line , Line } | T ], Gen , _ , Column ) when is_integer (Line ) -> get_ann (T , Gen , Line , Column );
46
+ get_ann ([{column , Column } | T ], Gen , Line , _ ) when is_integer (Column ) -> get_ann (T , Gen , Line , Column );
47
+ get_ann ([_ | T ], Gen , Line , Column ) -> get_ann (T , Gen , Line , Column );
48
+ get_ann ([], Gen , Line , undefined ) -> erl_anno :set_generated (Gen , erl_anno :new (Line ));
49
+ get_ann ([], Gen , Line , Column ) -> erl_anno :set_generated (Gen , erl_anno :new ({Line , Column })).
48
50
49
51
% % Converts an Elixir definition to an anonymous function.
50
52
@@ -122,7 +124,7 @@ consolidate(Map, TypeSpecs, Chunks) ->
122
124
123
125
% % Dynamic compilation hook, used in regular compiler
124
126
125
- compile (#{module := Module , line := Line } = Map ) ->
127
+ compile (#{module := Module , anno := Anno } = Map ) ->
126
128
{Set , Bag } = elixir_module :data_tables (Module ),
127
129
128
130
TranslatedTypespecs =
@@ -135,13 +137,14 @@ compile(#{module := Module, line := Line} = Map) ->
135
137
{Prefix , Forms , Def , Defmacro , Macros } = dynamic_form (Map ),
136
138
{Types , Callbacks , TypeSpecs } = typespecs_form (Map , TranslatedTypespecs , Macros ),
137
139
138
- DocsChunk = docs_chunk (Set , Module , Line , Def , Defmacro , Types , Callbacks ),
140
+ DocsChunk = docs_chunk (Map , Set , Module , Anno , Def , Defmacro , Types , Callbacks ),
139
141
CheckerChunk = checker_chunk (Def , Defmacro , Map ),
140
142
load_form (Map , Prefix , Forms , TypeSpecs , DocsChunk ++ CheckerChunk ).
141
143
142
- dynamic_form (#{module := Module , line := Line , relative_file := RelativeFile ,
144
+ dynamic_form (#{module := Module , anno := Anno , relative_file := RelativeFile ,
143
145
attributes := Attributes , definitions := Definitions , unreachable := Unreachable ,
144
146
deprecated := Deprecated , compile_opts := Opts } = Map ) ->
147
+ Line = erl_anno :line (Anno ),
145
148
{Def , Defmacro , Macros , Exports , Functions } =
146
149
split_definition (Definitions , Unreachable , Line , [], [], [], [], {[], []}),
147
150
@@ -168,13 +171,14 @@ split_definition([{Tuple, Kind, Meta, Clauses} | T], Unreachable, Line,
168
171
true ->
169
172
split_definition (T , Unreachable , Line , Def , Defmacro , Macros , Exports , Functions )
170
173
end ;
174
+
171
175
split_definition ([], _Unreachable , _Line , Def , Defmacro , Macros , Exports , {Head , Tail }) ->
172
- {lists :usort (Def ), lists :usort (Defmacro ), Macros , Exports , Head ++ Tail }.
176
+ {lists :sort (Def ), lists :sort (Defmacro ), Macros , Exports , Head ++ Tail }.
173
177
174
178
split_definition (Tuple , def , Meta , Clauses , T , Unreachable , Line ,
175
179
Def , Defmacro , Macros , Exports , Functions ) ->
176
180
{_ , _ , N , A , _ } = Entry = translate_definition (def , Line , Meta , Tuple , Clauses ),
177
- split_definition (T , Unreachable , Line , [Tuple | Def ], Defmacro , Macros , [{N , A } | Exports ],
181
+ split_definition (T , Unreachable , Line , [{ Tuple , Meta } | Def ], Defmacro , Macros , [{N , A } | Exports ],
178
182
add_definition (Meta , Entry , Functions ));
179
183
180
184
split_definition (Tuple , defp , Meta , Clauses , T , Unreachable , Line ,
@@ -186,7 +190,7 @@ split_definition(Tuple, defp, Meta, Clauses, T, Unreachable, Line,
186
190
split_definition (Tuple , defmacro , Meta , Clauses , T , Unreachable , Line ,
187
191
Def , Defmacro , Macros , Exports , Functions ) ->
188
192
{_ , _ , N , A , _ } = Entry = translate_definition (defmacro , Line , Meta , Tuple , Clauses ),
189
- split_definition (T , Unreachable , Line , Def , [Tuple | Defmacro ], [Tuple | Macros ], [{N , A } | Exports ],
193
+ split_definition (T , Unreachable , Line , Def , [{ Tuple , Meta } | Defmacro ], [Tuple | Macros ], [{N , A } | Exports ],
190
194
add_definition (Meta , Entry , Functions ));
191
195
192
196
split_definition (Tuple , defmacrop , Meta , Clauses , T , Unreachable , Line ,
@@ -261,6 +265,9 @@ functions_form(Line, Module, Def, Defmacro, Exports, Body, Deprecated, Struct) -
261
265
[{attribute , Line , export , lists :usort ([{'__info__' , 1 } | Exports ])}, Spec , Info | Body ].
262
266
263
267
add_info_function (Line , Module , Def , Defmacro , Deprecated , Struct ) ->
268
+ DefNA = [NA || {NA , _Meta } <- Def ],
269
+ DefmacroNA = [NA || {NA , _Meta } <- Defmacro ],
270
+
264
271
AllowedAttrs = [attributes , compile , functions , macros , md5 , exports_md5 , module , deprecated , struct ],
265
272
AllowedArgs = lists :map (fun (Atom ) -> {atom , Line , Atom } end , AllowedAttrs ),
266
273
@@ -277,10 +284,10 @@ add_info_function(Line, Module, Def, Defmacro, Deprecated, Struct) ->
277
284
Info =
278
285
{function , 0 , '__info__' , 1 , [
279
286
get_module_info (Module ),
280
- functions_info (Def ),
281
- macros_info (Defmacro ),
287
+ functions_info (DefNA ),
288
+ macros_info (DefmacroNA ),
282
289
struct_info (Struct ),
283
- exports_md5_info (Struct , Def , Defmacro ),
290
+ exports_md5_info (Struct , DefNA , DefmacroNA ),
284
291
get_module_info (Module , attributes ),
285
292
get_module_info (Module , compile ),
286
293
get_module_info (Module , md5 ),
@@ -331,19 +338,34 @@ typespecs_form(Map, TranslatedTypespecs, MacroNames) ->
331
338
Forms2 = callspecs_form (spec , Specs , [], MacroNames , Forms1 , Map ),
332
339
Forms3 = callspecs_form (callback , AllCallbacks , OptionalCallbacks , MacroCallbackNames , Forms2 , Map ),
333
340
334
- AllCallbacksWithoutSpecs = lists : usort ([
335
- {Kind , Name , Arity } || {Kind , {Name , Arity }, _Line , _Spec } <- AllCallbacks
341
+ AllCallbacksWithoutSpecs = usort_callbacks ([
342
+ {{ Kind , Name , Arity }, Meta } || {Kind , {Name , Arity }, Meta , _Spec } <- AllCallbacks
336
343
]),
337
344
338
345
{Types , AllCallbacksWithoutSpecs , Forms3 }.
339
346
347
+ usort_callbacks (Callbacks ) ->
348
+ % Sort and deduplicate callbacks. For duplicated callbacks we take
349
+ % the one with earliest line.
350
+
351
+ LineComparator = fun
352
+ ({Callback1 , Meta1 }, {Callback1 , Meta2 }) -> ? line (Meta1 ) =< ? line (Meta2 );
353
+ ({Callback1 , _Meta1 }, {Callback2 , _Meta2 }) -> Callback1 =< Callback2
354
+ end ,
355
+
356
+ UniqFun = fun ({Callback , _Meta }) -> Callback end ,
357
+
358
+ lists :uniq (UniqFun , lists :sort (LineComparator , Callbacks )).
359
+
340
360
% % Types
341
361
342
362
types_form (Types , Forms ) ->
343
363
Fun = fun
344
- ({Kind , NameArity , Line , Expr , true }, Acc ) ->
364
+ ({Kind , NameArity , Meta , Expr , true }, Acc ) ->
365
+ Line = ? line (Meta ),
345
366
[{attribute , Line , export_type , [NameArity ]}, {attribute , Line , Kind , Expr } | Acc ];
346
- ({Kind , _NameArity , Line , Expr , false }, Acc ) ->
367
+ ({Kind , _NameArity , Meta , Expr , false }, Acc ) ->
368
+ Line = ? line (Meta ),
347
369
[{attribute , Line , Kind , Expr } | Acc ]
348
370
end ,
349
371
@@ -387,7 +409,9 @@ callspecs_form(Kind, Entries, Optional, Macros, Forms, ModuleMap) ->
387
409
#{unreachable := Unreachable } = ModuleMap ,
388
410
389
411
{SpecsMap , Signatures } =
390
- lists :foldl (fun ({_ , NameArity , Line , Spec }, {Acc , NA }) ->
412
+ lists :foldl (fun ({_ , NameArity , Meta , Spec }, {Acc , NA }) ->
413
+ Line = ? line (Meta ),
414
+
391
415
case Kind of
392
416
spec -> validate_spec_for_existing_function (ModuleMap , NameArity , Line );
393
417
_ -> ok
@@ -440,7 +464,7 @@ validate_spec_for_existing_function(ModuleMap, NameAndArity, Line) ->
440
464
441
465
case lists :keymember (NameAndArity , 1 , Defs ) of
442
466
true -> ok ;
443
- false -> file_error (#{line => Line , file => File }, {spec_for_undefined_function , NameAndArity })
467
+ false -> file_error (#{anno => erl_anno : new ( Line ) , file => File }, {spec_for_undefined_function , NameAndArity })
444
468
end .
445
469
446
470
% Attributes
@@ -472,22 +496,30 @@ take_debug_opts(Opts) ->
472
496
extra_chunks_opts ([], Opts ) -> Opts ;
473
497
extra_chunks_opts (Chunks , Opts ) -> [{extra_chunks , Chunks } | Opts ].
474
498
475
- docs_chunk (Set , Module , Line , Def , Defmacro , Types , Callbacks ) ->
499
+ docs_chunk (Map , Set , Module , Anno , Def , Defmacro , Types , Callbacks ) ->
500
+ #{file := File , uses_behaviours := UsesBehaviours } = Map ,
501
+
476
502
case elixir_config :get (docs ) of
477
503
true ->
478
- {ModuleDocLine , ModuleDoc } = get_moduledoc (Line , Set ),
504
+ {ModuleDocLine , ModuleDoc } = get_moduledoc (erl_anno : line ( Anno ) , Set ),
479
505
ModuleDocMeta = get_moduledoc_meta (Set ),
480
506
FunctionDocs = get_docs (Set , Module , Def , function ),
481
507
MacroDocs = get_docs (Set , Module , Defmacro , macro ),
482
508
CallbackDocs = get_callback_docs (Set , Callbacks ),
483
509
TypeDocs = get_type_docs (Set , Types ),
484
510
511
+ ModuleMeta = ModuleDocMeta #{
512
+ source_path => File ,
513
+ source_annos => [Anno ],
514
+ behaviours => UsesBehaviours
515
+ },
516
+
485
517
DocsChunkData = term_to_binary ({docs_v1 ,
486
518
erl_anno :new (ModuleDocLine ),
487
519
elixir ,
488
520
<<" text/markdown" >>,
489
521
ModuleDoc ,
490
- ModuleDocMeta ,
522
+ ModuleMeta ,
491
523
FunctionDocs ++ MacroDocs ++ CallbackDocs ++ TypeDocs
492
524
}, [deterministic , compressed ]),
493
525
@@ -529,8 +561,8 @@ get_docs(Set, Module, Definitions, Kind) ->
529
561
maybe_generated (erl_anno :new (Line ), Ctx ),
530
562
[signature_to_binary (Module , Name , Signature )],
531
563
doc_value (Doc , Name ),
532
- Meta
533
- } || {Name , Arity } <- Definitions ,
564
+ Meta #{ source_annos => [ ? ann ( DefinitionMeta )]}
565
+ } || {{ Name , Arity }, DefinitionMeta } <- Definitions ,
534
566
{Key , Ctx , Line , Signature , Doc , Meta } <- ets :lookup (Set , {Kind , Name , Arity })].
535
567
536
568
maybe_generated (Ann , nil ) -> Ann ;
@@ -541,16 +573,16 @@ get_callback_docs(Set, Callbacks) ->
541
573
erl_anno :new (Line ),
542
574
[],
543
575
doc_value (Doc , Name ),
544
- Meta
545
- } || Callback <- Callbacks , {{ _ , Name , _ } = Key , Line , Doc , Meta } <- ets :lookup (Set , Callback )].
576
+ Meta #{ source_annos => [ ? ann ( DefinitionMeta )]}
577
+ } || {{ Kind , Name , Arity }, DefinitionMeta } <- Callbacks , { Key , Line , Doc , Meta } <- ets :lookup (Set , { Kind , Name , Arity } )].
546
578
547
579
get_type_docs (Set , Types ) ->
548
580
[{Key ,
549
581
erl_anno :new (Line ),
550
582
[],
551
583
doc_value (Doc , Name ),
552
- Meta
553
- } || {_Kind , {Name , Arity }, _ , _ , true } <- Types ,
584
+ Meta #{ source_annos => [ ? ann ( DefinitionMeta )]}
585
+ } || {_Kind , {Name , Arity }, DefinitionMeta , _ , true } <- Types ,
554
586
{Key , Line , Doc , Meta } <- ets :lookup (Set , {type , Name , Arity })].
555
587
556
588
signature_to_binary (_Module , Name , _Signature ) when Name == '__aliases__' ; Name == '__block__' ->
@@ -580,22 +612,23 @@ checker_chunk(Def, Defmacro, #{deprecated := Deprecated, defines_behaviour := De
580
612
581
613
Exports =
582
614
[{FA , #{kind => def , deprecated_reason => maps :get (FA , DeprecatedMap , nil )}}
583
- || FA <- prepend_behaviour_info (DefinesBehaviour , Def )] ++
615
+ || { FA , _Meta } <- prepend_behaviour_info (DefinesBehaviour , Def )] ++
584
616
[{FA , #{kind => defmacro , deprecated_reason => maps :get (FA , DeprecatedMap , nil )}}
585
- || FA <- Defmacro ],
617
+ || { FA , _Meta } <- Defmacro ],
586
618
587
619
Contents = #{
588
620
exports => Exports
589
621
},
590
622
591
623
[{<<" ExCk" >>, term_to_binary ({elixir_checker_v1 , Contents }, [deterministic ])}].
592
624
593
- prepend_behaviour_info (true , Def ) -> [{behaviour_info , 1 } | Def ];
625
+ prepend_behaviour_info (true , Def ) -> [{{ behaviour_info , 1 }, [] } | Def ];
594
626
prepend_behaviour_info (false , Def ) -> Def .
595
627
596
628
% % Errors
597
629
598
- file_error (#{line := Line , file := File }, Error ) ->
630
+ file_error (#{anno := Anno , file := File }, Error ) ->
631
+ Line = erl_anno :line (Anno ),
599
632
elixir_errors :file_error ([{line , Line }], File , ? MODULE , Error ).
600
633
601
634
format_error ({ill_defined_optional_callback , Callback }) ->
0 commit comments