Skip to content

Commit

Permalink
Fix for Rust compiler warning about derive helpers (#2581)
Browse files Browse the repository at this point in the history
## Motivation and Context
Follow-up to #2434


## Description
This provides a way to fix a compiler warning. Attributes created using
RustMetadata.additionalAttributes may trigger compiler warnings
(rust-lang/rust#79202) such as

```
warning: derive helper attribute is used before it is introduced
    --> src/model.rs:7674:3
     |
7674 | #[serde(tag = "_type", content = "_content")]
     |   ^^^^^
7675 | #[derive(
7676 |     serde::Deserialize,
     |     ------------------ the attribute is introduced here
     |
     = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
     = note: for more information, see issue #79202 <rust-lang/rust#79202>

```

## Testing
Added a unit test to validate the sort order is applied correctly to
Attributes with isDeriveHelper = true.

---------

Co-authored-by: david-perez <[email protected]>
  • Loading branch information
2 people authored and unexge committed Apr 24, 2023
1 parent 6499909 commit 93e0467
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -385,11 +385,17 @@ data class RustMetadata(
this.copy(derives = derives - withoutDerives.toSet())

fun renderAttributes(writer: RustWriter): RustMetadata {
additionalAttributes.forEach {
val (deriveHelperAttrs, otherAttrs) = additionalAttributes.partition { it.isDeriveHelper }
otherAttrs.forEach {
it.render(writer)
}

Attribute(derive(derives)).render(writer)

// Derive helper attributes must come after derive, see https://github.com/rust-lang/rust/issues/79202
deriveHelperAttrs.forEach {
it.render(writer)
}
return this
}

Expand Down Expand Up @@ -450,17 +456,22 @@ enum class AttributeKind {
* [Attributes](https://doc.rust-lang.org/reference/attributes.html) are general free form metadata
* that are interpreted by the compiler.
*
* If the attribute is a "derive helper", such as `#[serde]`, set `isDeriveHelper` to `true` so it is sorted correctly after
* the derive attribute is rendered. (See https://github.com/rust-lang/rust/issues/79202 for why sorting matters.)
*
* For example:
* ```rust
* #[allow(missing_docs)] // <-- this is an attribute, and it is not a derive helper
* #[derive(Clone, PartialEq, Serialize)] // <-- this is an attribute
* #[serde(serialize_with = "abc")] // <-- this is an attribute
* #[serde(serialize_with = "abc")] // <-- this attribute is a derive helper because the `Serialize` derive uses it
* struct Abc {
* a: i64
* }
* ```
*/
class Attribute(val inner: Writable) {
class Attribute(val inner: Writable, val isDeriveHelper: Boolean = false) {
constructor(str: String) : this(writable(str))
constructor(str: String, isDeriveHelper: Boolean) : this(writable(str), isDeriveHelper)
constructor(runtimeType: RuntimeType) : this(runtimeType.writable)

fun render(writer: RustWriter, attributeKind: AttributeKind = AttributeKind.Outer) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,19 @@ class RustWriterTest {
sut.toString().shouldContain("#[foo]\n/// here's an attribute")
}

@Test
fun `attributes with derive helpers must come after derives`() {
val attr = Attribute("foo", isDeriveHelper = true)
val metadata = RustMetadata(
derives = setOf(RuntimeType.Debug),
additionalAttributes = listOf(Attribute.AllowDeprecated, attr),
visibility = Visibility.PUBLIC,
)
val sut = RustWriter.root()
metadata.render(sut)
sut.toString().shouldContain("#[allow(deprecated)]\n#[derive(std::fmt::Debug)]\n#[foo]")
}

@Test
fun `deprecated attribute without any field`() {
val sut = RustWriter.root()
Expand Down

0 comments on commit 93e0467

Please sign in to comment.