Browse Source

Merge branch 'master' of github.com:icsharpcode/SharpDevelop

pull/23/head
PeterForstmeier 14 years ago
parent
commit
54ebb66da4
  1. 86
      SharpDevelop.Tests.sln
  2. 22
      SharpDevelop.sln
  3. 16
      src/AddIns/DisplayBindings/ILSpyAddIn/DebuggerDecompilerService.cs
  4. 76
      src/AddIns/DisplayBindings/ILSpyAddIn/DebuggerTextOutput.cs
  5. 7
      src/AddIns/DisplayBindings/ILSpyAddIn/ILSpyAddIn.csproj
  6. 13
      src/AddIns/DisplayBindings/ILSpyAddIn/Properties/AssemblyInfo.cs
  7. 2
      src/AddIns/DisplayBindings/ILSpyAddIn/ViewContent/DecompiledViewContent.cs
  8. 50
      src/Libraries/ICSharpCode.Decompiler/Ast/Annotations.cs
  9. 81
      src/Libraries/ICSharpCode.Decompiler/Ast/AstBuilder.cs
  10. 182
      src/Libraries/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  11. 16
      src/Libraries/ICSharpCode.Decompiler/Ast/CecilTypeResolveContext.cs
  12. 4
      src/Libraries/ICSharpCode.Decompiler/Ast/NameVariables.cs
  13. 213
      src/Libraries/ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs
  14. 2
      src/Libraries/ICSharpCode.Decompiler/Ast/Transforms/AddCheckedBlocks.cs
  15. 38
      src/Libraries/ICSharpCode.Decompiler/Ast/Transforms/CombineQueryExpressions.cs
  16. 6
      src/Libraries/ICSharpCode.Decompiler/Ast/Transforms/ConvertConstructorCallIntoInitializer.cs
  17. 109
      src/Libraries/ICSharpCode.Decompiler/Ast/Transforms/CustomPatterns.cs
  18. 28
      src/Libraries/ICSharpCode.Decompiler/Ast/Transforms/DeclareVariables.cs
  19. 29
      src/Libraries/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs
  20. 875
      src/Libraries/ICSharpCode.Decompiler/Ast/Transforms/ExpressionTreeConverter.cs
  21. 27
      src/Libraries/ICSharpCode.Decompiler/Ast/Transforms/FlattenSwitchBlocks.cs
  22. 6
      src/Libraries/ICSharpCode.Decompiler/Ast/Transforms/IntroduceExtensionMethods.cs
  23. 41
      src/Libraries/ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs
  24. 14
      src/Libraries/ICSharpCode.Decompiler/Ast/Transforms/PushNegation.cs
  25. 96
      src/Libraries/ICSharpCode.Decompiler/Ast/Transforms/ReplaceMethodCallsWithOperators.cs
  26. 3
      src/Libraries/ICSharpCode.Decompiler/Ast/Transforms/TransformationPipeline.cs
  27. 8
      src/Libraries/ICSharpCode.Decompiler/CecilExtensions.cs
  28. 180
      src/Libraries/ICSharpCode.Decompiler/CodeMappings.cs
  29. 47
      src/Libraries/ICSharpCode.Decompiler/DecompilerSettings.cs
  30. 4
      src/Libraries/ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs
  31. 8
      src/Libraries/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs
  32. 27
      src/Libraries/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs
  33. 2
      src/Libraries/ICSharpCode.Decompiler/FlowAnalysis/SsaFormBuilder.cs
  34. 28
      src/Libraries/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  35. 77
      src/Libraries/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs
  36. 50
      src/Libraries/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
  37. 29
      src/Libraries/ICSharpCode.Decompiler/ILAst/ILCodes.cs
  38. 9
      src/Libraries/ICSharpCode.Decompiler/ILAst/ILInlining.cs
  39. 528
      src/Libraries/ICSharpCode.Decompiler/ILAst/LiftedOperators.cs
  40. 196
      src/Libraries/ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs
  41. 10
      src/Libraries/ICSharpCode.Decompiler/ILAst/SimpleControlFlow.cs
  42. 156
      src/Libraries/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs
  43. 5
      src/Libraries/ICSharpCode.Decompiler/ILAst/YieldReturnDecompiler.cs
  44. 11
      src/Libraries/ICSharpCode.Decompiler/ITextOutput.cs
  45. 36
      src/Libraries/ICSharpCode.Decompiler/PlainTextOutput.cs
  46. 4
      src/Libraries/ICSharpCode.Decompiler/Properties/AssemblyInfo.cs
  47. 27
      src/Libraries/ICSharpCode.Decompiler/Properties/AssemblyInfo.template.cs
  48. 51
      src/Libraries/ICSharpCode.Decompiler/Tests/CheckedUnchecked.cs
  49. 370
      src/Libraries/ICSharpCode.Decompiler/Tests/ExpressionTrees.cs
  50. 5
      src/Libraries/ICSharpCode.Decompiler/Tests/Generics.cs
  51. 15
      src/Libraries/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj
  52. 24
      src/Libraries/ICSharpCode.Decompiler/Tests/InitializerTests.cs
  53. 830
      src/Libraries/ICSharpCode.Decompiler/Tests/LiftedOperators.cs
  54. 9
      src/Libraries/ICSharpCode.Decompiler/Tests/PInvoke.cs
  55. 79
      src/Libraries/ICSharpCode.Decompiler/Tests/QueryExpressions.cs
  56. 28
      src/Libraries/ICSharpCode.Decompiler/Tests/TestRunner.cs
  57. 14
      src/Libraries/ICSharpCode.Decompiler/Tests/TypeAnalysisTests.cs
  58. 3
      src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/.gitignore
  59. 26
      src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Analysis/ControlFlow.cs
  60. 24
      src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Analysis/DefiniteAssignmentAnalysis.cs
  61. 102
      src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/AstNode.cs
  62. 40
      src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/AstNodeCollection.cs
  63. 22
      src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/AstType.cs
  64. 49
      src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/CSharpModifierToken.cs
  65. 20
      src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/CSharpTokenNode.cs
  66. 95
      src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/CSharpUtil.cs
  67. 2
      src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/CompilationUnit.cs
  68. 10
      src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/ComposedType.cs
  69. 13
      src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/DepthFirstAstVisitor.cs
  70. 10
      src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/ErrorNode.cs
  71. 13
      src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/AnonymousMethodExpression.cs
  72. 12
      src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/AnonymousTypeCreateExpression.cs
  73. 20
      src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/ArrayCreateExpression.cs
  74. 18
      src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/ArrayInitializerExpression.cs
  75. 2
      src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/AsExpression.cs
  76. 2
      src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/AssignmentExpression.cs
  77. 10
      src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/BaseReferenceExpression.cs
  78. 15
      src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/BinaryOperatorExpression.cs
  79. 2
      src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/CastExpression.cs
  80. 2
      src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/CheckedExpression.cs
  81. 2
      src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/ConditionalExpression.cs
  82. 2
      src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/DefaultValueExpression.cs
  83. 2
      src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/DirectionExpression.cs
  84. 14
      src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/EmptyExpression.cs
  85. 31
      src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/Expression.cs
  86. 6
      src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/IdentifierExpression.cs
  87. 2
      src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/IndexerExpression.cs
  88. 2
      src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/InvocationExpression.cs
  89. 2
      src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/IsExpression.cs
  90. 13
      src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/LambdaExpression.cs
  91. 6
      src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/MemberReferenceExpression.cs
  92. 77
      src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/NamedArgumentExpression.cs
  93. 86
      src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/NamedExpression.cs
  94. 12
      src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/NullReferenceExpression.cs
  95. 2
      src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/ObjectCreateExpression.cs
  96. 2
      src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/ParenthesizedExpression.cs
  97. 6
      src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/PointerReferenceExpression.cs
  98. 14
      src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/PrimitiveExpression.cs
  99. 71
      src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/QueryExpression.cs
  100. 2
      src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/SizeOfExpression.cs
  101. Some files were not shown because too many files have changed in this diff Show More

86
SharpDevelop.Tests.sln

@ -1,7 +1,7 @@
 
