From d8eb839305a43521b155cf741210a5c11a188924 Mon Sep 17 00:00:00 2001 From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com> Date: Fri, 27 Dec 2024 10:57:08 -0600 Subject: [PATCH 001/115] Rename dependency tree view and dependency provider --- .../editors/code/src/commands.ts | 10 +++---- .../rust-analyzer/editors/code/src/ctx.ts | 26 +++++++++---------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/tools/rust-analyzer/editors/code/src/commands.ts b/src/tools/rust-analyzer/editors/code/src/commands.ts index 73e39c900e7b1..64af124e72693 100644 --- a/src/tools/rust-analyzer/editors/code/src/commands.ts +++ b/src/tools/rust-analyzer/editors/code/src/commands.ts @@ -288,13 +288,13 @@ export function openCargoToml(ctx: CtxInit): Cmd { export function revealDependency(ctx: CtxInit): Cmd { return async (editor: RustEditor) => { - if (!ctx.dependencies?.isInitialized()) { + if (!ctx.dependenciesProvider?.isInitialized()) { return; } const documentPath = editor.document.uri.fsPath; - const dep = ctx.dependencies?.getDependency(documentPath); + const dep = ctx.dependenciesProvider?.getDependency(documentPath); if (dep) { - await ctx.treeView?.reveal(dep, { select: true, expand: true }); + await ctx.dependencyTreeView?.reveal(dep, { select: true, expand: true }); } else { await revealParentChain(editor.document, ctx); } @@ -340,10 +340,10 @@ async function revealParentChain(document: RustDocument, ctx: CtxInit) { // a open file referencing the old version return; } - } while (!ctx.dependencies?.contains(documentPath)); + } while (!ctx.dependenciesProvider?.contains(documentPath)); parentChain.reverse(); for (const idx in parentChain) { - const treeView = ctx.treeView; + const treeView = ctx.dependencyTreeView; if (!treeView) { continue; } diff --git a/src/tools/rust-analyzer/editors/code/src/ctx.ts b/src/tools/rust-analyzer/editors/code/src/ctx.ts index 37a54abf71fd1..7b5cc9f106113 100644 --- a/src/tools/rust-analyzer/editors/code/src/ctx.ts +++ b/src/tools/rust-analyzer/editors/code/src/ctx.ts @@ -84,8 +84,8 @@ export class Ctx implements RustAnalyzerExtensionApi { private commandFactories: Record; private commandDisposables: Disposable[]; private unlinkedFiles: vscode.Uri[]; - private _dependencies: RustDependenciesProvider | undefined; - private _treeView: vscode.TreeView | undefined; + private _dependenciesProvider: RustDependenciesProvider | undefined; + private _dependencyTreeView: vscode.TreeView | undefined; private lastStatus: ServerStatusParams | { health: "stopped" } = { health: "stopped" }; private _serverVersion: string; private statusBarActiveEditorListener: Disposable; @@ -102,12 +102,12 @@ export class Ctx implements RustAnalyzerExtensionApi { return this._client; } - get treeView() { - return this._treeView; + get dependencyTreeView() { + return this._dependencyTreeView; } - get dependencies() { - return this._dependencies; + get dependenciesProvider() { + return this._dependenciesProvider; } constructor( @@ -285,13 +285,13 @@ export class Ctx implements RustAnalyzerExtensionApi { ...this, client: client, }; - this._dependencies = new RustDependenciesProvider(ctxInit); - this._treeView = vscode.window.createTreeView("rustDependencies", { - treeDataProvider: this._dependencies, + this._dependenciesProvider = new RustDependenciesProvider(ctxInit); + this._dependencyTreeView = vscode.window.createTreeView("rustDependencies", { + treeDataProvider: this._dependenciesProvider, showCollapseAll: true, }); - this.pushExtCleanup(this._treeView); + this.pushExtCleanup(this._dependencyTreeView); vscode.window.onDidChangeActiveTextEditor(async (e) => { // we should skip documents that belong to the current workspace if (this.shouldRevealDependency(e)) { @@ -303,7 +303,7 @@ export class Ctx implements RustAnalyzerExtensionApi { } }); - this.treeView?.onDidChangeVisibility(async (e) => { + this.dependencyTreeView?.onDidChangeVisibility(async (e) => { if (e.visible) { const activeEditor = vscode.window.activeTextEditor; if (this.shouldRevealDependency(activeEditor)) { @@ -322,7 +322,7 @@ export class Ctx implements RustAnalyzerExtensionApi { e !== undefined && isRustEditor(e) && !isDocumentInWorkspace(e.document) && - (this.treeView?.visible || false) + (this.dependencyTreeView?.visible || false) ); } @@ -423,7 +423,7 @@ export class Ctx implements RustAnalyzerExtensionApi { } else { statusBar.command = "rust-analyzer.openLogs"; } - this.dependencies?.refresh(); + this.dependenciesProvider?.refresh(); break; case "warning": statusBar.color = new vscode.ThemeColor("statusBarItem.warningForeground"); From bdb72bd405cee478f11ba4a720e0fb35423c14a2 Mon Sep 17 00:00:00 2001 From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com> Date: Sat, 14 Dec 2024 16:08:22 -0500 Subject: [PATCH 002/115] internal: Generalize `make::expr_from_text` to types which implement `Into` This will help with specializing the various `make::expr_*` functions later --- src/tools/rust-analyzer/crates/syntax/src/ast/make.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs index 282cbc4b3a4a2..0028fb93a5e50 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs @@ -663,7 +663,7 @@ pub fn expr_tuple(elements: impl IntoIterator) -> ast::Expr { pub fn expr_assignment(lhs: ast::Expr, rhs: ast::Expr) -> ast::Expr { expr_from_text(&format!("{lhs} = {rhs}")) } -fn expr_from_text(text: &str) -> ast::Expr { +fn expr_from_text + AstNode>(text: &str) -> E { ast_from_text(&format!("const C: () = {text};")) } pub fn expr_let(pattern: ast::Pat, expr: ast::Expr) -> ast::LetExpr { From 8435e3f945ccdb2e19148f3de78b676bbf331497 Mon Sep 17 00:00:00 2001 From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com> Date: Sat, 14 Dec 2024 16:12:25 -0500 Subject: [PATCH 003/115] internal: `make::expr_prefix` should return `ast::PrefixExpr` --- .../crates/ide-assists/src/handlers/apply_demorgan.rs | 2 +- .../crates/ide-assists/src/handlers/convert_closure_to_fn.rs | 2 +- .../ide-assists/src/handlers/replace_if_let_with_match.rs | 2 +- src/tools/rust-analyzer/crates/ide-assists/src/utils.rs | 4 ++-- .../crates/ide-assists/src/utils/ref_field_expr.rs | 2 +- .../crates/ide-completion/src/completions/postfix.rs | 2 +- src/tools/rust-analyzer/crates/syntax/src/ast/make.rs | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs index f178a7e0cec88..70fb5680052b0 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs @@ -252,7 +252,7 @@ fn tail_cb_impl(edit: &mut SourceChangeBuilder, e: &ast::Expr) { /// Add bang and parentheses to the expression. fn add_bang_paren(expr: ast::Expr) -> ast::Expr { - make::expr_prefix(T![!], make::expr_paren(expr)) + make::expr_prefix(T![!], make::expr_paren(expr)).into() } #[cfg(test)] diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs index 79f303b37a442..bb04a43cf9615 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs @@ -507,7 +507,7 @@ fn wrap_capture_in_deref_if_needed( if does_autoderef { return capture_name; } - make::expr_prefix(T![*], capture_name) + make::expr_prefix(T![*], capture_name).into() } fn capture_as_arg(ctx: &AssistContext<'_>, capture: &ClosureCapture) -> ast::Expr { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs index b31d45e6d4502..45e3f7a83d0e8 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs @@ -272,7 +272,7 @@ pub(crate) fn replace_match_with_if_let(acc: &mut Assists, ctx: &AssistContext<' ast::Pat::LiteralPat(p) if p.literal().is_some_and(|it| it.token().kind() == T![false]) => { - make::expr_prefix(T![!], scrutinee) + make::expr_prefix(T![!], scrutinee).into() } _ => make::expr_let(if_let_pat, scrutinee).into(), }; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs index e20c4ef09e8ce..78ff441791343 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs @@ -246,7 +246,7 @@ pub(crate) fn vis_offset(node: &SyntaxNode) -> TextSize { } pub(crate) fn invert_boolean_expression(expr: ast::Expr) -> ast::Expr { - invert_special_case(&expr).unwrap_or_else(|| make::expr_prefix(T![!], expr)) + invert_special_case(&expr).unwrap_or_else(|| make::expr_prefix(T![!], expr).into()) } fn invert_special_case(expr: &ast::Expr) -> Option { @@ -262,7 +262,7 @@ fn invert_special_case(expr: &ast::Expr) -> Option { T![>] => T![<=], T![>=] => T![<], // Parenthesize other expressions before prefixing `!` - _ => return Some(make::expr_prefix(T![!], make::expr_paren(expr.clone()))), + _ => return Some(make::expr_prefix(T![!], make::expr_paren(expr.clone())).into()), }; ted::replace(op_token, make::token(rev_token)); Some(bin.into()) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils/ref_field_expr.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils/ref_field_expr.rs index e95b291dd717a..d434872ea595e 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils/ref_field_expr.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils/ref_field_expr.rs @@ -121,7 +121,7 @@ impl RefData { /// Derefs `expr` and wraps it in parens if necessary pub(crate) fn wrap_expr(&self, mut expr: ast::Expr) -> ast::Expr { if self.needs_deref { - expr = make::expr_prefix(T![*], expr); + expr = make::expr_prefix(T![*], expr).into(); } if self.needs_parentheses { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs index 7b57eea0524fc..5bdc320d573f1 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs @@ -303,7 +303,7 @@ fn include_references(initial_element: &ast::Expr) -> (ast::Expr, ast::Expr) { resulting_element = ast::Expr::from(parent_deref_element); - new_element_opt = make::expr_prefix(syntax::T![*], new_element_opt); + new_element_opt = make::expr_prefix(syntax::T![*], new_element_opt).into(); } if let Some(first_ref_expr) = resulting_element.syntax().parent().and_then(ast::RefExpr::cast) { diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs index 0028fb93a5e50..804f76d7e118f 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs @@ -623,7 +623,7 @@ pub fn expr_loop(block: ast::BlockExpr) -> ast::Expr { expr_from_text(&format!("loop {block}")) } -pub fn expr_prefix(op: SyntaxKind, expr: ast::Expr) -> ast::Expr { +pub fn expr_prefix(op: SyntaxKind, expr: ast::Expr) -> ast::PrefixExpr { let token = token(op); expr_from_text(&format!("{token}{expr}")) } From aacc2ebfc842559de4fd09e6c1e00b9322e73cb4 Mon Sep 17 00:00:00 2001 From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com> Date: Sat, 14 Dec 2024 14:31:57 -0500 Subject: [PATCH 004/115] internal: `make::expr_if` should return `ast::IfExpr` --- .../crates/ide-assists/src/handlers/bool_to_enum.rs | 1 + .../crates/ide-assists/src/handlers/convert_while_to_loop.rs | 2 +- .../crates/ide-assists/src/handlers/extract_function.rs | 4 ++-- .../crates/ide-assists/src/handlers/move_guard.rs | 2 +- .../ide-assists/src/handlers/replace_if_let_with_match.rs | 2 +- .../ide-assists/src/handlers/replace_let_with_if_let.rs | 2 +- src/tools/rust-analyzer/crates/syntax/src/ast/make.rs | 2 +- 7 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs index f699899066b7a..cbd39796241b9 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs @@ -195,6 +195,7 @@ fn bool_expr_to_enum_expr(expr: ast::Expr) -> ast::Expr { make::tail_only_block_expr(true_expr), Some(ast::ElseBranch::Block(make::tail_only_block_expr(false_expr))), ) + .into() } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_while_to_loop.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_while_to_loop.rs index 434daa279cac6..0b92beefbcdfe 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_while_to_loop.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_while_to_loop.rs @@ -60,7 +60,7 @@ pub(crate) fn convert_while_to_loop(acc: &mut Assists, ctx: &AssistContext<'_>) .indent(while_indent_level); let block_expr = if is_pattern_cond(while_cond.clone()) { let if_expr = make::expr_if(while_cond, while_body, Some(break_block.into())); - let stmts = iter::once(make::expr_stmt(if_expr).into()); + let stmts = iter::once(make::expr_stmt(if_expr.into()).into()); make::block_expr(stmts, None) } else { let if_cond = invert_boolean_expression(while_cond); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs index 0d1b6af72042f..f8315e39a617b 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs @@ -1533,7 +1533,7 @@ impl FlowHandler { .into(), call_expr, ); - make::expr_if(condition.into(), block, None) + make::expr_if(condition.into(), block, None).into() } FlowHandler::IfOption { action } => { let path = make::ext::ident_path("Some"); @@ -1544,7 +1544,7 @@ impl FlowHandler { let action_expr = action.make_result_handler(Some(value)); let action_stmt = make::expr_stmt(action_expr); let then = make::block_expr(iter::once(action_stmt.into()), None); - make::expr_if(cond.into(), then, None) + make::expr_if(cond.into(), then, None).into() } FlowHandler::MatchOption { none } => { let some_name = "value"; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_guard.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_guard.rs index f0c96fe3cb85a..a487960d8d4c5 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_guard.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_guard.rs @@ -61,7 +61,7 @@ pub(crate) fn move_guard_to_arm_body(acc: &mut Assists, ctx: &AssistContext<'_>) }; edit.delete(guard.syntax().text_range()); - edit.replace_ast(arm_expr, if_expr); + edit.replace_ast(arm_expr, if_expr.into()); }, ) } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs index 45e3f7a83d0e8..637c6a610cccd 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs @@ -285,7 +285,7 @@ pub(crate) fn replace_match_with_if_let(acc: &mut Assists, ctx: &AssistContext<' ) .indent(IndentLevel::from_node(match_expr.syntax())); - edit.replace_ast::(match_expr.into(), if_let_expr); + edit.replace_ast::(match_expr.into(), if_let_expr.into()); }, ) } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_let_with_if_let.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_let_with_if_let.rs index c2be4593b97d0..7dbb1f6e24196 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_let_with_if_let.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_let_with_if_let.rs @@ -63,7 +63,7 @@ pub(crate) fn replace_let_with_if_let(acc: &mut Assists, ctx: &AssistContext<'_> let block = make::ext::empty_block_expr().indent(IndentLevel::from_node(let_stmt.syntax())); let if_ = make::expr_if(make::expr_let(pat, init).into(), block, None); - let stmt = make::expr_stmt(if_); + let stmt = make::expr_stmt(if_.into()); edit.replace_ast(ast::Stmt::from(let_stmt), ast::Stmt::from(stmt)); }, diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs index 804f76d7e118f..dc966a81fe4bc 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs @@ -607,7 +607,7 @@ pub fn expr_if( condition: ast::Expr, then_branch: ast::BlockExpr, else_branch: Option, -) -> ast::Expr { +) -> ast::IfExpr { let else_branch = match else_branch { Some(ast::ElseBranch::Block(block)) => format!("else {block}"), Some(ast::ElseBranch::IfExpr(if_expr)) => format!("else {if_expr}"), From ef7bb04deca035a5ac06bfbfa55a78f073ab9833 Mon Sep 17 00:00:00 2001 From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com> Date: Mon, 16 Dec 2024 14:27:31 -0500 Subject: [PATCH 005/115] internal: `make::expr_tuple` should return `ast::TupleExpr` --- .../crates/ide-assists/src/handlers/extract_function.rs | 6 +++--- .../crates/ide-assists/src/handlers/remove_dbg.rs | 2 +- .../crates/ide-assists/src/handlers/unwrap_block.rs | 2 +- .../crates/ide-assists/src/utils/gen_trait_fn_body.rs | 2 +- src/tools/rust-analyzer/crates/syntax/src/ast/make.rs | 2 +- src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs | 3 ++- 6 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs index f8315e39a617b..5c76db4b7afc5 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs @@ -1879,7 +1879,7 @@ fn make_body(ctx: &AssistContext<'_>, old_indent: IndentLevel, fun: &Function) - .iter() .map(|var| path_expr_from_local(ctx, var.local, fun.mods.edition)); let expr = make::expr_tuple(exprs); - tail_expr = Some(expr); + tail_expr = Some(expr.into()); } }, }; @@ -2130,13 +2130,13 @@ fn make_rewritten_flow(handler: &FlowHandler, arg_expr: Option) -> Op make::arg_list(iter::once(make::expr_unit())), ), FlowHandler::IfOption { .. } => { - let expr = arg_expr.unwrap_or_else(|| make::expr_tuple(Vec::new())); + let expr = arg_expr.unwrap_or_else(|| make::expr_unit()); let args = make::arg_list(iter::once(expr)); make::expr_call(make::expr_path(make::ext::ident_path("Some")), args) } FlowHandler::MatchOption { .. } => make::expr_path(make::ext::ident_path("None")), FlowHandler::MatchResult { .. } => { - let expr = arg_expr.unwrap_or_else(|| make::expr_tuple(Vec::new())); + let expr = arg_expr.unwrap_or_else(|| make::expr_unit()); let args = make::arg_list(iter::once(expr)); make::expr_call(make::expr_path(make::ext::ident_path("Err")), args) } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs index 94274f6d17c3f..31d4a33703c39 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs @@ -152,7 +152,7 @@ fn compute_dbg_replacement(macro_expr: ast::MacroExpr) -> Option<(TextRange, Opt exprs => { let exprs = exprs.iter().cloned().map(replace_nested_dbgs); let expr = make::expr_tuple(exprs); - (macro_call.syntax().text_range(), Some(expr)) + (macro_call.syntax().text_range(), Some(expr.into())) } }) } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_block.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_block.rs index f3e7f5f416769..c61394707497d 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_block.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_block.rs @@ -61,7 +61,7 @@ pub(crate) fn unwrap_block(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option } } None => { - let empty_tuple = make::expr_tuple([]); + let empty_tuple = make::expr_unit(); make::let_stmt(pattern, ty, Some(empty_tuple)).to_string() } }; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs index 75caf6d49f758..4ba6bd98e46db 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs @@ -541,7 +541,7 @@ fn gen_partial_eq(adt: &ast::Adt, func: &ast::Fn, trait_ref: Option) - arms.push(make::match_arm(Some(lhs), None, rhs)); } - let match_target = make::expr_tuple(vec![lhs_name, rhs_name]); + let match_target = make::expr_tuple([lhs_name, rhs_name]).into(); let list = make::match_arm_list(arms).indent(ast::edit::IndentLevel(1)); make::expr_match(match_target, list) } diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs index dc966a81fe4bc..812b0dc888a3f 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs @@ -656,7 +656,7 @@ pub fn expr_field(receiver: ast::Expr, field: &str) -> ast::Expr { pub fn expr_paren(expr: ast::Expr) -> ast::Expr { expr_from_text(&format!("({expr})")) } -pub fn expr_tuple(elements: impl IntoIterator) -> ast::Expr { +pub fn expr_tuple(elements: impl IntoIterator) -> ast::TupleExpr { let expr = elements.into_iter().format(", "); expr_from_text(&format!("({expr})")) } diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs index 992a847663af2..81c52e26cf10a 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs @@ -344,7 +344,8 @@ mod tests { make::expr_literal("2").into(), ), make::expr_literal("true").into(), - ]), + ]) + .into(), ); let to_wrap = root.syntax().descendants().find_map(ast::TupleExpr::cast).unwrap(); From 652865037e418a2ad05ec126ca6c177370ea4410 Mon Sep 17 00:00:00 2001 From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com> Date: Mon, 16 Dec 2024 14:38:53 -0500 Subject: [PATCH 006/115] internal: move `make::expr_unit` to `make::ext::expr_unit` `expr_unit` is just a shortcut for a common expression, so it belongs in `make::ext` --- .../src/handlers/convert_from_to_tryfrom.rs | 2 +- .../ide-assists/src/handlers/extract_function.rs | 14 +++++++------- .../crates/ide-assists/src/handlers/remove_dbg.rs | 2 +- .../src/handlers/replace_if_let_with_match.rs | 2 +- .../ide-assists/src/handlers/unwrap_block.rs | 2 +- .../rust-analyzer/crates/syntax/src/ast/edit.rs | 5 +++-- .../rust-analyzer/crates/syntax/src/ast/make.rs | 7 +++---- .../crates/syntax/src/syntax_editor.rs | 2 +- 8 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs index 67c72a93dadab..dd2e9cbcb5f2d 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs @@ -97,7 +97,7 @@ pub(crate) fn convert_from_to_tryfrom(acc: &mut Assists, ctx: &AssistContext<'_> ); for r in return_exprs { - let t = r.expr().unwrap_or_else(make::expr_unit); + let t = r.expr().unwrap_or_else(make::ext::expr_unit); ted::replace(t.syntax(), wrap_ok(t.clone()).syntax().clone_for_update()); } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs index 5c76db4b7afc5..8273ebe31082d 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs @@ -1910,7 +1910,7 @@ fn make_body(ctx: &AssistContext<'_>, old_indent: IndentLevel, fun: &Function) - match &handler { FlowHandler::None => block, FlowHandler::Try { kind } => { - let block = with_default_tail_expr(block, make::expr_unit()); + let block = with_default_tail_expr(block, make::ext::expr_unit()); map_tail_expr(block, |tail_expr| { let constructor = match kind { TryKind::Option => "Some", @@ -1924,7 +1924,7 @@ fn make_body(ctx: &AssistContext<'_>, old_indent: IndentLevel, fun: &Function) - FlowHandler::If { .. } => { let controlflow_continue = make::expr_call( make::expr_path(make::path_from_text("ControlFlow::Continue")), - make::arg_list(iter::once(make::expr_unit())), + make::arg_list([make::ext::expr_unit()]), ); with_tail_expr(block, controlflow_continue) } @@ -2127,17 +2127,17 @@ fn make_rewritten_flow(handler: &FlowHandler, arg_expr: Option) -> Op FlowHandler::None | FlowHandler::Try { .. } => return None, FlowHandler::If { .. } => make::expr_call( make::expr_path(make::path_from_text("ControlFlow::Break")), - make::arg_list(iter::once(make::expr_unit())), + make::arg_list([make::ext::expr_unit()]), ), FlowHandler::IfOption { .. } => { - let expr = arg_expr.unwrap_or_else(|| make::expr_unit()); - let args = make::arg_list(iter::once(expr)); + let expr = arg_expr.unwrap_or_else(make::ext::expr_unit); + let args = make::arg_list([expr]); make::expr_call(make::expr_path(make::ext::ident_path("Some")), args) } FlowHandler::MatchOption { .. } => make::expr_path(make::ext::ident_path("None")), FlowHandler::MatchResult { .. } => { - let expr = arg_expr.unwrap_or_else(|| make::expr_unit()); - let args = make::arg_list(iter::once(expr)); + let expr = arg_expr.unwrap_or_else(make::ext::expr_unit); + let args = make::arg_list([expr]); make::expr_call(make::expr_path(make::ext::ident_path("Err")), args) } }; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs index 31d4a33703c39..ae14075c26aeb 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs @@ -102,7 +102,7 @@ fn compute_dbg_replacement(macro_expr: ast::MacroExpr) -> Option<(TextRange, Opt }; (range, None) }, - _ => (macro_call.syntax().text_range(), Some(make::expr_unit())), + _ => (macro_call.syntax().text_range(), Some(make::ext::expr_unit())), } } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs index 637c6a610cccd..1a1da6564af43 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs @@ -179,7 +179,7 @@ fn make_else_arm( [(Either::Right(_), _)] => make::literal_pat("false").into(), _ => make::wildcard_pat().into(), }; - (pattern, make::expr_unit()) + (pattern, make::ext::expr_unit()) }; make::match_arm(iter::once(pattern), None, expr) } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_block.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_block.rs index c61394707497d..fd37140e9c2bf 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_block.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_block.rs @@ -61,7 +61,7 @@ pub(crate) fn unwrap_block(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option } } None => { - let empty_tuple = make::expr_unit(); + let empty_tuple = make::ext::expr_unit(); make::let_stmt(pattern, ty, Some(empty_tuple)).to_string() } }; diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs index de40d638be393..46fdfb65b39ec 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs @@ -153,8 +153,9 @@ impl AstNodeEdit for N {} #[test] fn test_increase_indent() { let arm_list = { - let arm = make::match_arm(iter::once(make::wildcard_pat().into()), None, make::expr_unit()); - make::match_arm_list(vec![arm.clone(), arm]) + let arm = + make::match_arm(iter::once(make::wildcard_pat().into()), None, make::ext::expr_unit()); + make::match_arm_list([arm.clone(), arm]) }; assert_eq!( arm_list.syntax().to_string(), diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs index 812b0dc888a3f..9d84d060c39eb 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs @@ -63,6 +63,9 @@ pub mod ext { Some(expr) } + pub fn expr_unit() -> ast::Expr { + expr_tuple([]).into() + } pub fn expr_unreachable() -> ast::Expr { expr_from_text("unreachable!()") } @@ -546,10 +549,6 @@ pub fn hacky_block_expr( ast_from_text(&format!("fn f() {buf}")) } -pub fn expr_unit() -> ast::Expr { - expr_from_text("()") -} - pub fn expr_literal(text: &str) -> ast::Literal { assert_eq!(text.trim(), text); ast_from_text(&format!("fn f() {{ let _ = {text}; }}")) diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs index 81c52e26cf10a..95162ea8d6b1c 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs @@ -550,7 +550,7 @@ mod tests { None, None, make::param_list(None, []), - make::block_expr([], Some(make::expr_unit())), + make::block_expr([], Some(make::ext::expr_unit())), Some(make::ret_type(make::ty_unit())), false, false, From 0606db43735def6da388403970e6951d5279b343 Mon Sep 17 00:00:00 2001 From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com> Date: Mon, 16 Dec 2024 15:28:17 -0500 Subject: [PATCH 007/115] internal: Generally improve `make::match_arm` `make::match_arm` should take a single `ast::Pat`, and callers can handle creating an `ast::OrPat` if need be. It should also take a proper `ast::MatchGuard`, instead of making one itself. --- .../src/handlers/add_missing_match_arms.rs | 12 +++----- .../src/handlers/extract_function.rs | 12 +++----- .../src/handlers/replace_if_let_with_match.rs | 12 ++++---- .../handlers/replace_try_expr_with_match.rs | 6 ++-- .../src/handlers/unmerge_match_arm.rs | 10 ++----- .../src/utils/gen_trait_fn_body.rs | 22 +++++++------- .../crates/syntax/src/ast/edit.rs | 3 +- .../crates/syntax/src/ast/make.rs | 30 ++++++++++++++----- .../crates/syntax/src/syntax_editor.rs | 2 +- 9 files changed, 53 insertions(+), 56 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs index 24b34f140bd03..5899ec5a00584 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs @@ -212,8 +212,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) !hidden }) .map(|(pat, _)| { - make::match_arm(iter::once(pat), None, make::ext::expr_todo()) - .clone_for_update() + make::match_arm(pat, None, make::ext::expr_todo()).clone_for_update() }); let catch_all_arm = new_match_arm_list @@ -243,12 +242,9 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) if needs_catch_all_arm && !has_catch_all_arm { cov_mark::hit!(added_wildcard_pattern); - let arm = make::match_arm( - iter::once(make::wildcard_pat().into()), - None, - make::ext::expr_todo(), - ) - .clone_for_update(); + let arm = + make::match_arm(make::wildcard_pat().into(), None, make::ext::expr_todo()) + .clone_for_update(); todo_placeholders.push(arm.expr().unwrap()); added_arms.push(arm); } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs index 8273ebe31082d..abe4329bfe936 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs @@ -1554,12 +1554,12 @@ impl FlowHandler { let value_pat = make::ext::simple_ident_pat(make::name(some_name)); let pat = make::tuple_struct_pat(path, iter::once(value_pat.into())); let value = make::expr_path(make::ext::ident_path(some_name)); - make::match_arm(iter::once(pat.into()), None, value) + make::match_arm(pat.into(), None, value) }; let none_arm = { let path = make::ext::ident_path("None"); let pat = make::path_pat(path); - make::match_arm(iter::once(pat), None, none.make_result_handler(None)) + make::match_arm(pat, None, none.make_result_handler(None)) }; let arms = make::match_arm_list(vec![some_arm, none_arm]); make::expr_match(call_expr, arms) @@ -1573,18 +1573,14 @@ impl FlowHandler { let value_pat = make::ext::simple_ident_pat(make::name(ok_name)); let pat = make::tuple_struct_pat(path, iter::once(value_pat.into())); let value = make::expr_path(make::ext::ident_path(ok_name)); - make::match_arm(iter::once(pat.into()), None, value) + make::match_arm(pat.into(), None, value) }; let err_arm = { let path = make::ext::ident_path("Err"); let value_pat = make::ext::simple_ident_pat(make::name(err_name)); let pat = make::tuple_struct_pat(path, iter::once(value_pat.into())); let value = make::expr_path(make::ext::ident_path(err_name)); - make::match_arm( - iter::once(pat.into()), - None, - err.make_result_handler(Some(value)), - ) + make::match_arm(pat.into(), None, err.make_result_handler(Some(value))) }; let arms = make::match_arm_list(vec![ok_arm, err_arm]); make::expr_match(call_expr, arms) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs index 1a1da6564af43..95c7db2662dd0 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs @@ -114,17 +114,15 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext<' let make_match_arm = |(pat, body): (_, ast::BlockExpr)| { let body = body.reset_indent().indent(IndentLevel(1)); match pat { - Either::Left(pat) => { - make::match_arm(iter::once(pat), None, unwrap_trivial_block(body)) - } + Either::Left(pat) => make::match_arm(pat, None, unwrap_trivial_block(body)), Either::Right(_) if !pat_seen => make::match_arm( - iter::once(make::literal_pat("true").into()), + make::literal_pat("true").into(), None, unwrap_trivial_block(body), ), Either::Right(expr) => make::match_arm( - iter::once(make::wildcard_pat().into()), - Some(expr), + make::wildcard_pat().into(), + Some(make::match_guard(expr)), unwrap_trivial_block(body), ), } @@ -181,7 +179,7 @@ fn make_else_arm( }; (pattern, make::ext::expr_unit()) }; - make::match_arm(iter::once(pattern), None, expr) + make::match_arm(pattern, None, expr) } // Assist: replace_match_with_if_let diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_try_expr_with_match.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_try_expr_with_match.rs index 2e26f59d030ff..aff5ee2ffcf54 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_try_expr_with_match.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_try_expr_with_match.rs @@ -71,13 +71,11 @@ pub(crate) fn replace_try_expr_with_match( }; let happy_arm = make::match_arm( - iter::once( - try_enum.happy_pattern(make::ident_pat(false, false, make::name("it")).into()), - ), + try_enum.happy_pattern(make::ident_pat(false, false, make::name("it")).into()), None, make::expr_path(make::ext::ident_path("it")), ); - let sad_arm = make::match_arm(iter::once(sad_pat), None, sad_expr); + let sad_arm = make::match_arm(sad_pat, None, sad_expr); let match_arm_list = make::match_arm_list([happy_arm, sad_arm]); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs index c6cffb5434a5c..6b9f661d4de54 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs @@ -54,13 +54,9 @@ pub(crate) fn unmerge_match_arm(acc: &mut Assists, ctx: &AssistContext<'_>) -> O let pats_after = pipe_token .siblings_with_tokens(Direction::Next) .filter_map(|it| ast::Pat::cast(it.into_node()?)); - // FIXME: We should add a leading pipe if the original arm has one. - let new_match_arm = make::match_arm( - pats_after, - match_arm.guard().and_then(|guard| guard.condition()), - match_arm_body, - ) - .clone_for_update(); + let new_pat = make::or_pat(pats_after, or_pat.leading_pipe().is_some()); + let new_match_arm = + make::match_arm(new_pat, match_arm.guard(), match_arm_body).clone_for_update(); let mut pipe_index = pipe_token.index(); if pipe_token diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs index 4ba6bd98e46db..325e938240c27 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs @@ -66,7 +66,7 @@ fn gen_clone_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { let pat = make::record_pat(variant_name.clone(), pats.into_iter()); let fields = make::record_expr_field_list(fields); let record_expr = make::record_expr(variant_name, fields).into(); - arms.push(make::match_arm(Some(pat.into()), None, record_expr)); + arms.push(make::match_arm(pat.into(), None, record_expr)); } // => match self { Self::Name(arg1) => Self::Name(arg1.clone()) } @@ -84,14 +84,14 @@ fn gen_clone_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { let pat = make::tuple_struct_pat(variant_name.clone(), pats.into_iter()); let struct_name = make::expr_path(variant_name); let tuple_expr = make::expr_call(struct_name, make::arg_list(fields)); - arms.push(make::match_arm(Some(pat.into()), None, tuple_expr)); + arms.push(make::match_arm(pat.into(), None, tuple_expr)); } // => match self { Self::Name => Self::Name } None => { let pattern = make::path_pat(variant_name.clone()); let variant_expr = make::expr_path(variant_name); - arms.push(make::match_arm(Some(pattern), None, variant_expr)); + arms.push(make::match_arm(pattern, None, variant_expr)); } } } @@ -190,7 +190,7 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { // => MyStruct { fields.. } => f.debug_struct("MyStruct")...finish(), let pat = make::record_pat(variant_name.clone(), pats.into_iter()); - arms.push(make::match_arm(Some(pat.into()), None, expr)); + arms.push(make::match_arm(pat.into(), None, expr)); } Some(ast::FieldList::TupleFieldList(list)) => { // => f.debug_tuple(name) @@ -223,7 +223,7 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { // => MyStruct (fields..) => f.debug_tuple("MyStruct")...finish(), let pat = make::tuple_struct_pat(variant_name.clone(), pats.into_iter()); - arms.push(make::match_arm(Some(pat.into()), None, expr)); + arms.push(make::match_arm(pat.into(), None, expr)); } None => { let fmt_string = make::expr_literal(&(format!("\"{name}\""))).into(); @@ -232,7 +232,7 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { let macro_call = make::expr_macro_call(macro_name, args); let variant_name = make::path_pat(variant_name); - arms.push(make::match_arm(Some(variant_name), None, macro_call)); + arms.push(make::match_arm(variant_name, None, macro_call)); } } } @@ -485,7 +485,7 @@ fn gen_partial_eq(adt: &ast::Adt, func: &ast::Fn, trait_ref: Option) - let tuple = make::tuple_pat(vec![left.into(), right.into()]); if let Some(expr) = expr { - arms.push(make::match_arm(Some(tuple.into()), None, expr)); + arms.push(make::match_arm(tuple.into(), None, expr)); } } @@ -518,7 +518,7 @@ fn gen_partial_eq(adt: &ast::Adt, func: &ast::Fn, trait_ref: Option) - let tuple = make::tuple_pat(vec![left.into(), right.into()]); if let Some(expr) = expr { - arms.push(make::match_arm(Some(tuple.into()), None, expr)); + arms.push(make::match_arm(tuple.into(), None, expr)); } } None => continue, @@ -538,7 +538,7 @@ fn gen_partial_eq(adt: &ast::Adt, func: &ast::Fn, trait_ref: Option) - } else { eq_check }; - arms.push(make::match_arm(Some(lhs), None, rhs)); + arms.push(make::match_arm(lhs, None, rhs)); } let match_target = make::expr_tuple([lhs_name, rhs_name]).into(); @@ -599,10 +599,10 @@ fn gen_partial_ord(adt: &ast::Adt, func: &ast::Fn, trait_ref: Option) let variant_name = make::path_pat(make::ext::path_from_idents(["core", "cmp", "Ordering", "Equal"])?); let lhs = make::tuple_struct_pat(make::ext::path_from_idents(["Some"])?, [variant_name]); - arms.push(make::match_arm(Some(lhs.into()), None, make::expr_empty_block())); + arms.push(make::match_arm(lhs.into(), None, make::expr_empty_block())); arms.push(make::match_arm( - [make::ident_pat(false, false, make::name("ord")).into()], + make::ident_pat(false, false, make::name("ord")).into(), None, make::expr_return(Some(make::expr_path(make::ext::ident_path("ord")))), )); diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs index 46fdfb65b39ec..579f3ba8b4fee 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs @@ -153,8 +153,7 @@ impl AstNodeEdit for N {} #[test] fn test_increase_indent() { let arm_list = { - let arm = - make::match_arm(iter::once(make::wildcard_pat().into()), None, make::ext::expr_unit()); + let arm = make::match_arm(make::wildcard_pat().into(), None, make::ext::expr_unit()); make::match_arm_list([arm.clone(), arm]) }; assert_eq!( diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs index 9d84d060c39eb..ca66a8744cc9b 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs @@ -787,15 +787,21 @@ pub fn path_pat(path: ast::Path) -> ast::Pat { } } -pub fn match_arm( - pats: impl IntoIterator, - guard: Option, - expr: ast::Expr, -) -> ast::MatchArm { - let pats_str = pats.into_iter().join(" | "); +/// Returns a `Pat` if the path has just one segment, an `OrPat` otherwise. +pub fn or_pat(pats: impl IntoIterator, leading_pipe: bool) -> ast::Pat { + let leading_pipe = if leading_pipe { "| " } else { "" }; + let pats = pats.into_iter().join(" | "); + + return from_text(&format!("{leading_pipe}{pats}")); + fn from_text(text: &str) -> ast::Pat { + ast_from_text(&format!("fn f({text}: ())")) + } +} + +pub fn match_arm(pat: ast::Pat, guard: Option, expr: ast::Expr) -> ast::MatchArm { return match guard { - Some(guard) => from_text(&format!("{pats_str} if {guard} => {expr}")), - None => from_text(&format!("{pats_str} => {expr}")), + Some(guard) => from_text(&format!("{pat} {guard} => {expr}")), + None => from_text(&format!("{pat} => {expr}")), }; fn from_text(text: &str) -> ast::MatchArm { @@ -816,6 +822,14 @@ pub fn match_arm_with_guard( } } +pub fn match_guard(condition: ast::Expr) -> ast::MatchGuard { + return from_text(&format!("if {condition}")); + + fn from_text(text: &str) -> ast::MatchGuard { + ast_from_text(&format!("fn f() {{ match () {{() {text} => () }}")) + } +} + pub fn match_arm_list(arms: impl IntoIterator) -> ast::MatchArmList { let arms_str = arms.into_iter().fold(String::new(), |mut acc, arm| { let needs_comma = arm.expr().is_none_or(|it| !it.is_block_like()); diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs index 95162ea8d6b1c..b82181ae13add 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs @@ -335,7 +335,7 @@ mod tests { #[test] fn basic_usage() { let root = make::match_arm( - [make::wildcard_pat().into()], + make::wildcard_pat().into(), None, make::expr_tuple([ make::expr_bin_op( From cce5f25f60c8e6fd6137076f9ef4691f2d1df527 Mon Sep 17 00:00:00 2001 From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com> Date: Mon, 16 Dec 2024 15:42:42 -0500 Subject: [PATCH 008/115] internal: `make::expr_match` should return `ast::MatchExpr` --- .../crates/ide-assists/src/handlers/extract_function.rs | 4 ++-- .../ide-assists/src/handlers/replace_if_let_with_match.rs | 2 +- .../src/handlers/replace_try_expr_with_match.rs | 2 +- .../crates/ide-assists/src/utils/gen_trait_fn_body.rs | 8 ++++---- src/tools/rust-analyzer/crates/syntax/src/ast/make.rs | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs index abe4329bfe936..967da41c15f77 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs @@ -1562,7 +1562,7 @@ impl FlowHandler { make::match_arm(pat, None, none.make_result_handler(None)) }; let arms = make::match_arm_list(vec![some_arm, none_arm]); - make::expr_match(call_expr, arms) + make::expr_match(call_expr, arms).into() } FlowHandler::MatchResult { err } => { let ok_name = "value"; @@ -1583,7 +1583,7 @@ impl FlowHandler { make::match_arm(pat.into(), None, err.make_result_handler(Some(value))) }; let arms = make::match_arm_list(vec![ok_arm, err_arm]); - make::expr_match(call_expr, arms) + make::expr_match(call_expr, arms).into() } } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs index 95c7db2662dd0..1964a4c096c4c 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs @@ -129,7 +129,7 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext<' }; let arms = cond_bodies.into_iter().map(make_match_arm).chain(iter::once(else_arm)); let match_expr = make::expr_match(scrutinee_to_be_expr, make::match_arm_list(arms)); - match_expr.indent(IndentLevel::from_node(if_expr.syntax())) + match_expr.indent(IndentLevel::from_node(if_expr.syntax())).into() }; let has_preceding_if_expr = diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_try_expr_with_match.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_try_expr_with_match.rs index aff5ee2ffcf54..88b50543dda87 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_try_expr_with_match.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_try_expr_with_match.rs @@ -81,7 +81,7 @@ pub(crate) fn replace_try_expr_with_match( let expr_match = make::expr_match(expr, match_arm_list) .indent(IndentLevel::from_node(qm_kw_parent.syntax())); - edit.replace_ast::(qm_kw_parent.into(), expr_match); + edit.replace_ast::(qm_kw_parent.into(), expr_match.into()); }, ) } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs index 325e938240c27..a9a889acc2359 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs @@ -98,7 +98,7 @@ fn gen_clone_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { let match_target = make::expr_path(make::ext::ident_path("self")); let list = make::match_arm_list(arms).indent(ast::edit::IndentLevel(1)); - make::expr_match(match_target, list) + make::expr_match(match_target, list).into() } ast::Adt::Struct(strukt) => { match strukt.field_list() { @@ -241,7 +241,7 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { let list = make::match_arm_list(arms).indent(ast::edit::IndentLevel(1)); let match_expr = make::expr_match(match_target, list); - let body = make::block_expr(None, Some(match_expr)); + let body = make::block_expr(None, Some(match_expr.into())); let body = body.indent(ast::edit::IndentLevel(1)); ted::replace(func.body()?.syntax(), body.clone_for_update().syntax()); Some(()) @@ -543,7 +543,7 @@ fn gen_partial_eq(adt: &ast::Adt, func: &ast::Fn, trait_ref: Option) - let match_target = make::expr_tuple([lhs_name, rhs_name]).into(); let list = make::match_arm_list(arms).indent(ast::edit::IndentLevel(1)); - make::expr_match(match_target, list) + make::expr_match(match_target, list).into() } }; @@ -607,7 +607,7 @@ fn gen_partial_ord(adt: &ast::Adt, func: &ast::Fn, trait_ref: Option) make::expr_return(Some(make::expr_path(make::ext::ident_path("ord")))), )); let list = make::match_arm_list(arms).indent(ast::edit::IndentLevel(1)); - Some(make::expr_stmt(make::expr_match(match_target, list)).into()) + Some(make::expr_stmt(make::expr_match(match_target, list).into()).into()) } fn gen_partial_cmp_call(lhs: ast::Expr, rhs: ast::Expr) -> ast::Expr { diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs index ca66a8744cc9b..a920fe4f359a5 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs @@ -599,7 +599,7 @@ pub fn expr_try(expr: ast::Expr) -> ast::Expr { pub fn expr_await(expr: ast::Expr) -> ast::Expr { expr_from_text(&format!("{expr}.await")) } -pub fn expr_match(expr: ast::Expr, match_arm_list: ast::MatchArmList) -> ast::Expr { +pub fn expr_match(expr: ast::Expr, match_arm_list: ast::MatchArmList) -> ast::MatchExpr { expr_from_text(&format!("match {expr} {match_arm_list}")) } pub fn expr_if( From cd803805b79bf7324a7dba73b129568069fac343 Mon Sep 17 00:00:00 2001 From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com> Date: Sat, 14 Dec 2024 15:55:27 -0500 Subject: [PATCH 009/115] internal: Add some path constructors to `SyntaxFactory` --- .../src/ast/syntax_factory/constructors.rs | 78 ++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs index bea6bfeafcf2a..253791bfc02ef 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs @@ -1,6 +1,6 @@ //! Wrappers over [`make`] constructors use crate::{ - ast::{self, make, HasGenericParams, HasName, HasTypeBounds, HasVisibility}, + ast::{self, make, HasGenericArgs, HasGenericParams, HasName, HasTypeBounds, HasVisibility}, syntax_editor::SyntaxMappingBuilder, AstNode, NodeOrToken, SyntaxKind, SyntaxNode, SyntaxToken, }; @@ -12,6 +12,10 @@ impl SyntaxFactory { make::name(name).clone_for_update() } + pub fn name_ref(&self, name: &str) -> ast::NameRef { + make::name_ref(name).clone_for_update() + } + pub fn ty(&self, text: &str) -> ast::Type { make::ty(text).clone_for_update() } @@ -46,6 +50,71 @@ impl SyntaxFactory { ast } + pub fn path_segment(&self, name_ref: ast::NameRef) -> ast::PathSegment { + let ast = make::path_segment(name_ref.clone()).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(name_ref.syntax().clone(), ast.name_ref().unwrap().syntax().clone()); + builder.finish(&mut mapping); + } + + ast + } + + pub fn path_segment_generics( + &self, + name_ref: ast::NameRef, + generic_arg_list: ast::GenericArgList, + ) -> ast::PathSegment { + let ast::Type::PathType(path) = make::ty(&format!("{name_ref}{generic_arg_list}")) else { + unreachable!(); + }; + + let ast = path.path().unwrap().segment().unwrap().clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(name_ref.syntax().clone(), ast.name_ref().unwrap().syntax().clone()); + builder.map_node( + generic_arg_list.syntax().clone(), + ast.generic_arg_list().unwrap().syntax().clone(), + ); + builder.finish(&mut mapping); + } + + ast + } + + pub fn path_unqualified(&self, segment: ast::PathSegment) -> ast::Path { + let ast = make::path_unqualified(segment.clone()).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(segment.syntax().clone(), ast.segment().unwrap().syntax().clone()); + builder.finish(&mut mapping); + } + + ast + } + + pub fn path_from_segments( + &self, + segments: impl IntoIterator, + is_abs: bool, + ) -> ast::Path { + let (segments, input) = iterator_input(segments); + let ast = make::path_from_segments(segments, is_abs).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_children(input.into_iter(), ast.segments().map(|it| it.syntax().clone())); + builder.finish(&mut mapping); + } + + ast + } + pub fn ident_pat(&self, ref_: bool, mut_: bool, name: ast::Name) -> ast::IdentPat { let ast = make::ident_pat(ref_, mut_, name.clone()).clone_for_update(); @@ -508,6 +577,13 @@ impl SyntaxFactory { } } +// `ext` constructors +impl SyntaxFactory { + pub fn ident_path(&self, ident: &str) -> ast::Path { + self.path_unqualified(self.path_segment(self.name_ref(ident))) + } +} + // We need to collect `input` here instead of taking `impl IntoIterator + Clone`, // because if we took `impl IntoIterator + Clone`, that could be something like an // `Iterator::map` with a closure that also makes use of a `SyntaxFactory` constructor. From 396b56fd5237e7fe76565882fa6c4a59e5374c5a Mon Sep 17 00:00:00 2001 From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com> Date: Wed, 18 Dec 2024 11:33:35 -0500 Subject: [PATCH 010/115] internal: Add some expr constructors to `SyntaxFactory` --- .../crates/syntax/src/ast/expr_ext.rs | 23 ++- .../src/ast/syntax_factory/constructors.rs | 154 +++++++++++++++++- 2 files changed, 175 insertions(+), 2 deletions(-) diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs index 9466755576b6c..93faeb40c32ba 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs @@ -10,7 +10,7 @@ use crate::{ FormatArgsArg, FormatArgsExpr, MacroDef, Static, TokenTree, }, AstToken, - SyntaxKind::*, + SyntaxKind::{self, *}, SyntaxNode, SyntaxToken, T, }; @@ -50,6 +50,27 @@ impl From for ElseBranch { } } +impl AstNode for ElseBranch { + fn can_cast(kind: SyntaxKind) -> bool { + ast::BlockExpr::can_cast(kind) || ast::IfExpr::can_cast(kind) + } + + fn cast(syntax: SyntaxNode) -> Option { + if let Some(block_expr) = ast::BlockExpr::cast(syntax.clone()) { + Some(Self::Block(block_expr)) + } else { + ast::IfExpr::cast(syntax).map(Self::IfExpr) + } + } + + fn syntax(&self) -> &SyntaxNode { + match self { + ElseBranch::Block(block_expr) => block_expr.syntax(), + ElseBranch::IfExpr(if_expr) => if_expr.syntax(), + } + } +} + impl ast::IfExpr { pub fn condition(&self) -> Option { // If the condition is a BlockExpr, check if the then body is missing. diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs index 253791bfc02ef..39320cf504c39 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs @@ -167,6 +167,19 @@ impl SyntaxFactory { ast::BlockExpr { syntax: make::expr_empty_block().syntax().clone_for_update() } } + pub fn expr_tuple(&self, fields: impl IntoIterator) -> ast::TupleExpr { + let (fields, input) = iterator_input(fields); + let ast = make::expr_tuple(fields).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_children(input.into_iter(), ast.fields().map(|it| it.syntax().clone())); + builder.finish(&mut mapping); + } + + ast + } + pub fn expr_bin(&self, lhs: ast::Expr, op: ast::BinaryOp, rhs: ast::Expr) -> ast::BinExpr { let ast::Expr::BinExpr(ast) = make::expr_bin_op(lhs.clone(), op, rhs.clone()).clone_for_update() @@ -184,6 +197,10 @@ impl SyntaxFactory { ast } + pub fn expr_literal(&self, text: &str) -> ast::Literal { + make::expr_literal(text).clone_for_update() + } + pub fn expr_path(&self, path: ast::Path) -> ast::Expr { let ast::Expr::PathExpr(ast) = make::expr_path(path.clone()).clone_for_update() else { unreachable!() @@ -198,6 +215,18 @@ impl SyntaxFactory { ast.into() } + pub fn expr_prefix(&self, op: SyntaxKind, expr: ast::Expr) -> ast::PrefixExpr { + let ast = make::expr_prefix(op, expr.clone()).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(expr.syntax().clone(), ast.expr().unwrap().syntax().clone()); + builder.finish(&mut mapping); + } + + ast + } + pub fn expr_ref(&self, expr: ast::Expr, exclusive: bool) -> ast::Expr { let ast::Expr::RefExpr(ast) = make::expr_ref(expr.clone(), exclusive).clone_for_update() else { @@ -229,6 +258,125 @@ impl SyntaxFactory { ast } + pub fn expr_if( + &self, + condition: ast::Expr, + then_branch: ast::BlockExpr, + else_branch: Option, + ) -> ast::IfExpr { + let ast = make::expr_if(condition.clone(), then_branch.clone(), else_branch.clone()) + .clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(condition.syntax().clone(), ast.condition().unwrap().syntax().clone()); + builder.map_node( + then_branch.syntax().clone(), + ast.then_branch().unwrap().syntax().clone(), + ); + + if let Some(else_branch) = else_branch { + builder.map_node( + else_branch.syntax().clone(), + ast.else_branch().unwrap().syntax().clone(), + ); + } + builder.finish(&mut mapping); + } + + ast + } + + pub fn expr_let(&self, pattern: ast::Pat, expr: ast::Expr) -> ast::LetExpr { + let ast = make::expr_let(pattern.clone(), expr.clone()).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(pattern.syntax().clone(), ast.pat().unwrap().syntax().clone()); + builder.map_node(expr.syntax().clone(), ast.expr().unwrap().syntax().clone()); + builder.finish(&mut mapping); + } + + ast + } + + pub fn expr_stmt(&self, expr: ast::Expr) -> ast::ExprStmt { + let ast = make::expr_stmt(expr.clone()).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(expr.syntax().clone(), ast.expr().unwrap().syntax().clone()); + builder.finish(&mut mapping); + } + + ast + } + + pub fn expr_match(&self, expr: ast::Expr, match_arm_list: ast::MatchArmList) -> ast::MatchExpr { + let ast = make::expr_match(expr.clone(), match_arm_list.clone()).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(expr.syntax().clone(), ast.expr().unwrap().syntax().clone()); + builder.map_node( + match_arm_list.syntax().clone(), + ast.match_arm_list().unwrap().syntax().clone(), + ); + builder.finish(&mut mapping); + } + + ast + } + + pub fn match_arm( + &self, + pat: ast::Pat, + guard: Option, + expr: ast::Expr, + ) -> ast::MatchArm { + let ast = make::match_arm(pat.clone(), guard.clone(), expr.clone()).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(pat.syntax().clone(), ast.pat().unwrap().syntax().clone()); + if let Some(guard) = guard { + builder.map_node(guard.syntax().clone(), ast.guard().unwrap().syntax().clone()); + } + builder.map_node(expr.syntax().clone(), ast.expr().unwrap().syntax().clone()); + builder.finish(&mut mapping); + } + + ast + } + + pub fn match_guard(&self, condition: ast::Expr) -> ast::MatchGuard { + let ast = make::match_guard(condition.clone()).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(condition.syntax().clone(), ast.condition().unwrap().syntax().clone()); + builder.finish(&mut mapping); + } + + ast + } + + pub fn match_arm_list( + &self, + match_arms: impl IntoIterator, + ) -> ast::MatchArmList { + let (match_arms, input) = iterator_input(match_arms); + let ast = make::match_arm_list(match_arms).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_children(input.into_iter(), ast.arms().map(|it| it.syntax().clone())); + builder.finish(&mut mapping); + } + + ast + } + pub fn let_stmt( &self, pattern: ast::Pat, @@ -572,13 +720,17 @@ impl SyntaxFactory { make::token(kind) } - pub fn whitespace(&self, text: &str) -> ast::SyntaxToken { + pub fn whitespace(&self, text: &str) -> SyntaxToken { make::tokens::whitespace(text) } } // `ext` constructors impl SyntaxFactory { + pub fn expr_unit(&self) -> ast::Expr { + self.expr_tuple([]).into() + } + pub fn ident_path(&self, ident: &str) -> ast::Path { self.path_unqualified(self.path_segment(self.name_ref(ident))) } From fa8acfac7e657b5ddb5ef76d6f05158bb5980f5d Mon Sep 17 00:00:00 2001 From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com> Date: Wed, 18 Dec 2024 11:34:31 -0500 Subject: [PATCH 011/115] internal: Add some pattern constructors to `SyntaxFactory` --- .../src/ast/syntax_factory/constructors.rs | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs index 39320cf504c39..d62c01ba761a0 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs @@ -127,6 +127,32 @@ impl SyntaxFactory { ast } + pub fn wildcard_pat(&self) -> ast::WildcardPat { + make::wildcard_pat().clone_for_update() + } + + pub fn literal_pat(&self, text: &str) -> ast::LiteralPat { + make::literal_pat(text).clone_for_update() + } + + pub fn tuple_struct_pat( + &self, + path: ast::Path, + fields: impl IntoIterator, + ) -> ast::TupleStructPat { + let (fields, input) = iterator_input(fields); + let ast = make::tuple_struct_pat(path.clone(), fields).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(path.syntax().clone(), ast.path().unwrap().syntax().clone()); + builder.map_children(input.into_iter(), ast.fields().map(|it| it.syntax().clone())); + builder.finish(&mut mapping); + } + + ast + } + pub fn block_expr( &self, statements: impl IntoIterator, From b2fa162071f057ede490135bfe5f427842281c94 Mon Sep 17 00:00:00 2001 From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com> Date: Wed, 18 Dec 2024 11:39:43 -0500 Subject: [PATCH 012/115] internal: Migrate `replace_let_with_if_let` assist to `SyntaxEditor` --- .../src/handlers/replace_let_with_if_let.rs | 27 +++++++++---------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_let_with_if_let.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_let_with_if_let.rs index 7dbb1f6e24196..c071d3022d251 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_let_with_if_let.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_let_with_if_let.rs @@ -1,12 +1,6 @@ -use std::iter::once; - use ide_db::ty_filter::TryEnum; use syntax::{ - ast::{ - self, - edit::{AstNodeEdit, IndentLevel}, - make, - }, + ast::{self, edit::IndentLevel, edit_in_place::Indent, syntax_factory::SyntaxFactory}, AstNode, T, }; @@ -47,7 +41,9 @@ pub(crate) fn replace_let_with_if_let(acc: &mut Assists, ctx: &AssistContext<'_> AssistId("replace_let_with_if_let", AssistKind::RefactorRewrite), "Replace let with if let", target, - |edit| { + |builder| { + let mut editor = builder.make_editor(let_stmt.syntax()); + let make = SyntaxFactory::new(); let ty = ctx.sema.type_of_expr(&init); let happy_variant = ty .and_then(|ty| TryEnum::from_ty(&ctx.sema, &ty.adjusted())) @@ -55,17 +51,18 @@ pub(crate) fn replace_let_with_if_let(acc: &mut Assists, ctx: &AssistContext<'_> let pat = match happy_variant { None => original_pat, Some(var_name) => { - make::tuple_struct_pat(make::ext::ident_path(var_name), once(original_pat)) - .into() + make.tuple_struct_pat(make.ident_path(var_name), [original_pat]).into() } }; - let block = - make::ext::empty_block_expr().indent(IndentLevel::from_node(let_stmt.syntax())); - let if_ = make::expr_if(make::expr_let(pat, init).into(), block, None); - let stmt = make::expr_stmt(if_.into()); + let block = make.block_expr([], None); + block.indent(IndentLevel::from_node(let_stmt.syntax())); + let if_expr = make.expr_if(make.expr_let(pat, init).into(), block, None); + let if_stmt = make.expr_stmt(if_expr.into()); - edit.replace_ast(ast::Stmt::from(let_stmt), ast::Stmt::from(stmt)); + editor.replace(let_stmt.syntax(), if_stmt.syntax()); + editor.add_mappings(make.finish_with_mappings()); + builder.add_file_edits(ctx.file_id(), editor); }, ) } From aa36ac8867ec17a9069ee7cce2a308128a0c7374 Mon Sep 17 00:00:00 2001 From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com> Date: Wed, 18 Dec 2024 11:52:14 -0500 Subject: [PATCH 013/115] internal: Migrate `if let` <=> `match` assists to `SyntaxEditor` --- .../src/handlers/replace_if_let_with_match.rs | 98 ++++++++++--------- 1 file changed, 53 insertions(+), 45 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs index 1964a4c096c4c..e324d6eaaad2f 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs @@ -1,4 +1,4 @@ -use std::iter::{self, successors}; +use std::iter::successors; use either::Either; use ide_db::{ @@ -8,11 +8,7 @@ use ide_db::{ RootDatabase, }; use syntax::{ - ast::{ - self, - edit::{AstNodeEdit, IndentLevel}, - make, HasName, - }, + ast::{self, edit::IndentLevel, edit_in_place::Indent, syntax_factory::SyntaxFactory, HasName}, AstNode, TextRange, T, }; @@ -108,51 +104,58 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext<' AssistId("replace_if_let_with_match", AssistKind::RefactorRewrite), format!("Replace if{let_} with match"), available_range, - move |edit| { + move |builder| { + let make = SyntaxFactory::new(); let match_expr = { - let else_arm = make_else_arm(ctx, else_block, &cond_bodies); + let else_arm = make_else_arm(ctx, &make, else_block, &cond_bodies); let make_match_arm = |(pat, body): (_, ast::BlockExpr)| { - let body = body.reset_indent().indent(IndentLevel(1)); + let body = make.block_expr(body.statements(), body.tail_expr()); + body.indent(IndentLevel::from(1)); + let body = unwrap_trivial_block(body); match pat { - Either::Left(pat) => make::match_arm(pat, None, unwrap_trivial_block(body)), - Either::Right(_) if !pat_seen => make::match_arm( - make::literal_pat("true").into(), - None, - unwrap_trivial_block(body), - ), - Either::Right(expr) => make::match_arm( - make::wildcard_pat().into(), - Some(make::match_guard(expr)), - unwrap_trivial_block(body), + Either::Left(pat) => make.match_arm(pat, None, body), + Either::Right(_) if !pat_seen => { + make.match_arm(make.literal_pat("true").into(), None, body) + } + Either::Right(expr) => make.match_arm( + make.wildcard_pat().into(), + Some(make.match_guard(expr)), + body, ), } }; - let arms = cond_bodies.into_iter().map(make_match_arm).chain(iter::once(else_arm)); - let match_expr = make::expr_match(scrutinee_to_be_expr, make::match_arm_list(arms)); - match_expr.indent(IndentLevel::from_node(if_expr.syntax())).into() + let arms = cond_bodies.into_iter().map(make_match_arm).chain([else_arm]); + let match_expr = make.expr_match(scrutinee_to_be_expr, make.match_arm_list(arms)); + match_expr.indent(IndentLevel::from_node(if_expr.syntax())); + match_expr.into() }; let has_preceding_if_expr = if_expr.syntax().parent().is_some_and(|it| ast::IfExpr::can_cast(it.kind())); let expr = if has_preceding_if_expr { // make sure we replace the `else if let ...` with a block so we don't end up with `else expr` - make::block_expr(None, Some(match_expr)).into() + make.block_expr([], Some(match_expr)).into() } else { match_expr }; - edit.replace_ast::(if_expr.into(), expr); + + let mut editor = builder.make_editor(if_expr.syntax()); + editor.replace(if_expr.syntax(), expr.syntax()); + editor.add_mappings(make.finish_with_mappings()); + builder.add_file_edits(ctx.file_id(), editor); }, ) } fn make_else_arm( ctx: &AssistContext<'_>, + make: &SyntaxFactory, else_block: Option, conditionals: &[(Either, ast::BlockExpr)], ) -> ast::MatchArm { let (pattern, expr) = if let Some(else_block) = else_block { let pattern = match conditionals { - [(Either::Right(_), _)] => make::literal_pat("false").into(), + [(Either::Right(_), _)] => make.literal_pat("false").into(), [(Either::Left(pat), _)] => match ctx .sema .type_of_pat(pat) @@ -162,24 +165,24 @@ fn make_else_arm( if does_pat_match_variant(pat, &it.sad_pattern()) { it.happy_pattern_wildcard() } else if does_pat_variant_nested_or_literal(ctx, pat) { - make::wildcard_pat().into() + make.wildcard_pat().into() } else { it.sad_pattern() } } - None => make::wildcard_pat().into(), + None => make.wildcard_pat().into(), }, - _ => make::wildcard_pat().into(), + _ => make.wildcard_pat().into(), }; (pattern, unwrap_trivial_block(else_block)) } else { let pattern = match conditionals { - [(Either::Right(_), _)] => make::literal_pat("false").into(), - _ => make::wildcard_pat().into(), + [(Either::Right(_), _)] => make.literal_pat("false").into(), + _ => make.wildcard_pat().into(), }; - (pattern, make::ext::expr_unit()) + (pattern, make.expr_unit()) }; - make::match_arm(pattern, None, expr) + make.match_arm(pattern, None, expr) } // Assist: replace_match_with_if_let @@ -245,21 +248,21 @@ pub(crate) fn replace_match_with_if_let(acc: &mut Assists, ctx: &AssistContext<' } _ => " let", }; - let target = match_expr.syntax().text_range(); acc.add( AssistId("replace_match_with_if_let", AssistKind::RefactorRewrite), format!("Replace match with if{let_}"), - target, - move |edit| { - fn make_block_expr(expr: ast::Expr) -> ast::BlockExpr { + match_expr.syntax().text_range(), + move |builder| { + let make = SyntaxFactory::new(); + let make_block_expr = |expr: ast::Expr| { // Blocks with modifiers (unsafe, async, etc.) are parsed as BlockExpr, but are // formatted without enclosing braces. If we encounter such block exprs, // wrap them in another BlockExpr. match expr { ast::Expr::BlockExpr(block) if block.modifier().is_none() => block, - expr => make::block_expr(iter::empty(), Some(expr)), + expr => make.block_expr([], Some(expr)), } - } + }; let condition = match if_let_pat { ast::Pat::LiteralPat(p) @@ -270,20 +273,25 @@ pub(crate) fn replace_match_with_if_let(acc: &mut Assists, ctx: &AssistContext<' ast::Pat::LiteralPat(p) if p.literal().is_some_and(|it| it.token().kind() == T![false]) => { - make::expr_prefix(T![!], scrutinee).into() + make.expr_prefix(T![!], scrutinee).into() } - _ => make::expr_let(if_let_pat, scrutinee).into(), + _ => make.expr_let(if_let_pat, scrutinee).into(), }; - let then_block = make_block_expr(then_expr.reset_indent()); + let then_expr = then_expr.clone_for_update(); + then_expr.reindent_to(IndentLevel::single()); + let then_block = make_block_expr(then_expr); let else_expr = if is_empty_expr(&else_expr) { None } else { Some(else_expr) }; - let if_let_expr = make::expr_if( + let if_let_expr = make.expr_if( condition, then_block, else_expr.map(make_block_expr).map(ast::ElseBranch::Block), - ) - .indent(IndentLevel::from_node(match_expr.syntax())); + ); + if_let_expr.indent(IndentLevel::from_node(match_expr.syntax())); - edit.replace_ast::(match_expr.into(), if_let_expr.into()); + let mut editor = builder.make_editor(match_expr.syntax()); + editor.replace(match_expr.syntax(), if_let_expr.syntax()); + editor.add_mappings(make.finish_with_mappings()); + builder.add_file_edits(ctx.file_id(), editor); }, ) } From bce64358b72145aad2aa9d77c2a85637848bc452 Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Tue, 7 Jan 2025 23:04:53 +0200 Subject: [PATCH 014/115] Fix a bug with missing binding in MBE We should immediately mark them as finished, on the first entry. The funny (or sad) part was that this bug was pre-existing, but previously to #18327, it was causing us to generate bindings non-stop, 65535 of them, until we get to the hardcoded repetition limit, and then throw it all away. And it was so Blazingly Fast that nobody noticed. With #18327 however, this is still what happens, except that now instead of *merging* the fragments into the result, we write them on-demand. Meaning that when we hit the limit, we've already written all previous entries. This is a minor change, I thought for myself when I was writing this, and it's actually for the better, so who cares. Minor change? Not so fast. This caused us to emit 65535 repetitions, all of which the MBE infra needs to handle when calling other macros with the expansion, and convert to rowan tree etc., which resulted a *massive* hang. The test (and also `analysis-stats`) used to crash with stack overflow on this macro, because we were dropping some crazily deep rowan tree. Now they work properly. Because I am lazy, and also because I could not find the exact conditions that causes a macro match but with a missing binding, I just copied all macros from tracing. Easy. --- .../crates/ide-diagnostics/src/tests.rs | 2 + .../src/tests/overly_long_real_world_cases.rs | 2726 +++++++++++++++++ .../crates/mbe/src/expander/transcriber.rs | 5 +- 3 files changed, 2732 insertions(+), 1 deletion(-) create mode 100644 src/tools/rust-analyzer/crates/ide-diagnostics/src/tests/overly_long_real_world_cases.rs diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs index ec74640a54d9a..7cf51f3d142be 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs @@ -1,5 +1,7 @@ #![allow(clippy::print_stderr)] +mod overly_long_real_world_cases; + use ide_db::{ assists::AssistResolveStrategy, base_db::SourceDatabase, LineIndexDatabase, RootDatabase, }; diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests/overly_long_real_world_cases.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests/overly_long_real_world_cases.rs new file mode 100644 index 0000000000000..c6831d818aac1 --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests/overly_long_real_world_cases.rs @@ -0,0 +1,2726 @@ +//! Overly long excerpts of failures from real world cases, that I was too lazy to minimize. + +use crate::tests::check_diagnostics_with_disabled; + +#[test] +fn tracing_infinite_repeat() { + check_diagnostics_with_disabled( + r#" +//- /core.rs crate:core +#[rustc_builtin_macro] +#[macro_export] +macro_rules! concat { +($($e:expr),* $(,)?) => {{ /* compiler built-in */ }}; +} +#[rustc_builtin_macro] +#[macro_export] +macro_rules! file { +() => { + /* compiler built-in */ +}; +} +#[allow_internal_unsafe] +#[allow_internal_unstable(fmt_internals)] +#[rustc_builtin_macro] +#[macro_export] +macro_rules! format_args { +($fmt:expr) => {{ /* compiler built-in */ }}; +($fmt:expr, $($args:tt)*) => {{ /* compiler built-in */ }}; +} +#[rustc_builtin_macro] +#[macro_export] +macro_rules! line { +() => { + /* compiler built-in */ +}; +} + +//- /tracing_core.rs crate:tracing_core deps:core +#[macro_export] +macro_rules! identify_callsite { +($callsite:expr) => { + $crate::callsite::Identifier($callsite) +}; +} + +#[macro_export] +macro_rules! metadata { +( + name: $name:expr, + target: $target:expr, + level: $level:expr, + fields: $fields:expr, + callsite: $callsite:expr, + kind: $kind:expr +) => { + $crate::metadata! { + name: $name, + target: $target, + level: $level, + fields: $fields, + callsite: $callsite, + kind: $kind, + } +}; +( + name: $name:expr, + target: $target:expr, + level: $level:expr, + fields: $fields:expr, + callsite: $callsite:expr, + kind: $kind:expr, +) => { + $crate::metadata::Metadata::new( + $name, + $target, + $level, + $crate::__macro_support::Option::Some($crate::__macro_support::file!()), + $crate::__macro_support::Option::Some($crate::__macro_support::line!()), + $crate::__macro_support::Option::Some($crate::__macro_support::module_path!()), + $crate::field::FieldSet::new($fields, $crate::identify_callsite!($callsite)), + $kind, + ) +}; +} + +//- /tracing.rs crate:tracing deps:core,tracing_core +#[doc(hidden)] +pub mod __macro_support { +// Re-export the `core` functions that are used in macros. This allows +// a crate to be named `core` and avoid name clashes. +// See here: /~https://github.com/tokio-rs/tracing/issues/2761 +pub use core::{concat, file, format_args, iter::Iterator, line, option::Option}; +} + +#[macro_export] +macro_rules! span { +(target: $target:expr, parent: $parent:expr, $lvl:expr, $name:expr) => { + $crate::span!(target: $target, parent: $parent, $lvl, $name,) +}; +(target: $target:expr, parent: $parent:expr, $lvl:expr, $name:expr, $($fields:tt)*) => { + { + use $crate::__macro_support::Callsite as _; + static __CALLSITE: $crate::__macro_support::MacroCallsite = $crate::callsite2! { + name: $name, + kind: $crate::metadata::Kind::SPAN, + target: $target, + level: $lvl, + fields: $($fields)* + }; + let mut interest = $crate::subscriber::Interest::never(); + if $crate::level_enabled!($lvl) + && { interest = __CALLSITE.interest(); !interest.is_never() } + && $crate::__macro_support::__is_enabled(__CALLSITE.metadata(), interest) + { + let meta = __CALLSITE.metadata(); + // span with explicit parent + $crate::Span::child_of( + $parent, + meta, + &$crate::valueset!(meta.fields(), $($fields)*), + ) + } else { + let span = $crate::__macro_support::__disabled_span(__CALLSITE.metadata()); + $crate::if_log_enabled! { $lvl, { + span.record_all(&$crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*)); + }}; + span + } + } +}; +(target: $target:expr, $lvl:expr, $name:expr, $($fields:tt)*) => { + { + use $crate::__macro_support::Callsite as _; + static __CALLSITE: $crate::callsite::DefaultCallsite = $crate::callsite2! { + name: $name, + kind: $crate::metadata::Kind::SPAN, + target: $target, + level: $lvl, + fields: $($fields)* + }; + let mut interest = $crate::subscriber::Interest::never(); + if $crate::level_enabled!($lvl) + && { interest = __CALLSITE.interest(); !interest.is_never() } + && $crate::__macro_support::__is_enabled(__CALLSITE.metadata(), interest) + { + let meta = __CALLSITE.metadata(); + // span with contextual parent + $crate::Span::new( + meta, + &$crate::valueset!(meta.fields(), $($fields)*), + ) + } else { + let span = $crate::__macro_support::__disabled_span(__CALLSITE.metadata()); + $crate::if_log_enabled! { $lvl, { + span.record_all(&$crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*)); + }}; + span + } + } +}; +(target: $target:expr, parent: $parent:expr, $lvl:expr, $name:expr) => { + $crate::span!(target: $target, parent: $parent, $lvl, $name,) +}; +(parent: $parent:expr, $lvl:expr, $name:expr, $($fields:tt)*) => { + $crate::span!( + target: module_path!(), + parent: $parent, + $lvl, + $name, + $($fields)* + ) +}; +(parent: $parent:expr, $lvl:expr, $name:expr) => { + $crate::span!( + target: module_path!(), + parent: $parent, + $lvl, + $name, + ) +}; +(target: $target:expr, $lvl:expr, $name:expr, $($fields:tt)*) => { + $crate::span!( + target: $target, + $lvl, + $name, + $($fields)* + ) +}; +(target: $target:expr, $lvl:expr, $name:expr) => { + $crate::span!(target: $target, $lvl, $name,) +}; +($lvl:expr, $name:expr, $($fields:tt)*) => { + $crate::span!( + target: module_path!(), + $lvl, + $name, + $($fields)* + ) +}; +($lvl:expr, $name:expr) => { + $crate::span!( + target: module_path!(), + $lvl, + $name, + ) +}; +} + +#[macro_export] +macro_rules! trace_span { +(target: $target:expr, parent: $parent:expr, $name:expr, $($field:tt)*) => { + $crate::span!( + target: $target, + parent: $parent, + $crate::Level::TRACE, + $name, + $($field)* + ) +}; +(target: $target:expr, parent: $parent:expr, $name:expr) => { + $crate::trace_span!(target: $target, parent: $parent, $name,) +}; +(parent: $parent:expr, $name:expr, $($field:tt)*) => { + $crate::span!( + target: module_path!(), + parent: $parent, + $crate::Level::TRACE, + $name, + $($field)* + ) +}; +(parent: $parent:expr, $name:expr) => { + $crate::trace_span!(parent: $parent, $name,) +}; +(target: $target:expr, $name:expr, $($field:tt)*) => { + $crate::span!( + target: $target, + $crate::Level::TRACE, + $name, + $($field)* + ) +}; +(target: $target:expr, $name:expr) => { + $crate::trace_span!(target: $target, $name,) +}; +($name:expr, $($field:tt)*) => { + $crate::span!( + target: module_path!(), + $crate::Level::TRACE, + $name, + $($field)* + ) +}; +($name:expr) => { $crate::trace_span!($name,) }; +} + +#[macro_export] +macro_rules! debug_span { +(target: $target:expr, parent: $parent:expr, $name:expr, $($field:tt)*) => { + $crate::span!( + target: $target, + parent: $parent, + $crate::Level::DEBUG, + $name, + $($field)* + ) +}; +(target: $target:expr, parent: $parent:expr, $name:expr) => { + $crate::debug_span!(target: $target, parent: $parent, $name,) +}; +(parent: $parent:expr, $name:expr, $($field:tt)*) => { + $crate::span!( + target: module_path!(), + parent: $parent, + $crate::Level::DEBUG, + $name, + $($field)* + ) +}; +(parent: $parent:expr, $name:expr) => { + $crate::debug_span!(parent: $parent, $name,) +}; +(target: $target:expr, $name:expr, $($field:tt)*) => { + $crate::span!( + target: $target, + $crate::Level::DEBUG, + $name, + $($field)* + ) +}; +(target: $target:expr, $name:expr) => { + $crate::debug_span!(target: $target, $name,) +}; +($name:expr, $($field:tt)*) => { + $crate::span!( + target: module_path!(), + $crate::Level::DEBUG, + $name, + $($field)* + ) +}; +($name:expr) => {$crate::debug_span!($name,)}; +} + +#[macro_export] +macro_rules! info_span { +(target: $target:expr, parent: $parent:expr, $name:expr, $($field:tt)*) => { + $crate::span!( + target: $target, + parent: $parent, + $crate::Level::INFO, + $name, + $($field)* + ) +}; +(target: $target:expr, parent: $parent:expr, $name:expr) => { + $crate::info_span!(target: $target, parent: $parent, $name,) +}; +(parent: $parent:expr, $name:expr, $($field:tt)*) => { + $crate::span!( + target: module_path!(), + parent: $parent, + $crate::Level::INFO, + $name, + $($field)* + ) +}; +(parent: $parent:expr, $name:expr) => { + $crate::info_span!(parent: $parent, $name,) +}; +(target: $target:expr, $name:expr, $($field:tt)*) => { + $crate::span!( + target: $target, + $crate::Level::INFO, + $name, + $($field)* + ) +}; +(target: $target:expr, $name:expr) => { + $crate::info_span!(target: $target, $name,) +}; +($name:expr, $($field:tt)*) => { + $crate::span!( + target: module_path!(), + $crate::Level::INFO, + $name, + $($field)* + ) +}; +($name:expr) => {$crate::info_span!($name,)}; +} + +#[macro_export] +macro_rules! warn_span { +(target: $target:expr, parent: $parent:expr, $name:expr, $($field:tt)*) => { + $crate::span!( + target: $target, + parent: $parent, + $crate::Level::WARN, + $name, + $($field)* + ) +}; +(target: $target:expr, parent: $parent:expr, $name:expr) => { + $crate::warn_span!(target: $target, parent: $parent, $name,) +}; +(parent: $parent:expr, $name:expr, $($field:tt)*) => { + $crate::span!( + target: module_path!(), + parent: $parent, + $crate::Level::WARN, + $name, + $($field)* + ) +}; +(parent: $parent:expr, $name:expr) => { + $crate::warn_span!(parent: $parent, $name,) +}; +(target: $target:expr, $name:expr, $($field:tt)*) => { + $crate::span!( + target: $target, + $crate::Level::WARN, + $name, + $($field)* + ) +}; +(target: $target:expr, $name:expr) => { + $crate::warn_span!(target: $target, $name,) +}; +($name:expr, $($field:tt)*) => { + $crate::span!( + target: module_path!(), + $crate::Level::WARN, + $name, + $($field)* + ) +}; +($name:expr) => {$crate::warn_span!($name,)}; +} + +#[macro_export] +macro_rules! error_span { +(target: $target:expr, parent: $parent:expr, $name:expr, $($field:tt)*) => { + $crate::span!( + target: $target, + parent: $parent, + $crate::Level::ERROR, + $name, + $($field)* + ) +}; +(target: $target:expr, parent: $parent:expr, $name:expr) => { + $crate::error_span!(target: $target, parent: $parent, $name,) +}; +(parent: $parent:expr, $name:expr, $($field:tt)*) => { + $crate::span!( + target: module_path!(), + parent: $parent, + $crate::Level::ERROR, + $name, + $($field)* + ) +}; +(parent: $parent:expr, $name:expr) => { + $crate::error_span!(parent: $parent, $name,) +}; +(target: $target:expr, $name:expr, $($field:tt)*) => { + $crate::span!( + target: $target, + $crate::Level::ERROR, + $name, + $($field)* + ) +}; +(target: $target:expr, $name:expr) => { + $crate::error_span!(target: $target, $name,) +}; +($name:expr, $($field:tt)*) => { + $crate::span!( + target: module_path!(), + $crate::Level::ERROR, + $name, + $($field)* + ) +}; +($name:expr) => {$crate::error_span!($name,)}; +} + +#[macro_export] +macro_rules! event { +// Name / target / parent. +(name: $name:expr, target: $target:expr, parent: $parent:expr, $lvl:expr, { $($fields:tt)* } )=> ({ + use $crate::__macro_support::Callsite as _; + static __CALLSITE: $crate::__macro_support::MacroCallsite = $crate::callsite2! { + name: $name, + kind: $crate::metadata::Kind::EVENT, + target: $target, + level: $lvl, + fields: $($fields)* + }; + + let enabled = $crate::level_enabled!($lvl) && { + let interest = __CALLSITE.interest(); + !interest.is_never() && $crate::__macro_support::__is_enabled(__CALLSITE.metadata(), interest) + }; + if enabled { + (|value_set: $crate::field::ValueSet| { + $crate::__tracing_log!( + $lvl, + __CALLSITE, + &value_set + ); + let meta = __CALLSITE.metadata(); + // event with explicit parent + $crate::Event::child_of( + $parent, + meta, + &value_set + ); + })($crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*)); + } else { + $crate::__tracing_log!( + $lvl, + __CALLSITE, + &$crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*) + ); + } +}); +(name: $name:expr, target: $target:expr, parent: $parent:expr, $lvl:expr, { $($fields:tt)* }, $($arg:tt)+ ) => ( + $crate::event!( + name: $name, + target: $target, + parent: $parent, + $lvl, + { message = $crate::__macro_support::format_args!($($arg)+), $($fields)* } + ) +); +(name: $name:expr, target: $target:expr, parent: $parent:expr, $lvl:expr, $($k:ident).+ = $($fields:tt)* ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $lvl, { $($k).+ = $($fields)* }) +); +(name: $name:expr, target: $target:expr, parent: $parent:expr, $lvl:expr, $($arg:tt)+) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $lvl, { $($arg)+ }) +); + +// Name / target. +(name: $name:expr, target: $target:expr, $lvl:expr, { $($fields:tt)* } )=> ({ + use $crate::__macro_support::Callsite as _; + static __CALLSITE: $crate::__macro_support::MacroCallsite = $crate::callsite2! { + name: $name, + kind: $crate::metadata::Kind::EVENT, + target: $target, + level: $lvl, + fields: $($fields)* + }; + let enabled = $crate::level_enabled!($lvl) && { + let interest = __CALLSITE.interest(); + !interest.is_never() && $crate::__macro_support::__is_enabled(__CALLSITE.metadata(), interest) + }; + if enabled { + (|value_set: $crate::field::ValueSet| { + let meta = __CALLSITE.metadata(); + // event with contextual parent + $crate::Event::dispatch( + meta, + &value_set + ); + $crate::__tracing_log!( + $lvl, + __CALLSITE, + &value_set + ); + })($crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*)); + } else { + $crate::__tracing_log!( + $lvl, + __CALLSITE, + &$crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*) + ); + } +}); +(name: $name:expr, target: $target:expr, $lvl:expr, { $($fields:tt)* }, $($arg:tt)+ ) => ( + $crate::event!( + name: $name, + target: $target, + $lvl, + { message = $crate::__macro_support::format_args!($($arg)+), $($fields)* } + ) +); +(name: $name:expr, target: $target:expr, $lvl:expr, $($k:ident).+ = $($fields:tt)* ) => ( + $crate::event!(name: $name, target: $target, $lvl, { $($k).+ = $($fields)* }) +); +(name: $name:expr, target: $target:expr, $lvl:expr, $($arg:tt)+) => ( + $crate::event!(name: $name, target: $target, $lvl, { $($arg)+ }) +); + +// Target / parent. +(target: $target:expr, parent: $parent:expr, $lvl:expr, { $($fields:tt)* } )=> ({ + use $crate::__macro_support::Callsite as _; + static __CALLSITE: $crate::callsite::DefaultCallsite = $crate::callsite2! { + name: $crate::__macro_support::concat!( + "event ", + $crate::__macro_support::file!(), + ":", + $crate::__macro_support::line!() + ), + kind: $crate::metadata::Kind::EVENT, + target: $target, + level: $lvl, + fields: $($fields)* + }; + + let enabled = $crate::level_enabled!($lvl) && { + let interest = __CALLSITE.interest(); + !interest.is_never() && $crate::__macro_support::__is_enabled(__CALLSITE.metadata(), interest) + }; + if enabled { + (|value_set: $crate::field::ValueSet| { + $crate::__tracing_log!( + $lvl, + __CALLSITE, + &value_set + ); + let meta = __CALLSITE.metadata(); + // event with explicit parent + $crate::Event::child_of( + $parent, + meta, + &value_set + ); + })($crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*)); + } else { + $crate::__tracing_log!( + $lvl, + __CALLSITE, + &$crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*) + ); + } +}); +(target: $target:expr, parent: $parent:expr, $lvl:expr, { $($fields:tt)* }, $($arg:tt)+ ) => ( + $crate::event!( + target: $target, + parent: $parent, + $lvl, + { message = $crate::__macro_support::format_args!($($arg)+), $($fields)* } + ) +); +(target: $target:expr, parent: $parent:expr, $lvl:expr, $($k:ident).+ = $($fields:tt)* ) => ( + $crate::event!(target: $target, parent: $parent, $lvl, { $($k).+ = $($fields)* }) +); +(target: $target:expr, parent: $parent:expr, $lvl:expr, $($arg:tt)+) => ( + $crate::event!(target: $target, parent: $parent, $lvl, { $($arg)+ }) +); + +// Name / parent. +(name: $name:expr, parent: $parent:expr, $lvl:expr, { $($fields:tt)* } )=> ({ + use $crate::__macro_support::Callsite as _; + static __CALLSITE: $crate::__macro_support::MacroCallsite = $crate::callsite2! { + name: $name, + kind: $crate::metadata::Kind::EVENT, + target: module_path!(), + level: $lvl, + fields: $($fields)* + }; + + let enabled = $crate::level_enabled!($lvl) && { + let interest = __CALLSITE.interest(); + !interest.is_never() && __CALLSITE.is_enabled(interest) + }; + if enabled { + (|value_set: $crate::field::ValueSet| { + $crate::__tracing_log!( + $lvl, + __CALLSITE, + &value_set + ); + let meta = __CALLSITE.metadata(); + // event with explicit parent + $crate::Event::child_of( + $parent, + meta, + &value_set + ); + })($crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*)); + } else { + $crate::__tracing_log!( + $lvl, + __CALLSITE, + &$crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*) + ); + } +}); +(name: $name:expr, parent: $parent:expr, $lvl:expr, { $($fields:tt)* }, $($arg:tt)+ ) => ( + $crate::event!( + name: $name, + parent: $parent, + $lvl, + { message = $crate::__macro_support::format_args!($($arg)+), $($fields)* } + ) +); +(name: $name:expr, parent: $parent:expr, $lvl:expr, $($k:ident).+ = $($fields:tt)* ) => ( + $crate::event!(name: $name, parent: $parent, $lvl, { $($k).+ = $($fields)* }) +); +(name: $name:expr, parent: $parent:expr, $lvl:expr, $($arg:tt)+) => ( + $crate::event!(name: $name, parent: $parent, $lvl, { $($arg)+ }) +); + +// Name. +(name: $name:expr, $lvl:expr, { $($fields:tt)* } )=> ({ + use $crate::__macro_support::Callsite as _; + static __CALLSITE: $crate::__macro_support::MacroCallsite = $crate::callsite2! { + name: $name, + kind: $crate::metadata::Kind::EVENT, + target: module_path!(), + level: $lvl, + fields: $($fields)* + }; + let enabled = $crate::level_enabled!($lvl) && { + let interest = __CALLSITE.interest(); + !interest.is_never() && $crate::__macro_support::__is_enabled(__CALLSITE.metadata(), interest) + }; + if enabled { + (|value_set: $crate::field::ValueSet| { + let meta = __CALLSITE.metadata(); + // event with contextual parent + $crate::Event::dispatch( + meta, + &value_set + ); + $crate::__tracing_log!( + $lvl, + __CALLSITE, + &value_set + ); + })($crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*)); + } else { + $crate::__tracing_log!( + $lvl, + __CALLSITE, + &$crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*) + ); + } +}); +(name: $name:expr, $lvl:expr, { $($fields:tt)* }, $($arg:tt)+ ) => ( + $crate::event!( + name: $name, + $lvl, + { message = $crate::__macro_support::format_args!($($arg)+), $($fields)* } + ) +); +(name: $name:expr, $lvl:expr, $($k:ident).+ = $($fields:tt)* ) => ( + $crate::event!(name: $name, $lvl, { $($k).+ = $($fields)* }) +); +(name: $name:expr, $lvl:expr, $($arg:tt)+ ) => ( + $crate::event!(name: $name, $lvl, { $($arg)+ }) +); + +// Target. +(target: $target:expr, $lvl:expr, { $($fields:tt)* } )=> ({ + use $crate::__macro_support::Callsite as _; + static __CALLSITE: $crate::callsite::DefaultCallsite = $crate::callsite2! { + name: $crate::__macro_support::concat!( + "event ", + $crate::__macro_support::file!(), + ":", + $crate::__macro_support::line!() + ), + kind: $crate::metadata::Kind::EVENT, + target: $target, + level: $lvl, + fields: $($fields)* + }; + let enabled = $crate::level_enabled!($lvl) && { + let interest = __CALLSITE.interest(); + !interest.is_never() && $crate::__macro_support::__is_enabled(__CALLSITE.metadata(), interest) + }; + if enabled { + (|value_set: $crate::field::ValueSet| { + let meta = __CALLSITE.metadata(); + // event with contextual parent + $crate::Event::dispatch( + meta, + &value_set + ); + $crate::__tracing_log!( + $lvl, + __CALLSITE, + &value_set + ); + })($crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*)); + } else { + $crate::__tracing_log!( + $lvl, + __CALLSITE, + &$crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*) + ); + } +}); +(target: $target:expr, $lvl:expr, { $($fields:tt)* }, $($arg:tt)+ ) => ( + $crate::event!( + target: $target, + $lvl, + { message = $crate::__macro_support::format_args!($($arg)+), $($fields)* } + ) +); +(target: $target:expr, $lvl:expr, $($k:ident).+ = $($fields:tt)* ) => ( + $crate::event!(target: $target, $lvl, { $($k).+ = $($fields)* }) +); +(target: $target:expr, $lvl:expr, $($arg:tt)+ ) => ( + $crate::event!(target: $target, $lvl, { $($arg)+ }) +); + +// Parent. +(parent: $parent:expr, $lvl:expr, { $($fields:tt)* }, $($arg:tt)+ ) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $lvl, + { message = $crate::__macro_support::format_args!($($arg)+), $($fields)* } + ) +); +(parent: $parent:expr, $lvl:expr, $($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $lvl, + { $($k).+ = $($field)*} + ) +); +(parent: $parent:expr, $lvl:expr, ?$($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $lvl, + { ?$($k).+ = $($field)*} + ) +); +(parent: $parent:expr, $lvl:expr, %$($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $lvl, + { %$($k).+ = $($field)*} + ) +); +(parent: $parent:expr, $lvl:expr, $($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $lvl, + { $($k).+, $($field)*} + ) +); +(parent: $parent:expr, $lvl:expr, %$($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $lvl, + { %$($k).+, $($field)*} + ) +); +(parent: $parent:expr, $lvl:expr, ?$($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $lvl, + { ?$($k).+, $($field)*} + ) +); +(parent: $parent:expr, $lvl:expr, $($arg:tt)+ ) => ( + $crate::event!(target: module_path!(), parent: $parent, $lvl, { $($arg)+ }) +); + +// ... +( $lvl:expr, { $($fields:tt)* }, $($arg:tt)+ ) => ( + $crate::event!( + target: module_path!(), + $lvl, + { message = $crate::__macro_support::format_args!($($arg)+), $($fields)* } + ) +); +( $lvl:expr, { $($fields:tt)* }, $($arg:tt)+ ) => ( + $crate::event!( + target: module_path!(), + $lvl, + { message = format_args!($($arg)+), $($fields)* } + ) +); +($lvl:expr, $($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $lvl, + { $($k).+ = $($field)*} + ) +); +($lvl:expr, $($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $lvl, + { $($k).+, $($field)*} + ) +); +($lvl:expr, ?$($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $lvl, + { ?$($k).+, $($field)*} + ) +); +($lvl:expr, %$($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $lvl, + { %$($k).+, $($field)*} + ) +); +($lvl:expr, ?$($k:ident).+) => ( + $crate::event!($lvl, ?$($k).+,) +); +($lvl:expr, %$($k:ident).+) => ( + $crate::event!($lvl, %$($k).+,) +); +($lvl:expr, $($k:ident).+) => ( + $crate::event!($lvl, $($k).+,) +); +( $lvl:expr, $($arg:tt)+ ) => ( + $crate::event!(target: module_path!(), $lvl, { $($arg)+ }) +); +} + +#[macro_export] +macro_rules! event_enabled { +($($rest:tt)*)=> ( + $crate::enabled!(kind: $crate::metadata::Kind::EVENT, $($rest)*) +) +} + +#[macro_export] +macro_rules! span_enabled { +($($rest:tt)*)=> ( + $crate::enabled!(kind: $crate::metadata::Kind::SPAN, $($rest)*) +) +} + +#[macro_export] +macro_rules! enabled { +(kind: $kind:expr, target: $target:expr, $lvl:expr, { $($fields:tt)* } )=> ({ + if $crate::level_enabled!($lvl) { + use $crate::__macro_support::Callsite as _; + static __CALLSITE: $crate::callsite::DefaultCallsite = $crate::callsite2! { + name: $crate::__macro_support::concat!( + "enabled ", + $crate::__macro_support::file!(), + ":", + $crate::__macro_support::line!() + ), + kind: $kind.hint(), + target: $target, + level: $lvl, + fields: $($fields)* + }; + let interest = __CALLSITE.interest(); + if !interest.is_never() && $crate::__macro_support::__is_enabled(__CALLSITE.metadata(), interest) { + let meta = __CALLSITE.metadata(); + $crate::dispatcher::get_default(|current| current.enabled(meta)) + } else { + false + } + } else { + false + } +}); +// Just target and level +(kind: $kind:expr, target: $target:expr, $lvl:expr ) => ( + $crate::enabled!(kind: $kind, target: $target, $lvl, { }) +); +(target: $target:expr, $lvl:expr ) => ( + $crate::enabled!(kind: $crate::metadata::Kind::HINT, target: $target, $lvl, { }) +); + +// These four cases handle fields with no values +(kind: $kind:expr, target: $target:expr, $lvl:expr, $($field:tt)*) => ( + $crate::enabled!( + kind: $kind, + target: $target, + $lvl, + { $($field)*} + ) +); +(target: $target:expr, $lvl:expr, $($field:tt)*) => ( + $crate::enabled!( + kind: $crate::metadata::Kind::HINT, + target: $target, + $lvl, + { $($field)*} + ) +); + +// Level and field case +(kind: $kind:expr, $lvl:expr, $($field:tt)*) => ( + $crate::enabled!( + kind: $kind, + target: module_path!(), + $lvl, + { $($field)*} + ) +); + +// Simplest `enabled!` case +(kind: $kind:expr, $lvl:expr) => ( + $crate::enabled!(kind: $kind, target: module_path!(), $lvl, { }) +); +($lvl:expr) => ( + $crate::enabled!(kind: $crate::metadata::Kind::HINT, target: module_path!(), $lvl, { }) +); + +// Fallthrough from above +($lvl:expr, $($field:tt)*) => ( + $crate::enabled!( + kind: $crate::metadata::Kind::HINT, + target: module_path!(), + $lvl, + { $($field)*} + ) +); +} + +#[macro_export] +macro_rules! trace { +// Name / target / parent. +(name: $name:expr, target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::TRACE, { $($field)* }, $($arg)*) +); +(name: $name:expr, target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::TRACE, { $($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::TRACE, { ?$($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::TRACE, { %$($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::TRACE, {}, $($arg)+) +); + +// Name / target. +(name: $name:expr, target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::TRACE, { $($field)* }, $($arg)*) +); +(name: $name:expr, target: $target:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::TRACE, { $($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::TRACE, { ?$($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::TRACE, { %$($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, $($arg:tt)+ ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::TRACE, {}, $($arg)+) +); + +// Target / parent. +(target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::TRACE, { $($field)* }, $($arg)*) +); +(target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::TRACE, { $($k).+ $($field)* }) +); +(target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::TRACE, { ?$($k).+ $($field)* }) +); +(target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::TRACE, { %$($k).+ $($field)* }) +); +(target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::TRACE, {}, $($arg)+) +); + +// Name / parent. +(name: $name:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::TRACE, { $($field)* }, $($arg)*) +); +(name: $name:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::TRACE, { $($k).+ $($field)* }) +); +(name: $name:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::TRACE, { ?$($k).+ $($field)* }) +); +(name: $name:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::TRACE, { %$($k).+ $($field)* }) +); +(name: $name:expr, parent: $parent:expr, $($arg:tt)+ ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::TRACE, {}, $($arg)+) +); + +// Name. +(name: $name:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(name: $name, $crate::Level::TRACE, { $($field)* }, $($arg)*) +); +(name: $name:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, $crate::Level::TRACE, { $($k).+ $($field)* }) +); +(name: $name:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, $crate::Level::TRACE, { ?$($k).+ $($field)* }) +); +(name: $name:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, $crate::Level::TRACE, { %$($k).+ $($field)* }) +); +(name: $name:expr, $($arg:tt)+ ) => ( + $crate::event!(name: $name, $crate::Level::TRACE, {}, $($arg)+) +); + +// Target. +(target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(target: $target, $crate::Level::TRACE, { $($field)* }, $($arg)*) +); +(target: $target:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, $crate::Level::TRACE, { $($k).+ $($field)* }) +); +(target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, $crate::Level::TRACE, { ?$($k).+ $($field)* }) +); +(target: $target:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, $crate::Level::TRACE, { %$($k).+ $($field)* }) +); +(target: $target:expr, $($arg:tt)+ ) => ( + $crate::event!(target: $target, $crate::Level::TRACE, {}, $($arg)+) +); + +// Parent. +(parent: $parent:expr, { $($field:tt)+ }, $($arg:tt)+ ) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::TRACE, + { $($field)+ }, + $($arg)+ + ) +); +(parent: $parent:expr, $($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::TRACE, + { $($k).+ = $($field)*} + ) +); +(parent: $parent:expr, ?$($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::TRACE, + { ?$($k).+ = $($field)*} + ) +); +(parent: $parent:expr, %$($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::TRACE, + { %$($k).+ = $($field)*} + ) +); +(parent: $parent:expr, $($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::TRACE, + { $($k).+, $($field)*} + ) +); +(parent: $parent:expr, ?$($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::TRACE, + { ?$($k).+, $($field)*} + ) +); +(parent: $parent:expr, %$($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::TRACE, + { %$($k).+, $($field)*} + ) +); +(parent: $parent:expr, $($arg:tt)+) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::TRACE, + {}, + $($arg)+ + ) +); + +// ... +({ $($field:tt)+ }, $($arg:tt)+ ) => ( + $crate::event!( + target: module_path!(), + $crate::Level::TRACE, + { $($field)+ }, + $($arg)+ + ) +); +($($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::TRACE, + { $($k).+ = $($field)*} + ) +); +(?$($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::TRACE, + { ?$($k).+ = $($field)*} + ) +); +(%$($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::TRACE, + { %$($k).+ = $($field)*} + ) +); +($($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::TRACE, + { $($k).+, $($field)*} + ) +); +(?$($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::TRACE, + { ?$($k).+, $($field)*} + ) +); +(%$($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::TRACE, + { %$($k).+, $($field)*} + ) +); +(?$($k:ident).+) => ( + $crate::event!( + target: module_path!(), + $crate::Level::TRACE, + { ?$($k).+ } + ) +); +(%$($k:ident).+) => ( + $crate::event!( + target: module_path!(), + $crate::Level::TRACE, + { %$($k).+ } + ) +); +($($k:ident).+) => ( + $crate::event!( + target: module_path!(), + $crate::Level::TRACE, + { $($k).+ } + ) +); +($($arg:tt)+) => ( + $crate::event!( + target: module_path!(), + $crate::Level::TRACE, + $($arg)+ + ) +); +} + +#[macro_export] +macro_rules! debug { +// Name / target / parent. +(name: $name:expr, target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::DEBUG, { $($field)* }, $($arg)*) +); +(name: $name:expr, target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::DEBUG, { $($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::DEBUG, { ?$($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::DEBUG, { %$($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::DEBUG, {}, $($arg)+) +); + +// Name / target. +(name: $name:expr, target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::DEBUG, { $($field)* }, $($arg)*) +); +(name: $name:expr, target: $target:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::DEBUG, { $($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::DEBUG, { ?$($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::DEBUG, { %$($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, $($arg:tt)+ ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::DEBUG, {}, $($arg)+) +); + +// Target / parent. +(target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::DEBUG, { $($field)* }, $($arg)*) +); +(target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::DEBUG, { $($k).+ $($field)* }) +); +(target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::DEBUG, { ?$($k).+ $($field)* }) +); +(target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::DEBUG, { %$($k).+ $($field)* }) +); +(target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::DEBUG, {}, $($arg)+) +); + +// Name / parent. +(name: $name:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::DEBUG, { $($field)* }, $($arg)*) +); +(name: $name:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::DEBUG, { $($k).+ $($field)* }) +); +(name: $name:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::DEBUG, { ?$($k).+ $($field)* }) +); +(name: $name:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::DEBUG, { %$($k).+ $($field)* }) +); +(name: $name:expr, parent: $parent:expr, $($arg:tt)+ ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::DEBUG, {}, $($arg)+) +); + +// Name. +(name: $name:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(name: $name, $crate::Level::DEBUG, { $($field)* }, $($arg)*) +); +(name: $name:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, $crate::Level::DEBUG, { $($k).+ $($field)* }) +); +(name: $name:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, $crate::Level::DEBUG, { ?$($k).+ $($field)* }) +); +(name: $name:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, $crate::Level::DEBUG, { %$($k).+ $($field)* }) +); +(name: $name:expr, $($arg:tt)+ ) => ( + $crate::event!(name: $name, $crate::Level::DEBUG, {}, $($arg)+) +); + +// Target. +(target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(target: $target, $crate::Level::DEBUG, { $($field)* }, $($arg)*) +); +(target: $target:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, $crate::Level::DEBUG, { $($k).+ $($field)* }) +); +(target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, $crate::Level::DEBUG, { ?$($k).+ $($field)* }) +); +(target: $target:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, $crate::Level::DEBUG, { %$($k).+ $($field)* }) +); +(target: $target:expr, $($arg:tt)+ ) => ( + $crate::event!(target: $target, $crate::Level::DEBUG, {}, $($arg)+) +); + +// Parent. +(parent: $parent:expr, { $($field:tt)+ }, $($arg:tt)+ ) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::DEBUG, + { $($field)+ }, + $($arg)+ + ) +); +(parent: $parent:expr, $($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::DEBUG, + { $($k).+ = $($field)*} + ) +); +(parent: $parent:expr, ?$($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::DEBUG, + { ?$($k).+ = $($field)*} + ) +); +(parent: $parent:expr, %$($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::DEBUG, + { %$($k).+ = $($field)*} + ) +); +(parent: $parent:expr, $($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::DEBUG, + { $($k).+, $($field)*} + ) +); +(parent: $parent:expr, ?$($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::DEBUG, + { ?$($k).+, $($field)*} + ) +); +(parent: $parent:expr, %$($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::DEBUG, + { %$($k).+, $($field)*} + ) +); +(parent: $parent:expr, $($arg:tt)+) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::DEBUG, + {}, + $($arg)+ + ) +); + +// ... +({ $($field:tt)+ }, $($arg:tt)+ ) => ( + $crate::event!( + target: module_path!(), + $crate::Level::DEBUG, + { $($field)+ }, + $($arg)+ + ) +); +($($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::DEBUG, + { $($k).+ = $($field)*} + ) +); +(?$($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::DEBUG, + { ?$($k).+ = $($field)*} + ) +); +(%$($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::DEBUG, + { %$($k).+ = $($field)*} + ) +); +($($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::DEBUG, + { $($k).+, $($field)*} + ) +); +(?$($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::DEBUG, + { ?$($k).+, $($field)*} + ) +); +(%$($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::DEBUG, + { %$($k).+, $($field)*} + ) +); +(?$($k:ident).+) => ( + $crate::event!( + target: module_path!(), + $crate::Level::DEBUG, + { ?$($k).+ } + ) +); +(%$($k:ident).+) => ( + $crate::event!( + target: module_path!(), + $crate::Level::DEBUG, + { %$($k).+ } + ) +); +($($k:ident).+) => ( + $crate::event!( + target: module_path!(), + $crate::Level::DEBUG, + { $($k).+ } + ) +); +($($arg:tt)+) => ( + $crate::event!( + target: module_path!(), + $crate::Level::DEBUG, + $($arg)+ + ) +); +} + +#[macro_export] +macro_rules! info { +// Name / target / parent. +(name: $name:expr, target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::INFO, { $($field)* }, $($arg)*) +); +(name: $name:expr, target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::INFO, { $($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::INFO, { ?$($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::INFO, { %$($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::INFO, {}, $($arg)+) +); + +// Name / target. +(name: $name:expr, target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::INFO, { $($field)* }, $($arg)*) +); +(name: $name:expr, target: $target:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::INFO, { $($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::INFO, { ?$($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::INFO, { %$($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, $($arg:tt)+ ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::INFO, {}, $($arg)+) +); + +// Target / parent. +(target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::INFO, { $($field)* }, $($arg)*) +); +(target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::INFO, { $($k).+ $($field)* }) +); +(target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::INFO, { ?$($k).+ $($field)* }) +); +(target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::INFO, { %$($k).+ $($field)* }) +); +(target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::INFO, {}, $($arg)+) +); + +// Name / parent. +(name: $name:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::INFO, { $($field)* }, $($arg)*) +); +(name: $name:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::INFO, { $($k).+ $($field)* }) +); +(name: $name:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::INFO, { ?$($k).+ $($field)* }) +); +(name: $name:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::INFO, { %$($k).+ $($field)* }) +); +(name: $name:expr, parent: $parent:expr, $($arg:tt)+ ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::INFO, {}, $($arg)+) +); + +// Name. +(name: $name:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(name: $name, $crate::Level::INFO, { $($field)* }, $($arg)*) +); +(name: $name:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, $crate::Level::INFO, { $($k).+ $($field)* }) +); +(name: $name:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, $crate::Level::INFO, { ?$($k).+ $($field)* }) +); +(name: $name:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, $crate::Level::INFO, { %$($k).+ $($field)* }) +); +(name: $name:expr, $($arg:tt)+ ) => ( + $crate::event!(name: $name, $crate::Level::INFO, {}, $($arg)+) +); + +// Target. +(target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(target: $target, $crate::Level::INFO, { $($field)* }, $($arg)*) +); +(target: $target:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, $crate::Level::INFO, { $($k).+ $($field)* }) +); +(target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, $crate::Level::INFO, { ?$($k).+ $($field)* }) +); +(target: $target:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, $crate::Level::INFO, { %$($k).+ $($field)* }) +); +(target: $target:expr, $($arg:tt)+ ) => ( + $crate::event!(target: $target, $crate::Level::INFO, {}, $($arg)+) +); + +// Parent. +(parent: $parent:expr, { $($field:tt)+ }, $($arg:tt)+ ) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::INFO, + { $($field)+ }, + $($arg)+ + ) +); +(parent: $parent:expr, $($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::INFO, + { $($k).+ = $($field)*} + ) +); +(parent: $parent:expr, ?$($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::INFO, + { ?$($k).+ = $($field)*} + ) +); +(parent: $parent:expr, %$($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::INFO, + { %$($k).+ = $($field)*} + ) +); +(parent: $parent:expr, $($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::INFO, + { $($k).+, $($field)*} + ) +); +(parent: $parent:expr, ?$($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::INFO, + { ?$($k).+, $($field)*} + ) +); +(parent: $parent:expr, %$($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::INFO, + { %$($k).+, $($field)*} + ) +); +(parent: $parent:expr, $($arg:tt)+) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::INFO, + {}, + $($arg)+ + ) +); + +// ... +({ $($field:tt)+ }, $($arg:tt)+ ) => ( + $crate::event!( + target: module_path!(), + $crate::Level::INFO, + { $($field)+ }, + $($arg)+ + ) +); +($($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::INFO, + { $($k).+ = $($field)*} + ) +); +(?$($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::INFO, + { ?$($k).+ = $($field)*} + ) +); +(%$($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::INFO, + { %$($k).+ = $($field)*} + ) +); +($($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::INFO, + { $($k).+, $($field)*} + ) +); +(?$($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::INFO, + { ?$($k).+, $($field)*} + ) +); +(%$($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::INFO, + { %$($k).+, $($field)*} + ) +); +(?$($k:ident).+) => ( + $crate::event!( + target: module_path!(), + $crate::Level::INFO, + { ?$($k).+ } + ) +); +(%$($k:ident).+) => ( + $crate::event!( + target: module_path!(), + $crate::Level::INFO, + { %$($k).+ } + ) +); +($($k:ident).+) => ( + $crate::event!( + target: module_path!(), + $crate::Level::INFO, + { $($k).+ } + ) +); +($($arg:tt)+) => ( + $crate::event!( + target: module_path!(), + $crate::Level::INFO, + $($arg)+ + ) +); +} + +#[macro_export] +macro_rules! warn { +// Name / target / parent. +(name: $name:expr, target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::WARN, { $($field)* }, $($arg)*) +); +(name: $name:expr, target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::WARN, { $($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::WARN, { ?$($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::WARN, { %$($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::WARN, {}, $($arg)+) +); + +// Name / target. +(name: $name:expr, target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::WARN, { $($field)* }, $($arg)*) +); +(name: $name:expr, target: $target:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::WARN, { $($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::WARN, { ?$($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::WARN, { %$($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, $($arg:tt)+ ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::WARN, {}, $($arg)+) +); + +// Target / parent. +(target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::WARN, { $($field)* }, $($arg)*) +); +(target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::WARN, { $($k).+ $($field)* }) +); +(target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::WARN, { ?$($k).+ $($field)* }) +); +(target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::WARN, { %$($k).+ $($field)* }) +); +(target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::WARN, {}, $($arg)+) +); + +// Name / parent. +(name: $name:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::WARN, { $($field)* }, $($arg)*) +); +(name: $name:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::WARN, { $($k).+ $($field)* }) +); +(name: $name:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::WARN, { ?$($k).+ $($field)* }) +); +(name: $name:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::WARN, { %$($k).+ $($field)* }) +); +(name: $name:expr, parent: $parent:expr, $($arg:tt)+ ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::WARN, {}, $($arg)+) +); + +// Name. +(name: $name:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(name: $name, $crate::Level::WARN, { $($field)* }, $($arg)*) +); +(name: $name:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, $crate::Level::WARN, { $($k).+ $($field)* }) +); +(name: $name:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, $crate::Level::WARN, { ?$($k).+ $($field)* }) +); +(name: $name:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, $crate::Level::WARN, { %$($k).+ $($field)* }) +); +(name: $name:expr, $($arg:tt)+ ) => ( + $crate::event!(name: $name, $crate::Level::WARN, {}, $($arg)+) +); + +// Target. +(target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(target: $target, $crate::Level::WARN, { $($field)* }, $($arg)*) +); +(target: $target:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, $crate::Level::WARN, { $($k).+ $($field)* }) +); +(target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, $crate::Level::WARN, { ?$($k).+ $($field)* }) +); +(target: $target:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, $crate::Level::WARN, { %$($k).+ $($field)* }) +); +(target: $target:expr, $($arg:tt)+ ) => ( + $crate::event!(target: $target, $crate::Level::WARN, {}, $($arg)+) +); + +// Parent. +(parent: $parent:expr, { $($field:tt)+ }, $($arg:tt)+ ) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::WARN, + { $($field)+ }, + $($arg)+ + ) +); +(parent: $parent:expr, $($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::WARN, + { $($k).+ = $($field)*} + ) +); +(parent: $parent:expr, ?$($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::WARN, + { ?$($k).+ = $($field)*} + ) +); +(parent: $parent:expr, %$($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::WARN, + { %$($k).+ = $($field)*} + ) +); +(parent: $parent:expr, $($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::WARN, + { $($k).+, $($field)*} + ) +); +(parent: $parent:expr, ?$($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::WARN, + { ?$($k).+, $($field)*} + ) +); +(parent: $parent:expr, %$($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::WARN, + { %$($k).+, $($field)*} + ) +); +(parent: $parent:expr, $($arg:tt)+) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::WARN, + {}, + $($arg)+ + ) +); + +// ... +({ $($field:tt)+ }, $($arg:tt)+ ) => ( + $crate::event!( + target: module_path!(), + $crate::Level::WARN, + { $($field)+ }, + $($arg)+ + ) +); +($($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::WARN, + { $($k).+ = $($field)*} + ) +); +(?$($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::WARN, + { ?$($k).+ = $($field)*} + ) +); +(%$($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::WARN, + { %$($k).+ = $($field)*} + ) +); +($($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::WARN, + { $($k).+, $($field)*} + ) +); +(?$($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::WARN, + { ?$($k).+, $($field)*} + ) +); +(%$($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::WARN, + { %$($k).+, $($field)*} + ) +); +(?$($k:ident).+) => ( + $crate::event!( + target: module_path!(), + $crate::Level::WARN, + { ?$($k).+ } + ) +); +(%$($k:ident).+) => ( + $crate::event!( + target: module_path!(), + $crate::Level::WARN, + { %$($k).+ } + ) +); +($($k:ident).+) => ( + $crate::event!( + target: module_path!(), + $crate::Level::WARN, + { $($k).+ } + ) +); +($($arg:tt)+) => ( + $crate::event!( + target: module_path!(), + $crate::Level::WARN, + $($arg)+ + ) +); +} + +#[macro_export] +macro_rules! error { +// Name / target / parent. +(name: $name:expr, target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::ERROR, { $($field)* }, $($arg)*) +); +(name: $name:expr, target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::ERROR, { $($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::ERROR, { ?$($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::ERROR, { %$($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::ERROR, {}, $($arg)+) +); + +// Name / target. +(name: $name:expr, target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::ERROR, { $($field)* }, $($arg)*) +); +(name: $name:expr, target: $target:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::ERROR, { $($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::ERROR, { ?$($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::ERROR, { %$($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, $($arg:tt)+ ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::ERROR, {}, $($arg)+) +); + +// Target / parent. +(target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::ERROR, { $($field)* }, $($arg)*) +); +(target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::ERROR, { $($k).+ $($field)* }) +); +(target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::ERROR, { ?$($k).+ $($field)* }) +); +(target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::ERROR, { %$($k).+ $($field)* }) +); +(target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::ERROR, {}, $($arg)+) +); + +// Name / parent. +(name: $name:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::ERROR, { $($field)* }, $($arg)*) +); +(name: $name:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::ERROR, { $($k).+ $($field)* }) +); +(name: $name:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::ERROR, { ?$($k).+ $($field)* }) +); +(name: $name:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::ERROR, { %$($k).+ $($field)* }) +); +(name: $name:expr, parent: $parent:expr, $($arg:tt)+ ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::ERROR, {}, $($arg)+) +); + +// Name. +(name: $name:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(name: $name, $crate::Level::ERROR, { $($field)* }, $($arg)*) +); +(name: $name:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, $crate::Level::ERROR, { $($k).+ $($field)* }) +); +(name: $name:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, $crate::Level::ERROR, { ?$($k).+ $($field)* }) +); +(name: $name:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, $crate::Level::ERROR, { %$($k).+ $($field)* }) +); +(name: $name:expr, $($arg:tt)+ ) => ( + $crate::event!(name: $name, $crate::Level::ERROR, {}, $($arg)+) +); + +// Target. +(target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(target: $target, $crate::Level::ERROR, { $($field)* }, $($arg)*) +); +(target: $target:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, $crate::Level::ERROR, { $($k).+ $($field)* }) +); +(target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, $crate::Level::ERROR, { ?$($k).+ $($field)* }) +); +(target: $target:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, $crate::Level::ERROR, { %$($k).+ $($field)* }) +); +(target: $target:expr, $($arg:tt)+ ) => ( + $crate::event!(target: $target, $crate::Level::ERROR, {}, $($arg)+) +); + +// Parent. +(parent: $parent:expr, { $($field:tt)+ }, $($arg:tt)+ ) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::ERROR, + { $($field)+ }, + $($arg)+ + ) +); +(parent: $parent:expr, $($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::ERROR, + { $($k).+ = $($field)*} + ) +); +(parent: $parent:expr, ?$($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::ERROR, + { ?$($k).+ = $($field)*} + ) +); +(parent: $parent:expr, %$($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::ERROR, + { %$($k).+ = $($field)*} + ) +); +(parent: $parent:expr, $($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::ERROR, + { $($k).+, $($field)*} + ) +); +(parent: $parent:expr, ?$($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::ERROR, + { ?$($k).+, $($field)*} + ) +); +(parent: $parent:expr, %$($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::ERROR, + { %$($k).+, $($field)*} + ) +); +(parent: $parent:expr, $($arg:tt)+) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::ERROR, + {}, + $($arg)+ + ) +); + +// ... +({ $($field:tt)+ }, $($arg:tt)+ ) => ( + $crate::event!( + target: module_path!(), + $crate::Level::ERROR, + { $($field)+ }, + $($arg)+ + ) +); +($($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::ERROR, + { $($k).+ = $($field)*} + ) +); +(?$($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::ERROR, + { ?$($k).+ = $($field)*} + ) +); +(%$($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::ERROR, + { %$($k).+ = $($field)*} + ) +); +($($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::ERROR, + { $($k).+, $($field)*} + ) +); +(?$($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::ERROR, + { ?$($k).+, $($field)*} + ) +); +(%$($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::ERROR, + { %$($k).+, $($field)*} + ) +); +(?$($k:ident).+) => ( + $crate::event!( + target: module_path!(), + $crate::Level::ERROR, + { ?$($k).+ } + ) +); +(%$($k:ident).+) => ( + $crate::event!( + target: module_path!(), + $crate::Level::ERROR, + { %$($k).+ } + ) +); +($($k:ident).+) => ( + $crate::event!( + target: module_path!(), + $crate::Level::ERROR, + { $($k).+ } + ) +); +($($arg:tt)+) => ( + $crate::event!( + target: module_path!(), + $crate::Level::ERROR, + $($arg)+ + ) +); +} + +#[doc(hidden)] +#[macro_export] +macro_rules! callsite { +(name: $name:expr, kind: $kind:expr, fields: $($fields:tt)*) => {{ + $crate::callsite! { + name: $name, + kind: $kind, + target: module_path!(), + level: $crate::Level::TRACE, + fields: $($fields)* + } +}}; +( + name: $name:expr, + kind: $kind:expr, + level: $lvl:expr, + fields: $($fields:tt)* +) => {{ + $crate::callsite! { + name: $name, + kind: $kind, + target: module_path!(), + level: $lvl, + fields: $($fields)* + } +}}; +( + name: $name:expr, + kind: $kind:expr, + target: $target:expr, + level: $lvl:expr, + fields: $($fields:tt)* +) => {{ + static META: $crate::Metadata<'static> = { + $crate::metadata! { + name: $name, + target: $target, + level: $lvl, + fields: $crate::fieldset!( $($fields)* ), + callsite: &__CALLSITE, + kind: $kind, + } + }; + static __CALLSITE: $crate::callsite::DefaultCallsite = $crate::callsite::DefaultCallsite::new(&META); + __CALLSITE.register(); + &__CALLSITE +}}; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! callsite2 { +(name: $name:expr, kind: $kind:expr, fields: $($fields:tt)*) => {{ + $crate::callsite2! { + name: $name, + kind: $kind, + target: module_path!(), + level: $crate::Level::TRACE, + fields: $($fields)* + } +}}; +( + name: $name:expr, + kind: $kind:expr, + level: $lvl:expr, + fields: $($fields:tt)* +) => {{ + $crate::callsite2! { + name: $name, + kind: $kind, + target: module_path!(), + level: $lvl, + fields: $($fields)* + } +}}; +( + name: $name:expr, + kind: $kind:expr, + target: $target:expr, + level: $lvl:expr, + fields: $($fields:tt)* +) => {{ + static META: $crate::Metadata<'static> = { + $crate::metadata! { + name: $name, + target: $target, + level: $lvl, + fields: $crate::fieldset!( $($fields)* ), + callsite: &__CALLSITE, + kind: $kind, + } + }; + $crate::callsite::DefaultCallsite::new(&META) +}}; +} + +#[macro_export] +#[doc(hidden)] +macro_rules! level_enabled { +($lvl:expr) => { + $lvl <= $crate::level_filters::STATIC_MAX_LEVEL + && $lvl <= $crate::level_filters::LevelFilter::current() +}; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! valueset { + +// === base case === +(@ { $(,)* $($val:expr),* $(,)* }, $next:expr $(,)*) => { + &[ $($val),* ] +}; + +(@ { $(,)* $($out:expr),* }, $next:expr, $($k:ident).+ = ?$val:expr, $($rest:tt)*) => { + $crate::valueset!( + @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&debug(&$val) as &dyn Value)) }, + $next, + $($rest)* + ) +}; +(@ { $(,)* $($out:expr),* }, $next:expr, $($k:ident).+ = %$val:expr, $($rest:tt)*) => { + $crate::valueset!( + @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&display(&$val) as &dyn Value)) }, + $next, + $($rest)* + ) +}; +(@ { $(,)* $($out:expr),* }, $next:expr, $($k:ident).+ = $val:expr, $($rest:tt)*) => { + $crate::valueset!( + @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&$val as &dyn Value)) }, + $next, + $($rest)* + ) +}; +(@ { $(,)* $($out:expr),* }, $next:expr, $($k:ident).+, $($rest:tt)*) => { + $crate::valueset!( + @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&$($k).+ as &dyn Value)) }, + $next, + $($rest)* + ) +}; +(@ { $(,)* $($out:expr),* }, $next:expr, ?$($k:ident).+, $($rest:tt)*) => { + $crate::valueset!( + @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&debug(&$($k).+) as &dyn Value)) }, + $next, + $($rest)* + ) +}; +(@ { $(,)* $($out:expr),* }, $next:expr, %$($k:ident).+, $($rest:tt)*) => { + $crate::valueset!( + @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&display(&$($k).+) as &dyn Value)) }, + $next, + $($rest)* + ) +}; +(@ { $(,)* $($out:expr),* }, $next:expr, $($k:ident).+ = ?$val:expr) => { + $crate::valueset!( + @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&debug(&$val) as &dyn Value)) }, + $next, + ) +}; +(@ { $(,)* $($out:expr),* }, $next:expr, $($k:ident).+ = %$val:expr) => { + $crate::valueset!( + @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&display(&$val) as &dyn Value)) }, + $next, + ) +}; +(@ { $(,)* $($out:expr),* }, $next:expr, $($k:ident).+ = $val:expr) => { + $crate::valueset!( + @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&$val as &dyn Value)) }, + $next, + ) +}; +(@ { $(,)* $($out:expr),* }, $next:expr, $($k:ident).+) => { + $crate::valueset!( + @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&$($k).+ as &dyn Value)) }, + $next, + ) +}; +(@ { $(,)* $($out:expr),* }, $next:expr, ?$($k:ident).+) => { + $crate::valueset!( + @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&debug(&$($k).+) as &dyn Value)) }, + $next, + ) +}; +(@ { $(,)* $($out:expr),* }, $next:expr, %$($k:ident).+) => { + $crate::valueset!( + @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&display(&$($k).+) as &dyn Value)) }, + $next, + ) +}; + +// Handle literal names +(@ { $(,)* $($out:expr),* }, $next:expr, $k:literal = ?$val:expr, $($rest:tt)*) => { + $crate::valueset!( + @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&debug(&$val) as &dyn Value)) }, + $next, + $($rest)* + ) +}; +(@ { $(,)* $($out:expr),* }, $next:expr, $k:literal = %$val:expr, $($rest:tt)*) => { + $crate::valueset!( + @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&display(&$val) as &dyn Value)) }, + $next, + $($rest)* + ) +}; +(@ { $(,)* $($out:expr),* }, $next:expr, $k:literal = $val:expr, $($rest:tt)*) => { + $crate::valueset!( + @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&$val as &dyn Value)) }, + $next, + $($rest)* + ) +}; +(@ { $(,)* $($out:expr),* }, $next:expr, $k:literal = ?$val:expr) => { + $crate::valueset!( + @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&debug(&$val) as &dyn Value)) }, + $next, + ) +}; +(@ { $(,)* $($out:expr),* }, $next:expr, $k:literal = %$val:expr) => { + $crate::valueset!( + @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&display(&$val) as &dyn Value)) }, + $next, + ) +}; +(@ { $(,)* $($out:expr),* }, $next:expr, $k:literal = $val:expr) => { + $crate::valueset!( + @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&$val as &dyn Value)) }, + $next, + ) +}; + +// Handle constant names +(@ { $(,)* $($out:expr),* }, $next:expr, { $k:expr } = ?$val:expr, $($rest:tt)*) => { + $crate::valueset!( + @ { $($out),*, (&$next, Some(&debug(&$val) as &dyn Value)) }, + $next, + $($rest)* + ) +}; +(@ { $(,)* $($out:expr),* }, $next:expr, { $k:expr } = %$val:expr, $($rest:tt)*) => { + $crate::valueset!( + @ { $($out),*, (&$next, Some(&display(&$val) as &dyn Value)) }, + $next, + $($rest)* + ) +}; +(@ { $(,)* $($out:expr),* }, $next:expr, { $k:expr } = $val:expr, $($rest:tt)*) => { + $crate::valueset!( + @ { $($out),*, (&$next, Some(&$val as &dyn Value)) }, + $next, + $($rest)* + ) +}; +(@ { $(,)* $($out:expr),* }, $next:expr, { $k:expr } = ?$val:expr) => { + $crate::valueset!( + @ { $($out),*, (&$next, Some(&debug(&$val) as &dyn Value)) }, + $next, + ) +}; +(@ { $(,)* $($out:expr),* }, $next:expr, { $k:expr } = %$val:expr) => { + $crate::valueset!( + @ { $($out),*, (&$next, Some(&display(&$val) as &dyn Value)) }, + $next, + ) +}; +(@ { $(,)* $($out:expr),* }, $next:expr, { $k:expr } = $val:expr) => { + $crate::valueset!( + @ { $($out),*, (&$next, Some(&$val as &dyn Value)) }, + $next, + ) +}; + +(@ { $(,)* $($out:expr),* }, $next:expr, $($rest:tt)+) => { + $crate::valueset!(@ { (&$next, $crate::__macro_support::Option::Some(&$crate::__macro_support::format_args!($($rest)+) as &dyn Value)), $($out),* }, $next, ) +}; + +($fields:expr, $($kvs:tt)+) => { + { + #[allow(unused_imports)] + use $crate::field::{debug, display, Value}; + let mut iter = $fields.iter(); + $fields.value_set($crate::valueset!( + @ { }, + $crate::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"), + $($kvs)+ + )) + } +}; +($fields:expr,) => { + { + $fields.value_set(&[]) + } +}; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! fieldset { +(@ { $(,)* $($out:expr),* $(,)* } $(,)*) => { + &[ $($out),* ] +}; + +(@ { $(,)* $($out:expr),* } $($k:ident).+ = ?$val:expr, $($rest:tt)*) => { + $crate::fieldset!(@ { $($out),*, $crate::__tracing_stringify!($($k).+) } $($rest)*) +}; +(@ { $(,)* $($out:expr),* } $($k:ident).+ = %$val:expr, $($rest:tt)*) => { + $crate::fieldset!(@ { $($out),*, $crate::__tracing_stringify!($($k).+) } $($rest)*) +}; +(@ { $(,)* $($out:expr),* } $($k:ident).+ = $val:expr, $($rest:tt)*) => { + $crate::fieldset!(@ { $($out),*, $crate::__tracing_stringify!($($k).+) } $($rest)*) +}; +(@ { $(,)* $($out:expr),* } ?$($k:ident).+, $($rest:tt)*) => { + $crate::fieldset!(@ { $($out),*, $crate::__tracing_stringify!($($k).+) } $($rest)*) +}; +(@ { $(,)* $($out:expr),* } %$($k:ident).+, $($rest:tt)*) => { + $crate::fieldset!(@ { $($out),*, $crate::__tracing_stringify!($($k).+) } $($rest)*) +}; +(@ { $(,)* $($out:expr),* } $($k:ident).+, $($rest:tt)*) => { + $crate::fieldset!(@ { $($out),*, $crate::__tracing_stringify!($($k).+) } $($rest)*) +}; + +// Handle literal names +(@ { $(,)* $($out:expr),* } $k:literal = ?$val:expr, $($rest:tt)*) => { + $crate::fieldset!(@ { $($out),*, $k } $($rest)*) +}; +(@ { $(,)* $($out:expr),* } $k:literal = %$val:expr, $($rest:tt)*) => { + $crate::fieldset!(@ { $($out),*, $k } $($rest)*) +}; +(@ { $(,)* $($out:expr),* } $k:literal = $val:expr, $($rest:tt)*) => { + $crate::fieldset!(@ { $($out),*, $k } $($rest)*) +}; + +// Handle constant names +(@ { $(,)* $($out:expr),* } { $k:expr } = ?$val:expr, $($rest:tt)*) => { + $crate::fieldset!(@ { $($out),*, $k } $($rest)*) +}; +(@ { $(,)* $($out:expr),* } { $k:expr } = %$val:expr, $($rest:tt)*) => { + $crate::fieldset!(@ { $($out),*, $k } $($rest)*) +}; +(@ { $(,)* $($out:expr),* } { $k:expr } = $val:expr, $($rest:tt)*) => { + $crate::fieldset!(@ { $($out),*, $k } $($rest)*) +}; + +(@ { $(,)* $($out:expr),* } $($rest:tt)+) => { + $crate::fieldset!(@ { "message", $($out),*, }) +}; + +($($args:tt)*) => { + $crate::fieldset!(@ { } $($args)*,) +}; + +} + +#[cfg(feature = "log")] +#[doc(hidden)] +#[macro_export] +macro_rules! level_to_log { +($level:expr) => { + match $level { + $crate::Level::ERROR => $crate::log::Level::Error, + $crate::Level::WARN => $crate::log::Level::Warn, + $crate::Level::INFO => $crate::log::Level::Info, + $crate::Level::DEBUG => $crate::log::Level::Debug, + _ => $crate::log::Level::Trace, + } +}; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! __tracing_stringify { +($($t:tt)*) => { + stringify!($($t)*) +}; +} + +#[cfg(not(feature = "log"))] +#[doc(hidden)] +#[macro_export] +macro_rules! __tracing_log { +($level:expr, $callsite:expr, $value_set:expr) => {}; +} + +#[cfg(feature = "log")] +#[doc(hidden)] +#[macro_export] +macro_rules! __tracing_log { +($level:expr, $callsite:expr, $value_set:expr) => { + $crate::if_log_enabled! { $level, { + use $crate::log; + let level = $crate::level_to_log!($level); + if level <= log::max_level() { + let meta = $callsite.metadata(); + let log_meta = log::Metadata::builder() + .level(level) + .target(meta.target()) + .build(); + let logger = log::logger(); + if logger.enabled(&log_meta) { + $crate::__macro_support::__tracing_log(meta, logger, log_meta, $value_set) + } + } + }} +}; +} + +#[cfg(not(feature = "log"))] +#[doc(hidden)] +#[macro_export] +macro_rules! if_log_enabled { +($lvl:expr, $e:expr;) => { + $crate::if_log_enabled! { $lvl, $e } +}; +($lvl:expr, $if_log:block) => { + $crate::if_log_enabled! { $lvl, $if_log else {} } +}; +($lvl:expr, $if_log:block else $else_block:block) => { + $else_block +}; +} + +#[cfg(all(feature = "log", not(feature = "log-always")))] +#[doc(hidden)] +#[macro_export] +macro_rules! if_log_enabled { +($lvl:expr, $e:expr;) => { + $crate::if_log_enabled! { $lvl, $e } +}; +($lvl:expr, $if_log:block) => { + $crate::if_log_enabled! { $lvl, $if_log else {} } +}; +($lvl:expr, $if_log:block else $else_block:block) => { + if $crate::level_to_log!($lvl) <= $crate::log::STATIC_MAX_LEVEL { + if !$crate::dispatcher::has_been_set() { + $if_log + } else { + $else_block + } + } else { + $else_block + } +}; +} + +#[cfg(all(feature = "log", feature = "log-always"))] +#[doc(hidden)] +#[macro_export] +macro_rules! if_log_enabled { +($lvl:expr, $e:expr;) => { + $crate::if_log_enabled! { $lvl, $e } +}; +($lvl:expr, $if_log:block) => { + $crate::if_log_enabled! { $lvl, $if_log else {} } +}; +($lvl:expr, $if_log:block else $else_block:block) => { + if $crate::level_to_log!($lvl) <= $crate::log::STATIC_MAX_LEVEL { + #[allow(unused_braces)] + $if_log + } else { + $else_block + } +}; +} + +//- /lib.rs crate:ra_test_fixture deps:tracing +fn foo() { +tracing::error!(); +} + "#, + &["E0432", "inactive-code", "unresolved-macro-call", "syntax-error", "macro-error"], + ); +} diff --git a/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs b/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs index 9255c5a6899b2..acab989437af7 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs @@ -38,7 +38,10 @@ impl<'t> Bindings<'t> { nesting_state.hit = true; b = match b { Binding::Fragment(_) => break, - Binding::Missing(_) => break, + Binding::Missing(_) => { + nesting_state.at_end = true; + break; + } Binding::Nested(bs) => bs.get(nesting_state.idx).ok_or_else(|| { nesting_state.at_end = true; binding_err!("could not find nested binding `{name}`") From cc07c98314b85cc4511bf42d68e7ba405f16e287 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Wed, 8 Jan 2025 10:19:46 +0200 Subject: [PATCH 015/115] Fix test-fixture autopublishing --- src/tools/rust-analyzer/Cargo.toml | 4 ++-- src/tools/rust-analyzer/crates/test-fixture/Cargo.toml | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index 9440123de70dc..629bd74467628 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -79,6 +79,7 @@ span = { path = "./crates/span", version = "0.0.0" } stdx = { path = "./crates/stdx", version = "0.0.0" } syntax = { path = "./crates/syntax", version = "0.0.0" } syntax-bridge = { path = "./crates/syntax-bridge", version = "0.0.0" } +test-fixture = { path = "./crates/test-fixture", version = "0.0.0" } test-utils = { path = "./crates/test-utils", version = "0.0.0" } toolchain = { path = "./crates/toolchain", version = "0.0.0" } tt = { path = "./crates/tt", version = "0.0.0" } @@ -93,9 +94,8 @@ ra-ap-rustc_abi = { version = "0.87", default-features = false } ra-ap-rustc_pattern_analysis = { version = "0.87", default-features = false } # local crates that aren't published to crates.io. These should not have versions. -test-fixture = { path = "./crates/test-fixture" } -# In-tree crates that are published separately and follow semver. See lib/README.md +# in-tree crates that are published separately and follow semver. See lib/README.md line-index = { version = "0.1.2" } la-arena = { version = "0.3.1" } lsp-server = { version = "0.7.6" } diff --git a/src/tools/rust-analyzer/crates/test-fixture/Cargo.toml b/src/tools/rust-analyzer/crates/test-fixture/Cargo.toml index c860e7b1183d5..95f4cb9d67e25 100644 --- a/src/tools/rust-analyzer/crates/test-fixture/Cargo.toml +++ b/src/tools/rust-analyzer/crates/test-fixture/Cargo.toml @@ -2,6 +2,8 @@ name = "test-fixture" version = "0.0.0" rust-version.workspace = true +description = "Test fixtures for rust-analyzer." + edition.workspace = true license.workspace = true authors.workspace = true From bc1a7fa83457009b9949a844179512f38ccec0a1 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 8 Jan 2025 10:59:58 +0100 Subject: [PATCH 016/115] fix: Fix `env`/`option_env` macro check disregarding macro_rules definitions --- src/tools/rust-analyzer/crates/hir/src/lib.rs | 17 ++++-- .../src/completions/env_vars.rs | 57 +++++++++---------- 2 files changed, 40 insertions(+), 34 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 00b4db5437401..b7c3e6bb415bc 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -3046,14 +3046,23 @@ impl Macro { MacroId::Macro2Id(it) => { matches!(it.lookup(db.upcast()).expander, MacroExpander::BuiltInEager(eager) if eager.is_env_or_option_env()) } - MacroId::MacroRulesId(_) | MacroId::ProcMacroId(_) => false, + MacroId::MacroRulesId(it) => { + matches!(it.lookup(db.upcast()).expander, MacroExpander::BuiltInEager(eager) if eager.is_env_or_option_env()) + } + MacroId::ProcMacroId(_) => false, } } pub fn is_asm_or_global_asm(&self, db: &dyn HirDatabase) -> bool { - matches!(self.id, MacroId::Macro2Id(it) if { - matches!(it.lookup(db.upcast()).expander, MacroExpander::BuiltIn(m) if m.is_asm()) - }) + match self.id { + MacroId::Macro2Id(it) => { + matches!(it.lookup(db.upcast()).expander, MacroExpander::BuiltIn(m) if m.is_asm()) + } + MacroId::MacroRulesId(it) => { + matches!(it.lookup(db.upcast()).expander, MacroExpander::BuiltIn(m) if m.is_asm()) + } + MacroId::ProcMacroId(_) => false, + } } pub fn is_attr(&self, db: &dyn HirDatabase) -> bool { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs index 0b6790d42a610..40af5203e9c32 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs @@ -68,43 +68,40 @@ pub(crate) fn complete_cargo_env_vars( mod tests { use crate::tests::{check_edit, completion_list}; - fn check(macro_name: &str) { + #[test] + fn completes_env_variable_in_env() { check_edit( "CARGO_BIN_NAME", - &format!( - r#" - #[rustc_builtin_macro] - macro {macro_name} {{ - ($var:literal) => {{ 0 }} - }} - - fn main() {{ - let foo = {macro_name}!("CAR$0"); - }} - "# - ), - &format!( - r#" - #[rustc_builtin_macro] - macro {macro_name} {{ - ($var:literal) => {{ 0 }} - }} - - fn main() {{ - let foo = {macro_name}!("CARGO_BIN_NAME"); - }} - "# - ), + r#" +//- minicore: env +fn main() { + let foo = env!("CAR$0"); +} + "#, + r#" +fn main() { + let foo = env!("CARGO_BIN_NAME"); +} + "#, ); } - #[test] - fn completes_env_variable_in_env() { - check("env") - } #[test] fn completes_env_variable_in_option_env() { - check("option_env"); + check_edit( + "CARGO_BIN_NAME", + r#" +//- minicore: env +fn main() { + let foo = option_env!("CAR$0"); +} + "#, + r#" +fn main() { + let foo = option_env!("CARGO_BIN_NAME"); +} + "#, + ); } #[test] From 2be4ce099d4af070ba71481a048f175b2da9c1c0 Mon Sep 17 00:00:00 2001 From: qjerome Date: Wed, 8 Jan 2025 11:20:08 +0100 Subject: [PATCH 017/115] refactor: struct holding cargo cfgs settings --- .../crates/rust-analyzer/src/config.rs | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index 30f0031905f19..1fe8d0ce4209b 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -571,12 +571,10 @@ config_data! { /// avoid checking unnecessary things. cargo_buildScripts_useRustcWrapper: bool = true, /// List of cfg options to enable with the given values. - cargo_cfgs: FxHashMap> = { - let mut m = FxHashMap::default(); - m.insert("debug_assertions".to_owned(), None); - m.insert("miri".to_owned(), None); - m - }, + cargo_cfgs: Vec = { + vec!["debug_assertion".into(), "miri".into()] + } + , /// Extra arguments that are passed to every cargo invocation. cargo_extraArgs: Vec = vec![], /// Extra environment variables that will be set when running cargo, rustc @@ -1944,6 +1942,17 @@ impl Config { global: CfgDiff::new( self.cargo_cfgs(source_root) .iter() + // parse any cfg setting formatted as key=value + .map(|s| { + let mut sp = s.splitn(2, "="); + let key = sp.next(); + let val = sp.next(); + (key, val) + }) + // we filter out anything with a None key + .filter(|(key, _)| key.is_some()) + // unwrap cannot panic here as we are sure key is Some + .map(|(key, val)| (key.unwrap(), val)) .map(|(key, val)| match val { Some(val) => CfgAtom::KeyValue { key: Symbol::intern(key), From c59ecb3af45898ad2385be9fc945467af02a45b5 Mon Sep 17 00:00:00 2001 From: qjerome Date: Wed, 8 Jan 2025 14:47:21 +0100 Subject: [PATCH 018/115] fix: autogenerate files --- .../rust-analyzer/docs/user/generated_config.adoc | 8 ++++---- src/tools/rust-analyzer/editors/code/package.json | 13 ++++++++----- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/tools/rust-analyzer/docs/user/generated_config.adoc b/src/tools/rust-analyzer/docs/user/generated_config.adoc index 5b86766aa8eac..c6f5852f87ff6 100644 --- a/src/tools/rust-analyzer/docs/user/generated_config.adoc +++ b/src/tools/rust-analyzer/docs/user/generated_config.adoc @@ -94,10 +94,10 @@ avoid checking unnecessary things. -- Default: ---- -{ - "miri": null, - "debug_assertions": null -} +[ + "debug_assertion", + "miri" +] ---- List of cfg options to enable with the given values. diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index 80246bf3feac9..6cb74a94a00c7 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -791,11 +791,14 @@ "properties": { "rust-analyzer.cargo.cfgs": { "markdownDescription": "List of cfg options to enable with the given values.", - "default": { - "miri": null, - "debug_assertions": null - }, - "type": "object" + "default": [ + "debug_assertion", + "miri" + ], + "type": "array", + "items": { + "type": "string" + } } } }, From 93d08b7c7741d4a7233c344caa760d74f8a9c583 Mon Sep 17 00:00:00 2001 From: qjerome Date: Wed, 8 Jan 2025 14:47:46 +0100 Subject: [PATCH 019/115] =?UTF-8?q?fix:=C2=A0requested=20changed?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../crates/rust-analyzer/src/config.rs | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index 1fe8d0ce4209b..051871020af71 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -573,8 +573,7 @@ config_data! { /// List of cfg options to enable with the given values. cargo_cfgs: Vec = { vec!["debug_assertion".into(), "miri".into()] - } - , + }, /// Extra arguments that are passed to every cargo invocation. cargo_extraArgs: Vec = vec![], /// Extra environment variables that will be set when running cargo, rustc @@ -1942,17 +1941,13 @@ impl Config { global: CfgDiff::new( self.cargo_cfgs(source_root) .iter() - // parse any cfg setting formatted as key=value - .map(|s| { + // parse any cfg setting formatted as key=value or just key (without value) + .filter_map(|s| { let mut sp = s.splitn(2, "="); let key = sp.next(); let val = sp.next(); - (key, val) + key.map(|key| (key, val)) }) - // we filter out anything with a None key - .filter(|(key, _)| key.is_some()) - // unwrap cannot panic here as we are sure key is Some - .map(|(key, val)| (key.unwrap(), val)) .map(|(key, val)| match val { Some(val) => CfgAtom::KeyValue { key: Symbol::intern(key), From 8d1ae292945920fac74dded469899f291ead8347 Mon Sep 17 00:00:00 2001 From: Vishruth-Thimmaiah Date: Wed, 8 Jan 2025 22:53:09 +0530 Subject: [PATCH 020/115] refactor test helpers within ide-completions --- .../ide-completion/src/completions/dot.rs | 108 ++++++++---------- .../src/completions/extern_abi.rs | 15 +-- .../src/completions/format_string.rs | 13 +-- .../src/completions/item_list/trait_impl.rs | 41 +++---- .../ide-completion/src/completions/keyword.rs | 9 +- .../src/completions/lifetime.rs | 9 +- .../ide-completion/src/completions/mod_.rs | 9 +- .../ide-completion/src/completions/postfix.rs | 9 +- .../crates/ide-completion/src/tests.rs | 25 +++- .../ide-completion/src/tests/attribute.rs | 51 +++------ .../ide-completion/src/tests/expression.rs | 87 +++++++------- .../ide-completion/src/tests/fn_param.rs | 16 +-- .../crates/ide-completion/src/tests/item.rs | 41 +++---- .../ide-completion/src/tests/item_list.rs | 53 ++++----- .../ide-completion/src/tests/pattern.rs | 93 +++++++-------- .../ide-completion/src/tests/predicate.rs | 25 ++-- .../ide-completion/src/tests/proc_macros.rs | 9 +- .../crates/ide-completion/src/tests/record.rs | 9 +- .../ide-completion/src/tests/special.rs | 24 +--- .../ide-completion/src/tests/type_pos.rs | 99 ++++++++-------- .../ide-completion/src/tests/use_tree.rs | 9 +- .../ide-completion/src/tests/visibility.rs | 16 +-- 22 files changed, 322 insertions(+), 448 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs index 26074672ba9ce..8d44dbab60610 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs @@ -214,25 +214,13 @@ fn complete_methods( #[cfg(test)] mod tests { - use expect_test::{expect, Expect}; + use expect_test::expect; - use crate::tests::{ - check_edit, completion_list_no_kw, completion_list_no_kw_with_private_editable, - }; - - fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list_no_kw(ra_fixture); - expect.assert_eq(&actual); - } - - fn check_with_private_editable(ra_fixture: &str, expect: Expect) { - let actual = completion_list_no_kw_with_private_editable(ra_fixture); - expect.assert_eq(&actual); - } + use crate::tests::{check_edit, check_no_kw, check_with_private_editable}; #[test] fn test_struct_field_and_method_completion() { - check( + check_no_kw( r#" struct S { foo: u32 } impl S { @@ -249,7 +237,7 @@ fn foo(s: S) { s.$0 } #[test] fn no_unstable_method_on_stable() { - check( + check_no_kw( r#" //- /main.rs crate:main deps:std fn foo(s: std::S) { s.$0 } @@ -266,7 +254,7 @@ impl S { #[test] fn unstable_method_on_nightly() { - check( + check_no_kw( r#" //- toolchain:nightly //- /main.rs crate:main deps:std @@ -286,7 +274,7 @@ impl S { #[test] fn test_struct_field_completion_self() { - check( + check_no_kw( r#" struct S { the_field: (u32,) } impl S { @@ -302,7 +290,7 @@ impl S { #[test] fn test_struct_field_completion_autoderef() { - check( + check_no_kw( r#" struct A { the_field: (u32, i32) } impl A { @@ -318,7 +306,7 @@ impl A { #[test] fn test_no_struct_field_completion_for_method_call() { - check( + check_no_kw( r#" struct A { the_field: u32 } fn foo(a: A) { a.$0() } @@ -329,7 +317,7 @@ fn foo(a: A) { a.$0() } #[test] fn test_visibility_filtering() { - check( + check_no_kw( r#" //- /lib.rs crate:lib new_source_root:local pub mod m { @@ -348,7 +336,7 @@ fn foo(a: lib::m::A) { a.$0 } "#]], ); - check( + check_no_kw( r#" //- /lib.rs crate:lib new_source_root:library pub mod m { @@ -367,7 +355,7 @@ fn foo(a: lib::m::A) { a.$0 } "#]], ); - check( + check_no_kw( r#" //- /lib.rs crate:lib new_source_root:library pub mod m { @@ -384,7 +372,7 @@ fn foo(a: lib::m::A) { a.$0 } "#]], ); - check( + check_no_kw( r#" //- /lib.rs crate:lib new_source_root:local pub struct A {} @@ -402,7 +390,7 @@ fn foo(a: lib::A) { a.$0 } me pub_method() fn(&self) "#]], ); - check( + check_no_kw( r#" //- /lib.rs crate:lib new_source_root:library pub struct A {} @@ -524,7 +512,7 @@ fn foo(a: lib::A) { a.$0 } #[test] fn test_local_impls() { - check( + check_no_kw( r#" pub struct A {} mod m { @@ -553,7 +541,7 @@ fn foo(a: A) { #[test] fn test_doc_hidden_filtering() { - check( + check_no_kw( r#" //- /lib.rs crate:lib deps:dep fn foo(a: dep::A) { a.$0 } @@ -580,7 +568,7 @@ impl A { #[test] fn test_union_field_completion() { - check( + check_no_kw( r#" union U { field: u8, other: u16 } fn foo(u: U) { u.$0 } @@ -594,7 +582,7 @@ fn foo(u: U) { u.$0 } #[test] fn test_method_completion_only_fitting_impls() { - check( + check_no_kw( r#" struct A {} impl A { @@ -613,7 +601,7 @@ fn foo(a: A) { a.$0 } #[test] fn test_trait_method_completion() { - check( + check_no_kw( r#" struct A {} trait Trait { fn the_method(&self); } @@ -643,7 +631,7 @@ fn foo(a: A) { a.the_method();$0 } #[test] fn test_trait_method_completion_deduplicated() { - check( + check_no_kw( r" struct A {} trait Trait { fn the_method(&self); } @@ -658,7 +646,7 @@ fn foo(a: &A) { a.$0 } #[test] fn completes_trait_method_from_other_module() { - check( + check_no_kw( r" struct A {} mod m { @@ -676,7 +664,7 @@ fn foo(a: A) { a.$0 } #[test] fn test_no_non_self_method() { - check( + check_no_kw( r#" struct A {} impl A { @@ -692,7 +680,7 @@ fn foo(a: A) { #[test] fn test_tuple_field_completion() { - check( + check_no_kw( r#" fn foo() { let b = (0, 3.14); @@ -708,7 +696,7 @@ fn foo() { #[test] fn test_tuple_struct_field_completion() { - check( + check_no_kw( r#" struct S(i32, f64); fn foo() { @@ -725,7 +713,7 @@ fn foo() { #[test] fn test_tuple_field_inference() { - check( + check_no_kw( r#" pub struct S; impl S { pub fn blah(&self) {} } @@ -747,7 +735,7 @@ impl T { #[test] fn test_field_no_same_name() { - check( + check_no_kw( r#" //- minicore: deref struct A { field: u8 } @@ -770,7 +758,7 @@ fn test(a: A) { #[test] fn test_tuple_field_no_same_index() { - check( + check_no_kw( r#" //- minicore: deref struct A(u8); @@ -793,7 +781,7 @@ fn test(a: A) { #[test] fn test_tuple_struct_deref_to_tuple_no_same_index() { - check( + check_no_kw( r#" //- minicore: deref struct A(u8); @@ -815,7 +803,7 @@ fn test(a: A) { #[test] fn test_completion_works_in_consts() { - check( + check_no_kw( r#" struct A { the_field: u32 } const X: u32 = { @@ -830,7 +818,7 @@ const X: u32 = { #[test] fn works_in_simple_macro_1() { - check( + check_no_kw( r#" macro_rules! m { ($e:expr) => { $e } } struct A { the_field: u32 } @@ -847,7 +835,7 @@ fn foo(a: A) { #[test] fn works_in_simple_macro_2() { // this doesn't work yet because the macro doesn't expand without the token -- maybe it can be fixed with better recovery - check( + check_no_kw( r#" macro_rules! m { ($e:expr) => { $e } } struct A { the_field: u32 } @@ -863,7 +851,7 @@ fn foo(a: A) { #[test] fn works_in_simple_macro_recursive_1() { - check( + check_no_kw( r#" macro_rules! m { ($e:expr) => { $e } } struct A { the_field: u32 } @@ -879,7 +867,7 @@ fn foo(a: A) { #[test] fn macro_expansion_resilient() { - check( + check_no_kw( r#" macro_rules! d { () => {}; @@ -905,7 +893,7 @@ fn foo(a: A) { #[test] fn test_method_completion_issue_3547() { - check( + check_no_kw( r#" struct HashSet {} impl HashSet { @@ -924,7 +912,7 @@ fn foo() { #[test] fn completes_method_call_when_receiver_is_a_macro_call() { - check( + check_no_kw( r#" struct S; impl S { fn foo(&self) {} } @@ -939,7 +927,7 @@ fn main() { make_s!().f$0; } #[test] fn completes_after_macro_call_in_submodule() { - check( + check_no_kw( r#" macro_rules! empty { () => {}; @@ -967,7 +955,7 @@ mod foo { #[test] fn issue_8931() { - check( + check_no_kw( r#" //- minicore: fn struct S; @@ -994,7 +982,7 @@ impl S { #[test] fn completes_bare_fields_and_methods_in_methods() { - check( + check_no_kw( r#" struct Foo { field: i32 } @@ -1008,7 +996,7 @@ impl Foo { fn foo(&self) { $0 } }"#, bt u32 u32 "#]], ); - check( + check_no_kw( r#" struct Foo(i32); @@ -1026,7 +1014,7 @@ impl Foo { fn foo(&mut self) { $0 } }"#, #[test] fn macro_completion_after_dot() { - check( + check_no_kw( r#" macro_rules! m { ($e:expr) => { $e }; @@ -1051,7 +1039,7 @@ fn f() { #[test] fn completes_method_call_when_receiver_type_has_errors_issue_10297() { - check( + check_no_kw( r#" //- minicore: iterator, sized struct Vec; @@ -1102,7 +1090,7 @@ fn main() { #[test] fn issue_12484() { - check( + check_no_kw( r#" //- minicore: sized trait SizeUser { @@ -1124,7 +1112,7 @@ fn test(thing: impl Encrypt) { #[test] fn only_consider_same_type_once() { - check( + check_no_kw( r#" //- minicore: deref struct A(u8); @@ -1150,7 +1138,7 @@ fn test(a: A) { #[test] fn no_inference_var_in_completion() { - check( + check_no_kw( r#" struct S(T); fn test(s: S) { @@ -1165,7 +1153,7 @@ fn test(s: S) { #[test] fn assoc_impl_1() { - check( + check_no_kw( r#" //- minicore: deref fn main() { @@ -1206,7 +1194,7 @@ impl> Foo { #[test] fn assoc_impl_2() { - check( + check_no_kw( r#" //- minicore: deref fn main() { @@ -1242,7 +1230,7 @@ impl> Foo { #[test] fn test_struct_function_field_completion() { - check( + check_no_kw( r#" struct S { va_field: u32, fn_field: fn() } fn foo() { S { va_field: 0, fn_field: || {} }.fi$0() } @@ -1267,7 +1255,7 @@ fn foo() { (S { va_field: 0, fn_field: || {} }.fn_field)() } #[test] fn test_tuple_function_field_completion() { - check( + check_no_kw( r#" struct B(u32, fn()) fn foo() { @@ -1301,7 +1289,7 @@ fn foo() { #[test] fn test_fn_field_dot_access_method_has_parens_false() { - check( + check_no_kw( r#" struct Foo { baz: fn() } impl Foo { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs index bcfda928c4da5..7c2cc2a6c1d8f 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs @@ -65,18 +65,13 @@ pub(crate) fn complete_extern_abi( #[cfg(test)] mod tests { - use expect_test::{expect, Expect}; + use expect_test::expect; - use crate::tests::{check_edit, completion_list_no_kw}; - - fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list_no_kw(ra_fixture); - expect.assert_eq(&actual); - } + use crate::tests::{check_edit, check_no_kw}; #[test] fn only_completes_in_string_literals() { - check( + check_no_kw( r#" $0 fn foo {} "#, @@ -86,7 +81,7 @@ $0 fn foo {} #[test] fn requires_extern_prefix() { - check( + check_no_kw( r#" "$0" fn foo {} "#, @@ -96,7 +91,7 @@ $0 fn foo {} #[test] fn works() { - check( + check_no_kw( r#" extern "$0" fn foo {} "#, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/format_string.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/format_string.rs index a87c60c694ac7..dcd40c3412c70 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/format_string.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/format_string.rs @@ -61,18 +61,13 @@ pub(crate) fn format_string( #[cfg(test)] mod tests { - use expect_test::{expect, Expect}; + use expect_test::expect; - use crate::tests::{check_edit, completion_list_no_kw}; - - fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list_no_kw(ra_fixture); - expect.assert_eq(&actual); - } + use crate::tests::{check_edit, check_no_kw}; #[test] fn works_when_wrapped() { - check( + check_no_kw( r#" //- minicore: fmt macro_rules! print { @@ -89,7 +84,7 @@ fn main() { #[test] fn no_completion_without_brace() { - check( + check_no_kw( r#" //- minicore: fmt fn main() { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs index 80d72b460f958..6d1945c45341d 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs @@ -514,18 +514,13 @@ fn function_declaration( #[cfg(test)] mod tests { - use expect_test::{expect, Expect}; + use expect_test::expect; - use crate::tests::{check_edit, completion_list_no_kw}; - - fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list_no_kw(ra_fixture); - expect.assert_eq(&actual) - } + use crate::tests::{check_edit, check_no_kw}; #[test] fn no_completion_inside_fn() { - check( + check_no_kw( r" trait Test { fn test(); fn test2(); } struct T; @@ -544,7 +539,7 @@ impl Test for T { "#]], ); - check( + check_no_kw( r" trait Test { fn test(); fn test2(); } struct T; @@ -558,7 +553,7 @@ impl Test for T { expect![[""]], ); - check( + check_no_kw( r" trait Test { fn test(); fn test2(); } struct T; @@ -573,7 +568,7 @@ impl Test for T { ); // /~https://github.com/rust-lang/rust-analyzer/pull/5976#issuecomment-692332191 - check( + check_no_kw( r" trait Test { fn test(); fn test2(); } struct T; @@ -587,7 +582,7 @@ impl Test for T { expect![[r#""#]], ); - check( + check_no_kw( r" trait Test { fn test(_: i32); fn test2(); } struct T; @@ -606,7 +601,7 @@ impl Test for T { "#]], ); - check( + check_no_kw( r" trait Test { fn test(_: fn()); fn test2(); } struct T; @@ -624,7 +619,7 @@ impl Test for T { #[test] fn no_completion_inside_const() { - check( + check_no_kw( r" trait Test { const TEST: fn(); const TEST2: u32; type Test; fn test(); } struct T; @@ -636,7 +631,7 @@ impl Test for T { expect![[r#""#]], ); - check( + check_no_kw( r" trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); } struct T; @@ -653,7 +648,7 @@ impl Test for T { "#]], ); - check( + check_no_kw( r" trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); } struct T; @@ -670,7 +665,7 @@ impl Test for T { "#]], ); - check( + check_no_kw( r" trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); } struct T; @@ -689,7 +684,7 @@ impl Test for T { "#]], ); - check( + check_no_kw( r" trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); } struct T; @@ -703,7 +698,7 @@ impl Test for T { expect![[""]], ); - check( + check_no_kw( r" trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); } struct T; @@ -720,7 +715,7 @@ impl Test for T { #[test] fn no_completion_inside_type() { - check( + check_no_kw( r" trait Test { type Test; type Test2; fn test(); } struct T; @@ -737,7 +732,7 @@ impl Test for T { "#]], ); - check( + check_no_kw( r" trait Test { type Test; type Test2; fn test(); } struct T; @@ -1263,7 +1258,7 @@ impl Foo for Bar { #[test] fn works_directly_in_impl() { - check( + check_no_kw( r#" trait Tr { fn required(); @@ -1277,7 +1272,7 @@ impl Tr for () { fn fn required() "#]], ); - check( + check_no_kw( r#" trait Tr { fn provided() {} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs index 4700ed6c1ae82..6541ee502d83d 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs @@ -32,14 +32,9 @@ pub(crate) fn complete_for_and_where( #[cfg(test)] mod tests { - use expect_test::{expect, Expect}; + use expect_test::expect; - use crate::tests::{check_edit, completion_list}; - - fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture); - expect.assert_eq(&actual) - } + use crate::tests::{check, check_edit}; #[test] fn test_else_edit_after_if() { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs index 0692446381be6..53a62fe49c5aa 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs @@ -59,14 +59,9 @@ pub(crate) fn complete_label( #[cfg(test)] mod tests { - use expect_test::{expect, Expect}; + use expect_test::expect; - use crate::tests::{check_edit, completion_list}; - - fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture); - expect.assert_eq(&actual); - } + use crate::tests::{check, check_edit}; #[test] fn check_lifetime_edit() { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs index f12f011a6bd35..bafe32942098c 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs @@ -159,14 +159,9 @@ fn module_chain_to_containing_module_file( #[cfg(test)] mod tests { - use expect_test::{expect, Expect}; + use expect_test::expect; - use crate::tests::completion_list; - - fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture); - expect.assert_eq(&actual); - } + use crate::tests::check; #[test] fn lib_module_completion() { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs index 5bdc320d573f1..67ea05e002b73 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs @@ -401,18 +401,13 @@ fn add_custom_postfix_completions( #[cfg(test)] mod tests { - use expect_test::{expect, Expect}; + use expect_test::expect; use crate::{ - tests::{check_edit, check_edit_with_config, completion_list, TEST_CONFIG}, + tests::{check, check_edit, check_edit_with_config, TEST_CONFIG}, CompletionConfig, Snippet, }; - fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture); - expect.assert_eq(&actual) - } - #[test] fn postfix_completion_works_for_trivial_path_expression() { check( diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs index 1815f34053216..71d143a2b7525 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs @@ -253,11 +253,34 @@ pub(crate) fn check_edit_with_config( assert_eq_text!(&ra_fixture_after, &actual) } -fn check_empty(ra_fixture: &str, expect: Expect) { +pub(crate) fn check(ra_fixture: &str, expect: Expect) { let actual = completion_list(ra_fixture); expect.assert_eq(&actual); } +pub(crate) fn check_with_base_items(ra_fixture: &str, expect: Expect) { + check(&format!("{BASE_ITEMS_FIXTURE}{ra_fixture}"), expect) +} + +pub(crate) fn check_no_kw(ra_fixture: &str, expect: Expect) { + let actual = completion_list_no_kw(ra_fixture); + expect.assert_eq(&actual) +} + +pub(crate) fn check_with_private_editable(ra_fixture: &str, expect: Expect) { + let actual = completion_list_no_kw_with_private_editable(ra_fixture); + expect.assert_eq(&actual); +} + +pub(crate) fn check_with_trigger_character( + ra_fixture: &str, + trigger_character: Option, + expect: Expect, +) { + let actual = completion_list_with_trigger_character(ra_fixture, trigger_character); + expect.assert_eq(&actual) +} + pub(crate) fn get_all_items( config: CompletionConfig<'_>, code: &str, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs index ebf3582057062..32d3b50f237e0 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs @@ -1,12 +1,7 @@ //! Completion tests for attributes. -use expect_test::{expect, Expect}; +use expect_test::expect; -use crate::tests::{check_edit, completion_list}; - -fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture); - expect.assert_eq(&actual); -} +use crate::tests::{check, check_edit}; #[test] fn derive_helpers() { @@ -788,14 +783,9 @@ mod cfg { mod derive { use super::*; - fn check_derive(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture); - expect.assert_eq(&actual); - } - #[test] fn no_completion_for_incorrect_derive() { - check_derive( + check( r#" //- minicore: derive, copy, clone, ord, eq, default, fmt #[derive{$0)] struct Test; @@ -806,7 +796,7 @@ mod derive { #[test] fn empty_derive() { - check_derive( + check( r#" //- minicore: derive, copy, clone, ord, eq, default, fmt #[derive($0)] struct Test; @@ -828,7 +818,7 @@ mod derive { #[test] fn derive_with_input_before() { - check_derive( + check( r#" //- minicore: derive, copy, clone, ord, eq, default, fmt #[derive(serde::Serialize, PartialEq, $0)] struct Test; @@ -849,7 +839,7 @@ mod derive { #[test] fn derive_with_input_after() { - check_derive( + check( r#" //- minicore: derive, copy, clone, ord, eq, default, fmt #[derive($0 serde::Serialize, PartialEq)] struct Test; @@ -870,7 +860,7 @@ mod derive { #[test] fn derive_with_existing_derives() { - check_derive( + check( r#" //- minicore: derive, copy, clone, ord, eq, default, fmt #[derive(PartialEq, Eq, Or$0)] struct Test; @@ -890,7 +880,7 @@ mod derive { #[test] fn derive_flyimport() { - check_derive( + check( r#" //- proc_macros: derive_identity //- minicore: derive @@ -904,7 +894,7 @@ mod derive { kw self:: "#]], ); - check_derive( + check( r#" //- proc_macros: derive_identity //- minicore: derive @@ -940,7 +930,7 @@ use proc_macros::DeriveIdentity; #[test] fn qualified() { - check_derive( + check( r#" //- proc_macros: derive_identity //- minicore: derive, copy, clone @@ -950,7 +940,7 @@ use proc_macros::DeriveIdentity; de DeriveIdentity proc_macro DeriveIdentity "#]], ); - check_derive( + check( r#" //- proc_macros: derive_identity //- minicore: derive, copy, clone @@ -1056,19 +1046,14 @@ mod lint { mod repr { use super::*; - fn check_repr(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture); - expect.assert_eq(&actual); - } - #[test] fn no_completion_for_incorrect_repr() { - check_repr(r#"#[repr{$0)] struct Test;"#, expect![[]]) + check(r#"#[repr{$0)] struct Test;"#, expect![[]]) } #[test] fn empty() { - check_repr( + check( r#"#[repr($0)] struct Test;"#, expect![[r#" ba C @@ -1093,12 +1078,12 @@ mod repr { #[test] fn transparent() { - check_repr(r#"#[repr(transparent, $0)] struct Test;"#, expect![[r#""#]]); + check(r#"#[repr(transparent, $0)] struct Test;"#, expect![[r#""#]]); } #[test] fn align() { - check_repr( + check( r#"#[repr(align(1), $0)] struct Test;"#, expect![[r#" ba C @@ -1121,7 +1106,7 @@ mod repr { #[test] fn packed() { - check_repr( + check( r#"#[repr(packed, $0)] struct Test;"#, expect![[r#" ba C @@ -1144,7 +1129,7 @@ mod repr { #[test] fn c() { - check_repr( + check( r#"#[repr(C, $0)] struct Test;"#, expect![[r#" ba align($0) @@ -1167,7 +1152,7 @@ mod repr { #[test] fn prim() { - check_repr( + check( r#"#[repr(usize, $0)] struct Test;"#, expect![[r#" ba C diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs index 3046614868644..3cc7fc9d92e1c 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs @@ -4,17 +4,12 @@ use expect_test::{expect, Expect}; use crate::{ config::AutoImportExclusionType, tests::{ - check_edit, check_empty, completion_list, completion_list_with_config, BASE_ITEMS_FIXTURE, + check, check_edit, check_with_base_items, completion_list_with_config, BASE_ITEMS_FIXTURE, TEST_CONFIG, }, CompletionConfig, }; -fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(&format!("{BASE_ITEMS_FIXTURE}{ra_fixture}")); - expect.assert_eq(&actual) -} - fn check_with_config(config: CompletionConfig<'_>, ra_fixture: &str, expect: Expect) { let actual = completion_list_with_config( config, @@ -28,7 +23,7 @@ fn check_with_config(config: CompletionConfig<'_>, ra_fixture: &str, expect: Exp #[test] fn complete_literal_struct_with_a_private_field() { // `FooDesc.bar` is private, the completion should not be triggered. - check( + check_with_base_items( r#" mod _69latrick { pub struct FooDesc { pub six: bool, pub neuf: Vec, bar: bool } @@ -79,7 +74,7 @@ fn baz() { #[test] fn completes_various_bindings() { - check_empty( + check( r#" fn func(param0 @ (param1, param2): (i32, i32)) { let letlocal = 92; @@ -125,7 +120,7 @@ fn func(param0 @ (param1, param2): (i32, i32)) { #[test] fn completes_all_the_things_in_fn_body() { - check( + check_with_base_items( r#" use non_existent::Unresolved; mod qualified { pub enum Enum { Variant } } @@ -191,7 +186,7 @@ impl Unit { ?? Unresolved "#]], ); - check( + check_with_base_items( r#" use non_existent::Unresolved; mod qualified { pub enum Enum { Variant } } @@ -224,7 +219,7 @@ impl Unit { #[test] fn complete_in_block() { - check_empty( + check( r#" fn foo() { if true { @@ -273,7 +268,7 @@ fn complete_in_block() { #[test] fn complete_after_if_expr() { - check_empty( + check( r#" fn foo() { if true {} @@ -321,7 +316,7 @@ fn complete_after_if_expr() { #[test] fn complete_in_match_arm() { - check_empty( + check( r#" fn foo() { match () { @@ -351,7 +346,7 @@ fn complete_in_match_arm() { #[test] fn completes_in_loop_ctx() { - check_empty( + check( r"fn my() { loop { $0 } }", expect![[r#" fn my() fn() @@ -390,7 +385,7 @@ fn completes_in_loop_ctx() { sn ppd "#]], ); - check_empty( + check( r"fn my() { loop { foo.$0 } }", expect![[r#" sn box Box::new(expr) @@ -415,7 +410,7 @@ fn completes_in_loop_ctx() { #[test] fn completes_in_let_initializer() { - check_empty( + check( r#"fn main() { let _ = $0 }"#, expect![[r#" fn main() fn() @@ -439,7 +434,7 @@ fn completes_in_let_initializer() { #[test] fn struct_initializer_field_expr() { - check_empty( + check( r#" struct Foo { pub f: i32, @@ -475,7 +470,7 @@ fn foo() { fn shadowing_shows_single_completion() { cov_mark::check!(shadowing_shows_single_completion); - check_empty( + check( r#" fn foo() { let bar = 92; @@ -508,7 +503,7 @@ fn foo() { #[test] fn in_macro_expr_frag() { - check_empty( + check( r#" macro_rules! m { ($e:expr) => { $e } } fn quux(x: i32) { @@ -535,7 +530,7 @@ fn quux(x: i32) { kw while let "#]], ); - check_empty( + check( r" macro_rules! m { ($e:expr) => { $e } } fn quux(x: i32) { @@ -562,7 +557,7 @@ fn quux(x: i32) { kw while let "#]], ); - check_empty( + check( r#" macro_rules! m { ($e:expr) => { $e } } fn quux(x: i32) { @@ -595,7 +590,7 @@ fn quux(x: i32) { #[test] fn enum_qualified() { - check( + check_with_base_items( r#" impl Enum { type AssocType = (); @@ -619,7 +614,7 @@ fn func() { #[test] fn ty_qualified_no_drop() { - check_empty( + check( r#" //- minicore: drop struct Foo; @@ -636,7 +631,7 @@ fn func() { #[test] fn with_parens() { - check_empty( + check( r#" enum Enum { Variant() @@ -657,7 +652,7 @@ fn func() { #[test] fn detail_impl_trait_in_return_position() { - check_empty( + check( r" //- minicore: sized trait Trait {} @@ -676,7 +671,7 @@ fn main() { #[test] fn detail_async_fn() { - check_empty( + check( r#" //- minicore: future, sized trait Trait {} @@ -697,7 +692,7 @@ fn main() { #[test] fn detail_impl_trait_in_argument_position() { - check_empty( + check( r" //- minicore: sized trait Trait {} @@ -717,7 +712,7 @@ fn main() { #[test] fn complete_record_expr_path() { - check( + check_with_base_items( r#" struct Zulu; impl Zulu { @@ -738,7 +733,7 @@ fn main() { #[test] fn variant_with_struct() { - check_empty( + check( r#" pub struct YoloVariant { pub f: usize @@ -813,7 +808,7 @@ fn return_value_no_block() { #[test] fn else_completion_after_if() { - check_empty( + check( r#" fn foo() { if foo {} $0 } "#, @@ -854,7 +849,7 @@ fn foo() { if foo {} $0 } sn ppd "#]], ); - check_empty( + check( r#" fn foo() { if foo {} el$0 } "#, @@ -895,7 +890,7 @@ fn foo() { if foo {} el$0 } sn ppd "#]], ); - check_empty( + check( r#" fn foo() { bar(if foo {} $0) } "#, @@ -919,7 +914,7 @@ fn foo() { bar(if foo {} $0) } kw while let "#]], ); - check_empty( + check( r#" fn foo() { bar(if foo {} el$0) } "#, @@ -943,7 +938,7 @@ fn foo() { bar(if foo {} el$0) } kw while let "#]], ); - check_empty( + check( r#" fn foo() { if foo {} $0 let x = 92; } "#, @@ -984,7 +979,7 @@ fn foo() { if foo {} $0 let x = 92; } sn ppd "#]], ); - check_empty( + check( r#" fn foo() { if foo {} el$0 let x = 92; } "#, @@ -1025,7 +1020,7 @@ fn foo() { if foo {} el$0 let x = 92; } sn ppd "#]], ); - check_empty( + check( r#" fn foo() { if foo {} el$0 { let x = 92; } } "#, @@ -1070,7 +1065,7 @@ fn foo() { if foo {} el$0 { let x = 92; } } #[test] fn expr_no_unstable_item_on_stable() { - check_empty( + check( r#" //- /main.rs crate:main deps:std use std::*; @@ -1121,7 +1116,7 @@ pub struct UnstableThisShouldNotBeListed; #[test] fn expr_unstable_item_on_nightly() { - check_empty( + check( r#" //- toolchain:nightly //- /main.rs crate:main deps:std @@ -1174,7 +1169,7 @@ pub struct UnstableButWeAreOnNightlyAnyway; #[test] fn inside_format_args_completions_work() { - check_empty( + check( r#" //- minicore: fmt struct Foo; @@ -1200,7 +1195,7 @@ fn main() { sn unsafe unsafe {} "#]], ); - check_empty( + check( r#" //- minicore: fmt struct Foo; @@ -1230,7 +1225,7 @@ fn main() { #[test] fn inside_faulty_format_args_completions_work() { - check_empty( + check( r#" //- minicore: fmt struct Foo; @@ -1256,7 +1251,7 @@ fn main() { sn unsafe unsafe {} "#]], ); - check_empty( + check( r#" //- minicore: fmt struct Foo; @@ -1282,7 +1277,7 @@ fn main() { sn unsafe unsafe {} "#]], ); - check_empty( + check( r#" //- minicore: fmt struct Foo; @@ -1308,7 +1303,7 @@ fn main() { sn unsafe unsafe {} "#]], ); - check_empty( + check( r#" //- minicore: fmt struct Foo; @@ -1340,7 +1335,7 @@ fn main() { #[test] fn macro_that_ignores_completion_marker() { - check( + check_with_base_items( r#" macro_rules! helper { ($v:ident) => {}; @@ -1788,7 +1783,7 @@ fn foo() { #[test] fn hide_ragennew_synthetic_identifiers() { - check_empty( + check( r#" //- minicore: iterator fn bar() { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/fn_param.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/fn_param.rs index 4a89f874e15ea..451ce07c7454b 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/fn_param.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/fn_param.rs @@ -1,16 +1,6 @@ -use expect_test::{expect, Expect}; +use expect_test::expect; -use crate::tests::{completion_list, completion_list_with_trigger_character}; - -fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture); - expect.assert_eq(&actual); -} - -fn check_with_trigger_character(ra_fixture: &str, trigger_character: char, expect: Expect) { - let actual = completion_list_with_trigger_character(ra_fixture, Some(trigger_character)); - expect.assert_eq(&actual) -} +use crate::tests::{check, check_with_trigger_character}; #[test] fn only_param() { @@ -124,7 +114,7 @@ fn trigger_by_l_paren() { r#" fn foo($0) "#, - '(', + Some('('), expect![[]], ) } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/item.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/item.rs index 79561a0419f99..bea6d60769cc9 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/item.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/item.rs @@ -2,20 +2,13 @@ //! //! Except for use items which are tested in [super::use_tree] and mod declarations with are tested //! in [crate::completions::mod_]. -use expect_test::{expect, Expect}; +use expect_test::expect; -use crate::tests::{completion_list, BASE_ITEMS_FIXTURE}; - -use super::check_edit; - -fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(&format!("{BASE_ITEMS_FIXTURE}{ra_fixture}")); - expect.assert_eq(&actual) -} +use crate::tests::{check_edit, check_with_base_items}; #[test] fn target_type_or_trait_in_impl_block() { - check( + check_with_base_items( r#" impl Tra$0 "#, @@ -37,7 +30,7 @@ impl Tra$0 #[test] fn target_type_in_trait_impl_block() { - check( + check_with_base_items( r#" impl Trait for Str$0 "#, @@ -59,7 +52,7 @@ impl Trait for Str$0 #[test] fn after_trait_name_in_trait_def() { - check( + check_with_base_items( r"trait A $0", expect![[r#" kw where @@ -69,21 +62,21 @@ fn after_trait_name_in_trait_def() { #[test] fn after_target_name_in_impl() { - check( + check_with_base_items( r"impl Trait $0", expect![[r#" kw for kw where "#]], ); - check( + check_with_base_items( r"impl Trait f$0", expect![[r#" kw for kw where "#]], ); - check( + check_with_base_items( r"impl Trait for Type $0", expect![[r#" kw where @@ -93,44 +86,44 @@ fn after_target_name_in_impl() { #[test] fn completes_where() { - check( + check_with_base_items( r"struct Struct $0", expect![[r#" kw where "#]], ); - check( + check_with_base_items( r"struct Struct $0 {}", expect![[r#" kw where "#]], ); // FIXME: This shouldn't be completed here - check( + check_with_base_items( r"struct Struct $0 ()", expect![[r#" kw where "#]], ); - check( + check_with_base_items( r"fn func() $0", expect![[r#" kw where "#]], ); - check( + check_with_base_items( r"enum Enum $0", expect![[r#" kw where "#]], ); - check( + check_with_base_items( r"enum Enum $0 {}", expect![[r#" kw where "#]], ); - check( + check_with_base_items( r"trait Trait $0 {}", expect![[r#" kw where @@ -140,7 +133,7 @@ fn completes_where() { #[test] fn before_record_field() { - check( + check_with_base_items( r#" struct Foo { $0 @@ -244,7 +237,7 @@ impl Copy for S where $0 #[test] fn test_is_not_considered_macro() { - check( + check_with_base_items( r#" #[rustc_builtin] pub macro test($item:item) { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/item_list.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/item_list.rs index d3d52dc6dfc5f..841c42123a017 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/item_list.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/item_list.rs @@ -1,16 +1,11 @@ //! Completion tests for item list position. -use expect_test::{expect, Expect}; +use expect_test::expect; -use crate::tests::{check_edit, check_empty, completion_list, BASE_ITEMS_FIXTURE}; - -fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(&format!("{BASE_ITEMS_FIXTURE}{ra_fixture}")); - expect.assert_eq(&actual) -} +use crate::tests::{check, check_edit, check_with_base_items}; #[test] fn in_mod_item_list() { - check( + check_with_base_items( r#"mod tests { $0 }"#, expect![[r#" ma makro!(…) macro_rules! makro @@ -43,7 +38,7 @@ fn in_mod_item_list() { #[test] fn in_source_file_item_list() { - check( + check_with_base_items( r#"$0"#, expect![[r#" ma makro!(…) macro_rules! makro @@ -76,7 +71,7 @@ fn in_source_file_item_list() { #[test] fn in_item_list_after_attr() { - check( + check_with_base_items( r#"#[attr] $0"#, expect![[r#" ma makro!(…) macro_rules! makro @@ -109,7 +104,7 @@ fn in_item_list_after_attr() { #[test] fn in_qualified_path() { - check( + check_with_base_items( r#"crate::$0"#, expect![[r#" ma makro!(…) macro_rules! makro @@ -120,7 +115,7 @@ fn in_qualified_path() { #[test] fn after_unsafe_token() { - check( + check_with_base_items( r#"unsafe $0"#, expect![[r#" kw async @@ -134,7 +129,7 @@ fn after_unsafe_token() { #[test] fn after_async_token() { - check( + check_with_base_items( r#"async $0"#, expect![[r#" kw fn @@ -145,7 +140,7 @@ fn after_async_token() { #[test] fn after_visibility() { - check( + check_with_base_items( r#"pub $0"#, expect![[r#" kw async @@ -167,7 +162,7 @@ fn after_visibility() { #[test] fn after_visibility_unsafe() { - check( + check_with_base_items( r#"pub unsafe $0"#, expect![[r#" kw async @@ -179,7 +174,7 @@ fn after_visibility_unsafe() { #[test] fn in_impl_assoc_item_list() { - check( + check_with_base_items( r#"impl Struct { $0 }"#, expect![[r#" ma makro!(…) macro_rules! makro @@ -199,7 +194,7 @@ fn in_impl_assoc_item_list() { #[test] fn in_impl_assoc_item_list_after_attr() { - check( + check_with_base_items( r#"impl Struct { #[attr] $0 }"#, expect![[r#" ma makro!(…) macro_rules! makro @@ -219,7 +214,7 @@ fn in_impl_assoc_item_list_after_attr() { #[test] fn in_trait_assoc_item_list() { - check( + check_with_base_items( r"trait Foo { $0 }", expect![[r#" ma makro!(…) macro_rules! makro @@ -237,7 +232,7 @@ fn in_trait_assoc_item_list() { #[test] fn in_trait_assoc_fn_missing_body() { - check( + check_with_base_items( r#"trait Foo { fn function(); $0 }"#, expect![[r#" ma makro!(…) macro_rules! makro @@ -255,7 +250,7 @@ fn in_trait_assoc_fn_missing_body() { #[test] fn in_trait_assoc_const_missing_body() { - check( + check_with_base_items( r#"trait Foo { const CONST: (); $0 }"#, expect![[r#" ma makro!(…) macro_rules! makro @@ -273,7 +268,7 @@ fn in_trait_assoc_const_missing_body() { #[test] fn in_trait_assoc_type_aliases_missing_ty() { - check( + check_with_base_items( r#"trait Foo { type Type; $0 }"#, expect![[r#" ma makro!(…) macro_rules! makro @@ -291,7 +286,7 @@ fn in_trait_assoc_type_aliases_missing_ty() { #[test] fn in_trait_impl_assoc_item_list() { - check( + check_with_base_items( r#" trait Test { type Type0; @@ -326,7 +321,7 @@ impl Test for () { #[test] fn in_trait_impl_no_unstable_item_on_stable() { - check_empty( + check( r#" trait Test { #[unstable] @@ -350,7 +345,7 @@ impl Test for () { #[test] fn in_trait_impl_unstable_item_on_nightly() { - check_empty( + check( r#" //- toolchain:nightly trait Test { @@ -378,7 +373,7 @@ impl Test for () { #[test] fn after_unit_struct() { - check( + check_with_base_items( r#"struct S; f$0"#, expect![[r#" ma makro!(…) macro_rules! makro @@ -500,7 +495,7 @@ type O = $0; #[test] fn inside_extern_blocks() { // Should suggest `fn`, `static`, `unsafe` - check( + check_with_base_items( r#"extern { $0 }"#, expect![[r#" ma makro!(…) macro_rules! makro @@ -517,7 +512,7 @@ fn inside_extern_blocks() { ); // Should suggest `fn`, `static`, `safe`, `unsafe` - check( + check_with_base_items( r#"unsafe extern { $0 }"#, expect![[r#" ma makro!(…) macro_rules! makro @@ -534,7 +529,7 @@ fn inside_extern_blocks() { "#]], ); - check( + check_with_base_items( r#"unsafe extern { pub safe $0 }"#, expect![[r#" kw fn @@ -542,7 +537,7 @@ fn inside_extern_blocks() { "#]], ); - check( + check_with_base_items( r#"unsafe extern { pub unsafe $0 }"#, expect![[r#" kw fn diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs index 2f1f555e5249e..9ec27252fd741 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs @@ -1,16 +1,11 @@ //! Completion tests for pattern position. -use expect_test::{expect, Expect}; +use expect_test::expect; -use crate::tests::{check_edit, check_empty, completion_list, BASE_ITEMS_FIXTURE}; - -fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(&format!("{BASE_ITEMS_FIXTURE}\n{ra_fixture}")); - expect.assert_eq(&actual) -} +use crate::tests::{check, check_edit, check_with_base_items}; #[test] fn wildcard() { - check( + check_with_base_items( r#" fn quux() { let _$0 @@ -22,7 +17,7 @@ fn quux() { #[test] fn ident_rebind_pat() { - check_empty( + check( r#" fn quux() { let en$0 @ x @@ -37,7 +32,7 @@ fn quux() { #[test] fn ident_ref_pat() { - check_empty( + check( r#" fn quux() { let ref en$0 @@ -47,7 +42,7 @@ fn quux() { kw mut "#]], ); - check_empty( + check( r#" fn quux() { let ref en$0 @ x @@ -61,7 +56,7 @@ fn quux() { #[test] fn ident_ref_mut_pat() { - check_empty( + check( r#" fn quux() { let ref mut en$0 @@ -69,7 +64,7 @@ fn quux() { "#, expect![[r#""#]], ); - check_empty( + check( r#" fn quux() { let ref mut en$0 @ x @@ -81,7 +76,7 @@ fn quux() { #[test] fn ref_pat() { - check_empty( + check( r#" fn quux() { let &en$0 @@ -91,7 +86,7 @@ fn quux() { kw mut "#]], ); - check_empty( + check( r#" fn quux() { let &mut en$0 @@ -99,7 +94,7 @@ fn quux() { "#, expect![[r#""#]], ); - check_empty( + check( r#" fn foo() { for &$0 in () {} @@ -113,7 +108,7 @@ fn foo() { #[test] fn refutable() { - check( + check_with_base_items( r#" fn foo() { if let a$0 @@ -139,7 +134,7 @@ fn foo() { #[test] fn irrefutable() { - check( + check_with_base_items( r#" enum SingleVariantEnum { Variant @@ -168,7 +163,7 @@ fn foo() { #[test] fn in_param() { - check( + check_with_base_items( r#" fn foo(a$0) { } @@ -185,7 +180,7 @@ fn foo(a$0) { kw ref "#]], ); - check( + check_with_base_items( r#" fn foo(a$0: Tuple) { } @@ -207,7 +202,7 @@ fn foo(a$0: Tuple) { #[test] fn only_fn_like_macros() { - check_empty( + check( r#" macro_rules! m { ($e:expr) => { $e } } @@ -228,7 +223,7 @@ fn foo() { #[test] fn in_simple_macro_call() { - check_empty( + check( r#" macro_rules! m { ($e:expr) => { $e } } enum E { X } @@ -249,7 +244,7 @@ fn foo() { #[test] fn omits_private_fields_pat() { - check_empty( + check( r#" mod foo { pub struct Record { pub field: i32, _field: i32 } @@ -277,7 +272,7 @@ fn outer() { #[test] fn completes_self_pats() { - check_empty( + check( r#" struct Foo(i32); impl Foo { @@ -301,7 +296,7 @@ impl Foo { #[test] fn enum_qualified() { - check( + check_with_base_items( r#" impl Enum { type AssocType = (); @@ -323,7 +318,7 @@ fn func() { #[test] fn completes_in_record_field_pat() { - check_empty( + check( r#" struct Foo { bar: Bar } struct Bar(u32); @@ -342,7 +337,7 @@ fn outer(Foo { bar: $0 }: Foo) {} #[test] fn skips_in_record_field_pat_name() { - check_empty( + check( r#" struct Foo { bar: Bar } struct Bar(u32); @@ -357,7 +352,7 @@ fn outer(Foo { bar$0 }: Foo) {} #[test] fn completes_in_record_field_pat_with_generic_type_alias() { - check_empty( + check( r#" type Wrap = T; @@ -386,7 +381,7 @@ fn main() { #[test] fn completes_in_fn_param() { - check_empty( + check( r#" struct Foo { bar: Bar } struct Bar(u32); @@ -405,7 +400,7 @@ fn foo($0) {} #[test] fn completes_in_closure_param() { - check_empty( + check( r#" struct Foo { bar: Bar } struct Bar(u32); @@ -426,7 +421,7 @@ fn foo() { #[test] fn completes_no_delims_if_existing() { - check_empty( + check( r#" struct Bar(u32); fn foo() { @@ -441,7 +436,7 @@ fn foo() { kw self:: "#]], ); - check_empty( + check( r#" struct Foo { bar: u32 } fn foo() { @@ -456,7 +451,7 @@ fn foo() { kw self:: "#]], ); - check_empty( + check( r#" enum Enum { TupleVariant(u32) @@ -471,7 +466,7 @@ fn foo() { bn TupleVariant TupleVariant "#]], ); - check_empty( + check( r#" enum Enum { RecordVariant { field: u32 } @@ -519,7 +514,7 @@ fn foo() { #[test] fn completes_enum_variant_pat_escape() { cov_mark::check!(enum_variant_pattern_path); - check_empty( + check( r#" enum Enum { A, @@ -544,7 +539,7 @@ fn foo() { "#]], ); - check_empty( + check( r#" enum Enum { A, @@ -569,7 +564,7 @@ fn foo() { #[test] fn completes_associated_const() { - check_empty( + check( r#" #[derive(PartialEq, Eq)] struct Ty(u8); @@ -590,7 +585,7 @@ fn f(t: Ty) { "#]], ); - check_empty( + check( r#" enum MyEnum {} @@ -612,7 +607,7 @@ fn f(e: MyEnum) { "#]], ); - check_empty( + check( r#" union U { i: i32, @@ -637,7 +632,7 @@ fn f(u: U) { "#]], ); - check_empty( + check( r#" #![rustc_coherence_is_core] #[lang = "u32"] @@ -659,7 +654,7 @@ fn f(v: u32) { #[test] fn in_method_param() { - check_empty( + check( r#" struct Ty(u8); @@ -680,7 +675,7 @@ impl Ty { kw ref "#]], ); - check_empty( + check( r#" struct Ty(u8); @@ -701,7 +696,7 @@ impl Ty { kw ref "#]], ); - check_empty( + check( r#" struct Ty(u8); @@ -722,7 +717,7 @@ impl Ty { kw ref "#]], ); - check_empty( + check( r#" struct Ty(u8); @@ -743,7 +738,7 @@ impl Ty { #[test] fn through_alias() { - check_empty( + check( r#" enum Enum { Unit, @@ -770,7 +765,7 @@ fn f(x: EnumAlias) { #[test] fn pat_no_unstable_item_on_stable() { - check_empty( + check( r#" //- /main.rs crate:main deps:std use std::*; @@ -795,7 +790,7 @@ pub enum Enum { #[test] fn pat_unstable_item_on_nightly() { - check_empty( + check( r#" //- toolchain:nightly //- /main.rs crate:main deps:std @@ -908,7 +903,7 @@ fn foo() { ); // Do not suggest reserved keywords - check_empty( + check( r#" struct Struct; @@ -926,7 +921,7 @@ fn foo() { #[test] fn private_item_in_module_in_function_body() { - check_empty( + check( r#" fn main() { mod foo { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/predicate.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/predicate.rs index c1926359efc25..65036f6a22405 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/predicate.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/predicate.rs @@ -1,17 +1,12 @@ //! Completion tests for predicates and bounds. -use expect_test::{expect, Expect}; +use expect_test::expect; -use crate::tests::{check_empty, completion_list, BASE_ITEMS_FIXTURE}; - -fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(&format!("{BASE_ITEMS_FIXTURE}\n{ra_fixture}")); - expect.assert_eq(&actual) -} +use crate::tests::{check, check_with_base_items}; #[test] fn predicate_start() { // FIXME: `for` kw - check( + check_with_base_items( r#" struct Foo<'lt, T, const C: usize> where $0 {} "#, @@ -34,7 +29,7 @@ struct Foo<'lt, T, const C: usize> where $0 {} #[test] fn bound_for_type_pred() { - check( + check_with_base_items( r#" struct Foo<'lt, T, const C: usize> where T: $0 {} "#, @@ -52,7 +47,7 @@ struct Foo<'lt, T, const C: usize> where T: $0 {} fn bound_for_lifetime_pred() { // FIXME: should only show lifetimes here, that is we shouldn't get any completions here when not typing // a `'` - check( + check_with_base_items( r#" struct Foo<'lt, T, const C: usize> where 'lt: $0 {} "#, @@ -68,7 +63,7 @@ struct Foo<'lt, T, const C: usize> where 'lt: $0 {} #[test] fn bound_for_for_pred() { - check( + check_with_base_items( r#" struct Foo<'lt, T, const C: usize> where for<'a> T: $0 {} "#, @@ -84,7 +79,7 @@ struct Foo<'lt, T, const C: usize> where for<'a> T: $0 {} #[test] fn param_list_for_for_pred() { - check( + check_with_base_items( r#" struct Foo<'lt, T, const C: usize> where for<'a> $0 {} "#, @@ -107,7 +102,7 @@ struct Foo<'lt, T, const C: usize> where for<'a> $0 {} #[test] fn pred_on_fn_in_impl() { - check( + check_with_base_items( r#" impl Record { fn method(self) where $0 {} @@ -132,7 +127,7 @@ impl Record { #[test] fn pred_no_unstable_item_on_stable() { - check_empty( + check( r#" //- /main.rs crate:main deps:std use std::*; @@ -151,7 +146,7 @@ pub trait Trait {} #[test] fn pred_unstable_item_on_nightly() { - check_empty( + check( r#" //- toolchain:nightly //- /main.rs crate:main deps:std diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/proc_macros.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/proc_macros.rs index afc286b6fb4de..6b1dfe366ce2d 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/proc_macros.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/proc_macros.rs @@ -1,12 +1,7 @@ //! Completion tests for expressions. -use expect_test::{expect, Expect}; +use expect_test::expect; -use crate::tests::completion_list; - -fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture); - expect.assert_eq(&actual) -} +use crate::tests::check; #[test] fn complete_dot_in_attr() { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs index a9c9f604e075b..a1013b86548be 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs @@ -1,14 +1,9 @@ -use expect_test::{expect, Expect}; +use expect_test::expect; -use crate::tests::completion_list; +use crate::tests::check; use super::check_edit; -fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture); - expect.assert_eq(&actual); -} - #[test] fn without_default_impl() { check( diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs index 6cfb2231a9906..2b05184bdbeba 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs @@ -5,32 +5,12 @@ use ide_db::SymbolKind; use crate::{ tests::{ - check_edit, completion_list, completion_list_no_kw, completion_list_with_trigger_character, + check, check_edit, check_no_kw, check_with_trigger_character, do_completion_with_config, + TEST_CONFIG, }, CompletionItemKind, }; -use super::{do_completion_with_config, TEST_CONFIG}; - -fn check_no_kw(ra_fixture: &str, expect: Expect) { - let actual = completion_list_no_kw(ra_fixture); - expect.assert_eq(&actual) -} - -fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture); - expect.assert_eq(&actual) -} - -pub(crate) fn check_with_trigger_character( - ra_fixture: &str, - trigger_character: Option, - expect: Expect, -) { - let actual = completion_list_with_trigger_character(ra_fixture, trigger_character); - expect.assert_eq(&actual) -} - #[test] fn completes_if_prefix_is_keyword() { check_edit( diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs index 9ea262bcc597b..c7e2d058257e3 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs @@ -1,16 +1,11 @@ //! Completion tests for type position. -use expect_test::{expect, Expect}; +use expect_test::expect; -use crate::tests::{check_empty, completion_list, BASE_ITEMS_FIXTURE}; - -fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(&format!("{BASE_ITEMS_FIXTURE}\n{ra_fixture}")); - expect.assert_eq(&actual) -} +use crate::tests::{check, check_with_base_items}; #[test] fn record_field_ty() { - check( + check_with_base_items( r#" struct Foo<'lt, T, const C: usize> { f: $0 @@ -37,7 +32,7 @@ struct Foo<'lt, T, const C: usize> { #[test] fn tuple_struct_field() { - check( + check_with_base_items( r#" struct Foo<'lt, T, const C: usize>(f$0); "#, @@ -65,7 +60,7 @@ struct Foo<'lt, T, const C: usize>(f$0); #[test] fn fn_return_type() { - check( + check_with_base_items( r#" fn x<'lt, T, const C: usize>() -> $0 "#, @@ -88,7 +83,7 @@ fn x<'lt, T, const C: usize>() -> $0 #[test] fn fn_return_type_no_local_items() { - check( + check_with_base_items( r#" fn foo() -> B$0 { struct Bar; @@ -118,7 +113,7 @@ fn foo() -> B$0 { #[test] fn inferred_type_const() { - check( + check_with_base_items( r#" struct Foo(T); const FOO: $0 = Foo(2); @@ -143,7 +138,7 @@ const FOO: $0 = Foo(2); #[test] fn inferred_type_closure_param() { - check( + check_with_base_items( r#" fn f1(f: fn(i32) -> i32) {} fn f2() { @@ -169,7 +164,7 @@ fn f2() { #[test] fn inferred_type_closure_return() { - check( + check_with_base_items( r#" fn f1(f: fn(u64) -> u64) {} fn f2() { @@ -197,7 +192,7 @@ fn f2() { #[test] fn inferred_type_fn_return() { - check( + check_with_base_items( r#" fn f2(x: u64) -> $0 { x + 5 @@ -222,7 +217,7 @@ fn f2(x: u64) -> $0 { #[test] fn inferred_type_fn_param() { - check( + check_with_base_items( r#" fn f1(x: i32) {} fn f2(x: $0) { @@ -248,7 +243,7 @@ fn f2(x: $0) { #[test] fn inferred_type_not_in_the_scope() { - check( + check_with_base_items( r#" mod a { pub struct Foo(T); @@ -282,7 +277,7 @@ fn foo<'lt, T, const C: usize>() { #[test] fn inferred_type_let() { - check( + check_with_base_items( r#" struct Foo(T); fn foo<'lt, T, const C: usize>() { @@ -311,7 +306,7 @@ fn foo<'lt, T, const C: usize>() { #[test] fn body_type_pos() { - check( + check_with_base_items( r#" fn foo<'lt, T, const C: usize>() { let local = (); @@ -333,7 +328,7 @@ fn foo<'lt, T, const C: usize>() { kw self:: "#]], ); - check( + check_with_base_items( r#" fn foo<'lt, T, const C: usize>() { let local = (); @@ -356,7 +351,7 @@ fn foo<'lt, T, const C: usize>() { #[test] fn completes_types_and_const_in_arg_list() { cov_mark::check!(complete_assoc_type_in_generics_list); - check( + check_with_base_items( r#" trait Trait1 { type Super; @@ -372,7 +367,7 @@ fn foo<'lt, T: Trait2<$0>, const CONST_PARAM: usize>(_: T) {} ta Super = (as Trait1) type Super "#]], ); - check( + check_with_base_items( r#" trait Trait1 { type Super; @@ -400,7 +395,7 @@ fn foo<'lt, T: Trait2<$0>, const CONST_PARAM: usize>(_: T) {} kw self:: "#]], ); - check( + check_with_base_items( r#" trait Trait2 { type Foo; @@ -424,7 +419,7 @@ fn foo<'lt, T: Trait2, const CONST_PARAM: usize>(_: T) {} #[test] fn no_assoc_completion_outside_type_bounds() { - check( + check_with_base_items( r#" struct S; trait Tr { @@ -454,7 +449,7 @@ impl Tr<$0 #[test] fn enum_qualified() { - check( + check_with_base_items( r#" impl Enum { type AssocType = (); @@ -471,7 +466,7 @@ fn func(_: Enum::$0) {} #[test] fn completes_type_parameter_or_associated_type() { - check( + check_with_base_items( r#" trait MyTrait { type Item1; @@ -496,7 +491,7 @@ fn f(t: impl MyTrait { type Item1; @@ -521,7 +516,7 @@ fn f(t: impl MyTrait { type Item1; @@ -539,7 +534,7 @@ fn f(t: impl MyTrait { type Item1; @@ -564,7 +559,7 @@ fn f(t: impl MyTrait { type Item1; @@ -591,7 +586,7 @@ fn f(t: impl MyTrait { type Item1; @@ -609,7 +604,7 @@ fn f(t: impl MyTrait()`, but we currently don't suggest `usize` in constant position. - check( + check_with_base_items( r#" struct Foo; const X: usize = 0; @@ -775,7 +770,7 @@ fn completes_const_and_type_generics_separately() { ); // Method generic params - check( + check_with_base_items( r#" const X: usize = 0; struct Foo; @@ -799,7 +794,7 @@ fn completes_const_and_type_generics_separately() { kw self:: "#]], ); - check( + check_with_base_items( r#" const X: usize = 0; struct Foo; @@ -818,7 +813,7 @@ fn completes_const_and_type_generics_separately() { ); // Associated type generic params - check( + check_with_base_items( r#" const X: usize = 0; struct Foo; @@ -843,7 +838,7 @@ fn completes_const_and_type_generics_separately() { kw self:: "#]], ); - check( + check_with_base_items( r#" const X: usize = 0; struct Foo; @@ -862,7 +857,7 @@ fn completes_const_and_type_generics_separately() { ); // Type generic params - check( + check_with_base_items( r#" const X: usize = 0; struct Foo(T); @@ -880,7 +875,7 @@ fn completes_const_and_type_generics_separately() { ); // Type alias generic params - check( + check_with_base_items( r#" const X: usize = 0; struct Foo(T); @@ -899,7 +894,7 @@ fn completes_const_and_type_generics_separately() { ); // Enum variant params - check( + check_with_base_items( r#" const X: usize = 0; enum Foo { A(T), B } @@ -917,7 +912,7 @@ fn completes_const_and_type_generics_separately() { ); // Trait params - check( + check_with_base_items( r#" const X: usize = 0; trait Foo {} @@ -933,7 +928,7 @@ fn completes_const_and_type_generics_separately() { ); // Trait alias params - check( + check_with_base_items( r#" #![feature(trait_alias)] const X: usize = 0; @@ -951,7 +946,7 @@ fn completes_const_and_type_generics_separately() { ); // Omitted lifetime params - check( + check_with_base_items( r#" struct S<'a, 'b, const C: usize, T>(core::marker::PhantomData<&'a &'b T>); fn foo<'a>() { S::; } @@ -964,7 +959,7 @@ fn foo<'a>() { S::; } "#]], ); // Explicit lifetime params - check( + check_with_base_items( r#" struct S<'a, 'b, const C: usize, T>(core::marker::PhantomData<&'a &'b T>); fn foo<'a>() { S::<'static, 'static, F$0, _>; } @@ -976,7 +971,7 @@ fn foo<'a>() { S::<'static, 'static, F$0, _>; } kw self:: "#]], ); - check( + check_with_base_items( r#" struct S<'a, 'b, const C: usize, T>(core::marker::PhantomData<&'a &'b T>); fn foo<'a>() { S::<'static, F$0, _, _>; } @@ -992,7 +987,7 @@ fn foo<'a>() { S::<'static, F$0, _, _>; } #[test] fn complete_traits_on_impl_trait_block() { - check( + check_with_base_items( r#" trait Foo {} @@ -1012,7 +1007,7 @@ impl $0 for Bar { } #[test] fn complete_traits_with_path_on_impl_trait_block() { - check( + check_with_base_items( r#" mod outer { pub trait Foo {} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/use_tree.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/use_tree.rs index 2ea2e4e4c967d..04b3a47a64dab 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/use_tree.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/use_tree.rs @@ -1,12 +1,7 @@ //! Completion tests for use trees. -use expect_test::{expect, Expect}; +use expect_test::expect; -use crate::tests::completion_list; - -fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture); - expect.assert_eq(&actual) -} +use crate::tests::check; #[test] fn use_tree_completion() { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/visibility.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/visibility.rs index c18d6e66dd602..4b5a0ac1c2b97 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/visibility.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/visibility.rs @@ -1,17 +1,7 @@ //! Completion tests for visibility modifiers. -use expect_test::{expect, Expect}; +use expect_test::expect; -use crate::tests::{completion_list, completion_list_with_trigger_character}; - -fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture); - expect.assert_eq(&actual) -} - -fn check_with_trigger_character(ra_fixture: &str, trigger_character: char, expect: Expect) { - let actual = completion_list_with_trigger_character(ra_fixture, Some(trigger_character)); - expect.assert_eq(&actual) -} +use crate::tests::{check, check_with_trigger_character}; #[test] fn empty_pub() { @@ -20,7 +10,7 @@ fn empty_pub() { r#" pub($0) "#, - '(', + Some('('), expect![[r#" kw crate kw in From 253bba044eccc1b7480ac5b17b6278bede677b99 Mon Sep 17 00:00:00 2001 From: Nicholas Rishel Date: Tue, 7 Jan 2025 18:40:46 -0800 Subject: [PATCH 021/115] Add config setting which allows adding additional include paths to the VFS. --- .../project-model/src/cargo_workspace.rs | 2 ++ .../crates/project-model/src/tests.rs | 3 ++ .../crates/project-model/src/workspace.rs | 32 +++++++++++++++++-- .../rust-analyzer/src/cli/rustc_tests.rs | 1 + .../crates/rust-analyzer/src/config.rs | 12 +++++++ .../docs/user/generated_config.adoc | 7 ++++ .../rust-analyzer/editors/code/package.json | 13 ++++++++ 7 files changed, 67 insertions(+), 3 deletions(-) diff --git a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs index 4d906c2aeb3b5..e4a6113462054 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs @@ -92,6 +92,8 @@ pub struct CargoConfig { pub sysroot_src: Option, /// rustc private crate source pub rustc_source: Option, + /// Extra includes to add to the VFS. + pub extra_includes: Vec, pub cfg_overrides: CfgOverrides, /// Invoke `cargo check` through the RUSTC_WRAPPER. pub wrap_rustc_in_build_scripts: bool, diff --git a/src/tools/rust-analyzer/crates/project-model/src/tests.rs b/src/tools/rust-analyzer/crates/project-model/src/tests.rs index 681bce3a5a640..f111383112593 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/tests.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/tests.rs @@ -49,6 +49,7 @@ fn load_workspace_from_metadata(file: &str) -> ProjectWorkspace { rustc_cfg: Vec::new(), toolchain: None, target_layout: Err("target_data_layout not loaded".into()), + extra_includes: Vec::new(), } } @@ -63,6 +64,7 @@ fn load_rust_project(file: &str) -> (CrateGraph, ProcMacroPaths) { toolchain: None, target_layout: Err(Arc::from("test has no data layout")), cfg_overrides: Default::default(), + extra_includes: Vec::new(), }; to_crate_graph(project_workspace, &mut Default::default()) } @@ -284,6 +286,7 @@ fn smoke_test_real_sysroot_cargo() { cfg_overrides: Default::default(), toolchain: None, target_layout: Err("target_data_layout not loaded".into()), + extra_includes: Vec::new(), }; project_workspace.to_crate_graph( &mut { diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs index a345c6bcce45f..465a1ad0ec506 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs @@ -63,6 +63,8 @@ pub struct ProjectWorkspace { pub target_layout: TargetLayoutLoadResult, /// A set of cfg overrides for this workspace. pub cfg_overrides: CfgOverrides, + /// Additional includes to add for the VFS. + pub extra_includes: Vec, } #[derive(Clone)] @@ -104,7 +106,15 @@ pub enum ProjectWorkspaceKind { impl fmt::Debug for ProjectWorkspace { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // Make sure this isn't too verbose. - let Self { kind, sysroot, rustc_cfg, toolchain, target_layout, cfg_overrides } = self; + let Self { + kind, + sysroot, + rustc_cfg, + toolchain, + target_layout, + cfg_overrides, + extra_includes, + } = self; match kind { ProjectWorkspaceKind::Cargo { cargo, error: _, build_scripts, rustc, set_test } => f .debug_struct("Cargo") @@ -117,6 +127,7 @@ impl fmt::Debug for ProjectWorkspace { ) .field("n_rustc_cfg", &rustc_cfg.len()) .field("n_cfg_overrides", &cfg_overrides.len()) + .field("n_extra_includes", &extra_includes.len()) .field("toolchain", &toolchain) .field("data_layout", &target_layout) .field("set_test", set_test) @@ -130,7 +141,8 @@ impl fmt::Debug for ProjectWorkspace { .field("n_rustc_cfg", &rustc_cfg.len()) .field("toolchain", &toolchain) .field("data_layout", &target_layout) - .field("n_cfg_overrides", &cfg_overrides.len()); + .field("n_cfg_overrides", &cfg_overrides.len()) + .field("n_extra_includes", &extra_includes.len()); debug_struct.finish() } @@ -144,6 +156,7 @@ impl fmt::Debug for ProjectWorkspace { .field("toolchain", &toolchain) .field("data_layout", &target_layout) .field("n_cfg_overrides", &cfg_overrides.len()) + .field("n_extra_includes", &extra_includes.len()) .field("set_test", set_test) .finish(), } @@ -320,6 +333,7 @@ impl ProjectWorkspace { cfg_overrides, toolchain, target_layout: data_layout.map(Arc::from).map_err(|it| Arc::from(it.to_string())), + extra_includes: config.extra_includes.clone(), }) } @@ -340,6 +354,7 @@ impl ProjectWorkspace { toolchain, target_layout: data_layout.map(Arc::from).map_err(|it| Arc::from(it.to_string())), cfg_overrides: config.cfg_overrides.clone(), + extra_includes: config.extra_includes.clone(), } } @@ -399,6 +414,7 @@ impl ProjectWorkspace { toolchain, target_layout: data_layout.map(Arc::from).map_err(|it| Arc::from(it.to_string())), cfg_overrides: config.cfg_overrides.clone(), + extra_includes: config.extra_includes.clone(), }) } @@ -565,7 +581,13 @@ impl ProjectWorkspace { PackageRoot { is_local: krate.is_workspace_member, - include: krate.include.iter().cloned().chain(build_file).collect(), + include: krate + .include + .iter() + .cloned() + .chain(build_file) + .chain(self.extra_includes.iter().cloned()) + .collect(), exclude: krate.exclude.clone(), } }) @@ -603,6 +625,8 @@ impl ProjectWorkspace { let mut exclude = vec![pkg_root.join(".git")]; if is_local { + include.extend(self.extra_includes.iter().cloned()); + exclude.push(pkg_root.join("target")); } else { exclude.push(pkg_root.join("tests")); @@ -661,6 +685,8 @@ impl ProjectWorkspace { let mut exclude = vec![pkg_root.join(".git")]; if is_local { + include.extend(self.extra_includes.iter().cloned()); + exclude.push(pkg_root.join("target")); } else { exclude.push(pkg_root.join("tests")); diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs index 6b0ce4db7c932..199f61e70f027 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs @@ -93,6 +93,7 @@ impl Tester { toolchain: None, target_layout: data_layout.map(Arc::from).map_err(|it| Arc::from(it.to_string())), cfg_overrides: Default::default(), + extra_includes: vec![], }; let load_cargo_config = LoadCargoConfig { load_out_dirs_from_check: false, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index 30f0031905f19..28afd83e5c95e 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -728,6 +728,10 @@ config_data! { /// available on a nightly build. rustfmt_rangeFormatting_enable: bool = false, + /// Additional paths to include in the VFS. Generally for code that is + /// generated or otherwise managed by a build system outside of Cargo, + /// though Cargo might be the eventual consumer. + vfs_extraIncludes: Vec = vec![], /// Workspace symbol search kind. workspace_symbol_search_kind: WorkspaceSymbolSearchKindDef = WorkspaceSymbolSearchKindDef::OnlyTypes, @@ -1926,6 +1930,13 @@ impl Config { }); let sysroot_src = self.cargo_sysrootSrc(source_root).as_ref().map(|sysroot| self.root_path.join(sysroot)); + let extra_includes = self + .vfs_extraIncludes(source_root) + .iter() + .map(String::as_str) + .map(AbsPathBuf::try_from) + .filter_map(Result::ok) + .collect(); CargoConfig { all_targets: *self.cargo_allTargets(source_root), @@ -1940,6 +1951,7 @@ impl Config { sysroot, sysroot_src, rustc_source, + extra_includes, cfg_overrides: project_model::CfgOverrides { global: CfgDiff::new( self.cargo_cfgs(source_root) diff --git a/src/tools/rust-analyzer/docs/user/generated_config.adoc b/src/tools/rust-analyzer/docs/user/generated_config.adoc index 5b86766aa8eac..b3d3614e22b7c 100644 --- a/src/tools/rust-analyzer/docs/user/generated_config.adoc +++ b/src/tools/rust-analyzer/docs/user/generated_config.adoc @@ -1051,6 +1051,13 @@ Show documentation. -- Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. -- +[[rust-analyzer.vfs.extraIncludes]]rust-analyzer.vfs.extraIncludes (default: `[]`):: ++ +-- +Additional paths to include in the VFS. Generally for code that is +generated or otherwise managed by a build system outside of Cargo, +though Cargo might be the eventual consumer. +-- [[rust-analyzer.workspace.discoverConfig]]rust-analyzer.workspace.discoverConfig (default: `null`):: + -- diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index 80246bf3feac9..87afc5c281bb8 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -2718,6 +2718,19 @@ } } }, + { + "title": "vfs", + "properties": { + "rust-analyzer.vfs.extraIncludes": { + "markdownDescription": "Additional paths to include in the VFS. Generally for code that is\ngenerated or otherwise managed by a build system outside of Cargo,\nthough Cargo might be the eventual consumer.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + } + } + }, { "title": "workspace", "properties": { From 4001c468ddf22a47cd985861d1b8d332d6a665be Mon Sep 17 00:00:00 2001 From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com> Date: Sat, 16 Nov 2024 14:42:17 -0500 Subject: [PATCH 022/115] internal: Migrate `wrap_return_type` assist to use `SyntaxEditor` --- .../src/handlers/add_turbo_fish.rs | 2 +- .../src/handlers/wrap_return_type.rs | 119 +++++++++--------- .../src/ast/syntax_factory/constructors.rs | 110 +++++++++++++++- 3 files changed, 168 insertions(+), 63 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs index 62700ab1809fb..04d63f5bc8fe6 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs @@ -189,7 +189,7 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti /// This will create a turbofish generic arg list corresponding to the number of arguments fn get_fish_head(make: &SyntaxFactory, number_of_arguments: usize) -> ast::GenericArgList { let args = (0..number_of_arguments).map(|_| make::type_arg(make::ty_placeholder()).into()); - make.turbofish_generic_arg_list(args) + make.generic_arg_list(args, true) } #[cfg(test)] diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type.rs index 658600cd2d0e8..0b145dcb06ba3 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type.rs @@ -6,10 +6,9 @@ use ide_db::{ famous_defs::FamousDefs, syntax_helpers::node_ext::{for_each_tail_expr, walk_expr}, }; -use itertools::Itertools; use syntax::{ - ast::{self, make, Expr, HasGenericParams}, - match_ast, ted, AstNode, ToSmolStr, + ast::{self, syntax_factory::SyntaxFactory, Expr, HasGenericArgs, HasGenericParams}, + match_ast, AstNode, }; use crate::{AssistContext, AssistId, AssistKind, Assists}; @@ -43,11 +42,11 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; pub(crate) fn wrap_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let ret_type = ctx.find_node_at_offset::()?; let parent = ret_type.syntax().parent()?; - let body = match_ast! { + let body_expr = match_ast! { match parent { - ast::Fn(func) => func.body()?, + ast::Fn(func) => func.body()?.into(), ast::ClosureExpr(closure) => match closure.body()? { - Expr::BlockExpr(block) => block, + Expr::BlockExpr(block) => block.into(), // closures require a block when a return type is specified _ => return None, }, @@ -75,56 +74,65 @@ pub(crate) fn wrap_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op kind.assist_id(), kind.label(), type_ref.syntax().text_range(), - |edit| { - let alias = wrapper_alias(ctx, &core_wrapper, type_ref, kind.symbol()); - let new_return_ty = - alias.unwrap_or_else(|| kind.wrap_type(type_ref)).clone_for_update(); - - let body = edit.make_mut(ast::Expr::BlockExpr(body.clone())); + |builder| { + let mut editor = builder.make_editor(&parent); + let make = SyntaxFactory::new(); + let alias = wrapper_alias(ctx, &make, &core_wrapper, type_ref, kind.symbol()); + let new_return_ty = alias.unwrap_or_else(|| match kind { + WrapperKind::Option => make.ty_option(type_ref.clone()), + WrapperKind::Result => make.ty_result(type_ref.clone(), make.ty_infer().into()), + }); let mut exprs_to_wrap = Vec::new(); let tail_cb = &mut |e: &_| tail_cb_impl(&mut exprs_to_wrap, e); - walk_expr(&body, &mut |expr| { + walk_expr(&body_expr, &mut |expr| { if let Expr::ReturnExpr(ret_expr) = expr { if let Some(ret_expr_arg) = &ret_expr.expr() { for_each_tail_expr(ret_expr_arg, tail_cb); } } }); - for_each_tail_expr(&body, tail_cb); + for_each_tail_expr(&body_expr, tail_cb); for ret_expr_arg in exprs_to_wrap { - let happy_wrapped = make::expr_call( - make::expr_path(make::ext::ident_path(kind.happy_ident())), - make::arg_list(iter::once(ret_expr_arg.clone())), - ) - .clone_for_update(); - ted::replace(ret_expr_arg.syntax(), happy_wrapped.syntax()); + let happy_wrapped = make.expr_call( + make.expr_path(make.ident_path(kind.happy_ident())), + make.arg_list(iter::once(ret_expr_arg.clone())), + ); + editor.replace(ret_expr_arg.syntax(), happy_wrapped.syntax()); } - let old_return_ty = edit.make_mut(type_ref.clone()); - ted::replace(old_return_ty.syntax(), new_return_ty.syntax()); + editor.replace(type_ref.syntax(), new_return_ty.syntax()); if let WrapperKind::Result = kind { // Add a placeholder snippet at the first generic argument that doesn't equal the return type. // This is normally the error type, but that may not be the case when we inserted a type alias. - let args = - new_return_ty.syntax().descendants().find_map(ast::GenericArgList::cast); - let error_type_arg = args.and_then(|list| { - list.generic_args().find(|arg| match arg { - ast::GenericArg::TypeArg(_) => { - arg.syntax().text() != type_ref.syntax().text() - } - ast::GenericArg::LifetimeArg(_) => false, - _ => true, - }) + let args = new_return_ty + .path() + .unwrap() + .segment() + .unwrap() + .generic_arg_list() + .unwrap(); + let error_type_arg = args.generic_args().find(|arg| match arg { + ast::GenericArg::TypeArg(_) => { + arg.syntax().text() != type_ref.syntax().text() + } + ast::GenericArg::LifetimeArg(_) => false, + _ => true, }); if let Some(error_type_arg) = error_type_arg { if let Some(cap) = ctx.config.snippet_cap { - edit.add_placeholder_snippet(cap, error_type_arg); + editor.add_annotation( + error_type_arg.syntax(), + builder.make_placeholder_snippet(cap), + ); } } } + + editor.add_mappings(make.finish_with_mappings()); + builder.add_file_edits(ctx.file_id(), editor); }, ); } @@ -176,22 +184,16 @@ impl WrapperKind { WrapperKind::Result => hir::sym::Result.clone(), } } - - fn wrap_type(&self, type_ref: &ast::Type) -> ast::Type { - match self { - WrapperKind::Option => make::ext::ty_option(type_ref.clone()), - WrapperKind::Result => make::ext::ty_result(type_ref.clone(), make::ty_placeholder()), - } - } } // Try to find an wrapper type alias in the current scope (shadowing the default). fn wrapper_alias( ctx: &AssistContext<'_>, + make: &SyntaxFactory, core_wrapper: &hir::Enum, ret_type: &ast::Type, wrapper: hir::Symbol, -) -> Option { +) -> Option { let wrapper_path = hir::ModPath::from_segments( hir::PathKind::Plain, iter::once(hir::Name::new_symbol_root(wrapper)), @@ -207,25 +209,28 @@ fn wrapper_alias( }) .find_map(|alias| { let mut inserted_ret_type = false; - let generic_params = alias - .source(ctx.db())? - .value - .generic_param_list()? - .generic_params() - .map(|param| match param { - // Replace the very first type parameter with the functions return type. - ast::GenericParam::TypeParam(_) if !inserted_ret_type => { - inserted_ret_type = true; - ret_type.to_smolstr() + let generic_args = + alias.source(ctx.db())?.value.generic_param_list()?.generic_params().map(|param| { + match param { + // Replace the very first type parameter with the function's return type. + ast::GenericParam::TypeParam(_) if !inserted_ret_type => { + inserted_ret_type = true; + make.type_arg(ret_type.clone()).into() + } + ast::GenericParam::LifetimeParam(_) => { + make.lifetime_arg(make.lifetime("'_")).into() + } + _ => make.type_arg(make.ty_infer().into()).into(), } - ast::GenericParam::LifetimeParam(_) => make::lifetime("'_").to_smolstr(), - _ => make::ty_placeholder().to_smolstr(), - }) - .join(", "); + }); let name = alias.name(ctx.db()); - let name = name.as_str(); - Some(make::ty(&format!("{name}<{generic_params}>"))) + let generic_arg_list = make.generic_arg_list(generic_args, false); + let path = make.path_unqualified( + make.path_segment_generics(make.name_ref(name.as_str()), generic_arg_list), + ); + + Some(make.ty_path(path)) }) }) } diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs index d62c01ba761a0..af7b3c815812d 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs @@ -1,6 +1,9 @@ //! Wrappers over [`make`] constructors use crate::{ - ast::{self, make, HasGenericArgs, HasGenericParams, HasName, HasTypeBounds, HasVisibility}, + ast::{ + self, make, HasArgList, HasGenericArgs, HasGenericParams, HasName, HasTypeBounds, + HasVisibility, + }, syntax_editor::SyntaxMappingBuilder, AstNode, NodeOrToken, SyntaxKind, SyntaxNode, SyntaxToken, }; @@ -16,6 +19,10 @@ impl SyntaxFactory { make::name_ref(name).clone_for_update() } + pub fn lifetime(&self, text: &str) -> ast::Lifetime { + make::lifetime(text).clone_for_update() + } + pub fn ty(&self, text: &str) -> ast::Type { make::ty(text).clone_for_update() } @@ -28,6 +35,20 @@ impl SyntaxFactory { ast } + pub fn ty_path(&self, path: ast::Path) -> ast::PathType { + let ast::Type::PathType(ast) = make::ty_path(path.clone()).clone_for_update() else { + unreachable!() + }; + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(path.syntax().clone(), ast.path().unwrap().syntax().clone()); + builder.finish(&mut mapping); + } + + ast + } + pub fn type_param( &self, name: ast::Name, @@ -253,6 +274,37 @@ impl SyntaxFactory { ast } + pub fn expr_call(&self, expr: ast::Expr, arg_list: ast::ArgList) -> ast::CallExpr { + // FIXME: `make::expr_call`` should return a `CallExpr`, not just an `Expr` + let ast::Expr::CallExpr(ast) = + make::expr_call(expr.clone(), arg_list.clone()).clone_for_update() + else { + unreachable!() + }; + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(expr.syntax().clone(), ast.expr().unwrap().syntax().clone()); + builder.map_node(arg_list.syntax().clone(), ast.arg_list().unwrap().syntax().clone()); + builder.finish(&mut mapping); + } + + ast + } + + pub fn arg_list(&self, args: impl IntoIterator) -> ast::ArgList { + let (args, input) = iterator_input(args); + let ast = make::arg_list(args).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax.clone()); + builder.map_children(input.into_iter(), ast.args().map(|it| it.syntax().clone())); + builder.finish(&mut mapping); + } + + ast + } + pub fn expr_ref(&self, expr: ast::Expr, exclusive: bool) -> ast::Expr { let ast::Expr::RefExpr(ast) = make::expr_ref(expr.clone(), exclusive).clone_for_update() else { @@ -428,6 +480,30 @@ impl SyntaxFactory { ast } + pub fn type_arg(&self, ty: ast::Type) -> ast::TypeArg { + let ast = make::type_arg(ty.clone()).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(ty.syntax().clone(), ast.ty().unwrap().syntax().clone()); + builder.finish(&mut mapping); + } + + ast + } + + pub fn lifetime_arg(&self, lifetime: ast::Lifetime) -> ast::LifetimeArg { + let ast = make::lifetime_arg(lifetime.clone()).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(lifetime.syntax().clone(), ast.lifetime().unwrap().syntax().clone()); + builder.finish(&mut mapping); + } + + ast + } + pub fn item_const( &self, visibility: Option, @@ -495,12 +571,17 @@ impl SyntaxFactory { ast } - pub fn turbofish_generic_arg_list( + pub fn generic_arg_list( &self, generic_args: impl IntoIterator, + is_turbo: bool, ) -> ast::GenericArgList { let (generic_args, input) = iterator_input(generic_args); - let ast = make::turbofish_generic_arg_list(generic_args.clone()).clone_for_update(); + let ast = if is_turbo { + make::turbofish_generic_arg_list(generic_args).clone_for_update() + } else { + make::generic_arg_list(generic_args).clone_for_update() + }; if let Some(mut mapping) = self.mappings() { let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); @@ -753,12 +834,31 @@ impl SyntaxFactory { // `ext` constructors impl SyntaxFactory { + pub fn ident_path(&self, ident: &str) -> ast::Path { + self.path_unqualified(self.path_segment(self.name_ref(ident))) + } + pub fn expr_unit(&self) -> ast::Expr { self.expr_tuple([]).into() } - pub fn ident_path(&self, ident: &str) -> ast::Path { - self.path_unqualified(self.path_segment(self.name_ref(ident))) + pub fn ty_option(&self, t: ast::Type) -> ast::PathType { + let generic_arg_list = self.generic_arg_list([self.type_arg(t).into()], false); + let path = self.path_unqualified( + self.path_segment_generics(self.name_ref("Option"), generic_arg_list), + ); + + self.ty_path(path) + } + + pub fn ty_result(&self, t: ast::Type, e: ast::Type) -> ast::PathType { + let generic_arg_list = + self.generic_arg_list([self.type_arg(t).into(), self.type_arg(e).into()], false); + let path = self.path_unqualified( + self.path_segment_generics(self.name_ref("Result"), generic_arg_list), + ); + + self.ty_path(path) } } From 9b6b6293340c81e6d1ee85ecc1be483262ef2a5f Mon Sep 17 00:00:00 2001 From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com> Date: Sun, 17 Nov 2024 14:03:28 -0500 Subject: [PATCH 023/115] internal: Migrate `unwrap_return_type` assist to use `SyntaxEditor` Also changes `make::expr_empty_block()` to return `ast::BlockExpr` instead of `ast::Expr` --- .../src/handlers/unwrap_return_type.rs | 126 ++++++++++-------- .../src/utils/gen_trait_fn_body.rs | 2 +- .../crates/syntax/src/ast/make.rs | 4 +- .../src/ast/syntax_factory/constructors.rs | 2 +- 4 files changed, 76 insertions(+), 58 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_return_type.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_return_type.rs index 64d5e2c9b8210..6fd46260c0ce2 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_return_type.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_return_type.rs @@ -1,11 +1,11 @@ +use either::Either; use ide_db::{ famous_defs::FamousDefs, syntax_helpers::node_ext::{for_each_tail_expr, walk_expr}, }; -use itertools::Itertools; use syntax::{ - ast::{self, Expr, HasGenericArgs}, - match_ast, AstNode, NodeOrToken, SyntaxKind, TextRange, + ast::{self, syntax_factory::SyntaxFactory, HasArgList, HasGenericArgs}, + match_ast, AstNode, NodeOrToken, SyntaxKind, }; use crate::{AssistContext, AssistId, AssistKind, Assists}; @@ -39,11 +39,11 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; pub(crate) fn unwrap_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let ret_type = ctx.find_node_at_offset::()?; let parent = ret_type.syntax().parent()?; - let body = match_ast! { + let body_expr = match_ast! { match parent { - ast::Fn(func) => func.body()?, + ast::Fn(func) => func.body()?.into(), ast::ClosureExpr(closure) => match closure.body()? { - Expr::BlockExpr(block) => block, + ast::Expr::BlockExpr(block) => block.into(), // closures require a block when a return type is specified _ => return None, }, @@ -65,72 +65,94 @@ pub(crate) fn unwrap_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> let happy_type = extract_wrapped_type(type_ref)?; acc.add(kind.assist_id(), kind.label(), type_ref.syntax().text_range(), |builder| { - let body = ast::Expr::BlockExpr(body); + let mut editor = builder.make_editor(&parent); + let make = SyntaxFactory::new(); let mut exprs_to_unwrap = Vec::new(); let tail_cb = &mut |e: &_| tail_cb_impl(&mut exprs_to_unwrap, e); - walk_expr(&body, &mut |expr| { - if let Expr::ReturnExpr(ret_expr) = expr { + walk_expr(&body_expr, &mut |expr| { + if let ast::Expr::ReturnExpr(ret_expr) = expr { if let Some(ret_expr_arg) = &ret_expr.expr() { for_each_tail_expr(ret_expr_arg, tail_cb); } } }); - for_each_tail_expr(&body, tail_cb); + for_each_tail_expr(&body_expr, tail_cb); let is_unit_type = is_unit_type(&happy_type); if is_unit_type { - let mut text_range = ret_type.syntax().text_range(); - if let Some(NodeOrToken::Token(token)) = ret_type.syntax().next_sibling_or_token() { if token.kind() == SyntaxKind::WHITESPACE { - text_range = TextRange::new(text_range.start(), token.text_range().end()); + editor.delete(token); } } - builder.delete(text_range); + editor.delete(ret_type.syntax()); } else { - builder.replace(type_ref.syntax().text_range(), happy_type.syntax().text()); + editor.replace(type_ref.syntax(), happy_type.syntax()); } - for ret_expr_arg in exprs_to_unwrap { - let ret_expr_str = ret_expr_arg.to_string(); - - let needs_replacing = match kind { - UnwrapperKind::Option => ret_expr_str.starts_with("Some("), - UnwrapperKind::Result => { - ret_expr_str.starts_with("Ok(") || ret_expr_str.starts_with("Err(") - } - }; + for tail_expr in exprs_to_unwrap { + match &tail_expr { + ast::Expr::CallExpr(call_expr) => { + let ast::Expr::PathExpr(path_expr) = call_expr.expr().unwrap() else { + continue; + }; + + let path_str = path_expr.path().unwrap().to_string(); + let needs_replacing = match kind { + UnwrapperKind::Option => path_str == "Some", + UnwrapperKind::Result => path_str == "Ok" || path_str == "Err", + }; + + if !needs_replacing { + continue; + } - if needs_replacing { - let arg_list = ret_expr_arg.syntax().children().find_map(ast::ArgList::cast); - if let Some(arg_list) = arg_list { + let arg_list = call_expr.arg_list().unwrap(); if is_unit_type { - match ret_expr_arg.syntax().prev_sibling_or_token() { - // Useful to delete the entire line without leaving trailing whitespaces - Some(whitespace) => { - let new_range = TextRange::new( - whitespace.text_range().start(), - ret_expr_arg.syntax().text_range().end(), - ); - builder.delete(new_range); + let tail_parent = tail_expr + .syntax() + .parent() + .and_then(Either::::cast) + .unwrap(); + match tail_parent { + Either::Left(ret_expr) => { + editor.replace(ret_expr.syntax(), make.expr_return(None).syntax()) } - None => { - builder.delete(ret_expr_arg.syntax().text_range()); + Either::Right(stmt_list) => { + let new_block = if stmt_list.statements().next().is_none() { + make.expr_empty_block() + } else { + make.block_expr(stmt_list.statements(), None) + }; + editor.replace( + stmt_list.syntax(), + new_block.stmt_list().unwrap().syntax(), + ); } } - } else { - builder.replace( - ret_expr_arg.syntax().text_range(), - arg_list.args().join(", "), - ); + } else if let Some(first_arg) = arg_list.args().next() { + editor.replace(tail_expr.syntax(), first_arg.syntax()); } } - } else if matches!(kind, UnwrapperKind::Option if ret_expr_str == "None") { - builder.replace(ret_expr_arg.syntax().text_range(), "()"); + ast::Expr::PathExpr(path_expr) => { + let UnwrapperKind::Option = kind else { + continue; + }; + + if path_expr.path().unwrap().to_string() != "None" { + continue; + } + + editor.replace(path_expr.syntax(), make.expr_unit().syntax()); + } + _ => (), } } + + editor.add_mappings(make.finish_with_mappings()); + builder.add_file_edits(ctx.file_id(), editor); }) } @@ -168,12 +190,12 @@ impl UnwrapperKind { fn tail_cb_impl(acc: &mut Vec, e: &ast::Expr) { match e { - Expr::BreakExpr(break_expr) => { + ast::Expr::BreakExpr(break_expr) => { if let Some(break_expr_arg) = break_expr.expr() { for_each_tail_expr(&break_expr_arg, &mut |e| tail_cb_impl(acc, e)) } } - Expr::ReturnExpr(_) => { + ast::Expr::ReturnExpr(_) => { // all return expressions have already been handled by the walk loop } e => acc.push(e.clone()), @@ -238,8 +260,7 @@ fn foo() -> Option<()$0> { } "#, r#" -fn foo() { -} +fn foo() {} "#, "Unwrap Option return type", ); @@ -254,8 +275,7 @@ fn foo() -> Option<()$0>{ } "#, r#" -fn foo() { -} +fn foo() {} "#, "Unwrap Option return type", ); @@ -1262,8 +1282,7 @@ fn foo() -> Result<(), Box> { } "#, r#" -fn foo() { -} +fn foo() {} "#, "Unwrap Result return type", ); @@ -1278,8 +1297,7 @@ fn foo() -> Result<(), Box>{ } "#, r#" -fn foo() { -} +fn foo() {} "#, "Unwrap Result return type", ); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs index a9a889acc2359..7a9bdfe1ecc24 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs @@ -599,7 +599,7 @@ fn gen_partial_ord(adt: &ast::Adt, func: &ast::Fn, trait_ref: Option) let variant_name = make::path_pat(make::ext::path_from_idents(["core", "cmp", "Ordering", "Equal"])?); let lhs = make::tuple_struct_pat(make::ext::path_from_idents(["Some"])?, [variant_name]); - arms.push(make::match_arm(lhs.into(), None, make::expr_empty_block())); + arms.push(make::match_arm(lhs.into(), None, make::expr_empty_block().into())); arms.push(make::match_arm( make::ident_pat(false, false, make::name("ord")).into(), diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs index a920fe4f359a5..dca231604fa13 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs @@ -558,8 +558,8 @@ pub fn expr_const_value(text: &str) -> ast::ConstArg { ast_from_text(&format!("trait Foo {{}}")) } -pub fn expr_empty_block() -> ast::Expr { - expr_from_text("{}") +pub fn expr_empty_block() -> ast::BlockExpr { + ast_from_text("const C: () = {};") } pub fn expr_path(path: ast::Path) -> ast::Expr { expr_from_text(&path.to_string()) diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs index af7b3c815812d..572622db544cd 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs @@ -211,7 +211,7 @@ impl SyntaxFactory { } pub fn expr_empty_block(&self) -> ast::BlockExpr { - ast::BlockExpr { syntax: make::expr_empty_block().syntax().clone_for_update() } + make::expr_empty_block().clone_for_update() } pub fn expr_tuple(&self, fields: impl IntoIterator) -> ast::TupleExpr { From 3d6c2f2ea1afaf8968b968e047b5c5447767d56a Mon Sep 17 00:00:00 2001 From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com> Date: Sun, 17 Nov 2024 14:34:05 -0500 Subject: [PATCH 024/115] minor: Use placeholders in `unwrap_return_type` --- .../src/handlers/unwrap_return_type.rs | 55 ++++++++++++++++++- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_return_type.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_return_type.rs index 6fd46260c0ce2..f647b531b7742 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_return_type.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_return_type.rs @@ -92,6 +92,7 @@ pub(crate) fn unwrap_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> editor.replace(type_ref.syntax(), happy_type.syntax()); } + let mut final_placeholder = None; for tail_expr in exprs_to_unwrap { match &tail_expr { ast::Expr::CallExpr(call_expr) => { @@ -145,12 +146,27 @@ pub(crate) fn unwrap_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> continue; } - editor.replace(path_expr.syntax(), make.expr_unit().syntax()); + let new_tail_expr = make.expr_unit(); + editor.replace(path_expr.syntax(), new_tail_expr.syntax()); + if let Some(cap) = ctx.config.snippet_cap { + editor.add_annotation( + new_tail_expr.syntax(), + builder.make_placeholder_snippet(cap), + ); + + final_placeholder = Some(new_tail_expr); + } } _ => (), } } + if let Some(cap) = ctx.config.snippet_cap { + if let Some(final_placeholder) = final_placeholder { + editor.add_annotation(final_placeholder.syntax(), builder.make_tabstop_after(cap)); + } + } + editor.add_mappings(make.finish_with_mappings()); builder.add_file_edits(ctx.file_id(), editor); }) @@ -300,7 +316,42 @@ fn foo() -> i32 { if true { 42 } else { - () + ${1:()}$0 + } +} +"#, + "Unwrap Option return type", + ); + } + + #[test] + fn unwrap_option_return_type_multi_none() { + check_assist_by_label( + unwrap_return_type, + r#" +//- minicore: option +fn foo() -> Option { + if false { + return None; + } + + if true { + Some(42) + } else { + None + } +} +"#, + r#" +fn foo() -> i32 { + if false { + return ${1:()}; + } + + if true { + 42 + } else { + ${2:()}$0 } } "#, From 13e302c3242fdbea1ea6e3204784804a01b5224a Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Thu, 9 Jan 2025 05:22:14 +0200 Subject: [PATCH 025/115] Fix actual token lookup in completion's `expand()` It should be left biased, not right biased, because when e.g. the use has typed `h` then requested completion, the `h` is what we want to find, not the next token (which might indeed be inside a macro call). I'm not sure why I wrote `right_biased()` to begin with (I remember I had a reason and not just "both should work"), I might've copied the code in `expand_and_analyze()` (which is wrong, because there it lookups on the speculative file, where right biased will always find the correct token and left biased not). This is still not perfect, because there might not be an identifier already typed then we might still end up in a macro call, but this is the best we can do. --- .../crates/ide-completion/src/context/analysis.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs index acce62a041cf2..1a5609baf9c6a 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs @@ -123,10 +123,11 @@ fn expand( ) -> Option { let _p = tracing::info_span!("CompletionContext::expand").entered(); + // Left biased since there may already be an identifier token there, and we appended to it. if !sema.might_be_inside_macro_call(&fake_ident_token) && original_file .token_at_offset(original_offset + relative_offset) - .right_biased() + .left_biased() .is_some_and(|original_token| !sema.might_be_inside_macro_call(&original_token)) { // Recursion base case. From 89a72c78fc60106b8eeba707dd82cf6eaafe41ef Mon Sep 17 00:00:00 2001 From: Chayim Refael Friedman Date: Tue, 7 Jan 2025 08:00:18 +0200 Subject: [PATCH 026/115] Make edition per-token, not per-file More correctly, *also* per-token. Because as it turns out, while the top-level edition affects parsing (I think), the per-token edition affects escaping of identifiers/keywords. --- .../rust-analyzer/crates/edition/src/lib.rs | 3 +- .../rust-analyzer/crates/hir-def/src/body.rs | 15 +- .../crates/hir-def/src/body/lower.rs | 2 +- .../crates/hir-def/src/expander.rs | 4 +- .../crates/hir-def/src/item_tree/tests.rs | 2 +- .../hir-def/src/macro_expansion_tests/mbe.rs | 30 +-- .../hir-def/src/macro_expansion_tests/mod.rs | 1 + .../src/macro_expansion_tests/proc_macros.rs | 6 +- .../crates/hir-def/src/nameres/collector.rs | 2 +- .../crates/hir-def/src/resolver.rs | 2 +- .../hir-expand/src/builtin/derive_macro.rs | 105 ++++++++--- .../crates/hir-expand/src/builtin/fn_macro.rs | 10 +- .../crates/hir-expand/src/builtin/quote.rs | 8 +- .../rust-analyzer/crates/hir-expand/src/db.rs | 37 ++-- .../crates/hir-expand/src/declarative.rs | 11 +- .../crates/hir-expand/src/files.rs | 11 +- .../crates/hir-expand/src/fixup.rs | 3 +- .../crates/hir-expand/src/hygiene.rs | 46 +++-- .../crates/hir-expand/src/mod_path.rs | 7 +- .../crates/hir-expand/src/name.rs | 11 +- .../rust-analyzer/crates/hir/src/attrs.rs | 5 +- src/tools/rust-analyzer/crates/hir/src/lib.rs | 4 +- .../rust-analyzer/crates/hir/src/semantics.rs | 7 +- .../src/handlers/no_such_field.rs | 34 ++++ src/tools/rust-analyzer/crates/mbe/src/lib.rs | 3 +- .../rust-analyzer/crates/mbe/src/tests.rs | 177 +++++++++--------- .../proc-macro-api/src/legacy_protocol/msg.rs | 20 +- .../src/server_impl/rust_analyzer_span.rs | 4 +- .../crates/proc-macro-srv/src/tests/mod.rs | 130 ++++++------- .../crates/proc-macro-srv/src/tests/utils.rs | 4 +- .../rust-analyzer/crates/span/src/hygiene.rs | 29 ++- .../rust-analyzer/crates/span/src/map.rs | 2 +- .../crates/syntax-bridge/src/lib.rs | 17 +- .../syntax-bridge/src/to_parser_input.rs | 44 +++-- 34 files changed, 480 insertions(+), 316 deletions(-) diff --git a/src/tools/rust-analyzer/crates/edition/src/lib.rs b/src/tools/rust-analyzer/crates/edition/src/lib.rs index c25d5b9557b8c..7e9c94af408c1 100644 --- a/src/tools/rust-analyzer/crates/edition/src/lib.rs +++ b/src/tools/rust-analyzer/crates/edition/src/lib.rs @@ -5,7 +5,8 @@ use std::fmt; #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(u8)] pub enum Edition { - Edition2015, + // The syntax context stuff needs the discriminants to start from 0 and be consecutive. + Edition2015 = 0, Edition2018, Edition2021, Edition2024, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/body.rs index 433a956ff9a4c..de43924930632 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body.rs @@ -15,7 +15,7 @@ use hir_expand::{name::Name, ExpandError, InFile}; use la_arena::{Arena, ArenaMap, Idx, RawIdx}; use rustc_hash::FxHashMap; use smallvec::SmallVec; -use span::{Edition, MacroFileId}; +use span::{Edition, MacroFileId, SyntaxContextData}; use syntax::{ast, AstPtr, SyntaxNodePtr}; use triomphe::Arc; use tt::TextRange; @@ -37,15 +37,22 @@ use crate::{ /// A wrapper around [`span::SyntaxContextId`] that is intended only for comparisons. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct HygieneId(pub(crate) span::SyntaxContextId); +pub struct HygieneId(span::SyntaxContextId); impl HygieneId { - pub const ROOT: Self = Self(span::SyntaxContextId::ROOT); + // The edition doesn't matter here, we only use this for comparisons and to lookup the macro. + pub const ROOT: Self = Self(span::SyntaxContextId::root(Edition::Edition2015)); - pub fn new(ctx: span::SyntaxContextId) -> Self { + pub fn new(mut ctx: span::SyntaxContextId) -> Self { + // See `Name` for why we're doing that. + ctx.remove_root_edition(); Self(ctx) } + pub(crate) fn lookup(self, db: &dyn DefDatabase) -> SyntaxContextData { + db.lookup_intern_syntax_context(self.0) + } + pub(crate) fn is_root(self) -> bool { self.0.is_root() } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs index eed9f9468fd96..71d8b8123607b 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs @@ -2460,7 +2460,7 @@ impl ExprCollector<'_> { None => HygieneId::ROOT, Some(span_map) => { let ctx = span_map.span_at(span_start).ctx; - HygieneId(self.db.lookup_intern_syntax_context(ctx).opaque_and_semitransparent) + HygieneId::new(self.db.lookup_intern_syntax_context(ctx).opaque_and_semitransparent) } } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expander.rs b/src/tools/rust-analyzer/crates/hir-def/src/expander.rs index 5315c1c6fbd34..108258d5a112f 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expander.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expander.rs @@ -10,7 +10,7 @@ use hir_expand::{ ExpandResult, HirFileId, InFile, Lookup, MacroCallId, }; use limit::Limit; -use span::SyntaxContextId; +use span::{Edition, SyntaxContextId}; use syntax::{ast, Parse}; use triomphe::Arc; @@ -60,7 +60,7 @@ impl Expander { pub fn syntax_context(&self) -> SyntaxContextId { // FIXME: - SyntaxContextId::ROOT + SyntaxContextId::root(Edition::CURRENT) } pub fn enter_expand( diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs index 0f53969d6c708..735586c049da6 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs @@ -270,7 +270,7 @@ m!(); // AstId: 2 pub macro m2 { ... } - // AstId: 3, SyntaxContext: 0, ExpandTo: Items + // AstId: 3, SyntaxContext: 2, ExpandTo: Items m!(...); "#]], ); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs index 511626b5ed910..8c5bd3b6d3696 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs @@ -35,9 +35,9 @@ macro_rules! f { }; } -struct#0:1@58..64#1# MyTraitMap2#0:2@31..42#0# {#0:1@72..73#1# - map#0:1@86..89#1#:#0:1@89..90#1# #0:1@89..90#1#::#0:1@91..93#1#std#0:1@93..96#1#::#0:1@96..98#1#collections#0:1@98..109#1#::#0:1@109..111#1#HashSet#0:1@111..118#1#<#0:1@118..119#1#(#0:1@119..120#1#)#0:1@120..121#1#>#0:1@121..122#1#,#0:1@122..123#1# -}#0:1@132..133#1# +struct#0:1@58..64#4# MyTraitMap2#0:2@31..42#2# {#0:1@72..73#4# + map#0:1@86..89#4#:#0:1@89..90#4# #0:1@89..90#4#::#0:1@91..93#4#std#0:1@93..96#4#::#0:1@96..98#4#collections#0:1@98..109#4#::#0:1@109..111#4#HashSet#0:1@111..118#4#<#0:1@118..119#4#(#0:1@119..120#4#)#0:1@120..121#4#>#0:1@121..122#4#,#0:1@122..123#4# +}#0:1@132..133#4# "#]], ); } @@ -75,12 +75,12 @@ macro_rules! f { }; } -fn#0:2@30..32#0# main#0:2@33..37#0#(#0:2@37..38#0#)#0:2@38..39#0# {#0:2@40..41#0# - 1#0:2@50..51#0#;#0:2@51..52#0# - 1.0#0:2@61..64#0#;#0:2@64..65#0# - (#0:2@74..75#0#(#0:2@75..76#0#1#0:2@76..77#0#,#0:2@77..78#0# )#0:2@78..79#0#,#0:2@79..80#0# )#0:2@80..81#0#.#0:2@81..82#0#0#0:2@82..85#0#.#0:2@82..85#0#0#0:2@82..85#0#;#0:2@85..86#0# - let#0:2@95..98#0# x#0:2@99..100#0# =#0:2@101..102#0# 1#0:2@103..104#0#;#0:2@104..105#0# -}#0:2@110..111#0# +fn#0:2@30..32#2# main#0:2@33..37#2#(#0:2@37..38#2#)#0:2@38..39#2# {#0:2@40..41#2# + 1#0:2@50..51#2#;#0:2@51..52#2# + 1.0#0:2@61..64#2#;#0:2@64..65#2# + (#0:2@74..75#2#(#0:2@75..76#2#1#0:2@76..77#2#,#0:2@77..78#2# )#0:2@78..79#2#,#0:2@79..80#2# )#0:2@80..81#2#.#0:2@81..82#2#0#0:2@82..85#2#.#0:2@82..85#2#0#0:2@82..85#2#;#0:2@85..86#2# + let#0:2@95..98#2# x#0:2@99..100#2# =#0:2@101..102#2# 1#0:2@103..104#2#;#0:2@104..105#2# +}#0:2@110..111#2# "#]], @@ -171,7 +171,7 @@ fn main(foo: ()) { } fn main(foo: ()) { - /* error: unresolved macro unresolved */"helloworld!"#0:3@236..321#0#; + /* error: unresolved macro unresolved */"helloworld!"#0:3@236..321#2#; } } @@ -197,7 +197,7 @@ macro_rules! mk_struct { #[macro_use] mod foo; -struct#1:1@59..65#1# Foo#0:2@32..35#0#(#1:1@70..71#1#u32#0:2@41..44#0#)#1:1@74..75#1#;#1:1@75..76#1# +struct#1:1@59..65#4# Foo#0:2@32..35#2#(#1:1@70..71#4#u32#0:2@41..44#2#)#1:1@74..75#4#;#1:1@75..76#4# "#]], ); } @@ -423,10 +423,10 @@ m! { foo, bar } macro_rules! m { ($($i:ident),*) => ( impl Bar { $(fn $i() {})* } ); } -impl#\1# Bar#\1# {#\1# - fn#\1# foo#\0#(#\1#)#\1# {#\1#}#\1# - fn#\1# bar#\0#(#\1#)#\1# {#\1#}#\1# -}#\1# +impl#\4# Bar#\4# {#\4# + fn#\4# foo#\2#(#\4#)#\4# {#\4#}#\4# + fn#\4# bar#\2#(#\4#)#\4# {#\4#}#\4# +}#\4# "#]], ); } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs index 5b9ffdf37beda..adcf27847205f 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs @@ -358,6 +358,7 @@ impl ProcMacroExpander for IdentityWhenValidProcMacroExpander { let (parse, _) = syntax_bridge::token_tree_to_syntax_node( subtree, syntax_bridge::TopEntryPoint::MacroItems, + &mut |_| span::Edition::CURRENT, span::Edition::CURRENT, ); if parse.errors().is_empty() { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs index c0178adc9a63a..70e3e1ed4e9cd 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs @@ -181,9 +181,9 @@ fn foo(&self) { self.0. 1; } -fn#0:1@45..47#0# foo#0:1@48..51#0#(#0:1@51..52#0#�:1@52..53#0#self#0:1@53..57#0# )#0:1@57..58#0# {#0:1@59..60#0# - self#0:1@65..69#0# .#0:1@69..70#0#0#0:1@70..71#0#.#0:1@71..72#0#1#0:1@73..74#0#;#0:1@74..75#0# -}#0:1@76..77#0#"#]], +fn#0:1@45..47#2# foo#0:1@48..51#2#(#0:1@51..52#2#�:1@52..53#2#self#0:1@53..57#2# )#0:1@57..58#2# {#0:1@59..60#2# + self#0:1@65..69#2# .#0:1@69..70#2#0#0:1@70..71#2#.#0:1@71..72#2#1#0:1@73..74#2#;#0:1@74..75#2# +}#0:1@76..77#2#"#]], ); } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs index de76257587a78..988e5e83c894c 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs @@ -74,7 +74,7 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, def_map: DefMap, tree_id: TreeI let proc_macros = if krate.is_proc_macro { db.proc_macros() - .for_crate(def_map.krate, db.syntax_context(tree_id.file_id())) + .for_crate(def_map.krate, db.syntax_context(tree_id.file_id(), krate.edition)) .unwrap_or_default() } else { Default::default() diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs index 82da57a9bb2e5..df48ce6737314 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs @@ -324,7 +324,7 @@ impl Resolver { if n_segments <= 1 { let mut hygiene_info = if !hygiene_id.is_root() { - let ctx = db.lookup_intern_syntax_context(hygiene_id.0); + let ctx = hygiene_id.lookup(db); ctx.outer_expn.map(|expansion| { let expansion = db.lookup_intern_macro_call(expansion); (ctx.parent, expansion.def) diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/derive_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/derive_macro.rs index 4510a593af4da..28b6812139446 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/derive_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/derive_macro.rs @@ -4,7 +4,7 @@ use intern::sym; use itertools::{izip, Itertools}; use parser::SyntaxKind; use rustc_hash::FxHashSet; -use span::{MacroCallId, Span, SyntaxContextId}; +use span::{Edition, MacroCallId, Span, SyntaxContextId}; use stdx::never; use syntax_bridge::DocCommentDesugarMode; use tracing::debug; @@ -33,7 +33,7 @@ macro_rules! register_builtin { } impl BuiltinDeriveExpander { - pub fn expander(&self) -> fn(Span, &tt::TopSubtree) -> ExpandResult { + pub fn expander(&self) -> fn(&dyn ExpandDatabase, Span, &tt::TopSubtree) -> ExpandResult { match *self { $( BuiltinDeriveExpander::$trait => $expand, )* } @@ -58,8 +58,8 @@ impl BuiltinDeriveExpander { tt: &tt::TopSubtree, span: Span, ) -> ExpandResult { - let span = span_with_def_site_ctxt(db, span, id); - self.expander()(span, tt) + let span = span_with_def_site_ctxt(db, span, id, Edition::CURRENT); + self.expander()(db, span, tt) } } @@ -226,8 +226,12 @@ struct AdtParam { } // FIXME: This whole thing needs a refactor. Each derive requires its special values, and the result is a mess. -fn parse_adt(tt: &tt::TopSubtree, call_site: Span) -> Result { - let (adt, tm) = to_adt_syntax(tt, call_site)?; +fn parse_adt( + db: &dyn ExpandDatabase, + tt: &tt::TopSubtree, + call_site: Span, +) -> Result { + let (adt, tm) = to_adt_syntax(db, tt, call_site)?; parse_adt_from_syntax(&adt, &tm, call_site) } @@ -382,12 +386,14 @@ fn parse_adt_from_syntax( } fn to_adt_syntax( + db: &dyn ExpandDatabase, tt: &tt::TopSubtree, call_site: Span, ) -> Result<(ast::Adt, span::SpanMap), ExpandError> { - let (parsed, tm) = syntax_bridge::token_tree_to_syntax_node( + let (parsed, tm) = crate::db::token_tree_to_syntax_node( + db, tt, - syntax_bridge::TopEntryPoint::MacroItems, + crate::ExpandTo::Items, parser::Edition::CURRENT_FIXME, ); let macro_items = ast::MacroItems::cast(parsed.syntax_node()) @@ -446,12 +452,13 @@ fn name_to_token( /// where B1, ..., BN are the bounds given by `bounds_paths`. Z is a phantom type, and /// therefore does not get bound by the derived trait. fn expand_simple_derive( + db: &dyn ExpandDatabase, invoc_span: Span, tt: &tt::TopSubtree, trait_path: tt::TopSubtree, make_trait_body: impl FnOnce(&BasicAdtInfo) -> tt::TopSubtree, ) -> ExpandResult { - let info = match parse_adt(tt, invoc_span) { + let info = match parse_adt(db, tt, invoc_span) { Ok(info) => info, Err(e) => { return ExpandResult::new( @@ -520,14 +527,22 @@ fn expand_simple_derive_with_parsed( } } -fn copy_expand(span: Span, tt: &tt::TopSubtree) -> ExpandResult { +fn copy_expand( + db: &dyn ExpandDatabase, + span: Span, + tt: &tt::TopSubtree, +) -> ExpandResult { let krate = dollar_crate(span); - expand_simple_derive(span, tt, quote! {span => #krate::marker::Copy }, |_| quote! {span =>}) + expand_simple_derive(db, span, tt, quote! {span => #krate::marker::Copy }, |_| quote! {span =>}) } -fn clone_expand(span: Span, tt: &tt::TopSubtree) -> ExpandResult { +fn clone_expand( + db: &dyn ExpandDatabase, + span: Span, + tt: &tt::TopSubtree, +) -> ExpandResult { let krate = dollar_crate(span); - expand_simple_derive(span, tt, quote! {span => #krate::clone::Clone }, |adt| { + expand_simple_derive(db, span, tt, quote! {span => #krate::clone::Clone }, |adt| { if matches!(adt.shape, AdtShape::Union) { let star = tt::Punct { char: '*', spacing: ::tt::Spacing::Alone, span }; return quote! {span => @@ -576,9 +591,13 @@ fn and_and(span: Span) -> tt::TopSubtree { quote! {span => #and& } } -fn default_expand(span: Span, tt: &tt::TopSubtree) -> ExpandResult { +fn default_expand( + db: &dyn ExpandDatabase, + span: Span, + tt: &tt::TopSubtree, +) -> ExpandResult { let krate = &dollar_crate(span); - expand_simple_derive(span, tt, quote! {span => #krate::default::Default }, |adt| { + expand_simple_derive(db, span, tt, quote! {span => #krate::default::Default }, |adt| { let body = match &adt.shape { AdtShape::Struct(fields) => { let name = &adt.name; @@ -615,9 +634,13 @@ fn default_expand(span: Span, tt: &tt::TopSubtree) -> ExpandResult ExpandResult { +fn debug_expand( + db: &dyn ExpandDatabase, + span: Span, + tt: &tt::TopSubtree, +) -> ExpandResult { let krate = &dollar_crate(span); - expand_simple_derive(span, tt, quote! {span => #krate::fmt::Debug }, |adt| { + expand_simple_derive(db, span, tt, quote! {span => #krate::fmt::Debug }, |adt| { let for_variant = |name: String, v: &VariantShape| match v { VariantShape::Struct(fields) => { let for_fields = fields.iter().map(|it| { @@ -687,9 +710,13 @@ fn debug_expand(span: Span, tt: &tt::TopSubtree) -> ExpandResult }) } -fn hash_expand(span: Span, tt: &tt::TopSubtree) -> ExpandResult { +fn hash_expand( + db: &dyn ExpandDatabase, + span: Span, + tt: &tt::TopSubtree, +) -> ExpandResult { let krate = &dollar_crate(span); - expand_simple_derive(span, tt, quote! {span => #krate::hash::Hash }, |adt| { + expand_simple_derive(db, span, tt, quote! {span => #krate::hash::Hash }, |adt| { if matches!(adt.shape, AdtShape::Union) { // FIXME: Return expand error here return quote! {span =>}; @@ -734,14 +761,22 @@ fn hash_expand(span: Span, tt: &tt::TopSubtree) -> ExpandResult }) } -fn eq_expand(span: Span, tt: &tt::TopSubtree) -> ExpandResult { +fn eq_expand( + db: &dyn ExpandDatabase, + span: Span, + tt: &tt::TopSubtree, +) -> ExpandResult { let krate = dollar_crate(span); - expand_simple_derive(span, tt, quote! {span => #krate::cmp::Eq }, |_| quote! {span =>}) + expand_simple_derive(db, span, tt, quote! {span => #krate::cmp::Eq }, |_| quote! {span =>}) } -fn partial_eq_expand(span: Span, tt: &tt::TopSubtree) -> ExpandResult { +fn partial_eq_expand( + db: &dyn ExpandDatabase, + span: Span, + tt: &tt::TopSubtree, +) -> ExpandResult { let krate = dollar_crate(span); - expand_simple_derive(span, tt, quote! {span => #krate::cmp::PartialEq }, |adt| { + expand_simple_derive(db, span, tt, quote! {span => #krate::cmp::PartialEq }, |adt| { if matches!(adt.shape, AdtShape::Union) { // FIXME: Return expand error here return quote! {span =>}; @@ -811,9 +846,13 @@ fn self_and_other_patterns( (self_patterns, other_patterns) } -fn ord_expand(span: Span, tt: &tt::TopSubtree) -> ExpandResult { +fn ord_expand( + db: &dyn ExpandDatabase, + span: Span, + tt: &tt::TopSubtree, +) -> ExpandResult { let krate = &dollar_crate(span); - expand_simple_derive(span, tt, quote! {span => #krate::cmp::Ord }, |adt| { + expand_simple_derive(db, span, tt, quote! {span => #krate::cmp::Ord }, |adt| { fn compare( krate: &tt::Ident, left: tt::TopSubtree, @@ -869,9 +908,13 @@ fn ord_expand(span: Span, tt: &tt::TopSubtree) -> ExpandResult { }) } -fn partial_ord_expand(span: Span, tt: &tt::TopSubtree) -> ExpandResult { +fn partial_ord_expand( + db: &dyn ExpandDatabase, + span: Span, + tt: &tt::TopSubtree, +) -> ExpandResult { let krate = &dollar_crate(span); - expand_simple_derive(span, tt, quote! {span => #krate::cmp::PartialOrd }, |adt| { + expand_simple_derive(db, span, tt, quote! {span => #krate::cmp::PartialOrd }, |adt| { fn compare( krate: &tt::Ident, left: tt::TopSubtree, @@ -932,8 +975,12 @@ fn partial_ord_expand(span: Span, tt: &tt::TopSubtree) -> ExpandResult ExpandResult { - let (adt, _span_map) = match to_adt_syntax(tt, span) { +fn coerce_pointee_expand( + db: &dyn ExpandDatabase, + span: Span, + tt: &tt::TopSubtree, +) -> ExpandResult { + let (adt, _span_map) = match to_adt_syntax(db, tt, span) { Ok(it) => it, Err(err) => { return ExpandResult::new(tt::TopSubtree::empty(tt::DelimSpan::from_single(span)), err); diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs index 5b06de98757f7..310ddaaf9e9e8 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs @@ -69,7 +69,7 @@ impl BuiltinFnLikeExpander { tt: &tt::TopSubtree, span: Span, ) -> ExpandResult { - let span = span_with_def_site_ctxt(db, span, id); + let span = span_with_def_site_ctxt(db, span, id, Edition::CURRENT); self.expander()(db, id, tt, span) } @@ -86,7 +86,7 @@ impl EagerExpander { tt: &tt::TopSubtree, span: Span, ) -> ExpandResult { - let span = span_with_def_site_ctxt(db, span, id); + let span = span_with_def_site_ctxt(db, span, id, Edition::CURRENT); self.expander()(db, id, tt, span) } @@ -221,7 +221,7 @@ fn assert_expand( tt: &tt::TopSubtree, span: Span, ) -> ExpandResult { - let call_site_span = span_with_call_site_ctxt(db, span, id); + let call_site_span = span_with_call_site_ctxt(db, span, id, Edition::CURRENT); let mut iter = tt.iter(); @@ -342,7 +342,7 @@ fn panic_expand( span: Span, ) -> ExpandResult { let dollar_crate = dollar_crate(span); - let call_site_span = span_with_call_site_ctxt(db, span, id); + let call_site_span = span_with_call_site_ctxt(db, span, id, Edition::CURRENT); let mac = if use_panic_2021(db, call_site_span) { sym::panic_2021.clone() @@ -373,7 +373,7 @@ fn unreachable_expand( span: Span, ) -> ExpandResult { let dollar_crate = dollar_crate(span); - let call_site_span = span_with_call_site_ctxt(db, span, id); + let call_site_span = span_with_call_site_ctxt(db, span, id, Edition::CURRENT); let mac = if use_panic_2021(db, call_site_span) { sym::unreachable_2021.clone() diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/quote.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/quote.rs index 6c1abc2620310..fcd242bb494b9 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/quote.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/quote.rs @@ -225,7 +225,7 @@ mod tests { use ::tt::IdentIsRaw; use expect_test::expect; use intern::Symbol; - use span::{SpanAnchor, SyntaxContextId, ROOT_ERASED_FILE_AST_ID}; + use span::{Edition, SpanAnchor, SyntaxContextId, ROOT_ERASED_FILE_AST_ID}; use syntax::{TextRange, TextSize}; use super::quote; @@ -239,7 +239,7 @@ mod tests { ), ast_id: ROOT_ERASED_FILE_AST_ID, }, - ctx: SyntaxContextId::ROOT, + ctx: SyntaxContextId::root(Edition::CURRENT), }; #[test] @@ -276,8 +276,8 @@ mod tests { assert_eq!(quoted.to_string(), "hello"); let t = format!("{quoted:#?}"); expect![[r#" - SUBTREE $$ 937550:0@0..0#0 937550:0@0..0#0 - IDENT hello 937550:0@0..0#0"#]] + SUBTREE $$ 937550:0@0..0#2 937550:0@0..0#2 + IDENT hello 937550:0@0..0#2"#]] .assert_eq(&t); } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs index f4e80ef9e2601..b7804f888ae78 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs @@ -5,7 +5,7 @@ use either::Either; use limit::Limit; use mbe::MatchedArmIndex; use rustc_hash::FxHashSet; -use span::{AstIdMap, EditionedFileId, Span, SyntaxContextData, SyntaxContextId}; +use span::{AstIdMap, Edition, EditionedFileId, Span, SyntaxContextData, SyntaxContextId}; use syntax::{ast, AstNode, Parse, SyntaxElement, SyntaxError, SyntaxNode, SyntaxToken, T}; use syntax_bridge::{syntax_node_to_token_tree, DocCommentDesugarMode}; use triomphe::Arc; @@ -136,12 +136,12 @@ pub trait ExpandDatabase: SourceDatabase { macro_call: MacroCallId, ) -> Option>>>; #[ra_salsa::transparent] - fn syntax_context(&self, file: HirFileId) -> SyntaxContextId; + fn syntax_context(&self, file: HirFileId, edition: Edition) -> SyntaxContextId; } -fn syntax_context(db: &dyn ExpandDatabase, file: HirFileId) -> SyntaxContextId { +fn syntax_context(db: &dyn ExpandDatabase, file: HirFileId, edition: Edition) -> SyntaxContextId { match file.repr() { - HirFileIdRepr::FileId(_) => SyntaxContextId::ROOT, + HirFileIdRepr::FileId(_) => SyntaxContextId::root(edition), HirFileIdRepr::MacroFile(m) => { db.macro_arg_considering_derives(m.macro_call_id, &m.macro_call_id.lookup(db).kind) .2 @@ -273,9 +273,9 @@ pub fn expand_speculative( loc.krate, &tt, attr_arg.as_ref(), - span_with_def_site_ctxt(db, span, actual_macro_call), - span_with_call_site_ctxt(db, span, actual_macro_call), - span_with_mixed_site_ctxt(db, span, actual_macro_call), + span_with_def_site_ctxt(db, span, actual_macro_call, loc.def.edition), + span_with_call_site_ctxt(db, span, actual_macro_call, loc.def.edition), + span_with_mixed_site_ctxt(db, span, actual_macro_call, loc.def.edition), ) } MacroDefKind::BuiltInAttr(_, it) if it.is_derive() => { @@ -300,7 +300,7 @@ pub fn expand_speculative( fixup::reverse_fixups(&mut speculative_expansion.value, &undo_info); let (node, rev_tmap) = - token_tree_to_syntax_node(&speculative_expansion.value, expand_to, loc.def.edition); + token_tree_to_syntax_node(db, &speculative_expansion.value, expand_to, loc.def.edition); let syntax_node = node.syntax_node(); let token = rev_tmap @@ -346,6 +346,7 @@ fn parse_macro_expansion( macro_expand(db, macro_file.macro_call_id, loc); let (parse, mut rev_token_map) = token_tree_to_syntax_node( + db, match &tt { CowArc::Arc(it) => it, CowArc::Owned(it) => it, @@ -699,9 +700,9 @@ fn expand_proc_macro( loc.krate, ¯o_arg, attr_arg, - span_with_def_site_ctxt(db, span, id), - span_with_call_site_ctxt(db, span, id), - span_with_mixed_site_ctxt(db, span, id), + span_with_def_site_ctxt(db, span, id, loc.def.edition), + span_with_call_site_ctxt(db, span, id, loc.def.edition), + span_with_mixed_site_ctxt(db, span, id, loc.def.edition), ) }; @@ -715,7 +716,8 @@ fn expand_proc_macro( ExpandResult { value: Arc::new(tt), err } } -fn token_tree_to_syntax_node( +pub(crate) fn token_tree_to_syntax_node( + db: &dyn ExpandDatabase, tt: &tt::TopSubtree, expand_to: ExpandTo, edition: parser::Edition, @@ -727,7 +729,12 @@ fn token_tree_to_syntax_node( ExpandTo::Type => syntax_bridge::TopEntryPoint::Type, ExpandTo::Expr => syntax_bridge::TopEntryPoint::Expr, }; - syntax_bridge::token_tree_to_syntax_node(tt, entry_point, edition) + syntax_bridge::token_tree_to_syntax_node( + tt, + entry_point, + &mut |ctx| ctx.lookup(db).edition, + edition, + ) } fn check_tt_count(tt: &tt::TopSubtree) -> Result<(), ExpandResult<()>> { @@ -751,5 +758,7 @@ fn check_tt_count(tt: &tt::TopSubtree) -> Result<(), ExpandResult<()>> { } fn setup_syntax_context_root(db: &dyn ExpandDatabase) { - db.intern_syntax_context(SyntaxContextData::root()); + for edition in Edition::iter() { + db.intern_syntax_context(SyntaxContextData::root(edition)); + } } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs b/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs index d1c39f32ca387..fef77acb7bbb7 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs @@ -2,7 +2,7 @@ use base_db::CrateId; use intern::sym; -use span::{Edition, MacroCallId, Span, SyntaxContextId}; +use span::{Edition, HirFileIdRepr, MacroCallId, Span, SyntaxContextId}; use stdx::TupleExt; use syntax::{ast, AstNode}; use syntax_bridge::DocCommentDesugarMode; @@ -20,6 +20,7 @@ use crate::{ pub struct DeclarativeMacroExpander { pub mac: mbe::DeclarativeMacro, pub transparency: Transparency, + edition: Edition, } impl DeclarativeMacroExpander { @@ -40,7 +41,7 @@ impl DeclarativeMacroExpander { .mac .expand( &tt, - |s| s.ctx = apply_mark(db, s.ctx, call_id, self.transparency), + |s| s.ctx = apply_mark(db, s.ctx, call_id, self.transparency, self.edition), span, loc.def.edition, ) @@ -159,6 +160,10 @@ impl DeclarativeMacroExpander { transparency(¯o_def).unwrap_or(Transparency::Opaque), ), }; - Arc::new(DeclarativeMacroExpander { mac, transparency }) + let edition = ctx_edition(match id.file_id.repr() { + HirFileIdRepr::MacroFile(macro_file) => macro_file.macro_call_id.lookup(db).ctxt, + HirFileIdRepr::FileId(file) => SyntaxContextId::root(file.edition()), + }); + Arc::new(DeclarativeMacroExpander { mac, transparency, edition }) } } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/files.rs b/src/tools/rust-analyzer/crates/hir-expand/src/files.rs index 8c04d054029cc..13ddb0d4acce2 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/files.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/files.rs @@ -380,14 +380,14 @@ impl InFile { ) -> (FileRange, SyntaxContextId) { match self.file_id.repr() { HirFileIdRepr::FileId(file_id) => { - (FileRange { file_id, range: self.value }, SyntaxContextId::ROOT) + (FileRange { file_id, range: self.value }, SyntaxContextId::root(file_id.edition())) } HirFileIdRepr::MacroFile(mac_file) => { match map_node_range_up(db, &db.expansion_span_map(mac_file), self.value) { Some(it) => it, None => { let loc = db.lookup_intern_macro_call(mac_file.macro_call_id); - (loc.kind.original_call_range(db), SyntaxContextId::ROOT) + (loc.kind.original_call_range(db), SyntaxContextId::root(loc.def.edition)) } } } @@ -432,9 +432,10 @@ impl InFile { db: &dyn db::ExpandDatabase, ) -> Option<(FileRange, SyntaxContextId)> { match self.file_id.repr() { - HirFileIdRepr::FileId(file_id) => { - Some((FileRange { file_id, range: self.value }, SyntaxContextId::ROOT)) - } + HirFileIdRepr::FileId(file_id) => Some(( + FileRange { file_id, range: self.value }, + SyntaxContextId::root(file_id.edition()), + )), HirFileIdRepr::MacroFile(mac_file) => { map_node_range_up(db, &db.expansion_span_map(mac_file), self.value) } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs b/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs index 90012dd1f77cc..00fad67578680 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs @@ -380,7 +380,7 @@ pub(crate) fn reverse_fixups(tt: &mut TopSubtree, undo_info: &SyntaxFixupUndoInf let span = |file_id| Span { range: TextRange::empty(TextSize::new(0)), anchor: SpanAnchor { file_id, ast_id: ROOT_ERASED_FILE_AST_ID }, - ctx: SyntaxContextId::ROOT, + ctx: SyntaxContextId::root(span::Edition::Edition2015), }; delimiter.open = span(delimiter.open.anchor.file_id); delimiter.close = span(delimiter.close.anchor.file_id); @@ -554,6 +554,7 @@ mod tests { let (parse, _) = syntax_bridge::token_tree_to_syntax_node( &tt, syntax_bridge::TopEntryPoint::MacroItems, + &mut |_| parser::Edition::CURRENT, parser::Edition::CURRENT, ); assert!( diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs b/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs index f48de807c28c7..fe05af0ac9d31 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs @@ -24,26 +24,37 @@ use std::iter; -use span::{MacroCallId, Span, SyntaxContextData, SyntaxContextId}; +use span::{Edition, MacroCallId, Span, SyntaxContextData, SyntaxContextId}; use crate::db::{ExpandDatabase, InternSyntaxContextQuery}; pub use span::Transparency; -pub fn span_with_def_site_ctxt(db: &dyn ExpandDatabase, span: Span, expn_id: MacroCallId) -> Span { - span_with_ctxt_from_mark(db, span, expn_id, Transparency::Opaque) +pub fn span_with_def_site_ctxt( + db: &dyn ExpandDatabase, + span: Span, + expn_id: MacroCallId, + edition: Edition, +) -> Span { + span_with_ctxt_from_mark(db, span, expn_id, Transparency::Opaque, edition) } -pub fn span_with_call_site_ctxt(db: &dyn ExpandDatabase, span: Span, expn_id: MacroCallId) -> Span { - span_with_ctxt_from_mark(db, span, expn_id, Transparency::Transparent) +pub fn span_with_call_site_ctxt( + db: &dyn ExpandDatabase, + span: Span, + expn_id: MacroCallId, + edition: Edition, +) -> Span { + span_with_ctxt_from_mark(db, span, expn_id, Transparency::Transparent, edition) } pub fn span_with_mixed_site_ctxt( db: &dyn ExpandDatabase, span: Span, expn_id: MacroCallId, + edition: Edition, ) -> Span { - span_with_ctxt_from_mark(db, span, expn_id, Transparency::SemiTransparent) + span_with_ctxt_from_mark(db, span, expn_id, Transparency::SemiTransparent, edition) } fn span_with_ctxt_from_mark( @@ -51,8 +62,12 @@ fn span_with_ctxt_from_mark( span: Span, expn_id: MacroCallId, transparency: Transparency, + edition: Edition, ) -> Span { - Span { ctx: apply_mark(db, SyntaxContextId::ROOT, expn_id, transparency), ..span } + Span { + ctx: apply_mark(db, SyntaxContextId::root(edition), expn_id, transparency, edition), + ..span + } } pub(super) fn apply_mark( @@ -60,9 +75,10 @@ pub(super) fn apply_mark( ctxt: SyntaxContextId, call_id: MacroCallId, transparency: Transparency, + edition: Edition, ) -> SyntaxContextId { if transparency == Transparency::Opaque { - return apply_mark_internal(db, ctxt, call_id, transparency); + return apply_mark_internal(db, ctxt, call_id, transparency, edition); } let call_site_ctxt = db.lookup_intern_macro_call(call_id).ctxt; @@ -73,7 +89,7 @@ pub(super) fn apply_mark( }; if call_site_ctxt.is_root() { - return apply_mark_internal(db, ctxt, call_id, transparency); + return apply_mark_internal(db, ctxt, call_id, transparency, edition); } // Otherwise, `expn_id` is a macros 1.0 definition and the call site is in a @@ -86,9 +102,9 @@ pub(super) fn apply_mark( // // See the example at `test/ui/hygiene/legacy_interaction.rs`. for (call_id, transparency) in ctxt.marks(db) { - call_site_ctxt = apply_mark_internal(db, call_site_ctxt, call_id, transparency); + call_site_ctxt = apply_mark_internal(db, call_site_ctxt, call_id, transparency, edition); } - apply_mark_internal(db, call_site_ctxt, call_id, transparency) + apply_mark_internal(db, call_site_ctxt, call_id, transparency, edition) } fn apply_mark_internal( @@ -96,6 +112,7 @@ fn apply_mark_internal( ctxt: SyntaxContextId, call_id: MacroCallId, transparency: Transparency, + edition: Edition, ) -> SyntaxContextId { use base_db::ra_salsa; @@ -108,13 +125,14 @@ fn apply_mark_internal( if transparency >= Transparency::Opaque { let parent = opaque; opaque = ra_salsa::plumbing::get_query_table::(db).get_or_insert( - (parent, call_id, transparency), + (parent, call_id, transparency, edition), |new_opaque| SyntaxContextData { outer_expn: call_id, outer_transparency: transparency, parent, opaque: new_opaque, opaque_and_semitransparent: new_opaque, + edition, }, ); } @@ -123,13 +141,14 @@ fn apply_mark_internal( let parent = opaque_and_semitransparent; opaque_and_semitransparent = ra_salsa::plumbing::get_query_table::(db).get_or_insert( - (parent, call_id, transparency), + (parent, call_id, transparency, edition), |new_opaque_and_semitransparent| SyntaxContextData { outer_expn: call_id, outer_transparency: transparency, parent, opaque, opaque_and_semitransparent: new_opaque_and_semitransparent, + edition, }, ); } @@ -141,6 +160,7 @@ fn apply_mark_internal( parent, opaque, opaque_and_semitransparent, + edition, }) } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs index 7ecf5219873b0..876919f3ed736 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs @@ -273,10 +273,9 @@ fn convert_path( res } } - ast::PathSegmentKind::SelfTypeKw => ModPath::from_segments( - PathKind::Plain, - Some(Name::new_symbol(sym::Self_.clone(), SyntaxContextId::ROOT)), - ), + ast::PathSegmentKind::SelfTypeKw => { + ModPath::from_segments(PathKind::Plain, Some(Name::new_symbol_root(sym::Self_.clone()))) + } ast::PathSegmentKind::CrateKw => ModPath::from_segments(PathKind::Crate, iter::empty()), ast::PathSegmentKind::SelfKw => handle_super_kw(0)?, ast::PathSegmentKind::SuperKw => handle_super_kw(1)?, diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs index 267d54583338d..54a61a096d704 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs @@ -80,11 +80,20 @@ impl Name { Name { symbol: Symbol::intern(text), ctx: () } } - pub fn new(text: &str, ctx: SyntaxContextId) -> Name { + pub fn new(text: &str, mut ctx: SyntaxContextId) -> Name { + // For comparisons etc. we remove the edition, because sometimes we search for some `Name` + // and we don't know which edition it came from. + // Can't do that for all `SyntaxContextId`s because it breaks Salsa. + ctx.remove_root_edition(); _ = ctx; Self::new_text(text) } + pub fn new_root(text: &str) -> Name { + // The edition doesn't matter for hygiene. + Self::new(text, SyntaxContextId::root(Edition::Edition2015)) + } + pub fn new_tuple_field(idx: usize) -> Name { Name { symbol: Symbol::intern(&idx.to_string()), ctx: () } } diff --git a/src/tools/rust-analyzer/crates/hir/src/attrs.rs b/src/tools/rust-analyzer/crates/hir/src/attrs.rs index a23fdf1b39345..01cb040bdfb0d 100644 --- a/src/tools/rust-analyzer/crates/hir/src/attrs.rs +++ b/src/tools/rust-analyzer/crates/hir/src/attrs.rs @@ -12,7 +12,6 @@ use hir_def::{ }; use hir_expand::{mod_path::PathKind, name::Name}; use hir_ty::{db::HirDatabase, method_resolution}; -use span::SyntaxContextId; use crate::{ Adt, AsAssocItem, AssocItem, BuiltinType, Const, ConstParam, DocLinkDef, Enum, ExternCrateDecl, @@ -328,9 +327,7 @@ fn doc_modpath_from_str(link: &str) -> Option { }; let parts = first_segment.into_iter().chain(parts).map(|segment| match segment.parse() { Ok(idx) => Name::new_tuple_field(idx), - Err(_) => { - Name::new(segment.split_once('<').map_or(segment, |it| it.0), SyntaxContextId::ROOT) - } + Err(_) => Name::new_root(segment.split_once('<').map_or(segment, |it| it.0)), }); Some(ModPath::from_segments(kind, parts)) }; diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index fe4b255d3c57e..ac109be5ef361 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -83,7 +83,7 @@ use itertools::Itertools; use nameres::diagnostics::DefDiagnosticKind; use rustc_hash::FxHashSet; use smallvec::SmallVec; -use span::{Edition, EditionedFileId, FileId, MacroCallId, SyntaxContextId}; +use span::{Edition, EditionedFileId, FileId, MacroCallId}; use stdx::{format_to, impl_from, never}; use syntax::{ ast::{self, HasAttrs as _, HasGenericParams, HasName}, @@ -4824,7 +4824,7 @@ impl Type { let iterator_trait = db.lang_item(self.env.krate, LangItem::Iterator)?.as_trait()?; let iterator_item = db .trait_data(iterator_trait) - .associated_type_by_name(&Name::new_symbol(sym::Item.clone(), SyntaxContextId::ROOT))?; + .associated_type_by_name(&Name::new_symbol_root(sym::Item.clone()))?; self.normalize_trait_assoc_type(db, &[], iterator_item.into()) } diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index 7f44f396bf366..7414735016a29 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -959,7 +959,10 @@ impl<'db> SemanticsImpl<'db> { process_expansion_for_token(&mut stack, include)?; } None => { - stack.push((file_id.into(), smallvec![(token, SyntaxContextId::ROOT)])); + stack.push(( + file_id.into(), + smallvec![(token, SyntaxContextId::root(file_id.edition()))], + )); } } @@ -1571,7 +1574,7 @@ impl<'db> SemanticsImpl<'db> { self.db.upcast(), &ModPath::from_segments( hir_def::path::PathKind::Plain, - segments.into_iter().map(|it| Name::new(&it, SyntaxContextId::ROOT)), + segments.into_iter().map(|it| Name::new_root(&it)), ), ); Some(items.iter_items().map(|(item, _)| item.into())) diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs index e5d871975b628..0f126a1a6562c 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs @@ -399,4 +399,38 @@ fn f(s@m::Struct { "#, ) } + + #[test] + fn editions_between_macros() { + check_diagnostics( + r#" +//- /edition2015.rs crate:edition2015 edition:2015 +#[macro_export] +macro_rules! pass_expr_thorough { + ($e:expr) => { $e }; +} + +//- /edition2018.rs crate:edition2018 deps:edition2015 edition:2018 +async fn bar() {} +async fn foo() { + edition2015::pass_expr_thorough!(bar().await); +} + "#, + ); + check_diagnostics( + r#" +//- /edition2018.rs crate:edition2018 edition:2018 +pub async fn bar() {} +#[macro_export] +macro_rules! make_await { + () => { async { $crate::bar().await }; }; +} + +//- /edition2015.rs crate:edition2015 deps:edition2018 edition:2015 +fn foo() { + edition2018::make_await!(); +} + "#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/mbe/src/lib.rs b/src/tools/rust-analyzer/crates/mbe/src/lib.rs index 6abf56d4b37c0..bebd29ef74700 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/lib.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/lib.rs @@ -369,7 +369,8 @@ pub fn expect_fragment<'t>( ) -> ExpandResult> { use ::parser; let buffer = tt_iter.remaining(); - let parser_input = to_parser_input(edition, buffer); + // FIXME: Pass the correct edition per token. Due to the split between mbe and hir-expand it's complicated. + let parser_input = to_parser_input(buffer, &mut |_ctx| edition); let tree_traversal = entry_point.parse(&parser_input, edition); let mut cursor = buffer.cursor(); let mut error = false; diff --git a/src/tools/rust-analyzer/crates/mbe/src/tests.rs b/src/tools/rust-analyzer/crates/mbe/src/tests.rs index e63ad113ffd23..fb68d35a4c84f 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/tests.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/tests.rs @@ -26,7 +26,7 @@ fn check_( file_id: EditionedFileId::new(FileId::from_raw(0), def_edition), ast_id: ErasedFileAstId::from_raw(0), }, - SyntaxContextId::ROOT, + SyntaxContextId::root(Edition::CURRENT), decl, ) .unwrap(); @@ -39,16 +39,20 @@ fn check_( file_id: EditionedFileId::new(FileId::from_raw(1), call_edition), ast_id: ErasedFileAstId::from_raw(0), }; - let arg_tt = - syntax_bridge::parse_to_token_tree(call_edition, call_anchor, SyntaxContextId::ROOT, arg) - .unwrap(); + let arg_tt = syntax_bridge::parse_to_token_tree( + call_edition, + call_anchor, + SyntaxContextId::root(Edition::CURRENT), + arg, + ) + .unwrap(); let res = mac.expand( &arg_tt, |_| (), Span { range: TextRange::up_to(TextSize::of(arg)), anchor: call_anchor, - ctx: SyntaxContextId::ROOT, + ctx: SyntaxContextId::root(Edition::CURRENT), }, def_edition, ); @@ -59,7 +63,12 @@ fn check_( if render_debug { format_to!(expect_res, "{:#?}\n\n", res.value.0); } - let (node, _) = syntax_bridge::token_tree_to_syntax_node(&res.value.0, parse, def_edition); + let (node, _) = syntax_bridge::token_tree_to_syntax_node( + &res.value.0, + parse, + &mut |_| def_edition, + def_edition, + ); format_to!( expect_res, "{}", @@ -106,25 +115,25 @@ fn token_mapping_smoke_test() { struct MyTraitMap2 "#, expect![[r#" - SUBTREE $$ 1:0@0..20#0 1:0@0..20#0 - IDENT struct 0:0@34..40#0 - IDENT MyTraitMap2 1:0@8..19#0 - SUBTREE {} 0:0@48..49#0 0:0@100..101#0 - IDENT map 0:0@58..61#0 - PUNCH : [alone] 0:0@61..62#0 - PUNCH : [joint] 0:0@63..64#0 - PUNCH : [alone] 0:0@64..65#0 - IDENT std 0:0@65..68#0 - PUNCH : [joint] 0:0@68..69#0 - PUNCH : [alone] 0:0@69..70#0 - IDENT collections 0:0@70..81#0 - PUNCH : [joint] 0:0@81..82#0 - PUNCH : [alone] 0:0@82..83#0 - IDENT HashSet 0:0@83..90#0 - PUNCH < [alone] 0:0@90..91#0 - SUBTREE () 0:0@91..92#0 0:0@92..93#0 - PUNCH > [joint] 0:0@93..94#0 - PUNCH , [alone] 0:0@94..95#0 + SUBTREE $$ 1:0@0..20#2 1:0@0..20#2 + IDENT struct 0:0@34..40#2 + IDENT MyTraitMap2 1:0@8..19#2 + SUBTREE {} 0:0@48..49#2 0:0@100..101#2 + IDENT map 0:0@58..61#2 + PUNCH : [alone] 0:0@61..62#2 + PUNCH : [joint] 0:0@63..64#2 + PUNCH : [alone] 0:0@64..65#2 + IDENT std 0:0@65..68#2 + PUNCH : [joint] 0:0@68..69#2 + PUNCH : [alone] 0:0@69..70#2 + IDENT collections 0:0@70..81#2 + PUNCH : [joint] 0:0@81..82#2 + PUNCH : [alone] 0:0@82..83#2 + IDENT HashSet 0:0@83..90#2 + PUNCH < [alone] 0:0@90..91#2 + SUBTREE () 0:0@91..92#2 0:0@92..93#2 + PUNCH > [joint] 0:0@93..94#2 + PUNCH , [alone] 0:0@94..95#2 struct MyTraitMap2 { map: ::std::collections::HashSet<()>, @@ -153,28 +162,28 @@ fn main() { } "#, expect![[r#" - SUBTREE $$ 1:0@0..63#0 1:0@0..63#0 - IDENT fn 1:0@1..3#0 - IDENT main 1:0@4..8#0 - SUBTREE () 1:0@8..9#0 1:0@9..10#0 - SUBTREE {} 1:0@11..12#0 1:0@61..62#0 - LITERAL Integer 1 1:0@17..18#0 - PUNCH ; [alone] 1:0@18..19#0 - LITERAL Float 1.0 1:0@24..27#0 - PUNCH ; [alone] 1:0@27..28#0 - SUBTREE () 1:0@33..34#0 1:0@39..40#0 - SUBTREE () 1:0@34..35#0 1:0@37..38#0 - LITERAL Integer 1 1:0@35..36#0 - PUNCH , [alone] 1:0@36..37#0 - PUNCH , [alone] 1:0@38..39#0 - PUNCH . [alone] 1:0@40..41#0 - LITERAL Float 0.0 1:0@41..44#0 - PUNCH ; [alone] 1:0@44..45#0 - IDENT let 1:0@50..53#0 - IDENT x 1:0@54..55#0 - PUNCH = [alone] 1:0@56..57#0 - LITERAL Integer 1 1:0@58..59#0 - PUNCH ; [alone] 1:0@59..60#0 + SUBTREE $$ 1:0@0..63#2 1:0@0..63#2 + IDENT fn 1:0@1..3#2 + IDENT main 1:0@4..8#2 + SUBTREE () 1:0@8..9#2 1:0@9..10#2 + SUBTREE {} 1:0@11..12#2 1:0@61..62#2 + LITERAL Integer 1 1:0@17..18#2 + PUNCH ; [alone] 1:0@18..19#2 + LITERAL Float 1.0 1:0@24..27#2 + PUNCH ; [alone] 1:0@27..28#2 + SUBTREE () 1:0@33..34#2 1:0@39..40#2 + SUBTREE () 1:0@34..35#2 1:0@37..38#2 + LITERAL Integer 1 1:0@35..36#2 + PUNCH , [alone] 1:0@36..37#2 + PUNCH , [alone] 1:0@38..39#2 + PUNCH . [alone] 1:0@40..41#2 + LITERAL Float 0.0 1:0@41..44#2 + PUNCH ; [alone] 1:0@44..45#2 + IDENT let 1:0@50..53#2 + IDENT x 1:0@54..55#2 + PUNCH = [alone] 1:0@56..57#2 + LITERAL Integer 1 1:0@58..59#2 + PUNCH ; [alone] 1:0@59..60#2 fn main(){ 1; @@ -200,14 +209,14 @@ fn expr_2021() { const { 1 }, "#, expect![[r#" - SUBTREE $$ 1:0@0..25#0 1:0@0..25#0 - IDENT _ 1:0@5..6#0 - PUNCH ; [joint] 0:0@36..37#0 - SUBTREE () 0:0@34..35#0 0:0@34..35#0 - IDENT const 1:0@12..17#0 - SUBTREE {} 1:0@18..19#0 1:0@22..23#0 - LITERAL Integer 1 1:0@20..21#0 - PUNCH ; [alone] 0:0@39..40#0 + SUBTREE $$ 1:0@0..25#2 1:0@0..25#2 + IDENT _ 1:0@5..6#2 + PUNCH ; [joint] 0:0@36..37#2 + SUBTREE () 0:0@34..35#2 0:0@34..35#2 + IDENT const 1:0@12..17#2 + SUBTREE {} 1:0@18..19#2 1:0@22..23#2 + LITERAL Integer 1 1:0@20..21#2 + PUNCH ; [alone] 0:0@39..40#2 _; (const { @@ -228,13 +237,13 @@ fn expr_2021() { expect![[r#" ExpandError { inner: ( - 1:0@5..6#0, + 1:0@5..6#2, NoMatchingRule, ), } - SUBTREE $$ 1:0@0..8#0 1:0@0..8#0 - PUNCH ; [alone] 0:0@39..40#0 + SUBTREE $$ 1:0@0..8#2 1:0@0..8#2 + PUNCH ; [alone] 0:0@39..40#2 ;"#]], ); @@ -252,13 +261,13 @@ fn expr_2021() { expect![[r#" ExpandError { inner: ( - 1:0@5..10#0, + 1:0@5..10#2, NoMatchingRule, ), } - SUBTREE $$ 1:0@0..18#0 1:0@0..18#0 - PUNCH ; [alone] 0:0@39..40#0 + SUBTREE $$ 1:0@0..18#2 1:0@0..18#2 + PUNCH ; [alone] 0:0@39..40#2 ;"#]], ); @@ -278,26 +287,26 @@ fn expr_2021() { break 'foo bar, "#, expect![[r#" - SUBTREE $$ 1:0@0..76#0 1:0@0..76#0 - LITERAL Integer 4 1:0@5..6#0 - PUNCH ; [joint] 0:0@41..42#0 - LITERAL Str literal 1:0@12..21#0 - PUNCH ; [joint] 0:0@41..42#0 - SUBTREE () 0:0@39..40#0 0:0@39..40#0 - IDENT funcall 1:0@27..34#0 - SUBTREE () 1:0@34..35#0 1:0@35..36#0 - PUNCH ; [joint] 0:0@41..42#0 - SUBTREE () 0:0@39..40#0 0:0@39..40#0 - IDENT future 1:0@42..48#0 - PUNCH . [alone] 1:0@48..49#0 - IDENT await 1:0@49..54#0 - PUNCH ; [joint] 0:0@41..42#0 - SUBTREE () 0:0@39..40#0 0:0@39..40#0 - IDENT break 1:0@60..65#0 - PUNCH ' [joint] 1:0@66..67#0 - IDENT foo 1:0@67..70#0 - IDENT bar 1:0@71..74#0 - PUNCH ; [alone] 0:0@44..45#0 + SUBTREE $$ 1:0@0..76#2 1:0@0..76#2 + LITERAL Integer 4 1:0@5..6#2 + PUNCH ; [joint] 0:0@41..42#2 + LITERAL Str literal 1:0@12..21#2 + PUNCH ; [joint] 0:0@41..42#2 + SUBTREE () 0:0@39..40#2 0:0@39..40#2 + IDENT funcall 1:0@27..34#2 + SUBTREE () 1:0@34..35#2 1:0@35..36#2 + PUNCH ; [joint] 0:0@41..42#2 + SUBTREE () 0:0@39..40#2 0:0@39..40#2 + IDENT future 1:0@42..48#2 + PUNCH . [alone] 1:0@48..49#2 + IDENT await 1:0@49..54#2 + PUNCH ; [joint] 0:0@41..42#2 + SUBTREE () 0:0@39..40#2 0:0@39..40#2 + IDENT break 1:0@60..65#2 + PUNCH ' [joint] 1:0@66..67#2 + IDENT foo 1:0@67..70#2 + IDENT bar 1:0@71..74#2 + PUNCH ; [alone] 0:0@44..45#2 4; "literal"; @@ -319,13 +328,13 @@ fn expr_2021() { expect![[r#" ExpandError { inner: ( - 1:0@5..6#0, + 1:0@5..6#2, NoMatchingRule, ), } - SUBTREE $$ 1:0@0..8#0 1:0@0..8#0 - PUNCH ; [alone] 0:0@44..45#0 + SUBTREE $$ 1:0@0..8#2 1:0@0..8#2 + PUNCH ; [alone] 0:0@44..45#2 ;"#]], ); diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/legacy_protocol/msg.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/legacy_protocol/msg.rs index 6ea8db9a90580..4b831e4acebb9 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/legacy_protocol/msg.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/legacy_protocol/msg.rs @@ -159,7 +159,7 @@ type ProtocolWrite = for<'o, 'msg> fn(out: &'o mut W, msg: &'msg str) #[cfg(test)] mod tests { use intern::{sym, Symbol}; - use span::{ErasedFileAstId, Span, SpanAnchor, SyntaxContextId, TextRange, TextSize}; + use span::{Edition, ErasedFileAstId, Span, SpanAnchor, SyntaxContextId, TextRange, TextSize}; use tt::{ Delimiter, DelimiterKind, Ident, Leaf, Literal, Punct, Spacing, TopSubtree, TopSubtreeBuilder, @@ -180,12 +180,12 @@ mod tests { open: Span { range: TextRange::empty(TextSize::new(0)), anchor, - ctx: SyntaxContextId::ROOT, + ctx: SyntaxContextId::root(Edition::CURRENT), }, close: Span { range: TextRange::empty(TextSize::new(19)), anchor, - ctx: SyntaxContextId::ROOT, + ctx: SyntaxContextId::root(Edition::CURRENT), }, kind: DelimiterKind::Invisible, }); @@ -196,7 +196,7 @@ mod tests { span: Span { range: TextRange::at(TextSize::new(0), TextSize::of("struct")), anchor, - ctx: SyntaxContextId::ROOT, + ctx: SyntaxContextId::root(Edition::CURRENT), }, is_raw: tt::IdentIsRaw::No, } @@ -208,7 +208,7 @@ mod tests { span: Span { range: TextRange::at(TextSize::new(5), TextSize::of("r#Foo")), anchor, - ctx: SyntaxContextId::ROOT, + ctx: SyntaxContextId::root(Edition::CURRENT), }, is_raw: tt::IdentIsRaw::Yes, } @@ -219,7 +219,7 @@ mod tests { span: Span { range: TextRange::at(TextSize::new(10), TextSize::of("\"Foo\"")), anchor, - ctx: SyntaxContextId::ROOT, + ctx: SyntaxContextId::root(Edition::CURRENT), }, kind: tt::LitKind::Str, suffix: None, @@ -229,7 +229,7 @@ mod tests { span: Span { range: TextRange::at(TextSize::new(13), TextSize::of('@')), anchor, - ctx: SyntaxContextId::ROOT, + ctx: SyntaxContextId::root(Edition::CURRENT), }, spacing: Spacing::Joint, })); @@ -238,7 +238,7 @@ mod tests { Span { range: TextRange::at(TextSize::new(14), TextSize::of('{')), anchor, - ctx: SyntaxContextId::ROOT, + ctx: SyntaxContextId::root(Edition::CURRENT), }, ); builder.push(Leaf::Literal(Literal { @@ -246,7 +246,7 @@ mod tests { span: Span { range: TextRange::at(TextSize::new(15), TextSize::of("0u32")), anchor, - ctx: SyntaxContextId::ROOT, + ctx: SyntaxContextId::root(Edition::CURRENT), }, kind: tt::LitKind::Integer, suffix: Some(sym::u32.clone()), @@ -254,7 +254,7 @@ mod tests { builder.close(Span { range: TextRange::at(TextSize::new(19), TextSize::of('}')), anchor, - ctx: SyntaxContextId::ROOT, + ctx: SyntaxContextId::root(Edition::CURRENT), }); builder.build() diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs index beaebf33300df..c7614849e015b 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs @@ -440,7 +440,7 @@ mod tests { file_id: EditionedFileId::current_edition(FileId::from_raw(0)), ast_id: span::ErasedFileAstId::from_raw(0), }, - ctx: SyntaxContextId::ROOT, + ctx: SyntaxContextId::root(span::Edition::CURRENT), }; let s = TokenStream { token_trees: vec![ @@ -482,7 +482,7 @@ mod tests { file_id: EditionedFileId::current_edition(FileId::from_raw(0)), ast_id: span::ErasedFileAstId::from_raw(0), }, - ctx: SyntaxContextId::ROOT, + ctx: SyntaxContextId::root(span::Edition::CURRENT), }; let subtree_paren_a = vec![ tt::TokenTree::Subtree(tt::Subtree { diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs index dc6e71163b2f2..15de88ea656d0 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs @@ -12,7 +12,7 @@ fn test_derive_empty() { "DeriveEmpty", r#"struct S;"#, expect!["SUBTREE $$ 1 1"], - expect!["SUBTREE $$ 42:2@0..100#0 42:2@0..100#0"], + expect!["SUBTREE $$ 42:2@0..100#2 42:2@0..100#2"], ); } @@ -29,12 +29,12 @@ fn test_derive_error() { LITERAL Str #[derive(DeriveError)] struct S ; 1 PUNCH ; [alone] 1"#]], expect![[r#" - SUBTREE $$ 42:2@0..100#0 42:2@0..100#0 - IDENT compile_error 42:2@0..100#0 - PUNCH ! [alone] 42:2@0..100#0 - SUBTREE () 42:2@0..100#0 42:2@0..100#0 - LITERAL Str #[derive(DeriveError)] struct S ; 42:2@0..100#0 - PUNCH ; [alone] 42:2@0..100#0"#]], + SUBTREE $$ 42:2@0..100#2 42:2@0..100#2 + IDENT compile_error 42:2@0..100#2 + PUNCH ! [alone] 42:2@0..100#2 + SUBTREE () 42:2@0..100#2 42:2@0..100#2 + LITERAL Str #[derive(DeriveError)] struct S ; 42:2@0..100#2 + PUNCH ; [alone] 42:2@0..100#2"#]], ); } @@ -53,14 +53,14 @@ fn test_fn_like_macro_noop() { PUNCH , [alone] 1 SUBTREE [] 1 1"#]], expect![[r#" - SUBTREE $$ 42:2@0..100#0 42:2@0..100#0 - IDENT ident 42:2@0..5#0 - PUNCH , [alone] 42:2@5..6#0 - LITERAL Integer 0 42:2@7..8#0 - PUNCH , [alone] 42:2@8..9#0 - LITERAL Integer 1 42:2@10..11#0 - PUNCH , [alone] 42:2@11..12#0 - SUBTREE [] 42:2@13..14#0 42:2@14..15#0"#]], + SUBTREE $$ 42:2@0..100#2 42:2@0..100#2 + IDENT ident 42:2@0..5#2 + PUNCH , [alone] 42:2@5..6#2 + LITERAL Integer 0 42:2@7..8#2 + PUNCH , [alone] 42:2@8..9#2 + LITERAL Integer 1 42:2@10..11#2 + PUNCH , [alone] 42:2@11..12#2 + SUBTREE [] 42:2@13..14#2 42:2@14..15#2"#]], ); } @@ -75,10 +75,10 @@ fn test_fn_like_macro_clone_ident_subtree() { PUNCH , [alone] 1 SUBTREE [] 1 1"#]], expect![[r#" - SUBTREE $$ 42:2@0..100#0 42:2@0..100#0 - IDENT ident 42:2@0..5#0 - PUNCH , [alone] 42:2@5..6#0 - SUBTREE [] 42:2@7..8#0 42:2@7..8#0"#]], + SUBTREE $$ 42:2@0..100#2 42:2@0..100#2 + IDENT ident 42:2@0..5#2 + PUNCH , [alone] 42:2@5..6#2 + SUBTREE [] 42:2@7..8#2 42:2@7..8#2"#]], ); } @@ -91,8 +91,8 @@ fn test_fn_like_macro_clone_raw_ident() { SUBTREE $$ 1 1 IDENT r#async 1"#]], expect![[r#" - SUBTREE $$ 42:2@0..100#0 42:2@0..100#0 - IDENT r#async 42:2@0..7#0"#]], + SUBTREE $$ 42:2@0..100#2 42:2@0..100#2 + IDENT r#async 42:2@0..7#2"#]], ); } @@ -105,8 +105,8 @@ fn test_fn_like_fn_like_span_join() { SUBTREE $$ 1 1 IDENT r#joined 1"#]], expect![[r#" - SUBTREE $$ 42:2@0..100#0 42:2@0..100#0 - IDENT r#joined 42:2@0..11#0"#]], + SUBTREE $$ 42:2@0..100#2 42:2@0..100#2 + IDENT r#joined 42:2@0..11#2"#]], ); } @@ -121,10 +121,10 @@ fn test_fn_like_fn_like_span_ops() { IDENT resolved_at_def_site 1 IDENT start_span 1"#]], expect![[r#" - SUBTREE $$ 42:2@0..100#0 42:2@0..100#0 - IDENT set_def_site 41:1@0..150#0 - IDENT resolved_at_def_site 42:2@13..33#0 - IDENT start_span 42:2@34..34#0"#]], + SUBTREE $$ 42:2@0..100#2 42:2@0..100#2 + IDENT set_def_site 41:1@0..150#2 + IDENT resolved_at_def_site 42:2@13..33#2 + IDENT start_span 42:2@34..34#2"#]], ); } @@ -143,14 +143,14 @@ fn test_fn_like_mk_literals() { LITERAL Integer 123i64 1 LITERAL Integer 123 1"#]], expect![[r#" - SUBTREE $$ 42:2@0..100#0 42:2@0..100#0 - LITERAL ByteStr byte_string 42:2@0..100#0 - LITERAL Char c 42:2@0..100#0 - LITERAL Str string 42:2@0..100#0 - LITERAL Float 3.14f64 42:2@0..100#0 - LITERAL Float 3.14 42:2@0..100#0 - LITERAL Integer 123i64 42:2@0..100#0 - LITERAL Integer 123 42:2@0..100#0"#]], + SUBTREE $$ 42:2@0..100#2 42:2@0..100#2 + LITERAL ByteStr byte_string 42:2@0..100#2 + LITERAL Char c 42:2@0..100#2 + LITERAL Str string 42:2@0..100#2 + LITERAL Float 3.14f64 42:2@0..100#2 + LITERAL Float 3.14 42:2@0..100#2 + LITERAL Integer 123i64 42:2@0..100#2 + LITERAL Integer 123 42:2@0..100#2"#]], ); } @@ -164,9 +164,9 @@ fn test_fn_like_mk_idents() { IDENT standard 1 IDENT r#raw 1"#]], expect![[r#" - SUBTREE $$ 42:2@0..100#0 42:2@0..100#0 - IDENT standard 42:2@0..100#0 - IDENT r#raw 42:2@0..100#0"#]], + SUBTREE $$ 42:2@0..100#2 42:2@0..100#2 + IDENT standard 42:2@0..100#2 + IDENT r#raw 42:2@0..100#2"#]], ); } @@ -198,27 +198,27 @@ fn test_fn_like_macro_clone_literals() { PUNCH , [alone] 1 LITERAL CStr null 1"#]], expect![[r#" - SUBTREE $$ 42:2@0..100#0 42:2@0..100#0 - LITERAL Integer 1u16 42:2@0..4#0 - PUNCH , [alone] 42:2@4..5#0 - LITERAL Integer 2_u32 42:2@6..11#0 - PUNCH , [alone] 42:2@11..12#0 - PUNCH - [alone] 42:2@13..14#0 - LITERAL Integer 4i64 42:2@14..18#0 - PUNCH , [alone] 42:2@18..19#0 - LITERAL Float 3.14f32 42:2@20..27#0 - PUNCH , [alone] 42:2@27..28#0 - LITERAL Str hello bridge 42:2@29..43#0 - PUNCH , [alone] 42:2@43..44#0 - LITERAL Str suffixedsuffix 42:2@45..61#0 - PUNCH , [alone] 42:2@61..62#0 - LITERAL StrRaw(2) raw 42:2@63..73#0 - PUNCH , [alone] 42:2@73..74#0 - LITERAL Char a 42:2@75..78#0 - PUNCH , [alone] 42:2@78..79#0 - LITERAL Byte b 42:2@80..84#0 - PUNCH , [alone] 42:2@84..85#0 - LITERAL CStr null 42:2@86..93#0"#]], + SUBTREE $$ 42:2@0..100#2 42:2@0..100#2 + LITERAL Integer 1u16 42:2@0..4#2 + PUNCH , [alone] 42:2@4..5#2 + LITERAL Integer 2_u32 42:2@6..11#2 + PUNCH , [alone] 42:2@11..12#2 + PUNCH - [alone] 42:2@13..14#2 + LITERAL Integer 4i64 42:2@14..18#2 + PUNCH , [alone] 42:2@18..19#2 + LITERAL Float 3.14f32 42:2@20..27#2 + PUNCH , [alone] 42:2@27..28#2 + LITERAL Str hello bridge 42:2@29..43#2 + PUNCH , [alone] 42:2@43..44#2 + LITERAL Str suffixedsuffix 42:2@45..61#2 + PUNCH , [alone] 42:2@61..62#2 + LITERAL StrRaw(2) raw 42:2@63..73#2 + PUNCH , [alone] 42:2@73..74#2 + LITERAL Char a 42:2@75..78#2 + PUNCH , [alone] 42:2@78..79#2 + LITERAL Byte b 42:2@80..84#2 + PUNCH , [alone] 42:2@84..85#2 + LITERAL CStr null 42:2@86..93#2"#]], ); } @@ -239,12 +239,12 @@ fn test_attr_macro() { LITERAL Str #[attr_error(some arguments)] mod m {} 1 PUNCH ; [alone] 1"#]], expect![[r#" - SUBTREE $$ 42:2@0..100#0 42:2@0..100#0 - IDENT compile_error 42:2@0..100#0 - PUNCH ! [alone] 42:2@0..100#0 - SUBTREE () 42:2@0..100#0 42:2@0..100#0 - LITERAL Str #[attr_error(some arguments)] mod m {} 42:2@0..100#0 - PUNCH ; [alone] 42:2@0..100#0"#]], + SUBTREE $$ 42:2@0..100#2 42:2@0..100#2 + IDENT compile_error 42:2@0..100#2 + PUNCH ! [alone] 42:2@0..100#2 + SUBTREE () 42:2@0..100#2 42:2@0..100#2 + LITERAL Str #[attr_error(some arguments)] mod m {} 42:2@0..100#2 + PUNCH ; [alone] 42:2@0..100#2"#]], ); } diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs index 37d51050f32cc..42f0a7f59b8cc 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs @@ -76,7 +76,7 @@ fn assert_expand_impl( file_id: EditionedFileId::current_edition(FileId::from_raw(41)), ast_id: ErasedFileAstId::from_raw(1), }, - ctx: SyntaxContextId::ROOT, + ctx: SyntaxContextId::root(span::Edition::CURRENT), }; let call_site = Span { range: TextRange::new(0.into(), 100.into()), @@ -84,7 +84,7 @@ fn assert_expand_impl( file_id: EditionedFileId::current_edition(FileId::from_raw(42)), ast_id: ErasedFileAstId::from_raw(2), }, - ctx: SyntaxContextId::ROOT, + ctx: SyntaxContextId::root(span::Edition::CURRENT), }; let mixed_site = call_site; diff --git a/src/tools/rust-analyzer/crates/span/src/hygiene.rs b/src/tools/rust-analyzer/crates/span/src/hygiene.rs index 87a948df550ad..6becc8e41ed00 100644 --- a/src/tools/rust-analyzer/crates/span/src/hygiene.rs +++ b/src/tools/rust-analyzer/crates/span/src/hygiene.rs @@ -26,7 +26,7 @@ use crate::InternId; #[cfg(feature = "ra-salsa")] use ra_salsa::{InternId, InternValue}; -use crate::MacroCallId; +use crate::{Edition, MacroCallId}; /// Interned [`SyntaxContextData`]. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -59,11 +59,20 @@ impl fmt::Display for SyntaxContextId { } impl SyntaxContextId { + #[inline] + pub fn remove_root_edition(&mut self) { + if self.is_root() { + *self = Self::root(Edition::Edition2015); + } + } + /// The root context, which is the parent of all other contexts. All [`FileId`]s have this context. - pub const ROOT: Self = SyntaxContextId(unsafe { InternId::new_unchecked(0) }); + pub const fn root(edition: Edition) -> Self { + SyntaxContextId(unsafe { InternId::new_unchecked(edition as u32) }) + } pub fn is_root(self) -> bool { - self == Self::ROOT + self.into_u32() <= Edition::LATEST as u32 } /// Deconstruct a `SyntaxContextId` into a raw `u32`. @@ -89,6 +98,7 @@ pub struct SyntaxContextData { // per crate. Though that is likely not a problem as `MacroCallId`s are already crate calling dependent. pub outer_expn: Option, pub outer_transparency: Transparency, + pub edition: Edition, pub parent: SyntaxContextId, /// This context, but with all transparent and semi-transparent expansions filtered away. pub opaque: SyntaxContextId, @@ -98,10 +108,10 @@ pub struct SyntaxContextData { #[cfg(feature = "ra-salsa")] impl InternValue for SyntaxContextData { - type Key = (SyntaxContextId, Option, Transparency); + type Key = (SyntaxContextId, Option, Transparency, Edition); fn into_key(&self) -> Self::Key { - (self.parent, self.outer_expn, self.outer_transparency) + (self.parent, self.outer_expn, self.outer_transparency, self.edition) } } @@ -118,13 +128,14 @@ impl std::fmt::Debug for SyntaxContextData { } impl SyntaxContextData { - pub fn root() -> Self { + pub fn root(edition: Edition) -> Self { SyntaxContextData { outer_expn: None, outer_transparency: Transparency::Opaque, - parent: SyntaxContextId::ROOT, - opaque: SyntaxContextId::ROOT, - opaque_and_semitransparent: SyntaxContextId::ROOT, + parent: SyntaxContextId::root(edition), + opaque: SyntaxContextId::root(edition), + opaque_and_semitransparent: SyntaxContextId::root(edition), + edition, } } } diff --git a/src/tools/rust-analyzer/crates/span/src/map.rs b/src/tools/rust-analyzer/crates/span/src/map.rs index 66bbce185940b..dc35de67fd8db 100644 --- a/src/tools/rust-analyzer/crates/span/src/map.rs +++ b/src/tools/rust-analyzer/crates/span/src/map.rs @@ -208,7 +208,7 @@ impl RealSpanMap { Span { range: range - offset, anchor: SpanAnchor { file_id: self.file_id, ast_id }, - ctx: SyntaxContextId::ROOT, + ctx: SyntaxContextId::root(self.file_id.edition()), } } } diff --git a/src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs b/src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs index ed8b1908d6018..19801c49e4341 100644 --- a/src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs +++ b/src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs @@ -1,6 +1,6 @@ //! Conversions between [`SyntaxNode`] and [`tt::TokenTree`]. -use std::fmt; +use std::{fmt, hash::Hash}; use intern::Symbol; use rustc_hash::{FxHashMap, FxHashSet}; @@ -58,7 +58,7 @@ pub mod dummy_test_span_utils { ), ast_id: span::ROOT_ERASED_FILE_AST_ID, }, - ctx: SyntaxContextId::ROOT, + ctx: SyntaxContextId::root(Edition::CURRENT), }; pub struct DummyTestSpanMap; @@ -74,7 +74,7 @@ pub mod dummy_test_span_utils { ), ast_id: span::ROOT_ERASED_FILE_AST_ID, }, - ctx: SyntaxContextId::ROOT, + ctx: SyntaxContextId::root(Edition::CURRENT), } } } @@ -141,15 +141,16 @@ where pub fn token_tree_to_syntax_node( tt: &tt::TopSubtree>, entry_point: parser::TopEntryPoint, - edition: parser::Edition, + span_to_edition: &mut dyn FnMut(Ctx) -> Edition, + top_edition: Edition, ) -> (Parse, SpanMap) where - SpanData: Copy + fmt::Debug, - Ctx: PartialEq, + Ctx: Copy + fmt::Debug + PartialEq + PartialEq + Eq + Hash, { let buffer = tt.view().strip_invisible(); - let parser_input = to_parser_input(edition, buffer); - let parser_output = entry_point.parse(&parser_input, edition); + let parser_input = to_parser_input(buffer, span_to_edition); + // It matters what edition we parse with even when we escape all identifiers correctly. + let parser_output = entry_point.parse(&parser_input, top_edition); let mut tree_sink = TtTreeSink::new(buffer.cursor()); for event in parser_output.iter() { match event { diff --git a/src/tools/rust-analyzer/crates/syntax-bridge/src/to_parser_input.rs b/src/tools/rust-analyzer/crates/syntax-bridge/src/to_parser_input.rs index 1bbb05f550755..0dcb2be316c38 100644 --- a/src/tools/rust-analyzer/crates/syntax-bridge/src/to_parser_input.rs +++ b/src/tools/rust-analyzer/crates/syntax-bridge/src/to_parser_input.rs @@ -2,17 +2,20 @@ //! format that works for our parser. use std::fmt; +use std::hash::Hash; -use span::Edition; +use rustc_hash::FxHashMap; +use span::{Edition, SpanData}; use syntax::{SyntaxKind, SyntaxKind::*, T}; -pub fn to_parser_input( - edition: Edition, - buffer: tt::TokenTreesView<'_, S>, +pub fn to_parser_input( + buffer: tt::TokenTreesView<'_, SpanData>, + span_to_edition: &mut dyn FnMut(Ctx) -> Edition, ) -> parser::Input { let mut res = parser::Input::default(); let mut current = buffer.cursor(); + let mut syntax_context_to_edition_cache = FxHashMap::default(); while !current.eof() { let tt = current.token_tree(); @@ -57,20 +60,25 @@ pub fn to_parser_input( res.was_joint(); } } - tt::Leaf::Ident(ident) => match ident.sym.as_str() { - "_" => res.push(T![_]), - i if i.starts_with('\'') => res.push(LIFETIME_IDENT), - _ if ident.is_raw.yes() => res.push(IDENT), - text => match SyntaxKind::from_keyword(text, edition) { - Some(kind) => res.push(kind), - None => { - let contextual_keyword = - SyntaxKind::from_contextual_keyword(text, edition) - .unwrap_or(SyntaxKind::IDENT); - res.push_ident(contextual_keyword); - } - }, - }, + tt::Leaf::Ident(ident) => { + let edition = *syntax_context_to_edition_cache + .entry(ident.span.ctx) + .or_insert_with(|| span_to_edition(ident.span.ctx)); + match ident.sym.as_str() { + "_" => res.push(T![_]), + i if i.starts_with('\'') => res.push(LIFETIME_IDENT), + _ if ident.is_raw.yes() => res.push(IDENT), + text => match SyntaxKind::from_keyword(text, edition) { + Some(kind) => res.push(kind), + None => { + let contextual_keyword = + SyntaxKind::from_contextual_keyword(text, edition) + .unwrap_or(SyntaxKind::IDENT); + res.push_ident(contextual_keyword); + } + }, + } + } tt::Leaf::Punct(punct) => { let kind = SyntaxKind::from_char(punct.char) .unwrap_or_else(|| panic!("{punct:#?} is not a valid punct")); From cd60477dc8eeb20559c5de75666e6eccd2ede134 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Thu, 9 Jan 2025 09:37:54 +0100 Subject: [PATCH 027/115] minor: Fixup macro error kinds --- src/tools/rust-analyzer/crates/hir-expand/src/lib.rs | 6 ++++-- .../crates/ide-diagnostics/src/handlers/macro_error.rs | 6 +++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs index a0c4c125db47a..2c664029f615c 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs @@ -188,6 +188,8 @@ impl fmt::Display for RenderedExpandError { impl RenderedExpandError { const GENERAL_KIND: &str = "macro-error"; + const DISABLED: &str = "proc-macro-disabled"; + const ATTR_EXP_DISABLED: &str = "attribute-expansion-disabled"; } impl ExpandErrorKind { @@ -196,12 +198,12 @@ impl ExpandErrorKind { ExpandErrorKind::ProcMacroAttrExpansionDisabled => RenderedExpandError { message: "procedural attribute macro expansion is disabled".to_owned(), error: false, - kind: "proc-macros-disabled", + kind: RenderedExpandError::ATTR_EXP_DISABLED, }, ExpandErrorKind::MacroDisabled => RenderedExpandError { message: "proc-macro is explicitly disabled".to_owned(), error: false, - kind: "proc-macro-disabled", + kind: RenderedExpandError::DISABLED, }, &ExpandErrorKind::MissingProcMacroExpander(def_crate) => { match db.proc_macros().get_error_for_crate(def_crate) { diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs index e177b72e4d435..edf656ed04947 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs @@ -4,13 +4,13 @@ use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext, Severity}; // // This diagnostic is shown for macro expansion errors. -// Diagnostic: proc-macros-disabled +// Diagnostic: attribute-expansion-disabled // -// This diagnostic is shown for proc macros where proc macros have been disabled. +// This diagnostic is shown for attribute proc macros when attribute expansions have been disabled. // Diagnostic: proc-macro-disabled // -// This diagnostic is shown for proc macros that has been specifically disabled via `rust-analyzer.procMacro.ignored`. +// This diagnostic is shown for proc macros that have been specifically disabled via `rust-analyzer.procMacro.ignored`. pub(crate) fn macro_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroError) -> Diagnostic { // Use more accurate position if available. let display_range = ctx.resolve_precise_location(&d.node, d.precise_location); From c26f175b16c1a3ce9fca0476484a3a6b5638731b Mon Sep 17 00:00:00 2001 From: duncan Date: Thu, 9 Jan 2025 16:01:08 +0000 Subject: [PATCH 028/115] Fix parsing cargo test json output by making stdout and optional field --- .../rust-analyzer/crates/rust-analyzer/src/test_runner.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/test_runner.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/test_runner.rs index 503b3ee43a127..3edfb812cf5cf 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/test_runner.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/test_runner.rs @@ -18,7 +18,11 @@ pub(crate) enum TestState { Started, Ok, Ignored, - Failed { stdout: String }, + Failed { + // the stdout field is not always present depending on cargo test flags + #[serde(skip_serializing_if = "String::is_empty", default)] + stdout: String, + }, } #[derive(Debug, Deserialize)] From 78c377f956ffb7c9d1cd5d1786f8873959681f50 Mon Sep 17 00:00:00 2001 From: Giga Bowser <45986823+Giga-Bowser@users.noreply.github.com> Date: Fri, 20 Dec 2024 19:12:04 -0500 Subject: [PATCH 029/115] Add a new and improved syntax tree viewer --- src/tools/rust-analyzer/crates/ide/src/lib.rs | 5 + .../crates/ide/src/syntax_tree.rs | 4 +- .../crates/ide/src/view_syntax_tree.rs | 226 +++++++++++++ .../rust-analyzer/src/handlers/request.rs | 10 + .../crates/rust-analyzer/src/lsp/ext.rs | 14 + .../crates/rust-analyzer/src/main_loop.rs | 1 + .../rust-analyzer/docs/dev/lsp-extensions.md | 19 +- .../rust-analyzer/editors/code/package.json | 70 ++++ .../editors/code/src/commands.ts | 33 ++ .../rust-analyzer/editors/code/src/config.ts | 4 + .../rust-analyzer/editors/code/src/ctx.ts | 69 +++- .../rust-analyzer/editors/code/src/lsp_ext.ts | 4 + .../rust-analyzer/editors/code/src/main.ts | 3 + .../editors/code/src/syntax_tree_provider.ts | 301 ++++++++++++++++++ 14 files changed, 759 insertions(+), 4 deletions(-) create mode 100644 src/tools/rust-analyzer/crates/ide/src/view_syntax_tree.rs create mode 100644 src/tools/rust-analyzer/editors/code/src/syntax_tree_provider.ts diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index 6e7c718953cc9..5cb77e6201683 100644 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs @@ -56,6 +56,7 @@ mod view_hir; mod view_item_tree; mod view_memory_layout; mod view_mir; +mod view_syntax_tree; use std::{iter, panic::UnwindSafe}; @@ -339,6 +340,10 @@ impl Analysis { self.with_db(|db| syntax_tree::syntax_tree(db, file_id, text_range)) } + pub fn view_syntax_tree(&self, file_id: FileId) -> Cancellable { + self.with_db(|db| view_syntax_tree::view_syntax_tree(db, file_id)) + } + pub fn view_hir(&self, position: FilePosition) -> Cancellable { self.with_db(|db| view_hir::view_hir(db, position)) } diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_tree.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_tree.rs index e241cb82bd5b2..86c6676f92807 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_tree.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_tree.rs @@ -4,9 +4,9 @@ use syntax::{ AstNode, NodeOrToken, SourceFile, SyntaxKind::STRING, SyntaxToken, TextRange, TextSize, }; -// Feature: Show Syntax Tree +// Feature: Show Debug Syntax Tree // -// Shows the parse tree of the current file. It exists mostly for debugging +// Shows the textual parse tree of the current file. It exists mostly for debugging // rust-analyzer itself. // // |=== diff --git a/src/tools/rust-analyzer/crates/ide/src/view_syntax_tree.rs b/src/tools/rust-analyzer/crates/ide/src/view_syntax_tree.rs new file mode 100644 index 0000000000000..b2adff0f36ab4 --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide/src/view_syntax_tree.rs @@ -0,0 +1,226 @@ +use hir::Semantics; +use ide_db::{FileId, RootDatabase}; +use span::TextRange; +use stdx::format_to; +use syntax::{ + ast::{self, IsString}, + AstNode, AstToken, NodeOrToken, SourceFile, SyntaxNode, SyntaxToken, WalkEvent, +}; + +// Feature: Show Syntax Tree +// +// Shows a tree view with the syntax tree of the current file +// +// |=== +// | Editor | Panel Name +// +// | VS Code | **Rust Syntax Tree** +// |=== +pub(crate) fn view_syntax_tree(db: &RootDatabase, file_id: FileId) -> String { + let sema = Semantics::new(db); + let parse = sema.parse_guess_edition(file_id); + syntax_node_to_json(parse.syntax(), None) +} + +fn syntax_node_to_json(node: &SyntaxNode, ctx: Option) -> String { + let mut result = String::new(); + for event in node.preorder_with_tokens() { + match event { + WalkEvent::Enter(it) => { + let kind = it.kind(); + let (text_range, inner_range_str) = match &ctx { + Some(ctx) => { + let inner_start: u32 = it.text_range().start().into(); + let inner_end: u32 = it.text_range().end().into(); + + let mut true_start = inner_start + ctx.offset; + let mut true_end = inner_end + ctx.offset; + for pos in &ctx.marker_positions { + if *pos >= inner_end { + break; + } + + // We conditionally add to true_start in case + // the marker is between the start and end. + true_start += 2 * (*pos < inner_start) as u32; + true_end += 2; + } + + let true_range = TextRange::new(true_start.into(), true_end.into()); + + ( + true_range, + format!( + r#","istart":{:?},"iend":{:?}"#, + it.text_range().start(), + it.text_range().end() + ), + ) + } + None => (it.text_range(), "".to_owned()), + }; + let start = text_range.start(); + let end = text_range.end(); + + match it { + NodeOrToken::Node(_) => { + format_to!( + result, + r#"{{"type":"Node","kind":"{kind:?}","start":{start:?},"end":{end:?}{inner_range_str},"children":["# + ); + } + NodeOrToken::Token(token) => { + let comma = if token.next_sibling_or_token().is_some() { "," } else { "" }; + match parse_rust_string(token) { + Some(parsed) => { + format_to!( + result, + r#"{{"type":"Node","kind":"{kind:?}","start":{start:?},"end":{end:?}{inner_range_str},"children":[{parsed}]}}{comma}"# + ); + } + None => format_to!( + result, + r#"{{"type":"Token","kind":"{kind:?}","start":{start:?},"end":{end:?}{inner_range_str}}}{comma}"# + ), + } + } + } + } + WalkEvent::Leave(it) => match it { + NodeOrToken::Node(node) => { + let comma = if node.next_sibling_or_token().is_some() { "," } else { "" }; + format_to!(result, "]}}{comma}") + } + NodeOrToken::Token(_) => (), + }, + } + } + + result +} + +fn parse_rust_string(token: SyntaxToken) -> Option { + let string_node = ast::String::cast(token)?; + let text = string_node.value().ok()?; + + let mut trim_result = String::new(); + let mut marker_positions = Vec::new(); + let mut skipped = 0; + let mut last_end = 0; + for (start, part) in text.match_indices("$0") { + marker_positions.push((start - skipped) as u32); + trim_result.push_str(&text[last_end..start]); + skipped += part.len(); + last_end = start + part.len(); + } + trim_result.push_str(&text[last_end..text.len()]); + + let parsed = SourceFile::parse(&trim_result, span::Edition::CURRENT); + + if !parsed.errors().is_empty() { + return None; + } + + let node: &SyntaxNode = &parsed.syntax_node(); + + if node.children().count() == 0 { + // C'mon, you should have at least one node other than SOURCE_FILE + return None; + } + + Some(syntax_node_to_json( + node, + Some(InStringCtx { + offset: string_node.text_range_between_quotes()?.start().into(), + marker_positions, + }), + )) +} + +struct InStringCtx { + offset: u32, + marker_positions: Vec, +} + +#[cfg(test)] +mod tests { + use expect_test::expect; + + use crate::fixture; + + fn check(ra_fixture: &str, expect: expect_test::Expect) { + let (analysis, file_id) = fixture::file(ra_fixture); + let syn = analysis.view_syntax_tree(file_id).unwrap(); + expect.assert_eq(&syn) + } + + #[test] + fn view_syntax_tree() { + // Basic syntax + check( + r#"fn foo() {}"#, + expect![[ + r#"{"type":"Node","kind":"SOURCE_FILE","start":0,"end":11,"children":[{"type":"Node","kind":"FN","start":0,"end":11,"children":[{"type":"Token","kind":"FN_KW","start":0,"end":2},{"type":"Token","kind":"WHITESPACE","start":2,"end":3},{"type":"Node","kind":"NAME","start":3,"end":6,"children":[{"type":"Token","kind":"IDENT","start":3,"end":6}]},{"type":"Node","kind":"PARAM_LIST","start":6,"end":8,"children":[{"type":"Token","kind":"L_PAREN","start":6,"end":7},{"type":"Token","kind":"R_PAREN","start":7,"end":8}]},{"type":"Token","kind":"WHITESPACE","start":8,"end":9},{"type":"Node","kind":"BLOCK_EXPR","start":9,"end":11,"children":[{"type":"Node","kind":"STMT_LIST","start":9,"end":11,"children":[{"type":"Token","kind":"L_CURLY","start":9,"end":10},{"type":"Token","kind":"R_CURLY","start":10,"end":11}]}]}]}]}"# + ]], + ); + + check( + r#" +fn test() { + assert!(" + fn foo() { + } + ", ""); +}"#, + expect![[ + r#"{"type":"Node","kind":"SOURCE_FILE","start":0,"end":60,"children":[{"type":"Node","kind":"FN","start":0,"end":60,"children":[{"type":"Token","kind":"FN_KW","start":0,"end":2},{"type":"Token","kind":"WHITESPACE","start":2,"end":3},{"type":"Node","kind":"NAME","start":3,"end":7,"children":[{"type":"Token","kind":"IDENT","start":3,"end":7}]},{"type":"Node","kind":"PARAM_LIST","start":7,"end":9,"children":[{"type":"Token","kind":"L_PAREN","start":7,"end":8},{"type":"Token","kind":"R_PAREN","start":8,"end":9}]},{"type":"Token","kind":"WHITESPACE","start":9,"end":10},{"type":"Node","kind":"BLOCK_EXPR","start":10,"end":60,"children":[{"type":"Node","kind":"STMT_LIST","start":10,"end":60,"children":[{"type":"Token","kind":"L_CURLY","start":10,"end":11},{"type":"Token","kind":"WHITESPACE","start":11,"end":16},{"type":"Node","kind":"EXPR_STMT","start":16,"end":58,"children":[{"type":"Node","kind":"MACRO_EXPR","start":16,"end":57,"children":[{"type":"Node","kind":"MACRO_CALL","start":16,"end":57,"children":[{"type":"Node","kind":"PATH","start":16,"end":22,"children":[{"type":"Node","kind":"PATH_SEGMENT","start":16,"end":22,"children":[{"type":"Node","kind":"NAME_REF","start":16,"end":22,"children":[{"type":"Token","kind":"IDENT","start":16,"end":22}]}]}]},{"type":"Token","kind":"BANG","start":22,"end":23},{"type":"Node","kind":"TOKEN_TREE","start":23,"end":57,"children":[{"type":"Token","kind":"L_PAREN","start":23,"end":24},{"type":"Node","kind":"STRING","start":24,"end":52,"children":[{"type":"Node","kind":"SOURCE_FILE","start":25,"end":51,"istart":0,"iend":26,"children":[{"type":"Token","kind":"WHITESPACE","start":25,"end":30,"istart":0,"iend":5},{"type":"Node","kind":"FN","start":30,"end":46,"istart":5,"iend":21,"children":[{"type":"Token","kind":"FN_KW","start":30,"end":32,"istart":5,"iend":7},{"type":"Token","kind":"WHITESPACE","start":32,"end":33,"istart":7,"iend":8},{"type":"Node","kind":"NAME","start":33,"end":36,"istart":8,"iend":11,"children":[{"type":"Token","kind":"IDENT","start":33,"end":36,"istart":8,"iend":11}]},{"type":"Node","kind":"PARAM_LIST","start":36,"end":38,"istart":11,"iend":13,"children":[{"type":"Token","kind":"L_PAREN","start":36,"end":37,"istart":11,"iend":12},{"type":"Token","kind":"R_PAREN","start":37,"end":38,"istart":12,"iend":13}]},{"type":"Token","kind":"WHITESPACE","start":38,"end":39,"istart":13,"iend":14},{"type":"Node","kind":"BLOCK_EXPR","start":39,"end":46,"istart":14,"iend":21,"children":[{"type":"Node","kind":"STMT_LIST","start":39,"end":46,"istart":14,"iend":21,"children":[{"type":"Token","kind":"L_CURLY","start":39,"end":40,"istart":14,"iend":15},{"type":"Token","kind":"WHITESPACE","start":40,"end":45,"istart":15,"iend":20},{"type":"Token","kind":"R_CURLY","start":45,"end":46,"istart":20,"iend":21}]}]}]},{"type":"Token","kind":"WHITESPACE","start":46,"end":51,"istart":21,"iend":26}]}]},{"type":"Token","kind":"COMMA","start":52,"end":53},{"type":"Token","kind":"WHITESPACE","start":53,"end":54},{"type":"Token","kind":"STRING","start":54,"end":56},{"type":"Token","kind":"R_PAREN","start":56,"end":57}]}]}]},{"type":"Token","kind":"SEMICOLON","start":57,"end":58}]},{"type":"Token","kind":"WHITESPACE","start":58,"end":59},{"type":"Token","kind":"R_CURLY","start":59,"end":60}]}]}]}]}"# + ]], + ) + } + + #[test] + fn view_syntax_tree_inside_string() { + check( + r#"fn test() { + assert!(" +$0fn foo() { +}$0 +fn bar() { +} + ", ""); +}"#, + expect![[ + r#"{"type":"Node","kind":"SOURCE_FILE","start":0,"end":65,"children":[{"type":"Node","kind":"FN","start":0,"end":65,"children":[{"type":"Token","kind":"FN_KW","start":0,"end":2},{"type":"Token","kind":"WHITESPACE","start":2,"end":3},{"type":"Node","kind":"NAME","start":3,"end":7,"children":[{"type":"Token","kind":"IDENT","start":3,"end":7}]},{"type":"Node","kind":"PARAM_LIST","start":7,"end":9,"children":[{"type":"Token","kind":"L_PAREN","start":7,"end":8},{"type":"Token","kind":"R_PAREN","start":8,"end":9}]},{"type":"Token","kind":"WHITESPACE","start":9,"end":10},{"type":"Node","kind":"BLOCK_EXPR","start":10,"end":65,"children":[{"type":"Node","kind":"STMT_LIST","start":10,"end":65,"children":[{"type":"Token","kind":"L_CURLY","start":10,"end":11},{"type":"Token","kind":"WHITESPACE","start":11,"end":16},{"type":"Node","kind":"EXPR_STMT","start":16,"end":63,"children":[{"type":"Node","kind":"MACRO_EXPR","start":16,"end":62,"children":[{"type":"Node","kind":"MACRO_CALL","start":16,"end":62,"children":[{"type":"Node","kind":"PATH","start":16,"end":22,"children":[{"type":"Node","kind":"PATH_SEGMENT","start":16,"end":22,"children":[{"type":"Node","kind":"NAME_REF","start":16,"end":22,"children":[{"type":"Token","kind":"IDENT","start":16,"end":22}]}]}]},{"type":"Token","kind":"BANG","start":22,"end":23},{"type":"Node","kind":"TOKEN_TREE","start":23,"end":62,"children":[{"type":"Token","kind":"L_PAREN","start":23,"end":24},{"type":"Node","kind":"STRING","start":24,"end":57,"children":[{"type":"Node","kind":"SOURCE_FILE","start":25,"end":56,"istart":0,"iend":31,"children":[{"type":"Token","kind":"WHITESPACE","start":25,"end":26,"istart":0,"iend":1},{"type":"Node","kind":"FN","start":26,"end":38,"istart":1,"iend":13,"children":[{"type":"Token","kind":"FN_KW","start":26,"end":28,"istart":1,"iend":3},{"type":"Token","kind":"WHITESPACE","start":28,"end":29,"istart":3,"iend":4},{"type":"Node","kind":"NAME","start":29,"end":32,"istart":4,"iend":7,"children":[{"type":"Token","kind":"IDENT","start":29,"end":32,"istart":4,"iend":7}]},{"type":"Node","kind":"PARAM_LIST","start":32,"end":34,"istart":7,"iend":9,"children":[{"type":"Token","kind":"L_PAREN","start":32,"end":33,"istart":7,"iend":8},{"type":"Token","kind":"R_PAREN","start":33,"end":34,"istart":8,"iend":9}]},{"type":"Token","kind":"WHITESPACE","start":34,"end":35,"istart":9,"iend":10},{"type":"Node","kind":"BLOCK_EXPR","start":35,"end":38,"istart":10,"iend":13,"children":[{"type":"Node","kind":"STMT_LIST","start":35,"end":38,"istart":10,"iend":13,"children":[{"type":"Token","kind":"L_CURLY","start":35,"end":36,"istart":10,"iend":11},{"type":"Token","kind":"WHITESPACE","start":36,"end":37,"istart":11,"iend":12},{"type":"Token","kind":"R_CURLY","start":37,"end":38,"istart":12,"iend":13}]}]}]},{"type":"Token","kind":"WHITESPACE","start":38,"end":39,"istart":13,"iend":14},{"type":"Node","kind":"FN","start":39,"end":51,"istart":14,"iend":26,"children":[{"type":"Token","kind":"FN_KW","start":39,"end":41,"istart":14,"iend":16},{"type":"Token","kind":"WHITESPACE","start":41,"end":42,"istart":16,"iend":17},{"type":"Node","kind":"NAME","start":42,"end":45,"istart":17,"iend":20,"children":[{"type":"Token","kind":"IDENT","start":42,"end":45,"istart":17,"iend":20}]},{"type":"Node","kind":"PARAM_LIST","start":45,"end":47,"istart":20,"iend":22,"children":[{"type":"Token","kind":"L_PAREN","start":45,"end":46,"istart":20,"iend":21},{"type":"Token","kind":"R_PAREN","start":46,"end":47,"istart":21,"iend":22}]},{"type":"Token","kind":"WHITESPACE","start":47,"end":48,"istart":22,"iend":23},{"type":"Node","kind":"BLOCK_EXPR","start":48,"end":51,"istart":23,"iend":26,"children":[{"type":"Node","kind":"STMT_LIST","start":48,"end":51,"istart":23,"iend":26,"children":[{"type":"Token","kind":"L_CURLY","start":48,"end":49,"istart":23,"iend":24},{"type":"Token","kind":"WHITESPACE","start":49,"end":50,"istart":24,"iend":25},{"type":"Token","kind":"R_CURLY","start":50,"end":51,"istart":25,"iend":26}]}]}]},{"type":"Token","kind":"WHITESPACE","start":51,"end":56,"istart":26,"iend":31}]}]},{"type":"Token","kind":"COMMA","start":57,"end":58},{"type":"Token","kind":"WHITESPACE","start":58,"end":59},{"type":"Token","kind":"STRING","start":59,"end":61},{"type":"Token","kind":"R_PAREN","start":61,"end":62}]}]}]},{"type":"Token","kind":"SEMICOLON","start":62,"end":63}]},{"type":"Token","kind":"WHITESPACE","start":63,"end":64},{"type":"Token","kind":"R_CURLY","start":64,"end":65}]}]}]}]}"# + ]], + ); + + // With a raw string + check( + r###"fn test() { + assert!(r#" +$0fn foo() { +}$0 +fn bar() { +} + "#, ""); +}"###, + expect![[ + r#"{"type":"Node","kind":"SOURCE_FILE","start":0,"end":68,"children":[{"type":"Node","kind":"FN","start":0,"end":68,"children":[{"type":"Token","kind":"FN_KW","start":0,"end":2},{"type":"Token","kind":"WHITESPACE","start":2,"end":3},{"type":"Node","kind":"NAME","start":3,"end":7,"children":[{"type":"Token","kind":"IDENT","start":3,"end":7}]},{"type":"Node","kind":"PARAM_LIST","start":7,"end":9,"children":[{"type":"Token","kind":"L_PAREN","start":7,"end":8},{"type":"Token","kind":"R_PAREN","start":8,"end":9}]},{"type":"Token","kind":"WHITESPACE","start":9,"end":10},{"type":"Node","kind":"BLOCK_EXPR","start":10,"end":68,"children":[{"type":"Node","kind":"STMT_LIST","start":10,"end":68,"children":[{"type":"Token","kind":"L_CURLY","start":10,"end":11},{"type":"Token","kind":"WHITESPACE","start":11,"end":16},{"type":"Node","kind":"EXPR_STMT","start":16,"end":66,"children":[{"type":"Node","kind":"MACRO_EXPR","start":16,"end":65,"children":[{"type":"Node","kind":"MACRO_CALL","start":16,"end":65,"children":[{"type":"Node","kind":"PATH","start":16,"end":22,"children":[{"type":"Node","kind":"PATH_SEGMENT","start":16,"end":22,"children":[{"type":"Node","kind":"NAME_REF","start":16,"end":22,"children":[{"type":"Token","kind":"IDENT","start":16,"end":22}]}]}]},{"type":"Token","kind":"BANG","start":22,"end":23},{"type":"Node","kind":"TOKEN_TREE","start":23,"end":65,"children":[{"type":"Token","kind":"L_PAREN","start":23,"end":24},{"type":"Node","kind":"STRING","start":24,"end":60,"children":[{"type":"Node","kind":"SOURCE_FILE","start":27,"end":58,"istart":0,"iend":31,"children":[{"type":"Token","kind":"WHITESPACE","start":27,"end":28,"istart":0,"iend":1},{"type":"Node","kind":"FN","start":28,"end":40,"istart":1,"iend":13,"children":[{"type":"Token","kind":"FN_KW","start":28,"end":30,"istart":1,"iend":3},{"type":"Token","kind":"WHITESPACE","start":30,"end":31,"istart":3,"iend":4},{"type":"Node","kind":"NAME","start":31,"end":34,"istart":4,"iend":7,"children":[{"type":"Token","kind":"IDENT","start":31,"end":34,"istart":4,"iend":7}]},{"type":"Node","kind":"PARAM_LIST","start":34,"end":36,"istart":7,"iend":9,"children":[{"type":"Token","kind":"L_PAREN","start":34,"end":35,"istart":7,"iend":8},{"type":"Token","kind":"R_PAREN","start":35,"end":36,"istart":8,"iend":9}]},{"type":"Token","kind":"WHITESPACE","start":36,"end":37,"istart":9,"iend":10},{"type":"Node","kind":"BLOCK_EXPR","start":37,"end":40,"istart":10,"iend":13,"children":[{"type":"Node","kind":"STMT_LIST","start":37,"end":40,"istart":10,"iend":13,"children":[{"type":"Token","kind":"L_CURLY","start":37,"end":38,"istart":10,"iend":11},{"type":"Token","kind":"WHITESPACE","start":38,"end":39,"istart":11,"iend":12},{"type":"Token","kind":"R_CURLY","start":39,"end":40,"istart":12,"iend":13}]}]}]},{"type":"Token","kind":"WHITESPACE","start":40,"end":41,"istart":13,"iend":14},{"type":"Node","kind":"FN","start":41,"end":53,"istart":14,"iend":26,"children":[{"type":"Token","kind":"FN_KW","start":41,"end":43,"istart":14,"iend":16},{"type":"Token","kind":"WHITESPACE","start":43,"end":44,"istart":16,"iend":17},{"type":"Node","kind":"NAME","start":44,"end":47,"istart":17,"iend":20,"children":[{"type":"Token","kind":"IDENT","start":44,"end":47,"istart":17,"iend":20}]},{"type":"Node","kind":"PARAM_LIST","start":47,"end":49,"istart":20,"iend":22,"children":[{"type":"Token","kind":"L_PAREN","start":47,"end":48,"istart":20,"iend":21},{"type":"Token","kind":"R_PAREN","start":48,"end":49,"istart":21,"iend":22}]},{"type":"Token","kind":"WHITESPACE","start":49,"end":50,"istart":22,"iend":23},{"type":"Node","kind":"BLOCK_EXPR","start":50,"end":53,"istart":23,"iend":26,"children":[{"type":"Node","kind":"STMT_LIST","start":50,"end":53,"istart":23,"iend":26,"children":[{"type":"Token","kind":"L_CURLY","start":50,"end":51,"istart":23,"iend":24},{"type":"Token","kind":"WHITESPACE","start":51,"end":52,"istart":24,"iend":25},{"type":"Token","kind":"R_CURLY","start":52,"end":53,"istart":25,"iend":26}]}]}]},{"type":"Token","kind":"WHITESPACE","start":53,"end":58,"istart":26,"iend":31}]}]},{"type":"Token","kind":"COMMA","start":60,"end":61},{"type":"Token","kind":"WHITESPACE","start":61,"end":62},{"type":"Token","kind":"STRING","start":62,"end":64},{"type":"Token","kind":"R_PAREN","start":64,"end":65}]}]}]},{"type":"Token","kind":"SEMICOLON","start":65,"end":66}]},{"type":"Token","kind":"WHITESPACE","start":66,"end":67},{"type":"Token","kind":"R_CURLY","start":67,"end":68}]}]}]}]}"# + ]], + ); + + // With a raw string + check( + r###"fn test() { + assert!(r$0#" +fn foo() { +} +fn bar() { +}"$0#, ""); +}"###, + expect![[ + r#"{"type":"Node","kind":"SOURCE_FILE","start":0,"end":63,"children":[{"type":"Node","kind":"FN","start":0,"end":63,"children":[{"type":"Token","kind":"FN_KW","start":0,"end":2},{"type":"Token","kind":"WHITESPACE","start":2,"end":3},{"type":"Node","kind":"NAME","start":3,"end":7,"children":[{"type":"Token","kind":"IDENT","start":3,"end":7}]},{"type":"Node","kind":"PARAM_LIST","start":7,"end":9,"children":[{"type":"Token","kind":"L_PAREN","start":7,"end":8},{"type":"Token","kind":"R_PAREN","start":8,"end":9}]},{"type":"Token","kind":"WHITESPACE","start":9,"end":10},{"type":"Node","kind":"BLOCK_EXPR","start":10,"end":63,"children":[{"type":"Node","kind":"STMT_LIST","start":10,"end":63,"children":[{"type":"Token","kind":"L_CURLY","start":10,"end":11},{"type":"Token","kind":"WHITESPACE","start":11,"end":16},{"type":"Node","kind":"EXPR_STMT","start":16,"end":61,"children":[{"type":"Node","kind":"MACRO_EXPR","start":16,"end":60,"children":[{"type":"Node","kind":"MACRO_CALL","start":16,"end":60,"children":[{"type":"Node","kind":"PATH","start":16,"end":22,"children":[{"type":"Node","kind":"PATH_SEGMENT","start":16,"end":22,"children":[{"type":"Node","kind":"NAME_REF","start":16,"end":22,"children":[{"type":"Token","kind":"IDENT","start":16,"end":22}]}]}]},{"type":"Token","kind":"BANG","start":22,"end":23},{"type":"Node","kind":"TOKEN_TREE","start":23,"end":60,"children":[{"type":"Token","kind":"L_PAREN","start":23,"end":24},{"type":"Node","kind":"STRING","start":24,"end":55,"children":[{"type":"Node","kind":"SOURCE_FILE","start":27,"end":53,"istart":0,"iend":26,"children":[{"type":"Token","kind":"WHITESPACE","start":27,"end":28,"istart":0,"iend":1},{"type":"Node","kind":"FN","start":28,"end":40,"istart":1,"iend":13,"children":[{"type":"Token","kind":"FN_KW","start":28,"end":30,"istart":1,"iend":3},{"type":"Token","kind":"WHITESPACE","start":30,"end":31,"istart":3,"iend":4},{"type":"Node","kind":"NAME","start":31,"end":34,"istart":4,"iend":7,"children":[{"type":"Token","kind":"IDENT","start":31,"end":34,"istart":4,"iend":7}]},{"type":"Node","kind":"PARAM_LIST","start":34,"end":36,"istart":7,"iend":9,"children":[{"type":"Token","kind":"L_PAREN","start":34,"end":35,"istart":7,"iend":8},{"type":"Token","kind":"R_PAREN","start":35,"end":36,"istart":8,"iend":9}]},{"type":"Token","kind":"WHITESPACE","start":36,"end":37,"istart":9,"iend":10},{"type":"Node","kind":"BLOCK_EXPR","start":37,"end":40,"istart":10,"iend":13,"children":[{"type":"Node","kind":"STMT_LIST","start":37,"end":40,"istart":10,"iend":13,"children":[{"type":"Token","kind":"L_CURLY","start":37,"end":38,"istart":10,"iend":11},{"type":"Token","kind":"WHITESPACE","start":38,"end":39,"istart":11,"iend":12},{"type":"Token","kind":"R_CURLY","start":39,"end":40,"istart":12,"iend":13}]}]}]},{"type":"Token","kind":"WHITESPACE","start":40,"end":41,"istart":13,"iend":14},{"type":"Node","kind":"FN","start":41,"end":53,"istart":14,"iend":26,"children":[{"type":"Token","kind":"FN_KW","start":41,"end":43,"istart":14,"iend":16},{"type":"Token","kind":"WHITESPACE","start":43,"end":44,"istart":16,"iend":17},{"type":"Node","kind":"NAME","start":44,"end":47,"istart":17,"iend":20,"children":[{"type":"Token","kind":"IDENT","start":44,"end":47,"istart":17,"iend":20}]},{"type":"Node","kind":"PARAM_LIST","start":47,"end":49,"istart":20,"iend":22,"children":[{"type":"Token","kind":"L_PAREN","start":47,"end":48,"istart":20,"iend":21},{"type":"Token","kind":"R_PAREN","start":48,"end":49,"istart":21,"iend":22}]},{"type":"Token","kind":"WHITESPACE","start":49,"end":50,"istart":22,"iend":23},{"type":"Node","kind":"BLOCK_EXPR","start":50,"end":53,"istart":23,"iend":26,"children":[{"type":"Node","kind":"STMT_LIST","start":50,"end":53,"istart":23,"iend":26,"children":[{"type":"Token","kind":"L_CURLY","start":50,"end":51,"istart":23,"iend":24},{"type":"Token","kind":"WHITESPACE","start":51,"end":52,"istart":24,"iend":25},{"type":"Token","kind":"R_CURLY","start":52,"end":53,"istart":25,"iend":26}]}]}]}]}]},{"type":"Token","kind":"COMMA","start":55,"end":56},{"type":"Token","kind":"WHITESPACE","start":56,"end":57},{"type":"Token","kind":"STRING","start":57,"end":59},{"type":"Token","kind":"R_PAREN","start":59,"end":60}]}]}]},{"type":"Token","kind":"SEMICOLON","start":60,"end":61}]},{"type":"Token","kind":"WHITESPACE","start":61,"end":62},{"type":"Token","kind":"R_CURLY","start":62,"end":63}]}]}]}]}"# + ]], + ); + } +} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs index 7ac70efe2d6eb..4644ebd44d738 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs @@ -148,6 +148,16 @@ pub(crate) fn handle_syntax_tree( Ok(res) } +pub(crate) fn handle_view_syntax_tree( + snap: GlobalStateSnapshot, + params: lsp_ext::ViewSyntaxTreeParams, +) -> anyhow::Result { + let _p = tracing::info_span!("handle_view_syntax_tree").entered(); + let id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; + let res = snap.analysis.view_syntax_tree(id)?; + Ok(res) +} + pub(crate) fn handle_view_hir( snap: GlobalStateSnapshot, params: lsp_types::TextDocumentPositionParams, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs index f50cbba7acfe2..48c2ff0a15381 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs @@ -123,6 +123,20 @@ pub struct SyntaxTreeParams { pub range: Option, } +pub enum ViewSyntaxTree {} + +impl Request for ViewSyntaxTree { + type Params = ViewSyntaxTreeParams; + type Result = String; + const METHOD: &'static str = "rust-analyzer/viewSyntaxTree"; +} + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct ViewSyntaxTreeParams { + pub text_document: TextDocumentIdentifier, +} + pub enum ViewHir {} impl Request for ViewHir { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs index 97657b9265830..325b0afc71436 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs @@ -1146,6 +1146,7 @@ impl GlobalState { .on::(handlers::handle_ssr) .on::(handlers::handle_view_recursive_memory_layout) .on::(handlers::handle_syntax_tree) + .on::(handlers::handle_view_syntax_tree) .on::(handlers::handle_view_hir) .on::(handlers::handle_view_mir) .on::(handlers::handle_interpret_function) diff --git a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md index 21ac3a5a26939..8cd042277380c 100644 --- a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md +++ b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md @@ -1,5 +1,5 @@