mirror of https://github.com/icsharpcode/ILSpy.git
68 changed files with 2433 additions and 446 deletions
|
After Width: | Height: | Size: 2.4 KiB |
@ -0,0 +1,43 @@ |
|||||||
|
using System; |
||||||
|
using System.Collections; |
||||||
|
using System.Collections.Generic; |
||||||
|
|
||||||
|
namespace ICSharpCode.Decompiler.Tests.TestCases.Ugly |
||||||
|
{ |
||||||
|
internal class NoForEachStatement |
||||||
|
{ |
||||||
|
public static void SimpleNonGenericForeach(IEnumerable enumerable) |
||||||
|
{ |
||||||
|
IEnumerator enumerator = enumerable.GetEnumerator(); |
||||||
|
try { |
||||||
|
while (enumerator.MoveNext()) { |
||||||
|
#if ROSLYN && OPT
|
||||||
|
Console.WriteLine(enumerator.Current); |
||||||
|
#else
|
||||||
|
object current = enumerator.Current; |
||||||
|
Console.WriteLine(current); |
||||||
|
#endif
|
||||||
|
} |
||||||
|
} finally { |
||||||
|
IDisposable disposable = enumerator as IDisposable; |
||||||
|
if (disposable != null) { |
||||||
|
disposable.Dispose(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static void SimpleForeachOverInts(IEnumerable<int> enumerable) |
||||||
|
{ |
||||||
|
using (IEnumerator<int> enumerator = enumerable.GetEnumerator()) { |
||||||
|
while (enumerator.MoveNext()) { |
||||||
|
#if ROSLYN && OPT
|
||||||
|
Console.WriteLine(enumerator.Current); |
||||||
|
#else
|
||||||
|
int current = enumerator.Current; |
||||||
|
Console.WriteLine(current); |
||||||
|
#endif
|
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,23 @@ |
|||||||
|
using System; |
||||||
|
using System.Collections; |
||||||
|
using System.Collections.Generic; |
||||||
|
|
||||||
|
namespace ICSharpCode.Decompiler.Tests.TestCases.Ugly |
||||||
|
{ |
||||||
|
internal class NoForEachStatement |
||||||
|
{ |
||||||
|
public static void SimpleNonGenericForeach(IEnumerable enumerable) |
||||||
|
{ |
||||||
|
foreach (object item in enumerable) { |
||||||
|
Console.WriteLine(item); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static void SimpleForeachOverInts(IEnumerable<int> enumerable) |
||||||
|
{ |
||||||
|
foreach (int item in enumerable) { |
||||||
|
Console.WriteLine(item); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,156 @@ |
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Metadata version: v4.0.30319 |
||||||
|
.assembly extern mscorlib |
||||||
|
{ |
||||||
|
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4.. |
||||||
|
.ver 4:0:0:0 |
||||||
|
} |
||||||
|
.assembly rerff2f0 |
||||||
|
{ |
||||||
|
.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 |
||||||
|
63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows. |
||||||
|
.permissionset reqmin |
||||||
|
= {[mscorlib]System.Security.Permissions.SecurityPermissionAttribute = {property bool 'SkipVerification' = bool(true)}} |
||||||
|
.hash algorithm 0x00008004 |
||||||
|
.ver 0:0:0:0 |
||||||
|
} |
||||||
|
.module rerff2f0.dll |
||||||
|
.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 |
||||||
|
|
||||||
|
|
||||||
|
// =============== CLASS MEMBERS DECLARATION =================== |
||||||
|
|
||||||
|
.class private auto ansi beforefieldinit ICSharpCode.Decompiler.Tests.TestCases.Ugly.NoForEachStatement |
||||||
|
extends [mscorlib]System.Object |
||||||
|
{ |
||||||
|
.method public hidebysig static void SimpleNonGenericForeach(class [mscorlib]System.Collections.IEnumerable enumerable) cil managed |
||||||
|
{ |
||||||
|
// Code size 64 (0x40) |
||||||
|
.maxstack 2 |
||||||
|
.locals init (object V_0, |
||||||
|
class [mscorlib]System.Collections.IEnumerator V_1, |
||||||
|
bool V_2, |
||||||
|
class [mscorlib]System.IDisposable V_3) |
||||||
|
IL_0000: nop |
||||||
|
IL_0001: nop |
||||||
|
IL_0002: ldarg.0 |
||||||
|
IL_0003: callvirt instance class [mscorlib]System.Collections.IEnumerator [mscorlib]System.Collections.IEnumerable::GetEnumerator() |
||||||
|
IL_0008: stloc.1 |
||||||
|
.try |
||||||
|
{ |
||||||
|
IL_0009: br.s IL_001b |
||||||
|
|
||||||
|
IL_000b: ldloc.1 |
||||||
|
IL_000c: callvirt instance object [mscorlib]System.Collections.IEnumerator::get_Current() |
||||||
|
IL_0011: stloc.0 |
||||||
|
IL_0012: nop |
||||||
|
IL_0013: ldloc.0 |
||||||
|
IL_0014: call void [mscorlib]System.Console::WriteLine(object) |
||||||
|
IL_0019: nop |
||||||
|
IL_001a: nop |
||||||
|
IL_001b: ldloc.1 |
||||||
|
IL_001c: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext() |
||||||
|
IL_0021: stloc.2 |
||||||
|
IL_0022: ldloc.2 |
||||||
|
IL_0023: brtrue.s IL_000b |
||||||
|
|
||||||
|
IL_0025: leave.s IL_003e |
||||||
|
|
||||||
|
} // end .try |
||||||
|
finally |
||||||
|
{ |
||||||
|
IL_0027: ldloc.1 |
||||||
|
IL_0028: isinst [mscorlib]System.IDisposable |
||||||
|
IL_002d: stloc.3 |
||||||
|
IL_002e: ldloc.3 |
||||||
|
IL_002f: ldnull |
||||||
|
IL_0030: ceq |
||||||
|
IL_0032: stloc.2 |
||||||
|
IL_0033: ldloc.2 |
||||||
|
IL_0034: brtrue.s IL_003d |
||||||
|
|
||||||
|
IL_0036: ldloc.3 |
||||||
|
IL_0037: callvirt instance void [mscorlib]System.IDisposable::Dispose() |
||||||
|
IL_003c: nop |
||||||
|
IL_003d: endfinally |
||||||
|
} // end handler |
||||||
|
IL_003e: nop |
||||||
|
IL_003f: ret |
||||||
|
} // end of method NoForEachStatement::SimpleNonGenericForeach |
||||||
|
|
||||||
|
.method public hidebysig static void SimpleForeachOverInts(class [mscorlib]System.Collections.Generic.IEnumerable`1<int32> enumerable) cil managed |
||||||
|
{ |
||||||
|
// Code size 57 (0x39) |
||||||
|
.maxstack 2 |
||||||
|
.locals init (int32 V_0, |
||||||
|
class [mscorlib]System.Collections.Generic.IEnumerator`1<int32> V_1, |
||||||
|
bool V_2) |
||||||
|
IL_0000: nop |
||||||
|
IL_0001: nop |
||||||
|
IL_0002: ldarg.0 |
||||||
|
IL_0003: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerator`1<!0> class [mscorlib]System.Collections.Generic.IEnumerable`1<int32>::GetEnumerator() |
||||||
|
IL_0008: stloc.1 |
||||||
|
.try |
||||||
|
{ |
||||||
|
IL_0009: br.s IL_001b |
||||||
|
|
||||||
|
IL_000b: ldloc.1 |
||||||
|
IL_000c: callvirt instance !0 class [mscorlib]System.Collections.Generic.IEnumerator`1<int32>::get_Current() |
||||||
|
IL_0011: stloc.0 |
||||||
|
IL_0012: nop |
||||||
|
IL_0013: ldloc.0 |
||||||
|
IL_0014: call void [mscorlib]System.Console::WriteLine(int32) |
||||||
|
IL_0019: nop |
||||||
|
IL_001a: nop |
||||||
|
IL_001b: ldloc.1 |
||||||
|
IL_001c: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext() |
||||||
|
IL_0021: stloc.2 |
||||||
|
IL_0022: ldloc.2 |
||||||
|
IL_0023: brtrue.s IL_000b |
||||||
|
|
||||||
|
IL_0025: leave.s IL_0037 |
||||||
|
|
||||||
|
} // end .try |
||||||
|
finally |
||||||
|
{ |
||||||
|
IL_0027: ldloc.1 |
||||||
|
IL_0028: ldnull |
||||||
|
IL_0029: ceq |
||||||
|
IL_002b: stloc.2 |
||||||
|
IL_002c: ldloc.2 |
||||||
|
IL_002d: brtrue.s IL_0036 |
||||||
|
|
||||||
|
IL_002f: ldloc.1 |
||||||
|
IL_0030: callvirt instance void [mscorlib]System.IDisposable::Dispose() |
||||||
|
IL_0035: nop |
||||||
|
IL_0036: endfinally |
||||||
|
} // end handler |
||||||
|
IL_0037: nop |
||||||
|
IL_0038: ret |
||||||
|
} // end of method NoForEachStatement::SimpleForeachOverInts |
||||||
|
|
||||||
|
.method public hidebysig specialname rtspecialname |
||||||
|
instance void .ctor() cil managed |
||||||
|
{ |
||||||
|
// Code size 7 (0x7) |
||||||
|
.maxstack 8 |
||||||
|
IL_0000: ldarg.0 |
||||||
|
IL_0001: call instance void [mscorlib]System.Object::.ctor() |
||||||
|
IL_0006: ret |
||||||
|
} // end of method NoForEachStatement::.ctor |
||||||
|
|
||||||
|
} // end of class ICSharpCode.Decompiler.Tests.TestCases.Ugly.NoForEachStatement |
||||||
|
|
||||||
|
|
||||||
|
// ============================================================= |
||||||
|
|
||||||
|
// *********** DISASSEMBLY COMPLETE *********************** |
||||||
@ -0,0 +1,128 @@ |
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Metadata version: v4.0.30319 |
||||||
|
.assembly extern mscorlib |
||||||
|
{ |
||||||
|
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4.. |
||||||
|
.ver 4:0:0:0 |
||||||
|
} |
||||||
|
.assembly prqfqkbt |
||||||
|
{ |
||||||
|
.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 |
||||||
|
63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows. |
||||||
|
.permissionset reqmin |
||||||
|
= {[mscorlib]System.Security.Permissions.SecurityPermissionAttribute = {property bool 'SkipVerification' = bool(true)}} |
||||||
|
.hash algorithm 0x00008004 |
||||||
|
.ver 0:0:0:0 |
||||||
|
} |
||||||
|
.module prqfqkbt.dll |
||||||
|
.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 |
||||||
|
|
||||||
|
|
||||||
|
// =============== CLASS MEMBERS DECLARATION =================== |
||||||
|
|
||||||
|
.class private auto ansi beforefieldinit ICSharpCode.Decompiler.Tests.TestCases.Ugly.NoForEachStatement |
||||||
|
extends [mscorlib]System.Object |
||||||
|
{ |
||||||
|
.method public hidebysig static void SimpleNonGenericForeach(class [mscorlib]System.Collections.IEnumerable enumerable) cil managed |
||||||
|
{ |
||||||
|
// Code size 50 (0x32) |
||||||
|
.maxstack 1 |
||||||
|
.locals init (object V_0, |
||||||
|
class [mscorlib]System.Collections.IEnumerator V_1, |
||||||
|
class [mscorlib]System.IDisposable V_2) |
||||||
|
IL_0000: ldarg.0 |
||||||
|
IL_0001: callvirt instance class [mscorlib]System.Collections.IEnumerator [mscorlib]System.Collections.IEnumerable::GetEnumerator() |
||||||
|
IL_0006: stloc.1 |
||||||
|
.try |
||||||
|
{ |
||||||
|
IL_0007: br.s IL_0016 |
||||||
|
|
||||||
|
IL_0009: ldloc.1 |
||||||
|
IL_000a: callvirt instance object [mscorlib]System.Collections.IEnumerator::get_Current() |
||||||
|
IL_000f: stloc.0 |
||||||
|
IL_0010: ldloc.0 |
||||||
|
IL_0011: call void [mscorlib]System.Console::WriteLine(object) |
||||||
|
IL_0016: ldloc.1 |
||||||
|
IL_0017: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext() |
||||||
|
IL_001c: brtrue.s IL_0009 |
||||||
|
|
||||||
|
IL_001e: leave.s IL_0031 |
||||||
|
|
||||||
|
} // end .try |
||||||
|
finally |
||||||
|
{ |
||||||
|
IL_0020: ldloc.1 |
||||||
|
IL_0021: isinst [mscorlib]System.IDisposable |
||||||
|
IL_0026: stloc.2 |
||||||
|
IL_0027: ldloc.2 |
||||||
|
IL_0028: brfalse.s IL_0030 |
||||||
|
|
||||||
|
IL_002a: ldloc.2 |
||||||
|
IL_002b: callvirt instance void [mscorlib]System.IDisposable::Dispose() |
||||||
|
IL_0030: endfinally |
||||||
|
} // end handler |
||||||
|
IL_0031: ret |
||||||
|
} // end of method NoForEachStatement::SimpleNonGenericForeach |
||||||
|
|
||||||
|
.method public hidebysig static void SimpleForeachOverInts(class [mscorlib]System.Collections.Generic.IEnumerable`1<int32> enumerable) cil managed |
||||||
|
{ |
||||||
|
// Code size 43 (0x2b) |
||||||
|
.maxstack 1 |
||||||
|
.locals init (int32 V_0, |
||||||
|
class [mscorlib]System.Collections.Generic.IEnumerator`1<int32> V_1) |
||||||
|
IL_0000: ldarg.0 |
||||||
|
IL_0001: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerator`1<!0> class [mscorlib]System.Collections.Generic.IEnumerable`1<int32>::GetEnumerator() |
||||||
|
IL_0006: stloc.1 |
||||||
|
.try |
||||||
|
{ |
||||||
|
IL_0007: br.s IL_0016 |
||||||
|
|
||||||
|
IL_0009: ldloc.1 |
||||||
|
IL_000a: callvirt instance !0 class [mscorlib]System.Collections.Generic.IEnumerator`1<int32>::get_Current() |
||||||
|
IL_000f: stloc.0 |
||||||
|
IL_0010: ldloc.0 |
||||||
|
IL_0011: call void [mscorlib]System.Console::WriteLine(int32) |
||||||
|
IL_0016: ldloc.1 |
||||||
|
IL_0017: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext() |
||||||
|
IL_001c: brtrue.s IL_0009 |
||||||
|
|
||||||
|
IL_001e: leave.s IL_002a |
||||||
|
|
||||||
|
} // end .try |
||||||
|
finally |
||||||
|
{ |
||||||
|
IL_0020: ldloc.1 |
||||||
|
IL_0021: brfalse.s IL_0029 |
||||||
|
|
||||||
|
IL_0023: ldloc.1 |
||||||
|
IL_0024: callvirt instance void [mscorlib]System.IDisposable::Dispose() |
||||||
|
IL_0029: endfinally |
||||||
|
} // end handler |
||||||
|
IL_002a: ret |
||||||
|
} // end of method NoForEachStatement::SimpleForeachOverInts |
||||||
|
|
||||||
|
.method public hidebysig specialname rtspecialname |
||||||
|
instance void .ctor() cil managed |
||||||
|
{ |
||||||
|
// Code size 7 (0x7) |
||||||
|
.maxstack 8 |
||||||
|
IL_0000: ldarg.0 |
||||||
|
IL_0001: call instance void [mscorlib]System.Object::.ctor() |
||||||
|
IL_0006: ret |
||||||
|
} // end of method NoForEachStatement::.ctor |
||||||
|
|
||||||
|
} // end of class ICSharpCode.Decompiler.Tests.TestCases.Ugly.NoForEachStatement |
||||||
|
|
||||||
|
|
||||||
|
// ============================================================= |
||||||
|
|
||||||
|
// *********** DISASSEMBLY COMPLETE *********************** |
||||||
@ -0,0 +1,126 @@ |
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Metadata version: v4.0.30319 |
||||||
|
.assembly extern mscorlib |
||||||
|
{ |
||||||
|
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4.. |
||||||
|
.ver 4:0:0:0 |
||||||
|
} |
||||||
|
.assembly NoForEachStatement |
||||||
|
{ |
||||||
|
.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 |
||||||
|
63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows. |
||||||
|
|
||||||
|
// --- The following custom attribute is added automatically, do not uncomment ------- |
||||||
|
// .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 02 00 00 00 00 00 ) |
||||||
|
|
||||||
|
.permissionset reqmin |
||||||
|
= {[mscorlib]System.Security.Permissions.SecurityPermissionAttribute = {property bool 'SkipVerification' = bool(true)}} |
||||||
|
.hash algorithm 0x00008004 |
||||||
|
.ver 0:0:0:0 |
||||||
|
} |
||||||
|
.module NoForEachStatement.dll |
||||||
|
.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 |
||||||
|
|
||||||
|
|
||||||
|
// =============== CLASS MEMBERS DECLARATION =================== |
||||||
|
|
||||||
|
.class private auto ansi beforefieldinit ICSharpCode.Decompiler.Tests.TestCases.Ugly.NoForEachStatement |
||||||
|
extends [mscorlib]System.Object |
||||||
|
{ |
||||||
|
.method public hidebysig static void SimpleNonGenericForeach(class [mscorlib]System.Collections.IEnumerable enumerable) cil managed |
||||||
|
{ |
||||||
|
// Code size 48 (0x30) |
||||||
|
.maxstack 1 |
||||||
|
.locals init (class [mscorlib]System.Collections.IEnumerator V_0, |
||||||
|
class [mscorlib]System.IDisposable V_1) |
||||||
|
IL_0000: ldarg.0 |
||||||
|
IL_0001: callvirt instance class [mscorlib]System.Collections.IEnumerator [mscorlib]System.Collections.IEnumerable::GetEnumerator() |
||||||
|
IL_0006: stloc.0 |
||||||
|
.try |
||||||
|
{ |
||||||
|
IL_0007: br.s IL_0014 |
||||||
|
|
||||||
|
IL_0009: ldloc.0 |
||||||
|
IL_000a: callvirt instance object [mscorlib]System.Collections.IEnumerator::get_Current() |
||||||
|
IL_000f: call void [mscorlib]System.Console::WriteLine(object) |
||||||
|
IL_0014: ldloc.0 |
||||||
|
IL_0015: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext() |
||||||
|
IL_001a: brtrue.s IL_0009 |
||||||
|
|
||||||
|
IL_001c: leave.s IL_002f |
||||||
|
|
||||||
|
} // end .try |
||||||
|
finally |
||||||
|
{ |
||||||
|
IL_001e: ldloc.0 |
||||||
|
IL_001f: isinst [mscorlib]System.IDisposable |
||||||
|
IL_0024: stloc.1 |
||||||
|
IL_0025: ldloc.1 |
||||||
|
IL_0026: brfalse.s IL_002e |
||||||
|
|
||||||
|
IL_0028: ldloc.1 |
||||||
|
IL_0029: callvirt instance void [mscorlib]System.IDisposable::Dispose() |
||||||
|
IL_002e: endfinally |
||||||
|
} // end handler |
||||||
|
IL_002f: ret |
||||||
|
} // end of method NoForEachStatement::SimpleNonGenericForeach |
||||||
|
|
||||||
|
.method public hidebysig static void SimpleForeachOverInts(class [mscorlib]System.Collections.Generic.IEnumerable`1<int32> enumerable) cil managed |
||||||
|
{ |
||||||
|
// Code size 41 (0x29) |
||||||
|
.maxstack 1 |
||||||
|
.locals init (class [mscorlib]System.Collections.Generic.IEnumerator`1<int32> V_0) |
||||||
|
IL_0000: ldarg.0 |
||||||
|
IL_0001: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerator`1<!0> class [mscorlib]System.Collections.Generic.IEnumerable`1<int32>::GetEnumerator() |
||||||
|
IL_0006: stloc.0 |
||||||
|
.try |
||||||
|
{ |
||||||
|
IL_0007: br.s IL_0014 |
||||||
|
|
||||||
|
IL_0009: ldloc.0 |
||||||
|
IL_000a: callvirt instance !0 class [mscorlib]System.Collections.Generic.IEnumerator`1<int32>::get_Current() |
||||||
|
IL_000f: call void [mscorlib]System.Console::WriteLine(int32) |
||||||
|
IL_0014: ldloc.0 |
||||||
|
IL_0015: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext() |
||||||
|
IL_001a: brtrue.s IL_0009 |
||||||
|
|
||||||
|
IL_001c: leave.s IL_0028 |
||||||
|
|
||||||
|
} // end .try |
||||||
|
finally |
||||||
|
{ |
||||||
|
IL_001e: ldloc.0 |
||||||
|
IL_001f: brfalse.s IL_0027 |
||||||
|
|
||||||
|
IL_0021: ldloc.0 |
||||||
|
IL_0022: callvirt instance void [mscorlib]System.IDisposable::Dispose() |
||||||
|
IL_0027: endfinally |
||||||
|
} // end handler |
||||||
|
IL_0028: ret |
||||||
|
} // end of method NoForEachStatement::SimpleForeachOverInts |
||||||
|
|
||||||
|
.method public hidebysig specialname rtspecialname |
||||||
|
instance void .ctor() cil managed |
||||||
|
{ |
||||||
|
// Code size 7 (0x7) |
||||||
|
.maxstack 8 |
||||||
|
IL_0000: ldarg.0 |
||||||
|
IL_0001: call instance void [mscorlib]System.Object::.ctor() |
||||||
|
IL_0006: ret |
||||||
|
} // end of method NoForEachStatement::.ctor |
||||||
|
|
||||||
|
} // end of class ICSharpCode.Decompiler.Tests.TestCases.Ugly.NoForEachStatement |
||||||
|
|
||||||
|
|
||||||
|
// ============================================================= |
||||||
|
|
||||||
|
// *********** DISASSEMBLY COMPLETE *********************** |
||||||
@ -0,0 +1,145 @@ |
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Metadata version: v4.0.30319 |
||||||
|
.assembly extern mscorlib |
||||||
|
{ |
||||||
|
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4.. |
||||||
|
.ver 4:0:0:0 |
||||||
|
} |
||||||
|
.assembly NoForEachStatement |
||||||
|
{ |
||||||
|
.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 |
||||||
|
63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows. |
||||||
|
|
||||||
|
// --- The following custom attribute is added automatically, do not uncomment ------- |
||||||
|
// .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 07 01 00 00 00 00 ) |
||||||
|
|
||||||
|
.permissionset reqmin |
||||||
|
= {[mscorlib]System.Security.Permissions.SecurityPermissionAttribute = {property bool 'SkipVerification' = bool(true)}} |
||||||
|
.hash algorithm 0x00008004 |
||||||
|
.ver 0:0:0:0 |
||||||
|
} |
||||||
|
.module NoForEachStatement.dll |
||||||
|
.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 |
||||||
|
|
||||||
|
|
||||||
|
// =============== CLASS MEMBERS DECLARATION =================== |
||||||
|
|
||||||
|
.class private auto ansi beforefieldinit ICSharpCode.Decompiler.Tests.TestCases.Ugly.NoForEachStatement |
||||||
|
extends [mscorlib]System.Object |
||||||
|
{ |
||||||
|
.method public hidebysig static void SimpleNonGenericForeach(class [mscorlib]System.Collections.IEnumerable enumerable) cil managed |
||||||
|
{ |
||||||
|
// Code size 56 (0x38) |
||||||
|
.maxstack 1 |
||||||
|
.locals init (class [mscorlib]System.Collections.IEnumerator V_0, |
||||||
|
object V_1, |
||||||
|
class [mscorlib]System.IDisposable V_2) |
||||||
|
IL_0000: nop |
||||||
|
IL_0001: nop |
||||||
|
IL_0002: ldarg.0 |
||||||
|
IL_0003: callvirt instance class [mscorlib]System.Collections.IEnumerator [mscorlib]System.Collections.IEnumerable::GetEnumerator() |
||||||
|
IL_0008: stloc.0 |
||||||
|
.try |
||||||
|
{ |
||||||
|
IL_0009: br.s IL_001b |
||||||
|
|
||||||
|
IL_000b: ldloc.0 |
||||||
|
IL_000c: callvirt instance object [mscorlib]System.Collections.IEnumerator::get_Current() |
||||||
|
IL_0011: stloc.1 |
||||||
|
IL_0012: nop |
||||||
|
IL_0013: ldloc.1 |
||||||
|
IL_0014: call void [mscorlib]System.Console::WriteLine(object) |
||||||
|
IL_0019: nop |
||||||
|
IL_001a: nop |
||||||
|
IL_001b: ldloc.0 |
||||||
|
IL_001c: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext() |
||||||
|
IL_0021: brtrue.s IL_000b |
||||||
|
|
||||||
|
IL_0023: leave.s IL_0037 |
||||||
|
|
||||||
|
} // end .try |
||||||
|
finally |
||||||
|
{ |
||||||
|
IL_0025: ldloc.0 |
||||||
|
IL_0026: isinst [mscorlib]System.IDisposable |
||||||
|
IL_002b: stloc.2 |
||||||
|
IL_002c: ldloc.2 |
||||||
|
IL_002d: brfalse.s IL_0036 |
||||||
|
|
||||||
|
IL_002f: ldloc.2 |
||||||
|
IL_0030: callvirt instance void [mscorlib]System.IDisposable::Dispose() |
||||||
|
IL_0035: nop |
||||||
|
IL_0036: endfinally |
||||||
|
} // end handler |
||||||
|
IL_0037: ret |
||||||
|
} // end of method NoForEachStatement::SimpleNonGenericForeach |
||||||
|
|
||||||
|
.method public hidebysig static void SimpleForeachOverInts(class [mscorlib]System.Collections.Generic.IEnumerable`1<int32> enumerable) cil managed |
||||||
|
{ |
||||||
|
// Code size 49 (0x31) |
||||||
|
.maxstack 1 |
||||||
|
.locals init (class [mscorlib]System.Collections.Generic.IEnumerator`1<int32> V_0, |
||||||
|
int32 V_1) |
||||||
|
IL_0000: nop |
||||||
|
IL_0001: nop |
||||||
|
IL_0002: ldarg.0 |
||||||
|
IL_0003: callvirt instance class [mscorlib]System.Collections.Generic.IEnumerator`1<!0> class [mscorlib]System.Collections.Generic.IEnumerable`1<int32>::GetEnumerator() |
||||||
|
IL_0008: stloc.0 |
||||||
|
.try |
||||||
|
{ |
||||||
|
IL_0009: br.s IL_001b |
||||||
|
|
||||||
|
IL_000b: ldloc.0 |
||||||
|
IL_000c: callvirt instance !0 class [mscorlib]System.Collections.Generic.IEnumerator`1<int32>::get_Current() |
||||||
|
IL_0011: stloc.1 |
||||||
|
IL_0012: nop |
||||||
|
IL_0013: ldloc.1 |
||||||
|
IL_0014: call void [mscorlib]System.Console::WriteLine(int32) |
||||||
|
IL_0019: nop |
||||||
|
IL_001a: nop |
||||||
|
IL_001b: ldloc.0 |
||||||
|
IL_001c: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext() |
||||||
|
IL_0021: brtrue.s IL_000b |
||||||
|
|
||||||
|
IL_0023: leave.s IL_0030 |
||||||
|
|
||||||
|
} // end .try |
||||||
|
finally |
||||||
|
{ |
||||||
|
IL_0025: ldloc.0 |
||||||
|
IL_0026: brfalse.s IL_002f |
||||||
|
|
||||||
|
IL_0028: ldloc.0 |
||||||
|
IL_0029: callvirt instance void [mscorlib]System.IDisposable::Dispose() |
||||||
|
IL_002e: nop |
||||||
|
IL_002f: endfinally |
||||||
|
} // end handler |
||||||
|
IL_0030: ret |
||||||
|
} // end of method NoForEachStatement::SimpleForeachOverInts |
||||||
|
|
||||||
|
.method public hidebysig specialname rtspecialname |
||||||
|
instance void .ctor() cil managed |
||||||
|
{ |
||||||
|
// Code size 8 (0x8) |
||||||
|
.maxstack 8 |
||||||
|
IL_0000: ldarg.0 |
||||||
|
IL_0001: call instance void [mscorlib]System.Object::.ctor() |
||||||
|
IL_0006: nop |
||||||
|
IL_0007: ret |
||||||
|
} // end of method NoForEachStatement::.ctor |
||||||
|
|
||||||
|
} // end of class ICSharpCode.Decompiler.Tests.TestCases.Ugly.NoForEachStatement |
||||||
|
|
||||||
|
|
||||||
|
// ============================================================= |
||||||
|
|
||||||
|
// *********** DISASSEMBLY COMPLETE *********************** |
||||||
|
After Width: | Height: | Size: 2.4 KiB |
@ -0,0 +1,240 @@ |
|||||||
|
// Copyright (c) 2009-2013 AlphaSierraPapa for the SharpDevelop Team
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||||
|
// software and associated documentation files (the "Software"), to deal in the Software
|
||||||
|
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
||||||
|
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
||||||
|
// to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in all copies or
|
||||||
|
// substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||||
|
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||||
|
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||||
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Linq; |
||||||
|
using System.Text; |
||||||
|
using System.Threading; |
||||||
|
using System.Xml.Linq; |
||||||
|
using ICSharpCode.Decompiler.Documentation; |
||||||
|
using ICSharpCode.Decompiler.TypeSystem; |
||||||
|
using ICSharpCode.Decompiler.Util; |
||||||
|
|
||||||
|
namespace ICSharpCode.Decompiler.Documentation |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Represents an element in the XML documentation.
|
||||||
|
/// Any occurrences of "<inheritdoc/>" are replaced with the inherited documentation.
|
||||||
|
/// </summary>
|
||||||
|
public class XmlDocumentationElement |
||||||
|
{ |
||||||
|
static XmlDocumentationElement Create(string documentationComment, IEntity declaringEntity) |
||||||
|
{ |
||||||
|
return new XmlDocumentationElement(XElement.Parse(documentationComment), declaringEntity, null); |
||||||
|
} |
||||||
|
|
||||||
|
readonly XElement element; |
||||||
|
readonly IEntity declaringEntity; |
||||||
|
readonly Func<string, IEntity> crefResolver; |
||||||
|
volatile string textContent; |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Inheritance level; used to prevent cyclic doc inheritance.
|
||||||
|
/// </summary>
|
||||||
|
int nestingLevel; |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new documentation element.
|
||||||
|
/// </summary>
|
||||||
|
public XmlDocumentationElement(XElement element, IEntity declaringEntity, Func<string, IEntity> crefResolver) |
||||||
|
{ |
||||||
|
if (element == null) |
||||||
|
throw new ArgumentNullException("element"); |
||||||
|
this.element = element; |
||||||
|
this.declaringEntity = declaringEntity; |
||||||
|
this.crefResolver = crefResolver; |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new documentation element.
|
||||||
|
/// </summary>
|
||||||
|
public XmlDocumentationElement(string text, IEntity declaringEntity) |
||||||
|
{ |
||||||
|
if (text == null) |
||||||
|
throw new ArgumentNullException("text"); |
||||||
|
this.declaringEntity = declaringEntity; |
||||||
|
this.textContent = text; |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the entity on which this documentation was originally declared.
|
||||||
|
/// May return null.
|
||||||
|
/// </summary>
|
||||||
|
public IEntity DeclaringEntity { |
||||||
|
get { return declaringEntity; } |
||||||
|
} |
||||||
|
|
||||||
|
IEntity referencedEntity; |
||||||
|
volatile bool referencedEntityInitialized; |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the entity referenced by the 'cref' attribute.
|
||||||
|
/// May return null.
|
||||||
|
/// </summary>
|
||||||
|
public IEntity ReferencedEntity { |
||||||
|
get { |
||||||
|
if (!referencedEntityInitialized) { |
||||||
|
string cref = GetAttribute("cref"); |
||||||
|
if (!string.IsNullOrEmpty(cref) && crefResolver != null) |
||||||
|
referencedEntity = crefResolver(cref); |
||||||
|
referencedEntityInitialized = true; |
||||||
|
} |
||||||
|
return referencedEntity; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the element name.
|
||||||
|
/// </summary>
|
||||||
|
public string Name { |
||||||
|
get { |
||||||
|
return element != null ? element.Name.LocalName : string.Empty; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the attribute value.
|
||||||
|
/// </summary>
|
||||||
|
public string GetAttribute(string name) |
||||||
|
{ |
||||||
|
return element?.Attribute(name)?.Value ?? string.Empty; |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets whether this is a pure text node.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsTextNode { |
||||||
|
get { return element == null; } |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the text content.
|
||||||
|
/// </summary>
|
||||||
|
public string TextContent { |
||||||
|
get { |
||||||
|
if (textContent == null) { |
||||||
|
StringBuilder b = new StringBuilder(); |
||||||
|
foreach (var child in this.Children) |
||||||
|
b.Append(child.TextContent); |
||||||
|
textContent = b.ToString(); |
||||||
|
} |
||||||
|
return textContent; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
IList<XmlDocumentationElement> children; |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the child elements.
|
||||||
|
/// </summary>
|
||||||
|
public IList<XmlDocumentationElement> Children { |
||||||
|
get { |
||||||
|
if (element == null) |
||||||
|
return EmptyList<XmlDocumentationElement>.Instance; |
||||||
|
return LazyInitializer.EnsureInitialized( |
||||||
|
ref this.children, |
||||||
|
() => CreateElements(element.Nodes(), declaringEntity, crefResolver, nestingLevel)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static readonly string[] doNotInheritIfAlreadyPresent = { |
||||||
|
"example", "exclude", "filterpriority", "preliminary", "summary", |
||||||
|
"remarks", "returns", "threadsafety", "value" |
||||||
|
}; |
||||||
|
|
||||||
|
static List<XmlDocumentationElement> CreateElements(IEnumerable<XObject> childObjects, IEntity declaringEntity, Func<string, IEntity> crefResolver, int nestingLevel) |
||||||
|
{ |
||||||
|
List<XmlDocumentationElement> list = new List<XmlDocumentationElement>(); |
||||||
|
foreach (var child in childObjects) { |
||||||
|
var childText = child as XText; |
||||||
|
var childTag = child as XCData; |
||||||
|
var childElement = child as XElement; |
||||||
|
if (childText != null) { |
||||||
|
list.Add(new XmlDocumentationElement(childText.Value, declaringEntity)); |
||||||
|
} else if (childTag != null) { |
||||||
|
list.Add(new XmlDocumentationElement(childTag.Value, declaringEntity)); |
||||||
|
} else if (childElement != null) { |
||||||
|
if (nestingLevel < 5 && childElement.Name == "inheritdoc") { |
||||||
|
string cref = childElement.Attribute("cref").Value; |
||||||
|
IEntity inheritedFrom = null; |
||||||
|
string inheritedDocumentation = null; |
||||||
|
if (cref != null) { |
||||||
|
inheritedFrom = crefResolver(cref); |
||||||
|
if (inheritedFrom != null) |
||||||
|
inheritedDocumentation = inheritedFrom.GetDocumentation(); |
||||||
|
} else { |
||||||
|
foreach (IMember baseMember in InheritanceHelper.GetBaseMembers((IMember)declaringEntity, includeImplementedInterfaces: true)) { |
||||||
|
inheritedDocumentation = baseMember.GetDocumentation(); |
||||||
|
if (inheritedDocumentation != null) { |
||||||
|
inheritedFrom = baseMember; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (inheritedDocumentation != null) { |
||||||
|
var doc = XDocument.Parse(inheritedDocumentation); |
||||||
|
|
||||||
|
// XPath filter not yet implemented
|
||||||
|
if (childElement.Parent == null && childElement.Attribute("select").Value == null) { |
||||||
|
// Inheriting documentation at the root level
|
||||||
|
List<string> doNotInherit = new List<string>(); |
||||||
|
doNotInherit.Add("overloads"); |
||||||
|
doNotInherit.AddRange(childObjects.OfType<XElement>().Select(e => e.Name.LocalName).Intersect( |
||||||
|
doNotInheritIfAlreadyPresent)); |
||||||
|
|
||||||
|
var inheritedChildren = doc.Nodes().Where( |
||||||
|
inheritedObject => { |
||||||
|
XElement inheritedElement = inheritedObject as XElement; |
||||||
|
return !(inheritedElement != null && doNotInherit.Contains(inheritedElement.Name.LocalName)); |
||||||
|
}); |
||||||
|
|
||||||
|
list.AddRange(CreateElements(inheritedChildren, inheritedFrom, crefResolver, nestingLevel + 1)); |
||||||
|
} |
||||||
|
} |
||||||
|
} else { |
||||||
|
list.Add(new XmlDocumentationElement(childElement, declaringEntity, crefResolver) { nestingLevel = nestingLevel }); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
if (list.Count > 0 && list[0].IsTextNode) { |
||||||
|
if (string.IsNullOrWhiteSpace(list[0].textContent)) |
||||||
|
list.RemoveAt(0); |
||||||
|
else |
||||||
|
list[0].textContent = list[0].textContent.TrimStart(); |
||||||
|
} |
||||||
|
if (list.Count > 0 && list[list.Count - 1].IsTextNode) { |
||||||
|
if (string.IsNullOrWhiteSpace(list[list.Count - 1].textContent)) |
||||||
|
list.RemoveAt(list.Count - 1); |
||||||
|
else |
||||||
|
list[list.Count - 1].textContent = list[list.Count - 1].textContent.TrimEnd(); |
||||||
|
} |
||||||
|
return list; |
||||||
|
} |
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override string ToString() |
||||||
|
{ |
||||||
|
if (element != null) |
||||||
|
return "<" + element.Name + ">"; |
||||||
|
else |
||||||
|
return this.TextContent; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,551 @@ |
|||||||
|
// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||||
|
// software and associated documentation files (the "Software"), to deal in the Software
|
||||||
|
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
||||||
|
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
||||||
|
// to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in all copies or
|
||||||
|
// substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||||
|
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||||||
|
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||||
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Diagnostics; |
||||||
|
using System.IO; |
||||||
|
using System.Linq; |
||||||
|
using System.Text; |
||||||
|
using System.Text.RegularExpressions; |
||||||
|
using System.Windows; |
||||||
|
using System.Windows.Controls; |
||||||
|
using System.Windows.Documents; |
||||||
|
using System.Windows.Media; |
||||||
|
using System.Xml; |
||||||
|
using System.Xml.Linq; |
||||||
|
using ICSharpCode.AvalonEdit.Document; |
||||||
|
using ICSharpCode.AvalonEdit.Highlighting; |
||||||
|
using ICSharpCode.AvalonEdit.Utils; |
||||||
|
using ICSharpCode.Decompiler.Documentation; |
||||||
|
using ICSharpCode.Decompiler.Output; |
||||||
|
using ICSharpCode.Decompiler.TypeSystem; |
||||||
|
using ICSharpCode.ILSpy.Options; |
||||||
|
|
||||||
|
namespace ICSharpCode.ILSpy.TextView |
||||||
|
{ |
||||||
|
/// <summary>
|
||||||
|
/// Renders XML documentation into a WPF <see cref="FlowDocument"/>.
|
||||||
|
/// </summary>
|
||||||
|
public class DocumentationUIBuilder |
||||||
|
{ |
||||||
|
readonly IAmbience ambience; |
||||||
|
readonly IHighlightingDefinition highlightingDefinition; |
||||||
|
readonly FlowDocument document; |
||||||
|
BlockCollection blockCollection; |
||||||
|
InlineCollection inlineCollection; |
||||||
|
|
||||||
|
public DocumentationUIBuilder(IAmbience ambience, IHighlightingDefinition highlightingDefinition) |
||||||
|
{ |
||||||
|
this.ambience = ambience; |
||||||
|
this.highlightingDefinition = highlightingDefinition; |
||||||
|
this.document = new FlowDocument(); |
||||||
|
this.blockCollection = document.Blocks; |
||||||
|
|
||||||
|
this.ShowSummary = true; |
||||||
|
this.ShowAllParameters = true; |
||||||
|
this.ShowReturns = true; |
||||||
|
this.ShowThreadSafety = true; |
||||||
|
this.ShowExceptions = true; |
||||||
|
this.ShowTypeParameters = true; |
||||||
|
|
||||||
|
this.ShowExample = true; |
||||||
|
this.ShowPreliminary = true; |
||||||
|
this.ShowSeeAlso = true; |
||||||
|
this.ShowValue = true; |
||||||
|
this.ShowPermissions = true; |
||||||
|
this.ShowRemarks = true; |
||||||
|
} |
||||||
|
|
||||||
|
public FlowDocument CreateDocument() |
||||||
|
{ |
||||||
|
FlushAddedText(true); |
||||||
|
return document; |
||||||
|
} |
||||||
|
|
||||||
|
public bool ShowExceptions { get; set; } |
||||||
|
public bool ShowPermissions { get; set; } |
||||||
|
public bool ShowExample { get; set; } |
||||||
|
public bool ShowPreliminary { get; set; } |
||||||
|
public bool ShowRemarks { get; set; } |
||||||
|
public bool ShowSummary { get; set; } |
||||||
|
public bool ShowReturns { get; set; } |
||||||
|
public bool ShowSeeAlso { get; set; } |
||||||
|
public bool ShowThreadSafety { get; set; } |
||||||
|
public bool ShowTypeParameters { get; set; } |
||||||
|
public bool ShowValue { get; set; } |
||||||
|
public bool ShowAllParameters { get; set; } |
||||||
|
|
||||||
|
public void AddCodeBlock(string textContent, bool keepLargeMargin = false) |
||||||
|
{ |
||||||
|
var document = new TextDocument(textContent); |
||||||
|
var highlighter = new DocumentHighlighter(document, highlightingDefinition); |
||||||
|
var richText = DocumentPrinter.ConvertTextDocumentToRichText(document, highlighter).ToRichTextModel(); |
||||||
|
|
||||||
|
var block = new Paragraph(); |
||||||
|
block.Inlines.AddRange(richText.CreateRuns(document)); |
||||||
|
block.FontFamily = GetCodeFont(); |
||||||
|
if (!keepLargeMargin) |
||||||
|
block.Margin = new Thickness(0, 6, 0, 6); |
||||||
|
AddBlock(block); |
||||||
|
} |
||||||
|
|
||||||
|
public void AddSignatureBlock(string signature, RichTextModel highlighting = null) |
||||||
|
{ |
||||||
|
var document = new TextDocument(signature); |
||||||
|
var richText = highlighting ?? DocumentPrinter.ConvertTextDocumentToRichText(document, new DocumentHighlighter(document, highlightingDefinition)).ToRichTextModel(); |
||||||
|
var block = new Paragraph(); |
||||||
|
// HACK: measure width of signature using a TextBlock
|
||||||
|
// Paragraph sadly does not support TextWrapping.NoWrap
|
||||||
|
var text = new TextBlock { |
||||||
|
FontFamily = GetCodeFont(), |
||||||
|
FontSize = DisplaySettingsPanel.CurrentDisplaySettings.SelectedFontSize, |
||||||
|
TextAlignment = TextAlignment.Left |
||||||
|
}; |
||||||
|
text.Inlines.AddRange(richText.CreateRuns(document)); |
||||||
|
text.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); |
||||||
|
this.document.MinPageWidth = Math.Min(text.DesiredSize.Width, MainWindow.Instance.ActualWidth); |
||||||
|
block.Inlines.AddRange(richText.CreateRuns(document)); |
||||||
|
block.FontFamily = GetCodeFont(); |
||||||
|
block.TextAlignment = TextAlignment.Left; |
||||||
|
AddBlock(block); |
||||||
|
} |
||||||
|
|
||||||
|
public void AddXmlDocumentation(string xmlDocumentation, IEntity declaringEntity, Func<string, IEntity> resolver) |
||||||
|
{ |
||||||
|
if (xmlDocumentation == null) |
||||||
|
return; |
||||||
|
Debug.WriteLine(xmlDocumentation); |
||||||
|
var xml = XElement.Parse("<doc>" + xmlDocumentation + "</doc>"); |
||||||
|
AddDocumentationElement(new XmlDocumentationElement(xml, declaringEntity, resolver)); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets/Sets the name of the parameter that should be shown.
|
||||||
|
/// </summary>
|
||||||
|
public string ParameterName { get; set; } |
||||||
|
|
||||||
|
public void AddDocumentationElement(XmlDocumentationElement element) |
||||||
|
{ |
||||||
|
if (element == null) |
||||||
|
throw new ArgumentNullException("element"); |
||||||
|
if (element.IsTextNode) { |
||||||
|
AddText(element.TextContent); |
||||||
|
return; |
||||||
|
} |
||||||
|
switch (element.Name) { |
||||||
|
case "b": |
||||||
|
AddSpan(new Bold(), element.Children); |
||||||
|
break; |
||||||
|
case "i": |
||||||
|
AddSpan(new Italic(), element.Children); |
||||||
|
break; |
||||||
|
case "c": |
||||||
|
AddSpan(new Span { FontFamily = GetCodeFont() }, element.Children); |
||||||
|
break; |
||||||
|
case "code": |
||||||
|
AddCodeBlock(element.TextContent); |
||||||
|
break; |
||||||
|
case "example": |
||||||
|
if (ShowExample) |
||||||
|
AddSection("Example: ", element.Children); |
||||||
|
break; |
||||||
|
case "exception": |
||||||
|
if (ShowExceptions) |
||||||
|
AddException(element.ReferencedEntity, element.Children); |
||||||
|
break; |
||||||
|
case "list": |
||||||
|
AddList(element.GetAttribute("type"), element.Children); |
||||||
|
break; |
||||||
|
//case "note":
|
||||||
|
// throw new NotImplementedException();
|
||||||
|
case "para": |
||||||
|
AddParagraph(new Paragraph { Margin = new Thickness(0, 5, 0, 5) }, element.Children); |
||||||
|
break; |
||||||
|
case "param": |
||||||
|
if (ShowAllParameters || (ParameterName != null && ParameterName == element.GetAttribute("name"))) |
||||||
|
AddParam(element.GetAttribute("name"), element.Children); |
||||||
|
break; |
||||||
|
case "paramref": |
||||||
|
AddParamRef(element.GetAttribute("name")); |
||||||
|
break; |
||||||
|
case "permission": |
||||||
|
if (ShowPermissions) |
||||||
|
AddPermission(element.ReferencedEntity, element.Children); |
||||||
|
break; |
||||||
|
case "preliminary": |
||||||
|
if (ShowPreliminary) |
||||||
|
AddPreliminary(element.Children); |
||||||
|
break; |
||||||
|
case "remarks": |
||||||
|
if (ShowRemarks) |
||||||
|
AddSection("Remarks: ", element.Children); |
||||||
|
break; |
||||||
|
case "returns": |
||||||
|
if (ShowReturns) |
||||||
|
AddSection("Returns: ", element.Children); |
||||||
|
break; |
||||||
|
case "see": |
||||||
|
AddSee(element); |
||||||
|
break; |
||||||
|
case "seealso": |
||||||
|
if (inlineCollection != null) |
||||||
|
AddSee(element); |
||||||
|
else if (ShowSeeAlso) |
||||||
|
AddSection(new Run("See also: "), () => AddSee(element)); |
||||||
|
break; |
||||||
|
case "summary": |
||||||
|
if (ShowSummary) |
||||||
|
AddSection("Summary: ", element.Children); |
||||||
|
break; |
||||||
|
case "threadsafety": |
||||||
|
if (ShowThreadSafety) |
||||||
|
AddThreadSafety(ParseBool(element.GetAttribute("static")), ParseBool(element.GetAttribute("instance")), element.Children); |
||||||
|
break; |
||||||
|
case "typeparam": |
||||||
|
if (ShowTypeParameters) |
||||||
|
AddSection("Type parameter " + element.GetAttribute("name") + ": ", element.Children); |
||||||
|
break; |
||||||
|
case "typeparamref": |
||||||
|
AddText(element.GetAttribute("name")); |
||||||
|
break; |
||||||
|
case "value": |
||||||
|
if (ShowValue) |
||||||
|
AddSection("Value: ", element.Children); |
||||||
|
break; |
||||||
|
case "exclude": |
||||||
|
case "filterpriority": |
||||||
|
case "overloads": |
||||||
|
// ignore children
|
||||||
|
break; |
||||||
|
case "br": |
||||||
|
AddLineBreak(); |
||||||
|
break; |
||||||
|
default: |
||||||
|
foreach (var child in element.Children) |
||||||
|
AddDocumentationElement(child); |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void AddList(string type, IEnumerable<XmlDocumentationElement> items) |
||||||
|
{ |
||||||
|
List list = new List(); |
||||||
|
AddBlock(list); |
||||||
|
list.Margin = new Thickness(0, 5, 0, 5); |
||||||
|
if (type == "number") |
||||||
|
list.MarkerStyle = TextMarkerStyle.Decimal; |
||||||
|
else if (type == "bullet") |
||||||
|
list.MarkerStyle = TextMarkerStyle.Disc; |
||||||
|
var oldBlockCollection = blockCollection; |
||||||
|
try { |
||||||
|
foreach (var itemElement in items) { |
||||||
|
if (itemElement.Name == "listheader" || itemElement.Name == "item") { |
||||||
|
ListItem item = new ListItem(); |
||||||
|
blockCollection = item.Blocks; |
||||||
|
inlineCollection = null; |
||||||
|
foreach (var prop in itemElement.Children) { |
||||||
|
AddDocumentationElement(prop); |
||||||
|
} |
||||||
|
FlushAddedText(false); |
||||||
|
list.ListItems.Add(item); |
||||||
|
} |
||||||
|
} |
||||||
|
} finally { |
||||||
|
blockCollection = oldBlockCollection; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
bool? ParseBool(string input) |
||||||
|
{ |
||||||
|
if (bool.TryParse(input, out bool result)) |
||||||
|
return result; |
||||||
|
else |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
void AddThreadSafety(bool? staticThreadSafe, bool? instanceThreadSafe, IEnumerable<XmlDocumentationElement> children) |
||||||
|
{ |
||||||
|
AddSection( |
||||||
|
new Run("Thread-safety: "), |
||||||
|
delegate { |
||||||
|
if (staticThreadSafe == true) |
||||||
|
AddText("Any public static members of this type are thread safe. "); |
||||||
|
else if (staticThreadSafe == false) |
||||||
|
AddText("The static members of this type are not thread safe. "); |
||||||
|
|
||||||
|
if (instanceThreadSafe == true) |
||||||
|
AddText("Any public instance members of this type are thread safe. "); |
||||||
|
else if (instanceThreadSafe == false) |
||||||
|
AddText("Any instance members are not guaranteed to be thread safe. "); |
||||||
|
|
||||||
|
foreach (var child in children) |
||||||
|
AddDocumentationElement(child); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
void AddException(IEntity referencedEntity, IList<XmlDocumentationElement> children) |
||||||
|
{ |
||||||
|
Span span = new Span(); |
||||||
|
if (referencedEntity != null) |
||||||
|
span.Inlines.Add(ConvertReference(referencedEntity)); |
||||||
|
else |
||||||
|
span.Inlines.Add("Exception"); |
||||||
|
span.Inlines.Add(": "); |
||||||
|
AddSection(span, children); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
void AddPermission(IEntity referencedEntity, IList<XmlDocumentationElement> children) |
||||||
|
{ |
||||||
|
Span span = new Span(); |
||||||
|
span.Inlines.Add("Permission"); |
||||||
|
if (referencedEntity != null) { |
||||||
|
span.Inlines.Add(" "); |
||||||
|
span.Inlines.Add(ConvertReference(referencedEntity)); |
||||||
|
} |
||||||
|
span.Inlines.Add(": "); |
||||||
|
AddSection(span, children); |
||||||
|
} |
||||||
|
|
||||||
|
Inline ConvertReference(IEntity referencedEntity) |
||||||
|
{ |
||||||
|
var h = new Hyperlink(new Run(ambience.ConvertSymbol(referencedEntity))); |
||||||
|
h.Click += (sender, e) => { |
||||||
|
MainWindow.Instance.JumpToReference(referencedEntity); |
||||||
|
}; |
||||||
|
return h; |
||||||
|
} |
||||||
|
|
||||||
|
void AddParam(string name, IEnumerable<XmlDocumentationElement> children) |
||||||
|
{ |
||||||
|
Span span = new Span(); |
||||||
|
span.Inlines.Add(new Run(name ?? string.Empty) { FontStyle = FontStyles.Italic }); |
||||||
|
span.Inlines.Add(": "); |
||||||
|
AddSection(span, children); |
||||||
|
} |
||||||
|
|
||||||
|
void AddParamRef(string name) |
||||||
|
{ |
||||||
|
if (name != null) { |
||||||
|
AddInline(new Run(name) { FontStyle = FontStyles.Italic }); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void AddPreliminary(IEnumerable<XmlDocumentationElement> children) |
||||||
|
{ |
||||||
|
if (children.Any()) { |
||||||
|
foreach (var child in children) |
||||||
|
AddDocumentationElement(child); |
||||||
|
} else { |
||||||
|
AddText("[This is preliminary documentation and subject to change.]"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void AddSee(XmlDocumentationElement element) |
||||||
|
{ |
||||||
|
IEntity referencedEntity = element.ReferencedEntity; |
||||||
|
if (referencedEntity != null) { |
||||||
|
if (element.Children.Any()) { |
||||||
|
Hyperlink link = new Hyperlink(); |
||||||
|
link.Click += (sender, e) => { |
||||||
|
MainWindow.Instance.JumpToReference(referencedEntity); |
||||||
|
}; |
||||||
|
AddSpan(link, element.Children); |
||||||
|
} else { |
||||||
|
AddInline(ConvertReference(referencedEntity)); |
||||||
|
} |
||||||
|
} else if (element.GetAttribute("langword") != null) { |
||||||
|
AddInline(new Run(element.GetAttribute("langword")) { FontFamily = GetCodeFont() }); |
||||||
|
} else if (element.GetAttribute("href") != null) { |
||||||
|
Uri uri; |
||||||
|
if (Uri.TryCreate(element.GetAttribute("href"), UriKind.Absolute, out uri)) { |
||||||
|
if (element.Children.Any()) { |
||||||
|
AddSpan(new Hyperlink { NavigateUri = uri }, element.Children); |
||||||
|
} else { |
||||||
|
AddInline(new Hyperlink(new Run(element.GetAttribute("href"))) { NavigateUri = uri }); |
||||||
|
} |
||||||
|
} |
||||||
|
} else { |
||||||
|
// Invalid reference: print the cref value
|
||||||
|
AddText(element.GetAttribute("cref")); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static string GetCref(string cref) |
||||||
|
{ |
||||||
|
if (cref == null || cref.Trim().Length==0) { |
||||||
|
return ""; |
||||||
|
} |
||||||
|
if (cref.Length < 2) { |
||||||
|
return cref; |
||||||
|
} |
||||||
|
if (cref.Substring(1, 1) == ":") { |
||||||
|
return cref.Substring(2, cref.Length - 2); |
||||||
|
} |
||||||
|
return cref; |
||||||
|
} |
||||||
|
|
||||||
|
FontFamily GetCodeFont() |
||||||
|
{ |
||||||
|
return DisplaySettingsPanel.CurrentDisplaySettings.SelectedFont; |
||||||
|
} |
||||||
|
|
||||||
|
public void AddInline(Inline inline) |
||||||
|
{ |
||||||
|
FlushAddedText(false); |
||||||
|
if (inlineCollection == null) { |
||||||
|
var para = new Paragraph(); |
||||||
|
para.Margin = new Thickness(0, 0, 0, 5); |
||||||
|
inlineCollection = para.Inlines; |
||||||
|
AddBlock(para); |
||||||
|
} |
||||||
|
inlineCollection.Add(inline); |
||||||
|
ignoreWhitespace = false; |
||||||
|
} |
||||||
|
|
||||||
|
void AddSection(string title, IEnumerable<XmlDocumentationElement> children) |
||||||
|
{ |
||||||
|
AddSection(new Run(title), children); |
||||||
|
} |
||||||
|
|
||||||
|
void AddSection(Inline title, IEnumerable<XmlDocumentationElement> children) |
||||||
|
{ |
||||||
|
AddSection( |
||||||
|
title, delegate { |
||||||
|
foreach (var child in children) |
||||||
|
AddDocumentationElement(child); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
void AddSection(Inline title, Action addChildren) |
||||||
|
{ |
||||||
|
var section = new Section(); |
||||||
|
AddBlock(section); |
||||||
|
var oldBlockCollection = blockCollection; |
||||||
|
try { |
||||||
|
blockCollection = section.Blocks; |
||||||
|
inlineCollection = null; |
||||||
|
|
||||||
|
if (title != null) |
||||||
|
AddInline(new Bold(title)); |
||||||
|
|
||||||
|
addChildren(); |
||||||
|
FlushAddedText(false); |
||||||
|
} finally { |
||||||
|
blockCollection = oldBlockCollection; |
||||||
|
inlineCollection = null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void AddParagraph(Paragraph para, IEnumerable<XmlDocumentationElement> children) |
||||||
|
{ |
||||||
|
AddBlock(para); |
||||||
|
try { |
||||||
|
inlineCollection = para.Inlines; |
||||||
|
|
||||||
|
foreach (var child in children) |
||||||
|
AddDocumentationElement(child); |
||||||
|
FlushAddedText(false); |
||||||
|
} finally { |
||||||
|
inlineCollection = null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void AddSpan(Span span, IEnumerable<XmlDocumentationElement> children) |
||||||
|
{ |
||||||
|
AddInline(span); |
||||||
|
var oldInlineCollection = inlineCollection; |
||||||
|
try { |
||||||
|
inlineCollection = span.Inlines; |
||||||
|
foreach (var child in children) |
||||||
|
AddDocumentationElement(child); |
||||||
|
FlushAddedText(false); |
||||||
|
} finally { |
||||||
|
inlineCollection = oldInlineCollection; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void AddBlock(Block block) |
||||||
|
{ |
||||||
|
FlushAddedText(true); |
||||||
|
blockCollection.Add(block); |
||||||
|
} |
||||||
|
|
||||||
|
StringBuilder addedText = new StringBuilder(); |
||||||
|
bool ignoreWhitespace; |
||||||
|
|
||||||
|
public void AddLineBreak() |
||||||
|
{ |
||||||
|
TrimEndOfAddedText(); |
||||||
|
addedText.AppendLine(); |
||||||
|
ignoreWhitespace = true; |
||||||
|
} |
||||||
|
|
||||||
|
public void AddText(string textContent) |
||||||
|
{ |
||||||
|
if (string.IsNullOrEmpty(textContent)) |
||||||
|
return; |
||||||
|
for (int i = 0; i < textContent.Length; i++) { |
||||||
|
char c = textContent[i]; |
||||||
|
if (c == '\n' && IsEmptyLineBefore(textContent, i)) { |
||||||
|
AddLineBreak(); // empty line -> line break
|
||||||
|
} else if (char.IsWhiteSpace(c)) { |
||||||
|
// any whitespace sequence gets converted to a single space (like HTML)
|
||||||
|
if (!ignoreWhitespace) { |
||||||
|
addedText.Append(' '); |
||||||
|
ignoreWhitespace = true; |
||||||
|
} |
||||||
|
} else { |
||||||
|
addedText.Append(c); |
||||||
|
ignoreWhitespace = false; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
bool IsEmptyLineBefore(string text, int i) |
||||||
|
{ |
||||||
|
// Skip previous whitespace
|
||||||
|
do { |
||||||
|
i--; |
||||||
|
} while (i >= 0 && (text[i] == ' ' || text[i] == '\r')); |
||||||
|
// Check if previous non-whitespace char is \n
|
||||||
|
return i >= 0 && text[i] == '\n'; |
||||||
|
} |
||||||
|
|
||||||
|
void TrimEndOfAddedText() |
||||||
|
{ |
||||||
|
while (addedText.Length > 0 && addedText[addedText.Length - 1] == ' ') { |
||||||
|
addedText.Length--; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void FlushAddedText(bool trim) |
||||||
|
{ |
||||||
|
if (trim) // trim end of current text element
|
||||||
|
TrimEndOfAddedText(); |
||||||
|
if (addedText.Length == 0) |
||||||
|
return; |
||||||
|
string text = addedText.ToString(); |
||||||
|
addedText.Length = 0; |
||||||
|
AddInline(new Run(text)); |
||||||
|
ignoreWhitespace = trim; // trim start of next text element
|
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -1,137 +0,0 @@ |
|||||||
// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
|
|
||||||
//
|
|
||||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
|
||||||
// software and associated documentation files (the "Software"), to deal in the Software
|
|
||||||
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
|
||||||
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
|
||||||
// to whom the Software is furnished to do so, subject to the following conditions:
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be included in all copies or
|
|
||||||
// substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
|
||||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
|
||||||
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
|
||||||
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
|
||||||
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
||||||
// DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
||||||
using System; |
|
||||||
using System.Diagnostics; |
|
||||||
using System.IO; |
|
||||||
using System.Text; |
|
||||||
using System.Text.RegularExpressions; |
|
||||||
using System.Windows.Controls; |
|
||||||
using System.Xml; |
|
||||||
|
|
||||||
namespace ICSharpCode.ILSpy.TextView |
|
||||||
{ |
|
||||||
/// <summary>
|
|
||||||
/// Renders XML documentation into a WPF <see cref="TextBlock"/>.
|
|
||||||
/// </summary>
|
|
||||||
public class XmlDocRenderer |
|
||||||
{ |
|
||||||
readonly StringBuilder ret = new StringBuilder(); |
|
||||||
|
|
||||||
public void AppendText(string text) |
|
||||||
{ |
|
||||||
ret.Append(text); |
|
||||||
} |
|
||||||
|
|
||||||
public void AddXmlDocumentation(string xmlDocumentation) |
|
||||||
{ |
|
||||||
if (xmlDocumentation == null) |
|
||||||
return; |
|
||||||
Debug.WriteLine(xmlDocumentation); |
|
||||||
try { |
|
||||||
XmlTextReader r = new XmlTextReader(new StringReader("<docroot>" + xmlDocumentation + "</docroot>")); |
|
||||||
r.XmlResolver = null; |
|
||||||
AddXmlDocumentation(r); |
|
||||||
} catch (XmlException) { |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
static readonly Regex whitespace = new Regex(@"\s+"); |
|
||||||
|
|
||||||
public void AddXmlDocumentation(XmlReader xml) |
|
||||||
{ |
|
||||||
while (xml.Read()) { |
|
||||||
if (xml.NodeType == XmlNodeType.Element) { |
|
||||||
string elname = xml.Name.ToLowerInvariant(); |
|
||||||
switch (elname) { |
|
||||||
case "filterpriority": |
|
||||||
case "remarks": |
|
||||||
xml.Skip(); |
|
||||||
break; |
|
||||||
case "example": |
|
||||||
ret.Append(Environment.NewLine); |
|
||||||
ret.Append("Example:"); |
|
||||||
ret.Append(Environment.NewLine); |
|
||||||
break; |
|
||||||
case "exception": |
|
||||||
ret.Append(Environment.NewLine); |
|
||||||
ret.Append(GetCref(xml["cref"])); |
|
||||||
ret.Append(": "); |
|
||||||
break; |
|
||||||
case "returns": |
|
||||||
ret.Append(Environment.NewLine); |
|
||||||
ret.Append("Returns: "); |
|
||||||
break; |
|
||||||
case "see": |
|
||||||
ret.Append(GetCref(xml["cref"])); |
|
||||||
ret.Append(xml["langword"]); |
|
||||||
break; |
|
||||||
case "seealso": |
|
||||||
ret.Append(Environment.NewLine); |
|
||||||
ret.Append("See also: "); |
|
||||||
ret.Append(GetCref(xml["cref"])); |
|
||||||
break; |
|
||||||
case "paramref": |
|
||||||
ret.Append(xml["name"]); |
|
||||||
break; |
|
||||||
case "param": |
|
||||||
ret.Append(Environment.NewLine); |
|
||||||
ret.Append(whitespace.Replace(xml["name"].Trim()," ")); |
|
||||||
ret.Append(": "); |
|
||||||
break; |
|
||||||
case "typeparam": |
|
||||||
ret.Append(Environment.NewLine); |
|
||||||
ret.Append(whitespace.Replace(xml["name"].Trim()," ")); |
|
||||||
ret.Append(": "); |
|
||||||
break; |
|
||||||
case "value": |
|
||||||
ret.Append(Environment.NewLine); |
|
||||||
ret.Append("Value: "); |
|
||||||
ret.Append(Environment.NewLine); |
|
||||||
break; |
|
||||||
case "br": |
|
||||||
case "para": |
|
||||||
ret.Append(Environment.NewLine); |
|
||||||
break; |
|
||||||
} |
|
||||||
} else if (xml.NodeType == XmlNodeType.Text) { |
|
||||||
ret.Append(whitespace.Replace(xml.Value, " ")); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
static string GetCref(string cref) |
|
||||||
{ |
|
||||||
if (cref == null || cref.Trim().Length==0) { |
|
||||||
return ""; |
|
||||||
} |
|
||||||
if (cref.Length < 2) { |
|
||||||
return cref; |
|
||||||
} |
|
||||||
if (cref.Substring(1, 1) == ":") { |
|
||||||
return cref.Substring(2, cref.Length - 2); |
|
||||||
} |
|
||||||
return cref; |
|
||||||
} |
|
||||||
|
|
||||||
public TextBlock CreateTextBlock() |
|
||||||
{ |
|
||||||
return new TextBlock { Text = ret.ToString() }; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
Loading…
Reference in new issue