Skip to content

Commit 865e35b

Browse files
authored
Fix ReadOnly for OAPH (#186)
* Fix ReadOnly for OAPH * Delete ReactiveUI.SourceGenerators.slnx
1 parent e37e475 commit 865e35b

File tree

6 files changed

+82
-42
lines changed

6 files changed

+82
-42
lines changed

src/ReactiveUI.SourceGenerator.Tests/OAPH/OAPFromObservableGeneratorTests.FromPartialProperty#TestNs.TestVM.ObservableAsPropertyFromObservable.g.verified.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public partial class TestVM
1616
private double? _testProperty;
1717

1818
/// <inheritdoc cref="_testPropertyHelper"/>
19-
private ReactiveUI.ObservableAsPropertyHelper<double?>? _testPropertyHelper;
19+
private readonly ReactiveUI.ObservableAsPropertyHelper<double?> _testPropertyHelper;
2020

2121
/// <inheritdoc cref="_testProperty"/>
2222
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Copyright (c) 2024 .NET Foundation and Contributors. All rights reserved.
2+
// Licensed to the .NET Foundation under one or more agreements.
3+
// The .NET Foundation licenses this file to you under the MIT license.
4+
// See the LICENSE file in the project root for full license information.
5+
6+
using ReactiveUI;
7+
using ReactiveUI.SourceGenerators;
8+
9+
namespace SGReactiveUI.SourceGenerators.Test;
10+
11+
/// <summary>
12+
/// TestClassOAPH VM.
13+
/// </summary>
14+
public partial class TestClassOAPH_VM : ReactiveObject
15+
{
16+
[ObservableAsProperty]
17+
private bool _observableTestField;
18+
19+
[Reactive]
20+
private bool _reactiveTestField;
21+
22+
/// <summary>
23+
/// Initializes a new instance of the <see cref="TestClassOAPH_VM"/> class.
24+
/// </summary>
25+
public TestClassOAPH_VM()
26+
{
27+
_observableTestPropertyHelper = this.WhenAnyValue(x => x.ReactiveTestProperty)
28+
.ToProperty(this, x => x.ObservableTestProperty);
29+
30+
_observableTestFieldHelper = this.WhenAnyValue(x => x.ReactiveTestField)
31+
.ToProperty(this, x => x.ObservableTestField);
32+
}
33+
34+
/// <summary>
35+
/// Gets a value indicating whether [observable test property].
36+
/// </summary>
37+
/// <value>
38+
/// <c>true</c> if [observable test property]; otherwise, <c>false</c>.
39+
/// </value>
40+
[ObservableAsProperty]
41+
public partial bool ObservableTestProperty { get; }
42+
43+
/// <summary>
44+
/// Gets or sets a value indicating whether [reactive test property].
45+
/// </summary>
46+
/// <value>
47+
/// <c>true</c> if [reactive test property]; otherwise, <c>false</c>.
48+
/// </value>
49+
[Reactive]
50+
public partial bool ReactiveTestProperty { get; set; }
51+
}

src/ReactiveUI.SourceGenerators.Execute/TestViewModel.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ public partial class TestViewModel : ReactiveObject, IActivatableViewModel, IDis
7070

7171
[Reactive]
7272
private IEnumerable<Person> _people = [new Person()];
73+
[Reactive]
74+
private double? _myDoubleProperty;
75+
[Reactive]
76+
private double _myDoubleNonNullProperty;
7377

7478
[BindableDerivedList]
7579
private ReadOnlyObservableCollection<Person>? _visiblePeople;

src/ReactiveUI.SourceGenerators.Roslyn/ObservableAsProperty/Models/ObservableMethodInfo.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ internal record ObservableMethodInfo(
1919
bool IsNullableType,
2020
bool IsProperty,
2121
EquatableArray<string> ForwardedPropertyAttributes,
22+
string IsReadOnly,
2223
string AccessModifier,
2324
string? InitialValue)
2425
{

src/ReactiveUI.SourceGenerators.Roslyn/ObservableAsProperty/ObservableAsPropertyGenerator{FromObservable}.Execute.cs

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@ public sealed partial class ObservableAsPropertyGenerator
4141
attributeData.TryGetNamedArgument("UseProtected", out bool useProtected);
4242
var useProtectedModifier = useProtected ? "protected" : "private";
4343

44+
token.ThrowIfCancellationRequested();
45+
46+
// Get the can ReadOnly member, if any
47+
attributeData.TryGetNamedArgument("ReadOnly", out bool? isReadonly);
48+
4449
token.ThrowIfCancellationRequested();
4550
var compilation = context.SemanticModel.Compilation;
4651

@@ -106,6 +111,7 @@ public sealed partial class ObservableAsPropertyGenerator
106111
isNullableType,
107112
false,
108113
propertyAttributes,
114+
string.Empty,
109115
useProtectedModifier,
110116
initialValue),
111117
diagnostics.ToImmutable());
@@ -131,6 +137,7 @@ public sealed partial class ObservableAsPropertyGenerator
131137

