Browse Source

Use `nint` type for local IntPtr variables if arithmetic is performed on them.

pull/2063/head
Daniel Grunwald 5 years ago
parent
commit
1b2874eb5d
  1. 33
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/NativeInts.cs
  2. 6
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/TupleTests.cs
  3. 1
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
  4. 1
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  5. 29
      ICSharpCode.Decompiler/IL/Transforms/AssignVariableNames.cs
  6. 78
      ICSharpCode.Decompiler/IL/Transforms/IntroduceNativeIntTypeOnLocals.cs

33
ICSharpCode.Decompiler.Tests/TestCases/Pretty/NativeInts.cs

@ -161,5 +161,38 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -161,5 +161,38 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
GetInstance(7).i <<= i32;
}
public void LocalTypeFromStore()
{
nint num = 42;
IntPtr zero = IntPtr.Zero;
nint zero2 = IntPtr.Zero;
nuint num2 = 43u;
nint num3 = i;
IntPtr intPtr = intptr;
Console.WriteLine();
zero2 = 1;
Console.WriteLine();
intptr = num;
intptr = zero;
intptr = zero2;
uintptr = num2;
intptr = num3;
intptr = intPtr;
}
public void LocalTypeFromUse()
{
IntPtr intPtr = intptr;
nint num = intptr;
Console.WriteLine();
intptr = intPtr;
i = num + 1;
}
}
}

6
ICSharpCode.Decompiler.Tests/TestCases/Pretty/TupleTests.cs

@ -146,9 +146,9 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -146,9 +146,9 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
public void LocalVariables((int, int) a)
{
(int, int) valueTuple = (a.Item1 + a.Item2, a.Item1 * a.Item2);
Console.WriteLine(valueTuple.ToString());
Console.WriteLine(valueTuple.GetType().FullName);
(int, int) tuple = (a.Item1 + a.Item2, a.Item1 * a.Item2);
Console.WriteLine(tuple.ToString());
Console.WriteLine(tuple.GetType().FullName);
}
public void Foreach(IEnumerable<(int, string)> input)

1
ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

@ -165,6 +165,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -165,6 +165,7 @@ namespace ICSharpCode.Decompiler.CSharp
new HighLevelLoopTransform(),
new ReduceNestingTransform(),
new IntroduceDynamicTypeOnLocals(),
new IntroduceNativeIntTypeOnLocals(),
new AssignVariableNames(),
};
}

1
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -78,6 +78,7 @@ @@ -78,6 +78,7 @@
<Compile Include="Disassembler\DisassemblerSignatureTypeProvider.cs" />
<Compile Include="Documentation\XmlDocumentationElement.cs" />
<Compile Include="IL\ControlFlow\AwaitInFinallyTransform.cs" />
<Compile Include="IL\Transforms\IntroduceNativeIntTypeOnLocals.cs" />
<Compile Include="Solution\ProjectId.cs" />
<Compile Include="Solution\ProjectItem.cs" />
<Compile Include="Solution\SolutionCreator.cs" />

29
ICSharpCode.Decompiler/IL/Transforms/AssignVariableNames.cs

@ -417,19 +417,28 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -417,19 +417,28 @@ namespace ICSharpCode.Decompiler.IL.Transforms
type = NullableType.GetUnderlyingType(((TypeWithElementType)type).ElementType);
}
string name;
if (type is ArrayType) {
name = "array";
} else if (type is PointerType) {
name = "ptr";
} else if (type.Kind == TypeKind.TypeParameter || type.Kind == TypeKind.Unknown || type.Kind == TypeKind.Dynamic) {
name = "val";
} else if (type.Kind == TypeKind.ByReference) {
name = "reference";
} else if (type.IsAnonymousType()) {
string name = type.Kind switch
{
TypeKind.Array => "array",
TypeKind.Pointer => "ptr",
TypeKind.TypeParameter => "val",
TypeKind.Unknown => "val",
TypeKind.Dynamic => "val",
TypeKind.ByReference => "reference",
TypeKind.Tuple => "tuple",
TypeKind.NInt => "num",
TypeKind.NUInt => "num",
_ => null
};
if (name != null) {
return name;
}
if (type.IsAnonymousType()) {
name = "anon";
} else if (type.Name.EndsWith("Exception", StringComparison.Ordinal)) {
name = "ex";
} else if (type.IsCSharpNativeIntegerType()) {
name = "num";
} else if (!typeNameToVariableNameDict.TryGetValue(type.FullName, out name)) {
name = type.Name;
// remove the 'I' for interfaces

78
ICSharpCode.Decompiler/IL/Transforms/IntroduceNativeIntTypeOnLocals.cs

@ -0,0 +1,78 @@ @@ -0,0 +1,78 @@
// Copyright (c) 2020 Daniel Grunwald
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ICSharpCode.Decompiler.IL.Transforms;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.IL
{
class IntroduceNativeIntTypeOnLocals : IILTransform
{
public void Run(ILFunction function, ILTransformContext context)
{
if (!context.Settings.NativeIntegers)
return;
foreach (var variable in function.Variables) {
if (variable.Kind != VariableKind.Local &&
variable.Kind != VariableKind.StackSlot &&
variable.Kind != VariableKind.ForeachLocal &&
variable.Kind != VariableKind.UsingLocal) {
continue;
}
if (!(variable.Type.IsKnownType(KnownTypeCode.IntPtr) || variable.Type.IsKnownType(KnownTypeCode.UIntPtr)))
continue;
bool isUsedAsNativeInt = variable.LoadInstructions.Any(IsUsedAsNativeInt);
bool isAssignedNativeInt = variable.StoreInstructions.Any(store => IsNativeIntStore(store, context.TypeSystem));
if (isUsedAsNativeInt || isAssignedNativeInt) {
variable.Type = variable.Type.GetSign() == Sign.Unsigned ? SpecialType.NUInt : SpecialType.NInt;
}
}
}
static bool IsUsedAsNativeInt(LdLoc load)
{
return load.Parent switch
{
BinaryNumericInstruction { UnderlyingResultType: StackType.I } => true,
BitNot { UnderlyingResultType: StackType.I } => true,
CallInstruction call => call.GetParameter(load.ChildIndex)?.Type.IsCSharpNativeIntegerType() ?? false,
_ => false,
};
}
static bool IsNativeIntStore(IStoreInstruction store, ICompilation compilation)
{
if (store is StLoc stloc) {
switch (stloc.Value) {
case BinaryNumericInstruction { UnderlyingResultType: StackType.I }:
return true;
case Conv { ResultType: StackType.I }:
return true;
default:
var inferredType = stloc.Value.InferType(compilation);
return inferredType.IsCSharpNativeIntegerType();
}
}
return false;
}
}
}
Loading…
Cancel
Save