Browse Source

Merge branch 'master' of https://github.com/icsharpcode/ILSpy into dev/jacdavis/sequencepoints

pull/1967/head
Jackson Davis 5 years ago
parent
commit
8180070bc6
  1. 21
      ICSharpCode.Decompiler.Tests/Helpers/Tester.cs
  2. 9
      ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
  3. 6
      ICSharpCode.Decompiler.Tests/ILPrettyTestRunner.cs
  4. 2
      ICSharpCode.Decompiler.Tests/PdbGenerationTestRunner.cs
  5. 2
      ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
  6. 25
      ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Issue1918.cs
  7. 96
      ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Issue1918.il
  8. 9
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Generics.cs
  9. 11
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/QualifierTests.cs
  10. 10
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.cs
  11. 35
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/VariableNaming.cs
  12. 30
      ICSharpCode.Decompiler/CSharp/Annotations.cs
  13. 3
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
  14. 20
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  15. 23
      ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs
  16. 120
      ICSharpCode.Decompiler/CSharp/OutputVisitor/GenericGrammarAmbiguityVisitor.cs
  17. 1
      ICSharpCode.Decompiler/CSharp/OutputVisitor/TextWriterTokenWriter.cs
  18. 42
      ICSharpCode.Decompiler/CSharp/SequencePointBuilder.cs
  19. 6
      ICSharpCode.Decompiler/CSharp/StatementBuilder.cs
  20. 21
      ICSharpCode.Decompiler/CSharp/Transforms/CombineQueryExpressions.cs
  21. 74
      ICSharpCode.Decompiler/CSharp/Transforms/IntroduceQueryExpressions.cs
  22. 128
      ICSharpCode.Decompiler/CSharp/WholeProjectDecompiler.cs
  23. 47
      ICSharpCode.Decompiler/DebugInfo/DebugInfoGenerator.cs
  24. 1
      ICSharpCode.Decompiler/DebugInfo/PortablePdbWriter.cs
  25. 6
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  26. 81
      ICSharpCode.Decompiler/IL/ControlFlow/DetectPinnedRegions.cs
  27. 23
      ICSharpCode.Decompiler/IL/Transforms/AssignVariableNames.cs
  28. 17
      ICSharpCode.Decompiler/IL/Transforms/DelegateConstruction.cs
  29. 8
      ICSharpCode.Decompiler/IL/Transforms/TransformDisplayClassUsage.cs
  30. 21
      ICSharpCode.Decompiler/Solution/ProjectId.cs
  31. 4
      ICSharpCode.Decompiler/Solution/ProjectItem.cs
  32. 5
      ICSharpCode.Decompiler/Solution/SolutionCreator.cs
  33. 1
      ILSpy/Analyzers/AnalyzerScope.cs
  34. 1
      ILSpy/AssemblyList.cs
  35. 1
      ILSpy/DebugInfo/DebugInfoUtils.cs
  36. 1
      ILSpy/Languages/ILAstLanguage.cs
  37. 3
      ILSpy/Languages/Language.cs
  38. 15
      ILSpy/LoadedAssembly.cs
  39. 1
      ILSpy/Metadata/CorTables/GenericParamTableTreeNode.cs
  40. 1
      ILSpy/Metadata/CorTables/MethodImplTableTreeNode.cs
  41. 1
      ILSpy/Metadata/CorTables/ModuleTableTreeNode.cs
  42. 1
      ILSpy/Metadata/CorTables/ParamTableTreeNode.cs
  43. 1
      ILSpy/Metadata/CorTables/StandAloneSigTableTreeNode.cs
  44. 12
      ILSpy/Metadata/DebugMetadataTreeNode.cs
  45. 40
      ILSpy/Metadata/MetadataTreeNode.cs
  46. 4
      ILSpy/Metadata/OptionalHeaderTreeNode.cs
  47. 13
      ILSpy/Options/DisplaySettings.cs
  48. 1
      ILSpy/Options/DisplaySettingsPanel.xaml
  49. 2
      ILSpy/Options/DisplaySettingsPanel.xaml.cs
  50. 9
      ILSpy/Properties/Resources.Designer.cs
  51. 3
      ILSpy/Properties/Resources.resx
  52. 2
      ILSpy/SolutionWriter.cs
  53. 1
      ILSpy/TreeNodes/AssemblyTreeNode.cs
  54. 1
      README.md
  55. 13
      SharpTreeView/SharpTreeNode.cs
  56. 2
      SharpTreeView/SharpTreeNodeView.cs
  57. 15
      SharpTreeView/SharpTreeView.cs
  58. 11
      SharpTreeView/SharpTreeViewItem.cs
  59. 2
      SharpTreeView/Themes/Generic.xaml
  60. 9
      appveyor.yml
  61. 4
      azure-pipelines.yml
  62. 2
      global.json

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

@ -56,6 +56,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -56,6 +56,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
UseMcs = 0x20,
ReferenceVisualBasic = 0x40,
ReferenceCore = 0x80,
GeneratePdb = 0x100,
}
[Flags]
@ -272,7 +273,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -272,7 +273,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
preprocessorSymbols: preprocessorSymbols.ToArray(),
languageVersion: Microsoft.CodeAnalysis.CSharp.LanguageVersion.CSharp8
);
var syntaxTrees = sourceFileNames.Select(f => SyntaxFactory.ParseSyntaxTree(File.ReadAllText(f), parseOptions, path: f));
var syntaxTrees = sourceFileNames.Select(f => SyntaxFactory.ParseSyntaxTree(File.ReadAllText(f), parseOptions, path: f, encoding: Encoding.UTF8));
if (flags.HasFlag(CompilerOptions.ReferenceCore)) {
syntaxTrees = syntaxTrees.Concat(new[] { SyntaxFactory.ParseSyntaxTree(targetFrameworkAttributeSnippet) });
}
@ -296,7 +297,10 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -296,7 +297,10 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
));
CompilerResults results = new CompilerResults(new TempFileCollection());
results.PathToAssembly = outputFileName ?? Path.GetTempFileName();
var emitResult = compilation.Emit(results.PathToAssembly);
string pdbName = null;
if (flags.HasFlag(CompilerOptions.GeneratePdb))
pdbName = Path.ChangeExtension(outputFileName, ".pdb");
var emitResult = compilation.Emit(results.PathToAssembly, pdbName);
if (!emitResult.Success) {
StringBuilder b = new StringBuilder("Compiler error:");
foreach (var diag in emitResult.Diagnostics) {
@ -360,7 +364,12 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -360,7 +364,12 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
CompilerParameters options = new CompilerParameters();
options.GenerateExecutable = !flags.HasFlag(CompilerOptions.Library);
options.CompilerOptions = "/unsafe /o" + (flags.HasFlag(CompilerOptions.Optimize) ? "+" : "-");
options.CompilerOptions += (flags.HasFlag(CompilerOptions.UseDebug) ? " /debug" : "");
string debugOption = " /debug";
if (flags.HasFlag(CompilerOptions.GeneratePdb)) {
debugOption += ":full";
options.IncludeDebugInformation = true;
}
options.CompilerOptions += (flags.HasFlag(CompilerOptions.UseDebug) ? debugOption : "");
options.CompilerOptions += (flags.HasFlag(CompilerOptions.Force32Bit) ? " /platform:anycpu32bitpreferred" : "");
if (preprocessorSymbols.Count > 0) {
options.CompilerOptions += " /d:" + string.Join(";", preprocessorSymbols);
@ -368,7 +377,6 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -368,7 +377,6 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
if (outputFileName != null) {
options.OutputAssembly = outputFileName;
}
options.ReferencedAssemblies.Add("System.dll");
options.ReferencedAssemblies.Add("System.Core.dll");
options.ReferencedAssemblies.Add("System.Xml.dll");
@ -397,7 +405,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -397,7 +405,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
}
}
public static void CompileCSharpWithPdb(string assemblyName, Dictionary<string, string> sourceFiles, PdbToXmlOptions options)
public static void CompileCSharpWithPdb(string assemblyName, Dictionary<string, string> sourceFiles)
{
var parseOptions = new CSharpParseOptions(languageVersion: Microsoft.CodeAnalysis.CSharp.LanguageVersion.Latest);
@ -484,6 +492,9 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -484,6 +492,9 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
decompiler.AstTransforms.Insert(0, new RemoveCompilerAttribute());
decompiler.AstTransforms.Insert(0, new RemoveNamespaceMy());
decompiler.AstTransforms.Add(new EscapeInvalidIdentifiers());
var pdbFileName = Path.ChangeExtension(assemblyFileName, ".pdb");
if (File.Exists(pdbFileName))
decompiler.DebugInfoProvider = PdbProvider.DebugInfoUtils.FromFile(module, pdbFileName);
var syntaxTree = decompiler.DecompileWholeModuleAsSingleFile(sortTypes: true);
StringWriter output = new StringWriter();

9
ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj

@ -49,6 +49,7 @@ @@ -49,6 +49,7 @@
<PackageReference Include="System.Collections.Immutable" Version="1.5.0" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="System.Memory" Version="4.5.3" />
<PackageReference Include="Mono.Cecil" Version="0.10.3" />
</ItemGroup>
<ItemGroup>
@ -60,7 +61,10 @@ @@ -60,7 +61,10 @@
<None Include="TestCases\Correctness\StackTests.il" />
<None Include="TestCases\Correctness\StackTypes.il" />
<None Include="TestCases\Correctness\Uninit.vb" />
<None Include="TestCases\ILPretty\Issue1454.il" />
<None Include="TestCases\ILPretty\Issue1681.il" />
<None Include="TestCases\ILPretty\Issue1922.il" />
<None Include="TestCases\ILPretty\Issue1918.il" />
<None Include="TestCases\ILPretty\WeirdEnums.il" />
<None Include="TestCases\ILPretty\ConstantBlobs.il" />
<None Include="TestCases\ILPretty\CS1xSwitch_Debug.il" />
@ -80,8 +84,13 @@ @@ -80,8 +84,13 @@
</ItemGroup>
<ItemGroup>
<Compile Include="..\ICSharpCode.Decompiler.PdbProvider.Cecil\MonoCecilDebugInfoProvider.cs" Link="MonoCecilDebugInfoProvider.cs" />
<Compile Include="..\ILSpy\DebugInfo\DebugInfoUtils.cs" Link="DebugInfoUtils.cs" />
<Compile Include="..\ILSpy\DebugInfo\PortableDebugInfoProvider.cs" Link="PortableDebugInfoProvider.cs" />
<Compile Include="DisassemblerPrettyTestRunner.cs" />
<Compile Include="TestCases\Correctness\StringConcat.cs" />
<Compile Include="TestCases\ILPretty\Issue1681.cs" />
<None Include="TestCases\ILPretty\Issue1918.cs" />
<Compile Include="TestCases\ILPretty\Issue1922.cs" />
<Compile Include="TestCases\Ugly\NoLocalFunctions.cs" />
<Compile Include="TestCases\VBPretty\Issue1906.cs" />

6
ICSharpCode.Decompiler.Tests/ILPrettyTestRunner.cs

@ -94,6 +94,12 @@ namespace ICSharpCode.Decompiler.Tests @@ -94,6 +94,12 @@ namespace ICSharpCode.Decompiler.Tests
Run();
}
[Test]
public void Issue1918()
{
Run();
}
[Test]
public void Issue1922()
{

2
ICSharpCode.Decompiler.Tests/PdbGenerationTestRunner.cs

@ -51,7 +51,7 @@ namespace ICSharpCode.Decompiler.Tests @@ -51,7 +51,7 @@ namespace ICSharpCode.Decompiler.Tests
string xmlContent = File.ReadAllText(xmlFile);
XDocument document = XDocument.Parse(xmlContent);
var files = document.Descendants("file").ToDictionary(f => f.Attribute("name").Value, f => f.Value);
Tester.CompileCSharpWithPdb(Path.Combine(TestCasePath, testName + ".expected"), files, options);
Tester.CompileCSharpWithPdb(Path.Combine(TestCasePath, testName + ".expected"), files);
string peFileName = Path.Combine(TestCasePath, testName + ".expected.dll");
string pdbFileName = Path.Combine(TestCasePath, testName + ".expected.pdb");

2
ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs

@ -284,7 +284,7 @@ namespace ICSharpCode.Decompiler.Tests @@ -284,7 +284,7 @@ namespace ICSharpCode.Decompiler.Tests
[Test]
public void VariableNaming([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions)
{
RunForLibrary(cscOptions: cscOptions);
RunForLibrary(cscOptions: cscOptions | CompilerOptions.GeneratePdb);
}
[Test]

25
ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Issue1918.cs

@ -0,0 +1,25 @@ @@ -0,0 +1,25 @@
using System;
namespace ICSharpCode.Decompiler.Tests.TestCases.ILPretty
{
internal class Issue1918
{
public static Guid[] NullVal;
public unsafe void ProblemFunction(Guid[] A_0, int A_1)
{
fixed (Guid* ptr = A_0) {
void* ptr2 = ptr;
UIntPtr* ptr3 = (UIntPtr*)((byte*)ptr2 - sizeof(UIntPtr));
UIntPtr uIntPtr = *ptr3;
try {
*ptr3 = (UIntPtr)(ulong)A_1;
} finally {
*ptr3 = uIntPtr;
}
}
fixed (Guid[] ptr = NullVal) {
}
}
}
}

96
ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Issue1918.il

@ -0,0 +1,96 @@ @@ -0,0 +1,96 @@
// 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 Issue1918
{
.ver 1:0:0:0
}
.module Issue1918.exe
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00020003 // ILONLY 32BITPREFERRED
.class private auto ansi beforefieldinit ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue1918
extends [mscorlib]System.Object
{
.method public hidebysig
instance void ProblemFunction (valuetype [mscorlib]System.Guid[] '', int32 ''
) cil managed
{
.maxstack 2
.locals init (
[0] valuetype [mscorlib]System.Guid[],
[1] int32,
[2] void*,
[3] valuetype [mscorlib]System.Guid[] pinned,
[4] native uint*,
[5] native uint
)
IL_0000: ldarg.1
stloc.0
IL_0010:
ldarg.2
stloc.1
ldloc.0
dup
stloc.3
brfalse.s IL_0026
ldloc.3
ldlen
conv.i4
brtrue.s IL_002b
IL_0026: ldc.i4.0
conv.u
stloc.2
br.s IL_0034
IL_002b: ldloc.3
ldc.i4.0
ldelema [mscorlib]System.Guid
conv.u
stloc.2
IL_0034: ldloc.2
sizeof [mscorlib]System.UIntPtr
sub
stloc.s 4
ldloc.s 4
ldind.i
stloc.s 5
.try
{
ldloc.s 4
ldloc.1
conv.i8
call native uint [mscorlib]System.UIntPtr::op_Explicit(uint64)
stind.i
ldarg.1
leave.s IL_005c
} // end .try
finally
{
ldloc.s 4
ldloc.s 5
stind.i
endfinally
} // end handler
IL_005c: ldsfld valuetype [mscorlib]System.Guid[] ICSharpCode.Decompiler.Tests.TestCases.ILPretty.Issue1918::NullVal
stloc.3
ret
}
.field public static valuetype [mscorlib]System.Guid[] NullVal
}

9
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Generics.cs

@ -276,5 +276,14 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -276,5 +276,14 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
return sizeof(T);
}
#endif
public static void Issue1959(int a, int b, int? c)
{
// This line requires parentheses around `a < b` to avoid a grammar ambiguity.
Console.WriteLine("{}, {}", (a < b), a > (c ?? b));
// But here there's no ambiguity:
Console.WriteLine("{}, {}", a < b, a > b);
Console.WriteLine("{}, {}", a < Environment.GetLogicalDrives().Length, a > (c ?? b));
}
}
}

