From bfc263f1f98aece963a4b103d787005346f0c1c7 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 28 Dec 2021 18:57:13 +0300 Subject: [PATCH] introduce hacks module --- .../src/completions/attribute.rs | 2 +- crates/ide_completion/src/snippet.rs | 13 +++++------ crates/ide_db/src/helpers.rs | 13 +++++++++-- crates/syntax/src/hacks.rs | 14 ++++++++++++ crates/syntax/src/lib.rs | 21 +----------------- crates/syntax/src/parsing.rs | 22 +------------------ 6 files changed, 34 insertions(+), 51 deletions(-) create mode 100644 crates/syntax/src/hacks.rs diff --git a/crates/ide_completion/src/completions/attribute.rs b/crates/ide_completion/src/completions/attribute.rs index d763878834..f67d7d56d8 100644 --- a/crates/ide_completion/src/completions/attribute.rs +++ b/crates/ide_completion/src/completions/attribute.rs @@ -309,7 +309,7 @@ fn parse_comma_sep_expr(input: ast::TokenTree) -> Option> { input_expressions .into_iter() .filter_map(|(is_sep, group)| (!is_sep).then(|| group)) - .filter_map(|mut tokens| ast::Expr::parse(&tokens.join("")).ok()) + .filter_map(|mut tokens| syntax::hacks::parse_expr_from_str(&tokens.join(""))) .collect::>(), ) } diff --git a/crates/ide_completion/src/snippet.rs b/crates/ide_completion/src/snippet.rs index c5e2b009c7..98cd3f8f33 100644 --- a/crates/ide_completion/src/snippet.rs +++ b/crates/ide_completion/src/snippet.rs @@ -212,15 +212,14 @@ fn validate_snippet( ) -> Option<(Box<[GreenNode]>, String, Option>)> { let mut imports = Vec::with_capacity(requires.len()); for path in requires.iter() { - let path = ast::Path::parse(path).ok()?; - let valid_use_path = path.segments().all(|seg| { - matches!(seg.kind(), Some(ast::PathSegmentKind::Name(_))) - || seg.generic_arg_list().is_none() - }); - if !valid_use_path { + let use_path = ast::SourceFile::parse(&format!("use {};", path)) + .syntax_node() + .descendants() + .find_map(ast::Path::cast)?; + if use_path.syntax().text() != path.as_str() { return None; } - let green = path.syntax().green().into_owned(); + let green = use_path.syntax().green().into_owned(); imports.push(green); } let snippet = snippet.iter().join("\n"); diff --git a/crates/ide_db/src/helpers.rs b/crates/ide_db/src/helpers.rs index e4199898bf..e589940dae 100644 --- a/crates/ide_db/src/helpers.rs +++ b/crates/ide_db/src/helpers.rs @@ -67,7 +67,11 @@ pub fn get_path_at_cursor_in_tt(cursor: &ast::Ident) -> Option { .filter_map(SyntaxElement::into_token) .take_while(|tok| tok != cursor); - ast::Path::parse(&path_tokens.chain(iter::once(cursor.clone())).join("")).ok() + syntax::hacks::parse_expr_from_str(&path_tokens.chain(iter::once(cursor.clone())).join("")) + .and_then(|expr| match expr { + ast::Expr::PathExpr(it) => it.path(), + _ => None, + }) } /// Parses and resolves the path at the cursor position in the given attribute, if it is a derive. @@ -323,7 +327,12 @@ pub fn parse_tt_as_comma_sep_paths(input: ast::TokenTree) -> Option it.path(), + _ => None, + }) + }) .collect(); Some(paths) } diff --git a/crates/syntax/src/hacks.rs b/crates/syntax/src/hacks.rs new file mode 100644 index 0000000000..112b912ade --- /dev/null +++ b/crates/syntax/src/hacks.rs @@ -0,0 +1,14 @@ +//! Things which exist to solve practial issues, but which shouldn't exist. +//! +//! Please avoid adding new usages of the functions in this module + +use crate::{ast, AstNode}; + +pub fn parse_expr_from_str(s: &str) -> Option { + let file = ast::SourceFile::parse(&format!("const _: () = {};", s)); + let expr = file.syntax_node().descendants().find_map(ast::Expr::cast)?; + if expr.syntax().text() != s { + return None; + } + Some(expr) +} diff --git a/crates/syntax/src/lib.rs b/crates/syntax/src/lib.rs index 1fb3dc6a65..d6b1cce45f 100644 --- a/crates/syntax/src/lib.rs +++ b/crates/syntax/src/lib.rs @@ -40,6 +40,7 @@ pub mod ast; pub mod fuzz; pub mod utils; pub mod ted; +pub mod hacks; use std::{marker::PhantomData, sync::Arc}; @@ -167,26 +168,6 @@ impl SourceFile { } } -// FIXME: `parse` functions shouldn't hang directly from AST nodes, and they -// shouldn't return `Result`. -// -// We need a dedicated module for parser entry points, and they should always -// return `Parse`. - -impl ast::Path { - /// Returns `text`, parsed as a path, but only if it has no errors. - pub fn parse(text: &str) -> Result { - parsing::parse_text_as(text, parser::ParserEntryPoint::Path) - } -} - -impl ast::Expr { - /// Returns `text`, parsed as an expression, but only if it has no errors. - pub fn parse(text: &str) -> Result { - parsing::parse_text_as(text, parser::ParserEntryPoint::Expr) - } -} - /// Matches a `SyntaxNode` against an `ast` type. /// /// # Example: diff --git a/crates/syntax/src/parsing.rs b/crates/syntax/src/parsing.rs index 971fa2700d..ac1d920d69 100644 --- a/crates/syntax/src/parsing.rs +++ b/crates/syntax/src/parsing.rs @@ -5,7 +5,7 @@ mod reparsing; use rowan::TextRange; -use crate::{syntax_node::GreenNode, AstNode, SyntaxError, SyntaxNode, SyntaxTreeBuilder}; +use crate::{syntax_node::GreenNode, SyntaxError, SyntaxTreeBuilder}; pub(crate) use crate::parsing::reparsing::incremental_reparse; @@ -17,26 +17,6 @@ pub(crate) fn parse_text(text: &str) -> (GreenNode, Vec) { (node, errors) } -/// Returns `text` parsed as a `T` provided there are no parse errors. -pub(crate) fn parse_text_as( - text: &str, - entry_point: parser::ParserEntryPoint, -) -> Result { - let lexed = parser::LexedStr::new(text); - if lexed.errors().next().is_some() { - return Err(()); - } - let parser_input = lexed.to_input(); - let parser_output = parser::parse(&parser_input, entry_point); - let (node, errors, eof) = build_tree(lexed, parser_output, true); - - if !errors.is_empty() || !eof { - return Err(()); - } - - SyntaxNode::new_root(node).first_child().and_then(T::cast).ok_or(()) -} - pub(crate) fn build_tree( lexed: parser::LexedStr<'_>, parser_output: parser::Output,