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 @@ -16,7 +16,7 @@ public partial class TestVM
private double? _testProperty;

/// <inheritdoc cref="_testPropertyHelper"/>
private ReactiveUI.ObservableAsPropertyHelper<double?>? _testPropertyHelper;
private readonly ReactiveUI.ObservableAsPropertyHelper<double?> _testPropertyHelper;

/// <inheritdoc cref="_testProperty"/>
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
Expand Down
51 changes: 51 additions & 0 deletions src/ReactiveUI.SourceGenerators.Execute/TestClassOAPH_VM.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// 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.Test;

/// <summary>
/// TestClassOAPH VM.
/// </summary>
public partial class TestClassOAPH_VM : ReactiveObject
{
[ObservableAsProperty]
private bool _observableTestField;

[Reactive]
private bool _reactiveTestField;

/// <summary>
/// Initializes a new instance of the <see cref="TestClassOAPH_VM"/> class.
/// </summary>
public TestClassOAPH_VM()
{
_observableTestPropertyHelper = this.WhenAnyValue(x => x.ReactiveTestProperty)
.ToProperty(this, x => x.ObservableTestProperty);

_observableTestFieldHelper = this.WhenAnyValue(x => x.ReactiveTestField)
.ToProperty(this, x => x.ObservableTestField);
}

/// <summary>
/// Gets a value indicating whether [observable test property].
/// </summary>
/// <value>
/// <c>true</c> if [observable test property]; otherwise, <c>false</c>.
/// </value>
[ObservableAsProperty]
public partial bool ObservableTestProperty { get; }

/// <summary>
/// Gets or sets a value indicating whether [reactive test property].
/// </summary>
/// <value>
/// <c>true</c> if [reactive test property]; otherwise, <c>false</c>.
/// </value>
[Reactive]
public partial bool ReactiveTestProperty { get; set; }
}
4 changes: 4 additions & 0 deletions src/ReactiveUI.SourceGenerators.Execute/TestViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ public partial class TestViewModel : ReactiveObject, IActivatableViewModel, IDis

[Reactive]
private IEnumerable<Person> _people = [new Person()];
[Reactive]
private double? _myDoubleProperty;
[Reactive]
private double _myDoubleNonNullProperty;

[BindableDerivedList]
private ReadOnlyObservableCollection<Person>? _visiblePeople;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ internal record ObservableMethodInfo(
bool IsNullableType,
bool IsProperty,
EquatableArray<string> ForwardedPropertyAttributes,
string IsReadOnly,
string AccessModifier,
string? InitialValue)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ public sealed partial class ObservableAsPropertyGenerator
attributeData.TryGetNamedArgument("UseProtected", out bool useProtected);
var useProtectedModifier = useProtected ? "protected" : "private";

token.ThrowIfCancellationRequested();

// Get the can ReadOnly member, if any
attributeData.TryGetNamedArgument("ReadOnly", out bool? isReadonly);

token.ThrowIfCancellationRequested();
var compilation = context.SemanticModel.Compilation;

Expand Down Expand Up @@ -106,6 +111,7 @@ public sealed partial class ObservableAsPropertyGenerator
isNullableType,
false,
propertyAttributes,
string.Empty,
useProtectedModifier,
initialValue),
diagnostics.ToImmutable());
Expand All @@ -131,6 +137,7 @@ public sealed partial class ObservableAsPropertyGenerator

var observableType = string.Empty;
var isNullableType = false;
var isPartialProperty = false;

token.ThrowIfCancellationRequested();
context.GetForwardedAttributes(
Expand Down Expand Up @@ -173,10 +180,9 @@ public sealed partial class ObservableAsPropertyGenerator

token.ThrowIfCancellationRequested();

var inheritance = propertySymbol.IsVirtual ? " virtual" : propertySymbol.IsOverride ? " override" : string.Empty;
isPartialProperty = true;

// Get the can ReadOnly member, if any
attributeData.TryGetNamedArgument("ReadOnly", out bool? isReadonly);
var inheritance = propertySymbol.IsVirtual ? " virtual" : propertySymbol.IsOverride ? " override" : string.Empty;

token.ThrowIfCancellationRequested();

Expand Down Expand Up @@ -215,6 +221,12 @@ public sealed partial class ObservableAsPropertyGenerator
}
#endif

var isReadOnlyString = string.Empty;
if (isPartialProperty)
{
isReadOnlyString = isReadonly == false ? string.Empty : "readonly";
}

// Get the containing type info
var targetInfo = TargetInfo.From(propertySymbol.ContainingType);

Expand All @@ -229,6 +241,7 @@ public sealed partial class ObservableAsPropertyGenerator
isNullableType,
true,
propertyAttributes,
isReadOnlyString,
useProtectedModifier,
initialValue),
diagnostics.ToImmutable());
Expand Down Expand Up @@ -307,12 +320,20 @@ private static string GetPropertySyntax(ObservableMethodInfo propertyInfo)
propertyType = propertyInfo.PartialPropertyType;
}

var helperTypeName = $"{propertyInfo.AccessModifier} ReactiveUI.ObservableAsPropertyHelper<{propertyType}>?";

// If the property is readonly, we need to change the helper to be non-nullable
if (propertyInfo.IsReadOnly == "readonly")
{
helperTypeName = $"{propertyInfo.AccessModifier} readonly ReactiveUI.ObservableAsPropertyHelper<{propertyType}>";
}

return $$"""
/// <inheritdoc cref="{{propertyInfo.PropertyName}}"/>
private {{propertyType}} {{getterFieldIdentifierName}}{{initialValue}};

/// <inheritdoc cref="{{getterFieldIdentifierName}}Helper"/>
{{propertyInfo.AccessModifier}} ReactiveUI.ObservableAsPropertyHelper<{{propertyType}}>? {{getterFieldIdentifierName}}Helper;
{{helperTypeName}} {{getterFieldIdentifierName}}Helper;

/// <inheritdoc cref="{{getterFieldIdentifierName}}"/>
{{propertyAttributes}}
Expand Down
37 changes: 0 additions & 37 deletions src/ReactiveUI.SourceGenerators.slnx

This file was deleted.

Loading