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
115
116
117
118
119
120
121
use serde::ser::{SerializeStruct, Serializer};
use serde::Serialize;
use std::fmt;
use tree_sitter::Node;
use super::cyclomatic;
use super::halstead;
use super::loc;
use crate::checker::Checker;
use crate::*;
#[derive(Default, Debug)]
pub struct Stats {
halstead_length: f64,
halstead_vocabulary: f64,
halstead_volume: f64,
cyclomatic: f64,
sloc: f64,
comments_percentage: f64,
}
impl Serialize for Stats {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut st = serializer.serialize_struct("maintanability_index", 3)?;
st.serialize_field("mi_original", &self.mi_original())?;
st.serialize_field("mi_sei", &self.mi_sei())?;
st.serialize_field("mi_visual_studio", &self.mi_visual_studio())?;
st.end()
}
}
impl fmt::Display for Stats {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"mi_original: {}, mi_sei: {}, mi_visual_studio: {}",
self.mi_original(),
self.mi_sei(),
self.mi_visual_studio()
)
}
}
impl Stats {
pub fn merge(&mut self, other: &Stats) {
self.halstead_length += other.halstead_length;
self.halstead_vocabulary += other.halstead_vocabulary;
self.halstead_volume = self.halstead_length * self.halstead_vocabulary.log2();
}
#[inline(always)]
pub fn mi_original(&self) -> f64 {
171.0 - 5.2 * (self.halstead_volume).ln() - 0.23 * self.cyclomatic - 16.2 * self.sloc.ln()
}
#[inline(always)]
pub fn mi_sei(&self) -> f64 {
171.0 - 5.2 * self.halstead_volume.log2() - 0.23 * self.cyclomatic - 16.2 * self.sloc.log2()
+ 50.0 * (self.comments_percentage * 2.4).sqrt().sin()
}
#[inline(always)]
pub fn mi_visual_studio(&self) -> f64 {
let formula = 171.0
- 5.2 * self.halstead_volume.ln()
- 0.23 * self.cyclomatic
- 16.2 * self.sloc.ln();
(formula * 100.0 / 171.0).max(0.)
}
}
#[doc(hidden)]
pub trait Mi
where
Self: Checker,
{
fn compute<'a>(
_node: &Node<'a>,
loc: &loc::Stats,
cyclomatic: &cyclomatic::Stats,
halstead: &halstead::Stats<'a>,
stats: &mut Stats,
) {
stats.halstead_length = halstead.length();
stats.halstead_vocabulary = halstead.vocabulary();
stats.halstead_volume = halstead.volume();
stats.cyclomatic = cyclomatic.cyclomatic();
stats.sloc = loc.sloc();
stats.comments_percentage = loc.cloc() / stats.sloc;
}
}
impl Mi for RustCode {}
impl Mi for CppCode {}
impl Mi for PythonCode {}
impl Mi for MozjsCode {}
impl Mi for JavascriptCode {}
impl Mi for TypescriptCode {}
impl Mi for TsxCode {}
impl Mi for PreprocCode {}
impl Mi for CcommentCode {}
impl Mi for CSharpCode {}
impl Mi for JavaCode {}
impl Mi for GoCode {}
impl Mi for CssCode {}
impl Mi for HtmlCode {}