Microsoft Visual Studio Solution File, Format Version 11.00 Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010 # Visual Studio 2010
# SharpDevelop 4.2.0.7998-alpha # SharpDevelop 4.1.0.8000
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Main", "Main", "{256F5C28-532C-44C0-8AB8-D8EC5E492E01}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Main", "Main", "{256F5C28-532C-44C0-8AB8-D8EC5E492E01}"
ProjectSection(SolutionItems) = postProject ProjectSection(SolutionItems) = postProject
EndProjectSection EndProjectSection
@ -296,6 +296,21 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SettingsEditor", "src\AddIn
{35CEF10F-2D4C-45F2-9DD1-161E0FEC583C} = {35CEF10F-2D4C-45F2-9DD1-161E0FEC583C} {35CEF10F-2D4C-45F2-9DD1-161E0FEC583C} = {35CEF10F-2D4C-45F2-9DD1-161E0FEC583C}
EndProjectSection EndProjectSection
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Decompiler", "Decompiler", "{AD8272AC-5C9E-4061-90FB-CEF15A9A3F41}"
ProjectSection(SolutionItems) = postProject
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ILSpyAddIn", "src\AddIns\DisplayBindings\ILSpyAddIn\ILSpyAddIn.csproj", "{8AA421C8-D7AF-4957-9F43-5135328ACB24}"
ProjectSection(ProjectDependencies) = postProject
{35CEF10F-2D4C-45F2-9DD1-161E0FEC583C} = {35CEF10F-2D4C-45F2-9DD1-161E0FEC583C}
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.Decompiler", "src\Libraries\ICSharpCode.Decompiler\ICSharpCode.Decompiler.csproj", "{984CC812-9470-4A13-AFF9-CC44068D666C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.NRefactory", "src\Libraries\NewNRefactory\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj", "{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.NRefactory.CSharp", "src\Libraries\NewNRefactory\ICSharpCode.NRefactory.CSharp\ICSharpCode.NRefactory.CSharp.csproj", "{53DCA265-3C3C-42F9-B647-F72BA678122B}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Misc", "Misc", "{F3662720-9EA2-4591-BBC6-97361DCE50A9}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Misc", "Misc", "{F3662720-9EA2-4591-BBC6-97361DCE50A9}"
ProjectSection(SolutionItems) = postProject ProjectSection(SolutionItems) = postProject
EndProjectSection EndProjectSection
@ -1395,6 +1410,70 @@ Global
{3ED2897F-1A8A-4106-89D2-4D342860D480}.Release|x86.ActiveCfg = Release|Any CPU {3ED2897F-1A8A-4106-89D2-4D342860D480}.Release|x86.ActiveCfg = Release|Any CPU
{3ED2897F-1A8A-4106-89D2-4D342860D480}.Release|Debug.Build.0 = Release|Any CPU {3ED2897F-1A8A-4106-89D2-4D342860D480}.Release|Debug.Build.0 = Release|Any CPU
{3ED2897F-1A8A-4106-89D2-4D342860D480}.Release|Debug.ActiveCfg = Release|Any CPU {3ED2897F-1A8A-4106-89D2-4D342860D480}.Release|Debug.ActiveCfg = Release|Any CPU
{8AA421C8-D7AF-4957-9F43-5135328ACB24}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8AA421C8-D7AF-4957-9F43-5135328ACB24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8AA421C8-D7AF-4957-9F43-5135328ACB24}.Debug|Win32.Build.0 = Debug|Any CPU
{8AA421C8-D7AF-4957-9F43-5135328ACB24}.Debug|Win32.ActiveCfg = Debug|Any CPU
{8AA421C8-D7AF-4957-9F43-5135328ACB24}.Debug|x86.Build.0 = Debug|Any CPU
{8AA421C8-D7AF-4957-9F43-5135328ACB24}.Debug|x86.ActiveCfg = Debug|Any CPU
{8AA421C8-D7AF-4957-9F43-5135328ACB24}.Debug|Debug.Build.0 = Debug|Any CPU
{8AA421C8-D7AF-4957-9F43-5135328ACB24}.Debug|Debug.ActiveCfg = Debug|Any CPU
{8AA421C8-D7AF-4957-9F43-5135328ACB24}.Release|Any CPU.Build.0 = Release|Any CPU
{8AA421C8-D7AF-4957-9F43-5135328ACB24}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8AA421C8-D7AF-4957-9F43-5135328ACB24}.Release|Win32.Build.0 = Release|Any CPU
{8AA421C8-D7AF-4957-9F43-5135328ACB24}.Release|Win32.ActiveCfg = Release|Any CPU
{8AA421C8-D7AF-4957-9F43-5135328ACB24}.Release|x86.Build.0 = Release|Any CPU
{8AA421C8-D7AF-4957-9F43-5135328ACB24}.Release|x86.ActiveCfg = Release|Any CPU
{8AA421C8-D7AF-4957-9F43-5135328ACB24}.Release|Debug.Build.0 = Release|Any CPU
{8AA421C8-D7AF-4957-9F43-5135328ACB24}.Release|Debug.ActiveCfg = Release|Any CPU
{984CC812-9470-4A13-AFF9-CC44068D666C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{984CC812-9470-4A13-AFF9-CC44068D666C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{984CC812-9470-4A13-AFF9-CC44068D666C}.Debug|Win32.Build.0 = Debug|Any CPU
{984CC812-9470-4A13-AFF9-CC44068D666C}.Debug|Win32.ActiveCfg = Debug|Any CPU
{984CC812-9470-4A13-AFF9-CC44068D666C}.Debug|x86.Build.0 = Debug|Any CPU
{984CC812-9470-4A13-AFF9-CC44068D666C}.Debug|x86.ActiveCfg = Debug|Any CPU
{984CC812-9470-4A13-AFF9-CC44068D666C}.Debug|Debug.Build.0 = Debug|Any CPU
{984CC812-9470-4A13-AFF9-CC44068D666C}.Debug|Debug.ActiveCfg = Debug|Any CPU
{984CC812-9470-4A13-AFF9-CC44068D666C}.Release|Any CPU.Build.0 = Release|Any CPU
{984CC812-9470-4A13-AFF9-CC44068D666C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{984CC812-9470-4A13-AFF9-CC44068D666C}.Release|Win32.Build.0 = Release|Any CPU
{984CC812-9470-4A13-AFF9-CC44068D666C}.Release|Win32.ActiveCfg = Release|Any CPU
{984CC812-9470-4A13-AFF9-CC44068D666C}.Release|x86.Build.0 = Release|Any CPU
{984CC812-9470-4A13-AFF9-CC44068D666C}.Release|x86.ActiveCfg = Release|Any CPU
{984CC812-9470-4A13-AFF9-CC44068D666C}.Release|Debug.Build.0 = Release|Any CPU
{984CC812-9470-4A13-AFF9-CC44068D666C}.Release|Debug.ActiveCfg = Release|Any CPU
{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Debug|Win32.Build.0 = Debug|Any CPU
{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Debug|Win32.ActiveCfg = Debug|Any CPU
{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Debug|x86.Build.0 = Debug|Any CPU
{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Debug|x86.ActiveCfg = Debug|Any CPU
{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Debug|Debug.Build.0 = Debug|Any CPU
{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Debug|Debug.ActiveCfg = Debug|Any CPU
{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Release|Any CPU.Build.0 = Release|Any CPU
{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Release|Win32.Build.0 = Release|Any CPU
{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Release|Win32.ActiveCfg = Release|Any CPU
{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Release|x86.Build.0 = Release|Any CPU
{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Release|x86.ActiveCfg = Release|Any CPU
{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Release|Debug.Build.0 = Release|Any CPU
{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Release|Debug.ActiveCfg = Release|Any CPU
{53DCA265-3C3C-42F9-B647-F72BA678122B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{53DCA265-3C3C-42F9-B647-F72BA678122B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{53DCA265-3C3C-42F9-B647-F72BA678122B}.Debug|Win32.Build.0 = Debug|Any CPU
{53DCA265-3C3C-42F9-B647-F72BA678122B}.Debug|Win32.ActiveCfg = Debug|Any CPU
{53DCA265-3C3C-42F9-B647-F72BA678122B}.Debug|x86.Build.0 = Debug|Any CPU
{53DCA265-3C3C-42F9-B647-F72BA678122B}.Debug|x86.ActiveCfg = Debug|Any CPU
{53DCA265-3C3C-42F9-B647-F72BA678122B}.Debug|Debug.Build.0 = Debug|Any CPU
{53DCA265-3C3C-42F9-B647-F72BA678122B}.Debug|Debug.ActiveCfg = Debug|Any CPU
{53DCA265-3C3C-42F9-B647-F72BA678122B}.Release|Any CPU.Build.0 = Release|Any CPU
{53DCA265-3C3C-42F9-B647-F72BA678122B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{53DCA265-3C3C-42F9-B647-F72BA678122B}.Release|Win32.Build.0 = Release|Any CPU
{53DCA265-3C3C-42F9-B647-F72BA678122B}.Release|Win32.ActiveCfg = Release|Any CPU
{53DCA265-3C3C-42F9-B647-F72BA678122B}.Release|x86.Build.0 = Release|Any CPU
{53DCA265-3C3C-42F9-B647-F72BA678122B}.Release|x86.ActiveCfg = Release|Any CPU
{53DCA265-3C3C-42F9-B647-F72BA678122B}.Release|Debug.Build.0 = Release|Any CPU
{53DCA265-3C3C-42F9-B647-F72BA678122B}.Release|Debug.ActiveCfg = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -1450,6 +1529,7 @@ Global
{BFA3BF26-33BD-4A65-B84D-C7F30D131668} = {11BF9245-88A3-4A0A-9A8A-EC9D98036B0F} {BFA3BF26-33BD-4A65-B84D-C7F30D131668} = {11BF9245-88A3-4A0A-9A8A-EC9D98036B0F}
{C7F29FC2-1B03-4CDD-9E30-400F4765FF04} = {11BF9245-88A3-4A0A-9A8A-EC9D98036B0F} {C7F29FC2-1B03-4CDD-9E30-400F4765FF04} = {11BF9245-88A3-4A0A-9A8A-EC9D98036B0F}
{85226AFB-CE71-4851-9A75-7EEC663A8E8A} = {11BF9245-88A3-4A0A-9A8A-EC9D98036B0F} {85226AFB-CE71-4851-9A75-7EEC663A8E8A} = {11BF9245-88A3-4A0A-9A8A-EC9D98036B0F}
{AD8272AC-5C9E-4061-90FB-CEF15A9A3F41} = {11BF9245-88A3-4A0A-9A8A-EC9D98036B0F}
{88DA149F-21B2-48AB-82C4-28FB6BDFD783} = {6022AC51-B658-4C54-97EF-79187AC65B47} {88DA149F-21B2-48AB-82C4-28FB6BDFD783} = {6022AC51-B658-4C54-97EF-79187AC65B47}
{943DBBB3-E84E-4CF4-917C-C05AFA8743C1} = {6022AC51-B658-4C54-97EF-79187AC65B47} {943DBBB3-E84E-4CF4-917C-C05AFA8743C1} = {6022AC51-B658-4C54-97EF-79187AC65B47}
{78CC29AC-CC79-4355-B1F2-97936DF198AC} = {6022AC51-B658-4C54-97EF-79187AC65B47} {78CC29AC-CC79-4355-B1F2-97936DF198AC} = {6022AC51-B658-4C54-97EF-79187AC65B47}
@ -1466,6 +1546,10 @@ Global
{5C70D6AB-0A33-43F9-B8B5-54558C35BBB1} = {C7F29FC2-1B03-4CDD-9E30-400F4765FF04} {5C70D6AB-0A33-43F9-B8B5-54558C35BBB1} = {C7F29FC2-1B03-4CDD-9E30-400F4765FF04}
{EEF5E054-4192-4A57-8FBF-E860D808A51D} = {C7F29FC2-1B03-4CDD-9E30-400F4765FF04} {EEF5E054-4192-4A57-8FBF-E860D808A51D} = {C7F29FC2-1B03-4CDD-9E30-400F4765FF04}
{AFE34868-AFA1-4E1C-9450-47AB4BE329D5} = {C7F29FC2-1B03-4CDD-9E30-400F4765FF04} {AFE34868-AFA1-4E1C-9450-47AB4BE329D5} = {C7F29FC2-1B03-4CDD-9E30-400F4765FF04}
{8AA421C8-D7AF-4957-9F43-5135328ACB24} = {AD8272AC-5C9E-4061-90FB-CEF15A9A3F41}
{984CC812-9470-4A13-AFF9-CC44068D666C} = {AD8272AC-5C9E-4061-90FB-CEF15A9A3F41}
{3B2A5653-EC97-4001-BB9B-D90F1AF2C371} = {AD8272AC-5C9E-4061-90FB-CEF15A9A3F41}
{53DCA265-3C3C-42F9-B647-F72BA678122B} = {AD8272AC-5C9E-4061-90FB-CEF15A9A3F41}
{C6410CCE-C29F-4BF4-94BF-545DE1CBB144} = {F3662720-9EA2-4591-BBC6-97361DCE50A9} {C6410CCE-C29F-4BF4-94BF-545DE1CBB144} = {F3662720-9EA2-4591-BBC6-97361DCE50A9}
{DEFC8584-BEC3-4921-BD0F-40482E450B7B} = {F3662720-9EA2-4591-BBC6-97361DCE50A9} {DEFC8584-BEC3-4921-BD0F-40482E450B7B} = {F3662720-9EA2-4591-BBC6-97361DCE50A9}
{A569DCC1-C608-45FD-B770-4F79335EF154} = {F3662720-9EA2-4591-BBC6-97361DCE50A9} {A569DCC1-C608-45FD-B770-4F79335EF154} = {F3662720-9EA2-4591-BBC6-97361DCE50A9}

22
SharpDevelop.sln

@ -473,6 +473,11 @@ EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.NRefactory", "src\Libraries\NewNRefactory\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj", "{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.NRefactory", "src\Libraries\NewNRefactory\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj", "{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ILSpyAddIn", "src\AddIns\DisplayBindings\ILSpyAddIn\ILSpyAddIn.csproj", "88305E42-C90D-410F-B831-15161E23BAAA" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ILSpyAddIn", "src\AddIns\DisplayBindings\ILSpyAddIn\ILSpyAddIn.csproj", "88305E42-C90D-410F-B831-15161E23BAAA"
ProjectSection(ProjectDependencies) = postProject
{35CEF10F-2D4C-45F2-9DD1-161E0FEC583C} = {35CEF10F-2D4C-45F2-9DD1-161E0FEC583C}
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.NRefactory.CSharp", "src\Libraries\NewNRefactory\ICSharpCode.NRefactory.CSharp\ICSharpCode.NRefactory.CSharp.csproj", "{53DCA265-3C3C-42F9-B647-F72BA678122B}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Analysis", "Analysis", "{F355E45F-F54F-4B42-8916-9A633A392789}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Analysis", "Analysis", "{F355E45F-F54F-4B42-8916-9A633A392789}"
ProjectSection(SolutionItems) = postProject ProjectSection(SolutionItems) = postProject
@ -1131,6 +1136,22 @@ Global
{3ED2897F-1A8A-4106-89D2-4D342860D480}.Release|x86.ActiveCfg = Release|Any CPU {3ED2897F-1A8A-4106-89D2-4D342860D480}.Release|x86.ActiveCfg = Release|Any CPU
{3ED2897F-1A8A-4106-89D2-4D342860D480}.Release|Debug.Build.0 = Release|Any CPU {3ED2897F-1A8A-4106-89D2-4D342860D480}.Release|Debug.Build.0 = Release|Any CPU
{3ED2897F-1A8A-4106-89D2-4D342860D480}.Release|Debug.ActiveCfg = Release|Any CPU {3ED2897F-1A8A-4106-89D2-4D342860D480}.Release|Debug.ActiveCfg = Release|Any CPU
{53DCA265-3C3C-42F9-B647-F72BA678122B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{53DCA265-3C3C-42F9-B647-F72BA678122B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{53DCA265-3C3C-42F9-B647-F72BA678122B}.Debug|Win32.Build.0 = Debug|Any CPU
{53DCA265-3C3C-42F9-B647-F72BA678122B}.Debug|Win32.ActiveCfg = Debug|Any CPU
{53DCA265-3C3C-42F9-B647-F72BA678122B}.Debug|x86.Build.0 = Debug|Any CPU
{53DCA265-3C3C-42F9-B647-F72BA678122B}.Debug|x86.ActiveCfg = Debug|Any CPU
{53DCA265-3C3C-42F9-B647-F72BA678122B}.Debug|Debug.Build.0 = Debug|Any CPU
{53DCA265-3C3C-42F9-B647-F72BA678122B}.Debug|Debug.ActiveCfg = Debug|Any CPU
{53DCA265-3C3C-42F9-B647-F72BA678122B}.Release|Any CPU.Build.0 = Release|Any CPU
{53DCA265-3C3C-42F9-B647-F72BA678122B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{53DCA265-3C3C-42F9-B647-F72BA678122B}.Release|Win32.Build.0 = Release|Any CPU
{53DCA265-3C3C-42F9-B647-F72BA678122B}.Release|Win32.ActiveCfg = Release|Any CPU
{53DCA265-3C3C-42F9-B647-F72BA678122B}.Release|x86.Build.0 = Release|Any CPU
{53DCA265-3C3C-42F9-B647-F72BA678122B}.Release|x86.ActiveCfg = Release|Any CPU
{53DCA265-3C3C-42F9-B647-F72BA678122B}.Release|Debug.Build.0 = Release|Any CPU
{53DCA265-3C3C-42F9-B647-F72BA678122B}.Release|Debug.ActiveCfg = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@ -1238,6 +1259,7 @@ Global
{984CC812-9470-4A13-AFF9-CC44068D666C} = {814DFF39-5324-40BE-90EA-F62F758660B3} {984CC812-9470-4A13-AFF9-CC44068D666C} = {814DFF39-5324-40BE-90EA-F62F758660B3}
{3B2A5653-EC97-4001-BB9B-D90F1AF2C371} = {814DFF39-5324-40BE-90EA-F62F758660B3} {3B2A5653-EC97-4001-BB9B-D90F1AF2C371} = {814DFF39-5324-40BE-90EA-F62F758660B3}
88305E42-C90D-410F-B831-15161E23BAAA = {814DFF39-5324-40BE-90EA-F62F758660B3} 88305E42-C90D-410F-B831-15161E23BAAA = {814DFF39-5324-40BE-90EA-F62F758660B3}
{53DCA265-3C3C-42F9-B647-F72BA678122B} = {814DFF39-5324-40BE-90EA-F62F758660B3}
{1F261725-6318-4434-A1B1-6C70CE4CD324} = {F355E45F-F54F-4B42-8916-9A633A392789} {1F261725-6318-4434-A1B1-6C70CE4CD324} = {F355E45F-F54F-4B42-8916-9A633A392789}
{3EAA45A9-735C-4AC7-A799-947B93EA449D} = {F355E45F-F54F-4B42-8916-9A633A392789} {3EAA45A9-735C-4AC7-A799-947B93EA449D} = {F355E45F-F54F-4B42-8916-9A633A392789}
{08CE9972-283B-44F4-82FA-966F7DFA6B7A} = {F355E45F-F54F-4B42-8916-9A633A392789} {08CE9972-283B-44F4-82FA-966F7DFA6B7A} = {F355E45F-F54F-4B42-8916-9A633A392789}

16
src/AddIns/DisplayBindings/ILSpyAddIn/DebuggerDecompilerService.cs

@ -15,6 +15,13 @@ using Mono.Cecil;
namespace ICSharpCode.ILSpyAddIn namespace ICSharpCode.ILSpyAddIn
{ {
// Dummy class to avoid the build errors after updating the ICSharpCode.Decompiler version.
// TODO: get rid of this & fix debugging decompiled files
public class DecompileInformation {
public dynamic LocalVariables;
public dynamic CodeMappings;
}
/// <summary> /// <summary>
/// Stores the decompilation information. /// Stores the decompilation information.
/// </summary> /// </summary>
@ -73,9 +80,10 @@ namespace ICSharpCode.ILSpyAddIn
DecompilerContext context = new DecompilerContext(type.Module); DecompilerContext context = new DecompilerContext(type.Module);
AstBuilder astBuilder = new AstBuilder(context); AstBuilder astBuilder = new AstBuilder(context);
astBuilder.AddType(type); astBuilder.AddType(type);
astBuilder.GenerateCode(new PlainTextOutput()); DebuggerTextOutput output = new DebuggerTextOutput(new PlainTextOutput());
astBuilder.GenerateCode(output);
int token = type.MetadataToken.ToInt32(); /*int token = type.MetadataToken.ToInt32();
var info = new DecompileInformation { var info = new DecompileInformation {
CodeMappings = astBuilder.CodeMappings, CodeMappings = astBuilder.CodeMappings,
LocalVariables = astBuilder.LocalVariables, LocalVariables = astBuilder.LocalVariables,
@ -83,7 +91,7 @@ namespace ICSharpCode.ILSpyAddIn
}; };
// save the data // save the data
DebugInformation.AddOrUpdate(token, info, (k, v) => info); DebugInformation.AddOrUpdate(token, info, (k, v) => info);*/
} catch { } catch {
return; return;
} }
@ -104,7 +112,7 @@ namespace ICSharpCode.ILSpyAddIn
if (instruction == null) if (instruction == null)
continue; continue;
ilRanges = new [] { instruction.ILInstructionOffset.From, instruction.ILInstructionOffset.To }; ilRanges = new int[] { instruction.ILInstructionOffset.From, instruction.ILInstructionOffset.To };
memberToken = instruction.MemberMapping.MetadataToken; memberToken = instruction.MemberMapping.MetadataToken;
return true; return true;
} }

76
src/AddIns/DisplayBindings/ILSpyAddIn/DebuggerTextOutput.cs

@ -0,0 +1,76 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using ICSharpCode.Decompiler;
namespace ICSharpCode.ILSpyAddIn
{
sealed class DebuggerTextOutput : ITextOutput
{
readonly ITextOutput output;
public readonly List<MemberMapping> DebuggerMemberMappings = new List<MemberMapping>();
public DebuggerTextOutput(ITextOutput output)
{
this.output = output;
}
public ICSharpCode.NRefactory.TextLocation Location {
get { return output.Location; }
}
public void Indent()
{
output.Indent();
}
public void Unindent()
{
output.Unindent();
}
public void Write(char ch)
{
output.Write(ch);
}
public void Write(string text)
{
output.Write(text);
}
public void WriteLine()
{
output.WriteLine();
}
public void WriteDefinition(string text, object definition, bool isLocal)
{
output.WriteDefinition(text, definition, isLocal);
}
public void WriteReference(string text, object reference, bool isLocal)
{
output.WriteReference(text, reference, isLocal);
}
public void AddDebuggerMemberMapping(MemberMapping memberMapping)
{
DebuggerMemberMappings.Add(memberMapping);
output.AddDebuggerMemberMapping(memberMapping);
}
public void MarkFoldStart(string collapsedText, bool defaultCollapsed)
{
output.MarkFoldStart(collapsedText, defaultCollapsed);
}
public void MarkFoldEnd()
{
output.MarkFoldEnd();
}
}
}

7
src/AddIns/DisplayBindings/ILSpyAddIn/ILSpyAddIn.csproj

@ -40,6 +40,7 @@
</PropertyGroup> </PropertyGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
<ItemGroup> <ItemGroup>
<Reference Include="Microsoft.CSharp" />
<Reference Include="PresentationCore"> <Reference Include="PresentationCore">
<RequiredTargetFramework>3.0</RequiredTargetFramework> <RequiredTargetFramework>3.0</RequiredTargetFramework>
</Reference> </Reference>
@ -64,6 +65,7 @@
<Link>Properties\GlobalAssemblyInfo.cs</Link> <Link>Properties\GlobalAssemblyInfo.cs</Link>
</Compile> </Compile>
<Compile Include="DebuggerDecompilerService.cs" /> <Compile Include="DebuggerDecompilerService.cs" />
<Compile Include="DebuggerTextOutput.cs" />
<Compile Include="LaunchILSpy\ILSpyAssemblyResolver.cs" /> <Compile Include="LaunchILSpy\ILSpyAssemblyResolver.cs" />
<Compile Include="NavigateToDecompiledEntityService.cs" /> <Compile Include="NavigateToDecompiledEntityService.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
@ -97,6 +99,10 @@
<Name>Mono.Cecil</Name> <Name>Mono.Cecil</Name>
<Private>False</Private> <Private>False</Private>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\..\..\Libraries\NewNRefactory\ICSharpCode.NRefactory.CSharp\ICSharpCode.NRefactory.CSharp.csproj">
<Project>{53DCA265-3C3C-42F9-B647-F72BA678122B}</Project>
<Name>ICSharpCode.NRefactory.CSharp</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\Libraries\NewNRefactory\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj"> <ProjectReference Include="..\..\..\Libraries\NewNRefactory\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj">
<Project>{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}</Project> <Project>{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}</Project>
<Name>ICSharpCode.NRefactory</Name> <Name>ICSharpCode.NRefactory</Name>
@ -104,6 +110,7 @@
<ProjectReference Include="..\..\..\Libraries\NRefactory\Project\NRefactory.csproj"> <ProjectReference Include="..\..\..\Libraries\NRefactory\Project\NRefactory.csproj">
<Project>{3A9AE6AA-BC07-4A2F-972C-581E3AE2F195}</Project> <Project>{3A9AE6AA-BC07-4A2F-972C-581E3AE2F195}</Project>
<Name>NRefactory</Name> <Name>NRefactory</Name>
<Private>False</Private>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\..\..\Main\Base\Project\ICSharpCode.SharpDevelop.csproj"> <ProjectReference Include="..\..\..\Main\Base\Project\ICSharpCode.SharpDevelop.csproj">
<Project>{2748AD25-9C63-4E12-877B-4DCE96FBED54}</Project> <Project>{2748AD25-9C63-4E12-877B-4DCE96FBED54}</Project>

13
src/AddIns/DisplayBindings/ILSpyAddIn/Properties/AssemblyInfo.cs

@ -9,14 +9,5 @@ using System.Reflection;
// change them to the information which is associated with the assembly // change them to the information which is associated with the assembly
// you compile. // you compile.
[assembly: AssemblyTitle("Reflector AddIn")] [assembly: AssemblyTitle("ILSpy AddIn")]
[assembly: AssemblyDescription("Reflector AddIn for SharpDevelop")] [assembly: AssemblyDescription("ILSpy AddIn for SharpDevelop")]
#if DEBUG
[assembly: AssemblyConfiguration("Debug")]
#else
[assembly: AssemblyConfiguration("Release")]
#endif
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]

2
src/AddIns/DisplayBindings/ILSpyAddIn/ViewContent/DecompiledViewContent.cs

@ -175,6 +175,7 @@ namespace ICSharpCode.ILSpyAddIn
// save decompilation data // save decompilation data
decompiledType = typeDefinition; decompiledType = typeDefinition;
/*
int token = decompiledType.MetadataToken.ToInt32(); int token = decompiledType.MetadataToken.ToInt32();
var info = new DecompileInformation { var info = new DecompileInformation {
CodeMappings = astBuilder.CodeMappings, CodeMappings = astBuilder.CodeMappings,
@ -184,6 +185,7 @@ namespace ICSharpCode.ILSpyAddIn
// save the data // save the data
DebuggerDecompilerService.DebugInformation.AddOrUpdate(token, info, (k, v) => info); DebuggerDecompilerService.DebugInformation.AddOrUpdate(token, info, (k, v) => info);
*/
} }
void OnDecompilationFinished(StringWriter output) void OnDecompilationFinished(StringWriter output)

50
src/Libraries/ICSharpCode.Decompiler/Ast/Annotations.cs

@ -0,0 +1,50 @@
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 TypeInformation(TypeReference inferredType)
{
this.InferredType = inferredType;
}
}
public class LdTokenAnnotation {}
/// <summary>
/// Annotation that is applied to the body expression of an Expression.Lambda() call.
/// </summary>
public class ParameterDeclarationAnnotation
{
public readonly List<ParameterDeclaration> Parameters = new List<ParameterDeclaration>();
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));
}
}
}
/// <summary>
/// Annotation that is applied to a LambdaExpression that was produced by an expression tree.
/// </summary>
public class ExpressionTreeLambdaAnnotation
{
}
}

81
src/Libraries/ICSharpCode.Decompiler/Ast/AstBuilder.cs

@ -38,7 +38,6 @@ using Mono.Cecil.Cil;
namespace ICSharpCode.Decompiler.Ast namespace ICSharpCode.Decompiler.Ast
{ {
using Ast = ICSharpCode.NRefactory.CSharp; using Ast = ICSharpCode.NRefactory.CSharp;
using ClassType = ICSharpCode.NRefactory.TypeSystem.ClassType;
using VarianceModifier = ICSharpCode.NRefactory.TypeSystem.VarianceModifier; using VarianceModifier = ICSharpCode.NRefactory.TypeSystem.VarianceModifier;
[Flags] [Flags]
@ -50,7 +49,7 @@ namespace ICSharpCode.Decompiler.Ast
DoNotUsePrimitiveTypeNames = 4 DoNotUsePrimitiveTypeNames = 4
} }
public class AstBuilder : BaseCodeMappings public class AstBuilder
{ {
DecompilerContext context; DecompilerContext context;
CompilationUnit astCompileUnit = new CompilationUnit(); CompilationUnit astCompileUnit = new CompilationUnit();
@ -63,10 +62,6 @@ namespace ICSharpCode.Decompiler.Ast
throw new ArgumentNullException("context"); throw new ArgumentNullException("context");
this.context = context; this.context = context;
this.DecompileMethodBodies = true; this.DecompileMethodBodies = true;
this.LocalVariables = new ConcurrentDictionary<int, IEnumerable<ILVariable>>();
this.CodeMappings = new Dictionary<int, List<MemberMapping>>();
this.DecompiledMemberReferences = new Dictionary<int, MemberReference>();
} }
public static bool MemberIsHidden(MemberReference member, DecompilerSettings settings) public static bool MemberIsHidden(MemberReference member, DecompilerSettings settings)
@ -141,7 +136,7 @@ namespace ICSharpCode.Decompiler.Ast
formattingPolicy.SpaceBeforeMethodDeclarationParentheses = false; formattingPolicy.SpaceBeforeMethodDeclarationParentheses = false;
formattingPolicy.SpaceBeforeConstructorDeclarationParentheses = false; formattingPolicy.SpaceBeforeConstructorDeclarationParentheses = false;
formattingPolicy.SpaceBeforeDelegateDeclarationParentheses = false; formattingPolicy.SpaceBeforeDelegateDeclarationParentheses = false;
astCompileUnit.AcceptVisitor(new OutputVisitor(outputFormatter, formattingPolicy), null); astCompileUnit.AcceptVisitor(new CSharpOutputVisitor(outputFormatter, formattingPolicy), null);
} }
public void AddAssembly(AssemblyDefinition assemblyDefinition, bool onlyAssemblyLevel = false) public void AddAssembly(AssemblyDefinition assemblyDefinition, bool onlyAssemblyLevel = false)
@ -730,11 +725,7 @@ namespace ICSharpCode.Decompiler.Ast
AttributedNode CreateMethod(MethodDefinition methodDef) AttributedNode CreateMethod(MethodDefinition methodDef)
{ {
// Create mapping - used in debugger MethodDeclaration astMethod = new MethodDeclaration();
CreateCodeMappings(methodDef.MetadataToken.ToInt32(), methodDef);
MemberMapping methodMapping = methodDef.CreateCodeMapping(this.CodeMappings[methodDef.MetadataToken.ToInt32()]);
MethodDeclaration astMethod = new MethodDeclaration().WithAnnotation(methodMapping);
astMethod.AddAnnotation(methodDef); astMethod.AddAnnotation(methodDef);
astMethod.ReturnType = ConvertType(methodDef.ReturnType, methodDef.MethodReturnType); astMethod.ReturnType = ConvertType(methodDef.ReturnType, methodDef.MethodReturnType);
astMethod.Name = CleanName(methodDef.Name); astMethod.Name = CleanName(methodDef.Name);
@ -743,12 +734,12 @@ namespace ICSharpCode.Decompiler.Ast
// constraints for override and explicit interface implementation methods are inherited from the base method, so they cannot be specified directly // 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.IsVirtual || (methodDef.IsNewSlot && !methodDef.IsPrivate)) astMethod.Constraints.AddRange(MakeConstraints(methodDef.GenericParameters));
if (!methodDef.DeclaringType.IsInterface) { if (!methodDef.DeclaringType.IsInterface) {
if (!methodDef.HasOverrides) { if (IsExplicitInterfaceImplementation(methodDef)) {
astMethod.PrivateImplementationType = ConvertType(methodDef.Overrides.First().DeclaringType);
} else {
astMethod.Modifiers = ConvertModifiers(methodDef); astMethod.Modifiers = ConvertModifiers(methodDef);
if (methodDef.IsVirtual == methodDef.IsNewSlot) if (methodDef.IsVirtual == methodDef.IsNewSlot)
SetNewModifier(astMethod); SetNewModifier(astMethod);
} else {
astMethod.PrivateImplementationType = ConvertType(methodDef.Overrides.First().DeclaringType);
} }
astMethod.Body = CreateMethodBody(methodDef, astMethod.Parameters); astMethod.Body = CreateMethodBody(methodDef, astMethod.Parameters);
} }
@ -778,6 +769,11 @@ namespace ICSharpCode.Decompiler.Ast
} }
return astMethod; return astMethod;
} }
bool IsExplicitInterfaceImplementation(MethodDefinition methodDef)
{
return methodDef.HasOverrides && methodDef.IsPrivate;
}
IEnumerable<TypeParameterDeclaration> MakeTypeParameters(IEnumerable<GenericParameter> genericParameters) IEnumerable<TypeParameterDeclaration> MakeTypeParameters(IEnumerable<GenericParameter> genericParameters)
{ {
@ -819,10 +815,6 @@ namespace ICSharpCode.Decompiler.Ast
ConstructorDeclaration CreateConstructor(MethodDefinition methodDef) ConstructorDeclaration CreateConstructor(MethodDefinition methodDef)
{ {
// Create mapping - used in debugger
CreateCodeMappings(methodDef.MetadataToken.ToInt32(), methodDef);
MemberMapping methodMapping = methodDef.CreateCodeMapping(this.CodeMappings[methodDef.MetadataToken.ToInt32()]);
ConstructorDeclaration astMethod = new ConstructorDeclaration(); ConstructorDeclaration astMethod = new ConstructorDeclaration();
astMethod.AddAnnotation(methodDef); astMethod.AddAnnotation(methodDef);
astMethod.Modifiers = ConvertModifiers(methodDef); astMethod.Modifiers = ConvertModifiers(methodDef);
@ -834,7 +826,6 @@ namespace ICSharpCode.Decompiler.Ast
astMethod.Parameters.AddRange(MakeParameters(methodDef)); astMethod.Parameters.AddRange(MakeParameters(methodDef));
astMethod.Body = CreateMethodBody(methodDef, astMethod.Parameters); astMethod.Body = CreateMethodBody(methodDef, astMethod.Parameters);
ConvertAttributes(astMethod, methodDef); ConvertAttributes(astMethod, methodDef);
astMethod.WithAnnotation(methodMapping);
if (methodDef.IsStatic && methodDef.DeclaringType.IsBeforeFieldInit && !astMethod.Body.IsNull) { if (methodDef.IsStatic && methodDef.DeclaringType.IsBeforeFieldInit && !astMethod.Body.IsNull) {
astMethod.Body.InsertChildAfter(null, new Comment(" Note: this type is marked as 'beforefieldinit'."), AstNode.Roles.Comment); astMethod.Body.InsertChildAfter(null, new Comment(" Note: this type is marked as 'beforefieldinit'."), AstNode.Roles.Comment);
} }
@ -861,7 +852,7 @@ namespace ICSharpCode.Decompiler.Ast
var accessor = propDef.GetMethod ?? propDef.SetMethod; var accessor = propDef.GetMethod ?? propDef.SetMethod;
Modifiers getterModifiers = Modifiers.None; Modifiers getterModifiers = Modifiers.None;
Modifiers setterModifiers = Modifiers.None; Modifiers setterModifiers = Modifiers.None;
if (accessor.HasOverrides) { if (IsExplicitInterfaceImplementation(accessor)) {
astProp.PrivateImplementationType = ConvertType(accessor.Overrides.First().DeclaringType); astProp.PrivateImplementationType = ConvertType(accessor.Overrides.First().DeclaringType);
} else if (!propDef.DeclaringType.IsInterface) { } else if (!propDef.DeclaringType.IsInterface) {
getterModifiers = ConvertModifiers(propDef.GetMethod); getterModifiers = ConvertModifiers(propDef.GetMethod);
@ -887,10 +878,6 @@ namespace ICSharpCode.Decompiler.Ast
astProp.ReturnType = ConvertType(propDef.PropertyType, propDef); astProp.ReturnType = ConvertType(propDef.PropertyType, propDef);
if (propDef.GetMethod != null) { if (propDef.GetMethod != null) {
// Create mapping - used in debugger
CreateCodeMappings(propDef.GetMethod.MetadataToken.ToInt32(), propDef);
MemberMapping methodMapping = propDef.GetMethod.CreateCodeMapping(this.CodeMappings[propDef.GetMethod.MetadataToken.ToInt32()], propDef);
astProp.Getter = new Accessor(); astProp.Getter = new Accessor();
astProp.Getter.Body = CreateMethodBody(propDef.GetMethod); astProp.Getter.Body = CreateMethodBody(propDef.GetMethod);
astProp.Getter.AddAnnotation(propDef.GetMethod); astProp.Getter.AddAnnotation(propDef.GetMethod);
@ -898,14 +885,8 @@ namespace ICSharpCode.Decompiler.Ast
if ((getterModifiers & Modifiers.VisibilityMask) != (astProp.Modifiers & Modifiers.VisibilityMask)) if ((getterModifiers & Modifiers.VisibilityMask) != (astProp.Modifiers & Modifiers.VisibilityMask))
astProp.Getter.Modifiers = getterModifiers & Modifiers.VisibilityMask; astProp.Getter.Modifiers = getterModifiers & Modifiers.VisibilityMask;
astProp.Getter.WithAnnotation(methodMapping);
} }
if (propDef.SetMethod != null) { if (propDef.SetMethod != null) {
// Create mapping - used in debugger
CreateCodeMappings(propDef.SetMethod.MetadataToken.ToInt32(), propDef);
MemberMapping methodMapping = propDef.SetMethod.CreateCodeMapping(this.CodeMappings[propDef.SetMethod.MetadataToken.ToInt32()], propDef);
astProp.Setter = new Accessor(); astProp.Setter = new Accessor();
astProp.Setter.Body = CreateMethodBody(propDef.SetMethod); astProp.Setter.Body = CreateMethodBody(propDef.SetMethod);
astProp.Setter.AddAnnotation(propDef.SetMethod); astProp.Setter.AddAnnotation(propDef.SetMethod);
@ -920,8 +901,6 @@ namespace ICSharpCode.Decompiler.Ast
if ((setterModifiers & Modifiers.VisibilityMask) != (astProp.Modifiers & Modifiers.VisibilityMask)) if ((setterModifiers & Modifiers.VisibilityMask) != (astProp.Modifiers & Modifiers.VisibilityMask))
astProp.Setter.Modifiers = setterModifiers & Modifiers.VisibilityMask; astProp.Setter.Modifiers = setterModifiers & Modifiers.VisibilityMask;
astProp.Setter.WithAnnotation(methodMapping);
} }
ConvertCustomAttributes(astProp, propDef); ConvertCustomAttributes(astProp, propDef);
@ -967,34 +946,22 @@ namespace ICSharpCode.Decompiler.Ast
astEvent.AddAnnotation(eventDef); astEvent.AddAnnotation(eventDef);
astEvent.Name = CleanName(eventDef.Name); astEvent.Name = CleanName(eventDef.Name);
astEvent.ReturnType = ConvertType(eventDef.EventType, eventDef); astEvent.ReturnType = ConvertType(eventDef.EventType, eventDef);
if (eventDef.AddMethod == null || !eventDef.AddMethod.HasOverrides) if (eventDef.AddMethod == null || !IsExplicitInterfaceImplementation(eventDef.AddMethod))
astEvent.Modifiers = ConvertModifiers(eventDef.AddMethod); astEvent.Modifiers = ConvertModifiers(eventDef.AddMethod);
else else
astEvent.PrivateImplementationType = ConvertType(eventDef.AddMethod.Overrides.First().DeclaringType); astEvent.PrivateImplementationType = ConvertType(eventDef.AddMethod.Overrides.First().DeclaringType);
if (eventDef.AddMethod != null) { if (eventDef.AddMethod != null) {
// Create mapping - used in debugger
CreateCodeMappings(eventDef.AddMethod.MetadataToken.ToInt32(), eventDef);
MemberMapping methodMapping = eventDef.AddMethod.CreateCodeMapping(this.CodeMappings[eventDef.AddMethod.MetadataToken.ToInt32()], eventDef);
astEvent.AddAccessor = new Accessor { astEvent.AddAccessor = new Accessor {
Body = CreateMethodBody(eventDef.AddMethod) Body = CreateMethodBody(eventDef.AddMethod)
}.WithAnnotation(eventDef.AddMethod); }.WithAnnotation(eventDef.AddMethod);
ConvertAttributes(astEvent.AddAccessor, eventDef.AddMethod); ConvertAttributes(astEvent.AddAccessor, eventDef.AddMethod);
astEvent.AddAccessor.WithAnnotation(methodMapping);
} }
if (eventDef.RemoveMethod != null) { if (eventDef.RemoveMethod != null) {
// Create mapping - used in debugger
CreateCodeMappings(eventDef.RemoveMethod.MetadataToken.ToInt32(), eventDef);
MemberMapping methodMapping = eventDef.RemoveMethod.CreateCodeMapping(this.CodeMappings[eventDef.RemoveMethod.MetadataToken.ToInt32()], eventDef);
astEvent.RemoveAccessor = new Accessor { astEvent.RemoveAccessor = new Accessor {
Body = CreateMethodBody(eventDef.RemoveMethod) Body = CreateMethodBody(eventDef.RemoveMethod)
}.WithAnnotation(eventDef.RemoveMethod); }.WithAnnotation(eventDef.RemoveMethod);
ConvertAttributes(astEvent.RemoveAccessor, eventDef.RemoveMethod); ConvertAttributes(astEvent.RemoveAccessor, eventDef.RemoveMethod);
astEvent.RemoveAccessor.WithAnnotation(methodMapping);
} }
MethodDefinition accessor = eventDef.AddMethod ?? eventDef.RemoveMethod; MethodDefinition accessor = eventDef.AddMethod ?? eventDef.RemoveMethod;
if (accessor.IsVirtual == accessor.IsNewSlot) { if (accessor.IsVirtual == accessor.IsNewSlot) {
@ -1009,15 +976,13 @@ namespace ICSharpCode.Decompiler.Ast
BlockStatement CreateMethodBody(MethodDefinition method, IEnumerable<ParameterDeclaration> parameters = null) BlockStatement CreateMethodBody(MethodDefinition method, IEnumerable<ParameterDeclaration> parameters = null)
{ {
if (DecompileMethodBodies) if (DecompileMethodBodies)
return AstMethodBodyBuilder.CreateMethodBody(method, context, parameters, LocalVariables); return AstMethodBodyBuilder.CreateMethodBody(method, context, parameters);
else else
return null; return null;
} }
FieldDeclaration CreateField(FieldDefinition fieldDef) FieldDeclaration CreateField(FieldDefinition fieldDef)
{ {
this.DecompiledMemberReferences.Add(fieldDef.MetadataToken.ToInt32(), fieldDef);
FieldDeclaration astField = new FieldDeclaration(); FieldDeclaration astField = new FieldDeclaration();
astField.AddAnnotation(fieldDef); astField.AddAnnotation(fieldDef);
VariableInitializer initializer = new VariableInitializer(CleanName(fieldDef.Name)); VariableInitializer initializer = new VariableInitializer(CleanName(fieldDef.Name));
@ -1112,6 +1077,11 @@ namespace ICSharpCode.Decompiler.Ast
attributedNode.Attributes.Add(new AttributeSection(CreateNonCustomAttribute(typeof(SerializableAttribute)))); attributedNode.Attributes.Add(new AttributeSection(CreateNonCustomAttribute(typeof(SerializableAttribute))));
#endregion #endregion
#region ComImportAttribute
if (typeDefinition.IsImport)
attributedNode.Attributes.Add(new AttributeSection(CreateNonCustomAttribute(typeof(ComImportAttribute))));
#endregion
#region StructLayoutAttribute #region StructLayoutAttribute
LayoutKind layoutKind = LayoutKind.Auto; LayoutKind layoutKind = LayoutKind.Auto;
switch (typeDefinition.Attributes & TypeAttributes.LayoutMask) { switch (typeDefinition.Attributes & TypeAttributes.LayoutMask) {
@ -1347,7 +1317,7 @@ namespace ICSharpCode.Decompiler.Ast
{ {
if (customAttributeProvider.HasCustomAttributes) { if (customAttributeProvider.HasCustomAttributes) {
var attributes = new List<ICSharpCode.NRefactory.CSharp.Attribute>(); var attributes = new List<ICSharpCode.NRefactory.CSharp.Attribute>();
foreach (var customAttribute in customAttributeProvider.CustomAttributes) { foreach (var customAttribute in customAttributeProvider.CustomAttributes.OrderBy(a => a.AttributeType.FullName)) {
if (customAttribute.AttributeType.Name == "ExtensionAttribute" && customAttribute.AttributeType.Namespace == "System.Runtime.CompilerServices") { if (customAttribute.AttributeType.Name == "ExtensionAttribute" && customAttribute.AttributeType.Namespace == "System.Runtime.CompilerServices") {
// don't show the ExtensionAttribute (it's converted to the 'this' modifier) // don't show the ExtensionAttribute (it's converted to the 'this' modifier)
continue; continue;
@ -1417,8 +1387,8 @@ namespace ICSharpCode.Decompiler.Ast
if (!secDeclProvider.HasSecurityDeclarations) if (!secDeclProvider.HasSecurityDeclarations)
return; return;
var attributes = new List<ICSharpCode.NRefactory.CSharp.Attribute>(); var attributes = new List<ICSharpCode.NRefactory.CSharp.Attribute>();
foreach (var secDecl in secDeclProvider.SecurityDeclarations) { foreach (var secDecl in secDeclProvider.SecurityDeclarations.OrderBy(d => d.Action)) {
foreach (var secAttribute in secDecl.SecurityAttributes) { foreach (var secAttribute in secDecl.SecurityAttributes.OrderBy(a => a.AttributeType.FullName)) {
var attribute = new ICSharpCode.NRefactory.CSharp.Attribute(); var attribute = new ICSharpCode.NRefactory.CSharp.Attribute();
attribute.AddAnnotation(secAttribute); attribute.AddAnnotation(secAttribute);
attribute.Type = ConvertType(secAttribute.AttributeType); attribute.Type = ConvertType(secAttribute.AttributeType);
@ -1481,6 +1451,7 @@ namespace ICSharpCode.Decompiler.Ast
ArrayType arrayType = argument.Type as ArrayType; ArrayType arrayType = argument.Type as ArrayType;
return new ArrayCreateExpression { return new ArrayCreateExpression {
Type = ConvertType(arrayType != null ? arrayType.ElementType : argument.Type), Type = ConvertType(arrayType != null ? arrayType.ElementType : argument.Type),
AdditionalArraySpecifiers = { new ArraySpecifier() },
Initializer = arrayInit Initializer = arrayInit
}; };
} else if (argument.Value is CustomAttributeArgument) { } else if (argument.Value is CustomAttributeArgument) {
@ -1663,11 +1634,5 @@ namespace ICSharpCode.Decompiler.Ast
&& (condition == null || condition(m)) && (condition == null || condition(m))
&& TypesHierarchyHelpers.IsVisibleFromDerived(m, derived.DeclaringType)); && TypesHierarchyHelpers.IsVisibleFromDerived(m, derived.DeclaringType));
} }
/// <summary>
/// Gets the local variables for the current decompiled type, method, etc.
/// <remarks>The key is the metadata token.</remarks>
/// </summary>
public ConcurrentDictionary<int, IEnumerable<ILVariable>> LocalVariables { get; private set; }
} }
} }

182
src/Libraries/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -50,16 +50,11 @@ namespace ICSharpCode.Decompiler.Ast
/// <param name="context">Decompilation context.</param> /// <param name="context">Decompilation context.</param>
/// <param name="parameters">Parameter declarations of the method being decompiled. /// <param name="parameters">Parameter declarations of the method being decompiled.
/// These are used to update the parameter names when the decompiler generates names for the parameters.</param> /// These are used to update the parameter names when the decompiler generates names for the parameters.</param>
/// <param name="localVariables">Local variables storage that will be filled/updated with the local variables.</param>
/// <returns>Block for the method body</returns> /// <returns>Block for the method body</returns>
public static BlockStatement CreateMethodBody(MethodDefinition methodDef, public static BlockStatement CreateMethodBody(MethodDefinition methodDef,
DecompilerContext context, DecompilerContext context,
IEnumerable<ParameterDeclaration> parameters = null, IEnumerable<ParameterDeclaration> parameters = null)
ConcurrentDictionary<int, IEnumerable<ILVariable>> localVariables = null)
{ {
if (localVariables == null)
localVariables = new ConcurrentDictionary<int, IEnumerable<ILVariable>>();
MethodDefinition oldCurrentMethod = context.CurrentMethod; MethodDefinition oldCurrentMethod = context.CurrentMethod;
Debug.Assert(oldCurrentMethod == null || oldCurrentMethod == methodDef); Debug.Assert(oldCurrentMethod == null || oldCurrentMethod == methodDef);
context.CurrentMethod = methodDef; context.CurrentMethod = methodDef;
@ -69,10 +64,10 @@ namespace ICSharpCode.Decompiler.Ast
builder.context = context; builder.context = context;
builder.typeSystem = methodDef.Module.TypeSystem; builder.typeSystem = methodDef.Module.TypeSystem;
if (Debugger.IsAttached) { if (Debugger.IsAttached) {
return builder.CreateMethodBody(parameters, localVariables); return builder.CreateMethodBody(parameters);
} else { } else {
try { try {
return builder.CreateMethodBody(parameters, localVariables); return builder.CreateMethodBody(parameters);
} catch (OperationCanceledException) { } catch (OperationCanceledException) {
throw; throw;
} catch (Exception ex) { } catch (Exception ex) {
@ -84,28 +79,26 @@ namespace ICSharpCode.Decompiler.Ast
} }
} }
public BlockStatement CreateMethodBody(IEnumerable<ParameterDeclaration> parameters, public BlockStatement CreateMethodBody(IEnumerable<ParameterDeclaration> parameters)
ConcurrentDictionary<int, IEnumerable<ILVariable>> localVariables)
{ {
if (methodDef.Body == null) return null; if (methodDef.Body == null) {
return null;
if (localVariables == null) }
throw new ArgumentException("localVariables must be instantiated");
context.CancellationToken.ThrowIfCancellationRequested(); context.CancellationToken.ThrowIfCancellationRequested();
ILBlock ilMethod = new ILBlock(); ILBlock ilMethod = new ILBlock();
ILAstBuilder astBuilder = new ILAstBuilder(); ILAstBuilder astBuilder = new ILAstBuilder();
ilMethod.Body = astBuilder.Build(methodDef, true); ilMethod.Body = astBuilder.Build(methodDef, true, context);
context.CancellationToken.ThrowIfCancellationRequested(); context.CancellationToken.ThrowIfCancellationRequested();
ILAstOptimizer bodyGraph = new ILAstOptimizer(); ILAstOptimizer bodyGraph = new ILAstOptimizer();
bodyGraph.Optimize(context, ilMethod); bodyGraph.Optimize(context, ilMethod);
context.CancellationToken.ThrowIfCancellationRequested(); context.CancellationToken.ThrowIfCancellationRequested();
var allVariables = ilMethod.GetSelfAndChildrenRecursive<ILExpression>().Select(e => e.Operand as ILVariable) var localVariables = ilMethod.GetSelfAndChildrenRecursive<ILExpression>().Select(e => e.Operand as ILVariable)
.Where(v => v != null && !v.IsParameter).Distinct(); .Where(v => v != null && !v.IsParameter).Distinct();
Debug.Assert(context.CurrentMethod == methodDef); Debug.Assert(context.CurrentMethod == methodDef);
NameVariables.AssignNamesToVariables(context, astBuilder.Parameters, allVariables, ilMethod); NameVariables.AssignNamesToVariables(context, astBuilder.Parameters, localVariables, ilMethod);
if (parameters != null) { if (parameters != null) {
foreach (var pair in (from p in parameters foreach (var pair in (from p in parameters
@ -128,12 +121,11 @@ namespace ICSharpCode.Decompiler.Ast
else else
type = AstBuilder.ConvertType(v.Type); type = AstBuilder.ConvertType(v.Type);
var newVarDecl = new VariableDeclarationStatement(type, v.Name); var newVarDecl = new VariableDeclarationStatement(type, v.Name);
newVarDecl.Variables.Single().AddAnnotation(v);
astBlock.Statements.InsertBefore(insertionPoint, newVarDecl); astBlock.Statements.InsertBefore(insertionPoint, newVarDecl);
} }
// store the variables - used for debugger astBlock.AddAnnotation(new MemberMapping(methodDef) { LocalVariables = localVariables });
int token = methodDef.MetadataToken.ToInt32();
localVariables.AddOrUpdate(token, allVariables, (key, oldValue) => allVariables);
return astBlock; return astBlock;
} }
@ -210,7 +202,7 @@ namespace ICSharpCode.Decompiler.Ast
Type = AstBuilder.ConvertType(catchClause.ExceptionType), Type = AstBuilder.ConvertType(catchClause.ExceptionType),
VariableName = catchClause.ExceptionVariable == null ? null : catchClause.ExceptionVariable.Name, VariableName = catchClause.ExceptionVariable == null ? null : catchClause.ExceptionVariable.Name,
Body = TransformBlock(catchClause) Body = TransformBlock(catchClause)
}); }.WithAnnotation(catchClause.ExceptionVariable));
} }
} }
if (tryCatchNode.FinallyBlock != null) if (tryCatchNode.FinallyBlock != null)
@ -258,6 +250,9 @@ namespace ICSharpCode.Decompiler.Ast
else else
result = node; result = node;
if (result != null)
result = result.WithAnnotation(new TypeInformation(expr.InferredType));
if (result != null) if (result != null)
return result.WithAnnotation(ilRanges); return result.WithAnnotation(ilRanges);
@ -375,9 +370,6 @@ namespace ICSharpCode.Decompiler.Ast
// change "new (int[,])[10] to new int[10][,]" // change "new (int[,])[10] to new int[10][,]"
ct.ArraySpecifiers.MoveTo(ace.AdditionalArraySpecifiers); ct.ArraySpecifiers.MoveTo(ace.AdditionalArraySpecifiers);
ace.Initializer = new ArrayInitializerExpression(); ace.Initializer = new ArrayInitializerExpression();
var first = ace.AdditionalArraySpecifiers.First();
first.Remove();
ace.Arguments.AddRange(Enumerable.Repeat(0, first.Dimensions).Select(i => new EmptyExpression()));
} }
var newArgs = new List<Expression>(); var newArgs = new List<Expression>();
foreach (var arrayDimension in arrayType.Dimensions.Skip(1).Reverse()) foreach (var arrayDimension in arrayType.Dimensions.Skip(1).Reverse())
@ -397,7 +389,7 @@ namespace ICSharpCode.Decompiler.Ast
ace.Initializer.Elements.AddRange(args); ace.Initializer.Elements.AddRange(args);
return ace; return ace;
} }
case ILCode.Ldlen: return arg1.Member("Length"); case ILCode.Ldlen: return arg1.Member("Length");
case ILCode.Ldelem_I: case ILCode.Ldelem_I:
case ILCode.Ldelem_I1: case ILCode.Ldelem_I1:
case ILCode.Ldelem_I2: case ILCode.Ldelem_I2:
@ -426,7 +418,13 @@ namespace ICSharpCode.Decompiler.Ast
case ILCode.CompoundAssignment: case ILCode.CompoundAssignment:
{ {
CastExpression cast = arg1 as CastExpression; CastExpression cast = arg1 as CastExpression;
BinaryOperatorExpression boe = (BinaryOperatorExpression)(cast != null ? cast.Expression : arg1); 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 Ast.AssignmentExpression { var assignment = new Ast.AssignmentExpression {
Left = boe.Left.Detach(), Left = boe.Left.Detach(),
Operator = ReplaceMethodCallsWithOperators.GetAssignmentOperatorForBinaryOperator(boe.Operator), Operator = ReplaceMethodCallsWithOperators.GetAssignmentOperatorForBinaryOperator(boe.Operator),
@ -445,17 +443,25 @@ namespace ICSharpCode.Decompiler.Ast
#endregion #endregion
#region Comparison #region Comparison
case ILCode.Ceq: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2); case ILCode.Ceq: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2);
case ILCode.Cne: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, arg2);
case ILCode.Cgt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2); case ILCode.Cgt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2);
case ILCode.Cgt_Un: { case ILCode.Cgt_Un: {
// can also mean Inequality, when used with object references // can also mean Inequality, when used with object references
TypeReference arg1Type = byteCode.Arguments[0].InferredType; TypeReference arg1Type = byteCode.Arguments[0].InferredType;
if (arg1Type != null && !arg1Type.IsValueType) if (arg1Type != null && !arg1Type.IsValueType) goto case ILCode.Cne;
return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, arg2); goto case ILCode.Cgt;
else }
return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2); 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;
goto case ILCode.Cle;
} }
case ILCode.Cle: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2);
case ILCode.Cge_Un:
case ILCode.Cge: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2);
case ILCode.Clt_Un:
case ILCode.Clt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2); case ILCode.Clt: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2);
case ILCode.Clt_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2);
#endregion #endregion
#region Logical #region Logical
case ILCode.LogicNot: return new Ast.UnaryOperatorExpression(UnaryOperatorType.Not, arg1); case ILCode.LogicNot: return new Ast.UnaryOperatorExpression(UnaryOperatorType.Not, arg1);
@ -652,7 +658,26 @@ namespace ICSharpCode.Decompiler.Ast
if (operand is Cecil.TypeReference) { if (operand is Cecil.TypeReference) {
return AstBuilder.CreateTypeOfExpression((TypeReference)operand).Member("TypeHandle"); return AstBuilder.CreateTypeOfExpression((TypeReference)operand).Member("TypeHandle");
} else { } else {
return InlineAssembly(byteCode, args); Expression referencedEntity;
string loadName;
string handleName;
if (operand is Cecil.FieldReference) {
loadName = "fieldof";
handleName = "FieldHandle";
FieldReference fr = (FieldReference)operand;
referencedEntity = AstBuilder.ConvertType(fr.DeclaringType).Member(fr.Name).WithAnnotation(fr);
} else if (operand is Cecil.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.Leave: return new GotoStatement() { Label = ((ILLabel)operand).Name };
case ILCode.Localloc: case ILCode.Localloc:
@ -705,21 +730,25 @@ namespace ICSharpCode.Decompiler.Ast
return ace; return ace;
} }
} }
var oce = new Ast.ObjectCreateExpression();
if (declaringType.IsAnonymousType()) { if (declaringType.IsAnonymousType()) {
MethodDefinition ctor = ((MethodReference)operand).Resolve(); MethodDefinition ctor = ((MethodReference)operand).Resolve();
if (methodDef != null) { if (methodDef != null) {
oce.Initializer = new ArrayInitializerExpression(); AnonymousTypeCreateExpression atce = new AnonymousTypeCreateExpression();
for (int i = 0; i < args.Count; i++) { if (CanInferAnonymousTypePropertyNamesFromArguments(args, ctor.Parameters)) {
oce.Initializer.Elements.Add( atce.Initializers.AddRange(args);
new NamedArgumentExpression { } else {
Identifier = ctor.Parameters[i].Name, for (int i = 0; i < args.Count; i++) {
Expression = args[i] atce.Initializers.Add(
}); new NamedExpression {
Identifier = ctor.Parameters[i].Name,
Expression = args[i]
});
}
} }
return atce;
} }
return oce;
} }
var oce = new Ast.ObjectCreateExpression();
oce.Type = AstBuilder.ConvertType(declaringType); oce.Type = AstBuilder.ConvertType(declaringType);
oce.Arguments.AddRange(args); oce.Arguments.AddRange(args);
return oce.WithAnnotation(operand); return oce.WithAnnotation(operand);
@ -750,7 +779,7 @@ namespace ICSharpCode.Decompiler.Ast
case ILCode.YieldBreak: case ILCode.YieldBreak:
return new Ast.YieldBreakStatement(); return new Ast.YieldBreakStatement();
case ILCode.YieldReturn: case ILCode.YieldReturn:
return new Ast.YieldStatement { Expression = arg1 }; return new Ast.YieldReturnStatement { Expression = arg1 };
case ILCode.InitObject: case ILCode.InitObject:
case ILCode.InitCollection: case ILCode.InitCollection:
{ {
@ -760,7 +789,7 @@ namespace ICSharpCode.Decompiler.Ast
if (m.Success) { if (m.Success) {
MemberReferenceExpression mre = m.Get<MemberReferenceExpression>("left").Single(); MemberReferenceExpression mre = m.Get<MemberReferenceExpression>("left").Single();
initializer.Elements.Add( initializer.Elements.Add(
new NamedArgumentExpression { new NamedExpression {
Identifier = mre.MemberName, Identifier = mre.MemberName,
Expression = m.Get<Expression>("right").Single().Detach() Expression = m.Get<Expression>("right").Single().Detach()
}.CopyAnnotationsFrom(mre)); }.CopyAnnotationsFrom(mre));
@ -797,13 +826,38 @@ namespace ICSharpCode.Decompiler.Ast
} }
case ILCode.InitializedObject: case ILCode.InitializedObject:
return new InitializedObjectExpression(); return new InitializedObjectExpression();
case ILCode.Wrap:
return arg1.WithAnnotation(PushNegation.LiftedOperatorAnnotation);
case ILCode.AddressOf: case ILCode.AddressOf:
return MakeRef(arg1); return MakeRef(arg1);
case ILCode.ExpressionTreeParameterDeclarations:
args[args.Count - 1].AddAnnotation(new ParameterDeclarationAnnotation(byteCode));
return args[args.Count - 1];
case ILCode.NullableOf:
case ILCode.ValueOf: return arg1;
default: default:
throw new Exception("Unknown OpCode: " + byteCode.Code); throw new Exception("Unknown OpCode: " + byteCode.Code);
} }
} }
internal static bool CanInferAnonymousTypePropertyNamesFromArguments(IList<Expression> args, IList<ParameterDefinition> 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( static readonly AstNode objectInitializerPattern = new AssignmentExpression(
new MemberReferenceExpression { new MemberReferenceExpression {
Target = new InitializedObjectExpression() Target = new InitializedObjectExpression()
@ -906,14 +960,21 @@ namespace ICSharpCode.Decompiler.Ast
target = ((DirectionExpression)target).Expression; target = ((DirectionExpression)target).Expression;
target.Remove(); // detach from DirectionExpression target.Remove(); // detach from DirectionExpression
} }
if (cecilMethodDef != null && cecilMethodDef.DeclaringType.IsInterface) {
TypeReference tr = byteCode.Arguments[0].InferredType; if (cecilMethodDef != null) {
if (tr != null) { // convert null.ToLower() to ((string)null).ToLower()
TypeDefinition td = tr.Resolve(); if (target is NullReferenceExpression)
if (td != null && !td.IsInterface) { target = target.CastTo(AstBuilder.ConvertType(cecilMethod.DeclaringType));
// Calling an interface method on a non-interface object:
// we need to introduce an explicit cast if (cecilMethodDef.DeclaringType.IsInterface) {
target = target.CastTo(AstBuilder.ConvertType(cecilMethod.DeclaringType)); 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));
}
} }
} }
} }
@ -949,29 +1010,29 @@ namespace ICSharpCode.Decompiler.Ast
if (cecilMethodDef.IsGetter && methodArgs.Count == 0) { if (cecilMethodDef.IsGetter && methodArgs.Count == 0) {
foreach (var prop in cecilMethodDef.DeclaringType.Properties) { foreach (var prop in cecilMethodDef.DeclaringType.Properties) {
if (prop.GetMethod == cecilMethodDef) if (prop.GetMethod == cecilMethodDef)
return target.Member(prop.Name).WithAnnotation(prop); return target.Member(prop.Name).WithAnnotation(prop).WithAnnotation(cecilMethod);
} }
} else if (cecilMethodDef.IsGetter) { // with parameters } else if (cecilMethodDef.IsGetter) { // with parameters
PropertyDefinition indexer = GetIndexer(cecilMethodDef); PropertyDefinition indexer = GetIndexer(cecilMethodDef);
if (indexer != null) if (indexer != null)
return target.Indexer(methodArgs).WithAnnotation(indexer); return target.Indexer(methodArgs).WithAnnotation(indexer).WithAnnotation(cecilMethod);
} else if (cecilMethodDef.IsSetter && methodArgs.Count == 1) { } else if (cecilMethodDef.IsSetter && methodArgs.Count == 1) {
foreach (var prop in cecilMethodDef.DeclaringType.Properties) { foreach (var prop in cecilMethodDef.DeclaringType.Properties) {
if (prop.SetMethod == cecilMethodDef) if (prop.SetMethod == cecilMethodDef)
return new Ast.AssignmentExpression(target.Member(prop.Name).WithAnnotation(prop), methodArgs[0]); return new Ast.AssignmentExpression(target.Member(prop.Name).WithAnnotation(prop).WithAnnotation(cecilMethod), methodArgs[0]);
} }
} else if (cecilMethodDef.IsSetter && methodArgs.Count > 1) { } else if (cecilMethodDef.IsSetter && methodArgs.Count > 1) {
PropertyDefinition indexer = GetIndexer(cecilMethodDef); PropertyDefinition indexer = GetIndexer(cecilMethodDef);
if (indexer != null) if (indexer != null)
return new AssignmentExpression( return new AssignmentExpression(
target.Indexer(methodArgs.GetRange(0, methodArgs.Count - 1)).WithAnnotation(indexer), target.Indexer(methodArgs.GetRange(0, methodArgs.Count - 1)).WithAnnotation(indexer).WithAnnotation(cecilMethod),
methodArgs[methodArgs.Count - 1] methodArgs[methodArgs.Count - 1]
); );
} else if (cecilMethodDef.IsAddOn && methodArgs.Count == 1) { } else if (cecilMethodDef.IsAddOn && methodArgs.Count == 1) {
foreach (var ev in cecilMethodDef.DeclaringType.Events) { foreach (var ev in cecilMethodDef.DeclaringType.Events) {
if (ev.AddMethod == cecilMethodDef) { if (ev.AddMethod == cecilMethodDef) {
return new Ast.AssignmentExpression { return new Ast.AssignmentExpression {
Left = target.Member(ev.Name).WithAnnotation(ev), Left = target.Member(ev.Name).WithAnnotation(ev).WithAnnotation(cecilMethod),
Operator = AssignmentOperatorType.Add, Operator = AssignmentOperatorType.Add,
Right = methodArgs[0] Right = methodArgs[0]
}; };
@ -981,7 +1042,7 @@ namespace ICSharpCode.Decompiler.Ast
foreach (var ev in cecilMethodDef.DeclaringType.Events) { foreach (var ev in cecilMethodDef.DeclaringType.Events) {
if (ev.RemoveMethod == cecilMethodDef) { if (ev.RemoveMethod == cecilMethodDef) {
return new Ast.AssignmentExpression { return new Ast.AssignmentExpression {
Left = target.Member(ev.Name).WithAnnotation(ev), Left = target.Member(ev.Name).WithAnnotation(ev).WithAnnotation(cecilMethod),
Operator = AssignmentOperatorType.Subtract, Operator = AssignmentOperatorType.Subtract,
Right = methodArgs[0] Right = methodArgs[0]
}; };
@ -989,7 +1050,7 @@ namespace ICSharpCode.Decompiler.Ast
} }
} else if (cecilMethodDef.Name == "Invoke" && cecilMethodDef.DeclaringType.BaseType != null && cecilMethodDef.DeclaringType.BaseType.FullName == "System.MulticastDelegate") { } else if (cecilMethodDef.Name == "Invoke" && cecilMethodDef.DeclaringType.BaseType != null && cecilMethodDef.DeclaringType.BaseType.FullName == "System.MulticastDelegate") {
AdjustArgumentsForMethodCall(cecilMethod, methodArgs); AdjustArgumentsForMethodCall(cecilMethod, methodArgs);
return target.Invoke(methodArgs); return target.Invoke(methodArgs).WithAnnotation(cecilMethod);
} }
} }
// Default invocation // Default invocation
@ -1002,12 +1063,13 @@ namespace ICSharpCode.Decompiler.Ast
// Convert 'ref' into 'out' where necessary // Convert 'ref' into 'out' where necessary
for (int i = 0; i < methodArgs.Count && i < cecilMethod.Parameters.Count; i++) { for (int i = 0; i < methodArgs.Count && i < cecilMethod.Parameters.Count; i++) {
DirectionExpression dir = methodArgs[i] as DirectionExpression; DirectionExpression dir = methodArgs[i] as DirectionExpression;
if (dir != null && cecilMethod.Parameters[i].IsOut) ParameterDefinition p = cecilMethod.Parameters[i];
if (dir != null && p.IsOut && !p.IsIn)
dir.FieldDirection = FieldDirection.Out; dir.FieldDirection = FieldDirection.Out;
} }
} }
static PropertyDefinition GetIndexer(MethodDefinition cecilMethodDef) internal static PropertyDefinition GetIndexer(MethodDefinition cecilMethodDef)
{ {
TypeDefinition typeDef = cecilMethodDef.DeclaringType; TypeDefinition typeDef = cecilMethodDef.DeclaringType;
string indexerName = null; string indexerName = null;

16
src/Libraries/ICSharpCode.Decompiler/Ast/CecilTypeResolveContext.cs

@ -90,6 +90,12 @@ namespace ICSharpCode.Decompiler.Ast
countUntilNextCleanup = dict.Count + 4; countUntilNextCleanup = dict.Count + 4;
} }
public string AssemblyName {
get { return module.Assembly.Name.Name; }
}
public IList<IAttribute> ModuleAttributes { get; private set; }
public IList<IAttribute> AssemblyAttributes { get; private set; } public IList<IAttribute> AssemblyAttributes { get; private set; }
public ITypeDefinition GetTypeDefinition(string nameSpace, string name, int typeParameterCount, StringComparer nameComparer) public ITypeDefinition GetTypeDefinition(string nameSpace, string name, int typeParameterCount, StringComparer nameComparer)
@ -114,6 +120,11 @@ namespace ICSharpCode.Decompiler.Ast
return null; return null;
} }
public ITypeDefinition GetKnownTypeDefinition(TypeCode typeCode)
{
return GetTypeDefinition("System", ReflectionHelper.GetShortNameByTypeCode(typeCode), 0, StringComparer.Ordinal);
}
public IEnumerable<ITypeDefinition> GetTypes() public IEnumerable<ITypeDefinition> GetTypes()
{ {
foreach (TypeDefinition cecilType in module.Types) { foreach (TypeDefinition cecilType in module.Types) {
@ -165,6 +176,11 @@ namespace ICSharpCode.Decompiler.Ast
get { return new IParsedFile[0]; } get { return new IParsedFile[0]; }
} }
void IProjectContent.UpdateProjectContent(IParsedFile oldFile, IParsedFile newFile)
{
throw new NotSupportedException();
}
IParsedFile IProjectContent.GetFile(string fileName) IParsedFile IProjectContent.GetFile(string fileName)
{ {
return null; return null;

4
src/Libraries/ICSharpCode.Decompiler/Ast/NameVariables.cs

@ -175,6 +175,10 @@ namespace ICSharpCode.Decompiler.Ast
case ILCode.Clt_Un: case ILCode.Clt_Un:
case ILCode.Cgt: case ILCode.Cgt:
case ILCode.Cgt_Un: case ILCode.Cgt_Un:
case ILCode.Cle:
case ILCode.Cle_Un:
case ILCode.Cge:
case ILCode.Cge_Un:
ILVariable loadVar; ILVariable loadVar;
if (expr.Arguments[0].Match(ILCode.Ldloc, out loadVar) && loadVar == variable) { if (expr.Arguments[0].Match(ILCode.Ldloc, out loadVar) && loadVar == variable) {
isLoopCounter = true; isLoopCounter = true;

213
src/Libraries/ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs

@ -19,9 +19,9 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using ICSharpCode.Decompiler; using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.ILAst; using ICSharpCode.Decompiler.ILAst;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.CSharp;
using Mono.Cecil; using Mono.Cecil;
@ -33,6 +33,8 @@ namespace ICSharpCode.Decompiler.Ast
readonly Stack<AstNode> nodeStack = new Stack<AstNode>(); readonly Stack<AstNode> nodeStack = new Stack<AstNode>();
int braceLevelWithinType = -1; int braceLevelWithinType = -1;
bool inDocumentationComment = false; bool inDocumentationComment = false;
bool firstUsingDeclaration;
bool lastUsingDeclaration;
public TextOutputFormatter(ITextOutput output) public TextOutputFormatter(ITextOutput output)
{ {
@ -43,12 +45,37 @@ namespace ICSharpCode.Decompiler.Ast
public void WriteIdentifier(string identifier) public void WriteIdentifier(string identifier)
{ {
MemberReference memberRef = GetCurrentMemberReference(); var definition = GetCurrentDefinition();
if (definition != null) {
output.WriteDefinition(identifier, definition, false);
return;
}
if (memberRef != null) object memberRef = GetCurrentMemberReference();
if (memberRef != null) {
output.WriteReference(identifier, memberRef); output.WriteReference(identifier, memberRef);
else return;
output.Write(identifier); }
definition = GetCurrentLocalDefinition();
if (definition != null) {
output.WriteDefinition(identifier, definition);
return;
}
memberRef = GetCurrentLocalReference();
if (memberRef != null) {
output.WriteReference(identifier, memberRef, true);
return;
}
if (firstUsingDeclaration) {
output.MarkFoldStart(defaultCollapsed: true);
firstUsingDeclaration = false;
}
output.Write(identifier);
} }
MemberReference GetCurrentMemberReference() MemberReference GetCurrentMemberReference()
@ -60,6 +87,76 @@ namespace ICSharpCode.Decompiler.Ast
} }
return memberRef; return memberRef;
} }
object GetCurrentLocalReference()
{
AstNode node = nodeStack.Peek();
ILVariable variable = node.Annotation<ILVariable>();
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<MethodReference>()).FirstOrDefault(mr => mr != null);
if (method != null)
return method.ToString() + gotoStatement.Label;
}
return null;
}
object GetCurrentLocalDefinition()
{
AstNode node = nodeStack.Peek();
var parameterDef = node.Annotation<ParameterDefinition>();
if (parameterDef != null)
return parameterDef;
if (node is VariableInitializer || node is CatchClause || node is ForeachStatement) {
var variable = node.Annotation<ILVariable>();
if (variable != null) {
if (variable.OriginalParameter != null)
return variable.OriginalParameter;
//if (variable.OriginalVariable != null)
// return variable.OriginalVariable;
return variable;
} else {
}
}
var label = node as LabelStatement;
if (label != null)
{
var method = nodeStack.Select(nd => nd.Annotation<MethodReference>()).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 (IsDefinition(node))
return node.Annotation<MemberReference>();
var fieldDef = node.Parent.Annotation<FieldDefinition>();
if (fieldDef != null)
return node.Parent.Annotation<MemberReference>();
return null;
}
public void WriteKeyword(string keyword) public void WriteKeyword(string keyword)
{ {
@ -70,7 +167,8 @@ namespace ICSharpCode.Decompiler.Ast
{ {
// Attach member reference to token only if there's no identifier in the current node. // Attach member reference to token only if there's no identifier in the current node.
MemberReference memberRef = GetCurrentMemberReference(); MemberReference memberRef = GetCurrentMemberReference();
if (memberRef != null && nodeStack.Peek().GetChildByRole(AstNode.Roles.Identifier).IsNull) var node = nodeStack.Peek();
if (memberRef != null && node.GetChildByRole(AstNode.Roles.Identifier).IsNull)
output.WriteReference(token, memberRef); output.WriteReference(token, memberRef);
else else
output.Write(token); output.Write(token);
@ -115,6 +213,10 @@ namespace ICSharpCode.Decompiler.Ast
public void NewLine() public void NewLine()
{ {
if (lastUsingDeclaration) {
output.MarkFoldEnd();
lastUsingDeclaration = false;
}
output.WriteLine(); output.WriteLine();
} }
@ -131,13 +233,14 @@ namespace ICSharpCode.Decompiler.Ast
output.Write("*/"); output.Write("*/");
break; break;
case CommentType.Documentation: case CommentType.Documentation:
if (!inDocumentationComment) bool isLastLine = !(nodeStack.Peek().NextSibling is Comment);
if (!inDocumentationComment && !isLastLine) {
inDocumentationComment = true;
output.MarkFoldStart("///" + content, true); output.MarkFoldStart("///" + content, true);
}
output.Write("///"); output.Write("///");
output.Write(content); output.Write(content);
inDocumentationComment = true; if (inDocumentationComment && isLastLine) {
bool isLastLine = !(nodeStack.Peek().NextSibling is Comment);
if (isLastLine) {
inDocumentationComment = false; inDocumentationComment = false;
output.MarkFoldEnd(); output.MarkFoldEnd();
} }
@ -146,48 +249,78 @@ namespace ICSharpCode.Decompiler.Ast
} }
} }
Stack<TextLocation> startLocations = new Stack<TextLocation>();
MemberMapping currentMemberMapping;
Stack<MemberMapping> parentMemberMappings = new Stack<MemberMapping>();
public void StartNode(AstNode node) public void StartNode(AstNode node)
{ {
// code mappings if (nodeStack.Count == 0) {
var ranges = node.Annotation<List<ILRange>>(); if (IsUsingDeclaration(node)) {
if (ranges != null && ranges.Count > 0) { firstUsingDeclaration = !IsUsingDeclaration(node.PrevSibling);
// find the ancestor that has method mapping as annotation lastUsingDeclaration = !IsUsingDeclaration(node.NextSibling);
if (node.Parent != null) } else {
{ firstUsingDeclaration = false;
var n = node.Ancestors.FirstOrDefault(a => a.Annotation<MemberMapping>() != null); lastUsingDeclaration = false;
if (n != null) {
MemberMapping mapping = n.Annotation<MemberMapping>();
// add all ranges
foreach (var range in ranges) {
mapping.MemberCodeMappings.Add(new SourceCodeMapping {
ILInstructionOffset = range,
SourceCodeLine = output.CurrentLine,
MemberMapping = mapping
});
}
}
} }
} }
nodeStack.Push(node);
startLocations.Push(output.Location);
// definitions of types and their members MemberMapping mapping = node.Annotation<MemberMapping>();
Predicate<AstNode> predicate = n => n is AttributedNode; if (mapping != null) {
parentMemberMappings.Push(currentMemberMapping);
if (predicate(node)) { currentMemberMapping = mapping;
var n = node as AttributedNode;
int c = 0;
if (n != null)
c = n.Attributes.Count;
node.AddAnnotation(Tuple.Create(output.CurrentLine + c, output.CurrentColumn));
} }
nodeStack.Push(node);
} }
private bool IsUsingDeclaration(AstNode node)
{
return node is UsingDeclaration || node is UsingAliasDeclaration;
}
public void EndNode(AstNode node) public void EndNode(AstNode node)
{ {
if (nodeStack.Pop() != node) if (nodeStack.Pop() != node)
throw new InvalidOperationException(); throw new InvalidOperationException();
var startLocation = startLocations.Pop();
// code mappings
if (currentMemberMapping != null) {
var ranges = node.Annotation<List<ILRange>>();
if (ranges != null && ranges.Count > 0) {
// add all ranges
foreach (var range in ranges) {
currentMemberMapping.MemberCodeMappings.Add(
new SourceCodeMapping {
ILInstructionOffset = range,
StartLocation = startLocation,
EndLocation = output.Location,
MemberMapping = currentMemberMapping
});
}
}
}
if (node.Annotation<MemberMapping>() != null) {
output.AddDebuggerMemberMapping(currentMemberMapping);
currentMemberMapping = parentMemberMappings.Pop();
}
}
private static bool IsDefinition(AstNode node)
{
return
node is FieldDeclaration ||
node is ConstructorDeclaration ||
node is DestructorDeclaration ||
node is EventDeclaration ||
node is DelegateDeclaration ||
node is OperatorDeclaration||
node is MemberDeclaration ||
node is TypeDeclaration;
} }
} }
} }

2
src/Libraries/ICSharpCode.Decompiler/Ast/Transforms/AddCheckedBlocks.cs

@ -339,7 +339,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
result.NodesToInsertInCheckedContext = result.NodesToInsertInUncheckedContext + new ConvertCompoundAssignment(expr, false); result.NodesToInsertInCheckedContext = result.NodesToInsertInUncheckedContext + new ConvertCompoundAssignment(expr, false);
} }
} }
} else { } else if (expr.Role.IsValid(Expression.Null)) {
// We use '<' so that expressions are introduced on the deepest level possible (goal 3) // We use '<' so that expressions are introduced on the deepest level possible (goal 3)
if (result.CostInCheckedContext + new Cost(0, 1) < result.CostInUncheckedContext) { if (result.CostInCheckedContext + new Cost(0, 1) < result.CostInUncheckedContext) {
result.CostInUncheckedContext = result.CostInCheckedContext + new Cost(0, 1); result.CostInUncheckedContext = result.CostInCheckedContext + new Cost(0, 1);

38
src/Libraries/ICSharpCode.Decompiler/Ast/Transforms/CombineQueryExpressions.cs

@ -78,11 +78,17 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
} }
static readonly QuerySelectClause selectTransparentIdentifierPattern = new QuerySelectClause { static readonly QuerySelectClause selectTransparentIdentifierPattern = new QuerySelectClause {
Expression = new ObjectCreateExpression { Expression = new Choice {
Initializer = new ArrayInitializerExpression { new AnonymousTypeCreateExpression {
Elements = { Initializers = {
new NamedNode("nae1", new NamedArgumentExpression { Expression = new IdentifierExpression() }), new NamedNode("nae1", new NamedExpression { Expression = new IdentifierExpression() }),
new NamedNode("nae2", new NamedArgumentExpression { Expression = new AnyNode() }) new NamedNode("nae2", new NamedExpression { Expression = new AnyNode("nae2Expr") })
}
},
new AnonymousTypeCreateExpression {
Initializers = {
new NamedNode("identifier", new IdentifierExpression()),
new AnyNode("nae2Expr")
} }
} }
}}; }};
@ -100,12 +106,13 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
if (!match.Success) if (!match.Success)
return false; return false;
QuerySelectClause selectClause = (QuerySelectClause)innerQuery.Clauses.Last(); QuerySelectClause selectClause = (QuerySelectClause)innerQuery.Clauses.Last();
NamedArgumentExpression nae1 = match.Get<NamedArgumentExpression>("nae1").Single(); NamedExpression nae1 = match.Get<NamedExpression>("nae1").SingleOrDefault();
NamedArgumentExpression nae2 = match.Get<NamedArgumentExpression>("nae2").Single(); NamedExpression nae2 = match.Get<NamedExpression>("nae2").SingleOrDefault();
if (nae1.Identifier != ((IdentifierExpression)nae1.Expression).Identifier) if (nae1 != null && nae1.Identifier != ((IdentifierExpression)nae1.Expression).Identifier)
return false; return false;
IdentifierExpression nae2IdentExpr = nae2.Expression as IdentifierExpression; Expression nae2Expr = match.Get<Expression>("nae2Expr").Single();
if (nae2IdentExpr != null && nae2.Identifier == nae2IdentExpr.Identifier) { IdentifierExpression nae2IdentExpr = nae2Expr as IdentifierExpression;
if (nae2IdentExpr != null && (nae2 == null || nae2.Identifier == nae2IdentExpr.Identifier)) {
// from * in (from x in ... select new { x = x, y = y }) ... // from * in (from x in ... select new { x = x, y = y }) ...
// => // =>
// from x in ... ... // from x in ... ...
@ -127,7 +134,16 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
foreach (var clause in innerQuery.Clauses) { foreach (var clause in innerQuery.Clauses) {
query.Clauses.InsertAfter(insertionPos, insertionPos = clause.Detach()); query.Clauses.InsertAfter(insertionPos, insertionPos = clause.Detach());
} }
query.Clauses.InsertAfter(insertionPos, new QueryLetClause { Identifier = nae2.Identifier, Expression = nae2.Expression.Detach() }); string ident;
if (nae2 != null)
ident = nae2.Identifier;
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; return true;
} }

6
src/Libraries/ICSharpCode.Decompiler/Ast/Transforms/ConvertConstructorCallIntoInitializer.cs

@ -107,6 +107,10 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
AstNode fieldOrEventDecl = members.FirstOrDefault(f => f.Annotation<FieldDefinition>() == fieldDef); AstNode fieldOrEventDecl = members.FirstOrDefault(f => f.Annotation<FieldDefinition>() == fieldDef);
if (fieldOrEventDecl == null) if (fieldOrEventDecl == null)
break; break;
Expression initializer = m.Get<Expression>("initializer").Single();
// 'this'/'base' cannot be used in field initializers
if (initializer.DescendantsAndSelf.Any(n => n is ThisReferenceExpression || n is BaseReferenceExpression))
break;
allSame = true; allSame = true;
for (int i = 1; i < instanceCtorsNotChainingWithThis.Length; i++) { for (int i = 1; i < instanceCtorsNotChainingWithThis.Length; i++) {
@ -116,7 +120,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
if (allSame) { if (allSame) {
foreach (var ctor in instanceCtorsNotChainingWithThis) foreach (var ctor in instanceCtorsNotChainingWithThis)
ctor.Body.First().Remove(); ctor.Body.First().Remove();
fieldOrEventDecl.GetChildrenByRole(AstNode.Roles.Variable).Single().Initializer = m.Get<Expression>("initializer").Single().Detach(); fieldOrEventDecl.GetChildrenByRole(AstNode.Roles.Variable).Single().Initializer = initializer.Detach();
} }
} while (allSame); } while (allSame);
} }

