Browse Source

Merge pull request #1596 from icsharpcode/ref

Improved decompilation of ref typed expressions
pull/1612/head
Siegfried Pammer 6 years ago committed by GitHub
parent
commit
1b404e9a5c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      ICSharpCode.Decompiler.Tests/CorrectnessTestRunner.cs
  2. 1
      ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
  3. 79
      ICSharpCode.Decompiler.Tests/TestCases/Correctness/RefLocalsAndReturns.cs
  4. 28
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/DynamicTests.cs
  5. 11
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/QualifierTests.cs
  6. 135
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/RefLocalsAndReturns.cs
  7. 40
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/TupleTests.cs
  8. 45
      ICSharpCode.Decompiler.Tests/TypeSystem/TypeSystemLoaderTests.cs
  9. 4
      ICSharpCode.Decompiler/CSharp/CallBuilder.cs
  10. 32
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  11. 11
      ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs
  12. 2
      ICSharpCode.Decompiler/CSharp/OutputVisitor/InsertParenthesesVisitor.cs
  13. 16
      ICSharpCode.Decompiler/CSharp/Resolver/CSharpConversions.cs
  14. 2
      ICSharpCode.Decompiler/CSharp/Resolver/CSharpResolver.cs
  15. 4
      ICSharpCode.Decompiler/CSharp/Resolver/OverloadResolution.cs
  16. 12
      ICSharpCode.Decompiler/CSharp/Resolver/TypeInference.cs
  17. 2
      ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/MethodDeclaration.cs
  18. 31
      ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/ParameterDeclaration.cs
  19. 4
      ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs
  20. 8
      ICSharpCode.Decompiler/CSharp/Transforms/IntroduceExtensionMethods.cs
  21. 6
      ICSharpCode.Decompiler/CSharp/TranslatedExpression.cs
  22. 20
      ICSharpCode.Decompiler/DecompilerSettings.cs
  23. 20
      ICSharpCode.Decompiler/Semantics/ByReferenceResolveResult.cs
  24. 2
      ICSharpCode.Decompiler/Semantics/LocalResolveResult.cs
  25. 16
      ICSharpCode.Decompiler/TypeSystem/IParameter.cs
  26. 40
      ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultParameter.cs
  27. 4
      ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataMethod.cs
  28. 15
      ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataParameter.cs
  29. 1
      ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedParameter.cs
  30. 6
      ICSharpCode.Decompiler/TypeSystem/ParameterListComparer.cs
  31. 9
      ILSpy/Properties/Resources.Designer.cs
  32. 3
      ILSpy/Properties/Resources.resx

6
ICSharpCode.Decompiler.Tests/CorrectnessTestRunner.cs

@ -196,12 +196,6 @@ namespace ICSharpCode.Decompiler.Tests @@ -196,12 +196,6 @@ namespace ICSharpCode.Decompiler.Tests
RunCS(options: options);
}
[Test]
public void RefLocalsAndReturns([ValueSource("roslynOnlyOptions")] CompilerOptions options)
{
RunCS(options: options);
}
[Test]
public void BitNot([Values(false, true)] bool force32Bit)
{

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

@ -88,7 +88,6 @@ @@ -88,7 +88,6 @@
<Compile Include="Semantics\OverloadResolutionTests.cs" />
<Compile Include="DataFlowTest.cs" />
<Compile Include="TestCases\Pretty\LocalFunctions.cs" />
<Compile Include="TestCases\Correctness\RefLocalsAndReturns.cs" />
<Compile Include="TestCases\ILPretty\Issue1256.cs" />
<Compile Include="TestCases\ILPretty\Issue1323.cs" />
<Compile Include="TestCases\Pretty\CustomAttributes2.cs" />

79
ICSharpCode.Decompiler.Tests/TestCases/Correctness/RefLocalsAndReturns.cs

@ -1,79 +0,0 @@ @@ -1,79 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
{
class RefLocalsAndReturns
{
static int[] numbers = { 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023 };
static string[] strings = { "Hello", "World" };
static string NullString = "";
static int DefaultInt = 0;
public delegate ref TReturn RefFunc<T1, TReturn>(T1 param1);
public static TReturn Invoker<T1, TReturn>(RefFunc<T1, TReturn> action, T1 value)
{
return action(value);
}
public static ref int FindNumber(int target)
{
for (int ctr = 0; ctr < numbers.Length; ctr++) {
if (numbers[ctr] >= target)
return ref numbers[ctr];
}
return ref numbers[0];
}
public static ref int LastNumber()
{
return ref numbers[numbers.Length - 1];
}
public static ref int ElementAtOrDefault(int index)
{
return ref index < 0 || index >= numbers.Length ? ref DefaultInt : ref numbers[index];
}
public static ref int LastOrDefault()
{
return ref numbers.Length > 0 ? ref numbers[numbers.Length - 1] : ref DefaultInt;
}
public static void DoubleNumber(ref int num)
{
Console.WriteLine("old: " + num);
num *= 2;
Console.WriteLine("new: " + num);
}
public static ref string GetOrSetString(int index)
{
if (index < 0 || index >= strings.Length)
return ref NullString;
return ref strings[index];
}
public static void Main(string[] args)
{
DoubleNumber(ref FindNumber(32));
Console.WriteLine(string.Join(", ", numbers));
DoubleNumber(ref LastNumber());
Console.WriteLine(string.Join(", ", numbers));
Console.WriteLine(GetOrSetString(0));
GetOrSetString(0) = "Goodbye";
Console.WriteLine(string.Join(" ", strings));
GetOrSetString(5) = "Here I mutated the null value!?";
Console.WriteLine(GetOrSetString(-5));
Console.WriteLine(Invoker(x => ref numbers[x], 0));
Console.WriteLine(LastOrDefault());
LastOrDefault() = 10000;
Console.WriteLine(ElementAtOrDefault(-5));
}
}
}

28
ICSharpCode.Decompiler.Tests/TestCases/Pretty/DynamicTests.cs

@ -64,6 +64,34 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -64,6 +64,34 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
}
private static void CallWithOut(out dynamic d)
{
d = null;
}
#if CS70
private static void CallWithIn(in dynamic d)
{
}
#endif
private static void CallWithRef(ref dynamic d)
{
}
private static void RefCallSiteTests()
{
#if CS70
CallWithOut(out dynamic d);
CallWithIn(in d);
#else
dynamic d;
CallWithOut(out d);
#endif
CallWithRef(ref d);
d.SomeCall();
}
private static void InvokeConstructor()
{
DynamicTests dynamicTests = new DynamicTests();

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

@ -221,12 +221,21 @@ namespace ICSharpCode.Decompiler.Tests.Pretty @@ -221,12 +221,21 @@ namespace ICSharpCode.Decompiler.Tests.Pretty
{
}
#if CS72
public static void Do(this ref DateTime test)
{
}
#endif
public static void Do2(this int test)
public static void Do2(this int test, DateTime date)
{
test.Do();
((IEnumerable<int>)null).Any();
((object)null).Do();
#if CS72
date.Do();
#endif
}
}
}

135
ICSharpCode.Decompiler.Tests/TestCases/Pretty/RefLocalsAndReturns.cs

@ -2,10 +2,33 @@ @@ -2,10 +2,33 @@
namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
internal static class Ext
{
public static void ExtOnRef(this ref RefLocalsAndReturns.NormalStruct s)
{
}
public static void ExtOnIn(this in RefLocalsAndReturns.NormalStruct s)
{
}
public static void ExtOnRef(this ref RefLocalsAndReturns.ReadOnlyStruct s)
{
}
public static void ExtOnIn(this in RefLocalsAndReturns.ReadOnlyStruct s)
{
}
public static void ExtOnRef(this ref RefLocalsAndReturns.ReadOnlyRefStruct s)
{
}
public static void ExtOnIn(this in RefLocalsAndReturns.ReadOnlyRefStruct s)
{
}
}
internal class RefLocalsAndReturns
{
public delegate ref T RefFunc<T>();
public delegate ref readonly T ReadOnlyRefFunc<T>();
public delegate ref TReturn RefFunc<T1, TReturn>(T1 param1);
public ref struct RefStruct
{
@ -35,6 +58,28 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -35,6 +58,28 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
}
}
private static int[] numbers = new int[10] {
1,
3,
7,
15,
31,
63,
127,
255,
511,
1023
};
private static string[] strings = new string[2] {
"Hello",
"World"
};
private static string NullString = "";
private static int DefaultInt = 0;
public static ref T GetRef<T>()
{
throw new NotImplementedException();
@ -80,5 +125,95 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -80,5 +125,95 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
ReadOnlyStruct readOnlyStruct = rs;
readOnlyStruct.Method();
}
public static TReturn Invoker<T1, TReturn>(RefFunc<T1, TReturn> action, T1 value)
{
return action(value);
}
public static ref int FindNumber(int target)
{
for (int i = 0; i < numbers.Length; i++) {
if (numbers[i] >= target) {
return ref numbers[i];
}
}
return ref numbers[0];
}
public static ref int LastNumber()
{
return ref numbers[numbers.Length - 1];
}
public static ref int ElementAtOrDefault(int index)
{
if (index >= 0 && index < numbers.Length) {
return ref numbers[index];
}
return ref DefaultInt;
}
public static ref int LastOrDefault()
{
if (numbers.Length != 0) {
return ref numbers[numbers.Length - 1];
}
return ref DefaultInt;
}
public static void DoubleNumber(ref int num)
{
Console.WriteLine("old: " + num);
num *= 2;
Console.WriteLine("new: " + num);
}
public static ref string GetOrSetString(int index)
{
if (index < 0 || index >= strings.Length) {
return ref NullString;
}
return ref strings[index];
}
public void CallSiteTests(NormalStruct s, ReadOnlyStruct r, ReadOnlyRefStruct rr)
{
s.ExtOnIn();
s.ExtOnRef();
r.ExtOnIn();
r.ExtOnRef();
rr.ExtOnIn();
rr.ExtOnRef();
CallOnInParam(in s, in r);
}
public void RefReassignment(ref NormalStruct s)
{
ref NormalStruct @ref = ref GetRef<NormalStruct>();
RefReassignment(ref @ref);
@ref = ref GetRef<NormalStruct>();
RefReassignment(ref @ref.GetHashCode() == 4 ? ref @ref : ref s);
}
public static void Main(string[] args)
{
DoubleNumber(ref args.Length == 1 ? ref numbers[0] : ref DefaultInt);
DoubleNumber(ref FindNumber(32));
Console.WriteLine(string.Join(", ", numbers));
DoubleNumber(ref LastNumber());
Console.WriteLine(string.Join(", ", numbers));
Console.WriteLine(GetOrSetString(0));
GetOrSetString(0) = "Goodbye";
Console.WriteLine(string.Join(" ", strings));
GetOrSetString(5) = "Here I mutated the null value!?";
Console.WriteLine(GetOrSetString(-5));
Console.WriteLine(Invoker((int x) => ref numbers[x], 0));
Console.WriteLine(LastOrDefault());
LastOrDefault() = 10000;
Console.WriteLine(ElementAtOrDefault(-5));
}
}
}

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

@ -97,6 +97,36 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -97,6 +97,36 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
public object NotTargetTyping => ((string)null, (object)1, (Action)delegate {
});
public void UnnamedTupleOut(out (int, string, Action, dynamic) tuple)
{
tuple = (42, "Hello", Console.WriteLine, null);
}
public void UnnamedTupleIn(in (int, string, Action, dynamic) tuple)
{
}
public void UnnamedTupleRef(ref (int, string, Action, dynamic) tuple)
{
}
public void NamedTupleOut(out (int A, string B, Action C, dynamic D) tuple)
{
tuple = (42, "Hello", Console.WriteLine, null);
}
public void NamedTupleIn(in (int A, string B, Action C, dynamic D) tuple)
{
}
public void NamedTupleRef(ref (int A, string B, Action C, dynamic D) tuple)
{
}
public void UseDict()
{
if (TupleDict.Count > 10) {
@ -160,5 +190,15 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -160,5 +190,15 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
Console.WriteLine(s.Field.A + s.Property.B);
}
public void RefCallSites(out (int, string, Action, dynamic) tuple)
{
UnnamedTupleOut(out tuple);
UnnamedTupleIn(in tuple);
UnnamedTupleRef(ref tuple);
NamedTupleOut(out tuple);
NamedTupleIn(in tuple);
NamedTupleRef(ref tuple);
}
}
}

45
ICSharpCode.Decompiler.Tests/TypeSystem/TypeSystemLoaderTests.cs

