Skip to content

Improve syntax fixup for proc macros #12777

Open
@flodiebold

Description

@flodiebold

To make completion work inside attribute proc macros like #[tokio::main], we take incomplete code inside the attribute input and 'fix it up' to make sure the proc macro can parse it. This already works pretty well in the common cases, but I think there are lots of edge cases missing. This usually results in completion not working inside the proc macro for a moment while typing something, and then working again once one has typed a more complete expression, so I think people are unlikely to report cases like this and will just chalk it up to "rust-analyzer being unreliable". So I think it's worth to look for edge cases that are missing and add them.

Also, while it would be nice to have some more automatic / principled way to do this syntax fixup, any work adding more cases to the current code and extending the test suite will not be wasted; the test suite is really the most important part.

The syntax fixup code lives in the fixup module:

//! To make attribute macros work reliably when typing, we need to take care to
//! fix up syntax errors in the code we're passing to them.
use std::mem;

New cases will need to be added to the big match_ast! in the fixup_syntax function:

As can be seen from the existing cases, this mostly consists of checking if some part of a node is missing and inserting a simple placeholder token or two (an identifier, or some missing punctuation).

For each case, a test case should be added at the end of the module. The tests look like this:

#[test]
fn extraneous_comma() {
check(
r#"
fn foo() {
bar(,);
}
"#,
expect![[r#"
fn foo () {__ra_fixup ;}
"#]],
)
}

Test cases consist of the original incomplete code, and the "fixed up" code. The "fixed up" code can be automatically updated by running UPDATE_EXPECT=1 cargo test -p hir-expand, and the tests also check the important conditions that 1. the fixed-up code is syntactically complete, and 2. the fixups can be reversed afterwards, so if these checks succeed, the fixup is working.

Here are some cases that I think we are missing currently:

  • incomplete paths like foo::
  • incomplete flow control keywords like loop without a block, for missing its various components etc.

Metadata

Metadata

Assignees

Labels

A-macromacro expansionC-featureCategory: feature requestE-easyE-has-instructionsIssue has some instructions and pointers to code to get started

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions