Browse Source

Fix #2115: Re-introduce the evaluation order bug #2050 when a language version <=C# 5 is selected.

pull/2145/head
Daniel Grunwald 6 years ago
parent
commit
bb99e9668a
  1. 6
      ICSharpCode.Decompiler.Tests/CorrectnessTestRunner.cs
  2. 8
      ICSharpCode.Decompiler.Tests/Helpers/Tester.cs
  3. 24
      ICSharpCode.Decompiler/DecompilerSettings.cs
  4. 16
      ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs
  5. 27
      ILSpy/Properties/Resources.Designer.cs
  6. 9
      ILSpy/Properties/Resources.resx
  7. 6
      ILSpy/Properties/Resources.zh-Hans.resx

6
ICSharpCode.Decompiler.Tests/CorrectnessTestRunner.cs

@ -142,7 +142,7 @@ namespace ICSharpCode.Decompiler.Tests
[Test] [Test]
public void NullableTests([ValueSource("defaultOptions")] CompilerOptions options) public void NullableTests([ValueSource("defaultOptions")] CompilerOptions options)
{ {
RunCS(options: options, forceRoslynRecompile: true); RunCS(options: options);
} }
[Test] [Test]
@ -315,7 +315,7 @@ namespace ICSharpCode.Decompiler.Tests
RunCS(options: options); RunCS(options: options);
} }
void RunCS([CallerMemberName] string testName = null, CompilerOptions options = CompilerOptions.UseDebug, bool forceRoslynRecompile = false) void RunCS([CallerMemberName] string testName = null, CompilerOptions options = CompilerOptions.UseDebug)
{ {
string testFileName = testName + ".cs"; string testFileName = testName + ".cs";
string testOutputFileName = testName + Tester.GetSuffix(options) + ".exe"; string testOutputFileName = testName + Tester.GetSuffix(options) + ".exe";
@ -326,7 +326,7 @@ namespace ICSharpCode.Decompiler.Tests
outputFile = Tester.CompileCSharp(Path.Combine(TestCasePath, testFileName), options, outputFile = Tester.CompileCSharp(Path.Combine(TestCasePath, testFileName), options,
outputFileName: Path.Combine(TestCasePath, testOutputFileName)); outputFileName: Path.Combine(TestCasePath, testOutputFileName));
string decompiledCodeFile = Tester.DecompileCSharp(outputFile.PathToAssembly, Tester.GetSettings(options)); string decompiledCodeFile = Tester.DecompileCSharp(outputFile.PathToAssembly, Tester.GetSettings(options));
if (forceRoslynRecompile || options.HasFlag(CompilerOptions.UseMcs)) if (options.HasFlag(CompilerOptions.UseMcs))
{ {
// For second pass, use roslyn instead of mcs. // For second pass, use roslyn instead of mcs.
// mcs has some compiler bugs that cause it to not accept ILSpy-generated code, // mcs has some compiler bugs that cause it to not accept ILSpy-generated code,

8
ICSharpCode.Decompiler.Tests/Helpers/Tester.cs

@ -464,7 +464,13 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
} }
else else
{ {
return new DecompilerSettings(CSharp.LanguageVersion.CSharp5); var settings= new DecompilerSettings(CSharp.LanguageVersion.CSharp5);
if (cscOptions.HasFlag(CompilerOptions.UseMcs))
{
// we don't recompile with mcs but with roslyn, so we can use ref locals
settings.UseRefLocalsForAccurateOrderOfEvaluation = true;
}
return settings;
} }
} }

24
ICSharpCode.Decompiler/DecompilerSettings.cs

