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
40 changes: 40 additions & 0 deletions server/src/core/diagnostic_codes_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -457,4 +457,44 @@ OLS05056, DiagnosticSetting::Error, "Model '{0}' not found",
* Field not found in model
*/
OLS05057, DiagnosticSetting::Error, "Field '{0}' not found in model '{1}'",
/**
* The attribute is not valid for <asset> nodes.
*/
OLS05058, DiagnosticSetting::Error, "Invalid attribute {0} in asset node",
/**
* A <asset> node must have an id attribute.
*/
OLS05059, DiagnosticSetting::Error, "asset node must contain an id attribute",
/**
* A <asset> node must have a name attribute.
*/
OLS05060, DiagnosticSetting::Error, "asset node must contain a name attribute",
/**
* The attribute is not valid for <bundle> nodes inside <asset>.
*/
OLS05061, DiagnosticSetting::Error, "Invalid attribute {0} in the bundle node under asset",
/**
* The attribute is not valid for <path> nodes inside <asset>.
*/
OLS05062, DiagnosticSetting::Error, "Invalid attribute {0} in the path node under asset",
/**
* Only bundle, path, or field nodes are allowed as children of <asset>.
*/
OLS05063, DiagnosticSetting::Error, "Invalid child node {0} in asset node. Only bundle, path, or field allowed",
/**
* bundle node is required inside <asset>.
*/
OLS05064, DiagnosticSetting::Error, "Bundle node is required inside <asset>",
/**
* path node is required inside <asset>.
*/
OLS05065, DiagnosticSetting::Error, "Path node is required inside <asset>",
/**
* Bundle node in asset cannot be empty.
*/
OLS05066, DiagnosticSetting::Error, "Bundle node in asset cannot be empty",
/**
* Path node in asset cannot be empty.
*/
OLS05067, DiagnosticSetting::Error, "Path node in asset cannot be empty",
}
127 changes: 125 additions & 2 deletions server/src/core/xml_arch_builder_rng_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::rc::Rc;
use lsp_types::{Diagnostic, Position, Range};
use roxmltree::Node;

use crate::{constants::OYarn, core::{diagnostics::{create_diagnostic, DiagnosticCode}, odoo::SyncOdoo, xml_data::{OdooData, XmlDataDelete, OdooDataField, XmlDataMenuItem, OdooDataRecord, XmlDataTemplate}}, oyarn, threads::SessionInfo, Sy};
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 super::xml_arch_builder::XmlArchBuilder;

