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

Attributes on expressions become duplicated under certain conditions #4452

Closed
coadler opened this issue Oct 3, 2020 · 11 comments
Closed

Attributes on expressions become duplicated under certain conditions #4452

coadler opened this issue Oct 3, 2020 · 11 comments
Labels
bug Panic, non-idempotency, invalid code, etc. good first issue Issues up for grabs, also good candidates for new rustfmt contributors hacktoberfest help wanted

Comments

@coadler
Copy link

coadler commented Oct 3, 2020

Describe the bug

Attributes on expressions become doubled every time rustfmt is ran when preceeded by a comment and the expression contains a cast, i.e. as i64.

To Reproduce

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=2499dbd812381b73c863ad79691053fd

trait FooBar {
    fn foo(&self) -> i64 {
        // some comment
        #[allow(clippy::cast_possible_wrap)]
        1u64 as i64
    }
}

Running rustfmt under tools on the above playground link causes the attribute to double on every invocation.

Playing around with it, removing either the comment and as i64 cause this not to reproduce, so it seems like it's the combination of them both that is causing this bug.

Expected behavior

The attribute isn't doubled every time.

Meta

  • rustfmt version: rustfmt 1.4.21-nightly (01f2ead 2020-09-04) and latest stable
  • From where did you install rustfmt?: rustup
  • How do you run rustfmt: rustfmt directly on the file


(edited by calebcartwright to include inline reproduction snippet)

@coadler coadler added the bug Panic, non-idempotency, invalid code, etc. label Oct 3, 2020
@calebcartwright
Copy link
Member

calebcartwright commented Oct 3, 2020

Interesting. Seems that at least as of v679 of the rustc-ap-* crates that the span is off for expression statements with attributes, at least for cast expression kinds, as the attributes are only associated to the subexpr of the cast and not the expr nor the statement.

This should be fixed upstream in rustc (if it hasn't already), though I imagine we could work around it by using the lo of the span from the first attribute in these cases (Expr statement, expr kind cast, subexpr has attributes)

ast::StmtKind::Expr(ref expr) | ast::StmtKind::Semi(ref expr) => {
mk_sp(expr.span().lo(), self.span.hi())
}

@calebcartwright calebcartwright added good first issue Issues up for grabs, also good candidates for new rustfmt contributors hacktoberfest help wanted labels Oct 4, 2020
@chansuke
Copy link
Contributor

chansuke commented Oct 5, 2020

@calebcartwright I'm trying to fix this issue and update the first attribute of ast::ExprKind::Cast() in src/formatting/expr.rs but I have no idea to how to find the subexpr has attributes case. Could you give me a suggestion for that...

@calebcartwright
Copy link
Member

Thanks for looking into it @chansuke! The fix will need to be made within spanned as linked in my previous response. We can't mutate the actual AST nodes, so it's really more about ensuring that the correct span is used for the expression statement.

The problem in this case currently is that the attributes are associated to the cast subexpression and not the cast expression itself, but correct recognition of the presence of attributes is required for rustfmt for span derivation.

In the match arm I linked above for expression statements, we'll need to check the expression kind, and if it's ExprKind::Cast and there's attributes on that subexpression, then we'll want to use the lo of that first attribute instead of expr.span().lo() that is currently used as the lo arg in that call to mk_sp

Does that make sense?

@t-nelson
Copy link

t-nelson commented Oct 8, 2020

Another, perhaps more degenerate, case

fn foo()  {
    #[allow(clippy::cast_possible_wrap)]
    {
        // some comment
    }
}

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=9b93094ef421e9f36873fbae800a17ad

Here rustfmt's output is quite mangled 🙃

@chansuke
Copy link
Contributor

@calebcartwright Thank you for your comment!! I will try adding ast::ExprKind::Cast(ref subexpr) => mk_sp(subexpr.attrs[0].span.lo(), subexpr.span.hi()) to the arm.

@calebcartwright
Copy link
Member

Another, perhaps more degenerate, case

Thanks @t-nelson. Although that presents with similar symptoms, that's a separate and distinct issue in upstream rustc that has subsequently been fixed. That should resolve itself after we update rustfmt to the next version of the rustc mods used for parsing

@calebcartwright
Copy link
Member

Thank you for your comment!! I will try adding ast::ExprKind::Cast(ref subexpr) => mk_sp(subexpr.attrs[0].span.lo(), subexpr.span.hi()) to the arm.

Thanks @chansuke! I've gone ahead and opened a PR upstream in rustc to correct the span calculation, and would rather just pull in the fix from upstream vs. trying to work around it within rustfmt.

It'll probably be a few days before we can grab the upstream fixes, but once we do this issue will turn into adding test cases to prevent regressions if you'd be interested in working on that.

@chansuke
Copy link
Contributor

@calebcartwright Thank you for your comment!! I will close my PR.

@calebcartwright calebcartwright removed the blocked Blocked on rustc, an RFC, etc. label Oct 20, 2020
@calebcartwright
Copy link
Member

@chansuke - everything is unblocked now as of #4478, so you should be able to grab the latest changes from the master branch in this repo and add the tests.

Please include a cast expression as noted in the original issue description, as well as a range expression (I discovered the same span issue existed while fixing the bug in rustc). Something as simple as the below should cover it

// foo
#[attr]
1..2

While we're at it 😄 Please also include a test for blocks using the snippet posted above as well as the one from #4475

chansuke pushed a commit to chansuke/rustfmt that referenced this issue Oct 20, 2020
@chansuke
Copy link
Contributor

@calebcartwright I appreciate your support. I will add some tests on latest master.

calebcartwright pushed a commit that referenced this issue Oct 25, 2020
* Add tests for duplicated attributes on expressions(#4452)

* Add necessary comments and fix the target

* Add comments for testings

* Fix testing for extra brace insertion
@calebcartwright
Copy link
Member

Closing as this has been resolved

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Panic, non-idempotency, invalid code, etc. good first issue Issues up for grabs, also good candidates for new rustfmt contributors hacktoberfest help wanted
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants