@@ -527,6 +527,30 @@ impl<T: LspContext> Backend<T> {
527
527
_ => None ,
528
528
}
529
529
}
530
+ DefinitionLocation :: Unresolved { source, name } => {
531
+ match self . context . get_url_for_global_symbol ( & uri, & name) ? {
532
+ Some ( uri) => {
533
+ let loaded_location = self
534
+ . get_ast_or_load_from_disk ( & uri) ?
535
+ . and_then ( |ast| ast. find_exported_symbol ( & name) ) ;
536
+ match loaded_location {
537
+ None => Some ( LocationLink {
538
+ origin_selection_range : Some ( source. into ( ) ) ,
539
+ target_uri : uri. try_into ( ) ?,
540
+ target_range : Range :: default ( ) ,
541
+ target_selection_range : Range :: default ( ) ,
542
+ } ) ,
543
+ Some ( loaded_location) => Some ( LocationLink {
544
+ origin_selection_range : Some ( source. into ( ) ) ,
545
+ target_uri : uri. try_into ( ) ?,
546
+ target_range : loaded_location. into ( ) ,
547
+ target_selection_range : loaded_location. into ( ) ,
548
+ } ) ,
549
+ }
550
+ }
551
+ None => None ,
552
+ }
553
+ }
530
554
} ,
531
555
None => None ,
532
556
} ;
@@ -1565,4 +1589,91 @@ mod test {
1565
1589
1566
1590
Ok ( ( ) )
1567
1591
}
1592
+
1593
+ #[ test]
1594
+ fn goto_works_for_native_symbols ( ) -> anyhow:: Result < ( ) > {
1595
+ let foo_uri = temp_file_uri ( "foo.star" ) ;
1596
+ let native_uri = Url :: parse ( "starlark:/native/builtin.bzl" ) ?;
1597
+
1598
+ let mut server = TestServer :: new ( ) ?;
1599
+
1600
+ let foo_contents = dedent (
1601
+ r#"
1602
+ <click_n1>na<n1>t</n1>ive_function1</click_n1>()
1603
+ def f(<n2_loc>native_function1</n2_loc>):
1604
+ print(<click_n2>nat<n2>i</n2>ve_function1</click_n2>)
1605
+ mi<n3>s</n3>sing_global()
1606
+ "# ,
1607
+ )
1608
+ . trim ( )
1609
+ . to_owned ( ) ;
1610
+ let native_contents = dedent (
1611
+ r#"
1612
+ def <n1_loc>native_function1</n1_loc>():
1613
+ pass
1614
+
1615
+ def native_function2():
1616
+ pass
1617
+ "# ,
1618
+ )
1619
+ . trim ( )
1620
+ . to_owned ( ) ;
1621
+
1622
+ let foo = FixtureWithRanges :: from_fixture ( foo_uri. path ( ) , & foo_contents) ?;
1623
+ let native = FixtureWithRanges :: from_fixture ( native_uri. path ( ) , & native_contents) ?;
1624
+
1625
+ server. open_file ( foo_uri. clone ( ) , foo. program ( ) ) ?;
1626
+
1627
+ let expected_n1_location = expected_location_link_from_spans (
1628
+ native_uri,
1629
+ foo. span ( "click_n1" ) ,
1630
+ native. span ( "n1_loc" ) ,
1631
+ ) ;
1632
+
1633
+ let goto_definition = goto_definition_request (
1634
+ & mut server,
1635
+ foo_uri. clone ( ) ,
1636
+ foo. begin_line ( "n1" ) ,
1637
+ foo. begin_column ( "n1" ) ,
1638
+ ) ;
1639
+ let request_id = server. send_request ( goto_definition) ?;
1640
+ let n1_location = goto_definition_response_location ( & mut server, request_id) ?;
1641
+
1642
+ assert_eq ! ( expected_n1_location, n1_location) ;
1643
+
1644
+ let expected_n2_location = expected_location_link_from_spans (
1645
+ foo_uri. clone ( ) ,
1646
+ foo. span ( "click_n2" ) ,
1647
+ foo. span ( "n2_loc" ) ,
1648
+ ) ;
1649
+
1650
+ let goto_definition = goto_definition_request (
1651
+ & mut server,
1652
+ foo_uri. clone ( ) ,
1653
+ foo. begin_line ( "n2" ) ,
1654
+ foo. begin_column ( "n2" ) ,
1655
+ ) ;
1656
+ let request_id = server. send_request ( goto_definition) ?;
1657
+ let n2_location = goto_definition_response_location ( & mut server, request_id) ?;
1658
+
1659
+ assert_eq ! ( expected_n2_location, n2_location) ;
1660
+
1661
+ let goto_definition = goto_definition_request (
1662
+ & mut server,
1663
+ foo_uri,
1664
+ foo. begin_line ( "n3" ) ,
1665
+ foo. begin_column ( "n3" ) ,
1666
+ ) ;
1667
+ let request_id = server. send_request ( goto_definition) ?;
1668
+ let n3_response = server. get_response :: < GotoDefinitionResponse > ( request_id) ?;
1669
+ match n3_response {
1670
+ GotoDefinitionResponse :: Array ( definitions) if definitions. is_empty ( ) => Ok ( ( ) ) ,
1671
+ response => Err ( anyhow:: anyhow!(
1672
+ "Expected empty definitions, got `{:?}`" ,
1673
+ response
1674
+ ) ) ,
1675
+ } ?;
1676
+
1677
+ Ok ( ( ) )
1678
+ }
1568
1679
}
0 commit comments