From e903fd0d9726dc6343a26ddeb919099fb8e4979e Mon Sep 17 00:00:00 2001 From: Hannes De Valkeneer Date: Mon, 9 Mar 2020 22:06:45 +0100 Subject: feat: add debug code lens Refs #3539 --- crates/rust-analyzer/src/cargo_target_spec.rs | 42 ++++++++++++-------------- crates/rust-analyzer/src/main_loop/handlers.rs | 21 +++++++++++-- crates/rust-analyzer/src/req.rs | 1 + crates/rust-analyzer/tests/heavy_tests/main.rs | 8 +++-- editors/code/package.json | 3 ++ editors/code/src/commands/runnables.ts | 28 ++++++++++++++++- editors/code/src/main.ts | 1 + editors/code/src/rust-analyzer-api.ts | 3 +- 8 files changed, 77 insertions(+), 30 deletions(-) diff --git a/crates/rust-analyzer/src/cargo_target_spec.rs b/crates/rust-analyzer/src/cargo_target_spec.rs index 53751aafb..321861b16 100644 --- a/crates/rust-analyzer/src/cargo_target_spec.rs +++ b/crates/rust-analyzer/src/cargo_target_spec.rs @@ -19,50 +19,48 @@ impl CargoTargetSpec { pub(crate) fn runnable_args( spec: Option, kind: &RunnableKind, - ) -> Result> { - let mut res = Vec::new(); + ) -> Result<(Vec, Vec)> { + let mut args = Vec::new(); + let mut extra_args = Vec::new(); match kind { RunnableKind::Test { test_id } => { - res.push("test".to_string()); + args.push("test".to_string()); if let Some(spec) = spec { - spec.push_to(&mut res); + spec.push_to(&mut args); } - res.push("--".to_string()); - res.push(test_id.to_string()); + extra_args.push(test_id.to_string()); if let TestId::Path(_) = test_id { - res.push("--exact".to_string()); + extra_args.push("--exact".to_string()); } - res.push("--nocapture".to_string()); + extra_args.push("--nocapture".to_string()); } RunnableKind::TestMod { path } => { - res.push("test".to_string()); + args.push("test".to_string()); if let Some(spec) = spec { - spec.push_to(&mut res); + spec.push_to(&mut args); } - res.push("--".to_string()); - res.push(path.to_string()); - res.push("--nocapture".to_string()); + extra_args.push(path.to_string()); + extra_args.push("--nocapture".to_string()); } RunnableKind::Bench { test_id } => { - res.push("bench".to_string()); + args.push("bench".to_string()); if let Some(spec) = spec { - spec.push_to(&mut res); + spec.push_to(&mut args); } - res.push("--".to_string()); - res.push(test_id.to_string()); + extra_args.push(test_id.to_string()); if let TestId::Path(_) = test_id { - res.push("--exact".to_string()); + extra_args.push("--exact".to_string()); } - res.push("--nocapture".to_string()); + extra_args.push("--nocapture".to_string()); } RunnableKind::Bin => { - res.push("run".to_string()); + args.push("run".to_string()); if let Some(spec) = spec { - spec.push_to(&mut res); + spec.push_to(&mut args); } } } - Ok(res) + Ok((args, extra_args)) } pub(crate) fn for_file( diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs index fcb40432d..044273333 100644 --- a/crates/rust-analyzer/src/main_loop/handlers.rs +++ b/crates/rust-analyzer/src/main_loop/handlers.rs @@ -381,6 +381,7 @@ pub fn handle_runnables( label, bin: "cargo".to_string(), args: check_args, + extra_args: Vec::with_capacity(0), env: FxHashMap::default(), cwd: workspace_root.map(|root| root.to_string_lossy().to_string()), }); @@ -795,17 +796,29 @@ pub fn handle_code_lens( } .to_string(); let r = to_lsp_runnable(&world, file_id, runnable)?; + let range = r.range; + let arguments = vec![to_value(r).unwrap()]; let lens = CodeLens { - range: r.range, + range: range.clone(), command: Some(Command { title, command: "rust-analyzer.runSingle".into(), - arguments: Some(vec![to_value(r).unwrap()]), + arguments: Some(arguments.clone()), + }), + data: None, + }; + let debug_lens = CodeLens { + range, + command: Some(Command { + title: "Debug".into(), + command: "rust-analyzer.debugSingle".into(), + arguments: Some(arguments.clone()), }), data: None, }; lenses.push(lens); + lenses.push(debug_lens); } // Handle impls @@ -952,7 +965,7 @@ fn to_lsp_runnable( runnable: Runnable, ) -> Result { let spec = CargoTargetSpec::for_file(world, file_id)?; - let args = CargoTargetSpec::runnable_args(spec, &runnable.kind)?; + let (args, extra_args) = CargoTargetSpec::runnable_args(spec, &runnable.kind)?; let line_index = world.analysis().file_line_index(file_id)?; let label = match &runnable.kind { RunnableKind::Test { test_id } => format!("test {}", test_id), @@ -965,6 +978,7 @@ fn to_lsp_runnable( label, bin: "cargo".to_string(), args, + extra_args, env: { let mut m = FxHashMap::default(); m.insert("RUST_BACKTRACE".to_string(), "short".to_string()); @@ -973,6 +987,7 @@ fn to_lsp_runnable( cwd: world.workspace_root_for(file_id).map(|root| root.to_string_lossy().to_string()), }) } + fn highlight(world: &WorldSnapshot, file_id: FileId) -> Result> { let line_index = world.analysis().file_line_index(file_id)?; let res = world diff --git a/crates/rust-analyzer/src/req.rs b/crates/rust-analyzer/src/req.rs index a3efe3b9f..156328df8 100644 --- a/crates/rust-analyzer/src/req.rs +++ b/crates/rust-analyzer/src/req.rs @@ -169,6 +169,7 @@ pub struct Runnable { pub label: String, pub bin: String, pub args: Vec, + pub extra_args: Vec, pub env: FxHashMap, pub cwd: Option, } diff --git a/crates/rust-analyzer/tests/heavy_tests/main.rs b/crates/rust-analyzer/tests/heavy_tests/main.rs index 970185dec..55af6c5e0 100644 --- a/crates/rust-analyzer/tests/heavy_tests/main.rs +++ b/crates/rust-analyzer/tests/heavy_tests/main.rs @@ -75,7 +75,8 @@ fn foo() { RunnablesParams { text_document: server.doc_id("lib.rs"), position: None }, json!([ { - "args": [ "test", "--", "foo", "--nocapture" ], + "args": [ "test" ], + "extraArgs": [ "foo", "--nocapture" ], "bin": "cargo", "env": { "RUST_BACKTRACE": "short" }, "cwd": null, @@ -90,6 +91,7 @@ fn foo() { "check", "--all" ], + "extraArgs": [], "bin": "cargo", "env": {}, "cwd": null, @@ -147,7 +149,8 @@ fn main() {} }, json!([ { - "args": [ "test", "--package", "foo", "--test", "spam", "--", "test_eggs", "--exact", "--nocapture" ], + "args": [ "test", "--package", "foo", "--test", "spam" ], + "extraArgs": [ "test_eggs", "--exact", "--nocapture" ], "bin": "cargo", "env": { "RUST_BACKTRACE": "short" }, "label": "test test_eggs", @@ -165,6 +168,7 @@ fn main() {} "--test", "spam" ], + "extraArgs": [], "bin": "cargo", "env": {}, "cwd": server.path().join("foo"), diff --git a/editors/code/package.json b/editors/code/package.json index 1fe8e9f8a..744585721 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -51,6 +51,9 @@ "typescript-formatter": "^7.2.2", "vsce": "^1.74.0" }, + "extensionDependencies": [ + "vadimcn.vscode-lldb" + ], "activationEvents": [ "onLanguage:rust", "onCommand:rust-analyzer.analyzerStatus", diff --git a/editors/code/src/commands/runnables.ts b/editors/code/src/commands/runnables.ts index 06b513466..faa92799c 100644 --- a/editors/code/src/commands/runnables.ts +++ b/editors/code/src/commands/runnables.ts @@ -3,6 +3,7 @@ import * as lc from 'vscode-languageclient'; import * as ra from '../rust-analyzer-api'; import { Ctx, Cmd } from '../ctx'; +import { debug } from 'vscode'; export function run(ctx: Ctx): Cmd { let prevRunnable: RunnableQuickPick | undefined; @@ -62,6 +63,31 @@ export function runSingle(ctx: Ctx): Cmd { }; } +export function debugSingle(ctx: Ctx): Cmd { + return async (config: ra.Runnable) => { + const editor = ctx.activeRustEditor; + if (!editor) return; + + if (config.args[0] === 'run') { + config.args[0] = 'build'; + } else { + config.args.push('--no-run'); + } + + const debugConfig = { + type: "lldb", + request: "launch", + name: config.label, + cargo: { + args: config.args, + }, + args: config.extraArgs, + cwd: config.cwd + }; + return debug.startDebugging(undefined, debugConfig); + }; +} + class RunnableQuickPick implements vscode.QuickPickItem { public label: string; public description?: string | undefined; @@ -87,7 +113,7 @@ function createTask(spec: ra.Runnable): vscode.Task { type: 'cargo', label: spec.label, command: spec.bin, - args: spec.args, + args: spec.extraArgs ? [...spec.args, '--', ...spec.extraArgs] : spec.args, env: spec.env, }; diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts index ecf53cf77..e01c89cc7 100644 --- a/editors/code/src/main.ts +++ b/editors/code/src/main.ts @@ -83,6 +83,7 @@ export async function activate(context: vscode.ExtensionContext) { // Internal commands which are invoked by the server. ctx.registerCommand('runSingle', commands.runSingle); + ctx.registerCommand('debugSingle', commands.debugSingle); ctx.registerCommand('showReferences', commands.showReferences); ctx.registerCommand('applySourceChange', commands.applySourceChange); ctx.registerCommand('selectAndApplySourceChange', commands.selectAndApplySourceChange); diff --git a/editors/code/src/rust-analyzer-api.ts b/editors/code/src/rust-analyzer-api.ts index bd6e3ada0..e09a203c9 100644 --- a/editors/code/src/rust-analyzer-api.ts +++ b/editors/code/src/rust-analyzer-api.ts @@ -80,13 +80,12 @@ export interface Runnable { label: string; bin: string; args: Vec; + extraArgs: Vec; env: FxHashMap; cwd: Option; } export const runnables = request>("runnables"); - - export type InlayHint = InlayHint.TypeHint | InlayHint.ParamHint; export namespace InlayHint { -- cgit v1.2.3 From 60b154ff92e0d4625b551abe7ab7c59e2c9ca47b Mon Sep 17 00:00:00 2001 From: hdevalke <2261239+hdevalke@users.noreply.github.com> Date: Thu, 12 Mar 2020 20:56:34 +0100 Subject: Update crates/rust-analyzer/src/main_loop/handlers.rs use `Vec::new` instead of `Vec::with_capacity(0)` Co-Authored-By: Veetaha --- crates/rust-analyzer/src/main_loop/handlers.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs index 044273333..07761f00a 100644 --- a/crates/rust-analyzer/src/main_loop/handlers.rs +++ b/crates/rust-analyzer/src/main_loop/handlers.rs @@ -381,7 +381,7 @@ pub fn handle_runnables( label, bin: "cargo".to_string(), args: check_args, - extra_args: Vec::with_capacity(0), + extra_args: Vec::new(), env: FxHashMap::default(), cwd: workspace_root.map(|root| root.to_string_lossy().to_string()), }); -- cgit v1.2.3 From a034257e5ed5a3758e1ea2f72b3b905d1b2b320a Mon Sep 17 00:00:00 2001 From: Hannes De Valkeneer Date: Thu, 12 Mar 2020 21:00:40 +0100 Subject: fixup! feat: add debug code lens --- editors/code/src/commands/runnables.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/editors/code/src/commands/runnables.ts b/editors/code/src/commands/runnables.ts index faa92799c..51cfb37d5 100644 --- a/editors/code/src/commands/runnables.ts +++ b/editors/code/src/commands/runnables.ts @@ -3,7 +3,6 @@ import * as lc from 'vscode-languageclient'; import * as ra from '../rust-analyzer-api'; import { Ctx, Cmd } from '../ctx'; -import { debug } from 'vscode'; export function run(ctx: Ctx): Cmd { let prevRunnable: RunnableQuickPick | undefined; @@ -84,7 +83,7 @@ export function debugSingle(ctx: Ctx): Cmd { args: config.extraArgs, cwd: config.cwd }; - return debug.startDebugging(undefined, debugConfig); + return vscode.debug.startDebugging(undefined, debugConfig); }; } -- cgit v1.2.3 From e9d025b618aaa1a5a06e60c17392a18f12471217 Mon Sep 17 00:00:00 2001 From: Hannes De Valkeneer Date: Thu, 12 Mar 2020 21:28:26 +0100 Subject: fixup! feat: add debug code lens avoid repetition of `--no-run` --- crates/rust-analyzer/src/main_loop/handlers.rs | 17 ++++++++++------- crates/rust-analyzer/tests/heavy_tests/main.rs | 7 ++----- editors/code/src/commands/runnables.ts | 7 +------ 3 files changed, 13 insertions(+), 18 deletions(-) diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs index 07761f00a..f9715e675 100644 --- a/crates/rust-analyzer/src/main_loop/handlers.rs +++ b/crates/rust-analyzer/src/main_loop/handlers.rs @@ -795,24 +795,27 @@ pub fn handle_code_lens( RunnableKind::Bin => "Run", } .to_string(); - let r = to_lsp_runnable(&world, file_id, runnable)?; - let range = r.range; - let arguments = vec![to_value(r).unwrap()]; + let mut r = to_lsp_runnable(&world, file_id, runnable)?; let lens = CodeLens { - range: range.clone(), + range: r.range, command: Some(Command { title, command: "rust-analyzer.runSingle".into(), - arguments: Some(arguments.clone()), + arguments: Some(vec![to_value(&r).unwrap()]), }), data: None, }; + if r.args[0] == "run" { + r.args[0] = "build".into(); + } else { + r.args.push("--no-run".into()); + } let debug_lens = CodeLens { - range, + range: r.range, command: Some(Command { title: "Debug".into(), command: "rust-analyzer.debugSingle".into(), - arguments: Some(arguments.clone()), + arguments: Some(vec![to_value(r).unwrap()]), }), data: None, }; diff --git a/crates/rust-analyzer/tests/heavy_tests/main.rs b/crates/rust-analyzer/tests/heavy_tests/main.rs index 55af6c5e0..145429571 100644 --- a/crates/rust-analyzer/tests/heavy_tests/main.rs +++ b/crates/rust-analyzer/tests/heavy_tests/main.rs @@ -143,10 +143,7 @@ fn main() {} server.wait_until_workspace_is_loaded(); server.request::( - RunnablesParams { - text_document: server.doc_id("foo/tests/spam.rs"), - position: None, - }, + RunnablesParams { text_document: server.doc_id("foo/tests/spam.rs"), position: None }, json!([ { "args": [ "test", "--package", "foo", "--test", "spam" ], @@ -184,7 +181,7 @@ fn main() {} } } } - ]) + ]), ); } diff --git a/editors/code/src/commands/runnables.ts b/editors/code/src/commands/runnables.ts index 51cfb37d5..357155163 100644 --- a/editors/code/src/commands/runnables.ts +++ b/editors/code/src/commands/runnables.ts @@ -67,12 +67,6 @@ export function debugSingle(ctx: Ctx): Cmd { const editor = ctx.activeRustEditor; if (!editor) return; - if (config.args[0] === 'run') { - config.args[0] = 'build'; - } else { - config.args.push('--no-run'); - } - const debugConfig = { type: "lldb", request: "launch", @@ -83,6 +77,7 @@ export function debugSingle(ctx: Ctx): Cmd { args: config.extraArgs, cwd: config.cwd }; + return vscode.debug.startDebugging(undefined, debugConfig); }; } -- cgit v1.2.3 From 39c92b38726a4ca0e0e48198cbd5bdd82bbf2fb5 Mon Sep 17 00:00:00 2001 From: Hannes De Valkeneer Date: Thu, 12 Mar 2020 22:31:47 +0100 Subject: fixup! feat: add debug code lens autodetect vscode-lldb --- crates/rust-analyzer/src/config.rs | 4 +++ crates/rust-analyzer/src/main_loop.rs | 1 + crates/rust-analyzer/src/main_loop/handlers.rs | 34 ++++++++++++++------------ crates/rust-analyzer/src/world.rs | 1 + editors/code/package.json | 3 --- editors/code/src/client.ts | 1 + editors/code/src/config.ts | 1 + 7 files changed, 26 insertions(+), 19 deletions(-) diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index a8bf29ddf..cfca06f56 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -51,6 +51,9 @@ pub struct ServerConfig { /// Cargo feature configurations. pub cargo_features: CargoFeatures, + + /// Enabled if the vscode_lldb extension is available. + pub vscode_lldb: bool, } impl Default for ServerConfig { @@ -70,6 +73,7 @@ impl Default for ServerConfig { additional_out_dirs: FxHashMap::default(), cargo_features: Default::default(), rustfmt_args: Vec::new(), + vscode_lldb: false, } } } diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs index 4f7aac754..b4add046f 100644 --- a/crates/rust-analyzer/src/main_loop.rs +++ b/crates/rust-analyzer/src/main_loop.rs @@ -185,6 +185,7 @@ pub fn main_loop( all_targets: config.cargo_watch_all_targets, }, rustfmt_args: config.rustfmt_args, + vscode_lldb: config.vscode_lldb, } }; diff --git a/crates/rust-analyzer/src/main_loop/handlers.rs b/crates/rust-analyzer/src/main_loop/handlers.rs index f9715e675..571a896f3 100644 --- a/crates/rust-analyzer/src/main_loop/handlers.rs +++ b/crates/rust-analyzer/src/main_loop/handlers.rs @@ -805,23 +805,25 @@ pub fn handle_code_lens( }), data: None, }; - if r.args[0] == "run" { - r.args[0] = "build".into(); - } else { - r.args.push("--no-run".into()); - } - let debug_lens = CodeLens { - range: r.range, - command: Some(Command { - title: "Debug".into(), - command: "rust-analyzer.debugSingle".into(), - arguments: Some(vec![to_value(r).unwrap()]), - }), - data: None, - }; - lenses.push(lens); - lenses.push(debug_lens); + + if world.options.vscode_lldb { + if r.args[0] == "run" { + r.args[0] = "build".into(); + } else { + r.args.push("--no-run".into()); + } + let debug_lens = CodeLens { + range: r.range, + command: Some(Command { + title: "Debug".into(), + command: "rust-analyzer.debugSingle".into(), + arguments: Some(vec![to_value(r).unwrap()]), + }), + data: None, + }; + lenses.push(debug_lens); + } } // Handle impls diff --git a/crates/rust-analyzer/src/world.rs b/crates/rust-analyzer/src/world.rs index 9ef368529..a4fda9f80 100644 --- a/crates/rust-analyzer/src/world.rs +++ b/crates/rust-analyzer/src/world.rs @@ -37,6 +37,7 @@ pub struct Options { pub max_inlay_hint_length: Option, pub rustfmt_args: Vec, pub cargo_watch: CheckOptions, + pub vscode_lldb: bool, } /// `WorldState` is the primary mutable state of the language server diff --git a/editors/code/package.json b/editors/code/package.json index 744585721..1fe8e9f8a 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -51,9 +51,6 @@ "typescript-formatter": "^7.2.2", "vsce": "^1.74.0" }, - "extensionDependencies": [ - "vadimcn.vscode-lldb" - ], "activationEvents": [ "onLanguage:rust", "onCommand:rust-analyzer.analyzerStatus", diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts index 6ce3b9235..99c9c5ae7 100644 --- a/editors/code/src/client.ts +++ b/editors/code/src/client.ts @@ -41,6 +41,7 @@ export async function createClient(config: Config, serverPath: string): Promise< withSysroot: config.withSysroot, cargoFeatures: config.cargoFeatures, rustfmtArgs: config.rustfmtArgs, + vscodeLldb: vscode.extensions.getExtension("vadimcn.vscode-lldb") != null, }, traceOutputChannel, middleware: { diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts index 3ade7e900..40f4c7a0d 100644 --- a/editors/code/src/config.ts +++ b/editors/code/src/config.ts @@ -156,6 +156,7 @@ export class Config { get featureFlags() { return this.cfg.get("featureFlags") as Record; } get additionalOutDirs() { return this.cfg.get("additionalOutDirs") as Record; } get rustfmtArgs() { return this.cfg.get("rustfmtArgs") as string[]; } + get vscodeLldb() { return this.cfg.get("vscodeLldb") as boolean; } get cargoWatchOptions(): CargoWatchOptions { return { -- cgit v1.2.3 From fa655912b540ece5920de8deb7856629850f5bdc Mon Sep 17 00:00:00 2001 From: hdevalke <2261239+hdevalke@users.noreply.github.com> Date: Thu, 12 Mar 2020 22:56:37 +0100 Subject: Update editors/code/src/config.ts Co-Authored-By: Veetaha --- editors/code/src/config.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts index 40f4c7a0d..3ade7e900 100644 --- a/editors/code/src/config.ts +++ b/editors/code/src/config.ts @@ -156,7 +156,6 @@ export class Config { get featureFlags() { return this.cfg.get("featureFlags") as Record; } get additionalOutDirs() { return this.cfg.get("additionalOutDirs") as Record; } get rustfmtArgs() { return this.cfg.get("rustfmtArgs") as string[]; } - get vscodeLldb() { return this.cfg.get("vscodeLldb") as boolean; } get cargoWatchOptions(): CargoWatchOptions { return { -- cgit v1.2.3 From 89eb9e8002466f3099de77bc42cdabbf67d5dc1b Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Fri, 13 Mar 2020 13:57:44 +0100 Subject: Protect against infinite macro expansion in def collector There was a test for this, but it wasn't actually working because the first recursive expansion failed. (The comma...) Even with this limit, that test (when fixed) still takes some time to pass because of the exponential growth of the expansions, so I disabled it and added a different one without growth. --- crates/ra_hir_def/src/nameres/collector.rs | 48 ++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 9 deletions(-) diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs index d0459d9b0..db9838cb5 100644 --- a/crates/ra_hir_def/src/nameres/collector.rs +++ b/crates/ra_hir_def/src/nameres/collector.rs @@ -102,6 +102,7 @@ struct MacroDirective { module_id: LocalModuleId, ast_id: AstIdWithPath, legacy: Option, + depth: usize, } #[derive(Clone, Debug, Eq, PartialEq)] @@ -134,6 +135,7 @@ where self.def_map.modules[module_id].origin = ModuleOrigin::CrateRoot { definition: file_id }; ModCollector { def_collector: &mut *self, + macro_depth: 0, module_id, file_id: file_id.into(), raw_items: &raw_items, @@ -516,7 +518,7 @@ where macros.retain(|directive| { if let Some(call_id) = directive.legacy { res = ReachedFixedPoint::No; - resolved.push((directive.module_id, call_id)); + resolved.push((directive.module_id, call_id, directive.depth)); return false; } @@ -530,7 +532,7 @@ where ); resolved_res.resolved_def.take_macros() }) { - resolved.push((directive.module_id, call_id)); + resolved.push((directive.module_id, call_id, directive.depth)); res = ReachedFixedPoint::No; return false; } @@ -541,7 +543,7 @@ where if let Some(call_id) = directive.ast_id.as_call_id(self.db, |path| self.resolve_attribute_macro(&path)) { - resolved.push((directive.module_id, call_id)); + resolved.push((directive.module_id, call_id, 0)); res = ReachedFixedPoint::No; return false; } @@ -552,8 +554,12 @@ where self.unexpanded_macros = macros; self.unexpanded_attribute_macros = attribute_macros; - for (module_id, macro_call_id) in resolved { - self.collect_macro_expansion(module_id, macro_call_id); + for (module_id, macro_call_id, depth) in resolved { + if depth > 1024 { + log::debug!("Max macro expansion depth reached"); + continue; + } + self.collect_macro_expansion(module_id, macro_call_id, depth); } res @@ -573,12 +579,18 @@ where None } - fn collect_macro_expansion(&mut self, module_id: LocalModuleId, macro_call_id: MacroCallId) { + fn collect_macro_expansion( + &mut self, + module_id: LocalModuleId, + macro_call_id: MacroCallId, + depth: usize, + ) { let file_id: HirFileId = macro_call_id.as_file(); let raw_items = self.db.raw_items(file_id); let mod_dir = self.mod_dirs[&module_id].clone(); ModCollector { def_collector: &mut *self, + macro_depth: depth, file_id, module_id, raw_items: &raw_items, @@ -595,6 +607,7 @@ where /// Walks a single module, populating defs, imports and macros struct ModCollector<'a, D> { def_collector: D, + macro_depth: usize, module_id: LocalModuleId, file_id: HirFileId, raw_items: &'a raw::RawItems, @@ -684,6 +697,7 @@ where ModCollector { def_collector: &mut *self.def_collector, + macro_depth: self.macro_depth, module_id, file_id: self.file_id, raw_items: self.raw_items, @@ -713,6 +727,7 @@ where let raw_items = self.def_collector.db.raw_items(file_id.into()); ModCollector { def_collector: &mut *self.def_collector, + macro_depth: self.macro_depth, module_id, file_id: file_id.into(), raw_items: &raw_items, @@ -887,6 +902,7 @@ where module_id: self.module_id, ast_id, legacy: Some(macro_call_id), + depth: self.macro_depth + 1, }); return; @@ -902,6 +918,7 @@ where module_id: self.module_id, ast_id, legacy: None, + depth: self.macro_depth + 1, }); } @@ -971,13 +988,26 @@ mod tests { } #[test] - fn test_macro_expand_will_stop() { + fn test_macro_expand_will_stop_1() { + do_resolve( + r#" + macro_rules! foo { + ($($ty:ty)*) => { foo!($($ty)*); } + } + foo!(KABOOM); + "#, + ); + } + + #[ignore] // this test does succeed, but takes quite a while :/ + #[test] + fn test_macro_expand_will_stop_2() { do_resolve( r#" macro_rules! foo { - ($($ty:ty)*) => { foo!($($ty)*, $($ty)*); } + ($($ty:ty)*) => { foo!($($ty)* $($ty)*); } } -foo!(KABOOM); + foo!(KABOOM); "#, ); } -- cgit v1.2.3