Skip to content

Commit 3077e69

Browse files
committed
Auto merge of #17115 - leviska:json_is_not_rust_better_names, r=Veykril
Try to generate more meaningful names in json converter I just found out about rust-analyzer json converter, but I think it would be more convenient, if names were more useful, like using the names of the keys. Let's look at some realistic arbitrary json: ```json { "user": { "address": { "street": "Main St", "house": 3 }, "email": "[email protected]" } } ``` I think, new generated code is much easier to read and to edit, than the old: ```rust // Old struct Struct1{ house: i64, street: String } struct Struct2{ address: Struct1, email: String } struct Struct3{ user: Struct2 } // New struct Address1{ house: i64, street: String } struct User1{ address: Address1, email: String } struct Root1{ user: User1 } ``` Ideally, if we drop the numbers, I can see it being usable just as is (may be rename root) ```rust struct Address{ house: i64, street: String } struct User{ address: Address, email: String } struct Root{ user: User } ``` Sadly, we can't just drop them, because there can be multiple fields (recursive) with the same name, and we can't just easily retroactively add numbers if the name has 2 instances due to parsing being single pass. We could ignore the `1` and add number only if it's > 1, but I will leave this open to discussion and right now made it the simpler way In sum, even with numbers, I think this PR still helps in readability
2 parents 7baabfc + 029c710 commit 3077e69

File tree

1 file changed

+66
-18
lines changed

1 file changed

+66
-18
lines changed

crates/ide-diagnostics/src/handlers/json_is_not_rust.rs

Lines changed: 66 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use ide_db::{
77
helpers::mod_path_to_ast,
88
imports::insert_use::{insert_use, ImportScope},
99
source_change::SourceChangeBuilder,
10-
RootDatabase,
10+
FxHashMap, RootDatabase,
1111
};
1212
use itertools::Itertools;
1313
use stdx::{format_to, never};
@@ -22,15 +22,22 @@ use crate::{fix, Diagnostic, DiagnosticCode, DiagnosticsConfig, Severity};
2222
#[derive(Default)]
2323
struct State {
2424
result: String,
25-
struct_counts: usize,
2625
has_serialize: bool,
2726
has_deserialize: bool,
27+
names: FxHashMap<String, usize>,
2828
}
2929

