Browse Source

Merge branch 'master' of https://github.com/icsharpcode/ILSpy into local-functions

pull/1586/head
Siegfried Pammer 6 years ago
parent
commit
ddcf2cea74
  1. 2
      DecompilerNuGetDemos.workbook
  2. 4
      ICSharpCode.Decompiler.Console/ICSharpCode.Decompiler.Console.csproj
  3. 2
      ICSharpCode.Decompiler.PowerShell/ICSharpCode.Decompiler.PowerShell.csproj
  4. 8
      ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
  5. 4
      ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
  6. 10
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/OptionalArguments.cs
  7. 1
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
  8. 4
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  9. 12
      ICSharpCode.Decompiler/CSharp/Transforms/ReplaceMethodCallsWithOperators.cs
  10. 1
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  11. 9
      ICSharpCode.Decompiler/IL/ILInstructionExtensions.cs
  12. 5
      ICSharpCode.Decompiler/IL/ILVariable.cs
  13. 31
      ICSharpCode.Decompiler/IL/Instructions/Block.cs
  14. 202
      ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs
  15. 5
      ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs
  16. 4
      ICSharpCode.Decompiler/IL/Transforms/RemoveDeadVariableInit.cs
  17. 7
      ICSharpCode.Decompiler/IL/Transforms/SwitchOnStringTransform.cs
  18. 4
      ICSharpCode.Decompiler/IL/Transforms/TransformCollectionAndObjectInitializers.cs
  19. 319
      ICSharpCode.Decompiler/IL/Transforms/TransformDisplayClassUsage.cs
  20. 18
      ICSharpCode.Decompiler/IL/Transforms/TransformExpressionTrees.cs
  21. 17
      ICSharpCode.Decompiler/Output/TextTokenWriter.cs
  22. 17
      ICSharpCode.Decompiler/SRMExtensions.cs
  23. 1
      ILSpy.AddIn/ILSpy.AddIn.csproj
  24. 2
      ILSpy.BamlDecompiler.Tests/ILSpy.BamlDecompiler.Tests.csproj
  25. 8
      ILSpy.BamlDecompiler.Tests/app.config
  26. 6
      ILSpy/Analyzers/AnalyzerScope.cs
  27. 2
      ILSpy/Properties/AssemblyInfo.template.cs
  28. 2
      ILSpy/TreeNodes/DerivedTypesEntryNode.cs
  29. 4
      README.md
  30. 13
      appveyor.yml

2
DecompilerNuGetDemos.workbook

@ -6,7 +6,7 @@ platforms: @@ -6,7 +6,7 @@ platforms:
- DotNetCore
packages:
- id: ICSharpCode.Decompiler
version: 5.0.0.4793-preview2
version: 5.0.0.4861-preview3
---
Setup: load the references required to work with the decompiler

4
ICSharpCode.Decompiler.Console/ICSharpCode.Decompiler.Console.csproj

@ -7,7 +7,7 @@ @@ -7,7 +7,7 @@
<PackAsTool>true</PackAsTool>
<AssemblyName>ilspycmd</AssemblyName>
<ToolCommandName>ilspycmd</ToolCommandName>
<Version>5.0.0-preview2</Version>
<Version>5.0.0-preview3</Version>
<Description>Command-line decompiler using the ILSpy decompilation engine</Description>
<Copyright>Copyright 2011-2019 AlphaSierraPapa</Copyright>
<PackageProjectUrl>https://github.com/icsharpcode/ILSpy/</PackageProjectUrl>
@ -28,7 +28,7 @@ @@ -28,7 +28,7 @@
<ItemGroup>
<PackageReference Include="McMaster.Extensions.CommandLineUtils" Version="2.3.2" />
<PackageReference Include="ICSharpCode.Decompiler" Version="5.0.0.4793-preview2" />
<PackageReference Include="ICSharpCode.Decompiler" Version="5.0.0.4861-preview3" />
<PackageReference Include="System.IO.FileSystem.Primitives" Version="4.3.0" />
<PackageReference Include="System.Runtime.Handles" Version="4.3.0" />

2
ICSharpCode.Decompiler.PowerShell/ICSharpCode.Decompiler.PowerShell.csproj

@ -8,7 +8,7 @@ @@ -8,7 +8,7 @@
<ItemGroup>
<PackageReference Include="PowerShellStandard.Library" Version="5.1.0" />
<PackageReference Include="ICSharpCode.Decompiler" Version="5.0.0.4793-preview2" />
<PackageReference Include="ICSharpCode.Decompiler" Version="5.0.0.4861-preview3" />
</ItemGroup>
</Project>

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

@ -42,13 +42,13 @@ @@ -42,13 +42,13 @@
<ItemGroup>
<PackageReference Include="DiffLib" Version="2017.7.26.1241" />
<PackageReference Include="Microsoft.Build.Locator" Version="1.2.2" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.0.0-beta4-final" />
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic" Version="3.0.0-beta4-final" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.2.0-beta3-final" />
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic" Version="3.2.0-beta3-final" />
<PackageReference Include="Microsoft.DiaSymReader.Converter.Xml" Version="1.1.0-beta1-63314-01" />
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
<PackageReference Include="System.Collections.Immutable" Version="1.5.0" />
<PackageReference Include="NUnit" Version="3.11.0" />
<PackageReference Include="System.Memory" Version="4.5.1" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="System.Memory" Version="4.5.3" />
</ItemGroup>
<ItemGroup>

4
ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs

@ -134,7 +134,7 @@ namespace ICSharpCode.Decompiler.Tests @@ -134,7 +134,7 @@ namespace ICSharpCode.Decompiler.Tests
}
[Test]
public void DelegateConstruction([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions)
public void DelegateConstruction([ValueSource(nameof(defaultOptionsWithMcs))] CompilerOptions cscOptions)
{
RunForLibrary(cscOptions: cscOptions);
}
@ -420,7 +420,7 @@ namespace ICSharpCode.Decompiler.Tests @@ -420,7 +420,7 @@ namespace ICSharpCode.Decompiler.Tests
}
[Test]
public void YieldReturn([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions)
public void YieldReturn([ValueSource(nameof(defaultOptionsWithMcs))] CompilerOptions cscOptions)
{
RunForLibrary(cscOptions: cscOptions);
}

10
ICSharpCode.Decompiler.Tests/TestCases/Pretty/OptionalArguments.cs

@ -97,6 +97,16 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -97,6 +97,16 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
};
}
private static string GetStr(int unused)
{
return " ";
}
public static string Issue1567(string str1, string str2)
{
return string.Concat(str1.Replace('"', '\''), str2: str2.Replace('"', '\''), str1: GetStr(42));
}
private void CallerMemberName([CallerMemberName] string memberName = null)
{

1
ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

@ -157,6 +157,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -157,6 +157,7 @@ namespace ICSharpCode.Decompiler.CSharp
new ProxyCallReplacer(),
new DelegateConstruction(),
new LocalFunctionDecompiler(),
new TransformDisplayClassUsage(),
new HighLevelLoopTransform(),
new ReduceNestingTransform(),
new IntroduceDynamicTypeOnLocals(),

4
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -1829,6 +1829,10 @@ namespace ICSharpCode.Decompiler.CSharp @@ -1829,6 +1829,10 @@ namespace ICSharpCode.Decompiler.CSharp
int i = 0;
foreach (var parameter in parameters) {
var pd = astBuilder.ConvertParameter(parameter);
if (string.IsNullOrEmpty(pd.Name) && !pd.Type.IsArgList()) {
// needs to be consistent with logic in ILReader.CreateILVarable(ParameterDefinition)
pd.Name = "P_" + i;
}
if (settings.AnonymousTypes && parameter.Type.ContainsAnonymousType())
pd.Type = null;
ILVariable v;

12
ICSharpCode.Decompiler/CSharp/Transforms/ReplaceMethodCallsWithOperators.cs

@ -154,8 +154,16 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -154,8 +154,16 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
if (arguments.Length < 2)
return false;
return arguments[0].GetResolveResult().Type.IsKnownType(KnownTypeCode.String) ||
arguments[1].GetResolveResult().Type.IsKnownType(KnownTypeCode.String);
bool valid = false;
foreach (var argument in arguments) {
if (argument is NamedArgumentExpression)
return false;
if (argument.GetResolveResult().Type.IsKnownType(KnownTypeCode.String))
valid = true;
}
return valid;
}
static BinaryOperatorType? GetBinaryOperatorTypeFromMetadataName(string name)

1
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -273,6 +273,7 @@ @@ -273,6 +273,7 @@
<Compile Include="IL\Transforms\DynamicIsEventAssignmentTransform.cs" />
<Compile Include="IL\Transforms\ReduceNestingTransform.cs" />
<Compile Include="IL\Transforms\LocalFunctionDecompiler.cs" />
<Compile Include="IL\Transforms\TransformDisplayClassUsage.cs" />
<Compile Include="IL\Transforms\UserDefinedLogicTransform.cs" />
<Compile Include="Metadata\AssemblyReferences.cs" />
<Compile Include="Metadata\CodeMappingInfo.cs" />

9
ICSharpCode.Decompiler/IL/ILInstructionExtensions.cs

@ -18,5 +18,14 @@ namespace ICSharpCode.Decompiler.IL @@ -18,5 +18,14 @@ namespace ICSharpCode.Decompiler.IL
target.AddILRange(range);
return target;
}
public static ILInstruction GetNextSibling(this ILInstruction instruction)
{
if (instruction?.Parent == null)
return null;
if (instruction.ChildIndex + 1 >= instruction.Parent.Children.Count)
return null;
return instruction.Parent.Children[instruction.ChildIndex + 1];
}
}
}

5
ICSharpCode.Decompiler/IL/ILVariable.cs

