Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion server/src/core/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ use tracing::error;

use crate::constants::{CONFIG_WIKI_URL};
use crate::core::diagnostics::{DiagnosticCode, DiagnosticSetting, SchemaDiagnosticCodes};
use crate::core::file_mgr::FileMgr;
use crate::threads::SessionInfo;
use crate::utils::{fill_validate_path, get_python_command, has_template, is_addon_path, is_odoo_path, is_python_path, PathSanitizer};
use crate::S;
Expand Down
1 change: 0 additions & 1 deletion server/src/core/evaluation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ use crate::threads::SessionInfo;
use crate::S;

use super::file_mgr::FileMgr;
use super::python_validator::PythonValidator;
use super::symbols::function_symbol::{Argument, ArgumentType, FunctionSymbol};
use super::symbols::symbol::Symbol;
use super::symbols::symbol_mgr::SectionIndex;
Expand Down
115 changes: 111 additions & 4 deletions server/src/core/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,14 @@ use std::rc::Rc;
use std::rc::Weak;
use lsp_types::MessageType;
use weak_table::PtrWeakHashSet;
use weak_table::PtrWeakKeyHashMap;
use std::collections::HashSet;

use crate::constants::BuildStatus;
use crate::constants::BuildSteps;
use crate::constants::OYarn;
use crate::constants::SymType;
use crate::core::xml_data::OdooDataRecord;
use crate::threads::SessionInfo;

