Skip to content

Commit 70c49d1

Browse files
committed
Add '[GeneratedAppServiceHost]' attribute type
1 parent f68b369 commit 70c49d1

File tree

2 files changed

+76
-4
lines changed

2 files changed

+76
-4
lines changed

components/AppServices/CommunityToolkit.AppServices.SourceGenerators/AppServiceGenerator.cs

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
7878
});
7979

8080
// Gather all interfaces, and only enable this branch if the target is a UWP app (the host)
81-
IncrementalValuesProvider<(HierarchyInfo Hierarchy, AppServiceInfo Info)> appServiceHostInfo =
81+
IncrementalValuesProvider<(HierarchyInfo, AppServiceInfo)> appServiceHostInfo =
8282
context.ForAttributeWithMetadataNameAndOptions(
8383
"CommunityToolkit.AppServices.AppServiceAttribute",
8484
static (node, _) => node is InterfaceDeclarationSyntax,
@@ -105,6 +105,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
105105

106106
token.ThrowIfCancellationRequested();
107107

108+
// Gather all methods for the app service type
108109
ImmutableArray<MethodInfo> methods = MethodInfo.From(typeSymbol, token);
109110

110111
token.ThrowIfCancellationRequested();
@@ -113,8 +114,47 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
113114
})
114115
.Where(static item => item.Hierarchy is not null);
115116

116-
// Produce the host type
117-
context.RegisterSourceOutput(appServiceHostInfo, static (context, item) =>
117+
// Also gather all explicitly requested host implementation types
118+
IncrementalValuesProvider<(HierarchyInfo, AppServiceInfo)> additionalAppServiceHostInfo =
119+
context.ForAttributeWithMetadataNameAndOptions(
120+
"CommunityToolkit.AppServices.GeneratedAppServiceHostAttribute",
121+
static (node, _) => true,
122+
static (context, token) =>
123+
{
124+
// Only retrieve host info if the target is a UWP application
125+
if (!Helpers.IsUwpTarget(context.SemanticModel.Compilation, context.GlobalOptions))
126+
{
127+
return default;
128+
}
129+
130+
// Get the target interface
131+
if (context.Attributes[0].ConstructorArguments is not [{ Kind: TypedConstantKind.Type, Value: INamedTypeSymbol appServiceType }])
132+
{
133+
return default;
134+
}
135+
136+
// Check if the current interface is in fact an app service type
137+
if (!appServiceType.TryGetAppServicesNameFromAttribute(out string? appServiceName))
138+
{
139+
return default;
140+
}
141+
142+
token.ThrowIfCancellationRequested();
143+
144+
HierarchyInfo hierarchy = HierarchyInfo.From(appServiceType, appServiceType.Name.Substring(1));
145+
146+
token.ThrowIfCancellationRequested();
147+
148+
ImmutableArray<MethodInfo> methods = MethodInfo.From(appServiceType, token);
149+
150+
token.ThrowIfCancellationRequested();
151+
152+
return (Hierarchy: hierarchy, new AppServiceInfo(methods, appServiceName, appServiceType.GetFullyQualifiedName()));
153+
})
154+
.Where(static item => item.Hierarchy is not null);
155+
156+
// Shared helper to emit all discovered types
157+
static void GenerateAppServiceHostType(SourceProductionContext context, (HierarchyInfo Hierarchy, AppServiceInfo Info) item)
118158
{
119159
ConstructorDeclarationSyntax constructorSyntax = Host.GetConstructorSyntax(item.Hierarchy, item.Info);
120160
ImmutableArray<MethodDeclarationSyntax> methodDeclarations = Host.GetMethodDeclarationsSyntax(item.Info);
@@ -126,6 +166,10 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
126166
$"/// <summary>A generated host implementation for the <see cref=\"{item.Info.InterfaceFullyQualifiedName}\"/> interface.</summary>");
127167

128168
context.AddSource($"{item.Hierarchy.FilenameHint}.g.cs", compilationUnit.GetText(Encoding.UTF8));
129-
});
169+
}
170+
171+
// Produce the host types
172+
context.RegisterSourceOutput(appServiceHostInfo, GenerateAppServiceHostType);
173+
context.RegisterSourceOutput(additionalAppServiceHostInfo, GenerateAppServiceHostType);
130174
}
131175
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System;
6+
7+
namespace CommunityToolkit.AppServices;
8+
9+
/// <summary>
10+
/// An attribute that can be used to request the generator to emit a host implementation of a given app service.
11+
/// </summary>
12+
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false, Inherited = false)]
13+
public sealed class GeneratedAppServiceHostAttribute : Attribute
14+
{
15+
/// <summary>
16+
/// Creates a new <see cref="GeneratedAppServiceHostAttribute"/> instance with the specified parameters.
17+
/// </summary>
18+
/// <param name="appServiceType">The type of the app service.</param>
19+
public GeneratedAppServiceHostAttribute(Type appServiceType)
20+
{
21+
AppServiceType = appServiceType;
22+
}
23+
24+
/// <summary>
25+
/// Gets the type of the app service.
26+
/// </summary>
27+
public Type AppServiceType { get; }
28+
}

0 commit comments

Comments
 (0)