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 @@ -17,6 +17,16 @@ public string FormatForCode(TypedConstant constant, ITypeSymbol? targetType = nu
switch (constant.Kind)
{
case TypedConstantKind.Primitive:
// Check for special floating-point values first using the TypedConstant's type info
if (constant.Type?.SpecialType == SpecialType.System_Single ||
constant.Type?.SpecialType == SpecialType.System_Double)
{
var specialValue = Helpers.SpecialFloatingPointValuesHelper.TryFormatSpecialFloatingPointValue(constant.Value);
if (specialValue != null)
{
return specialValue;
}
}
return FormatPrimitiveForCode(constant.Value, targetType);

case TypedConstantKind.Enum:
Expand Down Expand Up @@ -242,6 +252,13 @@ private string FormatArrayForCode(TypedConstant constant, ITypeSymbol? targetTyp

private static string FormatPrimitive(object? value)
{
// Check for special floating-point values first
var specialFloatValue = Helpers.SpecialFloatingPointValuesHelper.TryFormatSpecialFloatingPointValue(value);
if (specialFloatValue != null)
{
return specialFloatValue;
}

switch (value)
{
case string s:
Expand All @@ -250,18 +267,6 @@ private static string FormatPrimitive(object? value)
return SymbolDisplay.FormatLiteral(c, quote: true);
case bool b:
return b ? "true" : "false";
case float.NaN:
return "float.NaN";
case float f when float.IsPositiveInfinity(f):
return "float.PositiveInfinity";
case float f when float.IsNegativeInfinity(f):
return "float.NegativeInfinity";
case double.NaN:
return "double.NaN";
case double d when double.IsPositiveInfinity(d):
return "double.PositiveInfinity";
case double d when double.IsNegativeInfinity(d):
return "double.NegativeInfinity";
case null:
return "null";
// Use InvariantCulture for numeric types to ensure consistent formatting
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,25 @@ public override SyntaxNode VisitNamespaceDeclaration(NamespaceDeclarationSyntax
{
var symbol = node.GetSymbolInfo(semanticModel);

// Special handling for double/float special constants (NaN, PositiveInfinity, NegativeInfinity)
if (symbol is IFieldSymbol fieldSymbol && fieldSymbol.IsConst)
{
var containingType = fieldSymbol.ContainingType;
if (containingType?.SpecialType == SpecialType.System_Double ||
containingType?.SpecialType == SpecialType.System_Single)
{
// Get the constant value and use the helper to create the appropriate syntax
if (fieldSymbol.HasConstantValue)
{
var specialSyntax = SpecialFloatingPointValuesHelper.TryCreateSpecialFloatingPointSyntax(fieldSymbol.ConstantValue);
if (specialSyntax != null)
{
return specialSyntax;
}
}
}
}

if (node.Name is IdentifierNameSyntax identifierName)
{
return VisitIdentifierName(identifierName);
Expand Down Expand Up @@ -95,6 +114,13 @@ private static bool TryParseConstant(ISymbol? symbol, [NotNullWhen(true)] out Sy

private static SyntaxNode Literal(object? constantValue)
{
// Check for special floating-point values first
var specialFloatSyntax = SpecialFloatingPointValuesHelper.TryCreateSpecialFloatingPointSyntax(constantValue);
if (specialFloatSyntax != null)
{
return specialFloatSyntax;
}

return constantValue switch
{
null => SyntaxFactory.LiteralExpression(SyntaxKind.NullLiteralExpression),
Expand All @@ -103,13 +129,7 @@ private static SyntaxNode Literal(object? constantValue)
bool boolValue => boolValue ? SyntaxFactory.LiteralExpression(SyntaxKind.TrueLiteralExpression)
: SyntaxFactory.LiteralExpression(SyntaxKind.FalseLiteralExpression),
int intValue => SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(intValue)),
double and Double.NaN => SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal("double.NaN", double.NaN)),
double doubleValue when double.IsPositiveInfinity(doubleValue) => SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal("double.PositiveInfinity", double.PositiveInfinity)),
double doubleValue when double.IsNegativeInfinity(doubleValue) => SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal("double.NegativeInfinity", double.NegativeInfinity)),
double doubleValue => SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(doubleValue)),
float and Single.NaN => SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal("float.NaN", float.NaN)),
float floatValue when float.IsPositiveInfinity(floatValue) => SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal("float.PositiveInfinity", float.PositiveInfinity)),
float floatValue when float.IsNegativeInfinity(floatValue) => SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal("float.NegativeInfinity", float.NegativeInfinity)),
float floatValue => SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(floatValue)),
long longValue => SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(longValue)),
decimal decimalValue => SyntaxFactory.LiteralExpression(SyntaxKind.NumericLiteralExpression, SyntaxFactory.Literal(decimalValue)),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;

namespace TUnit.Core.SourceGenerator.CodeGenerators.Helpers;

/// <summary>
/// Helper class for handling special floating-point values (NaN, Infinity) in code generation.
/// </summary>
internal static class SpecialFloatingPointValuesHelper
{
/// <summary>
/// Formats a floating-point value as a string for code generation,
/// handling special values like NaN and Infinity.
/// </summary>
public static string? TryFormatSpecialFloatingPointValue(object? value)
{
if (value == null)
return null;

// Handle float values
if (value is float floatValue)
{
if (float.IsNaN(floatValue))
return "float.NaN";
if (float.IsPositiveInfinity(floatValue))
return "float.PositiveInfinity";
if (float.IsNegativeInfinity(floatValue))
return "float.NegativeInfinity";
}

// Handle double values
if (value is double doubleValue)
{
if (double.IsNaN(doubleValue))
return "double.NaN";
if (double.IsPositiveInfinity(doubleValue))
return "double.PositiveInfinity";
if (double.IsNegativeInfinity(doubleValue))
return "double.NegativeInfinity";
}

return null;
}

/// <summary>
/// Creates a SyntaxNode for a special floating-point value using member access expressions.
/// Returns null if the value is not a special floating-point value.
/// </summary>
public static SyntaxNode? TryCreateSpecialFloatingPointSyntax(object? value)
{
return value switch
{
float f when float.IsNaN(f) => CreateFloatMemberAccess("NaN"),
float f when float.IsPositiveInfinity(f) => CreateFloatMemberAccess("PositiveInfinity"),
float f when float.IsNegativeInfinity(f) => CreateFloatMemberAccess("NegativeInfinity"),
double d when double.IsNaN(d) => CreateDoubleMemberAccess("NaN"),
double d when double.IsPositiveInfinity(d) => CreateDoubleMemberAccess("PositiveInfinity"),
double d when double.IsNegativeInfinity(d) => CreateDoubleMemberAccess("NegativeInfinity"),
_ => null
};
}

private static MemberAccessExpressionSyntax CreateFloatMemberAccess(string memberName)
{
return SyntaxFactory.MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.FloatKeyword)),
SyntaxFactory.IdentifierName(memberName));
}

