Browse Source

Add special case for non-generic foreach and add more tests.

pull/877/head
Siegfried Pammer 8 years ago
parent
commit
9bdfdd09ff
  1. 20
      ICSharpCode.Decompiler.Tests/TestCases/Correctness/Loops.cs
  2. 19
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.cs
  3. 80
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.il
  4. 56
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.opt.il
  5. 52
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.opt.roslyn.il
  6. 74
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.roslyn.il
  7. 41
      ICSharpCode.Decompiler/CSharp/StatementBuilder.cs
  8. 43
      ICSharpCode.Decompiler/IL/Transforms/AssignVariableNames.cs
  9. 11
      ICSharpCode.Decompiler/IL/Transforms/UsingTransform.cs

20
ICSharpCode.Decompiler.Tests/TestCases/Correctness/Loops.cs

@ -17,6 +17,7 @@ @@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@ -70,5 +71,24 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness @@ -70,5 +71,24 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
current = 1;
Console.WriteLine(current);
}
public static void NonGenericForeachWithReturnFallbackTest(IEnumerable e)
{
Console.WriteLine("NonGenericForeachWithReturnFallback:");
IEnumerator enumerator = e.GetEnumerator();
try {
Console.WriteLine("MoveNext");
if (enumerator.MoveNext()) {
object current = enumerator.Current;
Console.WriteLine("current: " + current);
}
} finally {
IDisposable disposable = enumerator as IDisposable;
if (disposable != null) {
disposable.Dispose();
}
}
Console.WriteLine("After finally!");
}
}
}

19
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.cs

@ -220,5 +220,24 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -220,5 +220,24 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
}
Console.WriteLine("Last: " + num);
}
public static void NonGenericForeachWithReturnFallbackTest(IEnumerable e)
{
Console.WriteLine("NonGenericForeachWithReturnFallback:");
IEnumerator enumerator = e.GetEnumerator();
try {
Console.WriteLine("MoveNext");
if (enumerator.MoveNext()) {
object current = enumerator.Current;
Console.WriteLine("current: " + current);
}
} finally {
IDisposable disposable = enumerator as IDisposable;
if (disposable != null) {
disposable.Dispose();
}
}
Console.WriteLine("After finally!");
}
}
}

80
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.il

