diff --git a/src/CommunityToolkit.Mvvm.SourceGenerators/CommunityToolkit.Mvvm.SourceGenerators.projitems b/src/CommunityToolkit.Mvvm.SourceGenerators/CommunityToolkit.Mvvm.SourceGenerators.projitems
index 5bc1b1792..c4cbb324e 100644
--- a/src/CommunityToolkit.Mvvm.SourceGenerators/CommunityToolkit.Mvvm.SourceGenerators.projitems
+++ b/src/CommunityToolkit.Mvvm.SourceGenerators/CommunityToolkit.Mvvm.SourceGenerators.projitems
@@ -55,6 +55,7 @@
+
diff --git a/src/CommunityToolkit.Mvvm.SourceGenerators/Extensions/GeneratorAttributeSyntaxContextWithOptions.cs b/src/CommunityToolkit.Mvvm.SourceGenerators/Extensions/GeneratorAttributeSyntaxContextWithOptions.cs
new file mode 100644
index 000000000..2af137911
--- /dev/null
+++ b/src/CommunityToolkit.Mvvm.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.Mvvm.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/src/CommunityToolkit.Mvvm.SourceGenerators/Extensions/IncrementalGeneratorInitializationContextExtensions.cs b/src/CommunityToolkit.Mvvm.SourceGenerators/Extensions/IncrementalGeneratorInitializationContextExtensions.cs
index d009810eb..1c627db6d 100644
--- a/src/CommunityToolkit.Mvvm.SourceGenerators/Extensions/IncrementalGeneratorInitializationContextExtensions.cs
+++ b/src/CommunityToolkit.Mvvm.SourceGenerators/Extensions/IncrementalGeneratorInitializationContextExtensions.cs
@@ -4,7 +4,11 @@
using System;
using System.Collections.Immutable;
+using System.Threading;
using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Diagnostics;
+
+#pragma warning disable CS1574
namespace CommunityToolkit.Mvvm.SourceGenerators.Extensions;
@@ -13,6 +17,31 @@ namespace CommunityToolkit.Mvvm.SourceGenerators.Extensions;
///
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));
+ }
+
///
/// Conditionally invokes
/// if the value produced by the input is .
diff --git a/src/CommunityToolkit.Mvvm/CommunityToolkit.Mvvm.FeatureSwitches.targets b/src/CommunityToolkit.Mvvm/CommunityToolkit.Mvvm.FeatureSwitches.targets
index 19c3c56c0..bf6d6ed6c 100644
--- a/src/CommunityToolkit.Mvvm/CommunityToolkit.Mvvm.FeatureSwitches.targets
+++ b/src/CommunityToolkit.Mvvm/CommunityToolkit.Mvvm.FeatureSwitches.targets
@@ -5,6 +5,14 @@
true
+
+
+
+
+