/src/tools/clippy/clippy_lints/src/cargo/multiple_crate_versions.rs

https://gitlab.com/rust-lang/rust · Rust · 63 lines · 53 code · 9 blank · 1 comment · 12 complexity · dc55c8d08345390dbbfa2af211041f41 MD5 · raw file

  1. //! lint on multiple versions of a crate being used
  2. use cargo_metadata::{DependencyKind, Metadata, Node, Package, PackageId};
  3. use clippy_utils::diagnostics::span_lint;
  4. use if_chain::if_chain;
  5. use itertools::Itertools;
  6. use rustc_hir::def_id::LOCAL_CRATE;
  7. use rustc_lint::LateContext;
  8. use rustc_span::source_map::DUMMY_SP;
  9. use super::MULTIPLE_CRATE_VERSIONS;
  10. pub(super) fn check(cx: &LateContext<'_>, metadata: &Metadata) {
  11. let local_name = cx.tcx.crate_name(LOCAL_CRATE);
  12. let mut packages = metadata.packages.clone();
  13. packages.sort_by(|a, b| a.name.cmp(&b.name));
  14. if_chain! {
  15. if let Some(resolve) = &metadata.resolve;
  16. if let Some(local_id) = packages
  17. .iter()
  18. .find_map(|p| if p.name == local_name.as_str() { Some(&p.id) } else { None });
  19. then {
  20. for (name, group) in &packages.iter().group_by(|p| p.name.clone()) {
  21. let group: Vec<&Package> = group.collect();
  22. if group.len() <= 1 {
  23. continue;
  24. }
  25. if group.iter().all(|p| is_normal_dep(&resolve.nodes, local_id, &p.id)) {
  26. let mut versions: Vec<_> = group.into_iter().map(|p| &p.version).collect();
  27. versions.sort();
  28. let versions = versions.iter().join(", ");
  29. span_lint(
  30. cx,
  31. MULTIPLE_CRATE_VERSIONS,
  32. DUMMY_SP,
  33. &format!("multiple versions for dependency `{}`: {}", name, versions),
  34. );
  35. }
  36. }
  37. }
  38. }
  39. }
  40. fn is_normal_dep(nodes: &[Node], local_id: &PackageId, dep_id: &PackageId) -> bool {
  41. fn depends_on(node: &Node, dep_id: &PackageId) -> bool {
  42. node.deps.iter().any(|dep| {
  43. dep.pkg == *dep_id
  44. && dep
  45. .dep_kinds
  46. .iter()
  47. .any(|info| matches!(info.kind, DependencyKind::Normal))
  48. })
  49. }
  50. nodes
  51. .iter()
  52. .filter(|node| depends_on(node, dep_id))
  53. .any(|node| node.id == *local_id || is_normal_dep(nodes, local_id, &node.id))
  54. }