Skip to content

Commit ca3a499

Browse files
xMAC94xmikefaille
authored andcommitted
[Rust] harden against name collisions while generate cleaner rust code, fix OpenAPITools#20337 (OpenAPITools#20396)
* prevent all name clashes by using a prefix for all parameters, this way they CANNOT clash with anything locally, as our hardcoded stuff in mustache files doesnt start with "p_" , when using the grouped option, we just use the params directly and dont unpack the variables at all, prevending furthur name clashes. * get rid of "local_var" prefix, now that we no longer clash with paramater names * fix a typo and remove the r# generated to the paramName when we create the identifier * java code formatting and added a fake-endpoint parameter test * update rust samples
1 parent 09530b4 commit ca3a499

File tree

68 files changed

+3412
-4341
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

68 files changed

+3412
-4341
lines changed

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractRustCodegen.java

+2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ public abstract class AbstractRustCodegen extends DefaultCodegen implements Code
2121

2222
private final Logger LOGGER = LoggerFactory.getLogger(AbstractRustCodegen.class);
2323

24+
protected static final String VENDOR_EXTENSION_PARAM_IDENTIFIER = "x-rust-param-identifier";
25+
2426
protected List<String> charactersToAllow = Collections.singletonList("_");
2527
protected Set<String> keywordsThatDoNotSupportRawIdentifiers = new HashSet<>(
2628
Arrays.asList("super", "self", "Self", "extern", "crate"));

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustClientCodegen.java

+22-1
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,10 @@
3939
import org.openapitools.codegen.CodegenModel;
4040
import org.openapitools.codegen.CodegenOperation;
4141
import org.openapitools.codegen.CodegenProperty;
42+
import org.openapitools.codegen.CodegenParameter;
4243
import org.openapitools.codegen.CodegenType;
4344
import org.openapitools.codegen.SupportingFile;
45+
import org.openapitools.codegen.VendorExtension;
4446
import org.openapitools.codegen.meta.features.ClientModificationFeature;
4547
import org.openapitools.codegen.meta.features.DocumentationFeature;
4648
import org.openapitools.codegen.meta.features.GlobalFeature;
@@ -602,6 +604,25 @@ public void postProcessModelProperty(CodegenModel model, CodegenProperty propert
602604
}
603605
}
604606

