From 4a4d9f7a90dc0605992c4f774a8d9a1323ad6d1e Mon Sep 17 00:00:00 2001 From: krk Date: Thu, 31 Oct 2019 21:10:58 +0100 Subject: [PATCH 01/21] Handle IfLet in convert_to_guarded_return. --- crates/ra_assists/src/assists/early_return.rs | 183 +++++++++++++++--- crates/ra_syntax/src/ast/make.rs | 16 ++ 2 files changed, 171 insertions(+), 28 deletions(-) diff --git a/crates/ra_assists/src/assists/early_return.rs b/crates/ra_assists/src/assists/early_return.rs index ad6c5695a3a4..827170f8f90a 100644 --- a/crates/ra_assists/src/assists/early_return.rs +++ b/crates/ra_assists/src/assists/early_return.rs @@ -37,7 +37,9 @@ use crate::{ // ``` pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Option { let if_expr: ast::IfExpr = ctx.find_node_at_offset()?; - let expr = if_expr.condition()?.expr()?; + let cond = if_expr.condition()?; + let pat = &cond.pat(); + let expr = cond.expr()?; let then_block = if_expr.then_branch()?.block()?; if if_expr.else_branch().is_some() { return None; @@ -63,8 +65,8 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Opt let parent_container = parent_block.syntax().parent()?.parent()?; let early_expression = match parent_container.kind() { - WHILE_EXPR | LOOP_EXPR => Some("continue;"), - FN_DEF => Some("return;"), + WHILE_EXPR | LOOP_EXPR => Some("continue"), + FN_DEF => Some("return"), _ => None, }?; @@ -77,31 +79,67 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Opt ctx.add_assist(AssistId("convert_to_guarded_return"), "convert to guarded return", |edit| { let if_indent_level = IndentLevel::from_node(&if_expr.syntax()); - let new_if_expr = - if_indent_level.increase_indent(make::if_expression(&expr, early_expression)); - let then_block_items = IndentLevel::from(1).decrease_indent(then_block.clone()); - let end_of_then = then_block_items.syntax().last_child_or_token().unwrap(); - let end_of_then = - if end_of_then.prev_sibling_or_token().map(|n| n.kind()) == Some(WHITESPACE) { - end_of_then.prev_sibling_or_token().unwrap() - } else { - end_of_then - }; - let mut new_if_and_then_statements = new_if_expr.syntax().children_with_tokens().chain( - then_block_items - .syntax() - .children_with_tokens() - .skip(1) - .take_while(|i| *i != end_of_then), - ); - let new_block = replace_children( - &parent_block.syntax(), - RangeInclusive::new( - if_expr.clone().syntax().clone().into(), - if_expr.syntax().clone().into(), - ), - &mut new_if_and_then_statements, - ); + let new_block = match pat { + None => { + // If. + let early_expression = &(early_expression.to_owned() + ";"); + let new_if_expr = + if_indent_level.increase_indent(make::if_expression(&expr, early_expression)); + let then_block_items = IndentLevel::from(1).decrease_indent(then_block.clone()); + let end_of_then = then_block_items.syntax().last_child_or_token().unwrap(); + let end_of_then = + if end_of_then.prev_sibling_or_token().map(|n| n.kind()) == Some(WHITESPACE) { + end_of_then.prev_sibling_or_token().unwrap() + } else { + end_of_then + }; + let mut new_if_and_then_statements = + new_if_expr.syntax().children_with_tokens().chain( + then_block_items + .syntax() + .children_with_tokens() + .skip(1) + .take_while(|i| *i != end_of_then), + ); + replace_children( + &parent_block.syntax(), + RangeInclusive::new( + if_expr.clone().syntax().clone().into(), + if_expr.syntax().clone().into(), + ), + &mut new_if_and_then_statements, + ) + } + _ => { + // If-let. + let new_match_expr = + if_indent_level.increase_indent(make::let_match_early(expr, early_expression)); + let then_block_items = IndentLevel::from(1).decrease_indent(then_block.clone()); + let end_of_then = then_block_items.syntax().last_child_or_token().unwrap(); + let end_of_then = + if end_of_then.prev_sibling_or_token().map(|n| n.kind()) == Some(WHITESPACE) { + end_of_then.prev_sibling_or_token().unwrap() + } else { + end_of_then + }; + let mut then_statements = new_match_expr.syntax().children_with_tokens().chain( + then_block_items + .syntax() + .children_with_tokens() + .skip(1) + .take_while(|i| *i != end_of_then), + ); + let new_block = replace_children( + &parent_block.syntax(), + RangeInclusive::new( + if_expr.clone().syntax().clone().into(), + if_expr.syntax().clone().into(), + ), + &mut then_statements, + ); + new_block + } + }; edit.target(if_expr.syntax().text_range()); edit.replace_ast(parent_block, ast::Block::cast(new_block).unwrap()); edit.set_cursor(cursor_position); @@ -143,6 +181,37 @@ mod tests { ); } + #[test] + fn convert_let_inside_fn() { + check_assist( + convert_to_guarded_return, + r#" + fn main(n: Option) { + bar(); + if<|> let Some(n) = n { + foo(n); + + //comment + bar(); + } + } + "#, + r#" + fn main(n: Option) { + bar(); + le<|>t n = match n { + Some(it) => it, + None => return, + }; + foo(n); + + //comment + bar(); + } + "#, + ); + } + #[test] fn convert_inside_while() { check_assist( @@ -171,6 +240,35 @@ mod tests { ); } + #[test] + fn convert_let_inside_while() { + check_assist( + convert_to_guarded_return, + r#" + fn main() { + while true { + if<|> let Some(n) = n { + foo(n); + bar(); + } + } + } + "#, + r#" + fn main() { + while true { + le<|>t n = match n { + Some(it) => it, + None => continue, + }; + foo(n); + bar(); + } + } + "#, + ); + } + #[test] fn convert_inside_loop() { check_assist( @@ -199,6 +297,35 @@ mod tests { ); } + #[test] + fn convert_let_inside_loop() { + check_assist( + convert_to_guarded_return, + r#" + fn main() { + loop { + if<|> let Some(n) = n { + foo(n); + bar(); + } + } + } + "#, + r#" + fn main() { + loop { + le<|>t n = match n { + Some(it) => it, + None => continue, + }; + foo(n); + bar(); + } + } + "#, + ); + } + #[test] fn ignore_already_converted_if() { check_assist_not_applicable( diff --git a/crates/ra_syntax/src/ast/make.rs b/crates/ra_syntax/src/ast/make.rs index 3d5f18bfae68..979819d4b5db 100644 --- a/crates/ra_syntax/src/ast/make.rs +++ b/crates/ra_syntax/src/ast/make.rs @@ -110,6 +110,22 @@ pub fn match_arm_list(arms: impl Iterator) -> ast::MatchAr } } +pub fn let_match_early(expr: ast::Expr, early_expression: &str) -> ast::LetStmt { + return from_text(&format!( + r#"let {} = match {} {{ + Some(it) => it, + None => {}, +}};"#, + expr.syntax().text(), + expr.syntax().text(), + early_expression + )); + + fn from_text(text: &str) -> ast::LetStmt { + ast_from_text(&format!("fn f() {{ {} }}", text)) + } +} + pub fn where_pred(path: ast::Path, bounds: impl Iterator) -> ast::WherePred { let bounds = bounds.map(|b| b.syntax().to_string()).join(" + "); return from_text(&format!("{}: {}", path.syntax(), bounds)); From 1841a39f865b38041e84cd80840587dbe57d62c1 Mon Sep 17 00:00:00 2001 From: krk Date: Fri, 1 Nov 2019 16:58:09 +0100 Subject: [PATCH 02/21] Remove variable pat. --- crates/ra_assists/src/assists/early_return.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/ra_assists/src/assists/early_return.rs b/crates/ra_assists/src/assists/early_return.rs index 827170f8f90a..4322d37370cd 100644 --- a/crates/ra_assists/src/assists/early_return.rs +++ b/crates/ra_assists/src/assists/early_return.rs @@ -38,7 +38,6 @@ use crate::{ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Option { let if_expr: ast::IfExpr = ctx.find_node_at_offset()?; let cond = if_expr.condition()?; - let pat = &cond.pat(); let expr = cond.expr()?; let then_block = if_expr.then_branch()?.block()?; if if_expr.else_branch().is_some() { @@ -79,7 +78,7 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Opt ctx.add_assist(AssistId("convert_to_guarded_return"), "convert to guarded return", |edit| { let if_indent_level = IndentLevel::from_node(&if_expr.syntax()); - let new_block = match pat { + let new_block = match cond.pat() { None => { // If. let early_expression = &(early_expression.to_owned() + ";"); From 91ab3f876020872f1f692577792569b7b6c8239d Mon Sep 17 00:00:00 2001 From: krk Date: Fri, 1 Nov 2019 18:18:58 +0100 Subject: [PATCH 03/21] Support paths other than "Some". --- crates/ra_assists/src/assists/early_return.rs | 64 ++++++++++++++++--- crates/ra_syntax/src/ast/make.rs | 5 +- 2 files changed, 59 insertions(+), 10 deletions(-) diff --git a/crates/ra_assists/src/assists/early_return.rs b/crates/ra_assists/src/assists/early_return.rs index 4322d37370cd..8536b015b3af 100644 --- a/crates/ra_assists/src/assists/early_return.rs +++ b/crates/ra_assists/src/assists/early_return.rs @@ -3,7 +3,7 @@ use std::ops::RangeInclusive; use hir::db::HirDatabase; use ra_syntax::{ algo::replace_children, - ast::{self, edit::IndentLevel, make}, + ast::{self, edit::IndentLevel, make, Pat::TupleStructPat}, AstNode, SyntaxKind::{FN_DEF, LOOP_EXPR, L_CURLY, R_CURLY, WHILE_EXPR, WHITESPACE}, }; @@ -38,6 +38,21 @@ use crate::{ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Option { let if_expr: ast::IfExpr = ctx.find_node_at_offset()?; let cond = if_expr.condition()?; + let mut if_let_ident: Option = None; + + // Check if there is an IfLet that we can handle. + match cond.pat() { + None => {} // No IfLet, supported. + Some(TupleStructPat(ref pat)) if pat.args().count() == 1usize => match &pat.path() { + Some(p) => match p.qualifier() { + None => if_let_ident = Some(p.syntax().text().to_string()), + _ => return None, + }, + _ => return None, + }, + _ => return None, // Unsupported IfLet. + }; + let expr = cond.expr()?; let then_block = if_expr.then_branch()?.block()?; if if_expr.else_branch().is_some() { @@ -78,7 +93,7 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Opt ctx.add_assist(AssistId("convert_to_guarded_return"), "convert to guarded return", |edit| { let if_indent_level = IndentLevel::from_node(&if_expr.syntax()); - let new_block = match cond.pat() { + let new_block = match if_let_ident { None => { // If. let early_expression = &(early_expression.to_owned() + ";"); @@ -109,10 +124,13 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Opt &mut new_if_and_then_statements, ) } - _ => { + Some(if_let_ident) => { // If-let. - let new_match_expr = - if_indent_level.increase_indent(make::let_match_early(expr, early_expression)); + let new_match_expr = if_indent_level.increase_indent(make::let_match_early( + expr, + &if_let_ident, + early_expression, + )); let then_block_items = IndentLevel::from(1).decrease_indent(then_block.clone()); let end_of_then = then_block_items.syntax().last_child_or_token().unwrap(); let end_of_then = @@ -128,15 +146,14 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Opt .skip(1) .take_while(|i| *i != end_of_then), ); - let new_block = replace_children( + replace_children( &parent_block.syntax(), RangeInclusive::new( if_expr.clone().syntax().clone().into(), if_expr.syntax().clone().into(), ), &mut then_statements, - ); - new_block + ) } }; edit.target(if_expr.syntax().text_range()); @@ -211,6 +228,37 @@ mod tests { ); } + #[test] + fn convert_let_ok_inside_fn() { + check_assist( + convert_to_guarded_return, + r#" + fn main(n: Option) { + bar(); + if<|> let Ok(n) = n { + foo(n); + + //comment + bar(); + } + } + "#, + r#" + fn main(n: Option) { + bar(); + le<|>t n = match n { + Ok(it) => it, + None => return, + }; + foo(n); + + //comment + bar(); + } + "#, + ); + } + #[test] fn convert_inside_while() { check_assist( diff --git a/crates/ra_syntax/src/ast/make.rs b/crates/ra_syntax/src/ast/make.rs index 979819d4b5db..95062ef6c467 100644 --- a/crates/ra_syntax/src/ast/make.rs +++ b/crates/ra_syntax/src/ast/make.rs @@ -110,14 +110,15 @@ pub fn match_arm_list(arms: impl Iterator) -> ast::MatchAr } } -pub fn let_match_early(expr: ast::Expr, early_expression: &str) -> ast::LetStmt { +pub fn let_match_early(expr: ast::Expr, path: &str, early_expression: &str) -> ast::LetStmt { return from_text(&format!( r#"let {} = match {} {{ - Some(it) => it, + {}(it) => it, None => {}, }};"#, expr.syntax().text(), expr.syntax().text(), + path, early_expression )); From bc14f500a0b0e1349d0f795b85dde5946da113bd Mon Sep 17 00:00:00 2001 From: krk Date: Fri, 1 Nov 2019 18:34:42 +0100 Subject: [PATCH 04/21] Extract common parts of match arms in convert_to_guarded_return assist. --- crates/ra_assists/src/assists/early_return.rs | 87 ++++++++----------- 1 file changed, 37 insertions(+), 50 deletions(-) diff --git a/crates/ra_assists/src/assists/early_return.rs b/crates/ra_assists/src/assists/early_return.rs index 8536b015b3af..570a07a20c56 100644 --- a/crates/ra_assists/src/assists/early_return.rs +++ b/crates/ra_assists/src/assists/early_return.rs @@ -3,9 +3,10 @@ use std::ops::RangeInclusive; use hir::db::HirDatabase; use ra_syntax::{ algo::replace_children, - ast::{self, edit::IndentLevel, make, Pat::TupleStructPat}, + ast::{self, edit::IndentLevel, make, Block, Pat::TupleStructPat}, AstNode, SyntaxKind::{FN_DEF, LOOP_EXPR, L_CURLY, R_CURLY, WHILE_EXPR, WHITESPACE}, + SyntaxNode, }; use crate::{ @@ -97,68 +98,54 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Opt None => { // If. let early_expression = &(early_expression.to_owned() + ";"); - let new_if_expr = + let new_expr = if_indent_level.increase_indent(make::if_expression(&expr, early_expression)); - let then_block_items = IndentLevel::from(1).decrease_indent(then_block.clone()); - let end_of_then = then_block_items.syntax().last_child_or_token().unwrap(); - let end_of_then = - if end_of_then.prev_sibling_or_token().map(|n| n.kind()) == Some(WHITESPACE) { - end_of_then.prev_sibling_or_token().unwrap() - } else { - end_of_then - }; - let mut new_if_and_then_statements = - new_if_expr.syntax().children_with_tokens().chain( - then_block_items - .syntax() - .children_with_tokens() - .skip(1) - .take_while(|i| *i != end_of_then), - ); - replace_children( - &parent_block.syntax(), - RangeInclusive::new( - if_expr.clone().syntax().clone().into(), - if_expr.syntax().clone().into(), - ), - &mut new_if_and_then_statements, - ) + replace(new_expr, &then_block, &parent_block, &if_expr) } Some(if_let_ident) => { // If-let. - let new_match_expr = if_indent_level.increase_indent(make::let_match_early( + let new_expr = if_indent_level.increase_indent(make::let_match_early( expr, &if_let_ident, early_expression, )); - let then_block_items = IndentLevel::from(1).decrease_indent(then_block.clone()); - let end_of_then = then_block_items.syntax().last_child_or_token().unwrap(); - let end_of_then = - if end_of_then.prev_sibling_or_token().map(|n| n.kind()) == Some(WHITESPACE) { - end_of_then.prev_sibling_or_token().unwrap() - } else { - end_of_then - }; - let mut then_statements = new_match_expr.syntax().children_with_tokens().chain( - then_block_items - .syntax() - .children_with_tokens() - .skip(1) - .take_while(|i| *i != end_of_then), - ); - replace_children( - &parent_block.syntax(), - RangeInclusive::new( - if_expr.clone().syntax().clone().into(), - if_expr.syntax().clone().into(), - ), - &mut then_statements, - ) + replace(new_expr, &then_block, &parent_block, &if_expr) } }; edit.target(if_expr.syntax().text_range()); edit.replace_ast(parent_block, ast::Block::cast(new_block).unwrap()); edit.set_cursor(cursor_position); + + fn replace( + new_expr: impl AstNode, + then_block: &Block, + parent_block: &Block, + if_expr: &ast::IfExpr, + ) -> SyntaxNode { + let then_block_items = IndentLevel::from(1).decrease_indent(then_block.clone()); + let end_of_then = then_block_items.syntax().last_child_or_token().unwrap(); + let end_of_then = + if end_of_then.prev_sibling_or_token().map(|n| n.kind()) == Some(WHITESPACE) { + end_of_then.prev_sibling_or_token().unwrap() + } else { + end_of_then + }; + let mut then_statements = new_expr.syntax().children_with_tokens().chain( + then_block_items + .syntax() + .children_with_tokens() + .skip(1) + .take_while(|i| *i != end_of_then), + ); + replace_children( + &parent_block.syntax(), + RangeInclusive::new( + if_expr.clone().syntax().clone().into(), + if_expr.syntax().clone().into(), + ), + &mut then_statements, + ) + } }) } From c5e44b208418c7090d9dd4bf3e5bc4dc140af91a Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sat, 2 Nov 2019 15:32:08 +0100 Subject: [PATCH 05/21] Upgrade Chalk --- Cargo.lock | 54 ++++++++++++++++++++-------------------- crates/ra_hir/Cargo.toml | 6 ++--- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 10f51403a380..29f77044e832 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -126,7 +126,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "chalk-derive" version = "0.1.0" -source = "git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809#8314f2fcec8582a58c24b638f1a259d4145a0809" +source = "git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05#50f9f636123bd88d0cc1b958749981d6702e4d05" dependencies = [ "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -136,9 +136,9 @@ dependencies = [ [[package]] name = "chalk-engine" version = "0.9.0" -source = "git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809#8314f2fcec8582a58c24b638f1a259d4145a0809" +source = "git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05#50f9f636123bd88d0cc1b958749981d6702e4d05" dependencies = [ - "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)", + "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05)", "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "stacker 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -146,18 +146,18 @@ dependencies = [ [[package]] name = "chalk-ir" version = "0.1.0" -source = "git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809#8314f2fcec8582a58c24b638f1a259d4145a0809" +source = "git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05#50f9f636123bd88d0cc1b958749981d6702e4d05" dependencies = [ - "chalk-derive 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)", - "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)", - "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)", + "chalk-derive 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05)", + "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05)", + "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05)", "lalrpop-intern 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "chalk-macros" version = "0.1.1" -source = "git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809#8314f2fcec8582a58c24b638f1a259d4145a0809" +source = "git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05#50f9f636123bd88d0cc1b958749981d6702e4d05" dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -165,23 +165,23 @@ dependencies = [ [[package]] name = "chalk-rust-ir" version = "0.1.0" -source = "git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809#8314f2fcec8582a58c24b638f1a259d4145a0809" +source = "git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05#50f9f636123bd88d0cc1b958749981d6702e4d05" dependencies = [ - "chalk-derive 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)", - "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)", - "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)", - "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)", + "chalk-derive 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05)", + "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05)", + "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05)", + "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05)", ] [[package]] name = "chalk-solve" version = "0.1.0" -source = "git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809#8314f2fcec8582a58c24b638f1a259d4145a0809" +source = "git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05#50f9f636123bd88d0cc1b958749981d6702e4d05" dependencies = [ - "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)", - "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)", - "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)", - "chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)", + "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05)", + "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05)", + "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05)", + "chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05)", "ena 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "petgraph 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1000,9 +1000,9 @@ name = "ra_hir" version = "0.1.0" dependencies = [ "arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)", - "chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)", - "chalk-solve 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)", + "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05)", + "chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05)", + "chalk-solve 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05)", "ena 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "insta 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "lalrpop-intern 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1849,12 +1849,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum cargo_metadata 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8d2d1617e838936c0d2323a65cc151e03ae19a7678dd24f72bccf27119b90a5d" "checksum cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)" = "0213d356d3c4ea2c18c40b037c3be23cd639825c18f25ee670ac7813beeef99c" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" -"checksum chalk-derive 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)" = "" -"checksum chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)" = "" -"checksum chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)" = "" -"checksum chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)" = "" -"checksum chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)" = "" -"checksum chalk-solve 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=8314f2fcec8582a58c24b638f1a259d4145a0809)" = "" +"checksum chalk-derive 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05)" = "" +"checksum chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05)" = "" +"checksum chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05)" = "" +"checksum chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05)" = "" +"checksum chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05)" = "" +"checksum chalk-solve 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=50f9f636123bd88d0cc1b958749981d6702e4d05)" = "" "checksum chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e8493056968583b0193c1bb04d6f7684586f3726992d6c573261941a895dbd68" "checksum clicolors-control 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90082ee5dcdd64dc4e9e0d37fbf3ee325419e39c0092191e0393df65518f741e" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" diff --git a/crates/ra_hir/Cargo.toml b/crates/ra_hir/Cargo.toml index 5df371bc0f97..fae5dc7cb526 100644 --- a/crates/ra_hir/Cargo.toml +++ b/crates/ra_hir/Cargo.toml @@ -24,9 +24,9 @@ hir_def = { path = "../ra_hir_def", package = "ra_hir_def" } test_utils = { path = "../test_utils" } ra_prof = { path = "../ra_prof" } -chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "8314f2fcec8582a58c24b638f1a259d4145a0809" } -chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "8314f2fcec8582a58c24b638f1a259d4145a0809" } -chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "8314f2fcec8582a58c24b638f1a259d4145a0809" } +chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "50f9f636123bd88d0cc1b958749981d6702e4d05" } +chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "50f9f636123bd88d0cc1b958749981d6702e4d05" } +chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "50f9f636123bd88d0cc1b958749981d6702e4d05" } lalrpop-intern = "0.15.1" [dev-dependencies] From 7f1903ed460ed3ba7de553d13ce4e23bad70f1ad Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 2 Nov 2019 22:19:59 +0300 Subject: [PATCH 06/21] Remove forcing \n via rustfmt The original idea here was to make sure, on CI, that line endings are \n. Travis however uses autocrlf, so the check doesn't actually work, and forcing \n otherwise makes lives of windows folks difficult closes #2157 --- rustfmt.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/rustfmt.toml b/rustfmt.toml index f2e1646181bc..71007de81b9f 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,3 +1,2 @@ reorder_modules = false use_small_heuristics = "Max" -newline_style = "Unix" From b8533413cf082f2d942b78af841e3895db252106 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 2 Nov 2019 23:11:05 +0300 Subject: [PATCH 07/21] Move Source to hir_expand --- crates/ra_hir/src/code_model/src.rs | 2 +- crates/ra_hir/src/lib.rs | 4 ++-- crates/ra_hir_def/src/lib.rs | 17 +---------------- crates/ra_hir_expand/src/lib.rs | 20 +++++++++++++++++++- 4 files changed, 23 insertions(+), 20 deletions(-) diff --git a/crates/ra_hir/src/code_model/src.rs b/crates/ra_hir/src/code_model/src.rs index 0f4c78df760d..bd0c3c226aa4 100644 --- a/crates/ra_hir/src/code_model/src.rs +++ b/crates/ra_hir/src/code_model/src.rs @@ -10,7 +10,7 @@ use crate::{ ModuleSource, Static, Struct, StructField, Trait, TypeAlias, Union, }; -pub use hir_def::Source; +pub use hir_expand::Source; pub trait HasSource { type Ast; diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 40f5562b406a..0ba17e5710d3 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs @@ -62,7 +62,7 @@ pub use crate::{ adt::VariantDef, code_model::{ docs::{DocDef, Docs, Documentation}, - src::{HasBodySource, HasSource, Source}, + src::{HasBodySource, HasSource}, Adt, AssocItem, Const, ConstData, Container, Crate, CrateDependency, DefWithBody, Enum, EnumVariant, FieldSource, FnData, Function, HasBody, MacroDef, Module, ModuleDef, ModuleSource, Static, Struct, StructField, Trait, TypeAlias, Union, @@ -85,4 +85,4 @@ pub use hir_def::{ path::{Path, PathKind}, type_ref::Mutability, }; -pub use hir_expand::{either::Either, name::Name}; +pub use hir_expand::{either::Either, name::Name, Source}; diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs index 76d5f18522bc..6d66f481d3f8 100644 --- a/crates/ra_hir_def/src/lib.rs +++ b/crates/ra_hir_def/src/lib.rs @@ -19,19 +19,13 @@ pub mod nameres; use std::hash::{Hash, Hasher}; -use hir_expand::{ast_id_map::FileAstId, db::AstDatabase, AstId, HirFileId}; +use hir_expand::{ast_id_map::FileAstId, db::AstDatabase, AstId, HirFileId, Source}; use ra_arena::{impl_arena_id, RawId}; use ra_db::{salsa, CrateId, FileId}; use ra_syntax::{ast, AstNode, SyntaxNode}; use crate::{builtin_type::BuiltinType, db::InternDatabase}; -#[derive(Debug, PartialEq, Eq, Clone, Copy)] -pub struct Source { - pub file_id: HirFileId, - pub ast: T, -} - pub enum ModuleSource { SourceFile(ast::SourceFile), Module(ast::Module), @@ -94,15 +88,6 @@ impl ModuleSource { } } -impl Source { - pub fn map U, U>(self, f: F) -> Source { - Source { file_id: self.file_id, ast: f(self.ast) } - } - pub fn file_syntax(&self, db: &impl AstDatabase) -> SyntaxNode { - db.parse_or_expand(self.file_id).expect("source created from invalid file") - } -} - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct ModuleId { pub krate: CrateId, diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs index 5a0e5a19c533..85c2b22ace5a 100644 --- a/crates/ra_hir_expand/src/lib.rs +++ b/crates/ra_hir_expand/src/lib.rs @@ -13,7 +13,10 @@ pub mod hygiene; use std::hash::{Hash, Hasher}; use ra_db::{salsa, CrateId, FileId}; -use ra_syntax::ast::{self, AstNode}; +use ra_syntax::{ + ast::{self, AstNode}, + SyntaxNode, +}; use crate::ast_id_map::FileAstId; @@ -151,3 +154,18 @@ impl AstId { db.ast_id_map(self.file_id).get(self.file_ast_id).to_node(&root) } } + +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub struct Source { + pub file_id: HirFileId, + pub ast: T, +} + +impl Source { + pub fn map U, U>(self, f: F) -> Source { + Source { file_id: self.file_id, ast: f(self.ast) } + } + pub fn file_syntax(&self, db: &impl db::AstDatabase) -> SyntaxNode { + db.parse_or_expand(self.file_id).expect("source created from invalid file") + } +} From dc3848a6a3e659004ba4f2160503be28ea0f9051 Mon Sep 17 00:00:00 2001 From: Martin Asquino Date: Fri, 1 Nov 2019 23:52:59 -0300 Subject: [PATCH 08/21] Set `deprecated` field on `CompletionItem`s --- .../ra_ide_api/src/completion/complete_dot.rs | 11 +++ .../complete_macro_in_item_position.rs | 4 + .../src/completion/complete_path.rs | 17 ++++ .../src/completion/complete_record_literal.rs | 32 +++++++ .../src/completion/complete_record_pattern.rs | 3 + .../src/completion/complete_scope.rs | 19 +++++ .../src/completion/completion_item.rs | 17 ++++ .../ra_ide_api/src/completion/presentation.rs | 83 ++++++++++++++++++- crates/ra_lsp_server/src/conv.rs | 1 + 9 files changed, 186 insertions(+), 1 deletion(-) diff --git a/crates/ra_ide_api/src/completion/complete_dot.rs b/crates/ra_ide_api/src/completion/complete_dot.rs index b4df6ee2ad04..9c0abd59062b 100644 --- a/crates/ra_ide_api/src/completion/complete_dot.rs +++ b/crates/ra_ide_api/src/completion/complete_dot.rs @@ -96,6 +96,7 @@ mod tests { ⋮ insert: "the_field", ⋮ kind: Field, ⋮ detail: "u32", + ⋮ deprecated: false, ⋮ }, ⋮] "### @@ -128,6 +129,7 @@ mod tests { kind: Method, lookup: "foo", detail: "fn foo(self)", + deprecated: false, }, CompletionItem { label: "the_field", @@ -139,6 +141,7 @@ mod tests { documentation: Documentation( "This is the_field", ), + deprecated: false, }, ] "### @@ -168,6 +171,7 @@ mod tests { kind: Method, lookup: "foo", detail: "fn foo(&self)", + deprecated: false, }, CompletionItem { label: "the_field", @@ -176,6 +180,7 @@ mod tests { insert: "the_field", kind: Field, detail: "(u32, i32)", + deprecated: false, }, ] "### @@ -221,6 +226,7 @@ mod tests { kind: Method, lookup: "the_method", detail: "fn the_method(&self)", + deprecated: false, }, ] "### @@ -250,6 +256,7 @@ mod tests { kind: Method, lookup: "the_method", detail: "fn the_method(&self)", + deprecated: false, }, ] "### @@ -279,6 +286,7 @@ mod tests { kind: Method, lookup: "the_method", detail: "fn the_method(&self)", + deprecated: false, }, ] "### @@ -331,6 +339,7 @@ mod tests { kind: Method, lookup: "the_method", detail: "fn the_method(&self)", + deprecated: false, }, ] "### @@ -401,6 +410,7 @@ mod tests { kind: Method, lookup: "blah", detail: "pub fn blah(&self)", + deprecated: false, }, ] "### @@ -427,6 +437,7 @@ mod tests { ⋮ insert: "the_field", ⋮ kind: Field, ⋮ detail: "u32", + ⋮ deprecated: false, ⋮ }, ⋮] "### diff --git a/crates/ra_ide_api/src/completion/complete_macro_in_item_position.rs b/crates/ra_ide_api/src/completion/complete_macro_in_item_position.rs index 09f743c660cb..a082a3c7c9b9 100644 --- a/crates/ra_ide_api/src/completion/complete_macro_in_item_position.rs +++ b/crates/ra_ide_api/src/completion/complete_macro_in_item_position.rs @@ -45,6 +45,7 @@ mod tests { insert: "foo!($0)", kind: Macro, detail: "macro_rules! foo", + deprecated: false, }, ]"## ); @@ -86,6 +87,7 @@ mod tests { documentation: Documentation( "Creates a [`Vec`] containing the arguments.\n\n- Create a [`Vec`] containing a given list of elements:\n\n```\nlet v = vec![1, 2, 3];\nassert_eq!(v[0], 1);\nassert_eq!(v[1], 2);\nassert_eq!(v[2], 3);\n```", ), + deprecated: false, }, ]"## ); @@ -121,6 +123,7 @@ mod tests { documentation: Documentation( "Foo\n\nNot call `fooo!()` `fooo!()`, or `_foo![]` `_foo![]`.\nCall as `let _=foo! { hello world };`", ), + deprecated: false, }, CompletionItem { label: "main()", @@ -130,6 +133,7 @@ mod tests { kind: Function, lookup: "main", detail: "fn main()", + deprecated: false, }, ] "### diff --git a/crates/ra_ide_api/src/completion/complete_path.rs b/crates/ra_ide_api/src/completion/complete_path.rs index 9ac9768afb20..2c9c8645b97b 100644 --- a/crates/ra_ide_api/src/completion/complete_path.rs +++ b/crates/ra_ide_api/src/completion/complete_path.rs @@ -308,6 +308,7 @@ mod tests { documentation: Documentation( "Bar Variant with i32", ), + deprecated: false, }, CompletionItem { label: "Foo", @@ -319,6 +320,7 @@ mod tests { documentation: Documentation( "Foo Variant", ), + deprecated: false, }, ]"### ); @@ -354,6 +356,7 @@ mod tests { documentation: Documentation( "Bar Variant with i32 and u32", ), + deprecated: false, }, CompletionItem { label: "Foo", @@ -365,6 +368,7 @@ mod tests { documentation: Documentation( "Foo Variant (empty)", ), + deprecated: false, }, CompletionItem { label: "S", @@ -376,6 +380,7 @@ mod tests { documentation: Documentation( "", ), + deprecated: false, }, ]"### ); @@ -411,6 +416,7 @@ mod tests { documentation: Documentation( "An associated method", ), + deprecated: false, }, ] "### @@ -445,6 +451,7 @@ mod tests { documentation: Documentation( "An associated const", ), + deprecated: false, }, ]"### ); @@ -478,6 +485,7 @@ mod tests { documentation: Documentation( "An associated type", ), + deprecated: false, }, ]"### ); @@ -513,6 +521,7 @@ mod tests { documentation: Documentation( "An associated method", ), + deprecated: false, }, ] "### @@ -549,6 +558,7 @@ mod tests { documentation: Documentation( "An associated method", ), + deprecated: false, }, ] "### @@ -608,6 +618,7 @@ mod tests { documentation: Documentation( "A trait method", ), + deprecated: false, }, ] "### @@ -644,6 +655,7 @@ mod tests { documentation: Documentation( "A trait method", ), + deprecated: false, }, ] "### @@ -680,6 +692,7 @@ mod tests { documentation: Documentation( "A trait method", ), + deprecated: false, }, ] "### @@ -711,6 +724,7 @@ mod tests { kind: Function, lookup: "bar", detail: "fn bar()", + deprecated: false, }, CompletionItem { label: "foo()", @@ -720,6 +734,7 @@ mod tests { kind: Function, lookup: "foo", detail: "fn foo()", + deprecated: false, }, ] "### @@ -750,6 +765,7 @@ mod tests { insert: "foo!($0)", kind: Macro, detail: "#[macro_export]\nmacro_rules! foo", + deprecated: false, }, CompletionItem { label: "main()", @@ -759,6 +775,7 @@ mod tests { kind: Function, lookup: "main", detail: "fn main()", + deprecated: false, }, ] "### diff --git a/crates/ra_ide_api/src/completion/complete_record_literal.rs b/crates/ra_ide_api/src/completion/complete_record_literal.rs index 4406695d5179..33bea411f798 100644 --- a/crates/ra_ide_api/src/completion/complete_record_literal.rs +++ b/crates/ra_ide_api/src/completion/complete_record_literal.rs @@ -31,6 +31,34 @@ mod tests { do_completion(code, CompletionKind::Reference) } + #[test] + fn test_record_literal_deprecated_field() { + let completions = complete( + r" + struct A { + #[deprecated] + the_field: u32, + } + fn foo() { + A { the<|> } + } + ", + ); + assert_debug_snapshot!(completions, @r###" + ⋮[ + ⋮ CompletionItem { + ⋮ label: "the_field", + ⋮ source_range: [142; 145), + ⋮ delete: [142; 145), + ⋮ insert: "the_field", + ⋮ kind: Field, + ⋮ detail: "u32", + ⋮ deprecated: true, + ⋮ }, + ⋮] + "###); + } + #[test] fn test_record_literal_field() { let completions = complete( @@ -50,6 +78,7 @@ mod tests { ⋮ insert: "the_field", ⋮ kind: Field, ⋮ detail: "u32", + ⋮ deprecated: false, ⋮ }, ⋮] "###); @@ -76,6 +105,7 @@ mod tests { ⋮ insert: "a", ⋮ kind: Field, ⋮ detail: "u32", + ⋮ deprecated: false, ⋮ }, ⋮] "###); @@ -102,6 +132,7 @@ mod tests { ⋮ insert: "b", ⋮ kind: Field, ⋮ detail: "u32", + ⋮ deprecated: false, ⋮ }, ⋮] "###); @@ -127,6 +158,7 @@ mod tests { ⋮ insert: "a", ⋮ kind: Field, ⋮ detail: "u32", + ⋮ deprecated: false, ⋮ }, ⋮] "###); diff --git a/crates/ra_ide_api/src/completion/complete_record_pattern.rs b/crates/ra_ide_api/src/completion/complete_record_pattern.rs index d20fa796c7f8..93c26f2297f9 100644 --- a/crates/ra_ide_api/src/completion/complete_record_pattern.rs +++ b/crates/ra_ide_api/src/completion/complete_record_pattern.rs @@ -52,6 +52,7 @@ mod tests { ⋮ insert: "foo", ⋮ kind: Field, ⋮ detail: "u32", + ⋮ deprecated: false, ⋮ }, ⋮] "###); @@ -81,6 +82,7 @@ mod tests { ⋮ insert: "bar", ⋮ kind: Field, ⋮ detail: "()", + ⋮ deprecated: false, ⋮ }, ⋮ CompletionItem { ⋮ label: "foo", @@ -89,6 +91,7 @@ mod tests { ⋮ insert: "foo", ⋮ kind: Field, ⋮ detail: "u32", + ⋮ deprecated: false, ⋮ }, ⋮] "###); diff --git a/crates/ra_ide_api/src/completion/complete_scope.rs b/crates/ra_ide_api/src/completion/complete_scope.rs index 4e56de3f5424..9d2deee75fdc 100644 --- a/crates/ra_ide_api/src/completion/complete_scope.rs +++ b/crates/ra_ide_api/src/completion/complete_scope.rs @@ -155,6 +155,7 @@ mod tests { kind: Function, lookup: "quux", detail: "fn quux(x: i32)", + deprecated: false, }, CompletionItem { label: "x", @@ -218,6 +219,7 @@ mod tests { kind: Function, lookup: "quux", detail: "fn quux()", + deprecated: false, }, ] "### @@ -246,6 +248,7 @@ mod tests { kind: Function, lookup: "quux", detail: "fn quux()", + deprecated: false, }, CompletionItem { label: "x", @@ -286,6 +289,7 @@ mod tests { kind: Function, lookup: "quux", detail: "fn quux()", + deprecated: false, }, ] "### @@ -391,6 +395,7 @@ mod tests { kind: Function, lookup: "quux", detail: "fn quux()", + deprecated: false, }, ] "### @@ -450,6 +455,7 @@ mod tests { kind: Function, lookup: "quux", detail: "fn quux()", + deprecated: false, }, ] "### @@ -482,6 +488,7 @@ mod tests { kind: Function, lookup: "x", detail: "fn x()", + deprecated: false, }, ] "### @@ -520,6 +527,7 @@ mod tests { kind: Function, lookup: "foo", detail: "fn foo()", + deprecated: false, }, ] "### @@ -584,6 +592,7 @@ mod tests { kind: Function, lookup: "foo", detail: "fn foo()", + deprecated: false, }, CompletionItem { label: "std", @@ -639,6 +648,7 @@ mod tests { insert: "bar!($0)", kind: Macro, detail: "macro_rules! bar", + deprecated: false, }, CompletionItem { label: "baz!", @@ -647,6 +657,7 @@ mod tests { insert: "baz!($0)", kind: Macro, detail: "#[macro_export]\nmacro_rules! baz", + deprecated: false, }, CompletionItem { label: "foo!", @@ -655,6 +666,7 @@ mod tests { insert: "foo!($0)", kind: Macro, detail: "macro_rules! foo", + deprecated: false, }, CompletionItem { label: "m1", @@ -678,6 +690,7 @@ mod tests { kind: Function, lookup: "main", detail: "fn main()", + deprecated: false, }, ] "### @@ -708,6 +721,7 @@ mod tests { insert: "foo!($0)", kind: Macro, detail: "macro_rules! foo", + deprecated: false, }, CompletionItem { label: "foo()", @@ -717,6 +731,7 @@ mod tests { kind: Function, lookup: "foo", detail: "fn foo()", + deprecated: false, }, ] "### @@ -747,6 +762,7 @@ mod tests { insert: "foo!($0)", kind: Macro, detail: "macro_rules! foo", + deprecated: false, }, CompletionItem { label: "main()", @@ -756,6 +772,7 @@ mod tests { kind: Function, lookup: "main", detail: "fn main()", + deprecated: false, }, ] "### @@ -786,6 +803,7 @@ mod tests { insert: "foo!($0)", kind: Macro, detail: "macro_rules! foo", + deprecated: false, }, CompletionItem { label: "main()", @@ -795,6 +813,7 @@ mod tests { kind: Function, lookup: "main", detail: "fn main()", + deprecated: false, }, ] "### diff --git a/crates/ra_ide_api/src/completion/completion_item.rs b/crates/ra_ide_api/src/completion/completion_item.rs index 5c9c44704b3b..6753672ca4c0 100644 --- a/crates/ra_ide_api/src/completion/completion_item.rs +++ b/crates/ra_ide_api/src/completion/completion_item.rs @@ -44,6 +44,9 @@ pub struct CompletionItem { /// Additional info to show in the UI pop up. detail: Option, documentation: Option, + + /// Whether this item is marked as deprecated + deprecated: Option, } // We use custom debug for CompletionItem to make `insta`'s diffs more readable. @@ -70,6 +73,9 @@ impl fmt::Debug for CompletionItem { if let Some(documentation) = self.documentation() { s.field("documentation", &documentation); } + if let Some(deprecated) = self.deprecated { + s.field("deprecated", &deprecated); + } s.finish() } } @@ -132,6 +138,7 @@ impl CompletionItem { lookup: None, kind: None, text_edit: None, + deprecated: None, } } /// What user sees in pop-up in the UI. @@ -166,6 +173,10 @@ impl CompletionItem { pub fn kind(&self) -> Option { self.kind } + + pub fn deprecated(&self) -> Option { + self.deprecated + } } /// A helper to make `CompletionItem`s. @@ -181,6 +192,7 @@ pub(crate) struct Builder { lookup: Option, kind: Option, text_edit: Option, + deprecated: Option, } impl Builder { @@ -208,6 +220,7 @@ impl Builder { lookup: self.lookup, kind: self.kind, completion_kind: self.completion_kind, + deprecated: self.deprecated, } } pub(crate) fn lookup_by(mut self, lookup: impl Into) -> Builder { @@ -254,6 +267,10 @@ impl Builder { self.documentation = docs.map(Into::into); self } + pub(crate) fn set_deprecated(mut self, deprecated: bool) -> Builder { + self.deprecated = Some(deprecated); + self + } } impl<'a> Into for Builder { diff --git a/crates/ra_ide_api/src/completion/presentation.rs b/crates/ra_ide_api/src/completion/presentation.rs index 65bb639ed508..d98201887e51 100644 --- a/crates/ra_ide_api/src/completion/presentation.rs +++ b/crates/ra_ide_api/src/completion/presentation.rs @@ -2,7 +2,7 @@ use hir::{db::HirDatabase, Docs, HasSource, HirDisplay, ScopeDef, Ty, TypeWalk}; use join_to_string::join; -use ra_syntax::ast::NameOwner; +use ra_syntax::ast::{AttrsOwner, NameOwner}; use test_utils::tested_by; use crate::completion::{ @@ -18,6 +18,11 @@ impl Completions { field: hir::StructField, substs: &hir::Substs, ) { + let ast_node = field.source(ctx.db).ast; + let is_deprecated = match ast_node { + hir::FieldSource::Named(m) => is_deprecated(m), + hir::FieldSource::Pos(m) => is_deprecated(m), + }; CompletionItem::new( CompletionKind::Reference, ctx.source_range(), @@ -26,6 +31,7 @@ impl Completions { .kind(CompletionItemKind::Field) .detail(field.ty(ctx.db).subst(substs).display(ctx.db).to_string()) .set_documentation(field.docs(ctx.db)) + .set_deprecated(is_deprecated) .add_to(self); } @@ -179,6 +185,7 @@ impl Completions { CompletionItem::new(CompletionKind::Reference, ctx.source_range(), ¯o_declaration) .kind(CompletionItemKind::Macro) .set_documentation(docs.clone()) + .set_deprecated(is_deprecated(ast_node)) .detail(detail); builder = if ctx.use_item_syntax.is_some() { @@ -211,6 +218,7 @@ impl Completions { CompletionItemKind::Function }) .set_documentation(func.docs(ctx.db)) + .set_deprecated(is_deprecated(ast_node)) .detail(detail); // Add `<>` for generic types @@ -242,6 +250,7 @@ impl Completions { CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.text().to_string()) .kind(CompletionItemKind::Const) .set_documentation(constant.docs(ctx.db)) + .set_deprecated(is_deprecated(ast_node)) .detail(detail) .add_to(self); } @@ -257,11 +266,13 @@ impl Completions { CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.text().to_string()) .kind(CompletionItemKind::TypeAlias) .set_documentation(type_alias.docs(ctx.db)) + .set_deprecated(is_deprecated(type_def)) .detail(detail) .add_to(self); } pub(crate) fn add_enum_variant(&mut self, ctx: &CompletionContext, variant: hir::EnumVariant) { + let is_deprecated = is_deprecated(variant.source(ctx.db).ast); let name = match variant.name(ctx.db) { Some(it) => it, None => return, @@ -274,11 +285,16 @@ impl Completions { CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string()) .kind(CompletionItemKind::EnumVariant) .set_documentation(variant.docs(ctx.db)) + .set_deprecated(is_deprecated) .detail(detail) .add_to(self); } } +fn is_deprecated(node: impl AttrsOwner) -> bool { + node.attrs().filter_map(|x| x.simple_name()).any(|x| x == "deprecated") +} + fn has_non_default_type_params(def: hir::GenericDef, db: &db::RootDatabase) -> bool { let subst = db.generic_defaults(def); subst.iter().any(|ty| ty == &Ty::Unknown) @@ -295,6 +311,57 @@ mod tests { do_completion(code, CompletionKind::Reference) } + #[test] + fn sets_deprecated_flag_in_completion_items() { + assert_debug_snapshot!( + do_reference_completion( + r#" + #[deprecated] + fn something_deprecated() {} + + #[deprecated(since = "1.0.0")] + fn something_else_deprecated() {} + + fn main() { som<|> } + "#, + ), + @r###" + [ + CompletionItem { + label: "main()", + source_range: [203; 206), + delete: [203; 206), + insert: "main()$0", + kind: Function, + lookup: "main", + detail: "fn main()", + deprecated: false, + }, + CompletionItem { + label: "something_deprecated()", + source_range: [203; 206), + delete: [203; 206), + insert: "something_deprecated()$0", + kind: Function, + lookup: "something_deprecated", + detail: "fn something_deprecated()", + deprecated: true, + }, + CompletionItem { + label: "something_else_deprecated()", + source_range: [203; 206), + delete: [203; 206), + insert: "something_else_deprecated()$0", + kind: Function, + lookup: "something_else_deprecated", + detail: "fn something_else_deprecated()", + deprecated: true, + }, + ] + "### + ); + } + #[test] fn inserts_parens_for_function_calls() { covers!(inserts_parens_for_function_calls); @@ -315,6 +382,7 @@ mod tests { kind: Function, lookup: "main", detail: "fn main()", + deprecated: false, }, CompletionItem { label: "no_args()", @@ -324,6 +392,7 @@ mod tests { kind: Function, lookup: "no_args", detail: "fn no_args()", + deprecated: false, }, ] "### @@ -345,6 +414,7 @@ mod tests { kind: Function, lookup: "main", detail: "fn main()", + deprecated: false, }, CompletionItem { label: "with_args(…)", @@ -354,6 +424,7 @@ mod tests { kind: Function, lookup: "with_args", detail: "fn with_args(x: i32, y: String)", + deprecated: false, }, ] "### @@ -380,6 +451,7 @@ mod tests { kind: Method, lookup: "foo", detail: "fn foo(&self)", + deprecated: false, }, ] "### @@ -404,6 +476,7 @@ mod tests { insert: "foo", kind: Function, detail: "pub fn foo()", + deprecated: false, }, ]"# ); @@ -429,6 +502,7 @@ mod tests { insert: "frobnicate", kind: Function, detail: "fn frobnicate()", + deprecated: false, }, CompletionItem { label: "main", @@ -437,6 +511,7 @@ mod tests { insert: "main", kind: Function, detail: "fn main()", + deprecated: false, }, ]"# ); @@ -459,6 +534,7 @@ mod tests { insert: "new", kind: Function, detail: "fn new() -> Foo", + deprecated: false, }, ]"# ); @@ -492,6 +568,7 @@ mod tests { kind: Function, lookup: "foo", detail: "fn foo(xs: Ve)", + deprecated: false, }, ] "### @@ -521,6 +598,7 @@ mod tests { kind: Function, lookup: "foo", detail: "fn foo(xs: Ve)", + deprecated: false, }, ] "### @@ -549,6 +627,7 @@ mod tests { kind: Function, lookup: "foo", detail: "fn foo(xs: Ve)", + deprecated: false, }, ] "### @@ -577,6 +656,7 @@ mod tests { kind: Function, lookup: "foo", detail: "fn foo(xs: Ve)", + deprecated: false, }, ] "### @@ -607,6 +687,7 @@ mod tests { insert: "frobnicate", kind: Macro, detail: "#[macro_export]\nmacro_rules! frobnicate", + deprecated: false, }, ] "### diff --git a/crates/ra_lsp_server/src/conv.rs b/crates/ra_lsp_server/src/conv.rs index ee503633d7ee..a4667d284556 100644 --- a/crates/ra_lsp_server/src/conv.rs +++ b/crates/ra_lsp_server/src/conv.rs @@ -127,6 +127,7 @@ impl ConvWith<(&LineIndex, LineEndings)> for CompletionItem { text_edit: Some(text_edit), additional_text_edits: Some(additional_text_edits), documentation: self.documentation().map(|it| it.conv()), + deprecated: self.deprecated(), ..Default::default() }; res.insert_text_format = Some(match self.insert_text_format() { From 13735d91a78ba51fb202cb7dde1dfe25420afe9a Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 2 Nov 2019 23:42:38 +0300 Subject: [PATCH 09/21] Move diagnostics to hir_expand --- crates/ra_hir/src/code_model.rs | 6 +- crates/ra_hir/src/diagnostics.rs | 81 ++--------------------- crates/ra_hir/src/expr/validation.rs | 3 +- crates/ra_hir/src/mock.rs | 3 +- crates/ra_hir/src/nameres.rs | 5 +- crates/ra_hir/src/ty/infer.rs | 12 ++-- crates/ra_hir_expand/src/diagnostics.rs | 85 +++++++++++++++++++++++++ crates/ra_hir_expand/src/lib.rs | 1 + 8 files changed, 107 insertions(+), 89 deletions(-) create mode 100644 crates/ra_hir_expand/src/diagnostics.rs diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index c97ea18a24ea..5b78bdfef389 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs @@ -11,14 +11,16 @@ use hir_def::{ type_ref::{Mutability, TypeRef}, CrateModuleId, LocalEnumVariantId, LocalStructFieldId, ModuleId, }; -use hir_expand::name::{self, AsName}; +use hir_expand::{ + diagnostics::DiagnosticSink, + name::{self, AsName}, +}; use ra_db::{CrateId, Edition}; use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; use crate::{ adt::VariantDef, db::{AstDatabase, DefDatabase, HirDatabase}, - diagnostics::DiagnosticSink, expr::{validation::ExprValidator, Body, BodySourceMap}, generics::HasGenericParams, ids::{ diff --git a/crates/ra_hir/src/diagnostics.rs b/crates/ra_hir/src/diagnostics.rs index 9acdaf8ed3f4..a33af8f46753 100644 --- a/crates/ra_hir/src/diagnostics.rs +++ b/crates/ra_hir/src/diagnostics.rs @@ -1,82 +1,13 @@ //! FIXME: write short doc here -use std::{any::Any, fmt}; +use std::any::Any; -use ra_syntax::{ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr, TextRange}; +use ra_syntax::{ast, AstNode, AstPtr, SyntaxNodePtr}; use relative_path::RelativePathBuf; -use crate::{db::HirDatabase, HirFileId, Name, Source}; +use crate::{db::AstDatabase, HirFileId, Name, Source}; -/// Diagnostic defines hir API for errors and warnings. -/// -/// It is used as a `dyn` object, which you can downcast to a concrete -/// diagnostic. DiagnosticSink are structured, meaning that they include rich -/// information which can be used by IDE to create fixes. DiagnosticSink are -/// expressed in terms of macro-expanded syntax tree nodes (so, it's a bad idea -/// to diagnostic in a salsa value). -/// -/// Internally, various subsystems of hir produce diagnostics specific to a -/// subsystem (typically, an `enum`), which are safe to store in salsa but do not -/// include source locations. Such internal diagnostic are transformed into an -/// instance of `Diagnostic` on demand. -pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static { - fn message(&self) -> String; - fn source(&self) -> Source; - fn highlight_range(&self) -> TextRange { - self.source().ast.range() - } - fn as_any(&self) -> &(dyn Any + Send + 'static); -} - -pub trait AstDiagnostic { - type AST; - fn ast(&self, db: &impl HirDatabase) -> Self::AST; -} - -impl dyn Diagnostic { - pub fn syntax_node(&self, db: &impl HirDatabase) -> SyntaxNode { - let node = db.parse_or_expand(self.source().file_id).unwrap(); - self.source().ast.to_node(&node) - } - - pub fn downcast_ref(&self) -> Option<&D> { - self.as_any().downcast_ref() - } -} - -pub struct DiagnosticSink<'a> { - callbacks: Vec Result<(), ()> + 'a>>, - default_callback: Box, -} - -impl<'a> DiagnosticSink<'a> { - pub fn new(cb: impl FnMut(&dyn Diagnostic) + 'a) -> DiagnosticSink<'a> { - DiagnosticSink { callbacks: Vec::new(), default_callback: Box::new(cb) } - } - - pub fn on(mut self, mut cb: F) -> DiagnosticSink<'a> { - let cb = move |diag: &dyn Diagnostic| match diag.downcast_ref::() { - Some(d) => { - cb(d); - Ok(()) - } - None => Err(()), - }; - self.callbacks.push(Box::new(cb)); - self - } - - pub(crate) fn push(&mut self, d: impl Diagnostic) { - let d: &dyn Diagnostic = &d; - for cb in self.callbacks.iter_mut() { - match cb(d) { - Ok(()) => return, - Err(()) => (), - } - } - (self.default_callback)(d) - } -} +pub use hir_expand::diagnostics::{AstDiagnostic, Diagnostic, DiagnosticSink}; #[derive(Debug)] pub struct NoSuchField { @@ -139,7 +70,7 @@ impl Diagnostic for MissingFields { impl AstDiagnostic for MissingFields { type AST = ast::RecordFieldList; - fn ast(&self, db: &impl HirDatabase) -> Self::AST { + fn ast(&self, db: &impl AstDatabase) -> Self::AST { let root = db.parse_or_expand(self.source().file_id).unwrap(); let node = self.source().ast.to_node(&root); ast::RecordFieldList::cast(node).unwrap() @@ -167,7 +98,7 @@ impl Diagnostic for MissingOkInTailExpr { impl AstDiagnostic for MissingOkInTailExpr { type AST = ast::Expr; - fn ast(&self, db: &impl HirDatabase) -> Self::AST { + fn ast(&self, db: &impl AstDatabase) -> Self::AST { let root = db.parse_or_expand(self.file).unwrap(); let node = self.source().ast.to_node(&root); ast::Expr::cast(node).unwrap() diff --git a/crates/ra_hir/src/expr/validation.rs b/crates/ra_hir/src/expr/validation.rs index c685edda193f..3054f1dcedf4 100644 --- a/crates/ra_hir/src/expr/validation.rs +++ b/crates/ra_hir/src/expr/validation.rs @@ -3,12 +3,13 @@ use std::sync::Arc; use hir_def::path::known; +use hir_expand::diagnostics::DiagnosticSink; use ra_syntax::ast; use rustc_hash::FxHashSet; use crate::{ db::HirDatabase, - diagnostics::{DiagnosticSink, MissingFields, MissingOkInTailExpr}, + diagnostics::{MissingFields, MissingOkInTailExpr}, expr::AstPtr, ty::{ApplicationTy, InferenceResult, Ty, TypeCtor}, Adt, Function, Name, Path, diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs index 35dfaf3bad0e..4c89c8d38438 100644 --- a/crates/ra_hir/src/mock.rs +++ b/crates/ra_hir/src/mock.rs @@ -2,6 +2,7 @@ use std::{panic, sync::Arc}; +use hir_expand::diagnostics::DiagnosticSink; use parking_lot::Mutex; use ra_cfg::CfgOptions; use ra_db::{ @@ -12,7 +13,7 @@ use relative_path::{RelativePath, RelativePathBuf}; use rustc_hash::FxHashMap; use test_utils::{extract_offset, parse_fixture, CURSOR_MARKER}; -use crate::{db, debug::HirDebugHelper, diagnostics::DiagnosticSink}; +use crate::{db, debug::HirDebugHelper}; pub const WORKSPACE: SourceRootId = SourceRootId(0); diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index 7ba03182718c..32a6ab47495f 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs @@ -55,6 +55,7 @@ mod tests; use std::sync::Arc; use hir_def::{builtin_type::BuiltinType, CrateModuleId}; +use hir_expand::diagnostics::DiagnosticSink; use once_cell::sync::Lazy; use ra_arena::Arena; use ra_db::{Edition, FileId}; @@ -65,7 +66,6 @@ use test_utils::tested_by; use crate::{ db::{AstDatabase, DefDatabase}, - diagnostics::DiagnosticSink, ids::MacroDefId, nameres::diagnostics::DefDiagnostic, Adt, AstId, Crate, HirFileId, MacroDef, Module, ModuleDef, Name, Path, PathKind, Trait, @@ -513,12 +513,13 @@ impl CrateDefMap { } mod diagnostics { + use hir_expand::diagnostics::DiagnosticSink; use ra_syntax::{ast, AstPtr}; use relative_path::RelativePathBuf; use crate::{ db::{AstDatabase, DefDatabase}, - diagnostics::{DiagnosticSink, UnresolvedModule}, + diagnostics::UnresolvedModule, nameres::CrateModuleId, AstId, }; diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 6694467a36cb..2370e8d4f52f 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -25,7 +25,7 @@ use hir_def::{ path::known, type_ref::{Mutability, TypeRef}, }; -use hir_expand::name; +use hir_expand::{diagnostics::DiagnosticSink, name}; use ra_arena::map::ArenaMap; use ra_prof::profile; use test_utils::tested_by; @@ -40,7 +40,6 @@ use crate::{ adt::VariantDef, code_model::TypeAlias, db::HirDatabase, - diagnostics::DiagnosticSink, expr::{BindingAnnotation, Body, ExprId, PatId}, resolve::{Resolver, TypeNs}, ty::infer::diagnostics::InferenceDiagnostic, @@ -719,12 +718,9 @@ impl Expectation { } mod diagnostics { - use crate::{ - db::HirDatabase, - diagnostics::{DiagnosticSink, NoSuchField}, - expr::ExprId, - Function, HasSource, - }; + use hir_expand::diagnostics::DiagnosticSink; + + use crate::{db::HirDatabase, diagnostics::NoSuchField, expr::ExprId, Function, HasSource}; #[derive(Debug, PartialEq, Eq, Clone)] pub(super) enum InferenceDiagnostic { diff --git a/crates/ra_hir_expand/src/diagnostics.rs b/crates/ra_hir_expand/src/diagnostics.rs new file mode 100644 index 000000000000..201884b95745 --- /dev/null +++ b/crates/ra_hir_expand/src/diagnostics.rs @@ -0,0 +1,85 @@ +//! Semantic errors and warnings. +//! +//! The `Diagnostic` trait defines a trait object which can represent any +//! diagnostic. +//! +//! `DiagnosticSink` struct is used as an emitter for diagnostic. When creating +//! a `DiagnosticSink`, you supply a callback which can react to a `dyn +//! Diagnostic` or to any concrete diagnostic (downcasting is sued internally). +//! +//! Because diagnostics store file offsets, it's a bad idea to store them +//! directly in salsa. For this reason, every hir subsytem defines it's own +//! strongly-typed closed set of diagnostics which use hir ids internally, are +//! stored in salsa and do *not* implement the `Diagnostic` trait. Instead, a +//! subsystem provides a separate, non-query-based API which can walk all stored +//! values and transform them into instances of `Diagnostic`. + +use std::{any::Any, fmt}; + +use ra_syntax::{SyntaxNode, SyntaxNodePtr, TextRange}; + +use crate::{db::AstDatabase, Source}; + +pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static { + fn message(&self) -> String; + fn source(&self) -> Source; + fn highlight_range(&self) -> TextRange { + self.source().ast.range() + } + fn as_any(&self) -> &(dyn Any + Send + 'static); +} + +pub trait AstDiagnostic { + type AST; + fn ast(&self, db: &impl AstDatabase) -> Self::AST; +} + +impl dyn Diagnostic { + pub fn syntax_node(&self, db: &impl AstDatabase) -> SyntaxNode { + let node = db.parse_or_expand(self.source().file_id).unwrap(); + self.source().ast.to_node(&node) + } + + pub fn downcast_ref(&self) -> Option<&D> { + self.as_any().downcast_ref() + } +} + +pub struct DiagnosticSink<'a> { + callbacks: Vec Result<(), ()> + 'a>>, + default_callback: Box, +} + +impl<'a> DiagnosticSink<'a> { + /// FIXME: split `new` and `on` into a separate builder type + pub fn new(cb: impl FnMut(&dyn Diagnostic) + 'a) -> DiagnosticSink<'a> { + DiagnosticSink { callbacks: Vec::new(), default_callback: Box::new(cb) } + } + + pub fn on(mut self, mut cb: F) -> DiagnosticSink<'a> { + let cb = move |diag: &dyn Diagnostic| match diag.downcast_ref::() { + Some(d) => { + cb(d); + Ok(()) + } + None => Err(()), + }; + self.callbacks.push(Box::new(cb)); + self + } + + pub fn push(&mut self, d: impl Diagnostic) { + let d: &dyn Diagnostic = &d; + self._push(d); + } + + fn _push(&mut self, d: &dyn Diagnostic) { + for cb in self.callbacks.iter_mut() { + match cb(d) { + Ok(()) => return, + Err(()) => (), + } + } + (self.default_callback)(d) + } +} diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs index 85c2b22ace5a..dd07a16b4cad 100644 --- a/crates/ra_hir_expand/src/lib.rs +++ b/crates/ra_hir_expand/src/lib.rs @@ -9,6 +9,7 @@ pub mod ast_id_map; pub mod either; pub mod name; pub mod hygiene; +pub mod diagnostics; use std::hash::{Hash, Hasher}; From c7b7d7e6664ab677c392155b9a6aec37409f4bb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Sun, 3 Nov 2019 00:19:08 +0200 Subject: [PATCH 10/21] Silence some warnings --- crates/ra_tt/src/buffer.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/ra_tt/src/buffer.rs b/crates/ra_tt/src/buffer.rs index ef3f2323c98b..14b3f707df3b 100644 --- a/crates/ra_tt/src/buffer.rs +++ b/crates/ra_tt/src/buffer.rs @@ -111,7 +111,7 @@ impl<'a> Cursor<'a> { /// If the cursor is pointing at the end of a subtree, returns /// the parent subtree - pub fn end(self) -> Option<(&'a Subtree)> { + pub fn end(self) -> Option<&'a Subtree> { match self.entry() { Some(Entry::End(Some(ptr))) => { let idx = ptr.1; @@ -127,7 +127,7 @@ impl<'a> Cursor<'a> { } } - fn entry(self) -> Option<(&'a Entry<'a>)> { + fn entry(self) -> Option<&'a Entry<'a>> { self.buffer.entry(&self.ptr) } From ccf8817d181ab9430a00c38d96b481a07af701bb Mon Sep 17 00:00:00 2001 From: Martin Asquino Date: Sat, 2 Nov 2019 19:33:34 -0300 Subject: [PATCH 11/21] Use `bool` instead of `Option` and print it's value only when `true` --- .../ra_ide_api/src/completion/complete_dot.rs | 11 ----------- .../complete_macro_in_item_position.rs | 4 ---- .../src/completion/complete_path.rs | 17 ----------------- .../src/completion/complete_record_literal.rs | 4 ---- .../src/completion/complete_record_pattern.rs | 3 --- .../src/completion/complete_scope.rs | 19 ------------------- .../src/completion/completion_item.rs | 10 +++++----- .../ra_ide_api/src/completion/presentation.rs | 15 --------------- crates/ra_lsp_server/src/conv.rs | 2 +- 9 files changed, 6 insertions(+), 79 deletions(-) diff --git a/crates/ra_ide_api/src/completion/complete_dot.rs b/crates/ra_ide_api/src/completion/complete_dot.rs index 9c0abd59062b..b4df6ee2ad04 100644 --- a/crates/ra_ide_api/src/completion/complete_dot.rs +++ b/crates/ra_ide_api/src/completion/complete_dot.rs @@ -96,7 +96,6 @@ mod tests { ⋮ insert: "the_field", ⋮ kind: Field, ⋮ detail: "u32", - ⋮ deprecated: false, ⋮ }, ⋮] "### @@ -129,7 +128,6 @@ mod tests { kind: Method, lookup: "foo", detail: "fn foo(self)", - deprecated: false, }, CompletionItem { label: "the_field", @@ -141,7 +139,6 @@ mod tests { documentation: Documentation( "This is the_field", ), - deprecated: false, }, ] "### @@ -171,7 +168,6 @@ mod tests { kind: Method, lookup: "foo", detail: "fn foo(&self)", - deprecated: false, }, CompletionItem { label: "the_field", @@ -180,7 +176,6 @@ mod tests { insert: "the_field", kind: Field, detail: "(u32, i32)", - deprecated: false, }, ] "### @@ -226,7 +221,6 @@ mod tests { kind: Method, lookup: "the_method", detail: "fn the_method(&self)", - deprecated: false, }, ] "### @@ -256,7 +250,6 @@ mod tests { kind: Method, lookup: "the_method", detail: "fn the_method(&self)", - deprecated: false, }, ] "### @@ -286,7 +279,6 @@ mod tests { kind: Method, lookup: "the_method", detail: "fn the_method(&self)", - deprecated: false, }, ] "### @@ -339,7 +331,6 @@ mod tests { kind: Method, lookup: "the_method", detail: "fn the_method(&self)", - deprecated: false, }, ] "### @@ -410,7 +401,6 @@ mod tests { kind: Method, lookup: "blah", detail: "pub fn blah(&self)", - deprecated: false, }, ] "### @@ -437,7 +427,6 @@ mod tests { ⋮ insert: "the_field", ⋮ kind: Field, ⋮ detail: "u32", - ⋮ deprecated: false, ⋮ }, ⋮] "### diff --git a/crates/ra_ide_api/src/completion/complete_macro_in_item_position.rs b/crates/ra_ide_api/src/completion/complete_macro_in_item_position.rs index a082a3c7c9b9..09f743c660cb 100644 --- a/crates/ra_ide_api/src/completion/complete_macro_in_item_position.rs +++ b/crates/ra_ide_api/src/completion/complete_macro_in_item_position.rs @@ -45,7 +45,6 @@ mod tests { insert: "foo!($0)", kind: Macro, detail: "macro_rules! foo", - deprecated: false, }, ]"## ); @@ -87,7 +86,6 @@ mod tests { documentation: Documentation( "Creates a [`Vec`] containing the arguments.\n\n- Create a [`Vec`] containing a given list of elements:\n\n```\nlet v = vec![1, 2, 3];\nassert_eq!(v[0], 1);\nassert_eq!(v[1], 2);\nassert_eq!(v[2], 3);\n```", ), - deprecated: false, }, ]"## ); @@ -123,7 +121,6 @@ mod tests { documentation: Documentation( "Foo\n\nNot call `fooo!()` `fooo!()`, or `_foo![]` `_foo![]`.\nCall as `let _=foo! { hello world };`", ), - deprecated: false, }, CompletionItem { label: "main()", @@ -133,7 +130,6 @@ mod tests { kind: Function, lookup: "main", detail: "fn main()", - deprecated: false, }, ] "### diff --git a/crates/ra_ide_api/src/completion/complete_path.rs b/crates/ra_ide_api/src/completion/complete_path.rs index 2c9c8645b97b..9ac9768afb20 100644 --- a/crates/ra_ide_api/src/completion/complete_path.rs +++ b/crates/ra_ide_api/src/completion/complete_path.rs @@ -308,7 +308,6 @@ mod tests { documentation: Documentation( "Bar Variant with i32", ), - deprecated: false, }, CompletionItem { label: "Foo", @@ -320,7 +319,6 @@ mod tests { documentation: Documentation( "Foo Variant", ), - deprecated: false, }, ]"### ); @@ -356,7 +354,6 @@ mod tests { documentation: Documentation( "Bar Variant with i32 and u32", ), - deprecated: false, }, CompletionItem { label: "Foo", @@ -368,7 +365,6 @@ mod tests { documentation: Documentation( "Foo Variant (empty)", ), - deprecated: false, }, CompletionItem { label: "S", @@ -380,7 +376,6 @@ mod tests { documentation: Documentation( "", ), - deprecated: false, }, ]"### ); @@ -416,7 +411,6 @@ mod tests { documentation: Documentation( "An associated method", ), - deprecated: false, }, ] "### @@ -451,7 +445,6 @@ mod tests { documentation: Documentation( "An associated const", ), - deprecated: false, }, ]"### ); @@ -485,7 +478,6 @@ mod tests { documentation: Documentation( "An associated type", ), - deprecated: false, }, ]"### ); @@ -521,7 +513,6 @@ mod tests { documentation: Documentation( "An associated method", ), - deprecated: false, }, ] "### @@ -558,7 +549,6 @@ mod tests { documentation: Documentation( "An associated method", ), - deprecated: false, }, ] "### @@ -618,7 +608,6 @@ mod tests { documentation: Documentation( "A trait method", ), - deprecated: false, }, ] "### @@ -655,7 +644,6 @@ mod tests { documentation: Documentation( "A trait method", ), - deprecated: false, }, ] "### @@ -692,7 +680,6 @@ mod tests { documentation: Documentation( "A trait method", ), - deprecated: false, }, ] "### @@ -724,7 +711,6 @@ mod tests { kind: Function, lookup: "bar", detail: "fn bar()", - deprecated: false, }, CompletionItem { label: "foo()", @@ -734,7 +720,6 @@ mod tests { kind: Function, lookup: "foo", detail: "fn foo()", - deprecated: false, }, ] "### @@ -765,7 +750,6 @@ mod tests { insert: "foo!($0)", kind: Macro, detail: "#[macro_export]\nmacro_rules! foo", - deprecated: false, }, CompletionItem { label: "main()", @@ -775,7 +759,6 @@ mod tests { kind: Function, lookup: "main", detail: "fn main()", - deprecated: false, }, ] "### diff --git a/crates/ra_ide_api/src/completion/complete_record_literal.rs b/crates/ra_ide_api/src/completion/complete_record_literal.rs index 33bea411f798..0295b8101373 100644 --- a/crates/ra_ide_api/src/completion/complete_record_literal.rs +++ b/crates/ra_ide_api/src/completion/complete_record_literal.rs @@ -78,7 +78,6 @@ mod tests { ⋮ insert: "the_field", ⋮ kind: Field, ⋮ detail: "u32", - ⋮ deprecated: false, ⋮ }, ⋮] "###); @@ -105,7 +104,6 @@ mod tests { ⋮ insert: "a", ⋮ kind: Field, ⋮ detail: "u32", - ⋮ deprecated: false, ⋮ }, ⋮] "###); @@ -132,7 +130,6 @@ mod tests { ⋮ insert: "b", ⋮ kind: Field, ⋮ detail: "u32", - ⋮ deprecated: false, ⋮ }, ⋮] "###); @@ -158,7 +155,6 @@ mod tests { ⋮ insert: "a", ⋮ kind: Field, ⋮ detail: "u32", - ⋮ deprecated: false, ⋮ }, ⋮] "###); diff --git a/crates/ra_ide_api/src/completion/complete_record_pattern.rs b/crates/ra_ide_api/src/completion/complete_record_pattern.rs index 93c26f2297f9..d20fa796c7f8 100644 --- a/crates/ra_ide_api/src/completion/complete_record_pattern.rs +++ b/crates/ra_ide_api/src/completion/complete_record_pattern.rs @@ -52,7 +52,6 @@ mod tests { ⋮ insert: "foo", ⋮ kind: Field, ⋮ detail: "u32", - ⋮ deprecated: false, ⋮ }, ⋮] "###); @@ -82,7 +81,6 @@ mod tests { ⋮ insert: "bar", ⋮ kind: Field, ⋮ detail: "()", - ⋮ deprecated: false, ⋮ }, ⋮ CompletionItem { ⋮ label: "foo", @@ -91,7 +89,6 @@ mod tests { ⋮ insert: "foo", ⋮ kind: Field, ⋮ detail: "u32", - ⋮ deprecated: false, ⋮ }, ⋮] "###); diff --git a/crates/ra_ide_api/src/completion/complete_scope.rs b/crates/ra_ide_api/src/completion/complete_scope.rs index 9d2deee75fdc..4e56de3f5424 100644 --- a/crates/ra_ide_api/src/completion/complete_scope.rs +++ b/crates/ra_ide_api/src/completion/complete_scope.rs @@ -155,7 +155,6 @@ mod tests { kind: Function, lookup: "quux", detail: "fn quux(x: i32)", - deprecated: false, }, CompletionItem { label: "x", @@ -219,7 +218,6 @@ mod tests { kind: Function, lookup: "quux", detail: "fn quux()", - deprecated: false, }, ] "### @@ -248,7 +246,6 @@ mod tests { kind: Function, lookup: "quux", detail: "fn quux()", - deprecated: false, }, CompletionItem { label: "x", @@ -289,7 +286,6 @@ mod tests { kind: Function, lookup: "quux", detail: "fn quux()", - deprecated: false, }, ] "### @@ -395,7 +391,6 @@ mod tests { kind: Function, lookup: "quux", detail: "fn quux()", - deprecated: false, }, ] "### @@ -455,7 +450,6 @@ mod tests { kind: Function, lookup: "quux", detail: "fn quux()", - deprecated: false, }, ] "### @@ -488,7 +482,6 @@ mod tests { kind: Function, lookup: "x", detail: "fn x()", - deprecated: false, }, ] "### @@ -527,7 +520,6 @@ mod tests { kind: Function, lookup: "foo", detail: "fn foo()", - deprecated: false, }, ] "### @@ -592,7 +584,6 @@ mod tests { kind: Function, lookup: "foo", detail: "fn foo()", - deprecated: false, }, CompletionItem { label: "std", @@ -648,7 +639,6 @@ mod tests { insert: "bar!($0)", kind: Macro, detail: "macro_rules! bar", - deprecated: false, }, CompletionItem { label: "baz!", @@ -657,7 +647,6 @@ mod tests { insert: "baz!($0)", kind: Macro, detail: "#[macro_export]\nmacro_rules! baz", - deprecated: false, }, CompletionItem { label: "foo!", @@ -666,7 +655,6 @@ mod tests { insert: "foo!($0)", kind: Macro, detail: "macro_rules! foo", - deprecated: false, }, CompletionItem { label: "m1", @@ -690,7 +678,6 @@ mod tests { kind: Function, lookup: "main", detail: "fn main()", - deprecated: false, }, ] "### @@ -721,7 +708,6 @@ mod tests { insert: "foo!($0)", kind: Macro, detail: "macro_rules! foo", - deprecated: false, }, CompletionItem { label: "foo()", @@ -731,7 +717,6 @@ mod tests { kind: Function, lookup: "foo", detail: "fn foo()", - deprecated: false, }, ] "### @@ -762,7 +747,6 @@ mod tests { insert: "foo!($0)", kind: Macro, detail: "macro_rules! foo", - deprecated: false, }, CompletionItem { label: "main()", @@ -772,7 +756,6 @@ mod tests { kind: Function, lookup: "main", detail: "fn main()", - deprecated: false, }, ] "### @@ -803,7 +786,6 @@ mod tests { insert: "foo!($0)", kind: Macro, detail: "macro_rules! foo", - deprecated: false, }, CompletionItem { label: "main()", @@ -813,7 +795,6 @@ mod tests { kind: Function, lookup: "main", detail: "fn main()", - deprecated: false, }, ] "### diff --git a/crates/ra_ide_api/src/completion/completion_item.rs b/crates/ra_ide_api/src/completion/completion_item.rs index 6753672ca4c0..93f336370915 100644 --- a/crates/ra_ide_api/src/completion/completion_item.rs +++ b/crates/ra_ide_api/src/completion/completion_item.rs @@ -46,7 +46,7 @@ pub struct CompletionItem { documentation: Option, /// Whether this item is marked as deprecated - deprecated: Option, + deprecated: bool, } // We use custom debug for CompletionItem to make `insta`'s diffs more readable. @@ -73,8 +73,8 @@ impl fmt::Debug for CompletionItem { if let Some(documentation) = self.documentation() { s.field("documentation", &documentation); } - if let Some(deprecated) = self.deprecated { - s.field("deprecated", &deprecated); + if self.deprecated { + s.field("deprecated", &true); } s.finish() } @@ -174,7 +174,7 @@ impl CompletionItem { self.kind } - pub fn deprecated(&self) -> Option { + pub fn deprecated(&self) -> bool { self.deprecated } } @@ -220,7 +220,7 @@ impl Builder { lookup: self.lookup, kind: self.kind, completion_kind: self.completion_kind, - deprecated: self.deprecated, + deprecated: self.deprecated.unwrap_or(false), } } pub(crate) fn lookup_by(mut self, lookup: impl Into) -> Builder { diff --git a/crates/ra_ide_api/src/completion/presentation.rs b/crates/ra_ide_api/src/completion/presentation.rs index d98201887e51..cb55d18751b3 100644 --- a/crates/ra_ide_api/src/completion/presentation.rs +++ b/crates/ra_ide_api/src/completion/presentation.rs @@ -335,7 +335,6 @@ mod tests { kind: Function, lookup: "main", detail: "fn main()", - deprecated: false, }, CompletionItem { label: "something_deprecated()", @@ -382,7 +381,6 @@ mod tests { kind: Function, lookup: "main", detail: "fn main()", - deprecated: false, }, CompletionItem { label: "no_args()", @@ -392,7 +390,6 @@ mod tests { kind: Function, lookup: "no_args", detail: "fn no_args()", - deprecated: false, }, ] "### @@ -414,7 +411,6 @@ mod tests { kind: Function, lookup: "main", detail: "fn main()", - deprecated: false, }, CompletionItem { label: "with_args(…)", @@ -424,7 +420,6 @@ mod tests { kind: Function, lookup: "with_args", detail: "fn with_args(x: i32, y: String)", - deprecated: false, }, ] "### @@ -451,7 +446,6 @@ mod tests { kind: Method, lookup: "foo", detail: "fn foo(&self)", - deprecated: false, }, ] "### @@ -476,7 +470,6 @@ mod tests { insert: "foo", kind: Function, detail: "pub fn foo()", - deprecated: false, }, ]"# ); @@ -502,7 +495,6 @@ mod tests { insert: "frobnicate", kind: Function, detail: "fn frobnicate()", - deprecated: false, }, CompletionItem { label: "main", @@ -511,7 +503,6 @@ mod tests { insert: "main", kind: Function, detail: "fn main()", - deprecated: false, }, ]"# ); @@ -534,7 +525,6 @@ mod tests { insert: "new", kind: Function, detail: "fn new() -> Foo", - deprecated: false, }, ]"# ); @@ -568,7 +558,6 @@ mod tests { kind: Function, lookup: "foo", detail: "fn foo(xs: Ve)", - deprecated: false, }, ] "### @@ -598,7 +587,6 @@ mod tests { kind: Function, lookup: "foo", detail: "fn foo(xs: Ve)", - deprecated: false, }, ] "### @@ -627,7 +615,6 @@ mod tests { kind: Function, lookup: "foo", detail: "fn foo(xs: Ve)", - deprecated: false, }, ] "### @@ -656,7 +643,6 @@ mod tests { kind: Function, lookup: "foo", detail: "fn foo(xs: Ve)", - deprecated: false, }, ] "### @@ -687,7 +673,6 @@ mod tests { insert: "frobnicate", kind: Macro, detail: "#[macro_export]\nmacro_rules! frobnicate", - deprecated: false, }, ] "### diff --git a/crates/ra_lsp_server/src/conv.rs b/crates/ra_lsp_server/src/conv.rs index a4667d284556..94ed619faeca 100644 --- a/crates/ra_lsp_server/src/conv.rs +++ b/crates/ra_lsp_server/src/conv.rs @@ -127,7 +127,7 @@ impl ConvWith<(&LineIndex, LineEndings)> for CompletionItem { text_edit: Some(text_edit), additional_text_edits: Some(additional_text_edits), documentation: self.documentation().map(|it| it.conv()), - deprecated: self.deprecated(), + deprecated: Some(self.deprecated()), ..Default::default() }; res.insert_text_format = Some(match self.insert_text_format() { From c26fb1abb348ad9b27e8e9327402e6963760d929 Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Sun, 3 Nov 2019 11:45:05 +0800 Subject: [PATCH 12/21] Fix snapshots line-ending in windows --- .gitattributes | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitattributes b/.gitattributes index a77342d72447..183e9b521184 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,2 @@ -crates/ra_syntax/tests/data/** -text +crates/ra_syntax/test_data/** -text eof=LF +crates/ra_ide_api/src/snapshots/** -text eof=LF From ba2efca2bbe5f4434f9a2522b2b94df873f3563b Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Thu, 31 Oct 2019 18:45:10 +0300 Subject: [PATCH 13/21] Move CrateDefMap to hir_def --- crates/ra_hir/src/code_model.rs | 37 +- crates/ra_hir/src/code_model/src.rs | 4 +- crates/ra_hir/src/db.rs | 9 +- crates/ra_hir/src/diagnostics.rs | 21 +- crates/ra_hir/src/from_id.rs | 58 ++ crates/ra_hir/src/from_source.rs | 22 +- crates/ra_hir/src/lib.rs | 1 + crates/ra_hir/src/nameres.rs | 508 +----------------- crates/ra_hir/src/nameres/tests.rs | 21 +- crates/ra_hir/src/nameres/tests/globs.rs | 4 +- .../ra_hir/src/nameres/tests/incremental.rs | 7 +- crates/ra_hir/src/nameres/tests/macros.rs | 10 +- crates/ra_hir/src/resolve.rs | 104 ++-- crates/ra_hir/src/source_binder.rs | 7 +- crates/ra_hir/src/ty/tests.rs | 2 +- crates/ra_hir_def/src/adt.rs | 14 +- crates/ra_hir_def/src/db.rs | 15 +- crates/ra_hir_def/src/diagnostics.rs | 26 + crates/ra_hir_def/src/lib.rs | 5 +- crates/ra_hir_def/src/nameres.rs | 488 +++++++++++++++++ .../src/nameres/collector.rs | 160 +++--- .../src/nameres/per_ns.rs | 24 +- .../src/completion/complete_path.rs | 8 +- 23 files changed, 824 insertions(+), 731 deletions(-) create mode 100644 crates/ra_hir/src/from_id.rs create mode 100644 crates/ra_hir_def/src/diagnostics.rs rename crates/{ra_hir => ra_hir_def}/src/nameres/collector.rs (86%) rename crates/{ra_hir => ra_hir_def}/src/nameres/per_ns.rs (75%) diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 5b78bdfef389..f03b59217fe0 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs @@ -9,7 +9,7 @@ use hir_def::{ adt::VariantData, builtin_type::BuiltinType, type_ref::{Mutability, TypeRef}, - CrateModuleId, LocalEnumVariantId, LocalStructFieldId, ModuleId, + CrateModuleId, LocalEnumVariantId, LocalStructFieldId, ModuleId, UnionId, }; use hir_expand::{ diagnostics::DiagnosticSink, @@ -28,11 +28,11 @@ use crate::{ TypeAliasId, }, impl_block::ImplBlock, - nameres::{ImportId, ModuleScope, Namespace}, + nameres::{ImportId, Namespace}, resolve::{Resolver, Scope, TypeNs}, traits::TraitData, ty::{InferenceResult, TraitRef}, - Either, HasSource, Name, Ty, + Either, HasSource, Name, ScopeDef, Ty, }; /// hir::Crate describes a single crate. It's the main interface with which @@ -66,7 +66,7 @@ impl Crate { } pub fn root_module(self, db: &impl DefDatabase) -> Option { - let module_id = db.crate_def_map(self).root(); + let module_id = db.crate_def_map(self.crate_id).root(); Some(Module::new(self, module_id)) } @@ -120,7 +120,7 @@ impl Module { /// Name of this module. pub fn name(self, db: &impl DefDatabase) -> Option { - let def_map = db.crate_def_map(self.krate()); + let def_map = db.crate_def_map(self.id.krate); let parent = def_map[self.id.module_id].parent?; def_map[parent].children.iter().find_map(|(name, module_id)| { if *module_id == self.id.module_id { @@ -151,20 +151,20 @@ impl Module { /// might be missing `krate`. This can happen if a module's file is not included /// in the module tree of any target in `Cargo.toml`. pub fn crate_root(self, db: &impl DefDatabase) -> Module { - let def_map = db.crate_def_map(self.krate()); + let def_map = db.crate_def_map(self.id.krate); self.with_module_id(def_map.root()) } /// Finds a child module with the specified name. pub fn child(self, db: &impl HirDatabase, name: &Name) -> Option { - let def_map = db.crate_def_map(self.krate()); + let def_map = db.crate_def_map(self.id.krate); let child_id = def_map[self.id.module_id].children.get(name)?; Some(self.with_module_id(*child_id)) } /// Iterates over all child modules. pub fn children(self, db: &impl DefDatabase) -> impl Iterator { - let def_map = db.crate_def_map(self.krate()); + let def_map = db.crate_def_map(self.id.krate); let children = def_map[self.id.module_id] .children .iter() @@ -175,7 +175,7 @@ impl Module { /// Finds a parent module. pub fn parent(self, db: &impl DefDatabase) -> Option { - let def_map = db.crate_def_map(self.krate()); + let def_map = db.crate_def_map(self.id.krate); let parent_id = def_map[self.id.module_id].parent?; Some(self.with_module_id(parent_id)) } @@ -191,12 +191,16 @@ impl Module { } /// Returns a `ModuleScope`: a set of items, visible in this module. - pub fn scope(self, db: &impl HirDatabase) -> ModuleScope { - db.crate_def_map(self.krate())[self.id.module_id].scope.clone() + pub fn scope(self, db: &impl HirDatabase) -> Vec<(Name, ScopeDef, Option)> { + db.crate_def_map(self.id.krate)[self.id.module_id] + .scope + .entries() + .map(|(name, res)| (name.clone(), res.def.into(), res.import)) + .collect() } pub fn diagnostics(self, db: &impl HirDatabase, sink: &mut DiagnosticSink) { - db.crate_def_map(self.krate()).add_diagnostics(db, self.id.module_id, sink); + db.crate_def_map(self.id.krate).add_diagnostics(db, self.id.module_id, sink); for decl in self.declarations(db) { match decl { crate::ModuleDef::Function(f) => f.diagnostics(db, sink), @@ -220,12 +224,12 @@ impl Module { } pub(crate) fn resolver(self, db: &impl DefDatabase) -> Resolver { - let def_map = db.crate_def_map(self.krate()); + let def_map = db.crate_def_map(self.id.krate); Resolver::default().push_module_scope(def_map, self.id.module_id) } pub fn declarations(self, db: &impl DefDatabase) -> Vec { - let def_map = db.crate_def_map(self.krate()); + let def_map = db.crate_def_map(self.id.krate); def_map[self.id.module_id] .scope .entries() @@ -233,6 +237,7 @@ impl Module { .flat_map(|per_ns| { per_ns.take_types().into_iter().chain(per_ns.take_values().into_iter()) }) + .map(ModuleDef::from) .collect() } @@ -336,12 +341,12 @@ impl Struct { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Union { - pub(crate) id: StructId, + pub(crate) id: UnionId, } impl Union { pub fn name(self, db: &impl DefDatabase) -> Option { - db.struct_data(self.id).name.clone() + db.union_data(self.id).name.clone() } pub fn module(self, db: &impl HirDatabase) -> Module { diff --git a/crates/ra_hir/src/code_model/src.rs b/crates/ra_hir/src/code_model/src.rs index bd0c3c226aa4..6d116ee75c90 100644 --- a/crates/ra_hir/src/code_model/src.rs +++ b/crates/ra_hir/src/code_model/src.rs @@ -22,7 +22,7 @@ pub trait HasSource { impl Module { /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items. pub fn definition_source(self, db: &(impl DefDatabase + AstDatabase)) -> Source { - let def_map = db.crate_def_map(self.krate()); + let def_map = db.crate_def_map(self.id.krate); let decl_id = def_map[self.id.module_id].declaration; let file_id = def_map[self.id.module_id].definition; let ast = ModuleSource::new(db, file_id, decl_id); @@ -36,7 +36,7 @@ impl Module { self, db: &(impl DefDatabase + AstDatabase), ) -> Option> { - let def_map = db.crate_def_map(self.krate()); + let def_map = db.crate_def_map(self.id.krate); let decl = def_map[self.id.module_id].declaration?; let ast = decl.to_node(db); Some(Source { file_id: decl.file_id(), ast }) diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index 89ca4e39f0af..f45804c7ce90 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs @@ -11,7 +11,7 @@ use crate::{ ids, impl_block::{ImplBlock, ImplSourceMap, ModuleImplBlocks}, lang_item::{LangItemTarget, LangItems}, - nameres::{CrateDefMap, Namespace}, + nameres::Namespace, traits::TraitData, ty::{ method_resolution::CrateImplBlocks, traits::Impl, CallableDef, FnSig, GenericPredicate, @@ -23,8 +23,8 @@ use crate::{ }; pub use hir_def::db::{ - DefDatabase2, DefDatabase2Storage, EnumDataQuery, InternDatabase, InternDatabaseStorage, - RawItemsQuery, RawItemsWithSourceMapQuery, StructDataQuery, + CrateDefMapQuery, DefDatabase2, DefDatabase2Storage, EnumDataQuery, InternDatabase, + InternDatabaseStorage, RawItemsQuery, RawItemsWithSourceMapQuery, StructDataQuery, }; pub use hir_expand::db::{ AstDatabase, AstDatabaseStorage, AstIdMapQuery, MacroArgQuery, MacroDefQuery, MacroExpandQuery, @@ -41,9 +41,6 @@ pub trait DefDatabase: HirDebugDatabase + DefDatabase2 { #[salsa::invoke(crate::traits::TraitItemsIndex::trait_items_index)] fn trait_items_index(&self, module: Module) -> crate::traits::TraitItemsIndex; - #[salsa::invoke(CrateDefMap::crate_def_map_query)] - fn crate_def_map(&self, krate: Crate) -> Arc; - #[salsa::invoke(ModuleImplBlocks::impls_in_module_with_source_map_query)] fn impls_in_module_with_source_map( &self, diff --git a/crates/ra_hir/src/diagnostics.rs b/crates/ra_hir/src/diagnostics.rs index a33af8f46753..1751e7be33a2 100644 --- a/crates/ra_hir/src/diagnostics.rs +++ b/crates/ra_hir/src/diagnostics.rs @@ -3,10 +3,10 @@ use std::any::Any; use ra_syntax::{ast, AstNode, AstPtr, SyntaxNodePtr}; -use relative_path::RelativePathBuf; use crate::{db::AstDatabase, HirFileId, Name, Source}; +pub use hir_def::diagnostics::UnresolvedModule; pub use hir_expand::diagnostics::{AstDiagnostic, Diagnostic, DiagnosticSink}; #[derive(Debug)] @@ -29,25 +29,6 @@ impl Diagnostic for NoSuchField { } } -#[derive(Debug)] -pub struct UnresolvedModule { - pub file: HirFileId, - pub decl: AstPtr, - pub candidate: RelativePathBuf, -} - -impl Diagnostic for UnresolvedModule { - fn message(&self) -> String { - "unresolved module".to_string() - } - fn source(&self) -> Source { - Source { file_id: self.file, ast: self.decl.into() } - } - fn as_any(&self) -> &(dyn Any + Send + 'static) { - self - } -} - #[derive(Debug)] pub struct MissingFields { pub file: HirFileId, diff --git a/crates/ra_hir/src/from_id.rs b/crates/ra_hir/src/from_id.rs new file mode 100644 index 000000000000..c08203bca7ea --- /dev/null +++ b/crates/ra_hir/src/from_id.rs @@ -0,0 +1,58 @@ +use hir_def::{AdtId, EnumVariantId, ModuleDefId}; + +use crate::{Adt, EnumVariant, ModuleDef}; + +macro_rules! from_id { + ($(($id:path, $ty:path)),*) => {$( + impl From<$id> for $ty { + fn from(id: $id) -> $ty { + $ty { id } + } + } + )*} +} + +from_id![ + (hir_def::ModuleId, crate::Module), + (hir_def::StructId, crate::Struct), + (hir_def::UnionId, crate::Union), + (hir_def::EnumId, crate::Enum), + (hir_def::TypeAliasId, crate::TypeAlias), + (hir_def::TraitId, crate::Trait), + (hir_def::StaticId, crate::Static), + (hir_def::ConstId, crate::Const), + (hir_def::FunctionId, crate::Function), + (hir_expand::MacroDefId, crate::MacroDef) +]; + +impl From for Adt { + fn from(id: AdtId) -> Self { + match id { + AdtId::StructId(it) => Adt::Struct(it.into()), + AdtId::UnionId(it) => Adt::Union(it.into()), + AdtId::EnumId(it) => Adt::Enum(it.into()), + } + } +} + +impl From for EnumVariant { + fn from(id: EnumVariantId) -> Self { + EnumVariant { parent: id.parent.into(), id: id.local_id } + } +} + +impl From for ModuleDef { + fn from(id: ModuleDefId) -> Self { + match id { + ModuleDefId::ModuleId(it) => ModuleDef::Module(it.into()), + ModuleDefId::FunctionId(it) => ModuleDef::Function(it.into()), + ModuleDefId::AdtId(it) => ModuleDef::Adt(it.into()), + ModuleDefId::EnumVariantId(it) => ModuleDef::EnumVariant(it.into()), + ModuleDefId::ConstId(it) => ModuleDef::Const(it.into()), + ModuleDefId::StaticId(it) => ModuleDef::Static(it.into()), + ModuleDefId::TraitId(it) => ModuleDef::Trait(it.into()), + ModuleDefId::TypeAliasId(it) => ModuleDef::TypeAlias(it.into()), + ModuleDefId::BuiltinType(it) => ModuleDef::BuiltinType(it), + } + } +} diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs index a9de0145538b..9899bdbbce26 100644 --- a/crates/ra_hir/src/from_source.rs +++ b/crates/ra_hir/src/from_source.rs @@ -149,14 +149,20 @@ impl Module { ModuleSource::SourceFile(_) => None, }; - db.relevant_crates(src.file_id.original_file(db)) - .iter() - .map(|&crate_id| Crate { crate_id }) - .find_map(|krate| { - let def_map = db.crate_def_map(krate); - let module_id = def_map.find_module_by_source(src.file_id, decl_id)?; - Some(Module::new(krate, module_id)) - }) + db.relevant_crates(src.file_id.original_file(db)).iter().find_map(|&crate_id| { + let def_map = db.crate_def_map(crate_id); + + let (module_id, _module_data) = + def_map.modules.iter().find(|(_module_id, module_data)| { + if decl_id.is_some() { + module_data.declaration == decl_id + } else { + module_data.definition.map(|it| it.into()) == Some(src.file_id) + } + })?; + + Some(Module::new(Crate { crate_id }, module_id)) + }) } } diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 0ba17e5710d3..52bad22284b9 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs @@ -47,6 +47,7 @@ mod resolve; pub mod diagnostics; mod util; +mod from_id; mod code_model; pub mod from_source; diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index 32a6ab47495f..bb775cfc9d22 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs @@ -47,512 +47,10 @@ //! path and, upon success, we run macro expansion and "collect module" phase //! on the result -mod per_ns; -mod collector; #[cfg(test)] mod tests; -use std::sync::Arc; - -use hir_def::{builtin_type::BuiltinType, CrateModuleId}; -use hir_expand::diagnostics::DiagnosticSink; -use once_cell::sync::Lazy; -use ra_arena::Arena; -use ra_db::{Edition, FileId}; -use ra_prof::profile; -use ra_syntax::ast; -use rustc_hash::{FxHashMap, FxHashSet}; -use test_utils::tested_by; - -use crate::{ - db::{AstDatabase, DefDatabase}, - ids::MacroDefId, - nameres::diagnostics::DefDiagnostic, - Adt, AstId, Crate, HirFileId, MacroDef, Module, ModuleDef, Name, Path, PathKind, Trait, +pub use hir_def::nameres::{ + per_ns::{Namespace, PerNs}, + raw::ImportId, }; - -pub use self::per_ns::{Namespace, PerNs}; - -pub use hir_def::nameres::raw::ImportId; - -/// Contains all top-level defs from a macro-expanded crate -#[derive(Debug, PartialEq, Eq)] -pub struct CrateDefMap { - krate: Crate, - edition: Edition, - /// The prelude module for this crate. This either comes from an import - /// marked with the `prelude_import` attribute, or (in the normal case) from - /// a dependency (`std` or `core`). - prelude: Option, - extern_prelude: FxHashMap, - root: CrateModuleId, - modules: Arena, - - /// Some macros are not well-behavior, which leads to infinite loop - /// e.g. macro_rules! foo { ($ty:ty) => { foo!($ty); } } - /// We mark it down and skip it in collector - /// - /// FIXME: - /// Right now it only handle a poison macro in a single crate, - /// such that if other crate try to call that macro, - /// the whole process will do again until it became poisoned in that crate. - /// We should handle this macro set globally - /// However, do we want to put it as a global variable? - poison_macros: FxHashSet, - - diagnostics: Vec, -} - -impl std::ops::Index for CrateDefMap { - type Output = ModuleData; - fn index(&self, id: CrateModuleId) -> &ModuleData { - &self.modules[id] - } -} - -#[derive(Default, Debug, PartialEq, Eq)] -pub struct ModuleData { - pub(crate) parent: Option, - pub(crate) children: FxHashMap, - pub(crate) scope: ModuleScope, - /// None for root - pub(crate) declaration: Option>, - /// None for inline modules. - /// - /// Note that non-inline modules, by definition, live inside non-macro file. - pub(crate) definition: Option, -} - -#[derive(Debug, Default, PartialEq, Eq, Clone)] -pub struct ModuleScope { - items: FxHashMap, - /// Macros visable in current module in legacy textual scope - /// - /// For macros invoked by an unquatified identifier like `bar!()`, `legacy_macros` will be searched in first. - /// If it yields no result, then it turns to module scoped `macros`. - /// It macros with name quatified with a path like `crate::foo::bar!()`, `legacy_macros` will be skipped, - /// and only normal scoped `macros` will be searched in. - /// - /// Note that this automatically inherit macros defined textually before the definition of module itself. - /// - /// Module scoped macros will be inserted into `items` instead of here. - // FIXME: Macro shadowing in one module is not properly handled. Non-item place macros will - // be all resolved to the last one defined if shadowing happens. - legacy_macros: FxHashMap, -} - -static BUILTIN_SCOPE: Lazy> = Lazy::new(|| { - BuiltinType::ALL - .iter() - .map(|(name, ty)| { - (name.clone(), Resolution { def: PerNs::types(ty.clone().into()), import: None }) - }) - .collect() -}); - -/// Legacy macros can only be accessed through special methods like `get_legacy_macros`. -/// Other methods will only resolve values, types and module scoped macros only. -impl ModuleScope { - pub fn entries<'a>(&'a self) -> impl Iterator + 'a { - //FIXME: shadowing - self.items.iter().chain(BUILTIN_SCOPE.iter()) - } - - /// Iterate over all module scoped macros - pub fn macros<'a>(&'a self) -> impl Iterator + 'a { - self.items - .iter() - .filter_map(|(name, res)| res.def.get_macros().map(|macro_| (name, macro_))) - } - - /// Iterate over all legacy textual scoped macros visable at the end of the module - pub fn legacy_macros<'a>(&'a self) -> impl Iterator + 'a { - self.legacy_macros.iter().map(|(name, def)| (name, *def)) - } - - /// Get a name from current module scope, legacy macros are not included - pub fn get(&self, name: &Name) -> Option<&Resolution> { - self.items.get(name).or_else(|| BUILTIN_SCOPE.get(name)) - } - - pub fn traits<'a>(&'a self) -> impl Iterator + 'a { - self.items.values().filter_map(|r| match r.def.take_types() { - Some(ModuleDef::Trait(t)) => Some(t), - _ => None, - }) - } - - fn get_legacy_macro(&self, name: &Name) -> Option { - self.legacy_macros.get(name).copied() - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Default)] -pub struct Resolution { - /// None for unresolved - pub def: PerNs, - /// ident by which this is imported into local scope. - pub import: Option, -} - -impl Resolution { - pub(crate) fn from_macro(macro_: MacroDef) -> Self { - Resolution { def: PerNs::macros(macro_), import: None } - } -} - -#[derive(Debug, Clone)] -struct ResolvePathResult { - resolved_def: PerNs, - segment_index: Option, - reached_fixedpoint: ReachedFixedPoint, -} - -impl ResolvePathResult { - fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult { - ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None) - } - - fn with( - resolved_def: PerNs, - reached_fixedpoint: ReachedFixedPoint, - segment_index: Option, - ) -> ResolvePathResult { - ResolvePathResult { resolved_def, reached_fixedpoint, segment_index } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -enum ResolveMode { - Import, - Other, -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -enum ReachedFixedPoint { - Yes, - No, -} - -impl CrateDefMap { - pub(crate) fn crate_def_map_query( - // Note that this doesn't have `+ AstDatabase`! - // This gurantess that `CrateDefMap` is stable across reparses. - db: &impl DefDatabase, - krate: Crate, - ) -> Arc { - let _p = profile("crate_def_map_query"); - let def_map = { - let edition = krate.edition(db); - let mut modules: Arena = Arena::default(); - let root = modules.alloc(ModuleData::default()); - CrateDefMap { - krate, - edition, - extern_prelude: FxHashMap::default(), - prelude: None, - root, - modules, - poison_macros: FxHashSet::default(), - diagnostics: Vec::new(), - } - }; - let def_map = collector::collect_defs(db, def_map); - Arc::new(def_map) - } - - pub(crate) fn krate(&self) -> Crate { - self.krate - } - - pub(crate) fn root(&self) -> CrateModuleId { - self.root - } - - pub(crate) fn prelude(&self) -> Option { - self.prelude - } - - pub(crate) fn extern_prelude(&self) -> &FxHashMap { - &self.extern_prelude - } - - pub(crate) fn add_diagnostics( - &self, - db: &(impl DefDatabase + AstDatabase), - module: CrateModuleId, - sink: &mut DiagnosticSink, - ) { - self.diagnostics.iter().for_each(|it| it.add_to(db, module, sink)) - } - - pub(crate) fn find_module_by_source( - &self, - file_id: HirFileId, - decl_id: Option>, - ) -> Option { - let (module_id, _module_data) = self.modules.iter().find(|(_module_id, module_data)| { - if decl_id.is_some() { - module_data.declaration == decl_id - } else { - module_data.definition.map(|it| it.into()) == Some(file_id) - } - })?; - Some(module_id) - } - - pub(crate) fn resolve_path( - &self, - db: &impl DefDatabase, - original_module: CrateModuleId, - path: &Path, - ) -> (PerNs, Option) { - let res = self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path); - (res.resolved_def, res.segment_index) - } - - // Returns Yes if we are sure that additions to `ItemMap` wouldn't change - // the result. - fn resolve_path_fp_with_macro( - &self, - db: &impl DefDatabase, - mode: ResolveMode, - original_module: CrateModuleId, - path: &Path, - ) -> ResolvePathResult { - let mut segments = path.segments.iter().enumerate(); - let mut curr_per_ns: PerNs = match path.kind { - PathKind::DollarCrate(crate_id) => { - let krate = Crate { crate_id }; - if krate == self.krate { - tested_by!(macro_dollar_crate_self); - PerNs::types(Module::new(self.krate, self.root).into()) - } else { - match krate.root_module(db) { - Some(module) => { - tested_by!(macro_dollar_crate_other); - PerNs::types(module.into()) - } - None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), - } - } - } - PathKind::Crate => PerNs::types(Module::new(self.krate, self.root).into()), - PathKind::Self_ => PerNs::types(Module::new(self.krate, original_module).into()), - // plain import or absolute path in 2015: crate-relative with - // fallback to extern prelude (with the simplification in - // rust-lang/rust#57745) - // FIXME there must be a nicer way to write this condition - PathKind::Plain | PathKind::Abs - if self.edition == Edition::Edition2015 - && (path.kind == PathKind::Abs || mode == ResolveMode::Import) => - { - let segment = match segments.next() { - Some((_, segment)) => segment, - None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), - }; - log::debug!("resolving {:?} in crate root (+ extern prelude)", segment); - self.resolve_name_in_crate_root_or_extern_prelude(&segment.name) - } - PathKind::Plain => { - let segment = match segments.next() { - Some((_, segment)) => segment, - None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), - }; - log::debug!("resolving {:?} in module", segment); - self.resolve_name_in_module(db, original_module, &segment.name) - } - PathKind::Super => { - if let Some(p) = self.modules[original_module].parent { - PerNs::types(Module::new(self.krate, p).into()) - } else { - log::debug!("super path in root module"); - return ResolvePathResult::empty(ReachedFixedPoint::Yes); - } - } - PathKind::Abs => { - // 2018-style absolute path -- only extern prelude - let segment = match segments.next() { - Some((_, segment)) => segment, - None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), - }; - if let Some(def) = self.extern_prelude.get(&segment.name) { - log::debug!("absolute path {:?} resolved to crate {:?}", path, def); - PerNs::types(*def) - } else { - return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude - } - } - PathKind::Type(_) => { - // This is handled in `infer::infer_path_expr` - // The result returned here does not matter - return ResolvePathResult::empty(ReachedFixedPoint::Yes); - } - }; - - for (i, segment) in segments { - let curr = match curr_per_ns.take_types() { - Some(r) => r, - None => { - // we still have path segments left, but the path so far - // didn't resolve in the types namespace => no resolution - // (don't break here because `curr_per_ns` might contain - // something in the value namespace, and it would be wrong - // to return that) - return ResolvePathResult::empty(ReachedFixedPoint::No); - } - }; - // resolve segment in curr - - curr_per_ns = match curr { - ModuleDef::Module(module) => { - if module.krate() != self.krate { - let path = - Path { segments: path.segments[i..].to_vec(), kind: PathKind::Self_ }; - log::debug!("resolving {:?} in other crate", path); - let defp_map = db.crate_def_map(module.krate()); - let (def, s) = defp_map.resolve_path(db, module.id.module_id, &path); - return ResolvePathResult::with( - def, - ReachedFixedPoint::Yes, - s.map(|s| s + i), - ); - } - - // Since it is a qualified path here, it should not contains legacy macros - match self[module.id.module_id].scope.get(&segment.name) { - Some(res) => res.def, - _ => { - log::debug!("path segment {:?} not found", segment.name); - return ResolvePathResult::empty(ReachedFixedPoint::No); - } - } - } - ModuleDef::Adt(Adt::Enum(e)) => { - // enum variant - tested_by!(can_import_enum_variant); - match e.variant(db, &segment.name) { - Some(variant) => PerNs::both(variant.into(), variant.into()), - None => { - return ResolvePathResult::with( - PerNs::types(e.into()), - ReachedFixedPoint::Yes, - Some(i), - ); - } - } - } - s => { - // could be an inherent method call in UFCS form - // (`Struct::method`), or some other kind of associated item - log::debug!( - "path segment {:?} resolved to non-module {:?}, but is not last", - segment.name, - curr, - ); - - return ResolvePathResult::with( - PerNs::types(s), - ReachedFixedPoint::Yes, - Some(i), - ); - } - }; - } - ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None) - } - - fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> PerNs { - let from_crate_root = - self[self.root].scope.get(name).map_or_else(PerNs::none, |res| res.def); - let from_extern_prelude = self.resolve_name_in_extern_prelude(name); - - from_crate_root.or(from_extern_prelude) - } - - pub(crate) fn resolve_name_in_module( - &self, - db: &impl DefDatabase, - module: CrateModuleId, - name: &Name, - ) -> PerNs { - // Resolve in: - // - legacy scope of macro - // - current module / scope - // - extern prelude - // - std prelude - let from_legacy_macro = - self[module].scope.get_legacy_macro(name).map_or_else(PerNs::none, PerNs::macros); - let from_scope = self[module].scope.get(name).map_or_else(PerNs::none, |res| res.def); - let from_extern_prelude = - self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)); - let from_prelude = self.resolve_in_prelude(db, name); - - from_legacy_macro.or(from_scope).or(from_extern_prelude).or(from_prelude) - } - - fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs { - self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)) - } - - fn resolve_in_prelude(&self, db: &impl DefDatabase, name: &Name) -> PerNs { - if let Some(prelude) = self.prelude { - let keep; - let def_map = if prelude.krate() == self.krate { - self - } else { - // Extend lifetime - keep = db.crate_def_map(prelude.krate()); - &keep - }; - def_map[prelude.id.module_id].scope.get(name).map_or_else(PerNs::none, |res| res.def) - } else { - PerNs::none() - } - } -} - -mod diagnostics { - use hir_expand::diagnostics::DiagnosticSink; - use ra_syntax::{ast, AstPtr}; - use relative_path::RelativePathBuf; - - use crate::{ - db::{AstDatabase, DefDatabase}, - diagnostics::UnresolvedModule, - nameres::CrateModuleId, - AstId, - }; - - #[derive(Debug, PartialEq, Eq)] - pub(super) enum DefDiagnostic { - UnresolvedModule { - module: CrateModuleId, - declaration: AstId, - candidate: RelativePathBuf, - }, - } - - impl DefDiagnostic { - pub(super) fn add_to( - &self, - db: &(impl DefDatabase + AstDatabase), - target_module: CrateModuleId, - sink: &mut DiagnosticSink, - ) { - match self { - DefDiagnostic::UnresolvedModule { module, declaration, candidate } => { - if *module != target_module { - return; - } - let decl = declaration.to_node(db); - sink.push(UnresolvedModule { - file: declaration.file_id(), - decl: AstPtr::new(&decl), - candidate: candidate.clone(), - }) - } - } - } - } -} diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs index 8c6b40aaf2a0..02db91a86245 100644 --- a/crates/ra_hir/src/nameres/tests.rs +++ b/crates/ra_hir/src/nameres/tests.rs @@ -6,30 +6,25 @@ mod mod_resolution; use std::sync::Arc; +use hir_def::{db::DefDatabase2, nameres::*, CrateModuleId}; use insta::assert_snapshot; use ra_db::SourceDatabase; -use test_utils::covers; +// use test_utils::covers; -use crate::{ - mock::{CrateGraphFixture, MockDatabase}, - Crate, -}; - -use super::*; +use crate::mock::{CrateGraphFixture, MockDatabase}; fn compute_crate_def_map(fixture: &str, graph: Option) -> Arc { let mut db = MockDatabase::with_files(fixture); if let Some(graph) = graph { db.set_crate_graph_from_fixture(graph); } - let crate_id = db.crate_graph().iter().next().unwrap(); - let krate = Crate { crate_id }; + let krate = db.crate_graph().iter().next().unwrap(); db.crate_def_map(krate) } fn render_crate_def_map(map: &CrateDefMap) -> String { let mut buf = String::new(); - go(&mut buf, map, "\ncrate", map.root); + go(&mut buf, map, "\ncrate", map.root()); return buf.trim().to_string(); fn go(buf: &mut String, map: &CrateDefMap, path: &str, module: CrateModuleId) { @@ -118,7 +113,7 @@ fn crate_def_map_smoke_test() { #[test] fn bogus_paths() { - covers!(bogus_paths); + // covers!(bogus_paths); let map = def_map( " //- /lib.rs @@ -233,7 +228,7 @@ fn re_exports() { #[test] fn std_prelude() { - covers!(std_prelude); + // covers!(std_prelude); let map = def_map_with_crate_graph( " //- /main.rs @@ -261,7 +256,7 @@ fn std_prelude() { #[test] fn can_import_enum_variant() { - covers!(can_import_enum_variant); + // covers!(can_import_enum_variant); let map = def_map( " //- /lib.rs diff --git a/crates/ra_hir/src/nameres/tests/globs.rs b/crates/ra_hir/src/nameres/tests/globs.rs index 7ac22b47b808..b3e4d8d9454e 100644 --- a/crates/ra_hir/src/nameres/tests/globs.rs +++ b/crates/ra_hir/src/nameres/tests/globs.rs @@ -75,7 +75,7 @@ fn glob_2() { #[test] fn glob_across_crates() { - covers!(glob_across_crates); + // covers!(glob_across_crates); let map = def_map_with_crate_graph( " //- /main.rs @@ -98,7 +98,7 @@ fn glob_across_crates() { #[test] fn glob_enum() { - covers!(glob_enum); + // covers!(glob_enum); let map = def_map( " //- /lib.rs diff --git a/crates/ra_hir/src/nameres/tests/incremental.rs b/crates/ra_hir/src/nameres/tests/incremental.rs index af9c39760268..723ece7b0210 100644 --- a/crates/ra_hir/src/nameres/tests/incremental.rs +++ b/crates/ra_hir/src/nameres/tests/incremental.rs @@ -1,13 +1,12 @@ -use super::*; - use std::sync::Arc; use ra_db::{SourceDatabase, SourceDatabaseExt}; +use super::*; + fn check_def_map_is_not_recomputed(initial: &str, file_change: &str) { let (mut db, pos) = MockDatabase::with_position(initial); - let crate_id = db.crate_graph().iter().next().unwrap(); - let krate = Crate { crate_id }; + let krate = db.crate_graph().iter().next().unwrap(); { let events = db.log_executed(|| { db.crate_def_map(krate); diff --git a/crates/ra_hir/src/nameres/tests/macros.rs b/crates/ra_hir/src/nameres/tests/macros.rs index 4f52ad2c543a..78bb0eb0ddde 100644 --- a/crates/ra_hir/src/nameres/tests/macros.rs +++ b/crates/ra_hir/src/nameres/tests/macros.rs @@ -187,7 +187,7 @@ fn unexpanded_macro_should_expand_by_fixedpoint_loop() { #[test] fn macro_rules_from_other_crates_are_visible_with_macro_use() { - covers!(macro_rules_from_other_crates_are_visible_with_macro_use); + // covers!(macro_rules_from_other_crates_are_visible_with_macro_use); let map = def_map_with_crate_graph( " //- /main.rs @@ -241,7 +241,7 @@ fn macro_rules_from_other_crates_are_visible_with_macro_use() { #[test] fn prelude_is_macro_use() { - covers!(prelude_is_macro_use); + // covers!(prelude_is_macro_use); let map = def_map_with_crate_graph( " //- /main.rs @@ -531,8 +531,8 @@ fn path_qualified_macros() { #[test] fn macro_dollar_crate_is_correct_in_item() { - covers!(macro_dollar_crate_self); - covers!(macro_dollar_crate_other); + // covers!(macro_dollar_crate_self); + // covers!(macro_dollar_crate_other); let map = def_map_with_crate_graph( " //- /main.rs @@ -594,7 +594,7 @@ fn macro_dollar_crate_is_correct_in_item() { #[test] fn macro_dollar_crate_is_correct_in_indirect_deps() { - covers!(macro_dollar_crate_other); + // covers!(macro_dollar_crate_other); // From std let map = def_map_with_crate_graph( r#" diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index 75b24d386f16..3e3f8c252e2e 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs @@ -3,8 +3,9 @@ use std::sync::Arc; use hir_def::{ builtin_type::BuiltinType, + nameres::CrateDefMap, path::{Path, PathKind}, - CrateModuleId, + AdtId, CrateModuleId, ModuleDefId, }; use hir_expand::name::{self, Name}; use rustc_hash::FxHashSet; @@ -18,7 +19,7 @@ use crate::{ }, generics::GenericParams, impl_block::ImplBlock, - nameres::{CrateDefMap, PerNs}, + nameres::PerNs, Adt, Const, Enum, EnumVariant, Function, MacroDef, ModuleDef, Static, Struct, Trait, TypeAlias, }; @@ -90,7 +91,7 @@ impl Resolver { pub(crate) fn resolve_known_trait(&self, db: &impl HirDatabase, path: &Path) -> Option { let res = self.resolve_module_path(db, path).take_types()?; match res { - ModuleDef::Trait(it) => Some(it), + ModuleDefId::TraitId(it) => Some(it.into()), _ => None, } } @@ -103,7 +104,7 @@ impl Resolver { ) -> Option { let res = self.resolve_module_path(db, path).take_types()?; match res { - ModuleDef::Adt(Adt::Struct(it)) => Some(it), + ModuleDefId::AdtId(AdtId::StructId(it)) => Some(it.into()), _ => None, } } @@ -112,7 +113,7 @@ impl Resolver { pub(crate) fn resolve_known_enum(&self, db: &impl HirDatabase, path: &Path) -> Option { let res = self.resolve_module_path(db, path).take_types()?; match res { - ModuleDef::Adt(Adt::Enum(it)) => Some(it), + ModuleDefId::AdtId(AdtId::EnumId(it)) => Some(it.into()), _ => None, } } @@ -166,18 +167,18 @@ impl Resolver { Scope::ModuleScope(m) => { let (module_def, idx) = m.crate_def_map.resolve_path(db, m.module_id, path); let res = match module_def.take_types()? { - ModuleDef::Adt(it) => TypeNs::Adt(it), - ModuleDef::EnumVariant(it) => TypeNs::EnumVariant(it), + ModuleDefId::AdtId(it) => TypeNs::Adt(it.into()), + ModuleDefId::EnumVariantId(it) => TypeNs::EnumVariant(it.into()), - ModuleDef::TypeAlias(it) => TypeNs::TypeAlias(it), - ModuleDef::BuiltinType(it) => TypeNs::BuiltinType(it), + ModuleDefId::TypeAliasId(it) => TypeNs::TypeAlias(it.into()), + ModuleDefId::BuiltinType(it) => TypeNs::BuiltinType(it), - ModuleDef::Trait(it) => TypeNs::Trait(it), + ModuleDefId::TraitId(it) => TypeNs::Trait(it.into()), - ModuleDef::Function(_) - | ModuleDef::Const(_) - | ModuleDef::Static(_) - | ModuleDef::Module(_) => return None, + ModuleDefId::FunctionId(_) + | ModuleDefId::ConstId(_) + | ModuleDefId::StaticId(_) + | ModuleDefId::ModuleId(_) => return None, }; return Some((res, idx)); } @@ -261,33 +262,35 @@ impl Resolver { return match idx { None => { let value = match module_def.take_values()? { - ModuleDef::Function(it) => ValueNs::Function(it), - ModuleDef::Adt(Adt::Struct(it)) => ValueNs::Struct(it), - ModuleDef::EnumVariant(it) => ValueNs::EnumVariant(it), - ModuleDef::Const(it) => ValueNs::Const(it), - ModuleDef::Static(it) => ValueNs::Static(it), + ModuleDefId::FunctionId(it) => ValueNs::Function(it.into()), + ModuleDefId::AdtId(AdtId::StructId(it)) => { + ValueNs::Struct(it.into()) + } + ModuleDefId::EnumVariantId(it) => ValueNs::EnumVariant(it.into()), + ModuleDefId::ConstId(it) => ValueNs::Const(it.into()), + ModuleDefId::StaticId(it) => ValueNs::Static(it.into()), - ModuleDef::Adt(Adt::Enum(_)) - | ModuleDef::Adt(Adt::Union(_)) - | ModuleDef::Trait(_) - | ModuleDef::TypeAlias(_) - | ModuleDef::BuiltinType(_) - | ModuleDef::Module(_) => return None, + ModuleDefId::AdtId(AdtId::EnumId(_)) + | ModuleDefId::AdtId(AdtId::UnionId(_)) + | ModuleDefId::TraitId(_) + | ModuleDefId::TypeAliasId(_) + | ModuleDefId::BuiltinType(_) + | ModuleDefId::ModuleId(_) => return None, }; Some(ResolveValueResult::ValueNs(value)) } Some(idx) => { let ty = match module_def.take_types()? { - ModuleDef::Adt(it) => TypeNs::Adt(it), - ModuleDef::Trait(it) => TypeNs::Trait(it), - ModuleDef::TypeAlias(it) => TypeNs::TypeAlias(it), - ModuleDef::BuiltinType(it) => TypeNs::BuiltinType(it), + ModuleDefId::AdtId(it) => TypeNs::Adt(it.into()), + ModuleDefId::TraitId(it) => TypeNs::Trait(it.into()), + ModuleDefId::TypeAliasId(it) => TypeNs::TypeAlias(it.into()), + ModuleDefId::BuiltinType(it) => TypeNs::BuiltinType(it), - ModuleDef::Module(_) - | ModuleDef::Function(_) - | ModuleDef::EnumVariant(_) - | ModuleDef::Const(_) - | ModuleDef::Static(_) => return None, + ModuleDefId::ModuleId(_) + | ModuleDefId::FunctionId(_) + | ModuleDefId::EnumVariantId(_) + | ModuleDefId::ConstId(_) + | ModuleDefId::StaticId(_) => return None, }; Some(ResolveValueResult::Partial(ty, idx)) } @@ -315,7 +318,7 @@ impl Resolver { path: &Path, ) -> Option { let (item_map, module) = self.module()?; - item_map.resolve_path(db, module, path).0.get_macros() + item_map.resolve_path(db, module, path).0.get_macros().map(MacroDef::from) } pub(crate) fn process_all_names( @@ -333,10 +336,11 @@ impl Resolver { for scope in &self.scopes { if let Scope::ModuleScope(m) = scope { if let Some(prelude) = m.crate_def_map.prelude() { - let prelude_def_map = db.crate_def_map(prelude.krate()); - traits.extend(prelude_def_map[prelude.id.module_id].scope.traits()); + let prelude_def_map = db.crate_def_map(prelude.krate); + traits + .extend(prelude_def_map[prelude.module_id].scope.traits().map(Trait::from)); } - traits.extend(m.crate_def_map[m.module_id].scope.traits()); + traits.extend(m.crate_def_map[m.module_id].scope.traits().map(Trait::from)); } } traits @@ -351,7 +355,7 @@ impl Resolver { } pub(crate) fn krate(&self) -> Option { - self.module().map(|t| t.0.krate()) + self.module().map(|t| Crate { crate_id: t.0.krate() }) } pub(crate) fn where_predicates_in_scope<'a>( @@ -420,8 +424,10 @@ impl From for ScopeDef { fn from(def: PerNs) -> Self { def.take_types() .or_else(|| def.take_values()) - .map(ScopeDef::ModuleDef) - .or_else(|| def.get_macros().map(ScopeDef::MacroDef)) + .map(|module_def_id| ScopeDef::ModuleDef(module_def_id.into())) + .or_else(|| { + def.get_macros().map(|macro_def_id| ScopeDef::MacroDef(macro_def_id.into())) + }) .unwrap_or(ScopeDef::Unknown) } } @@ -441,18 +447,16 @@ impl Scope { f(name.clone(), res.def.into()); }); m.crate_def_map[m.module_id].scope.legacy_macros().for_each(|(name, macro_)| { - f(name.clone(), ScopeDef::MacroDef(macro_)); + f(name.clone(), ScopeDef::MacroDef(macro_.into())); }); - m.crate_def_map.extern_prelude().iter().for_each(|(name, def)| { - f(name.clone(), ScopeDef::ModuleDef(*def)); + m.crate_def_map.extern_prelude().iter().for_each(|(name, &def)| { + f(name.clone(), ScopeDef::ModuleDef(def.into())); }); if let Some(prelude) = m.crate_def_map.prelude() { - let prelude_def_map = db.crate_def_map(prelude.krate()); - prelude_def_map[prelude.id.module_id].scope.entries().for_each( - |(name, res)| { - f(name.clone(), res.def.into()); - }, - ); + let prelude_def_map = db.crate_def_map(prelude.krate); + prelude_def_map[prelude.module_id].scope.entries().for_each(|(name, res)| { + f(name.clone(), res.def.into()); + }); } } Scope::GenericParams(gp) => { diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index a4ca59bba1b4..66cb4b357f88 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs @@ -253,8 +253,11 @@ impl SourceAnalyzer { Some(res) }); - let items = - self.resolver.resolve_module_path(db, &path).take_types().map(PathResolution::Def); + let items = self + .resolver + .resolve_module_path(db, &path) + .take_types() + .map(|it| PathResolution::Def(it.into())); types.or(values).or(items).or_else(|| { self.resolver.resolve_path_as_macro(db, &path).map(|def| PathResolution::Macro(def)) }) diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index bfef48b1613a..f271557377d0 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -3403,7 +3403,7 @@ fn test() { S.foo()<|>; } #[test] fn infer_macro_with_dollar_crate_is_correct_in_expr() { - covers!(macro_dollar_crate_other); + // covers!(macro_dollar_crate_other); let (mut db, pos) = MockDatabase::with_position( r#" //- /main.rs diff --git a/crates/ra_hir_def/src/adt.rs b/crates/ra_hir_def/src/adt.rs index 22bd469f0a31..8f41e55d26f9 100644 --- a/crates/ra_hir_def/src/adt.rs +++ b/crates/ra_hir_def/src/adt.rs @@ -8,7 +8,7 @@ use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; use crate::{ db::DefDatabase2, type_ref::TypeRef, AstItemDef, EnumId, LocalEnumVariantId, - LocalStructFieldId, StructId, + LocalStructFieldId, StructId, UnionId, }; /// Note that we use `StructData` for unions as well! @@ -56,6 +56,13 @@ impl StructData { let variant_data = Arc::new(variant_data); Arc::new(StructData { name, variant_data }) } + pub(crate) fn union_data_query(db: &impl DefDatabase2, struct_: UnionId) -> Arc { + let src = struct_.source(db); + let name = src.ast.name().map(|n| n.as_name()); + let variant_data = VariantData::new(src.ast.kind()); + let variant_data = Arc::new(variant_data); + Arc::new(StructData { name, variant_data }) + } } impl EnumData { @@ -74,6 +81,11 @@ impl EnumData { .collect(); Arc::new(EnumData { name, variants }) } + + pub(crate) fn variant(&self, name: &Name) -> Option { + let (id, _) = self.variants.iter().find(|(_id, data)| data.name.as_ref() == Some(name))?; + Some(id) + } } impl VariantData { diff --git a/crates/ra_hir_def/src/db.rs b/crates/ra_hir_def/src/db.rs index f6027013f2a8..a42348101b48 100644 --- a/crates/ra_hir_def/src/db.rs +++ b/crates/ra_hir_def/src/db.rs @@ -2,13 +2,16 @@ use std::sync::Arc; use hir_expand::{db::AstDatabase, HirFileId}; -use ra_db::{salsa, SourceDatabase}; +use ra_db::{salsa, CrateId, SourceDatabase}; use ra_syntax::ast; use crate::{ adt::{EnumData, StructData}, - nameres::raw::{ImportSourceMap, RawItems}, - EnumId, StructId, + nameres::{ + raw::{ImportSourceMap, RawItems}, + CrateDefMap, + }, + EnumId, StructId, UnionId, }; #[salsa::query_group(InternDatabaseStorage)] @@ -42,9 +45,15 @@ pub trait DefDatabase2: InternDatabase + AstDatabase { #[salsa::invoke(RawItems::raw_items_query)] fn raw_items(&self, file_id: HirFileId) -> Arc; + #[salsa::invoke(CrateDefMap::crate_def_map_query)] + fn crate_def_map(&self, krate: CrateId) -> Arc; + #[salsa::invoke(StructData::struct_data_query)] fn struct_data(&self, s: StructId) -> Arc; + #[salsa::invoke(StructData::union_data_query)] + fn union_data(&self, s: UnionId) -> Arc; + #[salsa::invoke(EnumData::enum_data_query)] fn enum_data(&self, e: EnumId) -> Arc; } diff --git a/crates/ra_hir_def/src/diagnostics.rs b/crates/ra_hir_def/src/diagnostics.rs new file mode 100644 index 000000000000..637184c58229 --- /dev/null +++ b/crates/ra_hir_def/src/diagnostics.rs @@ -0,0 +1,26 @@ +use std::any::Any; + +use hir_expand::diagnostics::Diagnostic; +use ra_syntax::{ast, AstPtr, SyntaxNodePtr}; +use relative_path::RelativePathBuf; + +use hir_expand::{HirFileId, Source}; + +#[derive(Debug)] +pub struct UnresolvedModule { + pub file: HirFileId, + pub decl: AstPtr, + pub candidate: RelativePathBuf, +} + +impl Diagnostic for UnresolvedModule { + fn message(&self) -> String { + "unresolved module".to_string() + } + fn source(&self) -> Source { + Source { file_id: self.file, ast: self.decl.into() } + } + fn as_any(&self) -> &(dyn Any + Send + 'static) { + self + } +} diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs index 6d66f481d3f8..42e080a72e94 100644 --- a/crates/ra_hir_def/src/lib.rs +++ b/crates/ra_hir_def/src/lib.rs @@ -13,6 +13,7 @@ pub mod path; pub mod type_ref; pub mod builtin_type; pub mod adt; +pub mod diagnostics; // FIXME: this should be private pub mod nameres; @@ -237,8 +238,8 @@ impl AstItemDef for EnumId { // FIXME: rename to `VariantId`, only enums can ave variants #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct EnumVariantId { - parent: EnumId, - local_id: LocalEnumVariantId, + pub parent: EnumId, + pub local_id: LocalEnumVariantId, } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] diff --git a/crates/ra_hir_def/src/nameres.rs b/crates/ra_hir_def/src/nameres.rs index 11ba8a7770d9..db59344aa380 100644 --- a/crates/ra_hir_def/src/nameres.rs +++ b/crates/ra_hir_def/src/nameres.rs @@ -2,4 +2,492 @@ // FIXME: review privacy of submodules pub mod raw; +pub mod per_ns; +pub mod collector; pub mod mod_resolution; + +use std::sync::Arc; + +use hir_expand::{diagnostics::DiagnosticSink, name::Name, MacroDefId}; +use once_cell::sync::Lazy; +use ra_arena::Arena; +use ra_db::{CrateId, Edition, FileId}; +use ra_prof::profile; +use ra_syntax::ast; +use rustc_hash::{FxHashMap, FxHashSet}; +// use test_utils::tested_by; + +use crate::{ + builtin_type::BuiltinType, + db::DefDatabase2, + nameres::{diagnostics::DefDiagnostic, per_ns::PerNs, raw::ImportId}, + path::{Path, PathKind}, + AdtId, AstId, CrateModuleId, EnumVariantId, ModuleDefId, ModuleId, TraitId, +}; + +/// Contains all top-level defs from a macro-expanded crate +#[derive(Debug, PartialEq, Eq)] +pub struct CrateDefMap { + krate: CrateId, + edition: Edition, + /// The prelude module for this crate. This either comes from an import + /// marked with the `prelude_import` attribute, or (in the normal case) from + /// a dependency (`std` or `core`). + prelude: Option, + extern_prelude: FxHashMap, + root: CrateModuleId, + pub modules: Arena, + + /// Some macros are not well-behavior, which leads to infinite loop + /// e.g. macro_rules! foo { ($ty:ty) => { foo!($ty); } } + /// We mark it down and skip it in collector + /// + /// FIXME: + /// Right now it only handle a poison macro in a single crate, + /// such that if other crate try to call that macro, + /// the whole process will do again until it became poisoned in that crate. + /// We should handle this macro set globally + /// However, do we want to put it as a global variable? + poison_macros: FxHashSet, + + diagnostics: Vec, +} + +impl std::ops::Index for CrateDefMap { + type Output = ModuleData; + fn index(&self, id: CrateModuleId) -> &ModuleData { + &self.modules[id] + } +} + +#[derive(Default, Debug, PartialEq, Eq)] +pub struct ModuleData { + pub parent: Option, + pub children: FxHashMap, + pub scope: ModuleScope, + /// None for root + pub declaration: Option>, + /// None for inline modules. + /// + /// Note that non-inline modules, by definition, live inside non-macro file. + pub definition: Option, +} + +#[derive(Debug, Default, PartialEq, Eq, Clone)] +pub struct ModuleScope { + pub items: FxHashMap, + /// Macros visable in current module in legacy textual scope + /// + /// For macros invoked by an unquatified identifier like `bar!()`, `legacy_macros` will be searched in first. + /// If it yields no result, then it turns to module scoped `macros`. + /// It macros with name quatified with a path like `crate::foo::bar!()`, `legacy_macros` will be skipped, + /// and only normal scoped `macros` will be searched in. + /// + /// Note that this automatically inherit macros defined textually before the definition of module itself. + /// + /// Module scoped macros will be inserted into `items` instead of here. + // FIXME: Macro shadowing in one module is not properly handled. Non-item place macros will + // be all resolved to the last one defined if shadowing happens. + legacy_macros: FxHashMap, +} + +static BUILTIN_SCOPE: Lazy> = Lazy::new(|| { + BuiltinType::ALL + .iter() + .map(|(name, ty)| { + (name.clone(), Resolution { def: PerNs::types(ty.clone().into()), import: None }) + }) + .collect() +}); + +/// Legacy macros can only be accessed through special methods like `get_legacy_macros`. +/// Other methods will only resolve values, types and module scoped macros only. +impl ModuleScope { + pub fn entries<'a>(&'a self) -> impl Iterator + 'a { + //FIXME: shadowing + self.items.iter().chain(BUILTIN_SCOPE.iter()) + } + + /// Iterate over all module scoped macros + pub fn macros<'a>(&'a self) -> impl Iterator + 'a { + self.items + .iter() + .filter_map(|(name, res)| res.def.get_macros().map(|macro_| (name, macro_))) + } + + /// Iterate over all legacy textual scoped macros visable at the end of the module + pub fn legacy_macros<'a>(&'a self) -> impl Iterator + 'a { + self.legacy_macros.iter().map(|(name, def)| (name, *def)) + } + + /// Get a name from current module scope, legacy macros are not included + pub fn get(&self, name: &Name) -> Option<&Resolution> { + self.items.get(name).or_else(|| BUILTIN_SCOPE.get(name)) + } + + pub fn traits<'a>(&'a self) -> impl Iterator + 'a { + self.items.values().filter_map(|r| match r.def.take_types() { + Some(ModuleDefId::TraitId(t)) => Some(t), + _ => None, + }) + } + + fn get_legacy_macro(&self, name: &Name) -> Option { + self.legacy_macros.get(name).copied() + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Default)] +pub struct Resolution { + /// None for unresolved + pub def: PerNs, + /// ident by which this is imported into local scope. + pub import: Option, +} + +impl Resolution { + pub(crate) fn from_macro(macro_: MacroDefId) -> Self { + Resolution { def: PerNs::macros(macro_), import: None } + } +} + +#[derive(Debug, Clone)] +struct ResolvePathResult { + resolved_def: PerNs, + segment_index: Option, + reached_fixedpoint: ReachedFixedPoint, +} + +impl ResolvePathResult { + fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult { + ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None) + } + + fn with( + resolved_def: PerNs, + reached_fixedpoint: ReachedFixedPoint, + segment_index: Option, + ) -> ResolvePathResult { + ResolvePathResult { resolved_def, reached_fixedpoint, segment_index } + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum ResolveMode { + Import, + Other, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum ReachedFixedPoint { + Yes, + No, +} + +impl CrateDefMap { + pub(crate) fn crate_def_map_query( + // Note that this doesn't have `+ AstDatabase`! + // This gurantess that `CrateDefMap` is stable across reparses. + db: &impl DefDatabase2, + krate: CrateId, + ) -> Arc { + let _p = profile("crate_def_map_query"); + let def_map = { + let crate_graph = db.crate_graph(); + let edition = crate_graph.edition(krate); + let mut modules: Arena = Arena::default(); + let root = modules.alloc(ModuleData::default()); + CrateDefMap { + krate, + edition, + extern_prelude: FxHashMap::default(), + prelude: None, + root, + modules, + poison_macros: FxHashSet::default(), + diagnostics: Vec::new(), + } + }; + let def_map = collector::collect_defs(db, def_map); + Arc::new(def_map) + } + + pub fn krate(&self) -> CrateId { + self.krate + } + + pub fn root(&self) -> CrateModuleId { + self.root + } + + pub fn prelude(&self) -> Option { + self.prelude + } + + pub fn extern_prelude(&self) -> &FxHashMap { + &self.extern_prelude + } + + pub fn add_diagnostics( + &self, + db: &impl DefDatabase2, + module: CrateModuleId, + sink: &mut DiagnosticSink, + ) { + self.diagnostics.iter().for_each(|it| it.add_to(db, module, sink)) + } + + pub fn resolve_path( + &self, + db: &impl DefDatabase2, + original_module: CrateModuleId, + path: &Path, + ) -> (PerNs, Option) { + let res = self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path); + (res.resolved_def, res.segment_index) + } + + // Returns Yes if we are sure that additions to `ItemMap` wouldn't change + // the result. + fn resolve_path_fp_with_macro( + &self, + db: &impl DefDatabase2, + mode: ResolveMode, + original_module: CrateModuleId, + path: &Path, + ) -> ResolvePathResult { + let mut segments = path.segments.iter().enumerate(); + let mut curr_per_ns: PerNs = match path.kind { + PathKind::DollarCrate(krate) => { + if krate == self.krate { + // tested_by!(macro_dollar_crate_self); + PerNs::types(ModuleId { krate: self.krate, module_id: self.root }.into()) + } else { + let def_map = db.crate_def_map(krate); + let module = ModuleId { krate, module_id: def_map.root }; + // tested_by!(macro_dollar_crate_other); + PerNs::types(module.into()) + } + } + PathKind::Crate => { + PerNs::types(ModuleId { krate: self.krate, module_id: self.root }.into()) + } + PathKind::Self_ => { + PerNs::types(ModuleId { krate: self.krate, module_id: original_module }.into()) + } + // plain import or absolute path in 2015: crate-relative with + // fallback to extern prelude (with the simplification in + // rust-lang/rust#57745) + // FIXME there must be a nicer way to write this condition + PathKind::Plain | PathKind::Abs + if self.edition == Edition::Edition2015 + && (path.kind == PathKind::Abs || mode == ResolveMode::Import) => + { + let segment = match segments.next() { + Some((_, segment)) => segment, + None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), + }; + log::debug!("resolving {:?} in crate root (+ extern prelude)", segment); + self.resolve_name_in_crate_root_or_extern_prelude(&segment.name) + } + PathKind::Plain => { + let segment = match segments.next() { + Some((_, segment)) => segment, + None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), + }; + log::debug!("resolving {:?} in module", segment); + self.resolve_name_in_module(db, original_module, &segment.name) + } + PathKind::Super => { + if let Some(p) = self.modules[original_module].parent { + PerNs::types(ModuleId { krate: self.krate, module_id: p }.into()) + } else { + log::debug!("super path in root module"); + return ResolvePathResult::empty(ReachedFixedPoint::Yes); + } + } + PathKind::Abs => { + // 2018-style absolute path -- only extern prelude + let segment = match segments.next() { + Some((_, segment)) => segment, + None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), + }; + if let Some(def) = self.extern_prelude.get(&segment.name) { + log::debug!("absolute path {:?} resolved to crate {:?}", path, def); + PerNs::types(*def) + } else { + return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude + } + } + PathKind::Type(_) => { + // This is handled in `infer::infer_path_expr` + // The result returned here does not matter + return ResolvePathResult::empty(ReachedFixedPoint::Yes); + } + }; + + for (i, segment) in segments { + let curr = match curr_per_ns.take_types() { + Some(r) => r, + None => { + // we still have path segments left, but the path so far + // didn't resolve in the types namespace => no resolution + // (don't break here because `curr_per_ns` might contain + // something in the value namespace, and it would be wrong + // to return that) + return ResolvePathResult::empty(ReachedFixedPoint::No); + } + }; + // resolve segment in curr + + curr_per_ns = match curr { + ModuleDefId::ModuleId(module) => { + if module.krate != self.krate { + let path = + Path { segments: path.segments[i..].to_vec(), kind: PathKind::Self_ }; + log::debug!("resolving {:?} in other crate", path); + let defp_map = db.crate_def_map(module.krate); + let (def, s) = defp_map.resolve_path(db, module.module_id, &path); + return ResolvePathResult::with( + def, + ReachedFixedPoint::Yes, + s.map(|s| s + i), + ); + } + + // Since it is a qualified path here, it should not contains legacy macros + match self[module.module_id].scope.get(&segment.name) { + Some(res) => res.def, + _ => { + log::debug!("path segment {:?} not found", segment.name); + return ResolvePathResult::empty(ReachedFixedPoint::No); + } + } + } + ModuleDefId::AdtId(AdtId::EnumId(e)) => { + // enum variant + // tested_by!(can_import_enum_variant); + let enum_data = db.enum_data(e); + match enum_data.variant(&segment.name) { + Some(local_id) => { + let variant = EnumVariantId { parent: e, local_id }; + PerNs::both(variant.into(), variant.into()) + } + None => { + return ResolvePathResult::with( + PerNs::types(e.into()), + ReachedFixedPoint::Yes, + Some(i), + ); + } + } + } + s => { + // could be an inherent method call in UFCS form + // (`Struct::method`), or some other kind of associated item + log::debug!( + "path segment {:?} resolved to non-module {:?}, but is not last", + segment.name, + curr, + ); + + return ResolvePathResult::with( + PerNs::types(s), + ReachedFixedPoint::Yes, + Some(i), + ); + } + }; + } + ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None) + } + + fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> PerNs { + let from_crate_root = + self[self.root].scope.get(name).map_or_else(PerNs::none, |res| res.def); + let from_extern_prelude = self.resolve_name_in_extern_prelude(name); + + from_crate_root.or(from_extern_prelude) + } + + pub(crate) fn resolve_name_in_module( + &self, + db: &impl DefDatabase2, + module: CrateModuleId, + name: &Name, + ) -> PerNs { + // Resolve in: + // - legacy scope of macro + // - current module / scope + // - extern prelude + // - std prelude + let from_legacy_macro = + self[module].scope.get_legacy_macro(name).map_or_else(PerNs::none, PerNs::macros); + let from_scope = self[module].scope.get(name).map_or_else(PerNs::none, |res| res.def); + let from_extern_prelude = + self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)); + let from_prelude = self.resolve_in_prelude(db, name); + + from_legacy_macro.or(from_scope).or(from_extern_prelude).or(from_prelude) + } + + fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs { + self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)) + } + + fn resolve_in_prelude(&self, db: &impl DefDatabase2, name: &Name) -> PerNs { + if let Some(prelude) = self.prelude { + let keep; + let def_map = if prelude.krate == self.krate { + self + } else { + // Extend lifetime + keep = db.crate_def_map(prelude.krate); + &keep + }; + def_map[prelude.module_id].scope.get(name).map_or_else(PerNs::none, |res| res.def) + } else { + PerNs::none() + } + } +} + +mod diagnostics { + use hir_expand::diagnostics::DiagnosticSink; + use ra_syntax::{ast, AstPtr}; + use relative_path::RelativePathBuf; + + use crate::{db::DefDatabase2, diagnostics::UnresolvedModule, nameres::CrateModuleId, AstId}; + + #[derive(Debug, PartialEq, Eq)] + pub(super) enum DefDiagnostic { + UnresolvedModule { + module: CrateModuleId, + declaration: AstId, + candidate: RelativePathBuf, + }, + } + + impl DefDiagnostic { + pub(super) fn add_to( + &self, + db: &impl DefDatabase2, + target_module: CrateModuleId, + sink: &mut DiagnosticSink, + ) { + match self { + DefDiagnostic::UnresolvedModule { module, declaration, candidate } => { + if *module != target_module { + return; + } + let decl = declaration.to_node(db); + sink.push(UnresolvedModule { + file: declaration.file_id(), + decl: AstPtr::new(&decl), + candidate: candidate.clone(), + }) + } + } + } + } +} diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs similarity index 86% rename from crates/ra_hir/src/nameres/collector.rs rename to crates/ra_hir_def/src/nameres/collector.rs index ee0a4c99fe00..8a96d3d31f57 100644 --- a/crates/ra_hir/src/nameres/collector.rs +++ b/crates/ra_hir_def/src/nameres/collector.rs @@ -1,45 +1,49 @@ //! FIXME: write short doc here -use hir_def::{ - attr::Attr, - nameres::{mod_resolution::ModDir, raw}, +use hir_expand::{ + name::{self, AsName, Name}, + HirFileId, MacroCallId, MacroCallLoc, MacroDefId, MacroFileKind, }; -use hir_expand::name; use ra_cfg::CfgOptions; -use ra_db::FileId; +use ra_db::{CrateId, FileId}; use ra_syntax::{ast, SmolStr}; use rustc_hash::FxHashMap; -use test_utils::tested_by; +// use test_utils::tested_by; use crate::{ - db::DefDatabase, - ids::{AstItemDef, LocationCtx, MacroCallId, MacroCallLoc, MacroDefId, MacroFileKind}, + attr::Attr, + db::DefDatabase2, nameres::{ - diagnostics::DefDiagnostic, Crate, CrateDefMap, CrateModuleId, ModuleData, ModuleDef, - PerNs, ReachedFixedPoint, Resolution, ResolveMode, + diagnostics::DefDiagnostic, mod_resolution::ModDir, per_ns::PerNs, raw, CrateDefMap, + ModuleData, ReachedFixedPoint, Resolution, ResolveMode, }, - Adt, AstId, Const, Enum, Function, HirFileId, MacroDef, Module, Name, Path, PathKind, Static, - Struct, Trait, TypeAlias, Union, + path::{Path, PathKind}, + AdtId, AstId, AstItemDef, ConstId, CrateModuleId, EnumId, EnumVariantId, FunctionId, + LocationCtx, ModuleDefId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, UnionId, }; -pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap { +pub(super) fn collect_defs(db: &impl DefDatabase2, mut def_map: CrateDefMap) -> CrateDefMap { + let crate_graph = db.crate_graph(); + // populate external prelude - for dep in def_map.krate.dependencies(db) { - log::debug!("crate dep {:?} -> {:?}", dep.name, dep.krate); - if let Some(module) = dep.krate.root_module(db) { - def_map.extern_prelude.insert(dep.name.clone(), module.into()); - } + for dep in crate_graph.dependencies(def_map.krate) { + let dep_def_map = db.crate_def_map(dep.crate_id); + log::debug!("crate dep {:?} -> {:?}", dep.name, dep.crate_id); + def_map.extern_prelude.insert( + dep.as_name(), + ModuleId { krate: dep.crate_id, module_id: dep_def_map.root }.into(), + ); + // look for the prelude if def_map.prelude.is_none() { - let map = db.crate_def_map(dep.krate); + let map = db.crate_def_map(dep.crate_id); if map.prelude.is_some() { def_map.prelude = map.prelude; } } } - let crate_graph = db.crate_graph(); - let cfg_options = crate_graph.cfg_options(def_map.krate().crate_id()); + let cfg_options = crate_graph.cfg_options(def_map.krate); let mut collector = DefCollector { db, @@ -101,11 +105,11 @@ struct DefCollector<'a, DB> { impl DefCollector<'_, DB> where - DB: DefDatabase, + DB: DefDatabase2, { fn collect(&mut self) { let crate_graph = self.db.crate_graph(); - let file_id = crate_graph.crate_root(self.def_map.krate.crate_id()); + let file_id = crate_graph.crate_root(self.def_map.krate); let raw_items = self.db.raw_items(file_id.into()); let module_id = self.def_map.root; self.def_map.modules[module_id].definition = Some(file_id); @@ -168,7 +172,7 @@ where &mut self, module_id: CrateModuleId, name: Name, - macro_: MacroDef, + macro_: MacroDefId, export: bool, ) { // Textual scoping @@ -189,7 +193,7 @@ where /// the definition of current module. /// And also, `macro_use` on a module will import all legacy macros visable inside to /// current legacy scope, with possible shadowing. - fn define_legacy_macro(&mut self, module_id: CrateModuleId, name: Name, macro_: MacroDef) { + fn define_legacy_macro(&mut self, module_id: CrateModuleId, name: Name, macro_: MacroDefId) { // Always shadowing self.def_map.modules[module_id].scope.legacy_macros.insert(name, macro_); } @@ -213,9 +217,9 @@ where .expect("extern crate should have been desugared to one-element path"), ); - if let Some(ModuleDef::Module(m)) = res.take_types() { - tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use); - self.import_all_macros_exported(current_module_id, m.krate()); + if let Some(ModuleDefId::ModuleId(m)) = res.take_types() { + // tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use); + self.import_all_macros_exported(current_module_id, m.krate); } } @@ -224,7 +228,7 @@ where /// Exported macros are just all macros in the root module scope. /// Note that it contains not only all `#[macro_export]` macros, but also all aliases /// created by `use` in the root module, ignoring the visibility of `use`. - fn import_all_macros_exported(&mut self, current_module_id: CrateModuleId, krate: Crate) { + fn import_all_macros_exported(&mut self, current_module_id: CrateModuleId, krate: CrateId) { let def_map = self.db.crate_def_map(krate); for (name, def) in def_map[def_map.root].scope.macros() { // `macro_use` only bring things into legacy scope. @@ -288,15 +292,15 @@ where if import.is_glob { log::debug!("glob import: {:?}", import); match def.take_types() { - Some(ModuleDef::Module(m)) => { + Some(ModuleDefId::ModuleId(m)) => { if import.is_prelude { - tested_by!(std_prelude); + // tested_by!(std_prelude); self.def_map.prelude = Some(m); - } else if m.krate() != self.def_map.krate { - tested_by!(glob_across_crates); + } else if m.krate != self.def_map.krate { + // tested_by!(glob_across_crates); // glob import from other crate => we can just import everything once - let item_map = self.db.crate_def_map(m.krate()); - let scope = &item_map[m.id.module_id].scope; + let item_map = self.db.crate_def_map(m.krate); + let scope = &item_map[m.module_id].scope; // Module scoped macros is included let items = scope @@ -310,7 +314,7 @@ where // glob import from same crate => we do an initial // import, and then need to propagate any further // additions - let scope = &self.def_map[m.id.module_id].scope; + let scope = &self.def_map[m.module_id].scope; // Module scoped macros is included let items = scope @@ -322,23 +326,25 @@ where self.update(module_id, Some(import_id), &items); // record the glob import in case we add further items self.glob_imports - .entry(m.id.module_id) + .entry(m.module_id) .or_default() .push((module_id, import_id)); } } - Some(ModuleDef::Adt(Adt::Enum(e))) => { - tested_by!(glob_enum); + Some(ModuleDefId::AdtId(AdtId::EnumId(e))) => { + // tested_by!(glob_enum); // glob import from enum => just import all the variants - let variants = e.variants(self.db); - let resolutions = variants - .into_iter() - .filter_map(|variant| { + let enum_data = self.db.enum_data(e); + let resolutions = enum_data + .variants + .iter() + .filter_map(|(local_id, variant_data)| { + let name = variant_data.name.clone()?; + let variant = EnumVariantId { parent: e, local_id }; let res = Resolution { def: PerNs::both(variant.into(), variant.into()), import: Some(import_id), }; - let name = variant.name(self.db)?; Some((name, res)) }) .collect::>(); @@ -367,7 +373,8 @@ where let resolution = Resolution { def, import: Some(import_id) }; self.update(module_id, Some(import_id), &[(name, resolution)]); } - None => tested_by!(bogus_paths), + // tested_by!(bogus_paths), + None => (), } } } @@ -451,8 +458,8 @@ where ); if let Some(def) = resolved_res.resolved_def.get_macros() { - let call_id = self.db.intern_macro(MacroCallLoc { def: def.id, ast_id: *ast_id }); - resolved.push((*module_id, call_id, def.id)); + let call_id = self.db.intern_macro(MacroCallLoc { def, ast_id: *ast_id }); + resolved.push((*module_id, call_id, def)); res = ReachedFixedPoint::No; return false; } @@ -517,7 +524,7 @@ struct ModCollector<'a, D> { impl ModCollector<'_, &'_ mut DefCollector<'_, DB>> where - DB: DefDatabase, + DB: DefDatabase2, { fn collect(&mut self, items: &[raw::RawItem]) { // Note: don't assert that inserted value is fresh: it's simply not true @@ -526,10 +533,9 @@ where // Prelude module is always considered to be `#[macro_use]`. if let Some(prelude_module) = self.def_collector.def_map.prelude { - if prelude_module.krate() != self.def_collector.def_map.krate { - tested_by!(prelude_is_macro_use); - self.def_collector - .import_all_macros_exported(self.module_id, prelude_module.krate()); + if prelude_module.krate != self.def_collector.def_map.krate { + // tested_by!(prelude_is_macro_use); + self.def_collector.import_all_macros_exported(self.module_id, prelude_module.krate); } } @@ -635,7 +641,9 @@ where modules[res].scope.legacy_macros = modules[self.module_id].scope.legacy_macros.clone(); modules[self.module_id].children.insert(name.clone(), res); let resolution = Resolution { - def: PerNs::types(Module::new(self.def_collector.def_map.krate, res).into()), + def: PerNs::types( + ModuleId { krate: self.def_collector.def_map.krate, module_id: res }.into(), + ), import: None, }; self.def_collector.update(self.module_id, None, &[(name, resolution)]); @@ -643,30 +651,32 @@ where } fn define_def(&mut self, def: &raw::DefData) { - let module = Module::new(self.def_collector.def_map.krate, self.module_id); - let ctx = LocationCtx::new(self.def_collector.db, module.id, self.file_id); + let module = + ModuleId { krate: self.def_collector.def_map.krate, module_id: self.module_id }; + let ctx = LocationCtx::new(self.def_collector.db, module, self.file_id); - macro_rules! def { - ($kind:ident, $ast_id:ident) => { - $kind { id: AstItemDef::from_ast_id(ctx, $ast_id) }.into() - }; - } let name = def.name.clone(); let def: PerNs = match def.kind { - raw::DefKind::Function(ast_id) => PerNs::values(def!(Function, ast_id)), + raw::DefKind::Function(ast_id) => { + PerNs::values(FunctionId::from_ast_id(ctx, ast_id).into()) + } raw::DefKind::Struct(ast_id) => { - let s = def!(Struct, ast_id); + let s = StructId::from_ast_id(ctx, ast_id).into(); PerNs::both(s, s) } raw::DefKind::Union(ast_id) => { - let s = def!(Union, ast_id); + let s = UnionId::from_ast_id(ctx, ast_id).into(); PerNs::both(s, s) } - raw::DefKind::Enum(ast_id) => PerNs::types(def!(Enum, ast_id)), - raw::DefKind::Const(ast_id) => PerNs::values(def!(Const, ast_id)), - raw::DefKind::Static(ast_id) => PerNs::values(def!(Static, ast_id)), - raw::DefKind::Trait(ast_id) => PerNs::types(def!(Trait, ast_id)), - raw::DefKind::TypeAlias(ast_id) => PerNs::types(def!(TypeAlias, ast_id)), + raw::DefKind::Enum(ast_id) => PerNs::types(EnumId::from_ast_id(ctx, ast_id).into()), + raw::DefKind::Const(ast_id) => PerNs::values(ConstId::from_ast_id(ctx, ast_id).into()), + raw::DefKind::Static(ast_id) => { + PerNs::values(StaticId::from_ast_id(ctx, ast_id).into()) + } + raw::DefKind::Trait(ast_id) => PerNs::types(TraitId::from_ast_id(ctx, ast_id).into()), + raw::DefKind::TypeAlias(ast_id) => { + PerNs::types(TypeAliasId::from_ast_id(ctx, ast_id).into()) + } }; let resolution = Resolution { def, import: None }; self.def_collector.update(self.module_id, None, &[(name, resolution)]) @@ -678,10 +688,8 @@ where // Case 1: macro rules, define a macro in crate-global mutable scope if is_macro_rules(&mac.path) { if let Some(name) = &mac.name { - let macro_id = - MacroDefId { ast_id, krate: self.def_collector.def_map.krate.crate_id }; - let macro_ = MacroDef { id: macro_id }; - self.def_collector.define_macro(self.module_id, name.clone(), macro_, mac.export); + let macro_id = MacroDefId { ast_id, krate: self.def_collector.def_map.krate }; + self.def_collector.define_macro(self.module_id, name.clone(), macro_id, mac.export); } return; } @@ -691,10 +699,10 @@ where if let Some(macro_def) = mac.path.as_ident().and_then(|name| { self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name) }) { - let def = macro_def.id; - let macro_call_id = self.def_collector.db.intern_macro(MacroCallLoc { def, ast_id }); + let macro_call_id = + self.def_collector.db.intern_macro(MacroCallLoc { def: macro_def, ast_id }); - self.def_collector.collect_macro_expansion(self.module_id, macro_call_id, def); + self.def_collector.collect_macro_expansion(self.module_id, macro_call_id, macro_def); return; } @@ -731,7 +739,7 @@ fn is_macro_rules(path: &Path) -> bool { path.as_ident() == Some(&name::MACRO_RULES) } -#[cfg(test)] +#[cfg(never)] mod tests { use ra_db::SourceDatabase; diff --git a/crates/ra_hir/src/nameres/per_ns.rs b/crates/ra_hir_def/src/nameres/per_ns.rs similarity index 75% rename from crates/ra_hir/src/nameres/per_ns.rs rename to crates/ra_hir_def/src/nameres/per_ns.rs index 0da6789de609..298b0b0c724b 100644 --- a/crates/ra_hir/src/nameres/per_ns.rs +++ b/crates/ra_hir_def/src/nameres/per_ns.rs @@ -1,6 +1,8 @@ //! FIXME: write short doc here -use crate::{MacroDef, ModuleDef}; +use hir_expand::MacroDefId; + +use crate::ModuleDefId; #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum Namespace { @@ -12,11 +14,11 @@ pub enum Namespace { #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct PerNs { - pub types: Option, - pub values: Option, + pub types: Option, + pub values: Option, /// Since macros has different type, many methods simply ignore it. /// We can only use special method like `get_macros` to access it. - pub macros: Option, + pub macros: Option, } impl Default for PerNs { @@ -30,19 +32,19 @@ impl PerNs { PerNs { types: None, values: None, macros: None } } - pub fn values(t: ModuleDef) -> PerNs { + pub fn values(t: ModuleDefId) -> PerNs { PerNs { types: None, values: Some(t), macros: None } } - pub fn types(t: ModuleDef) -> PerNs { + pub fn types(t: ModuleDefId) -> PerNs { PerNs { types: Some(t), values: None, macros: None } } - pub fn both(types: ModuleDef, values: ModuleDef) -> PerNs { + pub fn both(types: ModuleDefId, values: ModuleDefId) -> PerNs { PerNs { types: Some(types), values: Some(values), macros: None } } - pub fn macros(macro_: MacroDef) -> PerNs { + pub fn macros(macro_: MacroDefId) -> PerNs { PerNs { types: None, values: None, macros: Some(macro_) } } @@ -54,15 +56,15 @@ impl PerNs { self.types.is_some() && self.values.is_some() && self.macros.is_some() } - pub fn take_types(self) -> Option { + pub fn take_types(self) -> Option { self.types } - pub fn take_values(self) -> Option { + pub fn take_values(self) -> Option { self.values } - pub fn get_macros(&self) -> Option { + pub fn get_macros(&self) -> Option { self.macros } diff --git a/crates/ra_ide_api/src/completion/complete_path.rs b/crates/ra_ide_api/src/completion/complete_path.rs index 9ac9768afb20..09ca401794ea 100644 --- a/crates/ra_ide_api/src/completion/complete_path.rs +++ b/crates/ra_ide_api/src/completion/complete_path.rs @@ -18,15 +18,15 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) { match def { hir::ModuleDef::Module(module) => { let module_scope = module.scope(ctx.db); - for (name, res) in module_scope.entries() { - if let Some(hir::ModuleDef::BuiltinType(..)) = res.def.take_types() { + for (name, def, import) in module_scope { + if let hir::ScopeDef::ModuleDef(hir::ModuleDef::BuiltinType(..)) = def { if ctx.use_item_syntax.is_some() { tested_by!(dont_complete_primitive_in_use); continue; } } if Some(module) == ctx.module { - if let Some(import) = res.import { + if let Some(import) = import { if let Either::A(use_tree) = module.import_source(ctx.db, import) { if use_tree.syntax().text_range().contains_inclusive(ctx.offset) { // for `use self::foo<|>`, don't suggest `foo` as a completion @@ -36,7 +36,7 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) { } } } - acc.add_resolution(ctx, name.to_string(), &res.def.into()); + acc.add_resolution(ctx, name.to_string(), &def); } } hir::ModuleDef::Adt(_) | hir::ModuleDef::TypeAlias(_) => { From 0933d914a37c4ab57fda6fe95464d194dab6f80c Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 3 Nov 2019 20:53:17 +0300 Subject: [PATCH 14/21] Introduce ra_db::fixture fixture module The goal here is to share more testing infrastructure between crates. --- Cargo.lock | 1 + crates/ra_db/Cargo.toml | 1 + crates/ra_db/src/fixture.rs | 40 ++++++++++++++++++++++ crates/ra_db/src/lib.rs | 3 +- crates/ra_hir_def/src/lib.rs | 3 ++ crates/ra_hir_def/src/nameres/collector.rs | 20 +++++------ crates/ra_hir_def/src/test_db.rs | 40 ++++++++++++++++++++++ 7 files changed, 97 insertions(+), 11 deletions(-) create mode 100644 crates/ra_db/src/fixture.rs create mode 100644 crates/ra_hir_def/src/test_db.rs diff --git a/Cargo.lock b/Cargo.lock index 29f77044e832..c96e0869cab3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -985,6 +985,7 @@ dependencies = [ "relative-path 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "salsa 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)", + "test_utils 0.1.0", ] [[package]] diff --git a/crates/ra_db/Cargo.toml b/crates/ra_db/Cargo.toml index 3394ae8ce6c3..bf1f7920c583 100644 --- a/crates/ra_db/Cargo.toml +++ b/crates/ra_db/Cargo.toml @@ -12,3 +12,4 @@ rustc-hash = "1.0" ra_syntax = { path = "../ra_syntax" } ra_cfg = { path = "../ra_cfg" } ra_prof = { path = "../ra_prof" } +test_utils = { path = "../test_utils" } diff --git a/crates/ra_db/src/fixture.rs b/crates/ra_db/src/fixture.rs new file mode 100644 index 000000000000..469251fe9aed --- /dev/null +++ b/crates/ra_db/src/fixture.rs @@ -0,0 +1,40 @@ +//! FIXME: write short doc here + +use std::sync::Arc; + +use ra_cfg::CfgOptions; + +use crate::{ + CrateGraph, Edition, FileId, RelativePathBuf, SourceDatabaseExt, SourceRoot, SourceRootId, +}; + +pub const WORKSPACE: SourceRootId = SourceRootId(0); + +pub trait WithFixture: Default + SourceDatabaseExt + 'static { + fn with_single_file(text: &str) -> (Self, FileId) { + let mut db = Self::default(); + let file_id = with_single_file(&mut db, text); + (db, file_id) + } +} + +impl WithFixture for DB {} + +fn with_single_file(db: &mut dyn SourceDatabaseExt, text: &str) -> FileId { + let file_id = FileId(0); + let rel_path: RelativePathBuf = "/main.rs".into(); + + let mut source_root = SourceRoot::default(); + source_root.insert_file(rel_path.clone(), file_id); + + let mut crate_graph = CrateGraph::default(); + crate_graph.add_crate_root(file_id, Edition::Edition2018, CfgOptions::default()); + + db.set_file_text(file_id, Arc::new(text.to_string())); + db.set_file_relative_path(file_id, rel_path); + db.set_file_source_root(file_id, WORKSPACE); + db.set_source_root(WORKSPACE, Arc::new(source_root)); + db.set_crate_graph(Arc::new(crate_graph)); + + file_id +} diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs index 0d1ab48438d0..b6bfd531de93 100644 --- a/crates/ra_db/src/lib.rs +++ b/crates/ra_db/src/lib.rs @@ -1,17 +1,18 @@ //! ra_db defines basic database traits. The concrete DB is defined by ra_ide_api. mod cancellation; mod input; +pub mod fixture; use std::{panic, sync::Arc}; use ra_prof::profile; use ra_syntax::{ast, Parse, SourceFile, TextRange, TextUnit}; -use relative_path::{RelativePath, RelativePathBuf}; pub use crate::{ cancellation::Canceled, input::{CrateGraph, CrateId, Dependency, Edition, FileId, SourceRoot, SourceRootId}, }; +pub use relative_path::{RelativePath, RelativePathBuf}; pub use salsa; pub trait CheckCanceled { diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs index 42e080a72e94..02bd808fc217 100644 --- a/crates/ra_hir_def/src/lib.rs +++ b/crates/ra_hir_def/src/lib.rs @@ -15,6 +15,9 @@ pub mod builtin_type; pub mod adt; pub mod diagnostics; +#[cfg(test)] +mod test_db; + // FIXME: this should be private pub mod nameres; diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs index 8a96d3d31f57..0bc36910c3f0 100644 --- a/crates/ra_hir_def/src/nameres/collector.rs +++ b/crates/ra_hir_def/src/nameres/collector.rs @@ -739,17 +739,18 @@ fn is_macro_rules(path: &Path) -> bool { path.as_ident() == Some(&name::MACRO_RULES) } -#[cfg(never)] +#[cfg(test)] mod tests { - use ra_db::SourceDatabase; - - use super::*; - use crate::{db::DefDatabase, mock::MockDatabase, Crate}; use ra_arena::Arena; + use ra_db::{fixture::WithFixture, SourceDatabase}; use rustc_hash::FxHashSet; + use crate::{db::DefDatabase2, test_db::TestDB}; + + use super::*; + fn do_collect_defs( - db: &impl DefDatabase, + db: &impl DefDatabase2, def_map: CrateDefMap, monitor: MacroStackMonitor, ) -> CrateDefMap { @@ -768,12 +769,11 @@ mod tests { } fn do_limited_resolve(code: &str, limit: u32, poison_limit: u32) -> CrateDefMap { - let (db, _source_root, _) = MockDatabase::with_single_file(&code); - let crate_id = db.crate_graph().iter().next().unwrap(); - let krate = Crate { crate_id }; + let (db, _file_id) = TestDB::with_single_file(&code); + let krate = db.crate_graph().iter().next().unwrap(); let def_map = { - let edition = krate.edition(&db); + let edition = db.crate_graph().edition(krate); let mut modules: Arena = Arena::default(); let root = modules.alloc(ModuleData::default()); CrateDefMap { diff --git a/crates/ra_hir_def/src/test_db.rs b/crates/ra_hir_def/src/test_db.rs new file mode 100644 index 000000000000..67714c68e2e8 --- /dev/null +++ b/crates/ra_hir_def/src/test_db.rs @@ -0,0 +1,40 @@ +use std::{panic, sync::Arc}; + +use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate}; +use relative_path::RelativePath; + +#[salsa::database( + ra_db::SourceDatabaseExtStorage, + ra_db::SourceDatabaseStorage, + hir_expand::db::AstDatabaseStorage, + crate::db::InternDatabaseStorage, + crate::db::DefDatabase2Storage +)] +#[derive(Debug, Default)] +pub struct TestDB { + runtime: salsa::Runtime, +} + +impl salsa::Database for TestDB { + fn salsa_runtime(&self) -> &salsa::Runtime { + &self.runtime + } +} + +impl panic::RefUnwindSafe for TestDB {} + +impl FileLoader for TestDB { + fn file_text(&self, file_id: FileId) -> Arc { + FileLoaderDelegate(self).file_text(file_id) + } + fn resolve_relative_path( + &self, + anchor: FileId, + relative_path: &RelativePath, + ) -> Option { + FileLoaderDelegate(self).resolve_relative_path(anchor, relative_path) + } + fn relevant_crates(&self, file_id: FileId) -> Arc> { + FileLoaderDelegate(self).relevant_crates(file_id) + } +} From 6fba51c5fc05264abcbf971dcf28142746588d74 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 3 Nov 2019 23:35:48 +0300 Subject: [PATCH 15/21] move crate_def_map tests to hir_def --- Cargo.lock | 1 + crates/ra_db/src/fixture.rs | 148 +++++++++++++++++- crates/ra_db/src/input.rs | 1 + crates/ra_hir/src/nameres.rs | 3 - crates/ra_hir_def/Cargo.toml | 4 + crates/ra_hir_def/src/nameres.rs | 3 + .../src/nameres/tests.rs | 145 ++++++----------- .../src/nameres/tests/globs.rs | 10 +- .../src/nameres/tests/incremental.rs | 25 ++- .../src/nameres/tests/macros.rs | 83 +++------- .../src/nameres/tests/mod_resolution.rs | 43 +++-- .../src/nameres/tests/primitives.rs | 0 crates/ra_hir_def/src/test_db.rs | 36 ++++- 13 files changed, 308 insertions(+), 194 deletions(-) rename crates/{ra_hir => ra_hir_def}/src/nameres/tests.rs (74%) rename crates/{ra_hir => ra_hir_def}/src/nameres/tests/globs.rs (88%) rename crates/{ra_hir => ra_hir_def}/src/nameres/tests/incremental.rs (76%) rename crates/{ra_hir => ra_hir_def}/src/nameres/tests/macros.rs (86%) rename crates/{ra_hir => ra_hir_def}/src/nameres/tests/mod_resolution.rs (93%) rename crates/{ra_hir => ra_hir_def}/src/nameres/tests/primitives.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index c96e0869cab3..889820c99612 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1028,6 +1028,7 @@ dependencies = [ name = "ra_hir_def" version = "0.1.0" dependencies = [ + "insta 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "once_cell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "ra_arena 0.1.0", diff --git a/crates/ra_db/src/fixture.rs b/crates/ra_db/src/fixture.rs index 469251fe9aed..f5dd59f84011 100644 --- a/crates/ra_db/src/fixture.rs +++ b/crates/ra_db/src/fixture.rs @@ -3,9 +3,12 @@ use std::sync::Arc; use ra_cfg::CfgOptions; +use rustc_hash::FxHashMap; +use test_utils::{extract_offset, parse_fixture, CURSOR_MARKER}; use crate::{ - CrateGraph, Edition, FileId, RelativePathBuf, SourceDatabaseExt, SourceRoot, SourceRootId, + CrateGraph, Edition, FileId, FilePosition, RelativePathBuf, SourceDatabaseExt, SourceRoot, + SourceRootId, }; pub const WORKSPACE: SourceRootId = SourceRootId(0); @@ -16,6 +19,19 @@ pub trait WithFixture: Default + SourceDatabaseExt + 'static { let file_id = with_single_file(&mut db, text); (db, file_id) } + + fn with_files(fixture: &str) -> Self { + let mut db = Self::default(); + let pos = with_files(&mut db, fixture); + assert!(pos.is_none()); + db + } + + fn with_position(fixture: &str) -> (Self, FilePosition) { + let mut db = Self::default(); + let pos = with_files(&mut db, fixture); + (db, pos.unwrap()) + } } impl WithFixture for DB {} @@ -38,3 +54,133 @@ fn with_single_file(db: &mut dyn SourceDatabaseExt, text: &str) -> FileId { file_id } + +fn with_files(db: &mut dyn SourceDatabaseExt, fixture: &str) -> Option { + let fixture = parse_fixture(fixture); + + let mut crate_graph = CrateGraph::default(); + let mut crates = FxHashMap::default(); + let mut crate_deps = Vec::new(); + let mut default_crate_root: Option = None; + + let mut source_root = SourceRoot::default(); + let mut source_root_id = WORKSPACE; + let mut source_root_prefix: RelativePathBuf = "/".into(); + let mut file_id = FileId(0); + + let mut file_position = None; + + for entry in fixture.iter() { + let meta = match parse_meta(&entry.meta) { + ParsedMeta::Root { path } => { + let source_root = std::mem::replace(&mut source_root, SourceRoot::default()); + db.set_source_root(source_root_id, Arc::new(source_root)); + source_root_id.0 += 1; + source_root_prefix = path; + continue; + } + ParsedMeta::File(it) => it, + }; + assert!(meta.path.starts_with(&source_root_prefix)); + + if let Some(krate) = meta.krate { + let crate_id = crate_graph.add_crate_root(file_id, meta.edition, meta.cfg); + let prev = crates.insert(krate.clone(), crate_id); + assert!(prev.is_none()); + for dep in meta.deps { + crate_deps.push((krate.clone(), dep)) + } + } else if meta.path == "/main.rs" || meta.path == "/lib.rs" { + assert!(default_crate_root.is_none()); + default_crate_root = Some(file_id); + } + + let text = if entry.text.contains(CURSOR_MARKER) { + let (offset, text) = extract_offset(&entry.text); + assert!(file_position.is_none()); + file_position = Some(FilePosition { file_id, offset }); + text.to_string() + } else { + entry.text.to_string() + }; + + db.set_file_text(file_id, Arc::new(text)); + db.set_file_relative_path(file_id, meta.path.clone()); + db.set_file_source_root(file_id, source_root_id); + source_root.insert_file(meta.path, file_id); + + file_id.0 += 1; + } + + if crates.is_empty() { + let crate_root = default_crate_root.unwrap(); + crate_graph.add_crate_root(crate_root, Edition::Edition2018, CfgOptions::default()); + } else { + for (from, to) in crate_deps { + let from_id = crates[&from]; + let to_id = crates[&to]; + crate_graph.add_dep(from_id, to.into(), to_id).unwrap(); + } + } + + db.set_source_root(source_root_id, Arc::new(source_root)); + db.set_crate_graph(Arc::new(crate_graph)); + + file_position +} + +enum ParsedMeta { + Root { path: RelativePathBuf }, + File(FileMeta), +} + +struct FileMeta { + path: RelativePathBuf, + krate: Option, + deps: Vec, + cfg: CfgOptions, + edition: Edition, +} + +//- /lib.rs crate:foo deps:bar,baz +fn parse_meta(meta: &str) -> ParsedMeta { + let components = meta.split_ascii_whitespace().collect::>(); + + if components[0] == "root" { + let path: RelativePathBuf = components[1].into(); + assert!(path.starts_with("/") && path.ends_with("/")); + return ParsedMeta::Root { path }; + } + + let path: RelativePathBuf = components[0].into(); + assert!(path.starts_with("/")); + + let mut krate = None; + let mut deps = Vec::new(); + let mut edition = Edition::Edition2018; + let mut cfg = CfgOptions::default(); + for component in components[1..].iter() { + let (key, value) = split1(component, ':').unwrap(); + match key { + "crate" => krate = Some(value.to_string()), + "deps" => deps = value.split(',').map(|it| it.to_string()).collect(), + "edition" => edition = Edition::from_string(&value), + "cfg" => { + for key in value.split(',') { + match split1(key, '=') { + None => cfg.insert_atom(key.into()), + Some((k, v)) => cfg.insert_key_value(k.into(), v.into()), + } + } + } + _ => panic!("bad component: {:?}", component), + } + } + + ParsedMeta::File(FileMeta { path, krate, deps, edition, cfg }) +} + +fn split1(haystack: &str, delim: char) -> Option<(&str, &str)> { + let idx = haystack.find(delim)?; + Some((&haystack[..idx], &haystack[idx + delim.len_utf8()..])) +} diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs index eafa95921cd6..7c8dac1d38da 100644 --- a/crates/ra_db/src/input.rs +++ b/crates/ra_db/src/input.rs @@ -97,6 +97,7 @@ pub enum Edition { } impl Edition { + //FIXME: replace with FromStr with proper error handling pub fn from_string(s: &str) -> Edition { match s { "2015" => Edition::Edition2015, diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs index bb775cfc9d22..875addc84a5e 100644 --- a/crates/ra_hir/src/nameres.rs +++ b/crates/ra_hir/src/nameres.rs @@ -47,9 +47,6 @@ //! path and, upon success, we run macro expansion and "collect module" phase //! on the result -#[cfg(test)] -mod tests; - pub use hir_def::nameres::{ per_ns::{Namespace, PerNs}, raw::ImportId, diff --git a/crates/ra_hir_def/Cargo.toml b/crates/ra_hir_def/Cargo.toml index 746c907e80da..15055db64e59 100644 --- a/crates/ra_hir_def/Cargo.toml +++ b/crates/ra_hir_def/Cargo.toml @@ -19,3 +19,7 @@ test_utils = { path = "../test_utils" } mbe = { path = "../ra_mbe", package = "ra_mbe" } ra_cfg = { path = "../ra_cfg" } tt = { path = "../ra_tt", package = "ra_tt" } + +[dev-dependencies] +insta = "0.12.0" + diff --git a/crates/ra_hir_def/src/nameres.rs b/crates/ra_hir_def/src/nameres.rs index db59344aa380..b3640da3d764 100644 --- a/crates/ra_hir_def/src/nameres.rs +++ b/crates/ra_hir_def/src/nameres.rs @@ -6,6 +6,9 @@ pub mod per_ns; pub mod collector; pub mod mod_resolution; +#[cfg(test)] +mod tests; + use std::sync::Arc; use hir_expand::{diagnostics::DiagnosticSink, name::Name, MacroDefId}; diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir_def/src/nameres/tests.rs similarity index 74% rename from crates/ra_hir/src/nameres/tests.rs rename to crates/ra_hir_def/src/nameres/tests.rs index 02db91a86245..f9a8edd43c3c 100644 --- a/crates/ra_hir/src/nameres/tests.rs +++ b/crates/ra_hir_def/src/nameres/tests.rs @@ -1,23 +1,24 @@ -mod macros; mod globs; mod incremental; -mod primitives; +mod macros; mod mod_resolution; +mod primitives; use std::sync::Arc; -use hir_def::{db::DefDatabase2, nameres::*, CrateModuleId}; use insta::assert_snapshot; -use ra_db::SourceDatabase; +use ra_db::{fixture::WithFixture, SourceDatabase}; // use test_utils::covers; -use crate::mock::{CrateGraphFixture, MockDatabase}; +use crate::{db::DefDatabase2, nameres::*, test_db::TestDB, CrateModuleId}; -fn compute_crate_def_map(fixture: &str, graph: Option) -> Arc { - let mut db = MockDatabase::with_files(fixture); - if let Some(graph) = graph { - db.set_crate_graph_from_fixture(graph); - } +fn def_map(fixtute: &str) -> String { + let dm = compute_crate_def_map(fixtute); + render_crate_def_map(&dm) +} + +fn compute_crate_def_map(fixture: &str) -> Arc { + let db = TestDB::with_files(fixture); let krate = db.crate_graph().iter().next().unwrap(); db.crate_def_map(krate) } @@ -65,16 +66,6 @@ fn render_crate_def_map(map: &CrateDefMap) -> String { } } -fn def_map(fixtute: &str) -> String { - let dm = compute_crate_def_map(fixtute, None); - render_crate_def_map(&dm) -} - -fn def_map_with_crate_graph(fixture: &str, graph: CrateGraphFixture) -> String { - let dm = compute_crate_def_map(fixture, Some(graph)); - render_crate_def_map(&dm) -} - #[test] fn crate_def_map_smoke_test() { let map = def_map( @@ -229,12 +220,12 @@ fn re_exports() { #[test] fn std_prelude() { // covers!(std_prelude); - let map = def_map_with_crate_graph( + let map = def_map( " - //- /main.rs + //- /main.rs crate:main deps:test_crate use Foo::*; - //- /lib.rs + //- /lib.rs crate:test_crate mod prelude; #[prelude_import] use prelude::*; @@ -242,10 +233,6 @@ fn std_prelude() { //- /prelude.rs pub enum Foo { Bar, Baz }; ", - crate_graph! { - "main": ("/main.rs", ["test_crate"]), - "test_crate": ("/lib.rs", []), - }, ); assert_snapshot!(map, @r###" ⋮crate @@ -274,9 +261,9 @@ fn can_import_enum_variant() { #[test] fn edition_2015_imports() { - let map = def_map_with_crate_graph( + let map = def_map( " - //- /main.rs + //- /main.rs crate:main deps:other_crate edition:2015 mod foo; mod bar; @@ -287,13 +274,9 @@ fn edition_2015_imports() { use bar::Bar; use other_crate::FromLib; - //- /lib.rs + //- /lib.rs crate:other_crate edition:2018 struct FromLib; ", - crate_graph! { - "main": ("/main.rs", "2015", ["other_crate"]), - "other_crate": ("/lib.rs", "2018", []), - }, ); assert_snapshot!(map, @r###" @@ -338,18 +321,14 @@ fn item_map_using_self() { #[test] fn item_map_across_crates() { - let map = def_map_with_crate_graph( + let map = def_map( " - //- /main.rs + //- /main.rs crate:main deps:test_crate use test_crate::Baz; - //- /lib.rs + //- /lib.rs crate:test_crate pub struct Baz; ", - crate_graph! { - "main": ("/main.rs", ["test_crate"]), - "test_crate": ("/lib.rs", []), - }, ); assert_snapshot!(map, @r###" @@ -360,9 +339,9 @@ fn item_map_across_crates() { #[test] fn extern_crate_rename() { - let map = def_map_with_crate_graph( + let map = def_map( " - //- /main.rs + //- /main.rs crate:main deps:alloc extern crate alloc as alloc_crate; mod alloc; @@ -371,13 +350,9 @@ fn extern_crate_rename() { //- /sync.rs use alloc_crate::Arc; - //- /lib.rs + //- /lib.rs crate:alloc struct Arc; ", - crate_graph! { - "main": ("/main.rs", ["alloc"]), - "alloc": ("/lib.rs", []), - }, ); assert_snapshot!(map, @r###" @@ -392,9 +367,9 @@ fn extern_crate_rename() { #[test] fn extern_crate_rename_2015_edition() { - let map = def_map_with_crate_graph( + let map = def_map( " - //- /main.rs + //- /main.rs crate:main deps:alloc edition:2015 extern crate alloc as alloc_crate; mod alloc; @@ -403,13 +378,9 @@ fn extern_crate_rename_2015_edition() { //- /sync.rs use alloc_crate::Arc; - //- /lib.rs + //- /lib.rs crate:alloc struct Arc; ", - crate_graph! { - "main": ("/main.rs", "2015", ["alloc"]), - "alloc": ("/lib.rs", []), - }, ); assert_snapshot!(map, @@ -426,24 +397,21 @@ fn extern_crate_rename_2015_edition() { #[test] fn import_across_source_roots() { - let map = def_map_with_crate_graph( + let map = def_map( " - //- /lib.rs + //- /main.rs crate:main deps:test_crate + use test_crate::a::b::C; + + //- root /test_crate/ + + //- /test_crate/lib.rs crate:test_crate pub mod a { pub mod b { pub struct C; } } - //- root /main/ - - //- /main/main.rs - use test_crate::a::b::C; ", - crate_graph! { - "main": ("/main/main.rs", ["test_crate"]), - "test_crate": ("/lib.rs", []), - }, ); assert_snapshot!(map, @r###" @@ -454,12 +422,12 @@ fn import_across_source_roots() { #[test] fn reexport_across_crates() { - let map = def_map_with_crate_graph( + let map = def_map( " - //- /main.rs + //- /main.rs crate:main deps:test_crate use test_crate::Baz; - //- /lib.rs + //- /lib.rs crate:test_crate pub use foo::Baz; mod foo; @@ -467,10 +435,6 @@ fn reexport_across_crates() { //- /foo.rs pub struct Baz; ", - crate_graph! { - "main": ("/main.rs", ["test_crate"]), - "test_crate": ("/lib.rs", []), - }, ); assert_snapshot!(map, @r###" @@ -481,19 +445,15 @@ fn reexport_across_crates() { #[test] fn values_dont_shadow_extern_crates() { - let map = def_map_with_crate_graph( + let map = def_map( " - //- /main.rs + //- /main.rs crate:main deps:foo fn foo() {} use foo::Bar; - //- /foo/lib.rs + //- /foo/lib.rs crate:foo pub struct Bar; ", - crate_graph! { - "main": ("/main.rs", ["foo"]), - "foo": ("/foo/lib.rs", []), - }, ); assert_snapshot!(map, @r###" @@ -505,11 +465,12 @@ fn values_dont_shadow_extern_crates() { #[test] fn cfg_not_test() { - let map = def_map_with_crate_graph( + let map = def_map( r#" - //- /main.rs + //- /main.rs crate:main deps:std use {Foo, Bar, Baz}; - //- /lib.rs + + //- /lib.rs crate:std #[prelude_import] pub use self::prelude::*; mod prelude { @@ -521,10 +482,6 @@ fn cfg_not_test() { pub struct Baz; } "#, - crate_graph! { - "main": ("/main.rs", ["std"]), - "std": ("/lib.rs", []), - }, ); assert_snapshot!(map, @r###" @@ -537,11 +494,12 @@ fn cfg_not_test() { #[test] fn cfg_test() { - let map = def_map_with_crate_graph( + let map = def_map( r#" - //- /main.rs + //- /main.rs crate:main deps:std use {Foo, Bar, Baz}; - //- /lib.rs + + //- /lib.rs crate:std cfg:test,feature=foo,feature=bar,opt=42 #[prelude_import] pub use self::prelude::*; mod prelude { @@ -553,15 +511,6 @@ fn cfg_test() { pub struct Baz; } "#, - crate_graph! { - "main": ("/main.rs", ["std"]), - "std": ("/lib.rs", [], cfg = { - "test", - "feature" = "foo", - "feature" = "bar", - "opt" = "42", - }), - }, ); assert_snapshot!(map, @r###" diff --git a/crates/ra_hir/src/nameres/tests/globs.rs b/crates/ra_hir_def/src/nameres/tests/globs.rs similarity index 88% rename from crates/ra_hir/src/nameres/tests/globs.rs rename to crates/ra_hir_def/src/nameres/tests/globs.rs index b3e4d8d9454e..cf4a2a851841 100644 --- a/crates/ra_hir/src/nameres/tests/globs.rs +++ b/crates/ra_hir_def/src/nameres/tests/globs.rs @@ -76,18 +76,14 @@ fn glob_2() { #[test] fn glob_across_crates() { // covers!(glob_across_crates); - let map = def_map_with_crate_graph( + let map = def_map( " - //- /main.rs + //- /main.rs crate:main deps:test_crate use test_crate::*; - //- /lib.rs + //- /lib.rs crate:test_crate pub struct Baz; ", - crate_graph! { - "main": ("/main.rs", ["test_crate"]), - "test_crate": ("/lib.rs", []), - }, ); assert_snapshot!(map, @r###" ⋮crate diff --git a/crates/ra_hir/src/nameres/tests/incremental.rs b/crates/ra_hir_def/src/nameres/tests/incremental.rs similarity index 76% rename from crates/ra_hir/src/nameres/tests/incremental.rs rename to crates/ra_hir_def/src/nameres/tests/incremental.rs index 723ece7b0210..80dcec62f0f9 100644 --- a/crates/ra_hir/src/nameres/tests/incremental.rs +++ b/crates/ra_hir_def/src/nameres/tests/incremental.rs @@ -5,7 +5,7 @@ use ra_db::{SourceDatabase, SourceDatabaseExt}; use super::*; fn check_def_map_is_not_recomputed(initial: &str, file_change: &str) { - let (mut db, pos) = MockDatabase::with_position(initial); + let (mut db, pos) = TestDB::with_position(initial); let krate = db.crate_graph().iter().next().unwrap(); { let events = db.log_executed(|| { @@ -91,7 +91,7 @@ fn adding_inner_items_should_not_invalidate_def_map() { #[test] fn typing_inside_a_macro_should_not_invalidate_def_map() { - let (mut db, pos) = MockDatabase::with_position( + let (mut db, pos) = TestDB::with_position( " //- /lib.rs macro_rules! m { @@ -111,15 +111,12 @@ fn typing_inside_a_macro_should_not_invalidate_def_map() { m!(X); ", ); + let krate = db.crate_graph().iter().next().unwrap(); { let events = db.log_executed(|| { - let src = crate::Source { - file_id: pos.file_id.into(), - ast: crate::ModuleSource::new(&db, Some(pos.file_id), None), - }; - let module = crate::Module::from_definition(&db, src).unwrap(); - let decls = module.declarations(&db); - assert_eq!(decls.len(), 18); + let crate_def_map = db.crate_def_map(krate); + let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); + assert_eq!(module_data.scope.items.len(), 1); }); assert!(format!("{:?}", events).contains("crate_def_map"), "{:#?}", events) } @@ -127,13 +124,9 @@ fn typing_inside_a_macro_should_not_invalidate_def_map() { { let events = db.log_executed(|| { - let src = crate::Source { - file_id: pos.file_id.into(), - ast: crate::ModuleSource::new(&db, Some(pos.file_id), None), - }; - let module = crate::Module::from_definition(&db, src).unwrap(); - let decls = module.declarations(&db); - assert_eq!(decls.len(), 18); + let crate_def_map = db.crate_def_map(krate); + let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); + assert_eq!(module_data.scope.items.len(), 1); }); assert!(!format!("{:?}", events).contains("crate_def_map"), "{:#?}", events) } diff --git a/crates/ra_hir/src/nameres/tests/macros.rs b/crates/ra_hir_def/src/nameres/tests/macros.rs similarity index 86% rename from crates/ra_hir/src/nameres/tests/macros.rs rename to crates/ra_hir_def/src/nameres/tests/macros.rs index 78bb0eb0ddde..9bb3895ad6a5 100644 --- a/crates/ra_hir/src/nameres/tests/macros.rs +++ b/crates/ra_hir_def/src/nameres/tests/macros.rs @@ -71,16 +71,16 @@ fn macro_rules_can_define_modules() { #[test] fn macro_rules_from_other_crates_are_visible() { - let map = def_map_with_crate_graph( + let map = def_map( " - //- /main.rs + //- /main.rs crate:main deps:foo foo::structs!(Foo, Bar) mod bar; //- /bar.rs use crate::*; - //- /lib.rs + //- /lib.rs crate:foo #[macro_export] macro_rules! structs { ($($i:ident),*) => { @@ -88,10 +88,6 @@ fn macro_rules_from_other_crates_are_visible() { } } ", - crate_graph! { - "main": ("/main.rs", ["foo"]), - "foo": ("/lib.rs", []), - }, ); assert_snapshot!(map, @r###" ⋮crate @@ -108,16 +104,16 @@ fn macro_rules_from_other_crates_are_visible() { #[test] fn macro_rules_export_with_local_inner_macros_are_visible() { - let map = def_map_with_crate_graph( + let map = def_map( " - //- /main.rs + //- /main.rs crate:main deps:foo foo::structs!(Foo, Bar) mod bar; //- /bar.rs use crate::*; - //- /lib.rs + //- /lib.rs crate:foo #[macro_export(local_inner_macros)] macro_rules! structs { ($($i:ident),*) => { @@ -125,10 +121,6 @@ fn macro_rules_export_with_local_inner_macros_are_visible() { } } ", - crate_graph! { - "main": ("/main.rs", ["foo"]), - "foo": ("/lib.rs", []), - }, ); assert_snapshot!(map, @r###" ⋮crate @@ -145,9 +137,9 @@ fn macro_rules_export_with_local_inner_macros_are_visible() { #[test] fn unexpanded_macro_should_expand_by_fixedpoint_loop() { - let map = def_map_with_crate_graph( + let map = def_map( " - //- /main.rs + //- /main.rs crate:main deps:foo macro_rules! baz { () => { use foo::bar; @@ -158,7 +150,7 @@ fn unexpanded_macro_should_expand_by_fixedpoint_loop() { bar!(); baz!(); - //- /lib.rs + //- /lib.rs crate:foo #[macro_export] macro_rules! foo { () => { @@ -172,10 +164,6 @@ fn unexpanded_macro_should_expand_by_fixedpoint_loop() { } } ", - crate_graph! { - "main": ("/main.rs", ["foo"]), - "foo": ("/lib.rs", []), - }, ); assert_snapshot!(map, @r###" ⋮crate @@ -188,9 +176,9 @@ fn unexpanded_macro_should_expand_by_fixedpoint_loop() { #[test] fn macro_rules_from_other_crates_are_visible_with_macro_use() { // covers!(macro_rules_from_other_crates_are_visible_with_macro_use); - let map = def_map_with_crate_graph( + let map = def_map( " - //- /main.rs + //- /main.rs crate:main deps:foo structs!(Foo); structs_priv!(Bar); structs_not_exported!(MacroNotResolved1); @@ -205,7 +193,7 @@ fn macro_rules_from_other_crates_are_visible_with_macro_use() { structs!(Baz); crate::structs!(MacroNotResolved3); - //- /lib.rs + //- /lib.rs crate:foo #[macro_export] macro_rules! structs { ($i:ident) => { struct $i; } @@ -222,10 +210,6 @@ fn macro_rules_from_other_crates_are_visible_with_macro_use() { } } ", - crate_graph! { - "main": ("/main.rs", ["foo"]), - "foo": ("/lib.rs", []), - }, ); assert_snapshot!(map, @r###" ⋮crate @@ -242,9 +226,9 @@ fn macro_rules_from_other_crates_are_visible_with_macro_use() { #[test] fn prelude_is_macro_use() { // covers!(prelude_is_macro_use); - let map = def_map_with_crate_graph( + let map = def_map( " - //- /main.rs + //- /main.rs crate:main deps:foo structs!(Foo); structs_priv!(Bar); structs_outside!(Out); @@ -256,7 +240,7 @@ fn prelude_is_macro_use() { structs!(Baz); crate::structs!(MacroNotResolved3); - //- /lib.rs + //- /lib.rs crate:foo #[prelude_import] use self::prelude::*; @@ -279,10 +263,6 @@ fn prelude_is_macro_use() { ($i:ident) => { struct $i; } } ", - crate_graph! { - "main": ("/main.rs", ["foo"]), - "foo": ("/lib.rs", []), - }, ); assert_snapshot!(map, @r###" ⋮crate @@ -447,16 +427,16 @@ fn type_value_macro_live_in_different_scopes() { #[test] fn macro_use_can_be_aliased() { - let map = def_map_with_crate_graph( + let map = def_map( " - //- /main.rs + //- /main.rs crate:main deps:foo #[macro_use] extern crate foo; foo!(Direct); bar!(Alias); - //- /lib.rs + //- /lib.rs crate:foo use crate::foo as bar; mod m { @@ -466,10 +446,6 @@ fn macro_use_can_be_aliased() { } } ", - crate_graph! { - "main": ("/main.rs", ["foo"]), - "foo": ("/lib.rs", []), - }, ); assert_snapshot!(map, @r###" ⋮crate @@ -533,9 +509,9 @@ fn path_qualified_macros() { fn macro_dollar_crate_is_correct_in_item() { // covers!(macro_dollar_crate_self); // covers!(macro_dollar_crate_other); - let map = def_map_with_crate_graph( + let map = def_map( " - //- /main.rs + //- /main.rs crate:main deps:foo #[macro_use] extern crate foo; @@ -554,7 +530,7 @@ fn macro_dollar_crate_is_correct_in_item() { not_current1!(); foo::not_current2!(); - //- /lib.rs + //- /lib.rs crate:foo mod m { #[macro_export] macro_rules! not_current1 { @@ -574,10 +550,6 @@ fn macro_dollar_crate_is_correct_in_item() { struct Bar; struct Baz; ", - crate_graph! { - "main": ("/main.rs", ["foo"]), - "foo": ("/lib.rs", []), - }, ); assert_snapshot!(map, @r###" ⋮crate @@ -596,12 +568,12 @@ fn macro_dollar_crate_is_correct_in_item() { fn macro_dollar_crate_is_correct_in_indirect_deps() { // covers!(macro_dollar_crate_other); // From std - let map = def_map_with_crate_graph( + let map = def_map( r#" - //- /main.rs + //- /main.rs crate:main deps:std foo!(); - //- /std.rs + //- /std.rs crate:std deps:core #[prelude_import] use self::prelude::*; @@ -612,7 +584,7 @@ fn macro_dollar_crate_is_correct_in_indirect_deps() { #[macro_use] mod std_macros; - //- /core.rs + //- /core.rs crate:core #[macro_export] macro_rules! foo { () => { @@ -622,11 +594,6 @@ fn macro_dollar_crate_is_correct_in_indirect_deps() { pub struct bar; "#, - crate_graph! { - "main": ("/main.rs", ["std"]), - "std": ("/std.rs", ["core"]), - "core": ("/core.rs", []), - }, ); assert_snapshot!(map, @r###" ⋮crate diff --git a/crates/ra_hir/src/nameres/tests/mod_resolution.rs b/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs similarity index 93% rename from crates/ra_hir/src/nameres/tests/mod_resolution.rs rename to crates/ra_hir_def/src/nameres/tests/mod_resolution.rs index abfe8b1c346e..8d804a63e8b4 100644 --- a/crates/ra_hir/src/nameres/tests/mod_resolution.rs +++ b/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs @@ -54,18 +54,15 @@ fn nested_module_resolution() { #[test] fn module_resolution_works_for_non_standard_filenames() { - let map = def_map_with_crate_graph( + let map = def_map( " - //- /my_library.rs + //- /my_library.rs crate:my_library mod foo; use self::foo::Bar; //- /foo/mod.rs pub struct Bar; ", - crate_graph! { - "my_library": ("/my_library.rs", []), - }, ); assert_snapshot!(map, @r###" @@ -650,7 +647,7 @@ fn module_resolution_decl_inside_inline_module_in_non_crate_root_2() { #[test] fn unresolved_module_diagnostics() { - let diagnostics = MockDatabase::with_files( + let db = TestDB::with_files( r" //- /lib.rs mod foo; @@ -658,11 +655,37 @@ fn unresolved_module_diagnostics() { mod baz {} //- /foo.rs ", - ) - .diagnostics(); + ); + let krate = db.crate_graph().iter().next().unwrap(); - assert_snapshot!(diagnostics, @r###" - "mod bar;": unresolved module + let crate_def_map = db.crate_def_map(krate); + + insta::assert_debug_snapshot!( + crate_def_map.diagnostics, + @r###" + [ + UnresolvedModule { + module: CrateModuleId( + 0, + ), + declaration: AstId { + file_id: HirFileId( + FileId( + FileId( + 0, + ), + ), + ), + file_ast_id: FileAstId { + raw: ErasedFileAstId( + 1, + ), + _ty: PhantomData, + }, + }, + candidate: "bar.rs", + }, + ] "### ); } diff --git a/crates/ra_hir/src/nameres/tests/primitives.rs b/crates/ra_hir_def/src/nameres/tests/primitives.rs similarity index 100% rename from crates/ra_hir/src/nameres/tests/primitives.rs rename to crates/ra_hir_def/src/nameres/tests/primitives.rs diff --git a/crates/ra_hir_def/src/test_db.rs b/crates/ra_hir_def/src/test_db.rs index 67714c68e2e8..05018f8e43c2 100644 --- a/crates/ra_hir_def/src/test_db.rs +++ b/crates/ra_hir_def/src/test_db.rs @@ -1,4 +1,7 @@ -use std::{panic, sync::Arc}; +use std::{ + panic, + sync::{Arc, Mutex}, +}; use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate}; use relative_path::RelativePath; @@ -13,12 +16,20 @@ use relative_path::RelativePath; #[derive(Debug, Default)] pub struct TestDB { runtime: salsa::Runtime, + events: Mutex>>>, } impl salsa::Database for TestDB { fn salsa_runtime(&self) -> &salsa::Runtime { &self.runtime } + + fn salsa_event(&self, event: impl Fn() -> salsa::Event) { + let mut events = self.events.lock().unwrap(); + if let Some(events) = &mut *events { + events.push(event()); + } + } } impl panic::RefUnwindSafe for TestDB {} @@ -38,3 +49,26 @@ impl FileLoader for TestDB { FileLoaderDelegate(self).relevant_crates(file_id) } } + +impl TestDB { + pub fn log(&self, f: impl FnOnce()) -> Vec> { + *self.events.lock().unwrap() = Some(Vec::new()); + f(); + self.events.lock().unwrap().take().unwrap() + } + + pub fn log_executed(&self, f: impl FnOnce()) -> Vec { + let events = self.log(f); + events + .into_iter() + .filter_map(|e| match e.kind { + // This pretty horrible, but `Debug` is the only way to inspect + // QueryDescriptor at the moment. + salsa::EventKind::WillExecute { database_key } => { + Some(format!("{:?}", database_key)) + } + _ => None, + }) + .collect() + } +} From 73fcf9a2d6ae14afa4e822370c0a46bf1d336081 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 3 Nov 2019 23:44:23 +0300 Subject: [PATCH 16/21] Restore crate_def_map marks --- crates/ra_hir_def/src/lib.rs | 2 ++ crates/ra_hir_def/src/marks.rs | 14 ++++++++++++++ crates/ra_hir_def/src/nameres.rs | 8 ++++---- crates/ra_hir_def/src/nameres/collector.rs | 15 +++++++-------- crates/ra_hir_def/src/nameres/raw.rs | 4 ++-- crates/ra_hir_def/src/nameres/tests.rs | 8 ++++---- crates/ra_hir_def/src/nameres/tests/globs.rs | 4 ++-- crates/ra_hir_def/src/nameres/tests/macros.rs | 10 +++++----- .../src/nameres/tests/mod_resolution.rs | 2 +- 9 files changed, 41 insertions(+), 26 deletions(-) create mode 100644 crates/ra_hir_def/src/marks.rs diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs index 02bd808fc217..63ed2a09833b 100644 --- a/crates/ra_hir_def/src/lib.rs +++ b/crates/ra_hir_def/src/lib.rs @@ -17,6 +17,8 @@ pub mod diagnostics; #[cfg(test)] mod test_db; +#[cfg(test)] +mod marks; // FIXME: this should be private pub mod nameres; diff --git a/crates/ra_hir_def/src/marks.rs b/crates/ra_hir_def/src/marks.rs new file mode 100644 index 000000000000..0b99eac71749 --- /dev/null +++ b/crates/ra_hir_def/src/marks.rs @@ -0,0 +1,14 @@ +//! See test_utils/src/marks.rs + +test_utils::marks!( + bogus_paths + name_res_works_for_broken_modules + can_import_enum_variant + glob_enum + glob_across_crates + std_prelude + macro_rules_from_other_crates_are_visible_with_macro_use + prelude_is_macro_use + macro_dollar_crate_self + macro_dollar_crate_other +); diff --git a/crates/ra_hir_def/src/nameres.rs b/crates/ra_hir_def/src/nameres.rs index b3640da3d764..b5c682219349 100644 --- a/crates/ra_hir_def/src/nameres.rs +++ b/crates/ra_hir_def/src/nameres.rs @@ -18,7 +18,7 @@ use ra_db::{CrateId, Edition, FileId}; use ra_prof::profile; use ra_syntax::ast; use rustc_hash::{FxHashMap, FxHashSet}; -// use test_utils::tested_by; +use test_utils::tested_by; use crate::{ builtin_type::BuiltinType, @@ -263,12 +263,12 @@ impl CrateDefMap { let mut curr_per_ns: PerNs = match path.kind { PathKind::DollarCrate(krate) => { if krate == self.krate { - // tested_by!(macro_dollar_crate_self); + tested_by!(macro_dollar_crate_self); PerNs::types(ModuleId { krate: self.krate, module_id: self.root }.into()) } else { let def_map = db.crate_def_map(krate); let module = ModuleId { krate, module_id: def_map.root }; - // tested_by!(macro_dollar_crate_other); + tested_by!(macro_dollar_crate_other); PerNs::types(module.into()) } } @@ -369,7 +369,7 @@ impl CrateDefMap { } ModuleDefId::AdtId(AdtId::EnumId(e)) => { // enum variant - // tested_by!(can_import_enum_variant); + tested_by!(can_import_enum_variant); let enum_data = db.enum_data(e); match enum_data.variant(&segment.name) { Some(local_id) => { diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs index 0bc36910c3f0..3b61d9895bc3 100644 --- a/crates/ra_hir_def/src/nameres/collector.rs +++ b/crates/ra_hir_def/src/nameres/collector.rs @@ -8,7 +8,7 @@ use ra_cfg::CfgOptions; use ra_db::{CrateId, FileId}; use ra_syntax::{ast, SmolStr}; use rustc_hash::FxHashMap; -// use test_utils::tested_by; +use test_utils::tested_by; use crate::{ attr::Attr, @@ -218,7 +218,7 @@ where ); if let Some(ModuleDefId::ModuleId(m)) = res.take_types() { - // tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use); + tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use); self.import_all_macros_exported(current_module_id, m.krate); } } @@ -294,10 +294,10 @@ where match def.take_types() { Some(ModuleDefId::ModuleId(m)) => { if import.is_prelude { - // tested_by!(std_prelude); + tested_by!(std_prelude); self.def_map.prelude = Some(m); } else if m.krate != self.def_map.krate { - // tested_by!(glob_across_crates); + tested_by!(glob_across_crates); // glob import from other crate => we can just import everything once let item_map = self.db.crate_def_map(m.krate); let scope = &item_map[m.module_id].scope; @@ -332,7 +332,7 @@ where } } Some(ModuleDefId::AdtId(AdtId::EnumId(e))) => { - // tested_by!(glob_enum); + tested_by!(glob_enum); // glob import from enum => just import all the variants let enum_data = self.db.enum_data(e); let resolutions = enum_data @@ -373,8 +373,7 @@ where let resolution = Resolution { def, import: Some(import_id) }; self.update(module_id, Some(import_id), &[(name, resolution)]); } - // tested_by!(bogus_paths), - None => (), + None => tested_by!(bogus_paths), } } } @@ -534,7 +533,7 @@ where // Prelude module is always considered to be `#[macro_use]`. if let Some(prelude_module) = self.def_collector.def_map.prelude { if prelude_module.krate != self.def_collector.def_map.krate { - // tested_by!(prelude_is_macro_use); + tested_by!(prelude_is_macro_use); self.def_collector.import_all_macros_exported(self.module_id, prelude_module.krate); } } diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs index 86c05d6028e7..cb47fa317d2d 100644 --- a/crates/ra_hir_def/src/nameres/raw.rs +++ b/crates/ra_hir_def/src/nameres/raw.rs @@ -14,6 +14,7 @@ use ra_syntax::{ ast::{self, AttrsOwner, NameOwner}, AstNode, AstPtr, SourceFile, }; +use test_utils::tested_by; use crate::{attr::Attr, db::DefDatabase2, path::Path, FileAstId, HirFileId, ModuleSource, Source}; @@ -297,8 +298,7 @@ impl RawItemsCollector { self.push_item(current_module, attrs, RawItemKind::Module(item)); return; } - // FIXME: restore this mark once we complete hir splitting - // tested_by!(name_res_works_for_broken_modules); + tested_by!(name_res_works_for_broken_modules); } fn add_use_item(&mut self, current_module: Option, use_item: ast::UseItem) { diff --git a/crates/ra_hir_def/src/nameres/tests.rs b/crates/ra_hir_def/src/nameres/tests.rs index f9a8edd43c3c..52bd0aa91e8c 100644 --- a/crates/ra_hir_def/src/nameres/tests.rs +++ b/crates/ra_hir_def/src/nameres/tests.rs @@ -8,7 +8,7 @@ use std::sync::Arc; use insta::assert_snapshot; use ra_db::{fixture::WithFixture, SourceDatabase}; -// use test_utils::covers; +use test_utils::covers; use crate::{db::DefDatabase2, nameres::*, test_db::TestDB, CrateModuleId}; @@ -104,7 +104,7 @@ fn crate_def_map_smoke_test() { #[test] fn bogus_paths() { - // covers!(bogus_paths); + covers!(bogus_paths); let map = def_map( " //- /lib.rs @@ -219,7 +219,7 @@ fn re_exports() { #[test] fn std_prelude() { - // covers!(std_prelude); + covers!(std_prelude); let map = def_map( " //- /main.rs crate:main deps:test_crate @@ -243,7 +243,7 @@ fn std_prelude() { #[test] fn can_import_enum_variant() { - // covers!(can_import_enum_variant); + covers!(can_import_enum_variant); let map = def_map( " //- /lib.rs diff --git a/crates/ra_hir_def/src/nameres/tests/globs.rs b/crates/ra_hir_def/src/nameres/tests/globs.rs index cf4a2a851841..5b03fe36504a 100644 --- a/crates/ra_hir_def/src/nameres/tests/globs.rs +++ b/crates/ra_hir_def/src/nameres/tests/globs.rs @@ -75,7 +75,7 @@ fn glob_2() { #[test] fn glob_across_crates() { - // covers!(glob_across_crates); + covers!(glob_across_crates); let map = def_map( " //- /main.rs crate:main deps:test_crate @@ -94,7 +94,7 @@ fn glob_across_crates() { #[test] fn glob_enum() { - // covers!(glob_enum); + covers!(glob_enum); let map = def_map( " //- /lib.rs diff --git a/crates/ra_hir_def/src/nameres/tests/macros.rs b/crates/ra_hir_def/src/nameres/tests/macros.rs index 9bb3895ad6a5..704065633a5f 100644 --- a/crates/ra_hir_def/src/nameres/tests/macros.rs +++ b/crates/ra_hir_def/src/nameres/tests/macros.rs @@ -175,7 +175,7 @@ fn unexpanded_macro_should_expand_by_fixedpoint_loop() { #[test] fn macro_rules_from_other_crates_are_visible_with_macro_use() { - // covers!(macro_rules_from_other_crates_are_visible_with_macro_use); + covers!(macro_rules_from_other_crates_are_visible_with_macro_use); let map = def_map( " //- /main.rs crate:main deps:foo @@ -225,7 +225,7 @@ fn macro_rules_from_other_crates_are_visible_with_macro_use() { #[test] fn prelude_is_macro_use() { - // covers!(prelude_is_macro_use); + covers!(prelude_is_macro_use); let map = def_map( " //- /main.rs crate:main deps:foo @@ -507,8 +507,8 @@ fn path_qualified_macros() { #[test] fn macro_dollar_crate_is_correct_in_item() { - // covers!(macro_dollar_crate_self); - // covers!(macro_dollar_crate_other); + covers!(macro_dollar_crate_self); + covers!(macro_dollar_crate_other); let map = def_map( " //- /main.rs crate:main deps:foo @@ -566,7 +566,7 @@ fn macro_dollar_crate_is_correct_in_item() { #[test] fn macro_dollar_crate_is_correct_in_indirect_deps() { - // covers!(macro_dollar_crate_other); + covers!(macro_dollar_crate_other); // From std let map = def_map( r#" diff --git a/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs b/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs index 8d804a63e8b4..dee364a1422f 100644 --- a/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs +++ b/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs @@ -2,7 +2,7 @@ use super::*; #[test] fn name_res_works_for_broken_modules() { - // covers!(name_res_works_for_broken_modules); + covers!(name_res_works_for_broken_modules); let map = def_map( " //- /lib.rs From f0eb9cc6e66a65d2df42c662499ebd77ea980de5 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 3 Nov 2019 23:49:44 +0300 Subject: [PATCH 17/21] Remove last traces of nameres from hir --- crates/ra_hir/src/code_model.rs | 3 +- crates/ra_hir/src/db.rs | 3 +- crates/ra_hir/src/lib.rs | 6 ++-- crates/ra_hir/src/nameres.rs | 53 ------------------------------ crates/ra_hir/src/resolve.rs | 4 +-- crates/ra_hir/src/ty/infer/expr.rs | 3 +- crates/ra_hir/src/ty/lower.rs | 5 ++- crates/ra_hir_def/src/nameres.rs | 49 ++++++++++++++++++++++++++- 8 files changed, 59 insertions(+), 67 deletions(-) delete mode 100644 crates/ra_hir/src/nameres.rs diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index f03b59217fe0..181c5d47afeb 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs @@ -28,11 +28,10 @@ use crate::{ TypeAliasId, }, impl_block::ImplBlock, - nameres::{ImportId, Namespace}, resolve::{Resolver, Scope, TypeNs}, traits::TraitData, ty::{InferenceResult, TraitRef}, - Either, HasSource, Name, ScopeDef, Ty, + Either, HasSource, Name, ScopeDef, Ty, {ImportId, Namespace}, }; /// hir::Crate describes a single crate. It's the main interface with which diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index f45804c7ce90..eb66325f7f12 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs @@ -11,14 +11,13 @@ use crate::{ ids, impl_block::{ImplBlock, ImplSourceMap, ModuleImplBlocks}, lang_item::{LangItemTarget, LangItems}, - nameres::Namespace, traits::TraitData, ty::{ method_resolution::CrateImplBlocks, traits::Impl, CallableDef, FnSig, GenericPredicate, InferenceResult, Substs, Ty, TypableDef, TypeCtor, }, type_alias::TypeAliasData, - Const, ConstData, Crate, DefWithBody, ExprScopes, FnData, Function, Module, Static, + Const, ConstData, Crate, DefWithBody, ExprScopes, FnData, Function, Module, Namespace, Static, StructField, Trait, TypeAlias, }; diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 52bad22284b9..3ba99d92d703 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs @@ -34,7 +34,6 @@ pub mod mock; pub mod source_binder; mod ids; -mod nameres; mod adt; mod traits; mod type_alias; @@ -73,7 +72,6 @@ pub use crate::{ generics::{GenericDef, GenericParam, GenericParams, HasGenericParams}, ids::{HirFileId, MacroCallId, MacroCallLoc, MacroDefId, MacroFile}, impl_block::ImplBlock, - nameres::{ImportId, Namespace, PerNs}, resolve::ScopeDef, source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer}, ty::{ @@ -83,6 +81,10 @@ pub use crate::{ pub use hir_def::{ builtin_type::BuiltinType, + nameres::{ + per_ns::{Namespace, PerNs}, + raw::ImportId, + }, path::{Path, PathKind}, type_ref::Mutability, }; diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs deleted file mode 100644 index 875addc84a5e..000000000000 --- a/crates/ra_hir/src/nameres.rs +++ /dev/null @@ -1,53 +0,0 @@ -//! This module implements import-resolution/macro expansion algorithm. -//! -//! The result of this module is `CrateDefMap`: a data structure which contains: -//! -//! * a tree of modules for the crate -//! * for each module, a set of items visible in the module (directly declared -//! or imported) -//! -//! Note that `CrateDefMap` contains fully macro expanded code. -//! -//! Computing `CrateDefMap` can be partitioned into several logically -//! independent "phases". The phases are mutually recursive though, there's no -//! strict ordering. -//! -//! ## Collecting RawItems -//! -//! This happens in the `raw` module, which parses a single source file into a -//! set of top-level items. Nested imports are desugared to flat imports in -//! this phase. Macro calls are represented as a triple of (Path, Option, -//! TokenTree). -//! -//! ## Collecting Modules -//! -//! This happens in the `collector` module. In this phase, we recursively walk -//! tree of modules, collect raw items from submodules, populate module scopes -//! with defined items (so, we assign item ids in this phase) and record the set -//! of unresolved imports and macros. -//! -//! While we walk tree of modules, we also record macro_rules definitions and -//! expand calls to macro_rules defined macros. -//! -//! ## Resolving Imports -//! -//! We maintain a list of currently unresolved imports. On every iteration, we -//! try to resolve some imports from this list. If the import is resolved, we -//! record it, by adding an item to current module scope and, if necessary, by -//! recursively populating glob imports. -//! -//! ## Resolving Macros -//! -//! macro_rules from the same crate use a global mutable namespace. We expand -//! them immediately, when we collect modules. -//! -//! Macros from other crates (including proc-macros) can be used with -//! `foo::bar!` syntax. We handle them similarly to imports. There's a list of -//! unexpanded macros. On every iteration, we try to resolve each macro call -//! path and, upon success, we run macro expansion and "collect module" phase -//! on the result - -pub use hir_def::nameres::{ - per_ns::{Namespace, PerNs}, - raw::ImportId, -}; diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs index 3e3f8c252e2e..b932b0c8cdbc 100644 --- a/crates/ra_hir/src/resolve.rs +++ b/crates/ra_hir/src/resolve.rs @@ -19,8 +19,8 @@ use crate::{ }, generics::GenericParams, impl_block::ImplBlock, - nameres::PerNs, - Adt, Const, Enum, EnumVariant, Function, MacroDef, ModuleDef, Static, Struct, Trait, TypeAlias, + Adt, Const, Enum, EnumVariant, Function, MacroDef, ModuleDef, PerNs, Static, Struct, Trait, + TypeAlias, }; #[derive(Debug, Clone, Default)] diff --git a/crates/ra_hir/src/ty/infer/expr.rs b/crates/ra_hir/src/ty/infer/expr.rs index fed52df39cef..a09ef5c5d3af 100644 --- a/crates/ra_hir/src/ty/infer/expr.rs +++ b/crates/ra_hir/src/ty/infer/expr.rs @@ -11,12 +11,11 @@ use crate::{ db::HirDatabase, expr::{self, Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp}, generics::{GenericParams, HasGenericParams}, - nameres::Namespace, ty::{ autoderef, method_resolution, op, primitive, CallableDef, InferTy, Mutability, Obligation, ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk, }, - Adt, Name, + Adt, Name, Namespace, }; impl<'a, D: HirDatabase> InferenceContext<'a, D> { diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index 8e28343071a2..e29ab8492a5e 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs @@ -23,15 +23,14 @@ use crate::{ db::HirDatabase, generics::HasGenericParams, generics::{GenericDef, WherePredicate}, - nameres::Namespace, resolve::{Resolver, TypeNs}, ty::{ primitive::{FloatTy, IntTy}, Adt, }, util::make_mut_slice, - Const, Enum, EnumVariant, Function, ModuleDef, Path, Static, Struct, StructField, Trait, - TypeAlias, Union, + Const, Enum, EnumVariant, Function, ModuleDef, Namespace, Path, Static, Struct, StructField, + Trait, TypeAlias, Union, }; impl Ty { diff --git a/crates/ra_hir_def/src/nameres.rs b/crates/ra_hir_def/src/nameres.rs index b5c682219349..fbd4248e6a74 100644 --- a/crates/ra_hir_def/src/nameres.rs +++ b/crates/ra_hir_def/src/nameres.rs @@ -1,4 +1,51 @@ -//! FIXME: write short doc here +//! This module implements import-resolution/macro expansion algorithm. +//! +//! The result of this module is `CrateDefMap`: a data structure which contains: +//! +//! * a tree of modules for the crate +//! * for each module, a set of items visible in the module (directly declared +//! or imported) +//! +//! Note that `CrateDefMap` contains fully macro expanded code. +//! +//! Computing `CrateDefMap` can be partitioned into several logically +//! independent "phases". The phases are mutually recursive though, there's no +//! strict ordering. +//! +//! ## Collecting RawItems +//! +//! This happens in the `raw` module, which parses a single source file into a +//! set of top-level items. Nested imports are desugared to flat imports in +//! this phase. Macro calls are represented as a triple of (Path, Option, +//! TokenTree). +//! +//! ## Collecting Modules +//! +//! This happens in the `collector` module. In this phase, we recursively walk +//! tree of modules, collect raw items from submodules, populate module scopes +//! with defined items (so, we assign item ids in this phase) and record the set +//! of unresolved imports and macros. +//! +//! While we walk tree of modules, we also record macro_rules definitions and +//! expand calls to macro_rules defined macros. +//! +//! ## Resolving Imports +//! +//! We maintain a list of currently unresolved imports. On every iteration, we +//! try to resolve some imports from this list. If the import is resolved, we +//! record it, by adding an item to current module scope and, if necessary, by +//! recursively populating glob imports. +//! +//! ## Resolving Macros +//! +//! macro_rules from the same crate use a global mutable namespace. We expand +//! them immediately, when we collect modules. +//! +//! Macros from other crates (including proc-macros) can be used with +//! `foo::bar!` syntax. We handle them similarly to imports. There's a list of +//! unexpanded macros. On every iteration, we try to resolve each macro call +//! path and, upon success, we run macro expansion and "collect module" phase +//! on the result // FIXME: review privacy of submodules pub mod raw; From 8922a44395482896fec0c0a47a7fac4612112d45 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 4 Nov 2019 00:11:37 +0300 Subject: [PATCH 18/21] Add small module-level docs --- crates/ra_hir/src/from_id.rs | 5 +++++ crates/ra_hir_def/src/diagnostics.rs | 2 ++ crates/ra_hir_def/src/test_db.rs | 2 ++ xtask/tests/tidy-tests/docs.rs | 15 +++++++++------ 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/crates/ra_hir/src/from_id.rs b/crates/ra_hir/src/from_id.rs index c08203bca7ea..089dbc9084a4 100644 --- a/crates/ra_hir/src/from_id.rs +++ b/crates/ra_hir/src/from_id.rs @@ -1,3 +1,8 @@ +//! Utility module for converting between hir_def ids and code_model wrappers. +//! +//! It's unclear if we need this long-term, but it's definitelly useful while we +//! are splitting the hir. + use hir_def::{AdtId, EnumVariantId, ModuleDefId}; use crate::{Adt, EnumVariant, ModuleDef}; diff --git a/crates/ra_hir_def/src/diagnostics.rs b/crates/ra_hir_def/src/diagnostics.rs index 637184c58229..1c1ccdecb72f 100644 --- a/crates/ra_hir_def/src/diagnostics.rs +++ b/crates/ra_hir_def/src/diagnostics.rs @@ -1,3 +1,5 @@ +//! Diagnostics produced by `hir_def`. + use std::any::Any; use hir_expand::diagnostics::Diagnostic; diff --git a/crates/ra_hir_def/src/test_db.rs b/crates/ra_hir_def/src/test_db.rs index 05018f8e43c2..f91a5b41df2b 100644 --- a/crates/ra_hir_def/src/test_db.rs +++ b/crates/ra_hir_def/src/test_db.rs @@ -1,3 +1,5 @@ +//! Database used for testing `hir_def`. + use std::{ panic, sync::{Arc, Mutex}, diff --git a/xtask/tests/tidy-tests/docs.rs b/xtask/tests/tidy-tests/docs.rs index 6a629ce63e8f..227937f462a6 100644 --- a/xtask/tests/tidy-tests/docs.rs +++ b/xtask/tests/tidy-tests/docs.rs @@ -36,6 +36,7 @@ fn is_hidden(entry: &DirEntry) -> bool { fn no_docs_comments() { let crates = project_root().join("crates"); let iter = WalkDir::new(crates); + let mut missing_docs = Vec::new(); for f in iter.into_iter().filter_entry(|e| !is_hidden(e)) { let f = f.unwrap(); if f.file_type().is_dir() { @@ -54,12 +55,14 @@ fn no_docs_comments() { let mut line = String::new(); reader.read_line(&mut line).unwrap(); if !line.starts_with("//!") { - panic!( - "\nMissing docs strings\n\ - module: {}\n\ - Need add doc for module\n", - f.path().display() - ) + missing_docs.push(f.path().display().to_string()); } } + if !missing_docs.is_empty() { + panic!( + "\nMissing docs strings\n\n\ + modules:\n{}\n\n", + missing_docs.join("\n") + ) + } } From 3603d0213480c7b3423345d21243397eb904a073 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 4 Nov 2019 01:14:17 +0300 Subject: [PATCH 19/21] Reexport relative_path from ra_db --- Cargo.lock | 3 --- crates/ra_db/src/input.rs | 3 ++- crates/ra_hir/Cargo.toml | 1 - crates/ra_hir/src/mock.rs | 3 +-- crates/ra_hir_def/Cargo.toml | 2 -- crates/ra_hir_def/src/diagnostics.rs | 2 +- crates/ra_hir_def/src/nameres.rs | 2 +- crates/ra_hir_def/src/nameres/mod_resolution.rs | 3 +-- crates/ra_hir_def/src/test_db.rs | 3 +-- crates/ra_ide_api/Cargo.toml | 1 - crates/ra_ide_api/src/change.rs | 4 ++-- crates/ra_ide_api/src/db.rs | 5 ++--- crates/ra_ide_api/src/diagnostics.rs | 3 +-- crates/ra_ide_api/src/mock_analysis.rs | 2 +- crates/ra_ide_api/src/references/rename.rs | 3 +-- crates/ra_ide_api/src/source_change.rs | 2 +- 16 files changed, 15 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 889820c99612..3879204d9e7a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1019,7 +1019,6 @@ dependencies = [ "ra_prof 0.1.0", "ra_syntax 0.1.0", "ra_tt 0.1.0", - "relative-path 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "test_utils 0.1.0", ] @@ -1039,7 +1038,6 @@ dependencies = [ "ra_prof 0.1.0", "ra_syntax 0.1.0", "ra_tt 0.1.0", - "relative-path 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "test_utils 0.1.0", ] @@ -1079,7 +1077,6 @@ dependencies = [ "ra_text_edit 0.1.0", "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "relative-path 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "superslice 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "test_utils 0.1.0", diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs index 7c8dac1d38da..60f7dc881565 100644 --- a/crates/ra_db/src/input.rs +++ b/crates/ra_db/src/input.rs @@ -6,13 +6,14 @@ //! actual IO. See `vfs` and `project_model` in the `ra_lsp_server` crate for how //! actual IO is done and lowered to input. -use relative_path::{RelativePath, RelativePathBuf}; use rustc_hash::FxHashMap; use ra_cfg::CfgOptions; use ra_syntax::SmolStr; use rustc_hash::FxHashSet; +use crate::{RelativePath, RelativePathBuf}; + /// `FileId` is an integer which uniquely identifies a file. File paths are /// messy and system-dependent, so most of the code should work directly with /// `FileId`, without inspecting the path. The mapping between `FileId` and path diff --git a/crates/ra_hir/Cargo.toml b/crates/ra_hir/Cargo.toml index fae5dc7cb526..324961328487 100644 --- a/crates/ra_hir/Cargo.toml +++ b/crates/ra_hir/Cargo.toml @@ -7,7 +7,6 @@ authors = ["rust-analyzer developers"] [dependencies] arrayvec = "0.5.1" log = "0.4.5" -relative-path = "1.0.0" rustc-hash = "1.0" parking_lot = "0.9.0" ena = "0.13" diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs index 4c89c8d38438..8d98f88ce174 100644 --- a/crates/ra_hir/src/mock.rs +++ b/crates/ra_hir/src/mock.rs @@ -7,9 +7,8 @@ use parking_lot::Mutex; use ra_cfg::CfgOptions; use ra_db::{ salsa, CrateGraph, CrateId, Edition, FileId, FileLoader, FileLoaderDelegate, FilePosition, - SourceDatabase, SourceDatabaseExt, SourceRoot, SourceRootId, + RelativePath, RelativePathBuf, SourceDatabase, SourceDatabaseExt, SourceRoot, SourceRootId, }; -use relative_path::{RelativePath, RelativePathBuf}; use rustc_hash::FxHashMap; use test_utils::{extract_offset, parse_fixture, CURSOR_MARKER}; diff --git a/crates/ra_hir_def/Cargo.toml b/crates/ra_hir_def/Cargo.toml index 15055db64e59..21262be79598 100644 --- a/crates/ra_hir_def/Cargo.toml +++ b/crates/ra_hir_def/Cargo.toml @@ -7,7 +7,6 @@ authors = ["rust-analyzer developers"] [dependencies] log = "0.4.5" once_cell = "1.0.1" -relative-path = "1.0.0" rustc-hash = "1.0" ra_arena = { path = "../ra_arena" } @@ -22,4 +21,3 @@ tt = { path = "../ra_tt", package = "ra_tt" } [dev-dependencies] insta = "0.12.0" - diff --git a/crates/ra_hir_def/src/diagnostics.rs b/crates/ra_hir_def/src/diagnostics.rs index 1c1ccdecb72f..9843009a5dc6 100644 --- a/crates/ra_hir_def/src/diagnostics.rs +++ b/crates/ra_hir_def/src/diagnostics.rs @@ -3,8 +3,8 @@ use std::any::Any; use hir_expand::diagnostics::Diagnostic; +use ra_db::RelativePathBuf; use ra_syntax::{ast, AstPtr, SyntaxNodePtr}; -use relative_path::RelativePathBuf; use hir_expand::{HirFileId, Source}; diff --git a/crates/ra_hir_def/src/nameres.rs b/crates/ra_hir_def/src/nameres.rs index fbd4248e6a74..433bdde48f7f 100644 --- a/crates/ra_hir_def/src/nameres.rs +++ b/crates/ra_hir_def/src/nameres.rs @@ -504,8 +504,8 @@ impl CrateDefMap { mod diagnostics { use hir_expand::diagnostics::DiagnosticSink; + use ra_db::RelativePathBuf; use ra_syntax::{ast, AstPtr}; - use relative_path::RelativePathBuf; use crate::{db::DefDatabase2, diagnostics::UnresolvedModule, nameres::CrateModuleId, AstId}; diff --git a/crates/ra_hir_def/src/nameres/mod_resolution.rs b/crates/ra_hir_def/src/nameres/mod_resolution.rs index 7d7e2779aa20..f6b0b8fb1ec6 100644 --- a/crates/ra_hir_def/src/nameres/mod_resolution.rs +++ b/crates/ra_hir_def/src/nameres/mod_resolution.rs @@ -1,8 +1,7 @@ //! This module resolves `mod foo;` declaration to file. use hir_expand::name::Name; -use ra_db::FileId; +use ra_db::{FileId, RelativePathBuf}; use ra_syntax::SmolStr; -use relative_path::RelativePathBuf; use crate::{db::DefDatabase2, HirFileId}; diff --git a/crates/ra_hir_def/src/test_db.rs b/crates/ra_hir_def/src/test_db.rs index f91a5b41df2b..8ee8e40d0814 100644 --- a/crates/ra_hir_def/src/test_db.rs +++ b/crates/ra_hir_def/src/test_db.rs @@ -5,8 +5,7 @@ use std::{ sync::{Arc, Mutex}, }; -use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate}; -use relative_path::RelativePath; +use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, RelativePath}; #[salsa::database( ra_db::SourceDatabaseExtStorage, diff --git a/crates/ra_ide_api/Cargo.toml b/crates/ra_ide_api/Cargo.toml index bf6ef12f3ffb..fa353b5dd8f2 100644 --- a/crates/ra_ide_api/Cargo.toml +++ b/crates/ra_ide_api/Cargo.toml @@ -12,7 +12,6 @@ format-buf = "1.0.0" itertools = "0.8.0" join_to_string = "0.1.3" log = "0.4.5" -relative-path = "1.0.0" rayon = "1.0.2" fst = { version = "0.3.1", default-features = false } rustc-hash = "1.0" diff --git a/crates/ra_ide_api/src/change.rs b/crates/ra_ide_api/src/change.rs index 39c5946c7f18..4416421ae013 100644 --- a/crates/ra_ide_api/src/change.rs +++ b/crates/ra_ide_api/src/change.rs @@ -4,13 +4,13 @@ use std::{fmt, sync::Arc, time}; use ra_db::{ salsa::{Database, Durability, SweepStrategy}, - CrateGraph, CrateId, FileId, SourceDatabase, SourceDatabaseExt, SourceRoot, SourceRootId, + CrateGraph, CrateId, FileId, RelativePathBuf, SourceDatabase, SourceDatabaseExt, SourceRoot, + SourceRootId, }; use ra_prof::{memory_usage, profile, Bytes}; use ra_syntax::SourceFile; #[cfg(not(feature = "wasm"))] use rayon::prelude::*; -use relative_path::RelativePathBuf; use rustc_hash::FxHashMap; use crate::{ diff --git a/crates/ra_ide_api/src/db.rs b/crates/ra_ide_api/src/db.rs index 785e71808b7c..c96465b6a3d9 100644 --- a/crates/ra_ide_api/src/db.rs +++ b/crates/ra_ide_api/src/db.rs @@ -4,10 +4,9 @@ use std::sync::Arc; use ra_db::{ salsa::{self, Database, Durability}, - Canceled, CheckCanceled, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, - SourceDatabaseExt, SourceRootId, + Canceled, CheckCanceled, CrateId, FileId, FileLoader, FileLoaderDelegate, RelativePath, + SourceDatabase, SourceDatabaseExt, SourceRootId, }; -use relative_path::RelativePath; use rustc_hash::FxHashMap; use crate::{ diff --git a/crates/ra_ide_api/src/diagnostics.rs b/crates/ra_ide_api/src/diagnostics.rs index 1f1f5cd742c9..2890a3d2b519 100644 --- a/crates/ra_ide_api/src/diagnostics.rs +++ b/crates/ra_ide_api/src/diagnostics.rs @@ -4,7 +4,7 @@ use std::cell::RefCell; use hir::diagnostics::{AstDiagnostic, Diagnostic as _, DiagnosticSink}; use itertools::Itertools; -use ra_db::{SourceDatabase, SourceDatabaseExt}; +use ra_db::{RelativePath, SourceDatabase, SourceDatabaseExt}; use ra_prof::profile; use ra_syntax::{ algo, @@ -12,7 +12,6 @@ use ra_syntax::{ Location, SyntaxNode, TextRange, T, }; use ra_text_edit::{TextEdit, TextEditBuilder}; -use relative_path::RelativePath; use crate::{db::RootDatabase, Diagnostic, FileId, FileSystemEdit, SourceChange, SourceFileEdit}; diff --git a/crates/ra_ide_api/src/mock_analysis.rs b/crates/ra_ide_api/src/mock_analysis.rs index 80b71894cdf6..2b1c96dbfd5b 100644 --- a/crates/ra_ide_api/src/mock_analysis.rs +++ b/crates/ra_ide_api/src/mock_analysis.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use ra_cfg::CfgOptions; -use relative_path::RelativePathBuf; +use ra_db::RelativePathBuf; use test_utils::{extract_offset, extract_range, parse_fixture, CURSOR_MARKER}; use crate::{ diff --git a/crates/ra_ide_api/src/references/rename.rs b/crates/ra_ide_api/src/references/rename.rs index a8783d7a0dc4..11f81cbb32f4 100644 --- a/crates/ra_ide_api/src/references/rename.rs +++ b/crates/ra_ide_api/src/references/rename.rs @@ -1,10 +1,9 @@ //! FIXME: write short doc here use hir::ModuleSource; -use ra_db::{SourceDatabase, SourceDatabaseExt}; +use ra_db::{RelativePath, RelativePathBuf, SourceDatabase, SourceDatabaseExt}; use ra_syntax::{algo::find_node_at_offset, ast, AstNode, SyntaxNode}; use ra_text_edit::TextEdit; -use relative_path::{RelativePath, RelativePathBuf}; use crate::{ db::RootDatabase, FileId, FilePosition, FileSystemEdit, RangeInfo, SourceChange, diff --git a/crates/ra_ide_api/src/source_change.rs b/crates/ra_ide_api/src/source_change.rs index 4e63bbf6f0c8..f5f7f8807c44 100644 --- a/crates/ra_ide_api/src/source_change.rs +++ b/crates/ra_ide_api/src/source_change.rs @@ -3,8 +3,8 @@ //! //! It can be viewed as a dual for `AnalysisChange`. +use ra_db::RelativePathBuf; use ra_text_edit::TextEdit; -use relative_path::RelativePathBuf; use crate::{FileId, FilePosition, SourceRootId, TextUnit}; From dfdb6321acbe30704ef07ba7a2257f860a7a1398 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 4 Nov 2019 13:25:42 +0300 Subject: [PATCH 20/21] Use new text DSL instead of crate_graph! macro --- crates/ra_hir/src/marks.rs | 1 - crates/ra_hir/src/mock.rs | 68 ---------------------------- crates/ra_hir/src/ty/tests.rs | 84 +++++++++++------------------------ 3 files changed, 25 insertions(+), 128 deletions(-) diff --git a/crates/ra_hir/src/marks.rs b/crates/ra_hir/src/marks.rs index b423489a1117..c086e5bedc0f 100644 --- a/crates/ra_hir/src/marks.rs +++ b/crates/ra_hir/src/marks.rs @@ -17,5 +17,4 @@ test_utils::marks!( prelude_is_macro_use coerce_merge_fail_fallback macro_dollar_crate_self - macro_dollar_crate_other ); diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs index 8d98f88ce174..ab97a09b9114 100644 --- a/crates/ra_hir/src/mock.rs +++ b/crates/ra_hir/src/mock.rs @@ -77,12 +77,6 @@ impl MockDatabase { (db, source_root, file_id) } - pub fn with_position(fixture: &str) -> (MockDatabase, FilePosition) { - let (db, position) = MockDatabase::from_fixture(fixture); - let position = position.expect("expected a marker ( <|> )"); - (db, position) - } - pub fn file_id_of(&self, path: &str) -> FileId { match self.files.get(path) { Some(it) => *it, @@ -90,25 +84,6 @@ impl MockDatabase { } } - pub fn set_crate_graph_from_fixture(&mut self, graph: CrateGraphFixture) { - let mut ids = FxHashMap::default(); - let mut crate_graph = CrateGraph::default(); - for (crate_name, (crate_root, edition, cfg_options, _)) in graph.0.iter() { - let crate_root = self.file_id_of(&crate_root); - let crate_id = crate_graph.add_crate_root(crate_root, *edition, cfg_options.clone()); - Arc::make_mut(&mut self.crate_names).insert(crate_id, crate_name.clone()); - ids.insert(crate_name, crate_id); - } - for (crate_name, (_, _, _, deps)) in graph.0.iter() { - let from = ids[crate_name]; - for dep in deps { - let to = ids[dep]; - crate_graph.add_dep(from, dep.as_str().into(), to).unwrap(); - } - } - self.set_crate_graph(Arc::new(crate_graph)) - } - pub fn diagnostics(&self) -> String { let mut buf = String::new(); let mut files: Vec = self.files.values().copied().collect(); @@ -285,46 +260,3 @@ impl MockDatabase { .collect() } } - -#[derive(Default)] -pub struct CrateGraphFixture(pub Vec<(String, (String, Edition, CfgOptions, Vec))>); - -#[macro_export] -macro_rules! crate_graph { - ($( - $crate_name:literal: ( - $crate_path:literal, - $($edition:literal,)? - [$($dep:literal),*] - $(, cfg = { - $($key:literal $(= $value:literal)?),* - $(,)? - })? - ), - )*) => {{ - let mut res = $crate::mock::CrateGraphFixture::default(); - $( - #[allow(unused_mut, unused_assignments)] - let mut edition = ra_db::Edition::Edition2018; - $(edition = ra_db::Edition::from_string($edition);)? - let cfg_options = { - #[allow(unused_mut)] - let mut cfg = ::ra_cfg::CfgOptions::default(); - $( - $( - if 0 == 0 $(+ { drop($value); 1})? { - cfg.insert_atom($key.into()); - } - $(cfg.insert_key_value($key.into(), $value.into());)? - )* - )? - cfg - }; - res.0.push(( - $crate_name.to_string(), - ($crate_path.to_string(), edition, cfg_options, vec![$($dep.to_string()),*]) - )); - )* - res - }} -} diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index f271557377d0..4b7e34878acd 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs @@ -2,8 +2,7 @@ use std::fmt::Write; use std::sync::Arc; use insta::assert_snapshot; - -use ra_db::{salsa::Database, FilePosition, SourceDatabase}; +use ra_db::{fixture::WithFixture, salsa::Database, FilePosition, SourceDatabase}; use ra_syntax::{ algo, ast::{self, AstNode}, @@ -25,9 +24,9 @@ mod coercion; #[test] fn cfg_impl_block() { - let (mut db, pos) = MockDatabase::with_position( + let (db, pos) = MockDatabase::with_position( r#" -//- /main.rs +//- /main.rs crate:main deps:foo cfg:test use foo::S as T; struct S; @@ -46,7 +45,7 @@ fn test() { t<|>; } -//- /foo.rs +//- /foo.rs crate:foo struct S; #[cfg(not(test))] @@ -60,18 +59,14 @@ impl S { } "#, ); - db.set_crate_graph_from_fixture(crate_graph! { - "main": ("/main.rs", ["foo"], cfg = { "test" }), - "foo": ("/foo.rs", []), - }); assert_eq!("(i32, {unknown}, i32, {unknown})", type_at_pos(&db, pos)); } #[test] fn infer_await() { - let (mut db, pos) = MockDatabase::with_position( + let (db, pos) = MockDatabase::with_position( r#" -//- /main.rs +//- /main.rs crate:main deps:std struct IntFuture; @@ -85,7 +80,7 @@ fn test() { v<|>; } -//- /std.rs +//- /std.rs crate:std #[prelude_import] use future::*; mod future { trait Future { @@ -95,18 +90,14 @@ mod future { "#, ); - db.set_crate_graph_from_fixture(crate_graph! { - "main": ("/main.rs", ["std"]), - "std": ("/std.rs", []), - }); assert_eq!("u64", type_at_pos(&db, pos)); } #[test] fn infer_box() { - let (mut db, pos) = MockDatabase::with_position( + let (db, pos) = MockDatabase::with_position( r#" -//- /main.rs +//- /main.rs crate:main deps:std fn test() { let x = box 1; @@ -114,7 +105,7 @@ fn test() { t<|>; } -//- /std.rs +//- /std.rs crate:std #[prelude_import] use prelude::*; mod prelude {} @@ -126,10 +117,6 @@ mod boxed { "#, ); - db.set_crate_graph_from_fixture(crate_graph! { - "main": ("/main.rs", ["std"]), - "std": ("/std.rs", []), - }); assert_eq!("(Box, Box>, Box<&i32>, Box<[i32;_]>)", type_at_pos(&db, pos)); } @@ -154,9 +141,9 @@ fn test() { #[test] fn infer_try() { - let (mut db, pos) = MockDatabase::with_position( + let (db, pos) = MockDatabase::with_position( r#" -//- /main.rs +//- /main.rs crate:main deps:std fn test() { let r: Result = Result::Ok(1); @@ -164,7 +151,7 @@ fn test() { v<|>; } -//- /std.rs +//- /std.rs crate:std #[prelude_import] use ops::*; mod ops { @@ -189,18 +176,14 @@ mod result { "#, ); - db.set_crate_graph_from_fixture(crate_graph! { - "main": ("/main.rs", ["std"]), - "std": ("/std.rs", []), - }); assert_eq!("i32", type_at_pos(&db, pos)); } #[test] fn infer_for_loop() { - let (mut db, pos) = MockDatabase::with_position( + let (db, pos) = MockDatabase::with_position( r#" -//- /main.rs +//- /main.rs crate:main deps:std use std::collections::Vec; @@ -212,7 +195,7 @@ fn test() { } } -//- /std.rs +//- /std.rs crate:std #[prelude_import] use iter::*; mod iter { @@ -234,10 +217,6 @@ mod collections { } "#, ); - db.set_crate_graph_from_fixture(crate_graph! { - "main": ("/main.rs", ["std"]), - "std": ("/std.rs", []), - }); assert_eq!("&str", type_at_pos(&db, pos)); } @@ -2505,15 +2484,15 @@ pub fn main_loop() { #[test] fn cross_crate_associated_method_call() { - let (mut db, pos) = MockDatabase::with_position( + let (db, pos) = MockDatabase::with_position( r#" -//- /main.rs +//- /main.rs crate:main deps:other_crate fn test() { let x = other_crate::foo::S::thing(); x<|>; } -//- /lib.rs +//- /lib.rs crate:other_crate mod foo { struct S; impl S { @@ -2522,10 +2501,6 @@ mod foo { } "#, ); - db.set_crate_graph_from_fixture(crate_graph! { - "main": ("/main.rs", ["other_crate"]), - "other_crate": ("/lib.rs", []), - }); assert_eq!("i128", type_at_pos(&db, pos)); } @@ -3403,16 +3378,15 @@ fn test() { S.foo()<|>; } #[test] fn infer_macro_with_dollar_crate_is_correct_in_expr() { - // covers!(macro_dollar_crate_other); - let (mut db, pos) = MockDatabase::with_position( + let (db, pos) = MockDatabase::with_position( r#" -//- /main.rs +//- /main.rs crate:main deps:foo fn test() { let x = (foo::foo!(1), foo::foo!(2)); x<|>; } -//- /lib.rs +//- /lib.rs crate:foo #[macro_export] macro_rules! foo { (1) => { $crate::bar!() }; @@ -3427,10 +3401,6 @@ macro_rules! bar { pub fn baz() -> usize { 31usize } "#, ); - db.set_crate_graph_from_fixture(crate_graph! { - "main": ("/main.rs", ["foo"]), - "foo": ("/lib.rs", []), - }); assert_eq!("(i32, usize)", type_at_pos(&db, pos)); } @@ -3512,9 +3482,9 @@ fn test() { (&S).foo()<|>; } #[test] fn method_resolution_trait_from_prelude() { - let (mut db, pos) = MockDatabase::with_position( + let (db, pos) = MockDatabase::with_position( r#" -//- /main.rs +//- /main.rs crate:main deps:other_crate struct S; impl Clone for S {} @@ -3522,7 +3492,7 @@ fn test() { S.clone()<|>; } -//- /lib.rs +//- /lib.rs crate:other_crate #[prelude_import] use foo::*; mod foo { @@ -3532,10 +3502,6 @@ mod foo { } "#, ); - db.set_crate_graph_from_fixture(crate_graph! { - "main": ("/main.rs", ["other_crate"]), - "other_crate": ("/lib.rs", []), - }); assert_eq!("S", type_at_pos(&db, pos)); } From 38b941db13efb18e203490b1ac078fa0ddd0eaf4 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Mon, 4 Nov 2019 13:29:07 +0300 Subject: [PATCH 21/21] Cleanup unused marks --- crates/ra_hir/src/marks.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/crates/ra_hir/src/marks.rs b/crates/ra_hir/src/marks.rs index c086e5bedc0f..0d4fa5b67363 100644 --- a/crates/ra_hir/src/marks.rs +++ b/crates/ra_hir/src/marks.rs @@ -1,20 +1,10 @@ //! See test_utils/src/marks.rs test_utils::marks!( - bogus_paths - // FIXME: restore this mark once hir is split - name_res_works_for_broken_modules - can_import_enum_variant type_var_cycles_resolve_completely type_var_cycles_resolve_as_possible type_var_resolves_to_int_var - glob_enum - glob_across_crates - std_prelude match_ergonomics_ref infer_while_let - macro_rules_from_other_crates_are_visible_with_macro_use - prelude_is_macro_use coerce_merge_fail_fallback - macro_dollar_crate_self );