diff --git a/api/sixtyfps-rs/sixtyfps-macros/lib.rs b/api/sixtyfps-rs/sixtyfps-macros/lib.rs index 2ca3c28bd..2a6cb92f9 100644 --- a/api/sixtyfps-rs/sixtyfps-macros/lib.rs +++ b/api/sixtyfps-rs/sixtyfps-macros/lib.rs @@ -328,8 +328,7 @@ pub fn sixtyfps(stream: TokenStream) -> TokenStream { let source_file = if let Some(cargo_manifest) = std::env::var_os("CARGO_MANIFEST_DIR") { let mut path: std::path::PathBuf = cargo_manifest.into(); path.push("Cargo.toml"); - diag.current_path = std::rc::Rc::new(path); - Some(diag.current_path.clone()) + Some(diagnostics::SourceFileInner::from_path(path)) } else { None }; @@ -371,7 +370,7 @@ fn report_diagnostics( let mut result = TokenStream::new(); let mut needs_error = diag.has_error(); for mut file_diag in diag.into_iter() { - if file_diag.source.is_none() { + if file_diag.current_path.path() == std::path::PathBuf::default() { file_diag.map_offsets_to_span(span_map); needs_error &= !file_diag.has_error(); result.extend(TokenStream::from(file_diag.into_token_stream())) diff --git a/sixtyfps_compiler/diagnostics.rs b/sixtyfps_compiler/diagnostics.rs index 6dcf985ef..0cef40503 100644 --- a/sixtyfps_compiler/diagnostics.rs +++ b/sixtyfps_compiler/diagnostics.rs @@ -8,7 +8,7 @@ Please contact info@sixtyfps.io for more information. LICENSE END */ use std::collections::HashMap; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use std::rc::Rc; #[derive(Debug, Clone)] @@ -65,7 +65,32 @@ pub trait Spanned { } } -pub type SourceFile = Rc; +#[derive(Debug, Default)] +pub struct SourceFileInner { + path: PathBuf, + + /// Complete source code of the path, used to map from offset to line number + source: Option, + + /// The offset of each linebreak + line_offsets: once_cell::unsync::OnceCell>, +} + +impl SourceFileInner { + pub fn new(path: PathBuf, source: String) -> Self { + Self { path, source: Some(source), line_offsets: Default::default() } + } + + pub fn path(&self) -> &Path { + &self.path + } + + pub fn from_path(path: PathBuf) -> Rc { + Rc::new(Self { path, ..Default::default() }) + } +} + +pub type SourceFile = Rc; #[derive(Debug, Clone)] pub struct SourceLocation { @@ -179,11 +204,6 @@ pub struct FileDiagnostics { pub inner: Vec, /// file path pub current_path: SourceFile, - /// Complete source code of the path, used to map from offset to line number - pub source: Option, - - /// The offset of each linebreak - pub line_offsets: once_cell::unsync::OnceCell>, } impl IntoIterator for FileDiagnostics { @@ -251,10 +271,10 @@ impl FileDiagnostics { } let mut codemap = codemap::CodeMap::new(); - let internal_errors = self.source.is_none(); + let internal_errors = self.current_path.source.is_none(); let file = codemap.add_file( - self.current_path.to_string_lossy().to_string(), - self.source.unwrap_or_default(), + self.current_path.path.to_string_lossy().to_string(), + self.current_path.source.clone().unwrap_or_default(), ); let file_span = file.span; @@ -342,17 +362,13 @@ impl FileDiagnostics { } pub fn new_from_error(path: std::path::PathBuf, err: std::io::Error) -> Self { - Self { - inner: vec![err.into()], - current_path: Rc::new(path), - source: None, - line_offsets: Default::default(), - } + Self { inner: vec![err.into()], current_path: SourceFileInner::from_path(path) } } fn line_offsets(&self) -> &[usize] { - self.line_offsets.get_or_init(|| { - self.source + self.current_path.line_offsets.get_or_init(|| { + self.current_path + .source .as_ref() .map(|s| { s.bytes() @@ -403,34 +419,33 @@ impl quote::ToTokens for FileDiagnostics { #[derive(Default)] pub struct BuildDiagnostics { - per_input_file_diagnostics: HashMap, + per_input_file_diagnostics: HashMap, internal_errors: Option, } impl BuildDiagnostics { pub fn add(&mut self, diagnostics: FileDiagnostics) { - match self.per_input_file_diagnostics.get_mut(&diagnostics.current_path) { + match self.per_input_file_diagnostics.get_mut(&diagnostics.current_path.path) { Some(existing_diags) => existing_diags.inner.extend(diagnostics.inner), None => { self.per_input_file_diagnostics - .insert(diagnostics.current_path.clone(), diagnostics); + .insert(diagnostics.current_path.path.clone(), diagnostics); } } } - fn file_diagnostics(&mut self, source_file: &Rc) -> &mut FileDiagnostics { - self.per_input_file_diagnostics.entry(source_file.clone()).or_insert_with(|| { - FileDiagnostics { current_path: source_file.clone(), ..Default::default() } + fn file_diagnostics(&mut self, path: &Path) -> &mut FileDiagnostics { + self.per_input_file_diagnostics.entry(path.into()).or_insert_with(|| FileDiagnostics { + current_path: Rc::new(SourceFileInner { path: path.into(), ..Default::default() }), + ..Default::default() }) } pub fn push_diagnostic(&mut self, message: String, source: &dyn Spanned, level: Level) { match source.source_file() { - Some(source_file) => self.file_diagnostics(source_file).push_diagnostic_with_span( - message, - source.span(), - level, - ), + Some(source_file) => self + .file_diagnostics(source_file.path()) + .push_diagnostic_with_span(message, source.span(), level), None => self.push_internal_error( CompilerDiagnostic { message, span: source.span(), level }.into(), ), @@ -444,7 +459,10 @@ impl BuildDiagnostics { pub fn push_internal_error(&mut self, err: Diagnostic) { self.internal_errors .get_or_insert_with(|| FileDiagnostics { - current_path: Rc::new("[internal error]".into()), + current_path: Rc::new(SourceFileInner { + path: "[internal error]".into(), + ..Default::default() + }), ..Default::default() }) .inner @@ -458,7 +476,7 @@ impl BuildDiagnostics { source: &impl Spanned, ) { self.file_diagnostics( - source.source_file().expect("deprecations cannot be created as internal errors"), + source.source_file().expect("deprecations cannot be created as internal errors").path(), ) .push_property_deprecation_warning(old_property, new_property, source); } @@ -488,7 +506,7 @@ impl BuildDiagnostics { .flat_map(|diag| { diag.to_string_vec() .iter() - .map(|err| format!("{}: {}", diag.current_path.to_string_lossy(), err)) + .map(|err| format!("{}: {}", diag.current_path.path().to_string_lossy(), err)) .collect::>() }) .collect() diff --git a/sixtyfps_compiler/object_tree.rs b/sixtyfps_compiler/object_tree.rs index a1dcdd654..f53e6332c 100644 --- a/sixtyfps_compiler/object_tree.rs +++ b/sixtyfps_compiler/object_tree.rs @@ -297,7 +297,7 @@ impl Spanned for Element { self.node.as_ref().map(|n| n.span()).unwrap_or_default() } - fn source_file(&self) -> Option<&Rc> { + fn source_file(&self) -> Option<&crate::diagnostics::SourceFile> { self.node.as_ref().map(|n| n.0.source_file.as_ref()).flatten() } } diff --git a/sixtyfps_compiler/parser.rs b/sixtyfps_compiler/parser.rs index dacd9a8b9..56b4c2d13 100644 --- a/sixtyfps_compiler/parser.rs +++ b/sixtyfps_compiler/parser.rs @@ -521,10 +521,8 @@ impl From> for DefaultParser { impl DefaultParser { /// Constructor that create a parser from the source code - pub fn new(source: String) -> Self { - let mut parser = Self::from(crate::lexer::lex(&source)); - parser.diags.source = Some(source); - parser + pub fn new(source: &str) -> Self { + Self::from(crate::lexer::lex(&source)) } fn current_token(&self) -> Token { @@ -811,10 +809,11 @@ pub fn parse( source: String, path: Option<&std::path::Path>, ) -> (SyntaxNodeWithSourceFile, FileDiagnostics) { - let mut p = DefaultParser::new(source); + let mut p = DefaultParser::new(&source); document::parse_document(&mut p); let source_file = if let Some(path) = path { - p.diags.current_path = std::rc::Rc::new(path.to_path_buf()); + p.diags.current_path = + std::rc::Rc::new(crate::diagnostics::SourceFileInner::new(path.to_path_buf(), source)); Some(p.diags.current_path.clone()) } else { None diff --git a/sixtyfps_compiler/passes/resolving.rs b/sixtyfps_compiler/passes/resolving.rs index 676e2d031..4c649e6c7 100644 --- a/sixtyfps_compiler/passes/resolving.rs +++ b/sixtyfps_compiler/passes/resolving.rs @@ -411,10 +411,7 @@ impl Expression { ctx.type_loader .and_then(|loader| { loader - .import_file( - node.source_file.as_ref().map(|path_rc| path_rc.as_path()), - &s, - ) + .import_file(node.source_file.as_ref().map(|sf| sf.path()), &s) .map(|resolved_file| resolved_file.path) }) .unwrap_or_else(|| { diff --git a/sixtyfps_compiler/tests/syntax_tests.rs b/sixtyfps_compiler/tests/syntax_tests.rs index 06a058c66..cb612a5e8 100644 --- a/sixtyfps_compiler/tests/syntax_tests.rs +++ b/sixtyfps_compiler/tests/syntax_tests.rs @@ -158,10 +158,10 @@ fn process_file_source( let mut success = true; for diagnostics in compile_diagnostics.into_iter() { - let source = if *diagnostics.current_path == path { + let source = if diagnostics.current_path.path() == path { source.clone() } else { - std::fs::read_to_string(diagnostics.current_path.as_ref())? + std::fs::read_to_string(diagnostics.current_path.path())? }; success &= process_diagnostics(diagnostics, source, silent)?; } diff --git a/sixtyfps_compiler/typeloader.rs b/sixtyfps_compiler/typeloader.rs index 8a3a1fb64..dcdb5f2f1 100644 --- a/sixtyfps_compiler/typeloader.rs +++ b/sixtyfps_compiler/typeloader.rs @@ -14,7 +14,7 @@ use std::io::Read; use std::path::{Path, PathBuf}; use std::rc::Rc; -use crate::diagnostics::{BuildDiagnostics, CompilerDiagnostic, FileDiagnostics, SourceFile}; +use crate::diagnostics::{BuildDiagnostics, CompilerDiagnostic, FileDiagnostics}; use crate::object_tree::{self, Document}; use crate::parser::{syntax_nodes, SyntaxKind, SyntaxTokenWithSourceFile}; use crate::typeregister::TypeRegister; @@ -234,13 +234,7 @@ impl<'a> TypeLoader<'a> { } }; - self.load_file( - &path_canon, - SourceFile::new(path.to_owned()), - source_code, - build_diagnostics, - ) - .await; + self.load_file(&path_canon, path, source_code, build_diagnostics).await; let _ok = self.all_documents.currently_loading.remove(path_canon.as_path()); assert!(_ok); Some(path_canon) @@ -252,15 +246,13 @@ impl<'a> TypeLoader<'a> { pub async fn load_file( &mut self, path: &Path, - source_path: SourceFile, + source_path: &Path, source_code: String, build_diagnostics: &mut BuildDiagnostics, ) { let (dependency_doc, mut dependency_diagnostics) = crate::parser::parse(source_code, Some(&source_path)); - dependency_diagnostics.current_path = source_path; - if dependency_diagnostics.has_error() { build_diagnostics.add(dependency_diagnostics); let mut d = Document::default(); @@ -401,7 +393,7 @@ impl<'a> TypeLoader<'a> { doc: &syntax_nodes::Document, doc_diagnostics: &mut FileDiagnostics, ) -> impl Iterator { - let referencing_file = doc.source_file.as_ref().unwrap().clone(); + let referencing_file = doc.source_file.as_ref().unwrap().path().clone(); let mut dependencies = DependenciesByFile::new(); diff --git a/tools/lsp/main.rs b/tools/lsp/main.rs index fbefb7189..abb55c8b1 100644 --- a/tools/lsp/main.rs +++ b/tools/lsp/main.rs @@ -194,22 +194,17 @@ fn reload_document( let path = Path::new(uri.path()); let path_canon = path.canonicalize().unwrap_or_else(|_| path.to_owned()); let mut diag = BuildDiagnostics::default(); - spin_on::spin_on(document_cache.documents.load_file( - &path_canon, - sixtyfps_compilerlib::diagnostics::SourceFile::new(path.to_owned()), - content, - &mut diag, - )); + spin_on::spin_on(document_cache.documents.load_file(&path_canon, path, content, &mut diag)); for file_diag in diag.into_iter() { - if file_diag.current_path.is_relative() { + if file_diag.current_path.path().is_relative() { continue; } let diagnostics = file_diag.inner.iter().map(|d| to_lsp_diag(d, &file_diag)).collect(); connection.sender.send(Message::Notification(lsp_server::Notification::new( "textDocument/publishDiagnostics".into(), PublishDiagnosticsParams { - uri: Url::from_file_path(file_diag.current_path.as_path()).unwrap(), + uri: Url::from_file_path(file_diag.current_path.path()).unwrap(), diagnostics, version: None, }, @@ -272,7 +267,7 @@ fn goto_definition( sixtyfps_compilerlib::object_tree::QualifiedTypeName::from_node(token.into()); match parent.kind() { SyntaxKind::Element => { - let doc = document_cache.documents.get_document(source_file.as_path())?; + let doc = document_cache.documents.get_document(source_file.path())?; match doc.local_registry.lookup_qualified(&qual.members) { sixtyfps_compilerlib::langtype::Type::Component(c) => { goto_node(document_cache, &c.root_element.borrow().node.as_ref()?.0) @@ -291,7 +286,7 @@ fn goto_node( document_cache: &mut DocumentCache, node: &SyntaxNodeWithSourceFile, ) -> Option { - let path = node.source_file.as_ref()?.as_path(); + let path = node.source_file.as_ref()?.path(); let target_uri = Url::from_file_path(path).ok()?; let newline_offsets = match document_cache.newline_offsets.entry(target_uri.clone()) { std::collections::hash_map::Entry::Occupied(e) => e.into_mut(),