Browse Source

Merge branch 'master' of https://github.com/icsharpcode/ILSpy into local-functions

pull/1586/head
Siegfried Pammer 7 years ago
parent
commit
8af609e7df
  1. 1
      ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
  2. 6
      ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
  3. 9
      ICSharpCode.Decompiler.Tests/TestCases/Correctness/TrickyTypes.cs
  4. 16
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/DelegateConstruction.cs
  5. 11
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/InlineAssignmentTest.cs
  6. 134
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/UserDefinedConversions.cs
  7. 14
      ICSharpCode.Decompiler/CSharp/Annotations.cs
  8. 11
      ICSharpCode.Decompiler/CSharp/CallBuilder.cs
  9. 2
      ICSharpCode.Decompiler/CSharp/Transforms/IntroduceExtensionMethods.cs
  10. 13
      ICSharpCode.Decompiler/CSharp/Transforms/ReplaceMethodCallsWithOperators.cs
  11. 23
      ICSharpCode.Decompiler/CSharp/TranslatedExpression.cs
  12. 11
      ICSharpCode.Decompiler/IL/ILReader.cs
  13. 149
      ICSharpCode.Decompiler/IL/InstructionOutputExtensions.cs
  14. 22
      ICSharpCode.Decompiler/IL/Instructions/CallIndirect.cs
  15. 1
      ICSharpCode.Decompiler/IL/Instructions/CompoundAssignmentInstruction.cs
  16. 9
      ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs
  17. 2
      ICSharpCode.Decompiler/IL/Transforms/ReduceNestingTransform.cs
  18. 12
      ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs
  19. 8
      ICSharpCode.Decompiler/TypeSystem/TypeProvider.cs
  20. 2
      ILSpy-tests
  21. 1
      ILSpy.AddIn/ILSpy.AddIn.csproj
  22. 4
      ILSpy/Options/DecompilerSettingsPanel.xaml.cs

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

@ -89,6 +89,7 @@
<Compile Include="TestCases\ILPretty\Issue1323.cs" /> <Compile Include="TestCases\ILPretty\Issue1323.cs" />
<Compile Include="TestCases\Pretty\CustomAttributes2.cs" /> <Compile Include="TestCases\Pretty\CustomAttributes2.cs" />
<Compile Include="TestCases\Pretty\EnumTests.cs" /> <Compile Include="TestCases\Pretty\EnumTests.cs" />
<Compile Include="TestCases\Pretty\UserDefinedConversions.cs" />
<None Include="TestCases\ILPretty\Unsafe.il" /> <None Include="TestCases\ILPretty\Unsafe.il" />
<None Include="TestCases\Pretty\NullableRefTypes.cs" /> <None Include="TestCases\Pretty\NullableRefTypes.cs" />
<Compile Include="TestCases\Pretty\TypeMemberTests.cs" /> <Compile Include="TestCases\Pretty\TypeMemberTests.cs" />

6
ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs

@ -425,6 +425,12 @@ namespace ICSharpCode.Decompiler.Tests
RunForLibrary(cscOptions: cscOptions); RunForLibrary(cscOptions: cscOptions);
} }
[Test]
public void UserDefinedConversions([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions)
{
RunForLibrary(cscOptions: cscOptions);
}
[Test] [Test]
public void Discards([ValueSource(nameof(roslynOnlyOptions))] CompilerOptions cscOptions) public void Discards([ValueSource(nameof(roslynOnlyOptions))] CompilerOptions cscOptions)
{ {

9
ICSharpCode.Decompiler.Tests/TestCases/Correctness/TrickyTypes.cs

@ -26,6 +26,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
{ {
InterestingConstants(); InterestingConstants();
TruncatedComp(); TruncatedComp();
StringConcat();
} }
static void Print<T>(T val) static void Print<T>(T val)
@ -92,5 +93,13 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
Print(val1 <= val2); Print(val1 <= val2);
Print((int)val1 <= val2); Print((int)val1 <= val2);
} }
static void StringConcat()
{
// Some string.Concat()-cases that cannot be replaced using operator+
Print(string.Concat("String concat:"));
Print(string.Concat(1, 2));
Print(string.Concat(1, 2, "str"));
}
} }
} }

16
ICSharpCode.Decompiler.Tests/TestCases/Pretty/DelegateConstruction.cs

@ -159,6 +159,17 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{ {
} }
public static Predicate<T> And<T>(this Predicate<T> filter1, Predicate<T> filter2)
{
if (filter1 == null) {
return filter2;
}
if (filter2 == null) {
return filter1;
}
return (T m) => filter1(m) && filter2(m);
}
public static Action<string> ExtensionMethodUnbound() public static Action<string> ExtensionMethodUnbound()
{ {
return Test; return Test;
@ -174,6 +185,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
return ((string)null).Test; return ((string)null).Test;
} }
public static Predicate<int> NoExtensionMethodOnLambda()
{
return And((int x) => x >= 0, (int x) => x <= 100);
}
public static object StaticMethod() public static object StaticMethod()
{ {
return new Func<Action>(ExtensionMethodBound); return new Func<Action>(ExtensionMethodBound);

11
ICSharpCode.Decompiler.Tests/TestCases/Pretty/InlineAssignmentTest.cs

@ -32,11 +32,17 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
get; get;
set; set;
} }
public static int StaticProperty { public static int StaticProperty {
get; get;
set; set;
} }
public bool BoolProperty {
get;
set;
}
public void SimpleInlineWithLocals() public void SimpleInlineWithLocals()
{ {
int index; int index;
@ -136,5 +142,10 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{ {
return InstanceProperty = GetIndex(); return InstanceProperty = GetIndex();
} }
public bool BoolPropertyTest(object x)
{
return BoolProperty = (x != null);
}
} }
} }

