Skip to content

Commit

Permalink
[Rust] harden against name collisions while generate cleaner rust code,
Browse files Browse the repository at this point in the history
fix #20337 (#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
  • Loading branch information
xMAC94x authored and mikefaille committed Jan 14, 2025
1 parent 09530b4 commit ca3a499
Show file tree
Hide file tree
Showing 68 changed files with 3,412 additions and 4,341 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ public abstract class AbstractRustCodegen extends DefaultCodegen implements Code

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

protected static final String VENDOR_EXTENSION_PARAM_IDENTIFIER = "x-rust-param-identifier";

protected List<String> charactersToAllow = Collections.singletonList("_");
protected Set<String> keywordsThatDoNotSupportRawIdentifiers = new HashSet<>(
Arrays.asList("super", "self", "Self", "extern", "crate"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,10 @@
import org.openapitools.codegen.CodegenModel;
import org.openapitools.codegen.CodegenOperation;
import org.openapitools.codegen.CodegenProperty;
import org.openapitools.codegen.CodegenParameter;
import org.openapitools.codegen.CodegenType;
import org.openapitools.codegen.SupportingFile;
import org.openapitools.codegen.VendorExtension;
import org.openapitools.codegen.meta.features.ClientModificationFeature;
import org.openapitools.codegen.meta.features.DocumentationFeature;
import org.openapitools.codegen.meta.features.GlobalFeature;
Expand Down Expand Up @@ -602,6 +604,25 @@ public void postProcessModelProperty(CodegenModel model, CodegenProperty propert
}
}

@Override
public void postProcessParameter(CodegenParameter parameter) {
super.postProcessParameter(parameter);
// in order to avoid name conflicts, we map parameters inside the functions
String inFunctionIdentifier = "";
if (this.useSingleRequestParameter) {
inFunctionIdentifier = "params." + parameter.paramName;
} else {
if (parameter.paramName.startsWith("r#")) {
inFunctionIdentifier = "p_" + parameter.paramName.substring(2);
} else {
inFunctionIdentifier = "p_" + parameter.paramName;
}
}
if (!parameter.vendorExtensions.containsKey(this.VENDOR_EXTENSION_PARAM_IDENTIFIER)) { // allow to overwrite this value
parameter.vendorExtensions.put(this.VENDOR_EXTENSION_PARAM_IDENTIFIER, inFunctionIdentifier);
}
}

@Override
public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List<ModelMap> allModels) {
OperationMap objectMap = objs.getOperations();
Expand Down Expand Up @@ -699,7 +720,7 @@ public String toDefaultValue(Schema p) {
@Override
protected ImmutableMap.Builder<String, Lambda> addMustacheLambdas() {
return super.addMustacheLambdas()
// Convert variable names to lifetime names.
// Convert variable names to lifetime names.
// Generally they are the same, but `#` is not valid in lifetime names.
// Rust uses `r#` prefix for variables that are also keywords.
.put("lifetimeName", new ReplaceAllLambda("^r#", "r_"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,26 @@ repository: {{.}}
publish_to: {{.}}
{{/pubPublishTo}}


environment:
sdk: '>={{#useJsonSerializable}}2.17.0{{/useJsonSerializable}}{{^useJsonSerializable}}2.15.0{{/useJsonSerializable}} <4.0.0'
sdk: '>={{^useJsonSerializable}}2.18.0{{/useJsonSerializable}}{{#useJsonSerializable}}3.5.0{{/useJsonSerializable}} <4.0.0'
dependencies:
dio: '^5.2.0'
dio: '^5.7.0'
{{#useBuiltValue}}
one_of: '>=1.5.0 <2.0.0'
one_of_serializer: '>=1.5.0 <2.0.0'
built_value: '>=8.4.0 <9.0.0'
built_collection: '>=5.1.1 <6.0.0'
{{/useBuiltValue}}
{{#useEquatable}}
equatable: '^2.0.5'
equatable: '^2.0.7'
{{/useEquatable}}
{{#useJsonSerializable}}
json_annotation: '^4.4.0'
json_annotation: '^4.9.0'
{{/useJsonSerializable}}
{{#useDateLibTimeMachine}}
time_machine: ^0.9.16
time_machine: ^0.9.17
{{/useDateLibTimeMachine}}
dev_dependencies:
Expand All @@ -37,6 +38,6 @@ dev_dependencies:
{{/useBuiltValue}}
{{#useJsonSerializable}}
build_runner: any
json_serializable: '^6.1.5'
json_serializable: '^6.9.3'
{{/useJsonSerializable}}
test: ^1.16.0
test: '^1.16.0'
206 changes: 100 additions & 106 deletions modules/openapi-generator/src/main/resources/rust/reqwest/api.mustache

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,11 @@ paths:
description: To test parameter names in upper case
schema:
type: string
- name: content
in: query
description: To test escaping of parameters in rust code works
schema:
type: string
responses:
'200':
description: successful operation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,30 +24,26 @@ pub enum ReproError {


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

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

let local_var_uri_str = format!("{}/repro", local_var_configuration.base_path);
let mut local_var_req_builder = local_var_client.request(reqwest::Method::POST, local_var_uri_str.as_str());

if let Some(ref local_var_user_agent) = local_var_configuration.user_agent {
local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone());
if let Some(ref user_agent) = configuration.user_agent {
req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
}

let local_var_req = local_var_req_builder.build()?;
let local_var_resp = local_var_client.execute(local_var_req)?;
let req = req_builder.build()?;
let resp = configuration.client.execute(req)?;

let local_var_status = local_var_resp.status();
let status = resp.status();

if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
let local_var_content = local_var_resp.text()?;
serde_json::from_str(&local_var_content).map_err(Error::from)
if !status.is_client_error() && !status.is_server_error() {
let content = resp.text()?;
serde_json::from_str(&content).map_err(Error::from)
} else {
let local_var_content = local_var_resp.text()?;
let local_var_entity: Option<ReproError> = serde_json::from_str(&local_var_content).ok();
let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity };
Err(Error::ResponseError(local_var_error))
let content = resp.text()?;
let entity: Option<ReproError> = serde_json::from_str(&content).ok();
Err(Error::ResponseError(ResponseContent { status, content, entity }))
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -24,29 +24,27 @@ pub enum DemoColorGetError {


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

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

let local_var_uri_str = format!("{}/demo/{color}", local_var_configuration.base_path, color=color.to_string());
let mut local_var_req_builder = local_var_client.request(reqwest::Method::GET, local_var_uri_str.as_str());

if let Some(ref local_var_user_agent) = local_var_configuration.user_agent {
local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone());
if let Some(ref user_agent) = configuration.user_agent {
req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
}

let local_var_req = local_var_req_builder.build()?;
let local_var_resp = local_var_client.execute(local_var_req).await?;
let req = req_builder.build()?;
let resp = configuration.client.execute(req).await?;

let local_var_status = local_var_resp.status();
let status = resp.status();

if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
if !status.is_client_error() && !status.is_server_error() {
Ok(())
} else {
let local_var_content = local_var_resp.text().await?;
let local_var_entity: Option<DemoColorGetError> = serde_json::from_str(&local_var_content).ok();
let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity };
Err(Error::ResponseError(local_var_error))
let content = resp.text().await?;
let entity: Option<DemoColorGetError> = serde_json::from_str(&content).ok();
Err(Error::ResponseError(ResponseContent { status, content, entity }))
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -31,58 +31,52 @@ pub enum GetStateError {


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

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

let local_var_uri_str = format!("{}/state", local_var_configuration.base_path);
let mut local_var_req_builder = local_var_client.request(reqwest::Method::POST, local_var_uri_str.as_str());

if let Some(ref local_var_user_agent) = local_var_configuration.user_agent {
local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone());
if let Some(ref user_agent) = configuration.user_agent {
req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
}
local_var_req_builder = local_var_req_builder.json(&create_state_request);
req_builder = req_builder.json(&p_create_state_request);

let local_var_req = local_var_req_builder.build()?;
let local_var_resp = local_var_client.execute(local_var_req)?;
let req = req_builder.build()?;
let resp = configuration.client.execute(req)?;

let local_var_status = local_var_resp.status();
let status = resp.status();

if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
if !status.is_client_error() && !status.is_server_error() {
Ok(())
} else {
let local_var_content = local_var_resp.text()?;
let local_var_entity: Option<CreateStateError> = serde_json::from_str(&local_var_content).ok();
let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity };
Err(Error::ResponseError(local_var_error))
let content = resp.text()?;
let entity: Option<CreateStateError> = serde_json::from_str(&content).ok();
Err(Error::ResponseError(ResponseContent { status, content, entity }))
}
}

pub fn get_state(configuration: &configuration::Configuration, ) -> Result<models::GetState200Response, Error<GetStateError>> {
let local_var_configuration = configuration;

let local_var_client = &local_var_configuration.client;

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

if let Some(ref local_var_user_agent) = local_var_configuration.user_agent {
local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone());
if let Some(ref user_agent) = configuration.user_agent {
req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
}

let local_var_req = local_var_req_builder.build()?;
let local_var_resp = local_var_client.execute(local_var_req)?;
let req = req_builder.build()?;
let resp = configuration.client.execute(req)?;

let local_var_status = local_var_resp.status();
let status = resp.status();

if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
let local_var_content = local_var_resp.text()?;
serde_json::from_str(&local_var_content).map_err(Error::from)
if !status.is_client_error() && !status.is_server_error() {
let content = resp.text()?;
serde_json::from_str(&content).map_err(Error::from)
} else {
let local_var_content = local_var_resp.text()?;
let local_var_entity: Option<GetStateError> = serde_json::from_str(&local_var_content).ok();
let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity };
Err(Error::ResponseError(local_var_error))
let content = resp.text()?;
let entity: Option<GetStateError> = serde_json::from_str(&content).ok();
Err(Error::ResponseError(ResponseContent { status, content, entity }))
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -24,30 +24,26 @@ pub enum EndpointGetError {


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

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

let local_var_uri_str = format!("{}/endpoint", local_var_configuration.base_path);
let mut local_var_req_builder = local_var_client.request(reqwest::Method::GET, local_var_uri_str.as_str());

if let Some(ref local_var_user_agent) = local_var_configuration.user_agent {
local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone());
if let Some(ref user_agent) = configuration.user_agent {
req_builder = req_builder.header(reqwest::header::USER_AGENT, user_agent.clone());
}

let local_var_req = local_var_req_builder.build()?;
let local_var_resp = local_var_client.execute(local_var_req)?;
let req = req_builder.build()?;
let resp = configuration.client.execute(req)?;

let local_var_status = local_var_resp.status();
let status = resp.status();

if !local_var_status.is_client_error() && !local_var_status.is_server_error() {
let local_var_content = local_var_resp.text()?;
serde_json::from_str(&local_var_content).map_err(Error::from)
if !status.is_client_error() && !status.is_server_error() {
let content = resp.text()?;
serde_json::from_str(&content).map_err(Error::from)
} else {
let local_var_content = local_var_resp.text()?;
let local_var_entity: Option<EndpointGetError> = serde_json::from_str(&local_var_content).ok();
let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity };
Err(Error::ResponseError(local_var_error))
let content = resp.text()?;
let entity: Option<EndpointGetError> = serde_json::from_str(&content).ok();
Err(Error::ResponseError(ResponseContent { status, content, entity }))
}
}

Loading

0 comments on commit ca3a499

Please sign in to comment.