private static MemberAccessExpressionSyntax CreateDoubleMemberAccess(string memberName)
{
return SyntaxFactory.MemberAccessExpression(
SyntaxKind.SimpleMemberAccessExpression,
SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.DoubleKeyword)),
SyntaxFactory.IdentifierName(memberName));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,13 @@ private static string FormatPrimitive(TypedConstant typedConstant)

public static string FormatPrimitive(object? value)
{
// Check for special floating-point values first
var specialFloatValue = SpecialFloatingPointValuesHelper.TryFormatSpecialFloatingPointValue(value);
if (specialFloatValue != null)
{
return specialFloatValue;
}

switch (value)
{
case string s:
Expand All @@ -87,18 +94,6 @@ public static string FormatPrimitive(object? value)
return SymbolDisplay.FormatLiteral(c, quote: true);
case bool b:
return b ? "true" : "false";
case float.NaN:
return "float.NaN";
case float f when float.IsPositiveInfinity(f):
return "float.PositiveInfinity";
case float f when float.IsNegativeInfinity(f):
return "float.NegativeInfinity";
case double.NaN:
return "double.NaN";
case double d when double.IsPositiveInfinity(d):
return "double.PositiveInfinity";
case double d when double.IsNegativeInfinity(d):
return "double.NegativeInfinity";
case null:
return "null";
// Use InvariantCulture for numeric types to ensure consistent formatting
Expand Down
54 changes: 54 additions & 0 deletions TUnit.TestProject/Bugs/_3157/3157_InfinitySymbolIssue.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using TUnit.TestProject.Attributes;

namespace TUnit.TestProject.Bugs._3157;

[EngineTest(ExpectedResult.Pass)]
public class InfinitySymbolIssue
{
[Test]
[Arguments("1.0", 1d)]
[Arguments("1.0i64", 1d)]
[Arguments("0.682287216i64", 0.682287216d)]
[Arguments("0xFFF8000000000000", double.NaN)]
[Arguments("0xFFF8000000000000i64", double.NaN)]
[Arguments("inf64", double.PositiveInfinity)]
[Arguments("inf", double.PositiveInfinity)]
[Arguments("-inf64", double.NegativeInfinity)]
[Arguments("-inf", double.NegativeInfinity)]
public async Task TestWithSpecialFloatingPointValues(string text, double expectedValue)
{
// Test that the special floating-point values are handled correctly
if (double.IsNaN(expectedValue))
{
await Assert.That(double.IsNaN(expectedValue)).IsTrue();
}
else if (double.IsPositiveInfinity(expectedValue))
{
await Assert.That(double.IsPositiveInfinity(expectedValue)).IsTrue();
}
else if (double.IsNegativeInfinity(expectedValue))
{
await Assert.That(double.IsNegativeInfinity(expectedValue)).IsTrue();
}
else
{
await Assert.That(expectedValue).IsEqualTo(expectedValue);
}
}

[Test]
[Arguments(float.NaN)]
[Arguments(float.PositiveInfinity)]
[Arguments(float.NegativeInfinity)]
public async Task TestFloatSpecialValues(float value)
{
if (float.IsNaN(value))
{
await Assert.That(float.IsNaN(value)).IsTrue();
}
else
{
await Assert.That(float.IsInfinity(value)).IsTrue();
}
}
}
Loading