Skip to content

Commit 77aa363

Browse files
committed
fix(#16458): regression in xml syntax parsing
xLiteral mistakenly assumed that the element just after `<` is always non-special element, but it is not true. It could be xCharData, comment, xProcInstr.
1 parent fff24b1 commit 77aa363

File tree

3 files changed

+56
-4
lines changed

3 files changed

+56
-4
lines changed

compiler/src/dotty/tools/dotc/parsing/xml/MarkupParserCommon.scala

+8
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,14 @@ private[dotty] trait MarkupParserCommon {
202202
/** skip optional space S? */
203203
def xSpaceOpt(): Unit = while (isSpace(ch) && !eof) nextch()
204204

205+
/** skip optional space S? and return the number of consumed characters */
206+
def xSpaceOptN(): Int =
207+
var i = 0
208+
while (isSpace(ch) && !eof) do
209+
nextch()
210+
i += 1
211+
i
212+
205213
/** scan [3] S ::= (#x20 | #x9 | #xD | #xA)+ */
206214
def xSpace(): Unit =
207215
if (isSpace(ch)) { nextch(); xSpaceOpt() }

compiler/src/dotty/tools/dotc/parsing/xml/MarkupParsers.scala

+11-4
Original file line numberDiff line numberDiff line change
@@ -371,10 +371,17 @@ object MarkupParsers {
371371
// parse more XML?
372372
if (charComingAfter(xSpaceOpt()) == '<') {
373373
while {
374-
xSpaceOpt()
375-
nextch()
376-
ts.append(element)
377-
charComingAfter(xSpaceOpt()) == '<'
374+
if xSpaceOptN() == 0 then
375+
nextch()
376+
if content_LT(ts) then // Is `</>` valid xml?
377+
xToken("/>")
378+
charComingAfter(xSpaceOpt()) == '<'
379+
else
380+
// this is surely not a special node as any special node
381+
// should start with `<{special symbol}` without space.
382+
nextch()
383+
ts.append(element)
384+
charComingAfter(xSpaceOpt()) == '<'
378385
} do ()
379386
handle.makeXMLseq(Span(start, curOffset, start), ts)
380387
}

tests/pos/i16458.scala

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
def x = <div>FooBar</div><!-- /.modal-content -->
2+
3+
package scala.xml {
4+
type MetaData = AnyRef
5+
6+
trait NamespaceBinding
7+
object TopScope extends NamespaceBinding
8+
object Null
9+
abstract class Node {
10+
def label: String
11+
def child: Seq[Node]
12+
override def toString = label + child.mkString
13+
}
14+
class Comment(commentText: String) extends Node{
15+
def label = commentText
16+
def child = Nil
17+
}
18+
class Elem(prefix: String, val label: String, attributes1: MetaData, scope: NamespaceBinding, minimizeEmpty: Boolean, val child: Node*) extends Node
19+
class NodeBuffer extends Seq[Node] {
20+
val nodes = scala.collection.mutable.ArrayBuffer.empty[Node]
21+
def &+(o: Any): NodeBuffer =
22+
o match {
23+
case n: Node => nodes.addOne(n) ; this
24+
case t: Text => nodes.addOne(Atom(t)) ; this
25+
}
26+
// Members declared in scala.collection.IterableOnce
27+
def iterator: Iterator[scala.xml.Node] = nodes.iterator
28+
// Members declared in scala.collection.SeqOps
29+
def apply(i: Int): scala.xml.Node = nodes(i)
30+
def length: Int = nodes.length
31+
}
32+
case class Text(text: String)
33+
case class Atom(t: Text) extends Node {
34+
def label = t.text
35+
def child = Nil
36+
}
37+
}

0 commit comments

Comments
 (0)