@ -74,6 +74,11 @@ namespace ICSharpCode.Decompiler.IL @@ -74,6 +74,11 @@ namespace ICSharpCode.Decompiler.IL
static class VariableKindExtensions
{
public static bool IsThis(this ILVariable v)
{
return v.Kind == VariableKind.Parameter && v.Index < 0;
}
public static bool IsLocal(this VariableKind kind)
{
switch (kind) {

31
ICSharpCode.Decompiler/IL/Instructions/Block.cs

@ -43,11 +43,11 @@ namespace ICSharpCode.Decompiler.IL @@ -43,11 +43,11 @@ namespace ICSharpCode.Decompiler.IL
{
public static readonly SlotInfo InstructionSlot = new SlotInfo("Instruction", isCollection: true);
public static readonly SlotInfo FinalInstructionSlot = new SlotInfo("FinalInstruction");
public readonly BlockKind Kind;
public readonly InstructionCollection<ILInstruction> Instructions;
ILInstruction finalInstruction;
/// <summary>
/// For blocks in a block container, this field holds
/// the number of incoming control flow edges to this block.
@ -77,21 +77,21 @@ namespace ICSharpCode.Decompiler.IL @@ -77,21 +77,21 @@ namespace ICSharpCode.Decompiler.IL
SetChildInstruction(ref finalInstruction, value, Instructions.Count);
}
}
protected internal override void InstructionCollectionUpdateComplete()
{
base.InstructionCollectionUpdateComplete();
if (finalInstruction.Parent == this)
finalInstruction.ChildIndex = Instructions.Count;
}
public Block(BlockKind kind = BlockKind.ControlFlow) : base(OpCode.Block)
{
this.Kind = kind;
this.Instructions = new InstructionCollection<ILInstruction>(this, 0);
this.FinalInstruction = new Nop();
}
public override ILInstruction Clone()
{
Block clone = new Block(Kind);
@ -100,7 +100,7 @@ namespace ICSharpCode.Decompiler.IL @@ -100,7 +100,7 @@ namespace ICSharpCode.Decompiler.IL
clone.FinalInstruction = this.FinalInstruction.Clone();
return clone;
}
internal override void CheckInvariant(ILPhase phase)
{
base.CheckInvariant(phase);
@ -133,18 +133,17 @@ namespace ICSharpCode.Decompiler.IL @@ -133,18 +133,17 @@ namespace ICSharpCode.Decompiler.IL
break;
}
}
public override StackType ResultType {
get {
return finalInstruction.ResultType;
}
}
/// <summary>
/// Gets the name of this block.
/// </summary>
public string Label
{
public string Label {
get { return Disassembler.DisassemblerHelpers.OffsetToString(this.StartILOffset); }
}
@ -179,19 +178,19 @@ namespace ICSharpCode.Decompiler.IL @@ -179,19 +178,19 @@ namespace ICSharpCode.Decompiler.IL
output.Write("}");
output.MarkFoldEnd();
}
protected override int GetChildCount()
{
return Instructions.Count + 1;
}
protected override ILInstruction GetChild(int index)
{
if (index == Instructions.Count)
return finalInstruction;
return Instructions[index];
}
protected override void SetChild(int index, ILInstruction value)
{
if (index == Instructions.Count)
@ -199,7 +198,7 @@ namespace ICSharpCode.Decompiler.IL @@ -199,7 +198,7 @@ namespace ICSharpCode.Decompiler.IL
else
Instructions[index] = value;
}
protected override SlotInfo GetChildSlot(int index)
{
if (index == Instructions.Count)
@ -207,7 +206,7 @@ namespace ICSharpCode.Decompiler.IL @@ -207,7 +206,7 @@ namespace ICSharpCode.Decompiler.IL
else
return InstructionSlot;
}
protected override InstructionFlags ComputeFlags()
{
var flags = InstructionFlags.None;
@ -217,7 +216,7 @@ namespace ICSharpCode.Decompiler.IL @@ -217,7 +216,7 @@ namespace ICSharpCode.Decompiler.IL
flags |= FinalInstruction.Flags;
return flags;
}
public override InstructionFlags DirectFlags {
get {
return InstructionFlags.None;

202
ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs

@ -16,9 +16,7 @@ @@ -16,9 +16,7 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection.Metadata;
using ICSharpCode.Decompiler.CSharp;
@ -37,9 +35,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -37,9 +35,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return;
this.context = context;
this.decompilationContext = new SimpleTypeResolveContext(function.Method);
var orphanedVariableInits = new List<ILInstruction>();
var targetsToReplace = new List<IInstructionWithVariableOperand>();
var translatedDisplayClasses = new HashSet<ITypeDefinition>();
var cancellationToken = context.CancellationToken;
foreach (var inst in function.Descendants) {
cancellationToken.ThrowIfCancellationRequested();
@ -50,49 +45,18 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -50,49 +45,18 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (instWithVar.Variable.Kind == VariableKind.Local) {
instWithVar.Variable.Kind = VariableKind.DisplayClassLocal;
}
targetsToReplace.Add(instWithVar);
var displayClassTypeDef = instWithVar.Variable.Type.GetDefinition();
if (instWithVar.Variable.IsSingleDefinition && instWithVar.Variable.StoreInstructions.SingleOrDefault() is StLoc store) {
if (store.Value is NewObj newObj) {
instWithVar.Variable.CaptureScope = BlockContainer.FindClosestContainer(store);
}
}
}
context.StepEndGroup();
}
if (inst.MatchStLoc(out ILVariable targetVariable, out ILInstruction value)) {
var newObj = value as NewObj;
// TODO : it is probably not a good idea to remove *all* display-classes
// is there a way to minimize the false-positives?
if (newObj != null && IsInSimpleDisplayClass(newObj.Method)) {
targetVariable.CaptureScope = BlockContainer.FindClosestContainer(inst);
targetsToReplace.Add((IInstructionWithVariableOperand)inst);
translatedDisplayClasses.Add(newObj.Method.DeclaringTypeDefinition);
}
}
}
foreach (var target in targetsToReplace.OrderByDescending(t => ((ILInstruction)t).StartILOffset)) {
context.Step($"TransformDisplayClassUsages {target.Variable}", (ILInstruction)target);
function.AcceptVisitor(new TransformDisplayClassUsages(function, target, target.Variable.CaptureScope, orphanedVariableInits, translatedDisplayClasses));
}
context.Step($"Remove orphanedVariableInits", function);
foreach (var store in orphanedVariableInits) {
if (store.Parent is Block containingBlock)
containingBlock.Instructions.Remove(store);
}
}
static bool IsInSimpleDisplayClass(IMethod method)
{
if (!method.IsCompilerGeneratedOrIsInCompilerGeneratedClass())
return false;
return IsSimpleDisplayClass(method.DeclaringType);
}
internal static bool IsSimpleDisplayClass(IType type)
{
if (!type.HasGeneratedName() || (!type.Name.Contains("DisplayClass") && !type.Name.Contains("AnonStorey")))
return false;
if (type.DirectBaseTypes.Any(t => !t.IsKnownType(KnownTypeCode.Object)))
return false;
return true;
}
#region TransformDelegateConstruction
internal static bool IsDelegateConstruction(NewObj inst, bool allowTransformed = false)
{
if (inst == null || inst.Arguments.Count != 2 || inst.Method.DeclaringType.Kind != TypeKind.Delegate)
@ -101,12 +65,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -101,12 +65,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return opCode == OpCode.LdFtn || opCode == OpCode.LdVirtFtn || (allowTransformed && opCode == OpCode.ILFunction);
}
internal static bool IsPotentialClosure(ILTransformContext context, NewObj inst)
{
var decompilationContext = new SimpleTypeResolveContext(context.Function.Method);
return IsPotentialClosure(decompilationContext.CurrentTypeDefinition, inst.Method.DeclaringTypeDefinition);
}
static bool IsAnonymousMethod(ITypeDefinition decompiledTypeDefinition, IMethod method)
{
@ -115,7 +73,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -115,7 +73,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (!(method.HasGeneratedName()
|| method.Name.Contains("$")
|| method.IsCompilerGeneratedOrIsInCompilerGeneratedClass()
|| IsPotentialClosure(decompiledTypeDefinition, method.DeclaringTypeDefinition)
|| TransformDisplayClassUsage.IsPotentialClosure(decompiledTypeDefinition, method.DeclaringTypeDefinition)
|| ContainsAnonymousType(method)))
return false;
return true;
@ -131,18 +89,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -131,18 +89,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
return false;
}
static bool IsPotentialClosure(ITypeDefinition decompiledTypeDefinition, ITypeDefinition potentialDisplayClass)
{
if (potentialDisplayClass == null || !potentialDisplayClass.IsCompilerGeneratedOrIsInCompilerGeneratedClass())
return false;
while (potentialDisplayClass != decompiledTypeDefinition) {
potentialDisplayClass = potentialDisplayClass.DeclaringTypeDefinition;
if (potentialDisplayClass == null)
return false;
}
return true;
}
internal static GenericContext? GenericContextFromTypeArguments(TypeParameterSubstitution subst)
{
@ -259,139 +205,5 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -259,139 +205,5 @@ namespace ICSharpCode.Decompiler.IL.Transforms
base.VisitLdObj(inst);
}
}
/// <summary>
/// 1. Stores to display class fields are replaced with stores to local variables (in some
/// cases existing variables are used; otherwise fresh variables are added to the
/// ILFunction-container) and all usages of those fields are replaced with the local variable.
/// (see initValues)
/// 2. Usages of the display class container (or any copy) are removed.
/// </summary>
class TransformDisplayClassUsages : ILVisitor
{
ILFunction currentFunction;
BlockContainer captureScope;
readonly IInstructionWithVariableOperand targetLoad;
readonly List<ILVariable> targetAndCopies = new List<ILVariable>();
readonly List<ILInstruction> orphanedVariableInits;
readonly HashSet<ITypeDefinition> translatedDisplayClasses;
readonly Dictionary<IField, DisplayClassVariable> initValues = new Dictionary<IField, DisplayClassVariable>();
struct DisplayClassVariable
{
public ILVariable variable;
public ILInstruction value;
}
public TransformDisplayClassUsages(ILFunction function, IInstructionWithVariableOperand targetLoad, BlockContainer captureScope, List<ILInstruction> orphanedVariableInits, HashSet<ITypeDefinition> translatedDisplayClasses)
{
this.currentFunction = function;
this.targetLoad = targetLoad;
this.captureScope = captureScope;
this.orphanedVariableInits = orphanedVariableInits;
this.translatedDisplayClasses = translatedDisplayClasses;
this.targetAndCopies.Add(targetLoad.Variable);
}
protected override void Default(ILInstruction inst)
{
foreach (var child in inst.Children) {
child.AcceptVisitor(this);
}
}
protected internal override void VisitStLoc(StLoc inst)
{
base.VisitStLoc(inst);
if (targetLoad is ILInstruction instruction && instruction.MatchLdThis())
return;
if (inst.Variable == targetLoad.Variable)
orphanedVariableInits.Add(inst);
if (MatchesTargetOrCopyLoad(inst.Value)) {
targetAndCopies.Add(inst.Variable);
orphanedVariableInits.Add(inst);
}
}
bool MatchesTargetOrCopyLoad(ILInstruction inst)
{
return targetAndCopies.Any(v => inst.MatchLdLoc(v));
}
protected internal override void VisitStObj(StObj inst)
{
base.VisitStObj(inst);
if (!inst.Target.MatchLdFlda(out ILInstruction target, out IField field) || !MatchesTargetOrCopyLoad(target) || target.MatchLdThis())
return;
field = (IField)field.MemberDefinition;
ILInstruction value;
if (initValues.TryGetValue(field, out DisplayClassVariable info)) {
inst.ReplaceWith(new StLoc(info.variable, inst.Value).WithILRange(inst));
} else {
if (inst.Value.MatchLdLoc(out var v) && v.Kind == VariableKind.Parameter && currentFunction == v.Function) {
// special case for parameters: remove copies of parameter values.
orphanedVariableInits.Add(inst);
value = inst.Value;
} else {
if (!translatedDisplayClasses.Contains(field.DeclaringTypeDefinition))
return;
v = currentFunction.RegisterVariable(VariableKind.Local, field.Type, field.Name);
v.CaptureScope = captureScope;
inst.ReplaceWith(new StLoc(v, inst.Value).WithILRange(inst));
value = new LdLoc(v);
}
initValues.Add(field, new DisplayClassVariable { value = value, variable = v });
}
}
protected internal override void VisitLdObj(LdObj inst)
{
base.VisitLdObj(inst);
if (!inst.Target.MatchLdFlda(out ILInstruction target, out IField field))
return;
if (!initValues.TryGetValue((IField)field.MemberDefinition, out DisplayClassVariable info))
return;
var replacement = info.value.Clone();
replacement.SetILRange(inst);
inst.ReplaceWith(replacement);
}
protected internal override void VisitLdFlda(LdFlda inst)
{
base.VisitLdFlda(inst);
if (inst.Target.MatchLdThis() && inst.Field.Name == "$this"
&& inst.Field.MemberDefinition.ReflectionName.Contains("c__Iterator")) {
var variable = currentFunction.Variables.First((f) => f.Index == -1);
inst.ReplaceWith(new LdLoca(variable).WithILRange(inst));
}
if (inst.Parent is LdObj || inst.Parent is StObj)
return;
if (!MatchesTargetOrCopyLoad(inst.Target))
return;
var field = (IField)inst.Field.MemberDefinition;
if (!initValues.TryGetValue(field, out DisplayClassVariable info)) {
if (!translatedDisplayClasses.Contains(field.DeclaringTypeDefinition))
return;
var v = currentFunction.RegisterVariable(VariableKind.Local, field.Type, field.Name);
v.CaptureScope = captureScope;
inst.ReplaceWith(new LdLoca(v).WithILRange(inst));
var value = new LdLoc(v);
initValues.Add(field, new DisplayClassVariable { value = value, variable = v });
} else if (info.value is LdLoc l) {
inst.ReplaceWith(new LdLoca(l.Variable).WithILRange(inst));
} else {
Debug.Fail("LdFlda pattern not supported!");
}
}
protected internal override void VisitNumericCompoundAssign(NumericCompoundAssign inst)
{
base.VisitNumericCompoundAssign(inst);
if (inst.Target.MatchLdLoc(out var v)) {
inst.ReplaceWith(new StLoc(v, new BinaryNumericInstruction(inst.Operator, inst.Target, inst.Value, inst.CheckForOverflow, inst.Sign).WithILRange(inst)));
}
}
}
#endregion
}
}

