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. 25
      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. 18
      ICSharpCode.Decompiler/Semantics/ByReferenceResolveResult.cs
  24. 2
      ICSharpCode.Decompiler/Semantics/LocalResolveResult.cs
  25. 16
      ICSharpCode.Decompiler/TypeSystem/IParameter.cs
  26. 34
      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
RunCS(options: options); RunCS(options: options);
} }
[Test]
public void RefLocalsAndReturns([ValueSource("roslynOnlyOptions")] CompilerOptions options)
{
RunCS(options: options);
}
[Test] [Test]
public void BitNot([Values(false, true)] bool force32Bit) public void BitNot([Values(false, true)] bool force32Bit)
{ {

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

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

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

@ -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
{ {
} }
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() private static void InvokeConstructor()
{ {
DynamicTests dynamicTests = new DynamicTests(); DynamicTests dynamicTests = new DynamicTests();

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

@ -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(); test.Do();
((IEnumerable<int>)null).Any(); ((IEnumerable<int>)null).Any();
((object)null).Do(); ((object)null).Do();
#if CS72
date.Do();
#endif
} }
} }
} }

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

@ -2,10 +2,33 @@
namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty 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 internal class RefLocalsAndReturns
{ {
public delegate ref T RefFunc<T>(); public delegate ref T RefFunc<T>();
public delegate ref readonly T ReadOnlyRefFunc<T>(); public delegate ref readonly T ReadOnlyRefFunc<T>();
public delegate ref TReturn RefFunc<T1, TReturn>(T1 param1);
public ref struct RefStruct public ref struct RefStruct
{ {
@ -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>() public static ref T GetRef<T>()
{ {
throw new NotImplementedException(); throw new NotImplementedException();
@ -80,5 +125,95 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
ReadOnlyStruct readOnlyStruct = rs; ReadOnlyStruct readOnlyStruct = rs;
readOnlyStruct.Method(); 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
public object NotTargetTyping => ((string)null, (object)1, (Action)delegate { 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() public void UseDict()
{ {
if (TupleDict.Count > 10) { if (TupleDict.Count > 10) {
@ -160,5 +190,15 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{ {
Console.WriteLine(s.Field.A + s.Property.B); 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
public void InOutParametersOnRefMethod() public void InOutParametersOnRefMethod()
{ {
IParameter p = GetTypeDefinition(typeof(NonCustomAttributes)).Methods.Single(m => m.Name == "DllMethod").Parameters.Single(); IParameter p = GetTypeDefinition(typeof(NonCustomAttributes)).Methods.Single(m => m.Name == "DllMethod").Parameters.Single();
Assert.IsTrue(p.IsRef); Assert.AreEqual(ReferenceKind.Ref, p.ReferenceKind);
Assert.IsFalse(p.IsOut);
var attr = p.GetAttributes().ToList(); var attr = p.GetAttributes().ToList();
Assert.AreEqual(2, attr.Count); Assert.AreEqual(2, attr.Count);
Assert.AreEqual("System.Runtime.InteropServices.InAttribute", attr[0].AttributeType.FullName); Assert.AreEqual("System.Runtime.InteropServices.InAttribute", attr[0].AttributeType.FullName);
@ -728,9 +727,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem
{ {
IParameter p = GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithOutParameter").Parameters.Single(); IParameter p = GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithOutParameter").Parameters.Single();
Assert.IsFalse(p.IsOptional); Assert.IsFalse(p.IsOptional);
Assert.IsFalse(p.IsRef); Assert.AreEqual(ReferenceKind.Out, p.ReferenceKind);
Assert.IsTrue(p.IsOut);
Assert.IsFalse(p.IsIn);
Assert.AreEqual(0, p.GetAttributes().Count()); Assert.AreEqual(0, p.GetAttributes().Count());
Assert.IsTrue(p.Type.Kind == TypeKind.ByReference); Assert.IsTrue(p.Type.Kind == TypeKind.ByReference);
} }
@ -740,9 +737,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem
{ {
IParameter p = GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithRefParameter").Parameters.Single(); IParameter p = GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithRefParameter").Parameters.Single();
Assert.IsFalse(p.IsOptional); Assert.IsFalse(p.IsOptional);
Assert.IsTrue(p.IsRef); Assert.AreEqual(ReferenceKind.Ref, p.ReferenceKind);
Assert.IsFalse(p.IsOut);
Assert.IsFalse(p.IsIn);
Assert.AreEqual(0, p.GetAttributes().Count()); Assert.AreEqual(0, p.GetAttributes().Count());
Assert.IsTrue(p.Type.Kind == TypeKind.ByReference); Assert.IsTrue(p.Type.Kind == TypeKind.ByReference);
} }
@ -752,9 +747,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem
{ {
IParameter p = GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithInParameter").Parameters.Single(); IParameter p = GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithInParameter").Parameters.Single();
Assert.IsFalse(p.IsOptional); Assert.IsFalse(p.IsOptional);
Assert.IsFalse(p.IsRef); Assert.AreEqual(ReferenceKind.In, p.ReferenceKind);
Assert.IsFalse(p.IsOut);
Assert.IsTrue(p.IsIn);
Assert.AreEqual(0, p.GetAttributes().Count()); Assert.AreEqual(0, p.GetAttributes().Count());
Assert.IsTrue(p.Type.Kind == TypeKind.ByReference); Assert.IsTrue(p.Type.Kind == TypeKind.ByReference);
} }
@ -764,8 +757,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem
{ {
IParameter p = GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithParamsArray").Parameters.Single(); IParameter p = GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithParamsArray").Parameters.Single();
Assert.IsFalse(p.IsOptional); Assert.IsFalse(p.IsOptional);
Assert.IsFalse(p.IsRef); Assert.AreEqual(ReferenceKind.None, p.ReferenceKind);
Assert.IsFalse(p.IsOut);
Assert.IsTrue(p.IsParams); Assert.IsTrue(p.IsParams);
Assert.AreEqual(0, p.GetAttributes().Count()); Assert.AreEqual(0, p.GetAttributes().Count());
Assert.IsTrue(p.Type.Kind == TypeKind.Array); Assert.IsTrue(p.Type.Kind == TypeKind.Array);
@ -776,8 +768,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem
{ {
IParameter p = GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithOptionalParameter").Parameters.Single(); IParameter p = GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithOptionalParameter").Parameters.Single();
Assert.IsTrue(p.IsOptional); Assert.IsTrue(p.IsOptional);
Assert.IsFalse(p.IsRef); Assert.AreEqual(ReferenceKind.None, p.ReferenceKind);
Assert.IsFalse(p.IsOut);
Assert.IsFalse(p.IsParams); Assert.IsFalse(p.IsParams);
Assert.IsTrue(p.HasConstantValueInSignature); Assert.IsTrue(p.HasConstantValueInSignature);
Assert.AreEqual(0, p.GetAttributes().Count()); Assert.AreEqual(0, p.GetAttributes().Count());
@ -789,8 +780,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem
{ {
IParameter p = GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithExplicitOptionalParameter").Parameters.Single(); IParameter p = GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithExplicitOptionalParameter").Parameters.Single();
Assert.IsTrue(p.IsOptional); Assert.IsTrue(p.IsOptional);
Assert.IsFalse(p.IsRef); Assert.AreEqual(ReferenceKind.None, p.ReferenceKind);
Assert.IsFalse(p.IsOut);
Assert.IsFalse(p.IsParams); Assert.IsFalse(p.IsParams);
Assert.IsFalse(p.HasConstantValueInSignature); Assert.IsFalse(p.HasConstantValueInSignature);
// explicit optional parameter appears in type system if it's read from C#, but not when read from IL // 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
{ {
IParameter p = GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithEnumOptionalParameter").Parameters.Single(); IParameter p = GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithEnumOptionalParameter").Parameters.Single();
Assert.IsTrue(p.IsOptional); Assert.IsTrue(p.IsOptional);
Assert.IsFalse(p.IsRef); Assert.AreEqual(ReferenceKind.None, p.ReferenceKind);
Assert.IsFalse(p.IsOut);
Assert.IsFalse(p.IsParams); Assert.IsFalse(p.IsParams);
Assert.IsTrue(p.HasConstantValueInSignature); Assert.IsTrue(p.HasConstantValueInSignature);
Assert.AreEqual(0, p.GetAttributes().Count()); Assert.AreEqual(0, p.GetAttributes().Count());
@ -815,8 +804,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem
{ {
IParameter p = GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithOptionalNullableParameter").Parameters.Single(); IParameter p = GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithOptionalNullableParameter").Parameters.Single();
Assert.IsTrue(p.IsOptional); Assert.IsTrue(p.IsOptional);
Assert.IsFalse(p.IsRef); Assert.AreEqual(ReferenceKind.None, p.ReferenceKind);
Assert.IsFalse(p.IsOut);
Assert.IsFalse(p.IsParams); Assert.IsFalse(p.IsParams);
Assert.IsTrue(p.HasConstantValueInSignature); Assert.IsTrue(p.HasConstantValueInSignature);
Assert.AreEqual(0, p.GetAttributes().Count()); Assert.AreEqual(0, p.GetAttributes().Count());
@ -828,8 +816,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem
{ {
IParameter p = GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithOptionalLongParameter").Parameters.Single(); IParameter p = GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithOptionalLongParameter").Parameters.Single();
Assert.IsTrue(p.IsOptional); Assert.IsTrue(p.IsOptional);
Assert.IsFalse(p.IsRef); Assert.AreEqual(ReferenceKind.None, p.ReferenceKind);
Assert.IsFalse(p.IsOut);
Assert.IsFalse(p.IsParams); Assert.IsFalse(p.IsParams);
Assert.IsTrue(p.HasConstantValueInSignature); Assert.IsTrue(p.HasConstantValueInSignature);
Assert.AreEqual(1L, p.GetConstantValue()); Assert.AreEqual(1L, p.GetConstantValue());
@ -841,8 +828,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem
{ {
IParameter p = GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithOptionalNullableLongParameter").Parameters.Single(); IParameter p = GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithOptionalNullableLongParameter").Parameters.Single();
Assert.IsTrue(p.IsOptional); Assert.IsTrue(p.IsOptional);
Assert.IsFalse(p.IsRef); Assert.AreEqual(ReferenceKind.None, p.ReferenceKind);
Assert.IsFalse(p.IsOut);
Assert.IsFalse(p.IsParams); Assert.IsFalse(p.IsParams);
Assert.IsTrue(p.HasConstantValueInSignature); Assert.IsTrue(p.HasConstantValueInSignature);
Assert.AreEqual(1L, p.GetConstantValue()); Assert.AreEqual(1L, p.GetConstantValue());
@ -854,8 +840,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem
{ {
IParameter p = GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithOptionalDecimalParameter").Parameters.Single(); IParameter p = GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "MethodWithOptionalDecimalParameter").Parameters.Single();
Assert.IsTrue(p.IsOptional); Assert.IsTrue(p.IsOptional);
Assert.IsFalse(p.IsRef); Assert.AreEqual(ReferenceKind.None, p.ReferenceKind);
Assert.IsFalse(p.IsOut);
Assert.IsFalse(p.IsParams); Assert.IsFalse(p.IsParams);
Assert.IsTrue(p.HasConstantValueInSignature); Assert.IsTrue(p.HasConstantValueInSignature);
Assert.AreEqual(1M, p.GetConstantValue()); Assert.AreEqual(1M, p.GetConstantValue());
@ -867,8 +852,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem
{ {
IParameter p = GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "VarArgsMethod").Parameters.Single(); IParameter p = GetTypeDefinition(typeof(ParameterTests)).Methods.Single(m => m.Name == "VarArgsMethod").Parameters.Single();
Assert.IsFalse(p.IsOptional); Assert.IsFalse(p.IsOptional);
Assert.IsFalse(p.IsRef); Assert.AreEqual(ReferenceKind.None, p.ReferenceKind);
Assert.IsFalse(p.IsOut);
Assert.IsFalse(p.IsParams); Assert.IsFalse(p.IsParams);
Assert.AreEqual(TypeKind.ArgList, p.Type.Kind); Assert.AreEqual(TypeKind.ArgList, p.Type.Kind);
Assert.AreEqual("", p.Name); Assert.AreEqual("", p.Name);
@ -879,8 +863,7 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem
{ {
IParameter p = GetTypeDefinition(typeof(VarArgsCtor)).Methods.Single(m => m.IsConstructor).Parameters.Single(); IParameter p = GetTypeDefinition(typeof(VarArgsCtor)).Methods.Single(m => m.IsConstructor).Parameters.Single();
Assert.IsFalse(p.IsOptional); Assert.IsFalse(p.IsOptional);
Assert.IsFalse(p.IsRef); Assert.AreEqual(ReferenceKind.None, p.ReferenceKind);
Assert.IsFalse(p.IsOut);
Assert.IsFalse(p.IsParams); Assert.IsFalse(p.IsParams);
Assert.AreEqual(TypeKind.ArgList, p.Type.Kind); Assert.AreEqual(TypeKind.ArgList, p.Type.Kind);
Assert.AreEqual("", p.Name); Assert.AreEqual("", p.Name);

4
ICSharpCode.Decompiler/CSharp/CallBuilder.cs

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

32
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

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

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

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

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

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

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

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

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

@ -2084,7 +2084,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
// create the parameter: // create the parameter:
ByReferenceResolveResult brrr = arguments[i] as ByReferenceResolveResult; ByReferenceResolveResult brrr = arguments[i] as ByReferenceResolveResult;
if (brrr != null) { 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 { } else {
// argument might be a lambda or delegate type, so we have to try to guess the delegate type // argument might be a lambda or delegate type, so we have to try to guess the delegate type
IType type = arguments[i].Type; IType type = arguments[i].Type;

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

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

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

@ -513,9 +513,9 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
for (int i = 0; i < args.Length; i++) { for (int i = 0; i < args.Length; i++) {
IParameter param = m.Parameters[i]; IParameter param = m.Parameters[i];
IType parameterType = param.Type.AcceptVisitor(substitution); 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; parameterType = ((ByReferenceType)parameterType).ElementType;
args[i] = new ByReferenceResolveResult(parameterType, param.IsOut); args[i] = new ByReferenceResolveResult(parameterType, param.ReferenceKind);
} else { } else {
args[i] = new ResolveResult(parameterType); args[i] = new ResolveResult(parameterType);
} }
@ -644,7 +644,13 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
MakeLowerBoundInference(NullableType.GetUnderlyingType(U), NullableType.GetUnderlyingType(V)); MakeLowerBoundInference(NullableType.GetUnderlyingType(U), NullableType.GetUnderlyingType(V));
return; 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: // Handle array types:
ArrayType arrU = U as ArrayType; ArrayType arrU = U as ArrayType;
ArrayType arrV = V as ArrayType; ArrayType arrV = V as ArrayType;

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

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

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

@ -27,12 +27,12 @@
namespace ICSharpCode.Decompiler.CSharp.Syntax namespace ICSharpCode.Decompiler.CSharp.Syntax
{ {
public enum ParameterModifier { public enum ParameterModifier
{
None, None,
Ref, Ref,
Out, Out,
Params, Params,
This,
In In
} }
@ -98,7 +98,26 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
} }
public AstNodeCollection<AttributeSection> Attributes { 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; ParameterModifier parameterModifier;

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

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

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

@ -137,7 +137,13 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
} }
if (!CanTransformToExtensionMethodCall(resolver, method, typeArguments, target, args, argNames)) if (!CanTransformToExtensionMethodCall(resolver, method, typeArguments, target, args, argNames))
return; 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)); 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())); 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
var convertedTemp = this.UnwrapChild(thisDir.Expression).ConvertTo(elementType, expressionBuilder, checkForOverflow); var convertedTemp = this.UnwrapChild(thisDir.Expression).ConvertTo(elementType, expressionBuilder, checkForOverflow);
return new DirectionExpression(FieldDirection.Ref, convertedTemp) return new DirectionExpression(FieldDirection.Ref, convertedTemp)
.WithILInstruction(this.ILInstructions) .WithILInstruction(this.ILInstructions)
.WithRR(new ByReferenceResolveResult(convertedTemp.ResolveResult, false)); .WithRR(new ByReferenceResolveResult(convertedTemp.ResolveResult, ReferenceKind.Ref));
} }
// Convert from integer/pointer to reference. // Convert from integer/pointer to reference.
// First, convert to the corresponding pointer type: // First, convert to the corresponding pointer type:
@ -396,7 +396,7 @@ namespace ICSharpCode.Decompiler.CSharp
// And then take a reference: // And then take a reference:
return new DirectionExpression(FieldDirection.Ref, expr) return new DirectionExpression(FieldDirection.Ref, expr)
.WithoutILInstruction() .WithoutILInstruction()
.WithRR(new ByReferenceResolveResult(elementRR, false)); .WithRR(new ByReferenceResolveResult(elementRR, ReferenceKind.Ref));
} }
var rr = expressionBuilder.resolver.WithCheckForOverflow(checkForOverflow).ResolveCast(targetType, ResolveResult); var rr = expressionBuilder.resolver.WithCheckForOverflow(checkForOverflow).ResolveCast(targetType, ResolveResult);
if (rr.IsCompileTimeConstant && !rr.IsError) { if (rr.IsCompileTimeConstant && !rr.IsError) {
@ -418,7 +418,7 @@ namespace ICSharpCode.Decompiler.CSharp
return this; return this;
} }
} else { } 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 // avoid an explicit cast when types differ only in nullability of reference types
return this; return this;
} }

20
ICSharpCode.Decompiler/DecompilerSettings.cs

@ -97,6 +97,7 @@ namespace ICSharpCode.Decompiler
introduceReadonlyAndInModifiers = false; introduceReadonlyAndInModifiers = false;
introduceRefModifiersOnStructs = false; introduceRefModifiersOnStructs = false;
nonTrailingNamedArguments = false; nonTrailingNamedArguments = false;
refExtensionMethods = false;
} }
if (languageVersion < CSharp.LanguageVersion.CSharp7_3) { if (languageVersion < CSharp.LanguageVersion.CSharp7_3) {
introduceUnmanagedConstraint = false; introduceUnmanagedConstraint = false;
@ -114,7 +115,7 @@ namespace ICSharpCode.Decompiler
return CSharp.LanguageVersion.CSharp8_0; return CSharp.LanguageVersion.CSharp8_0;
if (introduceUnmanagedConstraint || tupleComparisons || stackAllocInitializers) if (introduceUnmanagedConstraint || tupleComparisons || stackAllocInitializers)
return CSharp.LanguageVersion.CSharp7_3; return CSharp.LanguageVersion.CSharp7_3;
if (introduceRefModifiersOnStructs || introduceReadonlyAndInModifiers || nonTrailingNamedArguments) if (introduceRefModifiersOnStructs || introduceReadonlyAndInModifiers || nonTrailingNamedArguments || refExtensionMethods)
return CSharp.LanguageVersion.CSharp7_2; return CSharp.LanguageVersion.CSharp7_2;
// C# 7.1 missing // C# 7.1 missing
if (outVariables || tupleTypes || tupleConversions || discards || localFunctions) if (outVariables || tupleTypes || tupleConversions || discards || localFunctions)
@ -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; bool stringInterpolation = true;
/// <summary> /// <summary>

18
ICSharpCode.Decompiler/Semantics/ByReferenceResolveResult.cs

@ -24,25 +24,27 @@ using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.Semantics namespace ICSharpCode.Decompiler.Semantics
{ {
/// <summary> /// <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> /// </summary>
public class ByReferenceResolveResult : ResolveResult public class ByReferenceResolveResult : ResolveResult
{ {
public bool IsOut { get; private set; } public ReferenceKind ReferenceKind { get; }
public bool IsRef { get { return !IsOut;} } public bool IsOut => ReferenceKind == ReferenceKind.Out;
public bool IsRef => ReferenceKind == ReferenceKind.Ref;
public bool IsIn => ReferenceKind == ReferenceKind.In;
public readonly ResolveResult ElementResult; public readonly ResolveResult ElementResult;
public ByReferenceResolveResult(ResolveResult elementResult, bool isOut) public ByReferenceResolveResult(ResolveResult elementResult, ReferenceKind kind)
: this(elementResult.Type, isOut) : this(elementResult.Type, kind)
{ {
this.ElementResult = elementResult; this.ElementResult = elementResult;
} }
public ByReferenceResolveResult(IType elementType, bool isOut) public ByReferenceResolveResult(IType elementType, ReferenceKind kind)
: base(new ByReferenceType(elementType)) : base(new ByReferenceType(elementType))
{ {
this.IsOut = isOut; this.ReferenceKind = kind;
} }
public IType ElementType { public IType ElementType {
@ -59,7 +61,7 @@ namespace ICSharpCode.Decompiler.Semantics
public override string ToString() 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
IType type = variable.Type; IType type = variable.Type;
if (type.Kind == TypeKind.ByReference) { if (type.Kind == TypeKind.ByReference) {
IParameter p = variable as IParameter; IParameter p = variable as IParameter;
if (p != null && (p.IsRef || p.IsOut)) if (p != null && p.ReferenceKind != ReferenceKind.None)
return ((ByReferenceType)type).ElementType; return ((ByReferenceType)type).ElementType;
} }
return type; return type;

16
ICSharpCode.Decompiler/TypeSystem/IParameter.cs

@ -21,6 +21,17 @@ using System.Collections.Generic;
namespace ICSharpCode.Decompiler.TypeSystem 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 public interface IParameter : IVariable
{ {
/// <summary> /// <summary>
@ -28,6 +39,11 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// </summary> /// </summary>
IEnumerable<IAttribute> GetAttributes(); IEnumerable<IAttribute> GetAttributes();
/// <summary>
/// Gets the reference kind of this parameter.
/// </summary>
ReferenceKind ReferenceKind { get; }
/// <summary> /// <summary>
/// Gets whether this parameter is a C# 'ref' parameter. /// Gets whether this parameter is a C# 'ref' parameter.
/// </summary> /// </summary>

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

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

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

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

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

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

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

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

6
ICSharpCode.Decompiler/TypeSystem/ParameterListComparer.cs

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

9
ILSpy/Properties/Resources.Designer.cs generated

@ -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> /// <summary>
/// Looks up a localized string similar to Always cast targets of explicit interface implementation calls. /// Looks up a localized string similar to Always cast targets of explicit interface implementation calls.
/// </summary> /// </summary>

3
ILSpy/Properties/Resources.resx

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

Loading…
Cancel
Save