11
ICSharpCode.Decompiler.Tests/TestCases/Pretty/QualifierTests.cs

@ -74,6 +74,17 @@ namespace ICSharpCode.Decompiler.Tests.Pretty @@ -74,6 +74,17 @@ namespace ICSharpCode.Decompiler.Tests.Pretty
{
}
public string ThisQualifierWithCast()
{
return ((object)this).ToString();
}
public override string ToString()
{
// decompiled as return ((ValueType)this).ToString();
return base.ToString();
}
}
internal class Parent

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

@ -208,6 +208,16 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -208,6 +208,16 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
}
}
#if !(LEGACY_CSC && OPT)
// legacy csc manages to optimize out the pinned variable altogether in this case;
// leaving no pinned region we could detect.
public unsafe void FixedArrayNoPointerUse(int[] arr)
{
fixed (int* ptr = arr) {
}
}
#endif
public unsafe void PutDoubleIntoLongArray1(long[] array, int index, double val)
{
fixed (long* ptr = array) {

35
ICSharpCode.Decompiler.Tests/TestCases/Pretty/VariableNaming.cs

@ -1,7 +1,17 @@ @@ -1,7 +1,17 @@
namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
#if !OPT
using System;
#endif
namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
internal class VariableNaming
{
private enum MyEnum
{
VALUE1 = 1,
VALUE2
}
private class C
{
public string Name;
@ -25,5 +35,28 @@ @@ -25,5 +35,28 @@
string text2 = c.Text;
#endif
}
#if !OPT
private void Issue1841()
{
C gen1 = new C();
C gen2 = new C();
C gen3 = new C();
C gen4 = new C();
}
private void Issue1881()
{
MyEnum enumLocal1 = MyEnum.VALUE1;
MyEnum enumLocal2 = (MyEnum)0;
enumLocal2 = MyEnum.VALUE1;
object enumLocal3 = MyEnum.VALUE2;
object enumLocal4 = new object();
enumLocal4 = MyEnum.VALUE2;
ValueType enumLocal5 = MyEnum.VALUE1;
ValueType enumLocal6 = (MyEnum)0;
enumLocal6 = MyEnum.VALUE2;
}
#endif
}
}

30
ICSharpCode.Decompiler/CSharp/Annotations.cs

@ -289,4 +289,34 @@ namespace ICSharpCode.Decompiler.CSharp @@ -289,4 +289,34 @@ namespace ICSharpCode.Decompiler.CSharp
this.ConversionResolveResult = conversionResolveResult;
}
}
/// <summary>
/// Annotates a QueryGroupClause with the ILFunctions of each (implicit lambda) expression.
/// </summary>
public class QueryGroupClauseAnnotation
{
public readonly ILFunction KeyLambda;
public readonly ILFunction ProjectionLambda;
public QueryGroupClauseAnnotation(ILFunction key, ILFunction projection)
{
this.KeyLambda = key;
this.ProjectionLambda = projection;
}
}
/// <summary>
/// Annotates a QueryJoinClause with the ILFunctions of each (implicit lambda) expression.
/// </summary>
public class QueryJoinClauseAnnotation
{
public readonly ILFunction OnLambda;
public readonly ILFunction EqualsLambda;
public QueryJoinClauseAnnotation(ILFunction on, ILFunction equals)
{
this.OnLambda = on;
this.EqualsLambda = equals;
}
}
}

3
ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

@ -428,7 +428,10 @@ namespace ICSharpCode.Decompiler.CSharp @@ -428,7 +428,10 @@ namespace ICSharpCode.Decompiler.CSharp
CancellationToken.ThrowIfCancellationRequested();
transform.Run(rootNode, context);
}
CancellationToken.ThrowIfCancellationRequested();
rootNode.AcceptVisitor(new InsertParenthesesVisitor { InsertParenthesesForReadability = true });
CancellationToken.ThrowIfCancellationRequested();
GenericGrammarAmbiguityVisitor.ResolveAmbiguities(rootNode);
}
string SyntaxTreeToString(SyntaxTree syntaxTree)

