Browse Source

Merge branch 'master' into ranges

pull/1986/head
Siegfried Pammer 6 years ago committed by GitHub
parent
commit
2e5a597300
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
  2. 14
      ICSharpCode.Decompiler.Tests/TestCases/Correctness/ControlFlow.cs
  3. 52
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/NullPropagation.cs
  4. 8
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/NullableRefTypes.cs
  5. 6
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
  6. 12
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  7. 4
      ICSharpCode.Decompiler/CSharp/OutputVisitor/CSharpOutputVisitor.cs
  8. 3
      ICSharpCode.Decompiler/CSharp/OutputVisitor/InsertMissingTokensDecorator.cs
  9. 45
      ICSharpCode.Decompiler/CSharp/SequencePointBuilder.cs
  10. 1
      ICSharpCode.Decompiler/CSharp/StatementBuilder.cs
  11. 92
      ICSharpCode.Decompiler/CSharp/Syntax/Statements/TryCatchStatement.cs
  12. 65
      ICSharpCode.Decompiler/CSharp/Transforms/TransformFieldAndConstructorInitializers.cs
  13. 2
      ICSharpCode.Decompiler/CSharp/WholeProjectDecompiler.cs
  14. 2
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  15. 7
      ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs
  16. 17
      ICSharpCode.Decompiler/IL/ControlFlow/ControlFlowSimplification.cs
  17. 25
      ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs
  18. 13
      ICSharpCode.Decompiler/IL/Instructions/TryInstruction.cs
  19. 14
      ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs
  20. 183
      ICSharpCode.Decompiler/IL/Transforms/NullPropagationTransform.cs
  21. 505
      ICSharpCode.Decompiler/IL/Transforms/TransformExpressionTrees.cs
  22. 2
      ICSharpCode.Decompiler/Metadata/DotNetCorePathFinder.cs
  23. 28
      ICSharpCode.Decompiler/Metadata/DotNetCorePathFinderExtensions.cs
  24. 38
      ICSharpCode.Decompiler/Metadata/UniversalAssemblyResolver.cs
  25. 3
      ILSpy.AddIn/Commands/ProjectReferenceForILSpy.cs
  26. 19
      ILSpy.BamlDecompiler.Tests/BamlTestRunner.cs
  27. 19
      ILSpy.BamlDecompiler.Tests/Cases/AttachedEvent.xaml.cs
  28. 20
      ILSpy.BamlDecompiler.Tests/Cases/CustomControl.cs
  29. 20
      ILSpy.BamlDecompiler.Tests/Cases/Issue1547.xaml.cs
  30. 19
      ILSpy.BamlDecompiler.Tests/Cases/MyControl.xaml.cs
  31. 19
      ILSpy.BamlDecompiler.Tests/Cases/Resources.xaml.cs
  32. 19
      ILSpy.BamlDecompiler.Tests/Cases/Simple.xaml.cs
  33. 19
      ILSpy.BamlDecompiler.Tests/Cases/SimpleNames.xaml.cs
  34. 19
      ILSpy.BamlDecompiler.Tests/Mocks/AvalonDock.cs
  35. 4
      ILSpy.ReadyToRun/ILSpy.ReadyToRun.csproj
  36. 15
      ILSpy.ReadyToRun/ReadyToRunLanguage.cs
  37. 4
      ILSpy.Tests/ILSpy.Tests.csproj
  38. 4
      ILSpy/Analyzers/Builtin/TypeUsedByAnalyzer.cs
  39. 2
      ILSpy/AssemblyList.cs
  40. 35
      ILSpy/AssemblyListManager.cs
  41. 32
      ILSpy/Commands/DecompileCommand.cs
  42. 32
      ILSpy/Commands/DelegateCommand.cs
  43. 45
      ILSpy/EntityReference.cs
  44. 135
      ILSpy/Fusion.cs
  45. 137
      ILSpy/GacInterop.cs
  46. 3
      ILSpy/ILSpy.csproj
  47. 19
      ILSpy/Languages/CSharpLexer.cs
  48. 26
      ILSpy/LoadedAssembly.cs
  49. 14
      ILSpy/MainWindow.xaml.cs
  50. 54
      ILSpy/Properties/Resources.Designer.cs
  51. 14
      ILSpy/Properties/Resources.resx
  52. 2
      ILSpy/TextView/AvalonEditTextOutput.cs
  53. 19
      ILSpy/TextView/BracketHighlightRenderer.cs
  54. 7
      ILSpy/TextView/DecompilerTextView.cs
  55. 2
      ILSpy/ViewModels/DebugStepsPaneModel.cs
  56. 331
      ILSpy/ViewModels/ManageAssemblyListsViewModel.cs
  57. 6
      ILSpy/Views/CreateListDialog.xaml
  58. 16
      ILSpy/Views/CreateListDialog.xaml.cs
  59. 12
      ILSpy/Views/ManageAssemblyLIstsDialog.xaml.cs
  60. 12
      ILSpy/Views/ManageAssemblyListsDialog.xaml
  61. 2
      ILSpy/Views/OpenFromGacDialog.xaml
  62. 16
      ILSpy/Views/OpenFromGacDialog.xaml.cs

4
ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj

@ -42,8 +42,8 @@ @@ -42,8 +42,8 @@
<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.5.0-beta2-final" />
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic" Version="3.5.0-beta2-final" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.6.0-3.final" />
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic" Version="3.6.0-3.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" />

14
ICSharpCode.Decompiler.Tests/TestCases/Correctness/ControlFlow.cs

@ -41,6 +41,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness @@ -41,6 +41,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
BreakUnlessContinue(true);
BreakUnlessContinue(false);
TestConditionals();
Console.WriteLine("Issue1946:\n" + Issue1946());
return 0;
}
@ -149,5 +150,18 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness @@ -149,5 +150,18 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
byte answer = (byte)(value == 128 ? 255 : 0);
return answer;
}
static string Issue1946()
{
string obj = "1";
try {
obj = "2";
} catch {
obj = "3";
} finally {
obj = "4";
}
return obj;
}
}
}

52
ICSharpCode.Decompiler.Tests/TestCases/Pretty/NullPropagation.cs

@ -69,6 +69,48 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -69,6 +69,48 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
}
}
private class Container<T1, T2>
{
public GenericStruct<T1, T2> Other;
}
private struct GenericStruct<T1, T2>
{
public T1 Field1;
public T2 Field2;
public Container<T1, T2> Other;
public override string ToString()
{
return "(" + Field1?.ToString() + ", " + Field2?.ToString() + ")";
}
public int? GetTextLength()
{
return Field1?.ToString().Length + Field2?.ToString().Length + 4;
}
public string Chain1()
{
return Other?.Other.Other?.Other.Field1?.ToString();
}
public string Chain2()
{
return Other?.Other.Other?.Other.Field1?.ToString()?.GetType().Name;
}
public int? Test2()
{
return Field1?.ToString().Length ?? 42;
}
public int? GetTextLengthNRE()
{
return (Field1?.ToString()).Length;
}
}
public interface ITest
{
int Int();
@ -243,12 +285,10 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -243,12 +285,10 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
return t?.Int();
}
// See also: https://github.com/icsharpcode/ILSpy/issues/1050
// The C# compiler generates pretty weird code in this case.
//private static int? GenericRefUnconstrainedInt<T>(ref T t) where T : ITest
//{
// return t?.Int();
//}
private static int? GenericRefUnconstrainedInt<T>(ref T t) where T : ITest
{
return t?.Int();
}
private static int? GenericRefClassConstraintInt<T>(ref T t) where T : class, ITest
{

8
ICSharpCode.Decompiler.Tests/TestCases/Pretty/NullableRefTypes.cs

@ -79,6 +79,14 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -79,6 +79,14 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
set;
}
public event EventHandler? Event;
public static int? NullConditionalOperator(T02_EverythingIsNullableInHere? x)
{
// This code throws if `x != null && x.field1 == null`.
// But we can't decompile it to the warning-free "x?.field1!.Length",
// because of https://github.com/dotnet/roslyn/issues/43659
return x?.field1.Length;
}
}
public class T03_EverythingIsNotNullableInHere

6
ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

@ -181,7 +181,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -181,7 +181,7 @@ namespace ICSharpCode.Decompiler.CSharp
new IntroduceUnsafeModifier(),
new AddCheckedBlocks(),
new DeclareVariables(), // should run after most transforms that modify statements
new ConvertConstructorCallIntoInitializer(), // must run after DeclareVariables
new TransformFieldAndConstructorInitializers(), // must run after DeclareVariables
new DecimalConstantTransform(),
new PrettifyAssignments(), // must run after DeclareVariables
new IntroduceUsingDeclarations(),
@ -376,7 +376,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -376,7 +376,7 @@ namespace ICSharpCode.Decompiler.CSharp
return false;
if (name.Contains("DisplayClass") || name.Contains("AnonStorey"))
return true;
return type.BaseType.GetFullTypeName(metadata).ToString() == "System.Object" && !type.GetInterfaceImplementations().Any();
return type.BaseType.IsKnownType(metadata, KnownTypeCode.Object) && !type.GetInterfaceImplementations().Any();
}
#endregion
@ -396,7 +396,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -396,7 +396,7 @@ namespace ICSharpCode.Decompiler.CSharp
settings.LoadInMemory = true;
var file = LoadPEFile(fileName, settings);
var resolver = new UniversalAssemblyResolver(fileName, settings.ThrowOnAssemblyResolveErrors,
file.Reader.DetectTargetFrameworkId(),
file.DetectTargetFrameworkId(),
settings.LoadInMemory ? PEStreamOptions.PrefetchMetadata : PEStreamOptions.Default,
settings.ApplyWindowsRuntimeProjections ? MetadataReaderOptions.ApplyWindowsRuntimeProjections : MetadataReaderOptions.None);
return new DecompilerTypeSystem(file, resolver);

12
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -2027,7 +2027,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -2027,7 +2027,7 @@ namespace ICSharpCode.Decompiler.CSharp
.WithRR(new ResolveResult(NullableType.GetUnderlyingType(translatedTarget.Type)))
.WithoutILInstruction();
}
translatedTarget = EnsureTargetNotNullable(translatedTarget);
translatedTarget = EnsureTargetNotNullable(translatedTarget, target);
return translatedTarget;
}
} else {
@ -2055,12 +2055,18 @@ namespace ICSharpCode.Decompiler.CSharp @@ -2055,12 +2055,18 @@ namespace ICSharpCode.Decompiler.CSharp
}
}
private TranslatedExpression EnsureTargetNotNullable(TranslatedExpression expr)
private TranslatedExpression EnsureTargetNotNullable(TranslatedExpression expr, ILInstruction inst)
{
// inst is the instruction that got translated into expr.
if (expr.Type.Nullability == Nullability.Nullable) {
if (expr.Expression is UnaryOperatorExpression uoe && uoe.Operator == UnaryOperatorType.NullConditional) {
return expr;
}
if (inst.HasFlag(InstructionFlags.MayUnwrapNull)) {
// We can't use ! in the chain of operators after a NullConditional, due to
// https://github.com/dotnet/roslyn/issues/43659
return expr;
}
return new UnaryOperatorExpression(UnaryOperatorType.SuppressNullableWarning, expr)
.WithRR(new ResolveResult(expr.Type.ChangeNullability(Nullability.Oblivious)))
.WithoutILInstruction();
@ -2153,7 +2159,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -2153,7 +2159,7 @@ namespace ICSharpCode.Decompiler.CSharp
if (arrayExpr.Type.Kind != TypeKind.Array) {
arrayExpr = arrayExpr.ConvertTo(arrayType, this);
}
arrayExpr = EnsureTargetNotNullable(arrayExpr);
arrayExpr = EnsureTargetNotNullable(arrayExpr, inst.Array);
string memberName;
KnownTypeCode code;
if (inst.ResultType == StackType.I4) {

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

@ -1815,11 +1815,11 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -1815,11 +1815,11 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
Space();
WriteKeyword(CatchClause.WhenKeywordRole);
Space(policy.SpaceBeforeIfParentheses);
LPar();
WriteToken(CatchClause.CondLPar);
Space(policy.SpacesWithinIfParentheses);
catchClause.Condition.AcceptVisitor(this);
Space(policy.SpacesWithinIfParentheses);
RPar();
WriteToken(CatchClause.CondRPar);
}
WriteBlock(catchClause.Body, policy.StatementBraceStyle);
EndNode(catchClause);

3
ICSharpCode.Decompiler/CSharp/OutputVisitor/InsertMissingTokensDecorator.cs

@ -46,6 +46,9 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -46,6 +46,9 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
} else if (node is Comment comment) {
comment.SetStartLocation(locationProvider.Location);
}
if (node is ErrorExpression error) {
error.Location = locationProvider.Location;
}
base.StartNode(node);
}

45
ICSharpCode.Decompiler/CSharp/SequencePointBuilder.cs

@ -113,7 +113,13 @@ namespace ICSharpCode.Decompiler.CSharp @@ -113,7 +113,13 @@ namespace ICSharpCode.Decompiler.CSharp
ILInstruction blockContainer = blockStatement.Annotations.OfType<ILInstruction>().FirstOrDefault();
if (blockContainer != null) {
StartSequencePoint(blockStatement.LBraceToken);
int intervalStart = blockContainer.ILRanges.First().Start;
int intervalStart;
if (blockContainer.Parent is TryCatchHandler handler && !handler.ExceptionSpecifierILRange.IsEmpty) {
// if this block container is part of a TryCatchHandler, do not steal the exception-specifier IL range
intervalStart = handler.ExceptionSpecifierILRange.End;
} else {
intervalStart = blockContainer.StartILOffset;
}
// The end will be set to the first sequence point candidate location before the first statement of the function when the seqeunce point is adjusted
int intervalEnd = intervalStart + 1;
@ -256,12 +262,15 @@ namespace ICSharpCode.Decompiler.CSharp @@ -256,12 +262,15 @@ namespace ICSharpCode.Decompiler.CSharp
foreachStatement.InExpression.AcceptVisitor(this);
AddToSequencePoint(foreachInfo.GetEnumeratorCall);
EndSequencePoint(foreachStatement.InExpression.StartLocation, foreachStatement.InExpression.EndLocation);
StartSequencePoint(foreachStatement);
AddToSequencePoint(foreachInfo.MoveNextCall);
EndSequencePoint(foreachStatement.InToken.StartLocation, foreachStatement.InToken.EndLocation);
StartSequencePoint(foreachStatement);
AddToSequencePoint(foreachInfo.GetCurrentCall);
EndSequencePoint(foreachStatement.VariableType.StartLocation, foreachStatement.VariableNameToken.EndLocation);
VisitAsSequencePoint(foreachStatement.EmbeddedStatement);
}
@ -310,6 +319,33 @@ namespace ICSharpCode.Decompiler.CSharp @@ -310,6 +319,33 @@ namespace ICSharpCode.Decompiler.CSharp
VisitAsSequencePoint(fixedStatement.EmbeddedStatement);
}
public override void VisitTryCatchStatement(TryCatchStatement tryCatchStatement)
{
VisitAsSequencePoint(tryCatchStatement.TryBlock);
foreach (var c in tryCatchStatement.CatchClauses) {
VisitAsSequencePoint(c);
}
VisitAsSequencePoint(tryCatchStatement.FinallyBlock);
}
public override void VisitCatchClause(CatchClause catchClause)
{
if (catchClause.Condition.IsNull) {
var tryCatchHandler = catchClause.Annotation<TryCatchHandler>();
if (!tryCatchHandler.ExceptionSpecifierILRange.IsEmpty) {
StartSequencePoint(catchClause.CatchToken);
var function = tryCatchHandler.Ancestors.OfType<ILFunction>().FirstOrDefault();
AddToSequencePointRaw(function, new[] { tryCatchHandler.ExceptionSpecifierILRange });
EndSequencePoint(catchClause.CatchToken.StartLocation, catchClause.RParToken.IsNull ? catchClause.CatchToken.EndLocation : catchClause.RParToken.EndLocation);
}
} else {
StartSequencePoint(catchClause.WhenToken);
AddToSequencePoint(catchClause.Condition);
EndSequencePoint(catchClause.WhenToken.StartLocation, catchClause.CondRParToken.EndLocation);
}
VisitAsSequencePoint(catchClause.Body);
}
/// <summary>
/// Start a new C# statement = new sequence point.
/// </summary>
@ -339,6 +375,13 @@ namespace ICSharpCode.Decompiler.CSharp @@ -339,6 +375,13 @@ namespace ICSharpCode.Decompiler.CSharp
current = outerStates.Pop();
}
void AddToSequencePointRaw(ILFunction function, IEnumerable<Interval> ranges)
{
current.Intervals.AddRange(ranges);
Debug.Assert(current.Function == null || current.Function == function);
current.Function = function;
}
/// <summary>
/// Add the ILAst instruction associated with the AstNode to the sequence point.
/// Also add all its ILAst sub-instructions (unless they were already added to another sequence point).

1
ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