5
ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs

@ -271,6 +271,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -271,6 +271,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
Block block;
if (TransformSpanTCtorContainingStackAlloc(inst, out ILInstruction locallocSpan)) {
context.Step("new Span<T>(stackalloc) -> stackalloc Span<T>", inst);
inst.ReplaceWith(locallocSpan);
block = null;
ILInstruction stmt = locallocSpan;
@ -281,7 +282,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -281,7 +282,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
stmt = stmt.Parent;
}
//ILInlining.InlineIfPossible(block, stmt.ChildIndex - 1, context);
// Special case to eliminate extra store
if (stmt.GetNextSibling() is StLoc storeStmt && storeStmt.Value is LdLoc)
ILInlining.InlineIfPossible(block, stmt.ChildIndex, context);
return;
}
if (TransformArrayInitializers.TransformSpanTArrayInitialization(inst, context, out block)) {

4
ICSharpCode.Decompiler/IL/Transforms/RemoveDeadVariableInit.cs

@ -53,6 +53,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -53,6 +53,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms
var v = variableQueue.Dequeue();
if (v.Kind != VariableKind.Local && v.Kind != VariableKind.StackSlot)
continue;
// Skip variables that are captured in a mcs yield state-machine
// loads of these will only be visible after DelegateConstruction step.
if (function.StateMachineCompiledWithMono && v.StateMachineField != null)
continue;
if (v.LoadCount != 0 || v.AddressCount != 0)
continue;
foreach (var stloc in v.StoreInstructions.OfType<StLoc>().ToArray()) {

7
ICSharpCode.Decompiler/IL/Transforms/SwitchOnStringTransform.cs

@ -409,11 +409,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -409,11 +409,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (!switchValueVar.Type.IsKnownType(KnownTypeCode.String))
return false;
// either br nullCase or leave container
var leaveContainer = BlockContainer.FindClosestContainer(instructions[i]);
if (leaveContainer.Parent is TryInstruction) {
leaveContainer = BlockContainer.FindClosestContainer(leaveContainer.Parent);
}
if (!exitBlockJump.MatchBranch(out var nullValueCaseBlock) && !exitBlockJump.MatchLeave(leaveContainer))
BlockContainer leaveContainer = null;
if (!exitBlockJump.MatchBranch(out var nullValueCaseBlock) && !exitBlockJump.MatchLeave(out leaveContainer))
return false;
var nextBlockJump = instructions.ElementAtOrDefault(i + 1) as Branch;
if (nextBlockJump == null || nextBlockJump.TargetBlock.IncomingEdgeCount != 1)

4
ICSharpCode.Decompiler/IL/Transforms/TransformCollectionAndObjectInitializers.cs

@ -62,9 +62,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -62,9 +62,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
// Do not try to transform display class usages or delegate construction.
// DelegateConstruction transform cannot deal with this.
if (DelegateConstruction.IsSimpleDisplayClass(newObjInst.Method.DeclaringType))
if (TransformDisplayClassUsage.IsSimpleDisplayClass(newObjInst.Method.DeclaringType))
return false;
if (DelegateConstruction.IsDelegateConstruction(newObjInst) || DelegateConstruction.IsPotentialClosure(context, newObjInst))
if (DelegateConstruction.IsDelegateConstruction(newObjInst) || TransformDisplayClassUsage.IsPotentialClosure(context, newObjInst))
return false;
// Cannot build a collection/object initializer attached to an AnonymousTypeCreateExpression:s
// anon = new { A = 5 } { 3,4,5 } is invalid syntax.

319
ICSharpCode.Decompiler/IL/Transforms/TransformDisplayClassUsage.cs

@ -0,0 +1,319 @@ @@ -0,0 +1,319 @@
// Copyright (c) 2019 Siegfried Pammer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.Decompiler.IL.Transforms
{
/// <summary>
/// Transforms closure fields to local variables.
///
/// This is a post-processing step of <see cref="DelegateConstruction"/> and <see cref="TransformExpressionTrees"/>.
/// </summary>
class TransformDisplayClassUsage : ILVisitor, IILTransform
{
class DisplayClass
{
public bool IsMono;
public ILInstruction Initializer;
public ILVariable Variable;
public ITypeDefinition Definition;
public Dictionary<IField, DisplayClassVariable> Variables;
public BlockContainer CaptureScope;
}
struct DisplayClassVariable
{
public ILVariable Variable;
public ILInstruction Value;
}
ILTransformContext context;
ILFunction currentFunction;
readonly Dictionary<ILVariable, DisplayClass> displayClasses = new Dictionary<ILVariable, DisplayClass>();
readonly List<ILInstruction> instructionsToRemove = new List<ILInstruction>();
public void Run(ILFunction function, ILTransformContext context)
{
try {
if (this.context != null || this.currentFunction != null)
throw new InvalidOperationException("Reentrancy in " + nameof(TransformDisplayClassUsage));
this.context = context;
var decompilationContext = new SimpleTypeResolveContext(context.Function.Method);
// Traverse nested functions in post-order:
// Inner functions are transformed before outer functions
foreach (var f in function.Descendants.OfType<ILFunction>()) {
foreach (var v in f.Variables.ToArray()) {
if (HandleMonoStateMachine(function, v, decompilationContext, f))
continue;
if (!(v.IsSingleDefinition && v.StoreInstructions.SingleOrDefault() is StLoc inst))
continue;
if (IsClosureInit(inst, out ITypeDefinition closureType)) {
// TODO : figure out whether it is a mono compiled closure, without relying on the type name
bool isMono = f.StateMachineCompiledWithMono || closureType.Name.Contains("AnonStorey");
displayClasses.Add(inst.Variable, new DisplayClass {
IsMono = isMono,
Initializer = inst,
Variable = v,
Definition = closureType,
Variables = new Dictionary<IField, DisplayClassVariable>(),
CaptureScope = isMono && IsMonoNestedCaptureScope(closureType) ? null : inst.Variable.CaptureScope
});
instructionsToRemove.Add(inst);
}
}
foreach (var displayClass in displayClasses.Values.OrderByDescending(d => d.Initializer.StartILOffset).ToArray()) {
context.Step($"Transform references to " + displayClass.Variable, displayClass.Initializer);
this.currentFunction = f;
VisitILFunction(f);
}
}
context.Step($"Remove instructions", function);
foreach (var store in instructionsToRemove) {
if (store.Parent is Block containingBlock)
containingBlock.Instructions.Remove(store);
}
} finally {
instructionsToRemove.Clear();
displayClasses.Clear();
this.context = null;
this.currentFunction = null;
}
}
bool IsOuterClosureReference(IField field)
{
return displayClasses.Values.Any(disp => disp.Definition == field.DeclaringTypeDefinition);
}
bool IsMonoNestedCaptureScope(ITypeDefinition closureType)
{
var decompilationContext = new SimpleTypeResolveContext(context.Function.Method);
return closureType.Fields.Any(f => IsPotentialClosure(decompilationContext.CurrentTypeDefinition, f.ReturnType.GetDefinition()));
}
/// <summary>
/// mcs likes to optimize closures in yield state machines away by moving the captured variables' fields into the state machine type,
/// We construct a <see cref="DisplayClass"/> that spans the whole method body.
/// </summary>
bool HandleMonoStateMachine(ILFunction currentFunction, ILVariable thisVariable, SimpleTypeResolveContext decompilationContext, ILFunction nestedFunction)
{
if (!(nestedFunction.StateMachineCompiledWithMono && thisVariable.IsThis()))
return false;
// Special case for Mono-compiled yield state machines
ITypeDefinition closureType = thisVariable.Type.GetDefinition();
if (!(closureType != decompilationContext.CurrentTypeDefinition
&& IsPotentialClosure(decompilationContext.CurrentTypeDefinition, closureType)))
return false;
var displayClass = new DisplayClass {
IsMono = true,
Initializer = nestedFunction.Body,
Variable = thisVariable,
Definition = thisVariable.Type.GetDefinition(),
Variables = new Dictionary<IField, DisplayClassVariable>(),
CaptureScope = (BlockContainer)nestedFunction.Body
};
displayClasses.Add(thisVariable, displayClass);
foreach (var stateMachineVariable in nestedFunction.Variables) {
if (stateMachineVariable.StateMachineField == null)
continue;
displayClass.Variables.Add(stateMachineVariable.StateMachineField, new DisplayClassVariable {
Variable = stateMachineVariable,
Value = new LdLoc(stateMachineVariable)
});
}
if (!currentFunction.Method.IsStatic && FindThisField(out var thisField)) {
var thisVar = currentFunction.Variables
.FirstOrDefault(t => t.IsThis() && t.Type.GetDefinition() == decompilationContext.CurrentTypeDefinition);
if (thisVar == null) {
thisVar = new ILVariable(VariableKind.Parameter, decompilationContext.CurrentTypeDefinition, -1) { Name = "this" };
currentFunction.Variables.Add(thisVar);
}
displayClass.Variables.Add(thisField, new DisplayClassVariable { Variable = thisVar, Value = new LdLoc(thisVar) });
}
return true;
bool FindThisField(out IField foundField)
{
foundField = null;
foreach (var field in closureType.GetFields(f2 => !f2.IsStatic && !displayClass.Variables.ContainsKey(f2) && f2.Type.GetDefinition() == decompilationContext.CurrentTypeDefinition)) {
thisField = field;
return true;
}
return false;
}
}
internal static bool IsSimpleDisplayClass(IType type)
{
if (!type.HasGeneratedName() || (!type.Name.Contains("DisplayClass") && !type.Name.Contains("AnonStorey")))
return false;
if (type.DirectBaseTypes.Any(t => !t.IsKnownType(KnownTypeCode.Object)))
return false;
return true;
}
internal static bool IsPotentialClosure(ILTransformContext context, NewObj inst)
{
var decompilationContext = new SimpleTypeResolveContext(context.Function.Ancestors.OfType<ILFunction>().Last().Method);
return IsPotentialClosure(decompilationContext.CurrentTypeDefinition, inst.Method.DeclaringTypeDefinition);
}
internal static bool IsPotentialClosure(ITypeDefinition decompiledTypeDefinition, ITypeDefinition potentialDisplayClass)
{
if (potentialDisplayClass == null || !potentialDisplayClass.IsCompilerGeneratedOrIsInCompilerGeneratedClass())
return false;
while (potentialDisplayClass != decompiledTypeDefinition) {
potentialDisplayClass = potentialDisplayClass.DeclaringTypeDefinition;
if (potentialDisplayClass == null)
return false;
}
return true;
}
protected override void Default(ILInstruction inst)
{
foreach (var child in inst.Children) {
child.AcceptVisitor(this);
}
}
protected internal override void VisitStLoc(StLoc inst)
{
base.VisitStLoc(inst);
// Sometimes display class references are copied into other local variables.
// We remove the assignment and store the relationship between the display class and the variable in the
// displayClasses dictionary.
if (inst.Value.MatchLdLoc(out var closureVariable) && displayClasses.TryGetValue(closureVariable, out var displayClass)) {
displayClasses[inst.Variable] = displayClass;
instructionsToRemove.Add(inst);
}
}
bool IsClosureInit(StLoc inst, out ITypeDefinition closureType)
{
closureType = null;
if (!(inst.Value is NewObj newObj))
return false;
closureType = newObj.Method.DeclaringTypeDefinition;
return closureType != null && IsPotentialClosure(this.context, newObj);
}
protected internal override void VisitStObj(StObj inst)
{
base.VisitStObj(inst);
// This instruction has been marked deletable, do not transform it further
if (instructionsToRemove.Contains(inst))
return;
// The target of the store instruction must be a field reference
if (!inst.Target.MatchLdFlda(out ILInstruction target, out IField field))
return;
// Get display class info
if (!(target is LdLoc displayClassLoad && displayClasses.TryGetValue(displayClassLoad.Variable, out var displayClass)))
return;
field = (IField)field.MemberDefinition;
if (displayClass.Variables.TryGetValue(field, out DisplayClassVariable info)) {
// If the display class field was previously initialized, we use a simple assignment.
inst.ReplaceWith(new StLoc(info.Variable, inst.Value).WithILRange(inst));
} else {
// This is an uninitialized variable:
ILInstruction value;
if (inst.Value.MatchLdLoc(out var v) && v.Kind == VariableKind.Parameter && currentFunction == v.Function) {
// Special case for parameters: remove copies of parameter values.
instructionsToRemove.Add(inst);
value = inst.Value;
} else {
Debug.Assert(displayClass.Definition == field.DeclaringTypeDefinition);
// Introduce a fresh variable for the display class field.
v = currentFunction.RegisterVariable(VariableKind.Local, field.Type, field.Name);
if (displayClass.IsMono && displayClass.CaptureScope == null && !IsOuterClosureReference(field)) {
displayClass.CaptureScope = BlockContainer.FindClosestContainer(inst);
}
v.CaptureScope = displayClass.CaptureScope;
inst.ReplaceWith(new StLoc(v, inst.Value).WithILRange(inst));
value = new LdLoc(v);
}
displayClass.Variables.Add(field, new DisplayClassVariable { Value = value, Variable = v });
}
}
protected internal override void VisitLdObj(LdObj inst)
{
base.VisitLdObj(inst);
// The target of the store instruction must be a field reference
if (!inst.Target.MatchLdFlda(out var target, out IField field))
return;
// Get display class info
if (!(target is LdLoc displayClassLoad && displayClasses.TryGetValue(displayClassLoad.Variable, out var displayClass)))
return;
// Get display class variable info
if (!displayClass.Variables.TryGetValue((IField)field.MemberDefinition, out DisplayClassVariable info))
return;
// Replace usage of display class field with the variable.
var replacement = info.Value.Clone();
replacement.SetILRange(inst);
inst.ReplaceWith(replacement);
}
protected internal override void VisitLdFlda(LdFlda inst)
{
base.VisitLdFlda(inst);
// TODO : Figure out why this was added in https://github.com/icsharpcode/ILSpy/pull/1303
if (inst.Target.MatchLdThis() && inst.Field.Name == "$this"
&& inst.Field.MemberDefinition.ReflectionName.Contains("c__Iterator")) {
//Debug.Assert(false, "This should not be executed!");
var variable = currentFunction.Variables.First((f) => f.Index == -1);
inst.ReplaceWith(new LdLoca(variable).WithILRange(inst));
}
// Skip stfld/ldfld
if (inst.Parent is LdObj || inst.Parent is StObj)
return;
// Get display class info
if (!(inst.Target is LdLoc displayClassLoad && displayClasses.TryGetValue(displayClassLoad.Variable, out var displayClass)))
return;
var field = (IField)inst.Field.MemberDefinition;
if (!displayClass.Variables.TryGetValue(field, out DisplayClassVariable info)) {
// Introduce a fresh variable for the display class field.
Debug.Assert(displayClass.Definition == field.DeclaringTypeDefinition);
var v = currentFunction.RegisterVariable(VariableKind.Local, field.Type, field.Name);
v.CaptureScope = displayClass.CaptureScope;
inst.ReplaceWith(new LdLoca(v).WithILRange(inst));
displayClass.Variables.Add(field, new DisplayClassVariable { Value = new LdLoc(v), Variable = v });
} else if (info.Value is LdLoc l) {
inst.ReplaceWith(new LdLoca(l.Variable).WithILRange(inst));
} else {
Debug.Fail("LdFlda pattern not supported!");
}
}
protected internal override void VisitNumericCompoundAssign(NumericCompoundAssign inst)
{
base.VisitNumericCompoundAssign(inst);
// NumericCompoundAssign is only valid when used with fields: -> replace it with a BinaryNumericInstruction.
if (inst.Target.MatchLdLoc(out var v)) {
inst.ReplaceWith(new StLoc(v, new BinaryNumericInstruction(inst.Operator, inst.Target, inst.Value, inst.CheckForOverflow, inst.Sign).WithILRange(inst)));
}
}
}
}

18
ICSharpCode.Decompiler/IL/Transforms/TransformExpressionTrees.cs

@ -21,7 +21,6 @@ using System.Collections.Generic; @@ -21,7 +21,6 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using ICSharpCode.Decompiler.CSharp.Resolver;
using ICSharpCode.Decompiler.CSharp.Syntax;
using ICSharpCode.Decompiler.Semantics;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.TypeSystem.Implementation;
@ -1076,6 +1075,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -1076,6 +1075,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms
&& v.StackType.IsIntegerType())
return new LdLoca(v);
return null;
} else if (IsClosureReference(ldloc.Variable)) {
if (ldloc.Variable.Kind == VariableKind.Local) {
ldloc.Variable.Kind = VariableKind.DisplayClassLocal;
}
if (ldloc.Variable.CaptureScope == null) {
ldloc.Variable.CaptureScope = BlockContainer.FindClosestContainer(context);
}
return ldloc;
} else {
return ldloc;
}
@ -1084,6 +1091,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -1084,6 +1091,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
}
bool IsClosureReference(ILVariable variable)
{
if (!variable.IsSingleDefinition || !(variable.StoreInstructions.SingleOrDefault() is StLoc store))
return false;
if (!(store.Value is NewObj newObj))
return false;
return TransformDisplayClassUsage.IsPotentialClosure(this.context, newObj);
}
bool IsExpressionTreeParameter(ILVariable variable)
{
return variable.Type.FullName == "System.Linq.Expressions.ParameterExpression";

17
ICSharpCode.Decompiler/Output/TextTokenWriter.cs

@ -90,7 +90,7 @@ namespace ICSharpCode.Decompiler @@ -90,7 +90,7 @@ namespace ICSharpCode.Decompiler
return;
}
if (firstUsingDeclaration) {
if (firstUsingDeclaration && !lastUsingDeclaration) {
output.MarkFoldStart(defaultCollapsed: !settings.ExpandUsingDeclarations);
firstUsingDeclaration = false;
}
@ -264,11 +264,10 @@ namespace ICSharpCode.Decompiler @@ -264,11 +264,10 @@ namespace ICSharpCode.Decompiler
public override void NewLine()
{
if (lastUsingDeclaration) {
if (!firstUsingDeclaration && lastUsingDeclaration) {
output.MarkFoldEnd();
lastUsingDeclaration = false;
}
// lastEndOfLine = output.Location;
output.WriteLine();
}
@ -366,9 +365,6 @@ namespace ICSharpCode.Decompiler @@ -366,9 +365,6 @@ namespace ICSharpCode.Decompiler
}
}
// Stack<TextLocation> startLocations = new Stack<TextLocation>();
// Stack<MethodDebugSymbols> symbolsStack = new Stack<MethodDebugSymbols>();
public override void StartNode(AstNode node)
{
if (nodeStack.Count == 0) {
@ -381,15 +377,6 @@ namespace ICSharpCode.Decompiler @@ -381,15 +377,6 @@ namespace ICSharpCode.Decompiler
}
}
nodeStack.Push(node);
// startLocations.Push(output.Location);
// if (node is EntityDeclaration && node.GetSymbol() != null && node.GetChildByRole(Roles.Identifier).IsNull)
// output.WriteDefinition("", node.GetSymbol(), false);
// if (node.Annotation<MethodDebugSymbols>() != null) {
// symbolsStack.Push(node.Annotation<MethodDebugSymbols>());
// symbolsStack.Peek().StartLocation = startLocations.Peek();
// }
}
private bool IsUsingDeclaration(AstNode node)