109
src/Libraries/ICSharpCode.Decompiler/Ast/Transforms/CustomPatterns.cs

@ -0,0 +1,109 @@
// 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
{
sealed class TypePattern : Pattern
{
readonly string ns;
readonly string name;
public TypePattern(Type type)
{
this.ns = type.Namespace;
this.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<TypeReference>();
return tr != null && tr.Namespace == ns && tr.Name == name;
}
public override string ToString()
{
return name;
}
}
sealed class LdTokenPattern : Pattern
{
AnyNode childNode;
public LdTokenPattern(string groupName)
{
this.childNode = new AnyNode(groupName);
}
public override bool DoMatch(INode other, Match match)
{
InvocationExpression ie = other as InvocationExpression;
if (ie != null && ie.Annotation<LdTokenAnnotation>() != null && ie.Arguments.Count == 1) {
return childNode.DoMatch(ie.Arguments.Single(), match);
}
return false;
}
public override string ToString()
{
return "ldtoken(...)";
}
}
/// <summary>
/// typeof-Pattern that applies on the expanded form of typeof (prior to ReplaceMethodCallsWithOperators)
/// </summary>
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(...)";
}
}
}

28
src/Libraries/ICSharpCode.Decompiler/Ast/Transforms/DeclareVariables.cs

@ -21,6 +21,7 @@ using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using ICSharpCode.Decompiler.ILAst;
using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.Analysis; using ICSharpCode.NRefactory.CSharp.Analysis;
@ -35,6 +36,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
{ {
public AstType Type; public AstType Type;
public string Name; public string Name;
public ILVariable ILVariable;
public AssignmentExpression ReplacedAssignment; public AssignmentExpression ReplacedAssignment;
public Statement InsertionPoint; public Statement InsertionPoint;
@ -57,9 +59,12 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
foreach (var v in variablesToDeclare) { foreach (var v in variablesToDeclare) {
if (v.ReplacedAssignment == null) { if (v.ReplacedAssignment == null) {
BlockStatement block = (BlockStatement)v.InsertionPoint.Parent; 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( block.Statements.InsertBefore(
v.InsertionPoint, v.InsertionPoint,
new VariableDeclarationStatement((AstType)v.Type.Clone(), v.Name)); 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. // First do all the insertions, then do all the replacements. This is necessary because a replacement might remove our reference point from the AST.
@ -67,9 +72,10 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
if (v.ReplacedAssignment != null) { if (v.ReplacedAssignment != null) {
// We clone the right expression so that it doesn't get removed from the old ExpressionStatement, // 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. // 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 { VariableDeclarationStatement varDecl = new VariableDeclarationStatement {
Type = (AstType)v.Type.Clone(), Type = (AstType)v.Type.Clone(),
Variables = { new VariableInitializer(v.Name, v.ReplacedAssignment.Right.Detach()).CopyAnnotationsFrom(v.ReplacedAssignment) } Variables = { initializer }
}; };
ExpressionStatement es = v.ReplacedAssignment.Parent as ExpressionStatement; ExpressionStatement es = v.ReplacedAssignment.Parent as ExpressionStatement;
if (es != null) { if (es != null) {
@ -100,9 +106,11 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
daa = new DefiniteAssignmentAnalysis(block, cancellationToken); daa = new DefiniteAssignmentAnalysis(block, cancellationToken);
} }
foreach (VariableDeclarationStatement varDecl in variables) { foreach (VariableDeclarationStatement varDecl in variables) {
string variableName = varDecl.Variables.Single().Name; VariableInitializer initializer = varDecl.Variables.Single();
bool allowPassIntoLoops = varDecl.Variables.Single().Annotation<DelegateConstruction.CapturedVariableAnnotation>() == null; string variableName = initializer.Name;
DeclareVariableInBlock(daa, block, varDecl.Type, variableName, allowPassIntoLoops); ILVariable v = initializer.Annotation<ILVariable>();
bool allowPassIntoLoops = initializer.Annotation<DelegateConstruction.CapturedVariableAnnotation>() == null;
DeclareVariableInBlock(daa, block, varDecl.Type, variableName, v, allowPassIntoLoops);
} }
} }
} }
@ -111,7 +119,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
} }
} }
void DeclareVariableInBlock(DefiniteAssignmentAnalysis daa, BlockStatement block, AstType type, string variableName, bool allowPassIntoLoops) 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 // declarationPoint: The point where the variable would be declared, if we decide to declare it in this block
Statement declarationPoint = null; Statement declarationPoint = null;
@ -139,10 +147,10 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
foreach (AstNode child in stmt.Children) { foreach (AstNode child in stmt.Children) {
BlockStatement subBlock = child as BlockStatement; BlockStatement subBlock = child as BlockStatement;
if (subBlock != null) { if (subBlock != null) {
DeclareVariableInBlock(daa, subBlock, type, variableName, allowPassIntoLoops); DeclareVariableInBlock(daa, subBlock, type, variableName, v, allowPassIntoLoops);
} else if (HasNestedBlocks(child)) { } else if (HasNestedBlocks(child)) {
foreach (BlockStatement nestedSubBlock in child.Children.OfType<BlockStatement>()) { foreach (BlockStatement nestedSubBlock in child.Children.OfType<BlockStatement>()) {
DeclareVariableInBlock(daa, nestedSubBlock, type, variableName, allowPassIntoLoops); DeclareVariableInBlock(daa, nestedSubBlock, type, variableName, v, allowPassIntoLoops);
} }
} }
} }
@ -151,7 +159,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
// Try converting an assignment expression into a VariableDeclarationStatement // Try converting an assignment expression into a VariableDeclarationStatement
if (!TryConvertAssignmentExpressionIntoVariableDeclaration(declarationPoint, type, variableName)) { if (!TryConvertAssignmentExpressionIntoVariableDeclaration(declarationPoint, type, variableName)) {
// Declare the variable in front of declarationPoint // Declare the variable in front of declarationPoint
variablesToDeclare.Add(new VariableToDeclare { Type = type, Name = variableName, InsertionPoint = declarationPoint }); variablesToDeclare.Add(new VariableToDeclare { Type = type, Name = variableName, ILVariable = v, InsertionPoint = declarationPoint });
} }
} }
} }
@ -172,7 +180,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
if (ae != null && ae.Operator == AssignmentOperatorType.Assign) { if (ae != null && ae.Operator == AssignmentOperatorType.Assign) {
IdentifierExpression ident = ae.Left as IdentifierExpression; IdentifierExpression ident = ae.Left as IdentifierExpression;
if (ident != null && ident.Identifier == variableName) { if (ident != null && ident.Identifier == variableName) {
variablesToDeclare.Add(new VariableToDeclare { Type = type, Name = variableName, ReplacedAssignment = ae }); variablesToDeclare.Add(new VariableToDeclare { Type = type, Name = variableName, ILVariable = ident.Annotation<ILVariable>(), ReplacedAssignment = ae });
return true; return true;
} }
} }

29
src/Libraries/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs

@ -209,6 +209,18 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
return true; 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 #region Track current variables
public override object VisitMethodDeclaration(MethodDeclaration methodDeclaration, object data) public override object VisitMethodDeclaration(MethodDeclaration methodDeclaration, object data)
{ {
@ -386,7 +398,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
} }
// Now create variables for all fields of the display class (except for those that we already handled as parameters) // Now create variables for all fields of the display class (except for those that we already handled as parameters)
List<Tuple<AstType, string>> variablesToDeclare = new List<Tuple<AstType, string>>(); List<Tuple<AstType, ILVariable>> variablesToDeclare = new List<Tuple<AstType, ILVariable>>();
foreach (FieldDefinition field in type.Fields) { foreach (FieldDefinition field in type.Fields) {
if (field.IsStatic) if (field.IsStatic)
continue; // skip static fields continue; // skip static fields
@ -397,8 +409,14 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
capturedVariableName = capturedVariableName.Substring(10); capturedVariableName = capturedVariableName.Substring(10);
EnsureVariableNameIsAvailable(blockStatement, capturedVariableName); EnsureVariableNameIsAvailable(blockStatement, capturedVariableName);
currentlyUsedVariableNames.Add(capturedVariableName); currentlyUsedVariableNames.Add(capturedVariableName);
variablesToDeclare.Add(Tuple.Create(AstBuilder.ConvertType(field.FieldType, field), capturedVariableName)); ILVariable ilVar = new ILVariable
dict[field] = new IdentifierExpression(capturedVariableName); {
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: // Now figure out where the closure was accessed and use the simpler replacement expression there:
@ -414,15 +432,16 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
// Now insert the variable declarations (we can do this after the replacements only so that the scope detection works): // Now insert the variable declarations (we can do this after the replacements only so that the scope detection works):
Statement insertionPoint = blockStatement.Statements.FirstOrDefault(); Statement insertionPoint = blockStatement.Statements.FirstOrDefault();
foreach (var tuple in variablesToDeclare) { foreach (var tuple in variablesToDeclare) {
var newVarDecl = new VariableDeclarationStatement(tuple.Item1, tuple.Item2); var newVarDecl = new VariableDeclarationStatement(tuple.Item1, tuple.Item2.Name);
newVarDecl.Variables.Single().AddAnnotation(new CapturedVariableAnnotation()); newVarDecl.Variables.Single().AddAnnotation(new CapturedVariableAnnotation());
newVarDecl.Variables.Single().AddAnnotation(tuple.Item2);
blockStatement.Statements.InsertBefore(insertionPoint, newVarDecl); blockStatement.Statements.InsertBefore(insertionPoint, newVarDecl);
} }
} }
currentlyUsedVariableNames.RemoveRange(numberOfVariablesOutsideBlock, currentlyUsedVariableNames.Count - numberOfVariablesOutsideBlock); currentlyUsedVariableNames.RemoveRange(numberOfVariablesOutsideBlock, currentlyUsedVariableNames.Count - numberOfVariablesOutsideBlock);
return null; return null;
} }
void EnsureVariableNameIsAvailable(AstNode currentNode, string name) void EnsureVariableNameIsAvailable(AstNode currentNode, string name)
{ {
int pos = currentlyUsedVariableNames.IndexOf(name); int pos = currentlyUsedVariableNames.IndexOf(name);

875
src/Libraries/ICSharpCode.Decompiler/Ast/Transforms/ExpressionTreeConverter.cs

@ -0,0 +1,875 @@
// 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<MethodReference>();
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<LambdaExpression> activeLambdas = new Stack<LambdaExpression>();
private 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<MethodReference>();
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<ILVariable>();
if (v != null) {
foreach (LambdaExpression lambda in activeLambdas) {
foreach (ParameterDeclaration p in lambda.Parameters) {
if (p.Annotation<ILVariable>() == 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<ParameterDeclarationAnnotation>();
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<AstNode>("field").Single().Annotation<FieldReference>();
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<AstType>("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<AstNode>("method").Single().Annotation<MethodReference>();
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<AstType>("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<AstNode>("method").Single().Annotation<MethodReference>();
if (mr == null)
return null;
Expression convertedTarget;
if (target == null || target is NullReferenceExpression) {
// static method
if (m.Has("declaringType"))
convertedTarget = new TypeReferenceExpression(m.Get<AstType>("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<Expression> arguments = null;
if (invocation.Arguments.Count == firstArgumentPosition + 1) {
Expression argumentArray = invocation.Arguments.ElementAt(firstArgumentPosition);
arguments = ConvertExpressionsArray(argumentArray);
}
if (arguments == null) {
arguments = new List<Expression>();
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<Expression> 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<AstNode>("method").Single().Annotation<MethodReference>());
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<AstNode>("method").Single().Annotation<MethodReference>());
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<AstNode>("method").Single().Annotation<MethodReference>());
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<AstNode>("ctor").Single().Annotation<MethodReference>();
if (ctor == null)
return null;
AstType declaringTypeNode;
TypeReference declaringType;
if (m.Has("declaringType")) {
declaringTypeNode = m.Get<AstType>("declaringType").Single().Clone();
declaringType = declaringTypeNode.Annotation<TypeReference>();
} 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<Expression> 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 {
Identifier = 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<Expression> 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<Expression>("addArgumentsArrays")) {
IList<Expression> 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<Expression>("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<AstNode>("method").Single().Annotation<MethodReference>();
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<AstNode>("method").Single().Annotation<MethodReference>());
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<Expression> ConvertExpressionsArray(Expression arrayExpression)
{
Match m = expressionArrayPattern.Match(arrayExpression);
if (m.Success) {
List<Expression> result = new List<Expression>();
foreach (Expression expr in m.Get<Expression>("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<AstType>("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<Expression> indexesConverted = ConvertExpressionsArray(index);
if (indexConverted != 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<Expression> 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<Expression> 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<AstType>()) {
TypeReference tr = t.Annotation<TypeReference>();
if (tr != null && tr.IsAnonymousType())
return true;
}
return false;
}
#endregion
}
}

27
src/Libraries/ICSharpCode.Decompiler/Ast/Transforms/FlattenSwitchBlocks.cs

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ICSharpCode.NRefactory.CSharp;
namespace ICSharpCode.Decompiler.Ast.Transforms
{
class FlattenSwitchBlocks : IAstTransform
{
public void Run(AstNode compilationUnit)
{
foreach (var switchSection in compilationUnit.Descendants.OfType<SwitchSection>())
{
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);
}
}
}
}

6
src/Libraries/ICSharpCode.Decompiler/Ast/Transforms/IntroduceExtensionMethods.cs

@ -45,7 +45,11 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
if (d != null) { if (d != null) {
foreach (var ca in d.CustomAttributes) { foreach (var ca in d.CustomAttributes) {
if (ca.AttributeType.Name == "ExtensionAttribute" && ca.AttributeType.Namespace == "System.Runtime.CompilerServices") { if (ca.AttributeType.Name == "ExtensionAttribute" && ca.AttributeType.Namespace == "System.Runtime.CompilerServices") {
mre.Target = invocation.Arguments.First().Detach(); 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()) { if (invocation.Arguments.Any()) {
// HACK: removing type arguments should be done indepently from whether a method is an extension method, // 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 // just by testing whether the arguments can be inferred

41
src/Libraries/ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs

@ -227,6 +227,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
Name = variableName, Name = variableName,
Initializer = m1.Get<Expression>("initializer").Single().Detach() Initializer = m1.Get<Expression>("initializer").Single().Detach()
}.CopyAnnotationsFrom(node.Expression) }.CopyAnnotationsFrom(node.Expression)
.WithAnnotation(m1.Get<AstNode>("variable").Single().Annotation<ILVariable>())
} }
}.CopyAnnotationsFrom(node); }.CopyAnnotationsFrom(node);
} else { } else {
@ -382,7 +383,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
VariableName = itemVar.Identifier, VariableName = itemVar.Identifier,
InExpression = m.Get<Expression>("collection").Single().Detach(), InExpression = m.Get<Expression>("collection").Single().Detach(),
EmbeddedStatement = newBody EmbeddedStatement = newBody
}; }.WithAnnotation(itemVarDecl.Variables.Single().Annotation<ILVariable>());
if (foreachStatement.InExpression is BaseReferenceExpression) { if (foreachStatement.InExpression is BaseReferenceExpression) {
foreachStatement.InExpression = new ThisReferenceExpression().CopyAnnotationsFrom(foreachStatement.InExpression); foreachStatement.InExpression = new ThisReferenceExpression().CopyAnnotationsFrom(foreachStatement.InExpression);
} }
@ -471,10 +472,12 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
// We just care that we can move it in front of the loop: // We just care that we can move it in front of the loop:
if (declarationPoint != loop) if (declarationPoint != loop)
return null; return null;
ForeachStatement foreachStatement = new ForeachStatement(); ForeachStatement foreachStatement = new ForeachStatement
foreachStatement.VariableType = itemVarDecl.Type.Clone(); {
foreachStatement.VariableName = itemVar.Identifier; VariableType = itemVarDecl.Type.Clone(),
VariableName = itemVar.Identifier,
}.WithAnnotation(itemVarDecl.Variables.Single().Annotation<ILVariable>());
BlockStatement body = new BlockStatement(); BlockStatement body = new BlockStatement();
foreachStatement.EmbeddedStatement = body; foreachStatement.EmbeddedStatement = body;
((BlockStatement)node.Parent).Statements.InsertBefore(node, foreachStatement); ((BlockStatement)node.Parent).Statements.InsertBefore(node, foreachStatement);
@ -982,33 +985,5 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
return null; return null;
} }
#endregion #endregion
#region Pattern Matching Helpers
sealed class TypePattern : Pattern
{
readonly string ns;
readonly string name;
public TypePattern(Type type)
{
this.ns = type.Namespace;
this.name = type.Name;
}
public override bool DoMatch(INode other, Match match)
{
AstNode o = other as AstNode;
if (o == null)
return false;
TypeReference tr = o.Annotation<TypeReference>();
return tr != null && tr.Namespace == ns && tr.Name == name;
}
public override S AcceptVisitor<T, S>(IPatternAstVisitor<T, S> visitor, T data)
{
throw new NotImplementedException();
}
}
#endregion
} }
} }

14
src/Libraries/ICSharpCode.Decompiler/Ast/Transforms/PushNegation.cs

@ -26,8 +26,18 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
{ {
public class PushNegation: DepthFirstAstVisitor<object, object>, IAstTransform public class PushNegation: DepthFirstAstVisitor<object, object>, IAstTransform
{ {
sealed class LiftedOperator { }
/// <summary>
/// Annotation for lifted operators that cannot be transformed by PushNegation
/// </summary>
public static readonly object LiftedOperatorAnnotation = new LiftedOperator();
public override object VisitUnaryOperatorExpression(UnaryOperatorExpression unary, object data) public override object VisitUnaryOperatorExpression(UnaryOperatorExpression unary, object data)
{ {
// lifted operators can't be transformed
if (unary.Annotation<LiftedOperator>() != null || unary.Expression.Annotation<LiftedOperator>() != null)
return base.VisitUnaryOperatorExpression(unary, data);
// Remove double negation // Remove double negation
// !!a // !!a
if (unary.Operator == UnaryOperatorType.Not && if (unary.Operator == UnaryOperatorType.Not &&
@ -108,6 +118,10 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
public override object VisitBinaryOperatorExpression(BinaryOperatorExpression binaryOperatorExpression, object data) public override object VisitBinaryOperatorExpression(BinaryOperatorExpression binaryOperatorExpression, object data)
{ {
// lifted operators can't be transformed
if (binaryOperatorExpression.Annotation<LiftedOperator>() != null)
return base.VisitBinaryOperatorExpression(binaryOperatorExpression, data);
BinaryOperatorType op = binaryOperatorExpression.Operator; BinaryOperatorType op = binaryOperatorExpression.Operator;
bool? rightOperand = null; bool? rightOperand = null;
if (binaryOperatorExpression.Right is PrimitiveExpression) if (binaryOperatorExpression.Right is PrimitiveExpression)

96
src/Libraries/ICSharpCode.Decompiler/Ast/Transforms/ReplaceMethodCallsWithOperators.cs

@ -19,6 +19,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection;
using ICSharpCode.NRefactory.PatternMatching; using ICSharpCode.NRefactory.PatternMatching;
using Mono.Cecil; using Mono.Cecil;
using Ast = ICSharpCode.NRefactory.CSharp; using Ast = ICSharpCode.NRefactory.CSharp;
@ -40,13 +41,25 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
MemberName = "TypeHandle" MemberName = "TypeHandle"
}; };
DecompilerContext context;
public ReplaceMethodCallsWithOperators(DecompilerContext context)
{
this.context = context;
}
public override object VisitInvocationExpression(InvocationExpression invocationExpression, object data) public override object VisitInvocationExpression(InvocationExpression invocationExpression, object data)
{ {
base.VisitInvocationExpression(invocationExpression, data); base.VisitInvocationExpression(invocationExpression, data);
ProcessInvocationExpression(invocationExpression);
return null;
}
internal static void ProcessInvocationExpression(InvocationExpression invocationExpression)
{
MethodReference methodRef = invocationExpression.Annotation<MethodReference>(); MethodReference methodRef = invocationExpression.Annotation<MethodReference>();
if (methodRef == null) if (methodRef == null)
return null; return;
var arguments = invocationExpression.Arguments.ToArray(); var arguments = invocationExpression.Arguments.ToArray();
// Reduce "String.Concat(a, b)" to "a + b" // Reduce "String.Concat(a, b)" to "a + b"
@ -58,7 +71,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
expr = new BinaryOperatorExpression(expr, BinaryOperatorType.Add, arguments[i]); expr = new BinaryOperatorExpression(expr, BinaryOperatorType.Add, arguments[i]);
} }
invocationExpression.ReplaceWith(expr); invocationExpression.ReplaceWith(expr);
return null; return;
} }
switch (methodRef.FullName) { switch (methodRef.FullName) {
@ -66,7 +79,34 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
if (arguments.Length == 1) { if (arguments.Length == 1) {
if (typeHandleOnTypeOfPattern.IsMatch(arguments[0])) { if (typeHandleOnTypeOfPattern.IsMatch(arguments[0])) {
invocationExpression.ReplaceWith(((MemberReferenceExpression)arguments[0]).Target); invocationExpression.ReplaceWith(((MemberReferenceExpression)arguments[0]).Target);
return null; 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<LdTokenAnnotation>() != 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<LdTokenAnnotation>() != null) {
if (mre2 != null && mre2.MemberName == "TypeHandle" && mre2.Target is TypeOfExpression) {
Expression oldArg = ((InvocationExpression)mre1.Target).Arguments.Single();
FieldReference field = oldArg.Annotation<FieldReference>();
if (field != null) {
AstType declaringType = ((TypeOfExpression)mre2.Target).Type.Detach();
oldArg.ReplaceWith(declaringType.Member(field.Name).WithAnnotation(field));
invocationExpression.ReplaceWith(mre1.Target);
return;
}
}
} }
} }
break; break;
@ -78,7 +118,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
invocationExpression.ReplaceWith( invocationExpression.ReplaceWith(
new BinaryOperatorExpression(arguments[0], bop.Value, arguments[1]).WithAnnotation(methodRef) new BinaryOperatorExpression(arguments[0], bop.Value, arguments[1]).WithAnnotation(methodRef)
); );
return null; return;
} }
UnaryOperatorType? uop = GetUnaryOperatorTypeFromMetadataName(methodRef.Name); UnaryOperatorType? uop = GetUnaryOperatorTypeFromMetadataName(methodRef.Name);
if (uop != null && arguments.Length == 1) { if (uop != null && arguments.Length == 1) {
@ -86,7 +126,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
invocationExpression.ReplaceWith( invocationExpression.ReplaceWith(
new UnaryOperatorExpression(uop.Value, arguments[0]).WithAnnotation(methodRef) new UnaryOperatorExpression(uop.Value, arguments[0]).WithAnnotation(methodRef)
); );
return null; return;
} }
if (methodRef.Name == "op_Explicit" && arguments.Length == 1) { if (methodRef.Name == "op_Explicit" && arguments.Length == 1) {
arguments[0].Remove(); // detach argument arguments[0].Remove(); // detach argument
@ -94,21 +134,21 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
arguments[0].CastTo(AstBuilder.ConvertType(methodRef.ReturnType, methodRef.MethodReturnType)) arguments[0].CastTo(AstBuilder.ConvertType(methodRef.ReturnType, methodRef.MethodReturnType))
.WithAnnotation(methodRef) .WithAnnotation(methodRef)
); );
return null; return;
} }
if (methodRef.Name == "op_Implicit" && arguments.Length == 1) { if (methodRef.Name == "op_Implicit" && arguments.Length == 1) {
invocationExpression.ReplaceWith(arguments[0]); invocationExpression.ReplaceWith(arguments[0]);
return null; return;
} }
if (methodRef.Name == "op_True" && arguments.Length == 1 && invocationExpression.Role == AstNode.Roles.Condition) { if (methodRef.Name == "op_True" && arguments.Length == 1 && invocationExpression.Role == AstNode.Roles.Condition) {
invocationExpression.ReplaceWith(arguments[0]); invocationExpression.ReplaceWith(arguments[0]);
return null; return;
} }
return null; return;
} }
BinaryOperatorType? GetBinaryOperatorTypeFromMetadataName(string name) static BinaryOperatorType? GetBinaryOperatorTypeFromMetadataName(string name)
{ {
switch (name) { switch (name) {
case "op_Addition": case "op_Addition":
@ -125,7 +165,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
return BinaryOperatorType.BitwiseAnd; return BinaryOperatorType.BitwiseAnd;
case "op_BitwiseOr": case "op_BitwiseOr":
return BinaryOperatorType.BitwiseOr; return BinaryOperatorType.BitwiseOr;
case "op_ExlusiveOr": case "op_ExclusiveOr":
return BinaryOperatorType.ExclusiveOr; return BinaryOperatorType.ExclusiveOr;
case "op_LeftShift": case "op_LeftShift":
return BinaryOperatorType.ShiftLeft; return BinaryOperatorType.ShiftLeft;
@ -148,7 +188,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
} }
} }
UnaryOperatorType? GetUnaryOperatorTypeFromMetadataName(string name) static UnaryOperatorType? GetUnaryOperatorTypeFromMetadataName(string name)
{ {
switch (name) { switch (name) {
case "op_LogicalNot": case "op_LogicalNot":
@ -214,7 +254,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
} }
} }
} }
if (assignment.Operator == AssignmentOperatorType.Add || assignment.Operator == AssignmentOperatorType.Subtract) { if (context.Settings.IntroduceIncrementAndDecrement && (assignment.Operator == AssignmentOperatorType.Add || assignment.Operator == AssignmentOperatorType.Subtract)) {
// detect increment/decrement // detect increment/decrement
if (assignment.Right.IsMatch(new PrimitiveExpression(1))) { if (assignment.Right.IsMatch(new PrimitiveExpression(1))) {
// only if it's not a custom operator // only if it's not a custom operator
@ -280,6 +320,34 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
return left is ThisReferenceExpression || left is IdentifierExpression || left is TypeReferenceExpression || left is BaseReferenceExpression; 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<AstNode>("method").Single().Annotation<MethodReference>();
if (m.Has("declaringType")) {
Expression newNode = m.Get<AstType>("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<AstNode>("method").Single().ReplaceWith(newNode);
}
castExpression.ReplaceWith(m.Get<AstNode>("ldtokenNode").Single());
}
return null;
}
void IAstTransform.Run(AstNode node) void IAstTransform.Run(AstNode node)
{ {
node.AcceptVisitor(this, null); node.AcceptVisitor(this, null);

3
src/Libraries/ICSharpCode.Decompiler/Ast/Transforms/TransformationPipeline.cs

@ -35,7 +35,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
new PushNegation(), new PushNegation(),
new DelegateConstruction(context), new DelegateConstruction(context),
new PatternStatementTransform(context), new PatternStatementTransform(context),
new ReplaceMethodCallsWithOperators(), new ReplaceMethodCallsWithOperators(context),
new IntroduceUnsafeModifier(), new IntroduceUnsafeModifier(),
new AddCheckedBlocks(), new AddCheckedBlocks(),
new DeclareVariables(context), // should run after most transforms that modify statements new DeclareVariables(context), // should run after most transforms that modify statements
@ -45,6 +45,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
new IntroduceExtensionMethods(context), // must run after IntroduceUsingDeclarations new IntroduceExtensionMethods(context), // must run after IntroduceUsingDeclarations
new IntroduceQueryExpressions(context), // must run after IntroduceExtensionMethods new IntroduceQueryExpressions(context), // must run after IntroduceExtensionMethods
new CombineQueryExpressions(context), new CombineQueryExpressions(context),
new FlattenSwitchBlocks(),
}; };
} }

8
src/Libraries/ICSharpCode.Decompiler/CecilExtensions.cs

@ -59,7 +59,7 @@ namespace ICSharpCode.Decompiler
throw new NotSupportedException (); throw new NotSupportedException ();
} }
public static int? GetPopDelta(this Instruction instruction) public static int? GetPopDelta(this Instruction instruction, MethodDefinition methodDef)
{ {
OpCode code = instruction.OpCode; OpCode code = instruction.OpCode;
switch (code.StackBehaviourPop) { switch (code.StackBehaviourPop) {
@ -93,15 +93,17 @@ namespace ICSharpCode.Decompiler
case StackBehaviour.Varpop: case StackBehaviour.Varpop:
if (code == OpCodes.Ret) if (code == OpCodes.Ret)
return null; return methodDef.ReturnType.IsVoid() ? 0 : 1;
if (code.FlowControl != FlowControl.Call) if (code.FlowControl != FlowControl.Call)
break; break;
IMethodSignature method = (IMethodSignature) instruction.Operand; IMethodSignature method = (IMethodSignature) instruction.Operand;
int count = method.HasParameters ? method.Parameters.Count : 0; int count = method.HasParameters ? method.Parameters.Count : 0;
if (code == OpCodes.Calli || (method.HasThis && code != OpCodes.Newobj)) if (method.HasThis && code != OpCodes.Newobj)
++count; ++count;
if (code == OpCodes.Calli)
++count; // calli takes a function pointer in additional to the normal args
return count; return count;
} }

180
src/Libraries/ICSharpCode.Decompiler/CodeMappings.cs

@ -20,73 +20,39 @@ using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using ICSharpCode.Decompiler.Ast; using ICSharpCode.Decompiler.Ast;
using ICSharpCode.Decompiler.Disassembler; using ICSharpCode.Decompiler.Disassembler;
using ICSharpCode.Decompiler.ILAst; using ICSharpCode.Decompiler.ILAst;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.CSharp;
using Mono.Cecil; using Mono.Cecil;
namespace ICSharpCode.Decompiler namespace ICSharpCode.Decompiler
{ {
public enum DecompiledLanguages
{
IL,
CSharp
}
/// <summary> /// <summary>
/// Base class for decompliler classes : AstBuilder & ReflectionDisassembler. /// Maps the source code to IL.
/// </summary> /// </summary>
public abstract class BaseCodeMappings public sealed class SourceCodeMapping
{ {
/// <summary> /// <summary>
/// Gets the code mappings. /// Gets or sets the start location of the instruction.
/// <remarks>Key is the metadata token.</remarks>
/// </summary> /// </summary>
public Dictionary<int, List<MemberMapping>> CodeMappings { get; protected set; } public TextLocation StartLocation { get; set; }
/// <summary> /// <summary>
/// Gets the MembeReference that is decompiled (a MethodDefinition, PropertyDefinition etc.) /// Gets or sets the end location of the instruction.
/// <remarks>Key is the metadata token.</remarks>
/// </summary> /// </summary>
public Dictionary<int, MemberReference> DecompiledMemberReferences { get; protected set; } public TextLocation EndLocation { get; set; }
/// <summary>
/// Create data in the CodeMappings and DecompiledMemberReferences.
/// </summary>
/// <param name="token">Token of the current method.</param>
/// <param name="member">Current member (MethodDefinition, PropertyDefinition, EventDefinition).</param>
/// <remarks>The token is used in CodeMappings; member (and its token) is used in DecompiledMemberReferences.</remarks>
protected virtual void CreateCodeMappings(int token, MemberReference member)
{
this.CodeMappings.Add(token, new List<MemberMapping>());
int t = member.MetadataToken.ToInt32();
if (!this.DecompiledMemberReferences.ContainsKey(t))
this.DecompiledMemberReferences.Add(t, member);
}
}
/// <summary>
/// Maps the source code to IL.
/// </summary>
public sealed class SourceCodeMapping
{
/// <summary>
/// Gets or sets the source code line number in the output.
/// </summary>
public int SourceCodeLine { get; internal set; }
/// <summary> /// <summary>
/// Gets or sets IL Range offset for the source code line. E.g.: 13-19 &lt;-&gt; 135. /// Gets or sets IL Range offset for the source code line. E.g.: 13-19 &lt;-&gt; 135.
/// </summary> /// </summary>
public ILRange ILInstructionOffset { get; internal set; } public ILRange ILInstructionOffset { get; set; }
/// <summary> /// <summary>
/// Gets or sets the member mapping this source code mapping belongs to. /// Gets or sets the member mapping this source code mapping belongs to.
/// </summary> /// </summary>
public MemberMapping MemberMapping { get; internal set; } public MemberMapping MemberMapping { get; set; }
/// <summary> /// <summary>
/// Retrieves the array that contains the IL range and the missing gaps between ranges. /// Retrieves the array that contains the IL range and the missing gaps between ranges.
@ -98,7 +64,7 @@ namespace ICSharpCode.Decompiler
// add list for the current source code line // add list for the current source code line
currentList.AddRange(ILRange.OrderAndJoint(MemberMapping.MemberCodeMappings currentList.AddRange(ILRange.OrderAndJoint(MemberMapping.MemberCodeMappings
.FindAll(m => m.SourceCodeLine == this.SourceCodeLine) .FindAll(m => m.StartLocation.Line == this.StartLocation.Line)
.ConvertAll<ILRange>(m => m.ILInstructionOffset))); .ConvertAll<ILRange>(m => m.ILInstructionOffset)));
if (!isMatch) { if (!isMatch) {
@ -123,12 +89,24 @@ namespace ICSharpCode.Decompiler
} }
/// <summary> /// <summary>
/// Stores the method information and its source code mappings. /// Stores the member information and its source code mappings.
/// </summary> /// </summary>
public sealed class MemberMapping public sealed class MemberMapping
{ {
IEnumerable<ILRange> invertedList; IEnumerable<ILRange> invertedList;
internal MemberMapping()
{
}
public MemberMapping(MethodDefinition method)
{
this.MetadataToken = method.MetadataToken.ToInt32();
this.MemberCodeMappings = new List<SourceCodeMapping>();
this.MemberReference = method;
this.CodeSize = method.Body.CodeSize;
}
/// <summary> /// <summary>
/// Gets or sets the type of the mapping. /// Gets or sets the type of the mapping.
/// </summary> /// </summary>
@ -149,6 +127,11 @@ namespace ICSharpCode.Decompiler
/// </summary> /// </summary>
public List<SourceCodeMapping> MemberCodeMappings { get; internal set; } public List<SourceCodeMapping> MemberCodeMappings { get; internal set; }
/// <summary>
/// Gets or sets the local variables.
/// </summary>
public IEnumerable<ILVariable> LocalVariables { get; internal set; }
/// <summary> /// <summary>
/// Gets the inverted IL Ranges.<br/> /// Gets the inverted IL Ranges.<br/>
/// E.g.: for (0-9, 11-14, 14-18, 21-25) => (9-11,18-21). /// E.g.: for (0-9, 11-14, 14-18, 21-25) => (9-11,18-21).
@ -172,40 +155,6 @@ namespace ICSharpCode.Decompiler
/// </summary> /// </summary>
public static class CodeMappings public static class CodeMappings
{ {
/// <summary>
/// Create code mapping for a method.
/// </summary>
/// <param name="method">Method to create the mapping for.</param>
/// <param name="codeMappings">Source code mapping storage.</param>
/// <param name="actualMemberReference">The actual member reference.</param>
internal static MemberMapping CreateCodeMapping(
this MethodDefinition member,
List<MemberMapping> codeMappings,
MemberReference actualMemberReference = null)
{
if (member == null || !member.HasBody)
return null;
if (codeMappings == null)
return null;
// create IL/CSharp code mappings - used in debugger
MemberMapping currentMemberMapping = null;
if (codeMappings.Find(map => map.MetadataToken == member.MetadataToken.ToInt32()) == null) {
currentMemberMapping = new MemberMapping() {
MetadataToken = member.MetadataToken.ToInt32(),
MemberCodeMappings = new List<SourceCodeMapping>(),
MemberReference = actualMemberReference ?? member,
CodeSize = member.Body.CodeSize
};
codeMappings.Add(currentMemberMapping);
}
return currentMemberMapping;
}
/// <summary> /// <summary>
/// Gets source code mapping and metadata token based on type name and line number. /// Gets source code mapping and metadata token based on type name and line number.
/// </summary> /// </summary>
@ -215,19 +164,17 @@ namespace ICSharpCode.Decompiler
/// <param name="metadataToken">Metadata token.</param> /// <param name="metadataToken">Metadata token.</param>
/// <returns></returns> /// <returns></returns>
public static SourceCodeMapping GetInstructionByLineNumber( public static SourceCodeMapping GetInstructionByLineNumber(
this List<MemberMapping> codeMappings, this MemberMapping codeMapping,
int lineNumber, int lineNumber,
out int metadataToken) out int metadataToken)
{ {
if (codeMappings == null) if (codeMapping == null)
throw new ArgumentException("CodeMappings storage must be valid!"); throw new ArgumentException("CodeMappings storage must be valid!");
foreach (var maping in codeMappings) { var map = codeMapping.MemberCodeMappings.Find(m => m.StartLocation.Line == lineNumber);
var map = maping.MemberCodeMappings.Find(m => m.SourceCodeLine == lineNumber); if (map != null) {
if (map != null) { metadataToken = codeMapping.MetadataToken;
metadataToken = maping.MetadataToken; return map;
return map;
}
} }
metadataToken = 0; metadataToken = 0;
@ -243,30 +190,24 @@ namespace ICSharpCode.Decompiler
/// <param name="isMatch">True, if perfect match.</param> /// <param name="isMatch">True, if perfect match.</param>
/// <returns>A code mapping.</returns> /// <returns>A code mapping.</returns>
public static SourceCodeMapping GetInstructionByTokenAndOffset( public static SourceCodeMapping GetInstructionByTokenAndOffset(
this List<MemberMapping> codeMappings, this MemberMapping codeMapping,
int token, int ilOffset,
int ilOffset,
out bool isMatch) out bool isMatch)
{ {
isMatch = false; isMatch = false;
if (codeMappings == null) if (codeMapping == null)
throw new ArgumentNullException("CodeMappings storage must be valid!"); throw new ArgumentNullException("CodeMappings storage must be valid!");
var maping = codeMappings.Find(m => m.MetadataToken == token);
if (maping == null)
return null;
// try find an exact match // try find an exact match
var map = maping.MemberCodeMappings.Find(m => m.ILInstructionOffset.From <= ilOffset && ilOffset < m.ILInstructionOffset.To); var map = codeMapping.MemberCodeMappings.Find(m => m.ILInstructionOffset.From <= ilOffset && ilOffset < m.ILInstructionOffset.To);
if (map == null) { if (map == null) {
// get the immediate next one // get the immediate next one
map = maping.MemberCodeMappings.Find(m => m.ILInstructionOffset.From > ilOffset); map = codeMapping.MemberCodeMappings.Find(m => m.ILInstructionOffset.From > ilOffset);
isMatch = false; isMatch = false;
if (map == null) if (map == null)
map = maping.MemberCodeMappings.LastOrDefault(); // get the last map = codeMapping.MemberCodeMappings.LastOrDefault(); // get the last
return map; return map;
} }
@ -278,15 +219,14 @@ namespace ICSharpCode.Decompiler
/// <summary> /// <summary>
/// Gets the source code and type name from metadata token and offset. /// Gets the source code and type name from metadata token and offset.
/// </summary> /// </summary>
/// <param name="codeMappings">Code mappings storage.</param> /// <param name="codeMappings">Code mapping storage.</param>
/// <param name="token">Metadata token.</param> /// <param name="token">Metadata token.</param>
/// <param name="ilOffset">IL offset.</param> /// <param name="ilOffset">IL offset.</param>
/// <param name="typeName">Type definition.</param> /// <param name="typeName">Type definition.</param>
/// <param name="line">Line number.</param> /// <param name="line">Line number.</param>
/// <remarks>It is possible to exist to different types from different assemblies with the same metadata token.</remarks> /// <remarks>It is possible to exist to different types from different assemblies with the same metadata token.</remarks>
public static bool GetInstructionByTokenAndOffset( public static bool GetInstructionByTokenAndOffset(
this List<MemberMapping> codeMappings, this MemberMapping mapping,
int token,
int ilOffset, int ilOffset,
out MemberReference member, out MemberReference member,
out int line) out int line)
@ -294,13 +234,9 @@ namespace ICSharpCode.Decompiler
member = null; member = null;
line = 0; line = 0;
if (codeMappings == null)
throw new ArgumentException("CodeMappings storage must be valid!");
var mapping = codeMappings.Find(m => m.MetadataToken == token);
if (mapping == null) if (mapping == null)
return false; throw new ArgumentException("CodeMappings storage must be valid!");
var codeMapping = mapping.MemberCodeMappings.Find( var codeMapping = mapping.MemberCodeMappings.Find(
cm => cm.ILInstructionOffset.From <= ilOffset && ilOffset <= cm.ILInstructionOffset.To - 1); cm => cm.ILInstructionOffset.From <= ilOffset && ilOffset <= cm.ILInstructionOffset.To - 1);
if (codeMapping == null) { if (codeMapping == null) {
@ -313,34 +249,8 @@ namespace ICSharpCode.Decompiler
} }
member = mapping.MemberReference; member = mapping.MemberReference;
line = codeMapping.SourceCodeLine; line = codeMapping.StartLocation.Line;
return true; return true;
} }
} }
/// <summary>
/// Decompilation data. Can be used by other applications to store the decompilation data.
/// </summary>
public class DecompileInformation
{
/// <summary>
/// Gets ot sets the code mappings
/// </summary>
public Dictionary<int, List<MemberMapping>> CodeMappings { get; set; }
/// <summary>
/// Gets or sets the local variables.
/// </summary>
public ConcurrentDictionary<int, IEnumerable<ILVariable>> LocalVariables { get; set; }
/// <summary>
/// Gets the list of MembeReferences that are decompiled (TypeDefinitions, MethodDefinitions, etc)
/// </summary>
public Dictionary<int, MemberReference> DecompiledMemberReferences { get; set; }
/// <summary>
/// Gets (or internal sets) the AST nodes.
/// </summary>
public IEnumerable<AstNode> AstNodes { get; set; }
}
} }

47
src/Libraries/ICSharpCode.Decompiler/DecompilerSettings.cs

@ -41,6 +41,21 @@ namespace ICSharpCode.Decompiler
} }
} }
bool expressionTrees = true;
/// <summary>
/// Decompile expression trees.
/// </summary>
public bool ExpressionTrees {
get { return expressionTrees; }
set {
if (expressionTrees != value) {
expressionTrees = value;
OnPropertyChanged("ExpressionTrees");
}
}
}
bool yieldReturn = true; bool yieldReturn = true;
/// <summary> /// <summary>
@ -224,6 +239,38 @@ namespace ICSharpCode.Decompiler
} }
} }
#region Options to aid VB decompilation
bool introduceIncrementAndDecrement = true;
/// <summary>
/// Gets/Sets whether to use increment and decrement operators
/// </summary>
public bool IntroduceIncrementAndDecrement {
get { return introduceIncrementAndDecrement; }
set {
if (introduceIncrementAndDecrement != value) {
introduceIncrementAndDecrement = value;
OnPropertyChanged("IntroduceIncrementAndDecrement");
}
}
}
bool alwaysGenerateExceptionVariableForCatchBlocks = false;
/// <summary>
/// Gets/Sets whether to always generate exception variables in catch blocks
/// </summary>
public bool AlwaysGenerateExceptionVariableForCatchBlocks {
get { return alwaysGenerateExceptionVariableForCatchBlocks; }
set {
if (alwaysGenerateExceptionVariableForCatchBlocks != value) {
alwaysGenerateExceptionVariableForCatchBlocks = value;
OnPropertyChanged("AlwaysGenerateExceptionVariableForCatchBlocks");
}
}
}
#endregion
public event PropertyChangedEventHandler PropertyChanged; public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName) protected virtual void OnPropertyChanged(string propertyName)

4
src/Libraries/ICSharpCode.Decompiler/Disassembler/DisassemblerHelpers.cs

@ -222,7 +222,7 @@ namespace ICSharpCode.Decompiler.Disassembler
} else { } else {
// The ECMA specification says that ' inside SQString should be ecaped using an octal escape sequence, // The ECMA specification says that ' inside SQString should be ecaped using an octal escape sequence,
// but we follow Microsoft's ILDasm and use \'. // but we follow Microsoft's ILDasm and use \'.
return "'" + NRefactory.CSharp.OutputVisitor.ConvertString(identifier).Replace("'", "\\'") + "'"; return "'" + NRefactory.CSharp.CSharpOutputVisitor.ConvertString(identifier).Replace("'", "\\'") + "'";
} }
} }
@ -353,7 +353,7 @@ namespace ICSharpCode.Decompiler.Disassembler
string s = operand as string; string s = operand as string;
if (s != null) { if (s != null) {
writer.Write("\"" + NRefactory.CSharp.OutputVisitor.ConvertString(s) + "\""); writer.Write("\"" + NRefactory.CSharp.CSharpOutputVisitor.ConvertString(s) + "\"");
} else if (operand is char) { } else if (operand is char) {
writer.Write(((int)(char)operand).ToString()); writer.Write(((int)(char)operand).ToString());
} else if (operand is float) { } else if (operand is float) {

8
src/Libraries/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs

@ -85,13 +85,15 @@ namespace ICSharpCode.Decompiler.Disassembler
WriteStructureBody(new ILStructure(body), branchTargets, ref inst, methodMapping, method.Body.CodeSize); WriteStructureBody(new ILStructure(body), branchTargets, ref inst, methodMapping, method.Body.CodeSize);
} else { } else {
foreach (var inst in method.Body.Instructions) { foreach (var inst in method.Body.Instructions) {
var startLocation = output.Location;
inst.WriteTo(output); inst.WriteTo(output);
if (methodMapping != null) { if (methodMapping != null) {
// add IL code mappings - used in debugger // add IL code mappings - used in debugger
methodMapping.MemberCodeMappings.Add( methodMapping.MemberCodeMappings.Add(
new SourceCodeMapping() { new SourceCodeMapping() {
SourceCodeLine = output.CurrentLine, StartLocation = output.Location,
EndLocation = output.Location,
ILInstructionOffset = new ILRange { From = inst.Offset, To = inst.Next == null ? method.Body.CodeSize : inst.Next.Offset }, ILInstructionOffset = new ILRange { From = inst.Offset, To = inst.Next == null ? method.Body.CodeSize : inst.Next.Offset },
MemberMapping = methodMapping MemberMapping = methodMapping
}); });
@ -188,13 +190,15 @@ namespace ICSharpCode.Decompiler.Disassembler
if (!isFirstInstructionInStructure && (prevInstructionWasBranch || branchTargets.Contains(offset))) { if (!isFirstInstructionInStructure && (prevInstructionWasBranch || branchTargets.Contains(offset))) {
output.WriteLine(); // put an empty line after branches, and in front of branch targets output.WriteLine(); // put an empty line after branches, and in front of branch targets
} }
var startLocation = output.Location;
inst.WriteTo(output); inst.WriteTo(output);
// add IL code mappings - used in debugger // add IL code mappings - used in debugger
if (currentMethodMapping != null) { if (currentMethodMapping != null) {
currentMethodMapping.MemberCodeMappings.Add( currentMethodMapping.MemberCodeMappings.Add(
new SourceCodeMapping() { new SourceCodeMapping() {
SourceCodeLine = output.CurrentLine, StartLocation = startLocation,
EndLocation = output.Location,
ILInstructionOffset = new ILRange { From = inst.Offset, To = inst.Next == null ? codeSize : inst.Next.Offset }, ILInstructionOffset = new ILRange { From = inst.Offset, To = inst.Next == null ? codeSize : inst.Next.Offset },
MemberMapping = currentMethodMapping MemberMapping = currentMethodMapping
}); });

27
src/Libraries/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs

@ -30,7 +30,7 @@ namespace ICSharpCode.Decompiler.Disassembler
/// <summary> /// <summary>
/// Disassembles type and member definitions. /// Disassembles type and member definitions.
/// </summary> /// </summary>
public sealed class ReflectionDisassembler : BaseCodeMappings public sealed class ReflectionDisassembler
{ {
ITextOutput output; ITextOutput output;
CancellationToken cancellationToken; CancellationToken cancellationToken;
@ -45,9 +45,6 @@ namespace ICSharpCode.Decompiler.Disassembler
this.output = output; this.output = output;
this.cancellationToken = cancellationToken; this.cancellationToken = cancellationToken;
this.methodBodyDisassembler = new MethodBodyDisassembler(output, detectControlStructure, cancellationToken); this.methodBodyDisassembler = new MethodBodyDisassembler(output, detectControlStructure, cancellationToken);
this.CodeMappings = new Dictionary<int, List<MemberMapping>>();
this.DecompiledMemberReferences = new Dictionary<int, MemberReference>();
} }
#region Disassemble Method #region Disassemble Method
@ -126,10 +123,10 @@ namespace ICSharpCode.Decompiler.Disassembler
output.Write("pinvokeimpl"); output.Write("pinvokeimpl");
if (method.HasPInvokeInfo && method.PInvokeInfo != null) { if (method.HasPInvokeInfo && method.PInvokeInfo != null) {
PInvokeInfo info = method.PInvokeInfo; PInvokeInfo info = method.PInvokeInfo;
output.Write("(\"" + NRefactory.CSharp.OutputVisitor.ConvertString(info.Module.Name) + "\""); output.Write("(\"" + NRefactory.CSharp.CSharpOutputVisitor.ConvertString(info.Module.Name) + "\"");
if (!string.IsNullOrEmpty(info.EntryPoint) && info.EntryPoint != method.Name) if (!string.IsNullOrEmpty(info.EntryPoint) && info.EntryPoint != method.Name)
output.Write(" as \"" + NRefactory.CSharp.OutputVisitor.ConvertString(info.EntryPoint) + "\""); output.Write(" as \"" + NRefactory.CSharp.CSharpOutputVisitor.ConvertString(info.EntryPoint) + "\"");
if (info.IsNoMangle) if (info.IsNoMangle)
output.Write(" nomangle"); output.Write(" nomangle");
@ -163,7 +160,7 @@ namespace ICSharpCode.Decompiler.Disassembler
output.WriteLine(); output.WriteLine();
output.Indent(); output.Indent();
if (method.ExplicitThis) { if (method.ExplicitThis) {
output.Write("instance explicit "); output.Write("instance explicit ");
} else if (method.HasThis) { } else if (method.HasThis) {
output.Write("instance "); output.Write("instance ");
} }
@ -220,9 +217,9 @@ namespace ICSharpCode.Decompiler.Disassembler
if (method.HasBody) { if (method.HasBody) {
// create IL code mappings - used in debugger // create IL code mappings - used in debugger
CreateCodeMappings(method.MetadataToken.ToInt32(), currentMember); MemberMapping methodMapping = new MemberMapping(method);
MemberMapping methodMapping = method.CreateCodeMapping(this.CodeMappings[method.MetadataToken.ToInt32()], currentMember);
methodBodyDisassembler.Disassemble(method.Body, methodMapping); methodBodyDisassembler.Disassemble(method.Body, methodMapping);
output.AddDebuggerMemberMapping(methodMapping);
} }
CloseBlock("end of method " + DisassemblerHelpers.Escape(method.DeclaringType.Name) + "::" + DisassemblerHelpers.Escape(method.Name)); CloseBlock("end of method " + DisassemblerHelpers.Escape(method.DeclaringType.Name) + "::" + DisassemblerHelpers.Escape(method.Name));
@ -344,7 +341,7 @@ namespace ICSharpCode.Decompiler.Disassembler
output.Write(" = "); output.Write(" = ");
if (na.Argument.Value is string) { if (na.Argument.Value is string) {
// secdecls use special syntax for strings // secdecls use special syntax for strings
output.Write("string('{0}')", NRefactory.CSharp.OutputVisitor.ConvertString((string)na.Argument.Value).Replace("'", "\'")); output.Write("string('{0}')", NRefactory.CSharp.CSharpOutputVisitor.ConvertString((string)na.Argument.Value).Replace("'", "\'"));
} else { } else {
WriteConstant(na.Argument.Value); WriteConstant(na.Argument.Value);
} }
@ -572,10 +569,10 @@ namespace ICSharpCode.Decompiler.Disassembler
if (cmi == null) if (cmi == null)
goto default; goto default;
output.Write("custom(\"{0}\", \"{1}\"", output.Write("custom(\"{0}\", \"{1}\"",
NRefactory.CSharp.OutputVisitor.ConvertString(cmi.ManagedType.FullName), NRefactory.CSharp.CSharpOutputVisitor.ConvertString(cmi.ManagedType.FullName),
NRefactory.CSharp.OutputVisitor.ConvertString(cmi.Cookie)); NRefactory.CSharp.CSharpOutputVisitor.ConvertString(cmi.Cookie));
if (cmi.Guid != Guid.Empty || !string.IsNullOrEmpty(cmi.UnmanagedType)) { if (cmi.Guid != Guid.Empty || !string.IsNullOrEmpty(cmi.UnmanagedType)) {
output.Write(", \"{0}\", \"{1}\"", cmi.Guid.ToString(), NRefactory.CSharp.OutputVisitor.ConvertString(cmi.UnmanagedType)); output.Write(", \"{0}\", \"{1}\"", cmi.Guid.ToString(), NRefactory.CSharp.CSharpOutputVisitor.ConvertString(cmi.UnmanagedType));
} }
output.Write(')'); output.Write(')');
break; break;
@ -676,9 +673,6 @@ namespace ICSharpCode.Decompiler.Disassembler
public void DisassembleField(FieldDefinition field) public void DisassembleField(FieldDefinition field)
{ {
// create mappings for decompiled fields only
this.DecompiledMemberReferences.Add(field.MetadataToken.ToInt32(), field);
output.WriteDefinition(".field ", field); output.WriteDefinition(".field ", field);
WriteEnum(field.Attributes & FieldAttributes.FieldAccessMask, fieldVisibility); WriteEnum(field.Attributes & FieldAttributes.FieldAccessMask, fieldVisibility);
const FieldAttributes hasXAttributes = FieldAttributes.HasDefault | FieldAttributes.HasFieldMarshal | FieldAttributes.HasFieldRVA; const FieldAttributes hasXAttributes = FieldAttributes.HasDefault | FieldAttributes.HasFieldMarshal | FieldAttributes.HasFieldRVA;
@ -749,6 +743,7 @@ namespace ICSharpCode.Decompiler.Disassembler
{ {
if (method == null) if (method == null)
return; return;
output.Write(keyword); output.Write(keyword);
output.Write(' '); output.Write(' ');
method.WriteTo(output); method.WriteTo(output);

2
src/Libraries/ICSharpCode.Decompiler/FlowAnalysis/SsaFormBuilder.cs

@ -129,7 +129,7 @@ namespace ICSharpCode.Decompiler.FlowAnalysis
continue; continue;
} }
int popCount = inst.GetPopDelta() ?? stackSize; int popCount = inst.GetPopDelta(method) ?? stackSize;
stackSize -= popCount; stackSize -= popCount;
if (stackSize < 0) if (stackSize < 0)
throw new InvalidProgramException("IL stack underflow"); throw new InvalidProgramException("IL stack underflow");

28
src/Libraries/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -19,8 +19,7 @@
<PlatformTarget>AnyCPU</PlatformTarget> <PlatformTarget>AnyCPU</PlatformTarget>
<RegisterForComInterop>False</RegisterForComInterop> <RegisterForComInterop>False</RegisterForComInterop>
<GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies> <GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies>
<BaseAddress>4194304</BaseAddress> <BaseAddress>448462848</BaseAddress>
<FileAlignment>4096</FileAlignment>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<OutputPath>bin\Debug\</OutputPath> <OutputPath>bin\Debug\</OutputPath>
@ -32,8 +31,8 @@
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' "> <PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<OutputPath>bin\Release\</OutputPath> <OutputPath>bin\Release\</OutputPath>
<DebugSymbols>False</DebugSymbols> <DebugSymbols>true</DebugSymbols>
<DebugType>None</DebugType> <DebugType>PdbOnly</DebugType>
<Optimize>True</Optimize> <Optimize>True</Optimize>
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow> <CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
<DefineConstants>TRACE</DefineConstants> <DefineConstants>TRACE</DefineConstants>
@ -49,9 +48,7 @@
</Reference> </Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="..\..\Main\GlobalAssemblyInfo.cs"> <Compile Include="Ast\Annotations.cs" />
<Link>Properties\GlobalAssemblyInfo.cs</Link>
</Compile>
<Compile Include="Ast\AstBuilder.cs" /> <Compile Include="Ast\AstBuilder.cs" />
<Compile Include="Ast\AstMethodBodyBuilder.cs" /> <Compile Include="Ast\AstMethodBodyBuilder.cs" />
<Compile Include="Ast\CecilTypeResolveContext.cs" /> <Compile Include="Ast\CecilTypeResolveContext.cs" />
@ -64,9 +61,12 @@
<Compile Include="Ast\Transforms\CombineQueryExpressions.cs" /> <Compile Include="Ast\Transforms\CombineQueryExpressions.cs" />
<Compile Include="Ast\Transforms\ContextTrackingVisitor.cs" /> <Compile Include="Ast\Transforms\ContextTrackingVisitor.cs" />
<Compile Include="Ast\Transforms\ConvertConstructorCallIntoInitializer.cs" /> <Compile Include="Ast\Transforms\ConvertConstructorCallIntoInitializer.cs" />
<Compile Include="Ast\Transforms\CustomPatterns.cs" />
<Compile Include="Ast\Transforms\DecimalConstantTransform.cs" /> <Compile Include="Ast\Transforms\DecimalConstantTransform.cs" />
<Compile Include="Ast\Transforms\DeclareVariables.cs" /> <Compile Include="Ast\Transforms\DeclareVariables.cs" />
<Compile Include="Ast\Transforms\DelegateConstruction.cs" /> <Compile Include="Ast\Transforms\DelegateConstruction.cs" />
<Compile Include="Ast\Transforms\ExpressionTreeConverter.cs" />
<Compile Include="Ast\Transforms\FlattenSwitchBlocks.cs" />
<Compile Include="Ast\Transforms\IntroduceExtensionMethods.cs" /> <Compile Include="Ast\Transforms\IntroduceExtensionMethods.cs" />
<Compile Include="Ast\Transforms\IntroduceQueryExpressions.cs" /> <Compile Include="Ast\Transforms\IntroduceQueryExpressions.cs" />
<Compile Include="Ast\Transforms\IntroduceUnsafeModifier.cs" /> <Compile Include="Ast\Transforms\IntroduceUnsafeModifier.cs" />
@ -98,6 +98,7 @@
<Compile Include="FlowAnalysis\SsaOptimization.cs" /> <Compile Include="FlowAnalysis\SsaOptimization.cs" />
<Compile Include="FlowAnalysis\SsaVariable.cs" /> <Compile Include="FlowAnalysis\SsaVariable.cs" />
<Compile Include="FlowAnalysis\TransformToSsa.cs" /> <Compile Include="FlowAnalysis\TransformToSsa.cs" />
<Compile Include="ILAst\LiftedOperators.cs" />
<Compile Include="ILAst\InitializerPeepholeTransforms.cs" /> <Compile Include="ILAst\InitializerPeepholeTransforms.cs" />
<Compile Include="ILAst\DefaultDictionary.cs" /> <Compile Include="ILAst\DefaultDictionary.cs" />
<Compile Include="ILAst\GotoRemoval.cs" /> <Compile Include="ILAst\GotoRemoval.cs" />
@ -116,23 +117,22 @@
<Compile Include="PlainTextOutput.cs" /> <Compile Include="PlainTextOutput.cs" />
<Compile Include="ReferenceResolvingException.cs" /> <Compile Include="ReferenceResolvingException.cs" />
<Compile Include="TextOutputWriter.cs" /> <Compile Include="TextOutputWriter.cs" />
<None Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Mono.Cecil\Mono.Cecil.csproj"> <ProjectReference Include="..\Mono.Cecil\Mono.Cecil.csproj">
<Project>{D68133BD-1E63-496E-9EDE-4FBDBF77B486}</Project> <Project>{D68133BD-1E63-496E-9EDE-4FBDBF77B486}</Project>
<Name>Mono.Cecil</Name> <Name>Mono.Cecil</Name>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\NewNRefactory\ICSharpCode.NRefactory.CSharp\ICSharpCode.NRefactory.CSharp.csproj">
<Project>{53DCA265-3C3C-42F9-B647-F72BA678122B}</Project>
<Name>ICSharpCode.NRefactory.CSharp</Name>
</ProjectReference>
<ProjectReference Include="..\NewNRefactory\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj"> <ProjectReference Include="..\NewNRefactory\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj">
<Project>{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}</Project> <Project>{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}</Project>
<Name>ICSharpCode.NRefactory</Name> <Name>ICSharpCode.NRefactory</Name>
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup />
<Folder Include="Ast" />
<Folder Include="Ast\Transforms" />
<Folder Include="Disassembler" />
<Folder Include="ILAst" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
</Project> </Project>

77
src/Libraries/ICSharpCode.Decompiler/ILAst/ILAstBuilder.cs

@ -62,7 +62,7 @@ namespace ICSharpCode.Decompiler.ILAst
/// <summary> Immutable </summary> /// <summary> Immutable </summary>
class VariableSlot class VariableSlot
{ {
public readonly ByteCode[] StoredBy; // One of those public readonly ByteCode[] StoredBy; // One of those
public readonly bool StoredByAll; // Overestimate which is useful for exceptional control flow. public readonly bool StoredByAll; // Overestimate which is useful for exceptional control flow.
@ -224,10 +224,13 @@ namespace ICSharpCode.Decompiler.ILAst
// Virtual instructions to load exception on stack // Virtual instructions to load exception on stack
Dictionary<ExceptionHandler, ByteCode> ldexceptions = new Dictionary<ExceptionHandler, ILAstBuilder.ByteCode>(); Dictionary<ExceptionHandler, ByteCode> ldexceptions = new Dictionary<ExceptionHandler, ILAstBuilder.ByteCode>();
public List<ILNode> Build(MethodDefinition methodDef, bool optimize) DecompilerContext context;
public List<ILNode> Build(MethodDefinition methodDef, bool optimize, DecompilerContext context)
{ {
this.methodDef = methodDef; this.methodDef = methodDef;
this.optimize = optimize; this.optimize = optimize;
this.context = context;
if (methodDef.Body.Instructions.Count == 0) return new List<ILNode>(); if (methodDef.Body.Instructions.Count == 0) return new List<ILNode>();
@ -260,7 +263,7 @@ namespace ICSharpCode.Decompiler.ILAst
EndOffset = inst.Next != null ? inst.Next.Offset : methodDef.Body.CodeSize, EndOffset = inst.Next != null ? inst.Next.Offset : methodDef.Body.CodeSize,
Code = code, Code = code,
Operand = operand, Operand = operand,
PopCount = inst.GetPopDelta(), PopCount = inst.GetPopDelta(methodDef),
PushCount = inst.GetPushDelta() PushCount = inst.GetPushDelta()
}; };
if (prefixes != null) { if (prefixes != null) {
@ -336,9 +339,10 @@ namespace ICSharpCode.Decompiler.ILAst
// Calculate new variable state // Calculate new variable state
VariableSlot[] newVariableState = VariableSlot.CloneVariableState(byteCode.VariablesBefore); VariableSlot[] newVariableState = VariableSlot.CloneVariableState(byteCode.VariablesBefore);
if (byteCode.Code == ILCode.Stloc) { if (byteCode.Code == ILCode.Stloc || byteCode.Code == ILCode.Ldloca) {
int varIndex = ((VariableReference)byteCode.Operand).Index; int varIndex = ((VariableReference)byteCode.Operand).Index;
newVariableState[varIndex] = new VariableSlot(byteCode); newVariableState[varIndex] = byteCode.Code == ILCode.Stloc || byteCode.Next.Code == ILCode.Initobj ?
new VariableSlot(byteCode) : new VariableSlot(newVariableState[varIndex].StoredBy.Union(byteCode), false);
} }
// After the leave, finally block might have touched the variables // After the leave, finally block might have touched the variables
@ -351,7 +355,7 @@ namespace ICSharpCode.Decompiler.ILAst
if (!byteCode.Code.IsUnconditionalControlFlow()) { if (!byteCode.Code.IsUnconditionalControlFlow()) {
if (exceptionHandlerStarts.Contains(byteCode.Next)) { if (exceptionHandlerStarts.Contains(byteCode.Next)) {
// Do not fall though down to exception handler // 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 // It is invalid IL as per ECMA-335 §12.4.2.8.1, but some obfuscators produce it
} else { } else {
branchTargets.Add(byteCode.Next); branchTargets.Add(byteCode.Next);
} }
@ -520,8 +524,12 @@ namespace ICSharpCode.Decompiler.ILAst
for(int variableIndex = 0; variableIndex < varCount; variableIndex++) { for(int variableIndex = 0; variableIndex < varCount; variableIndex++) {
// Find all stores and loads for this variable // Find all stores and loads for this variable
List<ByteCode> stores = body.Where(b => b.Code == ILCode.Stloc && b.Operand is VariableDefinition && b.OperandAsVariable.Index == variableIndex).ToList(); var stores = body.Where(b => (b.Code == ILCode.Stloc || b.Code == ILCode.Ldloca) && b.Operand is VariableDefinition && b.OperandAsVariable.Index == variableIndex).ToList();
List<ByteCode> loads = body.Where(b => (b.Code == ILCode.Ldloc || b.Code == ILCode.Ldloca) && b.Operand is VariableDefinition && b.OperandAsVariable.Index == variableIndex).ToList(); // ldloca on an uninitialized variable or followed by initobj isn't considered a load
var loads = body.Where(b =>
(b.Code == ILCode.Ldloc || (b.Code == ILCode.Ldloca && b.Next.Code != ILCode.Initobj &&
(b.VariablesBefore[variableIndex].StoredBy.Length != 0 || b.VariablesBefore[variableIndex].StoredByAll)))
&& b.Operand is VariableDefinition && b.OperandAsVariable.Index == variableIndex).ToList();
TypeReference varType = methodDef.Body.Variables[variableIndex].VariableType; TypeReference varType = methodDef.Body.Variables[variableIndex].VariableType;
List<VariableInfo> newVars; List<VariableInfo> newVars;
@ -529,8 +537,7 @@ namespace ICSharpCode.Decompiler.ILAst
bool isPinned = methodDef.Body.Variables[variableIndex].IsPinned; bool isPinned = methodDef.Body.Variables[variableIndex].IsPinned;
// If the variable is pinned, use single variable. // If the variable is pinned, use single variable.
// If any of the loads is from "all", use single variable // If any of the loads is from "all", use single variable
// If any of the loads is ldloca, fallback to single variable as well if (isPinned || loads.Any(b => b.VariablesBefore[variableIndex].StoredByAll)) {
if (isPinned || loads.Any(b => b.VariablesBefore[variableIndex].StoredByAll || b.Code == ILCode.Ldloca)) {
newVars = new List<VariableInfo>(1) { new VariableInfo() { newVars = new List<VariableInfo>(1) { new VariableInfo() {
Variable = new ILVariable() { Variable = new ILVariable() {
Name = "var_" + variableIndex, Name = "var_" + variableIndex,
@ -542,7 +549,12 @@ namespace ICSharpCode.Decompiler.ILAst
}}; }};
} else { } else {
// Create a new variable for each store // Create a new variable for each store
newVars = stores.Select(st => new VariableInfo() { newVars = stores.Where(st =>
{
if (st.Code == ILCode.Stloc || st.Next.Code == ILCode.Initobj) return true;
var storedBy = st.VariablesBefore[variableIndex].StoredBy;
return storedBy.Length == 0 || storedBy[0] == st;
}).Select(st => new VariableInfo() {
Variable = new ILVariable() { Variable = new ILVariable() {
Name = "var_" + variableIndex + "_" + st.Offset.ToString("X2"), Name = "var_" + variableIndex + "_" + st.Offset.ToString("X2"),
Type = varType, Type = varType,
@ -579,14 +591,16 @@ namespace ICSharpCode.Decompiler.ILAst
} else if (storedBy.Length == 1) { } else if (storedBy.Length == 1) {
VariableInfo newVar = newVars.Single(v => v.Stores.Contains(storedBy[0])); VariableInfo newVar = newVars.Single(v => v.Stores.Contains(storedBy[0]));
newVar.Loads.Add(load); newVar.Loads.Add(load);
if (load.Code == ILCode.Ldloca) newVar.Stores.Add(load);
} else { } else {
List<VariableInfo> mergeVars = newVars.Where(v => v.Stores.Union(storedBy).Any()).ToList(); List<VariableInfo> mergeVars = newVars.Where(v => v.Stores.Intersect(storedBy).Any()).ToList();
VariableInfo mergedVar = new VariableInfo() { VariableInfo mergedVar = new VariableInfo() {
Variable = mergeVars[0].Variable, Variable = mergeVars[0].Variable,
Stores = mergeVars.SelectMany(v => v.Stores).ToList(), Stores = mergeVars.SelectMany(v => v.Stores).ToList(),
Loads = mergeVars.SelectMany(v => v.Loads).ToList() Loads = mergeVars.SelectMany(v => v.Loads).ToList()
}; };
mergedVar.Loads.Add(load); mergedVar.Loads.Add(load);
if (load.Code == ILCode.Ldloca) mergedVar.Stores.Add(load);
newVars = newVars.Except(mergeVars).ToList(); newVars = newVars.Except(mergeVars).ToList();
newVars.Add(mergedVar); newVars.Add(mergedVar);
} }
@ -629,6 +643,10 @@ namespace ICSharpCode.Decompiler.ILAst
foreach (ParameterDefinition p in methodDef.Parameters) { foreach (ParameterDefinition p in methodDef.Parameters) {
this.Parameters.Add(new ILVariable { Type = p.ParameterType, Name = p.Name, OriginalParameter = p }); this.Parameters.Add(new ILVariable { Type = p.ParameterType, Name = p.Name, OriginalParameter = p });
} }
if (this.Parameters.Count > 0 && (methodDef.IsSetter || methodDef.IsAddOn || methodDef.IsRemoveOn)) {
// last parameter must be 'value', so rename it
this.Parameters.Last().Name = "value";
}
foreach (ByteCode byteCode in body) { foreach (ByteCode byteCode in body) {
ParameterDefinition p; ParameterDefinition p;
switch (byteCode.Code) { switch (byteCode.Code) {
@ -701,8 +719,9 @@ namespace ICSharpCode.Decompiler.ILAst
}; };
// Handle the automatically pushed exception on the stack // Handle the automatically pushed exception on the stack
ByteCode ldexception = ldexceptions[eh]; ByteCode ldexception = ldexceptions[eh];
if (ldexception.StoreTo.Count == 0) { if (ldexception.StoreTo == null || ldexception.StoreTo.Count == 0) {
throw new Exception("Exception should be consumed by something"); // Exception is not used
catchBlock.ExceptionVariable = null;
} else if (ldexception.StoreTo.Count == 1) { } else if (ldexception.StoreTo.Count == 1) {
ILExpression first = catchBlock.Body[0] as ILExpression; ILExpression first = catchBlock.Body[0] as ILExpression;
if (first != null && if (first != null &&
@ -711,7 +730,10 @@ namespace ICSharpCode.Decompiler.ILAst
first.Arguments[0].Operand == ldexception.StoreTo[0]) first.Arguments[0].Operand == ldexception.StoreTo[0])
{ {
// The exception is just poped - optimize it all away; // The exception is just poped - optimize it all away;
catchBlock.ExceptionVariable = null; 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); catchBlock.Body.RemoveAt(0);
} else { } else {
catchBlock.ExceptionVariable = ldexception.StoreTo[0]; catchBlock.ExceptionVariable = ldexception.StoreTo[0];
@ -778,7 +800,7 @@ namespace ICSharpCode.Decompiler.ILAst
StackSlot slot = byteCode.StackBefore[i]; StackSlot slot = byteCode.StackBefore[i];
expr.Arguments.Add(new ILExpression(ILCode.Ldloc, slot.LoadFrom)); expr.Arguments.Add(new ILExpression(ILCode.Ldloc, slot.LoadFrom));
} }
// Store the result to temporary variable(s) if needed // Store the result to temporary variable(s) if needed
if (byteCode.StoreTo == null || byteCode.StoreTo.Count == 0) { if (byteCode.StoreTo == null || byteCode.StoreTo.Count == 0) {
ast.Add(expr); ast.Add(expr);
@ -808,15 +830,34 @@ namespace ICSharpCode.Decompiler.ILAst
list.RemoveRange(start, count); list.RemoveRange(start, count);
return ret; return ret;
} }
public static T[] Union<T>(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, res, a.Length);
res[res.Length - 1] = b;
return res;
}
public static T[] Union<T>(this T[] a, T[] b) public static T[] Union<T>(this T[] a, T[] b)
{ {
if (a == b)
return a;
if (a.Length == 0) if (a.Length == 0)
return b; return b;
if (b.Length == 0) if (b.Length == 0)
return a; return a;
if (a.Length == 1 && b.Length == 1 && a[0].Equals(b[0])) if (a.Length == 1) {
return a; 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(); return Enumerable.Union(a, b).ToArray();
} }
} }

50
src/Libraries/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

@ -42,15 +42,18 @@ namespace ICSharpCode.Decompiler.ILAst
SimplifyTernaryOperator, SimplifyTernaryOperator,
SimplifyNullCoalescing, SimplifyNullCoalescing,
JoinBasicBlocks, JoinBasicBlocks,
SimplifyLogicNot,
SimplifyShiftOperators, SimplifyShiftOperators,
TransformDecimalCtorToConstant, TransformDecimalCtorToConstant,
SimplifyLdObjAndStObj, SimplifyLdObjAndStObj,
SimplifyCustomShortCircuit, SimplifyCustomShortCircuit,
SimplifyLiftedOperators,
TransformArrayInitializers, TransformArrayInitializers,
TransformMultidimensionalArrayInitializers, TransformMultidimensionalArrayInitializers,
TransformObjectInitializers, TransformObjectInitializers,
MakeAssignmentExpression, MakeAssignmentExpression,
IntroducePostIncrement, IntroducePostIncrement,
InlineExpressionTreeParameterDeclarations,
InlineVariables2, InlineVariables2,
FindLoops, FindLoops,
FindConditions, FindConditions,
@ -134,6 +137,9 @@ namespace ICSharpCode.Decompiler.ILAst
if (abortBeforeStep == ILAstOptimizationStep.JoinBasicBlocks) return; if (abortBeforeStep == ILAstOptimizationStep.JoinBasicBlocks) return;
modified |= block.RunOptimization(new SimpleControlFlow(context, method).JoinBasicBlocks); modified |= block.RunOptimization(new SimpleControlFlow(context, method).JoinBasicBlocks);
if (abortBeforeStep == ILAstOptimizationStep.SimplifyLogicNot) return;
modified |= block.RunOptimization(SimplifyLogicNot);
if (abortBeforeStep == ILAstOptimizationStep.SimplifyShiftOperators) return; if (abortBeforeStep == ILAstOptimizationStep.SimplifyShiftOperators) return;
modified |= block.RunOptimization(SimplifyShiftOperators); modified |= block.RunOptimization(SimplifyShiftOperators);
@ -146,6 +152,9 @@ namespace ICSharpCode.Decompiler.ILAst
if (abortBeforeStep == ILAstOptimizationStep.SimplifyCustomShortCircuit) return; if (abortBeforeStep == ILAstOptimizationStep.SimplifyCustomShortCircuit) return;
modified |= block.RunOptimization(new SimpleControlFlow(context, method).SimplifyCustomShortCircuit); modified |= block.RunOptimization(new SimpleControlFlow(context, method).SimplifyCustomShortCircuit);
if (abortBeforeStep == ILAstOptimizationStep.SimplifyLiftedOperators) return;
modified |= block.RunOptimization(SimplifyLiftedOperators);
if (abortBeforeStep == ILAstOptimizationStep.TransformArrayInitializers) return; if (abortBeforeStep == ILAstOptimizationStep.TransformArrayInitializers) return;
modified |= block.RunOptimization(TransformArrayInitializers); modified |= block.RunOptimization(TransformArrayInitializers);
@ -163,6 +172,11 @@ namespace ICSharpCode.Decompiler.ILAst
if (abortBeforeStep == ILAstOptimizationStep.IntroducePostIncrement) return; if (abortBeforeStep == ILAstOptimizationStep.IntroducePostIncrement) return;
modified |= block.RunOptimization(IntroducePostIncrement); modified |= block.RunOptimization(IntroducePostIncrement);
if (abortBeforeStep == ILAstOptimizationStep.InlineExpressionTreeParameterDeclarations) return;
if (context.Settings.ExpressionTrees) {
modified |= block.RunOptimization(InlineExpressionTreeParameterDeclarations);
}
if (abortBeforeStep == ILAstOptimizationStep.InlineVariables2) return; if (abortBeforeStep == ILAstOptimizationStep.InlineVariables2) return;
modified |= new ILInlining(method).InlineAllInBlock(block); modified |= new ILInlining(method).InlineAllInBlock(block);
new ILInlining(method).CopyPropagation(); new ILInlining(method).CopyPropagation();
@ -240,6 +254,7 @@ namespace ICSharpCode.Decompiler.ILAst
/// <summary> /// <summary>
/// Removes redundatant Br, Nop, Dup, Pop /// Removes redundatant Br, Nop, Dup, Pop
/// Ignore arguments of 'leave'
/// </summary> /// </summary>
/// <param name="method"></param> /// <param name="method"></param>
void RemoveRedundantCode(ILBlock method) void RemoveRedundantCode(ILBlock method)
@ -278,6 +293,13 @@ namespace ICSharpCode.Decompiler.ILAst
block.Body = newBody; block.Body = newBody;
} }
// Ignore arguments of 'leave'
foreach (ILExpression expr in method.GetSelfAndChildrenRecursive<ILExpression>(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 // 'dup' removal
foreach (ILExpression expr in method.GetSelfAndChildrenRecursive<ILExpression>()) { foreach (ILExpression expr in method.GetSelfAndChildrenRecursive<ILExpression>()) {
for (int i = 0; i < expr.Arguments.Count; i++) { for (int i = 0; i < expr.Arguments.Count; i++) {
@ -299,27 +321,30 @@ namespace ICSharpCode.Decompiler.ILAst
for (int i = 0; i < block.Body.Count; i++) { for (int i = 0; i < block.Body.Count; i++) {
ILExpression expr = block.Body[i] as ILExpression; ILExpression expr = block.Body[i] as ILExpression;
if (expr != null && expr.Prefixes == null) { if (expr != null && expr.Prefixes == null) {
ILCode op;
switch(expr.Code) { switch(expr.Code) {
case ILCode.Switch: case ILCode.Switch:
case ILCode.Brtrue: case ILCode.Brtrue:
expr.Arguments.Single().ILRanges.AddRange(expr.ILRanges); expr.Arguments.Single().ILRanges.AddRange(expr.ILRanges);
expr.ILRanges.Clear(); expr.ILRanges.Clear();
continue; continue;
case ILCode.__Brfalse: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, expr.Arguments.Single())); break; case ILCode.__Brfalse: op = ILCode.LogicNot; break;
case ILCode.__Beq: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Ceq, null, expr.Arguments)); break; case ILCode.__Beq: op = ILCode.Ceq; break;
case ILCode.__Bne_Un: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Ceq, null, expr.Arguments))); break; case ILCode.__Bne_Un: op = ILCode.Cne; break;
case ILCode.__Bgt: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Cgt, null, expr.Arguments)); break; case ILCode.__Bgt: op = ILCode.Cgt; break;
case ILCode.__Bgt_Un: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Cgt_Un, null, expr.Arguments)); break; case ILCode.__Bgt_Un: op = ILCode.Cgt_Un; break;
case ILCode.__Ble: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Cgt, null, expr.Arguments))); break; case ILCode.__Ble: op = ILCode.Cle; break;
case ILCode.__Ble_Un: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Cgt_Un, null, expr.Arguments))); break; case ILCode.__Ble_Un: op = ILCode.Cle_Un; break;
case ILCode.__Blt: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Clt, null, expr.Arguments)); break; case ILCode.__Blt: op = ILCode.Clt; break;
case ILCode.__Blt_Un: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.Clt_Un, null, expr.Arguments)); break; case ILCode.__Blt_Un: op = ILCode.Clt_Un; break;
case ILCode.__Bge: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Clt, null, expr.Arguments))); break; case ILCode.__Bge: op = ILCode.Cge; break;
case ILCode.__Bge_Un: block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, new ILExpression(ILCode.LogicNot, null, new ILExpression(ILCode.Clt_Un, null, expr.Arguments))); break; case ILCode.__Bge_Un: op = ILCode.Cge_Un; break;
default: default:
continue; continue;
} }
((ILExpression)block.Body[i]).Arguments.Single().ILRanges.AddRange(expr.ILRanges); var newExpr = new ILExpression(op, null, expr.Arguments);
block.Body[i] = new ILExpression(ILCode.Brtrue, expr.Operand, newExpr);
newExpr.ILRanges = expr.ILRanges;
} }
} }
} }
@ -713,6 +738,7 @@ namespace ICSharpCode.Decompiler.ILAst
case ILCode.Ldc_I8: case ILCode.Ldc_I8:
case ILCode.Ldc_R4: case ILCode.Ldc_R4:
case ILCode.Ldc_R8: case ILCode.Ldc_R8:
case ILCode.Ldc_Decimal:
return true; return true;
default: default:
return false; return false;

29
src/Libraries/ICSharpCode.Decompiler/ILAst/ILCodes.cs

@ -247,12 +247,22 @@ namespace ICSharpCode.Decompiler.ILAst
Readonly, Readonly,
// Virtual codes - defined for convenience // Virtual codes - defined for convenience
Cne,
Cge,
Cge_Un,
Cle,
Cle_Un,
Ldexception, // Operand holds the CatchType for catch handler, null for filter Ldexception, // Operand holds the CatchType for catch handler, null for filter
LogicNot, LogicNot,
LogicAnd, LogicAnd,
LogicOr, LogicOr,
NullCoalescing, NullCoalescing,
InitArray, // Array Initializer InitArray, // Array Initializer
/// <summary>
/// Defines a barrier between the parent expression and the argument expression that prevents combining them
/// </summary>
Wrap,
// new Class { Prop = 1, Collection = { { 2, 3 }, {4, 5} }} // new Class { Prop = 1, Collection = { { 2, 3 }, {4, 5} }}
// is represented as: // is represented as:
@ -306,7 +316,24 @@ namespace ICSharpCode.Decompiler.ILAst
/// Used for postincrement for properties, and to represent the Address() method on multi-dimensional arrays. /// 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(...))" /// Also used when inlining a method call on a value type: "stloc(v, ...); call(M, ldloca(v));" becomes "call(M, AddressOf(...))"
/// </remarks> /// </remarks>
AddressOf AddressOf,
/// <summary>Simulates getting the value of a lifted operator's nullable argument</summary>
/// <remarks>
/// 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(...), ...))"
/// </remarks>
ValueOf,
/// <summary>Simulates creating a new nullable value from a value type argument</summary>
/// <remarks>
/// 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(...), ...))"
/// </remarks>
NullableOf,
/// <summary>
/// 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.
/// </summary>
ExpressionTreeParameterDeclarations
} }
public static class ILCodeUtil public static class ILCodeUtil

9
src/Libraries/ICSharpCode.Decompiler/ILAst/ILInlining.cs

@ -406,7 +406,7 @@ namespace ICSharpCode.Decompiler.ILAst
} }
/// <summary> /// <summary>
/// Determines whether it is save to move 'expressionBeingMoved' past 'expr' /// Determines whether it is safe to move 'expressionBeingMoved' past 'expr'
/// </summary> /// </summary>
bool IsSafeForInlineOver(ILExpression expr, ILExpression expressionBeingMoved) bool IsSafeForInlineOver(ILExpression expr, ILExpression expressionBeingMoved)
{ {
@ -427,6 +427,9 @@ namespace ICSharpCode.Decompiler.ILAst
case ILCode.Ldflda: case ILCode.Ldflda:
case ILCode.Ldsflda: case ILCode.Ldsflda:
case ILCode.Ldelema: case ILCode.Ldelema:
case ILCode.AddressOf:
case ILCode.ValueOf:
case ILCode.NullableOf:
// address-loading instructions are safe if their arguments are safe // address-loading instructions are safe if their arguments are safe
foreach (ILExpression arg in expr.Arguments) { foreach (ILExpression arg in expr.Arguments) {
if (!IsSafeForInlineOver(arg, expressionBeingMoved)) if (!IsSafeForInlineOver(arg, expressionBeingMoved))
@ -434,8 +437,8 @@ namespace ICSharpCode.Decompiler.ILAst
} }
return true; return true;
default: default:
// abort, inlining is not possible // instructions with no side-effects are safe (except for Ldloc and Ldloca which are handled separately)
return false; return expr.HasNoSideEffects();
} }
} }

528
src/Libraries/ICSharpCode.Decompiler/ILAst/LiftedOperators.cs

@ -0,0 +1,528 @@
// 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<ILNode> 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)
{
this.Arguments = arguments;
}
public virtual bool Match(PatternMatcher pm, ILExpression e)
{
if (e.Arguments.Count != this.Arguments.Length || e.Prefixes != null) return false;
for (int i = 0; i < this.Arguments.Length; i++)
if (!this.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 == this.code && base.Match(pm, e);
}
public override ILExpression BuildNew(PatternMatcher pm)
{
var args = new ILExpression[this.Arguments.Length];
for (int i = 0; i < args.Length; i++) args[i] = this.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 != this.code) return false;
var m = (MethodReference)e.Operand;
return m.Name == this.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 != this.code) return false;
var v = e.Operand as ILVariable;
return v != null && (this.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 = this.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) && object.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()
{
this.A = null;
this.B = null;
this.Operator = null;
this.SimpleOperand = null;
this.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++) {
this.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) {
this.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<ILExpression>().Except(n.GetSelfAndChildrenRecursive<ILExpression>());
n.ILRanges = ILRange.OrderAndJoint(n.ILRanges.Concat(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;
}
}
}
}

196
src/Libraries/ICSharpCode.Decompiler/ILAst/PeepholeTransform.cs

