• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

nshkrdotcom / ElixirScope / e3c85b2dec2a55971a334d0061997410177723b4

28 May 2025 09:47AM UTC coverage: 59.568% (-4.1%) from 63.697%
e3c85b2dec2a55971a334d0061997410177723b4

push

github

NSHkr
Add new AST enhanced features with tests. 892 tests, 0 failures, 76 excluded

1752 of 3271 new or added lines in 17 files covered. (53.56%)

3 existing lines in 1 file now uncovered.

4797 of 8053 relevant lines covered (59.57%)

3798.33 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/lib/elixir_scope/ast_repository/enhanced_function_data.ex
1
defmodule ElixirScope.ASTRepository.EnhancedFunctionData do
2
  @moduledoc """
3
  Enhanced function data structure with comprehensive AST analysis information.
4
  
5
  This structure extends the basic FunctionData to support advanced analysis including:
6
  - Control Flow Graph (CFG) and Data Flow Graph (DFG) analysis
7
  - Comprehensive variable tracking and mutation analysis
8
  - Pattern matching and call graph data
9
  - Performance profiling hooks
10
  - Detailed complexity metrics
11
  
12
  ## Features
13
  - Complete function AST with head/body separation
14
  - Variable lifetime and mutation tracking
15
  - Control and data flow analysis
16
  - Call dependency tracking
17
  - Performance profiling integration
18
  - Pattern matching analysis
19
  - Comprehensive documentation support
20
  
21
  ## Usage
22
  
23
      iex> function_data = EnhancedFunctionData.new({MyModule, :my_func, 2}, ast)
24
      iex> EnhancedFunctionData.validate(function_data)
25
      :ok
26
  """
27
  
28
  alias ElixirScope.ASTRepository.Enhanced.{
29
    CFGData,
30
    DFGData,
31
    VariableData
32
  }
33
  alias ElixirScope.ASTRepository.Enhanced.SupportingStructures.{
34
    ClauseData,
35
    PatternData,
36
    ParameterData,
37
    CaptureData,
38
    VariableMutation,
39
    ReturnPoint,
40
    FunctionCall,
41
    FunctionReference,
42
    ExternalCall,
43
    PerformanceProfile,
44
    TypespecData,
45
    Example
46
  }
47
  # alias ElixirScope.Utils
48
  
49
  @type t :: %__MODULE__{
50
    # Identity
51
    module_name: atom(),
52
    function_name: atom(),
53
    arity: non_neg_integer(),
54
    ast_node_id: String.t(),  # e.g., "MyModule:my_func:2:def"
55
    
56
    # Location
57
    file_path: String.t(),
58
    line_start: pos_integer(),
59
    line_end: pos_integer(),
60
    column_start: pos_integer(),
61
    column_end: pos_integer(),
62
    
63
    # AST Data
64
    ast: Macro.t(),  # Complete function AST
65
    head_ast: Macro.t(),  # Function head/signature
66
    body_ast: Macro.t(),  # Function body
67
    
68
    # Function Characteristics
69
    visibility: :public | :private,
70
    is_macro: boolean(),
71
    is_guard: boolean(),
72
    is_callback: boolean(),
73
    is_delegate: boolean(),
74
    
75
    # Clauses & Patterns
76
    clauses: [ClauseData.t()],
77
    guard_clauses: [Macro.t()],
78
    pattern_matches: [PatternData.t()],
79
    
80
    # Variables & Data Flow
81
    parameters: [ParameterData.t()],
82
    local_variables: [VariableData.t()],
83
    captures: [CaptureData.t()],  # Captured variables in closures
84
    
85
    # Control Flow
86
    control_flow_graph: CFGData.t(),
87
    cyclomatic_complexity: non_neg_integer(),
88
    nesting_depth: non_neg_integer(),
89
    
90
    # Data Flow
91
    data_flow_graph: DFGData.t(),
92
    variable_mutations: [VariableMutation.t()],
93
    return_points: [ReturnPoint.t()],
94
    
95
    # Dependencies
96
    called_functions: [FunctionCall.t()],
97
    calling_functions: [FunctionReference.t()],  # Reverse index
98
    external_calls: [ExternalCall.t()],
99
    
100
    # Analysis Results
101
    complexity_score: float(),
102
    maintainability_index: float(),
103
    test_coverage: float() | nil,
104
    performance_profile: PerformanceProfile.t() | nil,
105
    
106
    # Documentation
107
    doc_string: String.t() | nil,
108
    spec: TypespecData.t() | nil,
109
    examples: [Example.t()],
110
    
111
    # Metadata
112
    tags: [String.t()],
113
    annotations: map(),
114
    metadata: map()
115
  }