17
ICSharpCode.Decompiler/SRMExtensions.cs

@ -69,12 +69,17 @@ namespace ICSharpCode.Decompiler @@ -69,12 +69,17 @@ namespace ICSharpCode.Decompiler
return false;
if (!baseType.IsKnownType(reader, KnownTypeCode.Enum))
return false;
var field = reader.GetFieldDefinition(typeDefinition.GetFields().First());
var blob = reader.GetBlobReader(field.Signature);
if (blob.ReadSignatureHeader().Kind != SignatureKind.Field)
return false;
underlyingType = (PrimitiveTypeCode)blob.ReadByte();
return true;
foreach (var handle in typeDefinition.GetFields()) {
var field = reader.GetFieldDefinition(handle);
if ((field.Attributes & FieldAttributes.Static) != 0)
continue;
var blob = reader.GetBlobReader(field.Signature);
if (blob.ReadSignatureHeader().Kind != SignatureKind.Field)
return false;
underlyingType = (PrimitiveTypeCode)blob.ReadByte();
return true;
}
return false;
}
public static bool IsDelegate(this TypeDefinitionHandle handle, MetadataReader reader)

1
ILSpy.AddIn/ILSpy.AddIn.csproj

@ -131,6 +131,7 @@ @@ -131,6 +131,7 @@
<AdditionalDependencies Include="$(ILSpyBuildPath)ILSpy.BamlDecompiler.Plugin.dll" />
<AdditionalDependencies Include="$(ILSpyBuildPath)System.*.dll" />
<AdditionalDependencies Include="$(ILSpyBuildPath)Microsoft.DiaSymReader.*.dll" />
<AdditionalDependencies Include="$(ILSpyBuildPath)OSVersionHelper.dll" />
</ItemGroup>
<ItemGroup>

