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
@@ -0,0 +1,38 @@
//HintName: ReactiveUI.SourceGenerators.ObservableAsPropertyAttribute.g.cs
// Copyright (c) 2024 .NET Foundation and Contributors. All rights reserved.
// 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 full license information.

using System;

// <auto-generated/>
#pragma warning disable
#nullable enable
namespace ReactiveUI.SourceGenerators;

/// <summary>
/// ObservableAsPropertyAttribute.
/// </summary>
/// <seealso cref="Attribute" />
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
internal sealed class ObservableAsPropertyAttribute : Attribute
{
/// <summary>
/// Gets the name of the property.
/// </summary>
/// <value>
/// The name of the property.
/// </value>
public string? PropertyName { get; init; }

/// <summary>
/// Gets the Readonly state of the OAPH property.
/// </summary>
/// <value>
/// The is read only of the OAPH property.
/// </value>
public bool ReadOnly { get; init; } = true;
}
#nullable restore
#pragma warning restore
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//HintName: TestVM.ObservableAsPropertyFromObservable.g.cs
// <auto-generated/>
using ReactiveUI;

#pragma warning disable
#nullable enable

namespace TestNs
{
/// <summary>
/// Partial class for the TestVM which contains ReactiveUI Reactive property initialization.
/// </summary>
public partial class TestVM
{
/// <inheritdoc cref="Test7Property"/>
private object? _test7Property;

/// <inheritdoc cref="_test7PropertyHelper"/>
private ReactiveUI.ObservableAsPropertyHelper<object?>? _test7PropertyHelper;

/// <inheritdoc cref="_test7Property"/>
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
[global::System.Text.Json.Serialization.JsonIncludeAttribute()]
public object? Test7Property { get => _test7Property = (_test7PropertyHelper == null ? _test7Property : _test7PropertyHelper.Value); }

[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
protected void InitializeOAPH()
{
_test7PropertyHelper = Test7!.ToProperty(this, nameof(Test7Property));
}
}
}
#nullable restore
#pragma warning restore
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//HintName: ReactiveUI.SourceGenerators.ObservableAsPropertyAttribute.g.cs
// Copyright (c) 2024 .NET Foundation and Contributors. All rights reserved.
// 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 full license information.

using System;

// <auto-generated/>
#pragma warning disable
#nullable enable
namespace ReactiveUI.SourceGenerators;

/// <summary>
/// ObservableAsPropertyAttribute.
/// </summary>
/// <seealso cref="Attribute" />
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
internal sealed class ObservableAsPropertyAttribute : Attribute
{
/// <summary>
/// Gets the name of the property.
/// </summary>
/// <value>
/// The name of the property.
/// </value>
public string? PropertyName { get; init; }

/// <summary>
/// Gets the Readonly state of the OAPH property.
/// </summary>
/// <value>
/// The is read only of the OAPH property.
/// </value>
public bool ReadOnly { get; init; } = true;
}
#nullable restore
#pragma warning restore
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//HintName: TestVM.ObservableAsPropertyFromObservable.g.cs
// <auto-generated/>
using ReactiveUI;

#pragma warning disable
#nullable enable

namespace TestNs
{
/// <summary>
/// Partial class for the TestVM which contains ReactiveUI Reactive property initialization.
/// </summary>
public partial class TestVM
{
/// <inheritdoc cref="Test6Property"/>
private object _test6Property;

/// <inheritdoc cref="_test6PropertyHelper"/>
private ReactiveUI.ObservableAsPropertyHelper<object>? _test6PropertyHelper;

/// <inheritdoc cref="_test6Property"/>
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
[global::System.Text.Json.Serialization.JsonIncludeAttribute()]
public object Test6Property { get => _test6Property = _test6PropertyHelper?.Value ?? _test6Property; }

[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
protected void InitializeOAPH()
{
_test6PropertyHelper = Test6!.ToProperty(this, nameof(Test6Property));
}
}
}
#nullable restore
#pragma warning restore
Original file line number Diff line number Diff line change
Expand Up @@ -169,5 +169,73 @@ public partial class TestVM : ReactiveObject
return VerifyGenerator(driver);
}

/// <summary>
/// Tests that the source generator correctly generates observable properties.
/// </summary>
/// <returns>A task to monitor the async.</returns>
[Fact]
public Task FromObservablePropertiesWithAttributeRef()
{
// Arrange: Setup the source code that matches the generator input expectations.
const string sourceCode = """
using System;
using System.Runtime.Serialization;
using System.Text.Json.Serialization;
using ReactiveUI;
using ReactiveUI.SourceGenerators;
using System.Reactive.Linq;

namespace TestNs;

public partial class TestVM : ReactiveObject
{
[ObservableAsProperty(PropertyName = "MyNamedProperty")]
[property: JsonInclude]
[DataMember]
public IObservable<object> Test6 => Observable.Return(new object());
}
""";

// Act: Initialize the helper and run the generator.
var driver = TestHelper.TestPass(sourceCode);

// Assert: Verify the generated code.
return VerifyGenerator(driver);
}

/// <summary>
/// Tests that the source generator correctly generates observable properties.
/// </summary>
/// <returns>A task to monitor the async.</returns>
[Fact]
public Task FromObservablePropertiesWithAttributeNullableRef()
{
// Arrange: Setup the source code that matches the generator input expectations.
const string sourceCode = """
using System;
using System.Runtime.Serialization;
using System.Text.Json.Serialization;
using ReactiveUI;
using ReactiveUI.SourceGenerators;
using System.Reactive.Linq;

namespace TestNs;

public partial class TestVM : ReactiveObject
{
[ObservableAsProperty(PropertyName = "MyNamedProperty")]
[property: JsonInclude]
[DataMember]
public IObservable<object?> Test7 => Observable.Return(new object());
}
""";

// Act: Initialize the helper and run the generator.
var driver = TestHelper.TestPass(sourceCode);

// Assert: Verify the generated code.
return VerifyGenerator(driver);
}

private SettingsTask VerifyGenerator(GeneratorDriver driver) => Verify(driver).UseDirectory(TestHelper.VerifiedFilePath()).ScrubLinesContaining("[global::System.CodeDom.Compiler.GeneratedCode(\"");
}
18 changes: 18 additions & 0 deletions src/ReactiveUI.SourceGenerators.Execute.Nested1/Class1.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright (c) 2024 .NET Foundation and Contributors. All rights reserved.
// 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 full license information.

