hind 0.1.6 → 0.1.8
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 +4 -4
- data/lib/hind/cli.rb +43 -161
- data/lib/hind/lsif/generator.rb +96 -82
- data/lib/hind/lsif/global_state.rb +4 -81
- data/lib/hind/lsif/visitors/declaration_visitor.rb +0 -170
- data/lib/hind/lsif/visitors/reference_visitor.rb +0 -159
- data/lib/hind/lsif.rb +0 -1
- data/lib/hind/version.rb +1 -1
- metadata +1 -2
- data/lib/hind/lsif/visitor.rb +0 -255
@@ -13,10 +13,6 @@ module Hind
|
|
13
13
|
@result_sets = {} # {qualified_name => result_set_id}
|
14
14
|
@ranges = {} # {file_path => [range_ids]}
|
15
15
|
@project_id = nil
|
16
|
-
|
17
|
-
# Method visibility tracking
|
18
|
-
@visibility_stack = [] # Stack of method visibility states per scope
|
19
|
-
@current_visibility = :public
|
20
16
|
end
|
21
17
|
|
22
18
|
def add_declaration(qualified_name, data)
|
@@ -24,12 +20,12 @@ module Hind
|
|
24
20
|
@result_sets[qualified_name] = data[:result_set_id] if data[:result_set_id]
|
25
21
|
end
|
26
22
|
|
27
|
-
def add_reference(qualified_name, file_path, range_id,
|
23
|
+
def add_reference(qualified_name, file_path, range_id, document_id)
|
28
24
|
@references[qualified_name] ||= []
|
29
25
|
@references[qualified_name] << {
|
30
26
|
file: file_path,
|
31
27
|
range_id: range_id,
|
32
|
-
|
28
|
+
document_id: document_id
|
33
29
|
}
|
34
30
|
end
|
35
31
|
|
@@ -58,98 +54,31 @@ module Hind
|
|
58
54
|
@ranges[file_path] || []
|
59
55
|
end
|
60
56
|
|
61
|
-
def push_visibility_scope(visibility = :public)
|
62
|
-
@visibility_stack.push(@current_visibility)
|
63
|
-
@current_visibility = visibility
|
64
|
-
end
|
65
|
-
|
66
|
-
def pop_visibility_scope
|
67
|
-
@current_visibility = @visibility_stack.pop || :public
|
68
|
-
end
|
69
|
-
|
70
|
-
def current_visibility
|
71
|
-
@current_visibility
|
72
|
-
end
|
73
|
-
|
74
|
-
def get_declaration_in_scope(name, scope)
|
75
|
-
# Try exact scope first
|
76
|
-
qualified_name = scope.empty? ? name : "#{scope}::#{name}"
|
77
|
-
return qualified_name if has_declaration?(qualified_name)
|
78
|
-
|
79
|
-
# Try parent scopes
|
80
|
-
scope_parts = scope.split('::')
|
81
|
-
while scope_parts.any?
|
82
|
-
scope_parts.pop
|
83
|
-
qualified_name = scope_parts.empty? ? name : "#{scope_parts.join('::')}::#{name}"
|
84
|
-
return qualified_name if has_declaration?(qualified_name)
|
85
|
-
end
|
86
|
-
|
87
|
-
# Try top level
|
88
|
-
has_declaration?(name) ? name : nil
|
89
|
-
end
|
90
|
-
|
91
|
-
def get_method_declaration(method_name, scope, instance_method = true)
|
92
|
-
separator = instance_method ? '#' : '.'
|
93
|
-
qualified_name = scope.empty? ? method_name : "#{scope}#{separator}#{method_name}"
|
94
|
-
|
95
|
-
return qualified_name if has_declaration?(qualified_name)
|
96
|
-
|
97
|
-
# For instance methods, try to find in superclass chain
|
98
|
-
if instance_method && !scope.empty?
|
99
|
-
current_scope = scope
|
100
|
-
while (class_data = @declarations[current_scope])
|
101
|
-
break unless class_data[:type] == :class && class_data[:superclass]
|
102
|
-
|
103
|
-
superclass = class_data[:superclass]
|
104
|
-
superclass_method = "#{superclass}#{separator}#{method_name}"
|
105
|
-
return superclass_method if has_declaration?(superclass_method)
|
106
|
-
|
107
|
-
current_scope = superclass
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
nil
|
112
|
-
end
|
113
|
-
|
114
57
|
def find_constant_declaration(name, current_scope)
|
115
58
|
return name if has_declaration?(name)
|
116
59
|
|
117
|
-
# Try with current scope
|
118
60
|
if current_scope && !current_scope.empty?
|
119
61
|
qualified_name = "#{current_scope}::#{name}"
|
120
62
|
return qualified_name if has_declaration?(qualified_name)
|
121
63
|
|
122
|
-
# Try parent scopes
|
123
64
|
scope_parts = current_scope.split('::')
|
124
65
|
while scope_parts.any?
|
125
66
|
scope_parts.pop
|
126
|
-
qualified_name = scope_parts.empty? ? name : "#{scope_parts.join(
|
67
|
+
qualified_name = scope_parts.empty? ? name : "#{scope_parts.join("::")}::#{name}"
|
127
68
|
return qualified_name if has_declaration?(qualified_name)
|
128
69
|
end
|
129
70
|
end
|
130
71
|
|
131
|
-
# Try top level
|
132
72
|
has_declaration?(name) ? name : nil
|
133
73
|
end
|
134
74
|
|
135
|
-
def get_instance_variable_scope(var_name, current_scope)
|
136
|
-
return nil unless current_scope
|
137
|
-
"#{current_scope}##{var_name}"
|
138
|
-
end
|
139
|
-
|
140
|
-
def get_class_variable_scope(var_name, current_scope)
|
141
|
-
return nil unless current_scope
|
142
|
-
"#{current_scope}::#{var_name}"
|
143
|
-
end
|
144
|
-
|
145
75
|
def debug_info
|
146
76
|
{
|
147
77
|
declarations_count: @declarations.size,
|
148
78
|
references_count: @references.values.sum(&:size),
|
149
79
|
result_sets_count: @result_sets.size,
|
150
80
|
ranges_count: @ranges.values.sum(&:size),
|
151
|
-
declaration_types: declaration_types_count
|
152
|
-
reference_types: reference_types_count
|
81
|
+
declaration_types: declaration_types_count
|
153
82
|
}
|
154
83
|
end
|
155
84
|
|
@@ -160,12 +89,6 @@ module Hind
|
|
160
89
|
counts[decl[:type]] += 1
|
161
90
|
end
|
162
91
|
end
|
163
|
-
|
164
|
-
def reference_types_count
|
165
|
-
@references.values.flatten.each_with_object(Hash.new(0)) do |ref, counts|
|
166
|
-
counts[ref[:type]] += 1
|
167
|
-
end
|
168
|
-
end
|
169
92
|
end
|
170
93
|
end
|
171
94
|
end
|
@@ -10,16 +10,12 @@ module Hind
|
|
10
10
|
@generator = generator
|
11
11
|
@file_path = file_path
|
12
12
|
@current_scope = []
|
13
|
-
@current_visibility = :public
|
14
|
-
@visibility_stack = []
|
15
|
-
@in_singleton_class = false
|
16
13
|
end
|
17
14
|
|
18
15
|
def visit_class_node(node)
|
19
16
|
@current_scope.push(node.constant_path.slice)
|
20
17
|
class_name = current_scope_name
|
21
18
|
|
22
|
-
# Register class declaration
|
23
19
|
@generator.register_declaration({
|
24
20
|
type: :class,
|
25
21
|
name: class_name,
|
@@ -28,10 +24,7 @@ module Hind
|
|
28
24
|
superclass: node.superclass&.slice
|
29
25
|
})
|
30
26
|
|
31
|
-
# Process the class body with proper scope and visibility
|
32
|
-
push_visibility(:public)
|
33
27
|
super
|
34
|
-
pop_visibility
|
35
28
|
@current_scope.pop
|
36
29
|
end
|
37
30
|
|
@@ -46,32 +39,10 @@ module Hind
|
|
46
39
|
scope: @current_scope[0..-2].join('::')
|
47
40
|
})
|
48
41
|
|
49
|
-
push_visibility(:public)
|
50
42
|
super
|
51
|
-
pop_visibility
|
52
43
|
@current_scope.pop
|
53
44
|
end
|
54
45
|
|
55
|
-
def visit_def_node(node)
|
56
|
-
method_name = node.name.to_s
|
57
|
-
# Use '#' for instance methods
|
58
|
-
qualified_name = @in_singleton_class ?
|
59
|
-
"#{current_scope_name}.#{method_name}" :
|
60
|
-
"#{current_scope_name}##{method_name}"
|
61
|
-
|
62
|
-
@generator.register_declaration({
|
63
|
-
type: :method,
|
64
|
-
name: qualified_name,
|
65
|
-
node: node,
|
66
|
-
scope: current_scope_name,
|
67
|
-
visibility: current_visibility,
|
68
|
-
params: node.parameters&.slice,
|
69
|
-
instance_method: !@in_singleton_class
|
70
|
-
})
|
71
|
-
|
72
|
-
super
|
73
|
-
end
|
74
|
-
|
75
46
|
def visit_constant_write_node(node)
|
76
47
|
return unless node.name
|
77
48
|
|
@@ -88,152 +59,11 @@ module Hind
|
|
88
59
|
super
|
89
60
|
end
|
90
61
|
|
91
|
-
def visit_singleton_class_node(node)
|
92
|
-
if node.expression.is_a?(Prism::SelfNode)
|
93
|
-
# class << self
|
94
|
-
@in_singleton_class = true
|
95
|
-
super
|
96
|
-
@in_singleton_class = false
|
97
|
-
else
|
98
|
-
# Process regular singleton class
|
99
|
-
super
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
def visit_call_node(node)
|
104
|
-
method_name = node.name.to_s
|
105
|
-
case method_name
|
106
|
-
when 'private', 'protected', 'public'
|
107
|
-
handle_visibility_method(node)
|
108
|
-
when 'attr_reader', 'attr_writer', 'attr_accessor'
|
109
|
-
handle_attribute_method(node)
|
110
|
-
end
|
111
|
-
|
112
|
-
super
|
113
|
-
end
|
114
|
-
|
115
|
-
def visit_class_variable_write_node(node)
|
116
|
-
return unless node.name
|
117
|
-
|
118
|
-
var_name = node.name.to_s
|
119
|
-
qualified_name = "#{current_scope_name}::#{var_name}"
|
120
|
-
|
121
|
-
@generator.register_declaration({
|
122
|
-
type: :class_variable,
|
123
|
-
name: qualified_name,
|
124
|
-
node: node,
|
125
|
-
scope: current_scope_name
|
126
|
-
})
|
127
|
-
|
128
|
-
super
|
129
|
-
end
|
130
|
-
|
131
|
-
def visit_instance_variable_write_node(node)
|
132
|
-
return unless node.name && current_scope_name
|
133
|
-
|
134
|
-
var_name = node.name.to_s
|
135
|
-
qualified_name = "#{current_scope_name}##{var_name}"
|
136
|
-
|
137
|
-
@generator.register_declaration({
|
138
|
-
type: :instance_variable,
|
139
|
-
name: qualified_name,
|
140
|
-
node: node,
|
141
|
-
scope: current_scope_name
|
142
|
-
})
|
143
|
-
|
144
|
-
super
|
145
|
-
end
|
146
|
-
|
147
62
|
private
|
148
63
|
|
149
64
|
def current_scope_name
|
150
65
|
@current_scope.join('::')
|
151
66
|
end
|
152
|
-
|
153
|
-
def current_visibility
|
154
|
-
@current_visibility
|
155
|
-
end
|
156
|
-
|
157
|
-
def push_visibility(visibility)
|
158
|
-
@visibility_stack.push(@current_visibility)
|
159
|
-
@current_visibility = visibility
|
160
|
-
end
|
161
|
-
|
162
|
-
def pop_visibility
|
163
|
-
@current_visibility = @visibility_stack.pop || :public
|
164
|
-
end
|
165
|
-
|
166
|
-
def handle_visibility_method(node)
|
167
|
-
visibility = node.name.to_sym
|
168
|
-
|
169
|
-
if node.arguments&.arguments&.empty?
|
170
|
-
# Global visibility change
|
171
|
-
@current_visibility = visibility
|
172
|
-
elsif node.arguments
|
173
|
-
# Per-method visibility change
|
174
|
-
node.arguments.arguments.each do |arg|
|
175
|
-
next unless arg.is_a?(Prism::SymbolNode) || arg.is_a?(Prism::StringNode)
|
176
|
-
|
177
|
-
method_name = arg.value.to_s
|
178
|
-
qualified_name = "#{current_scope_name}##{method_name}"
|
179
|
-
|
180
|
-
if @generator.global_state.has_declaration?(qualified_name)
|
181
|
-
@generator.global_state.get_declaration(qualified_name)[:visibility] = visibility
|
182
|
-
end
|
183
|
-
end
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
|
-
def handle_attribute_method(node)
|
188
|
-
return unless node.arguments
|
189
|
-
|
190
|
-
attr_type = node.name.to_s
|
191
|
-
node.arguments.arguments.each do |arg|
|
192
|
-
next unless arg.respond_to?(:value)
|
193
|
-
|
194
|
-
attr_name = arg.value.to_s
|
195
|
-
register_attribute(attr_name, attr_type)
|
196
|
-
end
|
197
|
-
end
|
198
|
-
|
199
|
-
def register_attribute(attr_name, attr_type)
|
200
|
-
base_name = "#{current_scope_name}##{attr_name}"
|
201
|
-
|
202
|
-
# Register reader method if applicable
|
203
|
-
if %w[attr_reader attr_accessor].include?(attr_type)
|
204
|
-
@generator.register_declaration({
|
205
|
-
type: :method,
|
206
|
-
name: base_name,
|
207
|
-
node: nil, # Synthetic node
|
208
|
-
scope: current_scope_name,
|
209
|
-
visibility: current_visibility,
|
210
|
-
synthetic: true,
|
211
|
-
kind: :reader
|
212
|
-
})
|
213
|
-
end
|
214
|
-
|
215
|
-
# Register writer method if applicable
|
216
|
-
if %w[attr_writer attr_accessor].include?(attr_type)
|
217
|
-
@generator.register_declaration({
|
218
|
-
type: :method,
|
219
|
-
name: "#{base_name}=",
|
220
|
-
node: nil, # Synthetic node
|
221
|
-
scope: current_scope_name,
|
222
|
-
visibility: current_visibility,
|
223
|
-
synthetic: true,
|
224
|
-
kind: :writer
|
225
|
-
})
|
226
|
-
end
|
227
|
-
|
228
|
-
# Register the instance variable
|
229
|
-
@generator.register_declaration({
|
230
|
-
type: :instance_variable,
|
231
|
-
name: "@#{attr_name}",
|
232
|
-
node: nil, # Synthetic node
|
233
|
-
scope: current_scope_name,
|
234
|
-
synthetic: true
|
235
|
-
})
|
236
|
-
end
|
237
67
|
end
|
238
68
|
end
|
239
69
|
end
|
@@ -1,4 +1,3 @@
|
|
1
|
-
# lib/hind/lsif/visitors/reference_visitor.rb
|
2
1
|
# frozen_string_literal: true
|
3
2
|
|
4
3
|
module Hind
|
@@ -12,27 +11,6 @@ module Hind
|
|
12
11
|
@current_scope = []
|
13
12
|
end
|
14
13
|
|
15
|
-
# Method calls
|
16
|
-
def visit_call_node(node)
|
17
|
-
return unless node.name && node.location
|
18
|
-
|
19
|
-
method_name = node.name.to_s
|
20
|
-
qualified_names = generate_qualified_names_for_call(node)
|
21
|
-
|
22
|
-
qualified_names.each do |qualified_name|
|
23
|
-
@generator.register_reference({
|
24
|
-
type: :method,
|
25
|
-
name: qualified_name,
|
26
|
-
node: node,
|
27
|
-
scope: current_scope_name,
|
28
|
-
call_type: :instance_method
|
29
|
-
})
|
30
|
-
end
|
31
|
-
|
32
|
-
super
|
33
|
-
end
|
34
|
-
|
35
|
-
# Class/module references
|
36
14
|
def visit_constant_read_node(node)
|
37
15
|
return unless node.name
|
38
16
|
|
@@ -49,7 +27,6 @@ module Hind
|
|
49
27
|
super
|
50
28
|
end
|
51
29
|
|
52
|
-
# Constant path references (e.g., A::B::C)
|
53
30
|
def visit_constant_path_node(node)
|
54
31
|
qualified_name = node.slice
|
55
32
|
|
@@ -63,87 +40,6 @@ module Hind
|
|
63
40
|
super
|
64
41
|
end
|
65
42
|
|
66
|
-
# Instance variable references
|
67
|
-
def visit_instance_variable_read_node(node)
|
68
|
-
return unless node.name && current_scope_name
|
69
|
-
|
70
|
-
var_name = node.name.to_s
|
71
|
-
qualified_name = "#{current_scope_name}##{var_name}"
|
72
|
-
|
73
|
-
@generator.register_reference({
|
74
|
-
type: :instance_variable,
|
75
|
-
name: qualified_name,
|
76
|
-
node: node,
|
77
|
-
scope: current_scope_name
|
78
|
-
})
|
79
|
-
|
80
|
-
super
|
81
|
-
end
|
82
|
-
|
83
|
-
# Class variable references
|
84
|
-
def visit_class_variable_read_node(node)
|
85
|
-
return unless node.name && current_scope_name
|
86
|
-
|
87
|
-
var_name = node.name.to_s
|
88
|
-
qualified_name = "#{current_scope_name}::#{var_name}"
|
89
|
-
|
90
|
-
@generator.register_reference({
|
91
|
-
type: :class_variable,
|
92
|
-
name: qualified_name,
|
93
|
-
node: node,
|
94
|
-
scope: current_scope_name
|
95
|
-
})
|
96
|
-
|
97
|
-
super
|
98
|
-
end
|
99
|
-
|
100
|
-
# Singleton method calls (class methods)
|
101
|
-
def visit_constant_path_call_node(node)
|
102
|
-
return unless node.name
|
103
|
-
|
104
|
-
method_name = node.name.to_s
|
105
|
-
receiver_name = node.receiver.slice
|
106
|
-
qualified_name = "#{receiver_name}.#{method_name}"
|
107
|
-
|
108
|
-
@generator.register_reference({
|
109
|
-
type: :method,
|
110
|
-
name: qualified_name,
|
111
|
-
node: node,
|
112
|
-
scope: current_scope_name,
|
113
|
-
call_type: :class_method
|
114
|
-
})
|
115
|
-
|
116
|
-
super
|
117
|
-
end
|
118
|
-
|
119
|
-
# Super method calls
|
120
|
-
def visit_super_node(node)
|
121
|
-
return unless current_scope_name
|
122
|
-
|
123
|
-
# Extract current method name from scope
|
124
|
-
current_method = current_method_name
|
125
|
-
return unless current_method
|
126
|
-
|
127
|
-
# Try to find the superclass method
|
128
|
-
if in_class_scope?
|
129
|
-
superclass = find_superclass
|
130
|
-
if superclass
|
131
|
-
qualified_name = "#{superclass}##{current_method}"
|
132
|
-
|
133
|
-
@generator.register_reference({
|
134
|
-
type: :method,
|
135
|
-
name: qualified_name,
|
136
|
-
node: node,
|
137
|
-
scope: current_scope_name,
|
138
|
-
call_type: :super
|
139
|
-
})
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
super
|
144
|
-
end
|
145
|
-
|
146
|
-
# Track class/module scope
|
147
43
|
def visit_class_node(node)
|
148
44
|
@current_scope.push(node.constant_path.slice)
|
149
45
|
super
|
@@ -161,61 +57,6 @@ module Hind
|
|
161
57
|
def current_scope_name
|
162
58
|
@current_scope.join('::')
|
163
59
|
end
|
164
|
-
|
165
|
-
def generate_qualified_names_for_call(node)
|
166
|
-
qualified_names = []
|
167
|
-
method_name = node.name.to_s
|
168
|
-
|
169
|
-
# Try with current scope first
|
170
|
-
qualified_names << "#{current_scope_name}##{method_name}" unless current_scope_name.empty?
|
171
|
-
|
172
|
-
# Try with receiver's type if available
|
173
|
-
if node.receiver
|
174
|
-
case node.receiver
|
175
|
-
when Prism::ConstantReadNode
|
176
|
-
qualified_names << "#{node.receiver.name}##{method_name}"
|
177
|
-
when Prism::ConstantPathNode
|
178
|
-
qualified_names << "#{node.receiver.slice}##{method_name}"
|
179
|
-
when Prism::CallNode
|
180
|
-
# Method chaining - try both instance and class methods
|
181
|
-
if node.receiver.name
|
182
|
-
qualified_names << "#{node.receiver.name}##{method_name}"
|
183
|
-
qualified_names << "#{node.receiver.name}.#{method_name}"
|
184
|
-
end
|
185
|
-
when Prism::InstanceVariableReadNode
|
186
|
-
# Instance variable calls - try current class context
|
187
|
-
qualified_names << "#{current_scope_name}##{method_name}" if current_scope_name
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|
191
|
-
# Try as a standalone method
|
192
|
-
qualified_names << method_name
|
193
|
-
|
194
|
-
# Add potential class method variant
|
195
|
-
qualified_names << "#{current_scope_name}.#{method_name}" unless current_scope_name.empty?
|
196
|
-
|
197
|
-
qualified_names.uniq
|
198
|
-
end
|
199
|
-
|
200
|
-
def current_method_name
|
201
|
-
# Try to find the nearest method node in the AST
|
202
|
-
# This is a simplified version - you might need to enhance this
|
203
|
-
# based on your specific needs
|
204
|
-
"current_method"
|
205
|
-
end
|
206
|
-
|
207
|
-
def in_class_scope?
|
208
|
-
# Check if we're currently in a class definition
|
209
|
-
!@current_scope.empty? && @generator.global_state.declarations[@current_scope.last]&.[](:type) == :class
|
210
|
-
end
|
211
|
-
|
212
|
-
def find_superclass
|
213
|
-
return unless in_class_scope?
|
214
|
-
|
215
|
-
current_class = @current_scope.last
|
216
|
-
class_declaration = @generator.global_state.declarations[current_class]
|
217
|
-
class_declaration&.[](:superclass)
|
218
|
-
end
|
219
60
|
end
|
220
61
|
end
|
221
62
|
end
|
data/lib/hind/lsif.rb
CHANGED
data/lib/hind/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hind
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aboobacker MK
|
@@ -111,7 +111,6 @@ files:
|
|
111
111
|
- lib/hind/lsif/generator.rb
|
112
112
|
- lib/hind/lsif/global_state.rb
|
113
113
|
- lib/hind/lsif/vertex.rb
|
114
|
-
- lib/hind/lsif/visitor.rb
|
115
114
|
- lib/hind/lsif/visitors/declaration_visitor.rb
|
116
115
|
- lib/hind/lsif/visitors/reference_visitor.rb
|
117
116
|
- lib/hind/parser.rb
|