116
  
117
  defstruct [
118
    # Identity
119
    :module_name,
120
    :function_name,
121
    :arity,
122
    :ast_node_id,
123
    
124
    # Location
125
    :file_path,
126
    :line_start,
127
    :line_end,
128
    :column_start,
129
    :column_end,
130
    
131
    # AST Data
132
    :ast,
133
    :head_ast,
134
    :body_ast,
135
    
136
    # Function Characteristics
137
    :visibility,
138
    :is_macro,
139
    :is_guard,
140
    :is_callback,
141
    :is_delegate,
142
    
143
    # Clauses & Patterns
144
    :clauses,
145
    :guard_clauses,
146
    :pattern_matches,
147
    
148
    # Variables & Data Flow
149
    :parameters,
150
    :local_variables,
151
    :captures,
152
    
153
    # Control Flow
154
    :control_flow_graph,
155
    :cyclomatic_complexity,
156
    :nesting_depth,
157
    
158
    # Data Flow
159
    :data_flow_graph,
160
    :variable_mutations,
161
    :return_points,
162
    
163
    # Dependencies
164
    :called_functions,
165
    :calling_functions,
166
    :external_calls,
167
    
168
    # Analysis Results
169
    :complexity_score,
170
    :maintainability_index,
171
    :test_coverage,
172
    :performance_profile,
173
    
174
    # Documentation
175
    :doc_string,
176
    :spec,
177
    :examples,
178
    
179
    # Metadata
180
    :tags,
181
    :annotations,
182
    :metadata
183
  ]
184
  
185
  @doc """
186
  Creates a new EnhancedFunctionData structure from function AST.
187
  
188
  ## Parameters
189
  - `function_key` - The {module, function, arity} tuple
190
  - `ast` - The function AST
191
  - `opts` - Optional parameters including file_path, visibility, etc.
192
  
193
  ## Examples
194
  
195
      iex> ast = quote do: def hello(name), do: "Hello, " <> name
196
      iex> data = EnhancedFunctionData.new({MyModule, :hello, 1}, ast)
197
      iex> data.function_name
198
      :hello
199
  """
200
  @spec new({atom(), atom(), non_neg_integer()}, Macro.t(), keyword()) :: t()
201
  def new({module_name, function_name, arity}, ast, opts \\ []) do
NEW
202
    ast_node_id = generate_ast_node_id(module_name, function_name, arity, ast)
×
NEW
203
    {head_ast, body_ast} = extract_head_and_body(ast)
×
NEW
204
    location = extract_location(ast, opts)
×
205
    
