Skip to content

Commit 5a6ef92

Browse files
Merge pull request #3635 from icsharpcode/ilambience
Refactoring of EntityToString API
2 parents 67bc204 + 11dfe61 commit 5a6ef92

33 files changed

+1129
-428
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@
143143
<Compile Include="DisassemblerPrettyTestRunner.cs" />
144144
<Compile Include="Helpers\RoslynToolset.cs" />
145145
<Compile Include="Helpers\TestsAssemblyOutput.cs" />
146+
<Compile Include="Output\ILAmbienceTests.cs" />
146147
<Compile Include="Output\InsertParenthesesVisitorTests.cs" />
147148
<Compile Include="ProjectDecompiler\TargetFrameworkTests.cs" />
148149
<Compile Include="ProjectDecompiler\WholeProjectDecompilerTests.cs" />

ICSharpCode.Decompiler.Tests/Output/ILAmbienceTests.cs

Lines changed: 403 additions & 0 deletions
Large diffs are not rendered by default.

ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpAmbience.cs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
1717
// DEALINGS IN THE SOFTWARE.
1818

19+
#nullable enable
20+
1921
using System;
2022
using System.Collections.Generic;
2123
using System.IO;
@@ -58,8 +60,7 @@ public void ConvertSymbol(ISymbol symbol, TokenWriter writer, CSharpFormattingOp
5860
TypeSystemAstBuilder astBuilder = CreateAstBuilder();
5961
AstNode node = astBuilder.ConvertSymbol(symbol);
6062
writer.StartNode(node);
61-
EntityDeclaration entityDecl = node as EntityDeclaration;
62-
if (entityDecl != null)
63+
if (node is EntityDeclaration entityDecl)
6364
PrintModifiers(entityDecl.Modifiers, writer);
6465

6566
if ((ConversionFlags & ConversionFlags.ShowDefinitionKeyword) == ConversionFlags.ShowDefinitionKeyword)
@@ -280,7 +281,7 @@ void WriteMemberDeclarationName(IMember member, TokenWriter writer, CSharpFormat
280281
ConvertType(member.DeclaringType, writer, formattingPolicy);
281282
writer.WriteToken(Roles.Dot, ".");
282283
}
283-
IType explicitInterfaceType = GetExplicitInterfaceType(member);
284+
IType? explicitInterfaceType = GetExplicitInterfaceType(member);
284285
string name = member.Name;
285286
if (explicitInterfaceType != null)
286287
{
@@ -297,11 +298,11 @@ void WriteMemberDeclarationName(IMember member, TokenWriter writer, CSharpFormat
297298
writer.WriteKeyword(Roles.Identifier, "this");
298299
break;
299300
case SymbolKind.Constructor:
300-
WriteQualifiedName(member.DeclaringType.Name, writer, formattingPolicy);
301+
WriteQualifiedName(member.DeclaringType!.Name, writer, formattingPolicy);
301302
break;
302303
case SymbolKind.Destructor:
303304
writer.WriteToken(DestructorDeclaration.TildeRole, "~");
304-
WriteQualifiedName(member.DeclaringType.Name, writer, formattingPolicy);
305+
WriteQualifiedName(member.DeclaringType!.Name, writer, formattingPolicy);
305306
break;
306307
case SymbolKind.Operator:
307308
switch (name)
@@ -431,15 +432,15 @@ public string ConvertType(IType type)
431432
return astType.ToString();
432433
}
433434

434-
public void ConvertType(IType type, TokenWriter writer, CSharpFormattingOptions formattingPolicy)
435+
void ConvertType(IType type, TokenWriter writer, CSharpFormattingOptions formattingPolicy)
435436
{
436437
TypeSystemAstBuilder astBuilder = CreateAstBuilder();
437438
astBuilder.AlwaysUseShortTypeNames = (ConversionFlags & ConversionFlags.UseFullyQualifiedEntityNames) != ConversionFlags.UseFullyQualifiedEntityNames;
438439
AstType astType = astBuilder.ConvertType(type);
439440
astType.AcceptVisitor(new CSharpOutputVisitor(writer, formattingPolicy));
440441
}
441442

442-
IType GetExplicitInterfaceType(IMember member)
443+
IType? GetExplicitInterfaceType(IMember member)
443444
{
444445
if (member.IsExplicitInterfaceImplementation)
445446
{

ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs

Lines changed: 31 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ public ReflectionDisassembler(ITextOutput output, MethodBodyDisassembler methodB
9999
}
100100

101101
#region Disassemble Method
102-
EnumNameCollection<MethodAttributes> methodAttributeFlags = new EnumNameCollection<MethodAttributes>() {
102+
internal static readonly EnumNameCollection<MethodAttributes> methodAttributeFlags = new EnumNameCollection<MethodAttributes>() {
103103
{ MethodAttributes.Final, "final" },
104104
{ MethodAttributes.HideBySig, "hidebysig" },
105105
{ MethodAttributes.SpecialName, "specialname" },
@@ -115,7 +115,7 @@ public ReflectionDisassembler(ITextOutput output, MethodBodyDisassembler methodB
115115
{ MethodAttributes.HasSecurity, null }, // ?? also invisible in ILDasm
116116
};
117117

118-
EnumNameCollection<MethodAttributes> methodVisibility = new EnumNameCollection<MethodAttributes>() {
118+
internal static readonly EnumNameCollection<MethodAttributes> methodVisibility = new EnumNameCollection<MethodAttributes>() {
119119
{ MethodAttributes.Private, "private" },
120120
{ MethodAttributes.FamANDAssem, "famandassem" },
121121
{ MethodAttributes.Assembly, "assembly" },
@@ -124,7 +124,7 @@ public ReflectionDisassembler(ITextOutput output, MethodBodyDisassembler methodB
124124
{ MethodAttributes.Public, "public" },
125125
};
126126

127-
EnumNameCollection<SignatureCallingConvention> callingConvention = new EnumNameCollection<SignatureCallingConvention>() {
127+
internal static readonly EnumNameCollection<SignatureCallingConvention> callingConvention = new EnumNameCollection<SignatureCallingConvention>() {
128128
{ SignatureCallingConvention.CDecl, "unmanaged cdecl" },
129129
{ SignatureCallingConvention.StdCall, "unmanaged stdcall" },
130130
{ SignatureCallingConvention.ThisCall, "unmanaged thiscall" },
@@ -133,14 +133,14 @@ public ReflectionDisassembler(ITextOutput output, MethodBodyDisassembler methodB
133133
{ SignatureCallingConvention.Default, null },
134134
};
135135

136-
EnumNameCollection<MethodImplAttributes> methodCodeType = new EnumNameCollection<MethodImplAttributes>() {
136+
internal static readonly EnumNameCollection<MethodImplAttributes> methodCodeType = new EnumNameCollection<MethodImplAttributes>() {
137137
{ MethodImplAttributes.IL, "cil" },
138138
{ MethodImplAttributes.Native, "native" },
139139
{ MethodImplAttributes.OPTIL, "optil" },
140140
{ MethodImplAttributes.Runtime, "runtime" },
141141
};
142142

143-
EnumNameCollection<MethodImplAttributes> methodImpl = new EnumNameCollection<MethodImplAttributes>() {
143+
internal static readonly EnumNameCollection<MethodImplAttributes> methodImpl = new EnumNameCollection<MethodImplAttributes>() {
144144
{ MethodImplAttributes.Synchronized, "synchronized" },
145145
{ MethodImplAttributes.NoInlining, "noinlining" },
146146
{ MethodImplAttributes.NoOptimization, "nooptimization" },
@@ -180,8 +180,8 @@ void DisassembleMethodHeaderInternal(MetadataFile module, MethodDefinitionHandle
180180
// instance default class [mscorlib]System.IO.TextWriter get_BaseWriter () cil managed
181181
//
182182
//emit flags
183-
WriteEnum(methodDefinition.Attributes & MethodAttributes.MemberAccessMask, methodVisibility);
184-
WriteFlags(methodDefinition.Attributes & ~MethodAttributes.MemberAccessMask, methodAttributeFlags);
183+
WriteEnum(methodDefinition.Attributes & MethodAttributes.MemberAccessMask, methodVisibility, output);
184+
WriteFlags(methodDefinition.Attributes & ~MethodAttributes.MemberAccessMask, methodAttributeFlags, output);
185185
bool isCompilerControlled = (methodDefinition.Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.PrivateScope;
186186
if (isCompilerControlled)
187187
output.Write("privatescope ");
@@ -259,7 +259,7 @@ void DisassembleMethodHeaderInternal(MetadataFile module, MethodDefinitionHandle
259259
}
260260

261261
//call convention
262-
WriteEnum(signature.Value.Header.CallingConvention, callingConvention);
262+
WriteEnum(signature.Value.Header.CallingConvention, callingConvention, output);
263263

264264
//return type
265265
signature.Value.ReturnType(ILNameSyntax.Signature);
@@ -307,12 +307,12 @@ void DisassembleMethodHeaderInternal(MetadataFile module, MethodDefinitionHandle
307307
}
308308
output.Write(") ");
309309
//cil managed
310-
WriteEnum(methodDefinition.ImplAttributes & MethodImplAttributes.CodeTypeMask, methodCodeType);
310+
WriteEnum(methodDefinition.ImplAttributes & MethodImplAttributes.CodeTypeMask, methodCodeType, output);
311311
if ((methodDefinition.ImplAttributes & MethodImplAttributes.ManagedMask) == MethodImplAttributes.Managed)
312312
output.Write("managed ");
313313
else
314314
output.Write("unmanaged ");
315-
WriteFlags(methodDefinition.ImplAttributes & ~(MethodImplAttributes.CodeTypeMask | MethodImplAttributes.ManagedMask), methodImpl);
315+
WriteFlags(methodDefinition.ImplAttributes & ~(MethodImplAttributes.CodeTypeMask | MethodImplAttributes.ManagedMask), methodImpl, output);
316316

317317
output.Unindent();
318318
}
@@ -1267,7 +1267,7 @@ void WriteConstant(MetadataReader metadata, Constant constant)
12671267
#endregion
12681268

12691269
#region Disassemble Field
1270-
EnumNameCollection<FieldAttributes> fieldVisibility = new EnumNameCollection<FieldAttributes>() {
1270+
internal static readonly EnumNameCollection<FieldAttributes> fieldVisibility = new EnumNameCollection<FieldAttributes>() {
12711271
{ FieldAttributes.Private, "private" },
12721272
{ FieldAttributes.FamANDAssem, "famandassem" },
12731273
{ FieldAttributes.Assembly, "assembly" },
@@ -1276,7 +1276,7 @@ void WriteConstant(MetadataReader metadata, Constant constant)
12761276
{ FieldAttributes.Public, "public" },
12771277
};
12781278

1279-
EnumNameCollection<FieldAttributes> fieldAttributes = new EnumNameCollection<FieldAttributes>() {
1279+
internal static readonly EnumNameCollection<FieldAttributes> fieldAttributes = new EnumNameCollection<FieldAttributes>() {
12801280
{ FieldAttributes.Static, "static" },
12811281
{ FieldAttributes.Literal, "literal" },
12821282
{ FieldAttributes.InitOnly, "initonly" },
@@ -1360,9 +1360,9 @@ private char DisassembleFieldHeaderInternal(MetadataFile module, FieldDefinition
13601360
{
13611361
output.Write("[" + offset + "] ");
13621362
}
1363-
WriteEnum(fieldDefinition.Attributes & FieldAttributes.FieldAccessMask, fieldVisibility);
1363+
WriteEnum(fieldDefinition.Attributes & FieldAttributes.FieldAccessMask, fieldVisibility, output);
13641364
const FieldAttributes hasXAttributes = FieldAttributes.HasDefault | FieldAttributes.HasFieldMarshal | FieldAttributes.HasFieldRVA;
1365-
WriteFlags(fieldDefinition.Attributes & ~(FieldAttributes.FieldAccessMask | hasXAttributes), fieldAttributes);
1365+
WriteFlags(fieldDefinition.Attributes & ~(FieldAttributes.FieldAccessMask | hasXAttributes), fieldAttributes, output);
13661366

13671367
var signature = fieldDefinition.DecodeSignature(new DisassemblerSignatureTypeProvider(module, output), new MetadataGenericContext(fieldDefinition.GetDeclaringType(), module));
13681368

@@ -1415,7 +1415,7 @@ char GetRVASectionPrefix(MetadataFile module, int rva)
14151415
#endregion
14161416

14171417
#region Disassemble Property
1418-
EnumNameCollection<PropertyAttributes> propertyAttributes = new EnumNameCollection<PropertyAttributes>() {
1418+
internal static readonly EnumNameCollection<PropertyAttributes> propertyAttributes = new EnumNameCollection<PropertyAttributes>() {
14191419
{ PropertyAttributes.SpecialName, "specialname" },
14201420
{ PropertyAttributes.RTSpecialName, "rtspecialname" },
14211421
{ PropertyAttributes.HasDefault, "hasdefault" },
@@ -1450,7 +1450,7 @@ private PropertyAccessors DisassemblePropertyHeaderInternal(MetadataFile module,
14501450
output.WriteReference(module, handle, ".property", isDefinition: true);
14511451
WriteMetadataToken(output, module, handle, MetadataTokens.GetToken(handle),
14521452
spaceAfter: true, spaceBefore: true, ShowMetadataTokens, ShowMetadataTokensInBase10);
1453-
WriteFlags(propertyDefinition.Attributes, propertyAttributes);
1453+
WriteFlags(propertyDefinition.Attributes, propertyAttributes, output);
14541454
var accessors = propertyDefinition.GetAccessors();
14551455
var declaringType = metadata.GetMethodDefinition(accessors.GetAny()).GetDeclaringType();
14561456
var signature = propertyDefinition.DecodeSignature(new DisassemblerSignatureTypeProvider(module, output), new MetadataGenericContext(declaringType, module));
@@ -1489,7 +1489,7 @@ void WriteNestedMethod(string keyword, MetadataFile module, MethodDefinitionHand
14891489
#endregion
14901490

14911491
#region Disassemble Event
1492-
EnumNameCollection<EventAttributes> eventAttributes = new EnumNameCollection<EventAttributes>() {
1492+
internal static readonly EnumNameCollection<EventAttributes> eventAttributes = new EnumNameCollection<EventAttributes>() {
14931493
{ EventAttributes.SpecialName, "specialname" },
14941494
{ EventAttributes.RTSpecialName, "rtspecialname" },
14951495
};
@@ -1536,7 +1536,7 @@ private void DisassembleEventHeaderInternal(MetadataFile module, EventDefinition
15361536
output.WriteReference(module, handle, ".event", isDefinition: true);
15371537
WriteMetadataToken(output, module, handle, MetadataTokens.GetToken(handle),
15381538
spaceAfter: true, spaceBefore: true, ShowMetadataTokens, ShowMetadataTokensInBase10);
1539-
WriteFlags(eventDefinition.Attributes, eventAttributes);
1539+
WriteFlags(eventDefinition.Attributes, eventAttributes, output);
15401540
var provider = new DisassemblerSignatureTypeProvider(module, output);
15411541
Action<ILNameSyntax> signature;
15421542
switch (eventDefinition.Type.Kind)
@@ -1561,7 +1561,7 @@ private void DisassembleEventHeaderInternal(MetadataFile module, EventDefinition
15611561
#endregion
15621562

15631563
#region Disassemble Type
1564-
EnumNameCollection<TypeAttributes> typeVisibility = new EnumNameCollection<TypeAttributes>() {
1564+
internal static readonly EnumNameCollection<TypeAttributes> typeVisibility = new EnumNameCollection<TypeAttributes>() {
15651565
{ TypeAttributes.Public, "public" },
15661566
{ TypeAttributes.NotPublic, "private" },
15671567
{ TypeAttributes.NestedPublic, "nested public" },
@@ -1584,7 +1584,7 @@ private void DisassembleEventHeaderInternal(MetadataFile module, EventDefinition
15841584
{ TypeAttributes.UnicodeClass, "unicode" },
15851585
};
15861586

1587-
EnumNameCollection<TypeAttributes> typeAttributes = new EnumNameCollection<TypeAttributes>() {
1587+
internal static readonly EnumNameCollection<TypeAttributes> typeAttributes = new EnumNameCollection<TypeAttributes>() {
15881588
{ TypeAttributes.Abstract, "abstract" },
15891589
{ TypeAttributes.Sealed, "sealed" },
15901590
{ TypeAttributes.SpecialName, "specialname" },
@@ -1730,11 +1730,11 @@ private void DisassembleTypeHeaderInternal(MetadataFile module, TypeDefinitionHa
17301730
spaceAfter: true, spaceBefore: true, ShowMetadataTokens, ShowMetadataTokensInBase10);
17311731
if ((typeDefinition.Attributes & TypeAttributes.ClassSemanticsMask) == TypeAttributes.Interface)
17321732
output.Write("interface ");
1733-
WriteEnum(typeDefinition.Attributes & TypeAttributes.VisibilityMask, typeVisibility);
1734-
WriteEnum(typeDefinition.Attributes & TypeAttributes.LayoutMask, typeLayout);
1735-
WriteEnum(typeDefinition.Attributes & TypeAttributes.StringFormatMask, typeStringFormat);
1733+
WriteEnum(typeDefinition.Attributes & TypeAttributes.VisibilityMask, typeVisibility, output);
1734+
WriteEnum(typeDefinition.Attributes & TypeAttributes.LayoutMask, typeLayout, output);
1735+
WriteEnum(typeDefinition.Attributes & TypeAttributes.StringFormatMask, typeStringFormat, output);
17361736
const TypeAttributes masks = TypeAttributes.ClassSemanticsMask | TypeAttributes.VisibilityMask | TypeAttributes.LayoutMask | TypeAttributes.StringFormatMask;
1737-
WriteFlags(typeDefinition.Attributes & ~masks, typeAttributes);
1737+
WriteFlags(typeDefinition.Attributes & ~masks, typeAttributes, output);
17381738

17391739
output.Write(typeDefinition.GetDeclaringType().IsNil ? typeDefinition.GetFullTypeName(module.Metadata).ToILNameString() : DisassemblerHelpers.Escape(module.Metadata.GetString(typeDefinition.Name)));
17401740
WriteTypeParameters(output, module, genericContext, typeDefinition.GetGenericParameters());
@@ -1967,7 +1967,7 @@ void CloseBlock(string comment = null)
19671967
output.WriteLine();
19681968
}
19691969

1970-
void WriteFlags<T>(T flags, EnumNameCollection<T> flagNames) where T : struct
1970+
internal static void WriteFlags<T>(T flags, EnumNameCollection<T> flagNames, ITextOutput output) where T : struct
19711971
{
19721972
long val = Convert.ToInt64(flags);
19731973
long tested = 0;
@@ -1984,7 +1984,7 @@ void WriteFlags<T>(T flags, EnumNameCollection<T> flagNames) where T : struct
19841984
output.Write("flags({0:x4}) ", val & ~tested);
19851985
}
19861986

1987-
void WriteEnum<T>(T enumValue, EnumNameCollection<T> enumNames) where T : struct
1987+
internal static void WriteEnum<T>(T enumValue, EnumNameCollection<T> enumNames, ITextOutput output) where T : struct
19881988
{
19891989
long val = Convert.ToInt64(enumValue);
19901990
foreach (var pair in enumNames)
@@ -2006,10 +2006,14 @@ void WriteEnum<T>(T enumValue, EnumNameCollection<T> enumNames) where T : struct
20062006

20072007
}
20082008

2009-
sealed class EnumNameCollection<T> : IEnumerable<KeyValuePair<long, string>> where T : struct
2009+
internal struct EnumNameCollection<T> : IEnumerable<KeyValuePair<long, string>> where T : struct
20102010
{
20112011
List<KeyValuePair<long, string>> names = new List<KeyValuePair<long, string>>();
20122012

2013+
public EnumNameCollection()
2014+
{
2015+
}
2016+
20132017
public void Add(T flag, string name)
20142018
{
20152019
this.names.Add(new KeyValuePair<long, string>(Convert.ToInt64(flag), name));

ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@
109109
<Compile Include="Disassembler\IEntityProcessor.cs" />
110110
<Compile Include="Disassembler\SortByNameProcessor.cs" />
111111
<Compile Include="Humanizer\StringHumanizeExtensions.cs" />
112+
<Compile Include="IL\ILAmbience.cs" />
112113
<Compile Include="IL\Transforms\InlineArrayTransform.cs" />
113114
<Compile Include="IL\Transforms\RemoveUnconstrainedGenericReferenceTypeCheck.cs" />
114115
<Compile Include="Metadata\MetadataFile.cs" />

0 commit comments

Comments
 (0)