Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate write.rs to rustc_ast::FormatArgs #10275

Merged
merged 3 commits into from
Mar 10, 2023

Conversation

Alexendoo
Copy link
Member

@Alexendoo Alexendoo commented Feb 1, 2023

changelog: none

Part 1 of #10233

The additions to clippy_utils are the main novelty of this PR, there's no removals yet since other parts still rely on FormatArgsExpn

The changes to write.rs itself are relatively straightforward this time around, as there's no lints in it that rely on type checking format params

r? @flip1995

@nyurik
Copy link
Contributor

nyurik commented Feb 2, 2023

This is awesome, thanks for the implementation! The code looks reasonable, and I learnt a few things.

If my understanding is correct, you essentially store every format_args invocation in a hashmap as span -> AST during the early pass, and later get the AST during the late pass, and you do it in the context of the write lint. My guess is that some other lints may need the same functionality, and it would be a bit wasteful for each lint to generate a full copy of such mapping for all format_args. Is there a way to have a shared cache of those, where each lint that needs it can set some flag to enable this feature if that lint is being used?

@llogiq
Copy link
Contributor

llogiq commented Feb 2, 2023

Yeah, I suggested on zulip to have one internal lint pass that stores the mapping in a shared hash map.

@Alexendoo
Copy link
Member Author

It's being populated by the Write early pass but other late lints can use it as well, as the thread local lives in clippy_utils

Putting the populating part in its own internal lint would make that clearer so I'll look at doing that

@nyurik
Copy link
Contributor

nyurik commented Feb 2, 2023

Looks good!

Somewhat related -- does clippy optimize lint running if a lint is disabled? Or does it run all lints all the time, but hides output of the disabled lints? If first, all arg formatting lints would need some way to indicate they are dependent on this internal lint.

@flip1995
Copy link
Member

flip1995 commented Feb 2, 2023

does clippy optimize lint running if a lint is disabled? Or does it run all lints all the time, but hides output of the disabled lints?

rust-lang/rust#106983 Currently the latter. In the future maybe also the former.

Also in the future lint passes might run in parallel. This might lead to problems with the thread_local. But I think we should be fine here, because one is a early lint and the others are all late lints. And I think it's safe to assume that early and late lints will never run in parallel. (Also this is far in the future).

I still have to do a proper review.

@Alexendoo
Copy link
Member Author

It shouldn't be too much of an issue if it does optimise that in the future because you'd have to go pretty far out of your way to disable the collector lint, it's not part of any group like clippy::all so you'd have to #[allow] it by name, and the name isn't listed on the website or in clippy-driver -W help

Is clippy tested anywhere with parallel_compiler? That could be an issue if the threads change there, though it should still compile fine

Comment on lines +374 to +387
let format_args_expr = for_each_expr(start, |expr| {
let ctxt = expr.span.ctxt();
if ctxt == start.span.ctxt() {
ControlFlow::Continue(Descend::Yes)
} else if ctxt.outer_expn().is_descendant_of(expn_id)
&& macro_backtrace(expr.span)
.map(|macro_call| cx.tcx.item_name(macro_call.def_id))
.any(|name| matches!(name, sym::const_format_args | sym::format_args | sym::format_args_nl))
{
ControlFlow::Break(expr)
} else {
ControlFlow::Continue(Descend::No)
}
});
Copy link
Member Author

Choose a reason for hiding this comment

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

Worth mentioning that I pulled this from the existing FormatArgsExpn::find_nested and the very start of FormatArgsExpn::parse:

pub fn find_nested(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, expn_id: ExpnId) -> Option<Self> {
for_each_expr(expr, |e| {
let e_ctxt = e.span.ctxt();
if e_ctxt == expr.span.ctxt() {
ControlFlow::Continue(Descend::Yes)
} else if e_ctxt.outer_expn().is_descendant_of(expn_id) {
if let Some(args) = FormatArgsExpn::parse(cx, e) {
ControlFlow::Break(args)
} else {
ControlFlow::Continue(Descend::No)
}
} else {
ControlFlow::Continue(Descend::No)
}
})
}