@ -707,8 +707,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem @@ -707,8 +707,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem
public void InOutParametersOnRefMethod()
{
IParameter p = GetTypeDefinition(typeof(NonCustomAttributes)).Methods.Single(m => m.Name == "DllMethod").Parameters.Single();
Assert.IsTrue(p.IsRef);
Assert.IsFalse(p.IsOut);
Assert.AreEqual(ReferenceKind.Ref, p.ReferenceKind);
var attr = p.GetAttributes().ToList();
Assert.AreEqual(2, attr.Count);
Assert.AreEqual("System.Runtime.InteropServices.InAttribute", attr[0].AttributeType.FullName);
@ -728,9 +727,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem @@ -728,9 +727,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem
{
IParameter p = GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithOutParameter").Parameters.Single();
Assert.IsFalse(p.IsOptional);
Assert.IsFalse(p.IsRef);
Assert.IsTrue(p.IsOut);
Assert.IsFalse(p.IsIn);
Assert.AreEqual(ReferenceKind.Out, p.ReferenceKind);
Assert.AreEqual(0, p.GetAttributes().Count());
Assert.IsTrue(p.Type.Kind == TypeKind.ByReference);
}
@ -740,9 +737,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem @@ -740,9 +737,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem
{
IParameter p = GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithRefParameter").Parameters.Single();
Assert.IsFalse(p.IsOptional);
Assert.IsTrue(p.IsRef);
Assert.IsFalse(p.IsOut);
Assert.IsFalse(p.IsIn);
Assert.AreEqual(ReferenceKind.Ref, p.ReferenceKind);
Assert.AreEqual(0, p.GetAttributes().Count());
Assert.IsTrue(p.Type.Kind == TypeKind.ByReference);
}
@ -752,9 +747,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem @@ -752,9 +747,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem
{
IParameter p = GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithInParameter").Parameters.Single();
Assert.IsFalse(p.IsOptional);
Assert.IsFalse(p.IsRef);
Assert.IsFalse(p.IsOut);
Assert.IsTrue(p.IsIn);
Assert.AreEqual(ReferenceKind.In, p.ReferenceKind);
Assert.AreEqual(0, p.GetAttributes().Count());
Assert.IsTrue(p.Type.Kind == TypeKind.ByReference);
}
@ -764,8 +757,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem @@ -764,8 +757,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem
{
IParameter p = GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithParamsArray").Parameters.Single();
Assert.IsFalse(p.IsOptional);
Assert.IsFalse(p.IsRef);
Assert.IsFalse(p.IsOut);
Assert.AreEqual(ReferenceKind.None, p.ReferenceKind);
Assert.IsTrue(p.IsParams);
Assert.AreEqual(0, p.GetAttributes().Count());
Assert.IsTrue(p.Type.Kind == TypeKind.Array);
@ -776,8 +768,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem @@ -776,8 +768,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem
{
IParameter p = GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithOptionalParameter").Parameters.Single();
Assert.IsTrue(p.IsOptional);
Assert.IsFalse(p.IsRef);
Assert.IsFalse(p.IsOut);
Assert.AreEqual(ReferenceKind.None, p.ReferenceKind);
Assert.IsFalse(p.IsParams);
Assert.IsTrue(p.HasConstantValueInSignature);
Assert.AreEqual(0, p.GetAttributes().Count());
@ -789,8 +780,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem @@ -789,8 +780,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem
{
IParameter p = GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithExplicitOptionalParameter").Parameters.Single();
Assert.IsTrue(p.IsOptional);
Assert.IsFalse(p.IsRef);
Assert.IsFalse(p.IsOut);
Assert.AreEqual(ReferenceKind.None, p.ReferenceKind);
Assert.IsFalse(p.IsParams);
Assert.IsFalse(p.HasConstantValueInSignature);
// explicit optional parameter appears in type system if it's read from C#, but not when read from IL
@ -802,8 +792,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem @@ -802,8 +792,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem
{
IParameter p = GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithEnumOptionalParameter").Parameters.Single();
Assert.IsTrue(p.IsOptional);
Assert.IsFalse(p.IsRef);
Assert.IsFalse(p.IsOut);
Assert.AreEqual(ReferenceKind.None, p.ReferenceKind);
Assert.IsFalse(p.IsParams);
Assert.IsTrue(p.HasConstantValueInSignature);
Assert.AreEqual(0, p.GetAttributes().Count());
@ -815,8 +804,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem @@ -815,8 +804,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem
{
IParameter p = GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithOptionalNullableParameter").Parameters.Single();
Assert.IsTrue(p.IsOptional);
Assert.IsFalse(p.IsRef);
Assert.IsFalse(p.IsOut);
Assert.AreEqual(ReferenceKind.None, p.ReferenceKind);
Assert.IsFalse(p.IsParams);
Assert.IsTrue(p.HasConstantValueInSignature);
Assert.AreEqual(0, p.GetAttributes().Count());
@ -828,8 +816,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem @@ -828,8 +816,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem
{
IParameter p = GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithOptionalLongParameter").Parameters.Single();
Assert.IsTrue(p.IsOptional);
Assert.IsFalse(p.IsRef);
Assert.IsFalse(p.IsOut);
Assert.AreEqual(ReferenceKind.None, p.ReferenceKind);
Assert.IsFalse(p.IsParams);
Assert.IsTrue(p.HasConstantValueInSignature);
Assert.AreEqual(1L, p.GetConstantValue());
@ -841,8 +828,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem @@ -841,8 +828,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem
{
IParameter p = GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithOptionalNullableLongParameter").Parameters.Single();
Assert.IsTrue(p.IsOptional);
Assert.IsFalse(p.IsRef);
Assert.IsFalse(p.IsOut);
Assert.AreEqual(ReferenceKind.None, p.ReferenceKind);
Assert.IsFalse(p.IsParams);
Assert.IsTrue(p.HasConstantValueInSignature);
Assert.AreEqual(1L, p.GetConstantValue());
@ -854,8 +840,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem @@ -854,8 +840,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem
{
IParameter p = GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithOptionalDecimalParameter").Parameters.Single();
Assert.IsTrue(p.IsOptional);
Assert.IsFalse(p.IsRef);
Assert.IsFalse(p.IsOut);
Assert.AreEqual(ReferenceKind.None, p.ReferenceKind);
Assert.IsFalse(p.IsParams);
Assert.IsTrue(p.HasConstantValueInSignature);
Assert.AreEqual(1M, p.GetConstantValue());
@ -867,8 +852,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem @@ -867,8 +852,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem
{
IParameter p = GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "VarArgsMethod").Parameters.Single();
Assert.IsFalse(p.IsOptional);
Assert.IsFalse(p.IsRef);
Assert.IsFalse(p.IsOut);
Assert.AreEqual(ReferenceKind.None, p.ReferenceKind);
Assert.IsFalse(p.IsParams);
Assert.AreEqual(TypeKind.ArgList, p.Type.Kind);
Assert.AreEqual("", p.Name);
@ -879,8 +863,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem @@ -879,8 +863,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem
{
IParameter p = GetTypeDefinition(typeof(VarArgsCtor)).Methods.Single(m => m.IsConstructor).Parameters.Single();
Assert.IsFalse(p.IsOptional);
Assert.IsFalse(p.IsRef);
Assert.IsFalse(p.IsOut);
Assert.AreEqual(ReferenceKind.None, p.ReferenceKind);
Assert.IsFalse(p.IsParams);
Assert.AreEqual(TypeKind.ArgList, p.Type.Kind);
Assert.AreEqual("", p.Name);

4
ICSharpCode.Decompiler/CSharp/CallBuilder.cs

@ -652,8 +652,8 @@ namespace ICSharpCode.Decompiler.CSharp @@ -652,8 +652,8 @@ namespace ICSharpCode.Decompiler.CSharp
arg = arg.ConvertTo(parameterType, expressionBuilder, allowImplicitConversion: arg.Type.Kind != TypeKind.Dynamic);
if (parameter.IsOut) {
arg = ExpressionBuilder.ChangeDirectionExpressionToOut(arg);
if (parameter.ReferenceKind != ReferenceKind.None) {
arg = ExpressionBuilder.ChangeDirectionExpressionTo(arg, parameter.ReferenceKind);
}
arguments.Add(arg);

32
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -181,7 +181,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -181,7 +181,7 @@ namespace ICSharpCode.Decompiler.CSharp
expr.WithRR(new ILVariableResolveResult(variable, elementType));
expr = new DirectionExpression(FieldDirection.Ref, expr);
return expr.WithRR(new ByReferenceResolveResult(elementType, isOut: false));
return expr.WithRR(new ByReferenceResolveResult(elementType, ReferenceKind.Ref));
} else {
return expr.WithRR(new ILVariableResolveResult(variable, variable.Type));
}
@ -608,7 +608,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -608,7 +608,7 @@ namespace ICSharpCode.Decompiler.CSharp
// because the DirectionExpression might get removed by dereferencing instructions such as LdObj
return new DirectionExpression(FieldDirection.Ref, expr.Expression)
.WithoutILInstruction()
.WithRR(new ByReferenceResolveResult(expr.ResolveResult, isOut: false));
.WithRR(new ByReferenceResolveResult(expr.ResolveResult, ReferenceKind.Ref));
}
protected internal override TranslatedExpression VisitStLoc(StLoc inst, TranslationContext context)
@ -1088,7 +1088,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1088,7 +1088,7 @@ namespace ICSharpCode.Decompiler.CSharp
.WithILInstruction(inst)
.WithRR(new ResolveResult(elementType));
return new DirectionExpression(FieldDirection.Ref, expr)
.WithoutILInstruction().WithRR(new ByReferenceResolveResult(expr.Type, isOut: false));
.WithoutILInstruction().WithRR(new ByReferenceResolveResult(expr.Type, ReferenceKind.Ref));
}
return CallUnsafeIntrinsic(name, new[] { left.Expression, Translate(offsetInst).Expression }, brt, inst);
} else {
@ -1760,7 +1760,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1760,7 +1760,7 @@ namespace ICSharpCode.Decompiler.CSharp
if (type.Kind == TypeKind.ByReference) {
return new DirectionExpression(FieldDirection.Ref, expr.Expression)
.WithoutILInstruction()
.WithRR(new ByReferenceResolveResult(expr.ResolveResult, isOut: false));
.WithRR(new ByReferenceResolveResult(expr.ResolveResult, ReferenceKind.Ref));
}
return expr;
}
@ -2113,7 +2113,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -2113,7 +2113,7 @@ namespace ICSharpCode.Decompiler.CSharp
} else {
// ldflda producing managed pointer
return new DirectionExpression(FieldDirection.Ref, expr)
.WithoutILInstruction().WithRR(new ByReferenceResolveResult(expr.ResolveResult, isOut: false));
.WithoutILInstruction().WithRR(new ByReferenceResolveResult(expr.ResolveResult, ReferenceKind.Ref));
}
}
@ -2121,7 +2121,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -2121,7 +2121,7 @@ namespace ICSharpCode.Decompiler.CSharp
{
var expr = ConvertField(inst.Field).WithILInstruction(inst);
return new DirectionExpression(FieldDirection.Ref, expr)
.WithoutILInstruction().WithRR(new ByReferenceResolveResult(expr.Type, isOut: false));
.WithoutILInstruction().WithRR(new ByReferenceResolveResult(expr.Type, ReferenceKind.Ref));
}
protected internal override TranslatedExpression VisitLdElema(LdElema inst, TranslationContext context)
@ -2136,7 +2136,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -2136,7 +2136,7 @@ namespace ICSharpCode.Decompiler.CSharp
arrayExpr, inst.Indices.Select(i => TranslateArrayIndex(i).Expression)
).WithILInstruction(inst).WithRR(new ResolveResult(arrayType.ElementType));
return new DirectionExpression(FieldDirection.Ref, expr)
.WithoutILInstruction().WithRR(new ByReferenceResolveResult(expr.Type, isOut: false));
.WithoutILInstruction().WithRR(new ByReferenceResolveResult(expr.Type, ReferenceKind.Ref));
}
TranslatedExpression TranslateArrayIndex(ILInstruction i)
@ -2194,7 +2194,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -2194,7 +2194,7 @@ namespace ICSharpCode.Decompiler.CSharp
.WithRR(new ConversionResolveResult(inst.Type, arg.ResolveResult, Conversion.UnboxingConversion));
return new DirectionExpression(FieldDirection.Ref, castExpression)
.WithILInstruction(inst)
.WithRR(new ByReferenceResolveResult(castExpression.ResolveResult, isOut: false));
.WithRR(new ByReferenceResolveResult(castExpression.ResolveResult, ReferenceKind.Ref));
}
protected internal override TranslatedExpression VisitBox(Box inst, TranslationContext context)
@ -2254,7 +2254,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -2254,7 +2254,7 @@ namespace ICSharpCode.Decompiler.CSharp
Arguments = { Translate(inst.Argument).Expression, new TypeReferenceExpression(ConvertType(inst.Type)) }
}.WithRR(new ResolveResult(inst.Type));
return new DirectionExpression(FieldDirection.Ref, expr.WithILInstruction(inst)).WithoutILInstruction()
.WithRR(new ByReferenceResolveResult(inst.Type, false));
.WithRR(new ByReferenceResolveResult(inst.Type, ReferenceKind.Ref));
}
protected internal override TranslatedExpression VisitBlock(Block block, TranslationContext context)
@ -2738,7 +2738,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -2738,7 +2738,7 @@ namespace ICSharpCode.Decompiler.CSharp
new ConditionalExpression(condition.Expression, trueBranch.Expression, falseBranch.Expression)
.WithILInstruction(inst)
.WithRR(conditionalResolveResult)
).WithoutILInstruction().WithRR(new ByReferenceResolveResult(conditionalResolveResult, isOut: false));
).WithoutILInstruction().WithRR(new ByReferenceResolveResult(conditionalResolveResult, ReferenceKind.Ref));
} else {
return new ConditionalExpression(condition.Expression, trueBranch.Expression, falseBranch.Expression)
.WithILInstruction(inst)
@ -2758,7 +2758,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -2758,7 +2758,7 @@ namespace ICSharpCode.Decompiler.CSharp
var value = Translate(inst.Value, targetTypeHint);
return new DirectionExpression(FieldDirection.Ref, value)
.WithILInstruction(inst)
.WithRR(new ByReferenceResolveResult(value.ResolveResult, false));
.WithRR(new ByReferenceResolveResult(value.ResolveResult, ReferenceKind.Ref));
}
protected internal override TranslatedExpression VisitAwait(Await inst, TranslationContext context)
@ -2913,7 +2913,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -2913,7 +2913,7 @@ namespace ICSharpCode.Decompiler.CSharp
translatedExpression = translatedExpression.ConvertTo(typeHint, this);
}
if (info.HasFlag(CSharpArgumentInfoFlags.IsOut)) {
translatedExpression = ChangeDirectionExpressionToOut(translatedExpression);
translatedExpression = ChangeDirectionExpressionTo(translatedExpression, ReferenceKind.Out);
}
if (info.HasFlag(CSharpArgumentInfoFlags.NamedArgument) && !string.IsNullOrWhiteSpace(info.Name)) {
translatedExpression = new TranslatedExpression(new NamedArgumentExpression(info.Name, translatedExpression.Expression));
@ -2922,16 +2922,16 @@ namespace ICSharpCode.Decompiler.CSharp @@ -2922,16 +2922,16 @@ namespace ICSharpCode.Decompiler.CSharp
return translatedExpression;
}
internal static TranslatedExpression ChangeDirectionExpressionToOut(TranslatedExpression input)
internal static TranslatedExpression ChangeDirectionExpressionTo(TranslatedExpression input, ReferenceKind kind)
{
if (!(input.Expression is DirectionExpression dirExpr && input.ResolveResult is ByReferenceResolveResult brrr))
return input;
dirExpr.FieldDirection = FieldDirection.Out;
dirExpr.FieldDirection = (FieldDirection)kind;
dirExpr.RemoveAnnotations<ByReferenceResolveResult>();
if (brrr.ElementResult == null)
brrr = new ByReferenceResolveResult(brrr.ElementType, isOut: true);
brrr = new ByReferenceResolveResult(brrr.ElementType, kind);
else
brrr = new ByReferenceResolveResult(brrr.ElementResult, isOut: true);
brrr = new ByReferenceResolveResult(brrr.ElementResult, kind);
dirExpr.AddAnnotation(brrr);
return new TranslatedExpression(dirExpr);
}

