未验证 提交 03518080 编写于 作者: S Sam Harwell 提交者: GitHub

Merge pull request #30742 from Scott-Caldwell/29786-Fix-Int.MinValue

Fix double negation of integral `MinValue`s
......@@ -22,6 +22,21 @@ public abstract partial class AbstractMetadataAsSourceTests
}
}
internal static async Task GenerateAndVerifySourceLineAsync(string source, string language, string expected)
{
using (var context = TestContext.Create(language, sourceWithSymbolReference: source))
{
var navigationSymbol = await context.GetNavigationSymbolAsync();
var metadataAsSourceFile = await context.GenerateSourceAsync(navigationSymbol);
var document = context.GetDocument(metadataAsSourceFile);
var text = await document.GetTextAsync();
var line = text.Lines.GetLineFromPosition(metadataAsSourceFile.IdentifierLocation.SourceSpan.Start);
var lineText = line.ToString().Trim();
Assert.Equal(expected, lineText);
}
}
internal static async Task TestNotReusedOnAssemblyDiffersAsync(string projectLanguage)
{
var metadataSources = new[]
......
......@@ -1511,5 +1511,121 @@ void M([|D|]<int> lambda)
context.VerifyResult(metadataAsSourceFile, expected);
}
}
[WorkItem(29786, "https://github.com/dotnet/roslyn/issues/29786")]
[Fact, Trait(Traits.Feature, Traits.Features.MetadataAsSource)]
public async Task TestSByteMinValue()
{
var source = @"
class C
{
sbyte Goo = sbyte.[|MinValue|];
}";
var expected = "public const SByte MinValue = -128;";
await GenerateAndVerifySourceLineAsync(source, LanguageNames.CSharp, expected);
}
[WorkItem(29786, "https://github.com/dotnet/roslyn/issues/29786")]
[Fact, Trait(Traits.Feature, Traits.Features.MetadataAsSource)]
public async Task TestSByteMinValueVB()
{
var source = @"
Class C
Public Goo = SByte.[|MinValue|]
End Class";
var expected = "Public Const MinValue As [SByte] = -128";
await GenerateAndVerifySourceLineAsync(source, LanguageNames.VisualBasic, expected);
}
[WorkItem(29786, "https://github.com/dotnet/roslyn/issues/29786")]
[Fact, Trait(Traits.Feature, Traits.Features.MetadataAsSource)]
public async Task TestInt16MinValue()
{
var source = @"
class C
{
short Goo = short.[|MinValue|];
}";
var expected = $"public const Int16 MinValue = -32768;";
await GenerateAndVerifySourceLineAsync(source, LanguageNames.CSharp, expected);
}
[WorkItem(29786, "https://github.com/dotnet/roslyn/issues/29786")]
[Fact, Trait(Traits.Feature, Traits.Features.MetadataAsSource)]
public async Task TestInt16MinValueVB()
{
var source = @"
Class C
Public Goo = Short.[|MinValue|]
End Class";
var expected = $"Public Const MinValue As Int16 = -32768";
await GenerateAndVerifySourceLineAsync(source, LanguageNames.VisualBasic, expected);
}
[WorkItem(29786, "https://github.com/dotnet/roslyn/issues/29786")]
[Fact, Trait(Traits.Feature, Traits.Features.MetadataAsSource)]
public async Task TestInt32MinValue()
{
var source = @"
class C
{
int Goo = int.[|MinValue|];
}";
var expected = $"public const Int32 MinValue = -2147483648;";
await GenerateAndVerifySourceLineAsync(source, LanguageNames.CSharp, expected);
}
[WorkItem(29786, "https://github.com/dotnet/roslyn/issues/29786")]
[Fact, Trait(Traits.Feature, Traits.Features.MetadataAsSource)]
public async Task TestInt32MinValueVB()
{
var source = @"
Class C
Public Goo = Integer.[|MinValue|]
End Class";
var expected = $"Public Const MinValue As Int32 = -2147483648";
await GenerateAndVerifySourceLineAsync(source, LanguageNames.VisualBasic, expected);
}
[WorkItem(29786, "https://github.com/dotnet/roslyn/issues/29786")]
[Fact, Trait(Traits.Feature, Traits.Features.MetadataAsSource)]
public async Task TestInt64MinValue()
{
var source = @"
class C
{
long Goo = long.[|MinValue|];
}";
var expected = $"public const Int64 MinValue = -9223372036854775808;";
await GenerateAndVerifySourceLineAsync(source, LanguageNames.CSharp, expected);
}
[WorkItem(29786, "https://github.com/dotnet/roslyn/issues/29786")]
[Fact, Trait(Traits.Feature, Traits.Features.MetadataAsSource)]
public async Task TestInt64MinValueVB()
{
var source = @"
Class C
Public Goo = Long.[|MinValue|]
End Class";
var expected = $"Public Const MinValue As Int64 = -9223372036854775808";
await GenerateAndVerifySourceLineAsync(source, LanguageNames.VisualBasic, expected);
}
}
}
......@@ -79,17 +79,17 @@ private static ExpressionSyntax GenerateNullLiteral()
case bool val: return GenerateBooleanLiteralExpression(val);
case string val: return GenerateStringLiteralExpression(val);
case char val: return GenerateCharLiteralExpression(val);
case sbyte val: return GenerateLiteralExpression(type, val, LiteralSpecialValues.SByteSpecialValues, null, canUseFieldReference, (s, v) => SyntaxFactory.Literal(s, v), x => x < 0, x => (sbyte)-x);
case short val: return GenerateLiteralExpression(type, val, LiteralSpecialValues.Int16SpecialValues, null, canUseFieldReference, (s, v) => SyntaxFactory.Literal(s, v), x => x < 0, x => (short)-x);
case int val: return GenerateLiteralExpression(type, val, LiteralSpecialValues.Int32SpecialValues, null, canUseFieldReference, SyntaxFactory.Literal, x => x < 0, x => -x);
case long val: return GenerateLiteralExpression(type, val, LiteralSpecialValues.Int64SpecialValues, null, canUseFieldReference, SyntaxFactory.Literal, x => x < 0, x => -x);
case sbyte val: return GenerateLiteralExpression(type, val, LiteralSpecialValues.SByteSpecialValues, null, canUseFieldReference, (s, v) => SyntaxFactory.Literal(s, v), x => x < 0, x => (sbyte)-x, "128");
case short val: return GenerateLiteralExpression(type, val, LiteralSpecialValues.Int16SpecialValues, null, canUseFieldReference, (s, v) => SyntaxFactory.Literal(s, v), x => x < 0, x => (short)-x, "32768");
case int val: return GenerateLiteralExpression(type, val, LiteralSpecialValues.Int32SpecialValues, null, canUseFieldReference, SyntaxFactory.Literal, x => x < 0, x => -x, "2147483648");
case long val: return GenerateLiteralExpression(type, val, LiteralSpecialValues.Int64SpecialValues, null, canUseFieldReference, SyntaxFactory.Literal, x => x < 0, x => -x, "9223372036854775808");
case byte val: return GenerateNonNegativeLiteralExpression(type, val, LiteralSpecialValues.ByteSpecialValues, null, canUseFieldReference, (s, v) => SyntaxFactory.Literal(s, v));
case ushort val: return GenerateNonNegativeLiteralExpression(type, val, LiteralSpecialValues.UInt16SpecialValues, null, canUseFieldReference, (s, v) => SyntaxFactory.Literal(s, (uint)v));
case uint val: return GenerateNonNegativeLiteralExpression(type, val, LiteralSpecialValues.UInt32SpecialValues, null, canUseFieldReference, SyntaxFactory.Literal);
case ulong val: return GenerateNonNegativeLiteralExpression(type, val, LiteralSpecialValues.UInt64SpecialValues, null, canUseFieldReference, SyntaxFactory.Literal);
case float val: return GenerateSingleLiteralExpression(type, val, canUseFieldReference);
case double val: return GenerateDoubleLiteralExpression(type, val, canUseFieldReference);
case decimal val: return GenerateLiteralExpression(type, val, LiteralSpecialValues.DecimalSpecialValues, null, canUseFieldReference, SyntaxFactory.Literal, x => x < 0, x => -x);
case decimal val: return GenerateLiteralExpression(type, val, LiteralSpecialValues.DecimalSpecialValues, null, canUseFieldReference, SyntaxFactory.Literal, x => x < 0, x => -x, null);
}
return type == null || type.IsReferenceType || type.IsPointerType() || type.IsNullable()
......@@ -198,7 +198,7 @@ private static ExpressionSyntax GenerateDoubleLiteralExpression(ITypeSymbol type
return GenerateLiteralExpression(
type, value, LiteralSpecialValues.DoubleSpecialValues, "R", canUseFieldReference,
SyntaxFactory.Literal, x => x < 0, x => -x);
SyntaxFactory.Literal, x => x < 0, x => -x, null);
}
private static ExpressionSyntax GenerateSingleLiteralExpression(ITypeSymbol type, float value, bool canUseFieldReference)
......@@ -227,24 +227,27 @@ private static ExpressionSyntax GenerateSingleLiteralExpression(ITypeSymbol type
return GenerateLiteralExpression(
type, value, LiteralSpecialValues.SingleSpecialValues, "R", canUseFieldReference,
SyntaxFactory.Literal, x => x < 0, x => -x);
SyntaxFactory.Literal, x => x < 0, x => -x, null);
}
private static ExpressionSyntax GenerateNonNegativeLiteralExpression<T>(
ITypeSymbol type, T value, IEnumerable<KeyValuePair<T, string>> constants,
string formatString, bool canUseFieldReference,
Func<string, T, SyntaxToken> tokenFactory)
where T : IEquatable<T>
{
return GenerateLiteralExpression(
type, value, constants, formatString, canUseFieldReference,
tokenFactory, isNegative: x => false, negate: t => throw new InvalidOperationException());
tokenFactory, isNegative: x => false, negate: t => throw new InvalidOperationException(), null);
}
private static ExpressionSyntax GenerateLiteralExpression<T>(
ITypeSymbol type, T value, IEnumerable<KeyValuePair<T, string>> constants,
string formatString, bool canUseFieldReference,
Func<string, T, SyntaxToken> tokenFactory,
Func<T, bool> isNegative, Func<T, T> negate)
Func<T, bool> isNegative, Func<T, T> negate,
string integerMinValueString)
where T : IEquatable<T>
{
if (canUseFieldReference)
{
......@@ -254,18 +257,21 @@ private static ExpressionSyntax GenerateSingleLiteralExpression(ITypeSymbol type
return result;
}
}
var negative = isNegative(value);
if (negative)
{
value = negate(value);
}
var suffix = DetermineSuffix(type, value);
var stringValue = ((IFormattable)value).ToString(formatString, CultureInfo.InvariantCulture) + suffix;
var nonNegativeValue = negative
? negate(value)
: value;
var suffix = DetermineSuffix(type, nonNegativeValue);
var stringValue = negative && nonNegativeValue.Equals(value)
? integerMinValueString
: ((IFormattable)nonNegativeValue).ToString(formatString, CultureInfo.InvariantCulture) + suffix;
var literal = SyntaxFactory.LiteralExpression(
SyntaxKind.NumericLiteralExpression, tokenFactory(stringValue, value));
SyntaxKind.NumericLiteralExpression, tokenFactory(stringValue, nonNegativeValue));
return negative
? SyntaxFactory.PrefixUnaryExpression(SyntaxKind.UnaryMinusExpression, literal)
......
......@@ -65,13 +65,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration
ElseIf TypeOf value Is Char Then
Return GenerateCharLiteralExpression(DirectCast(value, Char))
ElseIf TypeOf value Is SByte Then
Return GenerateIntegralLiteralExpression(type, SpecialType.System_SByte, DirectCast(value, SByte), canUseFieldReference, LiteralSpecialValues.SByteSpecialValues, Function(t) t < 0, Function(t) -t)
Return GenerateIntegralLiteralExpression(type, SpecialType.System_SByte, DirectCast(value, SByte), canUseFieldReference, LiteralSpecialValues.SByteSpecialValues, Function(x) x < 0, Function(x) -x, "128")
ElseIf TypeOf value Is Short Then
Return GenerateIntegralLiteralExpression(type, SpecialType.System_Int16, DirectCast(value, Short), canUseFieldReference, LiteralSpecialValues.Int16SpecialValues, Function(t) t < 0, Function(t) -t)
Return GenerateIntegralLiteralExpression(type, SpecialType.System_Int16, DirectCast(value, Short), canUseFieldReference, LiteralSpecialValues.Int16SpecialValues, Function(x) x < 0, Function(x) -x, "32768")
ElseIf TypeOf value Is Integer Then
Return GenerateIntegralLiteralExpression(type, SpecialType.System_Int32, DirectCast(value, Integer), canUseFieldReference, LiteralSpecialValues.Int32SpecialValues, Function(t) t < 0, Function(t) -t)
Return GenerateIntegralLiteralExpression(type, SpecialType.System_Int32, DirectCast(value, Integer), canUseFieldReference, LiteralSpecialValues.Int32SpecialValues, Function(x) x < 0, Function(x) -x, "2147483648")
ElseIf TypeOf value Is Long Then
Return GenerateLongLiteralExpression(type, DirectCast(value, Long), canUseFieldReference)
Return GenerateIntegralLiteralExpression(type, SpecialType.System_Int64, DirectCast(value, Long), canUseFieldReference, LiteralSpecialValues.Int64SpecialValues, Function(x) x < 0, Function(x) -x, "9223372036854775808")
ElseIf TypeOf value Is Byte Then
Return GenerateNonNegativeIntegralLiteralExpression(type, SpecialType.System_Byte, DirectCast(value, Byte), canUseFieldReference, LiteralSpecialValues.ByteSpecialValues)
ElseIf TypeOf value Is UShort Then
......@@ -155,7 +155,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration
Return invocation.WithAdditionalAnnotations(Simplifier.Annotation)
End Function
Private Function GenerateNonNegativeIntegralLiteralExpression(Of TStructure)(
Private Function GenerateNonNegativeIntegralLiteralExpression(Of TStructure As IEquatable(Of TStructure))(
type As ITypeSymbol,
specialType As SpecialType,
value As TStructure,
......@@ -164,19 +164,22 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration
Return GenerateIntegralLiteralExpression(
type, specialType, value, canUseFieldReference, specialValues,
Function(v) False, Function(v)
Throw New InvalidOperationException()
End Function)
Function(v) False,
Function(v)
Throw New InvalidOperationException()
End Function,
Nothing)
End Function
Private Function GenerateIntegralLiteralExpression(Of TStructure)(
Private Function GenerateIntegralLiteralExpression(Of TStructure As IEquatable(Of TStructure))(
type As ITypeSymbol,
specialType As SpecialType,
value As TStructure,
canUseFieldReference As Boolean,
specialValues As IEnumerable(Of KeyValuePair(Of TStructure, String)),
isNegative As Func(Of TStructure, Boolean),
negate As Func(Of TStructure, TStructure)) As ExpressionSyntax
negate As Func(Of TStructure, TStructure),
integerMinValueString As String) As ExpressionSyntax
If canUseFieldReference Then
Dim field = GenerateFieldReference(specialType, value, specialValues)
......@@ -186,18 +189,22 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration
End If
Dim negative = isNegative(value)
If negative Then
value = negate(value)
End If
Dim nonNegativeValue = If(negative,
negate(value),
value)
Dim typeSuffix As TypeCharacter = TypeCharacter.None
Dim suffix As String = String.Empty
DetermineSuffix(type, value, typeSuffix, suffix)
DetermineSuffix(type, nonNegativeValue, typeSuffix, suffix)
Dim literal = If(negative AndAlso nonNegativeValue.Equals(value),
integerMinValueString,
DirectCast(nonNegativeValue, IFormattable).ToString(Nothing, CultureInfo.InvariantCulture) & suffix)
Dim literal = DirectCast(value, IFormattable).ToString(Nothing, CultureInfo.InvariantCulture) & suffix
Dim expression As ExpressionSyntax = SyntaxFactory.NumericLiteralExpression(SyntaxFactory.IntegerLiteralToken(
literal, LiteralBase.Decimal, typeSuffix,
IntegerUtilities.ToUInt64(value)))
IntegerUtilities.ToUInt64(nonNegativeValue)))
If negative Then
expression = SyntaxFactory.UnaryMinusExpression(expression)
......@@ -212,19 +219,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.CodeGeneration
Return expression
End Function
Private Function GenerateLongLiteralExpression(type As ITypeSymbol,
value As Long,
canUseFieldReference As Boolean) As ExpressionSyntax
If canUseFieldReference OrElse value > Long.MinValue Then
Return GenerateIntegralLiteralExpression(type, SpecialType.System_Int64, value, canUseFieldReference, LiteralSpecialValues.Int64SpecialValues, Function(t) t < 0, Function(t) -t)
End If
' We have to special case how Long.MinValue is printed when we can't refer to the
' field directly.
Return SyntaxFactory.NumericLiteralExpression(SyntaxFactory.IntegerLiteralToken(
"&H8000000000000000", LiteralBase.Hexadecimal, TypeCharacter.None, IntegerUtilities.ToUInt64(value)))
End Function
Private Sub DetermineSuffix(type As ITypeSymbol,
value As Object,
ByRef typeSuffix As TypeCharacter,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册