134
ICSharpCode.Decompiler.Tests/TestCases/Pretty/UserDefinedConversions.cs

@ -0,0 +1,134 @@
// Copyright (c) 2019 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.
namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
internal class T01Issue1574
{
private struct A
{
private bool val;
public static implicit operator bool(A a)
{
return a.val;
}
}
private struct C
{
private int val;
public static implicit operator C(bool b)
{
return default(C);
}
}
private C ChainedConversion()
{
return (bool)default(A);
}
public void Call_Overloaded()
{
Overloaded((bool)default(A));
}
private void Overloaded(A a)
{
}
private void Overloaded(bool a)
{
}
}
internal class T02BothDirectAndChainedConversionPossible
{
private struct A
{
private bool val;
public static implicit operator bool(A a)
{
return a.val;
}
}
private struct C
{
private int val;
public static implicit operator C(bool b)
{
return default(C);
}
public static implicit operator C(A a)
{
return default(C);
}
public static bool operator ==(C a, C b)
{
return true;
}
public static bool operator !=(C a, C b)
{
return false;
}
}
private C DirectConvert(A a)
{
return a;
}
private C IndirectConvert(A a)
{
return (bool)a;
}
private C? LiftedDirectConvert(A? a)
{
return a;
}
private C? LiftedIndirectConvert(A? a)
{
return (bool?)a;
}
private bool Compare(A a, C c)
{
return a == c;
}
private void LiftedCompare(A? a, C? c)
{
UseBool(a == c);
UseBool(a == default(C));
UseBool(c == default(A));
}
private void UseBool(bool b)
{
}
}
}

14
ICSharpCode.Decompiler/CSharp/Annotations.cs

@ -240,4 +240,18 @@ namespace ICSharpCode.Decompiler.CSharp
this.Leave = leave; this.Leave = leave;
} }
} }
/// <summary>
/// Annotates an expression when an implicit user-defined conversion was omitted.
/// </summary>
public class ImplicitConversionAnnotation
{
public readonly ConversionResolveResult ConversionResolveResult;
public IType TargetType => ConversionResolveResult.Type;
public ImplicitConversionAnnotation(ConversionResolveResult conversionResolveResult)
{
this.ConversionResolveResult = conversionResolveResult;
}
}
} }

11
ICSharpCode.Decompiler/CSharp/CallBuilder.cs

