@@ -114,10 +114,10 @@ def create_scanner
114
114
params (
115
115
position : PositionShape ,
116
116
node_types : T ::Array [ T . class_of ( SyntaxTree ::Node ) ] ,
117
- ) . returns ( [ T . nilable ( SyntaxTree ::Node ) , T . nilable ( SyntaxTree ::Node ) ] )
117
+ ) . returns ( [ T . nilable ( SyntaxTree ::Node ) , T . nilable ( SyntaxTree ::Node ) , T :: Array [ String ] ] )
118
118
end
119
119
def locate_node ( position , node_types : [ ] )
120
- return [ nil , nil ] unless parsed?
120
+ return [ nil , nil , [ ] ] unless parsed?
121
121
122
122
locate ( T . must ( @tree ) , create_scanner . find_char_position ( position ) , node_types : node_types )
123
123
end
@@ -127,21 +127,24 @@ def locate_node(position, node_types: [])
127
127
node : SyntaxTree ::Node ,
128
128
char_position : Integer ,
129
129
node_types : T ::Array [ T . class_of ( SyntaxTree ::Node ) ] ,
130
- ) . returns ( [ T . nilable ( SyntaxTree ::Node ) , T . nilable ( SyntaxTree ::Node ) ] )
130
+ ) . returns ( [ T . nilable ( SyntaxTree ::Node ) , T . nilable ( SyntaxTree ::Node ) , T :: Array [ String ] ] )
131
131
end
132
132
def locate ( node , char_position , node_types : [ ] )
133
133
queue = T . let ( node . child_nodes . compact , T ::Array [ T . nilable ( SyntaxTree ::Node ) ] )
134
134
closest = node
135
135
parent = T . let ( nil , T . nilable ( SyntaxTree ::Node ) )
136
+ nesting = T . let ( [ ] , T ::Array [ T . any ( SyntaxTree ::ClassDeclaration , SyntaxTree ::ModuleDeclaration ) ] )
136
137
137
138
until queue . empty?
138
139
candidate = queue . shift
139
140
140
141
# Skip nil child nodes
141
142
next if candidate . nil?
142
143
143
- # Add the next child_nodes to the queue to be processed
144
- queue . concat ( candidate . child_nodes )
144
+ # Add the next child_nodes to the queue to be processed. The order here is important! We want to move in the
145
+ # same order as the visiting mechanism, which means searching the child nodes before moving on to the next
146
+ # sibling
147
+ queue . unshift ( *candidate . child_nodes )
145
148
146
149
# Skip if the current node doesn't cover the desired position
147
150
loc = candidate . location
@@ -160,9 +163,20 @@ def locate(node, char_position, node_types: [])
160
163
parent = closest
161
164
closest = candidate
162
165
end
166
+
167
+ # If the candidate starts after the end of the previous nesting level, then we've exited that nesting level and
168
+ # need to pop the stack
169
+ previous_level = nesting . last
170
+ nesting . pop if previous_level && candidate . start_char > previous_level . end_char
171
+
172
+ # Keep track of the nesting where we found the target. This is used to determine the fully qualified name of the
173
+ # target when it is a constant
174
+ if candidate . is_a? ( SyntaxTree ::ClassDeclaration ) || candidate . is_a? ( SyntaxTree ::ModuleDeclaration )
175
+ nesting << candidate
176
+ end
163
177
end
164
178
165
- [ closest , parent ]
179
+ [ closest , parent , nesting . map { | n | n . constant . constant . value } ]
166
180
end
167
181
168
182
class Scanner
0 commit comments