hind 0.1.4 → 0.1.6
Sign up to get free protection for your applications and to get access to all the features.
- 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
|