Skip to content

Commit 163301b

Browse files
authored
feature: add avalonia generation (#422)
* add avalonia generation * Update ReactiveUI.Avalonia.ViewToViewModelBindings.csproj * add base dll * fix "new" properties * add avalonia int test
1 parent 160fa9a commit 163301b

File tree

7 files changed

+231
-36
lines changed

7 files changed

+231
-36
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<TargetFramework>net8.0-windows10.0.19041</TargetFramework>
4+
<LangVersion>9</LangVersion>
5+
<DebugType>full</DebugType>
6+
<DebugSymbols>True</DebugSymbols>
7+
<!--
8+
If you're seeing CS8032 warnings, it can be because the upstream source generator dll has been rebuilt or you've changed the
9+
target frameworks in this project. Visual Studio seems to have a cache that invalidates. Reloading Visual Studio can
10+
solve the issue.
11+
-->
12+
<!--<WarningsAsErrors>8032,8785</WarningsAsErrors>-->
13+
<TreatWarningsAsErrors />
14+
<IsPackable>False</IsPackable>
15+
</PropertyGroup>
16+
<ItemGroup>
17+
<PackageReference Include="Avalonia.ReactiveUI" Version="11.0.10" />
18+
</ItemGroup>
19+
20+
<ItemGroup>
21+
<ProjectReference Include="..\Vetuviem.Avalonia.SourceGenerator\Vetuviem.Avalonia.SourceGenerator.csproj" OutputItemType="Analyzer" />
22+
<ProjectReference Include="..\Vetuviem.Core\Vetuviem.Core.csproj" />
23+
</ItemGroup>
24+
25+
<Import Project="..\Vetuviem.SourceGenerator\Vetuviem-SourceGenerator.props" />
26+
<PropertyGroup>
27+
<Vetuviem_Make_Classes_Public>true</Vetuviem_Make_Classes_Public>
28+
</PropertyGroup>
29+
</Project>
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright (c) 2022 DPVreony and Contributors. All rights reserved.
2+
// DPVreony and Contributors licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for full license information.
4+
5+
using Microsoft.CodeAnalysis;
6+
using Vetuviem.SourceGenerator;
7+
using Vetuviem.SourceGenerator.Features.Core;
8+
9+
namespace Vetuviem.Avalonia.SourceGenerator
10+
{
11+
/// <summary>
12+
/// Control Binding Model Source Generator for Blazor.
13+
/// </summary>
14+
[Generator]
15+
public sealed class AvaloniaControlBindingModelSourceGenerator : AbstractControlBindingModelSourceGenerator
16+
{
17+
/// <inheritdoc />
18+
protected override MetadataReference? CheckIfShouldAddMissingAssemblyReference(string assemblyOfInterest)
19+
{
20+
return null;
21+
}
22+
23+
/// <inheritdoc />
24+
protected override IPlatformResolver GetPlatformResolver()
25+
{
26+
return new AvaloniaPlatformResolver();
27+
}
28+
29+
/// <inheritdoc />
30+
protected override string GetPlatformName()
31+
{
32+
return "Avalonia";
33+
}
34+
}
35+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright (c) 2022 DPVreony and Contributors. All rights reserved.
2+
// DPVreony and Contributors licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for full license information.
4+
5+
using Vetuviem.SourceGenerator.Features.Core;
6+
7+
namespace Vetuviem.Avalonia.SourceGenerator
8+
{
9+
/// <summary>
10+
/// UI Platform resolver for Blazor.
11+
/// </summary>
12+
public sealed class AvaloniaPlatformResolver : IPlatformResolver
13+
{
14+
/// <inheritdoc />
15+
public string[] GetAssemblyNames()
16+
{
17+
return new[]
18+
{
19+
"Avalonia.Base.dll",
20+
"Avalonia.Controls.dll",
21+
"Avalonia.ReactiveUI.dll"
22+
};
23+
}
24+
25+
/// <inheritdoc />
26+
public string GetBaseUiElement()
27+
{
28+
return "global::Avalonia.Visual";
29+
}
30+
31+
/// <inheritdoc />
32+
public string? GetCommandSourceInterface()
33+
{
34+
return "global::Avalonia.Input.ICommandSource";
35+
}
36+
37+
/// <inheritdoc />
38+
public string GetCommandInterface()
39+
{
40+
return "global::Avalonia.Input.ICommand";
41+
}
42+
}
43+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// Copyright (c) 2022 DPVreony and Contributors. All rights reserved.
2+
// DPVreony and Contributors licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for full license information.
4+
5+
using System;
6+
using System.Collections.Generic;
7+
using System.IO;
8+
using Microsoft.CodeAnalysis;
9+
using Microsoft.CodeAnalysis.Diagnostics;
10+
using Vetuviem.Avalonia.SourceGenerator;
11+
using Vetuviem.SourceGenerator.Features.ControlBindingModels;
12+
using Vetuviem.Testing;
13+
using Vetuviem.Winforms.SourceGenerator;
14+
using Xunit.Abstractions;
15+
16+
namespace Vetuviem.IntegrationTests.ReactiveUI.Avalonia
17+
{
18+
/// <summary>
19+
/// Unit Tests for the ViewBinding Model Source Generator.
20+
/// </summary>
21+
public static class AvaloniaViewBindingModelGeneratorTests
22+
{
23+
/// <inheritdoc />
24+
public sealed class ExecuteMethod : BaseGeneratorTests.BaseExecuteMethod<AvaloniaControlBindingModelSourceGenerator, ControlBindingModelGeneratorProcessor>
25+
{
26+
/// <summary>
27+
/// Initializes a new instance of the <see cref="ExecuteMethod"/> class.
28+
/// </summary>
29+
/// <param name="output">Test Output Helper.</param>
30+
public ExecuteMethod(ITestOutputHelper output)
31+
: base(output)
32+
{
33+
}
34+
35+
/// <inheritdoc />
36+
protected override AnalyzerConfigOptionsProvider? GetAnalyzerConfigOptionsProvider()
37+
{
38+
return null;
39+
}
40+
41+
/// <inheritdoc />
42+
protected override void AddReferenceAssemblies(IList<MetadataReference> metadataReferences)
43+
{
44+
if (metadataReferences == null)
45+
{
46+
throw new ArgumentNullException(nameof(metadataReferences));
47+
}
48+
49+
var trustedAssembliesPaths = GetPlatformAssemblyPaths();
50+
if (trustedAssembliesPaths == null)
51+
{
52+
return;
53+
}
54+
55+
foreach (string trustedAssembliesPath in trustedAssembliesPaths)
56+
{
57+
var metadataReference = MetadataReference.CreateFromFile(trustedAssembliesPath);
58+
metadataReferences.Add(metadataReference);
59+
}
60+
}
61+
62+
/// <inheritdoc />
63+
protected override Func<AvaloniaControlBindingModelSourceGenerator> GetFactory()
64+
{
65+
return () => new AvaloniaControlBindingModelSourceGenerator();
66+
}
67+
68+
private static string[]? GetPlatformAssemblyPaths()
69+
{
70+
if (AppContext.GetData("TRUSTED_PLATFORM_ASSEMBLIES") is string trustedPlatformAssemblies)
71+
{
72+
return trustedPlatformAssemblies.Split(Path.PathSeparator);
73+
}
74+
75+
return null;
76+
}
77+
}
78+
}
79+
}

src/Vetuviem.IntegrationTests/Vetuviem.IntegrationTests.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,15 @@
77
</PropertyGroup>
88

99
<ItemGroup>
10+
<PackageReference Include="Avalonia.ReactiveUI" Version="11.0.10" />
1011
<PackageReference Include="MahApps.Metro" Version="2.4.10" />
1112
<PackageReference Include="MahApps.Metro.SimpleChildWindow" Version="2.2.1" />
1213
<PackageReference Include="ReactiveUI.WPF" Version="20.1.1" />
1314
</ItemGroup>
1415

1516
<ItemGroup>
17+
<ProjectReference Include="..\Vetuviem.Avalonia.SourceGenerator\Vetuviem.Avalonia.SourceGenerator.csproj" />
18+
<ProjectReference Include="..\Vetuviem.Maui.SourceGenerator\Vetuviem.Maui.SourceGenerator.csproj" />
1619
<ProjectReference Include="..\Vetuviem.Testing\Vetuviem.Testing.csproj" />
1720
<ProjectReference Include="..\Vetuviem.Winforms.SourceGenerator\Vetuviem.Winforms.SourceGenerator.csproj" />
1821
<ProjectReference Include="..\Vetuviem.WinUi.SourceGenerator\Vetuviem.WinUi.SourceGenerator.csproj" />

src/Vetuviem.SourceGenerator/Features/ControlBindingModels/ControlBindingModelPropertyGenerator.cs

Lines changed: 19 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System;
66
using System.Collections.Generic;
77
using System.Collections.Immutable;
8+
using System.ComponentModel;
89
using System.Linq;
910
using Microsoft.CodeAnalysis;
1011
using Microsoft.CodeAnalysis.CSharp;
@@ -58,9 +59,7 @@ public static SyntaxList<MemberDeclarationSyntax> GetProperties(
5859

5960
foreach (var prop in properties)
6061
{
61-
var propertySymbol = prop as IPropertySymbol;
62-
63-
if (propertySymbol == null
62+
if (prop is not IPropertySymbol propertySymbol
6463
|| propertySymbol.IsIndexer
6564
|| propertySymbol.IsOverride
6665
|| propertySymbol.DeclaredAccessibility != Accessibility.Public
@@ -78,13 +77,7 @@ public static SyntaxList<MemberDeclarationSyntax> GetProperties(
7877
continue;
7978
}
8079

81-
// windows forms has an issue where some properties are provided as "new" instances instead of overridden
82-
// we're getting build warnings for these.
83-
if (ReplacesBaseProperty(propertySymbol, namedTypeSymbol))
84-
{
85-
// for now we skip, but we may adjust our model moving forward to make them "new".
86-
continue;
87-
}
80+
var treatAsNewImplementation = ReplacesBaseProperty(propertySymbol);
8881

8982
var accessorList = GetAccessorDeclarationSyntaxes();
9083

@@ -97,7 +90,8 @@ public static SyntaxList<MemberDeclarationSyntax> GetProperties(
9790
accessorList,
9891
summary,
9992
desiredCommandInterface,
100-
makeClassesPublic);
93+
makeClassesPublic,
94+
treatAsNewImplementation);
10195

10296
nodes.Add(propSyntax);
10397
}
@@ -145,31 +139,11 @@ private static MemberDeclarationSyntax GetBindCommandPropertyDeclaration(
145139
platformCommandType);
146140
}
147141

148-
private static bool ReplacesBaseProperty(
149-
IPropertySymbol propertySymbol,
150-
INamedTypeSymbol namedTypeSymbol)
142+
private static bool ReplacesBaseProperty(IPropertySymbol propertySymbol)
151143
{
152-
var wantedName = propertySymbol.Name;
153-
var baseType = namedTypeSymbol.BaseType;
154-
while (baseType != null)
155-
{
156-
var nameMatches = baseType.GetMembers()
157-
.Where(x => x.Kind == SymbolKind.Property && x.Name.Equals(wantedName, StringComparison.Ordinal))
158-
.Cast<IPropertySymbol>()
159-
.ToImmutableArray();
160-
161-
foreach (var nameMatch in nameMatches)
162-
{
163-
if (SymbolEqualityComparer.Default.Equals(nameMatch.Type, propertySymbol.Type))
164-
{
165-
return true;
166-
}
167-
}
144+
var accessor = propertySymbol.GetMethod ?? propertySymbol.SetMethod;
168145

169-
baseType = baseType.BaseType;
170-
}
171-
172-
return false;
146+
return accessor is { HidesBaseMethodsByName: true };
173147
}
174148

175149
private static PropertyDeclarationSyntax GetBindCommandPropertyDeclaration(
@@ -196,18 +170,27 @@ private static PropertyDeclarationSyntax GetPropertyDeclaration(
196170
AccessorDeclarationSyntax[] accessorList,
197171
IEnumerable<SyntaxTrivia> summary,
198172
string? desiredCommandInterface,
199-
bool makeClassesPublic)
173+
bool makeClassesPublic,
174+
bool treatAsNewImplementation)
200175
{
201176
TypeSyntax type = GetBindingTypeSyntax(prop, desiredCommandInterface);
202177

178+
var modifiers =
179+
SyntaxFactory.Token(makeClassesPublic ? SyntaxKind.PublicKeyword : SyntaxKind.InternalKeyword);
180+
203181
var result = SyntaxFactory.PropertyDeclaration(
204182
type,
205183
prop.Name)
206-
.AddModifiers(SyntaxFactory.Token(makeClassesPublic ? SyntaxKind.PublicKeyword : SyntaxKind.InternalKeyword))
184+
.AddModifiers(modifiers)
207185
.WithAccessorList(
208186
SyntaxFactory.AccessorList(SyntaxFactory.List(accessorList)))
209187
.WithLeadingTrivia(summary);
210188

189+
if (treatAsNewImplementation)
190+
{
191+
result = result.AddModifiers(SyntaxFactory.Token(SyntaxKind.NewKeyword));
192+
}
193+
211194
return result;
212195
}
213196

src/Vetuviem.sln

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Vetuviem.Winforms.SourceGen
4747
EndProject
4848
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Vetuviem.Avalonia.SourceGenerator", "Vetuviem.Avalonia.SourceGenerator\Vetuviem.Avalonia.SourceGenerator.csproj", "{00BC63E3-7FD3-483E-A2E0-CCB9897947E0}"
4949
EndProject
50+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReactiveUI.Avalonia.ViewToViewModelBindings", "ReactiveUI.Avalonia.ViewToViewModelBindings\ReactiveUI.Avalonia.ViewToViewModelBindings.csproj", "{ED7AD6E7-AA52-419A-A127-6AEA2933EEFB}"
51+
EndProject
5052
Global
5153
GlobalSection(SolutionConfigurationPlatforms) = preSolution
5254
Debug|Any CPU = Debug|Any CPU
@@ -441,6 +443,26 @@ Global
441443
{00BC63E3-7FD3-483E-A2E0-CCB9897947E0}.Release|x64.Build.0 = Release|Any CPU
442444
{00BC63E3-7FD3-483E-A2E0-CCB9897947E0}.Release|x86.ActiveCfg = Release|Any CPU
443445
{00BC63E3-7FD3-483E-A2E0-CCB9897947E0}.Release|x86.Build.0 = Release|Any CPU
446+
{ED7AD6E7-AA52-419A-A127-6AEA2933EEFB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
447+
{ED7AD6E7-AA52-419A-A127-6AEA2933EEFB}.Debug|Any CPU.Build.0 = Debug|Any CPU
448+
{ED7AD6E7-AA52-419A-A127-6AEA2933EEFB}.Debug|ARM.ActiveCfg = Debug|Any CPU
449+
{ED7AD6E7-AA52-419A-A127-6AEA2933EEFB}.Debug|ARM.Build.0 = Debug|Any CPU
450+
{ED7AD6E7-AA52-419A-A127-6AEA2933EEFB}.Debug|ARM64.ActiveCfg = Debug|Any CPU
451+
{ED7AD6E7-AA52-419A-A127-6AEA2933EEFB}.Debug|ARM64.Build.0 = Debug|Any CPU
452+
{ED7AD6E7-AA52-419A-A127-6AEA2933EEFB}.Debug|x64.ActiveCfg = Debug|Any CPU
453+
{ED7AD6E7-AA52-419A-A127-6AEA2933EEFB}.Debug|x64.Build.0 = Debug|Any CPU
454+
{ED7AD6E7-AA52-419A-A127-6AEA2933EEFB}.Debug|x86.ActiveCfg = Debug|Any CPU
455+
{ED7AD6E7-AA52-419A-A127-6AEA2933EEFB}.Debug|x86.Build.0 = Debug|Any CPU
456+
{ED7AD6E7-AA52-419A-A127-6AEA2933EEFB}.Release|Any CPU.ActiveCfg = Release|Any CPU
457+
{ED7AD6E7-AA52-419A-A127-6AEA2933EEFB}.Release|Any CPU.Build.0 = Release|Any CPU
458+
{ED7AD6E7-AA52-419A-A127-6AEA2933EEFB}.Release|ARM.ActiveCfg = Release|Any CPU
459+
{ED7AD6E7-AA52-419A-A127-6AEA2933EEFB}.Release|ARM.Build.0 = Release|Any CPU
460+
{ED7AD6E7-AA52-419A-A127-6AEA2933EEFB}.Release|ARM64.ActiveCfg = Release|Any CPU
461+
{ED7AD6E7-AA52-419A-A127-6AEA2933EEFB}.Release|ARM64.Build.0 = Release|Any CPU
462+
{ED7AD6E7-AA52-419A-A127-6AEA2933EEFB}.Release|x64.ActiveCfg = Release|Any CPU
463+
{ED7AD6E7-AA52-419A-A127-6AEA2933EEFB}.Release|x64.Build.0 = Release|Any CPU
464+
{ED7AD6E7-AA52-419A-A127-6AEA2933EEFB}.Release|x86.ActiveCfg = Release|Any CPU
465+
{ED7AD6E7-AA52-419A-A127-6AEA2933EEFB}.Release|x86.Build.0 = Release|Any CPU
444466
EndGlobalSection
445467
GlobalSection(SolutionProperties) = preSolution
446468
HideSolutionNode = FALSE
@@ -455,6 +477,7 @@ Global
455477
{15274B47-731E-4352-9CBD-2639C548D9A9} = {1B3AF279-0165-4820-947C-222B1AE379D9}
456478
{3AA61E19-4EC3-4B5E-B7DB-3AB65F931F6C} = {1B3AF279-0165-4820-947C-222B1AE379D9}
457479
{D8E39D69-FD9A-4ACF-8743-048EF199884C} = {106C1632-9789-48A3-B7D0-FE793EC46DB8}
480+
{ED7AD6E7-AA52-419A-A127-6AEA2933EEFB} = {1B3AF279-0165-4820-947C-222B1AE379D9}
458481
EndGlobalSection
459482
GlobalSection(ExtensibilityGlobals) = postSolution
460483
SolutionGuid = {3C43A2D4-5AAF-4846-936D-75F742D25A81}

0 commit comments

Comments
 (0)