diff --git a/feature_tests/kotlin/somelib/src/main/kotlin/dev/diplomattest/somelib/Float64Vec.kt b/feature_tests/kotlin/somelib/src/main/kotlin/dev/diplomattest/somelib/Float64Vec.kt index 6e368cdbd..90bc70ce3 100644 --- a/feature_tests/kotlin/somelib/src/main/kotlin/dev/diplomattest/somelib/Float64Vec.kt +++ b/feature_tests/kotlin/somelib/src/main/kotlin/dev/diplomattest/somelib/Float64Vec.kt @@ -144,7 +144,7 @@ class Float64Vec internal constructor ( } - fun toString_(): String { + override fun toString(): String { val write = DW.lib.diplomat_buffer_write_create(0) val returnVal = lib.Float64Vec_to_string(handle, write); diff --git a/tool/src/kotlin/formatter.rs b/tool/src/kotlin/formatter.rs index 58fdb3d6d..93d2cecc4 100644 --- a/tool/src/kotlin/formatter.rs +++ b/tool/src/kotlin/formatter.rs @@ -16,10 +16,11 @@ pub(super) struct KotlinFormatter<'tcx> { docs_url_gen: &'tcx DocsUrlGenerator, } -const INVALID_METHOD_NAMES: &[&str] = &[ +const INVALID_RAW_METHOD_NAMES: &[&str] = &[ "new", "static", "default", "private", "internal", "toString", ]; const DISALLOWED_CORE_TYPES: &[&str] = &["Object", "String"]; +const OVERRIDE_METHOD_SIGS: &[&str] = &["fun toString(): String"]; impl<'tcx> KotlinFormatter<'tcx> { pub fn new( @@ -112,18 +113,37 @@ impl<'tcx> KotlinFormatter<'tcx> { } } - pub fn fmt_method_name<'a>(&self, method: &'a hir::Method) -> Cow<'a, str> { + pub fn fmt_method_name<'a>( + &self, + method: &'a hir::Method, + should_be_overridden: bool, + ) -> Cow<'a, str> { // TODO(#60): handle other keywords let name = method.name.as_str().to_lower_camel_case(); let name = method.attrs.rename.apply(name.into()); - if INVALID_METHOD_NAMES.contains(&&*name) { + if INVALID_RAW_METHOD_NAMES.contains(&&*name) && !should_be_overridden { format!("{name}_").into() } else { name } } + pub fn method_should_be_overridden<'a>( + &self, + method: &'a hir::Method, + params: &str, + return_type: &str, + ) -> bool { + let method_sig = format!( + "fun {}({}): {}", + &&*method.name.as_str().to_lower_camel_case(), + params, + return_type + ); + OVERRIDE_METHOD_SIGS.contains(&&*method_sig) + } + pub fn fmt_trait_method_name<'a>(&self, method: &'a hir::Callback) -> Cow<'a, str> { if method.name.is_none() { panic!("Trait methods need a name"); @@ -134,7 +154,7 @@ impl<'tcx> KotlinFormatter<'tcx> { } else { name.into() }; - if INVALID_METHOD_NAMES.contains(&&*name) { + if INVALID_RAW_METHOD_NAMES.contains(&&*name) { format!("{name}_").into() } else { name diff --git a/tool/src/kotlin/mod.rs b/tool/src/kotlin/mod.rs index 0782dfdd7..51b6e4e76 100644 --- a/tool/src/kotlin/mod.rs +++ b/tool/src/kotlin/mod.rs @@ -1188,11 +1188,23 @@ returnVal.option() ?: return null panic!("Can only have one iterable method per opaque struct") } } - _ => format!( - "fun {}({}): {return_ty}", - self.formatter.fmt_method_name(method), - params - ), + _ => { + let should_be_overridden = self.formatter.method_should_be_overridden( + method, + ¶ms, + &return_ty.to_string(), + ); + format!( + "{}fun {}({}): {return_ty}", + if should_be_overridden { + "override " + } else { + "" + }, + self.formatter.fmt_method_name(method, should_be_overridden), + params + ) + } }; MethodTpl {