@ -397,9 +397,21 @@ namespace ICSharpCode.Decompiler.ILAst
return false; return false;
ILExpression op = expr.Arguments.Last(); ILExpression op = expr.Arguments.Last();
if (!CanBeRepresentedAsCompoundAssignment(op.Code)) // 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; return false;
ILExpression ldelem = op.Arguments[0]; ILExpression ldelem = op.Arguments[0];
if (liftedOperator) {
if (ldelem.Code != ILCode.ValueOf)
return false;
ldelem = ldelem.Arguments[0];
}
if (ldelem.Code != expectedLdelemCode) if (ldelem.Code != expectedLdelemCode)
return false; return false;
Debug.Assert(ldelem.Arguments.Count == expr.Arguments.Count - 1); Debug.Assert(ldelem.Arguments.Count == expr.Arguments.Count - 1);
@ -414,9 +426,9 @@ namespace ICSharpCode.Decompiler.ILAst
return true; return true;
} }
static bool CanBeRepresentedAsCompoundAssignment(ILCode code) static bool CanBeRepresentedAsCompoundAssignment(ILExpression expr)
{ {
switch (code) { switch (expr.Code) {
case ILCode.Add: case ILCode.Add:
case ILCode.Add_Ovf: case ILCode.Add_Ovf:
case ILCode.Add_Ovf_Un: case ILCode.Add_Ovf_Un:
@ -437,6 +449,24 @@ namespace ICSharpCode.Decompiler.ILAst
case ILCode.Shr: case ILCode.Shr:
case ILCode.Shr_Un: case ILCode.Shr_Un:
return true; 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: default:
return false; return false;
} }
@ -869,6 +899,78 @@ namespace ICSharpCode.Decompiler.ILAst
} }
#endregion #endregion
#region SimplifyLogicNot
static bool SimplifyLogicNot(List<ILNode> 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;
}
/// <summary>
/// If the argument is a binary comparison operation then the negation is pushed through it
/// </summary>
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 #region SimplifyShiftOperators
static bool SimplifyShiftOperators(List<ILNode> body, ILExpression expr, int pos) static bool SimplifyShiftOperators(List<ILNode> body, ILExpression expr, int pos)
{ {
@ -880,20 +982,20 @@ namespace ICSharpCode.Decompiler.ILAst
static void SimplifyShiftOperators(ILExpression expr, ref bool modified) static void SimplifyShiftOperators(ILExpression expr, ref bool modified)
{ {
for (int i = 0; i < expr.Arguments.Count; i++) for (int i = 0; i < expr.Arguments.Count; i++)
SimplifyShiftOperators(expr.Arguments[i], ref modified); SimplifyShiftOperators(expr.Arguments[i], ref modified);
if (expr.Code != ILCode.Shl && expr.Code != ILCode.Shr && expr.Code != ILCode.Shr_Un) if (expr.Code != ILCode.Shl && expr.Code != ILCode.Shr && expr.Code != ILCode.Shr_Un)
return; return;
var a = expr.Arguments[1]; var a = expr.Arguments[1];
if (a.Code != ILCode.And || a.Arguments[1].Code != ILCode.Ldc_I4 || expr.InferredType == null) if (a.Code != ILCode.And || a.Arguments[1].Code != ILCode.Ldc_I4 || expr.InferredType == null)
return; return;
int mask; int mask;
switch (expr.InferredType.MetadataType) { switch (expr.InferredType.MetadataType) {
case MetadataType.Int32: case MetadataType.Int32:
case MetadataType.UInt32: mask = 31; break; case MetadataType.UInt32: mask = 31; break;
case MetadataType.Int64: case MetadataType.Int64:
case MetadataType.UInt64: mask = 63; break; case MetadataType.UInt64: mask = 63; break;
default: return; default: return;
} }
if ((int)a.Arguments[1].Operand != mask) return; if ((int)a.Arguments[1].Operand != mask) return;
var res = a.Arguments[0]; var res = a.Arguments[0];
@ -903,5 +1005,81 @@ namespace ICSharpCode.Decompiler.ILAst
modified = true; modified = true;
} }
#endregion #endregion
#region InlineExpressionTreeParameterDeclarations
bool InlineExpressionTreeParameterDeclarations(List<ILNode> 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
} }
} }

10
src/Libraries/ICSharpCode.Decompiler/ILAst/SimpleControlFlow.cs

@ -98,16 +98,16 @@ namespace ICSharpCode.Decompiler.ILAst
if (leftBoolVal != 0) { if (leftBoolVal != 0) {
newExpr = condExpr; newExpr = condExpr;
} else { } else {
newExpr = new ILExpression(ILCode.LogicNot, null, condExpr); newExpr = new ILExpression(ILCode.LogicNot, null, condExpr) { InferredType = typeSystem.Boolean };
} }
} else if (retTypeIsBoolean && trueExpr.Match(ILCode.Ldc_I4, out leftBoolVal)) { } 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 // It can be expressed as logical expression
if (leftBoolVal != 0) { if (leftBoolVal != 0) {
newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicOr, condExpr, falseExpr); newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicOr, condExpr, falseExpr);
} else { } else {
newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicAnd, new ILExpression(ILCode.LogicNot, null, condExpr), falseExpr); newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicAnd, new ILExpression(ILCode.LogicNot, null, condExpr), falseExpr);
} }
} else if (retTypeIsBoolean && falseExpr.Match(ILCode.Ldc_I4, out rightBoolVal)) { } 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 // It can be expressed as logical expression
if (rightBoolVal != 0) { if (rightBoolVal != 0) {
newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicOr, new ILExpression(ILCode.LogicNot, null, condExpr), trueExpr); newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicOr, new ILExpression(ILCode.LogicNot, null, condExpr), trueExpr);
@ -343,10 +343,10 @@ namespace ICSharpCode.Decompiler.ILAst
ILExpression current = right; ILExpression current = right;
while(current.Arguments[0].Match(code)) while(current.Arguments[0].Match(code))
current = current.Arguments[0]; current = current.Arguments[0];
current.Arguments[0] = new ILExpression(code, null, left, current.Arguments[0]); current.Arguments[0] = new ILExpression(code, null, left, current.Arguments[0]) { InferredType = typeSystem.Boolean };
return right; return right;
} else { } else {
return new ILExpression(code, null, left, right); return new ILExpression(code, null, left, right) { InferredType = typeSystem.Boolean };
} }
} }

156
src/Libraries/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs

@ -280,15 +280,9 @@ namespace ICSharpCode.Decompiler.ILAst
if (forceInferChildren) { if (forceInferChildren) {
InferTypeForExpression(expr.Arguments[0], typeSystem.Boolean); InferTypeForExpression(expr.Arguments[0], typeSystem.Boolean);
} }
return TypeWithMoreInformation( return InferBinaryArguments(expr.Arguments[1], expr.Arguments[2], expectedType, forceInferChildren);
InferTypeForExpression(expr.Arguments[1], expectedType, forceInferChildren),
InferTypeForExpression(expr.Arguments[2], expectedType, forceInferChildren)
);
case ILCode.NullCoalescing: case ILCode.NullCoalescing:
return TypeWithMoreInformation( return InferBinaryArguments(expr.Arguments[0], expr.Arguments[1], expectedType, forceInferChildren);
InferTypeForExpression(expr.Arguments[0], expectedType, forceInferChildren),
InferTypeForExpression(expr.Arguments[1], expectedType, forceInferChildren)
);
#endregion #endregion
#region Variable load/store #region Variable load/store
case ILCode.Stloc: case ILCode.Stloc:
@ -472,7 +466,7 @@ namespace ICSharpCode.Decompiler.ILAst
if (forceInferChildren) { if (forceInferChildren) {
InferTypeForExpression(expr.Arguments[0], typeSystem.TypedReference); InferTypeForExpression(expr.Arguments[0], typeSystem.TypedReference);
} }
return new TypeReference("System", "RuntimeTypeHandle", module, module, true); return new TypeReference("System", "RuntimeTypeHandle", module, module.TypeSystem.Corlib, true);
case ILCode.Refanyval: case ILCode.Refanyval:
if (forceInferChildren) { if (forceInferChildren) {
InferTypeForExpression(expr.Arguments[0], typeSystem.TypedReference); InferTypeForExpression(expr.Arguments[0], typeSystem.TypedReference);
@ -483,6 +477,10 @@ namespace ICSharpCode.Decompiler.ILAst
TypeReference t = InferTypeForExpression(expr.Arguments[0], UnpackPointer(expectedType)); TypeReference t = InferTypeForExpression(expr.Arguments[0], UnpackPointer(expectedType));
return t != null ? new ByReferenceType(t) : null; 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 #endregion
#region Arithmetic instructions #region Arithmetic instructions
case ILCode.Not: // bitwise complement case ILCode.Not: // bitwise complement
@ -557,7 +555,9 @@ namespace ICSharpCode.Decompiler.ILAst
} }
case ILCode.CompoundAssignment: case ILCode.CompoundAssignment:
{ {
TypeReference varType = InferTypeForExpression(expr.Arguments[0].Arguments[0], null); 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) { if (forceInferChildren) {
InferTypeForExpression(expr.Arguments[0], varType); InferTypeForExpression(expr.Arguments[0], varType);
} }
@ -593,16 +593,16 @@ namespace ICSharpCode.Decompiler.ILAst
case ILCode.Ldc_R8: case ILCode.Ldc_R8:
return typeSystem.Double; return typeSystem.Double;
case ILCode.Ldc_Decimal: case ILCode.Ldc_Decimal:
return new TypeReference("System", "Decimal", module, module, true); return new TypeReference("System", "Decimal", module, module.TypeSystem.Corlib, true);
case ILCode.Ldtoken: case ILCode.Ldtoken:
if (expr.Operand is TypeReference) if (expr.Operand is TypeReference)
return new TypeReference("System", "RuntimeTypeHandle", module, module, true); return new TypeReference("System", "RuntimeTypeHandle", module, module.TypeSystem.Corlib, true);
else if (expr.Operand is FieldReference) else if (expr.Operand is FieldReference)
return new TypeReference("System", "RuntimeFieldHandle", module, module, true); return new TypeReference("System", "RuntimeFieldHandle", module, module.TypeSystem.Corlib, true);
else else
return new TypeReference("System", "RuntimeMethodHandle", module, module, true); return new TypeReference("System", "RuntimeMethodHandle", module, module.TypeSystem.Corlib, true);
case ILCode.Arglist: case ILCode.Arglist:
return new TypeReference("System", "RuntimeArgumentHandle", module, module, true); return new TypeReference("System", "RuntimeArgumentHandle", module, module.TypeSystem.Corlib, true);
#endregion #endregion
#region Array instructions #region Array instructions
case ILCode.Newarr: case ILCode.Newarr:
@ -735,22 +735,30 @@ namespace ICSharpCode.Decompiler.ILAst
return tr.IsValueType ? typeSystem.Object : tr; return tr.IsValueType ? typeSystem.Object : tr;
} }
case ILCode.Box: case ILCode.Box:
if (forceInferChildren) {
InferTypeForExpression(expr.Arguments.Single(), (TypeReference)expr.Operand); var tr = (TypeReference)expr.Operand;
return (TypeReference)expr.Operand; if (forceInferChildren)
InferTypeForExpression(expr.Arguments.Single(), tr);
return tr.IsValueType ? typeSystem.Object : tr;
}
#endregion #endregion
#region Comparison instructions #region Comparison instructions
case ILCode.Ceq: case ILCode.Ceq:
case ILCode.Cne:
if (forceInferChildren) if (forceInferChildren)
InferArgumentsInBinaryOperator(expr, null, null); InferArgumentsInBinaryOperator(expr, null, null);
return typeSystem.Boolean; return typeSystem.Boolean;
case ILCode.Clt: case ILCode.Clt:
case ILCode.Cgt: case ILCode.Cgt:
case ILCode.Cle:
case ILCode.Cge:
if (forceInferChildren) if (forceInferChildren)
InferArgumentsInBinaryOperator(expr, true, null); InferArgumentsInBinaryOperator(expr, true, null);
return typeSystem.Boolean; return typeSystem.Boolean;
case ILCode.Clt_Un: case ILCode.Clt_Un:
case ILCode.Cgt_Un: case ILCode.Cgt_Un:
case ILCode.Cle_Un:
case ILCode.Cge_Un:
if (forceInferChildren) if (forceInferChildren)
InferArgumentsInBinaryOperator(expr, false, null); InferArgumentsInBinaryOperator(expr, false, null);
return typeSystem.Boolean; return typeSystem.Boolean;
@ -787,8 +795,12 @@ namespace ICSharpCode.Decompiler.ILAst
#endregion #endregion
case ILCode.Pop: case ILCode.Pop:
return null; return null;
case ILCode.Wrap:
case ILCode.Dup: case ILCode.Dup:
return InferTypeForExpression(expr.Arguments.Single(), expectedType); {
var arg = expr.Arguments.Single();
return arg.ExpectedType = InferTypeForExpression(expr.Arguments.Single(), expectedType);
}
default: default:
Debug.WriteLine("Type Inference: Can't handle " + expr.Code.GetName()); Debug.WriteLine("Type Inference: Can't handle " + expr.Code.GetName());
return null; return null;
@ -904,14 +916,12 @@ namespace ICSharpCode.Decompiler.ILAst
} }
GenericParameter gp = type as GenericParameter; GenericParameter gp = type as GenericParameter;
if (gp != null) { if (gp != null) {
if (gp.Owner.GenericParameterType == GenericParameterType.Method) { if (member.DeclaringType is ArrayType) {
return ((ArrayType)member.DeclaringType).ElementType;
} else if (gp.Owner.GenericParameterType == GenericParameterType.Method) {
return ((GenericInstanceMethod)member).GenericArguments[gp.Position]; return ((GenericInstanceMethod)member).GenericArguments[gp.Position];
} else { } else {
if (member.DeclaringType is ArrayType) { return ((GenericInstanceType)member.DeclaringType).GenericArguments[gp.Position];
return ((ArrayType)member.DeclaringType).ElementType;
} else {
return ((GenericInstanceType)member.DeclaringType).GenericArguments[gp.Position];
}
} }
} }
return type; return type;
@ -934,25 +944,24 @@ namespace ICSharpCode.Decompiler.ILAst
type = ((TypeSpecification)type).ElementType; type = ((TypeSpecification)type).ElementType;
return type; 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) TypeReference InferArgumentsInBinaryOperator(ILExpression expr, bool? isSigned, TypeReference expectedType)
{ {
ILExpression left = expr.Arguments[0]; return InferBinaryArguments(expr.Arguments[0], expr.Arguments[1], expectedType);
ILExpression right = expr.Arguments[1];
TypeReference leftPreferred = DoInferTypeForExpression(left, expectedType);
TypeReference rightPreferred = DoInferTypeForExpression(right, expectedType);
if (IsSameType(leftPreferred, rightPreferred)) {
return left.InferredType = right.InferredType = left.ExpectedType = right.ExpectedType = leftPreferred;
} else if (IsSameType(rightPreferred, DoInferTypeForExpression(left, rightPreferred))) {
return left.InferredType = right.InferredType = left.ExpectedType = right.ExpectedType = rightPreferred;
} else if (IsSameType(leftPreferred, DoInferTypeForExpression(right, leftPreferred))) {
return left.InferredType = right.InferredType = left.ExpectedType = right.ExpectedType = leftPreferred;
} else {
left.ExpectedType = right.ExpectedType = TypeWithMoreInformation(leftPreferred, rightPreferred);
left.InferredType = DoInferTypeForExpression(left, left.ExpectedType);
right.InferredType = DoInferTypeForExpression(right, right.ExpectedType);
return left.ExpectedType;
}
} }
TypeReference InferArgumentsInAddition(ILExpression expr, bool? isSigned, TypeReference expectedType) TypeReference InferArgumentsInAddition(ILExpression expr, bool? isSigned, TypeReference expectedType)
@ -964,25 +973,14 @@ namespace ICSharpCode.Decompiler.ILAst
left.InferredType = left.ExpectedType = leftPreferred; left.InferredType = left.ExpectedType = leftPreferred;
InferTypeForExpression(right, typeSystem.IntPtr); InferTypeForExpression(right, typeSystem.IntPtr);
return leftPreferred; return leftPreferred;
} else {
TypeReference rightPreferred = DoInferTypeForExpression(right, expectedType);
if (rightPreferred is PointerType) {
InferTypeForExpression(left, typeSystem.IntPtr);
right.InferredType = right.ExpectedType = rightPreferred;
return rightPreferred;
} else if (IsSameType(leftPreferred, rightPreferred)) {
return left.InferredType = right.InferredType = left.ExpectedType = right.ExpectedType = leftPreferred;
} else if (IsSameType(rightPreferred, DoInferTypeForExpression(left, rightPreferred))) {
return left.InferredType = right.InferredType = left.ExpectedType = right.ExpectedType = rightPreferred;
} else if (IsSameType(leftPreferred, DoInferTypeForExpression(right, leftPreferred))) {
return left.InferredType = right.InferredType = left.ExpectedType = right.ExpectedType = leftPreferred;
} else {
left.ExpectedType = right.ExpectedType = TypeWithMoreInformation(leftPreferred, rightPreferred);
left.InferredType = DoInferTypeForExpression(left, left.ExpectedType);
right.InferredType = DoInferTypeForExpression(right, right.ExpectedType);
return left.ExpectedType;
}
} }
TypeReference rightPreferred = DoInferTypeForExpression(right, expectedType);
if (rightPreferred is PointerType) {
InferTypeForExpression(left, typeSystem.IntPtr);
right.InferredType = right.ExpectedType = rightPreferred;
return rightPreferred;
}
return InferBinaryArguments(left, right, expectedType, leftPreferred: leftPreferred, rightPreferred: rightPreferred);
} }
TypeReference InferArgumentsInSubtraction(ILExpression expr, bool? isSigned, TypeReference expectedType) TypeReference InferArgumentsInSubtraction(ILExpression expr, bool? isSigned, TypeReference expectedType)
@ -994,20 +992,27 @@ namespace ICSharpCode.Decompiler.ILAst
left.InferredType = left.ExpectedType = leftPreferred; left.InferredType = left.ExpectedType = leftPreferred;
InferTypeForExpression(right, typeSystem.IntPtr); InferTypeForExpression(right, typeSystem.IntPtr);
return leftPreferred; return 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 { } else {
TypeReference rightPreferred = DoInferTypeForExpression(right, expectedType); left.ExpectedType = right.ExpectedType = TypeWithMoreInformation(leftPreferred, rightPreferred);
if (IsSameType(leftPreferred, rightPreferred)) { left.InferredType = DoInferTypeForExpression(left, left.ExpectedType, forceInferChildren);
return left.InferredType = right.InferredType = left.ExpectedType = right.ExpectedType = leftPreferred; right.InferredType = DoInferTypeForExpression(right, right.ExpectedType, forceInferChildren);
} else if (IsSameType(rightPreferred, DoInferTypeForExpression(left, rightPreferred))) { return left.ExpectedType;
return left.InferredType = right.InferredType = left.ExpectedType = right.ExpectedType = rightPreferred;
} else if (IsSameType(leftPreferred, DoInferTypeForExpression(right, leftPreferred))) {
return left.InferredType = right.InferredType = left.ExpectedType = right.ExpectedType = leftPreferred;
} else {
left.ExpectedType = right.ExpectedType = TypeWithMoreInformation(leftPreferred, rightPreferred);
left.InferredType = DoInferTypeForExpression(left, left.ExpectedType);
right.InferredType = DoInferTypeForExpression(right, right.ExpectedType);
return left.ExpectedType;
}
} }
} }
@ -1152,6 +1157,11 @@ namespace ICSharpCode.Decompiler.ILAst
} }
return false; return false;
} }
internal static bool IsNullableType(TypeReference type)
{
return type != null && type.Name == "Nullable`1" && type.Namespace == "System";
}
public static TypeCode GetTypeCode(TypeReference type) public static TypeCode GetTypeCode(TypeReference type)
{ {

5
src/Libraries/ICSharpCode.Decompiler/ILAst/YieldReturnDecompiler.cs

@ -224,7 +224,7 @@ namespace ICSharpCode.Decompiler.ILAst
ILBlock ilMethod = new ILBlock(); ILBlock ilMethod = new ILBlock();
ILAstBuilder astBuilder = new ILAstBuilder(); ILAstBuilder astBuilder = new ILAstBuilder();
ilMethod.Body = astBuilder.Build(method, true); ilMethod.Body = astBuilder.Build(method, true, context);
ILAstOptimizer optimizer = new ILAstOptimizer(); ILAstOptimizer optimizer = new ILAstOptimizer();
optimizer.Optimize(context, ilMethod, ILAstOptimizationStep.YieldReturn); optimizer.Optimize(context, ilMethod, ILAstOptimizationStep.YieldReturn);
return ilMethod; return ilMethod;
@ -634,13 +634,14 @@ namespace ICSharpCode.Decompiler.ILAst
case ILCode.Ldc_I4: case ILCode.Ldc_I4:
return new SymbolicValue(SymbolicValueType.IntegerConstant, (int)expr.Operand); return new SymbolicValue(SymbolicValueType.IntegerConstant, (int)expr.Operand);
case ILCode.Ceq: case ILCode.Ceq:
case ILCode.Cne:
left = Eval(expr.Arguments[0]); left = Eval(expr.Arguments[0]);
right = Eval(expr.Arguments[1]); right = Eval(expr.Arguments[1]);
if (left.Type != SymbolicValueType.State || right.Type != SymbolicValueType.IntegerConstant) if (left.Type != SymbolicValueType.State || right.Type != SymbolicValueType.IntegerConstant)
throw new YieldAnalysisFailedException(); throw new YieldAnalysisFailedException();
// bool: (state + left.Constant == right.Constant) // bool: (state + left.Constant == right.Constant)
// bool: (state == right.Constant - left.Constant) // bool: (state == right.Constant - left.Constant)
return new SymbolicValue(SymbolicValueType.StateEquals, unchecked ( right.Constant - left.Constant )); return new SymbolicValue(expr.Code == ILCode.Ceq ? SymbolicValueType.StateEquals : SymbolicValueType.StateInEquals, unchecked(right.Constant - left.Constant));
case ILCode.LogicNot: case ILCode.LogicNot:
SymbolicValue val = Eval(expr.Arguments[0]); SymbolicValue val = Eval(expr.Arguments[0]);
if (val.Type == SymbolicValueType.StateEquals) if (val.Type == SymbolicValueType.StateEquals)

11
src/Libraries/ICSharpCode.Decompiler/ITextOutput.cs

@ -18,21 +18,24 @@
using System; using System;
using System.IO; using System.IO;
using ICSharpCode.NRefactory;
using Mono.Cecil;
namespace ICSharpCode.Decompiler namespace ICSharpCode.Decompiler
{ {
public interface ITextOutput public interface ITextOutput
{ {
int CurrentLine { get; } TextLocation Location { get; }
int CurrentColumn { get; }
void Indent(); void Indent();
void Unindent(); void Unindent();
void Write(char ch); void Write(char ch);
void Write(string text); void Write(string text);
void WriteLine(); void WriteLine();
void WriteDefinition(string text, object definition); void WriteDefinition(string text, object definition, bool isLocal = true);
void WriteReference(string text, object reference); void WriteReference(string text, object reference, bool isLocal = false);
void AddDebuggerMemberMapping(MemberMapping memberMapping);
void MarkFoldStart(string collapsedText = "...", bool defaultCollapsed = false); void MarkFoldStart(string collapsedText = "...", bool defaultCollapsed = false);
void MarkFoldEnd(); void MarkFoldEnd();

36
src/Libraries/ICSharpCode.Decompiler/PlainTextOutput.cs

@ -18,18 +18,18 @@
using System; using System;
using System.IO; using System.IO;
using ICSharpCode.NRefactory;
namespace ICSharpCode.Decompiler namespace ICSharpCode.Decompiler
{ {
public sealed class PlainTextOutput : ITextOutput public sealed class PlainTextOutput : ITextOutput
{ {
const int TAB_SIZE = 4;
readonly TextWriter writer; readonly TextWriter writer;
int indent; int indent;
bool needsIndent; bool needsIndent;
int lineNumber = 1;
int columnNumber = 1; int line = 1;
int column = 1;
public PlainTextOutput(TextWriter writer) public PlainTextOutput(TextWriter writer)
{ {
@ -43,12 +43,10 @@ namespace ICSharpCode.Decompiler
this.writer = new StringWriter(); this.writer = new StringWriter();
} }
public int CurrentLine { public TextLocation Location {
get { return lineNumber; } get {
} return new TextLocation(line, column + (needsIndent ? indent : 0));
}
public int CurrentColumn {
get { return columnNumber; }
} }
public override string ToString() public override string ToString()
@ -72,8 +70,8 @@ namespace ICSharpCode.Decompiler
needsIndent = false; needsIndent = false;
for (int i = 0; i < indent; i++) { for (int i = 0; i < indent; i++) {
writer.Write('\t'); writer.Write('\t');
columnNumber += TAB_SIZE - 1;
} }
column += indent;
} }
} }
@ -81,30 +79,30 @@ namespace ICSharpCode.Decompiler
{ {
WriteIndent(); WriteIndent();
writer.Write(ch); writer.Write(ch);
columnNumber++; column++;
} }
public void Write(string text) public void Write(string text)
{ {
WriteIndent(); WriteIndent();
writer.Write(text); writer.Write(text);
columnNumber += text.Length; column += text.Length;
} }
public void WriteLine() public void WriteLine()
{ {
lineNumber++;
writer.WriteLine(); writer.WriteLine();
needsIndent = true; needsIndent = true;
columnNumber = TAB_SIZE * indent; line++;
column = 1;
} }
public void WriteDefinition(string text, object definition) public void WriteDefinition(string text, object definition, bool isLocal)
{ {
Write(text); Write(text);
} }
public void WriteReference(string text, object reference) public void WriteReference(string text, object reference, bool isLocal)
{ {
Write(text); Write(text);
} }
@ -116,5 +114,9 @@ namespace ICSharpCode.Decompiler
void ITextOutput.MarkFoldEnd() void ITextOutput.MarkFoldEnd()
{ {
} }
void ITextOutput.AddDebuggerMemberMapping(MemberMapping memberMapping)
{
}
} }
} }

4
src/Libraries/ICSharpCode.Decompiler/Properties/AssemblyInfo.cs

@ -19,8 +19,8 @@ using System.Runtime.InteropServices;
// If you need to expose a type to COM, use [ComVisible(true)] on that type. // If you need to expose a type to COM, use [ComVisible(true)] on that type.
[assembly: ComVisible(false)] [assembly: ComVisible(false)]
[assembly: AssemblyVersion("2.0.0.1221")] [assembly: AssemblyVersion("2.0.0.1486")]
[assembly: AssemblyInformationalVersion("2.0.0.1221-26633dc2")] [assembly: AssemblyInformationalVersion("2.0.0.1486-becc8f14")]
[assembly: NeutralResourcesLanguage("en-US")] [assembly: NeutralResourcesLanguage("en-US")]
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2243:AttributeStringLiteralsShouldParseCorrectly", [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2243:AttributeStringLiteralsShouldParseCorrectly",

27
src/Libraries/ICSharpCode.Decompiler/Properties/AssemblyInfo.template.cs

@ -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 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")]

51
src/Libraries/ICSharpCode.Decompiler/Tests/CheckedUnchecked.cs

@ -16,6 +16,8 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System;
public class CheckedUnchecked public class CheckedUnchecked
{ {
public int Operators(int a, int b) public int Operators(int a, int b)
@ -63,4 +65,53 @@ public class CheckedUnchecked
} }
} }
} }
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<int[]>(new int[]
{
1,
2
}, (int[] n) => checked(new int[]
{
n[0] + 1,
n[1] + 1
}));
}
public T TestHelp<T>(T t, Func<T, T> f)
{
return f(t);
}
public void CheckedInArrayCreationArgument(int a, int b)
{
Console.WriteLine(new int[checked(a + b)]);
}
} }

370
src/Libraries/ICSharpCode.Decompiler/Tests/ExpressionTrees.cs

@ -0,0 +1,370 @@
// 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<X>
{
public static X StaticField;
public X InstanceField;
public static X StaticProperty { get; set; }
public X InstanceProperty { get; set; }
public static bool GenericMethod<Y>()
{
return false;
}
}
int field;
static object ToCode<R>(object x, Expression<Func<R>> expr)
{
return expr;
}
static object ToCode<T, R>(object x, Expression<Func<T, R>> 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<int, bool>)(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<int, int> { { 1, 1 }, { 2, 2 }, { 3, 4 } }.Count == 3);
}
public void ListInitializer2()
{
ToCode(X(), () => new List<int>(50) { 1, 2, 3 }.Count == 3);
}
public void ListInitializer3()
{
ToCode(X(), () => new List<int> { 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<int>).Count);
ToCode(X(), () => default(int[]).Clone() == null);
ToCode(X(), () => default(Type).IsInstanceOfType(new object()));
ToCode(X(), () => default(List<int>).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<bool>)new[] { 2000, 2004, 2008, 2012 }.Any);
}
public void MethodGroupConstant()
{
ToCode(X(), () => Array.TrueForAll(new[] { 2000, 2004, 2008, 2012 }, DateTime.IsLeapYear));
HashSet<int> set = new HashSet<int>();
ToCode(X(), () => new[] { 2000, 2004, 2008, 2012 }.All(set.Add));
Func<Func<object, object, bool>, 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<Func<int>, 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<int, Func<int, Func<int, int>>>(X(), a => b => c => a + b + c);
}
bool Fizz(Func<int, bool> a)
{
return a(42);
}
bool Buzz(Func<int, bool> a)
{
return a(42);
}
bool Fizz(Func<string, bool> 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<Func<int, string, string>>)((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<int>().InstanceField + new GenericClass<double>().InstanceProperty);
}
public void GenericClassStatic()
{
ToCode(X(), () => GenericClass<int>.StaticField + GenericClass<double>.StaticProperty);
}
public void InvokeGenericMethod()
{
ToCode(X(), () => GenericClass<int>.GenericMethod<double>());
}
}

5
src/Libraries/ICSharpCode.Decompiler/Tests/Generics.cs

@ -97,6 +97,11 @@ public static class Generics
{ {
} }
private static void MultidimensionalArray<T>(T[,] array)
{
array[0, 0] = array[0, 1];
}
public static Dictionary<string, string>.KeyCollection.Enumerator GetEnumerator(Dictionary<string, string> d, Generics.MyArray<string>.NestedClass<int> nc) public static Dictionary<string, string>.KeyCollection.Enumerator GetEnumerator(Dictionary<string, string> d, Generics.MyArray<string>.NestedClass<int> nc)
{ {
// Tests references to inner classes in generic classes // Tests references to inner classes in generic classes

15
src/Libraries/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj

@ -14,7 +14,7 @@
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors> <TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow> <CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
<NoWarn>67,169,1058,728</NoWarn> <NoWarn>67,169,1058,728,1720,649</NoWarn>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Platform)' == 'x86' "> <PropertyGroup Condition=" '$(Platform)' == 'x86' ">
<PlatformTarget>x86</PlatformTarget> <PlatformTarget>x86</PlatformTarget>
@ -23,6 +23,13 @@
<BaseAddress>4194304</BaseAddress> <BaseAddress>4194304</BaseAddress>
<FileAlignment>4096</FileAlignment> <FileAlignment>4096</FileAlignment>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Platform)' == 'AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<RegisterForComInterop>False</RegisterForComInterop>
<GenerateSerializationAssemblies>Auto</GenerateSerializationAssemblies>
<BaseAddress>4194304</BaseAddress>
<FileAlignment>4096</FileAlignment>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<OutputPath>..\bin\Debug\</OutputPath> <OutputPath>..\bin\Debug\</OutputPath>
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
@ -57,6 +64,8 @@
<ItemGroup> <ItemGroup>
<Compile Include="CallOverloadedMethod.cs" /> <Compile Include="CallOverloadedMethod.cs" />
<Compile Include="CheckedUnchecked.cs" /> <Compile Include="CheckedUnchecked.cs" />
<Compile Include="ExpressionTrees.cs" />
<Compile Include="LiftedOperators.cs" />
<Compile Include="CustomShortCircuitOperators.cs" /> <Compile Include="CustomShortCircuitOperators.cs" />
<Compile Include="Helpers\CodeAssert.cs" /> <Compile Include="Helpers\CodeAssert.cs" />
<Compile Include="IncrementDecrement.cs" /> <Compile Include="IncrementDecrement.cs" />
@ -95,6 +104,10 @@
<Project>{D68133BD-1E63-496E-9EDE-4FBDBF77B486}</Project> <Project>{D68133BD-1E63-496E-9EDE-4FBDBF77B486}</Project>
<Name>Mono.Cecil</Name> <Name>Mono.Cecil</Name>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\..\NRefactory\ICSharpCode.NRefactory.CSharp\ICSharpCode.NRefactory.CSharp.csproj">
<Project>{53DCA265-3C3C-42F9-B647-F72BA678122B}</Project>
<Name>ICSharpCode.NRefactory.CSharp</Name>
</ProjectReference>
<ProjectReference Include="..\..\NRefactory\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj"> <ProjectReference Include="..\..\NRefactory\ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj">
<Project>{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}</Project> <Project>{3B2A5653-EC97-4001-BB9B-D90F1AF2C371}</Project>
<Name>ICSharpCode.NRefactory</Name> <Name>ICSharpCode.NRefactory</Name>

24
src/Libraries/ICSharpCode.Decompiler/Tests/InitializerTests.cs

