Browse Source

Fix ConvertConstructorCallIntoInitializer transform.

pull/728/head
Daniel Grunwald 11 years ago
parent
commit
7e9f6bb9d6
  1. 10
      ICSharpCode.Decompiler/CSharp/Annotations.cs
  2. 75
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
  3. 4
      ICSharpCode.Decompiler/CSharp/Transforms/AddCheckedBlocks.cs
  4. 42
      ICSharpCode.Decompiler/CSharp/Transforms/ConvertConstructorCallIntoInitializer.cs
  5. 15
      ICSharpCode.Decompiler/CSharp/Transforms/IAstTransform.cs
  6. 2
      ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUnsafeModifier.cs
  7. 2
      ICSharpCode.Decompiler/CSharp/Transforms/ReplaceMethodCallsWithOperators.cs
  8. 47
      ICSharpCode.Decompiler/CSharp/Transforms/TransformationPipeline.cs
  9. 1
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  10. 4
      ICSharpCode.Decompiler/Tests/Helpers/Tester.cs
  11. 13
      ICSharpCode.Decompiler/Tests/TestRunner.cs

10
ICSharpCode.Decompiler/CSharp/Annotations.cs

@ -11,6 +11,7 @@ using System.Collections; @@ -11,6 +11,7 @@ using System.Collections;
using System.Collections.Generic;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.Decompiler.IL;
namespace ICSharpCode.Decompiler.CSharp
@ -72,5 +73,14 @@ namespace ICSharpCode.Decompiler.CSharp @@ -72,5 +73,14 @@ namespace ICSharpCode.Decompiler.CSharp
expression.Expression.AddAnnotation(resolveResult);
return new ConvertedExpression(expression, resolveResult);
}
/// <summary>
/// Retrieves the symbol associated with this AstNode, or null if no symbol is associated with the node.
/// </summary>
public static ISymbol GetSymbol(this AstNode node)
{
var rr = node.Annotation<ResolveResult>();
return rr != null ? rr.GetSymbol() : null;
}
}
}

75
ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