2
ILSpy.BamlDecompiler.Tests/ILSpy.BamlDecompiler.Tests.csproj

@ -31,7 +31,7 @@ @@ -31,7 +31,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="NUnit" Version="3.11.0" />
<PackageReference Include="NUnit" Version="3.12.0" />
</ItemGroup>
<ItemGroup>

8
ILSpy.BamlDecompiler.Tests/app.config

@ -7,8 +7,14 @@ @@ -7,8 +7,14 @@
<bindingRedirect oldVersion="0.0.0.0-1.2.1.0" newVersion="1.2.1.0"/>
</dependentAssembly>
</assemblyBinding>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.1.1" newVersion="4.0.1.1"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1"/>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2"/>
</startup>
</configuration>

6
ILSpy/Analyzers/AnalyzerScope.cs

@ -130,6 +130,10 @@ namespace ICSharpCode.ILSpy.Analyzers @@ -130,6 +130,10 @@ namespace ICSharpCode.ILSpy.Analyzers
{
yield return self;
string reflectionTypeScopeName = typeScope.Name;
if (typeScope.TypeParameterCount > 0)
reflectionTypeScopeName += "`" + typeScope.TypeParameterCount;
foreach (var assembly in AssemblyList.GetAssemblies()) {
ct.ThrowIfCancellationRequested();
bool found = false;
@ -145,7 +149,7 @@ namespace ICSharpCode.ILSpy.Analyzers @@ -145,7 +149,7 @@ namespace ICSharpCode.ILSpy.Analyzers
}
}
}
if (found && ModuleReferencesScopeType(module.Metadata, typeScope.Name, typeScope.Namespace))
if (found && ModuleReferencesScopeType(module.Metadata, reflectionTypeScopeName, typeScope.Namespace))
yield return module;
}
}

