Browse Source

Merge branch 'master' of git://github.com/icsharpcode/ILSpy into Debugger

pull/191/merge
Eusebiu Marcu 15 years ago
parent
commit
48cb099229
  1. 22
      ICSharpCode.Decompiler/Ast/NameVariables.cs
  2. 153
      ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs
  3. 15
      ICSharpCode.Decompiler/DecompilerSettings.cs
  4. 10
      ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
  5. 23
      ICSharpCode.Decompiler/Tests/Loops.cs
  6. 6
      ICSharpCode.Decompiler/Tests/Switch.cs
  7. 4
      ICSharpCode.Decompiler/Tests/TestRunner.cs
  8. 30
      ILSpy.sln
  9. 6
      ILSpy/ILSpy.csproj
  10. 5
      ILSpy/Images/Images.cs
  11. 1
      ILSpy/Images/MemberIcon.cs
  12. BIN
      ILSpy/Images/OverlayStatic.png
  13. BIN
      ILSpy/Images/PInvokeMethod.png
  14. 22
      ILSpy/LoadedAssembly.cs
  15. 32
      ILSpy/MainWindow.xaml.cs
  16. 52
      ILSpy/NavigationHistory.cs
  17. 28
      ILSpy/NavigationState.cs
  18. 1
      ILSpy/Options/DecompilerSettingsPanel.xaml
  19. 2
      ILSpy/Options/DecompilerSettingsPanel.xaml.cs
  20. 3
      ILSpy/Options/OptionsDialog.xaml.cs
  21. 5
      ILSpy/TreeNodes/MethodTreeNode.cs
  22. 2
      Mono.Cecil/symbols/pdb/Mono.Cecil.Pdb/PdbHelper.cs
  23. 4
      TestPlugin/TestPlugin.csproj

22
ICSharpCode.Decompiler/Ast/NameVariables.cs

