diff --git a/src/CommunityToolkit.Mvvm.SourceGenerators/CommunityToolkit.Mvvm.SourceGenerators.projitems b/src/CommunityToolkit.Mvvm.SourceGenerators/CommunityToolkit.Mvvm.SourceGenerators.projitems
index 91866191c..5e950360e 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/ComponentModel/ObservablePropertyGenerator.cs b/src/CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/ObservablePropertyGenerator.cs
index e97cfed29..a1f4e942f 100644
--- a/src/CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/ObservablePropertyGenerator.cs
+++ b/src/CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/ObservablePropertyGenerator.cs
@@ -4,7 +4,6 @@
using System.Collections.Immutable;
using System.Linq;
-using System.Text;
using CommunityToolkit.Mvvm.SourceGenerators.ComponentModel.Models;
using CommunityToolkit.Mvvm.SourceGenerators.Extensions;
using CommunityToolkit.Mvvm.SourceGenerators.Helpers;
@@ -75,7 +74,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
// Insert all members into the same partial type declaration
CompilationUnitSyntax compilationUnit = item.Hierarchy.GetCompilationUnit(memberDeclarations);
- context.AddSource($"{item.Hierarchy.FilenameHint}.g.cs", compilationUnit.GetText(Encoding.UTF8));
+ context.AddSource($"{item.Hierarchy.FilenameHint}.g.cs", compilationUnit);
});
// Gather all property changing names
@@ -92,7 +91,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
if (compilationUnit is not null)
{
- context.AddSource("__KnownINotifyPropertyChangingArgs.g.cs", compilationUnit.GetText(Encoding.UTF8));
+ context.AddSource("__KnownINotifyPropertyChangingArgs.g.cs", compilationUnit);
}
});
@@ -110,7 +109,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
if (compilationUnit is not null)
{
- context.AddSource("__KnownINotifyPropertyChangedArgs.g.cs", compilationUnit.GetText(Encoding.UTF8));
+ context.AddSource("__KnownINotifyPropertyChangedArgs.g.cs", compilationUnit);
}
});
}
diff --git a/src/CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/ObservableValidatorValidateAllPropertiesGenerator.cs b/src/CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/ObservableValidatorValidateAllPropertiesGenerator.cs
index 66ddec019..b4a5b1537 100644
--- a/src/CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/ObservableValidatorValidateAllPropertiesGenerator.cs
+++ b/src/CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/ObservableValidatorValidateAllPropertiesGenerator.cs
@@ -3,7 +3,6 @@
// See the LICENSE file in the project root for more information.
using System.Linq;
-using System.Text;
using CommunityToolkit.Mvvm.SourceGenerators.ComponentModel.Models;
using CommunityToolkit.Mvvm.SourceGenerators.Extensions;
using Microsoft.CodeAnalysis;
@@ -79,7 +78,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
{
CompilationUnitSyntax compilationUnit = Execute.GetSyntax(item);
- context.AddSource("__ObservableValidatorExtensions.g.cs", compilationUnit.GetText(Encoding.UTF8));
+ context.AddSource("__ObservableValidatorExtensions.g.cs", compilationUnit);
});
// Generate the class with all validation methods
@@ -87,7 +86,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
{
CompilationUnitSyntax compilationUnit = Execute.GetSyntax(item);
- context.AddSource($"{item.FilenameHint}.g.cs", compilationUnit.GetText(Encoding.UTF8));
+ context.AddSource($"{item.FilenameHint}.g.cs", compilationUnit);
});
}
}
diff --git a/src/CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/TransitiveMembersGenerator.cs b/src/CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/TransitiveMembersGenerator.cs
index fc430a04f..bd1d37498 100644
--- a/src/CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/TransitiveMembersGenerator.cs
+++ b/src/CommunityToolkit.Mvvm.SourceGenerators/ComponentModel/TransitiveMembersGenerator.cs
@@ -5,7 +5,6 @@
using System;
using System.Collections.Immutable;
using System.Linq;
-using System.Text;
using CommunityToolkit.Mvvm.SourceGenerators.Extensions;
using CommunityToolkit.Mvvm.SourceGenerators.Models;
using Microsoft.CodeAnalysis;
@@ -34,12 +33,12 @@ public abstract partial class TransitiveMembersGenerator : IIncrementalGe
///
/// The sequence of member declarations for sealed types.
///
- private ImmutableArray sealedMemberDeclarations;
+ private readonly ImmutableArray sealedMemberDeclarations;
///
/// The resulting sequence of member declarations for non sealed types.
///
- private ImmutableArray nonSealedMemberDeclarations;
+ private readonly ImmutableArray nonSealedMemberDeclarations;
///
/// Initializes a new instance of the class.
@@ -108,7 +107,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
ImmutableArray updatedMemberDeclarations = Execute.AdjustMemberDeclarationNullabilityAnnotations(filteredMemberDeclarations, item.MetadataInfo.IsNullabilitySupported);
CompilationUnitSyntax compilationUnit = item.Hierarchy.GetCompilationUnit(updatedMemberDeclarations, this.classDeclaration.BaseList);
- context.AddSource($"{item.Hierarchy.FilenameHint}.g.cs", compilationUnit.GetText(Encoding.UTF8));
+ context.AddSource($"{item.Hierarchy.FilenameHint}.g.cs", compilationUnit);
});
}
diff --git a/src/CommunityToolkit.Mvvm.SourceGenerators/Extensions/SourceProductionContextExtensions.cs b/src/CommunityToolkit.Mvvm.SourceGenerators/Extensions/SourceProductionContextExtensions.cs
new file mode 100644
index 000000000..f3ba65e77
--- /dev/null
+++ b/src/CommunityToolkit.Mvvm.SourceGenerators/Extensions/SourceProductionContextExtensions.cs
@@ -0,0 +1,33 @@
+// 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.Text;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+
+namespace CommunityToolkit.Mvvm.SourceGenerators.Extensions;
+
+///
+/// Extension methods for the type.
+///
+internal static class SourceProductionContextExtensions
+{
+ ///
+ /// Adds a new source file to a target instance.
+ ///
+ /// The input instance to use.
+ /// The name of the source file to add.
+ /// The instance representing the syntax tree to add.
+ public static void AddSource(this SourceProductionContext context, string name, CompilationUnitSyntax compilationUnit)
+ {
+#if !ROSLYN_4_3_1_OR_GREATER
+ // We're fine with the extra allocation in the few cases where adjusting the filename is necessary.
+ // This will only ever be done when code generation is executed again anyway, which is a slow path.
+ name = name.Replace('+', '.').Replace('`', '_');
+#endif
+
+ // Add the UTF8 text for the input compilation unit
+ context.AddSource(name, compilationUnit.GetText(Encoding.UTF8));
+ }
+}
diff --git a/src/CommunityToolkit.Mvvm.SourceGenerators/Input/RelayCommandGenerator.cs b/src/CommunityToolkit.Mvvm.SourceGenerators/Input/RelayCommandGenerator.cs
index 78bdb2294..46b64a56c 100644
--- a/src/CommunityToolkit.Mvvm.SourceGenerators/Input/RelayCommandGenerator.cs
+++ b/src/CommunityToolkit.Mvvm.SourceGenerators/Input/RelayCommandGenerator.cs
@@ -4,7 +4,6 @@
using System.Collections.Immutable;
using System.Linq;
-using System.Text;
using CommunityToolkit.Mvvm.SourceGenerators.Extensions;
using CommunityToolkit.Mvvm.SourceGenerators.Input.Models;
using CommunityToolkit.Mvvm.SourceGenerators.Models;
@@ -61,7 +60,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
ImmutableArray memberDeclarations = Execute.GetSyntax(item.Info.Value);
CompilationUnitSyntax compilationUnit = item.Hierarchy.GetCompilationUnit(memberDeclarations);
- context.AddSource($"{item.Hierarchy.FilenameHint}.{item.Info.Value.MethodName}.g.cs", compilationUnit.GetText(Encoding.UTF8));
+ context.AddSource($"{item.Hierarchy.FilenameHint}.{item.Info.Value.MethodName}.g.cs", compilationUnit);
});
}
}
diff --git a/src/CommunityToolkit.Mvvm.SourceGenerators/Messaging/IMessengerRegisterAllGenerator.cs b/src/CommunityToolkit.Mvvm.SourceGenerators/Messaging/IMessengerRegisterAllGenerator.cs
index 03d8319e4..a9ee5b060 100644
--- a/src/CommunityToolkit.Mvvm.SourceGenerators/Messaging/IMessengerRegisterAllGenerator.cs
+++ b/src/CommunityToolkit.Mvvm.SourceGenerators/Messaging/IMessengerRegisterAllGenerator.cs
@@ -4,7 +4,6 @@
using System.Collections.Immutable;
using System.Linq;
-using System.Text;
using CommunityToolkit.Mvvm.SourceGenerators.Extensions;
using CommunityToolkit.Mvvm.SourceGenerators.Messaging.Models;
using Microsoft.CodeAnalysis;
@@ -84,7 +83,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
{
CompilationUnitSyntax compilationUnit = Execute.GetSyntax(item);
- context.AddSource("__IMessengerExtensions.g.cs", compilationUnit.GetText(Encoding.UTF8));
+ context.AddSource("__IMessengerExtensions.g.cs", compilationUnit);
});
// Generate the class with all registration methods
@@ -92,7 +91,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
{
CompilationUnitSyntax compilationUnit = Execute.GetSyntax(item);
- context.AddSource($"{item.FilenameHint}.g.cs", compilationUnit.GetText(Encoding.UTF8));
+ context.AddSource($"{item.FilenameHint}.g.cs", compilationUnit);
});
}
}
diff --git a/tests/CommunityToolkit.Mvvm.SourceGenerators.Roslyn401.UnitTests/CommunityToolkit.Mvvm.SourceGenerators.Roslyn401.UnitTests.csproj b/tests/CommunityToolkit.Mvvm.SourceGenerators.Roslyn401.UnitTests/CommunityToolkit.Mvvm.SourceGenerators.Roslyn401.UnitTests.csproj
index 947810b2e..849698ae5 100644
--- a/tests/CommunityToolkit.Mvvm.SourceGenerators.Roslyn401.UnitTests/CommunityToolkit.Mvvm.SourceGenerators.Roslyn401.UnitTests.csproj
+++ b/tests/CommunityToolkit.Mvvm.SourceGenerators.Roslyn401.UnitTests/CommunityToolkit.Mvvm.SourceGenerators.Roslyn401.UnitTests.csproj
@@ -8,7 +8,7 @@
-
+
diff --git a/tests/CommunityToolkit.Mvvm.SourceGenerators.Roslyn431.UnitTests/CommunityToolkit.Mvvm.SourceGenerators.Roslyn431.UnitTests.csproj b/tests/CommunityToolkit.Mvvm.SourceGenerators.Roslyn431.UnitTests/CommunityToolkit.Mvvm.SourceGenerators.Roslyn431.UnitTests.csproj
index f8974ac8f..0ba357902 100644
--- a/tests/CommunityToolkit.Mvvm.SourceGenerators.Roslyn431.UnitTests/CommunityToolkit.Mvvm.SourceGenerators.Roslyn431.UnitTests.csproj
+++ b/tests/CommunityToolkit.Mvvm.SourceGenerators.Roslyn431.UnitTests/CommunityToolkit.Mvvm.SourceGenerators.Roslyn431.UnitTests.csproj
@@ -2,6 +2,7 @@
net472;net6.0;net7.0
+ $(DefineConstants);ROSLYN_4_3_1_OR_GREATER
diff --git a/tests/CommunityToolkit.Mvvm.SourceGenerators.UnitTests/Test_SourceGeneratorsCodegen.cs b/tests/CommunityToolkit.Mvvm.SourceGenerators.UnitTests/Test_SourceGeneratorsCodegen.cs
index 0a357ffac..88567b938 100644
--- a/tests/CommunityToolkit.Mvvm.SourceGenerators.UnitTests/Test_SourceGeneratorsCodegen.cs
+++ b/tests/CommunityToolkit.Mvvm.SourceGenerators.UnitTests/Test_SourceGeneratorsCodegen.cs
@@ -193,6 +193,92 @@ public object? A
VerifyGenerateSources(source, new[] { new ObservablePropertyGenerator() }, ("MyApp.MyViewModel.g.cs", result));
}
+ [TestMethod]
+ public void ObservablePropertyWithinGenericAndNestedTypes()
+ {
+ string source = """
+ using System.ComponentModel;
+ using CommunityToolkit.Mvvm.ComponentModel;
+
+ #nullable enable
+
+ namespace MyApp;
+
+ partial class Foo
+ {
+ partial class MyViewModel : ObservableObject
+ {
+ [ObservableProperty]
+ private string? a;
+ }
+ }
+ """;
+
+ string result = """
+ //
+ #pragma warning disable
+ #nullable enable
+ namespace MyApp
+ {
+ partial class Foo
+ {
+ partial class MyViewModel
+ {
+ ///
+ [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "8.1.0.0")]
+ [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
+ public string? A
+ {
+ get => a;
+ set
+ {
+ if (!global::System.Collections.Generic.EqualityComparer.Default.Equals(a, value))
+ {
+ OnAChanging(value);
+ OnAChanging(default, value);
+ OnPropertyChanging(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangingArgs.A);
+ a = value;
+ OnAChanged(value);
+ OnAChanged(default, value);
+ OnPropertyChanged(global::CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedArgs.A);
+ }
+ }
+ }
+
+ /// Executes the logic for when is changing.
+ /// The new property value being set.
+ /// This method is invoked right before the value of is changed.
+ [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "8.1.0.0")]
+ partial void OnAChanging(string? value);
+ /// Executes the logic for when is changing.
+ /// The previous property value that is being replaced.
+ /// The new property value being set.
+ /// This method is invoked right before the value of is changed.
+ [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "8.1.0.0")]
+ partial void OnAChanging(string? oldValue, string? newValue);
+ /// Executes the logic for when just changed.
+ /// The new property value that was set.
+ /// This method is invoked right after the value of is changed.
+ [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "8.1.0.0")]
+ partial void OnAChanged(string? value);
+ /// Executes the logic for when just changed.
+ /// The previous property value that was replaced.
+ /// The new property value that was set.
+ /// This method is invoked right after the value of is changed.
+ [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "8.1.0.0")]
+ partial void OnAChanged(string? oldValue, string? newValue);
+ }
+ }
+ }
+ """;
+
+#if ROSLYN_4_3_1_OR_GREATER
+ VerifyGenerateSources(source, new[] { new ObservablePropertyGenerator() }, ("MyApp.Foo+MyViewModel`1.g.cs", result));
+#else
+ VerifyGenerateSources(source, new[] { new ObservablePropertyGenerator() }, ("MyApp.Foo.MyViewModel_1.g.cs", result));
+#endif
+ }
+
///
/// Generates the requested sources
///
@@ -212,7 +298,7 @@ from assembly in AppDomain.CurrentDomain.GetAssemblies()
let reference = MetadataReference.CreateFromFile(assembly.Location)
select reference;
- SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(source, CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp11));
+ SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(source, CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp10));
// Create a syntax tree with the input source
CSharpCompilation compilation = CSharpCompilation.Create(