Expand Down Expand Up @@ -36,7 +36,9 @@ impl XmlArchBuilder {
|| self.load_template(session, &child, diagnostics)
|| self.load_delete(session, &child, diagnostics)
|| self.load_function(session, &child, diagnostics)
|| child.is_text() || child.is_comment()) {
|| self.load_asset(session, &child, diagnostics)
|| child.is_text() || child.is_comment()
) {
if let Some(diagnostic) = create_diagnostic(session, DiagnosticCode::OLS05005, &[child.tag_name().name(), node.tag_name().name()]) {
diagnostics.push(
Diagnostic {
Expand Down Expand Up @@ -603,4 +605,125 @@ impl XmlArchBuilder {
}
true
}

fn load_asset(&mut self, session: &mut SessionInfo, node: &Node, diagnostics: &mut Vec<Diagnostic>) -> bool {
if node.tag_name().name() != "asset" { return false; }
// Validate required attributes: id, name
let mut found_id = None;
let mut has_name = false;
for attr in node.attributes() {
match attr.name() {
"id" => { found_id = Some(attr.value().to_string()); },
"name" => { has_name = true; },
"active" => {},
_ => {
if let Some(diagnostic) = create_diagnostic(session, DiagnosticCode::OLS05058, &[attr.name()]) {
diagnostics.push(Diagnostic {
range: Range { start: Position::new(attr.range().start as u32, 0), end: Position::new(attr.range().end as u32, 0) },
..diagnostic.clone()
});
}
}
}
}
if found_id.is_none() {
if let Some(diagnostic) = create_diagnostic(session, DiagnosticCode::OLS05059, &[]) {
diagnostics.push(Diagnostic {
range: Range { start: Position::new(node.range().start as u32, 0), end: Position::new(node.range().end as u32, 0) },
..diagnostic.clone()
});
}
}
else if !has_name {
if let Some(diagnostic) = create_diagnostic(session, DiagnosticCode::OLS05060, &[]) {
diagnostics.push(Diagnostic {
range: Range { start: Position::new(node.range().start as u32, 0), end: Position::new(node.range().end as u32, 0) },
..diagnostic.clone()
});
}
}
// Validate children: must be bundle, path, or field
let (mut has_bundle, mut has_path) = (false, false);
for child in node.children().filter(|n| n.is_element()) {
match child.tag_name().name() {
"bundle" => {
has_bundle = true;
for attr in child.attributes() {
if attr.name() != "directive" {
if let Some(diagnostic) = create_diagnostic(session, DiagnosticCode::OLS05061, &[attr.name()]) {
diagnostics.push(Diagnostic {
range: Range { start: Position::new(attr.range().start as u32, 0), end: Position::new(attr.range().end as u32, 0) },
..diagnostic.clone()
});
}
}
}
if child.text().is_none() {
if let Some(diagnostic) = create_diagnostic(session, DiagnosticCode::OLS05066, &[]) {
diagnostics.push(Diagnostic {
range: Range { start: Position::new(child.range().start as u32, 0), end: Position::new(child.range().end as u32, 0) },
..diagnostic.clone()
});
}
}
},
"path" => {
has_path = true;
if child.attributes().count() > 0 {
for attr in child.attributes() {
if let Some(diagnostic) = create_diagnostic(session, DiagnosticCode::OLS05062, &[attr.name()]) {
diagnostics.push(Diagnostic {
range: Range { start: Position::new(attr.range().start as u32, 0), end: Position::new(attr.range().end as u32, 0) },
..diagnostic.clone()
});
}
}
}
if child.text().is_none() {
if let Some(diagnostic) = create_diagnostic(session, DiagnosticCode::OLS05067, &[]) {
diagnostics.push(Diagnostic {
range: Range { start: Position::new(child.range().start as u32, 0), end: Position::new(child.range().end as u32, 0) },
..diagnostic.clone()
});
}
}
},
"field" => {
self.load_field(session, &child, diagnostics);
},
"active" => {},
_ => {
if let Some(diagnostic) = create_diagnostic(session, DiagnosticCode::OLS05063, &[child.tag_name().name()]) {
diagnostics.push(Diagnostic {
range: Range { start: Position::new(child.range().start as u32, 0), end: Position::new(child.range().end as u32, 0) },
..diagnostic.clone()
});
}
}
}
}
if !has_bundle {
if let Some(diagnostic) = create_diagnostic(session, DiagnosticCode::OLS05064, &[]) {
diagnostics.push(Diagnostic {
range: Range { start: Position::new(node.range().start as u32, 0), end: Position::new(node.range().end as u32, 0) },
..diagnostic.clone()
});
}
}
if !has_path {
if let Some(diagnostic) = create_diagnostic(session, DiagnosticCode::OLS05065, &[]) {
diagnostics.push(Diagnostic {
range: Range { start: Position::new(node.range().start as u32, 0), end: Position::new(node.range().end as u32, 0) },
..diagnostic.clone()
});
}
}
let data = OdooData::ASSET(XmlDataAsset {
file_symbol: Rc::downgrade(&self.xml_symbol),
xml_id: found_id.clone().map(|id| oyarn!("{}", id)),
range: node.range().clone(),
});
self.on_operation_creation(session, found_id, node, data, diagnostics);
true
}
}
15 changes: 15 additions & 0 deletions server/src/core/xml_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub enum OdooData {
RECORD(OdooDataRecord),
MENUITEM(XmlDataMenuItem),
TEMPLATE(XmlDataTemplate),
ASSET(XmlDataAsset),
DELETE(XmlDataDelete),
}

Expand Down Expand Up @@ -43,6 +44,13 @@ pub struct XmlDataTemplate {
pub range: Range<usize>,
}

#[derive(Debug, Clone)]
pub struct XmlDataAsset {
pub file_symbol: Weak<RefCell<Symbol>>,
pub xml_id: Option<OYarn>,
pub range: Range<usize>,
}

#[derive(Debug, Clone)]
pub struct XmlDataDelete {
pub file_symbol: Weak<RefCell<Symbol>>,
Expand All @@ -67,6 +75,9 @@ impl OdooData {
OdooData::DELETE(delete) => {
delete.file_symbol = Rc::downgrade(xml_symbol);
},
OdooData::ASSET(asset) => {
asset.file_symbol = Rc::downgrade(xml_symbol);
}
}
}

Expand All @@ -76,6 +87,7 @@ impl OdooData {
OdooData::MENUITEM(menu_item) => menu_item.range.clone(),
OdooData::TEMPLATE(template) => template.range.clone(),
OdooData::DELETE(delete) => delete.range.clone(),
OdooData::ASSET(asset) => asset.range.clone(),
}
}

Expand Down Expand Up @@ -103,6 +115,9 @@ impl OdooData {
},
OdooData::DELETE(delete) => {
Some(delete.file_symbol.clone())
},
OdooData::ASSET(asset) => {
Some(asset.file_symbol.clone())
}
}
}
Expand Down
7 changes: 6 additions & 1 deletion server/src/core/xml_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::{cell::RefCell, cmp::Ordering, collections::{HashMap, HashSet}, rc::Rc}
use lsp_types::{Diagnostic, Position, Range};
use tracing::{info, trace};

use crate::{Sy, constants::{BuildSteps, DEBUG_STEPS, OYarn}, core::{diagnostics::{DiagnosticCode, create_diagnostic}, entry_point::{EntryPoint, EntryPointType}, evaluation::ContextValue, file_mgr::FileInfo, model::Model, odoo::SyncOdoo, symbols::symbol::Symbol, xml_data::{OdooData, OdooDataRecord, XmlDataDelete, XmlDataMenuItem, XmlDataTemplate}}, oyarn, threads::SessionInfo, utils::compare_semver};
use crate::{Sy, constants::{BuildSteps, DEBUG_STEPS, OYarn}, core::{diagnostics::{DiagnosticCode, create_diagnostic}, entry_point::{EntryPoint, EntryPointType}, evaluation::ContextValue, file_mgr::FileInfo, model::Model, odoo::SyncOdoo, symbols::symbol::Symbol, xml_data::{OdooData, OdooDataRecord, XmlDataAsset, XmlDataDelete, XmlDataMenuItem, XmlDataTemplate}}, oyarn, threads::SessionInfo, utils::compare_semver};



Expand Down Expand Up @@ -67,6 +67,7 @@ impl XmlValidator {
OdooData::MENUITEM(xml_data_menu_item) => self.validate_menu_item(session, module, xml_data_menu_item, diagnostics, dependencies, model_dependencies, missing_model_dependencies),
OdooData::TEMPLATE(xml_data_template) => self.validate_template(session, module, xml_data_template, diagnostics, dependencies, model_dependencies, missing_model_dependencies),
OdooData::DELETE(xml_data_delete) => self.validate_delete(session, module, xml_data_delete, diagnostics, dependencies, model_dependencies, missing_model_dependencies),
OdooData::ASSET(xml_data_asset) => self.validate_asset(session, module, xml_data_asset, diagnostics, dependencies, model_dependencies, missing_model_dependencies),
}
}
fn validate_record(&self, session: &mut SessionInfo, module: &Rc<RefCell<Symbol>>, xml_data_record: &OdooDataRecord, diagnostics: &mut Vec<Diagnostic>, dependencies: &mut Vec<Rc<RefCell<Symbol>>>, model_dependencies: &mut Vec<Rc<RefCell<Model>>>, missing_model_dependencies: &mut HashSet<OYarn>) {
Expand Down Expand Up @@ -254,4 +255,8 @@ impl XmlValidator {
fn validate_delete(&self, _session: &mut SessionInfo, _module: &Rc<RefCell<Symbol>>, _xml_data_delete: &XmlDataDelete, _diagnostics: &mut Vec<Diagnostic>, _dependencies: &mut Vec<Rc<RefCell<Symbol>>>, _model_dependencies: &mut Vec<Rc<RefCell<Model>>>, _missing_model_dependencies: &mut HashSet<OYarn>) {

}

fn validate_asset(&self, _session: &mut SessionInfo, _module: &Rc<RefCell<Symbol>>, _xml_data_asset: &XmlDataAsset, _diagnostics: &mut Vec<Diagnostic>, _dependencies: &mut Vec<Rc<RefCell<Symbol>>>, _model_dependencies: &mut Vec<Rc<RefCell<Model>>>, _missing_model_dependencies: &mut HashSet<OYarn>) {

}
}
27 changes: 27 additions & 0 deletions server/tests/data/addons/module_for_diagnostics/data/bikes.xml
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,31 @@
<record id="bikes.bike" model="bikes.bike"><field name="fine"/></record> <!-- OLS05057 -->
<record id="bikes.bike" model="ir.ui.view"><field name="model">module_2.empty_model</field></record> <!-- OLS05055 -->
<record id="bikes.bike" model="ir.ui.view"><field name="model">wrong.model</field></record> <!-- OLS05056 -->
<asset invalid="invalid" id="id" name="name"> <!-- OLS05058 -->
<bundle>data</bundle>
<path>ols_tests/tests/something.scss</path>
</asset>
<asset name="no_id"> <!-- OLS05059 -->
<bundle>data</bundle>
<path>ols_tests/tests/something.scss</path>
</asset>
<asset id="no_name"> <!-- OLS05060 -->
<bundle>data</bundle>
<path>ols_tests/tests/something.scss</path>
</asset>
<asset id="id" name="name" active="false">
<bundle invalid_tag="t" directive="directive_is_allowed">data</bundle> <!-- OLS05061 -->
<path invalid_tag="t">ols_tests/tests/something.scss</path> <!-- OLS05062 -->
<invalid /> <!-- OLS05063 -->
</asset>
<asset id="id" name="name" active="false">
<path>ols_tests/tests/something.scss</path> <!-- OLS05064 -->
</asset>
<asset id="id" name="name" active="false">
<bundle>data</bundle> <!-- OLS05065 -->
</asset>
<asset id="id" name="name" active="false">
<bundle></bundle> <!-- OLS05066 -->
<path></path> <!-- OLS05067 -->
</asset>
</odoo>
10 changes: 10 additions & 0 deletions server/tests/diagnostics/ols05000s.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,16 @@ fn test_ols05000s_xml_file() {
check_xml_diag("OLS05057", 91);
check_xml_diag("OLS05055", 92);
check_xml_diag("OLS05056", 93);
check_xml_diag("OLS05058", 94);
check_xml_diag("OLS05059", 98);
check_xml_diag("OLS05060", 102);
check_xml_diag("OLS05061", 107);
check_xml_diag("OLS05062", 108);
check_xml_diag("OLS05063", 109);
check_xml_diag("OLS05064", 112);
check_xml_diag("OLS05065", 115);
check_xml_diag("OLS05066", 118);
check_xml_diag("OLS05067", 119);
}

#[test]
Expand Down