code-gauge 4.7.0 → 4.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/THIRD-PARTY-NOTICES.txt +595 -29
- package/dist/cli.cjs +1 -1
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +1 -1
- package/dist/cli.js.map +1 -1
- package/dist/cliConfig.cjs +1 -1
- package/dist/cliConfig.cjs.map +1 -1
- package/dist/cliConfig.js +1 -1
- package/dist/cliConfig.js.map +1 -1
- package/dist/crossFileDuplication.cjs +1 -1
- package/dist/crossFileDuplication.cjs.map +1 -1
- package/dist/crossFileDuplication.js +1 -1
- package/dist/crossFileDuplication.js.map +1 -1
- package/dist/crossFileNearMiss.cjs +1 -1
- package/dist/crossFileNearMiss.cjs.map +1 -1
- package/dist/crossFileNearMiss.js +1 -1
- package/dist/crossFileNearMiss.js.map +1 -1
- package/dist/diffCommand.cjs +3 -3
- package/dist/diffCommand.cjs.map +1 -1
- package/dist/diffCommand.js +3 -3
- package/dist/diffCommand.js.map +1 -1
- package/dist/duplicateSelection.cjs +1 -1
- package/dist/duplicateSelection.cjs.map +1 -1
- package/dist/duplicateSelection.js +1 -1
- package/dist/duplicateSelection.js.map +1 -1
- package/dist/duplication.cjs +1 -1
- package/dist/duplication.cjs.map +1 -1
- package/dist/duplication.js +1 -1
- package/dist/duplication.js.map +1 -1
- package/dist/git.cjs +1 -1
- package/dist/git.cjs.map +1 -1
- package/dist/git.js +1 -1
- package/dist/git.js.map +1 -1
- package/dist/languages.cjs +1 -1
- package/dist/languages.cjs.map +1 -1
- package/dist/languages.js +1 -1
- package/dist/languages.js.map +1 -1
- package/dist/metrics.cjs +1 -1
- package/dist/metrics.cjs.map +1 -1
- package/dist/metrics.d.ts +8 -3
- package/dist/metrics.js +1 -1
- package/dist/metrics.js.map +1 -1
- package/dist/nativeMetrics.cjs +3 -3
- package/dist/nativeMetrics.cjs.map +1 -1
- package/dist/nativeMetrics.d.ts +19 -3
- package/dist/nativeMetrics.js +3 -3
- package/dist/nativeMetrics.js.map +1 -1
- package/dist/regressionGate.cjs +1 -1
- package/dist/regressionGate.cjs.map +1 -1
- package/dist/regressionGate.js +1 -1
- package/dist/regressionGate.js.map +1 -1
- package/dist/scan.cjs +1 -1
- package/dist/scan.cjs.map +1 -1
- package/dist/scan.d.ts +2 -2
- package/dist/scan.js +1 -1
- package/dist/scan.js.map +1 -1
- package/dist/wasmBinding.cjs +1 -1
- package/dist/wasmBinding.cjs.map +1 -1
- package/dist/wasmBinding.js +1 -1
- package/dist/wasmBinding.js.map +1 -1
- package/native/Cargo.lock +48 -15
- package/native/Cargo.toml +11 -10
- package/native/code-gauge.wasm +0 -0
- package/native/src/complexity.rs +152 -255
- package/native/src/dep_degree.rs +79 -65
- package/native/src/duplication.rs +114 -97
- package/native/src/functions.rs +181 -206
- package/native/src/languages.rs +48 -7
- package/native/src/lib.rs +10 -5
- package/native/src/measure.rs +125 -150
- package/native/src/napi.rs +61 -2
- package/native/src/ncss.rs +108 -104
- package/native/src/near_miss.rs +7 -7
- package/native/src/tree_index.rs +119 -0
- package/native/src/util.rs +15 -55
- package/native/src/worker_pool.rs +53 -0
- package/package.json +10 -10
package/native/src/dep_degree.rs
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
use
|
|
1
|
+
use rustc_hash::{FxHashMap, FxHashSet};
|
|
2
2
|
use tree_sitter::Node;
|
|
3
3
|
|
|
4
4
|
use crate::complexity::is_function_boundary;
|
|
5
|
-
use crate::
|
|
5
|
+
use crate::tree_index::NodeExt;
|
|
6
|
+
use crate::util::{node_text, Source};
|
|
6
7
|
|
|
7
8
|
/// Leaf node types treated as variable references by the def-use approximation.
|
|
8
9
|
const VARIABLE_NODE_TYPES: &[&str] = &[
|
|
9
10
|
"identifier",
|
|
10
|
-
"simple_identifier",
|
|
11
|
-
"interpolated_identifier",
|
|
12
11
|
"implicit_parameter",
|
|
13
12
|
"instance_variable",
|
|
14
13
|
"class_variable",
|
|
@@ -50,18 +49,10 @@ const DEFINITION_FIELD_BY_PARENT_TYPE: &[(&str, &str)] = &[
|
|
|
50
49
|
("from_clause", "name"),
|
|
51
50
|
];
|
|
52
51
|
|
|
53
|
-
/// Kotlin
|
|
52
|
+
/// Kotlin marks no binding fields: an identifier directly under one of these declares a binding
|
|
54
53
|
/// (`val x`, `for (x in xs)`, lambda parameters, and the `catch (e: T)` exception name).
|
|
55
54
|
const KOTLIN_DEFINITION_PARENT_TYPES: &[&str] = &["variable_declaration", "catch_block"];
|
|
56
55
|
|
|
57
|
-
/// Kotlin parameter nodes whose identifier child is the declared name; the parameter LIST nodes
|
|
58
|
-
/// (`function_value_parameters`) also hold default-value expressions, which are reads.
|
|
59
|
-
const KOTLIN_PARAMETER_TYPES: &[&str] = &[
|
|
60
|
-
"parameter",
|
|
61
|
-
"parameter_with_optional_type",
|
|
62
|
-
"class_parameter",
|
|
63
|
-
];
|
|
64
|
-
|
|
65
56
|
/// C# LINQ clauses that bind a range variable as their first identifier child (no grammar field):
|
|
66
57
|
/// `join y in ...`, `into ys`, `let z = ...`, and a query continuation `into g`.
|
|
67
58
|
const CSHARP_QUERY_BINDING_PARENT_TYPES: &[&str] = &[
|
|
@@ -112,7 +103,7 @@ struct DepDegreeLeaf<'t> {
|
|
|
112
103
|
pub fn measure_dep_degree(
|
|
113
104
|
function_node: Node<'_>,
|
|
114
105
|
code: &Source<'_>,
|
|
115
|
-
function_nodes: &
|
|
106
|
+
function_nodes: &FxHashSet<&'static str>,
|
|
116
107
|
) -> u64 {
|
|
117
108
|
let mut leaves = Vec::new();
|
|
118
109
|
let mut next_scope_id = 0usize;
|
|
@@ -125,14 +116,14 @@ pub fn measure_dep_degree(
|
|
|
125
116
|
&mut leaves,
|
|
126
117
|
true,
|
|
127
118
|
);
|
|
128
|
-
let mut definition_scopes_by_name:
|
|
119
|
+
let mut definition_scopes_by_name: FxHashMap<&str, Vec<String>> = FxHashMap::default();
|
|
129
120
|
for name in implicit_accessor_definitions(function_node, code) {
|
|
130
121
|
add_definition(&mut definition_scopes_by_name, name, "");
|
|
131
122
|
}
|
|
132
123
|
let mut pairs = 0u64;
|
|
133
124
|
for index in 0..leaves.len() {
|
|
134
125
|
let leaf = &leaves[index];
|
|
135
|
-
if !is_variable_leaf(leaf
|
|
126
|
+
if !is_variable_leaf(leaf) {
|
|
136
127
|
continue;
|
|
137
128
|
}
|
|
138
129
|
let name = node_text(leaf.node, code);
|
|
@@ -160,22 +151,30 @@ pub fn measure_dep_degree(
|
|
|
160
151
|
|
|
161
152
|
/// A C++ member-pointer variable (`int C::* p`, also `int C::* arr[1]`) is declared as a
|
|
162
153
|
/// `type_identifier` under the `pointer_type_declarator` spelling `C::*`, possibly through further
|
|
163
|
-
/// declarator wrappers; every other `type_identifier` names a type, not a variable.
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
154
|
+
/// declarator wrappers; every other `type_identifier` names a type, not a variable. Kotlin spells
|
|
155
|
+
/// type names as identifiers: in a `user_type`, or as a type parameter's fieldless name (C# puts its
|
|
156
|
+
/// type parameter in a `name` field).
|
|
157
|
+
fn is_variable_leaf(leaf: &DepDegreeLeaf<'_>) -> bool {
|
|
158
|
+
let node = leaf.node;
|
|
159
|
+
if node.kind_name() == "type_identifier" {
|
|
160
|
+
return is_member_pointer_name(node);
|
|
161
|
+
}
|
|
162
|
+
VARIABLE_NODE_TYPES.contains(&node.kind_name())
|
|
163
|
+
&& !node.parent_node().is_some_and(|parent| {
|
|
164
|
+
parent.kind_name() == "user_type"
|
|
165
|
+
|| (parent.kind_name() == "type_parameter" && leaf.field_name.is_none())
|
|
166
|
+
})
|
|
168
167
|
}
|
|
169
168
|
|
|
170
169
|
fn is_member_pointer_name(node: Node<'_>) -> bool {
|
|
171
170
|
let mut current = node;
|
|
172
|
-
while let Some(parent) = current.
|
|
173
|
-
if parent.
|
|
171
|
+
while let Some(parent) = current.parent_node() {
|
|
172
|
+
if parent.kind_name() == "pointer_type_declarator" {
|
|
174
173
|
return true;
|
|
175
174
|
}
|
|
176
175
|
// The climb follows the declared-name position only, exactly like unwrap_declarator_wrappers.
|
|
177
|
-
if !DECLARATOR_WRAPPER_TYPES.contains(&parent.
|
|
178
|
-
|| parent.
|
|
176
|
+
if !DECLARATOR_WRAPPER_TYPES.contains(&parent.kind_name())
|
|
177
|
+
|| parent.kind_name() == "qualified_identifier"
|
|
179
178
|
|| field_name_in_parent(current, parent).is_some_and(|field| field != "declarator")
|
|
180
179
|
{
|
|
181
180
|
return false;
|
|
@@ -189,7 +188,7 @@ fn is_member_pointer_name(node: Node<'_>) -> bool {
|
|
|
189
188
|
/// indexer's parameters (including a `params` array, which the grammar names directly on the
|
|
190
189
|
/// parameter list) and, in a setter, initializer, or event accessor, the implicit `value`.
|
|
191
190
|
fn implicit_accessor_definitions<'a>(function_node: Node<'_>, code: &Source<'a>) -> Vec<&'a str> {
|
|
192
|
-
if function_node.
|
|
191
|
+
if function_node.kind_name() != "accessor_declaration" {
|
|
193
192
|
return Vec::new();
|
|
194
193
|
}
|
|
195
194
|
let mut names = Vec::new();
|
|
@@ -201,9 +200,11 @@ fn implicit_accessor_definitions<'a>(function_node: Node<'_>, code: &Source<'a>)
|
|
|
201
200
|
{
|
|
202
201
|
names.push("value");
|
|
203
202
|
}
|
|
204
|
-
let owner = function_node
|
|
203
|
+
let owner = function_node
|
|
204
|
+
.parent_node()
|
|
205
|
+
.and_then(|list| list.parent_node());
|
|
205
206
|
if let Some(parameters) = owner
|
|
206
|
-
.filter(|owner| owner.
|
|
207
|
+
.filter(|owner| owner.kind_name() == "indexer_declaration")
|
|
207
208
|
.and_then(|owner| owner.child_by_field_name("parameters"))
|
|
208
209
|
{
|
|
209
210
|
let declared = crate::util::named_children(parameters)
|
|
@@ -223,17 +224,17 @@ fn collect_dep_degree_leaves<'t>(
|
|
|
223
224
|
field_name: Option<&'static str>,
|
|
224
225
|
scope: &str,
|
|
225
226
|
next_scope_id: &mut usize,
|
|
226
|
-
function_nodes: &
|
|
227
|
+
function_nodes: &FxHashSet<&'static str>,
|
|
227
228
|
leaves: &mut Vec<DepDegreeLeaf<'t>>,
|
|
228
229
|
is_measured_root: bool,
|
|
229
230
|
) {
|
|
230
231
|
if matches!(
|
|
231
|
-
node.
|
|
232
|
-
"comment" | "line_comment" | "block_comment"
|
|
232
|
+
node.kind_name(),
|
|
233
|
+
"comment" | "line_comment" | "block_comment"
|
|
233
234
|
) {
|
|
234
235
|
return;
|
|
235
236
|
}
|
|
236
|
-
if
|
|
237
|
+
if node.child_count() == 0 {
|
|
237
238
|
leaves.push(DepDegreeLeaf {
|
|
238
239
|
node,
|
|
239
240
|
field_name,
|
|
@@ -268,7 +269,7 @@ fn collect_dep_degree_leaves<'t>(
|
|
|
268
269
|
}
|
|
269
270
|
|
|
270
271
|
fn add_definition<'a>(
|
|
271
|
-
definition_scopes_by_name: &mut
|
|
272
|
+
definition_scopes_by_name: &mut FxHashMap<&'a str, Vec<String>>,
|
|
272
273
|
name: &'a str,
|
|
273
274
|
scope: &str,
|
|
274
275
|
) {
|
|
@@ -291,37 +292,39 @@ fn is_definition_visible(definition_scopes: Option<&Vec<String>>, scope: &str) -
|
|
|
291
292
|
}
|
|
292
293
|
|
|
293
294
|
fn is_structural_definition(leaf: &DepDegreeLeaf<'_>) -> bool {
|
|
294
|
-
let Some(parent) = leaf.node.
|
|
295
|
+
let Some(parent) = leaf.node.parent_node() else {
|
|
295
296
|
return false;
|
|
296
297
|
};
|
|
297
|
-
|
|
298
|
-
|
|
298
|
+
// C#'s `variable_declaration` holds its type in the `type` field; Kotlin's bound name has none.
|
|
299
|
+
if leaf.node.kind_name() == "identifier"
|
|
300
|
+
&& leaf.field_name.is_none()
|
|
301
|
+
&& KOTLIN_DEFINITION_PARENT_TYPES.contains(&parent.kind_name())
|
|
299
302
|
{
|
|
300
303
|
return true;
|
|
301
304
|
}
|
|
302
|
-
if leaf.node.
|
|
303
|
-
&& CSHARP_QUERY_BINDING_PARENT_TYPES.contains(&parent.
|
|
305
|
+
if leaf.node.kind_name() == "identifier"
|
|
306
|
+
&& CSHARP_QUERY_BINDING_PARENT_TYPES.contains(&parent.kind_name())
|
|
304
307
|
&& crate::util::named_children(parent)
|
|
305
308
|
.into_iter()
|
|
306
|
-
.find(|child| child.
|
|
309
|
+
.find(|child| child.kind_name() == "identifier")
|
|
307
310
|
.is_some_and(|first| first.id() == leaf.node.id())
|
|
308
311
|
{
|
|
309
312
|
return true;
|
|
310
313
|
}
|
|
311
314
|
let (declared, declared_field) = unwrap_declarator_wrappers(leaf);
|
|
312
315
|
if declared
|
|
313
|
-
.
|
|
316
|
+
.parent_node()
|
|
314
317
|
.is_some_and(|holder| is_definition_field(holder, declared_field))
|
|
315
318
|
{
|
|
316
319
|
return true;
|
|
317
320
|
}
|
|
318
|
-
if !DEFINITION_LIST_NODE_TYPES.contains(&parent.
|
|
321
|
+
if !DEFINITION_LIST_NODE_TYPES.contains(&parent.kind_name()) {
|
|
319
322
|
return false;
|
|
320
323
|
}
|
|
321
|
-
let Some(holder) = parent.
|
|
324
|
+
let Some(holder) = parent.parent_node() else {
|
|
322
325
|
return false;
|
|
323
326
|
};
|
|
324
|
-
DEFINITION_LIST_HOLDER_TYPES.contains(&holder.
|
|
327
|
+
DEFINITION_LIST_HOLDER_TYPES.contains(&holder.kind_name())
|
|
325
328
|
&& field_name_in_parent(parent, holder) == Some("left")
|
|
326
329
|
}
|
|
327
330
|
|
|
@@ -329,7 +332,7 @@ fn is_definition_field(holder: Node<'_>, field_name: Option<&str>) -> bool {
|
|
|
329
332
|
DEFINITION_FIELD_BY_PARENT_TYPE
|
|
330
333
|
.iter()
|
|
331
334
|
.any(|(parent_type, definition_field)| {
|
|
332
|
-
*parent_type == holder.
|
|
335
|
+
*parent_type == holder.kind_name() && field_name == Some(definition_field)
|
|
333
336
|
})
|
|
334
337
|
}
|
|
335
338
|
|
|
@@ -342,10 +345,10 @@ fn unwrap_declarator_wrappers<'t>(leaf: &DepDegreeLeaf<'t>) -> (Node<'t>, Option
|
|
|
342
345
|
let mut current = leaf.node;
|
|
343
346
|
let mut field_name = leaf.field_name;
|
|
344
347
|
while let Some(parent) = current
|
|
345
|
-
.
|
|
346
|
-
.filter(|parent| DECLARATOR_WRAPPER_TYPES.contains(&parent.
|
|
348
|
+
.parent_node()
|
|
349
|
+
.filter(|parent| DECLARATOR_WRAPPER_TYPES.contains(&parent.kind_name()))
|
|
347
350
|
{
|
|
348
|
-
let declared_field = if parent.
|
|
351
|
+
let declared_field = if parent.kind_name() == "qualified_identifier" {
|
|
349
352
|
"name"
|
|
350
353
|
} else {
|
|
351
354
|
"declarator"
|
|
@@ -354,7 +357,7 @@ fn unwrap_declarator_wrappers<'t>(leaf: &DepDegreeLeaf<'t>) -> (Node<'t>, Option
|
|
|
354
357
|
break;
|
|
355
358
|
}
|
|
356
359
|
field_name = parent
|
|
357
|
-
.
|
|
360
|
+
.parent_node()
|
|
358
361
|
.and_then(|grandparent| field_name_in_parent(parent, grandparent));
|
|
359
362
|
current = parent;
|
|
360
363
|
}
|
|
@@ -365,18 +368,6 @@ fn unwrap_declarator_wrappers<'t>(leaf: &DepDegreeLeaf<'t>) -> (Node<'t>, Option
|
|
|
365
368
|
/// (C/C++ function-pointer or array parameters) is a parameter-ish node, or the identifier
|
|
366
369
|
/// directly occupies a parameter field; type annotations and default values bind nothing.
|
|
367
370
|
fn is_parameter_definition(leaf: &DepDegreeLeaf<'_>) -> bool {
|
|
368
|
-
// Kotlin has no `type`/`value` fields to veto default values: a function parameter's default
|
|
369
|
-
// sits in the parameter list (`fun f(b: Int = a)`), a class parameter's inside the parameter
|
|
370
|
-
// node (`class A(val y: Int = a)`), so only a parameter node's first identifier child binds.
|
|
371
|
-
if leaf.node.kind() == "simple_identifier" {
|
|
372
|
-
return leaf.node.parent().is_some_and(|parent| {
|
|
373
|
-
KOTLIN_PARAMETER_TYPES.contains(&parent.kind())
|
|
374
|
-
&& crate::util::named_children(parent)
|
|
375
|
-
.into_iter()
|
|
376
|
-
.find(|child| child.kind() == "simple_identifier")
|
|
377
|
-
.is_some_and(|first| first.id() == leaf.node.id())
|
|
378
|
-
});
|
|
379
|
-
}
|
|
380
371
|
let mut current = leaf.node;
|
|
381
372
|
let mut depth = 0usize;
|
|
382
373
|
// Only the member pointer's own declared name may climb past its qualified name; a size or
|
|
@@ -384,10 +375,23 @@ fn is_parameter_definition(leaf: &DepDegreeLeaf<'_>) -> bool {
|
|
|
384
375
|
let declares_member_pointer = is_member_pointer_name(leaf.node);
|
|
385
376
|
let mut in_member_pointer = false;
|
|
386
377
|
loop {
|
|
387
|
-
let Some(parent) = current.
|
|
378
|
+
let Some(parent) = current.parent_node() else {
|
|
388
379
|
return false;
|
|
389
380
|
};
|
|
390
|
-
|
|
381
|
+
// Kotlin has no `type`/`value` fields to veto default values: a function parameter's default
|
|
382
|
+
// sits in the parameter list (`fun f(b: Int = a)`), a class parameter's inside the parameter
|
|
383
|
+
// node (`class A(val y: Int = a)`), so only such a node's first identifier child binds.
|
|
384
|
+
if parent.kind_name() == "function_value_parameters" {
|
|
385
|
+
return false;
|
|
386
|
+
}
|
|
387
|
+
if is_kotlin_parameter(parent) {
|
|
388
|
+
return depth == 0
|
|
389
|
+
&& crate::util::named_children(parent)
|
|
390
|
+
.into_iter()
|
|
391
|
+
.find(|child| child.kind_name() == "identifier")
|
|
392
|
+
.is_some_and(|first| first.id() == leaf.node.id());
|
|
393
|
+
}
|
|
394
|
+
let parent_is_parameterish = parent.kind_name().contains("parameter");
|
|
391
395
|
// Beyond the grandparent, only declarator wrappers keep climbing, plus the
|
|
392
396
|
// `qualified_identifier` nodes that spell a member-pointer parameter's class (`int C::* q`,
|
|
393
397
|
// `int N::C::* q`) — entered from the pointer declarator and continued through the `name`
|
|
@@ -395,13 +399,13 @@ fn is_parameter_definition(leaf: &DepDegreeLeaf<'_>) -> bool {
|
|
|
395
399
|
// a read. Checking this before the field lookup also keeps reads inside high-arity nodes
|
|
396
400
|
// O(1).
|
|
397
401
|
let continues_member_pointer = declares_member_pointer
|
|
398
|
-
&& parent.
|
|
399
|
-
&& (current.
|
|
402
|
+
&& parent.kind_name() == "qualified_identifier"
|
|
403
|
+
&& (current.kind_name() == "pointer_type_declarator" || in_member_pointer)
|
|
400
404
|
&& field_name_in_parent(current, parent) == Some("name");
|
|
401
405
|
in_member_pointer = continues_member_pointer;
|
|
402
406
|
if depth >= 1
|
|
403
407
|
&& !parent_is_parameterish
|
|
404
|
-
&& !parent.
|
|
408
|
+
&& !parent.kind_name().contains("declarator")
|
|
405
409
|
&& !continues_member_pointer
|
|
406
410
|
{
|
|
407
411
|
return false;
|
|
@@ -424,6 +428,16 @@ fn is_parameter_definition(leaf: &DepDegreeLeaf<'_>) -> bool {
|
|
|
424
428
|
}
|
|
425
429
|
}
|
|
426
430
|
|
|
431
|
+
/// A Kotlin class parameter, or a setter's parameter list (`set(value)`; Ruby's `setter` is a method
|
|
432
|
+
/// name, never under a property).
|
|
433
|
+
fn is_kotlin_parameter(node: Node<'_>) -> bool {
|
|
434
|
+
node.kind_name() == "class_parameter"
|
|
435
|
+
|| (node.kind_name() == "setter"
|
|
436
|
+
&& node
|
|
437
|
+
.parent_node()
|
|
438
|
+
.is_some_and(|property| property.kind_name() == "property_declaration"))
|
|
439
|
+
}
|
|
440
|
+
|
|
427
441
|
/// Only called with small-arity parents (declarator wrappers, definition-list holders).
|
|
428
442
|
fn field_name_in_parent(node: Node<'_>, parent: Node<'_>) -> Option<&'static str> {
|
|
429
443
|
for index in 0..parent.child_count() {
|