NEW
206
    %__MODULE__{
×
207
      # Identity
208
      module_name: module_name,
209
      function_name: function_name,
210
      arity: arity,
211
      ast_node_id: ast_node_id,
212
      
213
      # Location
214
      file_path: Keyword.get(opts, :file_path, ""),
NEW
215
      line_start: location.line_start,
×
NEW
216
      line_end: location.line_end,
×
NEW
217
      column_start: location.column_start,
×
NEW
218
      column_end: location.column_end,
×
219
      
220
      # AST Data
221
      ast: ast,
222
      head_ast: head_ast,
223
      body_ast: body_ast,
224
      
225
      # Function Characteristics
226
      visibility: detect_visibility(ast),
227
      is_macro: detect_is_macro(ast),
228
      is_guard: detect_is_guard(ast),
229
      is_callback: detect_is_callback(ast, opts),
230
      is_delegate: detect_is_delegate(ast),
231
      
232
      # Clauses & Patterns
233
      clauses: extract_clauses(ast),
234
      guard_clauses: extract_guard_clauses(ast),
235
      pattern_matches: extract_pattern_matches(ast),
236
      
237
      # Variables & Data Flow
238
      parameters: extract_parameters(head_ast),
239
      local_variables: extract_local_variables(body_ast),
240
      captures: extract_captures(body_ast),
241
      
242
      # Control Flow
243
      control_flow_graph: generate_cfg(ast),
244
      cyclomatic_complexity: calculate_cyclomatic_complexity(ast),
245
      nesting_depth: calculate_nesting_depth(ast),
246
      
247
      # Data Flow
248
      data_flow_graph: generate_dfg(ast),
249
      variable_mutations: extract_variable_mutations(ast),
250
      return_points: extract_return_points(ast),
251
      
252
      # Dependencies
253
      called_functions: extract_called_functions(ast),
254
      calling_functions: [],  # Populated by reverse indexing
255
      external_calls: extract_external_calls(ast),
256
      
257
      # Analysis Results
258
      complexity_score: calculate_complexity_score(ast),
259
      maintainability_index: calculate_maintainability_index(ast),
260
      test_coverage: nil,  # Populated by test analysis
261
      performance_profile: nil,  # Populated by runtime profiling
262
      
263
      # Documentation
264
      doc_string: extract_doc_string(ast, opts),
265
      spec: extract_spec(ast, opts),
266
      examples: extract_examples(ast, opts),
267
      
268
      # Metadata
269
      tags: Keyword.get(opts, :tags, []),
270
      annotations: Keyword.get(opts, :annotations, %{}),
271
      metadata: Keyword.get(opts, :metadata, %{})
272
    }
273
  end
274
  
275
  @doc """
276
  Validates the structure and data integrity of an EnhancedFunctionData.
277
  
278
  ## Returns
279
  - `:ok` if valid
280
  - `{:error, reason}` if invalid
281
  """
282
  @spec validate(t()) :: :ok | {:error, term()}
283
  def validate(%__MODULE__{} = data) do
NEW
284
    with :ok <- validate_required_fields(data),
×
NEW
285
         :ok <- validate_ast_consistency(data),
×
NEW
286
         :ok <- validate_location_data(data),
×
NEW
287
         :ok <- validate_complexity_metrics(data) do
×
288
      :ok
289
    end
290
  end
291
  
292
  @doc """
293
  Converts the structure to a format suitable for ETS storage.
294
  """
295
  @spec to_ets_format(t()) :: {{atom(), atom(), non_neg_integer()}, binary()}
296
  def to_ets_format(%__MODULE__{} = data) do
NEW
297
    function_key = {data.module_name, data.function_name, data.arity}
×
298
    
NEW
299
    compressed_data = %{
×
NEW
300
      ast_node_id: data.ast_node_id,
×
NEW
301
      file_path: data.file_path,
×
302
      location: %{
NEW
303
        line_start: data.line_start,
×
NEW
304
        line_end: data.line_end,
×
NEW
305
        column_start: data.column_start,
×
NEW
306
        column_end: data.column_end
×
307
      },
NEW
308
      ast_compressed: compress_ast(data.ast),
×
309
      characteristics: %{
NEW
310
        visibility: data.visibility,
×
NEW
311
        is_macro: data.is_macro,
×
NEW
312
        is_guard: data.is_guard,
×
NEW
313
        is_callback: data.is_callback,
×
NEW
314
        is_delegate: data.is_delegate
×
315
      },
316
      analysis: %{
NEW
317
        complexity_score: data.complexity_score,
×
NEW
318
        cyclomatic_complexity: data.cyclomatic_complexity,
×
NEW
319
        nesting_depth: data.nesting_depth,
×
NEW
320
        maintainability_index: data.maintainability_index
×
321
      },
NEW
322
      variables_count: length(data.local_variables),
×
NEW
323
      calls_count: length(data.called_functions),
×
NEW
324
      metadata: data.metadata
×
325
    }
