Put what is the FileDiagnostics into the SourceFile so the SourceFile has the content

This commit is contained in:
Olivier Goffart 2021-03-11 16:23:46 +01:00
parent 7c48bcdd4c
commit 968dfaae87
8 changed files with 70 additions and 70 deletions

View file

@ -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 source_file = if let Some(cargo_manifest) = std::env::var_os("CARGO_MANIFEST_DIR") {
let mut path: std::path::PathBuf = cargo_manifest.into(); let mut path: std::path::PathBuf = cargo_manifest.into();
path.push("Cargo.toml"); path.push("Cargo.toml");
diag.current_path = std::rc::Rc::new(path); Some(diagnostics::SourceFileInner::from_path(path))
Some(diag.current_path.clone())
} else { } else {
None None
}; };
@ -371,7 +370,7 @@ fn report_diagnostics(
let mut result = TokenStream::new(); let mut result = TokenStream::new();
let mut needs_error = diag.has_error(); let mut needs_error = diag.has_error();
for mut file_diag in diag.into_iter() { 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); file_diag.map_offsets_to_span(span_map);
needs_error &= !file_diag.has_error(); needs_error &= !file_diag.has_error();
result.extend(TokenStream::from(file_diag.into_token_stream())) result.extend(TokenStream::from(file_diag.into_token_stream()))

View file

@ -8,7 +8,7 @@
Please contact info@sixtyfps.io for more information. Please contact info@sixtyfps.io for more information.
LICENSE END */ LICENSE END */
use std::collections::HashMap; use std::collections::HashMap;
use std::path::PathBuf; use std::path::{Path, PathBuf};
use std::rc::Rc; use std::rc::Rc;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -65,7 +65,32 @@ pub trait Spanned {
} }
} }
pub type SourceFile = Rc<PathBuf>; #[derive(Debug, Default)]
pub struct SourceFileInner {
path: PathBuf,
/// Complete source code of the path, used to map from offset to line number
source: Option<String>,
/// The offset of each linebreak
line_offsets: once_cell::unsync::OnceCell<Vec<usize>>,
}
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<Self> {
Rc::new(Self { path, ..Default::default() })
}
}
pub type SourceFile = Rc<SourceFileInner>;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct SourceLocation { pub struct SourceLocation {
@ -179,11 +204,6 @@ pub struct FileDiagnostics {
pub inner: Vec<Diagnostic>, pub inner: Vec<Diagnostic>,
/// file path /// file path
pub current_path: SourceFile, pub current_path: SourceFile,
/// Complete source code of the path, used to map from offset to line number
pub source: Option<String>,
/// The offset of each linebreak
pub line_offsets: once_cell::unsync::OnceCell<Vec<usize>>,
} }
impl IntoIterator for FileDiagnostics { impl IntoIterator for FileDiagnostics {
@ -251,10 +271,10 @@ impl FileDiagnostics {
} }
let mut codemap = codemap::CodeMap::new(); 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( let file = codemap.add_file(
self.current_path.to_string_lossy().to_string(), self.current_path.path.to_string_lossy().to_string(),
self.source.unwrap_or_default(), self.current_path.source.clone().unwrap_or_default(),
); );
let file_span = file.span; 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 { pub fn new_from_error(path: std::path::PathBuf, err: std::io::Error) -> Self {
Self { Self { inner: vec![err.into()], current_path: SourceFileInner::from_path(path) }
inner: vec![err.into()],
current_path: Rc::new(path),
source: None,
line_offsets: Default::default(),
}
} }
fn line_offsets(&self) -> &[usize] { fn line_offsets(&self) -> &[usize] {
self.line_offsets.get_or_init(|| { self.current_path.line_offsets.get_or_init(|| {
self.source self.current_path
.source
.as_ref() .as_ref()
.map(|s| { .map(|s| {
s.bytes() s.bytes()
@ -403,34 +419,33 @@ impl quote::ToTokens for FileDiagnostics {
#[derive(Default)] #[derive(Default)]
pub struct BuildDiagnostics { pub struct BuildDiagnostics {
per_input_file_diagnostics: HashMap<SourceFile, FileDiagnostics>, per_input_file_diagnostics: HashMap<PathBuf, FileDiagnostics>,
internal_errors: Option<FileDiagnostics>, internal_errors: Option<FileDiagnostics>,
} }
impl BuildDiagnostics { impl BuildDiagnostics {
pub fn add(&mut self, diagnostics: FileDiagnostics) { 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), Some(existing_diags) => existing_diags.inner.extend(diagnostics.inner),
None => { None => {
self.per_input_file_diagnostics 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<PathBuf>) -> &mut FileDiagnostics { fn file_diagnostics(&mut self, path: &Path) -> &mut FileDiagnostics {
self.per_input_file_diagnostics.entry(source_file.clone()).or_insert_with(|| { self.per_input_file_diagnostics.entry(path.into()).or_insert_with(|| FileDiagnostics {
FileDiagnostics { current_path: source_file.clone(), ..Default::default() } 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) { pub fn push_diagnostic(&mut self, message: String, source: &dyn Spanned, level: Level) {
match source.source_file() { match source.source_file() {
Some(source_file) => self.file_diagnostics(source_file).push_diagnostic_with_span( Some(source_file) => self
message, .file_diagnostics(source_file.path())
source.span(), .push_diagnostic_with_span(message, source.span(), level),
level,
),
None => self.push_internal_error( None => self.push_internal_error(
CompilerDiagnostic { message, span: source.span(), level }.into(), CompilerDiagnostic { message, span: source.span(), level }.into(),
), ),
@ -444,7 +459,10 @@ impl BuildDiagnostics {
pub fn push_internal_error(&mut self, err: Diagnostic) { pub fn push_internal_error(&mut self, err: Diagnostic) {
self.internal_errors self.internal_errors
.get_or_insert_with(|| FileDiagnostics { .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() ..Default::default()
}) })
.inner .inner
@ -458,7 +476,7 @@ impl BuildDiagnostics {
source: &impl Spanned, source: &impl Spanned,
) { ) {
self.file_diagnostics( 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); .push_property_deprecation_warning(old_property, new_property, source);
} }
@ -488,7 +506,7 @@ impl BuildDiagnostics {
.flat_map(|diag| { .flat_map(|diag| {
diag.to_string_vec() diag.to_string_vec()
.iter() .iter()
.map(|err| format!("{}: {}", diag.current_path.to_string_lossy(), err)) .map(|err| format!("{}: {}", diag.current_path.path().to_string_lossy(), err))
.collect::<Vec<_>>() .collect::<Vec<_>>()
}) })
.collect() .collect()

View file

@ -297,7 +297,7 @@ impl Spanned for Element {
self.node.as_ref().map(|n| n.span()).unwrap_or_default() self.node.as_ref().map(|n| n.span()).unwrap_or_default()
} }
fn source_file(&self) -> Option<&Rc<std::path::PathBuf>> { fn source_file(&self) -> Option<&crate::diagnostics::SourceFile> {
self.node.as_ref().map(|n| n.0.source_file.as_ref()).flatten() self.node.as_ref().map(|n| n.0.source_file.as_ref()).flatten()
} }
} }

View file

@ -521,10 +521,8 @@ impl From<Vec<Token>> for DefaultParser {
impl DefaultParser { impl DefaultParser {
/// Constructor that create a parser from the source code /// Constructor that create a parser from the source code
pub fn new(source: String) -> Self { pub fn new(source: &str) -> Self {
let mut parser = Self::from(crate::lexer::lex(&source)); Self::from(crate::lexer::lex(&source))
parser.diags.source = Some(source);
parser
} }
fn current_token(&self) -> Token { fn current_token(&self) -> Token {
@ -811,10 +809,11 @@ pub fn parse(
source: String, source: String,
path: Option<&std::path::Path>, path: Option<&std::path::Path>,
) -> (SyntaxNodeWithSourceFile, FileDiagnostics) { ) -> (SyntaxNodeWithSourceFile, FileDiagnostics) {
let mut p = DefaultParser::new(source); let mut p = DefaultParser::new(&source);
document::parse_document(&mut p); document::parse_document(&mut p);
let source_file = if let Some(path) = path { 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()) Some(p.diags.current_path.clone())
} else { } else {
None None

View file

@ -411,10 +411,7 @@ impl Expression {
ctx.type_loader ctx.type_loader
.and_then(|loader| { .and_then(|loader| {
loader loader
.import_file( .import_file(node.source_file.as_ref().map(|sf| sf.path()), &s)
node.source_file.as_ref().map(|path_rc| path_rc.as_path()),
&s,
)
.map(|resolved_file| resolved_file.path) .map(|resolved_file| resolved_file.path)
}) })
.unwrap_or_else(|| { .unwrap_or_else(|| {

View file

@ -158,10 +158,10 @@ fn process_file_source(
let mut success = true; let mut success = true;
for diagnostics in compile_diagnostics.into_iter() { for diagnostics in compile_diagnostics.into_iter() {
let source = if *diagnostics.current_path == path { let source = if diagnostics.current_path.path() == path {
source.clone() source.clone()
} else { } 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)?; success &= process_diagnostics(diagnostics, source, silent)?;
} }

View file

@ -14,7 +14,7 @@ use std::io::Read;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::rc::Rc; 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::object_tree::{self, Document};
use crate::parser::{syntax_nodes, SyntaxKind, SyntaxTokenWithSourceFile}; use crate::parser::{syntax_nodes, SyntaxKind, SyntaxTokenWithSourceFile};
use crate::typeregister::TypeRegister; use crate::typeregister::TypeRegister;
@ -234,13 +234,7 @@ impl<'a> TypeLoader<'a> {
} }
}; };
self.load_file( self.load_file(&path_canon, path, source_code, build_diagnostics).await;
&path_canon,
SourceFile::new(path.to_owned()),
source_code,
build_diagnostics,
)
.await;
let _ok = self.all_documents.currently_loading.remove(path_canon.as_path()); let _ok = self.all_documents.currently_loading.remove(path_canon.as_path());
assert!(_ok); assert!(_ok);
Some(path_canon) Some(path_canon)
@ -252,15 +246,13 @@ impl<'a> TypeLoader<'a> {
pub async fn load_file( pub async fn load_file(
&mut self, &mut self,
path: &Path, path: &Path,
source_path: SourceFile, source_path: &Path,
source_code: String, source_code: String,
build_diagnostics: &mut BuildDiagnostics, build_diagnostics: &mut BuildDiagnostics,
) { ) {
let (dependency_doc, mut dependency_diagnostics) = let (dependency_doc, mut dependency_diagnostics) =
crate::parser::parse(source_code, Some(&source_path)); crate::parser::parse(source_code, Some(&source_path));
dependency_diagnostics.current_path = source_path;
if dependency_diagnostics.has_error() { if dependency_diagnostics.has_error() {
build_diagnostics.add(dependency_diagnostics); build_diagnostics.add(dependency_diagnostics);
let mut d = Document::default(); let mut d = Document::default();
@ -401,7 +393,7 @@ impl<'a> TypeLoader<'a> {
doc: &syntax_nodes::Document, doc: &syntax_nodes::Document,
doc_diagnostics: &mut FileDiagnostics, doc_diagnostics: &mut FileDiagnostics,
) -> impl Iterator<Item = ImportedTypes> { ) -> impl Iterator<Item = ImportedTypes> {
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(); let mut dependencies = DependenciesByFile::new();

View file

@ -194,22 +194,17 @@ fn reload_document(
let path = Path::new(uri.path()); let path = Path::new(uri.path());
let path_canon = path.canonicalize().unwrap_or_else(|_| path.to_owned()); let path_canon = path.canonicalize().unwrap_or_else(|_| path.to_owned());
let mut diag = BuildDiagnostics::default(); let mut diag = BuildDiagnostics::default();
spin_on::spin_on(document_cache.documents.load_file( spin_on::spin_on(document_cache.documents.load_file(&path_canon, path, content, &mut diag));
&path_canon,
sixtyfps_compilerlib::diagnostics::SourceFile::new(path.to_owned()),
content,
&mut diag,
));
for file_diag in diag.into_iter() { for file_diag in diag.into_iter() {
if file_diag.current_path.is_relative() { if file_diag.current_path.path().is_relative() {
continue; continue;
} }
let diagnostics = file_diag.inner.iter().map(|d| to_lsp_diag(d, &file_diag)).collect(); let diagnostics = file_diag.inner.iter().map(|d| to_lsp_diag(d, &file_diag)).collect();
connection.sender.send(Message::Notification(lsp_server::Notification::new( connection.sender.send(Message::Notification(lsp_server::Notification::new(
"textDocument/publishDiagnostics".into(), "textDocument/publishDiagnostics".into(),
PublishDiagnosticsParams { 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, diagnostics,
version: None, version: None,
}, },
@ -272,7 +267,7 @@ fn goto_definition(
sixtyfps_compilerlib::object_tree::QualifiedTypeName::from_node(token.into()); sixtyfps_compilerlib::object_tree::QualifiedTypeName::from_node(token.into());
match parent.kind() { match parent.kind() {
SyntaxKind::Element => { 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) { match doc.local_registry.lookup_qualified(&qual.members) {
sixtyfps_compilerlib::langtype::Type::Component(c) => { sixtyfps_compilerlib::langtype::Type::Component(c) => {
goto_node(document_cache, &c.root_element.borrow().node.as_ref()?.0) goto_node(document_cache, &c.root_element.borrow().node.as_ref()?.0)
@ -291,7 +286,7 @@ fn goto_node(
document_cache: &mut DocumentCache, document_cache: &mut DocumentCache,
node: &SyntaxNodeWithSourceFile, node: &SyntaxNodeWithSourceFile,
) -> Option<GotoDefinitionResponse> { ) -> Option<GotoDefinitionResponse> {
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 target_uri = Url::from_file_path(path).ok()?;
let newline_offsets = match document_cache.newline_offsets.entry(target_uri.clone()) { let newline_offsets = match document_cache.newline_offsets.entry(target_uri.clone()) {
std::collections::hash_map::Entry::Occupied(e) => e.into_mut(), std::collections::hash_map::Entry::Occupied(e) => e.into_mut(),