@ -10,7 +10,7 @@ @@ -10,7 +10,7 @@
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly nknknvk4
.assembly kpve0joz
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
@ -20,15 +20,15 @@ @@ -20,15 +20,15 @@
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module nknknvk4.dll
// MVID: {90F191A2-32E6-4921-8379-FD1D98A52EE5}
.module kpve0joz.dll
// MVID: {20825129-FBF4-4D0D-B2DB-BB2FE12F3807}
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x02820000
// Image base: 0x02A50000
// =============== CLASS MEMBERS DECLARATION ===================
@ -658,6 +658,78 @@ @@ -658,6 +658,78 @@
IL_005c: ret
} // end of method Loops::ForeachExceptForContinuedUse
.method public hidebysig static void NonGenericForeachWithReturnFallbackTest(class [mscorlib]System.Collections.IEnumerable e) cil managed
{
// Code size 113 (0x71)
.maxstack 2
.locals init (class [mscorlib]System.Collections.IEnumerator V_0,
object V_1,
class [mscorlib]System.IDisposable V_2,
bool V_3)
IL_0000: nop
IL_0001: ldstr "NonGenericForeachWithReturnFallback:"
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ldarg.0
IL_000d: callvirt instance class [mscorlib]System.Collections.IEnumerator [mscorlib]System.Collections.IEnumerable::GetEnumerator()
IL_0012: stloc.0
.try
{
IL_0013: nop
IL_0014: ldstr "MoveNext"
IL_0019: call void [mscorlib]System.Console::WriteLine(string)
IL_001e: nop
IL_001f: ldloc.0
IL_0020: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
IL_0025: ldc.i4.0
IL_0026: ceq
IL_0028: stloc.3
IL_0029: ldloc.3
IL_002a: brtrue.s IL_0046
IL_002c: nop
IL_002d: ldloc.0
IL_002e: callvirt instance object [mscorlib]System.Collections.IEnumerator::get_Current()
IL_0033: stloc.1
IL_0034: ldstr "current: "
IL_0039: ldloc.1
IL_003a: call string [mscorlib]System.String::Concat(object,
object)
IL_003f: call void [mscorlib]System.Console::WriteLine(string)
IL_0044: nop
IL_0045: nop
IL_0046: nop
IL_0047: leave.s IL_0064
} // end .try
finally
{
IL_0049: nop
IL_004a: ldloc.0
IL_004b: isinst [mscorlib]System.IDisposable
IL_0050: stloc.2
IL_0051: ldloc.2
IL_0052: ldnull
IL_0053: ceq
IL_0055: stloc.3
IL_0056: ldloc.3
IL_0057: brtrue.s IL_0062
IL_0059: nop
IL_005a: ldloc.2
IL_005b: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_0060: nop
IL_0061: nop
IL_0062: nop
IL_0063: endfinally
} // end handler
IL_0064: nop
IL_0065: ldstr "After finally!"
IL_006a: call void [mscorlib]System.Console::WriteLine(string)
IL_006f: nop
IL_0070: ret
} // end of method Loops::NonGenericForeachWithReturnFallbackTest
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{

56
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.opt.il

@ -10,7 +10,7 @@ @@ -10,7 +10,7 @@
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly mwkkmknt
.assembly ukcebu5a
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
@ -20,15 +20,15 @@ @@ -20,15 +20,15 @@
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module mwkkmknt.dll
// MVID: {A6DBEA2E-03CE-4841-BC30-F2B0EDA8AC75}
.module ukcebu5a.dll
// MVID: {D6A0A420-9828-48A7-BAA6-F0BAFB50052B}
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x02F00000
// Image base: 0x02F50000
// =============== CLASS MEMBERS DECLARATION ===================
@ -473,6 +473,54 @@ @@ -473,6 +473,54 @@
IL_004b: ret
} // end of method Loops::ForeachExceptForContinuedUse
.method public hidebysig static void NonGenericForeachWithReturnFallbackTest(class [mscorlib]System.Collections.IEnumerable e) cil managed
{
// Code size 88 (0x58)
.maxstack 2
.locals init (class [mscorlib]System.Collections.IEnumerator V_0,
object V_1,
class [mscorlib]System.IDisposable V_2)
IL_0000: ldstr "NonGenericForeachWithReturnFallback:"
IL_0005: call void [mscorlib]System.Console::WriteLine(string)
IL_000a: ldarg.0
IL_000b: callvirt instance class [mscorlib]System.Collections.IEnumerator [mscorlib]System.Collections.IEnumerable::GetEnumerator()
IL_0010: stloc.0
.try
{
IL_0011: ldstr "MoveNext"
IL_0016: call void [mscorlib]System.Console::WriteLine(string)
IL_001b: ldloc.0
IL_001c: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
IL_0021: brfalse.s IL_003a
IL_0023: ldloc.0
IL_0024: callvirt instance object [mscorlib]System.Collections.IEnumerator::get_Current()
IL_0029: stloc.1
IL_002a: ldstr "current: "
IL_002f: ldloc.1
IL_0030: call string [mscorlib]System.String::Concat(object,
object)
IL_0035: call void [mscorlib]System.Console::WriteLine(string)
IL_003a: leave.s IL_004d
} // end .try
finally
{
IL_003c: ldloc.0
IL_003d: isinst [mscorlib]System.IDisposable
IL_0042: stloc.2
IL_0043: ldloc.2
IL_0044: brfalse.s IL_004c
IL_0046: ldloc.2
IL_0047: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_004c: endfinally
} // end handler
IL_004d: ldstr "After finally!"
IL_0052: call void [mscorlib]System.Console::WriteLine(string)
IL_0057: ret
} // end of method Loops::NonGenericForeachWithReturnFallbackTest
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{

52
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.opt.roslyn.il

@ -25,14 +25,14 @@ @@ -25,14 +25,14 @@
.ver 0:0:0:0
}
.module Loops.dll
// MVID: {03277CBF-8A87-4FAE-8B0F-A5BF6427386C}
// MVID: {7BFC079C-5BB9-4A1A-A6EB-BA407AB11CEF}
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x01720000
// Image base: 0x011F0000
// =============== CLASS MEMBERS DECLARATION ===================
@ -465,6 +465,54 @@ @@ -465,6 +465,54 @@
IL_004b: ret
} // end of method Loops::ForeachExceptForContinuedUse
.method public hidebysig static void NonGenericForeachWithReturnFallbackTest(class [mscorlib]System.Collections.IEnumerable e) cil managed
{
// Code size 88 (0x58)
.maxstack 2
.locals init (class [mscorlib]System.Collections.IEnumerator V_0,
object V_1,
class [mscorlib]System.IDisposable V_2)
IL_0000: ldstr "NonGenericForeachWithReturnFallback:"
IL_0005: call void [mscorlib]System.Console::WriteLine(string)
IL_000a: ldarg.0
IL_000b: callvirt instance class [mscorlib]System.Collections.IEnumerator [mscorlib]System.Collections.IEnumerable::GetEnumerator()
IL_0010: stloc.0
.try
{
IL_0011: ldstr "MoveNext"
IL_0016: call void [mscorlib]System.Console::WriteLine(string)
IL_001b: ldloc.0
IL_001c: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
IL_0021: brfalse.s IL_003a
IL_0023: ldloc.0
IL_0024: callvirt instance object [mscorlib]System.Collections.IEnumerator::get_Current()
IL_0029: stloc.1
IL_002a: ldstr "current: "
IL_002f: ldloc.1
IL_0030: call string [mscorlib]System.String::Concat(object,
object)
IL_0035: call void [mscorlib]System.Console::WriteLine(string)
IL_003a: leave.s IL_004d
} // end .try
finally
{
IL_003c: ldloc.0
IL_003d: isinst [mscorlib]System.IDisposable
IL_0042: stloc.2
IL_0043: ldloc.2
IL_0044: brfalse.s IL_004c
IL_0046: ldloc.2
IL_0047: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_004c: endfinally
} // end handler
IL_004d: ldstr "After finally!"
IL_0052: call void [mscorlib]System.Console::WriteLine(string)
IL_0057: ret
} // end of method Loops::NonGenericForeachWithReturnFallbackTest
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{

74
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.roslyn.il

@ -25,14 +25,14 @@ @@ -25,14 +25,14 @@
.ver 0:0:0:0
}
.module Loops.dll
// MVID: {BAC1C379-EE42-472A-8FCB-BE9DD2565A1C}
// MVID: {C3B63F66-C940-45B6-9786-076A79DB1EC5}
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x027A0000
// Image base: 0x011E0000
// =============== CLASS MEMBERS DECLARATION ===================
@ -621,6 +621,76 @@ @@ -621,6 +621,76 @@
IL_0056: ret
} // end of method Loops::ForeachExceptForContinuedUse
.method public hidebysig static void NonGenericForeachWithReturnFallbackTest(class [mscorlib]System.Collections.IEnumerable e) cil managed
{
// Code size 111 (0x6f)
.maxstack 2
.locals init (class [mscorlib]System.Collections.IEnumerator V_0,
bool V_1,
object V_2,
class [mscorlib]System.IDisposable V_3,
bool V_4)
IL_0000: nop
IL_0001: ldstr "NonGenericForeachWithReturnFallback:"
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ldarg.0
IL_000d: callvirt instance class [mscorlib]System.Collections.IEnumerator [mscorlib]System.Collections.IEnumerable::GetEnumerator()
IL_0012: stloc.0
.try
{
IL_0013: nop
IL_0014: ldstr "MoveNext"
IL_0019: call void [mscorlib]System.Console::WriteLine(string)
IL_001e: nop
IL_001f: ldloc.0
IL_0020: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext()
IL_0025: stloc.1
IL_0026: ldloc.1
IL_0027: brfalse.s IL_0043
IL_0029: nop
IL_002a: ldloc.0
IL_002b: callvirt instance object [mscorlib]System.Collections.IEnumerator::get_Current()
IL_0030: stloc.2
IL_0031: ldstr "current: "
IL_0036: ldloc.2
IL_0037: call string [mscorlib]System.String::Concat(object,
object)
IL_003c: call void [mscorlib]System.Console::WriteLine(string)
IL_0041: nop
IL_0042: nop
IL_0043: nop
IL_0044: leave.s IL_0063
} // end .try
finally
{
IL_0046: nop
IL_0047: ldloc.0
IL_0048: isinst [mscorlib]System.IDisposable
IL_004d: stloc.3
IL_004e: ldloc.3
IL_004f: ldnull
IL_0050: cgt.un
IL_0052: stloc.s V_4
IL_0054: ldloc.s V_4
IL_0056: brfalse.s IL_0061
IL_0058: nop
IL_0059: ldloc.3
IL_005a: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_005f: nop
IL_0060: nop
IL_0061: nop
IL_0062: endfinally
} // end handler
IL_0063: ldstr "After finally!"
IL_0068: call void [mscorlib]System.Console::WriteLine(string)
IL_006d: nop
IL_006e: ret
} // end of method Loops::NonGenericForeachWithReturnFallbackTest
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{

41
ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

@ -267,16 +267,37 @@ namespace ICSharpCode.Decompiler.CSharp @@ -267,16 +267,37 @@ namespace ICSharpCode.Decompiler.CSharp
return transformed;
AstNode usingInit = resource;
var var = inst.Variable;
if (var.LoadCount > 0 || var.AddressCount > 0) {
var type = settings.AnonymousTypes && var.Type.ContainsAnonymousType() ? new SimpleType("var") : exprBuilder.ConvertType(var.Type);
var vds = new VariableDeclarationStatement(type, var.Name, resource);
vds.Variables.Single().AddAnnotation(new ILVariableResolveResult(var, var.Type));
usingInit = vds;
if (!var.Type.GetAllBaseTypes().Any(b => b.IsKnownType(KnownTypeCode.IDisposable))) {
var disposeType = exprBuilder.compilation.FindType(KnownTypeCode.IDisposable);
var disposeVariable = currentFunction.RegisterVariable(
VariableKind.Local, disposeType,
AssignVariableNames.GenerateVariableName(currentFunction, disposeType)
);
return new BlockStatement {
new ExpressionStatement(new AssignmentExpression(new IdentifierExpression(var.Name), resource.Detach())),
new TryCatchStatement {
TryBlock = ConvertAsBlock(inst.Body),
FinallyBlock = {
new ExpressionStatement(new AssignmentExpression(new IdentifierExpression(disposeVariable.Name), new AsExpression(new IdentifierExpression(var.Name), exprBuilder.ConvertType(disposeType)))),
new IfElseStatement {
Condition = new BinaryOperatorExpression(new IdentifierExpression(disposeVariable.Name), BinaryOperatorType.InEquality, new NullReferenceExpression()),
TrueStatement = new ExpressionStatement(new InvocationExpression(new MemberReferenceExpression(new IdentifierExpression(disposeVariable.Name), "Dispose")))
}
}
},
};
} else {
if (var.LoadCount > 0 || var.AddressCount > 0) {
var type = settings.AnonymousTypes && var.Type.ContainsAnonymousType() ? new SimpleType("var") : exprBuilder.ConvertType(var.Type);
var vds = new VariableDeclarationStatement(type, var.Name, resource);
vds.Variables.Single().AddAnnotation(new ILVariableResolveResult(var, var.Type));
usingInit = vds;
}
return new UsingStatement {
ResourceAcquisition = usingInit,
EmbeddedStatement = ConvertAsBlock(inst.Body)
};
}
return new UsingStatement {
ResourceAcquisition = usingInit,
EmbeddedStatement = ConvertAsBlock(inst.Body)
};
}
Statement TransformToForeach(UsingInstruction inst, out Expression resource)
@ -330,7 +351,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -330,7 +351,7 @@ namespace ICSharpCode.Decompiler.CSharp
itemVariable.Kind = VariableKind.ForeachLocal;
itemVariable.Name = AssignVariableNames.GenerateForeachVariableName(currentFunction, collectionExpr.Annotation<ILInstruction>(), itemVariable);
}
var whileLoop = (WhileStatement)ConvertAsBlock(inst.Body).First();
var whileLoop = (WhileStatement)ConvertAsBlock(container).First();
BlockStatement foreachBody = (BlockStatement)whileLoop.EmbeddedStatement.Detach();
foreachBody.Statements.First().Detach();
var foreachStmt = new ForeachStatement {

43
ICSharpCode.Decompiler/IL/Transforms/AssignVariableNames.cs

@ -272,7 +272,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -272,7 +272,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return null;
}
string GetNameByType(IType type)
static string GetNameByType(IType type)
{
var git = type as ParameterizedType;
if (git != null && git.FullName == "System.Nullable`1" && git.TypeArguments.Count == 1) {
@ -387,6 +387,47 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -387,6 +387,47 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
}
internal static string GenerateVariableName(ILFunction function, IType type, ILVariable existingVariable = null)
{
if (function == null)
throw new ArgumentNullException(nameof(function));
var reservedVariableNames = new Dictionary<string, int>();
foreach (var v in function.Descendants.OfType<ILFunction>().SelectMany(m => m.Variables)) {
if (v != existingVariable)
AddExistingName(reservedVariableNames, v.Name);
}
foreach (var f in function.Method.DeclaringType.Fields.Select(f => f.Name))
AddExistingName(reservedVariableNames, f);
string baseName = GetNameByType(type);
string proposedName = "obj";
if (!string.IsNullOrEmpty(baseName)) {
if (!IsPlural(baseName, ref proposedName)) {
if (baseName.Length > 4 && baseName.EndsWith("List", StringComparison.Ordinal)) {
proposedName = baseName.Substring(0, baseName.Length - 4);
} else if (baseName.Equals("list", StringComparison.OrdinalIgnoreCase)) {
proposedName = "item";
} else if (baseName.EndsWith("children", StringComparison.OrdinalIgnoreCase)) {
proposedName = baseName.Remove(baseName.Length - 3);
}
}
}
// remove any numbers from the proposed name
proposedName = SplitName(proposedName, out int number);
if (!reservedVariableNames.ContainsKey(proposedName)) {
reservedVariableNames.Add(proposedName, 0);
}
int count = ++reservedVariableNames[proposedName];
if (count > 1) {
return proposedName + count.ToString();
} else {
return proposedName;
}
}
private static bool IsPlural(string baseName, ref string proposedName)
{
if (baseName.EndsWith("ies", StringComparison.OrdinalIgnoreCase) && baseName.Length > 3) {

11
ICSharpCode.Decompiler/IL/Transforms/UsingTransform.cs

@ -74,7 +74,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -74,7 +74,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (i < 1) return false;
if (!(block.Instructions[i] is TryFinally tryFinally) || !(block.Instructions[i - 1] is StLoc storeInst))
return false;
if (!(storeInst.Value.MatchLdNull() || NullableType.GetUnderlyingType(storeInst.Variable.Type).GetAllBaseTypes().Any(b => b.IsKnownType(KnownTypeCode.IDisposable))))
if (!(storeInst.Value.MatchLdNull() || CheckResourceType(storeInst.Variable.Type)))
return false;
if (storeInst.Variable.LoadInstructions.Any(ld => !ld.IsDescendantOf(tryFinally)))
return false;
@ -91,6 +91,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -91,6 +91,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return true;
}
bool CheckResourceType(IType type)
{
// non-generic IEnumerator does not implement IDisposable.
// This is a workaround for non-generic foreach.
if (type.IsKnownType(KnownTypeCode.IEnumerator))
return true;
return NullableType.GetUnderlyingType(type).GetAllBaseTypes().Any(b => b.IsKnownType(KnownTypeCode.IDisposable));
}
bool MatchDisposeBlock(BlockContainer container, ILVariable objVar, bool usingNull)
{
var entryPoint = container.EntryPoint;

Loading…
Cancel
Save