#![allow(clippy::wildcard_imports, clippy::enum_glob_use)]
#![allow(
clippy::cast_precision_loss,
clippy::cast_possible_truncation,
clippy::cast_sign_loss
)]
use super::*;
fn objc_count_instance_variables(block: &Node) -> (usize, usize) {
let (mut total, mut public) = (0usize, 0usize);
let mut is_public = false;
for ivar in block.children() {
if ivar.kind_id() != Objc::InstanceVariable as u16 {
continue;
}
if let Some(vis) = ivar.first_child(|id| id == Objc::VisibilitySpecification as u16) {
is_public = vis.first_child(|id| id == Objc::ATpublic as u16).is_some();
continue;
}
let mut fields = 0;
for decl in ivar.children() {
if decl.kind_id() == Objc::StructDeclaration as u16 {
fields += decl
.children()
.filter(|d| d.kind_id() == Objc::StructDeclarator as u16)
.count();
}
}
total += fields;
if is_public {
public += fields;
}
}
(total, public)
}
impl Npa for ObjcCode {
fn compute<'a>(node: &Node<'a>, _code: &'a [u8], stats: &mut Stats) {
use Objc::*;
let is_interface = matches!(node.kind_id().into(), ClassInterface | ProtocolDeclaration);
if !is_interface && node.kind_id() != ClassImplementation as u16 {
return;
}
if stats.is_disabled() {
stats.is_class_space = true;
}
let (mut attributes, mut public) = (0usize, 0usize);
for child in node.children() {
match child.kind_id().into() {
PropertyDeclaration => {
attributes += 1;
public += 1;
}
QualifiedProtocolInterfaceDeclaration => {
for inner in child.children() {
if inner.kind_id() == Objc::PropertyDeclaration as u16 {
attributes += 1;
public += 1;
}
}
}
InstanceVariables => {
let (na, npa) = objc_count_instance_variables(&child);
attributes += na;
public += npa;
}
_ => {}
}
}
if is_interface {
stats.interface_na += attributes;
stats.interface_npa += public;
} else {
stats.class_na += attributes;
stats.class_npa += public;
}
}
}