1 use clippy_utils
::diagnostics
::span_lint
;
3 use rustc_hir
::intravisit
::{walk_inf, walk_ty, NestedVisitorMap, Visitor}
;
4 use rustc_hir
::{GenericParamKind, TyKind}
;
5 use rustc_lint
::LateContext
;
6 use rustc_middle
::hir
::map
::Map
;
7 use rustc_target
::spec
::abi
::Abi
;
9 use super::TYPE_COMPLEXITY
;
11 pub(super) fn check(cx
: &LateContext
<'_
>, ty
: &hir
::Ty
<'_
>, type_complexity_threshold
: u64) -> bool
{
13 let mut visitor
= TypeComplexityVisitor { score: 0, nest: 1 }
;
18 if score
> type_complexity_threshold
{
23 "very complex type used. Consider factoring parts into `type` definitions",
31 /// Walks a type and assigns a complexity score to it.
32 struct TypeComplexityVisitor
{
33 /// total complexity score of the type
35 /// current nesting level
39 impl<'tcx
> Visitor
<'tcx
> for TypeComplexityVisitor
{
42 fn visit_infer(&mut self, inf
: &'tcx hir
::InferArg
) {
47 fn visit_ty(&mut self, ty
: &'tcx hir
::Ty
<'_
>) {
48 let (add_score
, sub_nest
) = match ty
.kind
{
49 // _, &x and *x have only small overhead; don't mess with nesting level
50 TyKind
::Infer
| TyKind
::Ptr(..) | TyKind
::Rptr(..) => (1, 0),
52 // the "normal" components of a type: named types, arrays/tuples
53 TyKind
::Path(..) | TyKind
::Slice(..) | TyKind
::Tup(..) | TyKind
::Array(..) => (10 * self.nest
, 1),
55 // function types bring a lot of overhead
56 TyKind
::BareFn(bare
) if bare
.abi
== Abi
::Rust
=> (50 * self.nest
, 1),
58 TyKind
::TraitObject(param_bounds
, _
, _
) => {
59 let has_lifetime_parameters
= param_bounds
.iter().any(|bound
| {
63 .any(|gen
| matches
!(gen
.kind
, GenericParamKind
::Lifetime { .. }
))
65 if has_lifetime_parameters
{
66 // complex trait bounds like A<'a, 'b>
69 // simple trait bounds like A + B
76 self.score
+= add_score
;
77 self.nest
+= sub_nest
;
79 self.nest
-= sub_nest
;
81 fn nested_visit_map(&mut self) -> NestedVisitorMap
<Self::Map
> {
82 NestedVisitorMap
::None