Browse Source

CSharpAmbience: Add ConversionFlags.ShowParameterModifiers and ShowTypeParameterVarianceModifier to make labels in ILSpy main tree view more concise. + Added Tests.

pull/1253/head
Siegfried Pammer 7 years ago
parent
commit
a7ad5990ac
  1. 274
      ICSharpCode.Decompiler.Tests/Output/CSharpAmbienceTests.cs
  2. 36
      ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpAmbience.cs
  3. 15
      ICSharpCode.Decompiler/Output/IAmbience.cs
  4. 11
      ILSpy/Languages/CSharpLanguage.cs

274
ICSharpCode.Decompiler.Tests/Output/CSharpAmbienceTests.cs

@ -26,6 +26,8 @@ using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.TypeSystem.Implementation; using ICSharpCode.Decompiler.TypeSystem.Implementation;
using NUnit.Framework; using NUnit.Framework;
using static ICSharpCode.Decompiler.Output.ConversionFlags;
namespace ICSharpCode.Decompiler.Tests.Output namespace ICSharpCode.Decompiler.Tests.Output
{ {
[TestFixture] [TestFixture]
@ -43,156 +45,201 @@ namespace ICSharpCode.Decompiler.Tests.Output
TypeSystemLoaderTests.Mscorlib.WithOptions(TypeSystemOptions.Default | TypeSystemOptions.OnlyPublicAPI)); TypeSystemLoaderTests.Mscorlib.WithOptions(TypeSystemOptions.Default | TypeSystemOptions.OnlyPublicAPI));
} }
#region ITypeDefinition tests ITypeDefinition GetDefinition(Type type)
[Test]
public void GenericType()
{ {
var typeDef = compilation.FindType(typeof(Dictionary<,>)).GetDefinition(); if (type == null) {
ambience.ConversionFlags = ConversionFlags.UseFullyQualifiedEntityNames | ConversionFlags.ShowTypeParameterList; throw new ArgumentNullException(nameof(type));
string result = ambience.ConvertSymbol(typeDef); }
Assert.AreEqual("System.Collections.Generic.Dictionary<TKey,TValue>", result); var foundType = compilation.FindType(type).GetDefinition();
Assert.IsNotNull(foundType);
return foundType;
} }
[Test] const ConversionFlags ILSpyMainTreeViewTypeFlags = ShowTypeParameterList | PlaceReturnTypeAfterParameterList;
public void GenericTypeShortName() const ConversionFlags ILSpyMainTreeViewMemberFlags = ILSpyMainTreeViewTypeFlags | ShowParameterList | ShowReturnType | ShowParameterModifiers;
{
var typeDef = compilation.FindType(typeof(Dictionary<,>)).GetDefinition();
ambience.ConversionFlags = ConversionFlags.ShowTypeParameterList;
string result = ambience.ConvertSymbol(typeDef);
Assert.AreEqual("Dictionary<TKey,TValue>", result); #region ITypeDefinition tests
[TestCase(None, "Dictionary")]
[TestCase(ShowDefinitionKeyword, "class Dictionary")]
[TestCase(ShowAccessibility, "public Dictionary")]
[TestCase(ShowDefinitionKeyword | ShowAccessibility, "public class Dictionary")]
[TestCase(ShowTypeParameterList, "Dictionary<TKey,TValue>")]
[TestCase(ShowTypeParameterList | ShowDefinitionKeyword | ShowAccessibility, "public class Dictionary<TKey,TValue>")]
[TestCase(UseFullyQualifiedEntityNames | ShowTypeParameterList, "System.Collections.Generic.Dictionary<TKey,TValue>")]
[TestCase(UseFullyQualifiedEntityNames | ShowTypeParameterList | ShowDefinitionKeyword | ShowAccessibility, "public class System.Collections.Generic.Dictionary<TKey,TValue>")]
[TestCase(ILSpyMainTreeViewTypeFlags, "Dictionary<TKey,TValue>")]
public void GenericType(ConversionFlags flags, string expectedOutput)
{
var typeDef = GetDefinition(typeof(Dictionary<,>));
ambience.ConversionFlags = flags;
Assert.AreEqual(expectedOutput, ambience.ConvertSymbol(typeDef));
} }
[Test] [TestCase(None, "Object")]
public void SimpleType() [TestCase(ShowDefinitionKeyword, "class Object")]
[TestCase(ShowAccessibility, "public Object")]
[TestCase(ShowDefinitionKeyword | ShowAccessibility, "public class Object")]
[TestCase(ShowTypeParameterList, "Object")]
[TestCase(ShowTypeParameterList | ShowDefinitionKeyword | ShowAccessibility, "public class Object")]
[TestCase(UseFullyQualifiedEntityNames | ShowTypeParameterList, "System.Object")]
[TestCase(All, "public class System.Object")]
[TestCase(ILSpyMainTreeViewTypeFlags, "Object")]
public void SimpleType(ConversionFlags flags, string expectedOutput)
{ {
var typeDef = compilation.FindType(typeof(Object)).GetDefinition(); var typeDef = GetDefinition(typeof(object));
ambience.ConversionFlags = ConversionFlags.UseFullyQualifiedEntityNames | ConversionFlags.ShowTypeParameterList; ambience.ConversionFlags = flags;
string result = ambience.ConvertSymbol(typeDef); Assert.AreEqual(expectedOutput, ambience.ConvertSymbol(typeDef));
Assert.AreEqual("System.Object", result);
} }
[Test] [TestCase(None, "IEnumerable")]
public void SimpleTypeDefinition() [TestCase(ShowTypeParameterList, "IEnumerable<T>")]
[TestCase(ShowTypeParameterList | ShowTypeParameterVarianceModifier, "IEnumerable<out T>")]
[TestCase(All, "public interface System.Collections.Generic.IEnumerable<out T>")]
[TestCase(ILSpyMainTreeViewTypeFlags, "IEnumerable<T>")]
public void GenericInterface(ConversionFlags flags, string expectedOutput)
{ {
var typeDef = compilation.FindType(typeof(Object)).GetDefinition(); var typeDef = GetDefinition(typeof(IEnumerable<>));
ambience.ConversionFlags = ConversionFlags.All & ~(ConversionFlags.UseFullyQualifiedEntityNames); ambience.ConversionFlags = flags;
string result = ambience.ConvertSymbol(typeDef); Assert.AreEqual(expectedOutput, ambience.ConvertSymbol(typeDef));
Assert.AreEqual("public class Object", result);
} }
[Test] [TestCase(None, "Enumerator")]
public void SimpleTypeDefinitionWithoutModifiers() [TestCase(ShowDefinitionKeyword, "struct Enumerator")]
[TestCase(ShowAccessibility, "public Enumerator")]
[TestCase(ShowDefinitionKeyword | ShowAccessibility, "public struct Enumerator")]
[TestCase(ShowTypeParameterList, "Enumerator")]
[TestCase(ShowTypeParameterList | ShowDefinitionKeyword | ShowAccessibility, "public struct Enumerator")]
[TestCase(UseFullyQualifiedEntityNames | ShowTypeParameterList, "System.Collections.Generic.List<T>.Enumerator")]
[TestCase(ShowDeclaringType | ShowTypeParameterList, "List<T>.Enumerator")]
[TestCase(All, "public struct System.Collections.Generic.List<T>.Enumerator")]
[TestCase(ILSpyMainTreeViewTypeFlags, "Enumerator")]
public void GenericTypeWithNested(ConversionFlags flags, string expectedOutput)
{ {
var typeDef = compilation.FindType(typeof(Object)).GetDefinition(); var typeDef = GetDefinition(typeof(List<>.Enumerator));
ambience.ConversionFlags = ConversionFlags.All & ~(ConversionFlags.UseFullyQualifiedEntityNames | ConversionFlags.ShowModifiers | ConversionFlags.ShowAccessibility); ambience.ConversionFlags = flags;
string result = ambience.ConvertSymbol(typeDef); Assert.AreEqual(expectedOutput, ambience.ConvertSymbol(typeDef));
Assert.AreEqual("class Object", result);
} }
[Test] [TestCase(None, "StaticClass")]
public void GenericTypeDefinitionFull() [TestCase(ShowDefinitionKeyword, "class StaticClass")]
[TestCase(ShowModifiers | ShowDefinitionKeyword, "static class StaticClass")]
[TestCase(ShowModifiers | ShowAccessibility, "private static StaticClass")]
[TestCase(ShowModifiers | ShowDefinitionKeyword | ShowAccessibility, "private static class StaticClass")]
[TestCase(ShowModifiers | ShowTypeParameterList, "static StaticClass")]
[TestCase(ShowModifiers | ShowTypeParameterList | ShowDefinitionKeyword | ShowAccessibility, "private static class StaticClass")]
[TestCase(All, "private static class ICSharpCode.Decompiler.Tests.Output.CSharpAmbienceTests.StaticClass")]
[TestCase(ILSpyMainTreeViewTypeFlags, "StaticClass")]
public void StaticClassTest(ConversionFlags flags, string expectedOutput)
{ {
var typeDef = compilation.FindType(typeof(List<>)).GetDefinition(); var typeDef = GetDefinition(typeof(StaticClass));
ambience.ConversionFlags = ConversionFlags.All; ambience.ConversionFlags = flags;
string result = ambience.ConvertSymbol(typeDef); Assert.AreEqual(expectedOutput, ambience.ConvertSymbol(typeDef));
Assert.AreEqual("public class System.Collections.Generic.List<T>", result);
} }
[Test] [TestCase(None, "SealedClass")]
public void GenericInterfaceFull() [TestCase(ShowDefinitionKeyword, "class SealedClass")]
[TestCase(ShowModifiers | ShowDefinitionKeyword, "sealed class SealedClass")]
[TestCase(ShowModifiers | ShowAccessibility, "private sealed SealedClass")]
[TestCase(ShowModifiers | ShowDefinitionKeyword | ShowAccessibility, "private sealed class SealedClass")]
[TestCase(ShowModifiers | ShowTypeParameterList, "sealed SealedClass")]
[TestCase(ShowModifiers | ShowTypeParameterList | ShowDefinitionKeyword | ShowAccessibility, "private sealed class SealedClass")]
[TestCase(All, "private sealed class ICSharpCode.Decompiler.Tests.Output.CSharpAmbienceTests.SealedClass")]
[TestCase(ILSpyMainTreeViewTypeFlags, "SealedClass")]
public void SealedClassTest(ConversionFlags flags, string expectedOutput)
{ {
var typeDef = compilation.FindType(typeof(IEnumerable<>)).GetDefinition(); var typeDef = GetDefinition(typeof(SealedClass));
ambience.ConversionFlags = ConversionFlags.All; ambience.ConversionFlags = flags;
string result = ambience.ConvertSymbol(typeDef); Assert.AreEqual(expectedOutput, ambience.ConvertSymbol(typeDef));
Assert.AreEqual("public interface System.Collections.Generic.IEnumerable<out T>", result);
} }
[Test] [TestCase(None, "RefStruct")]
public void SimpleTypeShortName() [TestCase(ShowDefinitionKeyword, "struct RefStruct")]
[TestCase(ShowModifiers | ShowDefinitionKeyword, "ref struct RefStruct")]
[TestCase(ShowModifiers | ShowAccessibility, "private ref RefStruct")]
[TestCase(ShowModifiers | ShowDefinitionKeyword | ShowAccessibility, "private ref struct RefStruct")]
[TestCase(ShowModifiers | ShowTypeParameterList, "ref RefStruct")]
[TestCase(ShowModifiers | ShowTypeParameterList | ShowDefinitionKeyword | ShowAccessibility, "private ref struct RefStruct")]
[TestCase(All, "private ref struct ICSharpCode.Decompiler.Tests.Output.CSharpAmbienceTests.RefStruct")]
[TestCase(ILSpyMainTreeViewTypeFlags, "RefStruct")]
public void RefStructTest(ConversionFlags flags, string expectedOutput)
{ {
var typeDef = compilation.FindType(typeof(Object)).GetDefinition(); var typeDef = GetDefinition(typeof(RefStruct));
ambience.ConversionFlags = ConversionFlags.ShowTypeParameterList; ambience.ConversionFlags = flags;
string result = ambience.ConvertSymbol(typeDef); Assert.AreEqual(expectedOutput, ambience.ConvertSymbol(typeDef));
Assert.AreEqual("Object", result);
} }
[Test] [TestCase(None, "ReadonlyStruct")]
public void GenericTypeWithNested() [TestCase(ShowDefinitionKeyword, "struct ReadonlyStruct")]
[TestCase(ShowModifiers | ShowDefinitionKeyword, "readonly struct ReadonlyStruct")]
[TestCase(ShowModifiers | ShowAccessibility, "private readonly ReadonlyStruct")]
[TestCase(ShowModifiers | ShowDefinitionKeyword | ShowAccessibility, "private readonly struct ReadonlyStruct")]
[TestCase(ShowModifiers | ShowTypeParameterList, "readonly ReadonlyStruct")]
[TestCase(ShowModifiers | ShowTypeParameterList | ShowDefinitionKeyword | ShowAccessibility, "private readonly struct ReadonlyStruct")]
[TestCase(All, "private readonly struct ICSharpCode.Decompiler.Tests.Output.CSharpAmbienceTests.ReadonlyStruct")]
[TestCase(ILSpyMainTreeViewTypeFlags, "ReadonlyStruct")]
public void ReadonlyStructTest(ConversionFlags flags, string expectedOutput)
{ {
var typeDef = compilation.FindType(typeof(List<>.Enumerator)).GetDefinition(); var typeDef = GetDefinition(typeof(ReadonlyStruct));
ambience.ConversionFlags = ConversionFlags.UseFullyQualifiedEntityNames | ConversionFlags.ShowTypeParameterList; ambience.ConversionFlags = flags;
string result = ambience.ConvertSymbol(typeDef); Assert.AreEqual(expectedOutput, ambience.ConvertSymbol(typeDef));
Assert.AreEqual("System.Collections.Generic.List<T>.Enumerator", result);
} }
[Test] [TestCase(None, "ReadonlyRefStruct")]
public void GenericTypeWithNestedShortName() [TestCase(ShowDefinitionKeyword, "struct ReadonlyRefStruct")]
[TestCase(ShowModifiers | ShowDefinitionKeyword, "readonly ref struct ReadonlyRefStruct")]
[TestCase(ShowModifiers | ShowAccessibility, "private readonly ref ReadonlyRefStruct")]
[TestCase(ShowModifiers | ShowDefinitionKeyword | ShowAccessibility, "private readonly ref struct ReadonlyRefStruct")]
[TestCase(ShowModifiers | ShowTypeParameterList, "readonly ref ReadonlyRefStruct")]
[TestCase(ShowModifiers | ShowTypeParameterList | ShowDefinitionKeyword | ShowAccessibility, "private readonly ref struct ReadonlyRefStruct")]
[TestCase(All, "private readonly ref struct ICSharpCode.Decompiler.Tests.Output.CSharpAmbienceTests.ReadonlyRefStruct")]
[TestCase(ILSpyMainTreeViewTypeFlags, "ReadonlyRefStruct")]
public void ReadonlyRefStructTest(ConversionFlags flags, string expectedOutput)
{ {
var typeDef = compilation.FindType(typeof(List<>.Enumerator)).GetDefinition(); var typeDef = GetDefinition(typeof(ReadonlyRefStruct));
ambience.ConversionFlags = ConversionFlags.ShowDeclaringType | ConversionFlags.ShowTypeParameterList; ambience.ConversionFlags = flags;
string result = ambience.ConvertSymbol(typeDef); Assert.AreEqual(expectedOutput, ambience.ConvertSymbol(typeDef));
Assert.AreEqual("List<T>.Enumerator", result);
} }
#endregion #endregion
#region Delegate tests #region Delegate tests
[Test] [TestCase(None, "Func")]
public void DelegateName() [TestCase(ShowTypeParameterList, "Func<T,TResult>")]
{ [TestCase(ShowTypeParameterList | ShowTypeParameterVarianceModifier, "Func<in T,out TResult>")]
var func = compilation.FindType(typeof(Func<,>)).GetDefinition(); [TestCase(ShowTypeParameterList | ShowReturnType | ShowTypeParameterVarianceModifier, "TResult Func<in T,out TResult>")]
ambience.ConversionFlags = ConversionFlags.ShowTypeParameterList; [TestCase(ShowTypeParameterList | ShowParameterList | ShowTypeParameterVarianceModifier, "Func<in T,out TResult>(T)")]
[TestCase(ShowTypeParameterList | ShowParameterList | ShowReturnType | ShowTypeParameterVarianceModifier, "TResult Func<in T,out TResult>(T)")]
Assert.AreEqual("Func<in T,out TResult>", ambience.ConvertSymbol(func)); [TestCase(All & ~PlaceReturnTypeAfterParameterList, "public delegate TResult System.Func<in T,out TResult>(T arg);")]
} [TestCase(All, "public delegate System.Func<in T,out TResult>(T arg) : TResult;")]
[TestCase(ILSpyMainTreeViewTypeFlags, "Func<T,TResult>")]
[Test] public void FuncDelegate(ConversionFlags flags, string expectedOutput)
public void FullDelegate()
{ {
var func = compilation.FindType(typeof(Func<,>)).GetDefinition(); var func = GetDefinition(typeof(Func<,>));
ambience.ConversionFlags = ConversionFlags.All; ambience.ConversionFlags = flags;
Assert.AreEqual("public delegate TResult System.Func<in T,out TResult>(T arg);", ambience.ConvertSymbol(func)); Assert.AreEqual(expectedOutput, ambience.ConvertSymbol(func));
} }
#endregion #endregion
#region IField tests #region IField tests
[Test] [TestCase(All & ~PlaceReturnTypeAfterParameterList, "private int ICSharpCode.Decompiler.Tests.Output.CSharpAmbienceTests.Program.test;")]
public void SimpleField() [TestCase(ILSpyMainTreeViewMemberFlags, "test : int")]
[TestCase(ConversionFlags.All & ~(ConversionFlags.ShowDeclaringType | ConversionFlags.ShowModifiers | ConversionFlags.ShowAccessibility | ConversionFlags.PlaceReturnTypeAfterParameterList), "int test;")]
public void SimpleField(ConversionFlags flags, string expectedOutput)
{ {
var field = compilation.FindType(typeof(CSharpAmbienceTests.Program)).GetFields(f => f.Name == "test").Single(); var field = GetDefinition(typeof(CSharpAmbienceTests.Program)).GetFields(f => f.Name == "test").Single();
ambience.ConversionFlags = ConversionFlags.All; ambience.ConversionFlags = flags;
string result = ambience.ConvertSymbol(field);
Assert.AreEqual("private int ICSharpCode.Decompiler.Tests.Output.CSharpAmbienceTests.Program.test;", result); Assert.AreEqual(expectedOutput, ambience.ConvertSymbol(field));
} }
[Test] [TestCase(All & ~PlaceReturnTypeAfterParameterList, "private const int ICSharpCode.Decompiler.Tests.Output.CSharpAmbienceTests.Program.TEST2;")]
public void SimpleConstField() [TestCase(ILSpyMainTreeViewMemberFlags, "TEST2 : int")]
public void SimpleConstField(ConversionFlags flags, string expectedOutput)
{ {
var field = compilation.FindType(typeof(CSharpAmbienceTests.Program)).GetFields(f => f.Name == "TEST2").Single(); var field = compilation.FindType(typeof(CSharpAmbienceTests.Program)).GetFields(f => f.Name == "TEST2").Single();
ambience.ConversionFlags = ConversionFlags.All; ambience.ConversionFlags = flags;
string result = ambience.ConvertSymbol(field);
Assert.AreEqual("private const int ICSharpCode.Decompiler.Tests.Output.CSharpAmbienceTests.Program.TEST2;", result); Assert.AreEqual(expectedOutput, ambience.ConvertSymbol(field));
}
[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 #endregion
@ -240,10 +287,22 @@ namespace ICSharpCode.Decompiler.Tests.Output
} }
#endregion #endregion
#region IMethod tests
[Test]
public void ConstructorTests()
{
}
#endregion
#region Test types #region Test types
#pragma warning disable 169, 67 #pragma warning disable 169, 67
class Test { } class Test { }
static class StaticClass { }
sealed class SealedClass { }
ref struct RefStruct { }
readonly struct ReadonlyStruct { }
readonly ref struct ReadonlyRefStruct { }
class Program class Program
{ {
@ -297,6 +356,11 @@ namespace ICSharpCode.Decompiler.Tests.Output
Console.Write("Press any key to continue . . . "); Console.Write("Press any key to continue . . . ");
Console.ReadKey(true); Console.ReadKey(true);
} }
public static void InParameter(in int a)
{
}
} }
#endregion #endregion
} }

