Browse Source

Implement support for x:ClassModifier="internal" and TryLoad generators

pull/11551/head
Max Katz 3 years ago
parent
commit
ec47ea9e2a
  1. 35
      src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs
  2. 4
      src/Markup/Avalonia.Markup.Xaml.Loader/AvaloniaXamlIlRuntimeCompiler.cs
  3. 3
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlDocumentResource.cs

35
src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs

@ -288,6 +288,24 @@ namespace Avalonia.Build.Tasks
if (precompileText != "true")
throw new XamlParseException("Invalid value for x:Precompile", precompileDirective);
}
var classModifierDirective = initialRoot.Children.OfType<XamlAstXmlDirective>()
.FirstOrDefault(d => d.Namespace == XamlNamespaces.Xaml2006 && d.Name == "ClassModifier");
bool? classModifierPublic = null;
if (classModifierDirective != null)
{
var classModifierText = (classModifierDirective.Values[0] as XamlAstTextNode)?.Text.Trim()
.ToLowerInvariant();
if ("Public".Equals(classModifierText, StringComparison.OrdinalIgnoreCase))
classModifierPublic = true;
// XAML spec uses "Public" and "NotPublic" values,
// When WPF documentation uses "public" and "internal".
else if ("NotPublic".Equals(classModifierText, StringComparison.OrdinalIgnoreCase)
|| "Internal".Equals(classModifierText, StringComparison.OrdinalIgnoreCase))
classModifierPublic = false;
else
throw new XamlParseException("Invalid value for x:ClassModifier. Expected value are: Public, NotPublic.", precompileDirective);
}
var classDirective = initialRoot.Children.OfType<XamlAstXmlDirective>()
.FirstOrDefault(d => d.Namespace == XamlNamespaces.Xaml2006 && d.Name == "Class");
@ -297,8 +315,21 @@ namespace Avalonia.Build.Tasks
if (classDirective.Values.Count != 1 || !(classDirective.Values[0] is XamlAstTextNode tn))
throw new XamlParseException("x:Class should have a string value", classDirective);
classType = typeSystem.TargetAssembly.FindType(tn.Text);
if (classType == null)
throw new XamlParseException($"Unable to find type `{tn.Text}`", classDirective);
var isClassPublic = typeSystem.GetTypeReference(classType).Resolve().IsPublic;
classModifierPublic ??= isClassPublic;
// We do not really need x:ClassModifier support for x:Class, but we can at least use it for validation here.
if (classModifierPublic != isClassPublic)
{
throw new XamlParseException(
"XAML file x:ClassModifier doesn't match the x:Class type modifiers.",
precompileDirective);
}
compiler.OverrideRootType(parsed,
new XamlAstClrTypeReference(classDirective, classType, false));
initialRoot.Children.Remove(classDirective);
@ -319,6 +350,7 @@ namespace Avalonia.Build.Tasks
((List<XamlDocumentResource>)parsedXamlDocuments).Add(new XamlDocumentResource(
parsed, res.Uri, res, classType,
classModifierPublic ?? true,
populateBuilder,
compiler.DefinePopulateMethod(populateBuilder, parsed, populateName,
classTypeDefinition == null),
@ -502,7 +534,8 @@ namespace Avalonia.Build.Tasks
}
if (document.BuildMethod != null || classTypeDefinition != null)
if (document.IsPublic
&& (document.BuildMethod != null || classTypeDefinition != null))
{
var compiledBuildMethod = document.BuildMethod == null ?
null :

4
src/Markup/Avalonia.Markup.Xaml.Loader/AvaloniaXamlIlRuntimeCompiler.cs

@ -231,8 +231,8 @@ namespace Avalonia.Markup.Xaml.XamlIl
?? ((IXamlAstValueNode)parsed.Root).Type.GetClrType().Name;
var tb = _sreBuilder.DefineType("Builder_" + Guid.NewGuid().ToString("N") + "_" + xamlName);
var builder = _sreTypeSystem.CreateTypeBuilder(tb);
parsedDocuments.Add(new XamlDocumentResource(parsed, document.BaseUri?.ToString(), null, null,
builder,
parsedDocuments.Add(new XamlDocumentResource(parsed, document.BaseUri?.ToString(),
null, null, true, builder,
compiler.DefinePopulateMethod(builder, parsed, AvaloniaXamlIlCompiler.PopulateName, true),
document.RootInstance is null ? compiler.DefineBuildMethod(builder, parsed, AvaloniaXamlIlCompiler.BuildName, true) : null));
originalDocuments.Add(document);

3
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlDocumentResource.cs

@ -13,6 +13,7 @@ internal class XamlDocumentResource : IXamlDocumentResource
string? uri,
IFileSource? fileSource,
IXamlType? classType,
bool isPublic,
IXamlTypeBuilder<IXamlILEmitter> typeBuilder,
IXamlMethodBuilder<IXamlILEmitter> populateMethod,
IXamlMethodBuilder<IXamlILEmitter>? buildMethod)
@ -21,6 +22,7 @@ internal class XamlDocumentResource : IXamlDocumentResource
Uri = uri;
FileSource = fileSource;
ClassType = classType;
IsPublic = isPublic;
TypeBuilder = typeBuilder;
PopulateMethod = populateMethod;
BuildMethod = buildMethod;
@ -31,6 +33,7 @@ internal class XamlDocumentResource : IXamlDocumentResource
public IFileSource? FileSource { get; }
public IXamlType? ClassType { get; }
public bool IsPublic { get; }
public IXamlTypeBuilder<IXamlILEmitter> TypeBuilder { get; }
public IXamlMethodBuilder<IXamlILEmitter> PopulateMethod { get; }
public IXamlMethodBuilder<IXamlILEmitter>? BuildMethod { get; }

Loading…
Cancel
Save