diff --git a/build.sbt b/build.sbt
index 9ba74983..a2019981 100644
--- a/build.sbt
+++ b/build.sbt
@@ -1,4 +1,5 @@
-import sbtcrossproject.CrossPlugin.autoImport.{crossProject, CrossType}
+import com.typesafe.tools.mima.core._
+import sbtcrossproject.CrossPlugin.autoImport.{CrossType, crossProject}
publish / skip := true // root project
@@ -68,6 +69,51 @@ lazy val xml = crossProject(JSPlatform, JVMPlatform, NativePlatform)
//import com.typesafe.tools.mima.core.{}
//import com.typesafe.tools.mima.core.ProblemFilters
Seq( // exclusions for all Scala versions
+ // new method in `Node` with return type `immutable.Seq`
+ ProblemFilters.exclude[ReversedMissingMethodProblem]("scala.xml.Node.child"),
+
+ // these used to be declared methods, but are now bridges without generic signature
+ ProblemFilters.exclude[IncompatibleSignatureProblem]("scala.xml.Node.nonEmptyChildren"),
+ ProblemFilters.exclude[IncompatibleSignatureProblem]("scala.xml.Group.child"),
+ ProblemFilters.exclude[IncompatibleSignatureProblem]("scala.xml.SpecialNode.child"),
+
+ // new methods with return type immutable.Seq
+ ProblemFilters.exclude[ReversedMissingMethodProblem]("scala.xml.Attribute.apply"),
+ ProblemFilters.exclude[ReversedMissingMethodProblem]("scala.xml.Attribute.value"),
+ ProblemFilters.exclude[ReversedMissingMethodProblem]("scala.xml.MetaData.apply"),
+ ProblemFilters.exclude[ReversedMissingMethodProblem]("scala.xml.MetaData.value"),
+ ProblemFilters.exclude[ReversedMissingMethodProblem]("scala.xml.NodeSeq.theSeq"),
+
+ // Synthetic static accessors (for Java interop) have a changed return type
+ ProblemFilters.exclude[IncompatibleResultTypeProblem]("scala.xml.Null.apply"),
+ ProblemFilters.exclude[IncompatibleResultTypeProblem]("scala.xml.Null.value"),
+ ProblemFilters.exclude[IncompatibleResultTypeProblem]("scala.xml.Utility.parseAttributeValue"),
+ ProblemFilters.exclude[IncompatibleResultTypeProblem]("scala.xml.Utility.trimProper"),
+
+ // used to be a declared method, now a bridge without generic signature
+ ProblemFilters.exclude[IncompatibleSignatureProblem]("scala.xml.MetaData.apply"),
+ ProblemFilters.exclude[IncompatibleSignatureProblem]("scala.xml.Null.apply"),
+ ProblemFilters.exclude[IncompatibleSignatureProblem]("scala.xml.Null.value"),
+ ProblemFilters.exclude[IncompatibleSignatureProblem]("scala.xml.PrefixedAttribute.apply"),
+ ProblemFilters.exclude[IncompatibleSignatureProblem]("scala.xml.PrefixedAttribute.value"),
+ ProblemFilters.exclude[IncompatibleSignatureProblem]("scala.xml.UnprefixedAttribute.apply"),
+ ProblemFilters.exclude[IncompatibleSignatureProblem]("scala.xml.UnprefixedAttribute.value"),
+ ProblemFilters.exclude[IncompatibleSignatureProblem]("scala.xml.Document.theSeq"),
+ ProblemFilters.exclude[IncompatibleSignatureProblem]("scala.xml.Group.theSeq"),
+ ProblemFilters.exclude[IncompatibleSignatureProblem]("scala.xml.Node.theSeq"),
+ ProblemFilters.exclude[IncompatibleSignatureProblem]("scala.xml.TextBuffer.toText"),
+ ProblemFilters.exclude[IncompatibleSignatureProblem]("scala.xml.Utility.trimProper"),
+ ProblemFilters.exclude[IncompatibleSignatureProblem]("scala.xml.Utility.parseAttributeValue"),
+
+ // Option[c.Seq] => Option[i.Seq] results in a changed generic signature
+ ProblemFilters.exclude[IncompatibleSignatureProblem]("scala.xml.MetaData.get"),
+ ProblemFilters.exclude[IncompatibleSignatureProblem]("scala.xml.Null.get"),
+ ProblemFilters.exclude[IncompatibleSignatureProblem]("scala.xml.Node.attribute"),
+
+ // trait Attribute now extends trait ScalaVersionSpecificMetaData to ensure the previous signatures
+ // with return type `collection.Seq` remain valid.
+ // (trait Attribute extends MetaData, but that parent is not present in bytecode because it's a class.)
+ ProblemFilters.exclude[InheritedNewAbstractMethodProblem]("scala.xml.Attribute.apply"),
) ++ (CrossVersion.partialVersion(scalaVersion.value) match {
case Some((3, _)) => Seq( // Scala 3-specific exclusions
)
diff --git a/jvm/src/test/scala/scala/xml/SerializationTest.scala b/jvm/src/test/scala/scala/xml/SerializationTest.scala
index e8c5c880..f795daae 100644
--- a/jvm/src/test/scala/scala/xml/SerializationTest.scala
+++ b/jvm/src/test/scala/scala/xml/SerializationTest.scala
@@ -25,7 +25,7 @@ class SerializationTest {
def implicitConversion(): Unit = {
val parent: Elem =
val children: Seq[Node] = parent.child
- val asNodeSeq: NodeSeq = children
+ val asNodeSeq: NodeSeq = children // implicit seqToNodeSeq
assertEquals(asNodeSeq, JavaByteSerialization.roundTrip(asNodeSeq))
}
}
diff --git a/shared/src/main/scala-2.12/scala/xml/ScalaVersionSpecific.scala b/shared/src/main/scala-2.12/scala/xml/ScalaVersionSpecific.scala
index b74e3183..71f13003 100644
--- a/shared/src/main/scala-2.12/scala/xml/ScalaVersionSpecific.scala
+++ b/shared/src/main/scala-2.12/scala/xml/ScalaVersionSpecific.scala
@@ -22,7 +22,8 @@ private[xml] object ScalaVersionSpecific {
override def apply(from: Coll): mutable.Builder[Node, NodeSeq] = NodeSeq.newBuilder
override def apply(): mutable.Builder[Node, NodeSeq] = NodeSeq.newBuilder
}
- type SeqNodeUnapplySeq = scala.collection.Seq[Node]
+ type SeqOfNode = scala.collection.Seq[Node]
+ type SeqOfText = scala.collection.Seq[Text]
}
private[xml] trait ScalaVersionSpecificNodeSeq extends SeqLike[Node, NodeSeq] { self: NodeSeq =>
@@ -33,3 +34,11 @@ private[xml] trait ScalaVersionSpecificNodeSeq extends SeqLike[Node, NodeSeq] {
private[xml] trait ScalaVersionSpecificNodeBuffer { self: NodeBuffer =>
override def stringPrefix: String = "NodeBuffer"
}
+
+private[xml] trait ScalaVersionSpecificNode { self: Node => }
+
+private[xml] trait ScalaVersionSpecificMetaData { self: MetaData => }
+
+private[xml] trait ScalaVersionSpecificTextBuffer { self: TextBuffer => }
+
+private[xml] trait ScalaVersionSpecificUtility { self: Utility.type => }
diff --git a/shared/src/main/scala-2.13+/scala/xml/ScalaVersionSpecific.scala b/shared/src/main/scala-2.13+/scala/xml/ScalaVersionSpecific.scala
index e08d9ad9..49da95b8 100644
--- a/shared/src/main/scala-2.13+/scala/xml/ScalaVersionSpecific.scala
+++ b/shared/src/main/scala-2.13+/scala/xml/ScalaVersionSpecific.scala
@@ -24,7 +24,8 @@ private[xml] object ScalaVersionSpecific {
def newBuilder(from: Coll): Builder[Node, NodeSeq] = NodeSeq.newBuilder
def fromSpecific(from: Coll)(it: IterableOnce[Node]): NodeSeq = (NodeSeq.newBuilder ++= from).result()
}
- type SeqNodeUnapplySeq = scala.collection.immutable.Seq[Node]
+ type SeqOfNode = scala.collection.immutable.Seq[Node]
+ type SeqOfText = scala.collection.immutable.Seq[Text]
}
private[xml] trait ScalaVersionSpecificNodeSeq
@@ -48,8 +49,34 @@ private[xml] trait ScalaVersionSpecificNodeSeq
fromSpecific(new View.Map(this, f))
def flatMap(f: Node => IterableOnce[Node]): NodeSeq =
fromSpecific(new View.FlatMap(this, f))
+
+ def theSeq: scala.collection.Seq[Node]
}
private[xml] trait ScalaVersionSpecificNodeBuffer { self: NodeBuffer =>
override def className: String = "NodeBuffer"
}
+
+private[xml] trait ScalaVersionSpecificNode { self: Node =>
+ // These methods are overridden in Node with return type `immutable.Seq`. The declarations here result
+ // in a bridge method in `Node` with result type `collection.Seq` which is needed for binary compatibility.
+ def child: scala.collection.Seq[Node]
+ def nonEmptyChildren: scala.collection.Seq[Node]
+}
+
+private[xml] trait ScalaVersionSpecificMetaData { self: MetaData =>
+ def apply(key: String): scala.collection.Seq[Node]
+ def apply(namespace_uri: String, owner: Node, key: String): scala.collection.Seq[Node]
+ def apply(namespace_uri: String, scp: NamespaceBinding, k: String): scala.collection.Seq[Node]
+
+ def value: scala.collection.Seq[Node]
+}
+
+private[xml] trait ScalaVersionSpecificTextBuffer { self: TextBuffer =>
+ def toText: scala.collection.Seq[Text]
+}
+
+private[xml] trait ScalaVersionSpecificUtility { self: Utility.type =>
+ def trimProper(x: Node): scala.collection.Seq[Node]
+ def parseAttributeValue(value: String): scala.collection.Seq[Node]
+}
diff --git a/shared/src/main/scala-2/scala/xml/ScalaVersionSpecificReturnTypes.scala b/shared/src/main/scala-2/scala/xml/ScalaVersionSpecificReturnTypes.scala
index 22820dea..6d40d40f 100644
--- a/shared/src/main/scala-2/scala/xml/ScalaVersionSpecificReturnTypes.scala
+++ b/shared/src/main/scala-2/scala/xml/ScalaVersionSpecificReturnTypes.scala
@@ -28,7 +28,6 @@ private[xml] object ScalaVersionSpecificReturnTypes { // should be
type NullNext = scala.Null
type NullKey = scala.Null
type NullValue = scala.Null
- type NullApply1 = scala.collection.Seq[Node] // scala.Null
type NullApply3 = scala.Null
type NullRemove = Null.type
type SpecialNodeChild = Nil.type
diff --git a/shared/src/main/scala-3/scala/xml/ScalaVersionSpecificReturnTypes.scala b/shared/src/main/scala-3/scala/xml/ScalaVersionSpecificReturnTypes.scala
index 8e7fcdfc..e6dce41c 100644
--- a/shared/src/main/scala-3/scala/xml/ScalaVersionSpecificReturnTypes.scala
+++ b/shared/src/main/scala-3/scala/xml/ScalaVersionSpecificReturnTypes.scala
@@ -19,18 +19,17 @@ package scala.xml
What should have been specified explicitly is given in the comments;
next time we break binary compatibility the types should be changed in the code and this class removed.
*/
-private[xml] object ScalaVersionSpecificReturnTypes { // should be
- type ExternalIDAttribute = MetaData // Null.type
- type NoExternalIDId = String // scala.Null
- type NodeNoAttributes = MetaData // Null.type
- type NullFilter = MetaData // Null.type
- type NullGetNamespace = String // scala.Null
- type NullNext = MetaData // scala.Null
- type NullKey = String // scala.Null
- type NullValue = scala.collection.Seq[Node] // scala.Null
- type NullApply1 = scala.collection.Seq[Node] // scala.Null
- type NullApply3 = scala.collection.Seq[Node] // scala.Null
- type NullRemove = MetaData // Null.type
- type SpecialNodeChild = scala.collection.Seq[Node] // Nil.type
- type GroupChild = scala.collection.Seq[Node] // Nothing
+private[xml] object ScalaVersionSpecificReturnTypes { // should be
+ type ExternalIDAttribute = MetaData // Null.type
+ type NoExternalIDId = String // scala.Null
+ type NodeNoAttributes = MetaData // Null.type
+ type NullFilter = MetaData // Null.type
+ type NullGetNamespace = String // scala.Null
+ type NullNext = MetaData // scala.Null
+ type NullKey = String // scala.Null
+ type NullValue = scala.collection.immutable.Seq[Node] // scala.Null
+ type NullApply3 = scala.collection.immutable.Seq[Node] // scala.Null
+ type NullRemove = MetaData // Null.type
+ type SpecialNodeChild = scala.collection.immutable.Seq[Node] // Nil.type
+ type GroupChild = scala.collection.immutable.Seq[Node] // Nothing
}
diff --git a/shared/src/main/scala/scala/xml/Attribute.scala b/shared/src/main/scala/scala/xml/Attribute.scala
index 97457ab7..1c7c3575 100644
--- a/shared/src/main/scala/scala/xml/Attribute.scala
+++ b/shared/src/main/scala/scala/xml/Attribute.scala
@@ -53,14 +53,14 @@ object Attribute {
*
* @author Burak Emir
*/
-trait Attribute extends MetaData {
+trait Attribute extends MetaData with ScalaVersionSpecificMetaData {
def pre: String // will be null if unprefixed
override val key: String
- override val value: Seq[Node]
+ override val value: ScalaVersionSpecific.SeqOfNode
override val next: MetaData
- override def apply(key: String): Seq[Node]
- override def apply(namespace: String, scope: NamespaceBinding, key: String): Seq[Node]
+ override def apply(key: String): ScalaVersionSpecific.SeqOfNode
+ override def apply(namespace: String, scope: NamespaceBinding, key: String): ScalaVersionSpecific.SeqOfNode
override def copy(next: MetaData): Attribute
override def remove(key: String): MetaData =
diff --git a/shared/src/main/scala/scala/xml/Document.scala b/shared/src/main/scala/scala/xml/Document.scala
index e242794f..8fe1c6ae 100644
--- a/shared/src/main/scala/scala/xml/Document.scala
+++ b/shared/src/main/scala/scala/xml/Document.scala
@@ -36,7 +36,7 @@ class Document extends NodeSeq with Serializable {
* excluded. If there is a document type declaration, the list also
* contains a document type declaration information item.
*/
- var children: Seq[Node] = _
+ var children: Seq[Node] = _ // effectively an `immutable.Seq`, not changed due to binary compatibility
/** The element information item corresponding to the document element. */
var docElem: Node = _
@@ -96,7 +96,7 @@ class Document extends NodeSeq with Serializable {
// methods for NodeSeq
- override def theSeq: Seq[Node] = this.docElem
+ override def theSeq: ScalaVersionSpecific.SeqOfNode = this.docElem
override def canEqual(other: Any): Boolean = other match {
case _: Document => true
diff --git a/shared/src/main/scala/scala/xml/Elem.scala b/shared/src/main/scala/scala/xml/Elem.scala
index bd420e53..6b77f164 100755
--- a/shared/src/main/scala/scala/xml/Elem.scala
+++ b/shared/src/main/scala/scala/xml/Elem.scala
@@ -27,10 +27,10 @@ object Elem {
def apply(prefix: String, label: String, attributes: MetaData, scope: NamespaceBinding, minimizeEmpty: Boolean, child: Node*): Elem =
new Elem(prefix, label, attributes, scope, minimizeEmpty, child: _*)
- def unapplySeq(n: Node): Option[(String, String, MetaData, NamespaceBinding, ScalaVersionSpecific.SeqNodeUnapplySeq)] =
+ def unapplySeq(n: Node): Option[(String, String, MetaData, NamespaceBinding, ScalaVersionSpecific.SeqOfNode)] =
n match {
case _: SpecialNode | _: Group => None
- case _ => Some((n.prefix, n.label, n.attributes, n.scope, n.child.toSeq))
+ case _ => Some((n.prefix, n.label, n.attributes, n.scope, n.child))
}
}
@@ -104,7 +104,7 @@ class Elem(
scope: NamespaceBinding = this.scope,
minimizeEmpty: Boolean = this.minimizeEmpty,
child: Seq[Node] = this.child
- ): Elem = Elem(prefix, label, attributes, scope, minimizeEmpty, child: _*)
+ ): Elem = Elem(prefix, label, attributes, scope, minimizeEmpty, child.toSeq: _*)
/**
* Returns concatenation of `text(n)` for each child `n`.
diff --git a/shared/src/main/scala/scala/xml/Group.scala b/shared/src/main/scala/scala/xml/Group.scala
index 4c8fd7ba..3abc7222 100644
--- a/shared/src/main/scala/scala/xml/Group.scala
+++ b/shared/src/main/scala/scala/xml/Group.scala
@@ -22,7 +22,7 @@ import scala.collection.Seq
*/
// Note: used by the Scala compiler.
final case class Group(nodes: Seq[Node]) extends Node {
- override def theSeq: Seq[Node] = nodes
+ override def theSeq: ScalaVersionSpecific.SeqOfNode = nodes.toSeq
override def canEqual(other: Any): Boolean = other match {
case _: Group => true
diff --git a/shared/src/main/scala/scala/xml/MetaData.scala b/shared/src/main/scala/scala/xml/MetaData.scala
index 97931133..6bdd080f 100644
--- a/shared/src/main/scala/scala/xml/MetaData.scala
+++ b/shared/src/main/scala/scala/xml/MetaData.scala
@@ -85,6 +85,7 @@ abstract class MetaData
with Iterable[MetaData]
with Equality
with Serializable
+ with ScalaVersionSpecificMetaData
{
private[xml] def isNull: Boolean = this.eq(Null)
@@ -106,7 +107,7 @@ abstract class MetaData
* @param key
* @return value as Seq[Node] if key is found, null otherwise
*/
- def apply(key: String): Seq[Node]
+ def apply(key: String): ScalaVersionSpecific.SeqOfNode
/**
* convenience method, same as `apply(namespace, owner.scope, key)`.
@@ -115,7 +116,7 @@ abstract class MetaData
* @param owner the element owning this attribute list
* @param key the attribute key
*/
- final def apply(namespace_uri: String, owner: Node, key: String): Seq[Node] =
+ final def apply(namespace_uri: String, owner: Node, key: String): ScalaVersionSpecific.SeqOfNode =
apply(namespace_uri, owner.scope, key)
/**
@@ -126,7 +127,7 @@ abstract class MetaData
* @param k to be looked for
* @return value as Seq[Node] if key is found, null otherwise
*/
- def apply(namespace_uri: String, scp: NamespaceBinding, k: String): Seq[Node]
+ def apply(namespace_uri: String, scp: NamespaceBinding, k: String): ScalaVersionSpecific.SeqOfNode
/**
* returns a copy of this MetaData item with next field set to argument.
@@ -168,7 +169,7 @@ abstract class MetaData
def key: String
/** returns value of this MetaData item */
- def value: Seq[Node]
+ def value: ScalaVersionSpecific.SeqOfNode
/**
* Returns a String containing "prefix:key" if the first key is
@@ -183,7 +184,7 @@ abstract class MetaData
* Returns a Map containing the attributes stored as key/value pairs.
*/
def asAttrMap: Map[String, String] =
- iterator.map(x => (x.prefixedKey, x.value.text)).toMap
+ iterator.map(x => (x.prefixedKey, NodeSeq.fromSeq(x.value).text)).toMap
/** returns Null or the next MetaData item */
def next: MetaData
@@ -194,10 +195,10 @@ abstract class MetaData
* @param key
* @return value in Some(Seq[Node]) if key is found, None otherwise
*/
- final def get(key: String): Option[Seq[Node]] = Option(apply(key))
+ final def get(key: String): Option[ScalaVersionSpecific.SeqOfNode] = Option(apply(key))
/** same as get(uri, owner.scope, key) */
- final def get(uri: String, owner: Node, key: String): Option[Seq[Node]] =
+ final def get(uri: String, owner: Node, key: String): Option[ScalaVersionSpecific.SeqOfNode] =
get(uri, owner.scope, key)
/**
@@ -208,7 +209,7 @@ abstract class MetaData
* @param key to be looked fore
* @return value as `Some[Seq[Node]]` if key is found, None otherwise
*/
- final def get(uri: String, scope: NamespaceBinding, key: String): Option[Seq[Node]] =
+ final def get(uri: String, scope: NamespaceBinding, key: String): Option[ScalaVersionSpecific.SeqOfNode] =
Option(apply(uri, scope, key))
protected def toString1: String = sbToString(toString1)
diff --git a/shared/src/main/scala/scala/xml/Node.scala b/shared/src/main/scala/scala/xml/Node.scala
index ca1d6379..d9c41dd1 100755
--- a/shared/src/main/scala/scala/xml/Node.scala
+++ b/shared/src/main/scala/scala/xml/Node.scala
@@ -28,8 +28,8 @@ object Node {
/** the empty namespace */
val EmptyNamespace: String = ""
- def unapplySeq(n: Node): Some[(String, MetaData, ScalaVersionSpecific.SeqNodeUnapplySeq)] =
- Some((n.label, n.attributes, n.child.toSeq))
+ def unapplySeq(n: Node): Some[(String, MetaData, ScalaVersionSpecific.SeqOfNode)] =
+ Some((n.label, n.attributes, n.child))
}
/**
@@ -45,7 +45,7 @@ object Node {
*
* @author Burak Emir and others
*/
-abstract class Node extends NodeSeq {
+abstract class Node extends NodeSeq with ScalaVersionSpecificNode {
/** prefix of this node */
def prefix: String = null
@@ -92,7 +92,7 @@ abstract class Node extends NodeSeq {
* @return value of `UnprefixedAttribute` with given key
* in attributes, if it exists, otherwise `null`.
*/
- final def attribute(key: String): Option[Seq[Node]] = attributes.get(key)
+ final def attribute(key: String): Option[ScalaVersionSpecific.SeqOfNode] = attributes.get(key)
/**
* Convenience method, looks up a prefixed attribute in attributes of this node.
@@ -103,7 +103,7 @@ abstract class Node extends NodeSeq {
* @return value of `PrefixedAttribute` with given namespace
* and given key, otherwise `'''null'''`.
*/
- final def attribute(uri: String, key: String): Option[Seq[Node]] =
+ final def attribute(uri: String, key: String): Option[ScalaVersionSpecific.SeqOfNode] =
attributes.get(uri, this, key)
/**
@@ -120,12 +120,12 @@ abstract class Node extends NodeSeq {
*
* @return all children of this node
*/
- def child: Seq[Node]
+ def child: ScalaVersionSpecific.SeqOfNode
/**
* Children which do not stringify to "" (needed for equality)
*/
- def nonEmptyChildren: Seq[Node] = child.filterNot(_.toString.isEmpty)
+ def nonEmptyChildren: ScalaVersionSpecific.SeqOfNode = child.filterNot(_.toString.isEmpty)
/**
* Descendant axis (all descendants of this node, not including node itself)
@@ -166,7 +166,7 @@ abstract class Node extends NodeSeq {
/**
* returns a sequence consisting of only this node
*/
- override def theSeq: Seq[Node] = this :: Nil
+ override def theSeq: ScalaVersionSpecific.SeqOfNode = this :: Nil
/**
* String representation of this node
diff --git a/shared/src/main/scala/scala/xml/NodeSeq.scala b/shared/src/main/scala/scala/xml/NodeSeq.scala
index bdf316f9..07cbb8a6 100644
--- a/shared/src/main/scala/scala/xml/NodeSeq.scala
+++ b/shared/src/main/scala/scala/xml/NodeSeq.scala
@@ -26,7 +26,10 @@ import scala.collection.Seq
object NodeSeq {
final val Empty: NodeSeq = fromSeq(Nil)
def fromSeq(s: Seq[Node]): NodeSeq = new NodeSeq {
- override def theSeq: Seq[Node] = s
+ override def theSeq: ScalaVersionSpecific.SeqOfNode = s match {
+ case ns: ScalaVersionSpecific.SeqOfNode => ns
+ case _ => s.toVector
+ }
}
// ---
@@ -48,7 +51,7 @@ object NodeSeq {
* @author Burak Emir
*/
abstract class NodeSeq extends AbstractSeq[Node] with immutable.Seq[Node] with ScalaVersionSpecificNodeSeq with Equality with Serializable {
- def theSeq: Seq[Node]
+ def theSeq: ScalaVersionSpecific.SeqOfNode
override def length: Int = theSeq.length
override def iterator: Iterator[Node] = theSeq.iterator
diff --git a/shared/src/main/scala/scala/xml/Null.scala b/shared/src/main/scala/scala/xml/Null.scala
index 5613a462..c8e35640 100644
--- a/shared/src/main/scala/scala/xml/Null.scala
+++ b/shared/src/main/scala/scala/xml/Null.scala
@@ -49,7 +49,7 @@ case object Null extends MetaData {
override protected def basisForHashCode: Seq[Any] = Nil
override def apply(namespace: String, scope: NamespaceBinding, key: String): ScalaVersionSpecificReturnTypes.NullApply3 = null
- override def apply(key: String): ScalaVersionSpecificReturnTypes.NullApply1 =
+ override def apply(key: String): ScalaVersionSpecific.SeqOfNode =
if (Utility.isNameStart(key.head)) null
else throw new IllegalArgumentException(s"not a valid attribute name '$key', so can never match !")
diff --git a/shared/src/main/scala/scala/xml/PrefixedAttribute.scala b/shared/src/main/scala/scala/xml/PrefixedAttribute.scala
index 3a3985fe..1dc6ba12 100644
--- a/shared/src/main/scala/scala/xml/PrefixedAttribute.scala
+++ b/shared/src/main/scala/scala/xml/PrefixedAttribute.scala
@@ -27,11 +27,16 @@ import scala.collection.Seq
class PrefixedAttribute(
override val pre: String,
override val key: String,
- override val value: Seq[Node],
+ _value: Seq[Node],
val next1: MetaData
)
extends Attribute
{
+ override val value: ScalaVersionSpecific.SeqOfNode = if (_value == null) null else _value match {
+ case ns: ScalaVersionSpecific.SeqOfNode => ns
+ case _ => _value.toVector
+ }
+
override val next: MetaData = if (value != null) next1 else next1.remove(key)
/** same as this(pre, key, Text(value), next), or no attribute if value is null */
@@ -53,12 +58,12 @@ class PrefixedAttribute(
owner.getNamespace(pre)
/** forwards the call to next (because caller looks for unprefixed attribute */
- override def apply(key: String): Seq[Node] = next(key)
+ override def apply(key: String): ScalaVersionSpecific.SeqOfNode = next(key)
/**
* gets attribute value of qualified (prefixed) attribute with given key
*/
- override def apply(namespace: String, scope: NamespaceBinding, key: String): Seq[Node] =
+ override def apply(namespace: String, scope: NamespaceBinding, key: String): ScalaVersionSpecific.SeqOfNode =
if (key == this.key && scope.getURI(pre) == namespace)
value
else
diff --git a/shared/src/main/scala/scala/xml/QNode.scala b/shared/src/main/scala/scala/xml/QNode.scala
index c5128eb4..ddf7818c 100644
--- a/shared/src/main/scala/scala/xml/QNode.scala
+++ b/shared/src/main/scala/scala/xml/QNode.scala
@@ -20,6 +20,6 @@ package xml
* @author Burak Emir
*/
object QNode {
- def unapplySeq(n: Node): Some[(String, String, MetaData, ScalaVersionSpecific.SeqNodeUnapplySeq)] =
- Some((n.scope.getURI(n.prefix), n.label, n.attributes, n.child.toSeq))
+ def unapplySeq(n: Node): Some[(String, String, MetaData, ScalaVersionSpecific.SeqOfNode)] =
+ Some((n.scope.getURI(n.prefix), n.label, n.attributes, n.child))
}
diff --git a/shared/src/main/scala/scala/xml/TextBuffer.scala b/shared/src/main/scala/scala/xml/TextBuffer.scala
index a56fde47..5492790a 100644
--- a/shared/src/main/scala/scala/xml/TextBuffer.scala
+++ b/shared/src/main/scala/scala/xml/TextBuffer.scala
@@ -14,6 +14,7 @@ package scala
package xml
import scala.collection.Seq
+import scala.collection.immutable.{Seq => ISeq}
import Utility.isSpace
object TextBuffer {
@@ -26,7 +27,7 @@ object TextBuffer {
* appended with the `append` method will be replaced by a single space
* character, and leading and trailing space will be removed completely.
*/
-class TextBuffer {
+class TextBuffer extends ScalaVersionSpecificTextBuffer {
val sb: StringBuilder = new StringBuilder()
/**
@@ -45,8 +46,8 @@ class TextBuffer {
*
* @return the text without whitespaces.
*/
- def toText: Seq[Text] = sb.toString.trim match {
+ def toText: ScalaVersionSpecific.SeqOfText = sb.toString.trim match {
case "" => Nil
- case s => Seq(Text(s))
+ case s => ISeq(Text(s))
}
}
diff --git a/shared/src/main/scala/scala/xml/UnprefixedAttribute.scala b/shared/src/main/scala/scala/xml/UnprefixedAttribute.scala
index 0f044680..877a59b2 100644
--- a/shared/src/main/scala/scala/xml/UnprefixedAttribute.scala
+++ b/shared/src/main/scala/scala/xml/UnprefixedAttribute.scala
@@ -23,11 +23,16 @@ import scala.collection.Seq
// Note: used by the Scala compiler.
class UnprefixedAttribute(
override val key: String,
- override val value: Seq[Node],
+ _value: Seq[Node],
next1: MetaData
)
extends Attribute
{
+ override val value: ScalaVersionSpecific.SeqOfNode = if (_value == null) null else _value match {
+ case ns: ScalaVersionSpecific.SeqOfNode => ns
+ case _ => _value.toVector
+ }
+
final override val pre: scala.Null = null
override val next: MetaData = if (value != null) next1 else next1.remove(key)
@@ -50,7 +55,7 @@ class UnprefixedAttribute(
* @param key
* @return value as Seq[Node] if key is found, null otherwise
*/
- override def apply(key: String): Seq[Node] =
+ override def apply(key: String): ScalaVersionSpecific.SeqOfNode =
if (key == this.key) value else next(key)
/**
@@ -61,7 +66,7 @@ class UnprefixedAttribute(
* @param key
* @return ..
*/
- override def apply(namespace: String, scope: NamespaceBinding, key: String): Seq[Node] =
+ override def apply(namespace: String, scope: NamespaceBinding, key: String): ScalaVersionSpecific.SeqOfNode =
next(namespace, scope, key)
}
object UnprefixedAttribute {
diff --git a/shared/src/main/scala/scala/xml/Utility.scala b/shared/src/main/scala/scala/xml/Utility.scala
index ff8a2fb4..cf85be14 100755
--- a/shared/src/main/scala/scala/xml/Utility.scala
+++ b/shared/src/main/scala/scala/xml/Utility.scala
@@ -17,6 +17,7 @@ import scala.annotation.tailrec
import scala.collection.mutable
import scala.language.implicitConversions
import scala.collection.Seq
+import scala.collection.immutable.{Seq => ISeq}
/**
* The `Utility` object provides utility functions for processing instances
@@ -24,7 +25,7 @@ import scala.collection.Seq
*
* @author Burak Emir
*/
-object Utility extends AnyRef with parsing.TokenTests {
+object Utility extends AnyRef with parsing.TokenTests with ScalaVersionSpecificUtility {
final val SU: Char = '\u001A'
// [Martin] This looks dubious. We don't convert StringBuilders to
@@ -51,12 +52,12 @@ object Utility extends AnyRef with parsing.TokenTests {
*/
def trim(x: Node): Node = x match {
case Elem(pre, lab, md, scp, child@_*) =>
- val children: Seq[Node] = combineAdjacentTextNodes(child).flatMap(trimProper)
+ val children = combineAdjacentTextNodes(child).flatMap(trimProper)
Elem(pre, lab, md, scp, children.isEmpty, children: _*)
}
- private def combineAdjacentTextNodes(children: Seq[Node]): Seq[Node] =
- children.foldRight(Seq.empty[Node]) {
+ private def combineAdjacentTextNodes(children: ScalaVersionSpecific.SeqOfNode): ScalaVersionSpecific.SeqOfNode =
+ children.foldRight(ISeq.empty[Node]) {
case (Text(left), Text(right) +: nodes) => Text(left + right) +: nodes
case (n, nodes) => n +: nodes
}
@@ -65,9 +66,9 @@ object Utility extends AnyRef with parsing.TokenTests {
* trim a child of an element. `Attribute` values and `Atom` nodes that
* are not `Text` nodes are unaffected.
*/
- def trimProper(x: Node): Seq[Node] = x match {
+ def trimProper(x: Node): ScalaVersionSpecific.SeqOfNode = x match {
case Elem(pre, lab, md, scp, child@_*) =>
- val children: Seq[Node] = combineAdjacentTextNodes(child).flatMap(trimProper)
+ val children = combineAdjacentTextNodes(child).flatMap(trimProper)
Elem(pre, lab, md, scp, children.isEmpty, children: _*)
case Text(s) =>
new TextBuffer().append(s).toText
@@ -89,7 +90,7 @@ object Utility extends AnyRef with parsing.TokenTests {
*/
def sort(n: Node): Node = n match {
case Elem(pre, lab, md, scp, child@_*) =>
- val children: Seq[Node] = child.map(sort)
+ val children = child.map(sort)
Elem(pre, lab, sort(md), scp, children.isEmpty, children: _*)
case _ => n
}
@@ -353,7 +354,8 @@ object Utility extends AnyRef with parsing.TokenTests {
null
}
- def parseAttributeValue(value: String): Seq[Node] = {
+ // unused, untested
+ def parseAttributeValue(value: String): ScalaVersionSpecific.SeqOfNode = {
val sb: StringBuilder = new StringBuilder
var rfb: StringBuilder = null
val nb: NodeBuffer = new NodeBuffer()
@@ -397,7 +399,7 @@ object Utility extends AnyRef with parsing.TokenTests {
else
nb += x
}
- nb
+ nb.toVector
}
/**
diff --git a/shared/src/main/scala/scala/xml/factory/XMLLoader.scala b/shared/src/main/scala/scala/xml/factory/XMLLoader.scala
index afe54330..251027c1 100644
--- a/shared/src/main/scala/scala/xml/factory/XMLLoader.scala
+++ b/shared/src/main/scala/scala/xml/factory/XMLLoader.scala
@@ -58,7 +58,7 @@ trait XMLLoader[T <: Node] {
// TODO remove
def loadXML(inputSource: InputSource, parser: SAXParser): T = getDocElem(adapter.loadDocument(inputSource, parser.getXMLReader))
- def loadXMLNodes(inputSource: InputSource, parser: SAXParser): Seq[Node] = adapter.loadDocument(inputSource, parser.getXMLReader).children
+ def loadXMLNodes(inputSource: InputSource, parser: SAXParser): Seq[Node] = adapter.loadDocument(inputSource, parser.getXMLReader).children.toSeq
def adapter: parsing.FactoryAdapter = new parsing.NoBindingFactoryAdapter()
/** Loads XML Document. */
@@ -85,13 +85,13 @@ trait XMLLoader[T <: Node] {
def loadString(string: String): T = getDocElem(loadStringDocument(string))
/** Load XML nodes, including comments and processing instructions that precede and follow the root element. */
- def loadNodes(inputSource: InputSource): Seq[Node] = loadDocument(inputSource).children
- def loadFileNodes(fileName: String): Seq[Node] = loadFileDocument(fileName).children
- def loadFileNodes(file: File): Seq[Node] = loadFileDocument(file).children
- def loadNodes(url: URL): Seq[Node] = loadDocument(url).children
- def loadNodes(sysId: String): Seq[Node] = loadDocument(sysId).children
- def loadFileNodes(fileDescriptor: FileDescriptor): Seq[Node] = loadFileDocument(fileDescriptor).children
- def loadNodes(inputStream: InputStream): Seq[Node] = loadDocument(inputStream).children
- def loadNodes(reader: Reader): Seq[Node] = loadDocument(reader).children
- def loadStringNodes(string: String): Seq[Node] = loadStringDocument(string).children
+ def loadNodes(inputSource: InputSource): Seq[Node] = loadDocument(inputSource).children.toSeq
+ def loadFileNodes(fileName: String): Seq[Node] = loadFileDocument(fileName).children.toSeq
+ def loadFileNodes(file: File): Seq[Node] = loadFileDocument(file).children.toSeq
+ def loadNodes(url: URL): Seq[Node] = loadDocument(url).children.toSeq
+ def loadNodes(sysId: String): Seq[Node] = loadDocument(sysId).children.toSeq
+ def loadFileNodes(fileDescriptor: FileDescriptor): Seq[Node] = loadFileDocument(fileDescriptor).children.toSeq
+ def loadNodes(inputStream: InputStream): Seq[Node] = loadDocument(inputStream).children.toSeq
+ def loadNodes(reader: Reader): Seq[Node] = loadDocument(reader).children.toSeq
+ def loadStringNodes(string: String): Seq[Node] = loadStringDocument(string).children.toSeq
}
diff --git a/shared/src/main/scala/scala/xml/parsing/MarkupParser.scala b/shared/src/main/scala/scala/xml/parsing/MarkupParser.scala
index 2ca4773c..618133a2 100755
--- a/shared/src/main/scala/scala/xml/parsing/MarkupParser.scala
+++ b/shared/src/main/scala/scala/xml/parsing/MarkupParser.scala
@@ -242,7 +242,7 @@ trait MarkupParser extends MarkupParserCommon with TokenTests {
}
nextch() // is prolog ?
- var children: NodeSeq = null
+ var children: Seq[Node] = null
if ('?' == ch) {
nextch()
info_prolog = prolog()
@@ -255,7 +255,7 @@ trait MarkupParser extends MarkupParserCommon with TokenTests {
val ts: NodeBuffer = new NodeBuffer()
content1(TopScope, ts) // DTD handled as side effect
ts &+ content(TopScope)
- children = NodeSeq.fromSeq(ts)
+ children = ts.toVector
}
//println("[MarkupParser::document] children now: "+children.toList)
var elemCount: Int = 0
@@ -451,8 +451,7 @@ trait MarkupParser extends MarkupParserCommon with TokenTests {
def content(pscope: NamespaceBinding): NodeSeq = {
val ts: NodeBuffer = new NodeBuffer
var exit: Boolean = eof
- // todo: optimize seq repr.
- def done: NodeSeq = NodeSeq.fromSeq(ts.toList)
+ def done: NodeSeq = NodeSeq.fromSeq(ts.toVector)
while (!exit) {
tmppos = pos
diff --git a/shared/src/main/scala/scala/xml/parsing/NoBindingFactoryAdapter.scala b/shared/src/main/scala/scala/xml/parsing/NoBindingFactoryAdapter.scala
index bd57b40c..fcc522a6 100644
--- a/shared/src/main/scala/scala/xml/parsing/NoBindingFactoryAdapter.scala
+++ b/shared/src/main/scala/scala/xml/parsing/NoBindingFactoryAdapter.scala
@@ -27,7 +27,7 @@ class NoBindingFactoryAdapter extends FactoryAdapter with NodeFactory[Elem] {
/** From NodeFactory. Constructs an instance of scala.xml.Elem -- TODO: deprecate as in Elem */
override protected def create(pre: String, label: String, attrs: MetaData, scope: NamespaceBinding, children: Seq[Node]): Elem =
- Elem(pre, label, attrs, scope, children.isEmpty, children: _*)
+ Elem(pre, label, attrs, scope, children.isEmpty, children.toSeq: _*)
/** From FactoryAdapter. Creates a node. never creates the same node twice, using hash-consing.
TODO: deprecate as in Elem, or forward to create?? */
diff --git a/shared/src/main/scala/scala/xml/transform/BasicTransformer.scala b/shared/src/main/scala/scala/xml/transform/BasicTransformer.scala
index 7ad543b4..14484916 100644
--- a/shared/src/main/scala/scala/xml/transform/BasicTransformer.scala
+++ b/shared/src/main/scala/scala/xml/transform/BasicTransformer.scala
@@ -46,11 +46,11 @@ abstract class BasicTransformer extends (Node => Node) {
if (n.doTransform) n match {
case Group(xs) => Group(transform(xs)) // un-group the hack Group tag
case _ =>
- val ch: Seq[Node] = n.child
- val nch: Seq[Node] = transform(ch)
+ val ch = n.child
+ val nch = transform(ch)
if (ch.eq(nch)) n
- else Elem(n.prefix, n.label, n.attributes, n.scope, nch.isEmpty, nch: _*)
+ else Elem(n.prefix, n.label, n.attributes, n.scope, nch.isEmpty, nch.toSeq: _*)
}
else n
diff --git a/shared/src/test/scala/scala/xml/AttributeTest.scala b/shared/src/test/scala/scala/xml/AttributeTest.scala
index 5f1a6134..90ea3b0a 100644
--- a/shared/src/test/scala/scala/xml/AttributeTest.scala
+++ b/shared/src/test/scala/scala/xml/AttributeTest.scala
@@ -167,7 +167,7 @@ class AttributeTest {
@Test(expected=classOf[IllegalArgumentException])
def invalidAttributeFailForMany(): Unit = {
- .child \ "@"
+ .child \ "@" // implicit seqToNodeSeq
}
@Test(expected=classOf[IllegalArgumentException])
@@ -177,6 +177,6 @@ class AttributeTest {
@Test(expected=classOf[IllegalArgumentException])
def invalidEmptyAttributeFailForMany(): Unit = {
- .child \@ ""
+ .child \@ "" // implicit seqToNodeSeq
}
}
diff --git a/shared/src/test/scala/scala/xml/NodeSeqTest.scala b/shared/src/test/scala/scala/xml/NodeSeqTest.scala
index 558a77a7..a5808e79 100644
--- a/shared/src/test/scala/scala/xml/NodeSeqTest.scala
+++ b/shared/src/test/scala/scala/xml/NodeSeqTest.scala
@@ -1,6 +1,5 @@
package scala.xml
-import scala.xml.NodeSeq.seqToNodeSeq
import org.junit.Test
import org.junit.Assert.assertEquals
import org.junit.Assert.fail
@@ -30,7 +29,7 @@ class NodeSeqTest {
case res: Seq[Node] => assertEquals(2, res.size.toLong)
case _: NodeSeq => fail("Should be Seq[Node] was NodeSeq") // Unreachable code?
}
- val res: NodeSeq = a :+ b
+ val res: NodeSeq = a :+ b // implicit seqToNodeSeq
val exp: NodeSeq = NodeSeq.fromSeq(Seq(Hello, Hi))
assertEquals(exp, res)
}
@@ -59,7 +58,7 @@ class NodeSeqTest {
case res: Seq[Node] => assertEquals(3, res.size.toLong)
case _: NodeSeq => fail("Should be Seq[Node] was NodeSeq") // Unreachable code?
}
- val res: NodeSeq = a ++: b ++: c
+ val res: NodeSeq = a ++: b ++: c // implicit seqToNodeSeq
val exp: NodeSeq = NodeSeq.fromSeq(Seq(Hello, Hi, Hey))
assertEquals(exp, res)
}
@@ -67,7 +66,7 @@ class NodeSeqTest {
@Test
def testMap(): Unit = {
val a: NodeSeq = Hello
- val exp: NodeSeq = Seq(Hi)
+ val exp: NodeSeq = Seq(Hi) // implicit seqToNodeSeq
assertEquals(exp, a.map(_ => Hi))
assertEquals(exp, for { _ <- a } yield { Hi })
}
@@ -75,7 +74,7 @@ class NodeSeqTest {
@Test
def testFlatMap(): Unit = {
val a: NodeSeq = Hello
- val exp: NodeSeq = Seq(Hi)
+ val exp: NodeSeq = Seq(Hi) // implicit seqToNodeSeq
assertEquals(exp, a.flatMap(_ => Seq(Hi)))
assertEquals(exp, for { b <- a; _ <- b } yield { Hi })
assertEquals(exp, for { b <- a; c <- b; _ <- c } yield { Hi })
diff --git a/shared/src/test/scala/scala/xml/ShouldCompile.scala b/shared/src/test/scala/scala/xml/ShouldCompile.scala
index df8a237d..63dd91fc 100644
--- a/shared/src/test/scala/scala/xml/ShouldCompile.scala
+++ b/shared/src/test/scala/scala/xml/ShouldCompile.scala
@@ -70,7 +70,7 @@ class Floozy {
object guardedMatch { // SI-3705
// guard caused verifyerror in oldpatmat -- TODO: move this to compiler test suite
- def updateNodes(ns: Seq[Node]): Seq[Node] =
+ def updateNodes(ns: ScalaVersionSpecific.SeqOfNode): ScalaVersionSpecific.SeqOfNode =
for (subnode <- ns) yield subnode match {
case { _ } if true => abc
case Elem(prefix, label, attribs, scope, children @ _*) =>
diff --git a/shared/src/test/scala/scala/xml/XMLTest.scala b/shared/src/test/scala/scala/xml/XMLTest.scala
index 989ca02e..746d58d6 100644
--- a/shared/src/test/scala/scala/xml/XMLTest.scala
+++ b/shared/src/test/scala/scala/xml/XMLTest.scala
@@ -521,7 +521,7 @@ Ours is the portal of hope, come as you are."
@UnitTest
def i1976(): Unit = {
val node: Elem = { "whatever " }
- assertEquals("whatever ", node.child.text)
+ assertEquals("whatever ", node.child.text) // implicit seqToNodeSeq
}
@UnitTest