607+
@Override
608+
public void postProcessParameter(CodegenParameter parameter) {
609+
super.postProcessParameter(parameter);
610+
// in order to avoid name conflicts, we map parameters inside the functions
611+
String inFunctionIdentifier = "";
612+
if (this.useSingleRequestParameter) {
613+
inFunctionIdentifier = "params." + parameter.paramName;
614+
} else {
615+
if (parameter.paramName.startsWith("r#")) {
616+
inFunctionIdentifier = "p_" + parameter.paramName.substring(2);
617+
} else {
618+
inFunctionIdentifier = "p_" + parameter.paramName;
619+
}
620+
}
621+
if (!parameter.vendorExtensions.containsKey(this.VENDOR_EXTENSION_PARAM_IDENTIFIER)) { // allow to overwrite this value
622+
parameter.vendorExtensions.put(this.VENDOR_EXTENSION_PARAM_IDENTIFIER, inFunctionIdentifier);
623+
}
624+
}
625+
605626
@Override
606627
public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List<ModelMap> allModels) {
607628
OperationMap objectMap = objs.getOperations();
@@ -699,7 +720,7 @@ public String toDefaultValue(Schema p) {
699720
@Override
700721
protected ImmutableMap.Builder<String, Lambda> addMustacheLambdas() {
701722
return super.addMustacheLambdas()
702-
// Convert variable names to lifetime names.
723+
// Convert variable names to lifetime names.
703724
// Generally they are the same, but `#` is not valid in lifetime names.
704725
// Rust uses `r#` prefix for variables that are also keywords.
705726
.put("lifetimeName", new ReplaceAllLambda("^r#", "r_"));

modules/openapi-generator/src/main/resources/dart/libraries/dio/pubspec.mustache

+8-7
Original file line numberDiff line numberDiff line change
@@ -9,25 +9,26 @@ repository: {{.}}
99
publish_to: {{.}}
1010
{{/pubPublishTo}}
1111

12+
1213
environment:
13-
sdk: '>={{#useJsonSerializable}}2.17.0{{/useJsonSerializable}}{{^useJsonSerializable}}2.15.0{{/useJsonSerializable}} <4.0.0'
14+
sdk: '>={{^useJsonSerializable}}2.18.0{{/useJsonSerializable}}{{#useJsonSerializable}}3.5.0{{/useJsonSerializable}} <4.0.0'
1415
1516
dependencies:
16-
dio: '^5.2.0'
17+
dio: '^5.7.0'
1718
{{#useBuiltValue}}
1819
one_of: '>=1.5.0 <2.0.0'
1920
one_of_serializer: '>=1.5.0 <2.0.0'
2021
built_value: '>=8.4.0 <9.0.0'
2122
built_collection: '>=5.1.1 <6.0.0'
2223
{{/useBuiltValue}}
2324
{{#useEquatable}}
24-
equatable: '^2.0.5'
25+
equatable: '^2.0.7'
2526
{{/useEquatable}}
2627
{{#useJsonSerializable}}
27-
json_annotation: '^4.4.0'
28+
json_annotation: '^4.9.0'
2829
{{/useJsonSerializable}}
2930
{{#useDateLibTimeMachine}}
30-
time_machine: ^0.9.16
31+
time_machine: ^0.9.17
3132
{{/useDateLibTimeMachine}}
3233
3334
dev_dependencies:
@@ -37,6 +38,6 @@ dev_dependencies:
3738
{{/useBuiltValue}}
3839
{{#useJsonSerializable}}
3940
build_runner: any
40-
json_serializable: '^6.1.5'
41+
json_serializable: '^6.9.3'
4142
{{/useJsonSerializable}}
42-
test: ^1.16.0
43+
test: '^1.16.0'

modules/openapi-generator/src/main/resources/rust/reqwest/api.mustache

+100-106
Large diffs are not rendered by default.

modules/openapi-generator/src/test/resources/3_0/rust/petstore.yaml

+5
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,11 @@ paths:
608608
description: To test parameter names in upper case
609609
schema:
610610
type: string
611+
- name: content
612+
in: query
613+
description: To test escaping of parameters in rust code works
614+
schema:
615+
type: string
611616
responses:
612617
'200':
613618
description: successful operation

samples/client/others/rust/reqwest-regression-16119/src/apis/default_api.rs

+13-17
Original file line numberDiff line numberDiff line change
@@ -24,30 +24,26 @@ pub enum ReproError {
2424

2525

2626
pub fn repro(configuration: &configuration::Configuration, ) -> Result<models::Parent, Error<ReproError>> {
27-
let local_var_configuration = configuration;
2827

29-
let local_var_client = &local_var_configuration.client;
28+
let uri_str = format!("{}/repro", configuration.base_path);
29+
let mut req_builder = configuration.client.request(reqwest::Method::POST, &uri_str);
3030

31-
let local_var_uri_str = format!("{}/repro", local_var_configuration.base_path);
32-
let mut local_var_req_builder = local_var_client.request(reqwest::Method::POST, local_var_uri_str.as_str());
33-
34-
if let Some(ref local_var_user_agent) = local_var_configuration.user_agent {
35-
local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone());
31+
if let Some(ref user_agent) = configuration.user_agent {
32+
req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
3633
}
3734

38-
let local_var_req = local_var_req_builder.build()?;
39-
let local_var_resp = local_var_client.execute(local_var_req)?;
35+
let req = req_builder.build()?;
36+
let resp = configuration.client.execute(req)?;
4037

41-
let local_var_status = local_var_resp.status();
38+
let status = resp.status();
4239

43-
if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
44-
let local_var_content = local_var_resp.text()?;
45-
serde_json::from_str(&local_var_content).map_err(Error::from)
40+
if !status.is_client_error() && !status.is_server_error() {
41+
let content = resp.text()?;
42+
serde_json::from_str(&content).map_err(Error::from)
4643
} else {
47-
let local_var_content = local_var_resp.text()?;
48-
let local_var_entity: Option<ReproError> = serde_json::from_str(&local_var_content).ok();
49-
let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity };
50-
Err(Error::ResponseError(local_var_error))
44+
let content = resp.text()?;
45+
let entity: Option<ReproError> = serde_json::from_str(&content).ok();
46+
Err(Error::ResponseError(ResponseContent { status, content, entity }))
5147
}
5248
}
5349

samples/client/others/rust/reqwest/api-with-ref-param/src/apis/default_api.rs

+13-15
Original file line numberDiff line numberDiff line change
@@ -24,29 +24,27 @@ pub enum DemoColorGetError {
2424

2525

2626
pub async fn demo_color_get(configuration: &configuration::Configuration, color: models::Color) -> Result<(), Error<DemoColorGetError>> {
27-
let local_var_configuration = configuration;
27+
// add a prefix to parameters to efficiently prevent name collisions
28+
let p_color = color;
2829

29-
let local_var_client = &local_var_configuration.client;
30+
let uri_str = format!("{}/demo/{color}", configuration.base_path, color=p_color.to_string());
31+
let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
3032

31-
let local_var_uri_str = format!("{}/demo/{color}", local_var_configuration.base_path, color=color.to_string());
32-
let mut local_var_req_builder = local_var_client.request(reqwest::Method::GET, local_var_uri_str.as_str());
33-
34-
if let Some(ref local_var_user_agent) = local_var_configuration.user_agent {
35-
local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone());
33+
if let Some(ref user_agent) = configuration.user_agent {
34+
req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
3635
}
3736

38-
let local_var_req = local_var_req_builder.build()?;
39-
let local_var_resp = local_var_client.execute(local_var_req).await?;
37+
let req = req_builder.build()?;
38+
let resp = configuration.client.execute(req).await?;
4039

41-
let local_var_status = local_var_resp.status();
40+
let status = resp.status();
4241

43-
if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
42+
if !status.is_client_error() && !status.is_server_error() {
4443
Ok(())
4544
} else {
46-
let local_var_content = local_var_resp.text().await?;
47-
let local_var_entity: Option<DemoColorGetError> = serde_json::from_str(&local_var_content).ok();
48-
let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity };
49-
Err(Error::ResponseError(local_var_error))
45+
let content = resp.text().await?;
46+
let entity: Option<DemoColorGetError> = serde_json::from_str(&content).ok();
47+
Err(Error::ResponseError(ResponseContent { status, content, entity }))
5048
}
5149
}
5250

samples/client/others/rust/reqwest/composed-oneof/src/apis/default_api.rs

+27-33
Original file line numberDiff line numberDiff line change
@@ -31,58 +31,52 @@ pub enum GetStateError {
3131

3232

3333
pub fn create_state(configuration: &configuration::Configuration, create_state_request: models::CreateStateRequest) -> Result<(), Error<CreateStateError>> {
34-
let local_var_configuration = configuration;
34+
// add a prefix to parameters to efficiently prevent name collisions
35+
let p_create_state_request = create_state_request;
3536

36-
let local_var_client = &local_var_configuration.client;
37+
let uri_str = format!("{}/state", configuration.base_path);
38+
let mut req_builder = configuration.client.request(reqwest::Method::POST, &uri_str);
3739

38-
let local_var_uri_str = format!("{}/state", local_var_configuration.base_path);
39-
let mut local_var_req_builder = local_var_client.request(reqwest::Method::POST, local_var_uri_str.as_str());
40-
41-
if let Some(ref local_var_user_agent) = local_var_configuration.user_agent {
42-
local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone());
40+
if let Some(ref user_agent) = configuration.user_agent {
41+
req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
4342
}
44-
local_var_req_builder = local_var_req_builder.json(&create_state_request);
43+
req_builder = req_builder.json(&p_create_state_request);
4544

46-
let local_var_req = local_var_req_builder.build()?;
47-
let local_var_resp = local_var_client.execute(local_var_req)?;
45+
let req = req_builder.build()?;
46+
let resp = configuration.client.execute(req)?;
4847

49-
let local_var_status = local_var_resp.status();
48+
let status = resp.status();
5049

51-
if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
50+
if !status.is_client_error() && !status.is_server_error() {
5251
Ok(())
5352
} else {
54-
let local_var_content = local_var_resp.text()?;
55-
let local_var_entity: Option<CreateStateError> = serde_json::from_str(&local_var_content).ok();
56-
let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity };
57-
Err(Error::ResponseError(local_var_error))
53+
let content = resp.text()?;
54+
let entity: Option<CreateStateError> = serde_json::from_str(&content).ok();
55+
Err(Error::ResponseError(ResponseContent { status, content, entity }))
5856
}
5957
}
6058

6159
pub fn get_state(configuration: &configuration::Configuration, ) -> Result<models::GetState200Response, Error<GetStateError>> {
62-
let local_var_configuration = configuration;
63-
64-
let local_var_client = &local_var_configuration.client;
6560

66-
let local_var_uri_str = format!("{}/state", local_var_configuration.base_path);
67-
let mut local_var_req_builder = local_var_client.request(reqwest::Method::GET, local_var_uri_str.as_str());
61+
let uri_str = format!("{}/state", configuration.base_path);
62+
let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
6863

69-
if let Some(ref local_var_user_agent) = local_var_configuration.user_agent {
70-
local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone());
64+
if let Some(ref user_agent) = configuration.user_agent {
65+
req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
7166
}
7267

73-
let local_var_req = local_var_req_builder.build()?;
74-
let local_var_resp = local_var_client.execute(local_var_req)?;
68+
let req = req_builder.build()?;
69+
let resp = configuration.client.execute(req)?;
7570

76-
let local_var_status = local_var_resp.status();
71+
let status = resp.status();
7772

78-
if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
79-
let local_var_content = local_var_resp.text()?;
80-
serde_json::from_str(&local_var_content).map_err(Error::from)
73+
if !status.is_client_error() && !status.is_server_error() {
74+
let content = resp.text()?;
75+
serde_json::from_str(&content).map_err(Error::from)
8176
} else {
82-
let local_var_content = local_var_resp.text()?;
83-
let local_var_entity: Option<GetStateError> = serde_json::from_str(&local_var_content).ok();
84-
let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity };
85-
Err(Error::ResponseError(local_var_error))
77+
let content = resp.text()?;
78+
let entity: Option<GetStateError> = serde_json::from_str(&content).ok();
79+
Err(Error::ResponseError(ResponseContent { status, content, entity }))
8680
}
8781
}
8882

samples/client/others/rust/reqwest/emptyObject/src/apis/default_api.rs

+13-17
Original file line numberDiff line numberDiff line change
@@ -24,30 +24,26 @@ pub enum EndpointGetError {
2424

2525

2626
pub fn endpoint_get(configuration: &configuration::Configuration, ) -> Result<models::EmptyObject, Error<EndpointGetError>> {
27-
let local_var_configuration = configuration;
2827

29-
let local_var_client = &local_var_configuration.client;
28+
let uri_str = format!("{}/endpoint", configuration.base_path);
29+
let mut req_builder = configuration.client.request(reqwest::Method::GET, &uri_str);
3030

31-
let local_var_uri_str = format!("{}/endpoint", local_var_configuration.base_path);
32-
let mut local_var_req_builder = local_var_client.request(reqwest::Method::GET, local_var_uri_str.as_str());
33-
34-
if let Some(ref local_var_user_agent) = local_var_configuration.user_agent {
35-
local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone());
31+
if let Some(ref user_agent) = configuration.user_agent {
32+
req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
3633
}
3734

38-
let local_var_req = local_var_req_builder.build()?;
39-
let local_var_resp = local_var_client.execute(local_var_req)?;
35+
let req = req_builder.build()?;
36+
let resp = configuration.client.execute(req)?;
4037

41-
let local_var_status = local_var_resp.status();
38+
let status = resp.status();
4239

43-
if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
44-
let local_var_content = local_var_resp.text()?;
45-
serde_json::from_str(&local_var_content).map_err(Error::from)
40+
if !status.is_client_error() && !status.is_server_error() {
41+
let content = resp.text()?;
42+
serde_json::from_str(&content).map_err(Error::from)
4643
} else {
47-
let local_var_content = local_var_resp.text()?;
48-
let local_var_entity: Option<EndpointGetError> = serde_json::from_str(&local_var_content).ok();
49-
let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity };
50-
Err(Error::ResponseError(local_var_error))
44+
let content = resp.text()?;
45+
let entity: Option<EndpointGetError> = serde_json::from_str(&content).ok();
46+
Err(Error::ResponseError(ResponseContent { status, content, entity }))
5147
}
5248
}
5349

0 commit comments

Comments
 (0)