Skip to content

fix Treat doctests as rust code #4170#21949

Draft
asukaminato0721 wants to merge 1 commit intorust-lang:masterfrom
asukaminato0721:4170
Draft

fix Treat doctests as rust code #4170#21949
asukaminato0721 wants to merge 1 commit intorust-lang:masterfrom
asukaminato0721:4170

Conversation

@asukaminato0721
Copy link
Copy Markdown
Contributor

@asukaminato0721 asukaminato0721 commented Apr 4, 2026

fix #4170

I use this method:

inject a function

  fn __ra_doctest_completion() {
      ...doctest lines...
  }

So the completion works, then maintain a map between the real code and inject function.

current limitation: proc-macro is not well supported.

@asukaminato0721 asukaminato0721 force-pushed the 4170 branch 2 times, most recently from c5c332f to 6397575 Compare April 4, 2026 05:05
@asukaminato0721 asukaminato0721 marked this pull request as ready for review April 4, 2026 05:32
Copilot AI review requested due to automatic review settings April 4, 2026 05:32
@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Apr 4, 2026
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds Rust completion support inside Rust doctest code fences embedded in doc comments by injecting the doctest snippet into a temporary wrapper function and mapping completion edits/ranges back to the original file.

Changes:

  • Adds a doctest-aware completion fast-path that runs before normal completion.
  • Introduces a new completions::doctest module that builds an injected view of the file and upmaps completion results.
  • Adds a regression test ensuring hel$0 in a /// ```rust fenced block completes helper.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.

File Description
crates/ide-completion/src/lib.rs Routes completion requests through doctest completion first.
crates/ide-completion/src/completions.rs Exposes the new doctest completion module.
crates/ide-completion/src/completions/doctest.rs Implements doctest fence detection, injection/mapping, and completion dispatch.
crates/ide-completion/src/tests.rs Adds a doctest code fence completion test and updates expect-test imports.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

View changes since this review

Comment on lines +309 to +335
fn build_doctest_db(
db: &RootDatabase,
changed_file_id: ide_db::FileId,
changed_file_text: String,
) -> RootDatabase {
let mut doctest_db = RootDatabase::new(None);
if db.expand_proc_attr_macros() {
doctest_db.enable_proc_attr_macros();
}

let roots = source_roots(db);
let mut change = ChangeWithProcMacros::default();
change.set_roots(roots.clone());
for root in &roots {
for file_id in root.iter() {
let text = if file_id == changed_file_id {
changed_file_text.clone()
} else {
db.file_text(file_id).text(db).to_string()
};
change.change_file(file_id, Some(text));
}
}
change.set_crate_graph(copy_crate_graph(db));
doctest_db.apply_change(change);
doctest_db
}
Copy link

Copilot AI Apr 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

build_doctest_db rebuilds a fresh RootDatabase, re-sets all source roots, and copies every file’s text + reconstructs the crate graph on each completion request. This is O(workspace size) work in a very hot path and is likely to cause severe completion latency/memory churn on medium/large projects. Prefer cloning the existing RootDatabase (db.clone()) and applying a ChangeWithProcMacros that only updates changed_file_id’s text (no set_roots / no crate-graph rebuild), so salsa can reuse existing inputs/caches and only re-analyze what’s needed.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a bottleneck but can't figure out it for now.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is completely unacceptable as it's now.

Comment thread crates/ide-completion/src/completions/doctest.rs
Comment thread crates/ide-completion/src/completions/doctest.rs Outdated
Comment thread crates/ide-completion/src/completions/doctest.rs Outdated
Comment thread crates/ide-completion/src/completions/doctest.rs Outdated
@ChayimFriedman2
Copy link
Copy Markdown
Contributor

I haven't looked at the code yet, but this is likely to need design discussions to meet expected performance. Just opening a PR is likely not going to go well.

@ChayimFriedman2
Copy link
Copy Markdown
Contributor

We already have a fine injection system for fixtures. We can reuse that, however we need to think how to represent crate dependencies.

@asukaminato0721 asukaminato0721 marked this pull request as draft April 5, 2026 23:41
@rustbot rustbot removed the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Apr 5, 2026
fmt

fix some copilot problem
@ChayimFriedman2
Copy link
Copy Markdown
Contributor

@asukaminato0721 What's the status of this? Do you intend to complete this?

@asukaminato0721
Copy link
Copy Markdown
Contributor Author

@asukaminato0721 What's the status of this? Do you intend to complete this?

Stuck on how to represent crate dependencies.

yeah, if possible.

@ChayimFriedman2
Copy link
Copy Markdown
Contributor

This is indeed a problem. If we create a new RootDatabase, we can't link it to the crates in the current db. And if we use the current db, we cannot easily do cleanup after.

I don't have a solution in my head for that (perhaps speculative execution will help, once we have that in Salsa). @rust-lang/rust-analyzer do you have any idea?

@ChayimFriedman2
Copy link
Copy Markdown
Contributor

We might be able to go by swapping Crate with #[derive(salsa::Supertype)] enum Crate { RealCrate(RealCrate), DocsCrate(DocsCrate) } where RealCrate is an input like currently and DocsCrate is an interned/tracked struct created from a docs_crate() query which is LRUed, and similarly add a variant to HirFileId to represent a fake docs file, but this is going to be a complicated refactoring and I want to get a buy-in from the team before merging something like that.

So, if you want to try this, please open a Zulip discussion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Treat doctests as rust code

4 participants