diff --git a/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj b/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
index 112acb1e5..83b84a146 100644
--- a/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
+++ b/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
@@ -143,6 +143,7 @@
+
diff --git a/ICSharpCode.Decompiler.Tests/Output/ILAmbienceTests.cs b/ICSharpCode.Decompiler.Tests/Output/ILAmbienceTests.cs
new file mode 100644
index 000000000..ce6d35545
--- /dev/null
+++ b/ICSharpCode.Decompiler.Tests/Output/ILAmbienceTests.cs
@@ -0,0 +1,403 @@
+// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this
+// software and associated documentation files (the "Software"), to deal in the Software
+// without restriction, including without limitation the rights to use, copy, modify, merge,
+// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
+// to whom the Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or
+// substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+using ICSharpCode.Decompiler.IL;
+using ICSharpCode.Decompiler.Output;
+using ICSharpCode.Decompiler.Tests.TypeSystem;
+using ICSharpCode.Decompiler.TypeSystem;
+using ICSharpCode.Decompiler.TypeSystem.Implementation;
+
+using NUnit.Framework;
+
+using static ICSharpCode.Decompiler.Output.ConversionFlags;
+
+namespace ICSharpCode.Decompiler.Tests.Output
+{
+ [TestFixture]
+ public class ILAmbienceTests
+ {
+ ICompilation compilation;
+ ILAmbience ambience;
+
+ [OneTimeSetUp]
+ public void FixtureSetUp()
+ {
+ ambience = new ILAmbience();
+
+ compilation = new SimpleCompilation(TypeSystemLoaderTests.TestAssembly,
+ TypeSystemLoaderTests.Mscorlib.WithOptions(TypeSystemOptions.Default));
+ }
+
+ ITypeDefinition GetDefinition(Type type)
+ {
+ if (type == null)
+ {
+ throw new ArgumentNullException(nameof(type));
+ }
+
+ var foundType = compilation.FindType(type).GetDefinition();
+ Assert.That(foundType, Is.Not.Null);
+ return foundType;
+ }
+
+ const ConversionFlags ILSpyMainTreeViewTypeFlags = ShowTypeParameterList | PlaceReturnTypeAfterParameterList;
+ const ConversionFlags ILSpyMainTreeViewMemberFlags = ILSpyMainTreeViewTypeFlags | ShowParameterList | ShowReturnType | ShowParameterModifiers;
+
+ #region ITypeDefinition tests
+ [TestCase(None, "Dictionary`2")]
+ [TestCase(ShowDefinitionKeyword, ".class Dictionary`2")]
+ [TestCase(ShowAccessibility, "public Dictionary`2")]
+ [TestCase(ShowDefinitionKeyword | ShowAccessibility, ".class public Dictionary`2")]
+ [TestCase(ShowTypeParameterList, "Dictionary`2")]
+ [TestCase(ShowTypeParameterList | ShowDefinitionKeyword | ShowAccessibility, ".class public Dictionary`2")]
+ [TestCase(UseFullyQualifiedEntityNames | ShowTypeParameterList, "System.Collections.Generic.Dictionary`2")]
+ [TestCase(UseFullyQualifiedEntityNames | ShowTypeParameterList | ShowDefinitionKeyword | ShowAccessibility, ".class public System.Collections.Generic.Dictionary`2")]
+ [TestCase(ILSpyMainTreeViewTypeFlags, "Dictionary`2")]
+ public void GenericType(ConversionFlags flags, string expectedOutput)
+ {
+ var typeDef = GetDefinition(typeof(Dictionary<,>));
+ ambience.ConversionFlags = flags;
+ Assert.That(ambience.ConvertSymbol(typeDef), Is.EqualTo(expectedOutput));
+ }
+
+ [TestCase(None, "Object")]
+ [TestCase(ShowDefinitionKeyword, ".class Object")]
+ [TestCase(ShowAccessibility, "public Object")]
+ [TestCase(ShowDefinitionKeyword | ShowAccessibility, ".class public Object")]
+ [TestCase(ShowTypeParameterList, "Object")]
+ [TestCase(ShowTypeParameterList | ShowDefinitionKeyword | ShowAccessibility, ".class public Object")]
+ [TestCase(UseFullyQualifiedEntityNames | ShowTypeParameterList, "System.Object")]
+ [TestCase(All, ".class public serializable beforefieldinit System.Object")]
+ [TestCase(ILSpyMainTreeViewTypeFlags, "Object")]
+ public void SimpleType(ConversionFlags flags, string expectedOutput)
+ {
+ var typeDef = GetDefinition(typeof(object));
+ ambience.ConversionFlags = flags;
+ Assert.That(ambience.ConvertSymbol(typeDef), Is.EqualTo(expectedOutput));
+ }
+
+ [TestCase(None, "IEnumerable`1")]
+ [TestCase(ShowTypeParameterList, "IEnumerable`1")]
+ [TestCase(ShowTypeParameterList | ShowTypeParameterVarianceModifier, "IEnumerable`1<+T>")]
+ [TestCase(All, ".class interface public abstract System.Collections.Generic.IEnumerable`1<+T>")]
+ [TestCase(ILSpyMainTreeViewTypeFlags, "IEnumerable`1")]
+ public void GenericInterface(ConversionFlags flags, string expectedOutput)
+ {
+ var typeDef = GetDefinition(typeof(IEnumerable<>));
+ ambience.ConversionFlags = flags;
+ Assert.That(ambience.ConvertSymbol(typeDef), Is.EqualTo(expectedOutput));
+ }
+
+ [TestCase(None, "Enumerator")]
+ [TestCase(ShowDefinitionKeyword, ".class Enumerator")]
+ [TestCase(ShowAccessibility, "nested public Enumerator")]
+ [TestCase(ShowDefinitionKeyword | ShowAccessibility, ".class nested public Enumerator")]
+ [TestCase(ShowTypeParameterList, "Enumerator")]
+ [TestCase(ShowTypeParameterList | ShowDefinitionKeyword | ShowAccessibility, ".class nested public Enumerator")]
+ [TestCase(UseFullyQualifiedEntityNames | ShowTypeParameterList, "System.Collections.Generic.List`1.Enumerator")]
+ [TestCase(ShowDeclaringType | ShowTypeParameterList, "List`1.Enumerator")]
+ [TestCase(All, ".class nested public sealed serializable beforefieldinit System.Collections.Generic.List`1.Enumerator")]
+ [TestCase(ILSpyMainTreeViewTypeFlags, "Enumerator")]
+ public void GenericTypeWithNested(ConversionFlags flags, string expectedOutput)
+ {
+ var typeDef = GetDefinition(typeof(List<>.Enumerator));
+ ambience.ConversionFlags = flags;
+ Assert.That(ambience.ConvertSymbol(typeDef), Is.EqualTo(expectedOutput));
+ }
+
+ [TestCase(None, "StaticClass")]
+ [TestCase(ShowDefinitionKeyword, ".class StaticClass")]
+ [TestCase(ShowModifiers | ShowDefinitionKeyword, ".class abstract sealed beforefieldinit StaticClass")]
+ [TestCase(ShowModifiers | ShowAccessibility, "private abstract sealed beforefieldinit StaticClass")]
+ [TestCase(ShowModifiers | ShowDefinitionKeyword | ShowAccessibility, ".class private abstract sealed beforefieldinit StaticClass")]
+ [TestCase(ShowModifiers | ShowTypeParameterList, "abstract sealed beforefieldinit StaticClass")]
+ [TestCase(ShowModifiers | ShowTypeParameterList | ShowDefinitionKeyword | ShowAccessibility, ".class private abstract sealed beforefieldinit StaticClass")]
+ [TestCase(All, ".class private abstract sealed beforefieldinit ICSharpCode.Decompiler.Tests.Output.StaticClass")]
+ [TestCase(ILSpyMainTreeViewTypeFlags, "StaticClass")]
+ public void StaticClassTest(ConversionFlags flags, string expectedOutput)
+ {
+ var typeDef = GetDefinition(typeof(StaticClass));
+ ambience.ConversionFlags = flags;
+ Assert.That(ambience.ConvertSymbol(typeDef), Is.EqualTo(expectedOutput));
+ }
+
+ [TestCase(None, "SealedClass")]
+ [TestCase(ShowDefinitionKeyword, ".class SealedClass")]
+ [TestCase(ShowModifiers | ShowDefinitionKeyword, ".class sealed beforefieldinit SealedClass")]
+ [TestCase(ShowModifiers | ShowAccessibility, "private sealed beforefieldinit SealedClass")]
+ [TestCase(ShowModifiers | ShowDefinitionKeyword | ShowAccessibility, ".class private sealed beforefieldinit SealedClass")]
+ [TestCase(ShowModifiers | ShowTypeParameterList, "sealed beforefieldinit SealedClass")]
+ [TestCase(ShowModifiers | ShowTypeParameterList | ShowDefinitionKeyword | ShowAccessibility, ".class private sealed beforefieldinit SealedClass")]
+ [TestCase(All, ".class private sealed beforefieldinit ICSharpCode.Decompiler.Tests.Output.SealedClass")]
+ [TestCase(ILSpyMainTreeViewTypeFlags, "SealedClass")]
+ public void SealedClassTest(ConversionFlags flags, string expectedOutput)
+ {
+ var typeDef = GetDefinition(typeof(SealedClass));
+ ambience.ConversionFlags = flags;
+ Assert.That(ambience.ConvertSymbol(typeDef), Is.EqualTo(expectedOutput));
+ }
+
+ [TestCase(None, "RefStruct")]
+ [TestCase(ShowDefinitionKeyword, ".class RefStruct")]
+ [TestCase(ShowModifiers | ShowDefinitionKeyword, ".class sealed beforefieldinit RefStruct")]
+ [TestCase(ShowModifiers | ShowAccessibility, "private sealed beforefieldinit RefStruct")]
+ [TestCase(ShowModifiers | ShowDefinitionKeyword | ShowAccessibility, ".class private sealed beforefieldinit RefStruct")]
+ [TestCase(ShowModifiers | ShowTypeParameterList, "sealed beforefieldinit RefStruct")]
+ [TestCase(ShowModifiers | ShowTypeParameterList | ShowDefinitionKeyword | ShowAccessibility, ".class private sealed beforefieldinit RefStruct")]
+ [TestCase(All, ".class private sealed beforefieldinit ICSharpCode.Decompiler.Tests.Output.RefStruct")]
+ [TestCase(ILSpyMainTreeViewTypeFlags, "RefStruct")]
+ public void RefStructTest(ConversionFlags flags, string expectedOutput)
+ {
+ var typeDef = GetDefinition(typeof(RefStruct));
+ ambience.ConversionFlags = flags;
+ Assert.That(ambience.ConvertSymbol(typeDef), Is.EqualTo(expectedOutput));
+ }
+
+ [TestCase(None, "ReadonlyStruct")]
+ [TestCase(ShowDefinitionKeyword, ".class ReadonlyStruct")]
+ [TestCase(ShowModifiers | ShowDefinitionKeyword, ".class sealed beforefieldinit ReadonlyStruct")]
+ [TestCase(ShowModifiers | ShowAccessibility, "private sealed beforefieldinit ReadonlyStruct")]
+ [TestCase(ShowModifiers | ShowDefinitionKeyword | ShowAccessibility, ".class private sealed beforefieldinit ReadonlyStruct")]
+ [TestCase(ShowModifiers | ShowTypeParameterList, "sealed beforefieldinit ReadonlyStruct")]
+ [TestCase(ShowModifiers | ShowTypeParameterList | ShowDefinitionKeyword | ShowAccessibility, ".class private sealed beforefieldinit ReadonlyStruct")]
+ [TestCase(All, ".class private sealed beforefieldinit ICSharpCode.Decompiler.Tests.Output.ReadonlyStruct")]
+ [TestCase(ILSpyMainTreeViewTypeFlags, "ReadonlyStruct")]
+ public void ReadonlyStructTest(ConversionFlags flags, string expectedOutput)
+ {
+ var typeDef = GetDefinition(typeof(ReadonlyStruct));
+ ambience.ConversionFlags = flags;
+ Assert.That(ambience.ConvertSymbol(typeDef), Is.EqualTo(expectedOutput));
+ }
+
+ [TestCase(None, "ReadonlyRefStruct")]
+ [TestCase(ShowDefinitionKeyword, ".class ReadonlyRefStruct")]
+ [TestCase(ShowModifiers | ShowDefinitionKeyword, ".class sealed beforefieldinit ReadonlyRefStruct")]
+ [TestCase(ShowModifiers | ShowAccessibility, "private sealed beforefieldinit ReadonlyRefStruct")]
+ [TestCase(ShowModifiers | ShowDefinitionKeyword | ShowAccessibility, ".class private sealed beforefieldinit ReadonlyRefStruct")]
+ [TestCase(ShowModifiers | ShowTypeParameterList, "sealed beforefieldinit ReadonlyRefStruct")]
+ [TestCase(ShowModifiers | ShowTypeParameterList | ShowDefinitionKeyword | ShowAccessibility, ".class private sealed beforefieldinit ReadonlyRefStruct")]
+ [TestCase(All, ".class private sealed beforefieldinit ICSharpCode.Decompiler.Tests.Output.ReadonlyRefStruct")]
+ [TestCase(ILSpyMainTreeViewTypeFlags, "ReadonlyRefStruct")]
+ public void ReadonlyRefStructTest(ConversionFlags flags, string expectedOutput)
+ {
+ var typeDef = GetDefinition(typeof(ReadonlyRefStruct));
+ ambience.ConversionFlags = flags;
+ Assert.That(ambience.ConvertSymbol(typeDef), Is.EqualTo(expectedOutput));
+ }
+ #endregion
+
+ #region Delegate tests
+ [TestCase(None, "Func`2")]
+ [TestCase(ShowTypeParameterList, "Func`2")]
+ [TestCase(ShowTypeParameterList | ShowTypeParameterVarianceModifier, "Func`2<-T,+TResult>")]
+ [TestCase(All, ".class public sealed System.Func`2<-T,+TResult>")]
+ [TestCase(ILSpyMainTreeViewTypeFlags, "Func`2")]
+ public void FuncDelegate(ConversionFlags flags, string expectedOutput)
+ {
+ var func = GetDefinition(typeof(Func<,>));
+ ambience.ConversionFlags = flags;
+ Assert.That(ambience.ConvertSymbol(func), Is.EqualTo(expectedOutput));
+ }
+ #endregion
+
+ #region IField tests
+ [TestCase(All & ~PlaceReturnTypeAfterParameterList, ".field private instance int32 ICSharpCode.Decompiler.Tests.Output.Program::test")]
+ [TestCase(ILSpyMainTreeViewMemberFlags, "test : int32")]
+ [TestCase(All & ~(ShowDeclaringType | ShowModifiers | ShowAccessibility | PlaceReturnTypeAfterParameterList), ".field int32 ICSharpCode.Decompiler.Tests.Output.Program::test")]
+ public void SimpleField(ConversionFlags flags, string expectedOutput)
+ {
+ var field = GetDefinition(typeof(Program)).GetFields(f => f.Name == "test").Single();
+ ambience.ConversionFlags = flags;
+
+ Assert.That(ambience.ConvertSymbol(field), Is.EqualTo(expectedOutput));
+ }
+
+ [TestCase(All & ~PlaceReturnTypeAfterParameterList, ".field private static literal int32 ICSharpCode.Decompiler.Tests.Output.Program::TEST2")]
+ [TestCase(ILSpyMainTreeViewMemberFlags, "TEST2 : int32")]
+ public void SimpleConstField(ConversionFlags flags, string expectedOutput)
+ {
+ var field = compilation.FindType(typeof(Program)).GetFields(f => f.Name == "TEST2").Single();
+ ambience.ConversionFlags = flags;
+
+ Assert.That(ambience.ConvertSymbol(field), Is.EqualTo(expectedOutput));
+ }
+ #endregion
+
+ #region IEvent tests
+ [Test]
+ public void EventWithDeclaringType()
+ {
+ var ev = compilation.FindType(typeof(Program)).GetEvents(f => f.Name == "ProgramChanged").Single();
+ ambience.ConversionFlags = ConversionFlags.StandardConversionFlags | ConversionFlags.ShowDeclaringType;
+ string result = ambience.ConvertSymbol(ev);
+
+ Assert.That(result, Is.EqualTo(".event instance EventHandler Program::ProgramChanged"));
+ }
+
+ [Test]
+ public void CustomEvent()
+ {
+ var ev = compilation.FindType(typeof(Program)).GetEvents(f => f.Name == "SomeEvent").Single();
+ ambience.ConversionFlags = ConversionFlags.StandardConversionFlags;
+ string result = ambience.ConvertSymbol(ev);
+
+ Assert.That(result, Is.EqualTo(".event instance EventHandler SomeEvent"));
+ }
+ #endregion
+
+ #region Property tests
+ [TestCase(StandardConversionFlags, ".property instance int32 Test")]
+ [TestCase(ILSpyMainTreeViewMemberFlags, "Test : int32")]
+ public void AutomaticProperty(ConversionFlags flags, string expectedOutput)
+ {
+ var prop = compilation.FindType(typeof(Program)).GetProperties(p => p.Name == "Test").Single();
+ ambience.ConversionFlags = flags;
+
+ Assert.That(ambience.ConvertSymbol(prop), Is.EqualTo(expectedOutput));
+ }
+
+ [TestCase(StandardConversionFlags, ".property instance int32 Item(int32 index)")]
+ [TestCase(ILSpyMainTreeViewMemberFlags, "Item(int32) : int32")]
+ public void Indexer(ConversionFlags flags, string expectedOutput)
+ {
+ var prop = compilation.FindType(typeof(Program)).GetProperties(p => p.IsIndexer && !p.IsExplicitInterfaceImplementation).Single();
+ ambience.ConversionFlags = flags;
+
+ Assert.That(ambience.ConvertSymbol(prop), Is.EqualTo(expectedOutput));
+ }
+
+ [TestCase(StandardConversionFlags, ".property instance int32 ICSharpCode.Decompiler.Tests.Output.Interface.Item(int32 index)")]
+ [TestCase(ILSpyMainTreeViewMemberFlags, "ICSharpCode.Decompiler.Tests.Output.Interface.Item(int32) : int32")]
+ public void ExplicitIndexer(ConversionFlags flags, string expectedOutput)
+ {
+ var prop = compilation.FindType(typeof(Program)).GetProperties(p => p.IsIndexer && p.IsExplicitInterfaceImplementation).Single();
+ ambience.ConversionFlags = flags;
+
+ Assert.That(ambience.ConvertSymbol(prop), Is.EqualTo(expectedOutput));
+ }
+ #endregion
+
+ #region IMethod tests
+ [TestCase(StandardConversionFlags, ".method public hidebysig specialname rtspecialname instance .ctor(int32 x)")]
+ [TestCase(ILSpyMainTreeViewMemberFlags, ".ctor(int32)")]
+ public void ConstructorTests(ConversionFlags flags, string expectedOutput)
+ {
+ var prop = compilation.FindType(typeof(Program)).GetConstructors().Single();
+ ambience.ConversionFlags = flags;
+
+ Assert.That(ambience.ConvertSymbol(prop), Is.EqualTo(expectedOutput));
+ }
+
+ [TestCase(StandardConversionFlags, ".method family hidebysig virtual instance void Finalize()")]
+ [TestCase(ILSpyMainTreeViewMemberFlags, "Finalize() : void")]
+ public void DestructorTests(ConversionFlags flags, string expectedOutput)
+ {
+ var dtor = compilation.FindType(typeof(Program))
+ .GetMembers(m => m.SymbolKind == SymbolKind.Destructor, GetMemberOptions.IgnoreInheritedMembers).Single();
+ ambience.ConversionFlags = flags;
+
+ Assert.That(ambience.ConvertSymbol(dtor), Is.EqualTo(expectedOutput));
+ }
+ #endregion
+ }
+
+ #region Test types
+#pragma warning disable 169, 67
+
+ class Test { }
+ static class StaticClass { }
+ sealed class SealedClass { }
+ ref struct RefStruct { }
+ readonly struct ReadonlyStruct { }
+ readonly ref struct ReadonlyRefStruct { }
+
+ interface Interface
+ {
+ int this[int x] { get; }
+ }
+
+ class Program : Interface
+ {
+ int test;
+ const int TEST2 = 2;
+
+ public int Test { get; set; }
+
+ public int this[int index] {
+ get {
+ return index;
+ }
+ }
+
+ int Interface.this[int index] {
+ get {
+ return index;
+ }
+ }
+
+ public event EventHandler ProgramChanged;
+
+ public event EventHandler SomeEvent {
+ add { }
+ remove { }
+ }
+
+ public static bool operator +(Program lhs, Program rhs)
+ {
+ throw new NotImplementedException();
+ }
+
+ public static implicit operator Test(Program lhs)
+ {
+ throw new NotImplementedException();
+ }
+
+ public static explicit operator int(Program lhs)
+ {
+ throw new NotImplementedException();
+ }
+
+ public Program(int x)
+ {
+
+ }
+
+ ~Program()
+ {
+
+ }
+
+ public static void Main(string[] args)
+ {
+ Console.WriteLine("Hello World!");
+
+ Console.Write("Press any key to continue . . . ");
+ Console.ReadKey(true);
+ }
+
+ public static void InParameter(in int a)
+ {
+
+ }
+ }
+ #endregion
+}
diff --git a/ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpAmbience.cs b/ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpAmbience.cs
index 35036232e..6bd362ecb 100644
--- a/ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpAmbience.cs
+++ b/ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpAmbience.cs
@@ -16,6 +16,8 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
+#nullable enable
+
using System;
using System.Collections.Generic;
using System.IO;
@@ -58,8 +60,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
TypeSystemAstBuilder astBuilder = CreateAstBuilder();
AstNode node = astBuilder.ConvertSymbol(symbol);
writer.StartNode(node);
- EntityDeclaration entityDecl = node as EntityDeclaration;
- if (entityDecl != null)
+ if (node is EntityDeclaration entityDecl)
PrintModifiers(entityDecl.Modifiers, writer);
if ((ConversionFlags & ConversionFlags.ShowDefinitionKeyword) == ConversionFlags.ShowDefinitionKeyword)
@@ -280,7 +281,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
ConvertType(member.DeclaringType, writer, formattingPolicy);
writer.WriteToken(Roles.Dot, ".");
}
- IType explicitInterfaceType = GetExplicitInterfaceType(member);
+ IType? explicitInterfaceType = GetExplicitInterfaceType(member);
string name = member.Name;
if (explicitInterfaceType != null)
{
@@ -297,11 +298,11 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
writer.WriteKeyword(Roles.Identifier, "this");
break;
case SymbolKind.Constructor:
- WriteQualifiedName(member.DeclaringType.Name, writer, formattingPolicy);
+ WriteQualifiedName(member.DeclaringType!.Name, writer, formattingPolicy);
break;
case SymbolKind.Destructor:
writer.WriteToken(DestructorDeclaration.TildeRole, "~");
- WriteQualifiedName(member.DeclaringType.Name, writer, formattingPolicy);
+ WriteQualifiedName(member.DeclaringType!.Name, writer, formattingPolicy);
break;
case SymbolKind.Operator:
switch (name)
@@ -431,7 +432,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
return astType.ToString();
}
- public void ConvertType(IType type, TokenWriter writer, CSharpFormattingOptions formattingPolicy)
+ void ConvertType(IType type, TokenWriter writer, CSharpFormattingOptions formattingPolicy)
{
TypeSystemAstBuilder astBuilder = CreateAstBuilder();
astBuilder.AlwaysUseShortTypeNames = (ConversionFlags & ConversionFlags.UseFullyQualifiedEntityNames) != ConversionFlags.UseFullyQualifiedEntityNames;
@@ -439,7 +440,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
astType.AcceptVisitor(new CSharpOutputVisitor(writer, formattingPolicy));
}
- IType GetExplicitInterfaceType(IMember member)
+ IType? GetExplicitInterfaceType(IMember member)
{
if (member.IsExplicitInterfaceImplementation)
{
diff --git a/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs b/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs
index 47230c2b6..fba0fdaef 100644
--- a/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs
+++ b/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs
@@ -99,7 +99,7 @@ namespace ICSharpCode.Decompiler.Disassembler
}
#region Disassemble Method
- EnumNameCollection methodAttributeFlags = new EnumNameCollection() {
+ internal static readonly EnumNameCollection methodAttributeFlags = new EnumNameCollection() {
{ MethodAttributes.Final, "final" },
{ MethodAttributes.HideBySig, "hidebysig" },
{ MethodAttributes.SpecialName, "specialname" },
@@ -115,7 +115,7 @@ namespace ICSharpCode.Decompiler.Disassembler
{ MethodAttributes.HasSecurity, null }, // ?? also invisible in ILDasm
};
- EnumNameCollection methodVisibility = new EnumNameCollection() {
+ internal static readonly EnumNameCollection methodVisibility = new EnumNameCollection() {
{ MethodAttributes.Private, "private" },
{ MethodAttributes.FamANDAssem, "famandassem" },
{ MethodAttributes.Assembly, "assembly" },
@@ -124,7 +124,7 @@ namespace ICSharpCode.Decompiler.Disassembler
{ MethodAttributes.Public, "public" },
};
- EnumNameCollection callingConvention = new EnumNameCollection() {
+ internal static readonly EnumNameCollection callingConvention = new EnumNameCollection() {
{ SignatureCallingConvention.CDecl, "unmanaged cdecl" },
{ SignatureCallingConvention.StdCall, "unmanaged stdcall" },
{ SignatureCallingConvention.ThisCall, "unmanaged thiscall" },
@@ -133,14 +133,14 @@ namespace ICSharpCode.Decompiler.Disassembler
{ SignatureCallingConvention.Default, null },
};
- EnumNameCollection methodCodeType = new EnumNameCollection() {
+ internal static readonly EnumNameCollection methodCodeType = new EnumNameCollection() {
{ MethodImplAttributes.IL, "cil" },
{ MethodImplAttributes.Native, "native" },
{ MethodImplAttributes.OPTIL, "optil" },
{ MethodImplAttributes.Runtime, "runtime" },
};
- EnumNameCollection methodImpl = new EnumNameCollection() {
+ internal static readonly EnumNameCollection methodImpl = new EnumNameCollection() {
{ MethodImplAttributes.Synchronized, "synchronized" },
{ MethodImplAttributes.NoInlining, "noinlining" },
{ MethodImplAttributes.NoOptimization, "nooptimization" },
@@ -180,8 +180,8 @@ namespace ICSharpCode.Decompiler.Disassembler
// instance default class [mscorlib]System.IO.TextWriter get_BaseWriter () cil managed
//
//emit flags
- WriteEnum(methodDefinition.Attributes & MethodAttributes.MemberAccessMask, methodVisibility);
- WriteFlags(methodDefinition.Attributes & ~MethodAttributes.MemberAccessMask, methodAttributeFlags);
+ WriteEnum(methodDefinition.Attributes & MethodAttributes.MemberAccessMask, methodVisibility, output);
+ WriteFlags(methodDefinition.Attributes & ~MethodAttributes.MemberAccessMask, methodAttributeFlags, output);
bool isCompilerControlled = (methodDefinition.Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.PrivateScope;
if (isCompilerControlled)
output.Write("privatescope ");
@@ -259,7 +259,7 @@ namespace ICSharpCode.Decompiler.Disassembler
}
//call convention
- WriteEnum(signature.Value.Header.CallingConvention, callingConvention);
+ WriteEnum(signature.Value.Header.CallingConvention, callingConvention, output);
//return type
signature.Value.ReturnType(ILNameSyntax.Signature);
@@ -307,12 +307,12 @@ namespace ICSharpCode.Decompiler.Disassembler
}
output.Write(") ");
//cil managed
- WriteEnum(methodDefinition.ImplAttributes & MethodImplAttributes.CodeTypeMask, methodCodeType);
+ WriteEnum(methodDefinition.ImplAttributes & MethodImplAttributes.CodeTypeMask, methodCodeType, output);
if ((methodDefinition.ImplAttributes & MethodImplAttributes.ManagedMask) == MethodImplAttributes.Managed)
output.Write("managed ");
else
output.Write("unmanaged ");
- WriteFlags(methodDefinition.ImplAttributes & ~(MethodImplAttributes.CodeTypeMask | MethodImplAttributes.ManagedMask), methodImpl);
+ WriteFlags(methodDefinition.ImplAttributes & ~(MethodImplAttributes.CodeTypeMask | MethodImplAttributes.ManagedMask), methodImpl, output);
output.Unindent();
}
@@ -1267,7 +1267,7 @@ namespace ICSharpCode.Decompiler.Disassembler
#endregion
#region Disassemble Field
- EnumNameCollection fieldVisibility = new EnumNameCollection() {
+ internal static readonly EnumNameCollection fieldVisibility = new EnumNameCollection() {
{ FieldAttributes.Private, "private" },
{ FieldAttributes.FamANDAssem, "famandassem" },
{ FieldAttributes.Assembly, "assembly" },
@@ -1276,7 +1276,7 @@ namespace ICSharpCode.Decompiler.Disassembler
{ FieldAttributes.Public, "public" },
};
- EnumNameCollection fieldAttributes = new EnumNameCollection() {
+ internal static readonly EnumNameCollection fieldAttributes = new EnumNameCollection() {
{ FieldAttributes.Static, "static" },
{ FieldAttributes.Literal, "literal" },
{ FieldAttributes.InitOnly, "initonly" },
@@ -1360,9 +1360,9 @@ namespace ICSharpCode.Decompiler.Disassembler
{
output.Write("[" + offset + "] ");
}
- WriteEnum(fieldDefinition.Attributes & FieldAttributes.FieldAccessMask, fieldVisibility);
+ WriteEnum(fieldDefinition.Attributes & FieldAttributes.FieldAccessMask, fieldVisibility, output);
const FieldAttributes hasXAttributes = FieldAttributes.HasDefault | FieldAttributes.HasFieldMarshal | FieldAttributes.HasFieldRVA;
- WriteFlags(fieldDefinition.Attributes & ~(FieldAttributes.FieldAccessMask | hasXAttributes), fieldAttributes);
+ WriteFlags(fieldDefinition.Attributes & ~(FieldAttributes.FieldAccessMask | hasXAttributes), fieldAttributes, output);
var signature = fieldDefinition.DecodeSignature(new DisassemblerSignatureTypeProvider(module, output), new MetadataGenericContext(fieldDefinition.GetDeclaringType(), module));
@@ -1415,7 +1415,7 @@ namespace ICSharpCode.Decompiler.Disassembler
#endregion
#region Disassemble Property
- EnumNameCollection propertyAttributes = new EnumNameCollection() {
+ internal static readonly EnumNameCollection propertyAttributes = new EnumNameCollection() {
{ PropertyAttributes.SpecialName, "specialname" },
{ PropertyAttributes.RTSpecialName, "rtspecialname" },
{ PropertyAttributes.HasDefault, "hasdefault" },
@@ -1450,7 +1450,7 @@ namespace ICSharpCode.Decompiler.Disassembler
output.WriteReference(module, handle, ".property", isDefinition: true);
WriteMetadataToken(output, module, handle, MetadataTokens.GetToken(handle),
spaceAfter: true, spaceBefore: true, ShowMetadataTokens, ShowMetadataTokensInBase10);
- WriteFlags(propertyDefinition.Attributes, propertyAttributes);
+ WriteFlags(propertyDefinition.Attributes, propertyAttributes, output);
var accessors = propertyDefinition.GetAccessors();
var declaringType = metadata.GetMethodDefinition(accessors.GetAny()).GetDeclaringType();
var signature = propertyDefinition.DecodeSignature(new DisassemblerSignatureTypeProvider(module, output), new MetadataGenericContext(declaringType, module));
@@ -1489,7 +1489,7 @@ namespace ICSharpCode.Decompiler.Disassembler
#endregion
#region Disassemble Event
- EnumNameCollection eventAttributes = new EnumNameCollection() {
+ internal static readonly EnumNameCollection eventAttributes = new EnumNameCollection() {
{ EventAttributes.SpecialName, "specialname" },
{ EventAttributes.RTSpecialName, "rtspecialname" },
};
@@ -1536,7 +1536,7 @@ namespace ICSharpCode.Decompiler.Disassembler
output.WriteReference(module, handle, ".event", isDefinition: true);
WriteMetadataToken(output, module, handle, MetadataTokens.GetToken(handle),
spaceAfter: true, spaceBefore: true, ShowMetadataTokens, ShowMetadataTokensInBase10);
- WriteFlags(eventDefinition.Attributes, eventAttributes);
+ WriteFlags(eventDefinition.Attributes, eventAttributes, output);
var provider = new DisassemblerSignatureTypeProvider(module, output);
Action signature;
switch (eventDefinition.Type.Kind)
@@ -1561,7 +1561,7 @@ namespace ICSharpCode.Decompiler.Disassembler
#endregion
#region Disassemble Type
- EnumNameCollection typeVisibility = new EnumNameCollection() {
+ internal static readonly EnumNameCollection typeVisibility = new EnumNameCollection() {
{ TypeAttributes.Public, "public" },
{ TypeAttributes.NotPublic, "private" },
{ TypeAttributes.NestedPublic, "nested public" },
@@ -1584,7 +1584,7 @@ namespace ICSharpCode.Decompiler.Disassembler
{ TypeAttributes.UnicodeClass, "unicode" },
};
- EnumNameCollection typeAttributes = new EnumNameCollection() {
+ internal static readonly EnumNameCollection typeAttributes = new EnumNameCollection() {
{ TypeAttributes.Abstract, "abstract" },
{ TypeAttributes.Sealed, "sealed" },
{ TypeAttributes.SpecialName, "specialname" },
@@ -1730,11 +1730,11 @@ namespace ICSharpCode.Decompiler.Disassembler
spaceAfter: true, spaceBefore: true, ShowMetadataTokens, ShowMetadataTokensInBase10);
if ((typeDefinition.Attributes & TypeAttributes.ClassSemanticsMask) == TypeAttributes.Interface)
output.Write("interface ");
- WriteEnum(typeDefinition.Attributes & TypeAttributes.VisibilityMask, typeVisibility);
- WriteEnum(typeDefinition.Attributes & TypeAttributes.LayoutMask, typeLayout);
- WriteEnum(typeDefinition.Attributes & TypeAttributes.StringFormatMask, typeStringFormat);
+ WriteEnum(typeDefinition.Attributes & TypeAttributes.VisibilityMask, typeVisibility, output);
+ WriteEnum(typeDefinition.Attributes & TypeAttributes.LayoutMask, typeLayout, output);
+ WriteEnum(typeDefinition.Attributes & TypeAttributes.StringFormatMask, typeStringFormat, output);
const TypeAttributes masks = TypeAttributes.ClassSemanticsMask | TypeAttributes.VisibilityMask | TypeAttributes.LayoutMask | TypeAttributes.StringFormatMask;
- WriteFlags(typeDefinition.Attributes & ~masks, typeAttributes);
+ WriteFlags(typeDefinition.Attributes & ~masks, typeAttributes, output);
output.Write(typeDefinition.GetDeclaringType().IsNil ? typeDefinition.GetFullTypeName(module.Metadata).ToILNameString() : DisassemblerHelpers.Escape(module.Metadata.GetString(typeDefinition.Name)));
WriteTypeParameters(output, module, genericContext, typeDefinition.GetGenericParameters());
@@ -1967,7 +1967,7 @@ namespace ICSharpCode.Decompiler.Disassembler
output.WriteLine();
}
- void WriteFlags(T flags, EnumNameCollection flagNames) where T : struct
+ internal static void WriteFlags(T flags, EnumNameCollection flagNames, ITextOutput output) where T : struct
{
long val = Convert.ToInt64(flags);
long tested = 0;
@@ -1984,7 +1984,7 @@ namespace ICSharpCode.Decompiler.Disassembler
output.Write("flags({0:x4}) ", val & ~tested);
}
- void WriteEnum(T enumValue, EnumNameCollection enumNames) where T : struct
+ internal static void WriteEnum(T enumValue, EnumNameCollection enumNames, ITextOutput output) where T : struct
{
long val = Convert.ToInt64(enumValue);
foreach (var pair in enumNames)
@@ -2006,10 +2006,14 @@ namespace ICSharpCode.Decompiler.Disassembler
}
- sealed class EnumNameCollection : IEnumerable> where T : struct
+ internal struct EnumNameCollection : IEnumerable> where T : struct
{
List> names = new List>();
+ public EnumNameCollection()
+ {
+ }
+
public void Add(T flag, string name)
{
this.names.Add(new KeyValuePair(Convert.ToInt64(flag), name));
diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
index 20a1b5d0a..4066fee3f 100644
--- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
+++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
@@ -109,6 +109,7 @@
+
diff --git a/ICSharpCode.Decompiler/IL/ILAmbience.cs b/ICSharpCode.Decompiler/IL/ILAmbience.cs
new file mode 100644
index 000000000..071145d46
--- /dev/null
+++ b/ICSharpCode.Decompiler/IL/ILAmbience.cs
@@ -0,0 +1,520 @@
+// Copyright (c) Siegfried Pammer
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this
+// software and associated documentation files (the "Software"), to deal in the Software
+// without restriction, including without limitation the rights to use, copy, modify, merge,
+// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
+// to whom the Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or
+// substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Reflection;
+using System.Reflection.Metadata;
+using System.Text;
+
+using ICSharpCode.Decompiler.Disassembler;
+using ICSharpCode.Decompiler.Output;
+using ICSharpCode.Decompiler.TypeSystem;
+using ICSharpCode.Decompiler.TypeSystem.Implementation;
+
+#nullable enable
+
+namespace ICSharpCode.Decompiler.IL
+{
+ public class ILAmbience : IAmbience
+ {
+ public ConversionFlags ConversionFlags { get; set; }
+
+ public string ConvertConstantValue(object constantValue)
+ {
+ throw new NotImplementedException();
+ }
+
+ public string ConvertSymbol(ISymbol symbol)
+ {
+ StringWriter sw = new StringWriter();
+
+ ConvertSymbol(sw, symbol);
+
+ return sw.ToString();
+ }
+
+ void ConvertSymbol(StringWriter writer, ISymbol symbol)
+ {
+ var metadata = (symbol as IEntity)?.ParentModule!.MetadataFile?.Metadata;
+ var token = (symbol as IEntity)?.MetadataToken ?? default;
+
+ var output = new PlainTextOutput(writer);
+
+ switch (symbol)
+ {
+ case IField f:
+ Debug.Assert(metadata != null);
+ if (ConversionFlags.HasFlag(ConversionFlags.ShowDefinitionKeyword))
+ writer.Write(".field ");
+ var fd = metadata.GetFieldDefinition((FieldDefinitionHandle)token);
+ if (ConversionFlags.HasFlag(ConversionFlags.ShowAccessibility))
+ ReflectionDisassembler.WriteEnum(fd.Attributes & FieldAttributes.FieldAccessMask, ReflectionDisassembler.fieldVisibility, output);
+ if (ConversionFlags.HasFlag(ConversionFlags.ShowModifiers))
+ {
+ const FieldAttributes hasXAttributes = FieldAttributes.HasDefault | FieldAttributes.HasFieldMarshal | FieldAttributes.HasFieldRVA;
+ ReflectionDisassembler.WriteFlags(fd.Attributes & ~(FieldAttributes.FieldAccessMask | hasXAttributes), ReflectionDisassembler.fieldAttributes, output);
+ if (!f.IsStatic)
+ {
+ writer.Write("instance ");
+ }
+ }
+ break;
+ case IMethod m:
+ Debug.Assert(metadata != null);
+ if (ConversionFlags.HasFlag(ConversionFlags.ShowDefinitionKeyword))
+ writer.Write(".method ");
+ var md = metadata.GetMethodDefinition((MethodDefinitionHandle)token);
+ if (ConversionFlags.HasFlag(ConversionFlags.ShowAccessibility))
+ ReflectionDisassembler.WriteEnum(md.Attributes & MethodAttributes.MemberAccessMask, ReflectionDisassembler.methodVisibility, output);
+ if (ConversionFlags.HasFlag(ConversionFlags.ShowModifiers))
+ {
+ ReflectionDisassembler.WriteFlags(md.Attributes & ~MethodAttributes.MemberAccessMask, ReflectionDisassembler.methodAttributeFlags, output);
+ if (!m.IsStatic)
+ {
+ writer.Write("instance ");
+ }
+ }
+ break;
+ case IProperty p:
+ Debug.Assert(metadata != null);
+ if (ConversionFlags.HasFlag(ConversionFlags.ShowDefinitionKeyword))
+ writer.Write(".property ");
+ var pd = metadata.GetPropertyDefinition((PropertyDefinitionHandle)token);
+ if (ConversionFlags.HasFlag(ConversionFlags.ShowModifiers))
+ {
+ ReflectionDisassembler.WriteFlags(pd.Attributes, ReflectionDisassembler.propertyAttributes, output);
+ if (!p.IsStatic)
+ {
+ writer.Write("instance ");
+ }
+ }
+ break;
+ case IEvent e:
+ Debug.Assert(metadata != null);
+ if (ConversionFlags.HasFlag(ConversionFlags.ShowDefinitionKeyword))
+ writer.Write(".event ");
+ var ed = metadata.GetEventDefinition((EventDefinitionHandle)token);
+ if (ConversionFlags.HasFlag(ConversionFlags.ShowModifiers))
+ {
+ ReflectionDisassembler.WriteFlags(ed.Attributes, ReflectionDisassembler.eventAttributes, output);
+ if (!e.IsStatic)
+ {
+ writer.Write("instance ");
+ }
+ }
+ break;
+ case ITypeDefinition:
+ Debug.Assert(metadata != null);
+ var td = metadata.GetTypeDefinition((TypeDefinitionHandle)token);
+ if (ConversionFlags.HasFlag(ConversionFlags.ShowDefinitionKeyword))
+ {
+ writer.Write(".class ");
+ if (td.Attributes.HasFlag(TypeAttributes.Interface))
+ writer.Write("interface ");
+ }
+ if (ConversionFlags.HasFlag(ConversionFlags.ShowAccessibility))
+ ReflectionDisassembler.WriteEnum(td.Attributes & TypeAttributes.VisibilityMask, ReflectionDisassembler.typeVisibility, output);
+ const TypeAttributes masks = TypeAttributes.ClassSemanticsMask | TypeAttributes.VisibilityMask | TypeAttributes.LayoutMask | TypeAttributes.StringFormatMask;
+ if (ConversionFlags.HasFlag(ConversionFlags.ShowModifiers))
+ ReflectionDisassembler.WriteFlags(td.Attributes & ~masks, ReflectionDisassembler.typeAttributes, output);
+ break;
+ }
+
+ bool showReturnTypeBefore = ConversionFlags.HasFlag(ConversionFlags.ShowReturnType)
+ && !ConversionFlags.HasFlag(ConversionFlags.PlaceReturnTypeAfterParameterList);
+ bool showReturnTypeAfter = ConversionFlags.HasFlag(ConversionFlags.ShowReturnType)
+ && ConversionFlags.HasFlag(ConversionFlags.PlaceReturnTypeAfterParameterList);
+
+ if (showReturnTypeBefore && symbol is IMember { SymbolKind: not SymbolKind.Constructor })
+ {
+ switch (symbol)
+ {
+ case IField f:
+ writer.Write(ConvertType(f.ReturnType));
+ break;
+ case IMethod m:
+ writer.Write(ConvertType(m.ReturnType));
+ break;
+ case IProperty p:
+ writer.Write(ConvertType(p.ReturnType));
+ break;
+ case IEvent e:
+ writer.Write(ConvertType(e.ReturnType));
+ break;
+ }
+
+ writer.Write(' ');
+ }
+
+ void WriteTypeDefinition(ITypeDefinition typeDef)
+ {
+ if ((ConversionFlags.HasFlag(ConversionFlags.UseFullyQualifiedEntityNames)
+ || ConversionFlags.HasFlag(ConversionFlags.ShowDeclaringType))
+ && typeDef.DeclaringTypeDefinition != null)
+ {
+ WriteTypeDefinition(typeDef.DeclaringTypeDefinition);
+ writer.Write('.');
+ }
+ else if (ConversionFlags.HasFlag(ConversionFlags.UseFullyQualifiedEntityNames)
+ && !string.IsNullOrEmpty(typeDef.Namespace))
+ {
+ writer.Write(typeDef.Namespace);
+ writer.Write('.');
+ }
+ writer.Write(typeDef.Name);
+ WriteTypeParameters(typeDef.TypeParameters, typeDef);
+ }
+
+ void WriteTypeParameters(IReadOnlyList typeParameters, IEntity owner)
+ {
+ if (typeParameters.Count > 0)
+ {
+ int typeParameterCount = typeParameters.Count - (owner.DeclaringTypeDefinition?.TypeParameterCount ?? 0);
+ if (typeParameterCount > 0)
+ {
+ switch (owner)
+ {
+ case IType:
+ writer.Write("`");
+ break;
+ case IMethod _:
+ writer.Write("``");
+ break;
+ }
+
+ writer.Write(typeParameterCount);
+ }
+
+ if (ConversionFlags.HasFlag(ConversionFlags.ShowTypeParameterList))
+ {
+ int i = 0;
+ writer.Write('<');
+ foreach (var tp in typeParameters)
+ {
+ if (i > 0)
+ writer.Write(",");
+ if (ConversionFlags.HasFlag(ConversionFlags.ShowTypeParameterVarianceModifier))
+ {
+ switch (tp.Variance)
+ {
+ case VarianceModifier.Covariant:
+ writer.Write('+');
+ break;
+ case VarianceModifier.Contravariant:
+ writer.Write('-');
+ break;
+ }
+ }
+ writer.Write(tp.Name);
+ i++;
+ }
+ writer.Write('>');
+ }
+ }
+ }
+
+ switch (symbol)
+ {
+ case ITypeDefinition definition:
+ WriteTypeDefinition(definition);
+ break;
+ case IMember member:
+ if ((ConversionFlags.HasFlag(ConversionFlags.UseFullyQualifiedTypeNames)
+ || ConversionFlags.HasFlag(ConversionFlags.ShowDeclaringType)) && member.DeclaringTypeDefinition != null)
+ {
+ WriteTypeDefinition(member.DeclaringTypeDefinition);
+ writer.Write("::");
+ }
+ writer.Write(member.Name);
+ if (member is IMethod method)
+ {
+ WriteTypeParameters(method.TypeParameters, member);
+ }
+ break;
+ }
+
+ if (ConversionFlags.HasFlag(ConversionFlags.ShowParameterList) && symbol is IParameterizedMember { SymbolKind: not SymbolKind.Property } pm)
+ {
+ writer.Write('(');
+ int i = 0;
+ foreach (var parameter in pm.Parameters)
+ {
+ if (i > 0)
+ writer.Write(", ");
+ writer.Write(ConvertType(parameter.Type));
+ if (ConversionFlags.HasFlag(ConversionFlags.ShowParameterNames))
+ writer.Write(" " + parameter.Name);
+ i++;
+ }
+ writer.Write(')');
+ }
+
+ if (showReturnTypeAfter && symbol is IMember { SymbolKind: not SymbolKind.Constructor })
+ {
+ writer.Write(" : ");
+
+ switch (symbol)
+ {
+ case IField f:
+ writer.Write(ConvertType(f.ReturnType));
+ break;
+ case IMethod m:
+ writer.Write(ConvertType(m.ReturnType));
+ break;
+ case IProperty p:
+ writer.Write(ConvertType(p.ReturnType));
+ break;
+ case IEvent e:
+ writer.Write(ConvertType(e.ReturnType));
+ break;
+ }
+ }
+ }
+
+ public string ConvertType(IType type)
+ {
+ var visitor = new TypeToStringVisitor(ConversionFlags);
+ type.AcceptVisitor(visitor);
+ return visitor.ToString();
+ }
+
+ class TypeToStringVisitor : TypeVisitor
+ {
+ readonly ConversionFlags flags;
+ readonly StringBuilder builder;
+
+ public override string ToString()
+ {
+ return builder.ToString();
+ }
+
+ public TypeToStringVisitor(ConversionFlags flags)
+ {
+ this.flags = flags;
+ this.builder = new StringBuilder();
+ }
+
+ public override IType VisitArrayType(ArrayType type)
+ {
+ base.VisitArrayType(type);
+ builder.Append('[');
+ builder.Append(',', type.Dimensions - 1);
+ builder.Append(']');
+ return type;
+ }
+
+ public override IType VisitByReferenceType(ByReferenceType type)
+ {
+ base.VisitByReferenceType(type);
+ builder.Append('&');
+ return type;
+ }
+
+ public override IType VisitModOpt(ModifiedType type)
+ {
+ type.ElementType.AcceptVisitor(this);
+ builder.Append(" modopt(");
+ type.Modifier.AcceptVisitor(this);
+ builder.Append(")");
+ return type;
+ }
+
+ public override IType VisitModReq(ModifiedType type)
+ {
+ type.ElementType.AcceptVisitor(this);
+ builder.Append(" modreq(");
+ type.Modifier.AcceptVisitor(this);
+ builder.Append(")");
+ return type;
+ }
+
+ public override IType VisitPointerType(PointerType type)
+ {
+ base.VisitPointerType(type);
+ builder.Append('*');
+ return type;
+ }
+
+ public override IType VisitTypeParameter(ITypeParameter type)
+ {
+ base.VisitTypeParameter(type);
+ EscapeName(builder, type.Name);
+ return type;
+ }
+
+ public override IType VisitParameterizedType(ParameterizedType type)
+ {
+ type.GenericType.AcceptVisitor(this);
+ builder.Append('<');
+ for (int i = 0; i < type.TypeArguments.Count; i++)
+ {
+ if (i > 0)
+ builder.Append(',');
+ type.TypeArguments[i].AcceptVisitor(this);
+ }
+ builder.Append('>');
+ return type;
+ }
+
+ public override IType VisitTupleType(TupleType type)
+ {
+ type.UnderlyingType.AcceptVisitor(this);
+ return type;
+ }
+
+ public override IType VisitFunctionPointerType(FunctionPointerType type)
+ {
+ builder.Append("method ");
+ if (type.CallingConvention != SignatureCallingConvention.Default)
+ {
+ builder.Append(type.CallingConvention.ToILSyntax());
+ builder.Append(' ');
+ }
+ type.ReturnType.AcceptVisitor(this);
+ builder.Append(" *(");
+ bool first = true;
+ foreach (var p in type.ParameterTypes)
+ {
+ if (first)
+ first = false;
+ else
+ builder.Append(", ");
+
+ p.AcceptVisitor(this);
+ }
+ builder.Append(')');
+ return type;
+ }
+
+ public override IType VisitOtherType(IType type)
+ {
+ WriteType(type);
+ return type;
+ }
+
+ private void WriteType(IType type)
+ {
+ if (flags.HasFlag(ConversionFlags.UseFullyQualifiedTypeNames))
+ EscapeName(builder, type.FullName);
+ else
+ EscapeName(builder, type.Name);
+ if (type.TypeParameterCount > 0)
+ {
+ builder.Append('`');
+ builder.Append(type.TypeParameterCount);
+ }
+ }
+
+ public override IType VisitTypeDefinition(ITypeDefinition type)
+ {
+ switch (type.KnownTypeCode)
+ {
+ case KnownTypeCode.Object:
+ builder.Append("object");
+ break;
+ case KnownTypeCode.Boolean:
+ builder.Append("bool");
+ break;
+ case KnownTypeCode.Char:
+ builder.Append("char");
+ break;
+ case KnownTypeCode.SByte:
+ builder.Append("int8");
+ break;
+ case KnownTypeCode.Byte:
+ builder.Append("uint8");
+ break;
+ case KnownTypeCode.Int16:
+ builder.Append("int16");
+ break;
+ case KnownTypeCode.UInt16:
+ builder.Append("uint16");
+ break;
+ case KnownTypeCode.Int32:
+ builder.Append("int32");
+ break;
+ case KnownTypeCode.UInt32:
+ builder.Append("uint32");
+ break;
+ case KnownTypeCode.Int64:
+ builder.Append("int64");
+ break;
+ case KnownTypeCode.UInt64:
+ builder.Append("uint64");
+ break;
+ case KnownTypeCode.Single:
+ builder.Append("float32");
+ break;
+ case KnownTypeCode.Double:
+ builder.Append("float64");
+ break;
+ case KnownTypeCode.String:
+ builder.Append("string");
+ break;
+ case KnownTypeCode.Void:
+ builder.Append("void");
+ break;
+ case KnownTypeCode.IntPtr:
+ builder.Append("native int");
+ break;
+ case KnownTypeCode.UIntPtr:
+ builder.Append("native uint");
+ break;
+ case KnownTypeCode.TypedReference:
+ builder.Append("typedref");
+ break;
+ default:
+ WriteType(type);
+ break;
+ }
+ return type;
+ }
+ }
+
+ public string WrapComment(string comment)
+ {
+ return "// " + comment;
+ }
+
+ ///
+ /// Escape characters that cannot be displayed in the UI.
+ ///
+ public static StringBuilder EscapeName(StringBuilder sb, string name)
+ {
+ foreach (char ch in name)
+ {
+ if (char.IsWhiteSpace(ch) || char.IsControl(ch) || char.IsSurrogate(ch))
+ sb.AppendFormat("\\u{0:x4}", (int)ch);
+ else
+ sb.Append(ch);
+ }
+ return sb;
+ }
+
+ ///
+ /// Escape characters that cannot be displayed in the UI.
+ ///
+ public static string EscapeName(string name)
+ {
+ return EscapeName(new StringBuilder(name.Length), name).ToString();
+ }
+ }
+}
diff --git a/ICSharpCode.ILSpyX/Abstractions/ILanguage.cs b/ICSharpCode.ILSpyX/Abstractions/ILanguage.cs
index e230f4467..1d85e3aca 100644
--- a/ICSharpCode.ILSpyX/Abstractions/ILanguage.cs
+++ b/ICSharpCode.ILSpyX/Abstractions/ILanguage.cs
@@ -19,6 +19,7 @@
using System.Reflection.Metadata;
using ICSharpCode.Decompiler.Metadata;
+using ICSharpCode.Decompiler.Output;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.ILSpyX.Abstractions
@@ -30,10 +31,7 @@ namespace ICSharpCode.ILSpyX.Abstractions
string GetEntityName(MetadataFile module, System.Reflection.Metadata.EntityHandle handle, bool fullName, bool omitGenerics);
string GetTooltip(IEntity entity);
- string TypeToString(IType type, bool includeNamespace);
- string MethodToString(IMethod method, bool includeDeclaringTypeName, bool includeNamespace, bool includeNamespaceOfDeclaringTypeName);
- string FieldToString(IField field, bool includeDeclaringTypeName, bool includeNamespace, bool includeNamespaceOfDeclaringTypeName);
- string PropertyToString(IProperty property, bool includeDeclaringTypeName, bool includeNamespace, bool includeNamespaceOfDeclaringTypeName);
- string EventToString(IEvent @event, bool includeDeclaringTypeName, bool includeNamespace, bool includeNamespaceOfDeclaringTypeName);
+ string TypeToString(IType type, ConversionFlags conversionFlags = ConversionFlags.UseFullyQualifiedEntityNames | ConversionFlags.UseFullyQualifiedTypeNames);
+ string EntityToString(IEntity entity, ConversionFlags conversionFlags);
}
}
diff --git a/ILSpy/Analyzers/TreeNodes/AnalyzedEventTreeNode.cs b/ILSpy/Analyzers/TreeNodes/AnalyzedEventTreeNode.cs
index a197ed0a2..9df55a061 100644
--- a/ILSpy/Analyzers/TreeNodes/AnalyzedEventTreeNode.cs
+++ b/ILSpy/Analyzers/TreeNodes/AnalyzedEventTreeNode.cs
@@ -20,6 +20,7 @@ using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
+using ICSharpCode.Decompiler.Output;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpy.TreeNodes;
@@ -45,7 +46,7 @@ namespace ICSharpCode.ILSpy.Analyzers.TreeNodes
public override object Icon => EventTreeNode.GetIcon(analyzedEvent);
// TODO: This way of formatting is not suitable for events which explicitly implement interfaces.
- public override object Text => prefix + Language.EventToString(analyzedEvent, includeDeclaringTypeName: true, includeNamespace: false, includeNamespaceOfDeclaringTypeName: true);
+ public override object Text => prefix + Language.EntityToString(analyzedEvent, ConversionFlags.ShowDeclaringType | ConversionFlags.UseFullyQualifiedEntityNames);
protected override void LoadChildren()
{
diff --git a/ILSpy/Analyzers/TreeNodes/AnalyzedFieldTreeNode.cs b/ILSpy/Analyzers/TreeNodes/AnalyzedFieldTreeNode.cs
index 48831a67c..64a508c57 100644
--- a/ILSpy/Analyzers/TreeNodes/AnalyzedFieldTreeNode.cs
+++ b/ILSpy/Analyzers/TreeNodes/AnalyzedFieldTreeNode.cs
@@ -19,6 +19,7 @@
using System;
using System.Diagnostics;
+using ICSharpCode.Decompiler.Output;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpy.TreeNodes;
@@ -39,7 +40,7 @@ namespace ICSharpCode.ILSpy.Analyzers.TreeNodes
public override object Icon => FieldTreeNode.GetIcon(analyzedField);
- public override object Text => Language.FieldToString(analyzedField, true, false, true);
+ public override object Text => Language.EntityToString(analyzedField, ConversionFlags.ShowDeclaringType | ConversionFlags.UseFullyQualifiedEntityNames);
protected override void LoadChildren()
{
diff --git a/ILSpy/Analyzers/TreeNodes/AnalyzedMethodTreeNode.cs b/ILSpy/Analyzers/TreeNodes/AnalyzedMethodTreeNode.cs
index 421c9bf2d..2ce76fe51 100644
--- a/ILSpy/Analyzers/TreeNodes/AnalyzedMethodTreeNode.cs
+++ b/ILSpy/Analyzers/TreeNodes/AnalyzedMethodTreeNode.cs
@@ -19,6 +19,7 @@
using System;
using System.Diagnostics;
+using ICSharpCode.Decompiler.Output;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpy.TreeNodes;
@@ -41,7 +42,7 @@ namespace ICSharpCode.ILSpy.Analyzers.TreeNodes
public override object Icon => MethodTreeNode.GetIcon(analyzedMethod);
- public override object Text => prefix + Language.MethodToString(analyzedMethod, true, false, true);
+ public override object Text => prefix + Language.EntityToString(analyzedMethod, ConversionFlags.ShowDeclaringType | ConversionFlags.UseFullyQualifiedEntityNames);
protected override void LoadChildren()
{
diff --git a/ILSpy/Analyzers/TreeNodes/AnalyzedPropertyTreeNode.cs b/ILSpy/Analyzers/TreeNodes/AnalyzedPropertyTreeNode.cs
index 4de437182..d6cb1df5e 100644
--- a/ILSpy/Analyzers/TreeNodes/AnalyzedPropertyTreeNode.cs
+++ b/ILSpy/Analyzers/TreeNodes/AnalyzedPropertyTreeNode.cs
@@ -19,6 +19,7 @@
using System;
using System.Diagnostics;
+using ICSharpCode.Decompiler.Output;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpy.TreeNodes;
@@ -42,7 +43,7 @@ namespace ICSharpCode.ILSpy.Analyzers.TreeNodes
public override object Icon => PropertyTreeNode.GetIcon(analyzedProperty);
// TODO: This way of formatting is not suitable for properties which explicitly implement interfaces.
- public override object Text => prefix + Language.PropertyToString(analyzedProperty, includeNamespace: false, includeDeclaringTypeName: true, includeNamespaceOfDeclaringTypeName: true);
+ public override object Text => prefix + Language.EntityToString(analyzedProperty, ConversionFlags.ShowDeclaringType | ConversionFlags.UseFullyQualifiedEntityNames);
protected override void LoadChildren()
{
diff --git a/ILSpy/Analyzers/TreeNodes/AnalyzedTypeTreeNode.cs b/ILSpy/Analyzers/TreeNodes/AnalyzedTypeTreeNode.cs
index c4cd300ce..67f37d6f9 100644
--- a/ILSpy/Analyzers/TreeNodes/AnalyzedTypeTreeNode.cs
+++ b/ILSpy/Analyzers/TreeNodes/AnalyzedTypeTreeNode.cs
@@ -39,7 +39,7 @@ namespace ICSharpCode.ILSpy.Analyzers.TreeNodes
public override object Icon => TypeTreeNode.GetIcon(analyzedType);
- public override object Text => Language.TypeToString(analyzedType, includeNamespace: true);
+ public override object Text => Language.TypeToString(analyzedType);
protected override void LoadChildren()
{
diff --git a/ILSpy/Languages/CSharpLanguage.cs b/ILSpy/Languages/CSharpLanguage.cs
index 7ec5bb06a..2e0ef396d 100644
--- a/ILSpy/Languages/CSharpLanguage.cs
+++ b/ILSpy/Languages/CSharpLanguage.cs
@@ -34,6 +34,7 @@ using ICSharpCode.Decompiler.CSharp.OutputVisitor;
using ICSharpCode.Decompiler.CSharp.ProjectDecompiler;
using ICSharpCode.Decompiler.CSharp.Syntax;
using ICSharpCode.Decompiler.CSharp.Transforms;
+using ICSharpCode.Decompiler.IL;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.Output;
using ICSharpCode.Decompiler.Solution;
@@ -157,7 +158,7 @@ namespace ICSharpCode.ILSpy
AddReferenceAssemblyWarningMessage(assembly, output);
AddReferenceWarningMessage(assembly, output);
WriteCommentLine(output, assembly.FullName);
- WriteCommentLine(output, TypeToString(method.DeclaringType, includeNamespace: true));
+ WriteCommentLine(output, TypeToString(method.DeclaringType));
var methodDefinition = decompiler.TypeSystem.MainModule.ResolveEntity(method.MetadataToken) as IMethod;
if (methodDefinition.IsConstructor && methodDefinition.DeclaringType.IsReferenceType != false)
{
@@ -258,7 +259,7 @@ namespace ICSharpCode.ILSpy
AddReferenceAssemblyWarningMessage(assembly, output);
AddReferenceWarningMessage(assembly, output);
WriteCommentLine(output, assembly.FullName);
- WriteCommentLine(output, TypeToString(property.DeclaringType, includeNamespace: true));
+ WriteCommentLine(output, TypeToString(property.DeclaringType));
WriteCode(output, options.DecompilerSettings, decompiler.Decompile(property.MetadataToken), decompiler.TypeSystem);
}
@@ -269,7 +270,7 @@ namespace ICSharpCode.ILSpy
AddReferenceAssemblyWarningMessage(assembly, output);
AddReferenceWarningMessage(assembly, output);
WriteCommentLine(output, assembly.FullName);
- WriteCommentLine(output, TypeToString(field.DeclaringType, includeNamespace: true));
+ WriteCommentLine(output, TypeToString(field.DeclaringType));
if (field.IsConst)
{
WriteCode(output, options.DecompilerSettings, decompiler.Decompile(field.MetadataToken), decompiler.TypeSystem);
@@ -348,7 +349,7 @@ namespace ICSharpCode.ILSpy
AddReferenceAssemblyWarningMessage(assembly, output);
AddReferenceWarningMessage(assembly, output);
WriteCommentLine(output, assembly.FullName);
- WriteCommentLine(output, TypeToString(@event.DeclaringType, includeNamespace: true));
+ WriteCommentLine(output, TypeToString(@event.DeclaringType));
WriteCode(output, options.DecompilerSettings, decompiler.Decompile(@event.MetadataToken), decompiler.TypeSystem);
}
@@ -359,7 +360,7 @@ namespace ICSharpCode.ILSpy
AddReferenceAssemblyWarningMessage(assembly, output);
AddReferenceWarningMessage(assembly, output);
WriteCommentLine(output, assembly.FullName);
- WriteCommentLine(output, TypeToString(type, includeNamespace: true));
+ WriteCommentLine(output, TypeToString(type, ConversionFlags.UseFullyQualifiedTypeNames | ConversionFlags.UseFullyQualifiedEntityNames));
WriteCode(output, options.DecompilerSettings, decompiler.Decompile(type.MetadataToken), decompiler.TypeSystem);
}
@@ -456,7 +457,7 @@ namespace ICSharpCode.ILSpy
if (globalType != null)
{
output.Write("// Global type: ");
- output.WriteReference(globalType, EscapeName(globalType.FullName));
+ output.WriteReference(globalType, ILAmbience.EscapeName(globalType.FullName));
output.WriteLine();
}
var metadata = module.Metadata;
@@ -470,7 +471,7 @@ namespace ICSharpCode.ILSpy
if (entrypoint != null)
{
output.Write("// Entry point: ");
- output.WriteReference(entrypoint, EscapeName(entrypoint.DeclaringType.FullName + "." + entrypoint.Name));
+ output.WriteReference(entrypoint, ILAmbience.EscapeName(entrypoint.DeclaringType.FullName + "." + entrypoint.Name));
output.WriteLine();
}
}
@@ -595,40 +596,27 @@ namespace ICSharpCode.ILSpy
return ambience;
}
- string EntityToString(IEntity entity, bool includeDeclaringTypeName, bool includeNamespace, bool includeNamespaceOfDeclaringTypeName)
+ public override string EntityToString(IEntity entity, ConversionFlags conversionFlags)
{
// Do not forget to update CSharpAmbienceTests, if this ever changes.
var ambience = CreateAmbience();
- ambience.ConversionFlags |= ConversionFlags.ShowReturnType | ConversionFlags.ShowParameterList | ConversionFlags.ShowParameterModifiers;
- if (includeDeclaringTypeName)
- ambience.ConversionFlags |= ConversionFlags.ShowDeclaringType;
- if (includeNamespace)
- ambience.ConversionFlags |= ConversionFlags.UseFullyQualifiedTypeNames;
- if (includeNamespaceOfDeclaringTypeName)
- ambience.ConversionFlags |= ConversionFlags.UseFullyQualifiedEntityNames;
+ ambience.ConversionFlags |= conversionFlags
+ | ConversionFlags.ShowReturnType
+ | ConversionFlags.ShowParameterList
+ | ConversionFlags.ShowParameterModifiers;
return ambience.ConvertSymbol(entity);
}
- public override string TypeToString(IType type, bool includeNamespace)
+ public override string TypeToString(IType type, ConversionFlags conversionFlags = ConversionFlags.UseFullyQualifiedEntityNames | ConversionFlags.UseFullyQualifiedTypeNames)
{
if (type == null)
throw new ArgumentNullException(nameof(type));
var ambience = CreateAmbience();
// Do not forget to update CSharpAmbienceTests.ILSpyMainTreeViewFlags, if this ever changes.
- if (includeNamespace)
- {
- ambience.ConversionFlags |= ConversionFlags.UseFullyQualifiedTypeNames;
- ambience.ConversionFlags |= ConversionFlags.UseFullyQualifiedEntityNames;
- }
+ ambience.ConversionFlags |= conversionFlags;
if (type is ITypeDefinition definition)
{
return ambience.ConvertSymbol(definition);
- // HACK : UnknownType is not supported by CSharpAmbience.
- }
- else if (type.Kind == TypeKind.Unknown)
- {
- return (includeNamespace ? type.FullName : type.Name)
- + (type.TypeParameterCount > 0 ? "<" + string.Join(", ", type.TypeArguments.Select(t => t.Name)) + ">" : "");
}
else
{
@@ -636,34 +624,6 @@ namespace ICSharpCode.ILSpy
}
}
- public override string FieldToString(IField field, bool includeDeclaringTypeName, bool includeNamespace, bool includeNamespaceOfDeclaringTypeName)
- {
- if (field == null)
- throw new ArgumentNullException(nameof(field));
- return EntityToString(field, includeDeclaringTypeName, includeNamespace, includeNamespaceOfDeclaringTypeName);
- }
-
- public override string PropertyToString(IProperty property, bool includeDeclaringTypeName, bool includeNamespace, bool includeNamespaceOfDeclaringTypeName)
- {
- if (property == null)
- throw new ArgumentNullException(nameof(property));
- return EntityToString(property, includeDeclaringTypeName, includeNamespace, includeNamespaceOfDeclaringTypeName);
- }
-
- public override string MethodToString(IMethod method, bool includeDeclaringTypeName, bool includeNamespace, bool includeNamespaceOfDeclaringTypeName)
- {
- if (method == null)
- throw new ArgumentNullException(nameof(method));
- return EntityToString(method, includeDeclaringTypeName, includeNamespace, includeNamespaceOfDeclaringTypeName);
- }
-
- public override string EventToString(IEvent @event, bool includeDeclaringTypeName, bool includeNamespace, bool includeNamespaceOfDeclaringTypeName)
- {
- if (@event == null)
- throw new ArgumentNullException(nameof(@event));
- return EntityToString(@event, includeDeclaringTypeName, includeNamespace, includeNamespaceOfDeclaringTypeName);
- }
-
static string ToCSharpString(MetadataReader metadata, TypeDefinitionHandle handle, bool fullName, bool omitGenerics)
{
var currentTypeDefHandle = handle;
diff --git a/ILSpy/Languages/Language.cs b/ILSpy/Languages/Language.cs
index 072b2a9d4..3aa09dff3 100644
--- a/ILSpy/Languages/Language.cs
+++ b/ILSpy/Languages/Language.cs
@@ -21,14 +21,14 @@ using System.Collections.Generic;
using System.Linq;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
-using System.Text;
using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.Decompiler;
+using ICSharpCode.Decompiler.IL;
using ICSharpCode.Decompiler.Metadata;
+using ICSharpCode.Decompiler.Output;
using ICSharpCode.Decompiler.Solution;
using ICSharpCode.Decompiler.TypeSystem;
-using ICSharpCode.Decompiler.TypeSystem.Implementation;
using ICSharpCode.Decompiler.Util;
using ICSharpCode.ILSpy.AssemblyTree;
using ICSharpCode.ILSpyX;
@@ -87,27 +87,27 @@ namespace ICSharpCode.ILSpy
public virtual void DecompileMethod(IMethod method, ITextOutput output, DecompilationOptions options)
{
- WriteCommentLine(output, TypeToString(method.DeclaringTypeDefinition, includeNamespace: true) + "." + method.Name);
+ WriteCommentLine(output, TypeToString(method.DeclaringTypeDefinition) + "." + method.Name);
}
public virtual void DecompileProperty(IProperty property, ITextOutput output, DecompilationOptions options)
{
- WriteCommentLine(output, TypeToString(property.DeclaringTypeDefinition, includeNamespace: true) + "." + property.Name);
+ WriteCommentLine(output, TypeToString(property.DeclaringTypeDefinition) + "." + property.Name);
}
public virtual void DecompileField(IField field, ITextOutput output, DecompilationOptions options)
{
- WriteCommentLine(output, TypeToString(field.DeclaringTypeDefinition, includeNamespace: true) + "." + field.Name);
+ WriteCommentLine(output, TypeToString(field.DeclaringTypeDefinition) + "." + field.Name);
}
public virtual void DecompileEvent(IEvent @event, ITextOutput output, DecompilationOptions options)
{
- WriteCommentLine(output, TypeToString(@event.DeclaringTypeDefinition, includeNamespace: true) + "." + @event.Name);
+ WriteCommentLine(output, TypeToString(@event.DeclaringTypeDefinition) + "." + @event.Name);
}
public virtual void DecompileType(ITypeDefinition type, ITextOutput output, DecompilationOptions options)
{
- WriteCommentLine(output, TypeToString(type, includeNamespace: true));
+ WriteCommentLine(output, TypeToString(type));
}
public virtual void DecompileNamespace(string nameSpace, IEnumerable types, ITextOutput output, DecompilationOptions options)
@@ -158,204 +158,9 @@ namespace ICSharpCode.ILSpy
///
/// Converts a type definition, reference or specification into a string. This method is used by tree nodes and search results.
///
- public virtual string TypeToString(IType type, bool includeNamespace)
+ public virtual string TypeToString(IType type, ConversionFlags conversionFlags = ConversionFlags.UseFullyQualifiedTypeNames | ConversionFlags.UseFullyQualifiedEntityNames)
{
- var visitor = new TypeToStringVisitor(includeNamespace);
- type.AcceptVisitor(visitor);
- return visitor.ToString();
- }
-
- class TypeToStringVisitor : TypeVisitor
- {
- readonly bool includeNamespace;
- readonly StringBuilder builder;
-
- public override string ToString()
- {
- return builder.ToString();
- }
-
- public TypeToStringVisitor(bool includeNamespace)
- {
- this.includeNamespace = includeNamespace;
- this.builder = new StringBuilder();
- }
-
- public override IType VisitArrayType(ArrayType type)
- {
- base.VisitArrayType(type);
- builder.Append('[');
- builder.Append(',', type.Dimensions - 1);
- builder.Append(']');
- return type;
- }
-
- public override IType VisitByReferenceType(ByReferenceType type)
- {
- base.VisitByReferenceType(type);
- builder.Append('&');
- return type;
- }
-
- public override IType VisitModOpt(ModifiedType type)
- {
- type.ElementType.AcceptVisitor(this);
- builder.Append(" modopt(");
- type.Modifier.AcceptVisitor(this);
- builder.Append(")");
- return type;
- }
-
- public override IType VisitModReq(ModifiedType type)
- {
- type.ElementType.AcceptVisitor(this);
- builder.Append(" modreq(");
- type.Modifier.AcceptVisitor(this);
- builder.Append(")");
- return type;
- }
-
- public override IType VisitPointerType(PointerType type)
- {
- base.VisitPointerType(type);
- builder.Append('*');
- return type;
- }
-
- public override IType VisitTypeParameter(ITypeParameter type)
- {
- base.VisitTypeParameter(type);
- EscapeName(builder, type.Name);
- return type;
- }
-
- public override IType VisitParameterizedType(ParameterizedType type)
- {
- type.GenericType.AcceptVisitor(this);
- builder.Append('<');
- for (int i = 0; i < type.TypeArguments.Count; i++)
- {
- if (i > 0)
- builder.Append(',');
- type.TypeArguments[i].AcceptVisitor(this);
- }
- builder.Append('>');
- return type;
- }
-
- public override IType VisitTupleType(TupleType type)
- {
- type.UnderlyingType.AcceptVisitor(this);
- return type;
- }
-
- public override IType VisitFunctionPointerType(FunctionPointerType type)
- {
- builder.Append("method ");
- if (type.CallingConvention != SignatureCallingConvention.Default)
- {
- builder.Append(type.CallingConvention.ToILSyntax());
- builder.Append(' ');
- }
- type.ReturnType.AcceptVisitor(this);
- builder.Append(" *(");
- bool first = true;
- foreach (var p in type.ParameterTypes)
- {
- if (first)
- first = false;
- else
- builder.Append(", ");
-
- p.AcceptVisitor(this);
- }
- builder.Append(')');
- return type;
- }
-
- public override IType VisitOtherType(IType type)
- {
- WriteType(type);
- return type;
- }
-
- private void WriteType(IType type)
- {
- if (includeNamespace)
- EscapeName(builder, type.FullName);
- else
- EscapeName(builder, type.Name);
- if (type.TypeParameterCount > 0)
- {
- builder.Append('`');
- builder.Append(type.TypeParameterCount);
- }
- }
-
- public override IType VisitTypeDefinition(ITypeDefinition type)
- {
- switch (type.KnownTypeCode)
- {
- case KnownTypeCode.Object:
- builder.Append("object");
- break;
- case KnownTypeCode.Boolean:
- builder.Append("bool");
- break;
- case KnownTypeCode.Char:
- builder.Append("char");
- break;
- case KnownTypeCode.SByte:
- builder.Append("int8");
- break;
- case KnownTypeCode.Byte:
- builder.Append("uint8");
- break;
- case KnownTypeCode.Int16:
- builder.Append("int16");
- break;
- case KnownTypeCode.UInt16:
- builder.Append("uint16");
- break;
- case KnownTypeCode.Int32:
- builder.Append("int32");
- break;
- case KnownTypeCode.UInt32:
- builder.Append("uint32");
- break;
- case KnownTypeCode.Int64:
- builder.Append("int64");
- break;
- case KnownTypeCode.UInt64:
- builder.Append("uint64");
- break;
- case KnownTypeCode.Single:
- builder.Append("float32");
- break;
- case KnownTypeCode.Double:
- builder.Append("float64");
- break;
- case KnownTypeCode.String:
- builder.Append("string");
- break;
- case KnownTypeCode.Void:
- builder.Append("void");
- break;
- case KnownTypeCode.IntPtr:
- builder.Append("native int");
- break;
- case KnownTypeCode.UIntPtr:
- builder.Append("native uint");
- break;
- case KnownTypeCode.TypedReference:
- builder.Append("typedref");
- break;
- default:
- WriteType(type);
- break;
- }
- return type;
- }
+ return new ILAmbience() { ConversionFlags = conversionFlags }.ConvertType(type);
}
#endregion
@@ -377,72 +182,92 @@ namespace ICSharpCode.ILSpy
return GetTooltip(entity);
}
+ [Obsolete("Use EntityToString instead")]
public virtual string FieldToString(IField field, bool includeDeclaringTypeName, bool includeNamespace, bool includeNamespaceOfDeclaringTypeName)
{
if (field == null)
throw new ArgumentNullException(nameof(field));
- return GetDisplayName(field, includeDeclaringTypeName, includeNamespace, includeNamespaceOfDeclaringTypeName) + " : " + TypeToString(field.ReturnType, includeNamespace);
+ var flags = ConversionFlags.ShowTypeParameterList
+ | ConversionFlags.PlaceReturnTypeAfterParameterList
+ | ConversionFlags.ShowReturnType
+ | ConversionFlags.ShowParameterList
+ | ConversionFlags.ShowParameterModifiers;
+ if (includeDeclaringTypeName)
+ flags |= ConversionFlags.ShowDeclaringType;
+ if (includeNamespace)
+ flags |= ConversionFlags.UseFullyQualifiedTypeNames;
+ if (includeNamespaceOfDeclaringTypeName)
+ flags |= ConversionFlags.UseFullyQualifiedEntityNames;
+ return EntityToString(field, flags);
}
+ [Obsolete("Use EntityToString instead")]
public virtual string PropertyToString(IProperty property, bool includeDeclaringTypeName, bool includeNamespace, bool includeNamespaceOfDeclaringTypeName)
{
if (property == null)
throw new ArgumentNullException(nameof(property));
- return GetDisplayName(property, includeDeclaringTypeName, includeNamespace, includeNamespaceOfDeclaringTypeName) + " : " + TypeToString(property.ReturnType, includeNamespace);
+ var flags = ConversionFlags.ShowTypeParameterList
+ | ConversionFlags.PlaceReturnTypeAfterParameterList
+ | ConversionFlags.ShowReturnType
+ | ConversionFlags.ShowParameterList
+ | ConversionFlags.ShowParameterModifiers;
+ if (includeDeclaringTypeName)
+ flags |= ConversionFlags.ShowDeclaringType;
+ if (includeNamespace)
+ flags |= ConversionFlags.UseFullyQualifiedTypeNames;
+ if (includeNamespaceOfDeclaringTypeName)
+ flags |= ConversionFlags.UseFullyQualifiedEntityNames;
+ return EntityToString(property, flags);
}
+ [Obsolete("Use EntityToString instead")]
public virtual string MethodToString(IMethod method, bool includeDeclaringTypeName, bool includeNamespace, bool includeNamespaceOfDeclaringTypeName)
{
if (method == null)
throw new ArgumentNullException(nameof(method));
-
- int i = 0;
- var buffer = new StringBuilder();
- buffer.Append(GetDisplayName(method, includeDeclaringTypeName, includeNamespace, includeNamespaceOfDeclaringTypeName));
- var typeParameters = method.TypeParameters;
- if (typeParameters.Count > 0)
- {
- buffer.Append("``");
- buffer.Append(typeParameters.Count);
- buffer.Append('<');
- foreach (var tp in typeParameters)
- {
- if (i > 0)
- buffer.Append(", ");
- buffer.Append(tp.Name);
- i++;
- }
- buffer.Append('>');
- }
- buffer.Append('(');
-
- i = 0;
- var parameters = method.Parameters;
- foreach (var param in parameters)
- {
- if (i > 0)
- buffer.Append(", ");
- buffer.Append(TypeToString(param.Type, includeNamespace));
- i++;
- }
- buffer.Append(')');
- if (!method.IsConstructor)
- {
- buffer.Append(" : ");
- buffer.Append(TypeToString(method.ReturnType, includeNamespace));
- }
- return buffer.ToString();
+ var flags = ConversionFlags.ShowTypeParameterList
+ | ConversionFlags.PlaceReturnTypeAfterParameterList
+ | ConversionFlags.ShowReturnType
+ | ConversionFlags.ShowParameterList
+ | ConversionFlags.ShowParameterModifiers;
+ if (includeDeclaringTypeName)
+ flags |= ConversionFlags.ShowDeclaringType;
+ if (includeNamespace)
+ flags |= ConversionFlags.UseFullyQualifiedTypeNames;
+ if (includeNamespaceOfDeclaringTypeName)
+ flags |= ConversionFlags.UseFullyQualifiedEntityNames;
+ return EntityToString(method, flags);
}
+ [Obsolete("Use EntityToString instead")]
public virtual string EventToString(IEvent @event, bool includeDeclaringTypeName, bool includeNamespace, bool includeNamespaceOfDeclaringTypeName)
{
if (@event == null)
throw new ArgumentNullException(nameof(@event));
- var buffer = new StringBuilder();
- buffer.Append(GetDisplayName(@event, includeDeclaringTypeName, includeNamespace, includeNamespaceOfDeclaringTypeName));
- buffer.Append(" : ");
- buffer.Append(TypeToString(@event.ReturnType, includeNamespace));
- return buffer.ToString();
+ var flags = ConversionFlags.ShowTypeParameterList
+ | ConversionFlags.PlaceReturnTypeAfterParameterList
+ | ConversionFlags.ShowReturnType
+ | ConversionFlags.ShowParameterList
+ | ConversionFlags.ShowParameterModifiers;
+ if (includeDeclaringTypeName)
+ flags |= ConversionFlags.ShowDeclaringType;
+ if (includeNamespace)
+ flags |= ConversionFlags.UseFullyQualifiedTypeNames;
+ if (includeNamespaceOfDeclaringTypeName)
+ flags |= ConversionFlags.UseFullyQualifiedEntityNames;
+ return EntityToString(@event, flags);
+ }
+
+ public virtual string EntityToString(IEntity entity, ConversionFlags conversionFlags)
+ {
+ var ambience = new ILAmbience();
+ ambience.ConversionFlags = ConversionFlags.ShowTypeParameterList
+ | ConversionFlags.PlaceReturnTypeAfterParameterList
+ | ConversionFlags.ShowReturnType
+ | ConversionFlags.ShowParameterList
+ | ConversionFlags.ShowParameterModifiers
+ | conversionFlags;
+ return ambience.ConvertSymbol(entity);
}
protected string GetDisplayName(IEntity entity, bool includeDeclaringTypeName, bool includeNamespace, bool includeNamespaceOfDeclaringTypeName)
@@ -452,17 +277,17 @@ namespace ICSharpCode.ILSpy
{
MetadataReader metadata = t.ParentModule.MetadataFile.Metadata;
var typeDef = metadata.GetTypeDefinition((TypeDefinitionHandle)t.MetadataToken);
- entityName = EscapeName(metadata.GetString(typeDef.Name));
+ entityName = ILAmbience.EscapeName(metadata.GetString(typeDef.Name));
}
else
{
- entityName = EscapeName(entity.Name);
+ entityName = ILAmbience.EscapeName(entity.Name);
}
if (includeNamespace || includeDeclaringTypeName)
{
if (entity.DeclaringTypeDefinition != null)
- return TypeToString(entity.DeclaringTypeDefinition, includeNamespaceOfDeclaringTypeName) + "." + entityName;
- return EscapeName(entity.Namespace) + "." + entityName;
+ return TypeToString(entity.DeclaringTypeDefinition, ConversionFlags.ShowDeclaringType | ConversionFlags.UseFullyQualifiedEntityNames) + "." + entityName;
+ return ILAmbience.EscapeName(entity.Namespace) + "." + entityName;
}
else
{
@@ -493,14 +318,14 @@ namespace ICSharpCode.ILSpy
{
case HandleKind.TypeDefinition:
if (fullName)
- return EscapeName(((TypeDefinitionHandle)handle).GetFullTypeName(metadata).ToILNameString(omitGenerics));
+ return ILAmbience.EscapeName(((TypeDefinitionHandle)handle).GetFullTypeName(metadata).ToILNameString(omitGenerics));
var td = metadata.GetTypeDefinition((TypeDefinitionHandle)handle);
- return EscapeName(metadata.GetString(td.Name));
+ return ILAmbience.EscapeName(metadata.GetString(td.Name));
case HandleKind.FieldDefinition:
var fd = metadata.GetFieldDefinition((FieldDefinitionHandle)handle);
if (fullName)
- return EscapeName(fd.GetDeclaringType().GetFullTypeName(metadata).ToILNameString(omitGenerics) + "." + metadata.GetString(fd.Name));
- return EscapeName(metadata.GetString(fd.Name));
+ return ILAmbience.EscapeName(fd.GetDeclaringType().GetFullTypeName(metadata).ToILNameString(omitGenerics) + "." + metadata.GetString(fd.Name));
+ return ILAmbience.EscapeName(metadata.GetString(fd.Name));
case HandleKind.MethodDefinition:
var md = metadata.GetMethodDefinition((MethodDefinitionHandle)handle);
string methodName = metadata.GetString(md.Name);
@@ -511,20 +336,20 @@ namespace ICSharpCode.ILSpy
methodName += "``" + genericParamCount;
}
if (fullName)
- return EscapeName(md.GetDeclaringType().GetFullTypeName(metadata).ToILNameString(omitGenerics) + "." + methodName);
- return EscapeName(methodName);
+ return ILAmbience.EscapeName(md.GetDeclaringType().GetFullTypeName(metadata).ToILNameString(omitGenerics) + "." + methodName);
+ return ILAmbience.EscapeName(methodName);
case HandleKind.EventDefinition:
var ed = metadata.GetEventDefinition((EventDefinitionHandle)handle);
var declaringType = metadata.GetMethodDefinition(ed.GetAccessors().GetAny()).GetDeclaringType();
if (fullName)
- return EscapeName(declaringType.GetFullTypeName(metadata).ToILNameString(omitGenerics) + "." + metadata.GetString(ed.Name));
- return EscapeName(metadata.GetString(ed.Name));
+ return ILAmbience.EscapeName(declaringType.GetFullTypeName(metadata).ToILNameString(omitGenerics) + "." + metadata.GetString(ed.Name));
+ return ILAmbience.EscapeName(metadata.GetString(ed.Name));
case HandleKind.PropertyDefinition:
var pd = metadata.GetPropertyDefinition((PropertyDefinitionHandle)handle);
declaringType = metadata.GetMethodDefinition(pd.GetAccessors().GetAny()).GetDeclaringType();
if (fullName)
- return EscapeName(declaringType.GetFullTypeName(metadata).ToILNameString(omitGenerics) + "." + metadata.GetString(pd.Name));
- return EscapeName(metadata.GetString(pd.Name));
+ return ILAmbience.EscapeName(declaringType.GetFullTypeName(metadata).ToILNameString(omitGenerics) + "." + metadata.GetString(pd.Name));
+ return ILAmbience.EscapeName(metadata.GetString(pd.Name));
default:
return null;
}
@@ -573,28 +398,5 @@ namespace ICSharpCode.ILSpy
{
return module.Metadata.MetadataVersion;
}
-
- ///
- /// Escape characters that cannot be displayed in the UI.
- ///
- public static StringBuilder EscapeName(StringBuilder sb, string name)
- {
- foreach (char ch in name)
- {
- if (char.IsWhiteSpace(ch) || char.IsControl(ch) || char.IsSurrogate(ch))
- sb.AppendFormat("\\u{0:x4}", (int)ch);
- else
- sb.Append(ch);
- }
- return sb;
- }
-
- ///
- /// Escape characters that cannot be displayed in the UI.
- ///
- public static string EscapeName(string name)
- {
- return EscapeName(new StringBuilder(name.Length), name).ToString();
- }
}
}
diff --git a/ILSpy/Search/SearchResultFactory.cs b/ILSpy/Search/SearchResultFactory.cs
index 4c12095ff..7fd1f6220 100644
--- a/ILSpy/Search/SearchResultFactory.cs
+++ b/ILSpy/Search/SearchResultFactory.cs
@@ -16,11 +16,11 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
-using System.Collections.Generic;
using System.Composition;
using System.Windows.Media;
using ICSharpCode.Decompiler.Metadata;
+using ICSharpCode.Decompiler.Output;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpy.TreeNodes;
using ICSharpCode.ILSpyX.Abstractions;
@@ -65,15 +65,15 @@ namespace ICSharpCode.ILSpy.Search
switch (member)
{
case ITypeDefinition t:
- return language.TypeToString(t, false);
+ return language.TypeToString(t, ConversionFlags.None);
case IField f:
- return language.FieldToString(f, true, false, false);
+ return language.EntityToString(f, ConversionFlags.ShowDeclaringType);
case IProperty p:
- return language.PropertyToString(p, true, false, false);
+ return language.EntityToString(p, ConversionFlags.ShowDeclaringType);
case IMethod m:
- return language.MethodToString(m, true, false, false);
+ return language.EntityToString(m, ConversionFlags.ShowDeclaringType);
case IEvent e:
- return language.EventToString(e, true, false, false);
+ return language.EntityToString(e, ConversionFlags.ShowDeclaringType);
default:
throw new NotSupportedException(member?.GetType() + " not supported!");
}
@@ -105,7 +105,7 @@ namespace ICSharpCode.ILSpy.Search
Member = entity,
Fitness = CalculateFitness(entity),
Name = GetLanguageSpecificName(entity),
- Location = declaringType != null ? language.TypeToString(declaringType, includeNamespace: true) : entity.Namespace,
+ Location = declaringType != null ? language.TypeToString(declaringType, ConversionFlags.UseFullyQualifiedEntityNames | ConversionFlags.UseFullyQualifiedTypeNames) : entity.Namespace,
Assembly = entity.ParentModule.FullAssemblyName,
ToolTip = entity.ParentModule.MetadataFile?.FileName,
Image = GetIcon(entity),
diff --git a/ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs b/ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs
index 41ab3e54f..b0e90b699 100644
--- a/ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs
+++ b/ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs
@@ -23,6 +23,7 @@ using System.Windows.Threading;
using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.Decompiler;
+using ICSharpCode.Decompiler.IL;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpy.Themes;
@@ -60,7 +61,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
public AssemblyReference AssemblyReference => r;
public override object Text {
- get { return Language.EscapeName(r.Name) + GetSuffixString(r.Handle); }
+ get { return ILAmbience.EscapeName(r.Name) + GetSuffixString(r.Handle); }
}
public override object NavigationText => $"{Text} ({Properties.Resources.References})";
diff --git a/ILSpy/TreeNodes/AssemblyTreeNode.cs b/ILSpy/TreeNodes/AssemblyTreeNode.cs
index 3d1b8c20d..2150edbbd 100644
--- a/ILSpy/TreeNodes/AssemblyTreeNode.cs
+++ b/ILSpy/TreeNodes/AssemblyTreeNode.cs
@@ -28,6 +28,7 @@ using System.Windows.Documents;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.CSharp.ProjectDecompiler;
+using ICSharpCode.Decompiler.IL;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpy.AssemblyTree;
@@ -286,20 +287,20 @@ namespace ICSharpCode.ILSpy.TreeNodes
int decimalIndex = @namespace.LastIndexOf('.');
if (decimalIndex < 0)
{
- var escapedNamespace = Language.EscapeName(@namespace);
+ var escapedNamespace = ILAmbience.EscapeName(@namespace);
ns = new NamespaceTreeNode(escapedNamespace);
}
else
{
var parentNamespaceTreeNode = GetOrCreateNamespaceTreeNode(@namespace.Substring(0, decimalIndex));
- var escapedInnerNamespace = Language.EscapeName(@namespace.Substring(decimalIndex + 1));
+ var escapedInnerNamespace = ILAmbience.EscapeName(@namespace.Substring(decimalIndex + 1));
ns = new NamespaceTreeNode(escapedInnerNamespace);
parentNamespaceTreeNode.Children.Add(ns);
}
}
else
{
- var escapedNamespace = Language.EscapeName(@namespace);
+ var escapedNamespace = ILAmbience.EscapeName(@namespace);
ns = new NamespaceTreeNode(escapedNamespace);
}
namespaces.Add(@namespace, ns);
diff --git a/ILSpy/TreeNodes/BaseTypesEntryNode.cs b/ILSpy/TreeNodes/BaseTypesEntryNode.cs
index 7d6168aff..a8a1288ca 100644
--- a/ILSpy/TreeNodes/BaseTypesEntryNode.cs
+++ b/ILSpy/TreeNodes/BaseTypesEntryNode.cs
@@ -34,7 +34,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
this.type = type;
}
- public override object Text => this.Language.TypeToString(type, includeNamespace: true);
+ public override object Text => this.Language.TypeToString(type);
public override object NavigationText => $"{Text} ({Properties.Resources.BaseTypes})";
@@ -61,7 +61,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
- language.WriteCommentLine(output, language.TypeToString(type, includeNamespace: true));
+ language.WriteCommentLine(output, language.TypeToString(type));
}
IEntity IMemberTreeNode.Member => type;
diff --git a/ILSpy/TreeNodes/BaseTypesTreeNode.cs b/ILSpy/TreeNodes/BaseTypesTreeNode.cs
index d19184ffa..488898297 100644
--- a/ILSpy/TreeNodes/BaseTypesTreeNode.cs
+++ b/ILSpy/TreeNodes/BaseTypesTreeNode.cs
@@ -46,7 +46,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
public override object Text => Properties.Resources.BaseTypes;
- public override object NavigationText => $"{Text} ({this.Language.TypeToString(type, includeNamespace: true)})";
+ public override object NavigationText => $"{Text} ({this.Language.TypeToString(type)})";
public override object Icon => Images.SuperTypes;
diff --git a/ILSpy/TreeNodes/DerivedTypesEntryNode.cs b/ILSpy/TreeNodes/DerivedTypesEntryNode.cs
index 3e511b704..290b6bc5c 100644
--- a/ILSpy/TreeNodes/DerivedTypesEntryNode.cs
+++ b/ILSpy/TreeNodes/DerivedTypesEntryNode.cs
@@ -44,7 +44,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
public override bool ShowExpander => !type.IsSealed && base.ShowExpander;
public override object Text {
- get { return Language.TypeToString(type, includeNamespace: true) + GetSuffixString(type.MetadataToken); }
+ get { return Language.TypeToString(type) + GetSuffixString(type.MetadataToken); }
}
public override object NavigationText => $"{Text} ({Properties.Resources.DerivedTypes})";
@@ -98,7 +98,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
- language.WriteCommentLine(output, language.TypeToString(type, includeNamespace: true));
+ language.WriteCommentLine(output, language.TypeToString(type));
}
IEntity IMemberTreeNode.Member => type;
diff --git a/ILSpy/TreeNodes/DerivedTypesTreeNode.cs b/ILSpy/TreeNodes/DerivedTypesTreeNode.cs
index fdf250030..ddddf0644 100644
--- a/ILSpy/TreeNodes/DerivedTypesTreeNode.cs
+++ b/ILSpy/TreeNodes/DerivedTypesTreeNode.cs
@@ -46,7 +46,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
public override object Text => Resources.DerivedTypes;
- public override object NavigationText => $"{Text} ({this.Language.TypeToString(type, includeNamespace: true)})";
+ public override object NavigationText => $"{Text} ({this.Language.TypeToString(type)})";
public override object Icon => Images.SubTypes;
diff --git a/ILSpy/TreeNodes/EventTreeNode.cs b/ILSpy/TreeNodes/EventTreeNode.cs
index 1c10674e9..434630af2 100644
--- a/ILSpy/TreeNodes/EventTreeNode.cs
+++ b/ILSpy/TreeNodes/EventTreeNode.cs
@@ -24,6 +24,7 @@ using ICSharpCode.Decompiler;
namespace ICSharpCode.ILSpy.TreeNodes
{
+ using ICSharpCode.Decompiler.Output;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpyX;
@@ -60,7 +61,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
public static object GetText(IEvent ev, Language language, bool includeDeclaringTypeName = false)
{
- return language.EventToString(ev, includeDeclaringTypeName, false, false);
+ return language.EntityToString(ev, includeDeclaringTypeName ? ConversionFlags.ShowDeclaringType : ConversionFlags.None);
}
public override object Icon => GetIcon(GetEventDefinition());
diff --git a/ILSpy/TreeNodes/ExportedTypeTreeNode.cs b/ILSpy/TreeNodes/ExportedTypeTreeNode.cs
index 7be2765d9..7d765a3c5 100644
--- a/ILSpy/TreeNodes/ExportedTypeTreeNode.cs
+++ b/ILSpy/TreeNodes/ExportedTypeTreeNode.cs
@@ -43,7 +43,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
}
public override object Text
- => Language.TypeToString(resolvedType, includeNamespace: true) + GetSuffixString(r.Handle);
+ => Language.TypeToString(resolvedType) + GetSuffixString(r.Handle);
public override object Icon => Images.ExportedType;
@@ -57,7 +57,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
- language.WriteCommentLine(output, $"{Language.TypeToString(resolvedType, includeNamespace: true)} (Exported, IsForwarder: {r.IsForwarder}, Attributes: {(int)r.Attributes:X8})");
+ language.WriteCommentLine(output, $"{Language.TypeToString(resolvedType)} (Exported, IsForwarder: {r.IsForwarder}, Attributes: {(int)r.Attributes:X8})");
}
}
}
diff --git a/ILSpy/TreeNodes/FieldTreeNode.cs b/ILSpy/TreeNodes/FieldTreeNode.cs
index 5bf508aaf..271041bbe 100644
--- a/ILSpy/TreeNodes/FieldTreeNode.cs
+++ b/ILSpy/TreeNodes/FieldTreeNode.cs
@@ -24,6 +24,7 @@ using ICSharpCode.Decompiler;
namespace ICSharpCode.ILSpy.TreeNodes
{
+ using ICSharpCode.Decompiler.Output;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpyX;
@@ -52,7 +53,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
public static object GetText(IField field, Language language, bool includeDeclaringTypeName = false)
{
- return language.FieldToString(field, includeDeclaringTypeName, includeNamespace: false, includeNamespaceOfDeclaringTypeName: false);
+ return language.EntityToString(field, includeDeclaringTypeName ? ConversionFlags.ShowDeclaringType : ConversionFlags.None);
}
public override object Icon => GetIcon(GetFieldDefinition());
diff --git a/ILSpy/TreeNodes/MemberReferenceTreeNode.cs b/ILSpy/TreeNodes/MemberReferenceTreeNode.cs
index 4d4598a8d..e7f81e166 100644
--- a/ILSpy/TreeNodes/MemberReferenceTreeNode.cs
+++ b/ILSpy/TreeNodes/MemberReferenceTreeNode.cs
@@ -23,6 +23,7 @@ using System.Reflection.Metadata;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Metadata;
+using ICSharpCode.Decompiler.Output;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.ILSpy.TreeNodes
@@ -57,7 +58,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
_ => throw new NotSupportedException(),
};
- public string Signature => resolvedMember is IMethod m ? Language.MethodToString(m, false, false, false) : Language.FieldToString((IField)resolvedMember, false, false, false);
+ public string Signature => Language.EntityToString(resolvedMember, ConversionFlags.None);
public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
diff --git a/ILSpy/TreeNodes/MethodTreeNode.cs b/ILSpy/TreeNodes/MethodTreeNode.cs
index fc6d44ce6..c01355db1 100644
--- a/ILSpy/TreeNodes/MethodTreeNode.cs
+++ b/ILSpy/TreeNodes/MethodTreeNode.cs
@@ -24,6 +24,7 @@ using ICSharpCode.Decompiler;
namespace ICSharpCode.ILSpy.TreeNodes
{
+ using ICSharpCode.Decompiler.Output;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpyX;
@@ -52,7 +53,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
public static object GetText(IMethod method, Language language, bool includeDeclaringTypeName = false)
{
- return language.MethodToString(method, includeDeclaringTypeName, false, false);
+ return language.EntityToString(method, includeDeclaringTypeName ? ConversionFlags.ShowDeclaringType : ConversionFlags.None);
}
public override object Icon => GetIcon(GetMethodDefinition());
@@ -108,7 +109,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
public override string ToString()
{
- return LanguageService.ILLanguage.MethodToString(MethodDefinition, false, false, false);
+ return LanguageService.ILLanguage.EntityToString(MethodDefinition, ConversionFlags.None);
}
}
}
diff --git a/ILSpy/TreeNodes/ModuleReferenceTreeNode.cs b/ILSpy/TreeNodes/ModuleReferenceTreeNode.cs
index 57e91cee8..09b1c8ff6 100644
--- a/ILSpy/TreeNodes/ModuleReferenceTreeNode.cs
+++ b/ILSpy/TreeNodes/ModuleReferenceTreeNode.cs
@@ -20,6 +20,7 @@ using System;
using System.Reflection.Metadata;
using ICSharpCode.Decompiler;
+using ICSharpCode.Decompiler.IL;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.ILSpyX.TreeView.PlatformAbstractions;
@@ -49,7 +50,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
this.module = module ?? throw new ArgumentNullException(nameof(module));
this.metadata = module.Metadata;
this.reference = module.Metadata.GetModuleReference(r);
- this.moduleName = Language.EscapeName(metadata.GetString(reference.Name));
+ this.moduleName = ILAmbience.EscapeName(metadata.GetString(reference.Name));
foreach (var h in metadata.AssemblyFiles)
{
diff --git a/ILSpy/TreeNodes/PropertyTreeNode.cs b/ILSpy/TreeNodes/PropertyTreeNode.cs
index 255299f8c..5f9c2c07f 100644
--- a/ILSpy/TreeNodes/PropertyTreeNode.cs
+++ b/ILSpy/TreeNodes/PropertyTreeNode.cs
@@ -24,6 +24,7 @@ using ICSharpCode.Decompiler;
namespace ICSharpCode.ILSpy.TreeNodes
{
+ using ICSharpCode.Decompiler.Output;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpyX;
@@ -62,7 +63,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
public static object GetText(IProperty property, Language language, bool includeDeclaringTypeName = false)
{
- return language.PropertyToString(property, includeDeclaringTypeName, false, false);
+ return language.EntityToString(property, includeDeclaringTypeName ? ConversionFlags.ShowDeclaringType : ConversionFlags.None);
}
public override object Icon => GetIcon(GetPropertyDefinition());
@@ -106,7 +107,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
public override string ToString()
{
- return LanguageService.ILLanguage.PropertyToString(PropertyDefinition, false, false, false);
+ return LanguageService.ILLanguage.EntityToString(PropertyDefinition, ConversionFlags.None);
}
}
}
diff --git a/ILSpy/TreeNodes/ResourceNodes/ResourceEntryNode.cs b/ILSpy/TreeNodes/ResourceNodes/ResourceEntryNode.cs
index e20257537..bea90056d 100644
--- a/ILSpy/TreeNodes/ResourceNodes/ResourceEntryNode.cs
+++ b/ILSpy/TreeNodes/ResourceNodes/ResourceEntryNode.cs
@@ -21,6 +21,7 @@ using System.IO;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.CSharp.ProjectDecompiler;
+using ICSharpCode.Decompiler.IL;
using ICSharpCode.Decompiler.Metadata;
using Microsoft.Win32;
@@ -35,7 +36,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
private readonly string key;
private readonly Func openStream;
- public override object Text => Language.EscapeName(key);
+ public override object Text => ILAmbience.EscapeName(key);
public override object Icon => Images.Resource;
diff --git a/ILSpy/TreeNodes/ResourceNodes/ResourceTreeNode.cs b/ILSpy/TreeNodes/ResourceNodes/ResourceTreeNode.cs
index a0df8f29e..8e757f2f4 100644
--- a/ILSpy/TreeNodes/ResourceNodes/ResourceTreeNode.cs
+++ b/ILSpy/TreeNodes/ResourceNodes/ResourceTreeNode.cs
@@ -25,6 +25,7 @@ using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.AvalonEdit.Utils;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.CSharp.ProjectDecompiler;
+using ICSharpCode.Decompiler.IL;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.ILSpy.Properties;
using ICSharpCode.ILSpy.TextView;
@@ -51,7 +52,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
public Resource Resource { get; }
- public override object Text => Language.EscapeName(Resource.Name);
+ public override object Text => ILAmbience.EscapeName(Resource.Name);
public override object Icon => Images.Resource;
diff --git a/ILSpy/TreeNodes/TypeReferenceTreeNode.cs b/ILSpy/TreeNodes/TypeReferenceTreeNode.cs
index 6a47c4767..e05cabf19 100644
--- a/ILSpy/TreeNodes/TypeReferenceTreeNode.cs
+++ b/ILSpy/TreeNodes/TypeReferenceTreeNode.cs
@@ -20,6 +20,7 @@ using System;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Metadata;
+using ICSharpCode.Decompiler.Output;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.ILSpy.TreeNodes
@@ -43,7 +44,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
}
public override object Text
- => Language.TypeToString(resolvedType, includeNamespace: false) + GetSuffixString(r.Handle);
+ => Language.TypeToString(resolvedType, ConversionFlags.None) + GetSuffixString(r.Handle);
public override object NavigationText => $"{Text} ({Properties.Resources.ReferencedTypes})";
@@ -62,7 +63,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
- language.WriteCommentLine(output, Language.TypeToString(resolvedType, includeNamespace: true));
+ language.WriteCommentLine(output, Language.TypeToString(resolvedType));
EnsureLazyChildren();
foreach (ILSpyTreeNode child in Children)
{
diff --git a/ILSpy/TreeNodes/TypeTreeNode.cs b/ILSpy/TreeNodes/TypeTreeNode.cs
index 343f8f3df..5502cab46 100644
--- a/ILSpy/TreeNodes/TypeTreeNode.cs
+++ b/ILSpy/TreeNodes/TypeTreeNode.cs
@@ -26,6 +26,7 @@ using SRM = System.Reflection.Metadata;
namespace ICSharpCode.ILSpy.TreeNodes
{
+ using ICSharpCode.Decompiler.Output;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpyX;
@@ -42,10 +43,10 @@ namespace ICSharpCode.ILSpy.TreeNodes
public AssemblyTreeNode ParentAssemblyNode { get; }
- public override object Text => this.Language.TypeToString(GetTypeDefinition(), includeNamespace: false)
+ public override object Text => this.Language.TypeToString(GetTypeDefinition(), ConversionFlags.None)
+ GetSuffixString(TypeDefinition.MetadataToken);
- public override object NavigationText => this.Language.TypeToString(GetTypeDefinition(), includeNamespace: true)
+ public override object NavigationText => this.Language.TypeToString(GetTypeDefinition())
+ GetSuffixString(TypeDefinition.MetadataToken);
private ITypeDefinition GetTypeDefinition()
diff --git a/ILSpy/ViewModels/CompareViewModel.cs b/ILSpy/ViewModels/CompareViewModel.cs
index 163650ce8..5e6266286 100644
--- a/ILSpy/ViewModels/CompareViewModel.cs
+++ b/ILSpy/ViewModels/CompareViewModel.cs
@@ -41,6 +41,7 @@ using ICSharpCode.ILSpyX.TreeView.PlatformAbstractions;
namespace ICSharpCode.ILSpy.ViewModels
{
+ using ICSharpCode.Decompiler.Output;
using ICSharpCode.Decompiler.TypeSystem;
using TomsToolbox.Wpf;
@@ -217,11 +218,8 @@ namespace ICSharpCode.ILSpy.ViewModels
return result;
string? GetEntityText(ISymbol? symbol) => symbol switch {
- ITypeDefinition t => this.assemblyTreeModel.CurrentLanguage.TypeToString(t, includeNamespace: true),
- IMethod m => this.assemblyTreeModel.CurrentLanguage.MethodToString(m, false, false, false),
- IField f => this.assemblyTreeModel.CurrentLanguage.FieldToString(f, false, false, false),
- IProperty p => this.assemblyTreeModel.CurrentLanguage.PropertyToString(p, false, false, false),
- IEvent e => this.assemblyTreeModel.CurrentLanguage.EventToString(e, false, false, false),
+ ITypeDefinition t => this.assemblyTreeModel.CurrentLanguage.TypeToString(t),
+ IEntity m => this.assemblyTreeModel.CurrentLanguage.EntityToString(m, ConversionFlags.None),
INamespace n => n.FullName,
IModule m => m.FullAssemblyName,
_ => null,
@@ -651,11 +649,8 @@ namespace ICSharpCode.ILSpy.ViewModels
return entityText + (otherText != null && entityText != otherText ? " -> " + otherText : "");
string? GetEntityText(ISymbol? symbol) => symbol switch {
- ITypeDefinition t => this.Language.TypeToString(t, includeNamespace: false) + GetSuffixString(t.MetadataToken),
- IMethod m => this.Language.MethodToString(m, false, false, false) + GetSuffixString(m.MetadataToken),
- IField f => this.Language.FieldToString(f, false, false, false) + GetSuffixString(f.MetadataToken),
- IProperty p => this.Language.PropertyToString(p, false, false, false) + GetSuffixString(p.MetadataToken),
- IEvent e => this.Language.EventToString(e, false, false, false) + GetSuffixString(e.MetadataToken),
+ ITypeDefinition t => this.Language.TypeToString(t, ConversionFlags.None) + GetSuffixString(t.MetadataToken),
+ IEntity e => this.Language.EntityToString(e, ConversionFlags.None) + GetSuffixString(e.MetadataToken),
INamespace n => n.FullName,
IModule m => m.FullAssemblyName,
_ => null,