@@ -1419,6 +1419,294 @@ def bar
14191419 end
14201420 end
14211421
1422+ def test_definition_for_implicit_self_method_call_inside_singleton_method
1423+ source = <<~RUBY
1424+ # typed: false
1425+
1426+ class Foo
1427+ def self.bar; end
1428+
1429+ def self.baz
1430+ bar
1431+ end
1432+ end
1433+ RUBY
1434+
1435+ with_server ( source ) do |server , uri |
1436+ server . process_message (
1437+ id : 1 ,
1438+ method : "textDocument/definition" ,
1439+ params : { textDocument : { uri : uri } , position : { character : 4 , line : 6 } } ,
1440+ )
1441+
1442+ response = server . pop_response . response
1443+ assert_equal ( 1 , response . length )
1444+ assert_equal ( 3 , response [ 0 ] . target_range . start . line )
1445+ end
1446+ end
1447+
1448+ def test_definition_for_method_call_inside_method_with_constant_receiver
1449+ source = <<~RUBY
1450+ # typed: false
1451+
1452+ class Bar
1453+ def self.helper; end
1454+ end
1455+
1456+ class Foo
1457+ def Bar.check
1458+ helper
1459+ end
1460+ end
1461+ RUBY
1462+
1463+ with_server ( source ) do |server , uri |
1464+ server . process_message (
1465+ id : 1 ,
1466+ method : "textDocument/definition" ,
1467+ params : { textDocument : { uri : uri } , position : { character : 4 , line : 8 } } ,
1468+ )
1469+
1470+ response = server . pop_response . response
1471+ assert_equal ( 1 , response . length )
1472+ assert_equal ( 3 , response [ 0 ] . target_range . start . line )
1473+ end
1474+ end
1475+
1476+ def test_definition_for_super_inside_singleton_method
1477+ source = <<~RUBY
1478+ class Parent
1479+ def self.foo; end
1480+ end
1481+
1482+ class Child < Parent
1483+ def self.foo
1484+ super
1485+ end
1486+ end
1487+ RUBY
1488+
1489+ with_server ( source ) do |server , uri |
1490+ server . process_message (
1491+ id : 1 ,
1492+ method : "textDocument/definition" ,
1493+ params : { textDocument : { uri : uri } , position : { character : 4 , line : 6 } } ,
1494+ )
1495+
1496+ response = server . pop_response . response
1497+ assert_equal ( 1 , response . length )
1498+ assert_equal ( 1 , response [ 0 ] . target_range . start . line )
1499+ end
1500+ end
1501+
1502+ def test_definition_for_implicit_self_method_call_inside_singleton_method_with_compact_namespace
1503+ source = <<~RUBY
1504+ # typed: false
1505+
1506+ module Foo; end
1507+
1508+ class Foo::Bar
1509+ def self.helper; end
1510+
1511+ def self.check
1512+ helper
1513+ end
1514+ end
1515+ RUBY
1516+
1517+ with_server ( source ) do |server , uri |
1518+ server . process_message (
1519+ id : 1 ,
1520+ method : "textDocument/definition" ,
1521+ params : { textDocument : { uri : uri } , position : { character : 4 , line : 8 } } ,
1522+ )
1523+
1524+ response = server . pop_response . response
1525+ assert_equal ( 1 , response . length )
1526+ assert_equal ( 5 , response [ 0 ] . target_range . start . line )
1527+ end
1528+ end
1529+
1530+ def test_super_definition_for_method_definition_with_receiver
1531+ source = <<~RUBY
1532+ # typed: false
1533+
1534+ class Foo
1535+ class << self
1536+ # You found me!
1537+ def bar; end
1538+ end
1539+ end
1540+
1541+ class Bar < Foo
1542+ class << self
1543+ end
1544+ end
1545+
1546+ class Qux
1547+ def Bar.bar
1548+ super
1549+ end
1550+ end
1551+ RUBY
1552+
1553+ with_server ( source ) do |server , uri |
1554+ server . process_message (
1555+ id : 1 ,
1556+ method : "textDocument/definition" ,
1557+ params : { textDocument : { uri : uri } , position : { character : 4 , line : 16 } } ,
1558+ )
1559+
1560+ response = server . pop_response . response
1561+ assert_equal ( 1 , response . length )
1562+ assert_equal ( 5 , response [ 0 ] . target_range . start . line )
1563+ end
1564+ end
1565+
1566+ def test_definition_for_method_call_inside_class_singleton_block_method
1567+ source = <<~RUBY
1568+ # typed: false
1569+
1570+ class Foo
1571+ def self.bar; end
1572+
1573+ class << self
1574+ def baz
1575+ bar
1576+ end
1577+ end
1578+ end
1579+ RUBY
1580+
1581+ with_server ( source ) do |server , uri |
1582+ server . process_message (
1583+ id : 1 ,
1584+ method : "textDocument/definition" ,
1585+ params : { textDocument : { uri : uri } , position : { character : 6 , line : 7 } } ,
1586+ )
1587+
1588+ response = server . pop_response . response
1589+ assert_equal ( 1 , response . length )
1590+ assert_equal ( 3 , response [ 0 ] . target_range . start . line )
1591+ end
1592+ end
1593+
1594+ def test_definition_for_instance_variable_in_method_with_constant_receiver
1595+ source = <<~RUBY
1596+ class Bar
1597+ class << self; end
1598+
1599+ @config = "default"
1600+ end
1601+
1602+ class Foo
1603+ def Bar.configure
1604+ @config
1605+ end
1606+ end
1607+ RUBY
1608+
1609+ with_server ( source ) do |server , uri |
1610+ server . process_message (
1611+ id : 1 ,
1612+ method : "textDocument/definition" ,
1613+ params : { textDocument : { uri : uri } , position : { character : 4 , line : 8 } } ,
1614+ )
1615+
1616+ # @config should resolve through Bar's singleton class, not Foo
1617+ response = server . pop_response . response
1618+ assert_equal ( 1 , response . length )
1619+ assert_equal ( 3 , response [ 0 ] . range . start . line )
1620+ end
1621+ end
1622+
1623+ def test_definition_for_class_variable_in_method_with_constant_receiver
1624+ source = <<~RUBY
1625+ class Bar
1626+ @@shared = 1
1627+ end
1628+
1629+ class Foo
1630+ def Bar.check
1631+ @@shared
1632+ end
1633+ end
1634+ RUBY
1635+
1636+ with_server ( source ) do |server , uri |
1637+ server . process_message (
1638+ id : 1 ,
1639+ method : "textDocument/definition" ,
1640+ params : { textDocument : { uri : uri } , position : { character : 4 , line : 6 } } ,
1641+ )
1642+
1643+ # @@shared follows lexical scope (Foo), not the receiver (Bar).
1644+ # Since @@shared is defined in Bar but not in Foo, definition should be empty
1645+ assert_empty ( server . pop_response . response )
1646+ end
1647+ end
1648+
1649+ def test_definition_for_constant_in_method_with_constant_receiver
1650+ source = <<~RUBY
1651+ # typed: ignore
1652+ class Bar
1653+ OTHER = "other"
1654+ end
1655+
1656+ class Foo
1657+ MY_CONST = "hello"
1658+
1659+ def Bar.check
1660+ MY_CONST
1661+ end
1662+ end
1663+ RUBY
1664+
1665+ with_server ( source ) do |server , uri |
1666+ server . process_message (
1667+ id : 1 ,
1668+ method : "textDocument/definition" ,
1669+ params : { textDocument : { uri : uri } , position : { character : 4 , line : 9 } } ,
1670+ )
1671+
1672+ # MY_CONST resolves through Foo's lexical scope, not Bar
1673+ response = server . pop_response . response
1674+ assert_equal ( 1 , response . length )
1675+ assert_equal ( 6 , response [ 0 ] . target_range . start . line )
1676+ end
1677+ end
1678+
1679+ def test_definition_for_instance_variable_in_hoisted_parent_scope
1680+ source = <<~RUBY
1681+ module Bar; end
1682+
1683+ module Foo
1684+ class Bar::Baz
1685+ class << self; end
1686+
1687+ @var = 1
1688+
1689+ def self.get_var
1690+ @var
1691+ end
1692+ end
1693+ end
1694+ RUBY
1695+
1696+ with_server ( source ) do |server , uri |
1697+ server . process_message (
1698+ id : 1 ,
1699+ method : "textDocument/definition" ,
1700+ params : { textDocument : { uri : uri } , position : { character : 6 , line : 9 } } ,
1701+ )
1702+
1703+ # @var should resolve through Bar::Baz's singleton class, not Foo::Bar::Baz
1704+ response = server . pop_response . response
1705+ assert_equal ( 1 , response . length )
1706+ assert_equal ( 6 , response [ 0 ] . range . start . line )
1707+ end
1708+ end
1709+
14221710 private
14231711
14241712 def create_definition_addon
0 commit comments