2
ILSpy/Properties/AssemblyInfo.template.cs

@ -39,7 +39,7 @@ internal static class RevisionClass @@ -39,7 +39,7 @@ internal static class RevisionClass
public const string Minor = "0";
public const string Build = "0";
public const string Revision = "$INSERTREVISION$";
public const string VersionName = "preview2";
public const string VersionName = "preview3";
public const string FullVersion = Major + "." + Minor + "." + Build + ".$INSERTREVISION$$INSERTBRANCHPOSTFIX$$INSERTVERSIONNAMEPOSTFIX$";
}

2
ILSpy/TreeNodes/DerivedTypesEntryNode.cs

@ -42,7 +42,7 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -42,7 +42,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
public override object Text
{
get { return type.FullName + type.MetadataToken.ToSuffixString(); }
get { return Language.TypeToString(type, includeNamespace: true) + type.MetadataToken.ToSuffixString(); }
}
public override object Icon => TypeTreeNode.GetIcon(type);

4
README.md

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
# ILSpy [![Join the chat at https://gitter.im/icsharpcode/ILSpy](https://badges.gitter.im/icsharpcode/ILSpy.svg)](https://gitter.im/icsharpcode/ILSpy?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![NuGet](https://img.shields.io/nuget/v/ICSharpCode.Decompiler.svg)](https://nuget.org/packages/ICSharpCode.Decompiler) [![Build status](https://ci.appveyor.com/api/projects/status/imgec05g0wwv25ij/branch/master?svg=true)](https://ci.appveyor.com/project/icsharpcode/ilspy/branch/master) [![Twitter Follow](https://img.shields.io/twitter/follow/ILSpy.svg?label=Follow%20@ILSpy)](https://twitter.com/ilspy) [![ilspy.net](https://img.shields.io/badge/@-ilspy.net-blue.svg)](http://www.ilspy.net) [![ILSpy VS extension](https://img.shields.io/badge/VS%20Extension-ILSpy-blue.svg)](https://visualstudiogallery.msdn.microsoft.com/8ef1d688-f80c-4380-8004-2ec7f814e7de)
# ILSpy [![Join the chat at https://gitter.im/icsharpcode/ILSpy](https://badges.gitter.im/icsharpcode/ILSpy.svg)](https://gitter.im/icsharpcode/ILSpy?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![NuGet](https://img.shields.io/nuget/v/ICSharpCode.Decompiler.svg)](https://nuget.org/packages/ICSharpCode.Decompiler) [![Build status](https://ci.appveyor.com/api/projects/status/imgec05g0wwv25ij/branch/master?svg=true)](https://ci.appveyor.com/project/icsharpcode/ilspy/branch/master) [![Twitter Follow](https://img.shields.io/twitter/follow/ILSpy.svg?label=Follow%20@ILSpy)](https://twitter.com/ilspy) [![ILSpy VS extension](https://img.shields.io/badge/VS%20Extension-ILSpy-blue.svg)](https://visualstudiogallery.msdn.microsoft.com/8ef1d688-f80c-4380-8004-2ec7f814e7de) [![Build Status](https://icsharpcode.visualstudio.com/icsharpcode-pipelines/_apis/build/status/icsharpcode.ILSpy?branchName=master)](https://icsharpcode.visualstudio.com/icsharpcode-pipelines/_build/latest?definitionId=1&branchName=master)
ILSpy is the open-source .NET assembly browser and decompiler.
@ -54,6 +54,7 @@ Windows: @@ -54,6 +54,7 @@ Windows:
- Individual Component "VC++ 2017 version 15.9 v14.16 latest v141 tools" (or similar)
- The VC++ toolset is optional; if present it is used for `editbin.exe` to modify the stack size used by ILSpy.exe from 1MB to 16MB, because the decompiler makes heavy use of recursion, where small stack sizes lead to problems in very complex methods.
- Install the [.NET Core SDK 2.2](https://dotnet.microsoft.com/download)
- Install the [.NET Core SDK 3](https://dotnet.microsoft.com/download/dotnet-core)
- Check out the ILSpy repository using git.
- Execute `git submodule update --init --recursive` to download the ILSpy-Tests submodule (used by some test cases).
- Open ILSpy.sln in Visual Studio.
@ -63,6 +64,7 @@ Windows: @@ -63,6 +64,7 @@ Windows:
Unix:
- Make sure .NET Core 2.2 is installed (you can get it here: https://get.dot.net).
- Make sure [.NET Core SDK 3](https://dotnet.microsoft.com/download/dotnet-core) is installed.
- Check out the repository using git.
- Execute `git submodule update --init --recursive` to download the ILSpy-Tests submodule (used by some test cases).
- Use `dotnet build Frontends.sln` to build the non-Windows flavors of ILSpy (cli and powershell core).

13
appveyor.yml

@ -1,28 +1,39 @@ @@ -1,28 +1,39 @@
platform: Any CPU
configuration:
- Debug
- Release
image: Visual Studio 2019 Preview
image: Visual Studio 2019
install:
- cmd: choco install dotnetcore-sdk --pre
- git submodule update --init --recursive
- ps: .\BuildTools\appveyor-install.ps1
nuget:
account_feed: false
project_feed: true
disable_publish_on_pr: true
before_build:
- nuget restore ILSpy.sln
build_script:
- msbuild ILSpy.sln /v:minimal /p:ResolveNuGetPackages=false "/logger:%ProgramFiles%\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll"
after_build:
- 7z a ILSpy_binaries.zip %APPVEYOR_BUILD_FOLDER%\ILSpy\bin\%configuration%\net462\*.dll %APPVEYOR_BUILD_FOLDER%\ILSpy\bin\%configuration%\net462\*.exe %APPVEYOR_BUILD_FOLDER%\ILSpy\bin\%configuration%\net462\*.config %APPVEYOR_BUILD_FOLDER%\ILSpy\bin\%configuration%\net462\*\ILSpy.resources.dll
test:
assemblies:
- 'ICSharpCode.Decompiler.Tests\bin\%configuration%\net462\ICSharpCode.Decompiler.Tests.exe'
- 'ILSpy.Tests\bin\%configuration%\net462\ILSpy.Tests.exe'
- 'ILSpy.BamlDecompiler.Tests\bin\%configuration%\net462\ILSpy.BamlDecompiler.Tests.dll'
after_test:
- python BuildTools\tidy.py
for:
- branches:
except:

Loading…
Cancel
Save