mirror of
https://github.com/astral-sh/ruff
synced 2026-01-21 05:20:49 -05:00
[ty] Fix goto definition for relative imports in third-party files (#22457)
This commit is contained in:
@@ -69,13 +69,6 @@ pub(crate) struct Session {
|
||||
/// The projects across all workspaces.
|
||||
projects: BTreeMap<SystemPathBuf, ProjectState>,
|
||||
|
||||
/// The project to use for files outside any workspace. For example, if the user
|
||||
/// opens the project `<home>/my_project` in VS code but they then opens a Python file from their Desktop.
|
||||
/// This file isn't part of the active workspace, nor is it part of any project. But we still want
|
||||
/// to provide some basic functionality like navigation, completions, syntax highlighting, etc.
|
||||
/// That's what we use the default project for.
|
||||
default_project: DefaultProject,
|
||||
|
||||
/// Initialization options that were provided by the client during server initialization.
|
||||
initialization_options: InitializationOptions,
|
||||
|
||||
@@ -165,7 +158,6 @@ impl Session {
|
||||
workspaces,
|
||||
deferred_messages: VecDeque::new(),
|
||||
index: Some(index),
|
||||
default_project: DefaultProject::new(),
|
||||
initialization_options,
|
||||
global_settings: Arc::new(GlobalSettings::default()),
|
||||
projects: BTreeMap::new(),
|
||||
@@ -304,7 +296,7 @@ impl Session {
|
||||
/// Returns a reference to the project's [`ProjectDatabase`] in which the given `path` belongs.
|
||||
///
|
||||
/// If the path is a system path, it will return the project database that is closest to the
|
||||
/// given path, or the default project if no project is found for the path.
|
||||
/// given path, or the first project if no project is found for the path.
|
||||
///
|
||||
/// If the path is a virtual path, it will return the first project database in the session.
|
||||
pub(crate) fn project_db(&self, path: &AnySystemPath) -> &ProjectDatabase {
|
||||
@@ -341,15 +333,17 @@ impl Session {
|
||||
/// Returns a reference to the project's [`ProjectState`] in which the given `path` belongs.
|
||||
///
|
||||
/// If the path is a system path, it will return the project database that is closest to the
|
||||
/// given path, or the default project if no project is found for the path.
|
||||
/// given path, or the first project if no project is found for the path.
|
||||
///
|
||||
/// If the path is a virtual path, it will return the first project database in the session.
|
||||
pub(crate) fn project_state(&self, path: &AnySystemPath) -> &ProjectState {
|
||||
match path {
|
||||
AnySystemPath::System(system_path) => {
|
||||
self.project_state_for_path(system_path).unwrap_or_else(|| {
|
||||
self.default_project
|
||||
.get(self.index.as_ref(), &self.native_system)
|
||||
self.projects
|
||||
.values()
|
||||
.next()
|
||||
.expect("To always have at least one project")
|
||||
})
|
||||
}
|
||||
AnySystemPath::SystemVirtual(_virtual_path) => {
|
||||
@@ -373,15 +367,22 @@ impl Session {
|
||||
/// [`project_db`]: Session::project_db
|
||||
pub(crate) fn project_state_mut(&mut self, path: &AnySystemPath) -> &mut ProjectState {
|
||||
match path {
|
||||
AnySystemPath::System(system_path) => self
|
||||
.projects
|
||||
.range_mut(..=system_path.to_path_buf())
|
||||
.next_back()
|
||||
.map(|(_, project)| project)
|
||||
.unwrap_or_else(|| {
|
||||
self.default_project
|
||||
.get_mut(self.index.as_ref(), &self.native_system)
|
||||
}),
|
||||
AnySystemPath::System(system_path) => {
|
||||
let range = ..=system_path.to_path_buf();
|
||||
|
||||
// Using `range` here to work around a borrow checker limitation
|
||||
// where it can't prove that the `range_mut` call and the `self.projects.values_mut`
|
||||
// never borrow `self.projects` mutably at the same time.
|
||||
// https://rust-lang.github.io/rfcs/2094-nll.html#problem-case-3-conditional-control-flow-across-functions
|
||||
if self.projects.range(range.clone()).next_back().is_some() {
|
||||
return self.projects.range_mut(range).next_back().unwrap().1;
|
||||
}
|
||||
|
||||
// TODO: Currently, ty only supports single workspaces but we need to figure out
|
||||
// which project to use when we support multiple projects (e.g. look for the first project
|
||||
// with an overlapping search path?)
|
||||
self.projects.values_mut().next().unwrap()
|
||||
}
|
||||
AnySystemPath::SystemVirtual(_virtual_path) => {
|
||||
// TODO: Currently, ty only supports single workspace but we need to figure out
|
||||
// which project should this virtual path belong to when there are multiple
|
||||
@@ -426,19 +427,14 @@ impl Session {
|
||||
.apply_changes(changes, overrides.as_ref())
|
||||
}
|
||||
|
||||
/// Returns a mutable iterator over all project databases that have been initialized to this point.
|
||||
///
|
||||
/// This iterator will only yield the default project database if it has been used.
|
||||
/// Returns a mutable iterator over all project databases.
|
||||
pub(crate) fn projects_mut(&mut self) -> impl Iterator<Item = &'_ mut ProjectDatabase> + '_ {
|
||||
self.project_states_mut().map(|project| &mut project.db)
|
||||
}
|
||||
|
||||
/// Returns a mutable iterator over all projects that have been initialized to this point.
|
||||
///
|
||||
/// This iterator will only yield the default project if it has been used.
|
||||
/// Returns a mutable iterator over all projects.
|
||||
pub(crate) fn project_states_mut(&mut self) -> impl Iterator<Item = &'_ mut ProjectState> + '_ {
|
||||
let default_project = self.default_project.try_get_mut();
|
||||
self.projects.values_mut().chain(default_project)
|
||||
self.projects.values_mut()
|
||||
}
|
||||
|
||||
pub(crate) fn initialize_workspaces(
|
||||
@@ -1245,64 +1241,6 @@ impl Workspace {
|
||||
}
|
||||
}
|
||||
|
||||
/// Thin wrapper around the default project database that ensures it only gets initialized
|
||||
/// when it's first accessed.
|
||||
///
|
||||
/// There are a few advantages to this:
|
||||
///
|
||||
/// 1. Salsa has a fast-path for query lookups for the first created database.
|
||||
/// We really want that to be the actual project database and not our fallback database.
|
||||
/// 2. The logs when the server starts can be confusing if it once shows it uses Python X (for the default db)
|
||||
/// but then has another log that it uses Python Y (for the actual project db).
|
||||
struct DefaultProject(std::sync::OnceLock<ProjectState>);
|
||||
|
||||
impl DefaultProject {
|
||||
pub(crate) fn new() -> Self {
|
||||
DefaultProject(std::sync::OnceLock::new())
|
||||
}
|
||||
|
||||
pub(crate) fn get(
|
||||
&self,
|
||||
index: Option<&Arc<Index>>,
|
||||
fallback_system: &Arc<dyn System + 'static + Send + Sync + RefUnwindSafe>,
|
||||
) -> &ProjectState {
|
||||
self.0.get_or_init(|| {
|
||||
tracing::info!("Initializing the default project");
|
||||
|
||||
let index = index.unwrap();
|
||||
let system = LSPSystem::new(index.clone(), fallback_system.clone());
|
||||
let metadata = ProjectMetadata::from_options(
|
||||
Options::default(),
|
||||
system.current_directory().to_path_buf(),
|
||||
None,
|
||||
MisconfigurationMode::UseDefault,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
ProjectState {
|
||||
db: ProjectDatabase::new(metadata, system).unwrap(),
|
||||
untracked_files_with_pushed_diagnostics: Vec::new(),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn get_mut(
|
||||
&mut self,
|
||||
index: Option<&Arc<Index>>,
|
||||
fallback_system: &Arc<dyn System + 'static + Send + Sync + RefUnwindSafe>,
|
||||
) -> &mut ProjectState {
|
||||
let _ = self.get(index, fallback_system);
|
||||
|
||||
// SAFETY: The `OnceLock` is guaranteed to be initialized at this point because
|
||||
// we called `get` above, which initializes it if it wasn't already.
|
||||
self.0.get_mut().unwrap()
|
||||
}
|
||||
|
||||
pub(crate) fn try_get_mut(&mut self) -> Option<&mut ProjectState> {
|
||||
self.0.get_mut()
|
||||
}
|
||||
}
|
||||
|
||||
/// A workspace diagnostic request that didn't yield any changes or diagnostic
|
||||
/// when it ran the last time.
|
||||
#[derive(Debug)]
|
||||
|
||||
Reference in New Issue
Block a user