diff --git a/components/AppServices/CommunityToolkit.AppServices.SourceGenerators/AppServiceGenerator.Helpers.cs b/components/AppServices/CommunityToolkit.AppServices.SourceGenerators/AppServiceGenerator.Helpers.cs
index 94c333763..ed86c952a 100644
--- a/components/AppServices/CommunityToolkit.AppServices.SourceGenerators/AppServiceGenerator.Helpers.cs
+++ b/components/AppServices/CommunityToolkit.AppServices.SourceGenerators/AppServiceGenerator.Helpers.cs
@@ -1,8 +1,9 @@
-// Licensed to the .NET Foundation under one or more agreements.
+// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Diagnostics;
namespace CommunityToolkit.AppServices.SourceGenerators;
@@ -18,10 +19,27 @@ private static class Helpers
/// Gets whether the current target is a UWP application.
///
/// The input instance to inspect.
+ /// The analyzer options to use to get info on the target application.
/// Whether the current target is a UWP application.
- public static bool IsUwpTarget(Compilation compilation)
+ public static bool IsUwpTarget(Compilation compilation, AnalyzerConfigOptions analyzerOptions)
{
- return compilation.Options.OutputKind == OutputKind.WindowsRuntimeApplication;
+ // If the application type is a Windows Runtime application, then it's for sure a UWP app
+ if (compilation.Options.OutputKind == OutputKind.WindowsRuntimeApplication)
+ {
+ return true;
+ }
+
+ // Otherwise, the application is UWP if "UseUwpTools" is set
+ if (analyzerOptions.TryGetValue("build_property.UseUwpTools", out string? propertyValue))
+ {
+ if (bool.TryParse(propertyValue, out bool useUwpTools))
+ {
+ return true;
+ }
+ }
+
+ // The app is definitely not a UWP app
+ return false;
}
}
}
diff --git a/components/AppServices/CommunityToolkit.AppServices.SourceGenerators/AppServiceGenerator.cs b/components/AppServices/CommunityToolkit.AppServices.SourceGenerators/AppServiceGenerator.cs
index 466f313bc..f85e2a73b 100644
--- a/components/AppServices/CommunityToolkit.AppServices.SourceGenerators/AppServiceGenerator.cs
+++ b/components/AppServices/CommunityToolkit.AppServices.SourceGenerators/AppServiceGenerator.cs
@@ -24,13 +24,12 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
{
// Get all app service class implementations, and only enable this branch if the target is not a UWP app (the component)
IncrementalValuesProvider<(HierarchyInfo Hierarchy, AppServiceInfo Info)> appServiceComponentInfo =
- context.SyntaxProvider
- .CreateSyntaxProvider(
+ context.CreateSyntaxProviderWithOptions(
static (node, _) => node is ClassDeclarationSyntax classDeclaration && classDeclaration.HasOrPotentiallyHasBaseTypes(),
static (context, token) =>
{
// Only retrieve host info if the target is not a UWP application
- if (Helpers.IsUwpTarget(context.SemanticModel.Compilation))
+ if (Helpers.IsUwpTarget(context.SemanticModel.Compilation, context.GlobalOptions))
{
return default;
}
@@ -80,14 +79,13 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
// Gather all interfaces, and only enable this branch if the target is a UWP app (the host)
IncrementalValuesProvider<(HierarchyInfo Hierarchy, AppServiceInfo Info)> appServiceHostInfo =
- context.SyntaxProvider
- .ForAttributeWithMetadataName(
+ context.ForAttributeWithMetadataNameAndOptions(
"CommunityToolkit.AppServices.AppServiceAttribute",
static (node, _) => node is InterfaceDeclarationSyntax,
static (context, token) =>
{
// Only retrieve host info if the target is a UWP application
- if (!Helpers.IsUwpTarget(context.SemanticModel.Compilation))
+ if (!Helpers.IsUwpTarget(context.SemanticModel.Compilation, context.GlobalOptions))
{
return default;
}
diff --git a/components/AppServices/CommunityToolkit.AppServices.SourceGenerators/Extensions/GeneratorAttributeSyntaxContextWithOptions.cs b/components/AppServices/CommunityToolkit.AppServices.SourceGenerators/Extensions/GeneratorAttributeSyntaxContextWithOptions.cs
new file mode 100644
index 000000000..7f7596e01
--- /dev/null
+++ b/components/AppServices/CommunityToolkit.AppServices.SourceGenerators/Extensions/GeneratorAttributeSyntaxContextWithOptions.cs
@@ -0,0 +1,34 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Immutable;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Diagnostics;
+
+namespace CommunityToolkit.AppServices.SourceGenerators.Extensions;
+
+///
+///
+///
+/// The original value.
+/// The original value.
+internal readonly struct GeneratorAttributeSyntaxContextWithOptions(
+ GeneratorAttributeSyntaxContext syntaxContext,
+ AnalyzerConfigOptions globalOptions)
+{
+ ///
+ public SyntaxNode TargetNode { get; } = syntaxContext.TargetNode;
+
+ ///
+ public ISymbol TargetSymbol { get; } = syntaxContext.TargetSymbol;
+
+ ///
+ public SemanticModel SemanticModel { get; } = syntaxContext.SemanticModel;
+
+ ///
+ public ImmutableArray Attributes { get; } = syntaxContext.Attributes;
+
+ ///
+ public AnalyzerConfigOptions GlobalOptions { get; } = globalOptions;
+}
diff --git a/components/AppServices/CommunityToolkit.AppServices.SourceGenerators/Extensions/GeneratorSyntaxContextWithOptions.cs b/components/AppServices/CommunityToolkit.AppServices.SourceGenerators/Extensions/GeneratorSyntaxContextWithOptions.cs
new file mode 100644
index 000000000..141087948
--- /dev/null
+++ b/components/AppServices/CommunityToolkit.AppServices.SourceGenerators/Extensions/GeneratorSyntaxContextWithOptions.cs
@@ -0,0 +1,27 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Diagnostics;
+
+namespace CommunityToolkit.AppServices.SourceGenerators.Extensions;
+
+///
+///
+///
+/// The original value.
+/// The original value.
+internal readonly struct GeneratorSyntaxContextWithOptions(
+ GeneratorSyntaxContext syntaxContext,
+ AnalyzerConfigOptions globalOptions)
+{
+ ///
+ public SyntaxNode Node { get; } = syntaxContext.Node;
+
+ ///
+ public SemanticModel SemanticModel { get; } = syntaxContext.SemanticModel;
+
+ ///
+ public AnalyzerConfigOptions GlobalOptions { get; } = globalOptions;
+}
diff --git a/components/AppServices/CommunityToolkit.AppServices.SourceGenerators/Extensions/IncrementalGeneratorInitializationContextExtensions.cs b/components/AppServices/CommunityToolkit.AppServices.SourceGenerators/Extensions/IncrementalGeneratorInitializationContextExtensions.cs
new file mode 100644
index 000000000..d8e900d9b
--- /dev/null
+++ b/components/AppServices/CommunityToolkit.AppServices.SourceGenerators/Extensions/IncrementalGeneratorInitializationContextExtensions.cs
@@ -0,0 +1,59 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Threading;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Diagnostics;
+
+namespace CommunityToolkit.AppServices.SourceGenerators.Extensions;
+
+///
+/// Extension methods for .
+///
+internal static class IncrementalGeneratorInitializationContextExtensions
+{
+ ///
+ public static IncrementalValuesProvider ForAttributeWithMetadataNameAndOptions(
+ this IncrementalGeneratorInitializationContext context,
+ string fullyQualifiedMetadataName,
+ Func predicate,
+ Func transform)
+ {
+ // Invoke 'ForAttributeWithMetadataName' normally, but just return the context directly
+ IncrementalValuesProvider syntaxContext = context.SyntaxProvider.ForAttributeWithMetadataName(
+ fullyQualifiedMetadataName,
+ predicate,
+ static (context, token) => context);
+
+ // Do the same for the analyzer config options
+ IncrementalValueProvider configOptions = context.AnalyzerConfigOptionsProvider.Select(static (provider, token) => provider.GlobalOptions);
+
+ // Merge the two and invoke the provided transform on these two values. Neither value
+ // is equatable, meaning the pipeline will always re-run until this point. This is
+ // intentional: we don't want any symbols or other expensive objects to be kept alive
+ // across incremental steps, especially if they could cause entire compilations to be
+ // rooted, which would significantly increase memory use and introduce more GC pauses.
+ // In this specific case, flowing non equatable values in a pipeline is therefore fine.
+ return syntaxContext.Combine(configOptions).Select((input, token) => transform(new GeneratorAttributeSyntaxContextWithOptions(input.Left, input.Right), token));
+ }
+
+ ///
+ public static IncrementalValuesProvider CreateSyntaxProviderWithOptions(
+ this IncrementalGeneratorInitializationContext context,
+ Func predicate,
+ Func transform)
+ {
+ // Invoke 'ForAttributeWithMetadataName' normally, but just return the context directly
+ IncrementalValuesProvider syntaxContext = context.SyntaxProvider.CreateSyntaxProvider(
+ predicate,
+ static (context, token) => context);
+
+ // Do the same for the analyzer config options
+ IncrementalValueProvider configOptions = context.AnalyzerConfigOptionsProvider.Select(static (provider, token) => provider.GlobalOptions);
+
+ // Merge the two and invoke the provided transform, like the extension above
+ return syntaxContext.Combine(configOptions).Select((input, token) => transform(new GeneratorSyntaxContextWithOptions(input.Left, input.Right), token));
+ }
+}
diff --git a/components/AppServices/src/AppServiceComponent.cs b/components/AppServices/src/AppServiceComponent.cs
index 3e70a95f0..2692f96fe 100644
--- a/components/AppServices/src/AppServiceComponent.cs
+++ b/components/AppServices/src/AppServiceComponent.cs
@@ -14,7 +14,7 @@
using System.Diagnostics.CodeAnalysis;
using CommunityToolkit.AppServices.Helpers;
-#pragma warning disable CA2213, CA1063
+#pragma warning disable CA2213, CA1063, CsWinRT1028
namespace CommunityToolkit.AppServices;
diff --git a/components/AppServices/src/CommunityToolkit.AppServices.csproj b/components/AppServices/src/CommunityToolkit.AppServices.csproj
index e0f0267bc..ed88531c1 100644
--- a/components/AppServices/src/CommunityToolkit.AppServices.csproj
+++ b/components/AppServices/src/CommunityToolkit.AppServices.csproj
@@ -36,7 +36,7 @@
-
+
@@ -49,13 +49,8 @@
-
-
-
-
-
-
-
+
+
diff --git a/components/AppServices/src/CommunityToolkit.AppServices.targets b/components/AppServices/src/CommunityToolkit.AppServices.targets
index 78089e0a2..21ddc5cf2 100644
--- a/components/AppServices/src/CommunityToolkit.AppServices.targets
+++ b/components/AppServices/src/CommunityToolkit.AppServices.targets
@@ -1,5 +1,10 @@
+
+
+
+
+