Browse Source

Decompile TupleElementNamesAttribute into tuple type syntax.

pull/1134/head
Daniel Grunwald 7 years ago
parent
commit
395bc185a3
  1. 16
      ICSharpCode.Decompiler.Tests/Helpers/RemoveCompilerAttribute.cs
  2. 3
      ICSharpCode.Decompiler.Tests/Helpers/Tester.cs
  3. 1
      ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
  4. 6
      ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
  5. 48
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/TupleTypes.cs
  6. 91
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/TupleTypes.opt.roslyn.il
  7. 92
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/TupleTypes.roslyn.il
  8. 2
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
  9. 30
      ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs
  10. 17
      ICSharpCode.Decompiler/CSharp/Syntax/DepthFirstAstVisitor.cs
  11. 3
      ICSharpCode.Decompiler/CSharp/Syntax/IAstVisitor.cs
  12. 96
      ICSharpCode.Decompiler/CSharp/Syntax/TupleAstType.cs
  13. 12
      ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs
  14. 68
      ICSharpCode.Decompiler/DecompilerSettings.cs
  15. 179
      ICSharpCode.Decompiler/TypeSystem/CecilLoader.cs
  16. 25
      ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs
  17. 88
      ICSharpCode.Decompiler/TypeSystem/TupleType.cs

16
ICSharpCode.Decompiler.Tests/Helpers/RemoveCompilerAttribute.cs

@ -6,9 +6,9 @@ using ICSharpCode.Decompiler.TypeSystem; @@ -6,9 +6,9 @@ using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.Tests.Helpers
{
class RemoveCompilerAttribute : DepthFirstAstVisitor<object, object>, IAstTransform
class RemoveCompilerAttribute : DepthFirstAstVisitor, IAstTransform
{
public override object VisitAttribute(CSharp.Syntax.Attribute attribute, object data)
public override void VisitAttribute(CSharp.Syntax.Attribute attribute)
{
var section = (AttributeSection)attribute.Parent;
SimpleType type = attribute.Type as SimpleType;
@ -25,16 +25,15 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -25,16 +25,15 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
if (section.Attributes.Count == 0)
section.Remove();
}
return null;
}
public void Run(AstNode rootNode, TransformContext context)
{
rootNode.AcceptVisitor(this, null);
rootNode.AcceptVisitor(this);
}
}
public class RemoveEmbeddedAtttributes : DepthFirstAstVisitor<object, object>, IAstTransform
public class RemoveEmbeddedAtttributes : DepthFirstAstVisitor, IAstTransform
{
HashSet<string> attributeNames = new HashSet<string>() {
"System.Runtime.CompilerServices.IsReadOnlyAttribute",
@ -42,21 +41,20 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -42,21 +41,20 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
"Microsoft.CodeAnalysis.EmbeddedAttribute",
};
public override object VisitTypeDeclaration(TypeDeclaration typeDeclaration, object data)
public override void VisitTypeDeclaration(TypeDeclaration typeDeclaration)
{
var typeDefinition = typeDeclaration.GetSymbol() as ITypeDefinition;
if (typeDefinition == null || !attributeNames.Contains(typeDefinition.FullName))
return null;
return;
if (typeDeclaration.Parent is NamespaceDeclaration ns && ns.Members.Count == 1)
ns.Remove();
else
typeDeclaration.Remove();
return null;
}
public void Run(AstNode rootNode, TransformContext context)
{
rootNode.AcceptVisitor(this, null);
rootNode.AcceptVisitor(this);
}
}
}

3
ICSharpCode.Decompiler.Tests/Helpers/Tester.cs

@ -178,7 +178,8 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -178,7 +178,8 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
MetadataReference.CreateFromFile(Path.Combine(refAsmPath, "mscorlib.dll")),
MetadataReference.CreateFromFile(Path.Combine(refAsmPath, "System.dll")),
MetadataReference.CreateFromFile(Path.Combine(refAsmPath, "System.Core.dll")),
MetadataReference.CreateFromFile(Path.Combine(refAsmPath, "System.Xml.dll"))
MetadataReference.CreateFromFile(Path.Combine(refAsmPath, "System.Xml.dll")),
MetadataReference.CreateFromFile(typeof(ValueTuple).Assembly.Location)
};
});

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

@ -70,6 +70,7 @@ @@ -70,6 +70,7 @@
<Compile Include="TestCases\Pretty\Issue1080.cs" />
<Compile Include="TestCases\Pretty\QualifierTests.cs" />
<Compile Include="TestCases\Pretty\RefLocalsAndReturns.cs" />
<Compile Include="TestCases\Pretty\TupleTypes.cs" />
<Compile Include="TestCases\Pretty\WellKnownConstants.cs" />
<Compile Include="TypeSystem\TypeSystemHelper.cs" />
<Compile Include="TypeSystem\TypeSystemLoaderTests.cs" />

6
ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs

@ -279,6 +279,12 @@ namespace ICSharpCode.Decompiler.Tests @@ -279,6 +279,12 @@ namespace ICSharpCode.Decompiler.Tests
RunForLibrary(cscOptions: cscOptions);
}
[Test]
public void TupleTypes([ValueSource("roslynOnlyOptions")] CSharpCompilerOptions cscOptions)
{
RunForLibrary(cscOptions: cscOptions);
}
[Test]
public void Issue1080([ValueSource(nameof(roslynOnlyOptions))] CSharpCompilerOptions cscOptions)
{

48
ICSharpCode.Decompiler.Tests/TestCases/Pretty/TupleTypes.cs

@ -0,0 +1,48 @@ @@ -0,0 +1,48 @@
// Copyright (c) 2018 Daniel Grunwald
//
// 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;
namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
public class TupleTypes
{
public ValueTuple VT0;
public ValueTuple<int> VT1;
public ValueTuple<int, int, int, int, int, int, int, ValueTuple> VT7EmptyRest;
public (int, uint) Unnamed2;
public (int, int, int) Unnamed3;
public (int, int, int, int) Unnamed4;
public (int, int, int, int, int) Unnamed5;
public (int, int, int, int, int, int) Unnamed6;
public (int, int, int, int, int, int, int) Unnamed7;
public (int, int, int, int, int, int, int, int) Unnamed8;
public (int a, uint b) Named2;
public (int a, uint b)[] Named2Array;
public (int a, int b, int c, int d, int e, int f, int g, int h) Named8;
public (int, int a, int, int b, int) PartiallyNamed;
public ((int a, int b) x, (int, int) y, (int c, int d) z) Nested1;
public ((object a, dynamic b), dynamic, (dynamic c, object d)) Nested2;
public (ValueTuple a, (int x1, int x2), ValueTuple<int> b, (int y1, int y2), (int, int) c) Nested3;
public (int a, int b, int c, int d, int e, int f, int g, int h, (int i, int j)) Nested4;
}
}

