11defmodule ExDoc.Language.Source do
22 @ moduledoc false
33
4+ def anno_line ( line ) when is_integer ( line ) , do: abs ( line )
5+ def anno_line ( anno ) , do: anno |> :erl_anno . line ( ) |> abs ( )
6+
7+ def anno_file ( anno ) do
8+ case :erl_anno . file ( anno ) do
9+ :undefined ->
10+ nil
11+
12+ file ->
13+ String.Chars . to_string ( file )
14+ end
15+ end
16+
417 @ doc """
518 Get abstract code and basedir for a module
619
@@ -18,7 +31,7 @@ defmodule ExDoc.Language.Source do
1831 end
1932
2033 defp expand_records_in_types ( abst_code ) do
21- ## Find all records in ast and collect any fields with type declarations
34+ # Find all records in ast and collect any fields with type declarations
2235 records =
2336 filtermap_ast ( abst_code , nil , fn
2437 { :attribute , anno , :record , { name , fields } } ->
@@ -40,7 +53,7 @@ defmodule ExDoc.Language.Source do
4053 end )
4154 |> Map . new ( )
4255
43- ## Expand records in all specs, callbacks, types and opaques
56+ # Expand records in all specs, callbacks, types and opaques
4457 filtermap_ast ( abst_code , nil , fn
4558 { :attribute , anno , kind , { mfa , ast } } when kind in [ :spec , :callback ] ->
4659 ast = Enum . map ( ast , & expand_records ( & 1 , records ) )
@@ -62,16 +75,16 @@ defmodule ExDoc.Language.Source do
6275 { :ann_type , anno , [ name , expand_records ( type , records ) ] }
6376 end
6477
65- ## When we encounter a record, we fetch the type definitions in the record and
66- ## merge then with the type. If there are duplicates we take the one in the type
67- ## declaration
78+ # When we encounter a record, we fetch the type definitions in the record and
79+ # merge then with the type. If there are duplicates we take the one in the type
80+ # declaration
6881 defp expand_records ( { :type , anno , :record , [ { :atom , _ , record } = name | args ] } , records ) do
6982 args =
7083 ( args ++ Map . get ( records , record , [ ] ) )
7184 |> Enum . uniq_by ( fn { :type , _ , :field_type , [ { :atom , _ , name } | _ ] } -> name end )
7285
73- ## We delete the record from the map so that recursive
74- ## record definitions are not expanded.
86+ # We delete the record from the map so that recursive
87+ # record definitions are not expanded.
7588 records = Map . delete ( records , record )
7689
7790 { :type , anno , :record , expand_records ( [ name | args ] , records ) }
@@ -90,32 +103,31 @@ defmodule ExDoc.Language.Source do
90103 end
91104
92105 @ doc """
93- Get the basedir of a module
106+ Fetches the basedir of a module.
94107
95108 The basedir is the cwd of the Elixir/Erlang compiler when compiling the module.
96109 All `-file` attributes in the module is relative to this directory.
97110 """
98- def get_basedir ( abst_code , module ) do
99- ## We look for the first -file attribute to see what the source file that
100- ## was compiled is called. Both Erlang and Elixir places one at the top.
111+ def fetch_basedir! ( abst_code , module ) do
112+ # We look for the first -file attribute to see what the source file that
113+ # was compiled is called. Both Erlang and Elixir places one at the top.
101114 filename =
102115 Enum . find_value ( abst_code , fn
103116 { :attribute , _anno , :file , { filename , _line } } ->
104117 filename
105118
106119 _ ->
107120 nil
108- end )
121+ end ) || raise "could not find base directory for #{ inspect ( module ) } "
109122
110- ## The first -file attribute will be either relative or absolute
111- ## depending on whether the compiler was called with an absolute
112- ## or relative path.
123+ # The first -file attribute will be either relative or absolute
124+ # depending on whether the compiler was called with an absolute
125+ # or relative path.
113126 if Path . type ( filename ) == :relative do
114- ## If the compiler was called with a relative path, then any other
115- ## relative -file attribute will be relative to the same directory.
116- ## We use `module_info(:compile)[:source]` to get an absolute path
117- ## to the source file and calculate the basedir from that
118-
127+ # If the compiler was called with a relative path, then any other
128+ # relative -file attribute will be relative to the same directory.
129+ # We use `module_info(:compile)[:source]` to get an absolute path
130+ # to the source file and calculate the basedir from that
119131 compile_source =
120132 cond do
121133 source = module . module_info ( :compile ) [ :source ] ->
@@ -143,27 +155,27 @@ defmodule ExDoc.Language.Source do
143155 |> Enum . drop ( Path . split ( filename ) |> Enum . count ( ) |> Kernel . * ( - 1 ) )
144156 |> Path . join ( )
145157 else
146- ## If an absolute path was used, then any relative -file attribute
147- ## is relative to the directory of the source file
158+ # If an absolute path was used, then any relative -file attribute
159+ # is relative to the directory of the source file
148160 Path . dirname ( filename )
149161 end
150162 end
151163
152- def get_module_location ( abst_code , source_basedir , module ) do
164+ def fetch_module_location! ( abst_code , source_basedir , module ) do
153165 find_ast ( abst_code , source_basedir , fn
154166 { :attribute , anno , :module , ^ module } ->
155167 { anno_file ( anno ) , anno_line ( anno ) }
156168
157169 _ ->
158170 nil
159- end )
171+ end ) || raise "could not find module definition for #{ inspect ( module ) } "
160172 end
161173
162- def get_function_location ( module_data , { name , arity } ) do
174+ def fetch_function_location! ( module_data , { name , arity } ) do
163175 find_ast ( module_data . private . abst_code , module_data . source_basedir , fn
164176 { :function , anno , ^ name , ^ arity , _ } -> { anno_file ( anno ) , anno_line ( anno ) }
165177 _ -> nil
166- end )
178+ end ) || raise "could not find function definition for #{ name } / #{ arity } "
167179 end
168180
169181 # Returns a map of {name, arity} => spec.
@@ -178,7 +190,7 @@ defmodule ExDoc.Language.Source do
178190 |> Map . new ( )
179191 end
180192
181- def get_type_from_module_data ( module_data , name , arity ) do
193+ def fetch_type! ( module_data , name , arity ) do
182194 find_ast ( module_data . private . abst_code , module_data . source_basedir , fn
183195 { :attribute , anno , type , { ^ name , _ , args } = spec } = attr ->
184196 if type in [ :opaque , :type ] and length ( args ) == arity do
@@ -193,7 +205,7 @@ defmodule ExDoc.Language.Source do
193205
194206 _ ->
195207 nil
196- end )
208+ end ) || raise "could not find type definition for #{ name } / #{ arity } "
197209 end
198210
199211 def get_callbacks ( abst_code , source_basedir ) do
@@ -215,20 +227,16 @@ defmodule ExDoc.Language.Source do
215227
216228 def get_optional_callbacks ( _module , _type ) , do: [ ]
217229
218- def find_ast ( ast , source_basedir , fun ) do
219- filtermap_ast ( ast , source_basedir , fun ) |> hd ( )
230+ defp find_ast ( ast , source_basedir , fun ) do
231+ filtermap_ast ( ast , source_basedir , fun ) |> List . first ( )
220232 end
221233
222- @ doc """
223- Does a filtermap operation over the forms in an abstract syntax tree with
224- updated anno for each form pointing to the correct file.
225- """
226234 # The file which a form belongs to is decided by the previous :file
227235 # attribute in the AST. The :file can be either relative, or absolute
228236 # depending on how the file was included. So when traversing the AST
229237 # we need to keep track of the :file attributes and update the anno
230238 # with the correct file.
231- def filtermap_ast ( ast , source_basedir , fun ) do
239+ defp filtermap_ast ( ast , source_basedir , fun ) do
232240 Enum . reduce ( ast , { nil , [ ] } , fn
233241 { :attribute , _anno , :file , { filename , _line } } = entry , { _file , acc } ->
234242 { if Path . type ( filename ) == :relative && source_basedir do
@@ -262,17 +270,4 @@ defmodule ExDoc.Language.Source do
262270 |> elem ( 1 )
263271 |> Enum . reverse ( )
264272 end
265-
266- def anno_line ( line ) when is_integer ( line ) , do: abs ( line )
267- def anno_line ( anno ) , do: anno |> :erl_anno . line ( ) |> abs ( )
268-
269- def anno_file ( anno ) do
270- case :erl_anno . file ( anno ) do
271- :undefined ->
272- nil
273-
274- file ->
275- String.Chars . to_string ( file )
276- end
277- end
278273end
0 commit comments