use super::symbols::module_symbol::ModuleSymbol;
Expand Down Expand Up @@ -73,6 +75,10 @@ impl ModelData {
pub struct Model {
name: OYarn,
symbols: PtrWeakHashSet<Weak<RefCell<Symbol>>>,
// One XML file can have multiple records that define models or fields
// xml symbols and model fields are thus maps from xml file symbol to a list of records
xml_symbols: PtrWeakKeyHashMap<Weak<RefCell<Symbol>>, HashSet<OdooDataRecord>>,
model_fields: PtrWeakKeyHashMap<Weak<RefCell<Symbol>>, HashSet<OdooDataRecord>>,
pub dependents: PtrWeakHashSet<Weak<RefCell<Symbol>>>,
}

Expand All @@ -81,12 +87,30 @@ impl Model {
let mut res = Self {
name,
symbols: PtrWeakHashSet::new(),
xml_symbols: PtrWeakKeyHashMap::new(),
model_fields: PtrWeakKeyHashMap::new(),
dependents: PtrWeakHashSet::new(),
};
res.symbols.insert(symbol);
res
}

pub fn new_from_xml(name: OYarn, xml_file_symbol: Rc<RefCell<Symbol>>, record: OdooDataRecord) -> Self {
let mut res = Self {
name,
symbols: PtrWeakHashSet::new(),
xml_symbols: PtrWeakKeyHashMap::new(),
model_fields: PtrWeakKeyHashMap::new(),
dependents: PtrWeakHashSet::new(),
};
res.xml_symbols.insert(xml_file_symbol, HashSet::from([record]));
res
}

pub fn name(&self) -> &OYarn {
&self.name
}

pub fn add_symbol(&mut self, session: &mut SessionInfo, symbol: Rc<RefCell<Symbol>>) {
if self.symbols.contains(&symbol) {
return;
Expand All @@ -96,6 +120,78 @@ impl Model {
self.add_dependents_to_validation(session, from_module);
}

fn add_xml_ref(collection: &mut PtrWeakKeyHashMap<Weak<RefCell<Symbol>>, HashSet<OdooDataRecord>>, symbol: &Rc<RefCell<Symbol>>, record: OdooDataRecord) -> bool {
if let Some(records) = collection.get_mut(symbol) {
records.insert(record)
} else {
collection.insert(symbol.clone(), HashSet::from([record]));
true
}
}

pub fn add_xml_symbol(&mut self, session: &mut SessionInfo, symbol: Rc<RefCell<Symbol>>, record: OdooDataRecord) {
if Self::add_xml_ref(&mut self.xml_symbols, &symbol, record) {
self.add_dependents_to_validation(session, symbol.borrow().find_module());
}
}

pub fn add_model_field(&mut self, session: &mut SessionInfo, symbol: Rc<RefCell<Symbol>>, record: OdooDataRecord) {
if Self::add_xml_ref(&mut self.model_fields, &symbol, record) {
self.add_dependents_to_validation(session, symbol.borrow().find_module());
}
}


pub fn get_model_field_records(&self, session: &mut SessionInfo, from_module: Option<Rc<RefCell<Symbol>>>) -> Vec<(Rc<RefCell<Symbol>>, OdooDataRecord)> {
let mut result = Vec::new();
for (s, records) in self.model_fields.iter() {
let module = s.borrow().find_module();
if let Some(module) = module {
if from_module.is_none() || ModuleSymbol::is_in_deps(session, from_module.as_ref().unwrap(), &module.borrow().as_module_package().dir_name) {
for r in records.iter() {
result.push((s.clone(), r.clone()));
}
}
}
}
result
}


pub fn get_model_field_record_by_name(&self, session: &mut SessionInfo, from_module: Option<Rc<RefCell<Symbol>>>, field_name: &str) -> Vec<(Rc<RefCell<Symbol>>, OdooDataRecord)> {
self.get_model_field_records(session, from_module).into_iter().filter(|(_, r)| {
r.fields.iter().any(|f| f.name.as_str() == "name" && f.text.as_deref() == Some(field_name))
}).collect()
}

pub fn get_xml_symbols(&self, session: &mut SessionInfo, from_module: Option<Rc<RefCell<Symbol>>>) -> Vec<Rc<RefCell<Symbol>>> {
let mut result = Vec::new();
for (s, _records) in self.xml_symbols.iter() {
let module = s.borrow().find_module();
if let Some(module) = module {
if from_module.is_none() || ModuleSymbol::is_in_deps(session, from_module.as_ref().unwrap(), &module.borrow().as_module_package().dir_name) {
result.push(s);
}
}
}
result
}

pub fn get_xml_symbol_records(&self, session: &mut SessionInfo, from_module: Option<Rc<RefCell<Symbol>>>) -> Vec<(Rc<RefCell<Symbol>>, OdooDataRecord)> {
let mut result = Vec::new();
for (s, record) in self.xml_symbols.iter() {
let module = s.borrow().find_module();
if let Some(module) = module {
if from_module.is_none() || ModuleSymbol::is_in_deps(session, from_module.as_ref().unwrap(), &module.borrow().as_module_package().dir_name) {
for r in record.iter() {
result.push((s.clone(), r.clone()));
}
}
}
}
result
}

pub fn remove_symbol(&mut self, session: &mut SessionInfo, symbol: &Rc<RefCell<Symbol>>, from_module: Option<Rc<RefCell<Symbol>>>) {
self.symbols.remove(symbol);
self.add_dependents_to_validation(session, from_module);
Expand Down Expand Up @@ -130,13 +226,22 @@ impl Model {
}

pub fn model_in_deps(&self, session: &mut SessionInfo, from_module: &Rc<RefCell<Symbol>>) -> bool {
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) {
let dir_name = sym.borrow().find_module().unwrap().borrow().as_module_package().dir_name.clone();
let sym_module_check = |session: &mut SessionInfo<'_>, sym: &Rc<RefCell<Symbol>>| {
if let Some(module) = sym.borrow().find_module() {
let dir_name = module.borrow().as_module_package().dir_name.clone();
if ModuleSymbol::is_in_deps(session, from_module, &dir_name) {
return true;
}
}
false
};
if self.symbols.iter().any(|sym|
!sym.borrow().as_class_sym()._model.as_ref().unwrap().inherit.contains(&sym.borrow().as_class_sym()._model.as_ref().unwrap().name)
&& sym_module_check(session, &sym)) {
return true;
}
if self.xml_symbols.iter().any(|(sym, _record)| sym_module_check(session, &sym)) {
return true;
}
false
}
Expand Down Expand Up @@ -188,7 +293,9 @@ impl Model {

pub fn has_symbols(&mut self) -> bool {
self.symbols.remove_expired();
!self.symbols.is_empty()
self.xml_symbols.remove_expired();
self.model_fields.remove_expired();
!self.symbols.is_empty() || !self.xml_symbols.is_empty()
}

/* Return all symbols that build this model.
Expand Down
14 changes: 12 additions & 2 deletions server/src/core/python_odoo_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use weak_table::PtrWeakHashSet;
use crate::constants::{OYarn, SymType};
use crate::core::model::{Model, ModelData};
use crate::core::symbols::symbol::Symbol;
use crate::core::xml_data::{OdooData, OdooDataRecord};
use crate::core::xml_data::{OdooData, OdooDataField, OdooDataRecord};
use crate::threads::SessionInfo;
use crate::utils::compare_semver;
use crate::{oyarn, Sy, S};
Expand Down Expand Up @@ -72,7 +72,17 @@ impl PythonOdooBuilder {
end: 1,
}),
xml_id: Some(xml_id_model_name),
fields: vec![],
fields: vec![
OdooDataField {
name: Sy!("model"),
range: std::ops::Range::<usize> {
start: self.symbol.borrow().range().start().to_usize(),
end: self.symbol.borrow().range().end().to_usize(),
},
text: Some(model_name.to_string()),
..Default::default()
},
],
range: std::ops::Range::<usize> {
start: self.symbol.borrow().range().start().to_usize(),
end: self.symbol.borrow().range().end().to_usize(),
Expand Down
104 changes: 101 additions & 3 deletions server/src/core/xml_arch_builder_rng_validation.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,22 @@
use std::rc::Rc;
use std::{cell::RefCell, rc::Rc};

use lsp_types::{Diagnostic, Position, Range};
use roxmltree::Node;

use crate::{Sy, constants::OYarn, core::{diagnostics::{DiagnosticCode, create_diagnostic}, odoo::SyncOdoo, xml_data::{OdooData, OdooDataField, OdooDataRecord, XmlDataAsset, XmlDataDelete, XmlDataMenuItem, XmlDataTemplate}}, oyarn, threads::SessionInfo};

use crate::{
Sy,
constants::OYarn,
core::{
diagnostics::{DiagnosticCode, create_diagnostic},
model::Model,
odoo::SyncOdoo,
xml_data::{
OdooData, OdooDataField, OdooDataRecord, XmlDataAsset, XmlDataDelete, XmlDataMenuItem, XmlDataTemplate
},
},
oyarn,
threads::SessionInfo,
};
use super::xml_arch_builder::XmlArchBuilder;

/* Contains the RelaxNG Validation part of the XmlArchBuilder */
Expand Down Expand Up @@ -232,11 +244,97 @@ impl XmlArchBuilder {
}
}
}
self.register_ir_model_record(session, &data);
self.register_ir_model_fields_record(session, &data);
let data = OdooData::RECORD(data);
self.on_operation_creation(session, found_id, node, data, diagnostics);
true
}

fn register_ir_model_fields_record(&self, session: &mut SessionInfo, data: &OdooDataRecord) {
if data.model.0.as_str() != "ir.model.fields" {
return;
}

let model_name_str: String = if let Some(f) =
data.fields.iter().find(|f| f.name.as_str() == "model")
{
let Some(t) = f.text.as_deref() else {
return;
};
t.to_string()
} else if let Some(f) = data.fields.iter().find(|f| f.name.as_str() == "model_id") {
let Some((ref_key, ref_range)) = f.ref_key.as_ref() else {
return;
};
let xml_ids =
SyncOdoo::get_xml_ids(session, &self.xml_symbol, ref_key, ref_range, &mut vec![]);
let model_name_option = xml_ids.iter().find_map(|xml_data| {
let OdooData::RECORD(r) = xml_data else {
return None;
};
if r.model.0.as_str() != "ir.model" {
return None;
}
if let Some(name) = r
.fields
.iter()
.find(|f| f.name.as_str() == "model")
.and_then(|model_field| model_field.text.as_deref())
{
return Some(name.to_string());
}
None
});
match model_name_option {
Some(model_name) => model_name,
None => return,
}
} else {
return;
};
let model_name_yarn = Sy!(model_name_str);
let xml_sym = self.xml_symbol.clone();
if let Some(model) = session.sync_odoo.models.get(&model_name_yarn).cloned() {
model
.borrow_mut()
.add_model_field(session, xml_sym, data.clone());
}
}

fn register_ir_model_record(&self, session: &mut SessionInfo, data: &OdooDataRecord) {
if data.model.0.as_str() != "ir.model" {
return;
}
let Some(model_field) = data.fields.iter().find(|f| f.name.as_str() == "model") else {
return;
};
let Some(model_name) = model_field.text.as_deref() else {
return;
};
let model_name_yarn = oyarn!("{}", model_name);
let xml_sym = self.xml_symbol.clone();
match session.sync_odoo.models.get(&model_name_yarn).cloned() {
Some(model) => {
model
.borrow_mut()
.add_xml_symbol(session, xml_sym, data.clone());
}
None => {
let new_model = Model::new_from_xml(model_name_yarn.clone(), xml_sym, data.clone());
session
.sync_odoo
.models
.insert(model_name_yarn.clone(), Rc::new(RefCell::new(new_model)));
}
}
session
.sync_odoo
.get_main_entry()
.borrow_mut()
.search_rebuild_for_models(session, model_name_yarn);
}

fn load_field(&mut self, session: &mut SessionInfo, node: &Node, diagnostics: &mut Vec<Diagnostic>) -> Option<OdooDataField> {
if node.tag_name().name() != "field" { return None; }
let Some(node_name_node) = node.attribute_node("name") else {
Expand Down
24 changes: 23 additions & 1 deletion server/src/core/xml_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,29 @@ pub struct OdooDataRecord {
pub range: Range<usize>,
}

#[derive(Debug, Clone)]
impl PartialEq for OdooDataRecord {
fn eq(&self, other: &Self) -> bool {
Weak::ptr_eq(&self.file_symbol, &other.file_symbol)
&& self.model == other.model
&& self.xml_id == other.xml_id
&& self.fields == other.fields
&& self.range == other.range
}
}

impl Eq for OdooDataRecord {}

impl std::hash::Hash for OdooDataRecord {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.file_symbol.as_ptr().hash(state);
self.model.hash(state);
self.xml_id.hash(state);
self.fields.hash(state);
self.range.hash(state);
}
}

#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
pub struct OdooDataField {
pub name: OYarn,
pub range: Range<usize>,
Expand Down
Loading
Loading