91
ICSharpCode.Decompiler.Tests/TestCases/Pretty/TupleTypes.opt.roslyn.il

@ -0,0 +1,91 @@ @@ -0,0 +1,91 @@
// Metadata version: v4.0.30319
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly extern System.Core
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly TupleTypes
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows.
// --- The following custom attribute is added automatically, do not uncomment -------
// .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 02 00 00 00 00 00 )
.permissionset reqmin
= {[mscorlib]System.Security.Permissions.SecurityPermissionAttribute = {property bool 'SkipVerification' = bool(true)}}
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module TupleTypes.dll
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// =============== CLASS MEMBERS DECLARATION ===================
.class public auto ansi beforefieldinit ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTypes
extends [mscorlib]System.Object
{
.field public valuetype [mscorlib]System.ValueTuple VT0
.field public valuetype [mscorlib]System.ValueTuple`1<int32> VT1
.field public valuetype [mscorlib]System.ValueTuple`8<int32,int32,int32,int32,int32,int32,int32,valuetype [mscorlib]System.ValueTuple> VT7EmptyRest
.field public valuetype [mscorlib]System.ValueTuple`2<int32,uint32> Unnamed2
.field public valuetype [mscorlib]System.ValueTuple`3<int32,int32,int32> Unnamed3
.field public valuetype [mscorlib]System.ValueTuple`4<int32,int32,int32,int32> Unnamed4
.field public valuetype [mscorlib]System.ValueTuple`5<int32,int32,int32,int32,int32> Unnamed5
.field public valuetype [mscorlib]System.ValueTuple`6<int32,int32,int32,int32,int32,int32> Unnamed6
.field public valuetype [mscorlib]System.ValueTuple`7<int32,int32,int32,int32,int32,int32,int32> Unnamed7
.field public valuetype [mscorlib]System.ValueTuple`8<int32,int32,int32,int32,int32,int32,int32,valuetype [mscorlib]System.ValueTuple`1<int32>> Unnamed8
.field public valuetype [mscorlib]System.ValueTuple`2<int32,uint32> Named2
.custom instance void [mscorlib]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) = ( 01 00 02 00 00 00 01 61 01 62 00 00 ) // .......a.b..
.field public valuetype [mscorlib]System.ValueTuple`2<int32,uint32>[] Named2Array
.custom instance void [mscorlib]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) = ( 01 00 02 00 00 00 01 61 01 62 00 00 ) // .......a.b..
.field public valuetype [mscorlib]System.ValueTuple`8<int32,int32,int32,int32,int32,int32,int32,valuetype [mscorlib]System.ValueTuple`1<int32>> Named8
.custom instance void [mscorlib]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) = ( 01 00 09 00 00 00 01 61 01 62 01 63 01 64 01 65 // .......a.b.c.d.e
01 66 01 67 01 68 FF 00 00 ) // .f.g.h...
.field public valuetype [mscorlib]System.ValueTuple`5<int32,int32,int32,int32,int32> PartiallyNamed
.custom instance void [mscorlib]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) = ( 01 00 05 00 00 00 FF 01 61 FF 01 62 FF 00 00 ) // ........a..b...
.field public valuetype [mscorlib]System.ValueTuple`3<valuetype [mscorlib]System.ValueTuple`2<int32,int32>,valuetype [mscorlib]System.ValueTuple`2<int32,int32>,valuetype [mscorlib]System.ValueTuple`2<int32,int32>> Nested1
.custom instance void [mscorlib]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) = ( 01 00 09 00 00 00 01 78 01 79 01 7A 01 61 01 62 // .......x.y.z.a.b
FF FF 01 63 01 64 00 00 ) // ...c.d..
.field public valuetype [mscorlib]System.ValueTuple`3<valuetype [mscorlib]System.ValueTuple`2<object,object>,object,valuetype [mscorlib]System.ValueTuple`2<object,object>> Nested2
.custom instance void [System.Core]System.Runtime.CompilerServices.DynamicAttribute::.ctor(bool[]) = ( 01 00 08 00 00 00 00 00 00 01 01 00 01 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) = ( 01 00 07 00 00 00 FF FF FF 01 61 01 62 01 63 01 // ..........a.b.c.
64 00 00 ) // d..
.field public valuetype [mscorlib]System.ValueTuple`5<valuetype [mscorlib]System.ValueTuple,valuetype [mscorlib]System.ValueTuple`2<int32,int32>,valuetype [mscorlib]System.ValueTuple`1<int32>,valuetype [mscorlib]System.ValueTuple`2<int32,int32>,valuetype [mscorlib]System.ValueTuple`2<int32,int32>> Nested3
.custom instance void [mscorlib]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) = ( 01 00 0C 00 00 00 01 61 FF 01 62 FF 01 63 02 78 // .......a..b..c.x
31 02 78 32 FF 02 79 31 02 79 32 FF FF 00 00 ) // 1.x2..y1.y2....
.field public valuetype [mscorlib]System.ValueTuple`8<int32,int32,int32,int32,int32,int32,int32,valuetype [mscorlib]System.ValueTuple`2<int32,valuetype [mscorlib]System.ValueTuple`2<int32,int32>>> Nested4
.custom instance void [mscorlib]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) = ( 01 00 0D 00 00 00 01 61 01 62 01 63 01 64 01 65 // .......a.b.c.d.e
01 66 01 67 01 68 FF FF FF 01 69 01 6A 00 00 ) // .f.g.h....i.j..
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ret
} // end of method TupleTypes::.ctor
} // end of class ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTypes
// =============================================================
// *********** DISASSEMBLY COMPLETE ***********************

92
ICSharpCode.Decompiler.Tests/TestCases/Pretty/TupleTypes.roslyn.il

