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/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 { diff --git a/ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUsingDeclarations.cs b/ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUsingDeclarations.cs index de33e29fe..1aca09db5 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,26 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms base.VisitTypeDeclaration(typeDeclaration); return; } + + if (typeDeclaration.HasPrimaryConstructor) + { + inPrimaryConstructor = true; + + try + { + typeDeclaration.PrimaryConstructorParameters.AcceptVisitor(this); + } + finally + { + inPrimaryConstructor = false; + } + } + var previousResolver = resolver; var previousAstBuilder = astBuilder; + resolver = resolver.WithCurrentTypeDefinition(typeDeclaration.GetSymbol() as ITypeDefinition); + try { astBuilder = CreateAstBuilder(resolver); @@ -280,6 +299,17 @@ 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); + } + public override void VisitMethodDeclaration(MethodDeclaration methodDeclaration) { Visit(methodDeclaration, base.VisitMethodDeclaration);