1 //! lint on multiple versions of a crate being used
3 use cargo_metadata
::{DependencyKind, Metadata, Node, Package, PackageId}
;
4 use clippy_utils
::diagnostics
::span_lint
;
5 use if_chain
::if_chain
;
6 use itertools
::Itertools
;
7 use rustc_hir
::def_id
::LOCAL_CRATE
;
8 use rustc_lint
::LateContext
;
9 use rustc_span
::source_map
::DUMMY_SP
;
11 use super::MULTIPLE_CRATE_VERSIONS
;
13 pub(super) fn check(cx
: &LateContext
<'_
>, metadata
: &Metadata
) {
14 let local_name
= cx
.tcx
.crate_name(LOCAL_CRATE
);
15 let mut packages
= metadata
.packages
.clone();
16 packages
.sort_by(|a
, b
| a
.name
.cmp(&b
.name
));
19 if let Some(resolve
) = &metadata
.resolve
;
20 if let Some(local_id
) = packages
22 .find_map(|p
| if p
.name
== local_name
.as_str() { Some(&p.id) }
else { None }
);
24 for (name
, group
) in &packages
.iter().group_by(|p
| p
.name
.clone()) {
25 let group
: Vec
<&Package
> = group
.collect();
31 if group
.iter().all(|p
| is_normal_dep(&resolve
.nodes
, local_id
, &p
.id
)) {
32 let mut versions
: Vec
<_
> = group
.into_iter().map(|p
| &p
.version
).collect();
34 let versions
= versions
.iter().join(", ");
38 MULTIPLE_CRATE_VERSIONS
,
40 &format
!("multiple versions for dependency `{name}`: {versions}"),
48 fn is_normal_dep(nodes
: &[Node
], local_id
: &PackageId
, dep_id
: &PackageId
) -> bool
{
49 fn depends_on(node
: &Node
, dep_id
: &PackageId
) -> bool
{
50 node
.deps
.iter().any(|dep
| {
55 .any(|info
| matches
!(info
.kind
, DependencyKind
::Normal
))
61 .filter(|node
| depends_on(node
, dep_id
))
62 .any(|node
| node
.id
== *local_id
|| is_normal_dep(nodes
, local_id
, &node
.id
))