Skip to content

Commit 95108c9

Browse files
Fix #3108: illegal nested classes in enums throw off EnumValueDisplayMode handling.
1 parent 0bab8a0 commit 95108c9

File tree

4 files changed

+87
-17
lines changed

4 files changed

+87
-17
lines changed

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,19 @@ public enum BooleanEnum : bool
1010
Max = byte.MaxValue
1111
}
1212

13+
public enum EnumWithNestedClass
14+
{
15+
#pragma warning disable format
16+
// error: nested types are not permitted in C#.
17+
public class NestedClass
18+
{
19+
}
20+
,
21+
#pragma warning enable format
22+
Zero,
23+
One
24+
}
25+
1326
public enum NativeIntEnum : IntPtr
1427
{
1528
Zero = 0L,

ICSharpCode.Decompiler.Tests/TestCases/ILPretty/WeirdEnums.il

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,33 @@
3434
.field public static literal valuetype TestEnum.NativeIntEnum One = int64(1)
3535
.field public static literal valuetype TestEnum.NativeIntEnum FortyTwo = int64(42)
3636
}
37+
38+
.class nested public auto ansi sealed TestEnum.EnumWithNestedClass
39+
extends [System.Runtime]System.Enum
40+
{
41+
// Nested Types
42+
.class nested public auto ansi beforefieldinit NestedClass
43+
extends [mscorlib]System.Object
44+
{
45+
// Methods
46+
.method public hidebysig specialname rtspecialname
47+
instance void .ctor () cil managed
48+
{
49+
// Method begins at RVA 0x206c
50+
// Code size 8 (0x8)
51+
.maxstack 8
52+
53+
IL_0000: ldarg.0
54+
IL_0001: call instance void [mscorlib]System.Object::.ctor()
55+
IL_0006: nop
56+
IL_0007: ret
57+
} // end of method TestEnum.NestedClass::.ctor
58+
59+
} // end of class NestedClass
60+
61+
// Fields
62+
.field public specialname rtspecialname int32 value__
63+
.field public static literal valuetype TestEnum.EnumWithNestedClass Zero = int32(0)
64+
.field public static literal valuetype TestEnum.EnumWithNestedClass One = int32(1)
65+
66+
} // end of class EnumWithNestedClass

ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1339,10 +1339,6 @@ EntityDeclaration DoDecompile(ITypeDefinition typeDef, DecompileRun decompileRun
13391339
}
13401340
}
13411341

1342-
decompileRun.EnumValueDisplayMode = typeDef.Kind == TypeKind.Enum
1343-
? DetectBestEnumValueDisplayMode(typeDef, module.PEFile)
1344-
: null;
1345-
13461342
// With C# 9 records, the relative order of fields and properties matters:
13471343
IEnumerable<IMember> fieldsAndProperties = recordDecompiler?.FieldsAndProperties
13481344
?? typeDef.Fields.Concat<IMember>(typeDef.Properties);
@@ -1406,7 +1402,9 @@ EntityDeclaration DoDecompile(ITypeDefinition typeDef, DecompileRun decompileRun
14061402
}
14071403
if (typeDecl.ClassType == ClassType.Enum)
14081404
{
1409-
switch (decompileRun.EnumValueDisplayMode)
1405+
Debug.Assert(typeDef.Kind == TypeKind.Enum);
1406+
EnumValueDisplayMode displayMode = DetectBestEnumValueDisplayMode(typeDef, module.PEFile);
1407+
switch (displayMode)
14101408
{
14111409
case EnumValueDisplayMode.FirstOnly:
14121410
foreach (var enumMember in typeDecl.Members.OfType<EnumMemberDeclaration>().Skip(1))
@@ -1425,13 +1423,33 @@ EntityDeclaration DoDecompile(ITypeDefinition typeDef, DecompileRun decompileRun
14251423
}
14261424
break;
14271425
case EnumValueDisplayMode.All:
1428-
case EnumValueDisplayMode.AllHex:
14291426
// nothing needs to be changed.
14301427
break;
1428+
case EnumValueDisplayMode.AllHex:
1429+
foreach (var enumMember in typeDecl.Members.OfType<EnumMemberDeclaration>())
1430+
{
1431+
var constantValue = (enumMember.GetSymbol() as IField).GetConstantValue();
1432+
if (constantValue == null || enumMember.Initializer is not PrimitiveExpression pe)
1433+
{
1434+
continue;
1435+
}
1436+
long initValue = (long)CSharpPrimitiveCast.Cast(TypeCode.Int64, constantValue, false);
1437+
if (initValue >= 10)
1438+
{
1439+
pe.Format = LiteralFormat.HexadecimalNumber;
1440+
}
1441+
}
1442+
break;
14311443
default:
14321444
throw new ArgumentOutOfRangeException();
14331445
}
1434-
decompileRun.EnumValueDisplayMode = null;
1446+
foreach (var item in typeDecl.Members)
1447+
{
1448+
if (item is not EnumMemberDeclaration)
1449+
{
1450+
typeDecl.InsertChildBefore(item, new Comment(" error: nested types are not permitted in C#."), Roles.Comment);
1451+
}
1452+
}
14351453
}
14361454
return typeDecl;
14371455
}
@@ -1927,13 +1945,7 @@ EntityDeclaration DoDecompile(IField field, DecompileRun decompileRun, ITypeReso
19271945
object constantValue = field.GetConstantValue();
19281946
if (constantValue != null)
19291947
{
1930-
long initValue = (long)CSharpPrimitiveCast.Cast(TypeCode.Int64, constantValue, false);
19311948
enumDec.Initializer = typeSystemAstBuilder.ConvertConstantValue(decompilationContext.CurrentTypeDefinition.EnumUnderlyingType, constantValue);
1932-
if (enumDec.Initializer is PrimitiveExpression primitive
1933-
&& initValue >= 10 && decompileRun.EnumValueDisplayMode == EnumValueDisplayMode.AllHex)
1934-
{
1935-
primitive.Format = LiteralFormat.HexadecimalNumber;
1936-
}
19371949
}
19381950
enumDec.Attributes.AddRange(field.GetAttributes().Select(a => new AttributeSection(typeSystemAstBuilder.ConvertAttribute(a))));
19391951
enumDec.AddAnnotation(new MemberResolveResult(null, field));

ICSharpCode.Decompiler/DecompileRun.cs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,23 @@
1-
using System;
1+
// Copyright (c) 2018 Siegfried Pammer
2+
//
3+
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
4+
// software and associated documentation files (the "Software"), to deal in the Software
5+
// without restriction, including without limitation the rights to use, copy, modify, merge,
6+
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
7+
// to whom the Software is furnished to do so, subject to the following conditions:
8+
//
9+
// The above copyright notice and this permission notice shall be included in all copies or
10+
// substantial portions of the Software.
11+
//
12+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
13+
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14+
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
15+
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
16+
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
17+
// DEALINGS IN THE SOFTWARE.
18+
19+
using System;
220
using System.Collections.Generic;
3-
using System.Text;
421
using System.Threading;
522

623
using ICSharpCode.Decompiler.CSharp;
@@ -49,8 +66,6 @@ CSharp.TypeSystem.UsingScope CreateUsingScope(HashSet<string> requiredNamespaces
4966
}
5067
return usingScope;
5168
}
52-
53-
public EnumValueDisplayMode? EnumValueDisplayMode { get; set; }
5469
}
5570

5671
enum EnumValueDisplayMode

0 commit comments

Comments
 (0)