Skip to content

XAML xmlns simplifications #29579

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

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ bld/

# Visual Studio 2017 auto generated files
Generated\ Files/
Generated/

# MSTest test Results
[Tt]est[Rr]esult*/
Expand Down
7 changes: 7 additions & 0 deletions Microsoft.Maui-vscode.sln
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UITest.Analyzers", "src\Tes
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Maui.Controls.Sample.Embedding", "src\Controls\samples\Controls.Sample.Embedding\Maui.Controls.Sample.Embedding.csproj", "{4ADCBA87-30DB-44F5-85E9-94A4F4132FD9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SourceGen.UnitTests", "src\Controls\tests\SourceGen.UnitTests\SourceGen.UnitTests.csproj", "{A426B2FC-F012-436B-BDD9-BEC0025DB96B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -539,6 +541,10 @@ Global
{4ADCBA87-30DB-44F5-85E9-94A4F4132FD9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4ADCBA87-30DB-44F5-85E9-94A4F4132FD9}.Release|Any CPU.Build.0 = Release|Any CPU
{4ADCBA87-30DB-44F5-85E9-94A4F4132FD9}.Release|Any CPU.Deploy.0 = Release|Any CPU
{A426B2FC-F012-436B-BDD9-BEC0025DB96B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A426B2FC-F012-436B-BDD9-BEC0025DB96B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A426B2FC-F012-436B-BDD9-BEC0025DB96B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A426B2FC-F012-436B-BDD9-BEC0025DB96B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -636,6 +642,7 @@ Global
{0048EA9A-D751-4576-A2BB-2A37BFB385A5} = {25D0D27A-C5FE-443D-8B65-D6C987F4A80E}
{DA001142-4777-4EDE-97D5-B1AC08162F99} = {7AC28763-9C68-4BF9-A1BA-25CBFFD2D15C}
{4ADCBA87-30DB-44F5-85E9-94A4F4132FD9} = {E1082E26-D700-4127-9329-66D673FD2D55}
{A426B2FC-F012-436B-BDD9-BEC0025DB96B} = {25D0D27A-C5FE-443D-8B65-D6C987F4A80E}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {0B8ABEAD-D2B5-4370-A187-62B5ABE4EE50}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
</Docs>
<Members>
<Member MemberName=".ctor">
<MemberSignature Language="C#" Value="public XmlnsDefinitionAttribute (string xmlNamespace, string clrNamespace);" />
<MemberSignature Language="ILAsm" Value=".method public hidebysig specialname rtspecialname instance void .ctor(string xmlNamespace, string clrNamespace) cil managed" />
<MemberSignature Language="C#" Value="public XmlnsDefinitionAttribute (string xmlNamespace, string target);" />
<MemberSignature Language="ILAsm" Value=".method public hidebysig specialname rtspecialname instance void .ctor(string xmlNamespace, string target) cil managed" />
<MemberSignature Language="DocId" Value="M:Microsoft.Maui.Controls.XmlnsDefinitionAttribute.#ctor(System.String,System.String)" />
<MemberSignature Language="F#" Value="new Microsoft.Maui.Controls.XmlnsDefinitionAttribute : string * string -&gt; Microsoft.Maui.Controls.XmlnsDefinitionAttribute" Usage="new Microsoft.Maui.Controls.XmlnsDefinitionAttribute (xmlNamespace, clrNamespace)" />
<MemberType>Constructor</MemberType>
Expand All @@ -35,11 +35,11 @@
</AssemblyInfo>
<Parameters>
<Parameter Name="xmlNamespace" Type="System.String" />
<Parameter Name="clrNamespace" Type="System.String" />
<Parameter Name="target" Type="System.String" />
</Parameters>
<Docs>
<param name="xmlNamespace">To be added.</param>
<param name="clrNamespace">To be added.</param>
<param name="target">To be added.</param>
</Docs>
</Member>
<Member MemberName="AssemblyName">
Expand Down Expand Up @@ -74,6 +74,22 @@
<Docs>
</Docs>
</Member>
<Member MemberName="Target">
<MemberSignature Language="C#" Value="public string Target { get; }" />
<MemberSignature Language="ILAsm" Value=".property instance string Target" />
<MemberSignature Language="DocId" Value="P:Microsoft.Maui.Controls.XmlnsDefinitionAttribute.Target" />
<MemberSignature Language="F#" Value="member this.ClrNamespace : string" Usage="Microsoft.Maui.Controls.XmlnsDefinitionAttribute.Target" />
<MemberType>Property</MemberType>
<AssemblyInfo>
<AssemblyName>Microsoft.Maui.Controls.Core</AssemblyName>
<AssemblyVersion>2.0.0.0</AssemblyVersion>
</AssemblyInfo>
<ReturnValue>
<ReturnType>System.String</ReturnType>
</ReturnValue>
<Docs>
</Docs>
</Member>
<Member MemberName="XmlNamespace">
<MemberSignature Language="C#" Value="public string XmlNamespace { get; }" />
<MemberSignature Language="ILAsm" Value=".property instance string XmlNamespace" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,8 @@ public static TypeDefinition GetTypeDefinition(this ModuleDefinition module, Xam
{
return cache.GetOrAddTypeDefinition(module, type, x =>
{
var asm = module.Assembly.Name.Name == type.assemblyName
var assemblyName = module.Assembly.Name;
var asm = (assemblyName.Name == type.assemblyName || assemblyName.FullName == type.assemblyName)
? module.Assembly
: module.AssemblyResolver.Resolve(AssemblyNameReference.Parse(type.assemblyName));
var typeDef = asm.MainModule.GetType($"{type.clrNamespace}.{type.typeName}");
Expand Down
56 changes: 30 additions & 26 deletions src/Controls/src/Build.Tasks/TypeReferenceExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,14 @@ namespace Microsoft.Maui.Controls.Build.Tasks
{
class TypeRefComparer : IEqualityComparer<TypeReference>
{
static string GetAssemblyName(TypeReference typeRef)
{
if (typeRef.Scope is ModuleDefinition md)
return md.Assembly.Name.Name;
if (typeRef.Scope is AssemblyNameReference anr)
return anr.Name;
throw new ArgumentOutOfRangeException(nameof(typeRef));
}

public bool Equals(TypeReference x, TypeReference y)
{
if (x == null)
return y == null;
if (y == null)
return x == null;
if (x == null && y == null)
return true;
if (x == null || y == null)
return false;

//strip the leading `&` as byref typered fullnames have a `&`
//strip the leading `&` as byref typeref fullnames have a `&`
var xname = x.FullName.EndsWith("&", StringComparison.InvariantCulture) ? x.FullName.Substring(0, x.FullName.Length - 1) : x.FullName;
var yname = y.FullName.EndsWith("&", StringComparison.InvariantCulture) ? y.FullName.Substring(0, y.FullName.Length - 1) : y.FullName;
if (xname != yname)
Expand All @@ -34,27 +25,40 @@ public bool Equals(TypeReference x, TypeReference y)
var yasm = GetAssemblyName(y);

//standard types comes from either mscorlib. System.Runtime or netstandard. Assume they are equivalent
if ((xasm.StartsWith("System.Runtime", StringComparison.Ordinal)
|| xasm.StartsWith("System", StringComparison.Ordinal)
|| xasm.StartsWith("mscorlib", StringComparison.Ordinal)
|| xasm.StartsWith("netstandard", StringComparison.Ordinal)
|| xasm.StartsWith("System.Xml", StringComparison.Ordinal))
&& (yasm.StartsWith("System.Runtime", StringComparison.Ordinal)
|| yasm.StartsWith("System", StringComparison.Ordinal)
|| yasm.StartsWith("mscorlib", StringComparison.Ordinal)
|| yasm.StartsWith("netstandard", StringComparison.Ordinal)
|| yasm.StartsWith("System.Xml", StringComparison.Ordinal)))
if (IsSystemAssemvly(xasm) && IsSystemAssemvly(yasm))
return true;
return xasm == yasm;
}

public int GetHashCode(TypeReference obj)
{
return $"{GetAssemblyName(obj)}//{obj.FullName}".GetHashCode();
var assemblyName = GetAssemblyName(obj);
if (IsSystemAssemvly(assemblyName))
return obj.FullName.GetHashCode();
return assemblyName.GetHashCode() ^ obj.FullName.GetHashCode();
}

static string GetAssemblyName(TypeReference typeRef)
{
if (typeRef.Scope is ModuleDefinition md)
return md.Assembly.Name.Name;
if (typeRef.Scope is AssemblyNameReference anr)
return anr.Name;
throw new ArgumentOutOfRangeException(nameof(typeRef));
}

bool IsSystemAssemvly(string assemblyName)
{
return assemblyName.StartsWith("System", StringComparison.Ordinal)
|| assemblyName.StartsWith("mscorlib", StringComparison.Ordinal)
|| assemblyName.StartsWith("netstandard", StringComparison.Ordinal)
|| assemblyName.StartsWith("System.Runtime", StringComparison.Ordinal)
|| assemblyName.StartsWith("System.Xml", StringComparison.Ordinal)
|| assemblyName.StartsWith("System.Private.CoreLib", StringComparison.Ordinal);
}

static TypeRefComparer s_default;
public static TypeRefComparer Default => s_default ?? (s_default = new TypeRefComparer());
public static TypeRefComparer Default => s_default ??= new TypeRefComparer();
}

static class TypeReferenceExtensions
Expand Down
2 changes: 1 addition & 1 deletion src/Controls/src/Build.Tasks/XamlCTask.cs
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ public override bool Execute(out IList<Exception> thrownExceptions)
ILRootNode rootnode = null;
try
{
rootnode = ParseXaml(resource.GetResourceStream(), typeDef);
rootnode = ParseXaml(resource.GetResourceStream(), module, typeDef);
if (rootnode == null)
{
LoggingHelper.LogMessage(Low, $"{new string(' ', 8)}failed.");
Expand Down
35 changes: 32 additions & 3 deletions src/Controls/src/Build.Tasks/XamlTask.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Xml;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
Expand Down Expand Up @@ -40,9 +41,23 @@ public bool Execute()

public abstract bool Execute(out IList<Exception> thrownExceptions);

internal static ILRootNode ParseXaml(Stream stream, TypeReference typeReference)
internal static ILRootNode ParseXaml(Stream stream, ModuleDefinition module, TypeReference typeReference)
{
using (var reader = XmlReader.Create(stream))
var allowImplicitXmlns = module.Assembly.CustomAttributes.Any(a =>
a.AttributeType.FullName == typeof(Microsoft.Maui.Controls.Xaml.Internals.AllowImplicitXmlnsDeclarationAttribute).FullName
&& (a.ConstructorArguments.Count == 0 || a.ConstructorArguments[0].Value is bool b && b));

var nsmgr = new XmlNamespaceManager(new NameTable());
if (allowImplicitXmlns)
{
nsmgr.AddNamespace("", XamlParser.DefaultImplicitUri);
foreach (var xmlnsPrefix in XmlTypeExtensions.GetXmlnsPrefixAttributes(module))
nsmgr.AddNamespace(xmlnsPrefix.Prefix, xmlnsPrefix.XmlNamespace);
}

using (var reader = XmlReader.Create(stream,
new XmlReaderSettings { ConformanceLevel = allowImplicitXmlns ? ConformanceLevel.Fragment : ConformanceLevel.Document },
new XmlParserContext(nsmgr.NameTable, nsmgr, null, XmlSpace.None)))
{
while (reader.Read())
{
Expand Down Expand Up @@ -73,8 +88,22 @@ public static bool IsXaml(this EmbeddedResource resource, XamlCache cache, Modul
if (!resource.Name.EndsWith(".xaml", StringComparison.InvariantCulture))
return false;

var allowImplicitXmlns = module.Assembly.CustomAttributes.Any(a =>
a.AttributeType.FullName == typeof(Microsoft.Maui.Controls.Xaml.Internals.AllowImplicitXmlnsDeclarationAttribute).FullName
&& (a.ConstructorArguments.Count == 0 || a.ConstructorArguments[0].Value is bool b && b));

var nsmgr = new XmlNamespaceManager(new NameTable());
nsmgr.AddNamespace("__f__", XamlParser.MauiUri);
if (allowImplicitXmlns)
{
nsmgr.AddNamespace("", XamlParser.DefaultImplicitUri);
foreach (var xmlnsPrefix in XmlTypeExtensions.GetXmlnsPrefixAttributes(module))
nsmgr.AddNamespace(xmlnsPrefix.Prefix, xmlnsPrefix.XmlNamespace);
}
using (var resourceStream = resource.GetResourceStream())
using (var reader = XmlReader.Create(resourceStream))
using (var reader = XmlReader.Create(resourceStream,
new XmlReaderSettings { ConformanceLevel = allowImplicitXmlns ? ConformanceLevel.Fragment : ConformanceLevel.Document },
new XmlParserContext(nsmgr.NameTable, nsmgr, null, XmlSpace.None)))
{
// Read to the first Element
while (reader.Read() && reader.NodeType != XmlNodeType.Element)
Expand Down
Loading