@ -363,6 +363,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -363,6 +363,7 @@ namespace ICSharpCode.Decompiler.CSharp
tryCatch.TryBlock = ConvertAsBlock(inst.TryBlock);
foreach (var handler in inst.Handlers) {
var catchClause = new CatchClause();
catchClause.AddAnnotation(handler);
var v = handler.Variable;
if (v != null) {
catchClause.AddAnnotation(new ILVariableResolveResult(v, v.Type));

92
ICSharpCode.Decompiler/CSharp/Syntax/Statements/TryCatchStatement.cs

@ -32,47 +32,47 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -32,47 +32,47 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// </summary>
public class TryCatchStatement : Statement
{
public static readonly TokenRole TryKeywordRole = new TokenRole ("try");
public static readonly TokenRole TryKeywordRole = new TokenRole("try");
public static readonly Role<BlockStatement> TryBlockRole = new Role<BlockStatement>("TryBlock", BlockStatement.Null);
public static readonly Role<CatchClause> CatchClauseRole = new Role<CatchClause>("CatchClause", CatchClause.Null);
public static readonly TokenRole FinallyKeywordRole = new TokenRole ("finally");
public static readonly TokenRole FinallyKeywordRole = new TokenRole("finally");
public static readonly Role<BlockStatement> FinallyBlockRole = new Role<BlockStatement>("FinallyBlock", BlockStatement.Null);
public CSharpTokenNode TryToken {
get { return GetChildByRole (TryKeywordRole); }
get { return GetChildByRole(TryKeywordRole); }
}
public BlockStatement TryBlock {
get { return GetChildByRole (TryBlockRole); }
set { SetChildByRole (TryBlockRole, value); }
get { return GetChildByRole(TryBlockRole); }
set { SetChildByRole(TryBlockRole, value); }
}
public AstNodeCollection<CatchClause> CatchClauses {
get { return GetChildrenByRole (CatchClauseRole); }
get { return GetChildrenByRole(CatchClauseRole); }
}
public CSharpTokenNode FinallyToken {
get { return GetChildByRole (FinallyKeywordRole); }
get { return GetChildByRole(FinallyKeywordRole); }
}
public BlockStatement FinallyBlock {
get { return GetChildByRole (FinallyBlockRole); }
set { SetChildByRole (FinallyBlockRole, value); }
get { return GetChildByRole(FinallyBlockRole); }
set { SetChildByRole(FinallyBlockRole, value); }
}
public override void AcceptVisitor (IAstVisitor visitor)
public override void AcceptVisitor(IAstVisitor visitor)
{
visitor.VisitTryCatchStatement (this);
visitor.VisitTryCatchStatement(this);
}
public override T AcceptVisitor<T> (IAstVisitor<T> visitor)
public override T AcceptVisitor<T>(IAstVisitor<T> visitor)
{
return visitor.VisitTryCatchStatement (this);
return visitor.VisitTryCatchStatement(this);
}
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data)
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data)
{
return visitor.VisitTryCatchStatement (this, data);
return visitor.VisitTryCatchStatement(this, data);
}
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
@ -87,12 +87,14 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -87,12 +87,14 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
/// </summary>
public class CatchClause : AstNode
{
public static readonly TokenRole CatchKeywordRole = new TokenRole ("catch");
public static readonly TokenRole WhenKeywordRole = new TokenRole ("when");
public static readonly TokenRole CatchKeywordRole = new TokenRole("catch");
public static readonly TokenRole WhenKeywordRole = new TokenRole("when");
public static readonly Role<Expression> ConditionRole = Roles.Condition;
public static readonly TokenRole CondLPar = new TokenRole("(");
public static readonly TokenRole CondRPar = new TokenRole(")");
#region Null
public new static readonly CatchClause Null = new NullCatchClause ();
public new static readonly CatchClause Null = new NullCatchClause();
sealed class NullCatchClause : CatchClause
{
@ -102,17 +104,17 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -102,17 +104,17 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
}
}
public override void AcceptVisitor (IAstVisitor visitor)
public override void AcceptVisitor(IAstVisitor visitor)
{
visitor.VisitNullNode(this);
}
public override T AcceptVisitor<T> (IAstVisitor<T> visitor)
public override T AcceptVisitor<T>(IAstVisitor<T> visitor)
{
return visitor.VisitNullNode(this);
}
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data)
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data)
{
return visitor.VisitNullNode(this, data);
}
@ -143,12 +145,12 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -143,12 +145,12 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
get { return NodeType.Pattern; }
}
public override void AcceptVisitor (IAstVisitor visitor)
public override void AcceptVisitor(IAstVisitor visitor)
{
visitor.VisitPatternPlaceholder(this, child);
}
public override T AcceptVisitor<T> (IAstVisitor<T> visitor)
public override T AcceptVisitor<T>(IAstVisitor<T> visitor)
{
return visitor.VisitPatternPlaceholder(this, child);
}
@ -177,31 +179,31 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -177,31 +179,31 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
}
public CSharpTokenNode CatchToken {
get { return GetChildByRole (CatchKeywordRole); }
get { return GetChildByRole(CatchKeywordRole); }
}
public CSharpTokenNode LParToken {
get { return GetChildByRole (Roles.LPar); }
get { return GetChildByRole(Roles.LPar); }
}
public AstType Type {
get { return GetChildByRole (Roles.Type); }
set { SetChildByRole (Roles.Type, value); }
get { return GetChildByRole(Roles.Type); }
set { SetChildByRole(Roles.Type, value); }
}
public string VariableName {
get { return GetChildByRole (Roles.Identifier).Name; }
get { return GetChildByRole(Roles.Identifier).Name; }
set {
if (string.IsNullOrEmpty(value))
SetChildByRole (Roles.Identifier, null);
SetChildByRole(Roles.Identifier, null);
else
SetChildByRole (Roles.Identifier, Identifier.Create (value));
SetChildByRole(Roles.Identifier, Identifier.Create(value));
}
}
public Identifier VariableNameToken {
get {
return GetChildByRole (Roles.Identifier);
return GetChildByRole(Roles.Identifier);
}
set {
SetChildByRole(Roles.Identifier, value);
@ -209,11 +211,15 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -209,11 +211,15 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
}
public CSharpTokenNode RParToken {
get { return GetChildByRole (Roles.RPar); }
get { return GetChildByRole(Roles.RPar); }
}
public CSharpTokenNode WhenToken {
get { return GetChildByRole (WhenKeywordRole); }
get { return GetChildByRole(WhenKeywordRole); }
}
public CSharpTokenNode CondLParToken {
get { return GetChildByRole(CondLPar); }
}
public Expression Condition {
@ -221,24 +227,28 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax @@ -221,24 +227,28 @@ namespace ICSharpCode.Decompiler.CSharp.Syntax
set { SetChildByRole(ConditionRole, value); }
}
public CSharpTokenNode CondRParToken {
get { return GetChildByRole(CondRPar); }
}
public BlockStatement Body {
get { return GetChildByRole (Roles.Body); }
set { SetChildByRole (Roles.Body, value); }
get { return GetChildByRole(Roles.Body); }
set { SetChildByRole(Roles.Body, value); }
}
public override void AcceptVisitor (IAstVisitor visitor)
public override void AcceptVisitor(IAstVisitor visitor)
{
visitor.VisitCatchClause (this);
visitor.VisitCatchClause(this);
}
public override T AcceptVisitor<T> (IAstVisitor<T> visitor)
public override T AcceptVisitor<T>(IAstVisitor<T> visitor)
{
return visitor.VisitCatchClause (this);
return visitor.VisitCatchClause(this);
}
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data)
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data)
{
return visitor.VisitCatchClause (this, data);
return visitor.VisitCatchClause(this, data);
}
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)

65
ICSharpCode.Decompiler/CSharp/Transforms/ConvertConstructorCallIntoInitializer.cs → ICSharpCode.Decompiler/CSharp/Transforms/TransformFieldAndConstructorInitializers.cs

