Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Extensions\IncrementalGeneratorInitializationContextExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Extensions\IncrementalValuesProviderExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Extensions\ISymbolExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Extensions\SourceProductionContextExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Extensions\ITypeSymbolExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Extensions\MemberDeclarationSyntaxExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Extensions\SyntaxNodeExtensions.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand All @@ -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);
}
});

Expand All @@ -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);
}
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -79,15 +78,15 @@ 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
context.RegisterImplementationSourceOutput(validationInfo, static (context, item) =>
{
CompilationUnitSyntax compilationUnit = Execute.GetSyntax(item);

context.AddSource($"{item.FilenameHint}.g.cs", compilationUnit.GetText(Encoding.UTF8));
context.AddSource($"{item.FilenameHint}.g.cs", compilationUnit);
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -34,12 +33,12 @@ public abstract partial class TransitiveMembersGenerator<TInfo> : IIncrementalGe
/// <summary>
/// The sequence of member declarations for sealed types.
/// </summary>
private ImmutableArray<MemberDeclarationSyntax> sealedMemberDeclarations;
private readonly ImmutableArray<MemberDeclarationSyntax> sealedMemberDeclarations;

/// <summary>
/// The resulting sequence of member declarations for non sealed types.
/// </summary>
private ImmutableArray<MemberDeclarationSyntax> nonSealedMemberDeclarations;
private readonly ImmutableArray<MemberDeclarationSyntax> nonSealedMemberDeclarations;

/// <summary>
/// Initializes a new instance of the <see cref="TransitiveMembersGenerator{TInfo}"/> class.
Expand Down Expand Up @@ -108,7 +107,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
ImmutableArray<MemberDeclarationSyntax> 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);
});
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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;

/// <summary>
/// Extension methods for the <see cref="SourceProductionContext"/> type.
/// </summary>
internal static class SourceProductionContextExtensions
{
/// <summary>
/// Adds a new source file to a target <see cref="SourceProductionContext"/> instance.
/// </summary>
/// <param name="context">The input <see cref="SourceProductionContext"/> instance to use.</param>
/// <param name="name">The name of the source file to add.</param>
/// <param name="compilationUnit">The <see cref="CompilationUnitSyntax"/> instance representing the syntax tree to add.</param>
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));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -61,7 +60,7 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
ImmutableArray<MemberDeclarationSyntax> 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);
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -84,15 +83,15 @@ 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
context.RegisterImplementationSourceOutput(recipientInfo, static (context, item) =>
{
CompilationUnitSyntax compilationUnit = Execute.GetSyntax(item);

context.AddSource($"{item.FilenameHint}.g.cs", compilationUnit.GetText(Encoding.UTF8));
context.AddSource($"{item.FilenameHint}.g.cs", compilationUnit);
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Analyzer.Testing.MSTest" Version="1.1.1" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.CodeFix.Testing" Version="1.1.1" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.CodeFix.Testing.MSTest" Version="1.1.1" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.4.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="4.0.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.4.1" />
<PackageReference Include="MSTest.TestAdapter" Version="3.0.1" />
<PackageReference Include="MSTest.TestFramework" Version="3.0.1" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

<PropertyGroup>
<TargetFrameworks>net472;net6.0;net7.0</TargetFrameworks>
<DefineConstants>$(DefineConstants);ROSLYN_4_3_1_OR_GREATER</DefineConstants>
</PropertyGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<T> : ObservableObject
{
[ObservableProperty]
private string? a;
}
}
""";

string result = """
// <auto-generated/>
#pragma warning disable
#nullable enable
namespace MyApp
{
partial class Foo
{
partial class MyViewModel<T>
{
/// <inheritdoc cref="a"/>
[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<string?>.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);
}
}
}

/// <summary>Executes the logic for when <see cref="A"/> is changing.</summary>
/// <param name="value">The new property value being set.</param>
/// <remarks>This method is invoked right before the value of <see cref="A"/> is changed.</remarks>
[global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "8.1.0.0")]
partial void OnAChanging(string? value);
/// <summary>Executes the logic for when <see cref="A"/> is changing.</summary>
/// <param name="oldValue">The previous property value that is being replaced.</param>
/// <param name="newValue">The new property value being set.</param>
/// <remarks>This method is invoked right before the value of <see cref="A"/> is changed.</remarks>
[global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "8.1.0.0")]
partial void OnAChanging(string? oldValue, string? newValue);
/// <summary>Executes the logic for when <see cref="A"/> just changed.</summary>
/// <param name="value">The new property value that was set.</param>
/// <remarks>This method is invoked right after the value of <see cref="A"/> is changed.</remarks>
[global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "8.1.0.0")]
partial void OnAChanged(string? value);
/// <summary>Executes the logic for when <see cref="A"/> just changed.</summary>
/// <param name="oldValue">The previous property value that was replaced.</param>
/// <param name="newValue">The new property value that was set.</param>
/// <remarks>This method is invoked right after the value of <see cref="A"/> is changed.</remarks>
[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
}

/// <summary>
/// Generates the requested sources
/// </summary>
Expand All @@ -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(
Expand Down