@ -0,0 +1,92 @@ @@ -0,0 +1,92 @@
// Metadata version: v4.0.30319
.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly extern System.Core
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly TupleTypes
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows.
// --- The following custom attribute is added automatically, do not uncomment -------
// .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 07 01 00 00 00 00 )
.permissionset reqmin
= {[mscorlib]System.Security.Permissions.SecurityPermissionAttribute = {property bool 'SkipVerification' = bool(true)}}
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module TupleTypes.dll
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// =============== CLASS MEMBERS DECLARATION ===================
.class public auto ansi beforefieldinit ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTypes
extends [mscorlib]System.Object
{
.field public valuetype [mscorlib]System.ValueTuple VT0
.field public valuetype [mscorlib]System.ValueTuple`1<int32> VT1
.field public valuetype [mscorlib]System.ValueTuple`8<int32,int32,int32,int32,int32,int32,int32,valuetype [mscorlib]System.ValueTuple> VT7EmptyRest
.field public valuetype [mscorlib]System.ValueTuple`2<int32,uint32> Unnamed2
.field public valuetype [mscorlib]System.ValueTuple`3<int32,int32,int32> Unnamed3
.field public valuetype [mscorlib]System.ValueTuple`4<int32,int32,int32,int32> Unnamed4
.field public valuetype [mscorlib]System.ValueTuple`5<int32,int32,int32,int32,int32> Unnamed5
.field public valuetype [mscorlib]System.ValueTuple`6<int32,int32,int32,int32,int32,int32> Unnamed6
.field public valuetype [mscorlib]System.ValueTuple`7<int32,int32,int32,int32,int32,int32,int32> Unnamed7
.field public valuetype [mscorlib]System.ValueTuple`8<int32,int32,int32,int32,int32,int32,int32,valuetype [mscorlib]System.ValueTuple`1<int32>> Unnamed8
.field public valuetype [mscorlib]System.ValueTuple`2<int32,uint32> Named2
.custom instance void [mscorlib]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) = ( 01 00 02 00 00 00 01 61 01 62 00 00 ) // .......a.b..
.field public valuetype [mscorlib]System.ValueTuple`2<int32,uint32>[] Named2Array
.custom instance void [mscorlib]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) = ( 01 00 02 00 00 00 01 61 01 62 00 00 ) // .......a.b..
.field public valuetype [mscorlib]System.ValueTuple`8<int32,int32,int32,int32,int32,int32,int32,valuetype [mscorlib]System.ValueTuple`1<int32>> Named8
.custom instance void [mscorlib]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) = ( 01 00 09 00 00 00 01 61 01 62 01 63 01 64 01 65 // .......a.b.c.d.e
01 66 01 67 01 68 FF 00 00 ) // .f.g.h...
.field public valuetype [mscorlib]System.ValueTuple`5<int32,int32,int32,int32,int32> PartiallyNamed
.custom instance void [mscorlib]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) = ( 01 00 05 00 00 00 FF 01 61 FF 01 62 FF 00 00 ) // ........a..b...
.field public valuetype [mscorlib]System.ValueTuple`3<valuetype [mscorlib]System.ValueTuple`2<int32,int32>,valuetype [mscorlib]System.ValueTuple`2<int32,int32>,valuetype [mscorlib]System.ValueTuple`2<int32,int32>> Nested1
.custom instance void [mscorlib]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) = ( 01 00 09 00 00 00 01 78 01 79 01 7A 01 61 01 62 // .......x.y.z.a.b
FF FF 01 63 01 64 00 00 ) // ...c.d..
.field public valuetype [mscorlib]System.ValueTuple`3<valuetype [mscorlib]System.ValueTuple`2<object,object>,object,valuetype [mscorlib]System.ValueTuple`2<object,object>> Nested2
.custom instance void [System.Core]System.Runtime.CompilerServices.DynamicAttribute::.ctor(bool[]) = ( 01 00 08 00 00 00 00 00 00 01 01 00 01 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) = ( 01 00 07 00 00 00 FF FF FF 01 61 01 62 01 63 01 // ..........a.b.c.
64 00 00 ) // d..
.field public valuetype [mscorlib]System.ValueTuple`5<valuetype [mscorlib]System.ValueTuple,valuetype [mscorlib]System.ValueTuple`2<int32,int32>,valuetype [mscorlib]System.ValueTuple`1<int32>,valuetype [mscorlib]System.ValueTuple`2<int32,int32>,valuetype [mscorlib]System.ValueTuple`2<int32,int32>> Nested3
.custom instance void [mscorlib]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) = ( 01 00 0C 00 00 00 01 61 FF 01 62 FF 01 63 02 78 // .......a..b..c.x
31 02 78 32 FF 02 79 31 02 79 32 FF FF 00 00 ) // 1.x2..y1.y2....
.field public valuetype [mscorlib]System.ValueTuple`8<int32,int32,int32,int32,int32,int32,int32,valuetype [mscorlib]System.ValueTuple`2<int32,valuetype [mscorlib]System.ValueTuple`2<int32,int32>>> Nested4
.custom instance void [mscorlib]System.Runtime.CompilerServices.TupleElementNamesAttribute::.ctor(string[]) = ( 01 00 0D 00 00 00 01 61 01 62 01 63 01 64 01 65 // .......a.b.c.d.e
01 66 01 67 01 68 FF FF FF 01 69 01 6A 00 00 ) // .f.g.h....i.j..
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: nop
IL_0007: ret
} // end of method TupleTypes::.ctor
} // end of class ICSharpCode.Decompiler.Tests.TestCases.Pretty.TupleTypes
// =============================================================
// *********** DISASSEMBLY COMPLETE ***********************

2
ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

@ -187,7 +187,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -187,7 +187,7 @@ namespace ICSharpCode.Decompiler.CSharp
}
public CSharpDecompiler(ModuleDefinition module, DecompilerSettings settings)
: this(new DecompilerTypeSystem(module), settings)
: this(new DecompilerTypeSystem(module, settings), settings)
{
}

30
ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs

@ -445,6 +445,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -445,6 +445,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
{
foreach (CSharpModifierToken modifier in modifierTokens) {
modifier.AcceptVisitor(this);
Space();
}
}
@ -2283,28 +2284,25 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -2283,28 +2284,25 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
public virtual void VisitTupleType(TupleAstType tupleType)
{
Debug.Assert(tupleType.ElementTypes.Count >= 2);
Debug.Assert(tupleType.Elements.Count >= 2);
StartNode(tupleType);
LPar();
if (tupleType.ElementNames.Any()) {
bool isFirst = true;
foreach (var (type, name) in tupleType.ElementTypes.Zip(tupleType.ElementNames)) {
if (isFirst) {
isFirst = false;
} else {
Comma(type);
}
type.AcceptVisitor(this);
Space();
name.AcceptVisitor(this);
}
} else {
WriteCommaSeparatedList(tupleType.ElementTypes);
}
WriteCommaSeparatedList(tupleType.Elements);
RPar();
EndNode(tupleType);
}
public virtual void VisitTupleTypeElement(TupleTypeElement tupleTypeElement)
{
StartNode(tupleTypeElement);
tupleTypeElement.Type.AcceptVisitor(this);
if (!tupleTypeElement.NameToken.IsNull) {
Space();
tupleTypeElement.NameToken.AcceptVisitor(this);
}
EndNode(tupleTypeElement);
}
public virtual void VisitComposedType(ComposedType composedType)
{
StartNode(composedType);

17
ICSharpCode.Decompiler/CSharp/Syntax/DepthFirstAstVisitor.cs

@ -121,6 +121,11 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -121,6 +121,11 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
VisitChildren(tupleType);
}
public virtual void VisitTupleTypeElement(TupleTypeElement tupleTypeElement)
{
VisitChildren (tupleTypeElement);
}
public virtual void VisitAttribute (Attribute attribute)
{
VisitChildren (attribute);
@ -762,7 +767,12 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -762,7 +767,12 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
{
return VisitChildren (tupleType);
}
public virtual T VisitTupleTypeElement(TupleTypeElement tupleTypeElement)
{
return VisitChildren (tupleTypeElement);
}
public virtual T VisitAttribute (Attribute attribute)
{
return VisitChildren (attribute);
@ -1405,6 +1415,11 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -1405,6 +1415,11 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
return VisitChildren (tupleType, data);
}
public virtual S VisitTupleTypeElement(TupleTypeElement tupleTypeElement, T data)
{
return VisitChildren (tupleTypeElement, data);
}
public virtual S VisitAttribute (Attribute attribute, T data)
{
return VisitChildren (attribute, data);

3
ICSharpCode.Decompiler/CSharp/Syntax/IAstVisitor.cs

@ -135,6 +135,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -135,6 +135,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
void VisitSimpleType(SimpleType simpleType);
void VisitMemberType(MemberType memberType);
void VisitTupleType(TupleAstType tupleType);
void VisitTupleTypeElement(TupleTypeElement tupleTypeElement);
void VisitComposedType(ComposedType composedType);
void VisitArraySpecifier(ArraySpecifier arraySpecifier);
void VisitPrimitiveType(PrimitiveType primitiveType);
@ -275,6 +276,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -275,6 +276,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
S VisitSimpleType(SimpleType simpleType);
S VisitMemberType(MemberType memberType);
S VisitTupleType(TupleAstType tupleType);
S VisitTupleTypeElement(TupleTypeElement tupleTypeElement);
S VisitComposedType(ComposedType composedType);
S VisitArraySpecifier(ArraySpecifier arraySpecifier);
S VisitPrimitiveType(PrimitiveType primitiveType);
@ -415,6 +417,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -415,6 +417,7 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
S VisitSimpleType(SimpleType simpleType, T data);
S VisitMemberType(MemberType memberType, T data);
S VisitTupleType(TupleAstType tupleType, T data);
S VisitTupleTypeElement(TupleTypeElement tupleTypeElement, T data);
S VisitComposedType(ComposedType composedType, T data);
S VisitArraySpecifier(ArraySpecifier arraySpecifier, T data);
S VisitPrimitiveType(PrimitiveType primitiveType, T data);

96
ICSharpCode.Decompiler/CSharp/Syntax/TupleAstType.cs

@ -17,6 +17,8 @@ @@ -17,6 +17,8 @@
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Immutable;
using System.Linq;
using ICSharpCode.Decompiler.CSharp.Resolver;
using ICSharpCode.Decompiler.CSharp.Syntax.PatternMatching;
using ICSharpCode.Decompiler.TypeSystem;
@ -25,14 +27,12 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -25,14 +27,12 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
{
public class TupleAstType : AstType
{
public AstNodeCollection<AstType> ElementTypes {
get { return GetChildrenByRole(Roles.TypeArgument); }
}
public static readonly Role<TupleTypeElement> ElementRole = new Role<TupleTypeElement>("Element", TupleTypeElement.Null);
public AstNodeCollection<Identifier> ElementNames {
get { return GetChildrenByRole(Roles.Identifier); }
public AstNodeCollection<TupleTypeElement> Elements {
get { return GetChildrenByRole(ElementRole); }
}
public override void AcceptVisitor(IAstVisitor visitor)
{
visitor.VisitTupleType(this);
@ -50,14 +50,90 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -50,14 +50,90 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
public override ITypeReference ToTypeReference(NameLookupMode lookupMode, InterningProvider interningProvider = null)
{
throw new NotSupportedException();
return new TupleTypeReference(
this.Elements.Select(e => e.Type.ToTypeReference(lookupMode, interningProvider)).ToImmutableArray(),
this.Elements.Select(e => e.Name).ToImmutableArray()
);
}
protected internal override bool DoMatch(AstNode other, Match match)
{
return other is TupleAstType o && Elements.DoMatch(o.Elements, match);
}
}
public class TupleTypeElement : AstNode
{
#region Null
public new static readonly TupleTypeElement Null = new TupleTypeElement();
sealed class NullTupleTypeElement : TupleTypeElement
{
public override bool IsNull {
get {
return true;
}
}
public override void AcceptVisitor(IAstVisitor visitor)
{
visitor.VisitNullNode(this);
}
public override T AcceptVisitor<T>(IAstVisitor<T> visitor)
{
return visitor.VisitNullNode(this);
}
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data)
{
return visitor.VisitNullNode(this, data);
}
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
{
return other == null || other.IsNull;
}
}
#endregion
public AstType Type {
get { return GetChildByRole(Roles.Type); }
set { SetChildByRole(Roles.Type, value); }
}
public string Name {
get { return GetChildByRole(Roles.Identifier).Name; }
set { SetChildByRole(Roles.Identifier, Identifier.Create(value)); }
}
public Identifier NameToken {
get { return GetChildByRole(Roles.Identifier); }
set { SetChildByRole(Roles.Identifier, value); }
}
public override NodeType NodeType => NodeType.Unknown;
public override void AcceptVisitor(IAstVisitor visitor)
{
visitor.VisitTupleTypeElement(this);
}
public override T AcceptVisitor<T>(IAstVisitor<T> visitor)
{
return visitor.VisitTupleTypeElement(this);
}
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data)
{
return visitor.VisitTupleTypeElement(this, data);
}
protected internal override bool DoMatch(AstNode other, Match match)
{
return other is TupleAstType o
&& ElementTypes.DoMatch(o.ElementTypes, match)
&& ElementNames.DoMatch(o.ElementNames, match);
return other is TupleTypeElement o
&& Type.DoMatch(o.Type, match)
&& MatchString(Name, o.Name);
}
}
}

12
ICSharpCode.Decompiler/CSharp/Syntax/TypeSystemAstBuilder.cs

@ -239,13 +239,11 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -239,13 +239,11 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
}
if (type is TupleType tuple) {
var astType = new TupleAstType();
if (tuple.HasCustomElementNames) {
foreach (var (etype, ename) in tuple.TupleElementTypes.Zip(tuple.TupleElementNames)) {
astType.ElementTypes.Add(ConvertType(etype));
astType.ElementNames.Add(Identifier.Create(ename));
}
} else {
astType.ElementTypes.AddRange(tuple.TupleElementTypes.Select(ConvertType));
foreach (var (etype, ename) in tuple.ElementTypes.Zip(tuple.ElementNames)) {
astType.Elements.Add(new TupleTypeElement {
Type = ConvertType(etype),
Name = ename
});
}
return astType;
}

68
ICSharpCode.Decompiler/DecompilerSettings.cs

@ -59,7 +59,7 @@ namespace ICSharpCode.Decompiler @@ -59,7 +59,7 @@ namespace ICSharpCode.Decompiler
expressionTrees = false;
}
if (languageVersion < CSharp.LanguageVersion.CSharp4) {
// * dynamic (not supported yet)
dynamic = false;
// * named and optional arguments (not supported yet)
}
if (languageVersion < CSharp.LanguageVersion.CSharp5) {
@ -74,6 +74,8 @@ namespace ICSharpCode.Decompiler @@ -74,6 +74,8 @@ namespace ICSharpCode.Decompiler
}
if (languageVersion < CSharp.LanguageVersion.CSharp7) {
outVariables = false;
tupleTypes = false;
tupleConversions = false;
discards = false;
}
if (languageVersion < CSharp.LanguageVersion.CSharp7_2) {
@ -81,7 +83,7 @@ namespace ICSharpCode.Decompiler @@ -81,7 +83,7 @@ namespace ICSharpCode.Decompiler
}
if (languageVersion < CSharp.LanguageVersion.CSharp7_3) {
//introduceUnmanagedTypeConstraint = false;
//...
tupleComparisons = false;
}
}
@ -145,6 +147,21 @@ namespace ICSharpCode.Decompiler @@ -145,6 +147,21 @@ namespace ICSharpCode.Decompiler
}
}
bool dynamic = true;
/// <summary>
/// Decompile use of the 'dynamic' type.
/// </summary>
public bool Dynamic {
get { return dynamic; }
set {
if (dynamic != value) {
dynamic = value;
OnPropertyChanged();
}
}
}
bool asyncAwait = true;
/// <summary>
@ -571,6 +588,53 @@ namespace ICSharpCode.Decompiler @@ -571,6 +588,53 @@ namespace ICSharpCode.Decompiler
}
}
bool tupleTypes = true;
/// <summary>
/// Gets/Sets whether tuple type syntax <c>(int, string)</c>
/// should be used for <c>System.ValueTuple</c>.
/// </summary>
public bool TupleTypes {
get { return tupleTypes; }
set {
if (tupleTypes != value) {
tupleTypes = value;
OnPropertyChanged();
}
}
}
bool tupleConversions = true;
/// <summary>
/// Gets/Sets whether implicit conversions between tuples
/// should be used in the decompiled output.
/// </summary>
public bool TupleConversions {
get { return tupleConversions; }
set {
if (tupleConversions != value) {
tupleConversions = value;
OnPropertyChanged();
}
}
}
bool tupleComparisons = true;
/// <summary>
/// Gets/Sets whether tuple comparisons should be detected.
/// </summary>
public bool TupleComparisons {
get { return tupleComparisons; }
set {
if (tupleComparisons != value) {
tupleComparisons = value;
OnPropertyChanged();
}
}
}
#region Options to aid VB decompilation
bool assumeArrayLengthFitsIntoInt32 = true;