36
ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpAmbience.cs

@ -17,7 +17,10 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using ICSharpCode.Decompiler.CSharp.Syntax; using ICSharpCode.Decompiler.CSharp.Syntax;
using ICSharpCode.Decompiler.Output; using ICSharpCode.Decompiler.Output;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
@ -109,6 +112,9 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
writer.WriteToken(symbol.SymbolKind == SymbolKind.Indexer ? Roles.LBracket : Roles.LPar, symbol.SymbolKind == SymbolKind.Indexer ? "[" : "("); writer.WriteToken(symbol.SymbolKind == SymbolKind.Indexer ? Roles.LBracket : Roles.LPar, symbol.SymbolKind == SymbolKind.Indexer ? "[" : "(");
bool first = true; bool first = true;
foreach (var param in node.GetChildrenByRole(Roles.Parameter)) { foreach (var param in node.GetChildrenByRole(Roles.Parameter)) {
if ((ConversionFlags & ConversionFlags.ShowParameterModifiers) == 0) {
param.ParameterModifier = ParameterModifier.None;
}
if (first) { if (first) {
first = false; first = false;
} else { } else {
@ -186,7 +192,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
{ {
TypeSystemAstBuilder astBuilder = CreateAstBuilder(); TypeSystemAstBuilder astBuilder = CreateAstBuilder();
EntityDeclaration node = astBuilder.ConvertEntity(typeDef); EntityDeclaration node = astBuilder.ConvertEntity(typeDef);
if (typeDef.DeclaringTypeDefinition != null && if (typeDef.DeclaringTypeDefinition != null &&
((ConversionFlags & ConversionFlags.ShowDeclaringType) == ConversionFlags.ShowDeclaringType || ((ConversionFlags & ConversionFlags.ShowDeclaringType) == ConversionFlags.ShowDeclaringType ||
(ConversionFlags & ConversionFlags.UseFullyQualifiedEntityNames) == ConversionFlags.UseFullyQualifiedEntityNames)) { (ConversionFlags & ConversionFlags.UseFullyQualifiedEntityNames) == ConversionFlags.UseFullyQualifiedEntityNames)) {
WriteTypeDeclarationName(typeDef.DeclaringTypeDefinition, writer, formattingPolicy); WriteTypeDeclarationName(typeDef.DeclaringTypeDefinition, writer, formattingPolicy);
@ -198,12 +204,9 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
} }
} }
writer.WriteIdentifier(node.NameToken); writer.WriteIdentifier(node.NameToken);
if ((ConversionFlags & ConversionFlags.ShowTypeParameterList) == ConversionFlags.ShowTypeParameterList) { WriteTypeParameters(node, writer, formattingPolicy);
var outputVisitor = new CSharpOutputVisitor(writer, formattingPolicy);
outputVisitor.WriteTypeParameters(node.GetChildrenByRole(Roles.TypeParameter));
}
} }
void WriteMemberDeclarationName(IMember member, TokenWriter writer, CSharpFormattingOptions formattingPolicy) void WriteMemberDeclarationName(IMember member, TokenWriter writer, CSharpFormattingOptions formattingPolicy)
{ {
TypeSystemAstBuilder astBuilder = CreateAstBuilder(); TypeSystemAstBuilder astBuilder = CreateAstBuilder();
@ -254,12 +257,27 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
writer.WriteIdentifier(Identifier.Create(member.Name)); writer.WriteIdentifier(Identifier.Create(member.Name));
break; break;
} }
if ((ConversionFlags & ConversionFlags.ShowTypeParameterList) == ConversionFlags.ShowTypeParameterList && member.SymbolKind == SymbolKind.Method) { WriteTypeParameters(node, writer, formattingPolicy);
}
void WriteTypeParameters(EntityDeclaration node, TokenWriter writer, CSharpFormattingOptions formattingPolicy)
{
if ((ConversionFlags & ConversionFlags.ShowTypeParameterList) == ConversionFlags.ShowTypeParameterList) {
var outputVisitor = new CSharpOutputVisitor(writer, formattingPolicy); var outputVisitor = new CSharpOutputVisitor(writer, formattingPolicy);
outputVisitor.WriteTypeParameters(node.GetChildrenByRole(Roles.TypeParameter)); IEnumerable<TypeParameterDeclaration> typeParameters = node.GetChildrenByRole(Roles.TypeParameter);
if ((ConversionFlags & ConversionFlags.ShowTypeParameterVarianceModifier) == 0) {
typeParameters = typeParameters.Select(RemoveVarianceModifier);
}
outputVisitor.WriteTypeParameters(typeParameters);
}
TypeParameterDeclaration RemoveVarianceModifier(TypeParameterDeclaration decl)
{
decl.Variance = VarianceModifier.Invariant;
return decl;
} }
} }
void PrintModifiers(Modifiers modifiers, TokenWriter writer) void PrintModifiers(Modifiers modifiers, TokenWriter writer)
{ {
foreach (var m in CSharpModifierToken.AllModifiers) { foreach (var m in CSharpModifierToken.AllModifiers) {

15
ICSharpCode.Decompiler/Output/IAmbience.cs

@ -79,17 +79,28 @@ namespace ICSharpCode.Decompiler.Output
/// append it after the parameter list, preceeded by a colon. /// append it after the parameter list, preceeded by a colon.
/// </summary> /// </summary>
PlaceReturnTypeAfterParameterList = 0x800, PlaceReturnTypeAfterParameterList = 0x800,
/// <summary>
/// Show the variance modifier of the type parameter.
/// If active, shows 'Func&lt;in T, out TResult&gt;' instead of 'Func&lt;T, TResult&gt;'.
/// </summary>
ShowTypeParameterVarianceModifier = 0x1000,
/// <summary>
/// Show modifiers of parameters, e.g. 'this', 'params', 'ref', 'out' and 'in'.
/// </summary>
ShowParameterModifiers = 0x2000,
StandardConversionFlags = ShowParameterNames | StandardConversionFlags = ShowParameterNames |
ShowAccessibility | ShowAccessibility |
ShowParameterList | ShowParameterList |
ShowParameterModifiers |
ShowReturnType | ShowReturnType |
ShowModifiers | ShowModifiers |
ShowTypeParameterList | ShowTypeParameterList |
ShowTypeParameterVarianceModifier |
ShowDefinitionKeyword | ShowDefinitionKeyword |
ShowBody, ShowBody,
All = 0x7ff, All = 0x7ffff,
} }
/// <summary> /// <summary>

11
ILSpy/Languages/CSharpLanguage.cs

@ -429,16 +429,16 @@ namespace ICSharpCode.ILSpy
static CSharpAmbience CreateAmbience() static CSharpAmbience CreateAmbience()
{ {
CSharpAmbience ambience = new CSharpAmbience(); CSharpAmbience ambience = new CSharpAmbience();
ambience.ConversionFlags = ConversionFlags.ShowParameterList // Do not forget to update CSharpAmbienceTests.ILSpyMainTreeViewTypeFlags, if this ever changes.
| ConversionFlags.ShowReturnType ambience.ConversionFlags = ConversionFlags.ShowTypeParameterList | ConversionFlags.PlaceReturnTypeAfterParameterList;
| ConversionFlags.ShowTypeParameterList
| ConversionFlags.PlaceReturnTypeAfterParameterList;
return ambience; return ambience;
} }
static string EntityToString(IEntity entity, bool includeDeclaringTypeName, bool includeNamespace, bool includeNamespaceOfDeclaringTypeName) static string EntityToString(IEntity entity, bool includeDeclaringTypeName, bool includeNamespace, bool includeNamespaceOfDeclaringTypeName)
{ {
// Do not forget to update CSharpAmbienceTests, if this ever changes.
var ambience = CreateAmbience(); var ambience = CreateAmbience();
ambience.ConversionFlags |= ConversionFlags.ShowReturnType | ConversionFlags.ShowParameterList | ConversionFlags.ShowParameterModifiers;
if (includeDeclaringTypeName) if (includeDeclaringTypeName)
ambience.ConversionFlags |= ConversionFlags.ShowDeclaringType; ambience.ConversionFlags |= ConversionFlags.ShowDeclaringType;
if (includeNamespace) if (includeNamespace)
@ -453,6 +453,7 @@ namespace ICSharpCode.ILSpy
if (type == null) if (type == null)
throw new ArgumentNullException(nameof(type)); throw new ArgumentNullException(nameof(type));
var ambience = CreateAmbience(); var ambience = CreateAmbience();
// Do not forget to update CSharpAmbienceTests.ILSpyMainTreeViewFlags, if this ever changes.
if (includeNamespace) if (includeNamespace)
ambience.ConversionFlags |= ConversionFlags.UseFullyQualifiedTypeNames; ambience.ConversionFlags |= ConversionFlags.UseFullyQualifiedTypeNames;
if (type is ITypeDefinition definition) { if (type is ITypeDefinition definition) {
@ -584,7 +585,7 @@ namespace ICSharpCode.ILSpy
public override string GetTooltip(IEntity entity) public override string GetTooltip(IEntity entity)
{ {
var flags = ConversionFlags.All & ~ConversionFlags.ShowBody; var flags = ConversionFlags.All & ~(ConversionFlags.ShowBody | ConversionFlags.PlaceReturnTypeAfterParameterList);
return new CSharpAmbience() { ConversionFlags = flags }.ConvertSymbol(entity); return new CSharpAmbience() { ConversionFlags = flags }.ConvertSymbol(entity);
} }

Loading…
Cancel
Save