From 98117192dda418796220cb6db61d90e9ac2318df Mon Sep 17 00:00:00 2001 From: Springcomp Date: Mon, 16 Jun 2025 13:01:48 +0000 Subject: [PATCH 1/4] Enforced strict error on malformed self-closing tag. --- Core.Tests/Parser/ParsingTests.cs | 26 +++++++++++++++++++------- Core/Parser/XmlTagState.cs | 18 +++++++++++------- 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/Core.Tests/Parser/ParsingTests.cs b/Core.Tests/Parser/ParsingTests.cs index f3098f8..db0dea2 100644 --- a/Core.Tests/Parser/ParsingTests.cs +++ b/Core.Tests/Parser/ParsingTests.cs @@ -222,6 +222,18 @@ public void BadClosingTag () result.AssertDiagnosticCount (2); } + [Test] + public void MalformedSelfClosingTag () + { + var parser = new XmlTreeParser (CreateRootState ()); + var result = parser.Parse (@""); + + parser.AssertDiagnostics ( + (XmlCoreDiagnostics.MalformedSelfClosingTag, 7, 0), + (XmlCoreDiagnostics.IncompleteTagEof, 9, 0) + ); + } + [Test] public void MismatchedElementNameWithNamespace () { @@ -417,8 +429,8 @@ abc defg result.AssertNoDiagnostics (); var el = result.doc - .RootElement.AssertNotNull() - .FirstChild.AssertCast(); + .RootElement.AssertNotNull () + .FirstChild.AssertCast (); Assert.AreEqual (2, el.Nodes.Count ()); var b = el.FirstChild as XElement; Assert.NotNull (b); @@ -438,7 +450,7 @@ some text "; var parser = new XmlTreeParser (CreateRootState ()); - var result = parser.Parse(docTxt, preserveWindowsNewlines: true); + var result = parser.Parse (docTxt, preserveWindowsNewlines: true); var rootElement = result.doc.RootElement.AssertNotNull (); @@ -446,13 +458,13 @@ some text AssertSubstring (@"", rootElement); AssertSubstring (@"someAtt=""SomeVal""", rootElement.Attributes.First.AssertNotNull ()); - AssertSubstring (@"", rootElement.Nodes.OfType().First ()); - AssertSubstring (@"", rootElement.Nodes.OfType().First ()); + AssertSubstring (@"", rootElement.Nodes.OfType ().First ()); + AssertSubstring (@"", rootElement.Nodes.OfType ().First ()); AssertSubstring (@"", rootElement.ClosingTag.AssertNotNull ()); } [Test] - public void ProcessingInstruction() + public void ProcessingInstruction () { var docTxt = @""; @@ -603,7 +615,7 @@ void AssertEqual (XmlParserContext a, XmlParserContext b) AssertEqual (a.KeywordBuilder, b.KeywordBuilder); Assert.AreEqual (a.Nodes.Count, b.Nodes.Count); - Assert.AreEqual (a.Nodes.Peek().GetType(), b.Nodes.Peek().GetType()); + Assert.AreEqual (a.Nodes.Peek ().GetType (), b.Nodes.Peek ().GetType ()); } // avoid allocating strings unless they're not equal diff --git a/Core/Parser/XmlTagState.cs b/Core/Parser/XmlTagState.cs index d9c98e3..4e429b0 100644 --- a/Core/Parser/XmlTagState.cs +++ b/Core/Parser/XmlTagState.cs @@ -41,16 +41,16 @@ public class XmlTagState : XmlParserState const int ATTEMPT_RECOVERY = 1; const int RECOVERY_FOUND_WHITESPACE = 2; - const int MAYBE_SELF_CLOSING = 2; + const int MAYBE_SELF_CLOSING = 3; const int FREE = 0; readonly XmlAttributeState AttributeState; readonly XmlNameState NameState; - public XmlTagState () : this (new XmlAttributeState ()) {} + public XmlTagState () : this (new XmlAttributeState ()) { } - public XmlTagState (XmlAttributeState attributeState) - : this (attributeState, new XmlNameState ()) {} + public XmlTagState (XmlAttributeState attributeState) + : this (attributeState, new XmlNameState ()) { } public XmlTagState (XmlAttributeState attributeState, XmlNameState nameState) { @@ -63,7 +63,7 @@ public XmlTagState (XmlAttributeState attributeState, XmlNameState nameState) public override XmlParserState? PushChar (char c, XmlParserContext context, ref bool replayCharacter, bool isEndOfFile) { - var peekedNode = (XContainer) context.Nodes.Peek (); + var peekedNode = (XContainer)context.Nodes.Peek (); var element = peekedNode as XElement; // if the current node on the stack is ended or not an element, then it's the parent @@ -87,8 +87,7 @@ public XmlTagState (XmlAttributeState attributeState, XmlNameState nameState) } if (isEndOfFile) { context.Diagnostics?.Add (XmlCoreDiagnostics.IncompleteTagEof, context.PositionBeforeCurrentChar); - } - else if (element.Name.IsValid) { + } else if (element.Name.IsValid) { context.Diagnostics?.Add (XmlCoreDiagnostics.MalformedNamedTag, context.PositionBeforeCurrentChar, element.Name.FullName, '<'); } else { context.Diagnostics?.Add (XmlCoreDiagnostics.UnnamedTag, context.PositionBeforeCurrentChar); @@ -139,6 +138,11 @@ public XmlTagState (XmlAttributeState attributeState, XmlNameState nameState) return null; } + if (context.StateTag == MAYBE_SELF_CLOSING) { + context.Diagnostics?.Add (XmlCoreDiagnostics.MalformedSelfClosingTag, context.Position, c); + return Parent; + } + if (context.StateTag == ATTEMPT_RECOVERY) { if (XmlChar.IsWhitespace (c)) { context.StateTag = RECOVERY_FOUND_WHITESPACE; From b76f7ea4e3ff1681776b452f13fb2c35a50fbb55 Mon Sep 17 00:00:00 2001 From: Springcomp Date: Mon, 16 Jun 2025 13:45:25 +0000 Subject: [PATCH 2/4] fix: revert unnecessary reformats --- Core.Tests/Parser/ParsingTests.cs | 14 +++++++------- Core/Parser/XmlTagState.cs | 11 ++++++----- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/Core.Tests/Parser/ParsingTests.cs b/Core.Tests/Parser/ParsingTests.cs index db0dea2..de6c9a2 100644 --- a/Core.Tests/Parser/ParsingTests.cs +++ b/Core.Tests/Parser/ParsingTests.cs @@ -429,8 +429,8 @@ abc defg result.AssertNoDiagnostics (); var el = result.doc - .RootElement.AssertNotNull () - .FirstChild.AssertCast (); + .RootElement.AssertNotNull() + .FirstChild.AssertCast(); Assert.AreEqual (2, el.Nodes.Count ()); var b = el.FirstChild as XElement; Assert.NotNull (b); @@ -450,7 +450,7 @@ some text "; var parser = new XmlTreeParser (CreateRootState ()); - var result = parser.Parse (docTxt, preserveWindowsNewlines: true); + var result = parser.Parse(docTxt, preserveWindowsNewlines: true); var rootElement = result.doc.RootElement.AssertNotNull (); @@ -458,13 +458,13 @@ some text AssertSubstring (@"", rootElement); AssertSubstring (@"someAtt=""SomeVal""", rootElement.Attributes.First.AssertNotNull ()); - AssertSubstring (@"", rootElement.Nodes.OfType ().First ()); - AssertSubstring (@"", rootElement.Nodes.OfType ().First ()); + AssertSubstring (@"", rootElement.Nodes.OfType().First ()); + AssertSubstring (@"", rootElement.Nodes.OfType().First ()); AssertSubstring (@"", rootElement.ClosingTag.AssertNotNull ()); } [Test] - public void ProcessingInstruction () + public void ProcessingInstruction() { var docTxt = @""; @@ -615,7 +615,7 @@ void AssertEqual (XmlParserContext a, XmlParserContext b) AssertEqual (a.KeywordBuilder, b.KeywordBuilder); Assert.AreEqual (a.Nodes.Count, b.Nodes.Count); - Assert.AreEqual (a.Nodes.Peek ().GetType (), b.Nodes.Peek ().GetType ()); + Assert.AreEqual (a.Nodes.Peek().GetType(), b.Nodes.Peek().GetType()); } // avoid allocating strings unless they're not equal diff --git a/Core/Parser/XmlTagState.cs b/Core/Parser/XmlTagState.cs index 4e429b0..feb4693 100644 --- a/Core/Parser/XmlTagState.cs +++ b/Core/Parser/XmlTagState.cs @@ -47,10 +47,10 @@ public class XmlTagState : XmlParserState readonly XmlAttributeState AttributeState; readonly XmlNameState NameState; - public XmlTagState () : this (new XmlAttributeState ()) { } + public XmlTagState () : this (new XmlAttributeState ()) {} - public XmlTagState (XmlAttributeState attributeState) - : this (attributeState, new XmlNameState ()) { } + public XmlTagState (XmlAttributeState attributeState) + : this (attributeState, new XmlNameState ()) {} public XmlTagState (XmlAttributeState attributeState, XmlNameState nameState) { @@ -63,7 +63,7 @@ public XmlTagState (XmlAttributeState attributeState, XmlNameState nameState) public override XmlParserState? PushChar (char c, XmlParserContext context, ref bool replayCharacter, bool isEndOfFile) { - var peekedNode = (XContainer)context.Nodes.Peek (); + var peekedNode = (XContainer) context.Nodes.Peek (); var element = peekedNode as XElement; // if the current node on the stack is ended or not an element, then it's the parent @@ -87,7 +87,8 @@ public XmlTagState (XmlAttributeState attributeState, XmlNameState nameState) } if (isEndOfFile) { context.Diagnostics?.Add (XmlCoreDiagnostics.IncompleteTagEof, context.PositionBeforeCurrentChar); - } else if (element.Name.IsValid) { + } + else if (element.Name.IsValid) { context.Diagnostics?.Add (XmlCoreDiagnostics.MalformedNamedTag, context.PositionBeforeCurrentChar, element.Name.FullName, '<'); } else { context.Diagnostics?.Add (XmlCoreDiagnostics.UnnamedTag, context.PositionBeforeCurrentChar); From c240d68ad66624364e4ebd471abf60d10921d8a9 Mon Sep 17 00:00:00 2001 From: Springcomp Date: Mon, 16 Jun 2025 14:04:52 +0000 Subject: [PATCH 3/4] fix: > should still be part of the tag. --- Core.Tests/Parser/ParsingTests.cs | 9 ++++++--- Core/Parser/XmlTagState.cs | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Core.Tests/Parser/ParsingTests.cs b/Core.Tests/Parser/ParsingTests.cs index de6c9a2..2c8f6bc 100644 --- a/Core.Tests/Parser/ParsingTests.cs +++ b/Core.Tests/Parser/ParsingTests.cs @@ -226,11 +226,14 @@ public void BadClosingTag () public void MalformedSelfClosingTag () { var parser = new XmlTreeParser (CreateRootState ()); - var result = parser.Parse (@""); + var result = parser.Parse (@"", + + () => { + parser.AssertStateIs (); + }); parser.AssertDiagnostics ( - (XmlCoreDiagnostics.MalformedSelfClosingTag, 7, 0), - (XmlCoreDiagnostics.IncompleteTagEof, 9, 0) + (XmlCoreDiagnostics.MalformedSelfClosingTag, 7, 0) ); } diff --git a/Core/Parser/XmlTagState.cs b/Core/Parser/XmlTagState.cs index feb4693..6b08f6d 100644 --- a/Core/Parser/XmlTagState.cs +++ b/Core/Parser/XmlTagState.cs @@ -141,7 +141,7 @@ public XmlTagState (XmlAttributeState attributeState, XmlNameState nameState) if (context.StateTag == MAYBE_SELF_CLOSING) { context.Diagnostics?.Add (XmlCoreDiagnostics.MalformedSelfClosingTag, context.Position, c); - return Parent; + return this; } if (context.StateTag == ATTEMPT_RECOVERY) { From 4413f24eda8668a44a16f628efdc906ae4945a83 Mon Sep 17 00:00:00 2001 From: Springcomp Date: Mon, 16 Jun 2025 14:34:03 +0000 Subject: [PATCH 4/4] fix: return null behaves like return this. --- Core/Parser/XmlTagState.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/Parser/XmlTagState.cs b/Core/Parser/XmlTagState.cs index 6b08f6d..9a1869f 100644 --- a/Core/Parser/XmlTagState.cs +++ b/Core/Parser/XmlTagState.cs @@ -141,7 +141,7 @@ public XmlTagState (XmlAttributeState attributeState, XmlNameState nameState) if (context.StateTag == MAYBE_SELF_CLOSING) { context.Diagnostics?.Add (XmlCoreDiagnostics.MalformedSelfClosingTag, context.Position, c); - return this; + return null; } if (context.StateTag == ATTEMPT_RECOVERY) {