mirror of
				https://github.com/rust-lang/rust-analyzer.git
				synced 2025-10-31 12:04:43 +00:00 
			
		
		
		
	Merge pull request #20689 from ShoyuVanilla/accurate-flycheck
fix: Make flycheck clearing dependency-aware
This commit is contained in:
		
						commit
						a196eba3eb
					
				
					 8 changed files with 213 additions and 43 deletions
				
			
		|  | @ -9,7 +9,7 @@ | ||||||
| use std::{cell::RefCell, io, mem, process::Command}; | use std::{cell::RefCell, io, mem, process::Command}; | ||||||
| 
 | 
 | ||||||
| use base_db::Env; | use base_db::Env; | ||||||
| use cargo_metadata::{Message, camino::Utf8Path}; | use cargo_metadata::{Message, PackageId, camino::Utf8Path}; | ||||||
| use cfg::CfgAtom; | use cfg::CfgAtom; | ||||||
| use itertools::Itertools; | use itertools::Itertools; | ||||||
| use la_arena::ArenaMap; | use la_arena::ArenaMap; | ||||||
|  | @ -18,6 +18,7 @@ use rustc_hash::{FxHashMap, FxHashSet}; | ||||||
| use serde::Deserialize as _; | use serde::Deserialize as _; | ||||||
| use stdx::never; | use stdx::never; | ||||||
| use toolchain::Tool; | use toolchain::Tool; | ||||||
|  | use triomphe::Arc; | ||||||
| 
 | 
 | ||||||