@ -92,6 +92,7 @@ namespace ICSharpCode.Decompiler
stringInterpolation = false; stringInterpolation = false;
dictionaryInitializers = false; dictionaryInitializers = false;
extensionMethodsInCollectionInitializers = false; extensionMethodsInCollectionInitializers = false;
useRefLocalsForAccurateOrderOfEvaluation = false;
} }
if (languageVersion < CSharp.LanguageVersion.CSharp7) if (languageVersion < CSharp.LanguageVersion.CSharp7)
{ {
@ -153,7 +154,7 @@ namespace ICSharpCode.Decompiler
|| discards || localFunctions) || discards || localFunctions)
return CSharp.LanguageVersion.CSharp7; return CSharp.LanguageVersion.CSharp7;
if (awaitInCatchFinally || useExpressionBodyForCalculatedGetterOnlyProperties || nullPropagation if (awaitInCatchFinally || useExpressionBodyForCalculatedGetterOnlyProperties || nullPropagation
|| stringInterpolation || dictionaryInitializers || extensionMethodsInCollectionInitializers) || stringInterpolation || dictionaryInitializers || extensionMethodsInCollectionInitializers || useRefLocalsForAccurateOrderOfEvaluation)
return CSharp.LanguageVersion.CSharp6; return CSharp.LanguageVersion.CSharp6;
if (asyncAwait) if (asyncAwait)
return CSharp.LanguageVersion.CSharp5; return CSharp.LanguageVersion.CSharp5;
@ -445,7 +446,7 @@ namespace ICSharpCode.Decompiler
/// Decompile C# 6 ?. and ?[] operators. /// Decompile C# 6 ?. and ?[] operators.
/// </summary> /// </summary>
[Category("C# 6.0 / VS 2015")] [Category("C# 6.0 / VS 2015")]
[Description("DecompilerSettings.DecompileAndOperators")] [Description("DecompilerSettings.NullPropagation")]
public bool NullPropagation { public bool NullPropagation {
get { return nullPropagation; } get { return nullPropagation; }
set { set {
@ -819,6 +820,25 @@ namespace ICSharpCode.Decompiler
} }
} }
bool useRefLocalsForAccurateOrderOfEvaluation = true;
/// <summary>
/// Gets/Sets whether to use C# 6.0 Extension Add methods in collection initializers.
/// Only has an effect if ObjectOrCollectionInitializers is enabled.
/// </summary>
[Category("C# 6.0 / VS 2015")]
[Description("DecompilerSettings.UseRefLocalsForAccurateOrderOfEvaluation")]
public bool UseRefLocalsForAccurateOrderOfEvaluation {
get { return useRefLocalsForAccurateOrderOfEvaluation; }
set {
if (useRefLocalsForAccurateOrderOfEvaluation != value)
{
useRefLocalsForAccurateOrderOfEvaluation = value;
OnPropertyChanged();
}
}
}
bool refExtensionMethods = true; bool refExtensionMethods = true;
/// <summary> /// <summary>

16
ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs

@ -33,6 +33,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
Aggressive = 1, Aggressive = 1,
IntroduceNamedArguments = 2, IntroduceNamedArguments = 2,
FindDeconstruction = 4, FindDeconstruction = 4,
AllowChangingOrderOfEvaluationForExceptions = 8,
} }
/// <summary> /// <summary>
@ -73,6 +74,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (IsInConstructorInitializer(function, inst)) if (IsInConstructorInitializer(function, inst))
options |= InliningOptions.Aggressive; options |= InliningOptions.Aggressive;
} }
if (!context.Settings.UseRefLocalsForAccurateOrderOfEvaluation)
{
options |= InliningOptions.AllowChangingOrderOfEvaluationForExceptions;
}
return options; return options;
} }
@ -666,10 +671,21 @@ namespace ICSharpCode.Decompiler.IL.Transforms
{ {
// Match found, we can inline // Match found, we can inline
if (expr.SlotInfo == StObj.TargetSlot && !((StObj)expr.Parent).CanInlineIntoTargetSlot(expressionBeingMoved)) if (expr.SlotInfo == StObj.TargetSlot && !((StObj)expr.Parent).CanInlineIntoTargetSlot(expressionBeingMoved))
{
if ((options & InliningOptions.AllowChangingOrderOfEvaluationForExceptions) != 0)
{
// Intentionally change code semantics so that we can avoid a ref local
if (expressionBeingMoved is LdFlda ldflda)
ldflda.DelayExceptions = true;
else if (expressionBeingMoved is LdElema ldelema)
ldelema.DelayExceptions = true;
}
else
{ {
// special case: the StObj.TargetSlot does not accept some kinds of expressions // special case: the StObj.TargetSlot does not accept some kinds of expressions
return FindResult.Stop; return FindResult.Stop;
} }
}
return FindResult.Found(expr); return FindResult.Found(expr);
} }
else if (expr is Block block) else if (expr is Block block)

27
ILSpy/Properties/Resources.Designer.cs generated