11
ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs

@ -2192,21 +2192,26 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -2192,21 +2192,26 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
{
StartNode(parameterDeclaration);
WriteAttributes(parameterDeclaration.Attributes);
if (parameterDeclaration.HasThisModifier) {
WriteKeyword(ParameterDeclaration.ThisModifierRole);
Space();
}
switch (parameterDeclaration.ParameterModifier) {
case ParameterModifier.Ref:
WriteKeyword(ParameterDeclaration.RefModifierRole);
Space();
break;
case ParameterModifier.Out:
WriteKeyword(ParameterDeclaration.OutModifierRole);
Space();
break;
case ParameterModifier.Params:
WriteKeyword(ParameterDeclaration.ParamsModifierRole);
break;
case ParameterModifier.This:
WriteKeyword(ParameterDeclaration.ThisModifierRole);
Space();
break;
case ParameterModifier.In:
WriteKeyword(ParameterDeclaration.InModifierRole);
Space();
break;
}
parameterDeclaration.Type.AcceptVisitor(this);

2
ICSharpCode.Decompiler/CSharp/OutputVisitor/InsertParenthesesVisitor.cs

@ -362,7 +362,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -362,7 +362,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
{
// assignment is right-associative
ParenthesizeIfRequired(assignmentExpression.Left, Assignment + 1);
if (InsertParenthesesForReadability) {
if (InsertParenthesesForReadability && !(assignmentExpression.Right is DirectionExpression)) {
ParenthesizeIfRequired(assignmentExpression.Right, RelationalAndTypeTesting + 1);
} else {
ParenthesizeIfRequired(assignmentExpression.Right, Assignment);

16
ICSharpCode.Decompiler/CSharp/Resolver/CSharpConversions.cs

@ -1018,7 +1018,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -1018,7 +1018,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
if (f.IsImplicitlyTyped) {
// If F has an implicitly typed parameter list, D has no ref or out parameters.
foreach (IParameter p in d.Parameters) {
if (p.IsOut || p.IsRef)
if (p.ReferenceKind != ReferenceKind.None)
return Conversion.None;
}
} else {
@ -1027,7 +1027,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -1027,7 +1027,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
for (int i = 0; i < f.Parameters.Count; i++) {
IParameter pD = d.Parameters[i];
IParameter pF = f.Parameters[i];
if (pD.IsRef != pF.IsRef || pD.IsOut != pF.IsOut)
if (pD.ReferenceKind != pF.ReferenceKind)
return Conversion.None;
if (!IdentityConversion(dParamTypes[i], pF.Type))
return Conversion.None;
@ -1071,9 +1071,9 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -1071,9 +1071,9 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
for (int i = 0; i < args.Length; i++) {
IParameter param = invoke.Parameters[i];
IType parameterType = param.Type;
if ((param.IsRef || param.IsOut) && parameterType.Kind == TypeKind.ByReference) {
if (param.ReferenceKind != ReferenceKind.None && parameterType.Kind == TypeKind.ByReference) {
parameterType = ((ByReferenceType)parameterType).ElementType;
args[i] = new ByReferenceResolveResult(parameterType, param.IsOut);
args[i] = new ByReferenceResolveResult(parameterType, param.ReferenceKind);
} else {
args[i] = new ResolveResult(parameterType);
}
@ -1132,11 +1132,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -1132,11 +1132,11 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
for (int i = 0; i < invoke.Parameters.Count; i++) {
var pm = m.Parameters[firstParameterInM + i];
var pd = invoke.Parameters[i];
// ret/out must match
if (pm.IsRef != pd.IsRef || pm.IsOut != pd.IsOut)
// ret/out/in must match
if (pm.ReferenceKind != pd.ReferenceKind)
return false;
if (pm.IsRef || pm.IsOut) {
// ref/out parameters must have same types
if (pm.ReferenceKind != ReferenceKind.None) {
// ref/out/in parameters must have same types
if (!pm.Type.Equals(pd.Type))
return false;
} else {

2
ICSharpCode.Decompiler/CSharp/Resolver/CSharpResolver.cs

@ -2084,7 +2084,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -2084,7 +2084,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
// create the parameter:
ByReferenceResolveResult brrr = arguments[i] as ByReferenceResolveResult;
if (brrr != null) {
list.Add(new DefaultParameter(arguments[i].Type, argumentNames[i], isRef: brrr.IsRef, isOut: brrr.IsOut));
list.Add(new DefaultParameter(arguments[i].Type, argumentNames[i], referenceKind: brrr.ReferenceKind));
} else {
// argument might be a lambda or delegate type, so we have to try to guess the delegate type
IType type = arguments[i].Type;

4
ICSharpCode.Decompiler/CSharp/Resolver/OverloadResolution.cs

@ -589,10 +589,10 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -589,10 +589,10 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
ByReferenceResolveResult brrr = arguments[i] as ByReferenceResolveResult;
if (brrr != null) {
if ((brrr.IsOut && !candidate.Parameters[parameterIndex].IsOut) || (brrr.IsRef && !candidate.Parameters[parameterIndex].IsRef))
if (brrr.ReferenceKind != candidate.Parameters[parameterIndex].ReferenceKind)
candidate.AddError(OverloadResolutionErrors.ParameterPassingModeMismatch);
} else {
if (candidate.Parameters[parameterIndex].IsOut || candidate.Parameters[parameterIndex].IsRef)
if (candidate.Parameters[parameterIndex].ReferenceKind != ReferenceKind.None)
candidate.AddError(OverloadResolutionErrors.ParameterPassingModeMismatch);
}
IType parameterType = candidate.ParameterTypes[parameterIndex];

12
ICSharpCode.Decompiler/CSharp/Resolver/TypeInference.cs

@ -513,9 +513,9 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -513,9 +513,9 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
for (int i = 0; i < args.Length; i++) {
IParameter param = m.Parameters[i];
IType parameterType = param.Type.AcceptVisitor(substitution);
if ((param.IsRef || param.IsOut) && parameterType.Kind == TypeKind.ByReference) {
if ((param.ReferenceKind != ReferenceKind.None) && parameterType.Kind == TypeKind.ByReference) {
parameterType = ((ByReferenceType)parameterType).ElementType;
args[i] = new ByReferenceResolveResult(parameterType, param.IsOut);
args[i] = new ByReferenceResolveResult(parameterType, param.ReferenceKind);
} else {
args[i] = new ResolveResult(parameterType);
}
@ -644,7 +644,13 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver @@ -644,7 +644,13 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
MakeLowerBoundInference(NullableType.GetUnderlyingType(U), NullableType.GetUnderlyingType(V));
return;
}
// Handle by reference types:
ByReferenceType brU = U as ByReferenceType;
ByReferenceType brV = V as ByReferenceType;
if (brU != null && brV != null) {
MakeExactInference(brU.ElementType, brV.ElementType);
return;
}
// Handle array types:
ArrayType arrU = U as ArrayType;
ArrayType arrV = V as ArrayType;

2
ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/MethodDeclaration.cs

@ -71,7 +71,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -71,7 +71,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public bool IsExtensionMethod {
get {
ParameterDeclaration pd = (ParameterDeclaration)GetChildByRole (Roles.Parameter);
return pd != null && pd.ParameterModifier == ParameterModifier.This;
return pd != null && pd.HasThisModifier;
}
}

31
ICSharpCode.Decompiler/CSharp/Syntax/TypeMembers/ParameterDeclaration.cs

@ -27,15 +27,15 @@ @@ -27,15 +27,15 @@
namespace ICSharpCode.Decompiler.CSharp.Syntax
{
public enum ParameterModifier {
public enum ParameterModifier
{
None,
Ref,
Out,
Params,
This,
In
}
public class ParameterDeclaration : AstNode
{
public static readonly Role<AttributeSection> AttributeRole = EntityDeclaration.AttributeRole;
@ -96,11 +96,30 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -96,11 +96,30 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
return NodeType.Unknown;
}
}
public AstNodeCollection<AttributeSection> Attributes {
get { return GetChildrenByRole (AttributeRole); }
get { return GetChildrenByRole(AttributeRole); }
}
bool hasThisModifier;
public CSharpTokenNode ThisKeyword {
get {
if (hasThisModifier) {
return GetChildByRole(ThisModifierRole);
}
return CSharpTokenNode.Null;
}
}
public bool HasThisModifier {
get { return hasThisModifier; }
set {
ThrowIfFrozen();
hasThisModifier = value;
}
}
ParameterModifier parameterModifier;
public ParameterModifier ParameterModifier {

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

@ -1633,8 +1633,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -1633,8 +1633,8 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
foreach (IParameter p in method.Parameters) {
decl.Parameters.Add(ConvertParameter(p));
}
if (method.IsExtensionMethod && method.ReducedFrom == null && decl.Parameters.Any() && decl.Parameters.First().ParameterModifier == ParameterModifier.None)
decl.Parameters.First().ParameterModifier = ParameterModifier.This;
if (method.IsExtensionMethod && method.ReducedFrom == null && decl.Parameters.Any())
decl.Parameters.First().HasThisModifier = true;
if (this.ShowTypeParameters && this.ShowTypeParameterConstraints && !method.IsOverride && !method.IsExplicitInterfaceImplementation) {
foreach (ITypeParameter tp in method.TypeParameters) {

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

@ -137,7 +137,13 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -137,7 +137,13 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
}
if (!CanTransformToExtensionMethodCall(resolver, method, typeArguments, target, args, argNames))
return;
if (firstArgument is NullReferenceExpression) {
if (firstArgument is DirectionExpression dirExpr) {
if (!context.Settings.RefExtensionMethods || dirExpr.FieldDirection == FieldDirection.Out)
return;
firstArgument = dirExpr.Expression;
target = firstArgument.GetResolveResult();
dirExpr.Detach();
} else if (firstArgument is NullReferenceExpression) {
Debug.Assert(context.RequiredNamespacesSuperset.Contains(method.Parameters[0].Type.Namespace));
firstArgument = firstArgument.ReplaceWith(expr => new CastExpression(context.TypeSystemAstBuilder.ConvertType(method.Parameters[0].Type), expr.Detach()));
}

6
ICSharpCode.Decompiler/CSharp/TranslatedExpression.cs

@ -376,7 +376,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -376,7 +376,7 @@ namespace ICSharpCode.Decompiler.CSharp
var convertedTemp = this.UnwrapChild(thisDir.Expression).ConvertTo(elementType, expressionBuilder, checkForOverflow);
return new DirectionExpression(FieldDirection.Ref, convertedTemp)
.WithILInstruction(this.ILInstructions)
.WithRR(new ByReferenceResolveResult(convertedTemp.ResolveResult, false));
.WithRR(new ByReferenceResolveResult(convertedTemp.ResolveResult, ReferenceKind.Ref));
}
// Convert from integer/pointer to reference.
// First, convert to the corresponding pointer type:
@ -396,7 +396,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -396,7 +396,7 @@ namespace ICSharpCode.Decompiler.CSharp
// And then take a reference:
return new DirectionExpression(FieldDirection.Ref, expr)
.WithoutILInstruction()
.WithRR(new ByReferenceResolveResult(elementRR, false));
.WithRR(new ByReferenceResolveResult(elementRR, ReferenceKind.Ref));
}
var rr = expressionBuilder.resolver.WithCheckForOverflow(checkForOverflow).ResolveCast(targetType, ResolveResult);
if (rr.IsCompileTimeConstant && !rr.IsError) {
@ -418,7 +418,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -418,7 +418,7 @@ namespace ICSharpCode.Decompiler.CSharp
return this;
}
} else {
if (NormalizeTypeVisitor.RemoveModifiersAndNullability.EquivalentTypes(type, targetType)) {
if (targetType.Kind != TypeKind.Dynamic && type.Kind != TypeKind.Dynamic && NormalizeTypeVisitor.TypeErasure.EquivalentTypes(type, targetType)) {
// avoid an explicit cast when types differ only in nullability of reference types
return this;
}

20
ICSharpCode.Decompiler/DecompilerSettings.cs

@ -97,6 +97,7 @@ namespace ICSharpCode.Decompiler @@ -97,6 +97,7 @@ namespace ICSharpCode.Decompiler
introduceReadonlyAndInModifiers = false;
introduceRefModifiersOnStructs = false;
nonTrailingNamedArguments = false;
refExtensionMethods = false;
}
if (languageVersion < CSharp.LanguageVersion.CSharp7_3) {
introduceUnmanagedConstraint = false;
@ -114,7 +115,7 @@ namespace ICSharpCode.Decompiler @@ -114,7 +115,7 @@ namespace ICSharpCode.Decompiler
return CSharp.LanguageVersion.CSharp8_0;
if (introduceUnmanagedConstraint || tupleComparisons || stackAllocInitializers)
return CSharp.LanguageVersion.CSharp7_3;
if (introduceRefModifiersOnStructs || introduceReadonlyAndInModifiers || nonTrailingNamedArguments)
if (introduceRefModifiersOnStructs || introduceReadonlyAndInModifiers || nonTrailingNamedArguments || refExtensionMethods)
return CSharp.LanguageVersion.CSharp7_2;
// C# 7.1 missing
if (outVariables || tupleTypes || tupleConversions || discards || localFunctions)
@ -626,6 +627,23 @@ namespace ICSharpCode.Decompiler @@ -626,6 +627,23 @@ namespace ICSharpCode.Decompiler
}
}
bool refExtensionMethods = true;
/// <summary>
/// Gets/Sets whether to use C# 7.2 'ref' extension methods.
/// </summary>
[Category("C# 7.2 / VS 2017.4")]
[Description("DecompilerSettings.AllowExtensionMethodSyntaxOnRef")]
public bool RefExtensionMethods {
get { return refExtensionMethods; }
set {
if (refExtensionMethods != value) {
refExtensionMethods = value;
OnPropertyChanged();
}
}
}
bool stringInterpolation = true;
/// <summary>

20
ICSharpCode.Decompiler/Semantics/ByReferenceResolveResult.cs

@ -24,25 +24,27 @@ using ICSharpCode.Decompiler.TypeSystem; @@ -24,25 +24,27 @@ using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.Semantics
{
/// <summary>
/// Represents the resolve result of an 'ref x' or 'out x' expression.
/// Represents the resolve result of an 'ref x', 'in x' or 'out x' expression.
/// </summary>
public class ByReferenceResolveResult : ResolveResult
{
public bool IsOut { get; private set; }
public bool IsRef { get { return !IsOut;} }
public ReferenceKind ReferenceKind { get; }
public bool IsOut => ReferenceKind == ReferenceKind.Out;
public bool IsRef => ReferenceKind == ReferenceKind.Ref;
public bool IsIn => ReferenceKind == ReferenceKind.In;
public readonly ResolveResult ElementResult;
public ByReferenceResolveResult(ResolveResult elementResult, bool isOut)
: this(elementResult.Type, isOut)
public ByReferenceResolveResult(ResolveResult elementResult, ReferenceKind kind)
: this(elementResult.Type, kind)
{
this.ElementResult = elementResult;
}
public ByReferenceResolveResult(IType elementType, bool isOut)
public ByReferenceResolveResult(IType elementType, ReferenceKind kind)
: base(new ByReferenceType(elementType))
{
this.IsOut = isOut;
this.ReferenceKind = kind;
}
public IType ElementType {
@ -59,7 +61,7 @@ namespace ICSharpCode.Decompiler.Semantics @@ -59,7 +61,7 @@ namespace ICSharpCode.Decompiler.Semantics
public override string ToString()
{
return string.Format(CultureInfo.InvariantCulture, "[{0} {1} {2}]", GetType().Name, IsOut ? "out" : "ref", ElementType);
return string.Format(CultureInfo.InvariantCulture, "[{0} {1} {2}]", GetType().Name, ReferenceKind.ToString().ToLowerInvariant(), ElementType);
}
}
}

2
ICSharpCode.Decompiler/Semantics/LocalResolveResult.cs

@ -42,7 +42,7 @@ namespace ICSharpCode.Decompiler.Semantics @@ -42,7 +42,7 @@ namespace ICSharpCode.Decompiler.Semantics
IType type = variable.Type;
if (type.Kind == TypeKind.ByReference) {
IParameter p = variable as IParameter;
if (p != null && (p.IsRef || p.IsOut))
if (p != null && p.ReferenceKind != ReferenceKind.None)
return ((ByReferenceType)type).ElementType;
}
return type;

16
ICSharpCode.Decompiler/TypeSystem/IParameter.cs

@ -21,12 +21,28 @@ using System.Collections.Generic; @@ -21,12 +21,28 @@ using System.Collections.Generic;
namespace ICSharpCode.Decompiler.TypeSystem
{
/// <remarks>
/// Should match order in <see cref="CSharp.Syntax.FieldDirection"/>.
/// </remarks>
public enum ReferenceKind
{
None,
Out,
Ref,
In
}
public interface IParameter : IVariable
{
/// <summary>
/// Gets the attributes on this parameter.
/// </summary>
IEnumerable<IAttribute> GetAttributes();
/// <summary>
/// Gets the reference kind of this parameter.
/// </summary>
ReferenceKind ReferenceKind { get; }
/// <summary>
/// Gets whether this parameter is a C# 'ref' parameter.

40
ICSharpCode.Decompiler/TypeSystem/Implementation/DefaultParameter.cs

@ -31,7 +31,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -31,7 +31,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
readonly IType type;
readonly string name;
readonly IReadOnlyList<IAttribute> attributes;
readonly bool isRef, isOut, isIn, isParams, isOptional;
readonly ReferenceKind referenceKind;
readonly bool isParams, isOptional;
readonly object defaultValue;
readonly IParameterizedMember owner;
@ -47,7 +48,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -47,7 +48,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
}
public DefaultParameter(IType type, string name, IParameterizedMember owner = null, IReadOnlyList<IAttribute> attributes = null,
bool isRef = false, bool isOut = false, bool isIn = false, bool isParams = false, bool isOptional = false, object defaultValue = null)
ReferenceKind referenceKind = ReferenceKind.None, bool isParams = false, bool isOptional = false, object defaultValue = null)
{
if (type == null)
throw new ArgumentNullException("type");
@ -57,9 +58,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -57,9 +58,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
this.name = name;
this.owner = owner;
this.attributes = attributes ?? EmptyList<IAttribute>.Instance;
this.isRef = isRef;
this.isOut = isOut;
this.isIn = isIn;
this.referenceKind = referenceKind;
this.isParams = isParams;
this.isOptional = isOptional;
this.defaultValue = defaultValue;
@ -74,27 +73,16 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -74,27 +73,16 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
}
public IEnumerable<IAttribute> GetAttributes() => attributes;
public bool IsRef {
get { return isRef; }
}
public bool IsOut {
get { return isOut; }
}
public bool IsIn {
get { return isIn; }
}
public bool IsParams {
get { return isParams; }
}
public bool IsOptional {
get { return isOptional; }
}
public ReferenceKind ReferenceKind => referenceKind;
public bool IsRef => referenceKind == ReferenceKind.Ref;
public bool IsOut => referenceKind == ReferenceKind.Out;
public bool IsIn => referenceKind == ReferenceKind.In;
public bool IsParams => isParams;
public bool IsOptional => isOptional;
public string Name {
get { return name; }
}
@ -128,6 +116,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -128,6 +116,8 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
b.Append("ref ");
if (parameter.IsOut)
b.Append("out ");
if (parameter.IsIn)
b.Append("in ");
if (parameter.IsParams)
b.Append("params ");
b.Append(parameter.Name);

4
ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataMethod.cs

@ -197,7 +197,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -197,7 +197,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
parameterType = ApplyAttributeTypeVisitor.ApplyAttributesToType(
signature.ParameterTypes[i], module.Compilation, null, metadata, module.TypeSystemOptions, nullableContext);
parameters[i] = new DefaultParameter(parameterType, name: string.Empty, owner,
isRef: parameterType.Kind == TypeKind.ByReference);
referenceKind: parameterType.Kind == TypeKind.ByReference ? ReferenceKind.Ref : ReferenceKind.None);
i++;
}
parameterType = ApplyAttributeTypeVisitor.ApplyAttributesToType(
@ -212,7 +212,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -212,7 +212,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
parameterType = ApplyAttributeTypeVisitor.ApplyAttributesToType(
signature.ParameterTypes[i], module.Compilation, null, metadata, module.TypeSystemOptions, nullableContext);
parameters[i] = new DefaultParameter(parameterType, name: string.Empty, owner,
isRef: parameterType.Kind == TypeKind.ByReference);
referenceKind: parameterType.Kind == TypeKind.ByReference ? ReferenceKind.Ref : ReferenceKind.None);
i++;
}
if (signature.Header.CallingConvention == SignatureCallingConvention.VarArgs) {

15
ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataParameter.cs

@ -81,25 +81,26 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -81,25 +81,26 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
const ParameterAttributes inOut = ParameterAttributes.In | ParameterAttributes.Out;
public bool IsRef => DetectRefKind() == CSharp.Syntax.ParameterModifier.Ref;
public ReferenceKind ReferenceKind => DetectRefKind();
public bool IsRef => DetectRefKind() == ReferenceKind.Ref;
public bool IsOut => Type.Kind == TypeKind.ByReference && (attributes & inOut) == ParameterAttributes.Out;
public bool IsIn => DetectRefKind() == CSharp.Syntax.ParameterModifier.In;
public bool IsIn => DetectRefKind() == ReferenceKind.In;
public bool IsOptional => (attributes & ParameterAttributes.Optional) != 0;
CSharp.Syntax.ParameterModifier DetectRefKind()
ReferenceKind DetectRefKind()
{
if (Type.Kind != TypeKind.ByReference)
return CSharp.Syntax.ParameterModifier.None;
return ReferenceKind.None;
if ((attributes & inOut) == ParameterAttributes.Out)
return CSharp.Syntax.ParameterModifier.Out;
return ReferenceKind.Out;
if ((module.TypeSystemOptions & TypeSystemOptions.ReadOnlyStructsAndParameters) != 0) {
var metadata = module.metadata;
var parameterDef = metadata.GetParameter(handle);
if (parameterDef.GetCustomAttributes().HasKnownAttribute(metadata, KnownAttribute.IsReadOnly))
return CSharp.Syntax.ParameterModifier.In;
return ReferenceKind.In;
}
return CSharp.Syntax.ParameterModifier.Ref;
return ReferenceKind.Ref;
}
public bool IsParams {

1
ICSharpCode.Decompiler/TypeSystem/Implementation/SpecializedParameter.cs

@ -36,6 +36,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation @@ -36,6 +36,7 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
}
IEnumerable<IAttribute> IParameter.GetAttributes() => baseParameter.GetAttributes();
ReferenceKind IParameter.ReferenceKind => baseParameter.ReferenceKind;
bool IParameter.IsRef => baseParameter.IsRef;
bool IParameter.IsOut => baseParameter.IsOut;
bool IParameter.IsIn => baseParameter.IsIn;

6
ICSharpCode.Decompiler/TypeSystem/ParameterListComparer.cs

@ -66,11 +66,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -66,11 +66,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
return false;
if (includeModifiers) {
if (a.IsIn != b.IsIn)
return false;
if (a.IsOut != b.IsOut)
return false;
if (a.IsRef != b.IsRef)
if (a.ReferenceKind != b.ReferenceKind)
return false;
if (a.IsParams != b.IsParams)
return false;

9
ILSpy/Properties/Resources.Designer.cs generated

@ -492,6 +492,15 @@ namespace ICSharpCode.ILSpy.Properties { @@ -492,6 +492,15 @@ namespace ICSharpCode.ILSpy.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Use &apos;ref&apos; extension methods.
/// </summary>
public static string DecompilerSettings_AllowExtensionMethodSyntaxOnRef {
get {
return ResourceManager.GetString("DecompilerSettings.AllowExtensionMethodSyntaxOnRef", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Always cast targets of explicit interface implementation calls.
/// </summary>

3
ILSpy/Properties/Resources.resx

@ -729,6 +729,9 @@ @@ -729,6 +729,9 @@
<data name="CannotAnalyzeMissingRef" xml:space="preserve">
<value>Entity could not be resolved. Cannot analyze entities from missing assembly references. Add the missing reference and try again.</value>
</data>
<data name="DecompilerSettings.AllowExtensionMethodSyntaxOnRef" xml:space="preserve">
<value>Use 'ref' extension methods</value>
</data>
<data name="AssemblySaveCodeDirectoryNotEmpty" xml:space="preserve">
<value>The directory is not empty. File will be overwritten.\r\nAre you sure you want to continue?</value>
</data>

Loading…
Cancel
Save