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
//! `Checker` implementation for C#.
#![allow(clippy::wildcard_imports, clippy::enum_glob_use)]
use super::*;
impl Checker for CsharpCode {
fn is_comment(node: &Node) -> bool {
node.kind_id() == Csharp::Comment
}
// A bodied indexer (`this[int i] { get; set; }`) or property
// (`int X { get; set; }`) defers to its `accessor_declaration` children
// for its function spaces — counting it here too double-counts (property,
// #472) or triple-counts (indexer, #464) the member in nom/wmc. Only the
// accessor-less expression-bodied form (`this[int i] => _d[i];` /
// `int W => _w;`) opens a space directly, matching the npm `.max(1)`
// fallback and the way the implicit getter is the sole callable.
fn is_func_space(node: &Node) -> bool {
if matches!(
node.kind_id().into(),
Csharp::IndexerDeclaration | Csharp::PropertyDeclaration
) {
return !csharp_member_has_accessors(node);
}
matches!(
node.kind_id().into(),
Csharp::CompilationUnit
| Csharp::ClassDeclaration
| Csharp::StructDeclaration
| Csharp::RecordDeclaration
| Csharp::InterfaceDeclaration
| Csharp::EnumDeclaration
| Csharp::MethodDeclaration
| Csharp::ConstructorDeclaration
| Csharp::DestructorDeclaration
| Csharp::LocalFunctionStatement
| Csharp::LambdaExpression
| Csharp::AnonymousMethodExpression
| Csharp::AccessorDeclaration
| Csharp::OperatorDeclaration
| Csharp::ConversionOperatorDeclaration
)
}
fn is_func(node: &Node) -> bool {
if matches!(
node.kind_id().into(),
Csharp::IndexerDeclaration | Csharp::PropertyDeclaration
) {
return !csharp_member_has_accessors(node);
}
matches!(
node.kind_id().into(),
Csharp::MethodDeclaration
| Csharp::ConstructorDeclaration
| Csharp::DestructorDeclaration
| Csharp::LocalFunctionStatement
| Csharp::AccessorDeclaration
| Csharp::OperatorDeclaration
| Csharp::ConversionOperatorDeclaration
)
}
fn is_closure(node: &Node) -> bool {
matches!(
node.kind_id().into(),
Csharp::LambdaExpression | Csharp::AnonymousMethodExpression
)
}
fn is_call(node: &Node) -> bool {
// The C# grammar emits three aliased `kind_id`s for
// `invocation_expression`; matching only the unsuffixed variant
// silently drops the rest (lesson #2 in lessons_learned.md).
matches!(node.kind_id().into(), csharp_invocation_expr_kinds!())
}
fn is_non_arg(node: &Node) -> bool {
matches!(
node.kind_id().into(),
Csharp::LPAREN | Csharp::COMMA | Csharp::RPAREN
)
}
impl_simple_is_string!(
Csharp,
StringLiteral,
VerbatimStringLiteral,
RawStringLiteral,
InterpolatedStringExpression,
);
// tree-sitter-c-sharp models `else if` as an `Else` keyword token
// followed by a nested `if_statement` (no wrapping `else_clause` node).
impl_is_else_if_prev_sibling!(Csharp, IfStatement, Else);
#[inline]
fn is_primitive(node: &Node) -> bool {
// Without this, every `PredefinedType` keyword (`int`, `string`,
// `bool`, `object`, …) collapses into a single Halstead operator
// because they share one `kind_id`. Returning `true` here routes
// them through the lexeme-keyed `primitive_operators` map so
// distinct keywords count as distinct operators (issue #286).
node.kind_id() == Csharp::PredefinedType as u16
}
}