pub fn parse(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<Self> {
let macro_name = macro_backtrace(expr.span)
.map(|macro_call| cx.tcx.item_name(macro_call.def_id))
.find(|&name| matches!(name, sym::const_format_args | sym::format_args | sym::format_args_nl))?;

@nyurik
Copy link
Contributor

nyurik commented Feb 22, 2023

Friendly ping @flip1995 :)

@nyurik
Copy link
Contributor

nyurik commented Mar 5, 2023

👋

Copy link
Member

@flip1995 flip1995 left a comment

Choose a reason for hiding this comment

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

I don't really like the thread_local variable to store the state, but I can't come up with a better implementation. So let's merge this to move things forward.

@flip1995
Copy link
Member

flip1995 commented Mar 6, 2023

@bors r+

Thanks!

@bors
Copy link
Contributor

bors commented Mar 6, 2023

📌 Commit d1407e5 has been approved by flip1995

It is now in the queue for this repository.

@bors
Copy link
Contributor

bors commented Mar 6, 2023

⌛ Testing commit d1407e5 with merge 717577f...

bors added a commit that referenced this pull request Mar 6, 2023
Migrate `write.rs` to `rustc_ast::FormatArgs`

changelog: none

Part 1 of #10233

The additions to `clippy_utils` are the main novelty of this PR, there's no removals yet since other parts still rely on `FormatArgsExpn`

The changes to `write.rs` itself are relatively straightforward this time around, as there's no lints in it that rely on type checking format params

r? `@flip1995`
@bors
Copy link
Contributor

bors commented Mar 6, 2023

💔 Test failed - checks-action_test

@Alexendoo
Copy link
Member Author

Damn proc macros

@Alexendoo
Copy link
Member Author

Moved that test to tests/ui/crashes as it's a false positive now, or at least the suggestion would cause an error. It was an ICE until a week ago (#10401) so it's not too much of a regression at least

@flip1995
Copy link
Member

flip1995 commented Mar 9, 2023

Why is this linted now and wasn't before this refactor?

@Alexendoo
Copy link
Member Author

Previously it parsed the string from the source text in order to hand it off to rustc_parse_format, but for an invalid string it would bail early

// Sometimes the original string comes from a macro which accepts a malformed string, such as in a
// #[display(""somestring)] attribute (accepted by the `displaythis` crate). Reconstructing the
// string from the span will not be possible, so we will just return None here.
let mut unparsable = false;
unescape_literal(inner, mode, &mut |_, ch| match ch {
Ok(ch) => unescaped.push(ch),
Err(e) if !e.is_fatal() => (),
Err(_) => unparsable = true,
});

After the refactor it doesn't need to use rustc_parse_format so there's no parsing of the source string, for valid strings it's a FP in both versions, i.e.

println!(with_span!("" ""));

currently produces

error: empty string literal in `println!`
  --> $DIR/x.rs:8:5
   |
LL |     println!(with_span!("" ""));
   |     ^^^^^^^^^^^^^^^^^^^^--^^^^^
   |                         |
   |                         help: remove the empty string

and is unchanged after this PR

@flip1995
Copy link
Member

Thanks for the explanation! I'm fine with this "regression" since it is only for invalid code anyway IIUC.

Let's get this merged to get it in with this sync.

@bors +

@flip1995
Copy link
Member

@bors r+ (forgot the r...)

@bors
Copy link
Contributor

bors commented Mar 10, 2023

📌 Commit fa0c3cc has been approved by flip1995

It is now in the queue for this repository.

@bors
Copy link
Contributor

bors commented Mar 10, 2023

⌛ Testing commit fa0c3cc with merge 3c06e0b...

@bors
Copy link
Contributor

bors commented Mar 10, 2023

☀️ Test successful - checks-action_dev_test, checks-action_remark_test, checks-action_test
Approved by: flip1995
Pushing 3c06e0b to master...

@bors bors merged commit 3c06e0b into rust-lang:master Mar 10, 2023
@Alexendoo Alexendoo deleted the format-args-ast branch March 10, 2023 11:23
bors added a commit to rust-lang-ci/rust that referenced this pull request Mar 10, 2023
Update Clippy

r? `@Manishearth`

cc `@m-ou-se` This sync also includes rust-lang/rust-clippy#10275
flip1995 pushed a commit to flip1995/rust-clippy that referenced this pull request Mar 24, 2023
Update Clippy

r? `@Manishearth`

cc `@m-ou-se` This sync also includes rust-lang#10275
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-review Status: Awaiting review from the assignee but also interested parties
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants