Keep all nodes for a given element (even if it is optimized out)

This commit is contained in:
Olivier Goffart 2024-01-25 11:57:25 +01:00
parent ffaf19812c
commit 09dc25f107
10 changed files with 40 additions and 36 deletions

View file

@ -650,8 +650,10 @@ pub struct Element {
/// How many times the element was inlined /// How many times the element was inlined
pub inline_depth: i32, pub inline_depth: i32,
/// The AST node, if available /// The AST nodes, if available.
pub node: Option<syntax_nodes::Element>, /// There can be several in case of inlining or optimization (child merged into their parent).
/// The order in the list is first the parent, and then the removed children.
pub node: Vec<syntax_nodes::Element>,
/// This element was a layout that has been lowered to a Rectangle /// This element was a layout that has been lowered to a Rectangle
pub layout: Option<crate::layout::Layout>, pub layout: Option<crate::layout::Layout>,
@ -659,11 +661,11 @@ pub struct Element {
impl Spanned for Element { impl Spanned for Element {
fn span(&self) -> crate::diagnostics::Span { fn span(&self) -> crate::diagnostics::Span {
self.node.as_ref().map(|n| n.span()).unwrap_or_default() self.node.first().map(|n| n.span()).unwrap_or_default()
} }
fn source_file(&self) -> Option<&crate::diagnostics::SourceFile> { fn source_file(&self) -> Option<&crate::diagnostics::SourceFile> {
self.node.as_ref().map(|n| &n.source_file) self.node.first().map(|n| &n.source_file)
} }
} }
@ -897,7 +899,7 @@ impl Element {
let mut r = Element { let mut r = Element {
id, id,
base_type, base_type,
node: Some(node.clone()), node: vec![node.clone()],
is_legacy_syntax, is_legacy_syntax,
..Default::default() ..Default::default()
}; };
@ -1632,7 +1634,7 @@ impl Element {
/// Returns the element's name as specified in the markup, not normalized. /// Returns the element's name as specified in the markup, not normalized.
pub fn original_name(&self) -> String { pub fn original_name(&self) -> String {
self.node self.node
.as_ref() .first()
.and_then(|n| n.child_token(parser::SyntaxKind::Identifier)) .and_then(|n| n.child_token(parser::SyntaxKind::Identifier))
.map(|n| n.to_string()) .map(|n| n.to_string())
.unwrap_or_else(|| self.id.clone()) .unwrap_or_else(|| self.id.clone())
@ -1777,7 +1779,7 @@ fn animation_element_from_node(
None None
} else { } else {
let mut anim_element = let mut anim_element =
Element { id: "".into(), base_type: anim_type, node: None, ..Default::default() }; Element { id: "".into(), base_type: anim_type, ..Default::default() };
anim_element.parse_bindings( anim_element.parse_bindings(
anim.Binding().filter_map(|b| { anim.Binding().filter_map(|b| {
Some((b.child_token(SyntaxKind::Identifier)?, b.BindingExpression().into())) Some((b.child_token(SyntaxKind::Identifier)?, b.BindingExpression().into()))

View file

@ -130,6 +130,7 @@ fn inline_element(
} }
elem_mut.children = new_children; elem_mut.children = new_children;
elem_mut.node.extend_from_slice(&inlined_component.root_element.borrow().node);
if let ElementType::Component(c) = &mut elem_mut.base_type { if let ElementType::Component(c) = &mut elem_mut.base_type {
if c.parent_element.upgrade().is_some() { if c.parent_element.upgrade().is_some() {

View file

@ -22,6 +22,7 @@ pub fn optimize_useless_rectangles(root_component: &Rc<Component>) {
} }
parent.children.extend(std::mem::take(&mut elem.borrow_mut().children)); parent.children.extend(std::mem::take(&mut elem.borrow_mut().children));
parent.node.extend(std::mem::take(&mut elem.borrow_mut().node));
let enclosing = parent.enclosing_component.upgrade().unwrap(); let enclosing = parent.enclosing_component.upgrade().unwrap();

View file

@ -136,7 +136,7 @@ fn find_element_at_offset(component: &Rc<Component>, path: PathBuf, offset: u32)
if elem.borrow().repeated.is_some() { if elem.borrow().repeated.is_some() {
return; return;
} }
if let Some(node) = elem.borrow().node.as_ref().and_then(|n| n.QualifiedName()) { for node in elem.borrow().node.iter().filter_map(|n| n.QualifiedName()) {
if node.source_file.path() == path && node.text_range().contains(offset.into()) { if node.source_file.path() == path && node.text_range().contains(offset.into()) {
result.push(elem.clone()); result.push(elem.clone());
} }

View file

@ -525,7 +525,7 @@ pub async fn set_binding_command(
element element
.borrow() .borrow()
.node .node
.as_ref() .first()
.ok_or("The element was found, but had no range defined!")?, .ok_or("The element was found, but had no range defined!")?,
) )
.ok_or("Failed to map node")?; .ok_or("Failed to map node")?;
@ -608,7 +608,7 @@ pub async fn remove_binding_command(
element element
.borrow() .borrow()
.node .node
.as_ref() .first()
.ok_or("The element was found, but had no range defined!")?, .ok_or("The element was found, but had no range defined!")?,
) )
.ok_or("Failed to map node")?; .ok_or("Failed to map node")?;
@ -755,7 +755,7 @@ fn get_document_and_offset<'a>(
} }
fn element_contains(element: &i_slint_compiler::object_tree::ElementRc, offset: u32) -> bool { fn element_contains(element: &i_slint_compiler::object_tree::ElementRc, offset: u32) -> bool {
element.borrow().node.as_ref().map_or(false, |n| n.text_range().contains(offset.into())) element.borrow().node.first().map_or(false, |n| n.text_range().contains(offset.into()))
} }
pub fn element_at_position( pub fn element_at_position(
@ -1110,7 +1110,7 @@ fn get_document_symbols(
.iter() .iter()
.filter_map(|c| { .filter_map(|c| {
let root_element = c.root_element.borrow(); let root_element = c.root_element.borrow();
let element_node = root_element.node.as_ref()?; let element_node = root_element.node.first()?;
let component_node = syntax_nodes::Component::new(element_node.parent()?)?; let component_node = syntax_nodes::Component::new(element_node.parent()?)?;
let selection_range = map_node(&component_node.DeclaredIdentifier())?; let selection_range = map_node(&component_node.DeclaredIdentifier())?;
if c.id.is_empty() { if c.id.is_empty() {
@ -1161,8 +1161,8 @@ fn get_document_symbols(
.filter_map(|child| { .filter_map(|child| {
let e = child.borrow(); let e = child.borrow();
Some(DocumentSymbol { Some(DocumentSymbol {
range: map_node(e.node.as_ref()?)?, range: map_node(e.node.first()?)?,
selection_range: map_node(e.node.as_ref()?.QualifiedName().as_ref()?)?, selection_range: map_node(e.node.first()?.QualifiedName().as_ref()?)?,
name: e.base_type.to_string(), name: e.base_type.to_string(),
detail: (!e.id.is_empty()).then(|| e.id.clone()), detail: (!e.id.is_empty()).then(|| e.id.clone()),
kind: lsp_types::SymbolKind::VARIABLE, kind: lsp_types::SymbolKind::VARIABLE,
@ -1194,7 +1194,7 @@ fn get_code_lenses(
// Handle preview lens // Handle preview lens
r.extend(inner_components.iter().filter(|c| !c.is_global()).filter_map(|c| { r.extend(inner_components.iter().filter(|c| !c.is_global()).filter_map(|c| {
Some(CodeLens { Some(CodeLens {
range: map_node(c.root_element.borrow().node.as_ref()?)?, range: map_node(c.root_element.borrow().node.first()?)?,
command: Some(create_show_preview_command(true, &text_document.uri, c.id.as_str())), command: Some(create_show_preview_command(true, &text_document.uri, c.id.as_str())),
data: None, data: None,
}) })

View file

@ -37,7 +37,7 @@ pub fn goto_definition(
let doc = document_cache.documents.get_document(node.source_file.path())?; let doc = document_cache.documents.get_document(node.source_file.path())?;
match doc.local_registry.lookup_element(&qual.to_string()) { match doc.local_registry.lookup_element(&qual.to_string()) {
Ok(ElementType::Component(c)) => { Ok(ElementType::Component(c)) => {
goto_node(c.root_element.borrow().node.as_ref()?) goto_node(c.root_element.borrow().node.first()?)
} }
_ => None, _ => None,
} }
@ -68,7 +68,7 @@ pub fn goto_definition(
LookupResult::Expression { LookupResult::Expression {
expression: Expression::ElementReference(e), expression: Expression::ElementReference(e),
.. ..
} => e.upgrade()?.borrow().node.clone()?.into(), } => e.upgrade()?.borrow().node.first()?.clone().into(),
LookupResult::Expression { LookupResult::Expression {
expression: expression:
Expression::CallbackReference(nr, _) Expression::CallbackReference(nr, _)
@ -107,7 +107,7 @@ pub fn goto_definition(
let doc = document_cache.documents.get_document(node.source_file.path())?; let doc = document_cache.documents.get_document(node.source_file.path())?;
let imp_name = i_slint_compiler::typeloader::ImportedName::from_node(n); let imp_name = i_slint_compiler::typeloader::ImportedName::from_node(n);
return match doc.local_registry.lookup_element(&imp_name.internal_name) { return match doc.local_registry.lookup_element(&imp_name.internal_name) {
Ok(ElementType::Component(c)) => goto_node(c.root_element.borrow().node.as_ref()?), Ok(ElementType::Component(c)) => goto_node(c.root_element.borrow().node.first()?),
_ => None, _ => None,
}; };
} else if let Some(n) = syntax_nodes::ImportSpecifier::new(node.clone()) { } else if let Some(n) = syntax_nodes::ImportSpecifier::new(node.clone()) {

View file

@ -234,7 +234,7 @@ fn find_expression_range(
} }
fn find_property_binding_offset(element: &Element, property_name: &str) -> Option<u32> { fn find_property_binding_offset(element: &Element, property_name: &str) -> Option<u32> {
let element_range = element.node.as_ref()?.text_range(); let element_range = element.node.first()?.text_range();
if let Some(v) = element.bindings.get(property_name) { if let Some(v) = element.bindings.get(property_name) {
if let Some(span) = &v.borrow().span { if let Some(span) = &v.borrow().span {
@ -252,7 +252,7 @@ fn find_property_binding_offset(element: &Element, property_name: &str) -> Optio
} }
fn insert_property_definitions(element: &Element, properties: &mut Vec<PropertyInformation>) { fn insert_property_definitions(element: &Element, properties: &mut Vec<PropertyInformation>) {
if let Some(element_node) = element.node.as_ref() { if let Some(element_node) = element.node.first() {
for prop_info in properties { for prop_info in properties {
if let Some(offset) = find_property_binding_offset(element, prop_info.name.as_str()) { if let Some(offset) = find_property_binding_offset(element, prop_info.name.as_str()) {
prop_info.defined_at = find_expression_range(element_node, offset); prop_info.defined_at = find_expression_range(element_node, offset);
@ -390,14 +390,14 @@ fn get_properties(element: &ElementRc) -> Vec<PropertyInformation> {
fn find_block_range(element: &ElementRc) -> Option<lsp_types::Range> { fn find_block_range(element: &ElementRc) -> Option<lsp_types::Range> {
let element = element.borrow(); let element = element.borrow();
let node = element.node.as_ref(); let node = element.node.first()?;
let open_brace = node?.child_token(SyntaxKind::LBrace)?; let open_brace = node.child_token(SyntaxKind::LBrace)?;
let close_brace = node?.child_token(SyntaxKind::RBrace)?; let close_brace = node.child_token(SyntaxKind::RBrace)?;
Some(lsp_types::Range::new( Some(lsp_types::Range::new(
map_position(node?.source_file()?, open_brace.text_range().start()), map_position(node.source_file()?, open_brace.text_range().start()),
map_position(node?.source_file()?, close_brace.text_range().end()), map_position(node.source_file()?, close_brace.text_range().end()),
)) ))
} }
@ -407,7 +407,7 @@ fn get_element_information(element: &ElementRc) -> ElementInformation {
ElementInformation { ElementInformation {
id: e.id.clone(), id: e.id.clone(),
type_name: e.base_type.to_string(), type_name: e.base_type.to_string(),
range: e.node.as_ref().and_then(|n| map_node(n)), range: e.node.first().and_then(|n| map_node(n)),
} }
} }
@ -628,7 +628,7 @@ fn set_binding_on_known_property(
// element. Returns the element indent followed by the block indent // element. Returns the element indent followed by the block indent
pub fn find_element_indent(element: &ElementRc) -> Option<String> { pub fn find_element_indent(element: &ElementRc) -> Option<String> {
let mut token = let mut token =
element.borrow().node.as_ref().and_then(|n| n.first_token()).and_then(|t| t.prev_token()); element.borrow().node.first().and_then(|n| n.first_token()).and_then(|t| t.prev_token());
while let Some(t) = token { while let Some(t) = token {
if t.kind() == SyntaxKind::Whitespace && t.text().contains('\n') { if t.kind() == SyntaxKind::Whitespace && t.text().contains('\n') {
return t.text().split('\n').last().map(|s| s.to_owned()); return t.text().split('\n').last().map(|s| s.to_owned());
@ -658,7 +658,7 @@ pub(crate) fn set_binding(
let new_expression_type = { let new_expression_type = {
let element = element.borrow(); let element = element.borrow();
if let Some(node) = element.node.as_ref() { if let Some(node) = element.node.first() {
let expr_context_info = let expr_context_info =
ExpressionContextInfo::new(node.clone(), property_name.to_string(), false); ExpressionContextInfo::new(node.clone(), property_name.to_string(), false);
with_property_lookup_ctx(document_cache, &expr_context_info, |ctx| { with_property_lookup_ctx(document_cache, &expr_context_info, |ctx| {
@ -740,10 +740,10 @@ pub(crate) fn remove_binding(
property_name: &str, property_name: &str,
) -> Result<lsp_types::WorkspaceEdit> { ) -> Result<lsp_types::WorkspaceEdit> {
let element = element.borrow(); let element = element.borrow();
let source_file = element.node.as_ref().and_then(|n| n.source_file()); let source_file = element.node.first().and_then(|n| n.source_file());
let range = find_property_binding_offset(&element, property_name) let range = find_property_binding_offset(&element, property_name)
.and_then(|offset| element.node.as_ref()?.token_at_offset(offset.into()).right_biased()) .and_then(|offset| element.node.first()?.token_at_offset(offset.into()).right_biased())
.and_then(|token| { .and_then(|token| {
for ancestor in token.parent_ancestors() { for ancestor in token.parent_ancestors() {
if (ancestor.kind() == SyntaxKind::Binding) if (ancestor.kind() == SyntaxKind::Binding)

View file

@ -26,7 +26,7 @@ fn self_or_embedded_component_root(element: &ElementRc) -> ElementRc {
fn lsp_element_position(element: &ElementRc) -> Option<(String, lsp_types::Range)> { fn lsp_element_position(element: &ElementRc) -> Option<(String, lsp_types::Range)> {
let e = &element.borrow(); let e = &element.borrow();
e.node e.node
.as_ref() .first()
.and_then(|n| { .and_then(|n| {
n.parent() n.parent()
.filter(|p| p.kind() == i_slint_compiler::parser::SyntaxKind::SubElement) .filter(|p| p.kind() == i_slint_compiler::parser::SyntaxKind::SubElement)
@ -77,7 +77,7 @@ fn select_element(component_instance: &ComponentInstance, selected_element: &Ele
} }
fn element_offset(element: &ElementRc) -> Option<(PathBuf, u32)> { fn element_offset(element: &ElementRc) -> Option<(PathBuf, u32)> {
let Some(node) = &element.borrow().node else { let Some(node) = element.borrow().node.first().cloned() else {
return None; return None;
}; };
let path = node.source_file.path().to_path_buf(); let path = node.source_file.path().to_path_buf();
@ -86,7 +86,7 @@ fn element_offset(element: &ElementRc) -> Option<(PathBuf, u32)> {
} }
fn element_source_range(element: &ElementRc) -> Option<(SourceFile, TextRange)> { fn element_source_range(element: &ElementRc) -> Option<(SourceFile, TextRange)> {
let Some(node) = &element.borrow().node else { let Some(node) = element.borrow().node.first().cloned() else {
return None; return None;
}; };
let source_file = node.source_file.clone(); let source_file = node.source_file.clone();
@ -140,7 +140,7 @@ impl SelectionCandidate {
fn is_builtin(&self) -> bool { fn is_builtin(&self) -> bool {
let elem = self.element.borrow(); let elem = self.element.borrow();
let Some(node) = &elem.node else { let Some(node) = elem.node.first() else {
return true; return true;
}; };
let Some(sf) = node.source_file() else { let Some(sf) = node.source_file() else {

View file

@ -152,7 +152,7 @@ pub fn with_property_lookup_ctx<R>(
loop { loop {
scope.push(it.clone()); scope.push(it.clone());
if let Some(c) = it.clone().borrow().children.iter().find(|c| { if let Some(c) = it.clone().borrow().children.iter().find(|c| {
c.borrow().node.as_ref().map_or(false, |n| n.text_range().contains(offset)) c.borrow().node.first().map_or(false, |n| n.text_range().contains(offset))
}) { }) {
it = c.clone(); it = c.clone();
} else { } else {

View file

@ -222,7 +222,7 @@ fn visit_node(
.borrow() .borrow()
.children .children
.iter() .iter()
.find(|c| c.borrow().node.as_ref().map_or(false, |n| n.node == node.node)) .find(|c| c.borrow().node.first().map_or(false, |n| n.node == node.node))
.cloned() .cloned()
} else if let Some(parent_co) = &state.current_component { } else if let Some(parent_co) = &state.current_component {
if node.parent().map_or(false, |n| n.kind() == SyntaxKind::Component) { if node.parent().map_or(false, |n| n.kind() == SyntaxKind::Component) {