326
    
327
    {function_key, :erlang.term_to_binary(compressed_data, [:compressed])}
328
  end
329
  
330
  @doc """
331
  Converts from ETS storage format back to full structure.
332
  """
333
  @spec from_ets_format({{atom(), atom(), non_neg_integer()}, binary()}) :: t()
334
  def from_ets_format({{module_name, function_name, arity}, binary_data}) do
NEW
335
    compressed_data = :erlang.binary_to_term(binary_data)
×
NEW
336
    location = compressed_data.location
×
NEW
337
    characteristics = compressed_data.characteristics
×
NEW
338
    analysis = compressed_data.analysis
×
339
    
NEW
340
    %__MODULE__{
×
341
      module_name: module_name,
342
      function_name: function_name,
343
      arity: arity,
NEW
344
      ast_node_id: compressed_data.ast_node_id,
×
NEW
345
      file_path: compressed_data.file_path,
×
NEW
346
      line_start: location.line_start,
×
NEW
347
      line_end: location.line_end,
×
NEW
348
      column_start: location.column_start,
×
NEW
349
      column_end: location.column_end,
×
NEW
350
      ast: decompress_ast(compressed_data.ast_compressed),
×
351
      head_ast: nil,  # Reconstructed on demand
352
      body_ast: nil,  # Reconstructed on demand
NEW
353
      visibility: characteristics.visibility,
×
NEW
354
      is_macro: characteristics.is_macro,
×
NEW
355
      is_guard: characteristics.is_guard,
×
NEW
356
      is_callback: characteristics.is_callback,
×
NEW
357
      is_delegate: characteristics.is_delegate,
×
358
      clauses: [],  # Loaded separately for performance
359
      guard_clauses: [],
360
      pattern_matches: [],
361
      parameters: [],
362
      local_variables: [],
363
      captures: [],
364
      control_flow_graph: nil,
NEW
365
      cyclomatic_complexity: analysis.cyclomatic_complexity,
×
NEW
366
      nesting_depth: analysis.nesting_depth,
×
367
      data_flow_graph: nil,
368
      variable_mutations: [],
369
      return_points: [],
370
      called_functions: [],
371
      calling_functions: [],
372
      external_calls: [],
NEW
373
      complexity_score: analysis.complexity_score,
×
NEW
374
      maintainability_index: analysis.maintainability_index,
×
375
      test_coverage: nil,
376
      performance_profile: nil,
377
      doc_string: nil,
378
      spec: nil,
379
      examples: [],
380
      tags: [],
381
      annotations: %{},
NEW
382
      metadata: compressed_data.metadata
×
383
    }
384
  end
385
  
386
  @doc """
387
  Updates the function with performance profile data.
388
  """
389
  @spec update_performance_profile(t(), PerformanceProfile.t()) :: t()
390
  def update_performance_profile(%__MODULE__{} = data, profile) do
NEW
391
    %{data | performance_profile: profile}
×
392
  end
393
  
394
  @doc """
395
  Adds a calling function reference for reverse indexing.
396
  """
397
  @spec add_calling_function(t(), FunctionReference.t()) :: t()
398
  def add_calling_function(%__MODULE__{} = data, function_ref) do
NEW
399
    %{data | calling_functions: [function_ref | data.calling_functions]}
×
400
  end
401
  
402
  @doc """
403
  Gets the function signature as a string.
404
  """
405
  @spec get_signature(t()) :: String.t()
406
  def get_signature(%__MODULE__{} = data) do
NEW
407
    "#{data.module_name}.#{data.function_name}/#{data.arity}"
×
408
  end
409
  
410
  @doc """
411
  Checks if the function is a hot path based on complexity and call frequency.
412
  """
