Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix forwarded double attribute parameters #603

Merged
merged 1 commit into from
Feb 10, 2023
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 @@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.

using System;
using System.Globalization;
using System.Linq;
using CommunityToolkit.Mvvm.SourceGenerators.Helpers;
using Microsoft.CodeAnalysis;
Expand Down Expand Up @@ -89,7 +90,13 @@ public override ExpressionSyntax GetSyntax()
{
byte b => Literal(b),
char c => Literal(c),
double d => Literal(d),

// For doubles, we need to manually format it and always add the trailing "D" suffix.
// This ensures that the correct type is produced if the expression was assigned to
// an object (eg. the literal was used in an attribute object parameter/property).
double d => Literal(d.ToString("R", CultureInfo.InvariantCulture) + "D", d),

// For floats, Roslyn will automatically add the "F" suffix, so no extra work is needed
float f => Literal(f),
int i => Literal(i),
long l => Literal(l),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,105 @@ public string Name
VerifyGenerateSources(source, new[] { new ObservablePropertyGenerator() }, ("MyApp.MyViewModel.g.cs", result));
}

// See https://github.com/CommunityToolkit/dotnet/issues/601
[TestMethod]
public void ObservablePropertyWithForwardedAttributesWithNumberLiterals_PreservesType()
{
string source = """
using System.ComponentModel;
using CommunityToolkit.Mvvm.ComponentModel;

#nullable enable

namespace MyApp;

partial class MyViewModel : ObservableObject
{
const double MyDouble = 3.14;
const float MyFloat = 3.14f;

[ObservableProperty]
[property: DefaultValue(0.0)]
[property: DefaultValue(1.24)]
[property: DefaultValue(0.0f)]
[property: DefaultValue(0.0f)]
[property: DefaultValue(MyDouble)]
[property: DefaultValue(MyFloat)]
private object? a;
}

public class DefaultValueAttribute : Attribute
{
public DefaultValueAttribute(object value)
{
}
}
""";

string result = """
// <auto-generated/>
#pragma warning disable
#nullable enable
namespace MyApp
{
partial class MyViewModel
{
/// <inheritdoc cref="a"/>
[global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.ObservablePropertyGenerator", "8.1.0.0")]
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
[global::MyApp.DefaultValueAttribute(0D)]
[global::MyApp.DefaultValueAttribute(1.24D)]
[global::MyApp.DefaultValueAttribute(0F)]
[global::MyApp.DefaultValueAttribute(0F)]
[global::MyApp.DefaultValueAttribute(3.14D)]
[global::MyApp.DefaultValueAttribute(3.14F)]
public object? A
{
get => a;
set
{
if (!global::System.Collections.Generic.EqualityComparer<object?>.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(object? 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(object? oldValue, object? 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(object? 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(object? oldValue, object? newValue);
}
}
""";

VerifyGenerateSources(source, new[] { new ObservablePropertyGenerator() }, ("MyApp.MyViewModel.g.cs", result));
}

/// <summary>
/// Generates the requested sources
/// </summary>
Expand Down