diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Playstation.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Playstation.cs index 42b1f80be..ccea9b125 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Playstation.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Playstation.cs @@ -4,6 +4,8 @@ using System.Threading; namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.Playstation { +#pragma warning disable CS0414, CS9113, CS9124 + public record struct CopilotContextId { public Guid Id { get; } @@ -176,6 +178,54 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.Playstation Leet = (int)Math.Min(dummy1, dummy2); } } + + internal class Issue3452 + { + private struct Data + { + public object Obj; + } + + private class C1(object obj) + { + internal Data d = new Data { + Obj = obj + }; + } + + private class C2(object obj) + { + public object Obj => obj; + } + + private class C3(StringComparison comparison) + { + private StringComparison _comparison = comparison; + + internal StringComparison Test() + { + return comparison; + } + } + + private struct S1 + { + internal Data d; + + public S1(object obj) + { + d = new Data { + Obj = obj + }; + } + } + + private struct S2(object obj) + { + public object Obj => obj; + } + } + public record NamedParameter(string name, object? value, bool encode = true) : Parameter(Ensure.NotEmptyString(name, "name"), value, encode); [DebuggerDisplay("{DebuggerDisplay()}")] diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/PlaystationPreferPrimary.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/PlaystationPreferPrimary.cs index 8b1f54696..9aa4e1e33 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/PlaystationPreferPrimary.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/PlaystationPreferPrimary.cs @@ -4,6 +4,8 @@ using System.Threading; namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.PlaystationPreferPrimary { +#pragma warning disable CS0414, CS9113, CS9124 + public record struct CopilotContextId { public Guid Id { get; } @@ -157,6 +159,48 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.PlaystationPreferPrimary public int Leet = (int)Math.Min(dummy1, dummy2); } + internal class Issue3452 + { + private struct Data + { + public object Obj; + } + + private class C1(object obj) + { + internal Data d = new Data { + Obj = obj + }; + } + + private class C2(object obj) + { + public object Obj => obj; + } + + private class C3(StringComparison comparison) + { + private StringComparison _comparison = comparison; + + internal StringComparison Test() + { + return comparison; + } + } + + private struct S1(object obj) + { + internal Data d = new Data { + Obj = obj + }; + } + + private struct S2(object obj) + { + public object Obj => obj; + } + } + public record NamedParameter(string name, object? value, bool encode = true) : Parameter(Ensure.NotEmptyString(name, "name"), value, encode); [DebuggerDisplay("{DebuggerDisplay()}")] @@ -238,14 +282,10 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.PlaystationPreferPrimary } } - public class PersonRegular2 + public class PersonRegular2(string name, int age) { private readonly string _name = "name" + Environment.GetEnvironmentVariable("Path"); private readonly int _age = Environment.GetEnvironmentVariable("Path")?.Length ?? (-1); - - public PersonRegular2(string name, int age) - { - } } public record QueryParameter(string name, object? value, bool encode = true) : NamedParameter(name, value, encode); diff --git a/ICSharpCode.Decompiler/CSharp/RecordDecompiler.cs b/ICSharpCode.Decompiler/CSharp/RecordDecompiler.cs index 82a2829ff..64f750ba4 100644 --- a/ICSharpCode.Decompiler/CSharp/RecordDecompiler.cs +++ b/ICSharpCode.Decompiler/CSharp/RecordDecompiler.cs @@ -185,7 +185,7 @@ namespace ICSharpCode.Decompiler.CSharp if (method.IsStatic || !method.IsConstructor) continue; var m = method.Specialize(subst); - var body = DecompileBody(method); + var body = DecompileBody(method, allTransforms: method.Accessibility == Accessibility.Public && !recordTypeDef.IsRecord); if (body == null) continue; if (primaryCtor == null && method.Accessibility == Accessibility.Public && IsPrimaryConstructorBody(m, method, body)) @@ -268,7 +268,7 @@ namespace ICSharpCode.Decompiler.CSharp else { backingMember = field; - referencesMembersDeclaredByPrimaryConstructor |= valueReferencesParameter && recordTypeDef.IsReferenceType == true; + referencesMembersDeclaredByPrimaryConstructor |= valueReferencesParameter && (FieldIsGenerated(field) || recordTypeDef.IsReferenceType == true); } if (offset < method.Parameters.Count) { @@ -1206,7 +1206,7 @@ namespace ICSharpCode.Decompiler.CSharp } } - Block DecompileBody(IMethod method) + Block DecompileBody(IMethod method, bool allTransforms = false) { if (method == null || method.MetadataToken.IsNil) return null; @@ -1223,7 +1223,7 @@ namespace ICSharpCode.Decompiler.CSharp var body = typeSystem.MainModule.MetadataFile.GetMethodBody(methodDef.RelativeVirtualAddress); var ilReader = new ILReader(typeSystem.MainModule); var il = ilReader.ReadIL(methodDefHandle, body, genericContext, ILFunctionKind.TopLevelFunction, cancellationToken); - var settings = new DecompilerSettings(LanguageVersion.CSharp1); + var settings = allTransforms ? this.settings : new DecompilerSettings(LanguageVersion.CSharp1); var transforms = CSharpDecompiler.GetILTransforms(); // Remove the last couple transforms -- we don't need variable names etc. here int lastBlockTransform = transforms.FindLastIndex(t => t is BlockILTransform); diff --git a/ICSharpCode.Decompiler/CSharp/Transforms/TransformFieldAndConstructorInitializers.cs b/ICSharpCode.Decompiler/CSharp/Transforms/TransformFieldAndConstructorInitializers.cs index e4c1e04df..ee2270660 100644 --- a/ICSharpCode.Decompiler/CSharp/Transforms/TransformFieldAndConstructorInitializers.cs +++ b/ICSharpCode.Decompiler/CSharp/Transforms/TransformFieldAndConstructorInitializers.cs @@ -227,14 +227,13 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms // Recognize field or property initializers: // Translate first statement in all ctors (if all ctors have the same statement) into an initializer. bool allSame; - bool isStructPrimaryCtor = false; do { Match m = fieldInitializerPattern.Match(instanceCtorsNotChainingWithThis[0].Body.FirstOrDefault()); if (!m.Success) break; IMember fieldOrPropertyOrEvent = (m.Get("fieldAccess").Single().GetSymbol() as IMember)?.MemberDefinition; - if (!(fieldOrPropertyOrEvent is IField) && !(fieldOrPropertyOrEvent is IProperty) && !(fieldOrPropertyOrEvent is IEvent)) + if (fieldOrPropertyOrEvent is not (IField or IProperty or IEvent)) break; var fieldOrPropertyOrEventDecl = members.FirstOrDefault(f => f.GetSymbol() == fieldOrPropertyOrEvent) as EntityDeclaration; // Cannot transform if it is a custom event. @@ -245,12 +244,11 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms // 'this'/'base' cannot be used in initializers if (initializer.DescendantsAndSelf.Any(n => n is ThisReferenceExpression || n is BaseReferenceExpression)) break; - var v = initializer.Annotation()?.Variable; - if (v?.Kind == IL.VariableKind.Parameter && IsPropertyDeclaredByPrimaryCtor(fieldOrPropertyOrEvent, record)) + + if (record != null && ctorMethodDef.Equals(record.PrimaryConstructor)) { // remove record ctor parameter assignments - isStructPrimaryCtor = true; - if (fieldOrPropertyOrEvent is IField f) + if (fieldOrPropertyOrEvent is IField f && initializer.Annotation()?.Variable is ILVariable v) fieldToVariableMap.Add(f, v); } else @@ -259,14 +257,14 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms if (fieldOrPropertyOrEventDecl == null) break; // or if this is a struct record, but not the primary ctor - if (declaringTypeDefinition.IsRecord && declaringTypeDefinition.IsReferenceType == false && !isStructPrimaryCtor) + if (declaringTypeDefinition.IsRecord && declaringTypeDefinition.IsReferenceType == false) break; // or if this is not a primary constructor and the initializer contains any parameter reference, we have to abort if (!ctorMethodDef.Equals(record?.PrimaryConstructor)) { - bool referencesParameter = initializer.Annotation()?.Descendants + bool referencesParameter = initializer.Annotations.OfType().Any(inst => inst.Descendants .OfType() - .Any(inst => inst.Variable.Kind == VariableKind.Parameter) ?? false; + .Any(inst => inst.Variable.Kind == VariableKind.Parameter)); if (referencesParameter) break; }