@ -711,15 +711,6 @@ namespace ICSharpCode.ILSpy.Properties {
} }
} }
/// <summary>
/// Looks up a localized string similar to Decompile ?. and ?[] operators.
/// </summary>
public static string DecompilerSettings_DecompileAndOperators {
get {
return ResourceManager.GetString("DecompilerSettings.DecompileAndOperators", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Decompile anonymous methods/lambdas. /// Looks up a localized string similar to Decompile anonymous methods/lambdas.
/// </summary> /// </summary>
@ -1010,6 +1001,15 @@ namespace ICSharpCode.ILSpy.Properties {
} }
} }
/// <summary>
/// Looks up a localized string similar to Decompile ?. and ?[] operators.
/// </summary>
public static string DecompilerSettings_NullPropagation {
get {
return ResourceManager.GetString("DecompilerSettings.NullPropagation", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Object/collection initializer expressions. /// Looks up a localized string similar to Object/collection initializer expressions.
/// </summary> /// </summary>
@ -1217,6 +1217,15 @@ namespace ICSharpCode.ILSpy.Properties {
} }
} }
/// <summary>
/// Looks up a localized string similar to Use ref locals to accurately represent order of evaluation.
/// </summary>
public static string DecompilerSettings_UseRefLocalsForAccurateOrderOfEvaluation {
get {
return ResourceManager.GetString("DecompilerSettings.UseRefLocalsForAccurateOrderOfEvaluation", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Use new SDK style format for generated project files (*.csproj). /// Looks up a localized string similar to Use new SDK style format for generated project files (*.csproj).
/// </summary> /// </summary>

9
ILSpy/Properties/Resources.resx

@ -267,9 +267,6 @@ Are you sure you want to continue?</value>
<data name="DecompilerSettings.AsyncEnumerator" xml:space="preserve"> <data name="DecompilerSettings.AsyncEnumerator" xml:space="preserve">
<value>Decompile async IAsyncEnumerator methods</value> <value>Decompile async IAsyncEnumerator methods</value>
</data> </data>
<data name="DecompilerSettings.DecompileAndOperators" xml:space="preserve">
<value>Decompile ?. and ?[] operators</value>
</data>
<data name="DecompilerSettings.DecompileAnonymousMethodsLambdas" xml:space="preserve"> <data name="DecompilerSettings.DecompileAnonymousMethodsLambdas" xml:space="preserve">
<value>Decompile anonymous methods/lambdas</value> <value>Decompile anonymous methods/lambdas</value>
</data> </data>
@ -363,6 +360,9 @@ Are you sure you want to continue?</value>
<data name="DecompilerSettings.NativeIntegers" xml:space="preserve"> <data name="DecompilerSettings.NativeIntegers" xml:space="preserve">
<value>Use nint/nuint types</value> <value>Use nint/nuint types</value>
</data> </data>
<data name="DecompilerSettings.NullPropagation" xml:space="preserve">
<value>Decompile ?. and ?[] operators</value>
</data>
<data name="DecompilerSettings.NullableReferenceTypes" xml:space="preserve"> <data name="DecompilerSettings.NullableReferenceTypes" xml:space="preserve">
<value>Nullable reference types</value> <value>Nullable reference types</value>
</data> </data>
@ -435,6 +435,9 @@ Are you sure you want to continue?</value>
<data name="DecompilerSettings.UsePatternBasedFixedStatement" xml:space="preserve"> <data name="DecompilerSettings.UsePatternBasedFixedStatement" xml:space="preserve">
<value>Use pattern-based fixed statement</value> <value>Use pattern-based fixed statement</value>
</data> </data>
<data name="DecompilerSettings.UseRefLocalsForAccurateOrderOfEvaluation" xml:space="preserve">
<value>Use ref locals to accurately represent order of evaluation</value>
</data>
<data name="DecompilerSettings.UseSdkStyleProjectFormat" xml:space="preserve"> <data name="DecompilerSettings.UseSdkStyleProjectFormat" xml:space="preserve">
<value>Use new SDK style format for generated project files (*.csproj)</value> <value>Use new SDK style format for generated project files (*.csproj)</value>
</data> </data>

6
ILSpy/Properties/Resources.zh-Hans.resx

@ -258,9 +258,6 @@
<data name="DecompilerSettings.AsyncEnumerator" xml:space="preserve"> <data name="DecompilerSettings.AsyncEnumerator" xml:space="preserve">
<value>反编译异步 IAsyncEnumerator 方法</value> <value>反编译异步 IAsyncEnumerator 方法</value>
</data> </data>
<data name="DecompilerSettings.DecompileAndOperators" xml:space="preserve">
<value>反编译 ?. 和 ?[] 运算符</value>
</data>
<data name="DecompilerSettings.DecompileAnonymousMethodsLambdas" xml:space="preserve"> <data name="DecompilerSettings.DecompileAnonymousMethodsLambdas" xml:space="preserve">
<value>反编译匿名方法或 lambda</value> <value>反编译匿名方法或 lambda</value>
</data> </data>
@ -348,6 +345,9 @@
<data name="DecompilerSettings.NativeIntegers" xml:space="preserve"> <data name="DecompilerSettings.NativeIntegers" xml:space="preserve">
<value>使用 nint/nuint 类型</value> <value>使用 nint/nuint 类型</value>
</data> </data>
<data name="DecompilerSettings.NullPropagation" xml:space="preserve">
<value>反编译 ?. 和 ?[] 运算符</value>
</data>
<data name="DecompilerSettings.NullableReferenceTypes" xml:space="preserve"> <data name="DecompilerSettings.NullableReferenceTypes" xml:space="preserve">
<value>可空引用类型</value> <value>可空引用类型</value>
</data> </data>

Loading…
Cancel
Save