#![allow(clippy::wildcard_imports, clippy::enum_glob_use)]
use super::*;
const GENERIC_ANGLES: GenericAngleKinds = GenericAngleKinds {
lists: &[
Csharp::TypeArgumentList as u16,
Csharp::TypeParameterList as u16,
Csharp::FunctionPointerType as u16,
],
openers: &[Csharp::LT as u16],
closers: &[Csharp::GT as u16],
is_misparse: csharp_comparison_misparse,
};
fn csharp_comparison_misparse<'a>(list: &Node<'a>, ancestors: Ancestors<'a, '_>) -> bool {
let mut up = ancestors.iter(list).map(|(node, _)| node);
let Some(name) = up
.next()
.filter(|name| name.kind_id() == Csharp::GenericName as u16)
else {
return false;
};
let declaration = match up.next() {
Some(qualified) if qualified.kind_id() == Csharp::QualifiedName as u16 => {
if qualified
.child_by_field_name("name")
.is_none_or(|last| last.id() != name.id())
{
return false;
}
up.next()
}
parent => parent,
};
let (Some(declaration), Some(argument), Some(arguments)) = (declaration, up.next(), up.next())
else {
return false;
};
declaration.kind_id() == Csharp::DeclarationExpression as u16
&& argument.kind_id() == Csharp::Argument as u16
&& !argument.is_child(Csharp::Out as u16)
&& matches!(
arguments.kind_id().into(),
Csharp::ArgumentList | Csharp::BracketedArgumentList
)
}
fn is_interpolation_clause_delimiter<'a>(node: &Node<'a>, ancestors: Ancestors<'a, '_>) -> bool {
let clause = match node.kind_id().into() {
Csharp::COLON => Csharp::InterpolationFormatClause,
Csharp::COMMA => Csharp::InterpolationAlignmentClause,
_ => return false,
};
ancestors.parent_has_kind(node, clause as u16)
}
impl Getter for CsharpCode {
fn get_space_kind(node: &Node) -> SpaceKind {
use Csharp::*;
if matches!(
node.kind_id().into(),
IndexerDeclaration | PropertyDeclaration
) {
return if crate::checker::csharp_member_has_accessors(node) {
SpaceKind::Unknown
} else {
SpaceKind::Function
};
}
match node.kind_id().into() {
ClassDeclaration | StructDeclaration | RecordDeclaration | EnumDeclaration => {
SpaceKind::Class
}
InterfaceDeclaration => SpaceKind::Interface,
MethodDeclaration
| ConstructorDeclaration
| DestructorDeclaration
| LocalFunctionStatement
| LambdaExpression
| AnonymousMethodExpression
| AccessorDeclaration
| OperatorDeclaration
| ConversionOperatorDeclaration => SpaceKind::Function,
CompilationUnit => SpaceKind::Unit,
_ => SpaceKind::Unknown,
}
}
fn get_op_type<'a>(node: &Node<'a>, ancestors: Ancestors<'a, '_>) -> TokenRole {
use Csharp::*;
if GENERIC_ANGLES.is_closer(node, ancestors)
|| is_interpolation_clause_delimiter(node, ancestors)
{
return TokenRole::Unknown;
}
match node.kind_id().into() {
If | Else | Switch | Case | Default | Try | Catch | Finally | Throw
| Return | Yield | Break | Continue | Goto | For | Foreach | While | Do
| Class | Struct | Interface | Enum | Record | Delegate | Namespace | Using
| Public | Private | Protected | Internal | Static | Abstract | Virtual
| Override | Sealed | Partial | Readonly | Const | Extern | Unsafe
| Volatile | Async | Required | File | New | Fixed | Implicit | Explicit
| Await | Is | As | Typeof | Sizeof | Checked | Unchecked | Ref | Out | In
| Params | Lock | Stackalloc | Where | With | When | Operator
| Scoped | Not | And | Or
| Get | Set | Init | Add | Remove
| LBRACE | LBRACK | LPAREN | COMMA | SEMI | COLON | COLONCOLON | DOT
| DOTDOT | EQGT | DASHGT | QMARK
| EQ | EQEQ | BANGEQ | LT | GT | LTEQ | GTEQ
| PLUS | DASH | STAR | SLASH | PERCENT
| AMP | PIPE | CARET | TILDE | BANG
| AMPAMP | PIPEPIPE | QMARKQMARK
| LTLT | GTGT | GTGTGT
| PLUSPLUS | DASHDASH
| PLUSEQ | DASHEQ | STAREQ | SLASHEQ | PERCENTEQ
| AMPEQ | PIPEEQ | CARETEQ | LTLTEQ | GTGTEQ | GTGTGTEQ | QMARKQMARKEQ
| PredefinedType
=> TokenRole::Operator,
True | False => match ancestors.parent(node).map(|p| p.kind_id().into()) {
Some(BooleanLiteral) => TokenRole::Unknown,
Some(OperatorDeclaration) => TokenRole::Operator,
_ => TokenRole::Operand,
},
This => match ancestors.parent(node).map(|p| p.kind_id().into()) {
Some(IndexerDeclaration) => TokenRole::Operator,
_ => TokenRole::Operand,
},
Identifier | Base | ImplicitParameter
| IntegerLiteral | RealLiteral | BooleanLiteral | NullLiteral
| CharacterLiteral | StringLiteral | VerbatimStringLiteral | RawStringLiteral
=> TokenRole::Operand,
InterpolatedStringExpression => {
Self::string_operand_type(node, &[Interpolation as u16])
}
_ => TokenRole::Unknown,
}
}
fn get_op_type_with_code<'a>(
node: &Node<'a>,
code: &[u8],
ancestors: Ancestors<'a, '_>,
) -> TokenRole {
if !crate::checker::csharp_is_aliased_modifier(node) {
return Self::get_op_type(node, ancestors);
}
match node_text(code, node) {
Some("this") => TokenRole::Operand,
Some("ref" | "out" | "in" | "scoped" | "readonly" | "static" | "async") => {
TokenRole::Operator
}
_ => TokenRole::Unknown,
}
}
fn get_operator_spelling<'a>(
node: &Node<'a>,
ancestors: Ancestors<'a, '_>,
) -> Option<&'static str> {
GENERIC_ANGLES.opener_spelling(node, ancestors)
}
get_operator!(Csharp);
}