@ -532,9 +532,9 @@ public class InitializerTests
}); });
} }
public void MultidimensionalInit() public int[,] MultidimensionalInit()
{ {
int[,] expr_09 = new int[, ] return new int[,]
{ {
{ {
@ -651,11 +651,11 @@ public class InitializerTests
}; };
} }
public void MultidimensionalInit2() public int[][,] MultidimensionalInit2()
{ {
int[][,] array = new int[][,] return new int[][,]
{ {
new int[, ] new int[,]
{ {
{ {
@ -687,7 +687,7 @@ public class InitializerTests
} }
}, },
new int[, ] new int[,]
{ {
{ {
@ -719,7 +719,7 @@ public class InitializerTests
} }
}, },
new int[, ] new int[,]
{ {
{ {
@ -750,7 +750,7 @@ public class InitializerTests
0 0
} }
}, },
new int[, ] new int[,]
{ {
{ {
@ -785,11 +785,11 @@ public class InitializerTests
}; };
} }
public void ArrayOfArrayOfArrayInit() public int[][,,] ArrayOfArrayOfArrayInit()
{ {
int[][,,] array = new int[][,,] return new int[][,,]
{ {
new int[, , ] new int[,,]
{ {
{ {
{ {
@ -827,7 +827,7 @@ public class InitializerTests
} }
}, },
new int[, , ] new int[,,]
{ {
{ {
{ {

830
src/Libraries/ICSharpCode.Decompiler/Tests/LiftedOperators.cs

@ -0,0 +1,830 @@
// 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<bool> 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<bool> 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<int> 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<int> 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<decimal> 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<decimal> 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<TS> 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<TS> x, Func<int> 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;
}
}

9
src/Libraries/ICSharpCode.Decompiler/Tests/PInvoke.cs

@ -84,4 +84,13 @@ public class PInvoke
public void CustomMarshal2([MarshalAs(UnmanagedType.CustomMarshaler, MarshalType = "MyCompany.MyMarshaler", MarshalCookie = "Cookie")] 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);
}
} }

79
src/Libraries/ICSharpCode.Decompiler/Tests/QueryExpressions.cs

@ -35,7 +35,7 @@ public class QueryExpressions
{ {
public int OrderID; public int OrderID;
public DateTime OrderDate; public DateTime OrderDate;
public Customer Customer; public QueryExpressions.Customer Customer;
public int CustomerID; public int CustomerID;
public decimal Total; public decimal Total;
public IEnumerable<QueryExpressions.OrderDetail> Details; public IEnumerable<QueryExpressions.OrderDetail> Details;
@ -54,7 +54,7 @@ public class QueryExpressions
{ {
return return
from c in this.customers from c in this.customers
where c.Orders.Count() > 10 where c.Orders.Count<QueryExpressions.Order>() > 10
where c.Country == "DE" where c.Country == "DE"
select c; select c;
} }
@ -64,7 +64,12 @@ public class QueryExpressions
return return
from c in this.customers from c in this.customers
from o in c.Orders from o in c.Orders
select new { c.Name, o.OrderID, o.Total }; select new
{
c.Name,
o.OrderID,
o.Total
};
} }
public object SelectManyFollowedByOrderBy() public object SelectManyFollowedByOrderBy()
@ -73,7 +78,12 @@ public class QueryExpressions
from c in this.customers from c in this.customers
from o in c.Orders from o in c.Orders
orderby o.Total descending orderby o.Total descending
select new { c.Name, o.OrderID, o.Total }; select new
{
c.Name,
o.OrderID,
o.Total
};
} }
public object MultipleSelectManyFollowedBySelect() public object MultipleSelectManyFollowedBySelect()
@ -82,7 +92,12 @@ public class QueryExpressions
from c in this.customers from c in this.customers
from o in c.Orders from o in c.Orders
from d in o.Details from d in o.Details
select new { c.Name, o.OrderID, d.Quantity }; select new
{
c.Name,
o.OrderID,
d.Quantity
};
} }
public object MultipleSelectManyFollowedByLet() public object MultipleSelectManyFollowedByLet()
@ -92,16 +107,25 @@ public class QueryExpressions
from o in c.Orders from o in c.Orders
from d in o.Details from d in o.Details
let x = d.Quantity * d.UnitPrice let x = d.Quantity * d.UnitPrice
select new { c.Name, o.OrderID, x }; select new
{
c.Name,
o.OrderID,
x
};
} }
public object FromLetWhereSelect() public object FromLetWhereSelect()
{ {
return return
from o in this.orders from o in this.orders
let t = o.Details.Sum(d => d.UnitPrice * d.Quantity) let t = o.Details.Sum((QueryExpressions.OrderDetail d) => d.UnitPrice * d.Quantity)
where t >= 1000 where t >= 1000m
select new { o.OrderID, Total = t }; select new
{
OrderID = o.OrderID,
Total = t
};
} }
public object MultipleLet() public object MultipleLet()
@ -116,25 +140,34 @@ public class QueryExpressions
public object Join() public object Join()
{ {
return return
from c in customers from c in this.customers
join o in orders on c.CustomerID equals o.CustomerID join o in this.orders on c.CustomerID equals o.CustomerID
select new { c.Name, o.OrderDate, o.Total }; select new
{
c.Name,
o.OrderDate,
o.Total
};
} }
public object JoinInto() public object JoinInto()
{ {
return return
from c in customers from c in this.customers
join o in orders on c.CustomerID equals o.CustomerID into co join o in this.orders on c.CustomerID equals o.CustomerID into co
let n = co.Count() let n = co.Count<QueryExpressions.Order>()
where n >= 10 where n >= 10
select new { c.Name, OrderCount = n }; select new
{
Name = c.Name,
OrderCount = n
};
} }
public object OrderBy() public object OrderBy()
{ {
return return
from o in orders from o in this.orders
orderby o.Customer.Name, o.Total descending orderby o.Customer.Name, o.Total descending
select o; select o;
} }
@ -142,14 +175,14 @@ public class QueryExpressions
public object GroupBy() public object GroupBy()
{ {
return return
from c in customers from c in this.customers
group c.Name by c.Country; group c.Name by c.Country;
} }
public object ExplicitType() public object ExplicitType()
{ {
return return
from Customer c in customers from QueryExpressions.Customer c in this.customers
where c.City == "London" where c.City == "London"
select c; select c;
} }
@ -157,8 +190,12 @@ public class QueryExpressions
public object QueryContinuation() public object QueryContinuation()
{ {
return return
from c in customers from c in this.customers
group c by c.Country into g group c by c.Country into g
select new { Country = g.Key, CustCount = g.Count() }; select new
{
Country = g.Key,
CustCount = g.Count<QueryExpressions.Customer>()
};
} }
} }

28
src/Libraries/ICSharpCode.Decompiler/Tests/TestRunner.cs

@ -52,10 +52,16 @@ namespace ICSharpCode.Decompiler.Tests
TestFile(@"..\..\Tests\DelegateConstruction.cs"); TestFile(@"..\..\Tests\DelegateConstruction.cs");
} }
[Test, Ignore("Not yet implemented")]
public void ExpressionTrees()
{
TestFile(@"..\..\Tests\ExpressionTrees.cs");
}
[Test] [Test]
public void ExceptionHandling() public void ExceptionHandling()
{ {
TestFile(@"..\..\Tests\ExceptionHandling.cs"); TestFile(@"..\..\Tests\ExceptionHandling.cs", false);
} }
[Test] [Test]
@ -81,6 +87,12 @@ namespace ICSharpCode.Decompiler.Tests
{ {
TestFile(@"..\..\Tests\InitializerTests.cs"); TestFile(@"..\..\Tests\InitializerTests.cs");
} }
[Test]
public void LiftedOperators()
{
TestFile(@"..\..\Tests\LiftedOperators.cs");
}
[Test] [Test]
public void Loops() public void Loops()
@ -106,7 +118,7 @@ namespace ICSharpCode.Decompiler.Tests
TestFile(@"..\..\Tests\PropertiesAndEvents.cs"); TestFile(@"..\..\Tests\PropertiesAndEvents.cs");
} }
[Test, Ignore("Formatting differences in anonymous method create expressions")] [Test]
public void QueryExpressions() public void QueryExpressions()
{ {
TestFile(@"..\..\Tests\QueryExpressions.cs"); TestFile(@"..\..\Tests\QueryExpressions.cs");
@ -149,9 +161,15 @@ namespace ICSharpCode.Decompiler.Tests
} }
static void TestFile(string fileName) static void TestFile(string fileName)
{
TestFile(fileName, false);
TestFile(fileName, true);
}
static void TestFile(string fileName, bool optimize)
{ {
string code = File.ReadAllText(fileName); string code = File.ReadAllText(fileName);
AssemblyDefinition assembly = Compile(code); AssemblyDefinition assembly = Compile(code, optimize);
AstBuilder decompiler = new AstBuilder(new DecompilerContext(assembly.MainModule)); AstBuilder decompiler = new AstBuilder(new DecompilerContext(assembly.MainModule));
decompiler.AddAssembly(assembly); decompiler.AddAssembly(assembly);
new Helpers.RemoveCompilerAttribute().Run(decompiler.CompilationUnit); new Helpers.RemoveCompilerAttribute().Run(decompiler.CompilationUnit);
@ -160,11 +178,11 @@ namespace ICSharpCode.Decompiler.Tests
CodeAssert.AreEqual(code, output.ToString()); CodeAssert.AreEqual(code, output.ToString());
} }
static AssemblyDefinition Compile(string code) static AssemblyDefinition Compile(string code, bool optimize)
{ {
CSharpCodeProvider provider = new CSharpCodeProvider(new Dictionary<string, string> { { "CompilerVersion", "v4.0" } }); CSharpCodeProvider provider = new CSharpCodeProvider(new Dictionary<string, string> { { "CompilerVersion", "v4.0" } });
CompilerParameters options = new CompilerParameters(); CompilerParameters options = new CompilerParameters();
options.CompilerOptions = "/unsafe /o-"; options.CompilerOptions = "/unsafe /o" + (optimize ? "+" : "-");
options.ReferencedAssemblies.Add("System.Core.dll"); options.ReferencedAssemblies.Add("System.Core.dll");
CompilerResults results = provider.CompileAssemblyFromSource(options, code); CompilerResults results = provider.CompileAssemblyFromSource(options, code);
try { try {

14
src/Libraries/ICSharpCode.Decompiler/Tests/TypeAnalysisTests.cs

@ -106,4 +106,18 @@ public class TypeAnalysisTests
{ {
return (int)num ^ (int)(num >> 32); 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));
}
} }

3
src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/.gitignore vendored

@ -0,0 +1,3 @@
bin/
obj/

26
src/Libraries/NewNRefactory/ICSharpCode.NRefactory/CSharp/Analysis/ControlFlow.cs → src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Analysis/ControlFlow.cs

@ -1,5 +1,20 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) // Copyright (c) AlphaSierraPapa for the SharpDevelop Team
// This code is distributed under MIT X11 license (for details please see \doc\license.txt) //
// 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;
using System.Collections.Generic; using System.Collections.Generic;
@ -8,6 +23,7 @@ using System.Linq;
using System.Threading; using System.Threading;
using ICSharpCode.NRefactory.CSharp.Resolver; using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp.Analysis namespace ICSharpCode.NRefactory.CSharp.Analysis
@ -96,7 +112,7 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
/// Gets the try-finally statements that this control flow edge is leaving. /// Gets the try-finally statements that this control flow edge is leaving.
/// </summary> /// </summary>
public IEnumerable<TryCatchStatement> TryFinallyStatements { public IEnumerable<TryCatchStatement> TryFinallyStatements {
get { return jumpOutOfTryFinally ?? Enumerable.Empty<TryCatchStatement>(); } get { return jumpOutOfTryFinally ?? EmptyList<TryCatchStatement>.Instance; }
} }
} }
@ -152,7 +168,7 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
{ {
return BuildControlFlowGraph(statement, new ResolveVisitor( return BuildControlFlowGraph(statement, new ResolveVisitor(
new CSharpResolver(context, cancellationToken), new CSharpResolver(context, cancellationToken),
null, ConstantModeResolveVisitorNavigator.Skip)); null));
} }
public IList<ControlFlowNode> BuildControlFlowGraph(Statement statement, ResolveVisitor resolveVisitor) public IList<ControlFlowNode> BuildControlFlowGraph(Statement statement, ResolveVisitor resolveVisitor)
@ -657,7 +673,7 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
return CreateConnectedEndNode(usingStatement, bodyEnd); return CreateConnectedEndNode(usingStatement, bodyEnd);
} }
public override ControlFlowNode VisitYieldStatement(YieldStatement yieldStatement, ControlFlowNode data) public override ControlFlowNode VisitYieldReturnStatement(YieldReturnStatement yieldStatement, ControlFlowNode data)
{ {
return CreateConnectedEndNode(yieldStatement, data); return CreateConnectedEndNode(yieldStatement, data);
} }

24
src/Libraries/NewNRefactory/ICSharpCode.NRefactory/CSharp/Analysis/DefiniteAssignmentAnalysis.cs → src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Analysis/DefiniteAssignmentAnalysis.cs

@ -1,13 +1,31 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) // Copyright (c) AlphaSierraPapa for the SharpDevelop Team
// This code is distributed under MIT X11 license (for details please see \doc\license.txt) //
// 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;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using ICSharpCode.NRefactory.CSharp.Resolver; using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
using ICSharpCode.NRefactory.Utils; using ICSharpCode.NRefactory.Utils;
namespace ICSharpCode.NRefactory.CSharp.Analysis namespace ICSharpCode.NRefactory.CSharp.Analysis
@ -96,7 +114,7 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
public DefiniteAssignmentAnalysis(Statement rootStatement, ITypeResolveContext context, CancellationToken cancellationToken) public DefiniteAssignmentAnalysis(Statement rootStatement, ITypeResolveContext context, CancellationToken cancellationToken)
: this(rootStatement, new ResolveVisitor(new CSharpResolver(context ?? MinimalResolveContext.Instance, cancellationToken), : this(rootStatement, new ResolveVisitor(new CSharpResolver(context ?? MinimalResolveContext.Instance, cancellationToken),
null, ConstantModeResolveVisitorNavigator.Skip)) null))
{ {
} }

102
src/Libraries/NewNRefactory/ICSharpCode.NRefactory/CSharp/Ast/AstNode.cs → src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/AstNode.cs

@ -27,6 +27,7 @@ using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
@ -51,7 +52,7 @@ namespace ICSharpCode.NRefactory.CSharp
} }
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data = default(T))
{ {
return default (S); return default (S);
} }
@ -82,7 +83,7 @@ namespace ICSharpCode.NRefactory.CSharp
get { return NodeType.Pattern; } get { return NodeType.Pattern; }
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data = default(T))
{ {
return visitor.VisitPatternPlaceholder (this, child, data); return visitor.VisitPatternPlaceholder (this, child, data);
} }
@ -116,20 +117,20 @@ namespace ICSharpCode.NRefactory.CSharp
} }
} }
public virtual AstLocation StartLocation { public virtual TextLocation StartLocation {
get { get {
var child = firstChild; var child = firstChild;
if (child == null) if (child == null)
return AstLocation.Empty; return TextLocation.Empty;
return child.StartLocation; return child.StartLocation;
} }
} }
public virtual AstLocation EndLocation { public virtual TextLocation EndLocation {
get { get {
var child = lastChild; var child = lastChild;
if (child == null) if (child == null)
return AstLocation.Empty; return TextLocation.Empty;
return child.EndLocation; return child.EndLocation;
} }
} }
@ -440,7 +441,7 @@ namespace ICSharpCode.NRefactory.CSharp
return copy; return copy;
} }
public abstract S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data); public abstract S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data = default(T));
#region Pattern Matching #region Pattern Matching
protected static bool MatchString (string name1, string name2) protected static bool MatchString (string name1, string name2)
@ -503,12 +504,12 @@ namespace ICSharpCode.NRefactory.CSharp
return null; return null;
} }
public AstNode GetNodeAt (int line, int column) public AstNode GetNodeAt (int line, int column, Predicate<AstNode> pred = null)
{ {
return GetNodeAt (new AstLocation (line, column)); return GetNodeAt (new TextLocation (line, column), pred);
} }
public AstNode GetNodeAt (AstLocation location, Predicate<AstNode> pred = null) public AstNode GetNodeAt (TextLocation location, Predicate<AstNode> pred = null)
{ {
AstNode result = null; AstNode result = null;
AstNode node = this; AstNode node = this;
@ -532,14 +533,14 @@ namespace ICSharpCode.NRefactory.CSharp
public T GetNodeAt<T> (int line, int column) where T : AstNode public T GetNodeAt<T> (int line, int column) where T : AstNode
{ {
return GetNodeAt<T> (new AstLocation (line, column)); return GetNodeAt<T> (new TextLocation (line, column));
} }
/// <summary> /// <summary>
/// Gets the node specified by T at location. This is useful for getting a specific node from the tree. For example searching /// Gets the node specified by T at location. This is useful for getting a specific node from the tree. For example searching
/// the current method declaration. /// the current method declaration.
/// </summary> /// </summary>
public T GetNodeAt<T> (AstLocation location) where T : AstNode public T GetNodeAt<T> (TextLocation location) where T : AstNode
{ {
T result = null; T result = null;
AstNode node = this; AstNode node = this;
@ -561,68 +562,12 @@ namespace ICSharpCode.NRefactory.CSharp
return result; return result;
} }
public AstNode GetResolveableNodeAt (int line, int column)
{
return GetResolveableNodeAt (new AstLocation (line, column));
}
/// <summary>
/// Gets a node that can be resolved at location.
/// </summary>
public AstNode GetResolveableNodeAt (AstLocation location)
{
return GetNodeAt (location, delegate (AstNode n) {
if (n is TypeDeclaration) {
var decl = (TypeDeclaration)n;
return decl.NameToken.StartLocation <= location && location <= decl.NameToken.EndLocation;
}
if (n is DelegateDeclaration) {
var decl = (DelegateDeclaration)n;
return decl.NameToken.StartLocation <= location && location <= decl.NameToken.EndLocation;
}
if (n is MemberDeclaration) {
var decl = (MemberDeclaration)n;
return decl.NameToken.StartLocation <= location && location <= decl.NameToken.EndLocation;
}
if (n is ConstructorDeclaration) {
var decl = (ConstructorDeclaration)n;
return decl.IdentifierToken.StartLocation <= location && location <= decl.IdentifierToken.EndLocation;
}
if (n is DestructorDeclaration) {
var decl = (DestructorDeclaration)n;
return decl.IdentifierToken.StartLocation <= location && location <= decl.IdentifierToken.EndLocation;
}
if (n is VariableInitializer) {
var decl = (VariableInitializer)n;
return decl.NameToken.StartLocation <= location && location <= decl.NameToken.EndLocation;
}
if (n is ParameterDeclaration) {
var decl = (ParameterDeclaration)n;
return decl.NameToken.StartLocation <= location && location <= decl.NameToken.EndLocation;
}
if (n is MemberReferenceExpression) {
var decl = (MemberReferenceExpression)n;
return decl.MemberNameToken.StartLocation <= location && location <= decl.MemberNameToken.EndLocation;
}
return n is IdentifierExpression || n is AstType;
});
}
public IEnumerable<AstNode> GetNodesBetween (int startLine, int startColumn, int endLine, int endColumn) public IEnumerable<AstNode> GetNodesBetween (int startLine, int startColumn, int endLine, int endColumn)
{ {
return GetNodesBetween (new AstLocation (startLine, startColumn), new AstLocation (endLine, endColumn)); return GetNodesBetween (new TextLocation (startLine, startColumn), new TextLocation (endLine, endColumn));
} }
public IEnumerable<AstNode> GetNodesBetween (AstLocation start, AstLocation end) public IEnumerable<AstNode> GetNodesBetween (TextLocation start, TextLocation end)
{ {
AstNode node = this; AstNode node = this;
while (node != null) { while (node != null) {
@ -648,10 +593,10 @@ namespace ICSharpCode.NRefactory.CSharp
public bool Contains (int line, int column) public bool Contains (int line, int column)
{ {
return Contains (new AstLocation (line, column)); return Contains (new TextLocation (line, column));
} }
public bool Contains (AstLocation location) public bool Contains (TextLocation location)
{ {
return this.StartLocation <= location && location < this.EndLocation; return this.StartLocation <= location && location < this.EndLocation;
} }
@ -663,6 +608,19 @@ namespace ICSharpCode.NRefactory.CSharp
base.AddAnnotation (annotation); base.AddAnnotation (annotation);
} }
internal string DebugToString()
{
if (IsNull)
return "Null";
StringWriter w = new StringWriter();
AcceptVisitor(new CSharpOutputVisitor(w, new CSharpFormattingOptions()), null);
string text = w.ToString().TrimEnd().Replace("\t", "").Replace(w.NewLine, " ");
if (text.Length > 100)
return text.Substring(0, 97) + "...";
else
return text;
}
// the Root role must be available when creating the null nodes, so we can't put it in the Roles class // the Root role must be available when creating the null nodes, so we can't put it in the Roles class
static readonly Role<AstNode> RootRole = new Role<AstNode> ("Root"); static readonly Role<AstNode> RootRole = new Role<AstNode> ("Root");

40
src/Libraries/NewNRefactory/ICSharpCode.NRefactory/CSharp/Ast/AstNodeCollection.cs → src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/AstNodeCollection.cs

@ -1,5 +1,20 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) // Copyright (c) AlphaSierraPapa for the SharpDevelop Team
// This code is distributed under MIT X11 license (for details please see \doc\license.txt) //
// 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;
using System.Collections; using System.Collections;
@ -132,28 +147,17 @@ namespace ICSharpCode.NRefactory.CSharp
} }
#region Equals and GetHashCode implementation #region Equals and GetHashCode implementation
public override bool Equals(object obj)
{
if (obj is AstNodeCollection<T>) {
return ((AstNodeCollection<T>)obj) == this;
} else {
return false;
}
}
public override int GetHashCode() public override int GetHashCode()
{ {
return node.GetHashCode() ^ role.GetHashCode(); return node.GetHashCode() ^ role.GetHashCode();
} }
public static bool operator ==(AstNodeCollection<T> left, AstNodeCollection<T> right) public override bool Equals(object obj)
{
return left.role == right.role && left.node == right.node;
}
public static bool operator !=(AstNodeCollection<T> left, AstNodeCollection<T> right)
{ {
return !(left.role == right.role && left.node == right.node); AstNodeCollection<T> other = obj as AstNodeCollection<T>;
if (other == null)
return false;
return this.node == other.node && this.role == other.role;
} }
#endregion #endregion

22
src/Libraries/NewNRefactory/ICSharpCode.NRefactory/CSharp/Ast/AstType.cs → src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/AstType.cs

@ -1,3 +1,21 @@
// 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;
using System.Collections.Generic; using System.Collections.Generic;
@ -19,7 +37,7 @@ namespace ICSharpCode.NRefactory.CSharp
} }
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data = default(T))
{ {
return default (S); return default (S);
} }
@ -50,7 +68,7 @@ namespace ICSharpCode.NRefactory.CSharp
get { return NodeType.Pattern; } get { return NodeType.Pattern; }
} }
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data = default(T))
{ {
return visitor.VisitPatternPlaceholder(this, child, data); return visitor.VisitPatternPlaceholder(this, child, data);
} }

49
src/Libraries/NewNRefactory/ICSharpCode.NRefactory/CSharp/Ast/CSharpModifierToken.cs → src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/CSharpModifierToken.cs

@ -1,6 +1,6 @@
// //
// CSharpModifierToken.cs // CSharpModifierToken.cs
// //
// Author: // Author:
// Mike Krüger <mkrueger@novell.com> // Mike Krüger <mkrueger@novell.com>
// //
@ -37,14 +37,8 @@ namespace ICSharpCode.NRefactory.CSharp
public Modifiers Modifier { public Modifiers Modifier {
get { return modifier; } get { return modifier; }
set { set {
for (int i = 0; i < lengthTable.Count; i++) { this.tokenLength = GetModifierName(value).Length;
if (lengthTable[i].Key == value) { this.modifier = value;
this.modifier = value;
this.tokenLength = lengthTable[i].Value;
return;
}
}
throw new ArgumentException ("Modifier " + value + " is invalid.");
} }
} }
@ -56,33 +50,21 @@ namespace ICSharpCode.NRefactory.CSharp
// Not worth using a dictionary for such few elements. // Not worth using a dictionary for such few elements.
// This table is sorted in the order that modifiers should be output when generating code. // This table is sorted in the order that modifiers should be output when generating code.
static readonly List<KeyValuePair<Modifiers, int>> lengthTable = new List<KeyValuePair<Modifiers, int>> () { static readonly Modifiers[] allModifiers = {
new KeyValuePair<Modifiers, int>(Modifiers.Public, "public".Length), Modifiers.Public, Modifiers.Protected, Modifiers.Private, Modifiers.Internal,
new KeyValuePair<Modifiers, int>(Modifiers.Protected, "protected".Length), Modifiers.New,
new KeyValuePair<Modifiers, int>(Modifiers.Private, "private".Length), Modifiers.Unsafe,
new KeyValuePair<Modifiers, int>(Modifiers.Internal, "internal".Length), Modifiers.Abstract, Modifiers.Virtual, Modifiers.Sealed, Modifiers.Static, Modifiers.Override,
new KeyValuePair<Modifiers, int>(Modifiers.New, "new".Length), Modifiers.Readonly, Modifiers.Volatile,
new KeyValuePair<Modifiers, int>(Modifiers.Unsafe, "unsafe".Length), Modifiers.Extern, Modifiers.Partial, Modifiers.Const,
new KeyValuePair<Modifiers, int>(Modifiers.Abstract, "abstract".Length), Modifiers.Any
new KeyValuePair<Modifiers, int>(Modifiers.Virtual, "virtual".Length),
new KeyValuePair<Modifiers, int>(Modifiers.Sealed, "sealed".Length),
new KeyValuePair<Modifiers, int>(Modifiers.Static, "static".Length),
new KeyValuePair<Modifiers, int>(Modifiers.Override, "override".Length),
new KeyValuePair<Modifiers, int>(Modifiers.Readonly, "readonly".Length),
new KeyValuePair<Modifiers, int>(Modifiers.Volatile, "volatile".Length),
new KeyValuePair<Modifiers, int>(Modifiers.Extern, "extern".Length),
new KeyValuePair<Modifiers, int>(Modifiers.Partial, "partial".Length),
new KeyValuePair<Modifiers, int>(Modifiers.Const, "const".Length),
// even though it's used for patterns only, it needs to be in this table to be usable in the AST
new KeyValuePair<Modifiers, int>(Modifiers.Any, "any".Length)
}; };
public static IEnumerable<Modifiers> AllModifiers { public static IEnumerable<Modifiers> AllModifiers {
get { return lengthTable.Select(p => p.Key); } get { return allModifiers; }
} }
public CSharpModifierToken (AstLocation location, Modifiers modifier) : base (location, 0) public CSharpModifierToken (TextLocation location, Modifiers modifier) : base (location, 0)
{ {
this.Modifier = modifier; this.Modifier = modifier;
} }
@ -122,8 +104,9 @@ namespace ICSharpCode.NRefactory.CSharp
return "volatile"; return "volatile";
case Modifiers.Unsafe: case Modifiers.Unsafe:
return "unsafe"; return "unsafe";
case Modifiers.Fixed: case Modifiers.Any:
return "fixed"; // even though it's used for patterns only, it needs to be in this list to be usable in the AST
return "any";
default: default:
throw new NotSupportedException("Invalid value for Modifiers"); throw new NotSupportedException("Invalid value for Modifiers");
} }

20
src/Libraries/NewNRefactory/ICSharpCode.NRefactory/CSharp/Ast/CSharpTokenNode.cs → src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/CSharpTokenNode.cs

@ -1,4 +1,4 @@
// //
// TokenNode.cs // TokenNode.cs
// //
// Author: // Author:
@ -38,11 +38,11 @@ namespace ICSharpCode.NRefactory.CSharp
} }
} }
public NullCSharpTokenNode () : base (AstLocation.Empty, 0) public NullCSharpTokenNode () : base (TextLocation.Empty, 0)
{ {
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data = default(T))
{ {
return default (S); return default (S);
} }
@ -60,34 +60,34 @@ namespace ICSharpCode.NRefactory.CSharp
} }
} }
AstLocation startLocation; TextLocation startLocation;
public override AstLocation StartLocation { public override TextLocation StartLocation {
get { get {
return startLocation; return startLocation;
} }
} }
protected int tokenLength; protected int tokenLength;
public override AstLocation EndLocation { public override TextLocation EndLocation {
get { get {
return new AstLocation (StartLocation.Line, StartLocation.Column + tokenLength); return new TextLocation (StartLocation.Line, StartLocation.Column + tokenLength);
} }
} }
public CSharpTokenNode (AstLocation location, int tokenLength) public CSharpTokenNode (TextLocation location, int tokenLength)
{ {
this.startLocation = location; this.startLocation = location;
this.tokenLength = tokenLength; this.tokenLength = tokenLength;
} }
#region IRelocationable implementation #region IRelocationable implementation
void IRelocatable.SetStartLocation (AstLocation startLocation) void IRelocatable.SetStartLocation (TextLocation startLocation)
{ {
this.startLocation = startLocation; this.startLocation = startLocation;
} }
#endregion #endregion
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data = default(T))
{ {
return visitor.VisitCSharpTokenNode (this, data); return visitor.VisitCSharpTokenNode (this, data);
} }

95
src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/CSharpUtil.cs

@ -0,0 +1,95 @@
//
// CSharpUtil.cs
//
// Author:
// Mike Krüger <mkrueger@novell.com>
//
// Copyright (c) 2011 Novell, Inc (http://www.novell.com)
//
// 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.NRefactory.CSharp
{
public static class CSharpUtil
{
public static Expression InvertCondition (Expression condition)
{
return InvertConditionInternal (condition.Clone ());
}
static Expression InvertConditionInternal (Expression condition)
{
if (condition is ParenthesizedExpression) {
((ParenthesizedExpression)condition).Expression = InvertCondition (((ParenthesizedExpression)condition).Expression);
return condition;
}
if (condition is UnaryOperatorExpression) {
var uOp = (UnaryOperatorExpression)condition;
if (uOp.Operator == UnaryOperatorType.Not)
return uOp.Expression;
return new UnaryOperatorExpression (UnaryOperatorType.Not, uOp);
}
if (condition is BinaryOperatorExpression) {
var bOp = (BinaryOperatorExpression)condition;
switch (bOp.Operator) {
case BinaryOperatorType.GreaterThan:
bOp.Operator = BinaryOperatorType.LessThanOrEqual;
return bOp;
case BinaryOperatorType.GreaterThanOrEqual:
bOp.Operator = BinaryOperatorType.LessThan;
return bOp;
case BinaryOperatorType.Equality:
bOp.Operator = BinaryOperatorType.InEquality;
return bOp;
case BinaryOperatorType.InEquality:
bOp.Operator = BinaryOperatorType.Equality;
return bOp;
case BinaryOperatorType.LessThan:
bOp.Operator = BinaryOperatorType.GreaterThanOrEqual;
return bOp;
case BinaryOperatorType.LessThanOrEqual:
bOp.Operator = BinaryOperatorType.GreaterThan;
return bOp;
default:
return new UnaryOperatorExpression (UnaryOperatorType.Not, new ParenthesizedExpression (condition));
}
}
if (condition is ConditionalExpression) {
var cEx = condition as ConditionalExpression;
cEx.Condition = InvertCondition (cEx.Condition);
return cEx;
}
if (condition is PrimitiveExpression) {
var pex = condition as PrimitiveExpression;
if (pex.Value is bool) {
pex.Value = !((bool)pex.Value);
return pex;
}
}
return new UnaryOperatorExpression (UnaryOperatorType.Not, condition);
}
}
}

2
src/Libraries/NewNRefactory/ICSharpCode.NRefactory/CSharp/Ast/CompilationUnit.cs → src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/CompilationUnit.cs

@ -83,7 +83,7 @@ namespace ICSharpCode.NRefactory.CSharp
return o != null && GetChildrenByRole(MemberRole).DoMatch(o.GetChildrenByRole(MemberRole), match); return o != null && GetChildrenByRole(MemberRole).DoMatch(o.GetChildrenByRole(MemberRole), match);
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data = default(T))
{ {
return visitor.VisitCompilationUnit (this, data); return visitor.VisitCompilationUnit (this, data);
} }

10
src/Libraries/NewNRefactory/ICSharpCode.NRefactory/CSharp/Ast/ComposedType.cs → src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/ComposedType.cs

@ -46,7 +46,7 @@ namespace ICSharpCode.NRefactory.CSharp
return !GetChildByRole(NullableRole).IsNull; return !GetChildByRole(NullableRole).IsNull;
} }
set { set {
SetChildByRole(NullableRole, value ? new CSharpTokenNode(AstLocation.Empty, 1) : null); SetChildByRole(NullableRole, value ? new CSharpTokenNode(TextLocation.Empty, 1) : null);
} }
} }
@ -63,7 +63,7 @@ namespace ICSharpCode.NRefactory.CSharp
d--; d--;
} }
while (d < value) { while (d < value) {
InsertChildBefore(GetChildByRole(PointerRole), new CSharpTokenNode(AstLocation.Empty, 1), PointerRole); InsertChildBefore(GetChildByRole(PointerRole), new CSharpTokenNode(TextLocation.Empty, 1), PointerRole);
d++; d++;
} }
} }
@ -73,7 +73,7 @@ namespace ICSharpCode.NRefactory.CSharp
get { return GetChildrenByRole (ArraySpecifierRole); } get { return GetChildrenByRole (ArraySpecifierRole); }
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data = default(T))
{ {
return visitor.VisitComposedType (this, data); return visitor.VisitComposedType (this, data);
} }
@ -149,7 +149,7 @@ namespace ICSharpCode.NRefactory.CSharp
d--; d--;
} }
while (d < value) { while (d < value) {
InsertChildBefore(GetChildByRole(Roles.Comma), new CSharpTokenNode(AstLocation.Empty, 1), Roles.Comma); InsertChildBefore(GetChildByRole(Roles.Comma), new CSharpTokenNode(TextLocation.Empty, 1), Roles.Comma);
d++; d++;
} }
} }
@ -159,7 +159,7 @@ namespace ICSharpCode.NRefactory.CSharp
get { return GetChildByRole (Roles.RBracket); } get { return GetChildByRole (Roles.RBracket); }
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data = default(T))
{ {
return visitor.VisitArraySpecifier(this, data); return visitor.VisitArraySpecifier(this, data);
} }

13
src/Libraries/NewNRefactory/ICSharpCode.NRefactory/CSharp/Ast/DepthFirstAstVisitor.cs → src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/DepthFirstAstVisitor.cs