@ -42,8 +42,23 @@ namespace ICSharpCode.Decompiler.Ast @@ -42,8 +42,23 @@ namespace ICSharpCode.Decompiler.Ast
foreach (var p in parameters)
nv.AddExistingName(p.Name);
foreach (var v in variables) {
if (v.IsGenerated)
if (v.IsGenerated) {
// don't introduce names for variables generated by ILSpy - keep "expr"/"arg"
nv.AddExistingName(v.Name);
} else if (v.OriginalVariable != null && context.Settings.UseDebugSymbols) {
string varName = v.OriginalVariable.Name;
if (string.IsNullOrEmpty(varName) || varName.StartsWith("V_", StringComparison.Ordinal) || varName.StartsWith("CS$", StringComparison.Ordinal))
{
// don't use the name from the debug symbols if it looks like a generated name
v.Name = null;
} else {
// use the name from the debug symbols
// (but ensure we don't use the same name for two variables)
v.Name = nv.GetAlternativeName(varName);
}
} else {
v.Name = null;
}
}
// Now generate names:
foreach (ILVariable p in parameters) {
@ -51,9 +66,8 @@ namespace ICSharpCode.Decompiler.Ast @@ -51,9 +66,8 @@ namespace ICSharpCode.Decompiler.Ast
p.Name = nv.GenerateNameForVariable(p, methodBody);
}
foreach (ILVariable varDef in variables) {
if (!varDef.IsGenerated) {
if (string.IsNullOrEmpty(varDef.Name))
varDef.Name = nv.GenerateNameForVariable(varDef, methodBody);
}
}
}
@ -107,7 +121,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -107,7 +121,7 @@ namespace ICSharpCode.Decompiler.Ast
string nameWithoutDigits = SplitName(oldVariableName, out number);
if (!typeNames.ContainsKey(nameWithoutDigits)) {
typeNames.Add(nameWithoutDigits, 0);
typeNames.Add(nameWithoutDigits, number - 1);
}
int count = ++typeNames[nameWithoutDigits];
if (count > 1) {

153
ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs

@ -47,6 +47,9 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -47,6 +47,9 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
result = TransformUsings(expressionStatement);
if (result != null)
return result;
result = TransformNonGenericForEach(expressionStatement);
if (result != null)
return result;
}
result = TransformFor(expressionStatement);
if (result != null)
@ -118,7 +121,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -118,7 +121,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
#endregion
/// <summary>
/// $type $variable = $initializer;
/// $variable = $initializer;
/// </summary>
static readonly AstNode variableAssignPattern = new ExpressionStatement(
new AssignmentExpression(
@ -235,8 +238,8 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -235,8 +238,8 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
}
#endregion
#region foreach
static readonly UsingStatement foreachPattern = new UsingStatement {
#region foreach (generic)
static readonly UsingStatement genericForeachPattern = new UsingStatement {
ResourceAcquisition = new VariableDeclarationStatement {
Type = new AnyNode("enumeratorType"),
Variables = {
@ -270,7 +273,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -270,7 +273,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
public ForeachStatement TransformForeach(UsingStatement node)
{
Match m = foreachPattern.Match(node);
Match m = genericForeachPattern.Match(node);
if (!m.Success)
return null;
if (!(node.Parent is BlockStatement) && m.Has("variablesOutsideLoop")) {
@ -308,8 +311,9 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -308,8 +311,9 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
InExpression = m.Get<Expression>("collection").Single().Detach(),
EmbeddedStatement = newBody
};
if (foreachStatement.InExpression is BaseReferenceExpression)
foreachStatement.InExpression = new ThisReferenceExpression();
if (foreachStatement.InExpression is BaseReferenceExpression) {
foreachStatement.InExpression = new ThisReferenceExpression().CopyAnnotationsFrom(foreachStatement.InExpression);
}
node.ReplaceWith(foreachStatement);
foreach (Statement stmt in m.Get<Statement>("variablesOutsideLoop")) {
((BlockStatement)foreachStatement.Parent).Statements.InsertAfter(null, stmt.Detach());
@ -318,6 +322,117 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -318,6 +322,117 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
}
#endregion
#region foreach (non-generic)
ExpressionStatement getEnumeratorPattern = new ExpressionStatement(
new AssignmentExpression(
new NamedNode("left", new IdentifierExpression()),
new AnyNode("collection").ToExpression().Invoke("GetEnumerator")
));
TryCatchStatement nonGenericForeachPattern = new TryCatchStatement {
TryBlock = new BlockStatement {
new WhileStatement {
Condition = new IdentifierExpression().WithName("enumerator").Invoke("MoveNext"),
EmbeddedStatement = new BlockStatement {
new AssignmentExpression(
new IdentifierExpression().WithName("itemVar"),
new Choice {
new Backreference("enumerator").ToExpression().Member("Current"),
new CastExpression {
Type = new AnyNode("castType"),
Expression = new Backreference("enumerator").ToExpression().Member("Current")
}
}
),
new Repeat(new AnyNode("stmt")).ToStatement()
}
}.WithName("loop")
},
FinallyBlock = new BlockStatement {
new AssignmentExpression(
new IdentifierExpression().WithName("disposable"),
new Backreference("enumerator").ToExpression().CastAs(new TypePattern(typeof(IDisposable)))
),
new IfElseStatement {
Condition = new BinaryOperatorExpression {
Left = new Backreference("disposable"),
Operator = BinaryOperatorType.InEquality,
Right = new NullReferenceExpression()
},
TrueStatement = new BlockStatement {
new Backreference("disposable").ToExpression().Invoke("Dispose")
}
}
}};
public ForeachStatement TransformNonGenericForEach(ExpressionStatement node)
{
Match m1 = getEnumeratorPattern.Match(node);
if (!m1.Success) return null;
AstNode tryCatch = node.NextSibling;
Match m2 = nonGenericForeachPattern.Match(tryCatch);
if (!m2.Success) return null;
IdentifierExpression enumeratorVar = m2.Get<IdentifierExpression>("enumerator").Single();
IdentifierExpression itemVar = m2.Get<IdentifierExpression>("itemVar").Single();
WhileStatement loop = m2.Get<WhileStatement>("loop").Single();
// verify that the getEnumeratorPattern assigns to the same variable as the nonGenericForeachPattern is reading from
if (!enumeratorVar.IsMatch(m1.Get("left").Single()))
return null;
VariableDeclarationStatement enumeratorVarDecl = FindVariableDeclaration(loop, enumeratorVar.Identifier);
if (enumeratorVarDecl == null || !(enumeratorVarDecl.Parent is BlockStatement))
return null;
// Find the declaration of the item variable:
// Because we look only outside the loop, we won't make the mistake of moving a captured variable across the loop boundary
VariableDeclarationStatement itemVarDecl = FindVariableDeclaration(loop, itemVar.Identifier);
if (itemVarDecl == null || !(itemVarDecl.Parent is BlockStatement))
return null;
// Now verify that we can move the variable declaration in front of the loop:
Statement declarationPoint;
CanMoveVariableDeclarationIntoStatement(itemVarDecl, loop, out declarationPoint);
// We ignore the return value because we don't care whether we can move the variable into the loop
// (that is possible only with non-captured variables).
// We just care that we can move it in front of the loop:
if (declarationPoint != loop)
return null;
ForeachStatement foreachStatement = new ForeachStatement();
foreachStatement.VariableType = itemVarDecl.Type.Clone();
foreachStatement.VariableName = itemVar.Identifier;
BlockStatement body = new BlockStatement();
foreachStatement.EmbeddedStatement = body;
((BlockStatement)node.Parent).Statements.InsertBefore(node, foreachStatement);
body.Add(node.Detach());
body.Add((Statement)tryCatch.Detach());
// Now that we moved the whole try-catch into the foreach loop; verify that we can
// move the enumerator into the foreach loop:
CanMoveVariableDeclarationIntoStatement(enumeratorVarDecl, foreachStatement, out declarationPoint);
if (declarationPoint != foreachStatement) {
// oops, the enumerator variable can't be moved into the foreach loop
// Undo our AST changes:
((BlockStatement)foreachStatement.Parent).Statements.InsertBefore(foreachStatement, node.Detach());
foreachStatement.ReplaceWith(tryCatch);
return null;
}
// Now create the correct body for the foreach statement:
foreachStatement.InExpression = m1.Get<Expression>("collection").Single().Detach();
if (foreachStatement.InExpression is BaseReferenceExpression) {
foreachStatement.InExpression = new ThisReferenceExpression().CopyAnnotationsFrom(foreachStatement.InExpression);
}
body.Statements.Clear();
body.Statements.AddRange(m2.Get<Statement>("stmt").Select(stmt => stmt.Detach()));
return foreachStatement;
}
#endregion
#region for
static readonly WhileStatement forPattern = new WhileStatement {
Condition = new BinaryOperatorExpression {
@ -515,8 +630,6 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -515,8 +630,6 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
Match m = switchOnStringPattern.Match(node);
if (!m.Success)
return null;
if (m.Has("nonNullDefaultStmt") && !m.Has("nullStmt"))
return null;
// switchVar must be the same as switchExpr; or switchExpr must be an assignment and switchVar the left side of that assignment
if (!m.Get("switchVar").Single().IsMatch(m.Get("switchExpr").Single())) {
AssignmentExpression assign = m.Get("switchExpr").Single() as AssignmentExpression;
@ -551,15 +664,21 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -551,15 +664,21 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
block.Statements.Add(new BreakStatement());
section.Statements.Add(block.Detach());
sw.SwitchSections.Add(section);
if (m.Has("nonNullDefaultStmt")) {
section = new SwitchSection();
section.CaseLabels.Add(new CaseLabel());
block = new BlockStatement();
block.Statements.AddRange(m.Get<Statement>("nonNullDefaultStmt").Select(s => s.Detach()));
block.Add(new BreakStatement());
section.Statements.Add(block);
sw.SwitchSections.Add(section);
}
} else if (m.Has("nonNullDefaultStmt")) {
sw.SwitchSections.Add(
new SwitchSection {
CaseLabels = { new CaseLabel { Expression = new NullReferenceExpression() } },
Statements = { new BlockStatement { new BreakStatement() } }
});
}
if (m.Has("nonNullDefaultStmt")) {
SwitchSection section = new SwitchSection();
section.CaseLabels.Add(new CaseLabel());
BlockStatement block = new BlockStatement();
block.Statements.AddRange(m.Get<Statement>("nonNullDefaultStmt").Select(s => s.Detach()));
block.Add(new BreakStatement());
section.Statements.Add(block);
sw.SwitchSections.Add(section);
}
node.ReplaceWith(sw);
return sw;

15
ICSharpCode.Decompiler/DecompilerSettings.cs

@ -164,6 +164,21 @@ namespace ICSharpCode.Decompiler @@ -164,6 +164,21 @@ namespace ICSharpCode.Decompiler
}
}
bool useDebugSymbols = true;
/// <summary>
/// Gets/Sets whether to use variable names from debug symbols, if available.
/// </summary>
public bool UseDebugSymbols {
get { return useDebugSymbols; }
set {
if (useDebugSymbols != value) {
useDebugSymbols = value;
OnPropertyChanged("UseDebugSymbols");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)

10
ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs

@ -458,6 +458,16 @@ namespace ICSharpCode.Decompiler.ILAst @@ -458,6 +458,16 @@ namespace ICSharpCode.Decompiler.ILAst
InferTypeForExpression(expr.Arguments[0], (TypeReference)expr.Operand);
}
return typeSystem.TypedReference;
case ILCode.Refanytype:
if (forceInferChildren) {
InferTypeForExpression(expr.Arguments[0], typeSystem.TypedReference);
}
return new TypeReference("System", "RuntimeTypeHandle", module, module, true);
case ILCode.Refanyval:
if (forceInferChildren) {
InferTypeForExpression(expr.Arguments[0], typeSystem.TypedReference);
}
return new ByReferenceType((TypeReference)expr.Operand);
#endregion
#region Arithmetic instructions
case ILCode.Not: // bitwise complement

23
ICSharpCode.Decompiler/Tests/Loops.cs

@ -2,6 +2,7 @@ @@ -2,6 +2,7 @@
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
using System.Collections;
using System.Collections.Generic;
public class Loops
@ -23,14 +24,30 @@ public class Loops @@ -23,14 +24,30 @@ public class Loops
}
}
public void ForEachOverArray(string[] array)
public void ForEachOverNonGenericEnumerable(IEnumerable enumerable)
{
foreach (string text in array)
foreach (object current in enumerable)
{
text.ToLower();
current.ToString();
}
}
public void ForEachOverNonGenericEnumerableWithAutomaticCast(IEnumerable enumerable)
{
foreach (int num in enumerable)
{
num.ToString();
}
}
// public void ForEachOverArray(string[] array)
// {
// foreach (string text in array)
// {
// text.ToLower();
// }
// }
public void ForOverArray(string[] array)
{
for (int i = 0; i < array.Length; i++)

6
ICSharpCode.Decompiler/Tests/Switch.cs

@ -17,7 +17,8 @@ public static class Switch @@ -17,7 +17,8 @@ public static class Switch
public static string SwitchOverString1(string text)
{
switch (text) {
switch (text)
{
case "First case":
return "Text1";
case "Second case":
@ -40,7 +41,8 @@ public static class Switch @@ -40,7 +41,8 @@ public static class Switch
public static string SwitchOverString2()
{
switch (Environment.UserName) {
switch (Environment.UserName)
{
case "First case":
return "Text1";
case "Second case":

4
ICSharpCode.Decompiler/Tests/TestRunner.cs

@ -61,7 +61,7 @@ namespace ICSharpCode.Decompiler.Tests @@ -61,7 +61,7 @@ namespace ICSharpCode.Decompiler.Tests
TestFile(@"..\..\Tests\InitializerTests.cs");
}
[Test, Ignore("ForEachOverArray not supported")]
[Test]
public void Loops()
{
TestFile(@"..\..\Tests\Loops.cs");
@ -85,7 +85,7 @@ namespace ICSharpCode.Decompiler.Tests @@ -85,7 +85,7 @@ namespace ICSharpCode.Decompiler.Tests
TestFile(@"..\..\Tests\QueryExpressions.cs");
}
[Test, Ignore("switch transform is currently broken")]
[Test, Ignore("switch transform doesn't recreate the exact original switch")]
public void Switch()
{
TestFile(@"..\..\Tests\Switch.cs");

30
ILSpy.sln

@ -26,6 +26,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.Decompiler.Test @@ -26,6 +26,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.Decompiler.Test
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestPlugin", "TestPlugin\TestPlugin.csproj", "{F32EBCC8-0E53-4421-867E-05B3D6E10C70}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Cecil.Pdb", "Mono.Cecil\symbols\pdb\Mono.Cecil.Pdb.csproj", "{63E6915C-7EA4-4D76-AB28-0D7191EEA626}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -53,11 +55,11 @@ Global @@ -53,11 +55,11 @@ Global
{D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|Any CPU.ActiveCfg = net_4_0_Debug|Any CPU
{D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|Any CPU.Build.0 = net_4_0_Debug|Any CPU
{D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|x86.ActiveCfg = net_4_0_Debug|Any CPU
{D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|x86.Build.0 = net_2_0_Debug|Any CPU
{D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|x86.Build.0 = net_4_0_Debug|Any CPU
{D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|Any CPU.ActiveCfg = net_4_0_Release|Any CPU
{D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|Any CPU.Build.0 = net_4_0_Release|Any CPU
{D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|x86.ActiveCfg = net_4_0_Release|Any CPU
{D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|x86.Build.0 = net_2_0_Debug|Any CPU
{D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|x86.Build.0 = net_4_0_Debug|Any CPU
{6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}.Debug|x86.ActiveCfg = Debug|Any CPU
@ -90,14 +92,22 @@ Global @@ -90,14 +92,22 @@ Global
{FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Release|Any CPU.Build.0 = Release|x86
{FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Release|x86.ActiveCfg = Release|x86
{FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Release|x86.Build.0 = Release|x86
{F32EBCC8-0E53-4421-867E-05B3D6E10C70}.Debug|Any CPU.Build.0 = Debug|x86
{F32EBCC8-0E53-4421-867E-05B3D6E10C70}.Debug|Any CPU.ActiveCfg = Debug|x86
{F32EBCC8-0E53-4421-867E-05B3D6E10C70}.Debug|x86.Build.0 = Debug|x86
{F32EBCC8-0E53-4421-867E-05B3D6E10C70}.Debug|x86.ActiveCfg = Debug|x86
{F32EBCC8-0E53-4421-867E-05B3D6E10C70}.Release|Any CPU.Build.0 = Release|x86
{F32EBCC8-0E53-4421-867E-05B3D6E10C70}.Release|Any CPU.ActiveCfg = Release|x86
{F32EBCC8-0E53-4421-867E-05B3D6E10C70}.Release|x86.Build.0 = Release|x86
{F32EBCC8-0E53-4421-867E-05B3D6E10C70}.Release|x86.ActiveCfg = Release|x86
{F32EBCC8-0E53-4421-867E-05B3D6E10C70}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F32EBCC8-0E53-4421-867E-05B3D6E10C70}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F32EBCC8-0E53-4421-867E-05B3D6E10C70}.Debug|x86.Build.0 = Debug|Any CPU
{F32EBCC8-0E53-4421-867E-05B3D6E10C70}.Debug|x86.ActiveCfg = Debug|Any CPU
{F32EBCC8-0E53-4421-867E-05B3D6E10C70}.Release|Any CPU.Build.0 = Release|Any CPU
{F32EBCC8-0E53-4421-867E-05B3D6E10C70}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F32EBCC8-0E53-4421-867E-05B3D6E10C70}.Release|x86.Build.0 = Release|Any CPU
{F32EBCC8-0E53-4421-867E-05B3D6E10C70}.Release|x86.ActiveCfg = Release|Any CPU
{63E6915C-7EA4-4D76-AB28-0D7191EEA626}.Debug|Any CPU.Build.0 = net_4_0_Debug|Any CPU
{63E6915C-7EA4-4D76-AB28-0D7191EEA626}.Debug|Any CPU.ActiveCfg = net_4_0_Debug|Any CPU
{63E6915C-7EA4-4D76-AB28-0D7191EEA626}.Debug|x86.Build.0 = net_4_0_Debug|Any CPU
{63E6915C-7EA4-4D76-AB28-0D7191EEA626}.Debug|x86.ActiveCfg = net_4_0_Debug|Any CPU
{63E6915C-7EA4-4D76-AB28-0D7191EEA626}.Release|Any CPU.Build.0 = net_4_0_Debug|Any CPU
{63E6915C-7EA4-4D76-AB28-0D7191EEA626}.Release|Any CPU.ActiveCfg = net_4_0_Release|Any CPU
{63E6915C-7EA4-4D76-AB28-0D7191EEA626}.Release|x86.Build.0 = net_4_0_Debug|Any CPU
{63E6915C-7EA4-4D76-AB28-0D7191EEA626}.Release|x86.ActiveCfg = net_4_0_Release|Any CPU
{1D18D788-F7EE-4585-A23B-34DC8EC63CB8}.Debug|x86.Build.0 = Debug|Any CPU
{1D18D788-F7EE-4585-A23B-34DC8EC63CB8}.Debug|x86.ActiveCfg = Debug|Any CPU
{1D18D788-F7EE-4585-A23B-34DC8EC63CB8}.Debug|Any CPU.Build.0 = Debug|Any CPU

6
ILSpy/ILSpy.csproj

@ -118,6 +118,7 @@ @@ -118,6 +118,7 @@
<Compile Include="LoadedAssembly.cs" />
<Compile Include="NativeMethods.cs" />
<Compile Include="NavigationHistory.cs" />
<Compile Include="NavigationState.cs" />
<Compile Include="OpenFromGacDialog.xaml.cs">
<DependentUpon>OpenFromGacDialog.xaml</DependentUpon>
<SubType>Code</SubType>
@ -254,6 +255,7 @@ @@ -254,6 +255,7 @@
<Resource Include="Images\OverlayProtectedInternal.png" />
<Resource Include="Images\OverlayStatic.png" />
<Resource Include="Images\VirtualMethod.png" />
<Resource Include="Images\PInvokeMethod.png" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Debugger\ILSpy.Debugger\ILSpy.Debugger.csproj">
@ -272,6 +274,10 @@ @@ -272,6 +274,10 @@
<Project>{6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}</Project>
<Name>ICSharpCode.AvalonEdit</Name>
</ProjectReference>
<ProjectReference Include="..\Mono.Cecil\symbols\pdb\Mono.Cecil.Pdb.csproj">
<Project>{63E6915C-7EA4-4D76-AB28-0D7191EEA626}</Project>
<Name>Mono.Cecil.Pdb</Name>
</ProjectReference>
<ProjectReference Include="..\NRefactory\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj">
<Project>{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}</Project>
<Name>ICSharpCode.NRefactory</Name>

5
ILSpy/Images/Images.cs

@ -62,6 +62,7 @@ namespace ICSharpCode.ILSpy @@ -62,6 +62,7 @@ namespace ICSharpCode.ILSpy
private static readonly BitmapImage VirtualMethod = LoadBitmap("VirtualMethod");
private static readonly BitmapImage Operator = LoadBitmap("Operator");
private static readonly BitmapImage ExtensionMethod = LoadBitmap("ExtensionMethod");
private static readonly BitmapImage PInvokeMethod = LoadBitmap("PInvokeMethod");
private static readonly BitmapImage Property = LoadBitmap("Property");
private static readonly BitmapImage Indexer = LoadBitmap("Indexer");
@ -159,6 +160,7 @@ namespace ICSharpCode.ILSpy @@ -159,6 +160,7 @@ namespace ICSharpCode.ILSpy
PreloadPublicIconToCache(MemberIcon.VirtualMethod, Images.VirtualMethod);
PreloadPublicIconToCache(MemberIcon.Operator, Images.Operator);
PreloadPublicIconToCache(MemberIcon.ExtensionMethod, Images.ExtensionMethod);
PreloadPublicIconToCache(MemberIcon.PInvokeMethod, Images.PInvokeMethod);
PreloadPublicIconToCache(MemberIcon.Event, Images.Event);
}
@ -199,6 +201,9 @@ namespace ICSharpCode.ILSpy @@ -199,6 +201,9 @@ namespace ICSharpCode.ILSpy
case MemberIcon.ExtensionMethod:
baseImage = Images.ExtensionMethod;
break;
case MemberIcon.PInvokeMethod:
baseImage = Images.PInvokeMethod;
break;
case MemberIcon.Event:
baseImage = Images.Event;
break;

1
ILSpy/Images/MemberIcon.cs

@ -33,6 +33,7 @@ namespace ICSharpCode.ILSpy @@ -33,6 +33,7 @@ namespace ICSharpCode.ILSpy
VirtualMethod,
Operator,
ExtensionMethod,
PInvokeMethod,
Event
}
}

BIN
ILSpy/Images/OverlayStatic.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 312 B

After

Width:  |  Height:  |  Size: 310 B

BIN
ILSpy/Images/PInvokeMethod.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 630 B

22
ILSpy/LoadedAssembly.cs

@ -69,7 +69,27 @@ namespace ICSharpCode.ILSpy @@ -69,7 +69,27 @@ namespace ICSharpCode.ILSpy
// runs on background thread
ReaderParameters p = new ReaderParameters();
p.AssemblyResolver = new MyAssemblyResolver(this);
return AssemblyDefinition.ReadAssembly(fileName, p);
try {
if (DecompilerSettingsPanel.CurrentDecompilerSettings.UseDebugSymbols) {
SetSymbolSettings(p);
}
return AssemblyDefinition.ReadAssembly(fileName, p);
} finally {
if (p.SymbolStream != null)
p.SymbolStream.Dispose();
}
}
private void SetSymbolSettings(ReaderParameters p)
{
// search for pdb in same directory as dll
string pdbName = Path.Combine(Path.GetDirectoryName(fileName), Path.GetFileNameWithoutExtension(fileName) + ".pdb");
if (File.Exists(pdbName)) {
p.ReadSymbols = true;
p.SymbolStream = File.OpenRead(pdbName);
}
// TODO: use symbol cache, get symbols from microsoft
}
[ThreadStatic]

32
ILSpy/MainWindow.xaml.cs

@ -51,8 +51,7 @@ namespace ICSharpCode.ILSpy @@ -51,8 +51,7 @@ namespace ICSharpCode.ILSpy
/// </summary>
partial class MainWindow : Window
{
NavigationHistory<Tuple<List<SharpTreeNode>, DecompilerTextViewState>> history =
new NavigationHistory<Tuple<List<SharpTreeNode>, DecompilerTextViewState>>();
NavigationHistory<NavigationState> history = new NavigationHistory<NavigationState>();
ILSpySettings spySettings;
internal SessionSettings sessionSettings;
AssemblyListManager assemblyListManager;
@ -343,7 +342,7 @@ namespace ICSharpCode.ILSpy @@ -343,7 +342,7 @@ namespace ICSharpCode.ILSpy
{
if (e.OldItems != null)
foreach (LoadedAssembly asm in e.OldItems)
history.RemoveAll(n => n.Item1.Any(nd => nd.AncestorsAndSelf().OfType<AssemblyTreeNode>().Any(a => a.LoadedAssembly == asm)));
history.RemoveAll(n => n.TreeNodes.Any(nd => nd.AncestorsAndSelf().OfType<AssemblyTreeNode>().Any(a => a.LoadedAssembly == asm)));
}
void LoadInitialAssemblies()
@ -391,12 +390,9 @@ namespace ICSharpCode.ILSpy @@ -391,12 +390,9 @@ namespace ICSharpCode.ILSpy
}
#region Node Selection
internal void SelectNode(SharpTreeNode obj, bool recordNavigationInHistory = true)
internal void SelectNode(SharpTreeNode obj)
{
if (obj != null) {
SharpTreeNode oldNode = treeView.SelectedItem as SharpTreeNode;
if (oldNode != null && recordNavigationInHistory)
history.Record(Tuple.Create(treeView.SelectedItems.OfType<SharpTreeNode>().ToList(), decompilerTextView.GetState()));
// Set both the selection and focus to ensure that keyboard navigation works as expected.
treeView.FocusNode(obj);
treeView.SelectedItem = obj;
@ -522,11 +518,14 @@ namespace ICSharpCode.ILSpy @@ -522,11 +518,14 @@ namespace ICSharpCode.ILSpy
private bool ignoreDecompilationRequests;
private void DecompileSelectedNodes(DecompilerTextViewState state = null)
private void DecompileSelectedNodes(DecompilerTextViewState state = null, bool recordHistory = true)
{
if (ignoreDecompilationRequests)
return;
if (recordHistory)
history.Record(new NavigationState(treeView.SelectedItems.OfType<SharpTreeNode>(), decompilerTextView.GetState()));
if (treeView.SelectedItems.Count == 1) {
ILSpyTreeNode node = treeView.SelectedItem as ILSpyTreeNode;
if (node != null && node.View(decompilerTextView))
@ -599,21 +598,20 @@ namespace ICSharpCode.ILSpy @@ -599,21 +598,20 @@ namespace ICSharpCode.ILSpy
void NavigateHistory(bool forward)
{
var currentSelection = treeView.SelectedItems.OfType<SharpTreeNode>().ToList();
var state = decompilerTextView.GetState();
var combinedState = Tuple.Create(currentSelection, state);
var newState = forward ? history.GoForward(combinedState) : history.GoBack(combinedState);
var combinedState = new NavigationState(treeView.SelectedItems.OfType<SharpTreeNode>(), decompilerTextView.GetState());
history.Record(combinedState, replace: true, clearForward: false);
var newState = forward ? history.GoForward() : history.GoBack();
ignoreDecompilationRequests = true;
treeView.SelectedItems.Clear();
foreach (var node in newState.Item1)
foreach (var node in newState.TreeNodes)
{
treeView.SelectedItems.Add(node);
}
if (newState.Item1.Count > 0)
treeView.FocusNode(newState.Item1[0]);
if (newState.TreeNodes.Any())
treeView.FocusNode(newState.TreeNodes.First());
ignoreDecompilationRequests = false;
DecompileSelectedNodes(newState.Item2);
DecompileSelectedNodes(newState.ViewState, false);
}
#endregion
@ -681,4 +679,4 @@ namespace ICSharpCode.ILSpy @@ -681,4 +679,4 @@ namespace ICSharpCode.ILSpy
this.StatusLabel.Text = status;
}
}
}
}

52
ILSpy/NavigationHistory.cs

@ -4,14 +4,20 @@ @@ -4,14 +4,20 @@
using System;
using System.Collections.Generic;
using ICSharpCode.TreeView;
using System.Diagnostics;
namespace ICSharpCode.ILSpy
{
/// <summary>
/// Stores the navigation history.
/// </summary>
sealed class NavigationHistory<T>
internal sealed class NavigationHistory<T>
where T : class, IEquatable<T>
{
private const double NavigationSecondsBeforeNewEntry = 0.5;
private DateTime lastNavigationTime = DateTime.MinValue;
T current;
List<T> back = new List<T>();
List<T> forward = new List<T>();
@ -23,26 +29,22 @@ namespace ICSharpCode.ILSpy @@ -23,26 +29,22 @@ namespace ICSharpCode.ILSpy
get { return forward.Count > 0; }
}
public T GoBack(T oldNode)
public T GoBack()
{
if (oldNode != null)
forward.Add(oldNode);
T node = back[back.Count - 1];
forward.Add(current);
current = back[back.Count - 1];
back.RemoveAt(back.Count - 1);
return node;
return current;
}
public T GoForward(T oldNode)
public T GoForward()
{
if (oldNode != null)
back.Add(oldNode);
T node = forward[forward.Count - 1];
back.Add(current);
current = forward[forward.Count - 1];
forward.RemoveAt(forward.Count - 1);
return node;
return current;
}
public void RemoveAll(Predicate<T> predicate)
{
back.RemoveAll(predicate);
@ -55,10 +57,26 @@ namespace ICSharpCode.ILSpy @@ -55,10 +57,26 @@ namespace ICSharpCode.ILSpy
forward.Clear();
}
public void Record(T node)
public void Record(T node, bool replace = false, bool clearForward = true)
{
forward.Clear();
back.Add(node);
var navigationTime = DateTime.Now;
var period = navigationTime - lastNavigationTime;
if (period.TotalSeconds < NavigationSecondsBeforeNewEntry || replace) {
current = node;
} else {
if (current != null)
back.Add(current);
// We only store a record once, and ensure it is on the top of the stack, so we just remove the old record
back.Remove(node);
current = node;
}
if (clearForward)
forward.Clear();
lastNavigationTime = navigationTime;
}
}
}

28
ILSpy/NavigationState.cs

@ -0,0 +1,28 @@ @@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ICSharpCode.ILSpy.TextView;
using ICSharpCode.TreeView;
namespace ICSharpCode.ILSpy
{
public class NavigationState : IEquatable<NavigationState>
{
private HashSet<SharpTreeNode> treeNodes;
public IEnumerable<SharpTreeNode> TreeNodes { get { return treeNodes; } }
public DecompilerTextViewState ViewState { get; private set; }
public NavigationState(IEnumerable<SharpTreeNode> treeNodes, DecompilerTextViewState viewState)
{
this.treeNodes = new HashSet<SharpTreeNode>(treeNodes);
ViewState = viewState;
}
public bool Equals(NavigationState other)
{
// TODO: should this care about the view state as well?
return this.treeNodes.SetEquals(other.treeNodes);
}
}
}

1
ILSpy/Options/DecompilerSettingsPanel.xaml

@ -6,5 +6,6 @@ @@ -6,5 +6,6 @@
<CheckBox IsChecked="{Binding AnonymousMethods}">Decompile anonymous methods/lambdas</CheckBox>
<CheckBox IsChecked="{Binding YieldReturn}">Decompile enumerators (yield return)</CheckBox>
<CheckBox IsChecked="{Binding QueryExpressions}" IsEnabled="{Binding AnonymousMethods}">Decompile query expressions</CheckBox>
<CheckBox IsChecked="{Binding UseDebugSymbols}">Use variable names from debug symbols, if available</CheckBox>
</StackPanel>
</UserControl>

2
ILSpy/Options/DecompilerSettingsPanel.xaml.cs

@ -46,6 +46,7 @@ namespace ICSharpCode.ILSpy @@ -46,6 +46,7 @@ namespace ICSharpCode.ILSpy
s.AnonymousMethods = (bool?)e.Attribute("anonymousMethods") ?? s.AnonymousMethods;
s.YieldReturn = (bool?)e.Attribute("yieldReturn") ?? s.YieldReturn;
s.QueryExpressions = (bool?)e.Attribute("queryExpressions") ?? s.QueryExpressions;
s.UseDebugSymbols = (bool?)e.Attribute("useDebugSymbols") ?? s.UseDebugSymbols;
return s;
}
@ -56,6 +57,7 @@ namespace ICSharpCode.ILSpy @@ -56,6 +57,7 @@ namespace ICSharpCode.ILSpy
section.SetAttributeValue("anonymousMethods", s.AnonymousMethods);
section.SetAttributeValue("yieldReturn", s.YieldReturn);
section.SetAttributeValue("queryExpressions", s.QueryExpressions);
section.SetAttributeValue("useDebugSymbols", s.UseDebugSymbols);
XElement existingElement = root.Element("DecompilerSettings");
if (existingElement != null)

3
ILSpy/Options/OptionsDialog.xaml.cs

@ -88,8 +88,7 @@ namespace ICSharpCode.ILSpy @@ -88,8 +88,7 @@ namespace ICSharpCode.ILSpy
OptionsDialog dlg = new OptionsDialog();
dlg.Owner = MainWindow.Instance;
if (dlg.ShowDialog() == true) {
MainWindow.Instance.RefreshTreeViewFilter();
MainWindow.Instance.RefreshDecompiledView();
new RefreshCommand().Execute(parameter);
}
}
}

5
ILSpy/TreeNodes/MethodTreeNode.cs

@ -92,10 +92,13 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -92,10 +92,13 @@ namespace ICSharpCode.ILSpy.TreeNodes
}
if (method.IsSpecialName &&
(method.Name == ".ctor" || method.Name == ".cctor")) {
(method.Name == ".ctor" || method.Name == ".cctor")) {
return Images.GetIcon(MemberIcon.Constructor, GetOverlayIcon(method.Attributes), false);
}
if (method.HasPInvokeInfo)
return Images.GetIcon(MemberIcon.PInvokeMethod, GetOverlayIcon(method.Attributes), true);
bool showAsVirtual = method.IsVirtual && !(method.IsNewSlot && method.IsFinal) && !method.DeclaringType.IsInterface;
return Images.GetIcon(

2
Mono.Cecil/symbols/pdb/Mono.Cecil.Pdb/PdbHelper.cs

@ -65,7 +65,7 @@ namespace Mono.Cecil.Pdb { @@ -65,7 +65,7 @@ namespace Mono.Cecil.Pdb {
public ISymbolReader GetSymbolReader (ModuleDefinition module, Stream symbolStream)
{
throw new NotImplementedException ();
return new PdbReader (symbolStream);
}
}

4
TestPlugin/TestPlugin.csproj

@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
<PropertyGroup>
<ProjectGuid>{F32EBCC8-0E53-4421-867E-05B3D6E10C70}</ProjectGuid>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<OutputType>Library</OutputType>
<RootNamespace>TestPlugin</RootNamespace>
<AssemblyName>Test.Plugin</AssemblyName>
@ -15,7 +15,7 @@ @@ -15,7 +15,7 @@
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<StartArguments>/separate</StartArguments>
</PropertyGroup>
<PropertyGroup Condition=" '$(Platform)' == 'x86' ">
<PropertyGroup Condition=" '$(Platform)' == 'AnyCPU' ">
<PlatformTarget>x86</PlatformTarget>
<RegisterForComInterop>False</RegisterForComInterop>
<GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies>

Loading…
Cancel
Save