use alloc::string::String;
use alloc::vec::Vec;
use crate::syntax::builders::utils::{
enter_scope_stack, exit_scope_stack_if_current, register_symbol_in_scope,
};
use crate::syntax::metadata::java::add_node_range_to_method;
use crate::syntax::SyntaxNode;
use crate::syntax::{SyntaxGraphArgs, SyntaxGraphError};
use crate::{Language, NodeId};
#[allow(
clippy::struct_field_names,
reason = "mirrors the Python DirectChildren keys"
)]
#[derive(Clone, PartialEq, Eq, Debug, Default)]
pub struct MethodDirectChildren {
pub block_id: Option<NodeId>,
pub modifiers_id: Option<NodeId>,
pub parameters_id: Option<NodeId>,
}
#[derive(Clone, PartialEq, Eq, Debug, Default)]
pub struct MethodListChildren {
pub modifiers_ids: Vec<NodeId>,
pub parameters_ids: Vec<NodeId>,
}
fn add_child(
args: &mut SyntaxGraphArgs<'_>,
n_id: NodeId,
child_id: NodeId,
) -> Result<(), SyntaxGraphError> {
let built = args.generic(child_id)?;
args.syntax_graph.add_ast_edge(n_id, built);
Ok(())
}
fn process_method_children(
args: &mut SyntaxGraphArgs<'_>,
n_id: NodeId,
children: &MethodDirectChildren,
) -> Result<(), SyntaxGraphError> {
if let Some(parameters_id) = children.parameters_id {
add_child(args, n_id, parameters_id)?;
}
if let Some(block_id) = children.block_id {
add_child(args, n_id, block_id)?;
}
if let Some(modifiers_id) = children.modifiers_id {
add_child(args, n_id, modifiers_id)?;
}
Ok(())
}
fn process_method_list_children(
args: &mut SyntaxGraphArgs<'_>,
n_id: NodeId,
children: &MethodListChildren,
) -> Result<(), SyntaxGraphError> {
for child_id in children
.modifiers_ids
.iter()
.chain(&children.parameters_ids)
{
add_child(args, n_id, *child_id)?;
}
Ok(())
}
#[allow(
clippy::too_many_arguments,
reason = "mirrors the Python build_method_declaration_node inputs"
)]
pub fn build_method_declaration_node(
args: &mut SyntaxGraphArgs<'_>,
n_id: NodeId,
name: Option<String>,
direct_children: &MethodDirectChildren,
list_children: &MethodListChildren,
access_modifiers: Option<String>,
) -> Result<NodeId, SyntaxGraphError> {
let name = name.filter(|value| !value.is_empty());
args.syntax_graph.add_node(
n_id,
SyntaxNode::MethodDeclaration {
name: name.clone(),
access_modifiers: access_modifiers.filter(|value| !value.is_empty()),
block_id: direct_children.block_id,
modifiers_id: direct_children.modifiers_id,
parameters_id: direct_children.parameters_id,
},
);
if let Some(name) = &name {
register_symbol_in_scope(args.syntax_graph, args.metadata, name.clone(), n_id);
}
enter_scope_stack(args.syntax_graph, args.metadata, n_id);
process_method_children(args, n_id, direct_children)?;
process_method_list_children(args, n_id, list_children)?;
if args.language == Language::Java && args.syntax_graph.nodes.contains_key(&NodeId(0)) {
if let Some(name) = &name {
add_node_range_to_method(args, n_id, name)?;
}
}
exit_scope_stack_if_current(args.metadata, n_id);
Ok(n_id)
}