| use crate::{ | use crate::{ | ||||||
|     CargoConfig, CargoFeatures, CargoWorkspace, InvocationStrategy, ManifestPath, Package, Sysroot, |     CargoConfig, CargoFeatures, CargoWorkspace, InvocationStrategy, ManifestPath, Package, Sysroot, | ||||||
|  | @ -284,7 +285,7 @@ impl WorkspaceBuildScripts { | ||||||
|         // NB: Cargo.toml could have been modified between `cargo metadata` and
 |         // NB: Cargo.toml could have been modified between `cargo metadata` and
 | ||||||
|         // `cargo check`. We shouldn't assume that package ids we see here are
 |         // `cargo check`. We shouldn't assume that package ids we see here are
 | ||||||
|         // exactly those from `config`.
 |         // exactly those from `config`.
 | ||||||
|         let mut by_id: FxHashMap<String, Package> = FxHashMap::default(); |         let mut by_id: FxHashMap<Arc<PackageId>, Package> = FxHashMap::default(); | ||||||
|         for package in workspace.packages() { |         for package in workspace.packages() { | ||||||
|             outputs.insert(package, BuildScriptOutput::default()); |             outputs.insert(package, BuildScriptOutput::default()); | ||||||
|             by_id.insert(workspace[package].id.clone(), package); |             by_id.insert(workspace[package].id.clone(), package); | ||||||
|  | @ -323,7 +324,7 @@ impl WorkspaceBuildScripts { | ||||||
|         // ideally this would be something like:
 |         // ideally this would be something like:
 | ||||||
|         // with_output_for: impl FnMut(&str, dyn FnOnce(&mut BuildScriptOutput)),
 |         // with_output_for: impl FnMut(&str, dyn FnOnce(&mut BuildScriptOutput)),
 | ||||||
|         // but owned trait objects aren't a thing
 |         // but owned trait objects aren't a thing
 | ||||||
|         mut with_output_for: impl FnMut(&str, &mut dyn FnMut(&str, &mut BuildScriptOutput)), |         mut with_output_for: impl FnMut(&PackageId, &mut dyn FnMut(&str, &mut BuildScriptOutput)), | ||||||
|         progress: &dyn Fn(String), |         progress: &dyn Fn(String), | ||||||
|     ) -> io::Result<Option<String>> { |     ) -> io::Result<Option<String>> { | ||||||
|         let errors = RefCell::new(String::new()); |         let errors = RefCell::new(String::new()); | ||||||
|  | @ -346,7 +347,7 @@ impl WorkspaceBuildScripts { | ||||||
| 
 | 
 | ||||||
|                 match message { |                 match message { | ||||||
|                     Message::BuildScriptExecuted(mut message) => { |                     Message::BuildScriptExecuted(mut message) => { | ||||||
|                         with_output_for(&message.package_id.repr, &mut |name, data| { |                         with_output_for(&message.package_id, &mut |name, data| { | ||||||
|                             progress(format!("build script {name} run")); |                             progress(format!("build script {name} run")); | ||||||
|                             let cfgs = { |                             let cfgs = { | ||||||
|                                 let mut acc = Vec::new(); |                                 let mut acc = Vec::new(); | ||||||
|  | @ -377,7 +378,7 @@ impl WorkspaceBuildScripts { | ||||||
|                         }); |                         }); | ||||||
|                     } |                     } | ||||||
|                     Message::CompilerArtifact(message) => { |                     Message::CompilerArtifact(message) => { | ||||||
|                         with_output_for(&message.package_id.repr, &mut |name, data| { |                         with_output_for(&message.package_id, &mut |name, data| { | ||||||
|                             progress(format!("proc-macro {name} built")); |                             progress(format!("proc-macro {name} built")); | ||||||
|                             if data.proc_macro_dylib_path == ProcMacroDylibPath::NotBuilt { |                             if data.proc_macro_dylib_path == ProcMacroDylibPath::NotBuilt { | ||||||
|                                 data.proc_macro_dylib_path = ProcMacroDylibPath::NotProcMacro; |                                 data.proc_macro_dylib_path = ProcMacroDylibPath::NotProcMacro; | ||||||
|  |  | ||||||
|  | @ -5,7 +5,7 @@ use std::str::from_utf8; | ||||||
| 
 | 
 | ||||||
| use anyhow::Context; | use anyhow::Context; | ||||||
| use base_db::Env; | use base_db::Env; | ||||||
| use cargo_metadata::{CargoOpt, MetadataCommand}; | use cargo_metadata::{CargoOpt, MetadataCommand, PackageId}; | ||||||
| use la_arena::{Arena, Idx}; | use la_arena::{Arena, Idx}; | ||||||
| use paths::{AbsPath, AbsPathBuf, Utf8Path, Utf8PathBuf}; | use paths::{AbsPath, AbsPathBuf, Utf8Path, Utf8PathBuf}; | ||||||
| use rustc_hash::{FxHashMap, FxHashSet}; | use rustc_hash::{FxHashMap, FxHashSet}; | ||||||
|  | @ -14,6 +14,7 @@ use serde_json::from_value; | ||||||
| use span::Edition; | use span::Edition; | ||||||
| use stdx::process::spawn_with_streaming_output; | use stdx::process::spawn_with_streaming_output; | ||||||
| use toolchain::Tool; | use toolchain::Tool; | ||||||
|  | use triomphe::Arc; | ||||||
| 
 | 
 | ||||||
| use crate::cargo_config_file::make_lockfile_copy; | use crate::cargo_config_file::make_lockfile_copy; | ||||||
| use crate::{CfgOverrides, InvocationStrategy}; | use crate::{CfgOverrides, InvocationStrategy}; | ||||||
|  | @ -155,8 +156,8 @@ pub struct PackageData { | ||||||
|     pub features: FxHashMap<String, Vec<String>>, |     pub features: FxHashMap<String, Vec<String>>, | ||||||
|     /// List of features enabled on this package
 |     /// List of features enabled on this package
 | ||||||
|     pub active_features: Vec<String>, |     pub active_features: Vec<String>, | ||||||
|     /// String representation of package id
 |     /// Package id
 | ||||||
|     pub id: String, |     pub id: Arc<PackageId>, | ||||||
|     /// Authors as given in the `Cargo.toml`
 |     /// Authors as given in the `Cargo.toml`
 | ||||||
|     pub authors: Vec<String>, |     pub authors: Vec<String>, | ||||||
|     /// Description as given in the `Cargo.toml`
 |     /// Description as given in the `Cargo.toml`
 | ||||||
|  | @ -173,6 +174,10 @@ pub struct PackageData { | ||||||
|     pub rust_version: Option<semver::Version>, |     pub rust_version: Option<semver::Version>, | ||||||
|     /// The contents of [package.metadata.rust-analyzer]
 |     /// The contents of [package.metadata.rust-analyzer]
 | ||||||
|     pub metadata: RustAnalyzerPackageMetaData, |     pub metadata: RustAnalyzerPackageMetaData, | ||||||
|  |     /// If this package is a member of the workspace, store all direct and transitive
 | ||||||
|  |     /// dependencies as long as they are workspace members, to track dependency relationships
 | ||||||
|  |     /// between members.
 | ||||||
|  |     pub all_member_deps: Option<FxHashSet<Package>>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Deserialize, Default, Debug, Clone, Eq, PartialEq)] | #[derive(Deserialize, Default, Debug, Clone, Eq, PartialEq)] | ||||||
|  | @ -334,6 +339,8 @@ impl CargoWorkspace { | ||||||
|         let mut is_virtual_workspace = true; |         let mut is_virtual_workspace = true; | ||||||
|         let mut requires_rustc_private = false; |         let mut requires_rustc_private = false; | ||||||
| 
 | 
 | ||||||
|  |         let mut members = FxHashSet::default(); | ||||||
|  | 
 | ||||||
|         meta.packages.sort_by(|a, b| a.id.cmp(&b.id)); |         meta.packages.sort_by(|a, b| a.id.cmp(&b.id)); | ||||||
|         for meta_pkg in meta.packages { |         for meta_pkg in meta.packages { | ||||||
|             let cargo_metadata::Package { |             let cargo_metadata::Package { | ||||||
|  | @ -356,6 +363,7 @@ impl CargoWorkspace { | ||||||
|                 rust_version, |                 rust_version, | ||||||
|                 .. |                 .. | ||||||
|             } = meta_pkg; |             } = meta_pkg; | ||||||
|  |             let id = Arc::new(id); | ||||||
|             let meta = from_value::<PackageMetadata>(metadata).unwrap_or_default(); |             let meta = from_value::<PackageMetadata>(metadata).unwrap_or_default(); | ||||||
|             let edition = match edition { |             let edition = match edition { | ||||||
|                 cargo_metadata::Edition::E2015 => Edition::Edition2015, |                 cargo_metadata::Edition::E2015 => Edition::Edition2015, | ||||||
|  | @ -375,7 +383,7 @@ impl CargoWorkspace { | ||||||
|             let manifest = ManifestPath::try_from(AbsPathBuf::assert(manifest_path)).unwrap(); |             let manifest = ManifestPath::try_from(AbsPathBuf::assert(manifest_path)).unwrap(); | ||||||
|             is_virtual_workspace &= manifest != ws_manifest_path; |             is_virtual_workspace &= manifest != ws_manifest_path; | ||||||
|             let pkg = packages.alloc(PackageData { |             let pkg = packages.alloc(PackageData { | ||||||
|                 id: id.repr.clone(), |                 id: id.clone(), | ||||||
|                 name: name.to_string(), |                 name: name.to_string(), | ||||||
|                 version, |                 version, | ||||||
|                 manifest: manifest.clone(), |                 manifest: manifest.clone(), | ||||||
|  | @ -395,7 +403,11 @@ impl CargoWorkspace { | ||||||
|                 features: features.into_iter().collect(), |                 features: features.into_iter().collect(), | ||||||
|                 active_features: Vec::new(), |                 active_features: Vec::new(), | ||||||
|                 metadata: meta.rust_analyzer.unwrap_or_default(), |                 metadata: meta.rust_analyzer.unwrap_or_default(), | ||||||
|  |                 all_member_deps: None, | ||||||
|             }); |             }); | ||||||
|  |             if is_member { | ||||||
|  |                 members.insert(pkg); | ||||||
|  |             } | ||||||
|             let pkg_data = &mut packages[pkg]; |             let pkg_data = &mut packages[pkg]; | ||||||
|             requires_rustc_private |= pkg_data.metadata.rustc_private; |             requires_rustc_private |= pkg_data.metadata.rustc_private; | ||||||
|             pkg_by_id.insert(id, pkg); |             pkg_by_id.insert(id, pkg); | ||||||
|  | @ -440,6 +452,43 @@ impl CargoWorkspace { | ||||||
|                 .extend(node.features.into_iter().map(|it| it.to_string())); |                 .extend(node.features.into_iter().map(|it| it.to_string())); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         fn saturate_all_member_deps( | ||||||
|  |             packages: &mut Arena<PackageData>, | ||||||
|  |             to_visit: Package, | ||||||
|  |             visited: &mut FxHashSet<Package>, | ||||||
|  |             members: &FxHashSet<Package>, | ||||||
|  |         ) { | ||||||
|  |             let pkg_data = &mut packages[to_visit]; | ||||||
|  | 
 | ||||||
|  |             if !visited.insert(to_visit) { | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             let deps: Vec<_> = pkg_data | ||||||
|  |                 .dependencies | ||||||
|  |                 .iter() | ||||||
|  |                 .filter_map(|dep| { | ||||||
|  |                     let pkg = dep.pkg; | ||||||
|  |                     if members.contains(&pkg) { Some(pkg) } else { None } | ||||||
|  |                 }) | ||||||
|  |                 .collect(); | ||||||
|  | 
 | ||||||
|  |             let mut all_member_deps = FxHashSet::from_iter(deps.iter().copied()); | ||||||
|  |             for dep in deps { | ||||||
|  |                 saturate_all_member_deps(packages, dep, visited, members); | ||||||
|  |                 if let Some(transitives) = &packages[dep].all_member_deps { | ||||||
|  |                     all_member_deps.extend(transitives); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             packages[to_visit].all_member_deps = Some(all_member_deps); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         let mut visited = FxHashSet::default(); | ||||||
|  |         for member in members.iter() { | ||||||
|  |             saturate_all_member_deps(&mut packages, *member, &mut visited, &members); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         CargoWorkspace { |         CargoWorkspace { | ||||||
|             packages, |             packages, | ||||||
|             targets, |             targets, | ||||||
|  |  | ||||||
|  | @ -120,6 +120,29 @@ impl DiagnosticCollection { | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     pub(crate) fn clear_check_older_than_for_package( | ||||||
|  |         &mut self, | ||||||
|  |         flycheck_id: usize, | ||||||
|  |         package_id: Arc<PackageId>, | ||||||
|  |         generation: DiagnosticsGeneration, | ||||||
|  |     ) { | ||||||
|  |         let Some(check) = self.check.get_mut(flycheck_id) else { | ||||||
|  |             return; | ||||||
|  |         }; | ||||||
|  |         let package_id = Some(package_id); | ||||||
|  |         let Some((_, checks)) = check | ||||||
|  |             .per_package | ||||||
|  |             .extract_if(|k, v| *k == package_id && v.generation < generation) | ||||||
|  |             .next() | ||||||
|  |         else { | ||||||
|  |             return; | ||||||
|  |         }; | ||||||
|  |         self.changes.extend(checks.per_file.into_keys()); | ||||||
|  |         if let Some(fixes) = Arc::make_mut(&mut self.check_fixes).get_mut(flycheck_id) { | ||||||
|  |             fixes.remove(&package_id); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     pub(crate) fn clear_native_for(&mut self, file_id: FileId) { |     pub(crate) fn clear_native_for(&mut self, file_id: FileId) { | ||||||
|         self.native_syntax.remove(&file_id); |         self.native_syntax.remove(&file_id); | ||||||
|         self.native_semantic.remove(&file_id); |         self.native_semantic.remove(&file_id); | ||||||
|  |  | ||||||
|  | @ -180,17 +180,27 @@ impl FlycheckHandle { | ||||||
|     pub(crate) fn restart_workspace(&self, saved_file: Option<AbsPathBuf>) { |     pub(crate) fn restart_workspace(&self, saved_file: Option<AbsPathBuf>) { | ||||||
|         let generation = self.generation.fetch_add(1, Ordering::Relaxed) + 1; |         let generation = self.generation.fetch_add(1, Ordering::Relaxed) + 1; | ||||||
|         self.sender |         self.sender | ||||||
|             .send(StateChange::Restart { generation, package: None, saved_file, target: None }) |             .send(StateChange::Restart { | ||||||
|  |                 generation, | ||||||
|  |                 scope: FlycheckScope::Workspace, | ||||||
|  |                 saved_file, | ||||||
|  |                 target: None, | ||||||
|  |             }) | ||||||
|             .unwrap(); |             .unwrap(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Schedule a re-start of the cargo check worker to do a package wide check.
 |     /// Schedule a re-start of the cargo check worker to do a package wide check.
 | ||||||
|     pub(crate) fn restart_for_package(&self, package: String, target: Option<Target>) { |     pub(crate) fn restart_for_package( | ||||||
|  |         &self, | ||||||
|  |         package: Arc<PackageId>, | ||||||
|  |         target: Option<Target>, | ||||||
|  |         workspace_deps: Option<FxHashSet<Arc<PackageId>>>, | ||||||
|  |     ) { | ||||||
|         let generation = self.generation.fetch_add(1, Ordering::Relaxed) + 1; |         let generation = self.generation.fetch_add(1, Ordering::Relaxed) + 1; | ||||||
|         self.sender |         self.sender | ||||||
|             .send(StateChange::Restart { |             .send(StateChange::Restart { | ||||||
|                 generation, |                 generation, | ||||||
|                 package: Some(package), |                 scope: FlycheckScope::Package { package, workspace_deps }, | ||||||
|                 saved_file: None, |                 saved_file: None, | ||||||
|                 target, |                 target, | ||||||
|             }) |             }) | ||||||
|  | @ -213,8 +223,13 @@ impl FlycheckHandle { | ||||||
| 
 | 
 | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| pub(crate) enum ClearDiagnosticsKind { | pub(crate) enum ClearDiagnosticsKind { | ||||||
|     All, |     All(ClearScope), | ||||||
|     OlderThan(DiagnosticsGeneration), |     OlderThan(DiagnosticsGeneration, ClearScope), | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub(crate) enum ClearScope { | ||||||
|  |     Workspace, | ||||||
|     Package(Arc<PackageId>), |     Package(Arc<PackageId>), | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -275,10 +290,15 @@ pub(crate) enum Progress { | ||||||
|     DidFailToRestart(String), |     DidFailToRestart(String), | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | enum FlycheckScope { | ||||||
|  |     Workspace, | ||||||
|  |     Package { package: Arc<PackageId>, workspace_deps: Option<FxHashSet<Arc<PackageId>>> }, | ||||||
|  | } | ||||||
|  | 
 | ||||||
| enum StateChange { | enum StateChange { | ||||||
|     Restart { |     Restart { | ||||||
|         generation: DiagnosticsGeneration, |         generation: DiagnosticsGeneration, | ||||||
|         package: Option<String>, |         scope: FlycheckScope, | ||||||
|         saved_file: Option<AbsPathBuf>, |         saved_file: Option<AbsPathBuf>, | ||||||
|         target: Option<Target>, |         target: Option<Target>, | ||||||
|     }, |     }, | ||||||
|  | @ -298,6 +318,7 @@ struct FlycheckActor { | ||||||
|     /// or the project root of the project.
 |     /// or the project root of the project.
 | ||||||
|     root: Arc<AbsPathBuf>, |     root: Arc<AbsPathBuf>, | ||||||
|     sysroot_root: Option<AbsPathBuf>, |     sysroot_root: Option<AbsPathBuf>, | ||||||
|  |     scope: FlycheckScope, | ||||||
|     /// CargoHandle exists to wrap around the communication needed to be able to
 |     /// CargoHandle exists to wrap around the communication needed to be able to
 | ||||||
|     /// run `cargo check` without blocking. Currently the Rust standard library
 |     /// run `cargo check` without blocking. Currently the Rust standard library
 | ||||||
|     /// doesn't provide a way to read sub-process output without blocking, so we
 |     /// doesn't provide a way to read sub-process output without blocking, so we
 | ||||||
|  | @ -343,6 +364,7 @@ impl FlycheckActor { | ||||||
|             config, |             config, | ||||||
|             sysroot_root, |             sysroot_root, | ||||||
|             root: Arc::new(workspace_root), |             root: Arc::new(workspace_root), | ||||||
|  |             scope: FlycheckScope::Workspace, | ||||||
|             manifest_path, |             manifest_path, | ||||||
|             command_handle: None, |             command_handle: None, | ||||||
|             command_receiver: None, |             command_receiver: None, | ||||||
|  | @ -376,7 +398,7 @@ impl FlycheckActor { | ||||||
|                 } |                 } | ||||||
|                 Event::RequestStateChange(StateChange::Restart { |                 Event::RequestStateChange(StateChange::Restart { | ||||||
|                     generation, |                     generation, | ||||||
|                     package, |                     scope, | ||||||
|                     saved_file, |                     saved_file, | ||||||
|                     target, |                     target, | ||||||
|                 }) => { |                 }) => { | ||||||
|  | @ -389,11 +411,11 @@ impl FlycheckActor { | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
| 
 | 
 | ||||||
|  |                     let command = self.check_command(&scope, saved_file.as_deref(), target); | ||||||
|  |                     self.scope = scope; | ||||||
|                     self.generation = generation; |                     self.generation = generation; | ||||||
| 
 | 
 | ||||||
|                     let Some(command) = |                     let Some(command) = command else { | ||||||
|                         self.check_command(package.as_deref(), saved_file.as_deref(), target) |  | ||||||
|                     else { |  | ||||||
|                         continue; |                         continue; | ||||||
|                     }; |                     }; | ||||||
| 
 | 
 | ||||||
|  | @ -435,19 +457,55 @@ impl FlycheckActor { | ||||||
|                         tracing::trace!(flycheck_id = self.id, "clearing diagnostics"); |                         tracing::trace!(flycheck_id = self.id, "clearing diagnostics"); | ||||||
|                         // We finished without receiving any diagnostics.
 |                         // We finished without receiving any diagnostics.
 | ||||||
|                         // Clear everything for good measure
 |                         // Clear everything for good measure
 | ||||||
|                         self.send(FlycheckMessage::ClearDiagnostics { |                         match &self.scope { | ||||||
|                             id: self.id, |                             FlycheckScope::Workspace => { | ||||||
|                             kind: ClearDiagnosticsKind::All, |                                 self.send(FlycheckMessage::ClearDiagnostics { | ||||||
|                         }); |                                     id: self.id, | ||||||
|  |                                     kind: ClearDiagnosticsKind::All(ClearScope::Workspace), | ||||||
|  |                                 }); | ||||||
|  |                             } | ||||||
|  |                             FlycheckScope::Package { package, workspace_deps } => { | ||||||
|  |                                 for pkg in | ||||||
|  |                                     std::iter::once(package).chain(workspace_deps.iter().flatten()) | ||||||
|  |                                 { | ||||||
|  |                                     self.send(FlycheckMessage::ClearDiagnostics { | ||||||
|  |                                         id: self.id, | ||||||
|  |                                         kind: ClearDiagnosticsKind::All(ClearScope::Package( | ||||||
|  |                                             pkg.clone(), | ||||||
|  |                                         )), | ||||||
|  |                                     }); | ||||||
|  |                                 } | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|                     } else if res.is_ok() { |                     } else if res.is_ok() { | ||||||
|                         // We clear diagnostics for packages on
 |                         // We clear diagnostics for packages on
 | ||||||
|                         // `[CargoCheckMessage::CompilerArtifact]` but there seem to be setups where
 |                         // `[CargoCheckMessage::CompilerArtifact]` but there seem to be setups where
 | ||||||
|                         // cargo may not report an artifact to our runner at all. To handle such
 |                         // cargo may not report an artifact to our runner at all. To handle such
 | ||||||
|                         // cases, clear stale diagnostics when flycheck completes successfully.
 |                         // cases, clear stale diagnostics when flycheck completes successfully.
 | ||||||
|                         self.send(FlycheckMessage::ClearDiagnostics { |                         match &self.scope { | ||||||
|                             id: self.id, |                             FlycheckScope::Workspace => { | ||||||
|                             kind: ClearDiagnosticsKind::OlderThan(self.generation), |                                 self.send(FlycheckMessage::ClearDiagnostics { | ||||||
|                         }); |                                     id: self.id, | ||||||
|  |                                     kind: ClearDiagnosticsKind::OlderThan( | ||||||
|  |                                         self.generation, | ||||||
|  |                                         ClearScope::Workspace, | ||||||
|  |                                     ), | ||||||
|  |                                 }); | ||||||
|  |                             } | ||||||
|  |                             FlycheckScope::Package { package, workspace_deps } => { | ||||||
|  |                                 for pkg in | ||||||
|  |                                     std::iter::once(package).chain(workspace_deps.iter().flatten()) | ||||||
|  |                                 { | ||||||
|  |                                     self.send(FlycheckMessage::ClearDiagnostics { | ||||||
|  |                                         id: self.id, | ||||||
|  |                                         kind: ClearDiagnosticsKind::OlderThan( | ||||||
|  |                                             self.generation, | ||||||
|  |                                             ClearScope::Package(pkg.clone()), | ||||||
|  |                                         ), | ||||||
|  |                                     }); | ||||||
|  |                                 } | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|                     } |                     } | ||||||
|                     self.clear_diagnostics_state(); |                     self.clear_diagnostics_state(); | ||||||
| 
 | 
 | ||||||
|  | @ -475,7 +533,7 @@ impl FlycheckActor { | ||||||
|                             ); |                             ); | ||||||
|                             self.send(FlycheckMessage::ClearDiagnostics { |                             self.send(FlycheckMessage::ClearDiagnostics { | ||||||
|                                 id: self.id, |                                 id: self.id, | ||||||
|                                 kind: ClearDiagnosticsKind::Package(package_id), |                                 kind: ClearDiagnosticsKind::All(ClearScope::Package(package_id)), | ||||||
|                             }); |                             }); | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
|  | @ -498,7 +556,9 @@ impl FlycheckActor { | ||||||
|                                 ); |                                 ); | ||||||
|                                 self.send(FlycheckMessage::ClearDiagnostics { |                                 self.send(FlycheckMessage::ClearDiagnostics { | ||||||
|                                     id: self.id, |                                     id: self.id, | ||||||
|                                     kind: ClearDiagnosticsKind::Package(package_id.clone()), |                                     kind: ClearDiagnosticsKind::All(ClearScope::Package( | ||||||
|  |                                         package_id.clone(), | ||||||
|  |                                     )), | ||||||
|                                 }); |                                 }); | ||||||
|                             } |                             } | ||||||
|                         } else if self.diagnostics_received |                         } else if self.diagnostics_received | ||||||
|  | @ -507,7 +567,7 @@ impl FlycheckActor { | ||||||
|                             self.diagnostics_received = DiagnosticsReceived::YesAndClearedForAll; |                             self.diagnostics_received = DiagnosticsReceived::YesAndClearedForAll; | ||||||
|                             self.send(FlycheckMessage::ClearDiagnostics { |                             self.send(FlycheckMessage::ClearDiagnostics { | ||||||
|                                 id: self.id, |                                 id: self.id, | ||||||
|                                 kind: ClearDiagnosticsKind::All, |                                 kind: ClearDiagnosticsKind::All(ClearScope::Workspace), | ||||||
|                             }); |                             }); | ||||||
|                         } |                         } | ||||||
|                         self.send(FlycheckMessage::AddDiagnostic { |                         self.send(FlycheckMessage::AddDiagnostic { | ||||||
|  | @ -548,7 +608,7 @@ impl FlycheckActor { | ||||||
|     /// return None.
 |     /// return None.
 | ||||||
|     fn check_command( |     fn check_command( | ||||||
|         &self, |         &self, | ||||||
|         package: Option<&str>, |         scope: &FlycheckScope, | ||||||
|         saved_file: Option<&AbsPath>, |         saved_file: Option<&AbsPath>, | ||||||
|         target: Option<Target>, |         target: Option<Target>, | ||||||
|     ) -> Option<Command> { |     ) -> Option<Command> { | ||||||
|  | @ -564,9 +624,9 @@ impl FlycheckActor { | ||||||
|                 } |                 } | ||||||
|                 cmd.arg(command); |                 cmd.arg(command); | ||||||
| 
 | 
 | ||||||
|                 match package { |                 match scope { | ||||||
|                     Some(pkg) => cmd.arg("-p").arg(pkg), |                     FlycheckScope::Workspace => cmd.arg("--workspace"), | ||||||
|                     None => cmd.arg("--workspace"), |                     FlycheckScope::Package { package, .. } => cmd.arg("-p").arg(&package.repr), | ||||||
|                 }; |                 }; | ||||||
| 
 | 
 | ||||||
|                 if let Some(tgt) = target { |                 if let Some(tgt) = target { | ||||||
|  |  | ||||||
|  | @ -9,6 +9,7 @@ use std::{ | ||||||
|     time::{Duration, Instant}, |     time::{Duration, Instant}, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | use cargo_metadata::PackageId; | ||||||
| use crossbeam_channel::{Receiver, Sender, unbounded}; | use crossbeam_channel::{Receiver, Sender, unbounded}; | ||||||
| use hir::ChangeWithProcMacros; | use hir::ChangeWithProcMacros; | ||||||
| use ide::{Analysis, AnalysisHost, Cancellable, FileId, SourceRootId}; | use ide::{Analysis, AnalysisHost, Cancellable, FileId, SourceRootId}; | ||||||
|  | @ -784,6 +785,7 @@ impl GlobalStateSnapshot { | ||||||
|                         cargo_toml: package_data.manifest.clone(), |                         cargo_toml: package_data.manifest.clone(), | ||||||
|                         crate_id, |                         crate_id, | ||||||
|                         package: cargo.package_flag(package_data), |                         package: cargo.package_flag(package_data), | ||||||
|  |                         package_id: package_data.id.clone(), | ||||||
|                         target: target_data.name.clone(), |                         target: target_data.name.clone(), | ||||||
|                         target_kind: target_data.kind, |                         target_kind: target_data.kind, | ||||||
|                         required_features: target_data.required_features.clone(), |                         required_features: target_data.required_features.clone(), | ||||||
|  | @ -812,6 +814,27 @@ impl GlobalStateSnapshot { | ||||||
|         None |         None | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     pub(crate) fn all_workspace_dependencies_for_package( | ||||||
|  |         &self, | ||||||
|  |         package: &Arc<PackageId>, | ||||||
|  |     ) -> Option<FxHashSet<Arc<PackageId>>> { | ||||||
|  |         for workspace in self.workspaces.iter() { | ||||||
|  |             match &workspace.kind { | ||||||
|  |                 ProjectWorkspaceKind::Cargo { cargo, .. } | ||||||
|  |                 | ProjectWorkspaceKind::DetachedFile { cargo: Some((cargo, _, _)), .. } => { | ||||||
|  |                     let package = cargo.packages().find(|p| cargo[*p].id == *package)?; | ||||||
|  | 
 | ||||||
|  |                     return cargo[package] | ||||||
|  |                         .all_member_deps | ||||||
|  |                         .as_ref() | ||||||
|  |                         .map(|deps| deps.iter().map(|dep| cargo[*dep].id.clone()).collect()); | ||||||
|  |                 } | ||||||
|  |                 _ => {} | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         None | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     pub(crate) fn file_exists(&self, file_id: FileId) -> bool { |     pub(crate) fn file_exists(&self, file_id: FileId) -> bool { | ||||||
|         self.vfs.read().0.exists(file_id) |         self.vfs.read().0.exists(file_id) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -331,7 +331,7 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool { | ||||||
|                         let target = TargetSpec::for_file(&world, file_id)?.and_then(|it| { |                         let target = TargetSpec::for_file(&world, file_id)?.and_then(|it| { | ||||||
|                             let tgt_kind = it.target_kind(); |                             let tgt_kind = it.target_kind(); | ||||||
|                             let (tgt_name, root, package) = match it { |                             let (tgt_name, root, package) = match it { | ||||||
|                                 TargetSpec::Cargo(c) => (c.target, c.workspace_root, c.package), |                                 TargetSpec::Cargo(c) => (c.target, c.workspace_root, c.package_id), | ||||||
|                                 _ => return None, |                                 _ => return None, | ||||||
|                             }; |                             }; | ||||||
| 
 | 
 | ||||||
|  | @ -368,7 +368,13 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool { | ||||||
|                                         _ => false, |                                         _ => false, | ||||||
|                                     }); |                                     }); | ||||||
|                                 if let Some(idx) = package_workspace_idx { |                                 if let Some(idx) = package_workspace_idx { | ||||||
|                                     world.flycheck[idx].restart_for_package(package, target); |                                     let workspace_deps = | ||||||
|  |                                         world.all_workspace_dependencies_for_package(&package); | ||||||
|  |                                     world.flycheck[idx].restart_for_package( | ||||||
|  |                                         package, | ||||||
|  |                                         target, | ||||||
|  |                                         workspace_deps, | ||||||
|  |                                     ); | ||||||
|                                 } |                                 } | ||||||
|                             } |                             } | ||||||
|                         } |                         } | ||||||
|  |  | ||||||
|  | @ -20,7 +20,7 @@ use crate::{ | ||||||
|     config::Config, |     config::Config, | ||||||
|     diagnostics::{DiagnosticsGeneration, NativeDiagnosticsFetchKind, fetch_native_diagnostics}, |     diagnostics::{DiagnosticsGeneration, NativeDiagnosticsFetchKind, fetch_native_diagnostics}, | ||||||
|     discover::{DiscoverArgument, DiscoverCommand, DiscoverProjectMessage}, |     discover::{DiscoverArgument, DiscoverCommand, DiscoverProjectMessage}, | ||||||
|     flycheck::{self, ClearDiagnosticsKind, FlycheckMessage}, |     flycheck::{self, ClearDiagnosticsKind, ClearScope, FlycheckMessage}, | ||||||
|     global_state::{ |     global_state::{ | ||||||
|         FetchBuildDataResponse, FetchWorkspaceRequest, FetchWorkspaceResponse, GlobalState, |         FetchBuildDataResponse, FetchWorkspaceRequest, FetchWorkspaceResponse, GlobalState, | ||||||
|         file_id_to_url, url_to_file_id, |         file_id_to_url, url_to_file_id, | ||||||
|  | @ -1042,17 +1042,22 @@ impl GlobalState { | ||||||
|                     }; |                     }; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             FlycheckMessage::ClearDiagnostics { id, kind: ClearDiagnosticsKind::All } => { |  | ||||||
|                 self.diagnostics.clear_check(id) |  | ||||||
|             } |  | ||||||
|             FlycheckMessage::ClearDiagnostics { |             FlycheckMessage::ClearDiagnostics { | ||||||
|                 id, |                 id, | ||||||
|                 kind: ClearDiagnosticsKind::OlderThan(generation), |                 kind: ClearDiagnosticsKind::All(ClearScope::Workspace), | ||||||
|  |             } => self.diagnostics.clear_check(id), | ||||||
|  |             FlycheckMessage::ClearDiagnostics { | ||||||
|  |                 id, | ||||||
|  |                 kind: ClearDiagnosticsKind::All(ClearScope::Package(package_id)), | ||||||
|  |             } => self.diagnostics.clear_check_for_package(id, package_id), | ||||||
|  |             FlycheckMessage::ClearDiagnostics { | ||||||
|  |                 id, | ||||||
|  |                 kind: ClearDiagnosticsKind::OlderThan(generation, ClearScope::Workspace), | ||||||
|             } => self.diagnostics.clear_check_older_than(id, generation), |             } => self.diagnostics.clear_check_older_than(id, generation), | ||||||
|             FlycheckMessage::ClearDiagnostics { |             FlycheckMessage::ClearDiagnostics { | ||||||
|                 id, |                 id, | ||||||
|                 kind: ClearDiagnosticsKind::Package(package_id), |                 kind: ClearDiagnosticsKind::OlderThan(generation, ClearScope::Package(package_id)), | ||||||
|             } => self.diagnostics.clear_check_for_package(id, package_id), |             } => self.diagnostics.clear_check_older_than_for_package(id, package_id, generation), | ||||||
|             FlycheckMessage::Progress { id, progress } => { |             FlycheckMessage::Progress { id, progress } => { | ||||||
|                 let (state, message) = match progress { |                 let (state, message) = match progress { | ||||||
|                     flycheck::Progress::DidStart => (Progress::Begin, None), |                     flycheck::Progress::DidStart => (Progress::Begin, None), | ||||||
|  |  | ||||||
|  | @ -2,12 +2,14 @@ | ||||||
| 
 | 
 | ||||||
| use std::mem; | use std::mem; | ||||||
| 
 | 
 | ||||||
|  | use cargo_metadata::PackageId; | ||||||
| use cfg::{CfgAtom, CfgExpr}; | use cfg::{CfgAtom, CfgExpr}; | ||||||
| use hir::sym; | use hir::sym; | ||||||
| use ide::{Cancellable, Crate, FileId, RunnableKind, TestId}; | use ide::{Cancellable, Crate, FileId, RunnableKind, TestId}; | ||||||
| use project_model::project_json::Runnable; | use project_model::project_json::Runnable; | ||||||
| use project_model::{CargoFeatures, ManifestPath, TargetKind}; | use project_model::{CargoFeatures, ManifestPath, TargetKind}; | ||||||
| use rustc_hash::FxHashSet; | use rustc_hash::FxHashSet; | ||||||
|  | use triomphe::Arc; | ||||||
| use vfs::AbsPathBuf; | use vfs::AbsPathBuf; | ||||||
| 
 | 
 | ||||||
| use crate::global_state::GlobalStateSnapshot; | use crate::global_state::GlobalStateSnapshot; | ||||||
|  | @ -52,6 +54,7 @@ pub(crate) struct CargoTargetSpec { | ||||||
|     pub(crate) workspace_root: AbsPathBuf, |     pub(crate) workspace_root: AbsPathBuf, | ||||||
|     pub(crate) cargo_toml: ManifestPath, |     pub(crate) cargo_toml: ManifestPath, | ||||||
|     pub(crate) package: String, |     pub(crate) package: String, | ||||||
|  |     pub(crate) package_id: Arc<PackageId>, | ||||||
|     pub(crate) target: String, |     pub(crate) target: String, | ||||||
|     pub(crate) target_kind: TargetKind, |     pub(crate) target_kind: TargetKind, | ||||||
|     pub(crate) crate_id: Crate, |     pub(crate) crate_id: Crate, | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 David Barsky
						David Barsky