Repository: intellij-rust/intellij-rust
Issue: Add missing fields silently fails for structs with raw identifiers for fields

<!--
Hello and thank you for the issue!
If you would like to report a bug, we have added some points below that you can fill out.
Feel free to remove all the irrelevant text to request a new feature.
-->

## Environment

* **IntelliJ Rust plugin version:** 0.2.114.2151-193
* **Rust toolchain version:** rustc 1.40.0 (73528e339 2019-12-16)
* **IDE name and version:** CL-193.6015.37
* **Operating system:** Windows 10(amd64) v10.0

## Problem description

Given this struct definition:

```rust
use std::os::raw::{c_float, c_int};

pub struct MplaneT
{
    dist: c_float,
    r#type: c_int,
   signbits: c_int,
}
```
...the add missing fields helper will stop at dist and  you'll end up with this:

```rust
impl Default for MplaneT {
    fn default() -> Self {
        Self {
            dist: 0.0,
        }
    }
}
```

The r# syntax is used in rust to escape the names of fields that contain keywords, which is very important for ffi compatibility:

https://doc.rust-lang.org/book/appendix-01-keywords.html
"Raw identifiers are the syntax that lets you use keywords where they wouldn’t normally be allowed. You use a raw identifier by prefixing a keyword with r#."

Submitted to CLion bug tracker as https://youtrack.jetbrains.com/issue/CPP-18787
## Steps to reproduce

<!--
Please include as much of your codebase as needed to reproduce the error.
If the relevant files are large, please provide a link to a public repository or a [Gist](https://gist.github.com/).
-->


Changed files:
src/main/kotlin/org/rust/lang/core/psi/RsDefaultValueBuilder.kt, src/test/kotlin/org/rust/ide/annotator/fixes/AddStructFieldsFixTest.kt

diff --git a/src/main/kotlin/org/rust/lang/core/psi/RsDefaultValueBuilder.kt b/src/main/kotlin/org/rust/lang/core/psi/RsDefaultValueBuilder.kt
index 091c8dd57..506ef966c 100644
--- a/src/main/kotlin/org/rust/lang/core/psi/RsDefaultValueBuilder.kt
+++ b/src/main/kotlin/org/rust/lang/core/psi/RsDefaultValueBuilder.kt
@@ -160,15 +160,16 @@ class RsDefaultValueBuilder(
         val type = fieldDecl.typeReference?.type ?: return null
 
         val binding = bindings[name] ?: return null
+        val escapedName = escapeFieldName(fieldDecl) ?: return null
         return when {
             type == binding.type -> {
-                val field = psiFactory.createStructLiteralField(name, psiFactory.createExpression(name))
+                val field = psiFactory.createStructLiteralField(escapedName, psiFactory.createExpression(escapedName))
                 RsFieldInitShorthandInspection.applyShorthandInit(field)
                 field
             }
             isRefContainer(type, binding.type) -> {
-                val expr = buildReference(type, psiFactory.createExpression(name))
-                psiFactory.createStructLiteralField(name, expr)
+                val expr = buildReference(type, psiFactory.createExpression(escapedName))
+                psiFactory.createStructLiteralField(escapedName, expr)
             }
             else -> null
         }
@@ -232,8 +233,18 @@ class RsDefaultValueBuilder(
         return null
     }
 
+    private fun escapeFieldName(fieldDecl: RsFieldDecl): String? {
+        val name = fieldDecl.name ?: return null
+
+        // Tuple structs field names are integers and we don't want to escape them
+        return if (name.all { it.isDigit() }) {
+            name
+        }
+        else fieldDecl.name?.escapeIdentifierIfNeeded()
+    }
+
     private fun specializedCreateStructLiteralField(fieldDecl: RsFieldDecl, bindings: Map<String, RsPatBinding>): RsStructLiteralField? {
-        val fieldName = fieldDecl.name ?: return null
+        val fieldName = escapeFieldName(fieldDecl) ?: return null
         val fieldType = fieldDecl.typeReference?.type ?: return null
         val fieldLiteral = buildFor(fieldType, bindings)
         return psiFactory.createStructLiteralField(fieldName, fieldLiteral)
diff --git a/src/test/kotlin/org/rust/ide/annotator/fixes/AddStructFieldsFixTest.kt b/src/test/kotlin/org/rust/ide/annotator/fixes/AddStructFieldsFixTest.kt
index cbb0e92a5..394d8a6fd 100644
--- a/src/test/kotlin/org/rust/ide/annotator/fixes/AddStructFieldsFixTest.kt
+++ b/src/test/kotlin/org/rust/ide/annotator/fixes/AddStructFieldsFixTest.kt
@@ -659,6 +659,54 @@ class AddStructFieldsFixTest : RsAnnotatorTestBase(RsExpressionAnnotator::class)
         }
     """)
 
+    fun `test raw identifier field`() = checkBothQuickFix("""
+        struct S { r#type: i32 }
+
+        fn main() {
+            <error>S</error> { /*caret*/ };
+        }
+    """, """
+        struct S { r#type: i32 }
+
+        fn main() {
+            S { r#type: 0/*caret*/ };
+        }
+    """)
+
+    fun `test raw identifier field local variable`() = checkBothQuickFix("""
+        struct S { r#type: i32 }
+
+        fn main() {
+            let r#type: i32 = 0;
+            <error>S</error> { /*caret*/ };
+        }
+    """, """
+        struct S { r#type: i32 }
+
+        fn main() {
+            let r#type: i32 = 0;
+            S { r#type };
+        }
+    """)
+
+    fun `test raw identifier field unnecessary escape`() = checkBothQuickFix("""
+        struct S { r#foo: i32, bar: i32 }
+
+        fn main() {
+            let foo: i32 = 0;
+            let r#bar: i32 = 0;
+            <error>S</error> { /*caret*/ };
+        }
+    """, """
+        struct S { r#foo: i32, bar: i32 }
+
+        fn main() {
+            let foo: i32 = 0;
+            let r#bar: i32 = 0;
+            S { foo, bar };
+        }
+    """)
+
     private fun checkBothQuickFix(@Language("Rust") before: String, @Language("Rust") after: String) {
         checkFixByText("Add missing fields", before, after)
         checkFixByText("Recursively add missing fields", before, after)