@ -360,7 +360,7 @@ namespace ICSharpCode.Decompiler.CSharp
// settings.AlwaysCastTargetsOfExplicitInterfaceImplementationCalls == true is used in Windows Forms' InitializeComponent methods. // settings.AlwaysCastTargetsOfExplicitInterfaceImplementationCalls == true is used in Windows Forms' InitializeComponent methods.
if (method.IsExplicitInterfaceImplementation && (target.Expression is ThisReferenceExpression || settings.AlwaysCastTargetsOfExplicitInterfaceImplementationCalls)) { if (method.IsExplicitInterfaceImplementation && (target.Expression is ThisReferenceExpression || settings.AlwaysCastTargetsOfExplicitInterfaceImplementationCalls)) {
var interfaceMember = method.ExplicitlyImplementedInterfaceMembers.First(); var interfaceMember = method.ExplicitlyImplementedInterfaceMembers.First();
var castExpression = new CastExpression(expressionBuilder.ConvertType(interfaceMember.DeclaringType), target.Expression); var castExpression = new CastExpression(expressionBuilder.ConvertType(interfaceMember.DeclaringType), target.Expression.Detach());
methodName = interfaceMember.Name; methodName = interfaceMember.Name;
targetExpr = new MemberReferenceExpression(castExpression, methodName); targetExpr = new MemberReferenceExpression(castExpression, methodName);
typeArgumentList = ((MemberReferenceExpression)targetExpr).TypeArguments; typeArgumentList = ((MemberReferenceExpression)targetExpr).TypeArguments;
@ -1008,11 +1008,14 @@ namespace ICSharpCode.Decompiler.CSharp
} else if (method.IsOperator) { } else if (method.IsOperator) {
IEnumerable<IParameterizedMember> operatorCandidates; IEnumerable<IParameterizedMember> operatorCandidates;
if (arguments.Count == 1) { if (arguments.Count == 1) {
operatorCandidates = resolver.GetUserDefinedOperatorCandidates(arguments[0].Type, method.Name); IType argType = NullableType.GetUnderlyingType(arguments[0].Type);
operatorCandidates = resolver.GetUserDefinedOperatorCandidates(argType, method.Name);
} else if (arguments.Count == 2) { } else if (arguments.Count == 2) {
IType lhsType = NullableType.GetUnderlyingType(arguments[0].Type);
IType rhsType = NullableType.GetUnderlyingType(arguments[1].Type);
var hashSet = new HashSet<IParameterizedMember>(); var hashSet = new HashSet<IParameterizedMember>();
hashSet.UnionWith(resolver.GetUserDefinedOperatorCandidates(arguments[0].Type, method.Name)); hashSet.UnionWith(resolver.GetUserDefinedOperatorCandidates(lhsType, method.Name));
hashSet.UnionWith(resolver.GetUserDefinedOperatorCandidates(arguments[1].Type, method.Name)); hashSet.UnionWith(resolver.GetUserDefinedOperatorCandidates(rhsType, method.Name));
operatorCandidates = hashSet; operatorCandidates = hashSet;
} else { } else {
operatorCandidates = EmptyList<IParameterizedMember>.Instance; operatorCandidates = EmptyList<IParameterizedMember>.Instance;

2
ICSharpCode.Decompiler/CSharp/Transforms/IntroduceExtensionMethods.cs

@ -162,6 +162,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
public static bool CanTransformToExtensionMethodCall(CSharpResolver resolver, IMethod method, public static bool CanTransformToExtensionMethodCall(CSharpResolver resolver, IMethod method,
IReadOnlyList<IType> typeArguments, ResolveResult target, ResolveResult[] arguments, string[] argumentNames) IReadOnlyList<IType> typeArguments, ResolveResult target, ResolveResult[] arguments, string[] argumentNames)
{ {
if (target is LambdaResolveResult)
return false;
var rr = resolver.ResolveMemberAccess(target, method.Name, typeArguments, NameLookupMode.InvocationTarget) as MethodGroupResolveResult; var rr = resolver.ResolveMemberAccess(target, method.Name, typeArguments, NameLookupMode.InvocationTarget) as MethodGroupResolveResult;
if (rr == null) if (rr == null)
return false; return false;

13
ICSharpCode.Decompiler/CSharp/Transforms/ReplaceMethodCallsWithOperators.cs

@ -154,16 +154,9 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
if (arguments.Length < 2) if (arguments.Length < 2)
return false; return false;
bool valid = false; return !arguments.Any(arg => arg is NamedArgumentExpression) &&
(arguments[0].GetResolveResult().Type.IsKnownType(KnownTypeCode.String) ||
foreach (var argument in arguments) { arguments[1].GetResolveResult().Type.IsKnownType(KnownTypeCode.String));
if (argument is NamedArgumentExpression)
return false;
if (argument.GetResolveResult().Type.IsKnownType(KnownTypeCode.String))
valid = true;
}
return valid;
} }
static BinaryOperatorType? GetBinaryOperatorTypeFromMetadataName(string name) static BinaryOperatorType? GetBinaryOperatorTypeFromMetadataName(string name)

23
ICSharpCode.Decompiler/CSharp/TranslatedExpression.cs

@ -191,7 +191,11 @@ namespace ICSharpCode.Decompiler.CSharp
conversion.Input.Type, conversion.Input.Type,
type, targetType type, targetType
)) { )) {
return this.UnwrapChild(cast.Expression); var result = this.UnwrapChild(cast.Expression);
if (conversion.Conversion.IsUserDefined) {
result.Expression.AddAnnotation(new ImplicitConversionAnnotation(conversion));
}
return result;
} else if (Expression is ObjectCreateExpression oce && conversion.Conversion.IsMethodGroupConversion } else if (Expression is ObjectCreateExpression oce && conversion.Conversion.IsMethodGroupConversion
&& oce.Arguments.Count == 1 && expressionBuilder.settings.UseImplicitMethodGroupConversion) { && oce.Arguments.Count == 1 && expressionBuilder.settings.UseImplicitMethodGroupConversion) {
return this.UnwrapChild(oce.Arguments.Single()); return this.UnwrapChild(oce.Arguments.Single());
@ -211,6 +215,18 @@ namespace ICSharpCode.Decompiler.CSharp
if (targetType.Kind == TypeKind.Unknown || targetType.Kind == TypeKind.Void || targetType.Kind == TypeKind.None) { if (targetType.Kind == TypeKind.Unknown || targetType.Kind == TypeKind.Void || targetType.Kind == TypeKind.None) {
return this; // don't attempt to insert cast to '?' or 'void' as these are not valid. return this; // don't attempt to insert cast to '?' or 'void' as these are not valid.
} }
var convAnnotation = this.Expression.Annotation<ImplicitConversionAnnotation>();
if (convAnnotation != null) {
// If an implicit user-defined conversion was stripped from this expression;
// it needs to be re-introduced before we can apply other casts to this expression.
// This happens when the CallBuilder discovers that the conversion is necessary in
// order to choose the correct overload.
this.Expression.RemoveAnnotations<ImplicitConversionAnnotation>();
return new CastExpression(expressionBuilder.ConvertType(convAnnotation.TargetType), Expression)
.WithoutILInstruction()
.WithRR(convAnnotation.ConversionResolveResult)
.ConvertTo(targetType, expressionBuilder, checkForOverflow, allowImplicitConversion);
}
if (Expression is TupleExpression tupleExpr && targetType is TupleType targetTupleType if (Expression is TupleExpression tupleExpr && targetType is TupleType targetTupleType
&& tupleExpr.Elements.Count == targetTupleType.ElementTypes.Length) && tupleExpr.Elements.Count == targetTupleType.ElementTypes.Length)
{ {
@ -231,8 +247,9 @@ namespace ICSharpCode.Decompiler.CSharp
} }
var compilation = expressionBuilder.compilation; var compilation = expressionBuilder.compilation;
var conversions = Resolver.CSharpConversions.Get(compilation); var conversions = Resolver.CSharpConversions.Get(compilation);
if (ResolveResult is ConversionResolveResult conv && Expression is CastExpression cast2 && if (ResolveResult is ConversionResolveResult conv && Expression is CastExpression cast2
CastCanBeMadeImplicit(conversions, conv.Conversion, conv.Input.Type, type, targetType)) && !conv.Conversion.IsUserDefined
&& CastCanBeMadeImplicit(conversions, conv.Conversion, conv.Input.Type, type, targetType))
{ {
var unwrapped = this.UnwrapChild(cast2.Expression); var unwrapped = this.UnwrapChild(cast2.Expression);
if (allowImplicitConversion) if (allowImplicitConversion)

11
ICSharpCode.Decompiler/IL/ILReader.cs

@ -1401,12 +1401,17 @@ namespace ICSharpCode.Decompiler.IL
var signatureHandle = (StandaloneSignatureHandle)ReadAndDecodeMetadataToken(); var signatureHandle = (StandaloneSignatureHandle)ReadAndDecodeMetadataToken();
var signature = module.DecodeMethodSignature(signatureHandle, genericContext); var signature = module.DecodeMethodSignature(signatureHandle, genericContext);
var functionPointer = Pop(StackType.I); var functionPointer = Pop(StackType.I);
Debug.Assert(!signature.Header.IsInstance); int firstArgument = signature.Header.IsInstance ? 1 : 0;
var arguments = new ILInstruction[signature.ParameterTypes.Length]; var arguments = new ILInstruction[firstArgument + signature.ParameterTypes.Length];
for (int i = signature.ParameterTypes.Length - 1; i >= 0; i--) { for (int i = signature.ParameterTypes.Length - 1; i >= 0; i--) {
arguments[i] = Pop(signature.ParameterTypes[i].GetStackType()); arguments[firstArgument + i] = Pop(signature.ParameterTypes[i].GetStackType());
}
if (firstArgument == 1) {
arguments[0] = Pop();
} }
var call = new CallIndirect( var call = new CallIndirect(
signature.Header.IsInstance,
signature.Header.HasExplicitThis,
signature.Header.CallingConvention, signature.Header.CallingConvention,
signature.ReturnType, signature.ReturnType,
signature.ParameterTypes, signature.ParameterTypes,

149
ICSharpCode.Decompiler/IL/InstructionOutputExtensions.cs

@ -133,14 +133,7 @@ namespace ICSharpCode.Decompiler.IL
case HandleKind.MethodDefinition: { case HandleKind.MethodDefinition: {
var md = metadata.GetMethodDefinition((MethodDefinitionHandle)entity); var md = metadata.GetMethodDefinition((MethodDefinitionHandle)entity);
methodSignature = md.DecodeSignature(new DisassemblerSignatureProvider(module, output), new Metadata.GenericContext((MethodDefinitionHandle)entity, module)); methodSignature = md.DecodeSignature(new DisassemblerSignatureProvider(module, output), new Metadata.GenericContext((MethodDefinitionHandle)entity, module));
if (methodSignature.Header.HasExplicitThis) { WriteSignatureHeader(output, methodSignature);
output.Write("instance explicit ");
} else if (methodSignature.Header.IsInstance) {
output.Write("instance ");
}
if (methodSignature.Header.CallingConvention == SignatureCallingConvention.VarArgs) {
output.Write("vararg ");
}
methodSignature.ReturnType(ILNameSyntax.SignatureNoNamedTypeParameters); methodSignature.ReturnType(ILNameSyntax.SignatureNoNamedTypeParameters);
output.Write(' '); output.Write(' ');
var declaringType = md.GetDeclaringType(); var declaringType = md.GetDeclaringType();
@ -189,13 +182,7 @@ namespace ICSharpCode.Decompiler.IL
} }
output.Write('>'); output.Write('>');
} }
output.Write("("); WriteParameterList(output, methodSignature);
for (int i = 0; i < methodSignature.ParameterTypes.Length; ++i) {
if (i > 0)
output.Write(", ");
methodSignature.ParameterTypes[i](ILNameSyntax.SignatureNoNamedTypeParameters);
}
output.Write(")");
break; break;
} }
case HandleKind.MemberReference: case HandleKind.MemberReference:
@ -204,28 +191,13 @@ namespace ICSharpCode.Decompiler.IL
switch (mr.GetKind()) { switch (mr.GetKind()) {
case MemberReferenceKind.Method: case MemberReferenceKind.Method:
methodSignature = mr.DecodeMethodSignature(new DisassemblerSignatureProvider(module, output), genericContext); methodSignature = mr.DecodeMethodSignature(new DisassemblerSignatureProvider(module, output), genericContext);
if (methodSignature.Header.HasExplicitThis) { WriteSignatureHeader(output, methodSignature);
output.Write("instance explicit ");
} else if (methodSignature.Header.IsInstance) {
output.Write("instance ");
}
if (methodSignature.Header.CallingConvention == SignatureCallingConvention.VarArgs) {
output.Write("vararg ");
}
methodSignature.ReturnType(ILNameSyntax.SignatureNoNamedTypeParameters); methodSignature.ReturnType(ILNameSyntax.SignatureNoNamedTypeParameters);
output.Write(' '); output.Write(' ');
WriteParent(output, module, metadata, mr.Parent, genericContext, syntax); WriteParent(output, module, metadata, mr.Parent, genericContext, syntax);
output.Write("::"); output.Write("::");
output.WriteReference(module, entity, DisassemblerHelpers.Escape(memberName)); output.WriteReference(module, entity, DisassemblerHelpers.Escape(memberName));
output.Write("("); WriteParameterList(output, methodSignature);
for (int i = 0; i < methodSignature.ParameterTypes.Length; ++i) {
if (i > 0)
output.Write(", ");
if (i == methodSignature.RequiredParameterCount)
output.Write("..., ");
methodSignature.ParameterTypes[i](ILNameSyntax.SignatureNoNamedTypeParameters);
}
output.Write(")");
break; break;
case MemberReferenceKind.Field: case MemberReferenceKind.Field:
var fieldSignature = mr.DecodeFieldSignature(new DisassemblerSignatureProvider(module, output), genericContext); var fieldSignature = mr.DecodeFieldSignature(new DisassemblerSignatureProvider(module, output), genericContext);
@ -245,14 +217,7 @@ namespace ICSharpCode.Decompiler.IL
var methodDefinition = metadata.GetMethodDefinition((MethodDefinitionHandle)ms.Method); var methodDefinition = metadata.GetMethodDefinition((MethodDefinitionHandle)ms.Method);
var methodName = metadata.GetString(methodDefinition.Name); var methodName = metadata.GetString(methodDefinition.Name);
methodSignature = methodDefinition.DecodeSignature(new DisassemblerSignatureProvider(module, output), genericContext); methodSignature = methodDefinition.DecodeSignature(new DisassemblerSignatureProvider(module, output), genericContext);
if (methodSignature.Header.HasExplicitThis) { WriteSignatureHeader(output, methodSignature);
output.Write("instance explicit ");
} else if (methodSignature.Header.IsInstance) {
output.Write("instance ");
}
if (methodSignature.Header.CallingConvention == SignatureCallingConvention.VarArgs) {
output.Write("vararg ");
}
methodSignature.ReturnType(ILNameSyntax.SignatureNoNamedTypeParameters); methodSignature.ReturnType(ILNameSyntax.SignatureNoNamedTypeParameters);
output.Write(' '); output.Write(' ');
var declaringType = methodDefinition.GetDeclaringType(); var declaringType = methodDefinition.GetDeclaringType();
@ -266,52 +231,21 @@ namespace ICSharpCode.Decompiler.IL
} else { } else {
output.Write(DisassemblerHelpers.Escape(methodName)); output.Write(DisassemblerHelpers.Escape(methodName));
} }
output.Write('<'); WriteTypeParameterList(output, syntax, substitution);
for (int i = 0; i < substitution.Length; i++) { WriteParameterList(output, methodSignature);
if (i > 0)
output.Write(", ");
substitution[i](syntax);
}
output.Write('>');
output.Write("(");
for (int i = 0; i < methodSignature.ParameterTypes.Length; ++i) {
if (i > 0)
output.Write(", ");
methodSignature.ParameterTypes[i](ILNameSyntax.SignatureNoNamedTypeParameters);
}
output.Write(")");
break; break;
case HandleKind.MemberReference: case HandleKind.MemberReference:
var memberReference = metadata.GetMemberReference((MemberReferenceHandle)ms.Method); var memberReference = metadata.GetMemberReference((MemberReferenceHandle)ms.Method);
memberName = metadata.GetString(memberReference.Name); memberName = metadata.GetString(memberReference.Name);
methodSignature = memberReference.DecodeMethodSignature(new DisassemblerSignatureProvider(module, output), genericContext); methodSignature = memberReference.DecodeMethodSignature(new DisassemblerSignatureProvider(module, output), genericContext);
if (methodSignature.Header.HasExplicitThis) { WriteSignatureHeader(output, methodSignature);
output.Write("instance explicit ");
} else if (methodSignature.Header.IsInstance) {
output.Write("instance ");
}
if (methodSignature.Header.CallingConvention == SignatureCallingConvention.VarArgs) {
output.Write("vararg ");
}
methodSignature.ReturnType(ILNameSyntax.SignatureNoNamedTypeParameters); methodSignature.ReturnType(ILNameSyntax.SignatureNoNamedTypeParameters);
output.Write(' '); output.Write(' ');
WriteParent(output, module, metadata, memberReference.Parent, genericContext, syntax); WriteParent(output, module, metadata, memberReference.Parent, genericContext, syntax);
output.Write("::"); output.Write("::");
output.Write(DisassemblerHelpers.Escape(memberName)); output.Write(DisassemblerHelpers.Escape(memberName));
output.Write('<'); WriteTypeParameterList(output, syntax, substitution);
for (int i = 0; i < substitution.Length; i++) { WriteParameterList(output, methodSignature);
if (i > 0)
output.Write(", ");
substitution[i](syntax);
}
output.Write('>');
output.Write("(");
for (int i = 0; i < methodSignature.ParameterTypes.Length; ++i) {
if (i > 0)
output.Write(", ");
methodSignature.ParameterTypes[i](ILNameSyntax.SignatureNoNamedTypeParameters);
}
output.Write(")");
break; break;
} }
break; break;
@ -319,15 +253,10 @@ namespace ICSharpCode.Decompiler.IL
var standaloneSig = metadata.GetStandaloneSignature((StandaloneSignatureHandle)entity); var standaloneSig = metadata.GetStandaloneSignature((StandaloneSignatureHandle)entity);
switch (standaloneSig.GetKind()) { switch (standaloneSig.GetKind()) {
case StandaloneSignatureKind.Method: case StandaloneSignatureKind.Method:
var methodSig = standaloneSig.DecodeMethodSignature(new DisassemblerSignatureProvider(module, output), genericContext); methodSignature = standaloneSig.DecodeMethodSignature(new DisassemblerSignatureProvider(module, output), genericContext);
methodSig.ReturnType(ILNameSyntax.SignatureNoNamedTypeParameters); WriteSignatureHeader(output, methodSignature);
output.Write('('); methodSignature.ReturnType(ILNameSyntax.SignatureNoNamedTypeParameters);
for (int i = 0; i < methodSig.ParameterTypes.Length; i++) { WriteParameterList(output, methodSignature);
if (i > 0)
output.Write(", ");
methodSig.ParameterTypes[i](ILNameSyntax.SignatureNoNamedTypeParameters);
}
output.Write(')');
break; break;
case StandaloneSignatureKind.LocalVariables: case StandaloneSignatureKind.LocalVariables:
default: default:
@ -341,6 +270,56 @@ namespace ICSharpCode.Decompiler.IL
} }
} }
static void WriteTypeParameterList(ITextOutput output, ILNameSyntax syntax, System.Collections.Immutable.ImmutableArray<Action<ILNameSyntax>> substitution)
{
output.Write('<');
for (int i = 0; i < substitution.Length; i++) {
if (i > 0)
output.Write(", ");
substitution[i](syntax);
}
output.Write('>');
}
static void WriteParameterList(ITextOutput output, MethodSignature<Action<ILNameSyntax>> methodSignature)
{
output.Write("(");
for (int i = 0; i < methodSignature.ParameterTypes.Length; ++i) {
if (i > 0)
output.Write(", ");
if (i == methodSignature.RequiredParameterCount)
output.Write("..., ");
methodSignature.ParameterTypes[i](ILNameSyntax.SignatureNoNamedTypeParameters);
}
output.Write(")");
}
static void WriteSignatureHeader(ITextOutput output, MethodSignature<Action<ILNameSyntax>> methodSignature)
{
if (methodSignature.Header.HasExplicitThis) {
output.Write("instance explicit ");
} else if (methodSignature.Header.IsInstance) {
output.Write("instance ");
}
switch (methodSignature.Header.CallingConvention) {
case SignatureCallingConvention.CDecl:
output.Write("unmanaged cdecl ");
break;
case SignatureCallingConvention.StdCall:
output.Write("unmanaged stdcall ");
break;
case SignatureCallingConvention.ThisCall:
output.Write("unmanaged thiscall ");
break;
case SignatureCallingConvention.FastCall:
output.Write("unmanaged fastcall ");
break;
case SignatureCallingConvention.VarArgs:
output.Write("vararg ");
break;
}
}
static void WriteParent(ITextOutput output, PEFile module, MetadataReader metadata, EntityHandle parentHandle, Metadata.GenericContext genericContext, ILNameSyntax syntax) static void WriteParent(ITextOutput output, PEFile module, MetadataReader metadata, EntityHandle parentHandle, Metadata.GenericContext genericContext, ILNameSyntax syntax)
{ {
switch (parentHandle.Kind) { switch (parentHandle.Kind) {

22
ICSharpCode.Decompiler/IL/Instructions/CallIndirect.cs

@ -32,7 +32,8 @@ namespace ICSharpCode.Decompiler.IL
public readonly InstructionCollection<ILInstruction> Arguments; public readonly InstructionCollection<ILInstruction> Arguments;
ILInstruction functionPointer; ILInstruction functionPointer;
public bool IsInstance { get; }
public bool HasExplicitThis { get; }
public System.Reflection.Metadata.SignatureCallingConvention CallingConvention { get; } public System.Reflection.Metadata.SignatureCallingConvention CallingConvention { get; }
public IType ReturnType { get; } public IType ReturnType { get; }
public ImmutableArray<IType> ParameterTypes { get; } public ImmutableArray<IType> ParameterTypes { get; }
@ -61,9 +62,11 @@ namespace ICSharpCode.Decompiler.IL
functionPointer.ChildIndex = Arguments.Count; functionPointer.ChildIndex = Arguments.Count;
} }
public CallIndirect(System.Reflection.Metadata.SignatureCallingConvention callingConvention, IType returnType, ImmutableArray<IType> parameterTypes, public CallIndirect(bool isInstance, bool hasExplicitThis, System.Reflection.Metadata.SignatureCallingConvention callingConvention, IType returnType, ImmutableArray<IType> parameterTypes,
IEnumerable<ILInstruction> arguments, ILInstruction functionPointer) : base(OpCode.CallIndirect) IEnumerable<ILInstruction> arguments, ILInstruction functionPointer) : base(OpCode.CallIndirect)
{ {
this.IsInstance = isInstance;
this.HasExplicitThis = hasExplicitThis;
this.CallingConvention = callingConvention; this.CallingConvention = callingConvention;
this.ReturnType = returnType ?? throw new ArgumentNullException("returnType"); this.ReturnType = returnType ?? throw new ArgumentNullException("returnType");
this.ParameterTypes = parameterTypes.ToImmutableArray(); this.ParameterTypes = parameterTypes.ToImmutableArray();
@ -74,7 +77,7 @@ namespace ICSharpCode.Decompiler.IL
public override ILInstruction Clone() public override ILInstruction Clone()
{ {
return new CallIndirect(CallingConvention, ReturnType, ParameterTypes, return new CallIndirect(IsInstance, HasExplicitThis, CallingConvention, ReturnType, ParameterTypes,
this.Arguments.Select(inst => inst.Clone()), functionPointer.Clone() this.Arguments.Select(inst => inst.Clone()), functionPointer.Clone()
).WithILRange(this); ).WithILRange(this);
} }
@ -84,7 +87,7 @@ namespace ICSharpCode.Decompiler.IL
internal override void CheckInvariant(ILPhase phase) internal override void CheckInvariant(ILPhase phase)
{ {
base.CheckInvariant(phase); base.CheckInvariant(phase);
Debug.Assert(Arguments.Count == ParameterTypes.Length); Debug.Assert(Arguments.Count == ParameterTypes.Length + (IsInstance ? 1 : 0));
} }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) public override void WriteTo(ITextOutput output, ILAstWritingOptions options)
@ -94,7 +97,12 @@ namespace ICSharpCode.Decompiler.IL
ReturnType.WriteTo(output); ReturnType.WriteTo(output);
output.Write('('); output.Write('(');
bool first = true; bool first = true;
foreach (var (inst, type) in Arguments.Zip(ParameterTypes, (a,b) => (a,b))) { int firstArgument = IsInstance ? 1 : 0;
if (firstArgument == 1) {
Arguments[0].WriteTo(output, options);
first = false;
}
foreach (var (inst, type) in Arguments.Skip(firstArgument).Zip(ParameterTypes, (a,b) => (a,b))) {
if (first) if (first)
first = false; first = false;
else else
@ -155,6 +163,10 @@ namespace ICSharpCode.Decompiler.IL
bool EqualSignature(CallIndirect other) bool EqualSignature(CallIndirect other)
{ {
if (IsInstance != other.IsInstance)
return false;
if (HasExplicitThis != other.HasExplicitThis)
return false;
if (CallingConvention != other.CallingConvention) if (CallingConvention != other.CallingConvention)
return false; return false;
if (ParameterTypes.Length != other.ParameterTypes.Length) if (ParameterTypes.Length != other.ParameterTypes.Length)

1
ICSharpCode.Decompiler/IL/Instructions/CompoundAssignmentInstruction.cs

@ -97,6 +97,7 @@ namespace ICSharpCode.Decompiler.IL
this.AddILRange(binary); this.AddILRange(binary);
Debug.Assert(compoundAssignmentType == CompoundAssignmentType.EvaluatesToNewValue || (Operator == BinaryNumericOperator.Add || Operator == BinaryNumericOperator.Sub)); Debug.Assert(compoundAssignmentType == CompoundAssignmentType.EvaluatesToNewValue || (Operator == BinaryNumericOperator.Add || Operator == BinaryNumericOperator.Sub));
Debug.Assert(IsValidCompoundAssignmentTarget(Target)); Debug.Assert(IsValidCompoundAssignmentTarget(Target));
Debug.Assert(this.ResultType == (IsLifted ? StackType.O : UnderlyingResultType));
} }
/// <summary> /// <summary>

9
ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs

@ -64,8 +64,13 @@ namespace ICSharpCode.Decompiler.IL.Transforms
protected internal override void VisitBlock(Block block) protected internal override void VisitBlock(Block block)
{ {
// Don't visit child blocks; since this is a block transform if (block.Kind == BlockKind.ControlFlow) {
// we know those were already handled previously. // Don't visit child control flow blocks;
// since this is a block transform
// we know those were already handled previously.
return;
}
base.VisitBlock(block);
} }
protected internal override void VisitComp(Comp inst) protected internal override void VisitComp(Comp inst)

2
ICSharpCode.Decompiler/IL/Transforms/ReduceNestingTransform.cs

@ -216,6 +216,8 @@ namespace ICSharpCode.Decompiler.IL
var defaultSection = switchInst.Sections.MaxBy(s => s.Labels.Count()); var defaultSection = switchInst.Sections.MaxBy(s => s.Labels.Count());
if (!defaultSection.Body.MatchBranch(out var defaultBlock) || defaultBlock.IncomingEdgeCount != 1) if (!defaultSection.Body.MatchBranch(out var defaultBlock) || defaultBlock.IncomingEdgeCount != 1)
return false; return false;
if (defaultBlock.Parent != switchContainer)
return false;
// tally stats for heuristic from each case block // tally stats for heuristic from each case block
int maxStatements = 0, maxDepth = 0; int maxStatements = 0, maxDepth = 0;

12
ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs

@ -478,9 +478,17 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// Try to determine the real type of the object we're modifying: // Try to determine the real type of the object we're modifying:
storeType = stobj.Target.InferType(compilation); storeType = stobj.Target.InferType(compilation);
if (storeType is ByReferenceType refType) { if (storeType is ByReferenceType refType) {
storeType = refType.ElementType; if (TypeUtils.IsCompatibleTypeForMemoryAccess(refType.ElementType, stobj.Type)) {
storeType = refType.ElementType;
} else {
storeType = stobj.Type;
}
} else if (storeType is PointerType pointerType) { } else if (storeType is PointerType pointerType) {
storeType = pointerType.ElementType; if (TypeUtils.IsCompatibleTypeForMemoryAccess(pointerType.ElementType, stobj.Type)) {
storeType = pointerType.ElementType;
} else {
storeType = stobj.Type;
}
} else { } else {
storeType = stobj.Type; storeType = stobj.Type;
} }

8
ICSharpCode.Decompiler/TypeSystem/TypeProvider.cs

@ -141,8 +141,12 @@ namespace ICSharpCode.Decompiler.TypeSystem
if (name == null) { if (name == null) {
return null; return null;
} }
return ReflectionHelper.ParseReflectionName(name) try {
.Resolve(module != null ? new SimpleTypeResolveContext(module) : new SimpleTypeResolveContext(compilation)); return ReflectionHelper.ParseReflectionName(name)
.Resolve(module != null ? new SimpleTypeResolveContext(module) : new SimpleTypeResolveContext(compilation));
} catch (ReflectionNameParseException ex) {
throw new BadImageFormatException($"Invalid type name: \"{name}\": {ex.Message}");
}
} }
public IType GetTypeFromSpecification(SRM.MetadataReader reader, GenericContext genericContext, SRM.TypeSpecificationHandle handle, byte rawTypeKind) public IType GetTypeFromSpecification(SRM.MetadataReader reader, GenericContext genericContext, SRM.TypeSpecificationHandle handle, byte rawTypeKind)

2
ILSpy-tests

@ -1 +1 @@
Subproject commit 28f74a2a8f4050fe455a982dbd361a981841a9bd Subproject commit 4d29b27bd7262790efe52edfcb9c100bb62a0382

1
ILSpy.AddIn/ILSpy.AddIn.csproj

@ -51,6 +51,7 @@
<PackageReference Include="Microsoft.VisualStudio.ComponentModelHost" Version="15.6.27413" /> <PackageReference Include="Microsoft.VisualStudio.ComponentModelHost" Version="15.6.27413" />
<PackageReference Include="Microsoft.VisualStudio.Editor" Version="15.6.27740" /> <PackageReference Include="Microsoft.VisualStudio.Editor" Version="15.6.27740" />
<PackageReference Include="Microsoft.VisualStudio.LanguageServices" Version="2.4.0" /> <PackageReference Include="Microsoft.VisualStudio.LanguageServices" Version="2.4.0" />
<PackageReference Include="Microsoft.VisualStudio.SDK.Analyzers" Version="16.0.29" />
<PackageReference Include="Microsoft.VisualStudio.Shell.15.0" Version="15.6.27413" /> <PackageReference Include="Microsoft.VisualStudio.Shell.15.0" Version="15.6.27413" />
<PackageReference Include="Microsoft.VisualStudio.Shell.Interop.14.0.DesignTime" Version="14.3.26929" /> <PackageReference Include="Microsoft.VisualStudio.Shell.Interop.14.0.DesignTime" Version="14.3.26929" />
<PackageReference Include="Microsoft.VisualStudio.Text.UI" Version="15.6.27740" /> <PackageReference Include="Microsoft.VisualStudio.Text.UI" Version="15.6.27740" />

4
ILSpy/Options/DecompilerSettingsPanel.xaml.cs

@ -54,7 +54,9 @@ namespace ICSharpCode.ILSpy.Options
var properties = typeof(Decompiler.DecompilerSettings).GetProperties() var properties = typeof(Decompiler.DecompilerSettings).GetProperties()
.Where(p => p.GetCustomAttribute<BrowsableAttribute>()?.Browsable != false); .Where(p => p.GetCustomAttribute<BrowsableAttribute>()?.Browsable != false);
foreach (var p in properties) { foreach (var p in properties) {
p.SetValue(newSettings, (bool?)e.Attribute(p.Name) ?? true); var value = (bool?)e.Attribute(p.Name);
if (value.HasValue)
p.SetValue(newSettings, value.Value);
} }
return newSettings; return newSettings;
} }

Loading…
Cancel
Save