diff --git a/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj b/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
index 51d24fc07..51ed72689 100644
--- a/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
+++ b/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
@@ -89,6 +89,7 @@
+
diff --git a/ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs b/ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
index 6c66f55c3..e7786ac67 100644
--- a/ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
+++ b/ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
@@ -425,6 +425,12 @@ namespace ICSharpCode.Decompiler.Tests
RunForLibrary(cscOptions: cscOptions);
}
+ [Test]
+ public void UserDefinedConversions([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions)
+ {
+ RunForLibrary(cscOptions: cscOptions);
+ }
+
[Test]
public void Discards([ValueSource(nameof(roslynOnlyOptions))] CompilerOptions cscOptions)
{
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Correctness/TrickyTypes.cs b/ICSharpCode.Decompiler.Tests/TestCases/Correctness/TrickyTypes.cs
index 83b609b2f..437c37e54 100644
--- a/ICSharpCode.Decompiler.Tests/TestCases/Correctness/TrickyTypes.cs
+++ b/ICSharpCode.Decompiler.Tests/TestCases/Correctness/TrickyTypes.cs
@@ -26,6 +26,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
{
InterestingConstants();
TruncatedComp();
+ StringConcat();
}
static void Print(T val)
@@ -92,5 +93,13 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
Print(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"));
+ }
}
}
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/DelegateConstruction.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/DelegateConstruction.cs
index 1a748024d..3fd129fa1 100644
--- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/DelegateConstruction.cs
+++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/DelegateConstruction.cs
@@ -159,6 +159,17 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
}
+ public static Predicate And(this Predicate filter1, Predicate filter2)
+ {
+ if (filter1 == null) {
+ return filter2;
+ }
+ if (filter2 == null) {
+ return filter1;
+ }
+ return (T m) => filter1(m) && filter2(m);
+ }
+
public static Action ExtensionMethodUnbound()
{
return Test;
@@ -174,6 +185,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
return ((string)null).Test;
}
+ public static Predicate NoExtensionMethodOnLambda()
+ {
+ return And((int x) => x >= 0, (int x) => x <= 100);
+ }
+
public static object StaticMethod()
{
return new Func(ExtensionMethodBound);
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InlineAssignmentTest.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InlineAssignmentTest.cs
index 9620accb5..8ca021f08 100644
--- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InlineAssignmentTest.cs
+++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/InlineAssignmentTest.cs
@@ -32,11 +32,17 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
get;
set;
}
+
public static int StaticProperty {
get;
set;
}
+ public bool BoolProperty {
+ get;
+ set;
+ }
+
public void SimpleInlineWithLocals()
{
int index;
@@ -136,5 +142,10 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
return InstanceProperty = GetIndex();
}
+
+ public bool BoolPropertyTest(object x)
+ {
+ return BoolProperty = (x != null);
+ }
}
}
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/UserDefinedConversions.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/UserDefinedConversions.cs
new file mode 100644
index 000000000..a91ca7a82
--- /dev/null
+++ b/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)
+ {
+ }
+ }
+}
diff --git a/ICSharpCode.Decompiler/CSharp/Annotations.cs b/ICSharpCode.Decompiler/CSharp/Annotations.cs
index 064da15f2..ea813e554 100644
--- a/ICSharpCode.Decompiler/CSharp/Annotations.cs
+++ b/ICSharpCode.Decompiler/CSharp/Annotations.cs
@@ -240,4 +240,18 @@ namespace ICSharpCode.Decompiler.CSharp
this.Leave = leave;
}
}
+
+ ///
+ /// Annotates an expression when an implicit user-defined conversion was omitted.
+ ///
+ public class ImplicitConversionAnnotation
+ {
+ public readonly ConversionResolveResult ConversionResolveResult;
+ public IType TargetType => ConversionResolveResult.Type;
+
+ public ImplicitConversionAnnotation(ConversionResolveResult conversionResolveResult)
+ {
+ this.ConversionResolveResult = conversionResolveResult;
+ }
+ }
}
diff --git a/ICSharpCode.Decompiler/CSharp/CallBuilder.cs b/ICSharpCode.Decompiler/CSharp/CallBuilder.cs
index 7ca971359..c674d8589 100644
--- a/ICSharpCode.Decompiler/CSharp/CallBuilder.cs
+++ b/ICSharpCode.Decompiler/CSharp/CallBuilder.cs
@@ -360,7 +360,7 @@ namespace ICSharpCode.Decompiler.CSharp
// settings.AlwaysCastTargetsOfExplicitInterfaceImplementationCalls == true is used in Windows Forms' InitializeComponent methods.
if (method.IsExplicitInterfaceImplementation && (target.Expression is ThisReferenceExpression || settings.AlwaysCastTargetsOfExplicitInterfaceImplementationCalls)) {
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;
targetExpr = new MemberReferenceExpression(castExpression, methodName);
typeArgumentList = ((MemberReferenceExpression)targetExpr).TypeArguments;
@@ -1008,11 +1008,14 @@ namespace ICSharpCode.Decompiler.CSharp
} else if (method.IsOperator) {
IEnumerable operatorCandidates;
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) {
+ IType lhsType = NullableType.GetUnderlyingType(arguments[0].Type);
+ IType rhsType = NullableType.GetUnderlyingType(arguments[1].Type);
var hashSet = new HashSet();
- hashSet.UnionWith(resolver.GetUserDefinedOperatorCandidates(arguments[0].Type, method.Name));
- hashSet.UnionWith(resolver.GetUserDefinedOperatorCandidates(arguments[1].Type, method.Name));
+ hashSet.UnionWith(resolver.GetUserDefinedOperatorCandidates(lhsType, method.Name));
+ hashSet.UnionWith(resolver.GetUserDefinedOperatorCandidates(rhsType, method.Name));
operatorCandidates = hashSet;
} else {
operatorCandidates = EmptyList.Instance;
diff --git a/ICSharpCode.Decompiler/CSharp/Transforms/IntroduceExtensionMethods.cs b/ICSharpCode.Decompiler/CSharp/Transforms/IntroduceExtensionMethods.cs
index 54d9b6a58..e3bd8d7fc 100644
--- a/ICSharpCode.Decompiler/CSharp/Transforms/IntroduceExtensionMethods.cs
+++ b/ICSharpCode.Decompiler/CSharp/Transforms/IntroduceExtensionMethods.cs
@@ -162,6 +162,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
public static bool CanTransformToExtensionMethodCall(CSharpResolver resolver, IMethod method,
IReadOnlyList 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;
if (rr == null)
return false;
diff --git a/ICSharpCode.Decompiler/CSharp/Transforms/ReplaceMethodCallsWithOperators.cs b/ICSharpCode.Decompiler/CSharp/Transforms/ReplaceMethodCallsWithOperators.cs
index 7aea2a4a8..0486ce871 100644
--- a/ICSharpCode.Decompiler/CSharp/Transforms/ReplaceMethodCallsWithOperators.cs
+++ b/ICSharpCode.Decompiler/CSharp/Transforms/ReplaceMethodCallsWithOperators.cs
@@ -154,16 +154,9 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
if (arguments.Length < 2)
return false;
- bool valid = false;
-
- foreach (var argument in arguments) {
- if (argument is NamedArgumentExpression)
- return false;
- if (argument.GetResolveResult().Type.IsKnownType(KnownTypeCode.String))
- valid = true;
- }
-
- return valid;
+ return !arguments.Any(arg => arg is NamedArgumentExpression) &&
+ (arguments[0].GetResolveResult().Type.IsKnownType(KnownTypeCode.String) ||
+ arguments[1].GetResolveResult().Type.IsKnownType(KnownTypeCode.String));
}
static BinaryOperatorType? GetBinaryOperatorTypeFromMetadataName(string name)
diff --git a/ICSharpCode.Decompiler/CSharp/TranslatedExpression.cs b/ICSharpCode.Decompiler/CSharp/TranslatedExpression.cs
index e0d3dbae6..e270f5563 100644
--- a/ICSharpCode.Decompiler/CSharp/TranslatedExpression.cs
+++ b/ICSharpCode.Decompiler/CSharp/TranslatedExpression.cs
@@ -191,7 +191,11 @@ namespace ICSharpCode.Decompiler.CSharp
conversion.Input.Type,
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
&& oce.Arguments.Count == 1 && expressionBuilder.settings.UseImplicitMethodGroupConversion) {
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) {
return this; // don't attempt to insert cast to '?' or 'void' as these are not valid.
}
+ var convAnnotation = this.Expression.Annotation();
+ 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();
+ 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
&& tupleExpr.Elements.Count == targetTupleType.ElementTypes.Length)
{
@@ -231,8 +247,9 @@ namespace ICSharpCode.Decompiler.CSharp
}
var compilation = expressionBuilder.compilation;
var conversions = Resolver.CSharpConversions.Get(compilation);
- if (ResolveResult is ConversionResolveResult conv && Expression is CastExpression cast2 &&
- CastCanBeMadeImplicit(conversions, conv.Conversion, conv.Input.Type, type, targetType))
+ if (ResolveResult is ConversionResolveResult conv && Expression is CastExpression cast2
+ && !conv.Conversion.IsUserDefined
+ && CastCanBeMadeImplicit(conversions, conv.Conversion, conv.Input.Type, type, targetType))
{
var unwrapped = this.UnwrapChild(cast2.Expression);
if (allowImplicitConversion)
diff --git a/ICSharpCode.Decompiler/IL/ILReader.cs b/ICSharpCode.Decompiler/IL/ILReader.cs
index 2c3c8b654..552f2468d 100644
--- a/ICSharpCode.Decompiler/IL/ILReader.cs
+++ b/ICSharpCode.Decompiler/IL/ILReader.cs
@@ -1401,12 +1401,17 @@ namespace ICSharpCode.Decompiler.IL
var signatureHandle = (StandaloneSignatureHandle)ReadAndDecodeMetadataToken();
var signature = module.DecodeMethodSignature(signatureHandle, genericContext);
var functionPointer = Pop(StackType.I);
- Debug.Assert(!signature.Header.IsInstance);
- var arguments = new ILInstruction[signature.ParameterTypes.Length];
+ int firstArgument = signature.Header.IsInstance ? 1 : 0;
+ var arguments = new ILInstruction[firstArgument + signature.ParameterTypes.Length];
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(
+ signature.Header.IsInstance,
+ signature.Header.HasExplicitThis,
signature.Header.CallingConvention,
signature.ReturnType,
signature.ParameterTypes,
diff --git a/ICSharpCode.Decompiler/IL/InstructionOutputExtensions.cs b/ICSharpCode.Decompiler/IL/InstructionOutputExtensions.cs
index 3e3134d71..d1aab3e59 100644
--- a/ICSharpCode.Decompiler/IL/InstructionOutputExtensions.cs
+++ b/ICSharpCode.Decompiler/IL/InstructionOutputExtensions.cs
@@ -133,14 +133,7 @@ namespace ICSharpCode.Decompiler.IL
case HandleKind.MethodDefinition: {
var md = metadata.GetMethodDefinition((MethodDefinitionHandle)entity);
methodSignature = md.DecodeSignature(new DisassemblerSignatureProvider(module, output), new Metadata.GenericContext((MethodDefinitionHandle)entity, module));
- if (methodSignature.Header.HasExplicitThis) {
- output.Write("instance explicit ");
- } else if (methodSignature.Header.IsInstance) {
- output.Write("instance ");
- }
- if (methodSignature.Header.CallingConvention == SignatureCallingConvention.VarArgs) {
- output.Write("vararg ");
- }
+ WriteSignatureHeader(output, methodSignature);
methodSignature.ReturnType(ILNameSyntax.SignatureNoNamedTypeParameters);
output.Write(' ');
var declaringType = md.GetDeclaringType();
@@ -189,13 +182,7 @@ namespace ICSharpCode.Decompiler.IL
}
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(")");
+ WriteParameterList(output, methodSignature);
break;
}
case HandleKind.MemberReference:
@@ -204,28 +191,13 @@ namespace ICSharpCode.Decompiler.IL
switch (mr.GetKind()) {
case MemberReferenceKind.Method:
methodSignature = mr.DecodeMethodSignature(new DisassemblerSignatureProvider(module, output), genericContext);
- if (methodSignature.Header.HasExplicitThis) {
- output.Write("instance explicit ");
- } else if (methodSignature.Header.IsInstance) {
- output.Write("instance ");
- }
- if (methodSignature.Header.CallingConvention == SignatureCallingConvention.VarArgs) {
- output.Write("vararg ");
- }
+ WriteSignatureHeader(output, methodSignature);
methodSignature.ReturnType(ILNameSyntax.SignatureNoNamedTypeParameters);
output.Write(' ');
WriteParent(output, module, metadata, mr.Parent, genericContext, syntax);
output.Write("::");
output.WriteReference(module, entity, DisassemblerHelpers.Escape(memberName));
- 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(")");
+ WriteParameterList(output, methodSignature);
break;
case MemberReferenceKind.Field:
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 methodName = metadata.GetString(methodDefinition.Name);
methodSignature = methodDefinition.DecodeSignature(new DisassemblerSignatureProvider(module, output), genericContext);
- if (methodSignature.Header.HasExplicitThis) {
- output.Write("instance explicit ");
- } else if (methodSignature.Header.IsInstance) {
- output.Write("instance ");
- }
- if (methodSignature.Header.CallingConvention == SignatureCallingConvention.VarArgs) {
- output.Write("vararg ");
- }
+ WriteSignatureHeader(output, methodSignature);
methodSignature.ReturnType(ILNameSyntax.SignatureNoNamedTypeParameters);
output.Write(' ');
var declaringType = methodDefinition.GetDeclaringType();
@@ -266,52 +231,21 @@ namespace ICSharpCode.Decompiler.IL
} else {
output.Write(DisassemblerHelpers.Escape(methodName));
}
- output.Write('<');
- for (int i = 0; i < substitution.Length; i++) {
- 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(")");
+ WriteTypeParameterList(output, syntax, substitution);
+ WriteParameterList(output, methodSignature);
break;
case HandleKind.MemberReference:
var memberReference = metadata.GetMemberReference((MemberReferenceHandle)ms.Method);
memberName = metadata.GetString(memberReference.Name);
methodSignature = memberReference.DecodeMethodSignature(new DisassemblerSignatureProvider(module, output), genericContext);
- if (methodSignature.Header.HasExplicitThis) {
- output.Write("instance explicit ");
- } else if (methodSignature.Header.IsInstance) {
- output.Write("instance ");
- }
- if (methodSignature.Header.CallingConvention == SignatureCallingConvention.VarArgs) {
- output.Write("vararg ");
- }
+ WriteSignatureHeader(output, methodSignature);
methodSignature.ReturnType(ILNameSyntax.SignatureNoNamedTypeParameters);
output.Write(' ');
WriteParent(output, module, metadata, memberReference.Parent, genericContext, syntax);
output.Write("::");
output.Write(DisassemblerHelpers.Escape(memberName));
- output.Write('<');
- for (int i = 0; i < substitution.Length; i++) {
- 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(")");
+ WriteTypeParameterList(output, syntax, substitution);
+ WriteParameterList(output, methodSignature);
break;
}
break;
@@ -319,15 +253,10 @@ namespace ICSharpCode.Decompiler.IL
var standaloneSig = metadata.GetStandaloneSignature((StandaloneSignatureHandle)entity);
switch (standaloneSig.GetKind()) {
case StandaloneSignatureKind.Method:
- var methodSig = standaloneSig.DecodeMethodSignature(new DisassemblerSignatureProvider(module, output), genericContext);
- methodSig.ReturnType(ILNameSyntax.SignatureNoNamedTypeParameters);
- output.Write('(');
- for (int i = 0; i < methodSig.ParameterTypes.Length; i++) {
- if (i > 0)
- output.Write(", ");
- methodSig.ParameterTypes[i](ILNameSyntax.SignatureNoNamedTypeParameters);
- }
- output.Write(')');
+ methodSignature = standaloneSig.DecodeMethodSignature(new DisassemblerSignatureProvider(module, output), genericContext);
+ WriteSignatureHeader(output, methodSignature);
+ methodSignature.ReturnType(ILNameSyntax.SignatureNoNamedTypeParameters);
+ WriteParameterList(output, methodSignature);
break;
case StandaloneSignatureKind.LocalVariables:
default:
@@ -341,6 +270,56 @@ namespace ICSharpCode.Decompiler.IL
}
}
+ static void WriteTypeParameterList(ITextOutput output, ILNameSyntax syntax, System.Collections.Immutable.ImmutableArray> 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> 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> 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)
{
switch (parentHandle.Kind) {
diff --git a/ICSharpCode.Decompiler/IL/Instructions/CallIndirect.cs b/ICSharpCode.Decompiler/IL/Instructions/CallIndirect.cs
index 07f980fa7..e2b751218 100644
--- a/ICSharpCode.Decompiler/IL/Instructions/CallIndirect.cs
+++ b/ICSharpCode.Decompiler/IL/Instructions/CallIndirect.cs
@@ -32,7 +32,8 @@ namespace ICSharpCode.Decompiler.IL
public readonly InstructionCollection Arguments;
ILInstruction functionPointer;
-
+ public bool IsInstance { get; }
+ public bool HasExplicitThis { get; }
public System.Reflection.Metadata.SignatureCallingConvention CallingConvention { get; }
public IType ReturnType { get; }
public ImmutableArray ParameterTypes { get; }
@@ -61,9 +62,11 @@ namespace ICSharpCode.Decompiler.IL
functionPointer.ChildIndex = Arguments.Count;
}
- public CallIndirect(System.Reflection.Metadata.SignatureCallingConvention callingConvention, IType returnType, ImmutableArray parameterTypes,
+ public CallIndirect(bool isInstance, bool hasExplicitThis, System.Reflection.Metadata.SignatureCallingConvention callingConvention, IType returnType, ImmutableArray parameterTypes,
IEnumerable arguments, ILInstruction functionPointer) : base(OpCode.CallIndirect)
{
+ this.IsInstance = isInstance;
+ this.HasExplicitThis = hasExplicitThis;
this.CallingConvention = callingConvention;
this.ReturnType = returnType ?? throw new ArgumentNullException("returnType");
this.ParameterTypes = parameterTypes.ToImmutableArray();
@@ -74,7 +77,7 @@ namespace ICSharpCode.Decompiler.IL
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()
).WithILRange(this);
}
@@ -84,7 +87,7 @@ namespace ICSharpCode.Decompiler.IL
internal override void CheckInvariant(ILPhase 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)
@@ -94,7 +97,12 @@ namespace ICSharpCode.Decompiler.IL
ReturnType.WriteTo(output);
output.Write('(');
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)
first = false;
else
@@ -155,6 +163,10 @@ namespace ICSharpCode.Decompiler.IL
bool EqualSignature(CallIndirect other)
{
+ if (IsInstance != other.IsInstance)
+ return false;
+ if (HasExplicitThis != other.HasExplicitThis)
+ return false;
if (CallingConvention != other.CallingConvention)
return false;
if (ParameterTypes.Length != other.ParameterTypes.Length)
diff --git a/ICSharpCode.Decompiler/IL/Instructions/CompoundAssignmentInstruction.cs b/ICSharpCode.Decompiler/IL/Instructions/CompoundAssignmentInstruction.cs
index b3d3fe8ce..972be8aa0 100644
--- a/ICSharpCode.Decompiler/IL/Instructions/CompoundAssignmentInstruction.cs
+++ b/ICSharpCode.Decompiler/IL/Instructions/CompoundAssignmentInstruction.cs
@@ -97,6 +97,7 @@ namespace ICSharpCode.Decompiler.IL
this.AddILRange(binary);
Debug.Assert(compoundAssignmentType == CompoundAssignmentType.EvaluatesToNewValue || (Operator == BinaryNumericOperator.Add || Operator == BinaryNumericOperator.Sub));
Debug.Assert(IsValidCompoundAssignmentTarget(Target));
+ Debug.Assert(this.ResultType == (IsLifted ? StackType.O : UnderlyingResultType));
}
///
diff --git a/ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs b/ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs
index 08c0a965c..93575cae4 100644
--- a/ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs
+++ b/ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs
@@ -64,8 +64,13 @@ namespace ICSharpCode.Decompiler.IL.Transforms
protected internal override void VisitBlock(Block block)
{
- // Don't visit child blocks; since this is a block transform
- // we know those were already handled previously.
+ if (block.Kind == BlockKind.ControlFlow) {
+ // 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)
diff --git a/ICSharpCode.Decompiler/IL/Transforms/ReduceNestingTransform.cs b/ICSharpCode.Decompiler/IL/Transforms/ReduceNestingTransform.cs
index 03e3297f3..cdd1822a0 100644
--- a/ICSharpCode.Decompiler/IL/Transforms/ReduceNestingTransform.cs
+++ b/ICSharpCode.Decompiler/IL/Transforms/ReduceNestingTransform.cs
@@ -216,6 +216,8 @@ namespace ICSharpCode.Decompiler.IL
var defaultSection = switchInst.Sections.MaxBy(s => s.Labels.Count());
if (!defaultSection.Body.MatchBranch(out var defaultBlock) || defaultBlock.IncomingEdgeCount != 1)
return false;
+ if (defaultBlock.Parent != switchContainer)
+ return false;
// tally stats for heuristic from each case block
int maxStatements = 0, maxDepth = 0;
diff --git a/ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs b/ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs
index 1f337c420..f7a6bee67 100644
--- a/ICSharpCode.Decompiler/IL/Transforms/TransformAssignment.cs
+++ b/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:
storeType = stobj.Target.InferType(compilation);
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) {
- storeType = pointerType.ElementType;
+ if (TypeUtils.IsCompatibleTypeForMemoryAccess(pointerType.ElementType, stobj.Type)) {
+ storeType = pointerType.ElementType;
+ } else {
+ storeType = stobj.Type;
+ }
} else {
storeType = stobj.Type;
}
diff --git a/ICSharpCode.Decompiler/TypeSystem/TypeProvider.cs b/ICSharpCode.Decompiler/TypeSystem/TypeProvider.cs
index ccf21ac9c..0ab8f4faa 100644
--- a/ICSharpCode.Decompiler/TypeSystem/TypeProvider.cs
+++ b/ICSharpCode.Decompiler/TypeSystem/TypeProvider.cs
@@ -141,8 +141,12 @@ namespace ICSharpCode.Decompiler.TypeSystem
if (name == null) {
return null;
}
- return ReflectionHelper.ParseReflectionName(name)
- .Resolve(module != null ? new SimpleTypeResolveContext(module) : new SimpleTypeResolveContext(compilation));
+ try {
+ 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)
diff --git a/ILSpy-tests b/ILSpy-tests
index 28f74a2a8..4d29b27bd 160000
--- a/ILSpy-tests
+++ b/ILSpy-tests
@@ -1 +1 @@
-Subproject commit 28f74a2a8f4050fe455a982dbd361a981841a9bd
+Subproject commit 4d29b27bd7262790efe52edfcb9c100bb62a0382
diff --git a/ILSpy.AddIn/ILSpy.AddIn.csproj b/ILSpy.AddIn/ILSpy.AddIn.csproj
index e61b4e2a5..1126fcf82 100644
--- a/ILSpy.AddIn/ILSpy.AddIn.csproj
+++ b/ILSpy.AddIn/ILSpy.AddIn.csproj
@@ -51,6 +51,7 @@
+
diff --git a/ILSpy/Options/DecompilerSettingsPanel.xaml.cs b/ILSpy/Options/DecompilerSettingsPanel.xaml.cs
index c1c734173..134f9faf0 100644
--- a/ILSpy/Options/DecompilerSettingsPanel.xaml.cs
+++ b/ILSpy/Options/DecompilerSettingsPanel.xaml.cs
@@ -54,7 +54,9 @@ namespace ICSharpCode.ILSpy.Options
var properties = typeof(Decompiler.DecompilerSettings).GetProperties()
.Where(p => p.GetCustomAttribute()?.Browsable != false);
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;
}