From 1a5bead2f2e24cc16da23753eaf0882d38d54ea1 Mon Sep 17 00:00:00 2001 From: Stephane Delcroix Date: Mon, 5 Dec 2016 13:31:31 +0100 Subject: [XamlC] drop ICSharpCode.Decompiler (#586) * [XamlC] drop ICSharpCode.Decompiler * update nuspec * fix typo --- .nuspec/Xamarin.Forms.nuspec | 5 - ICSharpCode.Decompiler/Ast/Annotations.cs | 52 - ICSharpCode.Decompiler/Ast/AstBuilder.cs | 1687 -------------------- ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs | 1220 -------------- ICSharpCode.Decompiler/Ast/CommentStatement.cs | 69 - ICSharpCode.Decompiler/Ast/DecompilerContext.cs | 71 - ICSharpCode.Decompiler/Ast/NRefactoryExtensions.cs | 86 - ICSharpCode.Decompiler/Ast/NameVariables.cs | 347 ---- ICSharpCode.Decompiler/Ast/TextTokenWriter.cs | 369 ----- .../Ast/Transforms/AddCheckedBlocks.cs | 368 ----- .../Ast/Transforms/CombineQueryExpressions.cs | 179 --- .../Ast/Transforms/ContextTrackingVisitor.cs | 111 -- .../ConvertConstructorCallIntoInitializer.cs | 183 --- .../Ast/Transforms/CustomPatterns.cs | 109 -- .../Ast/Transforms/DecimalConstantTransform.cs | 58 - .../Ast/Transforms/DeclareVariables.cs | 368 ----- .../Ast/Transforms/DelegateConstruction.cs | 502 ------ .../Ast/Transforms/ExpressionTreeConverter.cs | 875 ---------- .../Ast/Transforms/FlattenSwitchBlocks.cs | 27 - .../Ast/Transforms/IntroduceExtensionMethods.cs | 66 - .../Ast/Transforms/IntroduceQueryExpressions.cs | 295 ---- .../Ast/Transforms/IntroduceUnsafeModifier.cs | 106 -- .../Ast/Transforms/IntroduceUsingDeclarations.cs | 359 ----- .../Ast/Transforms/PatternStatementTransform.cs | 1123 ------------- .../Ast/Transforms/PushNegation.cs | 164 -- .../Transforms/ReplaceMethodCallsWithOperators.cs | 356 ----- .../Ast/Transforms/TransformationPipeline.cs | 65 - .../Ast/TypesHierarchyHelpers.cs | 536 ------- ICSharpCode.Decompiler/CecilExtensions.cs | 374 ----- ICSharpCode.Decompiler/CodeMappings.cs | 57 - ICSharpCode.Decompiler/DecompilerException.cs | 42 - ICSharpCode.Decompiler/DecompilerSettings.cs | 356 ----- .../Disassembler/DisassemblerHelpers.cs | 447 ------ ICSharpCode.Decompiler/Disassembler/ILStructure.cs | 228 --- .../Disassembler/MethodBodyDisassembler.cs | 239 --- .../Disassembler/ReflectionDisassembler.cs | 1168 -------------- .../FlowAnalysis/ControlFlowEdge.cs | 78 - .../FlowAnalysis/ControlFlowGraph.cs | 191 --- .../FlowAnalysis/ControlFlowGraphBuilder.cs | 439 ----- .../FlowAnalysis/ControlFlowNode.cs | 305 ---- .../FlowAnalysis/ControlStructureDetector.cs | 241 --- ICSharpCode.Decompiler/FlowAnalysis/OpCodeInfo.cs | 312 ---- .../FlowAnalysis/SimplifyByRefCalls.cs | 174 -- ICSharpCode.Decompiler/FlowAnalysis/SsaBlock.cs | 60 - ICSharpCode.Decompiler/FlowAnalysis/SsaForm.cs | 162 -- .../FlowAnalysis/SsaFormBuilder.cs | 257 --- .../FlowAnalysis/SsaInstruction.cs | 191 --- .../FlowAnalysis/SsaOptimization.cs | 138 -- ICSharpCode.Decompiler/FlowAnalysis/SsaVariable.cs | 91 -- .../FlowAnalysis/TransformToSsa.cs | 254 --- .../ICSharpCode.Decompiler.csproj | 167 -- ICSharpCode.Decompiler/ICSharpCode.Decompiler.sln | 17 - ICSharpCode.Decompiler/ILAst/AsyncDecompiler.cs | 704 -------- ICSharpCode.Decompiler/ILAst/DefaultDictionary.cs | 128 -- ICSharpCode.Decompiler/ILAst/GotoRemoval.cs | 319 ---- ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs | 839 ---------- ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs | 988 ------------ ICSharpCode.Decompiler/ILAst/ILAstTypes.cs | 601 ------- ICSharpCode.Decompiler/ILAst/ILCodes.cs | 490 ------ ICSharpCode.Decompiler/ILAst/ILInlining.cs | 524 ------ .../ILAst/InitializerPeepholeTransforms.cs | 535 ------- ICSharpCode.Decompiler/ILAst/LiftedOperators.cs | 528 ------ ICSharpCode.Decompiler/ILAst/LoopsAndConditions.cs | 443 ----- ICSharpCode.Decompiler/ILAst/PatternMatching.cs | 177 -- ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs | 1103 ------------- ICSharpCode.Decompiler/ILAst/SimpleControlFlow.cs | 376 ----- ICSharpCode.Decompiler/ILAst/StateRange.cs | 312 ---- ICSharpCode.Decompiler/ILAst/SymbolicExecution.cs | 157 -- ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs | 1294 --------------- .../ILAst/YieldReturnDecompiler.cs | 635 -------- ICSharpCode.Decompiler/ITextOutput.cs | 62 - ICSharpCode.Decompiler/PlainTextOutput.cs | 122 -- .../Properties/AssemblyInfo.template.cs | 27 - .../ReferenceResolvingException.cs | 68 - ICSharpCode.Decompiler/Tests/Async.cs | 155 -- .../Tests/BooleanConsumedAsInteger.il | 59 - .../Tests/CallOverloadedMethod.cs | 52 - ICSharpCode.Decompiler/Tests/CheckedUnchecked.cs | 117 -- .../Tests/CodeSampleFileParser.cs | 133 -- ICSharpCode.Decompiler/Tests/ControlFlow.cs | 97 -- .../Tests/CustomAttributes.code.cs | 41 - .../Tests/CustomAttributes/CustomAttributeTests.cs | 30 - .../CustomAttributes/S_AssemblyCustomAttribute.cs | 21 - .../CustomAttributes/S_CustomAttributeSamples.cs | 508 ------ .../Tests/CustomAttributes/S_CustomAttributes.cs | 79 - .../Tests/CustomShortCircuitOperators.cs | 88 - ICSharpCode.Decompiler/Tests/DecompilerTestBase.cs | 89 -- .../Tests/DelegateConstruction.cs | 205 --- ICSharpCode.Decompiler/Tests/DoubleConstants.cs | 28 - ICSharpCode.Decompiler/Tests/ExceptionHandling.cs | 128 -- ICSharpCode.Decompiler/Tests/ExpressionTrees.cs | 370 ----- ICSharpCode.Decompiler/Tests/Generics.cs | 165 -- ICSharpCode.Decompiler/Tests/Helpers/CodeAssert.cs | 110 -- .../Tests/Helpers/RemoveCompilerAttribute.cs | 38 - .../Tests/ICSharpCode.Decompiler.Tests.csproj | 137 -- ICSharpCode.Decompiler/Tests/IL/ILTests.cs | 51 - .../Tests/IL/SequenceOfNestedIfs.Output.cs | 53 - .../Tests/IL/SequenceOfNestedIfs.il | 140 -- ICSharpCode.Decompiler/Tests/IL/StackTests.il | 132 -- ICSharpCode.Decompiler/Tests/IncrementDecrement.cs | 254 --- ICSharpCode.Decompiler/Tests/InitializerTests.cs | 885 ---------- ICSharpCode.Decompiler/Tests/LiftedOperators.cs | 830 ---------- ICSharpCode.Decompiler/Tests/Lock.cs | 38 - ICSharpCode.Decompiler/Tests/Loops.cs | 74 - .../Tests/MultidimensionalArray.cs | 58 - ICSharpCode.Decompiler/Tests/PInvoke.cs | 96 -- .../Tests/PropertiesAndEvents.cs | 80 - ICSharpCode.Decompiler/Tests/QueryExpressions.cs | 188 --- ICSharpCode.Decompiler/Tests/Switch.cs | 89 -- ICSharpCode.Decompiler/Tests/TestRunner.cs | 198 --- ICSharpCode.Decompiler/Tests/TypeAnalysisTests.cs | 153 -- ICSharpCode.Decompiler/Tests/Types/EnumTests.cs | 18 - .../Tests/Types/S_EnumSamples.cs | 129 -- .../Tests/Types/S_TypeDeclarations.cs | 17 - .../Tests/Types/S_TypeMemberDeclarations.cs | 1138 ------------- ICSharpCode.Decompiler/Tests/Types/TypeTests.cs | 18 - .../Tests/UndocumentedExpressions.cs | 41 - ICSharpCode.Decompiler/Tests/UnsafeCode.cs | 145 -- ICSharpCode.Decompiler/Tests/ValueTypes.cs | 188 --- ICSharpCode.Decompiler/Tests/YieldReturn.cs | 148 -- ICSharpCode.Decompiler/Tests/packages.config | 6 - ICSharpCode.Decompiler/TextOutputWriter.cs | 55 - ICSharpCode.Decompiler/packages.config | 5 - .../Xamarin.Forms.Build.Tasks.csproj | 4 - Xamarin.Forms.Build.Tasks/XamlCTask.cs | 27 +- Xamarin.Forms.Xaml.Xamlc/Xamlc.cs | 5 +- Xamarin.Forms.sln | 31 - 127 files changed, 10 insertions(+), 34110 deletions(-) delete mode 100644 ICSharpCode.Decompiler/Ast/Annotations.cs delete mode 100644 ICSharpCode.Decompiler/Ast/AstBuilder.cs delete mode 100644 ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs delete mode 100644 ICSharpCode.Decompiler/Ast/CommentStatement.cs delete mode 100644 ICSharpCode.Decompiler/Ast/DecompilerContext.cs delete mode 100644 ICSharpCode.Decompiler/Ast/NRefactoryExtensions.cs delete mode 100644 ICSharpCode.Decompiler/Ast/NameVariables.cs delete mode 100644 ICSharpCode.Decompiler/Ast/TextTokenWriter.cs delete mode 100644 ICSharpCode.Decompiler/Ast/Transforms/AddCheckedBlocks.cs delete mode 100644 ICSharpCode.Decompiler/Ast/Transforms/CombineQueryExpressions.cs delete mode 100644 ICSharpCode.Decompiler/Ast/Transforms/ContextTrackingVisitor.cs delete mode 100644 ICSharpCode.Decompiler/Ast/Transforms/ConvertConstructorCallIntoInitializer.cs delete mode 100644 ICSharpCode.Decompiler/Ast/Transforms/CustomPatterns.cs delete mode 100644 ICSharpCode.Decompiler/Ast/Transforms/DecimalConstantTransform.cs delete mode 100644 ICSharpCode.Decompiler/Ast/Transforms/DeclareVariables.cs delete mode 100644 ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs delete mode 100644 ICSharpCode.Decompiler/Ast/Transforms/ExpressionTreeConverter.cs delete mode 100644 ICSharpCode.Decompiler/Ast/Transforms/FlattenSwitchBlocks.cs delete mode 100644 ICSharpCode.Decompiler/Ast/Transforms/IntroduceExtensionMethods.cs delete mode 100644 ICSharpCode.Decompiler/Ast/Transforms/IntroduceQueryExpressions.cs delete mode 100644 ICSharpCode.Decompiler/Ast/Transforms/IntroduceUnsafeModifier.cs delete mode 100644 ICSharpCode.Decompiler/Ast/Transforms/IntroduceUsingDeclarations.cs delete mode 100644 ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs delete mode 100644 ICSharpCode.Decompiler/Ast/Transforms/PushNegation.cs delete mode 100644 ICSharpCode.Decompiler/Ast/Transforms/ReplaceMethodCallsWithOperators.cs delete mode 100644 ICSharpCode.Decompiler/Ast/Transforms/TransformationPipeline.cs delete mode 100644 ICSharpCode.Decompiler/Ast/TypesHierarchyHelpers.cs delete mode 100644 ICSharpCode.Decompiler/CecilExtensions.cs delete mode 100644 ICSharpCode.Decompiler/CodeMappings.cs delete mode 100644 ICSharpCode.Decompiler/DecompilerException.cs delete mode 100644 ICSharpCode.Decompiler/DecompilerSettings.cs delete mode 100644 ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs delete mode 100644 ICSharpCode.Decompiler/Disassembler/ILStructure.cs delete mode 100644 ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs delete mode 100644 ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs delete mode 100644 ICSharpCode.Decompiler/FlowAnalysis/ControlFlowEdge.cs delete mode 100644 ICSharpCode.Decompiler/FlowAnalysis/ControlFlowGraph.cs delete mode 100644 ICSharpCode.Decompiler/FlowAnalysis/ControlFlowGraphBuilder.cs delete mode 100644 ICSharpCode.Decompiler/FlowAnalysis/ControlFlowNode.cs delete mode 100644 ICSharpCode.Decompiler/FlowAnalysis/ControlStructureDetector.cs delete mode 100644 ICSharpCode.Decompiler/FlowAnalysis/OpCodeInfo.cs delete mode 100644 ICSharpCode.Decompiler/FlowAnalysis/SimplifyByRefCalls.cs delete mode 100644 ICSharpCode.Decompiler/FlowAnalysis/SsaBlock.cs delete mode 100644 ICSharpCode.Decompiler/FlowAnalysis/SsaForm.cs delete mode 100644 ICSharpCode.Decompiler/FlowAnalysis/SsaFormBuilder.cs delete mode 100644 ICSharpCode.Decompiler/FlowAnalysis/SsaInstruction.cs delete mode 100644 ICSharpCode.Decompiler/FlowAnalysis/SsaOptimization.cs delete mode 100644 ICSharpCode.Decompiler/FlowAnalysis/SsaVariable.cs delete mode 100644 ICSharpCode.Decompiler/FlowAnalysis/TransformToSsa.cs delete mode 100644 ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj delete mode 100644 ICSharpCode.Decompiler/ICSharpCode.Decompiler.sln delete mode 100644 ICSharpCode.Decompiler/ILAst/AsyncDecompiler.cs delete mode 100644 ICSharpCode.Decompiler/ILAst/DefaultDictionary.cs delete mode 100644 ICSharpCode.Decompiler/ILAst/GotoRemoval.cs delete mode 100644 ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs delete mode 100644 ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs delete mode 100644 ICSharpCode.Decompiler/ILAst/ILAstTypes.cs delete mode 100644 ICSharpCode.Decompiler/ILAst/ILCodes.cs delete mode 100644 ICSharpCode.Decompiler/ILAst/ILInlining.cs delete mode 100644 ICSharpCode.Decompiler/ILAst/InitializerPeepholeTransforms.cs delete mode 100644 ICSharpCode.Decompiler/ILAst/LiftedOperators.cs delete mode 100644 ICSharpCode.Decompiler/ILAst/LoopsAndConditions.cs delete mode 100644 ICSharpCode.Decompiler/ILAst/PatternMatching.cs delete mode 100644 ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs delete mode 100644 ICSharpCode.Decompiler/ILAst/SimpleControlFlow.cs delete mode 100644 ICSharpCode.Decompiler/ILAst/StateRange.cs delete mode 100644 ICSharpCode.Decompiler/ILAst/SymbolicExecution.cs delete mode 100644 ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs delete mode 100644 ICSharpCode.Decompiler/ILAst/YieldReturnDecompiler.cs delete mode 100644 ICSharpCode.Decompiler/ITextOutput.cs delete mode 100644 ICSharpCode.Decompiler/PlainTextOutput.cs delete mode 100644 ICSharpCode.Decompiler/Properties/AssemblyInfo.template.cs delete mode 100644 ICSharpCode.Decompiler/ReferenceResolvingException.cs delete mode 100644 ICSharpCode.Decompiler/Tests/Async.cs delete mode 100644 ICSharpCode.Decompiler/Tests/BooleanConsumedAsInteger.il delete mode 100644 ICSharpCode.Decompiler/Tests/CallOverloadedMethod.cs delete mode 100644 ICSharpCode.Decompiler/Tests/CheckedUnchecked.cs delete mode 100644 ICSharpCode.Decompiler/Tests/CodeSampleFileParser.cs delete mode 100644 ICSharpCode.Decompiler/Tests/ControlFlow.cs delete mode 100644 ICSharpCode.Decompiler/Tests/CustomAttributes.code.cs delete mode 100644 ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeTests.cs delete mode 100644 ICSharpCode.Decompiler/Tests/CustomAttributes/S_AssemblyCustomAttribute.cs delete mode 100644 ICSharpCode.Decompiler/Tests/CustomAttributes/S_CustomAttributeSamples.cs delete mode 100644 ICSharpCode.Decompiler/Tests/CustomAttributes/S_CustomAttributes.cs delete mode 100644 ICSharpCode.Decompiler/Tests/CustomShortCircuitOperators.cs delete mode 100644 ICSharpCode.Decompiler/Tests/DecompilerTestBase.cs delete mode 100644 ICSharpCode.Decompiler/Tests/DelegateConstruction.cs delete mode 100644 ICSharpCode.Decompiler/Tests/DoubleConstants.cs delete mode 100644 ICSharpCode.Decompiler/Tests/ExceptionHandling.cs delete mode 100644 ICSharpCode.Decompiler/Tests/ExpressionTrees.cs delete mode 100644 ICSharpCode.Decompiler/Tests/Generics.cs delete mode 100644 ICSharpCode.Decompiler/Tests/Helpers/CodeAssert.cs delete mode 100644 ICSharpCode.Decompiler/Tests/Helpers/RemoveCompilerAttribute.cs delete mode 100644 ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj delete mode 100644 ICSharpCode.Decompiler/Tests/IL/ILTests.cs delete mode 100644 ICSharpCode.Decompiler/Tests/IL/SequenceOfNestedIfs.Output.cs delete mode 100644 ICSharpCode.Decompiler/Tests/IL/SequenceOfNestedIfs.il delete mode 100644 ICSharpCode.Decompiler/Tests/IL/StackTests.il delete mode 100644 ICSharpCode.Decompiler/Tests/IncrementDecrement.cs delete mode 100644 ICSharpCode.Decompiler/Tests/InitializerTests.cs delete mode 100644 ICSharpCode.Decompiler/Tests/LiftedOperators.cs delete mode 100644 ICSharpCode.Decompiler/Tests/Lock.cs delete mode 100644 ICSharpCode.Decompiler/Tests/Loops.cs delete mode 100644 ICSharpCode.Decompiler/Tests/MultidimensionalArray.cs delete mode 100644 ICSharpCode.Decompiler/Tests/PInvoke.cs delete mode 100644 ICSharpCode.Decompiler/Tests/PropertiesAndEvents.cs delete mode 100644 ICSharpCode.Decompiler/Tests/QueryExpressions.cs delete mode 100644 ICSharpCode.Decompiler/Tests/Switch.cs delete mode 100644 ICSharpCode.Decompiler/Tests/TestRunner.cs delete mode 100644 ICSharpCode.Decompiler/Tests/TypeAnalysisTests.cs delete mode 100644 ICSharpCode.Decompiler/Tests/Types/EnumTests.cs delete mode 100644 ICSharpCode.Decompiler/Tests/Types/S_EnumSamples.cs delete mode 100644 ICSharpCode.Decompiler/Tests/Types/S_TypeDeclarations.cs delete mode 100644 ICSharpCode.Decompiler/Tests/Types/S_TypeMemberDeclarations.cs delete mode 100644 ICSharpCode.Decompiler/Tests/Types/TypeTests.cs delete mode 100644 ICSharpCode.Decompiler/Tests/UndocumentedExpressions.cs delete mode 100644 ICSharpCode.Decompiler/Tests/UnsafeCode.cs delete mode 100644 ICSharpCode.Decompiler/Tests/ValueTypes.cs delete mode 100644 ICSharpCode.Decompiler/Tests/YieldReturn.cs delete mode 100644 ICSharpCode.Decompiler/Tests/packages.config delete mode 100644 ICSharpCode.Decompiler/TextOutputWriter.cs delete mode 100644 ICSharpCode.Decompiler/packages.config diff --git a/.nuspec/Xamarin.Forms.nuspec b/.nuspec/Xamarin.Forms.nuspec index b87a1406..b96376ae 100644 --- a/.nuspec/Xamarin.Forms.nuspec +++ b/.nuspec/Xamarin.Forms.nuspec @@ -118,11 +118,6 @@ - - - - - diff --git a/ICSharpCode.Decompiler/Ast/Annotations.cs b/ICSharpCode.Decompiler/Ast/Annotations.cs deleted file mode 100644 index ec9fd61f..00000000 --- a/ICSharpCode.Decompiler/Ast/Annotations.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using ICSharpCode.Decompiler.ILAst; -using ICSharpCode.NRefactory.CSharp; -using Mono.Cecil; - -namespace ICSharpCode.Decompiler.Ast -{ - public class TypeInformation - { - public readonly TypeReference InferredType; - public readonly TypeReference ExpectedType; - - public TypeInformation(TypeReference inferredType, TypeReference expectedType) - { - InferredType = inferredType; - ExpectedType = expectedType; - } - } - - public class LdTokenAnnotation {} - - /// - /// Annotation that is applied to the body expression of an Expression.Lambda() call. - /// - public class ParameterDeclarationAnnotation - { - public readonly List Parameters = new List(); - - public ParameterDeclarationAnnotation(ILExpression expr) - { - Debug.Assert(expr.Code == ILCode.ExpressionTreeParameterDeclarations); - for (int i = 0; i < expr.Arguments.Count - 1; i++) { - ILExpression p = expr.Arguments[i]; - // p looks like this: - // stloc(v, call(Expression::Parameter, call(Type::GetTypeFromHandle, ldtoken(...)), ldstr(...))) - ILVariable v = (ILVariable)p.Operand; - TypeReference typeRef = (TypeReference)p.Arguments[0].Arguments[0].Arguments[0].Operand; - string name = (string)p.Arguments[0].Arguments[1].Operand; - Parameters.Add(new ParameterDeclaration(AstBuilder.ConvertType(typeRef), name).WithAnnotation(v)); - } - } - } - - /// - /// Annotation that is applied to a LambdaExpression that was produced by an expression tree. - /// - public class ExpressionTreeLambdaAnnotation - { - } -} diff --git a/ICSharpCode.Decompiler/Ast/AstBuilder.cs b/ICSharpCode.Decompiler/Ast/AstBuilder.cs deleted file mode 100644 index 9a53237a..00000000 --- a/ICSharpCode.Decompiler/Ast/AstBuilder.cs +++ /dev/null @@ -1,1687 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Threading; - -using ICSharpCode.Decompiler; -using ICSharpCode.Decompiler.Ast.Transforms; -using ICSharpCode.Decompiler.ILAst; -using ICSharpCode.NRefactory.CSharp; -using ICSharpCode.NRefactory.Utils; -using Mono.Cecil; -using Mono.Cecil.Cil; - -namespace ICSharpCode.Decompiler.Ast -{ - using Ast = NRefactory.CSharp; - using VarianceModifier = NRefactory.TypeSystem.VarianceModifier; - - [Flags] - public enum ConvertTypeOptions - { - None = 0, - IncludeNamespace = 1, - IncludeTypeParameterDefinitions = 2, - DoNotUsePrimitiveTypeNames = 4 - } - - public class AstBuilder - { - DecompilerContext context; - SyntaxTree syntaxTree = new SyntaxTree(); - Dictionary astNamespaces = new Dictionary(); - bool transformationsHaveRun; - - public AstBuilder(DecompilerContext context) - { - if (context == null) - throw new ArgumentNullException("context"); - this.context = context; - DecompileMethodBodies = true; - } - - public static bool MemberIsHidden(MemberReference member, DecompilerSettings settings) - { - MethodDefinition method = member as MethodDefinition; - if (method != null) { - if (method.IsGetter || method.IsSetter || method.IsAddOn || method.IsRemoveOn) - return true; - if (settings.AnonymousMethods && method.HasGeneratedName() && method.IsCompilerGenerated()) - return true; - } - - TypeDefinition type = member as TypeDefinition; - if (type != null) { - if (type.DeclaringType != null) { - if (settings.AnonymousMethods && IsClosureType(type)) - return true; - if (settings.YieldReturn && YieldReturnDecompiler.IsCompilerGeneratorEnumerator(type)) - return true; - if (settings.AsyncAwait && AsyncDecompiler.IsCompilerGeneratedStateMachine(type)) - return true; - } else if (type.IsCompilerGenerated()) { - if (type.Name.StartsWith("", StringComparison.Ordinal)) - return true; - if (type.IsAnonymousType()) - return true; - } - } - - FieldDefinition field = member as FieldDefinition; - if (field != null) { - if (field.IsCompilerGenerated()) { - if (settings.AnonymousMethods && IsAnonymousMethodCacheField(field)) - return true; - if (settings.AutomaticProperties && IsAutomaticPropertyBackingField(field)) - return true; - if (settings.SwitchStatementOnString && IsSwitchOnStringCache(field)) - return true; - } - // event-fields are not [CompilerGenerated] - if (settings.AutomaticEvents && field.DeclaringType.Events.Any(ev => ev.Name == field.Name)) - return true; - } - - return false; - } - - static bool IsSwitchOnStringCache(FieldDefinition field) - { - return field.Name.StartsWith("<>f__switch", StringComparison.Ordinal); - } - - static bool IsAutomaticPropertyBackingField(FieldDefinition field) - { - return field.HasGeneratedName() && field.Name.EndsWith("BackingField", StringComparison.Ordinal); - } - - static bool IsAnonymousMethodCacheField(FieldDefinition field) - { - return field.Name.StartsWith("CS$<>", StringComparison.Ordinal) || field.Name.StartsWith("<>f__am", StringComparison.Ordinal); - } - - static bool IsClosureType(TypeDefinition type) - { - return type.HasGeneratedName() && type.IsCompilerGenerated() && (type.Name.Contains("DisplayClass") || type.Name.Contains("AnonStorey")); - } - - /// - /// Runs the C# transformations on the compilation unit. - /// - public void RunTransformations() - { - RunTransformations(null); - } - - public void RunTransformations(Predicate transformAbortCondition) - { - TransformationPipeline.RunTransformationsUntil(syntaxTree, transformAbortCondition, context); - transformationsHaveRun = true; - } - - /// - /// Gets the abstract source tree. - /// - public SyntaxTree SyntaxTree { - get { return syntaxTree; } - } - - /// - /// Generates C# code from the abstract source tree. - /// - public void GenerateCode(ITextOutput output) - { - if (!transformationsHaveRun) - RunTransformations(); - - syntaxTree.AcceptVisitor(new InsertParenthesesVisitor { InsertParenthesesForReadability = true }); - var outputFormatter = new TextTokenWriter(output, context) { FoldBraces = context.Settings.FoldBraces }; - var formattingPolicy = context.Settings.CSharpFormattingOptions; - syntaxTree.AcceptVisitor(new CSharpOutputVisitor(outputFormatter, formattingPolicy)); - } - - public void AddAssembly(AssemblyDefinition assemblyDefinition, bool onlyAssemblyLevel = false) - { - AddAssembly(assemblyDefinition.MainModule, onlyAssemblyLevel); - } - - public void AddAssembly(ModuleDefinition moduleDefinition, bool onlyAssemblyLevel = false) - { - if (moduleDefinition.Assembly != null && moduleDefinition.Assembly.Name.Version != null) { - syntaxTree.AddChild( - new AttributeSection { - AttributeTarget = "assembly", - Attributes = { - new NRefactory.CSharp.Attribute { - Type = new SimpleType("AssemblyVersion") - .WithAnnotation(new TypeReference( - "System.Reflection", "AssemblyVersionAttribute", - moduleDefinition, moduleDefinition.TypeSystem.Corlib)), - Arguments = { - new PrimitiveExpression(moduleDefinition.Assembly.Name.Version.ToString()) - } - } - } - }, EntityDeclaration.AttributeRole); - } - - if (moduleDefinition.Assembly != null) { - ConvertCustomAttributes(syntaxTree, moduleDefinition.Assembly, "assembly"); - ConvertSecurityAttributes(syntaxTree, moduleDefinition.Assembly, "assembly"); - } - ConvertCustomAttributes(syntaxTree, moduleDefinition, "module"); - AddTypeForwarderAttributes(syntaxTree, moduleDefinition, "assembly"); - - if (!onlyAssemblyLevel) { - foreach (TypeDefinition typeDef in moduleDefinition.Types) { - // Skip the class - if (typeDef.Name == "") continue; - // Skip any hidden types - if (MemberIsHidden(typeDef, context.Settings)) - continue; - - AddType(typeDef); - } - } - } - - void AddTypeForwarderAttributes(SyntaxTree astCompileUnit, ModuleDefinition module, string target) - { - if (!module.HasExportedTypes) - return; - foreach (ExportedType type in module.ExportedTypes) { - if (type.IsForwarder) { - var forwardedType = CreateTypeOfExpression(new TypeReference(type.Namespace, type.Name, module, type.Scope)); - astCompileUnit.AddChild( - new AttributeSection { - AttributeTarget = target, - Attributes = { - new NRefactory.CSharp.Attribute { - Type = new SimpleType("TypeForwardedTo") - .WithAnnotation(new TypeReference( - "System.Runtime.CompilerServices", "TypeForwardedToAttribute", - module, module.TypeSystem.Corlib)), - Arguments = { forwardedType } - } - } - }, EntityDeclaration.AttributeRole); - } - } - } - - NamespaceDeclaration GetCodeNamespace(string name) - { - if (string.IsNullOrEmpty(name)) { - return null; - } - if (astNamespaces.ContainsKey(name)) { - return astNamespaces[name]; - } else { - // Create the namespace - NamespaceDeclaration astNamespace = new NamespaceDeclaration { Name = name }; - syntaxTree.Members.Add(astNamespace); - astNamespaces[name] = astNamespace; - return astNamespace; - } - } - - public void AddType(TypeDefinition typeDef) - { - var astType = CreateType(typeDef); - NamespaceDeclaration astNS = GetCodeNamespace(typeDef.Namespace); - if (astNS != null) { - astNS.Members.Add(astType); - } else { - syntaxTree.Members.Add(astType); - } - } - - public void AddMethod(MethodDefinition method) - { - AstNode node = method.IsConstructor ? (AstNode)CreateConstructor(method) : CreateMethod(method); - syntaxTree.Members.Add(node); - } - - public void AddProperty(PropertyDefinition property) - { - syntaxTree.Members.Add(CreateProperty(property)); - } - - public void AddField(FieldDefinition field) - { - syntaxTree.Members.Add(CreateField(field)); - } - - public void AddEvent(EventDefinition ev) - { - syntaxTree.Members.Add(CreateEvent(ev)); - } - - /// - /// Creates the AST for a type definition. - /// - /// - /// TypeDeclaration or DelegateDeclaration. - public EntityDeclaration CreateType(TypeDefinition typeDef) - { - // create type - TypeDefinition oldCurrentType = context.CurrentType; - context.CurrentType = typeDef; - TypeDeclaration astType = new TypeDeclaration(); - ConvertAttributes(astType, typeDef); - astType.AddAnnotation(typeDef); - astType.Modifiers = ConvertModifiers(typeDef); - astType.Name = CleanName(typeDef.Name); - - if (typeDef.IsEnum) { // NB: Enum is value type - astType.ClassType = ClassType.Enum; - astType.Modifiers &= ~Modifiers.Sealed; - } else if (typeDef.IsValueType) { - astType.ClassType = ClassType.Struct; - astType.Modifiers &= ~Modifiers.Sealed; - } else if (typeDef.IsInterface) { - astType.ClassType = ClassType.Interface; - astType.Modifiers &= ~Modifiers.Abstract; - } else { - astType.ClassType = ClassType.Class; - } - - IEnumerable genericParameters = typeDef.GenericParameters; - if (typeDef.DeclaringType != null && typeDef.DeclaringType.HasGenericParameters) - genericParameters = genericParameters.Skip(typeDef.DeclaringType.GenericParameters.Count); - astType.TypeParameters.AddRange(MakeTypeParameters(genericParameters)); - astType.Constraints.AddRange(MakeConstraints(genericParameters)); - - EntityDeclaration result = astType; - if (typeDef.IsEnum) { - long expectedEnumMemberValue = 0; - bool forcePrintingInitializers = IsFlagsEnum(typeDef); - TypeCode baseType = TypeCode.Int32; - foreach (FieldDefinition field in typeDef.Fields) { - if (!field.IsStatic) { - // the value__ field - if (field.FieldType != typeDef.Module.TypeSystem.Int32) { - astType.AddChild(ConvertType(field.FieldType), Roles.BaseType); - baseType = TypeAnalysis.GetTypeCode(field.FieldType); - } - } else { - EnumMemberDeclaration enumMember = new EnumMemberDeclaration(); - enumMember.AddAnnotation(field); - enumMember.Name = CleanName(field.Name); - long memberValue = (long)CSharpPrimitiveCast.Cast(TypeCode.Int64, field.Constant, false); - if (forcePrintingInitializers || memberValue != expectedEnumMemberValue) { - enumMember.AddChild(new PrimitiveExpression(CSharpPrimitiveCast.Cast(baseType, field.Constant, false)), EnumMemberDeclaration.InitializerRole); - } - expectedEnumMemberValue = memberValue + 1; - astType.AddChild(enumMember, Roles.TypeMemberRole); - } - } - } else if (typeDef.BaseType != null && typeDef.BaseType.FullName == "System.MulticastDelegate") { - DelegateDeclaration dd = new DelegateDeclaration(); - dd.Modifiers = astType.Modifiers & ~Modifiers.Sealed; - dd.Name = astType.Name; - dd.AddAnnotation(typeDef); - astType.Attributes.MoveTo(dd.Attributes); - astType.TypeParameters.MoveTo(dd.TypeParameters); - astType.Constraints.MoveTo(dd.Constraints); - foreach (var m in typeDef.Methods) { - if (m.Name == "Invoke") { - dd.ReturnType = ConvertType(m.ReturnType, m.MethodReturnType); - dd.Parameters.AddRange(MakeParameters(m)); - ConvertAttributes(dd, m.MethodReturnType, m.Module); - } - } - result = dd; - } else { - // Base type - if (typeDef.BaseType != null && !typeDef.IsValueType && typeDef.BaseType.FullName != "System.Object") { - astType.AddChild(ConvertType(typeDef.BaseType), Roles.BaseType); - } - foreach (var i in typeDef.Interfaces) - astType.AddChild(ConvertType(i), Roles.BaseType); - - AddTypeMembers(astType, typeDef); - - if (astType.Members.OfType().Any(idx => idx.PrivateImplementationType.IsNull)) { - // Remove the [DefaultMember] attribute if the class contains indexers - foreach (AttributeSection section in astType.Attributes) { - foreach (Ast.Attribute attr in section.Attributes) { - TypeReference tr = attr.Type.Annotation(); - if (tr != null && tr.Name == "DefaultMemberAttribute" && tr.Namespace == "System.Reflection") { - attr.Remove(); - } - } - if (section.Attributes.Count == 0) - section.Remove(); - } - } - } - - context.CurrentType = oldCurrentType; - return result; - } - - internal static string CleanName(string name) - { - int pos = name.LastIndexOf('`'); - if (pos >= 0) - name = name.Substring(0, pos); - pos = name.LastIndexOf('.'); - if (pos >= 0) - name = name.Substring(pos + 1); - return name; - } - - #region Create TypeOf Expression - /// - /// Creates a typeof-expression for the specified type. - /// - public static TypeOfExpression CreateTypeOfExpression(TypeReference type) - { - return new TypeOfExpression(AddEmptyTypeArgumentsForUnboundGenerics(ConvertType(type))); - } - - static AstType AddEmptyTypeArgumentsForUnboundGenerics(AstType type) - { - TypeReference typeRef = type.Annotation(); - if (typeRef == null) - return type; - TypeDefinition typeDef = typeRef.Resolve(); // need to resolve to figure out the number of type parameters - if (typeDef == null || !typeDef.HasGenericParameters) - return type; - SimpleType sType = type as SimpleType; - MemberType mType = type as MemberType; - if (sType != null) { - while (typeDef.GenericParameters.Count > sType.TypeArguments.Count) { - sType.TypeArguments.Add(new SimpleType("")); - } - } - - if (mType != null) { - AddEmptyTypeArgumentsForUnboundGenerics(mType.Target); - - int outerTypeParamCount = typeDef.DeclaringType == null ? 0 : typeDef.DeclaringType.GenericParameters.Count; - - while (typeDef.GenericParameters.Count - outerTypeParamCount > mType.TypeArguments.Count) { - mType.TypeArguments.Add(new SimpleType("")); - } - } - - return type; - } - #endregion - - #region Convert Type Reference - /// - /// Converts a type reference. - /// - public static AstType ConvertType(TypeReference type, ICustomAttributeProvider typeAttributes = null, ConvertTypeOptions options = ConvertTypeOptions.None) - { - int typeIndex = 0; - return ConvertType(type, typeAttributes, ref typeIndex, options); - } - - static AstType ConvertType(TypeReference type, ICustomAttributeProvider typeAttributes, ref int typeIndex, ConvertTypeOptions options) - { - while (type is OptionalModifierType || type is RequiredModifierType) { - type = ((TypeSpecification)type).ElementType; - } - if (type == null) { - return AstType.Null; - } - - if (type is ByReferenceType) { - typeIndex++; - // by reference type cannot be represented in C#; so we'll represent it as a pointer instead - return ConvertType((type as ByReferenceType).ElementType, typeAttributes, ref typeIndex, options) - .MakePointerType(); - } else if (type is PointerType) { - typeIndex++; - return ConvertType((type as PointerType).ElementType, typeAttributes, ref typeIndex, options) - .MakePointerType(); - } else if (type is ArrayType) { - typeIndex++; - return ConvertType((type as ArrayType).ElementType, typeAttributes, ref typeIndex, options) - .MakeArrayType((type as ArrayType).Rank); - } else if (type is GenericInstanceType) { - GenericInstanceType gType = (GenericInstanceType)type; - if (gType.ElementType.Namespace == "System" && gType.ElementType.Name == "Nullable`1" && gType.GenericArguments.Count == 1) { - typeIndex++; - return new ComposedType { - BaseType = ConvertType(gType.GenericArguments[0], typeAttributes, ref typeIndex, options), - HasNullableSpecifier = true - }; - } - AstType baseType = ConvertType(gType.ElementType, typeAttributes, ref typeIndex, options & ~ConvertTypeOptions.IncludeTypeParameterDefinitions); - List typeArguments = new List(); - foreach (var typeArgument in gType.GenericArguments) { - typeIndex++; - typeArguments.Add(ConvertType(typeArgument, typeAttributes, ref typeIndex, options)); - } - ApplyTypeArgumentsTo(baseType, typeArguments); - return baseType; - } else if (type is GenericParameter) { - return new SimpleType(type.Name); - } else if (type.IsNested) { - AstType typeRef = ConvertType(type.DeclaringType, typeAttributes, ref typeIndex, options & ~ConvertTypeOptions.IncludeTypeParameterDefinitions); - string namepart = NRefactory.TypeSystem.ReflectionHelper.SplitTypeParameterCountFromReflectionName(type.Name); - MemberType memberType = new MemberType { Target = typeRef, MemberName = namepart }; - memberType.AddAnnotation(type); - if ((options & ConvertTypeOptions.IncludeTypeParameterDefinitions) == ConvertTypeOptions.IncludeTypeParameterDefinitions) { - AddTypeParameterDefininitionsTo(type, memberType); - } - return memberType; - } else { - string ns = type.Namespace ?? string.Empty; - string name = type.Name; - if (name == null) - throw new InvalidOperationException("type.Name returned null. Type: " + type.ToString()); - - if (name == "Object" && ns == "System" && HasDynamicAttribute(typeAttributes, typeIndex)) { - return new PrimitiveType("dynamic"); - } else { - if (ns == "System") { - if ((options & ConvertTypeOptions.DoNotUsePrimitiveTypeNames) - != ConvertTypeOptions.DoNotUsePrimitiveTypeNames) { - switch (name) { - case "SByte": - return new PrimitiveType("sbyte"); - case "Int16": - return new PrimitiveType("short"); - case "Int32": - return new PrimitiveType("int"); - case "Int64": - return new PrimitiveType("long"); - case "Byte": - return new PrimitiveType("byte"); - case "UInt16": - return new PrimitiveType("ushort"); - case "UInt32": - return new PrimitiveType("uint"); - case "UInt64": - return new PrimitiveType("ulong"); - case "String": - return new PrimitiveType("string"); - case "Single": - return new PrimitiveType("float"); - case "Double": - return new PrimitiveType("double"); - case "Decimal": - return new PrimitiveType("decimal"); - case "Char": - return new PrimitiveType("char"); - case "Boolean": - return new PrimitiveType("bool"); - case "Void": - return new PrimitiveType("void"); - case "Object": - return new PrimitiveType("object"); - } - } - } - - name = NRefactory.TypeSystem.ReflectionHelper.SplitTypeParameterCountFromReflectionName(name); - - AstType astType; - if ((options & ConvertTypeOptions.IncludeNamespace) == ConvertTypeOptions.IncludeNamespace && ns.Length > 0) { - string[] parts = ns.Split('.'); - AstType nsType = new SimpleType(parts[0]); - for (int i = 1; i < parts.Length; i++) { - nsType = new MemberType { Target = nsType, MemberName = parts[i] }; - } - astType = new MemberType { Target = nsType, MemberName = name }; - } else { - astType = new SimpleType(name); - } - astType.AddAnnotation(type); - - if ((options & ConvertTypeOptions.IncludeTypeParameterDefinitions) == ConvertTypeOptions.IncludeTypeParameterDefinitions) { - AddTypeParameterDefininitionsTo(type, astType); - } - return astType; - } - } - } - - static void AddTypeParameterDefininitionsTo(TypeReference type, AstType astType) - { - if (type.HasGenericParameters) { - List typeArguments = new List(); - foreach (GenericParameter gp in type.GenericParameters) { - typeArguments.Add(new SimpleType(gp.Name)); - } - ApplyTypeArgumentsTo(astType, typeArguments); - } - } - - static void ApplyTypeArgumentsTo(AstType baseType, List typeArguments) - { - SimpleType st = baseType as SimpleType; - if (st != null) { - st.TypeArguments.AddRange(typeArguments); - } - MemberType mt = baseType as MemberType; - if (mt != null) { - TypeReference type = mt.Annotation(); - if (type != null) { - int typeParameterCount; - NRefactory.TypeSystem.ReflectionHelper.SplitTypeParameterCountFromReflectionName(type.Name, out typeParameterCount); - if (typeParameterCount > typeArguments.Count) - typeParameterCount = typeArguments.Count; - mt.TypeArguments.AddRange(typeArguments.GetRange(typeArguments.Count - typeParameterCount, typeParameterCount)); - typeArguments.RemoveRange(typeArguments.Count - typeParameterCount, typeParameterCount); - if (typeArguments.Count > 0) - ApplyTypeArgumentsTo(mt.Target, typeArguments); - } else { - mt.TypeArguments.AddRange(typeArguments); - } - } - } - - const string DynamicAttributeFullName = "System.Runtime.CompilerServices.DynamicAttribute"; - - static bool HasDynamicAttribute(ICustomAttributeProvider attributeProvider, int typeIndex) - { - if (attributeProvider == null || !attributeProvider.HasCustomAttributes) - return false; - foreach (CustomAttribute a in attributeProvider.CustomAttributes) { - if (a.Constructor.DeclaringType.FullName == DynamicAttributeFullName) { - if (a.ConstructorArguments.Count == 1) { - CustomAttributeArgument[] values = a.ConstructorArguments[0].Value as CustomAttributeArgument[]; - if (values != null && typeIndex < values.Length && values[typeIndex].Value is bool) - return (bool)values[typeIndex].Value; - } - return true; - } - } - return false; - } - #endregion - - #region ConvertModifiers - Modifiers ConvertModifiers(TypeDefinition typeDef) - { - Modifiers modifiers = Modifiers.None; - if (typeDef.IsNestedPrivate) - modifiers |= Modifiers.Private; - else if (typeDef.IsNestedAssembly || typeDef.IsNestedFamilyAndAssembly || typeDef.IsNotPublic) - modifiers |= Modifiers.Internal; - else if (typeDef.IsNestedFamily) - modifiers |= Modifiers.Protected; - else if (typeDef.IsNestedFamilyOrAssembly) - modifiers |= Modifiers.Protected | Modifiers.Internal; - else if (typeDef.IsPublic || typeDef.IsNestedPublic) - modifiers |= Modifiers.Public; - - if (typeDef.IsAbstract && typeDef.IsSealed) - modifiers |= Modifiers.Static; - else if (typeDef.IsAbstract) - modifiers |= Modifiers.Abstract; - else if (typeDef.IsSealed) - modifiers |= Modifiers.Sealed; - - return modifiers; - } - - Modifiers ConvertModifiers(FieldDefinition fieldDef) - { - Modifiers modifiers = Modifiers.None; - if (fieldDef.IsPrivate) - modifiers |= Modifiers.Private; - else if (fieldDef.IsAssembly || fieldDef.IsFamilyAndAssembly) - modifiers |= Modifiers.Internal; - else if (fieldDef.IsFamily) - modifiers |= Modifiers.Protected; - else if (fieldDef.IsFamilyOrAssembly) - modifiers |= Modifiers.Protected | Modifiers.Internal; - else if (fieldDef.IsPublic) - modifiers |= Modifiers.Public; - - if (fieldDef.IsLiteral) { - modifiers |= Modifiers.Const; - } else { - if (fieldDef.IsStatic) - modifiers |= Modifiers.Static; - - if (fieldDef.IsInitOnly) - modifiers |= Modifiers.Readonly; - } - - RequiredModifierType modreq = fieldDef.FieldType as RequiredModifierType; - if (modreq != null && modreq.ModifierType.FullName == typeof(IsVolatile).FullName) - modifiers |= Modifiers.Volatile; - - return modifiers; - } - - Modifiers ConvertModifiers(MethodDefinition methodDef) - { - if (methodDef == null) - return Modifiers.None; - Modifiers modifiers = Modifiers.None; - if (methodDef.IsPrivate) - modifiers |= Modifiers.Private; - else if (methodDef.IsAssembly || methodDef.IsFamilyAndAssembly) - modifiers |= Modifiers.Internal; - else if (methodDef.IsFamily) - modifiers |= Modifiers.Protected; - else if (methodDef.IsFamilyOrAssembly) - modifiers |= Modifiers.Protected | Modifiers.Internal; - else if (methodDef.IsPublic) - modifiers |= Modifiers.Public; - - if (methodDef.IsStatic) - modifiers |= Modifiers.Static; - - if (methodDef.IsAbstract) { - modifiers |= Modifiers.Abstract; - if (!methodDef.IsNewSlot) - modifiers |= Modifiers.Override; - } else if (methodDef.IsFinal) { - if (!methodDef.IsNewSlot) { - modifiers |= Modifiers.Sealed | Modifiers.Override; - } - } else if (methodDef.IsVirtual) { - if (methodDef.IsNewSlot) - modifiers |= Modifiers.Virtual; - else - modifiers |= Modifiers.Override; - } - if (!methodDef.HasBody && !methodDef.IsAbstract) - modifiers |= Modifiers.Extern; - - return modifiers; - } - - #endregion - - void AddTypeMembers(TypeDeclaration astType, TypeDefinition typeDef) - { - // Nested types - foreach (TypeDefinition nestedTypeDef in typeDef.NestedTypes) { - if (MemberIsHidden(nestedTypeDef, context.Settings)) - continue; - var nestedType = CreateType(nestedTypeDef); - SetNewModifier(nestedType); - astType.AddChild(nestedType, Roles.TypeMemberRole); - } - - // Add fields - foreach(FieldDefinition fieldDef in typeDef.Fields) { - if (MemberIsHidden(fieldDef, context.Settings)) continue; - astType.AddChild(CreateField(fieldDef), Roles.TypeMemberRole); - } - - // Add events - foreach(EventDefinition eventDef in typeDef.Events) { - astType.AddChild(CreateEvent(eventDef), Roles.TypeMemberRole); - } - - // Add properties - foreach(PropertyDefinition propDef in typeDef.Properties) { - astType.Members.Add(CreateProperty(propDef)); - } - - // Add methods - foreach(MethodDefinition methodDef in typeDef.Methods) { - if (MemberIsHidden(methodDef, context.Settings)) continue; - - if (methodDef.IsConstructor) - astType.Members.Add(CreateConstructor(methodDef)); - else - astType.Members.Add(CreateMethod(methodDef)); - } - } - - EntityDeclaration CreateMethod(MethodDefinition methodDef) - { - MethodDeclaration astMethod = new MethodDeclaration(); - astMethod.AddAnnotation(methodDef); - astMethod.ReturnType = ConvertType(methodDef.ReturnType, methodDef.MethodReturnType); - astMethod.Name = CleanName(methodDef.Name); - astMethod.TypeParameters.AddRange(MakeTypeParameters(methodDef.GenericParameters)); - astMethod.Parameters.AddRange(MakeParameters(methodDef)); - // constraints for override and explicit interface implementation methods are inherited from the base method, so they cannot be specified directly - if (!methodDef.IsVirtual || (methodDef.IsNewSlot && !methodDef.IsPrivate)) astMethod.Constraints.AddRange(MakeConstraints(methodDef.GenericParameters)); - if (!methodDef.DeclaringType.IsInterface) { - if (IsExplicitInterfaceImplementation(methodDef)) { - astMethod.PrivateImplementationType = ConvertType(methodDef.Overrides.First().DeclaringType); - } else { - astMethod.Modifiers = ConvertModifiers(methodDef); - if (methodDef.IsVirtual == methodDef.IsNewSlot) - SetNewModifier(astMethod); - } - astMethod.Body = CreateMethodBody(methodDef, astMethod.Parameters); - if (context.CurrentMethodIsAsync) { - astMethod.Modifiers |= Modifiers.Async; - context.CurrentMethodIsAsync = false; - } - } - ConvertAttributes(astMethod, methodDef); - if (methodDef.HasCustomAttributes && astMethod.Parameters.Count > 0) { - foreach (CustomAttribute ca in methodDef.CustomAttributes) { - if (ca.AttributeType.Name == "ExtensionAttribute" && ca.AttributeType.Namespace == "System.Runtime.CompilerServices") { - astMethod.Parameters.First().ParameterModifier = ParameterModifier.This; - } - } - } - - // Convert MethodDeclaration to OperatorDeclaration if possible - if (methodDef.IsSpecialName && !methodDef.HasGenericParameters) { - OperatorType? opType = OperatorDeclaration.GetOperatorType(methodDef.Name); - if (opType.HasValue) { - OperatorDeclaration op = new OperatorDeclaration(); - op.CopyAnnotationsFrom(astMethod); - op.ReturnType = astMethod.ReturnType.Detach(); - op.OperatorType = opType.Value; - op.Modifiers = astMethod.Modifiers; - astMethod.Parameters.MoveTo(op.Parameters); - astMethod.Attributes.MoveTo(op.Attributes); - op.Body = astMethod.Body.Detach(); - return op; - } - } - return astMethod; - } - - bool IsExplicitInterfaceImplementation(MethodDefinition methodDef) - { - return methodDef.HasOverrides && methodDef.IsPrivate; - } - - IEnumerable MakeTypeParameters(IEnumerable genericParameters) - { - foreach (var gp in genericParameters) { - TypeParameterDeclaration tp = new TypeParameterDeclaration(); - tp.Name = CleanName(gp.Name); - if (gp.IsContravariant) - tp.Variance = VarianceModifier.Contravariant; - else if (gp.IsCovariant) - tp.Variance = VarianceModifier.Covariant; - ConvertCustomAttributes(tp, gp); - yield return tp; - } - } - - IEnumerable MakeConstraints(IEnumerable genericParameters) - { - foreach (var gp in genericParameters) { - Constraint c = new Constraint(); - c.TypeParameter = new SimpleType(CleanName(gp.Name)); - // class/struct must be first - if (gp.HasReferenceTypeConstraint) - c.BaseTypes.Add(new PrimitiveType("class")); - if (gp.HasNotNullableValueTypeConstraint) - c.BaseTypes.Add(new PrimitiveType("struct")); - - foreach (var constraintType in gp.Constraints) { - if (gp.HasNotNullableValueTypeConstraint && constraintType.FullName == "System.ValueType") - continue; - c.BaseTypes.Add(ConvertType(constraintType)); - } - - if (gp.HasDefaultConstructorConstraint && !gp.HasNotNullableValueTypeConstraint) - c.BaseTypes.Add(new PrimitiveType("new")); // new() must be last - if (c.BaseTypes.Any()) - yield return c; - } - } - - ConstructorDeclaration CreateConstructor(MethodDefinition methodDef) - { - ConstructorDeclaration astMethod = new ConstructorDeclaration(); - astMethod.AddAnnotation(methodDef); - astMethod.Modifiers = ConvertModifiers(methodDef); - if (methodDef.IsStatic) { - // don't show visibility for static ctors - astMethod.Modifiers &= ~Modifiers.VisibilityMask; - } - astMethod.Name = CleanName(methodDef.DeclaringType.Name); - astMethod.Parameters.AddRange(MakeParameters(methodDef)); - astMethod.Body = CreateMethodBody(methodDef, astMethod.Parameters); - ConvertAttributes(astMethod, methodDef); - if (methodDef.IsStatic && methodDef.DeclaringType.IsBeforeFieldInit && !astMethod.Body.IsNull) { - astMethod.Body.InsertChildAfter(null, new Comment(" Note: this type is marked as 'beforefieldinit'."), Roles.Comment); - } - return astMethod; - } - - Modifiers FixUpVisibility(Modifiers m) - { - Modifiers v = m & Modifiers.VisibilityMask; - // If any of the modifiers is public, use that - if ((v & Modifiers.Public) == Modifiers.Public) - return Modifiers.Public | (m & ~Modifiers.VisibilityMask); - // If both modifiers are private, no need to fix anything - if (v == Modifiers.Private) - return m; - // Otherwise, use the other modifiers (internal and/or protected) - return m & ~Modifiers.Private; - } - - EntityDeclaration CreateProperty(PropertyDefinition propDef) - { - PropertyDeclaration astProp = new PropertyDeclaration(); - astProp.AddAnnotation(propDef); - var accessor = propDef.GetMethod ?? propDef.SetMethod; - Modifiers getterModifiers = Modifiers.None; - Modifiers setterModifiers = Modifiers.None; - if (IsExplicitInterfaceImplementation(accessor)) { - astProp.PrivateImplementationType = ConvertType(accessor.Overrides.First().DeclaringType); - } else if (!propDef.DeclaringType.IsInterface) { - getterModifiers = ConvertModifiers(propDef.GetMethod); - setterModifiers = ConvertModifiers(propDef.SetMethod); - astProp.Modifiers = FixUpVisibility(getterModifiers | setterModifiers); - try { - if (accessor.IsVirtual && !accessor.IsNewSlot && (propDef.GetMethod == null || propDef.SetMethod == null)) { - foreach (var basePropDef in TypesHierarchyHelpers.FindBaseProperties(propDef)) { - if (basePropDef.GetMethod != null && basePropDef.SetMethod != null) { - var propVisibilityModifiers = ConvertModifiers(basePropDef.GetMethod) | ConvertModifiers(basePropDef.SetMethod); - astProp.Modifiers = FixUpVisibility((astProp.Modifiers & ~Modifiers.VisibilityMask) | (propVisibilityModifiers & Modifiers.VisibilityMask)); - break; - } else if ((basePropDef.GetMethod ?? basePropDef.SetMethod).IsNewSlot) { - break; - } - } - } - } catch (ReferenceResolvingException) { - // TODO: add some kind of notification (a comment?) about possible problems with decompiled code due to unresolved references. - } - } - astProp.Name = CleanName(propDef.Name); - astProp.ReturnType = ConvertType(propDef.PropertyType, propDef); - - if (propDef.GetMethod != null) { - astProp.Getter = new Accessor(); - astProp.Getter.Body = CreateMethodBody(propDef.GetMethod); - astProp.Getter.AddAnnotation(propDef.GetMethod); - ConvertAttributes(astProp.Getter, propDef.GetMethod); - - if ((getterModifiers & Modifiers.VisibilityMask) != (astProp.Modifiers & Modifiers.VisibilityMask)) - astProp.Getter.Modifiers = getterModifiers & Modifiers.VisibilityMask; - } - if (propDef.SetMethod != null) { - astProp.Setter = new Accessor(); - astProp.Setter.Body = CreateMethodBody(propDef.SetMethod); - astProp.Setter.AddAnnotation(propDef.SetMethod); - ConvertAttributes(astProp.Setter, propDef.SetMethod); - ParameterDefinition lastParam = propDef.SetMethod.Parameters.LastOrDefault(); - if (lastParam != null) { - ConvertCustomAttributes(astProp.Setter, lastParam, "param"); - if (lastParam.HasMarshalInfo) { - astProp.Setter.Attributes.Add(new AttributeSection(ConvertMarshalInfo(lastParam, propDef.Module)) { AttributeTarget = "param" }); - } - } - - if ((setterModifiers & Modifiers.VisibilityMask) != (astProp.Modifiers & Modifiers.VisibilityMask)) - astProp.Setter.Modifiers = setterModifiers & Modifiers.VisibilityMask; - } - ConvertCustomAttributes(astProp, propDef); - - EntityDeclaration member = astProp; - if(propDef.IsIndexer()) - member = ConvertPropertyToIndexer(astProp, propDef); - if(!accessor.HasOverrides && !accessor.DeclaringType.IsInterface) - if (accessor.IsVirtual == accessor.IsNewSlot) - SetNewModifier(member); - return member; - } - - IndexerDeclaration ConvertPropertyToIndexer(PropertyDeclaration astProp, PropertyDefinition propDef) - { - var astIndexer = new IndexerDeclaration(); - astIndexer.CopyAnnotationsFrom(astProp); - astProp.Attributes.MoveTo(astIndexer.Attributes); - astIndexer.Modifiers = astProp.Modifiers; - astIndexer.PrivateImplementationType = astProp.PrivateImplementationType.Detach(); - astIndexer.ReturnType = astProp.ReturnType.Detach(); - astIndexer.Getter = astProp.Getter.Detach(); - astIndexer.Setter = astProp.Setter.Detach(); - astIndexer.Parameters.AddRange(MakeParameters(propDef.Parameters)); - return astIndexer; - } - - EntityDeclaration CreateEvent(EventDefinition eventDef) - { - if (eventDef.AddMethod != null && eventDef.AddMethod.IsAbstract) { - // An abstract event cannot be custom - EventDeclaration astEvent = new EventDeclaration(); - ConvertCustomAttributes(astEvent, eventDef); - astEvent.AddAnnotation(eventDef); - astEvent.Variables.Add(new VariableInitializer(CleanName(eventDef.Name))); - astEvent.ReturnType = ConvertType(eventDef.EventType, eventDef); - if (!eventDef.DeclaringType.IsInterface) - astEvent.Modifiers = ConvertModifiers(eventDef.AddMethod); - return astEvent; - } else { - CustomEventDeclaration astEvent = new CustomEventDeclaration(); - ConvertCustomAttributes(astEvent, eventDef); - astEvent.AddAnnotation(eventDef); - astEvent.Name = CleanName(eventDef.Name); - astEvent.ReturnType = ConvertType(eventDef.EventType, eventDef); - if (eventDef.AddMethod == null || !IsExplicitInterfaceImplementation(eventDef.AddMethod)) - astEvent.Modifiers = ConvertModifiers(eventDef.AddMethod); - else - astEvent.PrivateImplementationType = ConvertType(eventDef.AddMethod.Overrides.First().DeclaringType); - - if (eventDef.AddMethod != null) { - astEvent.AddAccessor = new Accessor { - Body = CreateMethodBody(eventDef.AddMethod) - }.WithAnnotation(eventDef.AddMethod); - ConvertAttributes(astEvent.AddAccessor, eventDef.AddMethod); - } - if (eventDef.RemoveMethod != null) { - astEvent.RemoveAccessor = new Accessor { - Body = CreateMethodBody(eventDef.RemoveMethod) - }.WithAnnotation(eventDef.RemoveMethod); - ConvertAttributes(astEvent.RemoveAccessor, eventDef.RemoveMethod); - } - MethodDefinition accessor = eventDef.AddMethod ?? eventDef.RemoveMethod; - if (accessor.IsVirtual == accessor.IsNewSlot) { - SetNewModifier(astEvent); - } - return astEvent; - } - } - - public bool DecompileMethodBodies { get; set; } - - BlockStatement CreateMethodBody(MethodDefinition method, IEnumerable parameters = null) - { - if (DecompileMethodBodies) - return AstMethodBodyBuilder.CreateMethodBody(method, context, parameters); - else - return null; - } - - FieldDeclaration CreateField(FieldDefinition fieldDef) - { - FieldDeclaration astField = new FieldDeclaration(); - astField.AddAnnotation(fieldDef); - VariableInitializer initializer = new VariableInitializer(CleanName(fieldDef.Name)); - astField.AddChild(initializer, Roles.Variable); - astField.ReturnType = ConvertType(fieldDef.FieldType, fieldDef); - astField.Modifiers = ConvertModifiers(fieldDef); - if (fieldDef.HasConstant) { - initializer.Initializer = CreateExpressionForConstant(fieldDef.Constant, fieldDef.FieldType, fieldDef.DeclaringType.IsEnum); - } - ConvertAttributes(astField, fieldDef); - SetNewModifier(astField); - return astField; - } - - static Expression CreateExpressionForConstant(object constant, TypeReference type, bool isEnumMemberDeclaration = false) - { - if (constant == null) { - if (type.IsValueType && !(type.Namespace == "System" && type.Name == "Nullable`1")) - return new DefaultValueExpression(ConvertType(type)); - else - return new NullReferenceExpression(); - } else { - TypeCode c = Type.GetTypeCode(constant.GetType()); - if (c >= TypeCode.SByte && c <= TypeCode.UInt64 && !isEnumMemberDeclaration) { - return MakePrimitive((long)CSharpPrimitiveCast.Cast(TypeCode.Int64, constant, false), type); - } else { - return new PrimitiveExpression(constant); - } - } - } - - public static IEnumerable MakeParameters(MethodDefinition method, bool isLambda = false) - { - var parameters = MakeParameters(method.Parameters, isLambda); - if (method.CallingConvention == MethodCallingConvention.VarArg) { - return parameters.Concat(new[] { new ParameterDeclaration { Type = new PrimitiveType("__arglist") } }); - } else { - return parameters; - } - } - - public static IEnumerable MakeParameters(IEnumerable paramCol, bool isLambda = false) - { - foreach(ParameterDefinition paramDef in paramCol) { - ParameterDeclaration astParam = new ParameterDeclaration(); - astParam.AddAnnotation(paramDef); - if (!(isLambda && paramDef.ParameterType.ContainsAnonymousType())) - astParam.Type = ConvertType(paramDef.ParameterType, paramDef); - astParam.Name = paramDef.Name; - - if (paramDef.ParameterType is ByReferenceType) { - astParam.ParameterModifier = (!paramDef.IsIn && paramDef.IsOut) ? ParameterModifier.Out : ParameterModifier.Ref; - ComposedType ct = astParam.Type as ComposedType; - if (ct != null && ct.PointerRank > 0) - ct.PointerRank--; - } - - if (paramDef.HasCustomAttributes) { - foreach (CustomAttribute ca in paramDef.CustomAttributes) { - if (ca.AttributeType.Name == "ParamArrayAttribute" && ca.AttributeType.Namespace == "System") - astParam.ParameterModifier = ParameterModifier.Params; - } - } - if (paramDef.IsOptional) { - astParam.DefaultExpression = CreateExpressionForConstant(paramDef.Constant, paramDef.ParameterType); - } - - ConvertCustomAttributes(astParam, paramDef); - ModuleDefinition module = ((MethodDefinition)paramDef.Method).Module; - if (paramDef.HasMarshalInfo) { - astParam.Attributes.Add(new AttributeSection(ConvertMarshalInfo(paramDef, module))); - } - if (astParam.ParameterModifier != ParameterModifier.Out) { - if (paramDef.IsIn) - astParam.Attributes.Add(new AttributeSection(CreateNonCustomAttribute(typeof(InAttribute), module))); - if (paramDef.IsOut) - astParam.Attributes.Add(new AttributeSection(CreateNonCustomAttribute(typeof(OutAttribute), module))); - } - yield return astParam; - } - } - - #region ConvertAttributes - void ConvertAttributes(EntityDeclaration attributedNode, TypeDefinition typeDefinition) - { - ConvertCustomAttributes(attributedNode, typeDefinition); - ConvertSecurityAttributes(attributedNode, typeDefinition); - - // Handle the non-custom attributes: - #region SerializableAttribute - if (typeDefinition.IsSerializable) - attributedNode.Attributes.Add(new AttributeSection(CreateNonCustomAttribute(typeof(SerializableAttribute)))); - #endregion - - #region ComImportAttribute - if (typeDefinition.IsImport) - attributedNode.Attributes.Add(new AttributeSection(CreateNonCustomAttribute(typeof(ComImportAttribute)))); - #endregion - - #region StructLayoutAttribute - LayoutKind layoutKind = LayoutKind.Auto; - switch (typeDefinition.Attributes & TypeAttributes.LayoutMask) { - case TypeAttributes.SequentialLayout: - layoutKind = LayoutKind.Sequential; - break; - case TypeAttributes.ExplicitLayout: - layoutKind = LayoutKind.Explicit; - break; - } - CharSet charSet = CharSet.None; - switch (typeDefinition.Attributes & TypeAttributes.StringFormatMask) { - case TypeAttributes.AnsiClass: - charSet = CharSet.Ansi; - break; - case TypeAttributes.AutoClass: - charSet = CharSet.Auto; - break; - case TypeAttributes.UnicodeClass: - charSet = CharSet.Unicode; - break; - } - LayoutKind defaultLayoutKind = (typeDefinition.IsValueType && !typeDefinition.IsEnum) ? LayoutKind.Sequential: LayoutKind.Auto; - if (layoutKind != defaultLayoutKind || charSet != CharSet.Ansi || typeDefinition.PackingSize > 0 || typeDefinition.ClassSize > 0) { - var structLayout = CreateNonCustomAttribute(typeof(StructLayoutAttribute)); - structLayout.Arguments.Add(new IdentifierExpression("LayoutKind").Member(layoutKind.ToString())); - if (charSet != CharSet.Ansi) { - structLayout.AddNamedArgument("CharSet", new IdentifierExpression("CharSet").Member(charSet.ToString())); - } - if (typeDefinition.PackingSize > 0) { - structLayout.AddNamedArgument("Pack", new PrimitiveExpression((int)typeDefinition.PackingSize)); - } - if (typeDefinition.ClassSize > 0) { - structLayout.AddNamedArgument("Size", new PrimitiveExpression((int)typeDefinition.ClassSize)); - } - attributedNode.Attributes.Add(new AttributeSection(structLayout)); - } - #endregion - } - - void ConvertAttributes(EntityDeclaration attributedNode, MethodDefinition methodDefinition) - { - ConvertCustomAttributes(attributedNode, methodDefinition); - ConvertSecurityAttributes(attributedNode, methodDefinition); - - MethodImplAttributes implAttributes = methodDefinition.ImplAttributes & ~MethodImplAttributes.CodeTypeMask; - - #region DllImportAttribute - if (methodDefinition.HasPInvokeInfo && methodDefinition.PInvokeInfo != null) { - PInvokeInfo info = methodDefinition.PInvokeInfo; - Ast.Attribute dllImport = CreateNonCustomAttribute(typeof(DllImportAttribute)); - dllImport.Arguments.Add(new PrimitiveExpression(info.Module.Name)); - - if (info.IsBestFitDisabled) - dllImport.AddNamedArgument("BestFitMapping", new PrimitiveExpression(false)); - if (info.IsBestFitEnabled) - dllImport.AddNamedArgument("BestFitMapping", new PrimitiveExpression(true)); - - CallingConvention callingConvention; - switch (info.Attributes & PInvokeAttributes.CallConvMask) { - case PInvokeAttributes.CallConvCdecl: - callingConvention = CallingConvention.Cdecl; - break; - case PInvokeAttributes.CallConvFastcall: - callingConvention = CallingConvention.FastCall; - break; - case PInvokeAttributes.CallConvStdCall: - callingConvention = CallingConvention.StdCall; - break; - case PInvokeAttributes.CallConvThiscall: - callingConvention = CallingConvention.ThisCall; - break; - case PInvokeAttributes.CallConvWinapi: - callingConvention = CallingConvention.Winapi; - break; - default: - throw new NotSupportedException("unknown calling convention"); - } - if (callingConvention != CallingConvention.Winapi) - dllImport.AddNamedArgument("CallingConvention", new IdentifierExpression("CallingConvention").Member(callingConvention.ToString())); - - CharSet charSet = CharSet.None; - switch (info.Attributes & PInvokeAttributes.CharSetMask) { - case PInvokeAttributes.CharSetAnsi: - charSet = CharSet.Ansi; - break; - case PInvokeAttributes.CharSetAuto: - charSet = CharSet.Auto; - break; - case PInvokeAttributes.CharSetUnicode: - charSet = CharSet.Unicode; - break; - } - if (charSet != CharSet.None) - dllImport.AddNamedArgument("CharSet", new IdentifierExpression("CharSet").Member(charSet.ToString())); - - if (!string.IsNullOrEmpty(info.EntryPoint) && info.EntryPoint != methodDefinition.Name) - dllImport.AddNamedArgument("EntryPoint", new PrimitiveExpression(info.EntryPoint)); - - if (info.IsNoMangle) - dllImport.AddNamedArgument("ExactSpelling", new PrimitiveExpression(true)); - - if ((implAttributes & MethodImplAttributes.PreserveSig) == MethodImplAttributes.PreserveSig) - implAttributes &= ~MethodImplAttributes.PreserveSig; - else - dllImport.AddNamedArgument("PreserveSig", new PrimitiveExpression(false)); - - if (info.SupportsLastError) - dllImport.AddNamedArgument("SetLastError", new PrimitiveExpression(true)); - - if (info.IsThrowOnUnmappableCharDisabled) - dllImport.AddNamedArgument("ThrowOnUnmappableChar", new PrimitiveExpression(false)); - if (info.IsThrowOnUnmappableCharEnabled) - dllImport.AddNamedArgument("ThrowOnUnmappableChar", new PrimitiveExpression(true)); - - attributedNode.Attributes.Add(new AttributeSection(dllImport)); - } - #endregion - - #region PreserveSigAttribute - if (implAttributes == MethodImplAttributes.PreserveSig) { - attributedNode.Attributes.Add(new AttributeSection(CreateNonCustomAttribute(typeof(PreserveSigAttribute)))); - implAttributes = 0; - } - #endregion - - #region MethodImplAttribute - if (implAttributes != 0) { - Ast.Attribute methodImpl = CreateNonCustomAttribute(typeof(MethodImplAttribute)); - TypeReference methodImplOptions = new TypeReference( - "System.Runtime.CompilerServices", "MethodImplOptions", - methodDefinition.Module, methodDefinition.Module.TypeSystem.Corlib); - methodImpl.Arguments.Add(MakePrimitive((long)implAttributes, methodImplOptions)); - attributedNode.Attributes.Add(new AttributeSection(methodImpl)); - } - #endregion - - ConvertAttributes(attributedNode, methodDefinition.MethodReturnType, methodDefinition.Module); - } - - void ConvertAttributes(EntityDeclaration attributedNode, MethodReturnType methodReturnType, ModuleDefinition module) - { - ConvertCustomAttributes(attributedNode, methodReturnType, "return"); - if (methodReturnType.HasMarshalInfo) { - var marshalInfo = ConvertMarshalInfo(methodReturnType, module); - attributedNode.Attributes.Add(new AttributeSection(marshalInfo) { AttributeTarget = "return" }); - } - } - - internal static void ConvertAttributes(EntityDeclaration attributedNode, FieldDefinition fieldDefinition, string attributeTarget = null) - { - ConvertCustomAttributes(attributedNode, fieldDefinition); - - #region FieldOffsetAttribute - if (fieldDefinition.HasLayoutInfo) { - Ast.Attribute fieldOffset = CreateNonCustomAttribute(typeof(FieldOffsetAttribute), fieldDefinition.Module); - fieldOffset.Arguments.Add(new PrimitiveExpression(fieldDefinition.Offset)); - attributedNode.Attributes.Add(new AttributeSection(fieldOffset) { AttributeTarget = attributeTarget }); - } - #endregion - - #region NonSerializedAttribute - if (fieldDefinition.IsNotSerialized) { - Ast.Attribute nonSerialized = CreateNonCustomAttribute(typeof(NonSerializedAttribute), fieldDefinition.Module); - attributedNode.Attributes.Add(new AttributeSection(nonSerialized) { AttributeTarget = attributeTarget }); - } - #endregion - - if (fieldDefinition.HasMarshalInfo) { - attributedNode.Attributes.Add(new AttributeSection(ConvertMarshalInfo(fieldDefinition, fieldDefinition.Module)) { AttributeTarget = attributeTarget }); - } - } - - #region MarshalAsAttribute (ConvertMarshalInfo) - static Ast.Attribute ConvertMarshalInfo(IMarshalInfoProvider marshalInfoProvider, ModuleDefinition module) - { - MarshalInfo marshalInfo = marshalInfoProvider.MarshalInfo; - Ast.Attribute attr = CreateNonCustomAttribute(typeof(MarshalAsAttribute), module); - var unmanagedType = new TypeReference("System.Runtime.InteropServices", "UnmanagedType", module, module.TypeSystem.Corlib); - attr.Arguments.Add(MakePrimitive((int)marshalInfo.NativeType, unmanagedType)); - - FixedArrayMarshalInfo fami = marshalInfo as FixedArrayMarshalInfo; - if (fami != null) { - attr.AddNamedArgument("SizeConst", new PrimitiveExpression(fami.Size)); - if (fami.ElementType != NativeType.None) - attr.AddNamedArgument("ArraySubType", MakePrimitive((int)fami.ElementType, unmanagedType)); - } - SafeArrayMarshalInfo sami = marshalInfo as SafeArrayMarshalInfo; - if (sami != null && sami.ElementType != VariantType.None) { - var varEnum = new TypeReference("System.Runtime.InteropServices", "VarEnum", module, module.TypeSystem.Corlib); - attr.AddNamedArgument("SafeArraySubType", MakePrimitive((int)sami.ElementType, varEnum)); - } - ArrayMarshalInfo ami = marshalInfo as ArrayMarshalInfo; - if (ami != null) { - if (ami.ElementType != NativeType.Max) - attr.AddNamedArgument("ArraySubType", MakePrimitive((int)ami.ElementType, unmanagedType)); - if (ami.Size >= 0) - attr.AddNamedArgument("SizeConst", new PrimitiveExpression(ami.Size)); - if (ami.SizeParameterMultiplier != 0 && ami.SizeParameterIndex >= 0) - attr.AddNamedArgument("SizeParamIndex", new PrimitiveExpression(ami.SizeParameterIndex)); - } - CustomMarshalInfo cmi = marshalInfo as CustomMarshalInfo; - if (cmi != null) { - attr.AddNamedArgument("MarshalType", new PrimitiveExpression(cmi.ManagedType.FullName)); - if (!string.IsNullOrEmpty(cmi.Cookie)) - attr.AddNamedArgument("MarshalCookie", new PrimitiveExpression(cmi.Cookie)); - } - FixedSysStringMarshalInfo fssmi = marshalInfo as FixedSysStringMarshalInfo; - if (fssmi != null) { - attr.AddNamedArgument("SizeConst", new PrimitiveExpression(fssmi.Size)); - } - return attr; - } - #endregion - - Ast.Attribute CreateNonCustomAttribute(Type attributeType) - { - return CreateNonCustomAttribute(attributeType, context.CurrentType != null ? context.CurrentType.Module : null); - } - - static Ast.Attribute CreateNonCustomAttribute(Type attributeType, ModuleDefinition module) - { - Debug.Assert(attributeType.Name.EndsWith("Attribute", StringComparison.Ordinal)); - Ast.Attribute attr = new Ast.Attribute(); - attr.Type = new SimpleType(attributeType.Name.Substring(0, attributeType.Name.Length - "Attribute".Length)); - if (module != null) { - attr.Type.AddAnnotation(new TypeReference(attributeType.Namespace, attributeType.Name, module, module.TypeSystem.Corlib)); - } - return attr; - } - - static void ConvertCustomAttributes(AstNode attributedNode, ICustomAttributeProvider customAttributeProvider, string attributeTarget = null) - { - EntityDeclaration entityDecl = attributedNode as EntityDeclaration; - if (customAttributeProvider.HasCustomAttributes) { - var attributes = new List(); - foreach (var customAttribute in customAttributeProvider.CustomAttributes.OrderBy(a => a.AttributeType.FullName)) { - if (customAttribute.AttributeType.Name == "ExtensionAttribute" && customAttribute.AttributeType.Namespace == "System.Runtime.CompilerServices") { - // don't show the ExtensionAttribute (it's converted to the 'this' modifier) - continue; - } - if (customAttribute.AttributeType.Name == "ParamArrayAttribute" && customAttribute.AttributeType.Namespace == "System") { - // don't show the ParamArrayAttribute (it's converted to the 'params' modifier) - continue; - } - // if the method is async, remove [DebuggerStepThrough] and [Async - if (entityDecl != null && entityDecl.HasModifier(Modifiers.Async)) { - if (customAttribute.AttributeType.Name == "DebuggerStepThroughAttribute" && customAttribute.AttributeType.Namespace == "System.Diagnostics") { - continue; - } - if (customAttribute.AttributeType.Name == "AsyncStateMachineAttribute" && customAttribute.AttributeType.Namespace == "System.Runtime.CompilerServices") { - continue; - } - } - - var attribute = new NRefactory.CSharp.Attribute(); - attribute.AddAnnotation(customAttribute); - attribute.Type = ConvertType(customAttribute.AttributeType); - attributes.Add(attribute); - - SimpleType st = attribute.Type as SimpleType; - if (st != null && st.Identifier.EndsWith("Attribute", StringComparison.Ordinal)) { - st.Identifier = st.Identifier.Substring(0, st.Identifier.Length - "Attribute".Length); - } - - if(customAttribute.HasConstructorArguments) { - foreach (var parameter in customAttribute.ConstructorArguments) { - Expression parameterValue = ConvertArgumentValue(parameter); - attribute.Arguments.Add(parameterValue); - } - } - if (customAttribute.HasProperties) { - TypeDefinition resolvedAttributeType = customAttribute.AttributeType.Resolve(); - foreach (var propertyNamedArg in customAttribute.Properties) { - var propertyReference = resolvedAttributeType != null ? resolvedAttributeType.Properties.FirstOrDefault(pr => pr.Name == propertyNamedArg.Name) : null; - var propertyName = new IdentifierExpression(propertyNamedArg.Name).WithAnnotation(propertyReference); - var argumentValue = ConvertArgumentValue(propertyNamedArg.Argument); - attribute.Arguments.Add(new AssignmentExpression(propertyName, argumentValue)); - } - } - - if (customAttribute.HasFields) { - TypeDefinition resolvedAttributeType = customAttribute.AttributeType.Resolve(); - foreach (var fieldNamedArg in customAttribute.Fields) { - var fieldReference = resolvedAttributeType != null ? resolvedAttributeType.Fields.FirstOrDefault(f => f.Name == fieldNamedArg.Name) : null; - var fieldName = new IdentifierExpression(fieldNamedArg.Name).WithAnnotation(fieldReference); - var argumentValue = ConvertArgumentValue(fieldNamedArg.Argument); - attribute.Arguments.Add(new AssignmentExpression(fieldName, argumentValue)); - } - } - } - - if (attributeTarget == "module" || attributeTarget == "assembly") { - // use separate section for each attribute - foreach (var attribute in attributes) { - var section = new AttributeSection(); - section.AttributeTarget = attributeTarget; - section.Attributes.Add(attribute); - attributedNode.AddChild(section, EntityDeclaration.AttributeRole); - } - } else if (attributes.Count > 0) { - // use single section for all attributes - var section = new AttributeSection(); - section.AttributeTarget = attributeTarget; - section.Attributes.AddRange(attributes); - attributedNode.AddChild(section, EntityDeclaration.AttributeRole); - } - } - } - - static void ConvertSecurityAttributes(AstNode attributedNode, ISecurityDeclarationProvider secDeclProvider, string attributeTarget = null) - { - if (!secDeclProvider.HasSecurityDeclarations) - return; - var attributes = new List(); - foreach (var secDecl in secDeclProvider.SecurityDeclarations.OrderBy(d => d.Action)) { - foreach (var secAttribute in secDecl.SecurityAttributes.OrderBy(a => a.AttributeType.FullName)) { - var attribute = new NRefactory.CSharp.Attribute(); - attribute.AddAnnotation(secAttribute); - attribute.Type = ConvertType(secAttribute.AttributeType); - attributes.Add(attribute); - - SimpleType st = attribute.Type as SimpleType; - if (st != null && st.Identifier.EndsWith("Attribute", StringComparison.Ordinal)) { - st.Identifier = st.Identifier.Substring(0, st.Identifier.Length - "Attribute".Length); - } - - var module = secAttribute.AttributeType.Module; - var securityActionType = new TypeReference("System.Security.Permissions", "SecurityAction", module, module.TypeSystem.Corlib); - attribute.Arguments.Add(MakePrimitive((int)secDecl.Action, securityActionType)); - - if (secAttribute.HasProperties) { - TypeDefinition resolvedAttributeType = secAttribute.AttributeType.Resolve(); - foreach (var propertyNamedArg in secAttribute.Properties) { - var propertyReference = resolvedAttributeType != null ? resolvedAttributeType.Properties.FirstOrDefault(pr => pr.Name == propertyNamedArg.Name) : null; - var propertyName = new IdentifierExpression(propertyNamedArg.Name).WithAnnotation(propertyReference); - var argumentValue = ConvertArgumentValue(propertyNamedArg.Argument); - attribute.Arguments.Add(new AssignmentExpression(propertyName, argumentValue)); - } - } - - if (secAttribute.HasFields) { - TypeDefinition resolvedAttributeType = secAttribute.AttributeType.Resolve(); - foreach (var fieldNamedArg in secAttribute.Fields) { - var fieldReference = resolvedAttributeType != null ? resolvedAttributeType.Fields.FirstOrDefault(f => f.Name == fieldNamedArg.Name) : null; - var fieldName = new IdentifierExpression(fieldNamedArg.Name).WithAnnotation(fieldReference); - var argumentValue = ConvertArgumentValue(fieldNamedArg.Argument); - attribute.Arguments.Add(new AssignmentExpression(fieldName, argumentValue)); - } - } - } - } - if (attributeTarget == "module" || attributeTarget == "assembly") { - // use separate section for each attribute - foreach (var attribute in attributes) { - var section = new AttributeSection(); - section.AttributeTarget = attributeTarget; - section.Attributes.Add(attribute); - attributedNode.AddChild(section, EntityDeclaration.AttributeRole); - } - } else if (attributes.Count > 0) { - // use single section for all attributes - var section = new AttributeSection(); - section.AttributeTarget = attributeTarget; - section.Attributes.AddRange(attributes); - attributedNode.AddChild(section, EntityDeclaration.AttributeRole); - } - } - - static Expression ConvertArgumentValue(CustomAttributeArgument argument) - { - if (argument.Value is CustomAttributeArgument[]) { - ArrayInitializerExpression arrayInit = new ArrayInitializerExpression(); - foreach (CustomAttributeArgument element in (CustomAttributeArgument[])argument.Value) { - arrayInit.Elements.Add(ConvertArgumentValue(element)); - } - ArrayType arrayType = argument.Type as ArrayType; - return new ArrayCreateExpression { - Type = ConvertType(arrayType != null ? arrayType.ElementType : argument.Type), - AdditionalArraySpecifiers = { new ArraySpecifier() }, - Initializer = arrayInit - }; - } else if (argument.Value is CustomAttributeArgument) { - // occurs with boxed arguments - return ConvertArgumentValue((CustomAttributeArgument)argument.Value); - } - var type = argument.Type.Resolve(); - if (type != null && type.IsEnum) { - return MakePrimitive(Convert.ToInt64(argument.Value), type); - } else if (argument.Value is TypeReference) { - return CreateTypeOfExpression((TypeReference)argument.Value); - } else { - return new PrimitiveExpression(argument.Value); - } - } - #endregion - - internal static Expression MakePrimitive(long val, TypeReference type) - { - if (TypeAnalysis.IsBoolean(type) && val == 0) - return new PrimitiveExpression(false); - else if (TypeAnalysis.IsBoolean(type) && val == 1) - return new PrimitiveExpression(true); - else if (val == 0 && type is PointerType) - return new NullReferenceExpression(); - if (type != null) - { // cannot rely on type.IsValueType, it's not set for typerefs (but is set for typespecs) - TypeDefinition enumDefinition = type.Resolve(); - if (enumDefinition != null && enumDefinition.IsEnum) { - TypeCode enumBaseTypeCode = TypeCode.Int32; - foreach (FieldDefinition field in enumDefinition.Fields) { - if (field.IsStatic && Equals(CSharpPrimitiveCast.Cast(TypeCode.Int64, field.Constant, false), val)) - return ConvertType(type).Member(field.Name).WithAnnotation(field); - else if (!field.IsStatic) - enumBaseTypeCode = TypeAnalysis.GetTypeCode(field.FieldType); // use primitive type of the enum - } - if (IsFlagsEnum(enumDefinition)) { - long enumValue = val; - Expression expr = null; - long negatedEnumValue = ~val; - // limit negatedEnumValue to the appropriate range - switch (enumBaseTypeCode) { - case TypeCode.Byte: - case TypeCode.SByte: - negatedEnumValue &= byte.MaxValue; - break; - case TypeCode.Int16: - case TypeCode.UInt16: - negatedEnumValue &= ushort.MaxValue; - break; - case TypeCode.Int32: - case TypeCode.UInt32: - negatedEnumValue &= uint.MaxValue; - break; - } - Expression negatedExpr = null; - foreach (FieldDefinition field in enumDefinition.Fields.Where(fld => fld.IsStatic)) { - long fieldValue = (long)CSharpPrimitiveCast.Cast(TypeCode.Int64, field.Constant, false); - if (fieldValue == 0) - continue; // skip None enum value - - if ((fieldValue & enumValue) == fieldValue) { - var fieldExpression = ConvertType(type).Member(field.Name).WithAnnotation(field); - if (expr == null) - expr = fieldExpression; - else - expr = new BinaryOperatorExpression(expr, BinaryOperatorType.BitwiseOr, fieldExpression); - - enumValue &= ~fieldValue; - } - if ((fieldValue & negatedEnumValue) == fieldValue) { - var fieldExpression = ConvertType(type).Member(field.Name).WithAnnotation(field); - if (negatedExpr == null) - negatedExpr = fieldExpression; - else - negatedExpr = new BinaryOperatorExpression(negatedExpr, BinaryOperatorType.BitwiseOr, fieldExpression); - - negatedEnumValue &= ~fieldValue; - } - } - if (enumValue == 0 && expr != null) { - if (!(negatedEnumValue == 0 && negatedExpr != null && negatedExpr.Descendants.Count() < expr.Descendants.Count())) { - return expr; - } - } - if (negatedEnumValue == 0 && negatedExpr != null) { - return new UnaryOperatorExpression(UnaryOperatorType.BitNot, negatedExpr); - } - } - return new PrimitiveExpression(CSharpPrimitiveCast.Cast(enumBaseTypeCode, val, false)).CastTo(ConvertType(type)); - } - } - TypeCode code = TypeAnalysis.GetTypeCode(type); - if (code == TypeCode.Object || code == TypeCode.Empty) - code = TypeCode.Int32; - return new PrimitiveExpression(CSharpPrimitiveCast.Cast(code, val, false)); - } - - static bool IsFlagsEnum(TypeDefinition type) - { - if (!type.HasCustomAttributes) - return false; - - return type.CustomAttributes.Any(attr => attr.AttributeType.FullName == "System.FlagsAttribute"); - } - - /// - /// Sets new modifier if the member hides some other member from a base type. - /// - /// The node of the member which new modifier state should be determined. - static void SetNewModifier(EntityDeclaration member) - { - try { - bool addNewModifier = false; - if (member is IndexerDeclaration) { - var propertyDef = member.Annotation(); - var baseProperties = - TypesHierarchyHelpers.FindBaseProperties(propertyDef); - addNewModifier = baseProperties.Any(); - } else - addNewModifier = HidesBaseMember(member); - - if (addNewModifier) - member.Modifiers |= Modifiers.New; - } - catch (ReferenceResolvingException) { - // TODO: add some kind of notification (a comment?) about possible problems with decompiled code due to unresolved references. - } - } - - static bool HidesBaseMember(EntityDeclaration member) - { - var memberDefinition = member.Annotation(); - bool addNewModifier = false; - var methodDefinition = memberDefinition as MethodDefinition; - if (methodDefinition != null) { - addNewModifier = HidesByName(memberDefinition, includeBaseMethods: false); - if (!addNewModifier) - addNewModifier = TypesHierarchyHelpers.FindBaseMethods(methodDefinition).Any(); - } else - addNewModifier = HidesByName(memberDefinition, includeBaseMethods: true); - return addNewModifier; - } - - /// - /// Determines whether any base class member has the same name as the given member. - /// - /// The derived type's member. - /// true if names of methods declared in base types should also be checked. - /// true if any base member has the same name as given member, otherwise false. - static bool HidesByName(IMemberDefinition member, bool includeBaseMethods) - { - Debug.Assert(!(member is PropertyDefinition) || !((PropertyDefinition)member).IsIndexer()); - - if (member.DeclaringType.BaseType != null) { - var baseTypeRef = member.DeclaringType.BaseType; - while (baseTypeRef != null) { -#pragma warning disable 618 - var baseType = baseTypeRef.ResolveOrThrow(); -#pragma warning restore 618 - if (baseType.HasProperties && AnyIsHiddenBy(baseType.Properties, member, m => !m.IsIndexer())) - return true; - if (baseType.HasEvents && AnyIsHiddenBy(baseType.Events, member)) - return true; - if (baseType.HasFields && AnyIsHiddenBy(baseType.Fields, member)) - return true; - if (includeBaseMethods && baseType.HasMethods - && AnyIsHiddenBy(baseType.Methods, member, m => !m.IsSpecialName)) - return true; - if (baseType.HasNestedTypes && AnyIsHiddenBy(baseType.NestedTypes, member)) - return true; - baseTypeRef = baseType.BaseType; - } - } - return false; - } - - static bool AnyIsHiddenBy(IEnumerable members, IMemberDefinition derived, Predicate condition = null) - where T : IMemberDefinition - { - return members.Any(m => m.Name == derived.Name - && (condition == null || condition(m)) - && TypesHierarchyHelpers.IsVisibleFromDerived(m, derived.DeclaringType)); - } - } -} diff --git a/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs b/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs deleted file mode 100644 index a4d80e59..00000000 --- a/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs +++ /dev/null @@ -1,1220 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Threading; - -using ICSharpCode.Decompiler.Ast.Transforms; -using ICSharpCode.Decompiler.ILAst; -using ICSharpCode.NRefactory.CSharp; -using ICSharpCode.NRefactory.PatternMatching; -using ICSharpCode.NRefactory.Utils; -using Mono.Cecil; -using Mono.Cecil.Cil; - -namespace ICSharpCode.Decompiler.Ast -{ - using Ast = NRefactory.CSharp; - using Cecil = Mono.Cecil; - - public class AstMethodBodyBuilder - { - MethodDefinition methodDef; - TypeSystem typeSystem; - DecompilerContext context; - HashSet localVariablesToDefine = new HashSet(); // local variables that are missing a definition - - /// - /// Creates the body for the method definition. - /// - /// Method definition to decompile. - /// Decompilation context. - /// Parameter declarations of the method being decompiled. - /// These are used to update the parameter names when the decompiler generates names for the parameters. - /// Block for the method body - public static BlockStatement CreateMethodBody(MethodDefinition methodDef, - DecompilerContext context, - IEnumerable parameters = null) - { - MethodDefinition oldCurrentMethod = context.CurrentMethod; - Debug.Assert(oldCurrentMethod == null || oldCurrentMethod == methodDef); - context.CurrentMethod = methodDef; - context.CurrentMethodIsAsync = false; - try { - AstMethodBodyBuilder builder = new AstMethodBodyBuilder(); - builder.methodDef = methodDef; - builder.context = context; - builder.typeSystem = methodDef.Module.TypeSystem; - if (Debugger.IsAttached) { - return builder.CreateMethodBody(parameters); - } else { - try { - return builder.CreateMethodBody(parameters); - } catch (OperationCanceledException) { - throw; - } catch (Exception ex) { - throw new DecompilerException(methodDef, ex); - } - } - } finally { - context.CurrentMethod = oldCurrentMethod; - } - } - - public BlockStatement CreateMethodBody(IEnumerable parameters) - { - if (methodDef.Body == null) { - return null; - } - - context.CancellationToken.ThrowIfCancellationRequested(); - ILBlock ilMethod = new ILBlock(); - ILAstBuilder astBuilder = new ILAstBuilder(); - ilMethod.Body = astBuilder.Build(methodDef, true, context); - - context.CancellationToken.ThrowIfCancellationRequested(); - ILAstOptimizer bodyGraph = new ILAstOptimizer(); - bodyGraph.Optimize(context, ilMethod); - context.CancellationToken.ThrowIfCancellationRequested(); - - var localVariables = ilMethod.GetSelfAndChildrenRecursive().Select(e => e.Operand as ILVariable) - .Where(v => v != null && !v.IsParameter).Distinct(); - Debug.Assert(context.CurrentMethod == methodDef); - NameVariables.AssignNamesToVariables(context, astBuilder.Parameters, localVariables, ilMethod); - - if (parameters != null) { - foreach (var pair in (from p in parameters - join v in astBuilder.Parameters on p.Annotation() equals v.OriginalParameter - select new { p, v.Name })) - { - pair.p.Name = pair.Name; - } - } - - context.CancellationToken.ThrowIfCancellationRequested(); - BlockStatement astBlock = TransformBlock(ilMethod); - CommentStatement.ReplaceAll(astBlock); // convert CommentStatements to Comments - - Statement insertionPoint = astBlock.Statements.FirstOrDefault(); - foreach (ILVariable v in localVariablesToDefine) { - AstType type; - if (v.Type.ContainsAnonymousType()) - type = new SimpleType("var"); - else - type = AstBuilder.ConvertType(v.Type); - var newVarDecl = new VariableDeclarationStatement(type, v.Name); - newVarDecl.Variables.Single().AddAnnotation(v); - astBlock.Statements.InsertBefore(insertionPoint, newVarDecl); - } - - astBlock.AddAnnotation(new MethodDebugSymbols(methodDef) { LocalVariables = localVariables.ToList() }); - - return astBlock; - } - - BlockStatement TransformBlock(ILBlock block) - { - BlockStatement astBlock = new BlockStatement(); - if (block != null) { - foreach(ILNode node in block.GetChildren()) { - astBlock.Statements.AddRange(TransformNode(node)); - } - } - return astBlock; - } - - IEnumerable TransformNode(ILNode node) - { - if (node is ILLabel) { - yield return new LabelStatement { Label = ((ILLabel)node).Name }; - } else if (node is ILExpression) { - List ilRanges = ILRange.OrderAndJoin(node.GetSelfAndChildrenRecursive().SelectMany(e => e.ILRanges)); - AstNode codeExpr = TransformExpression((ILExpression)node); - if (codeExpr != null) { - codeExpr = codeExpr.WithAnnotation(ilRanges); - if (codeExpr is Expression) { - yield return new ExpressionStatement { Expression = (Expression)codeExpr }; - } else if (codeExpr is Statement) { - yield return (Statement)codeExpr; - } else { - throw new Exception(); - } - } - } else if (node is ILWhileLoop) { - ILWhileLoop ilLoop = (ILWhileLoop)node; - WhileStatement whileStmt = new WhileStatement() { - Condition = ilLoop.Condition != null ? (Expression)TransformExpression(ilLoop.Condition) : new PrimitiveExpression(true), - EmbeddedStatement = TransformBlock(ilLoop.BodyBlock) - }; - yield return whileStmt; - } else if (node is ILCondition) { - ILCondition conditionalNode = (ILCondition)node; - bool hasFalseBlock = conditionalNode.FalseBlock.EntryGoto != null || conditionalNode.FalseBlock.Body.Count > 0; - yield return new IfElseStatement { - Condition = (Expression)TransformExpression(conditionalNode.Condition), - TrueStatement = TransformBlock(conditionalNode.TrueBlock), - FalseStatement = hasFalseBlock ? TransformBlock(conditionalNode.FalseBlock) : null - }; - } else if (node is ILSwitch) { - ILSwitch ilSwitch = (ILSwitch)node; - if (TypeAnalysis.IsBoolean(ilSwitch.Condition.InferredType) && ( - from cb in ilSwitch.CaseBlocks - where cb.Values != null - from val in cb.Values - select val - ).Any(val => val != 0 && val != 1)) - { - // If switch cases contain values other then 0 and 1, force the condition to be non-boolean - ilSwitch.Condition.ExpectedType = typeSystem.Int32; - } - SwitchStatement switchStmt = new SwitchStatement() { Expression = (Expression)TransformExpression(ilSwitch.Condition) }; - foreach (var caseBlock in ilSwitch.CaseBlocks) { - SwitchSection section = new SwitchSection(); - if (caseBlock.Values != null) { - section.CaseLabels.AddRange(caseBlock.Values.Select(i => new CaseLabel() { Expression = AstBuilder.MakePrimitive(i, ilSwitch.Condition.ExpectedType ?? ilSwitch.Condition.InferredType) })); - } else { - section.CaseLabels.Add(new CaseLabel()); - } - section.Statements.Add(TransformBlock(caseBlock)); - switchStmt.SwitchSections.Add(section); - } - yield return switchStmt; - } else if (node is ILTryCatchBlock) { - ILTryCatchBlock tryCatchNode = ((ILTryCatchBlock)node); - var tryCatchStmt = new TryCatchStatement(); - tryCatchStmt.TryBlock = TransformBlock(tryCatchNode.TryBlock); - foreach (var catchClause in tryCatchNode.CatchBlocks) { - if (catchClause.ExceptionVariable == null - && (catchClause.ExceptionType == null || catchClause.ExceptionType.MetadataType == MetadataType.Object)) - { - tryCatchStmt.CatchClauses.Add(new CatchClause { Body = TransformBlock(catchClause) }); - } else { - tryCatchStmt.CatchClauses.Add( - new CatchClause { - Type = AstBuilder.ConvertType(catchClause.ExceptionType), - VariableName = catchClause.ExceptionVariable == null ? null : catchClause.ExceptionVariable.Name, - Body = TransformBlock(catchClause) - }.WithAnnotation(catchClause.ExceptionVariable)); - } - } - if (tryCatchNode.FinallyBlock != null) - tryCatchStmt.FinallyBlock = TransformBlock(tryCatchNode.FinallyBlock); - if (tryCatchNode.FaultBlock != null) { - CatchClause cc = new CatchClause(); - cc.Body = TransformBlock(tryCatchNode.FaultBlock); - cc.Body.Add(new ThrowStatement()); // rethrow - tryCatchStmt.CatchClauses.Add(cc); - } - yield return tryCatchStmt; - } else if (node is ILFixedStatement) { - ILFixedStatement fixedNode = (ILFixedStatement)node; - FixedStatement fixedStatement = new FixedStatement(); - foreach (ILExpression initializer in fixedNode.Initializers) { - Debug.Assert(initializer.Code == ILCode.Stloc); - ILVariable v = (ILVariable)initializer.Operand; - fixedStatement.Variables.Add( - new VariableInitializer { - Name = v.Name, - Initializer = (Expression)TransformExpression(initializer.Arguments[0]) - }.WithAnnotation(v)); - } - fixedStatement.Type = AstBuilder.ConvertType(((ILVariable)fixedNode.Initializers[0].Operand).Type); - fixedStatement.EmbeddedStatement = TransformBlock(fixedNode.BodyBlock); - yield return fixedStatement; - } else if (node is ILBlock) { - yield return TransformBlock((ILBlock)node); - } else { - throw new Exception("Unknown node type"); - } - } - - AstNode TransformExpression(ILExpression expr) - { - AstNode node = TransformByteCode(expr); - Expression astExpr = node as Expression; - - // get IL ranges - used in debugger - List ilRanges = ILRange.OrderAndJoin(expr.GetSelfAndChildrenRecursive().SelectMany(e => e.ILRanges)); - AstNode result; - - if (astExpr != null) - result = Convert(astExpr, expr.InferredType, expr.ExpectedType); - else - result = node; - - if (result != null) - result = result.WithAnnotation(new TypeInformation(expr.InferredType, expr.ExpectedType)); - - if (result != null) - return result.WithAnnotation(ilRanges); - - return result; - } - - AstNode TransformByteCode(ILExpression byteCode) - { - object operand = byteCode.Operand; - AstType operandAsTypeRef = AstBuilder.ConvertType(operand as TypeReference); - - List args = new List(); - foreach(ILExpression arg in byteCode.Arguments) { - args.Add((Expression)TransformExpression(arg)); - } - Expression arg1 = args.Count >= 1 ? args[0] : null; - Expression arg2 = args.Count >= 2 ? args[1] : null; - Expression arg3 = args.Count >= 3 ? args[2] : null; - - switch (byteCode.Code) { - #region Arithmetic - case ILCode.Add: - case ILCode.Add_Ovf: - case ILCode.Add_Ovf_Un: - { - BinaryOperatorExpression boe; - if (byteCode.InferredType is PointerType) { - boe = new BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2); - if (byteCode.Arguments[0].ExpectedType is PointerType || - byteCode.Arguments[1].ExpectedType is PointerType) { - boe.AddAnnotation(IntroduceUnsafeModifier.PointerArithmeticAnnotation); - } - } else { - boe = new BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2); - } - boe.AddAnnotation(byteCode.Code == ILCode.Add ? AddCheckedBlocks.UncheckedAnnotation : AddCheckedBlocks.CheckedAnnotation); - return boe; - } - case ILCode.Sub: - case ILCode.Sub_Ovf: - case ILCode.Sub_Ovf_Un: - { - BinaryOperatorExpression boe; - if (byteCode.InferredType is PointerType) { - boe = new BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2); - if (byteCode.Arguments[0].ExpectedType is PointerType) { - boe.WithAnnotation(IntroduceUnsafeModifier.PointerArithmeticAnnotation); - } - } else { - boe = new BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2); - } - boe.AddAnnotation(byteCode.Code == ILCode.Sub ? AddCheckedBlocks.UncheckedAnnotation : AddCheckedBlocks.CheckedAnnotation); - return boe; - } - case ILCode.Div: return new BinaryOperatorExpression(arg1, BinaryOperatorType.Divide, arg2); - case ILCode.Div_Un: return new BinaryOperatorExpression(arg1, BinaryOperatorType.Divide, arg2); - case ILCode.Mul: return new BinaryOperatorExpression(arg1, BinaryOperatorType.Multiply, arg2).WithAnnotation(AddCheckedBlocks.UncheckedAnnotation); - case ILCode.Mul_Ovf: return new BinaryOperatorExpression(arg1, BinaryOperatorType.Multiply, arg2).WithAnnotation(AddCheckedBlocks.CheckedAnnotation); - case ILCode.Mul_Ovf_Un: return new BinaryOperatorExpression(arg1, BinaryOperatorType.Multiply, arg2).WithAnnotation(AddCheckedBlocks.CheckedAnnotation); - case ILCode.Rem: return new BinaryOperatorExpression(arg1, BinaryOperatorType.Modulus, arg2); - case ILCode.Rem_Un: return new BinaryOperatorExpression(arg1, BinaryOperatorType.Modulus, arg2); - case ILCode.And: return new BinaryOperatorExpression(arg1, BinaryOperatorType.BitwiseAnd, arg2); - case ILCode.Or: return new BinaryOperatorExpression(arg1, BinaryOperatorType.BitwiseOr, arg2); - case ILCode.Xor: return new BinaryOperatorExpression(arg1, BinaryOperatorType.ExclusiveOr, arg2); - case ILCode.Shl: return new BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftLeft, arg2); - case ILCode.Shr: return new BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftRight, arg2); - case ILCode.Shr_Un: return new BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftRight, arg2); - case ILCode.Neg: return new UnaryOperatorExpression(UnaryOperatorType.Minus, arg1).WithAnnotation(AddCheckedBlocks.UncheckedAnnotation); - case ILCode.Not: return new UnaryOperatorExpression(UnaryOperatorType.BitNot, arg1); - case ILCode.PostIncrement: - case ILCode.PostIncrement_Ovf: - case ILCode.PostIncrement_Ovf_Un: - { - if (arg1 is DirectionExpression) - arg1 = ((DirectionExpression)arg1).Expression.Detach(); - var uoe = new UnaryOperatorExpression( - (int)byteCode.Operand > 0 ? UnaryOperatorType.PostIncrement : UnaryOperatorType.PostDecrement, arg1); - uoe.AddAnnotation((byteCode.Code == ILCode.PostIncrement) ? AddCheckedBlocks.UncheckedAnnotation : AddCheckedBlocks.CheckedAnnotation); - return uoe; - } - #endregion - #region Arrays - case ILCode.Newarr: { - var ace = new ArrayCreateExpression(); - ace.Type = operandAsTypeRef; - ComposedType ct = operandAsTypeRef as ComposedType; - if (ct != null) { - // change "new (int[,])[10] to new int[10][,]" - ct.ArraySpecifiers.MoveTo(ace.AdditionalArraySpecifiers); - } - if (byteCode.Code == ILCode.InitArray) { - ace.Initializer = new ArrayInitializerExpression(); - ace.Initializer.Elements.AddRange(args); - } else { - ace.Arguments.Add(arg1); - } - return ace; - } - case ILCode.InitArray: { - var ace = new ArrayCreateExpression(); - ace.Type = operandAsTypeRef; - ComposedType ct = operandAsTypeRef as ComposedType; - var arrayType = (ArrayType) operand; - if (ct != null) - { - // change "new (int[,])[10] to new int[10][,]" - ct.ArraySpecifiers.MoveTo(ace.AdditionalArraySpecifiers); - ace.Initializer = new ArrayInitializerExpression(); - } - var newArgs = new List(); - foreach (var arrayDimension in arrayType.Dimensions.Skip(1).Reverse()) - { - int length = (int)arrayDimension.UpperBound - (int)arrayDimension.LowerBound; - for (int j = 0; j < args.Count; j += length) - { - var child = new ArrayInitializerExpression(); - child.Elements.AddRange(args.GetRange(j, length)); - newArgs.Add(child); - } - var temp = args; - args = newArgs; - newArgs = temp; - newArgs.Clear(); - } - ace.Initializer.Elements.AddRange(args); - return ace; - } - case ILCode.Ldlen: return arg1.Member("Length"); - case ILCode.Ldelem_I: - case ILCode.Ldelem_I1: - case ILCode.Ldelem_I2: - case ILCode.Ldelem_I4: - case ILCode.Ldelem_I8: - case ILCode.Ldelem_U1: - case ILCode.Ldelem_U2: - case ILCode.Ldelem_U4: - case ILCode.Ldelem_R4: - case ILCode.Ldelem_R8: - case ILCode.Ldelem_Ref: - case ILCode.Ldelem_Any: - return arg1.Indexer(arg2); - case ILCode.Ldelema: - return MakeRef(arg1.Indexer(arg2)); - case ILCode.Stelem_I: - case ILCode.Stelem_I1: - case ILCode.Stelem_I2: - case ILCode.Stelem_I4: - case ILCode.Stelem_I8: - case ILCode.Stelem_R4: - case ILCode.Stelem_R8: - case ILCode.Stelem_Ref: - case ILCode.Stelem_Any: - return new AssignmentExpression(arg1.Indexer(arg2), arg3); - case ILCode.CompoundAssignment: - { - CastExpression cast = arg1 as CastExpression; - var boe = cast != null ? (BinaryOperatorExpression)cast.Expression : arg1 as BinaryOperatorExpression; - // AssignmentExpression doesn't support overloaded operators so they have to be processed to BinaryOperatorExpression - if (boe == null) { - var tmp = new ParenthesizedExpression(arg1); - ReplaceMethodCallsWithOperators.ProcessInvocationExpression((InvocationExpression)arg1); - boe = (BinaryOperatorExpression)tmp.Expression; - } - var assignment = new AssignmentExpression { - Left = boe.Left.Detach(), - Operator = ReplaceMethodCallsWithOperators.GetAssignmentOperatorForBinaryOperator(boe.Operator), - Right = boe.Right.Detach() - }.CopyAnnotationsFrom(boe); - // We do not mark the resulting assignment as RestoreOriginalAssignOperatorAnnotation, because - // the operator cannot be translated back to the expanded form (as the left-hand expression - // would be evaluated twice, and might have side-effects) - if (cast != null) { - cast.Expression = assignment; - return cast; - } else { - return assignment; - } - } - #endregion - #region Comparison - case ILCode.Ceq: return new BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2); - case ILCode.Cne: return new BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, arg2); - case ILCode.Cgt: return new BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2); - case ILCode.Cgt_Un: { - // can also mean Inequality, when used with object references - TypeReference arg1Type = byteCode.Arguments[0].InferredType; - if (arg1Type != null && !arg1Type.IsValueType) goto case ILCode.Cne; - - // when comparing signed integral values using Cgt_Un with 0 - // the Ast should actually contain InEquality since "(uint)a > 0u" is identical to "a != 0" - if (arg1Type.IsSignedIntegralType()) - { - var p = arg2 as PrimitiveExpression; - if (p != null && p.Value.IsZero()) goto case ILCode.Cne; - } - - goto case ILCode.Cgt; - } - case ILCode.Cle_Un: { - // can also mean Equality, when used with object references - TypeReference arg1Type = byteCode.Arguments[0].InferredType; - if (arg1Type != null && !arg1Type.IsValueType) goto case ILCode.Ceq; - - // when comparing signed integral values using Cle_Un with 0 - // the Ast should actually contain Equality since "(uint)a <= 0u" is identical to "a == 0" - if (arg1Type.IsSignedIntegralType()) - { - var p = arg2 as PrimitiveExpression; - if (p != null && p.Value.IsZero()) goto case ILCode.Ceq; - } - - goto case ILCode.Cle; - } - case ILCode.Cle: return new BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2); - case ILCode.Cge_Un: - case ILCode.Cge: return new BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2); - case ILCode.Clt_Un: - case ILCode.Clt: return new BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2); - #endregion - #region Logical - case ILCode.LogicNot: return new UnaryOperatorExpression(UnaryOperatorType.Not, arg1); - case ILCode.LogicAnd: return new BinaryOperatorExpression(arg1, BinaryOperatorType.ConditionalAnd, arg2); - case ILCode.LogicOr: return new BinaryOperatorExpression(arg1, BinaryOperatorType.ConditionalOr, arg2); - case ILCode.TernaryOp: return new ConditionalExpression() { Condition = arg1, TrueExpression = arg2, FalseExpression = arg3 }; - case ILCode.NullCoalescing: return new BinaryOperatorExpression(arg1, BinaryOperatorType.NullCoalescing, arg2); - #endregion - #region Branch - case ILCode.Br: return new GotoStatement(((ILLabel)byteCode.Operand).Name); - case ILCode.Brtrue: - return new IfElseStatement() { - Condition = arg1, - TrueStatement = new BlockStatement() { - new GotoStatement(((ILLabel)byteCode.Operand).Name) - } - }; - case ILCode.LoopOrSwitchBreak: return new BreakStatement(); - case ILCode.LoopContinue: return new ContinueStatement(); - #endregion - #region Conversions - case ILCode.Conv_I1: - case ILCode.Conv_I2: - case ILCode.Conv_I4: - case ILCode.Conv_I8: - case ILCode.Conv_U1: - case ILCode.Conv_U2: - case ILCode.Conv_U4: - case ILCode.Conv_U8: - case ILCode.Conv_I: - case ILCode.Conv_U: - { - // conversion was handled by Convert() function using the info from type analysis - CastExpression cast = arg1 as CastExpression; - if (cast != null) { - cast.AddAnnotation(AddCheckedBlocks.UncheckedAnnotation); - } - return arg1; - } - case ILCode.Conv_R4: - case ILCode.Conv_R8: - case ILCode.Conv_R_Un: // TODO - return arg1; - case ILCode.Conv_Ovf_I1: - case ILCode.Conv_Ovf_I2: - case ILCode.Conv_Ovf_I4: - case ILCode.Conv_Ovf_I8: - case ILCode.Conv_Ovf_U1: - case ILCode.Conv_Ovf_U2: - case ILCode.Conv_Ovf_U4: - case ILCode.Conv_Ovf_U8: - case ILCode.Conv_Ovf_I1_Un: - case ILCode.Conv_Ovf_I2_Un: - case ILCode.Conv_Ovf_I4_Un: - case ILCode.Conv_Ovf_I8_Un: - case ILCode.Conv_Ovf_U1_Un: - case ILCode.Conv_Ovf_U2_Un: - case ILCode.Conv_Ovf_U4_Un: - case ILCode.Conv_Ovf_U8_Un: - case ILCode.Conv_Ovf_I: - case ILCode.Conv_Ovf_U: - case ILCode.Conv_Ovf_I_Un: - case ILCode.Conv_Ovf_U_Un: - { - // conversion was handled by Convert() function using the info from type analysis - CastExpression cast = arg1 as CastExpression; - if (cast != null) { - cast.AddAnnotation(AddCheckedBlocks.CheckedAnnotation); - } - return arg1; - } - case ILCode.Unbox_Any: - // unboxing does not require a cast if the argument was an isinst instruction - if (arg1 is AsExpression && byteCode.Arguments[0].Code == ILCode.Isinst && TypeAnalysis.IsSameType(operand as TypeReference, byteCode.Arguments[0].Operand as TypeReference)) - return arg1; - else - goto case ILCode.Castclass; - case ILCode.Castclass: - if ((byteCode.Arguments[0].InferredType != null && byteCode.Arguments[0].InferredType.IsGenericParameter) || ((TypeReference)operand).IsGenericParameter) - return arg1.CastTo(new PrimitiveType("object")).CastTo(operandAsTypeRef); - else - return arg1.CastTo(operandAsTypeRef); - case ILCode.Isinst: - return arg1.CastAs(operandAsTypeRef); - case ILCode.Box: - return arg1; - case ILCode.Unbox: - return MakeRef(arg1.CastTo(operandAsTypeRef)); - #endregion - #region Indirect - case ILCode.Ldind_Ref: - case ILCode.Ldobj: - if (arg1 is DirectionExpression) - return ((DirectionExpression)arg1).Expression.Detach(); - else - return new UnaryOperatorExpression(UnaryOperatorType.Dereference, arg1); - case ILCode.Stind_Ref: - case ILCode.Stobj: - if (arg1 is DirectionExpression) - return new AssignmentExpression(((DirectionExpression)arg1).Expression.Detach(), arg2); - else - return new AssignmentExpression(new UnaryOperatorExpression(UnaryOperatorType.Dereference, arg1), arg2); - #endregion - case ILCode.Arglist: - return new UndocumentedExpression { UndocumentedExpressionType = UndocumentedExpressionType.ArgListAccess }; - case ILCode.Break: return InlineAssembly(byteCode, args); - case ILCode.Call: - case ILCode.CallGetter: - case ILCode.CallSetter: - return TransformCall(false, byteCode, args); - case ILCode.Callvirt: - case ILCode.CallvirtGetter: - case ILCode.CallvirtSetter: - return TransformCall(true, byteCode, args); - case ILCode.Ldftn: { - MethodReference cecilMethod = ((MethodReference)operand); - var expr = new IdentifierExpression(cecilMethod.Name); - expr.TypeArguments.AddRange(ConvertTypeArguments(cecilMethod)); - expr.AddAnnotation(cecilMethod); - return new IdentifierExpression("ldftn").Invoke(expr) - .WithAnnotation(new DelegateConstruction.Annotation(false)); - } - case ILCode.Ldvirtftn: { - MethodReference cecilMethod = ((MethodReference)operand); - var expr = new IdentifierExpression(cecilMethod.Name); - expr.TypeArguments.AddRange(ConvertTypeArguments(cecilMethod)); - expr.AddAnnotation(cecilMethod); - return new IdentifierExpression("ldvirtftn").Invoke(expr) - .WithAnnotation(new DelegateConstruction.Annotation(true)); - } - case ILCode.Calli: return InlineAssembly(byteCode, args); - case ILCode.Ckfinite: return InlineAssembly(byteCode, args); - case ILCode.Constrained: return InlineAssembly(byteCode, args); - case ILCode.Cpblk: return InlineAssembly(byteCode, args); - case ILCode.Cpobj: return InlineAssembly(byteCode, args); - case ILCode.Dup: return arg1; - case ILCode.Endfilter: return InlineAssembly(byteCode, args); - case ILCode.Endfinally: return null; - case ILCode.Initblk: return InlineAssembly(byteCode, args); - case ILCode.Initobj: return InlineAssembly(byteCode, args); - case ILCode.DefaultValue: - return MakeDefaultValue((TypeReference)operand); - case ILCode.Jmp: return InlineAssembly(byteCode, args); - case ILCode.Ldc_I4: - return AstBuilder.MakePrimitive((int)operand, byteCode.InferredType); - case ILCode.Ldc_I8: - return AstBuilder.MakePrimitive((long)operand, byteCode.InferredType); - case ILCode.Ldc_R4: - case ILCode.Ldc_R8: - case ILCode.Ldc_Decimal: - return new PrimitiveExpression(operand); - case ILCode.Ldfld: - if (arg1 is DirectionExpression) - arg1 = ((DirectionExpression)arg1).Expression.Detach(); - return arg1.Member(((FieldReference) operand).Name).WithAnnotation(operand); - case ILCode.Ldsfld: - return AstBuilder.ConvertType(((FieldReference)operand).DeclaringType) - .Member(((FieldReference)operand).Name).WithAnnotation(operand); - case ILCode.Stfld: - if (arg1 is DirectionExpression) - arg1 = ((DirectionExpression)arg1).Expression.Detach(); - return new AssignmentExpression(arg1.Member(((FieldReference) operand).Name).WithAnnotation(operand), arg2); - case ILCode.Stsfld: - return new AssignmentExpression( - AstBuilder.ConvertType(((FieldReference)operand).DeclaringType) - .Member(((FieldReference)operand).Name).WithAnnotation(operand), - arg1); - case ILCode.Ldflda: - if (arg1 is DirectionExpression) - arg1 = ((DirectionExpression)arg1).Expression.Detach(); - return MakeRef(arg1.Member(((FieldReference) operand).Name).WithAnnotation(operand)); - case ILCode.Ldsflda: - return MakeRef( - AstBuilder.ConvertType(((FieldReference)operand).DeclaringType) - .Member(((FieldReference)operand).Name).WithAnnotation(operand)); - case ILCode.Ldloc: { - ILVariable v = (ILVariable)operand; - if (!v.IsParameter) - localVariablesToDefine.Add((ILVariable)operand); - Expression expr; - if (v.IsParameter && v.OriginalParameter.Index < 0) - expr = new ThisReferenceExpression(); - else - expr = new IdentifierExpression(((ILVariable)operand).Name).WithAnnotation(operand); - return v.IsParameter && v.Type is ByReferenceType ? MakeRef(expr) : expr; - } - case ILCode.Ldloca: { - ILVariable v = (ILVariable)operand; - if (v.IsParameter && v.OriginalParameter.Index < 0) - return MakeRef(new ThisReferenceExpression()); - if (!v.IsParameter) - localVariablesToDefine.Add((ILVariable)operand); - return MakeRef(new IdentifierExpression(((ILVariable)operand).Name).WithAnnotation(operand)); - } - case ILCode.Ldnull: return new NullReferenceExpression(); - case ILCode.Ldstr: return new PrimitiveExpression(operand); - case ILCode.Ldtoken: - if (operand is TypeReference) { - return AstBuilder.CreateTypeOfExpression((TypeReference)operand).Member("TypeHandle"); - } else { - Expression referencedEntity; - string loadName; - string handleName; - if (operand is FieldReference) { - loadName = "fieldof"; - handleName = "FieldHandle"; - FieldReference fr = (FieldReference)operand; - referencedEntity = AstBuilder.ConvertType(fr.DeclaringType).Member(fr.Name).WithAnnotation(fr); - } else if (operand is MethodReference) { - loadName = "methodof"; - handleName = "MethodHandle"; - MethodReference mr = (MethodReference)operand; - var methodParameters = mr.Parameters.Select(p => new TypeReferenceExpression(AstBuilder.ConvertType(p.ParameterType))); - referencedEntity = AstBuilder.ConvertType(mr.DeclaringType).Invoke(mr.Name, methodParameters).WithAnnotation(mr); - } else { - loadName = "ldtoken"; - handleName = "Handle"; - referencedEntity = new IdentifierExpression(FormatByteCodeOperand(byteCode.Operand)); - } - return new IdentifierExpression(loadName).Invoke(referencedEntity).WithAnnotation(new LdTokenAnnotation()).Member(handleName); - } - case ILCode.Leave: return new GotoStatement() { Label = ((ILLabel)operand).Name }; - case ILCode.Localloc: - { - PointerType ptrType = byteCode.InferredType as PointerType; - TypeReference type; - if (ptrType != null) { - type = ptrType.ElementType; - } else { - type = typeSystem.Byte; - } - return new StackAllocExpression { - Type = AstBuilder.ConvertType(type), - CountExpression = arg1 - }; - } - case ILCode.Mkrefany: - { - DirectionExpression dir = arg1 as DirectionExpression; - if (dir != null) { - return new UndocumentedExpression { - UndocumentedExpressionType = UndocumentedExpressionType.MakeRef, - Arguments = { dir.Expression.Detach() } - }; - } else { - return InlineAssembly(byteCode, args); - } - } - case ILCode.Refanytype: - return new UndocumentedExpression { - UndocumentedExpressionType = UndocumentedExpressionType.RefType, - Arguments = { arg1 } - }.Member("TypeHandle"); - case ILCode.Refanyval: - return MakeRef( - new UndocumentedExpression { - UndocumentedExpressionType = UndocumentedExpressionType.RefValue, - Arguments = { arg1, new TypeReferenceExpression(operandAsTypeRef) } - }); - case ILCode.Newobj: { - TypeReference declaringType = ((MethodReference)operand).DeclaringType; - if (declaringType is ArrayType) { - ComposedType ct = AstBuilder.ConvertType((ArrayType)declaringType) as ComposedType; - if (ct != null && ct.ArraySpecifiers.Count >= 1) { - var ace = new ArrayCreateExpression(); - ct.ArraySpecifiers.First().Remove(); - ct.ArraySpecifiers.MoveTo(ace.AdditionalArraySpecifiers); - ace.Type = ct; - ace.Arguments.AddRange(args); - return ace; - } - } - if (declaringType.IsAnonymousType()) { - MethodDefinition ctor = ((MethodReference)operand).Resolve(); - if (methodDef != null) { - AnonymousTypeCreateExpression atce = new AnonymousTypeCreateExpression(); - if (CanInferAnonymousTypePropertyNamesFromArguments(args, ctor.Parameters)) { - atce.Initializers.AddRange(args); - } else { - for (int i = 0; i < args.Count; i++) { - atce.Initializers.Add( - new NamedExpression { - Name = ctor.Parameters[i].Name, - Expression = args[i] - }); - } - } - return atce; - } - } - var oce = new ObjectCreateExpression(); - oce.Type = AstBuilder.ConvertType(declaringType); - oce.Arguments.AddRange(args); - return oce.WithAnnotation(operand); - } - case ILCode.No: return InlineAssembly(byteCode, args); - case ILCode.Nop: return null; - case ILCode.Pop: return arg1; - case ILCode.Readonly: return InlineAssembly(byteCode, args); - case ILCode.Ret: - if (methodDef.ReturnType.FullName != "System.Void") { - return new ReturnStatement { Expression = arg1 }; - } else { - return new ReturnStatement(); - } - case ILCode.Rethrow: return new ThrowStatement(); - case ILCode.Sizeof: return new SizeOfExpression { Type = operandAsTypeRef }; - case ILCode.Stloc: { - ILVariable locVar = (ILVariable)operand; - if (!locVar.IsParameter) - localVariablesToDefine.Add(locVar); - return new AssignmentExpression(new IdentifierExpression(locVar.Name).WithAnnotation(locVar), arg1); - } - case ILCode.Switch: return InlineAssembly(byteCode, args); - case ILCode.Tail: return InlineAssembly(byteCode, args); - case ILCode.Throw: return new ThrowStatement { Expression = arg1 }; - case ILCode.Unaligned: return InlineAssembly(byteCode, args); - case ILCode.Volatile: return InlineAssembly(byteCode, args); - case ILCode.YieldBreak: - return new YieldBreakStatement(); - case ILCode.YieldReturn: - return new YieldReturnStatement { Expression = arg1 }; - case ILCode.InitObject: - case ILCode.InitCollection: - { - ArrayInitializerExpression initializer = new ArrayInitializerExpression(); - for (int i = 1; i < args.Count; i++) { - Match m = objectInitializerPattern.Match(args[i]); - if (m.Success) { - MemberReferenceExpression mre = m.Get("left").Single(); - initializer.Elements.Add( - new NamedExpression { - Name = mre.MemberName, - Expression = m.Get("right").Single().Detach() - }.CopyAnnotationsFrom(mre)); - } else { - m = collectionInitializerPattern.Match(args[i]); - if (m.Success) { - if (m.Get("arg").Count() == 1) { - initializer.Elements.Add(m.Get("arg").Single().Detach()); - } else { - ArrayInitializerExpression argList = new ArrayInitializerExpression(); - foreach (var expr in m.Get("arg")) { - argList.Elements.Add(expr.Detach()); - } - initializer.Elements.Add(argList); - } - } else { - initializer.Elements.Add(args[i]); - } - } - } - ObjectCreateExpression oce = arg1 as ObjectCreateExpression; - DefaultValueExpression dve = arg1 as DefaultValueExpression; - if (oce != null) { - oce.Initializer = initializer; - return oce; - } else if (dve != null) { - oce = new ObjectCreateExpression(dve.Type.Detach()); - oce.CopyAnnotationsFrom(dve); - oce.Initializer = initializer; - return oce; - } else { - return new AssignmentExpression(arg1, initializer); - } - } - case ILCode.InitializedObject: - return new InitializedObjectExpression(); - case ILCode.Wrap: - return arg1.WithAnnotation(PushNegation.LiftedOperatorAnnotation); - case ILCode.AddressOf: - return MakeRef(arg1); - case ILCode.ExpressionTreeParameterDeclarations: - args[args.Count - 1].AddAnnotation(new ParameterDeclarationAnnotation(byteCode)); - return args[args.Count - 1]; - case ILCode.Await: - return new UnaryOperatorExpression(UnaryOperatorType.Await, UnpackDirectionExpression(arg1)); - case ILCode.NullableOf: - case ILCode.ValueOf: - return arg1; - default: - throw new Exception("Unknown OpCode: " + byteCode.Code); - } - } - - internal static bool CanInferAnonymousTypePropertyNamesFromArguments(IList args, IList parameters) - { - for (int i = 0; i < args.Count; i++) { - string inferredName; - if (args[i] is IdentifierExpression) - inferredName = ((IdentifierExpression)args[i]).Identifier; - else if (args[i] is MemberReferenceExpression) - inferredName = ((MemberReferenceExpression)args[i]).MemberName; - else - inferredName = null; - - if (inferredName != parameters[i].Name) { - return false; - } - } - return true; - } - - static readonly AstNode objectInitializerPattern = new AssignmentExpression( - new MemberReferenceExpression { - Target = new InitializedObjectExpression(), - MemberName = Pattern.AnyString - }.WithName("left"), - new AnyNode("right") - ); - - static readonly AstNode collectionInitializerPattern = new InvocationExpression { - Target = new MemberReferenceExpression { - Target = new InitializedObjectExpression(), - MemberName = "Add" - }, - Arguments = { new Repeat(new AnyNode("arg")) } - }; - - sealed class InitializedObjectExpression : IdentifierExpression - { - public InitializedObjectExpression() : base("__initialized_object__") {} - - protected override bool DoMatch(AstNode other, Match match) - { - return other is InitializedObjectExpression; - } - } - - Expression MakeDefaultValue(TypeReference type) - { - TypeDefinition typeDef = type.Resolve(); - if (typeDef != null) { - if (TypeAnalysis.IsIntegerOrEnum(typeDef)) - return AstBuilder.MakePrimitive(0, typeDef); - else if (!typeDef.IsValueType) - return new NullReferenceExpression(); - switch (typeDef.FullName) { - case "System.Nullable`1": - return new NullReferenceExpression(); - case "System.Single": - return new PrimitiveExpression(0f); - case "System.Double": - return new PrimitiveExpression(0.0); - case "System.Decimal": - return new PrimitiveExpression(0m); - } - } - return new DefaultValueExpression { Type = AstBuilder.ConvertType(type) }; - } - - AstNode TransformCall(bool isVirtual, ILExpression byteCode, List args) - { - MethodReference cecilMethod = (MethodReference)byteCode.Operand; - MethodDefinition cecilMethodDef = cecilMethod.Resolve(); - Expression target; - List methodArgs = new List(args); - if (cecilMethod.HasThis) { - target = methodArgs[0]; - methodArgs.RemoveAt(0); - - // Unpack any DirectionExpression that is used as target for the call - // (calling methods on value types implicitly passes the first argument by reference) - target = UnpackDirectionExpression(target); - - if (cecilMethodDef != null) { - // convert null.ToLower() to ((string)null).ToLower() - if (target is NullReferenceExpression) - target = target.CastTo(AstBuilder.ConvertType(cecilMethod.DeclaringType)); - - if (cecilMethodDef.DeclaringType.IsInterface) { - TypeReference tr = byteCode.Arguments[0].InferredType; - if (tr != null) { - TypeDefinition td = tr.Resolve(); - if (td != null && !td.IsInterface) { - // Calling an interface method on a non-interface object: - // we need to introduce an explicit cast - target = target.CastTo(AstBuilder.ConvertType(cecilMethod.DeclaringType)); - } - } - } - } - } else { - target = new TypeReferenceExpression { Type = AstBuilder.ConvertType(cecilMethod.DeclaringType) }; - } - if (target is ThisReferenceExpression && !isVirtual) { - // a non-virtual call on "this" might be a "base"-call. - if (cecilMethod.DeclaringType.GetElementType() != methodDef.DeclaringType) { - // If we're not calling a method in the current class; we must be calling one in the base class. - target = new BaseReferenceExpression(); - } - } - - if (cecilMethod.Name == ".ctor" && cecilMethod.DeclaringType.IsValueType) { - // On value types, the constructor can be called. - // This is equivalent to 'target = new ValueType(args);'. - ObjectCreateExpression oce = new ObjectCreateExpression(); - oce.Type = AstBuilder.ConvertType(cecilMethod.DeclaringType); - oce.AddAnnotation(cecilMethod); - AdjustArgumentsForMethodCall(cecilMethod, methodArgs); - oce.Arguments.AddRange(methodArgs); - return new AssignmentExpression(target, oce); - } - - if (cecilMethod.Name == "Get" && cecilMethod.DeclaringType is ArrayType && methodArgs.Count > 1) { - return target.Indexer(methodArgs); - } else if (cecilMethod.Name == "Set" && cecilMethod.DeclaringType is ArrayType && methodArgs.Count > 2) { - return new AssignmentExpression(target.Indexer(methodArgs.GetRange(0, methodArgs.Count - 1)), methodArgs.Last()); - } - - // Test whether the method is an accessor: - if (cecilMethodDef != null) { - if (cecilMethodDef.IsGetter && methodArgs.Count == 0) { - foreach (var prop in cecilMethodDef.DeclaringType.Properties) { - if (prop.GetMethod == cecilMethodDef) - return target.Member(prop.Name).WithAnnotation(prop).WithAnnotation(cecilMethod); - } - } else if (cecilMethodDef.IsGetter) { // with parameters - PropertyDefinition indexer = GetIndexer(cecilMethodDef); - if (indexer != null) - return target.Indexer(methodArgs).WithAnnotation(indexer).WithAnnotation(cecilMethod); - } else if (cecilMethodDef.IsSetter && methodArgs.Count == 1) { - foreach (var prop in cecilMethodDef.DeclaringType.Properties) { - if (prop.SetMethod == cecilMethodDef) - return new AssignmentExpression(target.Member(prop.Name).WithAnnotation(prop).WithAnnotation(cecilMethod), methodArgs[0]); - } - } else if (cecilMethodDef.IsSetter && methodArgs.Count > 1) { - PropertyDefinition indexer = GetIndexer(cecilMethodDef); - if (indexer != null) - return new AssignmentExpression( - target.Indexer(methodArgs.GetRange(0, methodArgs.Count - 1)).WithAnnotation(indexer).WithAnnotation(cecilMethod), - methodArgs[methodArgs.Count - 1] - ); - } else if (cecilMethodDef.IsAddOn && methodArgs.Count == 1) { - foreach (var ev in cecilMethodDef.DeclaringType.Events) { - if (ev.AddMethod == cecilMethodDef) { - return new AssignmentExpression { - Left = target.Member(ev.Name).WithAnnotation(ev).WithAnnotation(cecilMethod), - Operator = AssignmentOperatorType.Add, - Right = methodArgs[0] - }; - } - } - } else if (cecilMethodDef.IsRemoveOn && methodArgs.Count == 1) { - foreach (var ev in cecilMethodDef.DeclaringType.Events) { - if (ev.RemoveMethod == cecilMethodDef) { - return new AssignmentExpression { - Left = target.Member(ev.Name).WithAnnotation(ev).WithAnnotation(cecilMethod), - Operator = AssignmentOperatorType.Subtract, - Right = methodArgs[0] - }; - } - } - } else if (cecilMethodDef.Name == "Invoke" && cecilMethodDef.DeclaringType.BaseType != null && cecilMethodDef.DeclaringType.BaseType.FullName == "System.MulticastDelegate") { - AdjustArgumentsForMethodCall(cecilMethod, methodArgs); - return target.Invoke(methodArgs).WithAnnotation(cecilMethod); - } - } - // Default invocation - AdjustArgumentsForMethodCall(cecilMethodDef ?? cecilMethod, methodArgs); - return target.Invoke(cecilMethod.Name, ConvertTypeArguments(cecilMethod), methodArgs).WithAnnotation(cecilMethod); - } - - static Expression UnpackDirectionExpression(Expression target) - { - if (target is DirectionExpression) { - return ((DirectionExpression)target).Expression.Detach(); - } else { - return target; - } - } - - static void AdjustArgumentsForMethodCall(MethodReference cecilMethod, List methodArgs) - { - // Convert 'ref' into 'out' where necessary - for (int i = 0; i < methodArgs.Count && i < cecilMethod.Parameters.Count; i++) { - DirectionExpression dir = methodArgs[i] as DirectionExpression; - ParameterDefinition p = cecilMethod.Parameters[i]; - if (dir != null && p.IsOut && !p.IsIn) - dir.FieldDirection = FieldDirection.Out; - } - } - - internal static PropertyDefinition GetIndexer(MethodDefinition cecilMethodDef) - { - TypeDefinition typeDef = cecilMethodDef.DeclaringType; - string indexerName = null; - foreach (CustomAttribute ca in typeDef.CustomAttributes) { - if (ca.Constructor.FullName == "System.Void System.Reflection.DefaultMemberAttribute::.ctor(System.String)") { - indexerName = ca.ConstructorArguments.Single().Value as string; - break; - } - } - if (indexerName == null) - return null; - foreach (PropertyDefinition prop in typeDef.Properties) { - if (prop.Name == indexerName) { - if (prop.GetMethod == cecilMethodDef || prop.SetMethod == cecilMethodDef) - return prop; - } - } - return null; - } - - #if DEBUG - static readonly ConcurrentDictionary unhandledOpcodes = new ConcurrentDictionary(); - #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 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 string FormatByteCodeOperand(object operand) - { - if (operand == null) { - return string.Empty; - //} else if (operand is ILExpression) { - // return string.Format("IL_{0:X2}", ((ILExpression)operand).Offset); - } else if (operand is MethodReference) { - return ((MethodReference)operand).Name + "()"; - } else if (operand is TypeReference) { - return ((TypeReference)operand).FullName; - } else if (operand is VariableDefinition) { - return ((VariableDefinition)operand).Name; - } else if (operand is ParameterDefinition) { - return ((ParameterDefinition)operand).Name; - } else if (operand is FieldReference) { - return ((FieldReference)operand).Name; - } else if (operand is string) { - return "\"" + operand + "\""; - } else if (operand is int) { - return operand.ToString(); - } else { - return operand.ToString(); - } - } - - static IEnumerable ConvertTypeArguments(MethodReference cecilMethod) - { - GenericInstanceMethod g = cecilMethod as GenericInstanceMethod; - if (g == null) - return null; - if (g.GenericArguments.Any(ta => ta.ContainsAnonymousType())) - return null; - return g.GenericArguments.Select(t => AstBuilder.ConvertType(t)); - } - - static DirectionExpression MakeRef(Expression expr) - { - return new DirectionExpression { Expression = expr, FieldDirection = FieldDirection.Ref }; - } - - Expression Convert(Expression expr, TypeReference actualType, TypeReference reqType) - { - if (actualType == null || reqType == null || TypeAnalysis.IsSameType(actualType, reqType)) { - return expr; - } else if (actualType is ByReferenceType && reqType is PointerType && expr is DirectionExpression) { - return Convert( - new UnaryOperatorExpression(UnaryOperatorType.AddressOf, ((DirectionExpression)expr).Expression.Detach()), - new PointerType(((ByReferenceType)actualType).ElementType), - reqType); - } else if (actualType is PointerType && reqType is ByReferenceType) { - expr = Convert(expr, actualType, new PointerType(((ByReferenceType)reqType).ElementType)); - return new DirectionExpression { - FieldDirection = FieldDirection.Ref, - Expression = new UnaryOperatorExpression(UnaryOperatorType.Dereference, expr) - }; - } else if (actualType is PointerType && reqType is PointerType) { - if (actualType.FullName != reqType.FullName) - return expr.CastTo(AstBuilder.ConvertType(reqType)); - else - return expr; - } else { - bool actualIsIntegerOrEnum = TypeAnalysis.IsIntegerOrEnum(actualType); - bool requiredIsIntegerOrEnum = TypeAnalysis.IsIntegerOrEnum(reqType); - - if (TypeAnalysis.IsBoolean(reqType)) { - if (TypeAnalysis.IsBoolean(actualType)) - return expr; - if (actualIsIntegerOrEnum) { - return new BinaryOperatorExpression(expr, BinaryOperatorType.InEquality, AstBuilder.MakePrimitive(0, actualType)); - } else { - return new BinaryOperatorExpression(expr, BinaryOperatorType.InEquality, new NullReferenceExpression()); - } - } - if (TypeAnalysis.IsBoolean(actualType) && requiredIsIntegerOrEnum) { - return new ConditionalExpression { - Condition = expr, - TrueExpression = AstBuilder.MakePrimitive(1, reqType), - FalseExpression = AstBuilder.MakePrimitive(0, reqType) - }; - } - - if (expr is PrimitiveExpression && !requiredIsIntegerOrEnum && TypeAnalysis.IsEnum(actualType)) - { - return expr.CastTo(AstBuilder.ConvertType(actualType)); - } - - bool actualIsPrimitiveType = actualIsIntegerOrEnum - || actualType.MetadataType == MetadataType.Single || actualType.MetadataType == MetadataType.Double; - bool requiredIsPrimitiveType = requiredIsIntegerOrEnum - || reqType.MetadataType == MetadataType.Single || reqType.MetadataType == MetadataType.Double; - if (actualIsPrimitiveType && requiredIsPrimitiveType) { - return expr.CastTo(AstBuilder.ConvertType(reqType)); - } - return expr; - } - } - } -} diff --git a/ICSharpCode.Decompiler/Ast/CommentStatement.cs b/ICSharpCode.Decompiler/Ast/CommentStatement.cs deleted file mode 100644 index 39bc2450..00000000 --- a/ICSharpCode.Decompiler/Ast/CommentStatement.cs +++ /dev/null @@ -1,69 +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.Linq; -using ICSharpCode.NRefactory.CSharp; -using ICSharpCode.NRefactory.PatternMatching; - -namespace ICSharpCode.Decompiler.Ast -{ - /// - /// Allows storing comments inside IEnumerable{Statement}. Used in the AstMethodBuilder. - /// CommentStatement nodes are replaced with regular comments later on. - /// - internal class CommentStatement : Statement - { - string comment; - - public CommentStatement(string comment) - { - if (comment == null) - throw new ArgumentNullException("comment"); - this.comment = comment; - } - - public override void AcceptVisitor(IAstVisitor visitor) - { - } - - public override T AcceptVisitor(IAstVisitor visitor) - { - return default(T); - } - - public override S AcceptVisitor(IAstVisitor visitor, T data) - { - return default(S); - } - - public static void ReplaceAll(AstNode tree) - { - foreach (var cs in tree.Descendants.OfType()) { - cs.Parent.InsertChildBefore(cs, new Comment(cs.comment), Roles.Comment); - cs.Remove(); - } - } - - protected override bool DoMatch(AstNode other, Match match) - { - CommentStatement o = other as CommentStatement; - return o != null && MatchString(comment, o.comment); - } - } -} diff --git a/ICSharpCode.Decompiler/Ast/DecompilerContext.cs b/ICSharpCode.Decompiler/Ast/DecompilerContext.cs deleted file mode 100644 index d055de1d..00000000 --- a/ICSharpCode.Decompiler/Ast/DecompilerContext.cs +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Threading; -using ICSharpCode.Decompiler.Ast; -using ICSharpCode.NRefactory.TypeSystem; -using ICSharpCode.NRefactory.TypeSystem.Implementation; -using Mono.Cecil; - -namespace ICSharpCode.Decompiler -{ - public class DecompilerContext - { - public ModuleDefinition CurrentModule; - public CancellationToken CancellationToken; - public TypeDefinition CurrentType; - public MethodDefinition CurrentMethod; - public DecompilerSettings Settings = new DecompilerSettings(); - public bool CurrentMethodIsAsync; - -// public ITypeResolveContext TypeResolveContext; -// public IProjectContent ProjectContent; - - public DecompilerContext(ModuleDefinition currentModule) - { - if (currentModule == null) - throw new ArgumentNullException("currentModule"); - CurrentModule = currentModule; - -// this.ProjectContent = new CecilTypeResolveContext(currentModule); -// List resolveContexts = new List(); -// resolveContexts.Add(this.ProjectContent); -// foreach (AssemblyNameReference r in currentModule.AssemblyReferences) { -// AssemblyDefinition d = currentModule.AssemblyResolver.Resolve(r); -// if (d != null) { -// resolveContexts.Add(new CecilTypeResolveContext(d.MainModule)); -// } -// } -// this.TypeResolveContext = new CompositeTypeResolveContext(resolveContexts); - } - - /// - /// Used to pass variable names from a method to its anonymous methods. - /// - internal List ReservedVariableNames = new List(); - - public DecompilerContext Clone() - { - DecompilerContext ctx = (DecompilerContext)MemberwiseClone(); - ctx.ReservedVariableNames = new List(ctx.ReservedVariableNames); - return ctx; - } - } -} diff --git a/ICSharpCode.Decompiler/Ast/NRefactoryExtensions.cs b/ICSharpCode.Decompiler/Ast/NRefactoryExtensions.cs deleted file mode 100644 index 80730061..00000000 --- a/ICSharpCode.Decompiler/Ast/NRefactoryExtensions.cs +++ /dev/null @@ -1,86 +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 ICSharpCode.NRefactory.CSharp; -using ICSharpCode.NRefactory.PatternMatching; - -namespace ICSharpCode.Decompiler.Ast -{ - internal static class NRefactoryExtensions - { - public static T WithAnnotation(this T node, object annotation) where T : AstNode - { - if (annotation != null) - node.AddAnnotation(annotation); - return node; - } - - public static T CopyAnnotationsFrom(this T node, AstNode other) where T : AstNode - { - foreach (object annotation in other.Annotations) { - node.AddAnnotation(annotation); - } - return node; - } - - public static T Detach(this T node) where T : AstNode - { - node.Remove(); - return node; - } - - public static Expression WithName(this Expression node, string patternGroupName) - { - return new NamedNode(patternGroupName, node); - } - - public static Statement WithName(this Statement node, string patternGroupName) - { - return new NamedNode(patternGroupName, node); - } - - public static void AddNamedArgument(this NRefactory.CSharp.Attribute attribute, string name, Expression argument) - { - attribute.Arguments.Add(new AssignmentExpression(new IdentifierExpression(name), argument)); - } - - public static AstType ToType(this Pattern pattern) - { - return pattern; - } - - public static Expression ToExpression(this Pattern pattern) - { - return pattern; - } - - public static Statement ToStatement(this Pattern pattern) - { - return pattern; - } - - public static Statement GetNextStatement(this Statement statement) - { - AstNode next = statement.NextSibling; - while (next != null && !(next is Statement)) - next = next.NextSibling; - return (Statement)next; - } - } -} diff --git a/ICSharpCode.Decompiler/Ast/NameVariables.cs b/ICSharpCode.Decompiler/Ast/NameVariables.cs deleted file mode 100644 index 3da808cb..00000000 --- a/ICSharpCode.Decompiler/Ast/NameVariables.cs +++ /dev/null @@ -1,347 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Linq; - -using ICSharpCode.Decompiler.ILAst; -using Mono.Cecil; - -namespace ICSharpCode.Decompiler.Ast -{ - public class NameVariables - { - static readonly Dictionary typeNameToVariableNameDict = new Dictionary { - { "System.Boolean", "flag" }, - { "System.Byte", "b" }, - { "System.SByte", "b" }, - { "System.Int16", "num" }, - { "System.Int32", "num" }, - { "System.Int64", "num" }, - { "System.UInt16", "num" }, - { "System.UInt32", "num" }, - { "System.UInt64", "num" }, - { "System.Single", "num" }, - { "System.Double", "num" }, - { "System.Decimal", "num" }, - { "System.String", "text" }, - { "System.Object", "obj" }, - { "System.Char", "c" } - }; - - - public static void AssignNamesToVariables(DecompilerContext context, IEnumerable parameters, IEnumerable variables, ILBlock methodBody) - { - NameVariables nv = new NameVariables(); - nv.context = context; - nv.fieldNamesInCurrentType = context.CurrentType.Fields.Select(f => f.Name).ToList(); - // First mark existing variable names as reserved. - foreach (string name in context.ReservedVariableNames) - nv.AddExistingName(name); - foreach (var p in parameters) - nv.AddExistingName(p.Name); - foreach (var v in variables) { - 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) || !IsValidName(varName)) - { - // 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) { - if (string.IsNullOrEmpty(p.Name)) - p.Name = nv.GenerateNameForVariable(p, methodBody); - } - foreach (ILVariable varDef in variables) { - if (string.IsNullOrEmpty(varDef.Name)) - varDef.Name = nv.GenerateNameForVariable(varDef, methodBody); - } - } - - static bool IsValidName(string varName) - { - if (string.IsNullOrEmpty(varName)) - return false; - if (!(char.IsLetter(varName[0]) || varName[0] == '_')) - return false; - for (int i = 1; i < varName.Length; i++) { - if (!(char.IsLetterOrDigit(varName[i]) || varName[i] == '_')) - return false; - } - return true; - } - - DecompilerContext context; - List fieldNamesInCurrentType; - Dictionary typeNames = new Dictionary(); - - public void AddExistingName(string name) - { - if (string.IsNullOrEmpty(name)) - return; - int number; - string nameWithoutDigits = SplitName(name, out number); - int existingNumber; - if (typeNames.TryGetValue(nameWithoutDigits, out existingNumber)) { - typeNames[nameWithoutDigits] = Math.Max(number, existingNumber); - } else { - typeNames.Add(nameWithoutDigits, number); - } - } - - string SplitName(string name, out int number) - { - // First, identify whether the name already ends with a number: - int pos = name.Length; - while (pos > 0 && name[pos-1] >= '0' && name[pos-1] <= '9') - pos--; - if (pos < name.Length) { - if (int.TryParse(name.Substring(pos), out number)) { - return name.Substring(0, pos); - } - } - number = 1; - return name; - } - - const char maxLoopVariableName = 'n'; - - public string GetAlternativeName(string oldVariableName) - { - if (oldVariableName.Length == 1 && oldVariableName[0] >= 'i' && oldVariableName[0] <= maxLoopVariableName) { - for (char c = 'i'; c <= maxLoopVariableName; c++) { - if (!typeNames.ContainsKey(c.ToString())) { - typeNames.Add(c.ToString(), 1); - return c.ToString(); - } - } - } - - int number; - string nameWithoutDigits = SplitName(oldVariableName, out number); - - if (!typeNames.ContainsKey(nameWithoutDigits)) { - typeNames.Add(nameWithoutDigits, number - 1); - } - int count = ++typeNames[nameWithoutDigits]; - if (count != 1) { - return nameWithoutDigits + count.ToString(); - } else { - return nameWithoutDigits; - } - } - - string GenerateNameForVariable(ILVariable variable, ILBlock methodBody) - { - string proposedName = null; - if (variable.Type == context.CurrentType.Module.TypeSystem.Int32) { - // test whether the variable might be a loop counter - bool isLoopCounter = false; - foreach (ILWhileLoop loop in methodBody.GetSelfAndChildrenRecursive()) { - ILExpression expr = loop.Condition; - while (expr != null && expr.Code == ILCode.LogicNot) - expr = expr.Arguments[0]; - if (expr != null) { - switch (expr.Code) { - case ILCode.Clt: - case ILCode.Clt_Un: - case ILCode.Cgt: - case ILCode.Cgt_Un: - case ILCode.Cle: - case ILCode.Cle_Un: - case ILCode.Cge: - case ILCode.Cge_Un: - ILVariable loadVar; - if (expr.Arguments[0].Match(ILCode.Ldloc, out loadVar) && loadVar == variable) { - isLoopCounter = true; - } - break; - } - } - } - if (isLoopCounter) { - // For loop variables, use i,j,k,l,m,n - for (char c = 'i'; c <= maxLoopVariableName; c++) { - if (!typeNames.ContainsKey(c.ToString())) { - proposedName = c.ToString(); - break; - } - } - } - } - if (string.IsNullOrEmpty(proposedName)) { - var proposedNameForStores = - (from expr in methodBody.GetSelfAndChildrenRecursive() - where expr.Code == ILCode.Stloc && expr.Operand == variable - select GetNameFromExpression(expr.Arguments.Single()) - ).Except(fieldNamesInCurrentType).ToList(); - if (proposedNameForStores.Count == 1) { - proposedName = proposedNameForStores[0]; - } - } - if (string.IsNullOrEmpty(proposedName)) { - var proposedNameForLoads = - (from expr in methodBody.GetSelfAndChildrenRecursive() - from i in Enumerable.Range(0, expr.Arguments.Count) - let arg = expr.Arguments[i] - where arg.Code == ILCode.Ldloc && arg.Operand == variable - select GetNameForArgument(expr, i) - ).Except(fieldNamesInCurrentType).ToList(); - if (proposedNameForLoads.Count == 1) { - proposedName = proposedNameForLoads[0]; - } - } - if (string.IsNullOrEmpty(proposedName)) { - proposedName = GetNameByType(variable.Type); - } - - // remove any numbers from the proposed name - int number; - proposedName = SplitName(proposedName, out number); - - if (!typeNames.ContainsKey(proposedName)) { - typeNames.Add(proposedName, 0); - } - int count = ++typeNames[proposedName]; - if (count > 1) { - return proposedName + count.ToString(); - } else { - return proposedName; - } - } - - static string GetNameFromExpression(ILExpression expr) - { - switch (expr.Code) { - case ILCode.Ldfld: - case ILCode.Ldsfld: - return CleanUpVariableName(((FieldReference)expr.Operand).Name); - case ILCode.Call: - case ILCode.Callvirt: - case ILCode.CallGetter: - case ILCode.CallvirtGetter: - MethodReference mr = (MethodReference)expr.Operand; - if (mr.Name.StartsWith("get_", StringComparison.OrdinalIgnoreCase) && mr.Parameters.Count == 0) { - // use name from properties, but not from indexers - return CleanUpVariableName(mr.Name.Substring(4)); - } else if (mr.Name.StartsWith("Get", StringComparison.OrdinalIgnoreCase) && mr.Name.Length >= 4 && char.IsUpper(mr.Name[3])) { - // use name from Get-methods - return CleanUpVariableName(mr.Name.Substring(3)); - } - break; - } - return null; - } - - static string GetNameForArgument(ILExpression parent, int i) - { - switch (parent.Code) { - case ILCode.Stfld: - case ILCode.Stsfld: - if (i == parent.Arguments.Count - 1) // last argument is stored value - return CleanUpVariableName(((FieldReference)parent.Operand).Name); - else - break; - case ILCode.Call: - case ILCode.Callvirt: - case ILCode.Newobj: - case ILCode.CallGetter: - case ILCode.CallvirtGetter: - case ILCode.CallSetter: - case ILCode.CallvirtSetter: - MethodReference methodRef = (MethodReference)parent.Operand; - if (methodRef.Parameters.Count == 1 && i == parent.Arguments.Count - 1) { - // argument might be value of a setter - if (methodRef.Name.StartsWith("set_", StringComparison.OrdinalIgnoreCase)) { - return CleanUpVariableName(methodRef.Name.Substring(4)); - } else if (methodRef.Name.StartsWith("Set", StringComparison.OrdinalIgnoreCase) && methodRef.Name.Length >= 4 && char.IsUpper(methodRef.Name[3])) { - return CleanUpVariableName(methodRef.Name.Substring(3)); - } - } - MethodDefinition methodDef = methodRef.Resolve(); - if (methodDef != null) { - var p = methodDef.Parameters.ElementAtOrDefault((parent.Code != ILCode.Newobj && methodDef.HasThis) ? i - 1 : i); - if (p != null && !string.IsNullOrEmpty(p.Name)) - return CleanUpVariableName(p.Name); - } - break; - case ILCode.Ret: - return "result"; - } - return null; - } - - string GetNameByType(TypeReference type) - { - type = TypeAnalysis.UnpackModifiers(type); - - GenericInstanceType git = type as GenericInstanceType; - if (git != null && git.ElementType.FullName == "System.Nullable`1" && git.GenericArguments.Count == 1) { - type = ((GenericInstanceType)type).GenericArguments[0]; - } - - string name; - if (type.IsArray) { - name = "array"; - } else if (type.IsPointer || type.IsByReference) { - name = "ptr"; - } else if (type.Name.EndsWith("Exception", StringComparison.Ordinal)) { - name = "ex"; - } else if (!typeNameToVariableNameDict.TryGetValue(type.FullName, out name)) { - name = type.Name; - // remove the 'I' for interfaces - if (name.Length >= 3 && name[0] == 'I' && char.IsUpper(name[1]) && char.IsLower(name[2])) - name = name.Substring(1); - name = CleanUpVariableName(name); - } - return name; - } - - static string CleanUpVariableName(string name) - { - // remove the backtick (generics) - int pos = name.IndexOf('`'); - if (pos >= 0) - name = name.Substring(0, pos); - - // remove field prefix: - if (name.Length > 2 && name.StartsWith("m_", StringComparison.Ordinal)) - name = name.Substring(2); - else if (name.Length > 1 && name[0] == '_') - name = name.Substring(1); - - if (name.Length == 0) - return "obj"; - else - return char.ToLower(name[0]) + name.Substring(1); - } - } -} diff --git a/ICSharpCode.Decompiler/Ast/TextTokenWriter.cs b/ICSharpCode.Decompiler/Ast/TextTokenWriter.cs deleted file mode 100644 index fed08aaa..00000000 --- a/ICSharpCode.Decompiler/Ast/TextTokenWriter.cs +++ /dev/null @@ -1,369 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Linq; -using ICSharpCode.Decompiler; -using ICSharpCode.Decompiler.ILAst; -using ICSharpCode.NRefactory; -using ICSharpCode.NRefactory.CSharp; -using Mono.Cecil; - -namespace ICSharpCode.Decompiler.Ast -{ - public class TextTokenWriter : TokenWriter - { - readonly ITextOutput output; - readonly DecompilerContext context; - readonly Stack nodeStack = new Stack(); - int braceLevelWithinType = -1; - bool inDocumentationComment = false; - bool firstUsingDeclaration; - bool lastUsingDeclaration; - - TextLocation? lastEndOfLine; - - public bool FoldBraces = false; - - public TextTokenWriter(ITextOutput output, DecompilerContext context) - { - if (output == null) - throw new ArgumentNullException("output"); - if (context == null) - throw new ArgumentNullException("context"); - this.output = output; - this.context = context; - } - - public override void WriteIdentifier(Identifier identifier) - { - var definition = GetCurrentDefinition(); - if (definition != null) { - output.WriteDefinition(identifier.Name, definition, false); - return; - } - - object memberRef = GetCurrentMemberReference(); - - if (memberRef != null) { - output.WriteReference(identifier.Name, memberRef); - return; - } - - definition = GetCurrentLocalDefinition(); - if (definition != null) { - output.WriteDefinition(identifier.Name, definition); - return; - } - - memberRef = GetCurrentLocalReference(); - if (memberRef != null) { - output.WriteReference(identifier.Name, memberRef, true); - return; - } - - if (firstUsingDeclaration) { - output.MarkFoldStart(defaultCollapsed: true); - firstUsingDeclaration = false; - } - - output.Write(identifier.Name); - } - - MemberReference GetCurrentMemberReference() - { - AstNode node = nodeStack.Peek(); - MemberReference memberRef = node.Annotation(); - if (memberRef == null && node.Role == Roles.TargetExpression && (node.Parent is InvocationExpression || node.Parent is ObjectCreateExpression)) { - memberRef = node.Parent.Annotation(); - } - if (node is IdentifierExpression && node.Role == Roles.TargetExpression && node.Parent is InvocationExpression && memberRef != null) { - var declaringType = memberRef.DeclaringType.Resolve(); - if (declaringType != null && declaringType.IsDelegate()) - return null; - } - return FilterMemberReference(memberRef); - } - - MemberReference FilterMemberReference(MemberReference memberRef) - { - if (memberRef == null) - return null; - - if (context.Settings.AutomaticEvents && memberRef is FieldDefinition) { - var field = (FieldDefinition)memberRef; - return field.DeclaringType.Events.FirstOrDefault(ev => ev.Name == field.Name) ?? memberRef; - } - - return memberRef; - } - - object GetCurrentLocalReference() - { - AstNode node = nodeStack.Peek(); - ILVariable variable = node.Annotation(); - if (variable != null) { - if (variable.OriginalParameter != null) - return variable.OriginalParameter; - //if (variable.OriginalVariable != null) - // return variable.OriginalVariable; - return variable; - } - - var gotoStatement = node as GotoStatement; - if (gotoStatement != null) - { - var method = nodeStack.Select(nd => nd.Annotation()).FirstOrDefault(mr => mr != null); - if (method != null) - return method.ToString() + gotoStatement.Label; - } - - return null; - } - - object GetCurrentLocalDefinition() - { - AstNode node = nodeStack.Peek(); - if (node is Identifier && node.Parent != null) - node = node.Parent; - - var parameterDef = node.Annotation(); - if (parameterDef != null) - return parameterDef; - - if (node is VariableInitializer || node is CatchClause || node is ForeachStatement) { - var variable = node.Annotation(); - if (variable != null) { - if (variable.OriginalParameter != null) - return variable.OriginalParameter; - //if (variable.OriginalVariable != null) - // return variable.OriginalVariable; - return variable; - } - } - - var label = node as LabelStatement; - if (label != null) { - var method = nodeStack.Select(nd => nd.Annotation()).FirstOrDefault(mr => mr != null); - if (method != null) - return method.ToString() + label.Label; - } - - return null; - } - - object GetCurrentDefinition() - { - if (nodeStack == null || nodeStack.Count == 0) - return null; - - var node = nodeStack.Peek(); - if (node is Identifier) - node = node.Parent; - if (IsDefinition(node)) - return node.Annotation(); - - return null; - } - - public override void WriteKeyword(Role role, string keyword) - { - output.Write(keyword); - } - - public override void WriteToken(Role role, string token) - { - // Attach member reference to token only if there's no identifier in the current node. - MemberReference memberRef = GetCurrentMemberReference(); - var node = nodeStack.Peek(); - if (memberRef != null && node.GetChildByRole(Roles.Identifier).IsNull) - output.WriteReference(token, memberRef); - else - output.Write(token); - } - - public override void Space() - { - output.Write(' '); - } - - public void OpenBrace(BraceStyle style) - { - if (braceLevelWithinType >= 0 || nodeStack.Peek() is TypeDeclaration) - braceLevelWithinType++; - if (nodeStack.OfType().Count() <= 1 || FoldBraces) { - output.MarkFoldStart(defaultCollapsed: braceLevelWithinType == 1); - } - output.WriteLine(); - output.WriteLine("{"); - output.Indent(); - } - - public void CloseBrace(BraceStyle style) - { - output.Unindent(); - output.Write('}'); - if (nodeStack.OfType().Count() <= 1 || FoldBraces) - output.MarkFoldEnd(); - if (braceLevelWithinType >= 0) - braceLevelWithinType--; - } - - public override void Indent() - { - output.Indent(); - } - - public override void Unindent() - { - output.Unindent(); - } - - public override void NewLine() - { - if (lastUsingDeclaration) { - output.MarkFoldEnd(); - lastUsingDeclaration = false; - } - lastEndOfLine = output.Location; - output.WriteLine(); - } - - public override void WriteComment(CommentType commentType, string content) - { - switch (commentType) { - case CommentType.SingleLine: - output.Write("//"); - output.WriteLine(content); - break; - case CommentType.MultiLine: - output.Write("/*"); - output.Write(content); - output.Write("*/"); - break; - case CommentType.Documentation: - bool isLastLine = !(nodeStack.Peek().NextSibling is Comment); - if (!inDocumentationComment && !isLastLine) { - inDocumentationComment = true; - output.MarkFoldStart("///" + content, true); - } - output.Write("///"); - output.Write(content); - if (inDocumentationComment && isLastLine) { - inDocumentationComment = false; - output.MarkFoldEnd(); - } - output.WriteLine(); - break; - default: - output.Write(content); - break; - } - } - - public override void WritePreProcessorDirective(PreProcessorDirectiveType type, string argument) - { - // pre-processor directive must start on its own line - output.Write('#'); - output.Write(type.ToString().ToLowerInvariant()); - if (!string.IsNullOrEmpty(argument)) { - output.Write(' '); - output.Write(argument); - } - output.WriteLine(); - } - - public override void WritePrimitiveValue(object value, string literalValue = null) - { - new TextWriterTokenWriter(new TextOutputWriter(output)).WritePrimitiveValue(value, literalValue); - } - - public override void WritePrimitiveType(string type) - { - output.Write(type); - if (type == "new") { - output.Write("()"); - } - } - - Stack startLocations = new Stack(); - Stack symbolsStack = new Stack(); - - public override void StartNode(AstNode node) - { - if (nodeStack.Count == 0) { - if (IsUsingDeclaration(node)) { - firstUsingDeclaration = !IsUsingDeclaration(node.PrevSibling); - lastUsingDeclaration = !IsUsingDeclaration(node.NextSibling); - } else { - firstUsingDeclaration = false; - lastUsingDeclaration = false; - } - } - nodeStack.Push(node); - startLocations.Push(output.Location); - - if (node is EntityDeclaration && node.Annotation() != null && node.GetChildByRole(Roles.Identifier).IsNull) - output.WriteDefinition("", node.Annotation(), false); - - if (node.Annotation() != null) { - symbolsStack.Push(node.Annotation()); - symbolsStack.Peek().StartLocation = startLocations.Peek(); - } - } - - bool IsUsingDeclaration(AstNode node) - { - return node is UsingDeclaration || node is UsingAliasDeclaration; - } - - public override void EndNode(AstNode node) - { - if (nodeStack.Pop() != node) - throw new InvalidOperationException(); - - var startLocation = startLocations.Pop(); - - // code mappings - var ranges = node.Annotation>(); - if (symbolsStack.Count > 0 && ranges != null && ranges.Count > 0) { - // Ignore the newline which was printed at the end of the statement - TextLocation endLocation = (node is Statement) ? (lastEndOfLine ?? output.Location) : output.Location; - symbolsStack.Peek().SequencePoints.Add( - new SequencePoint() { - ILRanges = ILRange.OrderAndJoin(ranges).ToArray(), - StartLocation = startLocation, - EndLocation = endLocation - }); - } - - if (node.Annotation() != null) { - symbolsStack.Peek().EndLocation = output.Location; - output.AddDebugSymbols(symbolsStack.Pop()); - } - } - - static bool IsDefinition(AstNode node) - { - return node is EntityDeclaration - || (node is VariableInitializer && node.Parent is FieldDeclaration) - || node is FixedVariableInitializer; - } - } -} diff --git a/ICSharpCode.Decompiler/Ast/Transforms/AddCheckedBlocks.cs b/ICSharpCode.Decompiler/Ast/Transforms/AddCheckedBlocks.cs deleted file mode 100644 index dc018eb1..00000000 --- a/ICSharpCode.Decompiler/Ast/Transforms/AddCheckedBlocks.cs +++ /dev/null @@ -1,368 +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.Linq; -using ICSharpCode.Decompiler.ILAst; -using ICSharpCode.NRefactory.CSharp; - -namespace ICSharpCode.Decompiler.Ast.Transforms -{ - /// - /// Add checked/unchecked blocks. - /// - public class AddCheckedBlocks : IAstTransform - { - #region Annotation - sealed class CheckedUncheckedAnnotation { - /// - /// true=checked, false=unchecked - /// - public bool IsChecked; - } - - public static readonly object CheckedAnnotation = new CheckedUncheckedAnnotation { IsChecked = true }; - public static readonly object UncheckedAnnotation = new CheckedUncheckedAnnotation { IsChecked = false }; - #endregion - - /* - We treat placing checked/unchecked blocks as an optimization problem, with the following goals: - 1. Use minimum number of checked blocks+expressions - 2. Prefer checked expressions over checked blocks - 3. Make the scope of checked expressions as small as possible - 4. Open checked blocks as late as possible, and close checked blocks as late as possible - (where goal 1 has the highest priority) - - Goal 4a (open checked blocks as late as possible) is necessary so that we don't move variable declarations - into checked blocks, as the variable might still be used after the checked block. - (this could cause DeclareVariables to omit the variable declaration, producing incorrect code) - Goal 4b (close checked blocks as late as possible) makes the code look nicer in this case: - checked { - int c = a + b; - int r = a + c; - return r; - } - If the checked block was closed as early as possible, the variable r would have to be declared outside - (this would work, but look badly) - */ - - #region struct Cost - struct Cost - { - // highest possible cost so that the Blocks+Expressions addition doesn't overflow - public static readonly Cost Infinite = new Cost(0x3fffffff, 0x3fffffff); - - public readonly int Blocks; - public readonly int Expressions; - - public Cost(int blocks, int expressions) - { - Blocks = blocks; - Expressions = expressions; - } - - public static bool operator <(Cost a, Cost b) - { - return a.Blocks + a.Expressions < b.Blocks + b.Expressions - || a.Blocks + a.Expressions == b.Blocks + b.Expressions && a.Blocks < b.Blocks; - } - - public static bool operator >(Cost a, Cost b) - { - return a.Blocks + a.Expressions > b.Blocks + b.Expressions - || a.Blocks + a.Expressions == b.Blocks + b.Expressions && a.Blocks > b.Blocks; - } - - public static bool operator <=(Cost a, Cost b) - { - return a.Blocks + a.Expressions < b.Blocks + b.Expressions - || a.Blocks + a.Expressions == b.Blocks + b.Expressions && a.Blocks <= b.Blocks; - } - - public static bool operator >=(Cost a, Cost b) - { - return a.Blocks + a.Expressions > b.Blocks + b.Expressions - || a.Blocks + a.Expressions == b.Blocks + b.Expressions && a.Blocks >= b.Blocks; - } - - public static Cost operator +(Cost a, Cost b) - { - return new Cost(a.Blocks + b.Blocks, a.Expressions + b.Expressions); - } - - public override string ToString() - { - return string.Format("[{0} + {1}]", Blocks, Expressions); - } - } - #endregion - - #region class InsertedNode - /// - /// Holds the blocks and expressions that should be inserted - /// - abstract class InsertedNode - { - public static InsertedNode operator +(InsertedNode a, InsertedNode b) - { - if (a == null) - return b; - if (b == null) - return a; - return new InsertedNodeList(a, b); - } - - public abstract void Insert(); - } - - class InsertedNodeList : InsertedNode - { - readonly InsertedNode child1, child2; - - public InsertedNodeList(InsertedNode child1, InsertedNode child2) - { - this.child1 = child1; - this.child2 = child2; - } - - public override void Insert() - { - child1.Insert(); - child2.Insert(); - } - } - - class InsertedExpression : InsertedNode - { - readonly Expression expression; - readonly bool isChecked; - - public InsertedExpression(Expression expression, bool isChecked) - { - this.expression = expression; - this.isChecked = isChecked; - } - - public override void Insert() - { - if (isChecked) - expression.ReplaceWith(e => new CheckedExpression { Expression = e }); - else - expression.ReplaceWith(e => new UncheckedExpression { Expression = e }); - } - } - - class ConvertCompoundAssignment : InsertedNode - { - readonly Expression expression; - readonly bool isChecked; - - public ConvertCompoundAssignment(Expression expression, bool isChecked) - { - this.expression = expression; - this.isChecked = isChecked; - } - - public override void Insert() - { - AssignmentExpression assign = expression.Annotation().Restore(expression); - expression.ReplaceWith(assign); - if (isChecked) - assign.Right = new CheckedExpression { Expression = assign.Right.Detach() }; - else - assign.Right = new UncheckedExpression { Expression = assign.Right.Detach() }; - } - } - - class InsertedBlock : InsertedNode - { - readonly Statement firstStatement; // inclusive - readonly Statement lastStatement; // exclusive - readonly bool isChecked; - - public InsertedBlock(Statement firstStatement, Statement lastStatement, bool isChecked) - { - this.firstStatement = firstStatement; - this.lastStatement = lastStatement; - this.isChecked = isChecked; - } - - public override void Insert() - { - BlockStatement newBlock = new BlockStatement(); - // Move all statements except for the first - Statement next; - for (Statement stmt = firstStatement.GetNextStatement(); stmt != lastStatement; stmt = next) { - next = stmt.GetNextStatement(); - newBlock.Add(stmt.Detach()); - } - // Replace the first statement with the new (un)checked block - if (isChecked) - firstStatement.ReplaceWith(new CheckedStatement { Body = newBlock }); - else - firstStatement.ReplaceWith(new UncheckedStatement { Body = newBlock }); - // now also move the first node into the new block - newBlock.Statements.InsertAfter(null, firstStatement); - } - } - #endregion - - #region class Result - /// - /// Holds the result of an insertion operation. - /// - class Result - { - public Cost CostInCheckedContext; - public InsertedNode NodesToInsertInCheckedContext; - public Cost CostInUncheckedContext; - public InsertedNode NodesToInsertInUncheckedContext; - } - #endregion - - public void Run(AstNode node) - { - BlockStatement block = node as BlockStatement; - if (block == null) { - for (AstNode child = node.FirstChild; child != null; child = child.NextSibling) { - Run(child); - } - } else { - Result r = GetResultFromBlock(block); - if (r.NodesToInsertInUncheckedContext != null) - r.NodesToInsertInUncheckedContext.Insert(); - } - } - - Result GetResultFromBlock(BlockStatement block) - { - // For a block, we are tracking 4 possibilities: - // a) context is checked, no unchecked block open - Cost costCheckedContext = new Cost(0, 0); - InsertedNode nodesCheckedContext = null; - // b) context is checked, an unchecked block is open - Cost costCheckedContextUncheckedBlockOpen = Cost.Infinite; - InsertedNode nodesCheckedContextUncheckedBlockOpen = null; - Statement uncheckedBlockStart = null; - // c) context is unchecked, no checked block open - Cost costUncheckedContext = new Cost(0, 0); - InsertedNode nodesUncheckedContext = null; - // d) context is unchecked, a checked block is open - Cost costUncheckedContextCheckedBlockOpen = Cost.Infinite; - InsertedNode nodesUncheckedContextCheckedBlockOpen = null; - Statement checkedBlockStart = null; - - Statement statement = block.Statements.FirstOrDefault(); - while (true) { - // Blocks can be closed 'for free'. We use '<=' so that blocks are closed as late as possible (goal 4b) - if (costCheckedContextUncheckedBlockOpen <= costCheckedContext) { - costCheckedContext = costCheckedContextUncheckedBlockOpen; - nodesCheckedContext = nodesCheckedContextUncheckedBlockOpen + new InsertedBlock(uncheckedBlockStart, statement, false); - } - if (costUncheckedContextCheckedBlockOpen <= costUncheckedContext) { - costUncheckedContext = costUncheckedContextCheckedBlockOpen; - nodesUncheckedContext = nodesUncheckedContextCheckedBlockOpen + new InsertedBlock(checkedBlockStart, statement, true); - } - if (statement == null) - break; - // Now try opening blocks. We use '<=' so that blocks are opened as late as possible. (goal 4a) - if (costCheckedContext + new Cost(1, 0) <= costCheckedContextUncheckedBlockOpen) { - costCheckedContextUncheckedBlockOpen = costCheckedContext + new Cost(1, 0); - nodesCheckedContextUncheckedBlockOpen = nodesCheckedContext; - uncheckedBlockStart = statement; - } - if (costUncheckedContext + new Cost(1, 0) <= costUncheckedContextCheckedBlockOpen) { - costUncheckedContextCheckedBlockOpen = costUncheckedContext + new Cost(1, 0); - nodesUncheckedContextCheckedBlockOpen = nodesUncheckedContext; - checkedBlockStart = statement; - } - // Now handle the statement - Result stmtResult = GetResult(statement); - - costCheckedContext += stmtResult.CostInCheckedContext; - nodesCheckedContext += stmtResult.NodesToInsertInCheckedContext; - costCheckedContextUncheckedBlockOpen += stmtResult.CostInUncheckedContext; - nodesCheckedContextUncheckedBlockOpen += stmtResult.NodesToInsertInUncheckedContext; - costUncheckedContext += stmtResult.CostInUncheckedContext; - nodesUncheckedContext += stmtResult.NodesToInsertInUncheckedContext; - costUncheckedContextCheckedBlockOpen += stmtResult.CostInCheckedContext; - nodesUncheckedContextCheckedBlockOpen += stmtResult.NodesToInsertInCheckedContext; - - statement = statement.GetNextStatement(); - } - - return new Result { - CostInCheckedContext = costCheckedContext, NodesToInsertInCheckedContext = nodesCheckedContext, - CostInUncheckedContext = costUncheckedContext, NodesToInsertInUncheckedContext = nodesUncheckedContext - }; - } - - Result GetResult(AstNode node) - { - if (node is BlockStatement) - return GetResultFromBlock((BlockStatement)node); - Result result = new Result(); - for (AstNode child = node.FirstChild; child != null; child = child.NextSibling) { - Result childResult = GetResult(child); - result.CostInCheckedContext += childResult.CostInCheckedContext; - result.NodesToInsertInCheckedContext += childResult.NodesToInsertInCheckedContext; - result.CostInUncheckedContext += childResult.CostInUncheckedContext; - result.NodesToInsertInUncheckedContext += childResult.NodesToInsertInUncheckedContext; - } - Expression expr = node as Expression; - if (expr != null) { - CheckedUncheckedAnnotation annotation = expr.Annotation(); - if (annotation != null) { - // If the annotation requires this node to be in a specific context, add a huge cost to the other context - // That huge cost gives us the option to ignore a required checked/unchecked expression when there wouldn't be any - // solution otherwise. (e.g. "for (checked(M().x += 1); true; unchecked(M().x += 2)) {}") - if (annotation.IsChecked) - result.CostInUncheckedContext += new Cost(10000, 0); - else - result.CostInCheckedContext += new Cost(10000, 0); - } - // Embed this node in an checked/unchecked expression: - if (expr.Parent is ExpressionStatement) { - // We cannot use checked/unchecked for top-level-expressions. - // However, we could try converting a compound assignment (checked(a+=b);) or unary operator (checked(a++);) - // back to its old form. - if (expr.Annotation() != null) { - // We use '<' so that expressions are introduced on the deepest level possible (goal 3) - if (result.CostInCheckedContext + new Cost(1, 1) < result.CostInUncheckedContext) { - result.CostInUncheckedContext = result.CostInCheckedContext + new Cost(1, 1); - result.NodesToInsertInUncheckedContext = result.NodesToInsertInCheckedContext + new ConvertCompoundAssignment(expr, true); - } else if (result.CostInUncheckedContext + new Cost(1, 1) < result.CostInCheckedContext) { - result.CostInCheckedContext = result.CostInUncheckedContext + new Cost(1, 1); - result.NodesToInsertInCheckedContext = result.NodesToInsertInUncheckedContext + new ConvertCompoundAssignment(expr, false); - } - } - } else if (expr.Role.IsValid(Expression.Null)) { - // We use '<' so that expressions are introduced on the deepest level possible (goal 3) - if (result.CostInCheckedContext + new Cost(0, 1) < result.CostInUncheckedContext) { - result.CostInUncheckedContext = result.CostInCheckedContext + new Cost(0, 1); - result.NodesToInsertInUncheckedContext = result.NodesToInsertInCheckedContext + new InsertedExpression(expr, true); - } else if (result.CostInUncheckedContext + new Cost(0, 1) < result.CostInCheckedContext) { - result.CostInCheckedContext = result.CostInUncheckedContext + new Cost(0, 1); - result.NodesToInsertInCheckedContext = result.NodesToInsertInUncheckedContext + new InsertedExpression(expr, false); - } - } - } - return result; - } - } -} diff --git a/ICSharpCode.Decompiler/Ast/Transforms/CombineQueryExpressions.cs b/ICSharpCode.Decompiler/Ast/Transforms/CombineQueryExpressions.cs deleted file mode 100644 index a0d1ca8c..00000000 --- a/ICSharpCode.Decompiler/Ast/Transforms/CombineQueryExpressions.cs +++ /dev/null @@ -1,179 +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.Linq; -using ICSharpCode.NRefactory.CSharp; -using ICSharpCode.NRefactory.PatternMatching; - -namespace ICSharpCode.Decompiler.Ast.Transforms -{ - /// - /// Combines query expressions and removes transparent identifiers. - /// - public class CombineQueryExpressions : IAstTransform - { - readonly DecompilerContext context; - - public CombineQueryExpressions(DecompilerContext context) - { - this.context = context; - } - - public void Run(AstNode compilationUnit) - { - if (!context.Settings.QueryExpressions) - return; - CombineQueries(compilationUnit); - } - - static readonly InvocationExpression castPattern = new InvocationExpression { - Target = new MemberReferenceExpression { - Target = new AnyNode("inExpr"), - MemberName = "Cast", - TypeArguments = { new AnyNode("targetType") } - }}; - - void CombineQueries(AstNode node) - { - for (AstNode child = node.FirstChild; child != null; child = child.NextSibling) { - CombineQueries(child); - } - QueryExpression query = node as QueryExpression; - if (query != null) { - QueryFromClause fromClause = (QueryFromClause)query.Clauses.First(); - QueryExpression innerQuery = fromClause.Expression as QueryExpression; - if (innerQuery != null) { - if (TryRemoveTransparentIdentifier(query, fromClause, innerQuery)) { - RemoveTransparentIdentifierReferences(query); - } else { - QueryContinuationClause continuation = new QueryContinuationClause(); - continuation.PrecedingQuery = innerQuery.Detach(); - continuation.Identifier = fromClause.Identifier; - fromClause.ReplaceWith(continuation); - } - } else { - Match m = castPattern.Match(fromClause.Expression); - if (m.Success) { - fromClause.Type = m.Get("targetType").Single().Detach(); - fromClause.Expression = m.Get("inExpr").Single().Detach(); - } - } - } - } - - static readonly QuerySelectClause selectTransparentIdentifierPattern = new QuerySelectClause { - Expression = new Choice { - new AnonymousTypeCreateExpression { - Initializers = { - new NamedExpression { - Name = Pattern.AnyString, - Expression = new IdentifierExpression(Pattern.AnyString) - }.WithName("nae1"), - new NamedExpression { - Name = Pattern.AnyString, - Expression = new AnyNode("nae2Expr") - }.WithName("nae2") - } - }, - new AnonymousTypeCreateExpression { - Initializers = { - new NamedNode("identifier", new IdentifierExpression(Pattern.AnyString)), - new AnyNode("nae2Expr") - } - } - }}; - - bool IsTransparentIdentifier(string identifier) - { - return identifier.StartsWith("<>", StringComparison.Ordinal) && identifier.Contains("TransparentIdentifier"); - } - - bool TryRemoveTransparentIdentifier(QueryExpression query, QueryFromClause fromClause, QueryExpression innerQuery) - { - if (!IsTransparentIdentifier(fromClause.Identifier)) - return false; - Match match = selectTransparentIdentifierPattern.Match(innerQuery.Clauses.Last()); - if (!match.Success) - return false; - QuerySelectClause selectClause = (QuerySelectClause)innerQuery.Clauses.Last(); - NamedExpression nae1 = match.Get("nae1").SingleOrDefault(); - NamedExpression nae2 = match.Get("nae2").SingleOrDefault(); - if (nae1 != null && nae1.Name != ((IdentifierExpression)nae1.Expression).Identifier) - return false; - Expression nae2Expr = match.Get("nae2Expr").Single(); - IdentifierExpression nae2IdentExpr = nae2Expr as IdentifierExpression; - if (nae2IdentExpr != null && (nae2 == null || nae2.Name == nae2IdentExpr.Identifier)) { - // from * in (from x in ... select new { x = x, y = y }) ... - // => - // from x in ... ... - fromClause.Remove(); - selectClause.Remove(); - // Move clauses from innerQuery to query - QueryClause insertionPos = null; - foreach (var clause in innerQuery.Clauses) { - query.Clauses.InsertAfter(insertionPos, insertionPos = clause.Detach()); - } - } else { - // from * in (from x in ... select new { x = x, y = expr }) ... - // => - // from x in ... let y = expr ... - fromClause.Remove(); - selectClause.Remove(); - // Move clauses from innerQuery to query - QueryClause insertionPos = null; - foreach (var clause in innerQuery.Clauses) { - query.Clauses.InsertAfter(insertionPos, insertionPos = clause.Detach()); - } - string ident; - if (nae2 != null) - ident = nae2.Name; - else if (nae2Expr is IdentifierExpression) - ident = ((IdentifierExpression)nae2Expr).Identifier; - else if (nae2Expr is MemberReferenceExpression) - ident = ((MemberReferenceExpression)nae2Expr).MemberName; - else - throw new InvalidOperationException("Could not infer name from initializer in AnonymousTypeCreateExpression"); - query.Clauses.InsertAfter(insertionPos, new QueryLetClause { Identifier = ident, Expression = nae2Expr.Detach() }); - } - return true; - } - - /// - /// Removes all occurrences of transparent identifiers - /// - void RemoveTransparentIdentifierReferences(AstNode node) - { - foreach (AstNode child in node.Children) { - RemoveTransparentIdentifierReferences(child); - } - MemberReferenceExpression mre = node as MemberReferenceExpression; - if (mre != null) { - IdentifierExpression ident = mre.Target as IdentifierExpression; - if (ident != null && IsTransparentIdentifier(ident.Identifier)) { - IdentifierExpression newIdent = new IdentifierExpression(mre.MemberName); - mre.TypeArguments.MoveTo(newIdent.TypeArguments); - newIdent.CopyAnnotationsFrom(mre); - newIdent.RemoveAnnotations(); // remove the reference to the property of the anonymous type - mre.ReplaceWith(newIdent); - return; - } - } - } - } -} diff --git a/ICSharpCode.Decompiler/Ast/Transforms/ContextTrackingVisitor.cs b/ICSharpCode.Decompiler/Ast/Transforms/ContextTrackingVisitor.cs deleted file mode 100644 index 1d1f3d08..00000000 --- a/ICSharpCode.Decompiler/Ast/Transforms/ContextTrackingVisitor.cs +++ /dev/null @@ -1,111 +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.Diagnostics; -using ICSharpCode.NRefactory.CSharp; -using Mono.Cecil; - -namespace ICSharpCode.Decompiler.Ast.Transforms -{ - /// - /// Base class for AST visitors that need the current type/method context info. - /// - public abstract class ContextTrackingVisitor : DepthFirstAstVisitor, IAstTransform - { - protected readonly DecompilerContext context; - - protected ContextTrackingVisitor(DecompilerContext context) - { - if (context == null) - throw new ArgumentNullException("context"); - this.context = context; - } - - public override TResult VisitTypeDeclaration(TypeDeclaration typeDeclaration, object data) - { - TypeDefinition oldType = context.CurrentType; - try { - context.CurrentType = typeDeclaration.Annotation(); - return base.VisitTypeDeclaration(typeDeclaration, data); - } finally { - context.CurrentType = oldType; - } - } - - public override TResult VisitMethodDeclaration(MethodDeclaration methodDeclaration, object data) - { - Debug.Assert(context.CurrentMethod == null); - try { - context.CurrentMethod = methodDeclaration.Annotation(); - return base.VisitMethodDeclaration(methodDeclaration, data); - } finally { - context.CurrentMethod = null; - } - } - - public override TResult VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration, object data) - { - Debug.Assert(context.CurrentMethod == null); - try { - context.CurrentMethod = constructorDeclaration.Annotation(); - return base.VisitConstructorDeclaration(constructorDeclaration, data); - } finally { - context.CurrentMethod = null; - } - } - - public override TResult VisitDestructorDeclaration(DestructorDeclaration destructorDeclaration, object data) - { - Debug.Assert(context.CurrentMethod == null); - try { - context.CurrentMethod = destructorDeclaration.Annotation(); - return base.VisitDestructorDeclaration(destructorDeclaration, data); - } finally { - context.CurrentMethod = null; - } - } - - public override TResult VisitOperatorDeclaration(OperatorDeclaration operatorDeclaration, object data) - { - Debug.Assert(context.CurrentMethod == null); - try { - context.CurrentMethod = operatorDeclaration.Annotation(); - return base.VisitOperatorDeclaration(operatorDeclaration, data); - } finally { - context.CurrentMethod = null; - } - } - - public override TResult VisitAccessor(Accessor accessor, object data) - { - Debug.Assert(context.CurrentMethod == null); - try { - context.CurrentMethod = accessor.Annotation(); - return base.VisitAccessor(accessor, data); - } finally { - context.CurrentMethod = null; - } - } - - void IAstTransform.Run(AstNode node) - { - node.AcceptVisitor(this, null); - } - } -} diff --git a/ICSharpCode.Decompiler/Ast/Transforms/ConvertConstructorCallIntoInitializer.cs b/ICSharpCode.Decompiler/Ast/Transforms/ConvertConstructorCallIntoInitializer.cs deleted file mode 100644 index 36811c18..00000000 --- a/ICSharpCode.Decompiler/Ast/Transforms/ConvertConstructorCallIntoInitializer.cs +++ /dev/null @@ -1,183 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Linq; -using ICSharpCode.NRefactory.CSharp; -using ICSharpCode.NRefactory.PatternMatching; -using Mono.Cecil; - -namespace ICSharpCode.Decompiler.Ast.Transforms -{ - /// - /// If the first element of a constructor is a chained constructor call, convert it into a constructor initializer. - /// - public class ConvertConstructorCallIntoInitializer : DepthFirstAstVisitor, IAstTransform - { - public override object VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration, object data) - { - ExpressionStatement stmt = constructorDeclaration.Body.Statements.FirstOrDefault() as ExpressionStatement; - if (stmt == null) - return null; - InvocationExpression invocation = stmt.Expression as InvocationExpression; - if (invocation == null) - return null; - MemberReferenceExpression mre = invocation.Target as MemberReferenceExpression; - if (mre != null && mre.MemberName == ".ctor") { - ConstructorInitializer ci = new ConstructorInitializer(); - if (mre.Target is ThisReferenceExpression) - ci.ConstructorInitializerType = ConstructorInitializerType.This; - else if (mre.Target is BaseReferenceExpression) - ci.ConstructorInitializerType = ConstructorInitializerType.Base; - else - return null; - // Move arguments from invocation to initializer: - invocation.Arguments.MoveTo(ci.Arguments); - // Add the initializer: (unless it is the default 'base()') - if (!(ci.ConstructorInitializerType == ConstructorInitializerType.Base && ci.Arguments.Count == 0)) - constructorDeclaration.Initializer = ci.WithAnnotation(invocation.Annotation()); - // Remove the statement: - stmt.Remove(); - } - return null; - } - - static readonly ExpressionStatement fieldInitializerPattern = new ExpressionStatement { - Expression = new AssignmentExpression { - Left = new NamedNode("fieldAccess", new MemberReferenceExpression { - Target = new ThisReferenceExpression(), - MemberName = Pattern.AnyString - }), - Operator = AssignmentOperatorType.Assign, - Right = new AnyNode("initializer") - } - }; - - static readonly AstNode thisCallPattern = new ExpressionStatement(new ThisReferenceExpression().Invoke(".ctor", new Repeat(new AnyNode()))); - - public override object VisitTypeDeclaration(TypeDeclaration typeDeclaration, object data) - { - // Handle initializers on instance fields - HandleInstanceFieldInitializers(typeDeclaration.Members); - - // Now convert base constructor calls to initializers: - base.VisitTypeDeclaration(typeDeclaration, data); - - // Remove single empty constructor: - RemoveSingleEmptyConstructor(typeDeclaration); - - // Handle initializers on static fields: - HandleStaticFieldInitializers(typeDeclaration.Members); - return null; - } - - void HandleInstanceFieldInitializers(IEnumerable members) - { - var instanceCtors = members.OfType().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(); - if (ctorMethodDef != null && ctorMethodDef.DeclaringType.IsValueType) - return; - - // Recognize field initializers: - // Convert first statement in all ctors (if all ctors have the same statement) into a field initializer. - bool allSame; - do { - Match m = fieldInitializerPattern.Match(instanceCtorsNotChainingWithThis[0].Body.FirstOrDefault()); - if (!m.Success) - break; - - FieldDefinition fieldDef = m.Get("fieldAccess").Single().Annotation().ResolveWithinSameModule(); - if (fieldDef == null) - break; - AstNode fieldOrEventDecl = members.FirstOrDefault(f => f.Annotation() == fieldDef); - if (fieldOrEventDecl == null) - break; - Expression initializer = m.Get("initializer").Single(); - // 'this'/'base' cannot be used in field initializers - if (initializer.DescendantsAndSelf.Any(n => n is ThisReferenceExpression || n is BaseReferenceExpression)) - break; - - allSame = true; - for (int i = 1; i < instanceCtorsNotChainingWithThis.Length; i++) { - if (!instanceCtors[0].Body.First().IsMatch(instanceCtorsNotChainingWithThis[i].Body.FirstOrDefault())) - allSame = false; - } - if (allSame) { - foreach (var ctor in instanceCtorsNotChainingWithThis) - ctor.Body.First().Remove(); - fieldOrEventDecl.GetChildrenByRole(Roles.Variable).Single().Initializer = initializer.Detach(); - } - } while (allSame); - } - } - - void RemoveSingleEmptyConstructor(TypeDeclaration typeDeclaration) - { - var instanceCtors = typeDeclaration.Members.OfType().Where(c => (c.Modifiers & Modifiers.Static) == 0).ToArray(); - if (instanceCtors.Length == 1) { - ConstructorDeclaration emptyCtor = new ConstructorDeclaration(); - emptyCtor.Modifiers = ((typeDeclaration.Modifiers & Modifiers.Abstract) == Modifiers.Abstract ? Modifiers.Protected : Modifiers.Public); - emptyCtor.Body = new BlockStatement(); - if (emptyCtor.IsMatch(instanceCtors[0])) - instanceCtors[0].Remove(); - } - } - - void HandleStaticFieldInitializers(IEnumerable members) - { - // Convert static constructor into field initializers if the class is BeforeFieldInit - var staticCtor = members.OfType().FirstOrDefault(c => (c.Modifiers & Modifiers.Static) == Modifiers.Static); - if (staticCtor != null) { - MethodDefinition ctorMethodDef = staticCtor.Annotation(); - if (ctorMethodDef != null && ctorMethodDef.DeclaringType.IsBeforeFieldInit) { - while (true) { - ExpressionStatement es = staticCtor.Body.Statements.FirstOrDefault() as ExpressionStatement; - if (es == null) - break; - AssignmentExpression assignment = es.Expression as AssignmentExpression; - if (assignment == null || assignment.Operator != AssignmentOperatorType.Assign) - break; - FieldDefinition fieldDef = assignment.Left.Annotation().ResolveWithinSameModule(); - if (fieldDef == null || !fieldDef.IsStatic) - break; - FieldDeclaration fieldDecl = members.OfType().FirstOrDefault(f => f.Annotation() == fieldDef); - if (fieldDecl == null) - break; - fieldDecl.Variables.Single().Initializer = assignment.Right.Detach(); - es.Remove(); - } - if (staticCtor.Body.Statements.Count == 0) - staticCtor.Remove(); - } - } - } - - void IAstTransform.Run(AstNode node) - { - // 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); - - node.AcceptVisitor(this, null); - } - } -} diff --git a/ICSharpCode.Decompiler/Ast/Transforms/CustomPatterns.cs b/ICSharpCode.Decompiler/Ast/Transforms/CustomPatterns.cs deleted file mode 100644 index b80c56af..00000000 --- a/ICSharpCode.Decompiler/Ast/Transforms/CustomPatterns.cs +++ /dev/null @@ -1,109 +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.Linq; -using System.Reflection; -using ICSharpCode.NRefactory.CSharp; -using ICSharpCode.NRefactory.PatternMatching; -using Mono.Cecil; - -namespace ICSharpCode.Decompiler.Ast.Transforms -{ - internal sealed class TypePattern : Pattern - { - readonly string ns; - readonly string name; - - public TypePattern(Type type) - { - ns = type.Namespace; - name = type.Name; - } - - public override bool DoMatch(INode other, Match match) - { - ComposedType ct = other as ComposedType; - AstType o; - if (ct != null && !ct.HasNullableSpecifier && ct.PointerRank == 0 && !ct.ArraySpecifiers.Any()) { - // Special case: ILSpy sometimes produces a ComposedType but then removed all array specifiers - // from it. In that case, we need to look at the base type for the annotations. - o = ct.BaseType; - } else { - o = other as AstType; - if (o == null) - return false; - } - TypeReference tr = o.Annotation(); - return tr != null && tr.Namespace == ns && tr.Name == name; - } - - public override string ToString() - { - return name; - } - } - - internal sealed class LdTokenPattern : Pattern - { - AnyNode childNode; - - public LdTokenPattern(string groupName) - { - childNode = new AnyNode(groupName); - } - - public override bool DoMatch(INode other, Match match) - { - InvocationExpression ie = other as InvocationExpression; - if (ie != null && ie.Annotation() != null && ie.Arguments.Count == 1) { - return childNode.DoMatch(ie.Arguments.Single(), match); - } - return false; - } - - public override string ToString() - { - return "ldtoken(...)"; - } - } - - /// - /// typeof-Pattern that applies on the expanded form of typeof (prior to ReplaceMethodCallsWithOperators) - /// - internal sealed class TypeOfPattern : Pattern - { - INode childNode; - - public TypeOfPattern(string groupName) - { - childNode = new TypePattern(typeof(Type)).ToType().Invoke( - "GetTypeFromHandle", new TypeOfExpression(new AnyNode(groupName)).Member("TypeHandle")); - } - - public override bool DoMatch(INode other, Match match) - { - return childNode.DoMatch(other, match); - } - - public override string ToString() - { - return "typeof(...)"; - } - } -} diff --git a/ICSharpCode.Decompiler/Ast/Transforms/DecimalConstantTransform.cs b/ICSharpCode.Decompiler/Ast/Transforms/DecimalConstantTransform.cs deleted file mode 100644 index 298682af..00000000 --- a/ICSharpCode.Decompiler/Ast/Transforms/DecimalConstantTransform.cs +++ /dev/null @@ -1,58 +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 ICSharpCode.NRefactory.CSharp; -using ICSharpCode.NRefactory.PatternMatching; -using Mono.Cecil; - -namespace ICSharpCode.Decompiler.Ast.Transforms -{ - /// - /// Transforms decimal constant fields. - /// - public class DecimalConstantTransform : DepthFirstAstVisitor, IAstTransform - { - static readonly PrimitiveType decimalType = new PrimitiveType("decimal"); - - public override object VisitFieldDeclaration(FieldDeclaration fieldDeclaration, object data) - { - const Modifiers staticReadOnly = Modifiers.Static | Modifiers.Readonly; - if ((fieldDeclaration.Modifiers & staticReadOnly) == staticReadOnly && decimalType.IsMatch(fieldDeclaration.ReturnType)) { - foreach (var attributeSection in fieldDeclaration.Attributes) { - foreach (var attribute in attributeSection.Attributes) { - TypeReference tr = attribute.Type.Annotation(); - if (tr != null && tr.Name == "DecimalConstantAttribute" && tr.Namespace == "System.Runtime.CompilerServices") { - attribute.Remove(); - if (attributeSection.Attributes.Count == 0) - attributeSection.Remove(); - fieldDeclaration.Modifiers = (fieldDeclaration.Modifiers & ~staticReadOnly) | Modifiers.Const; - return null; - } - } - } - } - return null; - } - - public void Run(AstNode compilationUnit) - { - compilationUnit.AcceptVisitor(this, null); - } - } -} diff --git a/ICSharpCode.Decompiler/Ast/Transforms/DeclareVariables.cs b/ICSharpCode.Decompiler/Ast/Transforms/DeclareVariables.cs deleted file mode 100644 index a27f30b4..00000000 --- a/ICSharpCode.Decompiler/Ast/Transforms/DeclareVariables.cs +++ /dev/null @@ -1,368 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Threading; -using ICSharpCode.Decompiler.ILAst; -using ICSharpCode.NRefactory.CSharp; -using ICSharpCode.NRefactory.CSharp.Analysis; - -namespace ICSharpCode.Decompiler.Ast.Transforms -{ - /// - /// Moves variable declarations to improved positions. - /// - public class DeclareVariables : IAstTransform - { - sealed class VariableToDeclare - { - public AstType Type; - public string Name; - public ILVariable ILVariable; - - public AssignmentExpression ReplacedAssignment; - public Statement InsertionPoint; - } - - readonly CancellationToken cancellationToken; - List variablesToDeclare = new List(); - - public DeclareVariables(DecompilerContext context) - { - cancellationToken = context.CancellationToken; - } - - public void Run(AstNode node) - { - Run(node, null); - // Declare all the variables at the end, after all the logic has run. - // This is done so that definite assignment analysis can work on a single representation and doesn't have to be updated - // when we change the AST. - foreach (var v in variablesToDeclare) { - if (v.ReplacedAssignment == null) { - BlockStatement block = (BlockStatement)v.InsertionPoint.Parent; - var decl = new VariableDeclarationStatement((AstType)v.Type.Clone(), v.Name); - if (v.ILVariable != null) - decl.Variables.Single().AddAnnotation(v.ILVariable); - block.Statements.InsertBefore( - v.InsertionPoint, - decl); - } - } - // First do all the insertions, then do all the replacements. This is necessary because a replacement might remove our reference point from the AST. - foreach (var v in variablesToDeclare) { - if (v.ReplacedAssignment != null) { - // We clone the right expression so that it doesn't get removed from the old ExpressionStatement, - // which might be still in use by the definite assignment graph. - VariableInitializer initializer = new VariableInitializer(v.Name, v.ReplacedAssignment.Right.Detach()).CopyAnnotationsFrom(v.ReplacedAssignment).WithAnnotation(v.ILVariable); - VariableDeclarationStatement varDecl = new VariableDeclarationStatement { - Type = (AstType)v.Type.Clone(), - Variables = { initializer } - }; - ExpressionStatement es = v.ReplacedAssignment.Parent as ExpressionStatement; - if (es != null) { - // Note: if this crashes with 'Cannot replace the root node', check whether two variables were assigned the same name - es.ReplaceWith(varDecl.CopyAnnotationsFrom(es)); - } else { - v.ReplacedAssignment.ReplaceWith(varDecl); - } - } - } - variablesToDeclare = null; - } - - void Run(AstNode node, DefiniteAssignmentAnalysis daa) - { - BlockStatement block = node as BlockStatement; - if (block != null) { - var variables = block.Statements.TakeWhile(stmt => stmt is VariableDeclarationStatement) - .Cast().ToList(); - if (variables.Count > 0) { - // remove old variable declarations: - foreach (VariableDeclarationStatement varDecl in variables) { - Debug.Assert(varDecl.Variables.Single().Initializer.IsNull); - varDecl.Remove(); - } - if (daa == null) { - // If possible, reuse the DefiniteAssignmentAnalysis that was created for the parent block - daa = new DefiniteAssignmentAnalysis(block, cancellationToken); - } - foreach (VariableDeclarationStatement varDecl in variables) { - VariableInitializer initializer = varDecl.Variables.Single(); - string variableName = initializer.Name; - ILVariable v = initializer.Annotation(); - bool allowPassIntoLoops = initializer.Annotation() == null; - DeclareVariableInBlock(daa, block, varDecl.Type, variableName, v, allowPassIntoLoops); - } - } - } - for (AstNode child = node.FirstChild; child != null; child = child.NextSibling) { - Run(child, daa); - } - } - - void DeclareVariableInBlock(DefiniteAssignmentAnalysis daa, BlockStatement block, AstType type, string variableName, ILVariable v, bool allowPassIntoLoops) - { - // declarationPoint: The point where the variable would be declared, if we decide to declare it in this block - Statement declarationPoint = null; - // Check whether we can move down the variable into the sub-blocks - bool canMoveVariableIntoSubBlocks = FindDeclarationPoint(daa, variableName, allowPassIntoLoops, block, out declarationPoint); - if (declarationPoint == null) { - // The variable isn't used at all - return; - } - if (canMoveVariableIntoSubBlocks) { - // Declare the variable within the sub-blocks - foreach (Statement stmt in block.Statements) { - ForStatement forStmt = stmt as ForStatement; - if (forStmt != null && forStmt.Initializers.Count == 1) { - // handle the special case of moving a variable into the for initializer - if (TryConvertAssignmentExpressionIntoVariableDeclaration(forStmt.Initializers.Single(), type, variableName)) - continue; - } - UsingStatement usingStmt = stmt as UsingStatement; - if (usingStmt != null && usingStmt.ResourceAcquisition is AssignmentExpression) { - // handle the special case of moving a variable into a using statement - if (TryConvertAssignmentExpressionIntoVariableDeclaration((Expression)usingStmt.ResourceAcquisition, type, variableName)) - continue; - } - IfElseStatement ies = stmt as IfElseStatement; - if (ies != null) { - foreach (var child in IfElseChainChildren(ies)) { - BlockStatement subBlock = child as BlockStatement; - if (subBlock != null) - DeclareVariableInBlock(daa, subBlock, type, variableName, v, allowPassIntoLoops); - } - continue; - } - foreach (AstNode child in stmt.Children) { - BlockStatement subBlock = child as BlockStatement; - if (subBlock != null) { - DeclareVariableInBlock(daa, subBlock, type, variableName, v, allowPassIntoLoops); - } else if (HasNestedBlocks(child)) { - foreach (BlockStatement nestedSubBlock in child.Children.OfType()) { - DeclareVariableInBlock(daa, nestedSubBlock, type, variableName, v, allowPassIntoLoops); - } - } - } - } - } else { - // Try converting an assignment expression into a VariableDeclarationStatement - if (!TryConvertAssignmentExpressionIntoVariableDeclaration(declarationPoint, type, variableName)) { - // Declare the variable in front of declarationPoint - variablesToDeclare.Add(new VariableToDeclare { Type = type, Name = variableName, ILVariable = v, InsertionPoint = declarationPoint }); - } - } - } - - bool TryConvertAssignmentExpressionIntoVariableDeclaration(Statement declarationPoint, AstType type, string variableName) - { - // convert the declarationPoint into a VariableDeclarationStatement - ExpressionStatement es = declarationPoint as ExpressionStatement; - if (es != null) { - return TryConvertAssignmentExpressionIntoVariableDeclaration(es.Expression, type, variableName); - } - return false; - } - - bool TryConvertAssignmentExpressionIntoVariableDeclaration(Expression expression, AstType type, string variableName) - { - AssignmentExpression ae = expression as AssignmentExpression; - if (ae != null && ae.Operator == AssignmentOperatorType.Assign) { - IdentifierExpression ident = ae.Left as IdentifierExpression; - if (ident != null && ident.Identifier == variableName) { - variablesToDeclare.Add(new VariableToDeclare { Type = type, Name = variableName, ILVariable = ident.Annotation(), ReplacedAssignment = ae }); - return true; - } - } - return false; - } - - /// - /// Finds the declaration point for the variable within the specified block. - /// - /// - /// Definite assignment analysis, must be prepared for 'block' or one of its parents. - /// - /// The variable to declare - /// The block in which the variable should be declared - /// - /// Output parameter: the first statement within 'block' where the variable needs to be declared. - /// - /// - /// Returns whether it is possible to move the variable declaration into sub-blocks. - /// - public static bool FindDeclarationPoint(DefiniteAssignmentAnalysis daa, VariableDeclarationStatement varDecl, BlockStatement block, out Statement declarationPoint) - { - string variableName = varDecl.Variables.Single().Name; - bool allowPassIntoLoops = varDecl.Variables.Single().Annotation() == null; - return FindDeclarationPoint(daa, variableName, allowPassIntoLoops, block, out declarationPoint); - } - - static bool FindDeclarationPoint(DefiniteAssignmentAnalysis daa, string variableName, bool allowPassIntoLoops, BlockStatement block, out Statement declarationPoint) - { - // declarationPoint: The point where the variable would be declared, if we decide to declare it in this block - declarationPoint = null; - foreach (Statement stmt in block.Statements) { - if (UsesVariable(stmt, variableName)) { - if (declarationPoint == null) - declarationPoint = stmt; - if (!CanMoveVariableUseIntoSubBlock(stmt, variableName, allowPassIntoLoops)) { - // If it's not possible to move the variable use into a nested block, - // we need to declare the variable in this block - return false; - } - // If we can move the variable into the sub-block, we need to ensure that the remaining code - // does not use the value that was assigned by the first sub-block - Statement nextStatement = stmt.GetNextStatement(); - if (nextStatement != null) { - // Analyze the range from the next statement to the end of the block - daa.SetAnalyzedRange(nextStatement, block); - daa.Analyze(variableName); - if (daa.UnassignedVariableUses.Count > 0) { - return false; - } - } - } - } - return true; - } - - static bool CanMoveVariableUseIntoSubBlock(Statement stmt, string variableName, bool allowPassIntoLoops) - { - if (!allowPassIntoLoops && (stmt is ForStatement || stmt is ForeachStatement || stmt is DoWhileStatement || stmt is WhileStatement)) - return false; - - ForStatement forStatement = stmt as ForStatement; - if (forStatement != null && forStatement.Initializers.Count == 1) { - // for-statement is special case: we can move variable declarations into the initializer - ExpressionStatement es = forStatement.Initializers.Single() as ExpressionStatement; - if (es != null) { - AssignmentExpression ae = es.Expression as AssignmentExpression; - if (ae != null && ae.Operator == AssignmentOperatorType.Assign) { - IdentifierExpression ident = ae.Left as IdentifierExpression; - if (ident != null && ident.Identifier == variableName) { - return !UsesVariable(ae.Right, variableName); - } - } - } - } - - UsingStatement usingStatement = stmt as UsingStatement; - if (usingStatement != null) { - // using-statement is special case: we can move variable declarations into the initializer - AssignmentExpression ae = usingStatement.ResourceAcquisition as AssignmentExpression; - if (ae != null && ae.Operator == AssignmentOperatorType.Assign) { - IdentifierExpression ident = ae.Left as IdentifierExpression; - if (ident != null && ident.Identifier == variableName) { - return !UsesVariable(ae.Right, variableName); - } - } - } - - IfElseStatement ies = stmt as IfElseStatement; - if (ies != null) { - foreach (var child in IfElseChainChildren(ies)) { - if (!(child is BlockStatement) && UsesVariable(child, variableName)) - return false; - } - return true; - } - - // We can move the variable into a sub-block only if the variable is used in only that sub-block (and not in expressions such as the loop condition) - for (AstNode child = stmt.FirstChild; child != null; child = child.NextSibling) { - if (!(child is BlockStatement) && UsesVariable(child, variableName)) { - if (HasNestedBlocks(child)) { - // catch clauses/switch sections can contain nested blocks - for (AstNode grandchild = child.FirstChild; grandchild != null; grandchild = grandchild.NextSibling) { - if (!(grandchild is BlockStatement) && UsesVariable(grandchild, variableName)) - return false; - } - } else { - return false; - } - } - } - return true; - } - - static IEnumerable IfElseChainChildren(IfElseStatement ies) - { - IfElseStatement prev; - do { - yield return ies.Condition; - yield return ies.TrueStatement; - prev = ies; - ies = ies.FalseStatement as IfElseStatement; - } while (ies != null); - if (!prev.FalseStatement.IsNull) - yield return prev.FalseStatement; - } - - static bool HasNestedBlocks(AstNode node) - { - return node is CatchClause || node is SwitchSection; - } - - static bool UsesVariable(AstNode node, string variableName) - { - IdentifierExpression ie = node as IdentifierExpression; - if (ie != null && ie.Identifier == variableName) - return true; - - FixedStatement fixedStatement = node as FixedStatement; - if (fixedStatement != null) { - foreach (VariableInitializer v in fixedStatement.Variables) { - if (v.Name == variableName) - return false; // no need to introduce the variable here - } - } - - ForeachStatement foreachStatement = node as ForeachStatement; - if (foreachStatement != null) { - if (foreachStatement.VariableName == variableName) - return false; // no need to introduce the variable here - } - - UsingStatement usingStatement = node as UsingStatement; - if (usingStatement != null) { - VariableDeclarationStatement varDecl = usingStatement.ResourceAcquisition as VariableDeclarationStatement; - if (varDecl != null) { - foreach (VariableInitializer v in varDecl.Variables) { - if (v.Name == variableName) - return false; // no need to introduce the variable here - } - } - } - - CatchClause catchClause = node as CatchClause; - if (catchClause != null && catchClause.VariableName == variableName) { - return false; // no need to introduce the variable here - } - - for (AstNode child = node.FirstChild; child != null; child = child.NextSibling) { - if (UsesVariable(child, variableName)) - return true; - } - return false; - } - } -} diff --git a/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs b/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs deleted file mode 100644 index 04b2293d..00000000 --- a/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs +++ /dev/null @@ -1,502 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Threading; -using ICSharpCode.Decompiler; -using ICSharpCode.Decompiler.ILAst; -using ICSharpCode.NRefactory.CSharp; -using ICSharpCode.NRefactory.PatternMatching; -using Mono.Cecil; - -namespace ICSharpCode.Decompiler.Ast.Transforms -{ - /// - /// Converts "new Action(obj, ldftn(func))" into "new Action(obj.func)". - /// For anonymous methods, creates an AnonymousMethodExpression. - /// Also gets rid of any "Display Classes" left over after inlining an anonymous method. - /// - public class DelegateConstruction : ContextTrackingVisitor - { - internal sealed class Annotation - { - /// - /// ldftn or ldvirtftn? - /// - public readonly bool IsVirtual; - - public Annotation(bool isVirtual) - { - IsVirtual = isVirtual; - } - } - - internal sealed class CapturedVariableAnnotation - { - } - - List currentlyUsedVariableNames = new List(); - - public DelegateConstruction(DecompilerContext context) : base(context) - { - } - - public override object VisitObjectCreateExpression(ObjectCreateExpression objectCreateExpression, object data) - { - if (objectCreateExpression.Arguments.Count == 2) { - Expression obj = objectCreateExpression.Arguments.First(); - Expression func = objectCreateExpression.Arguments.Last(); - Annotation annotation = func.Annotation(); - if (annotation != null) { - IdentifierExpression methodIdent = (IdentifierExpression)((InvocationExpression)func).Arguments.Single(); - MethodReference method = methodIdent.Annotation(); - if (method != null) { - if (HandleAnonymousMethod(objectCreateExpression, obj, method)) - return null; - // Perform the transformation to "new Action(obj.func)". - obj.Remove(); - methodIdent.Remove(); - if (!annotation.IsVirtual && obj is ThisReferenceExpression) { - // maybe it's getting the pointer of a base method? - if (method.DeclaringType.GetElementType() != context.CurrentType) { - obj = new BaseReferenceExpression(); - } - } - if (!annotation.IsVirtual && obj is NullReferenceExpression && !method.HasThis) { - // We're loading a static method. - // However it is possible to load extension methods with an instance, so we compare the number of arguments: - bool isExtensionMethod = false; - TypeReference delegateType = objectCreateExpression.Type.Annotation(); - if (delegateType != null) { - TypeDefinition delegateTypeDef = delegateType.Resolve(); - if (delegateTypeDef != null) { - MethodDefinition invokeMethod = delegateTypeDef.Methods.FirstOrDefault(m => m.Name == "Invoke"); - if (invokeMethod != null) { - isExtensionMethod = (invokeMethod.Parameters.Count + 1 == method.Parameters.Count); - } - } - } - if (!isExtensionMethod) { - obj = new TypeReferenceExpression { Type = AstBuilder.ConvertType(method.DeclaringType) }; - } - } - // now transform the identifier into a member reference - MemberReferenceExpression mre = new MemberReferenceExpression(); - mre.Target = obj; - mre.MemberName = methodIdent.Identifier; - methodIdent.TypeArguments.MoveTo(mre.TypeArguments); - mre.AddAnnotation(method); - objectCreateExpression.Arguments.Clear(); - objectCreateExpression.Arguments.Add(mre); - return null; - } - } - } - return base.VisitObjectCreateExpression(objectCreateExpression, data); - } - - internal static bool IsAnonymousMethod(DecompilerContext context, MethodDefinition method) - { - if (method == null || !(method.HasGeneratedName() || method.Name.Contains("$"))) - return false; - if (!(method.IsCompilerGenerated() || IsPotentialClosure(context, method.DeclaringType))) - return false; - return true; - } - - bool HandleAnonymousMethod(ObjectCreateExpression objectCreateExpression, Expression target, MethodReference methodRef) - { - if (!context.Settings.AnonymousMethods) - return false; // anonymous method decompilation is disabled - if (target != null && !(target is IdentifierExpression || target is ThisReferenceExpression || target is NullReferenceExpression)) - return false; // don't copy arbitrary expressions, deal with identifiers only - - // Anonymous methods are defined in the same assembly - MethodDefinition method = methodRef.ResolveWithinSameModule(); - if (!IsAnonymousMethod(context, method)) - return false; - - // Create AnonymousMethodExpression and prepare parameters - AnonymousMethodExpression ame = new AnonymousMethodExpression(); - ame.CopyAnnotationsFrom(objectCreateExpression); // copy ILRanges etc. - ame.RemoveAnnotations(); // remove reference to delegate ctor - ame.AddAnnotation(method); // add reference to anonymous method - ame.Parameters.AddRange(AstBuilder.MakeParameters(method, isLambda: true)); - ame.HasParameterList = true; - - // rename variables so that they don't conflict with the parameters: - foreach (ParameterDeclaration pd in ame.Parameters) { - EnsureVariableNameIsAvailable(objectCreateExpression, pd.Name); - } - - // Decompile the anonymous method: - - DecompilerContext subContext = context.Clone(); - subContext.CurrentMethod = method; - subContext.CurrentMethodIsAsync = false; - subContext.ReservedVariableNames.AddRange(currentlyUsedVariableNames); - BlockStatement body = AstMethodBodyBuilder.CreateMethodBody(method, subContext, ame.Parameters); - TransformationPipeline.RunTransformationsUntil(body, v => v is DelegateConstruction, subContext); - body.AcceptVisitor(this, null); - - - bool isLambda = false; - if (ame.Parameters.All(p => p.ParameterModifier == ParameterModifier.None)) { - isLambda = (body.Statements.Count == 1 && body.Statements.Single() is ReturnStatement); - } - // Remove the parameter list from an AnonymousMethodExpression if the original method had no names, - // and the parameters are not used in the method body - if (!isLambda && method.Parameters.All(p => string.IsNullOrEmpty(p.Name))) { - var parameterReferencingIdentifiers = - from ident in body.Descendants.OfType() - let v = ident.Annotation() - where v != null && v.IsParameter && method.Parameters.Contains(v.OriginalParameter) - select ident; - if (!parameterReferencingIdentifiers.Any()) { - ame.Parameters.Clear(); - ame.HasParameterList = false; - } - } - - // Replace all occurrences of 'this' in the method body with the delegate's target: - foreach (AstNode node in body.Descendants) { - if (node is ThisReferenceExpression) - node.ReplaceWith(target.Clone()); - } - Expression replacement; - if (isLambda) { - LambdaExpression lambda = new LambdaExpression(); - lambda.CopyAnnotationsFrom(ame); - ame.Parameters.MoveTo(lambda.Parameters); - Expression returnExpr = ((ReturnStatement)body.Statements.Single()).Expression; - returnExpr.Remove(); - lambda.Body = returnExpr; - replacement = lambda; - } else { - ame.Body = body; - replacement = ame; - } - var expectedType = objectCreateExpression.Annotation().ExpectedType.Resolve(); - if (expectedType != null && !expectedType.IsDelegate()) { - var simplifiedDelegateCreation = (ObjectCreateExpression)objectCreateExpression.Clone(); - simplifiedDelegateCreation.Arguments.Clear(); - simplifiedDelegateCreation.Arguments.Add(replacement); - replacement = simplifiedDelegateCreation; - } - objectCreateExpression.ReplaceWith(replacement); - return true; - } - - internal static bool IsPotentialClosure(DecompilerContext context, TypeDefinition potentialDisplayClass) - { - if (potentialDisplayClass == null || !potentialDisplayClass.IsCompilerGeneratedOrIsInCompilerGeneratedClass()) - return false; - // check that methodContainingType is within containingType - while (potentialDisplayClass != context.CurrentType) { - potentialDisplayClass = potentialDisplayClass.DeclaringType; - if (potentialDisplayClass == null) - return false; - } - return true; - } - - public override object VisitInvocationExpression(InvocationExpression invocationExpression, object data) - { - if (context.Settings.ExpressionTrees && ExpressionTreeConverter.CouldBeExpressionTree(invocationExpression)) { - Expression converted = ExpressionTreeConverter.TryConvert(context, invocationExpression); - if (converted != null) { - invocationExpression.ReplaceWith(converted); - return converted.AcceptVisitor(this, data); - } - } - return base.VisitInvocationExpression(invocationExpression, data); - } - - #region Track current variables - public override object VisitMethodDeclaration(MethodDeclaration methodDeclaration, object data) - { - Debug.Assert(currentlyUsedVariableNames.Count == 0); - try { - currentlyUsedVariableNames.AddRange(methodDeclaration.Parameters.Select(p => p.Name)); - return base.VisitMethodDeclaration(methodDeclaration, data); - } finally { - currentlyUsedVariableNames.Clear(); - } - } - - public override object VisitOperatorDeclaration(OperatorDeclaration operatorDeclaration, object data) - { - Debug.Assert(currentlyUsedVariableNames.Count == 0); - try { - currentlyUsedVariableNames.AddRange(operatorDeclaration.Parameters.Select(p => p.Name)); - return base.VisitOperatorDeclaration(operatorDeclaration, data); - } finally { - currentlyUsedVariableNames.Clear(); - } - } - - public override object VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration, object data) - { - Debug.Assert(currentlyUsedVariableNames.Count == 0); - try { - currentlyUsedVariableNames.AddRange(constructorDeclaration.Parameters.Select(p => p.Name)); - return base.VisitConstructorDeclaration(constructorDeclaration, data); - } finally { - currentlyUsedVariableNames.Clear(); - } - } - - public override object VisitIndexerDeclaration(IndexerDeclaration indexerDeclaration, object data) - { - Debug.Assert(currentlyUsedVariableNames.Count == 0); - try { - currentlyUsedVariableNames.AddRange(indexerDeclaration.Parameters.Select(p => p.Name)); - return base.VisitIndexerDeclaration(indexerDeclaration, data); - } finally { - currentlyUsedVariableNames.Clear(); - } - } - - public override object VisitAccessor(Accessor accessor, object data) - { - try { - currentlyUsedVariableNames.Add("value"); - return base.VisitAccessor(accessor, data); - } finally { - currentlyUsedVariableNames.RemoveAt(currentlyUsedVariableNames.Count - 1); - } - } - - public override object VisitVariableDeclarationStatement(VariableDeclarationStatement variableDeclarationStatement, object data) - { - foreach (VariableInitializer v in variableDeclarationStatement.Variables) - currentlyUsedVariableNames.Add(v.Name); - return base.VisitVariableDeclarationStatement(variableDeclarationStatement, data); - } - - public override object VisitFixedStatement(FixedStatement fixedStatement, object data) - { - foreach (VariableInitializer v in fixedStatement.Variables) - currentlyUsedVariableNames.Add(v.Name); - return base.VisitFixedStatement(fixedStatement, data); - } - #endregion - - static readonly ExpressionStatement displayClassAssignmentPattern = - new ExpressionStatement(new AssignmentExpression( - new NamedNode("variable", new IdentifierExpression(Pattern.AnyString)), - new ObjectCreateExpression { Type = new AnyNode("type") } - )); - - public override object VisitBlockStatement(BlockStatement blockStatement, object data) - { - int numberOfVariablesOutsideBlock = currentlyUsedVariableNames.Count; - base.VisitBlockStatement(blockStatement, data); - foreach (ExpressionStatement stmt in blockStatement.Statements.OfType().ToArray()) { - Match displayClassAssignmentMatch = displayClassAssignmentPattern.Match(stmt); - if (!displayClassAssignmentMatch.Success) - continue; - - ILVariable variable = displayClassAssignmentMatch.Get("variable").Single().Annotation(); - if (variable == null) - continue; - TypeDefinition type = variable.Type.ResolveWithinSameModule(); - if (!IsPotentialClosure(context, type)) - continue; - if (displayClassAssignmentMatch.Get("type").Single().Annotation().ResolveWithinSameModule() != type) - continue; - - // Looks like we found a display class creation. Now let's verify that the variable is used only for field accesses: - bool ok = true; - foreach (var identExpr in blockStatement.Descendants.OfType()) { - if (identExpr.Identifier == variable.Name && identExpr != displayClassAssignmentMatch.Get("variable").Single()) { - if (!(identExpr.Parent is MemberReferenceExpression && identExpr.Parent.Annotation() != null)) - ok = false; - } - } - if (!ok) - continue; - Dictionary dict = new Dictionary(); - - // Delete the variable declaration statement: - VariableDeclarationStatement displayClassVarDecl = PatternStatementTransform.FindVariableDeclaration(stmt, variable.Name); - if (displayClassVarDecl != null) - displayClassVarDecl.Remove(); - - // Delete the assignment statement: - AstNode cur = stmt.NextSibling; - stmt.Remove(); - - // Delete any following statements as long as they assign parameters to the display class - BlockStatement rootBlock = blockStatement.Ancestors.OfType().LastOrDefault() ?? blockStatement; - List parameterOccurrances = rootBlock.Descendants.OfType() - .Select(n => n.Annotation()).Where(p => p != null && p.IsParameter).ToList(); - AstNode next; - for (; cur != null; cur = next) { - next = cur.NextSibling; - - // Test for the pattern: - // "variableName.MemberName = right;" - ExpressionStatement closureFieldAssignmentPattern = new ExpressionStatement( - new AssignmentExpression( - new NamedNode("left", new MemberReferenceExpression { - Target = new IdentifierExpression(variable.Name), - MemberName = Pattern.AnyString - }), - new AnyNode("right") - ) - ); - Match m = closureFieldAssignmentPattern.Match(cur); - if (m.Success) { - FieldDefinition fieldDef = m.Get("left").Single().Annotation().ResolveWithinSameModule(); - AstNode right = m.Get("right").Single(); - bool isParameter = false; - bool isDisplayClassParentPointerAssignment = false; - if (right is ThisReferenceExpression) { - isParameter = true; - } else if (right is IdentifierExpression) { - // handle parameters only if the whole method contains no other occurrence except for 'right' - ILVariable v = right.Annotation(); - isParameter = v.IsParameter && parameterOccurrances.Count(c => c == v) == 1; - if (!isParameter && IsPotentialClosure(context, v.Type.ResolveWithinSameModule())) { - // parent display class within the same method - // (closure2.localsX = closure1;) - isDisplayClassParentPointerAssignment = true; - } - } else if (right is MemberReferenceExpression) { - // copy of parent display class reference from an outer lambda - // closure2.localsX = this.localsY - MemberReferenceExpression mre = m.Get("right").Single(); - do { - // descend into the targets of the mre as long as the field types are closures - FieldDefinition fieldDef2 = mre.Annotation().ResolveWithinSameModule(); - if (fieldDef2 == null || !IsPotentialClosure(context, fieldDef2.FieldType.ResolveWithinSameModule())) { - break; - } - // if we finally get to a this reference, it's copying a display class parent pointer - if (mre.Target is ThisReferenceExpression) { - isDisplayClassParentPointerAssignment = true; - } - mre = mre.Target as MemberReferenceExpression; - } while (mre != null); - } - if (isParameter || isDisplayClassParentPointerAssignment) { - dict[fieldDef] = right; - cur.Remove(); - } else { - break; - } - } else { - break; - } - } - - // Now create variables for all fields of the display class (except for those that we already handled as parameters) - List> variablesToDeclare = new List>(); - foreach (FieldDefinition field in type.Fields) { - if (field.IsStatic) - continue; // skip static fields - if (dict.ContainsKey(field)) // skip field if it already was handled as parameter - continue; - string capturedVariableName = field.Name; - if (capturedVariableName.StartsWith("$VB$Local_", StringComparison.Ordinal) && capturedVariableName.Length > 10) - capturedVariableName = capturedVariableName.Substring(10); - EnsureVariableNameIsAvailable(blockStatement, capturedVariableName); - currentlyUsedVariableNames.Add(capturedVariableName); - ILVariable ilVar = new ILVariable - { - IsGenerated = true, - Name = capturedVariableName, - Type = field.FieldType, - }; - variablesToDeclare.Add(Tuple.Create(AstBuilder.ConvertType(field.FieldType, field), ilVar)); - dict[field] = new IdentifierExpression(capturedVariableName).WithAnnotation(ilVar); - } - - // Now figure out where the closure was accessed and use the simpler replacement expression there: - foreach (var identExpr in blockStatement.Descendants.OfType()) { - if (identExpr.Identifier == variable.Name) { - MemberReferenceExpression mre = (MemberReferenceExpression)identExpr.Parent; - AstNode replacement; - if (dict.TryGetValue(mre.Annotation().ResolveWithinSameModule(), out replacement)) { - mre.ReplaceWith(replacement.Clone()); - } - } - } - // Now insert the variable declarations (we can do this after the replacements only so that the scope detection works): - Statement insertionPoint = blockStatement.Statements.FirstOrDefault(); - foreach (var tuple in variablesToDeclare) { - var newVarDecl = new VariableDeclarationStatement(tuple.Item1, tuple.Item2.Name); - newVarDecl.Variables.Single().AddAnnotation(new CapturedVariableAnnotation()); - newVarDecl.Variables.Single().AddAnnotation(tuple.Item2); - blockStatement.Statements.InsertBefore(insertionPoint, newVarDecl); - } - } - currentlyUsedVariableNames.RemoveRange(numberOfVariablesOutsideBlock, currentlyUsedVariableNames.Count - numberOfVariablesOutsideBlock); - return null; - } - - void EnsureVariableNameIsAvailable(AstNode currentNode, string name) - { - int pos = currentlyUsedVariableNames.IndexOf(name); - if (pos < 0) { - // name is still available - return; - } - // Naming conflict. Let's rename the existing variable so that the field keeps the name from metadata. - NameVariables nv = new NameVariables(); - // Add currently used variable and parameter names - foreach (string nameInUse in currentlyUsedVariableNames) - nv.AddExistingName(nameInUse); - // variables declared in child nodes of this block - foreach (VariableInitializer vi in currentNode.Descendants.OfType()) - nv.AddExistingName(vi.Name); - // parameters in child lambdas - foreach (ParameterDeclaration pd in currentNode.Descendants.OfType()) - nv.AddExistingName(pd.Name); - - string newName = nv.GetAlternativeName(name); - currentlyUsedVariableNames[pos] = newName; - - // find top-most block - AstNode topMostBlock = currentNode.Ancestors.OfType().LastOrDefault() ?? currentNode; - - // rename identifiers - foreach (IdentifierExpression ident in topMostBlock.Descendants.OfType()) { - if (ident.Identifier == name) { - ident.Identifier = newName; - ILVariable v = ident.Annotation(); - if (v != null) - v.Name = newName; - } - } - // rename variable declarations - foreach (VariableInitializer vi in topMostBlock.Descendants.OfType()) { - if (vi.Name == name) { - vi.Name = newName; - ILVariable v = vi.Annotation(); - if (v != null) - v.Name = newName; - } - } - } - } -} diff --git a/ICSharpCode.Decompiler/Ast/Transforms/ExpressionTreeConverter.cs b/ICSharpCode.Decompiler/Ast/Transforms/ExpressionTreeConverter.cs deleted file mode 100644 index 2327200d..00000000 --- a/ICSharpCode.Decompiler/Ast/Transforms/ExpressionTreeConverter.cs +++ /dev/null @@ -1,875 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Reflection; -using ICSharpCode.Decompiler.ILAst; -using ICSharpCode.NRefactory.CSharp; -using ICSharpCode.NRefactory.PatternMatching; -using Mono.Cecil; - -namespace ICSharpCode.Decompiler.Ast.Transforms -{ - public class ExpressionTreeConverter - { - #region static TryConvert method - public static bool CouldBeExpressionTree(InvocationExpression expr) - { - if (expr != null && expr.Arguments.Count == 2) { - MethodReference mr = expr.Annotation(); - return mr != null && mr.Name == "Lambda" && mr.DeclaringType.FullName == "System.Linq.Expressions.Expression"; - } - return false; - } - - public static Expression TryConvert(DecompilerContext context, Expression expr) - { - Expression converted = new ExpressionTreeConverter(context).Convert(expr); - if (converted != null) { - converted.AddAnnotation(new ExpressionTreeLambdaAnnotation()); - } - return converted; - } - #endregion - - readonly DecompilerContext context; - Stack activeLambdas = new Stack(); - - ExpressionTreeConverter(DecompilerContext context) - { - this.context = context; - } - - #region Main Convert method - Expression Convert(Expression expr) - { - InvocationExpression invocation = expr as InvocationExpression; - if (invocation != null) { - MethodReference mr = invocation.Annotation(); - if (mr != null && mr.DeclaringType.FullName == "System.Linq.Expressions.Expression") { - switch (mr.Name) { - case "Add": - return ConvertBinaryOperator(invocation, BinaryOperatorType.Add, false); - case "AddChecked": - return ConvertBinaryOperator(invocation, BinaryOperatorType.Add, true); - case "AddAssign": - return ConvertAssignmentOperator(invocation, AssignmentOperatorType.Add, false); - case "AddAssignChecked": - return ConvertAssignmentOperator(invocation, AssignmentOperatorType.Add, true); - case "And": - return ConvertBinaryOperator(invocation, BinaryOperatorType.BitwiseAnd); - case "AndAlso": - return ConvertBinaryOperator(invocation, BinaryOperatorType.ConditionalAnd); - case "AndAssign": - return ConvertAssignmentOperator(invocation, AssignmentOperatorType.BitwiseAnd); - case "ArrayAccess": - case "ArrayIndex": - return ConvertArrayIndex(invocation); - case "ArrayLength": - return ConvertArrayLength(invocation); - case "Assign": - return ConvertAssignmentOperator(invocation, AssignmentOperatorType.Assign); - case "Call": - return ConvertCall(invocation); - case "Coalesce": - return ConvertBinaryOperator(invocation, BinaryOperatorType.NullCoalescing); - case "Condition": - return ConvertCondition(invocation); - case "Constant": - if (invocation.Arguments.Count >= 1) - return invocation.Arguments.First().Clone(); - else - return NotSupported(expr); - case "Convert": - return ConvertCast(invocation, false); - case "ConvertChecked": - return ConvertCast(invocation, true); - case "Divide": - return ConvertBinaryOperator(invocation, BinaryOperatorType.Divide); - case "DivideAssign": - return ConvertAssignmentOperator(invocation, AssignmentOperatorType.Divide); - case "Equal": - return ConvertBinaryOperator(invocation, BinaryOperatorType.Equality); - case "ExclusiveOr": - return ConvertBinaryOperator(invocation, BinaryOperatorType.ExclusiveOr); - case "ExclusiveOrAssign": - return ConvertAssignmentOperator(invocation, AssignmentOperatorType.ExclusiveOr); - case "Field": - return ConvertField(invocation); - case "GreaterThan": - return ConvertBinaryOperator(invocation, BinaryOperatorType.GreaterThan); - case "GreaterThanOrEqual": - return ConvertBinaryOperator(invocation, BinaryOperatorType.GreaterThanOrEqual); - case "Invoke": - return ConvertInvoke(invocation); - case "Lambda": - return ConvertLambda(invocation); - case "LeftShift": - return ConvertBinaryOperator(invocation, BinaryOperatorType.ShiftLeft); - case "LeftShiftAssign": - return ConvertAssignmentOperator(invocation, AssignmentOperatorType.ShiftLeft); - case "LessThan": - return ConvertBinaryOperator(invocation, BinaryOperatorType.LessThan); - case "LessThanOrEqual": - return ConvertBinaryOperator(invocation, BinaryOperatorType.LessThanOrEqual); - case "ListInit": - return ConvertListInit(invocation); - case "MemberInit": - return ConvertMemberInit(invocation); - case "Modulo": - return ConvertBinaryOperator(invocation, BinaryOperatorType.Modulus); - case "ModuloAssign": - return ConvertAssignmentOperator(invocation, AssignmentOperatorType.Modulus); - case "Multiply": - return ConvertBinaryOperator(invocation, BinaryOperatorType.Multiply, false); - case "MultiplyChecked": - return ConvertBinaryOperator(invocation, BinaryOperatorType.Multiply, true); - case "MultiplyAssign": - return ConvertAssignmentOperator(invocation, AssignmentOperatorType.Multiply, false); - case "MultiplyAssignChecked": - return ConvertAssignmentOperator(invocation, AssignmentOperatorType.Multiply, true); - case "Negate": - return ConvertUnaryOperator(invocation, UnaryOperatorType.Minus, false); - case "NegateChecked": - return ConvertUnaryOperator(invocation, UnaryOperatorType.Minus, true); - case "New": - return ConvertNewObject(invocation); - case "NewArrayBounds": - return ConvertNewArrayBounds(invocation); - case "NewArrayInit": - return ConvertNewArrayInit(invocation); - case "Not": - return ConvertUnaryOperator(invocation, UnaryOperatorType.Not); - case "NotEqual": - return ConvertBinaryOperator(invocation, BinaryOperatorType.InEquality); - case "OnesComplement": - return ConvertUnaryOperator(invocation, UnaryOperatorType.BitNot); - case "Or": - return ConvertBinaryOperator(invocation, BinaryOperatorType.BitwiseOr); - case "OrAssign": - return ConvertAssignmentOperator(invocation, AssignmentOperatorType.BitwiseOr); - case "OrElse": - return ConvertBinaryOperator(invocation, BinaryOperatorType.ConditionalOr); - case "Property": - return ConvertProperty(invocation); - case "Quote": - if (invocation.Arguments.Count == 1) - return Convert(invocation.Arguments.Single()); - else - return NotSupported(invocation); - case "RightShift": - return ConvertBinaryOperator(invocation, BinaryOperatorType.ShiftRight); - case "RightShiftAssign": - return ConvertAssignmentOperator(invocation, AssignmentOperatorType.ShiftRight); - case "Subtract": - return ConvertBinaryOperator(invocation, BinaryOperatorType.Subtract, false); - case "SubtractChecked": - return ConvertBinaryOperator(invocation, BinaryOperatorType.Subtract, true); - case "SubtractAssign": - return ConvertAssignmentOperator(invocation, AssignmentOperatorType.Subtract, false); - case "SubtractAssignChecked": - return ConvertAssignmentOperator(invocation, AssignmentOperatorType.Subtract, true); - case "TypeAs": - return ConvertTypeAs(invocation); - case "TypeIs": - return ConvertTypeIs(invocation); - } - } - } - IdentifierExpression ident = expr as IdentifierExpression; - if (ident != null) { - ILVariable v = ident.Annotation(); - if (v != null) { - foreach (LambdaExpression lambda in activeLambdas) { - foreach (ParameterDeclaration p in lambda.Parameters) { - if (p.Annotation() == v) - return new IdentifierExpression(p.Name).WithAnnotation(v); - } - } - } - } - return NotSupported(expr); - } - - Expression NotSupported(Expression expr) - { - Debug.WriteLine("Expression Tree Conversion Failed: '" + expr + "' is not supported"); - return null; - } - #endregion - - #region Convert Lambda - static readonly Expression emptyArrayPattern = new ArrayCreateExpression { - Type = new AnyNode(), - Arguments = { new PrimitiveExpression(0) } - }; - - Expression ConvertLambda(InvocationExpression invocation) - { - if (invocation.Arguments.Count != 2) - return NotSupported(invocation); - LambdaExpression lambda = new LambdaExpression(); - Expression body = invocation.Arguments.First(); - ArrayCreateExpression parameterArray = invocation.Arguments.Last() as ArrayCreateExpression; - if (parameterArray == null) - return NotSupported(invocation); - - var annotation = body.Annotation(); - if (annotation != null) { - lambda.Parameters.AddRange(annotation.Parameters); - } else { - // No parameter declaration annotation found. - if (!emptyArrayPattern.IsMatch(parameterArray)) - return null; - } - - activeLambdas.Push(lambda); - Expression convertedBody = Convert(body); - activeLambdas.Pop(); - if (convertedBody == null) - return null; - lambda.Body = convertedBody; - return lambda; - } - #endregion - - #region Convert Field - static readonly Expression getFieldFromHandlePattern = - new TypePattern(typeof(FieldInfo)).ToType().Invoke( - "GetFieldFromHandle", - new LdTokenPattern("field").ToExpression().Member("FieldHandle"), - new OptionalNode(new TypeOfExpression(new AnyNode("declaringType")).Member("TypeHandle")) - ); - - Expression ConvertField(InvocationExpression invocation) - { - if (invocation.Arguments.Count != 2) - return NotSupported(invocation); - - Expression fieldInfoExpr = invocation.Arguments.ElementAt(1); - Match m = getFieldFromHandlePattern.Match(fieldInfoExpr); - if (!m.Success) - return NotSupported(invocation); - - FieldReference fr = m.Get("field").Single().Annotation(); - if (fr == null) - return null; - - Expression target = invocation.Arguments.ElementAt(0); - Expression convertedTarget; - if (target is NullReferenceExpression) { - if (m.Has("declaringType")) - convertedTarget = new TypeReferenceExpression(m.Get("declaringType").Single().Clone()); - else - convertedTarget = new TypeReferenceExpression(AstBuilder.ConvertType(fr.DeclaringType)); - } else { - convertedTarget = Convert(target); - if (convertedTarget == null) - return null; - } - - return convertedTarget.Member(fr.Name).WithAnnotation(fr); - } - #endregion - - #region Convert Property - static readonly Expression getMethodFromHandlePattern = - new TypePattern(typeof(MethodBase)).ToType().Invoke( - "GetMethodFromHandle", - new LdTokenPattern("method").ToExpression().Member("MethodHandle"), - new OptionalNode(new TypeOfExpression(new AnyNode("declaringType")).Member("TypeHandle")) - ).CastTo(new TypePattern(typeof(MethodInfo))); - - Expression ConvertProperty(InvocationExpression invocation) - { - if (invocation.Arguments.Count != 2) - return NotSupported(invocation); - - Match m = getMethodFromHandlePattern.Match(invocation.Arguments.ElementAt(1)); - if (!m.Success) - return NotSupported(invocation); - - MethodReference mr = m.Get("method").Single().Annotation(); - if (mr == null) - return null; - - Expression target = invocation.Arguments.ElementAt(0); - Expression convertedTarget; - if (target is NullReferenceExpression) { - if (m.Has("declaringType")) - convertedTarget = new TypeReferenceExpression(m.Get("declaringType").Single().Clone()); - else - convertedTarget = new TypeReferenceExpression(AstBuilder.ConvertType(mr.DeclaringType)); - } else { - convertedTarget = Convert(target); - if (convertedTarget == null) - return null; - } - - return convertedTarget.Member(GetPropertyName(mr)).WithAnnotation(mr); - } - - string GetPropertyName(MethodReference accessor) - { - string name = accessor.Name; - if (name.StartsWith("get_", StringComparison.Ordinal) || name.StartsWith("set_", StringComparison.Ordinal)) - name = name.Substring(4); - return name; - } - #endregion - - #region Convert Call - Expression ConvertCall(InvocationExpression invocation) - { - if (invocation.Arguments.Count < 2) - return NotSupported(invocation); - - Expression target; - int firstArgumentPosition; - - Match m = getMethodFromHandlePattern.Match(invocation.Arguments.ElementAt(0)); - if (m.Success) { - target = null; - firstArgumentPosition = 1; - } else { - m = getMethodFromHandlePattern.Match(invocation.Arguments.ElementAt(1)); - if (!m.Success) - return NotSupported(invocation); - target = invocation.Arguments.ElementAt(0); - firstArgumentPosition = 2; - } - - MethodReference mr = m.Get("method").Single().Annotation(); - if (mr == null) - return null; - - Expression convertedTarget; - if (target == null || target is NullReferenceExpression) { - // static method - if (m.Has("declaringType")) - convertedTarget = new TypeReferenceExpression(m.Get("declaringType").Single().Clone()); - else - convertedTarget = new TypeReferenceExpression(AstBuilder.ConvertType(mr.DeclaringType)); - } else { - convertedTarget = Convert(target); - if (convertedTarget == null) - return null; - } - - MemberReferenceExpression mre = convertedTarget.Member(mr.Name); - GenericInstanceMethod gim = mr as GenericInstanceMethod; - if (gim != null) { - foreach (TypeReference tr in gim.GenericArguments) { - mre.TypeArguments.Add(AstBuilder.ConvertType(tr)); - } - } - IList arguments = null; - if (invocation.Arguments.Count == firstArgumentPosition + 1) { - Expression argumentArray = invocation.Arguments.ElementAt(firstArgumentPosition); - arguments = ConvertExpressionsArray(argumentArray); - } - if (arguments == null) { - arguments = new List(); - foreach (Expression argument in invocation.Arguments.Skip(firstArgumentPosition)) { - Expression convertedArgument = Convert(argument); - if (convertedArgument == null) - return null; - arguments.Add(convertedArgument); - } - } - MethodDefinition methodDef = mr.Resolve(); - if (methodDef != null && methodDef.IsGetter) { - PropertyDefinition indexer = AstMethodBodyBuilder.GetIndexer(methodDef); - if (indexer != null) - return new IndexerExpression(mre.Target.Detach(), arguments).WithAnnotation(indexer); - } - return new InvocationExpression(mre, arguments).WithAnnotation(mr); - } - - Expression ConvertInvoke(InvocationExpression invocation) - { - if (invocation.Arguments.Count != 2) - return NotSupported(invocation); - - Expression convertedTarget = Convert(invocation.Arguments.ElementAt(0)); - IList convertedArguments = ConvertExpressionsArray(invocation.Arguments.ElementAt(1)); - if (convertedTarget != null && convertedArguments != null) - return new InvocationExpression(convertedTarget, convertedArguments); - else - return null; - } - #endregion - - #region Convert Binary Operator - static readonly Pattern trueOrFalse = new Choice { - new PrimitiveExpression(true), - new PrimitiveExpression(false) - }; - - Expression ConvertBinaryOperator(InvocationExpression invocation, BinaryOperatorType op, bool? isChecked = null) - { - if (invocation.Arguments.Count < 2) - return NotSupported(invocation); - - Expression left = Convert(invocation.Arguments.ElementAt(0)); - if (left == null) - return null; - Expression right = Convert(invocation.Arguments.ElementAt(1)); - if (right == null) - return null; - - BinaryOperatorExpression boe = new BinaryOperatorExpression(left, op, right); - if (isChecked != null) - boe.AddAnnotation(isChecked.Value ? AddCheckedBlocks.CheckedAnnotation : AddCheckedBlocks.UncheckedAnnotation); - - switch (invocation.Arguments.Count) { - case 2: - return boe; - case 3: - Match m = getMethodFromHandlePattern.Match(invocation.Arguments.ElementAt(2)); - if (m.Success) - return boe.WithAnnotation(m.Get("method").Single().Annotation()); - else - return null; - case 4: - if (!trueOrFalse.IsMatch(invocation.Arguments.ElementAt(2))) - return null; - m = getMethodFromHandlePattern.Match(invocation.Arguments.ElementAt(3)); - if (m.Success) - return boe.WithAnnotation(m.Get("method").Single().Annotation()); - else - return null; - default: - return NotSupported(invocation); - } - } - #endregion - - #region Convert Assignment Operator - Expression ConvertAssignmentOperator(InvocationExpression invocation, AssignmentOperatorType op, bool? isChecked = null) - { - return NotSupported(invocation); - } - #endregion - - #region Convert Unary Operator - Expression ConvertUnaryOperator(InvocationExpression invocation, UnaryOperatorType op, bool? isChecked = null) - { - if (invocation.Arguments.Count < 1) - return NotSupported(invocation); - - Expression expr = Convert(invocation.Arguments.ElementAt(0)); - if (expr == null) - return null; - - UnaryOperatorExpression uoe = new UnaryOperatorExpression(op, expr); - if (isChecked != null) - uoe.AddAnnotation(isChecked.Value ? AddCheckedBlocks.CheckedAnnotation : AddCheckedBlocks.UncheckedAnnotation); - - switch (invocation.Arguments.Count) { - case 1: - return uoe; - case 2: - Match m = getMethodFromHandlePattern.Match(invocation.Arguments.ElementAt(1)); - if (m.Success) - return uoe.WithAnnotation(m.Get("method").Single().Annotation()); - else - return null; - default: - return NotSupported(invocation); - } - } - #endregion - - #region Convert Condition Operator - Expression ConvertCondition(InvocationExpression invocation) - { - if (invocation.Arguments.Count != 3) - return NotSupported(invocation); - - Expression condition = Convert(invocation.Arguments.ElementAt(0)); - Expression trueExpr = Convert(invocation.Arguments.ElementAt(1)); - Expression falseExpr = Convert(invocation.Arguments.ElementAt(2)); - if (condition != null && trueExpr != null && falseExpr != null) - return new ConditionalExpression(condition, trueExpr, falseExpr); - else - return null; - } - #endregion - - #region Convert New Object - static readonly Expression newObjectCtorPattern = new TypePattern(typeof(MethodBase)).ToType().Invoke - ( - "GetMethodFromHandle", - new LdTokenPattern("ctor").ToExpression().Member("MethodHandle"), - new OptionalNode(new TypeOfExpression(new AnyNode("declaringType")).Member("TypeHandle")) - ).CastTo(new TypePattern(typeof(ConstructorInfo))); - - Expression ConvertNewObject(InvocationExpression invocation) - { - if (invocation.Arguments.Count < 1 || invocation.Arguments.Count > 3) - return NotSupported(invocation); - - Match m = newObjectCtorPattern.Match(invocation.Arguments.First()); - if (!m.Success) - return NotSupported(invocation); - - MethodReference ctor = m.Get("ctor").Single().Annotation(); - if (ctor == null) - return null; - - AstType declaringTypeNode; - TypeReference declaringType; - if (m.Has("declaringType")) { - declaringTypeNode = m.Get("declaringType").Single().Clone(); - declaringType = declaringTypeNode.Annotation(); - } else { - declaringTypeNode = AstBuilder.ConvertType(ctor.DeclaringType); - declaringType = ctor.DeclaringType; - } - if (declaringTypeNode == null) - return null; - - ObjectCreateExpression oce = new ObjectCreateExpression(declaringTypeNode); - if (invocation.Arguments.Count >= 2) { - IList arguments = ConvertExpressionsArray(invocation.Arguments.ElementAtOrDefault(1)); - if (arguments == null) - return null; - oce.Arguments.AddRange(arguments); - } - if (invocation.Arguments.Count >= 3 && declaringType.IsAnonymousType()) { - MethodDefinition resolvedCtor = ctor.Resolve(); - if (resolvedCtor == null || resolvedCtor.Parameters.Count != oce.Arguments.Count) - return null; - AnonymousTypeCreateExpression atce = new AnonymousTypeCreateExpression(); - var arguments = oce.Arguments.ToArray(); - if (AstMethodBodyBuilder.CanInferAnonymousTypePropertyNamesFromArguments(arguments, resolvedCtor.Parameters)) { - oce.Arguments.MoveTo(atce.Initializers); - } else { - for (int i = 0; i < resolvedCtor.Parameters.Count; i++) { - atce.Initializers.Add( - new NamedExpression { - Name = resolvedCtor.Parameters[i].Name, - Expression = arguments[i].Detach() - }); - } - } - return atce; - } - - return oce; - } - #endregion - - #region Convert ListInit - static readonly Pattern elementInitArrayPattern = ArrayInitializationPattern( - typeof(System.Linq.Expressions.ElementInit), - new TypePattern(typeof(System.Linq.Expressions.Expression)).ToType().Invoke("ElementInit", new AnyNode("methodInfos"), new AnyNode("addArgumentsArrays")) - ); - - Expression ConvertListInit(InvocationExpression invocation) - { - if (invocation.Arguments.Count != 2) - return NotSupported(invocation); - ObjectCreateExpression oce = Convert(invocation.Arguments.ElementAt(0)) as ObjectCreateExpression; - if (oce == null) - return null; - Expression elementsArray = invocation.Arguments.ElementAt(1); - ArrayInitializerExpression initializer = ConvertElementInit(elementsArray); - if (initializer != null) { - oce.Initializer = initializer; - return oce; - } else { - return null; - } - } - - ArrayInitializerExpression ConvertElementInit(Expression elementsArray) - { - IList elements = ConvertExpressionsArray(elementsArray); - if (elements != null) { - return new ArrayInitializerExpression(elements); - } - Match m = elementInitArrayPattern.Match(elementsArray); - if (!m.Success) - return null; - ArrayInitializerExpression result = new ArrayInitializerExpression(); - foreach (var elementInit in m.Get("addArgumentsArrays")) { - IList arguments = ConvertExpressionsArray(elementInit); - if (arguments == null) - return null; - result.Elements.Add(new ArrayInitializerExpression(arguments)); - } - return result; - } - #endregion - - #region Convert MemberInit - Expression ConvertMemberInit(InvocationExpression invocation) - { - if (invocation.Arguments.Count != 2) - return NotSupported(invocation); - ObjectCreateExpression oce = Convert(invocation.Arguments.ElementAt(0)) as ObjectCreateExpression; - if (oce == null) - return null; - Expression elementsArray = invocation.Arguments.ElementAt(1); - ArrayInitializerExpression bindings = ConvertMemberBindings(elementsArray); - if (bindings == null) - return null; - oce.Initializer = bindings; - return oce; - } - - static readonly Pattern memberBindingArrayPattern = ArrayInitializationPattern(typeof(System.Linq.Expressions.MemberBinding), new AnyNode("binding")); - static readonly INode expressionTypeReference = new TypeReferenceExpression(new TypePattern(typeof(System.Linq.Expressions.Expression))); - - ArrayInitializerExpression ConvertMemberBindings(Expression elementsArray) - { - Match m = memberBindingArrayPattern.Match(elementsArray); - if (!m.Success) - return null; - ArrayInitializerExpression result = new ArrayInitializerExpression(); - foreach (var binding in m.Get("binding")) { - InvocationExpression bindingInvocation = binding as InvocationExpression; - if (bindingInvocation == null || bindingInvocation.Arguments.Count != 2) - return null; - MemberReferenceExpression bindingMRE = bindingInvocation.Target as MemberReferenceExpression; - if (bindingMRE == null || !expressionTypeReference.IsMatch(bindingMRE.Target)) - return null; - - Expression bindingTarget = bindingInvocation.Arguments.ElementAt(0); - Expression bindingValue = bindingInvocation.Arguments.ElementAt(1); - - string memberName; - Match m2 = getMethodFromHandlePattern.Match(bindingTarget); - if (m2.Success) { - MethodReference setter = m2.Get("method").Single().Annotation(); - if (setter == null) - return null; - memberName = GetPropertyName(setter); - } else { - return null; - } - - Expression convertedValue; - switch (bindingMRE.MemberName) { - case "Bind": - convertedValue = Convert(bindingValue); - break; - case "MemberBind": - convertedValue = ConvertMemberBindings(bindingValue); - break; - case "ListBind": - convertedValue = ConvertElementInit(bindingValue); - break; - default: - return null; - } - if (convertedValue == null) - return null; - result.Elements.Add(new NamedExpression(memberName, convertedValue)); - } - return result; - } - #endregion - - #region Convert Cast - Expression ConvertCast(InvocationExpression invocation, bool isChecked) - { - if (invocation.Arguments.Count < 2) - return null; - Expression converted = Convert(invocation.Arguments.ElementAt(0)); - AstType type = ConvertTypeReference(invocation.Arguments.ElementAt(1)); - if (converted != null && type != null) { - CastExpression cast = converted.CastTo(type); - cast.AddAnnotation(isChecked ? AddCheckedBlocks.CheckedAnnotation : AddCheckedBlocks.UncheckedAnnotation); - switch (invocation.Arguments.Count) { - case 2: - return cast; - case 3: - Match m = getMethodFromHandlePattern.Match(invocation.Arguments.ElementAt(2)); - if (m.Success) - return cast.WithAnnotation(m.Get("method").Single().Annotation()); - else - return null; - } - } - return null; - } - #endregion - - #region ConvertExpressionsArray - static Pattern ArrayInitializationPattern(Type arrayElementType, INode elementPattern) - { - return new Choice { - new ArrayCreateExpression { - Type = new TypePattern(arrayElementType), - Arguments = { new PrimitiveExpression(0) } - }, - new ArrayCreateExpression { - Type = new TypePattern(arrayElementType), - AdditionalArraySpecifiers = { new ArraySpecifier() }, - Initializer = new ArrayInitializerExpression { - Elements = { new Repeat(elementPattern) } - } - } - }; - } - - static readonly Pattern expressionArrayPattern = ArrayInitializationPattern(typeof(System.Linq.Expressions.Expression), new AnyNode("elements")); - - IList ConvertExpressionsArray(Expression arrayExpression) - { - Match m = expressionArrayPattern.Match(arrayExpression); - if (m.Success) { - List result = new List(); - foreach (Expression expr in m.Get("elements")) { - Expression converted = Convert(expr); - if (converted == null) - return null; - result.Add(converted); - } - return result; - } - return null; - } - #endregion - - #region Convert TypeAs/TypeIs - static readonly TypeOfPattern typeOfPattern = new TypeOfPattern("type"); - - AstType ConvertTypeReference(Expression typeOfExpression) - { - Match m = typeOfPattern.Match(typeOfExpression); - if (m.Success) - return m.Get("type").Single().Clone(); - else - return null; - } - - Expression ConvertTypeAs(InvocationExpression invocation) - { - if (invocation.Arguments.Count != 2) - return null; - Expression converted = Convert(invocation.Arguments.ElementAt(0)); - AstType type = ConvertTypeReference(invocation.Arguments.ElementAt(1)); - if (converted != null && type != null) - return new AsExpression(converted, type); - return null; - } - - Expression ConvertTypeIs(InvocationExpression invocation) - { - if (invocation.Arguments.Count != 2) - return null; - Expression converted = Convert(invocation.Arguments.ElementAt(0)); - AstType type = ConvertTypeReference(invocation.Arguments.ElementAt(1)); - if (converted != null && type != null) - return new IsExpression { Expression = converted, Type = type }; - return null; - } - #endregion - - #region Convert Array - Expression ConvertArrayIndex(InvocationExpression invocation) - { - if (invocation.Arguments.Count != 2) - return NotSupported(invocation); - - Expression targetConverted = Convert(invocation.Arguments.First()); - if (targetConverted == null) - return null; - - Expression index = invocation.Arguments.ElementAt(1); - Expression indexConverted = Convert(index); - if (indexConverted != null) { - return new IndexerExpression(targetConverted, indexConverted); - } - IList indexesConverted = ConvertExpressionsArray(index); - if (indexesConverted != null) { - return new IndexerExpression(targetConverted, indexesConverted); - } - return null; - } - - Expression ConvertArrayLength(InvocationExpression invocation) - { - if (invocation.Arguments.Count != 1) - return NotSupported(invocation); - - Expression targetConverted = Convert(invocation.Arguments.Single()); - if (targetConverted != null) - return targetConverted.Member("Length"); - else - return null; - } - - Expression ConvertNewArrayInit(InvocationExpression invocation) - { - if (invocation.Arguments.Count != 2) - return NotSupported(invocation); - - AstType elementType = ConvertTypeReference(invocation.Arguments.ElementAt(0)); - IList elements = ConvertExpressionsArray(invocation.Arguments.ElementAt(1)); - if (elementType != null && elements != null) { - if (ContainsAnonymousType(elementType)) { - elementType = null; - } - return new ArrayCreateExpression { - Type = elementType, - AdditionalArraySpecifiers = { new ArraySpecifier() }, - Initializer = new ArrayInitializerExpression(elements) - }; - } - return null; - } - - Expression ConvertNewArrayBounds(InvocationExpression invocation) - { - if (invocation.Arguments.Count != 2) - return NotSupported(invocation); - - AstType elementType = ConvertTypeReference(invocation.Arguments.ElementAt(0)); - IList arguments = ConvertExpressionsArray(invocation.Arguments.ElementAt(1)); - if (elementType != null && arguments != null) { - if (ContainsAnonymousType(elementType)) { - elementType = null; - } - ArrayCreateExpression ace = new ArrayCreateExpression(); - ace.Type = elementType; - ace.Arguments.AddRange(arguments); - return ace; - } - return null; - } - - bool ContainsAnonymousType(AstType type) - { - foreach (AstType t in type.DescendantsAndSelf.OfType()) { - TypeReference tr = t.Annotation(); - if (tr != null && tr.IsAnonymousType()) - return true; - } - return false; - } - #endregion - } -} diff --git a/ICSharpCode.Decompiler/Ast/Transforms/FlattenSwitchBlocks.cs b/ICSharpCode.Decompiler/Ast/Transforms/FlattenSwitchBlocks.cs deleted file mode 100644 index 9595e81b..00000000 --- a/ICSharpCode.Decompiler/Ast/Transforms/FlattenSwitchBlocks.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using ICSharpCode.NRefactory.CSharp; - -namespace ICSharpCode.Decompiler.Ast.Transforms -{ - internal class FlattenSwitchBlocks : IAstTransform - { - public void Run(AstNode compilationUnit) - { - foreach (var switchSection in compilationUnit.Descendants.OfType()) - { - if (switchSection.Statements.Count != 1) - continue; - - var blockStatement = switchSection.Statements.First() as BlockStatement; - if (blockStatement == null || blockStatement.Statements.Any(st => st is VariableDeclarationStatement)) - continue; - - blockStatement.Remove(); - blockStatement.Statements.MoveTo(switchSection.Statements); - } - } - } -} diff --git a/ICSharpCode.Decompiler/Ast/Transforms/IntroduceExtensionMethods.cs b/ICSharpCode.Decompiler/Ast/Transforms/IntroduceExtensionMethods.cs deleted file mode 100644 index 9f05285e..00000000 --- a/ICSharpCode.Decompiler/Ast/Transforms/IntroduceExtensionMethods.cs +++ /dev/null @@ -1,66 +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.Linq; -using ICSharpCode.NRefactory.CSharp; -using Mono.Cecil; - -namespace ICSharpCode.Decompiler.Ast.Transforms -{ - /// - /// Converts extension method calls into infix syntax. - /// - public class IntroduceExtensionMethods : IAstTransform - { - readonly DecompilerContext context; - - public IntroduceExtensionMethods(DecompilerContext context) - { - this.context = context; - } - - public void Run(AstNode compilationUnit) - { - foreach (InvocationExpression invocation in compilationUnit.Descendants.OfType()) { - MemberReferenceExpression mre = invocation.Target as MemberReferenceExpression; - MethodReference methodReference = invocation.Annotation(); - if (mre != null && mre.Target is TypeReferenceExpression && methodReference != null && invocation.Arguments.Any()) { - MethodDefinition d = methodReference.Resolve(); - if (d != null) { - foreach (var ca in d.CustomAttributes) { - if (ca.AttributeType.Name == "ExtensionAttribute" && ca.AttributeType.Namespace == "System.Runtime.CompilerServices") { - var firstArgument = invocation.Arguments.First(); - if (firstArgument is NullReferenceExpression) - firstArgument = firstArgument.ReplaceWith(expr => expr.CastTo(AstBuilder.ConvertType(d.Parameters.First().ParameterType))); - else - mre.Target = firstArgument.Detach(); - if (invocation.Arguments.Any()) { - // HACK: removing type arguments should be done indepently from whether a method is an extension method, - // just by testing whether the arguments can be inferred - mre.TypeArguments.Clear(); - } - break; - } - } - } - } - } - } - } -} diff --git a/ICSharpCode.Decompiler/Ast/Transforms/IntroduceQueryExpressions.cs b/ICSharpCode.Decompiler/Ast/Transforms/IntroduceQueryExpressions.cs deleted file mode 100644 index 0da56fe9..00000000 --- a/ICSharpCode.Decompiler/Ast/Transforms/IntroduceQueryExpressions.cs +++ /dev/null @@ -1,295 +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.Diagnostics; -using System.Linq; -using ICSharpCode.NRefactory.CSharp; - -namespace ICSharpCode.Decompiler.Ast.Transforms -{ - /// - /// Decompiles query expressions. - /// Based on C# 4.0 spec, §7.16.2 Query expression translation - /// - public class IntroduceQueryExpressions : IAstTransform - { - readonly DecompilerContext context; - - public IntroduceQueryExpressions(DecompilerContext context) - { - this.context = context; - } - - public void Run(AstNode compilationUnit) - { - if (!context.Settings.QueryExpressions) - return; - DecompileQueries(compilationUnit); - // After all queries were decompiled, detect degenerate queries (queries not property terminated with 'select' or 'group') - // and fix them, either by adding a degenerate select, or by combining them with another query. - foreach (QueryExpression query in compilationUnit.Descendants.OfType()) { - QueryFromClause fromClause = (QueryFromClause)query.Clauses.First(); - if (IsDegenerateQuery(query)) { - // introduce select for degenerate query - query.Clauses.Add(new QuerySelectClause { Expression = new IdentifierExpression(fromClause.Identifier) }); - } - // See if the data source of this query is a degenerate query, - // and combine the queries if possible. - QueryExpression innerQuery = fromClause.Expression as QueryExpression; - while (IsDegenerateQuery(innerQuery)) { - QueryFromClause innerFromClause = (QueryFromClause)innerQuery.Clauses.First(); - if (fromClause.Identifier != innerFromClause.Identifier) - break; - // Replace the fromClause with all clauses from the inner query - fromClause.Remove(); - QueryClause insertionPos = null; - foreach (var clause in innerQuery.Clauses) { - query.Clauses.InsertAfter(insertionPos, insertionPos = clause.Detach()); - } - fromClause = innerFromClause; - innerQuery = fromClause.Expression as QueryExpression; - } - } - } - - bool IsDegenerateQuery(QueryExpression query) - { - if (query == null) - return false; - var lastClause = query.Clauses.LastOrDefault(); - return !(lastClause is QuerySelectClause || lastClause is QueryGroupClause); - } - - void DecompileQueries(AstNode node) - { - QueryExpression query = DecompileQuery(node as InvocationExpression); - if (query != null) - node.ReplaceWith(query); - for (AstNode child = (query ?? node).FirstChild; child != null; child = child.NextSibling) { - DecompileQueries(child); - } - } - - QueryExpression DecompileQuery(InvocationExpression invocation) - { - if (invocation == null) - return null; - MemberReferenceExpression mre = invocation.Target as MemberReferenceExpression; - if (mre == null) - return null; - switch (mre.MemberName) { - case "Select": - { - if (invocation.Arguments.Count != 1) - return null; - string parameterName; - Expression body; - if (MatchSimpleLambda(invocation.Arguments.Single(), out parameterName, out body)) { - QueryExpression query = new QueryExpression(); - query.Clauses.Add(new QueryFromClause { Identifier = parameterName, Expression = mre.Target.Detach() }); - query.Clauses.Add(new QuerySelectClause { Expression = body.Detach() }); - return query; - } - return null; - } - case "GroupBy": - { - if (invocation.Arguments.Count == 2) { - string parameterName1, parameterName2; - Expression keySelector, elementSelector; - if (MatchSimpleLambda(invocation.Arguments.ElementAt(0), out parameterName1, out keySelector) - && MatchSimpleLambda(invocation.Arguments.ElementAt(1), out parameterName2, out elementSelector) - && parameterName1 == parameterName2) - { - QueryExpression query = new QueryExpression(); - query.Clauses.Add(new QueryFromClause { Identifier = parameterName1, Expression = mre.Target.Detach() }); - query.Clauses.Add(new QueryGroupClause { Projection = elementSelector.Detach(), Key = keySelector.Detach() }); - return query; - } - } else if (invocation.Arguments.Count == 1) { - string parameterName; - Expression keySelector; - if (MatchSimpleLambda(invocation.Arguments.Single(), out parameterName, out keySelector)) { - QueryExpression query = new QueryExpression(); - query.Clauses.Add(new QueryFromClause { Identifier = parameterName, Expression = mre.Target.Detach() }); - query.Clauses.Add(new QueryGroupClause { Projection = new IdentifierExpression(parameterName), Key = keySelector.Detach() }); - return query; - } - } - return null; - } - case "SelectMany": - { - if (invocation.Arguments.Count != 2) - return null; - string parameterName; - Expression collectionSelector; - if (!MatchSimpleLambda(invocation.Arguments.ElementAt(0), out parameterName, out collectionSelector)) - return null; - LambdaExpression lambda = invocation.Arguments.ElementAt(1) as LambdaExpression; - if (lambda != null && lambda.Parameters.Count == 2 && lambda.Body is Expression) { - ParameterDeclaration p1 = lambda.Parameters.ElementAt(0); - ParameterDeclaration p2 = lambda.Parameters.ElementAt(1); - if (p1.Name == parameterName) { - QueryExpression query = new QueryExpression(); - query.Clauses.Add(new QueryFromClause { Identifier = p1.Name, Expression = mre.Target.Detach() }); - query.Clauses.Add(new QueryFromClause { Identifier = p2.Name, Expression = collectionSelector.Detach() }); - query.Clauses.Add(new QuerySelectClause { Expression = ((Expression)lambda.Body).Detach() }); - return query; - } - } - return null; - } - case "Where": - { - if (invocation.Arguments.Count != 1) - return null; - string parameterName; - Expression body; - if (MatchSimpleLambda(invocation.Arguments.Single(), out parameterName, out body)) { - QueryExpression query = new QueryExpression(); - query.Clauses.Add(new QueryFromClause { Identifier = parameterName, Expression = mre.Target.Detach() }); - query.Clauses.Add(new QueryWhereClause { Condition = body.Detach() }); - return query; - } - return null; - } - case "OrderBy": - case "OrderByDescending": - case "ThenBy": - case "ThenByDescending": - { - if (invocation.Arguments.Count != 1) - return null; - string parameterName; - Expression orderExpression; - if (MatchSimpleLambda(invocation.Arguments.Single(), out parameterName, out orderExpression)) { - if (ValidateThenByChain(invocation, parameterName)) { - QueryOrderClause orderClause = new QueryOrderClause(); - InvocationExpression tmp = invocation; - while (mre.MemberName == "ThenBy" || mre.MemberName == "ThenByDescending") { - // insert new ordering at beginning - orderClause.Orderings.InsertAfter( - null, new QueryOrdering { - Expression = orderExpression.Detach(), - Direction = (mre.MemberName == "ThenBy" ? QueryOrderingDirection.None : QueryOrderingDirection.Descending) - }); - - tmp = (InvocationExpression)mre.Target; - mre = (MemberReferenceExpression)tmp.Target; - MatchSimpleLambda(tmp.Arguments.Single(), out parameterName, out orderExpression); - } - // insert new ordering at beginning - orderClause.Orderings.InsertAfter( - null, new QueryOrdering { - Expression = orderExpression.Detach(), - Direction = (mre.MemberName == "OrderBy" ? QueryOrderingDirection.None : QueryOrderingDirection.Descending) - }); - - QueryExpression query = new QueryExpression(); - query.Clauses.Add(new QueryFromClause { Identifier = parameterName, Expression = mre.Target.Detach() }); - query.Clauses.Add(orderClause); - return query; - } - } - return null; - } - case "Join": - case "GroupJoin": - { - if (invocation.Arguments.Count != 4) - return null; - Expression source1 = mre.Target; - Expression source2 = invocation.Arguments.ElementAt(0); - string elementName1, elementName2; - Expression key1, key2; - if (!MatchSimpleLambda(invocation.Arguments.ElementAt(1), out elementName1, out key1)) - return null; - if (!MatchSimpleLambda(invocation.Arguments.ElementAt(2), out elementName2, out key2)) - return null; - LambdaExpression lambda = invocation.Arguments.ElementAt(3) as LambdaExpression; - if (lambda != null && lambda.Parameters.Count == 2 && lambda.Body is Expression) { - ParameterDeclaration p1 = lambda.Parameters.ElementAt(0); - ParameterDeclaration p2 = lambda.Parameters.ElementAt(1); - if (p1.Name == elementName1 && (p2.Name == elementName2 || mre.MemberName == "GroupJoin")) { - QueryExpression query = new QueryExpression(); - query.Clauses.Add(new QueryFromClause { Identifier = elementName1, Expression = source1.Detach() }); - QueryJoinClause joinClause = new QueryJoinClause(); - joinClause.JoinIdentifier = elementName2; // join elementName2 - joinClause.InExpression = source2.Detach(); // in source2 - joinClause.OnExpression = key1.Detach(); // on key1 - joinClause.EqualsExpression = key2.Detach(); // equals key2 - if (mre.MemberName == "GroupJoin") { - joinClause.IntoIdentifier = p2.Name; // into p2.Name - } - query.Clauses.Add(joinClause); - query.Clauses.Add(new QuerySelectClause { Expression = ((Expression)lambda.Body).Detach() }); - return query; - } - } - return null; - } - default: - return null; - } - } - - /// - /// Ensure that all ThenBy's are correct, and that the list of ThenBy's is terminated by an 'OrderBy' invocation. - /// - bool ValidateThenByChain(InvocationExpression invocation, string expectedParameterName) - { - if (invocation == null || invocation.Arguments.Count != 1) - return false; - MemberReferenceExpression mre = invocation.Target as MemberReferenceExpression; - if (mre == null) - return false; - string parameterName; - Expression body; - if (!MatchSimpleLambda(invocation.Arguments.Single(), out parameterName, out body)) - return false; - if (parameterName != expectedParameterName) - return false; - - if (mre.MemberName == "OrderBy" || mre.MemberName == "OrderByDescending") - return true; - else if (mre.MemberName == "ThenBy" || mre.MemberName == "ThenByDescending") - return ValidateThenByChain(mre.Target as InvocationExpression, expectedParameterName); - else - return false; - } - - /// Matches simple lambdas of the form "a => b" - bool MatchSimpleLambda(Expression expr, out string parameterName, out Expression body) - { - LambdaExpression lambda = expr as LambdaExpression; - if (lambda != null && lambda.Parameters.Count == 1 && lambda.Body is Expression) { - ParameterDeclaration p = lambda.Parameters.Single(); - if (p.ParameterModifier == ParameterModifier.None) { - parameterName = p.Name; - body = (Expression)lambda.Body; - return true; - } - } - parameterName = null; - body = null; - return false; - } - } -} diff --git a/ICSharpCode.Decompiler/Ast/Transforms/IntroduceUnsafeModifier.cs b/ICSharpCode.Decompiler/Ast/Transforms/IntroduceUnsafeModifier.cs deleted file mode 100644 index 43548e38..00000000 --- a/ICSharpCode.Decompiler/Ast/Transforms/IntroduceUnsafeModifier.cs +++ /dev/null @@ -1,106 +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 ICSharpCode.NRefactory.CSharp; - -namespace ICSharpCode.Decompiler.Ast.Transforms -{ - public class IntroduceUnsafeModifier : DepthFirstAstVisitor, IAstTransform - { - public static readonly object PointerArithmeticAnnotation = new PointerArithmetic(); - - sealed class PointerArithmetic {} - - public void Run(AstNode compilationUnit) - { - compilationUnit.AcceptVisitor(this, null); - } - - protected override bool VisitChildren(AstNode node, object data) - { - bool result = false; - for (AstNode child = node.FirstChild; child != null; child = child.NextSibling) { - result |= child.AcceptVisitor(this, data); - } - if (result && node is EntityDeclaration && !(node is Accessor)) { - ((EntityDeclaration)node).Modifiers |= Modifiers.Unsafe; - return false; - } - return result; - } - - public override bool VisitPointerReferenceExpression(PointerReferenceExpression pointerReferenceExpression, object data) - { - base.VisitPointerReferenceExpression(pointerReferenceExpression, data); - return true; - } - - public override bool VisitComposedType(ComposedType composedType, object data) - { - if (composedType.PointerRank > 0) - return true; - else - return base.VisitComposedType(composedType, data); - } - - public override bool VisitUnaryOperatorExpression(UnaryOperatorExpression unaryOperatorExpression, object data) - { - bool result = base.VisitUnaryOperatorExpression(unaryOperatorExpression, data); - if (unaryOperatorExpression.Operator == UnaryOperatorType.Dereference) { - BinaryOperatorExpression bop = unaryOperatorExpression.Expression as BinaryOperatorExpression; - if (bop != null && bop.Operator == BinaryOperatorType.Add && bop.Annotation() != null) { - // transform "*(ptr + int)" to "ptr[int]" - IndexerExpression indexer = new IndexerExpression(); - indexer.Target = bop.Left.Detach(); - indexer.Arguments.Add(bop.Right.Detach()); - indexer.CopyAnnotationsFrom(unaryOperatorExpression); - indexer.CopyAnnotationsFrom(bop); - unaryOperatorExpression.ReplaceWith(indexer); - } - return true; - } else if (unaryOperatorExpression.Operator == UnaryOperatorType.AddressOf) { - return true; - } else { - return result; - } - } - - public override bool VisitMemberReferenceExpression(MemberReferenceExpression memberReferenceExpression, object data) - { - bool result = base.VisitMemberReferenceExpression(memberReferenceExpression, data); - UnaryOperatorExpression uoe = memberReferenceExpression.Target as UnaryOperatorExpression; - if (uoe != null && uoe.Operator == UnaryOperatorType.Dereference) { - PointerReferenceExpression pre = new PointerReferenceExpression(); - pre.Target = uoe.Expression.Detach(); - pre.MemberName = memberReferenceExpression.MemberName; - memberReferenceExpression.TypeArguments.MoveTo(pre.TypeArguments); - pre.CopyAnnotationsFrom(uoe); - pre.CopyAnnotationsFrom(memberReferenceExpression); - memberReferenceExpression.ReplaceWith(pre); - } - return result; - } - - public override bool VisitStackAllocExpression(StackAllocExpression stackAllocExpression, object data) - { - base.VisitStackAllocExpression(stackAllocExpression, data); - return true; - } - } -} diff --git a/ICSharpCode.Decompiler/Ast/Transforms/IntroduceUsingDeclarations.cs b/ICSharpCode.Decompiler/Ast/Transforms/IntroduceUsingDeclarations.cs deleted file mode 100644 index 6e9cc4f5..00000000 --- a/ICSharpCode.Decompiler/Ast/Transforms/IntroduceUsingDeclarations.cs +++ /dev/null @@ -1,359 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Linq; -using ICSharpCode.NRefactory.CSharp; -using Mono.Cecil; - -namespace ICSharpCode.Decompiler.Ast.Transforms -{ - /// - /// Introduces using declarations. - /// - public class IntroduceUsingDeclarations : IAstTransform - { - DecompilerContext context; - - public IntroduceUsingDeclarations(DecompilerContext context) - { - this.context = context; - } - - public void Run(AstNode compilationUnit) - { - // First determine all the namespaces that need to be imported: - compilationUnit.AcceptVisitor(new FindRequiredImports(this), null); - - importedNamespaces.Add("System"); // always import System, even when not necessary - - if (context.Settings.UsingDeclarations) { - // Now add using declarations for those namespaces: - foreach (string ns in importedNamespaces.OrderByDescending(n => n)) { - // we go backwards (OrderByDescending) through the list of namespaces because we insert them backwards - // (always inserting at the start of the list) - string[] parts = ns.Split('.'); - AstType nsType = new SimpleType(parts[0]); - for (int i = 1; i < parts.Length; i++) { - nsType = new MemberType { Target = nsType, MemberName = parts[i] }; - } - compilationUnit.InsertChildAfter(null, new UsingDeclaration { Import = nsType }, SyntaxTree.MemberRole); - } - } - - if (!context.Settings.FullyQualifyAmbiguousTypeNames) - return; - - FindAmbiguousTypeNames(context.CurrentModule, internalsVisible: true); - foreach (AssemblyNameReference r in context.CurrentModule.AssemblyReferences) { - AssemblyDefinition d = context.CurrentModule.AssemblyResolver.Resolve(r); - if (d != null) - FindAmbiguousTypeNames(d.MainModule, internalsVisible: false); - } - - // verify that the SimpleTypes refer to the correct type (no ambiguities) - compilationUnit.AcceptVisitor(new FullyQualifyAmbiguousTypeNamesVisitor(this), null); - } - - readonly HashSet declaredNamespaces = new HashSet() { string.Empty }; - readonly HashSet importedNamespaces = new HashSet(); - - // Note that we store type names with `n suffix, so we automatically disambiguate based on number of type parameters. - readonly HashSet availableTypeNames = new HashSet(); - readonly HashSet ambiguousTypeNames = new HashSet(); - - sealed class FindRequiredImports : DepthFirstAstVisitor - { - readonly IntroduceUsingDeclarations transform; - string currentNamespace; - - public FindRequiredImports(IntroduceUsingDeclarations transform) - { - this.transform = transform; - currentNamespace = transform.context.CurrentType != null ? transform.context.CurrentType.Namespace : string.Empty; - } - - bool IsParentOfCurrentNamespace(string ns) - { - if (ns.Length == 0) - return true; - if (currentNamespace.StartsWith(ns, StringComparison.Ordinal)) { - if (currentNamespace.Length == ns.Length) - return true; - if (currentNamespace[ns.Length] == '.') - return true; - } - return false; - } - - public override object VisitSimpleType(SimpleType simpleType, object data) - { - TypeReference tr = simpleType.Annotation(); - if (tr != null && !IsParentOfCurrentNamespace(tr.Namespace)) { - transform.importedNamespaces.Add(tr.Namespace); - } - return base.VisitSimpleType(simpleType, data); // also visit type arguments - } - - public override object VisitNamespaceDeclaration(NamespaceDeclaration namespaceDeclaration, object data) - { - string oldNamespace = currentNamespace; - foreach (string ident in namespaceDeclaration.Identifiers) { - currentNamespace = NamespaceDeclaration.BuildQualifiedName(currentNamespace, ident); - transform.declaredNamespaces.Add(currentNamespace); - } - base.VisitNamespaceDeclaration(namespaceDeclaration, data); - currentNamespace = oldNamespace; - return null; - } - } - - void FindAmbiguousTypeNames(ModuleDefinition module, bool internalsVisible) - { - foreach (TypeDefinition type in module.Types) { - if (internalsVisible || type.IsPublic) { - if (importedNamespaces.Contains(type.Namespace) || declaredNamespaces.Contains(type.Namespace)) { - if (!availableTypeNames.Add(type.Name)) - ambiguousTypeNames.Add(type.Name); - } - } - } - } - - sealed class FullyQualifyAmbiguousTypeNamesVisitor : DepthFirstAstVisitor - { - readonly IntroduceUsingDeclarations transform; - string currentNamespace; - HashSet currentMemberTypes; - Dictionary currentMembers; - bool isWithinTypeReferenceExpression; - - public FullyQualifyAmbiguousTypeNamesVisitor(IntroduceUsingDeclarations transform) - { - this.transform = transform; - currentNamespace = transform.context.CurrentType != null ? transform.context.CurrentType.Namespace : string.Empty; - } - - public override object VisitNamespaceDeclaration(NamespaceDeclaration namespaceDeclaration, object data) - { - string oldNamespace = currentNamespace; - foreach (string ident in namespaceDeclaration.Identifiers) { - currentNamespace = NamespaceDeclaration.BuildQualifiedName(currentNamespace, ident); - } - base.VisitNamespaceDeclaration(namespaceDeclaration, data); - currentNamespace = oldNamespace; - return null; - } - - public override object VisitTypeDeclaration(TypeDeclaration typeDeclaration, object data) - { - HashSet oldMemberTypes = currentMemberTypes; - currentMemberTypes = currentMemberTypes != null ? new HashSet(currentMemberTypes) : new HashSet(); - - Dictionary oldMembers = currentMembers; - currentMembers = new Dictionary(); - - TypeDefinition typeDef = typeDeclaration.Annotation(); - bool privateMembersVisible = true; - ModuleDefinition internalMembersVisibleInModule = typeDef.Module; - while (typeDef != null) { - foreach (GenericParameter gp in typeDef.GenericParameters) { - currentMemberTypes.Add(gp.Name); - } - foreach (TypeDefinition t in typeDef.NestedTypes) { - if (privateMembersVisible || IsVisible(t, internalMembersVisibleInModule)) - currentMemberTypes.Add(t.Name.Substring(t.Name.LastIndexOf('+') + 1)); - } - - foreach (MethodDefinition method in typeDef.Methods) { - if (privateMembersVisible || IsVisible(method, internalMembersVisibleInModule)) - AddCurrentMember(method); - } - foreach (PropertyDefinition property in typeDef.Properties) { - if (privateMembersVisible || IsVisible(property.GetMethod, internalMembersVisibleInModule) || IsVisible(property.SetMethod, internalMembersVisibleInModule)) - AddCurrentMember(property); - } - foreach (EventDefinition ev in typeDef.Events) { - if (privateMembersVisible || IsVisible(ev.AddMethod, internalMembersVisibleInModule) || IsVisible(ev.RemoveMethod, internalMembersVisibleInModule)) - AddCurrentMember(ev); - } - foreach (FieldDefinition f in typeDef.Fields) { - if (privateMembersVisible || IsVisible(f, internalMembersVisibleInModule)) - AddCurrentMember(f); - } - // repeat with base class: - if (typeDef.BaseType != null) - typeDef = typeDef.BaseType.Resolve(); - else - typeDef = null; - privateMembersVisible = false; - } - - // Now add current members from outer classes: - if (oldMembers != null) { - foreach (var pair in oldMembers) { - // add members from outer classes only if the inner class doesn't define the member - if (!currentMembers.ContainsKey(pair.Key)) - currentMembers.Add(pair.Key, pair.Value); - } - } - - base.VisitTypeDeclaration(typeDeclaration, data); - currentMembers = oldMembers; - return null; - } - - void AddCurrentMember(MemberReference m) - { - MemberReference existingMember; - if (currentMembers.TryGetValue(m.Name, out existingMember)) { - // We keep the existing member assignment if it was from another class (=from a derived class), - // because members in derived classes have precedence over members in base classes. - if (existingMember != null && existingMember.DeclaringType == m.DeclaringType) { - // Use null as value to signalize multiple members with the same name - currentMembers[m.Name] = null; - } - } else { - currentMembers.Add(m.Name, m); - } - } - - bool IsVisible(MethodDefinition m, ModuleDefinition internalMembersVisibleInModule) - { - if (m == null) - return false; - switch (m.Attributes & MethodAttributes.MemberAccessMask) { - case MethodAttributes.FamANDAssem: - case MethodAttributes.Assembly: - return m.Module == internalMembersVisibleInModule; - case MethodAttributes.Family: - case MethodAttributes.FamORAssem: - case MethodAttributes.Public: - return true; - default: - return false; - } - } - - bool IsVisible(FieldDefinition f, ModuleDefinition internalMembersVisibleInModule) - { - if (f == null) - return false; - switch (f.Attributes & FieldAttributes.FieldAccessMask) { - case FieldAttributes.FamANDAssem: - case FieldAttributes.Assembly: - return f.Module == internalMembersVisibleInModule; - case FieldAttributes.Family: - case FieldAttributes.FamORAssem: - case FieldAttributes.Public: - return true; - default: - return false; - } - } - - bool IsVisible(TypeDefinition t, ModuleDefinition internalMembersVisibleInModule) - { - if (t == null) - return false; - switch (t.Attributes & TypeAttributes.VisibilityMask) { - case TypeAttributes.NotPublic: - case TypeAttributes.NestedAssembly: - case TypeAttributes.NestedFamANDAssem: - return t.Module == internalMembersVisibleInModule; - case TypeAttributes.NestedFamily: - case TypeAttributes.NestedFamORAssem: - case TypeAttributes.NestedPublic: - case TypeAttributes.Public: - return true; - default: - return false; - } - } - - public override object VisitSimpleType(SimpleType simpleType, object data) - { - // Handle type arguments first, so that the fixed-up type arguments get moved over to the MemberType, - // if we're also creating one here. - base.VisitSimpleType(simpleType, data); - TypeReference tr = simpleType.Annotation(); - // Fully qualify any ambiguous type names. - if (tr != null && IsAmbiguous(tr.Namespace, tr.Name)) { - AstType ns; - if (string.IsNullOrEmpty(tr.Namespace)) { - ns = new SimpleType("global"); - } else { - string[] parts = tr.Namespace.Split('.'); - if (IsAmbiguous(string.Empty, parts[0])) { - // conflict between namespace and type name/member name - ns = new MemberType { Target = new SimpleType("global"), IsDoubleColon = true, MemberName = parts[0] }; - } else { - ns = new SimpleType(parts[0]); - } - for (int i = 1; i < parts.Length; i++) { - ns = new MemberType { Target = ns, MemberName = parts[i] }; - } - } - MemberType mt = new MemberType(); - mt.Target = ns; - mt.IsDoubleColon = string.IsNullOrEmpty(tr.Namespace); - mt.MemberName = simpleType.Identifier; - mt.CopyAnnotationsFrom(simpleType); - simpleType.TypeArguments.MoveTo(mt.TypeArguments); - simpleType.ReplaceWith(mt); - } - return null; - } - - public override object VisitTypeReferenceExpression(TypeReferenceExpression typeReferenceExpression, object data) - { - isWithinTypeReferenceExpression = true; - base.VisitTypeReferenceExpression(typeReferenceExpression, data); - isWithinTypeReferenceExpression = false; - return null; - } - - bool IsAmbiguous(string ns, string name) - { - // If the type name conflicts with an inner class/type parameter, we need to fully-qualify it: - if (currentMemberTypes != null && currentMemberTypes.Contains(name)) - return true; - // If the type name conflicts with a field/property etc. on the current class, we need to fully-qualify it, - // if we're inside an expression. - if (isWithinTypeReferenceExpression && currentMembers != null) { - MemberReference mr; - if (currentMembers.TryGetValue(name, out mr)) { - // However, in the special case where the member is a field or property with the same type - // as is requested, then we can use the short name (if it's not otherwise ambiguous) - PropertyDefinition prop = mr as PropertyDefinition; - FieldDefinition field = mr as FieldDefinition; - if (!(prop != null && prop.PropertyType.Namespace == ns && prop.PropertyType.Name == name) - && !(field != null && field.FieldType.Namespace == ns && field.FieldType.Name == name)) - return true; - } - } - // If the type is defined in the current namespace, - // then we can use the short name even if we imported type with same name from another namespace. - if (ns == currentNamespace && !string.IsNullOrEmpty(ns)) - return false; - return transform.ambiguousTypeNames.Contains(name); - } - } - } -} diff --git a/ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs b/ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs deleted file mode 100644 index d3ae46c1..00000000 --- a/ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs +++ /dev/null @@ -1,1123 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; - -using ICSharpCode.Decompiler.ILAst; -using ICSharpCode.NRefactory.CSharp; -using ICSharpCode.NRefactory.CSharp.Analysis; -using ICSharpCode.NRefactory.PatternMatching; -using Mono.Cecil; - -namespace ICSharpCode.Decompiler.Ast.Transforms -{ - /// - /// Finds the expanded form of using statements using pattern matching and replaces it with a UsingStatement. - /// - public sealed class PatternStatementTransform : ContextTrackingVisitor, IAstTransform - { - public PatternStatementTransform(DecompilerContext context) : base(context) - { - } - - #region Visitor Overrides - protected override AstNode VisitChildren(AstNode node, object data) - { - // Go through the children, and keep visiting a node as long as it changes. - // Because some transforms delete/replace nodes before and after the node being transformed, we rely - // on the transform's return value to know where we need to keep iterating. - for (AstNode child = node.FirstChild; child != null; child = child.NextSibling) { - AstNode oldChild; - do { - oldChild = child; - child = child.AcceptVisitor(this, data); - Debug.Assert(child != null && child.Parent == node); - } while (child != oldChild); - } - return node; - } - - public override AstNode VisitExpressionStatement(ExpressionStatement expressionStatement, object data) - { - AstNode result; - if (context.Settings.UsingStatement) { - result = TransformUsings(expressionStatement); - if (result != null) - return result; - result = TransformNonGenericForEach(expressionStatement); - if (result != null) - return result; - } - result = TransformFor(expressionStatement); - if (result != null) - return result; - if (context.Settings.LockStatement) { - result = TransformLock(expressionStatement); - if (result != null) - return result; - } - return base.VisitExpressionStatement(expressionStatement, data); - } - - public override AstNode VisitUsingStatement(UsingStatement usingStatement, object data) - { - if (context.Settings.ForEachStatement) { - AstNode result = TransformForeach(usingStatement); - if (result != null) - return result; - } - return base.VisitUsingStatement(usingStatement, data); - } - - public override AstNode VisitWhileStatement(WhileStatement whileStatement, object data) - { - return TransformDoWhile(whileStatement) ?? base.VisitWhileStatement(whileStatement, data); - } - - public override AstNode VisitIfElseStatement(IfElseStatement ifElseStatement, object data) - { - if (context.Settings.SwitchStatementOnString) { - AstNode result = TransformSwitchOnString(ifElseStatement); - if (result != null) - return result; - } - AstNode simplifiedIfElse = SimplifyCascadingIfElseStatements(ifElseStatement); - if (simplifiedIfElse != null) - return simplifiedIfElse; - return base.VisitIfElseStatement(ifElseStatement, data); - } - - public override AstNode VisitPropertyDeclaration(PropertyDeclaration propertyDeclaration, object data) - { - if (context.Settings.AutomaticProperties) { - AstNode result = TransformAutomaticProperties(propertyDeclaration); - if (result != null) - return result; - } - return base.VisitPropertyDeclaration(propertyDeclaration, data); - } - - public override AstNode VisitCustomEventDeclaration(CustomEventDeclaration eventDeclaration, object data) - { - // first apply transforms to the accessor bodies - base.VisitCustomEventDeclaration(eventDeclaration, data); - if (context.Settings.AutomaticEvents) { - AstNode result = TransformAutomaticEvents(eventDeclaration); - if (result != null) - return result; - } - return eventDeclaration; - } - - public override AstNode VisitMethodDeclaration(MethodDeclaration methodDeclaration, object data) - { - return TransformDestructor(methodDeclaration) ?? base.VisitMethodDeclaration(methodDeclaration, data); - } - - public override AstNode VisitTryCatchStatement(TryCatchStatement tryCatchStatement, object data) - { - return TransformTryCatchFinally(tryCatchStatement) ?? base.VisitTryCatchStatement(tryCatchStatement, data); - } - #endregion - - /// - /// $variable = $initializer; - /// - static readonly AstNode variableAssignPattern = new ExpressionStatement( - new AssignmentExpression( - new NamedNode("variable", new IdentifierExpression(Pattern.AnyString)), - new AnyNode("initializer") - )); - - #region using - static Expression InvokeDispose(Expression identifier) - { - return new Choice { - identifier.Invoke("Dispose"), - identifier.Clone().CastTo(new TypePattern(typeof(IDisposable))).Invoke("Dispose") - }; - } - - static readonly AstNode usingTryCatchPattern = new TryCatchStatement { - TryBlock = new AnyNode(), - FinallyBlock = new BlockStatement { - new Choice { - { "valueType", - new ExpressionStatement(InvokeDispose(new NamedNode("ident", new IdentifierExpression(Pattern.AnyString)))) - }, - { "referenceType", - new IfElseStatement { - Condition = new BinaryOperatorExpression( - new NamedNode("ident", new IdentifierExpression(Pattern.AnyString)), - BinaryOperatorType.InEquality, - new NullReferenceExpression() - ), - TrueStatement = new BlockStatement { - new ExpressionStatement(InvokeDispose(new Backreference("ident"))) - } - } - } - }.ToStatement() - } - }; - - public UsingStatement TransformUsings(ExpressionStatement node) - { - Match m1 = variableAssignPattern.Match(node); - if (!m1.Success) return null; - TryCatchStatement tryCatch = node.NextSibling as TryCatchStatement; - Match m2 = usingTryCatchPattern.Match(tryCatch); - if (!m2.Success) return null; - string variableName = m1.Get("variable").Single().Identifier; - if (variableName != m2.Get("ident").Single().Identifier) - return null; - if (m2.Has("valueType")) { - // if there's no if(x!=null), then it must be a value type - ILVariable v = m1.Get("variable").Single().Annotation(); - if (v == null || v.Type == null || !v.Type.IsValueType) - return null; - } - - // There are two variants of the using statement: - // "using (var a = init)" and "using (expr)". - // The former declares a read-only variable 'a', and the latter declares an unnamed read-only variable - // to store the original value of 'expr'. - // This means that in order to introduce a using statement, in both cases we need to detect a read-only - // variable that is used only within that block. - - if (HasAssignment(tryCatch, variableName)) - return null; - - VariableDeclarationStatement varDecl = FindVariableDeclaration(node, variableName); - if (varDecl == null || !(varDecl.Parent is BlockStatement)) - return null; - - // Validate that the variable is not used after the using statement: - if (!IsVariableValueUnused(varDecl, tryCatch)) - return null; - - node.Remove(); - - UsingStatement usingStatement = new UsingStatement(); - usingStatement.EmbeddedStatement = tryCatch.TryBlock.Detach(); - tryCatch.ReplaceWith(usingStatement); - - // If possible, we'll eliminate the variable completely: - if (usingStatement.EmbeddedStatement.Descendants.OfType().Any(ident => ident.Identifier == variableName)) { - // variable is used, so we'll create a variable declaration - usingStatement.ResourceAcquisition = new VariableDeclarationStatement { - Type = (AstType)varDecl.Type.Clone(), - Variables = { - new VariableInitializer { - Name = variableName, - Initializer = m1.Get("initializer").Single().Detach() - }.CopyAnnotationsFrom(node.Expression) - .WithAnnotation(m1.Get("variable").Single().Annotation()) - } - }.CopyAnnotationsFrom(node); - } else { - // the variable is never used; eliminate it: - usingStatement.ResourceAcquisition = m1.Get("initializer").Single().Detach(); - } - return usingStatement; - } - - internal static VariableDeclarationStatement FindVariableDeclaration(AstNode node, string identifier) - { - while (node != null) { - while (node.PrevSibling != null) { - node = node.PrevSibling; - VariableDeclarationStatement varDecl = node as VariableDeclarationStatement; - if (varDecl != null && varDecl.Variables.Count == 1 && varDecl.Variables.Single().Name == identifier) { - return varDecl; - } - } - node = node.Parent; - } - return null; - } - - /// - /// Gets whether the old variable value (assigned inside 'targetStatement' or earlier) - /// is read anywhere in the remaining scope of the variable declaration. - /// - bool IsVariableValueUnused(VariableDeclarationStatement varDecl, Statement targetStatement) - { - Debug.Assert(targetStatement.Ancestors.Contains(varDecl.Parent)); - BlockStatement block = (BlockStatement)varDecl.Parent; - DefiniteAssignmentAnalysis daa = new DefiniteAssignmentAnalysis(block, context.CancellationToken); - daa.SetAnalyzedRange(targetStatement, block, startInclusive: false); - daa.Analyze(varDecl.Variables.Single().Name); - return daa.UnassignedVariableUses.Count == 0; - } - - // I used this in the first implementation of the using-statement transform, but now no longer - // because there were problems when multiple using statements were using the same variable - // - no single using statement could be transformed without making the C# code invalid, - // but transforming both would work. - // We now use 'IsVariableValueUnused' which will perform the transform - // even if it results in two variables with the same name and overlapping scopes. - // (this issue could be fixed later by renaming one of the variables) - - // I'm not sure whether the other consumers of 'CanMoveVariableDeclarationIntoStatement' should be changed the same way. - bool CanMoveVariableDeclarationIntoStatement(VariableDeclarationStatement varDecl, Statement targetStatement, out Statement declarationPoint) - { - Debug.Assert(targetStatement.Ancestors.Contains(varDecl.Parent)); - // Find all blocks between targetStatement and varDecl.Parent - List blocks = targetStatement.Ancestors.TakeWhile(block => block != varDecl.Parent).OfType().ToList(); - blocks.Add((BlockStatement)varDecl.Parent); // also handle the varDecl.Parent block itself - blocks.Reverse(); // go from parent blocks to child blocks - DefiniteAssignmentAnalysis daa = new DefiniteAssignmentAnalysis(blocks[0], context.CancellationToken); - declarationPoint = null; - foreach (BlockStatement block in blocks) { - if (!DeclareVariables.FindDeclarationPoint(daa, varDecl, block, out declarationPoint)) { - return false; - } - } - return true; - } - - /// - /// Gets whether there is an assignment to 'variableName' anywhere within the given node. - /// - bool HasAssignment(AstNode root, string variableName) - { - foreach (AstNode node in root.DescendantsAndSelf) { - IdentifierExpression ident = node as IdentifierExpression; - if (ident != null && ident.Identifier == variableName) { - if (ident.Parent is AssignmentExpression && ident.Role == AssignmentExpression.LeftRole - || ident.Parent is DirectionExpression) - { - return true; - } - } - } - return false; - } - #endregion - - #region foreach (generic) - static readonly UsingStatement genericForeachPattern = new UsingStatement { - ResourceAcquisition = new VariableDeclarationStatement { - Type = new AnyNode("enumeratorType"), - Variables = { - new NamedNode( - "enumeratorVariable", - new VariableInitializer { - Name = Pattern.AnyString, - Initializer = new AnyNode("collection").ToExpression().Invoke("GetEnumerator") - } - ) - } - }, - EmbeddedStatement = new BlockStatement { - new Repeat( - new VariableDeclarationStatement { Type = new AnyNode(), Variables = { new VariableInitializer(Pattern.AnyString) } }.WithName("variablesOutsideLoop") - ).ToStatement(), - new WhileStatement { - Condition = new IdentifierExpressionBackreference("enumeratorVariable").ToExpression().Invoke("MoveNext"), - EmbeddedStatement = new BlockStatement { - new Repeat( - new VariableDeclarationStatement { - Type = new AnyNode(), - Variables = { new VariableInitializer(Pattern.AnyString) } - }.WithName("variablesInsideLoop") - ).ToStatement(), - new AssignmentExpression { - Left = new IdentifierExpression(Pattern.AnyString).WithName("itemVariable"), - Operator = AssignmentOperatorType.Assign, - Right = new IdentifierExpressionBackreference("enumeratorVariable").ToExpression().Member("Current") - }, - new Repeat(new AnyNode("statement")).ToStatement() - } - }.WithName("loop") - }}; - - public ForeachStatement TransformForeach(UsingStatement node) - { - Match m = genericForeachPattern.Match(node); - if (!m.Success) - return null; - if (!(node.Parent is BlockStatement) && m.Has("variablesOutsideLoop")) { - // if there are variables outside the loop, we need to put those into the parent block, and that won't work if the direct parent isn't a block - return null; - } - VariableInitializer enumeratorVar = m.Get("enumeratorVariable").Single(); - IdentifierExpression itemVar = m.Get("itemVariable").Single(); - WhileStatement loop = m.Get("loop").Single(); - - // 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; - - BlockStatement newBody = new BlockStatement(); - foreach (Statement stmt in m.Get("variablesInsideLoop")) - newBody.Add(stmt.Detach()); - foreach (Statement stmt in m.Get("statement")) - newBody.Add(stmt.Detach()); - - ForeachStatement foreachStatement = new ForeachStatement { - VariableType = (AstType)itemVarDecl.Type.Clone(), - VariableName = itemVar.Identifier, - InExpression = m.Get("collection").Single().Detach(), - EmbeddedStatement = newBody - }.WithAnnotation(itemVarDecl.Variables.Single().Annotation()); - if (foreachStatement.InExpression is BaseReferenceExpression) { - foreachStatement.InExpression = new ThisReferenceExpression().CopyAnnotationsFrom(foreachStatement.InExpression); - } - node.ReplaceWith(foreachStatement); - foreach (Statement stmt in m.Get("variablesOutsideLoop")) { - ((BlockStatement)foreachStatement.Parent).Statements.InsertAfter(null, stmt.Detach()); - } - return foreachStatement; - } - #endregion - - #region foreach (non-generic) - ExpressionStatement getEnumeratorPattern = new ExpressionStatement( - new AssignmentExpression( - new NamedNode("left", new IdentifierExpression(Pattern.AnyString)), - new AnyNode("collection").ToExpression().Invoke("GetEnumerator") - )); - - TryCatchStatement nonGenericForeachPattern = new TryCatchStatement { - TryBlock = new BlockStatement { - new WhileStatement { - Condition = new IdentifierExpression(Pattern.AnyString).WithName("enumerator").Invoke("MoveNext"), - EmbeddedStatement = new BlockStatement { - new AssignmentExpression( - new IdentifierExpression(Pattern.AnyString).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(Pattern.AnyString).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("enumerator").Single(); - IdentifierExpression itemVar = m2.Get("itemVar").Single(); - WhileStatement loop = m2.Get("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 - { - VariableType = itemVarDecl.Type.Clone(), - VariableName = itemVar.Identifier, - }.WithAnnotation(itemVarDecl.Variables.Single().Annotation()); - 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("collection").Single().Detach(); - if (foreachStatement.InExpression is BaseReferenceExpression) { - foreachStatement.InExpression = new ThisReferenceExpression().CopyAnnotationsFrom(foreachStatement.InExpression); - } - body.Statements.Clear(); - body.Statements.AddRange(m2.Get("stmt").Select(stmt => stmt.Detach())); - - return foreachStatement; - } - #endregion - - #region for - static readonly WhileStatement forPattern = new WhileStatement { - Condition = new BinaryOperatorExpression { - Left = new NamedNode("ident", new IdentifierExpression(Pattern.AnyString)), - Operator = BinaryOperatorType.Any, - Right = new AnyNode("endExpr") - }, - EmbeddedStatement = new BlockStatement { - Statements = { - new Repeat(new AnyNode("statement")), - new NamedNode( - "increment", - new ExpressionStatement( - new AssignmentExpression { - Left = new Backreference("ident"), - Operator = AssignmentOperatorType.Any, - Right = new AnyNode() - })) - } - }}; - - public ForStatement TransformFor(ExpressionStatement node) - { - Match m1 = variableAssignPattern.Match(node); - if (!m1.Success) return null; - AstNode next = node.NextSibling; - Match m2 = forPattern.Match(next); - if (!m2.Success) return null; - // ensure the variable in the for pattern is the same as in the declaration - if (m1.Get("variable").Single().Identifier != m2.Get("ident").Single().Identifier) - return null; - WhileStatement loop = (WhileStatement)next; - node.Remove(); - BlockStatement newBody = new BlockStatement(); - foreach (Statement stmt in m2.Get("statement")) - newBody.Add(stmt.Detach()); - ForStatement forStatement = new ForStatement(); - forStatement.Initializers.Add(node); - forStatement.Condition = loop.Condition.Detach(); - forStatement.Iterators.Add(m2.Get("increment").Single().Detach()); - forStatement.EmbeddedStatement = newBody; - loop.ReplaceWith(forStatement); - return forStatement; - } - #endregion - - #region doWhile - static readonly WhileStatement doWhilePattern = new WhileStatement { - Condition = new PrimitiveExpression(true), - EmbeddedStatement = new BlockStatement { - Statements = { - new Repeat(new AnyNode("statement")), - new IfElseStatement { - Condition = new AnyNode("condition"), - TrueStatement = new BlockStatement { new BreakStatement() } - } - } - }}; - - public DoWhileStatement TransformDoWhile(WhileStatement whileLoop) - { - Match m = doWhilePattern.Match(whileLoop); - if (m.Success) { - DoWhileStatement doLoop = new DoWhileStatement(); - doLoop.Condition = new UnaryOperatorExpression(UnaryOperatorType.Not, m.Get("condition").Single().Detach()); - doLoop.Condition.AcceptVisitor(new PushNegation(), null); - BlockStatement block = (BlockStatement)whileLoop.EmbeddedStatement; - block.Statements.Last().Remove(); // remove if statement - doLoop.EmbeddedStatement = block.Detach(); - whileLoop.ReplaceWith(doLoop); - - // we may have to extract variable definitions out of the loop if they were used in the condition: - foreach (var varDecl in block.Statements.OfType()) { - VariableInitializer v = varDecl.Variables.Single(); - if (doLoop.Condition.DescendantsAndSelf.OfType().Any(i => i.Identifier == v.Name)) { - AssignmentExpression assign = new AssignmentExpression(new IdentifierExpression(v.Name), v.Initializer.Detach()); - // move annotations from v to assign: - assign.CopyAnnotationsFrom(v); - v.RemoveAnnotations(); - // remove varDecl with assignment; and move annotations from varDecl to the ExpressionStatement: - varDecl.ReplaceWith(new ExpressionStatement(assign).CopyAnnotationsFrom(varDecl)); - varDecl.RemoveAnnotations(); - - // insert the varDecl above the do-while loop: - doLoop.Parent.InsertChildBefore(doLoop, varDecl, BlockStatement.StatementRole); - } - } - return doLoop; - } - return null; - } - #endregion - - #region lock - static readonly AstNode lockFlagInitPattern = new ExpressionStatement( - new AssignmentExpression( - new NamedNode("variable", new IdentifierExpression(Pattern.AnyString)), - new PrimitiveExpression(false) - )); - - static readonly AstNode lockTryCatchPattern = new TryCatchStatement { - TryBlock = new BlockStatement { - new OptionalNode(new VariableDeclarationStatement()).ToStatement(), - new TypePattern(typeof(System.Threading.Monitor)).ToType().Invoke( - "Enter", new AnyNode("enter"), - new DirectionExpression { - FieldDirection = FieldDirection.Ref, - Expression = new NamedNode("flag", new IdentifierExpression(Pattern.AnyString)) - }), - new Repeat(new AnyNode()).ToStatement() - }, - FinallyBlock = new BlockStatement { - new IfElseStatement { - Condition = new Backreference("flag"), - TrueStatement = new BlockStatement { - new TypePattern(typeof(System.Threading.Monitor)).ToType().Invoke("Exit", new AnyNode("exit")) - } - } - }}; - - static readonly AstNode oldMonitorCallPattern = new ExpressionStatement( - new TypePattern(typeof(System.Threading.Monitor)).ToType().Invoke("Enter", new AnyNode("enter")) - ); - - static readonly AstNode oldLockTryCatchPattern = new TryCatchStatement - { - TryBlock = new BlockStatement { - new Repeat(new AnyNode()).ToStatement() - }, - FinallyBlock = new BlockStatement { - new TypePattern(typeof(System.Threading.Monitor)).ToType().Invoke("Exit", new AnyNode("exit")) - } - }; - - bool AnalyzeLockV2(ExpressionStatement node, out Expression enter, out Expression exit) - { - enter = null; - exit = null; - Match m1 = oldMonitorCallPattern.Match(node); - if (!m1.Success) return false; - Match m2 = oldLockTryCatchPattern.Match(node.NextSibling); - if (!m2.Success) return false; - enter = m1.Get("enter").Single(); - exit = m2.Get("exit").Single(); - return true; - } - - bool AnalyzeLockV4(ExpressionStatement node, out Expression enter, out Expression exit) - { - enter = null; - exit = null; - Match m1 = lockFlagInitPattern.Match(node); - if (!m1.Success) return false; - Match m2 = lockTryCatchPattern.Match(node.NextSibling); - if (!m2.Success) return false; - enter = m2.Get("enter").Single(); - exit = m2.Get("exit").Single(); - return m1.Get("variable").Single().Identifier == m2.Get("flag").Single().Identifier; - } - - public LockStatement TransformLock(ExpressionStatement node) - { - Expression enter, exit; - bool isV2 = AnalyzeLockV2(node, out enter, out exit); - if (isV2 || AnalyzeLockV4(node, out enter, out exit)) { - AstNode tryCatch = node.NextSibling; - if (!exit.IsMatch(enter)) { - // If exit and enter are not the same, then enter must be "exit = ..." - AssignmentExpression assign = enter as AssignmentExpression; - if (assign == null) - return null; - if (!exit.IsMatch(assign.Left)) - return null; - enter = assign.Right; - // TODO: verify that 'obj' variable can be removed - } - // TODO: verify that 'flag' variable can be removed - // transform the code into a lock statement: - LockStatement l = new LockStatement(); - l.Expression = enter.Detach(); - l.EmbeddedStatement = ((TryCatchStatement)tryCatch).TryBlock.Detach(); - if (!isV2) // Remove 'Enter()' call - ((BlockStatement)l.EmbeddedStatement).Statements.First().Remove(); - tryCatch.ReplaceWith(l); - node.Remove(); // remove flag variable - return l; - } - return null; - } - #endregion - - #region switch on strings - static readonly IfElseStatement switchOnStringPattern = new IfElseStatement { - Condition = new BinaryOperatorExpression { - Left = new AnyNode("switchExpr"), - Operator = BinaryOperatorType.InEquality, - Right = new NullReferenceExpression() - }, - TrueStatement = new BlockStatement { - new IfElseStatement { - Condition = new BinaryOperatorExpression { - Left = new AnyNode("cachedDict"), - Operator = BinaryOperatorType.Equality, - Right = new NullReferenceExpression() - }, - TrueStatement = new AnyNode("dictCreation") - }, - new IfElseStatement { - Condition = new Backreference("cachedDict").ToExpression().Invoke( - "TryGetValue", - new NamedNode("switchVar", new IdentifierExpression(Pattern.AnyString)), - new DirectionExpression { - FieldDirection = FieldDirection.Out, - Expression = new IdentifierExpression(Pattern.AnyString).WithName("intVar") - }), - TrueStatement = new BlockStatement { - Statements = { - new NamedNode( - "switch", new SwitchStatement { - Expression = new IdentifierExpressionBackreference("intVar"), - SwitchSections = { new Repeat(new AnyNode()) } - }) - } - } - }, - new Repeat(new AnyNode("nonNullDefaultStmt")).ToStatement() - }, - FalseStatement = new OptionalNode("nullStmt", new BlockStatement { Statements = { new Repeat(new AnyNode()) } }) - }; - - public SwitchStatement TransformSwitchOnString(IfElseStatement node) - { - Match m = switchOnStringPattern.Match(node); - if (!m.Success) - 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; - if (!(assign != null && m.Get("switchVar").Single().IsMatch(assign.Left))) - return null; - } - FieldReference cachedDictField = m.Get("cachedDict").Single().Annotation(); - if (cachedDictField == null) - return null; - List dictCreation = m.Get("dictCreation").Single().Statements.ToList(); - List> dict = BuildDictionary(dictCreation); - SwitchStatement sw = m.Get("switch").Single(); - sw.Expression = m.Get("switchExpr").Single().Detach(); - foreach (SwitchSection section in sw.SwitchSections) { - List labels = section.CaseLabels.ToList(); - section.CaseLabels.Clear(); - foreach (CaseLabel label in labels) { - PrimitiveExpression expr = label.Expression as PrimitiveExpression; - if (expr == null || !(expr.Value is int)) - continue; - int val = (int)expr.Value; - foreach (var pair in dict) { - if (pair.Value == val) - section.CaseLabels.Add(new CaseLabel { Expression = new PrimitiveExpression(pair.Key) }); - } - } - } - if (m.Has("nullStmt")) { - SwitchSection section = new SwitchSection(); - section.CaseLabels.Add(new CaseLabel { Expression = new NullReferenceExpression() }); - BlockStatement block = m.Get("nullStmt").Single(); - block.Statements.Add(new BreakStatement()); - section.Statements.Add(block.Detach()); - 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("nonNullDefaultStmt").Select(s => s.Detach())); - block.Add(new BreakStatement()); - section.Statements.Add(block); - sw.SwitchSections.Add(section); - } - node.ReplaceWith(sw); - return sw; - } - - List> BuildDictionary(List dictCreation) - { - if (context.Settings.ObjectOrCollectionInitializers && dictCreation.Count == 1) - return BuildDictionaryFromInitializer(dictCreation[0]); - - return BuildDictionaryFromAddMethodCalls(dictCreation); - } - - static readonly Statement assignInitializedDictionary = new ExpressionStatement { - Expression = new AssignmentExpression { - Left = new AnyNode().ToExpression(), - Right = new ObjectCreateExpression { - Type = new AnyNode(), - Arguments = { new Repeat(new AnyNode()) }, - Initializer = new ArrayInitializerExpression { - Elements = { new Repeat(new AnyNode("dictJumpTable")) } - } - }, - }, - }; - - List> BuildDictionaryFromInitializer(Statement statement) - { - List> dict = new List>(); - Match m = assignInitializedDictionary.Match(statement); - if (!m.Success) - return dict; - - foreach (ArrayInitializerExpression initializer in m.Get("dictJumpTable")) { - KeyValuePair pair; - if (TryGetPairFrom(initializer.Elements, out pair)) - dict.Add(pair); - } - - return dict; - } - - static List> BuildDictionaryFromAddMethodCalls(List dictCreation) - { - List> dict = new List>(); - for (int i = 0; i < dictCreation.Count; i++) { - ExpressionStatement es = dictCreation[i] as ExpressionStatement; - if (es == null) - continue; - InvocationExpression ie = es.Expression as InvocationExpression; - if (ie == null) - continue; - - KeyValuePair pair; - if (TryGetPairFrom(ie.Arguments, out pair)) - dict.Add(pair); - } - return dict; - } - - static bool TryGetPairFrom(AstNodeCollection expressions, out KeyValuePair pair) - { - PrimitiveExpression arg1 = expressions.ElementAtOrDefault(0) as PrimitiveExpression; - PrimitiveExpression arg2 = expressions.ElementAtOrDefault(1) as PrimitiveExpression; - if (arg1 != null && arg2 != null && arg1.Value is string && arg2.Value is int) { - pair = new KeyValuePair((string)arg1.Value, (int)arg2.Value); - return true; - } - - pair = default(KeyValuePair); - return false; - } - - #endregion - - #region Automatic Properties - static readonly PropertyDeclaration automaticPropertyPattern = new PropertyDeclaration { - Attributes = { new Repeat(new AnyNode()) }, - Modifiers = Modifiers.Any, - ReturnType = new AnyNode(), - PrivateImplementationType = new OptionalNode(new AnyNode()), - Name = Pattern.AnyString, - Getter = new Accessor { - Attributes = { new Repeat(new AnyNode()) }, - Modifiers = Modifiers.Any, - Body = new BlockStatement { - new ReturnStatement { - Expression = new AnyNode("fieldReference") - } - } - }, - Setter = new Accessor { - Attributes = { new Repeat(new AnyNode()) }, - Modifiers = Modifiers.Any, - Body = new BlockStatement { - new AssignmentExpression { - Left = new Backreference("fieldReference"), - Right = new IdentifierExpression("value") - } - }}}; - - PropertyDeclaration TransformAutomaticProperties(PropertyDeclaration property) - { - PropertyDefinition cecilProperty = property.Annotation(); - if (cecilProperty == null || cecilProperty.GetMethod == null || cecilProperty.SetMethod == null) - return null; - if (!(cecilProperty.GetMethod.IsCompilerGenerated() && cecilProperty.SetMethod.IsCompilerGenerated())) - return null; - Match m = automaticPropertyPattern.Match(property); - if (m.Success) { - FieldDefinition field = m.Get("fieldReference").Single().Annotation().ResolveWithinSameModule(); - if (field.IsCompilerGenerated() && field.DeclaringType == cecilProperty.DeclaringType) { - RemoveCompilerGeneratedAttribute(property.Getter.Attributes); - RemoveCompilerGeneratedAttribute(property.Setter.Attributes); - property.Getter.Body = null; - property.Setter.Body = null; - } - } - // Since the event instance is not changed, we can continue in the visitor as usual, so return null - return null; - } - - void RemoveCompilerGeneratedAttribute(AstNodeCollection attributeSections) - { - foreach (AttributeSection section in attributeSections) { - foreach (var attr in section.Attributes) { - TypeReference tr = attr.Type.Annotation(); - if (tr != null && tr.Namespace == "System.Runtime.CompilerServices" && tr.Name == "CompilerGeneratedAttribute") { - attr.Remove(); - } - } - if (section.Attributes.Count == 0) - section.Remove(); - } - } - #endregion - - #region Automatic Events - static readonly Accessor automaticEventPatternV4 = new Accessor { - Attributes = { new Repeat(new AnyNode()) }, - Body = new BlockStatement { - new VariableDeclarationStatement { Type = new AnyNode("type"), Variables = { new AnyNode() } }, - new VariableDeclarationStatement { Type = new Backreference("type"), Variables = { new AnyNode() } }, - new VariableDeclarationStatement { Type = new Backreference("type"), Variables = { new AnyNode() } }, - new AssignmentExpression { - Left = new NamedNode("var1", new IdentifierExpression(Pattern.AnyString)), - Operator = AssignmentOperatorType.Assign, - Right = new NamedNode( - "field", - new MemberReferenceExpression { - Target = new Choice { new ThisReferenceExpression(), new TypeReferenceExpression { Type = new AnyNode() } }, - MemberName = Pattern.AnyString - }) - }, - new DoWhileStatement { - EmbeddedStatement = new BlockStatement { - new AssignmentExpression(new NamedNode("var2", new IdentifierExpression(Pattern.AnyString)), new IdentifierExpressionBackreference("var1")), - new AssignmentExpression { - Left = new NamedNode("var3", new IdentifierExpression(Pattern.AnyString)), - Operator = AssignmentOperatorType.Assign, - Right = new AnyNode("delegateCombine").ToExpression().Invoke( - new IdentifierExpressionBackreference("var2"), - new IdentifierExpression("value") - ).CastTo(new Backreference("type")) - }, - new AssignmentExpression { - Left = new IdentifierExpressionBackreference("var1"), - Right = new TypePattern(typeof(System.Threading.Interlocked)).ToType().Invoke( - "CompareExchange", - new AstType[] { new Backreference("type") }, // type argument - new Expression[] { // arguments - new DirectionExpression { FieldDirection = FieldDirection.Ref, Expression = new Backreference("field") }, - new IdentifierExpressionBackreference("var3"), - new IdentifierExpressionBackreference("var2") - } - )} - }, - Condition = new BinaryOperatorExpression { - Left = new IdentifierExpressionBackreference("var1"), - Operator = BinaryOperatorType.InEquality, - Right = new IdentifierExpressionBackreference("var2") - }} - }}; - - bool CheckAutomaticEventV4Match(Match m, CustomEventDeclaration ev, bool isAddAccessor) - { - if (!m.Success) - return false; - if (m.Get("field").Single().MemberName != ev.Name) - return false; // field name must match event name - if (!ev.ReturnType.IsMatch(m.Get("type").Single())) - return false; // variable types must match event type - var combineMethod = m.Get("delegateCombine").Single().Parent.Annotation(); - if (combineMethod == null || combineMethod.Name != (isAddAccessor ? "Combine" : "Remove")) - return false; - return combineMethod.DeclaringType.FullName == "System.Delegate"; - } - - EventDeclaration TransformAutomaticEvents(CustomEventDeclaration ev) - { - Match m1 = automaticEventPatternV4.Match(ev.AddAccessor); - if (!CheckAutomaticEventV4Match(m1, ev, true)) - return null; - Match m2 = automaticEventPatternV4.Match(ev.RemoveAccessor); - if (!CheckAutomaticEventV4Match(m2, ev, false)) - return null; - EventDeclaration ed = new EventDeclaration(); - ev.Attributes.MoveTo(ed.Attributes); - foreach (var attr in ev.AddAccessor.Attributes) { - attr.AttributeTarget = "method"; - ed.Attributes.Add(attr.Detach()); - } - ed.ReturnType = ev.ReturnType.Detach(); - ed.Modifiers = ev.Modifiers; - ed.Variables.Add(new VariableInitializer(ev.Name)); - ed.CopyAnnotationsFrom(ev); - - EventDefinition eventDef = ev.Annotation(); - if (eventDef != null) { - FieldDefinition field = eventDef.DeclaringType.Fields.FirstOrDefault(f => f.Name == ev.Name); - if (field != null) { - ed.AddAnnotation(field); - AstBuilder.ConvertAttributes(ed, field, "field"); - } - } - - ev.ReplaceWith(ed); - return ed; - } - #endregion - - #region Destructor - static readonly MethodDeclaration destructorPattern = new MethodDeclaration { - Attributes = { new Repeat(new AnyNode()) }, - Modifiers = Modifiers.Any, - ReturnType = new PrimitiveType("void"), - Name = "Finalize", - Body = new BlockStatement { - new TryCatchStatement { - TryBlock = new AnyNode("body"), - FinallyBlock = new BlockStatement { - new BaseReferenceExpression().Invoke("Finalize") - } - } - } - }; - - DestructorDeclaration TransformDestructor(MethodDeclaration methodDef) - { - Match m = destructorPattern.Match(methodDef); - if (m.Success) { - DestructorDeclaration dd = new DestructorDeclaration(); - methodDef.Attributes.MoveTo(dd.Attributes); - dd.Modifiers = methodDef.Modifiers & ~(Modifiers.Protected | Modifiers.Override); - dd.Body = m.Get("body").Single().Detach(); - dd.Name = AstBuilder.CleanName(context.CurrentType.Name); - methodDef.ReplaceWith(dd); - return dd; - } - return null; - } - #endregion - - #region Try-Catch-Finally - static readonly TryCatchStatement tryCatchFinallyPattern = new TryCatchStatement { - TryBlock = new BlockStatement { - new TryCatchStatement { - TryBlock = new AnyNode(), - CatchClauses = { new Repeat(new AnyNode()) } - } - }, - FinallyBlock = new AnyNode() - }; - - /// - /// Simplify nested 'try { try {} catch {} } finally {}'. - /// This transformation must run after the using/lock tranformations. - /// - TryCatchStatement TransformTryCatchFinally(TryCatchStatement tryFinally) - { - if (tryCatchFinallyPattern.IsMatch(tryFinally)) { - TryCatchStatement tryCatch = (TryCatchStatement)tryFinally.TryBlock.Statements.Single(); - tryFinally.TryBlock = tryCatch.TryBlock.Detach(); - tryCatch.CatchClauses.MoveTo(tryFinally.CatchClauses); - } - // Since the tryFinally instance is not changed, we can continue in the visitor as usual, so return null - return null; - } - #endregion - - #region Simplify cascading if-else-if statements - static readonly IfElseStatement cascadingIfElsePattern = new IfElseStatement - { - Condition = new AnyNode(), - TrueStatement = new AnyNode(), - FalseStatement = new BlockStatement { - Statements = { - new NamedNode( - "nestedIfStatement", - new IfElseStatement { - Condition = new AnyNode(), - TrueStatement = new AnyNode(), - FalseStatement = new OptionalNode(new AnyNode()) - } - ) - } - } - }; - - AstNode SimplifyCascadingIfElseStatements(IfElseStatement node) - { - Match m = cascadingIfElsePattern.Match(node); - if (m.Success) { - IfElseStatement elseIf = m.Get("nestedIfStatement").Single(); - node.FalseStatement = elseIf.Detach(); - } - - return null; - } - #endregion - } -} diff --git a/ICSharpCode.Decompiler/Ast/Transforms/PushNegation.cs b/ICSharpCode.Decompiler/Ast/Transforms/PushNegation.cs deleted file mode 100644 index 193c5e69..00000000 --- a/ICSharpCode.Decompiler/Ast/Transforms/PushNegation.cs +++ /dev/null @@ -1,164 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Linq; -using ICSharpCode.NRefactory.CSharp; -using ICSharpCode.NRefactory.PatternMatching; - -namespace ICSharpCode.Decompiler.Ast.Transforms -{ - public class PushNegation: DepthFirstAstVisitor, IAstTransform - { - sealed class LiftedOperator { } - /// - /// Annotation for lifted operators that cannot be transformed by PushNegation - /// - public static readonly object LiftedOperatorAnnotation = new LiftedOperator(); - - public override object VisitUnaryOperatorExpression(UnaryOperatorExpression unary, object data) - { - // lifted operators can't be transformed - if (unary.Annotation() != null || unary.Expression.Annotation() != null) - return base.VisitUnaryOperatorExpression(unary, data); - - // Remove double negation - // !!a - if (unary.Operator == UnaryOperatorType.Not && - unary.Expression is UnaryOperatorExpression && - (unary.Expression as UnaryOperatorExpression).Operator == UnaryOperatorType.Not) - { - AstNode newNode = (unary.Expression as UnaryOperatorExpression).Expression; - unary.ReplaceWith(newNode); - return newNode.AcceptVisitor(this, data); - } - - // Push through binary operation - // !((a) op (b)) - BinaryOperatorExpression binaryOp = unary.Expression as BinaryOperatorExpression; - if (unary.Operator == UnaryOperatorType.Not && binaryOp != null) { - bool successful = true; - switch (binaryOp.Operator) { - case BinaryOperatorType.Equality: - binaryOp.Operator = BinaryOperatorType.InEquality; - break; - case BinaryOperatorType.InEquality: - binaryOp.Operator = BinaryOperatorType.Equality; - break; - case BinaryOperatorType.GreaterThan: // TODO: these are invalid for floats (stupid NaN) - binaryOp.Operator = BinaryOperatorType.LessThanOrEqual; - break; - case BinaryOperatorType.GreaterThanOrEqual: - binaryOp.Operator = BinaryOperatorType.LessThan; - break; - case BinaryOperatorType.LessThanOrEqual: - binaryOp.Operator = BinaryOperatorType.GreaterThan; - break; - case BinaryOperatorType.LessThan: - binaryOp.Operator = BinaryOperatorType.GreaterThanOrEqual; - break; - default: - successful = false; - break; - } - if (successful) { - unary.ReplaceWith(binaryOp); - return binaryOp.AcceptVisitor(this, data); - } - - successful = true; - switch (binaryOp.Operator) { - case BinaryOperatorType.ConditionalAnd: - binaryOp.Operator = BinaryOperatorType.ConditionalOr; - break; - case BinaryOperatorType.ConditionalOr: - binaryOp.Operator = BinaryOperatorType.ConditionalAnd; - break; - default: - successful = false; - break; - } - if (successful) { - binaryOp.Left.ReplaceWith(e => new UnaryOperatorExpression(UnaryOperatorType.Not, e)); - binaryOp.Right.ReplaceWith(e => new UnaryOperatorExpression(UnaryOperatorType.Not, e)); - unary.ReplaceWith(binaryOp); - return binaryOp.AcceptVisitor(this, data); - } - } - return base.VisitUnaryOperatorExpression(unary, data); - } - - readonly static AstNode asCastIsNullPattern = new BinaryOperatorExpression( - new AnyNode("expr").ToExpression().CastAs(new AnyNode("type")), - BinaryOperatorType.Equality, - new NullReferenceExpression() - ); - - readonly static AstNode asCastIsNotNullPattern = new BinaryOperatorExpression( - new AnyNode("expr").ToExpression().CastAs(new AnyNode("type")), - BinaryOperatorType.InEquality, - new NullReferenceExpression() - ); - - public override object VisitBinaryOperatorExpression(BinaryOperatorExpression binaryOperatorExpression, object data) - { - // lifted operators can't be transformed - if (binaryOperatorExpression.Annotation() != null) - return base.VisitBinaryOperatorExpression(binaryOperatorExpression, data); - - BinaryOperatorType op = binaryOperatorExpression.Operator; - bool? rightOperand = null; - if (binaryOperatorExpression.Right is PrimitiveExpression) - rightOperand = ((PrimitiveExpression)binaryOperatorExpression.Right).Value as bool?; - if (op == BinaryOperatorType.Equality && rightOperand == true || op == BinaryOperatorType.InEquality && rightOperand == false) { - // 'b == true' or 'b != false' is useless - binaryOperatorExpression.Left.AcceptVisitor(this, data); - binaryOperatorExpression.ReplaceWith(binaryOperatorExpression.Left); - return null; - } else if (op == BinaryOperatorType.Equality && rightOperand == false || op == BinaryOperatorType.InEquality && rightOperand == true) { - // 'b == false' or 'b != true' is a negation: - Expression left = binaryOperatorExpression.Left; - left.Remove(); - UnaryOperatorExpression uoe = new UnaryOperatorExpression(UnaryOperatorType.Not, left); - binaryOperatorExpression.ReplaceWith(uoe); - return uoe.AcceptVisitor(this, data); - } else { - bool negate = false; - Match m = asCastIsNotNullPattern.Match(binaryOperatorExpression); - if (!m.Success) { - m = asCastIsNullPattern.Match(binaryOperatorExpression); - negate = true; - } - if (m.Success) { - Expression expr = m.Get("expr").Single().Detach().IsType(m.Get("type").Single().Detach()); - if (negate) - expr = new UnaryOperatorExpression(UnaryOperatorType.Not, expr); - binaryOperatorExpression.ReplaceWith(expr); - return expr.AcceptVisitor(this, data); - } else { - return base.VisitBinaryOperatorExpression(binaryOperatorExpression, data); - } - } - } - void IAstTransform.Run(AstNode node) - { - node.AcceptVisitor(this, null); - } - } -} diff --git a/ICSharpCode.Decompiler/Ast/Transforms/ReplaceMethodCallsWithOperators.cs b/ICSharpCode.Decompiler/Ast/Transforms/ReplaceMethodCallsWithOperators.cs deleted file mode 100644 index 6a3f8f97..00000000 --- a/ICSharpCode.Decompiler/Ast/Transforms/ReplaceMethodCallsWithOperators.cs +++ /dev/null @@ -1,356 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using ICSharpCode.NRefactory.PatternMatching; -using Mono.Cecil; -using Ast = ICSharpCode.NRefactory.CSharp; -using ICSharpCode.NRefactory.CSharp; - -namespace ICSharpCode.Decompiler.Ast.Transforms -{ - /// - /// Replaces method calls with the appropriate operator expressions. - /// Also simplifies "x = x op y" into "x op= y" where possible. - /// - public class ReplaceMethodCallsWithOperators : DepthFirstAstVisitor, IAstTransform - { - static readonly MemberReferenceExpression typeHandleOnTypeOfPattern = new MemberReferenceExpression { - Target = new Choice { - new TypeOfExpression(new AnyNode()), - new UndocumentedExpression { UndocumentedExpressionType = UndocumentedExpressionType.RefType, Arguments = { new AnyNode() } } - }, - MemberName = "TypeHandle" - }; - - DecompilerContext context; - - public ReplaceMethodCallsWithOperators(DecompilerContext context) - { - this.context = context; - } - - public override object VisitInvocationExpression(InvocationExpression invocationExpression, object data) - { - base.VisitInvocationExpression(invocationExpression, data); - ProcessInvocationExpression(invocationExpression); - return null; - } - - internal static void ProcessInvocationExpression(InvocationExpression invocationExpression) - { - MethodReference methodRef = invocationExpression.Annotation(); - if (methodRef == null) - return; - var arguments = invocationExpression.Arguments.ToArray(); - - // Reduce "String.Concat(a, b)" to "a + b" - if (methodRef.Name == "Concat" && methodRef.DeclaringType.FullName == "System.String" && arguments.Length >= 2) - { - invocationExpression.Arguments.Clear(); // detach arguments from invocationExpression - Expression expr = arguments[0]; - for (int i = 1; i < arguments.Length; i++) { - expr = new BinaryOperatorExpression(expr, BinaryOperatorType.Add, arguments[i]); - } - invocationExpression.ReplaceWith(expr); - return; - } - - switch (methodRef.FullName) { - case "System.Type System.Type::GetTypeFromHandle(System.RuntimeTypeHandle)": - if (arguments.Length == 1) { - if (typeHandleOnTypeOfPattern.IsMatch(arguments[0])) { - invocationExpression.ReplaceWith(((MemberReferenceExpression)arguments[0]).Target); - return; - } - } - break; - case "System.Reflection.FieldInfo System.Reflection.FieldInfo::GetFieldFromHandle(System.RuntimeFieldHandle)": - if (arguments.Length == 1) { - MemberReferenceExpression mre = arguments[0] as MemberReferenceExpression; - if (mre != null && mre.MemberName == "FieldHandle" && mre.Target.Annotation() != null) { - invocationExpression.ReplaceWith(mre.Target); - return; - } - } - break; - case "System.Reflection.FieldInfo System.Reflection.FieldInfo::GetFieldFromHandle(System.RuntimeFieldHandle,System.RuntimeTypeHandle)": - if (arguments.Length == 2) { - MemberReferenceExpression mre1 = arguments[0] as MemberReferenceExpression; - MemberReferenceExpression mre2 = arguments[1] as MemberReferenceExpression; - if (mre1 != null && mre1.MemberName == "FieldHandle" && mre1.Target.Annotation() != null) { - if (mre2 != null && mre2.MemberName == "TypeHandle" && mre2.Target is TypeOfExpression) { - Expression oldArg = ((InvocationExpression)mre1.Target).Arguments.Single(); - FieldReference field = oldArg.Annotation(); - if (field != null) { - AstType declaringType = ((TypeOfExpression)mre2.Target).Type.Detach(); - oldArg.ReplaceWith(declaringType.Member(field.Name).WithAnnotation(field)); - invocationExpression.ReplaceWith(mre1.Target); - return; - } - } - } - } - break; - } - - BinaryOperatorType? bop = GetBinaryOperatorTypeFromMetadataName(methodRef.Name); - if (bop != null && arguments.Length == 2) { - invocationExpression.Arguments.Clear(); // detach arguments from invocationExpression - invocationExpression.ReplaceWith( - new BinaryOperatorExpression(arguments[0], bop.Value, arguments[1]).WithAnnotation(methodRef) - ); - return; - } - UnaryOperatorType? uop = GetUnaryOperatorTypeFromMetadataName(methodRef.Name); - if (uop != null && arguments.Length == 1) { - arguments[0].Remove(); // detach argument - invocationExpression.ReplaceWith( - new UnaryOperatorExpression(uop.Value, arguments[0]).WithAnnotation(methodRef) - ); - return; - } - if (methodRef.Name == "op_Explicit" && arguments.Length == 1) { - arguments[0].Remove(); // detach argument - invocationExpression.ReplaceWith( - arguments[0].CastTo(AstBuilder.ConvertType(methodRef.ReturnType, methodRef.MethodReturnType)) - .WithAnnotation(methodRef) - ); - return; - } - if (methodRef.Name == "op_Implicit" && arguments.Length == 1) { - invocationExpression.ReplaceWith(arguments[0]); - return; - } - if (methodRef.Name == "op_True" && arguments.Length == 1 && invocationExpression.Role == Roles.Condition) { - invocationExpression.ReplaceWith(arguments[0]); - return; - } - - return; - } - - static BinaryOperatorType? GetBinaryOperatorTypeFromMetadataName(string name) - { - switch (name) { - case "op_Addition": - return BinaryOperatorType.Add; - case "op_Subtraction": - return BinaryOperatorType.Subtract; - case "op_Multiply": - return BinaryOperatorType.Multiply; - case "op_Division": - return BinaryOperatorType.Divide; - case "op_Modulus": - return BinaryOperatorType.Modulus; - case "op_BitwiseAnd": - return BinaryOperatorType.BitwiseAnd; - case "op_BitwiseOr": - return BinaryOperatorType.BitwiseOr; - case "op_ExclusiveOr": - return BinaryOperatorType.ExclusiveOr; - case "op_LeftShift": - return BinaryOperatorType.ShiftLeft; - case "op_RightShift": - return BinaryOperatorType.ShiftRight; - case "op_Equality": - return BinaryOperatorType.Equality; - case "op_Inequality": - return BinaryOperatorType.InEquality; - case "op_LessThan": - return BinaryOperatorType.LessThan; - case "op_LessThanOrEqual": - return BinaryOperatorType.LessThanOrEqual; - case "op_GreaterThan": - return BinaryOperatorType.GreaterThan; - case "op_GreaterThanOrEqual": - return BinaryOperatorType.GreaterThanOrEqual; - default: - return null; - } - } - - static UnaryOperatorType? GetUnaryOperatorTypeFromMetadataName(string name) - { - switch (name) { - case "op_LogicalNot": - return UnaryOperatorType.Not; - case "op_OnesComplement": - return UnaryOperatorType.BitNot; - case "op_UnaryNegation": - return UnaryOperatorType.Minus; - case "op_UnaryPlus": - return UnaryOperatorType.Plus; - case "op_Increment": - return UnaryOperatorType.Increment; - case "op_Decrement": - return UnaryOperatorType.Decrement; - default: - return null; - } - } - - /// - /// This annotation is used to convert a compound assignment "a += 2;" or increment operator "a++;" - /// back to the original "a = a + 2;". This is sometimes necessary when the checked/unchecked semantics - /// cannot be guaranteed otherwise (see CheckedUnchecked.ForWithCheckedInitializerAndUncheckedIterator test) - /// - public class RestoreOriginalAssignOperatorAnnotation - { - readonly BinaryOperatorExpression binaryOperatorExpression; - - public RestoreOriginalAssignOperatorAnnotation(BinaryOperatorExpression binaryOperatorExpression) - { - this.binaryOperatorExpression = binaryOperatorExpression; - } - - public AssignmentExpression Restore(Expression expression) - { - expression.RemoveAnnotations(); - AssignmentExpression assign = expression as AssignmentExpression; - if (assign == null) { - UnaryOperatorExpression uoe = (UnaryOperatorExpression)expression; - assign = new AssignmentExpression(uoe.Expression.Detach(), new PrimitiveExpression(1)); - } else { - assign.Operator = AssignmentOperatorType.Assign; - } - binaryOperatorExpression.Right = assign.Right.Detach(); - assign.Right = binaryOperatorExpression; - return assign; - } - } - - public override object VisitAssignmentExpression(AssignmentExpression assignment, object data) - { - base.VisitAssignmentExpression(assignment, data); - // Combine "x = x op y" into "x op= y" - BinaryOperatorExpression binary = assignment.Right as BinaryOperatorExpression; - if (binary != null && assignment.Operator == AssignmentOperatorType.Assign) { - if (CanConvertToCompoundAssignment(assignment.Left) && assignment.Left.IsMatch(binary.Left)) { - assignment.Operator = GetAssignmentOperatorForBinaryOperator(binary.Operator); - if (assignment.Operator != AssignmentOperatorType.Assign) { - // If we found a shorter operator, get rid of the BinaryOperatorExpression: - assignment.CopyAnnotationsFrom(binary); - assignment.Right = binary.Right; - assignment.AddAnnotation(new RestoreOriginalAssignOperatorAnnotation(binary)); - } - } - } - if (context.Settings.IntroduceIncrementAndDecrement && (assignment.Operator == AssignmentOperatorType.Add || assignment.Operator == AssignmentOperatorType.Subtract)) { - // detect increment/decrement - if (assignment.Right.IsMatch(new PrimitiveExpression(1))) { - // only if it's not a custom operator - if (assignment.Annotation() == null) { - UnaryOperatorType type; - // When the parent is an expression statement, pre- or post-increment doesn't matter; - // so we can pick post-increment which is more commonly used (for (int i = 0; i < x; i++)) - if (assignment.Parent is ExpressionStatement) - type = (assignment.Operator == AssignmentOperatorType.Add) ? UnaryOperatorType.PostIncrement : UnaryOperatorType.PostDecrement; - else - type = (assignment.Operator == AssignmentOperatorType.Add) ? UnaryOperatorType.Increment : UnaryOperatorType.Decrement; - assignment.ReplaceWith(new UnaryOperatorExpression(type, assignment.Left.Detach()).CopyAnnotationsFrom(assignment)); - } - } - } - return null; - } - - public static AssignmentOperatorType GetAssignmentOperatorForBinaryOperator(BinaryOperatorType bop) - { - switch (bop) { - case BinaryOperatorType.Add: - return AssignmentOperatorType.Add; - case BinaryOperatorType.Subtract: - return AssignmentOperatorType.Subtract; - case BinaryOperatorType.Multiply: - return AssignmentOperatorType.Multiply; - case BinaryOperatorType.Divide: - return AssignmentOperatorType.Divide; - case BinaryOperatorType.Modulus: - return AssignmentOperatorType.Modulus; - case BinaryOperatorType.ShiftLeft: - return AssignmentOperatorType.ShiftLeft; - case BinaryOperatorType.ShiftRight: - return AssignmentOperatorType.ShiftRight; - case BinaryOperatorType.BitwiseAnd: - return AssignmentOperatorType.BitwiseAnd; - case BinaryOperatorType.BitwiseOr: - return AssignmentOperatorType.BitwiseOr; - case BinaryOperatorType.ExclusiveOr: - return AssignmentOperatorType.ExclusiveOr; - default: - return AssignmentOperatorType.Assign; - } - } - - static bool CanConvertToCompoundAssignment(Expression left) - { - MemberReferenceExpression mre = left as MemberReferenceExpression; - if (mre != null) - return IsWithoutSideEffects(mre.Target); - IndexerExpression ie = left as IndexerExpression; - if (ie != null) - return IsWithoutSideEffects(ie.Target) && ie.Arguments.All(IsWithoutSideEffects); - UnaryOperatorExpression uoe = left as UnaryOperatorExpression; - if (uoe != null && uoe.Operator == UnaryOperatorType.Dereference) - return IsWithoutSideEffects(uoe.Expression); - return IsWithoutSideEffects(left); - } - - static bool IsWithoutSideEffects(Expression left) - { - return left is ThisReferenceExpression || left is IdentifierExpression || left is TypeReferenceExpression || left is BaseReferenceExpression; - } - - static readonly Expression getMethodOrConstructorFromHandlePattern = - new TypePattern(typeof(MethodBase)).ToType().Invoke( - "GetMethodFromHandle", - new NamedNode("ldtokenNode", new LdTokenPattern("method")).ToExpression().Member("MethodHandle"), - new OptionalNode(new TypeOfExpression(new AnyNode("declaringType")).Member("TypeHandle")) - ).CastTo(new Choice { - new TypePattern(typeof(MethodInfo)), - new TypePattern(typeof(ConstructorInfo)) - }); - - public override object VisitCastExpression(CastExpression castExpression, object data) - { - base.VisitCastExpression(castExpression, data); - // Handle methodof - Match m = getMethodOrConstructorFromHandlePattern.Match(castExpression); - if (m.Success) { - MethodReference method = m.Get("method").Single().Annotation(); - if (m.Has("declaringType")) { - Expression newNode = m.Get("declaringType").Single().Detach().Member(method.Name); - newNode = newNode.Invoke(method.Parameters.Select(p => new TypeReferenceExpression(AstBuilder.ConvertType(p.ParameterType, p)))); - newNode.AddAnnotation(method); - m.Get("method").Single().ReplaceWith(newNode); - } - castExpression.ReplaceWith(m.Get("ldtokenNode").Single()); - } - return null; - } - - void IAstTransform.Run(AstNode node) - { - node.AcceptVisitor(this, null); - } - } -} diff --git a/ICSharpCode.Decompiler/Ast/Transforms/TransformationPipeline.cs b/ICSharpCode.Decompiler/Ast/Transforms/TransformationPipeline.cs deleted file mode 100644 index 3091a109..00000000 --- a/ICSharpCode.Decompiler/Ast/Transforms/TransformationPipeline.cs +++ /dev/null @@ -1,65 +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.Ast.Transforms -{ - public interface IAstTransform - { - void Run(AstNode compilationUnit); - } - - public static class TransformationPipeline - { - public static IAstTransform[] CreatePipeline(DecompilerContext context) - { - return new IAstTransform[] { - new PushNegation(), - new DelegateConstruction(context), - new PatternStatementTransform(context), - new ReplaceMethodCallsWithOperators(context), - 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 static void RunTransformationsUntil(AstNode node, Predicate abortCondition, DecompilerContext context) - { - if (node == null) - return; - - foreach (var transform in CreatePipeline(context)) { - context.CancellationToken.ThrowIfCancellationRequested(); - if (abortCondition != null && abortCondition(transform)) - return; - transform.Run(node); - } - } - } -} diff --git a/ICSharpCode.Decompiler/Ast/TypesHierarchyHelpers.cs b/ICSharpCode.Decompiler/Ast/TypesHierarchyHelpers.cs deleted file mode 100644 index 19e7ff24..00000000 --- a/ICSharpCode.Decompiler/Ast/TypesHierarchyHelpers.cs +++ /dev/null @@ -1,536 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using System.Text; -using Mono.Cecil; - -namespace ICSharpCode.Decompiler.Ast -{ - public static class TypesHierarchyHelpers - { - public static bool IsBaseType(TypeDefinition baseType, TypeDefinition derivedType, bool resolveTypeArguments) - { - if (resolveTypeArguments) - return BaseTypes(derivedType).Any(t => t.Item == baseType); - else { - var comparableBaseType = baseType.Resolve(); - if (comparableBaseType == null) - return false; - while (derivedType.BaseType != null) { - var resolvedBaseType = derivedType.BaseType.Resolve(); - if (resolvedBaseType == null) - return false; - if (comparableBaseType == resolvedBaseType) - return true; - derivedType = resolvedBaseType; - } - return false; - } - } - - /// - /// Determines whether one method overrides or hides another method. - /// - /// The method declared in a base type. - /// The method declared in a derived type. - /// true if hides or overrides , - /// otherwise false. - public static bool IsBaseMethod(MethodDefinition parentMethod, MethodDefinition childMethod) - { - if (parentMethod == null) - throw new ArgumentNullException("parentMethod"); - if (childMethod == null) - throw new ArgumentNullException("childMethod"); - - if (parentMethod.Name != childMethod.Name) - return false; - - if (parentMethod.HasParameters || childMethod.HasParameters) - if (!parentMethod.HasParameters || !childMethod.HasParameters || parentMethod.Parameters.Count != childMethod.Parameters.Count) - return false; - - return FindBaseMethods(childMethod).Any(m => m == parentMethod);// || (parentMethod.HasGenericParameters && m.); - } - - /// - /// Determines whether a property overrides or hides another property. - /// - /// The property declared in a base type. - /// The property declared in a derived type. - /// true if the hides or overrides , - /// otherwise false. - public static bool IsBaseProperty(PropertyDefinition parentProperty, PropertyDefinition childProperty) - { - if (parentProperty == null) - throw new ArgumentNullException("parentProperty"); - if (childProperty == null) - throw new ArgumentNullException("childProperty"); - - if (parentProperty.Name != childProperty.Name) - return false; - - if (parentProperty.HasParameters || childProperty.HasParameters) - if (!parentProperty.HasParameters || !childProperty.HasParameters || parentProperty.Parameters.Count != childProperty.Parameters.Count) - return false; - - return FindBaseProperties(childProperty).Any(m => m == parentProperty); - } - - public static bool IsBaseEvent(EventDefinition parentEvent, EventDefinition childEvent) - { - if (parentEvent.Name != childEvent.Name) - return false; - - return FindBaseEvents(childEvent).Any(m => m == parentEvent); - } - - /// - /// Finds all methods from base types overridden or hidden by the specified method. - /// - /// The method which overrides or hides methods from base types. - /// Methods overriden or hidden by the specified method. - public static IEnumerable FindBaseMethods(MethodDefinition method) - { - if (method == null) - throw new ArgumentNullException("method"); - - var typeContext = CreateGenericContext(method.DeclaringType); - var gMethod = typeContext.ApplyTo(method); - - foreach (var baseType in BaseTypes(method.DeclaringType)) - foreach (var baseMethod in baseType.Item.Methods) - if (MatchMethod(baseType.ApplyTo(baseMethod), gMethod) && IsVisibleFromDerived(baseMethod, method.DeclaringType)) { - yield return baseMethod; - if (baseMethod.IsNewSlot == baseMethod.IsVirtual) - yield break; - } - } - - /// - /// Finds all properties from base types overridden or hidden by the specified property. - /// - /// The property which overrides or hides properties from base types. - /// Properties overriden or hidden by the specified property. - public static IEnumerable FindBaseProperties(PropertyDefinition property) - { - if (property == null) - throw new ArgumentNullException("property"); - - if ((property.GetMethod ?? property.SetMethod).HasOverrides) - yield break; - - var typeContext = CreateGenericContext(property.DeclaringType); - var gProperty = typeContext.ApplyTo(property); - bool isIndexer = property.IsIndexer(); - - foreach (var baseType in BaseTypes(property.DeclaringType)) - foreach (var baseProperty in baseType.Item.Properties) - if (MatchProperty(baseType.ApplyTo(baseProperty), gProperty) - && IsVisibleFromDerived(baseProperty, property.DeclaringType)) { - if (isIndexer != baseProperty.IsIndexer()) - continue; - yield return baseProperty; - var anyPropertyAccessor = baseProperty.GetMethod ?? baseProperty.SetMethod; - if (anyPropertyAccessor.IsNewSlot == anyPropertyAccessor.IsVirtual) - yield break; - } - } - - public static IEnumerable FindBaseEvents(EventDefinition eventDef) - { - if (eventDef == null) - throw new ArgumentNullException("eventDef"); - - var typeContext = CreateGenericContext(eventDef.DeclaringType); - var gEvent = typeContext.ApplyTo(eventDef); - - foreach (var baseType in BaseTypes(eventDef.DeclaringType)) - foreach (var baseEvent in baseType.Item.Events) - if (MatchEvent(baseType.ApplyTo(baseEvent), gEvent) && IsVisibleFromDerived(baseEvent, eventDef.DeclaringType)) { - yield return baseEvent; - var anyEventAccessor = baseEvent.AddMethod ?? baseEvent.RemoveMethod; - if (anyEventAccessor.IsNewSlot == anyEventAccessor.IsVirtual) - yield break; - } - - } - - /// - /// Determinates whether member of the base type is visible from a derived type. - /// - /// The member which visibility is checked. - /// The derived type. - /// true if the member is visible from derived type, othewise false. - public static bool IsVisibleFromDerived(IMemberDefinition baseMember, TypeDefinition derivedType) - { - if (baseMember == null) - throw new ArgumentNullException("baseMember"); - if (derivedType == null) - throw new ArgumentNullException("derivedType"); - - MethodAttributes attrs = GetAccessAttributes(baseMember) & MethodAttributes.MemberAccessMask; - if (attrs == MethodAttributes.Private) - return false; - - if (baseMember.DeclaringType.Module == derivedType.Module) - return true; - - if (attrs == MethodAttributes.Assembly || attrs == MethodAttributes.FamANDAssem) { - var derivedTypeAsm = derivedType.Module.Assembly; - var asm = baseMember.DeclaringType.Module.Assembly; - - if (asm.HasCustomAttributes) { - var attributes = asm.CustomAttributes - .Where(attr => attr.AttributeType.FullName == "System.Runtime.CompilerServices.InternalsVisibleToAttribute"); - foreach (var attribute in attributes) { - string assemblyName = attribute.ConstructorArguments[0].Value as string; - assemblyName = assemblyName.Split(',')[0]; // strip off any public key info - if (assemblyName == derivedTypeAsm.Name.Name) - return true; - } - } - - return false; - } - - return true; - } - - static MethodAttributes GetAccessAttributes(IMemberDefinition member) - { - var fld = member as FieldDefinition; - if (fld != null) - return (MethodAttributes)fld.Attributes; - - var method = member as MethodDefinition; - if (method != null) - return method.Attributes; - - var prop = member as PropertyDefinition; - if (prop != null) { - return (prop.GetMethod ?? prop.SetMethod).Attributes; - } - - var evnt = member as EventDefinition; - if (evnt != null) { - return (evnt.AddMethod ?? evnt.RemoveMethod).Attributes; - } - - var nestedType = member as TypeDefinition; - if (nestedType != null) { - if (nestedType.IsNestedPrivate) - return MethodAttributes.Private; - if (nestedType.IsNestedAssembly || nestedType.IsNestedFamilyAndAssembly) - return MethodAttributes.Assembly; - return MethodAttributes.Public; - } - - throw new NotSupportedException(); - } - - static bool MatchMethod(GenericContext candidate, GenericContext method) - { - var mCandidate = candidate.Item; - var mMethod = method.Item; - if (mCandidate.Name != mMethod.Name) - return false; - - if (mCandidate.HasOverrides) - return false; - - if (mCandidate.IsSpecialName != method.Item.IsSpecialName) - return false; - - if (mCandidate.HasGenericParameters || mMethod.HasGenericParameters) { - if (!mCandidate.HasGenericParameters || !mMethod.HasGenericParameters || mCandidate.GenericParameters.Count != mMethod.GenericParameters.Count) - return false; - } - - if (mCandidate.HasParameters || mMethod.HasParameters) { - if (!mCandidate.HasParameters || !mMethod.HasParameters || mCandidate.Parameters.Count != mMethod.Parameters.Count) - return false; - - for (int index = 0; index < mCandidate.Parameters.Count; index++) { - if (!MatchParameters(candidate.ApplyTo(mCandidate.Parameters[index]), method.ApplyTo(mMethod.Parameters[index]))) - return false; - } - } - - return true; - } - - public static bool MatchInterfaceMethod(MethodDefinition candidate, MethodDefinition method, TypeReference interfaceContextType) - { - var candidateContext = CreateGenericContext(candidate.DeclaringType); - var gCandidate = candidateContext.ApplyTo(candidate); - - if (interfaceContextType is GenericInstanceType) { - var methodContext = new GenericContext(interfaceContextType.Resolve(), ((GenericInstanceType)interfaceContextType).GenericArguments); - var gMethod = methodContext.ApplyTo(method); - return MatchMethod(gCandidate, gMethod); - } else { - var methodContext = CreateGenericContext(interfaceContextType.Resolve()); - var gMethod = candidateContext.ApplyTo(method); - return MatchMethod(gCandidate, gMethod); - } - } - - static bool MatchProperty(GenericContext candidate, GenericContext property) - { - var mCandidate = candidate.Item; - var mProperty = property.Item; - if (mCandidate.Name != mProperty.Name) - return false; - - if ((mCandidate.GetMethod ?? mCandidate.SetMethod).HasOverrides) - return false; - - if (mCandidate.HasParameters || mProperty.HasParameters) { - if (!mCandidate.HasParameters || !mProperty.HasParameters || mCandidate.Parameters.Count != mProperty.Parameters.Count) - return false; - - for (int index = 0; index < mCandidate.Parameters.Count; index++) { - if (!MatchParameters(candidate.ApplyTo(mCandidate.Parameters[index]), property.ApplyTo(mProperty.Parameters[index]))) - return false; - } - } - - return true; - } - - static bool MatchEvent(GenericContext candidate, GenericContext ev) - { - var mCandidate = candidate.Item; - var mEvent = ev.Item; - if (mCandidate.Name != mEvent.Name) - return false; - - if ((mCandidate.AddMethod ?? mCandidate.RemoveMethod).HasOverrides) - return false; - - if (!IsSameType(candidate.ResolveWithContext(mCandidate.EventType), ev.ResolveWithContext(mEvent.EventType))) - return false; - - return true; - } - - static bool MatchParameters(GenericContext baseParameterType, GenericContext parameterType) - { - if (baseParameterType.Item.IsIn != parameterType.Item.IsIn || - baseParameterType.Item.IsOut != parameterType.Item.IsOut) - return false; - var baseParam = baseParameterType.ResolveWithContext(baseParameterType.Item.ParameterType); - var param = parameterType.ResolveWithContext(parameterType.Item.ParameterType); - return IsSameType(baseParam, param); - } - - static bool IsSameType(TypeReference tr1, TypeReference tr2) - { - if (tr1 == tr2) - return true; - if (tr1 == null || tr2 == null) - return false; - - if (tr1.GetType() != tr2.GetType()) - return false; - - if (tr1.Name == tr2.Name && tr1.FullName == tr2.FullName) - return true; - - return false; - } - - static IEnumerable> BaseTypes(TypeDefinition type) - { - return BaseTypes(CreateGenericContext(type)); - } - - static IEnumerable> BaseTypes(GenericContext type) - { - while (type.Item.BaseType != null) { - var baseType = type.Item.BaseType; - var genericBaseType = baseType as GenericInstanceType; - if (genericBaseType != null) { -#pragma warning disable 618 - type = new GenericContext(genericBaseType.ResolveOrThrow(), -#pragma warning restore 618 - genericBaseType.GenericArguments.Select(t => type.ResolveWithContext(t))); - } else -#pragma warning disable 618 - type = new GenericContext(baseType.ResolveOrThrow()); -#pragma warning restore 618 - yield return type; - } - } - - static GenericContext CreateGenericContext(TypeDefinition type) - { - return type.HasGenericParameters - ? new GenericContext(type, type.GenericParameters) - : new GenericContext(type); - } - - struct GenericContext where T : class - { - static readonly ReadOnlyCollection Empty = new ReadOnlyCollection(new List()); - - static readonly GenericParameter UnresolvedGenericTypeParameter = - new DummyGenericParameterProvider(false).DummyParameter; - - static readonly GenericParameter UnresolvedGenericMethodParameter = - new DummyGenericParameterProvider(true).DummyParameter; - - public readonly T Item; - public readonly ReadOnlyCollection TypeArguments; - - public GenericContext(T item) - { - if (item == null) - throw new ArgumentNullException("item"); - - Item = item; - TypeArguments = Empty; - } - - public GenericContext(T item, IEnumerable typeArguments) - { - if (item == null) - throw new ArgumentNullException("item"); - - Item = item; - var list = new List(); - foreach (var arg in typeArguments) { - var resolved = arg != null ? arg.Resolve() : arg; - list.Add(resolved != null ? resolved : arg); - } - TypeArguments = new ReadOnlyCollection(list); - } - - GenericContext(T item, ReadOnlyCollection typeArguments) - { - Item = item; - TypeArguments = typeArguments; - } - - public TypeReference ResolveWithContext(TypeReference type) - { - var genericParameter = type as GenericParameter; - if (genericParameter != null) - if (genericParameter.Owner.GenericParameterType == GenericParameterType.Type) - return TypeArguments[genericParameter.Position]; - else - return genericParameter.Owner.GenericParameterType == GenericParameterType.Type - ? UnresolvedGenericTypeParameter : UnresolvedGenericMethodParameter; - var typeSpecification = type as TypeSpecification; - if (typeSpecification != null) { - var resolvedElementType = ResolveWithContext(typeSpecification.ElementType); - return ReplaceElementType(typeSpecification, resolvedElementType); - } -#pragma warning disable 618 - return type.ResolveOrThrow(); -#pragma warning restore 618 - } - - TypeReference ReplaceElementType(TypeSpecification ts, TypeReference newElementType) - { - var arrayType = ts as ArrayType; - if (arrayType != null) { - if (newElementType == arrayType.ElementType) - return arrayType; - var newArrayType = new ArrayType(newElementType, arrayType.Rank); - for (int dimension = 0; dimension < arrayType.Rank; dimension++) - newArrayType.Dimensions[dimension] = arrayType.Dimensions[dimension]; - return newArrayType; - } - var byReferenceType = ts as ByReferenceType; - if (byReferenceType != null) { - return new ByReferenceType(newElementType); - } - // TODO: should we throw an exception instead calling Resolve method? -#pragma warning disable 618 - return ts.ResolveOrThrow(); -#pragma warning restore 618 - } - - public GenericContext ApplyTo(T2 item) where T2 : class - { - return new GenericContext(item, TypeArguments); - } - - class DummyGenericParameterProvider : IGenericParameterProvider - { - readonly GenericParameterType type; - readonly Mono.Collections.Generic.Collection parameters; - - public DummyGenericParameterProvider(bool methodTypeParameter) - { - type = methodTypeParameter ? GenericParameterType.Method : - GenericParameterType.Type; - parameters = new Mono.Collections.Generic.Collection(1); - parameters.Add(new GenericParameter(this)); - } - - public GenericParameter DummyParameter - { - get { return parameters[0]; } - } - - bool IGenericParameterProvider.HasGenericParameters - { - get { throw new NotImplementedException(); } - } - - bool IGenericParameterProvider.IsDefinition - { - get { throw new NotImplementedException(); } - } - - ModuleDefinition IGenericParameterProvider.Module - { - get { throw new NotImplementedException(); } - } - - Mono.Collections.Generic.Collection IGenericParameterProvider.GenericParameters - { - get { return parameters; } - } - - GenericParameterType IGenericParameterProvider.GenericParameterType - { - get { return type; } - } - - MetadataToken IMetadataTokenProvider.MetadataToken - { - get - { - throw new NotImplementedException(); - } - set - { - throw new NotImplementedException(); - } - } - } - } - } -} diff --git a/ICSharpCode.Decompiler/CecilExtensions.cs b/ICSharpCode.Decompiler/CecilExtensions.cs deleted file mode 100644 index 0c7cb1e4..00000000 --- a/ICSharpCode.Decompiler/CecilExtensions.cs +++ /dev/null @@ -1,374 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Linq; -using Mono.Cecil; -using Mono.Cecil.Cil; - -namespace ICSharpCode.Decompiler -{ - /// - /// Cecil helper methods. - /// - public static class CecilExtensions - { - #region GetPushDelta / GetPopDelta - public static int GetPushDelta(this Instruction instruction) - { - OpCode code = instruction.OpCode; - switch (code.StackBehaviourPush) { - case StackBehaviour.Push0: - return 0; - - case StackBehaviour.Push1: - case StackBehaviour.Pushi: - case StackBehaviour.Pushi8: - case StackBehaviour.Pushr4: - case StackBehaviour.Pushr8: - case StackBehaviour.Pushref: - return 1; - - case StackBehaviour.Push1_push1: - return 2; - - case StackBehaviour.Varpush: - if (code.FlowControl != FlowControl.Call) - break; - - IMethodSignature method = (IMethodSignature) instruction.Operand; - return IsVoid (method.ReturnType) ? 0 : 1; - } - - throw new NotSupportedException (); - } - - public static int? GetPopDelta(this Instruction instruction, MethodDefinition methodDef) - { - OpCode code = instruction.OpCode; - switch (code.StackBehaviourPop) { - case StackBehaviour.Pop0: - return 0; - case StackBehaviour.Popi: - case StackBehaviour.Popref: - case StackBehaviour.Pop1: - return 1; - - case StackBehaviour.Pop1_pop1: - case StackBehaviour.Popi_pop1: - case StackBehaviour.Popi_popi: - case StackBehaviour.Popi_popi8: - case StackBehaviour.Popi_popr4: - case StackBehaviour.Popi_popr8: - case StackBehaviour.Popref_pop1: - case StackBehaviour.Popref_popi: - return 2; - - case StackBehaviour.Popi_popi_popi: - case StackBehaviour.Popref_popi_popi: - case StackBehaviour.Popref_popi_popi8: - case StackBehaviour.Popref_popi_popr4: - case StackBehaviour.Popref_popi_popr8: - case StackBehaviour.Popref_popi_popref: - return 3; - - case StackBehaviour.PopAll: - return null; - - case StackBehaviour.Varpop: - if (code == OpCodes.Ret) - return methodDef.ReturnType.IsVoid() ? 0 : 1; - - if (code.FlowControl != FlowControl.Call) - break; - - IMethodSignature method = (IMethodSignature) instruction.Operand; - int count = method.HasParameters ? method.Parameters.Count : 0; - if (method.HasThis && code != OpCodes.Newobj) - ++count; - if (code == OpCodes.Calli) - ++count; // calli takes a function pointer in additional to the normal args - - return count; - } - - throw new NotSupportedException (); - } - - public static bool IsVoid(this TypeReference type) - { - while (type is OptionalModifierType || type is RequiredModifierType) - type = ((TypeSpecification)type).ElementType; - return type.MetadataType == MetadataType.Void; - } - - public static bool IsValueTypeOrVoid(this TypeReference type) - { - while (type is OptionalModifierType || type is RequiredModifierType) - type = ((TypeSpecification)type).ElementType; - if (type is ArrayType) - return false; - return type.IsValueType || type.IsVoid(); - } - - /// - /// checks if the given TypeReference is one of the following types: - /// [sbyte, short, int, long, IntPtr] - /// - public static bool IsSignedIntegralType(this TypeReference type) - { - return type.MetadataType == MetadataType.SByte || - type.MetadataType == MetadataType.Int16 || - type.MetadataType == MetadataType.Int32 || - type.MetadataType == MetadataType.Int64 || - type.MetadataType == MetadataType.IntPtr; - } - - /// - /// checks if the given value is a numeric zero-value. - /// NOTE that this only works for types: [sbyte, short, int, long, IntPtr, byte, ushort, uint, ulong, float, double and decimal] - /// - public static bool IsZero(this object value) - { - return value.Equals((sbyte)0) || - value.Equals((short)0) || - value.Equals(0) || - value.Equals(0L) || - value.Equals(IntPtr.Zero) || - value.Equals((byte)0) || - value.Equals((ushort)0) || - value.Equals(0u) || - value.Equals(0UL) || - value.Equals(0.0f) || - value.Equals(0.0) || - value.Equals((decimal)0); - - } - - #endregion - - /// - /// Gets the (exclusive) end offset of this instruction. - /// - public static int GetEndOffset(this Instruction inst) - { - if (inst == null) - throw new ArgumentNullException("inst"); - return inst.Offset + inst.GetSize(); - } - - public static string OffsetToString(int offset) - { - return string.Format("IL_{0:x4}", offset); - } - - public static HashSet GetAccessorMethods(this TypeDefinition type) - { - HashSet accessorMethods = new HashSet(); - foreach (var property in type.Properties) { - accessorMethods.Add(property.GetMethod); - accessorMethods.Add(property.SetMethod); - if (property.HasOtherMethods) { - foreach (var m in property.OtherMethods) - accessorMethods.Add(m); - } - } - foreach (EventDefinition ev in type.Events) { - accessorMethods.Add(ev.AddMethod); - accessorMethods.Add(ev.RemoveMethod); - accessorMethods.Add(ev.InvokeMethod); - if (ev.HasOtherMethods) { - foreach (var m in ev.OtherMethods) - accessorMethods.Add(m); - } - } - return accessorMethods; - } - - public static TypeDefinition ResolveWithinSameModule(this TypeReference type) - { - if (type != null && type.GetElementType().Module == type.Module) - return type.Resolve(); - else - return null; - } - - public static FieldDefinition ResolveWithinSameModule(this FieldReference field) - { - if (field != null && field.DeclaringType.GetElementType().Module == field.Module) - return field.Resolve(); - else - return null; - } - - public static MethodDefinition ResolveWithinSameModule(this MethodReference method) - { - if (method != null && method.DeclaringType.GetElementType().Module == method.Module) - return method.Resolve(); - else - return null; - } - - [Obsolete("throwing exceptions is considered a bug")] - public static TypeDefinition ResolveOrThrow(this TypeReference typeReference) - { - var resolved = typeReference.Resolve(); - if (resolved == null) - throw new ReferenceResolvingException(); - return resolved; - } - - public static bool IsCompilerGenerated(this ICustomAttributeProvider provider) - { - if (provider != null && provider.HasCustomAttributes) { - foreach (CustomAttribute a in provider.CustomAttributes) { - if (a.AttributeType.FullName == "System.Runtime.CompilerServices.CompilerGeneratedAttribute") - return true; - } - } - return false; - } - - public static bool IsCompilerGeneratedOrIsInCompilerGeneratedClass(this IMemberDefinition member) - { - if (member == null) - return false; - if (member.IsCompilerGenerated()) - return true; - return IsCompilerGeneratedOrIsInCompilerGeneratedClass(member.DeclaringType); - } - - public static TypeReference GetEnumUnderlyingType(this TypeDefinition type) - { - if (!type.IsEnum) - throw new ArgumentException("Type must be an enum", "type"); - - var fields = type.Fields; - - for (int i = 0; i < fields.Count; i++) - { - var field = fields[i]; - if (!field.IsStatic) - return field.FieldType; - } - - throw new NotSupportedException(); - } - - public static bool IsAnonymousType(this TypeReference type) - { - if (type == null) - return false; - if (string.IsNullOrEmpty(type.Namespace) && type.HasGeneratedName() && (type.Name.Contains("AnonType") || type.Name.Contains("AnonymousType"))) { - TypeDefinition td = type.Resolve(); - return td != null && td.IsCompilerGenerated(); - } - return false; - } - - public static bool HasGeneratedName(this MemberReference member) - { - return member.Name.StartsWith("<", StringComparison.Ordinal); - } - - public static bool ContainsAnonymousType(this TypeReference type) - { - GenericInstanceType git = type as GenericInstanceType; - if (git != null) { - if (IsAnonymousType(git)) - return true; - for (int i = 0; i < git.GenericArguments.Count; i++) { - if (git.GenericArguments[i].ContainsAnonymousType()) - return true; - } - return false; - } - TypeSpecification typeSpec = type as TypeSpecification; - if (typeSpec != null) - return typeSpec.ElementType.ContainsAnonymousType(); - else - return false; - } - - public static string GetDefaultMemberName(this TypeDefinition type) - { - CustomAttribute attr; - return type.GetDefaultMemberName(out attr); - } - - public static string GetDefaultMemberName(this TypeDefinition type, out CustomAttribute defaultMemberAttribute) - { - if (type.HasCustomAttributes) - foreach (CustomAttribute ca in type.CustomAttributes) - if (ca.Constructor.DeclaringType.Name == "DefaultMemberAttribute" && ca.Constructor.DeclaringType.Namespace == "System.Reflection" - && ca.Constructor.FullName == @"System.Void System.Reflection.DefaultMemberAttribute::.ctor(System.String)") { - defaultMemberAttribute = ca; - return ca.ConstructorArguments[0].Value as string; - } - defaultMemberAttribute = null; - return null; - } - - public static bool IsIndexer(this PropertyDefinition property) - { - CustomAttribute attr; - return property.IsIndexer(out attr); - } - - public static bool IsIndexer(this PropertyDefinition property, out CustomAttribute defaultMemberAttribute) - { - defaultMemberAttribute = null; - if (property.HasParameters) { - var accessor = property.GetMethod ?? property.SetMethod; - PropertyDefinition basePropDef = property; - if (accessor.HasOverrides) { - // if the property is explicitly implementing an interface, look up the property in the interface: - MethodDefinition baseAccessor = accessor.Overrides.First().Resolve(); - if (baseAccessor != null) { - foreach (PropertyDefinition baseProp in baseAccessor.DeclaringType.Properties) { - if (baseProp.GetMethod == baseAccessor || baseProp.SetMethod == baseAccessor) { - basePropDef = baseProp; - break; - } - } - } else - return false; - } - CustomAttribute attr; - var defaultMemberName = basePropDef.DeclaringType.GetDefaultMemberName(out attr); - if (defaultMemberName == basePropDef.Name) { - defaultMemberAttribute = attr; - return true; - } - } - return false; - } - - public static bool IsDelegate(this TypeDefinition type) - { - if (type.BaseType != null && type.BaseType.Namespace == "System") { - if (type.BaseType.Name == "MulticastDelegate") - return true; - if (type.BaseType.Name == "Delegate" && type.Name != "MulticastDelegate") - return true; - } - return false; - } - } -} diff --git a/ICSharpCode.Decompiler/CodeMappings.cs b/ICSharpCode.Decompiler/CodeMappings.cs deleted file mode 100644 index ee62f76c..00000000 --- a/ICSharpCode.Decompiler/CodeMappings.cs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Linq; -using ICSharpCode.Decompiler.ILAst; -using ICSharpCode.NRefactory; -using Mono.Cecil; - -namespace ICSharpCode.Decompiler -{ - /// Maps method's source code to IL - public class MethodDebugSymbols - { - public MethodDefinition CecilMethod { get; set; } - public List LocalVariables { get; set; } - public List SequencePoints { get; set; } - public TextLocation StartLocation { get; set; } - public TextLocation EndLocation { get; set; } - - public MethodDebugSymbols(MethodDefinition methodDef) - { - CecilMethod = methodDef; - LocalVariables = new List(); - SequencePoints = new List(); - } - } - - public class SequencePoint - { - public ILRange[] ILRanges { get; set; } - public TextLocation StartLocation { get; set; } - public TextLocation EndLocation { get; set; } - public int ILOffset { get { return ILRanges[0].From; } } - - public override string ToString() - { - return string.Join(" ", ILRanges) + " " + StartLocation + "-" + EndLocation; - } - } -} diff --git a/ICSharpCode.Decompiler/DecompilerException.cs b/ICSharpCode.Decompiler/DecompilerException.cs deleted file mode 100644 index 5f5f022f..00000000 --- a/ICSharpCode.Decompiler/DecompilerException.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Runtime.Serialization; -using Mono.Cecil; - -namespace ICSharpCode.Decompiler -{ - /// - /// Description of DecompilerException. - /// - public class DecompilerException : Exception, ISerializable - { - public MethodDefinition DecompiledMethod { get; set; } - - public DecompilerException(MethodDefinition decompiledMethod, Exception innerException) - : base("Error decompiling " + decompiledMethod.FullName + Environment.NewLine, innerException) - { - } - - // This constructor is needed for serialization. - protected DecompilerException(SerializationInfo info, StreamingContext context) : base(info, context) - { - } - } -} \ No newline at end of file diff --git a/ICSharpCode.Decompiler/DecompilerSettings.cs b/ICSharpCode.Decompiler/DecompilerSettings.cs deleted file mode 100644 index 74bdc943..00000000 --- a/ICSharpCode.Decompiler/DecompilerSettings.cs +++ /dev/null @@ -1,356 +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.ComponentModel; -using ICSharpCode.NRefactory.CSharp; - -namespace ICSharpCode.Decompiler -{ - /// - /// Settings for the decompiler. - /// - public class DecompilerSettings : INotifyPropertyChanged - { - bool anonymousMethods = true; - - /// - /// Decompile anonymous methods/lambdas. - /// - public bool AnonymousMethods { - get { return anonymousMethods; } - set { - if (anonymousMethods != value) { - anonymousMethods = value; - OnPropertyChanged("AnonymousMethods"); - } - } - } - - bool expressionTrees = true; - - /// - /// Decompile expression trees. - /// - public bool ExpressionTrees { - get { return expressionTrees; } - set { - if (expressionTrees != value) { - expressionTrees = value; - OnPropertyChanged("ExpressionTrees"); - } - } - } - - bool yieldReturn = true; - - /// - /// Decompile enumerators. - /// - public bool YieldReturn { - get { return yieldReturn; } - set { - if (yieldReturn != value) { - yieldReturn = value; - OnPropertyChanged("YieldReturn"); - } - } - } - - bool asyncAwait = true; - - /// - /// Decompile async methods. - /// - public bool AsyncAwait { - get { return asyncAwait; } - set { - if (asyncAwait != value) { - asyncAwait = value; - OnPropertyChanged("AsyncAwait"); - } - } - } - - bool automaticProperties = true; - - /// - /// Decompile automatic properties - /// - public bool AutomaticProperties { - get { return automaticProperties; } - set { - if (automaticProperties != value) { - automaticProperties = value; - OnPropertyChanged("AutomaticProperties"); - } - } - } - - bool automaticEvents = true; - - /// - /// Decompile automatic events - /// - public bool AutomaticEvents { - get { return automaticEvents; } - set { - if (automaticEvents != value) { - automaticEvents = value; - OnPropertyChanged("AutomaticEvents"); - } - } - } - - bool usingStatement = true; - - /// - /// Decompile using statements. - /// - public bool UsingStatement { - get { return usingStatement; } - set { - if (usingStatement != value) { - usingStatement = value; - OnPropertyChanged("UsingStatement"); - } - } - } - - bool forEachStatement = true; - - /// - /// Decompile foreach statements. - /// - public bool ForEachStatement { - get { return forEachStatement; } - set { - if (forEachStatement != value) { - forEachStatement = value; - OnPropertyChanged("ForEachStatement"); - } - } - } - - bool lockStatement = true; - - /// - /// Decompile lock statements. - /// - public bool LockStatement { - get { return lockStatement; } - set { - if (lockStatement != value) { - lockStatement = value; - OnPropertyChanged("LockStatement"); - } - } - } - - bool switchStatementOnString = true; - - public bool SwitchStatementOnString { - get { return switchStatementOnString; } - set { - if (switchStatementOnString != value) { - switchStatementOnString = value; - OnPropertyChanged("SwitchStatementOnString"); - } - } - } - - bool usingDeclarations = true; - - public bool UsingDeclarations { - get { return usingDeclarations; } - set { - if (usingDeclarations != value) { - usingDeclarations = value; - OnPropertyChanged("UsingDeclarations"); - } - } - } - - bool queryExpressions = true; - - public bool QueryExpressions { - get { return queryExpressions; } - set { - if (queryExpressions != value) { - queryExpressions = value; - OnPropertyChanged("QueryExpressions"); - } - } - } - - bool fullyQualifyAmbiguousTypeNames = true; - - public bool FullyQualifyAmbiguousTypeNames { - get { return fullyQualifyAmbiguousTypeNames; } - set { - if (fullyQualifyAmbiguousTypeNames != value) { - fullyQualifyAmbiguousTypeNames = value; - OnPropertyChanged("FullyQualifyAmbiguousTypeNames"); - } - } - } - - bool useDebugSymbols = true; - - /// - /// Gets/Sets whether to use variable names from debug symbols, if available. - /// - public bool UseDebugSymbols { - get { return useDebugSymbols; } - set { - if (useDebugSymbols != value) { - useDebugSymbols = value; - OnPropertyChanged("UseDebugSymbols"); - } - } - } - - bool objectCollectionInitializers = true; - - /// - /// Gets/Sets whether to use C# 3.0 object/collection initializers - /// - public bool ObjectOrCollectionInitializers { - get { return objectCollectionInitializers; } - set { - if (objectCollectionInitializers != value) { - objectCollectionInitializers = value; - OnPropertyChanged("ObjectCollectionInitializers"); - } - } - } - - bool showXmlDocumentation = true; - - /// - /// Gets/Sets whether to include XML documentation comments in the decompiled code - /// - public bool ShowXmlDocumentation { - get { return showXmlDocumentation; } - set { - if (showXmlDocumentation != value) { - showXmlDocumentation = value; - OnPropertyChanged("ShowXmlDocumentation"); - } - } - } - - bool foldBraces = false; - - public bool FoldBraces { - get { return foldBraces; } - set { - if (foldBraces != value) { - foldBraces = value; - OnPropertyChanged("FoldBraces"); - } - } - } - - #region Options to aid VB decompilation - bool introduceIncrementAndDecrement = true; - - /// - /// Gets/Sets whether to use increment and decrement operators - /// - public bool IntroduceIncrementAndDecrement { - get { return introduceIncrementAndDecrement; } - set { - if (introduceIncrementAndDecrement != value) { - introduceIncrementAndDecrement = value; - OnPropertyChanged("IntroduceIncrementAndDecrement"); - } - } - } - - bool makeAssignmentExpressions = true; - - /// - /// Gets/Sets whether to use assignment expressions such as in while ((count = Do()) != 0) ; - /// - public bool MakeAssignmentExpressions { - get { return makeAssignmentExpressions; } - set { - if (makeAssignmentExpressions != value) { - makeAssignmentExpressions = value; - OnPropertyChanged("MakeAssignmentExpressions"); - } - } - } - - bool alwaysGenerateExceptionVariableForCatchBlocks = false; - - /// - /// Gets/Sets whether to always generate exception variables in catch blocks - /// - public bool AlwaysGenerateExceptionVariableForCatchBlocks { - get { return alwaysGenerateExceptionVariableForCatchBlocks; } - set { - if (alwaysGenerateExceptionVariableForCatchBlocks != value) { - alwaysGenerateExceptionVariableForCatchBlocks = value; - OnPropertyChanged("AlwaysGenerateExceptionVariableForCatchBlocks"); - } - } - } - #endregion - - CSharpFormattingOptions csharpFormattingOptions; - - public CSharpFormattingOptions CSharpFormattingOptions { - get { - if (csharpFormattingOptions == null) { - csharpFormattingOptions = FormattingOptionsFactory.CreateAllman(); - csharpFormattingOptions.IndentSwitchBody = false; - csharpFormattingOptions.ArrayInitializerWrapping = Wrapping.WrapAlways; - } - return csharpFormattingOptions; - } - set { - if (value == null) - throw new ArgumentNullException(); - if (csharpFormattingOptions != value) { - csharpFormattingOptions = value; - OnPropertyChanged("CSharpFormattingOptions"); - } - } - } - - public event PropertyChangedEventHandler PropertyChanged; - - protected virtual void OnPropertyChanged(string propertyName) - { - if (PropertyChanged != null) { - PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); - } - } - - public DecompilerSettings Clone() - { - DecompilerSettings settings = (DecompilerSettings)MemberwiseClone(); - if (csharpFormattingOptions != null) - settings.csharpFormattingOptions = csharpFormattingOptions.Clone(); - settings.PropertyChanged = null; - return settings; - } - } -} diff --git a/ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs b/ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs deleted file mode 100644 index ea6e54db..00000000 --- a/ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs +++ /dev/null @@ -1,447 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using Mono.Cecil; -using Mono.Cecil.Cil; - -namespace ICSharpCode.Decompiler.Disassembler -{ - public enum ILNameSyntax - { - /// - /// class/valuetype + TypeName (built-in types use keyword syntax) - /// - Signature, - /// - /// Like signature, but always refers to type parameters using their position - /// - SignatureNoNamedTypeParameters, - /// - /// [assembly]Full.Type.Name (even for built-in types) - /// - TypeName, - /// - /// Name (but built-in types use keyword syntax) - /// - ShortTypeName - } - - public static class DisassemblerHelpers - { - public static void WriteOffsetReference(ITextOutput writer, Instruction instruction) - { - writer.WriteReference(CecilExtensions.OffsetToString(instruction.Offset), instruction); - } - - public static void WriteTo(this ExceptionHandler exceptionHandler, ITextOutput writer) - { - writer.Write("Try "); - WriteOffsetReference(writer, exceptionHandler.TryStart); - writer.Write('-'); - WriteOffsetReference(writer, exceptionHandler.TryEnd); - writer.Write(' '); - writer.Write(exceptionHandler.HandlerType.ToString()); - if (exceptionHandler.FilterStart != null) { - writer.Write(' '); - WriteOffsetReference(writer, exceptionHandler.FilterStart); - writer.Write(" handler "); - } - if (exceptionHandler.CatchType != null) { - writer.Write(' '); - exceptionHandler.CatchType.WriteTo(writer); - } - writer.Write(' '); - WriteOffsetReference(writer, exceptionHandler.HandlerStart); - writer.Write('-'); - WriteOffsetReference(writer, exceptionHandler.HandlerEnd); - } - - public static void WriteTo(this Instruction instruction, ITextOutput writer) - { - writer.WriteDefinition(CecilExtensions.OffsetToString(instruction.Offset), instruction); - writer.Write(": "); - writer.WriteReference(instruction.OpCode.Name, instruction.OpCode); - if (instruction.Operand != null) { - writer.Write(' '); - if (instruction.OpCode == OpCodes.Ldtoken) { - if (instruction.Operand is MethodReference) - writer.Write("method "); - else if (instruction.Operand is FieldReference) - writer.Write("field "); - } - WriteOperand(writer, instruction.Operand); - } - } - - static void WriteLabelList(ITextOutput writer, Instruction[] instructions) - { - writer.Write("("); - for(int i = 0; i < instructions.Length; i++) { - if(i != 0) writer.Write(", "); - WriteOffsetReference(writer, instructions[i]); - } - writer.Write(")"); - } - - static string ToInvariantCultureString(object value) - { - IConvertible convertible = value as IConvertible; - return(null != convertible) - ? convertible.ToString(System.Globalization.CultureInfo.InvariantCulture) - : value.ToString(); - } - - public static void WriteTo(this MethodReference method, ITextOutput writer) - { - if (method.ExplicitThis) { - writer.Write("instance explicit "); - } - else if (method.HasThis) { - writer.Write("instance "); - } - method.ReturnType.WriteTo(writer, ILNameSyntax.SignatureNoNamedTypeParameters); - writer.Write(' '); - if (method.DeclaringType != null) { - method.DeclaringType.WriteTo(writer, ILNameSyntax.TypeName); - writer.Write("::"); - } - MethodDefinition md = method as MethodDefinition; - if (md != null && md.IsCompilerControlled) { - writer.WriteReference(Escape(method.Name + "$PST" + method.MetadataToken.ToInt32().ToString("X8")), method); - } else { - writer.WriteReference(Escape(method.Name), method); - } - GenericInstanceMethod gim = method as GenericInstanceMethod; - if (gim != null) { - writer.Write('<'); - for (int i = 0; i < gim.GenericArguments.Count; i++) { - if (i > 0) - writer.Write(", "); - gim.GenericArguments[i].WriteTo(writer); - } - writer.Write('>'); - } - writer.Write("("); - var parameters = method.Parameters; - for(int i = 0; i < parameters.Count; ++i) { - if (i > 0) writer.Write(", "); - parameters[i].ParameterType.WriteTo(writer, ILNameSyntax.SignatureNoNamedTypeParameters); - } - writer.Write(")"); - } - - static void WriteTo(this FieldReference field, ITextOutput writer) - { - field.FieldType.WriteTo(writer, ILNameSyntax.SignatureNoNamedTypeParameters); - writer.Write(' '); - field.DeclaringType.WriteTo(writer, ILNameSyntax.TypeName); - writer.Write("::"); - writer.WriteReference(Escape(field.Name), field); - } - - static bool IsValidIdentifierCharacter(char c) - { - return c == '_' || c == '$' || c == '@' || c == '?' || c == '`'; - } - - static bool IsValidIdentifier(string identifier) - { - if (string.IsNullOrEmpty(identifier)) - return false; - if (!(char.IsLetter(identifier[0]) || IsValidIdentifierCharacter(identifier[0]))) { - // As a special case, .ctor and .cctor are valid despite starting with a dot - return identifier == ".ctor" || identifier == ".cctor"; - } - for (int i = 1; i < identifier.Length; i++) { - if (!(char.IsLetterOrDigit(identifier[i]) || IsValidIdentifierCharacter(identifier[i]) || identifier[i] == '.')) - return false; - } - return true; - } - - static readonly HashSet ilKeywords = BuildKeywordList( - "abstract", "algorithm", "alignment", "ansi", "any", "arglist", - "array", "as", "assembly", "assert", "at", "auto", "autochar", "beforefieldinit", - "blob", "blob_object", "bool", "brnull", "brnull.s", "brzero", "brzero.s", "bstr", - "bytearray", "byvalstr", "callmostderived", "carray", "catch", "cdecl", "cf", - "char", "cil", "class", "clsid", "const", "currency", "custom", "date", "decimal", - "default", "demand", "deny", "endmac", "enum", "error", "explicit", "extends", "extern", - "false", "famandassem", "family", "famorassem", "fastcall", "fault", "field", "filetime", - "filter", "final", "finally", "fixed", "float", "float32", "float64", "forwardref", - "fromunmanaged", "handler", "hidebysig", "hresult", "idispatch", "il", "illegal", - "implements", "implicitcom", "implicitres", "import", "in", "inheritcheck", "init", - "initonly", "instance", "int", "int16", "int32", "int64", "int8", "interface", "internalcall", - "iunknown", "lasterr", "lcid", "linkcheck", "literal", "localloc", "lpstr", "lpstruct", "lptstr", - "lpvoid", "lpwstr", "managed", "marshal", "method", "modopt", "modreq", "native", "nested", - "newslot", "noappdomain", "noinlining", "nomachine", "nomangle", "nometadata", "noncasdemand", - "noncasinheritance", "noncaslinkdemand", "noprocess", "not", "not_in_gc_heap", "notremotable", - "notserialized", "null", "nullref", "object", "objectref", "opt", "optil", "out", - "permitonly", "pinned", "pinvokeimpl", "prefix1", "prefix2", "prefix3", "prefix4", "prefix5", "prefix6", - "prefix7", "prefixref", "prejitdeny", "prejitgrant", "preservesig", "private", "privatescope", "protected", - "public", "record", "refany", "reqmin", "reqopt", "reqrefuse", "reqsecobj", "request", "retval", - "rtspecialname", "runtime", "safearray", "sealed", "sequential", "serializable", "special", "specialname", - "static", "stdcall", "storage", "stored_object", "stream", "streamed_object", "string", "struct", - "synchronized", "syschar", "sysstring", "tbstr", "thiscall", "tls", "to", "true", "typedref", - "unicode", "unmanaged", "unmanagedexp", "unsigned", "unused", "userdefined", "value", "valuetype", - "vararg", "variant", "vector", "virtual", "void", "wchar", "winapi", "with", "wrapper", - - // These are not listed as keywords in spec, but ILAsm treats them as such - "property", "type", "flags", "callconv", "strict" - ); - - static HashSet BuildKeywordList(params string[] keywords) - { - HashSet s = new HashSet(keywords); - foreach (var field in typeof(OpCodes).GetFields()) { - s.Add(((OpCode)field.GetValue(null)).Name); - } - return s; - } - - public static string Escape(string identifier) - { - if (IsValidIdentifier(identifier) && !ilKeywords.Contains(identifier)) { - return identifier; - } else { - // The ECMA specification says that ' inside SQString should be ecaped using an octal escape sequence, - // but we follow Microsoft's ILDasm and use \'. - return "'" + NRefactory.CSharp.TextWriterTokenWriter.ConvertString(identifier).Replace("'", "\\'") + "'"; - } - } - - public static void WriteTo(this TypeReference type, ITextOutput writer, ILNameSyntax syntax = ILNameSyntax.Signature) - { - ILNameSyntax syntaxForElementTypes = syntax == ILNameSyntax.SignatureNoNamedTypeParameters ? syntax : ILNameSyntax.Signature; - if (type is PinnedType) { - ((PinnedType)type).ElementType.WriteTo(writer, syntaxForElementTypes); - writer.Write(" pinned"); - } else if (type is ArrayType) { - ArrayType at = (ArrayType)type; - at.ElementType.WriteTo(writer, syntaxForElementTypes); - writer.Write('['); - writer.Write(string.Join(", ", at.Dimensions)); - writer.Write(']'); - } else if (type is GenericParameter) { - writer.Write('!'); - if (((GenericParameter)type).Owner.GenericParameterType == GenericParameterType.Method) - writer.Write('!'); - if (string.IsNullOrEmpty(type.Name) || type.Name[0] == '!' || syntax == ILNameSyntax.SignatureNoNamedTypeParameters) - writer.Write(((GenericParameter)type).Position.ToString()); - else - writer.Write(Escape(type.Name)); - } else if (type is ByReferenceType) { - ((ByReferenceType)type).ElementType.WriteTo(writer, syntaxForElementTypes); - writer.Write('&'); - } else if (type is PointerType) { - ((PointerType)type).ElementType.WriteTo(writer, syntaxForElementTypes); - writer.Write('*'); - } else if (type is GenericInstanceType) { - type.GetElementType().WriteTo(writer, syntaxForElementTypes); - writer.Write('<'); - var arguments = ((GenericInstanceType)type).GenericArguments; - for (int i = 0; i < arguments.Count; i++) { - if (i > 0) - writer.Write(", "); - arguments[i].WriteTo(writer, syntaxForElementTypes); - } - writer.Write('>'); - } else if (type is OptionalModifierType) { - ((OptionalModifierType)type).ElementType.WriteTo(writer, syntax); - writer.Write(" modopt("); - ((OptionalModifierType)type).ModifierType.WriteTo(writer, ILNameSyntax.TypeName); - writer.Write(") "); - } else if (type is RequiredModifierType) { - ((RequiredModifierType)type).ElementType.WriteTo(writer, syntax); - writer.Write(" modreq("); - ((RequiredModifierType)type).ModifierType.WriteTo(writer, ILNameSyntax.TypeName); - writer.Write(") "); - } else { - string name = PrimitiveTypeName(type.FullName); - if (syntax == ILNameSyntax.ShortTypeName) { - if (name != null) - writer.Write(name); - else - writer.WriteReference(Escape(type.Name), type); - } else if ((syntax == ILNameSyntax.Signature || syntax == ILNameSyntax.SignatureNoNamedTypeParameters) && name != null) { - writer.Write(name); - } else { - if (syntax == ILNameSyntax.Signature || syntax == ILNameSyntax.SignatureNoNamedTypeParameters) - writer.Write(type.IsValueType ? "valuetype " : "class "); - - if (type.DeclaringType != null) { - type.DeclaringType.WriteTo(writer, ILNameSyntax.TypeName); - writer.Write('/'); - writer.WriteReference(Escape(type.Name), type); - } else { - if (!type.IsDefinition && type.Scope != null && !(type is TypeSpecification)) - writer.Write("[{0}]", Escape(type.Scope.Name)); - writer.WriteReference(Escape(type.FullName), type); - } - } - } - } - - public static void WriteOperand(ITextOutput writer, object operand) - { - if (operand == null) - throw new ArgumentNullException("operand"); - - Instruction targetInstruction = operand as Instruction; - if (targetInstruction != null) { - WriteOffsetReference(writer, targetInstruction); - return; - } - - Instruction[] targetInstructions = operand as Instruction[]; - if (targetInstructions != null) { - WriteLabelList(writer, targetInstructions); - return; - } - - VariableReference variableRef = operand as VariableReference; - if (variableRef != null) { - if (string.IsNullOrEmpty(variableRef.Name)) - writer.WriteReference(variableRef.Index.ToString(), variableRef); - else - writer.WriteReference(Escape(variableRef.Name), variableRef); - return; - } - - ParameterReference paramRef = operand as ParameterReference; - if (paramRef != null) { - if (string.IsNullOrEmpty(paramRef.Name)) - writer.WriteReference(paramRef.Index.ToString(), paramRef); - else - writer.WriteReference(Escape(paramRef.Name), paramRef); - return; - } - - MethodReference methodRef = operand as MethodReference; - if (methodRef != null) { - methodRef.WriteTo(writer); - return; - } - - TypeReference typeRef = operand as TypeReference; - if (typeRef != null) { - typeRef.WriteTo(writer, ILNameSyntax.TypeName); - return; - } - - FieldReference fieldRef = operand as FieldReference; - if (fieldRef != null) { - fieldRef.WriteTo(writer); - return; - } - - string s = operand as string; - if (s != null) { - writer.Write("\"" + NRefactory.CSharp.TextWriterTokenWriter.ConvertString(s) + "\""); - } else if (operand is char) { - writer.Write(((int)(char)operand).ToString()); - } else if (operand is float) { - float val = (float)operand; - if (val == 0) { - if (1 / val == float.NegativeInfinity) { - // negative zero is a special case - writer.Write('-'); - } - writer.Write("0.0"); - } else if (float.IsInfinity(val) || float.IsNaN(val)) { - byte[] data = BitConverter.GetBytes(val); - writer.Write('('); - for (int i = 0; i < data.Length; i++) { - if (i > 0) - writer.Write(' '); - writer.Write(data[i].ToString("X2")); - } - writer.Write(')'); - } else { - writer.Write(val.ToString("R", System.Globalization.CultureInfo.InvariantCulture)); - } - } else if (operand is double) { - double val = (double)operand; - if (val == 0) { - if (1 / val == double.NegativeInfinity) { - // negative zero is a special case - writer.Write('-'); - } - writer.Write("0.0"); - } else if (double.IsInfinity(val) || double.IsNaN(val)) { - byte[] data = BitConverter.GetBytes(val); - writer.Write('('); - for (int i = 0; i < data.Length; i++) { - if (i > 0) - writer.Write(' '); - writer.Write(data[i].ToString("X2")); - } - writer.Write(')'); - } else { - writer.Write(val.ToString("R", System.Globalization.CultureInfo.InvariantCulture)); - } - } else if (operand is bool) { - writer.Write((bool)operand ? "true" : "false"); - } else { - s = ToInvariantCultureString(operand); - writer.Write(s); - } - } - - public static string PrimitiveTypeName(string fullName) - { - switch (fullName) { - case "System.SByte": - return "int8"; - case "System.Int16": - return "int16"; - case "System.Int32": - return "int32"; - case "System.Int64": - return "int64"; - case "System.Byte": - return "uint8"; - case "System.UInt16": - return "uint16"; - case "System.UInt32": - return "uint32"; - case "System.UInt64": - return "uint64"; - case "System.Single": - return "float32"; - case "System.Double": - return "float64"; - case "System.Void": - return "void"; - case "System.Boolean": - return "bool"; - case "System.String": - return "string"; - case "System.Char": - return "char"; - case "System.Object": - return "object"; - case "System.IntPtr": - return "native int"; - default: - return null; - } - } - } -} diff --git a/ICSharpCode.Decompiler/Disassembler/ILStructure.cs b/ICSharpCode.Decompiler/Disassembler/ILStructure.cs deleted file mode 100644 index ff9285b2..00000000 --- a/ICSharpCode.Decompiler/Disassembler/ILStructure.cs +++ /dev/null @@ -1,228 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using ICSharpCode.Decompiler.FlowAnalysis; -using Mono.Cecil.Cil; - -namespace ICSharpCode.Decompiler.Disassembler -{ - /// - /// Specifies the type of an IL structure. - /// - public enum ILStructureType - { - /// - /// The root block of the method - /// - Root, - /// - /// A nested control structure representing a loop. - /// - Loop, - /// - /// A nested control structure representing a try block. - /// - Try, - /// - /// A nested control structure representing a catch, finally, or fault block. - /// - Handler, - /// - /// A nested control structure representing an exception filter block. - /// - Filter - } - - /// - /// An IL structure. - /// - public class ILStructure - { - public readonly ILStructureType Type; - - /// - /// Start position of the structure. - /// - public readonly int StartOffset; - - /// - /// End position of the structure. (exclusive) - /// - public readonly int EndOffset; - - /// - /// The exception handler associated with the Try, Filter or Handler block. - /// - public readonly ExceptionHandler ExceptionHandler; - - /// - /// The loop's entry point. - /// - public readonly Instruction LoopEntryPoint; - - /// - /// The list of child structures. - /// - public readonly List Children = new List(); - - public ILStructure(MethodBody body) - : this(ILStructureType.Root, 0, body.CodeSize) - { - // Build the tree of exception structures: - for (int i = 0; i < body.ExceptionHandlers.Count; i++) { - ExceptionHandler eh = body.ExceptionHandlers[i]; - if (!body.ExceptionHandlers.Take(i).Any(oldEh => oldEh.TryStart == eh.TryStart && oldEh.TryEnd == eh.TryEnd)) - AddNestedStructure(new ILStructure(ILStructureType.Try, eh.TryStart.Offset, eh.TryEnd.Offset, eh)); - if (eh.HandlerType == ExceptionHandlerType.Filter) - AddNestedStructure(new ILStructure(ILStructureType.Filter, eh.FilterStart.Offset, eh.HandlerStart.Offset, eh)); - AddNestedStructure(new ILStructure(ILStructureType.Handler, eh.HandlerStart.Offset, eh.HandlerEnd == null ? body.CodeSize : eh.HandlerEnd.Offset, eh)); - } - // Very simple loop detection: look for backward branches - List> allBranches = FindAllBranches(body); - // We go through the branches in reverse so that we find the biggest possible loop boundary first (think loops with "continue;") - for (int i = allBranches.Count - 1; i >= 0; i--) { - int loopEnd = allBranches[i].Key.GetEndOffset(); - int loopStart = allBranches[i].Value.Offset; - if (loopStart < loopEnd) { - // We found a backward branch. This is a potential loop. - // Check that is has only one entry point: - Instruction entryPoint = null; - - // entry point is first instruction in loop if prev inst isn't an unconditional branch - Instruction prev = allBranches[i].Value.Previous; - if (prev != null && !OpCodeInfo.IsUnconditionalBranch(prev.OpCode)) - entryPoint = allBranches[i].Value; - - bool multipleEntryPoints = false; - foreach (var pair in allBranches) { - if (pair.Key.Offset < loopStart || pair.Key.Offset >= loopEnd) { - if (loopStart <= pair.Value.Offset && pair.Value.Offset < loopEnd) { - // jump from outside the loop into the loop - if (entryPoint == null) - entryPoint = pair.Value; - else if (pair.Value != entryPoint) - multipleEntryPoints = true; - } - } - } - if (!multipleEntryPoints) { - AddNestedStructure(new ILStructure(ILStructureType.Loop, loopStart, loopEnd, entryPoint)); - } - } - } - SortChildren(); - } - - public ILStructure(ILStructureType type, int startOffset, int endOffset, ExceptionHandler handler = null) - { - Debug.Assert(startOffset < endOffset); - Type = type; - StartOffset = startOffset; - EndOffset = endOffset; - ExceptionHandler = handler; - } - - public ILStructure(ILStructureType type, int startOffset, int endOffset, Instruction loopEntryPoint) - { - Debug.Assert(startOffset < endOffset); - Type = type; - StartOffset = startOffset; - EndOffset = endOffset; - LoopEntryPoint = loopEntryPoint; - } - - bool AddNestedStructure(ILStructure newStructure) - { - // special case: don't consider the loop-like structure of "continue;" statements to be nested loops - if (Type == ILStructureType.Loop && newStructure.Type == ILStructureType.Loop && newStructure.StartOffset == StartOffset) - return false; - - // use <= for end-offset comparisons because both end and EndOffset are exclusive - Debug.Assert(StartOffset <= newStructure.StartOffset && newStructure.EndOffset <= EndOffset); - foreach (ILStructure child in Children) { - if (child.StartOffset <= newStructure.StartOffset && newStructure.EndOffset <= child.EndOffset) { - return child.AddNestedStructure(newStructure); - } else if (!(child.EndOffset <= newStructure.StartOffset || newStructure.EndOffset <= child.StartOffset)) { - // child and newStructure overlap - if (!(newStructure.StartOffset <= child.StartOffset && child.EndOffset <= newStructure.EndOffset)) { - // Invalid nesting, can't build a tree. -> Don't add the new structure. - return false; - } - } - } - // Move existing structures into the new structure: - for (int i = 0; i < Children.Count; i++) { - ILStructure child = Children[i]; - if (newStructure.StartOffset <= child.StartOffset && child.EndOffset <= newStructure.EndOffset) { - Children.RemoveAt(i--); - newStructure.Children.Add(child); - } - } - // Add the structure here: - Children.Add(newStructure); - return true; - } - - /// - /// Finds all branches. Returns list of source offset->target offset mapping. - /// Multiple entries for the same source offset are possible (switch statements). - /// The result is sorted by source offset. - /// - List> FindAllBranches(MethodBody body) - { - var result = new List>(); - foreach (Instruction inst in body.Instructions) { - switch (inst.OpCode.OperandType) { - case OperandType.InlineBrTarget: - case OperandType.ShortInlineBrTarget: - result.Add(new KeyValuePair(inst, (Instruction)inst.Operand)); - break; - case OperandType.InlineSwitch: - foreach (Instruction target in (Instruction[])inst.Operand) - result.Add(new KeyValuePair(inst, target)); - break; - } - } - return result; - } - - void SortChildren() - { - Children.Sort((a, b) => a.StartOffset.CompareTo(b.StartOffset)); - foreach (ILStructure child in Children) - child.SortChildren(); - } - - /// - /// Gets the innermost structure containing the specified offset. - /// - public ILStructure GetInnermost(int offset) - { - Debug.Assert(StartOffset <= offset && offset < EndOffset); - foreach (ILStructure child in Children) { - if (child.StartOffset <= offset && offset < child.EndOffset) - return child.GetInnermost(offset); - } - return this; - } - } -} diff --git a/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs b/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs deleted file mode 100644 index 2b5db78b..00000000 --- a/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs +++ /dev/null @@ -1,239 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; - -using ICSharpCode.Decompiler; -using ICSharpCode.Decompiler.FlowAnalysis; -using ICSharpCode.Decompiler.ILAst; -using Mono.Cecil; -using Mono.Cecil.Cil; - -namespace ICSharpCode.Decompiler.Disassembler -{ - /// - /// Disassembles a method body. - /// - public sealed class MethodBodyDisassembler - { - readonly ITextOutput output; - readonly bool detectControlStructure; - readonly CancellationToken cancellationToken; - - public MethodBodyDisassembler(ITextOutput output, bool detectControlStructure, CancellationToken cancellationToken) - { - if (output == null) - throw new ArgumentNullException("output"); - this.output = output; - this.detectControlStructure = detectControlStructure; - this.cancellationToken = cancellationToken; - } - - public void Disassemble(MethodBody body, MethodDebugSymbols debugSymbols) - { - // start writing IL code - MethodDefinition method = body.Method; - output.WriteLine("// Method begins at RVA 0x{0:x4}", method.RVA); - output.WriteLine("// Code size {0} (0x{0:x})", body.CodeSize); - output.WriteLine(".maxstack {0}", body.MaxStackSize); - if (method.DeclaringType.Module.Assembly != null && method.DeclaringType.Module.Assembly.EntryPoint == method) - output.WriteLine (".entrypoint"); - - if (method.Body.HasVariables) { - output.Write(".locals "); - if (method.Body.InitLocals) - output.Write("init "); - output.WriteLine("("); - output.Indent(); - foreach (var v in method.Body.Variables) { - output.WriteDefinition("[" + v.Index + "] ", v); - v.VariableType.WriteTo(output); - if (!string.IsNullOrEmpty(v.Name)) { - output.Write(' '); - output.Write(DisassemblerHelpers.Escape(v.Name)); - } - if (v.Index + 1 < method.Body.Variables.Count) - output.Write(','); - output.WriteLine(); - } - output.Unindent(); - output.WriteLine(")"); - } - output.WriteLine(); - - if (detectControlStructure && body.Instructions.Count > 0) { - Instruction inst = body.Instructions[0]; - HashSet branchTargets = GetBranchTargets(body.Instructions); - WriteStructureBody(new ILStructure(body), branchTargets, ref inst, debugSymbols, method.Body.CodeSize); - } else { - foreach (var inst in method.Body.Instructions) { - var startLocation = output.Location; - inst.WriteTo(output); - - if (debugSymbols != null) { - // add IL code mappings - used in debugger - debugSymbols.SequencePoints.Add( - new SequencePoint() { - StartLocation = output.Location, - EndLocation = output.Location, - ILRanges = new ILRange[] { new ILRange(inst.Offset, inst.Next == null ? method.Body.CodeSize : inst.Next.Offset) } - }); - } - - output.WriteLine(); - } - if (method.Body.HasExceptionHandlers) { - output.WriteLine(); - foreach (var eh in method.Body.ExceptionHandlers) { - eh.WriteTo(output); - output.WriteLine(); - } - } - } - } - - HashSet GetBranchTargets(IEnumerable instructions) - { - HashSet branchTargets = new HashSet(); - foreach (var inst in instructions) { - Instruction target = inst.Operand as Instruction; - if (target != null) - branchTargets.Add(target.Offset); - Instruction[] targets = inst.Operand as Instruction[]; - if (targets != null) - foreach (Instruction t in targets) - branchTargets.Add(t.Offset); - } - return branchTargets; - } - - void WriteStructureHeader(ILStructure s) - { - switch (s.Type) { - case ILStructureType.Loop: - output.Write("// loop start"); - if (s.LoopEntryPoint != null) { - output.Write(" (head: "); - DisassemblerHelpers.WriteOffsetReference(output, s.LoopEntryPoint); - output.Write(')'); - } - output.WriteLine(); - break; - case ILStructureType.Try: - output.WriteLine(".try"); - output.WriteLine("{"); - break; - case ILStructureType.Handler: - switch (s.ExceptionHandler.HandlerType) { - case ExceptionHandlerType.Catch: - case ExceptionHandlerType.Filter: - output.Write("catch"); - if (s.ExceptionHandler.CatchType != null) { - output.Write(' '); - s.ExceptionHandler.CatchType.WriteTo(output, ILNameSyntax.TypeName); - } - output.WriteLine(); - break; - case ExceptionHandlerType.Finally: - output.WriteLine("finally"); - break; - case ExceptionHandlerType.Fault: - output.WriteLine("fault"); - break; - default: - throw new NotSupportedException(); - } - output.WriteLine("{"); - break; - case ILStructureType.Filter: - output.WriteLine("filter"); - output.WriteLine("{"); - break; - default: - throw new NotSupportedException(); - } - output.Indent(); - } - - void WriteStructureBody(ILStructure s, HashSet branchTargets, ref Instruction inst, MethodDebugSymbols debugSymbols, int codeSize) - { - bool isFirstInstructionInStructure = true; - bool prevInstructionWasBranch = false; - int childIndex = 0; - while (inst != null && inst.Offset < s.EndOffset) { - int offset = inst.Offset; - if (childIndex < s.Children.Count && s.Children[childIndex].StartOffset <= offset && offset < s.Children[childIndex].EndOffset) { - ILStructure child = s.Children[childIndex++]; - WriteStructureHeader(child); - WriteStructureBody(child, branchTargets, ref inst, debugSymbols, codeSize); - WriteStructureFooter(child); - } else { - if (!isFirstInstructionInStructure && (prevInstructionWasBranch || branchTargets.Contains(offset))) { - output.WriteLine(); // put an empty line after branches, and in front of branch targets - } - var startLocation = output.Location; - inst.WriteTo(output); - - // add IL code mappings - used in debugger - if (debugSymbols != null) { - debugSymbols.SequencePoints.Add( - new SequencePoint() { - StartLocation = startLocation, - EndLocation = output.Location, - ILRanges = new ILRange[] { new ILRange(inst.Offset, inst.Next == null ? codeSize : inst.Next.Offset) } - }); - } - - output.WriteLine(); - - prevInstructionWasBranch = inst.OpCode.FlowControl == FlowControl.Branch - || inst.OpCode.FlowControl == FlowControl.Cond_Branch - || inst.OpCode.FlowControl == FlowControl.Return - || inst.OpCode.FlowControl == FlowControl.Throw; - - inst = inst.Next; - } - isFirstInstructionInStructure = false; - } - } - - void WriteStructureFooter(ILStructure s) - { - output.Unindent(); - switch (s.Type) { - case ILStructureType.Loop: - output.WriteLine("// end loop"); - break; - case ILStructureType.Try: - output.WriteLine("} // end .try"); - break; - case ILStructureType.Handler: - output.WriteLine("} // end handler"); - break; - case ILStructureType.Filter: - output.WriteLine("} // end filter"); - break; - default: - throw new NotSupportedException(); - } - } - } -} diff --git a/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs b/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs deleted file mode 100644 index 2a374c3a..00000000 --- a/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs +++ /dev/null @@ -1,1168 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Text; -using System.Threading; -using ICSharpCode.NRefactory; -using Mono.Cecil; -using Mono.Collections.Generic; - -namespace ICSharpCode.Decompiler.Disassembler -{ - /// - /// Disassembles type and member definitions. - /// - public sealed class ReflectionDisassembler - { - ITextOutput output; - CancellationToken cancellationToken; - bool isInType; // whether we are currently disassembling a whole type (-> defaultCollapsed for foldings) - MethodBodyDisassembler methodBodyDisassembler; - MemberReference currentMember; - - public ReflectionDisassembler(ITextOutput output, bool detectControlStructure, CancellationToken cancellationToken) - { - if (output == null) - throw new ArgumentNullException("output"); - this.output = output; - this.cancellationToken = cancellationToken; - methodBodyDisassembler = new MethodBodyDisassembler(output, detectControlStructure, cancellationToken); - } - - #region Disassemble Method - EnumNameCollection methodAttributeFlags = new EnumNameCollection() { - { MethodAttributes.Final, "final" }, - { MethodAttributes.HideBySig, "hidebysig" }, - { MethodAttributes.SpecialName, "specialname" }, - { MethodAttributes.PInvokeImpl, null }, // handled separately - { MethodAttributes.UnmanagedExport, "export" }, - { MethodAttributes.RTSpecialName, "rtspecialname" }, - { MethodAttributes.RequireSecObject, "reqsecobj" }, - { MethodAttributes.NewSlot, "newslot" }, - { MethodAttributes.CheckAccessOnOverride, "strict" }, - { MethodAttributes.Abstract, "abstract" }, - { MethodAttributes.Virtual, "virtual" }, - { MethodAttributes.Static, "static" }, - { MethodAttributes.HasSecurity, null }, // ?? also invisible in ILDasm - }; - - EnumNameCollection methodVisibility = new EnumNameCollection() { - { MethodAttributes.Private, "private" }, - { MethodAttributes.FamANDAssem, "famandassem" }, - { MethodAttributes.Assembly, "assembly" }, - { MethodAttributes.Family, "family" }, - { MethodAttributes.FamORAssem, "famorassem" }, - { MethodAttributes.Public, "public" }, - }; - - EnumNameCollection callingConvention = new EnumNameCollection() { - { MethodCallingConvention.C, "unmanaged cdecl" }, - { MethodCallingConvention.StdCall, "unmanaged stdcall" }, - { MethodCallingConvention.ThisCall, "unmanaged thiscall" }, - { MethodCallingConvention.FastCall, "unmanaged fastcall" }, - { MethodCallingConvention.VarArg, "vararg" }, - { MethodCallingConvention.Generic, null }, - }; - - EnumNameCollection methodCodeType = new EnumNameCollection() { - { MethodImplAttributes.IL, "cil" }, - { MethodImplAttributes.Native, "native" }, - { MethodImplAttributes.OPTIL, "optil" }, - { MethodImplAttributes.Runtime, "runtime" }, - }; - - EnumNameCollection methodImpl = new EnumNameCollection() { - { MethodImplAttributes.Synchronized, "synchronized" }, - { MethodImplAttributes.NoInlining, "noinlining" }, - { MethodImplAttributes.NoOptimization, "nooptimization" }, - { MethodImplAttributes.PreserveSig, "preservesig" }, - { MethodImplAttributes.InternalCall, "internalcall" }, - { MethodImplAttributes.ForwardRef, "forwardref" }, - }; - - public void DisassembleMethod(MethodDefinition method) - { - // set current member - currentMember = method; - - // write method header - output.WriteDefinition(".method ", method); - DisassembleMethodInternal(method); - } - - void DisassembleMethodInternal(MethodDefinition method) - { - // .method public hidebysig specialname - // instance default class [mscorlib]System.IO.TextWriter get_BaseWriter () cil managed - // - - TextLocation startLocation = output.Location; - - //emit flags - WriteEnum(method.Attributes & MethodAttributes.MemberAccessMask, methodVisibility); - WriteFlags(method.Attributes & ~MethodAttributes.MemberAccessMask, methodAttributeFlags); - if(method.IsCompilerControlled) output.Write("privatescope "); - - if ((method.Attributes & MethodAttributes.PInvokeImpl) == MethodAttributes.PInvokeImpl) { - output.Write("pinvokeimpl"); - if (method.HasPInvokeInfo && method.PInvokeInfo != null) { - PInvokeInfo info = method.PInvokeInfo; - output.Write("(\"" + NRefactory.CSharp.TextWriterTokenWriter.ConvertString(info.Module.Name) + "\""); - - if (!string.IsNullOrEmpty(info.EntryPoint) && info.EntryPoint != method.Name) - output.Write(" as \"" + NRefactory.CSharp.TextWriterTokenWriter.ConvertString(info.EntryPoint) + "\""); - - if (info.IsNoMangle) - output.Write(" nomangle"); - - if (info.IsCharSetAnsi) - output.Write(" ansi"); - else if (info.IsCharSetAuto) - output.Write(" autochar"); - else if (info.IsCharSetUnicode) - output.Write(" unicode"); - - if (info.SupportsLastError) - output.Write(" lasterr"); - - if (info.IsCallConvCdecl) - output.Write(" cdecl"); - else if (info.IsCallConvFastcall) - output.Write(" fastcall"); - else if (info.IsCallConvStdCall) - output.Write(" stdcall"); - else if (info.IsCallConvThiscall) - output.Write(" thiscall"); - else if (info.IsCallConvWinapi) - output.Write(" winapi"); - - output.Write(')'); - } - output.Write(' '); - } - - output.WriteLine(); - output.Indent(); - if (method.ExplicitThis) { - output.Write("instance explicit "); - } else if (method.HasThis) { - output.Write("instance "); - } - - //call convention - WriteEnum(method.CallingConvention & (MethodCallingConvention)0x1f, callingConvention); - - //return type - method.ReturnType.WriteTo(output); - output.Write(' '); - if (method.MethodReturnType.HasMarshalInfo) { - WriteMarshalInfo(method.MethodReturnType.MarshalInfo); - } - - if (method.IsCompilerControlled) { - output.Write(DisassemblerHelpers.Escape(method.Name + "$PST" + method.MetadataToken.ToInt32().ToString("X8"))); - } else { - output.Write(DisassemblerHelpers.Escape(method.Name)); - } - - WriteTypeParameters(output, method); - - //( params ) - output.Write(" ("); - if (method.HasParameters) { - output.WriteLine(); - output.Indent(); - WriteParameters(method.Parameters); - output.Unindent(); - } - output.Write(") "); - //cil managed - WriteEnum(method.ImplAttributes & MethodImplAttributes.CodeTypeMask, methodCodeType); - if ((method.ImplAttributes & MethodImplAttributes.ManagedMask) == MethodImplAttributes.Managed) - output.Write("managed "); - else - output.Write("unmanaged "); - WriteFlags(method.ImplAttributes & ~(MethodImplAttributes.CodeTypeMask | MethodImplAttributes.ManagedMask), methodImpl); - - output.Unindent(); - OpenBlock(defaultCollapsed: isInType); - WriteAttributes(method.CustomAttributes); - if (method.HasOverrides) { - foreach (var methodOverride in method.Overrides) { - output.Write(".override method "); - methodOverride.WriteTo(output); - output.WriteLine(); - } - } - foreach (var p in method.Parameters) { - WriteParameterAttributes(p); - } - WriteSecurityDeclarations(method); - - if (method.HasBody) { - // create IL code mappings - used in debugger - MethodDebugSymbols debugSymbols = new MethodDebugSymbols(method); - debugSymbols.StartLocation = startLocation; - methodBodyDisassembler.Disassemble(method.Body, debugSymbols); - debugSymbols.EndLocation = output.Location; - output.AddDebugSymbols(debugSymbols); - } - - CloseBlock("end of method " + DisassemblerHelpers.Escape(method.DeclaringType.Name) + "::" + DisassemblerHelpers.Escape(method.Name)); - } - - #region Write Security Declarations - void WriteSecurityDeclarations(ISecurityDeclarationProvider secDeclProvider) - { - if (!secDeclProvider.HasSecurityDeclarations) - return; - foreach (var secdecl in secDeclProvider.SecurityDeclarations) { - output.Write(".permissionset "); - switch (secdecl.Action) { - case SecurityAction.Request: - output.Write("request"); - break; - case SecurityAction.Demand: - output.Write("demand"); - break; - case SecurityAction.Assert: - output.Write("assert"); - break; - case SecurityAction.Deny: - output.Write("deny"); - break; - case SecurityAction.PermitOnly: - output.Write("permitonly"); - break; - case SecurityAction.LinkDemand: - output.Write("linkcheck"); - break; - case SecurityAction.InheritDemand: - output.Write("inheritcheck"); - break; - case SecurityAction.RequestMinimum: - output.Write("reqmin"); - break; - case SecurityAction.RequestOptional: - output.Write("reqopt"); - break; - case SecurityAction.RequestRefuse: - output.Write("reqrefuse"); - break; - case SecurityAction.PreJitGrant: - output.Write("prejitgrant"); - break; - case SecurityAction.PreJitDeny: - output.Write("prejitdeny"); - break; - case SecurityAction.NonCasDemand: - output.Write("noncasdemand"); - break; - case SecurityAction.NonCasLinkDemand: - output.Write("noncaslinkdemand"); - break; - case SecurityAction.NonCasInheritance: - output.Write("noncasinheritance"); - break; - default: - output.Write(secdecl.Action.ToString()); - break; - } - output.WriteLine(" = {"); - output.Indent(); - for (int i = 0; i < secdecl.SecurityAttributes.Count; i++) { - SecurityAttribute sa = secdecl.SecurityAttributes[i]; - if (sa.AttributeType.Scope == sa.AttributeType.Module) { - output.Write("class "); - output.Write(DisassemblerHelpers.Escape(GetAssemblyQualifiedName(sa.AttributeType))); - } else { - sa.AttributeType.WriteTo(output, ILNameSyntax.TypeName); - } - output.Write(" = {"); - if (sa.HasFields || sa.HasProperties) { - output.WriteLine(); - output.Indent(); - - foreach (CustomAttributeNamedArgument na in sa.Fields) { - output.Write("field "); - WriteSecurityDeclarationArgument(na); - output.WriteLine(); - } - - foreach (CustomAttributeNamedArgument na in sa.Properties) { - output.Write("property "); - WriteSecurityDeclarationArgument(na); - output.WriteLine(); - } - - output.Unindent(); - } - output.Write('}'); - - if (i + 1< secdecl.SecurityAttributes.Count) - output.Write(','); - output.WriteLine(); - } - output.Unindent(); - output.WriteLine("}"); - } - } - - void WriteSecurityDeclarationArgument(CustomAttributeNamedArgument na) - { - TypeReference type = na.Argument.Type; - if (type.MetadataType == MetadataType.Class || type.MetadataType == MetadataType.ValueType) { - output.Write("enum "); - if (type.Scope != type.Module) { - output.Write("class "); - output.Write(DisassemblerHelpers.Escape(GetAssemblyQualifiedName(type))); - } else { - type.WriteTo(output, ILNameSyntax.TypeName); - } - } else { - type.WriteTo(output); - } - output.Write(' '); - output.Write(DisassemblerHelpers.Escape(na.Name)); - output.Write(" = "); - if (na.Argument.Value is string) { - // secdecls use special syntax for strings - output.Write("string('{0}')", NRefactory.CSharp.TextWriterTokenWriter.ConvertString((string)na.Argument.Value).Replace("'", "\'")); - } else { - WriteConstant(na.Argument.Value); - } - } - - string GetAssemblyQualifiedName(TypeReference type) - { - AssemblyNameReference anr = type.Scope as AssemblyNameReference; - if (anr == null) { - ModuleDefinition md = type.Scope as ModuleDefinition; - if (md != null) { - anr = md.Assembly.Name; - } - } - if (anr != null) { - return type.FullName + ", " + anr.FullName; - } else { - return type.FullName; - } - } - #endregion - - #region WriteMarshalInfo - void WriteMarshalInfo(MarshalInfo marshalInfo) - { - output.Write("marshal("); - WriteNativeType(marshalInfo.NativeType, marshalInfo); - output.Write(") "); - } - - void WriteNativeType(NativeType nativeType, MarshalInfo marshalInfo = null) - { - switch (nativeType) { - case NativeType.None: - break; - case NativeType.Boolean: - output.Write("bool"); - break; - case NativeType.I1: - output.Write("int8"); - break; - case NativeType.U1: - output.Write("unsigned int8"); - break; - case NativeType.I2: - output.Write("int16"); - break; - case NativeType.U2: - output.Write("unsigned int16"); - break; - case NativeType.I4: - output.Write("int32"); - break; - case NativeType.U4: - output.Write("unsigned int32"); - break; - case NativeType.I8: - output.Write("int64"); - break; - case NativeType.U8: - output.Write("unsigned int64"); - break; - case NativeType.R4: - output.Write("float32"); - break; - case NativeType.R8: - output.Write("float64"); - break; - case NativeType.LPStr: - output.Write("lpstr"); - break; - case NativeType.Int: - output.Write("int"); - break; - case NativeType.UInt: - output.Write("unsigned int"); - break; - case NativeType.Func: - goto default; // ?? - case NativeType.Array: - ArrayMarshalInfo ami = (ArrayMarshalInfo)marshalInfo; - if (ami == null) - goto default; - if (ami.ElementType != NativeType.Max) - WriteNativeType(ami.ElementType); - output.Write('['); - if (ami.SizeParameterMultiplier == 0) { - output.Write(ami.Size.ToString()); - } else { - if (ami.Size >= 0) - output.Write(ami.Size.ToString()); - output.Write(" + "); - output.Write(ami.SizeParameterIndex.ToString()); - } - output.Write(']'); - break; - case NativeType.Currency: - output.Write("currency"); - break; - case NativeType.BStr: - output.Write("bstr"); - break; - case NativeType.LPWStr: - output.Write("lpwstr"); - break; - case NativeType.LPTStr: - output.Write("lptstr"); - break; - case NativeType.FixedSysString: - output.Write("fixed sysstring[{0}]", ((FixedSysStringMarshalInfo)marshalInfo).Size); - break; - case NativeType.IUnknown: - output.Write("iunknown"); - break; - case NativeType.IDispatch: - output.Write("idispatch"); - break; - case NativeType.Struct: - output.Write("struct"); - break; - case NativeType.IntF: - output.Write("interface"); - break; - case NativeType.SafeArray: - output.Write("safearray "); - SafeArrayMarshalInfo sami = marshalInfo as SafeArrayMarshalInfo; - if (sami != null) { - switch (sami.ElementType) { - case VariantType.None: - break; - case VariantType.I2: - output.Write("int16"); - break; - case VariantType.I4: - output.Write("int32"); - break; - case VariantType.R4: - output.Write("float32"); - break; - case VariantType.R8: - output.Write("float64"); - break; - case VariantType.CY: - output.Write("currency"); - break; - case VariantType.Date: - output.Write("date"); - break; - case VariantType.BStr: - output.Write("bstr"); - break; - case VariantType.Dispatch: - output.Write("idispatch"); - break; - case VariantType.Error: - output.Write("error"); - break; - case VariantType.Bool: - output.Write("bool"); - break; - case VariantType.Variant: - output.Write("variant"); - break; - case VariantType.Unknown: - output.Write("iunknown"); - break; - case VariantType.Decimal: - output.Write("decimal"); - break; - case VariantType.I1: - output.Write("int8"); - break; - case VariantType.UI1: - output.Write("unsigned int8"); - break; - case VariantType.UI2: - output.Write("unsigned int16"); - break; - case VariantType.UI4: - output.Write("unsigned int32"); - break; - case VariantType.Int: - output.Write("int"); - break; - case VariantType.UInt: - output.Write("unsigned int"); - break; - default: - output.Write(sami.ElementType.ToString()); - break; - } - } - break; - case NativeType.FixedArray: - output.Write("fixed array"); - FixedArrayMarshalInfo fami = marshalInfo as FixedArrayMarshalInfo; - if (fami != null) { - output.Write("[{0}]", fami.Size); - if (fami.ElementType != NativeType.None) { - output.Write(' '); - WriteNativeType(fami.ElementType); - } - } - break; - case NativeType.ByValStr: - output.Write("byvalstr"); - break; - case NativeType.ANSIBStr: - output.Write("ansi bstr"); - break; - case NativeType.TBStr: - output.Write("tbstr"); - break; - case NativeType.VariantBool: - output.Write("variant bool"); - break; - case NativeType.ASAny: - output.Write("as any"); - break; - case NativeType.LPStruct: - output.Write("lpstruct"); - break; - case NativeType.CustomMarshaler: - CustomMarshalInfo cmi = marshalInfo as CustomMarshalInfo; - if (cmi == null) - goto default; - output.Write("custom(\"{0}\", \"{1}\"", - NRefactory.CSharp.TextWriterTokenWriter.ConvertString(cmi.ManagedType.FullName), - NRefactory.CSharp.TextWriterTokenWriter.ConvertString(cmi.Cookie)); - if (cmi.Guid != Guid.Empty || !string.IsNullOrEmpty(cmi.UnmanagedType)) { - output.Write(", \"{0}\", \"{1}\"", cmi.Guid.ToString(), NRefactory.CSharp.TextWriterTokenWriter.ConvertString(cmi.UnmanagedType)); - } - output.Write(')'); - break; - case NativeType.Error: - output.Write("error"); - break; - default: - output.Write(nativeType.ToString()); - break; - } - } - #endregion - - void WriteParameters(Collection parameters) - { - for (int i = 0; i < parameters.Count; i++) { - var p = parameters[i]; - if (p.IsIn) - output.Write("[in] "); - if (p.IsOut) - output.Write("[out] "); - if (p.IsOptional) - output.Write("[opt] "); - p.ParameterType.WriteTo(output); - output.Write(' '); - if (p.HasMarshalInfo) { - WriteMarshalInfo(p.MarshalInfo); - } - output.WriteDefinition(DisassemblerHelpers.Escape(p.Name), p); - if (i < parameters.Count - 1) - output.Write(','); - output.WriteLine(); - } - } - - bool HasParameterAttributes(ParameterDefinition p) - { - return p.HasConstant || p.HasCustomAttributes; - } - - void WriteParameterAttributes(ParameterDefinition p) - { - if (!HasParameterAttributes(p)) - return; - output.Write(".param [{0}]", p.Index + 1); - if (p.HasConstant) { - output.Write(" = "); - WriteConstant(p.Constant); - } - output.WriteLine(); - WriteAttributes(p.CustomAttributes); - } - - void WriteConstant(object constant) - { - if (constant == null) { - output.Write("nullref"); - } else { - string typeName = DisassemblerHelpers.PrimitiveTypeName(constant.GetType().FullName); - if (typeName != null && typeName != "string") { - output.Write(typeName); - output.Write('('); - float? cf = constant as float?; - double? cd = constant as double?; - if (cf.HasValue && (float.IsNaN(cf.Value) || float.IsInfinity(cf.Value))) { - output.Write("0x{0:x8}", BitConverter.ToInt32(BitConverter.GetBytes(cf.Value), 0)); - } else if (cd.HasValue && (double.IsNaN(cd.Value) || double.IsInfinity(cd.Value))) { - output.Write("0x{0:x16}", BitConverter.DoubleToInt64Bits(cd.Value)); - } else { - DisassemblerHelpers.WriteOperand(output, constant); - } - output.Write(')'); - } else { - DisassemblerHelpers.WriteOperand(output, constant); - } - } - } - #endregion - - #region Disassemble Field - EnumNameCollection fieldVisibility = new EnumNameCollection() { - { FieldAttributes.Private, "private" }, - { FieldAttributes.FamANDAssem, "famandassem" }, - { FieldAttributes.Assembly, "assembly" }, - { FieldAttributes.Family, "family" }, - { FieldAttributes.FamORAssem, "famorassem" }, - { FieldAttributes.Public, "public" }, - }; - - EnumNameCollection fieldAttributes = new EnumNameCollection() { - { FieldAttributes.Static, "static" }, - { FieldAttributes.Literal, "literal" }, - { FieldAttributes.InitOnly, "initonly" }, - { FieldAttributes.SpecialName, "specialname" }, - { FieldAttributes.RTSpecialName, "rtspecialname" }, - { FieldAttributes.NotSerialized, "notserialized" }, - }; - - public void DisassembleField(FieldDefinition field) - { - output.WriteDefinition(".field ", field); - if (field.HasLayoutInfo) { - output.Write("[" + field.Offset + "] "); - } - WriteEnum(field.Attributes & FieldAttributes.FieldAccessMask, fieldVisibility); - const FieldAttributes hasXAttributes = FieldAttributes.HasDefault | FieldAttributes.HasFieldMarshal | FieldAttributes.HasFieldRVA; - WriteFlags(field.Attributes & ~(FieldAttributes.FieldAccessMask | hasXAttributes), fieldAttributes); - if (field.HasMarshalInfo) { - WriteMarshalInfo(field.MarshalInfo); - } - field.FieldType.WriteTo(output); - output.Write(' '); - output.Write(DisassemblerHelpers.Escape(field.Name)); - if ((field.Attributes & FieldAttributes.HasFieldRVA) == FieldAttributes.HasFieldRVA) { - output.Write(" at I_{0:x8}", field.RVA); - } - if (field.HasConstant) { - output.Write(" = "); - WriteConstant(field.Constant); - } - output.WriteLine(); - if (field.HasCustomAttributes) { - output.MarkFoldStart(); - WriteAttributes(field.CustomAttributes); - output.MarkFoldEnd(); - } - } - #endregion - - #region Disassemble Property - EnumNameCollection propertyAttributes = new EnumNameCollection() { - { PropertyAttributes.SpecialName, "specialname" }, - { PropertyAttributes.RTSpecialName, "rtspecialname" }, - { PropertyAttributes.HasDefault, "hasdefault" }, - }; - - public void DisassembleProperty(PropertyDefinition property) - { - // set current member - currentMember = property; - - output.WriteDefinition(".property ", property); - WriteFlags(property.Attributes, propertyAttributes); - if (property.HasThis) - output.Write("instance "); - property.PropertyType.WriteTo(output); - output.Write(' '); - output.Write(DisassemblerHelpers.Escape(property.Name)); - - output.Write("("); - if (property.HasParameters) { - output.WriteLine(); - output.Indent(); - WriteParameters(property.Parameters); - output.Unindent(); - } - output.Write(")"); - - OpenBlock(false); - WriteAttributes(property.CustomAttributes); - WriteNestedMethod(".get", property.GetMethod); - WriteNestedMethod(".set", property.SetMethod); - - foreach (var method in property.OtherMethods) { - WriteNestedMethod(".other", method); - } - CloseBlock(); - } - - void WriteNestedMethod(string keyword, MethodDefinition method) - { - if (method == null) - return; - - output.Write(keyword); - output.Write(' '); - method.WriteTo(output); - output.WriteLine(); - } - #endregion - - #region Disassemble Event - EnumNameCollection eventAttributes = new EnumNameCollection() { - { EventAttributes.SpecialName, "specialname" }, - { EventAttributes.RTSpecialName, "rtspecialname" }, - }; - - public void DisassembleEvent(EventDefinition ev) - { - // set current member - currentMember = ev; - - output.WriteDefinition(".event ", ev); - WriteFlags(ev.Attributes, eventAttributes); - ev.EventType.WriteTo(output, ILNameSyntax.TypeName); - output.Write(' '); - output.Write(DisassemblerHelpers.Escape(ev.Name)); - OpenBlock(false); - WriteAttributes(ev.CustomAttributes); - WriteNestedMethod(".addon", ev.AddMethod); - WriteNestedMethod(".removeon", ev.RemoveMethod); - WriteNestedMethod(".fire", ev.InvokeMethod); - foreach (var method in ev.OtherMethods) { - WriteNestedMethod(".other", method); - } - CloseBlock(); - } - #endregion - - #region Disassemble Type - EnumNameCollection typeVisibility = new EnumNameCollection() { - { TypeAttributes.Public, "public" }, - { TypeAttributes.NotPublic, "private" }, - { TypeAttributes.NestedPublic, "nested public" }, - { TypeAttributes.NestedPrivate, "nested private" }, - { TypeAttributes.NestedAssembly, "nested assembly" }, - { TypeAttributes.NestedFamily, "nested family" }, - { TypeAttributes.NestedFamANDAssem, "nested famandassem" }, - { TypeAttributes.NestedFamORAssem, "nested famorassem" }, - }; - - EnumNameCollection typeLayout = new EnumNameCollection() { - { TypeAttributes.AutoLayout, "auto" }, - { TypeAttributes.SequentialLayout, "sequential" }, - { TypeAttributes.ExplicitLayout, "explicit" }, - }; - - EnumNameCollection typeStringFormat = new EnumNameCollection() { - { TypeAttributes.AutoClass, "auto" }, - { TypeAttributes.AnsiClass, "ansi" }, - { TypeAttributes.UnicodeClass, "unicode" }, - }; - - EnumNameCollection typeAttributes = new EnumNameCollection() { - { TypeAttributes.Abstract, "abstract" }, - { TypeAttributes.Sealed, "sealed" }, - { TypeAttributes.SpecialName, "specialname" }, - { TypeAttributes.Import, "import" }, - { TypeAttributes.Serializable, "serializable" }, - { TypeAttributes.WindowsRuntime, "windowsruntime" }, - { TypeAttributes.BeforeFieldInit, "beforefieldinit" }, - { TypeAttributes.HasSecurity, null }, - }; - - public void DisassembleType(TypeDefinition type) - { - // start writing IL - output.WriteDefinition(".class ", type); - - if ((type.Attributes & TypeAttributes.ClassSemanticMask) == TypeAttributes.Interface) - output.Write("interface "); - WriteEnum(type.Attributes & TypeAttributes.VisibilityMask, typeVisibility); - WriteEnum(type.Attributes & TypeAttributes.LayoutMask, typeLayout); - WriteEnum(type.Attributes & TypeAttributes.StringFormatMask, typeStringFormat); - const TypeAttributes masks = TypeAttributes.ClassSemanticMask | TypeAttributes.VisibilityMask | TypeAttributes.LayoutMask | TypeAttributes.StringFormatMask; - WriteFlags(type.Attributes & ~masks, typeAttributes); - - output.Write(DisassemblerHelpers.Escape(type.DeclaringType != null ? type.Name : type.FullName)); - WriteTypeParameters(output, type); - output.MarkFoldStart(defaultCollapsed: isInType); - output.WriteLine(); - - if (type.BaseType != null) { - output.Indent(); - output.Write("extends "); - type.BaseType.WriteTo(output, ILNameSyntax.TypeName); - output.WriteLine(); - output.Unindent(); - } - if (type.HasInterfaces) { - output.Indent(); - for (int index = 0; index < type.Interfaces.Count; index++) { - if (index > 0) - output.WriteLine(","); - if (index == 0) - output.Write("implements "); - else - output.Write(" "); - type.Interfaces[index].WriteTo(output, ILNameSyntax.TypeName); - } - output.WriteLine(); - output.Unindent(); - } - - output.WriteLine("{"); - output.Indent(); - bool oldIsInType = isInType; - isInType = true; - WriteAttributes(type.CustomAttributes); - WriteSecurityDeclarations(type); - if (type.HasLayoutInfo) { - output.WriteLine(".pack {0}", type.PackingSize); - output.WriteLine(".size {0}", type.ClassSize); - output.WriteLine(); - } - if (type.HasNestedTypes) { - output.WriteLine("// Nested Types"); - foreach (var nestedType in type.NestedTypes) { - cancellationToken.ThrowIfCancellationRequested(); - DisassembleType(nestedType); - output.WriteLine(); - } - output.WriteLine(); - } - if (type.HasFields) { - output.WriteLine("// Fields"); - foreach (var field in type.Fields) { - cancellationToken.ThrowIfCancellationRequested(); - DisassembleField(field); - } - output.WriteLine(); - } - if (type.HasMethods) { - output.WriteLine("// Methods"); - foreach (var m in type.Methods) { - cancellationToken.ThrowIfCancellationRequested(); - DisassembleMethod(m); - output.WriteLine(); - } - } - if (type.HasEvents) { - output.WriteLine("// Events"); - foreach (var ev in type.Events) { - cancellationToken.ThrowIfCancellationRequested(); - DisassembleEvent(ev); - output.WriteLine(); - } - output.WriteLine(); - } - if (type.HasProperties) { - output.WriteLine("// Properties"); - foreach (var prop in type.Properties) { - cancellationToken.ThrowIfCancellationRequested(); - DisassembleProperty(prop); - } - output.WriteLine(); - } - CloseBlock("end of class " + (type.DeclaringType != null ? type.Name : type.FullName)); - isInType = oldIsInType; - } - - void WriteTypeParameters(ITextOutput output, IGenericParameterProvider p) - { - if (p.HasGenericParameters) { - output.Write('<'); - for (int i = 0; i < p.GenericParameters.Count; i++) { - if (i > 0) - output.Write(", "); - GenericParameter gp = p.GenericParameters[i]; - if (gp.HasReferenceTypeConstraint) { - output.Write("class "); - } else if (gp.HasNotNullableValueTypeConstraint) { - output.Write("valuetype "); - } - if (gp.HasDefaultConstructorConstraint) { - output.Write(".ctor "); - } - if (gp.HasConstraints) { - output.Write('('); - for (int j = 0; j < gp.Constraints.Count; j++) { - if (j > 0) - output.Write(", "); - gp.Constraints[j].WriteTo(output, ILNameSyntax.TypeName); - } - output.Write(") "); - } - if (gp.IsContravariant) { - output.Write('-'); - } else if (gp.IsCovariant) { - output.Write('+'); - } - output.Write(DisassemblerHelpers.Escape(gp.Name)); - } - output.Write('>'); - } - } - #endregion - - #region Helper methods - void WriteAttributes(Collection attributes) - { - foreach (CustomAttribute a in attributes) { - output.Write(".custom "); - a.Constructor.WriteTo(output); - byte[] blob = a.GetBlob(); - if (blob != null) { - output.Write(" = "); - WriteBlob(blob); - } - output.WriteLine(); - } - } - - void WriteBlob(byte[] blob) - { - output.Write("("); - output.Indent(); - - for (int i = 0; i < blob.Length; i++) { - if (i % 16 == 0 && i < blob.Length - 1) { - output.WriteLine(); - } else { - output.Write(' '); - } - output.Write(blob[i].ToString("x2")); - } - - output.WriteLine(); - output.Unindent(); - output.Write(")"); - } - - void OpenBlock(bool defaultCollapsed) - { - output.MarkFoldStart(defaultCollapsed: defaultCollapsed); - output.WriteLine(); - output.WriteLine("{"); - output.Indent(); - } - - void CloseBlock(string comment = null) - { - output.Unindent(); - output.Write("}"); - if (comment != null) - output.Write(" // " + comment); - output.MarkFoldEnd(); - output.WriteLine(); - } - - void WriteFlags(T flags, EnumNameCollection flagNames) where T : struct - { - long val = Convert.ToInt64(flags); - long tested = 0; - foreach (var pair in flagNames) { - tested |= pair.Key; - if ((val & pair.Key) != 0 && pair.Value != null) { - output.Write(pair.Value); - output.Write(' '); - } - } - if ((val & ~tested) != 0) - output.Write("flag({0:x4}) ", val & ~tested); - } - - void WriteEnum(T enumValue, EnumNameCollection enumNames) where T : struct - { - long val = Convert.ToInt64(enumValue); - foreach (var pair in enumNames) { - if (pair.Key == val) { - if (pair.Value != null) { - output.Write(pair.Value); - output.Write(' '); - } - return; - } - } - if (val != 0) { - output.Write("flag({0:x4})", val); - output.Write(' '); - } - - } - - sealed class EnumNameCollection : IEnumerable> where T : struct - { - List> names = new List>(); - - public void Add(T flag, string name) - { - names.Add(new KeyValuePair(Convert.ToInt64(flag), name)); - } - - public IEnumerator> GetEnumerator() - { - return names.GetEnumerator(); - } - - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() - { - return names.GetEnumerator(); - } - } - #endregion - - public void DisassembleNamespace(string nameSpace, IEnumerable types) - { - if (!string.IsNullOrEmpty(nameSpace)) { - output.Write(".namespace " + DisassemblerHelpers.Escape(nameSpace)); - OpenBlock(false); - } - bool oldIsInType = isInType; - isInType = true; - foreach (TypeDefinition td in types) { - cancellationToken.ThrowIfCancellationRequested(); - DisassembleType(td); - output.WriteLine(); - } - if (!string.IsNullOrEmpty(nameSpace)) { - CloseBlock(); - isInType = oldIsInType; - } - } - - public void WriteAssemblyHeader(AssemblyDefinition asm) - { - output.Write(".assembly "); - if (asm.Name.IsWindowsRuntime) - output.Write("windowsruntime "); - output.Write(DisassemblerHelpers.Escape(asm.Name.Name)); - OpenBlock(false); - WriteAttributes(asm.CustomAttributes); - WriteSecurityDeclarations(asm); - if (asm.Name.PublicKey != null && asm.Name.PublicKey.Length > 0) { - output.Write(".publickey = "); - WriteBlob(asm.Name.PublicKey); - output.WriteLine(); - } - if (asm.Name.HashAlgorithm != AssemblyHashAlgorithm.None) { - output.Write(".hash algorithm 0x{0:x8}", (int)asm.Name.HashAlgorithm); - if (asm.Name.HashAlgorithm == AssemblyHashAlgorithm.SHA1) - output.Write(" // SHA1"); - output.WriteLine(); - } - Version v = asm.Name.Version; - if (v != null) { - output.WriteLine(".ver {0}:{1}:{2}:{3}", v.Major, v.Minor, v.Build, v.Revision); - } - CloseBlock(); - } - - public void WriteAssemblyReferences(ModuleDefinition module) - { - foreach (var mref in module.ModuleReferences) { - output.WriteLine(".module extern {0}", DisassemblerHelpers.Escape(mref.Name)); - } - foreach (var aref in module.AssemblyReferences) { - output.Write(".assembly extern "); - if (aref.IsWindowsRuntime) - output.Write("windowsruntime "); - output.Write(DisassemblerHelpers.Escape(aref.Name)); - OpenBlock(false); - if (aref.PublicKeyToken != null) { - output.Write(".publickeytoken = "); - WriteBlob(aref.PublicKeyToken); - output.WriteLine(); - } - if (aref.Version != null) { - output.WriteLine(".ver {0}:{1}:{2}:{3}", aref.Version.Major, aref.Version.Minor, aref.Version.Build, aref.Version.Revision); - } - CloseBlock(); - } - } - - public void WriteModuleHeader(ModuleDefinition module) - { - if (module.HasExportedTypes) { - foreach (ExportedType exportedType in module.ExportedTypes) { - output.Write(".class extern "); - if (exportedType.IsForwarder) - output.Write("forwarder "); - output.Write(exportedType.DeclaringType != null ? exportedType.Name : exportedType.FullName); - OpenBlock(false); - if (exportedType.DeclaringType != null) - output.WriteLine(".class extern {0}", DisassemblerHelpers.Escape(exportedType.DeclaringType.FullName)); - else - output.WriteLine(".assembly extern {0}", DisassemblerHelpers.Escape(exportedType.Scope.Name)); - CloseBlock(); - } - } - - output.WriteLine(".module {0}", module.Name); - output.WriteLine("// MVID: {0}", module.Mvid.ToString("B").ToUpperInvariant()); - // TODO: imagebase, file alignment, stackreserve, subsystem - output.WriteLine(".corflags 0x{0:x} // {1}", module.Attributes, module.Attributes.ToString()); - - WriteAttributes(module.CustomAttributes); - } - - public void WriteModuleContents(ModuleDefinition module) - { - foreach (TypeDefinition td in module.Types) { - DisassembleType(td); - output.WriteLine(); - } - } - } -} diff --git a/ICSharpCode.Decompiler/FlowAnalysis/ControlFlowEdge.cs b/ICSharpCode.Decompiler/FlowAnalysis/ControlFlowEdge.cs deleted file mode 100644 index 98bd4399..00000000 --- a/ICSharpCode.Decompiler/FlowAnalysis/ControlFlowEdge.cs +++ /dev/null @@ -1,78 +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; - -namespace ICSharpCode.Decompiler.FlowAnalysis -{ - /// - /// Describes the type of a control flow egde. - /// - public enum JumpType - { - /// - /// A regular control flow edge. - /// - Normal, - /// - /// Jump to exception handler (an exception occurred) - /// - JumpToExceptionHandler, - /// - /// Jump from try block to leave target: - /// This is not a real jump, as the finally handler is executed first! - /// - LeaveTry, - /// - /// Jump at endfinally (to any of the potential leave targets). - /// For any leave-instruction, control flow enters the finally block - the edge to the leave target (LeaveTry) is not a real control flow edge. - /// EndFinally edges are inserted at the end of the finally block, jumping to any of the targets of the leave instruction. - /// This edge type is only used when copying of finally blocks is disabled (with copying, a normal deterministic edge is used at each copy of the endfinally node). - /// - EndFinally - } - - /// - /// Represents an edge in the control flow graph, pointing from Source to Target. - /// - public sealed class ControlFlowEdge - { - public readonly ControlFlowNode Source; - public readonly ControlFlowNode Target; - public readonly JumpType Type; - - public ControlFlowEdge(ControlFlowNode source, ControlFlowNode target, JumpType type) - { - Source = source; - Target = target; - Type = type; - } - - public override string ToString() - { - switch (Type) { - case JumpType.Normal: - return "#" + Target.BlockIndex; - case JumpType.JumpToExceptionHandler: - return "e:#" + Target.BlockIndex; - default: - return Type.ToString() + ":#" + Target.BlockIndex; - } - } - } -} diff --git a/ICSharpCode.Decompiler/FlowAnalysis/ControlFlowGraph.cs b/ICSharpCode.Decompiler/FlowAnalysis/ControlFlowGraph.cs deleted file mode 100644 index 7cc815a6..00000000 --- a/ICSharpCode.Decompiler/FlowAnalysis/ControlFlowGraph.cs +++ /dev/null @@ -1,191 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Diagnostics; -using System.Linq; -using System.Threading; - -using ICSharpCode.NRefactory.Utils; - -namespace ICSharpCode.Decompiler.FlowAnalysis -{ - /// - /// Contains the control flow graph. - /// - /// Use ControlFlowGraph builder to create instances of the ControlFlowGraph. - public sealed class ControlFlowGraph - { - readonly ReadOnlyCollection nodes; - - public ControlFlowNode EntryPoint { - get { return nodes[0]; } - } - - public ControlFlowNode RegularExit { - get { return nodes[1]; } - } - - public ControlFlowNode ExceptionalExit { - get { return nodes[2]; } - } - - public ReadOnlyCollection Nodes { - get { return nodes; } - } - - internal ControlFlowGraph(ControlFlowNode[] nodes) - { - this.nodes = new ReadOnlyCollection(nodes); - Debug.Assert(EntryPoint.NodeType == ControlFlowNodeType.EntryPoint); - Debug.Assert(RegularExit.NodeType == ControlFlowNodeType.RegularExit); - Debug.Assert(ExceptionalExit.NodeType == ControlFlowNodeType.ExceptionalExit); - } - - public GraphVizGraph ExportGraph() - { - GraphVizGraph graph = new GraphVizGraph(); - foreach (ControlFlowNode node in nodes) { - graph.AddNode(new GraphVizNode(node.BlockIndex) { label = node.ToString(), shape = "box" }); - } - foreach (ControlFlowNode node in nodes) { - foreach (ControlFlowEdge edge in node.Outgoing) { - GraphVizEdge e = new GraphVizEdge(edge.Source.BlockIndex, edge.Target.BlockIndex); - switch (edge.Type) { - case JumpType.Normal: - break; - case JumpType.LeaveTry: - case JumpType.EndFinally: - e.color = "red"; - break; - default: - e.color = "gray"; - //e.constraint = false; - break; - } - graph.AddEdge(e); - } - if (node.ImmediateDominator != null) { - graph.AddEdge(new GraphVizEdge(node.ImmediateDominator.BlockIndex, node.BlockIndex) { color = "green", constraint = false }); - } - } - return graph; - } - - /// - /// Resets "Visited" to false for all nodes in this graph. - /// - public void ResetVisited() - { - foreach (ControlFlowNode node in nodes) { - node.Visited = false; - } - } - - /// - /// Computes the dominator tree. - /// - public void ComputeDominance(CancellationToken cancellationToken = default(CancellationToken)) - { - // A Simple, Fast Dominance Algorithm - // Keith D. Cooper, Timothy J. Harvey and Ken Kennedy - - EntryPoint.ImmediateDominator = EntryPoint; - bool changed = true; - while (changed) { - changed = false; - ResetVisited(); - - cancellationToken.ThrowIfCancellationRequested(); - - // for all nodes b except the entry point - EntryPoint.TraversePreOrder( - b => b.Successors, - b => { - if (b != EntryPoint) { - ControlFlowNode newIdom = b.Predecessors.First(block => block.Visited && block != b); - // for all other predecessors p of b - foreach (ControlFlowNode p in b.Predecessors) { - if (p != b && p.ImmediateDominator != null) { - newIdom = FindCommonDominator(p, newIdom); - } - } - if (b.ImmediateDominator != newIdom) { - b.ImmediateDominator = newIdom; - changed = true; - } - } - }); - } - EntryPoint.ImmediateDominator = null; - foreach (ControlFlowNode node in nodes) { - if (node.ImmediateDominator != null) - node.ImmediateDominator.DominatorTreeChildren.Add(node); - } - } - - static ControlFlowNode FindCommonDominator(ControlFlowNode b1, ControlFlowNode b2) - { - // Here we could use the postorder numbers to get rid of the hashset, see "A Simple, Fast Dominance Algorithm" - HashSet path1 = new HashSet(); - while (b1 != null && path1.Add(b1)) - b1 = b1.ImmediateDominator; - while (b2 != null) { - if (path1.Contains(b2)) - return b2; - else - b2 = b2.ImmediateDominator; - } - throw new Exception("No common dominator found!"); - } - - /// - /// Computes dominance frontiers. - /// This method requires that the dominator tree is already computed! - /// - public void ComputeDominanceFrontier() - { - ResetVisited(); - - EntryPoint.TraversePostOrder( - b => b.DominatorTreeChildren, - n => { - //logger.WriteLine("Calculating dominance frontier for " + n.Name); - n.DominanceFrontier = new HashSet(); - // DF_local computation - foreach (ControlFlowNode succ in n.Successors) { - if (succ.ImmediateDominator != n) { - //logger.WriteLine(" local: " + succ.Name); - n.DominanceFrontier.Add(succ); - } - } - // DF_up computation - foreach (ControlFlowNode child in n.DominatorTreeChildren) { - foreach (ControlFlowNode p in child.DominanceFrontier) { - if (p.ImmediateDominator != n) { - //logger.WriteLine(" DF_up: " + p.Name + " (child=" + child.Name); - n.DominanceFrontier.Add(p); - } - } - } - }); - } - } -} diff --git a/ICSharpCode.Decompiler/FlowAnalysis/ControlFlowGraphBuilder.cs b/ICSharpCode.Decompiler/FlowAnalysis/ControlFlowGraphBuilder.cs deleted file mode 100644 index 7570884a..00000000 --- a/ICSharpCode.Decompiler/FlowAnalysis/ControlFlowGraphBuilder.cs +++ /dev/null @@ -1,439 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; - -using Mono.Cecil.Cil; - -namespace ICSharpCode.Decompiler.FlowAnalysis -{ - /// - /// Constructs the Control Flow Graph from a Cecil method body. - /// - public sealed class ControlFlowGraphBuilder - { - public static ControlFlowGraph Build(MethodBody methodBody) - { - return new ControlFlowGraphBuilder(methodBody).Build(); - } - - // This option controls how finally blocks are handled: - // false means that the endfinally instruction will jump to any of the leave targets (EndFinally edge type). - // true means that a copy of the whole finally block is created for each leave target. In this case, each endfinally node will be connected with the leave - // target using a normal edge. - bool copyFinallyBlocks = false; - - MethodBody methodBody; - int[] offsets; // array index = instruction index; value = IL offset - bool[] hasIncomingJumps; // array index = instruction index - List nodes = new List(); - ControlFlowNode entryPoint; - ControlFlowNode regularExit; - ControlFlowNode exceptionalExit; - - ControlFlowGraphBuilder(MethodBody methodBody) - { - this.methodBody = methodBody; - offsets = methodBody.Instructions.Select(i => i.Offset).ToArray(); - hasIncomingJumps = new bool[methodBody.Instructions.Count]; - - entryPoint = new ControlFlowNode(0, 0, ControlFlowNodeType.EntryPoint); - nodes.Add(entryPoint); - regularExit = new ControlFlowNode(1, -1, ControlFlowNodeType.RegularExit); - nodes.Add(regularExit); - exceptionalExit = new ControlFlowNode(2, -1, ControlFlowNodeType.ExceptionalExit); - nodes.Add(exceptionalExit); - Debug.Assert(nodes.Count == 3); - } - - /// - /// Determines the index of the instruction (for use with the hasIncomingJumps array) - /// - int GetInstructionIndex(Instruction inst) - { - int index = Array.BinarySearch(offsets, inst.Offset); - Debug.Assert(index >= 0); - return index; - } - - /// - /// Builds the ControlFlowGraph. - /// - public ControlFlowGraph Build() - { - CalculateHasIncomingJumps(); - CreateNodes(); - CreateRegularControlFlow(); - CreateExceptionalControlFlow(); - if (copyFinallyBlocks) - CopyFinallyBlocksIntoLeaveEdges(); - else - TransformLeaveEdges(); - return new ControlFlowGraph(nodes.ToArray()); - } - - #region Step 1: calculate which instructions are the targets of jump instructions. - void CalculateHasIncomingJumps() - { - foreach (Instruction inst in methodBody.Instructions) { - if (inst.OpCode.OperandType == OperandType.InlineBrTarget || inst.OpCode.OperandType == OperandType.ShortInlineBrTarget) { - hasIncomingJumps[GetInstructionIndex((Instruction)inst.Operand)] = true; - } else if (inst.OpCode.OperandType == OperandType.InlineSwitch) { - foreach (Instruction i in (Instruction[])inst.Operand) - hasIncomingJumps[GetInstructionIndex(i)] = true; - } - } - foreach (ExceptionHandler eh in methodBody.ExceptionHandlers) { - if (eh.FilterStart != null) { - hasIncomingJumps[GetInstructionIndex(eh.FilterStart)] = true; - } - hasIncomingJumps[GetInstructionIndex(eh.HandlerStart)] = true; - } - } - #endregion - - #region Step 2: create nodes - void CreateNodes() - { - // Step 2a: find basic blocks and create nodes for them - for (int i = 0; i < methodBody.Instructions.Count; i++) { - Instruction blockStart = methodBody.Instructions[i]; - ExceptionHandler blockStartEH = FindInnermostExceptionHandler(blockStart.Offset); - // try and see how big we can make that block: - for (; i + 1 < methodBody.Instructions.Count; i++) { - Instruction inst = methodBody.Instructions[i]; - if (IsBranch(inst.OpCode) || CanThrowException(inst.OpCode)) - break; - if (hasIncomingJumps[i + 1]) - break; - if (inst.Next != null) { - // ensure that blocks never contain instructions from different try blocks - ExceptionHandler instEH = FindInnermostExceptionHandler(inst.Next.Offset); - if (instEH != blockStartEH) - break; - } - } - - nodes.Add(new ControlFlowNode(nodes.Count, blockStart, methodBody.Instructions[i])); - } - // Step 2b: Create special nodes for the exception handling constructs - foreach (ExceptionHandler handler in methodBody.ExceptionHandlers) { - if (handler.HandlerType == ExceptionHandlerType.Filter) - throw new NotSupportedException(); - ControlFlowNode endFinallyOrFaultNode = null; - if (handler.HandlerType == ExceptionHandlerType.Finally || handler.HandlerType == ExceptionHandlerType.Fault) { - endFinallyOrFaultNode = new ControlFlowNode(nodes.Count, handler.HandlerEnd.Offset, ControlFlowNodeType.EndFinallyOrFault); - nodes.Add(endFinallyOrFaultNode); - } - nodes.Add(new ControlFlowNode(nodes.Count, handler, endFinallyOrFaultNode)); - } - } - #endregion - - #region Step 3: create edges for the normal flow of control (assuming no exceptions thrown) - void CreateRegularControlFlow() - { - CreateEdge(entryPoint, methodBody.Instructions[0], JumpType.Normal); - foreach (ControlFlowNode node in nodes) { - if (node.End != null) { - // create normal edges from one instruction to the next - if (!OpCodeInfo.IsUnconditionalBranch(node.End.OpCode)) - CreateEdge(node, node.End.Next, JumpType.Normal); - - // create edges for branch instructions - if (node.End.OpCode.OperandType == OperandType.InlineBrTarget || node.End.OpCode.OperandType == OperandType.ShortInlineBrTarget) { - if (node.End.OpCode == OpCodes.Leave || node.End.OpCode == OpCodes.Leave_S) { - var handlerBlock = FindInnermostHandlerBlock(node.End.Offset); - if (handlerBlock.NodeType == ControlFlowNodeType.FinallyOrFaultHandler) - CreateEdge(node, (Instruction)node.End.Operand, JumpType.LeaveTry); - else - CreateEdge(node, (Instruction)node.End.Operand, JumpType.Normal); - } else { - CreateEdge(node, (Instruction)node.End.Operand, JumpType.Normal); - } - } else if (node.End.OpCode.OperandType == OperandType.InlineSwitch) { - foreach (Instruction i in (Instruction[])node.End.Operand) - CreateEdge(node, i, JumpType.Normal); - } - - // create edges for return instructions - if (node.End.OpCode.FlowControl == FlowControl.Return) { - switch (node.End.OpCode.Code) { - case Code.Ret: - CreateEdge(node, regularExit, JumpType.Normal); - break; - case Code.Endfinally: - ControlFlowNode handlerBlock = FindInnermostHandlerBlock(node.End.Offset); - if (handlerBlock.EndFinallyOrFaultNode == null) - throw new InvalidProgramException("Found endfinally in block " + handlerBlock); - CreateEdge(node, handlerBlock.EndFinallyOrFaultNode, JumpType.Normal); - break; - default: - throw new NotSupportedException(node.End.OpCode.ToString()); - } - } - } - } - } - #endregion - - #region Step 4: create edges for the exceptional control flow (from instructions that might throw, to the innermost containing exception handler) - void CreateExceptionalControlFlow() - { - foreach (ControlFlowNode node in nodes) { - if (node.End != null && CanThrowException(node.End.OpCode)) { - CreateEdge(node, FindInnermostExceptionHandlerNode(node.End.Offset), JumpType.JumpToExceptionHandler); - } - if (node.ExceptionHandler != null) { - if (node.EndFinallyOrFaultNode != null) { - // For Fault and Finally blocks, create edge from "EndFinally" to next exception handler. - // This represents the exception bubbling up after finally block was executed. - CreateEdge(node.EndFinallyOrFaultNode, FindParentExceptionHandlerNode(node), JumpType.JumpToExceptionHandler); - } else { - // For Catch blocks, create edge from "CatchHandler" block (at beginning) to next exception handler. - // This represents the exception bubbling up because it did not match the type of the catch block. - CreateEdge(node, FindParentExceptionHandlerNode(node), JumpType.JumpToExceptionHandler); - } - CreateEdge(node, node.ExceptionHandler.HandlerStart, JumpType.Normal); - } - } - } - - ExceptionHandler FindInnermostExceptionHandler(int instructionOffsetInTryBlock) - { - foreach (ExceptionHandler h in methodBody.ExceptionHandlers) { - if (h.TryStart.Offset <= instructionOffsetInTryBlock && instructionOffsetInTryBlock < h.TryEnd.Offset) { - return h; - } - } - return null; - } - - ControlFlowNode FindInnermostExceptionHandlerNode(int instructionOffsetInTryBlock) - { - ExceptionHandler h = FindInnermostExceptionHandler(instructionOffsetInTryBlock); - if (h != null) - return nodes.Single(n => n.ExceptionHandler == h && n.CopyFrom == null); - else - return exceptionalExit; - } - - ControlFlowNode FindInnermostHandlerBlock(int instructionOffset) - { - foreach (ExceptionHandler h in methodBody.ExceptionHandlers) { - if (h.TryStart.Offset <= instructionOffset && instructionOffset < h.TryEnd.Offset - || h.HandlerStart.Offset <= instructionOffset && instructionOffset < h.HandlerEnd.Offset) - { - return nodes.Single(n => n.ExceptionHandler == h && n.CopyFrom == null); - } - } - return exceptionalExit; - } - - ControlFlowNode FindParentExceptionHandlerNode(ControlFlowNode exceptionHandler) - { - Debug.Assert(exceptionHandler.NodeType == ControlFlowNodeType.CatchHandler - || exceptionHandler.NodeType == ControlFlowNodeType.FinallyOrFaultHandler); - int offset = exceptionHandler.ExceptionHandler.TryStart.Offset; - for (int i = exceptionHandler.BlockIndex + 1; i < nodes.Count; i++) { - ExceptionHandler h = nodes[i].ExceptionHandler; - if (h != null && h.TryStart.Offset <= offset && offset < h.TryEnd.Offset) - return nodes[i]; - } - return exceptionalExit; - } - #endregion - - #region Step 5a: replace LeaveTry edges with EndFinally edges - // this is used only for copyFinallyBlocks==false; see Step 5b otherwise - void TransformLeaveEdges() - { - for (int i = nodes.Count - 1; i >= 0; i--) { - ControlFlowNode node = nodes[i]; - if (node.End != null && node.Outgoing.Count == 1 && node.Outgoing[0].Type == JumpType.LeaveTry) { - Debug.Assert(node.End.OpCode == OpCodes.Leave || node.End.OpCode == OpCodes.Leave_S); - - ControlFlowNode target = node.Outgoing[0].Target; - // remove the edge - target.Incoming.Remove(node.Outgoing[0]); - node.Outgoing.Clear(); - - ControlFlowNode handler = FindInnermostExceptionHandlerNode(node.End.Offset); - Debug.Assert(handler.NodeType == ControlFlowNodeType.FinallyOrFaultHandler); - - CreateEdge(node, handler, JumpType.Normal); - CreateEdge(handler.EndFinallyOrFaultNode, target, JumpType.EndFinally); - } - } - } - #endregion - - #region Step 5b: copy finally blocks into the LeaveTry edges - void CopyFinallyBlocksIntoLeaveEdges() - { - // We need to process try-finally blocks inside-out. - // We'll do that by going through all instructions in reverse order - for (int i = nodes.Count - 1; i >= 0; i--) { - ControlFlowNode node = nodes[i]; - if (node.End != null && node.Outgoing.Count == 1 && node.Outgoing[0].Type == JumpType.LeaveTry) { - Debug.Assert(node.End.OpCode == OpCodes.Leave || node.End.OpCode == OpCodes.Leave_S); - - ControlFlowNode target = node.Outgoing[0].Target; - // remove the edge - target.Incoming.Remove(node.Outgoing[0]); - node.Outgoing.Clear(); - - ControlFlowNode handler = FindInnermostExceptionHandlerNode(node.End.Offset); - Debug.Assert(handler.NodeType == ControlFlowNodeType.FinallyOrFaultHandler); - - ControlFlowNode copy = CopyFinallySubGraph(handler, handler.EndFinallyOrFaultNode, target); - CreateEdge(node, copy, JumpType.Normal); - } - } - } - - /// - /// Creates a copy of all nodes pointing to 'end' and replaces those references with references to 'newEnd'. - /// Nodes pointing to the copied node are copied recursively to update those references, too. - /// This recursion stops at 'start'. The modified version of start is returned. - /// - ControlFlowNode CopyFinallySubGraph(ControlFlowNode start, ControlFlowNode end, ControlFlowNode newEnd) - { - return new CopyFinallySubGraphLogic(this, start, end, newEnd).CopyFinallySubGraph(); - } - - class CopyFinallySubGraphLogic - { - readonly ControlFlowGraphBuilder builder; - readonly Dictionary oldToNew = new Dictionary(); - readonly ControlFlowNode start; - readonly ControlFlowNode end; - readonly ControlFlowNode newEnd; - - public CopyFinallySubGraphLogic(ControlFlowGraphBuilder builder, ControlFlowNode start, ControlFlowNode end, ControlFlowNode newEnd) - { - this.builder = builder; - this.start = start; - this.end = end; - this.newEnd = newEnd; - } - - internal ControlFlowNode CopyFinallySubGraph() - { - foreach (ControlFlowNode n in end.Predecessors) { - CollectNodes(n); - } - foreach (var pair in oldToNew) - ReconstructEdges(pair.Key, pair.Value); - return GetNew(start); - } - - void CollectNodes(ControlFlowNode node) - { - if (node == end || node == newEnd) - throw new InvalidOperationException("unexpected cycle involving finally construct"); - if (!oldToNew.ContainsKey(node)) { - int newBlockIndex = builder.nodes.Count; - ControlFlowNode copy; - switch (node.NodeType) { - case ControlFlowNodeType.Normal: - copy = new ControlFlowNode(newBlockIndex, node.Start, node.End); - break; - case ControlFlowNodeType.FinallyOrFaultHandler: - copy = new ControlFlowNode(newBlockIndex, node.ExceptionHandler, node.EndFinallyOrFaultNode); - break; - default: - // other nodes shouldn't occur when copying finally blocks - throw new NotSupportedException(node.NodeType.ToString()); - } - copy.CopyFrom = node; - builder.nodes.Add(copy); - oldToNew.Add(node, copy); - - if (node != start) { - foreach (ControlFlowNode n in node.Predecessors) { - CollectNodes(n); - } - } - } - } - - void ReconstructEdges(ControlFlowNode oldNode, ControlFlowNode newNode) - { - foreach (ControlFlowEdge oldEdge in oldNode.Outgoing) { - builder.CreateEdge(newNode, GetNew(oldEdge.Target), oldEdge.Type); - } - } - - ControlFlowNode GetNew(ControlFlowNode oldNode) - { - if (oldNode == end) - return newEnd; - ControlFlowNode newNode; - if (oldToNew.TryGetValue(oldNode, out newNode)) - return newNode; - return oldNode; - } - } - #endregion - - #region CreateEdge methods - void CreateEdge(ControlFlowNode fromNode, Instruction toInstruction, JumpType type) - { - CreateEdge(fromNode, nodes.Single(n => n.Start == toInstruction), type); - } - - void CreateEdge(ControlFlowNode fromNode, ControlFlowNode toNode, JumpType type) - { - ControlFlowEdge edge = new ControlFlowEdge(fromNode, toNode, type); - fromNode.Outgoing.Add(edge); - toNode.Incoming.Add(edge); - } - #endregion - - #region OpCode info - static bool CanThrowException(OpCode opcode) - { - if (opcode.OpCodeType == OpCodeType.Prefix) - return false; - return OpCodeInfo.Get(opcode).CanThrow; - } - - static bool IsBranch(OpCode opcode) - { - if (opcode.OpCodeType == OpCodeType.Prefix) - return false; - switch (opcode.FlowControl) { - case FlowControl.Cond_Branch: - case FlowControl.Branch: - case FlowControl.Throw: - case FlowControl.Return: - return true; - case FlowControl.Next: - case FlowControl.Call: - return false; - default: - throw new NotSupportedException(opcode.FlowControl.ToString()); - } - } - #endregion - } -} diff --git a/ICSharpCode.Decompiler/FlowAnalysis/ControlFlowNode.cs b/ICSharpCode.Decompiler/FlowAnalysis/ControlFlowNode.cs deleted file mode 100644 index 83294fd9..00000000 --- a/ICSharpCode.Decompiler/FlowAnalysis/ControlFlowNode.cs +++ /dev/null @@ -1,305 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; - -using ICSharpCode.Decompiler.Disassembler; -using Mono.Cecil.Cil; - -namespace ICSharpCode.Decompiler.FlowAnalysis -{ - /// - /// Type of the control flow node - /// - public enum ControlFlowNodeType - { - /// - /// A normal node represents a basic block. - /// - Normal, - /// - /// The entry point of the method. - /// - EntryPoint, - /// - /// The exit point of the method (every ret instruction branches to this node) - /// - RegularExit, - /// - /// This node represents leaving a method irregularly by throwing an exception. - /// - ExceptionalExit, - /// - /// This node is used as a header for exception handler blocks. - /// - CatchHandler, - /// - /// This node is used as a header for finally blocks and fault blocks. - /// Every leave instruction in the try block leads to the handler of the containing finally block; - /// and exceptional control flow also leads to this handler. - /// - FinallyOrFaultHandler, - /// - /// This node is used as footer for finally blocks and fault blocks. - /// Depending on the "copyFinallyBlocks" option used when creating the graph, it is connected with all leave targets using - /// EndFinally edges (when not copying); or with a specific leave target using a normal edge (when copying). - /// For fault blocks, an exception edge is used to represent the "re-throwing" of the exception. - /// - EndFinallyOrFault - } - - /// - /// Represents a block in the control flow graph. - /// - public sealed class ControlFlowNode - { - /// - /// Index of this node in the ControlFlowGraph.Nodes collection. - /// - public readonly int BlockIndex; - - /// - /// Gets the IL offset of this node. - /// - public readonly int Offset; - - /// - /// Type of the node. - /// - public readonly ControlFlowNodeType NodeType; - - /// - /// If this node is a FinallyOrFaultHandler node, this field points to the corresponding EndFinallyOrFault node. - /// Otherwise, this field is null. - /// - public readonly ControlFlowNode EndFinallyOrFaultNode; - - /// - /// Visited flag, used in various algorithms. - /// Before using it in your algorithm, reset it to false by calling ControlFlowGraph.ResetVisited(); - /// - public bool Visited; - - /// - /// Gets whether this node is reachable. Requires that dominance is computed! - /// - public bool IsReachable { - get { return ImmediateDominator != null || NodeType == ControlFlowNodeType.EntryPoint; } - } - - /// - /// Signalizes that this node is a copy of another node. - /// - public ControlFlowNode CopyFrom { get; internal set; } - - /// - /// Gets the immediate dominator (the parent in the dominator tree). - /// Null if dominance has not been calculated; or if the node is unreachable. - /// - public ControlFlowNode ImmediateDominator { get; internal set; } - - /// - /// List of children in the dominator tree. - /// - public readonly List DominatorTreeChildren = new List(); - - /// - /// The dominance frontier of this node. - /// This is the set of nodes for which this node dominates a predecessor, but which are not strictly dominated by this node. - /// - /// - /// b.DominanceFrontier = { y in CFG; (exists p in predecessors(y): b dominates p) and not (b strictly dominates y)} - /// - public HashSet DominanceFrontier; - - /// - /// Start of code block represented by this node. Only set for nodetype == Normal. - /// - public readonly Instruction Start; - - /// - /// End of the code block represented by this node. Only set for nodetype == Normal. - /// The end is exclusive, the end instruction itself does not belong to this block. - /// - public readonly Instruction End; - - /// - /// Gets the exception handler associated with this node. - /// Only set for nodetype == CatchHandler or nodetype == FinallyOrFaultHandler. - /// - public readonly ExceptionHandler ExceptionHandler; - - /// - /// List of incoming control flow edges. - /// - public readonly List Incoming = new List(); - - /// - /// List of outgoing control flow edges. - /// - public readonly List Outgoing = new List(); - - /// - /// Any user data - /// - public object UserData; - - internal ControlFlowNode(int blockIndex, int offset, ControlFlowNodeType nodeType) - { - BlockIndex = blockIndex; - Offset = offset; - NodeType = nodeType; - } - - internal ControlFlowNode(int blockIndex, Instruction start, Instruction end) - { - if (start == null) - throw new ArgumentNullException("start"); - if (end == null) - throw new ArgumentNullException("end"); - BlockIndex = blockIndex; - NodeType = ControlFlowNodeType.Normal; - Start = start; - End = end; - Offset = start.Offset; - } - - internal ControlFlowNode(int blockIndex, ExceptionHandler exceptionHandler, ControlFlowNode endFinallyOrFaultNode) - { - BlockIndex = blockIndex; - NodeType = endFinallyOrFaultNode != null ? ControlFlowNodeType.FinallyOrFaultHandler : ControlFlowNodeType.CatchHandler; - ExceptionHandler = exceptionHandler; - EndFinallyOrFaultNode = endFinallyOrFaultNode; - Debug.Assert((exceptionHandler.HandlerType == ExceptionHandlerType.Finally || exceptionHandler.HandlerType == ExceptionHandlerType.Fault) == (endFinallyOrFaultNode != null)); - Offset = exceptionHandler.HandlerStart.Offset; - } - - /// - /// Gets all predecessors (=sources of incoming edges) - /// - public IEnumerable Predecessors { - get { - return Incoming.Select(e => e.Source); - } - } - - /// - /// Gets all successors (=targets of outgoing edges) - /// - public IEnumerable Successors { - get { - return Outgoing.Select(e => e.Target); - } - } - - /// - /// Gets all instructions in this node. - /// Returns an empty list for special nodes that don't have any instructions. - /// - public IEnumerable Instructions { - get { - Instruction inst = Start; - if (inst != null) { - yield return inst; - while (inst != End) { - inst = inst.Next; - yield return inst; - } - } - } - } - - public void TraversePreOrder(Func> children, Action visitAction) - { - if (Visited) - return; - Visited = true; - visitAction(this); - foreach (ControlFlowNode t in children(this)) - t.TraversePreOrder(children, visitAction); - } - - public void TraversePostOrder(Func> children, Action visitAction) - { - if (Visited) - return; - Visited = true; - foreach (ControlFlowNode t in children(this)) - t.TraversePostOrder(children, visitAction); - visitAction(this); - } - - public override string ToString() - { - StringWriter writer = new StringWriter(); - switch (NodeType) { - case ControlFlowNodeType.Normal: - writer.Write("Block #{0}", BlockIndex); - if (Start != null) - writer.Write(": IL_{0:x4}", Start.Offset); - if (End != null) - writer.Write(" to IL_{0:x4}", End.GetEndOffset()); - break; - case ControlFlowNodeType.CatchHandler: - case ControlFlowNodeType.FinallyOrFaultHandler: - writer.Write("Block #{0}: {1}: ", BlockIndex, NodeType); - DisassemblerHelpers.WriteTo(ExceptionHandler, new PlainTextOutput(writer)); - break; - default: - writer.Write("Block #{0}: {1}", BlockIndex, NodeType); - break; - } -// if (ImmediateDominator != null) { -// writer.WriteLine(); -// writer.Write("ImmediateDominator: #{0}", ImmediateDominator.BlockIndex); -// } - if (DominanceFrontier != null && DominanceFrontier.Any()) { - writer.WriteLine(); - writer.Write("DominanceFrontier: " + string.Join(",", DominanceFrontier.OrderBy(d => d.BlockIndex).Select(d => d.BlockIndex.ToString()))); - } - foreach (Instruction inst in Instructions) { - writer.WriteLine(); - DisassemblerHelpers.WriteTo(inst, new PlainTextOutput(writer)); - } - if (UserData != null) { - writer.WriteLine(); - writer.Write(UserData.ToString()); - } - return writer.ToString(); - } - - /// - /// Gets whether this dominates . - /// - public bool Dominates(ControlFlowNode node) - { - // TODO: this can be made O(1) by numbering the dominator tree - ControlFlowNode tmp = node; - while (tmp != null) { - if (tmp == this) - return true; - tmp = tmp.ImmediateDominator; - } - return false; - } - } -} diff --git a/ICSharpCode.Decompiler/FlowAnalysis/ControlStructureDetector.cs b/ICSharpCode.Decompiler/FlowAnalysis/ControlStructureDetector.cs deleted file mode 100644 index b7b77e07..00000000 --- a/ICSharpCode.Decompiler/FlowAnalysis/ControlStructureDetector.cs +++ /dev/null @@ -1,241 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Threading; -using Mono.Cecil.Cil; - -namespace ICSharpCode.Decompiler.FlowAnalysis -{ - /// - /// Detects the structure of the control flow (exception blocks and loops). - /// - public class ControlStructureDetector - { - public static ControlStructure DetectStructure(ControlFlowGraph g, IEnumerable exceptionHandlers, CancellationToken cancellationToken) - { - ControlStructure root = new ControlStructure(new HashSet(g.Nodes), g.EntryPoint, ControlStructureType.Root); - // First build a structure tree out of the exception table - DetectExceptionHandling(root, g, exceptionHandlers); - // Then run the loop detection. - DetectLoops(g, root, cancellationToken); - return root; - } - - #region Exception Handling - static void DetectExceptionHandling(ControlStructure current, ControlFlowGraph g, IEnumerable exceptionHandlers) - { - // We rely on the fact that the exception handlers are sorted so that the innermost come first. - // For each exception handler, we determine the nodes and substructures inside that handler, and move them into a new substructure. - // This is always possible because exception handlers are guaranteed (by the CLR spec) to be properly nested and non-overlapping; - // so they directly form the tree that we need. - foreach (ExceptionHandler eh in exceptionHandlers) { - var tryNodes = FindNodes(current, eh.TryStart, eh.TryEnd); - current.Nodes.ExceptWith(tryNodes); - ControlStructure tryBlock = new ControlStructure( - tryNodes, - g.Nodes.Single(n => n.Start == eh.TryStart), - ControlStructureType.Try); - tryBlock.ExceptionHandler = eh; - MoveControlStructures(current, tryBlock, eh.TryStart, eh.TryEnd); - current.Children.Add(tryBlock); - - if (eh.FilterStart != null) { - throw new NotSupportedException(); - } - - var handlerNodes = FindNodes(current, eh.HandlerStart, eh.HandlerEnd); - var handlerNode = current.Nodes.Single(n => n.ExceptionHandler == eh); - handlerNodes.Add(handlerNode); - if (handlerNode.EndFinallyOrFaultNode != null) - handlerNodes.Add(handlerNode.EndFinallyOrFaultNode); - current.Nodes.ExceptWith(handlerNodes); - ControlStructure handlerBlock = new ControlStructure( - handlerNodes, handlerNode, ControlStructureType.Handler); - handlerBlock.ExceptionHandler = eh; - MoveControlStructures(current, handlerBlock, eh.HandlerStart, eh.HandlerEnd); - current.Children.Add(handlerBlock); - } - } - - /// - /// Removes all nodes from start to end (exclusive) from this ControlStructure and moves them to the target structure. - /// - static HashSet FindNodes(ControlStructure current, Instruction startInst, Instruction endInst) - { - HashSet result = new HashSet(); - int start = startInst.Offset; - int end = endInst.Offset; - foreach (var node in current.Nodes.ToArray()) { - if (node.Start != null && start <= node.Start.Offset && node.Start.Offset < end) { - result.Add(node); - } - } - return result; - } - - static void MoveControlStructures(ControlStructure current, ControlStructure target, Instruction startInst, Instruction endInst) - { - for (int i = 0; i < current.Children.Count; i++) { - var child = current.Children[i]; - if (startInst.Offset <= child.EntryPoint.Offset && child.EntryPoint.Offset < endInst.Offset) { - current.Children.RemoveAt(i--); - target.Children.Add(child); - target.AllNodes.UnionWith(child.AllNodes); - } - } - } - #endregion - - #region Loop Detection - // Loop detection works like this: - // We find a top-level loop by looking for its entry point, which is characterized by a node dominating its own predecessor. - // Then we determine all other nodes that belong to such a loop (all nodes which lead to the entry point, and are dominated by it). - // Finally, we check whether our result conforms with potential existing exception structures, and create the substructure for the loop if successful. - - // This algorithm is applied recursively for any substructures (both detected loops and exception blocks) - - // But maybe we should get rid of this complex stuff and instead treat every backward jump as a loop? - // That should still work with the IL produced by compilers, and has the advantage that the detected loop bodies are consecutive IL regions. - - static void DetectLoops(ControlFlowGraph g, ControlStructure current, CancellationToken cancellationToken) - { - if (!current.EntryPoint.IsReachable) - return; - g.ResetVisited(); - cancellationToken.ThrowIfCancellationRequested(); - FindLoops(current, current.EntryPoint); - foreach (ControlStructure loop in current.Children) - DetectLoops(g, loop, cancellationToken); - } - - static void FindLoops(ControlStructure current, ControlFlowNode node) - { - if (node.Visited) - return; - node.Visited = true; - if (current.Nodes.Contains(node) - && node.DominanceFrontier.Contains(node) - && !(node == current.EntryPoint && current.Type == ControlStructureType.Loop)) - { - HashSet loopContents = new HashSet(); - FindLoopContents(current, loopContents, node, node); - List containedChildStructures = new List(); - bool invalidNesting = false; - foreach (ControlStructure childStructure in current.Children) { - if (childStructure.AllNodes.IsSubsetOf(loopContents)) { - containedChildStructures.Add(childStructure); - } else if (childStructure.AllNodes.Intersect(loopContents).Any()) { - invalidNesting = true; - } - } - if (!invalidNesting) { - current.Nodes.ExceptWith(loopContents); - ControlStructure ctl = new ControlStructure(loopContents, node, ControlStructureType.Loop); - foreach (ControlStructure childStructure in containedChildStructures) { - ctl.Children.Add(childStructure); - current.Children.Remove(childStructure); - ctl.Nodes.ExceptWith(childStructure.AllNodes); - } - current.Children.Add(ctl); - } - } - foreach (var edge in node.Outgoing) { - FindLoops(current, edge.Target); - } - } - - static void FindLoopContents(ControlStructure current, HashSet loopContents, ControlFlowNode loopHead, ControlFlowNode node) - { - if (current.AllNodes.Contains(node) && loopHead.Dominates(node) && loopContents.Add(node)) { - foreach (var edge in node.Incoming) { - FindLoopContents(current, loopContents, loopHead, edge.Source); - } - } - } - #endregion - } - - public enum ControlStructureType - { - /// - /// The root block of the method - /// - Root, - /// - /// A nested control structure representing a loop. - /// - Loop, - /// - /// A nested control structure representing a try block. - /// - Try, - /// - /// A nested control structure representing a catch, finally, or fault block. - /// - Handler, - /// - /// A nested control structure representing an exception filter block. - /// - Filter - } - - /// - /// Represents the structure detected by the . - /// - /// This is a tree of ControlStructure nodes. Each node contains a set of CFG nodes, and every CFG node is contained in exactly one ControlStructure node. - /// - public class ControlStructure - { - public readonly ControlStructureType Type; - public readonly List Children = new List(); - - /// - /// The nodes in this control structure. - /// - public readonly HashSet Nodes; - - /// - /// The nodes in this control structure and in all child control structures. - /// - public readonly HashSet AllNodes; - - /// - /// The entry point of this control structure. - /// - public readonly ControlFlowNode EntryPoint; - - /// - /// The exception handler associated with this Try,Handler or Finally structure. - /// - public ExceptionHandler ExceptionHandler; - - public ControlStructure(HashSet nodes, ControlFlowNode entryPoint, ControlStructureType type) - { - if (nodes == null) - throw new ArgumentNullException("nodes"); - Nodes = nodes; - EntryPoint = entryPoint; - Type = type; - AllNodes = new HashSet(nodes); - } - } -} diff --git a/ICSharpCode.Decompiler/FlowAnalysis/OpCodeInfo.cs b/ICSharpCode.Decompiler/FlowAnalysis/OpCodeInfo.cs deleted file mode 100644 index e0dc724f..00000000 --- a/ICSharpCode.Decompiler/FlowAnalysis/OpCodeInfo.cs +++ /dev/null @@ -1,312 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Linq; - -using Mono.Cecil.Cil; - -namespace ICSharpCode.Decompiler.FlowAnalysis -{ - /// - /// Additional info about opcodes. - /// - internal sealed class OpCodeInfo - { - public static bool IsUnconditionalBranch(OpCode opcode) - { - if (opcode.OpCodeType == OpCodeType.Prefix) - return false; - switch (opcode.FlowControl) { - case FlowControl.Branch: - case FlowControl.Throw: - case FlowControl.Return: - return true; - case FlowControl.Next: - case FlowControl.Call: - case FlowControl.Cond_Branch: - return false; - default: - throw new NotSupportedException(opcode.FlowControl.ToString()); - } - } - - static readonly OpCodeInfo[] knownOpCodes = { - #region Base Instructions - new OpCodeInfo(OpCodes.Add) { CanThrow = false }, - new OpCodeInfo(OpCodes.Add_Ovf) { CanThrow = true }, - new OpCodeInfo(OpCodes.Add_Ovf_Un) { CanThrow = true }, - new OpCodeInfo(OpCodes.And) { CanThrow = false }, - new OpCodeInfo(OpCodes.Arglist) { CanThrow = false }, - new OpCodeInfo(OpCodes.Beq) { CanThrow = false }, - new OpCodeInfo(OpCodes.Beq_S) { CanThrow = false }, - new OpCodeInfo(OpCodes.Bge) { CanThrow = false }, - new OpCodeInfo(OpCodes.Bge_S) { CanThrow = false }, - new OpCodeInfo(OpCodes.Bge_Un) { CanThrow = false }, - new OpCodeInfo(OpCodes.Bge_Un_S) { CanThrow = false }, - new OpCodeInfo(OpCodes.Bgt) { CanThrow = false }, - new OpCodeInfo(OpCodes.Bgt_S) { CanThrow = false }, - new OpCodeInfo(OpCodes.Bgt_Un) { CanThrow = false }, - new OpCodeInfo(OpCodes.Bgt_Un_S) { CanThrow = false }, - new OpCodeInfo(OpCodes.Ble) { CanThrow = false }, - new OpCodeInfo(OpCodes.Ble_S) { CanThrow = false }, - new OpCodeInfo(OpCodes.Ble_Un) { CanThrow = false }, - new OpCodeInfo(OpCodes.Ble_Un_S) { CanThrow = false }, - new OpCodeInfo(OpCodes.Blt) { CanThrow = false }, - new OpCodeInfo(OpCodes.Blt_S) { CanThrow = false }, - new OpCodeInfo(OpCodes.Blt_Un) { CanThrow = false }, - new OpCodeInfo(OpCodes.Blt_Un_S) { CanThrow = false }, - new OpCodeInfo(OpCodes.Bne_Un) { CanThrow = false }, - new OpCodeInfo(OpCodes.Bne_Un_S) { CanThrow = false }, - new OpCodeInfo(OpCodes.Br) { CanThrow = false }, - new OpCodeInfo(OpCodes.Br_S) { CanThrow = false }, - new OpCodeInfo(OpCodes.Break) { CanThrow = true }, - new OpCodeInfo(OpCodes.Brfalse) { CanThrow = false }, - new OpCodeInfo(OpCodes.Brfalse_S) { CanThrow = false }, - new OpCodeInfo(OpCodes.Brtrue) { CanThrow = false }, - new OpCodeInfo(OpCodes.Brtrue_S) { CanThrow = false }, - new OpCodeInfo(OpCodes.Call) { CanThrow = true }, - new OpCodeInfo(OpCodes.Calli) { CanThrow = true }, - new OpCodeInfo(OpCodes.Ceq) { CanThrow = false }, - new OpCodeInfo(OpCodes.Cgt) { CanThrow = false }, - new OpCodeInfo(OpCodes.Cgt_Un) { CanThrow = false }, - new OpCodeInfo(OpCodes.Ckfinite) { CanThrow = true }, - new OpCodeInfo(OpCodes.Clt) { CanThrow = false }, - new OpCodeInfo(OpCodes.Clt_Un) { CanThrow = false }, - // conv. - new OpCodeInfo(OpCodes.Conv_I1) { CanThrow = false }, - new OpCodeInfo(OpCodes.Conv_I2) { CanThrow = false }, - new OpCodeInfo(OpCodes.Conv_I4) { CanThrow = false }, - new OpCodeInfo(OpCodes.Conv_I8) { CanThrow = false }, - new OpCodeInfo(OpCodes.Conv_R4) { CanThrow = false }, - new OpCodeInfo(OpCodes.Conv_R8) { CanThrow = false }, - new OpCodeInfo(OpCodes.Conv_U1) { CanThrow = false }, - new OpCodeInfo(OpCodes.Conv_U2) { CanThrow = false }, - new OpCodeInfo(OpCodes.Conv_U4) { CanThrow = false }, - new OpCodeInfo(OpCodes.Conv_U8) { CanThrow = false }, - new OpCodeInfo(OpCodes.Conv_I) { CanThrow = false }, - new OpCodeInfo(OpCodes.Conv_U) { CanThrow = false }, - new OpCodeInfo(OpCodes.Conv_R_Un) { CanThrow = false }, - // conv.ovf. - new OpCodeInfo(OpCodes.Conv_Ovf_I1) { CanThrow = true}, - new OpCodeInfo(OpCodes.Conv_Ovf_I2) { CanThrow = true}, - new OpCodeInfo(OpCodes.Conv_Ovf_I4) { CanThrow = true}, - new OpCodeInfo(OpCodes.Conv_Ovf_I8) { CanThrow = true}, - new OpCodeInfo(OpCodes.Conv_Ovf_U1) { CanThrow = true}, - new OpCodeInfo(OpCodes.Conv_Ovf_U2) { CanThrow = true}, - new OpCodeInfo(OpCodes.Conv_Ovf_U4) { CanThrow = true}, - new OpCodeInfo(OpCodes.Conv_Ovf_U8) { CanThrow = true}, - new OpCodeInfo(OpCodes.Conv_Ovf_I) { CanThrow = true}, - new OpCodeInfo(OpCodes.Conv_Ovf_U) { CanThrow = true}, - // conv.ovf..un - new OpCodeInfo(OpCodes.Conv_Ovf_I1_Un) { CanThrow = true }, - new OpCodeInfo(OpCodes.Conv_Ovf_I2_Un) { CanThrow = true }, - new OpCodeInfo(OpCodes.Conv_Ovf_I4_Un) { CanThrow = true }, - new OpCodeInfo(OpCodes.Conv_Ovf_I8_Un) { CanThrow = true }, - new OpCodeInfo(OpCodes.Conv_Ovf_U1_Un) { CanThrow = true }, - new OpCodeInfo(OpCodes.Conv_Ovf_U2_Un) { CanThrow = true }, - new OpCodeInfo(OpCodes.Conv_Ovf_U4_Un) { CanThrow = true }, - new OpCodeInfo(OpCodes.Conv_Ovf_U8_Un) { CanThrow = true }, - new OpCodeInfo(OpCodes.Conv_Ovf_I_Un) { CanThrow = true }, - new OpCodeInfo(OpCodes.Conv_Ovf_U_Un) { CanThrow = true }, - - //new OpCodeInfo(OpCodes.Cpblk) { CanThrow = true }, - no idea whether this might cause trouble for the type system, C# shouldn't use it so I'll disable it - new OpCodeInfo(OpCodes.Div) { CanThrow = true }, - new OpCodeInfo(OpCodes.Div_Un) { CanThrow = true }, - new OpCodeInfo(OpCodes.Dup) { CanThrow = true, IsMoveInstruction = true }, - new OpCodeInfo(OpCodes.Endfilter) { CanThrow = false }, - new OpCodeInfo(OpCodes.Endfinally) { CanThrow = false }, - //new OpCodeInfo(OpCodes.Initblk) { CanThrow = true }, - no idea whether this might cause trouble for the type system, C# shouldn't use it so I'll disable it - //new OpCodeInfo(OpCodes.Jmp) { CanThrow = true } - We don't support non-local control transfers. - new OpCodeInfo(OpCodes.Ldarg) { CanThrow = false, IsMoveInstruction = true }, - new OpCodeInfo(OpCodes.Ldarg_0) { CanThrow = false, IsMoveInstruction = true }, - new OpCodeInfo(OpCodes.Ldarg_1) { CanThrow = false, IsMoveInstruction = true }, - new OpCodeInfo(OpCodes.Ldarg_2) { CanThrow = false, IsMoveInstruction = true }, - new OpCodeInfo(OpCodes.Ldarg_3) { CanThrow = false, IsMoveInstruction = true }, - new OpCodeInfo(OpCodes.Ldarg_S) { CanThrow = false, IsMoveInstruction = true }, - new OpCodeInfo(OpCodes.Ldarga) { CanThrow = false }, - new OpCodeInfo(OpCodes.Ldarga_S) { CanThrow = false }, - new OpCodeInfo(OpCodes.Ldc_I4) { CanThrow = false }, - new OpCodeInfo(OpCodes.Ldc_I4_M1) { CanThrow = false }, - new OpCodeInfo(OpCodes.Ldc_I4_0) { CanThrow = false }, - new OpCodeInfo(OpCodes.Ldc_I4_1) { CanThrow = false }, - new OpCodeInfo(OpCodes.Ldc_I4_2) { CanThrow = false }, - new OpCodeInfo(OpCodes.Ldc_I4_3) { CanThrow = false }, - new OpCodeInfo(OpCodes.Ldc_I4_4) { CanThrow = false }, - new OpCodeInfo(OpCodes.Ldc_I4_5) { CanThrow = false }, - new OpCodeInfo(OpCodes.Ldc_I4_6) { CanThrow = false }, - new OpCodeInfo(OpCodes.Ldc_I4_7) { CanThrow = false }, - new OpCodeInfo(OpCodes.Ldc_I4_8) { CanThrow = false }, - new OpCodeInfo(OpCodes.Ldc_I4_S) { CanThrow = false }, - new OpCodeInfo(OpCodes.Ldc_I8) { CanThrow = false }, - new OpCodeInfo(OpCodes.Ldc_R4) { CanThrow = false }, - new OpCodeInfo(OpCodes.Ldc_R8) { CanThrow = false }, - new OpCodeInfo(OpCodes.Ldftn) { CanThrow = false }, - // ldind. - new OpCodeInfo(OpCodes.Ldind_I1) { CanThrow = true }, - new OpCodeInfo(OpCodes.Ldind_I2) { CanThrow = true }, - new OpCodeInfo(OpCodes.Ldind_I4) { CanThrow = true }, - new OpCodeInfo(OpCodes.Ldind_I8) { CanThrow = true }, - new OpCodeInfo(OpCodes.Ldind_U1) { CanThrow = true }, - new OpCodeInfo(OpCodes.Ldind_U2) { CanThrow = true }, - new OpCodeInfo(OpCodes.Ldind_U4) { CanThrow = true }, - new OpCodeInfo(OpCodes.Ldind_R4) { CanThrow = true }, - new OpCodeInfo(OpCodes.Ldind_R8) { CanThrow = true }, - new OpCodeInfo(OpCodes.Ldind_I) { CanThrow = true }, - new OpCodeInfo(OpCodes.Ldind_Ref) { CanThrow = true }, - // the ldloc exceptions described in the spec can only occur on methods without .localsinit - but csc always sets that flag - new OpCodeInfo(OpCodes.Ldloc) { CanThrow = false, IsMoveInstruction = true }, - new OpCodeInfo(OpCodes.Ldloc_0) { CanThrow = false, IsMoveInstruction = true }, - new OpCodeInfo(OpCodes.Ldloc_1) { CanThrow = false, IsMoveInstruction = true }, - new OpCodeInfo(OpCodes.Ldloc_2) { CanThrow = false, IsMoveInstruction = true }, - new OpCodeInfo(OpCodes.Ldloc_3) { CanThrow = false, IsMoveInstruction = true }, - new OpCodeInfo(OpCodes.Ldloc_S) { CanThrow = false, IsMoveInstruction = true }, - new OpCodeInfo(OpCodes.Ldloca) { CanThrow = false }, - new OpCodeInfo(OpCodes.Ldloca_S) { CanThrow = false }, - new OpCodeInfo(OpCodes.Ldnull) { CanThrow = false }, - new OpCodeInfo(OpCodes.Leave) { CanThrow = false }, - new OpCodeInfo(OpCodes.Leave_S) { CanThrow = false }, - new OpCodeInfo(OpCodes.Localloc) { CanThrow = true }, - new OpCodeInfo(OpCodes.Mul) { CanThrow = false }, - new OpCodeInfo(OpCodes.Mul_Ovf) { CanThrow = true }, - new OpCodeInfo(OpCodes.Mul_Ovf_Un) { CanThrow = true }, - new OpCodeInfo(OpCodes.Neg) { CanThrow = false }, - new OpCodeInfo(OpCodes.Nop) { CanThrow = false }, - new OpCodeInfo(OpCodes.Not) { CanThrow = false }, - new OpCodeInfo(OpCodes.Or) { CanThrow = false }, - new OpCodeInfo(OpCodes.Pop) { CanThrow = false }, - new OpCodeInfo(OpCodes.Rem) { CanThrow = true }, - new OpCodeInfo(OpCodes.Rem_Un) { CanThrow = true }, - new OpCodeInfo(OpCodes.Ret) { CanThrow = false }, - new OpCodeInfo(OpCodes.Shl) { CanThrow = false }, - new OpCodeInfo(OpCodes.Shr) { CanThrow = false }, - new OpCodeInfo(OpCodes.Shr_Un) { CanThrow = false }, - new OpCodeInfo(OpCodes.Starg) { CanThrow = false, IsMoveInstruction = true }, - new OpCodeInfo(OpCodes.Starg_S) { CanThrow = false, IsMoveInstruction = true }, - new OpCodeInfo(OpCodes.Stind_I1) { CanThrow = true }, - new OpCodeInfo(OpCodes.Stind_I2) { CanThrow = true }, - new OpCodeInfo(OpCodes.Stind_I4) { CanThrow = true }, - new OpCodeInfo(OpCodes.Stind_I8) { CanThrow = true }, - new OpCodeInfo(OpCodes.Stind_R4) { CanThrow = true }, - new OpCodeInfo(OpCodes.Stind_R8) { CanThrow = true }, - new OpCodeInfo(OpCodes.Stind_I) { CanThrow = true }, - new OpCodeInfo(OpCodes.Stind_Ref) { CanThrow = true }, - new OpCodeInfo(OpCodes.Stloc) { CanThrow = false, IsMoveInstruction = true }, - new OpCodeInfo(OpCodes.Stloc_0) { CanThrow = false, IsMoveInstruction = true }, - new OpCodeInfo(OpCodes.Stloc_1) { CanThrow = false, IsMoveInstruction = true }, - new OpCodeInfo(OpCodes.Stloc_2) { CanThrow = false, IsMoveInstruction = true }, - new OpCodeInfo(OpCodes.Stloc_3) { CanThrow = false, IsMoveInstruction = true }, - new OpCodeInfo(OpCodes.Stloc_S) { CanThrow = false, IsMoveInstruction = true }, - new OpCodeInfo(OpCodes.Sub) { CanThrow = false }, - new OpCodeInfo(OpCodes.Sub_Ovf) { CanThrow = true }, - new OpCodeInfo(OpCodes.Sub_Ovf_Un) { CanThrow = true }, - new OpCodeInfo(OpCodes.Switch) { CanThrow = false }, - new OpCodeInfo(OpCodes.Xor) { CanThrow = false }, - #endregion - #region Object model instructions - // CanThrow is true by default - most OO instructions can throw, so we don't specify CanThrow all of the time - new OpCodeInfo(OpCodes.Box), - new OpCodeInfo(OpCodes.Callvirt), - new OpCodeInfo(OpCodes.Castclass), - new OpCodeInfo(OpCodes.Cpobj), - new OpCodeInfo(OpCodes.Initobj) { CanThrow = false }, - new OpCodeInfo(OpCodes.Isinst) { CanThrow = false }, - new OpCodeInfo(OpCodes.Ldelem_Any), - // ldelem. - new OpCodeInfo(OpCodes.Ldelem_I) , - new OpCodeInfo(OpCodes.Ldelem_I1), - new OpCodeInfo(OpCodes.Ldelem_I2), - new OpCodeInfo(OpCodes.Ldelem_I4), - new OpCodeInfo(OpCodes.Ldelem_I8), - new OpCodeInfo(OpCodes.Ldelem_R4), - new OpCodeInfo(OpCodes.Ldelem_R8), - new OpCodeInfo(OpCodes.Ldelem_Ref), - new OpCodeInfo(OpCodes.Ldelem_U1), - new OpCodeInfo(OpCodes.Ldelem_U2), - new OpCodeInfo(OpCodes.Ldelem_U4), - new OpCodeInfo(OpCodes.Ldelema) , - new OpCodeInfo(OpCodes.Ldfld) , - new OpCodeInfo(OpCodes.Ldflda), - new OpCodeInfo(OpCodes.Ldlen) , - new OpCodeInfo(OpCodes.Ldobj) , - new OpCodeInfo(OpCodes.Ldsfld), - new OpCodeInfo(OpCodes.Ldsflda), - new OpCodeInfo(OpCodes.Ldstr) { CanThrow = false }, - new OpCodeInfo(OpCodes.Ldtoken) { CanThrow = false }, - new OpCodeInfo(OpCodes.Ldvirtftn), - new OpCodeInfo(OpCodes.Mkrefany), - new OpCodeInfo(OpCodes.Newarr), - new OpCodeInfo(OpCodes.Newobj), - new OpCodeInfo(OpCodes.Refanytype) { CanThrow = false }, - new OpCodeInfo(OpCodes.Refanyval), - new OpCodeInfo(OpCodes.Rethrow), - new OpCodeInfo(OpCodes.Sizeof) { CanThrow = false }, - new OpCodeInfo(OpCodes.Stelem_Any), - new OpCodeInfo(OpCodes.Stelem_I1), - new OpCodeInfo(OpCodes.Stelem_I2), - new OpCodeInfo(OpCodes.Stelem_I4), - new OpCodeInfo(OpCodes.Stelem_I8), - new OpCodeInfo(OpCodes.Stelem_R4), - new OpCodeInfo(OpCodes.Stelem_R8), - new OpCodeInfo(OpCodes.Stelem_Ref), - new OpCodeInfo(OpCodes.Stfld), - new OpCodeInfo(OpCodes.Stobj), - new OpCodeInfo(OpCodes.Stsfld), - new OpCodeInfo(OpCodes.Throw), - new OpCodeInfo(OpCodes.Unbox), - new OpCodeInfo(OpCodes.Unbox_Any), - #endregion - }; - static readonly Dictionary knownOpCodeDict = knownOpCodes.ToDictionary(info => info.OpCode.Code); - - public static OpCodeInfo Get(OpCode opCode) - { - return Get(opCode.Code); - } - - public static OpCodeInfo Get(Code code) - { - OpCodeInfo info; - if (knownOpCodeDict.TryGetValue(code, out info)) - return info; - else - throw new NotSupportedException(code.ToString()); - } - - OpCode opcode; - - OpCodeInfo(OpCode opcode) - { - this.opcode = opcode; - CanThrow = true; - } - - public OpCode OpCode { get { return opcode; } } - - /// - /// 'Move' kind of instructions have one input (may be stack or local variable) and copy that value to all outputs (again stack or local variable). - /// - public bool IsMoveInstruction { get; private set; } - - /// - /// Specifies whether this opcode is capable of throwing exceptions. - /// - public bool CanThrow { get; private set; } - } -} diff --git a/ICSharpCode.Decompiler/FlowAnalysis/SimplifyByRefCalls.cs b/ICSharpCode.Decompiler/FlowAnalysis/SimplifyByRefCalls.cs deleted file mode 100644 index 42c30914..00000000 --- a/ICSharpCode.Decompiler/FlowAnalysis/SimplifyByRefCalls.cs +++ /dev/null @@ -1,174 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Diagnostics; - -using Mono.Cecil; -using Mono.Cecil.Cil; - -namespace ICSharpCode.Decompiler.FlowAnalysis -{ - /// - /// This is a transformation working on SSA form. - /// It removes ldloca instructions and replaces them with SpecialOpCode.PrepareByOutCall or SpecialOpCode.PrepareByRefCall. - /// This then allows the variable that had its address taken to also be transformed into SSA. - /// - internal sealed class SimplifyByRefCalls - { - public static bool MakeByRefCallsSimple(SsaForm ssaForm) - { - SimplifyByRefCalls instance = new SimplifyByRefCalls(ssaForm); - foreach (SsaBlock block in ssaForm.Blocks) { - for (int i = 0; i < block.Instructions.Count; i++) { - SsaInstruction inst = block.Instructions[i]; - if (inst.Instruction != null) { - switch (inst.Instruction.OpCode.Code) { - case Code.Call: - case Code.Callvirt: - instance.MakeByRefCallSimple(block, ref i, (IMethodSignature)inst.Instruction.Operand); - break; - case Code.Initobj: - instance.MakeInitObjCallSimple(block, ref i); - break; - case Code.Ldfld: - instance.MakeLoadFieldCallSimple(block, ref i); - break; - } - } - } - } - instance.RemoveRedundantInstructions(); - if (instance.couldSimplifySomething) - ssaForm.ComputeVariableUsage(); - return instance.couldSimplifySomething; - } - - readonly SsaForm ssaForm; - - bool couldSimplifySomething; - - // the list of ldloca instructions we will remove - readonly List redundantLoadAddressInstructions = new List(); - - SimplifyByRefCalls(SsaForm ssaForm) - { - this.ssaForm = ssaForm; - } - - void MakeByRefCallSimple(SsaBlock block, ref int instructionIndexInBlock, IMethodSignature targetMethod) - { - SsaInstruction inst = block.Instructions[instructionIndexInBlock]; - for (int i = 0; i < inst.Operands.Length; i++) { - SsaVariable operand = inst.Operands[i]; - if (operand.IsSingleAssignment && operand.Usage.Count == 1 && IsLoadAddress(operand.Definition)) { - // address is used for this method call only - - Instruction loadAddressInstruction = operand.Definition.Instruction; - - // find target parameter type: - bool isOut; - if (i == 0 && targetMethod.HasThis) { - isOut = false; - } else { - ParameterDefinition parameter = targetMethod.Parameters[i - (targetMethod.HasThis ? 1 : 0)]; - isOut = parameter.IsOut; - } - - SsaVariable addressTakenOf = GetVariableFromLoadAddressInstruction(loadAddressInstruction); - - // insert "Prepare" instruction on front - SpecialOpCode loadOpCode = isOut ? SpecialOpCode.PrepareByOutCall : SpecialOpCode.PrepareByRefCall; - block.Instructions.Insert(instructionIndexInBlock++, new SsaInstruction( - block, null, operand, new SsaVariable[] { addressTakenOf }, specialOpCode: loadOpCode)); - - // insert "WriteAfterByRefOrOutCall" instruction after call - block.Instructions.Insert(instructionIndexInBlock + 1, new SsaInstruction( - block, null, addressTakenOf, new SsaVariable[] { operand }, specialOpCode: SpecialOpCode.WriteAfterByRefOrOutCall)); - - couldSimplifySomething = true; - - // remove the loadAddressInstruction later - // (later because it might be defined in the current block and we don't want instructionIndex to become invalid) - redundantLoadAddressInstructions.Add(operand.Definition); - } - } - } - - SsaVariable GetVariableFromLoadAddressInstruction(Instruction loadAddressInstruction) - { - if (loadAddressInstruction.OpCode == OpCodes.Ldloca) { - return ssaForm.GetOriginalVariable((VariableReference)loadAddressInstruction.Operand); - } else { - Debug.Assert(loadAddressInstruction.OpCode == OpCodes.Ldarga); - return ssaForm.GetOriginalVariable((ParameterReference)loadAddressInstruction.Operand); - } - } - - static bool IsLoadAddress(SsaInstruction inst) - { - return inst.Instruction != null && (inst.Instruction.OpCode == OpCodes.Ldloca || inst.Instruction.OpCode == OpCodes.Ldarga); - } - - void MakeInitObjCallSimple(SsaBlock block, ref int instructionIndexInBlock) - { - SsaInstruction inst = block.Instructions[instructionIndexInBlock]; - Debug.Assert(inst.Operands.Length == 1); - SsaVariable operand = inst.Operands[0]; - if (operand.IsSingleAssignment && operand.Usage.Count == 1 && IsLoadAddress(operand.Definition)) { - // replace instruction with special "InitObj" instruction - block.Instructions[instructionIndexInBlock] = new SsaInstruction( - inst.ParentBlock, null, GetVariableFromLoadAddressInstruction(operand.Definition.Instruction), null, - specialOpCode: SpecialOpCode.InitObj, - typeOperand: (TypeReference)inst.Instruction.Operand); - - couldSimplifySomething = true; - - // remove the loadAddressInstruction later - redundantLoadAddressInstructions.Add(operand.Definition); - } - } - - void MakeLoadFieldCallSimple(SsaBlock block, ref int instructionIndexInBlock) - { - SsaInstruction inst = block.Instructions[instructionIndexInBlock]; - Debug.Assert(inst.Operands.Length == 1); - SsaVariable operand = inst.Operands[0]; - if (operand.IsSingleAssignment && operand.Usage.Count == 1 && IsLoadAddress(operand.Definition)) { - // insert special "PrepareForFieldAccess" instruction in front - block.Instructions.Insert(instructionIndexInBlock++, new SsaInstruction( - inst.ParentBlock, null, operand, - new SsaVariable[] { GetVariableFromLoadAddressInstruction(operand.Definition.Instruction) }, - specialOpCode: SpecialOpCode.PrepareForFieldAccess)); - - couldSimplifySomething = true; - - // remove the loadAddressInstruction later - redundantLoadAddressInstructions.Add(operand.Definition); - } - } - - void RemoveRedundantInstructions() - { - foreach (SsaInstruction inst in redundantLoadAddressInstructions) { - inst.ParentBlock.Instructions.Remove(inst); - } - } - } -} diff --git a/ICSharpCode.Decompiler/FlowAnalysis/SsaBlock.cs b/ICSharpCode.Decompiler/FlowAnalysis/SsaBlock.cs deleted file mode 100644 index b1767b9b..00000000 --- a/ICSharpCode.Decompiler/FlowAnalysis/SsaBlock.cs +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.IO; - -namespace ICSharpCode.Decompiler.FlowAnalysis -{ - /// - /// A block in a control flow graph; with instructions represented by "SsaInstructions" (instructions use variables, no evaluation stack). - /// Usually these variables are in SSA form to make analysis easier. - /// - public sealed class SsaBlock - { - public readonly List Successors = new List(); - public readonly List Predecessors = new List(); - public readonly ControlFlowNodeType NodeType; - public readonly List Instructions = new List(); - - /// - /// The block index in the control flow graph. - /// This correspons to the node index in ControlFlowGraph.Nodes, so it can be used to retrieve the original CFG node and look - /// up additional information (e.g. dominance). - /// - public readonly int BlockIndex; - - internal SsaBlock(ControlFlowNode node) - { - NodeType = node.NodeType; - BlockIndex = node.BlockIndex; - } - - public override string ToString() - { - StringWriter writer = new StringWriter(); - writer.Write("Block #{0} ({1})", BlockIndex, NodeType); - foreach (SsaInstruction inst in Instructions) { - writer.WriteLine(); - inst.WriteTo(writer); - } - return writer.ToString(); - } - } -} diff --git a/ICSharpCode.Decompiler/FlowAnalysis/SsaForm.cs b/ICSharpCode.Decompiler/FlowAnalysis/SsaForm.cs deleted file mode 100644 index baf520eb..00000000 --- a/ICSharpCode.Decompiler/FlowAnalysis/SsaForm.cs +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright (c) 2010 Daniel Grunwald -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Diagnostics; -using System.Linq; - -using ICSharpCode.NRefactory.Utils; -using Mono.Cecil; -using Mono.Cecil.Cil; - -namespace ICSharpCode.Decompiler.FlowAnalysis -{ - /// - /// Represents a graph of SsaBlocks. - /// - public sealed class SsaForm - { - readonly SsaVariable[] parameters; - readonly SsaVariable[] locals; - public readonly ReadOnlyCollection OriginalVariables; - public readonly ReadOnlyCollection Blocks; - readonly bool methodHasThis; - - public SsaBlock EntryPoint { - get { return Blocks[0]; } - } - - public SsaBlock RegularExit { - get { return Blocks[1]; } - } - - public SsaBlock ExceptionalExit { - get { return Blocks[2]; } - } - - internal SsaForm(SsaBlock[] blocks, SsaVariable[] parameters, SsaVariable[] locals, SsaVariable[] stackLocations, bool methodHasThis) - { - this.parameters = parameters; - this.locals = locals; - Blocks = new ReadOnlyCollection(blocks); - OriginalVariables = new ReadOnlyCollection(parameters.Concat(locals).Concat(stackLocations).ToList()); - this.methodHasThis = methodHasThis; - - Debug.Assert(EntryPoint.NodeType == ControlFlowNodeType.EntryPoint); - Debug.Assert(RegularExit.NodeType == ControlFlowNodeType.RegularExit); - Debug.Assert(ExceptionalExit.NodeType == ControlFlowNodeType.ExceptionalExit); - for (int i = 0; i < OriginalVariables.Count; i++) { - OriginalVariables[i].OriginalVariableIndex = i; - } - } - - public GraphVizGraph ExportBlockGraph(Func labelProvider = null) - { - if (labelProvider == null) - labelProvider = b => b.ToString(); - GraphVizGraph graph = new GraphVizGraph(); - foreach (SsaBlock block in Blocks) { - graph.AddNode(new GraphVizNode(block.BlockIndex) { label = labelProvider(block), shape = "box" }); - } - foreach (SsaBlock block in Blocks) { - foreach (SsaBlock s in block.Successors) { - graph.AddEdge(new GraphVizEdge(block.BlockIndex, s.BlockIndex)); - } - } - return graph; - } - - public GraphVizGraph ExportVariableGraph(Func labelProvider = null) - { - if (labelProvider == null) - labelProvider = v => v.ToString(); - GraphVizGraph graph = new GraphVizGraph(); - foreach (SsaVariable v in AllVariables) { - graph.AddNode(new GraphVizNode(v.Name) { label = labelProvider(v) }); - } - int instructionIndex = 0; - foreach (SsaBlock block in Blocks) { - foreach (SsaInstruction inst in block.Instructions) { - if (inst.Operands.Length == 0 && inst.Target == null) - continue; - string id = "instruction" + (++instructionIndex); - graph.AddNode(new GraphVizNode(id) { label = inst.ToString(), shape = "box" }); - foreach (SsaVariable op in inst.Operands) - graph.AddEdge(new GraphVizEdge(op.Name, id)); - if (inst.Target != null) - graph.AddEdge(new GraphVizEdge(id, inst.Target.Name)); - } - } - return graph; - } - - public SsaVariable GetOriginalVariable(ParameterReference parameter) - { - if (methodHasThis) - return parameters[parameter.Index + 1]; - else - return parameters[parameter.Index]; - } - - public SsaVariable GetOriginalVariable(VariableReference variable) - { - return locals[variable.Index]; - } - - #region ComputeVariableUsage - public void ComputeVariableUsage() - { - // clear data from previous runs - foreach (SsaBlock block in Blocks) { - foreach (SsaInstruction inst in block.Instructions) { - foreach (SsaVariable v in inst.Operands) { - if (v.Usage != null) - v.Usage.Clear(); - } - if (inst.Target != null && inst.Target.Usage != null) - inst.Target.Usage.Clear(); - } - } - foreach (SsaBlock block in Blocks) { - foreach (SsaInstruction inst in block.Instructions) { - foreach (SsaVariable v in inst.Operands) { - if (v.Usage == null) - v.Usage = new List(); - v.Usage.Add(inst); - } - if (inst.Target != null && inst.Target.Usage == null) - inst.Target.Usage = new List(); - } - } - } - #endregion - - public IEnumerable AllVariables { - get { - return ( - from block in Blocks - from instruction in block.Instructions - where instruction.Target != null - select instruction.Target - ).Distinct(); - } - } - } -} diff --git a/ICSharpCode.Decompiler/FlowAnalysis/SsaFormBuilder.cs b/ICSharpCode.Decompiler/FlowAnalysis/SsaFormBuilder.cs deleted file mode 100644 index c7c86a57..00000000 --- a/ICSharpCode.Decompiler/FlowAnalysis/SsaFormBuilder.cs +++ /dev/null @@ -1,257 +0,0 @@ -// Copyright (c) 2010 Daniel Grunwald -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Diagnostics; - -using Mono.Cecil; -using Mono.Cecil.Cil; - -namespace ICSharpCode.Decompiler.FlowAnalysis -{ - /// - /// Constructs "SsaForm" graph for a CFG. - /// This class transforms the method from stack-based IL to a register-based IL language. - /// Then it calls into TransformToSsa to convert the resulting graph to static single assignment form. - /// - public sealed class SsaFormBuilder - { - public static SsaForm Build(MethodDefinition method) - { - if (method == null) - throw new ArgumentNullException("method"); - var cfg = ControlFlowGraphBuilder.Build(method.Body); - cfg.ComputeDominance(); - cfg.ComputeDominanceFrontier(); - var ssa = BuildRegisterIL(method, cfg); - TransformToSsa.Transform(cfg, ssa); - return ssa; - } - - public static SsaForm BuildRegisterIL(MethodDefinition method, ControlFlowGraph cfg) - { - if (method == null) - throw new ArgumentNullException("method"); - if (cfg == null) - throw new ArgumentNullException("cfg"); - return new SsaFormBuilder(method, cfg).Build(); - } - - readonly MethodDefinition method; - readonly ControlFlowGraph cfg; - - readonly SsaBlock[] blocks; // array index = block index - readonly int[] stackSizeAtBlockStart; // array index = block index - - readonly SsaVariable[] parameters; // array index = parameter number - readonly SsaVariable[] locals; // array index = local number - readonly SsaVariable[] stackLocations; // array index = position on the IL evaluation stack - SsaForm ssaForm; - - SsaFormBuilder(MethodDefinition method, ControlFlowGraph cfg) - { - this.method = method; - this.cfg = cfg; - - blocks = new SsaBlock[cfg.Nodes.Count]; - stackSizeAtBlockStart = new int[cfg.Nodes.Count]; - for (int i = 0; i < stackSizeAtBlockStart.Length; i++) { - stackSizeAtBlockStart[i] = -1; - } - stackSizeAtBlockStart[cfg.EntryPoint.BlockIndex] = 0; - - parameters = new SsaVariable[method.Parameters.Count + (method.HasThis ? 1 : 0)]; - if (method.HasThis) - parameters[0] = new SsaVariable(method.Body.ThisParameter); - for (int i = 0; i < method.Parameters.Count; i++) - parameters[i + (method.HasThis ? 1 : 0)] = new SsaVariable(method.Parameters[i]); - - locals = new SsaVariable[method.Body.Variables.Count]; - for (int i = 0; i < locals.Length; i++) - locals[i] = new SsaVariable(method.Body.Variables[i]); - - stackLocations = new SsaVariable[method.Body.MaxStackSize]; - for (int i = 0; i < stackLocations.Length; i++) { - stackLocations[i] = new SsaVariable(i); - } - } - - internal SsaForm Build() - { - CreateGraphStructure(); - ssaForm = new SsaForm(blocks, parameters, locals, stackLocations, method.HasThis); - CreateInstructions(cfg.EntryPoint.BlockIndex); - CreateSpecialInstructions(); - return ssaForm; - } - - void CreateGraphStructure() - { - for (int i = 0; i < blocks.Length; i++) { - blocks[i] = new SsaBlock(cfg.Nodes[i]); - } - for (int i = 0; i < blocks.Length; i++) { - foreach (ControlFlowNode node in cfg.Nodes[i].Successors) { - blocks[i].Successors.Add(blocks[node.BlockIndex]); - blocks[node.BlockIndex].Predecessors.Add(blocks[i]); - } - } - } - - void CreateInstructions(int blockIndex) - { - ControlFlowNode cfgNode = cfg.Nodes[blockIndex]; - SsaBlock block = blocks[blockIndex]; - - int stackSize = stackSizeAtBlockStart[blockIndex]; - Debug.Assert(stackSize >= 0); - - List prefixes = new List(); - foreach (Instruction inst in cfgNode.Instructions) { - if (inst.OpCode.OpCodeType == OpCodeType.Prefix) { - prefixes.Add(inst); - continue; - } - - int popCount = inst.GetPopDelta(method) ?? stackSize; - stackSize -= popCount; - if (stackSize < 0) - throw new InvalidProgramException("IL stack underflow"); - - int pushCount = inst.GetPushDelta(); - if (stackSize + pushCount > stackLocations.Length) - throw new InvalidProgramException("IL stack overflow"); - - SsaVariable target; - SsaVariable[] operands; - DetermineOperands(stackSize, inst, popCount, pushCount, out target, out operands); - - Instruction[] prefixArray = prefixes.Count > 0 ? prefixes.ToArray() : null; - prefixes.Clear(); - - // ignore NOP instructions - if (!(inst.OpCode == OpCodes.Nop || inst.OpCode == OpCodes.Pop)) { - block.Instructions.Add(new SsaInstruction(block, inst, target, operands, prefixArray)); - } - stackSize += pushCount; - } - - foreach (ControlFlowEdge edge in cfgNode.Outgoing) { - int newStackSize; - switch (edge.Type) { - case JumpType.Normal: - newStackSize = stackSize; - break; - case JumpType.EndFinally: - if (stackSize != 0) - throw new NotSupportedException("stacksize must be 0 in endfinally edge"); - newStackSize = 0; - break; - case JumpType.JumpToExceptionHandler: - switch (edge.Target.NodeType) { - case ControlFlowNodeType.FinallyOrFaultHandler: - newStackSize = 0; - break; - case ControlFlowNodeType.ExceptionalExit: - case ControlFlowNodeType.CatchHandler: - newStackSize = 1; - break; - default: - throw new NotSupportedException("unsupported target node type: " + edge.Target.NodeType); - } - break; - default: - throw new NotSupportedException("unsupported jump type: " + edge.Type); - } - - int nextStackSize = stackSizeAtBlockStart[edge.Target.BlockIndex]; - if (nextStackSize == -1) { - stackSizeAtBlockStart[edge.Target.BlockIndex] = newStackSize; - CreateInstructions(edge.Target.BlockIndex); - } else if (nextStackSize != newStackSize) { - throw new InvalidProgramException("Stack size doesn't match"); - } - } - } - - void DetermineOperands(int stackSize, Instruction inst, int popCount, int pushCount, out SsaVariable target, out SsaVariable[] operands) - { - switch (inst.OpCode.Code) { - case Code.Ldarg: - operands = new SsaVariable[] { ssaForm.GetOriginalVariable((ParameterReference)inst.Operand) }; - target = stackLocations[stackSize]; - break; - case Code.Starg: - operands = new SsaVariable[] { stackLocations[stackSize] }; - target = ssaForm.GetOriginalVariable((ParameterReference)inst.Operand); - break; - case Code.Ldloc: - operands = new SsaVariable[] { ssaForm.GetOriginalVariable((VariableReference)inst.Operand) }; - target = stackLocations[stackSize]; - break; - case Code.Stloc: - operands = new SsaVariable[] { stackLocations[stackSize] }; - target = ssaForm.GetOriginalVariable((VariableReference)inst.Operand); - break; - case Code.Dup: - operands = new SsaVariable[] { stackLocations[stackSize] }; - target = stackLocations[stackSize + 1]; - break; - default: - operands = new SsaVariable[popCount]; - for (int i = 0; i < popCount; i++) { - operands[i] = stackLocations[stackSize + i]; - } - - switch (pushCount) { - case 0: - target = null; - break; - case 1: - target = stackLocations[stackSize]; - break; - default: - throw new NotSupportedException("unsupported pushCount=" + pushCount); - } - break; - } - } - - void CreateSpecialInstructions() - { - // Everything needs an initial write for the SSA transformation to work correctly. - foreach (SsaVariable v in parameters) { - ssaForm.EntryPoint.Instructions.Add(new SsaInstruction(ssaForm.EntryPoint, null, v, null, specialOpCode: SpecialOpCode.Parameter)); - } - foreach (SsaVariable v in locals) { - ssaForm.EntryPoint.Instructions.Add(new SsaInstruction(ssaForm.EntryPoint, null, v, null, specialOpCode: SpecialOpCode.Uninitialized)); - } - foreach (SsaVariable v in stackLocations) { - ssaForm.EntryPoint.Instructions.Add(new SsaInstruction(ssaForm.EntryPoint, null, v, null, specialOpCode: SpecialOpCode.Uninitialized)); - } - foreach (SsaBlock b in blocks) { - if (b.NodeType == ControlFlowNodeType.CatchHandler) { - b.Instructions.Add(new SsaInstruction(b, null, stackLocations[0], null, - specialOpCode: SpecialOpCode.Exception, - typeOperand: cfg.Nodes[b.BlockIndex].ExceptionHandler.CatchType)); - } - } - } - } -} diff --git a/ICSharpCode.Decompiler/FlowAnalysis/SsaInstruction.cs b/ICSharpCode.Decompiler/FlowAnalysis/SsaInstruction.cs deleted file mode 100644 index c9375852..00000000 --- a/ICSharpCode.Decompiler/FlowAnalysis/SsaInstruction.cs +++ /dev/null @@ -1,191 +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.Diagnostics; -using System.IO; - -using ICSharpCode.Decompiler.Disassembler; -using Mono.Cecil; -using Mono.Cecil.Cil; - -namespace ICSharpCode.Decompiler.FlowAnalysis -{ - public enum SpecialOpCode - { - /// - /// No special op code: SsaInstruction has a normal IL instruction - /// - None, - /// - /// Φ function: chooses the appropriate variable based on which CFG edge was used to enter this block - /// - Phi, - /// - /// Variable is read from before passing it by ref. - /// This instruction constructs a managed reference to the variable. - /// - PrepareByRefCall, - /// - /// This instruction constructs a managed reference to the variable. - /// The variable is not really read from. - /// - PrepareByOutCall, - /// - /// This instruction constructs a managed reference to the variable. - /// The reference is used for a field access on a value type. - /// - PrepareForFieldAccess, - /// - /// Variable is written to after passing it by ref or out. - /// - WriteAfterByRefOrOutCall, - /// - /// Variable is not initialized. - /// - Uninitialized, - /// - /// Value is passed in as parameter - /// - Parameter, - /// - /// Value is a caught exception. - /// TypeOperand is set to the exception type. - /// - Exception, - /// - /// Initialize a value type. Unlike the real initobj instruction, this one does not take an address - /// but assigns to the target variable. - /// TypeOperand is set to the type being created. - /// - InitObj - } - - public sealed class SsaInstruction - { - public readonly SsaBlock ParentBlock; - public readonly SpecialOpCode SpecialOpCode; - - /// - /// The original IL instruction. - /// May be null for "invented" instructions (SpecialOpCode != None). - /// - public readonly Instruction Instruction; - - /// - /// Prefixes in front of the IL instruction. - /// - public readonly Instruction[] Prefixes; - - /// - /// Gets the type operand. This is used only in combination with some special opcodes. - /// - public readonly TypeReference TypeOperand; - - public SsaVariable Target; - public SsaVariable[] Operands; - - static readonly SsaVariable[] emptyVariableArray = {}; - static readonly Instruction[] emptyInstructionArray = {}; - - public SsaInstruction(SsaBlock parentBlock, Instruction instruction, SsaVariable target, SsaVariable[] operands, - Instruction[] prefixes = null, SpecialOpCode specialOpCode = SpecialOpCode.None, - TypeReference typeOperand = null) - { - ParentBlock = parentBlock; - Instruction = instruction; - Prefixes = prefixes ?? emptyInstructionArray; - Target = target; - Operands = operands ?? emptyVariableArray; - SpecialOpCode = specialOpCode; - TypeOperand = typeOperand; - Debug.Assert((typeOperand != null) == (specialOpCode == SpecialOpCode.Exception || specialOpCode == SpecialOpCode.InitObj)); - } - - /// - /// Gets whether this instruction is a simple assignment from one variable to another. - /// - public bool IsMoveInstruction { - get { - return Target != null && Operands.Length == 1 && Instruction != null && OpCodeInfo.Get(Instruction.OpCode).IsMoveInstruction; - } - } - - public void ReplaceVariableInOperands(SsaVariable oldVar, SsaVariable newVar) - { - for (int i = 0; i < Operands.Length; i++) { - if (Operands[i] == oldVar) - Operands[i] = newVar; - } - } - - public override string ToString() - { - StringWriter w = new StringWriter(); - WriteTo(w); - return w.ToString(); - } - - public void WriteTo(TextWriter writer) - { - foreach (Instruction prefix in Prefixes) { - DisassemblerHelpers.WriteTo(prefix, new PlainTextOutput(writer)); - writer.WriteLine(); - } - if (Instruction != null && Instruction.Offset >= 0) { - writer.Write(CecilExtensions.OffsetToString(Instruction.Offset)); - writer.Write(": "); - } - if (Target != null) { - writer.Write(Target.ToString()); - writer.Write(" = "); - } - if (IsMoveInstruction) { - writer.Write(Operands[0].ToString()); - if (Instruction != null) { - writer.Write(" (" + Instruction.OpCode.Name + ")"); - } - } else { - if (Instruction == null) { - writer.Write(SpecialOpCode.ToString()); - } else { - writer.Write(Instruction.OpCode.Name); - if(null != Instruction.Operand) { - writer.Write(' '); - DisassemblerHelpers.WriteOperand(new PlainTextOutput(writer), Instruction.Operand); - writer.Write(' '); - } - } - if (TypeOperand != null) { - writer.Write(' '); - writer.Write(TypeOperand.ToString()); - writer.Write(' '); - } - if (Operands.Length > 0) { - writer.Write('('); - for (int i = 0; i < Operands.Length; i++) { - if (i > 0) - writer.Write(", "); - writer.Write(Operands[i].ToString()); - } - writer.Write(')'); - } - } - } - } -} diff --git a/ICSharpCode.Decompiler/FlowAnalysis/SsaOptimization.cs b/ICSharpCode.Decompiler/FlowAnalysis/SsaOptimization.cs deleted file mode 100644 index 71696992..00000000 --- a/ICSharpCode.Decompiler/FlowAnalysis/SsaOptimization.cs +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Diagnostics; - -using Mono.Cecil.Cil; - -namespace ICSharpCode.Decompiler.FlowAnalysis -{ - /// - /// Contains some very simple optimizations that work on the SSA form. - /// - internal static class SsaOptimization - { - public static void Optimize(SsaForm ssaForm) - { - DirectlyStoreToVariables(ssaForm); - SimpleCopyPropagation(ssaForm); - RemoveDeadAssignments(ssaForm); - } - - /// - /// When any instructions stores its result in a stack location that's used only once in a 'stloc' or 'starg' instruction, - /// we optimize this to directly store in the target location. - /// As optimization this is redundant (does the same as copy propagation), but it'll make us keep the variables named - /// after locals instead of keeping the temps as using only the simple copy propagation would do. - /// - public static void DirectlyStoreToVariables(SsaForm ssaForm) - { - foreach (SsaBlock block in ssaForm.Blocks) { - block.Instructions.RemoveAll( - inst => { - if (inst.Instruction != null && (inst.Instruction.OpCode == OpCodes.Stloc || inst.Instruction.OpCode == OpCodes.Starg)) { - SsaVariable target = inst.Target; - SsaVariable temp = inst.Operands[0]; - if (target.IsSingleAssignment && temp.IsSingleAssignment && temp.Usage.Count == 1 && temp.IsStackLocation) { - temp.Definition.Target = target; - return true; - } - } - return false; - }); - } - ssaForm.ComputeVariableUsage(); // update usage after we modified stuff - } - - public static void SimpleCopyPropagation(SsaForm ssaForm, bool onlyForStackLocations = true) - { - foreach (SsaBlock block in ssaForm.Blocks) { - foreach (SsaInstruction inst in block.Instructions) { - if (inst.IsMoveInstruction && inst.Target.IsSingleAssignment && inst.Operands[0].IsSingleAssignment) { - if (inst.Target.IsStackLocation || !onlyForStackLocations) { - // replace all uses of 'target' with 'operands[0]'. - foreach (SsaInstruction useInstruction in inst.Target.Usage) { - useInstruction.ReplaceVariableInOperands(inst.Target, inst.Operands[0]); - } - } - } - } - } - ssaForm.ComputeVariableUsage(); // update usage after we modified stuff - } - - public static void RemoveDeadAssignments(SsaForm ssaForm) - { - HashSet liveVariables = new HashSet(); - // find variables that are used directly - foreach (SsaBlock block in ssaForm.Blocks) { - foreach (SsaInstruction inst in block.Instructions) { - if (!CanRemoveAsDeadCode(inst)) { - if (inst.Target != null) - liveVariables.Add(inst.Target); - foreach (SsaVariable op in inst.Operands) { - liveVariables.Add(op); - } - } - } - } - Queue queue = new Queue(liveVariables); - // find variables that are used indirectly - while (queue.Count > 0) { - SsaVariable v = queue.Dequeue(); - if (v.IsSingleAssignment) { - foreach (SsaVariable op in v.Definition.Operands) { - if (liveVariables.Add(op)) - queue.Enqueue(op); - } - } - } - // remove assignments to all unused variables - foreach (SsaBlock block in ssaForm.Blocks) { - block.Instructions.RemoveAll( - inst => { - if (inst.Target != null && !liveVariables.Contains(inst.Target)) { - Debug.Assert(inst.Target.IsSingleAssignment); - return true; - } - return false; - }); - } - ssaForm.ComputeVariableUsage(); // update usage after we modified stuff - } - - static bool CanRemoveAsDeadCode(SsaInstruction inst) - { - if (inst.Target != null && !inst.Target.IsSingleAssignment) - return false; - switch (inst.SpecialOpCode) { - case SpecialOpCode.Phi: - case SpecialOpCode.Exception: - case SpecialOpCode.Parameter: - case SpecialOpCode.Uninitialized: - return true; - case SpecialOpCode.None: - return inst.IsMoveInstruction; - default: - return false; - } - } - } -} diff --git a/ICSharpCode.Decompiler/FlowAnalysis/SsaVariable.cs b/ICSharpCode.Decompiler/FlowAnalysis/SsaVariable.cs deleted file mode 100644 index 902b7002..00000000 --- a/ICSharpCode.Decompiler/FlowAnalysis/SsaVariable.cs +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using Mono.Cecil; -using Mono.Cecil.Cil; - -namespace ICSharpCode.Decompiler.FlowAnalysis -{ - /// - /// Represents a variable used with the SsaInstruction register-based instructions. - /// Despite what the name suggests, the variable is not necessarily in single-assignment form - take a look at "bool IsSingleAssignment". - /// - public sealed class SsaVariable - { - public int OriginalVariableIndex; - public readonly string Name; - public readonly bool IsStackLocation; - - public readonly ParameterDefinition Parameter; - public readonly VariableDefinition Variable; - - public SsaVariable(ParameterDefinition p) - { - Name = string.IsNullOrEmpty(p.Name) ? "param" + p.Index : p.Name; - Parameter = p; - } - - public SsaVariable(VariableDefinition v) - { - Name = string.IsNullOrEmpty(v.Name) ? "V_" + v.Index : v.Name; - Variable = v; - } - - public SsaVariable(int stackLocation) - { - Name = "stack" + stackLocation; - IsStackLocation = true; - } - - public SsaVariable(SsaVariable original, string newName) - { - Name = newName; - IsStackLocation = original.IsStackLocation; - OriginalVariableIndex = original.OriginalVariableIndex; - Parameter = original.Parameter; - Variable = original.Variable; - } - - public override string ToString() - { - return Name; - } - - /// - /// Gets whether this variable has only a single assignment. - /// This field is initialized in TransformToSsa step. - /// - /// Not all variables can be transformed to single assignment form: variables that have their address taken - /// cannot be represented in SSA (although SimplifyByRefCalls will get rid of the address-taking instruction in almost all cases) - public bool IsSingleAssignment; - - /// - /// Gets the instruction defining the variable. - /// This field is initialized in TransformToSsa step. It is only set for variables with a single assignment. - /// - public SsaInstruction Definition; - - /// - /// Gets the places where a variable is used. - /// If a single instruction reads a variable 2 times (e.g. adding to itself), then it must be included 2 times in this list! - /// - public List Usage; - } -} diff --git a/ICSharpCode.Decompiler/FlowAnalysis/TransformToSsa.cs b/ICSharpCode.Decompiler/FlowAnalysis/TransformToSsa.cs deleted file mode 100644 index 47ff7bff..00000000 --- a/ICSharpCode.Decompiler/FlowAnalysis/TransformToSsa.cs +++ /dev/null @@ -1,254 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Diagnostics; -using System.Linq; - -using Mono.Cecil; -using Mono.Cecil.Cil; - -namespace ICSharpCode.Decompiler.FlowAnalysis -{ - /// - /// Convers a method to static single assignment form. - /// - internal sealed class TransformToSsa - { - public static void Transform(ControlFlowGraph cfg, SsaForm ssa, bool optimize = true) - { - TransformToSsa transform = new TransformToSsa(cfg, ssa); - transform.ConvertVariablesToSsa(); - SsaOptimization.RemoveDeadAssignments(ssa); // required so that 'MakeByRefCallsSimple' can detect more cases - if (SimplifyByRefCalls.MakeByRefCallsSimple(ssa)) { - transform.ConvertVariablesToSsa(); - } - if (optimize) - SsaOptimization.Optimize(ssa); - } - - readonly ControlFlowGraph cfg; - readonly SsaForm ssaForm; - readonly List[] writeToOriginalVariables; // array index -> SsaVariable OriginalVariableIndex - readonly bool[] addressTaken; // array index -> SsaVariable OriginalVariableIndex; value = whether ldloca instruction was used with variable - - TransformToSsa(ControlFlowGraph cfg, SsaForm ssaForm) - { - this.cfg = cfg; - this.ssaForm = ssaForm; - writeToOriginalVariables = new List[ssaForm.OriginalVariables.Count]; - addressTaken = new bool[ssaForm.OriginalVariables.Count]; - } - - #region CollectInformationAboutOriginalVariableUse - void CollectInformationAboutOriginalVariableUse() - { - Debug.Assert(addressTaken.Length == writeToOriginalVariables.Length); - for (int i = 0; i < writeToOriginalVariables.Length; i++) { - Debug.Assert(ssaForm.OriginalVariables[i].OriginalVariableIndex == i); - - addressTaken[i] = false; - // writeToOriginalVariables is only used when placing phi functions - // we don't need to do that anymore for variables that are already in SSA form - if (ssaForm.OriginalVariables[i].IsSingleAssignment) - writeToOriginalVariables[i] = null; - else - writeToOriginalVariables[i] = new List(); - } - foreach (SsaBlock block in ssaForm.Blocks) { - foreach (SsaInstruction inst in block.Instructions) { - if (inst.Target != null ) { - var list = writeToOriginalVariables[inst.Target.OriginalVariableIndex]; - if (list != null) - list.Add(inst); - } - if (inst.Instruction != null) { - if (inst.Instruction.OpCode == OpCodes.Ldloca) { - addressTaken[ssaForm.GetOriginalVariable((VariableDefinition)inst.Instruction.Operand).OriginalVariableIndex] = true; - } else if (inst.Instruction.OpCode == OpCodes.Ldarga) { - addressTaken[ssaForm.GetOriginalVariable((ParameterDefinition)inst.Instruction.Operand).OriginalVariableIndex] = true; - } - } - } - } - } - #endregion - - #region ConvertToSsa - void ConvertVariablesToSsa() - { - CollectInformationAboutOriginalVariableUse(); - bool[] processVariable = new bool[ssaForm.OriginalVariables.Count]; - foreach (SsaVariable variable in ssaForm.OriginalVariables) { - if (!variable.IsSingleAssignment && !addressTaken[variable.OriginalVariableIndex]) { - PlacePhiFunctions(variable); - processVariable[variable.OriginalVariableIndex] = true; - } - } - RenameVariables(processVariable); - foreach (SsaVariable variable in ssaForm.OriginalVariables) { - if (!addressTaken[variable.OriginalVariableIndex]) { - Debug.Assert(variable.IsSingleAssignment && variable.Definition != null); - } - } - ssaForm.ComputeVariableUsage(); - } - #endregion - - #region PlacePhiFunctions - void PlacePhiFunctions(SsaVariable variable) - { - cfg.ResetVisited(); - HashSet blocksWithPhi = new HashSet(); - Queue worklist = new Queue(); - foreach (SsaInstruction writeInstruction in writeToOriginalVariables[variable.OriginalVariableIndex]) { - ControlFlowNode cfgNode = cfg.Nodes[writeInstruction.ParentBlock.BlockIndex]; - if (!cfgNode.Visited) { - cfgNode.Visited = true; - worklist.Enqueue(cfgNode); - } - } - while (worklist.Count > 0) { - ControlFlowNode cfgNode = worklist.Dequeue(); - foreach (ControlFlowNode dfNode in cfgNode.DominanceFrontier) { - // we don't need phi functions in the exit node - if (dfNode.NodeType == ControlFlowNodeType.RegularExit || dfNode.NodeType == ControlFlowNodeType.ExceptionalExit) - continue; - SsaBlock y = ssaForm.Blocks[dfNode.BlockIndex]; - if (blocksWithPhi.Add(y)) { - // add a phi instruction in y - SsaVariable[] operands = Enumerable.Repeat(variable, dfNode.Incoming.Count).ToArray(); - y.Instructions.Insert(0, new SsaInstruction(y, null, variable, operands, specialOpCode: SpecialOpCode.Phi)); - if (!dfNode.Visited) { - dfNode.Visited = true; - worklist.Enqueue(dfNode); - } - } - } - } - } - #endregion - - #region RenameVariable - int tempVariableCounter = 1; - - void RenameVariables(bool[] processVariable) - { - VariableRenamer r = new VariableRenamer(this, processVariable); - r.Visit(ssaForm.EntryPoint); - } - - sealed class VariableRenamer - { - readonly TransformToSsa transform; - readonly ReadOnlyCollection inputVariables; - internal readonly Stack[] versionStacks; - int[] versionCounters; // specifies for each input variable the next version number - - // processVariable = specifies for each input variable whether we should rename it - public VariableRenamer(TransformToSsa transform, bool[] processVariable) - { - this.transform = transform; - inputVariables = transform.ssaForm.OriginalVariables; - Debug.Assert(inputVariables.Count == processVariable.Length); - versionCounters = new int[inputVariables.Count]; - versionStacks = new Stack[inputVariables.Count]; - for (int i = 0; i < versionStacks.Length; i++) { - if (processVariable[i]) { - Debug.Assert(inputVariables[i].IsSingleAssignment == false); - // only create version stacks for the variables that we need to process and that weren't already processed earlier - versionStacks[i] = new Stack(); - versionStacks[i].Push(inputVariables[i]); - } - } - } - - SsaVariable MakeNewVersion(int variableIndex) - { - int versionCounter = ++versionCounters[variableIndex]; - SsaVariable x = inputVariables[variableIndex]; - if (versionCounter == 1) { - return x; - } else { - if (x.IsStackLocation) { - return new SsaVariable(x, "temp" + (transform.tempVariableCounter++)); - } else { - return new SsaVariable(x, x.Name + "_" + versionCounter); - } - } - } - - internal void Visit(SsaBlock block) - { - // duplicate top of all stacks - foreach (var stack in versionStacks) { - if (stack != null) - stack.Push(stack.Peek()); - } - - foreach (SsaInstruction s in block.Instructions) { - // replace all uses of variables being processed with their current version. - if (s.SpecialOpCode != SpecialOpCode.Phi) { - for (int i = 0; i < s.Operands.Length; i++) { - var stack = versionStacks[s.Operands[i].OriginalVariableIndex]; - if (stack != null) - s.Operands[i] = stack.Peek(); - } - } - // if we're writing to a variable we should process: - if (s.Target != null) { - int targetIndex = s.Target.OriginalVariableIndex; - if (versionStacks[targetIndex] != null) { - s.Target = MakeNewVersion(targetIndex); - s.Target.IsSingleAssignment = true; - s.Target.Definition = s; - - // we already pushed our entry for this SsaBlock at the beginning (where we duplicated all stacks), - // so now replace the top element - versionStacks[targetIndex].Pop(); - versionStacks[targetIndex].Push(s.Target); - } - } - } - - foreach (SsaBlock succ in block.Successors) { - int j = succ.Predecessors.IndexOf(block); - Debug.Assert(j >= 0); - foreach (SsaInstruction f in succ.Instructions) { - if (f.SpecialOpCode == SpecialOpCode.Phi) { - var stack = versionStacks[f.Target.OriginalVariableIndex]; - if (stack != null) { - f.Operands[j] = stack.Peek(); - } - } - } - } - foreach (ControlFlowNode child in transform.cfg.Nodes[block.BlockIndex].DominatorTreeChildren) - Visit(transform.ssaForm.Blocks[child.BlockIndex]); - // restore stacks: - foreach (var stack in versionStacks) { - if (stack != null) - stack.Pop(); - } - } - } - #endregion - } -} diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj deleted file mode 100644 index 31972971..00000000 --- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj +++ /dev/null @@ -1,167 +0,0 @@ - - - - {984CC812-9470-4A13-AFF9-CC44068D666C} - Debug - AnyCPU - Library - ICSharpCode.Decompiler - ICSharpCode.Decompiler - v4.5.1 - Properties - False - False - 4 - false - false - ..\NRefactory\ICSharpCode.NRefactory.snk - False - File - ..\ - true - - - AnyCPU - False - Auto - 448462848 - - - bin\Debug\ - true - Full - False - True - DEBUG;TRACE - - - bin\Release\ - true - PdbOnly - True - False - TRACE - - - true - 0219;0414 - - - true - 0219;0414 - - - - - - - - ..\packages\ICSharpCode.NRefactory.5.5.1\lib\Net40\ICSharpCode.NRefactory.dll - - - ..\packages\ICSharpCode.NRefactory.5.5.1\lib\Net40\ICSharpCode.NRefactory.Cecil.dll - - - ..\packages\ICSharpCode.NRefactory.5.5.1\lib\Net40\ICSharpCode.NRefactory.CSharp.dll - - - ..\packages\ICSharpCode.NRefactory.5.5.1\lib\Net40\ICSharpCode.NRefactory.Xml.dll - - - ..\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.dll - - - ..\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Mdb.dll - - - ..\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Pdb.dll - - - ..\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Rocks.dll - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.sln b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.sln deleted file mode 100644 index daa5dc43..00000000 --- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.sln +++ /dev/null @@ -1,17 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2010 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.Decompiler", "ICSharpCode.Decompiler.csproj", "{984CC812-9470-4A13-AFF9-CC44068D666C}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {984CC812-9470-4A13-AFF9-CC44068D666C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {984CC812-9470-4A13-AFF9-CC44068D666C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {984CC812-9470-4A13-AFF9-CC44068D666C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {984CC812-9470-4A13-AFF9-CC44068D666C}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection -EndGlobal diff --git a/ICSharpCode.Decompiler/ILAst/AsyncDecompiler.cs b/ICSharpCode.Decompiler/ILAst/AsyncDecompiler.cs deleted file mode 100644 index 801673f9..00000000 --- a/ICSharpCode.Decompiler/ILAst/AsyncDecompiler.cs +++ /dev/null @@ -1,704 +0,0 @@ -// Copyright (c) 2012 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using Mono.Cecil; -using Mono.Cecil.Cil; - -namespace ICSharpCode.Decompiler.ILAst -{ - /// - /// Decompiler step for C# 5 async/await. - /// - internal class AsyncDecompiler - { - public static bool IsCompilerGeneratedStateMachine(TypeDefinition type) - { - if (!(type.DeclaringType != null && type.IsCompilerGenerated())) - return false; - foreach (TypeReference i in type.Interfaces) { - if (i.Namespace == "System.Runtime.CompilerServices" && i.Name == "IAsyncStateMachine") - return true; - } - return false; - } - - enum AsyncMethodType - { - Void, - Task, - TaskOfT - } - - DecompilerContext context; - - // These fields are set by MatchTaskCreationPattern() - AsyncMethodType methodType; - int initialState; - TypeDefinition stateMachineStruct; - MethodDefinition moveNextMethod; - FieldDefinition builderField; - FieldDefinition stateField; - Dictionary fieldToParameterMap = new Dictionary(); - ILVariable cachedStateVar; - - // These fields are set by AnalyzeMoveNext() - int finalState = -2; - ILTryCatchBlock mainTryCatch; - ILLabel setResultAndExitLabel; - ILLabel exitLabel; - ILExpression resultExpr; - - #region RunStep1() method - public static void RunStep1(DecompilerContext context, ILBlock method) - { - if (!context.Settings.AsyncAwait) - return; // abort if async decompilation is disabled - var yrd = new AsyncDecompiler(); - yrd.context = context; - if (!yrd.MatchTaskCreationPattern(method)) - return; - #if DEBUG - if (Debugger.IsAttached) { - yrd.Run(); - } else { - #endif - try { - yrd.Run(); - } catch (SymbolicAnalysisFailedException) { - return; - } - #if DEBUG - } - #endif - context.CurrentMethodIsAsync = true; - - method.Body.Clear(); - method.EntryGoto = null; - method.Body.AddRange(yrd.newTopLevelBody); - ILAstOptimizer.RemoveRedundantCode(method); - } - - void Run() - { - AnalyzeMoveNext(); - ValidateCatchBlock(mainTryCatch.CatchBlocks[0]); - AnalyzeStateMachine(mainTryCatch.TryBlock); - // AnalyzeStateMachine invokes ConvertBody - MarkGeneratedVariables(); - YieldReturnDecompiler.TranslateFieldsToLocalAccess(newTopLevelBody, fieldToParameterMap); - } - #endregion - - #region MatchTaskCreationPattern - bool MatchTaskCreationPattern(ILBlock method) - { - if (method.Body.Count < 5) - return false; - // Check the second-to-last instruction (the start call) first, as we can get the most information from that - MethodReference startMethod; - ILExpression loadStartTarget, loadStartArgument; - // call(AsyncTaskMethodBuilder::Start, ldloca(builder), ldloca(stateMachine)) - if (!method.Body[method.Body.Count - 2].Match(ILCode.Call, out startMethod, out loadStartTarget, out loadStartArgument)) - return false; - if (startMethod.Name != "Start" || startMethod.DeclaringType == null || startMethod.DeclaringType.Namespace != "System.Runtime.CompilerServices") - return false; - switch (startMethod.DeclaringType.Name) { - case "AsyncTaskMethodBuilder`1": - methodType = AsyncMethodType.TaskOfT; - break; - case "AsyncTaskMethodBuilder": - methodType = AsyncMethodType.Task; - break; - case "AsyncVoidMethodBuilder": - methodType = AsyncMethodType.Void; - break; - default: - return false; - } - ILVariable stateMachineVar, builderVar; - if (!loadStartTarget.Match(ILCode.Ldloca, out builderVar)) - return false; - if (!loadStartArgument.Match(ILCode.Ldloca, out stateMachineVar)) - return false; - - stateMachineStruct = stateMachineVar.Type.ResolveWithinSameModule(); - if (stateMachineStruct == null || !stateMachineStruct.IsValueType) - return false; - moveNextMethod = stateMachineStruct.Methods.FirstOrDefault(f => f.Name == "MoveNext"); - if (moveNextMethod == null) - return false; - - // Check third-to-last instruction (copy of builder): - // stloc(builder, ldfld(StateMachine::<>t__builder, ldloca(stateMachine))) - ILExpression loadBuilderExpr; - if (!method.Body[method.Body.Count - 3].MatchStloc(builderVar, out loadBuilderExpr)) - return false; - FieldReference builderFieldRef; - ILExpression loadStateMachineForBuilderExpr; - if (!loadBuilderExpr.Match(ILCode.Ldfld, out builderFieldRef, out loadStateMachineForBuilderExpr)) - return false; - if (!(loadStateMachineForBuilderExpr.MatchLdloca(stateMachineVar) || loadStateMachineForBuilderExpr.MatchLdloc(stateMachineVar))) - return false; - builderField = builderFieldRef.ResolveWithinSameModule(); - if (builderField == null) - return false; - - // Check the last instruction (ret) - if (methodType == AsyncMethodType.Void) { - if (!method.Body[method.Body.Count - 1].Match(ILCode.Ret)) - return false; - } else { - // ret(call(AsyncTaskMethodBuilder::get_Task, ldflda(StateMachine::<>t__builder, ldloca(stateMachine)))) - ILExpression returnValue; - if (!method.Body[method.Body.Count - 1].Match(ILCode.Ret, out returnValue)) - return false; - MethodReference getTaskMethod; - ILExpression builderExpr; - if (!returnValue.Match(ILCode.Call, out getTaskMethod, out builderExpr)) - return false; - ILExpression loadStateMachineForBuilderExpr2; - FieldReference builderField2; - if (!builderExpr.Match(ILCode.Ldflda, out builderField2, out loadStateMachineForBuilderExpr2)) - return false; - if (builderField2.ResolveWithinSameModule() != builderField || !loadStateMachineForBuilderExpr2.MatchLdloca(stateMachineVar)) - return false; - } - - // Check the last field assignment - this should be the state field - ILExpression initialStateExpr; - if (!MatchStFld(method.Body[method.Body.Count - 4], stateMachineVar, out stateField, out initialStateExpr)) - return false; - if (!initialStateExpr.Match(ILCode.Ldc_I4, out initialState)) - return false; - if (initialState != -1) - return false; - - // Check the second-to-last field assignment - this should be the builder field - FieldDefinition builderField3; - ILExpression builderInitialization; - if (!MatchStFld(method.Body[method.Body.Count - 5], stateMachineVar, out builderField3, out builderInitialization)) - return false; - MethodReference createMethodRef; - if (builderField3 != builderField || !builderInitialization.Match(ILCode.Call, out createMethodRef)) - return false; - if (createMethodRef.Name != "Create") - return false; - - for (int i = 0; i < method.Body.Count - 5; i++) { - FieldDefinition field; - ILExpression fieldInit; - if (!MatchStFld(method.Body[i], stateMachineVar, out field, out fieldInit)) - return false; - ILVariable v; - if (!fieldInit.Match(ILCode.Ldloc, out v)) - return false; - if (!v.IsParameter) - return false; - fieldToParameterMap[field] = v; - } - - return true; - } - - static bool MatchStFld(ILNode stfld, ILVariable stateMachineVar, out FieldDefinition field, out ILExpression expr) - { - field = null; - FieldReference fieldRef; - ILExpression ldloca; - if (!stfld.Match(ILCode.Stfld, out fieldRef, out ldloca, out expr)) - return false; - field = fieldRef.ResolveWithinSameModule(); - return field != null && ldloca.MatchLdloca(stateMachineVar); - } - #endregion - - #region Analyze MoveNext - void AnalyzeMoveNext() - { - ILBlock ilMethod = CreateILAst(moveNextMethod); - - int startIndex; - if (ilMethod.Body.Count == 6) { - startIndex = 0; - } else if (ilMethod.Body.Count == 7) { - // stloc(cachedState, ldfld(valuetype StateMachineStruct::<>1__state, ldloc(this))) - ILExpression cachedStateInit; - if (!ilMethod.Body[0].Match(ILCode.Stloc, out cachedStateVar, out cachedStateInit)) - throw new SymbolicAnalysisFailedException(); - ILExpression instanceExpr; - FieldReference loadedField; - if (!cachedStateInit.Match(ILCode.Ldfld, out loadedField, out instanceExpr) || loadedField.ResolveWithinSameModule() != stateField || !instanceExpr.MatchThis()) - throw new SymbolicAnalysisFailedException(); - startIndex = 1; - } else { - throw new SymbolicAnalysisFailedException(); - } - - mainTryCatch = ilMethod.Body[startIndex + 0] as ILTryCatchBlock; - if (mainTryCatch == null || mainTryCatch.CatchBlocks.Count != 1) - throw new SymbolicAnalysisFailedException(); - if (mainTryCatch.FaultBlock != null || mainTryCatch.FinallyBlock != null) - throw new SymbolicAnalysisFailedException(); - - setResultAndExitLabel = ilMethod.Body[startIndex + 1] as ILLabel; - if (setResultAndExitLabel == null) - throw new SymbolicAnalysisFailedException(); - - if (!MatchStateAssignment(ilMethod.Body[startIndex + 2], out finalState)) - throw new SymbolicAnalysisFailedException(); - - // call(AsyncTaskMethodBuilder`1::SetResult, ldflda(StateMachine::<>t__builder, ldloc(this)), ldloc(<>t__result)) - MethodReference setResultMethod; - ILExpression builderExpr; - if (methodType == AsyncMethodType.TaskOfT) { - if (!ilMethod.Body[startIndex + 3].Match(ILCode.Call, out setResultMethod, out builderExpr, out resultExpr)) - throw new SymbolicAnalysisFailedException(); - } else { - if (!ilMethod.Body[startIndex + 3].Match(ILCode.Call, out setResultMethod, out builderExpr)) - throw new SymbolicAnalysisFailedException(); - } - if (!(setResultMethod.Name == "SetResult" && IsBuilderFieldOnThis(builderExpr))) - throw new SymbolicAnalysisFailedException(); - - exitLabel = ilMethod.Body[startIndex + 4] as ILLabel; - if (exitLabel == null) - throw new SymbolicAnalysisFailedException(); - } - - /// - /// Creates ILAst for the specified method, optimized up to before the 'YieldReturn' step. - /// - ILBlock CreateILAst(MethodDefinition method) - { - if (method == null || !method.HasBody) - throw new SymbolicAnalysisFailedException(); - - ILBlock ilMethod = new ILBlock(); - ILAstBuilder astBuilder = new ILAstBuilder(); - ilMethod.Body = astBuilder.Build(method, true, context); - ILAstOptimizer optimizer = new ILAstOptimizer(); - optimizer.Optimize(context, ilMethod, ILAstOptimizationStep.YieldReturn); - return ilMethod; - } - - void ValidateCatchBlock(ILTryCatchBlock.CatchBlock catchBlock) - { - if (catchBlock.ExceptionType == null || catchBlock.ExceptionType.Name != "Exception") - throw new SymbolicAnalysisFailedException(); - if (catchBlock.Body.Count != 3) - throw new SymbolicAnalysisFailedException(); - int stateID; - if (!(MatchStateAssignment(catchBlock.Body[0], out stateID) && stateID == finalState)) - throw new SymbolicAnalysisFailedException(); - MethodReference setExceptionMethod; - ILExpression builderExpr, exceptionExpr; - if (!catchBlock.Body[1].Match(ILCode.Call, out setExceptionMethod, out builderExpr, out exceptionExpr)) - throw new SymbolicAnalysisFailedException(); - if (!(setExceptionMethod.Name == "SetException" && IsBuilderFieldOnThis(builderExpr) && exceptionExpr.MatchLdloc(catchBlock.ExceptionVariable))) - throw new SymbolicAnalysisFailedException(); - - ILLabel label; - if (!(catchBlock.Body[2].Match(ILCode.Leave, out label) && label == exitLabel)) - throw new SymbolicAnalysisFailedException(); - } - - bool IsBuilderFieldOnThis(ILExpression builderExpr) - { - // ldflda(StateMachine::<>t__builder, ldloc(this)) - FieldReference fieldRef; - ILExpression target; - return builderExpr.Match(ILCode.Ldflda, out fieldRef, out target) - && fieldRef.ResolveWithinSameModule() == builderField - && target.MatchThis(); - } - - bool MatchStateAssignment(ILNode stfld, out int stateID) - { - // stfld(StateMachine::<>1__state, ldloc(this), ldc.i4(stateId)) - stateID = 0; - FieldReference fieldRef; - ILExpression target, val; - if (stfld.Match(ILCode.Stfld, out fieldRef, out target, out val)) { - return fieldRef.ResolveWithinSameModule() == stateField - && target.MatchThis() - && val.Match(ILCode.Ldc_I4, out stateID); - } - return false; - } - - bool MatchRoslynStateAssignment(List block, int index, out int stateID) - { - // v = ldc.i4(stateId) - // stloc(cachedState, v) - // stfld(StateMachine::<>1__state, ldloc(this), v) - stateID = 0; - if (index < 0) - return false; - ILVariable v; - ILExpression val; - if (!block[index].Match(ILCode.Stloc, out v, out val) || !val.Match(ILCode.Ldc_I4, out stateID)) - return false; - ILExpression loadV; - if (!block[index + 1].MatchStloc(cachedStateVar, out loadV) || !loadV.MatchLdloc(v)) - return false; - ILExpression target; - FieldReference fieldRef; - if (block[index + 2].Match(ILCode.Stfld, out fieldRef, out target, out loadV)) { - return fieldRef.ResolveWithinSameModule() == stateField - && target.MatchThis() - && loadV.MatchLdloc(v); - } - return false; - } - #endregion - - #region AnalyzeStateMachine - ILVariable doFinallyBodies; - List newTopLevelBody; - - void AnalyzeStateMachine(ILBlock block) - { - var body = block.Body; - if (body.Count == 0) - throw new SymbolicAnalysisFailedException(); - if (DetectDoFinallyBodies(body)) { - body.RemoveAt(0); - if (body.Count == 0) - throw new SymbolicAnalysisFailedException(); - } - StateRangeAnalysis rangeAnalysis = new StateRangeAnalysis(body[0], StateRangeAnalysisMode.AsyncMoveNext, stateField, cachedStateVar); - int bodyLength = block.Body.Count; - int pos = rangeAnalysis.AssignStateRanges(body, bodyLength); - rangeAnalysis.EnsureLabelAtPos(body, ref pos, ref bodyLength); - - var labelStateRangeMapping = rangeAnalysis.CreateLabelRangeMapping(body, pos, bodyLength); - newTopLevelBody = ConvertBody(body, pos, bodyLength, labelStateRangeMapping); - newTopLevelBody.Insert(0, MakeGoTo(labelStateRangeMapping, initialState)); - newTopLevelBody.Add(setResultAndExitLabel); - if (methodType == AsyncMethodType.TaskOfT) { - newTopLevelBody.Add(new ILExpression(ILCode.Ret, null, resultExpr)); - } else { - newTopLevelBody.Add(new ILExpression(ILCode.Ret, null)); - } - } - - bool DetectDoFinallyBodies(List body) - { - ILVariable v; - ILExpression initExpr; - if (!body[0].Match(ILCode.Stloc, out v, out initExpr)) - return false; - int initialValue; - if (!(initExpr.Match(ILCode.Ldc_I4, out initialValue) && initialValue == 1)) - return false; - doFinallyBodies = v; - return true; - } - #endregion - - #region ConvertBody - ILExpression MakeGoTo(LabelRangeMapping mapping, int state) - { - foreach (var pair in mapping) { - if (pair.Value.Contains(state)) - return new ILExpression(ILCode.Br, pair.Key); - } - throw new SymbolicAnalysisFailedException(); - } - - List ConvertBody(List body, int startPos, int bodyLength, LabelRangeMapping mapping) - { - List newBody = new List(); - // Copy all instructions from the old body to newBody. - for (int pos = startPos; pos < bodyLength; pos++) { - ILTryCatchBlock tryCatchBlock = body[pos] as ILTryCatchBlock; - ILExpression expr = body[pos] as ILExpression; - if (expr != null && expr.Code == ILCode.Leave && expr.Operand == exitLabel) { - ILVariable awaiterVar; - FieldDefinition awaiterField; - int targetStateID; - HandleAwait(newBody, out awaiterVar, out awaiterField, out targetStateID); - MarkAsGeneratedVariable(awaiterVar); - newBody.Add(new ILExpression(ILCode.Await, null, new ILExpression(ILCode.Ldloca, awaiterVar))); - newBody.Add(MakeGoTo(mapping, targetStateID)); - } else if (tryCatchBlock != null) { - ILTryCatchBlock newTryCatchBlock = new ILTryCatchBlock(); - var tryBody = tryCatchBlock.TryBlock.Body; - if (tryBody.Count == 0) - throw new SymbolicAnalysisFailedException(); - StateRangeAnalysis rangeAnalysis = new StateRangeAnalysis(tryBody[0], StateRangeAnalysisMode.AsyncMoveNext, stateField); - int tryBodyLength = tryBody.Count; - int posInTryBody = rangeAnalysis.AssignStateRanges(tryBody, tryBodyLength); - rangeAnalysis.EnsureLabelAtPos(tryBody, ref posInTryBody, ref tryBodyLength); - - var mappingInTryBlock = rangeAnalysis.CreateLabelRangeMapping(tryBody, posInTryBody, tryBodyLength); - var newTryBody = ConvertBody(tryBody, posInTryBody, tryBodyLength, mappingInTryBlock); - newTryBody.Insert(0, MakeGoTo(mappingInTryBlock, initialState)); - - // If there's a label at the beginning of the state dispatcher, copy that - if (posInTryBody > 0 && tryBody.FirstOrDefault() is ILLabel) - newTryBody.Insert(0, tryBody.First()); - - newTryCatchBlock.TryBlock = new ILBlock(newTryBody); - newTryCatchBlock.CatchBlocks = new List(tryCatchBlock.CatchBlocks); - newTryCatchBlock.FaultBlock = tryCatchBlock.FaultBlock; - if (tryCatchBlock.FinallyBlock != null) - newTryCatchBlock.FinallyBlock = new ILBlock(ConvertFinally(tryCatchBlock.FinallyBlock.Body)); - - newBody.Add(newTryCatchBlock); - } else { - newBody.Add(body[pos]); - } - } - return newBody; - } - - List ConvertFinally(List body) - { - List newBody = new List(body); - if (newBody.Count == 0) - return newBody; - ILLabel endFinallyLabel; - ILExpression ceqExpr; - if (newBody[0].Match(ILCode.Brtrue, out endFinallyLabel, out ceqExpr)) { - ILExpression condition; - if (MatchLogicNot(ceqExpr, out condition)) { - if (condition.MatchLdloc(doFinallyBodies)) { - newBody.RemoveAt(0); - } else if (condition.Code == ILCode.Clt && condition.Arguments[0].MatchLdloc(cachedStateVar) && condition.Arguments[1].MatchLdcI4(0)) { - newBody.RemoveAt(0); - } - } - } - return newBody; - } - - bool MatchLogicNot(ILExpression expr, out ILExpression arg) - { - ILExpression loadZero; - object unused; - if (expr.Match(ILCode.Ceq, out unused, out arg, out loadZero)) { - int num; - return loadZero.Match(ILCode.Ldc_I4, out num) && num == 0; - } - return expr.Match(ILCode.LogicNot, out arg); - } - - void HandleAwait(List newBody, out ILVariable awaiterVar, out FieldDefinition awaiterField, out int targetStateID) - { - // Handle the instructions prior to the exit out of the method to detect what is being awaited. - // (analyses the last instructions in newBody and removes the analyzed instructions from newBody) - - if (doFinallyBodies != null) { - // stloc(<>t__doFinallyBodies, ldc.i4(0)) - ILExpression dfbInitExpr; - if (!newBody.LastOrDefault().MatchStloc(doFinallyBodies, out dfbInitExpr)) - throw new SymbolicAnalysisFailedException(); - int val; - if (!(dfbInitExpr.Match(ILCode.Ldc_I4, out val) && val == 0)) - throw new SymbolicAnalysisFailedException(); - newBody.RemoveAt(newBody.Count - 1); // remove doFinallyBodies assignment - } - - // call(AsyncTaskMethodBuilder::AwaitUnsafeOnCompleted, ldflda(StateMachine::<>t__builder, ldloc(this)), ldloca(CS$0$0001), ldloc(this)) - ILExpression callAwaitUnsafeOnCompleted = newBody.LastOrDefault() as ILExpression; - newBody.RemoveAt(newBody.Count - 1); // remove AwaitUnsafeOnCompleted call - if (callAwaitUnsafeOnCompleted == null || callAwaitUnsafeOnCompleted.Code != ILCode.Call) - throw new SymbolicAnalysisFailedException(); - string methodName = ((MethodReference)callAwaitUnsafeOnCompleted.Operand).Name; - if (methodName != "AwaitUnsafeOnCompleted" && methodName != "AwaitOnCompleted") - throw new SymbolicAnalysisFailedException(); - if (callAwaitUnsafeOnCompleted.Arguments.Count != 3) - throw new SymbolicAnalysisFailedException(); - if (!callAwaitUnsafeOnCompleted.Arguments[1].Match(ILCode.Ldloca, out awaiterVar)) - throw new SymbolicAnalysisFailedException(); - - // stfld(StateMachine::<>u__$awaiter6, ldloc(this), ldloc(CS$0$0001)) - FieldReference awaiterFieldRef; - ILExpression loadThis, loadAwaiterVar; - if (!newBody.LastOrDefault().Match(ILCode.Stfld, out awaiterFieldRef, out loadThis, out loadAwaiterVar)) - throw new SymbolicAnalysisFailedException(); - newBody.RemoveAt(newBody.Count - 1); // remove awaiter field assignment - awaiterField = awaiterFieldRef.ResolveWithinSameModule(); - if (!(awaiterField != null && loadThis.MatchThis() && loadAwaiterVar.MatchLdloc(awaiterVar))) - throw new SymbolicAnalysisFailedException(); - - // stfld(StateMachine::<>1__state, ldloc(this), ldc.i4(0)) - if (MatchStateAssignment(newBody.LastOrDefault(), out targetStateID)) - newBody.RemoveAt(newBody.Count - 1); // remove awaiter field assignment - else if (MatchRoslynStateAssignment(newBody, newBody.Count - 3, out targetStateID)) - newBody.RemoveRange(newBody.Count - 3, 3); // remove awaiter field assignment - } - #endregion - - #region MarkGeneratedVariables - int smallestGeneratedVariableIndex = int.MaxValue; - - void MarkAsGeneratedVariable(ILVariable v) - { - if (v.OriginalVariable != null && v.OriginalVariable.Index >= 0) { - smallestGeneratedVariableIndex = Math.Min(smallestGeneratedVariableIndex, v.OriginalVariable.Index); - } - } - - void MarkGeneratedVariables() - { - var expressions = new ILBlock(newTopLevelBody).GetSelfAndChildrenRecursive(); - foreach (var v in expressions.Select(e => e.Operand).OfType()) { - if (v.OriginalVariable != null && v.OriginalVariable.Index >= smallestGeneratedVariableIndex) - v.IsGenerated = true; - } - } - #endregion - - #region RunStep2() method - public static void RunStep2(DecompilerContext context, ILBlock method) - { - if (context.CurrentMethodIsAsync) { - Step2(method.Body); - ILAstOptimizer.RemoveRedundantCode(method); - // Repeat the inlining/copy propagation optimization because the conversion of field access - // to local variables can open up additional inlining possibilities. - ILInlining inlining = new ILInlining(method); - inlining.InlineAllVariables(); - inlining.CopyPropagation(); - } - } - - static void Step2(List body) - { - for (int pos = 0; pos < body.Count; pos++) { - ILTryCatchBlock tc = body[pos] as ILTryCatchBlock; - if (tc != null) { - Step2(tc.TryBlock.Body); - } else { - Step2(body, ref pos); - } - } - } - - static bool Step2(List body, ref int pos) - { - // stloc(CS$0$0001, callvirt(class System.Threading.Tasks.Task`1::GetAwaiter, awaiterExpr) - // brtrue(IL_7C, call(valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter`1::get_IsCompleted, ldloca(CS$0$0001))) - // await(ldloca(CS$0$0001)) - // ... - // IL_7C: - // arg_8B_0 = call(valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter`1::GetResult, ldloca(CS$0$0001)) - // initobj(valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter`1, ldloca(CS$0$0001)) - - ILExpression loadAwaiter; - ILVariable awaiterVar; - if (!body[pos].Match(ILCode.Await, out loadAwaiter)) - return false; - if (!loadAwaiter.Match(ILCode.Ldloca, out awaiterVar)) - return false; - - ILVariable stackVar; - ILExpression stackExpr; - while (pos >= 1 && body[pos - 1].Match(ILCode.Stloc, out stackVar, out stackExpr)) - pos--; - - // stloc(CS$0$0001, callvirt(class System.Threading.Tasks.Task`1::GetAwaiter, awaiterExpr) - ILExpression getAwaiterCall; - if (!(pos >= 2 && body[pos - 2].MatchStloc(awaiterVar, out getAwaiterCall))) - return false; - MethodReference getAwaiterMethod; - ILExpression awaitedExpr; - if (!(getAwaiterCall.Match(ILCode.Call, out getAwaiterMethod, out awaitedExpr) || getAwaiterCall.Match(ILCode.Callvirt, out getAwaiterMethod, out awaitedExpr))) - return false; - - if (awaitedExpr.Code == ILCode.AddressOf) { - // remove 'AddressOf()' when calling GetAwaiter() on a value type - awaitedExpr = awaitedExpr.Arguments[0]; - } - - // brtrue(IL_7C, call(valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter`1::get_IsCompleted, ldloca(CS$0$0001))) - ILLabel label; - ILExpression getIsCompletedCall; - if (!(pos >= 1 && body[pos - 1].Match(ILCode.Brtrue, out label, out getIsCompletedCall))) - return false; - - int labelPos = body.IndexOf(label); - if (labelPos < pos) - return false; - for (int i = pos + 1; i < labelPos; i++) { - // validate that we aren't deleting any unexpected instructions - - // between the await and the label, there should only be the stack, awaiter and state logic - ILExpression expr = body[i] as ILExpression; - if (expr == null) - return false; - switch (expr.Code) { - case ILCode.Stloc: - case ILCode.Initobj: - case ILCode.Stfld: - case ILCode.Await: - // e.g. - // stloc(CS$0$0001, ldfld(StateMachine::<>u__$awaitere, ldloc(this))) - // initobj(valuetype [mscorlib]System.Runtime.CompilerServices.TaskAwaiter`1, ldloca(CS$0$0002_66)) - // stfld('d__d'::<>u__$awaitere, ldloc(this), ldloc(CS$0$0002_66)) - // stfld('d__d'::<>1__state, ldloc(this), ldc.i4(-1)) - break; - default: - return false; - } - } - if (labelPos + 1 >= body.Count) - return false; - ILExpression resultAssignment = body[labelPos + 1] as ILExpression; - ILVariable resultVar; - ILExpression getResultCall; - bool isResultAssignment = resultAssignment.Match(ILCode.Stloc, out resultVar, out getResultCall); - if (!isResultAssignment) - getResultCall = resultAssignment; - if (!(getResultCall.Operand is MethodReference && ((MethodReference)getResultCall.Operand).Name == "GetResult")) - return false; - - pos -= 2; // also delete 'stloc', 'brtrue' and 'await' - body.RemoveRange(pos, labelPos - pos); - Debug.Assert(body[pos] == label); - - pos++; - if (isResultAssignment) { - Debug.Assert(body[pos] == resultAssignment); - resultAssignment.Arguments[0] = new ILExpression(ILCode.Await, null, awaitedExpr); - } else { - body[pos] = new ILExpression(ILCode.Await, null, awaitedExpr); - } - - // if the awaiter variable is cleared out in the next instruction, remove that instruction - if (IsVariableReset(body.ElementAtOrDefault(pos + 1), awaiterVar)) { - body.RemoveAt(pos + 1); - } - - return true; - } - - static bool IsVariableReset(ILNode expr, ILVariable variable) - { - object unused; - ILExpression ldloca; - return expr.Match(ILCode.Initobj, out unused, out ldloca) && ldloca.MatchLdloca(variable); - } - #endregion - } -} diff --git a/ICSharpCode.Decompiler/ILAst/DefaultDictionary.cs b/ICSharpCode.Decompiler/ILAst/DefaultDictionary.cs deleted file mode 100644 index 1e359a3d..00000000 --- a/ICSharpCode.Decompiler/ILAst/DefaultDictionary.cs +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections; -using System.Collections.Generic; - -namespace ICSharpCode.Decompiler.ILAst -{ - /// - /// Dictionary with default values. - /// - internal sealed class DefaultDictionary : IDictionary - { - readonly IDictionary dict; - readonly Func defaultProvider; - - public DefaultDictionary(TValue defaultValue, IDictionary dictionary = null) - : this(key => defaultValue, dictionary) - { - } - - public DefaultDictionary(Func defaultProvider = null, IDictionary dictionary = null) - { - dict = dictionary ?? new Dictionary(); - this.defaultProvider = defaultProvider ?? (key => default(TValue)); - } - - public TValue this[TKey key] { - get { - TValue val; - if (dict.TryGetValue(key, out val)) - return val; - else - return dict[key] = defaultProvider(key); - } - set { - dict[key] = value; - } - } - - public ICollection Keys { - get { return dict.Keys; } - } - - public ICollection Values { - get { return dict.Values; } - } - - public int Count { - get { return dict.Count; } - } - - bool ICollection>.IsReadOnly { - get { return false; } - } - - public bool ContainsKey(TKey key) - { - return dict.ContainsKey(key); - } - - public void Add(TKey key, TValue value) - { - dict.Add(key, value); - } - - public bool Remove(TKey key) - { - return dict.Remove(key); - } - - public bool TryGetValue(TKey key, out TValue value) - { - return dict.TryGetValue(key, out value); - } - - void ICollection>.Add(KeyValuePair item) - { - dict.Add(item); - } - - public void Clear() - { - dict.Clear(); - } - - bool ICollection>.Contains(KeyValuePair item) - { - return dict.Contains(item); - } - - void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) - { - dict.CopyTo(array, arrayIndex); - } - - bool ICollection>.Remove(KeyValuePair item) - { - return dict.Remove(item); - } - - IEnumerator> IEnumerable>.GetEnumerator() - { - return dict.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return dict.GetEnumerator(); - } - } -} \ No newline at end of file diff --git a/ICSharpCode.Decompiler/ILAst/GotoRemoval.cs b/ICSharpCode.Decompiler/ILAst/GotoRemoval.cs deleted file mode 100644 index fafe13e1..00000000 --- a/ICSharpCode.Decompiler/ILAst/GotoRemoval.cs +++ /dev/null @@ -1,319 +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.Diagnostics; -using System.IO; -using System.Collections.Generic; -using System.Linq; - -namespace ICSharpCode.Decompiler.ILAst -{ - public class GotoRemoval - { - Dictionary parent = new Dictionary(); - Dictionary nextSibling = new Dictionary(); - - public void RemoveGotos(ILBlock method) - { - // Build the navigation data - parent[method] = null; - foreach (ILNode node in method.GetSelfAndChildrenRecursive()) { - ILNode previousChild = null; - foreach (ILNode child in node.GetChildren()) { - if (parent.ContainsKey(child)) - throw new Exception("The following expression is linked from several locations: " + child.ToString()); - parent[child] = node; - if (previousChild != null) - nextSibling[previousChild] = child; - previousChild = child; - } - if (previousChild != null) - nextSibling[previousChild] = null; - } - - // Simplify gotos - bool modified; - do { - modified = false; - foreach (ILExpression gotoExpr in method.GetSelfAndChildrenRecursive(e => e.Code == ILCode.Br || e.Code == ILCode.Leave)) { - modified |= TrySimplifyGoto(gotoExpr); - } - } while(modified); - - RemoveRedundantCode(method); - } - - public static void RemoveRedundantCode(ILBlock method) - { - // Remove dead lables and nops - HashSet liveLabels = new HashSet(method.GetSelfAndChildrenRecursive(e => e.IsBranch()).SelectMany(e => e.GetBranchTargets())); - foreach(ILBlock block in method.GetSelfAndChildrenRecursive()) { - block.Body = block.Body.Where(n => !n.Match(ILCode.Nop) && !(n is ILLabel && !liveLabels.Contains((ILLabel)n))).ToList(); - } - - // Remove redundant continue - foreach(ILWhileLoop loop in method.GetSelfAndChildrenRecursive()) { - var body = loop.BodyBlock.Body; - if (body.Count > 0 && body.Last().Match(ILCode.LoopContinue)) { - body.RemoveAt(body.Count - 1); - } - } - - // Remove redundant break at the end of case - // Remove redundant case blocks altogether - foreach(ILSwitch ilSwitch in method.GetSelfAndChildrenRecursive()) { - foreach(ILBlock ilCase in ilSwitch.CaseBlocks) { - Debug.Assert(ilCase.EntryGoto == null); - - int count = ilCase.Body.Count; - if (count >= 2) { - if (ilCase.Body[count - 2].IsUnconditionalControlFlow() && - ilCase.Body[count - 1].Match(ILCode.LoopOrSwitchBreak)) - { - ilCase.Body.RemoveAt(count - 1); - } - } - } - - var defaultCase = ilSwitch.CaseBlocks.SingleOrDefault(cb => cb.Values == null); - // If there is no default block, remove empty case blocks - if (defaultCase == null || (defaultCase.Body.Count == 1 && defaultCase.Body.Single().Match(ILCode.LoopOrSwitchBreak))) { - ilSwitch.CaseBlocks.RemoveAll(b => b.Body.Count == 1 && b.Body.Single().Match(ILCode.LoopOrSwitchBreak)); - } - } - - // Remove redundant return at the end of method - if (method.Body.Count > 0 && method.Body.Last().Match(ILCode.Ret) && ((ILExpression)method.Body.Last()).Arguments.Count == 0) { - method.Body.RemoveAt(method.Body.Count - 1); - } - - // Remove unreachable return statements - bool modified = false; - foreach(ILBlock block in method.GetSelfAndChildrenRecursive()) { - for (int i = 0; i < block.Body.Count - 1;) { - if (block.Body[i].IsUnconditionalControlFlow() && block.Body[i+1].Match(ILCode.Ret)) { - modified = true; - block.Body.RemoveAt(i+1); - } else { - i++; - } - } - } - if (modified) { - // More removals might be possible - new GotoRemoval().RemoveGotos(method); - } - } - - IEnumerable GetParents(ILNode node) - { - ILNode current = node; - while(true) { - current = parent[current]; - if (current == null) - yield break; - yield return current; - } - } - - bool TrySimplifyGoto(ILExpression gotoExpr) - { - Debug.Assert(gotoExpr.Code == ILCode.Br || gotoExpr.Code == ILCode.Leave); - Debug.Assert(gotoExpr.Prefixes == null); - Debug.Assert(gotoExpr.Operand != null); - - ILNode target = Enter(gotoExpr, new HashSet()); - if (target == null) - return false; - - // The gotoExper is marked as visited because we do not want to - // walk over node which we plan to modify - - // The simulated path always has to start in the same try-block - // in other for the same finally blocks to be executed. - - if (target == Exit(gotoExpr, new HashSet() { gotoExpr })) { - gotoExpr.Code = ILCode.Nop; - gotoExpr.Operand = null; - if (target is ILExpression) - ((ILExpression)target).ILRanges.AddRange(gotoExpr.ILRanges); - gotoExpr.ILRanges.Clear(); - return true; - } - - ILNode breakBlock = GetParents(gotoExpr).FirstOrDefault(n => n is ILWhileLoop || n is ILSwitch); - if (breakBlock != null && target == Exit(breakBlock, new HashSet() { gotoExpr })) { - gotoExpr.Code = ILCode.LoopOrSwitchBreak; - gotoExpr.Operand = null; - return true; - } - - ILNode continueBlock = GetParents(gotoExpr).FirstOrDefault(n => n is ILWhileLoop); - if (continueBlock != null && target == Enter(continueBlock, new HashSet() { gotoExpr })) { - gotoExpr.Code = ILCode.LoopContinue; - gotoExpr.Operand = null; - return true; - } - - return false; - } - - /// - /// Get the first expression to be excecuted if the instruction pointer is at the start of the given node. - /// Try blocks may not be entered in any way. If possible, the try block is returned as the node to be executed. - /// - ILNode Enter(ILNode node, HashSet visitedNodes) - { - if (node == null) - throw new ArgumentNullException(); - - if (!visitedNodes.Add(node)) - return null; // Infinite loop - - ILLabel label = node as ILLabel; - if (label != null) { - return Exit(label, visitedNodes); - } - - ILExpression expr = node as ILExpression; - if (expr != null) { - if (expr.Code == ILCode.Br || expr.Code == ILCode.Leave) { - ILLabel target = (ILLabel)expr.Operand; - // Early exit - same try-block - if (GetParents(expr).OfType().FirstOrDefault() == GetParents(target).OfType().FirstOrDefault()) - return Enter(target, visitedNodes); - // Make sure we are not entering any try-block - var srcTryBlocks = GetParents(expr).OfType().Reverse().ToList(); - var dstTryBlocks = GetParents(target).OfType().Reverse().ToList(); - // Skip blocks that we are already in - int i = 0; - while(i < srcTryBlocks.Count && i < dstTryBlocks.Count && srcTryBlocks[i] == dstTryBlocks[i]) i++; - if (i == dstTryBlocks.Count) { - return Enter(target, visitedNodes); - } else { - ILTryCatchBlock dstTryBlock = dstTryBlocks[i]; - // Check that the goto points to the start - ILTryCatchBlock current = dstTryBlock; - while(current != null) { - foreach(ILNode n in current.TryBlock.Body) { - if (n is ILLabel) { - if (n == target) - return dstTryBlock; - } else if (!n.Match(ILCode.Nop)) { - current = n as ILTryCatchBlock; - break; - } - } - } - return null; - } - } else if (expr.Code == ILCode.Nop) { - return Exit(expr, visitedNodes); - } else if (expr.Code == ILCode.LoopOrSwitchBreak) { - ILNode breakBlock = GetParents(expr).First(n => n is ILWhileLoop || n is ILSwitch); - return Exit(breakBlock, new HashSet() { expr }); - } else if (expr.Code == ILCode.LoopContinue) { - ILNode continueBlock = GetParents(expr).First(n => n is ILWhileLoop); - return Enter(continueBlock, new HashSet() { expr }); - } else { - return expr; - } - } - - ILBlock block = node as ILBlock; - if (block != null) { - if (block.EntryGoto != null) { - return Enter(block.EntryGoto, visitedNodes); - } else if (block.Body.Count > 0) { - return Enter(block.Body[0], visitedNodes); - } else { - return Exit(block, visitedNodes); - } - } - - ILCondition cond = node as ILCondition; - if (cond != null) { - return cond.Condition; - } - - ILWhileLoop loop = node as ILWhileLoop; - if (loop != null) { - if (loop.Condition != null) { - return loop.Condition; - } else { - return Enter(loop.BodyBlock, visitedNodes); - } - } - - ILTryCatchBlock tryCatch = node as ILTryCatchBlock; - if (tryCatch != null) { - return tryCatch; - } - - ILSwitch ilSwitch = node as ILSwitch; - if (ilSwitch != null) { - return ilSwitch.Condition; - } - - throw new NotSupportedException(node.GetType().ToString()); - } - - /// - /// Get the first expression to be excecuted if the instruction pointer is at the end of the given node - /// - ILNode Exit(ILNode node, HashSet visitedNodes) - { - if (node == null) - throw new ArgumentNullException(); - - ILNode nodeParent = parent[node]; - if (nodeParent == null) - return null; // Exited main body - - if (nodeParent is ILBlock) { - ILNode nextNode = nextSibling[node]; - if (nextNode != null) { - return Enter(nextNode, visitedNodes); - } else { - return Exit(nodeParent, visitedNodes); - } - } - - if (nodeParent is ILCondition) { - return Exit(nodeParent, visitedNodes); - } - - if (nodeParent is ILTryCatchBlock) { - // Finally blocks are completely ignored. - // We rely on the fact that try blocks can not be entered. - return Exit(nodeParent, visitedNodes); - } - - if (nodeParent is ILSwitch) { - return null; // Implicit exit from switch is not allowed - } - - if (nodeParent is ILWhileLoop) { - return Enter(nodeParent, visitedNodes); - } - - throw new NotSupportedException(nodeParent.GetType().ToString()); - } - } -} diff --git a/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs b/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs deleted file mode 100644 index 21b2b150..00000000 --- a/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs +++ /dev/null @@ -1,839 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -using Mono.Cecil; -using Mono.Cecil.Cil; -using Cecil = Mono.Cecil; - -namespace ICSharpCode.Decompiler.ILAst -{ - /// - /// Converts stack-based bytecode to variable-based bytecode by calculating use-define chains - /// - public class ILAstBuilder - { - /// Immutable - struct StackSlot - { - public readonly ByteCode[] Definitions; // Reaching definitions of this stack slot - public readonly ILVariable LoadFrom; // Variable used for storage of the value - - public StackSlot(ByteCode[] definitions, ILVariable loadFrom) - { - Definitions = definitions; - LoadFrom = loadFrom; - } - - public static StackSlot[] ModifyStack(StackSlot[] stack, int popCount, int pushCount, ByteCode pushDefinition) - { - StackSlot[] newStack = new StackSlot[stack.Length - popCount + pushCount]; - Array.Copy(stack, newStack, stack.Length - popCount); - for (int i = stack.Length - popCount; i < newStack.Length; i++) { - newStack[i] = new StackSlot(new [] { pushDefinition }, null); - } - return newStack; - } - } - - /// Immutable - struct VariableSlot - { - public readonly ByteCode[] Definitions; // Reaching deinitions of this variable - public readonly bool UnknownDefinition; // Used for initial state and exceptional control flow - - static readonly VariableSlot UnknownInstance = new VariableSlot(new ByteCode[0], true); - - public VariableSlot(ByteCode[] definitions, bool unknownDefinition) - { - Definitions = definitions; - UnknownDefinition = unknownDefinition; - } - - public static VariableSlot[] CloneVariableState(VariableSlot[] state) - { - VariableSlot[] clone = new VariableSlot[state.Length]; - Array.Copy(state, clone, state.Length); - return clone; - } - - public static VariableSlot[] MakeUknownState(int varCount) - { - VariableSlot[] unknownVariableState = new VariableSlot[varCount]; - for (int i = 0; i < unknownVariableState.Length; i++) { - unknownVariableState[i] = UnknownInstance; - } - return unknownVariableState; - } - } - - sealed class ByteCode - { - public ILLabel Label; // Non-null only if needed - public int Offset; - public int EndOffset; - public ILCode Code; - public object Operand; - public int? PopCount; // Null means pop all - public int PushCount; - public string Name { get { return "IL_" + Offset.ToString("X2"); } } - public ByteCode Next; - public Instruction[] Prefixes; // Non-null only if needed - public StackSlot[] StackBefore; // Unique per bytecode; not shared - public VariableSlot[] VariablesBefore; // Unique per bytecode; not shared - public List StoreTo; // Store result of instruction to those AST variables - - public bool IsVariableDefinition { - get { - return (Code == ILCode.Stloc) || (Code == ILCode.Ldloca && Next != null && Next.Code == ILCode.Initobj); - } - } - - public override string ToString() - { - StringBuilder sb = new StringBuilder(); - - // Label - sb.Append(Name); - sb.Append(':'); - if (Label != null) - sb.Append('*'); - - // Name - sb.Append(' '); - if (Prefixes != null) { - foreach (var prefix in Prefixes) { - sb.Append(prefix.OpCode.Name); - sb.Append(' '); - } - } - sb.Append(Code.GetName()); - - if (Operand != null) { - sb.Append(' '); - if (Operand is Instruction) { - sb.Append("IL_" + ((Instruction)Operand).Offset.ToString("X2")); - } else if (Operand is Instruction[]) { - foreach(Instruction inst in (Instruction[])Operand) { - sb.Append("IL_" + inst.Offset.ToString("X2")); - sb.Append(" "); - } - } else if (Operand is ILLabel) { - sb.Append(((ILLabel)Operand).Name); - } else if (Operand is ILLabel[]) { - foreach(ILLabel label in (ILLabel[])Operand) { - sb.Append(label.Name); - sb.Append(" "); - } - } else { - sb.Append(Operand.ToString()); - } - } - - if (StackBefore != null) { - sb.Append(" StackBefore={"); - bool first = true; - foreach (StackSlot slot in StackBefore) { - if (!first) sb.Append(","); - bool first2 = true; - foreach(ByteCode defs in slot.Definitions) { - if (!first2) sb.Append("|"); - sb.AppendFormat("IL_{0:X2}", defs.Offset); - first2 = false; - } - first = false; - } - sb.Append("}"); - } - - if (StoreTo != null && StoreTo.Count > 0) { - sb.Append(" StoreTo={"); - bool first = true; - foreach (ILVariable stackVar in StoreTo) { - if (!first) sb.Append(","); - sb.Append(stackVar.Name); - first = false; - } - sb.Append("}"); - } - - if (VariablesBefore != null) { - sb.Append(" VarsBefore={"); - bool first = true; - foreach (VariableSlot varSlot in VariablesBefore) { - if (!first) sb.Append(","); - if (varSlot.UnknownDefinition) { - sb.Append("?"); - } else { - bool first2 = true; - foreach (ByteCode storedBy in varSlot.Definitions) { - if (!first2) sb.Append("|"); - sb.AppendFormat("IL_{0:X2}", storedBy.Offset); - first2 = false; - } - } - first = false; - } - sb.Append("}"); - } - - return sb.ToString(); - } - } - - MethodDefinition methodDef; - bool optimize; - - // Virtual instructions to load exception on stack - Dictionary ldexceptions = new Dictionary(); - - DecompilerContext context; - - public List Build(MethodDefinition methodDef, bool optimize, DecompilerContext context) - { - this.methodDef = methodDef; - this.optimize = optimize; - this.context = context; - - if (methodDef.Body.Instructions.Count == 0) return new List(); - - List body = StackAnalysis(methodDef); - - List ast = ConvertToAst(body, new HashSet(methodDef.Body.ExceptionHandlers)); - - return ast; - } - - static int offsetIdx; - List StackAnalysis(MethodDefinition methodDef) - { - Dictionary instrToByteCode = new Dictionary(); - - // Create temporary structure for the stack analysis - List body = new List(methodDef.Body.Instructions.Count); - List prefixes = null; - foreach(Instruction inst in methodDef.Body.Instructions) { - if (inst.OpCode.OpCodeType == OpCodeType.Prefix) { - if (prefixes == null) - prefixes = new List(1); - prefixes.Add(inst); - continue; - } - ILCode code = (ILCode)inst.OpCode.Code; - object operand = inst.Operand; - ILCodeUtil.ExpandMacro(ref code, ref operand, methodDef.Body); - ByteCode byteCode = new ByteCode() { - Offset = inst.Offset, - EndOffset = inst.Next != null ? inst.Next.Offset : methodDef.Body.CodeSize, - Code = code, - Operand = operand, - PopCount = inst.GetPopDelta(methodDef), - PushCount = inst.GetPushDelta() - }; - if (prefixes != null) { - instrToByteCode[prefixes[0]] = byteCode; - byteCode.Offset = prefixes[0].Offset; - byteCode.Prefixes = prefixes.ToArray(); - prefixes = null; - } else { - instrToByteCode[inst] = byteCode; - } - body.Add(byteCode); - } - for (int i = 0; i < body.Count - 1; i++) { - body[i].Next = body[i + 1]; - } - - Stack agenda = new Stack(); - - int varCount = methodDef.Body.Variables.Count; - - var exceptionHandlerStarts = new HashSet(methodDef.Body.ExceptionHandlers.Select(eh => instrToByteCode[eh.HandlerStart])); - - // Add known states - if(methodDef.Body.HasExceptionHandlers) { - foreach(ExceptionHandler ex in methodDef.Body.ExceptionHandlers) { - ByteCode handlerStart = instrToByteCode[ex.HandlerStart]; - handlerStart.StackBefore = new StackSlot[0]; - handlerStart.VariablesBefore = VariableSlot.MakeUknownState(varCount); - if (ex.HandlerType == ExceptionHandlerType.Catch || ex.HandlerType == ExceptionHandlerType.Filter) { - // Catch and Filter handlers start with the exeption on the stack - ByteCode ldexception = new ByteCode() { - Code = ILCode.Ldexception, - Operand = ex.CatchType, - PopCount = 0, - PushCount = 1 - }; - ldexceptions[ex] = ldexception; - handlerStart.StackBefore = new StackSlot[] { new StackSlot(new [] { ldexception }, null) }; - } - agenda.Push(handlerStart); - - if (ex.HandlerType == ExceptionHandlerType.Filter) - { - ByteCode filterStart = instrToByteCode[ex.FilterStart]; - ByteCode ldexception = new ByteCode() { - Code = ILCode.Ldexception, - Operand = ex.CatchType, - PopCount = 0, - PushCount = 1 - }; - // TODO: ldexceptions[ex] = ldexception; - filterStart.StackBefore = new StackSlot[] { new StackSlot(new [] { ldexception }, null) }; - filterStart.VariablesBefore = VariableSlot.MakeUknownState(varCount); - agenda.Push(filterStart); - } - } - } - - body[0].StackBefore = new StackSlot[0]; - body[0].VariablesBefore = VariableSlot.MakeUknownState(varCount); - agenda.Push(body[0]); - - // Process agenda - while(agenda.Count > 0) { - ByteCode byteCode = agenda.Pop(); - - // Calculate new stack - StackSlot[] newStack = StackSlot.ModifyStack(byteCode.StackBefore, byteCode.PopCount ?? byteCode.StackBefore.Length, byteCode.PushCount, byteCode); - - // Calculate new variable state - VariableSlot[] newVariableState = VariableSlot.CloneVariableState(byteCode.VariablesBefore); - if (byteCode.IsVariableDefinition) { - newVariableState[((VariableReference)byteCode.Operand).Index] = new VariableSlot(new [] { byteCode }, false); - } - - // After the leave, finally block might have touched the variables - if (byteCode.Code == ILCode.Leave) { - newVariableState = VariableSlot.MakeUknownState(varCount); - } - - // Find all successors - List branchTargets = new List(); - if (!byteCode.Code.IsUnconditionalControlFlow()) { - if (exceptionHandlerStarts.Contains(byteCode.Next)) { - // Do not fall though down to exception handler - // It is invalid IL as per ECMA-335 §12.4.2.8.1, but some obfuscators produce it - } else { - branchTargets.Add(byteCode.Next); - } - } - if (byteCode.Operand is Instruction[]) { - foreach(Instruction inst in (Instruction[])byteCode.Operand) { - ByteCode target = instrToByteCode[inst]; - branchTargets.Add(target); - // The target of a branch must have label - if (target.Label == null) { - target.Label = new ILLabel() { Name = target.Name }; - } - } - } else if (byteCode.Operand is Instruction) { - ByteCode target = instrToByteCode[(Instruction)byteCode.Operand]; - branchTargets.Add(target); - // The target of a branch must have label - if (target.Label == null) { - target.Label = new ILLabel() { Name = target.Name }; - } - } - - // Apply the state to successors - foreach (ByteCode branchTarget in branchTargets) { - if (branchTarget.StackBefore == null && branchTarget.VariablesBefore == null) { - if (branchTargets.Count == 1) { - branchTarget.StackBefore = newStack; - branchTarget.VariablesBefore = newVariableState; - } else { - // Do not share data for several bytecodes - branchTarget.StackBefore = StackSlot.ModifyStack(newStack, 0, 0, null); - branchTarget.VariablesBefore = VariableSlot.CloneVariableState(newVariableState); - } - agenda.Push(branchTarget); - } else { - if (branchTarget.StackBefore.Length != newStack.Length) { - throw new Exception("Inconsistent stack size at " + byteCode.Name); - } - - // Be careful not to change our new data - it might be reused for several branch targets. - // In general, be careful that two bytecodes never share data structures. - - bool modified = false; - - // Merge stacks - modify the target - for (int i = 0; i < newStack.Length; i++) { - ByteCode[] oldDefs = branchTarget.StackBefore[i].Definitions; - ByteCode[] newDefs = oldDefs.Union(newStack[i].Definitions); - if (newDefs.Length > oldDefs.Length) { - branchTarget.StackBefore[i] = new StackSlot(newDefs, null); - modified = true; - } - } - - // Merge variables - modify the target - for (int i = 0; i < newVariableState.Length; i++) { - VariableSlot oldSlot = branchTarget.VariablesBefore[i]; - VariableSlot newSlot = newVariableState[i]; - if (!oldSlot.UnknownDefinition) { - if (newSlot.UnknownDefinition) { - branchTarget.VariablesBefore[i] = newSlot; - modified = true; - } else { - ByteCode[] oldDefs = oldSlot.Definitions; - ByteCode[] newDefs = oldDefs.Union(newSlot.Definitions); - if (newDefs.Length > oldDefs.Length) { - branchTarget.VariablesBefore[i] = new VariableSlot(newDefs, false); - modified = true; - } - } - } - } - - if (modified) { - agenda.Push(branchTarget); - } - } - } - } - - // Occasionally the compilers or obfuscators generate unreachable code (which might be intentionally invalid) - // I believe it is safe to just remove it - body.RemoveAll(b => b.StackBefore == null); - - // Generate temporary variables to replace stack - foreach(ByteCode byteCode in body) { - int argIdx = 0; - int popCount = byteCode.PopCount ?? byteCode.StackBefore.Length; - for (int i = byteCode.StackBefore.Length - popCount; i < byteCode.StackBefore.Length; i++) { - var offset = byteCode.Offset != 0 ? byteCode.Offset : offsetIdx++; - ILVariable tmpVar = new ILVariable() { Name = string.Format("arg_{0:X2}_{1}", offset, argIdx), IsGenerated = true }; - byteCode.StackBefore[i] = new StackSlot(byteCode.StackBefore[i].Definitions, tmpVar); - foreach(ByteCode pushedBy in byteCode.StackBefore[i].Definitions) { - if (pushedBy.StoreTo == null) { - pushedBy.StoreTo = new List(1); - } - pushedBy.StoreTo.Add(tmpVar); - } - argIdx++; - } - } - - // Try to use single temporary variable insted of several if possilbe (especially useful for dup) - // This has to be done after all temporary variables are assigned so we know about all loads - foreach(ByteCode byteCode in body) { - if (byteCode.StoreTo != null && byteCode.StoreTo.Count > 1) { - var locVars = byteCode.StoreTo; - // For each of the variables, find the location where it is loaded - there should be preciesly one - var loadedBy = locVars.Select(locVar => body.SelectMany(bc => bc.StackBefore).Single(s => s.LoadFrom == locVar)).ToList(); - // We now know that all the variables have a single load, - // Let's make sure that they have also a single store - us - if (loadedBy.All(slot => slot.Definitions.Length == 1 && slot.Definitions[0] == byteCode)) { - // Great - we can reduce everything into single variable - var offset = byteCode.Offset != 0 ? byteCode.Offset : offsetIdx++; - ILVariable tmpVar = new ILVariable() { Name = string.Format("expr_{0:X2}", offset), IsGenerated = true }; - byteCode.StoreTo = new List() { tmpVar }; - foreach(ByteCode bc in body) { - for (int i = 0; i < bc.StackBefore.Length; i++) { - // Is it one of the variable to be merged? - if (locVars.Contains(bc.StackBefore[i].LoadFrom)) { - // Replace with the new temp variable - bc.StackBefore[i] = new StackSlot(bc.StackBefore[i].Definitions, tmpVar); - } - } - } - } - } - } - - // Split and convert the normal local variables - ConvertLocalVariables(body); - - // Convert branch targets to labels - foreach(ByteCode byteCode in body) { - if (byteCode.Operand is Instruction[]) { - List newOperand = new List(); - foreach(Instruction target in (Instruction[])byteCode.Operand) { - newOperand.Add(instrToByteCode[target].Label); - } - byteCode.Operand = newOperand.ToArray(); - } else if (byteCode.Operand is Instruction) { - byteCode.Operand = instrToByteCode[(Instruction)byteCode.Operand].Label; - } - } - - // Convert parameters to ILVariables - ConvertParameters(body); - - return body; - } - - static bool IsDeterministicLdloca(ByteCode b) - { - var v = b.Operand; - b = b.Next; - if (b.Code == ILCode.Initobj) return true; - - // instance method calls on value types use the variable ref deterministically - int stack = 1; - while (true) { - if (b.PopCount == null) return false; - stack -= b.PopCount.GetValueOrDefault(); - if (stack == 0) break; - if (stack < 0) return false; - if (b.Code.IsConditionalControlFlow() || b.Code.IsUnconditionalControlFlow()) return false; - switch (b.Code) { - case ILCode.Ldloc: - case ILCode.Ldloca: - case ILCode.Stloc: - if (b.Operand == v) return false; - break; - } - stack += b.PushCount; - b = b.Next; - if (b == null) return false; - } - if (b.Code == ILCode.Ldfld || b.Code == ILCode.Stfld) - return true; - return (b.Code == ILCode.Call || b.Code == ILCode.Callvirt) && ((MethodReference)b.Operand).HasThis; - } - - sealed class VariableInfo - { - public ILVariable Variable; - public List Defs; - public List Uses; - } - - /// - /// If possible, separates local variables into several independent variables. - /// It should undo any compilers merging. - /// - void ConvertLocalVariables(List body) - { - foreach(VariableDefinition varDef in methodDef.Body.Variables) { - - // Find all definitions and uses of this variable - var defs = body.Where(b => b.Operand == varDef && b.IsVariableDefinition).ToList(); - var uses = body.Where(b => b.Operand == varDef && !b.IsVariableDefinition).ToList(); - - List newVars; - - // If the variable is pinned, use single variable. - // If any of the uses is from unknown definition, use single variable - // If any of the uses is ldloca with a nondeterministic usage pattern, use single variable - if (!optimize || varDef.IsPinned || uses.Any(b => b.VariablesBefore[varDef.Index].UnknownDefinition || (b.Code == ILCode.Ldloca && !IsDeterministicLdloca(b)))) { - newVars = new List(1) { new VariableInfo() { - Variable = new ILVariable() { - Name = string.IsNullOrEmpty(varDef.Name) ? "var_" + varDef.Index : varDef.Name, - Type = varDef.IsPinned ? ((PinnedType)varDef.VariableType).ElementType : varDef.VariableType, - OriginalVariable = varDef - }, - Defs = defs, - Uses = uses - }}; - } else { - // Create a new variable for each definition - newVars = defs.Select(def => new VariableInfo() { - Variable = new ILVariable() { - Name = (string.IsNullOrEmpty(varDef.Name) ? "var_" + varDef.Index : varDef.Name) + "_" + def.Offset.ToString("X2"), - Type = varDef.VariableType, - OriginalVariable = varDef - }, - Defs = new List() { def }, - Uses = new List() - }).ToList(); - - // VB.NET uses the 'init' to allow use of uninitialized variables. - // We do not really care about them too much - if the original variable - // was uninitialized at that point it means that no store was called and - // thus all our new variables must be uninitialized as well. - // So it does not matter which one we load. - - // TODO: We should add explicit initialization so that C# code compiles. - // Remember to handle cases where one path inits the variable, but other does not. - - // Add loads to the data structure; merge variables if necessary - foreach(ByteCode use in uses) { - ByteCode[] useDefs = use.VariablesBefore[varDef.Index].Definitions; - if (useDefs.Length == 1) { - VariableInfo newVar = newVars.Single(v => v.Defs.Contains(useDefs[0])); - newVar.Uses.Add(use); - } else { - List mergeVars = newVars.Where(v => v.Defs.Intersect(useDefs).Any()).ToList(); - VariableInfo mergedVar = new VariableInfo() { - Variable = mergeVars[0].Variable, - Defs = mergeVars.SelectMany(v => v.Defs).ToList(), - Uses = mergeVars.SelectMany(v => v.Uses).ToList() - }; - mergedVar.Uses.Add(use); - newVars = newVars.Except(mergeVars).ToList(); - newVars.Add(mergedVar); - } - } - } - - // Set bytecode operands - foreach(VariableInfo newVar in newVars) { - foreach(ByteCode def in newVar.Defs) { - def.Operand = newVar.Variable; - } - foreach(ByteCode use in newVar.Uses) { - use.Operand = newVar.Variable; - } - } - } - } - - public List Parameters = new List(); - - void ConvertParameters(List body) - { - ILVariable thisParameter = null; - if (methodDef.HasThis) { - TypeReference type = methodDef.DeclaringType; - thisParameter = new ILVariable(); - thisParameter.Type = type.IsValueType ? new ByReferenceType(type) : type; - thisParameter.Name = "this"; - thisParameter.OriginalParameter = methodDef.Body.ThisParameter; - } - foreach (ParameterDefinition p in methodDef.Parameters) { - Parameters.Add(new ILVariable { Type = p.ParameterType, Name = p.Name, OriginalParameter = p }); - } - if (Parameters.Count > 0 && (methodDef.IsSetter || methodDef.IsAddOn || methodDef.IsRemoveOn)) { - // last parameter must be 'value', so rename it - Parameters.Last().Name = "value"; - } - foreach (ByteCode byteCode in body) { - ParameterDefinition p; - switch (byteCode.Code) { - case ILCode.__Ldarg: - p = (ParameterDefinition)byteCode.Operand; - byteCode.Code = ILCode.Ldloc; - byteCode.Operand = p.Index < 0 ? thisParameter : Parameters[p.Index]; - break; - case ILCode.__Starg: - p = (ParameterDefinition)byteCode.Operand; - byteCode.Code = ILCode.Stloc; - byteCode.Operand = p.Index < 0 ? thisParameter : Parameters[p.Index]; - break; - case ILCode.__Ldarga: - p = (ParameterDefinition)byteCode.Operand; - byteCode.Code = ILCode.Ldloca; - byteCode.Operand = p.Index < 0 ? thisParameter : Parameters[p.Index]; - break; - } - } - if (thisParameter != null) - Parameters.Add(thisParameter); - } - - List ConvertToAst(List body, HashSet ehs) - { - List ast = new List(); - - while (ehs.Any()) { - ILTryCatchBlock tryCatchBlock = new ILTryCatchBlock(); - - // Find the first and widest scope - int tryStart = ehs.Min(eh => eh.TryStart.Offset); - int tryEnd = ehs.Where(eh => eh.TryStart.Offset == tryStart).Max(eh => eh.TryEnd.Offset); - var handlers = ehs.Where(eh => eh.TryStart.Offset == tryStart && eh.TryEnd.Offset == tryEnd).ToList(); - - // Remember that any part of the body migt have been removed due to unreachability - - // Cut all instructions up to the try block - { - int tryStartIdx = 0; - while (tryStartIdx < body.Count && body[tryStartIdx].Offset < tryStart) tryStartIdx++; - ast.AddRange(ConvertToAst(body.CutRange(0, tryStartIdx))); - } - - // Cut the try block - { - HashSet nestedEHs = new HashSet(ehs.Where(eh => (tryStart <= eh.TryStart.Offset && eh.TryEnd.Offset < tryEnd) || (tryStart < eh.TryStart.Offset && eh.TryEnd.Offset <= tryEnd))); - ehs.ExceptWith(nestedEHs); - int tryEndIdx = 0; - while (tryEndIdx < body.Count && body[tryEndIdx].Offset < tryEnd) tryEndIdx++; - tryCatchBlock.TryBlock = new ILBlock(ConvertToAst(body.CutRange(0, tryEndIdx), nestedEHs)); - } - - // Cut all handlers - tryCatchBlock.CatchBlocks = new List(); - foreach(ExceptionHandler eh in handlers) { - int handlerEndOffset = eh.HandlerEnd == null ? methodDef.Body.CodeSize : eh.HandlerEnd.Offset; - int startIdx = 0; - while (startIdx < body.Count && body[startIdx].Offset < eh.HandlerStart.Offset) startIdx++; - int endIdx = 0; - while (endIdx < body.Count && body[endIdx].Offset < handlerEndOffset) endIdx++; - HashSet nestedEHs = new HashSet(ehs.Where(e => (eh.HandlerStart.Offset <= e.TryStart.Offset && e.TryEnd.Offset < handlerEndOffset) || (eh.HandlerStart.Offset < e.TryStart.Offset && e.TryEnd.Offset <= handlerEndOffset))); - ehs.ExceptWith(nestedEHs); - List handlerAst = ConvertToAst(body.CutRange(startIdx, endIdx - startIdx), nestedEHs); - if (eh.HandlerType == ExceptionHandlerType.Catch) { - ILTryCatchBlock.CatchBlock catchBlock = new ILTryCatchBlock.CatchBlock() { - ExceptionType = eh.CatchType, - Body = handlerAst - }; - // Handle the automatically pushed exception on the stack - ByteCode ldexception = ldexceptions[eh]; - if (ldexception.StoreTo == null || ldexception.StoreTo.Count == 0) { - // Exception is not used - catchBlock.ExceptionVariable = null; - } else if (ldexception.StoreTo.Count == 1) { - ILExpression first = catchBlock.Body[0] as ILExpression; - if (first != null && - first.Code == ILCode.Pop && - first.Arguments[0].Code == ILCode.Ldloc && - first.Arguments[0].Operand == ldexception.StoreTo[0]) - { - // The exception is just poped - optimize it all away; - if (context.Settings.AlwaysGenerateExceptionVariableForCatchBlocks) - catchBlock.ExceptionVariable = new ILVariable() { Name = "ex_" + eh.HandlerStart.Offset.ToString("X2"), IsGenerated = true }; - else - catchBlock.ExceptionVariable = null; - catchBlock.Body.RemoveAt(0); - } else { - catchBlock.ExceptionVariable = ldexception.StoreTo[0]; - } - } else { - ILVariable exTemp = new ILVariable() { Name = "ex_" + eh.HandlerStart.Offset.ToString("X2"), IsGenerated = true }; - catchBlock.ExceptionVariable = exTemp; - foreach(ILVariable storeTo in ldexception.StoreTo) { - catchBlock.Body.Insert(0, new ILExpression(ILCode.Stloc, storeTo, new ILExpression(ILCode.Ldloc, exTemp))); - } - } - tryCatchBlock.CatchBlocks.Add(catchBlock); - } else if (eh.HandlerType == ExceptionHandlerType.Finally) { - tryCatchBlock.FinallyBlock = new ILBlock(handlerAst); - } else if (eh.HandlerType == ExceptionHandlerType.Fault) { - tryCatchBlock.FaultBlock = new ILBlock(handlerAst); - } else { - // TODO: ExceptionHandlerType.Filter - } - } - - ehs.ExceptWith(handlers); - - ast.Add(tryCatchBlock); - } - - // Add whatever is left - ast.AddRange(ConvertToAst(body)); - - return ast; - } - - List ConvertToAst(List body) - { - List ast = new List(); - - // Convert stack-based IL code to ILAst tree - foreach(ByteCode byteCode in body) { - ILRange ilRange = new ILRange(byteCode.Offset, byteCode.EndOffset); - - if (byteCode.StackBefore == null) { - // Unreachable code - continue; - } - - ILExpression expr = new ILExpression(byteCode.Code, byteCode.Operand); - expr.ILRanges.Add(ilRange); - if (byteCode.Prefixes != null && byteCode.Prefixes.Length > 0) { - ILExpressionPrefix[] prefixes = new ILExpressionPrefix[byteCode.Prefixes.Length]; - for (int i = 0; i < prefixes.Length; i++) { - prefixes[i] = new ILExpressionPrefix((ILCode)byteCode.Prefixes[i].OpCode.Code, byteCode.Prefixes[i].Operand); - } - expr.Prefixes = prefixes; - } - - // Label for this instruction - if (byteCode.Label != null) { - ast.Add(byteCode.Label); - } - - // Reference arguments using temporary variables - int popCount = byteCode.PopCount ?? byteCode.StackBefore.Length; - for (int i = byteCode.StackBefore.Length - popCount; i < byteCode.StackBefore.Length; i++) { - StackSlot slot = byteCode.StackBefore[i]; - expr.Arguments.Add(new ILExpression(ILCode.Ldloc, slot.LoadFrom)); - } - - // Store the result to temporary variable(s) if needed - if (byteCode.StoreTo == null || byteCode.StoreTo.Count == 0) { - ast.Add(expr); - } else if (byteCode.StoreTo.Count == 1) { - ast.Add(new ILExpression(ILCode.Stloc, byteCode.StoreTo[0], expr)); - } else { - var offset = byteCode.Offset != 0 ? byteCode.Offset : offsetIdx++; - ILVariable tmpVar = new ILVariable() { Name = "expr_" + offset.ToString("X2"), IsGenerated = true }; - ast.Add(new ILExpression(ILCode.Stloc, tmpVar, expr)); - foreach(ILVariable storeTo in byteCode.StoreTo.AsEnumerable().Reverse()) { - ast.Add(new ILExpression(ILCode.Stloc, storeTo, new ILExpression(ILCode.Ldloc, tmpVar))); - } - } - } - - return ast; - } - } - - public static class ILAstBuilderExtensionMethods - { - public static List CutRange(this List list, int start, int count) - { - List ret = new List(count); - for (int i = 0; i < count; i++) { - ret.Add(list[start + i]); - } - list.RemoveRange(start, count); - return ret; - } - - public static T[] Union(this T[] a, T b) - { - if (a.Length == 0) - return new[] { b }; - if (Array.IndexOf(a, b) >= 0) - return a; - var res = new T[a.Length + 1]; - Array.Copy(a, 0, res, 0, a.Length); - res[res.Length - 1] = b; - return res; - } - - public static T[] Union(this T[] a, T[] b) - { - if (a == b) - return a; - if (a.Length == 0) - return b; - if (b.Length == 0) - return a; - if (a.Length == 1) { - if (b.Length == 1) - return a[0].Equals(b[0]) ? a : new[] { a[0], b[0] }; - return b.Union(a[0]); - } - if (b.Length == 1) - return a.Union(b[0]); - return Enumerable.Union(a, b).ToArray(); - } - } -} diff --git a/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs b/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs deleted file mode 100644 index 876718bc..00000000 --- a/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs +++ /dev/null @@ -1,988 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using ICSharpCode.Decompiler.FlowAnalysis; -using ICSharpCode.NRefactory.Utils; -using Mono.Cecil; -using Mono.Cecil.Cil; -using Mono.CSharp; - -namespace ICSharpCode.Decompiler.ILAst -{ - public enum ILAstOptimizationStep - { - RemoveRedundantCode, - ReduceBranchInstructionSet, - InlineVariables, - CopyPropagation, - YieldReturn, - AsyncAwait, - PropertyAccessInstructions, - SplitToMovableBlocks, - TypeInference, - HandlePointerArithmetic, - SimplifyShortCircuit, - SimplifyTernaryOperator, - SimplifyNullCoalescing, - JoinBasicBlocks, - SimplifyLogicNot, - SimplifyShiftOperators, - TypeConversionSimplifications, - SimplifyLdObjAndStObj, - SimplifyCustomShortCircuit, - SimplifyLiftedOperators, - TransformArrayInitializers, - TransformMultidimensionalArrayInitializers, - TransformObjectInitializers, - MakeAssignmentExpression, - IntroducePostIncrement, - InlineExpressionTreeParameterDeclarations, - InlineVariables2, - FindLoops, - FindConditions, - FlattenNestedMovableBlocks, - RemoveEndFinally, - RemoveRedundantCode2, - GotoRemoval, - DuplicateReturns, - GotoRemoval2, - ReduceIfNesting, - InlineVariables3, - CachedDelegateInitialization, - IntroduceFixedStatements, - RecombineVariables, - TypeInference2, - RemoveRedundantCode3, - None - } - - public partial class ILAstOptimizer - { - int nextLabelIndex = 0; - - DecompilerContext context; - TypeSystem typeSystem; - ILBlock method; - - public void Optimize(DecompilerContext context, ILBlock method, ILAstOptimizationStep abortBeforeStep = ILAstOptimizationStep.None) - { - this.context = context; - typeSystem = context.CurrentMethod.Module.TypeSystem; - this.method = method; - - if (abortBeforeStep == ILAstOptimizationStep.RemoveRedundantCode) return; - RemoveRedundantCode(method); - - if (abortBeforeStep == ILAstOptimizationStep.ReduceBranchInstructionSet) return; - foreach(ILBlock block in method.GetSelfAndChildrenRecursive()) { - ReduceBranchInstructionSet(block); - } - // ReduceBranchInstructionSet runs before inlining because the non-aggressive inlining heuristic - // looks at which type of instruction consumes the inlined variable. - - if (abortBeforeStep == ILAstOptimizationStep.InlineVariables) return; - // Works better after simple goto removal because of the following debug pattern: stloc X; br Next; Next:; ldloc X - ILInlining inlining1 = new ILInlining(method); - inlining1.InlineAllVariables(); - - if (abortBeforeStep == ILAstOptimizationStep.CopyPropagation) return; - inlining1.CopyPropagation(); - - if (abortBeforeStep == ILAstOptimizationStep.YieldReturn) return; - YieldReturnDecompiler.Run(context, method); - AsyncDecompiler.RunStep1(context, method); - - if (abortBeforeStep == ILAstOptimizationStep.AsyncAwait) return; - AsyncDecompiler.RunStep2(context, method); - - if (abortBeforeStep == ILAstOptimizationStep.PropertyAccessInstructions) return; - IntroducePropertyAccessInstructions(method); - - if (abortBeforeStep == ILAstOptimizationStep.SplitToMovableBlocks) return; - foreach(ILBlock block in method.GetSelfAndChildrenRecursive()) { - SplitToBasicBlocks(block); - } - - if (abortBeforeStep == ILAstOptimizationStep.TypeInference) return; - // Types are needed for the ternary operator optimization - TypeAnalysis.Run(context, method); - - if (abortBeforeStep == ILAstOptimizationStep.HandlePointerArithmetic) return; - HandlePointerArithmetic(method); - - foreach(ILBlock block in method.GetSelfAndChildrenRecursive()) { - bool modified; - do { - modified = false; - - if (abortBeforeStep == ILAstOptimizationStep.SimplifyShortCircuit) return; - modified |= block.RunOptimization(new SimpleControlFlow(context, method).SimplifyShortCircuit); - - if (abortBeforeStep == ILAstOptimizationStep.SimplifyTernaryOperator) return; - modified |= block.RunOptimization(new SimpleControlFlow(context, method).SimplifyTernaryOperator); - - if (abortBeforeStep == ILAstOptimizationStep.SimplifyNullCoalescing) return; - modified |= block.RunOptimization(new SimpleControlFlow(context, method).SimplifyNullCoalescing); - - if (abortBeforeStep == ILAstOptimizationStep.JoinBasicBlocks) return; - modified |= block.RunOptimization(new SimpleControlFlow(context, method).JoinBasicBlocks); - - if (abortBeforeStep == ILAstOptimizationStep.SimplifyLogicNot) return; - modified |= block.RunOptimization(SimplifyLogicNot); - - if (abortBeforeStep == ILAstOptimizationStep.SimplifyShiftOperators) return; - modified |= block.RunOptimization(SimplifyShiftOperators); - - if (abortBeforeStep == ILAstOptimizationStep.TypeConversionSimplifications) return; - modified |= block.RunOptimization(TypeConversionSimplifications); - - if (abortBeforeStep == ILAstOptimizationStep.SimplifyLdObjAndStObj) return; - modified |= block.RunOptimization(SimplifyLdObjAndStObj); - - if (abortBeforeStep == ILAstOptimizationStep.SimplifyCustomShortCircuit) return; - modified |= block.RunOptimization(new SimpleControlFlow(context, method).SimplifyCustomShortCircuit); - - if (abortBeforeStep == ILAstOptimizationStep.SimplifyLiftedOperators) return; - modified |= block.RunOptimization(SimplifyLiftedOperators); - - if (abortBeforeStep == ILAstOptimizationStep.TransformArrayInitializers) return; - modified |= block.RunOptimization(TransformArrayInitializers); - - if (abortBeforeStep == ILAstOptimizationStep.TransformMultidimensionalArrayInitializers) return; - modified |= block.RunOptimization(TransformMultidimensionalArrayInitializers); - - if (abortBeforeStep == ILAstOptimizationStep.TransformObjectInitializers) return; - modified |= block.RunOptimization(TransformObjectInitializers); - - if (abortBeforeStep == ILAstOptimizationStep.MakeAssignmentExpression) return; - if (context.Settings.MakeAssignmentExpressions) { - modified |= block.RunOptimization(MakeAssignmentExpression); - } - modified |= block.RunOptimization(MakeCompoundAssignments); - - if (abortBeforeStep == ILAstOptimizationStep.IntroducePostIncrement) return; - if (context.Settings.IntroduceIncrementAndDecrement) { - modified |= block.RunOptimization(IntroducePostIncrement); - } - - if (abortBeforeStep == ILAstOptimizationStep.InlineExpressionTreeParameterDeclarations) return; - if (context.Settings.ExpressionTrees) { - modified |= block.RunOptimization(InlineExpressionTreeParameterDeclarations); - } - - if (abortBeforeStep == ILAstOptimizationStep.InlineVariables2) return; - modified |= new ILInlining(method).InlineAllInBlock(block); - new ILInlining(method).CopyPropagation(); - - } while(modified); - } - - if (abortBeforeStep == ILAstOptimizationStep.FindLoops) return; - foreach(ILBlock block in method.GetSelfAndChildrenRecursive()) { - new LoopsAndConditions(context).FindLoops(block); - } - - if (abortBeforeStep == ILAstOptimizationStep.FindConditions) return; - foreach(ILBlock block in method.GetSelfAndChildrenRecursive()) { - new LoopsAndConditions(context).FindConditions(block); - } - - if (abortBeforeStep == ILAstOptimizationStep.FlattenNestedMovableBlocks) return; - FlattenBasicBlocks(method); - - if (abortBeforeStep == ILAstOptimizationStep.RemoveEndFinally) return; - RemoveEndFinally(method); - - if (abortBeforeStep == ILAstOptimizationStep.RemoveRedundantCode2) return; - RemoveRedundantCode(method); - - if (abortBeforeStep == ILAstOptimizationStep.GotoRemoval) return; - new GotoRemoval().RemoveGotos(method); - - if (abortBeforeStep == ILAstOptimizationStep.DuplicateReturns) return; - DuplicateReturnStatements(method); - - if (abortBeforeStep == ILAstOptimizationStep.GotoRemoval2) return; - new GotoRemoval().RemoveGotos(method); - - if (abortBeforeStep == ILAstOptimizationStep.ReduceIfNesting) return; - ReduceIfNesting(method); - - if (abortBeforeStep == ILAstOptimizationStep.InlineVariables3) return; - // The 2nd inlining pass is necessary because DuplicateReturns and the introduction of ternary operators - // open up additional inlining possibilities. - new ILInlining(method).InlineAllVariables(); - - if (abortBeforeStep == ILAstOptimizationStep.CachedDelegateInitialization) return; - if (context.Settings.AnonymousMethods) { - foreach(ILBlock block in method.GetSelfAndChildrenRecursive()) { - for (int i = 0; i < block.Body.Count; i++) { - // TODO: Move before loops - CachedDelegateInitializationWithField(block, ref i); - CachedDelegateInitializationWithLocal(block, ref i); - } - } - } - - if (abortBeforeStep == ILAstOptimizationStep.IntroduceFixedStatements) return; - // we need post-order traversal, not pre-order, for "fixed" to work correctly - foreach (ILBlock block in TreeTraversal.PostOrder(method, n => n.GetChildren()).OfType()) { - for (int i = block.Body.Count - 1; i >= 0; i--) { - // TODO: Move before loops - if (i < block.Body.Count) - IntroduceFixedStatements(block.Body, i); - } - } - - if (abortBeforeStep == ILAstOptimizationStep.RecombineVariables) return; - RecombineVariables(method); - - if (abortBeforeStep == ILAstOptimizationStep.TypeInference2) return; - TypeAnalysis.Reset(method); - TypeAnalysis.Run(context, method); - - if (abortBeforeStep == ILAstOptimizationStep.RemoveRedundantCode3) return; - GotoRemoval.RemoveRedundantCode(method); - - // ReportUnassignedILRanges(method); - } - - /// - /// Removes redundatant Br, Nop, Dup, Pop - /// Ignore arguments of 'leave' - /// - /// - internal static void RemoveRedundantCode(ILBlock method) - { - Dictionary labelRefCount = new Dictionary(); - foreach (ILLabel target in method.GetSelfAndChildrenRecursive(e => e.IsBranch()).SelectMany(e => e.GetBranchTargets())) { - labelRefCount[target] = labelRefCount.GetOrDefault(target) + 1; - } - - foreach(ILBlock block in method.GetSelfAndChildrenRecursive()) { - List body = block.Body; - List newBody = new List(body.Count); - for (int i = 0; i < body.Count; i++) { - ILLabel target; - ILExpression popExpr; - if (body[i].Match(ILCode.Br, out target) && i+1 < body.Count && body[i+1] == target) { - // Ignore the branch - if (labelRefCount[target] == 1) - i++; // Ignore the label as well - } else if (body[i].Match(ILCode.Nop)){ - // Ignore nop - } else if (body[i].Match(ILCode.Pop, out popExpr)) { - ILVariable v; - if (!popExpr.Match(ILCode.Ldloc, out v)) - throw new Exception("Pop should have just ldloc at this stage"); - // Best effort to move the ILRange to previous statement - ILVariable prevVar; - ILExpression prevExpr; - if (i - 1 >= 0 && body[i - 1].Match(ILCode.Stloc, out prevVar, out prevExpr) && prevVar == v) - prevExpr.ILRanges.AddRange(((ILExpression)body[i]).ILRanges); - // Ignore pop - } else { - ILLabel label = body[i] as ILLabel; - if (label != null) { - if (labelRefCount.GetOrDefault(label) > 0) - newBody.Add(label); - } else { - newBody.Add(body[i]); - } - } - } - block.Body = newBody; - } - - // Ignore arguments of 'leave' - foreach (ILExpression expr in method.GetSelfAndChildrenRecursive(e => e.Code == ILCode.Leave)) { - if (expr.Arguments.Any(arg => !arg.Match(ILCode.Ldloc))) - throw new Exception("Leave should have just ldloc at this stage"); - expr.Arguments.Clear(); - } - - // 'dup' removal - foreach (ILExpression expr in method.GetSelfAndChildrenRecursive()) { - for (int i = 0; i < expr.Arguments.Count; i++) { - ILExpression child; - if (expr.Arguments[i].Match(ILCode.Dup, out child)) { - child.ILRanges.AddRange(expr.Arguments[i].ILRanges); - expr.Arguments[i] = child; - } - } - } - } - - /// - /// Reduces the branch codes to just br and brtrue. - /// Moves ILRanges to the branch argument - /// - void ReduceBranchInstructionSet(ILBlock block) - { - for (int i = 0; i < block.Body.Count; i++) { - ILExpression expr = block.Body[i] as ILExpression; - if (expr != null && expr.Prefixes == null) { - ILCode op; - switch(expr.Code) { - case ILCode.Switch: - case ILCode.Brtrue: - expr.Arguments.Single().ILRanges.AddRange(expr.ILRanges); - expr.ILRanges.Clear(); - continue; - case ILCode.__Brfalse: op = ILCode.LogicNot; break; - case ILCode.__Beq: op = ILCode.Ceq; break; - case ILCode.__Bne_Un: op = ILCode.Cne; break; - case ILCode.__Bgt: op = ILCode.Cgt; break; - case ILCode.__Bgt_Un: op = ILCode.Cgt_Un; break; - case ILCode.__Ble: op = ILCode.Cle; break; - case ILCode.__Ble_Un: op = ILCode.Cle_Un; break; - case ILCode.__Blt: op = ILCode.Clt; break; - case ILCode.__Blt_Un: op = ILCode.Clt_Un; break; - case ILCode.__Bge: op = ILCode.Cge; break; - case ILCode.__Bge_Un: op = ILCode.Cge_Un; break; - default: - continue; - } - var newExpr = new ILExpression(op, null, expr.Arguments); - block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, newExpr); - newExpr.ILRanges = expr.ILRanges; - } - } - } - - /// - /// Converts call and callvirt instructions that read/write properties into CallGetter/CallSetter instructions. - /// - /// CallGetter/CallSetter is used to allow the ILAst to represent "while ((SomeProperty = value) != null)". - /// - /// Also simplifies 'newobj(SomeDelegate, target, ldvirtftn(F, target))' to 'newobj(SomeDelegate, target, ldvirtftn(F))' - /// - void IntroducePropertyAccessInstructions(ILNode node) - { - ILExpression parentExpr = node as ILExpression; - if (parentExpr != null) { - for (int i = 0; i < parentExpr.Arguments.Count; i++) { - ILExpression expr = parentExpr.Arguments[i]; - IntroducePropertyAccessInstructions(expr); - IntroducePropertyAccessInstructions(expr, parentExpr, i); - } - } else { - foreach (ILNode child in node.GetChildren()) { - IntroducePropertyAccessInstructions(child); - ILExpression expr = child as ILExpression; - if (expr != null) { - IntroducePropertyAccessInstructions(expr, null, -1); - } - } - } - } - - void IntroducePropertyAccessInstructions(ILExpression expr, ILExpression parentExpr, int posInParent) - { - if (expr.Code == ILCode.Call || expr.Code == ILCode.Callvirt) { - MethodReference cecilMethod = (MethodReference)expr.Operand; - if (cecilMethod.DeclaringType is ArrayType) { - switch (cecilMethod.Name) { - case "Get": - expr.Code = ILCode.CallGetter; - break; - case "Set": - expr.Code = ILCode.CallSetter; - break; - case "Address": - ByReferenceType brt = cecilMethod.ReturnType as ByReferenceType; - if (brt != null) { - MethodReference getMethod = new MethodReference("Get", brt.ElementType, cecilMethod.DeclaringType); - foreach (var p in cecilMethod.Parameters) - getMethod.Parameters.Add(p); - getMethod.HasThis = cecilMethod.HasThis; - expr.Operand = getMethod; - } - expr.Code = ILCode.CallGetter; - if (parentExpr != null) { - parentExpr.Arguments[posInParent] = new ILExpression(ILCode.AddressOf, null, expr); - } - break; - } - } else { - MethodDefinition cecilMethodDef = cecilMethod.Resolve(); - if (cecilMethodDef != null) { - if (cecilMethodDef.IsGetter) - expr.Code = (expr.Code == ILCode.Call) ? ILCode.CallGetter : ILCode.CallvirtGetter; - else if (cecilMethodDef.IsSetter) - expr.Code = (expr.Code == ILCode.Call) ? ILCode.CallSetter : ILCode.CallvirtSetter; - } - } - } else if (expr.Code == ILCode.Newobj && expr.Arguments.Count == 2) { - // Might be 'newobj(SomeDelegate, target, ldvirtftn(F, target))'. - ILVariable target; - if (expr.Arguments[0].Match(ILCode.Ldloc, out target) - && expr.Arguments[1].Code == ILCode.Ldvirtftn - && expr.Arguments[1].Arguments.Count == 1 - && expr.Arguments[1].Arguments[0].MatchLdloc(target)) - { - // Remove the 'target' argument from the ldvirtftn instruction. - // It's not needed in the translation to C#, and needs to be eliminated so that the target expression - // can be inlined. - expr.Arguments[1].Arguments.Clear(); - } - } - } - - /// - /// Group input into a set of blocks that can be later arbitraliby schufled. - /// The method adds necessary branches to make control flow between blocks - /// explicit and thus order independent. - /// - void SplitToBasicBlocks(ILBlock block) - { - List basicBlocks = new List(); - - ILLabel entryLabel = block.Body.FirstOrDefault() as ILLabel ?? new ILLabel() { Name = "Block_" + (nextLabelIndex++) }; - ILBasicBlock basicBlock = new ILBasicBlock(); - basicBlocks.Add(basicBlock); - basicBlock.Body.Add(entryLabel); - block.EntryGoto = new ILExpression(ILCode.Br, entryLabel); - - if (block.Body.Count > 0) { - if (block.Body[0] != entryLabel) - basicBlock.Body.Add(block.Body[0]); - - for (int i = 1; i < block.Body.Count; i++) { - ILNode lastNode = block.Body[i - 1]; - ILNode currNode = block.Body[i]; - - // Start a new basic block if necessary - if (currNode is ILLabel || - currNode is ILTryCatchBlock || // Counts as label - lastNode.IsConditionalControlFlow() || - lastNode.IsUnconditionalControlFlow()) - { - // Try to reuse the label - ILLabel label = currNode as ILLabel ?? new ILLabel() { Name = "Block_" + (nextLabelIndex++).ToString() }; - - // Terminate the last block - if (!lastNode.IsUnconditionalControlFlow()) { - // Explicit branch from one block to other - basicBlock.Body.Add(new ILExpression(ILCode.Br, label)); - } - - // Start the new block - basicBlock = new ILBasicBlock(); - basicBlocks.Add(basicBlock); - basicBlock.Body.Add(label); - - // Add the node to the basic block - if (currNode != label) - basicBlock.Body.Add(currNode); - } else { - basicBlock.Body.Add(currNode); - } - } - } - - block.Body = basicBlocks; - return; - } - - void DuplicateReturnStatements(ILBlock method) - { - Dictionary nextSibling = new Dictionary(); - - // Build navigation data - foreach(ILBlock block in method.GetSelfAndChildrenRecursive()) { - for (int i = 0; i < block.Body.Count - 1; i++) { - ILLabel curr = block.Body[i] as ILLabel; - if (curr != null) { - nextSibling[curr] = block.Body[i + 1]; - } - } - } - - // Duplicate returns - foreach(ILBlock block in method.GetSelfAndChildrenRecursive()) { - for (int i = 0; i < block.Body.Count; i++) { - ILLabel targetLabel; - if (block.Body[i].Match(ILCode.Br, out targetLabel) || block.Body[i].Match(ILCode.Leave, out targetLabel)) { - // Skip extra labels - while(nextSibling.ContainsKey(targetLabel) && nextSibling[targetLabel] is ILLabel) { - targetLabel = (ILLabel)nextSibling[targetLabel]; - } - - // Inline return statement - ILNode target; - List retArgs; - if (nextSibling.TryGetValue(targetLabel, out target)) { - if (target.Match(ILCode.Ret, out retArgs)) { - ILVariable locVar; - object constValue; - if (retArgs.Count == 0) { - block.Body[i] = new ILExpression(ILCode.Ret, null); - } else if (retArgs.Single().Match(ILCode.Ldloc, out locVar)) { - block.Body[i] = new ILExpression(ILCode.Ret, null, new ILExpression(ILCode.Ldloc, locVar)); - } else if (retArgs.Single().Match(ILCode.Ldc_I4, out constValue)) { - block.Body[i] = new ILExpression(ILCode.Ret, null, new ILExpression(ILCode.Ldc_I4, constValue)); - } - } - } else { - if (method.Body.Count > 0 && method.Body.Last() == targetLabel) { - // It exits the main method - so it is same as return; - block.Body[i] = new ILExpression(ILCode.Ret, null); - } - } - } - } - } - } - - /// - /// Flattens all nested basic blocks, except the the top level 'node' argument - /// - void FlattenBasicBlocks(ILNode node) - { - ILBlock block = node as ILBlock; - if (block != null) { - List flatBody = new List(); - foreach (ILNode child in block.GetChildren()) { - FlattenBasicBlocks(child); - ILBasicBlock childAsBB = child as ILBasicBlock; - if (childAsBB != null) { - if (!(childAsBB.Body.FirstOrDefault() is ILLabel)) - throw new Exception("Basic block has to start with a label. \n" + childAsBB.ToString()); - if (childAsBB.Body.LastOrDefault() is ILExpression && !childAsBB.Body.LastOrDefault().IsUnconditionalControlFlow()) - throw new Exception("Basci block has to end with unconditional control flow. \n" + childAsBB.ToString()); - flatBody.AddRange(childAsBB.GetChildren()); - } else { - flatBody.Add(child); - } - } - block.EntryGoto = null; - block.Body = flatBody; - } else if (node is ILExpression) { - // Optimization - no need to check expressions - } else if (node != null) { - // Recursively find all ILBlocks - foreach(ILNode child in node.GetChildren()) { - FlattenBasicBlocks(child); - } - } - } - - /// - /// Replace endfinally with jump to the end of the finally block - /// - void RemoveEndFinally(ILBlock method) - { - // Go thought the list in reverse so that we do the nested blocks first - foreach(var tryCatch in method.GetSelfAndChildrenRecursive(tc => tc.FinallyBlock != null).Reverse()) { - ILLabel label = new ILLabel() { Name = "EndFinally_" + nextLabelIndex++ }; - tryCatch.FinallyBlock.Body.Add(label); - foreach(var block in tryCatch.FinallyBlock.GetSelfAndChildrenRecursive()) { - for (int i = 0; i < block.Body.Count; i++) { - if (block.Body[i].Match(ILCode.Endfinally)) { - block.Body[i] = new ILExpression(ILCode.Br, label).WithILRanges(((ILExpression)block.Body[i]).ILRanges); - } - } - } - } - } - - /// - /// Reduce the nesting of conditions. - /// It should be done on flat data that already had most gotos removed - /// - void ReduceIfNesting(ILNode node) - { - ILBlock block = node as ILBlock; - if (block != null) { - for (int i = 0; i < block.Body.Count; i++) { - ILCondition cond = block.Body[i] as ILCondition; - if (cond != null) { - bool trueExits = cond.TrueBlock.Body.LastOrDefault().IsUnconditionalControlFlow(); - bool falseExits = cond.FalseBlock.Body.LastOrDefault().IsUnconditionalControlFlow(); - - if (trueExits) { - // Move the false block after the condition - block.Body.InsertRange(i + 1, cond.FalseBlock.GetChildren()); - cond.FalseBlock = new ILBlock(); - } else if (falseExits) { - // Move the true block after the condition - block.Body.InsertRange(i + 1, cond.TrueBlock.GetChildren()); - cond.TrueBlock = new ILBlock(); - } - - // Eliminate empty true block - if (!cond.TrueBlock.GetChildren().Any() && cond.FalseBlock.GetChildren().Any()) { - // Swap bodies - ILBlock tmp = cond.TrueBlock; - cond.TrueBlock = cond.FalseBlock; - cond.FalseBlock = tmp; - cond.Condition = new ILExpression(ILCode.LogicNot, null, cond.Condition); - } - } - } - } - - // We are changing the number of blocks so we use plain old recursion to get all blocks - foreach(ILNode child in node.GetChildren()) { - if (child != null && !(child is ILExpression)) - ReduceIfNesting(child); - } - } - - void RecombineVariables(ILBlock method) - { - // Recombine variables that were split when the ILAst was created - // This ensures that a single IL variable is a single C# variable (gets assigned only one name) - // The DeclareVariables transformation might then split up the C# variable again if it is used indendently in two separate scopes. - Dictionary dict = new Dictionary(); - ReplaceVariables( - method, - delegate(ILVariable v) { - if (v.OriginalVariable == null) - return v; - ILVariable combinedVariable; - if (!dict.TryGetValue(v.OriginalVariable, out combinedVariable)) { - dict.Add(v.OriginalVariable, v); - combinedVariable = v; - } - return combinedVariable; - }); - } - - static void HandlePointerArithmetic(ILNode method) - { - foreach (ILExpression expr in method.GetSelfAndChildrenRecursive()) { - List args = expr.Arguments; - switch (expr.Code) { - case ILCode.Localloc: - args[0] = DivideBySize(args[0], ((PointerType)expr.InferredType).ElementType); - break; - case ILCode.Add: - case ILCode.Add_Ovf: - case ILCode.Add_Ovf_Un: - if (expr.InferredType is PointerType) { - if (args[0].ExpectedType is PointerType) - args[1] = DivideBySize(args[1], ((PointerType)expr.InferredType).ElementType); - else if (args[1].ExpectedType is PointerType) - args[0] = DivideBySize(args[0], ((PointerType)expr.InferredType).ElementType); - } - break; - case ILCode.Sub: - case ILCode.Sub_Ovf: - case ILCode.Sub_Ovf_Un: - if (expr.InferredType is PointerType) { - if (args[0].ExpectedType is PointerType) - args[1] = DivideBySize(args[1], ((PointerType)expr.InferredType).ElementType); - } - break; - } - } - } - - static ILExpression UnwrapIntPtrCast(ILExpression expr) - { - if (expr.Code != ILCode.Conv_I && expr.Code != ILCode.Conv_U) - return expr; - - ILExpression arg = expr.Arguments[0]; - switch (arg.InferredType.MetadataType) { - case MetadataType.Byte: - case MetadataType.SByte: - case MetadataType.UInt16: - case MetadataType.Int16: - case MetadataType.UInt32: - case MetadataType.Int32: - case MetadataType.UInt64: - case MetadataType.Int64: - return arg; - } - - return expr; - } - - static ILExpression DivideBySize(ILExpression expr, TypeReference type) - { - expr = UnwrapIntPtrCast(expr); - - ILExpression sizeOfExpression; - switch (TypeAnalysis.GetInformationAmount(type)) { - case 1: - case 8: - sizeOfExpression = new ILExpression(ILCode.Ldc_I4, 1); - break; - case 16: - sizeOfExpression = new ILExpression(ILCode.Ldc_I4, 2); - break; - case 32: - sizeOfExpression = new ILExpression(ILCode.Ldc_I4, 4); - break; - case 64: - sizeOfExpression = new ILExpression(ILCode.Ldc_I4, 8); - break; - default: - sizeOfExpression = new ILExpression(ILCode.Sizeof, type); - break; - } - - if (expr.Code == ILCode.Mul || expr.Code == ILCode.Mul_Ovf || expr.Code == ILCode.Mul_Ovf_Un) { - ILExpression mulArg = expr.Arguments[1]; - if (mulArg.Code == sizeOfExpression.Code && sizeOfExpression.Operand.Equals(mulArg.Operand)) - return UnwrapIntPtrCast(expr.Arguments[0]); - } - - if (expr.Code == sizeOfExpression.Code) { - if (sizeOfExpression.Operand.Equals(expr.Operand)) - return new ILExpression(ILCode.Ldc_I4, 1); - - if (expr.Code == ILCode.Ldc_I4) { - int offsetInBytes = (int)expr.Operand; - int elementSize = (int)sizeOfExpression.Operand; - int offsetInElements = offsetInBytes / elementSize; - - // ensure integer division - if (offsetInElements * elementSize == offsetInBytes) { - expr.Operand = offsetInElements; - return expr; - } - } - } - - return new ILExpression(ILCode.Div_Un, null, expr, sizeOfExpression); - } - - public static void ReplaceVariables(ILNode node, Func variableMapping) - { - ILExpression expr = node as ILExpression; - if (expr != null) { - ILVariable v = expr.Operand as ILVariable; - if (v != null) - expr.Operand = variableMapping(v); - foreach (ILExpression child in expr.Arguments) - ReplaceVariables(child, variableMapping); - } else { - var catchBlock = node as ILTryCatchBlock.CatchBlock; - if (catchBlock != null && catchBlock.ExceptionVariable != null) { - catchBlock.ExceptionVariable = variableMapping(catchBlock.ExceptionVariable); - } - - foreach (ILNode child in node.GetChildren()) - ReplaceVariables(child, variableMapping); - } - } - - void ReportUnassignedILRanges(ILBlock method) - { - var unassigned = ILRange.Invert(method.GetSelfAndChildrenRecursive().SelectMany(e => e.ILRanges), context.CurrentMethod.Body.CodeSize).ToList(); - if (unassigned.Count > 0) - Debug.WriteLine(string.Format("Unassigned ILRanges for {0}.{1}: {2}", context.CurrentMethod.DeclaringType.Name, context.CurrentMethod.Name, string.Join(", ", unassigned.Select(r => r.ToString())))); - } - } - - public static class ILAstOptimizerExtensionMethods - { - /// - /// Perform one pass of a given optimization on this block. - /// This block must consist of only basicblocks. - /// - public static bool RunOptimization(this ILBlock block, Func, ILBasicBlock, int, bool> optimization) - { - bool modified = false; - List body = block.Body; - for (int i = body.Count - 1; i >= 0; i--) { - if (i < body.Count && optimization(body, (ILBasicBlock)body[i], i)) { - modified = true; - } - } - return modified; - } - - public static bool RunOptimization(this ILBlock block, Func, ILExpression, int, bool> optimization) - { - bool modified = false; - foreach (ILBasicBlock bb in block.Body) { - for (int i = bb.Body.Count - 1; i >= 0; i--) { - ILExpression expr = bb.Body.ElementAtOrDefault(i) as ILExpression; - if (expr != null && optimization(bb.Body, expr, i)) { - modified = true; - } - } - } - return modified; - } - - public static bool IsConditionalControlFlow(this ILNode node) - { - ILExpression expr = node as ILExpression; - return expr != null && expr.Code.IsConditionalControlFlow(); - } - - public static bool IsUnconditionalControlFlow(this ILNode node) - { - ILExpression expr = node as ILExpression; - return expr != null && expr.Code.IsUnconditionalControlFlow(); - } - - /// - /// The expression has no effect on the program and can be removed - /// if its return value is not needed. - /// - public static bool HasNoSideEffects(this ILExpression expr) - { - // Remember that if expression can throw an exception, it is a side effect - - switch(expr.Code) { - case ILCode.Ldloc: - case ILCode.Ldloca: - case ILCode.Ldstr: - case ILCode.Ldnull: - case ILCode.Ldc_I4: - case ILCode.Ldc_I8: - case ILCode.Ldc_R4: - case ILCode.Ldc_R8: - case ILCode.Ldc_Decimal: - return true; - default: - return false; - } - } - - public static bool IsStoreToArray(this ILCode code) - { - switch (code) { - case ILCode.Stelem_Any: - case ILCode.Stelem_I: - case ILCode.Stelem_I1: - case ILCode.Stelem_I2: - case ILCode.Stelem_I4: - case ILCode.Stelem_I8: - case ILCode.Stelem_R4: - case ILCode.Stelem_R8: - case ILCode.Stelem_Ref: - return true; - default: - return false; - } - } - - public static bool IsLoadFromArray(this ILCode code) - { - switch (code) { - case ILCode.Ldelem_Any: - case ILCode.Ldelem_I: - case ILCode.Ldelem_I1: - case ILCode.Ldelem_I2: - case ILCode.Ldelem_I4: - case ILCode.Ldelem_I8: - case ILCode.Ldelem_U1: - case ILCode.Ldelem_U2: - case ILCode.Ldelem_U4: - case ILCode.Ldelem_R4: - case ILCode.Ldelem_R8: - case ILCode.Ldelem_Ref: - return true; - default: - return false; - } - } - - /// - /// Can the expression be used as a statement in C#? - /// - public static bool CanBeExpressionStatement(this ILExpression expr) - { - switch(expr.Code) { - case ILCode.Call: - case ILCode.Callvirt: - // property getters can't be expression statements, but all other method calls can be - MethodReference mr = (MethodReference)expr.Operand; - return !mr.Name.StartsWith("get_", StringComparison.Ordinal); - case ILCode.CallSetter: - case ILCode.CallvirtSetter: - case ILCode.Newobj: - case ILCode.Newarr: - case ILCode.Stloc: - case ILCode.Stobj: - case ILCode.Stsfld: - case ILCode.Stfld: - case ILCode.Stind_Ref: - case ILCode.Stelem_Any: - case ILCode.Stelem_I: - case ILCode.Stelem_I1: - case ILCode.Stelem_I2: - case ILCode.Stelem_I4: - case ILCode.Stelem_I8: - case ILCode.Stelem_R4: - case ILCode.Stelem_R8: - case ILCode.Stelem_Ref: - return true; - default: - return false; - } - } - - public static ILExpression WithILRanges(this ILExpression expr, IEnumerable ilranges) - { - expr.ILRanges.AddRange(ilranges); - return expr; - } - - public static void RemoveTail(this List body, params ILCode[] codes) - { - for (int i = 0; i < codes.Length; i++) { - if (((ILExpression)body[body.Count - codes.Length + i]).Code != codes[i]) - throw new Exception("Tailing code does not match expected."); - } - body.RemoveRange(body.Count - codes.Length, codes.Length); - } - - public static V GetOrDefault(this Dictionary dict, K key) - { - V ret; - dict.TryGetValue(key, out ret); - return ret; - } - - public static void RemoveOrThrow(this ICollection collection, T item) - { - if (!collection.Remove(item)) - throw new Exception("The item was not found in the collection"); - } - - public static void RemoveOrThrow(this Dictionary collection, K key) - { - if (!collection.Remove(key)) - throw new Exception("The key was not found in the dictionary"); - } - - public static bool ContainsReferenceTo(this ILExpression expr, ILVariable v) - { - if (expr.Operand == v) - return true; - foreach (var arg in expr.Arguments) { - if (ContainsReferenceTo(arg, v)) - return true; - } - return false; - } - } -} diff --git a/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs b/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs deleted file mode 100644 index aab64e6e..00000000 --- a/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs +++ /dev/null @@ -1,601 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Text; -using ICSharpCode.Decompiler; -using ICSharpCode.Decompiler.Disassembler; -using ICSharpCode.NRefactory.Utils; -using Mono.Cecil; -using Mono.Cecil.Cil; -using Mono.CSharp; -using Cecil = Mono.Cecil; - -namespace ICSharpCode.Decompiler.ILAst -{ - public abstract class ILNode - { - public IEnumerable GetSelfAndChildrenRecursive(Func predicate = null) where T: ILNode - { - List result = new List(16); - AccumulateSelfAndChildrenRecursive(result, predicate); - return result; - } - - void AccumulateSelfAndChildrenRecursive(List list, Func predicate) where T:ILNode - { - // Note: RemoveEndFinally depends on self coming before children - T thisAsT = this as T; - if (thisAsT != null && (predicate == null || predicate(thisAsT))) - list.Add(thisAsT); - foreach (ILNode node in GetChildren()) { - if (node != null) - node.AccumulateSelfAndChildrenRecursive(list, predicate); - } - } - - public virtual IEnumerable GetChildren() - { - yield break; - } - - public override string ToString() - { - StringWriter w = new StringWriter(); - WriteTo(new PlainTextOutput(w)); - return w.ToString().Replace("\r\n", "; "); - } - - public abstract void WriteTo(ITextOutput output); - } - - public class ILBlock: ILNode - { - public ILExpression EntryGoto; - - public List Body; - - public ILBlock(params ILNode[] body) - { - Body = new List(body); - } - - public ILBlock(List body) - { - Body = body; - } - - public override IEnumerable GetChildren() - { - if (EntryGoto != null) - yield return EntryGoto; - foreach(ILNode child in Body) { - yield return child; - } - } - - public override void WriteTo(ITextOutput output) - { - foreach(ILNode child in GetChildren()) { - child.WriteTo(output); - output.WriteLine(); - } - } - } - - public class ILBasicBlock: ILNode - { - /// Body has to start with a label and end with unconditional control flow - public List Body = new List(); - - public override IEnumerable GetChildren() - { - return Body; - } - - public override void WriteTo(ITextOutput output) - { - foreach(ILNode child in GetChildren()) { - child.WriteTo(output); - output.WriteLine(); - } - } - } - - public class ILLabel: ILNode - { - public string Name; - - public override void WriteTo(ITextOutput output) - { - output.WriteDefinition(Name + ":", this); - } - } - - public class ILTryCatchBlock: ILNode - { - public class CatchBlock: ILBlock - { - public TypeReference ExceptionType; - public ILVariable ExceptionVariable; - - public override void WriteTo(ITextOutput output) - { - output.Write("catch "); - output.WriteReference(ExceptionType.FullName, ExceptionType); - if (ExceptionVariable != null) { - output.Write(' '); - output.Write(ExceptionVariable.Name); - } - output.WriteLine(" {"); - output.Indent(); - base.WriteTo(output); - output.Unindent(); - output.WriteLine("}"); - } - } - - public ILBlock TryBlock; - public List CatchBlocks; - public ILBlock FinallyBlock; - public ILBlock FaultBlock; - - public override IEnumerable GetChildren() - { - if (TryBlock != null) - yield return TryBlock; - foreach (var catchBlock in CatchBlocks) { - yield return catchBlock; - } - if (FaultBlock != null) - yield return FaultBlock; - if (FinallyBlock != null) - yield return FinallyBlock; - } - - public override void WriteTo(ITextOutput output) - { - output.WriteLine(".try {"); - output.Indent(); - TryBlock.WriteTo(output); - output.Unindent(); - output.WriteLine("}"); - foreach (CatchBlock block in CatchBlocks) { - block.WriteTo(output); - } - if (FaultBlock != null) { - output.WriteLine("fault {"); - output.Indent(); - FaultBlock.WriteTo(output); - output.Unindent(); - output.WriteLine("}"); - } - if (FinallyBlock != null) { - output.WriteLine("finally {"); - output.Indent(); - FinallyBlock.WriteTo(output); - output.Unindent(); - output.WriteLine("}"); - } - } - } - - public class ILVariable - { - public string Name; - public bool IsGenerated; - public TypeReference Type; - public VariableDefinition OriginalVariable; - public ParameterDefinition OriginalParameter; - - public bool IsPinned { - get { return OriginalVariable != null && OriginalVariable.IsPinned; } - } - - public bool IsParameter { - get { return OriginalParameter != null; } - } - - public override string ToString() - { - return Name; - } - } - - public struct ILRange - { - public readonly int From; - public readonly int To; // Exlusive - - public ILRange(int @from, int to) - { - From = @from; - To = to; - } - - public override string ToString() - { - return string.Format("{0:X2}-{1:X2}", From, To); - } - - public static List OrderAndJoin(IEnumerable input) - { - if (input == null) - throw new ArgumentNullException("Input is null!"); - - List result = new List(); - foreach(ILRange curr in input.OrderBy(r => r.From)) { - if (result.Count > 0) { - // Merge consequtive ranges if possible - ILRange last = result[result.Count - 1]; - if (curr.From <= last.To) { - result[result.Count - 1] = new ILRange(last.From, Math.Max(last.To, curr.To)); - continue; - } - } - result.Add(curr); - } - return result; - } - - public static List Invert(IEnumerable input, int codeSize) - { - if (input == null) - throw new ArgumentNullException("Input is null!"); - - if (codeSize <= 0) - throw new ArgumentException("Code size must be grater than 0"); - - List ordered = OrderAndJoin(input); - List result = new List(ordered.Count + 1); - if (ordered.Count == 0) { - result.Add(new ILRange(0, codeSize)); - } else { - // Gap before the first element - if (ordered.First().From != 0) - result.Add(new ILRange(0, ordered.First().From)); - - // Gaps between elements - for (int i = 0; i < ordered.Count - 1; i++) - result.Add(new ILRange(ordered[i].To, ordered[i + 1].From)); - - // Gap after the last element - Debug.Assert(ordered.Last().To <= codeSize); - if (ordered.Last().To != codeSize) - result.Add(new ILRange(ordered.Last().To, codeSize)); - } - return result; - } - } - - public class ILExpressionPrefix - { - public readonly ILCode Code; - public readonly object Operand; - - public ILExpressionPrefix(ILCode code, object operand = null) - { - Code = code; - Operand = operand; - } - } - - public class ILExpression : ILNode - { - public ILCode Code { get; set; } - public object Operand { get; set; } - public List Arguments { get; set; } - public ILExpressionPrefix[] Prefixes { get; set; } - // Mapping to the original instructions (useful for debugging) - public List ILRanges { get; set; } - - public TypeReference ExpectedType { get; set; } - public TypeReference InferredType { get; set; } - - public static readonly object AnyOperand = new object(); - - public ILExpression(ILCode code, object operand, List args) - { - if (operand is ILExpression) - throw new ArgumentException("operand"); - - Code = code; - Operand = operand; - Arguments = new List(args); - ILRanges = new List(1); - } - - public ILExpression(ILCode code, object operand, params ILExpression[] args) - { - if (operand is ILExpression) - throw new ArgumentException("operand"); - - Code = code; - Operand = operand; - Arguments = new List(args); - ILRanges = new List(1); - } - - public void AddPrefix(ILExpressionPrefix prefix) - { - ILExpressionPrefix[] arr = Prefixes; - if (arr == null) - arr = new ILExpressionPrefix[1]; - else - Array.Resize(ref arr, arr.Length + 1); - arr[arr.Length - 1] = prefix; - Prefixes = arr; - } - - public ILExpressionPrefix GetPrefix(ILCode code) - { - var prefixes = Prefixes; - if (prefixes != null) { - foreach (ILExpressionPrefix p in prefixes) { - if (p.Code == code) - return p; - } - } - return null; - } - - public override IEnumerable GetChildren() - { - return Arguments; - } - - public bool IsBranch() - { - return Operand is ILLabel || Operand is ILLabel[]; - } - - public IEnumerable GetBranchTargets() - { - if (Operand is ILLabel) { - return new ILLabel[] { (ILLabel)Operand }; - } else if (Operand is ILLabel[]) { - return (ILLabel[])Operand; - } else { - return new ILLabel[] { }; - } - } - - public override void WriteTo(ITextOutput output) - { - if (Operand is ILVariable && ((ILVariable)Operand).IsGenerated) { - if (Code == ILCode.Stloc && InferredType == null) { - output.Write(((ILVariable)Operand).Name); - output.Write(" = "); - Arguments.First().WriteTo(output); - return; - } else if (Code == ILCode.Ldloc) { - output.Write(((ILVariable)Operand).Name); - if (InferredType != null) { - output.Write(':'); - InferredType.WriteTo(output, ILNameSyntax.ShortTypeName); - if (ExpectedType != null && ExpectedType.FullName != InferredType.FullName) { - output.Write("[exp:"); - ExpectedType.WriteTo(output, ILNameSyntax.ShortTypeName); - output.Write(']'); - } - } - return; - } - } - - if (Prefixes != null) { - foreach (var prefix in Prefixes) { - output.Write(prefix.Code.GetName()); - output.Write(". "); - } - } - - output.Write(Code.GetName()); - if (InferredType != null) { - output.Write(':'); - InferredType.WriteTo(output, ILNameSyntax.ShortTypeName); - if (ExpectedType != null && ExpectedType.FullName != InferredType.FullName) { - output.Write("[exp:"); - ExpectedType.WriteTo(output, ILNameSyntax.ShortTypeName); - output.Write(']'); - } - } else if (ExpectedType != null) { - output.Write("[exp:"); - ExpectedType.WriteTo(output, ILNameSyntax.ShortTypeName); - output.Write(']'); - } - output.Write('('); - bool first = true; - if (Operand != null) { - if (Operand is ILLabel) { - output.WriteReference(((ILLabel)Operand).Name, Operand); - } else if (Operand is ILLabel[]) { - ILLabel[] labels = (ILLabel[])Operand; - for (int i = 0; i < labels.Length; i++) { - if (i > 0) - output.Write(", "); - output.WriteReference(labels[i].Name, labels[i]); - } - } else if (Operand is MethodReference) { - MethodReference method = (MethodReference)Operand; - if (method.DeclaringType != null) { - method.DeclaringType.WriteTo(output, ILNameSyntax.ShortTypeName); - output.Write("::"); - } - output.WriteReference(method.Name, method); - } else if (Operand is FieldReference) { - FieldReference field = (FieldReference)Operand; - field.DeclaringType.WriteTo(output, ILNameSyntax.ShortTypeName); - output.Write("::"); - output.WriteReference(field.Name, field); - } else { - DisassemblerHelpers.WriteOperand(output, Operand); - } - first = false; - } - foreach (ILExpression arg in Arguments) { - if (!first) output.Write(", "); - arg.WriteTo(output); - first = false; - } - output.Write(')'); - } - } - - public class ILWhileLoop : ILNode - { - public ILExpression Condition; - public ILBlock BodyBlock; - - public override IEnumerable GetChildren() - { - if (Condition != null) - yield return Condition; - if (BodyBlock != null) - yield return BodyBlock; - } - - public override void WriteTo(ITextOutput output) - { - output.WriteLine(""); - output.Write("loop ("); - if (Condition != null) - Condition.WriteTo(output); - output.WriteLine(") {"); - output.Indent(); - BodyBlock.WriteTo(output); - output.Unindent(); - output.WriteLine("}"); - } - } - - public class ILCondition : ILNode - { - public ILExpression Condition; - public ILBlock TrueBlock; // Branch was taken - public ILBlock FalseBlock; // Fall-though - - public override IEnumerable GetChildren() - { - if (Condition != null) - yield return Condition; - if (TrueBlock != null) - yield return TrueBlock; - if (FalseBlock != null) - yield return FalseBlock; - } - - public override void WriteTo(ITextOutput output) - { - output.Write("if ("); - Condition.WriteTo(output); - output.WriteLine(") {"); - output.Indent(); - TrueBlock.WriteTo(output); - output.Unindent(); - output.Write("}"); - if (FalseBlock != null) { - output.WriteLine(" else {"); - output.Indent(); - FalseBlock.WriteTo(output); - output.Unindent(); - output.WriteLine("}"); - } - } - } - - public class ILSwitch: ILNode - { - public class CaseBlock: ILBlock - { - public List Values; // null for the default case - - public override void WriteTo(ITextOutput output) - { - if (Values != null) { - foreach (int i in Values) { - output.WriteLine("case {0}:", i); - } - } else { - output.WriteLine("default:"); - } - output.Indent(); - base.WriteTo(output); - output.Unindent(); - } - } - - public ILExpression Condition; - public List CaseBlocks = new List(); - - public override IEnumerable GetChildren() - { - if (Condition != null) - yield return Condition; - foreach (ILBlock caseBlock in CaseBlocks) { - yield return caseBlock; - } - } - - public override void WriteTo(ITextOutput output) - { - output.Write("switch ("); - Condition.WriteTo(output); - output.WriteLine(") {"); - output.Indent(); - foreach (CaseBlock caseBlock in CaseBlocks) { - caseBlock.WriteTo(output); - } - output.Unindent(); - output.WriteLine("}"); - } - } - - public class ILFixedStatement : ILNode - { - public List Initializers = new List(); - public ILBlock BodyBlock; - - public override IEnumerable GetChildren() - { - foreach (ILExpression initializer in Initializers) - yield return initializer; - if (BodyBlock != null) - yield return BodyBlock; - } - - public override void WriteTo(ITextOutput output) - { - output.Write("fixed ("); - for (int i = 0; i < Initializers.Count; i++) { - if (i > 0) - output.Write(", "); - Initializers[i].WriteTo(output); - } - output.WriteLine(") {"); - output.Indent(); - BodyBlock.WriteTo(output); - output.Unindent(); - output.WriteLine("}"); - } - } -} \ No newline at end of file diff --git a/ICSharpCode.Decompiler/ILAst/ILCodes.cs b/ICSharpCode.Decompiler/ILAst/ILCodes.cs deleted file mode 100644 index 5ca063b7..00000000 --- a/ICSharpCode.Decompiler/ILAst/ILCodes.cs +++ /dev/null @@ -1,490 +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 Mono.Cecil; -using Mono.Cecil.Cil; - -namespace ICSharpCode.Decompiler.ILAst -{ - public enum ILCode - { - // For convenience, the start is exactly identical to Mono.Cecil.Cil.Code - // Instructions that should not be used are prepended by __ - Nop, - Break, - __Ldarg_0, - __Ldarg_1, - __Ldarg_2, - __Ldarg_3, - __Ldloc_0, - __Ldloc_1, - __Ldloc_2, - __Ldloc_3, - __Stloc_0, - __Stloc_1, - __Stloc_2, - __Stloc_3, - __Ldarg_S, - __Ldarga_S, - __Starg_S, - __Ldloc_S, - __Ldloca_S, - __Stloc_S, - Ldnull, - __Ldc_I4_M1, - __Ldc_I4_0, - __Ldc_I4_1, - __Ldc_I4_2, - __Ldc_I4_3, - __Ldc_I4_4, - __Ldc_I4_5, - __Ldc_I4_6, - __Ldc_I4_7, - __Ldc_I4_8, - __Ldc_I4_S, - Ldc_I4, - Ldc_I8, - Ldc_R4, - Ldc_R8, - Dup, - Pop, - Jmp, - Call, - Calli, - Ret, - __Br_S, - __Brfalse_S, - __Brtrue_S, - __Beq_S, - __Bge_S, - __Bgt_S, - __Ble_S, - __Blt_S, - __Bne_Un_S, - __Bge_Un_S, - __Bgt_Un_S, - __Ble_Un_S, - __Blt_Un_S, - Br, - __Brfalse, - Brtrue, - __Beq, - __Bge, - __Bgt, - __Ble, - __Blt, - __Bne_Un, - __Bge_Un, - __Bgt_Un, - __Ble_Un, - __Blt_Un, - Switch, - __Ldind_I1, - __Ldind_U1, - __Ldind_I2, - __Ldind_U2, - __Ldind_I4, - __Ldind_U4, - __Ldind_I8, - __Ldind_I, - __Ldind_R4, - __Ldind_R8, - Ldind_Ref, - Stind_Ref, - __Stind_I1, - __Stind_I2, - __Stind_I4, - __Stind_I8, - __Stind_R4, - __Stind_R8, - Add, - Sub, - Mul, - Div, - Div_Un, - Rem, - Rem_Un, - And, - Or, - Xor, - Shl, - Shr, - Shr_Un, - Neg, - Not, - Conv_I1, - Conv_I2, - Conv_I4, - Conv_I8, - Conv_R4, - Conv_R8, - Conv_U4, - Conv_U8, - Callvirt, - Cpobj, - Ldobj, - Ldstr, - Newobj, - Castclass, - Isinst, - Conv_R_Un, - Unbox, - Throw, - Ldfld, - Ldflda, - Stfld, - Ldsfld, - Ldsflda, - Stsfld, - Stobj, - Conv_Ovf_I1_Un, - Conv_Ovf_I2_Un, - Conv_Ovf_I4_Un, - Conv_Ovf_I8_Un, - Conv_Ovf_U1_Un, - Conv_Ovf_U2_Un, - Conv_Ovf_U4_Un, - Conv_Ovf_U8_Un, - Conv_Ovf_I_Un, - Conv_Ovf_U_Un, - Box, - Newarr, - Ldlen, - Ldelema, - Ldelem_I1, - Ldelem_U1, - Ldelem_I2, - Ldelem_U2, - Ldelem_I4, - Ldelem_U4, - Ldelem_I8, - Ldelem_I, - Ldelem_R4, - Ldelem_R8, - Ldelem_Ref, - Stelem_I, - Stelem_I1, - Stelem_I2, - Stelem_I4, - Stelem_I8, - Stelem_R4, - Stelem_R8, - Stelem_Ref, - Ldelem_Any, - Stelem_Any, - Unbox_Any, - Conv_Ovf_I1, - Conv_Ovf_U1, - Conv_Ovf_I2, - Conv_Ovf_U2, - Conv_Ovf_I4, - Conv_Ovf_U4, - Conv_Ovf_I8, - Conv_Ovf_U8, - Refanyval, - Ckfinite, - Mkrefany, - Ldtoken, - Conv_U2, - Conv_U1, - Conv_I, - Conv_Ovf_I, - Conv_Ovf_U, - Add_Ovf, - Add_Ovf_Un, - Mul_Ovf, - Mul_Ovf_Un, - Sub_Ovf, - Sub_Ovf_Un, - Endfinally, - Leave, - __Leave_S, - __Stind_I, - Conv_U, - Arglist, - Ceq, - Cgt, - Cgt_Un, - Clt, - Clt_Un, - Ldftn, - Ldvirtftn, - __Ldarg, - __Ldarga, - __Starg, - Ldloc, - Ldloca, - Stloc, - Localloc, - Endfilter, - Unaligned, - Volatile, - Tail, - Initobj, - Constrained, - Cpblk, - Initblk, - No, - Rethrow, - Sizeof, - Refanytype, - Readonly, - - // Virtual codes - defined for convenience - Cne, - Cge, - Cge_Un, - Cle, - Cle_Un, - Ldexception, // Operand holds the CatchType for catch handler, null for filter - LogicNot, - LogicAnd, - LogicOr, - NullCoalescing, - InitArray, // Array Initializer - - /// - /// Defines a barrier between the parent expression and the argument expression that prevents combining them - /// - Wrap, - - // new Class { Prop = 1, Collection = { { 2, 3 }, {4, 5} }} - // is represented as: - // InitObject(newobj Class, - // CallSetter(Prop, InitializedObject, 1), - // InitCollection(CallGetter(Collection, InitializedObject))), - // Call(Add, InitializedObject, 2, 3), - // Call(Add, InitializedObject, 4, 5))) - InitObject, // Object initializer: first arg is newobj/defaultvalue, remaining args are the initializing statements - InitCollection, // Collection initializer: first arg is newobj/defaultvalue, remaining args are the initializing statements - InitializedObject, // Refers the the object being initialized (refers to first arg in parent InitObject or InitCollection instruction) - - TernaryOp, // ?: - LoopOrSwitchBreak, - LoopContinue, - Ldc_Decimal, - YieldBreak, - YieldReturn, - /// - /// Represents the 'default(T)' instruction. - /// - /// Introduced by SimplifyLdObjAndStObj step - DefaultValue, - /// - /// ILExpression with a single child: binary operator. - /// This expression means that the binary operator will also assign the new value to its left-hand side. - /// 'CompoundAssignment' must not be used for local variables, as inlining (and other) optimizations don't know that it modifies the variable. - /// - /// Introduced by MakeCompoundAssignments step - CompoundAssignment, - /// - /// Represents the post-increment operator. - /// The first argument is the address of the variable to increment (ldloca instruction). - /// The second arugment is the amount the variable is incremented by (ldc.i4 instruction) - /// - /// Introduced by IntroducePostIncrement step - PostIncrement, - PostIncrement_Ovf, // checked variant of PostIncrement - PostIncrement_Ovf_Un, // checked variant of PostIncrement, for unsigned integers - /// Calls the getter of a static property (or indexer), or of an instance property on 'base' - CallGetter, - /// Calls the getter of an instance property (or indexer) - CallvirtGetter, - /// Calls the setter of a static property (or indexer), or of an instance property on 'base' - /// This allows us to represent "while ((SomeProperty = val) != null) {}" - CallSetter, - /// Calls the setter of a instance property (or indexer) - CallvirtSetter, - /// Simulates getting the address of the argument instruction. - /// - /// Used for postincrement for properties, and to represent the Address() method on multi-dimensional arrays. - /// Also used when inlining a method call on a value type: "stloc(v, ...); call(M, ldloca(v));" becomes "call(M, AddressOf(...))" - /// - AddressOf, - /// Simulates getting the value of a lifted operator's nullable argument - /// - /// For example "stloc(v1, ...); stloc(v2, ...); logicand(ceq(call(Nullable`1::GetValueOrDefault, ldloca(v1)), ldloc(v2)), callgetter(Nullable`1::get_HasValue, ldloca(v1)))" becomes "wrap(ceq(ValueOf(...), ...))" - /// - ValueOf, - /// Simulates creating a new nullable value from a value type argument - /// - /// For example "stloc(v1, ...); stloc(v2, ...); ternaryop(callgetter(Nullable`1::get_HasValue, ldloca(v1)), newobj(Nullable`1::.ctor, add(call(Nullable`1::GetValueOrDefault, ldloca(v1)), ldloc(v2))), defaultvalue(Nullable`1))" - /// becomes "NullableOf(add(valueof(...), ...))" - /// - NullableOf, - /// - /// Declares parameters that are used in an expression tree. - /// The last child of this node is the call constructing the expression tree, all other children are the - /// assignments to the ParameterExpression variables. - /// - ExpressionTreeParameterDeclarations, - /// - /// C# 5 await - /// - Await - } - - public static class ILCodeUtil - { - public static string GetName(this ILCode code) - { - return code.ToString().ToLowerInvariant().TrimStart('_').Replace('_','.'); - } - - public static bool IsConditionalControlFlow(this ILCode code) - { - switch(code) { - case ILCode.__Brfalse_S: - case ILCode.__Brtrue_S: - case ILCode.__Beq_S: - case ILCode.__Bge_S: - case ILCode.__Bgt_S: - case ILCode.__Ble_S: - case ILCode.__Blt_S: - case ILCode.__Bne_Un_S: - case ILCode.__Bge_Un_S: - case ILCode.__Bgt_Un_S: - case ILCode.__Ble_Un_S: - case ILCode.__Blt_Un_S: - case ILCode.__Brfalse: - case ILCode.Brtrue: - case ILCode.__Beq: - case ILCode.__Bge: - case ILCode.__Bgt: - case ILCode.__Ble: - case ILCode.__Blt: - case ILCode.__Bne_Un: - case ILCode.__Bge_Un: - case ILCode.__Bgt_Un: - case ILCode.__Ble_Un: - case ILCode.__Blt_Un: - case ILCode.Switch: - return true; - default: - return false; - } - } - - public static bool IsUnconditionalControlFlow(this ILCode code) - { - switch(code) { - case ILCode.Br: - case ILCode.__Br_S: - case ILCode.Leave: - case ILCode.__Leave_S: - case ILCode.Ret: - case ILCode.Endfilter: - case ILCode.Endfinally: - case ILCode.Throw: - case ILCode.Rethrow: - case ILCode.LoopContinue: - case ILCode.LoopOrSwitchBreak: - case ILCode.YieldBreak: - return true; - default: - return false; - } - } - - public static void ExpandMacro(ref ILCode code, ref object operand, MethodBody methodBody) - { - switch (code) { - case ILCode.__Ldarg_0: code = ILCode.__Ldarg; operand = methodBody.GetParameter(0); break; - case ILCode.__Ldarg_1: code = ILCode.__Ldarg; operand = methodBody.GetParameter(1); break; - case ILCode.__Ldarg_2: code = ILCode.__Ldarg; operand = methodBody.GetParameter(2); break; - case ILCode.__Ldarg_3: code = ILCode.__Ldarg; operand = methodBody.GetParameter(3); break; - case ILCode.__Ldloc_0: code = ILCode.Ldloc; operand = methodBody.Variables[0]; break; - case ILCode.__Ldloc_1: code = ILCode.Ldloc; operand = methodBody.Variables[1]; break; - case ILCode.__Ldloc_2: code = ILCode.Ldloc; operand = methodBody.Variables[2]; break; - case ILCode.__Ldloc_3: code = ILCode.Ldloc; operand = methodBody.Variables[3]; break; - case ILCode.__Stloc_0: code = ILCode.Stloc; operand = methodBody.Variables[0]; break; - case ILCode.__Stloc_1: code = ILCode.Stloc; operand = methodBody.Variables[1]; break; - case ILCode.__Stloc_2: code = ILCode.Stloc; operand = methodBody.Variables[2]; break; - case ILCode.__Stloc_3: code = ILCode.Stloc; operand = methodBody.Variables[3]; break; - case ILCode.__Ldarg_S: code = ILCode.__Ldarg; break; - case ILCode.__Ldarga_S: code = ILCode.__Ldarga; break; - case ILCode.__Starg_S: code = ILCode.__Starg; break; - case ILCode.__Ldloc_S: code = ILCode.Ldloc; break; - case ILCode.__Ldloca_S: code = ILCode.Ldloca; break; - case ILCode.__Stloc_S: code = ILCode.Stloc; break; - case ILCode.__Ldc_I4_M1: code = ILCode.Ldc_I4; operand = -1; break; - case ILCode.__Ldc_I4_0: code = ILCode.Ldc_I4; operand = 0; break; - case ILCode.__Ldc_I4_1: code = ILCode.Ldc_I4; operand = 1; break; - case ILCode.__Ldc_I4_2: code = ILCode.Ldc_I4; operand = 2; break; - case ILCode.__Ldc_I4_3: code = ILCode.Ldc_I4; operand = 3; break; - case ILCode.__Ldc_I4_4: code = ILCode.Ldc_I4; operand = 4; break; - case ILCode.__Ldc_I4_5: code = ILCode.Ldc_I4; operand = 5; break; - case ILCode.__Ldc_I4_6: code = ILCode.Ldc_I4; operand = 6; break; - case ILCode.__Ldc_I4_7: code = ILCode.Ldc_I4; operand = 7; break; - case ILCode.__Ldc_I4_8: code = ILCode.Ldc_I4; operand = 8; break; - case ILCode.__Ldc_I4_S: code = ILCode.Ldc_I4; operand = (int) (sbyte) operand; break; - case ILCode.__Br_S: code = ILCode.Br; break; - case ILCode.__Brfalse_S: code = ILCode.__Brfalse; break; - case ILCode.__Brtrue_S: code = ILCode.Brtrue; break; - case ILCode.__Beq_S: code = ILCode.__Beq; break; - case ILCode.__Bge_S: code = ILCode.__Bge; break; - case ILCode.__Bgt_S: code = ILCode.__Bgt; break; - case ILCode.__Ble_S: code = ILCode.__Ble; break; - case ILCode.__Blt_S: code = ILCode.__Blt; break; - case ILCode.__Bne_Un_S: code = ILCode.__Bne_Un; break; - case ILCode.__Bge_Un_S: code = ILCode.__Bge_Un; break; - case ILCode.__Bgt_Un_S: code = ILCode.__Bgt_Un; break; - case ILCode.__Ble_Un_S: code = ILCode.__Ble_Un; break; - case ILCode.__Blt_Un_S: code = ILCode.__Blt_Un; break; - case ILCode.__Leave_S: code = ILCode.Leave; break; - case ILCode.__Ldind_I: code = ILCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.IntPtr; break; - case ILCode.__Ldind_I1: code = ILCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.SByte; break; - case ILCode.__Ldind_I2: code = ILCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.Int16; break; - case ILCode.__Ldind_I4: code = ILCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.Int32; break; - case ILCode.__Ldind_I8: code = ILCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.Int64; break; - case ILCode.__Ldind_U1: code = ILCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.Byte; break; - case ILCode.__Ldind_U2: code = ILCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.UInt16; break; - case ILCode.__Ldind_U4: code = ILCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.UInt32; break; - case ILCode.__Ldind_R4: code = ILCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.Single; break; - case ILCode.__Ldind_R8: code = ILCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.Double; break; - case ILCode.__Stind_I: code = ILCode.Stobj; operand = methodBody.Method.Module.TypeSystem.IntPtr; break; - case ILCode.__Stind_I1: code = ILCode.Stobj; operand = methodBody.Method.Module.TypeSystem.Byte; break; - case ILCode.__Stind_I2: code = ILCode.Stobj; operand = methodBody.Method.Module.TypeSystem.Int16; break; - case ILCode.__Stind_I4: code = ILCode.Stobj; operand = methodBody.Method.Module.TypeSystem.Int32; break; - case ILCode.__Stind_I8: code = ILCode.Stobj; operand = methodBody.Method.Module.TypeSystem.Int64; break; - case ILCode.__Stind_R4: code = ILCode.Stobj; operand = methodBody.Method.Module.TypeSystem.Single; break; - case ILCode.__Stind_R8: code = ILCode.Stobj; operand = methodBody.Method.Module.TypeSystem.Double; break; - } - } - - public static ParameterDefinition GetParameter (this MethodBody self, int index) - { - var method = self.Method; - - if (method.HasThis) { - if (index == 0) - return self.ThisParameter; - - index--; - } - - var parameters = method.Parameters; - - if (index < 0 || index >= parameters.Count) - return null; - - return parameters [index]; - } - } -} diff --git a/ICSharpCode.Decompiler/ILAst/ILInlining.cs b/ICSharpCode.Decompiler/ILAst/ILInlining.cs deleted file mode 100644 index 11140ef0..00000000 --- a/ICSharpCode.Decompiler/ILAst/ILInlining.cs +++ /dev/null @@ -1,524 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using Mono.Cecil; - -namespace ICSharpCode.Decompiler.ILAst -{ - /// - /// Performs inlining transformations. - /// - public class ILInlining - { - readonly ILBlock method; - internal Dictionary numStloc = new Dictionary(); - internal Dictionary numLdloc = new Dictionary(); - internal Dictionary numLdloca = new Dictionary(); - - public ILInlining(ILBlock method) - { - this.method = method; - AnalyzeMethod(); - } - - void AnalyzeMethod() - { - numStloc.Clear(); - numLdloc.Clear(); - numLdloca.Clear(); - - // Analyse the whole method - AnalyzeNode(method); - } - - /// - /// For each variable reference, adds to the num* dicts. - /// Direction will be 1 for analysis, and -1 when removing a node from analysis. - /// - void AnalyzeNode(ILNode node, int direction = 1) - { - ILExpression expr = node as ILExpression; - if (expr != null) { - ILVariable locVar = expr.Operand as ILVariable; - if (locVar != null) { - if (expr.Code == ILCode.Stloc) { - numStloc[locVar] = numStloc.GetOrDefault(locVar) + direction; - } else if (expr.Code == ILCode.Ldloc) { - numLdloc[locVar] = numLdloc.GetOrDefault(locVar) + direction; - } else if (expr.Code == ILCode.Ldloca) { - numLdloca[locVar] = numLdloca.GetOrDefault(locVar) + direction; - } else { - throw new NotSupportedException(expr.Code.ToString()); - } - } - foreach (ILExpression child in expr.Arguments) - AnalyzeNode(child, direction); - } else { - var catchBlock = node as ILTryCatchBlock.CatchBlock; - if (catchBlock != null && catchBlock.ExceptionVariable != null) { - numStloc[catchBlock.ExceptionVariable] = numStloc.GetOrDefault(catchBlock.ExceptionVariable) + direction; - } - - foreach (ILNode child in node.GetChildren()) - AnalyzeNode(child, direction); - } - } - - public bool InlineAllVariables() - { - bool modified = false; - ILInlining i = new ILInlining(method); - foreach (ILBlock block in method.GetSelfAndChildrenRecursive()) - modified |= i.InlineAllInBlock(block); - return modified; - } - - public bool InlineAllInBlock(ILBlock block) - { - bool modified = false; - List body = block.Body; - if (block is ILTryCatchBlock.CatchBlock && body.Count > 1) { - ILVariable v = ((ILTryCatchBlock.CatchBlock)block).ExceptionVariable; - if (v != null && v.IsGenerated) { - if (numLdloca.GetOrDefault(v) == 0 && numStloc.GetOrDefault(v) == 1 && numLdloc.GetOrDefault(v) == 1) { - ILVariable v2; - ILExpression ldException; - if (body[0].Match(ILCode.Stloc, out v2, out ldException) && ldException.MatchLdloc(v)) { - body.RemoveAt(0); - ((ILTryCatchBlock.CatchBlock)block).ExceptionVariable = v2; - modified = true; - } - } - } - } - for(int i = 0; i < body.Count - 1;) { - ILVariable locVar; - ILExpression expr; - if (body[i].Match(ILCode.Stloc, out locVar, out expr) && InlineOneIfPossible(block.Body, i, aggressive: false)) { - modified = true; - i = Math.Max(0, i - 1); // Go back one step - } else { - i++; - } - } - foreach(ILBasicBlock bb in body.OfType()) { - modified |= InlineAllInBasicBlock(bb); - } - return modified; - } - - public bool InlineAllInBasicBlock(ILBasicBlock bb) - { - bool modified = false; - List body = bb.Body; - for(int i = 0; i < body.Count;) { - ILVariable locVar; - ILExpression expr; - if (body[i].Match(ILCode.Stloc, out locVar, out expr) && InlineOneIfPossible(bb.Body, i, aggressive: false)) { - modified = true; - i = Math.Max(0, i - 1); // Go back one step - } else { - i++; - } - } - return modified; - } - - /// - /// Inlines instructions before pos into block.Body[pos]. - /// - /// The number of instructions that were inlined. - public int InlineInto(List body, int pos, bool aggressive) - { - if (pos >= body.Count) - return 0; - int count = 0; - while (--pos >= 0) { - ILExpression expr = body[pos] as ILExpression; - if (expr == null || expr.Code != ILCode.Stloc) - break; - if (InlineOneIfPossible(body, pos, aggressive)) - count++; - else - break; - } - return count; - } - - /// - /// Aggressively inlines the stloc instruction at block.Body[pos] into the next instruction, if possible. - /// If inlining was possible; we will continue to inline (non-aggressively) into the the combined instruction. - /// - /// - /// After the operation, pos will point to the new combined instruction. - /// - public bool InlineIfPossible(List body, ref int pos) - { - if (InlineOneIfPossible(body, pos, true)) { - pos -= InlineInto(body, pos, false); - return true; - } - return false; - } - - /// - /// Inlines the stloc instruction at block.Body[pos] into the next instruction, if possible. - /// - public bool InlineOneIfPossible(List body, int pos, bool aggressive) - { - ILVariable v; - ILExpression inlinedExpression; - if (body[pos].Match(ILCode.Stloc, out v, out inlinedExpression) && !v.IsPinned) { - if (InlineIfPossible(v, inlinedExpression, body.ElementAtOrDefault(pos+1), aggressive)) { - // Assign the ranges of the stloc instruction: - inlinedExpression.ILRanges.AddRange(((ILExpression)body[pos]).ILRanges); - // Remove the stloc instruction: - body.RemoveAt(pos); - return true; - } else if (numLdloc.GetOrDefault(v) == 0 && numLdloca.GetOrDefault(v) == 0) { - // The variable is never loaded - if (inlinedExpression.HasNoSideEffects()) { - // Remove completely - AnalyzeNode(body[pos], -1); - body.RemoveAt(pos); - return true; - } else if (inlinedExpression.CanBeExpressionStatement() && v.IsGenerated) { - // Assign the ranges of the stloc instruction: - inlinedExpression.ILRanges.AddRange(((ILExpression)body[pos]).ILRanges); - // Remove the stloc, but keep the inner expression - body[pos] = inlinedExpression; - return true; - } - } - } - return false; - } - - /// - /// Inlines 'expr' into 'next', if possible. - /// - bool InlineIfPossible(ILVariable v, ILExpression inlinedExpression, ILNode next, bool aggressive) - { - // ensure the variable is accessed only a single time - if (numStloc.GetOrDefault(v) != 1) - return false; - int ldloc = numLdloc.GetOrDefault(v); - if (ldloc > 1 || ldloc + numLdloca.GetOrDefault(v) != 1) - return false; - - if (next is ILCondition) - next = ((ILCondition)next).Condition; - else if (next is ILWhileLoop) - next = ((ILWhileLoop)next).Condition; - - ILExpression parent; - int pos; - if (FindLoadInNext(next as ILExpression, v, inlinedExpression, out parent, out pos) == true) { - if (ldloc == 0) { - if (!IsGeneratedValueTypeTemporary((ILExpression)next, parent, pos, v, inlinedExpression)) - return false; - } else { - if (!aggressive && !v.IsGenerated && !NonAggressiveInlineInto((ILExpression)next, parent, inlinedExpression)) - return false; - } - - // Assign the ranges of the ldloc instruction: - inlinedExpression.ILRanges.AddRange(parent.Arguments[pos].ILRanges); - - if (ldloc == 0) { - // it was an ldloca instruction, so we need to use the pseudo-opcode 'addressof' so that the types - // comes out correctly - parent.Arguments[pos] = new ILExpression(ILCode.AddressOf, null, inlinedExpression); - } else { - parent.Arguments[pos] = inlinedExpression; - } - return true; - } - return false; - } - - /// - /// Is this a temporary variable generated by the C# compiler for instance method calls on value type values - /// - /// The next top-level expression - /// The direct parent of the load within 'next' - /// Index of the load within 'parent' - /// The variable being inlined. - /// The expression being inlined - bool IsGeneratedValueTypeTemporary(ILExpression next, ILExpression parent, int pos, ILVariable v, ILExpression inlinedExpression) - { - if (pos == 0 && v.Type != null && v.Type.IsValueType) { - // Inlining a value type variable is allowed only if the resulting code will maintain the semantics - // that the method is operating on a copy. - // Thus, we have to disallow inlining of other locals, fields, array elements, dereferenced pointers - switch (inlinedExpression.Code) { - case ILCode.Ldloc: - case ILCode.Stloc: - case ILCode.CompoundAssignment: - case ILCode.Ldelem_Any: - case ILCode.Ldelem_I: - case ILCode.Ldelem_I1: - case ILCode.Ldelem_I2: - case ILCode.Ldelem_I4: - case ILCode.Ldelem_I8: - case ILCode.Ldelem_R4: - case ILCode.Ldelem_R8: - case ILCode.Ldelem_Ref: - case ILCode.Ldelem_U1: - case ILCode.Ldelem_U2: - case ILCode.Ldelem_U4: - case ILCode.Ldobj: - case ILCode.Ldind_Ref: - return false; - case ILCode.Ldfld: - case ILCode.Stfld: - case ILCode.Ldsfld: - case ILCode.Stsfld: - // allow inlining field access only if it's a readonly field - FieldDefinition f = ((FieldReference)inlinedExpression.Operand).Resolve(); - if (!(f != null && f.IsInitOnly)) - return false; - break; - case ILCode.Call: - case ILCode.CallGetter: - // inlining runs both before and after IntroducePropertyAccessInstructions, - // so we have to handle both 'call' and 'callgetter' - MethodReference mr = (MethodReference)inlinedExpression.Operand; - // ensure that it's not an multi-dimensional array getter - if (mr.DeclaringType is ArrayType) - return false; - goto case ILCode.Callvirt; - case ILCode.Callvirt: - case ILCode.CallvirtGetter: - // don't inline foreach loop variables: - mr = (MethodReference)inlinedExpression.Operand; - if (mr.Name == "get_Current" && mr.HasThis) - return false; - break; - case ILCode.Castclass: - case ILCode.Unbox_Any: - // These are valid, but might occur as part of a foreach loop variable. - ILExpression arg = inlinedExpression.Arguments[0]; - if (arg.Code == ILCode.CallGetter || arg.Code == ILCode.CallvirtGetter || arg.Code == ILCode.Call || arg.Code == ILCode.Callvirt) { - mr = (MethodReference)arg.Operand; - if (mr.Name == "get_Current" && mr.HasThis) - return false; // looks like a foreach loop variable, so don't inline it - } - break; - } - - // inline the compiler-generated variable that are used when accessing a member on a value type: - switch (parent.Code) { - case ILCode.Call: - case ILCode.CallGetter: - case ILCode.CallSetter: - case ILCode.Callvirt: - case ILCode.CallvirtGetter: - case ILCode.CallvirtSetter: - MethodReference mr = (MethodReference)parent.Operand; - return mr.HasThis; - case ILCode.Stfld: - case ILCode.Ldfld: - case ILCode.Ldflda: - case ILCode.Await: - return true; - } - } - return false; - } - - /// - /// Determines whether a variable should be inlined in non-aggressive mode, even though it is not a generated variable. - /// - /// The next top-level expression - /// The direct parent of the load within 'next' - /// The expression being inlined - bool NonAggressiveInlineInto(ILExpression next, ILExpression parent, ILExpression inlinedExpression) - { - if (inlinedExpression.Code == ILCode.DefaultValue) - return true; - - switch (next.Code) { - case ILCode.Ret: - case ILCode.Brtrue: - return parent == next; - case ILCode.Switch: - return parent == next || (parent.Code == ILCode.Sub && parent == next.Arguments[0]); - default: - return false; - } - } - - /// - /// Gets whether 'expressionBeingMoved' can be inlined into 'expr'. - /// - public bool CanInlineInto(ILExpression expr, ILVariable v, ILExpression expressionBeingMoved) - { - ILExpression parent; - int pos; - return FindLoadInNext(expr, v, expressionBeingMoved, out parent, out pos) == true; - } - - /// - /// Finds the position to inline to. - /// - /// true = found; false = cannot continue search; null = not found - bool? FindLoadInNext(ILExpression expr, ILVariable v, ILExpression expressionBeingMoved, out ILExpression parent, out int pos) - { - parent = null; - pos = 0; - if (expr == null) - return false; - for (int i = 0; i < expr.Arguments.Count; i++) { - // Stop when seeing an opcode that does not guarantee that its operands will be evaluated. - // Inlining in that case might result in the inlined expresion not being evaluted. - if (i == 1 && (expr.Code == ILCode.LogicAnd || expr.Code == ILCode.LogicOr || expr.Code == ILCode.TernaryOp || expr.Code == ILCode.NullCoalescing)) - return false; - - ILExpression arg = expr.Arguments[i]; - - if ((arg.Code == ILCode.Ldloc || arg.Code == ILCode.Ldloca) && arg.Operand == v) { - parent = expr; - pos = i; - return true; - } - bool? r = FindLoadInNext(arg, v, expressionBeingMoved, out parent, out pos); - if (r != null) - return r; - } - if (IsSafeForInlineOver(expr, expressionBeingMoved)) - return null; // continue searching - else - return false; // abort, inlining not possible - } - - /// - /// Determines whether it is safe to move 'expressionBeingMoved' past 'expr' - /// - bool IsSafeForInlineOver(ILExpression expr, ILExpression expressionBeingMoved) - { - switch (expr.Code) { - case ILCode.Ldloc: - ILVariable loadedVar = (ILVariable)expr.Operand; - if (numLdloca.GetOrDefault(loadedVar) != 0) { - // abort, inlining is not possible - return false; - } - foreach (ILExpression potentialStore in expressionBeingMoved.GetSelfAndChildrenRecursive()) { - if (potentialStore.Code == ILCode.Stloc && potentialStore.Operand == loadedVar) - return false; - } - // the expression is loading a non-forbidden variable - return true; - case ILCode.Ldloca: - case ILCode.Ldflda: - case ILCode.Ldsflda: - case ILCode.Ldelema: - case ILCode.AddressOf: - case ILCode.ValueOf: - case ILCode.NullableOf: - // address-loading instructions are safe if their arguments are safe - foreach (ILExpression arg in expr.Arguments) { - if (!IsSafeForInlineOver(arg, expressionBeingMoved)) - return false; - } - return true; - default: - // instructions with no side-effects are safe (except for Ldloc and Ldloca which are handled separately) - return expr.HasNoSideEffects(); - } - } - - /// - /// Runs a very simple form of copy propagation. - /// Copy propagation is used in two cases: - /// 1) assignments from arguments to local variables - /// If the target variable is assigned to only once (so always is that argument) and the argument is never changed (no ldarga/starg), - /// then we can replace the variable with the argument. - /// 2) assignments of address-loading instructions to local variables - /// - public void CopyPropagation() - { - foreach (ILBlock block in method.GetSelfAndChildrenRecursive()) { - for (int i = 0; i < block.Body.Count; i++) { - ILVariable v; - ILExpression copiedExpr; - if (block.Body[i].Match(ILCode.Stloc, out v, out copiedExpr) - && !v.IsParameter && numStloc.GetOrDefault(v) == 1 && numLdloca.GetOrDefault(v) == 0 - && CanPerformCopyPropagation(copiedExpr, v)) - { - // un-inline the arguments of the ldArg instruction - ILVariable[] uninlinedArgs = new ILVariable[copiedExpr.Arguments.Count]; - for (int j = 0; j < uninlinedArgs.Length; j++) { - uninlinedArgs[j] = new ILVariable { IsGenerated = true, Name = v.Name + "_cp_" + j }; - block.Body.Insert(i++, new ILExpression(ILCode.Stloc, uninlinedArgs[j], copiedExpr.Arguments[j])); - } - - // perform copy propagation: - foreach (var expr in method.GetSelfAndChildrenRecursive()) { - if (expr.Code == ILCode.Ldloc && expr.Operand == v) { - expr.Code = copiedExpr.Code; - expr.Operand = copiedExpr.Operand; - for (int j = 0; j < uninlinedArgs.Length; j++) { - expr.Arguments.Add(new ILExpression(ILCode.Ldloc, uninlinedArgs[j])); - } - } - } - - block.Body.RemoveAt(i); - if (uninlinedArgs.Length > 0) { - // if we un-inlined stuff; we need to update the usage counters - AnalyzeMethod(); - } - InlineInto(block.Body, i, aggressive: false); // maybe inlining gets possible after the removal of block.Body[i] - i -= uninlinedArgs.Length + 1; - } - } - } - } - - bool CanPerformCopyPropagation(ILExpression expr, ILVariable copyVariable) - { - switch (expr.Code) { - case ILCode.Ldloca: - case ILCode.Ldelema: - case ILCode.Ldflda: - case ILCode.Ldsflda: - // All address-loading instructions always return the same value for a given operand/argument combination, - // so they can be safely copied. - return true; - case ILCode.Ldloc: - ILVariable v = (ILVariable)expr.Operand; - if (v.IsParameter) { - // Parameters can be copied only if they aren't assigned to (directly or indirectly via ldarga) - return numLdloca.GetOrDefault(v) == 0 && numStloc.GetOrDefault(v) == 0; - } else { - // Variables are be copied only if both they and the target copy variable are generated, - // and if the variable has only a single assignment - return v.IsGenerated && copyVariable.IsGenerated && numLdloca.GetOrDefault(v) == 0 && numStloc.GetOrDefault(v) == 1; - } - default: - return false; - } - } - } -} diff --git a/ICSharpCode.Decompiler/ILAst/InitializerPeepholeTransforms.cs b/ICSharpCode.Decompiler/ILAst/InitializerPeepholeTransforms.cs deleted file mode 100644 index 4fb248de..00000000 --- a/ICSharpCode.Decompiler/ILAst/InitializerPeepholeTransforms.cs +++ /dev/null @@ -1,535 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using Mono.Cecil; - -namespace ICSharpCode.Decompiler.ILAst -{ - /// - /// IL AST transformation that introduces array, object and collection initializers. - /// - partial class ILAstOptimizer - { - #region Array Initializers - bool TransformArrayInitializers(List body, ILExpression expr, int pos) - { - ILVariable v, v3; - ILExpression newarrExpr; - TypeReference elementType; - ILExpression lengthExpr; - int arrayLength; - if (expr.Match(ILCode.Stloc, out v, out newarrExpr) && - newarrExpr.Match(ILCode.Newarr, out elementType, out lengthExpr) && - lengthExpr.Match(ILCode.Ldc_I4, out arrayLength) && - arrayLength > 0) { - ILExpression[] newArr; - int initArrayPos; - if (ForwardScanInitializeArrayRuntimeHelper(body, pos + 1, v, elementType, arrayLength, out newArr, out initArrayPos)) { - var arrayType = new ArrayType(elementType, 1); - arrayType.Dimensions[0] = new ArrayDimension(0, arrayLength); - body[pos] = new ILExpression(ILCode.Stloc, v, new ILExpression(ILCode.InitArray, arrayType, newArr)); - body.RemoveAt(initArrayPos); - } - // Put in a limit so that we don't consume too much memory if the code allocates a huge array - // and populates it extremely sparsly. However, 255 "null" elements in a row actually occur in the Mono C# compiler! - const int maxConsecutiveDefaultValueExpressions = 300; - List operands = new List(); - int numberOfInstructionsToRemove = 0; - for (int j = pos + 1; j < body.Count; j++) { - ILExpression nextExpr = body[j] as ILExpression; - int arrayPos; - if (nextExpr != null && - nextExpr.Code.IsStoreToArray() && - nextExpr.Arguments[0].Match(ILCode.Ldloc, out v3) && - v == v3 && - nextExpr.Arguments[1].Match(ILCode.Ldc_I4, out arrayPos) && - arrayPos >= operands.Count && - arrayPos <= operands.Count + maxConsecutiveDefaultValueExpressions && - !nextExpr.Arguments[2].ContainsReferenceTo(v3)) - { - while (operands.Count < arrayPos) - operands.Add(new ILExpression(ILCode.DefaultValue, elementType)); - operands.Add(nextExpr.Arguments[2]); - numberOfInstructionsToRemove++; - } else { - break; - } - } - if (operands.Count == arrayLength) { - var arrayType = new ArrayType(elementType, 1); - arrayType.Dimensions[0] = new ArrayDimension(0, arrayLength); - expr.Arguments[0] = new ILExpression(ILCode.InitArray, arrayType, operands); - body.RemoveRange(pos + 1, numberOfInstructionsToRemove); - - new ILInlining(method).InlineIfPossible(body, ref pos); - return true; - } - } - return false; - } - - bool TransformMultidimensionalArrayInitializers(List body, ILExpression expr, int pos) - { - ILVariable v; - ILExpression newarrExpr; - MethodReference ctor; - List ctorArgs; - ArrayType arrayType; - if (expr.Match(ILCode.Stloc, out v, out newarrExpr) && - newarrExpr.Match(ILCode.Newobj, out ctor, out ctorArgs) && - (arrayType = (ctor.DeclaringType as ArrayType)) != null && - arrayType.Rank == ctorArgs.Count) { - // Clone the type, so we can muck about with the Dimensions - arrayType = new ArrayType(arrayType.ElementType, arrayType.Rank); - var arrayLengths = new int[arrayType.Rank]; - for (int i = 0; i < arrayType.Rank; i++) { - if (!ctorArgs[i].Match(ILCode.Ldc_I4, out arrayLengths[i])) return false; - if (arrayLengths[i] <= 0) return false; - arrayType.Dimensions[i] = new ArrayDimension(0, arrayLengths[i]); - } - - var totalElements = arrayLengths.Aggregate(1, (t, l) => t * l); - ILExpression[] newArr; - int initArrayPos; - if (ForwardScanInitializeArrayRuntimeHelper(body, pos + 1, v, arrayType, totalElements, out newArr, out initArrayPos)) { - body[pos] = new ILExpression(ILCode.Stloc, v, new ILExpression(ILCode.InitArray, arrayType, newArr)); - body.RemoveAt(initArrayPos); - return true; - } - } - return false; - } - - bool ForwardScanInitializeArrayRuntimeHelper(List body, int pos, ILVariable array, TypeReference arrayType, int arrayLength, out ILExpression[] values, out int foundPos) - { - ILVariable v2; - MethodReference methodRef; - ILExpression methodArg1; - ILExpression methodArg2; - FieldReference fieldRef; - if (body.ElementAtOrDefault(pos).Match(ILCode.Call, out methodRef, out methodArg1, out methodArg2) && - methodRef.DeclaringType.FullName == "System.Runtime.CompilerServices.RuntimeHelpers" && - methodRef.Name == "InitializeArray" && - methodArg1.Match(ILCode.Ldloc, out v2) && - array == v2 && - methodArg2.Match(ILCode.Ldtoken, out fieldRef)) - { - FieldDefinition fieldDef = fieldRef.ResolveWithinSameModule(); - if (fieldDef != null && fieldDef.InitialValue != null) { - ILExpression[] newArr = new ILExpression[arrayLength]; - if (DecodeArrayInitializer(arrayType.GetElementType(), fieldDef.InitialValue, newArr)) - { - values = newArr; - foundPos = pos; - return true; - } - } - } - values = null; - foundPos = -1; - return false; - } - - static bool DecodeArrayInitializer(TypeReference elementTypeRef, byte[] initialValue, ILExpression[] output) - { - TypeCode elementType = TypeAnalysis.GetTypeCode(elementTypeRef); - switch (elementType) { - case TypeCode.Boolean: - case TypeCode.Byte: - return DecodeArrayInitializer(initialValue, output, elementType, (d, i) => (int)d[i]); - case TypeCode.SByte: - return DecodeArrayInitializer(initialValue, output, elementType, (d, i) => (int)unchecked((sbyte)d[i])); - case TypeCode.Int16: - return DecodeArrayInitializer(initialValue, output, elementType, (d, i) => (int)BitConverter.ToInt16(d, i)); - case TypeCode.Char: - case TypeCode.UInt16: - return DecodeArrayInitializer(initialValue, output, elementType, (d, i) => (int)BitConverter.ToUInt16(d, i)); - case TypeCode.Int32: - case TypeCode.UInt32: - return DecodeArrayInitializer(initialValue, output, elementType, BitConverter.ToInt32); - case TypeCode.Int64: - case TypeCode.UInt64: - return DecodeArrayInitializer(initialValue, output, elementType, BitConverter.ToInt64); - case TypeCode.Single: - return DecodeArrayInitializer(initialValue, output, elementType, BitConverter.ToSingle); - case TypeCode.Double: - return DecodeArrayInitializer(initialValue, output, elementType, BitConverter.ToDouble); - case TypeCode.Object: - var typeDef = elementTypeRef.ResolveWithinSameModule(); - if (typeDef != null && typeDef.IsEnum) - return DecodeArrayInitializer(typeDef.GetEnumUnderlyingType(), initialValue, output); - - return false; - default: - return false; - } - } - - static bool DecodeArrayInitializer(byte[] initialValue, ILExpression[] output, TypeCode elementType, Func decoder) - { - int elementSize = ElementSizeOf(elementType); - if (initialValue.Length < (output.Length * elementSize)) - return false; - - ILCode code = LoadCodeFor(elementType); - for (int i = 0; i < output.Length; i++) - output[i] = new ILExpression(code, decoder(initialValue, i * elementSize)); - - return true; - } - - static ILCode LoadCodeFor(TypeCode elementType) - { - switch (elementType) { - case TypeCode.Boolean: - case TypeCode.Byte: - case TypeCode.SByte: - case TypeCode.Char: - case TypeCode.Int16: - case TypeCode.UInt16: - case TypeCode.Int32: - case TypeCode.UInt32: - return ILCode.Ldc_I4; - case TypeCode.Int64: - case TypeCode.UInt64: - return ILCode.Ldc_I8; - case TypeCode.Single: - return ILCode.Ldc_R4; - case TypeCode.Double: - return ILCode.Ldc_R8; - default: - throw new ArgumentOutOfRangeException("elementType"); - } - } - - static int ElementSizeOf(TypeCode elementType) - { - switch (elementType) { - case TypeCode.Boolean: - case TypeCode.Byte: - case TypeCode.SByte: - return 1; - case TypeCode.Char: - case TypeCode.Int16: - case TypeCode.UInt16: - return 2; - case TypeCode.Int32: - case TypeCode.UInt32: - case TypeCode.Single: - return 4; - case TypeCode.Int64: - case TypeCode.UInt64: - case TypeCode.Double: - return 8; - default: - throw new ArgumentOutOfRangeException("elementType"); - } - } - #endregion - - /// - /// Handles both object and collection initializers. - /// - bool TransformObjectInitializers(List body, ILExpression expr, int pos) - { - if (!context.Settings.ObjectOrCollectionInitializers) - return false; - - Debug.Assert(body[pos] == expr); // should be called for top-level expressions only - ILVariable v; - ILExpression newObjExpr; - TypeReference newObjType; - bool isValueType; - MethodReference ctor; - List ctorArgs; - if (expr.Match(ILCode.Stloc, out v, out newObjExpr)) { - if (newObjExpr.Match(ILCode.Newobj, out ctor, out ctorArgs)) { - // v = newObj(ctor, ctorArgs) - newObjType = ctor.DeclaringType; - isValueType = false; - } else if (newObjExpr.Match(ILCode.DefaultValue, out newObjType)) { - // v = defaultvalue(type) - isValueType = true; - } else { - return false; - } - } else if (expr.Match(ILCode.Call, out ctor, out ctorArgs)) { - // call(SomeStruct::.ctor, ldloca(v), remainingArgs) - if (ctorArgs.Count > 0 && ctorArgs[0].Match(ILCode.Ldloca, out v)) { - isValueType = true; - newObjType = ctor.DeclaringType; - ctorArgs = new List(ctorArgs); - ctorArgs.RemoveAt(0); - newObjExpr = new ILExpression(ILCode.Newobj, ctor, ctorArgs); - } else { - return false; - } - } else { - return false; - } - if (newObjType.IsValueType != isValueType) - return false; - - int originalPos = pos; - - // don't use object initializer syntax for closures - if (Ast.Transforms.DelegateConstruction.IsPotentialClosure(context, newObjType.ResolveWithinSameModule())) - return false; - - ILExpression initializer = ParseObjectInitializer(body, ref pos, v, newObjExpr, IsCollectionType(newObjType), isValueType); - - if (initializer.Arguments.Count == 1) // only newobj argument, no initializer elements - return false; - int totalElementCount = pos - originalPos - 1; // totalElementCount: includes elements from nested collections - Debug.Assert(totalElementCount >= initializer.Arguments.Count - 1); - - // Verify that we can inline 'v' into the next instruction: - - if (pos >= body.Count) - return false; // reached end of block, but there should be another instruction which consumes the initialized object - - ILInlining inlining = new ILInlining(method); - if (isValueType) { - // one ldloc for the use of the initialized object - if (inlining.numLdloc.GetOrDefault(v) != 1) - return false; - // one ldloca for each initializer argument, and also for the ctor call (if it exists) - if (inlining.numLdloca.GetOrDefault(v) != totalElementCount + (expr.Code == ILCode.Call ? 1 : 0)) - return false; - // one stloc for the initial store (if no ctor call was used) - if (inlining.numStloc.GetOrDefault(v) != (expr.Code == ILCode.Call ? 0 : 1)) - return false; - } else { - // one ldloc for each initializer argument, and another ldloc for the use of the initialized object - if (inlining.numLdloc.GetOrDefault(v) != totalElementCount + 1) - return false; - if (!(inlining.numStloc.GetOrDefault(v) == 1 && inlining.numLdloca.GetOrDefault(v) == 0)) - return false; - } - ILExpression nextExpr = body[pos] as ILExpression; - if (!inlining.CanInlineInto(nextExpr, v, initializer)) - return false; - - if (expr.Code == ILCode.Stloc) { - expr.Arguments[0] = initializer; - } else { - Debug.Assert(expr.Code == ILCode.Call); - expr.Code = ILCode.Stloc; - expr.Operand = v; - expr.Arguments.Clear(); - expr.Arguments.Add(initializer); - } - // remove all the instructions that were pulled into the initializer - body.RemoveRange(originalPos + 1, pos - originalPos - 1); - - // now that we know that it's an object initializer, change all the first arguments to 'InitializedObject' - ChangeFirstArgumentToInitializedObject(initializer); - - inlining = new ILInlining(method); - inlining.InlineIfPossible(body, ref originalPos); - - return true; - } - - /// - /// Gets whether the type supports collection initializers. - /// - static bool IsCollectionType(TypeReference tr) - { - if (tr == null) - return false; - TypeDefinition td = tr.Resolve(); - while (td != null) { - if (td.Interfaces.Any(intf => intf.Name == "IEnumerable" && intf.Namespace == "System.Collections")) - return true; - td = td.BaseType != null ? td.BaseType.Resolve() : null; - } - return false; - } - - /// - /// Gets whether 'expr' represents a setter in an object initializer. - /// ('CallvirtSetter(Property, v, value)') - /// - static bool IsSetterInObjectInitializer(ILExpression expr) - { - if (expr == null) - return false; - if (expr.Code == ILCode.CallvirtSetter || expr.Code == ILCode.CallSetter || expr.Code == ILCode.Stfld) { - return expr.Arguments.Count == 2; - } - return false; - } - - /// - /// Gets whether 'expr' represents the invocation of an 'Add' method in a collection initializer. - /// - static bool IsAddMethodCall(ILExpression expr) - { - MethodReference addMethod; - List args; - if (expr.Match(ILCode.Callvirt, out addMethod, out args) || expr.Match(ILCode.Call, out addMethod, out args)) { - if (addMethod.Name == "Add" && addMethod.HasThis) { - return args.Count >= 2; - } - } - return false; - } - - /// - /// Parses an object initializer. - /// - ILExpression ParseObjectInitializer(List body, ref int pos, ILVariable v, ILExpression newObjExpr, bool isCollection, bool isValueType) - { - // Take care not to modify any existing ILExpressions in here. - // We just construct new ones around the old ones, any modifications must wait until the whole - // object/collection initializer was analyzed. - ILExpression objectInitializer = new ILExpression(isCollection ? ILCode.InitCollection : ILCode.InitObject, null, newObjExpr); - List initializerStack = new List(); - initializerStack.Add(objectInitializer); - while (++pos < body.Count) { - ILExpression nextExpr = body[pos] as ILExpression; - if (IsSetterInObjectInitializer(nextExpr)) { - if (!AdjustInitializerStack(initializerStack, nextExpr.Arguments[0], v, false, isValueType)) { - CleanupInitializerStackAfterFailedAdjustment(initializerStack); - break; - } - initializerStack[initializerStack.Count - 1].Arguments.Add(nextExpr); - } else if (IsAddMethodCall(nextExpr)) { - if (!AdjustInitializerStack(initializerStack, nextExpr.Arguments[0], v, true, isValueType)) { - CleanupInitializerStackAfterFailedAdjustment(initializerStack); - break; - } - initializerStack[initializerStack.Count - 1].Arguments.Add(nextExpr); - } else { - // can't match any more initializers: end of object initializer - break; - } - } - return objectInitializer; - } - - static bool AdjustInitializerStack(List initializerStack, ILExpression argument, ILVariable v, bool isCollection, bool isValueType) - { - // Argument is of the form 'getter(getter(...(v)))' - // Unpack it into a list of getters: - List getters = new List(); - while (argument.Code == ILCode.CallvirtGetter || argument.Code == ILCode.CallGetter || argument.Code == ILCode.Ldfld) { - getters.Add(argument); - if (argument.Arguments.Count != 1) - return false; - argument = argument.Arguments[0]; - } - // Ensure that the final argument is 'v' - if (isValueType) { - ILVariable loadedVar; - if (!(argument.Match(ILCode.Ldloca, out loadedVar) && loadedVar == v)) - return false; - } else { - if (!argument.MatchLdloc(v)) - return false; - } - // Now compare the getters with those that are currently active on the initializer stack: - int i; - for (i = 1; i <= Math.Min(getters.Count, initializerStack.Count - 1); i++) { - ILExpression g1 = initializerStack[i].Arguments[0]; // getter stored in initializer - ILExpression g2 = getters[getters.Count - i]; // matching getter from argument - if (g1.Operand != g2.Operand) { - // operands differ, so we abort the comparison - break; - } - } - // Remove all initializers from the stack that were not matched with one from the argument: - initializerStack.RemoveRange(i, initializerStack.Count - i); - // Now create new initializers for the remaining arguments: - for (; i <= getters.Count; i++) { - ILExpression g = getters[getters.Count - i]; - MemberReference mr = (MemberReference)g.Operand; - TypeReference returnType; - if (mr is FieldReference) - returnType = TypeAnalysis.GetFieldType((FieldReference)mr); - else - returnType = TypeAnalysis.SubstituteTypeArgs(((MethodReference)mr).ReturnType, mr); - - ILExpression nestedInitializer = new ILExpression( - IsCollectionType(returnType) ? ILCode.InitCollection : ILCode.InitObject, - null, g); - // add new initializer to its parent: - ILExpression parentInitializer = initializerStack[initializerStack.Count - 1]; - if (parentInitializer.Code == ILCode.InitCollection) { - // can't add children to collection initializer - if (parentInitializer.Arguments.Count == 1) { - // convert empty collection initializer to object initializer - parentInitializer.Code = ILCode.InitObject; - } else { - return false; - } - } - parentInitializer.Arguments.Add(nestedInitializer); - initializerStack.Add(nestedInitializer); - } - ILExpression lastInitializer = initializerStack[initializerStack.Count - 1]; - if (isCollection) { - return lastInitializer.Code == ILCode.InitCollection; - } else { - if (lastInitializer.Code == ILCode.InitCollection) { - if (lastInitializer.Arguments.Count == 1) { - // convert empty collection initializer to object initializer - lastInitializer.Code = ILCode.InitObject; - return true; - } else { - return false; - } - } else { - return true; - } - } - } - - static void CleanupInitializerStackAfterFailedAdjustment(List initializerStack) - { - // There might be empty nested initializers left over; so we'll remove those: - while (initializerStack.Count > 1 && initializerStack[initializerStack.Count - 1].Arguments.Count == 1) { - ILExpression parent = initializerStack[initializerStack.Count - 2]; - Debug.Assert(parent.Arguments.Last() == initializerStack[initializerStack.Count - 1]); - parent.Arguments.RemoveAt(parent.Arguments.Count - 1); - initializerStack.RemoveAt(initializerStack.Count - 1); - } - } - - static void ChangeFirstArgumentToInitializedObject(ILExpression initializer) - { - // Go through all elements in the initializer (so skip the newobj-instr. at the start) - for (int i = 1; i < initializer.Arguments.Count; i++) { - ILExpression element = initializer.Arguments[i]; - if (element.Code == ILCode.InitCollection || element.Code == ILCode.InitObject) { - // nested collection/object initializer - ILExpression getCollection = element.Arguments[0]; - getCollection.Arguments[0] = new ILExpression(ILCode.InitializedObject, null); - ChangeFirstArgumentToInitializedObject(element); // handle the collection elements - } else { - element.Arguments[0] = new ILExpression(ILCode.InitializedObject, null); - } - } - } - } -} diff --git a/ICSharpCode.Decompiler/ILAst/LiftedOperators.cs b/ICSharpCode.Decompiler/ILAst/LiftedOperators.cs deleted file mode 100644 index 9edeac74..00000000 --- a/ICSharpCode.Decompiler/ILAst/LiftedOperators.cs +++ /dev/null @@ -1,528 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Linq; - -using Mono.Cecil; - -namespace ICSharpCode.Decompiler.ILAst -{ - partial class ILAstOptimizer - { - bool SimplifyLiftedOperators(List body, ILExpression expr, int pos) - { - if (!new PatternMatcher(typeSystem).SimplifyLiftedOperators(expr)) return false; - - var inlining = new ILInlining(method); - while (--pos >= 0 && inlining.InlineIfPossible(body, ref pos)) ; - - return true; - } - - sealed class PatternMatcher - { - readonly TypeSystem typeSystem; - public PatternMatcher(TypeSystem typeSystem) - { - this.typeSystem = typeSystem; - } - - public bool SimplifyLiftedOperators(ILExpression expr) - { - if (Simplify(expr)) return true; - - bool modified = false; - foreach (var a in expr.Arguments) - modified |= SimplifyLiftedOperators(a); - return modified; - } - - abstract class Pattern - { - public readonly Pattern[] Arguments; - - protected Pattern(Pattern[] arguments) - { - Arguments = arguments; - } - - public virtual bool Match(PatternMatcher pm, ILExpression e) - { - if (e.Arguments.Count != Arguments.Length || e.Prefixes != null) return false; - for (int i = 0; i < Arguments.Length; i++) - if (!Arguments[i].Match(pm, e.Arguments[i])) return false; - return true; - } - - public virtual ILExpression BuildNew(PatternMatcher pm) - { - throw new NotSupportedException(); - } - - public static Pattern operator &(Pattern a, Pattern b) - { - return new ILPattern(ILCode.LogicAnd, a, b); - } - - public static Pattern operator |(Pattern a, Pattern b) - { - return new ILPattern(ILCode.LogicOr, a, b); - } - - public static Pattern operator !(Pattern a) - { - return new ILPattern(ILCode.LogicNot, a); - } - } - - sealed class ILPattern : Pattern - { - readonly ILCode code; - - public ILPattern(ILCode code, params Pattern[] arguments) - : base(arguments) - { - this.code = code; - } - - public override bool Match(PatternMatcher pm, ILExpression e) - { - return e.Code == code && base.Match(pm, e); - } - - public override ILExpression BuildNew(PatternMatcher pm) - { - var args = new ILExpression[Arguments.Length]; - for (int i = 0; i < args.Length; i++) args[i] = Arguments[i].BuildNew(pm); - TypeReference t = null; - switch (code) { - case ILCode.Ceq: - case ILCode.Cne: - t = pm.typeSystem.Boolean; - break; - case ILCode.NullCoalescing: - t = args[1].InferredType; - break; - } - return new ILExpression(code, null, args) { InferredType = t }; - } - } - - sealed class MethodPattern : Pattern - { - readonly ILCode code; - readonly string method; - - public MethodPattern(ILCode code, string method, params Pattern[] arguments) - : base(arguments) - { - this.code = code; - this.method = method; - } - - public override bool Match(PatternMatcher pm, ILExpression e) - { - if (e.Code != code) return false; - var m = (MethodReference)e.Operand; - return m.Name == method && TypeAnalysis.IsNullableType(m.DeclaringType) && base.Match(pm, e); - } - } - - enum OperatorType - { - Equality, InEquality, Comparison, Other - } - - sealed class OperatorPattern : Pattern - { - OperatorType type; - bool simple; - - public OperatorPattern() : base(null) { } - - public OperatorPattern(OperatorType type, bool simple) - : this() - { - this.type = type; - this.simple = simple; - } - - public override bool Match(PatternMatcher pm, ILExpression e) - { - switch (e.Code) { - case ILCode.Ceq: - if (type != OperatorType.Equality) return false; - break; - case ILCode.Cne: - if (type != OperatorType.InEquality) return false; - break; - case ILCode.Cgt: - case ILCode.Cgt_Un: - case ILCode.Cge: - case ILCode.Cge_Un: - case ILCode.Clt: - case ILCode.Clt_Un: - case ILCode.Cle: - case ILCode.Cle_Un: - if (type != OperatorType.Comparison) return false; - break; - case ILCode.Add: - case ILCode.Add_Ovf: - case ILCode.Add_Ovf_Un: - case ILCode.Sub: - case ILCode.Sub_Ovf: - case ILCode.Sub_Ovf_Un: - case ILCode.Mul: - case ILCode.Mul_Ovf: - case ILCode.Mul_Ovf_Un: - case ILCode.Div: - case ILCode.Div_Un: - case ILCode.Rem: - case ILCode.Rem_Un: - case ILCode.And: - case ILCode.Or: - case ILCode.Xor: - case ILCode.Shl: - case ILCode.Shr: - case ILCode.Shr_Un: - case ILCode.Not: - case ILCode.Neg: - case ILCode.LogicNot: - if (type != OperatorType.Other) return false; - break; - case ILCode.Call: - var m = e.Operand as MethodReference; - if (m == null || m.HasThis || !m.HasParameters || e.Arguments.Count > 2 || !IsCustomOperator(m.Name)) return false; - break; - default: return false; - } - if (pm.Operator != null) throw new InvalidOperationException(); - pm.Operator = e; - - var a0 = e.Arguments[0]; - if (!simple) return VariableAGetValueOrDefault.Match(pm, a0) && VariableBGetValueOrDefault.Match(pm, e.Arguments[1]); - if (e.Arguments.Count == 1) return VariableAGetValueOrDefault.Match(pm, a0); - if (VariableAGetValueOrDefault.Match(pm, a0)) { - pm.SimpleOperand = e.Arguments[1]; - pm.SimpleLeftOperand = false; - return true; - } - if (VariableAGetValueOrDefault.Match(pm, e.Arguments[1])) { - pm.SimpleOperand = a0; - pm.SimpleLeftOperand = true; - return true; - } - return false; - } - - bool IsCustomOperator(string s) - { - switch (type) { - case OperatorType.Equality: return s == "op_Equality"; - case OperatorType.InEquality: return s == "op_Inequality"; - case OperatorType.Comparison: - if (s.Length < 11 || !s.StartsWith("op_", StringComparison.Ordinal)) return false; - switch (s) { - case "op_GreaterThan": - case "op_GreaterThanOrEqual": - case "op_LessThan": - case "op_LessThanOrEqual": return true; - default: return false; - } - default: - if (s.Length < 10 || !s.StartsWith("op_", StringComparison.Ordinal)) return false; - switch (s) { - case "op_Addition": - case "op_Subtraction": - case "op_Multiply": - case "op_Division": - case "op_Modulus": - case "op_BitwiseAnd": - case "op_BitwiseOr": - case "op_ExclusiveOr": - case "op_LeftShift": - case "op_RightShift": - case "op_UnaryNegation": - case "op_UnaryPlus": - case "op_LogicalNot": - case "op_OnesComplement": - case "op_Increment": - case "op_Decrement": return true; - default: return false; - } - } - } - - public override ILExpression BuildNew(PatternMatcher pm) - { - var res = pm.Operator; - res.Arguments.Clear(); - if (pm.SimpleLeftOperand) res.Arguments.Add(pm.SimpleOperand); - res.Arguments.Add(VariableA.BuildNew(pm)); - if (pm.B != null) res.Arguments.Add(VariableB.BuildNew(pm)); - else if (pm.SimpleOperand != null && !pm.SimpleLeftOperand) res.Arguments.Add(pm.SimpleOperand); - return res; - } - } - - sealed class AnyPattern : Pattern - { - public AnyPattern() : base(null) { } - - public override bool Match(PatternMatcher pm, ILExpression e) - { - if (pm.SimpleOperand != null) throw new InvalidOperationException(); - pm.SimpleOperand = e; - return true; - } - - public override ILExpression BuildNew(PatternMatcher pm) - { - return pm.SimpleOperand; - } - } - - sealed class VariablePattern : Pattern - { - readonly ILCode code; - readonly bool b; - - public VariablePattern(ILCode code, bool b) - : base(null) - { - this.code = code; - this.b = b; - } - - public override bool Match(PatternMatcher pm, ILExpression e) - { - if (e.Code != code) return false; - var v = e.Operand as ILVariable; - return v != null && (b ? Capture(ref pm.B, v) : Capture(ref pm.A, v)); - } - - static bool Capture(ref ILVariable pmvar, ILVariable v) - { - if (pmvar != null) return pmvar == v; - pmvar = v; - return true; - } - - static readonly ILExpression[] EmptyArguments = new ILExpression[0]; - public override ILExpression BuildNew(PatternMatcher pm) - { - var v = b ? pm.B : pm.A; - var e = new ILExpression(ILCode.Ldloc, v, EmptyArguments); - if (TypeAnalysis.IsNullableType(v.Type)) e = new ILExpression(ILCode.ValueOf, null, e); - return e; - } - } - - sealed class BooleanPattern : Pattern - { - public static readonly Pattern False = new BooleanPattern(false), True = new BooleanPattern(true); - - readonly object value; - BooleanPattern(bool value) - : base(null) - { - this.value = Convert.ToInt32(value); - } - - public override bool Match(PatternMatcher pm, ILExpression e) - { - return e.Code == ILCode.Ldc_I4 && TypeAnalysis.IsBoolean(e.InferredType) && Equals(e.Operand, value); - } - - public override ILExpression BuildNew(PatternMatcher pm) - { - // boolean constants are wrapped inside a container to disable simplyfication of equality comparisons - return new ILExpression(ILCode.Wrap, null, new ILExpression(ILCode.Ldc_I4, value)); - } - } - - static readonly Pattern VariableRefA = new VariablePattern(ILCode.Ldloca, false), VariableRefB = new VariablePattern(ILCode.Ldloca, true); - static readonly Pattern VariableA = new VariablePattern(ILCode.Ldloc, false), VariableB = new VariablePattern(ILCode.Ldloc, true); - static readonly Pattern VariableAHasValue = new MethodPattern(ILCode.CallGetter, "get_HasValue", VariableRefA); - static readonly Pattern VariableAGetValueOrDefault = new MethodPattern(ILCode.Call, "GetValueOrDefault", VariableRefA); - static readonly Pattern VariableBHasValue = new MethodPattern(ILCode.CallGetter, "get_HasValue", VariableRefB); - static readonly Pattern VariableBGetValueOrDefault = new MethodPattern(ILCode.Call, "GetValueOrDefault", VariableRefB); - static readonly Pattern CeqHasValue = new ILPattern(ILCode.Ceq, VariableAHasValue, VariableBHasValue); - static readonly Pattern CneHasValue = new ILPattern(ILCode.Cne, VariableAHasValue, VariableBHasValue); - static readonly Pattern AndHasValue = new ILPattern(ILCode.And, VariableAHasValue, VariableBHasValue); - static readonly Pattern Any = new AnyPattern(); - static readonly Pattern OperatorVariableAB = new OperatorPattern(); - - static OperatorPattern OperatorNN(OperatorType type) - { - return new OperatorPattern(type, false); - } - - static OperatorPattern OperatorNV(OperatorType type) - { - return new OperatorPattern(type, true); - } - - static Pattern NewObj(Pattern p) - { - return new MethodPattern(ILCode.Newobj, ".ctor", p); - } - - static readonly Pattern[] Comparisons = new Pattern[] { - /* both operands nullable */ - // == (primitive, decimal) - OperatorNN(OperatorType.Equality) & CeqHasValue, - // == (struct) - CeqHasValue & (!VariableAHasValue | OperatorNN(OperatorType.Equality)), - // != (primitive, decimal) - OperatorNN(OperatorType.InEquality) | CneHasValue, - // != (struct) - CneHasValue | (VariableAHasValue & OperatorNN(OperatorType.InEquality)), - // > , < , >= , <= (primitive, decimal) - OperatorNN(OperatorType.Comparison) & AndHasValue, - // > , < , >= , <= (struct) - AndHasValue & OperatorNN(OperatorType.Comparison), - - /* only one operand nullable */ - // == (primitive, decimal) - OperatorNV(OperatorType.Equality) & VariableAHasValue, - // == (struct) - VariableAHasValue & OperatorNV(OperatorType.Equality), - // != (primitive, decimal) - OperatorNV(OperatorType.InEquality) | !VariableAHasValue, - // != (struct) - !VariableAHasValue | OperatorNV(OperatorType.InEquality), - // > , <, >= , <= (primitive, decimal) - OperatorNV(OperatorType.Comparison) & VariableAHasValue, - // > , < , >= , <= (struct) - VariableAHasValue & OperatorNV(OperatorType.Comparison), - }; - - static readonly Pattern[] Other = new Pattern[] { - /* both operands nullable */ - // & (bool) - new ILPattern(ILCode.TernaryOp, VariableAGetValueOrDefault | (!VariableBGetValueOrDefault & !VariableAHasValue), VariableB, VariableA), - new ILPattern(ILCode.And, VariableA, VariableB), - // | (bool) - new ILPattern(ILCode.TernaryOp, VariableAGetValueOrDefault | (!VariableBGetValueOrDefault & !VariableAHasValue), VariableA, VariableB), - new ILPattern(ILCode.Or, VariableA, VariableB), - // null coalescing - new ILPattern(ILCode.TernaryOp, VariableAHasValue, NewObj(VariableAGetValueOrDefault), VariableB), - new ILPattern(ILCode.NullCoalescing, VariableA, VariableB), - // all other - new ILPattern(ILCode.TernaryOp, AndHasValue, NewObj(OperatorNN(OperatorType.Other)), new ILPattern(ILCode.DefaultValue)), - OperatorVariableAB, - - /* only one operand nullable */ - // & (bool) - new ILPattern(ILCode.TernaryOp, Any, VariableA, NewObj(BooleanPattern.False)), - new ILPattern(ILCode.And, VariableA, Any), - // | (bool) - new ILPattern(ILCode.TernaryOp, Any, NewObj(BooleanPattern.True), VariableA), - new ILPattern(ILCode.Or, VariableA, Any), - // == true - VariableAGetValueOrDefault & VariableAHasValue, - new ILPattern(ILCode.Ceq, VariableA, BooleanPattern.True), - // != true - !VariableAGetValueOrDefault | !VariableAHasValue, - new ILPattern(ILCode.Cne, VariableA, BooleanPattern.True), - // == false - !VariableAGetValueOrDefault & VariableAHasValue, - new ILPattern(ILCode.Ceq, VariableA, BooleanPattern.False), - // != false - VariableAGetValueOrDefault | !VariableAHasValue, - new ILPattern(ILCode.Cne, VariableA, BooleanPattern.False), - // ?? true - !VariableAHasValue | VariableAGetValueOrDefault, - new ILPattern(ILCode.NullCoalescing, VariableA, BooleanPattern.True), - // ?? false - VariableAHasValue & VariableAGetValueOrDefault, - new ILPattern(ILCode.NullCoalescing, VariableA, BooleanPattern.False), - // null coalescing - new ILPattern(ILCode.TernaryOp, VariableAHasValue, VariableAGetValueOrDefault, Any), - new ILPattern(ILCode.NullCoalescing, VariableA, Any), - // all other - new ILPattern(ILCode.TernaryOp, VariableAHasValue, NewObj(OperatorNV(OperatorType.Other)), new ILPattern(ILCode.DefaultValue)), - OperatorVariableAB, - }; - - ILVariable A, B; - ILExpression Operator, SimpleOperand; - bool SimpleLeftOperand; - - void Reset() - { - A = null; - B = null; - Operator = null; - SimpleOperand = null; - SimpleLeftOperand = false; - } - - bool Simplify(ILExpression expr) - { - if (expr.Code == ILCode.TernaryOp || expr.Code == ILCode.LogicAnd || expr.Code == ILCode.LogicOr) { - Pattern[] ps; - if (expr.Code != ILCode.TernaryOp) { - ps = Comparisons; - for (int i = 0; i < ps.Length; i++) { - Reset(); - if (!ps[i].Match(this, expr)) continue; - SetResult(expr, OperatorVariableAB.BuildNew(this)); - return true; - } - } - ps = Other; - for (int i = 0; i < ps.Length; i += 2) { - Reset(); - if (!ps[i].Match(this, expr)) continue; - var n = ps[i + 1].BuildNew(this); - SetResult(expr, n); - if (n.Code == ILCode.NullCoalescing) { - // if both operands are nullable then the result is also nullable - if (n.Arguments[1].Code == ILCode.ValueOf) { - n.Arguments[0] = n.Arguments[0].Arguments[0]; - n.Arguments[1] = n.Arguments[1].Arguments[0]; - } - } else if (n.Code != ILCode.Ceq && n.Code != ILCode.Cne) { - expr.Code = ILCode.NullableOf; - expr.InferredType = expr.ExpectedType = null; - } - return true; - } - } - return false; - } - - static void SetResult(ILExpression expr, ILExpression n) - { - // IL ranges from removed nodes are assigned to the new operator expression - var removednodes = expr.GetSelfAndChildrenRecursive().Except(n.GetSelfAndChildrenRecursive()); - n.ILRanges.AddRange(removednodes.SelectMany(el => el.ILRanges)); - // the new expression is wrapped in a container so that negations aren't pushed through lifted comparison operations - expr.Code = ILCode.Wrap; - expr.Arguments.Clear(); - expr.Arguments.Add(n); - expr.ILRanges.Clear(); - expr.InferredType = n.InferredType; - } - } - } -} diff --git a/ICSharpCode.Decompiler/ILAst/LoopsAndConditions.cs b/ICSharpCode.Decompiler/ILAst/LoopsAndConditions.cs deleted file mode 100644 index 32095b03..00000000 --- a/ICSharpCode.Decompiler/ILAst/LoopsAndConditions.cs +++ /dev/null @@ -1,443 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Linq; - -using ICSharpCode.Decompiler.FlowAnalysis; - -namespace ICSharpCode.Decompiler.ILAst -{ - /// - /// Description of LoopsAndConditions. - /// - public class LoopsAndConditions - { - Dictionary labelToCfNode = new Dictionary(); - - readonly DecompilerContext context; - - uint nextLabelIndex = 0; - - public LoopsAndConditions(DecompilerContext context) - { - this.context = context; - } - - public void FindLoops(ILBlock block) - { - if (block.Body.Count > 0) { - ControlFlowGraph graph; - graph = BuildGraph(block.Body, (ILLabel)block.EntryGoto.Operand); - graph.ComputeDominance(context.CancellationToken); - graph.ComputeDominanceFrontier(); - block.Body = FindLoops(new HashSet(graph.Nodes.Skip(3)), graph.EntryPoint, false); - } - } - - public void FindConditions(ILBlock block) - { - if (block.Body.Count > 0) { - ControlFlowGraph graph; - graph = BuildGraph(block.Body, (ILLabel)block.EntryGoto.Operand); - graph.ComputeDominance(context.CancellationToken); - graph.ComputeDominanceFrontier(); - block.Body = FindConditions(new HashSet(graph.Nodes.Skip(3)), graph.EntryPoint); - } - } - - ControlFlowGraph BuildGraph(List nodes, ILLabel entryLabel) - { - int index = 0; - List cfNodes = new List(); - ControlFlowNode entryPoint = new ControlFlowNode(index++, 0, ControlFlowNodeType.EntryPoint); - cfNodes.Add(entryPoint); - ControlFlowNode regularExit = new ControlFlowNode(index++, -1, ControlFlowNodeType.RegularExit); - cfNodes.Add(regularExit); - ControlFlowNode exceptionalExit = new ControlFlowNode(index++, -1, ControlFlowNodeType.ExceptionalExit); - cfNodes.Add(exceptionalExit); - - // Create graph nodes - labelToCfNode = new Dictionary(); - Dictionary astNodeToCfNode = new Dictionary(); - foreach(ILBasicBlock node in nodes) { - ControlFlowNode cfNode = new ControlFlowNode(index++, -1, ControlFlowNodeType.Normal); - cfNodes.Add(cfNode); - astNodeToCfNode[node] = cfNode; - cfNode.UserData = node; - - // Find all contained labels - foreach(ILLabel label in node.GetSelfAndChildrenRecursive()) { - labelToCfNode[label] = cfNode; - } - } - - // Entry endge - ControlFlowNode entryNode = labelToCfNode[entryLabel]; - ControlFlowEdge entryEdge = new ControlFlowEdge(entryPoint, entryNode, JumpType.Normal); - entryPoint.Outgoing.Add(entryEdge); - entryNode.Incoming.Add(entryEdge); - - // Create edges - foreach(ILBasicBlock node in nodes) { - ControlFlowNode source = astNodeToCfNode[node]; - - // Find all branches - foreach(ILLabel target in node.GetSelfAndChildrenRecursive(e => e.IsBranch()).SelectMany(e => e.GetBranchTargets())) { - ControlFlowNode destination; - // Labels which are out of out scope will not be in the collection - // Insert self edge only if we are sure we are a loop - if (labelToCfNode.TryGetValue(target, out destination) && (destination != source || target == node.Body.FirstOrDefault())) { - ControlFlowEdge edge = new ControlFlowEdge(source, destination, JumpType.Normal); - source.Outgoing.Add(edge); - destination.Incoming.Add(edge); - } - } - } - - return new ControlFlowGraph(cfNodes.ToArray()); - } - - List FindLoops(HashSet scope, ControlFlowNode entryPoint, bool excludeEntryPoint) - { - List result = new List(); - - // Do not modify entry data - scope = new HashSet(scope); - - Queue agenda = new Queue(); - agenda.Enqueue(entryPoint); - while(agenda.Count > 0) { - ControlFlowNode node = agenda.Dequeue(); - - // If the node is a loop header - if (scope.Contains(node) - && node.DominanceFrontier.Contains(node) - && (node != entryPoint || !excludeEntryPoint)) - { - HashSet loopContents = FindLoopContent(scope, node); - - // If the first expression is a loop condition - ILBasicBlock basicBlock = (ILBasicBlock)node.UserData; - ILExpression condExpr; - ILLabel trueLabel; - ILLabel falseLabel; - // It has to be just brtrue - any preceding code would introduce goto - if(basicBlock.MatchSingleAndBr(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel)) - { - ControlFlowNode trueTarget; - labelToCfNode.TryGetValue(trueLabel, out trueTarget); - ControlFlowNode falseTarget; - labelToCfNode.TryGetValue(falseLabel, out falseTarget); - - // If one point inside the loop and the other outside - if ((!loopContents.Contains(trueTarget) && loopContents.Contains(falseTarget)) || - (loopContents.Contains(trueTarget) && !loopContents.Contains(falseTarget)) ) - { - loopContents.RemoveOrThrow(node); - scope.RemoveOrThrow(node); - - // If false means enter the loop - if (loopContents.Contains(falseTarget) || falseTarget == node) - { - // Negate the condition - condExpr = new ILExpression(ILCode.LogicNot, null, condExpr); - ILLabel tmp = trueLabel; - trueLabel = falseLabel; - falseLabel = tmp; - } - - ControlFlowNode postLoopTarget; - labelToCfNode.TryGetValue(falseLabel, out postLoopTarget); - if (postLoopTarget != null) { - // Pull more nodes into the loop - HashSet postLoopContents = FindDominatedNodes(scope, postLoopTarget); - var pullIn = scope.Except(postLoopContents).Where(n => node.Dominates(n)); - loopContents.UnionWith(pullIn); - } - - // Use loop to implement the brtrue - basicBlock.Body.RemoveTail(ILCode.Brtrue, ILCode.Br); - basicBlock.Body.Add(new ILWhileLoop() { - Condition = condExpr, - BodyBlock = new ILBlock() { - EntryGoto = new ILExpression(ILCode.Br, trueLabel), - Body = FindLoops(loopContents, node, false) - } - }); - basicBlock.Body.Add(new ILExpression(ILCode.Br, falseLabel)); - result.Add(basicBlock); - - scope.ExceptWith(loopContents); - } - } - - // Fallback method: while(true) - if (scope.Contains(node)) { - result.Add(new ILBasicBlock() { - Body = new List() { - new ILLabel() { Name = "Loop_" + (nextLabelIndex++) }, - new ILWhileLoop() { - BodyBlock = new ILBlock() { - EntryGoto = new ILExpression(ILCode.Br, (ILLabel)basicBlock.Body.First()), - Body = FindLoops(loopContents, node, true) - } - }, - }, - }); - - scope.ExceptWith(loopContents); - } - } - - // Using the dominator tree should ensure we find the the widest loop first - foreach(var child in node.DominatorTreeChildren) { - agenda.Enqueue(child); - } - } - - // Add whatever is left - foreach(var node in scope) { - result.Add((ILNode)node.UserData); - } - scope.Clear(); - - return result; - } - - List FindConditions(HashSet scope, ControlFlowNode entryNode) - { - List result = new List(); - - // Do not modify entry data - scope = new HashSet(scope); - - Stack agenda = new Stack(); - agenda.Push(entryNode); - while(agenda.Count > 0) { - ControlFlowNode node = agenda.Pop(); - - // Find a block that represents a simple condition - if (scope.Contains(node)) { - - ILBasicBlock block = (ILBasicBlock)node.UserData; - - { - // Switch - ILLabel[] caseLabels; - ILExpression switchArg; - ILLabel fallLabel; - if (block.MatchLastAndBr(ILCode.Switch, out caseLabels, out switchArg, out fallLabel)) { - - // Replace the switch code with ILSwitch - ILSwitch ilSwitch = new ILSwitch() { Condition = switchArg }; - block.Body.RemoveTail(ILCode.Switch, ILCode.Br); - block.Body.Add(ilSwitch); - block.Body.Add(new ILExpression(ILCode.Br, fallLabel)); - result.Add(block); - - // Remove the item so that it is not picked up as content - scope.RemoveOrThrow(node); - - // Find the switch offset - int addValue = 0; - List subArgs; - if (ilSwitch.Condition.Match(ILCode.Sub, out subArgs) && subArgs[1].Match(ILCode.Ldc_I4, out addValue)) { - ilSwitch.Condition = subArgs[0]; - } - - // Pull in code of cases - ControlFlowNode fallTarget = null; - labelToCfNode.TryGetValue(fallLabel, out fallTarget); - - HashSet frontiers = new HashSet(); - if (fallTarget != null) - frontiers.UnionWith(fallTarget.DominanceFrontier.Except(new [] { fallTarget })); - - foreach(ILLabel condLabel in caseLabels) { - ControlFlowNode condTarget = null; - labelToCfNode.TryGetValue(condLabel, out condTarget); - if (condTarget != null) - frontiers.UnionWith(condTarget.DominanceFrontier.Except(new [] { condTarget })); - } - - for (int i = 0; i < caseLabels.Length; i++) { - ILLabel condLabel = caseLabels[i]; - - // Find or create new case block - ILSwitch.CaseBlock caseBlock = ilSwitch.CaseBlocks.FirstOrDefault(b => b.EntryGoto.Operand == condLabel); - if (caseBlock == null) { - caseBlock = new ILSwitch.CaseBlock() { - Values = new List(), - EntryGoto = new ILExpression(ILCode.Br, condLabel) - }; - ilSwitch.CaseBlocks.Add(caseBlock); - - ControlFlowNode condTarget = null; - labelToCfNode.TryGetValue(condLabel, out condTarget); - if (condTarget != null && !frontiers.Contains(condTarget)) { - HashSet content = FindDominatedNodes(scope, condTarget); - scope.ExceptWith(content); - caseBlock.Body.AddRange(FindConditions(content, condTarget)); - // Add explicit break which should not be used by default, but the goto removal might decide to use it - caseBlock.Body.Add(new ILBasicBlock() { - Body = { - new ILLabel() { Name = "SwitchBreak_" + (nextLabelIndex++) }, - new ILExpression(ILCode.LoopOrSwitchBreak, null) - } - }); - } - } - caseBlock.Values.Add(i + addValue); - } - - // Heuristis to determine if we want to use fallthough as default case - if (fallTarget != null && !frontiers.Contains(fallTarget)) { - HashSet content = FindDominatedNodes(scope, fallTarget); - if (content.Any()) { - var caseBlock = new ILSwitch.CaseBlock() { EntryGoto = new ILExpression(ILCode.Br, fallLabel) }; - ilSwitch.CaseBlocks.Add(caseBlock); - block.Body.RemoveTail(ILCode.Br); - - scope.ExceptWith(content); - caseBlock.Body.AddRange(FindConditions(content, fallTarget)); - // Add explicit break which should not be used by default, but the goto removal might decide to use it - caseBlock.Body.Add(new ILBasicBlock() { - Body = { - new ILLabel() { Name = "SwitchBreak_" + (nextLabelIndex++) }, - new ILExpression(ILCode.LoopOrSwitchBreak, null) - } - }); - } - } - } - - // Two-way branch - ILExpression condExpr; - ILLabel trueLabel; - ILLabel falseLabel; - if(block.MatchLastAndBr(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel)) { - - // Swap bodies since that seems to be the usual C# order - ILLabel temp = trueLabel; - trueLabel = falseLabel; - falseLabel = temp; - condExpr = new ILExpression(ILCode.LogicNot, null, condExpr); - - // Convert the brtrue to ILCondition - ILCondition ilCond = new ILCondition() { - Condition = condExpr, - TrueBlock = new ILBlock() { EntryGoto = new ILExpression(ILCode.Br, trueLabel) }, - FalseBlock = new ILBlock() { EntryGoto = new ILExpression(ILCode.Br, falseLabel) } - }; - block.Body.RemoveTail(ILCode.Brtrue, ILCode.Br); - block.Body.Add(ilCond); - result.Add(block); - - // Remove the item immediately so that it is not picked up as content - scope.RemoveOrThrow(node); - - ControlFlowNode trueTarget = null; - labelToCfNode.TryGetValue(trueLabel, out trueTarget); - ControlFlowNode falseTarget = null; - labelToCfNode.TryGetValue(falseLabel, out falseTarget); - - // Pull in the conditional code - if (trueTarget != null && HasSingleEdgeEnteringBlock(trueTarget)) { - HashSet content = FindDominatedNodes(scope, trueTarget); - scope.ExceptWith(content); - ilCond.TrueBlock.Body.AddRange(FindConditions(content, trueTarget)); - } - if (falseTarget != null && HasSingleEdgeEnteringBlock(falseTarget)) { - HashSet content = FindDominatedNodes(scope, falseTarget); - scope.ExceptWith(content); - ilCond.FalseBlock.Body.AddRange(FindConditions(content, falseTarget)); - } - } - } - - // Add the node now so that we have good ordering - if (scope.Contains(node)) { - result.Add((ILNode)node.UserData); - scope.Remove(node); - } - } - - // depth-first traversal of dominator tree - for (int i = node.DominatorTreeChildren.Count - 1; i >= 0; i--) { - agenda.Push(node.DominatorTreeChildren[i]); - } - } - - // Add whatever is left - foreach(var node in scope) { - result.Add((ILNode)node.UserData); - } - - return result; - } - - static bool HasSingleEdgeEnteringBlock(ControlFlowNode node) - { - return node.Incoming.Count(edge => !node.Dominates(edge.Source)) == 1; - } - - static HashSet FindDominatedNodes(HashSet scope, ControlFlowNode head) - { - HashSet agenda = new HashSet(); - HashSet result = new HashSet(); - agenda.Add(head); - - while(agenda.Count > 0) { - ControlFlowNode addNode = agenda.First(); - agenda.Remove(addNode); - - if (scope.Contains(addNode) && head.Dominates(addNode) && result.Add(addNode)) { - foreach (var successor in addNode.Successors) { - agenda.Add(successor); - } - } - } - - return result; - } - - static HashSet FindLoopContent(HashSet scope, ControlFlowNode head) - { - var viaBackEdges = head.Predecessors.Where(p => head.Dominates(p)); - HashSet agenda = new HashSet(viaBackEdges); - HashSet result = new HashSet(); - - while(agenda.Count > 0) { - ControlFlowNode addNode = agenda.First(); - agenda.Remove(addNode); - - if (scope.Contains(addNode) && head.Dominates(addNode) && result.Add(addNode)) { - foreach (var predecessor in addNode.Predecessors) { - agenda.Add(predecessor); - } - } - } - if (scope.Contains(head)) - result.Add(head); - - return result; - } - } -} diff --git a/ICSharpCode.Decompiler/ILAst/PatternMatching.cs b/ICSharpCode.Decompiler/ILAst/PatternMatching.cs deleted file mode 100644 index 441088b9..00000000 --- a/ICSharpCode.Decompiler/ILAst/PatternMatching.cs +++ /dev/null @@ -1,177 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using Mono.Cecil; - -namespace ICSharpCode.Decompiler.ILAst -{ - public static class PatternMatching - { - public static bool Match(this ILNode node, ILCode code) - { - ILExpression expr = node as ILExpression; - return expr != null && expr.Prefixes == null && expr.Code == code; - } - - public static bool Match(this ILNode node, ILCode code, out T operand) - { - ILExpression expr = node as ILExpression; - if (expr != null && expr.Prefixes == null && expr.Code == code && expr.Arguments.Count == 0) { - operand = (T)expr.Operand; - return true; - } - operand = default(T); - return false; - } - - public static bool Match(this ILNode node, ILCode code, out List args) - { - ILExpression expr = node as ILExpression; - if (expr != null && expr.Prefixes == null && expr.Code == code) { - Debug.Assert(expr.Operand == null); - args = expr.Arguments; - return true; - } - args = null; - return false; - } - - public static bool Match(this ILNode node, ILCode code, out ILExpression arg) - { - List args; - if (node.Match(code, out args) && args.Count == 1) { - arg = args[0]; - return true; - } - arg = null; - return false; - } - - public static bool Match(this ILNode node, ILCode code, out T operand, out List args) - { - ILExpression expr = node as ILExpression; - if (expr != null && expr.Prefixes == null && expr.Code == code) { - operand = (T)expr.Operand; - args = expr.Arguments; - return true; - } - operand = default(T); - args = null; - return false; - } - - public static bool Match(this ILNode node, ILCode code, out T operand, out ILExpression arg) - { - List args; - if (node.Match(code, out operand, out args) && args.Count == 1) { - arg = args[0]; - return true; - } - arg = null; - return false; - } - - public static bool Match(this ILNode node, ILCode code, out T operand, out ILExpression arg1, out ILExpression arg2) - { - List args; - if (node.Match(code, out operand, out args) && args.Count == 2) { - arg1 = args[0]; - arg2 = args[1]; - return true; - } - arg1 = null; - arg2 = null; - return false; - } - - public static bool MatchSingle(this ILBasicBlock bb, ILCode code, out T operand, out ILExpression arg) - { - if (bb.Body.Count == 2 && - bb.Body[0] is ILLabel && - bb.Body[1].Match(code, out operand, out arg)) - { - return true; - } - operand = default(T); - arg = null; - return false; - } - - public static bool MatchSingleAndBr(this ILBasicBlock bb, ILCode code, out T operand, out ILExpression arg, out ILLabel brLabel) - { - if (bb.Body.Count == 3 && - bb.Body[0] is ILLabel && - bb.Body[1].Match(code, out operand, out arg) && - bb.Body[2].Match(ILCode.Br, out brLabel)) - { - return true; - } - operand = default(T); - arg = null; - brLabel = null; - return false; - } - - public static bool MatchLastAndBr(this ILBasicBlock bb, ILCode code, out T operand, out ILExpression arg, out ILLabel brLabel) - { - if (bb.Body.ElementAtOrDefault(bb.Body.Count - 2).Match(code, out operand, out arg) && - bb.Body.LastOrDefault().Match(ILCode.Br, out brLabel)) - { - return true; - } - operand = default(T); - arg = null; - brLabel = null; - return false; - } - - public static bool MatchThis(this ILNode node) - { - ILVariable v; - return node.Match(ILCode.Ldloc, out v) && v.IsParameter && v.OriginalParameter.Index == -1; - } - - public static bool MatchLdloc(this ILNode node, ILVariable expectedVar) - { - ILVariable v; - return node.Match(ILCode.Ldloc, out v) && v == expectedVar; - } - - public static bool MatchLdloca(this ILNode node, ILVariable expectedVar) - { - ILVariable v; - return node.Match(ILCode.Ldloca, out v) && v == expectedVar; - } - - public static bool MatchStloc(this ILNode node, ILVariable expectedVar, out ILExpression expr) - { - ILVariable v; - return node.Match(ILCode.Stloc, out v, out expr) && v == expectedVar; - } - - public static bool MatchLdcI4(this ILNode node, int expectedValue) - { - int v; - return node.Match(ILCode.Ldc_I4, out v) && v == expectedValue; - } - } -} diff --git a/ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs b/ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs deleted file mode 100644 index f514aa45..00000000 --- a/ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs +++ /dev/null @@ -1,1103 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; - -using ICSharpCode.NRefactory.Utils; -using Mono.Cecil; - -namespace ICSharpCode.Decompiler.ILAst -{ - public partial class ILAstOptimizer - { - #region TypeConversionSimplifications - static bool TypeConversionSimplifications(List body, ILExpression expr, int pos) - { - bool modified = false; - modified |= TransformDecimalCtorToConstant(expr); - modified |= SimplifyLdcI4ConvI8(expr); - modified |= RemoveConvIFromArrayCreation(expr); - foreach(ILExpression arg in expr.Arguments) { - modified |= TypeConversionSimplifications(null, arg, -1); - } - return modified; - } - - static bool TransformDecimalCtorToConstant(ILExpression expr) - { - MethodReference r; - List args; - if (expr.Match(ILCode.Newobj, out r, out args) && - r.DeclaringType.Namespace == "System" && - r.DeclaringType.Name == "Decimal") - { - if (args.Count == 1) { - int val; - if (args[0].Match(ILCode.Ldc_I4, out val)) { - expr.Code = ILCode.Ldc_Decimal; - expr.Operand = new decimal(val); - expr.InferredType = r.DeclaringType; - expr.Arguments.Clear(); - return true; - } - } else if (args.Count == 5) { - int lo, mid, hi, isNegative, scale; - if (expr.Arguments[0].Match(ILCode.Ldc_I4, out lo) && - expr.Arguments[1].Match(ILCode.Ldc_I4, out mid) && - expr.Arguments[2].Match(ILCode.Ldc_I4, out hi) && - expr.Arguments[3].Match(ILCode.Ldc_I4, out isNegative) && - expr.Arguments[4].Match(ILCode.Ldc_I4, out scale)) - { - expr.Code = ILCode.Ldc_Decimal; - expr.Operand = new decimal(lo, mid, hi, isNegative != 0, (byte)scale); - expr.InferredType = r.DeclaringType; - expr.Arguments.Clear(); - return true; - } - } - } - return false; - } - - static bool SimplifyLdcI4ConvI8(ILExpression expr) - { - ILExpression ldc; - int val; - if (expr.Match(ILCode.Conv_I8, out ldc) && ldc.Match(ILCode.Ldc_I4, out val)) { - expr.Code = ILCode.Ldc_I8; - expr.Operand = (long)val; - expr.Arguments.Clear(); - return true; - } - return false; - } - - static bool RemoveConvIFromArrayCreation(ILExpression expr) - { - TypeReference typeRef; - ILExpression length; - ILExpression input; - if (expr.Match(ILCode.Newarr, out typeRef, out length)) { - if (length.Match(ILCode.Conv_Ovf_I, out input) || length.Match(ILCode.Conv_I, out input) - || length.Match(ILCode.Conv_Ovf_I_Un, out input) || length.Match(ILCode.Conv_U, out input)) - { - expr.Arguments[0] = input; - return true; - } - } - return false; - } - #endregion - - #region SimplifyLdObjAndStObj - static bool SimplifyLdObjAndStObj(List body, ILExpression expr, int pos) - { - bool modified = false; - expr = SimplifyLdObjAndStObj(expr, ref modified); - if (modified && body != null) - body[pos] = expr; - for (int i = 0; i < expr.Arguments.Count; i++) { - expr.Arguments[i] = SimplifyLdObjAndStObj(expr.Arguments[i], ref modified); - modified |= SimplifyLdObjAndStObj(null, expr.Arguments[i], -1); - } - return modified; - } - - static ILExpression SimplifyLdObjAndStObj(ILExpression expr, ref bool modified) - { - if (expr.Code == ILCode.Initobj) { - expr.Code = ILCode.Stobj; - expr.Arguments.Add(new ILExpression(ILCode.DefaultValue, expr.Operand)); - modified = true; - } else if (expr.Code == ILCode.Cpobj) { - expr.Code = ILCode.Stobj; - expr.Arguments[1] = new ILExpression(ILCode.Ldobj, expr.Operand, expr.Arguments[1]); - modified = true; - } - ILExpression arg, arg2; - TypeReference type; - ILCode? newCode = null; - if (expr.Match(ILCode.Stobj, out type, out arg, out arg2)) { - switch (arg.Code) { - case ILCode.Ldelema: newCode = ILCode.Stelem_Any; break; - case ILCode.Ldloca: newCode = ILCode.Stloc; break; - case ILCode.Ldflda: newCode = ILCode.Stfld; break; - case ILCode.Ldsflda: newCode = ILCode.Stsfld; break; - } - } else if (expr.Match(ILCode.Ldobj, out type, out arg)) { - switch (arg.Code) { - case ILCode.Ldelema: newCode = ILCode.Ldelem_Any; break; - case ILCode.Ldloca: newCode = ILCode.Ldloc; break; - case ILCode.Ldflda: newCode = ILCode.Ldfld; break; - case ILCode.Ldsflda: newCode = ILCode.Ldsfld; break; - } - } - if (newCode != null) { - arg.Code = newCode.Value; - if (expr.Code == ILCode.Stobj) { - arg.InferredType = expr.InferredType; - arg.ExpectedType = expr.ExpectedType; - arg.Arguments.Add(arg2); - } - arg.ILRanges.AddRange(expr.ILRanges); - modified = true; - return arg; - } else { - return expr; - } - } - #endregion - - #region CachedDelegateInitialization - void CachedDelegateInitializationWithField(ILBlock block, ref int i) - { - // if (logicnot(ldsfld(field))) { - // stsfld(field, newobj(Action::.ctor, ldnull(), ldftn(method))) - // } else { - // } - // ...(..., ldsfld(field), ...) - - ILCondition c = block.Body[i] as ILCondition; - if (c == null || c.Condition == null && c.TrueBlock == null || c.FalseBlock == null) - return; - if (!(c.TrueBlock.Body.Count == 1 && c.FalseBlock.Body.Count == 0)) - return; - if (!c.Condition.Match(ILCode.LogicNot)) - return; - ILExpression condition = c.Condition.Arguments.Single() as ILExpression; - if (condition == null || condition.Code != ILCode.Ldsfld) - return; - FieldDefinition field = ((FieldReference)condition.Operand).ResolveWithinSameModule(); // field is defined in current assembly - if (field == null || !field.IsCompilerGeneratedOrIsInCompilerGeneratedClass()) - return; - ILExpression stsfld = c.TrueBlock.Body[0] as ILExpression; - if (!(stsfld != null && stsfld.Code == ILCode.Stsfld && ((FieldReference)stsfld.Operand).ResolveWithinSameModule() == field)) - return; - ILExpression newObj = stsfld.Arguments[0]; - if (!(newObj.Code == ILCode.Newobj && newObj.Arguments.Count == 2)) - return; - if (newObj.Arguments[0].Code != ILCode.Ldnull) - return; - if (newObj.Arguments[1].Code != ILCode.Ldftn) - return; - MethodDefinition anonymousMethod = ((MethodReference)newObj.Arguments[1].Operand).ResolveWithinSameModule(); // method is defined in current assembly - if (!Ast.Transforms.DelegateConstruction.IsAnonymousMethod(context, anonymousMethod)) - return; - - ILNode followingNode = block.Body.ElementAtOrDefault(i + 1); - if (followingNode != null && followingNode.GetSelfAndChildrenRecursive().Count( - e => e.Code == ILCode.Ldsfld && ((FieldReference)e.Operand).ResolveWithinSameModule() == field) == 1) - { - foreach (ILExpression parent in followingNode.GetSelfAndChildrenRecursive()) { - for (int j = 0; j < parent.Arguments.Count; j++) { - if (parent.Arguments[j].Code == ILCode.Ldsfld && ((FieldReference)parent.Arguments[j].Operand).ResolveWithinSameModule() == field) { - parent.Arguments[j] = newObj; - block.Body.RemoveAt(i); - i -= new ILInlining(method).InlineInto(block.Body, i, aggressive: false); - return; - } - } - } - } - } - - void CachedDelegateInitializationWithLocal(ILBlock block, ref int i) - { - // if (logicnot(ldloc(v))) { - // stloc(v, newobj(Action::.ctor, ldloc(displayClass), ldftn(method))) - // } else { - // } - // ...(..., ldloc(v), ...) - - ILCondition c = block.Body[i] as ILCondition; - if (c == null || c.Condition == null && c.TrueBlock == null || c.FalseBlock == null) - return; - if (!(c.TrueBlock.Body.Count == 1 && c.FalseBlock.Body.Count == 0)) - return; - if (!c.Condition.Match(ILCode.LogicNot)) - return; - ILExpression condition = c.Condition.Arguments.Single() as ILExpression; - if (condition == null || condition.Code != ILCode.Ldloc) - return; - ILVariable v = (ILVariable)condition.Operand; - ILExpression stloc = c.TrueBlock.Body[0] as ILExpression; - if (!(stloc != null && stloc.Code == ILCode.Stloc && (ILVariable)stloc.Operand == v)) - return; - ILExpression newObj = stloc.Arguments[0]; - if (!(newObj.Code == ILCode.Newobj && newObj.Arguments.Count == 2)) - return; - if (newObj.Arguments[0].Code != ILCode.Ldloc) - return; - if (newObj.Arguments[1].Code != ILCode.Ldftn) - return; - MethodDefinition anonymousMethod = ((MethodReference)newObj.Arguments[1].Operand).ResolveWithinSameModule(); // method is defined in current assembly - if (!Ast.Transforms.DelegateConstruction.IsAnonymousMethod(context, anonymousMethod)) - return; - - ILNode followingNode = block.Body.ElementAtOrDefault(i + 1); - if (followingNode != null && followingNode.GetSelfAndChildrenRecursive().Count( - e => e.Code == ILCode.Ldloc && (ILVariable)e.Operand == v) == 1) - { - ILInlining inlining = new ILInlining(method); - if (!(inlining.numLdloc.GetOrDefault(v) == 2 && inlining.numStloc.GetOrDefault(v) == 2 && inlining.numLdloca.GetOrDefault(v) == 0)) - return; - - // Find the store instruction that initializes the local to null: - foreach (ILBlock storeBlock in method.GetSelfAndChildrenRecursive()) { - for (int j = 0; j < storeBlock.Body.Count; j++) { - ILVariable storedVar; - ILExpression storedExpr; - if (storeBlock.Body[j].Match(ILCode.Stloc, out storedVar, out storedExpr) && storedVar == v && storedExpr.Match(ILCode.Ldnull)) { - // Remove the instruction - storeBlock.Body.RemoveAt(j); - if (storeBlock == block && j < i) - i--; - break; - } - } - } - - block.Body[i] = stloc; // remove the 'if (v==null)' - inlining = new ILInlining(method); - inlining.InlineIfPossible(block.Body, ref i); - } - } - #endregion - - #region MakeAssignmentExpression - bool MakeAssignmentExpression(List body, ILExpression expr, int pos) - { - // exprVar = ... - // stloc(v, exprVar) - // -> - // exprVar = stloc(v, ...)) - ILVariable exprVar; - ILExpression initializer; - if (!(expr.Match(ILCode.Stloc, out exprVar, out initializer) && exprVar.IsGenerated)) - return false; - ILExpression nextExpr = body.ElementAtOrDefault(pos + 1) as ILExpression; - ILVariable v; - ILExpression stLocArg; - if (nextExpr.Match(ILCode.Stloc, out v, out stLocArg) && stLocArg.MatchLdloc(exprVar)) { - ILExpression store2 = body.ElementAtOrDefault(pos + 2) as ILExpression; - if (StoreCanBeConvertedToAssignment(store2, exprVar)) { - // expr_44 = ... - // stloc(v1, expr_44) - // anystore(v2, expr_44) - // -> - // stloc(v1, anystore(v2, ...)) - ILInlining inlining = new ILInlining(method); - if (inlining.numLdloc.GetOrDefault(exprVar) == 2 && inlining.numStloc.GetOrDefault(exprVar) == 1) { - body.RemoveAt(pos + 2); // remove store2 - body.RemoveAt(pos); // remove expr = ... - nextExpr.Arguments[0] = store2; - store2.Arguments[store2.Arguments.Count - 1] = initializer; - - inlining.InlineIfPossible(body, ref pos); - - return true; - } - } - - body.RemoveAt(pos + 1); // remove stloc - nextExpr.Arguments[0] = initializer; - ((ILExpression)body[pos]).Arguments[0] = nextExpr; - return true; - } else if ((nextExpr.Code == ILCode.Stsfld || nextExpr.Code == ILCode.CallSetter || nextExpr.Code == ILCode.CallvirtSetter) && nextExpr.Arguments.Count == 1) { - // exprVar = ... - // stsfld(fld, exprVar) - // -> - // exprVar = stsfld(fld, ...)) - if (nextExpr.Arguments[0].MatchLdloc(exprVar)) { - body.RemoveAt(pos + 1); // remove stsfld - nextExpr.Arguments[0] = initializer; - ((ILExpression)body[pos]).Arguments[0] = nextExpr; - return true; - } - } - return false; - } - - bool StoreCanBeConvertedToAssignment(ILExpression store, ILVariable exprVar) - { - if (store == null) - return false; - switch (store.Code) { - case ILCode.Stloc: - case ILCode.Stfld: - case ILCode.Stsfld: - case ILCode.Stobj: - case ILCode.CallSetter: - case ILCode.CallvirtSetter: - break; - default: - if (!store.Code.IsStoreToArray()) - return false; - break; - } - return store.Arguments.Last().Code == ILCode.Ldloc && store.Arguments.Last().Operand == exprVar; - } - #endregion - - #region MakeCompoundAssignments - bool MakeCompoundAssignments(List body, ILExpression expr, int pos) - { - bool modified = false; - modified |= MakeCompoundAssignment(expr); - // Static fields and local variables are not handled here - those are expressions without side effects - // and get handled by ReplaceMethodCallsWithOperators - // (which does a reversible transform to the short operator form, as the introduction of checked/unchecked might have to revert to the long form). - foreach (ILExpression arg in expr.Arguments) { - modified |= MakeCompoundAssignments(null, arg, -1); - } - if (modified && body != null) - new ILInlining(method).InlineInto(body, pos, aggressive: false); - return modified; - } - - bool MakeCompoundAssignment(ILExpression expr) - { - // stelem.any(T, ldloc(array), ldloc(pos), (ldelem.any(T, ldloc(array), ldloc(pos)), )) - // or - // stobj(T, ldloc(ptr), (ldobj(T, ldloc(ptr)), )) - ILCode expectedLdelemCode; - switch (expr.Code) { - case ILCode.Stelem_Any: - expectedLdelemCode = ILCode.Ldelem_Any; - break; - case ILCode.Stfld: - expectedLdelemCode = ILCode.Ldfld; - break; - case ILCode.Stobj: - expectedLdelemCode = ILCode.Ldobj; - break; - case ILCode.CallSetter: - expectedLdelemCode = ILCode.CallGetter; - break; - case ILCode.CallvirtSetter: - expectedLdelemCode = ILCode.CallvirtGetter; - break; - default: - return false; - } - - // all arguments except the last (so either array+pos, or ptr): - bool hasGeneratedVar = false; - for (int i = 0; i < expr.Arguments.Count - 1; i++) { - ILVariable inputVar; - if (!expr.Arguments[i].Match(ILCode.Ldloc, out inputVar)) - return false; - hasGeneratedVar |= inputVar.IsGenerated; - } - // At least one of the variables must be generated; otherwise we just keep the expanded form. - // We do this because we want compound assignments to be represented in ILAst only when strictly necessary; - // other compound assignments will be introduced by ReplaceMethodCallsWithOperator - // (which uses a reversible transformation, see ReplaceMethodCallsWithOperator.RestoreOriginalAssignOperatorAnnotation) - if (!hasGeneratedVar) - return false; - - ILExpression op = expr.Arguments.Last(); - // in case of compound assignments with a lifted operator the result is inside NullableOf and the operand is inside ValueOf - bool liftedOperator = false; - if (op.Code == ILCode.NullableOf) { - op = op.Arguments[0]; - liftedOperator = true; - } - if (!CanBeRepresentedAsCompoundAssignment(op)) - return false; - - ILExpression ldelem = op.Arguments[0]; - if (liftedOperator) { - if (ldelem.Code != ILCode.ValueOf) - return false; - ldelem = ldelem.Arguments[0]; - } - if (ldelem.Code != expectedLdelemCode) - return false; - Debug.Assert(ldelem.Arguments.Count == expr.Arguments.Count - 1); - for (int i = 0; i < ldelem.Arguments.Count; i++) { - if (!ldelem.Arguments[i].MatchLdloc((ILVariable)expr.Arguments[i].Operand)) - return false; - } - expr.Code = ILCode.CompoundAssignment; - expr.Operand = null; - expr.Arguments.RemoveRange(0, ldelem.Arguments.Count); - // result is "CompoundAssignment((ldelem.any(...), ))" - return true; - } - - static bool CanBeRepresentedAsCompoundAssignment(ILExpression expr) - { - switch (expr.Code) { - case ILCode.Add: - case ILCode.Add_Ovf: - case ILCode.Add_Ovf_Un: - case ILCode.Sub: - case ILCode.Sub_Ovf: - case ILCode.Sub_Ovf_Un: - case ILCode.Mul: - case ILCode.Mul_Ovf: - case ILCode.Mul_Ovf_Un: - case ILCode.Div: - case ILCode.Div_Un: - case ILCode.Rem: - case ILCode.Rem_Un: - case ILCode.And: - case ILCode.Or: - case ILCode.Xor: - case ILCode.Shl: - case ILCode.Shr: - case ILCode.Shr_Un: - return true; - case ILCode.Call: - var m = expr.Operand as MethodReference; - if (m == null || m.HasThis || expr.Arguments.Count != 2) return false; - switch (m.Name) { - case "op_Addition": - case "op_Subtraction": - case "op_Multiply": - case "op_Division": - case "op_Modulus": - case "op_BitwiseAnd": - case "op_BitwiseOr": - case "op_ExclusiveOr": - case "op_LeftShift": - case "op_RightShift": - return true; - default: - return false; - } - default: - return false; - } - } - #endregion - - #region IntroducePostIncrement - - bool IntroducePostIncrement(List body, ILExpression expr, int pos) - { - bool modified = IntroducePostIncrementForVariables(body, expr, pos); - Debug.Assert(body[pos] == expr); // IntroducePostIncrementForVariables shouldn't change the expression reference - ILExpression newExpr = IntroducePostIncrementForInstanceFields(expr); - if (newExpr != null) { - modified = true; - body[pos] = newExpr; - new ILInlining(method).InlineIfPossible(body, ref pos); - } - return modified; - } - - bool IntroducePostIncrementForVariables(List body, ILExpression expr, int pos) - { - // Works for variables and static fields/properties - - // expr = ldloc(i) - // stloc(i, add(expr, ldc.i4(1))) - // -> - // expr = postincrement(1, ldloca(i)) - ILVariable exprVar; - ILExpression exprInit; - if (!(expr.Match(ILCode.Stloc, out exprVar, out exprInit) && exprVar.IsGenerated)) - return false; - - //The next expression - ILExpression nextExpr = body.ElementAtOrDefault(pos + 1) as ILExpression; - if (nextExpr == null) - return false; - - ILCode loadInstruction = exprInit.Code; - ILCode storeInstruction = nextExpr.Code; - bool recombineVariable = false; - - // We only recognise local variables, static fields, and static getters with no arguments - switch (loadInstruction) { - case ILCode.Ldloc: - //Must be a matching store type - if (storeInstruction != ILCode.Stloc) - return false; - ILVariable loadVar = (ILVariable)exprInit.Operand; - ILVariable storeVar = (ILVariable)nextExpr.Operand; - if (loadVar != storeVar) { - if (loadVar.OriginalVariable != null && loadVar.OriginalVariable == storeVar.OriginalVariable) - recombineVariable = true; - else - return false; - } - break; - case ILCode.Ldsfld: - if (storeInstruction != ILCode.Stsfld) - return false; - if (exprInit.Operand != nextExpr.Operand) - return false; - break; - case ILCode.CallGetter: - // non-static getters would have the 'this' argument - if (exprInit.Arguments.Count != 0) - return false; - if (storeInstruction != ILCode.CallSetter) - return false; - if (!IsGetterSetterPair(exprInit.Operand, nextExpr.Operand)) - return false; - break; - default: - return false; - } - - ILExpression addExpr = nextExpr.Arguments[0]; - - int incrementAmount; - ILCode incrementCode = GetIncrementCode(addExpr, out incrementAmount); - if (!(incrementAmount != 0 && addExpr.Arguments[0].MatchLdloc(exprVar))) - return false; - - if (recombineVariable) { - // Split local variable, unsplit these two instances - // replace nextExpr.Operand with exprInit.Operand - ReplaceVariables(method, oldVar => oldVar == nextExpr.Operand ? (ILVariable)exprInit.Operand : oldVar); - } - - switch (loadInstruction) { - case ILCode.Ldloc: - exprInit.Code = ILCode.Ldloca; - break; - case ILCode.Ldsfld: - exprInit.Code = ILCode.Ldsflda; - break; - case ILCode.CallGetter: - exprInit = new ILExpression(ILCode.AddressOf, null, exprInit); - break; - } - expr.Arguments[0] = new ILExpression(incrementCode, incrementAmount, exprInit); - body.RemoveAt(pos + 1); // TODO ILRanges - return true; - } - - static bool IsGetterSetterPair(object getterOperand, object setterOperand) - { - MethodReference getter = getterOperand as MethodReference; - MethodReference setter = setterOperand as MethodReference; - if (getter == null || setter == null) - return false; - if (!TypeAnalysis.IsSameType(getter.DeclaringType, setter.DeclaringType)) - return false; - MethodDefinition getterDef = getter.Resolve(); - MethodDefinition setterDef = setter.Resolve(); - if (getterDef == null || setterDef == null) - return false; - foreach (PropertyDefinition prop in getterDef.DeclaringType.Properties) { - if (prop.GetMethod == getterDef) - return prop.SetMethod == setterDef; - } - return false; - } - - ILExpression IntroducePostIncrementForInstanceFields(ILExpression expr) - { - // stfld(field, ldloc(instance), add(stloc(helperVar, ldfld(field, ldloc(instance))), ldc.i4(1))) - // -> stloc(helperVar, postincrement(1, ldflda(field, ldloc(instance)))) - - // Also works for array elements and pointers: - - // stelem.any(T, ldloc(instance), ldloc(pos), add(stloc(helperVar, ldelem.any(T, ldloc(instance), ldloc(pos))), ldc.i4(1))) - // -> stloc(helperVar, postincrement(1, ldelema(ldloc(instance), ldloc(pos)))) - - // stobj(T, ldloc(ptr), add(stloc(helperVar, ldobj(T, ldloc(ptr)), ldc.i4(1)))) - // -> stloc(helperVar, postIncrement(1, ldloc(ptr))) - - // callsetter(set_P, ldloc(instance), add(stloc(helperVar, callgetter(get_P, ldloc(instance))), ldc.i4(1))) - // -> stloc(helperVar, postIncrement(1, propertyaddress. callgetter(get_P, ldloc(instance)))) - - if (!(expr.Code == ILCode.Stfld || expr.Code.IsStoreToArray() || expr.Code == ILCode.Stobj || expr.Code == ILCode.CallSetter || expr.Code == ILCode.CallvirtSetter)) - return null; - - // Test that all arguments except the last are ldloc (1 arg for fields and pointers, 2 args for arrays) - for (int i = 0; i < expr.Arguments.Count - 1; i++) { - if (expr.Arguments[i].Code != ILCode.Ldloc) - return null; - } - - ILExpression addExpr = expr.Arguments[expr.Arguments.Count - 1]; - int incrementAmount; - ILCode incrementCode = GetIncrementCode(addExpr, out incrementAmount); - ILVariable helperVar; - ILExpression initialValue; - if (!(incrementAmount != 0 && addExpr.Arguments[0].Match(ILCode.Stloc, out helperVar, out initialValue))) - return null; - - if (expr.Code == ILCode.Stfld) { - if (initialValue.Code != ILCode.Ldfld) - return null; - // There might be two different FieldReference instances, so we compare the field's signatures: - FieldReference getField = (FieldReference)initialValue.Operand; - FieldReference setField = (FieldReference)expr.Operand; - if (!(TypeAnalysis.IsSameType(getField.DeclaringType, setField.DeclaringType) - && getField.Name == setField.Name && TypeAnalysis.IsSameType(getField.FieldType, setField.FieldType))) - { - return null; - } - } else if (expr.Code == ILCode.Stobj) { - if (!(initialValue.Code == ILCode.Ldobj && initialValue.Operand == expr.Operand)) - return null; - } else if (expr.Code == ILCode.CallSetter) { - if (!(initialValue.Code == ILCode.CallGetter && IsGetterSetterPair(initialValue.Operand, expr.Operand))) - return null; - } else if (expr.Code == ILCode.CallvirtSetter) { - if (!(initialValue.Code == ILCode.CallvirtGetter && IsGetterSetterPair(initialValue.Operand, expr.Operand))) - return null; - } else { - if (!initialValue.Code.IsLoadFromArray()) - return null; - } - Debug.Assert(expr.Arguments.Count - 1 == initialValue.Arguments.Count); - for (int i = 0; i < initialValue.Arguments.Count; i++) { - if (!initialValue.Arguments[i].MatchLdloc((ILVariable)expr.Arguments[i].Operand)) - return null; - } - - ILExpression stloc = addExpr.Arguments[0]; - if (expr.Code == ILCode.Stobj) { - stloc.Arguments[0] = new ILExpression(ILCode.PostIncrement, incrementAmount, initialValue.Arguments[0]); - } else if (expr.Code == ILCode.CallSetter || expr.Code == ILCode.CallvirtSetter) { - initialValue = new ILExpression(ILCode.AddressOf, null, initialValue); - stloc.Arguments[0] = new ILExpression(ILCode.PostIncrement, incrementAmount, initialValue); - } else { - stloc.Arguments[0] = new ILExpression(ILCode.PostIncrement, incrementAmount, initialValue); - initialValue.Code = (expr.Code == ILCode.Stfld ? ILCode.Ldflda : ILCode.Ldelema); - } - // TODO: ILRanges? - - return stloc; - } - - ILCode GetIncrementCode(ILExpression addExpr, out int incrementAmount) - { - ILCode incrementCode; - bool decrement = false; - switch (addExpr.Code) { - case ILCode.Add: - incrementCode = ILCode.PostIncrement; - break; - case ILCode.Add_Ovf: - incrementCode = ILCode.PostIncrement_Ovf; - break; - case ILCode.Add_Ovf_Un: - incrementCode = ILCode.PostIncrement_Ovf_Un; - break; - case ILCode.Sub: - incrementCode = ILCode.PostIncrement; - decrement = true; - break; - case ILCode.Sub_Ovf: - incrementCode = ILCode.PostIncrement_Ovf; - decrement = true; - break; - case ILCode.Sub_Ovf_Un: - incrementCode = ILCode.PostIncrement_Ovf_Un; - decrement = true; - break; - default: - incrementAmount = 0; - return ILCode.Nop; - } - if (addExpr.Arguments[1].Match(ILCode.Ldc_I4, out incrementAmount)) { - if (incrementAmount == -1 || incrementAmount == 1) { // TODO pointer increment? - if (decrement) - incrementAmount = -incrementAmount; - return incrementCode; - } - } - incrementAmount = 0; - return ILCode.Nop; - } - #endregion - - #region IntroduceFixedStatements - bool IntroduceFixedStatements(List body, int i) - { - ILExpression initValue; - ILVariable pinnedVar; - int initEndPos; - if (!MatchFixedInitializer(body, i, out pinnedVar, out initValue, out initEndPos)) - return false; - - ILFixedStatement fixedStmt = body.ElementAtOrDefault(initEndPos) as ILFixedStatement; - if (fixedStmt != null) { - ILExpression expr = fixedStmt.BodyBlock.Body.LastOrDefault() as ILExpression; - if (expr != null && expr.Code == ILCode.Stloc && expr.Operand == pinnedVar && IsNullOrZero(expr.Arguments[0])) { - // we found a second initializer for the existing fixed statement - fixedStmt.Initializers.Insert(0, initValue); - body.RemoveRange(i, initEndPos - i); - fixedStmt.BodyBlock.Body.RemoveAt(fixedStmt.BodyBlock.Body.Count - 1); - if (pinnedVar.Type.IsByReference) - pinnedVar.Type = new PointerType(((ByReferenceType)pinnedVar.Type).ElementType); - return true; - } - } - - // find where pinnedVar is reset to 0: - int j; - for (j = initEndPos; j < body.Count; j++) { - ILVariable v2; - ILExpression storedVal; - // stloc(pinned_Var, conv.u(ldc.i4(0))) - if (body[j].Match(ILCode.Stloc, out v2, out storedVal) && v2 == pinnedVar) { - if (IsNullOrZero(storedVal)) { - break; - } - } - } - // Create fixed statement from i to j - fixedStmt = new ILFixedStatement(); - fixedStmt.Initializers.Add(initValue); - fixedStmt.BodyBlock = new ILBlock(body.GetRange(initEndPos, j - initEndPos)); // from initEndPos to j-1 (inclusive) - body.RemoveRange(i + 1, Math.Min(j, body.Count - 1) - i); // from i+1 to j (inclusive) - body[i] = fixedStmt; - if (pinnedVar.Type.IsByReference) - pinnedVar.Type = new PointerType(((ByReferenceType)pinnedVar.Type).ElementType); - - return true; - } - - bool IsNullOrZero(ILExpression expr) - { - if (expr.Code == ILCode.Conv_U || expr.Code == ILCode.Conv_I) - expr = expr.Arguments[0]; - return (expr.Code == ILCode.Ldc_I4 && (int)expr.Operand == 0) || expr.Code == ILCode.Ldnull; - } - - bool MatchFixedInitializer(List body, int i, out ILVariable pinnedVar, out ILExpression initValue, out int nextPos) - { - if (body[i].Match(ILCode.Stloc, out pinnedVar, out initValue) && pinnedVar.IsPinned && !IsNullOrZero(initValue)) { - initValue = (ILExpression)body[i]; - nextPos = i + 1; - HandleStringFixing(pinnedVar, body, ref nextPos, ref initValue); - return true; - } - ILCondition ifStmt = body[i] as ILCondition; - ILExpression arrayLoadingExpr; - if (ifStmt != null && MatchFixedArrayInitializerCondition(ifStmt.Condition, out arrayLoadingExpr)) { - ILVariable arrayVariable = (ILVariable)arrayLoadingExpr.Operand; - ILExpression trueValue; - if (ifStmt.TrueBlock != null && ifStmt.TrueBlock.Body.Count == 1 - && ifStmt.TrueBlock.Body[0].Match(ILCode.Stloc, out pinnedVar, out trueValue) - && pinnedVar.IsPinned && IsNullOrZero(trueValue)) - { - if (ifStmt.FalseBlock != null && ifStmt.FalseBlock.Body.Count == 1 && ifStmt.FalseBlock.Body[0] is ILFixedStatement) { - ILFixedStatement fixedStmt = (ILFixedStatement)ifStmt.FalseBlock.Body[0]; - ILVariable stlocVar; - ILExpression falseValue; - if (fixedStmt.Initializers.Count == 1 && fixedStmt.BodyBlock.Body.Count == 0 - && fixedStmt.Initializers[0].Match(ILCode.Stloc, out stlocVar, out falseValue) && stlocVar == pinnedVar) - { - ILVariable loadedVariable; - if (falseValue.Code == ILCode.Ldelema - && falseValue.Arguments[0].Match(ILCode.Ldloc, out loadedVariable) && loadedVariable == arrayVariable - && IsNullOrZero(falseValue.Arguments[1])) - { - // OK, we detected the pattern for fixing an array. - // Now check whether the loading expression was a store ot a temp. var - // that can be eliminated. - if (arrayLoadingExpr.Code == ILCode.Stloc) { - ILInlining inlining = new ILInlining(method); - if (inlining.numLdloc.GetOrDefault(arrayVariable) == 2 && - inlining.numStloc.GetOrDefault(arrayVariable) == 1 && inlining.numLdloca.GetOrDefault(arrayVariable) == 0) - { - arrayLoadingExpr = arrayLoadingExpr.Arguments[0]; - } - } - initValue = new ILExpression(ILCode.Stloc, pinnedVar, arrayLoadingExpr); - nextPos = i + 1; - return true; - } - } - } - } - } - initValue = null; - nextPos = -1; - return false; - } - - bool MatchFixedArrayInitializerCondition(ILExpression condition, out ILExpression initValue) - { - ILExpression logicAnd; - ILVariable arrayVar; - if (condition.Match(ILCode.LogicNot, out logicAnd) && logicAnd.Code == ILCode.LogicAnd) { - initValue = UnpackDoubleNegation(logicAnd.Arguments[0]); - ILExpression arrayVarInitializer; - if (initValue.Match(ILCode.Ldloc, out arrayVar) - || initValue.Match(ILCode.Stloc, out arrayVar, out arrayVarInitializer)) - { - ILExpression arrayLength = logicAnd.Arguments[1]; - if (arrayLength.Code == ILCode.Conv_I4) - arrayLength = arrayLength.Arguments[0]; - return arrayLength.Code == ILCode.Ldlen && arrayLength.Arguments[0].MatchLdloc(arrayVar); - } - } - initValue = null; - return false; - } - - ILExpression UnpackDoubleNegation(ILExpression expr) - { - ILExpression negated; - if (expr.Match(ILCode.LogicNot, out negated) && negated.Match(ILCode.LogicNot, out negated)) - return negated; - else - return expr; - } - - bool HandleStringFixing(ILVariable pinnedVar, List body, ref int pos, ref ILExpression fixedStmtInitializer) - { - // fixed (stloc(pinnedVar, ldloc(text))) { - // var1 = var2 = conv.i(ldloc(pinnedVar)) - // if (logicnot(logicnot(var1))) { - // var2 = add(var1, call(RuntimeHelpers::get_OffsetToStringData)) - // } - // stloc(ptrVar, var2) - // ... - - if (pos >= body.Count) - return false; - - ILVariable var1, var2; - ILExpression varAssignment, ptrInitialization; - if (!(body[pos].Match(ILCode.Stloc, out var1, out varAssignment) && varAssignment.Match(ILCode.Stloc, out var2, out ptrInitialization))) - return false; - if (!(var1.IsGenerated && var2.IsGenerated)) - return false; - if (ptrInitialization.Code == ILCode.Conv_I || ptrInitialization.Code == ILCode.Conv_U) - ptrInitialization = ptrInitialization.Arguments[0]; - if (!ptrInitialization.MatchLdloc(pinnedVar)) - return false; - - ILCondition ifStmt = body[pos + 1] as ILCondition; - if (!(ifStmt != null && ifStmt.TrueBlock != null && ifStmt.TrueBlock.Body.Count == 1 && (ifStmt.FalseBlock == null || ifStmt.FalseBlock.Body.Count == 0))) - return false; - if (!UnpackDoubleNegation(ifStmt.Condition).MatchLdloc(var1)) - return false; - ILVariable assignedVar; - ILExpression assignedExpr; - if (!(ifStmt.TrueBlock.Body[0].Match(ILCode.Stloc, out assignedVar, out assignedExpr) && assignedVar == var2 && assignedExpr.Code == ILCode.Add)) - return false; - MethodReference calledMethod; - if (!(assignedExpr.Arguments[0].MatchLdloc(var1))) - return false; - if (!(assignedExpr.Arguments[1].Match(ILCode.Call, out calledMethod) || assignedExpr.Arguments[1].Match(ILCode.CallGetter, out calledMethod))) - return false; - if (!(calledMethod.Name == "get_OffsetToStringData" && calledMethod.DeclaringType.FullName == "System.Runtime.CompilerServices.RuntimeHelpers")) - return false; - - ILVariable pointerVar; - if (body[pos + 2].Match(ILCode.Stloc, out pointerVar, out assignedExpr) && assignedExpr.MatchLdloc(var2)) { - pos += 3; - fixedStmtInitializer.Operand = pointerVar; - return true; - } - return false; - } - #endregion - - #region SimplifyLogicNot - static bool SimplifyLogicNot(List body, ILExpression expr, int pos) - { - bool modified = false; - expr = SimplifyLogicNot(expr, ref modified); - Debug.Assert(expr == null); - return modified; - } - - static ILExpression SimplifyLogicNot(ILExpression expr, ref bool modified) - { - ILExpression a; - // "ceq(a, ldc.i4.0)" becomes "logicnot(a)" if the inferred type for expression "a" is boolean - if (expr.Code == ILCode.Ceq && TypeAnalysis.IsBoolean(expr.Arguments[0].InferredType) && (a = expr.Arguments[1]).Code == ILCode.Ldc_I4 && (int)a.Operand == 0) { - expr.Code = ILCode.LogicNot; - expr.ILRanges.AddRange(a.ILRanges); - expr.Arguments.RemoveAt(1); - modified = true; - } - - ILExpression res = null; - while (expr.Code == ILCode.LogicNot) { - a = expr.Arguments[0]; - // remove double negation - if (a.Code == ILCode.LogicNot) { - res = a.Arguments[0]; - res.ILRanges.AddRange(expr.ILRanges); - res.ILRanges.AddRange(a.ILRanges); - expr = res; - } else { - if (SimplifyLogicNotArgument(expr)) res = expr = a; - break; - } - } - - for (int i = 0; i < expr.Arguments.Count; i++) { - a = SimplifyLogicNot(expr.Arguments[i], ref modified); - if (a != null) { - expr.Arguments[i] = a; - modified = true; - } - } - - return res; - } - - /// - /// If the argument is a binary comparison operation then the negation is pushed through it - /// - static bool SimplifyLogicNotArgument(ILExpression expr) - { - var a = expr.Arguments[0]; - ILCode c; - switch (a.Code) { - case ILCode.Ceq: c = ILCode.Cne; break; - case ILCode.Cne: c = ILCode.Ceq; break; - case ILCode.Cgt: c = ILCode.Cle; break; - case ILCode.Cgt_Un: c = ILCode.Cle_Un; break; - case ILCode.Cge: c = ILCode.Clt; break; - case ILCode.Cge_Un: c = ILCode.Clt_Un; break; - case ILCode.Clt: c = ILCode.Cge; break; - case ILCode.Clt_Un: c = ILCode.Cge_Un; break; - case ILCode.Cle: c = ILCode.Cgt; break; - case ILCode.Cle_Un: c = ILCode.Cgt_Un; break; - default: return false; - } - a.Code = c; - a.ILRanges.AddRange(expr.ILRanges); - return true; - } - #endregion - - #region SimplifyShiftOperators - static bool SimplifyShiftOperators(List body, ILExpression expr, int pos) - { - // C# compiles "a << b" to "a << (b & 31)", so we will remove the "& 31" if possible. - bool modified = false; - SimplifyShiftOperators(expr, ref modified); - return modified; - } - - static void SimplifyShiftOperators(ILExpression expr, ref bool modified) - { - for (int i = 0; i < expr.Arguments.Count; i++) - SimplifyShiftOperators(expr.Arguments[i], ref modified); - if (expr.Code != ILCode.Shl && expr.Code != ILCode.Shr && expr.Code != ILCode.Shr_Un) - return; - var a = expr.Arguments[1]; - if (a.Code != ILCode.And || a.Arguments[1].Code != ILCode.Ldc_I4 || expr.InferredType == null) - return; - int mask; - switch (expr.InferredType.MetadataType) { - case MetadataType.Int32: - case MetadataType.UInt32: mask = 31; break; - case MetadataType.Int64: - case MetadataType.UInt64: mask = 63; break; - default: return; - } - if ((int)a.Arguments[1].Operand != mask) return; - var res = a.Arguments[0]; - res.ILRanges.AddRange(a.ILRanges); - res.ILRanges.AddRange(a.Arguments[1].ILRanges); - expr.Arguments[1] = res; - modified = true; - } - #endregion - - #region InlineExpressionTreeParameterDeclarations - bool InlineExpressionTreeParameterDeclarations(List body, ILExpression expr, int pos) - { - // When there is a Expression.Lambda() call, and the parameters are declared in the - // IL statement immediately prior to the one containing the Lambda() call, - // using this code for the3 declaration: - // stloc(v, call(Expression::Parameter, call(Type::GetTypeFromHandle, ldtoken(...)), ldstr(...))) - // and the variables v are assigned only once (in that statements), and read only in a Expression::Lambda - // call that immediately follows the assignment statements, then we will inline those assignments - // into the Lambda call using ILCode.ExpressionTreeParameterDeclarations. - - // This is sufficient to allow inlining over the expression tree construction. The remaining translation - // of expression trees into C# will be performed by a C# AST transformer. - - for (int i = expr.Arguments.Count - 1; i >= 0; i--) { - if (InlineExpressionTreeParameterDeclarations(body, expr.Arguments[i], pos)) - return true; - } - - MethodReference mr; - ILExpression lambdaBodyExpr, parameterArray; - if (!(expr.Match(ILCode.Call, out mr, out lambdaBodyExpr, out parameterArray) && mr.Name == "Lambda")) - return false; - if (!(parameterArray.Code == ILCode.InitArray && mr.DeclaringType.FullName == "System.Linq.Expressions.Expression")) - return false; - int firstParameterPos = pos - parameterArray.Arguments.Count; - if (firstParameterPos < 0) - return false; - - ILExpression[] parameterInitExpressions = new ILExpression[parameterArray.Arguments.Count + 1]; - for (int i = 0; i < parameterArray.Arguments.Count; i++) { - parameterInitExpressions[i] = body[firstParameterPos + i] as ILExpression; - if (!MatchParameterVariableAssignment(parameterInitExpressions[i])) - return false; - ILVariable v = (ILVariable)parameterInitExpressions[i].Operand; - if (!parameterArray.Arguments[i].MatchLdloc(v)) - return false; - // TODO: validate that the variable is only used here and within 'body' - } - - parameterInitExpressions[parameterInitExpressions.Length - 1] = lambdaBodyExpr; - Debug.Assert(expr.Arguments[0] == lambdaBodyExpr); - expr.Arguments[0] = new ILExpression(ILCode.ExpressionTreeParameterDeclarations, null, parameterInitExpressions); - - body.RemoveRange(firstParameterPos, parameterArray.Arguments.Count); - - return true; - } - - bool MatchParameterVariableAssignment(ILExpression expr) - { - // stloc(v, call(Expression::Parameter, call(Type::GetTypeFromHandle, ldtoken(...)), ldstr(...))) - ILVariable v; - ILExpression init; - if (!expr.Match(ILCode.Stloc, out v, out init)) - return false; - if (v.IsGenerated || v.IsParameter || v.IsPinned) - return false; - if (v.Type == null || v.Type.FullName != "System.Linq.Expressions.ParameterExpression") - return false; - MethodReference parameterMethod; - ILExpression typeArg, nameArg; - if (!init.Match(ILCode.Call, out parameterMethod, out typeArg, out nameArg)) - return false; - if (!(parameterMethod.Name == "Parameter" && parameterMethod.DeclaringType.FullName == "System.Linq.Expressions.Expression")) - return false; - MethodReference getTypeFromHandle; - ILExpression typeToken; - if (!typeArg.Match(ILCode.Call, out getTypeFromHandle, out typeToken)) - return false; - if (!(getTypeFromHandle.Name == "GetTypeFromHandle" && getTypeFromHandle.DeclaringType.FullName == "System.Type")) - return false; - return typeToken.Code == ILCode.Ldtoken && nameArg.Code == ILCode.Ldstr; - } - #endregion - } -} diff --git a/ICSharpCode.Decompiler/ILAst/SimpleControlFlow.cs b/ICSharpCode.Decompiler/ILAst/SimpleControlFlow.cs deleted file mode 100644 index d3a74a37..00000000 --- a/ICSharpCode.Decompiler/ILAst/SimpleControlFlow.cs +++ /dev/null @@ -1,376 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; - -using Mono.Cecil; - -namespace ICSharpCode.Decompiler.ILAst -{ - public class SimpleControlFlow - { - Dictionary labelGlobalRefCount = new Dictionary(); - Dictionary labelToBasicBlock = new Dictionary(); - - DecompilerContext context; - TypeSystem typeSystem; - - public SimpleControlFlow(DecompilerContext context, ILBlock method) - { - this.context = context; - typeSystem = context.CurrentMethod.Module.TypeSystem; - - foreach(ILLabel target in method.GetSelfAndChildrenRecursive(e => e.IsBranch()).SelectMany(e => e.GetBranchTargets())) { - labelGlobalRefCount[target] = labelGlobalRefCount.GetOrDefault(target) + 1; - } - foreach(ILBasicBlock bb in method.GetSelfAndChildrenRecursive()) { - foreach(ILLabel label in bb.GetChildren().OfType()) { - labelToBasicBlock[label] = bb; - } - } - } - - public bool SimplifyTernaryOperator(List body, ILBasicBlock head, int pos) - { - Debug.Assert(body.Contains(head)); - - ILExpression condExpr; - ILLabel trueLabel; - ILLabel falseLabel; - ILVariable trueLocVar = null; - ILExpression trueExpr; - ILLabel trueFall; - ILVariable falseLocVar = null; - ILExpression falseExpr; - ILLabel falseFall; - object unused; - - if (head.MatchLastAndBr(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel) && - labelGlobalRefCount[trueLabel] == 1 && - labelGlobalRefCount[falseLabel] == 1 && - ((labelToBasicBlock[trueLabel].MatchSingleAndBr(ILCode.Stloc, out trueLocVar, out trueExpr, out trueFall) && - labelToBasicBlock[falseLabel].MatchSingleAndBr(ILCode.Stloc, out falseLocVar, out falseExpr, out falseFall) && - trueLocVar == falseLocVar && trueFall == falseFall) || - (labelToBasicBlock[trueLabel].MatchSingle(ILCode.Ret, out unused, out trueExpr) && - labelToBasicBlock[falseLabel].MatchSingle(ILCode.Ret, out unused, out falseExpr))) && - body.Contains(labelToBasicBlock[trueLabel]) && - body.Contains(labelToBasicBlock[falseLabel]) - ) - { - bool isStloc = trueLocVar != null; - ILCode opCode = isStloc ? ILCode.Stloc : ILCode.Ret; - TypeReference retType = isStloc ? trueLocVar.Type : context.CurrentMethod.ReturnType; - bool retTypeIsBoolean = TypeAnalysis.IsBoolean(retType); - int leftBoolVal; - int rightBoolVal; - ILExpression newExpr; - // a ? true:false is equivalent to a - // a ? false:true is equivalent to !a - // a ? true : b is equivalent to a || b - // a ? b : true is equivalent to !a || b - // a ? b : false is equivalent to a && b - // a ? false : b is equivalent to !a && b - if (retTypeIsBoolean && - trueExpr.Match(ILCode.Ldc_I4, out leftBoolVal) && - falseExpr.Match(ILCode.Ldc_I4, out rightBoolVal) && - ((leftBoolVal != 0 && rightBoolVal == 0) || (leftBoolVal == 0 && rightBoolVal != 0)) - ) - { - // It can be expressed as trivilal expression - if (leftBoolVal != 0) { - newExpr = condExpr; - } else { - newExpr = new ILExpression(ILCode.LogicNot, null, condExpr) { InferredType = typeSystem.Boolean }; - } - } else if ((retTypeIsBoolean || TypeAnalysis.IsBoolean(falseExpr.InferredType)) && trueExpr.Match(ILCode.Ldc_I4, out leftBoolVal) && (leftBoolVal == 0 || leftBoolVal == 1)) { - // It can be expressed as logical expression - if (leftBoolVal != 0) { - newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicOr, condExpr, falseExpr); - } else { - newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicAnd, new ILExpression(ILCode.LogicNot, null, condExpr), falseExpr); - } - } else if ((retTypeIsBoolean || TypeAnalysis.IsBoolean(trueExpr.InferredType)) && falseExpr.Match(ILCode.Ldc_I4, out rightBoolVal) && (rightBoolVal == 0 || rightBoolVal == 1)) { - // It can be expressed as logical expression - if (rightBoolVal != 0) { - newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicOr, new ILExpression(ILCode.LogicNot, null, condExpr), trueExpr); - } else { - newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicAnd, condExpr, trueExpr); - } - } else { - // Ternary operator tends to create long complicated return statements - if (opCode == ILCode.Ret) - return false; - - // Only simplify generated variables - if (opCode == ILCode.Stloc && !trueLocVar.IsGenerated) - return false; - - // Create ternary expression - newExpr = new ILExpression(ILCode.TernaryOp, null, condExpr, trueExpr, falseExpr); - } - - head.Body.RemoveTail(ILCode.Brtrue, ILCode.Br); - head.Body.Add(new ILExpression(opCode, trueLocVar, newExpr)); - if (isStloc) - head.Body.Add(new ILExpression(ILCode.Br, trueFall)); - - // Remove the old basic blocks - body.RemoveOrThrow(labelToBasicBlock[trueLabel]); - body.RemoveOrThrow(labelToBasicBlock[falseLabel]); - - return true; - } - return false; - } - - public bool SimplifyNullCoalescing(List body, ILBasicBlock head, int pos) - { - // ... - // v = ldloc(leftVar) - // brtrue(endBBLabel, ldloc(leftVar)) - // br(rightBBLabel) - // - // rightBBLabel: - // v = rightExpr - // br(endBBLabel) - // ... - // => - // ... - // v = NullCoalescing(ldloc(leftVar), rightExpr) - // br(endBBLabel) - - ILVariable v, v2; - ILExpression leftExpr, leftExpr2; - ILVariable leftVar; - ILLabel endBBLabel, endBBLabel2; - ILLabel rightBBLabel; - ILBasicBlock rightBB; - ILExpression rightExpr; - if (head.Body.Count >= 3 && - head.Body[head.Body.Count - 3].Match(ILCode.Stloc, out v, out leftExpr) && - leftExpr.Match(ILCode.Ldloc, out leftVar) && - head.MatchLastAndBr(ILCode.Brtrue, out endBBLabel, out leftExpr2, out rightBBLabel) && - leftExpr2.MatchLdloc(leftVar) && - labelToBasicBlock.TryGetValue(rightBBLabel, out rightBB) && - rightBB.MatchSingleAndBr(ILCode.Stloc, out v2, out rightExpr, out endBBLabel2) && - v == v2 && - endBBLabel == endBBLabel2 && - labelGlobalRefCount.GetOrDefault(rightBBLabel) == 1 && - body.Contains(rightBB) - ) - { - head.Body.RemoveTail(ILCode.Stloc, ILCode.Brtrue, ILCode.Br); - head.Body.Add(new ILExpression(ILCode.Stloc, v, new ILExpression(ILCode.NullCoalescing, null, leftExpr, rightExpr))); - head.Body.Add(new ILExpression(ILCode.Br, endBBLabel)); - - body.RemoveOrThrow(labelToBasicBlock[rightBBLabel]); - return true; - } - return false; - } - - public bool SimplifyShortCircuit(List body, ILBasicBlock head, int pos) - { - Debug.Assert(body.Contains(head)); - - ILExpression condExpr; - ILLabel trueLabel; - ILLabel falseLabel; - if(head.MatchLastAndBr(ILCode.Brtrue, out trueLabel, out condExpr, out falseLabel)) { - for (int pass = 0; pass < 2; pass++) { - - // On the second pass, swap labels and negate expression of the first branch - // It is slightly ugly, but much better then copy-pasting this whole block - ILLabel nextLabel = (pass == 0) ? trueLabel : falseLabel; - ILLabel otherLablel = (pass == 0) ? falseLabel : trueLabel; - bool negate = (pass == 1); - - ILBasicBlock nextBasicBlock = labelToBasicBlock[nextLabel]; - ILExpression nextCondExpr; - ILLabel nextTrueLablel; - ILLabel nextFalseLabel; - if (body.Contains(nextBasicBlock) && - nextBasicBlock != head && - labelGlobalRefCount[(ILLabel)nextBasicBlock.Body.First()] == 1 && - nextBasicBlock.MatchSingleAndBr(ILCode.Brtrue, out nextTrueLablel, out nextCondExpr, out nextFalseLabel) && - (otherLablel == nextFalseLabel || otherLablel == nextTrueLablel)) - { - // Create short cicuit branch - ILExpression logicExpr; - if (otherLablel == nextFalseLabel) { - logicExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicAnd, negate ? new ILExpression(ILCode.LogicNot, null, condExpr) : condExpr, nextCondExpr); - } else { - logicExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicOr, negate ? condExpr : new ILExpression(ILCode.LogicNot, null, condExpr), nextCondExpr); - } - head.Body.RemoveTail(ILCode.Brtrue, ILCode.Br); - head.Body.Add(new ILExpression(ILCode.Brtrue, nextTrueLablel, logicExpr)); - head.Body.Add(new ILExpression(ILCode.Br, nextFalseLabel)); - - // Remove the inlined branch from scope - body.RemoveOrThrow(nextBasicBlock); - - return true; - } - } - } - return false; - } - - public bool SimplifyCustomShortCircuit(List body, ILBasicBlock head, int pos) - { - Debug.Assert(body.Contains(head)); - - // --- looking for the following pattern --- - // stloc(targetVar, leftVar) - // brtrue(exitLabel, call(op_False, leftVar) - // br(followingBlock) - // - // FollowingBlock: - // stloc(targetVar, call(op_BitwiseAnd, leftVar, rightExpression)) - // br(exitLabel) - // --- - - if (head.Body.Count < 3) - return false; - - // looking for: - // stloc(targetVar, leftVar) - ILVariable targetVar; - ILExpression targetVarInitExpr; - if (!head.Body[head.Body.Count - 3].Match(ILCode.Stloc, out targetVar, out targetVarInitExpr)) - return false; - - ILVariable leftVar; - if (!targetVarInitExpr.Match(ILCode.Ldloc, out leftVar)) - return false; - - // looking for: - // brtrue(exitLabel, call(op_False, leftVar) - // br(followingBlock) - ILExpression callExpr; - ILLabel exitLabel; - ILLabel followingBlock; - if(!head.MatchLastAndBr(ILCode.Brtrue, out exitLabel, out callExpr, out followingBlock)) - return false; - - if (labelGlobalRefCount[followingBlock] > 1) - return false; - - MethodReference opFalse; - ILExpression opFalseArg; - if (!callExpr.Match(ILCode.Call, out opFalse, out opFalseArg)) - return false; - - // ignore operators other than op_False and op_True - if (opFalse.Name != "op_False" && opFalse.Name != "op_True") - return false; - - if (!opFalseArg.MatchLdloc(leftVar)) - return false; - - ILBasicBlock followingBasicBlock = labelToBasicBlock[followingBlock]; - - // FollowingBlock: - // stloc(targetVar, call(op_BitwiseAnd, leftVar, rightExpression)) - // br(exitLabel) - ILVariable _targetVar; - ILExpression opBitwiseCallExpr; - ILLabel _exitLabel; - if (!followingBasicBlock.MatchSingleAndBr(ILCode.Stloc, out _targetVar, out opBitwiseCallExpr, out _exitLabel)) - return false; - - if (_targetVar != targetVar || exitLabel != _exitLabel) - return false; - - MethodReference opBitwise; - ILExpression leftVarExpression; - ILExpression rightExpression; - if (!opBitwiseCallExpr.Match(ILCode.Call, out opBitwise, out leftVarExpression, out rightExpression)) - return false; - - if (!leftVarExpression.MatchLdloc(leftVar)) - return false; - - // ignore operators other than op_BitwiseAnd and op_BitwiseOr - if (opBitwise.Name != "op_BitwiseAnd" && opBitwise.Name != "op_BitwiseOr") - return false; - - // insert: - // stloc(targetVar, LogicAnd(C::op_BitwiseAnd, leftVar, rightExpression) - // br(exitLabel) - ILCode op = opBitwise.Name == "op_BitwiseAnd" ? ILCode.LogicAnd : ILCode.LogicOr; - - if (op == ILCode.LogicAnd && opFalse.Name != "op_False") - return false; - - if (op == ILCode.LogicOr && opFalse.Name != "op_True") - return false; - - ILExpression shortCircuitExpr = MakeLeftAssociativeShortCircuit(op, opFalseArg, rightExpression); - shortCircuitExpr.Operand = opBitwise; - - head.Body.RemoveTail(ILCode.Stloc, ILCode.Brtrue, ILCode.Br); - head.Body.Add(new ILExpression(ILCode.Stloc, targetVar, shortCircuitExpr)); - head.Body.Add(new ILExpression(ILCode.Br, exitLabel)); - body.Remove(followingBasicBlock); - - return true; - } - - ILExpression MakeLeftAssociativeShortCircuit(ILCode code, ILExpression left, ILExpression right) - { - // Assuming that the inputs are already left associative - if (right.Match(code)) { - // Find the leftmost logical expression - ILExpression current = right; - while(current.Arguments[0].Match(code)) - current = current.Arguments[0]; - current.Arguments[0] = new ILExpression(code, null, left, current.Arguments[0]) { InferredType = typeSystem.Boolean }; - return right; - } else { - return new ILExpression(code, null, left, right) { InferredType = typeSystem.Boolean }; - } - } - - public bool JoinBasicBlocks(List body, ILBasicBlock head, int pos) - { - ILLabel nextLabel; - ILBasicBlock nextBB; - if (!head.Body.ElementAtOrDefault(head.Body.Count - 2).IsConditionalControlFlow() && - head.Body.Last().Match(ILCode.Br, out nextLabel) && - labelGlobalRefCount[nextLabel] == 1 && - labelToBasicBlock.TryGetValue(nextLabel, out nextBB) && - body.Contains(nextBB) && - nextBB.Body.First() == nextLabel && - !nextBB.Body.OfType().Any() - ) - { - head.Body.RemoveTail(ILCode.Br); - nextBB.Body.RemoveAt(0); // Remove label - head.Body.AddRange(nextBB.Body); - - body.RemoveOrThrow(nextBB); - return true; - } - return false; - } - } -} diff --git a/ICSharpCode.Decompiler/ILAst/StateRange.cs b/ICSharpCode.Decompiler/ILAst/StateRange.cs deleted file mode 100644 index ef27c498..00000000 --- a/ICSharpCode.Decompiler/ILAst/StateRange.cs +++ /dev/null @@ -1,312 +0,0 @@ -// Copyright (c) 2012 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using Mono.Cecil; - -namespace ICSharpCode.Decompiler.ILAst -{ - internal struct Interval - { - public readonly int Start, End; - - public Interval(int start, int end) - { - Debug.Assert(start <= end || (start == 0 && end == -1)); - Start = start; - End = end; - } - - public override string ToString() - { - return string.Format("({0} to {1})", Start, End); - } - } - - internal class StateRange - { - readonly List data = new List(); - - public StateRange() - { - } - - public StateRange(int start, int end) - { - data.Add(new Interval(start, end)); - } - - public bool IsEmpty { - get { return data.Count == 0; } - } - - public bool Contains(int val) - { - foreach (Interval v in data) { - if (v.Start <= val && val <= v.End) - return true; - } - return false; - } - - public void UnionWith(StateRange other) - { - data.AddRange(other.data); - } - - /// - /// Unions this state range with (other intersect (minVal to maxVal)) - /// - public void UnionWith(StateRange other, int minVal, int maxVal) - { - foreach (Interval v in other.data) { - int start = Math.Max(v.Start, minVal); - int end = Math.Min(v.End, maxVal); - if (start <= end) - data.Add(new Interval(start, end)); - } - } - - /// - /// Merges overlapping interval ranges. - /// - public void Simplify() - { - if (data.Count < 2) - return; - data.Sort((a, b) => a.Start.CompareTo(b.Start)); - Interval prev = data[0]; - int prevIndex = 0; - for (int i = 1; i < data.Count; i++) { - Interval next = data[i]; - Debug.Assert(prev.Start <= next.Start); - if (next.Start <= prev.End + 1) { // intervals overlapping or touching - prev = new Interval(prev.Start, Math.Max(prev.End, next.End)); - data[prevIndex] = prev; - data[i] = new Interval(0, -1); // mark as deleted - } else { - prev = next; - prevIndex = i; - } - } - data.RemoveAll(i => i.Start > i.End); // remove all entries that were marked as deleted - } - - public override string ToString() - { - return string.Join(",", data); - } - - public Interval ToEnclosingInterval() - { - if (data.Count == 0) - throw new SymbolicAnalysisFailedException(); - return new Interval(data[0].Start, data[data.Count - 1].End); - } - } - - internal enum StateRangeAnalysisMode - { - IteratorMoveNext, - IteratorDispose, - AsyncMoveNext - } - - internal class StateRangeAnalysis - { - readonly StateRangeAnalysisMode mode; - readonly FieldDefinition stateField; - internal DefaultDictionary ranges; - SymbolicEvaluationContext evalContext; - - internal Dictionary finallyMethodToStateRange; // used only for IteratorDispose - - /// - /// Initializes the state range logic: - /// Clears 'ranges' and sets 'ranges[entryPoint]' to the full range (int.MinValue to int.MaxValue) - /// - public StateRangeAnalysis(ILNode entryPoint, StateRangeAnalysisMode mode, FieldDefinition stateField, ILVariable cachedStateVar = null) - { - this.mode = mode; - this.stateField = stateField; - if (mode == StateRangeAnalysisMode.IteratorDispose) { - finallyMethodToStateRange = new Dictionary(); - } - - ranges = new DefaultDictionary(n => new StateRange()); - ranges[entryPoint] = new StateRange(int.MinValue, int.MaxValue); - evalContext = new SymbolicEvaluationContext(stateField); - if (cachedStateVar != null) - evalContext.AddStateVariable(cachedStateVar); - } - - public int AssignStateRanges(List body, int bodyLength) - { - if (bodyLength == 0) - return 0; - for (int i = 0; i < bodyLength; i++) { - StateRange nodeRange = ranges[body[i]]; - nodeRange.Simplify(); - - ILLabel label = body[i] as ILLabel; - if (label != null) { - ranges[body[i + 1]].UnionWith(nodeRange); - continue; - } - - ILTryCatchBlock tryFinally = body[i] as ILTryCatchBlock; - if (tryFinally != null) { - if (mode == StateRangeAnalysisMode.IteratorDispose) { - if (tryFinally.CatchBlocks.Count != 0 || tryFinally.FaultBlock != null || tryFinally.FinallyBlock == null) - throw new SymbolicAnalysisFailedException(); - ranges[tryFinally.TryBlock].UnionWith(nodeRange); - if (tryFinally.TryBlock.Body.Count != 0) { - ranges[tryFinally.TryBlock.Body[0]].UnionWith(nodeRange); - AssignStateRanges(tryFinally.TryBlock.Body, tryFinally.TryBlock.Body.Count); - } - continue; - } else if (mode == StateRangeAnalysisMode.AsyncMoveNext) { - return i; - } else { - throw new SymbolicAnalysisFailedException(); - } - } - - ILExpression expr = body[i] as ILExpression; - if (expr == null) - throw new SymbolicAnalysisFailedException(); - switch (expr.Code) { - case ILCode.Switch: - { - SymbolicValue val = evalContext.Eval(expr.Arguments[0]); - if (val.Type != SymbolicValueType.State) - goto default; - ILLabel[] targetLabels = (ILLabel[])expr.Operand; - for (int j = 0; j < targetLabels.Length; j++) { - int state = j - val.Constant; - ranges[targetLabels[j]].UnionWith(nodeRange, state, state); - } - StateRange nextRange = ranges[body[i + 1]]; - nextRange.UnionWith(nodeRange, int.MinValue, -1 - val.Constant); - nextRange.UnionWith(nodeRange, targetLabels.Length - val.Constant, int.MaxValue); - break; - } - case ILCode.Br: - case ILCode.Leave: - ranges[(ILLabel)expr.Operand].UnionWith(nodeRange); - break; - case ILCode.Brtrue: - { - SymbolicValue val = evalContext.Eval(expr.Arguments[0]).AsBool(); - if (val.Type == SymbolicValueType.StateEquals) { - ranges[(ILLabel)expr.Operand].UnionWith(nodeRange, val.Constant, val.Constant); - StateRange nextRange = ranges[body[i + 1]]; - nextRange.UnionWith(nodeRange, int.MinValue, val.Constant - 1); - nextRange.UnionWith(nodeRange, val.Constant + 1, int.MaxValue); - break; - } else if (val.Type == SymbolicValueType.StateInEquals) { - ranges[body[i + 1]].UnionWith(nodeRange, val.Constant, val.Constant); - StateRange targetRange = ranges[(ILLabel)expr.Operand]; - targetRange.UnionWith(nodeRange, int.MinValue, val.Constant - 1); - targetRange.UnionWith(nodeRange, val.Constant + 1, int.MaxValue); - break; - } else { - goto default; - } - } - case ILCode.Nop: - ranges[body[i + 1]].UnionWith(nodeRange); - break; - case ILCode.Ret: - break; - case ILCode.Stloc: - { - SymbolicValue val = evalContext.Eval(expr.Arguments[0]); - if (val.Type == SymbolicValueType.State && val.Constant == 0) { - evalContext.AddStateVariable((ILVariable)expr.Operand); - goto case ILCode.Nop; - } else { - goto default; - } - } - case ILCode.Call: - // in some cases (e.g. foreach over array) the C# compiler produces a finally method outside of try-finally blocks - if (mode == StateRangeAnalysisMode.IteratorDispose) { - MethodDefinition mdef = (expr.Operand as MethodReference).ResolveWithinSameModule(); - if (mdef == null || finallyMethodToStateRange.ContainsKey(mdef)) - throw new SymbolicAnalysisFailedException(); - finallyMethodToStateRange.Add(mdef, nodeRange); - break; - } else { - goto default; - } - default: - if (mode == StateRangeAnalysisMode.IteratorDispose) { - throw new SymbolicAnalysisFailedException(); - } else { - return i; - } - } - } - return bodyLength; - } - - public void EnsureLabelAtPos(List body, ref int pos, ref int bodyLength) - { - if (pos > 0 && body[pos - 1] is ILLabel) { - pos--; - } else { - // ensure that the first element at body[pos] is a label: - ILLabel newLabel = new ILLabel(); - newLabel.Name = "YieldReturnEntryPoint"; - ranges[newLabel] = ranges[body[pos]]; // give the label the range of the instruction at body[pos] - body.Insert(pos, newLabel); - bodyLength++; - } - } - - public LabelRangeMapping CreateLabelRangeMapping(List body, int pos, int bodyLength) - { - LabelRangeMapping result = new LabelRangeMapping(); - CreateLabelRangeMapping(body, pos, bodyLength, result, false); - return result; - } - - void CreateLabelRangeMapping(List body, int pos, int bodyLength, LabelRangeMapping result, bool onlyInitialLabels) - { - for (int i = pos; i < bodyLength; i++) { - ILLabel label = body[i] as ILLabel; - if (label != null) { - result.Add(new KeyValuePair(label, ranges[label])); - } else { - ILTryCatchBlock tryCatchBlock = body[i] as ILTryCatchBlock; - if (tryCatchBlock != null) { - CreateLabelRangeMapping(tryCatchBlock.TryBlock.Body, 0, tryCatchBlock.TryBlock.Body.Count, result, true); - } else if (onlyInitialLabels) { - break; - } - } - } - } - } - - internal class LabelRangeMapping : List> {} -} diff --git a/ICSharpCode.Decompiler/ILAst/SymbolicExecution.cs b/ICSharpCode.Decompiler/ILAst/SymbolicExecution.cs deleted file mode 100644 index 76c57eb0..00000000 --- a/ICSharpCode.Decompiler/ILAst/SymbolicExecution.cs +++ /dev/null @@ -1,157 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using Mono.Cecil; - -namespace ICSharpCode.Decompiler.ILAst -{ - /// - /// This exception is thrown when we find something else than we expect from the C# compiler. - /// This aborts the analysis and makes the whole transform fail. - /// - internal class SymbolicAnalysisFailedException : Exception {} - - internal enum SymbolicValueType - { - /// - /// Unknown value - /// - Unknown, - /// - /// int: Constant (result of ldc.i4) - /// - IntegerConstant, - /// - /// int: State + Constant - /// - State, - /// - /// This pointer (result of ldarg.0) - /// - This, - /// - /// bool: State == Constant - /// - StateEquals, - /// - /// bool: State != Constant - /// - StateInEquals - } - - internal struct SymbolicValue - { - public readonly int Constant; - public readonly SymbolicValueType Type; - - public SymbolicValue(SymbolicValueType type, int constant = 0) - { - Type = type; - Constant = constant; - } - - public SymbolicValue AsBool() - { - if (Type == SymbolicValueType.State) { - // convert state integer to bool: - // if (state + c) = if (state + c != 0) = if (state != -c) - return new SymbolicValue(SymbolicValueType.StateInEquals, unchecked(-Constant)); - } - return this; - } - public override string ToString() - { - return string.Format("[SymbolicValue {0}: {1}]", Type, Constant); - } - } - - internal class SymbolicEvaluationContext - { - readonly FieldDefinition stateField; - readonly List stateVariables = new List(); - - public SymbolicEvaluationContext(FieldDefinition stateField) - { - this.stateField = stateField; - } - - public void AddStateVariable(ILVariable v) - { - if (!stateVariables.Contains(v)) - stateVariables.Add(v); - } - - SymbolicValue Failed() - { - return new SymbolicValue(SymbolicValueType.Unknown); - } - - public SymbolicValue Eval(ILExpression expr) - { - SymbolicValue left, right; - switch (expr.Code) { - case ILCode.Sub: - left = Eval(expr.Arguments[0]); - right = Eval(expr.Arguments[1]); - if (left.Type != SymbolicValueType.State && left.Type != SymbolicValueType.IntegerConstant) - return Failed(); - if (right.Type != SymbolicValueType.IntegerConstant) - return Failed(); - return new SymbolicValue(left.Type, unchecked ( left.Constant - right.Constant )); - case ILCode.Ldfld: - if (Eval(expr.Arguments[0]).Type != SymbolicValueType.This) - return Failed(); - if (CecilExtensions.ResolveWithinSameModule(expr.Operand as FieldReference) != stateField) - return Failed(); - return new SymbolicValue(SymbolicValueType.State); - case ILCode.Ldloc: - ILVariable loadedVariable = (ILVariable)expr.Operand; - if (stateVariables.Contains(loadedVariable)) - return new SymbolicValue(SymbolicValueType.State); - else if (loadedVariable.IsParameter && loadedVariable.OriginalParameter.Index < 0) - return new SymbolicValue(SymbolicValueType.This); - else - return Failed(); - case ILCode.Ldc_I4: - return new SymbolicValue(SymbolicValueType.IntegerConstant, (int)expr.Operand); - case ILCode.Ceq: - case ILCode.Cne: - left = Eval(expr.Arguments[0]); - right = Eval(expr.Arguments[1]); - if (left.Type != SymbolicValueType.State || right.Type != SymbolicValueType.IntegerConstant) - return Failed(); - // bool: (state + left.Constant == right.Constant) - // bool: (state == right.Constant - left.Constant) - return new SymbolicValue(expr.Code == ILCode.Ceq ? SymbolicValueType.StateEquals : SymbolicValueType.StateInEquals, unchecked(right.Constant - left.Constant)); - case ILCode.LogicNot: - SymbolicValue val = Eval(expr.Arguments[0]).AsBool(); - if (val.Type == SymbolicValueType.StateEquals) - return new SymbolicValue(SymbolicValueType.StateInEquals, val.Constant); - else if (val.Type == SymbolicValueType.StateInEquals) - return new SymbolicValue(SymbolicValueType.StateEquals, val.Constant); - else - return Failed(); - default: - return Failed(); - } - } - } -} diff --git a/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs b/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs deleted file mode 100644 index 1931d390..00000000 --- a/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs +++ /dev/null @@ -1,1294 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using Mono.Cecil; -using Mono.Cecil.Cil; - -namespace ICSharpCode.Decompiler.ILAst -{ - /// - /// Assigns C# types to IL expressions. - /// - /// - /// Types are inferred in a bidirectional manner: - /// The expected type flows from the outside to the inside, the actual inferred type flows from the inside to the outside. - /// - public class TypeAnalysis - { - public static void Run(DecompilerContext context, ILBlock method) - { - TypeAnalysis ta = new TypeAnalysis(); - ta.context = context; - ta.module = context.CurrentMethod.Module; - ta.typeSystem = ta.module.TypeSystem; - ta.method = method; - ta.CreateDependencyGraph(method); - ta.IdentifySingleLoadVariables(); - ta.RunInference(); - } - - sealed class ExpressionToInfer - { - public ILExpression Expression; - - public bool Done; - - /// - /// Set for assignment expressions that should wait until the variable type is available - /// from the context where the variable is used. - /// - public ILVariable DependsOnSingleLoad; - - /// - /// The list variables that are read by this expression. - /// - public List Dependencies = new List(); - - public override string ToString() - { - if (Done) - return "[Done] " + Expression.ToString(); - else - return Expression.ToString(); - } - - } - - DecompilerContext context; - TypeSystem typeSystem; - ILBlock method; - ModuleDefinition module; - List allExpressions = new List(); - DefaultDictionary> assignmentExpressions = new DefaultDictionary>(_ => new List()); - HashSet singleLoadVariables = new HashSet(); - - #region CreateDependencyGraph - /// - /// Creates the "ExpressionToInfer" instances (=nodes in dependency graph) - /// - /// - /// We are using a dependency graph to ensure that expressions are analyzed in the correct order. - /// - void CreateDependencyGraph(ILNode node) - { - ILCondition cond = node as ILCondition; - if (cond != null) { - cond.Condition.ExpectedType = typeSystem.Boolean; - } - ILWhileLoop loop = node as ILWhileLoop; - if (loop != null && loop.Condition != null) { - loop.Condition.ExpectedType = typeSystem.Boolean; - } - ILTryCatchBlock.CatchBlock catchBlock = node as ILTryCatchBlock.CatchBlock; - if (catchBlock != null && catchBlock.ExceptionVariable != null && catchBlock.ExceptionType != null && catchBlock.ExceptionVariable.Type == null) { - catchBlock.ExceptionVariable.Type = catchBlock.ExceptionType; - } - ILExpression expr = node as ILExpression; - if (expr != null) { - ExpressionToInfer expressionToInfer = new ExpressionToInfer(); - expressionToInfer.Expression = expr; - allExpressions.Add(expressionToInfer); - FindNestedAssignments(expr, expressionToInfer); - - if (expr.Code == ILCode.Stloc && ((ILVariable)expr.Operand).Type == null) - assignmentExpressions[(ILVariable)expr.Operand].Add(expressionToInfer); - return; - } - foreach (ILNode child in node.GetChildren()) { - CreateDependencyGraph(child); - } - } - - void FindNestedAssignments(ILExpression expr, ExpressionToInfer parent) - { - foreach (ILExpression arg in expr.Arguments) { - if (arg.Code == ILCode.Stloc) { - ExpressionToInfer expressionToInfer = new ExpressionToInfer(); - expressionToInfer.Expression = arg; - allExpressions.Add(expressionToInfer); - FindNestedAssignments(arg, expressionToInfer); - ILVariable v = (ILVariable)arg.Operand; - if (v.Type == null) { - assignmentExpressions[v].Add(expressionToInfer); - // the instruction that consumes the stloc result is handled as if it was reading the variable - parent.Dependencies.Add(v); - } - } else { - ILVariable v; - if (arg.Match(ILCode.Ldloc, out v) && v.Type == null) { - parent.Dependencies.Add(v); - } - FindNestedAssignments(arg, parent); - } - } - } - #endregion - - void IdentifySingleLoadVariables() - { - // Find all variables that are assigned to exactly a single time: - var q = from expr in allExpressions - from v in expr.Dependencies - group expr by v; - foreach (var g in q.ToArray()) { - ILVariable v = g.Key; - if (g.Count() == 1 && g.Single().Expression.GetSelfAndChildrenRecursive().Count(e => e.Operand == v) == 1) { - singleLoadVariables.Add(v); - // Mark the assignments as dependent on the type from the single load: - foreach (var assignment in assignmentExpressions[v]) { - assignment.DependsOnSingleLoad = v; - } - } - } - } - - void RunInference() - { - int numberOfExpressionsAlreadyInferred = 0; - // Two flags that allow resolving cycles: - bool ignoreSingleLoadDependencies = false; - bool assignVariableTypesBasedOnPartialInformation = false; - while (numberOfExpressionsAlreadyInferred < allExpressions.Count) { - int oldCount = numberOfExpressionsAlreadyInferred; - foreach (ExpressionToInfer expr in allExpressions) { - if (!expr.Done && expr.Dependencies.TrueForAll(v => v.Type != null || singleLoadVariables.Contains(v)) - && (expr.DependsOnSingleLoad == null || expr.DependsOnSingleLoad.Type != null || ignoreSingleLoadDependencies)) - { - RunInference(expr.Expression); - expr.Done = true; - numberOfExpressionsAlreadyInferred++; - } - } - if (numberOfExpressionsAlreadyInferred == oldCount) { - if (ignoreSingleLoadDependencies) { - if (assignVariableTypesBasedOnPartialInformation) - throw new InvalidOperationException("Could not infer any expression"); - else - assignVariableTypesBasedOnPartialInformation = true; - } else { - // We have a cyclic dependency; we'll try if we can resolve it by ignoring single-load dependencies. - // This can happen if the variable was not actually assigned an expected type by the single-load instruction. - ignoreSingleLoadDependencies = true; - continue; - } - } else { - assignVariableTypesBasedOnPartialInformation = false; - ignoreSingleLoadDependencies = false; - } - // Now infer types for variables: - foreach (var pair in assignmentExpressions) { - ILVariable v = pair.Key; - if (v.Type == null && (assignVariableTypesBasedOnPartialInformation ? pair.Value.Any(e => e.Done) : pair.Value.All(e => e.Done))) { - TypeReference inferredType = null; - foreach (ExpressionToInfer expr in pair.Value) { - Debug.Assert(expr.Expression.Code == ILCode.Stloc); - ILExpression assignedValue = expr.Expression.Arguments.Single(); - if (assignedValue.InferredType != null) { - if (inferredType == null) { - inferredType = assignedValue.InferredType; - } else { - // pick the common base type - inferredType = TypeWithMoreInformation(inferredType, assignedValue.InferredType); - } - } - } - if (inferredType == null) - inferredType = typeSystem.Object; - v.Type = inferredType; - // Assign inferred type to all the assignments (in case they used different inferred types): - foreach (ExpressionToInfer expr in pair.Value) { - expr.Expression.InferredType = inferredType; - // re-infer if the expected type has changed - InferTypeForExpression(expr.Expression.Arguments.Single(), inferredType); - } - } - } - } - } - - void RunInference(ILExpression expr) - { - bool anyArgumentIsMissingExpectedType = expr.Arguments.Any(a => a.ExpectedType == null); - if (expr.InferredType == null || anyArgumentIsMissingExpectedType) - InferTypeForExpression(expr, expr.ExpectedType, forceInferChildren: anyArgumentIsMissingExpectedType); - foreach (var arg in expr.Arguments) { - if (arg.Code != ILCode.Stloc) { - RunInference(arg); - } - } - } - - /// - /// Infers the C# type of . - /// - /// The expression - /// The expected type of the expression - /// Whether direct children should be inferred even if its not necessary. (does not apply to nested children!) - /// The inferred type - TypeReference InferTypeForExpression(ILExpression expr, TypeReference expectedType, bool forceInferChildren = false) - { - if (expectedType != null && !IsSameType(expr.ExpectedType, expectedType)) { - expr.ExpectedType = expectedType; - if (expr.Code != ILCode.Stloc) // stloc is special case and never gets re-evaluated - forceInferChildren = true; - } - if (forceInferChildren || expr.InferredType == null) - expr.InferredType = DoInferTypeForExpression(expr, expectedType, forceInferChildren); - return expr.InferredType; - } - - TypeReference DoInferTypeForExpression(ILExpression expr, TypeReference expectedType, bool forceInferChildren = false) - { - switch (expr.Code) { - #region Logical operators - case ILCode.LogicNot: - if (forceInferChildren) { - InferTypeForExpression(expr.Arguments.Single(), typeSystem.Boolean); - } - return typeSystem.Boolean; - case ILCode.LogicAnd: - case ILCode.LogicOr: - // if Operand is set the logic and/or expression is a custom operator - // we can deal with it the same as a normal invocation. - if (expr.Operand != null) - goto case ILCode.Call; - if (forceInferChildren) { - InferTypeForExpression(expr.Arguments[0], typeSystem.Boolean); - InferTypeForExpression(expr.Arguments[1], typeSystem.Boolean); - } - return typeSystem.Boolean; - case ILCode.TernaryOp: - if (forceInferChildren) { - InferTypeForExpression(expr.Arguments[0], typeSystem.Boolean); - } - return InferBinaryArguments(expr.Arguments[1], expr.Arguments[2], expectedType, forceInferChildren); - case ILCode.NullCoalescing: - return InferBinaryArguments(expr.Arguments[0], expr.Arguments[1], expectedType, forceInferChildren); - #endregion - #region Variable load/store - case ILCode.Stloc: - { - ILVariable v = (ILVariable)expr.Operand; - if (forceInferChildren) { - // do not use 'expectedType' in here! - InferTypeForExpression(expr.Arguments.Single(), v.Type); - } - return v.Type; - } - case ILCode.Ldloc: - { - ILVariable v = (ILVariable)expr.Operand; - if (v.Type == null && singleLoadVariables.Contains(v)) { - v.Type = expectedType; - } - return v.Type; - } - case ILCode.Ldloca: - { - ILVariable v = (ILVariable)expr.Operand; - if (v.Type != null) - return new ByReferenceType(v.Type); - else - return null; - } - #endregion - #region Call / NewObj - case ILCode.Call: - case ILCode.Callvirt: - case ILCode.CallGetter: - case ILCode.CallvirtGetter: - case ILCode.CallSetter: - case ILCode.CallvirtSetter: - { - MethodReference method = (MethodReference)expr.Operand; - if (forceInferChildren) { - for (int i = 0; i < expr.Arguments.Count; i++) { - if (i == 0 && method.HasThis) { - InferTypeForExpression(expr.Arguments[0], MakeRefIfValueType(method.DeclaringType, expr.GetPrefix(ILCode.Constrained))); - } else { - InferTypeForExpression(expr.Arguments[i], SubstituteTypeArgs(method.Parameters[method.HasThis ? i - 1 : i].ParameterType, method)); - } - } - } - if (expr.Code == ILCode.CallSetter || expr.Code == ILCode.CallvirtSetter) { - return SubstituteTypeArgs(method.Parameters.Last().ParameterType, method); - } else { - return SubstituteTypeArgs(method.ReturnType, method); - } - } - case ILCode.Newobj: - { - MethodReference ctor = (MethodReference)expr.Operand; - if (forceInferChildren) { - for (int i = 0; i < ctor.Parameters.Count; i++) { - InferTypeForExpression(expr.Arguments[i], SubstituteTypeArgs(ctor.Parameters[i].ParameterType, ctor)); - } - } - return ctor.DeclaringType; - } - case ILCode.InitObject: - case ILCode.InitCollection: - return InferTypeForExpression(expr.Arguments[0], expectedType); - case ILCode.InitializedObject: - // expectedType should always be known due to the parent method call / property setter - Debug.Assert(expectedType != null); - return expectedType; - #endregion - #region Load/Store Fields - case ILCode.Ldfld: - if (forceInferChildren) { - InferTypeForExpression(expr.Arguments[0], MakeRefIfValueType(((FieldReference)expr.Operand).DeclaringType, expr.GetPrefix(ILCode.Constrained))); - } - return GetFieldType((FieldReference)expr.Operand); - case ILCode.Ldsfld: - return GetFieldType((FieldReference)expr.Operand); - case ILCode.Ldflda: - if (forceInferChildren) { - InferTypeForExpression(expr.Arguments[0], MakeRefIfValueType(((FieldReference)expr.Operand).DeclaringType, expr.GetPrefix(ILCode.Constrained))); - } - return new ByReferenceType(GetFieldType((FieldReference)expr.Operand)); - case ILCode.Ldsflda: - return new ByReferenceType(GetFieldType((FieldReference)expr.Operand)); - case ILCode.Stfld: - if (forceInferChildren) { - InferTypeForExpression(expr.Arguments[0], MakeRefIfValueType(((FieldReference)expr.Operand).DeclaringType, expr.GetPrefix(ILCode.Constrained))); - InferTypeForExpression(expr.Arguments[1], GetFieldType((FieldReference)expr.Operand)); - } - return GetFieldType((FieldReference)expr.Operand); - case ILCode.Stsfld: - if (forceInferChildren) - InferTypeForExpression(expr.Arguments[0], GetFieldType((FieldReference)expr.Operand)); - return GetFieldType((FieldReference)expr.Operand); - #endregion - #region Reference/Pointer instructions - case ILCode.Ldind_Ref: - return UnpackPointer(InferTypeForExpression(expr.Arguments[0], null)); - case ILCode.Stind_Ref: - if (forceInferChildren) { - TypeReference elementType = UnpackPointer(InferTypeForExpression(expr.Arguments[0], null)); - InferTypeForExpression(expr.Arguments[1], elementType); - } - return null; - case ILCode.Ldobj: - { - TypeReference type = (TypeReference)expr.Operand; - var argType = InferTypeForExpression(expr.Arguments[0], null); - if (argType is PointerType || argType is ByReferenceType) { - var elementType = ((TypeSpecification)argType).ElementType; - int infoAmount = GetInformationAmount(elementType); - if (infoAmount == 1 && GetInformationAmount(type) == 8) { - // A bool can be loaded from both bytes and sbytes. - type = elementType; - } - if (infoAmount >= 8 && infoAmount <= 64 && infoAmount == GetInformationAmount(type)) { - // An integer can be loaded as another integer of the same size. - // For integers smaller than 32 bit, the signs must match (as loading performs sign extension) - bool? elementTypeIsSigned = IsSigned(elementType); - bool? typeIsSigned = IsSigned(type); - if (elementTypeIsSigned != null && typeIsSigned != null) { - if (infoAmount >= 32 || elementTypeIsSigned == typeIsSigned) - type = elementType; - } - } - } - if (argType is PointerType) - InferTypeForExpression(expr.Arguments[0], new PointerType(type)); - else - InferTypeForExpression(expr.Arguments[0], new ByReferenceType(type)); - return type; - } - case ILCode.Stobj: - { - TypeReference operandType = (TypeReference)expr.Operand; - TypeReference pointerType = InferTypeForExpression(expr.Arguments[0], new ByReferenceType(operandType)); - TypeReference elementType; - if (pointerType is PointerType) - elementType = ((PointerType)pointerType).ElementType; - else if (pointerType is ByReferenceType) - elementType = ((ByReferenceType)pointerType).ElementType; - else - elementType = null; - if (elementType != null) { - // An integer can be stored in any other integer of the same size. - int infoAmount = GetInformationAmount(elementType); - if (infoAmount == 1 && GetInformationAmount(operandType) == 8) - operandType = elementType; - else if (infoAmount == GetInformationAmount(operandType) && IsSigned(elementType) != null && IsSigned(operandType) != null) - operandType = elementType; - } - if (forceInferChildren) { - if (pointerType is PointerType) - InferTypeForExpression(expr.Arguments[0], new PointerType(operandType)); - else if (!IsSameType(operandType, expr.Operand as TypeReference)) - InferTypeForExpression(expr.Arguments[0], new ByReferenceType(operandType)); - InferTypeForExpression(expr.Arguments[1], operandType); - } - return operandType; - } - case ILCode.Initobj: - return null; - case ILCode.DefaultValue: - return (TypeReference)expr.Operand; - case ILCode.Localloc: - if (forceInferChildren) { - InferTypeForExpression(expr.Arguments[0], null); - } - if (expectedType is PointerType) - return expectedType; - else - return typeSystem.IntPtr; - case ILCode.Sizeof: - return typeSystem.Int32; - case ILCode.PostIncrement: - case ILCode.PostIncrement_Ovf: - case ILCode.PostIncrement_Ovf_Un: - { - TypeReference elementType = UnpackPointer(InferTypeForExpression(expr.Arguments[0], null)); - if (forceInferChildren && elementType != null) { - // Assign expected type to the child expression - InferTypeForExpression(expr.Arguments[0], new ByReferenceType(elementType)); - } - return elementType; - } - case ILCode.Mkrefany: - if (forceInferChildren) { - 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.TypeSystem.Corlib, true); - case ILCode.Refanyval: - if (forceInferChildren) { - InferTypeForExpression(expr.Arguments[0], typeSystem.TypedReference); - } - return new ByReferenceType((TypeReference)expr.Operand); - case ILCode.AddressOf: - { - TypeReference t = InferTypeForExpression(expr.Arguments[0], UnpackPointer(expectedType)); - return t != null ? new ByReferenceType(t) : null; - } - case ILCode.ValueOf: - return GetNullableTypeArgument(InferTypeForExpression(expr.Arguments[0], CreateNullableType(expectedType))); - case ILCode.NullableOf: - return CreateNullableType(InferTypeForExpression(expr.Arguments[0], GetNullableTypeArgument(expectedType))); - #endregion - #region Arithmetic instructions - case ILCode.Not: // bitwise complement - case ILCode.Neg: - return InferTypeForExpression(expr.Arguments.Single(), expectedType); - case ILCode.Add: - return InferArgumentsInAddition(expr, null, expectedType); - case ILCode.Sub: - return InferArgumentsInSubtraction(expr, null, expectedType); - case ILCode.Mul: - case ILCode.Or: - case ILCode.And: - case ILCode.Xor: - return InferArgumentsInBinaryOperator(expr, null, expectedType); - case ILCode.Add_Ovf: - return InferArgumentsInAddition(expr, true, expectedType); - case ILCode.Sub_Ovf: - return InferArgumentsInSubtraction(expr, true, expectedType); - case ILCode.Mul_Ovf: - case ILCode.Div: - case ILCode.Rem: - return InferArgumentsInBinaryOperator(expr, true, expectedType); - case ILCode.Add_Ovf_Un: - return InferArgumentsInAddition(expr, false, expectedType); - case ILCode.Sub_Ovf_Un: - return InferArgumentsInSubtraction(expr, false, expectedType); - case ILCode.Mul_Ovf_Un: - case ILCode.Div_Un: - case ILCode.Rem_Un: - return InferArgumentsInBinaryOperator(expr, false, expectedType); - case ILCode.Shl: - if (forceInferChildren) - InferTypeForExpression(expr.Arguments[1], typeSystem.Int32); - if (expectedType != null && ( - expectedType.MetadataType == MetadataType.Int32 || expectedType.MetadataType == MetadataType.UInt32 || - expectedType.MetadataType == MetadataType.Int64 || expectedType.MetadataType == MetadataType.UInt64) - ) - return NumericPromotion(InferTypeForExpression(expr.Arguments[0], expectedType)); - else - return NumericPromotion(InferTypeForExpression(expr.Arguments[0], null)); - case ILCode.Shr: - case ILCode.Shr_Un: - { - if (forceInferChildren) - InferTypeForExpression(expr.Arguments[1], typeSystem.Int32); - TypeReference type = NumericPromotion(InferTypeForExpression(expr.Arguments[0], null)); - if (type == null) - return null; - TypeReference expectedInputType = null; - switch (type.MetadataType) { - case MetadataType.Int32: - if (expr.Code == ILCode.Shr_Un) - expectedInputType = typeSystem.UInt32; - break; - case MetadataType.UInt32: - if (expr.Code == ILCode.Shr) - expectedInputType = typeSystem.Int32; - break; - case MetadataType.Int64: - if (expr.Code == ILCode.Shr_Un) - expectedInputType = typeSystem.UInt64; - break; - case MetadataType.UInt64: - if (expr.Code == ILCode.Shr) - expectedInputType = typeSystem.UInt64; - break; - } - if (expectedInputType != null) { - InferTypeForExpression(expr.Arguments[0], expectedInputType); - return expectedInputType; - } else { - return type; - } - } - case ILCode.CompoundAssignment: - { - var op = expr.Arguments[0]; - if (op.Code == ILCode.NullableOf) op = op.Arguments[0].Arguments[0]; - var varType = InferTypeForExpression(op.Arguments[0], null); - if (forceInferChildren) { - InferTypeForExpression(expr.Arguments[0], varType); - } - return varType; - } - #endregion - #region Constant loading instructions - case ILCode.Ldnull: - return typeSystem.Object; - case ILCode.Ldstr: - return typeSystem.String; - case ILCode.Ldftn: - case ILCode.Ldvirtftn: - return typeSystem.IntPtr; - case ILCode.Ldc_I4: - if (IsBoolean(expectedType) && ((int)expr.Operand == 0 || (int)expr.Operand == 1)) - return typeSystem.Boolean; - if (expectedType is PointerType && (int)expr.Operand == 0) - return expectedType; - if (IsIntegerOrEnum(expectedType) && OperandFitsInType(expectedType, (int)expr.Operand)) - return expectedType; - else - return typeSystem.Int32; - case ILCode.Ldc_I8: - if (expectedType is PointerType && (long)expr.Operand == 0) - return expectedType; - if (IsIntegerOrEnum(expectedType) && GetInformationAmount(expectedType) >= NativeInt) - return expectedType; - else - return typeSystem.Int64; - case ILCode.Ldc_R4: - return typeSystem.Single; - case ILCode.Ldc_R8: - return typeSystem.Double; - case ILCode.Ldc_Decimal: - return new TypeReference("System", "Decimal", module, module.TypeSystem.Corlib, true); - case ILCode.Ldtoken: - if (expr.Operand is TypeReference) - return new TypeReference("System", "RuntimeTypeHandle", module, module.TypeSystem.Corlib, true); - else if (expr.Operand is FieldReference) - return new TypeReference("System", "RuntimeFieldHandle", module, module.TypeSystem.Corlib, true); - else - return new TypeReference("System", "RuntimeMethodHandle", module, module.TypeSystem.Corlib, true); - case ILCode.Arglist: - return new TypeReference("System", "RuntimeArgumentHandle", module, module.TypeSystem.Corlib, true); - #endregion - #region Array instructions - case ILCode.Newarr: - if (forceInferChildren) { - var lengthType = InferTypeForExpression(expr.Arguments.Single(), null); - if (lengthType == typeSystem.IntPtr) { - lengthType = typeSystem.Int64; - } else if (lengthType == typeSystem.UIntPtr) { - lengthType = typeSystem.UInt64; - } else if (lengthType != typeSystem.UInt32 && lengthType != typeSystem.Int64 && lengthType != typeSystem.UInt64) { - lengthType = typeSystem.Int32; - } - if (forceInferChildren) { - InferTypeForExpression(expr.Arguments.Single(), lengthType); - } - } - return new ArrayType((TypeReference)expr.Operand); - case ILCode.InitArray: - var operandAsArrayType = (ArrayType)expr.Operand; - if (forceInferChildren) - { - foreach (ILExpression arg in expr.Arguments) - InferTypeForExpression(arg, operandAsArrayType.ElementType); - } - return operandAsArrayType; - case ILCode.Ldlen: - return typeSystem.Int32; - case ILCode.Ldelem_U1: - case ILCode.Ldelem_U2: - case ILCode.Ldelem_U4: - case ILCode.Ldelem_I1: - case ILCode.Ldelem_I2: - case ILCode.Ldelem_I4: - case ILCode.Ldelem_I8: - case ILCode.Ldelem_R4: - case ILCode.Ldelem_R8: - case ILCode.Ldelem_I: - case ILCode.Ldelem_Ref: - { - ArrayType arrayType = InferTypeForExpression(expr.Arguments[0], null) as ArrayType; - if (forceInferChildren) { - InferTypeForExpression(expr.Arguments[1], typeSystem.Int32); - } - return arrayType != null ? arrayType.ElementType : null; - } - case ILCode.Ldelem_Any: - if (forceInferChildren) { - InferTypeForExpression(expr.Arguments[1], typeSystem.Int32); - } - return (TypeReference)expr.Operand; - case ILCode.Ldelema: - { - ArrayType arrayType = InferTypeForExpression(expr.Arguments[0], null) as ArrayType; - if (forceInferChildren) - InferTypeForExpression(expr.Arguments[1], typeSystem.Int32); - return arrayType != null ? new ByReferenceType(arrayType.ElementType) : null; - } - case ILCode.Stelem_I: - case ILCode.Stelem_I1: - case ILCode.Stelem_I2: - case ILCode.Stelem_I4: - case ILCode.Stelem_I8: - case ILCode.Stelem_R4: - case ILCode.Stelem_R8: - case ILCode.Stelem_Ref: - case ILCode.Stelem_Any: - { - ArrayType arrayType = InferTypeForExpression(expr.Arguments[0], null) as ArrayType; - if (forceInferChildren) { - InferTypeForExpression(expr.Arguments[1], typeSystem.Int32); - if (arrayType != null) { - InferTypeForExpression(expr.Arguments[2], arrayType.ElementType); - } - } - return arrayType != null ? arrayType.ElementType : null; - } - #endregion - #region Conversion instructions - case ILCode.Conv_I1: - case ILCode.Conv_Ovf_I1: - case ILCode.Conv_Ovf_I1_Un: - return HandleConversion(8, true, expr.Arguments[0], expectedType, typeSystem.SByte); - case ILCode.Conv_I2: - case ILCode.Conv_Ovf_I2: - case ILCode.Conv_Ovf_I2_Un: - return HandleConversion(16, true, expr.Arguments[0], expectedType, typeSystem.Int16); - case ILCode.Conv_I4: - case ILCode.Conv_Ovf_I4: - case ILCode.Conv_Ovf_I4_Un: - return HandleConversion(32, true, expr.Arguments[0], expectedType, typeSystem.Int32); - case ILCode.Conv_I8: - case ILCode.Conv_Ovf_I8: - case ILCode.Conv_Ovf_I8_Un: - return HandleConversion(64, true, expr.Arguments[0], expectedType, typeSystem.Int64); - case ILCode.Conv_U1: - case ILCode.Conv_Ovf_U1: - case ILCode.Conv_Ovf_U1_Un: - return HandleConversion(8, false, expr.Arguments[0], expectedType, typeSystem.Byte); - case ILCode.Conv_U2: - case ILCode.Conv_Ovf_U2: - case ILCode.Conv_Ovf_U2_Un: - return HandleConversion(16, false, expr.Arguments[0], expectedType, typeSystem.UInt16); - case ILCode.Conv_U4: - case ILCode.Conv_Ovf_U4: - case ILCode.Conv_Ovf_U4_Un: - return HandleConversion(32, false, expr.Arguments[0], expectedType, typeSystem.UInt32); - case ILCode.Conv_U8: - case ILCode.Conv_Ovf_U8: - case ILCode.Conv_Ovf_U8_Un: - return HandleConversion(64, false, expr.Arguments[0], expectedType, typeSystem.UInt64); - case ILCode.Conv_I: - case ILCode.Conv_Ovf_I: - case ILCode.Conv_Ovf_I_Un: - return HandleConversion(NativeInt, true, expr.Arguments[0], expectedType, typeSystem.IntPtr); - case ILCode.Conv_U: - case ILCode.Conv_Ovf_U: - case ILCode.Conv_Ovf_U_Un: - return HandleConversion(NativeInt, false, expr.Arguments[0], expectedType, typeSystem.UIntPtr); - case ILCode.Conv_R4: - if (forceInferChildren) { - InferTypeForExpression(expr.Arguments[0], typeSystem.Single); - } - return typeSystem.Single; - case ILCode.Conv_R8: - if (forceInferChildren) { - InferTypeForExpression(expr.Arguments[0], typeSystem.Double); - } - return typeSystem.Double; - case ILCode.Conv_R_Un: - return (expectedType != null && expectedType.MetadataType == MetadataType.Single) ? typeSystem.Single : typeSystem.Double; - case ILCode.Castclass: - case ILCode.Unbox_Any: - return (TypeReference)expr.Operand; - case ILCode.Unbox: - return new ByReferenceType((TypeReference)expr.Operand); - case ILCode.Isinst: - { - // isinst performs the equivalent of a cast only for reference types; - // value types still need to be unboxed after an isinst instruction - TypeReference tr = (TypeReference)expr.Operand; - return tr.IsValueType ? typeSystem.Object : tr; - } - case ILCode.Box: - { - var tr = (TypeReference)expr.Operand; - if (forceInferChildren) - InferTypeForExpression(expr.Arguments.Single(), tr); - return tr.IsValueType ? typeSystem.Object : tr; - } - #endregion - #region Comparison instructions - case ILCode.Ceq: - case ILCode.Cne: - if (forceInferChildren) - InferArgumentsInBinaryOperator(expr, null, null); - return typeSystem.Boolean; - case ILCode.Clt: - case ILCode.Cgt: - case ILCode.Cle: - case ILCode.Cge: - if (forceInferChildren) - InferArgumentsInBinaryOperator(expr, true, null); - return typeSystem.Boolean; - case ILCode.Clt_Un: - case ILCode.Cgt_Un: - case ILCode.Cle_Un: - case ILCode.Cge_Un: - if (forceInferChildren) - InferArgumentsInBinaryOperator(expr, false, null); - return typeSystem.Boolean; - #endregion - #region Branch instructions - case ILCode.Brtrue: - if (forceInferChildren) - InferTypeForExpression(expr.Arguments.Single(), typeSystem.Boolean); - return null; - case ILCode.Br: - case ILCode.Leave: - case ILCode.Endfinally: - case ILCode.Switch: - case ILCode.Throw: - case ILCode.Rethrow: - case ILCode.LoopOrSwitchBreak: - case ILCode.LoopContinue: - case ILCode.YieldBreak: - return null; - case ILCode.Ret: - if (forceInferChildren && expr.Arguments.Count == 1) { - TypeReference returnType = context.CurrentMethod.ReturnType; - if (context.CurrentMethodIsAsync && returnType != null && returnType.Namespace == "System.Threading.Tasks") { - if (returnType.Name == "Task") { - returnType = typeSystem.Void; - } else if (returnType.Name == "Task`1" && returnType.IsGenericInstance) { - returnType = ((GenericInstanceType)returnType).GenericArguments[0]; - } - } - InferTypeForExpression(expr.Arguments[0], returnType); - } - return null; - case ILCode.YieldReturn: - if (forceInferChildren) { - GenericInstanceType genericType = context.CurrentMethod.ReturnType as GenericInstanceType; - if (genericType != null) { // IEnumerable or IEnumerator - InferTypeForExpression(expr.Arguments[0], genericType.GenericArguments[0]); - } else { // non-generic IEnumerable or IEnumerator - InferTypeForExpression(expr.Arguments[0], typeSystem.Object); - } - } - return null; - case ILCode.Await: - { - TypeReference taskType = InferTypeForExpression(expr.Arguments[0], null); - if (taskType != null && taskType.Name == "Task`1" && taskType.IsGenericInstance && taskType.Namespace == "System.Threading.Tasks") { - return ((GenericInstanceType)taskType).GenericArguments[0]; - } - return null; - } - #endregion - case ILCode.Pop: - return null; - case ILCode.Wrap: - case ILCode.Dup: - { - var arg = expr.Arguments.Single(); - return arg.ExpectedType = InferTypeForExpression(arg, expectedType); - } - default: - Debug.WriteLine("Type Inference: Can't handle " + expr.Code.GetName()); - return null; - } - } - - /// - /// Wraps 'type' in a ByReferenceType if it is a value type. If a constrained prefix is specified, - /// returns the constrained type wrapped in a ByReferenceType. - /// - TypeReference MakeRefIfValueType(TypeReference type, ILExpressionPrefix constrainedPrefix) - { - if (constrainedPrefix != null) - return new ByReferenceType((TypeReference)constrainedPrefix.Operand); - if (type.IsValueType) - return new ByReferenceType(type); - else - return type; - } - - /// - /// Promotes primitive types smaller than int32 to int32. - /// - /// - /// Always promotes to signed int32. - /// - TypeReference NumericPromotion(TypeReference type) - { - if (type == null) - return null; - switch (type.MetadataType) { - case MetadataType.SByte: - case MetadataType.Int16: - case MetadataType.Byte: - case MetadataType.UInt16: - return typeSystem.Int32; - default: - return type; - } - } - - TypeReference HandleConversion(int targetBitSize, bool targetSigned, ILExpression arg, TypeReference expectedType, TypeReference targetType) - { - if (targetBitSize >= NativeInt && expectedType is PointerType) { - InferTypeForExpression(arg, expectedType); - return expectedType; - } - TypeReference argType = InferTypeForExpression(arg, null); - if (targetBitSize >= NativeInt && argType is ByReferenceType) { - // conv instructions on managed references mean that the GC should stop tracking them, so they become pointers: - PointerType ptrType = new PointerType(((ByReferenceType)argType).ElementType); - InferTypeForExpression(arg, ptrType); - return ptrType; - } else if (targetBitSize >= NativeInt && argType is PointerType) { - return argType; - } - TypeReference resultType = (GetInformationAmount(expectedType) == targetBitSize && IsSigned(expectedType) == targetSigned) ? expectedType : targetType; - arg.ExpectedType = resultType; // store the expected type in the argument so that AstMethodBodyBuilder will insert a cast - return resultType; - } - - public static TypeReference GetFieldType(FieldReference fieldReference) - { - return SubstituteTypeArgs(UnpackModifiers(fieldReference.FieldType), fieldReference); - } - - public static TypeReference SubstituteTypeArgs(TypeReference type, MemberReference member) - { - if (type is TypeSpecification) { - ArrayType arrayType = type as ArrayType; - if (arrayType != null) { - TypeReference elementType = SubstituteTypeArgs(arrayType.ElementType, member); - if (elementType != arrayType.ElementType) { - ArrayType newArrayType = new ArrayType(elementType); - newArrayType.Dimensions.Clear(); // remove the single dimension that Cecil adds by default - foreach (ArrayDimension d in arrayType.Dimensions) - newArrayType.Dimensions.Add(d); - return newArrayType; - } else { - return type; - } - } - ByReferenceType refType = type as ByReferenceType; - if (refType != null) { - TypeReference elementType = SubstituteTypeArgs(refType.ElementType, member); - return elementType != refType.ElementType ? new ByReferenceType(elementType) : type; - } - GenericInstanceType giType = type as GenericInstanceType; - if (giType != null) { - GenericInstanceType newType = new GenericInstanceType(giType.ElementType); - bool isChanged = false; - for (int i = 0; i < giType.GenericArguments.Count; i++) { - newType.GenericArguments.Add(SubstituteTypeArgs(giType.GenericArguments[i], member)); - isChanged |= newType.GenericArguments[i] != giType.GenericArguments[i]; - } - return isChanged ? newType : type; - } - OptionalModifierType optmodType = type as OptionalModifierType; - if (optmodType != null) { - TypeReference elementType = SubstituteTypeArgs(optmodType.ElementType, member); - return elementType != optmodType.ElementType ? new OptionalModifierType(optmodType.ModifierType, elementType) : type; - } - RequiredModifierType reqmodType = type as RequiredModifierType; - if (reqmodType != null) { - TypeReference elementType = SubstituteTypeArgs(reqmodType.ElementType, member); - return elementType != reqmodType.ElementType ? new RequiredModifierType(reqmodType.ModifierType, elementType) : type; - } - PointerType ptrType = type as PointerType; - if (ptrType != null) { - TypeReference elementType = SubstituteTypeArgs(ptrType.ElementType, member); - return elementType != ptrType.ElementType ? new PointerType(elementType) : type; - } - } - GenericParameter gp = type as GenericParameter; - if (gp != null) { - if (member.DeclaringType is ArrayType) { - return ((ArrayType)member.DeclaringType).ElementType; - } else if (gp.Owner.GenericParameterType == GenericParameterType.Method) { - return ((GenericInstanceMethod)member).GenericArguments[gp.Position]; - } else { - return ((GenericInstanceType)member.DeclaringType).GenericArguments[gp.Position]; - } - } - return type; - } - - static TypeReference UnpackPointer(TypeReference pointerOrManagedReference) - { - ByReferenceType refType = pointerOrManagedReference as ByReferenceType; - if (refType != null) - return refType.ElementType; - PointerType ptrType = pointerOrManagedReference as PointerType; - if (ptrType != null) - return ptrType.ElementType; - return null; - } - - internal static TypeReference UnpackModifiers(TypeReference type) - { - while (type is OptionalModifierType || type is RequiredModifierType) - type = ((TypeSpecification)type).ElementType; - return type; - } - - static TypeReference GetNullableTypeArgument(TypeReference type) - { - var t = type as GenericInstanceType; - return IsNullableType(t) ? t.GenericArguments[0] : type; - } - - GenericInstanceType CreateNullableType(TypeReference type) - { - if (type == null) return null; - var t = new GenericInstanceType(new TypeReference("System", "Nullable`1", module, module.TypeSystem.Corlib, true)); - t.GenericArguments.Add(type); - return t; - } - - TypeReference InferArgumentsInBinaryOperator(ILExpression expr, bool? isSigned, TypeReference expectedType) - { - return InferBinaryArguments(expr.Arguments[0], expr.Arguments[1], expectedType); - } - - TypeReference InferArgumentsInAddition(ILExpression expr, bool? isSigned, TypeReference expectedType) - { - ILExpression left = expr.Arguments[0]; - ILExpression right = expr.Arguments[1]; - TypeReference leftPreferred = DoInferTypeForExpression(left, expectedType); - if (leftPreferred is PointerType) { - left.InferredType = left.ExpectedType = leftPreferred; - InferTypeForExpression(right, null); - return leftPreferred; - } - if (IsEnum(leftPreferred)) { - //E+U=E - left.InferredType = left.ExpectedType = leftPreferred; - InferTypeForExpression(right, GetEnumUnderlyingType(leftPreferred)); - return leftPreferred; - } - TypeReference rightPreferred = DoInferTypeForExpression(right, expectedType); - if (rightPreferred is PointerType) { - InferTypeForExpression(left, null); - right.InferredType = right.ExpectedType = rightPreferred; - return rightPreferred; - } - if (IsEnum(rightPreferred)) { - //U+E=E - right.InferredType = right.ExpectedType = rightPreferred; - InferTypeForExpression(left, GetEnumUnderlyingType(rightPreferred)); - return rightPreferred; - } - return InferBinaryArguments(left, right, expectedType, leftPreferred: leftPreferred, rightPreferred: rightPreferred); - } - - TypeReference InferArgumentsInSubtraction(ILExpression expr, bool? isSigned, TypeReference expectedType) - { - ILExpression left = expr.Arguments[0]; - ILExpression right = expr.Arguments[1]; - TypeReference leftPreferred = DoInferTypeForExpression(left, expectedType); - if (leftPreferred is PointerType) { - left.InferredType = left.ExpectedType = leftPreferred; - InferTypeForExpression(right, null); - return leftPreferred; - } - if (IsEnum(leftPreferred)) { - if (expectedType != null && IsEnum(expectedType)) { - // E-U=E - left.InferredType = left.ExpectedType = leftPreferred; - InferTypeForExpression(right, GetEnumUnderlyingType(leftPreferred)); - return leftPreferred; - } else { - // E-E=U - left.InferredType = left.ExpectedType = leftPreferred; - InferTypeForExpression(right, leftPreferred); - return GetEnumUnderlyingType(leftPreferred); - } - } - return InferBinaryArguments(left, right, expectedType, leftPreferred: leftPreferred); - } - - TypeReference InferBinaryArguments(ILExpression left, ILExpression right, TypeReference expectedType, bool forceInferChildren = false, TypeReference leftPreferred = null, TypeReference rightPreferred = null) - { - if (leftPreferred == null) leftPreferred = DoInferTypeForExpression(left, expectedType, forceInferChildren); - if (rightPreferred == null) rightPreferred = DoInferTypeForExpression(right, expectedType, forceInferChildren); - if (IsSameType(leftPreferred, rightPreferred)) { - return left.InferredType = right.InferredType = left.ExpectedType = right.ExpectedType = leftPreferred; - } else if (IsSameType(rightPreferred, DoInferTypeForExpression(left, rightPreferred, forceInferChildren))) { - return left.InferredType = right.InferredType = left.ExpectedType = right.ExpectedType = rightPreferred; - } else if (IsSameType(leftPreferred, DoInferTypeForExpression(right, leftPreferred, forceInferChildren))) { - // re-infer the left expression with the preferred type to reset any conflicts caused by the rightPreferred type - DoInferTypeForExpression(left, leftPreferred, forceInferChildren); - return left.InferredType = right.InferredType = left.ExpectedType = right.ExpectedType = leftPreferred; - } else { - left.ExpectedType = right.ExpectedType = TypeWithMoreInformation(leftPreferred, rightPreferred); - left.InferredType = DoInferTypeForExpression(left, left.ExpectedType, forceInferChildren); - right.InferredType = DoInferTypeForExpression(right, right.ExpectedType, forceInferChildren); - return left.ExpectedType; - } - } - - TypeReference TypeWithMoreInformation(TypeReference leftPreferred, TypeReference rightPreferred) - { - int left = GetInformationAmount(leftPreferred); - int right = GetInformationAmount(rightPreferred); - if (left < right) { - return rightPreferred; - } else if (left > right) { - return leftPreferred; - } else { - // TODO - return leftPreferred; - } - } - - /// - /// Information amount used for IntPtr. - /// - public const int NativeInt = 33; // treat native int as between int32 and int64 - - /// - /// Gets the underlying type, if the specified type is an enum. - /// Otherwise, returns null. - /// - public static TypeReference GetEnumUnderlyingType(TypeReference enumType) - { - // unfortunately we cannot rely on enumType.IsValueType here - it's not set when the instruction operand is a typeref (as opposed to a typespec) - if (enumType != null && !IsArrayPointerOrReference(enumType)) { - // value type might be an enum - TypeDefinition typeDef = enumType.Resolve() as TypeDefinition; - if (typeDef != null && typeDef.IsEnum) { - return typeDef.Fields.Single(f => !f.IsStatic).FieldType; - } - } - return null; - } - - public static int GetInformationAmount(TypeReference type) - { - type = GetEnumUnderlyingType(type) ?? type; - if (type == null) - return 0; - switch (type.MetadataType) { - case MetadataType.Void: - return 0; - case MetadataType.Boolean: - return 1; - case MetadataType.SByte: - case MetadataType.Byte: - return 8; - case MetadataType.Char: - case MetadataType.Int16: - case MetadataType.UInt16: - return 16; - case MetadataType.Int32: - case MetadataType.UInt32: - case MetadataType.Single: - return 32; - case MetadataType.Int64: - case MetadataType.UInt64: - case MetadataType.Double: - return 64; - case MetadataType.IntPtr: - case MetadataType.UIntPtr: - return NativeInt; - default: - return 100; // we consider structs/objects to have more information than any primitives - } - } - - public static bool IsBoolean(TypeReference type) - { - return type != null && type.MetadataType == MetadataType.Boolean; - } - - public static bool IsIntegerOrEnum(TypeReference type) - { - return IsSigned(type) != null; - } - - public static bool IsEnum(TypeReference type) - { - // Arrays/Pointers/ByReference resolve to their element type, but we don't want to consider those to be enums - // However, GenericInstanceTypes, ModOpts etc. should be considered enums. - if (type == null || IsArrayPointerOrReference(type)) - return false; - // unfortunately we cannot rely on type.IsValueType here - it's not set when the instruction operand is a typeref (as opposed to a typespec) - TypeDefinition typeDef = type.Resolve() as TypeDefinition; - return typeDef != null && typeDef.IsEnum; - } - - static bool? IsSigned(TypeReference type) - { - type = GetEnumUnderlyingType(type) ?? type; - if (type == null) - return null; - switch (type.MetadataType) { - case MetadataType.SByte: - case MetadataType.Int16: - case MetadataType.Int32: - case MetadataType.Int64: - case MetadataType.IntPtr: - return true; - case MetadataType.Byte: - case MetadataType.Char: - case MetadataType.UInt16: - case MetadataType.UInt32: - case MetadataType.UInt64: - case MetadataType.UIntPtr: - return false; - default: - return null; - } - } - - static bool OperandFitsInType(TypeReference type, int num) - { - type = GetEnumUnderlyingType(type) ?? type; - switch (type.MetadataType) { - case MetadataType.SByte: - return sbyte.MinValue <= num && num <= sbyte.MaxValue; - case MetadataType.Int16: - return short.MinValue <= num && num <= short.MaxValue; - case MetadataType.Byte: - return byte.MinValue <= num && num <= byte.MaxValue; - case MetadataType.Char: - return char.MinValue <= num && num <= char.MaxValue; - case MetadataType.UInt16: - return ushort.MinValue <= num && num <= ushort.MaxValue; - default: - return true; - } - } - - static bool IsArrayPointerOrReference(TypeReference type) - { - TypeSpecification typeSpec = type as TypeSpecification; - while (typeSpec != null) { - if (typeSpec is ArrayType || typeSpec is PointerType || typeSpec is ByReferenceType) - return true; - typeSpec = typeSpec.ElementType as TypeSpecification; - } - return false; - } - - internal static bool IsNullableType(TypeReference type) - { - return type != null && type.Name == "Nullable`1" && type.Namespace == "System"; - } - - public static TypeCode GetTypeCode(TypeReference type) - { - if (type == null) - return TypeCode.Empty; - switch (type.MetadataType) { - case MetadataType.Boolean: - return TypeCode.Boolean; - case MetadataType.Char: - return TypeCode.Char; - case MetadataType.SByte: - return TypeCode.SByte; - case MetadataType.Byte: - return TypeCode.Byte; - case MetadataType.Int16: - return TypeCode.Int16; - case MetadataType.UInt16: - return TypeCode.UInt16; - case MetadataType.Int32: - return TypeCode.Int32; - case MetadataType.UInt32: - return TypeCode.UInt32; - case MetadataType.Int64: - return TypeCode.Int64; - case MetadataType.UInt64: - return TypeCode.UInt64; - case MetadataType.Single: - return TypeCode.Single; - case MetadataType.Double: - return TypeCode.Double; - case MetadataType.String: - return TypeCode.String; - default: - return TypeCode.Object; - } - } - - /// - /// Clears the type inference data on the method. - /// - public static void Reset(ILBlock method) - { - foreach (ILExpression expr in method.GetSelfAndChildrenRecursive()) { - expr.InferredType = null; - expr.ExpectedType = null; - ILVariable v = expr.Operand as ILVariable; - if (v != null && v.IsGenerated) - v.Type = null; - } - } - - public static bool IsSameType(TypeReference type1, TypeReference type2) - { - if (type1 == type2) - return true; - if (type1 == null || type2 == null) - return false; - return type1.FullName == type2.FullName; // TODO: implement this more efficiently? - } - } -} diff --git a/ICSharpCode.Decompiler/ILAst/YieldReturnDecompiler.cs b/ICSharpCode.Decompiler/ILAst/YieldReturnDecompiler.cs deleted file mode 100644 index 7a9a09ed..00000000 --- a/ICSharpCode.Decompiler/ILAst/YieldReturnDecompiler.cs +++ /dev/null @@ -1,635 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using Mono.Cecil; - -namespace ICSharpCode.Decompiler.ILAst -{ - internal class YieldReturnDecompiler - { - // For a description on the code generated by the C# compiler for yield return: - // http://csharpindepth.com/Articles/Chapter6/IteratorBlockImplementation.aspx - - // The idea here is: - // - Figure out whether the current method is instanciating an enumerator - // - Figure out which of the fields is the state field - // - Construct an exception table based on states. This allows us to determine, for each state, what the parent try block is. - - // See http://community.sharpdevelop.net/blogs/danielgrunwald/archive/2011/03/06/ilspy-yield-return.aspx - // for a description of this step. - - DecompilerContext context; - TypeDefinition enumeratorType; - MethodDefinition enumeratorCtor; - MethodDefinition disposeMethod; - FieldDefinition stateField; - FieldDefinition currentField; - Dictionary fieldToParameterMap = new Dictionary(); - List newBody; - - #region Run() method - public static void Run(DecompilerContext context, ILBlock method) - { - if (!context.Settings.YieldReturn) - return; // abort if enumerator decompilation is disabled - var yrd = new YieldReturnDecompiler(); - yrd.context = context; - if (!yrd.MatchEnumeratorCreationPattern(method)) - return; - yrd.enumeratorType = yrd.enumeratorCtor.DeclaringType; - #if DEBUG - if (Debugger.IsAttached) { - yrd.Run(); - } else { - #endif - try { - yrd.Run(); - } catch (SymbolicAnalysisFailedException) { - return; - } - #if DEBUG - } - #endif - method.Body.Clear(); - method.EntryGoto = null; - method.Body.AddRange(yrd.newBody); - - // Repeat the inlining/copy propagation optimization because the conversion of field access - // to local variables can open up additional inlining possibilities. - ILInlining inlining = new ILInlining(method); - inlining.InlineAllVariables(); - inlining.CopyPropagation(); - } - - void Run() - { - AnalyzeCtor(); - AnalyzeCurrentProperty(); - ResolveIEnumerableIEnumeratorFieldMapping(); - ConstructExceptionTable(); - AnalyzeMoveNext(); - TranslateFieldsToLocalAccess(); - } - #endregion - - #region Match the enumerator creation pattern - bool MatchEnumeratorCreationPattern(ILBlock method) - { - if (method.Body.Count == 0) - return false; - ILExpression newObj; - if (method.Body.Count == 1) { - // ret(newobj(...)) - if (method.Body[0].Match(ILCode.Ret, out newObj)) - return MatchEnumeratorCreationNewObj(newObj, out enumeratorCtor); - else - return false; - } - // stloc(var_1, newobj(..) - ILVariable var1; - if (!method.Body[0].Match(ILCode.Stloc, out var1, out newObj)) - return false; - if (!MatchEnumeratorCreationNewObj(newObj, out enumeratorCtor)) - return false; - - int i; - for (i = 1; i < method.Body.Count; i++) { - // stfld(..., ldloc(var_1), ldloc(parameter)) - FieldReference storedField; - ILExpression ldloc, loadParameter; - if (!method.Body[i].Match(ILCode.Stfld, out storedField, out ldloc, out loadParameter)) - break; - ILVariable loadedVar, loadedArg; - if (!ldloc.Match(ILCode.Ldloc, out loadedVar) || !loadParameter.Match(ILCode.Ldloc, out loadedArg)) - return false; - storedField = GetFieldDefinition(storedField); - if (loadedVar != var1 || storedField == null || !loadedArg.IsParameter) - return false; - fieldToParameterMap[(FieldDefinition)storedField] = loadedArg; - } - ILVariable var2; - ILExpression ldlocForStloc2; - if (i < method.Body.Count && method.Body[i].Match(ILCode.Stloc, out var2, out ldlocForStloc2)) { - // stloc(var_2, ldloc(var_1)) - if (ldlocForStloc2.Code != ILCode.Ldloc || ldlocForStloc2.Operand != var1) - return false; - i++; - } else { - // the compiler might skip the above instruction in release builds; in that case, it directly returns stloc.Operand - var2 = var1; - } - ILExpression retArg; - if (i < method.Body.Count && method.Body[i].Match(ILCode.Ret, out retArg)) { - // ret(ldloc(var_2)) - if (retArg.Code == ILCode.Ldloc && retArg.Operand == var2) { - return true; - } - } - return false; - } - - static FieldDefinition GetFieldDefinition(FieldReference field) - { - return CecilExtensions.ResolveWithinSameModule(field); - } - - static MethodDefinition GetMethodDefinition(MethodReference method) - { - return CecilExtensions.ResolveWithinSameModule(method); - } - - bool MatchEnumeratorCreationNewObj(ILExpression expr, out MethodDefinition ctor) - { - // newobj(CurrentType/...::.ctor, ldc.i4(-2)) - ctor = null; - if (expr.Code != ILCode.Newobj || expr.Arguments.Count != 1) - return false; - if (expr.Arguments[0].Code != ILCode.Ldc_I4) - return false; - int initialState = (int)expr.Arguments[0].Operand; - if (!(initialState == -2 || initialState == 0)) - return false; - ctor = GetMethodDefinition(expr.Operand as MethodReference); - if (ctor == null || ctor.DeclaringType.DeclaringType != context.CurrentType) - return false; - return IsCompilerGeneratorEnumerator(ctor.DeclaringType); - } - - public static bool IsCompilerGeneratorEnumerator(TypeDefinition type) - { - if (!(type.DeclaringType != null && type.IsCompilerGenerated())) - return false; - foreach (TypeReference i in type.Interfaces) { - if (i.Namespace == "System.Collections" && i.Name == "IEnumerator") - return true; - } - return false; - } - #endregion - - #region Figure out what the 'state' field is (analysis of .ctor()) - /// - /// Looks at the enumerator's ctor and figures out which of the fields holds the state. - /// - void AnalyzeCtor() - { - ILBlock method = CreateILAst(enumeratorCtor); - - foreach (ILNode node in method.Body) { - FieldReference field; - ILExpression instExpr; - ILExpression stExpr; - ILVariable arg; - if (node.Match(ILCode.Stfld, out field, out instExpr, out stExpr) && - instExpr.MatchThis() && - stExpr.Match(ILCode.Ldloc, out arg) && - arg.IsParameter && arg.OriginalParameter.Index == 0) - { - stateField = GetFieldDefinition(field); - } - } - if (stateField == null) - throw new SymbolicAnalysisFailedException(); - } - - /// - /// Creates ILAst for the specified method, optimized up to before the 'YieldReturn' step. - /// - ILBlock CreateILAst(MethodDefinition method) - { - if (method == null || !method.HasBody) - throw new SymbolicAnalysisFailedException(); - - ILBlock ilMethod = new ILBlock(); - ILAstBuilder astBuilder = new ILAstBuilder(); - ilMethod.Body = astBuilder.Build(method, true, context); - ILAstOptimizer optimizer = new ILAstOptimizer(); - optimizer.Optimize(context, ilMethod, ILAstOptimizationStep.YieldReturn); - return ilMethod; - } - #endregion - - #region Figure out what the 'current' field is (analysis of get_Current()) - /// - /// Looks at the enumerator's get_Current method and figures out which of the fields holds the current value. - /// - void AnalyzeCurrentProperty() - { - MethodDefinition getCurrentMethod = enumeratorType.Methods.FirstOrDefault( - m => m.Name.StartsWith("System.Collections.Generic.IEnumerator", StringComparison.Ordinal) - && m.Name.EndsWith(".get_Current", StringComparison.Ordinal)); - ILBlock method = CreateILAst(getCurrentMethod); - if (method.Body.Count == 1) { - // release builds directly return the current field - ILExpression retExpr; - FieldReference field; - ILExpression ldFromObj; - if (method.Body[0].Match(ILCode.Ret, out retExpr) && - retExpr.Match(ILCode.Ldfld, out field, out ldFromObj) && - ldFromObj.MatchThis()) - { - currentField = GetFieldDefinition(field); - } - } else if (method.Body.Count == 2) { - ILVariable v, v2; - ILExpression stExpr; - FieldReference field; - ILExpression ldFromObj; - ILExpression retExpr; - if (method.Body[0].Match(ILCode.Stloc, out v, out stExpr) && - stExpr.Match(ILCode.Ldfld, out field, out ldFromObj) && - ldFromObj.MatchThis() && - method.Body[1].Match(ILCode.Ret, out retExpr) && - retExpr.Match(ILCode.Ldloc, out v2) && - v == v2) - { - currentField = GetFieldDefinition(field); - } - } - if (currentField == null) - throw new SymbolicAnalysisFailedException(); - } - #endregion - - #region Figure out the mapping of IEnumerable fields to IEnumerator fields (analysis of GetEnumerator()) - void ResolveIEnumerableIEnumeratorFieldMapping() - { - MethodDefinition getEnumeratorMethod = enumeratorType.Methods.FirstOrDefault( - m => m.Name.StartsWith("System.Collections.Generic.IEnumerable", StringComparison.Ordinal) - && m.Name.EndsWith(".GetEnumerator", StringComparison.Ordinal)); - if (getEnumeratorMethod == null) - return; // no mappings (maybe it's just an IEnumerator implementation?) - - ILBlock method = CreateILAst(getEnumeratorMethod); - foreach (ILNode node in method.Body) { - FieldReference stField; - ILExpression stToObj; - ILExpression stExpr; - FieldReference ldField; - ILExpression ldFromObj; - if (node.Match(ILCode.Stfld, out stField, out stToObj, out stExpr) && - stExpr.Match(ILCode.Ldfld, out ldField, out ldFromObj) && - ldFromObj.MatchThis()) - { - FieldDefinition storedField = GetFieldDefinition(stField); - FieldDefinition loadedField = GetFieldDefinition(ldField); - if (storedField != null && loadedField != null) { - ILVariable mappedParameter; - if (fieldToParameterMap.TryGetValue(loadedField, out mappedParameter)) - fieldToParameterMap[storedField] = mappedParameter; - } - } - } - } - #endregion - - #region Construction of the exception table (analysis of Dispose()) - // We construct the exception table by analyzing the enumerator's Dispose() method. - - // Assumption: there are no loops/backward jumps - // We 'run' the code, with "state" being a symbolic variable - // so it can form expressions like "state + x" (when there's a sub instruction) - // For each instruction, we maintain a list of value ranges for state for which the instruction is reachable. - // This is (int.MinValue, int.MaxValue) for the first instruction. - // These ranges are propagated depending on the conditional jumps performed by the code. - - Dictionary finallyMethodToStateRange; - - void ConstructExceptionTable() - { - disposeMethod = enumeratorType.Methods.FirstOrDefault(m => m.Name == "System.IDisposable.Dispose"); - ILBlock ilMethod = CreateILAst(disposeMethod); - - var rangeAnalysis = new StateRangeAnalysis(ilMethod.Body[0], StateRangeAnalysisMode.IteratorDispose, stateField); - rangeAnalysis.AssignStateRanges(ilMethod.Body, ilMethod.Body.Count); - finallyMethodToStateRange = rangeAnalysis.finallyMethodToStateRange; - - // Now look at the finally blocks: - foreach (var tryFinally in ilMethod.GetSelfAndChildrenRecursive()) { - var range = rangeAnalysis.ranges[tryFinally.TryBlock.Body[0]]; - var finallyBody = tryFinally.FinallyBlock.Body; - if (finallyBody.Count != 2) - throw new SymbolicAnalysisFailedException(); - ILExpression call = finallyBody[0] as ILExpression; - if (call == null || call.Code != ILCode.Call || call.Arguments.Count != 1) - throw new SymbolicAnalysisFailedException(); - if (!call.Arguments[0].MatchThis()) - throw new SymbolicAnalysisFailedException(); - if (!finallyBody[1].Match(ILCode.Endfinally)) - throw new SymbolicAnalysisFailedException(); - - MethodDefinition mdef = GetMethodDefinition(call.Operand as MethodReference); - if (mdef == null || finallyMethodToStateRange.ContainsKey(mdef)) - throw new SymbolicAnalysisFailedException(); - finallyMethodToStateRange.Add(mdef, range); - } - rangeAnalysis = null; - } - #endregion - - #region Analysis of MoveNext() - ILVariable returnVariable; - ILLabel returnLabel; - ILLabel returnFalseLabel; - - void AnalyzeMoveNext() - { - MethodDefinition moveNextMethod = enumeratorType.Methods.FirstOrDefault(m => m.Name == "MoveNext"); - ILBlock ilMethod = CreateILAst(moveNextMethod); - - if (ilMethod.Body.Count == 0) - throw new SymbolicAnalysisFailedException(); - ILExpression lastReturnArg; - if (!ilMethod.Body.Last().Match(ILCode.Ret, out lastReturnArg)) - throw new SymbolicAnalysisFailedException(); - - // There are two possibilities: - if (lastReturnArg.Code == ILCode.Ldloc) { - // a) the compiler uses a variable for returns (in debug builds, or when there are try-finally blocks) - returnVariable = (ILVariable)lastReturnArg.Operand; - returnLabel = ilMethod.Body.ElementAtOrDefault(ilMethod.Body.Count - 2) as ILLabel; - if (returnLabel == null) - throw new SymbolicAnalysisFailedException(); - } else { - // b) the compiler directly returns constants - returnVariable = null; - returnLabel = null; - // In this case, the last return must return false. - if (lastReturnArg.Code != ILCode.Ldc_I4 || (int)lastReturnArg.Operand != 0) - throw new SymbolicAnalysisFailedException(); - } - - ILTryCatchBlock tryFaultBlock = ilMethod.Body[0] as ILTryCatchBlock; - List body; - int bodyLength; - if (tryFaultBlock != null) { - // there are try-finally blocks - if (returnVariable == null) // in this case, we must use a return variable - throw new SymbolicAnalysisFailedException(); - // must be a try-fault block: - if (tryFaultBlock.CatchBlocks.Count != 0 || tryFaultBlock.FinallyBlock != null || tryFaultBlock.FaultBlock == null) - throw new SymbolicAnalysisFailedException(); - - ILBlock faultBlock = tryFaultBlock.FaultBlock; - // Ensure the fault block contains the call to Dispose(). - if (faultBlock.Body.Count != 2) - throw new SymbolicAnalysisFailedException(); - MethodReference disposeMethodRef; - ILExpression disposeArg; - if (!faultBlock.Body[0].Match(ILCode.Call, out disposeMethodRef, out disposeArg)) - throw new SymbolicAnalysisFailedException(); - if (GetMethodDefinition(disposeMethodRef) != disposeMethod || !disposeArg.MatchThis()) - throw new SymbolicAnalysisFailedException(); - if (!faultBlock.Body[1].Match(ILCode.Endfinally)) - throw new SymbolicAnalysisFailedException(); - - body = tryFaultBlock.TryBlock.Body; - bodyLength = body.Count; - } else { - // no try-finally blocks - body = ilMethod.Body; - if (returnVariable == null) - bodyLength = body.Count - 1; // all except for the return statement - else - bodyLength = body.Count - 2; // all except for the return label and statement - } - - // Now verify that the last instruction in the body is 'ret(false)' - if (returnVariable != null) { - // If we don't have a return variable, we already verified that above. - // If we do have one, check for 'stloc(returnVariable, ldc.i4(0))' - - // Maybe might be a jump to the return label after the stloc: - ILExpression leave = body.ElementAtOrDefault(bodyLength - 1) as ILExpression; - if (leave != null && (leave.Code == ILCode.Br || leave.Code == ILCode.Leave) && leave.Operand == returnLabel) - bodyLength--; - ILExpression store0 = body.ElementAtOrDefault(bodyLength - 1) as ILExpression; - if (store0 == null || store0.Code != ILCode.Stloc || store0.Operand != returnVariable) - throw new SymbolicAnalysisFailedException(); - if (store0.Arguments[0].Code != ILCode.Ldc_I4 || (int)store0.Arguments[0].Operand != 0) - throw new SymbolicAnalysisFailedException(); - - bodyLength--; // don't conside the stloc instruction to be part of the body - } - // The last element in the body usually is a label pointing to the 'ret(false)' - returnFalseLabel = body.ElementAtOrDefault(bodyLength - 1) as ILLabel; - // Note: in Roslyn-compiled code, returnFalseLabel may be null. - - var rangeAnalysis = new StateRangeAnalysis(body[0], StateRangeAnalysisMode.IteratorMoveNext, stateField); - int pos = rangeAnalysis.AssignStateRanges(body, bodyLength); - rangeAnalysis.EnsureLabelAtPos(body, ref pos, ref bodyLength); - - var labels = rangeAnalysis.CreateLabelRangeMapping(body, pos, bodyLength); - ConvertBody(body, pos, bodyLength, labels); - } - #endregion - - #region ConvertBody - struct SetState - { - public readonly int NewBodyPos; - public readonly int NewState; - - public SetState(int newBodyPos, int newState) - { - NewBodyPos = newBodyPos; - NewState = newState; - } - } - - void ConvertBody(List body, int startPos, int bodyLength, List> labels) - { - newBody = new List(); - newBody.Add(MakeGoTo(labels, 0)); - List stateChanges = new List(); - int currentState = -1; - // Copy all instructions from the old body to newBody. - for (int pos = startPos; pos < bodyLength; pos++) { - ILExpression expr = body[pos] as ILExpression; - if (expr != null && expr.Code == ILCode.Stfld && expr.Arguments[0].MatchThis()) { - // Handle stores to 'state' or 'current' - if (GetFieldDefinition(expr.Operand as FieldReference) == stateField) { - if (expr.Arguments[1].Code != ILCode.Ldc_I4) - throw new SymbolicAnalysisFailedException(); - currentState = (int)expr.Arguments[1].Operand; - stateChanges.Add(new SetState(newBody.Count, currentState)); - } else if (GetFieldDefinition(expr.Operand as FieldReference) == currentField) { - newBody.Add(new ILExpression(ILCode.YieldReturn, null, expr.Arguments[1])); - } else { - newBody.Add(body[pos]); - } - } else if (returnVariable != null && expr != null && expr.Code == ILCode.Stloc && expr.Operand == returnVariable) { - // handle store+branch to the returnVariable - ILExpression br = body.ElementAtOrDefault(++pos) as ILExpression; - if (br == null || !(br.Code == ILCode.Br || br.Code == ILCode.Leave) || br.Operand != returnLabel || expr.Arguments[0].Code != ILCode.Ldc_I4) - throw new SymbolicAnalysisFailedException(); - int val = (int)expr.Arguments[0].Operand; - if (val == 0) { - newBody.Add(new ILExpression(ILCode.YieldBreak, null)); - } else if (val == 1) { - newBody.Add(MakeGoTo(labels, currentState)); - } else { - throw new SymbolicAnalysisFailedException(); - } - } else if (expr != null && expr.Code == ILCode.Ret) { - if (expr.Arguments.Count != 1 || expr.Arguments[0].Code != ILCode.Ldc_I4) - throw new SymbolicAnalysisFailedException(); - // handle direct return (e.g. in release builds) - int val = (int)expr.Arguments[0].Operand; - if (val == 0) { - newBody.Add(new ILExpression(ILCode.YieldBreak, null)); - } else if (val == 1) { - newBody.Add(MakeGoTo(labels, currentState)); - } else { - throw new SymbolicAnalysisFailedException(); - } - } else if (expr != null && expr.Code == ILCode.Call && expr.Arguments.Count == 1 && expr.Arguments[0].MatchThis()) { - MethodDefinition method = GetMethodDefinition(expr.Operand as MethodReference); - if (method == null) - throw new SymbolicAnalysisFailedException(); - StateRange stateRange; - if (method == disposeMethod) { - // Explicit call to dispose is used for "yield break;" within the method. - ILExpression br = body.ElementAtOrDefault(++pos) as ILExpression; - if (br == null || !(br.Code == ILCode.Br || br.Code == ILCode.Leave) || br.Operand != returnFalseLabel) - throw new SymbolicAnalysisFailedException(); - newBody.Add(new ILExpression(ILCode.YieldBreak, null)); - } else if (finallyMethodToStateRange.TryGetValue(method, out stateRange)) { - // Call to Finally-method - int index = stateChanges.FindIndex(ss => stateRange.Contains(ss.NewState)); - if (index < 0) - throw new SymbolicAnalysisFailedException(); - - ILLabel label = new ILLabel(); - label.Name = "JumpOutOfTryFinally" + stateChanges[index].NewState; - newBody.Add(new ILExpression(ILCode.Leave, label)); - - SetState stateChange = stateChanges[index]; - // Move all instructions from stateChange.Pos to newBody.Count into a try-block - stateChanges.RemoveRange(index, stateChanges.Count - index); // remove all state changes up to the one we found - ILTryCatchBlock tryFinally = new ILTryCatchBlock(); - tryFinally.TryBlock = new ILBlock(newBody.GetRange(stateChange.NewBodyPos, newBody.Count - stateChange.NewBodyPos)); - newBody.RemoveRange(stateChange.NewBodyPos, newBody.Count - stateChange.NewBodyPos); // remove all nodes that we just moved into the try block - tryFinally.CatchBlocks = new List(); - tryFinally.FinallyBlock = ConvertFinallyBlock(method); - newBody.Add(tryFinally); - newBody.Add(label); - } - } else { - newBody.Add(body[pos]); - } - } - newBody.Add(new ILExpression(ILCode.YieldBreak, null)); - } - - ILExpression MakeGoTo(ILLabel targetLabel) - { - Debug.Assert(targetLabel != null); - if (targetLabel == returnFalseLabel) - return new ILExpression(ILCode.YieldBreak, null); - else - return new ILExpression(ILCode.Br, targetLabel); - } - - ILExpression MakeGoTo(List> labels, int state) - { - foreach (var pair in labels) { - if (pair.Value.Contains(state)) - return MakeGoTo(pair.Key); - } - throw new SymbolicAnalysisFailedException(); - } - - ILBlock ConvertFinallyBlock(MethodDefinition finallyMethod) - { - ILBlock block = CreateILAst(finallyMethod); - // Get rid of assignment to state - FieldReference stfld; - List args; - if (block.Body.Count > 0 && block.Body[0].Match(ILCode.Stfld, out stfld, out args)) { - if (GetFieldDefinition(stfld) == stateField && args[0].MatchThis()) - block.Body.RemoveAt(0); - } - // Convert ret to endfinally - foreach (ILExpression expr in block.GetSelfAndChildrenRecursive()) { - if (expr.Code == ILCode.Ret) - expr.Code = ILCode.Endfinally; - } - return block; - } - #endregion - - #region TranslateFieldsToLocalAccess - void TranslateFieldsToLocalAccess() - { - TranslateFieldsToLocalAccess(newBody, fieldToParameterMap); - } - - internal static void TranslateFieldsToLocalAccess(List newBody, Dictionary fieldToParameterMap) - { - var fieldToLocalMap = new DefaultDictionary(f => new ILVariable { Name = f.Name, Type = f.FieldType }); - foreach (ILNode node in newBody) { - foreach (ILExpression expr in node.GetSelfAndChildrenRecursive()) { - FieldDefinition field = GetFieldDefinition(expr.Operand as FieldReference); - if (field != null) { - switch (expr.Code) { - case ILCode.Ldfld: - if (expr.Arguments[0].MatchThis()) { - expr.Code = ILCode.Ldloc; - if (fieldToParameterMap.ContainsKey(field)) { - expr.Operand = fieldToParameterMap[field]; - } else { - expr.Operand = fieldToLocalMap[field]; - } - expr.Arguments.Clear(); - } - break; - case ILCode.Stfld: - if (expr.Arguments[0].MatchThis()) { - expr.Code = ILCode.Stloc; - if (fieldToParameterMap.ContainsKey(field)) { - expr.Operand = fieldToParameterMap[field]; - } else { - expr.Operand = fieldToLocalMap[field]; - } - expr.Arguments.RemoveAt(0); - } - break; - case ILCode.Ldflda: - if (expr.Arguments[0].MatchThis()) { - expr.Code = ILCode.Ldloca; - if (fieldToParameterMap.ContainsKey(field)) { - expr.Operand = fieldToParameterMap[field]; - } else { - expr.Operand = fieldToLocalMap[field]; - } - expr.Arguments.Clear(); - } - break; - } - } - } - } - } - #endregion - } -} diff --git a/ICSharpCode.Decompiler/ITextOutput.cs b/ICSharpCode.Decompiler/ITextOutput.cs deleted file mode 100644 index f13a55d6..00000000 --- a/ICSharpCode.Decompiler/ITextOutput.cs +++ /dev/null @@ -1,62 +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.IO; -using ICSharpCode.NRefactory; -using Mono.Cecil; - -namespace ICSharpCode.Decompiler -{ - public interface ITextOutput - { - TextLocation Location { get; } - - void Indent(); - void Unindent(); - void Write(char ch); - void Write(string text); - void WriteLine(); - void WriteDefinition(string text, object definition, bool isLocal = true); - void WriteReference(string text, object reference, bool isLocal = false); - - void AddDebugSymbols(MethodDebugSymbols methodDebugSymbols); - - void MarkFoldStart(string collapsedText = "...", bool defaultCollapsed = false); - void MarkFoldEnd(); - } - - public static class TextOutputExtensions - { - public static void Write(this ITextOutput output, string format, params object[] args) - { - output.Write(string.Format(format, args)); - } - - public static void WriteLine(this ITextOutput output, string text) - { - output.Write(text); - output.WriteLine(); - } - - public static void WriteLine(this ITextOutput output, string format, params object[] args) - { - output.WriteLine(string.Format(format, args)); - } - } -} diff --git a/ICSharpCode.Decompiler/PlainTextOutput.cs b/ICSharpCode.Decompiler/PlainTextOutput.cs deleted file mode 100644 index 468096fa..00000000 --- a/ICSharpCode.Decompiler/PlainTextOutput.cs +++ /dev/null @@ -1,122 +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.IO; -using ICSharpCode.NRefactory; - -namespace ICSharpCode.Decompiler -{ - public sealed class PlainTextOutput : ITextOutput - { - readonly TextWriter writer; - int indent; - bool needsIndent; - - int line = 1; - int column = 1; - - public PlainTextOutput(TextWriter writer) - { - if (writer == null) - throw new ArgumentNullException("writer"); - this.writer = writer; - } - - public PlainTextOutput() - { - writer = new StringWriter(); - } - - public TextLocation Location { - get { - return new TextLocation(line, column + (needsIndent ? indent : 0)); - } - } - - public override string ToString() - { - return writer.ToString(); - } - - public void Indent() - { - indent++; - } - - public void Unindent() - { - indent--; - } - - void WriteIndent() - { - if (needsIndent) { - needsIndent = false; - for (int i = 0; i < indent; i++) { - writer.Write('\t'); - } - column += indent; - } - } - - public void Write(char ch) - { - WriteIndent(); - writer.Write(ch); - column++; - } - - public void Write(string text) - { - WriteIndent(); - writer.Write(text); - column += text.Length; - } - - public void WriteLine() - { - writer.WriteLine(); - needsIndent = true; - line++; - column = 1; - } - - public void WriteDefinition(string text, object definition, bool isLocal) - { - Write(text); - } - - public void WriteReference(string text, object reference, bool isLocal) - { - Write(text); - } - - void ITextOutput.MarkFoldStart(string collapsedText, bool defaultCollapsed) - { - } - - void ITextOutput.MarkFoldEnd() - { - } - - void ITextOutput.AddDebugSymbols(MethodDebugSymbols methodDebugSymbols) - { - } - } -} diff --git a/ICSharpCode.Decompiler/Properties/AssemblyInfo.template.cs b/ICSharpCode.Decompiler/Properties/AssemblyInfo.template.cs deleted file mode 100644 index 3dba481a..00000000 --- a/ICSharpCode.Decompiler/Properties/AssemblyInfo.template.cs +++ /dev/null @@ -1,27 +0,0 @@ -#region Using directives - -using System; -using System.Resources; -using System.Reflection; -using System.Runtime.InteropServices; - -#endregion - -[assembly: AssemblyTitle("ICSharpCode.Decompiler")] -[assembly: AssemblyDescription("IL decompiler engine")] -[assembly: AssemblyCompany("ic#code")] -[assembly: AssemblyProduct("ILSpy")] -[assembly: AssemblyCopyright("Copyright 2011-2014 AlphaSierraPapa for the SharpDevelop Team")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// This sets the default COM visibility of types in the assembly to invisible. -// If you need to expose a type to COM, use [ComVisible(true)] on that type. -[assembly: ComVisible(false)] - -[assembly: AssemblyVersion("$INSERTVERSION$")] -[assembly: AssemblyInformationalVersion("$INSERTVERSION$$INSERTBRANCHPOSTFIX$$INSERTVERSIONNAMEPOSTFIX$-$INSERTSHORTCOMMITHASH$")] -[assembly: NeutralResourcesLanguage("en-US")] - -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2243:AttributeStringLiteralsShouldParseCorrectly", - Justification = "AssemblyInformationalVersion does not need to be a parsable version")] diff --git a/ICSharpCode.Decompiler/ReferenceResolvingException.cs b/ICSharpCode.Decompiler/ReferenceResolvingException.cs deleted file mode 100644 index dbceb44b..00000000 --- a/ICSharpCode.Decompiler/ReferenceResolvingException.cs +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace ICSharpCode.Decompiler -{ - /// - /// Represents an error while resolving a reference to a type or a member. - /// - [Serializable] - public class ReferenceResolvingException : Exception - { - /// - /// Initializes a new instance of the class - /// - public ReferenceResolvingException() - { - } - - /// - /// Initializes a new instance of the class - /// - /// A that describes the error. The content of message is intended to be understood by humans. The caller of this constructor is required to ensure that this string has been localized for the current system culture. - public ReferenceResolvingException(string message) - : base(message) - { - } - - /// - /// Initializes a new instance of the class - /// - /// A that describes the error. The content of message is intended to be understood by humans. The caller of this constructor is required to ensure that this string has been localized for the current system culture. - /// The exception that is the cause of the current exception. If the innerException parameter is not a null reference, the current exception is raised in a catch block that handles the inner exception. - public ReferenceResolvingException(string message, Exception inner) - : base(message, inner) - { - } - - /// - /// Initializes a new instance of the class - /// - /// The object that holds the serialized object data. - /// The contextual information about the source or destination. - protected ReferenceResolvingException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) - : base(info, context) - { - } - } -} diff --git a/ICSharpCode.Decompiler/Tests/Async.cs b/ICSharpCode.Decompiler/Tests/Async.cs deleted file mode 100644 index 7629dd5e..00000000 --- a/ICSharpCode.Decompiler/Tests/Async.cs +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright (c) 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. - -#pragma warning disable 1998 -using System; -using System.Collections.Generic; -using System.IO; -using System.Runtime.CompilerServices; -using System.Threading.Tasks; - -public class Async -{ - public async void SimpleVoidMethod() - { - Console.WriteLine("Before"); - await Task.Delay(TimeSpan.FromSeconds(1.0)); - Console.WriteLine("After"); - } - - public async void VoidMethodWithoutAwait() - { - Console.WriteLine("No Await"); - } - - public async void AwaitYield() - { - await Task.Yield(); - } - - public async void AwaitDefaultYieldAwaitable() - { - await default(YieldAwaitable); - } - - public async Task SimpleVoidTaskMethod() - { - Console.WriteLine("Before"); - await Task.Delay(TimeSpan.FromSeconds(1.0)); - Console.WriteLine("After"); - } - - public async Task TaskMethodWithoutAwait() - { - Console.WriteLine("No Await"); - } - - public async Task SimpleBoolTaskMethod() - { - Console.WriteLine("Before"); - await Task.Delay(TimeSpan.FromSeconds(1.0)); - Console.WriteLine("After"); - return true; - } - - public async void TwoAwaitsWithDifferentAwaiterTypes() - { - Console.WriteLine("Before"); - if (await this.SimpleBoolTaskMethod()) - { - await Task.Delay(TimeSpan.FromSeconds(1.0)); - } - Console.WriteLine("After"); - } - - public async void StreamCopyTo(Stream destination, int bufferSize) - { - byte[] array = new byte[bufferSize]; - int count; - while ((count = await destination.ReadAsync(array, 0, array.Length)) != 0) - { - await destination.WriteAsync(array, 0, count); - } - } - - public async void StreamCopyToWithConfigureAwait(Stream destination, int bufferSize) - { - byte[] array = new byte[bufferSize]; - int count; - while ((count = await destination.ReadAsync(array, 0, array.Length).ConfigureAwait(false)) != 0) - { - await destination.WriteAsync(array, 0, count).ConfigureAwait(false); - } - } - - public async void AwaitInLoopCondition() - { - while (await this.SimpleBoolTaskMethod()) - { - Console.WriteLine("Body"); - } - } - - public async Task AwaitInForEach(IEnumerable> elements) - { - int num = 0; - foreach (Task current in elements) - { - num += await current; - } - return num; - } - - public async Task TaskMethodWithoutAwaitButWithExceptionHandling() - { - try - { - using (new StringWriter()) - { - Console.WriteLine("No Await"); - } - } - catch (Exception) - { - Console.WriteLine("Crash"); - } - } - - public async Task NestedAwait(Task> task) - { - return await(await task); - } - - public async Task AwaitWithStack(Task task) - { - Console.WriteLine("A", 1, await task); - } - - public async Task AwaitWithStack2(Task task) - { - if (await this.SimpleBoolTaskMethod()) - { - Console.WriteLine("A", 1, await task); - } - else - { - int num = 1; - Console.WriteLine("A", 1, num); - } - } -} diff --git a/ICSharpCode.Decompiler/Tests/BooleanConsumedAsInteger.il b/ICSharpCode.Decompiler/Tests/BooleanConsumedAsInteger.il deleted file mode 100644 index 9e300027..00000000 --- a/ICSharpCode.Decompiler/Tests/BooleanConsumedAsInteger.il +++ /dev/null @@ -1,59 +0,0 @@ -.assembly extern mscorlib -{ - .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) - .ver 4:0:0:0 -} -.assembly BooleanConsumedAsInteger -{ - .hash algorithm 0x00008004 - .ver 1:0:0:0 -} -.module BooleanConsumedAsInteger.exe -.imagebase 0x00400000 -.file alignment 0x00000200 -.stackreserve 0x00100000 -.subsystem 0x0003 // WINDOWS_CUI -.corflags 0x00000003 // ILONLY 32BITREQUIRED - -.class private auto ansi beforefieldinit BooleanConsumedAsInteger.Program extends [mscorlib]System.Object -{ - .method public hidebysig static void Main(string[] args) cil managed - { - .entrypoint - .maxstack 8 - - ret - } - - .method public hidebysig static int32 ReturnBoolAsInt() cil managed - { - ldnull - ldnull - call bool [mscorlib] System.Object::Equals(object, object) - ret - } - - .method public hidebysig static int32 BitwiseOperationOnBool() cil managed - { - ldnull - ldnull - call bool [mscorlib] System.Object::Equals(object, object) - ldc.i4 255 - and - ret - } - - .method public hidebysig specialname rtspecialname - instance void .ctor() cil managed - { - // Code size 7 (0x7) - .maxstack 8 - IL_0000: ldarg.0 - IL_0001: call instance void [mscorlib]System.Object::.ctor() - IL_0006: ret - } // end of method Program::.ctor - -} // end of class StackTests.Program - - -// ============================================================= diff --git a/ICSharpCode.Decompiler/Tests/CallOverloadedMethod.cs b/ICSharpCode.Decompiler/Tests/CallOverloadedMethod.cs deleted file mode 100644 index 4f493ef2..00000000 --- a/ICSharpCode.Decompiler/Tests/CallOverloadedMethod.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (c) AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; - -public class CallOverloadedMethod -{ - public void OverloadedMethod(object a) - { - } - - public void OverloadedMethod(int? a) - { - } - - public void OverloadedMethod(string a) - { - } - - public void Call() - { - this.OverloadedMethod("(string)"); - this.OverloadedMethod((object)"(object)"); - this.OverloadedMethod(5); - this.OverloadedMethod((object)5); - this.OverloadedMethod(5L); - this.OverloadedMethod((object)null); - this.OverloadedMethod((string)null); - this.OverloadedMethod((int?)null); - } - - public void CallMethodUsingInterface(List list) - { - ((ICollection)list).Clear(); - } -} diff --git a/ICSharpCode.Decompiler/Tests/CheckedUnchecked.cs b/ICSharpCode.Decompiler/Tests/CheckedUnchecked.cs deleted file mode 100644 index fd1c4d89..00000000 --- a/ICSharpCode.Decompiler/Tests/CheckedUnchecked.cs +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright (c) 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; - -public class CheckedUnchecked -{ - public int Operators(int a, int b) - { - int num = checked(a + b); - int num2 = a + b; - int num3 = checked(a - b); - int num4 = a - b; - int num5 = checked(a * b); - int num6 = a * b; - int num7 = a / b; - int num8 = a % b; - // The division operators / and % only exist in one form (checked vs. unchecked doesn't matter for them) - return num * num2 * num3 * num4 * num5 * num6 * num7 * num8; - } - - public int Cast(int a) - { - short num = checked((short)a); - short num2 = (short)a; - byte b = checked((byte)a); - byte b2 = (byte)a; - return num * num2 * b * b2; - } - - public void ForWithCheckedIteratorAndUncheckedBody(int n) - { - checked - { - for (int i = n + 1; i < n + 1; i++) - { - n = unchecked(i * i); - } - } - } - - public void ForWithCheckedInitializerAndUncheckedIterator(int n) - { - checked - { - int i = n; - for (i -= 10; i < n; i = unchecked(i + 1)) - { - n--; - } - } - } - public void ObjectCreationInitializerChecked() - { - this.TestHelp(new - { - x = 0, - l = 0 - }, n => checked(new - { - x = n.x + 1, - l = n.l + 1 - })); - } - - public void ObjectCreationWithOneFieldChecked() - { - this.TestHelp(new - { - x = 0, - l = 0 - }, n => new - { - x = checked(n.x + 1), - l = n.l + 1 - }); - } - - - public void ArrayInitializerChecked() - { - this.TestHelp(new int[] - { - 1, - 2 - }, (int[] n) => checked(new int[] - { - n[0] + 1, - n[1] + 1 - })); - } - - public T TestHelp(T t, Func f) - { - return f(t); - } - - public void CheckedInArrayCreationArgument(int a, int b) - { - Console.WriteLine(new int[checked(a + b)]); - } -} diff --git a/ICSharpCode.Decompiler/Tests/CodeSampleFileParser.cs b/ICSharpCode.Decompiler/Tests/CodeSampleFileParser.cs deleted file mode 100644 index 5cb49aad..00000000 --- a/ICSharpCode.Decompiler/Tests/CodeSampleFileParser.cs +++ /dev/null @@ -1,133 +0,0 @@ -// Copyright (c) AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.IO; - -namespace ICSharpCode.Decompiler.Tests -{ - static class CodeSampleFileParser - { - public static IEnumerable ListSections(string s) - { - var query = from line in ToLines(s) - let sectionName = ReadSectionName(line) - where sectionName != null - select sectionName; - return query; - } - - public static string GetSection(string sectionName, string s) - { - var lines = ToLines(s); - - bool sectionFound = false; - var sectionText = new StringBuilder(); - - Action parser = null; - - Action commonSectionReader = line => - { - if (IsCommonSectionEnd(line)) - parser = null; - else - sectionText.AppendLine(line); - }; - - Action namedSectionReader = line => - { - string name = ReadSectionName(line); - if (name == null) - sectionText.AppendLine(line); - else if (name != sectionName) - parser = null; - }; - - Action defaultReader = line => - { - if (IsCommonSectionStart(line)) - parser = commonSectionReader; - else if (ReadSectionName(line) == sectionName) - { - parser = namedSectionReader; - sectionFound = true; - } - }; - - foreach(var line in lines) - { - (parser ?? defaultReader)(line); - } - - if (sectionFound) - return sectionText.ToString(); - else - return ""; - } - - public static bool IsCommentOrBlank(string s) - { - if(String.IsNullOrWhiteSpace(s)) - return true; - s = s.Trim(); - return s.StartsWith("//") || s.StartsWith("#"); // Also ignore #pragmas for warning suppression - } - - public static string ConcatLines(IEnumerable lines) - { - var buffer = new StringBuilder(); - foreach (var line in lines) - { - buffer.AppendLine(line); - } - return buffer.ToString(); - } - - static string ReadSectionName(string line) - { - line = line.TrimStart(); - if (line.StartsWith("//$$")) - return line.Substring(4).Trim(); - else - return null; - } - - static bool IsCommonSectionStart(string line) - { - return line.Trim() == "//$CS"; - } - - static bool IsCommonSectionEnd(string line) - { - return line.Trim() == "//$CE"; - } - - static IEnumerable ToLines(string s) - { - var reader = new StringReader(s); - string line; - while ((line = reader.ReadLine()) != null) - { - yield return line; - } - } - } -} diff --git a/ICSharpCode.Decompiler/Tests/ControlFlow.cs b/ICSharpCode.Decompiler/Tests/ControlFlow.cs deleted file mode 100644 index d83f04a2..00000000 --- a/ICSharpCode.Decompiler/Tests/ControlFlow.cs +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright (c) AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; - -public static class ControlFlow -{ - public static void EmptyIf(string input, List value, Dictionary _headers) - { - if (value.Contains("test")) - { - } - _headers.Add(2, "result"); - } - - public static void NormalIf(string input, List value, Dictionary _headers) - { - if (value.Contains("test")) - { - _headers.Add(1, "result"); - } - else - { - _headers.Add(1, "else"); - } - _headers.Add(2, "end"); - } - - public static void NormalIf2(string input, List value, Dictionary _headers) - { - if (value.Contains("test")) - { - _headers.Add(1, "result"); - } - _headers.Add(2, "end"); - } - - public static void NormalIf3(string input, List value, Dictionary _headers) - { - if (value.Contains("test")) - { - _headers.Add(1, "result"); - } - else - { - _headers.Add(1, "else"); - } - } - - public static void Test(string input, List value, Dictionary _headers) - { - foreach (string current in value) - { - _headers.Add(0, current); - } - if (value.Contains("test")) - { - _headers.Add(1, "result"); - } - else - { - _headers.Add(1, "else"); - } - } - - public static void CascadingIfElse(bool condition, string input, int index) - { - if (condition) - { - Console.WriteLine("condition"); - } - else if (input == null) - { - Console.WriteLine("condition2"); - } - else if (index > 1) - { - Console.WriteLine("condition3"); - } - } -} diff --git a/ICSharpCode.Decompiler/Tests/CustomAttributes.code.cs b/ICSharpCode.Decompiler/Tests/CustomAttributes.code.cs deleted file mode 100644 index 4130b0b0..00000000 --- a/ICSharpCode.Decompiler/Tests/CustomAttributes.code.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -namespace aa -{ - public static class CustomAtributes - { - [Flags] - public enum EnumWithFlag - { - All = 15, - None = 0, - Item1 = 1, - Item2 = 2, - Item3 = 4, - Item4 = 8 - } - [AttributeUsage(AttributeTargets.All)] - public class MyAttribute : Attribute - { - public MyAttribute(CustomAtributes.EnumWithFlag en) - { - } - } - [CustomAtributes.MyAttribute(CustomAtributes.EnumWithFlag.Item1 | CustomAtributes.EnumWithFlag.Item2)] - private static int field; - [CustomAtributes.MyAttribute(CustomAtributes.EnumWithFlag.All)] - public static string Property - { - get - { - return "aa"; - } - } - [Obsolete("some message")] - public static void ObsoletedMethod() - { - Console.WriteLine("{0} $$$ {1}", AttributeTargets.Interface, AttributeTargets.Property | AttributeTargets.Field); - AttributeTargets attributeTargets = AttributeTargets.Property | AttributeTargets.Field; - Console.WriteLine("{0} $$$ {1}", AttributeTargets.Interface, attributeTargets); - } - } -} diff --git a/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeTests.cs b/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeTests.cs deleted file mode 100644 index 892f33bf..00000000 --- a/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeTests.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using NUnit.Framework; - -namespace ICSharpCode.Decompiler.Tests.CustomAttributes -{ - [TestFixture] - public class CustomAttributeTests : DecompilerTestBase - { - [Test] - public void CustomAttributeSamples() - { - ValidateFileRoundtrip(@"CustomAttributes\S_CustomAttributeSamples.cs"); - } - - [Test] - public void CustomAttributesMultiTest() - { - ValidateFileRoundtrip(@"CustomAttributes\S_CustomAttributes.cs"); - } - - [Test] - public void AssemblyCustomAttributesMultiTest() - { - ValidateFileRoundtrip(@"CustomAttributes\S_AssemblyCustomAttribute.cs"); - } - } -} diff --git a/ICSharpCode.Decompiler/Tests/CustomAttributes/S_AssemblyCustomAttribute.cs b/ICSharpCode.Decompiler/Tests/CustomAttributes/S_AssemblyCustomAttribute.cs deleted file mode 100644 index feaa04a6..00000000 --- a/ICSharpCode.Decompiler/Tests/CustomAttributes/S_AssemblyCustomAttribute.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; - -[assembly: CLSCompliant(false)] diff --git a/ICSharpCode.Decompiler/Tests/CustomAttributes/S_CustomAttributeSamples.cs b/ICSharpCode.Decompiler/Tests/CustomAttributes/S_CustomAttributeSamples.cs deleted file mode 100644 index 7154b2c3..00000000 --- a/ICSharpCode.Decompiler/Tests/CustomAttributes/S_CustomAttributeSamples.cs +++ /dev/null @@ -1,508 +0,0 @@ -// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -//$CS -using System; -//$CE - -//$$ TargetModule (ignored) -//[module: CLSCompliantAttribute(false)] -//$$ ParameterlessAttributeUsage -namespace ParameterLessAttributeUsage -{ - [Flags] - public enum EnumWithFlagsAttribute - { - None = 0 - } -} -//$$ AttributeWithEnumArgument -namespace AttributeWithEnumArgument -{ - [AttributeUsage(AttributeTargets.All)] - public class MyAttributeAttribute : Attribute - { - } -} -//$$ AttributeWithEnumExpressionArgument -namespace AttributeWithEnumExpressionArgument -{ - [AttributeUsage(AttributeTargets.Method | AttributeTargets.Interface)] - public class MyAttributeAttribute : Attribute - { - } -} -//$$ AttributeWithStringExpressionArgument -namespace AttributeWithStringExpressionArgument -{ - [Obsolete("message")] - public class ObsoletedClass - { - } -} -//$$ AttributeWithTypeArgument -namespace AttributeWithTypeArgument -{ - [AttributeUsage(AttributeTargets.All)] - public class MyTypeAttribute : Attribute - { - public MyTypeAttribute(Type t) - { - } - } - - [MyType(typeof(Attribute))] - public class SomeClass - { - } -} -//$$ AppliedToEvent -namespace AppliedToEvent -{ - [AttributeUsage(AttributeTargets.Event)] - public class MyAttributeAttribute : Attribute - { - } - public class TestClass - { - [MyAttribute] - public event EventHandler MyEvent; - } -} -//$$ AppliedToEventMethods -namespace AppliedToEventMethods -{ - [AttributeUsage(AttributeTargets.Method)] - public class MyAttributeAttribute : Attribute - { - } - public class TestClass - { - [method: MyAttribute] - public event EventHandler MyEvent; - } -} -//$$ AppliedToField -namespace AppliedToField -{ - [AttributeUsage(AttributeTargets.Field)] - public class MyAttributeAttribute : Attribute - { - } - public class TestClass - { - [MyAttribute] - public int Field; - } -} -//$$ AppliedToProperty -namespace AppliedToProperty -{ - public class TestClass - { - [Obsolete("reason")] - public int Property - { - get - { - return 0; - } - } - } -} -//$$ AppliedToPropertyGet -namespace AppliedToPropertyGet -{ - [AttributeUsage(AttributeTargets.All)] - public class MyAttributeAttribute : Attribute - { - } - public class TestClass - { - public int Property - { - [MyAttribute] - get - { - return 0; - } - } - } -} -//$$ AppliedToPropertySet -namespace AppliedToPropertySet -{ - [AttributeUsage(AttributeTargets.All)] - public class MyAttributeAttribute : Attribute - { - } - public class TestClass - { - public int Property - { - get - { - return 3; - } - [MyAttribute] - set - { - } - } - } -} -//$$ AppliedToIndexer -namespace AppliedToIndexer -{ - public class TestClass - { - [Obsolete("reason")] - public int this[int i] - { - get - { - return 0; - } - } - } -} -//$$ AppliedToDelegate -[Obsolete("reason")] -public delegate int AppliedToDelegate(); -//$$ AppliedToMethod -namespace AppliedToMethod -{ - [AttributeUsage(AttributeTargets.Method)] - public class MyAttributeAttribute : Attribute - { - } - public class TestClass - { - [MyAttribute] - public void Method() - { - } - } -} -//$$ AppliedToInterface -[Obsolete("reason")] -public interface AppliedToInterface -{ -} -//$$ AppliedToStruct -[Obsolete("reason")] -public struct AppliedToStruct -{ - public int Field; -} -//$$ AppliedToParameter -namespace AppliedToParameter -{ - [AttributeUsage(AttributeTargets.Parameter)] - public class MyAttributeAttribute : Attribute - { - } - public class MyClass - { - public void Method([MyAttribute] int val) - { - } - } -} -//$$ NamedInitializerProperty -namespace NamedInitializerProperty -{ - [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] - public class MyAttributeAttribute : Attribute - { - } -} -//$$ NamedInitializerPropertyString -namespace NamedInitializerPropertyString -{ - [AttributeUsage(AttributeTargets.All)] - public class MyAttributeAttribute : Attribute - { - public string Prop - { - get - { - return ""; - } - set - { - } - } - } - [MyAttribute(Prop = "value")] - public class MyClass - { - } -} -//$$ NamedInitializerPropertyType -namespace NamedInitializerPropertyType -{ - [AttributeUsage(AttributeTargets.All)] - public class MyAttributeAttribute : Attribute - { - public Type Prop - { - get - { - return null; - } - set - { - } - } - } - [MyAttribute(Prop = typeof(Enum))] - public class MyClass - { - } -} -//$$ NamedInitializerPropertyEnum -namespace NamedInitializerPropertyEnum -{ - [AttributeUsage(AttributeTargets.All)] - public class MyAttributeAttribute : Attribute - { - public AttributeTargets Prop - { - get - { - return AttributeTargets.All; - } - set - { - } - } - } - [MyAttribute(Prop = (AttributeTargets.Class | AttributeTargets.Method))] - public class MyClass - { - } -} -//$$ NamedInitializerFieldEnum -namespace NamedInitializerFieldEnum -{ - [AttributeUsage(AttributeTargets.All)] - public class MyAttributeAttribute : Attribute - { - public AttributeTargets Field; - } - [MyAttribute(Field = (AttributeTargets.Class | AttributeTargets.Method))] - public class MyClass - { - } -} -//$$ TargetReturn -namespace TargetReturn -{ - [AttributeUsage(AttributeTargets.All)] - public class MyAttributeAttribute : Attribute - { - } - public class MyClass - { - [return: MyAttribute] - public int MyMethod() - { - return 5; - } - } -} -//$$ TargetPropertyGetReturn -namespace TargetPropertyGetReturn -{ - [AttributeUsage(AttributeTargets.All)] - public class MyAttributeAttribute : Attribute - { - } - public class MyClass - { - public int Prop - { - [return: MyAttribute] - get - { - return 3; - } - } - } -} -//$$ TargetPropertySetParam -namespace TargetPropertySetParam -{ - [AttributeUsage(AttributeTargets.All)] - public class MyAttributeAttribute : Attribute - { - } - public class MyClass - { - public int Prop - { - [param: MyAttribute] - set - { - } - } - } -} -//$$ TargetPropertySetReturn -namespace TargetPropertySetReturn -{ - [AttributeUsage(AttributeTargets.All)] - public class MyAttributeAttribute : Attribute - { - } - public class MyClass - { - public int Prop - { - get - { - return 3; - } - [return: MyAttribute] - set - { - } - } - } -} -//$$ TargetPropertyIndexGetReturn -namespace TargetPropertyIndexGetReturn -{ - [AttributeUsage(AttributeTargets.All)] - public class MyAttributeAttribute : Attribute - { - } - public class MyClass - { - public int this[string s] - { - [return: MyAttribute] - get - { - return 3; - } - } - } -} -//$$ TargetPropertyIndexParamOnlySet -namespace TargetPropertyIndexParamOnlySet -{ - [AttributeUsage(AttributeTargets.All)] - public class MyAttributeAttribute : Attribute - { - } - public class MyClass - { - public int this[[MyAttribute] string s] - { - set - { - } - } - } -} -//$$ TargetPropertyIndexParamOnlyGet -namespace TargetPropertyIndexParamOnlyGet -{ - [AttributeUsage(AttributeTargets.All)] - public class MyAttributeAttribute : Attribute - { - } - public class MyClass - { - public int this[[MyAttribute] string s] - { - get - { - return 3; - } - } - } -} -//$$ TargetPropertyIndexSetReturn -namespace TargetPropertyIndexSetReturn -{ - [AttributeUsage(AttributeTargets.All)] - public class MyAttributeAttribute : Attribute - { - } - public class MyClass - { - public string this[int index] - { - get - { - return ""; - } - [return: MyAttribute] - set - { - } - } - } -} -//$$ TargetPropertyIndexSetMultiParam -namespace TargetPropertyIndexSetMultiParam -{ - [AttributeUsage(AttributeTargets.All)] - public class MyAttributeAttribute : Attribute - { - public int Field; - } - public class MyClass - { - public string this[[MyAttribute(Field = 2)] int index1, [MyAttribute(Field = 3)] int index2] - { - get - { - return ""; - } - [param: MyAttribute] - set - { - } - } - } -} -//$$ ClassAttributeOnTypeParameter -namespace ClassAttributeOnTypeParameter -{ - [AttributeUsage(AttributeTargets.All)] - public class MyAttributeAttribute : Attribute - { - } - public class MyClass<[MyAttribute] T> - { - } -} -//$$ AttributeOnReturnTypeOfDelegate -namespace AttributeOnReturnTypeOfDelegate -{ - [AttributeUsage(AttributeTargets.All)] - public class MyAttributeAttribute : Attribute - { - } - [return: MyAttribute] - public delegate void Test(); -} diff --git a/ICSharpCode.Decompiler/Tests/CustomAttributes/S_CustomAttributes.cs b/ICSharpCode.Decompiler/Tests/CustomAttributes/S_CustomAttributes.cs deleted file mode 100644 index 37c1c0d7..00000000 --- a/ICSharpCode.Decompiler/Tests/CustomAttributes/S_CustomAttributes.cs +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; - -namespace aa -{ - public static class CustomAttributes - { - [Flags] - public enum EnumWithFlag - { - All = 15, - None = 0, - Item1 = 1, - Item2 = 2, - Item3 = 4, - Item4 = 8 - } - [AttributeUsage(AttributeTargets.All)] - public class MyAttribute : Attribute - { - public MyAttribute(object val) - { - } - } - [CustomAttributes.MyAttribute(CustomAttributes.EnumWithFlag.Item1 | CustomAttributes.EnumWithFlag.Item2)] - private static int field; - [CustomAttributes.MyAttribute(CustomAttributes.EnumWithFlag.All)] - public static string Property - { - get - { - return "aa"; - } - } - [Obsolete("some message")] - public static void ObsoletedMethod() - { - //Console.WriteLine("{0} $$$ {1}", AttributeTargets.Interface, (AttributeTargets)(AttributeTargets.Property | AttributeTargets.Field)); - Console.WriteLine("{0} $$$ {1}", AttributeTargets.Interface, AttributeTargets.Property | AttributeTargets.Field); - AttributeTargets attributeTargets = AttributeTargets.Property | AttributeTargets.Field; - Console.WriteLine("{0} $$$ {1}", AttributeTargets.Interface, attributeTargets); - } - // No Boxing - [CustomAttributes.MyAttribute(new StringComparison[] - { - StringComparison.Ordinal, - StringComparison.CurrentCulture - })] - public static void ArrayAsAttribute1() - { - } - // Boxing of each array element - [CustomAttributes.MyAttribute(new object[] - { - StringComparison.Ordinal, - StringComparison.CurrentCulture - })] - public static void ArrayAsAttribute2() - { - } - } -} diff --git a/ICSharpCode.Decompiler/Tests/CustomShortCircuitOperators.cs b/ICSharpCode.Decompiler/Tests/CustomShortCircuitOperators.cs deleted file mode 100644 index 5bd0ec51..00000000 --- a/ICSharpCode.Decompiler/Tests/CustomShortCircuitOperators.cs +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) 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; - -public static class CustomShortCircuitOperators -{ - // TODO: Restore base class after https://roslyn.codeplex.com/workitem/358 is fixed. - private class C - { - public static bool operator true(CustomShortCircuitOperators.C x) - { - return true; - } - - public static bool operator false(CustomShortCircuitOperators.C x) - { - return false; - } - - public static CustomShortCircuitOperators.C operator &(CustomShortCircuitOperators.C x, CustomShortCircuitOperators.C y) - { - return null; - } - - public static CustomShortCircuitOperators.C operator |(CustomShortCircuitOperators.C x, CustomShortCircuitOperators.C y) - { - return null; - } - - public static bool operator !(CustomShortCircuitOperators.C x) - { - return false; - } - - private static void Main() - { - CustomShortCircuitOperators.C c = new CustomShortCircuitOperators.C(); - CustomShortCircuitOperators.C c2 = new CustomShortCircuitOperators.C(); - CustomShortCircuitOperators.C c3 = c && c2; - CustomShortCircuitOperators.C c4 = c || c2; - Console.WriteLine(c3.ToString()); - Console.WriteLine(c4.ToString()); - } - - private static void Test2() - { - CustomShortCircuitOperators.C c = new CustomShortCircuitOperators.C(); - if (c && c) - { - Console.WriteLine(c.ToString()); - } - - if (!(c && c)) - { - Console.WriteLine(c.ToString()); - } - } - - private static void Test3() - { - CustomShortCircuitOperators.C c = new CustomShortCircuitOperators.C(); - if (c) - { - Console.WriteLine(c.ToString()); - } - if (!c) - { - Console.WriteLine(c.ToString()); - } - } - } -} \ No newline at end of file diff --git a/ICSharpCode.Decompiler/Tests/DecompilerTestBase.cs b/ICSharpCode.Decompiler/Tests/DecompilerTestBase.cs deleted file mode 100644 index 659bb2be..00000000 --- a/ICSharpCode.Decompiler/Tests/DecompilerTestBase.cs +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (c) 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.CodeDom.Compiler; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; - -using ICSharpCode.Decompiler.Ast; -using ICSharpCode.Decompiler.Tests.Helpers; -using Microsoft.CSharp; -using Mono.Cecil; -using NUnit.Framework; - -namespace ICSharpCode.Decompiler.Tests -{ - public abstract class DecompilerTestBase - { - protected static void ValidateFileRoundtrip(string samplesFileName) - { - var fullPath = Path.Combine(@"..\..\Tests", samplesFileName); - AssertRoundtripCode(fullPath); - } - - static string RemoveIgnorableLines(IEnumerable lines) - { - return CodeSampleFileParser.ConcatLines(lines.Where(l => !CodeSampleFileParser.IsCommentOrBlank(l))); - } - - protected static void AssertRoundtripCode(string fileName, bool optimize = false, bool useDebug = false, int compilerVersion = 4) - { - var code = RemoveIgnorableLines(File.ReadLines(fileName)); - AssemblyDefinition assembly = CompileLegacy(code, optimize, useDebug, compilerVersion); - - AstBuilder decompiler = new AstBuilder(new DecompilerContext(assembly.MainModule)); - decompiler.AddAssembly(assembly); - new Helpers.RemoveCompilerAttribute().Run(decompiler.SyntaxTree); - - StringWriter output = new StringWriter(); - decompiler.GenerateCode(new PlainTextOutput(output)); - CodeAssert.AreEqual(code, output.ToString()); - } - - protected static AssemblyDefinition CompileLegacy(string code, bool optimize, bool useDebug, int compilerVersion) - { - CSharpCodeProvider provider = new CSharpCodeProvider(new Dictionary { { "CompilerVersion", "v" + new Version(compilerVersion, 0) } }); - CompilerParameters options = new CompilerParameters(); - options.CompilerOptions = "/unsafe /o" + (optimize ? "+" : "-") + (useDebug ? " /debug" : ""); - if (compilerVersion >= 4) - options.ReferencedAssemblies.Add("System.Core.dll"); - CompilerResults results = provider.CompileAssemblyFromSource(options, code); - try - { - if (results.Errors.Count > 0) - { - StringBuilder b = new StringBuilder("Compiler error:"); - foreach (var error in results.Errors) - { - b.AppendLine(error.ToString()); - } - throw new Exception(b.ToString()); - } - return AssemblyDefinition.ReadAssembly(results.PathToAssembly); - } - finally - { - File.Delete(results.PathToAssembly); - results.TempFiles.Delete(); - } - } - } -} diff --git a/ICSharpCode.Decompiler/Tests/DelegateConstruction.cs b/ICSharpCode.Decompiler/Tests/DelegateConstruction.cs deleted file mode 100644 index 70c00fc6..00000000 --- a/ICSharpCode.Decompiler/Tests/DelegateConstruction.cs +++ /dev/null @@ -1,205 +0,0 @@ -// Copyright (c) AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Linq; - -public static class DelegateConstruction -{ - class InstanceTests - { - public Action CaptureOfThis() - { - return delegate { - CaptureOfThis(); - }; - } - - public Action CaptureOfThisAndParameter(int a) - { - return delegate { - CaptureOfThisAndParameter(a); - }; - } - - public Action CaptureOfThisAndParameterInForEach(int a) - { - foreach (int item in Enumerable.Empty()) { - if (item > 0) { - return delegate { - CaptureOfThisAndParameter(item + a); - }; - } - } - return null; - } - - public Action CaptureOfThisAndParameterInForEachWithItemCopy(int a) - { - foreach (int item in Enumerable.Empty()) { - int copyOfItem = item; - if (item > 0) { - return delegate { - CaptureOfThisAndParameter(item + a + copyOfItem); - }; - } - } - return null; - } - - public void LambdaInForLoop() - { - for (int i = 0; i < 100000; i++) { - Bar(() => Foo()); - } - } - - public int Foo() - { - return 0; - } - - public void Bar(Func f) - { - } - } - - public static void Test(this string a) - { - } - - public static Action ExtensionMethodUnbound() - { - return new Action(DelegateConstruction.Test); - } - - public static Action ExtensionMethodBound() - { - return new Action("abc".Test); - } - - public static Action ExtensionMethodBoundOnNull() - { - return new Action(((string)null).Test); - } - - public static object StaticMethod() - { - return new Func(DelegateConstruction.ExtensionMethodBound); - } - - public static object InstanceMethod() - { - return new Func("hello".ToUpper); - } - - public static object InstanceMethodOnNull() - { - return new Func(((string)null).ToUpper); - } - - public static List> AnonymousMethodStoreWithinLoop() - { - List> list = new List>(); - for (int i = 0; i < 10; i++) - { - int counter; - list.Add(delegate(int x) - { - counter = x; - } - ); - } - return list; - } - - public static List> AnonymousMethodStoreOutsideLoop() - { - List> list = new List>(); - int counter; - for (int i = 0; i < 10; i++) - { - list.Add(delegate(int x) - { - counter = x; - } - ); - } - return list; - } - - public static Action StaticAnonymousMethodNoClosure() - { - return delegate - { - Console.WriteLine(); - }; - } - - public static void NameConflict() - { - // i is captured variable, - // j is parameter in anonymous method - // k is local in anonymous method, - // l is local in main method - // Ensure that the decompiler doesn't introduce name conflicts - List> list = new List>(); - for (int l = 0; l < 10; l++) { - int i; - for (i = 0; i < 10; i++) { - list.Add( - delegate (int j) { - for (int k = 0; k < i; k += j) { - Console.WriteLine(); - } - }); - } - } - } - - public static void NameConflict2(int j) - { - List> list = new List>(); - for (int k = 0; k < 10; k++) { - list.Add( - delegate(int i) { - Console.WriteLine(i); - }); - } - } - - public static Action NameConflict3(int i) - { - return delegate(int j) { - for (int k = 0; k < j; k++) { - Console.WriteLine(k); - } - }; - } - - public static Func> CurriedAddition(int a) - { - return b => c => a + b + c; - } - - public static Func>> CurriedAddition2(int a) - { - return b => c => d => a + b + c + d; - } -} diff --git a/ICSharpCode.Decompiler/Tests/DoubleConstants.cs b/ICSharpCode.Decompiler/Tests/DoubleConstants.cs deleted file mode 100644 index 2bc20a77..00000000 --- a/ICSharpCode.Decompiler/Tests/DoubleConstants.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) 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; - -public class DoubleConstants -{ - public const double Zero = 0.0; - public const double MinusZero = -0.0; - public const double NaN = double.NaN; - public const double PositiveInfinity = double.PositiveInfinity; - public const double NegativeInfinity = double.NegativeInfinity; -} diff --git a/ICSharpCode.Decompiler/Tests/ExceptionHandling.cs b/ICSharpCode.Decompiler/Tests/ExceptionHandling.cs deleted file mode 100644 index 0db35e35..00000000 --- a/ICSharpCode.Decompiler/Tests/ExceptionHandling.cs +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright (c) 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; - -public class ExceptionHandling -{ - public void MethodEndingWithEndFinally() - { - try - { - throw null; - } - finally - { - Console.WriteLine(); - } - } - - public void MethodEndingWithRethrow() - { - try - { - throw null; - } - catch - { - throw; - } - } - - public void TryCatchFinally() - { - try - { - Console.WriteLine("Try"); - } - catch (Exception ex) - { - Console.WriteLine(ex.Message); - } - finally - { - Console.WriteLine("Finally"); - } - } - - public void TryCatchMultipleHandlers() - { - try - { - Console.WriteLine("Try"); - } - catch (InvalidOperationException ex) - { - Console.WriteLine(ex.Message); - } - catch (Exception ex2) - { - Console.WriteLine(ex2.Message); - } - catch - { - Console.WriteLine("other"); - } - } - - public void NoUsingStatementBecauseTheVariableIsAssignedTo() - { - CancellationTokenSource cancellationTokenSource = null; - try - { - cancellationTokenSource = new CancellationTokenSource(); - } - finally - { - if (cancellationTokenSource != null) - { - cancellationTokenSource.Dispose(); - } - } - } - - public void UsingStatementThatChangesTheVariable() - { - CancellationTokenSource cancellationTokenSource = null; - using (cancellationTokenSource) - { - cancellationTokenSource = new CancellationTokenSource(); - } - } - - public void TwoCatchBlocksWithSameVariable() - { - try - { - Console.WriteLine("Try1"); - } - catch (Exception ex) - { - Console.WriteLine(ex.Message); - } - try - { - Console.WriteLine("Try2"); - } - catch (Exception ex) - { - Console.WriteLine(ex.Message); - } - } -} diff --git a/ICSharpCode.Decompiler/Tests/ExpressionTrees.cs b/ICSharpCode.Decompiler/Tests/ExpressionTrees.cs deleted file mode 100644 index 9d325e9e..00000000 --- a/ICSharpCode.Decompiler/Tests/ExpressionTrees.cs +++ /dev/null @@ -1,370 +0,0 @@ -// Copyright (c) AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Linq.Expressions; -using System.Xml; - -public class ExpressionTrees -{ - class GenericClass - { - public static X StaticField; - public X InstanceField; - public static X StaticProperty { get; set; } - public X InstanceProperty { get; set; } - - public static bool GenericMethod() - { - return false; - } - } - - int field; - - static object ToCode(object x, Expression> expr) - { - return expr; - } - - static object ToCode(object x, Expression> expr) - { - return expr; - } - - static object X() - { - return null; - } - - public void Parameter(bool a) - { - ToCode(X(), () => a); - } - - public void LocalVariable() - { - bool a = true; - ToCode(X(), () => a); - } - - public void LambdaParameter() - { - ToCode(X(), (bool a) => a); - } - - public void AddOperator(int x) - { - ToCode(X(), () => 1 + x + 2); - } - - public void AnonymousClasses() - { - ToCode(X(), () => new { X = 3, A = "a" }); - } - - public void ArrayIndex() - { - ToCode(X(), () => new[] { 3, 4, 5 }[0 + (int)(DateTime.Now.Ticks % 3)]); - } - - public void ArrayLengthAndDoubles() - { - ToCode(X(), () => new[] { 1.0, 2.01, 3.5 }.Concat(new[] { 1.0, 2.0 }).ToArray().Length); - } - - public void AsOperator() - { - ToCode(X(), () => new object() as string); - } - - public void ComplexGenericName() - { - ToCode(X(), () => ((Func)(x => x > 0))(0)); - } - - public void DefaultValue() - { - ToCode(X(), () => new TimeSpan(1, 2, 3) == default(TimeSpan)); - } - - public void EnumConstant() - { - ToCode(X(), () => new object().Equals(MidpointRounding.ToEven)); - } - - public void IndexerAccess() - { - var dict = Enumerable.Range(1, 20).ToDictionary(n => n.ToString()); - ToCode(X(), () => dict["3"] == 3); - } - - public void IsOperator() - { - ToCode(X(), () => new object() is string); - } - - public void ListInitializer() - { - ToCode(X(), () => new Dictionary { { 1, 1 }, { 2, 2 }, { 3, 4 } }.Count == 3); - } - - public void ListInitializer2() - { - ToCode(X(), () => new List(50) { 1, 2, 3 }.Count == 3); - } - - public void ListInitializer3() - { - ToCode(X(), () => new List { 1, 2, 3 }.Count == 3); - } - - public void LiteralCharAndProperty() - { - ToCode(X(), () => new string(' ', 3).Length == 1); - } - - public void CharNoCast() - { - ToCode(X(), () => "abc"[1] == 'b'); - } - - public void StringsImplicitCast() - { - int i = 1; - string x = "X"; - ToCode(X(), () => (("a\n\\b" ?? x) + x).Length == 2 ? false : true && (1m + -i > 0 || false)); - } - - public void NotImplicitCast() - { - byte z = 42; - ToCode(X(), () => ~z == 0); - } - - public void MembersBuiltin() - { - ToCode(X(), () => 1.23m.ToString()); - ToCode(X(), () => AttributeTargets.All.HasFlag((Enum)AttributeTargets.Assembly)); - ToCode(X(), () => "abc".Length == 3); - ToCode(X(), () => 'a'.CompareTo('b') < 0); - } - - public void MembersDefault() - { - ToCode(X(), () => default(DateTime).Ticks == 0); - ToCode(X(), () => default(int[]).Length == 0); - ToCode(X(), () => default(Type).IsLayoutSequential); - ToCode(X(), () => default(List).Count); - ToCode(X(), () => default(int[]).Clone() == null); - ToCode(X(), () => default(Type).IsInstanceOfType(new object())); - ToCode(X(), () => default(List).AsReadOnly()); - } - - public void DoAssert() - { - field = 37; - ToCode(X(), () => field != C()); - ToCode(X(), () => !ReferenceEquals(this, new ExpressionTrees())); - ToCode(X(), () => MyEquals(this) && !MyEquals(default(ExpressionTrees))); - } - - int C() - { - return field + 5; - } - - bool MyEquals(ExpressionTrees other) - { - return other != null && field == other.field; - } - - public void MethodGroupAsExtensionMethod() - { - ToCode(X(), () => (Func)new[] { 2000, 2004, 2008, 2012 }.Any); - } - - public void MethodGroupConstant() - { - ToCode(X(), () => Array.TrueForAll(new[] { 2000, 2004, 2008, 2012 }, DateTime.IsLeapYear)); - - HashSet set = new HashSet(); - ToCode(X(), () => new[] { 2000, 2004, 2008, 2012 }.All(set.Add)); - - Func, bool> sink = f => f(null, null); - ToCode(X(), () => sink(int.Equals)); - } - - public void MultipleCasts() - { - ToCode(X(), () => 1 == (int)(object)1); - } - - public void MultipleDots() - { - ToCode(X(), () => 3.ToString().ToString().Length > 0); - } - - public void NestedLambda() - { - Func, int> call = f => f(); - //no params - ToCode(X(), () => call(() => 42)); - //one param - ToCode(X(), () => new[] { 37, 42 }.Select(x => x * 2)); - //two params - ToCode(X(), () => new[] { 37, 42 }.Select((x, i) => x * 2)); - } - - public void CurriedLambda() - { - ToCode>>(X(), a => b => c => a + b + c); - } - - bool Fizz(Func a) - { - return a(42); - } - - bool Buzz(Func a) - { - return a(42); - } - - bool Fizz(Func a) - { - return a("42"); - } - - public void NestedLambda2() - { - ToCode(X(), () => Fizz(x => x == "a")); - ToCode(X(), () => Fizz(x => x == 37)); - - ToCode(X(), () => Fizz((int x) => true)); - ToCode(X(), () => Buzz(x => true)); - } - - public void NewArrayAndExtensionMethod() - { - ToCode(X(), () => new[] { 1.0, 2.01, 3.5 }.SequenceEqual(new[] { 1.0, 2.01, 3.5 })); - } - - public void NewMultiDimArray() - { - ToCode(X(), () => new int[3, 4].Length == 1); - } - - public void NewObject() - { - ToCode(X(), () => new object() != new object()); - } - - public void NotOperator() - { - bool x = true; - int y = 3; - byte z = 42; - ToCode(X(), () => ~(int)z == 0); - ToCode(X(), () => ~y == 0); - ToCode(X(), () => !x); - } - - public void ObjectInitializers() - { - XmlReaderSettings s = new XmlReaderSettings { - CloseInput = false, - CheckCharacters = false - }; - ToCode(X(), () => new XmlReaderSettings { CloseInput = s.CloseInput, CheckCharacters = s.CheckCharacters }.Equals(s)); - } - - public void Quoted() - { - ToCode(X(), () => (Expression>)((n, s) => s + n.ToString()) != null); - } - - public void Quoted2() - { - ToCode(X(), () => ToCode(X(), () => true).Equals(null)); - } - - public void QuotedWithAnonymous() - { - ToCode(X(), () => new[] { new { X = "a", Y = "b" } }.Select(o => o.X + o.Y).Single()); - } - - public void StaticCall() - { - ToCode(X(), () => Equals(3, 0)); - } - - public void ThisCall() - { - ToCode(X(), () => !Equals(3)); - } - - public void ThisExplicit() - { - ToCode(X(), () => object.Equals(this, 3)); - } - - public void TypedConstant() - { - ToCode(X(), () => new[] { typeof(int), typeof(string) }); - } - - public void StaticCallImplicitCast() - { - ToCode(X(), () => Equals(3, 0)); - } - - public void StaticMembers() - { - ToCode(X(), () => (DateTime.Now > DateTime.Now + TimeSpan.FromMilliseconds(10.001)).ToString() == "False"); - } - - public void Strings() - { - int i = 1; - string x = "X"; - ToCode(X(), () => (("a\n\\b" ?? x) + x).Length == 2 ? false : true && (1m + (decimal)-i > 0m || false)); - } - - public void StringAccessor() - { - ToCode(X(), () => (int)"abc"[1] == 98); - } - - public void GenericClassInstance() - { - ToCode(X(), () => new GenericClass().InstanceField + new GenericClass().InstanceProperty); - } - - public void GenericClassStatic() - { - ToCode(X(), () => GenericClass.StaticField + GenericClass.StaticProperty); - } - - public void InvokeGenericMethod() - { - ToCode(X(), () => GenericClass.GenericMethod()); - } -} diff --git a/ICSharpCode.Decompiler/Tests/Generics.cs b/ICSharpCode.Decompiler/Tests/Generics.cs deleted file mode 100644 index 9776d42f..00000000 --- a/ICSharpCode.Decompiler/Tests/Generics.cs +++ /dev/null @@ -1,165 +0,0 @@ -// Copyright (c) AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; - -public static class Generics -{ - public class MyArray - { - public class NestedClass - { - public T Item1; - public Y Item2; - } - - public enum NestedEnum - { - A, - B - } - - private T[] arr; - - public MyArray(int capacity) - { - this.arr = new T[capacity]; - } - - public void Size(int capacity) - { - Array.Resize(ref this.arr, capacity); - } - - public void Grow(int capacity) - { - if (capacity >= this.arr.Length) - { - this.Size(capacity); - } - } - } - - public interface IInterface - { - void Method1() where T : class; - void Method2() where T : class; - } - - public abstract class Base : Generics.IInterface - { - // constraints must be repeated on implicit interface implementation - public abstract void Method1() where T : class; - - // constraints must not be specified on explicit interface implementation - void Generics.IInterface.Method2() - { - } - } - - public class Derived : Generics.Base - { - // constraints are inherited automatically and must not be specified - public override void Method1() - { - } - } - - private const Generics.MyArray.NestedEnum enumVal = Generics.MyArray.NestedEnum.A; - private static Type type1 = typeof(List<>); - private static Type type2 = typeof(Generics.MyArray<>); - private static Type type3 = typeof(List<>.Enumerator); - private static Type type4 = typeof(Generics.MyArray<>.NestedClass<>); - private static Type type5 = typeof(List[]); - private static Type type6 = typeof(Generics.MyArray<>.NestedEnum); - - public static void MethodWithConstraint() where T : class, S where S : ICloneable, new() - { - } - - public static void MethodWithStructConstraint() where T : struct - { - } - - private static void MultidimensionalArray(T[,] array) - { - array[0, 0] = array[0, 1]; - } - - public static Dictionary.KeyCollection.Enumerator GetEnumerator(Dictionary d, Generics.MyArray.NestedClass nc) - { - // Tests references to inner classes in generic classes - return d.Keys.GetEnumerator(); - } - - public static bool IsString(T input) - { - return input is string; - } - - public static string AsString(T input) - { - return input as string; - } - - public static string CastToString(T input) - { - return (string)((object)input); - } - - public static T CastFromString(string input) - { - return (T)((object)input); - } - - public static bool IsInt(T input) - { - return input is int; - } - - public static int CastToInt(T input) - { - return (int)((object)input); - } - - public static T CastFromInt(int input) - { - return (T)((object)input); - } - - public static bool IsNullableInt(T input) - { - return input is int?; - } - - public static int? AsNullableInt(T input) - { - return input as int?; - } - - public static int? CastToNullableInt(T input) - { - return (int?)((object)input); - } - - public static T CastFromNullableInt(int? input) - { - return (T)((object)input); - } -} diff --git a/ICSharpCode.Decompiler/Tests/Helpers/CodeAssert.cs b/ICSharpCode.Decompiler/Tests/Helpers/CodeAssert.cs deleted file mode 100644 index d06e2db2..00000000 --- a/ICSharpCode.Decompiler/Tests/Helpers/CodeAssert.cs +++ /dev/null @@ -1,110 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using DiffLib; -using NUnit.Framework; - -namespace ICSharpCode.Decompiler.Tests.Helpers -{ - public class CodeAssert - { - public static void AreEqual(string input1, string input2) - { - var diff = new StringWriter(); - if (!Compare(input1, input2, diff)) { - Assert.Fail(diff.ToString()); - } - } - - static bool Compare(string input1, string input2, StringWriter diff) - { - var differ = new AlignedDiff( - NormalizeAndSplitCode(input1), - NormalizeAndSplitCode(input2), - new CodeLineEqualityComparer(), - new StringSimilarityComparer(), - new StringAlignmentFilter()); - - bool result = true, ignoreChange; - - int line1 = 0, line2 = 0; - - foreach (var change in differ.Generate()) { - switch (change.Change) { - case ChangeType.Same: - diff.Write("{0,4} {1,4} ", ++line1, ++line2); - diff.Write(" "); - diff.WriteLine(change.Element1); - break; - case ChangeType.Added: - diff.Write(" {1,4} ", line1, ++line2); - result &= ignoreChange = ShouldIgnoreChange(change.Element2); - diff.Write(ignoreChange ? " " : " + "); - diff.WriteLine(change.Element2); - break; - case ChangeType.Deleted: - diff.Write("{0,4} ", ++line1, line2); - result &= ignoreChange = ShouldIgnoreChange(change.Element1); - diff.Write(ignoreChange ? " " : " - "); - diff.WriteLine(change.Element1); - break; - case ChangeType.Changed: - diff.Write("{0,4} ", ++line1, line2); - result = false; - diff.Write("(-) "); - diff.WriteLine(change.Element1); - diff.Write(" {1,4} ", line1, ++line2); - diff.Write("(+) "); - diff.WriteLine(change.Element2); - break; - } - } - - return result; - } - - class CodeLineEqualityComparer : IEqualityComparer - { - private IEqualityComparer baseComparer = EqualityComparer.Default; - - public bool Equals(string x, string y) - { - return baseComparer.Equals( - NormalizeLine(x), - NormalizeLine(y) - ); - } - - public int GetHashCode(string obj) - { - return baseComparer.GetHashCode(NormalizeLine(obj)); - } - } - - private static string NormalizeLine(string line) - { - line = line.Trim(); - var index = line.IndexOf("//"); - if (index >= 0) { - return line.Substring(0, index); - } else if (line.StartsWith("#")) { - return string.Empty; - } else { - return line; - } - } - - private static bool ShouldIgnoreChange(string line) - { - // for the result, we should ignore blank lines and added comments - return NormalizeLine(line) == string.Empty; - } - - private static IEnumerable NormalizeAndSplitCode(string input) - { - return input.Split(new[] { "\r\n", "\n\r", "\n", "\r" }, StringSplitOptions.RemoveEmptyEntries); - } - } -} diff --git a/ICSharpCode.Decompiler/Tests/Helpers/RemoveCompilerAttribute.cs b/ICSharpCode.Decompiler/Tests/Helpers/RemoveCompilerAttribute.cs deleted file mode 100644 index cb656202..00000000 --- a/ICSharpCode.Decompiler/Tests/Helpers/RemoveCompilerAttribute.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -using ICSharpCode.Decompiler.Ast.Transforms; -using ICSharpCode.NRefactory.CSharp; - -namespace ICSharpCode.Decompiler.Tests.Helpers -{ - class RemoveCompilerAttribute : DepthFirstAstVisitor, IAstTransform - { - public override object VisitAttribute(NRefactory.CSharp.Attribute attribute, object data) - { - var section = (AttributeSection)attribute.Parent; - SimpleType type = attribute.Type as SimpleType; - if (section.AttributeTarget == "assembly" && - (type.Identifier == "CompilationRelaxations" || type.Identifier == "RuntimeCompatibility" || type.Identifier == "SecurityPermission" || type.Identifier == "AssemblyVersion" || type.Identifier == "Debuggable")) - { - attribute.Remove(); - if (section.Attributes.Count == 0) - section.Remove(); - } - if (section.AttributeTarget == "module" && type.Identifier == "UnverifiableCode") - { - attribute.Remove(); - if (section.Attributes.Count == 0) - section.Remove(); - } - return null; - } - - public void Run(AstNode node) - { - node.AcceptVisitor(this, null); - } - } -} diff --git a/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj b/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj deleted file mode 100644 index 808290a4..00000000 --- a/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj +++ /dev/null @@ -1,137 +0,0 @@ - - - - {FEC0DA52-C4A6-4710-BE36-B484A20C5E22} - Debug - x86 - Library - ICSharpCode.Decompiler.Tests - ICSharpCode.Decompiler.Tests - v4.5 - Properties - True - False - 4 - false - False - 67,169,1058,728,1720,649 - - - - x86 - False - Auto - 4194304 - 4096 - - - AnyCPU - False - Auto - 4194304 - 4096 - - - ..\bin\Debug\ - true - Full - False - DEBUG;TRACE - - - ..\bin\Release\ - false - None - True - TRACE - - - - ..\..\packages\DiffLib.1.0.0.55\lib\net35-Client\DiffLib.dll - - - ..\..\packages\ICSharpCode.NRefactory.5.5.1\lib\Net40\ICSharpCode.NRefactory.dll - - - ..\..\packages\ICSharpCode.NRefactory.5.5.1\lib\Net40\ICSharpCode.NRefactory.CSharp.dll - - - False - .\nunit.framework.dll - - - - 3.5 - - - - 3.5 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {D68133BD-1E63-496E-9EDE-4FBDBF77B486} - Mono.Cecil - - - {984CC812-9470-4A13-AFF9-CC44068D666C} - ICSharpCode.Decompiler - - - - - - - - - - - \ No newline at end of file diff --git a/ICSharpCode.Decompiler/Tests/IL/ILTests.cs b/ICSharpCode.Decompiler/Tests/IL/ILTests.cs deleted file mode 100644 index f06f3108..00000000 --- a/ICSharpCode.Decompiler/Tests/IL/ILTests.cs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) 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 ICSharpCode.Decompiler.Ast; -using ICSharpCode.Decompiler.Tests.Helpers; -using Mono.Cecil; -using NUnit.Framework; - -namespace ICSharpCode.Decompiler.Tests -{ - [TestFixture] - public class ILTests - { - const string path = "../../Tests/IL"; - - [Test] - public void SequenceOfNestedIfs() - { - Run("SequenceOfNestedIfs.dll", "SequenceOfNestedIfs.Output.cs"); - } - - void Run(string compiledFile, string expectedOutputFile) - { - string expectedOutput = File.ReadAllText(Path.Combine(path, expectedOutputFile)); - var assembly = AssemblyDefinition.ReadAssembly(Path.Combine(path, compiledFile)); - AstBuilder decompiler = new AstBuilder(new DecompilerContext(assembly.MainModule)); - decompiler.AddAssembly(assembly); - new Helpers.RemoveCompilerAttribute().Run(decompiler.SyntaxTree); - StringWriter output = new StringWriter(); - decompiler.GenerateCode(new PlainTextOutput(output)); - CodeAssert.AreEqual(expectedOutput, output.ToString()); - } - } -} diff --git a/ICSharpCode.Decompiler/Tests/IL/SequenceOfNestedIfs.Output.cs b/ICSharpCode.Decompiler/Tests/IL/SequenceOfNestedIfs.Output.cs deleted file mode 100644 index 754d7daf..00000000 --- a/ICSharpCode.Decompiler/Tests/IL/SequenceOfNestedIfs.Output.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -[Serializable] -public class Material -{ - public static implicit operator bool(Material m) - { - return m == null; - } -} -[Serializable] -public class SequenceOfNestedIfs -{ - public bool _clear; - public Material _material; - public override bool CheckShader() - { - return false; - } - public override void CreateMaterials() - { - if (!this._clear) - { - if (!this.CheckShader()) - { - return; - } - this._material = new Material(); - } - if (!this._material) - { - if (!this.CheckShader()) - { - return; - } - this._material = new Material(); - } - if (!this._material) - { - if (!this.CheckShader()) - { - return; - } - this._material = new Material(); - } - if (!this._material) - { - if (this.CheckShader()) - { - this._material = new Material(); - } - } - } -} diff --git a/ICSharpCode.Decompiler/Tests/IL/SequenceOfNestedIfs.il b/ICSharpCode.Decompiler/Tests/IL/SequenceOfNestedIfs.il deleted file mode 100644 index 9c9b749c..00000000 --- a/ICSharpCode.Decompiler/Tests/IL/SequenceOfNestedIfs.il +++ /dev/null @@ -1,140 +0,0 @@ -// Metadata version: v2.0.50727 -.assembly extern mscorlib -{ - .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4.. - .ver 2:0:0:0 -} - -.assembly SequenceOfNestedIfs -{ - .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx - 63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows. - .hash algorithm 0x00008004 - .ver 0:0:0:0 -} -.module SequenceOfNestedIfs -// MVID: {DCEC8A87-5679-4EBE-89A3-51274D8B5446} -.imagebase 0x00400000 -.file alignment 0x00000200 -.stackreserve 0x00100000 -.subsystem 0x0003 // WINDOWS_CUI -.corflags 0x00000001 // ILONLY -// Image base: 0x01D60000 - - -// =============== CLASS MEMBERS DECLARATION =================== - -.class public auto ansi serializable beforefieldinit Material - extends [mscorlib]System.Object -{ - .method public hidebysig specialname rtspecialname - instance void .ctor() cil managed - { - // Code size 7 (0x7) - .maxstack 8 - IL_0000: ldarg.0 - IL_0001: call instance void [mscorlib]System.Object::.ctor() - IL_0006: ret - } // end of method Material::.ctor - - .method public hidebysig specialname static - bool op_Implicit(class Material m) cil managed - { - // Code size 11 (0xb) - .maxstack 8 - IL_0000: ldarg.0 - IL_0001: ldnull - IL_0008: ceq - IL_000a: ret - } // end of method Material::op_Implicit - -} // end of class Material - -.class public auto ansi serializable beforefieldinit SequenceOfNestedIfs - extends [mscorlib]System.Object -{ - .field public bool _clear - .field public class Material _material - .method public hidebysig specialname rtspecialname - instance void .ctor() cil managed - { - // Code size 7 (0x7) - .maxstack 8 - IL_0000: ldarg.0 - IL_0001: call instance void [mscorlib]System.Object::.ctor() - IL_0006: ret - } // end of method SequenceOfNestedIfs::.ctor - - .method public hidebysig virtual instance bool - CheckShader() cil managed - { - // Code size 2 (0x2) - .maxstack 8 - IL_0000: ldc.i4.0 - IL_0001: ret - } // end of method SequenceOfNestedIfs::CheckShader - - .method public hidebysig virtual instance void - CreateMaterials() cil managed - { - // Code size 168 (0xa8) - .maxstack 13 - IL_0000: ldarg.0 - IL_0001: ldfld bool SequenceOfNestedIfs::_clear - IL_0006: brtrue IL_0026 - - IL_000b: ldarg.0 - IL_000c: callvirt instance bool SequenceOfNestedIfs::CheckShader() - IL_0011: brtrue IL_001b - - IL_0016: br IL_00a7 - - IL_001b: ldarg.0 - IL_001c: newobj instance void Material::.ctor() - IL_0021: stfld class Material SequenceOfNestedIfs::_material - IL_0026: ldarg.0 - IL_0027: ldfld class Material SequenceOfNestedIfs::_material - IL_002c: call bool Material::op_Implicit(class Material) - IL_0031: brtrue IL_0051 - - IL_0036: ldarg.0 - IL_0037: callvirt instance bool SequenceOfNestedIfs::CheckShader() - IL_003c: brtrue IL_0046 - - IL_0041: br IL_00a7 - - IL_0046: ldarg.0 - IL_0047: newobj instance void Material::.ctor() - IL_004c: stfld class Material SequenceOfNestedIfs::_material - IL_0051: ldarg.0 - IL_0052: ldfld class Material SequenceOfNestedIfs::_material - IL_0057: call bool Material::op_Implicit(class Material) - IL_005c: brtrue IL_007c - - IL_0061: ldarg.0 - IL_0062: callvirt instance bool SequenceOfNestedIfs::CheckShader() - IL_0067: brtrue IL_0071 - - IL_006c: br IL_00a7 - - IL_0071: ldarg.0 - IL_0072: newobj instance void Material::.ctor() - IL_0077: stfld class Material SequenceOfNestedIfs::_material - IL_007c: ldarg.0 - IL_007d: ldfld class Material SequenceOfNestedIfs::_material - IL_0082: call bool Material::op_Implicit(class Material) - IL_0087: brtrue IL_00a7 - - IL_008c: ldarg.0 - IL_008d: callvirt instance bool SequenceOfNestedIfs::CheckShader() - IL_0092: brtrue IL_009c - - IL_0097: br IL_00a7 - - IL_009c: ldarg.0 - IL_009d: newobj instance void Material::.ctor() - IL_00a2: stfld class Material SequenceOfNestedIfs::_material - IL_00a7: ret - } // end of method SequenceOfNestedIfs::CreateMaterials - -} // end of class SequenceOfNestedIfs \ No newline at end of file diff --git a/ICSharpCode.Decompiler/Tests/IL/StackTests.il b/ICSharpCode.Decompiler/Tests/IL/StackTests.il deleted file mode 100644 index 51cee375..00000000 --- a/ICSharpCode.Decompiler/Tests/IL/StackTests.il +++ /dev/null @@ -1,132 +0,0 @@ -.assembly extern mscorlib -{ - .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) - .ver 4:0:0:0 -} -.assembly StackTests -{ - .hash algorithm 0x00008004 - .ver 1:0:4059:39717 -} -.module StackTests.exe -.imagebase 0x00400000 -.file alignment 0x00000200 -.stackreserve 0x00100000 -.subsystem 0x0003 // WINDOWS_CUI -.corflags 0x00000003 // ILONLY 32BITREQUIRED - -.class private auto ansi beforefieldinit StackTests.Program extends [mscorlib]System.Object -{ - .method public hidebysig static void Main(string[] args) cil managed - { - .entrypoint - .maxstack 8 - - ldc.i4.0 - call string StackTests.Program::Test1(bool cond) - call void [mscorlib]System.Console::WriteLine(string) // false - - ldc.i4.1 - call string StackTests.Program::Test1(bool cond) - call void [mscorlib]System.Console::WriteLine(string) // true - - ldc.i4.0 - ldc.i4.0 - ldc.i4.0 - call int32 StackTests.Program::Test2(int32 switch1, int32 br1, int32 br2) - call void [mscorlib]System.Console::WriteLine(int32) // 11 - - ldc.i4.0 - ldc.i4.1 - ldc.i4.0 - call int32 StackTests.Program::Test2(int32 switch1, int32 br1, int32 br2) - call void [mscorlib]System.Console::WriteLine(int32) // 21 - - ldc.i4.1 - ldc.i4.1 - ldc.i4.1 - call int32 StackTests.Program::Test2(int32 switch1, int32 br1, int32 br2) - call void [mscorlib]System.Console::WriteLine(int32) // 32 - - ldc.i4.2 - ldc.i4.1 - ldc.i4.0 - call int32 StackTests.Program::Test2(int32 switch1, int32 br1, int32 br2) - call void [mscorlib]System.Console::WriteLine(int32) // 23 - - ret - } - - .method public hidebysig static string Test1(bool cond) cil managed - { - ldarg.0 - brtrue TRUE - - FALSE: - ldstr "false" - br EXIT - - TRUE: - ldstr "true" - - EXIT: - ret - } - - .method public hidebysig static int32 Test2(int32 switch1, int32 br1, int32 br2) cil managed - { - ldarg.0 - switch (ENTRY1, ENTRY2, ENTRY3) - ldc.i4.0 - ret - - ENTRY1: - ldc.i4.1 - br BRANCH1 - - ENTRY2: - ldc.i4.2 - br BRANCH1 - - ENTRY3: - ldc.i4.3 - br BRANCH2 - - BRANCH1: - ldarg.1 - brtrue BRANCH2 - - EXIT1: - ldc.i4 10 - add - ret - - BRANCH2: - ldarg.2 - brtrue.s EXIT3 - - EXIT2: - ldc.i4 20 - add - ret - - EXIT3: - ldc.i4 30 - add - ret - } - - .method public hidebysig specialname rtspecialname - instance void .ctor() cil managed - { - // Code size 7 (0x7) - .maxstack 8 - IL_0000: ldarg.0 - IL_0001: call instance void [mscorlib]System.Object::.ctor() - IL_0006: ret - } // end of method Program::.ctor - -} // end of class StackTests.Program - - -// ============================================================= diff --git a/ICSharpCode.Decompiler/Tests/IncrementDecrement.cs b/ICSharpCode.Decompiler/Tests/IncrementDecrement.cs deleted file mode 100644 index e06b680d..00000000 --- a/ICSharpCode.Decompiler/Tests/IncrementDecrement.cs +++ /dev/null @@ -1,254 +0,0 @@ -// Copyright (c) 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; - -public class IncrementDecrement -{ - [Flags] - private enum MyEnum - { - None = 0, - One = 1, - Two = 2, - Four = 4 - } - - public class MutableClass - { - public int Field; - - public int Property - { - get; - set; - } - - public uint this[string name] - { - get - { - return 0u; - } - set - { - } - } - } - - private IncrementDecrement.MyEnum enumField; - public static int StaticField; - - public static int StaticProperty - { - get; - set; - } - - private IncrementDecrement.MutableClass M() - { - return new IncrementDecrement.MutableClass(); - } - - private int[,] Array() - { - return null; - } - - private unsafe int* GetPointer() - { - return null; - } - - public int PreIncrementInAddition(int i, int j) - { - return i + ++j; - } - - public int PreIncrementArrayElement(int[] array, int pos) - { - return --array[pos]; - } - - public int PreIncrementInstanceField() - { - return ++this.M().Field; - } - - public int PreIncrementInstanceField2(IncrementDecrement.MutableClass m) - { - return ++m.Field; - } - - public int PreIncrementInstanceProperty() - { - return ++this.M().Property; - } - - public int PreIncrementStaticField() - { - return ++IncrementDecrement.StaticField; - } - - public int PreIncrementStaticProperty() - { - return ++IncrementDecrement.StaticProperty; - } - -// public uint PreIncrementIndexer(string name) -// { -// return ++this.M()[name]; -// } - - public int PreIncrementByRef(ref int i) - { - return ++i; - } - - public unsafe int PreIncrementByPointer() - { - return ++(*this.GetPointer()); - } - - public int PreIncrement2DArray() - { - return ++this.Array()[1, 2]; - } - - public int CompoundAssignInstanceField() - { - return this.M().Field *= 10; - } - - public int CompoundAssignInstanceProperty() - { - return this.M().Property *= 10; - } - - public int CompoundAssignStaticField() - { - return IncrementDecrement.StaticField ^= 100; - } - - public int CompoundAssignStaticProperty() - { - return IncrementDecrement.StaticProperty &= 10; - } - - public int CompoundAssignArrayElement1(int[] array, int pos) - { - return array[pos] *= 10; - } - - public int CompoundAssignArrayElement2(int[] array) - { - return array[Environment.TickCount] *= 10; - } - -// public uint CompoundAssignIndexer(string name) -// { -// return this.M()[name] -= 2; -// } - - public int CompoundAssignIncrement2DArray() - { - return this.Array()[1, 2] %= 10; - } - - public int CompoundAssignByRef(ref int i) - { - return i <<= 2; - } - - public unsafe double CompoundAssignByPointer(double* ptr) - { - return *ptr /= 1.5; - } - - public void CompoundAssignEnum() - { - this.enumField |= IncrementDecrement.MyEnum.Two; - this.enumField &= ~IncrementDecrement.MyEnum.Four; - } - - public int PostIncrementInAddition(int i, int j) - { - return i++ + j; - } - - public void PostIncrementInlineLocalVariable(Func f) - { - int num = 0; - f(num++); - } - - public int PostIncrementArrayElement(int[] array, int pos) - { - return array[pos]--; - } - - public int PostIncrementStaticField() - { - return IncrementDecrement.StaticField++; - } - - public int PostIncrementStaticProperty() - { - return IncrementDecrement.StaticProperty++; - } - - public int PostIncrementInstanceField(IncrementDecrement.MutableClass m) - { - return m.Field++; - } - -// public uint PostIncrementIndexer(string name) -// { -// return this.M()[name]++; -// } - -// public unsafe int PostIncrementOfPointer(int* ptr) -// { -// return *(ptr++); -// } - - public int PostIncrementInstanceField() - { - return this.M().Field--; - } - - public int PostIncrementInstanceProperty() - { - return this.M().Property--; - } - - public int PostIncrement2DArray() - { - return this.Array()[IncrementDecrement.StaticField, IncrementDecrement.StaticProperty]++; - } - - public int PostIncrementByRef(ref int i) - { - return i++; - } - - public unsafe int PostIncrementByPointer() - { - return (*this.GetPointer())++; - } -} diff --git a/ICSharpCode.Decompiler/Tests/InitializerTests.cs b/ICSharpCode.Decompiler/Tests/InitializerTests.cs deleted file mode 100644 index 29e3d1d5..00000000 --- a/ICSharpCode.Decompiler/Tests/InitializerTests.cs +++ /dev/null @@ -1,885 +0,0 @@ -// Copyright (c) AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; - -public class InitializerTests -{ - private enum MyEnum - { - a, - b - } - - private enum MyEnum2 - { - c, - d - } - - private class Data - { - public List FieldList = new List(); - public InitializerTests.MyEnum a - { - get; - set; - } - public List PropertyList - { - get; - set; - } - - public InitializerTests.Data MoreData - { - get; - set; - } - - public InitializerTests.StructData NestedStruct - { - get; - set; - } - } - - private struct StructData - { - public int Field; - public int Property - { - get; - set; - } - - public InitializerTests.Data MoreData - { - get; - set; - } - - public StructData(int initialValue) - { - this = default(InitializerTests.StructData); - this.Field = initialValue; - this.Property = initialValue; - } - } - - // Helper methods used to ensure initializers used within expressions work correctly - private static void X(object a, object b) - { - } - - private static object Y() - { - return null; - } - - #region Array Initializers - public static void Array1() - { - InitializerTests.X(InitializerTests.Y(), new int[] - { - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10 - }); - } - - public static void Array2(int a, int b, int c) - { - InitializerTests.X(InitializerTests.Y(), new int[] - { - a, - 0, - b, - 0, - c - }); - } - - public static void NestedArray(int a, int b, int c) - { - InitializerTests.X(InitializerTests.Y(), new int[][] - { - new int[] - { - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10 - }, - new int[] - { - a, - b, - c - }, - new int[] - { - 1, - 2, - 3, - 4, - 5, - 6 - } - }); - } - - public static void ArrayBoolean() - { - InitializerTests.X(InitializerTests.Y(), new bool[] - { - true, - false, - true, - false, - false, - false, - true, - true - }); - } - - public static void ArrayByte() - { - InitializerTests.X(InitializerTests.Y(), new byte[] - { - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 254, - 255 - }); - } - - public static void ArraySByte() - { - InitializerTests.X(InitializerTests.Y(), new sbyte[] - { - -128, - -127, - 0, - 1, - 2, - 3, - 4, - 127 - }); - } - - public static void ArrayShort() - { - InitializerTests.X(InitializerTests.Y(), new short[] - { - -32768, - -1, - 0, - 1, - 32767 - }); - } - - public static void ArrayUShort() - { - InitializerTests.X(InitializerTests.Y(), new ushort[] - { - 0, - 1, - 32767, - 32768, - 65534, - 65535 - }); - } - - public static void ArrayInt() - { - InitializerTests.X(InitializerTests.Y(), new int[] - { - 1, - -2, - 2000000000, - 4, - 5, - -6, - 7, - 8, - 9, - 10 - }); - } - - public static void ArrayUInt() - { - InitializerTests.X(InitializerTests.Y(), new uint[] - { - 1u, - 2000000000u, - 3000000000u, - 4u, - 5u, - 6u, - 7u, - 8u, - 9u, - 10u - }); - } - - public static void ArrayLong() - { - InitializerTests.X(InitializerTests.Y(), new long[] - { - -4999999999999999999L, - -1L, - 0L, - 1L, - 4999999999999999999L - }); - } - - public static void ArrayULong() - { - InitializerTests.X(InitializerTests.Y(), new ulong[] - { - 1uL, - 2000000000uL, - 3000000000uL, - 4uL, - 5uL, - 6uL, - 7uL, - 8uL, - 4999999999999999999uL, - 9999999999999999999uL - }); - } - - public static void ArrayFloat() - { - InitializerTests.X(InitializerTests.Y(), new float[] - { - -1.5f, - 0f, - 1.5f, - float.NegativeInfinity, - float.PositiveInfinity, - float.NaN - }); - } - - public static void ArrayDouble() - { - InitializerTests.X(InitializerTests.Y(), new double[] - { - -1.5, - 0.0, - 1.5, - double.NegativeInfinity, - double.PositiveInfinity, - double.NaN - }); - } - - public static void ArrayDecimal() - { - InitializerTests.X(InitializerTests.Y(), new decimal[] - { - -100m, - 0m, - 100m, - -79228162514264337593543950335m, - 79228162514264337593543950335m, - 0.0000001m - }); - } - - public static void ArrayString() - { - InitializerTests.X(InitializerTests.Y(), new string[] - { - "", - null, - "Hello", - "World" - }); - } - - public static void ArrayEnum() - { - InitializerTests.X(InitializerTests.Y(), new InitializerTests.MyEnum[] - { - InitializerTests.MyEnum.a, - InitializerTests.MyEnum.b, - InitializerTests.MyEnum.a, - InitializerTests.MyEnum.b - }); - } - - public static void RecursiveArrayInitializer() - { - int[] array = new int[3]; - array[0] = 1; - array[1] = 2; - array[2] = array[1] + 1; - array[0] = 0; - } - #endregion - - public static void CollectionInitializerList() - { - InitializerTests.X(InitializerTests.Y(), new List - { - 1, - 2, - 3 - }); - } - - public static object RecursiveCollectionInitializer() - { - List list = new List(); - list.Add(list); - return list; - } - - public static void CollectionInitializerDictionary() - { - InitializerTests.X(InitializerTests.Y(), new Dictionary - { - { - "First", - 1 - }, - { - "Second", - 2 - }, - { - "Third", - 3 - } - }); - } - - public static void CollectionInitializerDictionaryWithEnumTypes() - { - InitializerTests.X(InitializerTests.Y(), new Dictionary - { - { - InitializerTests.MyEnum.a, - InitializerTests.MyEnum2.c - }, - { - InitializerTests.MyEnum.b, - InitializerTests.MyEnum2.d - } - }); - } - - public static void NotACollectionInitializer() - { - List list = new List(); - list.Add(1); - list.Add(2); - list.Add(3); - InitializerTests.X(InitializerTests.Y(), list); - } - - public static void ObjectInitializer() - { - InitializerTests.X(InitializerTests.Y(), new InitializerTests.Data - { - a = InitializerTests.MyEnum.a - }); - } - - public static void NotAObjectInitializer() - { - InitializerTests.Data data = new InitializerTests.Data(); - data.a = InitializerTests.MyEnum.a; - InitializerTests.X(InitializerTests.Y(), data); - } - - public static void ObjectInitializerAssignCollectionToField() - { - InitializerTests.X(InitializerTests.Y(), new InitializerTests.Data - { - a = InitializerTests.MyEnum.a, - FieldList = new List - { - InitializerTests.MyEnum2.c, - InitializerTests.MyEnum2.d - } - }); - } - - public static void ObjectInitializerAddToCollectionInField() - { - InitializerTests.X(InitializerTests.Y(), new InitializerTests.Data - { - a = InitializerTests.MyEnum.a, - FieldList = - { - InitializerTests.MyEnum2.c, - InitializerTests.MyEnum2.d - } - }); - } - - public static void ObjectInitializerAssignCollectionToProperty() - { - InitializerTests.X(InitializerTests.Y(), new InitializerTests.Data - { - a = InitializerTests.MyEnum.a, - PropertyList = new List - { - InitializerTests.MyEnum2.c, - InitializerTests.MyEnum2.d - } - }); - } - - public static void ObjectInitializerAddToCollectionInProperty() - { - InitializerTests.X(InitializerTests.Y(), new InitializerTests.Data - { - a = InitializerTests.MyEnum.a, - PropertyList = - { - InitializerTests.MyEnum2.c, - InitializerTests.MyEnum2.d - } - }); - } - - public static void ObjectInitializerWithInitializationOfNestedObjects() - { - InitializerTests.X(InitializerTests.Y(), new InitializerTests.Data - { - MoreData = - { - a = InitializerTests.MyEnum.a - } - }); - } - - public static void StructInitializer_DefaultConstructor() - { - InitializerTests.X(InitializerTests.Y(), new InitializerTests.StructData - { - Field = 1, - Property = 2 - }); - } - - public static void StructInitializer_ExplicitConstructor() - { - InitializerTests.X(InitializerTests.Y(), new InitializerTests.StructData(0) - { - Field = 1, - Property = 2 - }); - } - - public static void StructInitializerWithInitializationOfNestedObjects() - { - InitializerTests.X(InitializerTests.Y(), new InitializerTests.StructData - { - MoreData = - { - a = InitializerTests.MyEnum.a, - FieldList = - { - InitializerTests.MyEnum2.c, - InitializerTests.MyEnum2.d - } - } - }); - } - - public static void StructInitializerWithinObjectInitializer() - { - InitializerTests.X(InitializerTests.Y(), new InitializerTests.Data - { - NestedStruct = new InitializerTests.StructData(2) - { - Field = 1, - Property = 2 - } - }); - } - - public int[,] MultidimensionalInit() - { - return new int[,] - { - - { - 0, - 0, - 0, - 0 - }, - - { - 1, - 1, - 1, - 1 - }, - - { - 0, - 0, - 0, - 0 - }, - - { - 0, - 0, - 0, - 0 - }, - - { - 0, - 0, - 1, - 0 - }, - - { - 0, - 0, - 1, - 0 - }, - - { - 0, - 0, - 1, - 0 - }, - - { - 0, - 0, - 1, - 0 - }, - - { - 0, - 0, - 0, - 0 - }, - - { - 1, - 1, - 1, - 1 - }, - - { - 0, - 0, - 0, - 0 - }, - - { - 0, - 0, - 0, - 0 - }, - - { - 0, - 0, - 1, - 0 - }, - - { - 0, - 0, - 1, - 0 - }, - - { - 0, - 0, - 1, - 0 - }, - - { - 0, - 0, - 1, - 0 - } - }; - } - - public int[][,] MultidimensionalInit2() - { - return new int[][,] - { - new int[,] - { - - { - 0, - 0, - 0, - 0 - }, - - { - 1, - 1, - 1, - 1 - }, - - { - 0, - 0, - 0, - 0 - }, - - { - 0, - 0, - 0, - 0 - } - - }, - new int[,] - { - - { - 0, - 0, - 1, - 0 - }, - - { - 0, - 0, - 1, - 0 - }, - - { - 0, - 0, - 1, - 0 - }, - - { - 0, - 0, - 1, - 0 - } - - }, - new int[,] - { - - { - 0, - 0, - 0, - 0 - }, - - { - 1, - 1, - 1, - 1 - }, - - { - 0, - 0, - 0, - 0 - }, - - { - 0, - 0, - 0, - 0 - } - }, - new int[,] - { - - { - 0, - 0, - 1, - 0 - }, - - { - 0, - 0, - 1, - 0 - }, - - { - 0, - 0, - 1, - 0 - }, - - { - 0, - 0, - 1, - 0 - } - - } - }; - } - - public int[][,,] ArrayOfArrayOfArrayInit() - { - return new int[][,,] - { - new int[,,] - { - { - { - 1, - 2, - 3 - }, - { - 4, - 5, - 6 - }, - { - 7, - 8, - 9 - } - }, - { - { - 11, - 12, - 13 - }, - { - 14, - 15, - 16 - }, - { - 17, - 18, - 19 - } - } - }, - - new int[,,] - { - { - { - 21, - 22, - 23 - }, - { - 24, - 25, - 26 - }, - { - 27, - 28, - 29 - } - }, - { - { - 31, - 32, - 33 - }, - { - 34, - 35, - 36 - }, - { - 37, - 38, - 39 - } - } - } - }; - } -} diff --git a/ICSharpCode.Decompiler/Tests/LiftedOperators.cs b/ICSharpCode.Decompiler/Tests/LiftedOperators.cs deleted file mode 100644 index 426276ab..00000000 --- a/ICSharpCode.Decompiler/Tests/LiftedOperators.cs +++ /dev/null @@ -1,830 +0,0 @@ -// Copyright (c) AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Runtime.InteropServices; - -public static class LiftedOperators -{ - // C# uses 4 different patterns of IL for lifted operators: bool, other primitive types, decimal, other structs. - // Different patterns are used depending on whether both of the operands are nullable or only the left/right operand is nullable. - // Negation must not be pushed through such comparisons because it would change the semantics. - // A comparison used in a condition differs somewhat from a comparison used as a simple value. - - public static void BoolBasic(bool? a, bool? b) - { - if (a == b) - { - Console.WriteLine(); - } - if (a != b) - { - Console.WriteLine(); - } - - if (!(a == b)) - { - Console.WriteLine(); - } - if (!(a != b)) - { - Console.WriteLine(); - } - } - - public static void BoolComplex(bool? a, Func x) - { - if (a == x()) - { - Console.WriteLine(); - } - if (a != x()) - { - Console.WriteLine(); - } - - if (x() == a) - { - Console.WriteLine(); - } - if (x() != a) - { - Console.WriteLine(); - } - - if (!(a == x())) - { - Console.WriteLine(); - } - if (!(a != x())) - { - Console.WriteLine(); - } - if (!(x() == a)) - { - Console.WriteLine(); - } - if (!(x() != a)) - { - Console.WriteLine(); - } - } - - public static void BoolConst(bool? a) - { - if (a == true) - { - Console.WriteLine(); - } - if (a != true) - { - Console.WriteLine(); - } - if (a == false) - { - Console.WriteLine(); - } - if (a != false) - { - Console.WriteLine(); - } - if (a ?? true) - { - Console.WriteLine(); - } - if (a ?? false) - { - Console.WriteLine(); - } - } - - public static void BoolValueBasic(bool? a, bool? b) - { - Console.WriteLine(a == b); - Console.WriteLine(a != b); - - Console.WriteLine(!(a == b)); - Console.WriteLine(!(a != b)); - - Console.WriteLine(a & b); - Console.WriteLine(a | b); - Console.WriteLine(a ^ b); - Console.WriteLine(a ?? b); - Console.WriteLine(!a); - a &= b; - a |= b; - a ^= b; - } - - public static void BoolValueComplex(bool? a, Func x) - { - Console.WriteLine(a == x()); - Console.WriteLine(a != x()); - - Console.WriteLine(x() == a); - Console.WriteLine(x() != a); - - Console.WriteLine(!(a == x())); - Console.WriteLine(!(a != x())); - - Console.WriteLine(a & x()); - Console.WriteLine(a | x()); - Console.WriteLine(a ^ x()); - Console.WriteLine(a ?? x()); - a &= x(); - a |= x(); - a ^= x(); - - Console.WriteLine(x() ^ a); - (new bool?[0])[0] ^= x(); - } - - public static void BoolValueConst(bool? a) - { - Console.WriteLine(a == true); - Console.WriteLine(a != true); - Console.WriteLine(a == false); - Console.WriteLine(a != false); - Console.WriteLine(a ?? true); - Console.WriteLine(a ?? false); - } - - public static void IntBasic(int? a, int? b) - { - if (a == b) - { - Console.WriteLine(); - } - if (a != b) - { - Console.WriteLine(); - } - if (a > b) - { - Console.WriteLine(); - } - if (a < b) - { - Console.WriteLine(); - } - if (a >= b) - { - Console.WriteLine(); - } - if (a <= b) - { - Console.WriteLine(); - } - - if (!(a == b)) - { - Console.WriteLine(); - } - if (!(a != b)) - { - Console.WriteLine(); - } - if (!(a > b)) - { - Console.WriteLine(); - } - } - - public static void IntComplex(int? a, Func x) - { - if (a == x()) - { - Console.WriteLine(); - } - if (a != x()) - { - Console.WriteLine(); - } - if (a > x()) - { - Console.WriteLine(); - } - - if (x() == a) - { - Console.WriteLine(); - } - if (x() != a) - { - Console.WriteLine(); - } - if (x() > a) - { - Console.WriteLine(); - } - - if (!(a == x())) - { - Console.WriteLine(); - } - if (!(a != x())) - { - Console.WriteLine(); - } - if (!(a > x())) - { - Console.WriteLine(); - } - } - - public static void IntConst(int? a) - { - if (a == 2) - { - Console.WriteLine(); - } - if (a != 2) - { - Console.WriteLine(); - } - if (a > 2) - { - Console.WriteLine(); - } - - if (2 == a) - { - Console.WriteLine(); - } - if (2 != a) - { - Console.WriteLine(); - } - if (2 > a) - { - Console.WriteLine(); - } - } - - public static void IntValueBasic(int? a, int? b) - { - Console.WriteLine(a == b); - Console.WriteLine(a != b); - Console.WriteLine(a > b); - - Console.WriteLine(!(a == b)); - Console.WriteLine(!(a != b)); - Console.WriteLine(!(a > b)); - - Console.WriteLine(a + b); - Console.WriteLine(a - b); - Console.WriteLine(a * b); - Console.WriteLine(a / b); - Console.WriteLine(a % b); - Console.WriteLine(a & b); - Console.WriteLine(a | b); - Console.WriteLine(a ^ b); - Console.WriteLine(a << b); - Console.WriteLine(a >> b); - Console.WriteLine(a ?? b); - Console.WriteLine(-a); - Console.WriteLine(~a); - // TODO: - //Console.WriteLine(a++); - //Console.WriteLine(a--); - Console.WriteLine(++a); - Console.WriteLine(--a); - a += b; - a -= b; - a *= b; - a /= b; - a %= b; - a &= b; - a |= b; - a ^= b; - a <<= b; - a >>= b; - } - - public static void IntValueComplex(int? a, Func x) - { - Console.WriteLine(a == x()); - Console.WriteLine(a != x()); - Console.WriteLine(a > x()); - - Console.WriteLine(x() == a); - Console.WriteLine(x() != a); - Console.WriteLine(x() > a); - - Console.WriteLine(a + x()); - Console.WriteLine(a - x()); - Console.WriteLine(a * x()); - Console.WriteLine(a / x()); - Console.WriteLine(a % x()); - Console.WriteLine(a & x()); - Console.WriteLine(a | x()); - Console.WriteLine(a ^ x()); - Console.WriteLine(a << x()); - Console.WriteLine(a >> x()); - Console.WriteLine(a ?? x()); - a += x(); - a -= x(); - a *= x(); - a /= x(); - a %= x(); - a &= x(); - a |= x(); - a ^= x(); - a <<= x(); - a >>= x(); - - Console.WriteLine(x() + a); - (new int?[0])[0] += x(); - } - - public static void IntValueConst(int? a) - { - Console.WriteLine(a == 2); - Console.WriteLine(a != 2); - Console.WriteLine(a > 2); - - Console.WriteLine(2 == a); - Console.WriteLine(2 != a); - Console.WriteLine(2 > a); - - Console.WriteLine(a + 2); - Console.WriteLine(a - 2); - Console.WriteLine(a * 2); - Console.WriteLine(a / 2); - Console.WriteLine(a % 2); - Console.WriteLine(a & 2); - Console.WriteLine(a | 2); - Console.WriteLine(a ^ 2); - Console.WriteLine(a << 2); - Console.WriteLine(a >> 2); - Console.WriteLine(a ?? 2); - a += 2; - a -= 2; - a *= 2; - a /= 2; - a %= 2; - a &= 2; - a |= 2; - a ^= 2; - a <<= 2; - a >>= 2; - - Console.WriteLine(2 + a); - } - - public static void NumberBasic(decimal? a, decimal? b) - { - if (a == b) - { - Console.WriteLine(); - } - if (a != b) - { - Console.WriteLine(); - } - if (a > b) - { - Console.WriteLine(); - } - if (a < b) - { - Console.WriteLine(); - } - if (a >= b) - { - Console.WriteLine(); - } - if (a <= b) - { - Console.WriteLine(); - } - - if (!(a == b)) - { - Console.WriteLine(); - } - if (!(a != b)) - { - Console.WriteLine(); - } - if (!(a > b)) - { - Console.WriteLine(); - } - } - - public static void NumberComplex(decimal? a, Func x) - { - if (a == x()) - { - Console.WriteLine(); - } - if (a != x()) - { - Console.WriteLine(); - } - if (a > x()) - { - Console.WriteLine(); - } - - if (x() == a) - { - Console.WriteLine(); - } - if (x() != a) - { - Console.WriteLine(); - } - if (x() > a) - { - Console.WriteLine(); - } - } - - public static void NumberConst(decimal? a) - { - if (a == 2m) - { - Console.WriteLine(); - } - if (a != 2m) - { - Console.WriteLine(); - } - if (a > 2m) - { - Console.WriteLine(); - } - - if (2m == a) - { - Console.WriteLine(); - } - if (2m != a) - { - Console.WriteLine(); - } - if (2m > a) - { - Console.WriteLine(); - } - } - - public static void NumberValueBasic(decimal? a, decimal? b) - { - Console.WriteLine(a == b); - Console.WriteLine(a != b); - Console.WriteLine(a > b); - - Console.WriteLine(!(a == b)); - Console.WriteLine(!(a != b)); - Console.WriteLine(!(a > b)); - - Console.WriteLine(a + b); - Console.WriteLine(a - b); - Console.WriteLine(a * b); - Console.WriteLine(a / b); - Console.WriteLine(a % b); - Console.WriteLine(a ?? b); - Console.WriteLine(-a); - // TODO: - //Console.WriteLine(a++); - //Console.WriteLine(a--); - //Console.WriteLine(++a); - //Console.WriteLine(--a); - a += b; - a -= b; - a *= b; - a /= b; - a %= b; - } - - public static void NumberValueComplex(decimal? a, Func x) - { - Console.WriteLine(a == x()); - Console.WriteLine(a != x()); - Console.WriteLine(a > x()); - - Console.WriteLine(x() == a); - Console.WriteLine(x() != a); - Console.WriteLine(x() > a); - - Console.WriteLine(a + x()); - Console.WriteLine(a - x()); - Console.WriteLine(a * x()); - Console.WriteLine(a / x()); - Console.WriteLine(a % x()); - Console.WriteLine(a ?? x()); - a += x(); - a -= x(); - a *= x(); - a /= x(); - a %= x(); - - Console.WriteLine(x() + a); - (new decimal?[0])[0] += x(); - } - - public static void NumberValueConst(decimal? a) - { - Console.WriteLine(a == 2m); - Console.WriteLine(a != 2m); - Console.WriteLine(a > 2m); - - Console.WriteLine(2m == a); - Console.WriteLine(2m != a); - Console.WriteLine(2m > a); - - Console.WriteLine(a + 2m); - Console.WriteLine(a - 2m); - Console.WriteLine(a * 2m); - Console.WriteLine(a / 2m); - Console.WriteLine(a % 2m); - Console.WriteLine(a ?? 2m); - a += 2m; - a -= 2m; - a *= 2m; - a /= 2m; - a %= 2m; - - Console.WriteLine(2m + a); - } - - public static void StructBasic(TS? a, TS? b) - { - if (a == b) - { - Console.WriteLine(); - } - if (a != b) - { - Console.WriteLine(); - } - if (a > b) - { - Console.WriteLine(); - } - if (a < b) - { - Console.WriteLine(); - } - if (a >= b) - { - Console.WriteLine(); - } - if (a <= b) - { - Console.WriteLine(); - } - - if (!(a == b)) - { - Console.WriteLine(); - } - if (!(a != b)) - { - Console.WriteLine(); - } - if (!(a > b)) - { - Console.WriteLine(); - } - } - - public static void StructComplex(TS? a, Func x) - { - if (a == x()) - { - Console.WriteLine(); - } - if (a != x()) - { - Console.WriteLine(); - } - if (a > x()) - { - Console.WriteLine(); - } - - if (x() == a) - { - Console.WriteLine(); - } - if (x() != a) - { - Console.WriteLine(); - } - if (x() > a) - { - Console.WriteLine(); - } - } - - public static void StructValueBasic(TS? a, TS? b, int? i) - { - Console.WriteLine(a == b); - Console.WriteLine(a != b); - Console.WriteLine(a > b); - - Console.WriteLine(!(a == b)); - Console.WriteLine(!(a != b)); - Console.WriteLine(!(a > b)); - - Console.WriteLine(a + b); - Console.WriteLine(a - b); - Console.WriteLine(a * b); - Console.WriteLine(a / b); - Console.WriteLine(a % b); - Console.WriteLine(a & b); - Console.WriteLine(a | b); - Console.WriteLine(a ^ b); - Console.WriteLine(a << i); - Console.WriteLine(a >> i); - Console.WriteLine(a ?? b); - Console.WriteLine(+a); - Console.WriteLine(-a); - Console.WriteLine(!a); - Console.WriteLine(~a); - // TODO: - //Console.WriteLine(a++); - //Console.WriteLine(a--); - //Console.WriteLine(++a); - //Console.WriteLine(--a); - //Console.WriteLine((int?)a); - a += b; - a -= b; - a *= b; - a /= b; - a %= b; - a &= b; - a |= b; - a ^= b; - a <<= i; - a >>= i; - } - - public static void StructValueComplex(TS? a, Func x, Func i) - { - Console.WriteLine(a == x()); - Console.WriteLine(a != x()); - Console.WriteLine(a > x()); - - Console.WriteLine(x() == a); - Console.WriteLine(x() != a); - Console.WriteLine(x() > a); - - Console.WriteLine(a + x()); - Console.WriteLine(a - x()); - Console.WriteLine(a * x()); - Console.WriteLine(a / x()); - Console.WriteLine(a % x()); - Console.WriteLine(a & x()); - Console.WriteLine(a | x()); - Console.WriteLine(a ^ x()); - Console.WriteLine(a << i()); - Console.WriteLine(a >> i()); - Console.WriteLine(a ?? x()); - a += x(); - a -= x(); - a *= x(); - a /= x(); - a %= x(); - a &= x(); - a |= x(); - a ^= x(); - a <<= i(); - a >>= i(); - - Console.WriteLine(x() + a); - (new TS?[0])[0] += x(); - } -} - -// dummy structure for testing custom operators -[StructLayout(LayoutKind.Sequential, Size = 1)] -public struct TS -{ - // unary - public static TS operator +(TS a) - { - throw null; - } - public static TS operator -(TS a) - { - throw null; - } - public static TS operator !(TS a) - { - throw null; - } - public static TS operator ~(TS a) - { - throw null; - } - public static TS operator ++(TS a) - { - throw null; - } - public static TS operator --(TS a) - { - throw null; - } - - public static explicit operator int(TS a) - { - throw null; - } - - // binary - public static TS operator +(TS a, TS b) - { - throw null; - } - public static TS operator -(TS a, TS b) - { - throw null; - } - public static TS operator *(TS a, TS b) - { - throw null; - } - public static TS operator /(TS a, TS b) - { - throw null; - } - public static TS operator %(TS a, TS b) - { - throw null; - } - public static TS operator &(TS a, TS b) - { - throw null; - } - public static TS operator |(TS a, TS b) - { - throw null; - } - public static TS operator ^(TS a, TS b) - { - throw null; - } - public static TS operator <<(TS a, int b) - { - throw null; - } - public static TS operator >>(TS a, int b) - { - throw null; - } - - // comparisons - public static bool operator ==(TS a, TS b) - { - throw null; - } - public static bool operator !=(TS a, TS b) - { - throw null; - } - public static bool operator <(TS a, TS b) - { - throw null; - } - public static bool operator <=(TS a, TS b) - { - throw null; - } - public static bool operator >(TS a, TS b) - { - throw null; - } - public static bool operator >=(TS a, TS b) - { - throw null; - } - - public override bool Equals(object obj) - { - throw null; - } - public override int GetHashCode() - { - throw null; - } -} diff --git a/ICSharpCode.Decompiler/Tests/Lock.cs b/ICSharpCode.Decompiler/Tests/Lock.cs deleted file mode 100644 index da5a59c7..00000000 --- a/ICSharpCode.Decompiler/Tests/Lock.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 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; - -public class Lock -{ - public void LockThis() - { - lock (this) - { - Console.WriteLine(); - } - } - - public void LockOnType() - { - lock (typeof(Lock)) - { - Console.WriteLine(); - } - } -} diff --git a/ICSharpCode.Decompiler/Tests/Loops.cs b/ICSharpCode.Decompiler/Tests/Loops.cs deleted file mode 100644 index 03427a8b..00000000 --- a/ICSharpCode.Decompiler/Tests/Loops.cs +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (c) AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections; -using System.Collections.Generic; - -public class Loops -{ - public void ForEach(IEnumerable enumerable) - { - foreach (string current in enumerable) - { - current.ToLower(); - } - } - - public void ForEachOverList(List list) - { - // List has a struct as enumerator, so produces quite different IL than foreach over the IEnumerable interface - foreach (string current in list) - { - current.ToLower(); - } - } - - public void ForEachOverNonGenericEnumerable(IEnumerable enumerable) - { - foreach (object current in enumerable) - { - 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++) - { - array[i].ToLower(); - } - } -} - diff --git a/ICSharpCode.Decompiler/Tests/MultidimensionalArray.cs b/ICSharpCode.Decompiler/Tests/MultidimensionalArray.cs deleted file mode 100644 index c3557cee..00000000 --- a/ICSharpCode.Decompiler/Tests/MultidimensionalArray.cs +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) 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; - -public class MultidimensionalArray -{ - internal class Generic where T : new() - { - private T[,] a = new T[20, 20]; - private S[,][] b = new S[20, 20][]; - - public T this[int i, int j] - { - get - { - return this.a[i, j]; - } - set - { - this.a[i, j] = value; - } - } - - public void TestB(S x, ref S y) - { - this.b[5, 3] = new S[10]; - this.b[5, 3][0] = default(S); - this.b[5, 3][1] = x; - this.b[5, 3][2] = y; - } - - public void PassByReference(ref T arr) - { - this.PassByReference(ref this.a[10, 10]); - } - } - - public int[][,] MakeArray() - { - return new int[10][,]; - } -} diff --git a/ICSharpCode.Decompiler/Tests/PInvoke.cs b/ICSharpCode.Decompiler/Tests/PInvoke.cs deleted file mode 100644 index 0c828ac6..00000000 --- a/ICSharpCode.Decompiler/Tests/PInvoke.cs +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Runtime.InteropServices; - -// P/Invoke and marshalling attribute tests -public class PInvoke -{ - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 2)] - public struct MarshalAsTest - { - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public uint[] FixedArray; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4, ArraySubType = UnmanagedType.Bool)] - public int[] FixedBoolArray; - - [MarshalAs(UnmanagedType.SafeArray, SafeArraySubType = VarEnum.VT_BSTR)] - public string[] SafeBStrArray; - - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8)] - public string FixedString; - } - - [StructLayout(LayoutKind.Explicit)] - public struct Rect - { - [FieldOffset(0)] - public int left; - [FieldOffset(4)] - public int top; - [FieldOffset(8)] - public int right; - [FieldOffset(12)] - public int bottom; - } - - public static decimal MarshalAttributesOnPropertyAccessors - { - [return: MarshalAs(UnmanagedType.Currency)] - get - { - return 0m; - } - [param: MarshalAs(UnmanagedType.Currency)] - set - { - } - } - - [DllImport("xyz.dll", CharSet = CharSet.Auto)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool Method([MarshalAs(UnmanagedType.LPStr)] string input); - - [DllImport("xyz.dll")] - private static extern void New1(int ElemCnt, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] int[] ar); - - [DllImport("xyz.dll")] - private static extern void New2([MarshalAs(UnmanagedType.LPArray, SizeConst = 128)] int[] ar); - - [DllImport("xyz.dll")] - private static extern void New3([MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.Bool, SizeConst = 64, SizeParamIndex = 1)] int[] ar); - - public void CustomMarshal1([MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "MyCompany.MyMarshaler")] object o) - { - } - - public void CustomMarshal2([MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "MyCompany.MyMarshaler", MarshalCookie = "Cookie")] object o) - { - } - - [DllImport("ws2_32.dll", SetLastError = true)] - internal static extern IntPtr ioctlsocket([In] IntPtr socketHandle, [In] int cmd, [In] [Out] ref int argp); - - public void CallMethodWithInOutParameter() - { - int num = 0; - PInvoke.ioctlsocket(IntPtr.Zero, 0, ref num); - } -} diff --git a/ICSharpCode.Decompiler/Tests/PropertiesAndEvents.cs b/ICSharpCode.Decompiler/Tests/PropertiesAndEvents.cs deleted file mode 100644 index 9b3d1658..00000000 --- a/ICSharpCode.Decompiler/Tests/PropertiesAndEvents.cs +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright (c) 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.Text; - -public class PropertiesAndEvents -{ - public event EventHandler AutomaticEvent; - - [field: NonSerialized] - public event EventHandler AutomaticEventWithInitializer = delegate(object sender, EventArgs e) - { - }; - - public event EventHandler CustomEvent - { - add - { - this.AutomaticEvent += value; - } - remove - { - this.AutomaticEvent -= value; - } - } - - public int AutomaticProperty - { - get; - set; - } - - public int CustomProperty - { - get - { - return this.AutomaticProperty; - } - set - { - this.AutomaticProperty = value; - } - } - - public int Getter(StringBuilder b) - { - return b.Length; - } - - public void Setter(StringBuilder b) - { - b.Capacity = 100; - } - - public char IndexerGetter(StringBuilder b) - { - return b[50]; - } - - public void IndexerSetter(StringBuilder b) - { - b[42] = 'b'; - } -} diff --git a/ICSharpCode.Decompiler/Tests/QueryExpressions.cs b/ICSharpCode.Decompiler/Tests/QueryExpressions.cs deleted file mode 100644 index d8b6e062..00000000 --- a/ICSharpCode.Decompiler/Tests/QueryExpressions.cs +++ /dev/null @@ -1,188 +0,0 @@ -// Copyright (c) AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; -using System.Linq; - -public class QueryExpressions -{ - public class Customer - { - public int CustomerID; - public IEnumerable Orders; - public string Name; - public string Country; - public string City; - } - - public class Order - { - public int OrderID; - public DateTime OrderDate; - public QueryExpressions.Customer Customer; - public int CustomerID; - public decimal Total; - public IEnumerable Details; - } - - public class OrderDetail - { - public decimal UnitPrice; - public int Quantity; - } - - public IEnumerable customers; - public IEnumerable orders; - - public object MultipleWhere() - { - return from c in this.customers - where c.Orders.Count() > 10 - where c.Country == "DE" - select c; - } - - public object SelectManyFollowedBySelect() - { - return from c in this.customers - from o in c.Orders - select new - { - c.Name, - o.OrderID, - o.Total - }; - } - - public object SelectManyFollowedByOrderBy() - { - return from c in this.customers - from o in c.Orders - orderby o.Total descending - select new - { - c.Name, - o.OrderID, - o.Total - }; - } - - public object MultipleSelectManyFollowedBySelect() - { - return from c in this.customers - from o in c.Orders - from d in o.Details - select new - { - c.Name, - o.OrderID, - d.Quantity - }; - } - - public object MultipleSelectManyFollowedByLet() - { - return from c in this.customers - from o in c.Orders - from d in o.Details - let x = d.Quantity * d.UnitPrice - select new - { - c.Name, - o.OrderID, - x - }; - } - - public object FromLetWhereSelect() - { - return from o in this.orders - let t = o.Details.Sum((QueryExpressions.OrderDetail d) => d.UnitPrice * d.Quantity) - where t >= 1000m - select new - { - OrderID = o.OrderID, - Total = t - }; - } - - public object MultipleLet() - { - return from a in this.customers - let b = a.Country - let c = a.Name - select b + c; - } - - public object Join() - { - return from c in this.customers - join o in this.orders on c.CustomerID equals o.CustomerID - select new - { - c.Name, - o.OrderDate, - o.Total - }; - } - - public object JoinInto() - { - return from c in this.customers - join o in this.orders on c.CustomerID equals o.CustomerID into co - let n = co.Count() - where n >= 10 - select new - { - Name = c.Name, - OrderCount = n - }; - } - - public object OrderBy() - { - return from o in this.orders - orderby o.Customer.Name, o.Total descending - select o; - } - - public object GroupBy() - { - return from c in this.customers - group c.Name by c.Country; - } - - public object ExplicitType() - { - return from QueryExpressions.Customer c in this.customers - where c.City == "London" - select c; - } - - public object QueryContinuation() - { - return from c in this.customers - group c by c.Country into g - select new - { - Country = g.Key, - CustCount = g.Count() - }; - } -} diff --git a/ICSharpCode.Decompiler/Tests/Switch.cs b/ICSharpCode.Decompiler/Tests/Switch.cs deleted file mode 100644 index 4a20a639..00000000 --- a/ICSharpCode.Decompiler/Tests/Switch.cs +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (c) 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; - -public static class Switch -{ - public static string ShortSwitchOverString(string text) - { - switch (text) { - case "First case": - return "Text"; - default: - return "Default"; - } - } - - public static string SwitchOverString1(string text) - { - switch (text) - { - case "First case": - return "Text1"; - case "Second case": - case "2nd case": - return "Text2"; - case "Third case": - return "Text3"; - case "Fourth case": - return "Text4"; - case "Fifth case": - return "Text5"; - case "Sixth case": - return "Text6"; - case null: - return null; - default: - return "Default"; - } - } - - public static string SwitchOverString2() - { - switch (Environment.UserName) - { - case "First case": - return "Text1"; - case "Second case": - return "Text2"; - case "Third case": - return "Text3"; - case "Fourth case": - return "Text4"; - case "Fifth case": - return "Text5"; - case "Sixth case": - return "Text6"; - default: - return "Default"; - } - } - - public static string SwitchOverBool(bool b) - { - switch (b) { - case true: - return bool.TrueString; - case false: - return bool.FalseString; - default: - return null; - } - } -} diff --git a/ICSharpCode.Decompiler/Tests/TestRunner.cs b/ICSharpCode.Decompiler/Tests/TestRunner.cs deleted file mode 100644 index 215725b0..00000000 --- a/ICSharpCode.Decompiler/Tests/TestRunner.cs +++ /dev/null @@ -1,198 +0,0 @@ -// Copyright (c) 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.CodeDom.Compiler; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using DiffLib; -using ICSharpCode.Decompiler.Ast; -using ICSharpCode.Decompiler.Tests.Helpers; -using Microsoft.CSharp; -using Mono.Cecil; -using NUnit.Framework; - -namespace ICSharpCode.Decompiler.Tests -{ - [TestFixture] - public class TestRunner : DecompilerTestBase - { - [Test] - public void Async() - { - TestFile(@"..\..\Tests\Async.cs"); - } - - [Test, Ignore("disambiguating overloads is not yet implemented")] - public void CallOverloadedMethod() - { - TestFile(@"..\..\Tests\CallOverloadedMethod.cs"); - } - - [Test, Ignore("unncessary primitive casts")] - public void CheckedUnchecked() - { - TestFile(@"..\..\Tests\CheckedUnchecked.cs"); - } - - [Test, Ignore("Missing cast on null")] - public void DelegateConstruction() - { - TestFile(@"..\..\Tests\DelegateConstruction.cs"); - } - - [Test, Ignore("Not yet implemented")] - public void ExpressionTrees() - { - TestFile(@"..\..\Tests\ExpressionTrees.cs"); - } - - [Test] - public void ExceptionHandling() - { - AssertRoundtripCode(@"..\..\Tests\ExceptionHandling.cs", optimize: false); - AssertRoundtripCode(@"..\..\Tests\ExceptionHandling.cs", optimize: false); - } - - [Test] - public void Generics() - { - TestFile(@"..\..\Tests\Generics.cs"); - } - - [Test] - public void CustomShortCircuitOperators() - { - TestFile(@"..\..\Tests\CustomShortCircuitOperators.cs"); - } - - [Test] - public void ControlFlowWithDebug() - { - AssertRoundtripCode(@"..\..\Tests\ControlFlow.cs", optimize: false, useDebug: true); - AssertRoundtripCode(@"..\..\Tests\ControlFlow.cs", optimize: false, useDebug: true); - } - - [Test] - public void DoubleConstants() - { - TestFile(@"..\..\Tests\DoubleConstants.cs"); - } - - [Test] - public void IncrementDecrement() - { - TestFile(@"..\..\Tests\IncrementDecrement.cs"); - } - - [Test] - public void InitializerTests() - { - TestFile(@"..\..\Tests\InitializerTests.cs"); - } - - [Test] - public void LiftedOperators() - { - TestFile(@"..\..\Tests\LiftedOperators.cs"); - } - - [Test] - public void Lock() - { - //TestFile(@"..\..\Tests\Lock.cs", compilerVersion: 2); - TestFile(@"..\..\Tests\Lock.cs", compilerVersion: 4); - } - - [Test] - public void Loops() - { - TestFile(@"..\..\Tests\Loops.cs"); - } - - [Test] - public void MultidimensionalArray() - { - TestFile(@"..\..\Tests\MultidimensionalArray.cs"); - } - - [Test] - public void PInvoke() - { - TestFile(@"..\..\Tests\PInvoke.cs"); - } - - [Test] - public void PropertiesAndEvents() - { - TestFile(@"..\..\Tests\PropertiesAndEvents.cs"); - } - - [Test] - public void QueryExpressions() - { - TestFile(@"..\..\Tests\QueryExpressions.cs"); - } - - [Test, Ignore("switch transform doesn't recreate the exact original switch")] - public void Switch() - { - TestFile(@"..\..\Tests\Switch.cs"); - } - - [Test] - public void UndocumentedExpressions() - { - TestFile(@"..\..\Tests\UndocumentedExpressions.cs"); - } - - [Test, Ignore("has incorrect casts to IntPtr")] - public void UnsafeCode() - { - TestFile(@"..\..\Tests\UnsafeCode.cs"); - } - - [Test] - public void ValueTypes() - { - TestFile(@"..\..\Tests\ValueTypes.cs"); - } - - [Test, Ignore("Redundant yield break; not removed")] - public void YieldReturn() - { - TestFile(@"..\..\Tests\YieldReturn.cs"); - } - - [Test] - public void TypeAnalysis() - { - TestFile(@"..\..\Tests\TypeAnalysisTests.cs"); - } - - static void TestFile(string fileName, bool useDebug = false, int compilerVersion = 4) - { - AssertRoundtripCode(fileName, optimize: false, useDebug: useDebug, compilerVersion: compilerVersion); - AssertRoundtripCode(fileName, optimize: true, useDebug: useDebug, compilerVersion: compilerVersion); - AssertRoundtripCode(fileName, optimize: false, useDebug: useDebug, compilerVersion: compilerVersion); - AssertRoundtripCode(fileName, optimize: true, useDebug: useDebug, compilerVersion: compilerVersion); - } - } -} diff --git a/ICSharpCode.Decompiler/Tests/TypeAnalysisTests.cs b/ICSharpCode.Decompiler/Tests/TypeAnalysisTests.cs deleted file mode 100644 index 760bb862..00000000 --- a/ICSharpCode.Decompiler/Tests/TypeAnalysisTests.cs +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright (c) 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; - -public class TypeAnalysisTests -{ - public byte SubtractFrom256(byte b) - { - return (byte)(256 - (int)b); - } - - #region Shift - public int LShiftInteger(int num1, int num2) - { - return num1 << num2; - } - - public uint LShiftUnsignedInteger(uint num1, uint num2) - { - return num1 << (int)num2; - } - - public long LShiftLong(long num1, long num2) - { - return num1 << (int)num2; - } - - public ulong LShiftUnsignedLong(ulong num1, ulong num2) - { - return num1 << (int)num2; - } - - public int RShiftInteger(int num1, int num2) - { - return num1 >> num2; - } - - public uint RShiftUnsignedInteger(uint num1, int num2) - { - return num1 >> num2; - } - - public long RShiftLong(long num1, long num2) - { - return num1 >> (int)num2; - } - - public ulong RShiftUnsignedLong(ulong num1, ulong num2) - { - return num1 >> (int)num2; - } - - public int ShiftByte(byte num) - { - return (int)num << 8; - } - - public int RShiftByte(byte num) - { - return num >> 8; - } - - public uint RShiftByteWithZeroExtension(byte num) - { - return (uint)num >> 8; - } - - public int RShiftByteAsSByte(byte num) - { - return (sbyte)num >> 8; - } - - public int RShiftSByte(sbyte num) - { - return num >> 8; - } - - public uint RShiftSByteWithZeroExtension(sbyte num) - { - return (uint)num >> 8; - } - - public int RShiftSByteAsByte(sbyte num) - { - return (byte)num >> 8; - } - #endregion - - public int GetHashCode(long num) - { - return (int)num ^ (int)(num >> 32); - } - - public void TernaryOp(Random a, Random b, bool c) - { - if ((c ? a : b) == null) - { - Console.WriteLine(); - } - } - - public void OperatorIs(object o) - { - Console.WriteLine(o is Random); - Console.WriteLine(!(o is Random)); - } - - public byte[] CreateArrayWithInt(int length) - { - return new byte[length]; - } - - public byte[] CreateArrayWithLong(long length) - { - return new byte[length]; - } - - public byte[] CreateArrayWithUInt(uint length) - { - return new byte[length]; - } - - public byte[] CreateArrayWithULong(ulong length) - { - return new byte[length]; - } - - public StringComparison EnumDiffNumber(StringComparison data) - { - return data - 1; - } - - public int EnumDiff(StringComparison a, StringComparison b) - { - return Math.Abs(a - b); - } -} diff --git a/ICSharpCode.Decompiler/Tests/Types/EnumTests.cs b/ICSharpCode.Decompiler/Tests/Types/EnumTests.cs deleted file mode 100644 index fb48d016..00000000 --- a/ICSharpCode.Decompiler/Tests/Types/EnumTests.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using NUnit.Framework; - -namespace ICSharpCode.Decompiler.Tests.Types -{ - [TestFixture] - public class EnumTests : DecompilerTestBase - { - [Test] - public void EnumSamples() - { - ValidateFileRoundtrip(@"Types\S_EnumSamples.cs"); - } - } -} diff --git a/ICSharpCode.Decompiler/Tests/Types/S_EnumSamples.cs b/ICSharpCode.Decompiler/Tests/Types/S_EnumSamples.cs deleted file mode 100644 index 3149f575..00000000 --- a/ICSharpCode.Decompiler/Tests/Types/S_EnumSamples.cs +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -//$CS -using System; -//$CE - -//$$ SingleValue -public class TS_SingleValue -{ - public AttributeTargets Method() - { - return AttributeTargets.Class; - } -} -//$$ TwoValuesOr -public class TS_TwoValuesOr -{ - public AttributeTargets Method() - { - return AttributeTargets.Class | AttributeTargets.Method; - } -} -//$$ ThreeValuesOr -public class TS_ThreeValuesOr -{ - public AttributeTargets Method() - { - return AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Parameter; - } -} -//$$ UnknownNumericValue -public class TS_UnknownNumericValue -{ - public AttributeTargets Method() - { - return (AttributeTargets)1000000; - } -} -//$$ AllValue -public class TS_AllValue -{ - public AttributeTargets Method() - { - return AttributeTargets.All; - } -} -//$$ ZeroValue -public class TS_ZeroValue -{ - public AttributeTargets Method() - { - return (AttributeTargets)0; - } -} -//$$ PreservingTypeWhenBoxed -public class TS_PreservingTypeWhenBoxed -{ - public object Method() - { - return AttributeTargets.Delegate; - } -} -//$$ PreservingTypeWhenBoxedTwoEnum -public class TS_PreservingTypeWhenBoxedTwoEnum -{ - public object Method() - { - return AttributeTargets.Class | AttributeTargets.Delegate; - } -} -//$$ DeclarationSimpleEnum -public enum TS_DeclarationSimpleEnum -{ - Item1, - Item2 -} -//$$ DeclarationLongBasedEnum -public enum TS_DeclarationLongBasedEnum : long -{ - Item1, - Item2 -} -//$$ DeclarationLongWithInitializers -public enum TS_DeclarationLongWithInitializers : long -{ - Item1, - Item2 = 20L, - Item3 -} -//$$ DeclarationShortWithInitializers -public enum TS_DeclarationShortWithInitializers : short -{ - Item1, - Item2 = 20, - Item3 -} -//$$ DeclarationByteWithInitializers -public enum TS_DeclarationByteWithInitializers : byte -{ - Item1, - Item2 = 20, - Item3 -} -//$$ DeclarationFlags -[Flags] -public enum TS_DeclarationFlags -{ - None = 0, - Item1 = 1, - Item2 = 2, - Item3 = 4, - All = 7 -} diff --git a/ICSharpCode.Decompiler/Tests/Types/S_TypeDeclarations.cs b/ICSharpCode.Decompiler/Tests/Types/S_TypeDeclarations.cs deleted file mode 100644 index 99bf4279..00000000 --- a/ICSharpCode.Decompiler/Tests/Types/S_TypeDeclarations.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; - -namespace ClassMultiInterface -{ - public interface IA - { - } - public interface IA2 : IA - { - } - public interface IB - { - } - public class C : IA2, IB - { - } -} diff --git a/ICSharpCode.Decompiler/Tests/Types/S_TypeMemberDeclarations.cs b/ICSharpCode.Decompiler/Tests/Types/S_TypeMemberDeclarations.cs deleted file mode 100644 index 4a85b9f8..00000000 --- a/ICSharpCode.Decompiler/Tests/Types/S_TypeMemberDeclarations.cs +++ /dev/null @@ -1,1138 +0,0 @@ -// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -//$CS -using System; -//$CE - -//$$ IndexerWithGetOnly -namespace IndexerWithGetOnly -{ - public class MyClass - { - public int this[int i] - { - get - { - return i; - } - } - } -} -//$$ IndexerWithSetOnly -namespace IndexerWithSetOnly -{ - public class MyClass - { - public int this[int i] - { - set - { - } - } - } -} -//$$ IndexerWithMoreParameters -namespace IndexerWithMoreParameters -{ - public class MyClass - { - public int this[int i, string s, Type t] - { - get - { - return 0; - } - } - } -} -//$$ IndexerInGenericClass -namespace IndexerInGenericClass -{ - public class MyClass - { - public int this[T t] - { - get - { - return 0; - } - } - } -} -//$$ OverloadedIndexer -namespace OverloadedIndexer -{ - public class MyClass - { - public int this[int t] - { - get - { - return 0; - } - } - public int this[string s] - { - get - { - return 0; - } - set - { - Console.WriteLine(value + " " + s); - } - } - } -} -//$$ IndexerInInterface -namespace IndexerInInterface -{ - public interface IInterface - { - int this[string s, string s2] - { - set; - } - } -} -//$$ IndexerInterfaceExplicitImplementation -namespace IndexerInterfaceExplicitImplementation -{ - public interface IMyInterface - { - int this[string s] - { - get; - } - } - public class MyClass : IMyInterface - { - int IMyInterface.this[string s] - { - get - { - return 3; - } - } - } -} -//$$ IndexerInterfaceImplementation -namespace IndexerInterfaceImplementation -{ - public interface IMyInterface - { - int this[string s] - { - get; - } - } - public class MyClass : IMyInterface - { - public int this[string s] - { - get - { - return 3; - } - } - } -} -//$$ IndexerAbstract -namespace IndexerAbstract -{ - public abstract class MyClass - { - public abstract int this[string s, string s2] - { - set; - } - protected abstract string this[int index] - { - get; - } - } -} -//$$ MethodExplicit -namespace MethodExplicit -{ - public interface IMyInterface - { - void MyMethod(); - } - public class MyClass : IMyInterface - { - void IMyInterface.MyMethod() - { - } - } -} -//$$ MethodFromInterfaceVirtual -namespace MethodFromInterfaceVirtual -{ - public interface IMyInterface - { - void MyMethod(); - } - public class MyClass : IMyInterface - { - public virtual void MyMethod() - { - } - } -} -//$$ MethodFromInterface -namespace MethodFromInterface -{ - public interface IMyInterface - { - void MyMethod(); - } - public class MyClass : IMyInterface - { - public void MyMethod() - { - } - } -} -//$$ MethodFromInterfaceAbstract -namespace MethodFromInterfaceAbstract -{ - public interface IMyInterface - { - void MyMethod(); - } - public abstract class MyClass : IMyInterface - { - public abstract void MyMethod(); - } -} -//$$ PropertyInterface -namespace PropertyInterface -{ - public interface IMyInterface - { - int MyProperty - { - get; - set; - } - } -} -//$$ PropertyInterfaceExplicitImplementation -namespace PropertyInterfaceExplicitImplementation -{ - public interface IMyInterface - { - int MyProperty - { - get; - set; - } - } - public class MyClass : IMyInterface - { - int IMyInterface.MyProperty - { - get - { - return 0; - } - set - { - } - } - } -} -//$$ PropertyInterfaceImplementation -namespace PropertyInterfaceImplementation -{ - public interface IMyInterface - { - int MyProperty - { - get; - set; - } - } - public class MyClass : IMyInterface - { - public int MyProperty - { - get - { - return 0; - } - set - { - } - } - } -} -//$$ PropertyPrivateGetPublicSet -namespace PropertyPrivateGetPublicSet -{ - public class MyClass - { - public int MyProperty - { - private get - { - return 3; - } - set - { - } - } - } -} -//$$ PropertyPublicGetProtectedSet -namespace PropertyPublicGetProtectedSet -{ - public class MyClass - { - public int MyProperty - { - get - { - return 3; - } - protected set - { - } - } - } -} -//$$ PropertyOverrideDefaultAccessorOnly -namespace PropertyOverrideDefaultAccessorOnly -{ - public class MyClass - { - public virtual int MyProperty - { - get - { - return 3; - } - protected set - { - } - } - } - public class Derived : MyClass - { - public override int MyProperty - { - get - { - return 4; - } - } - } -} -//$$ PropertyOverrideRestrictedAccessorOnly -namespace PropertyOverrideRestrictedAccessorOnly -{ - public class MyClass - { - public virtual int MyProperty - { - get - { - return 3; - } - protected set - { - } - } - } - public class Derived : MyClass - { - public override int MyProperty - { - protected set - { - } - } - } -} -//$$ PropertyOverrideOneAccessor -namespace PropertyOverrideOneAccessor -{ - public class MyClass - { - protected internal virtual int MyProperty - { - get - { - return 3; - } - protected set - { - } - } - } - public class DerivedNew : MyClass - { - public new virtual int MyProperty - { - set - { - } - } - } - public class DerivedOverride : DerivedNew - { - public override int MyProperty - { - set - { - } - } - } -} -//$$ IndexerOverrideRestrictedAccessorOnly -namespace IndexerOverrideRestrictedAccessorOnly -{ - public class MyClass - { - public virtual int this[string s] - { - get - { - return 3; - } - protected set - { - } - } - protected internal virtual int this[int i] - { - protected get - { - return 2; - } - set - { - } - } - } - public class Derived : MyClass - { - protected internal override int this[int i] - { - protected get - { - return 4; - } - } - } -} -//$$ HideProperty -namespace HideProperty -{ - public class A - { - public virtual int P - { - get - { - return 0; - } - set - { - } - } - } - public class B : A - { - private new int P - { - get - { - return 0; - } - set - { - } - } - } - public class C : B - { - public override int P - { - set - { - } - } - } -} -//$$ HideMembers -namespace HideMembers -{ - public class A - { - public int F; - public int Prop - { - get - { - return 3; - } - } - public int G - { - get - { - return 3; - } - } - } - public class B : A - { - public new int F - { - get - { - return 3; - } - } - public new string Prop - { - get - { - return "a"; - } - } - } - public class C : A - { - public new int G; - } - public class D : A - { - public new void F() - { - } - } - public class D1 : D - { - public new int F; - } - public class E : A - { - private new class F - { - } - } -} -//$$ HideMembers2 -namespace HideMembers2 -{ - public class G - { - public int Item - { - get - { - return 1; - } - } - } - public class G2 : G - { - public int this[int i] - { - get - { - return 2; - } - } - } - public class G3 : G2 - { - public new int Item - { - get - { - return 4; - } - } - } - public class H - { - public int this[int j] - { - get - { - return 0; - } - } - } - public class H2 : H - { - public int Item - { - get - { - return 2; - } - } - } - public class H3 : H2 - { - public new string this[int j] - { - get - { - return null; - } - } - } -} -//$$ HideMembers2a -namespace HideMembers2a -{ - public interface IA - { - int this[int i] - { - get; - } - } - public class A : IA - { - int IA.this[int i] - { - get - { - throw new NotImplementedException(); - } - } - } - public class A1 : A - { - public int this[int i] - { - get - { - return 3; - } - } - } -} -//$$ HideMembers3 -namespace HideMembers3 -{ - public class G - { - public void M1(T p) - { - } - public int M2(int t) - { - return 3; - } - } - public class G1 : G - { - public new int M1(int i) - { - return 0; - } - public int M2(T i) - { - return 2; - } - } - public class G2 : G - { - public int M1(T p) - { - return 4; - } - } - public class J - { - public int P - { - get - { - return 2; - } - } - } - public class J2 : J - { -#pragma warning disable 0108 // Deliberate bad code for test case - public int get_P; -#pragma warning restore 0108 - } -} -//$$ HideMembers4 -namespace HideMembers4 -{ - public class A - { - public void M(T t) - { - } - } - public class A1 : A - { - public new void M(K t) - { - } - public void M(int t) - { - } - } - public class B - { - public void M() - { - } - public void M1() - { - } - public void M2(T t) - { - } - } - public class B1 : B - { - public void M() - { - } - public new void M1() - { - } - public new void M2(R r) - { - } - } - public class C - { - public void M(T t) - { - } - } - public class C1 : C - { - public void M(TT t) - { - } - } -} -//$$ HideMembers5 -namespace HideMembers5 -{ - public class A - { - public void M(int t) - { - } - } - public class A1 : A - { - public void M(ref int t) - { - } - } - public class B - { - public void M(ref int l) - { - } - } - public class B1 : B - { - public void M(out int l) - { - l = 2; - } - public void M(ref long l) - { - } - } -} -//$$ HideMemberSkipNotVisible -namespace HideMemberSkipNotVisible -{ - public class A - { - protected int F; - protected string P - { - get - { - return null; - } - } - } - public class B : A - { - private new string F; - private new int P - { - set - { - } - } - } -} -//$$ HideNestedClass -namespace HideNestedClass -{ - public class A - { - public class N1 - { - } - protected class N2 - { - } - private class N3 - { - } - internal class N4 - { - } - protected internal class N5 - { - } - } - public class B : A - { - public new int N1; - public new int N2; - public int N3; - public new int N4; - public new int N5; - } -} -//$$ HidePropertyReservedMethod -namespace HidePropertyReservedMethod -{ - public class A - { - public int P - { - get - { - return 1; - } - } - } - public class B : A - { - public int get_P() - { - return 2; - } - public void set_P(int value) - { - } - } -} -//$$ HideIndexerDiffAccessor -namespace HideIndexerDiffAccessor -{ - public class A - { - public int this[int i] - { - get - { - return 2; - } - } - } - public class B : A - { - public new int this[int j] - { - set - { - } - } - } -} -//$$ HideIndexerGeneric -namespace HideIndexerGeneric -{ - public class A - { - public virtual int this[T r] - { - get - { - return 0; - } - set - { - } - } - } - public class B : A - { - private new int this[int k] - { - get - { - return 0; - } - set - { - } - } - } - public class C : A - { - public override int this[T s] - { - set - { - } - } - } - public class D : C - { - public new virtual int this[T s] - { - set - { - } - } - } -} -//$$ HideMethod -namespace HideMethod -{ - public class A - { - public virtual void F() - { - } - } - public class B : A - { - private new void F() - { - base.F(); - } - } - public class C : B - { - public override void F() - { - base.F(); - } - } -} -//$$ HideMethodGeneric -namespace HideMethodGeneric -{ - public class A - { - public virtual void F(T s) - { - } - public new static bool Equals(object o1, object o2) - { - return true; - } - } - public class B : A - { - private new void F(string k) - { - } - public void F(int i) - { - } - } - public class C : A - { - public override void F(T r) - { - } - public void G(T t) - { - } - } - public class D : C - { - public new virtual void F(T1 k) - { - } - public virtual void F(T2 k) - { - } - public virtual void G(T2 t) - { - } - } -} -//$$ HideMethodGenericSkipPrivate -namespace HideMethodGenericSkipPrivate -{ - public class A - { - public virtual void F(T t) - { - } - } - public class B : A - { - private new void F(T t) - { - } - private void K() - { - } - } - public class C : B - { - public override void F(T tt) - { - } - public void K() - { - } - } - public class D : B - { - public override void F(int t) - { - } - } -} -//$$ HideMethodGeneric2 -namespace HideMethodGeneric2 -{ - public class A - { - public virtual void F(int i) - { - } - public void K() - { - } - } - public class B : A - { - protected virtual void F(T t) - { - } - public void K() - { - } - } - public class C : B - { - protected override void F(int k) - { - } - public new void K() - { - } - } - public class D : B - { - public override void F(int k) - { - } - public void L() - { - } - } - public class E - { - public void M(T t, T2 t2) - { - } - } - public class F : E - { - public void M(T t1, T t2) - { - } - } -} -//$$ HideMethodDiffSignatures -namespace HideMethodDiffSignatures -{ - public class C1 - { - public virtual void M(T arg) - { - } - } - public class C2 : C1 - { - public new virtual void M(T2 arg) - { - } - } - public class C3 : C2 - { - public new virtual void M(bool arg) - { - } - } -} -//$$ HideMethodStatic -namespace HideMethodStatic -{ - public class A - { - public int N - { - get - { - return 0; - } - } - } - public class B - { - public int N() - { - return 0; - } - } -} -//$$ HideEvent -namespace HideEvent -{ - public class A - { - public virtual event EventHandler E; - public event EventHandler F; - } - public class B : A - { - public new virtual event EventHandler E; - public new event EventHandler F; - } - public class C : B - { - public override event EventHandler E; - } -} diff --git a/ICSharpCode.Decompiler/Tests/Types/TypeTests.cs b/ICSharpCode.Decompiler/Tests/Types/TypeTests.cs deleted file mode 100644 index 3bb80ed8..00000000 --- a/ICSharpCode.Decompiler/Tests/Types/TypeTests.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using NUnit.Framework; - -namespace ICSharpCode.Decompiler.Tests.Types -{ - [TestFixture] - public class TypeTests : DecompilerTestBase - { - [Test] - public void TypeMemberDeclarations() - { - ValidateFileRoundtrip(@"Types\S_TypeMemberDeclarations.cs"); - } - } -} diff --git a/ICSharpCode.Decompiler/Tests/UndocumentedExpressions.cs b/ICSharpCode.Decompiler/Tests/UndocumentedExpressions.cs deleted file mode 100644 index 80f5b037..00000000 --- a/ICSharpCode.Decompiler/Tests/UndocumentedExpressions.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 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; - -public class UndocumentedExpressions -{ - public static int GetArgCount(__arglist) - { - ArgIterator argIterator = new ArgIterator(__arglist); - return argIterator.GetRemainingCount(); - } - - public static void MakeTypedRef(object o) - { - TypedReference tr = __makeref(o); - UndocumentedExpressions.AcceptTypedRef(tr); - } - - private static void AcceptTypedRef(TypedReference tr) - { - Console.WriteLine("Value is: " + __refvalue(tr, object).ToString()); - Console.WriteLine("Type is: " + __reftype(tr).Name); - __refvalue(tr, object) = 1; - } -} diff --git a/ICSharpCode.Decompiler/Tests/UnsafeCode.cs b/ICSharpCode.Decompiler/Tests/UnsafeCode.cs deleted file mode 100644 index 1a3bd6a0..00000000 --- a/ICSharpCode.Decompiler/Tests/UnsafeCode.cs +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright (c) 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; - -public class UnsafeCode -{ - public unsafe int* NullPointer - { - get - { - return null; - } - } - - public unsafe long ConvertDoubleToLong(double d) - { - return *(long*)(&d); - } - - public unsafe double ConvertLongToDouble(long d) - { - return *(double*)(&d); - } - - public unsafe int ConvertFloatToInt(float d) - { - return *(int*)(&d); - } - - public unsafe float ConvertIntToFloat(int d) - { - return *(float*)(&d); - } - - public unsafe void PassRefParameterAsPointer(ref int p) - { - fixed (int* ptr = &p) - { - this.PassPointerAsRefParameter(ptr); - } - } - - public unsafe void PassPointerAsRefParameter(int* p) - { - this.PassRefParameterAsPointer(ref *p); - } - - public unsafe void AddressInMultiDimensionalArray(double[,] matrix) - { - fixed (double* ptr = &matrix[1, 2]) - { - this.PointerReferenceExpression(ptr); - } - } - - public unsafe void FixedStringAccess(string text) - { - fixed (char* ptr = text) - { - char* ptr2 = ptr; - while (*ptr2 != '\0') - { - *ptr2 = 'A'; - ptr2++; - } - } - } - - public unsafe void PutDoubleIntoLongArray1(long[] array, int index, double val) - { - fixed (long* ptr = array) - { - ((double*)ptr)[index] = val; - } - } - - public unsafe void PutDoubleIntoLongArray2(long[] array, int index, double val) - { - fixed (long* ptr = &array[index]) - { - *(double*)ptr = val; - } - } - - public unsafe string PointerReferenceExpression(double* d) - { - return d->ToString(); - } - - public unsafe void FixMultipleStrings(string text) - { - fixed (char* ptr = text, userName = Environment.UserName, ptr2 = text) - { - *ptr = 'c'; - *userName = 'd'; - *ptr2 = 'e'; - } - } - - public unsafe string StackAlloc(int count) - { - char* ptr = stackalloc char[count]; - for (int i = 0; i < count; i++) - { - ptr[i] = (char)i; - } - return this.PointerReferenceExpression((double*)ptr); - } - - public unsafe int* PointerArithmetic(int* p) - { - return p + 2; - } - - public unsafe byte* PointerArithmetic2(long* p, int y, int x) - { - return (byte*)p + (y * x); - } - - public unsafe long* PointerArithmetic3(long* p) - { - return (long*)((byte*)p + 3); - } - - unsafe ~UnsafeCode() - { - this.PassPointerAsRefParameter(this.NullPointer); - } -} diff --git a/ICSharpCode.Decompiler/Tests/ValueTypes.cs b/ICSharpCode.Decompiler/Tests/ValueTypes.cs deleted file mode 100644 index 1493cff4..00000000 --- a/ICSharpCode.Decompiler/Tests/ValueTypes.cs +++ /dev/null @@ -1,188 +0,0 @@ -// Copyright (c) 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; - -public static class ValueTypes -{ - public struct S - { - public int Field; - - public S(int field) - { - this.Field = field; - } - - public void SetField() - { - this.Field = 5; - } - - public void MethodCalls() - { - this.SetField(); - ValueTypes.S.Test(this); - ValueTypes.S.Test(ref this); - } - - private static void Test(ValueTypes.S byVal) - { - } - - private static void Test(ref ValueTypes.S byRef) - { - } - } - - private static readonly ValueTypes.S ReadOnlyS = default(ValueTypes.S); - private static ValueTypes.S MutableS = default(ValueTypes.S); - private static volatile int VolatileInt; - - public static void CallMethodViaField() - { - ValueTypes.ReadOnlyS.SetField(); - ValueTypes.MutableS.SetField(); - ValueTypes.S mutableS = ValueTypes.MutableS; - mutableS.SetField(); - } - - public static ValueTypes.S InitObj1() - { - ValueTypes.S result = default(ValueTypes.S); - ValueTypes.MakeArray(); - return result; - } - - public static ValueTypes.S InitObj2() - { - return default(ValueTypes.S); - } - - public static void InitObj3(out ValueTypes.S p) - { - p = default(ValueTypes.S); - } - - public static ValueTypes.S CallValueTypeCtor1() - { - return new ValueTypes.S(10); - } - - public static ValueTypes.S CallValueTypeCtor2() - { - ValueTypes.S result = new ValueTypes.S(10); - return result; - } - - public static ValueTypes.S Copy1(ValueTypes.S p) - { - return p; - } - - public static ValueTypes.S Copy2(ref ValueTypes.S p) - { - return p; - } - - public static void Copy3(ValueTypes.S p, out ValueTypes.S o) - { - o = p; - } - - public static void Copy4(ref ValueTypes.S p, out ValueTypes.S o) - { - o = p; - } - - public static void Copy4b(ref ValueTypes.S p, out ValueTypes.S o) - { - // test passing through by-ref arguments - ValueTypes.Copy4(ref p, out o); - } - - public static void Issue56(int i, out string str) - { - str = "qq"; - str += i.ToString(); - } - - public static void CopyAroundAndModifyField(ValueTypes.S s) - { - ValueTypes.S s2 = s; - s2.Field += 10; - s = s2; - } - - private static int[] MakeArray() - { - return null; - } - - public static void IncrementArrayLocation() - { - ValueTypes.MakeArray()[Environment.TickCount]++; - } - - public static bool Is(object obj) - { - return obj is ValueTypes.S; - } - - public static bool IsNullable(object obj) - { - return obj is ValueTypes.S?; - } - - public static ValueTypes.S? As(object obj) - { - return obj as ValueTypes.S?; - } - - public static ValueTypes.S OnlyChangeTheCopy(ValueTypes.S p) - { - ValueTypes.S s = p; - s.SetField(); - return p; - } - - public static void UseRefBoolInCondition(ref bool x) - { - if (x) - { - Console.WriteLine("true"); - } - } - - public static void CompareNotEqual0IsReallyNotEqual(IComparable a) - { - if (a.CompareTo(0) != 0) - { - Console.WriteLine("true"); - } - } - - public static void CompareEqual0IsReallyEqual(IComparable a) - { - if (a.CompareTo(0) == 0) - { - Console.WriteLine("true"); - } - } - -} diff --git a/ICSharpCode.Decompiler/Tests/YieldReturn.cs b/ICSharpCode.Decompiler/Tests/YieldReturn.cs deleted file mode 100644 index 7546b194..00000000 --- a/ICSharpCode.Decompiler/Tests/YieldReturn.cs +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright (c) AlphaSierraPapa for the SharpDevelop Team -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of this -// software and associated documentation files (the "Software"), to deal in the Software -// without restriction, including without limitation the rights to use, copy, modify, merge, -// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -// to whom the Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all copies or -// substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. - -using System; -using System.Collections.Generic; - -public static class YieldReturn -{ - public static IEnumerable SimpleYieldReturn() - { - yield return "A"; - yield return "B"; - yield return "C"; - } - - public static IEnumerable YieldReturnInLoop() - { - for (int i = 0; i < 100; i++) { - yield return i; - } - } - - public static IEnumerable YieldReturnWithTryFinally() - { - yield return 0; - try { - yield return 1; - } finally { - Console.WriteLine("Finally!"); - } - yield return 2; - } - - public static IEnumerable YieldReturnInLock1(object o) - { - lock (o) { - yield return 1; - } - } - - public static IEnumerable YieldReturnInLock2(object o) - { - lock (o) { - yield return 1; - o = null; - yield return 2; - } - } - - public static IEnumerable YieldReturnWithNestedTryFinally(bool breakInMiddle) - { - Console.WriteLine("Start of method - 1"); - yield return "Start of method"; - Console.WriteLine("Start of method - 2"); - try { - Console.WriteLine("Within outer try - 1"); - yield return "Within outer try"; - Console.WriteLine("Within outer try - 2"); - try { - Console.WriteLine("Within inner try - 1"); - yield return "Within inner try"; - Console.WriteLine("Within inner try - 2"); - if (breakInMiddle) - yield break; - Console.WriteLine("End of inner try - 1"); - yield return "End of inner try"; - Console.WriteLine("End of inner try - 2"); - } finally { - Console.WriteLine("Inner Finally"); - } - Console.WriteLine("End of outer try - 1"); - yield return "End of outer try"; - Console.WriteLine("End of outer try - 2"); - } finally { - Console.WriteLine("Outer Finally"); - } - Console.WriteLine("End of method - 1"); - yield return "End of method"; - Console.WriteLine("End of method - 2"); - } - - public static IEnumerable YieldReturnWithTwoNonNestedFinallyBlocks(IEnumerable input) - { - // outer try-finally block - foreach (string line in input) { - // nested try-finally block - try { - yield return line; - } finally { - Console.WriteLine("Processed " + line); - } - } - yield return "A"; - yield return "B"; - yield return "C"; - yield return "D"; - yield return "E"; - yield return "F"; - // outer try-finally block - foreach (string line in input) - yield return line.ToUpper(); - } - - public static IEnumerable> YieldReturnWithAnonymousMethods1(IEnumerable input) - { - foreach (string line in input) { - yield return () => line; - } - } - - public static IEnumerable> YieldReturnWithAnonymousMethods2(IEnumerable input) - { - foreach (string line in input) { - string copy = line; - yield return () => copy; - } - } - - public static IEnumerable GetEvenNumbers(int n) - { - for (int i = 0; i < n; i++) { - if (i % 2 == 0) - yield return i; - } - } - - public static IEnumerable YieldChars() - { - yield return 'a'; - yield return 'b'; - yield return 'c'; - } -} diff --git a/ICSharpCode.Decompiler/Tests/packages.config b/ICSharpCode.Decompiler/Tests/packages.config deleted file mode 100644 index b6522ccd..00000000 --- a/ICSharpCode.Decompiler/Tests/packages.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/ICSharpCode.Decompiler/TextOutputWriter.cs b/ICSharpCode.Decompiler/TextOutputWriter.cs deleted file mode 100644 index 964187a3..00000000 --- a/ICSharpCode.Decompiler/TextOutputWriter.cs +++ /dev/null @@ -1,55 +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.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(); - } - } -} diff --git a/ICSharpCode.Decompiler/packages.config b/ICSharpCode.Decompiler/packages.config deleted file mode 100644 index 1bdbf546..00000000 --- a/ICSharpCode.Decompiler/packages.config +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/Xamarin.Forms.Build.Tasks/Xamarin.Forms.Build.Tasks.csproj b/Xamarin.Forms.Build.Tasks/Xamarin.Forms.Build.Tasks.csproj index 46d4f23b..c845b597 100644 --- a/Xamarin.Forms.Build.Tasks/Xamarin.Forms.Build.Tasks.csproj +++ b/Xamarin.Forms.Build.Tasks/Xamarin.Forms.Build.Tasks.csproj @@ -121,10 +121,6 @@ {57B8B73D-C3B5-4C42-869E-7B2F17D354AC} Xamarin.Forms.Core - - {984CC812-9470-4A13-AFF9-CC44068D666C} - ICSharpCode.Decompiler - diff --git a/Xamarin.Forms.Build.Tasks/XamlCTask.cs b/Xamarin.Forms.Build.Tasks/XamlCTask.cs index d8b80233..eda44a9a 100644 --- a/Xamarin.Forms.Build.Tasks/XamlCTask.cs +++ b/Xamarin.Forms.Build.Tasks/XamlCTask.cs @@ -2,8 +2,6 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; -using ICSharpCode.Decompiler; -using ICSharpCode.Decompiler.Ast; using Mono.Cecil; using Mono.Cecil.Cil; using Mono.Cecil.Rocks; @@ -16,7 +14,13 @@ namespace Xamarin.Forms.Build.Tasks bool hasCompiledXamlResources; public bool KeepXamlResources { get; set; } public bool OptimizeIL { get; set; } - public bool OutputGeneratedILAsCode { get; set; } + + bool outputGeneratedILAsCode; + [Obsolete("This option is no longer available")] + public bool OutputGeneratedILAsCode { + get { return outputGeneratedILAsCode; } + set { outputGeneratedILAsCode = value; } + } internal string Type { get; set; } @@ -185,22 +189,9 @@ namespace Xamarin.Forms.Build.Tasks Logger.LogLine(2, "done"); } - if (OutputGeneratedILAsCode) - { - var filepath = Path.Combine(Path.GetDirectoryName(Assembly), typeDef.FullName + ".decompiled.cs"); - Logger.LogString(2, " Decompiling {0} into {1}...", typeDef.FullName, filepath); - var decompilerContext = new DecompilerContext(module); - using (var writer = new StreamWriter(filepath)) - { - var output = new PlainTextOutput(writer); - - var codeDomBuilder = new AstBuilder(decompilerContext); - codeDomBuilder.AddType(typeDef); - codeDomBuilder.GenerateCode(output); - } + if (outputGeneratedILAsCode) + Logger.LogLine(2, " Decompiling option has been removed. Use a 3rd party decompiler to admire the beauty of the IL generated"); - Logger.LogLine(2, "done"); - } resourcesToPrune.Add(resource); } if (!KeepXamlResources) diff --git a/Xamarin.Forms.Xaml.Xamlc/Xamlc.cs b/Xamarin.Forms.Xaml.Xamlc/Xamlc.cs index 5a42fa02..ec99b71a 100644 --- a/Xamarin.Forms.Xaml.Xamlc/Xamlc.cs +++ b/Xamarin.Forms.Xaml.Xamlc/Xamlc.cs @@ -16,7 +16,6 @@ namespace Xamarin.Forms.Xaml int verbosity = 1; bool keep = false; bool optimize = false; - bool decompile = false; string paths = null; string refs = null; List extra = null; @@ -29,7 +28,6 @@ namespace Xamarin.Forms.Xaml { "keep", "do not strip compiled embedded xaml", v => keep = true }, { "p=|paths=|dependencypaths=", "look for dependencies in (comma separated) list of paths", v => paths = v }, { "r=", "referencepath", v => refs = v }, - { "d|decompile", v => decompile = true } }; if (help || args.Length < 1) @@ -64,8 +62,7 @@ namespace Xamarin.Forms.Xaml KeepXamlResources = keep, OptimizeIL = optimize, DependencyPaths = paths, - ReferencePath = refs, - OutputGeneratedILAsCode=decompile, + ReferencePath = refs }; xamlc.Execute(null); } diff --git a/Xamarin.Forms.sln b/Xamarin.Forms.sln index 0f848551..12ba3e80 100644 --- a/Xamarin.Forms.sln +++ b/Xamarin.Forms.sln @@ -27,8 +27,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xamarin.Forms.Xaml.UnitTest EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xamarin.Forms.Xaml.Xamlc", "Xamarin.Forms.Xaml.Xamlc\Xamarin.Forms.Xaml.Xamlc.csproj", "{928A23F3-2330-4F9F-B6A3-BFE01FE2A2DF}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.Decompiler", "ICSharpCode.Decompiler\ICSharpCode.Decompiler.csproj", "{984CC812-9470-4A13-AFF9-CC44068D666C}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{29583A59-ACE2-4C2C-8A73-768D6979551A}" ProjectSection(SolutionItems) = preProject .nuget\packages.config = .nuget\packages.config @@ -365,34 +363,6 @@ Global {928A23F3-2330-4F9F-B6A3-BFE01FE2A2DF}.Release|x64.Build.0 = Release|Any CPU {928A23F3-2330-4F9F-B6A3-BFE01FE2A2DF}.Release|x86.ActiveCfg = Release|Any CPU {928A23F3-2330-4F9F-B6A3-BFE01FE2A2DF}.Release|x86.Build.0 = Release|Any CPU - {984CC812-9470-4A13-AFF9-CC44068D666C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {984CC812-9470-4A13-AFF9-CC44068D666C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {984CC812-9470-4A13-AFF9-CC44068D666C}.Debug|ARM.ActiveCfg = Debug|Any CPU - {984CC812-9470-4A13-AFF9-CC44068D666C}.Debug|ARM.Build.0 = Debug|Any CPU - {984CC812-9470-4A13-AFF9-CC44068D666C}.Debug|iPhone.ActiveCfg = Debug|Any CPU - {984CC812-9470-4A13-AFF9-CC44068D666C}.Debug|iPhone.Build.0 = Debug|Any CPU - {984CC812-9470-4A13-AFF9-CC44068D666C}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU - {984CC812-9470-4A13-AFF9-CC44068D666C}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU - {984CC812-9470-4A13-AFF9-CC44068D666C}.Debug|Templates.ActiveCfg = Debug|Any CPU - {984CC812-9470-4A13-AFF9-CC44068D666C}.Debug|Templates.Build.0 = Debug|Any CPU - {984CC812-9470-4A13-AFF9-CC44068D666C}.Debug|x64.ActiveCfg = Debug|Any CPU - {984CC812-9470-4A13-AFF9-CC44068D666C}.Debug|x64.Build.0 = Debug|Any CPU - {984CC812-9470-4A13-AFF9-CC44068D666C}.Debug|x86.ActiveCfg = Debug|Any CPU - {984CC812-9470-4A13-AFF9-CC44068D666C}.Debug|x86.Build.0 = Debug|Any CPU - {984CC812-9470-4A13-AFF9-CC44068D666C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {984CC812-9470-4A13-AFF9-CC44068D666C}.Release|Any CPU.Build.0 = Release|Any CPU - {984CC812-9470-4A13-AFF9-CC44068D666C}.Release|ARM.ActiveCfg = Release|Any CPU - {984CC812-9470-4A13-AFF9-CC44068D666C}.Release|ARM.Build.0 = Release|Any CPU - {984CC812-9470-4A13-AFF9-CC44068D666C}.Release|iPhone.ActiveCfg = Release|Any CPU - {984CC812-9470-4A13-AFF9-CC44068D666C}.Release|iPhone.Build.0 = Release|Any CPU - {984CC812-9470-4A13-AFF9-CC44068D666C}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU - {984CC812-9470-4A13-AFF9-CC44068D666C}.Release|iPhoneSimulator.Build.0 = Release|Any CPU - {984CC812-9470-4A13-AFF9-CC44068D666C}.Release|Templates.ActiveCfg = Release|Any CPU - {984CC812-9470-4A13-AFF9-CC44068D666C}.Release|Templates.Build.0 = Release|Any CPU - {984CC812-9470-4A13-AFF9-CC44068D666C}.Release|x64.ActiveCfg = Release|Any CPU - {984CC812-9470-4A13-AFF9-CC44068D666C}.Release|x64.Build.0 = Release|Any CPU - {984CC812-9470-4A13-AFF9-CC44068D666C}.Release|x86.ActiveCfg = Release|Any CPU - {984CC812-9470-4A13-AFF9-CC44068D666C}.Release|x86.Build.0 = Release|Any CPU {517B6AE0-792B-4665-9376-5CA33E539181}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {517B6AE0-792B-4665-9376-5CA33E539181}.Debug|Any CPU.Build.0 = Debug|Any CPU {517B6AE0-792B-4665-9376-5CA33E539181}.Debug|ARM.ActiveCfg = Debug|ARM @@ -1536,7 +1506,6 @@ Global {D597E3C6-1A50-4042-99FA-3E7CE28E4819} = {32F608E2-6406-4DCF-9105-E2A7CB7085CF} {4B14D295-C09B-4C38-B880-7CC768E50585} = {32F608E2-6406-4DCF-9105-E2A7CB7085CF} {928A23F3-2330-4F9F-B6A3-BFE01FE2A2DF} = {32F608E2-6406-4DCF-9105-E2A7CB7085CF} - {984CC812-9470-4A13-AFF9-CC44068D666C} = {32F608E2-6406-4DCF-9105-E2A7CB7085CF} {517B6AE0-792B-4665-9376-5CA33E539181} = {29AC50BF-B4FB-450B-9386-0C5AD4B84226} {67F3837C-C663-4668-9CD3-5E6C5ABD59B8} = {4F5E2D21-17F6-4A42-B8FB-D03D82E24EC8} {57B8B73D-C3B5-4C42-869E-7B2F17D354AC} = {9AD757F5-E57A-459D-A0A7-E0675E045B84} -- cgit v1.2.3