Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Respect java.lang.Clonable trait and throw exception on clone when it's missing #3579

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion javalib/src/main/scala/java/util/regex/Matcher.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ object Matcher {
final class Matcher private[regex] (
var _pattern: Pattern,
var _inputSequence: CharSequence
) extends MatchResult {
) extends MatchResult
with Cloneable {

private val underlying = new rMatcher(_pattern.compiled, _inputSequence)

Expand Down
19 changes: 12 additions & 7 deletions nativelib/src/main/scala/java/lang/Object.scala
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,18 @@ class _Object {
addr.toInt ^ (addr >> 32).toInt
}

protected def __clone(): _Object = {
val cls = __getClass()
val size = cls.size.toUSize
val clone = GC.alloc(cls.asInstanceOf[Class[_]], size)
val src = castObjectToRawPtr(this)
libc.memcpy(clone, src, size)
castRawPtrToObject(clone).asInstanceOf[_Object]
protected def __clone(): _Object = this match {
case _: Cloneable =>
val cls = __getClass()
val size = cls.size.toUSize
val clone = GC.alloc(cls.asInstanceOf[Class[_]], size)
val src = castObjectToRawPtr(this)
libc.memcpy(clone, src, size)
castRawPtrToObject(clone).asInstanceOf[_Object]
case _ =>
throw new CloneNotSupportedException(
"Doesn't implement Cloneable interface!"
)
}

protected def __finalize(): Unit = ()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package org.scalanative.testsuite.javalib.lang

import java.lang._

import org.junit.{Ignore, Test}
import org.junit.Assert._

class CloneableTest {

class Foo(val x: Int, val y: String) {
override def clone(): Foo = super.clone().asInstanceOf[Foo]
}
class CloneableFoo(val x: Int, val y: String) extends Cloneable() {
override def clone(): CloneableFoo =
super.clone().asInstanceOf[CloneableFoo]
}

@Test def isNotClonable(): Unit = {
assertThrows(
classOf[CloneNotSupportedException],
() => (new Foo(42, "*").clone())
)
}

@Test def isClonable(): Unit = {
val instance = new CloneableFoo(42, "*")
val clone = instance.clone()
assertEquals(instance.getClass(), clone.getClass())
assertEquals(instance.x, clone.x)
assertEquals(instance.y, clone.y)
assertNotSame(instance, clone)
}
}
4 changes: 2 additions & 2 deletions unit-tests/shared/src/test/scala/scala/ObjectCloneTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import org.junit.Assert._

class ObjectCloneTest {

case class I(var i: Int) {
case class I(var i: Int) extends Cloneable {
def copy(): I = this.clone().asInstanceOf[I]
}

Expand All @@ -19,7 +19,7 @@ class ObjectCloneTest {
assertTrue(clone.i == 123)
}

case class Arr(val arr: Array[Int]) {
case class Arr(val arr: Array[Int]) extends Cloneable {
def copy(): Arr = this.clone().asInstanceOf[Arr]
}

Expand Down