hind 0.1.4 → 0.1.6
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/exe/hind +4 -2
- data/lib/hind/cli.rb +181 -64
- data/lib/hind/lsif/edge.rb +3 -1
- data/lib/hind/lsif/generator.rb +215 -86
- data/lib/hind/lsif/global_state.rb +152 -11
- data/lib/hind/lsif/vertex.rb +3 -1
- data/lib/hind/lsif/visitor.rb +211 -19
- data/lib/hind/lsif/visitors/declaration_visitor.rb +239 -0
- data/lib/hind/lsif/visitors/reference_visitor.rb +221 -0
- data/lib/hind/lsif.rb +6 -5
- data/lib/hind/parser.rb +3 -0
- data/lib/hind/scip/generator.rb +2 -0
- data/lib/hind/scip/visitor.rb +2 -0
- data/lib/hind/scip.rb +2 -0
- data/lib/hind/version.rb +1 -1
- data/lib/hind.rb +4 -4
- metadata +4 -2
@@ -0,0 +1,221 @@
|
|
1
|
+
# lib/hind/lsif/visitors/reference_visitor.rb
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module Hind
|
5
|
+
module LSIF
|
6
|
+
class ReferenceVisitor < Prism::Visitor
|
7
|
+
attr_reader :current_scope
|
8
|
+
|
9
|
+
def initialize(generator, file_path)
|
10
|
+
@generator = generator
|
11
|
+
@file_path = file_path
|
12
|
+
@current_scope = []
|
13
|
+
end
|
14
|
+
|
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
|
+
def visit_constant_read_node(node)
|
37
|
+
return unless node.name
|
38
|
+
|
39
|
+
constant_name = node.name.to_s
|
40
|
+
qualified_name = @current_scope.empty? ? constant_name : "#{current_scope_name}::#{constant_name}"
|
41
|
+
|
42
|
+
@generator.register_reference({
|
43
|
+
type: :constant,
|
44
|
+
name: qualified_name,
|
45
|
+
node: node,
|
46
|
+
scope: current_scope_name
|
47
|
+
})
|
48
|
+
|
49
|
+
super
|
50
|
+
end
|
51
|
+
|
52
|
+
# Constant path references (e.g., A::B::C)
|
53
|
+
def visit_constant_path_node(node)
|
54
|
+
qualified_name = node.slice
|
55
|
+
|
56
|
+
@generator.register_reference({
|
57
|
+
type: :constant,
|
58
|
+
name: qualified_name,
|
59
|
+
node: node,
|
60
|
+
scope: current_scope_name
|
61
|
+
})
|
62
|
+
|
63
|
+
super
|
64
|
+
end
|
65
|
+
|
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
|
+
def visit_class_node(node)
|
148
|
+
@current_scope.push(node.constant_path.slice)
|
149
|
+
super
|
150
|
+
@current_scope.pop
|
151
|
+
end
|
152
|
+
|
153
|
+
def visit_module_node(node)
|
154
|
+
@current_scope.push(node.constant_path.slice)
|
155
|
+
super
|
156
|
+
@current_scope.pop
|
157
|
+
end
|
158
|
+
|
159
|
+
private
|
160
|
+
|
161
|
+
def current_scope_name
|
162
|
+
@current_scope.join('::')
|
163
|
+
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
|
+
end
|
220
|
+
end
|
221
|
+
end
|
data/lib/hind/lsif.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
|
-
|
2
|
-
require_relative "lsif/edge"
|
3
|
-
require_relative "lsif/generator"
|
4
|
-
require_relative "lsif/vertex"
|
5
|
-
require_relative "lsif/visitor"
|
1
|
+
# frozen_string_literal: true
|
6
2
|
|
3
|
+
require_relative 'lsif/global_state'
|
4
|
+
require_relative 'lsif/edge'
|
5
|
+
require_relative 'lsif/generator'
|
6
|
+
require_relative 'lsif/vertex'
|
7
|
+
require_relative 'lsif/visitor'
|
7
8
|
|
8
9
|
module Hind
|
9
10
|
module LSIF
|
data/lib/hind/parser.rb
CHANGED
data/lib/hind/scip/generator.rb
CHANGED
data/lib/hind/scip/visitor.rb
CHANGED
data/lib/hind/scip.rb
CHANGED
data/lib/hind/version.rb
CHANGED
data/lib/hind.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
4
|
-
require_relative
|
5
|
-
require_relative
|
6
|
-
require_relative
|
3
|
+
require_relative 'hind/version'
|
4
|
+
require_relative 'hind/lsif'
|
5
|
+
require_relative 'hind/scip'
|
6
|
+
require_relative 'hind/parser'
|
7
7
|
|
8
8
|
module Hind
|
9
9
|
class Error < StandardError; end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
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.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aboobacker MK
|
8
8
|
bindir: exe
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-02-
|
10
|
+
date: 2025-02-10 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: prism
|
@@ -112,6 +112,8 @@ files:
|
|
112
112
|
- lib/hind/lsif/global_state.rb
|
113
113
|
- lib/hind/lsif/vertex.rb
|
114
114
|
- lib/hind/lsif/visitor.rb
|
115
|
+
- lib/hind/lsif/visitors/declaration_visitor.rb
|
116
|
+
- lib/hind/lsif/visitors/reference_visitor.rb
|
115
117
|
- lib/hind/parser.rb
|
116
118
|
- lib/hind/scip.rb
|
117
119
|
- lib/hind/scip/generator.rb
|