Skip to content

Commit 94050a4

Browse files
Rewrite TransformFieldAndConstructorInitializers from a step-by-step AST-based analysis to an analysis that tracks the whole constructor body.
1 parent 0ed1460 commit 94050a4

25 files changed

+1368
-1176
lines changed

ICSharpCode.Decompiler.Tests/Helpers/Tester.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
using ICSharpCode.Decompiler.CSharp.OutputVisitor;
3636
using ICSharpCode.Decompiler.CSharp.Transforms;
3737
using ICSharpCode.Decompiler.Disassembler;
38+
using ICSharpCode.Decompiler.Documentation;
3839
using ICSharpCode.Decompiler.Metadata;
3940
using ICSharpCode.Decompiler.TypeSystem;
4041
using ICSharpCode.ILSpyX.PdbProvider;
@@ -70,6 +71,7 @@ public enum CompilerOptions
7071
NullableEnable = 0x8000,
7172
ReferenceUnsafe = 0x10000,
7273
CheckForOverflowUnderflow = 0x20000,
74+
ProcessXmlDoc = 0x40000,
7375
UseMcsMask = UseMcs2_6_4 | UseMcs5_23,
7476
UseRoslynMask = UseRoslyn1_3_2 | UseRoslyn2_10_0 | UseRoslyn3_11_0 | UseRoslynLatest
7577
}
@@ -560,6 +562,8 @@ public static async Task<CompilerResults> CompileCSharp(string sourceFileName, C
560562
$"-langversion:{languageVersion} " +
561563
$"-unsafe -o{(flags.HasFlag(CompilerOptions.Optimize) ? "+ " : "- ")}";
562564

565+
HashSet<string> noWarn = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
566+
563567
// note: the /shared switch is undocumented. It allows us to use the VBCSCompiler.exe compiler
564568
// server to speed up testing
565569
if (roslynVersion != "legacy")
@@ -601,6 +605,11 @@ public static async Task<CompilerResults> CompileCSharp(string sourceFileName, C
601605
otherOptions += "-platform:anycpu ";
602606
}
603607

608+
if (flags.HasFlag(CompilerOptions.ProcessXmlDoc))
609+
{
610+
otherOptions += $"-doc:\"{Path.ChangeExtension(results.PathToAssembly, ".xml")}\" ";
611+
}
612+
604613
if (flags.HasFlag(CompilerOptions.CheckForOverflowUnderflow))
605614
{
606615
otherOptions += "-checked+ ";
@@ -613,6 +622,12 @@ public static async Task<CompilerResults> CompileCSharp(string sourceFileName, C
613622
if (preprocessorSymbols.Count > 0)
614623
{
615624
otherOptions += " \"-d:" + string.Join(";", preprocessorSymbols) + "\" ";
625+
noWarn.Add("CS1591");
626+
}
627+
628+
if (noWarn.Count > 0)
629+
{
630+
otherOptions += " -nowarn:" + string.Join(",", noWarn);
616631
}
617632

618633
var command = Cli.Wrap(cscPath)
@@ -833,6 +848,9 @@ public static Task<string> DecompileCSharp(string assemblyFileName, DecompilerSe
833848
var pdbFileName = Path.ChangeExtension(assemblyFileName, ".pdb");
834849
if (File.Exists(pdbFileName))
835850
decompiler.DebugInfoProvider = DebugInfoUtils.FromFile(module, pdbFileName);
851+
var xmlDocFileName = Path.ChangeExtension(assemblyFileName, ".xml");
852+
if (File.Exists(xmlDocFileName))
853+
decompiler.DocumentationProvider = new XmlDocumentationProvider(xmlDocFileName);
836854
var syntaxTree = decompiler.DecompileWholeModuleAsSingleFile(sortTypes: true);
837855

838856
StringWriter output = new StringWriter();

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,14 +158,16 @@
158158
<Compile Include="TestCases\ILPretty\Issue3552.cs" />
159159
<Compile Include="TestCases\Pretty\ExpandParamsArgumentsDisabled.cs" />
160160
<Compile Include="TestCases\Pretty\ExtensionProperties.cs" />
161+
<Compile Include="TestCases\Pretty\Issue3452.cs" />
161162
<Compile Include="TestCases\Pretty\Issue3541.cs" />
162163
<Compile Include="TestCases\Pretty\Issue3571_C.cs" />
163164
<Compile Include="TestCases\Pretty\Issue3571_B.cs" />
164165
<Compile Include="TestCases\Pretty\Issue3571_A.cs" />
165166
<Compile Include="TestCases\Pretty\Issue3576.cs" />
166167
<Compile Include="TestCases\Pretty\Issue3584.cs" />
167-
<Compile Include="TestCases\Pretty\PlaystationPreferPrimary.cs" />
168-
<Compile Include="TestCases\Pretty\Playstation.cs" />
168+
<Compile Include="TestCases\Pretty\Issue3610.cs" />
169+
<Compile Include="TestCases\Pretty\Issue3611.cs" />
170+
<Compile Include="TestCases\Pretty\Issue3598.cs" />
169171
<None Include="TestCases\Ugly\NoLocalFunctions.Expected.cs" />
170172
<None Include="TestCases\ILPretty\Issue3504.cs" />
171173
<Compile Include="TestCases\ILPretty\MonoFixed.cs" />

ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -396,7 +396,7 @@ public async Task UnsafeCode([ValueSource(nameof(defaultOptions))] CompilerOptio
396396
[Test]
397397
public async Task ConstructorInitializers([ValueSource(nameof(defaultOptionsWithMcs))] CompilerOptions cscOptions)
398398
{
399-
await RunForLibrary(cscOptions: cscOptions);
399+
await RunForLibrary(cscOptions: cscOptions | CompilerOptions.ProcessXmlDoc);
400400
}
401401

402402
[Test]
@@ -532,23 +532,31 @@ public async Task FunctionPointers([ValueSource(nameof(roslyn3OrNewerOptions))]
532532
[Test]
533533
public async Task Records([ValueSource(nameof(roslyn3OrNewerOptions))] CompilerOptions cscOptions)
534534
{
535-
await RunForLibrary(cscOptions: cscOptions | CompilerOptions.NullableEnable);
535+
await RunForLibrary(cscOptions: cscOptions);
536+
}
537+
538+
[Test]
539+
public async Task Issue3610([ValueSource(nameof(roslyn4OrNewerOptions))] CompilerOptions cscOptions)
540+
{
541+
await RunForLibrary(cscOptions: cscOptions);
536542
}
537543

538544
[Test]
539-
public async Task Playstation([ValueSource(nameof(roslyn4OrNewerOptions))] CompilerOptions cscOptions)
545+
public async Task Issue3611([ValueSource(nameof(roslyn4OrNewerOptions))] CompilerOptions cscOptions)
546+
{
547+
await RunForLibrary(cscOptions: cscOptions);
548+
}
549+
550+
[Test]
551+
public async Task Issue3452([ValueSource(nameof(roslyn4OrNewerOptions))] CompilerOptions cscOptions)
540552
{
541-
// see https://github.com/icsharpcode/ILSpy/pull/3598#issuecomment-3465151525
542553
await RunForLibrary(cscOptions: cscOptions | CompilerOptions.NullableEnable);
543554
}
544555

545556
[Test]
546-
public async Task PlaystationPreferPrimary([ValueSource(nameof(roslyn4OrNewerOptions))] CompilerOptions cscOptions)
557+
public async Task Issue3598([ValueSource(nameof(roslyn4OrNewerOptions))] CompilerOptions cscOptions)
547558
{
548-
// see https://github.com/icsharpcode/ILSpy/pull/3598#issuecomment-3465151525
549-
await RunForLibrary(cscOptions: cscOptions | CompilerOptions.NullableEnable, configureDecompiler: settings => {
550-
settings.PreferPrimaryConstructorIfPossible = true;
551-
});
559+
await RunForLibrary(cscOptions: cscOptions | CompilerOptions.NullableEnable);
552560
}
553561

554562
[Test]

ICSharpCode.Decompiler.Tests/TestCases/ILPretty/FSharpLoops_Debug.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ void IDisposable.Dispose()
5050
[Serializable]
5151
[SpecialName]
5252
[CompilationMapping(SourceConstructFlags.Closure)]
53-
internal sealed class getSeq_00405(int pc, int current) : GeneratedSequenceBase<int>()
53+
internal sealed class getSeq_00405(int pc, int current) : GeneratedSequenceBase<int>
5454
{
5555
[DebuggerNonUserCode]
5656
[DebuggerBrowsable(DebuggerBrowsableState.Never)]

ICSharpCode.Decompiler.Tests/TestCases/ILPretty/FSharpLoops_Release.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ void IDisposable.Dispose()
5050
[Serializable]
5151
[SpecialName]
5252
[CompilationMapping(SourceConstructFlags.Closure)]
53-
internal sealed class getSeq_00405(int pc, int current) : GeneratedSequenceBase<int>()
53+
internal sealed class getSeq_00405(int pc, int current) : GeneratedSequenceBase<int>
5454
{
5555
[DebuggerNonUserCode]
5656
[DebuggerBrowsable(DebuggerBrowsableState.Never)]

ICSharpCode.Decompiler.Tests/TestCases/Pretty/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
/*.dll
33
/*.exe
44
/*.pdb
5+
/*.xml

ICSharpCode.Decompiler.Tests/TestCases/Pretty/CS73_StackAllocInitializers.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,17 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
2424
{
2525
internal class CS73_StackAllocInitializers
2626
{
27+
#if CS120
28+
[StructLayout(LayoutKind.Sequential, Size = 5)]
29+
private struct StructWithSize5(byte a, byte b, byte c, byte d, byte e)
30+
{
31+
public byte a = a;
32+
public byte b = b;
33+
public byte c = c;
34+
public byte d = d;
35+
public byte e = e;
36+
}
37+
#else
2738
[StructLayout(LayoutKind.Sequential, Size = 5)]
2839
private struct StructWithSize5
2940
{
@@ -42,6 +53,7 @@ public StructWithSize5(byte a, byte b, byte c, byte d, byte e)
4253
this.e = e;
4354
}
4455
}
56+
#endif
4557

4658
#if CS80
4759
private class NestedContext1

ICSharpCode.Decompiler.Tests/TestCases/Pretty/ConstructorInitializers.cs

Lines changed: 106 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,40 @@
1717
// DEALINGS IN THE SOFTWARE.
1818

1919
using System;
20+
using System.Collections.Generic;
2021

2122
namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
2223
{
2324
public class ConstructorInitializers
2425
{
26+
public class JArray
27+
{
28+
private readonly List<object> objects = new List<object>();
29+
private readonly List<string> strings = new List<string>();
30+
31+
public JArray()
32+
{
33+
}
34+
35+
public JArray(params object[] items)
36+
{
37+
foreach (object item in items)
38+
{
39+
objects.Add(item);
40+
}
41+
}
42+
43+
public JArray(object content)
44+
{
45+
objects.Add(content);
46+
}
47+
48+
public JArray(string content)
49+
{
50+
strings.Add(content);
51+
}
52+
}
53+
2554
public struct Issue1743
2655
{
2756
public int Leet;
@@ -38,6 +67,48 @@ public Issue1743(int dummy1, int dummy2)
3867
}
3968
}
4069

70+
#if CS120
71+
public struct Issue1743WithPrimaryCtor(int dummy1, int dummy2)
72+
{
73+
public int Leet = dummy1 + dummy2;
74+
75+
public Issue1743WithPrimaryCtor(int dummy)
76+
: this(dummy, dummy)
77+
{
78+
Leet += dummy;
79+
}
80+
}
81+
82+
/// <summary>
83+
/// This is info about the class
84+
/// </summary>
85+
private struct StructWithXmlDocCtor
86+
{
87+
public int A;
88+
89+
public int B;
90+
91+
/// <summary>
92+
/// This is info about the constructor
93+
/// </summary>
94+
public StructWithXmlDocCtor(int a, int b)
95+
{
96+
A = a;
97+
B = b;
98+
}
99+
}
100+
101+
/// <summary>
102+
/// This is info about the class
103+
/// </summary>
104+
private struct StructWithoutXmlDocCtor(int a, int b)
105+
{
106+
public int A = a;
107+
108+
public int B = b;
109+
}
110+
#endif
111+
41112
public class ClassWithConstant
42113
{
43114
// using decimal constants has the effect that there is a cctor
@@ -97,11 +168,13 @@ public void Print()
97168

98169
public class ClassWithPrimaryCtorUsingGlobalParameterAssignedToField(int a)
99170
{
100-
private readonly int a = a;
171+
#pragma warning disable CS9124 // Parameter is captured into the state of the enclosing type and its value is also used to initialize a field, property, or event.
172+
private readonly int _a = a;
173+
#pragma warning restore CS9124 // Parameter is captured into the state of the enclosing type and its value is also used to initialize a field, property, or event.
101174

102175
public void Print()
103176
{
104-
Console.WriteLine(a);
177+
Console.WriteLine(_a);
105178
}
106179
}
107180

@@ -159,5 +232,36 @@ public NoRecordButCopyConstructorLike(NoRecordButCopyConstructorLike parent)
159232
this.parent = parent;
160233
}
161234
}
235+
236+
237+
#if CS100
238+
public class PrimaryCtorClassThisChain(Guid id)
239+
{
240+
public Guid guid { get; } = id;
241+
242+
public PrimaryCtorClassThisChain(Guid id, int value)
243+
: this(Guid.NewGuid())
244+
{
245+
246+
}
247+
public PrimaryCtorClassThisChain()
248+
: this(Guid.NewGuid(), 222)
249+
{
250+
251+
}
252+
}
253+
#if EXPECTED_OUTPUT
254+
public class UnusedPrimaryCtorParameter
255+
{
256+
public UnusedPrimaryCtorParameter(int unused)
257+
{
258+
}
259+
}
260+
#else
261+
public class UnusedPrimaryCtorParameter(int unused)
262+
{
263+
}
264+
#endif
265+
#endif
162266
}
163267
}

ICSharpCode.Decompiler.Tests/TestCases/Pretty/CustomShortCircuitOperators.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,14 @@ internal struct S
128128
{
129129
private readonly bool val;
130130

131+
public bool Val {
132+
get {
133+
return val;
134+
}
135+
set {
136+
}
137+
}
138+
131139
public S(bool val)
132140
{
133141
this.val = val;

ICSharpCode.Decompiler.Tests/TestCases/Pretty/InitializerTests.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,11 @@ public struct S
9393
public int A;
9494
public int B;
9595

96+
public int M()
97+
{
98+
return 42;
99+
}
100+
96101
public S(int a)
97102
{
98103
A = a;

0 commit comments

Comments
 (0)