@ -360,9 +360,9 @@ namespace ICSharpCode.NRefactory.CSharp
return VisitChildren (yieldBreakStatement, data); return VisitChildren (yieldBreakStatement, data);
} }
public virtual S VisitYieldStatement (YieldStatement yieldStatement, T data) public virtual S VisitYieldReturnStatement (YieldReturnStatement yieldReturnStatement, T data)
{ {
return VisitChildren (yieldStatement, data); return VisitChildren (yieldReturnStatement, data);
} }
public virtual S VisitAnonymousMethodExpression (AnonymousMethodExpression anonymousMethodExpression, T data) public virtual S VisitAnonymousMethodExpression (AnonymousMethodExpression anonymousMethodExpression, T data)
@ -445,9 +445,9 @@ namespace ICSharpCode.NRefactory.CSharp
return VisitChildren (anonymousTypeCreateExpression, data); return VisitChildren (anonymousTypeCreateExpression, data);
} }
public virtual S VisitArrayCreateExpression (ArrayCreateExpression arrayObjectCreateExpression, T data) public virtual S VisitArrayCreateExpression (ArrayCreateExpression arrayCreateExpression, T data)
{ {
return VisitChildren (arrayObjectCreateExpression, data); return VisitChildren (arrayCreateExpression, data);
} }
public virtual S VisitParenthesizedExpression (ParenthesizedExpression parenthesizedExpression, T data) public virtual S VisitParenthesizedExpression (ParenthesizedExpression parenthesizedExpression, T data)
@ -585,6 +585,11 @@ namespace ICSharpCode.NRefactory.CSharp
return VisitChildren (namedArgumentExpression, data); return VisitChildren (namedArgumentExpression, data);
} }
public virtual S VisitNamedExpression (NamedExpression namedExpression, T data)
{
return VisitChildren (namedExpression, data);
}
public virtual S VisitEmptyExpression (EmptyExpression emptyExpression, T data) public virtual S VisitEmptyExpression (EmptyExpression emptyExpression, T data)
{ {
return VisitChildren (emptyExpression, data); return VisitChildren (emptyExpression, data);

10
src/Libraries/NewNRefactory/ICSharpCode.NRefactory/CSharp/Ast/ErrorNode.cs → src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/ErrorNode.cs

@ -1,4 +1,4 @@
// //
// ErrorNode.cs // ErrorNode.cs
// //
// Author: // Author:
@ -34,7 +34,7 @@ namespace ICSharpCode.NRefactory.CSharp
/// </summary> /// </summary>
public class ErrorNode : AstNode public class ErrorNode : AstNode
{ {
static AstLocation maxLoc = new AstLocation (int.MaxValue, int.MaxValue); static TextLocation maxLoc = new TextLocation (int.MaxValue, int.MaxValue);
public override NodeType NodeType { public override NodeType NodeType {
get { get {
@ -42,13 +42,13 @@ namespace ICSharpCode.NRefactory.CSharp
} }
} }
public override AstLocation StartLocation { public override TextLocation StartLocation {
get { get {
return maxLoc; return maxLoc;
} }
} }
public override AstLocation EndLocation { public override TextLocation EndLocation {
get { get {
return maxLoc; return maxLoc;
} }
@ -58,7 +58,7 @@ namespace ICSharpCode.NRefactory.CSharp
{ {
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data = default(T))
{ {
// nothing // nothing
return default (S); return default (S);

13
src/Libraries/NewNRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/AnonymousMethodExpression.cs → src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/AnonymousMethodExpression.cs

@ -30,11 +30,15 @@ using System.Linq;
namespace ICSharpCode.NRefactory.CSharp namespace ICSharpCode.NRefactory.CSharp
{ {
/// <summary> /// <summary>
/// delegate(Parameters) {Body} /// [async] delegate(Parameters) {Body}
/// </summary> /// </summary>
public class AnonymousMethodExpression : Expression public class AnonymousMethodExpression : Expression
{ {
// used to make a difference between delegate {} and delegate () {} public readonly static Role<CSharpTokenNode> AsyncModifierRole = LambdaExpression.AsyncModifierRole;
public bool IsAsync { get; set; }
// used to tell the difference between delegate {} and delegate () {}
public bool HasParameterList { public bool HasParameterList {
get; set; get; set;
} }
@ -78,7 +82,7 @@ namespace ICSharpCode.NRefactory.CSharp
{ {
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data = default(T))
{ {
return visitor.VisitAnonymousMethodExpression (this, data); return visitor.VisitAnonymousMethodExpression (this, data);
} }
@ -86,7 +90,8 @@ namespace ICSharpCode.NRefactory.CSharp
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
{ {
AnonymousMethodExpression o = other as AnonymousMethodExpression; AnonymousMethodExpression o = other as AnonymousMethodExpression;
return o != null && this.HasParameterList == o.HasParameterList && this.Parameters.DoMatch(o.Parameters, match) && this.Body.DoMatch(o.Body, match); return o != null && this.IsAsync == o.IsAsync && this.HasParameterList == o.HasParameterList
&& this.Parameters.DoMatch(o.Parameters, match) && this.Body.DoMatch(o.Body, match);
} }
} }
} }

12
src/Libraries/NewNRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/AnonymousTypeCreateExpression.cs → src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/AnonymousTypeCreateExpression.cs

@ -1,4 +1,4 @@
// //
// AnonymousTypeCreateExpression.cs // AnonymousTypeCreateExpression.cs
// //
// Author: // Author:
@ -41,7 +41,7 @@ namespace ICSharpCode.NRefactory.CSharp
get { return GetChildByRole (Roles.LPar); } get { return GetChildByRole (Roles.LPar); }
} }
public AstNodeCollection<Expression> Initializer { public AstNodeCollection<Expression> Initializers {
get { return GetChildrenByRole (Roles.Expression); } get { return GetChildrenByRole (Roles.Expression); }
} }
@ -53,9 +53,9 @@ namespace ICSharpCode.NRefactory.CSharp
{ {
} }
public AnonymousTypeCreateExpression (IEnumerable<Expression> initializer) public AnonymousTypeCreateExpression (IEnumerable<Expression> initializers)
{ {
foreach (var ini in initializer) { foreach (var ini in initializers) {
AddChild (ini, Roles.Expression); AddChild (ini, Roles.Expression);
} }
} }
@ -64,7 +64,7 @@ namespace ICSharpCode.NRefactory.CSharp
{ {
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data = default(T))
{ {
return visitor.VisitAnonymousTypeCreateExpression (this, data); return visitor.VisitAnonymousTypeCreateExpression (this, data);
} }
@ -72,7 +72,7 @@ namespace ICSharpCode.NRefactory.CSharp
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
{ {
var o = other as AnonymousTypeCreateExpression; var o = other as AnonymousTypeCreateExpression;
return o != null && this.Initializer.DoMatch(o.Initializer, match); return o != null && this.Initializers.DoMatch(o.Initializers, match);
} }
} }
} }

20
src/Libraries/NewNRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ArrayCreateExpression.cs → src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/ArrayCreateExpression.cs

@ -1,3 +1,21 @@
// 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;
using System.Collections.Generic; using System.Collections.Generic;
@ -33,7 +51,7 @@ namespace ICSharpCode.NRefactory.CSharp
set { SetChildByRole (InitializerRole, value); } set { SetChildByRole (InitializerRole, value); }
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data = default(T))
{ {
return visitor.VisitArrayCreateExpression (this, data); return visitor.VisitArrayCreateExpression (this, data);
} }

18
src/Libraries/NewNRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ArrayInitializerExpression.cs → src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/ArrayInitializerExpression.cs

@ -33,6 +33,20 @@ namespace ICSharpCode.NRefactory.CSharp
/// </summary> /// </summary>
public class ArrayInitializerExpression : Expression public class ArrayInitializerExpression : Expression
{ {
public ArrayInitializerExpression()
{
}
public ArrayInitializerExpression(IEnumerable<Expression> elements)
{
this.Elements.AddRange(elements);
}
public ArrayInitializerExpression(params Expression[] elements)
{
this.Elements.AddRange(elements);
}
#region Null #region Null
public new static readonly ArrayInitializerExpression Null = new NullArrayInitializerExpression (); public new static readonly ArrayInitializerExpression Null = new NullArrayInitializerExpression ();
@ -44,7 +58,7 @@ namespace ICSharpCode.NRefactory.CSharp
} }
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data = default(T))
{ {
return default (S); return default (S);
} }
@ -68,7 +82,7 @@ namespace ICSharpCode.NRefactory.CSharp
get { return GetChildByRole (Roles.RBrace); } get { return GetChildByRole (Roles.RBrace); }
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data = default(T))
{ {
return visitor.VisitArrayInitializerExpression (this, data); return visitor.VisitArrayInitializerExpression (this, data);
} }

2
src/Libraries/NewNRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/AsExpression.cs → src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/AsExpression.cs

@ -55,7 +55,7 @@ namespace ICSharpCode.NRefactory.CSharp
AddChild (type, Roles.Type); AddChild (type, Roles.Type);
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data = default(T))
{ {
return visitor.VisitAsExpression (this, data); return visitor.VisitAsExpression (this, data);
} }

2
src/Libraries/NewNRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/AssignmentExpression.cs → src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/AssignmentExpression.cs

@ -74,7 +74,7 @@ namespace ICSharpCode.NRefactory.CSharp
set { SetChildByRole(RightRole, value); } set { SetChildByRole(RightRole, value); }
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data = default(T))
{ {
return visitor.VisitAssignmentExpression (this, data); return visitor.VisitAssignmentExpression (this, data);
} }

10
src/Libraries/NewNRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/BaseReferenceExpression.cs → src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/BaseReferenceExpression.cs

@ -31,23 +31,23 @@ namespace ICSharpCode.NRefactory.CSharp
/// </summary> /// </summary>
public class BaseReferenceExpression : Expression public class BaseReferenceExpression : Expression
{ {
public AstLocation Location { public TextLocation Location {
get; get;
set; set;
} }
public override AstLocation StartLocation { public override TextLocation StartLocation {
get { get {
return Location; return Location;
} }
} }
public override AstLocation EndLocation { public override TextLocation EndLocation {
get { get {
return new AstLocation (Location.Line, Location.Column + "base".Length); return new TextLocation (Location.Line, Location.Column + "base".Length);
} }
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data = default(T))
{ {
return visitor.VisitBaseReferenceExpression (this, data); return visitor.VisitBaseReferenceExpression (this, data);
} }

15
src/Libraries/NewNRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/BinaryOperatorExpression.cs → src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/BinaryOperatorExpression.cs

@ -67,7 +67,7 @@ namespace ICSharpCode.NRefactory.CSharp
set { SetChildByRole(RightRole, value); } set { SetChildByRole(RightRole, value); }
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data = default(T))
{ {
return visitor.VisitBinaryOperatorExpression (this, data); return visitor.VisitBinaryOperatorExpression (this, data);
} }
@ -128,11 +128,15 @@ namespace ICSharpCode.NRefactory.CSharp
public enum BinaryOperatorType public enum BinaryOperatorType
{ {
/// <summary>
/// Any binary operator (used in pattern matching)
/// </summary>
Any,
// We avoid 'logical or' on purpose, because it's not clear if that refers to the bitwise // We avoid 'logical or' on purpose, because it's not clear if that refers to the bitwise
// or to the short-circuiting (conditional) operator: // or to the short-circuiting (conditional) operator:
// MCS and old NRefactory used bitwise='|', logical='||' // MCS and old NRefactory used bitwise='|', logical='||'
// but the C# spec uses logical='|', conditional='||' // but the C# spec uses logical='|', conditional='||'
/// <summary>left &amp; right</summary> /// <summary>left &amp; right</summary>
BitwiseAnd, BitwiseAnd,
/// <summary>left | right</summary> /// <summary>left | right</summary>
@ -174,11 +178,6 @@ namespace ICSharpCode.NRefactory.CSharp
ShiftRight, ShiftRight,
/// <summary>left ?? right</summary> /// <summary>left ?? right</summary>
NullCoalescing, NullCoalescing
/// <summary>
/// Any binary operator (used in pattern matching)
/// </summary>
Any
} }
} }

2
src/Libraries/NewNRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/CastExpression.cs → src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/CastExpression.cs

@ -59,7 +59,7 @@ namespace ICSharpCode.NRefactory.CSharp
AddChild (expression, Roles.Expression); AddChild (expression, Roles.Expression);
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data = default(T))
{ {
return visitor.VisitCastExpression (this, data); return visitor.VisitCastExpression (this, data);
} }

2
src/Libraries/NewNRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/CheckedExpression.cs → src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/CheckedExpression.cs

@ -57,7 +57,7 @@ namespace ICSharpCode.NRefactory.CSharp
AddChild (expression, Roles.Expression); AddChild (expression, Roles.Expression);
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data = default(T))
{ {
return visitor.VisitCheckedExpression (this, data); return visitor.VisitCheckedExpression (this, data);
} }

2
src/Libraries/NewNRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ConditionalExpression.cs → src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/ConditionalExpression.cs

@ -71,7 +71,7 @@ namespace ICSharpCode.NRefactory.CSharp
AddChild (falseExpression, FalseRole); AddChild (falseExpression, FalseRole);
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data = default(T))
{ {
return visitor.VisitConditionalExpression (this, data); return visitor.VisitConditionalExpression (this, data);
} }

2
src/Libraries/NewNRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/DefaultValueExpression.cs → src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/DefaultValueExpression.cs

@ -57,7 +57,7 @@ namespace ICSharpCode.NRefactory.CSharp
AddChild (type, Roles.Type); AddChild (type, Roles.Type);
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data = default(T))
{ {
return visitor.VisitDefaultValueExpression (this, data); return visitor.VisitDefaultValueExpression (this, data);
} }

2
src/Libraries/NewNRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/DirectionExpression.cs → src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/DirectionExpression.cs

@ -62,7 +62,7 @@ namespace ICSharpCode.NRefactory.CSharp
AddChild (expression, Roles.Expression); AddChild (expression, Roles.Expression);
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data = default(T))
{ {
return visitor.VisitDirectionExpression (this, data); return visitor.VisitDirectionExpression (this, data);
} }

14
src/Libraries/NewNRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/EmptyExpression.cs → src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/EmptyExpression.cs

@ -1,4 +1,4 @@
// //
// EmptyExpression.cs // EmptyExpression.cs
// //
// Author: // Author:
@ -32,15 +32,15 @@ namespace ICSharpCode.NRefactory.CSharp
/// </summary> /// </summary>
public class EmptyExpression : Expression, IRelocatable public class EmptyExpression : Expression, IRelocatable
{ {
AstLocation location; TextLocation location;
public override AstLocation StartLocation { public override TextLocation StartLocation {
get { get {
return location; return location;
} }
} }
public override AstLocation EndLocation { public override TextLocation EndLocation {
get { get {
return location; return location;
} }
@ -50,19 +50,19 @@ namespace ICSharpCode.NRefactory.CSharp
{ {
} }
public EmptyExpression (AstLocation location) public EmptyExpression (TextLocation location)
{ {
this.location = location; this.location = location;
} }
#region IRelocationable implementation #region IRelocationable implementation
void IRelocatable.SetStartLocation (AstLocation startLocation) void IRelocatable.SetStartLocation (TextLocation startLocation)
{ {
this.location = startLocation; this.location = startLocation;
} }
#endregion #endregion
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data = default(T))
{ {
return visitor.VisitEmptyExpression (this, data); return visitor.VisitEmptyExpression (this, data);
} }

31
src/Libraries/NewNRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/Expression.cs → src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/Expression.cs

@ -1,10 +1,23 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) // Copyright (c) AlphaSierraPapa for the SharpDevelop Team
// This code is distributed under MIT X11 license (for details please see \doc\license.txt) //
// 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;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace ICSharpCode.NRefactory.CSharp namespace ICSharpCode.NRefactory.CSharp
{ {
@ -28,7 +41,7 @@ namespace ICSharpCode.NRefactory.CSharp
} }
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data = default(T))
{ {
return default (S); return default (S);
} }
@ -59,7 +72,7 @@ namespace ICSharpCode.NRefactory.CSharp
get { return NodeType.Pattern; } get { return NodeType.Pattern; }
} }
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data = default(T))
{ {
return visitor.VisitPatternPlaceholder(this, child, data); return visitor.VisitPatternPlaceholder(this, child, data);
} }
@ -90,11 +103,7 @@ namespace ICSharpCode.NRefactory.CSharp
// Make debugging easier by giving Expressions a ToString() implementation // Make debugging easier by giving Expressions a ToString() implementation
public override string ToString() public override string ToString()
{ {
if (IsNull) return DebugToString();
return "Null";
StringWriter w = new StringWriter();
AcceptVisitor(new OutputVisitor(w, new CSharpFormattingOptions()), null);
return w.ToString();
} }
public Expression ReplaceWith(Func<Expression, Expression> replaceFunction) public Expression ReplaceWith(Func<Expression, Expression> replaceFunction)

6
src/Libraries/NewNRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/IdentifierExpression.cs → src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/IdentifierExpression.cs

@ -38,7 +38,7 @@ namespace ICSharpCode.NRefactory.CSharp
this.Identifier = identifier; this.Identifier = identifier;
} }
public IdentifierExpression(string identifier, AstLocation location) public IdentifierExpression(string identifier, TextLocation location)
{ {
SetChildByRole(Roles.Identifier, CSharp.Identifier.Create (identifier, location)); SetChildByRole(Roles.Identifier, CSharp.Identifier.Create (identifier, location));
} }
@ -52,7 +52,7 @@ namespace ICSharpCode.NRefactory.CSharp
return GetChildByRole (Roles.Identifier).Name; return GetChildByRole (Roles.Identifier).Name;
} }
set { set {
SetChildByRole(Roles.Identifier, CSharp.Identifier.Create (value, AstLocation.Empty)); SetChildByRole(Roles.Identifier, CSharp.Identifier.Create (value, TextLocation.Empty));
} }
} }
@ -60,7 +60,7 @@ namespace ICSharpCode.NRefactory.CSharp
get { return GetChildrenByRole (Roles.TypeArgument); } get { return GetChildrenByRole (Roles.TypeArgument); }
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data = default(T))
{ {
return visitor.VisitIdentifierExpression (this, data); return visitor.VisitIdentifierExpression (this, data);
} }

2
src/Libraries/NewNRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/IndexerExpression.cs → src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/IndexerExpression.cs

@ -68,7 +68,7 @@ namespace ICSharpCode.NRefactory.CSharp
{ {
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data = default(T))
{ {
return visitor.VisitIndexerExpression (this, data); return visitor.VisitIndexerExpression (this, data);
} }

2
src/Libraries/NewNRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/InvocationExpression.cs → src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/InvocationExpression.cs

@ -50,7 +50,7 @@ namespace ICSharpCode.NRefactory.CSharp
get { return GetChildByRole (Roles.RPar); } get { return GetChildByRole (Roles.RPar); }
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data = default(T))
{ {
return visitor.VisitInvocationExpression (this, data); return visitor.VisitInvocationExpression (this, data);
} }

2
src/Libraries/NewNRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/IsExpression.cs → src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/IsExpression.cs

@ -45,7 +45,7 @@ namespace ICSharpCode.NRefactory.CSharp
set { SetChildByRole(Roles.Type, value); } set { SetChildByRole(Roles.Type, value); }
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data = default(T))
{ {
return visitor.VisitIsExpression (this, data); return visitor.VisitIsExpression (this, data);
} }

13
src/Libraries/NewNRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/LambdaExpression.cs → src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/LambdaExpression.cs

@ -1,6 +1,6 @@
// //
// LambdaExpression.cs // LambdaExpression.cs
// //
// Author: // Author:
// Mike Krüger <mkrueger@novell.com> // Mike Krüger <mkrueger@novell.com>
// //
@ -29,14 +29,17 @@ using System.Linq;
namespace ICSharpCode.NRefactory.CSharp namespace ICSharpCode.NRefactory.CSharp
{ {
/// <summary> /// <summary>
/// Parameters => Body /// [async] Parameters => Body
/// </summary> /// </summary>
public class LambdaExpression : Expression public class LambdaExpression : Expression
{ {
public readonly static Role<CSharpTokenNode> AsyncModifierRole = new Role<CSharpTokenNode>("AsyncModifier", CSharpTokenNode.Null);
public readonly static Role<CSharpTokenNode> ArrowRole = new Role<CSharpTokenNode>("Arrow", CSharpTokenNode.Null); public readonly static Role<CSharpTokenNode> ArrowRole = new Role<CSharpTokenNode>("Arrow", CSharpTokenNode.Null);
public static readonly Role<AstNode> BodyRole = new Role<AstNode>("Body", AstNode.Null); public static readonly Role<AstNode> BodyRole = new Role<AstNode>("Body", AstNode.Null);
public AstNodeCollection<ParameterDeclaration> Parameters { public bool IsAsync { get; set; }
public AstNodeCollection<ParameterDeclaration> Parameters {
get { return GetChildrenByRole (Roles.Parameter); } get { return GetChildrenByRole (Roles.Parameter); }
} }
@ -49,7 +52,7 @@ namespace ICSharpCode.NRefactory.CSharp
set { SetChildByRole (BodyRole, value); } set { SetChildByRole (BodyRole, value); }
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data = default(T))
{ {
return visitor.VisitLambdaExpression (this, data); return visitor.VisitLambdaExpression (this, data);
} }
@ -57,7 +60,7 @@ namespace ICSharpCode.NRefactory.CSharp
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
{ {
LambdaExpression o = other as LambdaExpression; LambdaExpression o = other as LambdaExpression;
return o != null && this.Parameters.DoMatch(o.Parameters, match) && this.Body.DoMatch(o.Body, match); return o != null && this.IsAsync == o.IsAsync && this.Parameters.DoMatch(o.Parameters, match) && this.Body.DoMatch(o.Body, match);
} }
} }
} }

6
src/Libraries/NewNRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/MemberReferenceExpression.cs → src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/MemberReferenceExpression.cs

@ -1,4 +1,4 @@
// //
// MemberReferenceExpression.cs // MemberReferenceExpression.cs
// //
// Author: // Author:
@ -43,7 +43,7 @@ namespace ICSharpCode.NRefactory.CSharp
return GetChildByRole (Roles.Identifier).Name; return GetChildByRole (Roles.Identifier).Name;
} }
set { set {
SetChildByRole (Roles.Identifier, Identifier.Create (value, AstLocation.Empty)); SetChildByRole (Roles.Identifier, Identifier.Create (value, TextLocation.Empty));
} }
} }
@ -87,7 +87,7 @@ namespace ICSharpCode.NRefactory.CSharp
{ {
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data = default(T))
{ {
return visitor.VisitMemberReferenceExpression (this, data); return visitor.VisitMemberReferenceExpression (this, data);
} }

77
src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/NamedArgumentExpression.cs

@ -0,0 +1,77 @@
// 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;
namespace ICSharpCode.NRefactory.CSharp
{
/// <summary>
/// Represents a named argument passed to a method or attribute.
/// name: expression
/// </summary>
public class NamedArgumentExpression : Expression
{
public NamedArgumentExpression()
{
}
public NamedArgumentExpression(string identifier, Expression expression)
{
this.Identifier = identifier;
this.Expression = expression;
}
public string Identifier {
get {
return GetChildByRole (Roles.Identifier).Name;
}
set {
SetChildByRole(Roles.Identifier, CSharp.Identifier.Create (value, TextLocation.Empty));
}
}
public Identifier IdentifierToken {
get {
return GetChildByRole (Roles.Identifier);
}
set {
SetChildByRole(Roles.Identifier, value);
}
}
public CSharpTokenNode ColonToken {
get { return GetChildByRole (Roles.Colon); }
}
public Expression Expression {
get { return GetChildByRole (Roles.Expression); }
set { SetChildByRole (Roles.Expression, value); }
}
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data = default(T))
{
return visitor.VisitNamedArgumentExpression(this, data);
}
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
{
NamedArgumentExpression o = other as NamedArgumentExpression;
return o != null && MatchString(this.Identifier, o.Identifier) && this.Expression.DoMatch(o.Expression, match);
}
}
}

86
src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/NamedExpression.cs

@ -0,0 +1,86 @@
//
// NamedExpression.cs
//
// Author:
// Mike Krüger <mkrueger@xamarin.com>
//
// Copyright (c) 2011 Xamarin
//
// 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.Collections.Generic;
using System.Linq;
namespace ICSharpCode.NRefactory.CSharp
{
/// <summary>
/// name = expression
/// This isn't the same as 'assign' even if it has the same syntax. This expression is used in object initializers.
/// </summary>
public class NamedExpression : Expression
{
public NamedExpression()
{
}
public NamedExpression (string identifier, Expression expression)
{
this.Identifier = identifier;
this.Expression = expression;
}
public string Identifier {
get {
return GetChildByRole (Roles.Identifier).Name;
}
set {
SetChildByRole(Roles.Identifier, CSharp.Identifier.Create (value, TextLocation.Empty));
}
}
public Identifier IdentifierToken {
get {
return GetChildByRole (Roles.Identifier);
}
set {
SetChildByRole(Roles.Identifier, value);
}
}
public CSharpTokenNode AssignToken {
get { return GetChildByRole (Roles.Assign); }
}
public Expression Expression {
get { return GetChildByRole (Roles.Expression); }
set { SetChildByRole (Roles.Expression, value); }
}
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data = default(T))
{
return visitor.VisitNamedExpression(this, data);
}
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
{
var o = other as NamedExpression;
return o != null && MatchString(this.Identifier, o.Identifier) && this.Expression.DoMatch(o.Expression, match);
}
}
}

12
src/Libraries/NewNRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/NullReferenceExpression.cs → src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/NullReferenceExpression.cs

@ -31,16 +31,16 @@ namespace ICSharpCode.NRefactory.CSharp
/// </summary> /// </summary>
public class NullReferenceExpression : Expression public class NullReferenceExpression : Expression
{ {
AstLocation location; TextLocation location;
public override AstLocation StartLocation { public override TextLocation StartLocation {
get { get {
return location; return location;
} }
} }
public override AstLocation EndLocation { public override TextLocation EndLocation {
get { get {
return new AstLocation (location.Line, location.Column + "null".Length); return new TextLocation (location.Line, location.Column + "null".Length);
} }
} }
@ -48,12 +48,12 @@ namespace ICSharpCode.NRefactory.CSharp
{ {
} }
public NullReferenceExpression (AstLocation location) public NullReferenceExpression (TextLocation location)
{ {
this.location = location; this.location = location;
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data = default(T))
{ {
return visitor.VisitNullReferenceExpression (this, data); return visitor.VisitNullReferenceExpression (this, data);
} }

2
src/Libraries/NewNRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ObjectCreateExpression.cs → src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/ObjectCreateExpression.cs

@ -79,7 +79,7 @@ namespace ICSharpCode.NRefactory.CSharp
{ {
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data = default(T))
{ {
return visitor.VisitObjectCreateExpression (this, data); return visitor.VisitObjectCreateExpression (this, data);
} }

2
src/Libraries/NewNRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ParenthesizedExpression.cs → src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/ParenthesizedExpression.cs

@ -53,7 +53,7 @@ namespace ICSharpCode.NRefactory.CSharp
Expression = expr; Expression = expr;
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data = default(T))
{ {
return visitor.VisitParenthesizedExpression (this, data); return visitor.VisitParenthesizedExpression (this, data);
} }

6
src/Libraries/NewNRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/PointerReferenceExpression.cs → src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/PointerReferenceExpression.cs

@ -1,4 +1,4 @@
// //
// PointerReferenceExpression.cs // PointerReferenceExpression.cs
// //
// Author: // Author:
@ -45,7 +45,7 @@ namespace ICSharpCode.NRefactory.CSharp
return GetChildByRole (Roles.Identifier).Name; return GetChildByRole (Roles.Identifier).Name;
} }
set { set {
SetChildByRole(Roles.Identifier, Identifier.Create (value, AstLocation.Empty)); SetChildByRole(Roles.Identifier, Identifier.Create (value, TextLocation.Empty));
} }
} }
@ -53,7 +53,7 @@ namespace ICSharpCode.NRefactory.CSharp
get { return GetChildrenByRole (Roles.TypeArgument); } get { return GetChildrenByRole (Roles.TypeArgument); }
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data = default(T))
{ {
return visitor.VisitPointerReferenceExpression (this, data); return visitor.VisitPointerReferenceExpression (this, data);
} }

14
src/Libraries/NewNRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/PrimitiveExpression.cs → src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/PrimitiveExpression.cs

@ -33,17 +33,17 @@ namespace ICSharpCode.NRefactory.CSharp
{ {
public static readonly object AnyValue = new object(); public static readonly object AnyValue = new object();
AstLocation startLocation; TextLocation startLocation;
public override AstLocation StartLocation { public override TextLocation StartLocation {
get { get {
return startLocation; return startLocation;
} }
} }
string literalValue; string literalValue;
public override AstLocation EndLocation { public override TextLocation EndLocation {
get { get {
return new AstLocation (StartLocation.Line, StartLocation.Column + literalValue.Length); return new TextLocation (StartLocation.Line, StartLocation.Column + literalValue.Length);
} }
} }
@ -69,7 +69,7 @@ namespace ICSharpCode.NRefactory.CSharp
this.literalValue = literalValue ?? ""; this.literalValue = literalValue ?? "";
} }
public PrimitiveExpression (object value, AstLocation startLocation, string literalValue) public PrimitiveExpression (object value, TextLocation startLocation, string literalValue)
{ {
this.Value = value; this.Value = value;
this.startLocation = startLocation; this.startLocation = startLocation;
@ -77,13 +77,13 @@ namespace ICSharpCode.NRefactory.CSharp
} }
#region IRelocationable implementation #region IRelocationable implementation
void IRelocatable.SetStartLocation (AstLocation startLocation) void IRelocatable.SetStartLocation (TextLocation startLocation)
{ {
this.startLocation = startLocation; this.startLocation = startLocation;
} }
#endregion #endregion
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data = default(T))
{ {
return visitor.VisitPrimitiveExpression (this, data); return visitor.VisitPrimitiveExpression (this, data);
} }

71
src/Libraries/NewNRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/QueryExpression.cs → src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/QueryExpression.cs

@ -1,5 +1,20 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) // Copyright (c) AlphaSierraPapa for the SharpDevelop Team
// This code is distributed under MIT X11 license (for details please see \doc\license.txt) //
// 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;
using System.Collections.Generic; using System.Collections.Generic;
@ -21,7 +36,7 @@ namespace ICSharpCode.NRefactory.CSharp
} }
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data = default(T))
{ {
return default (S); return default (S);
} }
@ -37,7 +52,7 @@ namespace ICSharpCode.NRefactory.CSharp
get { return GetChildrenByRole(ClauseRole); } get { return GetChildrenByRole(ClauseRole); }
} }
public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S>(IAstVisitor<T, S> visitor, T data = default(T))
{ {
return visitor.VisitQueryExpression (this, data); return visitor.VisitQueryExpression (this, data);
} }
@ -89,11 +104,15 @@ namespace ICSharpCode.NRefactory.CSharp
return GetChildByRole (Roles.Identifier).Name; return GetChildByRole (Roles.Identifier).Name;
} }
set { set {
SetChildByRole(Roles.Identifier, CSharp.Identifier.Create (value, AstLocation.Empty)); SetChildByRole(Roles.Identifier, CSharp.Identifier.Create (value, TextLocation.Empty));
} }
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public Identifier IdentifierToken {
get { return GetChildByRole (Roles.Identifier); }
}
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data = default(T))
{ {
return visitor.VisitQueryContinuationClause (this, data); return visitor.VisitQueryContinuationClause (this, data);
} }
@ -120,16 +139,20 @@ namespace ICSharpCode.NRefactory.CSharp
return GetChildByRole (Roles.Identifier).Name; return GetChildByRole (Roles.Identifier).Name;
} }
set { set {
SetChildByRole(Roles.Identifier, CSharp.Identifier.Create (value, AstLocation.Empty)); SetChildByRole(Roles.Identifier, CSharp.Identifier.Create (value, TextLocation.Empty));
} }
} }
public Identifier IdentifierToken {
get { return GetChildByRole(Roles.Identifier); }
}
public Expression Expression { public Expression Expression {
get { return GetChildByRole (Roles.Expression); } get { return GetChildByRole (Roles.Expression); }
set { SetChildByRole (Roles.Expression, value); } set { SetChildByRole (Roles.Expression, value); }
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data = default(T))
{ {
return visitor.VisitQueryFromClause (this, data); return visitor.VisitQueryFromClause (this, data);
} }
@ -153,10 +176,14 @@ namespace ICSharpCode.NRefactory.CSharp
return GetChildByRole(Roles.Identifier).Name; return GetChildByRole(Roles.Identifier).Name;
} }
set { set {
SetChildByRole(Roles.Identifier, CSharp.Identifier.Create (value, AstLocation.Empty)); SetChildByRole(Roles.Identifier, CSharp.Identifier.Create (value, TextLocation.Empty));
} }
} }
public Identifier IdentifierToken {
get { return GetChildByRole(Roles.Identifier); }
}
public CSharpTokenNode AssignToken { public CSharpTokenNode AssignToken {
get { return GetChildByRole(Roles.Assign); } get { return GetChildByRole(Roles.Assign); }
} }
@ -166,7 +193,7 @@ namespace ICSharpCode.NRefactory.CSharp
set { SetChildByRole(Roles.Expression, value); } set { SetChildByRole(Roles.Expression, value); }
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data = default(T))
{ {
return visitor.VisitQueryLetClause (this, data); return visitor.VisitQueryLetClause (this, data);
} }
@ -190,7 +217,7 @@ namespace ICSharpCode.NRefactory.CSharp
set { SetChildByRole (Roles.Condition, value); } set { SetChildByRole (Roles.Condition, value); }
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data = default(T))
{ {
return visitor.VisitQueryWhereClause (this, data); return visitor.VisitQueryWhereClause (this, data);
} }
@ -237,10 +264,14 @@ namespace ICSharpCode.NRefactory.CSharp
return GetChildByRole(JoinIdentifierRole).Name; return GetChildByRole(JoinIdentifierRole).Name;
} }
set { set {
SetChildByRole(JoinIdentifierRole, Identifier.Create (value, AstLocation.Empty)); SetChildByRole(JoinIdentifierRole, Identifier.Create (value, TextLocation.Empty));
} }
} }
public Identifier JoinIdentifierToken {
get { return GetChildByRole(JoinIdentifierRole); }
}
public CSharpTokenNode InKeyword { public CSharpTokenNode InKeyword {
get { return GetChildByRole (InKeywordRole); } get { return GetChildByRole (InKeywordRole); }
} }
@ -277,11 +308,15 @@ namespace ICSharpCode.NRefactory.CSharp
return GetChildByRole (IntoIdentifierRole).Name; return GetChildByRole (IntoIdentifierRole).Name;
} }
set { set {
SetChildByRole(IntoIdentifierRole, Identifier.Create (value, AstLocation.Empty)); SetChildByRole(IntoIdentifierRole, Identifier.Create (value, TextLocation.Empty));
} }
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public Identifier IntoIdentifierToken {
get { return GetChildByRole(IntoIdentifierRole); }
}
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data = default(T))
{ {
return visitor.VisitQueryJoinClause (this, data); return visitor.VisitQueryJoinClause (this, data);
} }
@ -309,7 +344,7 @@ namespace ICSharpCode.NRefactory.CSharp
get { return GetChildrenByRole (OrderingRole); } get { return GetChildrenByRole (OrderingRole); }
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data = default(T))
{ {
return visitor.VisitQueryOrderClause (this, data); return visitor.VisitQueryOrderClause (this, data);
} }
@ -341,7 +376,7 @@ namespace ICSharpCode.NRefactory.CSharp
get { return GetChildByRole (Roles.Keyword); } get { return GetChildByRole (Roles.Keyword); }
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data = default(T))
{ {
return visitor.VisitQueryOrdering (this, data); return visitor.VisitQueryOrdering (this, data);
} }
@ -371,7 +406,7 @@ namespace ICSharpCode.NRefactory.CSharp
set { SetChildByRole (Roles.Expression, value); } set { SetChildByRole (Roles.Expression, value); }
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data = default(T))
{ {
return visitor.VisitQuerySelectClause (this, data); return visitor.VisitQuerySelectClause (this, data);
} }
@ -408,7 +443,7 @@ namespace ICSharpCode.NRefactory.CSharp
set { SetChildByRole (KeyRole, value); } set { SetChildByRole (KeyRole, value); }
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data = default(T))
{ {
return visitor.VisitQueryGroupClause (this, data); return visitor.VisitQueryGroupClause (this, data);
} }

2
src/Libraries/NewNRefactory/ICSharpCode.NRefactory/CSharp/Ast/Expressions/SizeOfExpression.cs → src/Libraries/NewNRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/SizeOfExpression.cs

@ -57,7 +57,7 @@ namespace ICSharpCode.NRefactory.CSharp
AddChild (type, Roles.Type); AddChild (type, Roles.Type);
} }
public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data) public override S AcceptVisitor<T, S> (IAstVisitor<T, S> visitor, T data = default(T))
{ {
return visitor.VisitSizeOfExpression (this, data); return visitor.VisitSizeOfExpression (this, data);
} }

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save