413
  @spec is_hot_path?(t()) :: boolean()
414
  def is_hot_path?(%__MODULE__{} = data) do
NEW
415
    high_complexity = data.complexity_score > 10.0
×
NEW
416
    frequent_calls = length(data.calling_functions) > 5
×
417
    
NEW
418
    high_complexity or frequent_calls
×
419
  end
420
  
421
  @doc """
422
  Gets all variable names used in the function.
423
  """
424
  @spec get_variable_names(t()) :: [atom()]
425
  def get_variable_names(%__MODULE__{} = data) do
NEW
426
    parameter_names = Enum.map(data.parameters, & &1.name)
×
NEW
427
    local_names = Enum.map(data.local_variables, & &1.name)
×
NEW
428
    capture_names = Enum.map(data.captures, & &1.variable_name)
×
429
    
430
    (parameter_names ++ local_names ++ capture_names)
NEW
431
    |> Enum.uniq()
×
432
  end
433
  
434
  @doc """
435
  Migrates from basic FunctionData to EnhancedFunctionData.
436
  """
437
  @spec from_function_data(ElixirScope.ASTRepository.FunctionData.t()) :: t()
438
  def from_function_data(function_data) do
NEW
439
    {module_name, function_name, arity} = function_data.function_key
×
440
    
NEW
441
    %__MODULE__{
×
442
      module_name: module_name,
443
      function_name: function_name,
444
      arity: arity,
NEW
445
      ast_node_id: generate_ast_node_id(module_name, function_name, arity, function_data.ast),
×
NEW
446
      file_path: extract_file_path(function_data.source_location),
×
NEW
447
      line_start: extract_line_start(function_data.source_location),
×
NEW
448
      line_end: extract_line_end(function_data.source_location),
×
449
      column_start: 1,
450
      column_end: 1,
NEW
451
      ast: function_data.ast,
×
452
      head_ast: nil,
453
      body_ast: nil,
NEW
454
      visibility: function_data.visibility,
×
NEW
455
      is_macro: function_data.type == :macro,
×
456
      is_guard: false,
NEW
457
      is_callback: function_data.type == :callback,
×
458
      is_delegate: false,
459
      clauses: [],
NEW
460
      guard_clauses: function_data.guards || [],
×
461
      pattern_matches: [],
462
      parameters: [],
463
      local_variables: [],
464
      captures: [],
465
      control_flow_graph: nil,
NEW
466
      cyclomatic_complexity: get_cyclomatic_from_old_metrics(function_data.complexity_metrics),
×
467
      nesting_depth: 1,
468
      data_flow_graph: nil,
469
      variable_mutations: [],
470
      return_points: [],
NEW
471
      called_functions: migrate_dependencies_to_calls(function_data.dependencies),
×
472
      calling_functions: [],
473
      external_calls: [],
NEW
474
      complexity_score: get_complexity_score_from_old_metrics(function_data.complexity_metrics),
×
475
      maintainability_index: 100.0,
476
      test_coverage: nil,
NEW
477
      performance_profile: migrate_performance_profile(function_data.performance_profile),
×
NEW
478
      doc_string: function_data.documentation,
×
479
      spec: nil,
480
      examples: [],
481
      tags: [],
482
      annotations: %{},
483
      metadata: %{
484
        migrated_from: "FunctionData",
485
        migration_timestamp: DateTime.to_iso8601(DateTime.utc_now()),
NEW
486
        original_version: function_data.version
×
487
      }
488
    }
489
  end
490
  
491
  # Private helper functions
492
  
493
  defp generate_ast_node_id(module_name, function_name, arity, ast) do
NEW
494
    ast_hash = :crypto.hash(:md5, inspect(ast)) |> Base.encode16(case: :lower)
×
NEW
495
    "#{module_name}:#{function_name}:#{arity}:def:#{String.slice(ast_hash, 0, 8)}"
×
496
  end
497
  
NEW
498
  defp extract_head_and_body({:def, _, [head, body]}), do: {head, body}
