Skip to content

Commit c923aeb

Browse files
Copilotkwerle
andcommitted
Add global fallback when lookup fails to find anything in scope chain
Co-authored-by: kwerle <23320+kwerle@users.noreply.github.com>
1 parent a1cfb10 commit c923aeb

3 files changed

Lines changed: 104 additions & 61 deletions

File tree

lib/ruby_language_server/project_manager.rb

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,17 @@ def project_definitions_for(name, parent_scopes = [], class_method_filter = nil)
280280
# Move up to parent scope
281281
current_scope = current_scope.parent
282282
end
283+
284+
# Fallback: if nothing found in scope chain, search globally
285+
if results.empty?
286+
all_scopes = RubyLanguageServer::ScopeData::Scope.where(name: name)
287+
all_scopes = all_scopes.where(class_method: class_method_filter) unless class_method_filter.nil?
288+
results.concat(all_scopes.to_a)
289+
290+
# Also search for constants/variables globally
291+
all_variables = RubyLanguageServer::ScopeData::Variable.where(name: name)
292+
results.concat(all_variables.to_a)
293+
end
283294
end
284295

285296
# Return locations for all matching scopes and variables

spec/lib/ruby_language_server/project_manager_spec.rb

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,5 +467,98 @@ class Baz
467467
assert_equal 0, results.first[:range][:start][:line]
468468
end
469469
end
470+
471+
describe 'global fallback when not found in scope' do
472+
it 'finds constants defined elsewhere when not in local scope' do
473+
# Define a class in one file
474+
external_file = <<~CODE_FILE
475+
class ExternalClass
476+
def external_method
477+
end
478+
end
479+
CODE_FILE
480+
481+
# Reference it from another file in a different scope
482+
reference_file = <<~CODE_FILE
483+
module MyModule
484+
class MyClass
485+
def my_method
486+
ExternalClass # Not in local scope but exists globally
487+
end
488+
end
489+
end
490+
CODE_FILE
491+
492+
project_manager.update_document_content('external_uri', external_file)
493+
project_manager.tags_for_uri('external_uri') # Force load
494+
495+
project_manager.update_document_content('reference_uri', reference_file)
496+
project_manager.tags_for_uri('reference_uri') # Force load
497+
498+
# Position on "ExternalClass" (line 3, character 8)
499+
position = OpenStruct.new(line: 3, character: 8)
500+
results = project_manager.possible_definitions('reference_uri', position)
501+
502+
# Should find the class via global fallback
503+
assert_equal 1, results.length
504+
assert_equal 'external_uri', results.first[:uri]
505+
assert_equal 0, results.first[:range][:start][:line]
506+
end
507+
508+
it 'finds methods defined elsewhere when not in local scope' do
509+
# Define a class with a method in one file
510+
external_file = <<~CODE_FILE
511+
class MyExternalClass
512+
def my_external_method
513+
end
514+
end
515+
CODE_FILE
516+
517+
# Reference the method from another scope
518+
reference_file = <<~CODE_FILE
519+
module DifferentModule
520+
class DifferentClass
521+
def some_method
522+
# Call method that's not in local scope
523+
end
524+
end
525+
end
526+
CODE_FILE
527+
528+
project_manager.update_document_content('external_uri', external_file)
529+
project_manager.tags_for_uri('external_uri')
530+
531+
project_manager.update_document_content('reference_uri', reference_file)
532+
project_manager.tags_for_uri('reference_uri')
533+
534+
# Note: Testing method fallback would require context parsing
535+
# For now, just verify constant fallback doesn't break method lookup
536+
position = OpenStruct.new(line: 3, character: 8)
537+
results = project_manager.possible_definitions('reference_uri', position)
538+
assert_instance_of Array, results
539+
end
540+
541+
it 'returns empty array when nothing exists anywhere' do
542+
reference_file = <<~CODE_FILE
543+
module MyModule
544+
class MyClass
545+
def my_method
546+
CompletelyNonExistentClass
547+
end
548+
end
549+
end
550+
CODE_FILE
551+
552+
project_manager.update_document_content('reference_uri', reference_file)
553+
project_manager.tags_for_uri('reference_uri')
554+
555+
# Position on "CompletelyNonExistentClass"
556+
position = OpenStruct.new(line: 3, character: 8)
557+
results = project_manager.possible_definitions('reference_uri', position)
558+
559+
# Should return empty array as nothing exists
560+
assert_equal [], results
561+
end
562+
end
470563
end
471564
end

test_fallback.rb

Lines changed: 0 additions & 61 deletions
This file was deleted.

0 commit comments

Comments
 (0)