@ -16,20 +16,20 @@ @@ -16,20 +16,20 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using ICSharpCode.Decompiler.CSharp.Transforms;
using ICSharpCode.Decompiler.IL;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.Refactoring;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
using ICSharpCode.NRefactory.Utils;
using Mono.Cecil;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.Refactoring;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
using ICSharpCode.NRefactory.Utils;
using Mono.Cecil;
using ICSharpCode.Decompiler.CSharp.Transforms;
using ICSharpCode.Decompiler.IL;
namespace ICSharpCode.Decompiler.CSharp
{
@ -40,7 +40,22 @@ namespace ICSharpCode.Decompiler.CSharp @@ -40,7 +40,22 @@ namespace ICSharpCode.Decompiler.CSharp
NRefactoryCecilMapper cecilMapper;
ICompilation compilation;
TypeSystemAstBuilder typeSystemAstBuilder;
List<IAstTransform> astTransforms = new List<IAstTransform>(TransformationPipeline.CreatePipeline());
List<IAstTransform> astTransforms = new List<IAstTransform> {
//new PushNegation(),
//new DelegateConstruction(context),
//new PatternStatementTransform(context),
new ReplaceMethodCallsWithOperators(),
new IntroduceUnsafeModifier(),
new AddCheckedBlocks(),
//new DeclareVariables(context), // should run after most transforms that modify statements
new ConvertConstructorCallIntoInitializer(), // must run after DeclareVariables
//new DecimalConstantTransform(),
//new IntroduceUsingDeclarations(context),
//new IntroduceExtensionMethods(context), // must run after IntroduceUsingDeclarations
//new IntroduceQueryExpressions(context), // must run after IntroduceExtensionMethods
//new CombineQueryExpressions(context),
//new FlattenSwitchBlocks(),
};
public CancellationToken CancellationToken { get; set; }
@ -84,6 +99,14 @@ namespace ICSharpCode.Decompiler.CSharp @@ -84,6 +99,14 @@ namespace ICSharpCode.Decompiler.CSharp
return null;
}
void RunTransforms(AstNode rootNode)
{
var context = new TransformContext(compilation, cecilMapper);
foreach (var transform in astTransforms)
transform.Run(rootNode, context);
rootNode.AcceptVisitor(new InsertParenthesesVisitor { InsertParenthesesForReadability = true });
}
public SyntaxTree DecompileWholeModuleAsSingleFile()
{
SyntaxTree syntaxTree = new SyntaxTree();
@ -100,10 +123,11 @@ namespace ICSharpCode.Decompiler.CSharp @@ -100,10 +123,11 @@ namespace ICSharpCode.Decompiler.CSharp
foreach (var typeDef in g) {
if (typeDef.Name == "<Module>" && typeDef.Members.Count == 0)
continue;
var typeDecl = Decompile(typeDef);
var typeDecl = DoDecompile(typeDef);
groupNode.AddChild(typeDecl, SyntaxTree.MemberRole);
}
}
RunTransforms(syntaxTree);
return syntaxTree;
}
@ -114,24 +138,23 @@ namespace ICSharpCode.Decompiler.CSharp @@ -114,24 +138,23 @@ namespace ICSharpCode.Decompiler.CSharp
ITypeDefinition typeDef = cecilMapper.GetType(typeDefinition).GetDefinition();
if (typeDef == null)
throw new InvalidOperationException("Could not find type definition in NR type system");
return Decompile(typeDef);
var decl = DoDecompile(typeDef);
RunTransforms(decl);
return decl;
}
EntityDeclaration Decompile(ITypeDefinition typeDef)
EntityDeclaration DoDecompile(ITypeDefinition typeDef)
{
var entityDecl = typeSystemAstBuilder.ConvertEntity(typeDef);
var typeDecl = entityDecl as TypeDeclaration;
if (typeDecl == null)
{
if (typeDecl == null) {
// e.g. DelegateDeclaration
return entityDecl;
}
foreach (var method in typeDef.Methods)
{
foreach (var method in typeDef.Methods) {
var methodDef = cecilMapper.GetCecil(method) as MethodDefinition;
if (methodDef != null)
{
var memberDecl = Decompile(methodDef, method);
if (methodDef != null) {
var memberDecl = DoDecompile(methodDef, method);
typeDecl.Members.Add(memberDecl);
}
}
@ -145,10 +168,12 @@ namespace ICSharpCode.Decompiler.CSharp @@ -145,10 +168,12 @@ namespace ICSharpCode.Decompiler.CSharp
var method = cecilMapper.GetMethod(methodDefinition);
if (method == null)
throw new InvalidOperationException("Could not find method in NR type system");
return Decompile(methodDefinition, method);
var decl = DoDecompile(methodDefinition, method);
RunTransforms(decl);
return decl;
}
EntityDeclaration Decompile(MethodDefinition methodDefinition, IMethod method)
EntityDeclaration DoDecompile(MethodDefinition methodDefinition, IMethod method)
{
var entityDecl = typeSystemAstBuilder.ConvertEntity(method);
if (methodDefinition.HasBody) {
@ -159,9 +184,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -159,9 +184,7 @@ namespace ICSharpCode.Decompiler.CSharp
function.CheckInvariant();
var statementBuilder = new StatementBuilder(method, cecilMapper);
var body = statementBuilder.ConvertAsBlock(function.Body);
foreach (var transform in astTransforms) {
transform.Run(body);
}
// insert variables at start of body
Statement prevVarDecl = null;
foreach (var v in function.Variables) {
@ -172,9 +195,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -172,9 +195,7 @@ namespace ICSharpCode.Decompiler.CSharp
prevVarDecl = varDecl;
}
}
body.AcceptVisitor(new InsertParenthesesVisitor {
InsertParenthesesForReadability = true
});
entityDecl.AddChild(body, Roles.Body);
}
return entityDecl;

4
ICSharpCode.Decompiler/CSharp/Transforms/AddCheckedBlocks.cs

@ -234,12 +234,12 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -234,12 +234,12 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
}
#endregion
public void Run(AstNode node)
public void Run(AstNode node, TransformContext context)
{
BlockStatement block = node as BlockStatement;
if (block == null) {
for (AstNode child = node.FirstChild; child != null; child = child.NextSibling) {
Run(child);
Run(child, context);
}
} else {
Result r = GetResultFromBlock(block);

42
ICSharpCode.Decompiler/CSharp/Transforms/ConvertConstructorCallIntoInitializer.cs

@ -21,6 +21,8 @@ using System.Collections.Generic; @@ -21,6 +21,8 @@ using System.Collections.Generic;
using System.Linq;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.PatternMatching;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem;
using Mono.Cecil;
namespace ICSharpCode.Decompiler.CSharp.Transforms
@ -28,9 +30,9 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -28,9 +30,9 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
/// <summary>
/// If the first element of a constructor is a chained constructor call, convert it into a constructor initializer.
/// </summary>
public class ConvertConstructorCallIntoInitializer : DepthFirstAstVisitor<object, object>, IAstTransform
public class ConvertConstructorCallIntoInitializer : DepthFirstAstVisitor<TransformContext, object>, IAstTransform
{
public override object VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration, object data)
public override object VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration, TransformContext context)
{
ExpressionStatement stmt = constructorDeclaration.Body.Statements.FirstOrDefault() as ExpressionStatement;
if (stmt == null)
@ -60,7 +62,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -60,7 +62,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
static readonly ExpressionStatement fieldInitializerPattern = new ExpressionStatement {
Expression = new AssignmentExpression {
Left = new NamedNode("fieldAccess", new MemberReferenceExpression {
Left = new NamedNode("fieldAccess", new MemberReferenceExpression {
Target = new ThisReferenceExpression(),
MemberName = Pattern.AnyString
}),
@ -71,19 +73,20 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -71,19 +73,20 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
static readonly AstNode thisCallPattern = new ExpressionStatement(new ThisReferenceExpression().Invoke(".ctor", new Repeat(new AnyNode())));
public override object VisitTypeDeclaration(TypeDeclaration typeDeclaration, object data)
public override object VisitTypeDeclaration(TypeDeclaration typeDeclaration, TransformContext context)
{
// Handle initializers on instance fields
HandleInstanceFieldInitializers(typeDeclaration.Members);
// Now convert base constructor calls to initializers:
base.VisitTypeDeclaration(typeDeclaration, data);
base.VisitTypeDeclaration(typeDeclaration, context);
// Remove single empty constructor:
RemoveSingleEmptyConstructor(typeDeclaration);
// Handle initializers on static fields:
HandleStaticFieldInitializers(typeDeclaration.Members);
HandleStaticFieldInitializers(typeDeclaration.Members, context);
return null;
}
@ -92,8 +95,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -92,8 +95,8 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
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();
if (instanceCtorsNotChainingWithThis.Length > 0) {
MethodDefinition ctorMethodDef = instanceCtorsNotChainingWithThis[0].Annotation<MethodDefinition>();
if (ctorMethodDef != null && ctorMethodDef.DeclaringType.IsValueType)
var ctorMethodDef = instanceCtorsNotChainingWithThis[0].GetSymbol() as IMethod;
if (ctorMethodDef != null && ctorMethodDef.DeclaringType.IsReferenceType == false)
return;
// Recognize field initializers:
@ -104,10 +107,10 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -104,10 +107,10 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
if (!m.Success)
break;
FieldDefinition fieldDef = m.Get<AstNode>("fieldAccess").Single().Annotation<FieldReference>().ResolveWithinSameModule();
if (fieldDef == null)
IField field = m.Get<AstNode>("fieldAccess").Single().GetSymbol() as IField;
if (field == null)
break;
AstNode fieldOrEventDecl = members.FirstOrDefault(f => f.Annotation<FieldDefinition>() == fieldDef);
AstNode fieldOrEventDecl = members.FirstOrDefault(f => f.GetSymbol() == field);
if (fieldOrEventDecl == null)
break;
Expression initializer = m.Get<Expression>("initializer").Single();
@ -141,12 +144,13 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -141,12 +144,13 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
}
}
void HandleStaticFieldInitializers(IEnumerable<AstNode> members)
void HandleStaticFieldInitializers(IEnumerable<AstNode> members, TransformContext context)
{
// Convert static constructor into field initializers if the class is BeforeFieldInit
var staticCtor = members.OfType<ConstructorDeclaration>().FirstOrDefault(c => (c.Modifiers & Modifiers.Static) == Modifiers.Static);
if (staticCtor != null) {
MethodDefinition ctorMethodDef = staticCtor.Annotation<MethodDefinition>();
IMethod ctorMethod = staticCtor.GetSymbol() as IMethod;
MethodDefinition ctorMethodDef = context.CecilMapper.GetCecil(ctorMethod) as MethodDefinition;
if (ctorMethodDef != null && ctorMethodDef.DeclaringType.IsBeforeFieldInit) {
while (true) {
ExpressionStatement es = staticCtor.Body.Statements.FirstOrDefault() as ExpressionStatement;
@ -155,10 +159,10 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -155,10 +159,10 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
AssignmentExpression assignment = es.Expression as AssignmentExpression;
if (assignment == null || assignment.Operator != AssignmentOperatorType.Assign)
break;
FieldDefinition fieldDef = assignment.Left.Annotation<FieldReference>().ResolveWithinSameModule();
if (fieldDef == null || !fieldDef.IsStatic)
IField field = assignment.Left.GetSymbol() as IField;
if (field == null || !field.IsStatic)
break;
FieldDeclaration fieldDecl = members.OfType<FieldDeclaration>().FirstOrDefault(f => f.Annotation<FieldDefinition>() == fieldDef);
FieldDeclaration fieldDecl = members.OfType<FieldDeclaration>().FirstOrDefault(f => f.GetSymbol() == field);
if (fieldDecl == null)
break;
fieldDecl.Variables.Single().Initializer = assignment.Right.Detach();
@ -170,14 +174,14 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -170,14 +174,14 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
}
}
void IAstTransform.Run(AstNode node)
void IAstTransform.Run(AstNode node, TransformContext context)
{
// If we're viewing some set of members (fields are direct children of CompilationUnit),
// we also need to handle those:
HandleInstanceFieldInitializers(node.Children);
HandleStaticFieldInitializers(node.Children);
HandleStaticFieldInitializers(node.Children, context);
node.AcceptVisitor(this, null);
node.AcceptVisitor(this, context);
}
}
}

15
ICSharpCode.Decompiler/CSharp/Transforms/IAstTransform.cs

@ -19,11 +19,24 @@ @@ -19,11 +19,24 @@
using System;
using System.Threading;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.Decompiler.CSharp.Transforms
{
public interface IAstTransform
{
void Run(AstNode compilationUnit);
void Run(AstNode rootNode, TransformContext context);
}
public class TransformContext
{
internal readonly NRefactoryCecilMapper CecilMapper;
public readonly ICompilation Compilation;
internal TransformContext(ICompilation compilation, NRefactoryCecilMapper cecilMapper)
{
this.Compilation = compilation;
this.CecilMapper = cecilMapper;
}
}
}

2
ICSharpCode.Decompiler/CSharp/Transforms/IntroduceUnsafeModifier.cs

@ -27,7 +27,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -27,7 +27,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
sealed class PointerArithmetic {}
public void Run(AstNode compilationUnit)
public void Run(AstNode compilationUnit, TransformContext context)
{
compilationUnit.AcceptVisitor(this, null);
}

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

@ -348,7 +348,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -348,7 +348,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
return null;
}
void IAstTransform.Run(AstNode node)
void IAstTransform.Run(AstNode node, TransformContext context)
{
node.AcceptVisitor(this, null);
}

47
ICSharpCode.Decompiler/CSharp/Transforms/TransformationPipeline.cs

@ -1,47 +0,0 @@ @@ -1,47 +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.Threading;
using ICSharpCode.NRefactory.CSharp;
namespace ICSharpCode.Decompiler.CSharp.Transforms
{
public static class TransformationPipeline
{
public static IAstTransform[] CreatePipeline()
{
return new IAstTransform[] {
//new PushNegation(),
//new DelegateConstruction(context),
//new PatternStatementTransform(context),
new ReplaceMethodCallsWithOperators(),
new IntroduceUnsafeModifier(),
new AddCheckedBlocks(),
//new DeclareVariables(context), // should run after most transforms that modify statements
new ConvertConstructorCallIntoInitializer(), // must run after DeclareVariables
//new DecimalConstantTransform(),
//new IntroduceUsingDeclarations(context),
//new IntroduceExtensionMethods(context), // must run after IntroduceUsingDeclarations
//new IntroduceQueryExpressions(context), // must run after IntroduceExtensionMethods
//new CombineQueryExpressions(context),
//new FlattenSwitchBlocks(),
};
}
}
}

1
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -75,7 +75,6 @@ @@ -75,7 +75,6 @@
<Compile Include="CSharp\Transforms\IAstTransform.cs" />
<Compile Include="CSharp\Transforms\IntroduceUnsafeModifier.cs" />
<Compile Include="CSharp\Transforms\ReplaceMethodCallsWithOperators.cs" />
<Compile Include="CSharp\Transforms\TransformationPipeline.cs" />
<Compile Include="IL\Instructions.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>

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

@ -23,7 +23,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -23,7 +23,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
public static class Tester
{
public static string CompileCSharp(string sourceFileName, CompilerOptions flags = CompilerOptions.UseDebug)
public static CompilerResults CompileCSharp(string sourceFileName, CompilerOptions flags = CompilerOptions.UseDebug)
{
CSharpCodeProvider provider = new CSharpCodeProvider(new Dictionary<string, string> { { "CompilerVersion", "v4.0" } });
CompilerParameters options = new CompilerParameters();
@ -38,7 +38,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -38,7 +38,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
}
throw new Exception(b.ToString());
}
return results.PathToAssembly;
return results;
}
public static int Run(string assemblyFileName, out string output, out string error)

13
ICSharpCode.Decompiler/Tests/TestRunner.cs

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@ -49,24 +50,24 @@ namespace ICSharpCode.Decompiler.Tests @@ -49,24 +50,24 @@ namespace ICSharpCode.Decompiler.Tests
void TestCompileDecompileCompileOutput(string testFileName, CompilerOptions options = CompilerOptions.UseDebug)
{
string outputFile = null, decompiledOutputFile = null;
CompilerResults outputFile = null, decompiledOutputFile = null;
string output1, output2, error1, error2;
try {
outputFile = Tester.CompileCSharp(Path.Combine(TestCasePath, testFileName), options);
string decompiledCodeFile = Tester.DecompileCSharp(outputFile);
string decompiledCodeFile = Tester.DecompileCSharp(outputFile.PathToAssembly);
decompiledOutputFile = Tester.CompileCSharp(decompiledCodeFile, options);
int result1 = Tester.Run(outputFile, out output1, out error1);
int result2 = Tester.Run(decompiledOutputFile, out output2, out error2);
int result1 = Tester.Run(outputFile.PathToAssembly, out output1, out error1);
int result2 = Tester.Run(decompiledOutputFile.PathToAssembly, out output2, out error2);
Assert.AreEqual(result1, result2);
Assert.AreEqual(output1, output2);
Assert.AreEqual(error1, error2);
} finally {
if (outputFile != null)
File.Delete(outputFile);
outputFile.TempFiles.Delete();
if (decompiledOutputFile != null)
File.Delete(decompiledOutputFile);
decompiledOutputFile.TempFiles.Delete();
}
}
}

Loading…
Cancel
Save