3030
impl State {
31-
fn generate_new_name(&mut self) -> ast::Name {
32-
self.struct_counts += 1;
33-
make::name(&format!("Struct{}", self.struct_counts))
31+
fn generate_new_name(&mut self, name: &str) -> ast::Name {
32+
let name = stdx::to_camel_case(name);
33+
let count = if let Some(count) = self.names.get_mut(&name) {
34+
*count += 1;
35+
*count
36+
} else {
37+
self.names.insert(name.clone(), 1);
38+
1
39+
};
40+
make::name(&format!("{}{}", name, count))
3441
}
3542

3643
fn serde_derive(&self) -> String {
@@ -52,36 +59,42 @@ impl State {
5259
}
5360
}
5461

55-
fn build_struct(&mut self, value: &serde_json::Map<String, serde_json::Value>) -> ast::Type {
56-
let name = self.generate_new_name();
62+
fn build_struct(
63+
&mut self,
64+
name: &str,
65+
value: &serde_json::Map<String, serde_json::Value>,
66+
) -> ast::Type {
67+
let name = self.generate_new_name(name);
5768
let ty = make::ty(&name.to_string());
5869
let strukt = make::struct_(
5970
None,
6071
name,
6172
None,
6273
make::record_field_list(value.iter().sorted_unstable_by_key(|x| x.0).map(
63-
|(name, value)| make::record_field(None, make::name(name), self.type_of(value)),
74+
|(name, value)| {
75+
make::record_field(None, make::name(name), self.type_of(name, value))
76+
},
6477
))
6578
.into(),
6679
);
6780
format_to!(self.result, "{}{}\n", self.serde_derive(), strukt);
6881
ty
6982
}
7083

71-
fn type_of(&mut self, value: &serde_json::Value) -> ast::Type {
84+
fn type_of(&mut self, name: &str, value: &serde_json::Value) -> ast::Type {
7285
match value {
7386
serde_json::Value::Null => make::ty_unit(),
7487
serde_json::Value::Bool(_) => make::ty("bool"),
7588
serde_json::Value::Number(it) => make::ty(if it.is_i64() { "i64" } else { "f64" }),
7689
serde_json::Value::String(_) => make::ty("String"),
7790
serde_json::Value::Array(it) => {
7891
let ty = match it.iter().next() {
79-
Some(x) => self.type_of(x),
92+
Some(x) => self.type_of(name, x),
8093
None => make::ty_placeholder(),
8194
};
8295
make::ty(&format!("Vec<{ty}>"))
8396
}
84-
serde_json::Value::Object(x) => self.build_struct(x),
97+
serde_json::Value::Object(x) => self.build_struct(name, x),
8598
}
8699
}
87100
}
@@ -113,7 +126,7 @@ pub(crate) fn json_in_items(
113126
let serialize_resolved = scope_resolve("::serde::Serialize");
114127
state.has_deserialize = deserialize_resolved.is_some();
115128
state.has_serialize = serialize_resolved.is_some();
116-
state.build_struct(&it);
129+
state.build_struct("Root", &it);
117130
edit.insert(range.start(), state.result);
118131
acc.push(
119132
Diagnostic::new(
@@ -218,7 +231,7 @@ mod tests {
218231
}
219232
220233
#[derive(Serialize)]
221-
struct Struct1{ bar: f64, bay: i64, baz: (), r#box: bool, foo: String }
234+
struct Root1{ bar: f64, bay: i64, baz: (), r#box: bool, foo: String }
222235
223236
"#,
224237
);
@@ -237,9 +250,44 @@ mod tests {
237250
}
238251
"#,
239252
r#"
240-
struct Struct3{ }
241-
struct Struct2{ kind: String, value: Struct3 }
242-
struct Struct1{ bar: Struct2, foo: String }
253+
struct Value1{ }
254+
struct Bar1{ kind: String, value: Value1 }
255+
struct Root1{ bar: Bar1, foo: String }
256+
257+
"#,
258+
);
259+
}
260+
261+
#[test]
262+
fn naming() {
263+
check_fix(
264+
r#"
265+
{$0
266+
"user": {
267+
"address": {
268+
"street": "Main St",
269+
"house": 3
270+
},
271+
"email": "[email protected]"
272+
},
273+
"another_user": {
274+
"user": {
275+
"address": {
276+
"street": "Main St",
277+
"house": 3
278+
},
279+
"email": "[email protected]"
280+
}
281+
}
282+
}
283+
"#,
284+
r#"
285+
struct Address1{ house: i64, street: String }
286+
struct User1{ address: Address1, email: String }
287+
struct AnotherUser1{ user: User1 }
288+
struct Address2{ house: i64, street: String }
289+
struct User2{ address: Address2, email: String }
290+
struct Root1{ another_user: AnotherUser1, user: User2 }
243291
244292
"#,
245293
);
@@ -276,9 +324,9 @@ mod tests {
276324
use serde::Deserialize;
277325
278326
#[derive(Serialize, Deserialize)]
279-
struct Struct2{ x: i64, y: i64 }
327+
struct OfObject1{ x: i64, y: i64 }
280328
#[derive(Serialize, Deserialize)]
281-
struct Struct1{ empty: Vec<_>, nested: Vec<Vec<Vec<i64>>>, of_object: Vec<Struct2>, of_string: Vec<String> }
329+
struct Root1{ empty: Vec<_>, nested: Vec<Vec<Vec<i64>>>, of_object: Vec<OfObject1>, of_string: Vec<String> }
282330
283331
"#,
284332
);

0 commit comments

Comments
 (0)