×
NEW
499
  defp extract_head_and_body({:defp, _, [head, body]}), do: {head, body}
×
NEW
500
  defp extract_head_and_body({:defmacro, _, [head, body]}), do: {head, body}
×
NEW
501
  defp extract_head_and_body({:defmacrop, _, [head, body]}), do: {head, body}
×
NEW
502
  defp extract_head_and_body(ast), do: {ast, nil}
×
503
  
504
  defp extract_location(_ast, opts) do
NEW
505
    %{
×
506
      line_start: Keyword.get(opts, :line_start, 1),
507
      line_end: Keyword.get(opts, :line_end, 1),
508
      column_start: Keyword.get(opts, :column_start, 1),
509
      column_end: Keyword.get(opts, :column_end, 1)
510
    }
511
  end
512
  
NEW
513
  defp detect_visibility({:defp, _, _}), do: :private
×
NEW
514
  defp detect_visibility({:defmacrop, _, _}), do: :private
×
NEW
515
  defp detect_visibility(_), do: :public
×
516
  
NEW
517
  defp detect_is_macro({:defmacro, _, _}), do: true
×
NEW
518
  defp detect_is_macro({:defmacrop, _, _}), do: true
×
NEW
519
  defp detect_is_macro(_), do: false
×
520
  
NEW
521
  defp detect_is_guard(_ast), do: false  # TODO: Implement guard detection
×
NEW
522
  defp detect_is_callback(_ast, _opts), do: false  # TODO: Implement callback detection
×
NEW
523
  defp detect_is_delegate(_ast), do: false  # TODO: Implement delegate detection
×
524
  
NEW
525
  defp extract_clauses(_ast), do: []  # TODO: Implement clause extraction
×
NEW
526
  defp extract_guard_clauses(_ast), do: []  # TODO: Implement guard clause extraction
×
NEW
527
  defp extract_pattern_matches(_ast), do: []  # TODO: Implement pattern match extraction
×
NEW
528
  defp extract_parameters(_ast), do: []  # TODO: Implement parameter extraction
×
NEW
529
  defp extract_local_variables(_ast), do: []  # TODO: Implement variable extraction
×
NEW
530
  defp extract_captures(_ast), do: []  # TODO: Implement capture extraction
×
531
  
NEW
532
  defp generate_cfg(_ast), do: nil  # TODO: Implement CFG generation
×
NEW
533
  defp generate_dfg(_ast), do: nil  # TODO: Implement DFG generation
×
534
  
NEW
535
  defp calculate_cyclomatic_complexity(_ast), do: 1  # TODO: Implement complexity calculation
×
NEW
536
  defp calculate_nesting_depth(_ast), do: 1  # TODO: Implement nesting depth calculation
×
NEW
537
  defp calculate_complexity_score(_ast), do: 1.0  # TODO: Implement complexity scoring
×
NEW
538
  defp calculate_maintainability_index(_ast), do: 100.0  # TODO: Implement maintainability index
×
539
  
NEW
540
  defp extract_variable_mutations(_ast), do: []  # TODO: Implement mutation extraction
×
NEW
541
  defp extract_return_points(_ast), do: []  # TODO: Implement return point extraction
×
NEW
542
  defp extract_called_functions(_ast), do: []  # TODO: Implement function call extraction
×
NEW
543
  defp extract_external_calls(_ast), do: []  # TODO: Implement external call extraction
×
544
  
NEW
545
  defp extract_doc_string(_ast, _opts), do: nil  # TODO: Implement doc string extraction
×
NEW
546
  defp extract_spec(_ast, _opts), do: nil  # TODO: Implement spec extraction
×
NEW
547
  defp extract_examples(_ast, _opts), do: []  # TODO: Implement example extraction
×
548
  
NEW
549
  defp validate_required_fields(%__MODULE__{module_name: nil}), do: {:error, :missing_module_name}
×
NEW
550
  defp validate_required_fields(%__MODULE__{function_name: nil}), do: {:error, :missing_function_name}
