diff --git a/rust/extractor/src/main.rs b/rust/extractor/src/main.rs index f258f240935d..adcb6f681ae1 100644 --- a/rust/extractor/src/main.rs +++ b/rust/extractor/src/main.rs @@ -7,7 +7,7 @@ use anyhow::Context; use archive::Archiver; use ra_ap_ide_db::line_index::{LineCol, LineIndex}; use ra_ap_project_model::ProjectManifest; -use rust_analyzer::RustAnalyzer; +use rust_analyzer::{ParseResult, RustAnalyzer}; mod archive; mod config; pub mod generated; @@ -23,8 +23,14 @@ fn extract( ) { archiver.archive(file); - let (ast, input, parse_errors, file_id, semi) = rust_analyzer.parse(file); - let line_index = LineIndex::new(input.as_ref()); + let ParseResult { + ast, + text, + errors, + file_id, + semantics, + } = rust_analyzer.parse(file); + let line_index = LineIndex::new(text.as_ref()); let display_path = file.to_string_lossy(); let mut trap = traps.create("source", file); let label = trap.emit_file(file); @@ -34,14 +40,14 @@ fn extract( label, line_index, file_id, - semi, + semantics, ); - for err in parse_errors { + for err in errors { translator.emit_parse_error(&ast, &err); } let no_location = (LineCol { line: 0, col: 0 }, LineCol { line: 0, col: 0 }); - if translator.semi.is_none() { + if translator.semantics.is_none() { translator.emit_diagnostic( trap::DiagnosticSeverity::Warning, "semantics".to_owned(), diff --git a/rust/extractor/src/rust_analyzer.rs b/rust/extractor/src/rust_analyzer.rs index 648b58e2169d..80c34658a647 100644 --- a/rust/extractor/src/rust_analyzer.rs +++ b/rust/extractor/src/rust_analyzer.rs @@ -25,7 +25,13 @@ pub enum RustAnalyzer { WithDatabase { db: RootDatabase, vfs: Vfs }, WithoutDatabase(), } - +pub struct ParseResult<'a> { + pub ast: SourceFile, + pub text: Arc, + pub errors: Vec, + pub file_id: Option, + pub semantics: Option>, +} impl RustAnalyzer { pub fn new(project: &ProjectManifest, scratch_dir: &Path) -> Self { let config = CargoConfig { @@ -51,16 +57,7 @@ impl RustAnalyzer { } } } - pub fn parse( - &mut self, - path: &Path, - ) -> ( - SourceFile, - Arc, - Vec, - Option, - Option>, - ) { + pub fn parse(&mut self, path: &Path) -> ParseResult<'_> { let mut errors = Vec::new(); let input = match std::fs::read(path) { Ok(data) => data, @@ -82,28 +79,34 @@ impl RustAnalyzer { .and_then(|x| vfs.file_id(&x)) { db.set_file_text(file_id, &input); - let semi = Semantics::new(db); + let semantics = Semantics::new(db); let file_id = EditionedFileId::current_edition(file_id); - let source_file = semi.parse(file_id); + let source_file = semantics.parse(file_id); errors.extend( db.parse_errors(file_id) .into_iter() .flat_map(|x| x.to_vec()), ); - return ( - source_file, - input.as_ref().into(), + return ParseResult { + ast: source_file, + text: input.as_ref().into(), errors, - Some(file_id), - Some(semi), - ); + file_id: Some(file_id), + semantics: Some(semantics), + }; } } let parse = ra_ap_syntax::ast::SourceFile::parse(&input, Edition::CURRENT); errors.extend(parse.errors()); errors.extend(err); - (parse.tree(), input.as_ref().into(), errors, None, None) + ParseResult { + ast: parse.tree(), + text: input.as_ref().into(), + errors, + file_id: None, + semantics: None, + } } } diff --git a/rust/extractor/src/translate/base.rs b/rust/extractor/src/translate/base.rs index d6467b9dc700..721e2f1a537e 100644 --- a/rust/extractor/src/translate/base.rs +++ b/rust/extractor/src/translate/base.rs @@ -6,13 +6,15 @@ use codeql_extractor::trap::{self}; use log::Level; use ra_ap_hir::db::ExpandDatabase; use ra_ap_hir::Semantics; +use ra_ap_hir_expand::ExpandTo; use ra_ap_ide_db::line_index::{LineCol, LineIndex}; use ra_ap_ide_db::RootDatabase; use ra_ap_parser::SyntaxKind; use ra_ap_span::{EditionedFileId, TextSize}; use ra_ap_syntax::ast::RangeItem; use ra_ap_syntax::{ - ast, AstNode, NodeOrToken, SyntaxElementChildren, SyntaxError, SyntaxToken, TextRange, + ast, AstNode, NodeOrToken, SyntaxElementChildren, SyntaxError, SyntaxNode, SyntaxToken, + TextRange, }; #[macro_export] @@ -80,7 +82,7 @@ pub struct Translator<'a> { label: trap::Label, line_index: LineIndex, file_id: Option, - pub semi: Option>, + pub semantics: Option>, } impl<'a> Translator<'a> { @@ -90,7 +92,7 @@ impl<'a> Translator<'a> { label: trap::Label, line_index: LineIndex, file_id: Option, - semi: Option>, + semantics: Option>, ) -> Translator<'a> { Translator { trap, @@ -98,7 +100,7 @@ impl<'a> Translator<'a> { label, line_index, file_id, - semi, + semantics, } } fn location(&self, range: TextRange) -> (LineCol, LineCol) { @@ -122,8 +124,8 @@ impl<'a> Translator<'a> { } pub fn text_range_for_node(&mut self, node: &impl ast::AstNode) -> Option { - if let Some(semi) = self.semi.as_ref() { - let file_range = semi.original_range(node.syntax()); + if let Some(semantics) = self.semantics.as_ref() { + let file_range = semantics.original_range(node.syntax()); let file_id = self.file_id?; if file_id == file_range.file_id { Some(file_range.range) @@ -235,64 +237,75 @@ impl<'a> Translator<'a> { } } } + fn emit_macro_expansion_parse_errors(&mut self, mcall: &ast::MacroCall, expanded: &SyntaxNode) { + let semantics = self.semantics.as_ref().unwrap(); + if let Some(value) = semantics + .hir_file_for(expanded) + .macro_file() + .and_then(|macro_file| { + semantics + .db + .parse_macro_expansion_error(macro_file.macro_call_id) + }) + { + if let Some(err) = &value.err { + let (message, _error) = err.render_to_string(semantics.db); + + if err.span().anchor.file_id == semantics.hir_file_for(mcall.syntax()) { + let location = err.span().range + + semantics + .db + .ast_id_map(err.span().anchor.file_id.into()) + .get_erased(err.span().anchor.ast_id) + .text_range() + .start(); + self.emit_parse_error(mcall, &SyntaxError::new(message, location)); + }; + } + for err in value.value.iter() { + self.emit_parse_error(mcall, err); + } + } + } + + fn emit_expanded_as( + &mut self, + expand_to: ExpandTo, + expanded: SyntaxNode, + ) -> Option> { + match expand_to { + ra_ap_hir_expand::ExpandTo::Statements => { + ast::MacroStmts::cast(expanded).map(|x| self.emit_macro_stmts(x).into()) + } + ra_ap_hir_expand::ExpandTo::Items => { + ast::MacroItems::cast(expanded).map(|x| self.emit_macro_items(x).into()) + } + + ra_ap_hir_expand::ExpandTo::Pattern => { + ast::Pat::cast(expanded).map(|x| self.emit_pat(x).into()) + } + ra_ap_hir_expand::ExpandTo::Type => { + ast::Type::cast(expanded).map(|x| self.emit_type(x).into()) + } + ra_ap_hir_expand::ExpandTo::Expr => { + ast::Expr::cast(expanded).map(|x| self.emit_expr(x).into()) + } + } + } pub(crate) fn extract_macro_call_expanded( &mut self, mcall: &ast::MacroCall, label: Label, ) { - if let Some(semi) = &self.semi { - if let Some(expanded) = semi.expand(mcall) { - if let Some(value) = - semi.hir_file_for(&expanded) - .macro_file() - .and_then(|macro_file| { - semi.db - .parse_macro_expansion_error(macro_file.macro_call_id) - }) - { - if let Some(err) = &value.err { - let (message, _error) = err.render_to_string(semi.db); - - if err.span().anchor.file_id == semi.hir_file_for(mcall.syntax()) { - let location = err.span().range - + semi - .db - .ast_id_map(err.span().anchor.file_id.into()) - .get_erased(err.span().anchor.ast_id) - .text_range() - .start(); - self.emit_parse_error(mcall, &SyntaxError::new(message, location)); - }; - } - for err in value.value.iter() { - self.emit_parse_error(mcall, err); - } - } - let expand_to = ra_ap_hir_expand::ExpandTo::from_call_site(mcall); - let kind = expanded.kind(); - let value: Option> = match expand_to { - ra_ap_hir_expand::ExpandTo::Statements => { - ast::MacroStmts::cast(expanded).map(|x| self.emit_macro_stmts(x).into()) - } - ra_ap_hir_expand::ExpandTo::Items => { - ast::MacroItems::cast(expanded).map(|x| self.emit_macro_items(x).into()) - } - - ra_ap_hir_expand::ExpandTo::Pattern => { - ast::Pat::cast(expanded).map(|x| self.emit_pat(x).into()) - } - ra_ap_hir_expand::ExpandTo::Type => { - ast::Type::cast(expanded).map(|x| self.emit_type(x).into()) - } - ra_ap_hir_expand::ExpandTo::Expr => { - ast::Expr::cast(expanded).map(|x| self.emit_expr(x).into()) - } - }; - if let Some(value) = value { - MacroCall::emit_expanded(label, value, &mut self.trap.writer); - } else { - let range = self.text_range_for_node(mcall); - self.emit_parse_error(mcall, &SyntaxError::new( + if let Some(expanded) = self.semantics.as_ref().and_then(|s| s.expand(mcall)) { + self.emit_macro_expansion_parse_errors(mcall, &expanded); + let expand_to = ra_ap_hir_expand::ExpandTo::from_call_site(mcall); + let kind = expanded.kind(); + if let Some(value) = self.emit_expanded_as(expand_to, expanded) { + MacroCall::emit_expanded(label, value, &mut self.trap.writer); + } else { + let range = self.text_range_for_node(mcall); + self.emit_parse_error(mcall, &SyntaxError::new( format!( "macro expansion failed: the macro '{}' expands to {:?} but a {:?} was expected", mcall.path().map(|p| p.to_string()).unwrap_or_default(), @@ -300,21 +313,19 @@ impl<'a> Translator<'a> { ), range.unwrap_or_else(|| TextRange::empty(TextSize::from(0))), )); - } - } else { - let range = self.text_range_for_node(mcall); - - self.emit_parse_error( - mcall, - &SyntaxError::new( - format!( - "macro expansion failed: could not resolve macro '{}'", - mcall.path().map(|p| p.to_string()).unwrap_or_default() - ), - range.unwrap_or_else(|| TextRange::empty(TextSize::from(0))), - ), - ); } + } else { + let range = self.text_range_for_node(mcall); + self.emit_parse_error( + mcall, + &SyntaxError::new( + format!( + "macro expansion failed: could not resolve macro '{}'", + mcall.path().map(|p| p.to_string()).unwrap_or_default() + ), + range.unwrap_or_else(|| TextRange::empty(TextSize::from(0))), + ), + ); } } }