Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better domains - autocompletion, diagnostics, hover #167

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
7 changes: 6 additions & 1 deletion server/src/core/evaluation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ impl EvaluationSymbolWeak {
}

#[derive(Debug, Default, Clone)]
enum EvaluationSymbolPtr {
pub enum EvaluationSymbolPtr {
WEAK(EvaluationSymbolWeak),
SELF,
ARG(u32),
Expand Down Expand Up @@ -1240,4 +1240,9 @@ impl EvaluationSymbol {
}
}
}

//Return the symbol ptr, if you need to know its type (domain, None, ...). If you need the symbol behind the pointer, use get_symbol however
pub fn get_symbol_ptr(&self) -> &EvaluationSymbolPtr {
&self.sym
}
}
74 changes: 65 additions & 9 deletions server/src/core/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,36 +92,92 @@ impl Model {
let mut symbol = Vec::new();
for s in self.symbols.iter() {
let module = s.borrow().find_module().expect("Model should be declared in a module");
if ModuleSymbol::is_in_deps(session, &from_module, &module.borrow().as_module_package().dir_name, &mut None) {
if ModuleSymbol::is_in_deps(session, &from_module, &module.borrow().as_module_package().dir_name) {
symbol.push(s);
}
}
symbol.into_iter()
}

pub fn get_main_symbols(&self, session: &mut SessionInfo, from_module: Option<Rc<RefCell<Symbol>>>, acc: &mut Option<HashSet<String>>) -> Vec<Rc<RefCell<Symbol>>> {
if acc.is_none() {
*acc = Some(HashSet::new());
pub fn get_full_model_symbols(&self, session: &mut SessionInfo, from_module: Rc<RefCell<Symbol>>) -> impl Iterator<Item= Rc<RefCell<Symbol>>> {
let mut symbol: PtrWeakHashSet<Weak<RefCell<Symbol>>> = PtrWeakHashSet::new();
for s in self.symbols.iter() {
let module = s.borrow().find_module().expect("Model should be declared in a module");
if ModuleSymbol::is_in_deps(session, &from_module, &module.borrow().as_module_package().dir_name) {
symbol.insert(s);
}
}
for inherit_model in self.get_inherited_models(session, Some(from_module.clone())).iter() {
for s in inherit_model.borrow().symbols.iter() {
let module = s.borrow().find_module().expect("Model should be declared in a module");
if ModuleSymbol::is_in_deps(session, &from_module, &module.borrow().as_module_package().dir_name) {
symbol.insert(s);
}
}
}
symbol.into_iter()
}

pub fn get_main_symbols(&self, session: &mut SessionInfo, from_module: Option<Rc<RefCell<Symbol>>>) -> Vec<Rc<RefCell<Symbol>>> {
let mut res: Vec<Rc<RefCell<Symbol>>> = vec![];
for sym in self.symbols.iter() {
if !sym.borrow().as_class_sym()._model.as_ref().unwrap().inherit.contains(&sym.borrow().as_class_sym()._model.as_ref().unwrap().name) {
if from_module.is_none() || sym.as_ref().borrow().find_module().is_none() {
res.push(sym);
} else {
let dir_name = sym.borrow().find_module().unwrap().borrow().as_module_package().dir_name.clone();
if (acc.is_some() && acc.as_ref().unwrap().contains(&dir_name)) ||
ModuleSymbol::is_in_deps(session, from_module.as_ref().unwrap(), &dir_name, acc) {
if ModuleSymbol::is_in_deps(session, from_module.as_ref().unwrap(), &dir_name) {
res.push(sym);
acc.as_mut().unwrap().insert(dir_name);
}
}
}
}
res
}

/* Return all symbols that build this model.
pub fn get_inherited_models(&self, session: &mut SessionInfo, from_module: Option<Rc<RefCell<Symbol>>>) -> Vec<Rc<RefCell<Model>>> {
let mut res = vec![];
let mut already_in = HashSet::new();
if let Some(from_module) = from_module {
let symbols = self.get_symbols(session, from_module);
for symbol in symbols {
if let Some(model_data) = &symbol.borrow().as_class_sym()._model {
for inherit in model_data.inherit.iter() {
if let Some(model) = session.sync_odoo.models.get(inherit).cloned() {
if !already_in.contains(&model.borrow().name) {
res.push(model.clone());
already_in.insert(model.borrow().name.clone());
}
}
}
}
}
}
res
}

pub fn get_inherits_models(&self, session: &mut SessionInfo, from_module: Option<Rc<RefCell<Symbol>>>) -> Vec<Rc<RefCell<Model>>> {
let mut res = vec![];
let mut already_in = HashSet::new();
if let Some(from_module) = from_module {
let symbols = self.get_symbols(session, from_module);
for symbol in symbols {
if let Some(model_data) = &symbol.borrow().as_class_sym()._model {
for (model_name, _field) in model_data.inherits.iter() {
if let Some(model) = session.sync_odoo.models.get(model_name).cloned() {
if !already_in.contains(&model.borrow().name) {
res.push(model.clone());
already_in.insert(model.borrow().name.clone());
}
}
}
}
}
}
res
}

/* Return all symbols that build this model.
It returns the symbol and an optional string that represents the module name that should be added to dependencies to be used.
*/
pub fn all_symbols(&self, session: &mut SessionInfo, from_module: Option<Rc<RefCell<Symbol>>>) -> Vec<(Rc<RefCell<Symbol>>, Option<String>)> {
Expand All @@ -130,7 +186,7 @@ impl Model {
if let Some(from_module) = from_module.as_ref() {
let module = s.borrow().find_module();
if let Some(module) = module {
if ModuleSymbol::is_in_deps(session, &from_module, &module.borrow().as_module_package().dir_name, &mut None) {
if ModuleSymbol::is_in_deps(session, &from_module, &module.borrow().as_module_package().dir_name) {
symbol.push((s, None));
} else {
symbol.push((s, Some(module.borrow().as_module_package().dir_name.clone())));
Expand Down
9 changes: 8 additions & 1 deletion server/src/core/odoo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ pub struct SyncOdoo {
pub not_found_symbols: PtrWeakHashSet<Weak<RefCell<Symbol>>>,
pub must_reload_paths: Vec<(Weak<RefCell<Symbol>>, String)>,
pub load_odoo_addons: bool, //indicate if we want to load odoo addons or not
pub need_rebuild: bool //if true, the next process_rebuilds will drop everything and rebuild everything
pub need_rebuild: bool, //if true, the next process_rebuilds will drop everything and rebuild everything
pub capabilities: lsp_types::ClientCapabilities,
}

unsafe impl Send for SyncOdoo {}
Expand Down Expand Up @@ -99,6 +100,7 @@ impl SyncOdoo {
must_reload_paths: vec![],
load_odoo_addons: true,
need_rebuild: false,
capabilities: lsp_types::ClientCapabilities::default(),
};
sync_odoo
}
Expand Down Expand Up @@ -752,6 +754,11 @@ impl SyncOdoo {
return self.rebuild_arch.len() + self.rebuild_arch_eval.len() + self.rebuild_odoo.len() + self.rebuild_validation.len()
}

pub fn load_capabilities(&mut self, capabilities: &lsp_types::ClientCapabilities) {
info!("Client capabilities: {:?}", capabilities);
self.capabilities = capabilities.clone();
}

}

#[derive(Debug)]
Expand Down
96 changes: 93 additions & 3 deletions server/src/core/python_arch_eval_hooks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,96 @@ static arch_eval_function_hooks: Lazy<Vec<PythonArchEvalFunctionHook>> = Lazy::n
value: None
});
}},
PythonArchEvalFunctionHook { tree: (vec![S!("odoo"), S!("models")], vec![S!("BaseModel"), S!("with_company")]),
if_exist_only: true,
func: |odoo: &mut SyncOdoo, symbol: Rc<RefCell<Symbol>>| {
let mut browse: std::cell::RefMut<Symbol> = symbol.borrow_mut();
browse.evaluations_mut().unwrap().clear();
browse.evaluations_mut().unwrap().push(Evaluation {
symbol: EvaluationSymbol::new_self(
HashMap::new(),
None,
None,
),
range: None,
value: None
});
}},
PythonArchEvalFunctionHook { tree: (vec![S!("odoo"), S!("models")], vec![S!("BaseModel"), S!("with_context")]),
if_exist_only: true,
func: |odoo: &mut SyncOdoo, symbol: Rc<RefCell<Symbol>>| {
let mut browse: std::cell::RefMut<Symbol> = symbol.borrow_mut();
browse.evaluations_mut().unwrap().clear();
browse.evaluations_mut().unwrap().push(Evaluation {
symbol: EvaluationSymbol::new_self(
HashMap::new(),
None,
None,
),
range: None,
value: None
});
}},
PythonArchEvalFunctionHook { tree: (vec![S!("odoo"), S!("models")], vec![S!("BaseModel"), S!("with_prefetch")]),
if_exist_only: true,
func: |odoo: &mut SyncOdoo, symbol: Rc<RefCell<Symbol>>| {
let mut browse: std::cell::RefMut<Symbol> = symbol.borrow_mut();
browse.evaluations_mut().unwrap().clear();
browse.evaluations_mut().unwrap().push(Evaluation {
symbol: EvaluationSymbol::new_self(
HashMap::new(),
None,
None,
),
range: None,
value: None
});
}},
PythonArchEvalFunctionHook { tree: (vec![S!("odoo"), S!("models")], vec![S!("BaseModel"), S!("with_user")]),
if_exist_only: true,
func: |odoo: &mut SyncOdoo, symbol: Rc<RefCell<Symbol>>| {
let mut browse: std::cell::RefMut<Symbol> = symbol.borrow_mut();
browse.evaluations_mut().unwrap().clear();
browse.evaluations_mut().unwrap().push(Evaluation {
symbol: EvaluationSymbol::new_self(
HashMap::new(),
None,
None,
),
range: None,
value: None
});
}},
PythonArchEvalFunctionHook { tree: (vec![S!("odoo"), S!("models")], vec![S!("BaseModel"), S!("with_env")]),
if_exist_only: true,
func: |odoo: &mut SyncOdoo, symbol: Rc<RefCell<Symbol>>| {
let mut browse: std::cell::RefMut<Symbol> = symbol.borrow_mut();
browse.evaluations_mut().unwrap().clear();
browse.evaluations_mut().unwrap().push(Evaluation {
symbol: EvaluationSymbol::new_self(
HashMap::new(),
None,
None,
),
range: None,
value: None
});
}},
PythonArchEvalFunctionHook { tree: (vec![S!("odoo"), S!("models")], vec![S!("BaseModel"), S!("exists")]),
if_exist_only: true,
func: |odoo: &mut SyncOdoo, symbol: Rc<RefCell<Symbol>>| {
let mut browse: std::cell::RefMut<Symbol> = symbol.borrow_mut();
browse.evaluations_mut().unwrap().clear();
browse.evaluations_mut().unwrap().push(Evaluation {
symbol: EvaluationSymbol::new_self(
HashMap::new(),
None,
None,
),
range: None,
value: None
});
}},
]});

pub struct PythonArchEvalHooks {
Expand Down Expand Up @@ -437,17 +527,17 @@ impl PythonArchEvalHooks {
}
let model = model.clone();
let model = model.borrow();
let symbols = model.get_main_symbols(session, from_module.clone(), &mut None);
let symbols = model.get_main_symbols(session, from_module.clone());
if !symbols.is_empty() {
for s in symbols.iter() {
if from_module.is_none() || ModuleSymbol::is_in_deps(session, &from_module.as_ref().unwrap(),&s.borrow().find_module().unwrap().borrow().as_module_package().dir_name, &mut None) {
if from_module.is_none() || ModuleSymbol::is_in_deps(session, &from_module.as_ref().unwrap(),&s.borrow().find_module().unwrap().borrow().as_module_package().dir_name) {
return EvaluationSymbolWeak::new(Rc::downgrade(s), Some(true), false);
}
}
} else {
if from_module.is_some() {
//retry without from_module to see if model exists elsewhere
let symbols = model.get_main_symbols(session, None, &mut None);
let symbols = model.get_main_symbols(session, None);
if symbols.is_empty() {
let range = FileMgr::textRange_to_temporary_Range(&context.get(&S!("range")).unwrap().as_text_range());
diagnostics.push(Diagnostic::new(range,
Expand Down
8 changes: 4 additions & 4 deletions server/src/core/python_validator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ impl PythonValidator {
}
self.diagnostics.extend(sym.borrow_mut().as_func_mut().diagnostics.values().flat_map(|v| v.clone()));
} else {
panic!("function not found");
panic!("function '{}' not found", f.name.id);
}
},
Stmt::ClassDef(c) => {
Expand Down Expand Up @@ -246,7 +246,7 @@ impl PythonValidator {
if import_result.found && self.current_module.is_some() {
let module = import_result.symbol.borrow().find_module();
if let Some(module) = module {
if !ModuleSymbol::is_in_deps(session, self.current_module.as_ref().unwrap(), &module.borrow().as_module_package().dir_name, &mut None) && !self.safe_imports.last().unwrap() {
if !ModuleSymbol::is_in_deps(session, self.current_module.as_ref().unwrap(), &module.borrow().as_module_package().dir_name) && !self.safe_imports.last().unwrap() {
self.diagnostics.push(Diagnostic::new(
Range::new(Position::new(import_result.range.start().to_u32(), 0), Position::new(import_result.range.end().to_u32(), 0)),
Some(DiagnosticSeverity::ERROR),
Expand Down Expand Up @@ -321,13 +321,13 @@ impl PythonValidator {
let borrowed_model = model.borrow();
let mut main_modules = vec![];
let mut found_one = false;
for main_sym in borrowed_model.get_main_symbols(session, None, &mut None).iter() {
for main_sym in borrowed_model.get_main_symbols(session, None).iter() {
let main_sym = main_sym.borrow();
let main_sym_module = main_sym.find_module();
if let Some(main_sym_module) = main_sym_module {
let module_name = main_sym_module.borrow().as_module_package().dir_name.clone();
main_modules.push(module_name.clone());
if ModuleSymbol::is_in_deps(session, from, &module_name, &mut None) {
if ModuleSymbol::is_in_deps(session, from, &module_name) {
found_one = true;
}
}
Expand Down
28 changes: 27 additions & 1 deletion server/src/core/symbols/function_symbol.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::{cell::RefCell, collections::HashMap, rc::{Rc, Weak}};
use std::{cell::RefCell, cmp::min, collections::HashMap, rc::{Rc, Weak}};

use lsp_types::Diagnostic;
use ruff_python_ast::{Expr, ExprCall};
use ruff_text_size::{TextRange, TextSize};

use crate::{constants::{BuildStatus, BuildSteps, SymType}, core::evaluation::{Context, Evaluation}, threads::SessionInfo};
Expand Down Expand Up @@ -157,4 +158,29 @@ impl FunctionSymbol {
}*/
res
}

/* Given a call of this function and an index, return the corresponding parameter definition */
pub fn get_indexed_arg_in_call(&self, call: &ExprCall, index: u32, is_on_instance: bool) -> Option<&Argument> {
if self.is_overloaded() {
return None;
}
let mut call_arg_keyword = None;
if index > (call.arguments.args.len()-1) as u32 {
call_arg_keyword = call.arguments.keywords.get((index - call.arguments.args.len() as u32) as usize);
}
let mut arg_index = 0;
if is_on_instance {
arg_index += 1;
}
if let Some(keyword) = call_arg_keyword {
for arg in self.args.iter() {
if arg.symbol.upgrade().unwrap().borrow().name() == keyword.arg.as_ref().unwrap().id {
return Some(arg);
}
}
} else {
return self.args.get(arg_index as usize);
}
None
}
}
Loading