×
NEW
551
  defp validate_required_fields(%__MODULE__{ast: nil}), do: {:error, :missing_ast}
×
NEW
552
  defp validate_required_fields(_), do: :ok
×
553
  
NEW
554
  defp validate_ast_consistency(%__MODULE__{arity: arity}) when arity < 0, do: {:error, :invalid_arity}
×
NEW
555
  defp validate_ast_consistency(_), do: :ok
×
556
  
NEW
557
  defp validate_location_data(%__MODULE__{line_start: start, line_end: end_line}) when start > end_line, do: {:error, :invalid_line_range}
×
NEW
558
  defp validate_location_data(_), do: :ok
×
559
  
NEW
560
  defp validate_complexity_metrics(%__MODULE__{complexity_score: score}) when score < 0, do: {:error, :invalid_complexity_score}
×
NEW
561
  defp validate_complexity_metrics(_), do: :ok
×
562
  
563
  defp compress_ast(ast) do
564
    ast
565
    |> :erlang.term_to_binary([:compressed])
NEW
566
    |> Base.encode64()
×
567
  end
568
  
569
  defp decompress_ast(compressed_string) do
570
    compressed_string
571
    |> Base.decode64!()
NEW
572
    |> :erlang.binary_to_term()
×
573
  end
574
  
NEW
575
  defp extract_file_path({file, _line}), do: file
×
NEW
576
  defp extract_file_path(_), do: ""
×
577
  
NEW
578
  defp extract_line_start({_file, line}), do: line
×
NEW
579
  defp extract_line_start(_), do: 1
×
580
  
NEW
581
  defp extract_line_end({_file, line}), do: line
×
NEW
582
  defp extract_line_end(_), do: 1
×
583
  
NEW
584
  defp get_cyclomatic_from_old_metrics(nil), do: 1
×
NEW
585
  defp get_cyclomatic_from_old_metrics(metrics), do: Map.get(metrics, :cyclomatic, 1)
×
586
  
NEW
587
  defp get_complexity_score_from_old_metrics(nil), do: 1.0
×
NEW
588
  defp get_complexity_score_from_old_metrics(metrics), do: Map.get(metrics, :score, 1.0)
×
589
  
NEW
590
  defp migrate_dependencies_to_calls(nil), do: []
×
591
  defp migrate_dependencies_to_calls(deps) when is_list(deps) do
NEW
592
    Enum.map(deps, fn
×
593
      {module, function, arity} ->
NEW
594
        %FunctionCall{
×
595
          target_module: module,
596
          target_function: function,
597
          target_arity: arity,
598
          call_type: :local,
599
          ast_node_id: "migrated_call",
600
          line: 1
601
        }
602
      _ -> 
NEW
603
        %FunctionCall{
×
604
          target_module: :unknown,
605
          target_function: :unknown,
606
          target_arity: 0,
607
          call_type: :unknown,
608
          ast_node_id: "migrated_call",
609
          line: 1
610
        }
611
    end)
612
  end
NEW
613
  defp migrate_dependencies_to_calls(_), do: []
×
614
  
NEW
615
  defp migrate_performance_profile(nil), do: nil
×
616
  defp migrate_performance_profile(old_profile) do
NEW
617
    %PerformanceProfile{
×
618
      average_duration_ms: Map.get(old_profile, :average_duration, 0.0),
619
      min_duration_ms: Map.get(old_profile, :min_duration, 0.0),
620
      max_duration_ms: Map.get(old_profile, :max_duration, 0.0),
621
      p95_duration_ms: Map.get(old_profile, :p95_duration, 0.0),
622
      p99_duration_ms: Map.get(old_profile, :p99_duration, 0.0),
623
      memory_usage: Map.get(old_profile, :memory_usage, %{}),
624
      cpu_usage: Map.get(old_profile, :cpu_usage, %{}),
625
      call_count: 0,
626
      error_count: 0
627
    }
628
  end
629
end 
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc