From 23907c8d7d26bfb3c06b7b05eb70d015b2e8b71c Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Mon, 6 Aug 2018 23:23:01 +0200 Subject: [PATCH] Use IAmbience API in CSharpLanguage. --- .../ICSharpCode.Decompiler.Tests.csproj | 1 + .../Output/CSharpAmbienceTests.cs | 303 ++++++++++++++++++ .../CSharp/OutputVisitor/CSharpAmbience.cs | 21 +- .../ICSharpCode.Decompiler.csproj | 2 +- .../{TypeSystem => Output}/IAmbience.cs | 9 +- ILSpy.Tests/ILSpy.Tests.csproj | 7 +- ILSpy.Tests/Languages/CSharpLanguageTests.cs | 129 -------- ILSpy.Tests/Stub.cs | 2 +- ILSpy/Languages/CSharpLanguage.cs | 176 +++------- 9 files changed, 370 insertions(+), 280 deletions(-) create mode 100644 ICSharpCode.Decompiler.Tests/Output/CSharpAmbienceTests.cs rename ICSharpCode.Decompiler/{TypeSystem => Output}/IAmbience.cs (91%) delete mode 100644 ILSpy.Tests/Languages/CSharpLanguageTests.cs diff --git a/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj b/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj index 50dc56748..3852f4955 100644 --- a/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj +++ b/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj @@ -63,6 +63,7 @@ + diff --git a/ICSharpCode.Decompiler.Tests/Output/CSharpAmbienceTests.cs b/ICSharpCode.Decompiler.Tests/Output/CSharpAmbienceTests.cs new file mode 100644 index 000000000..79eee0a22 --- /dev/null +++ b/ICSharpCode.Decompiler.Tests/Output/CSharpAmbienceTests.cs @@ -0,0 +1,303 @@ +// 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.CSharp.OutputVisitor; +using ICSharpCode.Decompiler.Output; +using ICSharpCode.Decompiler.Tests.TypeSystem; +using ICSharpCode.Decompiler.TypeSystem; +using ICSharpCode.Decompiler.TypeSystem.Implementation; +using NUnit.Framework; + +namespace ICSharpCode.Decompiler.Tests.Output +{ + [TestFixture] + public class CSharpAmbienceTests + { + ICompilation compilation; + CSharpAmbience ambience; + + [OneTimeSetUp] + public void FixtureSetUp() + { + ambience = new CSharpAmbience(); + + compilation = new SimpleCompilation(TypeSystemLoaderTests.TestAssembly, + TypeSystemLoaderTests.Mscorlib.WithOptions(TypeSystemOptions.Default | TypeSystemOptions.OnlyPublicAPI)); + } + + #region ITypeDefinition tests + [Test] + public void GenericType() + { + var typeDef = compilation.FindType(typeof(Dictionary<,>)).GetDefinition(); + ambience.ConversionFlags = ConversionFlags.UseFullyQualifiedEntityNames | ConversionFlags.ShowTypeParameterList; + string result = ambience.ConvertSymbol(typeDef); + + Assert.AreEqual("System.Collections.Generic.Dictionary", result); + } + + [Test] + public void GenericTypeShortName() + { + var typeDef = compilation.FindType(typeof(Dictionary<,>)).GetDefinition(); + ambience.ConversionFlags = ConversionFlags.ShowTypeParameterList; + string result = ambience.ConvertSymbol(typeDef); + + Assert.AreEqual("Dictionary", result); + } + + [Test] + public void SimpleType() + { + var typeDef = compilation.FindType(typeof(Object)).GetDefinition(); + ambience.ConversionFlags = ConversionFlags.UseFullyQualifiedEntityNames | ConversionFlags.ShowTypeParameterList; + string result = ambience.ConvertSymbol(typeDef); + + Assert.AreEqual("System.Object", result); + } + + [Test] + public void SimpleTypeDefinition() + { + var typeDef = compilation.FindType(typeof(Object)).GetDefinition(); + ambience.ConversionFlags = ConversionFlags.All & ~(ConversionFlags.UseFullyQualifiedEntityNames); + string result = ambience.ConvertSymbol(typeDef); + + Assert.AreEqual("public class Object", result); + } + + [Test] + public void SimpleTypeDefinitionWithoutModifiers() + { + var typeDef = compilation.FindType(typeof(Object)).GetDefinition(); + ambience.ConversionFlags = ConversionFlags.All & ~(ConversionFlags.UseFullyQualifiedEntityNames | ConversionFlags.ShowModifiers | ConversionFlags.ShowAccessibility); + string result = ambience.ConvertSymbol(typeDef); + + Assert.AreEqual("class Object", result); + } + + [Test] + public void GenericTypeDefinitionFull() + { + var typeDef = compilation.FindType(typeof(List<>)).GetDefinition(); + ambience.ConversionFlags = ConversionFlags.All; + string result = ambience.ConvertSymbol(typeDef); + + Assert.AreEqual("public class System.Collections.Generic.List", result); + } + + [Test] + public void GenericInterfaceFull() + { + var typeDef = compilation.FindType(typeof(IEnumerable<>)).GetDefinition(); + ambience.ConversionFlags = ConversionFlags.All; + string result = ambience.ConvertSymbol(typeDef); + + Assert.AreEqual("public interface System.Collections.Generic.IEnumerable", result); + } + + [Test] + public void SimpleTypeShortName() + { + var typeDef = compilation.FindType(typeof(Object)).GetDefinition(); + ambience.ConversionFlags = ConversionFlags.ShowTypeParameterList; + string result = ambience.ConvertSymbol(typeDef); + + Assert.AreEqual("Object", result); + } + + [Test] + public void GenericTypeWithNested() + { + var typeDef = compilation.FindType(typeof(List<>.Enumerator)).GetDefinition(); + ambience.ConversionFlags = ConversionFlags.UseFullyQualifiedEntityNames | ConversionFlags.ShowTypeParameterList; + string result = ambience.ConvertSymbol(typeDef); + + Assert.AreEqual("System.Collections.Generic.List.Enumerator", result); + } + + [Test] + public void GenericTypeWithNestedShortName() + { + var typeDef = compilation.FindType(typeof(List<>.Enumerator)).GetDefinition(); + ambience.ConversionFlags = ConversionFlags.ShowDeclaringType | ConversionFlags.ShowTypeParameterList; + string result = ambience.ConvertSymbol(typeDef); + + Assert.AreEqual("List.Enumerator", result); + } + #endregion + + #region Delegate tests + [Test] + public void DelegateName() + { + var func = compilation.FindType(typeof(Func<,>)).GetDefinition(); + ambience.ConversionFlags = ConversionFlags.ShowTypeParameterList; + + Assert.AreEqual("Func", ambience.ConvertSymbol(func)); + } + + [Test] + public void FullDelegate() + { + var func = compilation.FindType(typeof(Func<,>)).GetDefinition(); + ambience.ConversionFlags = ConversionFlags.All; + Assert.AreEqual("public delegate TResult System.Func(T arg);", ambience.ConvertSymbol(func)); + } + #endregion + + #region IField tests + [Test] + public void SimpleField() + { + var field = compilation.FindType(typeof(CSharpAmbienceTests.Program)).GetFields(f => f.Name == "test").Single(); + ambience.ConversionFlags = ConversionFlags.All; + string result = ambience.ConvertSymbol(field); + + Assert.AreEqual("private int ICSharpCode.Decompiler.Tests.Output.CSharpAmbienceTests.Program.test;", result); + } + + [Test] + public void SimpleConstField() + { + var field = compilation.FindType(typeof(CSharpAmbienceTests.Program)).GetFields(f => f.Name == "TEST2").Single(); + ambience.ConversionFlags = ConversionFlags.All; + string result = ambience.ConvertSymbol(field); + + Assert.AreEqual("private const int ICSharpCode.Decompiler.Tests.Output.CSharpAmbienceTests.Program.TEST2;", result); + } + + [Test] + public void SimpleFieldWithoutModifiers() + { + var field = compilation.FindType(typeof(CSharpAmbienceTests.Program)).GetFields(f => f.Name == "test").Single(); + ambience.ConversionFlags = ConversionFlags.All & ~(ConversionFlags.ShowDeclaringType | ConversionFlags.ShowModifiers | ConversionFlags.ShowAccessibility); + string result = ambience.ConvertSymbol(field); + + Assert.AreEqual("int test;", result); + } + #endregion + + #region IEvent tests + [Test] + public void EventWithDeclaringType() + { + var ev = compilation.FindType(typeof(CSharpAmbienceTests.Program)).GetEvents(f => f.Name == "ProgramChanged").Single(); + ambience.ConversionFlags = ConversionFlags.StandardConversionFlags | ConversionFlags.ShowDeclaringType; + string result = ambience.ConvertSymbol(ev); + + Assert.AreEqual("public event EventHandler Program.ProgramChanged;", result); + } + + [Test] + public void CustomEvent() + { + var ev = compilation.FindType(typeof(CSharpAmbienceTests.Program)).GetEvents(f => f.Name == "SomeEvent").Single(); + ambience.ConversionFlags = ConversionFlags.StandardConversionFlags; + string result = ambience.ConvertSymbol(ev); + + Assert.AreEqual("public event EventHandler SomeEvent;", result); + } + #endregion + + #region Property tests + [Test] + public void AutomaticProperty() + { + var prop = compilation.FindType(typeof(CSharpAmbienceTests.Program)).GetProperties(p => p.Name == "Test").Single(); + ambience.ConversionFlags = ConversionFlags.StandardConversionFlags; + string result = ambience.ConvertSymbol(prop); + + Assert.AreEqual("public int Test { get; set; }", result); + } + + [Test] + public void Indexer() + { + var prop = compilation.FindType(typeof(CSharpAmbienceTests.Program)).GetProperties(p => p.IsIndexer).Single(); + ambience.ConversionFlags = ConversionFlags.StandardConversionFlags; + string result = ambience.ConvertSymbol(prop); + + Assert.AreEqual("public int this[int index] { get; }", result); + } + #endregion + + #region Test types +#pragma warning disable 169, 67 + + class Test { } + + class Program + { + int test; + const int TEST2 = 2; + + public int Test { get; set; } + + public int 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); + } + } + #endregion + } +} diff --git a/ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpAmbience.cs b/ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpAmbience.cs index fccd473d8..36e4afff4 100644 --- a/ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpAmbience.cs +++ b/ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpAmbience.cs @@ -19,6 +19,7 @@ using System; using System.IO; using ICSharpCode.Decompiler.CSharp.Syntax; +using ICSharpCode.Decompiler.Output; using ICSharpCode.Decompiler.TypeSystem; namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -37,7 +38,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor throw new ArgumentNullException("symbol"); StringWriter writer = new StringWriter(); - ConvertSymbol(symbol, new TextWriterTokenWriter(writer), FormattingOptionsFactory.CreateMono ()); + ConvertSymbol(symbol, new TextWriterTokenWriter(writer), FormattingOptionsFactory.CreateEmpty()); return writer.ToString(); } @@ -87,7 +88,9 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor } } - if ((ConversionFlags & ConversionFlags.ShowReturnType) == ConversionFlags.ShowReturnType) { + if ((ConversionFlags & ConversionFlags.PlaceReturnTypeAfterParameterList) != ConversionFlags.PlaceReturnTypeAfterParameterList + && (ConversionFlags & ConversionFlags.ShowReturnType) == ConversionFlags.ShowReturnType) + { var rt = node.GetChildByRole(Roles.Type); if (!rt.IsNull) { rt.AcceptVisitor(new CSharpOutputVisitor(writer, formattingPolicy)); @@ -116,7 +119,19 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor } writer.WriteToken(symbol.SymbolKind == SymbolKind.Indexer ? Roles.RBracket : Roles.RPar, symbol.SymbolKind == SymbolKind.Indexer ? "]" : ")"); } - + + if ((ConversionFlags & ConversionFlags.PlaceReturnTypeAfterParameterList) == ConversionFlags.PlaceReturnTypeAfterParameterList + && (ConversionFlags & ConversionFlags.ShowReturnType) == ConversionFlags.ShowReturnType) + { + var rt = node.GetChildByRole(Roles.Type); + if (!rt.IsNull) { + writer.Space(); + writer.WriteToken(Roles.Colon, ":"); + writer.Space(); + rt.AcceptVisitor(new CSharpOutputVisitor(writer, formattingPolicy)); + } + } + if ((ConversionFlags & ConversionFlags.ShowBody) == ConversionFlags.ShowBody && !(node is TypeDeclaration)) { IProperty property = symbol as IProperty; if (property != null) { diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj index 29eb15712..b85178a10 100644 --- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj +++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj @@ -487,7 +487,7 @@ - + diff --git a/ICSharpCode.Decompiler/TypeSystem/IAmbience.cs b/ICSharpCode.Decompiler/Output/IAmbience.cs similarity index 91% rename from ICSharpCode.Decompiler/TypeSystem/IAmbience.cs rename to ICSharpCode.Decompiler/Output/IAmbience.cs index 0552568ee..562f93372 100644 --- a/ICSharpCode.Decompiler/TypeSystem/IAmbience.cs +++ b/ICSharpCode.Decompiler/Output/IAmbience.cs @@ -17,8 +17,9 @@ // DEALINGS IN THE SOFTWARE. using System; +using ICSharpCode.Decompiler.TypeSystem; -namespace ICSharpCode.Decompiler.TypeSystem +namespace ICSharpCode.Decompiler.Output { [Flags] public enum ConversionFlags @@ -69,11 +70,15 @@ namespace ICSharpCode.Decompiler.TypeSystem /// For properties: shows "{ get; }" or similar. /// ShowBody = 0x200, - /// /// Use fully qualified names for members. /// UseFullyQualifiedEntityNames = 0x400, + /// + /// Instead of placing the return type before the entity name, + /// append it after the parameter list, preceeded by a colon. + /// + PlaceReturnTypeAfterParameterList = 0x800, StandardConversionFlags = ShowParameterNames | ShowAccessibility | diff --git a/ILSpy.Tests/ILSpy.Tests.csproj b/ILSpy.Tests/ILSpy.Tests.csproj index a9341a552..05231c047 100644 --- a/ILSpy.Tests/ILSpy.Tests.csproj +++ b/ILSpy.Tests/ILSpy.Tests.csproj @@ -19,6 +19,7 @@ True ..\ICSharpCode.Decompiler\ICSharpCode.Decompiler.snk + ICSharpCode.ILSpy.Tests @@ -36,8 +37,6 @@ - - @@ -63,8 +62,4 @@ - - - - \ No newline at end of file diff --git a/ILSpy.Tests/Languages/CSharpLanguageTests.cs b/ILSpy.Tests/Languages/CSharpLanguageTests.cs deleted file mode 100644 index 8d3f7617d..000000000 --- a/ILSpy.Tests/Languages/CSharpLanguageTests.cs +++ /dev/null @@ -1,129 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using ICSharpCode.Decompiler.Metadata; -using ICSharpCode.Decompiler.Tests.TypeSystem; -using ICSharpCode.Decompiler.TypeSystem; -using ICSharpCode.Decompiler.TypeSystem.Implementation; -using ICSharpCode.ILSpy; -using NUnit.Framework; - -namespace ILSpy.Tests.Languages -{ - [TestFixture, Parallelizable(ParallelScope.All)] - public class CSharpLanguageTests - { - const string ns = "ICSharpCode.Decompiler.Tests.TypeSystem"; - - static PEFile LoadAssembly(string filename) - { - return new PEFile(filename, new FileStream(filename, FileMode.Open, FileAccess.Read)); - } - - static readonly Lazy mscorlib = new Lazy( - delegate { - return LoadAssembly(typeof(object).Assembly.Location); - }); - - static readonly Lazy systemCore = new Lazy( - delegate { - return LoadAssembly(typeof(System.Linq.Enumerable).Assembly.Location); - }); - - static readonly Lazy testAssembly = new Lazy( - delegate { - return LoadAssembly(typeof(CSharpLanguageTests).Assembly.Location); - }); - - public static PEFile Mscorlib { get { return mscorlib.Value; } } - public static PEFile SystemCore { get { return systemCore.Value; } } - public static PEFile TestAssembly { get { return testAssembly.Value; } } - - [OneTimeSetUp] - public void FixtureSetUp() - { - compilation = new SimpleCompilation(TestAssembly, - Mscorlib.WithOptions(TypeSystemOptions.Default)); - language = new CSharpLanguage(); - } - - ICompilation compilation; - CSharpLanguage language; - - ITypeDefinition GetTypeDefinition(Type type) - { - return compilation.FindType(type).GetDefinition(); - } - - void TestType(Type t, string ns, string name) - { - var type = GetTypeDefinition(t); - Assert.AreEqual(name, language.TypeToString(type, includeNamespace: false)); - Assert.AreEqual(ns + "." + name, language.TypeToString(type, includeNamespace: true)); - } - - void TestMethod(Type t, Predicate filter, string ns, string typeName, string name, string paramListReturnType, string longParamListReturnType = null) - { - var type = GetTypeDefinition(t); - var method = type.GetMembers(filter, GetMemberOptions.IgnoreInheritedMembers).Single() as IMethod; - if (method == null) - throw new ArgumentNullException(); - if (longParamListReturnType == null) - longParamListReturnType = paramListReturnType; - Assert.AreEqual(name + paramListReturnType, language.MethodToString(method, includeDeclaringTypeName: false, includeNamespace: false, includeNamespaceOfDeclaringTypeName: false)); - Assert.AreEqual(typeName + "." + name + paramListReturnType, language.MethodToString(method, includeDeclaringTypeName: true, includeNamespace: false, includeNamespaceOfDeclaringTypeName: false)); - Assert.AreEqual(name + longParamListReturnType, language.MethodToString(method, includeDeclaringTypeName: false, includeNamespace: true, includeNamespaceOfDeclaringTypeName: false)); - Assert.AreEqual(typeName + "." + name + longParamListReturnType, language.MethodToString(method, includeDeclaringTypeName: true, includeNamespace: true, includeNamespaceOfDeclaringTypeName: false)); - Assert.AreEqual(name + paramListReturnType, language.MethodToString(method, includeDeclaringTypeName: false, includeNamespace: false, includeNamespaceOfDeclaringTypeName: true)); - Assert.AreEqual(ns + "." + typeName + "." + name + paramListReturnType, language.MethodToString(method, includeDeclaringTypeName: true, includeNamespace: false, includeNamespaceOfDeclaringTypeName: true)); - Assert.AreEqual(name + longParamListReturnType, language.MethodToString(method, includeDeclaringTypeName: false, includeNamespace: true, includeNamespaceOfDeclaringTypeName: true)); - Assert.AreEqual(ns + "." + typeName + "." + name + longParamListReturnType, language.MethodToString(method, includeDeclaringTypeName: true, includeNamespace: true, includeNamespaceOfDeclaringTypeName: true)); - } - - [Test] - public void PrimitiveTypes() - { - TestType(typeof(object), "System", "Object"); - TestType(typeof(string), "System", "String"); - TestType(typeof(int), "System", "Int32"); - } - - [Test] - public void ClassTests() - { - TestType(typeof(SimplePublicClass), ns, "SimplePublicClass"); - TestType(typeof(GenericClass<,>), ns, "GenericClass"); - TestType(typeof(OuterGeneric<>), ns, "OuterGeneric"); - TestType(typeof(OuterGeneric<>.Inner), ns + ".OuterGeneric", "Inner"); - } - - [Test] - public void InterfaceTests() - { - TestType(typeof(IBase1), ns, "IBase1"); - TestType(typeof(IGenericInterface<>), ns, "IGenericInterface"); - } - - [Test] - public void EnumTests() - { - TestType(typeof(MyEnum), ns, "MyEnum"); - TestType(typeof(GenericClass<,>.NestedEnum), ns + ".GenericClass", "NestedEnum"); - } - - [Test] - public void DelegateTests() - { - TestType(typeof(GenericDelegate<,>), ns, "GenericDelegate"); - } - - [Test] - public void MethodTests() - { - TestMethod(typeof(IMarshalAsTests), x => x.Name == "QueryApplicationFile", ns, "IMarshalAsTests", "QueryApplicationFile", "(string, out string, out string, out bool, out bool, out object[]) : void"); - TestMethod(typeof(MyClassWithCtor), x => x is IMethod m && m.IsConstructor, ns, "MyClassWithCtor", "MyClassWithCtor", "(int)"); - TestMethod(typeof(OuterGeneric<>), x => x is IMethod m && m.IsConstructor, ns, "OuterGeneric", "OuterGeneric", "()"); - } - } -} diff --git a/ILSpy.Tests/Stub.cs b/ILSpy.Tests/Stub.cs index 94f083677..910c6819d 100644 --- a/ILSpy.Tests/Stub.cs +++ b/ILSpy.Tests/Stub.cs @@ -1,6 +1,6 @@ using System; -namespace ILSpy.Tests +namespace ICSharpCode.ILSpy.Tests { class Stub { diff --git a/ILSpy/Languages/CSharpLanguage.cs b/ILSpy/Languages/CSharpLanguage.cs index 55b6662c9..ac4b99a75 100644 --- a/ILSpy/Languages/CSharpLanguage.cs +++ b/ILSpy/Languages/CSharpLanguage.cs @@ -21,19 +21,21 @@ using System.Collections.Generic; using System.ComponentModel.Composition; using System.IO; using System.Linq; +using System.Reflection.Metadata; +using System.Text; using System.Windows; using System.Windows.Controls; + using ICSharpCode.Decompiler; using ICSharpCode.Decompiler.CSharp; using ICSharpCode.Decompiler.CSharp.OutputVisitor; using ICSharpCode.Decompiler.CSharp.Syntax; using ICSharpCode.Decompiler.CSharp.Transforms; -using ICSharpCode.Decompiler.TypeSystem; -using ICSharpCode.ILSpy.TreeNodes; using ICSharpCode.Decompiler.Metadata; -using System.Reflection.Metadata; +using ICSharpCode.Decompiler.Output; +using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.Util; -using System.Text; +using ICSharpCode.ILSpy.TreeNodes; namespace ICSharpCode.ILSpy { @@ -113,7 +115,7 @@ namespace ICSharpCode.ILSpy return decompiler; } - void WriteCode(ITextOutput output, Decompiler.DecompilerSettings settings, SyntaxTree syntaxTree, IDecompilerTypeSystem typeSystem) + void WriteCode(ITextOutput output, DecompilerSettings settings, SyntaxTree syntaxTree, IDecompilerTypeSystem typeSystem) { syntaxTree.AcceptVisitor(new InsertParenthesesVisitor { InsertParenthesesForReadability = true }); TokenWriter tokenWriter = new TextTokenWriter(output, settings, typeSystem) { FoldBraces = settings.FoldBraces, ExpandMemberDefinitions = settings.ExpandMemberDefinitions }; @@ -424,170 +426,68 @@ namespace ICSharpCode.ILSpy } } - static readonly CSharpFormattingOptions TypeToStringFormattingOptions = FormattingOptionsFactory.CreateEmpty(); - - public override string TypeToString(IType type, bool includeNamespace) + static CSharpAmbience CreateAmbience() { - if (type == null) - throw new ArgumentNullException(nameof(type)); - if (type is ITypeDefinition definition && definition.TypeParameterCount > 0) { - return TypeToStringInternal(new ParameterizedType(definition, definition.TypeParameters), includeNamespace, false); - } - return TypeToStringInternal(type, includeNamespace, false); + CSharpAmbience ambience = new CSharpAmbience(); + ambience.ConversionFlags = ConversionFlags.ShowParameterList + | ConversionFlags.ShowReturnType + | ConversionFlags.ShowTypeParameterList + | ConversionFlags.PlaceReturnTypeAfterParameterList; + return ambience; } - string TypeToStringInternal(IType t, bool includeNamespace, bool useBuiltinTypeNames = true, ParameterModifier parameterModifier = ParameterModifier.None) + static string EntityToString(IEntity entity, bool includeDeclaringTypeName, bool includeNamespace, bool includeNamespaceOfDeclaringTypeName) { - TypeSystemAstBuilder builder = new TypeSystemAstBuilder(); - builder.AlwaysUseShortTypeNames = !includeNamespace; - builder.AlwaysUseBuiltinTypeNames = useBuiltinTypeNames; - - const ParameterModifier refInOutModifier = ParameterModifier.Ref | ParameterModifier.Out | ParameterModifier.In; - - AstType astType = builder.ConvertType(t); - if ((parameterModifier & refInOutModifier) != 0 && astType is ComposedType ct && ct.HasRefSpecifier) { - ct.HasRefSpecifier = false; - } - - StringWriter w = new StringWriter(); - - astType.AcceptVisitor(new CSharpOutputVisitor(w, TypeToStringFormattingOptions)); - string output = w.ToString(); - - switch (parameterModifier) { - case ParameterModifier.Ref: - output = "ref " + output; - break; - case ParameterModifier.Out: - output = "out " + output; - break; - case ParameterModifier.In: - output = "in " + output; - break; - } - - return output; + var ambience = CreateAmbience(); + if (includeDeclaringTypeName) + ambience.ConversionFlags |= ConversionFlags.ShowDeclaringType; + if (includeNamespace) + ambience.ConversionFlags |= ConversionFlags.UseFullyQualifiedTypeNames; + if (includeNamespaceOfDeclaringTypeName) + ambience.ConversionFlags |= ConversionFlags.UseFullyQualifiedEntityNames; + return ambience.ConvertSymbol(entity); } - static ParameterModifier GetModifier(IParameter p) + public override string TypeToString(IType type, bool includeNamespace) { - if (p.IsRef) - return ParameterModifier.Ref; - if (p.IsOut) - return ParameterModifier.Out; - if (p.IsIn) - return ParameterModifier.In; - return ParameterModifier.None; + if (type == null) + throw new ArgumentNullException(nameof(type)); + var ambience = CreateAmbience(); + if (includeNamespace) + ambience.ConversionFlags |= ConversionFlags.UseFullyQualifiedTypeNames; + if (type is ITypeDefinition definition) { + return ambience.ConvertSymbol(definition); + } else { + return ambience.ConvertType(type); + } } public override string FieldToString(IField field, bool includeDeclaringTypeName, bool includeNamespace, bool includeNamespaceOfDeclaringTypeName) { if (field == null) throw new ArgumentNullException(nameof(field)); - - string simple = field.Name + " : " + TypeToString(field.Type, includeNamespace); - if (!includeDeclaringTypeName) - return simple; - return TypeToStringInternal(field.DeclaringType, includeNamespaceOfDeclaringTypeName) + "." + simple; + 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)); - var buffer = new System.Text.StringBuilder(); - if (includeDeclaringTypeName) { - buffer.Append(TypeToString(property.DeclaringType, includeNamespaceOfDeclaringTypeName)); - buffer.Append('.'); - } - if (property.IsIndexer) { - if (property.IsExplicitInterfaceImplementation) { - string name = property.Name; - int index = name.LastIndexOf('.'); - if (index > 0) { - buffer.Append(name.Substring(0, index)); - buffer.Append('.'); - } - } - buffer.Append(@"this["); - - int i = 0; - var parameters = property.Parameters; - foreach (var param in parameters) { - if (i > 0) - buffer.Append(", "); - buffer.Append(TypeToStringInternal(param.Type, includeNamespace, parameterModifier: GetModifier(param))); - i++; - } - - buffer.Append(@"]"); - } else { - buffer.Append(property.Name); - } - buffer.Append(" : "); - buffer.Append(TypeToStringInternal(property.ReturnType, includeNamespace)); - return buffer.ToString(); + 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)); - string name; - if (includeDeclaringTypeName) { - name = TypeToString(method.DeclaringType, includeNamespace: includeNamespaceOfDeclaringTypeName) + "."; - } else { - name = ""; - } - if (method.IsConstructor) { - name += TypeToString(method.DeclaringType, false); - } else { - name += method.Name; - } - int i = 0; - var buffer = new StringBuilder(name); - - if (method.TypeParameters.Count > 0) { - buffer.Append('<'); - foreach (var tp in method.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(TypeToStringInternal(param.Type, includeNamespace, parameterModifier: GetModifier(param))); - i++; - } - - buffer.Append(')'); - if (!method.IsConstructor) { - buffer.Append(" : "); - buffer.Append(TypeToStringInternal(method.ReturnType, includeNamespace)); - } - return buffer.ToString(); + 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)); - var buffer = new System.Text.StringBuilder(); - if (includeDeclaringTypeName) { - buffer.Append(TypeToString(@event.DeclaringType, includeNamespaceOfDeclaringTypeName) + "."); - } - buffer.Append(@event.Name); - buffer.Append(" : "); - buffer.Append(TypeToStringInternal(@event.ReturnType, includeNamespace)); - return buffer.ToString(); + return EntityToString(@event, includeDeclaringTypeName, includeNamespace, includeNamespaceOfDeclaringTypeName); } string ToCSharpString(MetadataReader metadata, TypeDefinitionHandle handle, bool fullName)