179
ICSharpCode.Decompiler/TypeSystem/CecilLoader.cs

@ -18,6 +18,7 @@ @@ -18,6 +18,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
@ -38,13 +39,6 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -38,13 +39,6 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// if you want to load multiple project contents in parallel.</remarks>
public sealed class CecilLoader : AssemblyLoader
{
/// <summary>
/// Version number of the cecil loader.
/// Should be incremented when fixing bugs in the cecil loader so that project contents cached on disk
/// (which might be incorrect due to the bug) are re-created.
/// </summary>
const int cecilLoaderVersion = 1;
#region Options
// Most options are defined in the AssemblyLoader base class
@ -64,6 +58,16 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -64,6 +58,16 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// </remarks>
public bool LazyLoad { get; set; }
/// <summary>
/// Gets/Sets whether to use the <c>dynamic</c> type.
/// </summary>
public bool UseDynamicType { get; set; } = true;
/// <summary>
/// Gets/Sets whether to use the tuple types.
/// </summary>
public bool UseTupleTypes { get; set; } = true;
/// <summary>
/// This delegate gets executed whenever an entity was loaded.
/// </summary>
@ -75,20 +79,11 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -75,20 +79,11 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// </remarks>
public Action<IUnresolvedEntity, MemberReference> OnEntityLoaded { get; set; }
bool shortenInterfaceImplNames = true;
/// <summary>
/// Specifies whether method names of explicit interface-implementations should be shortened.
/// </summary>
/// <remarks>This is important when working with parser-initialized type-systems in order to be consistent.</remarks>
public bool ShortenInterfaceImplNames {
get {
return shortenInterfaceImplNames;
}
set {
shortenInterfaceImplNames = value;
}
}
public bool ShortenInterfaceImplNames { get; set; } = true;
#endregion
ModuleDefinition currentModule;
@ -108,6 +103,8 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -108,6 +103,8 @@ namespace ICSharpCode.Decompiler.TypeSystem
{
// use a shared typeSystemTranslationTable
this.IncludeInternalMembers = loader.IncludeInternalMembers;
this.UseDynamicType = loader.UseDynamicType;
this.UseTupleTypes = loader.UseTupleTypes;
this.LazyLoad = loader.LazyLoad;
this.OnEntityLoaded = loader.OnEntityLoaded;
this.ShortenInterfaceImplNames = loader.ShortenInterfaceImplNames;
@ -295,11 +292,12 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -295,11 +292,12 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// IsValueType is set correctly.</param>
public ITypeReference ReadTypeReference(TypeReference type, ICustomAttributeProvider typeAttributes = null, bool isFromSignature = false)
{
int typeIndex = 0;
return CreateType(type, typeAttributes, ref typeIndex, isFromSignature);
int dynamicTypeIndex = 0;
int tupleTypeIndex = 0;
return CreateType(type, typeAttributes, ref dynamicTypeIndex, ref tupleTypeIndex, isFromSignature);
}
ITypeReference CreateType(TypeReference type, ICustomAttributeProvider typeAttributes, ref int typeIndex, bool isFromSignature)
ITypeReference CreateType(TypeReference type, ICustomAttributeProvider typeAttributes, ref int dynamicTypeIndex, ref int tupleTypeIndex, bool isFromSignature)
{
if (type == null) {
return SpecialType.UnknownType;
@ -307,90 +305,120 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -307,90 +305,120 @@ namespace ICSharpCode.Decompiler.TypeSystem
switch (type.MetadataType) {
case MetadataType.Void:
return KnownTypeReference.Get(KnownTypeCode.Void);
return KnownTypeReference.Void;
case MetadataType.Boolean:
return KnownTypeReference.Get(KnownTypeCode.Boolean);
return KnownTypeReference.Boolean;
case MetadataType.Char:
return KnownTypeReference.Get(KnownTypeCode.Char);
return KnownTypeReference.Char;
case MetadataType.SByte:
return KnownTypeReference.Get(KnownTypeCode.SByte);
return KnownTypeReference.SByte;
case MetadataType.Byte:
return KnownTypeReference.Get(KnownTypeCode.Byte);
return KnownTypeReference.Byte;
case MetadataType.Int16:
return KnownTypeReference.Get(KnownTypeCode.Int16);
return KnownTypeReference.Int16;
case MetadataType.UInt16:
return KnownTypeReference.Get(KnownTypeCode.UInt16);
return KnownTypeReference.UInt16;
case MetadataType.Int32:
return KnownTypeReference.Get(KnownTypeCode.Int32);
return KnownTypeReference.Int32;
case MetadataType.UInt32:
return KnownTypeReference.Get(KnownTypeCode.UInt32);
return KnownTypeReference.UInt32;
case MetadataType.Int64:
return KnownTypeReference.Get(KnownTypeCode.Int64);
return KnownTypeReference.Int64;
case MetadataType.UInt64:
return KnownTypeReference.Get(KnownTypeCode.UInt64);
return KnownTypeReference.UInt64;
case MetadataType.Single:
return KnownTypeReference.Get(KnownTypeCode.Single);
return KnownTypeReference.Single;
case MetadataType.Double:
return KnownTypeReference.Get(KnownTypeCode.Double);
return KnownTypeReference.Double;
case MetadataType.String:
return KnownTypeReference.Get(KnownTypeCode.String);
return KnownTypeReference.String;
case MetadataType.Pointer:
typeIndex++;
dynamicTypeIndex++;
return interningProvider.Intern(
new PointerTypeReference(
CreateType(
(type as Mono.Cecil.PointerType).ElementType,
typeAttributes, ref typeIndex, isFromSignature: true)));
typeAttributes, ref dynamicTypeIndex, ref tupleTypeIndex, isFromSignature: true)));
case MetadataType.ByReference:
typeIndex++;
dynamicTypeIndex++;
return interningProvider.Intern(
new ByReferenceTypeReference(
CreateType(
(type as Mono.Cecil.ByReferenceType).ElementType,
typeAttributes, ref typeIndex, isFromSignature: true)));
typeAttributes, ref dynamicTypeIndex, ref tupleTypeIndex, isFromSignature: true)));
case MetadataType.Var:
return TypeParameterReference.Create(SymbolKind.TypeDefinition, ((GenericParameter)type).Position);
case MetadataType.MVar:
return TypeParameterReference.Create(SymbolKind.Method, ((GenericParameter)type).Position);
case MetadataType.Array:
typeIndex++;
dynamicTypeIndex++;
return interningProvider.Intern(
new ArrayTypeReference(
CreateType(
(type as Mono.Cecil.ArrayType).ElementType,
typeAttributes, ref typeIndex, isFromSignature: true),
typeAttributes, ref dynamicTypeIndex, ref tupleTypeIndex, isFromSignature: true),
(type as Mono.Cecil.ArrayType).Rank));
case MetadataType.GenericInstance:
GenericInstanceType gType = (GenericInstanceType)type;
ITypeReference baseType = CreateType(gType.ElementType, typeAttributes, ref typeIndex, isFromSignature: true);
ITypeReference baseType = CreateType(gType.ElementType, typeAttributes, ref dynamicTypeIndex, ref tupleTypeIndex, isFromSignature: true);
if (UseTupleTypes && IsValueTuple(gType, out int tupleCardinality)) {
if (tupleCardinality > 1) {
var elementNames = GetTupleElementNames(typeAttributes, tupleTypeIndex, tupleCardinality);
tupleTypeIndex += tupleCardinality;
ITypeReference[] elementTypeRefs = new ITypeReference[tupleCardinality];
int outPos = 0;
do {
int normalArgCount = Math.Min(gType.GenericArguments.Count, TupleType.RestPosition - 1);
for (int i = 0; i < normalArgCount; i++) {
dynamicTypeIndex++;
elementTypeRefs[outPos++] = CreateType(gType.GenericArguments[i], typeAttributes, ref dynamicTypeIndex, ref tupleTypeIndex, isFromSignature: true);
}
if (gType.GenericArguments.Count == TupleType.RestPosition) {
gType = (GenericInstanceType)gType.GenericArguments.Last();
dynamicTypeIndex++;
if (IsValueTuple(gType, out int nestedCardinality)) {
tupleTypeIndex += nestedCardinality;
} else {
Debug.Fail("TRest should be another value tuple");
}
} else {
gType = null;
}
} while (gType != null);
return new TupleTypeReference(elementTypeRefs.ToImmutableArray(), elementNames);
} else {
// C# doesn't have syntax for tuples of cardinality <= 1
tupleTypeIndex += tupleCardinality;
}
}
ITypeReference[] para = new ITypeReference[gType.GenericArguments.Count];
for (int i = 0; i < para.Length; ++i) {
typeIndex++;
para[i] = CreateType(gType.GenericArguments[i], typeAttributes, ref typeIndex, isFromSignature: true);
dynamicTypeIndex++;
para[i] = CreateType(gType.GenericArguments[i], typeAttributes, ref dynamicTypeIndex, ref tupleTypeIndex, isFromSignature: true);
}
return interningProvider.Intern(new ParameterizedTypeReference(baseType, para));
case MetadataType.IntPtr:
return KnownTypeReference.Get(KnownTypeCode.IntPtr);
return KnownTypeReference.IntPtr;
case MetadataType.UIntPtr:
return KnownTypeReference.Get(KnownTypeCode.UIntPtr);
return KnownTypeReference.UIntPtr;
case MetadataType.FunctionPointer:
// C# and the NR typesystem don't support function pointer types.
// Function pointer types map to StackType.I, so we'll use IntPtr instead.
return KnownTypeReference.Get(KnownTypeCode.IntPtr);
return KnownTypeReference.IntPtr;
case MetadataType.Object:
if (HasDynamicAttribute(typeAttributes, typeIndex)) {
if (UseDynamicType && HasDynamicAttribute(typeAttributes, dynamicTypeIndex)) {
return SpecialType.Dynamic;
} else {
return KnownTypeReference.Get(KnownTypeCode.Object);
return KnownTypeReference.Object;
}
case MetadataType.RequiredModifier:
case MetadataType.OptionalModifier:
// we don't store modopts/modreqs in the NR type system
return CreateType(((TypeSpecification)type).ElementType, typeAttributes, ref typeIndex, isFromSignature: true);
return CreateType(((TypeSpecification)type).ElementType, typeAttributes, ref dynamicTypeIndex, ref tupleTypeIndex, isFromSignature: true);
case MetadataType.Sentinel:
return SpecialType.ArgList;
case MetadataType.Pinned:
return CreateType(((PinnedType)type).ElementType, typeAttributes, ref typeIndex, isFromSignature: true);
return CreateType(((PinnedType)type).ElementType, typeAttributes, ref dynamicTypeIndex, ref tupleTypeIndex, isFromSignature: true);
}
// valuetype/class/typedbyreference
if (type is TypeDefinition) {
@ -400,7 +428,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -400,7 +428,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
// or if it's a TypeSpecification.
bool? isReferenceType = isFromSignature ? (bool?)!type.IsValueType : null;
if (type.IsNested) {
ITypeReference typeRef = CreateType(type.DeclaringType, typeAttributes, ref typeIndex, isFromSignature);
ITypeReference typeRef = CreateType(type.DeclaringType, typeAttributes, ref dynamicTypeIndex, ref tupleTypeIndex, isFromSignature);
int partTypeParameterCount;
string namepart = ReflectionHelper.SplitTypeParameterCountFromReflectionName(type.Name, out partTypeParameterCount);
namepart = interningProvider.Intern(namepart);
@ -411,7 +439,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -411,7 +439,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
if (name == null)
throw new InvalidOperationException("type.Name returned null. Type: " + type.ToString());
if (name == "Object" && ns == "System" && HasDynamicAttribute(typeAttributes, typeIndex)) {
if (UseDynamicType && name == "Object" && ns == "System" && HasDynamicAttribute(typeAttributes, dynamicTypeIndex)) {
return SpecialType.Dynamic;
}
int typeParameterCount;
@ -422,7 +450,46 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -422,7 +450,46 @@ namespace ICSharpCode.Decompiler.TypeSystem
isReferenceType));
}
}
static bool IsValueTuple(GenericInstanceType gType, out int tupleCardinality)
{
tupleCardinality = 0;
if (gType == null || !gType.Name.StartsWith("ValueTuple`", StringComparison.Ordinal) || gType.Namespace != "System")
return false;
if (gType.GenericArguments.Count == TupleType.RestPosition) {
if (IsValueTuple(gType.GenericArguments.Last() as GenericInstanceType, out tupleCardinality)) {
tupleCardinality += TupleType.RestPosition - 1;
return true;
}
}
tupleCardinality = gType.GenericArguments.Count;
return tupleCardinality > 0 && tupleCardinality < TupleType.RestPosition;
}
static ImmutableArray<string> GetTupleElementNames(ICustomAttributeProvider attributeProvider, int tupleTypeIndex, int tupleCardinality)
{
if (attributeProvider == null || !attributeProvider.HasCustomAttributes)
return default(ImmutableArray<string>);
foreach (CustomAttribute a in attributeProvider.CustomAttributes) {
TypeReference type = a.AttributeType;
if (type.Name == "TupleElementNamesAttribute" && type.Namespace == "System.Runtime.CompilerServices") {
if (a.ConstructorArguments.Count == 1) {
CustomAttributeArgument[] values = a.ConstructorArguments[0].Value as CustomAttributeArgument[];
if (values != null) {
string[] extractedValues = new string[tupleCardinality];
for (int i = 0; i < tupleCardinality; i++) {
if (tupleTypeIndex + i < values.Length) {
extractedValues[i] = values[tupleTypeIndex + i].Value as string;
}
}
return extractedValues.ToImmutableArray();
}
}
}
}
return default(ImmutableArray<string>);
}
IAssemblyReference GetAssemblyReference(IMetadataScope scope)
{
if (scope == null || scope == currentModule)
@ -827,7 +894,11 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -827,7 +894,11 @@ namespace ICSharpCode.Decompiler.TypeSystem
foreach (var cecilAttribute in attributes) {
TypeReference type = cecilAttribute.AttributeType;
if (type.Namespace == "System.Runtime.CompilerServices") {
if (type.Name == "DynamicAttribute" || type.Name == "ExtensionAttribute" || type.Name == "DecimalConstantAttribute")
if (type.Name == "ExtensionAttribute" || type.Name == "DecimalConstantAttribute")
continue;
if (UseDynamicType && type.Name == "DynamicAttribute")
continue;
if (UseTupleTypes && type.Name == "TupleElementNamesAttribute")
continue;
} else if (type.Name == "ParamArrayAttribute" && type.Namespace == "System") {
continue;

25
ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs

@ -23,7 +23,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -23,7 +23,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// CecilLoader used for converting cecil type references to ITypeReference.
/// May only be accessed within lock(typeReferenceCecilLoader).
/// </summary>
readonly CecilLoader typeReferenceCecilLoader = new CecilLoader();
readonly CecilLoader typeReferenceCecilLoader;
/// <summary>
/// Dictionary for NRefactory->Cecil lookup.
@ -35,13 +35,30 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -35,13 +35,30 @@ namespace ICSharpCode.Decompiler.TypeSystem
Dictionary<PropertyReference, IProperty> propertyLookupCache = new Dictionary<PropertyReference, IProperty>();
Dictionary<MethodReference, IMethod> methodLookupCache = new Dictionary<MethodReference, IMethod>();
Dictionary<EventReference, IEvent> eventLookupCache = new Dictionary<EventReference, IEvent>();
public DecompilerTypeSystem(ModuleDefinition moduleDefinition)
public DecompilerTypeSystem(ModuleDefinition moduleDefinition) : this(moduleDefinition, new DecompilerSettings())
{
}
public DecompilerTypeSystem(ModuleDefinition moduleDefinition, DecompilerSettings settings)
{
if (moduleDefinition == null)
throw new ArgumentNullException(nameof(moduleDefinition));
if (settings == null)
throw new ArgumentNullException(nameof(settings));
this.moduleDefinition = moduleDefinition;
CecilLoader cecilLoader = new CecilLoader { IncludeInternalMembers = true, LazyLoad = true, OnEntityLoaded = StoreMemberReference, ShortenInterfaceImplNames = false };
typeReferenceCecilLoader = new CecilLoader {
UseDynamicType = settings.Dynamic,
UseTupleTypes = settings.TupleTypes,
};
CecilLoader cecilLoader = new CecilLoader {
IncludeInternalMembers = true,
LazyLoad = true,
OnEntityLoaded = StoreMemberReference,
ShortenInterfaceImplNames = false,
UseDynamicType = settings.Dynamic,
UseTupleTypes = settings.TupleTypes,
};
typeReferenceCecilLoader.SetCurrentModule(moduleDefinition);
IUnresolvedAssembly mainAssembly = cecilLoader.LoadModule(moduleDefinition);
// Load referenced assemblies and type-forwarder references.

88
ICSharpCode.Decompiler/TypeSystem/TupleType.cs

@ -41,31 +41,25 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -41,31 +41,25 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// <summary>
/// Gets the tuple elements.
/// </summary>
public ImmutableArray<IType> TupleElementTypes { get; }
public ImmutableArray<IType> ElementTypes { get; }
/// <summary>
/// Gets the names of the tuple elements.
/// </summary>
public ImmutableArray<string> TupleElementNames { get; }
public bool HasCustomElementNames { get; }
public TupleType(ICompilation compilation, ImmutableArray<IType> elementTypes)
{
this.Compilation = compilation;
this.UnderlyingType = CreateUnderlyingType(compilation, elementTypes);
this.TupleElementTypes = elementTypes;
this.TupleElementNames = Enumerable.Range(1, elementTypes.Length).Select(p => "Item" + p).ToImmutableArray();
this.HasCustomElementNames = false;
}
public TupleType(ICompilation compilation, ImmutableArray<IType> elementTypes, ImmutableArray<string> elementNames)
public ImmutableArray<string> ElementNames { get; }
public TupleType(ICompilation compilation, ImmutableArray<IType> elementTypes,
ImmutableArray<string> elementNames = default(ImmutableArray<string>))
{
this.Compilation = compilation;
this.UnderlyingType = CreateUnderlyingType(compilation, elementTypes);
this.TupleElementTypes = elementTypes;
this.TupleElementNames = elementNames;
this.HasCustomElementNames = true;
this.ElementTypes = elementTypes;
if (elementNames.IsDefault) {
this.ElementNames = Enumerable.Repeat<string>(null, elementTypes.Length).ToImmutableArray();
} else {
Debug.Assert(elementNames.Length == elementTypes.Length);
this.ElementNames = elementNames;
}
}
static ParameterizedType CreateUnderlyingType(ICompilation compilation, ImmutableArray<IType> elementTypes)
@ -94,7 +88,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -94,7 +88,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
{
switch (type.Kind) {
case TypeKind.Tuple:
tupleCardinality = ((TupleType)type).TupleElementNames.Length;
tupleCardinality = ((TupleType)type).ElementNames.Length;
return true;
case TypeKind.Class:
case TypeKind.Struct:
@ -120,7 +114,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -120,7 +114,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
{
switch (type.Kind) {
case TypeKind.Tuple:
output.AddRange(((TupleType)type).TupleElementTypes);
output.AddRange(((TupleType)type).ElementTypes);
return true;
case TypeKind.Class:
case TypeKind.Struct:
@ -158,16 +152,16 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -158,16 +152,16 @@ namespace ICSharpCode.Decompiler.TypeSystem
if (!UnderlyingType.Equals(o.UnderlyingType))
return false;
return UnderlyingType.Equals(o.UnderlyingType)
&& TupleElementNames.SequenceEqual(o.TupleElementNames);
&& ElementNames.SequenceEqual(o.ElementNames);
}
public override int GetHashCode()
{
unchecked {
int hash = UnderlyingType.GetHashCode();
foreach (string name in TupleElementNames) {
foreach (string name in ElementNames) {
hash *= 31;
hash += name.GetHashCode();
hash += name != null ? name.GetHashCode() : 0;
}
return hash;
}
@ -181,18 +175,18 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -181,18 +175,18 @@ namespace ICSharpCode.Decompiler.TypeSystem
public override IType VisitChildren(TypeVisitor visitor)
{
IType[] newElementTypes = null;
for (int i = 0; i < TupleElementTypes.Length; i++) {
IType type = TupleElementTypes[i];
for (int i = 0; i < ElementTypes.Length; i++) {
IType type = ElementTypes[i];
var newType = type.AcceptVisitor(visitor);
if (newType != type) {
if (newElementTypes == null) {
newElementTypes = TupleElementTypes.ToArray();
newElementTypes = ElementTypes.ToArray();
}
newElementTypes[i] = newType;
}
}
if (newElementTypes != null) {
return new TupleType(this.Compilation, newElementTypes.ToImmutableArray(), this.TupleElementNames);
return new TupleType(this.Compilation, newElementTypes.ToImmutableArray(), this.ElementNames);
} else {
return this;
}
@ -225,12 +219,12 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -225,12 +219,12 @@ namespace ICSharpCode.Decompiler.TypeSystem
foreach (var field in UnderlyingType.GetFields(filter, options)) {
yield return field;
}
for (int i = 0; i <= TupleElementTypes.Length; i++) {
var type = TupleElementTypes[i];
var name = TupleElementNames[i];
for (int i = 0; i < ElementTypes.Length; i++) {
var type = ElementTypes[i];
var name = ElementNames[i];
int pos = i + 1;
string itemName = "Item" + pos;
if (name != itemName)
if (name != itemName && name != null)
yield return MakeField(type, name);
if (pos >= RestPosition)
yield return MakeField(type, itemName);
@ -268,6 +262,38 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -268,6 +262,38 @@ namespace ICSharpCode.Decompiler.TypeSystem
}
}
public class TupleTypeReference : ITypeReference
{
/// <summary>
/// Gets the types of the tuple elements.
/// </summary>
public ImmutableArray<ITypeReference> ElementTypes { get; }
/// <summary>
/// Gets the names of the tuple elements.
/// </summary>
public ImmutableArray<string> ElementNames { get; }
public TupleTypeReference(ImmutableArray<ITypeReference> elementTypes)
{
this.ElementTypes = elementTypes;
}
public TupleTypeReference(ImmutableArray<ITypeReference> elementTypes, ImmutableArray<string> elementNames)
{
this.ElementTypes = elementTypes;
this.ElementNames = elementNames;
}
public IType Resolve(ITypeResolveContext context)
{
return new TupleType(context.Compilation,
ElementTypes.Select(t => t.Resolve(context)).ToImmutableArray(),
ElementNames
);
}
}
public static class TupleTypeExtensions
{
public static IType TupleUnderlyingTypeOrSelf(this IType type)

Loading…
Cancel
Save