Browse Source

If possible, use nint/nuint for conversions to/from IntPtr.

pull/2063/head
Daniel Grunwald 5 years ago
parent
commit
2c9b84a1e1
  1. 1
      ICSharpCode.Decompiler.Tests/Helpers/RemoveCompilerAttribute.cs
  2. 9
      ICSharpCode.Decompiler.Tests/Helpers/Tester.cs
  3. 1
      ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
  4. 6
      ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
  5. 17
      ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs
  6. 38
      ICSharpCode.Decompiler/CSharp/TranslatedExpression.cs
  7. 11
      ICSharpCode.Decompiler/TypeSystem/NormalizeTypeVisitor.cs

1
ICSharpCode.Decompiler.Tests/Helpers/RemoveCompilerAttribute.cs

@ -39,6 +39,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -39,6 +39,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
"System.Runtime.CompilerServices.IsUnmanagedAttribute",
"System.Runtime.CompilerServices.NullableAttribute",
"System.Runtime.CompilerServices.NullableContextAttribute",
"System.Runtime.CompilerServices.NativeIntegerAttribute",
"Microsoft.CodeAnalysis.EmbeddedAttribute",
};

9
ICSharpCode.Decompiler.Tests/Helpers/Tester.cs

@ -57,6 +57,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -57,6 +57,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
ReferenceVisualBasic = 0x40,
ReferenceCore = 0x80,
GeneratePdb = 0x100,
Preview = 0x200
}
[Flags]
@ -271,7 +272,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -271,7 +272,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
if (flags.HasFlag(CompilerOptions.UseRoslyn)) {
var parseOptions = new CSharpParseOptions(
preprocessorSymbols: preprocessorSymbols.ToArray(),
languageVersion: Microsoft.CodeAnalysis.CSharp.LanguageVersion.CSharp8
languageVersion: flags.HasFlag(CompilerOptions.Preview) ? Microsoft.CodeAnalysis.CSharp.LanguageVersion.Preview : Microsoft.CodeAnalysis.CSharp.LanguageVersion.CSharp8
);
var syntaxTrees = sourceFileNames.Select(f => SyntaxFactory.ParseSyntaxTree(File.ReadAllText(f), parseOptions, path: f, encoding: Encoding.UTF8));
if (flags.HasFlag(CompilerOptions.ReferenceCore)) {
@ -399,7 +400,11 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -399,7 +400,11 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
internal static DecompilerSettings GetSettings(CompilerOptions cscOptions)
{
if (cscOptions.HasFlag(CompilerOptions.UseRoslyn)) {
return new DecompilerSettings(CSharp.LanguageVersion.Latest);
if (cscOptions.HasFlag(CompilerOptions.Preview)) {
return new DecompilerSettings(CSharp.LanguageVersion.Latest);
} else {
return new DecompilerSettings(CSharp.LanguageVersion.CSharp8_0);
}
} else {
return new DecompilerSettings(CSharp.LanguageVersion.CSharp5);
}

1
ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj

@ -92,6 +92,7 @@ @@ -92,6 +92,7 @@
<Compile Include="ProjectDecompiler\TargetFrameworkTests.cs" />
<Compile Include="TestAssemblyResolver.cs" />
<Compile Include="TestCases\Correctness\StringConcat.cs" />
<None Include="TestCases\Pretty\NativeInts.cs" />
<None Include="TestCases\ILPretty\CallIndirect.cs" />
<Compile Include="TestCases\ILPretty\Issue1681.cs" />
<Compile Include="TestCases\Ugly\AggressiveScalarReplacementOfAggregates.cs" />

6
ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs

@ -337,6 +337,12 @@ namespace ICSharpCode.Decompiler.Tests @@ -337,6 +337,12 @@ namespace ICSharpCode.Decompiler.Tests
RunForLibrary(cscOptions: cscOptions);
}
[Test]
public void NativeInts([ValueSource(nameof(roslynOnlyOptions))] CompilerOptions cscOptions)
{
RunForLibrary(cscOptions: cscOptions | CompilerOptions.Preview);
}
[Test]
public void NullPropagation([ValueSource(nameof(roslynOnlyOptions))] CompilerOptions cscOptions)
{

17
ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs

@ -248,12 +248,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -248,12 +248,6 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
AstType ConvertTypeHelper(IType type)
{
switch (type.Kind) {
case TypeKind.Dynamic:
case TypeKind.NInt:
case TypeKind.NUInt:
return new PrimitiveType(type.Name);
}
if (type is TypeWithElementType typeWithElementType) {
if (typeWithElementType is PointerType) {
return ConvertType(typeWithElementType.ElementType).MakePointerType();
@ -309,7 +303,16 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -309,7 +303,16 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
astType = ConvertTypeHelper(pt.GenericType, pt.TypeArguments);
break;
default:
astType = MakeSimpleType(type.Name);
switch (type.Kind) {
case TypeKind.Dynamic:
case TypeKind.NInt:
case TypeKind.NUInt:
astType = new PrimitiveType(type.Name);
break;
default:
astType = MakeSimpleType(type.Name);
break;
}
break;
}
if (type.Nullability == Nullability.Nullable) {

38
ICSharpCode.Decompiler/CSharp/TranslatedExpression.cs

@ -305,22 +305,28 @@ namespace ICSharpCode.Decompiler.CSharp @@ -305,22 +305,28 @@ namespace ICSharpCode.Decompiler.CSharp
// Direct cast only works correctly for IntPtr -> long.
// IntPtr -> int works correctly only in checked context.
// Everything else can be worked around by casting via long.
if (!(targetType.IsKnownType(KnownTypeCode.Int64) || checkForOverflow && targetType.IsKnownType(KnownTypeCode.Int32))) {
return this.ConvertTo(compilation.FindType(KnownTypeCode.Int64), expressionBuilder, checkForOverflow)
.ConvertTo(targetType, expressionBuilder, checkForOverflow);
if (!(targetType.IsKnownType(KnownTypeCode.Int64) || targetType.Kind == TypeKind.NInt || checkForOverflow && targetType.IsKnownType(KnownTypeCode.Int32))) {
var convertVia = expressionBuilder.settings.NativeIntegers ? SpecialType.NInt : compilation.FindType(KnownTypeCode.Int64);
return this.ConvertTo(convertVia, expressionBuilder, checkForOverflow)
.ConvertTo(targetType, expressionBuilder, checkForOverflow, allowImplicitConversion);
}
} else if (type.IsKnownType(KnownTypeCode.UIntPtr)) { // Conversion from UIntPtr
// Direct cast only works correctly for UIntPtr -> ulong.
// UIntPtr -> uint works correctly only in checked context.
// Everything else can be worked around by casting via ulong.
if (!(targetType.IsKnownType(KnownTypeCode.UInt64) || checkForOverflow && targetType.IsKnownType(KnownTypeCode.UInt32))) {
return this.ConvertTo(compilation.FindType(KnownTypeCode.UInt64), expressionBuilder, checkForOverflow)
.ConvertTo(targetType, expressionBuilder, checkForOverflow);
if (!(targetType.IsKnownType(KnownTypeCode.UInt64) || targetType.Kind == TypeKind.NUInt || checkForOverflow && targetType.IsKnownType(KnownTypeCode.UInt32))) {
var convertVia = expressionBuilder.settings.NativeIntegers ? SpecialType.NUInt : compilation.FindType(KnownTypeCode.UInt64);
return this.ConvertTo(convertVia, expressionBuilder, checkForOverflow)
.ConvertTo(targetType, expressionBuilder, checkForOverflow, allowImplicitConversion);
}
}
if (targetUType.IsKnownType(KnownTypeCode.IntPtr)) { // Conversion to IntPtr
if (type.IsKnownType(KnownTypeCode.Int32)) {
// normal casts work for int (both in checked and unchecked context)
if (type.IsKnownType(KnownTypeCode.Int32) || type.Kind == TypeKind.Pointer || type.Kind == TypeKind.NInt) {
// normal casts work for int/nint and pointers (both in checked and unchecked context)
} else if (expressionBuilder.settings.NativeIntegers) {
// if native integer types are available, prefer using those
return this.ConvertTo(SpecialType.NInt, expressionBuilder, checkForOverflow)
.ConvertTo(targetType, expressionBuilder, checkForOverflow, allowImplicitConversion);
} else if (checkForOverflow) {
// if overflow-checking is enabled, we can simply cast via long:
// (and long itself works directly in checked context)
@ -331,14 +337,16 @@ namespace ICSharpCode.Decompiler.CSharp @@ -331,14 +337,16 @@ namespace ICSharpCode.Decompiler.CSharp
} else {
// If overflow-checking is disabled, the only way to truncate to native size
// without throwing an exception in 32-bit mode is to use a pointer type.
if (type.Kind != TypeKind.Pointer) {
return this.ConvertTo(new PointerType(compilation.FindType(KnownTypeCode.Void)), expressionBuilder, checkForOverflow)
.ConvertTo(targetType, expressionBuilder, checkForOverflow);
}
return this.ConvertTo(new PointerType(compilation.FindType(KnownTypeCode.Void)), expressionBuilder, checkForOverflow)
.ConvertTo(targetType, expressionBuilder, checkForOverflow);
}
} else if (targetUType.IsKnownType(KnownTypeCode.UIntPtr)) { // Conversion to UIntPtr
if (type.IsKnownType(KnownTypeCode.UInt32) || type.Kind == TypeKind.Pointer) {
// normal casts work for uint and pointers (both in checked and unchecked context)
if (type.IsKnownType(KnownTypeCode.UInt32) || type.Kind == TypeKind.Pointer || type.Kind == TypeKind.NUInt) {
// normal casts work for uint/nuint and pointers (both in checked and unchecked context)
} else if (expressionBuilder.settings.NativeIntegers) {
// if native integer types are available, prefer using those
return this.ConvertTo(SpecialType.NUInt, expressionBuilder, checkForOverflow)
.ConvertTo(targetType, expressionBuilder, checkForOverflow, allowImplicitConversion);
} else if (checkForOverflow) {
// if overflow-checking is enabled, we can simply cast via ulong:
// (and ulong itself works directly in checked context)
@ -471,7 +479,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -471,7 +479,7 @@ namespace ICSharpCode.Decompiler.CSharp
return this;
}
} else {
if (targetType.Kind != TypeKind.Dynamic && type.Kind != TypeKind.Dynamic && NormalizeTypeVisitor.TypeErasure.EquivalentTypes(type, targetType)) {
if (NormalizeTypeVisitor.IgnoreNullabilityAndTuples.EquivalentTypes(type, targetType)) {
// avoid an explicit cast when types differ only in nullability of reference types
return this;
}

11
ICSharpCode.Decompiler/TypeSystem/NormalizeTypeVisitor.cs

@ -22,6 +22,17 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -22,6 +22,17 @@ namespace ICSharpCode.Decompiler.TypeSystem
RemoveNullability = true,
};
internal static readonly NormalizeTypeVisitor IgnoreNullabilityAndTuples = new NormalizeTypeVisitor {
ReplaceClassTypeParametersWithDummy = false,
ReplaceMethodTypeParametersWithDummy = false,
DynamicAndObject = false,
IntPtrToNInt = false,
TupleToUnderlyingType = true,
RemoveModOpt = true,
RemoveModReq = true,
RemoveNullability = true,
};
public bool EquivalentTypes(IType a, IType b)
{
a = a.AcceptVisitor(this);

Loading…
Cancel
Save