diff --git a/server/src/core/python_arch_builder.rs b/server/src/core/python_arch_builder.rs index 429d4c62..defef697 100644 --- a/server/src/core/python_arch_builder.rs +++ b/server/src/core/python_arch_builder.rs @@ -22,6 +22,7 @@ use super::entry_point::EntryPoint; use super::evaluation::{EvaluationSymbolPtr, EvaluationSymbolWeak}; use super::import_resolver::ImportResult; use super::odoo::SyncOdoo; +use super::python_utils::AssignTargetType; use super::symbols::function_symbol::{Argument, ArgumentType}; use super::symbols::symbol_mgr::SectionIndex; @@ -487,7 +488,13 @@ impl PythonArchBuilder { if let Some(ref expr) = assign.value{ self.visit_expr(session, expr); } - self.sym_stack.last().unwrap().borrow_mut().add_new_variable(session, oyarn!("{}", assign.target.id), &assign.target.range); + match assign.target { + AssignTargetType::Name(ref name_expr) => { + self.sym_stack.last().unwrap().borrow_mut().add_new_variable(session, oyarn!("{}", name_expr.id), &name_expr.range); + }, + AssignTargetType::Attribute(ref attr_expr) => { + } + } } } @@ -497,37 +504,43 @@ impl PythonArchBuilder { if let Some(ref expr) = assign.value { self.visit_expr(session, expr); } - let variable = self.sym_stack.last().unwrap().borrow_mut().add_new_variable(session, oyarn!("{}", assign.target.id), &assign.target.range); - let mut variable = variable.borrow_mut(); - if self.file_mode && variable.name() == "__all__" && assign.value.is_some() && variable.parent().is_some() { - let parent = variable.parent().as_ref().unwrap().upgrade(); - if parent.is_some() { - let parent = parent.unwrap(); - let eval = Evaluation::eval_from_ast(session, &assign.value.as_ref().unwrap(), parent, &assign_stmt.range.start()); - variable.as_variable_mut().evaluations = eval.0; - self.diagnostics.extend(eval.1); - if !variable.as_variable().evaluations.is_empty() { - if (*self.sym_stack.last().unwrap()).borrow().is_external() { - // external packages often import symbols from compiled files - // or with meta programmation like globals["var"] = __get_func(). - // we don't want to handle that, so just declare __all__ content - // as symbols to not raise any error. - let evaluation = variable.as_variable_mut().evaluations.get(0).unwrap(); - match &evaluation.value { - Some(EvaluationValue::LIST(list)) => { - for item in list.iter() { - match item { - Expr::StringLiteral(s) => { - self.__all_symbols_to_add.push((s.value.to_string(), evaluation.range.unwrap())); - }, - _ => {} - } + match assign.target { + AssignTargetType::Name(ref name_expr) => { + let variable = self.sym_stack.last().unwrap().borrow_mut().add_new_variable(session, oyarn!("{}", name_expr.id), &name_expr.range); + let mut variable = variable.borrow_mut(); + if self.file_mode && variable.name() == "__all__" && assign.value.is_some() && variable.parent().is_some() { + let parent = variable.parent().as_ref().unwrap().upgrade(); + if parent.is_some() { + let parent = parent.unwrap(); + let eval = Evaluation::eval_from_ast(session, &assign.value.as_ref().unwrap(), parent, &assign_stmt.range.start()); + variable.as_variable_mut().evaluations = eval.0; + self.diagnostics.extend(eval.1); + if !variable.as_variable().evaluations.is_empty() { + if (*self.sym_stack.last().unwrap()).borrow().is_external() { + // external packages often import symbols from compiled files + // or with meta programmation like globals["var"] = __get_func(). + // we don't want to handle that, so just declare __all__ content + // as symbols to not raise any error. + let evaluation = variable.as_variable_mut().evaluations.get(0).unwrap(); + match &evaluation.value { + Some(EvaluationValue::LIST(list)) => { + for item in list.iter() { + match item { + Expr::StringLiteral(s) => { + self.__all_symbols_to_add.push((s.value.to_string(), evaluation.range.unwrap())); + }, + _ => {} + } + } + }, + _ => {} } - }, - _ => {} + } } } } + }, + AssignTargetType::Attribute(ref attr_expr) => { } } } @@ -737,7 +750,13 @@ impl PythonArchBuilder { if let Some(ref expr) = assign.value { self.visit_expr(session, expr); } - scope.borrow_mut().add_new_variable(session, oyarn!("{}", assign.target.id), &assign.target.range); + match assign.target{ + AssignTargetType::Name(ref name_expr) => { + scope.borrow_mut().add_new_variable(session, oyarn!("{}", name_expr.id), &name_expr.range); + }, + AssignTargetType::Attribute(ref attr_expr) => { + } + } } let previous_section = SectionIndex::INDEX(scope.borrow().as_symbol_mgr().get_last_index()); scope.borrow_mut().as_mut_symbol_mgr().add_section( diff --git a/server/src/core/python_arch_eval.rs b/server/src/core/python_arch_eval.rs index b2b3c02f..d006144c 100644 --- a/server/src/core/python_arch_eval.rs +++ b/server/src/core/python_arch_eval.rs @@ -25,7 +25,7 @@ use super::evaluation::{ContextValue, EvaluationSymbolPtr, EvaluationSymbolWeak} use super::file_mgr::FileMgr; use super::import_resolver::ImportResult; use super::python_arch_eval_hooks::PythonArchEvalHooks; -use super::python_utils::Assign; +use super::python_utils::{Assign, AssignTargetType}; use super::symbols::function_symbol::FunctionSymbol; @@ -437,54 +437,61 @@ impl PythonArchEval { if let Some(ref expr) = assign.value { self.visit_expr(session, expr); } - let variable = self.sym_stack.last().unwrap().borrow().get_positioned_symbol(&OYarn::from(assign.target.id.to_string()), &assign.target.range); - if let Some(variable_rc) = variable { - let parent = variable_rc.borrow().parent().unwrap().upgrade().unwrap().clone(); - let (eval, diags) = if let Some(ref annotation) = assign.annotation { - Evaluation::eval_from_ast(session, annotation, parent.clone(), &range.start()) - } else if let Some(ref value) = assign.value { - Evaluation::eval_from_ast(session, value, parent.clone(), &range.start()) - } else { - panic!("either value or annotation should exists"); - }; - variable_rc.borrow_mut().evaluations_mut().unwrap().extend(eval); - self.diagnostics.extend(diags); - let mut dep_to_add = vec![]; - let mut v_mut = variable_rc.borrow_mut(); - let var_name = v_mut.name().clone(); - let evaluations = v_mut.evaluations_mut().unwrap(); - let mut ix = 0; - while ix < evaluations.len(){ - let evaluation = &evaluations[ix]; - if let Some(sym) = evaluation.symbol.get_symbol_as_weak(session, &mut None, &mut self.diagnostics, None).weak.upgrade() { - if Rc::ptr_eq(&sym, &variable_rc){ - // TODO: investigate deps, and fix cyclic evals - let file_path = parent.borrow().get_file().and_then(|file| file.upgrade()).and_then(|file| file.borrow().paths().first().cloned()); - warn!("Found cyclic evaluation symbol: {}, parent: {}, file: {}", var_name, parent.borrow().name(), file_path.unwrap_or(S!("N/A"))); - evaluations.remove(ix); - continue; - } - if let Some(file) = sym.borrow().get_file().clone() { - let sym_file = file.upgrade().unwrap().clone(); - if !Rc::ptr_eq(&self.file, &sym_file) { - match Rc::ptr_eq(&variable_rc, &sym_file) { - true => { - dep_to_add.push(variable_rc.clone()); - }, - false => { - dep_to_add.push(sym_file); + match assign.target { + AssignTargetType::Name(ref name_expr) => { + let variable = self.sym_stack.last().unwrap().borrow().get_positioned_symbol(&OYarn::from(name_expr.id.to_string()), &name_expr.range); + if let Some(variable_rc) = variable { + let parent = variable_rc.borrow().parent().unwrap().upgrade().unwrap().clone(); + let (eval, diags) = if let Some(ref annotation) = assign.annotation { + Evaluation::eval_from_ast(session, annotation, parent.clone(), &range.start()) + } else if let Some(ref value) = assign.value { + Evaluation::eval_from_ast(session, value, parent.clone(), &range.start()) + } else { + panic!("either value or annotation should exists"); + }; + variable_rc.borrow_mut().evaluations_mut().unwrap().extend(eval); + self.diagnostics.extend(diags); + let mut dep_to_add = vec![]; + let mut v_mut = variable_rc.borrow_mut(); + let var_name = v_mut.name().clone(); + let evaluations = v_mut.evaluations_mut().unwrap(); + let mut ix = 0; + while ix < evaluations.len(){ + let evaluation = &evaluations[ix]; + if let Some(sym) = evaluation.symbol.get_symbol_as_weak(session, &mut None, &mut self.diagnostics, None).weak.upgrade() { + if Rc::ptr_eq(&sym, &variable_rc){ + // TODO: investigate deps, and fix cyclic evals + let file_path = parent.borrow().get_file().and_then(|file| file.upgrade()).and_then(|file| file.borrow().paths().first().cloned()); + warn!("Found cyclic evaluation symbol: {}, parent: {}, file: {}", var_name, parent.borrow().name(), file_path.unwrap_or(S!("N/A"))); + evaluations.remove(ix); + continue; + } + if let Some(file) = sym.borrow().get_file().clone() { + let sym_file = file.upgrade().unwrap().clone(); + if !Rc::ptr_eq(&self.file, &sym_file) { + match Rc::ptr_eq(&variable_rc, &sym_file) { + true => { + dep_to_add.push(variable_rc.clone()); + }, + false => { + dep_to_add.push(sym_file); + } + }; } - }; + } } + ix += 1 + } + for dep in dep_to_add { + self.file.borrow_mut().add_dependency(&mut dep.borrow_mut(), self.current_step, BuildSteps::ARCH); } + } else { + debug!("Symbol not found"); } - ix += 1 - } - for dep in dep_to_add { - self.file.borrow_mut().add_dependency(&mut dep.borrow_mut(), self.current_step, BuildSteps::ARCH); + }, + AssignTargetType::Attribute(ref attr_expr) => { + //TODO } - } else { - debug!("Symbol not found"); } } } diff --git a/server/src/core/python_utils.rs b/server/src/core/python_utils.rs index c36e1721..d3a294ed 100644 --- a/server/src/core/python_utils.rs +++ b/server/src/core/python_utils.rs @@ -1,9 +1,15 @@ -use ruff_python_ast::{Expr, ExprName}; +use ruff_python_ast::{Expr, ExprAttribute, ExprName}; use tracing::error; +#[derive(Debug, Clone)] +pub enum AssignTargetType { + Name(ExprName), + Attribute(ExprAttribute), +} + #[derive(Debug, Clone)] pub struct Assign { - pub target: ExprName, + pub target: AssignTargetType, pub value: Option, pub annotation: Option, pub index: Option, //If index is set, it means that value is not unpackable, and that the target should be associated to the 'index' element of value @@ -21,7 +27,7 @@ fn _link_tuples(targets: Vec, values: Vec) -> Vec { Expr::Subscript(_) => {}, Expr::Name(expr) => { res.push(Assign { - target: expr.clone(), + target: AssignTargetType::Name(expr.clone()), annotation: None, value: Some(values.get(index).unwrap().clone()), index: None, @@ -40,7 +46,7 @@ fn _link_tuples(targets: Vec, values: Vec) -> Vec { match target { Expr::Name(tar) => { res.push(Assign { - target: tar.clone(), + target: AssignTargetType::Name(tar.clone()), annotation: None, value: Some(value.clone()), index: Some(index), @@ -64,7 +70,7 @@ fn _link_tuples(targets: Vec, values: Vec) -> Vec { match target { Expr::Name(tar) => { res.push(Assign { - target: tar.clone(), + target: AssignTargetType::Name(tar.clone()), annotation: None, value: Some(value.clone()), index: Some(index), @@ -95,13 +101,32 @@ pub fn unpack_assign(targets: &Vec, annotation: Option<&Expr>, value: Opti for target in targets.iter() { match target { - Expr::Attribute(_) => {}, + Expr::Attribute(expr) => { + match value { + Some(value) => { + res.push(Assign { + target: AssignTargetType::Attribute(expr.clone()), + annotation: annotation.cloned(), + value: Some(value.clone()), + index: None, + }); + }, + None => { + res.push(Assign { + target: AssignTargetType::Attribute(expr.clone()), + annotation: annotation.cloned(), + value: None, + index: None, + }); + } + } + }, Expr::Subscript(_) => {}, Expr::Name(expr) => { match value { Some(value) => { res.push(Assign { - target: expr.clone(), + target: AssignTargetType::Name(expr.clone()), annotation: annotation.cloned(), value: Some(value.clone()), index: None, @@ -109,7 +134,7 @@ pub fn unpack_assign(targets: &Vec, annotation: Option<&Expr>, value: Opti }, None => { res.push(Assign { - target: expr.clone(), + target: AssignTargetType::Name(expr.clone()), annotation: annotation.cloned(), value: None, index: None, @@ -134,7 +159,7 @@ pub fn unpack_assign(targets: &Vec, annotation: Option<&Expr>, value: Opti match target { Expr::Name(tar) => { res.push(Assign { - target: tar.clone(), + target: AssignTargetType::Name(tar.clone()), annotation: None, value: Some(value.clone()), index: Some(index), @@ -161,7 +186,7 @@ pub fn unpack_assign(targets: &Vec, annotation: Option<&Expr>, value: Opti match target { Expr::Name(tar) => { res.push(Assign { - target: tar.clone(), + target: AssignTargetType::Name(tar.clone()), annotation: None, value: Some(value.clone()), index: Some(index), diff --git a/server/src/features/document_symbols.rs b/server/src/features/document_symbols.rs index a93839e8..a4fac72a 100644 --- a/server/src/features/document_symbols.rs +++ b/server/src/features/document_symbols.rs @@ -4,7 +4,7 @@ use lsp_types::{DocumentSymbol, DocumentSymbolResponse, Range, SymbolKind}; use ruff_python_ast::{Expr, Stmt, StmtAnnAssign, StmtAssign, StmtAugAssign, StmtClassDef, StmtFor, StmtFunctionDef, StmtGlobal, StmtIf, StmtImport, StmtImportFrom, StmtMatch, StmtNonlocal, StmtTry, StmtTypeAlias, StmtWhile, StmtWith}; use ruff_text_size::Ranged; -use crate::{constants::SymType, core::{file_mgr::FileInfo, python_utils::{unpack_assign, Assign}, symbols::symbol::Symbol}, threads::SessionInfo}; +use crate::{constants::SymType, core::{file_mgr::FileInfo, python_utils::{unpack_assign, Assign, AssignTargetType}, symbols::symbol::Symbol}, threads::SessionInfo}; pub struct DocumentSymbolFeature; @@ -131,22 +131,29 @@ impl DocumentSymbolFeature { fn build_assign_results(session: &mut SessionInfo, results: &mut Vec, file_info: &Rc>, assigns: Vec) { for assign in assigns.iter() { - results.push(DocumentSymbol{ - name: assign.target.id.to_string(), - detail: None, - kind: SymbolKind::VARIABLE, - tags: None, - deprecated: None, - range: Range{ - start: file_info.borrow().offset_to_position(assign.target.range.start().to_usize()), - end: file_info.borrow().offset_to_position(assign.target.range.end().to_usize()), - }, - selection_range: Range{ - start: file_info.borrow().offset_to_position(assign.target.range.start().to_usize()), - end: file_info.borrow().offset_to_position(assign.target.range.end().to_usize()), + match assign.target { + AssignTargetType::Name(ref target_name) => { + results.push(DocumentSymbol{ + name: target_name.id.to_string(), + detail: None, + kind: SymbolKind::VARIABLE, + tags: None, + deprecated: None, + range: Range{ + start: file_info.borrow().offset_to_position(target_name.range.start().to_usize()), + end: file_info.borrow().offset_to_position(target_name.range.end().to_usize()), + }, + selection_range: Range{ + start: file_info.borrow().offset_to_position(target_name.range.start().to_usize()), + end: file_info.borrow().offset_to_position(target_name.range.end().to_usize()), + }, + children: None, + }); }, - children: None, - }); + AssignTargetType::Attribute(ref attr_target) => { + + } + } } }