@@ -201,10 +201,12 @@ use pyrefly_python::module::TextRangeWithModule;
201201use pyrefly_python:: module_name:: ModuleName ;
202202use pyrefly_python:: module_name:: ModuleNameWithKind ;
203203use pyrefly_python:: module_path:: ModulePath ;
204+ use pyrefly_python:: module_path:: ModulePathDetails ;
204205use pyrefly_python:: short_identifier:: ShortIdentifier ;
205206use pyrefly_util:: absolutize:: Absolutize as _;
206207use pyrefly_util:: arc_id:: ArcId ;
207208use pyrefly_util:: events:: CategorizedEvents ;
209+ use pyrefly_util:: fs_anyhow;
208210use pyrefly_util:: globs:: FilteredGlobs ;
209211use pyrefly_util:: globs:: HiddenDirFilter ;
210212use pyrefly_util:: includes:: Includes as _;
@@ -313,6 +315,7 @@ use crate::lsp::wasm::provide_type::ProvideTypeParams;
313315use crate :: lsp:: wasm:: provide_type:: ProvideTypeResponse ;
314316use crate :: lsp:: wasm:: provide_type:: provide_type;
315317use crate :: module:: bundled:: BundledStub ;
318+ use crate :: state:: load:: FileContents ;
316319use crate :: state:: load:: LspFile ;
317320use crate :: state:: lsp:: DisplayTypeErrors ;
318321use crate :: state:: lsp:: FindDefinitionItemWithDocstring ;
@@ -1528,6 +1531,41 @@ impl Server {
15281531 }
15291532 }
15301533
1534+ fn stale_definition_request_disk_contents (
1535+ & self ,
1536+ transaction : & Transaction < ' _ > ,
1537+ handle : & Handle ,
1538+ path : & Path ,
1539+ ) -> Option < String > {
1540+ let disk_contents = fs_anyhow:: read_to_string ( path) . ok ( ) ?;
1541+ if let Some ( open_file) = self . open_files . read ( ) . get ( path) {
1542+ return match & * * open_file {
1543+ LspFile :: Source ( contents) if contents. as_str ( ) != disk_contents. as_str ( ) => {
1544+ Some ( disk_contents)
1545+ }
1546+ LspFile :: Source ( _) | LspFile :: Notebook ( _) => None ,
1547+ } ;
1548+ }
1549+ let module_info = transaction. get_module_info ( handle) ?;
1550+ if module_info. is_notebook ( ) || module_info. contents ( ) . as_str ( ) == disk_contents. as_str ( ) {
1551+ None
1552+ } else {
1553+ Some ( disk_contents)
1554+ }
1555+ }
1556+
1557+ fn invalidate_all_definition_files ( & self , transaction : & mut Transaction < ' _ > ) {
1558+ let files = transaction
1559+ . handles ( )
1560+ . into_iter ( )
1561+ . filter_map ( |handle| match handle. path ( ) . details ( ) {
1562+ ModulePathDetails :: FileSystem ( path) => Some ( path. as_path ( ) . to_path_buf ( ) ) ,
1563+ _ => None ,
1564+ } )
1565+ . collect :: < Vec < _ > > ( ) ;
1566+ transaction. invalidate_disk ( & files) ;
1567+ }
1568+
15311569 /// Returns a snapshot of all currently open notebooks, keyed by their filesystem path.
15321570 /// Used to remap file paths to notebook cell URIs in closures that don't have
15331571 /// access to `self`.
@@ -1861,7 +1899,7 @@ impl Server {
18611899 params, & x. id ,
18621900 )
18631901 {
1864- let response = match self . goto_definition ( & transaction, params) {
1902+ let response = match self . goto_definition ( & mut transaction, params) {
18651903 Ok ( response) => response,
18661904 Err ( reason) => {
18671905 telemetry_event. set_empty_response_reason ( reason) ;
@@ -3933,19 +3971,18 @@ impl Server {
39333971 . map ( |( handle, _) | handle)
39343972 }
39353973
3936- fn goto_definition (
3974+ fn goto_definition_response (
39373975 & self ,
39383976 transaction : & Transaction < ' _ > ,
3939- params : GotoDefinitionParams ,
3977+ handle : & Handle ,
3978+ uri : & Url ,
3979+ position : Position ,
39403980 ) -> Result < Option < GotoDefinitionResponse > , EmptyResponseReason > {
3941- let uri = & params. text_document_position_params . text_document . uri ;
3942- let handle = self . make_handle_if_enabled ( uri, Some ( GotoDefinition :: METHOD ) ) ?;
39433981 let info = transaction
3944- . get_module_info ( & handle)
3982+ . get_module_info ( handle)
39453983 . ok_or ( EmptyResponseReason :: ModuleInfoNotFound ) ?;
3946- let range =
3947- self . from_lsp_position ( uri, & info, params. text_document_position_params . position ) ;
3948- let targets = transaction. goto_definition ( & handle, range) ?;
3984+ let range = self . from_lsp_position ( uri, & info, position) ;
3985+ let targets = transaction. goto_definition ( handle, range) ?;
39493986 let mut lsp_targets = targets
39503987 . iter ( )
39513988 . filter_map ( |x| self . to_lsp_location ( x) )
@@ -3967,6 +4004,55 @@ impl Server {
39674004 }
39684005 }
39694006
4007+ fn goto_definition (
4008+ & self ,
4009+ transaction : & mut Transaction < ' _ > ,
4010+ params : GotoDefinitionParams ,
4011+ ) -> Result < Option < GotoDefinitionResponse > , EmptyResponseReason > {
4012+ let uri = & params. text_document_position_params . text_document . uri ;
4013+ let handle = self . make_handle_if_enabled ( uri, Some ( GotoDefinition :: METHOD ) ) ?;
4014+ let path = self . path_for_uri ( uri) ;
4015+ let stale_disk_contents = path. as_deref ( ) . and_then ( |path| {
4016+ self . stale_definition_request_disk_contents ( transaction, & handle, path)
4017+ } ) ;
4018+ if stale_disk_contents. is_some ( ) {
4019+ self . invalidate_all_definition_files ( transaction) ;
4020+ transaction. run (
4021+ std:: slice:: from_ref ( & handle) ,
4022+ Require :: Everything ,
4023+ Some ( & self . lsp_thread_pool ) ,
4024+ ) ;
4025+ }
4026+ let position = params. text_document_position_params . position ;
4027+ let response = self . goto_definition_response ( transaction, & handle, uri, position) ;
4028+ if matches ! ( response, Ok ( Some ( _) ) ) {
4029+ return response;
4030+ }
4031+ let Some ( path) = path else {
4032+ return response;
4033+ } ;
4034+ let Some ( disk_contents) = stale_disk_contents else {
4035+ return response;
4036+ } ;
4037+ let should_retry = matches ! (
4038+ self . open_files. read( ) . get( & path) . map( |file| & * * file) ,
4039+ Some ( LspFile :: Source ( _) )
4040+ ) ;
4041+ if !should_retry {
4042+ return response;
4043+ }
4044+ transaction. set_memory ( vec ! [ (
4045+ path,
4046+ Some ( Arc :: new( FileContents :: from_source( disk_contents) ) ) ,
4047+ ) ] ) ;
4048+ transaction. run (
4049+ std:: slice:: from_ref ( & handle) ,
4050+ Require :: Everything ,
4051+ Some ( & self . lsp_thread_pool ) ,
4052+ ) ;
4053+ self . goto_definition_response ( transaction, & handle, uri, position)
4054+ }
4055+
39704056 fn goto_declaration (
39714057 & self ,
39724058 transaction : & Transaction < ' _ > ,
0 commit comments