1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
//! Complexity signals for editors, from the same threshold rule as
//! `fallow health`.
use std::path::PathBuf;
use fallow_config::{ResolvedConfig, Severity};
use fallow_types::discover::DiscoveredFile;
use super::threshold_overrides::{GlobalHealthThresholds, ThresholdOverrideResolver};
use crate::source::ModuleInfo;
/// One function above a complexity threshold, for an editor code lens.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct InlineComplexity {
/// Absolute path of the file that declares the function.
pub path: PathBuf,
/// Function name as extracted from the source.
pub name: String,
/// One-based line of the function declaration.
pub line: u32,
/// Zero-based column of the function declaration.
pub col: u32,
/// Measured cyclomatic complexity.
pub cyclomatic: u16,
/// Measured cognitive complexity.
pub cognitive: u16,
/// The function is above the effective cyclomatic threshold.
pub exceeds_cyclomatic: bool,
/// The function is above the effective cognitive threshold.
pub exceeds_cognitive: bool,
}
/// The functions of the parsed modules that are above a complexity threshold.
///
/// This applies the rules of the `fallow health` findings: `health.ignore`,
/// the `complexity` suppression comments, the module-scope unit that never
/// becomes a finding, and the effective thresholds of `health.thresholdOverrides`
/// per file and function. It also applies the `complexity-cyclomatic` and
/// `complexity-cognitive` rules with `overrides[].rules` for the file: a
/// function whose cyclomatic and cognitive kinds are all `off` is dropped.
///
/// A lens covers only the cyclomatic and cognitive kinds. It has no CRAP
/// score, so `complexity-crap` has no effect here. A function that the health
/// report flags only through CRAP, or whose cyclomatic and cognitive rules are
/// `off` while its CRAP rule is on, has a health finding but no lens.
#[must_use]
pub fn inline_complexity(
config: &ResolvedConfig,
modules: &[ModuleInfo],
files: &[DiscoveredFile],
) -> Vec<InlineComplexity> {
let file_paths: rustc_hash::FxHashMap<_, _> =
files.iter().map(|file| (file.id, &file.path)).collect();
let ignore_set = super::ignore::build_ignore_set(&config.health.ignore);
let resolver = ThresholdOverrideResolver::new(
&config.health.threshold_overrides,
GlobalHealthThresholds {
cyclomatic: config.health.max_cyclomatic,
cognitive: config.health.max_cognitive,
crap: config.health.max_crap,
unit_size: config.health.max_unit_size,
},
);
let mut findings = Vec::new();
for module in modules {
let Some(path) = file_paths.get(&module.file_id) else {
continue;
};
let relative = path.strip_prefix(&config.root).unwrap_or(path);
if ignore_set.is_match(relative) {
continue;
}
// The rules of this file, resolved one time for all of its functions.
let path_rules =
(!config.overrides.is_empty()).then(|| config.resolve_rules_for_path(path));
let rules = path_rules.as_ref().unwrap_or(&config.rules);
for function in &module.complexity {
if fallow_types::extract::is_synthetic_module_unit(&function.name)
|| crate::suppress::is_suppressed(
&module.suppressions,
function.line,
crate::suppress::IssueKind::Complexity,
)
{
continue;
}
let (applied, _) = resolver.resolve(relative, &function.name);
let Some((exceeds_cyclomatic, exceeds_cognitive)) =
super::findings::complexity_exceeded(function, applied.effective)
else {
continue;
};
// A lens has no CRAP score, so only the two kinds it shows count.
if rules.complexity_severity(exceeds_cyclomatic, exceeds_cognitive, false)
== Severity::Off
{
continue;
}
findings.push(InlineComplexity {
path: (*path).clone(),
name: function.name.clone(),
line: function.line,
col: function.col,
cyclomatic: function.cyclomatic,
cognitive: function.cognitive,
exceeds_cyclomatic,
exceeds_cognitive,
});
}
}
findings
}