20
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -2002,7 +2002,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -2002,7 +2002,7 @@ namespace ICSharpCode.Decompiler.CSharp
// If references are missing member.IsStatic might not be set correctly.
// Additionally check target for null, in order to avoid a crash.
if (!memberStatic && target != null) {
if (nonVirtualInvocation && target.MatchLdThis() && memberDeclaringType.GetDefinition() != resolver.CurrentTypeDefinition) {
if (nonVirtualInvocation && MatchLdThis(target) && memberDeclaringType.GetDefinition() != resolver.CurrentTypeDefinition) {
return new BaseReferenceExpression()
.WithILInstruction(target)
.WithRR(new ThisResolveResult(memberDeclaringType, nonVirtualInvocation));
@ -2037,6 +2037,24 @@ namespace ICSharpCode.Decompiler.CSharp @@ -2037,6 +2037,24 @@ namespace ICSharpCode.Decompiler.CSharp
.WithoutILInstruction()
.WithRR(new TypeResolveResult(memberDeclaringType));
}
bool MatchLdThis(ILInstruction inst)
{
// ldloc this
if (inst.MatchLdThis())
return true;
if (resolver.CurrentTypeDefinition.Kind == TypeKind.Struct) {
// box T(ldobj T(ldloc this))
if (!inst.MatchBox(out var arg, out var type))
return false;
if (!arg.MatchLdObj(out var arg2, out var type2))
return false;
if (!type.Equals(type2) || !type.Equals(resolver.CurrentTypeDefinition))
return false;
return arg2.MatchLdThis();
}
return false;
}
}
private TranslatedExpression EnsureTargetNotNullable(TranslatedExpression expr)

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

@ -148,29 +148,6 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -148,29 +148,6 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
RPar();
}
#if DOTNET35
void WriteCommaSeparatedList(IEnumerable<VariableInitializer> list)
{
WriteCommaSeparatedList(list.SafeCast<VariableInitializer, AstNode>());
}
void WriteCommaSeparatedList(IEnumerable<AstType> list)
{
WriteCommaSeparatedList(list.SafeCast<AstType, AstNode>());
}
void WriteCommaSeparatedListInParenthesis(IEnumerable<Expression> list, bool spaceWithin)
{
WriteCommaSeparatedListInParenthesis(list.SafeCast<Expression, AstNode>(), spaceWithin);
}
void WriteCommaSeparatedListInParenthesis(IEnumerable<ParameterDeclaration> list, bool spaceWithin)
{
WriteCommaSeparatedListInParenthesis(list.SafeCast<ParameterDeclaration, AstNode>(), spaceWithin);
}
#endif
protected virtual void WriteCommaSeparatedListInBrackets(IEnumerable<ParameterDeclaration> list, bool spaceWithin)
{
WriteToken(Roles.LBracket);

120
ICSharpCode.Decompiler/CSharp/OutputVisitor/GenericGrammarAmbiguityVisitor.cs

@ -0,0 +1,120 @@ @@ -0,0 +1,120 @@
// Copyright (c) 2020 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;
using System.Diagnostics;
using System.Linq;
using ICSharpCode.Decompiler.CSharp.Syntax;
namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
{
/// <summary>
/// Used to test for the "F(G&lt;A,B&gt;(7));" grammar ambiguity.
/// </summary>
class GenericGrammarAmbiguityVisitor : DepthFirstAstVisitor<bool>
{
/// <summary>
/// Resolves ambiguities in the specified syntax tree.
/// This method must be called after the InsertParenthesesVisitor, because the ambiguity depends on whether the
/// final `>` in the possible-type-argument is followed by an opening parenthesis.
/// </summary>
public static void ResolveAmbiguities(AstNode rootNode)
{
foreach (var node in rootNode.Descendants.OfType<BinaryOperatorExpression>()) {
if (CausesAmbiguityWithGenerics(node)) {
node.ReplaceWith(n => new ParenthesizedExpression(n));
}
}
}
public static bool CausesAmbiguityWithGenerics(BinaryOperatorExpression binaryOperatorExpression)
{
if (binaryOperatorExpression.Operator != BinaryOperatorType.LessThan)
return false;
var v = new GenericGrammarAmbiguityVisitor();
v.genericNestingLevel = 1;
for (AstNode node = binaryOperatorExpression.Right; node != null; node = node.GetNextNode()) {
if (node.AcceptVisitor(v))
return v.ambiguityFound;
}
return false;
}
int genericNestingLevel;
bool ambiguityFound;
protected override bool VisitChildren(AstNode node)
{
// unhandled node: probably not syntactically valid in a typename
// These are preconditions for all recursive Visit() calls.
Debug.Assert(genericNestingLevel > 0);
Debug.Assert(!ambiguityFound);
// The return value merely indicates whether to stop visiting.
return true; // stop visiting, no ambiguity found
}
public override bool VisitBinaryOperatorExpression(BinaryOperatorExpression binaryOperatorExpression)
{
if (binaryOperatorExpression.Left.AcceptVisitor(this))
return true;
Debug.Assert(genericNestingLevel > 0);
switch (binaryOperatorExpression.Operator) {
case BinaryOperatorType.LessThan:
genericNestingLevel += 1;
break;
case BinaryOperatorType.GreaterThan:
genericNestingLevel--;
break;
case BinaryOperatorType.ShiftRight when genericNestingLevel >= 2:
genericNestingLevel -= 2;
break;
default:
return true; // stop visiting, no ambiguity found
}
if (genericNestingLevel == 0) {
// Of the all tokens that might follow `>` and trigger the ambiguity to be resolved in favor of generics,
// `(` is the only one that might start an expression.
ambiguityFound = binaryOperatorExpression.Right is ParenthesizedExpression;
return true; // stop visiting
}
return binaryOperatorExpression.Right.AcceptVisitor(this);
}
public override bool VisitIdentifierExpression(IdentifierExpression identifierExpression)
{
// identifier could also be valid in a type argument
return false; // keep visiting
}
public override bool VisitTypeReferenceExpression(TypeReferenceExpression typeReferenceExpression)
{
return false; // keep visiting
}
public override bool VisitMemberReferenceExpression(MemberReferenceExpression memberReferenceExpression)
{
// MRE could also be valid in a type argument
return memberReferenceExpression.Target.AcceptVisitor(this);
}
}
}

1
ICSharpCode.Decompiler/CSharp/OutputVisitor/TextWriterTokenWriter.cs

@ -336,6 +336,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -336,6 +336,7 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
number += ".0";
}
textWriter.Write(number);
column += number.Length;
Length += number.Length;
} else if (value is IFormattable) {
StringBuilder b = new StringBuilder();

42
ICSharpCode.Decompiler/CSharp/SequencePointBuilder.cs

@ -181,6 +181,48 @@ namespace ICSharpCode.Decompiler.CSharp @@ -181,6 +181,48 @@ namespace ICSharpCode.Decompiler.CSharp
VisitAsSequencePoint(lambdaExpression.Body);
}
public override void VisitQueryContinuationClause(QueryContinuationClause queryContinuationClause)
{
AddToSequencePoint(queryContinuationClause);
VisitAsSequencePoint(queryContinuationClause.PrecedingQuery);
}
public override void VisitQueryFromClause(QueryFromClause queryFromClause)
{
if (queryFromClause.Parent.FirstChild != queryFromClause) {
AddToSequencePoint(queryFromClause);
VisitAsSequencePoint(queryFromClause.Expression);
} else {
base.VisitQueryFromClause(queryFromClause);
}
}
public override void VisitQueryGroupClause(QueryGroupClause queryGroupClause)
{
AddToSequencePoint(queryGroupClause);
VisitAsSequencePoint(queryGroupClause.Projection);
VisitAsSequencePoint(queryGroupClause.Key);
}
public override void VisitQueryJoinClause(QueryJoinClause queryJoinClause)
{
AddToSequencePoint(queryJoinClause);
VisitAsSequencePoint(queryJoinClause.OnExpression);
VisitAsSequencePoint(queryJoinClause.EqualsExpression);
}
public override void VisitQueryLetClause(QueryLetClause queryLetClause)
{
AddToSequencePoint(queryLetClause);
VisitAsSequencePoint(queryLetClause.Expression);
}
public override void VisitQueryOrdering(QueryOrdering queryOrdering)
{
AddToSequencePoint(queryOrdering);
VisitAsSequencePoint(queryOrdering.Expression);
}
public override void VisitQuerySelectClause(QuerySelectClause querySelectClause)
{
AddToSequencePoint(querySelectClause);

6
ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

@ -994,6 +994,12 @@ namespace ICSharpCode.Decompiler.CSharp @@ -994,6 +994,12 @@ namespace ICSharpCode.Decompiler.CSharp
stmt.Parameters.AddRange(exprBuilder.MakeParameters(function.Parameters, function));
stmt.ReturnType = exprBuilder.ConvertType(function.Method.ReturnType);
stmt.Body = nestedBuilder.ConvertAsBlock(function.Body);
Comment prev = null;
foreach (string warning in function.Warnings) {
stmt.Body.InsertChildAfter(prev, prev = new Comment(warning), Roles.Comment);
}
if (function.Method.TypeParameters.Count > 0) {
var astBuilder = exprBuilder.astBuilder;
if (astBuilder.ShowTypeParameters) {

21
ICSharpCode.Decompiler/CSharp/Transforms/CombineQueryExpressions.cs

@ -43,25 +43,26 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -43,25 +43,26 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
TypeArguments = { new AnyNode("targetType") }
}};
void CombineQueries(AstNode node, Dictionary<string, object> letIdentifiers)
void CombineQueries(AstNode node, Dictionary<string, object> fromOrLetIdentifiers)
{
AstNode next;
for (AstNode child = node.FirstChild; child != null; child = next) {
// store referece to next child before transformation
// store reference to next child before transformation
next = child.NextSibling;
CombineQueries(child, letIdentifiers);
CombineQueries(child, fromOrLetIdentifiers);
}
QueryExpression query = node as QueryExpression;
if (query != null) {
QueryFromClause fromClause = (QueryFromClause)query.Clauses.First();
QueryExpression innerQuery = fromClause.Expression as QueryExpression;
if (innerQuery != null) {
if (TryRemoveTransparentIdentifier(query, fromClause, innerQuery, letIdentifiers)) {
RemoveTransparentIdentifierReferences(query, letIdentifiers);
if (TryRemoveTransparentIdentifier(query, fromClause, innerQuery, fromOrLetIdentifiers)) {
RemoveTransparentIdentifierReferences(query, fromOrLetIdentifiers);
} else {
QueryContinuationClause continuation = new QueryContinuationClause();
continuation.PrecedingQuery = innerQuery.Detach();
continuation.Identifier = fromClause.Identifier;
continuation.CopyAnnotationsFrom(fromClause);
fromClause.ReplaceWith(continuation);
}
} else {
@ -119,8 +120,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -119,8 +120,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
foreach (var expr in match.Get<Expression>("expr")) {
switch (expr) {
case IdentifierExpression identifier:
// nothing to add
continue;
letClauses[identifier.Identifier] = identifier.Annotation<ILVariableResolveResult>();
break;
case MemberReferenceExpression member:
AddQueryLetClause(member.MemberName, member);
break;
@ -148,10 +149,10 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -148,10 +149,10 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
/// <summary>
/// Removes all occurrences of transparent identifiers
/// </summary>
void RemoveTransparentIdentifierReferences(AstNode node, Dictionary<string, object> letClauses)
void RemoveTransparentIdentifierReferences(AstNode node, Dictionary<string, object> fromOrLetIdentifiers)
{
foreach (AstNode child in node.Children) {
RemoveTransparentIdentifierReferences(child, letClauses);
RemoveTransparentIdentifierReferences(child, fromOrLetIdentifiers);
}
MemberReferenceExpression mre = node as MemberReferenceExpression;
if (mre != null) {
@ -161,7 +162,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -161,7 +162,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
mre.TypeArguments.MoveTo(newIdent.TypeArguments);
newIdent.CopyAnnotationsFrom(mre);
newIdent.RemoveAnnotations<Semantics.MemberResolveResult>(); // remove the reference to the property of the anonymous type
if (letClauses.TryGetValue(mre.MemberName, out var annotation))
if (fromOrLetIdentifiers.TryGetValue(mre.MemberName, out var annotation))
newIdent.AddAnnotation(annotation);
mre.ReplaceWith(newIdent);
return;

74
ICSharpCode.Decompiler/CSharp/Transforms/IntroduceQueryExpressions.cs

@ -76,7 +76,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -76,7 +76,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
node.ReplaceWith(query);
AstNode next;
for (AstNode child = (query ?? node).FirstChild; child != null; child = next) {
// store referece to next child before transformation
// store reference to next child before transformation
next = child.NextSibling;
DecompileQueries(child);
}
@ -95,10 +95,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -95,10 +95,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
return null;
if (!IsComplexQuery(mre))
return null;
ParameterDeclaration parameter;
Expression body;
Expression expr = invocation.Arguments.Single();
if (MatchSimpleLambda(expr, out parameter, out body)) {
if (MatchSimpleLambda(expr, out ParameterDeclaration parameter, out Expression body)) {
QueryExpression query = new QueryExpression();
query.Clauses.Add(MakeFromClause(parameter, mre.Target.Detach()));
query.Clauses.Add(new QuerySelectClause { Expression = WrapExpressionInParenthesesIfNecessary(body.Detach(), parameter.Name) }.CopyAnnotationsFrom(expr));
@ -109,21 +107,24 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -109,21 +107,24 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
case "GroupBy":
{
if (invocation.Arguments.Count == 2) {
ParameterDeclaration parameter1, parameter2;
Expression keySelector, elementSelector;
if (MatchSimpleLambda(invocation.Arguments.ElementAt(0), out parameter1, out keySelector)
&& MatchSimpleLambda(invocation.Arguments.ElementAt(1), out parameter2, out elementSelector)
&& parameter1.Name == parameter2.Name)
{
Expression keyLambda = invocation.Arguments.ElementAt(0);
Expression projectionLambda = invocation.Arguments.ElementAt(1);
if (MatchSimpleLambda(keyLambda, out ParameterDeclaration parameter1, out Expression keySelector)
&& MatchSimpleLambda(projectionLambda, out ParameterDeclaration parameter2, out Expression elementSelector)
&& parameter1.Name == parameter2.Name) {
QueryExpression query = new QueryExpression();
query.Clauses.Add(MakeFromClause(parameter1, mre.Target.Detach()));
query.Clauses.Add(new QueryGroupClause { Projection = elementSelector.Detach(), Key = keySelector.Detach() });
var queryGroupClause = new QueryGroupClause {
Projection = elementSelector.Detach(),
Key = keySelector.Detach()
};
queryGroupClause.AddAnnotation(new QueryGroupClauseAnnotation(keyLambda.Annotation<IL.ILFunction>(), projectionLambda.Annotation<IL.ILFunction>()));
query.Clauses.Add(queryGroupClause);
return query;
}
} else if (invocation.Arguments.Count == 1) {
ParameterDeclaration parameter;
Expression keySelector;
if (MatchSimpleLambda(invocation.Arguments.Single(), out parameter, out keySelector)) {
Expression lambda = invocation.Arguments.Single();
if (MatchSimpleLambda(lambda, out ParameterDeclaration parameter, out Expression keySelector)) {
QueryExpression query = new QueryExpression();
query.Clauses.Add(MakeFromClause(parameter, mre.Target.Detach()));
query.Clauses.Add(new QueryGroupClause { Projection = new IdentifierExpression(parameter.Name).CopyAnnotationsFrom(parameter), Key = keySelector.Detach() });
@ -136,9 +137,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -136,9 +137,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
{
if (invocation.Arguments.Count != 2)
return null;
ParameterDeclaration parameter;
Expression collectionSelector;
if (!MatchSimpleLambda(invocation.Arguments.ElementAt(0), out parameter, out collectionSelector))
var fromExpressionLambda = invocation.Arguments.ElementAt(0);
if (!MatchSimpleLambda(fromExpressionLambda, out ParameterDeclaration parameter, out Expression collectionSelector))
return null;
if (IsNullConditional(collectionSelector))
return null;
@ -149,7 +149,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -149,7 +149,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
if (p1.Name == parameter.Name) {
QueryExpression query = new QueryExpression();
query.Clauses.Add(MakeFromClause(p1, mre.Target.Detach()));
query.Clauses.Add(MakeFromClause(p2, collectionSelector.Detach()));
query.Clauses.Add(MakeFromClause(p2, collectionSelector.Detach()).CopyAnnotationsFrom(fromExpressionLambda));
query.Clauses.Add(new QuerySelectClause { Expression = WrapExpressionInParenthesesIfNecessary(((Expression)lambda.Body).Detach(), parameter.Name) });
return query;
}
@ -162,10 +162,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -162,10 +162,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
return null;
if (!IsComplexQuery(mre))
return null;
ParameterDeclaration parameter;
Expression body;
Expression expr = invocation.Arguments.Single();
if (MatchSimpleLambda(expr, out parameter, out body)) {
if (MatchSimpleLambda(expr, out ParameterDeclaration parameter, out Expression body)) {
QueryExpression query = new QueryExpression();
query.Clauses.Add(MakeFromClause(parameter, mre.Target.Detach()));
query.Clauses.Add(new QueryWhereClause { Condition = body.Detach() }.CopyAnnotationsFrom(expr));
@ -182,30 +180,29 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -182,30 +180,29 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
return null;
if (!IsComplexQuery(mre))
return null;
ParameterDeclaration parameter;
Expression orderExpression;
if (MatchSimpleLambda(invocation.Arguments.Single(), out parameter, out orderExpression)) {
var lambda = invocation.Arguments.Single();
if (MatchSimpleLambda(lambda, out ParameterDeclaration parameter, out Expression orderExpression)) {
if (ValidateThenByChain(invocation, parameter.Name)) {
QueryOrderClause orderClause = new QueryOrderClause();
InvocationExpression tmp = invocation;
while (mre.MemberName == "ThenBy" || mre.MemberName == "ThenByDescending") {
// insert new ordering at beginning
orderClause.Orderings.InsertAfter(
null, new QueryOrdering {
Expression = orderExpression.Detach(),
Direction = (mre.MemberName == "ThenBy" ? QueryOrderingDirection.None : QueryOrderingDirection.Descending)
});
}.CopyAnnotationsFrom(lambda));
tmp = (InvocationExpression)mre.Target;
InvocationExpression tmp = (InvocationExpression)mre.Target;
mre = (MemberReferenceExpression)tmp.Target;
MatchSimpleLambda(tmp.Arguments.Single(), out parameter, out orderExpression);
lambda = tmp.Arguments.Single();
MatchSimpleLambda(lambda, out parameter, out orderExpression);
}
// insert new ordering at beginning
orderClause.Orderings.InsertAfter(
null, new QueryOrdering {
Expression = orderExpression.Detach(),
Direction = (mre.MemberName == "OrderBy" ? QueryOrderingDirection.None : QueryOrderingDirection.Descending)
});
}.CopyAnnotationsFrom(lambda));
QueryExpression query = new QueryExpression();
query.Clauses.Add(MakeFromClause(parameter, mre.Target.Detach()));
@ -224,11 +221,11 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -224,11 +221,11 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
Expression source2 = invocation.Arguments.ElementAt(0);
if (IsNullConditional(source2))
return null;
ParameterDeclaration element1, element2;
Expression key1, key2;
if (!MatchSimpleLambda(invocation.Arguments.ElementAt(1), out element1, out key1))
Expression outerLambda = invocation.Arguments.ElementAt(1);
if (!MatchSimpleLambda(outerLambda, out ParameterDeclaration element1, out Expression key1))
return null;
if (!MatchSimpleLambda(invocation.Arguments.ElementAt(2), out element2, out key2))
Expression innerLambda = invocation.Arguments.ElementAt(2);
if (!MatchSimpleLambda(innerLambda, out ParameterDeclaration element2, out Expression key2))
return null;
LambdaExpression lambda = invocation.Arguments.ElementAt(3) as LambdaExpression;
if (lambda != null && lambda.Parameters.Count == 2 && lambda.Body is Expression) {
@ -245,6 +242,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -245,6 +242,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
if (mre.MemberName == "GroupJoin") {
joinClause.IntoIdentifier = p2.Name; // into p2.Name
}
joinClause.AddAnnotation(new QueryJoinClauseAnnotation(outerLambda.Annotation<IL.ILFunction>(), innerLambda.Annotation<IL.ILFunction>()));
query.Clauses.Add(joinClause);
query.Clauses.Add(new QuerySelectClause { Expression = ((Expression)lambda.Body).Detach() }.CopyAnnotationsFrom(lambda));
return query;
@ -316,12 +314,9 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -316,12 +314,9 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
{
if (invocation == null || invocation.Arguments.Count != 1)
return false;
MemberReferenceExpression mre = invocation.Target as MemberReferenceExpression;
if (mre == null)
if (!(invocation.Target is MemberReferenceExpression mre))
return false;
ParameterDeclaration parameter;
Expression body;
if (!MatchSimpleLambda(invocation.Arguments.Single(), out parameter, out body))
if (!MatchSimpleLambda(invocation.Arguments.Single(), out ParameterDeclaration parameter, out _))
return false;
if (parameter.Name != expectedParameterName)
return false;
@ -337,8 +332,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -337,8 +332,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
/// <summary>Matches simple lambdas of the form "a => b"</summary>
bool MatchSimpleLambda(Expression expr, out ParameterDeclaration parameter, out Expression body)
{
var lambda = expr as LambdaExpression;
if (lambda != null && lambda.Parameters.Count == 1 && lambda.Body is Expression) {
if (expr is LambdaExpression lambda && lambda.Parameters.Count == 1 && lambda.Body is Expression) {
ParameterDeclaration p = lambda.Parameters.Single();
if (p.ParameterModifier == ParameterModifier.None) {
parameter = p;

128
ICSharpCode.Decompiler/CSharp/WholeProjectDecompiler.cs

@ -127,18 +127,19 @@ namespace ICSharpCode.Decompiler.CSharp @@ -127,18 +127,19 @@ namespace ICSharpCode.Decompiler.CSharp
return WriteProjectFile(projectFileWriter, files, moduleDefinition);
}
enum LanguageTargets
{
None,
Portable
}
#region WriteProjectFile
ProjectId WriteProjectFile(TextWriter writer, IEnumerable<Tuple<string, string>> files, Metadata.PEFile module)
{
const string ns = "http://schemas.microsoft.com/developer/msbuild/2003";
string platformName = GetPlatformName(module);
Guid guid = this.ProjectGuid ?? Guid.NewGuid();
var targetFramework = DetectTargetFramework(module);
List<Guid> typeGuids = new List<Guid>();
if (targetFramework.IsPortableClassLibrary)
typeGuids.Add(ProjectTypeGuids.PortableLibrary);
typeGuids.Add(ProjectTypeGuids.CSharpWindows);
// TODO: .NET core support
using (XmlTextWriter w = new XmlTextWriter(writer)) {
w.Formatting = Formatting.Indented;
@ -149,6 +150,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -149,6 +150,7 @@ namespace ICSharpCode.Decompiler.CSharp
w.WriteStartElement("PropertyGroup");
w.WriteElementString("ProjectGuid", guid.ToString("B").ToUpperInvariant());
w.WriteElementString("ProjectTypeGuids", string.Join(";", typeGuids.Select(g => g.ToString("B").ToUpperInvariant())));
w.WriteStartElement("Configuration");
w.WriteAttributeString("Condition", " '$(Configuration)' == '' ");
@ -179,53 +181,12 @@ namespace ICSharpCode.Decompiler.CSharp @@ -179,53 +181,12 @@ namespace ICSharpCode.Decompiler.CSharp
w.WriteElementString("LangVersion", LanguageVersion.ToString().Replace("CSharp", "").Replace('_', '.'));
w.WriteElementString("AssemblyName", module.Name);
bool useTargetFrameworkAttribute = false;
LanguageTargets languageTargets = LanguageTargets.None;
string targetFramework = module.Reader.DetectTargetFrameworkId();
int frameworkVersionNumber = 0;
if (!string.IsNullOrEmpty(targetFramework)) {
string[] frameworkParts = targetFramework.Split(',');
string frameworkIdentifier = frameworkParts.FirstOrDefault(a => !a.StartsWith("Version=", StringComparison.OrdinalIgnoreCase) && !a.StartsWith("Profile=", StringComparison.OrdinalIgnoreCase));
if (frameworkIdentifier != null) {
w.WriteElementString("TargetFrameworkIdentifier", frameworkIdentifier);
switch (frameworkIdentifier) {
case ".NETPortable":
languageTargets = LanguageTargets.Portable;
break;
}
}
string frameworkVersion = frameworkParts.FirstOrDefault(a => a.StartsWith("Version=", StringComparison.OrdinalIgnoreCase));
if (frameworkVersion != null) {
w.WriteElementString("TargetFrameworkVersion", frameworkVersion.Substring("Version=".Length));
useTargetFrameworkAttribute = true;
frameworkVersionNumber = int.Parse(frameworkVersion.Substring("Version=v".Length).Replace(".", ""));
if (frameworkVersionNumber < 100) frameworkVersionNumber *= 10;
}
string frameworkProfile = frameworkParts.FirstOrDefault(a => a.StartsWith("Profile=", StringComparison.OrdinalIgnoreCase));
if (frameworkProfile != null)
w.WriteElementString("TargetFrameworkProfile", frameworkProfile.Substring("Profile=".Length));
}
if (!useTargetFrameworkAttribute) {
switch (module.GetRuntime()) {
case Metadata.TargetRuntime.Net_1_0:
frameworkVersionNumber = 100;
w.WriteElementString("TargetFrameworkVersion", "v1.0");
break;
case Metadata.TargetRuntime.Net_1_1:
frameworkVersionNumber = 110;
w.WriteElementString("TargetFrameworkVersion", "v1.1");
break;
case Metadata.TargetRuntime.Net_2_0:
frameworkVersionNumber = 200;
w.WriteElementString("TargetFrameworkVersion", "v2.0");
// TODO: Detect when .NET 3.0/3.5 is required
break;
default:
frameworkVersionNumber = 400;
w.WriteElementString("TargetFrameworkVersion", "v4.0");
break;
}
}
if (targetFramework.TargetFrameworkIdentifier != null)
w.WriteElementString("TargetFrameworkIdentifier", targetFramework.TargetFrameworkIdentifier);
if (targetFramework.TargetFrameworkVersion != null)
w.WriteElementString("TargetFrameworkVersion", targetFramework.TargetFrameworkVersion);
if (targetFramework.TargetFrameworkProfile != null)
w.WriteElementString("TargetFrameworkProfile", targetFramework.TargetFrameworkProfile);
w.WriteElementString("WarningLevel", "4");
w.WriteElementString("AllowUnsafeBlocks", "True");
@ -239,7 +200,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -239,7 +200,7 @@ namespace ICSharpCode.Decompiler.CSharp
w.WriteStartElement("PropertyGroup"); // platform-specific
w.WriteAttributeString("Condition", " '$(Platform)' == '" + platformName + "' ");
w.WriteElementString("PlatformTarget", platformName);
if (frameworkVersionNumber > 400 && platformName == "AnyCPU" && (module.Reader.PEHeaders.CorHeader.Flags & CorFlags.Prefers32Bit) == 0) {
if (targetFramework.VersionNumber > 400 && platformName == "AnyCPU" && (module.Reader.PEHeaders.CorHeader.Flags & CorFlags.Prefers32Bit) == 0) {
w.WriteElementString("Prefer32Bit", "false");
}
w.WriteEndElement(); // </PropertyGroup> (platform-specific)
@ -286,23 +247,70 @@ namespace ICSharpCode.Decompiler.CSharp @@ -286,23 +247,70 @@ namespace ICSharpCode.Decompiler.CSharp
}
w.WriteEndElement();
}
switch (languageTargets) {
case LanguageTargets.Portable:
if (targetFramework.IsPortableClassLibrary) {
w.WriteStartElement("Import");
w.WriteAttributeString("Project", "$(MSBuildExtensionsPath32)\\Microsoft\\Portable\\$(TargetFrameworkVersion)\\Microsoft.Portable.CSharp.targets");
w.WriteEndElement();
break;
default:
} else {
w.WriteStartElement("Import");
w.WriteAttributeString("Project", "$(MSBuildToolsPath)\\Microsoft.CSharp.targets");
w.WriteEndElement();
break;
}
w.WriteEndDocument();
}
return new ProjectId(platformName, guid);
return new ProjectId(platformName, guid, ProjectTypeGuids.CSharpWindows);
}
struct TargetFramework
{
public string TargetFrameworkIdentifier;
public string TargetFrameworkVersion;
public string TargetFrameworkProfile;
public int VersionNumber;
public bool IsPortableClassLibrary => TargetFrameworkIdentifier == ".NETPortable";
}
private TargetFramework DetectTargetFramework(PEFile module)
{
TargetFramework result = default;
switch (module.GetRuntime()) {
case Metadata.TargetRuntime.Net_1_0:
result.VersionNumber = 100;
result.TargetFrameworkVersion = "v1.0";
break;
case Metadata.TargetRuntime.Net_1_1:
result.VersionNumber = 110;
result.TargetFrameworkVersion = "v1.1";
break;
case Metadata.TargetRuntime.Net_2_0:
result.VersionNumber = 200;
result.TargetFrameworkVersion = "v2.0";
// TODO: Detect when .NET 3.0/3.5 is required
break;
default:
result.VersionNumber = 400;
result.TargetFrameworkVersion = "v4.0";
break;
}
string targetFramework = module.Reader.DetectTargetFrameworkId();
if (!string.IsNullOrEmpty(targetFramework)) {
string[] frameworkParts = targetFramework.Split(',');
result.TargetFrameworkIdentifier = frameworkParts.FirstOrDefault(a => !a.StartsWith("Version=", StringComparison.OrdinalIgnoreCase) && !a.StartsWith("Profile=", StringComparison.OrdinalIgnoreCase));
string frameworkVersion = frameworkParts.FirstOrDefault(a => a.StartsWith("Version=", StringComparison.OrdinalIgnoreCase));
if (frameworkVersion != null) {
result.TargetFrameworkVersion = frameworkVersion.Substring("Version=".Length);
result.VersionNumber = int.Parse(frameworkVersion.Substring("Version=v".Length).Replace(".", ""));
if (result.VersionNumber < 100) result.VersionNumber *= 10;
}
string frameworkProfile = frameworkParts.FirstOrDefault(a => a.StartsWith("Profile=", StringComparison.OrdinalIgnoreCase));
if (frameworkProfile != null)
result.TargetFrameworkProfile = frameworkProfile.Substring("Profile=".Length);
}
return result;
}
protected virtual bool IsGacAssembly(Metadata.IAssemblyReference r, Metadata.PEFile asm)

47
ICSharpCode.Decompiler/DebugInfo/DebugInfoGenerator.cs

@ -133,6 +133,47 @@ namespace ICSharpCode.Decompiler.DebugInfo @@ -133,6 +133,47 @@ namespace ICSharpCode.Decompiler.DebugInfo
HandleMethod(anonymousMethodExpression);
}
public override void VisitQueryFromClause(QueryFromClause queryFromClause)
{
if (queryFromClause.Parent.FirstChild != queryFromClause) {
HandleMethod(queryFromClause);
} else {
base.VisitQueryFromClause(queryFromClause);
}
}
public override void VisitQueryGroupClause(QueryGroupClause queryGroupClause)
{
var annotation = queryGroupClause.Annotation<QueryGroupClauseAnnotation>();
if (annotation == null) {
base.VisitQueryGroupClause(queryGroupClause);
return;
}
HandleMethod(queryGroupClause.Projection, annotation.ProjectionLambda);
HandleMethod(queryGroupClause.Key, annotation.KeyLambda);
}
public override void VisitQueryJoinClause(QueryJoinClause queryJoinClause)
{
var annotation = queryJoinClause.Annotation<QueryJoinClauseAnnotation>();
if (annotation == null) {
base.VisitQueryJoinClause(queryJoinClause);
return;
}
HandleMethod(queryJoinClause.OnExpression, annotation.OnLambda);
HandleMethod(queryJoinClause.EqualsExpression, annotation.EqualsLambda);
}
public override void VisitQueryLetClause(QueryLetClause queryLetClause)
{
HandleMethod(queryLetClause);
}
public override void VisitQueryOrdering(QueryOrdering queryOrdering)
{
HandleMethod(queryOrdering);
}
public override void VisitQuerySelectClause(QuerySelectClause querySelectClause)
{
HandleMethod(querySelectClause);
@ -144,11 +185,15 @@ namespace ICSharpCode.Decompiler.DebugInfo @@ -144,11 +185,15 @@ namespace ICSharpCode.Decompiler.DebugInfo
}
void HandleMethod(AstNode node)
{
HandleMethod(node, node.Annotation<ILFunction>());
}
void HandleMethod(AstNode node, ILFunction function)
{
// Look into method body, e.g. in order to find lambdas
VisitChildren(node);
var function = node.Annotation<ILFunction>();
if (function == null || function.Method == null || function.Method.MetadataToken.IsNil)
return;
this.functions.Add(function);

1
ICSharpCode.Decompiler/DebugInfo/PortablePdbWriter.cs

@ -297,7 +297,6 @@ namespace ICSharpCode.Decompiler.DebugInfo @@ -297,7 +297,6 @@ namespace ICSharpCode.Decompiler.DebugInfo
{
StringWriter w = new StringWriter();
TokenWriter tokenWriter = new TextWriterTokenWriter(w);
syntaxTree.AcceptVisitor(new InsertParenthesesVisitor { InsertParenthesesForReadability = true });
tokenWriter = TokenWriter.WrapInWriterThatSetsLocationsInAST(tokenWriter);
syntaxTree.AcceptVisitor(new CSharpOutputVisitor(tokenWriter, settings.CSharpFormattingOptions));
return w.ToString();

6
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -61,6 +61,7 @@ @@ -61,6 +61,7 @@
<Compile Include="CSharp\Annotations.cs" />
<Compile Include="CSharp\CallBuilder.cs" />
<Compile Include="CSharp\CSharpLanguageVersion.cs" />
<Compile Include="CSharp\OutputVisitor\GenericGrammarAmbiguityVisitor.cs" />
<Compile Include="CSharp\RequiredNamespaceCollector.cs" />
<Compile Include="CSharp\SequencePointBuilder.cs" />
<Compile Include="CSharp\TranslatedStatement.cs" />
@ -625,9 +626,12 @@ @@ -625,9 +626,12 @@
</ItemGroup>
<Target Name="ILSpyUpdateAssemblyInfo" BeforeTargets="BeforeBuild">
<PropertyGroup>
<PropertyGroup Condition=" '$(OS)' == 'Windows_NT' ">
<UpdateAssemblyInfo>powershell -NoProfile -ExecutionPolicy Bypass -File BuildTools/update-assemblyinfo.ps1 $(Configuration)</UpdateAssemblyInfo>
</PropertyGroup>
<PropertyGroup Condition=" '$(OS)' != 'Windows_NT' ">
<UpdateAssemblyInfo>pwsh -NoProfile -ExecutionPolicy Bypass -File BuildTools/update-assemblyinfo.ps1 $(Configuration)</UpdateAssemblyInfo>
</PropertyGroup>
<Exec WorkingDirectory=".." Command="$(UpdateAssemblyInfo)" Timeout="60000" />
</Target>

81
ICSharpCode.Decompiler/IL/ControlFlow/DetectPinnedRegions.cs

@ -95,7 +95,8 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -95,7 +95,8 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
for (int j = 0; j < block.Instructions.Count - 1; j++) {
var inst = block.Instructions[j];
ILVariable v;
if (inst.MatchStLoc(out v) && v.Kind == VariableKind.PinnedLocal && block.Instructions[j + 1].OpCode != OpCode.Branch) {
if (inst.MatchStLoc(out v) && v.Kind == VariableKind.PinnedLocal) {
if (block.Instructions[j + 1].OpCode != OpCode.Branch) {
// split block after j:
context.Step("Split block after pinned local write", inst);
var newBlock = new Block();
@ -107,6 +108,18 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -107,6 +108,18 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
block.Instructions.Add(new Branch(newBlock));
container.Blocks.Insert(i + 1, newBlock);
}
if (j > 0) {
// split block before j:
context.Step("Split block before pinned local write", inst);
var newBlock = new Block();
newBlock.Instructions.Add(block.Instructions[j]);
newBlock.Instructions.Add(block.Instructions[j + 1]);
Debug.Assert(block.Instructions.Count == j + 2);
block.Instructions.RemoveRange(j, 2);
block.Instructions.Insert(j, new Branch(newBlock));
container.Blocks.Insert(i + 1, newBlock);
}
}
}
}
}
@ -347,8 +360,17 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -347,8 +360,17 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
ILInstruction value;
if (block.Instructions.Count != 2)
return false;
if (!block.Instructions[0].MatchStLoc(p, out value))
if (!block.Instructions[0].MatchStLoc(out var p2, out value))
return false;
if (p != p2) {
// If the pointer is unused, the variable P might have been split.
if (p.LoadCount == 0 && p.AddressCount == 0 && p2.LoadCount == 0 && p2.AddressCount == 0) {
if (!ILVariableEqualityComparer.Instance.Equals(p, p2))
return false;
} else {
return false;
}
}
if (v.Kind == VariableKind.PinnedLocal) {
value = value.UnwrapConv(ConversionKind.StopGCTracking);
}
@ -411,26 +433,21 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -411,26 +433,21 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
// we didn't find a single block to be added to the pinned region
return false;
}
if (entryBlock.Instructions[0].MatchStLoc(stLoc.Variable, out _)) {
// pinned region has empty body
} else {
reachedEdgesPerBlock[entryBlock.ChildIndex]++;
workList.Enqueue(entryBlock);
}
while (workList.Count > 0) {
Block workItem = workList.Dequeue();
StLoc workStLoc = workItem.Instructions.SecondToLastOrDefault() as StLoc;
int instructionCount;
if (workStLoc != null && workStLoc.Variable == stLoc.Variable && IsNullOrZero(workStLoc.Value)) {
// found unpin instruction: only consider branches prior to that instruction
instructionCount = workStLoc.ChildIndex;
} else {
instructionCount = workItem.Instructions.Count;
}
for (int i = 0; i < instructionCount; i++) {
foreach (var branch in workItem.Instructions[i].Descendants.OfType<Branch>()) {
foreach (var branch in workItem.Descendants.OfType<Branch>()) {
if (branch.TargetBlock.Parent == sourceContainer) {
if (branch.TargetBlock == block) {
// pin instruction is within a loop, and can loop around without an unpin instruction
// This should never happen for C#-compiled code, but may happen with C++/CLI code.
return false;
if (branch.TargetBlock.Instructions[0].MatchStLoc(stLoc.Variable, out _)) {
// Found unpin instruction
continue;
}
Debug.Assert(branch.TargetBlock != block);
if (reachedEdgesPerBlock[branch.TargetBlock.ChildIndex]++ == 0) {
// detected first edge to that block: add block as work item
workList.Enqueue(branch.TargetBlock);
@ -438,7 +455,6 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -438,7 +455,6 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
}
}
}
}
// Validate that all uses of a block consistently are inside or outside the pinned region.
// (we cannot do this anymore after we start moving blocks around)
@ -454,12 +470,14 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -454,12 +470,14 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
if (reachedEdgesPerBlock[i] > 0) {
var innerBlock = sourceContainer.Blocks[i];
Branch br = innerBlock.Instructions.LastOrDefault() as Branch;
if (br != null && br.TargetContainer == sourceContainer && reachedEdgesPerBlock[br.TargetBlock.ChildIndex] == 0) {
if (br != null && br.TargetBlock.IncomingEdgeCount == 1
&& br.TargetContainer == sourceContainer && reachedEdgesPerBlock[br.TargetBlock.ChildIndex] == 0)
{
// branch that leaves body.
// Should have an instruction that resets the pin; delete that instruction:
StLoc innerStLoc = innerBlock.Instructions.SecondToLastOrDefault() as StLoc;
if (innerStLoc != null && innerStLoc.Variable == stLoc.Variable && IsNullOrZero(innerStLoc.Value)) {
innerBlock.Instructions.RemoveAt(innerBlock.Instructions.Count - 2);
// The target block should have an instruction that resets the pin; delete that instruction:
StLoc unpin = br.TargetBlock.Instructions.First() as StLoc;
if (unpin != null && unpin.Variable == stLoc.Variable && IsNullOrZero(unpin.Value)) {
br.TargetBlock.Instructions.RemoveAt(0);
}
}
@ -468,6 +486,14 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -468,6 +486,14 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
// we'll delete the dummy block later
}
}
if (body.Blocks.Count == 0) {
// empty body, the entryBlock itself doesn't belong into the pinned region
Debug.Assert(reachedEdgesPerBlock[entryBlock.ChildIndex] == 0);
var bodyBlock = new Block();
bodyBlock.SetILRange(stLoc);
bodyBlock.Instructions.Add(new Branch(entryBlock));
body.Blocks.Add(bodyBlock);
}
var pinnedRegion = new PinnedRegion(stLoc.Variable, stLoc.Value, body).WithILRange(stLoc);
stLoc.ReplaceWith(pinnedRegion);
@ -546,6 +572,8 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -546,6 +572,8 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
return; // variable access that is not LdLoc
}
}
if (ldloc == null)
return;
if (!(ldloc.Parent is GetPinnableReference arrayToPointer))
return;
if (!(arrayToPointer.Parent is Conv conv && conv.Kind == ConversionKind.StopGCTracking))
@ -642,20 +670,25 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -642,20 +670,25 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
return;
if (!IsBranchOnNull(body.EntryPoint.Instructions[1], nativeVar, out Block targetBlock))
return;
if (targetBlock.Parent != body)
return;
if (!body.EntryPoint.Instructions[2].MatchBranch(out Block adjustOffsetToStringData))
return;
if (!(adjustOffsetToStringData.Parent == body && adjustOffsetToStringData.IncomingEdgeCount == 1
&& IsOffsetToStringDataBlock(adjustOffsetToStringData, nativeVar, targetBlock)))
return;
context.Step("Handle pinned string (with adjustOffsetToStringData)", pinnedRegion);
if (targetBlock.Parent == body) {
// remove old entry point
body.Blocks.RemoveAt(0);
body.Blocks.RemoveAt(adjustOffsetToStringData.ChildIndex);
// make targetBlock the new entry point
body.Blocks.RemoveAt(targetBlock.ChildIndex);
body.Blocks.Insert(0, targetBlock);
} else {
// pinned region has empty body, immediately jumps to targetBlock which is outside
body.Blocks[0].Instructions.Clear();
body.Blocks.RemoveRange(1, body.Blocks.Count - 1);
body.Blocks[0].Instructions.Add(new Branch(targetBlock));
}
pinnedRegion.Init = new GetPinnableReference(pinnedRegion.Init, null);
ILVariable otherVar;

23
ICSharpCode.Decompiler/IL/Transforms/AssignVariableNames.cs

@ -20,12 +20,8 @@ using System; @@ -20,12 +20,8 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Humanizer;
using ICSharpCode.Decompiler.CSharp.OutputVisitor;
using ICSharpCode.Decompiler.IL;
using ICSharpCode.Decompiler.Semantics;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.TypeSystem.Implementation;
using ICSharpCode.Decompiler.Util;
@ -141,6 +137,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -141,6 +137,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// remove unused variables before assigning names
function.Variables.RemoveDead();
int numDisplayClassLocals = 0;
Dictionary<int, string> assignedLocalSignatureIndices = new Dictionary<int, string>();
foreach (var v in function.Variables.OrderBy(v => v.Name)) {
switch (v.Kind) {
case VariableKind.Parameter: // ignore
@ -151,7 +148,24 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -151,7 +148,24 @@ namespace ICSharpCode.Decompiler.IL.Transforms
case VariableKind.DisplayClassLocal:
v.Name = "CS$<>8__locals" + (numDisplayClassLocals++);
break;
case VariableKind.Local when v.Index != null:
if (assignedLocalSignatureIndices.TryGetValue(v.Index.Value, out string name)) {
// make sure all local ILVariables that refer to the same slot in the locals signature
// are assigned the same name.
v.Name = name;
} else {
AssignName();
// Remember the newly assigned name:
assignedLocalSignatureIndices.Add(v.Index.Value, v.Name);
}
break;
default:
AssignName();
break;
}
void AssignName()
{
if (v.HasGeneratedName || !IsValidName(v.Name) || ConflictWithLocal(v)) {
// don't use the name from the debug symbols if it looks like a generated name
v.Name = null;
@ -160,7 +174,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -160,7 +174,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// (but ensure we don't use the same name for two variables)
v.Name = GetAlternativeName(v.Name);
}
break;
}
}
foreach (var localFunction in function.LocalFunctions) {

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

@ -31,11 +31,16 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -31,11 +31,16 @@ namespace ICSharpCode.Decompiler.IL.Transforms
{
ILTransformContext context;
ITypeResolveContext decompilationContext;
readonly Stack<MethodDefinitionHandle> activeMethods = new Stack<MethodDefinitionHandle>();
void IILTransform.Run(ILFunction function, ILTransformContext context)
{
if (!context.Settings.AnonymousMethods)
return;
var prevContext = this.context;
var prevDecompilationContext = this.decompilationContext;
try {
activeMethods.Push((MethodDefinitionHandle)function.Method.MetadataToken);
this.context = context;
this.decompilationContext = new SimpleTypeResolveContext(function.Method);
var cancellationToken = context.CancellationToken;
@ -58,6 +63,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -58,6 +63,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms
context.StepEndGroup();
}
}
} finally {
this.context = prevContext;
this.decompilationContext = prevDecompilationContext;
activeMethods.Pop();
}
}
internal static bool IsDelegateConstruction(NewObj inst, bool allowTransformed = false)
@ -131,6 +141,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -131,6 +141,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (LocalFunctionDecompiler.IsLocalFunctionMethod(targetMethod, context))
return null;
target = value.Arguments[0];
var handle = (MethodDefinitionHandle)targetMethod.MetadataToken;
if (activeMethods.Contains(handle)) {
this.context.Function.Warnings.Add(" Found self-referencing delegate construction. Abort transformation to avoid stack overflow.");
return null;
}
var methodDefinition = context.PEFile.Metadata.GetMethodDefinition((MethodDefinitionHandle)targetMethod.MetadataToken);
if (!methodDefinition.HasBody())
return null;
@ -157,7 +172,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -157,7 +172,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
function.AcceptVisitor(new ReplaceDelegateTargetVisitor(target, function.Variables.SingleOrDefault(v => v.Index == -1 && v.Kind == VariableKind.Parameter)));
// handle nested lambdas
nestedContext.StepStartGroup("DelegateConstruction (nested lambdas)", function);
((IILTransform)new DelegateConstruction()).Run(function, nestedContext);
((IILTransform)this).Run(function, nestedContext);
nestedContext.StepEndGroup();
function.AddILRange(target);
function.AddILRange(value);

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

@ -84,7 +84,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -84,7 +84,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms
containingBlock.Instructions.Remove(store);
}
}
RemoveDeadVariableInit.ResetHasInitialValueFlag(function, context);
foreach (var f in TreeTraversal.PostOrder(function, f => f.LocalFunctions))
RemoveDeadVariableInit.ResetHasInitialValueFlag(f, context);
} finally {
instructionsToRemove.Clear();
displayClasses.Clear();
@ -96,6 +97,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -96,6 +97,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms
private bool CanRemoveAllReferencesTo(ILTransformContext context, ILVariable v)
{
foreach (var use in v.LoadInstructions) {
// we only accept stloc, stobj/ldobj and ld(s)flda instructions,
// as these are required by all patterns this transform understands.
if (!(use.Parent is StLoc || use.Parent is LdFlda || use.Parent is LdsFlda || use.Parent is StObj || use.Parent is LdObj)) {
return false;
}
if (use.Parent.MatchStLoc(out var targetVar) && !IsClosure(context, targetVar, out _, out _)) {
return false;
}

21
ICSharpCode.Decompiler/Solution/ProjectId.cs

@ -32,24 +32,43 @@ namespace ICSharpCode.Decompiler.Solution @@ -32,24 +32,43 @@ namespace ICSharpCode.Decompiler.Solution
/// <param name="projectGuid">The project GUID.</param>
///
/// <exception cref="ArgumentException">Thrown when <paramref name="projectPlatform"/> is null or empty.</exception>
public ProjectId(string projectPlatform, Guid projectGuid)
public ProjectId(string projectPlatform, Guid projectGuid, Guid typeGuid)
{
if (string.IsNullOrWhiteSpace(projectPlatform)) {
throw new ArgumentException("The platform cannot be null or empty.", nameof(projectPlatform));
}
Guid = projectGuid;
TypeGuid = typeGuid;
PlatformName = projectPlatform;
}
/// <summary>
/// Gets the GUID of this project.
/// This is usually a newly generated GUID for each decompiled project.
/// </summary>
public Guid Guid { get; }
/// <summary>
/// Gets the primary type GUID of this project.
/// This is one of the GUIDs from <see cref="ProjectTypeGuids"/>.
/// </summary>
public Guid TypeGuid { get; }
/// <summary>
/// Gets the platform name of this project. Only single platform per project is supported.
/// </summary>
public string PlatformName { get; }
}
public static class ProjectTypeGuids
{
public static readonly Guid SolutionFolder = Guid.Parse("{2150E333-8FDC-42A3-9474-1A3956D46DE8}");
public static readonly Guid CSharpWindows = Guid.Parse("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}");
public static readonly Guid CSharpCore = Guid.Parse("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}");
public static readonly Guid Silverlight = Guid.Parse("{A1591282-1198-4647-A2B1-27E5FF5F6F3B}");
public static readonly Guid PortableLibrary = Guid.Parse("{786C830F-07A1-408B-BD7F-6EE04809D6DB}");
}
}

4
ICSharpCode.Decompiler/Solution/ProjectItem.cs

@ -35,8 +35,8 @@ namespace ICSharpCode.Decompiler.Solution @@ -35,8 +35,8 @@ namespace ICSharpCode.Decompiler.Solution
///
/// <exception cref="ArgumentException">Thrown when <paramref name="projectFile"/>
/// or <paramref name="projectPlatform"/> is null or empty.</exception>
public ProjectItem(string projectFile, string projectPlatform, Guid projectGuid)
: base(projectPlatform, projectGuid)
public ProjectItem(string projectFile, string projectPlatform, Guid projectGuid, Guid typeGuid)
: base(projectPlatform, projectGuid, typeGuid)
{
ProjectName = Path.GetFileNameWithoutExtension(projectFile);
FilePath = projectFile;

5
ICSharpCode.Decompiler/Solution/SolutionCreator.cs

@ -88,13 +88,12 @@ namespace ICSharpCode.Decompiler.Solution @@ -88,13 +88,12 @@ namespace ICSharpCode.Decompiler.Solution
private static void WriteProjects(TextWriter writer, IEnumerable<ProjectItem> projects, string solutionFilePath)
{
var solutionGuid = Guid.NewGuid().ToString("B").ToUpperInvariant();
foreach (var project in projects) {
var projectRelativePath = GetRelativePath(solutionFilePath, project.FilePath);
var typeGuid = project.TypeGuid.ToString("B").ToUpperInvariant();
var projectGuid = project.Guid.ToString("B").ToUpperInvariant();
writer.WriteLine($"Project(\"{solutionGuid}\") = \"{project.ProjectName}\", \"{projectRelativePath}\", \"{projectGuid}\"");
writer.WriteLine($"Project(\"{typeGuid}\") = \"{project.ProjectName}\", \"{projectRelativePath}\", \"{projectGuid}\"");
writer.WriteLine("EndProject");
}
}

1
ILSpy/Analyzers/AnalyzerScope.cs

@ -84,7 +84,6 @@ namespace ICSharpCode.ILSpy.Analyzers @@ -84,7 +84,6 @@ namespace ICSharpCode.ILSpy.Analyzers
public IEnumerable<ITypeDefinition> GetTypesInScope(CancellationToken ct)
{
if (IsLocal) {
var typeSystem = new DecompilerTypeSystem(TypeScope.ParentModule.PEFile, TypeScope.ParentModule.PEFile.GetAssemblyResolver());
foreach (var type in TreeTraversal.PreOrder(typeScope, t => t.NestedTypes)) {
yield return type;
}

1
ILSpy/AssemblyList.cs

@ -146,6 +146,7 @@ namespace ICSharpCode.ILSpy @@ -146,6 +146,7 @@ namespace ICSharpCode.ILSpy
internal void ClearCache()
{
assemblyLookupCache.Clear();
moduleLookupCache.Clear();
}
public LoadedAssembly Open(string assemblyUri, bool isAutoLoaded = false)

1
ILSpy/DebugInfo/DebugInfoUtils.cs

@ -32,7 +32,6 @@ namespace ICSharpCode.Decompiler.PdbProvider @@ -32,7 +32,6 @@ namespace ICSharpCode.Decompiler.PdbProvider
public static IDebugInfoProvider LoadSymbols(PEFile module)
{
try {
var reader = module.Reader;
// try to open portable pdb file/embedded pdb info:
if (TryOpenPortablePdb(module, out var provider, out var pdbFileName)) {
return new PortableDebugInfoProvider(pdbFileName, provider);

1
ILSpy/Languages/ILAstLanguage.cs

@ -121,7 +121,6 @@ namespace ICSharpCode.ILSpy @@ -121,7 +121,6 @@ namespace ICSharpCode.ILSpy
reader.UseDebugSymbols = options.DecompilerSettings.UseDebugSymbols;
var methodBody = module.Reader.GetMethodBody(methodDef.RelativeVirtualAddress);
ILFunction il = reader.ReadIL((SRM.MethodDefinitionHandle)method.MetadataToken, methodBody, kind: ILFunctionKind.TopLevelFunction, cancellationToken: options.CancellationToken);
var namespaces = new HashSet<string>();
var decompiler = new CSharpDecompiler(typeSystem, options.DecompilerSettings) { CancellationToken = options.CancellationToken };
ILTransformContext context = decompiler.CreateILTransformContext(il);
context.Stepper.StepLimit = options.StepLimit;

3
ILSpy/Languages/Language.cs

@ -489,9 +489,6 @@ namespace ICSharpCode.ILSpy @@ -489,9 +489,6 @@ namespace ICSharpCode.ILSpy
public virtual CodeMappingInfo GetCodeMappingInfo(PEFile module, SRM.EntityHandle member)
{
var parts = new Dictionary<SRM.MethodDefinitionHandle, SRM.MethodDefinitionHandle[]>();
var locations = new Dictionary<SRM.EntityHandle, SRM.MethodDefinitionHandle>();
var declaringType = member.GetDeclaringType(module.Metadata);
if (declaringType.IsNil && member.Kind == SRM.HandleKind.TypeDefinition) {

15
ILSpy/LoadedAssembly.cs

@ -141,12 +141,17 @@ namespace ICSharpCode.ILSpy @@ -141,12 +141,17 @@ namespace ICSharpCode.ILSpy
get {
if (IsLoaded && !HasLoadError) {
var metadata = GetPEFileOrNull()?.Metadata;
string version = null;
if (metadata != null && metadata.IsAssembly)
version = metadata.GetAssemblyDefinition().Version?.ToString();
if (version == null)
string versionOrInfo = null;
if (metadata != null) {
if (metadata.IsAssembly) {
versionOrInfo = metadata.GetAssemblyDefinition().Version?.ToString();
} else {
versionOrInfo = ".netmodule";
}
}
if (versionOrInfo == null)
return ShortName;
return String.Format("{0} ({1})", ShortName, version);
return string.Format("{0} ({1})", ShortName, versionOrInfo);
} else {
return ShortName;
}

1
ILSpy/Metadata/CorTables/GenericParamTableTreeNode.cs

@ -45,7 +45,6 @@ namespace ICSharpCode.ILSpy.Metadata @@ -45,7 +45,6 @@ namespace ICSharpCode.ILSpy.Metadata
tabPage.SupportsLanguageSwitching = false;
var view = Helpers.PrepareDataGrid(tabPage, this);
var metadata = module.Metadata;
var list = new List<GenericParamEntry>();
GenericParamEntry scrollTargetEntry = default;

1
ILSpy/Metadata/CorTables/MethodImplTableTreeNode.cs

@ -44,7 +44,6 @@ namespace ICSharpCode.ILSpy.Metadata @@ -44,7 +44,6 @@ namespace ICSharpCode.ILSpy.Metadata
tabPage.SupportsLanguageSwitching = false;
var view = Helpers.PrepareDataGrid(tabPage, this);
var metadata = module.Metadata;
var list = new List<MethodImplEntry>();
MethodImplEntry scrollTargetEntry = default;

1
ILSpy/Metadata/CorTables/ModuleTableTreeNode.cs

@ -42,7 +42,6 @@ namespace ICSharpCode.ILSpy.Metadata @@ -42,7 +42,6 @@ namespace ICSharpCode.ILSpy.Metadata
tabPage.SupportsLanguageSwitching = false;
var view = Helpers.PrepareDataGrid(tabPage, this);
var metadata = module.Metadata;
var list = new List<ModuleEntry>();
ModuleEntry scrollTargetEntry = default;

1
ILSpy/Metadata/CorTables/ParamTableTreeNode.cs

@ -43,7 +43,6 @@ namespace ICSharpCode.ILSpy.Metadata @@ -43,7 +43,6 @@ namespace ICSharpCode.ILSpy.Metadata
tabPage.SupportsLanguageSwitching = false;
var view = Helpers.PrepareDataGrid(tabPage, this);
var metadata = module.Metadata;
var list = new List<ParamEntry>();
ParamEntry scrollTargetEntry = default;

1
ILSpy/Metadata/CorTables/StandAloneSigTableTreeNode.cs

@ -44,7 +44,6 @@ namespace ICSharpCode.ILSpy.Metadata @@ -44,7 +44,6 @@ namespace ICSharpCode.ILSpy.Metadata
tabPage.SupportsLanguageSwitching = false;
var view = Helpers.PrepareDataGrid(tabPage, this);
var metadata = module.Metadata;
var list = new List<StandAloneSigEntry>();
StandAloneSigEntry scrollTargetEntry = default;

12
ILSpy/Metadata/DebugMetadataTreeNode.cs

@ -18,8 +18,10 @@ @@ -18,8 +18,10 @@
using System.Linq;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.ILSpy.Options;
using ICSharpCode.ILSpy.TreeNodes;
using ICSharpCode.ILSpy.ViewModels;
@ -61,14 +63,24 @@ namespace ICSharpCode.ILSpy.Metadata @@ -61,14 +63,24 @@ namespace ICSharpCode.ILSpy.Metadata
protected override void LoadChildren()
{
if (ShowTable(TableIndex.Document))
this.Children.Add(new DocumentTableTreeNode(this.module, this.provider, isEmbedded));
if (ShowTable(TableIndex.MethodDebugInformation))
this.Children.Add(new MethodDebugInformationTableTreeNode(this.module, this.provider, isEmbedded));
if (ShowTable(TableIndex.LocalScope))
this.Children.Add(new LocalScopeTableTreeNode(this.module, this.provider, isEmbedded));
if (ShowTable(TableIndex.LocalVariable))
this.Children.Add(new LocalVariableTableTreeNode(this.module, this.provider, isEmbedded));
if (ShowTable(TableIndex.LocalConstant))
this.Children.Add(new LocalConstantTableTreeNode(this.module, this.provider, isEmbedded));
if (ShowTable(TableIndex.ImportScope))
this.Children.Add(new ImportScopeTableTreeNode(this.module, this.provider, isEmbedded));
if (ShowTable(TableIndex.StateMachineMethod))
this.Children.Add(new StateMachineMethodTableTreeNode(this.module, this.provider, isEmbedded));
if (ShowTable(TableIndex.CustomDebugInformation))
this.Children.Add(new CustomDebugInformationTableTreeNode(this.module, this.provider, isEmbedded));
bool ShowTable(TableIndex table) => !DisplaySettingsPanel.CurrentDisplaySettings.HideEmptyMetadataTables || module.Metadata.GetTableRowCount(table) > 0;
}
public MetadataTableTreeNode FindNodeByHandleKind(HandleKind kind)

40
ILSpy/Metadata/MetadataTreeNode.cs

@ -21,6 +21,7 @@ using System.Collections.Generic; @@ -21,6 +21,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using System.Reflection.PortableExecutable;
using System.Text;
using System.Threading.Tasks;
@ -28,6 +29,7 @@ using System.Windows; @@ -28,6 +29,7 @@ using System.Windows;
using System.Windows.Data;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.ILSpy.Options;
using ICSharpCode.ILSpy.TreeNodes;
using ICSharpCode.ILSpy.ViewModels;
@ -68,40 +70,76 @@ namespace ICSharpCode.ILSpy.Metadata @@ -68,40 +70,76 @@ namespace ICSharpCode.ILSpy.Metadata
this.Children.Add(new CoffHeaderTreeNode(module));
this.Children.Add(new OptionalHeaderTreeNode(module));
this.Children.Add(new DataDirectoriesTreeNode(module));
if (ShowTable(TableIndex.Module))
this.Children.Add(new ModuleTableTreeNode(module));
if (ShowTable(TableIndex.TypeRef))
this.Children.Add(new TypeRefTableTreeNode(module));
if (ShowTable(TableIndex.TypeDef))
this.Children.Add(new TypeDefTableTreeNode(module));
if (ShowTable(TableIndex.Field))
this.Children.Add(new FieldTableTreeNode(module));
if (ShowTable(TableIndex.MethodDef))
this.Children.Add(new MethodTableTreeNode(module));
if (ShowTable(TableIndex.Param))
this.Children.Add(new ParamTableTreeNode(module));
if (ShowTable(TableIndex.InterfaceImpl))
this.Children.Add(new InterfaceImplTableTreeNode(module));
if (ShowTable(TableIndex.MemberRef))
this.Children.Add(new MemberRefTableTreeNode(module));
if (ShowTable(TableIndex.Constant))
this.Children.Add(new ConstantTableTreeNode(module));
if (ShowTable(TableIndex.CustomAttribute))
this.Children.Add(new CustomAttributeTableTreeNode(module));
if (ShowTable(TableIndex.FieldMarshal))
this.Children.Add(new FieldMarshalTableTreeNode(module));
if (ShowTable(TableIndex.DeclSecurity))
this.Children.Add(new DeclSecurityTableTreeNode(module));
if (ShowTable(TableIndex.ClassLayout))
this.Children.Add(new ClassLayoutTableTreeNode(module));
if (ShowTable(TableIndex.FieldLayout))
this.Children.Add(new FieldLayoutTableTreeNode(module));
if (ShowTable(TableIndex.StandAloneSig))
this.Children.Add(new StandAloneSigTableTreeNode(module));
if (ShowTable(TableIndex.EventMap))
this.Children.Add(new EventMapTableTreeNode(module));
if (ShowTable(TableIndex.Event))
this.Children.Add(new EventTableTreeNode(module));
if (ShowTable(TableIndex.PropertyMap))
this.Children.Add(new PropertyMapTableTreeNode(module));
if (ShowTable(TableIndex.Property))
this.Children.Add(new PropertyTableTreeNode(module));
if (ShowTable(TableIndex.MethodSemantics))
this.Children.Add(new MethodSemanticsTableTreeNode(module));
if (ShowTable(TableIndex.MethodImpl))
this.Children.Add(new MethodImplTableTreeNode(module));
if (ShowTable(TableIndex.ModuleRef))
this.Children.Add(new ModuleRefTableTreeNode(module));
if (ShowTable(TableIndex.TypeSpec))
this.Children.Add(new TypeSpecTableTreeNode(module));
this.Children.Add(new ImplMapTableTreeNode(module)); ;
if (ShowTable(TableIndex.ImplMap))
this.Children.Add(new ImplMapTableTreeNode(module));
if (ShowTable(TableIndex.FieldRva))
this.Children.Add(new FieldRVATableTreeNode(module));
if (ShowTable(TableIndex.Assembly))
this.Children.Add(new AssemblyTableTreeNode(module));
if (ShowTable(TableIndex.AssemblyRef))
this.Children.Add(new AssemblyRefTableTreeNode(module));
if (ShowTable(TableIndex.File))
this.Children.Add(new FileTableTreeNode(module));
if (ShowTable(TableIndex.ExportedType))
this.Children.Add(new ExportedTypeTableTreeNode(module));
if (ShowTable(TableIndex.ManifestResource))
this.Children.Add(new ManifestResourceTableTreeNode(module));
if (ShowTable(TableIndex.NestedClass))
this.Children.Add(new NestedClassTableTreeNode(module));
if (ShowTable(TableIndex.GenericParam))
this.Children.Add(new GenericParamTableTreeNode(module));
if (ShowTable(TableIndex.MethodSpec))
this.Children.Add(new MethodSpecTableTreeNode(module));
if (ShowTable(TableIndex.GenericParamConstraint))
this.Children.Add(new GenericParamConstraintTableTreeNode(module));
bool ShowTable(TableIndex table) => !DisplaySettingsPanel.CurrentDisplaySettings.HideEmptyMetadataTables || module.Metadata.GetTableRowCount(table) > 0;
}
public MetadataTableTreeNode FindNodeByHandleKind(HandleKind kind)

4
ILSpy/Metadata/OptionalHeaderTreeNode.cs

@ -65,8 +65,8 @@ namespace ICSharpCode.ILSpy.Metadata @@ -65,8 +65,8 @@ namespace ICSharpCode.ILSpy.Metadata
entries.Add(new Entry(reader.Offset, reader.ReadByte(), 1, "Major Linker Version", ""));
entries.Add(new Entry(reader.Offset, reader.ReadByte(), 1, "Minor Linker Version", ""));
entries.Add(new Entry(reader.Offset, reader.ReadInt32(), 4, "Code Size", "Size of the code (text) section, or the sum of all code sections if there are multiple sections."));
entries.Add(new Entry(reader.Offset, reader.ReadInt32(), 4, "Initialized Data Size", "Size of the initialized data section, or the sum of all code sections if there are multiple data sections."));
entries.Add(new Entry(reader.Offset, reader.ReadInt32(), 4, "Uninitialized Data Size", "Size of the uninitialized data section, or the sum of all code sections if there are multiple uninitialized data sections."));
entries.Add(new Entry(reader.Offset, reader.ReadInt32(), 4, "Initialized Data Size", "Size of the initialized data section, or the sum of all initialized data sections if there are multiple data sections."));
entries.Add(new Entry(reader.Offset, reader.ReadInt32(), 4, "Uninitialized Data Size", "Size of the uninitialized data section, or the sum of all uninitialized data sections if there are multiple uninitialized data sections."));
entries.Add(new Entry(reader.Offset, reader.ReadInt32(), 4, "Entry Point RVA", "RVA of entry point, needs to point to bytes 0xFF 0x25 followed by the RVA in a section marked execute / read for EXEs or 0 for DLLs"));
entries.Add(new Entry(reader.Offset, reader.ReadInt32(), 4, "Base Of Code", "RVA of the code section."));
entries.Add(new Entry(reader.Offset, header.Magic == PEMagic.PE32Plus ? reader.ReadUInt64() : reader.ReadUInt32(), header.Magic == PEMagic.PE32Plus ? 8 : 4, "Base Of Data", "RVA of the data section."));

13
ILSpy/Options/DisplaySettings.cs

@ -234,6 +234,18 @@ namespace ICSharpCode.ILSpy.Options @@ -234,6 +234,18 @@ namespace ICSharpCode.ILSpy.Options
}
}
bool hideEmptyMetadataTables = true;
public bool HideEmptyMetadataTables {
get { return hideEmptyMetadataTables; }
set {
if (hideEmptyMetadataTables != value) {
hideEmptyMetadataTables = value;
OnPropertyChanged();
}
}
}
public void CopyValues(DisplaySettings s)
{
this.SelectedFont = s.selectedFont;
@ -251,6 +263,7 @@ namespace ICSharpCode.ILSpy.Options @@ -251,6 +263,7 @@ namespace ICSharpCode.ILSpy.Options
this.IndentationTabSize = s.indentationTabSize;
this.IndentationSize = s.indentationSize;
this.HighlightMatchingBraces = s.highlightMatchingBraces;
this.HideEmptyMetadataTables = s.HideEmptyMetadataTables;
}
}
}

1
ILSpy/Options/DisplaySettingsPanel.xaml

@ -77,6 +77,7 @@ @@ -77,6 +77,7 @@
<CheckBox IsChecked="{Binding ShowLineNumbers}" Content="{x:Static properties:Resources.ShowLineNumbers}"></CheckBox>
<CheckBox IsChecked="{Binding ShowMetadataTokens}" Content="{x:Static properties:Resources.ShowMetadataTokens}"></CheckBox>
<CheckBox IsChecked="{Binding ShowMetadataTokensInBase10}" Content="{x:Static properties:Resources.ShowMetadataTokensInBase10}"></CheckBox>
<CheckBox IsChecked="{Binding HideEmptyMetadataTables}" Content="{x:Static properties:Resources.HideEmptyMetadataTables}"></CheckBox>
<CheckBox IsChecked="{Binding ShowDebugInfo}" Content="{x:Static properties:Resources.ShowInfoFromDebugSymbolsAvailable}"></CheckBox>
<CheckBox IsChecked="{Binding EnableWordWrap}" Content="{x:Static properties:Resources.EnableWordWrap}"></CheckBox>
<CheckBox IsChecked="{Binding FoldBraces}" Content="{x:Static properties:Resources.EnableFoldingBlocksBraces}"></CheckBox>

2
ILSpy/Options/DisplaySettingsPanel.xaml.cs

@ -115,6 +115,7 @@ namespace ICSharpCode.ILSpy.Options @@ -115,6 +115,7 @@ namespace ICSharpCode.ILSpy.Options
s.IndentationSize = (int?)e.Attribute("IndentationSize") ?? 4;
s.IndentationTabSize = (int?)e.Attribute("IndentationTabSize") ?? 4;
s.HighlightMatchingBraces = (bool?)e.Attribute("HighlightMatchingBraces") ?? true;
s.HideEmptyMetadataTables = (bool?)e.Attribute("HideEmptyMetadataTables") ?? true;
return s;
}
@ -139,6 +140,7 @@ namespace ICSharpCode.ILSpy.Options @@ -139,6 +140,7 @@ namespace ICSharpCode.ILSpy.Options
section.SetAttributeValue("IndentationSize", s.IndentationSize);
section.SetAttributeValue("IndentationTabSize", s.IndentationTabSize);
section.SetAttributeValue("HighlightMatchingBraces", s.HighlightMatchingBraces);
section.SetAttributeValue("HideEmptyMetadataTables", s.HideEmptyMetadataTables);
XElement existingElement = root.Element("DisplaySettings");
if (existingElement != null)

9
ILSpy/Properties/Resources.Designer.cs generated

@ -1305,6 +1305,15 @@ namespace ICSharpCode.ILSpy.Properties { @@ -1305,6 +1305,15 @@ namespace ICSharpCode.ILSpy.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Hide empty metadata tables from tree view.
/// </summary>
public static string HideEmptyMetadataTables {
get {
return ResourceManager.GetString("HideEmptyMetadataTables", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Highlight matching braces.
/// </summary>

3
ILSpy/Properties/Resources.resx

@ -829,4 +829,7 @@ Are you sure you want to continue?</value> @@ -829,4 +829,7 @@ Are you sure you want to continue?</value>
<data name="DecompilerSettings.IntroduceStaticLocalFunctions" xml:space="preserve">
<value>Introduce static local functions</value>
</data>
<data name="HideEmptyMetadataTables" xml:space="preserve">
<value>Hide empty metadata tables from tree view</value>
</data>
</root>

2
ILSpy/SolutionWriter.cs

@ -171,7 +171,7 @@ namespace ICSharpCode.ILSpy @@ -171,7 +171,7 @@ namespace ICSharpCode.ILSpy
var projectInfo = language.DecompileAssembly(loadedAssembly, projectFileOutput, options);
if (projectInfo != null) {
projects.Add(new ProjectItem(projectFileName, projectInfo.PlatformName, projectInfo.Guid));
projects.Add(new ProjectItem(projectFileName, projectInfo.PlatformName, projectInfo.Guid, projectInfo.TypeGuid));
}
}
} catch (Exception e) when (!(e is OperationCanceledException)) {

1
ILSpy/TreeNodes/AssemblyTreeNode.cs

@ -141,7 +141,6 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -141,7 +141,6 @@ namespace ICSharpCode.ILSpy.TreeNodes
}
typeSystem = LoadedAssembly.GetTypeSystemOrNull(DecompilerTypeSystem.GetOptions(new DecompilationOptions().DecompilerSettings));
var assembly = (MetadataModule)typeSystem.MainModule;
var metadata = module.Metadata;
this.Children.Add(new Metadata.MetadataTreeNode(module, this));
Decompiler.DebugInfo.IDebugInfoProvider debugInfo = LoadedAssembly.GetDebugInfoOrNull();
if (debugInfo is Decompiler.PdbProvider.PortableDebugInfoProvider ppdb) {

1
README.md

@ -59,6 +59,7 @@ If this problem occurs, please manually install the .NET Core 3.1 SDK from [here @@ -59,6 +59,7 @@ If this problem occurs, please manually install the .NET Core 3.1 SDK from [here
Unix / Mac:
- Make sure .NET Core 2.1 LTS Runtime is installed (you can get it here: https://get.dot.net).
- Make sure [.NET Core 3.1 SDK](https://dotnet.microsoft.com/download/dotnet-core/3.1) is installed.
- Make sure [PowerShell](https://github.com/PowerShell/PowerShell) is installed (formerly known as PowerShell Core)
- 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 (.NET Core Global Tool and PowerShell Core).

13
SharpTreeView/SharpTreeNode.cs

@ -335,19 +335,14 @@ namespace ICSharpCode.TreeView @@ -335,19 +335,14 @@ namespace ICSharpCode.TreeView
public IEnumerable<SharpTreeNode> Ancestors()
{
var node = this;
while (node.Parent != null) {
yield return node.Parent;
node = node.Parent;
}
for (SharpTreeNode n = this.Parent; n != null; n = n.Parent)
yield return n;
}
public IEnumerable<SharpTreeNode> AncestorsAndSelf()
{
yield return this;
foreach (var node in Ancestors()) {
yield return node;
}
for (SharpTreeNode n = this; n != null; n = n.Parent)
yield return n;
}
#endregion

2
SharpTreeView/SharpTreeNodeView.cs

@ -147,7 +147,7 @@ namespace ICSharpCode.TreeView @@ -147,7 +147,7 @@ namespace ICSharpCode.TreeView
result -= 19;
}
if (result < 0) {
Debug.WriteLine("SharpTreeNodeView.CalculateIndent() on node without correctly-set level");
Debug.WriteLine("Negative indent level detected for node " + Node);
return 0;
}
return result;

15
SharpTreeView/SharpTreeView.cs

@ -178,7 +178,7 @@ namespace ICSharpCode.TreeView @@ -178,7 +178,7 @@ namespace ICSharpCode.TreeView
{
if (updatesLocked) return;
SetSelectedItems(newSelection ?? Enumerable.Empty<SharpTreeNode>());
if (SelectedItem == null) {
if (SelectedItem == null && this.IsKeyboardFocusWithin) {
// if we removed all selected nodes, then move the focus to the node
// preceding the first of the old selected nodes
SelectedIndex = topSelectedIndex;
@ -265,10 +265,23 @@ namespace ICSharpCode.TreeView @@ -265,10 +265,23 @@ namespace ICSharpCode.TreeView
}
break;
case Key.Return:
if (container != null && Keyboard.Modifiers == ModifierKeys.None && this.SelectedItems.Count == 1 && this.SelectedItem == container.Node) {
e.Handled = true;
container.Node.ActivateItem(e);
}
break;
case Key.Space:
if (container != null && Keyboard.Modifiers == ModifierKeys.None && this.SelectedItems.Count == 1 && this.SelectedItem == container.Node) {
e.Handled = true;
if (container.Node.IsCheckable) {
if (container.Node.IsChecked == null) // If partially selected, we want to select everything
container.Node.IsChecked = true;
else
container.Node.IsChecked = !container.Node.IsChecked;
} else {
container.Node.ActivateItem(e);
}
}
break;
case Key.Add:
if (container != null && ItemsControl.ItemsControlFromItemContainer(container) == this) {

11
SharpTreeView/SharpTreeViewItem.cs

@ -29,13 +29,16 @@ namespace ICSharpCode.TreeView @@ -29,13 +29,16 @@ namespace ICSharpCode.TreeView
{
switch (e.Key) {
case Key.F2:
// if (SharpTreeNode.ActiveNodes.Count == 1 && Node.IsEditable) {
// Node.IsEditing = true;
// e.Handled = true;
// }
if (Node.IsEditable && ParentTreeView != null && ParentTreeView.SelectedItems.Count == 1 && ParentTreeView.SelectedItems[0] == Node) {
Node.IsEditing = true;
e.Handled = true;
}
break;
case Key.Escape:
if (Node.IsEditing) {
Node.IsEditing = false;
e.Handled = true;
}
break;
}
}

2
SharpTreeView/Themes/Generic.xaml

@ -237,7 +237,7 @@ @@ -237,7 +237,7 @@
Style="{StaticResource ExpandCollapseToggleStyle}"
IsChecked="{Binding IsExpanded}"
Visibility="Hidden"
Margin="0 0 6 0"
Margin="0 0 7 0"
VerticalAlignment="Center" />
<Border Name="checkBoxContainer"
Width="16"

9
appveyor.yml

@ -8,7 +8,7 @@ image: Visual Studio 2019 @@ -8,7 +8,7 @@ image: Visual Studio 2019
install:
- git submodule update --init --recursive
- ps: .\BuildTools\appveyor-install.ps1
- pwsh .\BuildTools\appveyor-install.ps1
nuget:
account_feed: false
@ -24,11 +24,8 @@ build_script: @@ -24,11 +24,8 @@ build_script:
after_build:
- 7z a ILSpy_binaries.zip %APPVEYOR_BUILD_FOLDER%\ILSpy\bin\%configuration%\net472\*.dll %APPVEYOR_BUILD_FOLDER%\ILSpy\bin\%configuration%\net472\*.exe %APPVEYOR_BUILD_FOLDER%\ILSpy\bin\%configuration%\net472\*.config %APPVEYOR_BUILD_FOLDER%\ILSpy\bin\%configuration%\net472\*\ILSpy.resources.dll
test:
assemblies:
- 'ICSharpCode.Decompiler.Tests\bin\%configuration%\net472\ICSharpCode.Decompiler.Tests.exe'
- 'ILSpy.Tests\bin\%configuration%\net472\ILSpy.Tests.exe'
- 'ILSpy.BamlDecompiler.Tests\bin\%configuration%\net472\ILSpy.BamlDecompiler.Tests.dll'
test_script:
- vstest.console.exe /logger:Appveyor /Parallel "ICSharpCode.Decompiler.Tests\bin\%configuration%\net472\ICSharpCode.Decompiler.Tests.exe" "ILSpy.Tests\bin\%configuration%\net472\ILSpy.Tests.exe" "ILSpy.BamlDecompiler.Tests\bin\%configuration%\net472\ILSpy.BamlDecompiler.Tests.exe"
after_test:
- python BuildTools\tidy.py

4
azure-pipelines.yml

@ -45,7 +45,7 @@ jobs: @@ -45,7 +45,7 @@ jobs:
version: '3.1.100'
installationPath: $(Agent.ToolsDirectory)/dotnet
- powershell: .\BuildTools\pipelines-install.ps1
- script: pwsh .\BuildTools\pipelines-install.ps1
displayName: Install
- task: MSBuild@1
@ -71,7 +71,7 @@ jobs: @@ -71,7 +71,7 @@ jobs:
testAssemblyVer2: |
ICSharpCode.Decompiler.Tests\bin\$(BuildConfiguration)\net472\ICSharpCode.Decompiler.Tests.exe
ILSpy.Tests\bin\$(BuildConfiguration)\net472\ILSpy.Tests.exe
ILSpy.BamlDecompiler.Tests\bin\$(BuildConfiguration)\net472\ILSpy.BamlDecompiler.Tests.dll
ILSpy.BamlDecompiler.Tests\bin\$(BuildConfiguration)\net472\ILSpy.BamlDecompiler.Tests.exe
- task: ArchiveFiles@1
displayName: Create zip

2
global.json

@ -3,6 +3,6 @@ @@ -3,6 +3,6 @@
"MSBuild.Sdk.Extras": "2.0.54"
},
"sdk": {
"version": "3.2.000"
"version": "3.1"
}
}

Loading…
Cancel
Save