using ReactiveUI;
using ReactiveUI.SourceGenerators;

namespace SGReactiveUI.SourceGenerators.Execute.Nested1;

/// <summary>
/// Class1.
/// </summary>
public partial class Class1 : ReactiveObject
{
[Reactive]
private string? _property1;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\ReactiveUI.SourceGenerators\ReactiveUI.SourceGenerators.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" PrivateAssets="all" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="ReactiveUI" />
</ItemGroup>

</Project>
18 changes: 18 additions & 0 deletions src/ReactiveUI.SourceGenerators.Execute.Nested2/Class1.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright (c) 2024 .NET Foundation and Contributors. All rights reserved.
// 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 full license information.

using ReactiveUI;
using ReactiveUI.SourceGenerators;

namespace SGReactiveUI.SourceGenerators.Execute.Nested2;

/// <summary>
/// Class1.
/// </summary>
public partial class Class1 : ReactiveObject
{
[Reactive]
private string? _property1;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\ReactiveUI.SourceGenerators\ReactiveUI.SourceGenerators.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" PrivateAssets="all" />
<ProjectReference Include="..\ReactiveUI.SourceGenerators.Execute.Nested1\ReactiveUI.SourceGenerators.Execute.Nested1.csproj" />
</ItemGroup>

</Project>
18 changes: 18 additions & 0 deletions src/ReactiveUI.SourceGenerators.Execute.Nested3/Class1.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright (c) 2024 .NET Foundation and Contributors. All rights reserved.
// 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 full license information.

using ReactiveUI;
using ReactiveUI.SourceGenerators;

namespace SGReactiveUI.SourceGenerators.Execute.Nested3;

/// <summary>
/// Class1.
/// </summary>
public partial class Class1 : ReactiveObject
{
[Reactive]
private string? _property1;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<LangVersion>12.0</LangVersion>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\ReactiveUI.SourceGenerators\ReactiveUI.SourceGenerators.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" PrivateAssets="all" />
<ProjectReference Include="..\ReactiveUI.SourceGenerators.Execute.Nested2\ReactiveUI.SourceGenerators.Execute.Nested2.csproj" />
</ItemGroup>

</Project>
11 changes: 11 additions & 0 deletions src/ReactiveUI.SourceGenerators.Execute/TestViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ public TestViewModel()
_observableAsPropertyTest2Property = 11223344;
Console.Out.WriteLine(ObservableAsPropertyTest2Property);
Console.Out.WriteLine(_observableAsPropertyTest2Property);

_referenceTypeObservableProperty = default!;
ReferenceTypeObservable = Observable.Return(new object());
NullableReferenceTypeObservable = Observable.Return(new object());

InitializeOAPH();

Console.Out.WriteLine(Test1Command);
Expand Down Expand Up @@ -239,6 +244,12 @@ public TestViewModel()
/// </summary>
public ViewModelActivator Activator { get; } = new();

[ObservableAsProperty]
private IObservable<object> ReferenceTypeObservable { get; }

[ObservableAsProperty]
private IObservable<object?> NullableReferenceTypeObservable { get; }

/// <summary>
/// Gets observables as property test.
/// </summary>
Expand Down
Loading