Browse Source

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

pull/191/merge
Eusebiu Marcu 15 years ago
parent
commit
8af62b6f37
  1. 139
      ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  2. 2
      ICSharpCode.Decompiler/Ast/NameVariables.cs
  3. 2
      ICSharpCode.Decompiler/Ast/Transforms/PushNegation.cs
  4. 38
      ICSharpCode.Decompiler/Ast/Transforms/UsingStatementTransform.cs
  5. 127
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  6. 27
      ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs
  7. 15
      ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
  8. 11
      ICSharpCode.Decompiler/ILAst/ILAstTypes.cs
  9. 1
      ICSharpCode.Decompiler/ITextOutput.cs
  10. 55
      ICSharpCode.Decompiler/TextOutputWriter.cs
  11. 173
      ILSpy/CSharpLanguage.cs
  12. 5
      ILSpy/DecompilationOptions.cs
  13. 4
      ILSpy/Language.cs
  14. 65
      ILSpy/MainWindow.xaml.cs
  15. 13
      ILSpy/TextView/DecompilerTextView.cs
  16. 33
      ILSpy/TreeNodes/AssemblyTreeNode.cs
  17. 2
      ILSpy/TreeNodes/ILSpyTreeNode.cs
  18. 4
      ILSpy/TreeNodes/ResourceEntryNode.cs
  19. 4
      ILSpy/TreeNodes/ResourceListTreeNode.cs
  20. 2
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Backreference.cs
  21. 18
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Choice.cs
  22. 28
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Match.cs
  23. 5
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Pattern.cs
  24. 52
      NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Placeholder.cs
  25. 3
      NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs

139
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
@ -160,6 +161,8 @@ namespace Decompiler @@ -160,6 +161,8 @@ namespace Decompiler
yield return tryCatchStmt;
} else if (node is ILBlock) {
yield return TransformBlock((ILBlock)node);
} else if (node is ILComment) {
yield return new CommentStatement(((ILComment)node).Text).WithAnnotation(((ILComment)node).ILRanges);
} else {
throw new Exception("Unknown node type");
}
@ -276,7 +279,7 @@ namespace Decompiler @@ -276,7 +279,7 @@ namespace Decompiler
}
}
string FormatByteCodeOperand(object operand)
static string FormatByteCodeOperand(object operand)
{
if (operand == null) {
return string.Empty;
@ -303,8 +306,6 @@ namespace Decompiler @@ -303,8 +306,6 @@ namespace Decompiler
AstNode TransformByteCode_Internal(ILExpression byteCode, List<Ast.Expression> args)
{
// throw new NotImplementedException();
ILCode opCode = byteCode.Code;
object operand = byteCode.Operand;
AstType operandAsTypeRef = AstBuilder.ConvertType(operand as Cecil.TypeReference);
@ -367,7 +368,7 @@ namespace Decompiler @@ -367,7 +368,7 @@ namespace Decompiler
case Code.Ldelem_Ref:
return arg1.Indexer(arg2);
case Code.Ldelem_Any:
throw new NotImplementedException();
return InlineAssembly(byteCode, args);
case Code.Ldelema:
return MakeRef(arg1.Indexer(arg2));
@ -381,7 +382,7 @@ namespace Decompiler @@ -381,7 +382,7 @@ namespace Decompiler
case Code.Stelem_Ref:
return new Ast.AssignmentExpression(arg1.Indexer(arg2), arg3);
case Code.Stelem_Any:
throw new NotImplementedException();
return InlineAssembly(byteCode, args);
#endregion
#region Branching
case Code.Br: return new Ast.GotoStatement(((ILLabel)byteCode.Operand).Name);
@ -443,30 +444,30 @@ namespace Decompiler @@ -443,30 +444,30 @@ namespace Decompiler
case Code.Conv_Ovf_U8_Un: return arg1.CastTo(typeof(UInt64));
#endregion
#region Indirect
case Code.Ldind_I: throw new NotImplementedException();
case Code.Ldind_I1: throw new NotImplementedException();
case Code.Ldind_I2: throw new NotImplementedException();
case Code.Ldind_I4: throw new NotImplementedException();
case Code.Ldind_I8: throw new NotImplementedException();
case Code.Ldind_U1: throw new NotImplementedException();
case Code.Ldind_U2: throw new NotImplementedException();
case Code.Ldind_U4: throw new NotImplementedException();
case Code.Ldind_R4: throw new NotImplementedException();
case Code.Ldind_R8: throw new NotImplementedException();
case Code.Ldind_Ref: throw new NotImplementedException();
case Code.Ldind_I: return InlineAssembly(byteCode, args);
case Code.Ldind_I1: return InlineAssembly(byteCode, args);
case Code.Ldind_I2: return InlineAssembly(byteCode, args);
case Code.Ldind_I4: return InlineAssembly(byteCode, args);
case Code.Ldind_I8: return InlineAssembly(byteCode, args);
case Code.Ldind_U1: return InlineAssembly(byteCode, args);
case Code.Ldind_U2: return InlineAssembly(byteCode, args);
case Code.Ldind_U4: return InlineAssembly(byteCode, args);
case Code.Ldind_R4: return InlineAssembly(byteCode, args);
case Code.Ldind_R8: return InlineAssembly(byteCode, args);
case Code.Ldind_Ref: return InlineAssembly(byteCode, args);
case Code.Stind_I: throw new NotImplementedException();
case Code.Stind_I1: throw new NotImplementedException();
case Code.Stind_I2: throw new NotImplementedException();
case Code.Stind_I4: throw new NotImplementedException();
case Code.Stind_I8: throw new NotImplementedException();
case Code.Stind_R4: throw new NotImplementedException();
case Code.Stind_R8: throw new NotImplementedException();
case Code.Stind_Ref: throw new NotImplementedException();
case Code.Stind_I: return InlineAssembly(byteCode, args);
case Code.Stind_I1: return InlineAssembly(byteCode, args);
case Code.Stind_I2: return InlineAssembly(byteCode, args);
case Code.Stind_I4: return InlineAssembly(byteCode, args);
case Code.Stind_I8: return InlineAssembly(byteCode, args);
case Code.Stind_R4: return InlineAssembly(byteCode, args);
case Code.Stind_R8: return InlineAssembly(byteCode, args);
case Code.Stind_Ref: return InlineAssembly(byteCode, args);
#endregion
case Code.Arglist: throw new NotImplementedException();
case Code.Box: throw new NotImplementedException();
case Code.Break: throw new NotImplementedException();
case Code.Arglist: return InlineAssembly(byteCode, args);
case Code.Box: return InlineAssembly(byteCode, args);
case Code.Break: return InlineAssembly(byteCode, args);
case Code.Call:
return TransformCall(false, operand, methodDef, args);
case Code.Callvirt:
@ -490,19 +491,19 @@ namespace Decompiler @@ -490,19 +491,19 @@ namespace Decompiler
.WithAnnotation(new Transforms.DelegateConstruction.Annotation(true));
}
case Code.Calli: throw new NotImplementedException();
case Code.Calli: return InlineAssembly(byteCode, args);
case Code.Castclass: return arg1.CastTo(operandAsTypeRef);
case Code.Ckfinite: throw new NotImplementedException();
case Code.Constrained: throw new NotImplementedException();
case Code.Cpblk: throw new NotImplementedException();
case Code.Cpobj: throw new NotImplementedException();
case Code.Ckfinite: return InlineAssembly(byteCode, args);
case Code.Constrained: return InlineAssembly(byteCode, args);
case Code.Cpblk: return InlineAssembly(byteCode, args);
case Code.Cpobj: return InlineAssembly(byteCode, args);
case Code.Dup: return arg1;
case Code.Endfilter: throw new NotImplementedException();
case Code.Endfilter: return InlineAssembly(byteCode, args);
case Code.Endfinally: return null;
case Code.Initblk: throw new NotImplementedException();
case Code.Initobj: throw new NotImplementedException();
case Code.Initblk: return InlineAssembly(byteCode, args);
case Code.Initobj: return InlineAssembly(byteCode, args);
case Code.Isinst: return arg1.CastAs(AstBuilder.ConvertType((Cecil.TypeReference)operand));
case Code.Jmp: throw new NotImplementedException();
case Code.Jmp: return InlineAssembly(byteCode, args);
case Code.Ldarg:
if (methodDef.HasThis && ((ParameterDefinition)operand).Index < 0) {
return new Ast.ThisReferenceExpression();
@ -557,17 +558,17 @@ namespace Decompiler @@ -557,17 +558,17 @@ namespace Decompiler
case Code.Ldloca:
return MakeRef(new Ast.IdentifierExpression(((ILVariable)operand).Name));
case Code.Ldnull: return new Ast.NullReferenceExpression();
case Code.Ldobj: throw new NotImplementedException();
case Code.Ldobj: return InlineAssembly(byteCode, args);
case Code.Ldstr: return new Ast.PrimitiveExpression(operand);
case Code.Ldtoken:
if (operand is Cecil.TypeReference) {
return new Ast.TypeOfExpression { Type = operandAsTypeRef }.Member("TypeHandle");
} else {
throw new NotImplementedException();
return InlineAssembly(byteCode, args);
}
case Code.Leave: return null;
case Code.Localloc: throw new NotImplementedException();
case Code.Mkrefany: throw new NotImplementedException();
case Code.Localloc: return InlineAssembly(byteCode, args);
case Code.Mkrefany: return InlineAssembly(byteCode, args);
case Code.Newobj:
{
Cecil.TypeReference declaringType = ((MethodReference)operand).DeclaringType;
@ -584,12 +585,12 @@ namespace Decompiler @@ -584,12 +585,12 @@ namespace Decompiler
oce.Arguments.AddRange(args);
return oce.WithAnnotation(operand);
}
case Code.No: throw new NotImplementedException();
case Code.No: return InlineAssembly(byteCode, args);
case Code.Nop: return null;
case Code.Pop: return arg1;
case Code.Readonly: throw new NotImplementedException();
case Code.Refanytype: throw new NotImplementedException();
case Code.Refanyval: throw new NotImplementedException();
case Code.Readonly: return InlineAssembly(byteCode, args);
case Code.Refanytype: return InlineAssembly(byteCode, args);
case Code.Refanyval: return InlineAssembly(byteCode, args);
case Code.Ret: {
if (methodDef.ReturnType.FullName != "System.Void") {
arg1 = Convert(arg1, methodDef.ReturnType);
@ -600,7 +601,7 @@ namespace Decompiler @@ -600,7 +601,7 @@ namespace Decompiler
}
case Code.Rethrow: return new Ast.ThrowStatement();
case Code.Sizeof: return new Ast.SizeOfExpression { Type = AstBuilder.ConvertType(operand as TypeReference) };
case Code.Starg: throw new NotImplementedException();
case Code.Starg: return InlineAssembly(byteCode, args);
case Code.Stloc: {
ILVariable locVar = (ILVariable)operand;
if (!definedLocalVars.Contains(locVar)) {
@ -613,14 +614,14 @@ namespace Decompiler @@ -613,14 +614,14 @@ namespace Decompiler
return new Ast.AssignmentExpression(new Ast.IdentifierExpression(locVar.Name), arg1);
}
}
case Code.Stobj: throw new NotImplementedException();
case Code.Switch: throw new NotImplementedException();
case Code.Tail: throw new NotImplementedException();
case Code.Stobj: return InlineAssembly(byteCode, args);
case Code.Switch: return InlineAssembly(byteCode, args);
case Code.Tail: return InlineAssembly(byteCode, args);
case Code.Throw: return new Ast.ThrowStatement { Expression = arg1 };
case Code.Unaligned: throw new NotImplementedException();
case Code.Unbox: throw new NotImplementedException();
case Code.Unbox_Any: throw new NotImplementedException();
case Code.Volatile: throw new NotImplementedException();
case Code.Unaligned: return InlineAssembly(byteCode, args);
case Code.Unbox: return InlineAssembly(byteCode, args);
case Code.Unbox_Any: return InlineAssembly(byteCode, args);
case Code.Volatile: return InlineAssembly(byteCode, args);
default: throw new Exception("Unknown OpCode: " + opCode);
}
}
@ -690,6 +691,40 @@ namespace Decompiler @@ -690,6 +691,40 @@ namespace Decompiler
return target.Invoke(cecilMethod.Name, ConvertTypeArguments(cecilMethod), methodArgs).WithAnnotation(cecilMethod);
}
#if DEBUG
static readonly ConcurrentDictionary<ILCode, int> unhandledOpcodes = new ConcurrentDictionary<ILCode, int>();
#endif
[Conditional("DEBUG")]
public static void ClearUnhandledOpcodes()
{
#if DEBUG
unhandledOpcodes.Clear();
#endif
}
[Conditional("DEBUG")]
public static void PrintNumberOfUnhandledOpcodes()
{
#if DEBUG
foreach (var pair in unhandledOpcodes) {
Debug.WriteLine("AddMethodBodyBuilder unhandled opcode: {1}x {0}", pair.Key, pair.Value);
}
#endif
}
static Expression InlineAssembly(ILExpression byteCode, List<Ast.Expression> args)
{
#if DEBUG
unhandledOpcodes.AddOrUpdate(byteCode.Code, c => 1, (c, n) => n+1);
#endif
// Output the operand of the unknown IL code as well
if (byteCode.Operand != null) {
args.Insert(0, new IdentifierExpression(FormatByteCodeOperand(byteCode.Operand)));
}
return new IdentifierExpression(byteCode.Code.GetName()).Invoke(args);
}
static IEnumerable<AstType> ConvertTypeArguments(MethodReference cecilMethod)
{
GenericInstanceMethod g = cecilMethod as GenericInstanceMethod;

2
ICSharpCode.Decompiler/Ast/NameVariables.cs

@ -97,7 +97,7 @@ namespace Decompiler @@ -97,7 +97,7 @@ namespace Decompiler
switch (expr.Code) {
case ILCode.Ldfld:
// Use the field name only if it's not a field on this (avoid confusion between local variables and fields)
if (!(expr.Arguments[0].Code == ILCode.Ldloc && ((ParameterDefinition)expr.Arguments[0].Operand).Index < 0))
if (!(expr.Arguments[0].Code == ILCode.Ldarg && ((ParameterDefinition)expr.Arguments[0].Operand).Index < 0))
return ((FieldReference)expr.Operand).Name;
break;
case ILCode.Ldsfld:

2
ICSharpCode.Decompiler/Ast/Transforms/PushNegation.cs

@ -114,7 +114,7 @@ namespace Decompiler.Transforms @@ -114,7 +114,7 @@ namespace Decompiler.Transforms
negate = true;
}
if (m != null) {
Expression expr = ((Expression)m["expr"].Single()).Detach().IsType((AstType)m["type"].Single().Detach());
Expression expr = m.Get<Expression>("expr").Single().Detach().IsType(m.Get<AstType>("type").Single().Detach());
if (negate)
expr = new UnaryOperatorExpression(UnaryOperatorType.Not, expr);
binaryOperatorExpression.ReplaceWith(expr);

38
ICSharpCode.Decompiler/Ast/Transforms/UsingStatementTransform.cs

@ -6,6 +6,7 @@ using System.Linq; @@ -6,6 +6,7 @@ using System.Linq;
using Decompiler.Transforms;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.PatternMatching;
using Mono.Cecil;
namespace Decompiler.Transforms
{
@ -29,18 +30,25 @@ namespace Decompiler.Transforms @@ -29,18 +30,25 @@ namespace Decompiler.Transforms
TryBlock = new AnyNode("body").ToBlock(),
FinallyBlock = new BlockStatement {
Statements = {
new IfElseStatement {
Condition = new BinaryOperatorExpression(
new NamedNode("ident", new IdentifierExpression()).ToExpression(),
BinaryOperatorType.InEquality,
new NullReferenceExpression()
),
TrueStatement = new BlockStatement {
Statements = {
new ExpressionStatement(new Backreference("ident").ToExpression().Invoke("Dispose"))
new Choice {
{ "valueType",
new ExpressionStatement(new NamedNode("ident", new IdentifierExpression()).ToExpression().Invoke("Dispose"))
},
{ "referenceType",
new IfElseStatement {
Condition = new BinaryOperatorExpression(
new NamedNode("ident", new IdentifierExpression()).ToExpression(),
BinaryOperatorType.InEquality,
new NullReferenceExpression()
),
TrueStatement = new BlockStatement {
Statements = {
new ExpressionStatement(new Backreference("ident").ToExpression().Invoke("Dispose"))
}
}
}
}
}
}.ToStatement()
}
}
};
@ -52,8 +60,14 @@ namespace Decompiler.Transforms @@ -52,8 +60,14 @@ namespace Decompiler.Transforms
if (m1 == null) continue;
Match m2 = usingTryCatchPattern.Match(node.NextSibling);
if (m2 == null) continue;
if (((VariableInitializer)m1["variable"].Single()).Name == ((IdentifierExpression)m2["ident"].Single()).Identifier) {
BlockStatement body = (BlockStatement)m2["body"].Single();
if (m1.Get<VariableInitializer>("variable").Single().Name == m2.Get<IdentifierExpression>("ident").Single().Identifier) {
if (m2.Has("valueType")) {
// if there's no if(x!=null), then it must be a value type
TypeReference tr = m1.Get<AstType>("type").Single().Annotation<TypeReference>();
if (tr == null || !tr.IsValueType)
continue;
}
BlockStatement body = m2.Get<BlockStatement>("body").Single();
body.Remove();
node.NextSibling.Remove();
node.ReplaceWith(

127
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -1,3 +1,4 @@ @@ -1,3 +1,4 @@
<<<<<<< HEAD
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
<PropertyGroup>
@ -124,4 +125,130 @@ @@ -124,4 +125,130 @@
<Exec WorkingDirectory="$(MSBuildProjectDirectory)\..\BuildTools\UpdateAssemblyInfo\bin\Debug" Command="UpdateAssemblyInfo.exe --branchname $(BranchName)" Timeout="60000" Condition=" '$(BranchName)' != '' " />
<Exec WorkingDirectory="$(MSBuildProjectDirectory)\..\BuildTools\UpdateAssemblyInfo\bin\Debug" Command="UpdateAssemblyInfo.exe" Timeout="60000" Condition=" '$(BranchName)' == '' " />
</Target>
=======
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Build">
<PropertyGroup>
<ProjectGuid>{984CC812-9470-4A13-AFF9-CC44068D666C}</ProjectGuid>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<OutputType>Library</OutputType>
<RootNamespace>ICSharpCode.Decompiler</RootNamespace>
<AssemblyName>ICSharpCode.Decompiler</AssemblyName>
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
<AppDesignerFolder>Properties</AppDesignerFolder>
<AllowUnsafeBlocks>False</AllowUnsafeBlocks>
<NoStdLib>False</NoStdLib>
<WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup Condition=" '$(Platform)' == 'AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<RegisterForComInterop>False</RegisterForComInterop>
<GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies>
<BaseAddress>4194304</BaseAddress>
<FileAlignment>4096</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<OutputPath>bin\Debug\</OutputPath>
<DebugSymbols>true</DebugSymbols>
<DebugType>Full</DebugType>
<Optimize>False</Optimize>
<CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>
<DefineConstants>DEBUG;TRACE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<OutputPath>bin\Release\</OutputPath>
<DebugSymbols>False</DebugSymbols>
<DebugType>None</DebugType>
<Optimize>True</Optimize>
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
<DefineConstants>TRACE</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Xml" />
<Reference Include="System.Xml.Linq">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Ast\AstBuilder.cs" />
<Compile Include="Ast\AstMethodBodyBuilder.cs" />
<Compile Include="Ast\CommentStatement.cs" />
<Compile Include="Ast\DecompilerContext.cs" />
<Compile Include="Ast\NameVariables.cs" />
<Compile Include="Ast\NRefactoryExtensions.cs" />
<Compile Include="Ast\TextOutputFormatter.cs" />
<Compile Include="Ast\Transforms\ContextTrackingVisitor.cs" />
<Compile Include="Ast\Transforms\ConvertConstructorCallIntoInitializer.cs" />
<Compile Include="Ast\Transforms\DelegateConstruction.cs" />
<Compile Include="Ast\Transforms\ReplaceMethodCallsWithOperators.cs" />
<Compile Include="Ast\Transforms\PushNegation.cs" />
<Compile Include="Ast\Transforms\RemoveDeadLabels.cs" />
<Compile Include="Ast\Transforms\RemoveEmptyElseBody.cs" />
<Compile Include="Ast\Transforms\RemoveGotos.cs" />
<Compile Include="Ast\Transforms\RestoreLoop.cs" />
<Compile Include="Ast\Transforms\TransformationPipeline.cs" />
<Compile Include="Ast\Transforms\UsingStatementTransform.cs" />
<Compile Include="CecilExtensions.cs" />
<Compile Include="DecompilerException.cs" />
<Compile Include="Disassembler\DisassemblerHelpers.cs" />
<Compile Include="Disassembler\ILStructure.cs" />
<Compile Include="Disassembler\MethodBodyDisassembler.cs" />
<Compile Include="Disassembler\ReflectionDisassembler.cs" />
<Compile Include="FlowAnalysis\ControlFlowEdge.cs" />
<Compile Include="FlowAnalysis\ControlFlowGraph.cs" />
<Compile Include="FlowAnalysis\ControlFlowGraphBuilder.cs" />
<Compile Include="FlowAnalysis\ControlFlowNode.cs" />
<Compile Include="FlowAnalysis\ControlStructureDetector.cs" />
<Compile Include="FlowAnalysis\OpCodeInfo.cs" />
<Compile Include="FlowAnalysis\SimplifyByRefCalls.cs" />
<Compile Include="FlowAnalysis\SsaBlock.cs" />
<Compile Include="FlowAnalysis\SsaForm.cs" />
<Compile Include="FlowAnalysis\SsaFormBuilder.cs" />
<Compile Include="FlowAnalysis\SsaInstruction.cs" />
<Compile Include="FlowAnalysis\SsaOptimization.cs" />
<Compile Include="FlowAnalysis\SsaVariable.cs" />
<Compile Include="FlowAnalysis\TransformToSsa.cs" />
<Compile Include="GraphVizGraph.cs" />
<Compile Include="ILAst\ILAstBuilder.cs" />
<Compile Include="ILAst\ILAstOptimizer.cs" />
<Compile Include="ILAst\ILAstTypes.cs" />
<Compile Include="ILAst\ILCodes.cs" />
<Compile Include="ILAst\TypeAnalysis.cs" />
<Compile Include="ITextOutput.cs" />
<Compile Include="Options.cs" />
<Compile Include="PlainTextOutput.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="TextOutputWriter.cs" />
<None Include="Properties\AssemblyInfo.template.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Mono.Cecil\Mono.Cecil.csproj">
<Project>{D68133BD-1E63-496E-9EDE-4FBDBF77B486}</Project>
<Name>Mono.Cecil</Name>
</ProjectReference>
<ProjectReference Include="..\NRefactory\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj">
<Project>{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}</Project>
<Name>ICSharpCode.NRefactory</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Folder Include="Ast" />
<Folder Include="Ast\Transforms" />
<Folder Include="Disassembler" />
<Folder Include="ILAst" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
<Target Name="BeforeBuild">
<MSBuild Projects="$(MSBuildProjectDirectory)\..\BuildTools\UpdateAssemblyInfo\UpdateAssemblyInfo.csproj" Targets="Build" Properties="Configuration=Debug" />
<Exec WorkingDirectory="$(MSBuildProjectDirectory)\..\BuildTools\UpdateAssemblyInfo\bin\Debug" Command="UpdateAssemblyInfo.exe --branchname $(BranchName)" Timeout="60000" Condition=" '$(BranchName)' != '' " />
<Exec WorkingDirectory="$(MSBuildProjectDirectory)\..\BuildTools\UpdateAssemblyInfo\bin\Debug" Command="UpdateAssemblyInfo.exe" Timeout="60000" Condition=" '$(BranchName)' == '' " />
</Target>
>>>>>>> 758f18c73f2667591014666e73ee139fe449c022
</Project>

27
ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs

@ -57,7 +57,17 @@ namespace Decompiler @@ -57,7 +57,17 @@ namespace Decompiler
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("{0}:{1} {2} {3}", this.Name, this.Label != null ? " *" : "", this.Code.GetName(), this.Operand);
sb.AppendFormat("{0}:{1} {2} ", this.Name, this.Label != null ? " *" : "", this.Code.GetName());
if (this.Operand is ILLabel) {
sb.Append(((ILLabel)this.Operand).Name);
} else if (this.Operand is ILLabel[]) {
foreach(ILLabel label in (ILLabel[])this.Operand) {
sb.Append(label.Name);
sb.Append(" ");
}
} else {
sb.Append(this.Operand.ToString());
}
if (this.StackBefore != null) {
sb.Append(" StackBefore = {");
bool first = true;
@ -234,6 +244,9 @@ namespace Decompiler @@ -234,6 +244,9 @@ namespace Decompiler
// Genertate temporary variables to replace stack
foreach(ByteCode byteCode in body) {
if (byteCode.StackBefore == null)
continue;
int argIdx = 0;
int popCount = byteCode.PopCount ?? byteCode.StackBefore.Count;
for (int i = byteCode.StackBefore.Count - popCount; i < byteCode.StackBefore.Count; i++) {
@ -395,8 +408,18 @@ namespace Decompiler @@ -395,8 +408,18 @@ namespace Decompiler
// Convert stack-based IL code to ILAst tree
foreach(ByteCode byteCode in body) {
ILRange ilRange = new ILRange() { From = byteCode.Offset, To = byteCode.EndOffset };
if (byteCode.StackBefore == null) {
ast.Add(new ILComment() {
Text = "Unreachable code: " + byteCode.Code.GetName(),
ILRanges = new List<ILRange>(new[] { ilRange })
});
continue;
}
ILExpression expr = new ILExpression(byteCode.Code, byteCode.Operand);
expr.ILRanges.Add(new ILRange() { From = byteCode.Offset, To = byteCode.EndOffset });
expr.ILRanges.Add(ilRange);
// Label for this instruction
if (byteCode.Label != null) {

15
ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

@ -225,10 +225,15 @@ namespace Decompiler.ControlFlow @@ -225,10 +225,15 @@ namespace Decompiler.ControlFlow
{
List<ILNode> result = new List<ILNode>();
Queue<ControlFlowNode> agenda = new Queue<ControlFlowNode>();
agenda.Enqueue(entryNode);
while(agenda.Count > 0) {
ControlFlowNode node = agenda.Dequeue();
HashSet<ControlFlowNode> agenda = new HashSet<ControlFlowNode>();
agenda.Add(entryNode);
while(agenda.Any()) {
ControlFlowNode node = agenda.First();
// Attempt for a good order
while(agenda.Contains(node.ImmediateDominator)) {
node = node.ImmediateDominator;
}
agenda.Remove(node);
// Find a block that represents a simple condition
if (nodes.Contains(node)) {
@ -346,7 +351,7 @@ namespace Decompiler.ControlFlow @@ -346,7 +351,7 @@ namespace Decompiler.ControlFlow
// Using the dominator tree should ensure we find the the widest loop first
foreach(var child in node.DominatorTreeChildren) {
agenda.Enqueue(child);
agenda.Add(child);
}
}

11
ICSharpCode.Decompiler/ILAst/ILAstTypes.cs

@ -83,6 +83,17 @@ namespace Decompiler @@ -83,6 +83,17 @@ namespace Decompiler
}
}
public class ILComment: ILNode
{
public string Text;
public List<ILRange> ILRanges { get; set; }
public override void WriteTo(ITextOutput output)
{
output.WriteLine("// " + this.Text);
}
}
public class ILTryCatchBlock: ILNode
{
public class CatchBlock: ILBlock

1
ICSharpCode.Decompiler/ITextOutput.cs

@ -17,6 +17,7 @@ @@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE.
using System;
using System.IO;
namespace ICSharpCode.Decompiler
{

55
ICSharpCode.Decompiler/TextOutputWriter.cs

@ -0,0 +1,55 @@ @@ -0,0 +1,55 @@
// 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.IO;
using System.Text;
namespace ICSharpCode.Decompiler
{
public class TextOutputWriter : TextWriter
{
readonly ITextOutput output;
public TextOutputWriter(ITextOutput output)
{
if (output == null)
throw new ArgumentNullException("output");
this.output = output;
}
public override Encoding Encoding {
get { return Encoding.UTF8; }
}
public override void Write(char value)
{
output.Write(value);
}
public override void Write(string value)
{
output.Write(value);
}
public override void WriteLine()
{
output.WriteLine();
}
}
}

173
ILSpy/CSharpLanguage.cs

@ -21,6 +21,8 @@ using System.Collections.Generic; @@ -21,6 +21,8 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using Decompiler;
using Decompiler.Transforms;
using ICSharpCode.Decompiler;
@ -70,6 +72,10 @@ namespace ICSharpCode.ILSpy @@ -70,6 +72,10 @@ namespace ICSharpCode.ILSpy
get { return ".cs"; }
}
public override string ProjectFileExtension {
get { return ".csproj"; }
}
public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options)
{
AstBuilder codeDomBuilder = CreateAstBuilder(options, method.DeclaringType);
@ -108,17 +114,174 @@ namespace ICSharpCode.ILSpy @@ -108,17 +114,174 @@ namespace ICSharpCode.ILSpy
public override void DecompileAssembly(AssemblyDefinition assembly, string fileName, ITextOutput output, DecompilationOptions options)
{
if (options.FullDecompilation) {
foreach (TypeDefinition type in assembly.MainModule.Types) {
AstBuilder codeDomBuilder = CreateAstBuilder(options, type);
codeDomBuilder.AddType(type);
codeDomBuilder.GenerateCode(output, transformAbortCondition);
output.WriteLine();
if (options.SaveAsProjectDirectory != null) {
var files = WriteFilesInProject(assembly, options);
WriteProjectFile(new TextOutputWriter(output), files, assembly.MainModule);
} else {
foreach (TypeDefinition type in assembly.MainModule.Types) {
AstBuilder codeDomBuilder = CreateAstBuilder(options, type);
codeDomBuilder.AddType(type);
codeDomBuilder.GenerateCode(output, transformAbortCondition);
output.WriteLine();
}
}
} else {
base.DecompileAssembly(assembly, fileName, output, options);
}
}
void WriteProjectFile(TextWriter writer, IEnumerable<string> files, ModuleDefinition module)
{
const string ns = "http://schemas.microsoft.com/developer/msbuild/2003";
string platformName;
switch (module.Architecture) {
case TargetArchitecture.I386:
if ((module.Attributes & ModuleAttributes.Required32Bit) == ModuleAttributes.Required32Bit)
platformName = "x86";
else
platformName = "AnyCPU";
break;
case TargetArchitecture.AMD64:
platformName = "x64";
break;
case TargetArchitecture.IA64:
platformName = "Itanium";
break;
default:
throw new NotSupportedException("Invalid value for TargetArchitecture");
}
using (XmlTextWriter w = new XmlTextWriter(writer)) {
w.Formatting = Formatting.Indented;
w.WriteStartDocument();
w.WriteStartElement("Project", ns);
w.WriteAttributeString("ToolsVersion", "4.0");
w.WriteAttributeString("DefaultTargets", "Build");
w.WriteStartElement("PropertyGroup");
w.WriteElementString("ProjectGuid", Guid.NewGuid().ToString().ToUpperInvariant());
w.WriteStartElement("Configuration");
w.WriteAttributeString("Condition", " '$(Configuration)' == '' ");
w.WriteValue("Debug");
w.WriteEndElement(); // </Configuration>
w.WriteStartElement("Platform");
w.WriteAttributeString("Condition", " '$(Platform)' == '' ");
w.WriteValue(platformName);
w.WriteEndElement(); // </Platform>
switch (module.Kind) {
case ModuleKind.Windows:
w.WriteElementString("OutputType", "WinExe");
break;
case ModuleKind.Console:
w.WriteElementString("OutputType", "Exe");
break;
default:
w.WriteElementString("OutputType", "Library");
break;
}
w.WriteElementString("AssemblyName", module.Assembly.Name.Name);
switch (module.Runtime) {
case TargetRuntime.Net_1_0:
w.WriteElementString("TargetFrameworkVersion", "v1.0");
break;
case TargetRuntime.Net_1_1:
w.WriteElementString("TargetFrameworkVersion", "v1.1");
break;
case TargetRuntime.Net_2_0:
w.WriteElementString("TargetFrameworkVersion", "v2.0");
// TODO: Detect when .NET 3.0/3.5 is required
break;
default:
w.WriteElementString("TargetFrameworkVersion", "v4.0");
// TODO: Detect TargetFrameworkProfile
break;
}
w.WriteElementString("WarningLevel", "4");
w.WriteEndElement(); // </PropertyGroup>
w.WriteStartElement("PropertyGroup"); // platform-specific
w.WriteAttributeString("Condition", " '$(Platform)' == '" + platformName + "' ");
w.WriteElementString("PlatformTarget", platformName);
w.WriteEndElement(); // </PropertyGroup> (platform-specific)
w.WriteStartElement("PropertyGroup"); // Debug
w.WriteAttributeString("Condition", " '$(Configuration)' == 'Debug' ");
w.WriteElementString("OutputPath", "bin\\Debug\\");
w.WriteElementString("DebugSymbols", "true");
w.WriteElementString("DebugType", "full");
w.WriteElementString("Optimize", "false");
w.WriteEndElement(); // </PropertyGroup> (Debug)
w.WriteStartElement("PropertyGroup"); // Release
w.WriteAttributeString("Condition", " '$(Configuration)' == 'Release' ");
w.WriteElementString("OutputPath", "bin\\Release\\");
w.WriteElementString("DebugSymbols", "true");
w.WriteElementString("DebugType", "pdbonly");
w.WriteElementString("Optimize", "true");
w.WriteEndElement(); // </PropertyGroup> (Release)
w.WriteStartElement("ItemGroup"); // References
foreach (AssemblyNameReference r in module.AssemblyReferences) {
if (r.Name != "mscorlib") {
w.WriteStartElement("Reference");
w.WriteAttributeString("Include", r.Name);
// TODO: RequiredTargetFramework
w.WriteEndElement();
}
}
w.WriteEndElement(); // </ItemGroup> (References)
w.WriteStartElement("ItemGroup"); // Code
foreach (string file in files.OrderBy(f => f, StringComparer.OrdinalIgnoreCase)) {
w.WriteStartElement("Compile");
w.WriteAttributeString("Include", file);
w.WriteEndElement();
}
w.WriteEndElement();
w.WriteStartElement("Import");
w.WriteAttributeString("Project", "$(MSBuildToolsPath)\\Microsoft.CSharp.targets");
w.WriteEndElement();
w.WriteEndDocument();
}
}
IEnumerable<string> WriteFilesInProject(AssemblyDefinition assembly, DecompilationOptions options)
{
var files = assembly.MainModule.Types.Where(t => t.Name != "<Module>").GroupBy(
delegate (TypeDefinition type) {
string file = TextView.DecompilerTextView.CleanUpName(type.Name) + this.FileExtension;
if (string.IsNullOrEmpty(type.Namespace)) {
return file;
} else {
string dir = TextView.DecompilerTextView.CleanUpName(type.Namespace);
Directory.CreateDirectory(Path.Combine(options.SaveAsProjectDirectory, dir));
return Path.Combine(dir, file);
}
}, StringComparer.OrdinalIgnoreCase).ToList();
AstMethodBodyBuilder.ClearUnhandledOpcodes();
Parallel.ForEach(
files,
new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount },
delegate (IGrouping<string, TypeDefinition> file) {
using (StreamWriter w = new StreamWriter(Path.Combine(options.SaveAsProjectDirectory, file.Key))) {
AstBuilder codeDomBuilder = CreateAstBuilder(options, null);
foreach (TypeDefinition type in file)
codeDomBuilder.AddType(type);
codeDomBuilder.GenerateCode(new PlainTextOutput(w), transformAbortCondition);
}
});
AstMethodBodyBuilder.PrintNumberOfUnhandledOpcodes();
return files.Select(f => f.Key);
}
AstBuilder CreateAstBuilder(DecompilationOptions options, TypeDefinition currentType)
{
return new AstBuilder(

5
ILSpy/DecompilationOptions.cs

@ -32,6 +32,11 @@ namespace ICSharpCode.ILSpy @@ -32,6 +32,11 @@ namespace ICSharpCode.ILSpy
/// </summary>
public bool FullDecompilation { get; set; }
/// <summary>
/// Gets/Sets the directory into which the project is saved.
/// </summary>
public string SaveAsProjectDirectory { get; set; }
/// <summary>
/// Gets the cancellation token that is used to abort the decompiler.
/// </summary>

4
ILSpy/Language.cs

@ -40,6 +40,10 @@ namespace ICSharpCode.ILSpy @@ -40,6 +40,10 @@ namespace ICSharpCode.ILSpy
/// </summary>
public abstract string FileExtension { get; }
public virtual string ProjectFileExtension {
get { return null; }
}
/// <summary>
/// Gets the syntax highlighting used for this language.
/// </summary>

65
ILSpy/MainWindow.xaml.cs

@ -74,9 +74,6 @@ namespace ICSharpCode.ILSpy @@ -74,9 +74,6 @@ namespace ICSharpCode.ILSpy
}
sessionSettings.FilterSettings.PropertyChanged += filterSettings_PropertyChanged;
#if DEBUG
AddDebugItemsToToolbar();
#endif
this.Loaded += new RoutedEventHandler(MainWindow_Loaded);
}
@ -256,66 +253,6 @@ namespace ICSharpCode.ILSpy @@ -256,66 +253,6 @@ namespace ICSharpCode.ILSpy
}
#endregion
#region Debugging CFG
#if DEBUG
void AddDebugItemsToToolbar()
{
toolBar.Items.Add(new Separator());
Button cfg = new Button() { Content = "CFG" };
cfg.Click += new RoutedEventHandler(cfg_Click);
toolBar.Items.Add(cfg);
Button ssa = new Button() { Content = "SSA" };
ssa.Click += new RoutedEventHandler(ssa_Click);
toolBar.Items.Add(ssa);
Button varGraph = new Button() { Content = "Var" };
varGraph.Click += new RoutedEventHandler(varGraph_Click);
toolBar.Items.Add(varGraph);
}
void cfg_Click(object sender, RoutedEventArgs e)
{
MethodTreeNode node = treeView.SelectedItem as MethodTreeNode;
if (node != null && node.MethodDefinition.HasBody) {
var cfg = ControlFlowGraphBuilder.Build(node.MethodDefinition.Body);
cfg.ComputeDominance();
cfg.ComputeDominanceFrontier();
ShowGraph(node.MethodDefinition.Name + "-cfg", cfg.ExportGraph());
}
}
void ssa_Click(object sender, RoutedEventArgs e)
{
MethodTreeNode node = treeView.SelectedItem as MethodTreeNode;
if (node != null && node.MethodDefinition.HasBody) {
node.MethodDefinition.Body.SimplifyMacros();
ShowGraph(node.MethodDefinition.Name + "-ssa", SsaFormBuilder.Build(node.MethodDefinition).ExportBlockGraph());
}
}
void varGraph_Click(object sender, RoutedEventArgs e)
{
MethodTreeNode node = treeView.SelectedItem as MethodTreeNode;
if (node != null && node.MethodDefinition.HasBody) {
node.MethodDefinition.Body.SimplifyMacros();
ShowGraph(node.MethodDefinition.Name + "-var", SsaFormBuilder.Build(node.MethodDefinition).ExportVariableGraph());
}
}
void ShowGraph(string name, GraphVizGraph graph)
{
foreach (char c in Path.GetInvalidFileNameChars())
name = name.Replace(c, '-');
string fileName = Path.Combine(Path.GetTempPath(), name);
graph.Save(fileName + ".gv");
Process.Start("dot", "\"" + fileName + ".gv\" -Tpng -o \"" + fileName + ".png\"").WaitForExit();
Process.Start(fileName + ".png");
}
#endif
#endregion
#region Open/Refresh
void OpenCommandExecuted(object sender, ExecutedRoutedEventArgs e)
{
@ -477,7 +414,7 @@ namespace ICSharpCode.ILSpy @@ -477,7 +414,7 @@ namespace ICSharpCode.ILSpy
{
if (treeView.SelectedItems.Count == 1) {
ILSpyTreeNode node = treeView.SelectedItem as ILSpyTreeNode;
if (node != null && node.Save())
if (node != null && node.Save(decompilerTextView))
return;
}
decompilerTextView.SaveToDisk(sessionSettings.FilterSettings.Language,

13
ILSpy/TextView/DecompilerTextView.cs

@ -403,6 +403,11 @@ namespace ICSharpCode.ILSpy.TextView @@ -403,6 +403,11 @@ namespace ICSharpCode.ILSpy.TextView
}
}
public void SaveToDisk(ILSpy.Language language, IEnumerable<ILSpyTreeNode> treeNodes, DecompilationOptions options, string fileName)
{
SaveToDisk(new DecompilationContext(language, treeNodes.ToArray(), options), fileName);
}
/// <summary>
/// Starts the decompilation of the given nodes.
/// The result will be saved to the given file name.
@ -438,6 +443,8 @@ namespace ICSharpCode.ILSpy.TextView @@ -438,6 +443,8 @@ namespace ICSharpCode.ILSpy.TextView
Thread thread = new Thread(new ThreadStart(
delegate {
try {
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
using (StreamWriter w = new StreamWriter(fileName)) {
try {
DecompileNodes(context, new PlainTextOutput(w));
@ -447,8 +454,9 @@ namespace ICSharpCode.ILSpy.TextView @@ -447,8 +454,9 @@ namespace ICSharpCode.ILSpy.TextView
throw;
}
}
stopwatch.Stop();
AvalonEditTextOutput output = new AvalonEditTextOutput();
output.WriteLine("Decompilation complete.");
output.WriteLine("Decompilation complete in " + stopwatch.Elapsed.TotalSeconds.ToString("F1") + " seconds.");
output.WriteLine();
output.AddButton(null, "Open Explorer", delegate { Process.Start("explorer", "/select,\"" + fileName + "\""); });
output.WriteLine();
@ -474,6 +482,9 @@ namespace ICSharpCode.ILSpy.TextView @@ -474,6 +482,9 @@ namespace ICSharpCode.ILSpy.TextView
internal static string CleanUpName(string text)
{
int pos = text.IndexOf(':');
if (pos > 0)
text = text.Substring(0, pos);
pos = text.IndexOf('`');
if (pos > 0)
text = text.Substring(0, pos);
text = text.Trim();

33
ILSpy/TreeNodes/AssemblyTreeNode.cs

@ -27,7 +27,9 @@ using System.Windows; @@ -27,7 +27,9 @@ using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;
using ICSharpCode.Decompiler;
using ICSharpCode.ILSpy.TextView;
using ICSharpCode.TreeView;
using Microsoft.Win32;
using Mono.Cecil;
namespace ICSharpCode.ILSpy.TreeNodes
@ -201,5 +203,36 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -201,5 +203,36 @@ namespace ICSharpCode.ILSpy.TreeNodes
assembly.WaitUntilLoaded(); // necessary so that load errors are passed on to the caller
language.DecompileAssembly(assembly.AssemblyDefinition, assembly.FileName, output, options);
}
public override bool Save(DecompilerTextView textView)
{
Language language = this.Language;
if (string.IsNullOrEmpty(language.ProjectFileExtension))
return false;
SaveFileDialog dlg = new SaveFileDialog();
dlg.FileName = DecompilerTextView.CleanUpName(assembly.ShortName);
dlg.Filter = language.Name + " project|*" + language.ProjectFileExtension + "|" + language.Name + " single file|*" + language.FileExtension + "|All files|*.*";
if (dlg.ShowDialog() == true) {
DecompilationOptions options = new DecompilationOptions();
options.FullDecompilation = true;
if (dlg.FilterIndex == 1) {
options.SaveAsProjectDirectory = Path.GetDirectoryName(dlg.FileName);
foreach (string entry in Directory.GetFileSystemEntries(options.SaveAsProjectDirectory)) {
if (!string.Equals(entry, dlg.FileName, StringComparison.OrdinalIgnoreCase)) {
var result = MessageBox.Show(
"The directory is not empty. File will be overwritten." + Environment.NewLine +
"Are you sure you want to continue?",
"Project Directory not empty",
MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No);
if (result == MessageBoxResult.No)
return true; // don't save, but mark the Save operation as handled
break;
}
}
}
textView.SaveToDisk(language, new[]{this}, options, dlg.FileName);
}
return true;
}
}
}

2
ILSpy/TreeNodes/ILSpyTreeNode.cs

@ -79,7 +79,7 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -79,7 +79,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
/// This method is called on the main thread when only a single item is selected.
/// If it returns false, normal decompilation is used to save the item.
/// </summary>
public virtual bool Save()
public virtual bool Save(TextView.DecompilerTextView textView)
{
return false;
}

4
ILSpy/TreeNodes/ResourceEntryNode.cs

@ -75,7 +75,7 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -75,7 +75,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
image.EndInit();
output.AddUIElement(() => new Image { Source = image });
output.WriteLine();
output.AddButton(Images.Save, "Save", delegate { Save(); });
output.AddButton(Images.Save, "Save", delegate { Save(null); });
} catch (Exception) {
return false;
}
@ -106,7 +106,7 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -106,7 +106,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
return true;
}
public override bool Save()
public override bool Save(DecompilerTextView textView)
{
SaveFileDialog dlg = new SaveFileDialog();
dlg.FileName = Path.GetFileName(DecompilerTextView.CleanUpName(key));

4
ILSpy/TreeNodes/ResourceListTreeNode.cs

@ -102,7 +102,7 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -102,7 +102,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
ISmartTextOutput smartOutput = output as ISmartTextOutput;
if (smartOutput != null && r is EmbeddedResource) {
smartOutput.AddButton(Images.Save, "Save", delegate { Save(); });
smartOutput.AddButton(Images.Save, "Save", delegate { Save(null); });
output.WriteLine();
}
}
@ -132,7 +132,7 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -132,7 +132,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
return false;
}
public override bool Save()
public override bool Save(TextView.DecompilerTextView textView)
{
EmbeddedResource er = r as EmbeddedResource;
if (er != null) {

2
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Backreference.cs

@ -22,7 +22,7 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching @@ -22,7 +22,7 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching
protected internal override bool DoMatch(AstNode other, Match match)
{
return match[referencedGroupName].Last().Match(other) != null;
return match.Get(referencedGroupName).Last().Match(other) != null;
}
}
}

18
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Choice.cs

@ -2,20 +2,25 @@ @@ -2,20 +2,25 @@
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System;
using System.Collections;
namespace ICSharpCode.NRefactory.CSharp.PatternMatching
{
/// <summary>
/// Matches one of several alternatives.
/// </summary>
public class Choice : Pattern
public class Choice : Pattern, IEnumerable
{
public static readonly Role<AstNode> AlternativeRole = new Role<AstNode>("Alternative", AstNode.Null);
public Choice(params AstNode[] alternatives)
public void Add(string name, AstNode alternative)
{
foreach (AstNode node in alternatives)
AddChild(node, AlternativeRole);
AddChild(new NamedNode(name, alternative), AlternativeRole);
}
public void Add(AstNode alternative)
{
AddChild(alternative, AlternativeRole);
}
protected internal override bool DoMatch(AstNode other, Match match)
@ -29,5 +34,10 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching @@ -29,5 +34,10 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching
}
return false;
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetChildrenByRole(AlternativeRole).GetEnumerator();
}
}
}

28
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Match.cs

@ -24,13 +24,29 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching @@ -24,13 +24,29 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching
results.RemoveRange(checkPoint, results.Count - checkPoint);
}
public IEnumerable<AstNode> this[string groupName] {
get {
foreach (var pair in results) {
if (pair.Key == groupName)
yield return pair.Value;
}
public IEnumerable<AstNode> Get(string groupName)
{
foreach (var pair in results) {
if (pair.Key == groupName)
yield return pair.Value;
}
}
public IEnumerable<T> Get<T>(string groupName) where T : AstNode
{
foreach (var pair in results) {
if (pair.Key == groupName)
yield return (T)pair.Value;
}
}
public bool Has(string groupName)
{
foreach (var pair in results) {
if (pair.Key == groupName)
return true;
}
return false;
}
public void Add(string groupName, AstNode node)

5
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Pattern.cs

@ -29,6 +29,11 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching @@ -29,6 +29,11 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching
return new ExpressionPlaceholder(this);
}
public Statement ToStatement()
{
return new StatementPlaceholder(this);
}
public BlockStatement ToBlock()
{
return new BlockStatementPlaceholder(this);

52
NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Placeholder.cs

@ -7,113 +7,113 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching @@ -7,113 +7,113 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching
{
sealed class TypePlaceholder : AstType
{
public static readonly Role<Pattern> PatternRole = new Role<Pattern>("Pattern");
public static readonly Role<AstNode> ChildRole = new Role<AstNode>("Child", AstNode.Null);
public TypePlaceholder(Pattern pattern)
public TypePlaceholder(AstNode child)
{
AddChild(pattern, TypePlaceholder.PatternRole);
AddChild(child, TypePlaceholder.ChildRole);
}
public override NodeType NodeType {
get { return NodeType.Pattern; }
get { return GetChildByRole(TypePlaceholder.ChildRole).NodeType; }
}
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data)
{
return default(S);
return GetChildByRole(TypePlaceholder.ChildRole).AcceptVisitor(visitor, data);
}
protected internal override bool DoMatch(AstNode other, Match match)
{
return GetChildByRole(TypePlaceholder.PatternRole).DoMatch(other, match);
return GetChildByRole(TypePlaceholder.ChildRole).DoMatch(other, match);
}
}
sealed class ExpressionPlaceholder : Expression
{
public ExpressionPlaceholder(Pattern pattern)
public ExpressionPlaceholder(AstNode child)
{
AddChild(pattern, TypePlaceholder.PatternRole);
AddChild(child, TypePlaceholder.ChildRole);
}
public override NodeType NodeType {
get { return NodeType.Pattern; }
get { return GetChildByRole(TypePlaceholder.ChildRole).NodeType; }
}
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data)
{
return default(S);
return GetChildByRole(TypePlaceholder.ChildRole).AcceptVisitor(visitor, data);
}
protected internal override bool DoMatch(AstNode other, Match match)
{
return GetChildByRole(TypePlaceholder.PatternRole).DoMatch(other, match);
return GetChildByRole(TypePlaceholder.ChildRole).DoMatch(other, match);
}
}
sealed class StatementPlaceholder : Statement
{
public StatementPlaceholder(Pattern pattern)
public StatementPlaceholder(AstNode child)
{
AddChild(pattern, TypePlaceholder.PatternRole);
AddChild(child, TypePlaceholder.ChildRole);
}
public override NodeType NodeType {
get { return NodeType.Pattern; }
get { return GetChildByRole(TypePlaceholder.ChildRole).NodeType; }
}
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data)
{
return default(S);
return GetChildByRole(TypePlaceholder.ChildRole).AcceptVisitor(visitor, data);
}
protected internal override bool DoMatch(AstNode other, Match match)
{
return GetChildByRole(TypePlaceholder.PatternRole).DoMatch(other, match);
return GetChildByRole(TypePlaceholder.ChildRole).DoMatch(other, match);
}
}
sealed class BlockStatementPlaceholder : BlockStatement
{
public BlockStatementPlaceholder(Pattern pattern)
public BlockStatementPlaceholder(AstNode child)
{
AddChild(pattern, TypePlaceholder.PatternRole);
AddChild(child, TypePlaceholder.ChildRole);
}
public override NodeType NodeType {
get { return NodeType.Pattern; }
get { return GetChildByRole(TypePlaceholder.ChildRole).NodeType; }
}
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data)
{
return default(S);
return GetChildByRole(TypePlaceholder.ChildRole).AcceptVisitor(visitor, data);
}
protected internal override bool DoMatch(AstNode other, Match match)
{
return GetChildByRole(TypePlaceholder.PatternRole).DoMatch(other, match);
return GetChildByRole(TypePlaceholder.ChildRole).DoMatch(other, match);
}
}
sealed class VariablePlaceholder : VariableInitializer
{
public VariablePlaceholder(Pattern pattern)
public VariablePlaceholder(AstNode child)
{
AddChild(pattern, TypePlaceholder.PatternRole);
AddChild(child, TypePlaceholder.ChildRole);
}
public override NodeType NodeType {
get { return NodeType.Pattern; }
get { return GetChildByRole(TypePlaceholder.ChildRole).NodeType; }
}
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data)
{
return default(S);
return GetChildByRole(TypePlaceholder.ChildRole).AcceptVisitor(visitor, data);
}
protected internal override bool DoMatch(AstNode other, Match match)
{
return GetChildByRole(TypePlaceholder.PatternRole).DoMatch(other, match);
return GetChildByRole(TypePlaceholder.ChildRole).DoMatch(other, match);
}
}
}

3
NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs

@ -1689,6 +1689,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -1689,6 +1689,7 @@ namespace ICSharpCode.NRefactory.CSharp
WriteModifiers(eventDeclaration.ModifierTokens);
WriteKeyword("event");
eventDeclaration.ReturnType.AcceptVisitor(this, data);
Space();
WriteCommaSeparatedList(eventDeclaration.Variables);
Semicolon();
return EndNode(eventDeclaration);
@ -1700,6 +1701,8 @@ namespace ICSharpCode.NRefactory.CSharp @@ -1700,6 +1701,8 @@ namespace ICSharpCode.NRefactory.CSharp
WriteAttributes(customEventDeclaration.Attributes);
WriteModifiers(customEventDeclaration.ModifierTokens);
WriteKeyword("event");
customEventDeclaration.ReturnType.AcceptVisitor(this, data);
Space();
WritePrivateImplementationType(customEventDeclaration.PrivateImplementationType);
WriteIdentifier(customEventDeclaration.Name);
OpenBrace(policy.EventBraceStyle);

Loading…
Cancel
Save