From 3cc0275506cdcf821497f54514c3f1dd7b1f3fe2 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 26 Jun 2025 14:06:24 +0200 Subject: [PATCH] Make `CharacterReader` internal. (#19123) * Make `CharacterReader` internal. And by extension, make the static classes which define extension methods on it internal. To do this, I had to make Avalonia.Base's internals visible to Avalonia.Designer.HostApp, as that has a dependency on it, and exclude `StringCompatibilityExtensions` from there as the one from Avalonia.Base is now visible. * Don't expose internals to HostApp. Exposing Avalonia.Base's internals to Avalonia.Designer.HostApp caused an issue with the dependency on `StringCompatibilityExtensions` - because the hostapp is loaded into the target app and `StringCompatibilityExtensions` is conditionally compiled, you ended up with it being loaded into an app which does not have `StringCompatibilityExtensions`. Instead, add `string` overloads of the internal APIs which take a `CharacterReader` so that they can be called even when `CharacterReader` isn't available. * Update API diff. --- api/Avalonia.nupkg.xml | 24 +++++++++++++++++++ .../Utilities/CharacterReader.cs | 6 +---- .../Utilities/IdentifierParser.cs | 5 +--- src/Avalonia.Base/Utilities/KeywordParser.cs | 5 +--- .../Utilities/StyleClassParser.cs | 5 +--- .../AvaloniaXamlIlBindingPathParser.cs | 6 ++--- .../XamlIlAvaloniaPropertyHelper.cs | 2 +- .../Parsers/PropertyParser.cs | 9 ++++++- .../Parsers/BindingExpressionGrammar.cs | 10 ++++++-- 9 files changed, 47 insertions(+), 25 deletions(-) diff --git a/api/Avalonia.nupkg.xml b/api/Avalonia.nupkg.xml index 79381a04d7..be134deadc 100644 --- a/api/Avalonia.nupkg.xml +++ b/api/Avalonia.nupkg.xml @@ -7,6 +7,30 @@ baseline/netstandard2.0/Avalonia.Base.dll target/netstandard2.0/Avalonia.Base.dll + + CP0001 + T:Avalonia.Utilities.CharacterReader + baseline/netstandard2.0/Avalonia.Base.dll + target/netstandard2.0/Avalonia.Base.dll + + + CP0001 + T:Avalonia.Utilities.IdentifierParser + baseline/netstandard2.0/Avalonia.Base.dll + target/netstandard2.0/Avalonia.Base.dll + + + CP0001 + T:Avalonia.Utilities.KeywordParser + baseline/netstandard2.0/Avalonia.Base.dll + target/netstandard2.0/Avalonia.Base.dll + + + CP0001 + T:Avalonia.Utilities.StyleClassParser + baseline/netstandard2.0/Avalonia.Base.dll + target/netstandard2.0/Avalonia.Base.dll + CP0002 M:Avalonia.Diagnostics.AppliedStyle.get_HasActivator diff --git a/src/Avalonia.Base/Utilities/CharacterReader.cs b/src/Avalonia.Base/Utilities/CharacterReader.cs index e28d10d654..ec5e6b7f55 100644 --- a/src/Avalonia.Base/Utilities/CharacterReader.cs +++ b/src/Avalonia.Base/Utilities/CharacterReader.cs @@ -2,11 +2,7 @@ using System; namespace Avalonia.Utilities { - // TODO12: This should not be public -#if !BUILDTASK - public -#endif - ref struct CharacterReader + internal ref struct CharacterReader { private ReadOnlySpan _s; diff --git a/src/Avalonia.Base/Utilities/IdentifierParser.cs b/src/Avalonia.Base/Utilities/IdentifierParser.cs index f32d5f79a2..511f326187 100644 --- a/src/Avalonia.Base/Utilities/IdentifierParser.cs +++ b/src/Avalonia.Base/Utilities/IdentifierParser.cs @@ -3,10 +3,7 @@ using System.Globalization; namespace Avalonia.Utilities { -#if !BUILDTASK - public -#endif - static class IdentifierParser + internal static class IdentifierParser { public static ReadOnlySpan ParseIdentifier(this #if NET7SDK diff --git a/src/Avalonia.Base/Utilities/KeywordParser.cs b/src/Avalonia.Base/Utilities/KeywordParser.cs index 16ef95f5f4..d289f9577b 100644 --- a/src/Avalonia.Base/Utilities/KeywordParser.cs +++ b/src/Avalonia.Base/Utilities/KeywordParser.cs @@ -2,10 +2,7 @@ using System; namespace Avalonia.Utilities { -#if !BUILDTASK - public -#endif - static class KeywordParser + internal static class KeywordParser { public static bool CheckKeyword(this ref CharacterReader r, string keyword) { diff --git a/src/Avalonia.Base/Utilities/StyleClassParser.cs b/src/Avalonia.Base/Utilities/StyleClassParser.cs index 2db58f73d9..d528f0b7ca 100644 --- a/src/Avalonia.Base/Utilities/StyleClassParser.cs +++ b/src/Avalonia.Base/Utilities/StyleClassParser.cs @@ -3,10 +3,7 @@ using System.Globalization; namespace Avalonia.Utilities { -#if !BUILDTASK - public -#endif - static class StyleClassParser + internal static class StyleClassParser { public static ReadOnlySpan ParseStyleClass(this ref CharacterReader r) { diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlBindingPathParser.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlBindingPathParser.cs index 62e81f44d8..c74118b6f7 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlBindingPathParser.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlBindingPathParser.cs @@ -22,8 +22,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers if (binding.Arguments.Count > 0 && binding.Arguments[0] is XamlAstTextNode bindingPathText) { - var reader = new CharacterReader(bindingPathText.Text.AsSpan()); - var (nodes, _) = BindingExpressionGrammar.Parse(ref reader); + var (nodes, _) = BindingExpressionGrammar.Parse(bindingPathText.Text); if (convertedNode != null) { @@ -48,8 +47,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers if (bindingPathAssignment != null && bindingPathAssignment.Values[0] is XamlAstTextNode pathValue) { - var reader = new CharacterReader(pathValue.Text.AsSpan()); - var (nodes, _) = BindingExpressionGrammar.Parse(ref reader); + var (nodes, _) = BindingExpressionGrammar.Parse(pathValue.Text); if (nodes.Count == 1 && nodes[0] is BindingExpressionGrammar.EmptyExpressionNode) { diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlIlAvaloniaPropertyHelper.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlIlAvaloniaPropertyHelper.cs index 0d4b6eceef..48d7f26a5e 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlIlAvaloniaPropertyHelper.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlIlAvaloniaPropertyHelper.cs @@ -64,7 +64,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions { XamlAstNamePropertyReference forgedReference; - var parsedPropertyName = PropertyParser.Parse(new CharacterReader(propertyName.AsSpan())); + var parsedPropertyName = PropertyParser.Parse(propertyName); if(parsedPropertyName.owner == null) forgedReference = new XamlAstNamePropertyReference(lineInfo, selectorTypeReference, propertyName, selectorTypeReference); diff --git a/src/Markup/Avalonia.Markup.Xaml/Parsers/PropertyParser.cs b/src/Markup/Avalonia.Markup.Xaml/Parsers/PropertyParser.cs index a55a44dfe5..0f12307046 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Parsers/PropertyParser.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Parsers/PropertyParser.cs @@ -1,10 +1,17 @@ -using Avalonia.Data.Core; +using System; +using Avalonia.Data.Core; using Avalonia.Utilities; namespace Avalonia.Markup.Xaml.Parsers { internal class PropertyParser { + public static (string? ns, string? owner, string name) Parse(string text) + { + var r = new CharacterReader(text.AsSpan()); + return Parse(r); + } + public static (string? ns, string? owner, string name) Parse(CharacterReader r) { if (r.End) diff --git a/src/Markup/Avalonia.Markup/Markup/Parsers/BindingExpressionGrammar.cs b/src/Markup/Avalonia.Markup/Markup/Parsers/BindingExpressionGrammar.cs index 2529950691..97ae40931e 100644 --- a/src/Markup/Avalonia.Markup/Markup/Parsers/BindingExpressionGrammar.cs +++ b/src/Markup/Avalonia.Markup/Markup/Parsers/BindingExpressionGrammar.cs @@ -1,10 +1,10 @@ // Copyright (c) The Avalonia Project. All rights reserved. // Licensed under the MIT license. See licence.md file in the project root for full license information. -using Avalonia.Data.Core; -using Avalonia.Utilities; using System; using System.Collections.Generic; +using Avalonia.Data.Core; +using Avalonia.Utilities; namespace Avalonia.Markup.Parsers { @@ -18,6 +18,12 @@ namespace Avalonia.Markup.Parsers { private static readonly List s_pool = new(); + public static (List Nodes, SourceMode Mode) Parse(string text) + { + var r = new CharacterReader(text.AsSpan()); + return Parse(ref r); + } + public static (List Nodes, SourceMode Mode) Parse(ref CharacterReader r) { var result = new List();