Skip to content
Open
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,44 @@
//HintName: ReactiveUI.SourceGenerators.ReactiveCommandAttribute.g.cs
// Copyright (c) 2025 .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.

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

/// <summary>
/// ReativeCommandAttribute.
/// </summary>
/// <seealso cref="Attribute" />
[global::System.AttributeUsage(global::System.AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
internal sealed class ReactiveCommandAttribute : global::System.Attribute
{
/// <summary>
/// Gets the can execute method or property.
/// </summary>
/// <value>
/// The name of the CanExecute Observable of bool.
/// </value>
public string? CanExecute { get; init; }

/// <summary>
/// Gets the output scheduler.
/// </summary>
/// <value>
/// The output scheduler.
/// </value>
public string? OutputScheduler { get; init; }

/// <summary>
/// Gets the AccessModifier of the ReactiveCommand property.
/// </summary>
/// <value>
/// The AccessModifier of the property.
/// </value>
public PropertyAccessModifier AccessModifier { get; init; }
}
#nullable restore
#pragma warning restore
Original file line number Diff line number Diff line change
Expand Up @@ -238,4 +238,31 @@ public partial class TestVM : ReactiveObject
""";
return TestHelper.TestPass(sourceCode);
}

/// <summary>
/// Froms the type of the reactive command with nullable type and nullable return.
/// </summary>
/// <returns>A task to monitor the async.</returns>
[Test]
public Task FromReactiveCommandWithNullableTypeAndNullableReturnType()
{
const string sourceCode = """
using System;
using ReactiveUI;
using ReactiveUI.SourceGenerators;
namespace TestNs;

public class NullableInput
{
public string? Name { get; set; }
}

public partial class TestVM : ReactiveObject
{
[ReactiveCommand]
private NullableInput? Test1(NullableInput? input) => input;
}
""";
return TestHelper.TestPass(sourceCode);
}
}
20 changes: 20 additions & 0 deletions src/ReactiveUI.SourceGenerators.Execute.Nested3/Class1.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Diagnostics.CodeAnalysis;
using ReactiveUI;
using ReactiveUI.SourceGenerators;
using SGReactiveUI.SourceGenerators.Execute.Nested2;

namespace SGReactiveUI.SourceGenerators.Execute.Nested3;

Expand All @@ -17,4 +18,23 @@ public partial class Class1 : ReactiveObject
{
[Reactive]
private string? _property1;

/// <summary>
/// Initializes a new instance of the <see cref="Class1"/> class.
/// </summary>
public Class1()
{
SetPropertyCommand.Execute(new Nested1.Class1 { Property1 = "Initial Value" }).Subscribe();
}

[ReactiveCommand]
private SGReactiveUI.SourceGenerators.Execute.Nested2.Class1? SetProperty(Nested1.Class1? class1)
{
if (class1 == null)
{
return null;
}

return new() { Property1 = class1.Property1 };
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

<ItemGroup>
<ProjectReference Include="..\ReactiveUI.SourceGenerators.Analyzers.CodeFixes\ReactiveUI.SourceGenerators.Analyzers.CodeFixes.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
<ProjectReference Include="..\ReactiveUI.SourceGenerators.Execute.Nested3\ReactiveUI.SourceGenerators.Execute.Nested3.csproj" />
<ProjectReference Include="..\ReactiveUI.SourceGenerators.Roslyn4120\ReactiveUI.SourceGenerators.Roslyn4120.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
</ItemGroup>
</Project>
12 changes: 12 additions & 0 deletions src/ReactiveUI.SourceGenerators.Execute/TestViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
using DynamicData;
using ReactiveUI;
using ReactiveUI.SourceGenerators;
using SGReactiveUI.SourceGenerators.Execute.Nested3;

namespace SGReactiveUI.SourceGenerators.Test;

Expand Down Expand Up @@ -452,4 +453,15 @@ protected virtual void Dispose(bool disposing)
[ReactiveCommand]
private Task<System.Collections.IEnumerable> GetData(CancellationToken ct) =>
Task.FromResult<System.Collections.IEnumerable>(Array.Empty<System.Collections.IEnumerable>());

[ReactiveCommand]
private Execute.Nested2.Class1? SetProperty(Execute.Nested1.Class1? class1)
{
if (class1 == null)
{
return null;
}

return new() { Property1 = class1.Property1 };
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// The ReactiveUI and contributors licenses this file to you under the MIT license.
// See the LICENSE file in the project root for full license information.

using System.Collections.Generic;
using System;
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
Expand All @@ -15,7 +15,6 @@
using ReactiveUI.SourceGenerators.Helpers;
using ReactiveUI.SourceGenerators.Input.Models;
using ReactiveUI.SourceGenerators.Models;
using static ReactiveUI.SourceGenerators.Diagnostics.DiagnosticDescriptors;

namespace ReactiveUI.SourceGenerators;

Expand Down Expand Up @@ -120,11 +119,16 @@ public partial class ReactiveCommandGenerator

token.ThrowIfCancellationRequested();

var argumentType = methodParameters.ToImmutable().SingleOrDefault()?.Type;
var argumentTypeString = argumentType?.GetFullyQualifiedNameWithNullabilityAnnotations();

token.ThrowIfCancellationRequested();

return new(
targetInfo,
symbol.Name,
realReturnType.GetFullyQualifiedNameWithNullabilityAnnotations(),
methodParameters.ToImmutable().SingleOrDefault()?.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat),
argumentTypeString,
isTask,
isReturnTypeVoid,
isObservable,
Expand All @@ -138,7 +142,7 @@ public partial class ReactiveCommandGenerator
private static string GenerateSource(string containingTypeName, string containingNamespace, string containingClassVisibility, string containingType, CommandInfo[] commands)
{
// Get Parent class details from properties.ParentInfo
var (parentClassDeclarationsString, closingBrackets) = TargetInfo.GenerateParentClassDeclarations(commands.Select(p => p.TargetInfo.ParentInfo).ToArray());
var (parentClassDeclarationsString, closingBrackets) = TargetInfo.GenerateParentClassDeclarations([.. commands.Select(p => p.TargetInfo.ParentInfo)]);

var classes = GenerateClassWithCommands(containingTypeName, containingNamespace, containingClassVisibility, containingType, commands);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using ReactiveUI.SourceGenerators.Extensions;
using ReactiveUI.SourceGenerators.Helpers;

namespace ReactiveUI.SourceGenerators;
Expand Down
Loading