@ -17,7 +17,6 @@ @@ -17,7 +17,6 @@
// DEALINGS IN THE SOFTWARE.
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using ICSharpCode.Decompiler.CSharp.Syntax;
using ICSharpCode.Decompiler.CSharp.Syntax.PatternMatching;
@ -27,33 +26,29 @@ using SRM = System.Reflection.Metadata; @@ -27,33 +26,29 @@ using SRM = System.Reflection.Metadata;
namespace ICSharpCode.Decompiler.CSharp.Transforms
{
/// <summary>
/// If the first element of a constructor is a chained constructor call, convert it into a constructor initializer.
/// This transform moves field initializers at the start of constructors to their respective field declarations
/// and transforms this-/base-ctor calls in constructors to constructor initializers.
/// </summary>
public class ConvertConstructorCallIntoInitializer : IAstTransform
public class TransformFieldAndConstructorInitializers : DepthFirstAstVisitor, IAstTransform
{
TransformContext context;
public void Run(AstNode node, TransformContext context)
{
var visitor = new ConvertConstructorCallIntoInitializerVisitor(context);
this.context = context;
try {
// If we're viewing some set of members (fields are direct children of SyntaxTree),
// we also need to handle those:
visitor.HandleInstanceFieldInitializers(node.Children);
visitor.HandleStaticFieldInitializers(node.Children);
HandleInstanceFieldInitializers(node.Children);
HandleStaticFieldInitializers(node.Children);
node.AcceptVisitor(visitor);
node.AcceptVisitor(this);
visitor.RemoveSingleEmptyConstructor(node.Children, context.CurrentTypeDefinition);
}
RemoveSingleEmptyConstructor(node.Children, context.CurrentTypeDefinition);
} finally {
this.context = null;
}
sealed class ConvertConstructorCallIntoInitializerVisitor : DepthFirstAstVisitor
{
readonly TransformContext context;
public ConvertConstructorCallIntoInitializerVisitor(TransformContext context)
{
Debug.Assert(context != null);
this.context = context;
}
public override void VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration)
@ -141,7 +136,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -141,7 +136,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
HandleStaticFieldInitializers(typeDeclaration.Members);
}
internal void HandleInstanceFieldInitializers(IEnumerable<AstNode> members)
void HandleInstanceFieldInitializers(IEnumerable<AstNode> members)
{
var instanceCtors = members.OfType<ConstructorDeclaration>().Where(c => (c.Modifiers & Modifiers.Static) == 0).ToArray();
var instanceCtorsNotChainingWithThis = instanceCtors.Where(ctor => !thisCallPattern.IsMatch(ctor.Body.Statements.FirstOrDefault())).ToArray();
@ -200,22 +195,34 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -200,22 +195,34 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
}
}
internal void RemoveSingleEmptyConstructor(IEnumerable<AstNode> members, ITypeDefinition contextTypeDefinition)
void RemoveSingleEmptyConstructor(IEnumerable<AstNode> members, ITypeDefinition contextTypeDefinition)
{
// if we're outside of a type definition skip this altogether
if (contextTypeDefinition == null) return;
// first get non-static constructor declarations from the AST
var instanceCtors = members.OfType<ConstructorDeclaration>().Where(c => (c.Modifiers & Modifiers.Static) == 0).ToArray();
if (instanceCtors.Length == 1 && (members.Skip(1).Any() || instanceCtors[0].Parent is TypeDeclaration)) {
ConstructorDeclaration emptyCtor = new ConstructorDeclaration();
emptyCtor.Modifiers = contextTypeDefinition.IsAbstract ? Modifiers.Protected : Modifiers.Public;
if (instanceCtors[0].HasModifier(Modifiers.Unsafe))
emptyCtor.Modifiers |= Modifiers.Unsafe;
emptyCtor.Body = new BlockStatement();
if (emptyCtor.IsMatch(instanceCtors[0]))
instanceCtors[0].Remove();
// if there's exactly one ctor and it's part of a type declaration or there's more than one member in the current selection
// we can remove the constructor. (We do not want to hide the constructor if the user explicitly selected it in the tree view.)
if (instanceCtors.Length == 1 && (instanceCtors[0].Parent is TypeDeclaration || members.Skip(1).Any())) {
var ctor = instanceCtors[0];
// dynamically create a pattern of an empty ctor
ConstructorDeclaration emptyCtorPattern = new ConstructorDeclaration();
emptyCtorPattern.Modifiers = contextTypeDefinition.IsAbstract ? Modifiers.Protected : Modifiers.Public;
if (ctor.HasModifier(Modifiers.Unsafe))
emptyCtorPattern.Modifiers |= Modifiers.Unsafe;
emptyCtorPattern.Body = new BlockStatement();
if (emptyCtorPattern.IsMatch(ctor)) {
bool retainBecauseOfDocumentation = ctor.GetSymbol() is IMethod ctorMethod
&& context.Settings.ShowXmlDocumentation
&& context.DecompileRun.DocumentationProvider?.GetDocumentation(ctorMethod) != null;
if (!retainBecauseOfDocumentation)
ctor.Remove();
}
}
}
internal void HandleStaticFieldInitializers(IEnumerable<AstNode> members)
void HandleStaticFieldInitializers(IEnumerable<AstNode> members)
{
// Translate static constructor into field initializers if the class is BeforeFieldInit
var staticCtor = members.OfType<ConstructorDeclaration>().FirstOrDefault(c => (c.Modifiers & Modifiers.Static) == Modifiers.Static);

2
ICSharpCode.Decompiler/CSharp/WholeProjectDecompiler.cs

@ -296,7 +296,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -296,7 +296,7 @@ namespace ICSharpCode.Decompiler.CSharp
break;
}
string targetFramework = module.Reader.DetectTargetFrameworkId();
string targetFramework = module.DetectTargetFrameworkId();
if (!string.IsNullOrEmpty(targetFramework)) {
string[] frameworkParts = targetFramework.Split(',');
result.TargetFrameworkIdentifier = frameworkParts.FirstOrDefault(a => !a.StartsWith("Version=", StringComparison.OrdinalIgnoreCase) && !a.StartsWith("Profile=", StringComparison.OrdinalIgnoreCase));

2
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -272,7 +272,7 @@ @@ -272,7 +272,7 @@
<Compile Include="CSharp\ExpressionBuilder.cs" />
<Compile Include="CSharp\StatementBuilder.cs" />
<Compile Include="CSharp\Transforms\AddCheckedBlocks.cs" />
<Compile Include="CSharp\Transforms\ConvertConstructorCallIntoInitializer.cs" />
<Compile Include="CSharp\Transforms\TransformFieldAndConstructorInitializers.cs" />
<Compile Include="CSharp\Transforms\CustomPatterns.cs" />
<Compile Include="CSharp\Transforms\IAstTransform.cs" />
<Compile Include="CSharp\Transforms\IntroduceUnsafeModifier.cs" />

7
ICSharpCode.Decompiler/IL/ControlFlow/AsyncAwaitDecompiler.cs

@ -257,8 +257,13 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -257,8 +257,13 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
return false;
pos--;
}
if (!loadBuilderExpr.MatchLdFld(out var loadStateMachineForBuilderExpr, out builderField))
if (loadBuilderExpr.MatchLdFld(out var loadStateMachineForBuilderExpr, out builderField)) {
// OK, calling Start on copy of stateMachine.<>t__builder
} else if (loadBuilderExpr.MatchLdFlda(out loadStateMachineForBuilderExpr, out builderField)) {
// OK, Roslyn 3.6 started directly calling Start without making a copy
} else {
return false;
}
builderField = (IField)builderField.MemberDefinition;
if (!(loadStateMachineForBuilderExpr.MatchLdLocRef(stateMachineVar) || loadStateMachineForBuilderExpr.MatchLdLoc(stateMachineVar)))
return false;

17
ICSharpCode.Decompiler/IL/ControlFlow/ControlFlowSimplification.cs

@ -197,9 +197,22 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow @@ -197,9 +197,22 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
bool IsBranchToReturnBlock(Branch branch)
{
var targetBlock = branch.TargetBlock;
if (targetBlock.Instructions.Count != 1 || targetBlock.FinalInstruction.OpCode != OpCode.Nop)
if (targetBlock.Instructions.Count != 1)
return false;
return targetBlock.Instructions[0].MatchReturn(out var value) && value is LdLoc;
if (!targetBlock.Instructions[0].MatchReturn(out var value))
return false;
if (!value.MatchLdLoc(out var returnVar))
return false;
var container = branch.TargetContainer;
for (ILInstruction inst = branch; inst != container; inst = inst.Parent) {
if (inst.Parent is TryFinally tryFinally && inst.SlotInfo == TryFinally.TryBlockSlot) {
// The branch will trigger the finally block.
// Moving the return block into the try is only possible if the finally block doesn't touch the return variable.
if (returnVar.IsUsedWithin(tryFinally.FinallyBlock))
return false;
}
}
return true;
}
static bool CombineBlockWithNextBlock(BlockContainer container, Block block, ILTransformContext context)

25
ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs

@ -214,24 +214,29 @@ namespace ICSharpCode.Decompiler.IL @@ -214,24 +214,29 @@ namespace ICSharpCode.Decompiler.IL
public void AddILRange(Interval newRange)
{
if (this.ILRange.IsEmpty) {
this.ILRange = newRange;
return;
this.ILRange = CombineILRange(this.ILRange, newRange);
}
protected static Interval CombineILRange(Interval oldRange, Interval newRange)
{
if (oldRange.IsEmpty) {
return newRange;
}
if (newRange.IsEmpty) {
return;
return oldRange;
}
if (newRange.Start <= this.StartILOffset) {
if (newRange.End < this.StartILOffset) {
this.ILRange = newRange; // use the earlier range
if (newRange.Start <= oldRange.Start) {
if (newRange.End < oldRange.Start) {
return newRange; // use the earlier range
} else {
// join overlapping ranges
this.ILRange = new Interval(newRange.Start, Math.Max(newRange.End, this.ILRange.End));
return new Interval(newRange.Start, Math.Max(newRange.End, oldRange.End));
}
} else if (newRange.Start <= this.ILRange.End) {
} else if (newRange.Start <= oldRange.End) {
// join overlapping ranges
this.ILRange = new Interval(this.StartILOffset, Math.Max(newRange.End, this.ILRange.End));
return new Interval(oldRange.Start, Math.Max(newRange.End, oldRange.End));
}
return oldRange;
}
public void AddILRange(ILInstruction sourceInstruction)

13
ICSharpCode.Decompiler/IL/Instructions/TryInstruction.cs

@ -19,6 +19,7 @@ @@ -19,6 +19,7 @@
using System;
using System.Diagnostics;
using System.Linq;
using ICSharpCode.Decompiler.Util;
namespace ICSharpCode.Decompiler.IL
{
@ -175,6 +176,18 @@ namespace ICSharpCode.Decompiler.IL @@ -175,6 +176,18 @@ namespace ICSharpCode.Decompiler.IL
output.Write(' ');
body.WriteTo(output, options);
}
/// <summary>
/// Gets the ILRange of the instructions at the start of the catch-block,
/// that take the exception object and store it in the exception variable slot.
/// Note: This range is empty, if Filter is not empty, i.e., ldloc 1.
/// </summary>
public Interval ExceptionSpecifierILRange { get; private set; }
public void AddExceptionSpecifierILRange(Interval newRange)
{
ExceptionSpecifierILRange = CombineILRange(ExceptionSpecifierILRange, newRange);
}
}
partial class TryFinally

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

@ -17,10 +17,12 @@ @@ -17,10 +17,12 @@
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Util;
namespace ICSharpCode.Decompiler.IL.Transforms
{
@ -694,7 +696,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -694,7 +696,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
TransformCatchWhen(inst, filterContainer.EntryPoint);
}
if (inst.Body is BlockContainer catchContainer)
TransformCatchVariable(inst, catchContainer.EntryPoint);
TransformCatchVariable(inst, catchContainer.EntryPoint, isCatchBlock: true);
}
/// <summary>
@ -711,7 +713,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -711,7 +713,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// }
/// }
/// </summary>
void TransformCatchVariable(TryCatchHandler handler, Block entryPoint)
void TransformCatchVariable(TryCatchHandler handler, Block entryPoint, bool isCatchBlock)
{
if (!handler.Variable.IsSingleDefinition || handler.Variable.LoadCount != 1)
return; // handle.Variable already has non-trivial uses
@ -722,6 +724,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -722,6 +724,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (inlinedUnboxAny.Type.Equals(handler.Variable.Type)) {
context.Step("TransformCatchVariable - remove inlined UnboxAny", inlinedUnboxAny);
inlinedUnboxAny.ReplaceWith(inlinedUnboxAny.Argument);
foreach (var range in inlinedUnboxAny.ILRanges)
handler.AddExceptionSpecifierILRange(range);
}
}
return;
@ -748,6 +752,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -748,6 +752,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms
exceptionVar.Kind = VariableKind.ExceptionLocal;
exceptionVar.Type = handler.Variable.Type;
handler.Variable = exceptionVar;
if (isCatchBlock) {
foreach (var offset in entryPoint.Instructions[0].Descendants.SelectMany(o => o.ILRanges))
handler.AddExceptionSpecifierILRange(offset);
}
entryPoint.Instructions.RemoveAt(0);
}
@ -756,7 +764,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -756,7 +764,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// </summary>
void TransformCatchWhen(TryCatchHandler handler, Block entryPoint)
{
TransformCatchVariable(handler, entryPoint);
TransformCatchVariable(handler, entryPoint, isCatchBlock: false);
if (entryPoint.Instructions.Count == 1 && entryPoint.Instructions[0].MatchLeave(out _, out var condition)) {
context.Step("TransformCatchWhen", entryPoint.Instructions[0]);
handler.Filter = condition;

183
ICSharpCode.Decompiler/IL/Transforms/NullPropagationTransform.cs

@ -59,6 +59,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -59,6 +59,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// nullable type, used by reference (comparison is 'call get_HasValue(ldloc(testedVar))')
/// </summary>
NullableByReference,
/// <summary>
/// unconstrained generic type (see the pattern described in TransformNullPropagationOnUnconstrainedGenericExpression)
/// </summary>
UnconstrainedType,
}
/// <summary>
@ -142,9 +146,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -142,9 +146,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// </summary>
internal void RunStatements(Block block, int pos)
{
var ifInst = block.Instructions[pos] as IfInstruction;
if (ifInst == null || !ifInst.FalseInst.MatchNop())
return;
if (block.Instructions[pos] is IfInstruction ifInst && ifInst.FalseInst.MatchNop()) {
if (ifInst.Condition is Comp comp && comp.Kind == ComparisonKind.Inequality
&& comp.Left.MatchLdLoc(out var testedVar) && comp.Right.MatchLdNull()) {
TryNullPropForVoidCall(testedVar, Mode.ReferenceType, ifInst.TrueInst as Block, ifInst);
@ -156,6 +158,36 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -156,6 +158,36 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
}
}
if (TransformNullPropagationOnUnconstrainedGenericExpression(block, pos, out var testedVariable, out var nonNullInst, out var nullInst, out var endBlock)) {
var parentInstruction = nonNullInst.Parent;
var replacement = TryNullPropagation(testedVariable, nonNullInst, nullInst, Mode.UnconstrainedType);
if (replacement == null)
return;
context.Step("TransformNullPropagationOnUnconstrainedGenericExpression", block);
switch (parentInstruction) {
case StLoc stloc:
stloc.Value = replacement;
break;
case Leave leave:
leave.Value = replacement;
break;
default:
// if this ever happens, the pattern checked by TransformNullPropagationOnUnconstrainedGenericExpression
// has changed, but this part of the code was not properly adjusted.
throw new NotSupportedException();
}
// Remove the fallback conditions and blocks
block.Instructions.RemoveRange(pos + 1, 2);
// if the endBlock is only reachable through the current block,
// combine both blocks.
if (endBlock?.IncomingEdgeCount == 1) {
block.Instructions.AddRange(endBlock.Instructions);
block.Instructions.RemoveAt(pos + 2);
endBlock.Remove();
}
ILInlining.InlineIfPossible(block, pos, context);
}
}
void TryNullPropForVoidCall(ILVariable testedVar, Mode mode, Block body, IfInstruction ifInst)
{
@ -261,6 +293,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -261,6 +293,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
case Mode.NullableByReference:
return NullableLiftingTransform.MatchGetValueOrDefault(inst, out ILInstruction arg)
&& arg.MatchLdLoc(testedVar);
case Mode.UnconstrainedType:
// unconstrained generic type (expect: ldloc(testedVar))
return inst.MatchLdLoc(testedVar);
default:
throw new ArgumentOutOfRangeException(nameof(mode));
}
@ -288,6 +323,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -288,6 +323,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
ILInstruction replacement;
switch (mode) {
case Mode.ReferenceType:
case Mode.UnconstrainedType:
// Wrap varLoad in nullable.unwrap:
replacement = new NullableUnwrap(varLoad.ResultType, varLoad, refInput: varLoad.ResultType == StackType.Ref);
break;
@ -310,6 +346,147 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -310,6 +346,147 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
oldParentChildren[oldChildIndex] = replacement;
}
// stloc target(targetInst)
// stloc defaultTemporary(default.value type)
// if (logic.not(comp.o(box `0(ldloc defaultTemporary) != ldnull))) Block fallbackBlock {
// stloc defaultTemporary(ldobj type(ldloc target))
// stloc target(ldloca defaultTemporary)
// if (comp.o(ldloc defaultTemporary == ldnull)) Block fallbackBlock2 {
// stloc resultTemporary(nullInst)
// br endBlock
// }
// }
// stloc resultTemporary(constrained[type].call_instruction(ldloc target, ...))
// br endBlock
// =>
// stloc resultTemporary(nullable.rewrap(constrained[type].call_instruction(nullable.unwrap(targetInst), ...)))
//
// -or-
//
// stloc target(targetInst)
// stloc defaultTemporary(default.value type)
// if (logic.not(comp.o(box `0(ldloc defaultTemporary) != ldnull))) Block fallbackBlock {
// stloc defaultTemporary(ldobj type(ldloc target))
// stloc target(ldloca defaultTemporary)
// if (comp.o(ldloc defaultTemporary == ldnull)) Block fallbackBlock2 {
// leave(nullInst)
// }
// }
// leave (constrained[type].call_instruction(ldloc target, ...))
// =>
// leave (nullable.rewrap(constrained[type].call_instruction(nullable.unwrap(targetInst), ...)))
private bool TransformNullPropagationOnUnconstrainedGenericExpression(Block block, int pos,
out ILVariable target, out ILInstruction nonNullInst, out ILInstruction nullInst, out Block endBlock)
{
target = null;
nonNullInst = null;
nullInst = null;
endBlock = null;
if (pos + 3 >= block.Instructions.Count)
return false;
// stloc target(...)
if (!block.Instructions[pos].MatchStLoc(out target, out _))
return false;
if (!(target.Kind == VariableKind.StackSlot && target.LoadCount == 2 && target.StoreCount == 2))
return false;
// stloc defaultTemporary(default.value type)
if (!(block.Instructions[pos + 1].MatchStLoc(out var defaultTemporary, out var defaultExpression) && defaultExpression.MatchDefaultValue(out var type)))
return false;
// In the above pattern the defaultTemporary variable is used two times in stloc and ldloc instructions and once in a ldloca instruction
if (!(defaultTemporary.Kind == VariableKind.Local && defaultTemporary.LoadCount == 2 && defaultTemporary.StoreCount == 2 && defaultTemporary.AddressCount == 1))
return false;
// if (logic.not(comp.o(box `0(ldloc defaultTemporary) != ldnull))) Block fallbackBlock
if (!(block.Instructions[pos + 2].MatchIfInstruction(out var condition, out var fallbackBlock1) && condition.MatchCompEqualsNull(out var arg) && arg.MatchLdLoc(defaultTemporary)))
return false;
if (!MatchStLocResultTemporary(block, pos, type, target, defaultTemporary, fallbackBlock1, out nonNullInst, out nullInst, out endBlock)
&& !MatchLeaveResult(block, pos, type, target, defaultTemporary, fallbackBlock1, out nonNullInst, out nullInst))
return false;
return true;
}
// stloc resultTemporary(constrained[type].call_instruction(ldloc target, ...))
// br endBlock
private bool MatchStLocResultTemporary(Block block, int pos, IType type, ILVariable target, ILVariable defaultTemporary, ILInstruction fallbackBlock, out ILInstruction nonNullInst, out ILInstruction nullInst, out Block endBlock)
{
endBlock = null;
nonNullInst = null;
nullInst = null;
if (pos + 4 >= block.Instructions.Count)
return false;
// stloc resultTemporary(constrained[type].call_instruction(ldloc target, ...))
if (!(block.Instructions[pos + 3].MatchStLoc(out var resultTemporary, out nonNullInst)))
return false;
// br endBlock
if (!(block.Instructions[pos + 4].MatchBranch(out endBlock)))
return false;
// Analyze Block fallbackBlock
if (!(fallbackBlock is Block b && IsFallbackBlock(b, type, target, defaultTemporary, resultTemporary, endBlock, out nullInst)))
return false;
return true;
}
private bool MatchLeaveResult(Block block, int pos, IType type, ILVariable target, ILVariable defaultTemporary, ILInstruction fallbackBlock, out ILInstruction nonNullInst, out ILInstruction nullInst)
{
nonNullInst = null;
nullInst = null;
// leave (constrained[type].call_instruction(ldloc target, ...))
if (!(block.Instructions[pos + 3] is Leave leave && leave.IsLeavingFunction))
return false;
nonNullInst = leave.Value;
// Analyze Block fallbackBlock
if (!(fallbackBlock is Block b && IsFallbackBlock(b, type, target, defaultTemporary, null, leave.TargetContainer, out nullInst)))
return false;
return true;
}
// Block fallbackBlock {
// stloc defaultTemporary(ldobj type(ldloc target))
// stloc target(ldloca defaultTemporary)
// if (comp.o(ldloc defaultTemporary == ldnull)) Block fallbackBlock {
// stloc resultTemporary(ldnull)
// br endBlock
// }
// }
private bool IsFallbackBlock(Block block, IType type, ILVariable target, ILVariable defaultTemporary, ILVariable resultTemporary, ILInstruction endBlockOrLeaveContainer, out ILInstruction nullInst)
{
nullInst = null;
if (!(block.Instructions.Count == 3))
return false;
// stloc defaultTemporary(ldobj type(ldloc target))
if (!(block.Instructions[0].MatchStLoc(defaultTemporary, out var value)))
return false;
if (!(value.MatchLdObj(out var inst, out var t) && type.Equals(t) && inst.MatchLdLoc(target)))
return false;
// stloc target(ldloca defaultTemporary)
if (!(block.Instructions[1].MatchStLoc(target, out var defaultAddress) && defaultAddress.MatchLdLoca(defaultTemporary)))
return false;
// if (comp.o(ldloc defaultTemporary == ldnull)) Block fallbackBlock
if (!(block.Instructions[2].MatchIfInstruction(out var condition, out var tmp) && condition.MatchCompEqualsNull(out var arg) && arg.MatchLdLoc(defaultTemporary)))
return false;
// Block fallbackBlock {
// stloc resultTemporary(nullInst)
// br endBlock
// }
var fallbackInst = Block.Unwrap(tmp);
if (fallbackInst is Block fallbackBlock && endBlockOrLeaveContainer is Block endBlock) {
if (!(fallbackBlock.Instructions.Count == 2))
return false;
if (!fallbackBlock.Instructions[0].MatchStLoc(resultTemporary, out nullInst))
return false;
if (!fallbackBlock.Instructions[1].MatchBranch(endBlock))
return false;
} else {
if (!(fallbackInst is Leave fallbackLeave && endBlockOrLeaveContainer is BlockContainer leaveContainer
&& fallbackLeave.TargetContainer == leaveContainer && !fallbackLeave.Value.MatchNop()))
return false;
nullInst = fallbackLeave.Value;
}
return true;
}
}
class NullPropagationStatementTransform : IStatementTransform

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

@ -30,6 +30,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -30,6 +30,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms
{
/// <summary>
/// Converts LINQ Expression Trees to ILFunctions/ILAst instructions.
///
/// We build a tree of Func{ILInstruction}s, which are only executed, if the whole transform succeeds.
/// </summary>
public class TransformExpressionTrees : IStatementTransform
{
@ -122,9 +124,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -122,9 +124,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (MightBeExpressionTree(instruction, statement)) {
var (lambda, type) = ConvertLambda((CallInstruction)instruction);
if (lambda != null) {
SetExpressionTreeFlag((ILFunction)lambda, (CallInstruction)instruction);
context.Step("Convert Expression Tree", instruction);
instruction.ReplaceWith(lambda);
var newLambda = (ILFunction)lambda();
SetExpressionTreeFlag(newLambda, (CallInstruction)instruction);
instruction.ReplaceWith(newLambda);
return true;
}
return false;
@ -142,7 +145,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -142,7 +145,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// Converts a Expression.Lambda call into an ILFunction.
/// If the conversion fails, null is returned.
/// </summary>
(ILInstruction, IType) ConvertLambda(CallInstruction instruction)
(Func<ILInstruction>, IType) ConvertLambda(CallInstruction instruction)
{
if (instruction.Method.Name != "Lambda" || instruction.Arguments.Count != 2 || instruction.Method.ReturnType.FullName != "System.Linq.Expressions.Expression" || instruction.Method.ReturnType.TypeArguments.Count != 1)
return (null, SpecialType.UnknownType);
@ -164,8 +167,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -164,8 +167,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms
lambdaStack.Pop();
if (bodyInstruction == null)
return (null, SpecialType.UnknownType);
container.ExpectedResultType = bodyInstruction.ResultType;
container.Blocks.Add(new Block() { Instructions = { new Leave(container, bodyInstruction) } });
return (BuildFunction, function.DelegateType);
ILFunction BuildFunction()
{
lambdaStack.Push(function);
var convertedBody = bodyInstruction();
lambdaStack.Pop();
container.ExpectedResultType = convertedBody.ResultType;
container.Blocks.Add(new Block() { Instructions = { new Leave(container, convertedBody) } });
// Replace all other usages of the parameter variable
foreach (var mapping in parameterMapping) {
foreach (var load in mapping.Key.LoadInstructions.ToArray()) {
@ -174,24 +184,32 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -174,24 +184,32 @@ namespace ICSharpCode.Decompiler.IL.Transforms
load.ReplaceWith(new LdLoc(mapping.Value));
}
}
return (function, function.DelegateType);
return function;
}
}
(ILInstruction, IType) ConvertQuote(CallInstruction invocation)
(Func<ILInstruction>, IType) ConvertQuote(CallInstruction invocation)
{
if (invocation.Arguments.Count != 1)
return (null, SpecialType.UnknownType);
var argument = invocation.Arguments.Single();
if (argument is ILFunction function) {
return (function, function.DelegateType);
return (() => function, function.DelegateType);
} else {
var converted = ConvertInstruction(argument);
var (converted, type) = ConvertInstruction(argument);
if (converted == null)
return (converted, type);
return (BuildQuote, type);
if (converted.Item1 is ILFunction lambda && argument is CallInstruction call) {
ILInstruction BuildQuote()
{
var f = converted();
if (f is ILFunction lambda && argument is CallInstruction call) {
SetExpressionTreeFlag(lambda, call);
}
return converted;
return f;
}
}
}
@ -232,22 +250,28 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -232,22 +250,28 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
}
(ILInstruction, IType) ConvertInstruction(ILInstruction instruction, IType typeHint = null)
(Func<ILInstruction>, IType) ConvertInstruction(ILInstruction instruction, IType typeHint = null)
{
var (inst, type) = Convert();
if (inst == null)
return (null, type);
ILInstruction DoConvert()
{
var result = Convert();
if (result.Item1 != null) {
Debug.Assert(result.Item2 != null, "IType must be non-null!");
Debug.Assert(result.Item1.ResultType == result.Item2.GetStackType(), "StackTypes must match!");
var result = inst();
Debug.Assert(type != null, "IType must be non-null!");
Debug.Assert(result.ResultType == type.GetStackType(), "StackTypes must match!");
if (typeHint != null) {
var inst = result.Item1;
if (inst.ResultType != typeHint.GetStackType()) {
return (new Conv(inst, typeHint.GetStackType().ToPrimitiveType(), false, typeHint.GetSign()), typeHint);
}
if (result.ResultType != typeHint.GetStackType()) {
return new Conv(result, typeHint.GetStackType().ToPrimitiveType(), false, typeHint.GetSign());
}
}
return result;
}
return (DoConvert, typeHint ?? type);
(ILInstruction, IType) Convert() {
(Func<ILInstruction>, IType) Convert() {
switch (instruction) {
case CallInstruction invocation:
if (invocation.Method.DeclaringType.FullName != "System.Linq.Expressions.Expression")
@ -348,19 +372,23 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -348,19 +372,23 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
return (null, SpecialType.UnknownType);
case ILFunction function:
ILFunction ApplyChangesToILFunction()
{
if (function.Kind == ILFunctionKind.ExpressionTree) {
function.DelegateType = UnwrapExpressionTree(function.DelegateType);
function.Kind = ILFunctionKind.Delegate;
}
return (function, function.DelegateType);
return function;
}
return (ApplyChangesToILFunction, function.DelegateType);
case LdLoc ldloc:
if (IsExpressionTreeParameter(ldloc.Variable)) {
// Replace an already mapped parameter with the actual ILVariable,
// we generated earlier.
if (parameterMapping.TryGetValue(ldloc.Variable, out var v)) {
if (typeHint.SkipModifiers() is ByReferenceType && !v.Type.IsByRefLike)
return (new LdLoca(v), typeHint);
return (new LdLoc(v), v.Type);
return (() => new LdLoca(v), typeHint);
return (() => new LdLoc(v), v.Type);
}
// This is a parameter variable from an outer scope.
// We can't replace these variables just yet, because the transform works backwards.
@ -368,9 +396,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -368,9 +396,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// so our transform can continue normally.
// Later, we will replace all references to unmapped variables,
// with references to mapped parameters.
if (ldloc.Variable.IsSingleDefinition && ldloc.Variable.StoreInstructions[0] is ILInstruction inst) {
if (MatchParameterVariableAssignment(inst, out _, out var type, out _))
return (new ExpressionTreeCast(type, ldloc, false), type);
if (ldloc.Variable.IsSingleDefinition && ldloc.Variable.StoreInstructions[0] is ILInstruction instr) {
if (MatchParameterVariableAssignment(instr, out _, out var t, out _))
return (() => new ExpressionTreeCast(t, ldloc, false), t);
}
}
return (null, SpecialType.UnknownType);
@ -392,7 +420,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -392,7 +420,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return delegateType;
}
(ILInstruction, IType) ConvertArrayIndex(CallInstruction invocation)
(Func<ILInstruction>, IType) ConvertArrayIndex(CallInstruction invocation)
{
if (invocation.Arguments.Count != 2)
return (null, SpecialType.UnknownType);
@ -403,26 +431,32 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -403,26 +431,32 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return (null, SpecialType.UnknownType);
if (!MatchArgumentList(invocation.Arguments[1], out var arguments))
arguments = new[] { invocation.Arguments[1] };
ILInstruction Convert()
{
Func<ILInstruction>[] toBeConverted = new Func<ILInstruction>[arguments.Count];
for (int i = 0; i < arguments.Count; i++) {
var (converted, indexType) = ConvertInstruction(arguments[i]);
if (converted == null)
return (null, SpecialType.UnknownType);
arguments[i] = converted;
return null;
toBeConverted[i] = converted;
}
return new LdObj(new LdElema(type.ElementType, array(), toBeConverted.SelectArray(f => f())), type.ElementType);
}
return (new LdObj(new LdElema(type.ElementType, array, arguments.ToArray()), type.ElementType), type.ElementType);
return (Convert, type.ElementType);
}
(ILInstruction, IType) ConvertArrayLength(CallInstruction invocation)
(Func<ILInstruction>, IType) ConvertArrayLength(CallInstruction invocation)
{
if (invocation.Arguments.Count != 1)
return (null, SpecialType.UnknownType);
var (converted, arrayType) = ConvertInstruction(invocation.Arguments[0]);
var (converted, _) = ConvertInstruction(invocation.Arguments[0]);
if (converted == null)
return (null, SpecialType.UnknownType);
return (new LdLen(StackType.I4, converted), context.TypeSystem.FindType(KnownTypeCode.Int32));
return (() => new LdLen(StackType.I4, converted()), context.TypeSystem.FindType(KnownTypeCode.Int32));
}
(ILInstruction, IType) ConvertBinaryNumericOperator(CallInstruction invocation, BinaryNumericOperator op, bool? isChecked = null)
(Func<ILInstruction>, IType) ConvertBinaryNumericOperator(CallInstruction invocation, BinaryNumericOperator op, bool? isChecked = null)
{
if (invocation.Arguments.Count < 2)
return (null, SpecialType.UnknownType);
@ -442,12 +476,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -442,12 +476,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (!rightType.Equals(leftType))
return (null, SpecialType.UnknownType);
}
return (new BinaryNumericInstruction(op, left, right, isChecked == true, leftType.GetSign()), leftType);
return (() => new BinaryNumericInstruction(op, left(), right(), isChecked == true, leftType.GetSign()), leftType);
case 3:
if (!MatchGetMethodFromHandle(invocation.Arguments[2], out method))
return (null, SpecialType.UnknownType);
return (new Call((IMethod)method) {
Arguments = { left, right }
return (() => new Call((IMethod)method) {
Arguments = { left(), right() }
}, method.ReturnType);
case 4:
if (!invocation.Arguments[2].MatchLdcI4(out var isLifted))
@ -456,15 +490,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -456,15 +490,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return (null, SpecialType.UnknownType);
if (isLifted != 0)
method = CSharpOperators.LiftUserDefinedOperator((IMethod)method);
return (new Call((IMethod)method) {
Arguments = { left, right }
return (() => new Call((IMethod)method) {
Arguments = { left(), right() }
}, method.ReturnType);
default:
return (null, SpecialType.UnknownType);
}
}
(ILInstruction, IType) ConvertBind(CallInstruction invocation, ILVariable targetVariable)
(Func<ILVariable, ILInstruction>, IType) ConvertBind(CallInstruction invocation)
{
if (invocation.Arguments.Count != 2)
return (null, SpecialType.UnknownType);
@ -478,19 +512,19 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -478,19 +512,19 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
switch (member) {
case IMethod method:
return (new Call(method) { Arguments = { new LdLoc(targetVariable), value } }, method.ReturnType);
return (targetVariable => new Call(method) { Arguments = { new LdLoc(targetVariable), value() } }, method.ReturnType);
case IField field:
return (new StObj(new LdFlda(new LdLoc(targetVariable), (IField)member), value, member.ReturnType), field.ReturnType);
return (targetVariable => new StObj(new LdFlda(new LdLoc(targetVariable), (IField)member), value(), member.ReturnType), field.ReturnType);
}
return (null, SpecialType.UnknownType);
}
(ILInstruction, IType) ConvertCall(CallInstruction invocation)
(Func<ILInstruction>, IType) ConvertCall(CallInstruction invocation)
{
if (invocation.Arguments.Count < 2)
return (null, SpecialType.UnknownType);
IList<ILInstruction> arguments = null;
ILInstruction target = null;
Func<ILInstruction> targetConverter = null;
IType targetType = null;
if (MatchGetMethodFromHandle(invocation.Arguments[0], out var member)) {
// static method
@ -502,36 +536,42 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -502,36 +536,42 @@ namespace ICSharpCode.Decompiler.IL.Transforms
arguments = new List<ILInstruction>(invocation.Arguments.Skip(2));
}
if (!invocation.Arguments[0].MatchLdNull()) {
(target, targetType) = ConvertInstruction(invocation.Arguments[0]);
if (target == null)
(targetConverter, targetType) = ConvertInstruction(invocation.Arguments[0]);
if (targetConverter == null)
return (null, SpecialType.UnknownType);
}
}
if (arguments == null)
return (null, SpecialType.UnknownType);
IMethod method = (IMethod)member;
if (!ConvertCallArguments(arguments, method))
var convertedArguments = ConvertCallArguments(arguments, method);
if (convertedArguments == null)
return (null, SpecialType.UnknownType);
if (method.FullName == "System.Reflection.MethodInfo.CreateDelegate" && method.Parameters.Count == 2) {
if (!MatchGetMethodFromHandle(target, out var targetMethod))
if (!MatchGetMethodFromHandle(UnpackConstant(invocation.Arguments[0]), out var targetMethod))
return (null, SpecialType.UnknownType);
if (!MatchGetTypeFromHandle(arguments[0], out var delegateType))
if (!MatchGetTypeFromHandle(UnpackConstant(arguments[0]), out var delegateType))
return (null, SpecialType.UnknownType);
return (new NewObj(delegateType.GetConstructors().Single()) {
Arguments = { arguments[1], new LdFtn((IMethod)targetMethod) }
return (() => new NewObj(delegateType.GetConstructors().Single()) {
Arguments = { convertedArguments[1](), new LdFtn((IMethod)targetMethod) }
}, delegateType);
}
CallInstruction BuildCall()
{
CallInstruction call;
if (method.IsAbstract || method.IsVirtual || method.IsOverride) {
call = new CallVirt(method);
} else {
call = new Call(method);
}
if (target != null) {
call.Arguments.Add(PrepareCallTarget(method.DeclaringType, target, targetType));
if (targetConverter != null) {
call.Arguments.Add(PrepareCallTarget(method.DeclaringType, targetConverter(), targetType));
}
call.Arguments.AddRange(convertedArguments.Select(f => f()));
return call;
}
call.Arguments.AddRange(arguments);
return (call, method.ReturnType);
return (BuildCall, method.ReturnType);
}
ILInstruction PrepareCallTarget(IType expectedType, ILInstruction target, IType targetType)
@ -556,20 +596,28 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -556,20 +596,28 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
}
bool ConvertCallArguments(IList<ILInstruction> arguments, IMethod method)
ILInstruction UnpackConstant(ILInstruction inst)
{
if (!(inst is CallInstruction call && call.Method.FullName == "System.Linq.Expressions.Expression.Constant" && call.Arguments.Count == 2))
return inst;
return call.Arguments[0];
}
Func<ILInstruction>[] ConvertCallArguments(IList<ILInstruction> arguments, IMethod method)
{
var converted = new Func<ILInstruction>[arguments.Count];
Debug.Assert(arguments.Count == method.Parameters.Count);
for (int i = 0; i < arguments.Count; i++) {
var expectedType = method.Parameters[i].Type;
var argument = ConvertInstruction(arguments[i], expectedType).Item1;
if (argument == null)
return false;
arguments[i] = argument;
return null;
converted[i] = argument;
}
return true;
return converted;
}
(ILInstruction, IType) ConvertCast(CallInstruction invocation, bool isChecked)
(Func<ILInstruction>, IType) ConvertCast(CallInstruction invocation, bool isChecked)
{
if (invocation.Arguments.Count < 2)
return (null, SpecialType.UnknownType);
@ -580,10 +628,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -580,10 +628,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return (null, SpecialType.UnknownType);
if (exprType.IsSmallIntegerType() && targetType.IsKnownType(KnownTypeCode.Int32))
return (expr, targetType);
return (new ExpressionTreeCast(targetType, expr, isChecked), targetType);
return (() => new ExpressionTreeCast(targetType, expr(), isChecked), targetType);
}
(ILInstruction, IType) ConvertCoalesce(CallInstruction invocation)
(Func<ILInstruction>, IType) ConvertCoalesce(CallInstruction invocation)
{
if (invocation.Arguments.Count != 2)
return (null, SpecialType.UnknownType);
@ -604,12 +652,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -604,12 +652,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms
} else {
targetType = fallbackInstType;
}
return (new NullCoalescingInstruction(kind, trueInst, fallbackInst) {
return (() => new NullCoalescingInstruction(kind, trueInst(), fallbackInst()) {
UnderlyingResultType = trueInstTypeNonNullable.GetStackType()
}, targetType);
}
(ILInstruction, IType) ConvertComparison(CallInstruction invocation, ComparisonKind kind)
(Func<ILInstruction>, IType) ConvertComparison(CallInstruction invocation, ComparisonKind kind)
{
if (invocation.Arguments.Count < 2)
return (null, SpecialType.UnknownType);
@ -623,11 +671,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -623,11 +671,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (isLifted != 0) {
method = CSharpOperators.LiftUserDefinedOperator((IMethod)method);
}
return (new Call((IMethod)method) { Arguments = { left, right } }, method.ReturnType);
return (() => new Call((IMethod)method) { Arguments = { left(), right() } }, method.ReturnType);
}
var rr = resolver.ResolveBinaryOperator(kind.ToBinaryOperatorType(), new ResolveResult(leftType), new ResolveResult(rightType)) as OperatorResolveResult;
if (rr != null && !rr.IsError && rr.UserDefinedOperatorMethod != null) {
return (new Call(rr.UserDefinedOperatorMethod) { Arguments = { left, right } }, rr.UserDefinedOperatorMethod.ReturnType);
return (() => new Call(rr.UserDefinedOperatorMethod) { Arguments = { left(), right() } }, rr.UserDefinedOperatorMethod.ReturnType);
}
if (leftType.IsKnownType(KnownTypeCode.String) && rightType.IsKnownType(KnownTypeCode.String)) {
IMethod operatorMethod;
@ -645,15 +693,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -645,15 +693,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms
default:
return (null, SpecialType.UnknownType);
}
return (new Call(operatorMethod) { Arguments = { left, right } }, operatorMethod.ReturnType);
return (() => new Call(operatorMethod) { Arguments = { left(), right() } }, operatorMethod.ReturnType);
}
var resultType = context.TypeSystem.FindType(KnownTypeCode.Boolean);
var lifting = NullableType.IsNullable(leftType) ? ComparisonLiftingKind.CSharp : ComparisonLiftingKind.None;
var utype = NullableType.GetUnderlyingType(leftType);
return (new Comp(kind, lifting, utype.GetStackType(), utype.GetSign(), left, right), resultType);
return (() => new Comp(kind, lifting, utype.GetStackType(), utype.GetSign(), left(), right()), resultType);
}
(ILInstruction, IType) ConvertCondition(CallInstruction invocation)
(Func<ILInstruction>, IType) ConvertCondition(CallInstruction invocation)
{
if (invocation.Arguments.Count != 3)
return (null, SpecialType.UnknownType);
@ -666,25 +714,24 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -666,25 +714,24 @@ namespace ICSharpCode.Decompiler.IL.Transforms
var (falseInst, falseInstType) = ConvertInstruction(invocation.Arguments[2]);
if (falseInst == null)
return (null, SpecialType.UnknownType);
if (!trueInstType.Equals(falseInstType))
if (!NormalizeTypeVisitor.TypeErasure.EquivalentTypes(trueInstType, falseInstType))
return (null, SpecialType.UnknownType);
return (new IfInstruction(condition, trueInst, falseInst), trueInstType);
return (() => new IfInstruction(condition(), trueInst(), falseInst()), trueInstType);
}
(ILInstruction, IType) ConvertConstant(CallInstruction invocation)
(Func<ILInstruction>, IType) ConvertConstant(CallInstruction invocation)
{
if (!MatchConstantCall(invocation, out var value, out var type))
return (null, SpecialType.UnknownType);
if (value.MatchBox(out var arg, out var boxType)) {
if (boxType.Kind == TypeKind.Enum || boxType.IsKnownType(KnownTypeCode.Boolean))
return (new ExpressionTreeCast(boxType, ConvertValue(arg, invocation), false), boxType);
value = ConvertValue(arg, invocation);
return (value, type);
return (() => new ExpressionTreeCast(boxType, ConvertValue(arg, invocation), false), boxType);
return (() => ConvertValue(arg, invocation), type);
}
return (ConvertValue(value, invocation), type);
return (() => ConvertValue(value, invocation), type);
}
(ILInstruction, IType) ConvertElementInit(CallInstruction invocation)
(Func<ILInstruction>, IType) ConvertElementInit(CallInstruction invocation)
{
if (invocation.Arguments.Count != 2)
return (null, SpecialType.UnknownType);
@ -692,77 +739,97 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -692,77 +739,97 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return (null, SpecialType.UnknownType);
if (!MatchArgumentList(invocation.Arguments[1], out var arguments))
return (null, SpecialType.UnknownType);
CallInstruction call = new Call((IMethod)member);
var args = new Func<ILInstruction>[arguments.Count];
for (int i = 0; i < arguments.Count; i++) {
ILInstruction arg = ConvertInstruction(arguments[i]).Item1;
var arg = ConvertInstruction(arguments[i]).Item1;
if (arg == null)
return (null, SpecialType.UnknownType);
arguments[i] = arg;
args[i] = arg;
}
ILInstruction BuildCall()
{
CallInstruction call = new Call((IMethod)member);
call.Arguments.AddRange(args.Select(f => f()));
return call;
}
call.Arguments.AddRange(arguments);
return (call, member.ReturnType);
return (BuildCall, member.ReturnType);
}
(ILInstruction, IType) ConvertField(CallInstruction invocation, IType typeHint)
(Func<ILInstruction>, IType) ConvertField(CallInstruction invocation, IType typeHint)
{
if (invocation.Arguments.Count != 2)
return (null, SpecialType.UnknownType);
ILInstruction target = null;
Func<ILInstruction> targetConverter = null;
if (!invocation.Arguments[0].MatchLdNull()) {
target = ConvertInstruction(invocation.Arguments[0]).Item1;
if (target == null)
targetConverter = ConvertInstruction(invocation.Arguments[0]).Item1;
if (targetConverter == null)
return (null, SpecialType.UnknownType);
}
if (!MatchGetFieldFromHandle(invocation.Arguments[1], out var member))
return (null, SpecialType.UnknownType);
IType type = member.ReturnType;
if (typeHint.SkipModifiers() is ByReferenceType && !member.ReturnType.IsByRefLike) {
type = typeHint;
}
return (BuildField, type);
ILInstruction BuildField()
{
ILInstruction inst;
if (target == null) {
if (targetConverter == null) {
inst = new LdsFlda((IField)member);
} else {
var target = targetConverter();
if (member.DeclaringType.IsReferenceType == true) {
inst = new LdFlda(target, (IField)member);
} else {
inst = new LdFlda(new AddressOf(target, member.DeclaringType), (IField)member);
}
}
if (typeHint.SkipModifiers() is ByReferenceType brt && !member.ReturnType.IsByRefLike) {
type = typeHint;
} else {
if (!(typeHint.SkipModifiers() is ByReferenceType && !member.ReturnType.IsByRefLike)) {
inst = new LdObj(inst, member.ReturnType);
}
return (inst, type);
return inst;
}
}
(ILInstruction, IType) ConvertInvoke(CallInstruction invocation)
(Func<ILInstruction>, IType) ConvertInvoke(CallInstruction invocation)
{
if (invocation.Arguments.Count != 2)
return (null, SpecialType.UnknownType);
var (target, targetType) = ConvertInstruction(invocation.Arguments[0]);
if (target == null)
var (targetConverter, targetType) = ConvertInstruction(invocation.Arguments[0]);
if (targetConverter == null)
return (null, SpecialType.UnknownType);
var invokeMethod = targetType.GetDelegateInvokeMethod();
if (invokeMethod == null)
return (null, SpecialType.UnknownType);
if (!MatchArgumentList(invocation.Arguments[1], out var arguments))
return (null, SpecialType.UnknownType);
if (!ConvertCallArguments(arguments, invokeMethod))
var convertedArguments = ConvertCallArguments(arguments, invokeMethod);
if (convertedArguments == null)
return (null, SpecialType.UnknownType);
ILInstruction BuildCall()
{
var call = new CallVirt(invokeMethod);
call.Arguments.Add(target);
call.Arguments.AddRange(arguments);
return (call, invokeMethod.ReturnType);
call.Arguments.Add(targetConverter());
call.Arguments.AddRange(convertedArguments.Select(f => f()));
return call;
}
return (BuildCall, invokeMethod.ReturnType);
}
(ILInstruction, IType) ConvertListInit(CallInstruction invocation)
(Func<ILInstruction>, IType) ConvertListInit(CallInstruction invocation)
{
if (invocation.Arguments.Count < 2)
return (null, SpecialType.UnknownType);
var newObj = ConvertInstruction(invocation.Arguments[0]).Item1 as NewObj;
var newObj = ConvertInstruction(invocation.Arguments[0]).Item1;
if (newObj == null)
return (null, SpecialType.UnknownType);
IList<ILInstruction> arguments = null;
ILFunction function = lambdaStack.Peek();
if (!MatchNew((CallInstruction)invocation.Arguments[0], out var ctor))
return (null, SpecialType.UnknownType);
IList<ILInstruction> arguments;
if (!MatchGetMethodFromHandle(invocation.Arguments[1], out var member)) {
if (!MatchArgumentList(invocation.Arguments[1], out arguments))
return (null, SpecialType.UnknownType);
@ -772,29 +839,37 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -772,29 +839,37 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
if (arguments == null || arguments.Count == 0)
return (null, SpecialType.UnknownType);
var initializer = function.RegisterVariable(VariableKind.InitializerTarget, newObj.Method.DeclaringType);
Func<ILVariable, ILInstruction>[] convertedArguments = new Func<ILVariable, ILInstruction>[arguments.Count];
for (int i = 0; i < arguments.Count; i++) {
ILInstruction arg;
if (arguments[i] is CallInstruction elementInit && elementInit.Method.FullName == "System.Linq.Expressions.Expression.ElementInit") {
arg = ConvertElementInit(elementInit).Item1;
var arg = ConvertElementInit(elementInit).Item1;
if (arg == null)
return (null, SpecialType.UnknownType);
((CallInstruction)arg).Arguments.Insert(0, new LdLoc(initializer));
convertedArguments[i] = v => { var a = arg(); ((CallInstruction)a).Arguments.Insert(0, new LdLoc(v)); return a; };
} else {
arg = ConvertInstruction(arguments[i]).Item1;
var arg = ConvertInstruction(arguments[i]).Item1;
if (arg == null)
return (null, SpecialType.UnknownType);
convertedArguments[i] = v => arg();
}
arguments[i] = arg;
}
Block BuildBlock()
{
var initializerBlock = new Block(BlockKind.CollectionInitializer);
ILFunction function = lambdaStack.Peek();
var initializer = function.RegisterVariable(VariableKind.InitializerTarget, ctor.DeclaringType);
initializerBlock.FinalInstruction = new LdLoc(initializer);
initializerBlock.Instructions.Add(new StLoc(initializer, newObj));
initializerBlock.Instructions.AddRange(arguments);
return (initializerBlock, initializer.Type);
initializerBlock.Instructions.Add(new StLoc(initializer, newObj()));
initializerBlock.Instructions.AddRange(convertedArguments.Select(f => f(initializer)));
return initializerBlock;
}
return (BuildBlock, ctor.DeclaringType);
}
(ILInstruction, IType) ConvertLogicOperator(CallInstruction invocation, bool and)
(Func<ILInstruction>, IType) ConvertLogicOperator(CallInstruction invocation, bool and)
{
if (invocation.Arguments.Count < 2)
return (null, SpecialType.UnknownType);
@ -808,12 +883,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -808,12 +883,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms
switch (invocation.Arguments.Count) {
case 2:
var resultType = context.TypeSystem.FindType(KnownTypeCode.Boolean);
return (and ? IfInstruction.LogicAnd(left, right) : IfInstruction.LogicOr(left, right), resultType);
return (() => and ? IfInstruction.LogicAnd(left(), right()) : IfInstruction.LogicOr(left(), right()), resultType);
case 3:
if (!MatchGetMethodFromHandle(invocation.Arguments[2], out method))
return (null, SpecialType.UnknownType);
return (new Call((IMethod)method) {
Arguments = { left, right }
return (() => new Call((IMethod)method) {
Arguments = { left(), right() }
}, method.ReturnType);
case 4:
if (!invocation.Arguments[2].MatchLdcI4(out var isLifted))
@ -822,46 +897,59 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -822,46 +897,59 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return (null, SpecialType.UnknownType);
if (isLifted != 0)
method = CSharpOperators.LiftUserDefinedOperator((IMethod)method);
return (new Call((IMethod)method) {
Arguments = { left, right }
return (() => new Call((IMethod)method) {
Arguments = { left(), right() }
}, method.ReturnType);
default:
return (null, SpecialType.UnknownType);
}
}
(ILInstruction, IType) ConvertMemberInit(CallInstruction invocation)
(Func<ILInstruction>, IType) ConvertMemberInit(CallInstruction invocation)
{
if (invocation.Arguments.Count != 2)
return (null, SpecialType.UnknownType);
var newObj = ConvertInstruction(invocation.Arguments[0]).Item1 as NewObj;
var newObj = ConvertInstruction(invocation.Arguments[0]).Item1;
if (newObj == null)
return (null, SpecialType.UnknownType);
if (!MatchNew((CallInstruction)invocation.Arguments[0], out var ctor))
return (null, SpecialType.UnknownType);
if (!MatchArgumentList(invocation.Arguments[1], out var arguments))
return (null, SpecialType.UnknownType);
if (arguments == null || arguments.Count == 0)
return (null, SpecialType.UnknownType);
var function = lambdaStack.Peek();
var initializer = function.RegisterVariable(VariableKind.InitializerTarget, newObj.Method.DeclaringType);
Func<ILVariable, ILInstruction>[] convertedArguments = new Func<ILVariable, ILInstruction>[arguments.Count];
for (int i = 0; i < arguments.Count; i++) {
ILInstruction arg;
Func<ILVariable, ILInstruction> arg;
if (arguments[i] is CallInstruction bind && bind.Method.FullName == "System.Linq.Expressions.Expression.Bind") {
arg = ConvertBind(bind, initializer).Item1;
arg = ConvertBind(bind).Item1;
if (arg == null)
return (null, SpecialType.UnknownType);
} else {
return (null, SpecialType.UnknownType);
}
arguments[i] = arg;
convertedArguments[i] = arg;
}
ILInstruction BuildBlock()
{
var function = lambdaStack.Peek();
var initializer = function.RegisterVariable(VariableKind.InitializerTarget, ctor.DeclaringType);
var initializerBlock = new Block(BlockKind.CollectionInitializer);
initializerBlock.FinalInstruction = new LdLoc(initializer);
initializerBlock.Instructions.Add(new StLoc(initializer, newObj));
initializerBlock.Instructions.AddRange(arguments);
return (initializerBlock, initializer.Type);
initializerBlock.Instructions.Add(new StLoc(initializer, newObj()));
initializerBlock.Instructions.AddRange(convertedArguments.Select(f => f(initializer)));
return initializerBlock;
}
(ILInstruction, IType) ConvertNewArrayBounds(CallInstruction invocation)
return (BuildBlock, ctor.DeclaringType);
}
(Func<ILInstruction>, IType) ConvertNewArrayBounds(CallInstruction invocation)
{
if (invocation.Arguments.Count != 2)
return (null, SpecialType.UnknownType);
@ -871,17 +959,17 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -871,17 +959,17 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return (null, SpecialType.UnknownType);
if (arguments.Count == 0)
return (null, SpecialType.UnknownType);
var indices = new ILInstruction[arguments.Count];
var indices = new Func<ILInstruction>[arguments.Count];
for (int i = 0; i < arguments.Count; i++) {
var index = ConvertInstruction(arguments[i]).Item1;
if (index == null)
return (null, SpecialType.UnknownType);
indices[i] = index;
}
return (new NewArr(type, indices), new ArrayType(context.TypeSystem, type, arguments.Count));
return (() => new NewArr(type, indices.SelectArray(f => f())), new ArrayType(context.TypeSystem, type, arguments.Count));
}
(ILInstruction, IType) ConvertNewArrayInit(CallInstruction invocation)
(Func<ILInstruction>, IType) ConvertNewArrayInit(CallInstruction invocation)
{
if (invocation.Arguments.Count != 2)
return (null, SpecialType.UnknownType);
@ -891,67 +979,107 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -891,67 +979,107 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return (null, SpecialType.UnknownType);
ArrayType arrayType = new ArrayType(context.BlockContext.TypeSystem, type);
if (arguments.Count == 0)
return (new NewArr(type, new LdcI4(0)), arrayType);
return (() => new NewArr(type, new LdcI4(0)), arrayType);
var convertedArguments = new Func<ILInstruction>[arguments.Count];
for (int i = 0; i < arguments.Count; i++) {
ILInstruction item = arguments[i];
var value = ConvertInstruction(item).Item1;
if (value == null)
return (null, SpecialType.UnknownType);
convertedArguments[i] = value;
}
ILInstruction BuildInitializer()
{
var block = (Block)invocation.Arguments[1];
var function = lambdaStack.Peek();
var variable = function.RegisterVariable(VariableKind.InitializerTarget, arrayType);
Block initializer = new Block(BlockKind.ArrayInitializer);
int i = 0;
initializer.Instructions.Add(new StLoc(variable, new NewArr(type, new LdcI4(arguments.Count))));
foreach (var item in arguments) {
var value = ConvertInstruction(item).Item1;
if (value == null)
return (null, SpecialType.UnknownType);
initializer.Instructions.Add(new StObj(new LdElema(type, new LdLoc(variable), new LdcI4(i)), value, type));
initializer.Instructions.Add(new StLoc(variable, new NewArr(type, new LdcI4(convertedArguments.Length))));
for (int i = 0; i < convertedArguments.Length; i++) {
initializer.Instructions.Add(new StObj(new LdElema(type, new LdLoc(variable), new LdcI4(i)), convertedArguments[i](), type));
}
initializer.FinalInstruction = new LdLoc(variable);
return (initializer, variable.Type);
return initializer;
}
return (BuildInitializer, arrayType);
}
(ILInstruction, IType) ConvertNewObject(CallInstruction invocation)
bool MatchNew(CallInstruction invocation, out IMethod ctor)
{
ctor = null;
if (invocation.Method.Name != "New")
return false;
switch (invocation.Arguments.Count) {
case 1:
if (MatchGetTypeFromHandle(invocation.Arguments[0], out var type)) {
ctor = type.GetConstructors(c => c.Parameters.Count == 0).FirstOrDefault();
return ctor != null;
}
if (MatchGetConstructorFromHandle(invocation.Arguments[0], out var member)) {
ctor = (IMethod)member;
return true;
}
return false;
case 2:
case 3:
if (!MatchGetConstructorFromHandle(invocation.Arguments[0], out member))
return false;
ctor = (IMethod)member;
return true;
default:
return false;
}
}
(Func<ILInstruction>, IType) ConvertNewObject(CallInstruction invocation)
{
IMember member;
IList<ILInstruction> arguments;
NewObj newObj;
switch (invocation.Arguments.Count) {
case 1:
if (MatchGetTypeFromHandle(invocation.Arguments[0], out var type)) {
var ctor = type.GetConstructors(c => c.Parameters.Count == 0).FirstOrDefault();
if (ctor == null)
return (null, SpecialType.UnknownType);
return (new NewObj(ctor), type);
return (() => new NewObj(ctor), type);
}
if (MatchGetConstructorFromHandle(invocation.Arguments[0], out member)) {
return (new NewObj((IMethod)member), member.DeclaringType);
if (MatchGetConstructorFromHandle(invocation.Arguments[0], out var member)) {
return (() => new NewObj((IMethod)member), member.DeclaringType);
}
return (null, SpecialType.UnknownType);
case 2:
if (!MatchGetConstructorFromHandle(invocation.Arguments[0], out member))
return (null, SpecialType.UnknownType);
if (!MatchArgumentList(invocation.Arguments[1], out arguments))
if (!MatchArgumentList(invocation.Arguments[1], out var arguments))
return (null, SpecialType.UnknownType);
IMethod method = (IMethod)member;
if (!ConvertCallArguments(arguments, method))
Func<ILInstruction>[] convertedArguments = ConvertCallArguments(arguments, method);
if (convertedArguments == null)
return (null, SpecialType.UnknownType);
newObj = new NewObj(method);
newObj.Arguments.AddRange(arguments);
return (newObj, member.DeclaringType);
return (() => BuildNewObj(method, convertedArguments), member.DeclaringType);
case 3:
if (!MatchGetConstructorFromHandle(invocation.Arguments[0], out member))
return (null, SpecialType.UnknownType);
if (!MatchArgumentList(invocation.Arguments[1], out arguments))
return (null, SpecialType.UnknownType);
method = (IMethod)member;
if (!ConvertCallArguments(arguments, method))
convertedArguments = ConvertCallArguments(arguments, method);
if (convertedArguments == null)
return (null, SpecialType.UnknownType);
newObj = new NewObj(method);
newObj.Arguments.AddRange(arguments);
return (newObj, member.DeclaringType);
return (() => BuildNewObj(method, convertedArguments), member.DeclaringType);
}
ILInstruction BuildNewObj(IMethod method, Func<ILInstruction>[] args)
{
var newObj = new NewObj(method);
newObj.Arguments.AddRange(args.Select(f => f()));
return newObj;
}
return (null, SpecialType.UnknownType);
}
(ILInstruction, IType) ConvertNotOperator(CallInstruction invocation)
(Func<ILInstruction>, IType) ConvertNotOperator(CallInstruction invocation)
{
if (invocation.Arguments.Count < 1)
return (null, SpecialType.UnknownType);
@ -960,27 +1088,27 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -960,27 +1088,27 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return (null, SpecialType.UnknownType);
switch (invocation.Arguments.Count) {
case 1:
return (argumentType.IsKnownType(KnownTypeCode.Boolean) ? Comp.LogicNot(argument) : (ILInstruction)new BitNot(argument), argumentType);
return (() => argumentType.IsKnownType(KnownTypeCode.Boolean) ? Comp.LogicNot(argument()) : (ILInstruction)new BitNot(argument()), argumentType);
case 2:
if (!MatchGetMethodFromHandle(invocation.Arguments[1], out var method))
return (null, SpecialType.UnknownType);
return (new Call((IMethod)method) {
Arguments = { argument }
return (() => new Call((IMethod)method) {
Arguments = { argument() }
}, method.ReturnType);
default:
return (null, SpecialType.UnknownType);
}
}
(ILInstruction, IType) ConvertProperty(CallInstruction invocation)
(Func<ILInstruction>, IType) ConvertProperty(CallInstruction invocation)
{
if (invocation.Arguments.Count < 2)
return (null, SpecialType.UnknownType);
ILInstruction target = null;
Func<ILInstruction> targetConverter = null;
IType targetType = null;
if (!invocation.Arguments[0].MatchLdNull()) {
(target, targetType) = ConvertInstruction(invocation.Arguments[0]);
if (target == null)
(targetConverter, targetType) = ConvertInstruction(invocation.Arguments[0]);
if (targetConverter == null)
return (null, SpecialType.UnknownType);
}
if (!MatchGetMethodFromHandle(invocation.Arguments[1], out var member))
@ -988,24 +1116,28 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -988,24 +1116,28 @@ namespace ICSharpCode.Decompiler.IL.Transforms
IList<ILInstruction> arguments;
if (invocation.Arguments.Count != 3 || !MatchArgumentList(invocation.Arguments[2], out arguments)) {
arguments = new List<ILInstruction>();
} else {
if (!ConvertCallArguments(arguments, (IMethod)member))
return (null, SpecialType.UnknownType);
}
var convertedArguments = ConvertCallArguments(arguments, (IMethod)member);
if (convertedArguments == null)
return (null, SpecialType.UnknownType);
ILInstruction BuildProperty()
{
CallInstruction call;
if (member.IsAbstract || member.IsVirtual || member.IsOverride) {
call = new CallVirt((IMethod)member);
} else {
call = new Call((IMethod)member);
}
if (target != null) {
call.Arguments.Add(PrepareCallTarget(member.DeclaringType, target, targetType));
if (targetConverter != null) {
call.Arguments.Add(PrepareCallTarget(member.DeclaringType, targetConverter(), targetType));
}
call.Arguments.AddRange(arguments);
return (call, member.ReturnType);
call.Arguments.AddRange(convertedArguments.Select(f => f()));
return call;
}
return (BuildProperty, member.ReturnType);
}
(ILInstruction, IType) ConvertTypeAs(CallInstruction invocation)
(Func<ILInstruction>, IType) ConvertTypeAs(CallInstruction invocation)
{
if (invocation.Arguments.Count != 2)
return (null, SpecialType.UnknownType);
@ -1014,16 +1146,19 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -1014,16 +1146,19 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return (null, SpecialType.UnknownType);
if (converted == null)
return (null, SpecialType.UnknownType);
ILInstruction inst = new IsInst(converted, type);
ILInstruction BuildTypeAs()
{
ILInstruction inst = new IsInst(converted(), type);
// We must follow ECMA-335, III.4.6:
// If typeTok is a nullable type, Nullable<T>, it is interpreted as "boxed" T.
if (type.IsKnownType(KnownTypeCode.NullableOfT))
inst = new UnboxAny(inst, type);
return (inst, type);
return inst;
}
return (BuildTypeAs, type);
}
(ILInstruction, IType) ConvertTypeIs(CallInstruction invocation)
(Func<ILInstruction>, IType) ConvertTypeIs(CallInstruction invocation)
{
if (invocation.Arguments.Count != 2)
return (null, SpecialType.UnknownType);
@ -1032,11 +1167,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -1032,11 +1167,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return (null, SpecialType.UnknownType);
var resultType = context.TypeSystem.FindType(KnownTypeCode.Boolean);
if (converted != null)
return (new Comp(ComparisonKind.Inequality, Sign.None, new IsInst(converted, type), new LdNull()), resultType);
return (() => new Comp(ComparisonKind.Inequality, Sign.None, new IsInst(converted(), type), new LdNull()), resultType);
return (null, SpecialType.UnknownType);
}
(ILInstruction, IType) ConvertUnaryNumericOperator(CallInstruction invocation, BinaryNumericOperator op, bool? isChecked = null)
(Func<ILInstruction>, IType) ConvertUnaryNumericOperator(CallInstruction invocation, BinaryNumericOperator op, bool? isChecked = null)
{
if (invocation.Arguments.Count < 1)
return (null, SpecialType.UnknownType);
@ -1046,7 +1181,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -1046,7 +1181,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
switch (invocation.Arguments.Count) {
case 1:
ILInstruction left;
switch (argument.ResultType) {
switch (argumentType.GetStackType()) {
case StackType.I4:
left = new LdcI4(0);
break;
@ -1065,12 +1200,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -1065,12 +1200,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms
default:
return (null, SpecialType.UnknownType);
}
return (new BinaryNumericInstruction(op, left, argument, isChecked == true, argumentType.GetSign()), argumentType);
return (() => new BinaryNumericInstruction(op, left, argument(), isChecked == true, argumentType.GetSign()), argumentType);
case 2:
if (!MatchGetMethodFromHandle(invocation.Arguments[1], out var method))
return (null, SpecialType.UnknownType);
return (new Call((IMethod)method) {
Arguments = { argument }
return (() => new Call((IMethod)method) {
Arguments = { argument() }
}, method.ReturnType);
}
return (null, SpecialType.UnknownType);
@ -1082,11 +1217,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -1082,11 +1217,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms
case LdLoc ldloc:
if (IsExpressionTreeParameter(ldloc.Variable)) {
if (!parameterMapping.TryGetValue(ldloc.Variable, out var v))
return ldloc;
return ldloc.Clone();
if (context is CallInstruction parentCall
&& parentCall.Method.FullName == "System.Linq.Expressions.Expression.Call"
&& v.StackType.IsIntegerType())
return new LdLoca(v);
return new LdLoca(v).WithILRange(ldloc);
return null;
} else if (IsClosureReference(ldloc.Variable)) {
if (ldloc.Variable.Kind == VariableKind.Local) {

2
ICSharpCode.Decompiler/Metadata/DotNetCorePathFinder.cs

@ -206,7 +206,7 @@ namespace ICSharpCode.Decompiler.Metadata @@ -206,7 +206,7 @@ namespace ICSharpCode.Decompiler.Metadata
}
}
static string FindDotNetExeDirectory()
public static string FindDotNetExeDirectory()
{
string dotnetExeName = (Environment.OSVersion.Platform == PlatformID.Unix) ? "dotnet" : "dotnet.exe";
foreach (var item in Environment.GetEnvironmentVariable("PATH").Split(Path.PathSeparator)) {

28
ICSharpCode.Decompiler/Metadata/DotNetCorePathFinderExtensions.cs

@ -29,8 +29,16 @@ namespace ICSharpCode.Decompiler.Metadata @@ -29,8 +29,16 @@ namespace ICSharpCode.Decompiler.Metadata
public static class DotNetCorePathFinderExtensions
{
static readonly string RefPathPattern =
@"(Reference Assemblies[/\\]Microsoft[/\\]Framework[/\\](?<1>.NETFramework)[/\\]v(?<2>[^/\\]+)[/\\])" +
@"|(NuGetFallbackFolder[/\\](?<1>[^/\\]+)\\(?<2>[^/\\]+)([/\\].*)?[/\\]ref[/\\])";
@"(Reference Assemblies[/\\]Microsoft[/\\]Framework[/\\](?<type>.NETFramework)[/\\]v(?<version>[^/\\]+)[/\\])" +
@"|((?<type>Microsoft\.NET)[/\\]assembly[/\\]GAC_(MSIL|32|64)[/\\])" +
@"|((?<type>Microsoft\.NET)[/\\]Framework(64)?[/\\](?<version>[^/\\]+)[/\\])" +
@"|(NuGetFallbackFolder[/\\](?<type>[^/\\]+)\\(?<version>[^/\\]+)([/\\].*)?[/\\]ref[/\\])" +
@"|(shared[/\\](?<type>[^/\\]+)\\(?<version>[^/\\]+)([/\\].*)?[/\\])";
public static string DetectTargetFrameworkId(this PEFile assembly)
{
return DetectTargetFrameworkId(assembly.Reader, assembly.FileName);
}
public static string DetectTargetFrameworkId(this PEReader assembly, string assemblyPath = null)
{
@ -62,16 +70,20 @@ namespace ICSharpCode.Decompiler.Metadata @@ -62,16 +70,20 @@ namespace ICSharpCode.Decompiler.Metadata
var pathMatch = Regex.Match(assemblyPath, RefPathPattern,
RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.ExplicitCapture);
if (pathMatch.Success) {
var type = pathMatch.Groups[1].Value;
var version = pathMatch.Groups[2].Value;
var type = pathMatch.Groups["type"].Value;
var version = pathMatch.Groups["version"].Value;
if (string.IsNullOrEmpty(version))
version = reader.MetadataVersion;
if (type == ".NETFramework") {
return $".NETFramework,Version=v{version}";
} else if (type.Contains("netcore")) {
if (type == "Microsoft.NET" || type == ".NETFramework") {
return $".NETFramework,Version=v{version.TrimStart('v').Substring(0, 3)}";
} else if (type.IndexOf("netcore", StringComparison.OrdinalIgnoreCase) >= 0) {
return $".NETCoreApp,Version=v{version}";
} else if (type.Contains("netstandard")) {
} else if (type.IndexOf("netstandard", StringComparison.OrdinalIgnoreCase) >= 0) {
return $".NETStandard,Version=v{version}";
}
} else {
return $".NETFramework,Version={reader.MetadataVersion.Substring(0, 4)}";
}
}

38
ICSharpCode.Decompiler/Metadata/UniversalAssemblyResolver.cs

@ -23,6 +23,7 @@ using System.Linq; @@ -23,6 +23,7 @@ using System.Linq;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
using System.Text;
using System.Text.RegularExpressions;
namespace ICSharpCode.Decompiler.Metadata
{
@ -63,7 +64,7 @@ namespace ICSharpCode.Decompiler.Metadata @@ -63,7 +64,7 @@ namespace ICSharpCode.Decompiler.Metadata
readonly string mainAssemblyFileName;
readonly string baseDirectory;
readonly List<string> directories = new List<string>();
readonly List<string> gac_paths = GetGacPaths();
static readonly List<string> gac_paths = GetGacPaths();
HashSet<string> targetFrameworkSearchPaths;
static readonly DecompilerRuntime decompilerRuntime;
@ -465,7 +466,7 @@ namespace ICSharpCode.Decompiler.Metadata @@ -465,7 +466,7 @@ namespace ICSharpCode.Decompiler.Metadata
return path;
}
static List<string> GetGacPaths()
public static List<string> GetGacPaths()
{
if (decompilerRuntime == DecompilerRuntime.Mono)
return GetDefaultMonoGacPaths();
@ -512,7 +513,7 @@ namespace ICSharpCode.Decompiler.Metadata @@ -512,7 +513,7 @@ namespace ICSharpCode.Decompiler.Metadata
"gac");
}
string GetAssemblyInGac(IAssemblyReference reference)
public static string GetAssemblyInGac(IAssemblyReference reference)
{
if (reference.PublicKeyToken == null || reference.PublicKeyToken.Length == 0)
return null;
@ -523,7 +524,7 @@ namespace ICSharpCode.Decompiler.Metadata @@ -523,7 +524,7 @@ namespace ICSharpCode.Decompiler.Metadata
return GetAssemblyInNetGac(reference);
}
string GetAssemblyInMonoGac(IAssemblyReference reference)
static string GetAssemblyInMonoGac(IAssemblyReference reference)
{
for (int i = 0; i < gac_paths.Count; i++) {
var gac_path = gac_paths[i];
@ -535,7 +536,7 @@ namespace ICSharpCode.Decompiler.Metadata @@ -535,7 +536,7 @@ namespace ICSharpCode.Decompiler.Metadata
return null;
}
string GetAssemblyInNetGac(IAssemblyReference reference)
static string GetAssemblyInNetGac(IAssemblyReference reference)
{
var gacs = new[] { "GAC_MSIL", "GAC_32", "GAC_64", "GAC" };
var prefixes = new[] { string.Empty, "v4.0_" };
@ -568,6 +569,33 @@ namespace ICSharpCode.Decompiler.Metadata @@ -568,6 +569,33 @@ namespace ICSharpCode.Decompiler.Metadata
reference.Name + ".dll");
}
/// <summary>
/// Gets the names of all assemblies in the GAC.
/// </summary>
public static IEnumerable<AssemblyNameReference> EnumerateGac()
{
var gacs = new[] { "GAC_MSIL", "GAC_32", "GAC_64", "GAC" };
foreach (var path in GetGacPaths()) {
foreach (var gac in gacs) {
string rootPath = Path.Combine(path, gac);
if (!Directory.Exists(rootPath))
continue;
foreach (var item in new DirectoryInfo(rootPath).EnumerateFiles("*.dll", SearchOption.AllDirectories)) {
string[] name = Path.GetDirectoryName(item.FullName).Substring(rootPath.Length + 1).Split(new[] { "\\" }, StringSplitOptions.RemoveEmptyEntries);
if (name.Length != 2)
continue;
var match = Regex.Match(name[1], $"(v4.0_)?(?<version>[^_]+)_(?<culture>[^_]+)?_(?<publicKey>[^_]+)");
if (!match.Success)
continue;
string culture = match.Groups["culture"].Value;
if (string.IsNullOrEmpty(culture))
culture = "neutral";
yield return AssemblyNameReference.Parse(name[0] + ", Version=" + match.Groups["version"].Value + ", Culture=" + culture + ", PublicKeyToken=" + match.Groups["publicKey"].Value);
}
}
}
}
#endregion
}
}

3
ILSpy.AddIn/Commands/ProjectReferenceForILSpy.cs

@ -4,6 +4,7 @@ using System.Linq; @@ -4,6 +4,7 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using EnvDTE;
using ICSharpCode.Decompiler.Metadata;
using Microsoft.VisualStudio.Shell;
using Mono.Cecil;
@ -74,7 +75,7 @@ namespace ICSharpCode.ILSpy.AddIn.Commands @@ -74,7 +75,7 @@ namespace ICSharpCode.ILSpy.AddIn.Commands
if (resolvedPath != null) {
return new ILSpyParameters(new[] { $"{resolvedPath}" });
} else if (!string.IsNullOrWhiteSpace(fusionName)) {
return new ILSpyParameters(new string[] { GacInterop.FindAssemblyInNetGac(Decompiler.Metadata.AssemblyNameReference.Parse(fusionName)) });
return new ILSpyParameters(new string[] { UniversalAssemblyResolver.GetAssemblyInGac(Decompiler.Metadata.AssemblyNameReference.Parse(fusionName)) });
}
return null;

19
ILSpy.BamlDecompiler.Tests/BamlTestRunner.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
// Copyright (c) 2020 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections;

19
ILSpy.BamlDecompiler.Tests/Cases/AttachedEvent.xaml.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
// Copyright (c) 2020 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.Windows;

20
ILSpy.BamlDecompiler.Tests/Cases/CustomControl.cs

@ -1,4 +1,22 @@ @@ -1,4 +1,22 @@
using System.Windows;
// Copyright (c) 2020 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System.Windows;
using System.Windows.Controls;
namespace ILSpy.BamlDecompiler.Tests.Cases

20
ILSpy.BamlDecompiler.Tests/Cases/Issue1547.xaml.cs

@ -1,4 +1,22 @@ @@ -1,4 +1,22 @@
using System;
// Copyright (c) 2020 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.Linq;
using System.Text;

19
ILSpy.BamlDecompiler.Tests/Cases/MyControl.xaml.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
// Copyright (c) 2020 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.Windows.Controls;

19
ILSpy.BamlDecompiler.Tests/Cases/Resources.xaml.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
// Copyright (c) 2020 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.Windows;

19
ILSpy.BamlDecompiler.Tests/Cases/Simple.xaml.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
// Copyright (c) 2020 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.Windows;

19
ILSpy.BamlDecompiler.Tests/Cases/SimpleNames.xaml.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
// Copyright (c) 2020 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.Windows;

19
ILSpy.BamlDecompiler.Tests/Mocks/AvalonDock.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
// Copyright (c) 2020 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.Windows;
using System.Windows.Controls.Primitives;

4
ILSpy.ReadyToRun/ILSpy.ReadyToRun.csproj

@ -56,8 +56,8 @@ @@ -56,8 +56,8 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Iced" Version="1.4.0" />
<PackageReference Include="ILCompiler.Reflection.ReadyToRun" Version="1.0.6-alpha" />
<PackageReference Include="Iced" Version="1.6.0" />
<PackageReference Include="ILCompiler.Reflection.ReadyToRun" Version="1.0.7-alpha" />
</ItemGroup>
<Import Sdk="Microsoft.NET.Sdk" Project="Sdk.targets" />

15
ILSpy.ReadyToRun/ReadyToRunLanguage.cs

@ -125,13 +125,24 @@ namespace ICSharpCode.ILSpy.ReadyToRun @@ -125,13 +125,24 @@ namespace ICSharpCode.ILSpy.ReadyToRun
}
formatter.Options.DigitSeparator = "`";
formatter.Options.FirstOperandCharIndex = 10;
var tempOutput = new StringBuilderFormatterOutput();
var tempOutput = new StringOutput();
foreach (var instr in instructions) {
int byteBaseIndex = (int)(instr.IP - address);
foreach (var bound in runtimeFunction.DebugInfo.BoundsList) {
if (bound.NativeOffset == byteBaseIndex) {
if (bound.ILOffset == (uint)DebugInfoBoundsType.Prolog) {
WriteCommentLine(output, "Prolog");
} else if (bound.ILOffset == (uint)DebugInfoBoundsType.Epilog) {
WriteCommentLine(output, "Epilog");
} else {
WriteCommentLine(output, $"IL_{bound.ILOffset:x4}");
}
}
}
formatter.Format(instr, tempOutput);
output.Write(instr.IP.ToString("X16"));
output.Write(" ");
int instrLen = instr.ByteLength;
int instrLen = instr.Length;
for (int i = 0; i < instrLen; i++)
output.Write(codeBytes[byteBaseIndex + i].ToString("X2"));
int missingBytes = 10 - instrLen;

4
ILSpy.Tests/ILSpy.Tests.csproj

@ -45,8 +45,8 @@ @@ -45,8 +45,8 @@
<ItemGroup>
<PackageReference Include="DiffLib" Version="2017.7.26.1241" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.5.0-beta2-final" />
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic" Version="3.5.0-beta2-final" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="3.6.0-3.final" />
<PackageReference Include="Microsoft.CodeAnalysis.VisualBasic" Version="3.6.0-3.final" />
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
<PackageReference Include="System.Collections.Immutable" Version="1.5.0" />
<PackageReference Include="NUnit" Version="3.11.0" />

4
ILSpy/Analyzers/Builtin/TypeUsedByAnalyzer.cs

@ -82,6 +82,10 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin @@ -82,6 +82,10 @@ namespace ICSharpCode.ILSpy.Analyzers.Builtin
method.ReturnType.AcceptVisitor(visitor);
foreach (var t in method.TypeArguments) {
t.AcceptVisitor(visitor);
}
if (scanBodies && !visitor.Found)
ScanMethodBody(visitor, method, context.GetMethodBody(method), context);

2
ILSpy/AssemblyList.cs

@ -39,7 +39,7 @@ namespace ICSharpCode.ILSpy @@ -39,7 +39,7 @@ namespace ICSharpCode.ILSpy
/// <summary>Dirty flag, used to mark modifications so that the list is saved later</summary>
bool dirty;
internal readonly ConcurrentDictionary<(string assemblyName, bool isWinRT), LoadedAssembly> assemblyLookupCache = new ConcurrentDictionary<(string assemblyName, bool isWinRT), LoadedAssembly>();
internal readonly ConcurrentDictionary<(string assemblyName, bool isWinRT, string targetFrameworkIdentifier), LoadedAssembly> assemblyLookupCache = new ConcurrentDictionary<(string assemblyName, bool isWinRT, string targetFrameworkIdentifier), LoadedAssembly>();
internal readonly ConcurrentDictionary<string, LoadedAssembly> moduleLookupCache = new ConcurrentDictionary<string, LoadedAssembly>();
/// <summary>

35
ILSpy/AssemblyListManager.cs

@ -20,6 +20,7 @@ using System; @@ -20,6 +20,7 @@ using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Xml.Linq;
using ICSharpCode.ILSpy.ViewModels;
namespace ICSharpCode.ILSpy
{
@ -76,6 +77,13 @@ namespace ICSharpCode.ILSpy @@ -76,6 +77,13 @@ namespace ICSharpCode.ILSpy
return CreateList(newList);
}
public bool RenameList(string selectedAssemblyList, string newListName)
{
var list = DoLoadList(spySettings, selectedAssemblyList);
var newList = new AssemblyList(list, newListName);
return DeleteList(selectedAssemblyList) && CreateList(newList);
}
public const string DefaultListName = "(Default)";
/// <summary>
@ -144,5 +152,32 @@ namespace ICSharpCode.ILSpy @@ -144,5 +152,32 @@ namespace ICSharpCode.ILSpy
doc.Remove();
});
}
public void CreateDefaultAssemblyLists()
{
if (AssemblyLists.Count > 0)
return;
if (!AssemblyLists.Contains(ManageAssemblyListsViewModel.DotNet4List)) {
AssemblyList dotnet4 = ManageAssemblyListsViewModel.CreateDefaultList(ManageAssemblyListsViewModel.DotNet4List);
if (dotnet4.assemblies.Count > 0) {
CreateList(dotnet4);
}
}
if (!AssemblyLists.Contains(ManageAssemblyListsViewModel.DotNet35List)) {
AssemblyList dotnet35 = ManageAssemblyListsViewModel.CreateDefaultList(ManageAssemblyListsViewModel.DotNet35List);
if (dotnet35.assemblies.Count > 0) {
CreateList(dotnet35);
}
}
if (!AssemblyLists.Contains(ManageAssemblyListsViewModel.ASPDotNetMVC3List)) {
AssemblyList mvc = ManageAssemblyListsViewModel.CreateDefaultList(ManageAssemblyListsViewModel.ASPDotNetMVC3List);
if (mvc.assemblies.Count > 0) {
CreateList(mvc);
}
}
}
}
}

32
ILSpy/Commands/DecompileCommand.cs

@ -1,20 +1,28 @@ @@ -1,20 +1,28 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Linq;
using System.Reflection;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpy.Analyzers;
using ICSharpCode.ILSpy.Controls;
using ICSharpCode.ILSpy.Metadata;
using ICSharpCode.ILSpy.TreeNodes;
@ -66,7 +74,7 @@ namespace ICSharpCode.ILSpy.Commands @@ -66,7 +74,7 @@ namespace ICSharpCode.ILSpy.Commands
public void Execute(TextViewContext context)
{
int token = GetSelectedToken(context.DataGrid, out PEFile module).Value;
MainWindow.Instance.JumpToReference(("metadata", module, MetadataTokens.Handle(token)));
MainWindow.Instance.JumpToReference(new EntityReference("metadata", module, MetadataTokens.Handle(token)));
}
public bool IsEnabled(TextViewContext context)

32
ILSpy/Commands/DelegateCommand.cs

@ -7,6 +7,38 @@ using System.Windows.Input; @@ -7,6 +7,38 @@ using System.Windows.Input;
namespace ICSharpCode.ILSpy.Commands
{
public class DelegateCommand : ICommand
{
private readonly Action action;
private readonly Func<bool> canExecute;
public event EventHandler CanExecuteChanged {
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public DelegateCommand(Action action)
: this(action, () => true)
{
}
public DelegateCommand(Action action, Func<bool> canExecute)
{
this.action = action;
this.canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return canExecute();
}
public void Execute(object parameter)
{
action();
}
}
public class DelegateCommand<T> : ICommand
{
private readonly Action<T> action;

45
ILSpy/EntityReference.cs

@ -0,0 +1,45 @@ @@ -0,0 +1,45 @@
// Copyright (c) 2018 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.Diagnostics;
using System.Reflection.Metadata;
using ICSharpCode.Decompiler.Metadata;
namespace ICSharpCode.ILSpy
{
[DebuggerDisplay("EntityReference Module={Module}, Handle={Handle}, Protocol={Protocol}")]
public class EntityReference
{
public PEFile Module { get; }
public Handle Handle { get; }
public string Protocol { get; }
public EntityReference(PEFile module, Handle handle)
{
this.Module = module ?? throw new ArgumentNullException(nameof(module));
this.Handle = handle;
}
public EntityReference(string protocol, PEFile module, Handle handle)
: this(module, handle)
{
this.Protocol = protocol ?? "decompile";
}
}
}

135
ILSpy/Fusion.cs

@ -1,135 +0,0 @@ @@ -1,135 +0,0 @@
// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace ICSharpCode.ILSpy
{
// .NET Fusion COM interfaces
[ComImport(), Guid("CD193BC0-B4BC-11D2-9833-00C04FC31D2E"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IAssemblyName
{
[PreserveSig()]
int SetProperty(uint PropertyId, IntPtr pvProperty, uint cbProperty);
[PreserveSig()]
int GetProperty(uint PropertyId, IntPtr pvProperty, ref uint pcbProperty);
[PreserveSig()]
int Finalize();
[PreserveSig()]
int GetDisplayName([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder szDisplayName,
ref uint pccDisplayName,
uint dwDisplayFlags);
[PreserveSig()]
int BindToObject(object refIID,
object pAsmBindSink,
IApplicationContext pApplicationContext,
[MarshalAs(UnmanagedType.LPWStr)] string szCodeBase,
long llFlags,
int pvReserved,
uint cbReserved,
out int ppv);
[PreserveSig()]
int GetName(ref uint lpcwBuffer,
[Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pwzName);
[PreserveSig()]
int GetVersion(out uint pdwVersionHi, out uint pdwVersionLow);
[PreserveSig()]
int IsEqual(IAssemblyName pName,
uint dwCmpFlags);
[PreserveSig()]
int Clone(out IAssemblyName pName);
}
[ComImport(), Guid("7C23FF90-33AF-11D3-95DA-00A024A85B51"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IApplicationContext
{
void SetContextNameObject(IAssemblyName pName);
void GetContextNameObject(out IAssemblyName ppName);
void Set([MarshalAs(UnmanagedType.LPWStr)] string szName,
int pvValue,
uint cbValue,
uint dwFlags);
void Get([MarshalAs(UnmanagedType.LPWStr)] string szName,
out int pvValue,
ref uint pcbValue,
uint dwFlags);
void GetDynamicDirectory(out int wzDynamicDir,
ref uint pdwSize);
}
[ComImport(), Guid("21B8916C-F28E-11D2-A473-00C04F8EF448"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IAssemblyEnum
{
[PreserveSig()]
int GetNextAssembly(out IApplicationContext ppAppCtx,
out IAssemblyName ppName,
uint dwFlags);
[PreserveSig()]
int Reset();
[PreserveSig()]
int Clone(out IAssemblyEnum ppEnum);
}
internal static class Fusion
{
// dwFlags: 1 = Enumerate native image (NGEN) assemblies
// 2 = Enumerate GAC assemblies
// 4 = Enumerate Downloaded assemblies
//
[DllImport("fusion.dll", CharSet=CharSet.Auto)]
internal static extern int CreateAssemblyEnum(out IAssemblyEnum ppEnum,
IApplicationContext pAppCtx,
IAssemblyName pName,
uint dwFlags,
int pvReserved);
[DllImport("fusion.dll")]
internal static extern int GetCachePath(uint flags,
[MarshalAs(UnmanagedType.LPWStr)] StringBuilder wzDir,
ref uint pdwSize);
public static string GetGacPath(bool isCLRv4 = false)
{
const uint ASM_CACHE_ROOT = 0x08; // CLR V2.0
const uint ASM_CACHE_ROOT_EX = 0x80; // CLR V4.0
uint flags = isCLRv4 ? ASM_CACHE_ROOT_EX : ASM_CACHE_ROOT;
const int size = 260; // MAX_PATH
StringBuilder b = new StringBuilder(size);
uint tmp = size;
GetCachePath(flags, b, ref tmp);
return b.ToString();
}
}
}

137
ILSpy/GacInterop.cs

@ -1,137 +0,0 @@ @@ -1,137 +0,0 @@
// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Windows;
using ICSharpCode.Decompiler.Metadata;
namespace ICSharpCode.ILSpy
{
/// <summary>
/// Interop with the .NET GAC.
/// </summary>
static class GacInterop
{
/// <summary>
/// Gets the names of all assemblies in the GAC.
/// </summary>
public static IEnumerable<AssemblyNameReference> GetGacAssemblyFullNames()
{
IApplicationContext applicationContext = null;
IAssemblyEnum assemblyEnum = null;
IAssemblyName assemblyName = null;
uint result = unchecked((uint)Fusion.CreateAssemblyEnum(out assemblyEnum, null, null, 2, 0));
if (result == 0x80070005) {
MessageBox.Show($"Cannot access GAC, please restart with elevated privileges! (HRESULT 0x{result:X})", "ILSpy", MessageBoxButton.OK, MessageBoxImage.Error);
yield break;
}
while (assemblyEnum.GetNextAssembly(out applicationContext, out assemblyName, 0) == 0) {
if (assemblyName == null) continue;
uint nChars = 0;
assemblyName.GetDisplayName(null, ref nChars, 0);
StringBuilder name = new StringBuilder((int)nChars);
assemblyName.GetDisplayName(name, ref nChars, 0);
AssemblyNameReference r = null;
try {
r = AssemblyNameReference.Parse(name.ToString());
} catch (ArgumentException) {
} catch (FormatException) {
} catch (OverflowException) {
}
if (r != null)
yield return r;
}
}
#region FindAssemblyInGac
// This region is based on code from Mono.Cecil:
// Author:
// Jb Evain (jbevain@gmail.com)
//
// Copyright (c) 2008 - 2010 Jb Evain
//
// 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.
//
static readonly string[] gac_paths = { Fusion.GetGacPath(false), Fusion.GetGacPath(true) };
static readonly string[] gacs = { "GAC_MSIL", "GAC_32", "GAC" };
static readonly string[] prefixes = { string.Empty, "v4.0_" };
/// <summary>
/// Gets the file name for an assembly stored in the GAC.
/// </summary>
public static string FindAssemblyInNetGac (AssemblyNameReference reference)
{
// without public key, it can't be in the GAC
if (reference.PublicKeyToken == null)
return null;
for (int i = 0; i < 2; i++) {
for (int j = 0; j < gacs.Length; j++) {
var gac = Path.Combine (gac_paths [i], gacs [j]);
var file = GetAssemblyFile (reference, prefixes [i], gac);
if (File.Exists (file))
return file;
}
}
return null;
}
static string GetAssemblyFile (AssemblyNameReference reference, string prefix, string gac)
{
var gac_folder = new StringBuilder ()
.Append (prefix)
.Append (reference.Version)
.Append ("__");
for (int i = 0; i < reference.PublicKeyToken.Length; i++)
gac_folder.Append (reference.PublicKeyToken [i].ToString ("x2"));
return Path.Combine (
Path.Combine (
Path.Combine (gac, reference.Name), gac_folder.ToString ()),
reference.Name + ".dll");
}
#endregion
}
}

3
ILSpy/ILSpy.csproj

@ -138,6 +138,7 @@ @@ -138,6 +138,7 @@
<Compile Include="Controls\SearchBox.cs" />
<Compile Include="Controls\SortableGridViewColumn.cs" />
<Compile Include="Controls\XamlResourceExtension.cs" />
<Compile Include="EntityReference.cs" />
<Compile Include="Metadata\CorTables\FieldRVATableTreeNode.cs">
<SubType>Code</SubType>
<Generator>MSBuild:Compile</Generator>
@ -237,8 +238,6 @@ @@ -237,8 +238,6 @@
<Compile Include="DecompilationOptions.cs" />
<Compile Include="ExtensionMethods.cs" />
<Compile Include="FilterSettings.cs" />
<Compile Include="Fusion.cs" />
<Compile Include="GacInterop.cs" />
<Compile Include="GuessFileType.cs" />
<Compile Include="ContextMenuEntry.cs" />
<Compile Include="Languages\CSharpBracketSearcher.cs" />

19
ILSpy/Languages/CSharpLexer.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;

26
ILSpy/LoadedAssembly.cs

@ -65,7 +65,7 @@ namespace ICSharpCode.ILSpy @@ -65,7 +65,7 @@ namespace ICSharpCode.ILSpy
public async Task<string> GetTargetFrameworkIdAsync()
{
var assembly = await GetPEFileAsync().ConfigureAwait(false);
return assembly.Reader.DetectTargetFrameworkId() ?? string.Empty;
return assembly.DetectTargetFrameworkId() ?? string.Empty;
}
public ReferenceLoadInfo LoadedAssemblyReferencesInfo { get; } = new ReferenceLoadInfo();
@ -140,11 +140,15 @@ namespace ICSharpCode.ILSpy @@ -140,11 +140,15 @@ namespace ICSharpCode.ILSpy
public string Text {
get {
if (IsLoaded && !HasLoadError) {
var metadata = GetPEFileOrNull()?.Metadata;
PEFile module = GetPEFileOrNull();
var metadata = module?.Metadata;
string versionOrInfo = null;
if (metadata != null) {
if (metadata.IsAssembly) {
versionOrInfo = metadata.GetAssemblyDefinition().Version?.ToString();
var tfId = GetTargetFrameworkIdAsync().Result;
if (!string.IsNullOrEmpty(tfId))
versionOrInfo += ", " + tfId.Replace("Version=", " ");
} else {
versionOrInfo = ".netmodule";
}
@ -277,14 +281,15 @@ namespace ICSharpCode.ILSpy @@ -277,14 +281,15 @@ namespace ICSharpCode.ILSpy
return debugInfoProvider;
}
public LoadedAssembly LookupReferencedAssembly(Decompiler.Metadata.IAssemblyReference reference)
public LoadedAssembly LookupReferencedAssembly(IAssemblyReference reference)
{
if (reference == null)
throw new ArgumentNullException(nameof(reference));
var tfm = GetTargetFrameworkIdAsync().Result;
if (reference.IsWindowsRuntime) {
return assemblyList.assemblyLookupCache.GetOrAdd((reference.Name, true), key => LookupReferencedAssemblyInternal(reference, true));
return assemblyList.assemblyLookupCache.GetOrAdd((reference.Name, true, tfm), key => LookupReferencedAssemblyInternal(reference, true, tfm));
} else {
return assemblyList.assemblyLookupCache.GetOrAdd((reference.FullName, false), key => LookupReferencedAssemblyInternal(reference, false));
return assemblyList.assemblyLookupCache.GetOrAdd((reference.FullName, false, tfm), key => LookupReferencedAssemblyInternal(reference, false, tfm));
}
}
@ -308,19 +313,20 @@ namespace ICSharpCode.ILSpy @@ -308,19 +313,20 @@ namespace ICSharpCode.ILSpy
static readonly Dictionary<string, LoadedAssembly> loadingAssemblies = new Dictionary<string, LoadedAssembly>();
MyUniversalResolver universalResolver;
LoadedAssembly LookupReferencedAssemblyInternal(Decompiler.Metadata.IAssemblyReference fullName, bool isWinRT)
LoadedAssembly LookupReferencedAssemblyInternal(IAssemblyReference fullName, bool isWinRT, string tfm)
{
string GetName(Decompiler.Metadata.IAssemblyReference name) => isWinRT ? name.Name : name.FullName;
string key = tfm + ";" + (isWinRT ? fullName.Name : fullName.FullName);
string file;
LoadedAssembly asm;
lock (loadingAssemblies) {
foreach (LoadedAssembly loaded in assemblyList.GetAssemblies()) {
var reader = loaded.GetPEFileOrNull()?.Metadata;
var module = loaded.GetPEFileOrNull();
var reader = module?.Metadata;
if (reader == null || !reader.IsAssembly) continue;
var asmDef = reader.GetAssemblyDefinition();
var asmDefName = isWinRT ? reader.GetString(asmDef.Name) : reader.GetFullAssemblyName();
if (GetName(fullName).Equals(asmDefName, StringComparison.OrdinalIgnoreCase)) {
var asmDefName = loaded.GetTargetFrameworkIdAsync().Result + ";" + (isWinRT ? reader.GetString(asmDef.Name) : reader.GetFullAssemblyName());
if (key.Equals(asmDefName, StringComparison.OrdinalIgnoreCase)) {
LoadedAssemblyReferencesInfo.AddMessageOnce(fullName.FullName, MessageKind.Info, "Success - Found in Assembly List");
return loaded;
}

14
ILSpy/MainWindow.xaml.cs

@ -118,6 +118,8 @@ namespace ICSharpCode.ILSpy @@ -118,6 +118,8 @@ namespace ICSharpCode.ILSpy
AssemblyListManager = AssemblyListManager
};
AssemblyListManager.CreateDefaultAssemblyLists();
DockWorkspace.Instance.LoadSettings(sessionSettings);
InitializeComponent();
InitToolPanes();
@ -883,22 +885,22 @@ namespace ICSharpCode.ILSpy @@ -883,22 +885,22 @@ namespace ICSharpCode.ILSpy
case Decompiler.Disassembler.OpCodeInfo opCode:
OpenLink(opCode.Link);
break;
case ValueTuple<string, PEFile, Handle> unresolvedEntity:
string protocol = unresolvedEntity.Item1 ?? "decompile";
PEFile file = unresolvedEntity.Item2;
case EntityReference unresolvedEntity:
string protocol = unresolvedEntity.Protocol ?? "decompile";
PEFile file = unresolvedEntity.Module;
if (protocol != "decompile") {
var protocolHandlers = App.ExportProvider.GetExports<IProtocolHandler>();
foreach (var handler in protocolHandlers) {
var node = handler.Value.Resolve(protocol, file, unresolvedEntity.Item3, out bool newTabPage);
var node = handler.Value.Resolve(protocol, file, unresolvedEntity.Handle, out bool newTabPage);
if (node != null) {
SelectNode(node, newTabPage);
return decompilationTask;
}
}
}
if (MetadataTokenHelpers.TryAsEntityHandle(MetadataTokens.GetToken(unresolvedEntity.Item3)) != null) {
if (MetadataTokenHelpers.TryAsEntityHandle(MetadataTokens.GetToken(unresolvedEntity.Handle)) != null) {
var typeSystem = new DecompilerTypeSystem(file, file.GetAssemblyResolver(), TypeSystemOptions.Default | TypeSystemOptions.Uncached);
reference = typeSystem.MainModule.ResolveEntity((EntityHandle)unresolvedEntity.Item3);
reference = typeSystem.MainModule.ResolveEntity((EntityHandle)unresolvedEntity.Handle);
goto default;
}
break;

54
ILSpy/Properties/Resources.Designer.cs generated

@ -285,6 +285,15 @@ namespace ICSharpCode.ILSpy.Properties { @@ -285,6 +285,15 @@ namespace ICSharpCode.ILSpy.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Add preconfigured list....
/// </summary>
public static string AddPreconfiguredList {
get {
return ResourceManager.GetString("AddPreconfiguredList", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Add shell integration.
/// </summary>
@ -504,6 +513,15 @@ namespace ICSharpCode.ILSpy.Properties { @@ -504,6 +513,15 @@ namespace ICSharpCode.ILSpy.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Culture.
/// </summary>
public static string CultureLabel {
get {
return ResourceManager.GetString("CultureLabel", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to DEBUG -- Decompile All.
/// </summary>
@ -1397,15 +1415,6 @@ namespace ICSharpCode.ILSpy.Properties { @@ -1397,15 +1415,6 @@ namespace ICSharpCode.ILSpy.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to New list.
/// </summary>
public static string List {
get {
return ResourceManager.GetString("List", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Are you sure that you want to delete the selected assembly list?.
/// </summary>
@ -1515,6 +1524,15 @@ namespace ICSharpCode.ILSpy.Properties { @@ -1515,6 +1524,15 @@ namespace ICSharpCode.ILSpy.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to New list.
/// </summary>
public static string NewList {
get {
return ResourceManager.GetString("NewList", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Nuget Package Browser.
/// </summary>
@ -1641,6 +1659,15 @@ namespace ICSharpCode.ILSpy.Properties { @@ -1641,6 +1659,15 @@ namespace ICSharpCode.ILSpy.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to R_ename.
/// </summary>
public static string R_ename {
get {
return ResourceManager.GetString("R_ename", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Reference Name.
/// </summary>
@ -1715,6 +1742,15 @@ namespace ICSharpCode.ILSpy.Properties { @@ -1715,6 +1742,15 @@ namespace ICSharpCode.ILSpy.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Rename list.
/// </summary>
public static string RenameList {
get {
return ResourceManager.GetString("RenameList", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Reset to defaults.
/// </summary>

14
ILSpy/Properties/Resources.resx

@ -426,7 +426,7 @@ @@ -426,7 +426,7 @@
<data name="Create" xml:space="preserve">
<value>Create</value>
</data>
<data name="List" xml:space="preserve">
<data name="NewList" xml:space="preserve">
<value>New list</value>
</data>
<data name="SelectAssembliesOpen" xml:space="preserve">
@ -855,4 +855,16 @@ Do you want to continue?</value> @@ -855,4 +855,16 @@ Do you want to continue?</value>
<data name="DecompilerSettings.Ranges" xml:space="preserve">
<value>Ranges</value>
</data>
<data name="AddPreconfiguredList" xml:space="preserve">
<value>Add preconfigured list...</value>
</data>
<data name="R_ename" xml:space="preserve">
<value>R_ename</value>
</data>
<data name="RenameList" xml:space="preserve">
<value>Rename list</value>
</data>
<data name="CultureLabel" xml:space="preserve">
<value>Culture</value>
</data>
</root>

2
ILSpy/TextView/AvalonEditTextOutput.cs

@ -245,7 +245,7 @@ namespace ICSharpCode.ILSpy.TextView @@ -245,7 +245,7 @@ namespace ICSharpCode.ILSpy.TextView
if (isDefinition) {
this.DefinitionLookup.AddDefinition((module, handle), this.TextLength);
}
references.Add(new ReferenceSegment { StartOffset = start, EndOffset = end, Reference = (protocol, module, handle), IsDefinition = isDefinition });
references.Add(new ReferenceSegment { StartOffset = start, EndOffset = end, Reference = new EntityReference(protocol, module, handle), IsDefinition = isDefinition });
}
public void WriteReference(IType type, string text, bool isDefinition = false)

19
ILSpy/TextView/BracketHighlightRenderer.cs

@ -1,5 +1,20 @@ @@ -1,5 +1,20 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Windows.Media;

7
ILSpy/TextView/DecompilerTextView.cs

@ -23,6 +23,7 @@ using System.ComponentModel.Composition; @@ -23,6 +23,7 @@ using System.ComponentModel.Composition;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection.Metadata;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
@ -362,10 +363,10 @@ namespace ICSharpCode.ILSpy.TextView @@ -362,10 +363,10 @@ namespace ICSharpCode.ILSpy.TextView
if (document == null)
return null;
return new FlowDocumentTooltip(document);
} else if (segment.Reference is ValueTuple<PEFile, System.Reflection.Metadata.EntityHandle> unresolvedEntity) {
var typeSystem = new DecompilerTypeSystem(unresolvedEntity.Item1, unresolvedEntity.Item1.GetAssemblyResolver(), TypeSystemOptions.Default | TypeSystemOptions.Uncached);
} else if (segment.Reference is EntityReference unresolvedEntity) {
var typeSystem = new DecompilerTypeSystem(unresolvedEntity.Module, unresolvedEntity.Module.GetAssemblyResolver(), TypeSystemOptions.Default | TypeSystemOptions.Uncached);
try {
IEntity resolved = typeSystem.MainModule.ResolveEntity(unresolvedEntity.Item2);
IEntity resolved = typeSystem.MainModule.ResolveEntity((EntityHandle)unresolvedEntity.Handle);
if (resolved == null)
return null;
var document = CreateTooltipForEntity(resolved);

2
ILSpy/ViewModels/DebugStepsPaneModel.cs

@ -20,7 +20,9 @@ using System.Windows; @@ -20,7 +20,9 @@ using System.Windows;
namespace ICSharpCode.ILSpy.ViewModels
{
#if DEBUG
[ExportToolPane(ContentId = PaneContentId)]
#endif
public class DebugStepsPaneModel : ToolPaneModel
{
public const string PaneContentId = "debugStepsPane";

331
ILSpy/ViewModels/ManageAssemblyListsViewModel.cs

@ -16,11 +16,16 @@ @@ -16,11 +16,16 @@
// 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.Collections.ObjectModel;
using System.IO;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Input;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.ILSpy.Commands;
using ICSharpCode.ILSpy.Properties;
namespace ICSharpCode.ILSpy.ViewModels
{
@ -31,20 +36,67 @@ namespace ICSharpCode.ILSpy.ViewModels @@ -31,20 +36,67 @@ namespace ICSharpCode.ILSpy.ViewModels
public const string ASPDotNetMVC3List = "ASP.NET (MVC3)";
private readonly AssemblyListManager manager;
private readonly Window parent;
public ManageAssemblyListsViewModel()
public ManageAssemblyListsViewModel(Window parent)
{
this.manager = MainWindow.Instance.AssemblyListManager;
CreateDefaultAssemblyLists();
this.parent = parent;
NewCommand = new DelegateCommand<ManageAssemblyListsDialog>(ExecuteNew);
CloneCommand = new DelegateCommand<ManageAssemblyListsDialog>(ExecuteClone, CanExecuteClone);
ResetCommand = new DelegateCommand<ManageAssemblyListsDialog>(ExecuteReset);
DeleteCommand = new DelegateCommand<ManageAssemblyListsDialog>(ExecuteDelete, CanExecuteDelete);
NewCommand = new DelegateCommand(ExecuteNew);
CloneCommand = new DelegateCommand(ExecuteClone, CanExecuteClone);
RenameCommand = new DelegateCommand(ExecuteRename, CanExecuteRename);
ResetCommand = new DelegateCommand(ExecuteReset);
DeleteCommand = new DelegateCommand(ExecuteDelete, CanExecuteDelete);
CreatePreconfiguredAssemblyListCommand = new DelegateCommand<PreconfiguredAssemblyList>(ExecuteCreatePreconfiguredAssemblyList);
PreconfiguredAssemblyLists = new List<PreconfiguredAssemblyList>(ResolvePreconfiguredAssemblyLists());
}
IEnumerable<PreconfiguredAssemblyList> ResolvePreconfiguredAssemblyLists()
{
yield return new PreconfiguredAssemblyList(DotNet4List);
yield return new PreconfiguredAssemblyList(DotNet35List);
yield return new PreconfiguredAssemblyList(ASPDotNetMVC3List);
var basePath = DotNetCorePathFinder.FindDotNetExeDirectory();
if (basePath == null)
yield break;
Dictionary<string, string> foundVersions = new Dictionary<string, string>();
Dictionary<string, int> latestRevision = new Dictionary<string, int>();
foreach (var sdkDir in Directory.GetDirectories(Path.Combine(basePath, "shared"))) {
if (sdkDir.EndsWith(".Ref", StringComparison.OrdinalIgnoreCase))
continue;
foreach (var versionDir in Directory.GetDirectories(sdkDir)) {
var match = Regex.Match(versionDir, @"[/\\](?<name>[A-z0-9.]+)[/\\](?<version>\d+\.\d)+(.(?<revision>\d+))?$");
if (!match.Success)
continue;
string name = match.Groups["name"].Value;
int index = name.LastIndexOfAny(new[] { '/', '\\' });
if (index >= 0)
name = name.Substring(index + 1);
string text = name + " " + match.Groups["version"].Value;
if (!latestRevision.TryGetValue(text, out int revision))
revision = -1;
int newRevision = int.Parse(match.Groups["revision"].Value);
if (newRevision > revision) {
latestRevision[text] = newRevision;
foundVersions[text] = versionDir;
}
}
}
foreach (var pair in foundVersions) {
yield return new PreconfiguredAssemblyList(pair.Key + "(." + latestRevision[pair.Key] + ")", pair.Value);
}
}
public ObservableCollection<string> AssemblyLists => manager.AssemblyLists;
public List<PreconfiguredAssemblyList> PreconfiguredAssemblyLists { get; }
private string selectedAssemblyList;
public string SelectedAssemblyList {
@ -60,149 +112,228 @@ namespace ICSharpCode.ILSpy.ViewModels @@ -60,149 +112,228 @@ namespace ICSharpCode.ILSpy.ViewModels
public ICommand NewCommand { get; }
public ICommand CloneCommand { get; }
public ICommand ResetCommand { get; }
public ICommand RenameCommand { get; }
public ICommand DeleteCommand { get; }
public ICommand CreatePreconfiguredAssemblyListCommand { get; }
private void ExecuteNew(ManageAssemblyListsDialog dialog)
private void ExecuteNew()
{
CreateListDialog dlg = new CreateListDialog();
dlg.Owner = dialog;
CreateListDialog dlg = new CreateListDialog(Resources.NewList);
dlg.Owner = parent;
dlg.Closing += (s, args) => {
if (dlg.DialogResult == true) {
if (manager.AssemblyLists.Contains(dlg.NewListName)) {
if (manager.AssemblyLists.Contains(dlg.ListName)) {
args.Cancel = true;
MessageBox.Show(Properties.Resources.ListExistsAlready, null, MessageBoxButton.OK);
}
}
};
if (dlg.ShowDialog() == true) {
manager.CreateList(new AssemblyList(dlg.NewListName));
manager.CreateList(new AssemblyList(dlg.ListName));
}
}
private bool CanExecuteClone(ManageAssemblyListsDialog _)
private bool CanExecuteClone()
{
return selectedAssemblyList != null;
}
private void ExecuteClone(ManageAssemblyListsDialog dialog)
private void ExecuteClone()
{
CreateListDialog dlg = new CreateListDialog();
dlg.Owner = dialog;
CreateListDialog dlg = new CreateListDialog(Resources.NewList);
dlg.Owner = parent;
dlg.Closing += (s, args) => {
if (dlg.DialogResult == true) {
if (manager.AssemblyLists.Contains(dlg.NewListName)) {
if (manager.AssemblyLists.Contains(dlg.ListName)) {
args.Cancel = true;
MessageBox.Show(Properties.Resources.ListExistsAlready, null, MessageBoxButton.OK);
}
}
};
if (dlg.ShowDialog() == true) {
manager.CloneList(SelectedAssemblyList, dlg.NewListName);
manager.CloneList(SelectedAssemblyList, dlg.ListName);
}
}
private void ExecuteReset(ManageAssemblyListsDialog dialog)
private void ExecuteReset()
{
if (MessageBox.Show(dialog, Properties.Resources.ListsResetConfirmation,
if (MessageBox.Show(parent, Properties.Resources.ListsResetConfirmation,
"ILSpy", MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No, MessageBoxOptions.None) != MessageBoxResult.Yes)
return;
manager.ClearAll();
CreateDefaultAssemblyLists();
manager.CreateDefaultAssemblyLists();
MainWindow.Instance.SessionSettings.ActiveAssemblyList = manager.AssemblyLists[0];
}
private void ExecuteDelete(ManageAssemblyListsDialog dialog)
private void ExecuteDelete()
{
if (MessageBox.Show(dialog, Properties.Resources.ListDeleteConfirmation,
if (MessageBox.Show(parent, Properties.Resources.ListDeleteConfirmation,
"ILSpy", MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No, MessageBoxOptions.None) != MessageBoxResult.Yes)
return;
manager.DeleteList(SelectedAssemblyList);
}
private bool CanExecuteDelete(ManageAssemblyListsDialog _)
private bool CanExecuteDelete()
{
return selectedAssemblyList != null;
}
private bool CanExecuteRename()
{
return selectedAssemblyList != null;
}
private void CreateDefaultAssemblyLists()
{
if (!manager.AssemblyLists.Contains(DotNet4List)) {
AssemblyList dotnet4 = new AssemblyList(DotNet4List);
AddToList(dotnet4, "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToList(dotnet4, "System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToList(dotnet4, "System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToList(dotnet4, "System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToList(dotnet4, "System.Data.DataSetExtensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToList(dotnet4, "System.Xaml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToList(dotnet4, "System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToList(dotnet4, "System.Xml.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToList(dotnet4, "Microsoft.CSharp, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
AddToList(dotnet4, "PresentationCore, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
AddToList(dotnet4, "PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
AddToList(dotnet4, "WindowsBase, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
if (dotnet4.assemblies.Count > 0) {
manager.CreateList(dotnet4);
}
}
if (!manager.AssemblyLists.Contains(DotNet35List)) {
AssemblyList dotnet35 = new AssemblyList(DotNet35List);
AddToList(dotnet35, "mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToList(dotnet35, "System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToList(dotnet35, "System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToList(dotnet35, "System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToList(dotnet35, "System.Data.DataSetExtensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToList(dotnet35, "System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToList(dotnet35, "System.Xml.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToList(dotnet35, "PresentationCore, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
AddToList(dotnet35, "PresentationFramework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
AddToList(dotnet35, "WindowsBase, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
if (dotnet35.assemblies.Count > 0) {
manager.CreateList(dotnet35);
}
}
if (!manager.AssemblyLists.Contains(ASPDotNetMVC3List)) {
AssemblyList mvc = new AssemblyList(ASPDotNetMVC3List);
AddToList(mvc, "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToList(mvc, "System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToList(mvc, "System.ComponentModel.DataAnnotations, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
AddToList(mvc, "System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
AddToList(mvc, "System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToList(mvc, "System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToList(mvc, "System.Data.DataSetExtensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToList(mvc, "System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToList(mvc, "System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
AddToList(mvc, "System.EnterpriseServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
AddToList(mvc, "System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
AddToList(mvc, "System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
AddToList(mvc, "System.Web.ApplicationServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
AddToList(mvc, "System.Web.DynamicData, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
AddToList(mvc, "System.Web.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToList(mvc, "System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
AddToList(mvc, "System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
AddToList(mvc, "System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
AddToList(mvc, "System.Web.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
AddToList(mvc, "System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
AddToList(mvc, "System.Web.Helpers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
AddToList(mvc, "System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToList(mvc, "System.Xml.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToList(mvc, "Microsoft.CSharp, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
if (mvc.assemblies.Count > 0) {
manager.CreateList(mvc);
}
}
}
private void AddToList(AssemblyList list, string FullName)
{
AssemblyNameReference reference = AssemblyNameReference.Parse(FullName);
string file = GacInterop.FindAssemblyInNetGac(reference);
private void ExecuteRename()
{
CreateListDialog dlg = new CreateListDialog(Resources.RenameList);
dlg.Owner = parent;
dlg.ListName = selectedAssemblyList;
dlg.ListNameBox.SelectAll();
dlg.Closing += (s, args) => {
if (dlg.DialogResult == true) {
if (dlg.ListName == selectedAssemblyList) {
args.Cancel = true;
return;
}
if (manager.AssemblyLists.Contains(dlg.ListName)) {
args.Cancel = true;
MessageBox.Show(Properties.Resources.ListExistsAlready, null, MessageBoxButton.OK);
}
}
};
if (dlg.ShowDialog() == true) {
manager.RenameList(selectedAssemblyList, dlg.ListName);
}
}
internal static AssemblyList CreateDefaultList(string name, string path = null, string newName = null)
{
var list = new AssemblyList(newName ?? name);
switch (name) {
case DotNet4List:
AddToListFromGAC("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToListFromGAC("System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToListFromGAC("System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToListFromGAC("System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToListFromGAC("System.Data.DataSetExtensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToListFromGAC("System.Xaml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToListFromGAC("System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToListFromGAC("System.Xml.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToListFromGAC("Microsoft.CSharp, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
AddToListFromGAC("PresentationCore, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
AddToListFromGAC("PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
AddToListFromGAC("WindowsBase, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
break;
case DotNet35List:
AddToListFromGAC("mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToListFromGAC("System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToListFromGAC("System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToListFromGAC("System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToListFromGAC("System.Data.DataSetExtensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToListFromGAC("System.Xml, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToListFromGAC("System.Xml.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToListFromGAC("PresentationCore, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
AddToListFromGAC("PresentationFramework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
AddToListFromGAC("WindowsBase, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
break;
case ASPDotNetMVC3List:
AddToListFromGAC("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToListFromGAC("System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToListFromGAC("System.ComponentModel.DataAnnotations, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
AddToListFromGAC("System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
AddToListFromGAC("System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToListFromGAC("System.Data, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToListFromGAC("System.Data.DataSetExtensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToListFromGAC("System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToListFromGAC("System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
AddToListFromGAC("System.EnterpriseServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
AddToListFromGAC("System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
AddToListFromGAC("System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
AddToListFromGAC("System.Web.ApplicationServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
AddToListFromGAC("System.Web.DynamicData, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
AddToListFromGAC("System.Web.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToListFromGAC("System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
AddToListFromGAC("System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
AddToListFromGAC("System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
AddToListFromGAC("System.Web.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
AddToListFromGAC("System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
AddToListFromGAC("System.Web.Helpers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
AddToListFromGAC("System.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToListFromGAC("System.Xml.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
AddToListFromGAC("Microsoft.CSharp, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a");
break;
case object _ when path != null:
foreach (var file in Directory.GetFiles(path, "*.dll")) {
var dllname = Path.GetFileName(file);
if (DoIncludeFile(dllname))
AddToListFromDirectory(file);
}
break;
}
return list;
void AddToListFromGAC(string fullName)
{
AssemblyNameReference reference = AssemblyNameReference.Parse(fullName);
string file = UniversalAssemblyResolver.GetAssemblyInGac(reference);
if (file != null)
list.OpenAssembly(file);
}
void AddToListFromDirectory(string file)
{
if (File.Exists(file))
list.OpenAssembly(file);
}
bool DoIncludeFile(string fileName)
{
if (fileName == "Microsoft.DiaSymReader.Native.amd64.dll")
return false;
if (fileName.EndsWith("_cor3.dll", StringComparison.OrdinalIgnoreCase))
return false;
if (char.IsUpper(fileName[0]))
return true;
if (fileName == "netstandard.dll")
return true;
if (fileName == "mscorlib.dll")
return true;
return false;
}
}
private void ExecuteCreatePreconfiguredAssemblyList(PreconfiguredAssemblyList config)
{
CreateListDialog dlg = new CreateListDialog(Resources.AddPreconfiguredList);
dlg.Owner = parent;
dlg.ListName = config.Name;
dlg.ListNameBox.SelectAll();
dlg.Closing += (s, args) => {
if (dlg.DialogResult == true) {
if (manager.AssemblyLists.Contains(dlg.ListName)) {
args.Cancel = true;
MessageBox.Show(Properties.Resources.ListExistsAlready, null, MessageBoxButton.OK);
}
}
};
if (dlg.ShowDialog() == true) {
var list = CreateDefaultList(config.Name, config.Path, dlg.ListName);
if (list.assemblies.Count > 0) {
manager.CreateList(list);
}
}
}
}
public class PreconfiguredAssemblyList
{
public string Name { get; }
public string Path { get; }
public PreconfiguredAssemblyList(string name, string path = null)
{
this.Name = name;
this.Path = path;
}
}
}

6
ILSpy/Views/CreateListDialog.xaml

@ -2,14 +2,12 @@ @@ -2,14 +2,12 @@
x:Class="ICSharpCode.ILSpy.CreateListDialog" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:properties="clr-namespace:ICSharpCode.ILSpy.Properties"
xmlns:controls="clr-namespace:ICSharpCode.ILSpy.Controls"
Title="{x:Static properties:Resources.List}"
Style="{DynamicResource DialogWindow}"
WindowStartupLocation="CenterOwner"
ResizeMode="NoResize"
Width="300"
Height="150"
FocusManager.FocusedElement="{Binding ElementName=ListName}">
FocusManager.FocusedElement="{Binding ElementName=ListNameBox}">
<Grid Margin="12,8">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
@ -17,7 +15,7 @@ @@ -17,7 +15,7 @@
</Grid.RowDefinitions>
<StackPanel>
<Label Content="{x:Static properties:Resources.EnterListName}"/>
<TextBox Margin="8,8" Name="ListName" TextChanged="TextBox_TextChanged"></TextBox>
<TextBox Margin="8,8" Name="ListNameBox" TextChanged="TextBox_TextChanged"></TextBox>
</StackPanel>
<StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Right" Margin="8,0">
<Button IsDefault="True" Margin="2,0" IsEnabled="False" Name="okButton" Click="OKButton_Click" Content="{x:Static properties:Resources.Create}"/>

16
ILSpy/Views/CreateListDialog.xaml.cs

@ -8,31 +8,29 @@ namespace ICSharpCode.ILSpy @@ -8,31 +8,29 @@ namespace ICSharpCode.ILSpy
/// </summary>
public partial class CreateListDialog : Window
{
public CreateListDialog()
public CreateListDialog(string title)
{
InitializeComponent();
this.Title = title;
}
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
okButton.IsEnabled = !string.IsNullOrWhiteSpace(ListName.Text);
okButton.IsEnabled = !string.IsNullOrWhiteSpace(ListNameBox.Text);
}
private void OKButton_Click(object sender, RoutedEventArgs e)
{
if (!string.IsNullOrWhiteSpace(ListName.Text))
if (!string.IsNullOrWhiteSpace(ListNameBox.Text))
{
this.DialogResult = true;
}
}
public string NewListName
public string ListName
{
get
{
return ListName.Text;
}
get => ListNameBox.Text;
set => ListNameBox.Text = value;
}
}
}

12
ILSpy/Views/ManageAssemblyLIstsDialog.xaml.cs

@ -17,6 +17,8 @@ @@ -17,6 +17,8 @@
// DEALINGS IN THE SOFTWARE.
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using ICSharpCode.ILSpy.ViewModels;
namespace ICSharpCode.ILSpy
@ -29,7 +31,15 @@ namespace ICSharpCode.ILSpy @@ -29,7 +31,15 @@ namespace ICSharpCode.ILSpy
public ManageAssemblyListsDialog()
{
InitializeComponent();
DataContext = new ManageAssemblyListsViewModel();
DataContext = new ManageAssemblyListsViewModel(this);
}
private void PreconfiguredAssemblyListsMenuClick(object sender, RoutedEventArgs e)
{
var menu = (ContextMenu)Resources["PreconfiguredAssemblyListsMenu"];
menu.PlacementTarget = (Button)sender;
menu.Placement = PlacementMode.Bottom;
menu.IsOpen = true;
}
}
}

12
ILSpy/Views/ManageAssemblyListsDialog.xaml

@ -12,6 +12,16 @@ @@ -12,6 +12,16 @@
Height="350"
Width="480"
FocusManager.FocusedElement="{Binding ElementName=listView}">
<Window.Resources>
<ContextMenu x:Key="PreconfiguredAssemblyListsMenu" ItemsSource="{Binding PreconfiguredAssemblyLists}" DisplayMemberPath="Name">
<ContextMenu.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="Command" Value="{Binding DataContext.CreatePreconfiguredAssemblyListCommand, RelativeSource={RelativeSource AncestorType=Window}}" />
<Setter Property="CommandParameter" Value="{Binding}" />
</Style>
</ContextMenu.ItemContainerStyle>
</ContextMenu>
</Window.Resources>
<Grid Margin="12,8">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
@ -30,10 +40,12 @@ @@ -30,10 +40,12 @@
<StackPanel Grid.Column="5" Grid.RowSpan="2" Margin="4, 8">
<Button Margin="2 2 2 10" Command="{Binding NewCommand}" CommandParameter="{Binding ., RelativeSource={RelativeSource AncestorType=Window}}" Content="{x:Static properties:Resources._New}"/>
<Button Margin="2" Command="{Binding CloneCommand}" CommandParameter="{Binding ., RelativeSource={RelativeSource AncestorType=Window}}" Content="{x:Static properties:Resources.C_lone}"/>
<Button Margin="2" Command="{Binding RenameCommand}" CommandParameter="{Binding ., RelativeSource={RelativeSource AncestorType=Window}}" Content="{x:Static properties:Resources.R_ename}"/>
<Button Margin="2" Command="{Binding DeleteCommand}" CommandParameter="{Binding ., RelativeSource={RelativeSource AncestorType=Window}}" Content="{x:Static properties:Resources.OpenListDialog__Delete}"/>
<Button Margin="2 10 2 2" Command="{Binding ResetCommand}" CommandParameter="{Binding ., RelativeSource={RelativeSource AncestorType=Window}}" Content="{x:Static properties:Resources._Reset}"/>
</StackPanel>
<Button IsCancel="True" Grid.Row="2" Margin="2,0" Content="{x:Static properties:Resources.Close}" />
<Button Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2" Margin="2,0" Content="{x:Static properties:Resources.AddPreconfiguredList}" Click="PreconfiguredAssemblyListsMenuClick" />
</Grid>
</Window>

2
ILSpy/Views/OpenFromGacDialog.xaml

@ -33,7 +33,7 @@ @@ -33,7 +33,7 @@
<GridView>
<controls:SortableGridViewColumn x:Name="nameColumn" Width="300" Header="{x:Static properties:Resources.ReferenceName}" DisplayMemberBinding="{Binding ShortName}" />
<controls:SortableGridViewColumn Width="75" Header="{x:Static properties:Resources.Version}" DisplayMemberBinding="{Binding Version}" />
<controls:SortableGridViewColumn Width="65" Header="{x:Static properties:Resources.Culture}" DisplayMemberBinding="{Binding Culture}" />
<controls:SortableGridViewColumn Width="65" Header="{x:Static properties:Resources.CultureLabel}" DisplayMemberBinding="{Binding Culture}" />
<controls:SortableGridViewColumn Width="115" Header="{x:Static properties:Resources.PublicToken}" DisplayMemberBinding="{Binding PublicKeyToken}" />
<controls:SortableGridViewColumn Width="1000" Header="{x:Static properties:Resources.Location}" DisplayMemberBinding="{Binding FileName}" />
</GridView>

16
ILSpy/Views/OpenFromGacDialog.xaml.cs

@ -95,7 +95,11 @@ namespace ICSharpCode.ILSpy @@ -95,7 +95,11 @@ namespace ICSharpCode.ILSpy
}
public string Culture {
get { return r.Culture; }
get {
if (string.IsNullOrEmpty(r.Culture))
return "neutral";
return r.Culture;
}
}
public string PublicKeyToken {
@ -116,21 +120,21 @@ namespace ICSharpCode.ILSpy @@ -116,21 +120,21 @@ namespace ICSharpCode.ILSpy
void FetchGacContents()
{
HashSet<string> fullNames = new HashSet<string>();
UpdateProgressBar(pg => { pg.Visibility = System.Windows.Visibility.Visible; pg.IsIndeterminate = true; });
var list = GacInterop.GetGacAssemblyFullNames().TakeWhile(_ => !cancelFetchThread).ToList();
UpdateProgressBar(pg => { pg.Visibility = Visibility.Visible; pg.IsIndeterminate = true; });
var list = UniversalAssemblyResolver.EnumerateGac().TakeWhile(_ => !cancelFetchThread).ToList();
UpdateProgressBar(pg => { pg.IsIndeterminate = false; pg.Maximum = list.Count; });
foreach (var r in list) {
if (cancelFetchThread)
break;
if (fullNames.Add(r.FullName)) { // filter duplicates
var file = GacInterop.FindAssemblyInNetGac(r);
var file = UniversalAssemblyResolver.GetAssemblyInGac(r);
if (file != null) {
var entry = new GacEntry(r, file);
UpdateProgressBar(pg => { pg.Value = pg.Value + 1; AddNewEntry(entry); });
UpdateProgressBar(pg => { pg.Value++; AddNewEntry(entry); });
}
}
}
UpdateProgressBar(pg => { pg.Visibility = System.Windows.Visibility.Hidden; });
UpdateProgressBar(pg => { pg.Visibility = Visibility.Hidden; });
}
void UpdateProgressBar(Action<ProgressBar> updateAction)

Loading…
Cancel
Save