diff --git a/Avalonia.sln b/Avalonia.sln
index 3103ddeb16..b4decb7dcc 100644
--- a/Avalonia.sln
+++ b/Avalonia.sln
@@ -121,6 +121,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Props", "Props", "{F3AC8BC1
build\UnitTests.NetFX.props = build\UnitTests.NetFX.props
build\WarnAsErrors.props = build\WarnAsErrors.props
build\XUnit.props = build\XUnit.props
+ build\AnalyzerProject.targets = build\AnalyzerProject.targets
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Targets", "Targets", "{4D6FAF79-58B4-482F-9122-0668C346364C}"
diff --git a/build/AnalyzerProject.targets b/build/AnalyzerProject.targets
new file mode 100644
index 0000000000..f067ec0418
--- /dev/null
+++ b/build/AnalyzerProject.targets
@@ -0,0 +1,14 @@
+
+
+
+ true
+ true
+
+
+
+
+
+
+
+
+
diff --git a/samples/Generators.Sandbox/Controls/SignUpView.xaml b/samples/Generators.Sandbox/Controls/SignUpView.xaml
index c126f36f53..1cfb581cf9 100644
--- a/samples/Generators.Sandbox/Controls/SignUpView.xaml
+++ b/samples/Generators.Sandbox/Controls/SignUpView.xaml
@@ -8,7 +8,7 @@
Watermark="Please, enter user name..."
UseFloatingWatermark="True" />
netstandard2.0
false
- true
embedded
true
false
- true
-
-
-
-
-
-
-
-
+
+
+
diff --git a/src/tools/Avalonia.Generators/Avalonia.Generators.csproj b/src/tools/Avalonia.Generators/Avalonia.Generators.csproj
index 7945839563..8b8ac0db39 100644
--- a/src/tools/Avalonia.Generators/Avalonia.Generators.csproj
+++ b/src/tools/Avalonia.Generators/Avalonia.Generators.csproj
@@ -6,17 +6,10 @@
embedded
true
false
- true
- true
enable
../../../external/XamlX/src/XamlX
-
-
-
-
-
+
diff --git a/src/tools/Avalonia.Generators/Common/Domain/ICodeGenerator.cs b/src/tools/Avalonia.Generators/Common/Domain/ICodeGenerator.cs
index 4b426172f8..12dcbaf857 100644
--- a/src/tools/Avalonia.Generators/Common/Domain/ICodeGenerator.cs
+++ b/src/tools/Avalonia.Generators/Common/Domain/ICodeGenerator.cs
@@ -1,9 +1,8 @@
using System.Collections.Generic;
-using XamlX.TypeSystem;
namespace Avalonia.Generators.Common.Domain;
internal interface ICodeGenerator
{
- string GenerateCode(string className, string nameSpace, IXamlType xamlType, IEnumerable names);
+ string GenerateCode(string className, string nameSpace, IEnumerable names);
}
diff --git a/src/tools/Avalonia.Generators/Common/Domain/IGlobPattern.cs b/src/tools/Avalonia.Generators/Common/Domain/IGlobPattern.cs
index 04dbf9cbb9..09279d6986 100644
--- a/src/tools/Avalonia.Generators/Common/Domain/IGlobPattern.cs
+++ b/src/tools/Avalonia.Generators/Common/Domain/IGlobPattern.cs
@@ -1,6 +1,8 @@
+using System;
+
namespace Avalonia.Generators.Common.Domain;
-internal interface IGlobPattern
+internal interface IGlobPattern : IEquatable
{
bool Matches(string str);
}
diff --git a/src/tools/Avalonia.Generators/Common/Domain/INameResolver.cs b/src/tools/Avalonia.Generators/Common/Domain/INameResolver.cs
index cb5488d8a3..5943d73fa7 100644
--- a/src/tools/Avalonia.Generators/Common/Domain/INameResolver.cs
+++ b/src/tools/Avalonia.Generators/Common/Domain/INameResolver.cs
@@ -1,5 +1,7 @@
-using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Threading;
using XamlX.Ast;
+using XamlX.TypeSystem;
namespace Avalonia.Generators.Common.Domain;
@@ -13,7 +15,11 @@ internal enum NamedFieldModifier
internal interface INameResolver
{
- IReadOnlyList ResolveNames(XamlDocument xaml);
+ EquatableList ResolveXmlNames(XamlDocument xaml, CancellationToken cancellationToken);
+ ResolvedName ResolveName(IXamlType xamlType, string name, string? fieldModifier);
}
-internal record ResolvedName(string TypeName, string Name, string FieldModifier);
+internal record XamlXmlType(string Name, string? XmlNamespace, EquatableList GenericArguments);
+
+internal record ResolvedXmlName(XamlXmlType XmlType, string Name, string? FieldModifier);
+internal record ResolvedName(string TypeName, string Name, string? FieldModifier);
diff --git a/src/tools/Avalonia.Generators/Common/Domain/IViewResolver.cs b/src/tools/Avalonia.Generators/Common/Domain/IViewResolver.cs
index 49ceb6f69e..689aa25970 100644
--- a/src/tools/Avalonia.Generators/Common/Domain/IViewResolver.cs
+++ b/src/tools/Avalonia.Generators/Common/Domain/IViewResolver.cs
@@ -1,11 +1,46 @@
+using System.Collections.Immutable;
+using System.Threading;
using XamlX.Ast;
-using XamlX.TypeSystem;
namespace Avalonia.Generators.Common.Domain;
internal interface IViewResolver
{
- ResolvedView? ResolveView(string xaml);
+ ResolvedViewDocument? ResolveView(string xaml, CancellationToken cancellationToken);
}
-internal record ResolvedView(string ClassName, IXamlType XamlType, string Namespace, XamlDocument Xaml);
+internal record ResolvedViewInfo(string ClassName, string Namespace)
+{
+ public string FullName => $"{Namespace}.{ClassName}";
+ public override string ToString() => FullName;
+}
+
+internal record ResolvedViewDocument(string ClassName, string Namespace, XamlDocument Xaml)
+ : ResolvedViewInfo(ClassName, Namespace);
+
+internal record ResolvedXmlView(
+ string ClassName,
+ string Namespace,
+ EquatableList XmlNames)
+ : ResolvedViewInfo(ClassName, Namespace)
+{
+ public ResolvedXmlView(ResolvedViewInfo info, EquatableList xmlNames)
+ : this(info.ClassName, info.Namespace, xmlNames)
+ {
+
+ }
+}
+
+internal record ResolvedView(
+ string ClassName,
+ string Namespace,
+ bool IsWindow,
+ EquatableList Names)
+ : ResolvedViewInfo(ClassName, Namespace)
+{
+ public ResolvedView(ResolvedViewInfo info, bool isWindow, EquatableList names)
+ : this(info.ClassName, info.Namespace, isWindow, names)
+ {
+
+ }
+}
diff --git a/src/tools/Avalonia.Generators/Common/EquatableList.cs b/src/tools/Avalonia.Generators/Common/EquatableList.cs
new file mode 100644
index 0000000000..2b4c8a184d
--- /dev/null
+++ b/src/tools/Avalonia.Generators/Common/EquatableList.cs
@@ -0,0 +1,58 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+
+namespace Avalonia.Generators.Common;
+
+// https://github.com/dotnet/roslyn/blob/main/docs/features/incremental-generators.cookbook.md#pipeline-model-design
+// With minor modification to use ReadOnlyCollection instead of List
+internal class EquatableList(IList collection)
+ : ReadOnlyCollection(collection), IEquatable>
+{
+ public bool Equals(EquatableList? other)
+ {
+ // If the other list is null or a different size, they're not equal
+ if (other is null || Count != other.Count)
+ {
+ return false;
+ }
+
+ // Compare each pair of elements for equality
+ for (int i = 0; i < Count; i++)
+ {
+ if (!EqualityComparer.Default.Equals(this[i], other[i]))
+ {
+ return false;
+ }
+ }
+
+ // If we got this far, the lists are equal
+ return true;
+ }
+
+ public override bool Equals(object? obj)
+ {
+ return Equals(obj as EquatableList);
+ }
+
+ public override int GetHashCode()
+ {
+ var hash = 0;
+ for (var i = 0; i < Count; i++)
+ {
+ hash ^= this[i]?.GetHashCode() ?? 0;
+ }
+ return hash;
+ }
+
+ public static bool operator ==(EquatableList? list1, EquatableList? list2)
+ {
+ return ReferenceEquals(list1, list2)
+ || list1 is not null && list2 is not null && list1.Equals(list2);
+ }
+
+ public static bool operator !=(EquatableList? list1, EquatableList? list2)
+ {
+ return !(list1 == list2);
+ }
+}
diff --git a/src/tools/Avalonia.Generators/Common/GlobPattern.cs b/src/tools/Avalonia.Generators/Common/GlobPattern.cs
index 484e17d787..b76f4b2566 100644
--- a/src/tools/Avalonia.Generators/Common/GlobPattern.cs
+++ b/src/tools/Avalonia.Generators/Common/GlobPattern.cs
@@ -7,12 +7,19 @@ internal class GlobPattern : IGlobPattern
{
private const RegexOptions GlobOptions = RegexOptions.IgnoreCase | RegexOptions.Singleline;
private readonly Regex _regex;
+ private readonly string _pattern;
public GlobPattern(string pattern)
{
+ _pattern = pattern;
var expression = "^" + Regex.Escape(pattern).Replace(@"\*", ".*").Replace(@"\?", ".") + "$";
_regex = new Regex(expression, GlobOptions);
}
public bool Matches(string str) => _regex.IsMatch(str);
+
+ public bool Equals(IGlobPattern other) => other is GlobPattern pattern && pattern._pattern == _pattern;
+ public override int GetHashCode() => _pattern.GetHashCode();
+ public override bool Equals(object? obj) => obj is GlobPattern pattern && Equals(pattern);
+ public override string ToString() => _pattern;
}
diff --git a/src/tools/Avalonia.Generators/Common/GlobPatternGroup.cs b/src/tools/Avalonia.Generators/Common/GlobPatternGroup.cs
index 1358ee7920..f32f7c9a02 100644
--- a/src/tools/Avalonia.Generators/Common/GlobPatternGroup.cs
+++ b/src/tools/Avalonia.Generators/Common/GlobPatternGroup.cs
@@ -4,14 +4,20 @@ using Avalonia.Generators.Common.Domain;
namespace Avalonia.Generators.Common;
-internal class GlobPatternGroup : IGlobPattern
+internal class GlobPatternGroup(IEnumerable patterns)
+ : EquatableList(patterns.Select(p => new GlobPattern(p)).ToArray()), IGlobPattern
{
- private readonly GlobPattern[] _patterns;
+ public bool Matches(string str)
+ {
+ for (var i = 0; i < Count; i++)
+ {
+ if (this[i].Matches(str))
+ return true;
+ }
+ return false;
+ }
- public GlobPatternGroup(IEnumerable patterns) =>
- _patterns = patterns
- .Select(pattern => new GlobPattern(pattern))
- .ToArray();
-
- public bool Matches(string str) => _patterns.Any(pattern => pattern.Matches(str));
+ public bool Equals(IGlobPattern other) => other is GlobPatternGroup group && base.Equals(group);
+ public override string ToString() => $"[{string.Join(", ", this.Select(p => p.ToString()))}]";
}
+
diff --git a/src/tools/Avalonia.Generators/Common/ResolverExtensions.cs b/src/tools/Avalonia.Generators/Common/ResolverExtensions.cs
index 04352298c8..092eee6e2e 100644
--- a/src/tools/Avalonia.Generators/Common/ResolverExtensions.cs
+++ b/src/tools/Avalonia.Generators/Common/ResolverExtensions.cs
@@ -1,4 +1,4 @@
-using System.Linq;
+using System;
using XamlX.TypeSystem;
namespace Avalonia.Generators.Common;
@@ -6,20 +6,14 @@ namespace Avalonia.Generators.Common;
internal static class ResolverExtensions
{
public static bool IsAvaloniaStyledElement(this IXamlType clrType) =>
- clrType.HasStyledElementBaseType() ||
- clrType.HasIStyledElementInterface();
+ Inherits(clrType, "Avalonia.StyledElement");
+ public static bool IsAvaloniaWindow(this IXamlType clrType) =>
+ Inherits(clrType, "Avalonia.Controls.Window");
- private static bool HasStyledElementBaseType(this IXamlType clrType)
+ private static bool Inherits(IXamlType clrType, string metadataName)
{
- // Check for the base type since IStyledElement interface is removed.
- // https://github.com/AvaloniaUI/Avalonia/pull/9553
- if (clrType.FullName == "Avalonia.StyledElement")
+ if (string.Equals(clrType.FullName, metadataName, StringComparison.Ordinal))
return true;
- return clrType.BaseType != null && IsAvaloniaStyledElement(clrType.BaseType);
+ return clrType.BaseType is { } baseType && Inherits(baseType, metadataName);
}
-
- private static bool HasIStyledElementInterface(this IXamlType clrType) =>
- clrType.Interfaces.Any(abstraction =>
- abstraction.IsInterface &&
- abstraction.FullName == "Avalonia.IStyledElement");
}
diff --git a/src/tools/Avalonia.Generators/Common/XamlXNameResolver.cs b/src/tools/Avalonia.Generators/Common/XamlXNameResolver.cs
index 955df90ddd..0081d76196 100644
--- a/src/tools/Avalonia.Generators/Common/XamlXNameResolver.cs
+++ b/src/tools/Avalonia.Generators/Common/XamlXNameResolver.cs
@@ -1,38 +1,56 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
+using System.Threading;
using Avalonia.Generators.Common.Domain;
using XamlX;
using XamlX.Ast;
+using XamlX.TypeSystem;
namespace Avalonia.Generators.Common;
-internal class XamlXNameResolver : INameResolver, IXamlAstVisitor
+internal class XamlXNameResolver
+ : INameResolver, IXamlAstVisitor
{
- private readonly List _items = new();
- private readonly string _defaultFieldModifier;
+ private readonly Dictionary _items = new();
+ private CancellationToken _cancellationToken;
- public XamlXNameResolver(NamedFieldModifier namedFieldModifier = NamedFieldModifier.Internal)
+ public EquatableList ResolveXmlNames(XamlDocument xaml, CancellationToken cancellationToken)
{
- _defaultFieldModifier = namedFieldModifier.ToString().ToLowerInvariant();
+ _items.Clear();
+ try
+ {
+ _cancellationToken = cancellationToken;
+ xaml.Root.Visit(this);
+ xaml.Root.VisitChildren(this);
+ }
+ finally
+ {
+ _cancellationToken = CancellationToken.None;
+ }
+
+ return new EquatableList(_items.Values.ToArray());
}
- public IReadOnlyList ResolveNames(XamlDocument xaml)
+ public ResolvedName ResolveName(IXamlType clrType, string name, string? fieldModifier)
{
- _items.Clear();
- xaml.Root.Visit(this);
- xaml.Root.VisitChildren(this);
- return _items;
+ var typeName = $"{clrType.Namespace}.{clrType.Name}";
+ var typeAgs = clrType.GenericArguments.Select(arg => arg.FullName).ToImmutableList();
+ var genericTypeName = typeAgs.Count == 0
+ ? $"global::{typeName}"
+ : $"global::{typeName}<{string.Join(", ", typeAgs.Select(arg => $"global::{arg}"))}>";
+ return new ResolvedName(genericTypeName, name, fieldModifier);
}
IXamlAstNode IXamlAstVisitor.Visit(IXamlAstNode node)
{
+ _cancellationToken.ThrowIfCancellationRequested();
+
if (node is not XamlAstObjectNode objectNode)
return node;
- var clrType = objectNode.Type.GetClrType();
- if (!clrType.IsAvaloniaStyledElement())
- return node;
+ var xamlType = (XamlAstXmlTypeReference)objectNode.Type;
foreach (var child in objectNode.Children)
{
@@ -44,27 +62,24 @@ internal class XamlXNameResolver : INameResolver, IXamlAstVisitor
propertyValueNode.Values[0] is XamlAstTextNode text)
{
var fieldModifier = TryGetFieldModifier(objectNode);
- var typeName = $@"{clrType.Namespace}.{clrType.Name}";
- var typeAgs = clrType.GenericArguments.Select(arg => arg.FullName).ToImmutableList();
- var genericTypeName = typeAgs.Count == 0
- ? $"global::{typeName}"
- : $@"global::{typeName}<{string.Join(", ", typeAgs.Select(arg => $"global::{arg}"))}>";
-
- var resolvedName = new ResolvedName(genericTypeName, text.Text, fieldModifier);
- if (_items.Contains(resolvedName))
+ var resolvedName = new ResolvedXmlName(ConvertType(xamlType), text.Text, fieldModifier);
+ if (_items.ContainsKey(text.Text))
continue;
- _items.Add(resolvedName);
+ _items.Add(text.Text, resolvedName);
}
}
return node;
+
+ static XamlXmlType ConvertType(XamlAstXmlTypeReference type) => new(type.Name, type.XmlNamespace,
+ new EquatableList(type.GenericArguments.Select(ConvertType).ToArray()));
}
void IXamlAstVisitor.Push(IXamlAstNode node) { }
void IXamlAstVisitor.Pop() { }
- private string TryGetFieldModifier(XamlAstObjectNode objectNode)
+ private string? TryGetFieldModifier(XamlAstObjectNode objectNode)
{
// We follow Xamarin.Forms API behavior in terms of x:FieldModifier here:
// https://docs.microsoft.com/en-us/xamarin/xamarin-forms/xaml/field-modifiers
@@ -87,7 +102,7 @@ internal class XamlXNameResolver : INameResolver, IXamlAstVisitor
"protected" => "protected",
"internal" => "internal",
"notpublic" => "internal",
- _ => _defaultFieldModifier
+ _ => null
};
}
diff --git a/src/tools/Avalonia.Generators/Common/XamlXViewResolver.cs b/src/tools/Avalonia.Generators/Common/XamlXViewResolver.cs
index b0495b2840..35880dcc44 100644
--- a/src/tools/Avalonia.Generators/Common/XamlXViewResolver.cs
+++ b/src/tools/Avalonia.Generators/Common/XamlXViewResolver.cs
@@ -1,92 +1,61 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Threading;
using Avalonia.Generators.Common.Domain;
using Avalonia.Generators.Compiler;
using XamlX;
using XamlX.Ast;
using XamlX.Parsers;
+using XamlX.TypeSystem;
namespace Avalonia.Generators.Common;
-internal class XamlXViewResolver : IViewResolver, IXamlAstVisitor
+internal class XamlXViewResolver(MiniCompiler compiler) : IViewResolver, IXamlAstVisitor
{
- private readonly RoslynTypeSystem _typeSystem;
- private readonly MiniCompiler _compiler;
- private readonly bool _checkTypeValidity;
- private readonly Action? _onTypeInvalid;
- private readonly Action? _onUnhandledError;
-
- private ResolvedView? _resolvedClass;
+ private ResolvedViewDocument? _resolvedClass;
private XamlDocument? _xaml;
+ private CancellationToken _cancellationToken;
- public XamlXViewResolver(
- RoslynTypeSystem typeSystem,
- MiniCompiler compiler,
- bool checkTypeValidity = false,
- Action? onTypeInvalid = null,
- Action? onUnhandledError = null)
+ public ResolvedViewDocument? ResolveView(string xaml, CancellationToken cancellationToken)
{
- _checkTypeValidity = checkTypeValidity;
- _onTypeInvalid = onTypeInvalid;
- _onUnhandledError = onUnhandledError;
- _typeSystem = typeSystem;
- _compiler = compiler;
- }
+ _resolvedClass = null;
+ _xaml = XDocumentXamlParser.Parse(xaml, new Dictionary
+ {
+ {XamlNamespaces.Blend2008, XamlNamespaces.Blend2008}
+ });
- public ResolvedView? ResolveView(string xaml)
- {
try
{
- _resolvedClass = null;
- _xaml = XDocumentXamlParser.Parse(xaml, new Dictionary
- {
- {XamlNamespaces.Blend2008, XamlNamespaces.Blend2008}
- });
-
- _compiler.Transform(_xaml);
+ _cancellationToken = cancellationToken;
+ compiler.TransformWithCancellation(_xaml, cancellationToken);
_xaml.Root.Visit(this);
_xaml.Root.VisitChildren(this);
- return _resolvedClass;
}
- catch (Exception exception)
+ finally
{
- _onUnhandledError?.Invoke(exception);
- return null;
+ _cancellationToken = CancellationToken.None;
}
+ return _resolvedClass;
}
-
+
IXamlAstNode IXamlAstVisitor.Visit(IXamlAstNode node)
{
- if (node is not XamlAstObjectNode objectNode)
- return node;
+ _cancellationToken.ThrowIfCancellationRequested();
- var clrType = objectNode.Type.GetClrType();
- if (!clrType.IsAvaloniaStyledElement())
+ if (node is not XamlAstObjectNode objectNode)
return node;
foreach (var child in objectNode.Children)
{
- if (child is XamlAstXmlDirective directive &&
- directive.Name == "Class" &&
- directive.Namespace == XamlNamespaces.Xaml2006 &&
- directive.Values[0] is XamlAstTextNode text)
+ if (child is XamlAstXmlDirective { Name: "Class", Namespace: XamlNamespaces.Xaml2006 } directive
+ && directive.Values[0] is XamlAstTextNode text)
{
- if (_checkTypeValidity)
- {
- var existingType = _typeSystem.FindType(text.Text);
- if (existingType == null)
- {
- _onTypeInvalid?.Invoke(text.Text);
- return node;
- }
- }
-
var split = text.Text.Split('.');
var nameSpace = string.Join(".", split.Take(split.Length - 1));
var className = split.Last();
- _resolvedClass = new ResolvedView(className, clrType, nameSpace, _xaml!);
+ _resolvedClass = new ResolvedViewDocument(className, nameSpace, _xaml!);
return node;
}
}
diff --git a/src/tools/Avalonia.Generators/Compiler/MiniCompiler.cs b/src/tools/Avalonia.Generators/Compiler/MiniCompiler.cs
index b0421cd245..0c7805bb38 100644
--- a/src/tools/Avalonia.Generators/Compiler/MiniCompiler.cs
+++ b/src/tools/Avalonia.Generators/Compiler/MiniCompiler.cs
@@ -1,6 +1,9 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
+using System.Threading;
+using Avalonia.Generators.Common.Domain;
+using XamlX.Ast;
using XamlX.Compiler;
using XamlX.Emit;
using XamlX.Transform;
@@ -14,7 +17,22 @@ internal sealed class MiniCompiler : XamlCompiler
diff --git a/tests/Avalonia.Generators.Tests/CompilationUtils.cs b/tests/Avalonia.Generators.Tests/CompilationUtils.cs
new file mode 100644
index 0000000000..3094b65b28
--- /dev/null
+++ b/tests/Avalonia.Generators.Tests/CompilationUtils.cs
@@ -0,0 +1,24 @@
+using System.Collections.Generic;
+using System.Linq;
+using Avalonia.Generators.Common;
+using Avalonia.Generators.Common.Domain;
+using Avalonia.Generators.Compiler;
+using Microsoft.CodeAnalysis;
+
+namespace Avalonia.Generators.Tests;
+
+internal static class CompilationUtils
+{
+ internal static IEnumerable ResolveNames(this IEnumerable names, Compilation compilation, XamlXNameResolver nameResolver)
+ {
+ var compiler = MiniCompiler.CreateRoslyn(new RoslynTypeSystem(compilation), MiniCompiler.AvaloniaXmlnsDefinitionAttribute);
+ return names
+ .Select(xmlName =>
+ {
+ var clrType = compiler.ResolveXamlType(xmlName.XmlType);
+ return (clrType, nameResolver.ResolveName(clrType, xmlName.Name, xmlName.FieldModifier));
+ })
+ .Where(t => t.clrType.IsAvaloniaStyledElement())
+ .Select(t => t.Item2);
+ }
+}
diff --git a/tests/Avalonia.Generators.Tests/InitializeComponent/InitializeComponentTests.cs b/tests/Avalonia.Generators.Tests/InitializeComponent/InitializeComponentTests.cs
index 15fb282ed9..4e98f3c207 100644
--- a/tests/Avalonia.Generators.Tests/InitializeComponent/InitializeComponentTests.cs
+++ b/tests/Avalonia.Generators.Tests/InitializeComponent/InitializeComponentTests.cs
@@ -1,5 +1,8 @@
+using System.Linq;
+using System.Threading;
using System.Threading.Tasks;
using Avalonia.Generators.Common;
+using Avalonia.Generators.Common.Domain;
using Avalonia.Generators.Compiler;
using Avalonia.Generators.NameGenerator;
using Avalonia.Generators.Tests.InitializeComponent.GeneratedInitializeComponent;
@@ -23,7 +26,6 @@ public class InitializeComponentTests
[InlineData(InitializeComponentCode.FieldModifier, View.FieldModifier, false)]
[InlineData(InitializeComponentCode.AttachedPropsWithDevTools, View.AttachedProps, true)]
[InlineData(InitializeComponentCode.AttachedProps, View.AttachedProps, false)]
- [InlineData(InitializeComponentCode.ControlWithoutWindow, View.ControlWithoutWindow, true)]
[InlineData(InitializeComponentCode.ControlWithoutWindow, View.ControlWithoutWindow, false)]
public async Task Should_Generate_FindControl_Refs_From_Avalonia_Markup_File(
string expectation,
@@ -31,28 +33,28 @@ public class InitializeComponentTests
bool devToolsMode)
{
var excluded = devToolsMode ? null : "Avalonia.Diagnostics";
- var compilation =
- View.CreateAvaloniaCompilation(excluded)
- .WithCustomTextBox();
- var types = new RoslynTypeSystem(compilation);
- var classResolver = new XamlXViewResolver(
- types,
- MiniCompiler.CreateDefault(
- new RoslynTypeSystem(compilation),
- MiniCompiler.AvaloniaXmlnsDefinitionAttribute));
+ // Step 1: parse XAML as xml nodes, without any type information.
+ var classResolver = new XamlXViewResolver(MiniCompiler.CreateNoop());
var xaml = await View.Load(markup);
- var classInfo = classResolver.ResolveView(xaml);
+ var classInfo = classResolver.ResolveView(xaml, CancellationToken.None);
Assert.NotNull(classInfo);
var nameResolver = new XamlXNameResolver();
- var names = nameResolver.ResolveNames(classInfo.Xaml);
+ var names = nameResolver.ResolveXmlNames(classInfo.Xaml, CancellationToken.None);
+
+ // Step 2: use compilation context to resolve types
+ var compilation =
+ View.CreateAvaloniaCompilation(excluded)
+ .WithCustomTextBox();
+ var resolvedNames = names.ResolveNames(compilation, nameResolver).ToArray();
- var generator = new InitializeComponentCodeGenerator(types, devToolsMode);
+ // Step 3: run generator
+ var generator = new InitializeComponentCodeGenerator(devToolsMode);
var generatorVersion = typeof(InitializeComponentCodeGenerator).Assembly.GetName().Version?.ToString();
var code = generator
- .GenerateCode("SampleView", "Sample.App", classInfo.XamlType, names)
+ .GenerateCode("SampleView", "Sample.App", resolvedNames)
.Replace("\r", string.Empty);
var expected = (await InitializeComponentCode.Load(expectation))
diff --git a/tests/Avalonia.Generators.Tests/MiniCompilerTests.cs b/tests/Avalonia.Generators.Tests/MiniCompilerTests.cs
index a54fc7bf12..041e830674 100644
--- a/tests/Avalonia.Generators.Tests/MiniCompilerTests.cs
+++ b/tests/Avalonia.Generators.Tests/MiniCompilerTests.cs
@@ -21,7 +21,7 @@ public class MiniCompilerTests
{
var xaml = XDocumentXamlParser.Parse(MiniValidXaml);
var compilation = CreateBasicCompilation(MiniClass);
- MiniCompiler.CreateDefault(new RoslynTypeSystem(compilation)).Transform(xaml);
+ MiniCompiler.CreateRoslyn(new RoslynTypeSystem(compilation)).Transform(xaml);
Assert.NotNull(xaml.Root);
}
@@ -31,7 +31,7 @@ public class MiniCompilerTests
{
var xaml = XDocumentXamlParser.Parse(AvaloniaXaml);
var compilation = View.CreateAvaloniaCompilation();
- MiniCompiler.CreateDefault(new RoslynTypeSystem(compilation)).Transform(xaml);
+ MiniCompiler.CreateRoslyn(new RoslynTypeSystem(compilation)).Transform(xaml);
Assert.NotNull(xaml.Root);
}
diff --git a/tests/Avalonia.Generators.Tests/OnlyProperties/OnlyPropertiesTests.cs b/tests/Avalonia.Generators.Tests/OnlyProperties/OnlyPropertiesTests.cs
index 3f498c2be2..e0db63526b 100644
--- a/tests/Avalonia.Generators.Tests/OnlyProperties/OnlyPropertiesTests.cs
+++ b/tests/Avalonia.Generators.Tests/OnlyProperties/OnlyPropertiesTests.cs
@@ -1,5 +1,8 @@
+using System.Linq;
+using System.Threading;
using System.Threading.Tasks;
using Avalonia.Generators.Common;
+using Avalonia.Generators.Common.Domain;
using Avalonia.Generators.Compiler;
using Avalonia.Generators.NameGenerator;
using Avalonia.Generators.Tests.OnlyProperties.GeneratedCode;
@@ -25,27 +28,27 @@ public class OnlyPropertiesTests
[InlineData(OnlyPropertiesCode.ControlWithoutWindow, View.ControlWithoutWindow)]
public async Task Should_Generate_FindControl_Refs_From_Avalonia_Markup_File(string expectation, string markup)
{
- var compilation =
- View.CreateAvaloniaCompilation()
- .WithCustomTextBox();
-
- var classResolver = new XamlXViewResolver(
- new RoslynTypeSystem(compilation),
- MiniCompiler.CreateDefault(
- new RoslynTypeSystem(compilation),
- MiniCompiler.AvaloniaXmlnsDefinitionAttribute));
+ // Step 1: parse XAML as xml nodes, without any type information.
+ var classResolver = new XamlXViewResolver(MiniCompiler.CreateNoop());
var xaml = await View.Load(markup);
- var classInfo = classResolver.ResolveView(xaml);
+ var classInfo = classResolver.ResolveView(xaml, CancellationToken.None);
Assert.NotNull(classInfo);
var nameResolver = new XamlXNameResolver();
- var names = nameResolver.ResolveNames(classInfo.Xaml);
+ var names = nameResolver.ResolveXmlNames(classInfo.Xaml, CancellationToken.None);
+
+ // Step 2: use compilation context to resolve types
+ var compilation =
+ View.CreateAvaloniaCompilation()
+ .WithCustomTextBox();
+ var resolvedNames = names.ResolveNames(compilation, nameResolver).ToArray();
+ // Step 3: run generator
var generator = new OnlyPropertiesCodeGenerator();
var generatorVersion = typeof(OnlyPropertiesCodeGenerator).Assembly.GetName().Version?.ToString();
var code = generator
- .GenerateCode("SampleView", "Sample.App", classInfo.XamlType, names)
+ .GenerateCode("SampleView", "Sample.App", resolvedNames)
.Replace("\r", string.Empty);
var expected = (await OnlyPropertiesCode.Load(expectation))
diff --git a/tests/Avalonia.Generators.Tests/XamlXClassResolverTests.cs b/tests/Avalonia.Generators.Tests/XamlXClassResolverTests.cs
index 8d6db6ce47..6419488fd7 100644
--- a/tests/Avalonia.Generators.Tests/XamlXClassResolverTests.cs
+++ b/tests/Avalonia.Generators.Tests/XamlXClassResolverTests.cs
@@ -1,3 +1,4 @@
+using System.Threading;
using System.Threading.Tasks;
using Avalonia.Generators.Common;
using Avalonia.Generators.Compiler;
@@ -23,17 +24,9 @@ public class XamlXClassResolverTests
public async Task Should_Resolve_Base_Class_From_Xaml_File(string nameSpace, string className, string markup)
{
var xaml = await View.Load(markup);
- var compilation = View
- .CreateAvaloniaCompilation()
- .WithCustomTextBox()
- .WithBaseView();
+ var resolver = new XamlXViewResolver(MiniCompiler.CreateNoop());
- var types = new RoslynTypeSystem(compilation);
- var resolver = new XamlXViewResolver(
- types,
- MiniCompiler.CreateDefault(types, MiniCompiler.AvaloniaXmlnsDefinitionAttribute));
-
- var resolvedClass = resolver.ResolveView(xaml);
+ var resolvedClass = resolver.ResolveView(xaml, CancellationToken.None);
Assert.NotNull(resolvedClass);
Assert.Equal(className, resolvedClass.ClassName);
Assert.Equal(nameSpace, resolvedClass.Namespace);
diff --git a/tests/Avalonia.Generators.Tests/XamlXNameResolverTests.cs b/tests/Avalonia.Generators.Tests/XamlXNameResolverTests.cs
index 46bd75d643..5af5ba4b00 100644
--- a/tests/Avalonia.Generators.Tests/XamlXNameResolverTests.cs
+++ b/tests/Avalonia.Generators.Tests/XamlXNameResolverTests.cs
@@ -1,4 +1,6 @@
using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
using System.Threading.Tasks;
using Avalonia.Controls;
using Avalonia.Generators.Common;
@@ -6,6 +8,7 @@ using Avalonia.Generators.Common.Domain;
using Avalonia.Generators.Compiler;
using Avalonia.ReactiveUI;
using Avalonia.Generators.Tests.Views;
+using Microsoft.CodeAnalysis;
using Xunit;
namespace Avalonia.Generators.Tests;
@@ -123,20 +126,19 @@ public class XamlXNameResolverTests
private static IReadOnlyList ResolveNames(string xaml)
{
+ var nameResolver = new XamlXNameResolver();
+
+ // Step 1: parse XAML as xml nodes, without any type information.
+ var classResolver = new XamlXViewResolver(MiniCompiler.CreateNoop());
+ var classInfo = classResolver.ResolveView(xaml, CancellationToken.None);
+ Assert.NotNull(classInfo);
+ var names = nameResolver.ResolveXmlNames(classInfo.Xaml, CancellationToken.None);
+
+ // Step 2: use compilation context to resolve types
var compilation =
View.CreateAvaloniaCompilation()
.WithCustomTextBox()
.WithBaseView();
-
- var classResolver = new XamlXViewResolver(
- new RoslynTypeSystem(compilation),
- MiniCompiler.CreateDefault(
- new RoslynTypeSystem(compilation),
- MiniCompiler.AvaloniaXmlnsDefinitionAttribute));
-
- var classInfo = classResolver.ResolveView(xaml);
- Assert.NotNull(classInfo);
- var nameResolver = new XamlXNameResolver();
- return nameResolver.ResolveNames(classInfo.Xaml);
+ return names.ResolveNames(compilation, nameResolver).ToArray();
}
}