132138
var observableType = string.Empty;
133139
var isNullableType = false;
140+
var isPartialProperty = false;
134141

135142
token.ThrowIfCancellationRequested();
136143
context.GetForwardedAttributes(
@@ -173,10 +180,9 @@ public sealed partial class ObservableAsPropertyGenerator
173180

174181
token.ThrowIfCancellationRequested();
175182

176-
var inheritance = propertySymbol.IsVirtual ? " virtual" : propertySymbol.IsOverride ? " override" : string.Empty;
183+
isPartialProperty = true;
177184

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

181187
token.ThrowIfCancellationRequested();
182188

@@ -215,6 +221,12 @@ public sealed partial class ObservableAsPropertyGenerator
215221
}
216222
#endif
217223

224+
var isReadOnlyString = string.Empty;
225+
if (isPartialProperty)
226+
{
227+
isReadOnlyString = isReadonly == false ? string.Empty : "readonly";
228+
}
229+
218230
// Get the containing type info
219231
var targetInfo = TargetInfo.From(propertySymbol.ContainingType);
220232

@@ -229,6 +241,7 @@ public sealed partial class ObservableAsPropertyGenerator
229241
isNullableType,
230242
true,
231243
propertyAttributes,
244+
isReadOnlyString,
232245
useProtectedModifier,
233246
initialValue),
234247
diagnostics.ToImmutable());
@@ -307,12 +320,20 @@ private static string GetPropertySyntax(ObservableMethodInfo propertyInfo)
307320
propertyType = propertyInfo.PartialPropertyType;
308321
}
309322

323+
var helperTypeName = $"{propertyInfo.AccessModifier} ReactiveUI.ObservableAsPropertyHelper<{propertyType}>?";
324+
325+
// If the property is readonly, we need to change the helper to be non-nullable
326+
if (propertyInfo.IsReadOnly == "readonly")
327+
{
328+
helperTypeName = $"{propertyInfo.AccessModifier} readonly ReactiveUI.ObservableAsPropertyHelper<{propertyType}>";
329+
}
330+
310331
return $$"""
311332
/// <inheritdoc cref="{{propertyInfo.PropertyName}}"/>
312333
private {{propertyType}} {{getterFieldIdentifierName}}{{initialValue}};
313334
314335
/// <inheritdoc cref="{{getterFieldIdentifierName}}Helper"/>
315-
{{propertyInfo.AccessModifier}} ReactiveUI.ObservableAsPropertyHelper<{{propertyType}}>? {{getterFieldIdentifierName}}Helper;
336+
{{helperTypeName}} {{getterFieldIdentifierName}}Helper;
316337
317338
/// <inheritdoc cref="{{getterFieldIdentifierName}}"/>
318339
{{propertyAttributes}}

src/ReactiveUI.SourceGenerators.slnx

Lines changed: 0 additions & 37 deletions
This file was deleted.

0 commit comments

Comments
 (0)