From 22ceb6e7d162bc00e1d6ef540ddd2d534860b0e7 Mon Sep 17 00:00:00 2001 From: mmusu3 Date: Thu, 20 Nov 2025 17:19:39 +1000 Subject: [PATCH 1/3] Fix remaining cases with changes to IntroduceUsingDeclarations. --- .../TestCases/Pretty/Issue3611.cs | 39 ++++++++++--------- .../Transforms/IntroduceUsingDeclarations.cs | 18 +++++++++ 2 files changed, 38 insertions(+), 19 deletions(-) diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Issue3611.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Issue3611.cs index 4803fe8d0..e7b0d1286 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Issue3611.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Issue3611.cs @@ -12,19 +12,19 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty public string Value { get; } = value; } - //private class C5(C5.ValueArray array) - //{ - // public struct ValueArray - // { - // private bool b; - // public bool[] ToArray() - // { - // return null; - // } - // } + private class C5(C5.ValueArray array) + { + public struct ValueArray + { + private bool b; + public bool[] ToArray() + { + return null; + } + } - // public bool[] Values = array.ToArray(); - //} + public bool[] Values = array.ToArray(); + } private class BaseClass { @@ -33,14 +33,15 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty } } - //private class C6(C6.Data2 data) : BaseClass(data.Value) - //{ - // public struct Data2 { - // public int Value { get; set; } - // } + private class C6(C6.Data2 data) : BaseClass(data.Value) + { + public struct Data2 + { + public int Value { get; set; } + } - // public Data2 Data => data; - //} + public Data2 Data => data; + } private struct S3(T v) { diff --git a/ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUsingDeclarations.cs b/ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUsingDeclarations.cs index de33e29fe..a2321bf10 100644 --- a/ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUsingDeclarations.cs +++ b/ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUsingDeclarations.cs @@ -189,6 +189,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms CSharpResolver resolver; TypeSystemAstBuilder astBuilder; + bool inPrimaryConstructor; + public FullyQualifyAmbiguousTypeNamesVisitor(TransformContext context, UsingScope usingScope) { this.ignoreUsingScope = !context.Settings.UsingDeclarations; @@ -265,9 +267,19 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms base.VisitTypeDeclaration(typeDeclaration); return; } + + if (typeDeclaration.HasPrimaryConstructor) + { + inPrimaryConstructor = true; + typeDeclaration.PrimaryConstructorParameters.AcceptVisitor(this); + inPrimaryConstructor = false; + } + var previousResolver = resolver; var previousAstBuilder = astBuilder; + resolver = resolver.WithCurrentTypeDefinition(typeDeclaration.GetSymbol() as ITypeDefinition); + try { astBuilder = CreateAstBuilder(resolver); @@ -280,6 +292,12 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms } } + public override void VisitParameterDeclaration(ParameterDeclaration parameterDeclaration) + { + if (inPrimaryConstructor || parameterDeclaration.Parent is not TypeDeclaration) + base.VisitParameterDeclaration(parameterDeclaration); + } + public override void VisitMethodDeclaration(MethodDeclaration methodDeclaration) { Visit(methodDeclaration, base.VisitMethodDeclaration); From 45efc732a726e4efe82930510492bd73b23e2e28 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Thu, 20 Nov 2025 13:25:39 +0100 Subject: [PATCH 2/3] #3614: Use correct number of type arguments when adding type annotations to generic types with nested types. --- .../CSharp/Syntax/TypeSystemAstBuilder.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs b/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs index 58fd10c83..dae49f6d0 100644 --- a/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs @@ -546,7 +546,13 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax { // Handle nested types result.Target = ConvertTypeHelper(genericType.DeclaringType, typeArguments); - AddTypeAnnotation(result.Target, genericType.DeclaringType); + // Use correct number of type arguments on the declaring type + var declaringType = genericType.DeclaringType; + if (outerTypeParameterCount > 0) + { + declaringType = new ParameterizedType(genericType.DeclaringType, typeArguments.Take(outerTypeParameterCount)); + } + AddTypeAnnotation(result.Target, declaringType); } else { From 88b2c437a715cdd487511b4c046b940d869f6502 Mon Sep 17 00:00:00 2001 From: mmusu3 Date: Thu, 20 Nov 2025 23:23:35 +1000 Subject: [PATCH 3/3] Address PR review feedback --- .../Transforms/IntroduceUsingDeclarations.cs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUsingDeclarations.cs b/ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUsingDeclarations.cs index a2321bf10..1aca09db5 100644 --- a/ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUsingDeclarations.cs +++ b/ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUsingDeclarations.cs @@ -271,8 +271,15 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms if (typeDeclaration.HasPrimaryConstructor) { inPrimaryConstructor = true; - typeDeclaration.PrimaryConstructorParameters.AcceptVisitor(this); - inPrimaryConstructor = false; + + try + { + typeDeclaration.PrimaryConstructorParameters.AcceptVisitor(this); + } + finally + { + inPrimaryConstructor = false; + } } var previousResolver = resolver; @@ -294,6 +301,11 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms public override void VisitParameterDeclaration(ParameterDeclaration parameterDeclaration) { + // Parameters of primary constructors are visited separately from the rest of the + // type declaration since their types are at the same scope as the type declaration + // and so need to use the outer resolver. This check ensures that the visitor only + // runs once per parameter since their AstNodes will get revisited by the call to + // `base.VisitTypeDeclaration(typeDeclaration)` in `VisitTypeDeclaration` above. if (inPrimaryConstructor || parameterDeclaration.Parent is not TypeDeclaration) base.VisitParameterDeclaration(parameterDeclaration); }