mt-lang 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.ruby-version +1 -0
- data/AUTHORS +3 -0
- data/Gemfile +19 -0
- data/Gemfile.lock +82 -0
- data/LICENSE +21 -0
- data/README.md +1208 -0
- data/Rakefile +332 -0
- data/bin/mtc +8 -0
- data/bin/profile-mtc-checks +133 -0
- data/bin/tracy-profiler +0 -0
- data/docs/build-guide.md +536 -0
- data/docs/index.html +2778 -0
- data/docs/language-design.md +1519 -0
- data/docs/language-manual.md +1534 -0
- data/lib/milk_tea/base.rb +49 -0
- data/lib/milk_tea/bindings/bindgen/ast_parser.rb +398 -0
- data/lib/milk_tea/bindings/bindgen/declaration.rb +319 -0
- data/lib/milk_tea/bindings/bindgen/emitter.rb +387 -0
- data/lib/milk_tea/bindings/bindgen/overrides.rb +134 -0
- data/lib/milk_tea/bindings/bindgen/type_mapper.rb +622 -0
- data/lib/milk_tea/bindings/bindgen.rb +207 -0
- data/lib/milk_tea/bindings/cli.rb +121 -0
- data/lib/milk_tea/bindings/imported_bindings/defaults.rb +210 -0
- data/lib/milk_tea/bindings/imported_bindings/generator.rb +1114 -0
- data/lib/milk_tea/bindings/imported_bindings/method_source.rb +190 -0
- data/lib/milk_tea/bindings/imported_bindings/naming.rb +286 -0
- data/lib/milk_tea/bindings/imported_bindings.rb +215 -0
- data/lib/milk_tea/bindings/opengl_registry.rb +547 -0
- data/lib/milk_tea/bindings/raw_bindings/defaults.rb +1338 -0
- data/lib/milk_tea/bindings/raw_bindings.rb +269 -0
- data/lib/milk_tea/bindings/steamworks.rb +629 -0
- data/lib/milk_tea/bindings/upstream_sources.rb +352 -0
- data/lib/milk_tea/bindings/vendored_box2d.rb +79 -0
- data/lib/milk_tea/bindings/vendored_c_library.rb +322 -0
- data/lib/milk_tea/bindings/vendored_cjson.rb +52 -0
- data/lib/milk_tea/bindings/vendored_flecs.rb +78 -0
- data/lib/milk_tea/bindings/vendored_glfw.rb +77 -0
- data/lib/milk_tea/bindings/vendored_libuv.rb +75 -0
- data/lib/milk_tea/bindings/vendored_pcre2.rb +84 -0
- data/lib/milk_tea/bindings/vendored_raylib.rb +131 -0
- data/lib/milk_tea/bindings/vendored_sdl3.rb +78 -0
- data/lib/milk_tea/bindings/vendored_steamworks.rb +71 -0
- data/lib/milk_tea/bindings/vendored_tool.rb +71 -0
- data/lib/milk_tea/bindings/vendored_tools.rb +23 -0
- data/lib/milk_tea/bindings/vendored_tracy.rb +37 -0
- data/lib/milk_tea/bindings.rb +23 -0
- data/lib/milk_tea/core/ast.rb +311 -0
- data/lib/milk_tea/core/async_runtime_installer.rb +28 -0
- data/lib/milk_tea/core/binding_types.rb +18 -0
- data/lib/milk_tea/core/bindings/attribute_binding.rb +58 -0
- data/lib/milk_tea/core/bindings/function_binding.rb +5 -0
- data/lib/milk_tea/core/bindings/module_binding.rb +58 -0
- data/lib/milk_tea/core/bindings/value_binding.rb +21 -0
- data/lib/milk_tea/core/c_backend/aggregate_utils.rb +103 -0
- data/lib/milk_tea/core/c_backend/control_flow_emission.rb +412 -0
- data/lib/milk_tea/core/c_backend/expressions.rb +468 -0
- data/lib/milk_tea/core/c_backend/feature_detection.rb +483 -0
- data/lib/milk_tea/core/c_backend/reachability.rb +398 -0
- data/lib/milk_tea/core/c_backend/reinterpret.rb +226 -0
- data/lib/milk_tea/core/c_backend/runtime_helpers.rb +1080 -0
- data/lib/milk_tea/core/c_backend/statements.rb +563 -0
- data/lib/milk_tea/core/c_backend/type_collectors.rb +1545 -0
- data/lib/milk_tea/core/c_backend/type_declaration.rb +223 -0
- data/lib/milk_tea/core/c_backend/type_system.rb +345 -0
- data/lib/milk_tea/core/c_backend.rb +287 -0
- data/lib/milk_tea/core/compatibility_helpers.rb +79 -0
- data/lib/milk_tea/core/compile_time/const_eval.rb +187 -0
- data/lib/milk_tea/core/compile_time.rb +329 -0
- data/lib/milk_tea/core/control_flow/builder.rb +582 -0
- data/lib/milk_tea/core/control_flow/constant_propagation.rb +143 -0
- data/lib/milk_tea/core/control_flow/dataflow.rb +74 -0
- data/lib/milk_tea/core/control_flow/definite_assignment.rb +79 -0
- data/lib/milk_tea/core/control_flow/graph.rb +90 -0
- data/lib/milk_tea/core/control_flow/liveness.rb +24 -0
- data/lib/milk_tea/core/control_flow/nullability_flow.rb +43 -0
- data/lib/milk_tea/core/control_flow/reachability.rb +22 -0
- data/lib/milk_tea/core/control_flow/termination.rb +31 -0
- data/lib/milk_tea/core/control_flow.rb +34 -0
- data/lib/milk_tea/core/cst.rb +48 -0
- data/lib/milk_tea/core/cst_builder.rb +19 -0
- data/lib/milk_tea/core/ir.rb +85 -0
- data/lib/milk_tea/core/keywords.rb +97 -0
- data/lib/milk_tea/core/lexer/character_classes.rb +60 -0
- data/lib/milk_tea/core/lexer/format_strings.rb +225 -0
- data/lib/milk_tea/core/lexer/heredocs.rb +199 -0
- data/lib/milk_tea/core/lexer/indentation.rb +62 -0
- data/lib/milk_tea/core/lexer/numbers.rb +96 -0
- data/lib/milk_tea/core/lexer/recovery.rb +32 -0
- data/lib/milk_tea/core/lexer/strings.rb +167 -0
- data/lib/milk_tea/core/lexer/symbols.rb +71 -0
- data/lib/milk_tea/core/lexer/trivia.rb +53 -0
- data/lib/milk_tea/core/lexer.rb +430 -0
- data/lib/milk_tea/core/lowering/artifacts.rb +26 -0
- data/lib/milk_tea/core/lowering/async/analysis.rb +245 -0
- data/lib/milk_tea/core/lowering/async/lowering.rb +1399 -0
- data/lib/milk_tea/core/lowering/async/normalization.rb +459 -0
- data/lib/milk_tea/core/lowering/async.rb +714 -0
- data/lib/milk_tea/core/lowering/block.rb +1052 -0
- data/lib/milk_tea/core/lowering/calls.rb +1565 -0
- data/lib/milk_tea/core/lowering/declarations.rb +214 -0
- data/lib/milk_tea/core/lowering/dyn.rb +206 -0
- data/lib/milk_tea/core/lowering/events.rb +1054 -0
- data/lib/milk_tea/core/lowering/expressions.rb +1645 -0
- data/lib/milk_tea/core/lowering/foreign_cstr.rb +206 -0
- data/lib/milk_tea/core/lowering/functions.rb +242 -0
- data/lib/milk_tea/core/lowering/loops.rb +1087 -0
- data/lib/milk_tea/core/lowering/lowering_context.rb +80 -0
- data/lib/milk_tea/core/lowering/proc.rb +419 -0
- data/lib/milk_tea/core/lowering/resolve.rb +2516 -0
- data/lib/milk_tea/core/lowering/scans.rb +220 -0
- data/lib/milk_tea/core/lowering/str_buffer.rb +125 -0
- data/lib/milk_tea/core/lowering/utils.rb +1453 -0
- data/lib/milk_tea/core/lowering.rb +378 -0
- data/lib/milk_tea/core/module_binder.rb +181 -0
- data/lib/milk_tea/core/module_loader/errors.rb +21 -0
- data/lib/milk_tea/core/module_loader.rb +479 -0
- data/lib/milk_tea/core/module_path_resolver.rb +153 -0
- data/lib/milk_tea/core/module_roots.rb +88 -0
- data/lib/milk_tea/core/parser/attributes.rb +71 -0
- data/lib/milk_tea/core/parser/blocks.rb +119 -0
- data/lib/milk_tea/core/parser/declarations.rb +749 -0
- data/lib/milk_tea/core/parser/expressions.rb +624 -0
- data/lib/milk_tea/core/parser/recovery.rb +131 -0
- data/lib/milk_tea/core/parser/statements.rb +756 -0
- data/lib/milk_tea/core/parser/types.rb +271 -0
- data/lib/milk_tea/core/parser.rb +400 -0
- data/lib/milk_tea/core/prelude_installer.rb +29 -0
- data/lib/milk_tea/core/pretty_printer/ast_formatter.rb +917 -0
- data/lib/milk_tea/core/pretty_printer/base_formatter.rb +87 -0
- data/lib/milk_tea/core/pretty_printer/ir_formatter.rb +300 -0
- data/lib/milk_tea/core/pretty_printer.rb +17 -0
- data/lib/milk_tea/core/semantic_analyzer/analysis_context.rb +314 -0
- data/lib/milk_tea/core/semantic_analyzer/attributes.rb +184 -0
- data/lib/milk_tea/core/semantic_analyzer/calls.rb +992 -0
- data/lib/milk_tea/core/semantic_analyzer/expressions.rb +1735 -0
- data/lib/milk_tea/core/semantic_analyzer/flow_refinement.rb +355 -0
- data/lib/milk_tea/core/semantic_analyzer/foreign_functions.rb +155 -0
- data/lib/milk_tea/core/semantic_analyzer/function_binding.rb +354 -0
- data/lib/milk_tea/core/semantic_analyzer/generics.rb +383 -0
- data/lib/milk_tea/core/semantic_analyzer/interface_conformance.rb +78 -0
- data/lib/milk_tea/core/semantic_analyzer/module_context.rb +35 -0
- data/lib/milk_tea/core/semantic_analyzer/name_resolution.rb +1438 -0
- data/lib/milk_tea/core/semantic_analyzer/nullability.rb +421 -0
- data/lib/milk_tea/core/semantic_analyzer/statements.rb +1308 -0
- data/lib/milk_tea/core/semantic_analyzer/top_level.rb +588 -0
- data/lib/milk_tea/core/semantic_analyzer/type_compatibility.rb +307 -0
- data/lib/milk_tea/core/semantic_analyzer/type_declaration.rb +851 -0
- data/lib/milk_tea/core/semantic_analyzer.rb +327 -0
- data/lib/milk_tea/core/token.rb +26 -0
- data/lib/milk_tea/core/token_stream.rb +30 -0
- data/lib/milk_tea/core/types/layout.rb +243 -0
- data/lib/milk_tea/core/types/predicates.rb +609 -0
- data/lib/milk_tea/core/types/registry.rb +83 -0
- data/lib/milk_tea/core/types/types.rb +1696 -0
- data/lib/milk_tea/core/types/visitor.rb +442 -0
- data/lib/milk_tea/core.rb +25 -0
- data/lib/milk_tea/dap/backends/lldb_dap.rb +158 -0
- data/lib/milk_tea/dap/protocol.rb +58 -0
- data/lib/milk_tea/dap/server/breakpoints.rb +66 -0
- data/lib/milk_tea/dap/server/debug_map.rb +291 -0
- data/lib/milk_tea/dap/server/handlers.rb +374 -0
- data/lib/milk_tea/dap/server/launch.rb +261 -0
- data/lib/milk_tea/dap/server/lldb_backend.rb +380 -0
- data/lib/milk_tea/dap/server/pause_diagnostics.rb +109 -0
- data/lib/milk_tea/dap/server/utilities.rb +160 -0
- data/lib/milk_tea/dap/server/wire.rb +55 -0
- data/lib/milk_tea/dap/server.rb +131 -0
- data/lib/milk_tea/dap/session.rb +152 -0
- data/lib/milk_tea/dap.rb +6 -0
- data/lib/milk_tea/lsp/dependency_resolution.rb +52 -0
- data/lib/milk_tea/lsp/diagnostics.rb +611 -0
- data/lib/milk_tea/lsp/protocol.rb +104 -0
- data/lib/milk_tea/lsp/server/call_hierarchy.rb +274 -0
- data/lib/milk_tea/lsp/server/code_actions.rb +446 -0
- data/lib/milk_tea/lsp/server/code_lens.rb +97 -0
- data/lib/milk_tea/lsp/server/completion.rb +1099 -0
- data/lib/milk_tea/lsp/server/configuration.rb +167 -0
- data/lib/milk_tea/lsp/server/debug_info.rb +45 -0
- data/lib/milk_tea/lsp/server/definition.rb +779 -0
- data/lib/milk_tea/lsp/server/diagnostics_scheduling.rb +239 -0
- data/lib/milk_tea/lsp/server/execute_command.rb +25 -0
- data/lib/milk_tea/lsp/server/folding_range.rb +153 -0
- data/lib/milk_tea/lsp/server/formatting.rb +575 -0
- data/lib/milk_tea/lsp/server/hover.rb +1465 -0
- data/lib/milk_tea/lsp/server/inlay_hints.rb +204 -0
- data/lib/milk_tea/lsp/server/lifecycle.rb +234 -0
- data/lib/milk_tea/lsp/server/linked_editing_range.rb +43 -0
- data/lib/milk_tea/lsp/server/on_type_formatting.rb +73 -0
- data/lib/milk_tea/lsp/server/progress.rb +47 -0
- data/lib/milk_tea/lsp/server/references.rb +433 -0
- data/lib/milk_tea/lsp/server/rename.rb +598 -0
- data/lib/milk_tea/lsp/server/selection_range.rb +130 -0
- data/lib/milk_tea/lsp/server/semantic_tokens.rb +1745 -0
- data/lib/milk_tea/lsp/server/signature_help.rb +200 -0
- data/lib/milk_tea/lsp/server/text_documents.rb +125 -0
- data/lib/milk_tea/lsp/server/type_hierarchy.rb +167 -0
- data/lib/milk_tea/lsp/server/utilities.rb +520 -0
- data/lib/milk_tea/lsp/server.rb +415 -0
- data/lib/milk_tea/lsp/workspace/analysis.rb +209 -0
- data/lib/milk_tea/lsp/workspace/caches.rb +260 -0
- data/lib/milk_tea/lsp/workspace/collection.rb +98 -0
- data/lib/milk_tea/lsp/workspace/definition_index.rb +184 -0
- data/lib/milk_tea/lsp/workspace/dependency_graph.rb +282 -0
- data/lib/milk_tea/lsp/workspace/store.rb +154 -0
- data/lib/milk_tea/lsp/workspace/utilities.rb +490 -0
- data/lib/milk_tea/lsp/workspace.rb +127 -0
- data/lib/milk_tea/lsp.rb +13 -0
- data/lib/milk_tea/packages/atomic_write.rb +63 -0
- data/lib/milk_tea/packages/dependency_solver.rb +194 -0
- data/lib/milk_tea/packages/graph.rb +139 -0
- data/lib/milk_tea/packages/lock.rb +421 -0
- data/lib/milk_tea/packages/manager_cli.rb +485 -0
- data/lib/milk_tea/packages/manifest.rb +356 -0
- data/lib/milk_tea/packages/manifest_editor.rb +134 -0
- data/lib/milk_tea/packages/registry_metadata_provider.rb +34 -0
- data/lib/milk_tea/packages/registry_store.rb +420 -0
- data/lib/milk_tea/packages/services.rb +41 -0
- data/lib/milk_tea/packages/source_cache.rb +71 -0
- data/lib/milk_tea/packages/source_fetcher.rb +124 -0
- data/lib/milk_tea/packages/source_resolver.rb +389 -0
- data/lib/milk_tea/packages/version.rb +164 -0
- data/lib/milk_tea/packages.rb +16 -0
- data/lib/milk_tea/tooling/asset_pack.rb +141 -0
- data/lib/milk_tea/tooling/build.rb +1124 -0
- data/lib/milk_tea/tooling/build_cache.rb +240 -0
- data/lib/milk_tea/tooling/cli.rb +2688 -0
- data/lib/milk_tea/tooling/cst_formatter.rb +13 -0
- data/lib/milk_tea/tooling/debug_info_formatter.rb +456 -0
- data/lib/milk_tea/tooling/debug_map.rb +248 -0
- data/lib/milk_tea/tooling/docs_app.rb +369 -0
- data/lib/milk_tea/tooling/error_formatter.rb +86 -0
- data/lib/milk_tea/tooling/formatter.rb +787 -0
- data/lib/milk_tea/tooling/linter/doc_tags.rb +212 -0
- data/lib/milk_tea/tooling/linter/fix_engine.rb +237 -0
- data/lib/milk_tea/tooling/linter/flow_rules.rb +380 -0
- data/lib/milk_tea/tooling/linter/imports_platform.rb +841 -0
- data/lib/milk_tea/tooling/linter/release_rules.rb +744 -0
- data/lib/milk_tea/tooling/linter/reserved_names.rb +199 -0
- data/lib/milk_tea/tooling/linter/rules.rb +593 -0
- data/lib/milk_tea/tooling/linter/source_helpers.rb +407 -0
- data/lib/milk_tea/tooling/linter/trailing_comma.rb +139 -0
- data/lib/milk_tea/tooling/linter/visitors.rb +1286 -0
- data/lib/milk_tea/tooling/linter.rb +798 -0
- data/lib/milk_tea/tooling/project_scaffold.rb +82 -0
- data/lib/milk_tea/tooling/public/css/docs.css +166 -0
- data/lib/milk_tea/tooling/public/js/docs.js +94 -0
- data/lib/milk_tea/tooling/run.rb +408 -0
- data/lib/milk_tea/tooling/templates/wasm_shell.html +48 -0
- data/lib/milk_tea/tooling/toolchain_cli.rb +157 -0
- data/lib/milk_tea/tooling/views/404.erb +7 -0
- data/lib/milk_tea/tooling/views/index.erb +87 -0
- data/lib/milk_tea/tooling/views/layout.erb +69 -0
- data/lib/milk_tea/tooling/views/module.erb +97 -0
- data/lib/milk_tea/tooling/views/stdlib.erb +21 -0
- data/lib/milk_tea/tooling.rb +20 -0
- data/lib/milk_tea.rb +8 -0
- metadata +426 -0
|
@@ -0,0 +1,598 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MilkTea
|
|
4
|
+
module LSP
|
|
5
|
+
class Server
|
|
6
|
+
module ServerRename
|
|
7
|
+
private
|
|
8
|
+
|
|
9
|
+
def handle_prepare_rename(params)
|
|
10
|
+
uri = params['textDocument']['uri']
|
|
11
|
+
lsp_line = params['position']['line']
|
|
12
|
+
lsp_char = params['position']['character']
|
|
13
|
+
|
|
14
|
+
token = @workspace.find_token_at(uri, lsp_line, lsp_char)
|
|
15
|
+
return nil unless name_like_token?(token)
|
|
16
|
+
|
|
17
|
+
{ range: token_to_range(token), placeholder: token.lexeme }
|
|
18
|
+
rescue StandardError => e
|
|
19
|
+
warn "Error in prepareRename handler: #{e.message}"
|
|
20
|
+
nil
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def name_like_token?(tok)
|
|
24
|
+
return false if tok.nil?
|
|
25
|
+
tok.type == :identifier || Token::KEYWORDS.value?(tok.type)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def allow_hover_last_good_fallback?(uri)
|
|
29
|
+
return true unless @workspace.dependency_resolution_mode == :frozen
|
|
30
|
+
|
|
31
|
+
path = uri_to_path(uri)
|
|
32
|
+
return true unless path && File.file?(path)
|
|
33
|
+
|
|
34
|
+
DependencyResolution.resolve(path, mode: @workspace.dependency_resolution_mode).ok?
|
|
35
|
+
rescue StandardError
|
|
36
|
+
true
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def handle_rename(params)
|
|
40
|
+
uri = params['textDocument']['uri']
|
|
41
|
+
lsp_line = params['position']['line']
|
|
42
|
+
lsp_char = params['position']['character']
|
|
43
|
+
new_name = params['newName'].to_s
|
|
44
|
+
|
|
45
|
+
token = @workspace.find_token_at(uri, lsp_line, lsp_char)
|
|
46
|
+
return nil unless name_like_token?(token)
|
|
47
|
+
|
|
48
|
+
import_alias_changes = import_alias_rename_changes(uri, token, lsp_line, lsp_char, nil, new_name)
|
|
49
|
+
return { changes: import_alias_changes } if import_alias_changes
|
|
50
|
+
|
|
51
|
+
if (facts = @workspace.get_facts(uri))
|
|
52
|
+
sc = struct_field_rename_changes(uri, token, lsp_line, lsp_char, facts, new_name)
|
|
53
|
+
return { changes: sc } if sc && !sc.empty?
|
|
54
|
+
|
|
55
|
+
mc = method_rename_changes(uri, token, lsp_line, lsp_char, facts, new_name)
|
|
56
|
+
return { changes: mc } if mc && !mc.empty?
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
enum_member_changes = enum_member_rename_changes(uri, token, lsp_line, lsp_char, nil, new_name)
|
|
60
|
+
return { changes: enum_member_changes } if enum_member_changes
|
|
61
|
+
|
|
62
|
+
if (facts = @workspace.get_facts(uri))
|
|
63
|
+
scoped_changes = scoped_rename_changes(uri, token, lsp_line, lsp_char, facts, new_name)
|
|
64
|
+
return { changes: scoped_changes } if scoped_changes
|
|
65
|
+
|
|
66
|
+
enum_member_changes = enum_member_rename_changes(uri, token, lsp_line, lsp_char, facts, new_name)
|
|
67
|
+
return { changes: enum_member_changes } if enum_member_changes
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
workspace_symbol_changes = workspace_symbol_identity_rename_changes(uri, token, lsp_line, lsp_char, new_name)
|
|
71
|
+
return { changes: workspace_symbol_changes } if workspace_symbol_changes
|
|
72
|
+
|
|
73
|
+
if (facts = @workspace.get_facts(uri))
|
|
74
|
+
module_symbol_changes = module_level_symbol_rename_changes(uri, token, lsp_line, lsp_char, facts, new_name)
|
|
75
|
+
return { changes: module_symbol_changes } if module_symbol_changes
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
lexical_changes = lexical_rename_changes_in_document(uri, token.lexeme, new_name)
|
|
79
|
+
return { changes: lexical_changes } if lexical_changes
|
|
80
|
+
|
|
81
|
+
nil
|
|
82
|
+
rescue StandardError => e
|
|
83
|
+
warn "Error in rename handler: #{e.message}"
|
|
84
|
+
nil
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def lexical_rename_changes_in_document(uri, name, new_name)
|
|
88
|
+
tokens = @workspace.get_tokens(uri) || []
|
|
89
|
+
edits = tokens.flat_map do |tok|
|
|
90
|
+
result = []
|
|
91
|
+
|
|
92
|
+
if tok.type == :fstring && tok.literal.is_a?(Array)
|
|
93
|
+
tok.literal.each do |part|
|
|
94
|
+
next unless part.is_a?(Hash) && part[:kind] == :expr
|
|
95
|
+
next unless part[:line] && part[:column]
|
|
96
|
+
|
|
97
|
+
expr_tokens = MilkTea::Lexer.lex(part[:source], path: uri_to_path(uri))
|
|
98
|
+
expr_tokens.each do |etok|
|
|
99
|
+
next unless name_like_token?(etok) && etok.lexeme == name
|
|
100
|
+
|
|
101
|
+
result << {
|
|
102
|
+
range: {
|
|
103
|
+
start: { line: part[:line] - 1, character: part[:column] + etok.column - 2 },
|
|
104
|
+
end: { line: part[:line] - 1, character: part[:column] + etok.column - 2 + etok.lexeme.length },
|
|
105
|
+
},
|
|
106
|
+
newText: new_name,
|
|
107
|
+
}
|
|
108
|
+
end
|
|
109
|
+
rescue MilkTea::LexError
|
|
110
|
+
nil
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
if name_like_token?(tok) && tok.lexeme == name
|
|
115
|
+
result << { range: token_to_range(tok), newText: new_name }
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
result
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
return nil if edits.empty?
|
|
122
|
+
|
|
123
|
+
{ uri => edits }
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def workspace_symbol_identity_rename_changes(uri, token, lsp_line, lsp_char, new_name)
|
|
127
|
+
target_location = resolve_definition_location({
|
|
128
|
+
'textDocument' => { 'uri' => uri },
|
|
129
|
+
'position' => { 'line' => lsp_line, 'character' => lsp_char },
|
|
130
|
+
}, stages: nil)
|
|
131
|
+
return nil unless target_location
|
|
132
|
+
|
|
133
|
+
target_identity = definition_identity_key(target_location)
|
|
134
|
+
return nil unless target_identity
|
|
135
|
+
|
|
136
|
+
related_uris = @workspace.related_open_document_uris(uri)
|
|
137
|
+
return nil if related_uris.empty?
|
|
138
|
+
|
|
139
|
+
changes = {}
|
|
140
|
+
related_uris.each do |related_uri|
|
|
141
|
+
tokens = @workspace.get_tokens(related_uri) || []
|
|
142
|
+
next if tokens.empty?
|
|
143
|
+
|
|
144
|
+
edits = tokens.filter_map do |candidate|
|
|
145
|
+
next unless name_like_token?(candidate) && candidate.lexeme == token.lexeme
|
|
146
|
+
|
|
147
|
+
candidate_location = resolve_definition_location({
|
|
148
|
+
'textDocument' => { 'uri' => related_uri },
|
|
149
|
+
'position' => { 'line' => candidate.line - 1, 'character' => candidate.column - 1 },
|
|
150
|
+
}, stages: nil)
|
|
151
|
+
next unless candidate_location
|
|
152
|
+
next unless definition_identity_key(candidate_location) == target_identity
|
|
153
|
+
|
|
154
|
+
{
|
|
155
|
+
range: token_to_range(candidate),
|
|
156
|
+
newText: new_name,
|
|
157
|
+
}
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
changes[related_uri] = edits unless edits.empty?
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
return nil if changes.empty?
|
|
164
|
+
|
|
165
|
+
changes
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def definition_identity_key(location)
|
|
169
|
+
uri = location[:uri] || location['uri']
|
|
170
|
+
range = location[:range] || location['range']
|
|
171
|
+
return nil unless uri && range
|
|
172
|
+
|
|
173
|
+
start = range[:start] || range['start']
|
|
174
|
+
return nil unless start
|
|
175
|
+
|
|
176
|
+
line = start[:line] || start['line']
|
|
177
|
+
character = start[:character] || start['character']
|
|
178
|
+
return nil if line.nil? || character.nil?
|
|
179
|
+
|
|
180
|
+
[uri, line, character]
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def scoped_rename_changes(uri, token, lsp_line, lsp_char, facts, new_name)
|
|
184
|
+
binding_id = rename_target_binding_id(uri, token, lsp_line, lsp_char, facts)
|
|
185
|
+
unless binding_id
|
|
186
|
+
return import_alias_rename_changes(uri, token, lsp_line, lsp_char, facts, new_name)
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
ranges = scoped_binding_occurrence_ranges(uri, token.lexeme, facts, binding_id, include_declaration: true)
|
|
190
|
+
return nil if ranges.empty?
|
|
191
|
+
|
|
192
|
+
edits = ranges.map do |range|
|
|
193
|
+
{
|
|
194
|
+
range: {
|
|
195
|
+
start: { line: range[:line] - 1, character: range[:column] - 1 },
|
|
196
|
+
end: { line: range[:line] - 1, character: range[:column] - 1 + range[:length] },
|
|
197
|
+
},
|
|
198
|
+
newText: new_name,
|
|
199
|
+
}
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
{ uri => edits }
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def module_level_symbol_rename_changes(uri, token, lsp_line, lsp_char, facts, new_name)
|
|
206
|
+
name = token.lexeme
|
|
207
|
+
module_level = facts.functions.key?(name) || facts.values.key?(name) || facts.types.key?(name) || facts.interfaces&.key?(name)
|
|
208
|
+
return nil unless module_level
|
|
209
|
+
|
|
210
|
+
related_uris = @workspace.related_open_document_uris(uri)
|
|
211
|
+
changes = {}
|
|
212
|
+
[uri, *related_uris].uniq.each do |doc_uri|
|
|
213
|
+
edits = []
|
|
214
|
+
doc_tokens = @workspace.get_tokens(doc_uri) || []
|
|
215
|
+
doc_tokens.each do |tok|
|
|
216
|
+
next unless tok.type == :identifier && tok.lexeme == name
|
|
217
|
+
edits << { range: token_to_range(tok), newText: new_name }
|
|
218
|
+
end
|
|
219
|
+
changes[doc_uri] = edits unless edits.empty?
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
return nil if changes.empty?
|
|
223
|
+
changes
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
def import_alias_rename_changes(uri, token, lsp_line, lsp_char, facts, new_name)
|
|
227
|
+
alias_name = token.lexeme
|
|
228
|
+
if facts
|
|
229
|
+
return nil unless facts.imports.key?(alias_name)
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
ast = @workspace.get_ast(uri)
|
|
233
|
+
return nil unless ast
|
|
234
|
+
|
|
235
|
+
import_node = ast.imports.find do |imp|
|
|
236
|
+
(imp.alias_name || imp.path.parts.last) == alias_name
|
|
237
|
+
end
|
|
238
|
+
return nil unless import_node
|
|
239
|
+
|
|
240
|
+
# Validate the cursor is at the declaration site or a module-qualifier usage (alias followed by dot).
|
|
241
|
+
tokens = @workspace.get_tokens(uri) || []
|
|
242
|
+
|
|
243
|
+
cursor_at_declaration = token.line == import_node.line && token.column == import_node.column
|
|
244
|
+
unless cursor_at_declaration
|
|
245
|
+
# token was already located by find_token_at; verify it's used as a module qualifier
|
|
246
|
+
tok_idx = tokens.index { |t| t.line == token.line && t.column == token.column }
|
|
247
|
+
return nil unless tok_idx && tokens[tok_idx + 1]&.type == :dot
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
edits = []
|
|
251
|
+
|
|
252
|
+
# Declaration site
|
|
253
|
+
decl_char = import_node.column - 1
|
|
254
|
+
edits << {
|
|
255
|
+
range: {
|
|
256
|
+
start: { line: import_node.line - 1, character: decl_char },
|
|
257
|
+
end: { line: import_node.line - 1, character: decl_char + alias_name.length },
|
|
258
|
+
},
|
|
259
|
+
newText: new_name,
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
# Usage sites: every token with this lexeme immediately followed by a dot
|
|
263
|
+
tokens.each_with_index do |tok, i|
|
|
264
|
+
next unless tok.type == :identifier && tok.lexeme == alias_name
|
|
265
|
+
next unless tokens[i + 1]&.type == :dot
|
|
266
|
+
|
|
267
|
+
edits << {
|
|
268
|
+
range: {
|
|
269
|
+
start: { line: tok.line - 1, character: tok.column - 1 },
|
|
270
|
+
end: { line: tok.line - 1, character: tok.column - 1 + alias_name.length },
|
|
271
|
+
},
|
|
272
|
+
newText: new_name,
|
|
273
|
+
}
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
{ uri => edits }
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
def enum_member_rename_changes(uri, token, lsp_line, lsp_char, facts, new_name)
|
|
280
|
+
tokens = @workspace.get_tokens(uri) || []
|
|
281
|
+
|
|
282
|
+
cursor_index = tokens.index { |t| t.line == token.line && t.column == token.column }
|
|
283
|
+
return nil unless cursor_index
|
|
284
|
+
|
|
285
|
+
cursor_is_enum_member = variant_enum_member_declaration?(tokens, cursor_index) ||
|
|
286
|
+
type_name_member_access?(tokens, cursor_index, facts)
|
|
287
|
+
return nil unless cursor_is_enum_member
|
|
288
|
+
|
|
289
|
+
edits = tokens.each_with_index.filter_map do |tok, i|
|
|
290
|
+
next unless tok.type == :identifier && tok.lexeme == token.lexeme
|
|
291
|
+
|
|
292
|
+
enum_member_decl = variant_enum_member_declaration?(tokens, i)
|
|
293
|
+
enum_member_access = type_name_member_access?(tokens, i, facts)
|
|
294
|
+
next unless enum_member_decl || enum_member_access
|
|
295
|
+
|
|
296
|
+
{
|
|
297
|
+
range: token_to_range(tok),
|
|
298
|
+
newText: new_name,
|
|
299
|
+
}
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
return nil if edits.empty?
|
|
303
|
+
|
|
304
|
+
{ uri => edits }
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
def scoped_local_reference_locations(uri, token, lsp_line, lsp_char, facts, include_declaration:)
|
|
308
|
+
binding_id = rename_target_binding_id(uri, token, lsp_line, lsp_char, facts)
|
|
309
|
+
return nil unless binding_id
|
|
310
|
+
return nil unless local_binding_id?(uri, facts, binding_id)
|
|
311
|
+
|
|
312
|
+
ranges = scoped_binding_occurrence_ranges(uri, token.lexeme, facts, binding_id, include_declaration: include_declaration)
|
|
313
|
+
ranges.map do |range|
|
|
314
|
+
{
|
|
315
|
+
uri: uri,
|
|
316
|
+
range: {
|
|
317
|
+
start: { line: range[:line] - 1, character: range[:column] - 1 },
|
|
318
|
+
end: { line: range[:line] - 1, character: range[:column] - 1 + range[:length] },
|
|
319
|
+
},
|
|
320
|
+
}
|
|
321
|
+
end
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
def local_binding_id?(uri, facts, binding_id)
|
|
325
|
+
ast = @workspace.get_ast(uri)
|
|
326
|
+
return false unless ast
|
|
327
|
+
|
|
328
|
+
resolution = facts.binding_resolution
|
|
329
|
+
return false unless resolution
|
|
330
|
+
|
|
331
|
+
each_ast_node(ast) do |node|
|
|
332
|
+
next unless local_binding_declaration_node?(node)
|
|
333
|
+
next unless resolution.declaration_binding_ids[node.object_id] == binding_id
|
|
334
|
+
|
|
335
|
+
return true
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
false
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
def local_binding_declaration_node?(node)
|
|
342
|
+
node.is_a?(AST::LocalDecl) ||
|
|
343
|
+
node.is_a?(AST::Param) ||
|
|
344
|
+
node.is_a?(AST::ForBinding) ||
|
|
345
|
+
node.is_a?(AST::MatchArm) ||
|
|
346
|
+
node.is_a?(AST::MatchExprArm)
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
def rename_target_binding_id(uri, token, lsp_line, lsp_char, facts)
|
|
350
|
+
resolution = facts.binding_resolution
|
|
351
|
+
return nil unless resolution
|
|
352
|
+
|
|
353
|
+
line = lsp_line + 1
|
|
354
|
+
char = lsp_char + 1
|
|
355
|
+
ast = @workspace.get_ast(uri)
|
|
356
|
+
return nil unless ast
|
|
357
|
+
|
|
358
|
+
identifier_node = find_identifier_ast_node_at(ast, token.lexeme, line, char)
|
|
359
|
+
if identifier_node && (id = resolution.identifier_binding_ids[identifier_node.object_id])
|
|
360
|
+
return id
|
|
361
|
+
end
|
|
362
|
+
|
|
363
|
+
declaration_node = find_declaration_ast_node_at(ast, token.lexeme, line, char)
|
|
364
|
+
if declaration_node && (id = resolution.declaration_binding_ids[declaration_node.object_id])
|
|
365
|
+
return id
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
resolve_local_hover_binding(facts, token.lexeme, line, char)&.id
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
def scoped_binding_occurrence_ranges(uri, name, facts, binding_id, include_declaration:)
|
|
372
|
+
ast = @workspace.get_ast(uri)
|
|
373
|
+
return [] unless ast
|
|
374
|
+
|
|
375
|
+
resolution = facts.binding_resolution
|
|
376
|
+
return [] unless resolution
|
|
377
|
+
|
|
378
|
+
ranges = []
|
|
379
|
+
seen = Set.new
|
|
380
|
+
|
|
381
|
+
each_ast_node(ast) do |node|
|
|
382
|
+
range = nil
|
|
383
|
+
|
|
384
|
+
if node.is_a?(AST::Identifier) && node.name == name && resolution.identifier_binding_ids[node.object_id] == binding_id
|
|
385
|
+
range = ast_name_range(node.name, node.line, node.column)
|
|
386
|
+
elsif include_declaration && resolution.declaration_binding_ids[node.object_id] == binding_id
|
|
387
|
+
range = declaration_name_range(node)
|
|
388
|
+
end
|
|
389
|
+
|
|
390
|
+
next unless range
|
|
391
|
+
|
|
392
|
+
key = [range[:line], range[:column], range[:length]]
|
|
393
|
+
next if seen.include?(key)
|
|
394
|
+
|
|
395
|
+
seen << key
|
|
396
|
+
ranges << range
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
ranges
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
def find_identifier_ast_node_at(ast, name, line, char)
|
|
403
|
+
each_ast_node(ast) do |node|
|
|
404
|
+
next unless node.is_a?(AST::Identifier)
|
|
405
|
+
next unless node.name == name
|
|
406
|
+
next unless node.line == line
|
|
407
|
+
next unless char >= node.column && char < node.column + name.length
|
|
408
|
+
|
|
409
|
+
return node
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
nil
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
def find_declaration_ast_node_at(ast, name, line, char)
|
|
416
|
+
each_ast_node(ast) do |node|
|
|
417
|
+
range = declaration_name_range(node)
|
|
418
|
+
next unless range
|
|
419
|
+
next unless range[:name] == name
|
|
420
|
+
next unless range[:line] == line
|
|
421
|
+
next unless char >= range[:column] && char < range[:column] + range[:length]
|
|
422
|
+
|
|
423
|
+
return node
|
|
424
|
+
end
|
|
425
|
+
|
|
426
|
+
nil
|
|
427
|
+
end
|
|
428
|
+
|
|
429
|
+
def declaration_name_range(node)
|
|
430
|
+
if node.is_a?(AST::MatchArm) || node.is_a?(AST::MatchExprArm)
|
|
431
|
+
return nil unless node.binding_name && node.binding_line && node.binding_column
|
|
432
|
+
|
|
433
|
+
return {
|
|
434
|
+
name: node.binding_name,
|
|
435
|
+
line: node.binding_line,
|
|
436
|
+
column: node.binding_column,
|
|
437
|
+
length: node.binding_name.length,
|
|
438
|
+
}
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
return nil if node.is_a?(AST::ForStmt)
|
|
442
|
+
return nil unless node.respond_to?(:name) && node.respond_to?(:line) && node.respond_to?(:column)
|
|
443
|
+
return nil unless node.name.is_a?(String) && node.line && node.column
|
|
444
|
+
|
|
445
|
+
ast_name_range(node.name, node.line, node.column)
|
|
446
|
+
end
|
|
447
|
+
|
|
448
|
+
def ast_name_range(name, line, column)
|
|
449
|
+
{ name: name, line: line, column: column, length: name.length }
|
|
450
|
+
end
|
|
451
|
+
|
|
452
|
+
def each_ast_node(node, &block)
|
|
453
|
+
return if node.nil?
|
|
454
|
+
|
|
455
|
+
if node.is_a?(Array)
|
|
456
|
+
node.each { |item| each_ast_node(item, &block) }
|
|
457
|
+
return
|
|
458
|
+
end
|
|
459
|
+
|
|
460
|
+
class_name = node.class.name
|
|
461
|
+
return unless class_name && class_name.start_with?('MilkTea::AST::')
|
|
462
|
+
|
|
463
|
+
yield node
|
|
464
|
+
|
|
465
|
+
if node.respond_to?(:members)
|
|
466
|
+
node.members.each do |member|
|
|
467
|
+
next unless member.is_a?(Symbol)
|
|
468
|
+
each_ast_node(node.public_send(member), &block)
|
|
469
|
+
end
|
|
470
|
+
end
|
|
471
|
+
end
|
|
472
|
+
|
|
473
|
+
def struct_field_rename_changes(uri, token, _lsp_line, _lsp_char, facts, new_name)
|
|
474
|
+
field_name = token.lexeme
|
|
475
|
+
tokens = @workspace.get_tokens(uri) || []
|
|
476
|
+
idx = tokens.index { |t| t.line == token.line && t.column == token.column }
|
|
477
|
+
return nil unless idx
|
|
478
|
+
|
|
479
|
+
cursor_in_field_context = struct_field_cursor_context?(tokens, idx)
|
|
480
|
+
return nil unless cursor_in_field_context
|
|
481
|
+
|
|
482
|
+
struct_type = find_struct_containing_field(facts, field_name)
|
|
483
|
+
return nil unless struct_type
|
|
484
|
+
|
|
485
|
+
edits = []
|
|
486
|
+
tokens.each_with_index do |tok, i|
|
|
487
|
+
next unless tok.type == :identifier && tok.lexeme == field_name
|
|
488
|
+
next unless struct_field_edit_context?(tokens, i, struct_type)
|
|
489
|
+
|
|
490
|
+
edits << { range: token_to_range(tok), newText: new_name }
|
|
491
|
+
end
|
|
492
|
+
|
|
493
|
+
return nil if edits.empty?
|
|
494
|
+
{ uri => edits }
|
|
495
|
+
end
|
|
496
|
+
|
|
497
|
+
def struct_field_cursor_context?(tokens, index)
|
|
498
|
+
next_nt = skip_trivia_forward(tokens, index + 1)
|
|
499
|
+
return true if next_nt && tokens[next_nt]&.type == :colon
|
|
500
|
+
|
|
501
|
+
return true if index > 0 && tokens[index - 1].type == :dot
|
|
502
|
+
|
|
503
|
+
if index > 0 && (tokens[index - 1].type == :lparen || tokens[index - 1].type == :comma)
|
|
504
|
+
next_nt = skip_trivia_forward(tokens, index + 1)
|
|
505
|
+
return true if next_nt && (tokens[next_nt]&.type == :equal || tokens[next_nt]&.type == :colon)
|
|
506
|
+
return true if next_nt.nil? || !(tokens[next_nt]&.type == :equal || tokens[next_nt]&.type == :colon)
|
|
507
|
+
end
|
|
508
|
+
|
|
509
|
+
false
|
|
510
|
+
end
|
|
511
|
+
|
|
512
|
+
def struct_field_edit_context?(tokens, index, _struct_type)
|
|
513
|
+
return true if index > 0 && tokens[index - 1].type == :dot
|
|
514
|
+
|
|
515
|
+
next_nt = skip_trivia_forward(tokens, index + 1)
|
|
516
|
+
return true if next_nt && tokens[next_nt]&.type == :colon
|
|
517
|
+
|
|
518
|
+
if index > 0 && (tokens[index - 1].type == :lparen || tokens[index - 1].type == :comma)
|
|
519
|
+
next_nt = skip_trivia_forward(tokens, index + 1)
|
|
520
|
+
return true if next_nt.nil? || (tokens[next_nt]&.type == :equal || tokens[next_nt]&.type == :colon) || tokens[next_nt]&.type == :comma || tokens[next_nt]&.type == :rparen
|
|
521
|
+
end
|
|
522
|
+
|
|
523
|
+
false
|
|
524
|
+
end
|
|
525
|
+
|
|
526
|
+
def skip_trivia_forward(tokens, start_index)
|
|
527
|
+
i = start_index
|
|
528
|
+
while i < tokens.length
|
|
529
|
+
return i unless tokens[i].type == :whitespace || tokens[i].type == :newline || tokens[i].type == :comment
|
|
530
|
+
i += 1
|
|
531
|
+
end
|
|
532
|
+
nil
|
|
533
|
+
end
|
|
534
|
+
|
|
535
|
+
def find_struct_containing_field(facts, field_name)
|
|
536
|
+
facts.types.each_value do |type|
|
|
537
|
+
target = if type.is_a?(Types::GenericStructDefinition)
|
|
538
|
+
type
|
|
539
|
+
elsif type.is_a?(Types::Struct) || type.is_a?(Types::StructInstance)
|
|
540
|
+
type.is_a?(Types::StructInstance) ? type.definition : type
|
|
541
|
+
else
|
|
542
|
+
next
|
|
543
|
+
end
|
|
544
|
+
next unless target.respond_to?(:fields) && target.fields.key?(field_name)
|
|
545
|
+
return type
|
|
546
|
+
end
|
|
547
|
+
nil
|
|
548
|
+
end
|
|
549
|
+
|
|
550
|
+
def method_rename_changes(uri, token, _lsp_line, _lsp_char, facts, new_name)
|
|
551
|
+
method_name = token.lexeme
|
|
552
|
+
method_info = find_method_at_position(uri, token, facts)
|
|
553
|
+
return nil unless method_info
|
|
554
|
+
|
|
555
|
+
receiver_type = method_info[:receiver_type]
|
|
556
|
+
return nil unless receiver_type
|
|
557
|
+
|
|
558
|
+
edits = []
|
|
559
|
+
doc_tokens = @workspace.get_tokens(uri) || []
|
|
560
|
+
doc_tokens.each_with_index do |tok, i|
|
|
561
|
+
next unless tok.type == :identifier && tok.lexeme == method_name
|
|
562
|
+
next unless i > 0 && doc_tokens[i - 1].type == :dot
|
|
563
|
+
|
|
564
|
+
edits << { range: token_to_range(tok), newText: new_name }
|
|
565
|
+
end
|
|
566
|
+
|
|
567
|
+
return nil if edits.empty?
|
|
568
|
+
{ uri => edits }
|
|
569
|
+
end
|
|
570
|
+
|
|
571
|
+
def find_method_at_position(uri, token, facts)
|
|
572
|
+
ast = @workspace.get_ast(uri)
|
|
573
|
+
return nil unless ast
|
|
574
|
+
|
|
575
|
+
each_ast_node(ast) do |node|
|
|
576
|
+
next unless node.is_a?(AST::MethodDef)
|
|
577
|
+
next unless node.line == token.line
|
|
578
|
+
next unless token.column >= node.column && token.column < node.column + node.name.length
|
|
579
|
+
|
|
580
|
+
type_name = find_extending_type_for_method(ast, node)
|
|
581
|
+
next unless type_name
|
|
582
|
+
|
|
583
|
+
{ receiver_type: facts.types[type_name], method_name: node.name }
|
|
584
|
+
end
|
|
585
|
+
nil
|
|
586
|
+
end
|
|
587
|
+
|
|
588
|
+
def find_extending_type_for_method(ast, method_node)
|
|
589
|
+
each_ast_node(ast) do |node|
|
|
590
|
+
next unless node.is_a?(AST::ExtendingBlock)
|
|
591
|
+
return node.type_name if node.methods.any? { |m| m.object_id == method_node.object_id }
|
|
592
|
+
end
|
|
593
|
+
nil
|
|
594
|
+
end
|
|
595
|
+
end
|
|
596
|
+
end
|
|
597
|
+
end
|
|
598
|
+
end
|