mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-03 07:04:34 +00:00
Add aggregating BuildDiagnostics
This type aggregates different per-file diagnostics into a similar interface, in preparation for reporting diagnostics from multiple source files.
This commit is contained in:
parent
5dc53f0f79
commit
ada5f68908
6 changed files with 115 additions and 23 deletions
|
@ -1,3 +1,6 @@
|
|||
use std::collections::HashMap;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct Span {
|
||||
pub offset: usize,
|
||||
|
@ -206,3 +209,86 @@ impl quote::ToTokens for FileDiagnostics {
|
|||
quote!(#(#diags)*).to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct BuildDiagnostics {
|
||||
per_input_file_diagnostics: HashMap<PathBuf, FileDiagnostics>,
|
||||
internal_errors: Option<FileDiagnostics>,
|
||||
}
|
||||
|
||||
impl BuildDiagnostics {
|
||||
pub fn add(&mut self, diagnostics: FileDiagnostics) {
|
||||
match self.per_input_file_diagnostics.get_mut(&diagnostics.current_path) {
|
||||
Some(existing_diags) => existing_diags.inner.extend(diagnostics.inner),
|
||||
None => {
|
||||
self.per_input_file_diagnostics
|
||||
.insert(diagnostics.current_path.clone(), diagnostics);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push_internal_error(&mut self, err: Diagnostic) {
|
||||
self.internal_errors
|
||||
.get_or_insert_with(|| FileDiagnostics {
|
||||
current_path: "[internal error]".into(),
|
||||
..Default::default()
|
||||
})
|
||||
.inner
|
||||
.push(err)
|
||||
}
|
||||
|
||||
fn iter(&self) -> impl Iterator<Item = &FileDiagnostics> {
|
||||
self.per_input_file_diagnostics.values().chain(self.internal_errors.iter())
|
||||
}
|
||||
|
||||
fn into_iter(self) -> impl Iterator<Item = FileDiagnostics> {
|
||||
self.per_input_file_diagnostics
|
||||
.into_iter()
|
||||
.map(|(_, diag)| diag)
|
||||
.chain(self.internal_errors.into_iter())
|
||||
}
|
||||
|
||||
fn iter_mut(&mut self) -> impl Iterator<Item = &mut FileDiagnostics> {
|
||||
self.per_input_file_diagnostics.values_mut().chain(self.internal_errors.iter_mut())
|
||||
}
|
||||
|
||||
pub fn has_error(&self) -> bool {
|
||||
self.iter().any(|diag| diag.has_error())
|
||||
}
|
||||
|
||||
pub fn to_string_vec(&self) -> Vec<String> {
|
||||
self.iter()
|
||||
.flat_map(|diag| {
|
||||
diag.to_string_vec()
|
||||
.iter()
|
||||
.map(|err| format!("{}: {}", diag.current_path.to_string_lossy(), err))
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn print(self) {
|
||||
self.into_iter().for_each(|diag| diag.print());
|
||||
}
|
||||
|
||||
#[cfg(feature = "display-diagnostics")]
|
||||
pub fn check_and_exit_on_error(self) -> Self {
|
||||
if self.has_error() {
|
||||
self.print();
|
||||
std::process::exit(-1);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
#[cfg(feature = "proc_macro_span")]
|
||||
pub fn map_offsets_to_span(&mut self, span_map: &[crate::parser::Token]) {
|
||||
self.iter_mut().for_each(|diag| diag.map_offsets_to_span(span_map))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "proc_macro_span")]
|
||||
impl quote::ToTokens for BuildDiagnostics {
|
||||
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
|
||||
self.iter().for_each(|diag| diag.to_tokens(tokens))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ The module responsible for the code generation.
|
|||
There is one sub module for every language
|
||||
*/
|
||||
|
||||
use crate::diagnostics::FileDiagnostics;
|
||||
use crate::diagnostics::BuildDiagnostics;
|
||||
use crate::object_tree::{Component, ElementRc};
|
||||
use std::rc::Rc;
|
||||
|
||||
|
@ -51,7 +51,7 @@ pub fn generate(
|
|||
format: OutputFormat,
|
||||
destination: &mut impl std::io::Write,
|
||||
component: &Rc<Component>,
|
||||
diag: &mut FileDiagnostics,
|
||||
diag: &mut BuildDiagnostics,
|
||||
) -> std::io::Result<()> {
|
||||
#![allow(unused_variables)]
|
||||
#![allow(unreachable_code)]
|
||||
|
|
|
@ -127,7 +127,7 @@ mod cpp_ast {
|
|||
}
|
||||
}
|
||||
|
||||
use crate::diagnostics::{CompilerDiagnostic, FileDiagnostics};
|
||||
use crate::diagnostics::{BuildDiagnostics, CompilerDiagnostic};
|
||||
use crate::expression_tree::Expression;
|
||||
use crate::object_tree::{Component, Element, ElementRc, RepeatedElementInfo};
|
||||
use crate::parser::Spanned;
|
||||
|
@ -360,7 +360,7 @@ fn handle_repeater(
|
|||
/// Returns the text of the C++ code produced by the given root component
|
||||
pub fn generate(
|
||||
component: &Rc<Component>,
|
||||
diag: &mut FileDiagnostics,
|
||||
diag: &mut BuildDiagnostics,
|
||||
) -> Option<impl std::fmt::Display> {
|
||||
let mut file = File::default();
|
||||
|
||||
|
@ -377,7 +377,7 @@ pub fn generate(
|
|||
}
|
||||
}
|
||||
|
||||
fn generate_component(file: &mut File, component: &Rc<Component>, diag: &mut FileDiagnostics) {
|
||||
fn generate_component(file: &mut File, component: &Rc<Component>, diag: &mut BuildDiagnostics) {
|
||||
let component_id = component_id(component);
|
||||
let mut component_struct = Struct { name: component_id.clone(), ..Default::default() };
|
||||
|
||||
|
@ -405,7 +405,7 @@ fn generate_component(file: &mut File, component: &Rc<Component>, diag: &mut Fil
|
|||
span: property_decl.type_location.clone(),
|
||||
};
|
||||
|
||||
diag.push_compiler_error(err);
|
||||
diag.push_internal_error(err.into());
|
||||
"".into()
|
||||
});
|
||||
|
||||
|
@ -454,15 +454,18 @@ fn generate_component(file: &mut File, component: &Rc<Component>, diag: &mut Fil
|
|||
.ty()
|
||||
.cpp_type()
|
||||
.unwrap_or_else(|| {
|
||||
diag.push_compiler_error(CompilerDiagnostic {
|
||||
message: "Cannot map property type to C++".into(),
|
||||
span: parent_element
|
||||
.borrow()
|
||||
.node
|
||||
.as_ref()
|
||||
.map(|n| n.span())
|
||||
.unwrap_or_default(),
|
||||
});
|
||||
diag.push_internal_error(
|
||||
CompilerDiagnostic {
|
||||
message: "Cannot map property type to C++".into(),
|
||||
span: parent_element
|
||||
.borrow()
|
||||
.node
|
||||
.as_ref()
|
||||
.map(|n| n.span())
|
||||
.unwrap_or_default(),
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
String::default()
|
||||
})
|
||||
.to_owned();
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*! module for the Rust code generator
|
||||
*/
|
||||
|
||||
use crate::diagnostics::{CompilerDiagnostic, FileDiagnostics};
|
||||
use crate::diagnostics::{BuildDiagnostics, CompilerDiagnostic};
|
||||
use crate::expression_tree::{Expression, NamedReference, OperatorClass, Path};
|
||||
use crate::object_tree::{Component, ElementRc};
|
||||
use crate::parser::Spanned;
|
||||
|
@ -38,7 +38,7 @@ fn rust_type(
|
|||
/// Generate the rust code for the given component.
|
||||
///
|
||||
/// Fill the diagnostic in case of error.
|
||||
pub fn generate(component: &Rc<Component>, diag: &mut FileDiagnostics) -> Option<TokenStream> {
|
||||
pub fn generate(component: &Rc<Component>, diag: &mut BuildDiagnostics) -> Option<TokenStream> {
|
||||
let mut extra_components = vec![];
|
||||
let mut declared_property_vars = vec![];
|
||||
let mut declared_property_types = vec![];
|
||||
|
@ -66,7 +66,7 @@ pub fn generate(component: &Rc<Component>, diag: &mut FileDiagnostics) -> Option
|
|||
let rust_property_type =
|
||||
rust_type(&property_decl.property_type, &property_decl.type_location)
|
||||
.unwrap_or_else(|err| {
|
||||
diag.push_compiler_error(err);
|
||||
diag.push_internal_error(err.into());
|
||||
quote!().into()
|
||||
});
|
||||
declared_property_types.push(rust_property_type.clone());
|
||||
|
@ -141,7 +141,7 @@ pub fn generate(component: &Rc<Component>, diag: &mut FileDiagnostics) -> Option
|
|||
&item.node.as_ref().map_or_else(Default::default, |n| n.span()),
|
||||
)
|
||||
.unwrap_or_else(|err| {
|
||||
diag.push_compiler_error(err);
|
||||
diag.push_internal_error(err.into());
|
||||
quote!().into()
|
||||
});
|
||||
|
||||
|
@ -291,7 +291,7 @@ pub fn generate(component: &Rc<Component>, diag: &mut FileDiagnostics) -> Option
|
|||
.map_or_else(Default::default, |n| n.span()),
|
||||
)
|
||||
.unwrap_or_else(|err| {
|
||||
diag.push_compiler_error(err);
|
||||
diag.push_internal_error(err.into());
|
||||
quote!().into()
|
||||
}),
|
||||
);
|
||||
|
|
|
@ -53,14 +53,17 @@ pub fn compile_syntax_node<DocNode: Into<parser::syntax_nodes::Document>>(
|
|||
doc_node: DocNode,
|
||||
mut diagnostics: diagnostics::FileDiagnostics,
|
||||
compiler_config: &CompilerConfiguration,
|
||||
) -> (object_tree::Document, diagnostics::FileDiagnostics) {
|
||||
) -> (object_tree::Document, diagnostics::BuildDiagnostics) {
|
||||
let type_registry = typeregister::TypeRegister::builtin();
|
||||
let doc =
|
||||
crate::object_tree::Document::from_node(doc_node.into(), &mut diagnostics, &type_registry);
|
||||
|
||||
run_passes(&doc, &mut diagnostics, compiler_config);
|
||||
|
||||
(doc, diagnostics)
|
||||
let mut all_diagnostics = diagnostics::BuildDiagnostics::default();
|
||||
all_diagnostics.add(diagnostics);
|
||||
|
||||
(doc, all_diagnostics)
|
||||
}
|
||||
|
||||
pub fn run_passes(
|
||||
|
|
|
@ -222,7 +222,7 @@ fn rtti_for<T: 'static + Default + rtti::BuiltinItem + vtable::HasStaticVTable<I
|
|||
pub fn load(
|
||||
source: String,
|
||||
path: &std::path::Path,
|
||||
) -> Result<Rc<ComponentDescription>, sixtyfps_compilerlib::diagnostics::FileDiagnostics> {
|
||||
) -> Result<Rc<ComponentDescription>, sixtyfps_compilerlib::diagnostics::BuildDiagnostics> {
|
||||
let (syntax_node, diag) = parser::parse(source, Some(path));
|
||||
let compiler_config = CompilerConfiguration::default();
|
||||
let (tree, diag) = compile_syntax_node(syntax_node, diag, &compiler_config);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue