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 @@ @@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 11.00
# 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}"
ProjectSection(SolutionItems) = postProject
EndProjectSection
@ -296,6 +296,21 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SettingsEditor", "src\AddIn @@ -296,6 +296,21 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SettingsEditor", "src\AddIn
{35CEF10F-2D4C-45F2-9DD1-161E0FEC583C} = {35CEF10F-2D4C-45F2-9DD1-161E0FEC583C}
EndProjectSection
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}"
ProjectSection(SolutionItems) = postProject
EndProjectSection
@ -1395,6 +1410,70 @@ Global @@ -1395,6 +1410,70 @@ Global
{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.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
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -1450,6 +1529,7 @@ Global @@ -1450,6 +1529,7 @@ Global
{BFA3BF26-33BD-4A65-B84D-C7F30D131668} = {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}
{AD8272AC-5C9E-4061-90FB-CEF15A9A3F41} = {11BF9245-88A3-4A0A-9A8A-EC9D98036B0F}
{88DA149F-21B2-48AB-82C4-28FB6BDFD783} = {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}
@ -1466,6 +1546,10 @@ Global @@ -1466,6 +1546,10 @@ Global
{5C70D6AB-0A33-43F9-B8B5-54558C35BBB1} = {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}
{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}
{DEFC8584-BEC3-4921-BD0F-40482E450B7B} = {F3662720-9EA2-4591-BBC6-97361DCE50A9}
{A569DCC1-C608-45FD-B770-4F79335EF154} = {F3662720-9EA2-4591-BBC6-97361DCE50A9}

22
SharpDevelop.sln

@ -473,6 +473,11 @@ EndProject @@ -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}"
EndProject
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
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Analysis", "Analysis", "{F355E45F-F54F-4B42-8916-9A633A392789}"
ProjectSection(SolutionItems) = postProject
@ -1131,6 +1136,22 @@ Global @@ -1131,6 +1136,22 @@ Global
{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.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
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -1238,6 +1259,7 @@ Global @@ -1238,6 +1259,7 @@ Global
{984CC812-9470-4A13-AFF9-CC44068D666C} = {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}
{53DCA265-3C3C-42F9-B647-F72BA678122B} = {814DFF39-5324-40BE-90EA-F62F758660B3}
{1F261725-6318-4434-A1B1-6C70CE4CD324} = {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}

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

@ -15,6 +15,13 @@ using Mono.Cecil; @@ -15,6 +15,13 @@ using Mono.Cecil;
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>
/// Stores the decompilation information.
/// </summary>
@ -73,9 +80,10 @@ namespace ICSharpCode.ILSpyAddIn @@ -73,9 +80,10 @@ namespace ICSharpCode.ILSpyAddIn
DecompilerContext context = new DecompilerContext(type.Module);
AstBuilder astBuilder = new AstBuilder(context);
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 {
CodeMappings = astBuilder.CodeMappings,
LocalVariables = astBuilder.LocalVariables,
@ -83,7 +91,7 @@ namespace ICSharpCode.ILSpyAddIn @@ -83,7 +91,7 @@ namespace ICSharpCode.ILSpyAddIn
};
// save the data
DebugInformation.AddOrUpdate(token, info, (k, v) => info);
DebugInformation.AddOrUpdate(token, info, (k, v) => info);*/
} catch {
return;
}
@ -104,7 +112,7 @@ namespace ICSharpCode.ILSpyAddIn @@ -104,7 +112,7 @@ namespace ICSharpCode.ILSpyAddIn
if (instruction == null)
continue;
ilRanges = new [] { instruction.ILInstructionOffset.From, instruction.ILInstructionOffset.To };
ilRanges = new int[] { instruction.ILInstructionOffset.From, instruction.ILInstructionOffset.To };
memberToken = instruction.MemberMapping.MetadataToken;
return true;
}

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

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

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

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

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

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

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

@ -0,0 +1,50 @@ @@ -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; @@ -38,7 +38,6 @@ using Mono.Cecil.Cil;
namespace ICSharpCode.Decompiler.Ast
{
using Ast = ICSharpCode.NRefactory.CSharp;
using ClassType = ICSharpCode.NRefactory.TypeSystem.ClassType;
using VarianceModifier = ICSharpCode.NRefactory.TypeSystem.VarianceModifier;
[Flags]
@ -50,7 +49,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -50,7 +49,7 @@ namespace ICSharpCode.Decompiler.Ast
DoNotUsePrimitiveTypeNames = 4
}
public class AstBuilder : BaseCodeMappings
public class AstBuilder
{
DecompilerContext context;
CompilationUnit astCompileUnit = new CompilationUnit();
@ -63,10 +62,6 @@ namespace ICSharpCode.Decompiler.Ast @@ -63,10 +62,6 @@ namespace ICSharpCode.Decompiler.Ast
throw new ArgumentNullException("context");
this.context = context;
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)
@ -141,7 +136,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -141,7 +136,7 @@ namespace ICSharpCode.Decompiler.Ast
formattingPolicy.SpaceBeforeMethodDeclarationParentheses = false;
formattingPolicy.SpaceBeforeConstructorDeclarationParentheses = 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)
@ -730,11 +725,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -730,11 +725,7 @@ namespace ICSharpCode.Decompiler.Ast
AttributedNode CreateMethod(MethodDefinition methodDef)
{
// Create mapping - used in debugger
CreateCodeMappings(methodDef.MetadataToken.ToInt32(), methodDef);
MemberMapping methodMapping = methodDef.CreateCodeMapping(this.CodeMappings[methodDef.MetadataToken.ToInt32()]);
MethodDeclaration astMethod = new MethodDeclaration().WithAnnotation(methodMapping);
MethodDeclaration astMethod = new MethodDeclaration();
astMethod.AddAnnotation(methodDef);
astMethod.ReturnType = ConvertType(methodDef.ReturnType, methodDef.MethodReturnType);
astMethod.Name = CleanName(methodDef.Name);
@ -743,12 +734,12 @@ namespace ICSharpCode.Decompiler.Ast @@ -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
if (!methodDef.IsVirtual || (methodDef.IsNewSlot && !methodDef.IsPrivate)) astMethod.Constraints.AddRange(MakeConstraints(methodDef.GenericParameters));
if (!methodDef.DeclaringType.IsInterface) {
if (!methodDef.HasOverrides) {
if (IsExplicitInterfaceImplementation(methodDef)) {
astMethod.PrivateImplementationType = ConvertType(methodDef.Overrides.First().DeclaringType);
} else {
astMethod.Modifiers = ConvertModifiers(methodDef);
if (methodDef.IsVirtual == methodDef.IsNewSlot)
SetNewModifier(astMethod);
} else {
astMethod.PrivateImplementationType = ConvertType(methodDef.Overrides.First().DeclaringType);
}
astMethod.Body = CreateMethodBody(methodDef, astMethod.Parameters);
}
@ -778,6 +769,11 @@ namespace ICSharpCode.Decompiler.Ast @@ -778,6 +769,11 @@ namespace ICSharpCode.Decompiler.Ast
}
return astMethod;
}
bool IsExplicitInterfaceImplementation(MethodDefinition methodDef)
{
return methodDef.HasOverrides && methodDef.IsPrivate;
}
IEnumerable<TypeParameterDeclaration> MakeTypeParameters(IEnumerable<GenericParameter> genericParameters)
{
@ -819,10 +815,6 @@ namespace ICSharpCode.Decompiler.Ast @@ -819,10 +815,6 @@ namespace ICSharpCode.Decompiler.Ast
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();
astMethod.AddAnnotation(methodDef);
astMethod.Modifiers = ConvertModifiers(methodDef);
@ -834,7 +826,6 @@ namespace ICSharpCode.Decompiler.Ast @@ -834,7 +826,6 @@ namespace ICSharpCode.Decompiler.Ast
astMethod.Parameters.AddRange(MakeParameters(methodDef));
astMethod.Body = CreateMethodBody(methodDef, astMethod.Parameters);
ConvertAttributes(astMethod, methodDef);
astMethod.WithAnnotation(methodMapping);
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);
}
@ -861,7 +852,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -861,7 +852,7 @@ namespace ICSharpCode.Decompiler.Ast
var accessor = propDef.GetMethod ?? propDef.SetMethod;
Modifiers getterModifiers = Modifiers.None;
Modifiers setterModifiers = Modifiers.None;
if (accessor.HasOverrides) {
if (IsExplicitInterfaceImplementation(accessor)) {
astProp.PrivateImplementationType = ConvertType(accessor.Overrides.First().DeclaringType);
} else if (!propDef.DeclaringType.IsInterface) {
getterModifiers = ConvertModifiers(propDef.GetMethod);
@ -887,10 +878,6 @@ namespace ICSharpCode.Decompiler.Ast @@ -887,10 +878,6 @@ namespace ICSharpCode.Decompiler.Ast
astProp.ReturnType = ConvertType(propDef.PropertyType, propDef);
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.Body = CreateMethodBody(propDef.GetMethod);
astProp.Getter.AddAnnotation(propDef.GetMethod);
@ -898,14 +885,8 @@ namespace ICSharpCode.Decompiler.Ast @@ -898,14 +885,8 @@ namespace ICSharpCode.Decompiler.Ast
if ((getterModifiers & Modifiers.VisibilityMask) != (astProp.Modifiers & Modifiers.VisibilityMask))
astProp.Getter.Modifiers = getterModifiers & Modifiers.VisibilityMask;
astProp.Getter.WithAnnotation(methodMapping);
}
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.Body = CreateMethodBody(propDef.SetMethod);
astProp.Setter.AddAnnotation(propDef.SetMethod);
@ -920,8 +901,6 @@ namespace ICSharpCode.Decompiler.Ast @@ -920,8 +901,6 @@ namespace ICSharpCode.Decompiler.Ast
if ((setterModifiers & Modifiers.VisibilityMask) != (astProp.Modifiers & Modifiers.VisibilityMask))
astProp.Setter.Modifiers = setterModifiers & Modifiers.VisibilityMask;
astProp.Setter.WithAnnotation(methodMapping);
}
ConvertCustomAttributes(astProp, propDef);
@ -967,34 +946,22 @@ namespace ICSharpCode.Decompiler.Ast @@ -967,34 +946,22 @@ namespace ICSharpCode.Decompiler.Ast
astEvent.AddAnnotation(eventDef);
astEvent.Name = CleanName(eventDef.Name);
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);
else
astEvent.PrivateImplementationType = ConvertType(eventDef.AddMethod.Overrides.First().DeclaringType);
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 {
Body = CreateMethodBody(eventDef.AddMethod)
}.WithAnnotation(eventDef.AddMethod);
ConvertAttributes(astEvent.AddAccessor, eventDef.AddMethod);
astEvent.AddAccessor.WithAnnotation(methodMapping);
}
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 {
Body = CreateMethodBody(eventDef.RemoveMethod)
}.WithAnnotation(eventDef.RemoveMethod);
ConvertAttributes(astEvent.RemoveAccessor, eventDef.RemoveMethod);
astEvent.RemoveAccessor.WithAnnotation(methodMapping);
}
MethodDefinition accessor = eventDef.AddMethod ?? eventDef.RemoveMethod;
if (accessor.IsVirtual == accessor.IsNewSlot) {
@ -1009,15 +976,13 @@ namespace ICSharpCode.Decompiler.Ast @@ -1009,15 +976,13 @@ namespace ICSharpCode.Decompiler.Ast
BlockStatement CreateMethodBody(MethodDefinition method, IEnumerable<ParameterDeclaration> parameters = null)
{
if (DecompileMethodBodies)
return AstMethodBodyBuilder.CreateMethodBody(method, context, parameters, LocalVariables);
return AstMethodBodyBuilder.CreateMethodBody(method, context, parameters);
else
return null;
}
FieldDeclaration CreateField(FieldDefinition fieldDef)
{
this.DecompiledMemberReferences.Add(fieldDef.MetadataToken.ToInt32(), fieldDef);
FieldDeclaration astField = new FieldDeclaration();
astField.AddAnnotation(fieldDef);
VariableInitializer initializer = new VariableInitializer(CleanName(fieldDef.Name));
@ -1112,6 +1077,11 @@ namespace ICSharpCode.Decompiler.Ast @@ -1112,6 +1077,11 @@ namespace ICSharpCode.Decompiler.Ast
attributedNode.Attributes.Add(new AttributeSection(CreateNonCustomAttribute(typeof(SerializableAttribute))));
#endregion
#region ComImportAttribute
if (typeDefinition.IsImport)
attributedNode.Attributes.Add(new AttributeSection(CreateNonCustomAttribute(typeof(ComImportAttribute))));
#endregion
#region StructLayoutAttribute
LayoutKind layoutKind = LayoutKind.Auto;
switch (typeDefinition.Attributes & TypeAttributes.LayoutMask) {
@ -1347,7 +1317,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -1347,7 +1317,7 @@ namespace ICSharpCode.Decompiler.Ast
{
if (customAttributeProvider.HasCustomAttributes) {
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") {
// don't show the ExtensionAttribute (it's converted to the 'this' modifier)
continue;
@ -1417,8 +1387,8 @@ namespace ICSharpCode.Decompiler.Ast @@ -1417,8 +1387,8 @@ namespace ICSharpCode.Decompiler.Ast
if (!secDeclProvider.HasSecurityDeclarations)
return;
var attributes = new List<ICSharpCode.NRefactory.CSharp.Attribute>();
foreach (var secDecl in secDeclProvider.SecurityDeclarations) {
foreach (var secAttribute in secDecl.SecurityAttributes) {
foreach (var secDecl in secDeclProvider.SecurityDeclarations.OrderBy(d => d.Action)) {
foreach (var secAttribute in secDecl.SecurityAttributes.OrderBy(a => a.AttributeType.FullName)) {
var attribute = new ICSharpCode.NRefactory.CSharp.Attribute();
attribute.AddAnnotation(secAttribute);
attribute.Type = ConvertType(secAttribute.AttributeType);
@ -1481,6 +1451,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -1481,6 +1451,7 @@ namespace ICSharpCode.Decompiler.Ast
ArrayType arrayType = argument.Type as ArrayType;
return new ArrayCreateExpression {
Type = ConvertType(arrayType != null ? arrayType.ElementType : argument.Type),
AdditionalArraySpecifiers = { new ArraySpecifier() },
Initializer = arrayInit
};
} else if (argument.Value is CustomAttributeArgument) {
@ -1663,11 +1634,5 @@ namespace ICSharpCode.Decompiler.Ast @@ -1663,11 +1634,5 @@ namespace ICSharpCode.Decompiler.Ast
&& (condition == null || condition(m))
&& 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 @@ -50,16 +50,11 @@ namespace ICSharpCode.Decompiler.Ast
/// <param name="context">Decompilation context.</param>
/// <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>
/// <param name="localVariables">Local variables storage that will be filled/updated with the local variables.</param>
/// <returns>Block for the method body</returns>
public static BlockStatement CreateMethodBody(MethodDefinition methodDef,
DecompilerContext context,
IEnumerable<ParameterDeclaration> parameters = null,
ConcurrentDictionary<int, IEnumerable<ILVariable>> localVariables = null)
IEnumerable<ParameterDeclaration> parameters = null)
{
if (localVariables == null)
localVariables = new ConcurrentDictionary<int, IEnumerable<ILVariable>>();
MethodDefinition oldCurrentMethod = context.CurrentMethod;
Debug.Assert(oldCurrentMethod == null || oldCurrentMethod == methodDef);
context.CurrentMethod = methodDef;
@ -69,10 +64,10 @@ namespace ICSharpCode.Decompiler.Ast @@ -69,10 +64,10 @@ namespace ICSharpCode.Decompiler.Ast
builder.context = context;
builder.typeSystem = methodDef.Module.TypeSystem;
if (Debugger.IsAttached) {
return builder.CreateMethodBody(parameters, localVariables);
return builder.CreateMethodBody(parameters);
} else {
try {
return builder.CreateMethodBody(parameters, localVariables);
return builder.CreateMethodBody(parameters);
} catch (OperationCanceledException) {
throw;
} catch (Exception ex) {
@ -84,28 +79,26 @@ namespace ICSharpCode.Decompiler.Ast @@ -84,28 +79,26 @@ namespace ICSharpCode.Decompiler.Ast
}
}
public BlockStatement CreateMethodBody(IEnumerable<ParameterDeclaration> parameters,
ConcurrentDictionary<int, IEnumerable<ILVariable>> localVariables)
public BlockStatement CreateMethodBody(IEnumerable<ParameterDeclaration> parameters)
{
if (methodDef.Body == null) return null;
if (localVariables == null)
throw new ArgumentException("localVariables must be instantiated");
if (methodDef.Body == null) {
return null;
}
context.CancellationToken.ThrowIfCancellationRequested();
ILBlock ilMethod = new ILBlock();
ILAstBuilder astBuilder = new ILAstBuilder();
ilMethod.Body = astBuilder.Build(methodDef, true);
ilMethod.Body = astBuilder.Build(methodDef, true, context);
context.CancellationToken.ThrowIfCancellationRequested();
ILAstOptimizer bodyGraph = new ILAstOptimizer();
bodyGraph.Optimize(context, ilMethod);
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();
Debug.Assert(context.CurrentMethod == methodDef);
NameVariables.AssignNamesToVariables(context, astBuilder.Parameters, allVariables, ilMethod);
NameVariables.AssignNamesToVariables(context, astBuilder.Parameters, localVariables, ilMethod);
if (parameters != null) {
foreach (var pair in (from p in parameters
@ -128,12 +121,11 @@ namespace ICSharpCode.Decompiler.Ast @@ -128,12 +121,11 @@ namespace ICSharpCode.Decompiler.Ast
else
type = AstBuilder.ConvertType(v.Type);
var newVarDecl = new VariableDeclarationStatement(type, v.Name);
newVarDecl.Variables.Single().AddAnnotation(v);
astBlock.Statements.InsertBefore(insertionPoint, newVarDecl);
}
// store the variables - used for debugger
int token = methodDef.MetadataToken.ToInt32();
localVariables.AddOrUpdate(token, allVariables, (key, oldValue) => allVariables);
astBlock.AddAnnotation(new MemberMapping(methodDef) { LocalVariables = localVariables });
return astBlock;
}
@ -210,7 +202,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -210,7 +202,7 @@ namespace ICSharpCode.Decompiler.Ast
Type = AstBuilder.ConvertType(catchClause.ExceptionType),
VariableName = catchClause.ExceptionVariable == null ? null : catchClause.ExceptionVariable.Name,
Body = TransformBlock(catchClause)
});
}.WithAnnotation(catchClause.ExceptionVariable));
}
}
if (tryCatchNode.FinallyBlock != null)
@ -258,6 +250,9 @@ namespace ICSharpCode.Decompiler.Ast @@ -258,6 +250,9 @@ namespace ICSharpCode.Decompiler.Ast
else
result = node;
if (result != null)
result = result.WithAnnotation(new TypeInformation(expr.InferredType));
if (result != null)
return result.WithAnnotation(ilRanges);
@ -375,9 +370,6 @@ namespace ICSharpCode.Decompiler.Ast @@ -375,9 +370,6 @@ namespace ICSharpCode.Decompiler.Ast
// change "new (int[,])[10] to new int[10][,]"
ct.ArraySpecifiers.MoveTo(ace.AdditionalArraySpecifiers);
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>();
foreach (var arrayDimension in arrayType.Dimensions.Skip(1).Reverse())
@ -397,7 +389,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -397,7 +389,7 @@ namespace ICSharpCode.Decompiler.Ast
ace.Initializer.Elements.AddRange(args);
return ace;
}
case ILCode.Ldlen: return arg1.Member("Length");
case ILCode.Ldlen: return arg1.Member("Length");
case ILCode.Ldelem_I:
case ILCode.Ldelem_I1:
case ILCode.Ldelem_I2:
@ -426,7 +418,13 @@ namespace ICSharpCode.Decompiler.Ast @@ -426,7 +418,13 @@ namespace ICSharpCode.Decompiler.Ast
case ILCode.CompoundAssignment:
{
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 {
Left = boe.Left.Detach(),
Operator = ReplaceMethodCallsWithOperators.GetAssignmentOperatorForBinaryOperator(boe.Operator),
@ -445,17 +443,25 @@ namespace ICSharpCode.Decompiler.Ast @@ -445,17 +443,25 @@ namespace ICSharpCode.Decompiler.Ast
#endregion
#region Comparison
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_Un: {
// can also mean Inequality, when used with object references
TypeReference arg1Type = byteCode.Arguments[0].InferredType;
if (arg1Type != null && !arg1Type.IsValueType)
return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, arg2);
else
return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2);
if (arg1Type != null && !arg1Type.IsValueType) goto case ILCode.Cne;
goto case ILCode.Cgt;
}
case ILCode.Cle_Un: {
// can also mean Equality, when used with object references
TypeReference arg1Type = byteCode.Arguments[0].InferredType;
if (arg1Type != null && !arg1Type.IsValueType) goto case ILCode.Ceq;
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_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2);
#endregion
#region Logical
case ILCode.LogicNot: return new Ast.UnaryOperatorExpression(UnaryOperatorType.Not, arg1);
@ -652,7 +658,26 @@ namespace ICSharpCode.Decompiler.Ast @@ -652,7 +658,26 @@ namespace ICSharpCode.Decompiler.Ast
if (operand is Cecil.TypeReference) {
return AstBuilder.CreateTypeOfExpression((TypeReference)operand).Member("TypeHandle");
} 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.Localloc:
@ -705,21 +730,25 @@ namespace ICSharpCode.Decompiler.Ast @@ -705,21 +730,25 @@ namespace ICSharpCode.Decompiler.Ast
return ace;
}
}
var oce = new Ast.ObjectCreateExpression();
if (declaringType.IsAnonymousType()) {
MethodDefinition ctor = ((MethodReference)operand).Resolve();
if (methodDef != null) {
oce.Initializer = new ArrayInitializerExpression();
for (int i = 0; i < args.Count; i++) {
oce.Initializer.Elements.Add(
new NamedArgumentExpression {
Identifier = ctor.Parameters[i].Name,
Expression = args[i]
});
AnonymousTypeCreateExpression atce = new AnonymousTypeCreateExpression();
if (CanInferAnonymousTypePropertyNamesFromArguments(args, ctor.Parameters)) {
atce.Initializers.AddRange(args);
} else {
for (int i = 0; i < args.Count; i++) {
atce.Initializers.Add(
new NamedExpression {
Identifier = ctor.Parameters[i].Name,
Expression = args[i]
});
}
}
return atce;
}
return oce;
}
var oce = new Ast.ObjectCreateExpression();
oce.Type = AstBuilder.ConvertType(declaringType);
oce.Arguments.AddRange(args);
return oce.WithAnnotation(operand);
@ -750,7 +779,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -750,7 +779,7 @@ namespace ICSharpCode.Decompiler.Ast
case ILCode.YieldBreak:
return new Ast.YieldBreakStatement();
case ILCode.YieldReturn:
return new Ast.YieldStatement { Expression = arg1 };
return new Ast.YieldReturnStatement { Expression = arg1 };
case ILCode.InitObject:
case ILCode.InitCollection:
{
@ -760,7 +789,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -760,7 +789,7 @@ namespace ICSharpCode.Decompiler.Ast
if (m.Success) {
MemberReferenceExpression mre = m.Get<MemberReferenceExpression>("left").Single();
initializer.Elements.Add(
new NamedArgumentExpression {
new NamedExpression {
Identifier = mre.MemberName,
Expression = m.Get<Expression>("right").Single().Detach()
}.CopyAnnotationsFrom(mre));
@ -797,13 +826,38 @@ namespace ICSharpCode.Decompiler.Ast @@ -797,13 +826,38 @@ namespace ICSharpCode.Decompiler.Ast
}
case ILCode.InitializedObject:
return new InitializedObjectExpression();
case ILCode.Wrap:
return arg1.WithAnnotation(PushNegation.LiftedOperatorAnnotation);
case ILCode.AddressOf:
return MakeRef(arg1);
case ILCode.ExpressionTreeParameterDeclarations:
args[args.Count - 1].AddAnnotation(new ParameterDeclarationAnnotation(byteCode));
return args[args.Count - 1];
case ILCode.NullableOf:
case ILCode.ValueOf: return arg1;
default:
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(
new MemberReferenceExpression {
Target = new InitializedObjectExpression()
@ -906,14 +960,21 @@ namespace ICSharpCode.Decompiler.Ast @@ -906,14 +960,21 @@ namespace ICSharpCode.Decompiler.Ast
target = ((DirectionExpression)target).Expression;
target.Remove(); // detach from DirectionExpression
}
if (cecilMethodDef != null && cecilMethodDef.DeclaringType.IsInterface) {
TypeReference tr = byteCode.Arguments[0].InferredType;
if (tr != null) {
TypeDefinition td = tr.Resolve();
if (td != null && !td.IsInterface) {
// Calling an interface method on a non-interface object:
// we need to introduce an explicit cast
target = target.CastTo(AstBuilder.ConvertType(cecilMethod.DeclaringType));
if (cecilMethodDef != null) {
// convert null.ToLower() to ((string)null).ToLower()
if (target is NullReferenceExpression)
target = target.CastTo(AstBuilder.ConvertType(cecilMethod.DeclaringType));
if (cecilMethodDef.DeclaringType.IsInterface) {
TypeReference tr = byteCode.Arguments[0].InferredType;
if (tr != null) {
TypeDefinition td = tr.Resolve();
if (td != null && !td.IsInterface) {
// Calling an interface method on a non-interface object:
// we need to introduce an explicit cast
target = target.CastTo(AstBuilder.ConvertType(cecilMethod.DeclaringType));
}
}
}
}
@ -949,29 +1010,29 @@ namespace ICSharpCode.Decompiler.Ast @@ -949,29 +1010,29 @@ namespace ICSharpCode.Decompiler.Ast
if (cecilMethodDef.IsGetter && methodArgs.Count == 0) {
foreach (var prop in cecilMethodDef.DeclaringType.Properties) {
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
PropertyDefinition indexer = GetIndexer(cecilMethodDef);
if (indexer != null)
return target.Indexer(methodArgs).WithAnnotation(indexer);
return target.Indexer(methodArgs).WithAnnotation(indexer).WithAnnotation(cecilMethod);
} else if (cecilMethodDef.IsSetter && methodArgs.Count == 1) {
foreach (var prop in cecilMethodDef.DeclaringType.Properties) {
if (prop.SetMethod == cecilMethodDef)
return new 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) {
PropertyDefinition indexer = GetIndexer(cecilMethodDef);
if (indexer != null)
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]
);
} else if (cecilMethodDef.IsAddOn && methodArgs.Count == 1) {
foreach (var ev in cecilMethodDef.DeclaringType.Events) {
if (ev.AddMethod == cecilMethodDef) {
return new Ast.AssignmentExpression {
Left = target.Member(ev.Name).WithAnnotation(ev),
Left = target.Member(ev.Name).WithAnnotation(ev).WithAnnotation(cecilMethod),
Operator = AssignmentOperatorType.Add,
Right = methodArgs[0]
};
@ -981,7 +1042,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -981,7 +1042,7 @@ namespace ICSharpCode.Decompiler.Ast
foreach (var ev in cecilMethodDef.DeclaringType.Events) {
if (ev.RemoveMethod == cecilMethodDef) {
return new Ast.AssignmentExpression {
Left = target.Member(ev.Name).WithAnnotation(ev),
Left = target.Member(ev.Name).WithAnnotation(ev).WithAnnotation(cecilMethod),
Operator = AssignmentOperatorType.Subtract,
Right = methodArgs[0]
};
@ -989,7 +1050,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -989,7 +1050,7 @@ namespace ICSharpCode.Decompiler.Ast
}
} else if (cecilMethodDef.Name == "Invoke" && cecilMethodDef.DeclaringType.BaseType != null && cecilMethodDef.DeclaringType.BaseType.FullName == "System.MulticastDelegate") {
AdjustArgumentsForMethodCall(cecilMethod, methodArgs);
return target.Invoke(methodArgs);
return target.Invoke(methodArgs).WithAnnotation(cecilMethod);
}
}
// Default invocation
@ -1002,12 +1063,13 @@ namespace ICSharpCode.Decompiler.Ast @@ -1002,12 +1063,13 @@ namespace ICSharpCode.Decompiler.Ast
// Convert 'ref' into 'out' where necessary
for (int i = 0; i < methodArgs.Count && i < cecilMethod.Parameters.Count; i++) {
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;
}
}
static PropertyDefinition GetIndexer(MethodDefinition cecilMethodDef)
internal static PropertyDefinition GetIndexer(MethodDefinition cecilMethodDef)
{
TypeDefinition typeDef = cecilMethodDef.DeclaringType;
string indexerName = null;

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

@ -90,6 +90,12 @@ namespace ICSharpCode.Decompiler.Ast @@ -90,6 +90,12 @@ namespace ICSharpCode.Decompiler.Ast
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 ITypeDefinition GetTypeDefinition(string nameSpace, string name, int typeParameterCount, StringComparer nameComparer)
@ -114,6 +120,11 @@ namespace ICSharpCode.Decompiler.Ast @@ -114,6 +120,11 @@ namespace ICSharpCode.Decompiler.Ast
return null;
}
public ITypeDefinition GetKnownTypeDefinition(TypeCode typeCode)
{
return GetTypeDefinition("System", ReflectionHelper.GetShortNameByTypeCode(typeCode), 0, StringComparer.Ordinal);
}
public IEnumerable<ITypeDefinition> GetTypes()
{
foreach (TypeDefinition cecilType in module.Types) {
@ -165,6 +176,11 @@ namespace ICSharpCode.Decompiler.Ast @@ -165,6 +176,11 @@ namespace ICSharpCode.Decompiler.Ast
get { return new IParsedFile[0]; }
}
void IProjectContent.UpdateProjectContent(IParsedFile oldFile, IParsedFile newFile)
{
throw new NotSupportedException();
}
IParsedFile IProjectContent.GetFile(string fileName)
{
return null;

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

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

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

@ -19,9 +19,9 @@ @@ -19,9 +19,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.ILAst;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.CSharp;
using Mono.Cecil;
@ -33,6 +33,8 @@ namespace ICSharpCode.Decompiler.Ast @@ -33,6 +33,8 @@ namespace ICSharpCode.Decompiler.Ast
readonly Stack<AstNode> nodeStack = new Stack<AstNode>();
int braceLevelWithinType = -1;
bool inDocumentationComment = false;
bool firstUsingDeclaration;
bool lastUsingDeclaration;
public TextOutputFormatter(ITextOutput output)
{
@ -43,12 +45,37 @@ namespace ICSharpCode.Decompiler.Ast @@ -43,12 +45,37 @@ namespace ICSharpCode.Decompiler.Ast
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);
else
output.Write(identifier);
return;
}
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()
@ -60,6 +87,76 @@ namespace ICSharpCode.Decompiler.Ast @@ -60,6 +87,76 @@ namespace ICSharpCode.Decompiler.Ast
}
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)
{
@ -70,7 +167,8 @@ namespace ICSharpCode.Decompiler.Ast @@ -70,7 +167,8 @@ namespace ICSharpCode.Decompiler.Ast
{
// Attach member reference to token only if there's no identifier in the current node.
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);
else
output.Write(token);
@ -115,6 +213,10 @@ namespace ICSharpCode.Decompiler.Ast @@ -115,6 +213,10 @@ namespace ICSharpCode.Decompiler.Ast
public void NewLine()
{
if (lastUsingDeclaration) {
output.MarkFoldEnd();
lastUsingDeclaration = false;
}
output.WriteLine();
}
@ -131,13 +233,14 @@ namespace ICSharpCode.Decompiler.Ast @@ -131,13 +233,14 @@ namespace ICSharpCode.Decompiler.Ast
output.Write("*/");
break;
case CommentType.Documentation:
if (!inDocumentationComment)
bool isLastLine = !(nodeStack.Peek().NextSibling is Comment);
if (!inDocumentationComment && !isLastLine) {
inDocumentationComment = true;
output.MarkFoldStart("///" + content, true);
}
output.Write("///");
output.Write(content);
inDocumentationComment = true;
bool isLastLine = !(nodeStack.Peek().NextSibling is Comment);
if (isLastLine) {
if (inDocumentationComment && isLastLine) {
inDocumentationComment = false;
output.MarkFoldEnd();
}
@ -146,48 +249,78 @@ namespace ICSharpCode.Decompiler.Ast @@ -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)
{
// code mappings
var ranges = node.Annotation<List<ILRange>>();
if (ranges != null && ranges.Count > 0) {
// find the ancestor that has method mapping as annotation
if (node.Parent != null)
{
var n = node.Ancestors.FirstOrDefault(a => a.Annotation<MemberMapping>() != null);
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
});
}
}
if (nodeStack.Count == 0) {
if (IsUsingDeclaration(node)) {
firstUsingDeclaration = !IsUsingDeclaration(node.PrevSibling);
lastUsingDeclaration = !IsUsingDeclaration(node.NextSibling);
} else {
firstUsingDeclaration = false;
lastUsingDeclaration = false;
}
}
nodeStack.Push(node);
startLocations.Push(output.Location);
// definitions of types and their members
Predicate<AstNode> predicate = n => n is AttributedNode;
if (predicate(node)) {
var n = node as AttributedNode;
int c = 0;
if (n != null)
c = n.Attributes.Count;
node.AddAnnotation(Tuple.Create(output.CurrentLine + c, output.CurrentColumn));
MemberMapping mapping = node.Annotation<MemberMapping>();
if (mapping != null) {
parentMemberMappings.Push(currentMemberMapping);
currentMemberMapping = mapping;
}
nodeStack.Push(node);
}
private bool IsUsingDeclaration(AstNode node)
{
return node is UsingDeclaration || node is UsingAliasDeclaration;
}
public void EndNode(AstNode node)
{
if (nodeStack.Pop() != node)
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 @@ -339,7 +339,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
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)
if (result.CostInCheckedContext + new Cost(0, 1) < result.CostInUncheckedContext) {
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 @@ -78,11 +78,17 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
}
static readonly QuerySelectClause selectTransparentIdentifierPattern = new QuerySelectClause {
Expression = new ObjectCreateExpression {
Initializer = new ArrayInitializerExpression {
Elements = {
new NamedNode("nae1", new NamedArgumentExpression { Expression = new IdentifierExpression() }),
new NamedNode("nae2", new NamedArgumentExpression { Expression = new AnyNode() })
Expression = new Choice {
new AnonymousTypeCreateExpression {
Initializers = {
new NamedNode("nae1", new NamedExpression { Expression = new IdentifierExpression() }),
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 @@ -100,12 +106,13 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
if (!match.Success)
return false;
QuerySelectClause selectClause = (QuerySelectClause)innerQuery.Clauses.Last();
NamedArgumentExpression nae1 = match.Get<NamedArgumentExpression>("nae1").Single();
NamedArgumentExpression nae2 = match.Get<NamedArgumentExpression>("nae2").Single();
if (nae1.Identifier != ((IdentifierExpression)nae1.Expression).Identifier)
NamedExpression nae1 = match.Get<NamedExpression>("nae1").SingleOrDefault();
NamedExpression nae2 = match.Get<NamedExpression>("nae2").SingleOrDefault();
if (nae1 != null && nae1.Identifier != ((IdentifierExpression)nae1.Expression).Identifier)
return false;
IdentifierExpression nae2IdentExpr = nae2.Expression as IdentifierExpression;
if (nae2IdentExpr != null && nae2.Identifier == nae2IdentExpr.Identifier) {
Expression nae2Expr = match.Get<Expression>("nae2Expr").Single();
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 x in ... ...
@ -127,7 +134,16 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -127,7 +134,16 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
foreach (var clause in innerQuery.Clauses) {
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;
}

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

@ -107,6 +107,10 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -107,6 +107,10 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
AstNode fieldOrEventDecl = members.FirstOrDefault(f => f.Annotation<FieldDefinition>() == fieldDef);
if (fieldOrEventDecl == null)
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;
for (int i = 1; i < instanceCtorsNotChainingWithThis.Length; i++) {
@ -116,7 +120,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -116,7 +120,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
if (allSame) {
foreach (var ctor in instanceCtorsNotChainingWithThis)
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);
}

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

@ -0,0 +1,109 @@ @@ -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; @@ -21,6 +21,7 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using ICSharpCode.Decompiler.ILAst;
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp.Analysis;
@ -35,6 +36,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -35,6 +36,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
{
public AstType Type;
public string Name;
public ILVariable ILVariable;
public AssignmentExpression ReplacedAssignment;
public Statement InsertionPoint;
@ -57,9 +59,12 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -57,9 +59,12 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
foreach (var v in variablesToDeclare) {
if (v.ReplacedAssignment == null) {
BlockStatement block = (BlockStatement)v.InsertionPoint.Parent;
var decl = new VariableDeclarationStatement((AstType)v.Type.Clone(), v.Name);
if (v.ILVariable != null)
decl.Variables.Single().AddAnnotation(v.ILVariable);
block.Statements.InsertBefore(
v.InsertionPoint,
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.
@ -67,9 +72,10 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -67,9 +72,10 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
if (v.ReplacedAssignment != null) {
// We clone the right expression so that it doesn't get removed from the old ExpressionStatement,
// which might be still in use by the definite assignment graph.
VariableInitializer initializer = new VariableInitializer(v.Name, v.ReplacedAssignment.Right.Detach()).CopyAnnotationsFrom(v.ReplacedAssignment).WithAnnotation(v.ILVariable);
VariableDeclarationStatement varDecl = new VariableDeclarationStatement {
Type = (AstType)v.Type.Clone(),
Variables = { new VariableInitializer(v.Name, v.ReplacedAssignment.Right.Detach()).CopyAnnotationsFrom(v.ReplacedAssignment) }
Variables = { initializer }
};
ExpressionStatement es = v.ReplacedAssignment.Parent as ExpressionStatement;
if (es != null) {
@ -100,9 +106,11 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -100,9 +106,11 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
daa = new DefiniteAssignmentAnalysis(block, cancellationToken);
}
foreach (VariableDeclarationStatement varDecl in variables) {
string variableName = varDecl.Variables.Single().Name;
bool allowPassIntoLoops = varDecl.Variables.Single().Annotation<DelegateConstruction.CapturedVariableAnnotation>() == null;
DeclareVariableInBlock(daa, block, varDecl.Type, variableName, allowPassIntoLoops);
VariableInitializer initializer = varDecl.Variables.Single();
string variableName = initializer.Name;
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 @@ -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
Statement declarationPoint = null;
@ -139,10 +147,10 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -139,10 +147,10 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
foreach (AstNode child in stmt.Children) {
BlockStatement subBlock = child as BlockStatement;
if (subBlock != null) {
DeclareVariableInBlock(daa, subBlock, type, variableName, allowPassIntoLoops);
DeclareVariableInBlock(daa, subBlock, type, variableName, v, allowPassIntoLoops);
} else if (HasNestedBlocks(child)) {
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 @@ -151,7 +159,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
// Try converting an assignment expression into a VariableDeclarationStatement
if (!TryConvertAssignmentExpressionIntoVariableDeclaration(declarationPoint, type, variableName)) {
// Declare the variable in front of declarationPoint
variablesToDeclare.Add(new VariableToDeclare { Type = type, Name = variableName, InsertionPoint = declarationPoint });
variablesToDeclare.Add(new VariableToDeclare { Type = type, Name = variableName, ILVariable = v, InsertionPoint = declarationPoint });
}
}
}
@ -172,7 +180,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -172,7 +180,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
if (ae != null && ae.Operator == AssignmentOperatorType.Assign) {
IdentifierExpression ident = ae.Left as IdentifierExpression;
if (ident != null && ident.Identifier == variableName) {
variablesToDeclare.Add(new VariableToDeclare { Type = type, Name = variableName, ReplacedAssignment = ae });
variablesToDeclare.Add(new VariableToDeclare { Type = type, Name = variableName, ILVariable = ident.Annotation<ILVariable>(), ReplacedAssignment = ae });
return true;
}
}

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

@ -209,6 +209,18 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -209,6 +209,18 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
return true;
}
public override object VisitInvocationExpression(InvocationExpression invocationExpression, object data)
{
if (context.Settings.ExpressionTrees && ExpressionTreeConverter.CouldBeExpressionTree(invocationExpression)) {
Expression converted = ExpressionTreeConverter.TryConvert(context, invocationExpression);
if (converted != null) {
invocationExpression.ReplaceWith(converted);
return converted.AcceptVisitor(this, data);
}
}
return base.VisitInvocationExpression(invocationExpression, data);
}
#region Track current variables
public override object VisitMethodDeclaration(MethodDeclaration methodDeclaration, object data)
{
@ -386,7 +398,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -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)
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) {
if (field.IsStatic)
continue; // skip static fields
@ -397,8 +409,14 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -397,8 +409,14 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
capturedVariableName = capturedVariableName.Substring(10);
EnsureVariableNameIsAvailable(blockStatement, capturedVariableName);
currentlyUsedVariableNames.Add(capturedVariableName);
variablesToDeclare.Add(Tuple.Create(AstBuilder.ConvertType(field.FieldType, field), capturedVariableName));
dict[field] = new IdentifierExpression(capturedVariableName);
ILVariable ilVar = new ILVariable
{
IsGenerated = true,
Name = capturedVariableName,
Type = field.FieldType,
};
variablesToDeclare.Add(Tuple.Create(AstBuilder.ConvertType(field.FieldType, field), ilVar));
dict[field] = new IdentifierExpression(capturedVariableName).WithAnnotation(ilVar);
}
// Now figure out where the closure was accessed and use the simpler replacement expression there:
@ -414,15 +432,16 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -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):
Statement insertionPoint = blockStatement.Statements.FirstOrDefault();
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(tuple.Item2);
blockStatement.Statements.InsertBefore(insertionPoint, newVarDecl);
}
}
currentlyUsedVariableNames.RemoveRange(numberOfVariablesOutsideBlock, currentlyUsedVariableNames.Count - numberOfVariablesOutsideBlock);
return null;
}
void EnsureVariableNameIsAvailable(AstNode currentNode, string name)
{
int pos = currentlyUsedVariableNames.IndexOf(name);

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

@ -0,0 +1,875 @@ @@ -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 @@ @@ -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 @@ -45,7 +45,11 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
if (d != null) {
foreach (var ca in d.CustomAttributes) {
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()) {
// 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

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

@ -227,6 +227,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -227,6 +227,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
Name = variableName,
Initializer = m1.Get<Expression>("initializer").Single().Detach()
}.CopyAnnotationsFrom(node.Expression)
.WithAnnotation(m1.Get<AstNode>("variable").Single().Annotation<ILVariable>())
}
}.CopyAnnotationsFrom(node);
} else {
@ -382,7 +383,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -382,7 +383,7 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
VariableName = itemVar.Identifier,
InExpression = m.Get<Expression>("collection").Single().Detach(),
EmbeddedStatement = newBody
};
}.WithAnnotation(itemVarDecl.Variables.Single().Annotation<ILVariable>());
if (foreachStatement.InExpression is BaseReferenceExpression) {
foreachStatement.InExpression = new ThisReferenceExpression().CopyAnnotationsFrom(foreachStatement.InExpression);
}
@ -471,10 +472,12 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -471,10 +472,12 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
// We just care that we can move it in front of the loop:
if (declarationPoint != loop)
return null;
ForeachStatement foreachStatement = new ForeachStatement();
foreachStatement.VariableType = itemVarDecl.Type.Clone();
foreachStatement.VariableName = itemVar.Identifier;
ForeachStatement foreachStatement = new ForeachStatement
{
VariableType = itemVarDecl.Type.Clone(),
VariableName = itemVar.Identifier,
}.WithAnnotation(itemVarDecl.Variables.Single().Annotation<ILVariable>());
BlockStatement body = new BlockStatement();
foreachStatement.EmbeddedStatement = body;
((BlockStatement)node.Parent).Statements.InsertBefore(node, foreachStatement);
@ -982,33 +985,5 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -982,33 +985,5 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
return null;
}
#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 @@ -26,8 +26,18 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
{
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)
{
// lifted operators can't be transformed
if (unary.Annotation<LiftedOperator>() != null || unary.Expression.Annotation<LiftedOperator>() != null)
return base.VisitUnaryOperatorExpression(unary, data);
// Remove double negation
// !!a
if (unary.Operator == UnaryOperatorType.Not &&
@ -108,6 +118,10 @@ namespace ICSharpCode.Decompiler.Ast.Transforms @@ -108,6 +118,10 @@ namespace ICSharpCode.Decompiler.Ast.Transforms
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;
bool? rightOperand = null;
if (binaryOperatorExpression.Right is PrimitiveExpression)

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

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

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

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

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

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

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

@ -20,73 +20,39 @@ using System; @@ -20,73 +20,39 @@ using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using ICSharpCode.Decompiler.Ast;
using ICSharpCode.Decompiler.Disassembler;
using ICSharpCode.Decompiler.ILAst;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.CSharp;
using Mono.Cecil;
namespace ICSharpCode.Decompiler
{
public enum DecompiledLanguages
{
IL,
CSharp
}
/// <summary>
/// Base class for decompliler classes : AstBuilder & ReflectionDisassembler.
/// Maps the source code to IL.
/// </summary>
public abstract class BaseCodeMappings
public sealed class SourceCodeMapping
{
/// <summary>
/// Gets the code mappings.
/// <remarks>Key is the metadata token.</remarks>
/// Gets or sets the start location of the instruction.
/// </summary>
public Dictionary<int, List<MemberMapping>> CodeMappings { get; protected set; }
public TextLocation StartLocation { get; set; }
/// <summary>
/// Gets the MembeReference that is decompiled (a MethodDefinition, PropertyDefinition etc.)
/// <remarks>Key is the metadata token.</remarks>
/// Gets or sets the end location of the instruction.
/// </summary>
public Dictionary<int, MemberReference> DecompiledMemberReferences { get; protected 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; }
public TextLocation EndLocation { get; set; }
/// <summary>
/// Gets or sets IL Range offset for the source code line. E.g.: 13-19 &lt;-&gt; 135.
/// </summary>
public ILRange ILInstructionOffset { get; internal set; }
public ILRange ILInstructionOffset { get; set; }
/// <summary>
/// Gets or sets the member mapping this source code mapping belongs to.
/// </summary>
public MemberMapping MemberMapping { get; internal set; }
public MemberMapping MemberMapping { get; set; }
/// <summary>
/// Retrieves the array that contains the IL range and the missing gaps between ranges.
@ -98,7 +64,7 @@ namespace ICSharpCode.Decompiler @@ -98,7 +64,7 @@ namespace ICSharpCode.Decompiler
// add list for the current source code line
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)));
if (!isMatch) {
@ -123,12 +89,24 @@ namespace ICSharpCode.Decompiler @@ -123,12 +89,24 @@ namespace ICSharpCode.Decompiler
}
/// <summary>
/// Stores the method information and its source code mappings.
/// Stores the member information and its source code mappings.
/// </summary>
public sealed class MemberMapping
{
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>
/// Gets or sets the type of the mapping.
/// </summary>
@ -149,6 +127,11 @@ namespace ICSharpCode.Decompiler @@ -149,6 +127,11 @@ namespace ICSharpCode.Decompiler
/// </summary>
public List<SourceCodeMapping> MemberCodeMappings { get; internal set; }
/// <summary>
/// Gets or sets the local variables.
/// </summary>
public IEnumerable<ILVariable> LocalVariables { get; internal set; }
/// <summary>
/// Gets the inverted IL Ranges.<br/>
/// E.g.: for (0-9, 11-14, 14-18, 21-25) => (9-11,18-21).
@ -172,40 +155,6 @@ namespace ICSharpCode.Decompiler @@ -172,40 +155,6 @@ namespace ICSharpCode.Decompiler
/// </summary>
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>
/// Gets source code mapping and metadata token based on type name and line number.
/// </summary>
@ -215,19 +164,17 @@ namespace ICSharpCode.Decompiler @@ -215,19 +164,17 @@ namespace ICSharpCode.Decompiler
/// <param name="metadataToken">Metadata token.</param>
/// <returns></returns>
public static SourceCodeMapping GetInstructionByLineNumber(
this List<MemberMapping> codeMappings,
this MemberMapping codeMapping,
int lineNumber,
out int metadataToken)
{
if (codeMappings == null)
if (codeMapping == null)
throw new ArgumentException("CodeMappings storage must be valid!");
foreach (var maping in codeMappings) {
var map = maping.MemberCodeMappings.Find(m => m.SourceCodeLine == lineNumber);
if (map != null) {
metadataToken = maping.MetadataToken;
return map;
}
var map = codeMapping.MemberCodeMappings.Find(m => m.StartLocation.Line == lineNumber);
if (map != null) {
metadataToken = codeMapping.MetadataToken;
return map;
}
metadataToken = 0;
@ -243,30 +190,24 @@ namespace ICSharpCode.Decompiler @@ -243,30 +190,24 @@ namespace ICSharpCode.Decompiler
/// <param name="isMatch">True, if perfect match.</param>
/// <returns>A code mapping.</returns>
public static SourceCodeMapping GetInstructionByTokenAndOffset(
this List<MemberMapping> codeMappings,
int token,
int ilOffset,
this MemberMapping codeMapping,
int ilOffset,
out bool isMatch)
{
isMatch = false;
if (codeMappings == null)
if (codeMapping == null)
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
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) {
// 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;
if (map == null)
map = maping.MemberCodeMappings.LastOrDefault(); // get the last
map = codeMapping.MemberCodeMappings.LastOrDefault(); // get the last
return map;
}
@ -278,15 +219,14 @@ namespace ICSharpCode.Decompiler @@ -278,15 +219,14 @@ namespace ICSharpCode.Decompiler
/// <summary>
/// Gets the source code and type name from metadata token and offset.
/// </summary>
/// <param name="codeMappings">Code mappings storage.</param>
/// <param name="codeMappings">Code mapping storage.</param>
/// <param name="token">Metadata token.</param>
/// <param name="ilOffset">IL offset.</param>
/// <param name="typeName">Type definition.</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>
public static bool GetInstructionByTokenAndOffset(
this List<MemberMapping> codeMappings,
int token,
this MemberMapping mapping,
int ilOffset,
out MemberReference member,
out int line)
@ -294,13 +234,9 @@ namespace ICSharpCode.Decompiler @@ -294,13 +234,9 @@ namespace ICSharpCode.Decompiler
member = null;
line = 0;
if (codeMappings == null)
throw new ArgumentException("CodeMappings storage must be valid!");
var mapping = codeMappings.Find(m => m.MetadataToken == token);
if (mapping == null)
return false;
throw new ArgumentException("CodeMappings storage must be valid!");
var codeMapping = mapping.MemberCodeMappings.Find(
cm => cm.ILInstructionOffset.From <= ilOffset && ilOffset <= cm.ILInstructionOffset.To - 1);
if (codeMapping == null) {
@ -313,34 +249,8 @@ namespace ICSharpCode.Decompiler @@ -313,34 +249,8 @@ namespace ICSharpCode.Decompiler
}
member = mapping.MemberReference;
line = codeMapping.SourceCodeLine;
line = codeMapping.StartLocation.Line;
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 @@ -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;
/// <summary>
@ -224,6 +239,38 @@ namespace ICSharpCode.Decompiler @@ -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;
protected virtual void OnPropertyChanged(string propertyName)

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

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

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

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

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

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

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

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

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

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

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

@ -62,7 +62,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -62,7 +62,7 @@ namespace ICSharpCode.Decompiler.ILAst
/// <summary> Immutable </summary>
class VariableSlot
{
{
public readonly ByteCode[] StoredBy; // One of those
public readonly bool StoredByAll; // Overestimate which is useful for exceptional control flow.
@ -224,10 +224,13 @@ namespace ICSharpCode.Decompiler.ILAst @@ -224,10 +224,13 @@ namespace ICSharpCode.Decompiler.ILAst
// Virtual instructions to load exception on stack
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.optimize = optimize;
this.context = context;
if (methodDef.Body.Instructions.Count == 0) return new List<ILNode>();
@ -260,7 +263,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -260,7 +263,7 @@ namespace ICSharpCode.Decompiler.ILAst
EndOffset = inst.Next != null ? inst.Next.Offset : methodDef.Body.CodeSize,
Code = code,
Operand = operand,
PopCount = inst.GetPopDelta(),
PopCount = inst.GetPopDelta(methodDef),
PushCount = inst.GetPushDelta()
};
if (prefixes != null) {
@ -336,9 +339,10 @@ namespace ICSharpCode.Decompiler.ILAst @@ -336,9 +339,10 @@ namespace ICSharpCode.Decompiler.ILAst
// Calculate new variable state
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;
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
@ -351,7 +355,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -351,7 +355,7 @@ namespace ICSharpCode.Decompiler.ILAst
if (!byteCode.Code.IsUnconditionalControlFlow()) {
if (exceptionHandlerStarts.Contains(byteCode.Next)) {
// Do not fall though down to exception handler
// It is invalid IL as per ECMA-335 §12.4.2.8.1, but some obfuscators produce it
// It is invalid IL as per ECMA-335 §12.4.2.8.1, but some obfuscators produce it
} else {
branchTargets.Add(byteCode.Next);
}
@ -520,8 +524,12 @@ namespace ICSharpCode.Decompiler.ILAst @@ -520,8 +524,12 @@ namespace ICSharpCode.Decompiler.ILAst
for(int variableIndex = 0; variableIndex < varCount; variableIndex++) {
// 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();
List<ByteCode> loads = body.Where(b => (b.Code == ILCode.Ldloc || b.Code == ILCode.Ldloca) && 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();
// 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;
List<VariableInfo> newVars;
@ -529,8 +537,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -529,8 +537,7 @@ namespace ICSharpCode.Decompiler.ILAst
bool isPinned = methodDef.Body.Variables[variableIndex].IsPinned;
// 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 ldloca, fallback to single variable as well
if (isPinned || loads.Any(b => b.VariablesBefore[variableIndex].StoredByAll || b.Code == ILCode.Ldloca)) {
if (isPinned || loads.Any(b => b.VariablesBefore[variableIndex].StoredByAll)) {
newVars = new List<VariableInfo>(1) { new VariableInfo() {
Variable = new ILVariable() {
Name = "var_" + variableIndex,
@ -542,7 +549,12 @@ namespace ICSharpCode.Decompiler.ILAst @@ -542,7 +549,12 @@ namespace ICSharpCode.Decompiler.ILAst
}};
} else {
// 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() {
Name = "var_" + variableIndex + "_" + st.Offset.ToString("X2"),
Type = varType,
@ -579,14 +591,16 @@ namespace ICSharpCode.Decompiler.ILAst @@ -579,14 +591,16 @@ namespace ICSharpCode.Decompiler.ILAst
} else if (storedBy.Length == 1) {
VariableInfo newVar = newVars.Single(v => v.Stores.Contains(storedBy[0]));
newVar.Loads.Add(load);
if (load.Code == ILCode.Ldloca) newVar.Stores.Add(load);
} 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() {
Variable = mergeVars[0].Variable,
Stores = mergeVars.SelectMany(v => v.Stores).ToList(),
Loads = mergeVars.SelectMany(v => v.Loads).ToList()
};
mergedVar.Loads.Add(load);
if (load.Code == ILCode.Ldloca) mergedVar.Stores.Add(load);
newVars = newVars.Except(mergeVars).ToList();
newVars.Add(mergedVar);
}
@ -629,6 +643,10 @@ namespace ICSharpCode.Decompiler.ILAst @@ -629,6 +643,10 @@ namespace ICSharpCode.Decompiler.ILAst
foreach (ParameterDefinition p in methodDef.Parameters) {
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) {
ParameterDefinition p;
switch (byteCode.Code) {
@ -701,8 +719,9 @@ namespace ICSharpCode.Decompiler.ILAst @@ -701,8 +719,9 @@ namespace ICSharpCode.Decompiler.ILAst
};
// Handle the automatically pushed exception on the stack
ByteCode ldexception = ldexceptions[eh];
if (ldexception.StoreTo.Count == 0) {
throw new Exception("Exception should be consumed by something");
if (ldexception.StoreTo == null || ldexception.StoreTo.Count == 0) {
// Exception is not used
catchBlock.ExceptionVariable = null;
} else if (ldexception.StoreTo.Count == 1) {
ILExpression first = catchBlock.Body[0] as ILExpression;
if (first != null &&
@ -711,7 +730,10 @@ namespace ICSharpCode.Decompiler.ILAst @@ -711,7 +730,10 @@ namespace ICSharpCode.Decompiler.ILAst
first.Arguments[0].Operand == ldexception.StoreTo[0])
{
// 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);
} else {
catchBlock.ExceptionVariable = ldexception.StoreTo[0];
@ -778,7 +800,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -778,7 +800,7 @@ namespace ICSharpCode.Decompiler.ILAst
StackSlot slot = byteCode.StackBefore[i];
expr.Arguments.Add(new ILExpression(ILCode.Ldloc, slot.LoadFrom));
}
// Store the result to temporary variable(s) if needed
if (byteCode.StoreTo == null || byteCode.StoreTo.Count == 0) {
ast.Add(expr);
@ -808,15 +830,34 @@ namespace ICSharpCode.Decompiler.ILAst @@ -808,15 +830,34 @@ namespace ICSharpCode.Decompiler.ILAst
list.RemoveRange(start, count);
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)
{
if (a == b)
return a;
if (a.Length == 0)
return b;
if (b.Length == 0)
return a;
if (a.Length == 1 && b.Length == 1 && a[0].Equals(b[0]))
return a;
if (a.Length == 1) {
if (b.Length == 1)
return a[0].Equals(b[0]) ? a : new[] { a[0], b[0] };
return b.Union(a[0]);
}
if (b.Length == 1)
return a.Union(b[0]);
return Enumerable.Union(a, b).ToArray();
}
}

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

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

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

@ -247,12 +247,22 @@ namespace ICSharpCode.Decompiler.ILAst @@ -247,12 +247,22 @@ namespace ICSharpCode.Decompiler.ILAst
Readonly,
// Virtual codes - defined for convenience
Cne,
Cge,
Cge_Un,
Cle,
Cle_Un,
Ldexception, // Operand holds the CatchType for catch handler, null for filter
LogicNot,
LogicAnd,
LogicOr,
NullCoalescing,
InitArray, // Array Initializer
/// <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} }}
// is represented as:
@ -306,7 +316,24 @@ namespace ICSharpCode.Decompiler.ILAst @@ -306,7 +316,24 @@ namespace ICSharpCode.Decompiler.ILAst
/// 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(...))"
/// </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

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

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

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

@ -0,0 +1,528 @@ @@ -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 @@ -397,9 +397,21 @@ namespace ICSharpCode.Decompiler.ILAst
return false;
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;
ILExpression ldelem = op.Arguments[0];
if (liftedOperator) {
if (ldelem.Code != ILCode.ValueOf)
return false;
ldelem = ldelem.Arguments[0];
}
if (ldelem.Code != expectedLdelemCode)
return false;
Debug.Assert(ldelem.Arguments.Count == expr.Arguments.Count - 1);
@ -414,9 +426,9 @@ namespace ICSharpCode.Decompiler.ILAst @@ -414,9 +426,9 @@ namespace ICSharpCode.Decompiler.ILAst
return true;
}
static bool CanBeRepresentedAsCompoundAssignment(ILCode code)
static bool CanBeRepresentedAsCompoundAssignment(ILExpression expr)
{
switch (code) {
switch (expr.Code) {
case ILCode.Add:
case ILCode.Add_Ovf:
case ILCode.Add_Ovf_Un:
@ -437,6 +449,24 @@ namespace ICSharpCode.Decompiler.ILAst @@ -437,6 +449,24 @@ namespace ICSharpCode.Decompiler.ILAst
case ILCode.Shr:
case ILCode.Shr_Un:
return true;
case ILCode.Call:
var m = expr.Operand as MethodReference;
if (m == null || m.HasThis || expr.Arguments.Count != 2) return false;
switch (m.Name) {
case "op_Addition":
case "op_Subtraction":
case "op_Multiply":
case "op_Division":
case "op_Modulus":
case "op_BitwiseAnd":
case "op_BitwiseOr":
case "op_ExclusiveOr":
case "op_LeftShift":
case "op_RightShift":
return true;
default:
return false;
}
default:
return false;
}
@ -869,6 +899,78 @@ namespace ICSharpCode.Decompiler.ILAst @@ -869,6 +899,78 @@ namespace ICSharpCode.Decompiler.ILAst
}
#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
static bool SimplifyShiftOperators(List<ILNode> body, ILExpression expr, int pos)
{
@ -880,20 +982,20 @@ namespace ICSharpCode.Decompiler.ILAst @@ -880,20 +982,20 @@ namespace ICSharpCode.Decompiler.ILAst
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);
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;
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;
int mask;
switch (expr.InferredType.MetadataType) {
case MetadataType.Int32:
case MetadataType.UInt32: mask = 31; break;
case MetadataType.UInt32: mask = 31; break;
case MetadataType.Int64:
case MetadataType.UInt64: mask = 63; break;
default: return;
case MetadataType.UInt64: mask = 63; break;
default: return;
}
if ((int)a.Arguments[1].Operand != mask) return;
var res = a.Arguments[0];
@ -903,5 +1005,81 @@ namespace ICSharpCode.Decompiler.ILAst @@ -903,5 +1005,81 @@ namespace ICSharpCode.Decompiler.ILAst
modified = true;
}
#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 @@ -98,16 +98,16 @@ namespace ICSharpCode.Decompiler.ILAst
if (leftBoolVal != 0) {
newExpr = condExpr;
} 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
if (leftBoolVal != 0) {
newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicOr, condExpr, falseExpr);
} else {
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
if (rightBoolVal != 0) {
newExpr = MakeLeftAssociativeShortCircuit(ILCode.LogicOr, new ILExpression(ILCode.LogicNot, null, condExpr), trueExpr);
@ -343,10 +343,10 @@ namespace ICSharpCode.Decompiler.ILAst @@ -343,10 +343,10 @@ namespace ICSharpCode.Decompiler.ILAst
ILExpression current = right;
while(current.Arguments[0].Match(code))
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;
} 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 @@ -280,15 +280,9 @@ namespace ICSharpCode.Decompiler.ILAst
if (forceInferChildren) {
InferTypeForExpression(expr.Arguments[0], typeSystem.Boolean);
}
return TypeWithMoreInformation(
InferTypeForExpression(expr.Arguments[1], expectedType, forceInferChildren),
InferTypeForExpression(expr.Arguments[2], expectedType, forceInferChildren)
);
return InferBinaryArguments(expr.Arguments[1], expr.Arguments[2], expectedType, forceInferChildren);
case ILCode.NullCoalescing:
return TypeWithMoreInformation(
InferTypeForExpression(expr.Arguments[0], expectedType, forceInferChildren),
InferTypeForExpression(expr.Arguments[1], expectedType, forceInferChildren)
);
return InferBinaryArguments(expr.Arguments[0], expr.Arguments[1], expectedType, forceInferChildren);
#endregion
#region Variable load/store
case ILCode.Stloc:
@ -472,7 +466,7 @@ namespace ICSharpCode.Decompiler.ILAst @@ -472,7 +466,7 @@ namespace ICSharpCode.Decompiler.ILAst
if (forceInferChildren) {
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:
if (forceInferChildren) {
InferTypeForExpression(expr.Arguments[0], typeSystem.TypedReference);
@ -483,6 +477,10 @@ namespace ICSharpCode.Decompiler.ILAst @@ -483,6 +477,10 @@ namespace ICSharpCode.Decompiler.ILAst
TypeReference t = InferTypeForExpression(expr.Arguments[0], UnpackPointer(expectedType));
return t != null ? new ByReferenceType(t) : null;
}
case ILCode.ValueOf:
return GetNullableTypeArgument(InferTypeForExpression(expr.Arguments[0], CreateNullableType(expectedType)));
case ILCode.NullableOf:
return CreateNullableType(InferTypeForExpression(expr.Arguments[0], GetNullableTypeArgument(expectedType)));
#endregion
#region Arithmetic instructions
case ILCode.Not: // bitwise complement
@ -557,7 +555,9 @@ namespace ICSharpCode.Decompiler.ILAst @@ -557,7 +555,9 @@ namespace ICSharpCode.Decompiler.ILAst
}
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) {
InferTypeForExpression(expr.Arguments[0], varType);
}
@ -593,16 +593,16 @@ namespace ICSharpCode.Decompiler.ILAst @@ -593,16 +593,16 @@ namespace ICSharpCode.Decompiler.ILAst
case ILCode.Ldc_R8:
return typeSystem.Double;
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:
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)
return new TypeReference("System", "RuntimeFieldHandle", module, module, true);
return new TypeReference("System", "RuntimeFieldHandle", module, module.TypeSystem.Corlib, true);
else
return new TypeReference("System", "RuntimeMethodHandle", module, module, true);
return new TypeReference("System", "RuntimeMethodHandle", module, module.TypeSystem.Corlib, true);
case ILCode.Arglist:
return new TypeReference("System", "RuntimeArgumentHandle", module, module, true);
return new TypeReference("System", "RuntimeArgumentHandle", module, module.TypeSystem.Corlib, true);
#endregion
#region Array instructions
case ILCode.Newarr:
@ -735,22 +735,30 @@ namespace ICSharpCode.Decompiler.ILAst @@ -735,22 +735,30 @@ namespace ICSharpCode.Decompiler.ILAst
return tr.IsValueType ? typeSystem.Object : tr;
}
case ILCode.Box:
if (forceInferChildren)
InferTypeForExpression(expr.Arguments.Single(), (TypeReference)expr.Operand);
return (TypeReference)expr.Operand;
{
var tr = (TypeReference)expr.Operand;
if (forceInferChildren)
InferTypeForExpression(expr.Arguments.Single(), tr);
return tr.IsValueType ? typeSystem.Object : tr;
}
#endregion
#region Comparison instructions
case ILCode.Ceq:
case ILCode.Cne:
if (forceInferChildren)
InferArgumentsInBinaryOperator(expr, null, null);
return typeSystem.Boolean;
case ILCode.Clt:
case ILCode.Cgt:
case ILCode.Cle:
case ILCode.Cge:
if (forceInferChildren)
InferArgumentsInBinaryOperator(expr, true, null);
return typeSystem.Boolean;
case ILCode.Clt_Un:
case ILCode.Cgt_Un:
case ILCode.Cle_Un:
case ILCode.Cge_Un:
if (forceInferChildren)
InferArgumentsInBinaryOperator(expr, false, null);
return typeSystem.Boolean;
@ -787,8 +795,12 @@ namespace ICSharpCode.Decompiler.ILAst @@ -787,8 +795,12 @@ namespace ICSharpCode.Decompiler.ILAst
#endregion
case ILCode.Pop:
return null;
case ILCode.Wrap:
case ILCode.Dup:
return InferTypeForExpression(expr.Arguments.Single(), expectedType);
{
var arg = expr.Arguments.Single();
return arg.ExpectedType = InferTypeForExpression(expr.Arguments.Single(), expectedType);
}
default:
Debug.WriteLine("Type Inference: Can't handle " + expr.Code.GetName());
return null;
@ -904,14 +916,12 @@ namespace ICSharpCode.Decompiler.ILAst @@ -904,14 +916,12 @@ namespace ICSharpCode.Decompiler.ILAst
}
GenericParameter gp = type as GenericParameter;
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];
} else {
if (member.DeclaringType is ArrayType) {
return ((ArrayType)member.DeclaringType).ElementType;
} else {
return ((GenericInstanceType)member.DeclaringType).GenericArguments[gp.Position];
}
} else {
return ((GenericInstanceType)member.DeclaringType).GenericArguments[gp.Position];
}
}
return type;
@ -934,25 +944,24 @@ namespace ICSharpCode.Decompiler.ILAst @@ -934,25 +944,24 @@ namespace ICSharpCode.Decompiler.ILAst
type = ((TypeSpecification)type).ElementType;
return type;
}
static TypeReference GetNullableTypeArgument(TypeReference type)
{
var t = type as GenericInstanceType;
return IsNullableType(t) ? t.GenericArguments[0] : type;
}
GenericInstanceType CreateNullableType(TypeReference type)
{
if (type == null) return null;
var t = new GenericInstanceType(new TypeReference("System", "Nullable`1", module, module.TypeSystem.Corlib, true));
t.GenericArguments.Add(type);
return t;
}
TypeReference InferArgumentsInBinaryOperator(ILExpression expr, bool? isSigned, TypeReference expectedType)
{
ILExpression left = expr.Arguments[0];
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;
}
return InferBinaryArguments(expr.Arguments[0], expr.Arguments[1], expectedType);
}
TypeReference InferArgumentsInAddition(ILExpression expr, bool? isSigned, TypeReference expectedType)
@ -964,25 +973,14 @@ namespace ICSharpCode.Decompiler.ILAst @@ -964,25 +973,14 @@ namespace ICSharpCode.Decompiler.ILAst
left.InferredType = left.ExpectedType = leftPreferred;
InferTypeForExpression(right, typeSystem.IntPtr);
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)
@ -994,20 +992,27 @@ namespace ICSharpCode.Decompiler.ILAst @@ -994,20 +992,27 @@ namespace ICSharpCode.Decompiler.ILAst
left.InferredType = left.ExpectedType = leftPreferred;
InferTypeForExpression(right, typeSystem.IntPtr);
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 {
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;
}
left.ExpectedType = right.ExpectedType = TypeWithMoreInformation(leftPreferred, rightPreferred);
left.InferredType = DoInferTypeForExpression(left, left.ExpectedType, forceInferChildren);
right.InferredType = DoInferTypeForExpression(right, right.ExpectedType, forceInferChildren);
return left.ExpectedType;
}
}
@ -1152,6 +1157,11 @@ namespace ICSharpCode.Decompiler.ILAst @@ -1152,6 +1157,11 @@ namespace ICSharpCode.Decompiler.ILAst
}
return false;
}
internal static bool IsNullableType(TypeReference type)
{
return type != null && type.Name == "Nullable`1" && type.Namespace == "System";
}
public static TypeCode GetTypeCode(TypeReference type)
{

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

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

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

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

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

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

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

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

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

@ -1,27 +0,0 @@ @@ -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 @@ @@ -16,6 +16,8 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
public class CheckedUnchecked
{
public int Operators(int a, int b)
@ -63,4 +65,53 @@ public class CheckedUnchecked @@ -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 @@ @@ -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 @@ -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)
{
// Tests references to inner classes in generic classes

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

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

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

@ -532,9 +532,9 @@ public class InitializerTests @@ -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 @@ -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 @@ -687,7 +687,7 @@ public class InitializerTests
}
},
new int[, ]
new int[,]
{
{
@ -719,7 +719,7 @@ public class InitializerTests @@ -719,7 +719,7 @@ public class InitializerTests
}
},
new int[, ]
new int[,]
{
{
@ -750,7 +750,7 @@ public class InitializerTests @@ -750,7 +750,7 @@ public class InitializerTests
0
}
},
new int[, ]
new int[,]
{
{
@ -785,11 +785,11 @@ public class InitializerTests @@ -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 @@ -827,7 +827,7 @@ public class InitializerTests
}
},
new int[, , ]
new int[,,]
{
{
{

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

@ -0,0 +1,830 @@ @@ -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 @@ -84,4 +84,13 @@ public class PInvoke
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 @@ -35,7 +35,7 @@ public class QueryExpressions
{
public int OrderID;
public DateTime OrderDate;
public Customer Customer;
public QueryExpressions.Customer Customer;
public int CustomerID;
public decimal Total;
public IEnumerable<QueryExpressions.OrderDetail> Details;
@ -54,7 +54,7 @@ public class QueryExpressions @@ -54,7 +54,7 @@ public class QueryExpressions
{
return
from c in this.customers
where c.Orders.Count() > 10
where c.Orders.Count<QueryExpressions.Order>() > 10
where c.Country == "DE"
select c;
}
@ -64,7 +64,12 @@ public class QueryExpressions @@ -64,7 +64,12 @@ public class QueryExpressions
return
from c in this.customers
from o in c.Orders
select new { c.Name, o.OrderID, o.Total };
select new
{
c.Name,
o.OrderID,
o.Total
};
}
public object SelectManyFollowedByOrderBy()
@ -73,7 +78,12 @@ public class QueryExpressions @@ -73,7 +78,12 @@ public class QueryExpressions
from c in this.customers
from o in c.Orders
orderby o.Total descending
select new { c.Name, o.OrderID, o.Total };
select new
{
c.Name,
o.OrderID,
o.Total
};
}
public object MultipleSelectManyFollowedBySelect()
@ -82,7 +92,12 @@ public class QueryExpressions @@ -82,7 +92,12 @@ public class QueryExpressions
from c in this.customers
from o in c.Orders
from d in o.Details
select new { c.Name, o.OrderID, d.Quantity };
select new
{
c.Name,
o.OrderID,
d.Quantity
};
}
public object MultipleSelectManyFollowedByLet()
@ -92,16 +107,25 @@ public class QueryExpressions @@ -92,16 +107,25 @@ public class QueryExpressions
from o in c.Orders
from d in o.Details
let x = d.Quantity * d.UnitPrice
select new { c.Name, o.OrderID, x };
select new
{
c.Name,
o.OrderID,
x
};
}
public object FromLetWhereSelect()
{
return
from o in this.orders
let t = o.Details.Sum(d => d.UnitPrice * d.Quantity)
where t >= 1000
select new { o.OrderID, Total = t };
let t = o.Details.Sum((QueryExpressions.OrderDetail d) => d.UnitPrice * d.Quantity)
where t >= 1000m
select new
{
OrderID = o.OrderID,
Total = t
};
}
public object MultipleLet()
@ -116,25 +140,34 @@ public class QueryExpressions @@ -116,25 +140,34 @@ public class QueryExpressions
public object Join()
{
return
from c in customers
join o in orders on c.CustomerID equals o.CustomerID
select new { c.Name, o.OrderDate, o.Total };
from c in this.customers
join o in this.orders on c.CustomerID equals o.CustomerID
select new
{
c.Name,
o.OrderDate,
o.Total
};
}
public object JoinInto()
{
return
from c in customers
join o in orders on c.CustomerID equals o.CustomerID into co
let n = co.Count()
from c in this.customers
join o in this.orders on c.CustomerID equals o.CustomerID into co
let n = co.Count<QueryExpressions.Order>()
where n >= 10
select new { c.Name, OrderCount = n };
select new
{
Name = c.Name,
OrderCount = n
};
}
public object OrderBy()
{
return
from o in orders
from o in this.orders
orderby o.Customer.Name, o.Total descending
select o;
}
@ -142,14 +175,14 @@ public class QueryExpressions @@ -142,14 +175,14 @@ public class QueryExpressions
public object GroupBy()
{
return
from c in customers
from c in this.customers
group c.Name by c.Country;
}
public object ExplicitType()
{
return
from Customer c in customers
from QueryExpressions.Customer c in this.customers
where c.City == "London"
select c;
}
@ -157,8 +190,12 @@ public class QueryExpressions @@ -157,8 +190,12 @@ public class QueryExpressions
public object QueryContinuation()
{
return
from c in customers
from c in this.customers
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 @@ -52,10 +52,16 @@ namespace ICSharpCode.Decompiler.Tests
TestFile(@"..\..\Tests\DelegateConstruction.cs");
}
[Test, Ignore("Not yet implemented")]
public void ExpressionTrees()
{
TestFile(@"..\..\Tests\ExpressionTrees.cs");
}
[Test]
public void ExceptionHandling()
{
TestFile(@"..\..\Tests\ExceptionHandling.cs");
TestFile(@"..\..\Tests\ExceptionHandling.cs", false);
}
[Test]
@ -81,6 +87,12 @@ namespace ICSharpCode.Decompiler.Tests @@ -81,6 +87,12 @@ namespace ICSharpCode.Decompiler.Tests
{
TestFile(@"..\..\Tests\InitializerTests.cs");
}
[Test]
public void LiftedOperators()
{
TestFile(@"..\..\Tests\LiftedOperators.cs");
}
[Test]
public void Loops()
@ -106,7 +118,7 @@ namespace ICSharpCode.Decompiler.Tests @@ -106,7 +118,7 @@ namespace ICSharpCode.Decompiler.Tests
TestFile(@"..\..\Tests\PropertiesAndEvents.cs");
}
[Test, Ignore("Formatting differences in anonymous method create expressions")]
[Test]
public void QueryExpressions()
{
TestFile(@"..\..\Tests\QueryExpressions.cs");
@ -149,9 +161,15 @@ namespace ICSharpCode.Decompiler.Tests @@ -149,9 +161,15 @@ namespace ICSharpCode.Decompiler.Tests
}
static void TestFile(string fileName)
{
TestFile(fileName, false);
TestFile(fileName, true);
}
static void TestFile(string fileName, bool optimize)
{
string code = File.ReadAllText(fileName);
AssemblyDefinition assembly = Compile(code);
AssemblyDefinition assembly = Compile(code, optimize);
AstBuilder decompiler = new AstBuilder(new DecompilerContext(assembly.MainModule));
decompiler.AddAssembly(assembly);
new Helpers.RemoveCompilerAttribute().Run(decompiler.CompilationUnit);
@ -160,11 +178,11 @@ namespace ICSharpCode.Decompiler.Tests @@ -160,11 +178,11 @@ namespace ICSharpCode.Decompiler.Tests
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" } });
CompilerParameters options = new CompilerParameters();
options.CompilerOptions = "/unsafe /o-";
options.CompilerOptions = "/unsafe /o" + (optimize ? "+" : "-");
options.ReferencedAssemblies.Add("System.Core.dll");
CompilerResults results = provider.CompileAssemblyFromSource(options, code);
try {

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

@ -106,4 +106,18 @@ public class TypeAnalysisTests @@ -106,4 +106,18 @@ public class TypeAnalysisTests
{
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 @@ @@ -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 @@ @@ -1,5 +1,20 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
// 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;
@ -8,6 +23,7 @@ using System.Linq; @@ -8,6 +23,7 @@ using System.Linq;
using System.Threading;
using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem;
namespace ICSharpCode.NRefactory.CSharp.Analysis
@ -96,7 +112,7 @@ 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.
/// </summary>
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 @@ -152,7 +168,7 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
{
return BuildControlFlowGraph(statement, new ResolveVisitor(
new CSharpResolver(context, cancellationToken),
null, ConstantModeResolveVisitorNavigator.Skip));
null));
}
public IList<ControlFlowNode> BuildControlFlowGraph(Statement statement, ResolveVisitor resolveVisitor)
@ -657,7 +673,7 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis @@ -657,7 +673,7 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
return CreateConnectedEndNode(usingStatement, bodyEnd);
}
public override ControlFlowNode VisitYieldStatement(YieldStatement yieldStatement, ControlFlowNode data)
public override ControlFlowNode VisitYieldReturnStatement(YieldReturnStatement yieldStatement, ControlFlowNode 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 @@ @@ -1,13 +1,31 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
// 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.Diagnostics;
using System.Linq;
using System.Threading;
using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
using ICSharpCode.NRefactory.Utils;
namespace ICSharpCode.NRefactory.CSharp.Analysis
@ -96,7 +114,7 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis @@ -96,7 +114,7 @@ namespace ICSharpCode.NRefactory.CSharp.Analysis
public DefiniteAssignmentAnalysis(Statement rootStatement, ITypeResolveContext context, CancellationToken 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; @@ -27,6 +27,7 @@ using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
@ -51,7 +52,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -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);
}
@ -82,7 +83,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -82,7 +83,7 @@ namespace ICSharpCode.NRefactory.CSharp
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);
}
@ -116,20 +117,20 @@ namespace ICSharpCode.NRefactory.CSharp @@ -116,20 +117,20 @@ namespace ICSharpCode.NRefactory.CSharp
}
}
public virtual AstLocation StartLocation {
public virtual TextLocation StartLocation {
get {
var child = firstChild;
if (child == null)
return AstLocation.Empty;
return TextLocation.Empty;
return child.StartLocation;
}
}
public virtual AstLocation EndLocation {
public virtual TextLocation EndLocation {
get {
var child = lastChild;
if (child == null)
return AstLocation.Empty;
return TextLocation.Empty;
return child.EndLocation;
}
}
@ -440,7 +441,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -440,7 +441,7 @@ namespace ICSharpCode.NRefactory.CSharp
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
protected static bool MatchString (string name1, string name2)
@ -503,12 +504,12 @@ namespace ICSharpCode.NRefactory.CSharp @@ -503,12 +504,12 @@ namespace ICSharpCode.NRefactory.CSharp
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 node = this;
@ -532,14 +533,14 @@ namespace ICSharpCode.NRefactory.CSharp @@ -532,14 +533,14 @@ namespace ICSharpCode.NRefactory.CSharp
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>
/// 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.
/// </summary>
public T GetNodeAt<T> (AstLocation location) where T : AstNode
public T GetNodeAt<T> (TextLocation location) where T : AstNode
{
T result = null;
AstNode node = this;
@ -561,68 +562,12 @@ namespace ICSharpCode.NRefactory.CSharp @@ -561,68 +562,12 @@ namespace ICSharpCode.NRefactory.CSharp
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)
{
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;
while (node != null) {
@ -648,10 +593,10 @@ namespace ICSharpCode.NRefactory.CSharp @@ -648,10 +593,10 @@ namespace ICSharpCode.NRefactory.CSharp
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;
}
@ -663,6 +608,19 @@ namespace ICSharpCode.NRefactory.CSharp @@ -663,6 +608,19 @@ namespace ICSharpCode.NRefactory.CSharp
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
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 @@ @@ -1,5 +1,20 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
// 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;
@ -132,28 +147,17 @@ namespace ICSharpCode.NRefactory.CSharp @@ -132,28 +147,17 @@ namespace ICSharpCode.NRefactory.CSharp
}
#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()
{
return node.GetHashCode() ^ role.GetHashCode();
}
public static bool operator ==(AstNodeCollection<T> left, AstNodeCollection<T> right)
{
return left.role == right.role && left.node == right.node;
}
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);
AstNodeCollection<T> other = obj as AstNodeCollection<T>;
if (other == null)
return false;
return this.node == other.node && this.role == other.role;
}
#endregion

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

@ -1,3 +1,21 @@ @@ -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.Collections.Generic;
@ -19,7 +37,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -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);
}
@ -50,7 +68,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -50,7 +68,7 @@ namespace ICSharpCode.NRefactory.CSharp
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);
}

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

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
//
// CSharpModifierToken.cs
//
//
// Author:
// Mike Krüger <mkrueger@novell.com>
//
@ -37,14 +37,8 @@ namespace ICSharpCode.NRefactory.CSharp @@ -37,14 +37,8 @@ namespace ICSharpCode.NRefactory.CSharp
public Modifiers Modifier {
get { return modifier; }
set {
for (int i = 0; i < lengthTable.Count; i++) {
if (lengthTable[i].Key == value) {
this.modifier = value;
this.tokenLength = lengthTable[i].Value;
return;
}
}
throw new ArgumentException ("Modifier " + value + " is invalid.");
this.tokenLength = GetModifierName(value).Length;
this.modifier = value;
}
}
@ -56,33 +50,21 @@ namespace ICSharpCode.NRefactory.CSharp @@ -56,33 +50,21 @@ namespace ICSharpCode.NRefactory.CSharp
// Not worth using a dictionary for such few elements.
// 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>> () {
new KeyValuePair<Modifiers, int>(Modifiers.Public, "public".Length),
new KeyValuePair<Modifiers, int>(Modifiers.Protected, "protected".Length),
new KeyValuePair<Modifiers, int>(Modifiers.Private, "private".Length),
new KeyValuePair<Modifiers, int>(Modifiers.Internal, "internal".Length),
new KeyValuePair<Modifiers, int>(Modifiers.New, "new".Length),
new KeyValuePair<Modifiers, int>(Modifiers.Unsafe, "unsafe".Length),
new KeyValuePair<Modifiers, int>(Modifiers.Abstract, "abstract".Length),
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)
static readonly Modifiers[] allModifiers = {
Modifiers.Public, Modifiers.Protected, Modifiers.Private, Modifiers.Internal,
Modifiers.New,
Modifiers.Unsafe,
Modifiers.Abstract, Modifiers.Virtual, Modifiers.Sealed, Modifiers.Static, Modifiers.Override,
Modifiers.Readonly, Modifiers.Volatile,
Modifiers.Extern, Modifiers.Partial, Modifiers.Const,
Modifiers.Any
};
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;
}
@ -122,8 +104,9 @@ namespace ICSharpCode.NRefactory.CSharp @@ -122,8 +104,9 @@ namespace ICSharpCode.NRefactory.CSharp
return "volatile";
case Modifiers.Unsafe:
return "unsafe";
case Modifiers.Fixed:
return "fixed";
case Modifiers.Any:
// even though it's used for patterns only, it needs to be in this list to be usable in the AST
return "any";
default:
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 @@ @@ -1,4 +1,4 @@
//
//
// TokenNode.cs
//
// Author:
@ -38,11 +38,11 @@ namespace ICSharpCode.NRefactory.CSharp @@ -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);
}
@ -60,34 +60,34 @@ namespace ICSharpCode.NRefactory.CSharp @@ -60,34 +60,34 @@ namespace ICSharpCode.NRefactory.CSharp
}
}
AstLocation startLocation;
public override AstLocation StartLocation {
TextLocation startLocation;
public override TextLocation StartLocation {
get {
return startLocation;
}
}
protected int tokenLength;
public override AstLocation EndLocation {
public override TextLocation EndLocation {
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.tokenLength = tokenLength;
}
#region IRelocationable implementation
void IRelocatable.SetStartLocation (AstLocation startLocation)
void IRelocatable.SetStartLocation (TextLocation startLocation)
{
this.startLocation = startLocation;
}
#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);
}

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

@ -0,0 +1,95 @@ @@ -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 @@ -83,7 +83,7 @@ namespace ICSharpCode.NRefactory.CSharp
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);
}

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 @@ -46,7 +46,7 @@ namespace ICSharpCode.NRefactory.CSharp
return !GetChildByRole(NullableRole).IsNull;
}
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 @@ -63,7 +63,7 @@ namespace ICSharpCode.NRefactory.CSharp
d--;
}
while (d < value) {
InsertChildBefore(GetChildByRole(PointerRole), new CSharpTokenNode(AstLocation.Empty, 1), PointerRole);
InsertChildBefore(GetChildByRole(PointerRole), new CSharpTokenNode(TextLocation.Empty, 1), PointerRole);
d++;
}
}
@ -73,7 +73,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -73,7 +73,7 @@ namespace ICSharpCode.NRefactory.CSharp
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);
}
@ -149,7 +149,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -149,7 +149,7 @@ namespace ICSharpCode.NRefactory.CSharp
d--;
}
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++;
}
}
@ -159,7 +159,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -159,7 +159,7 @@ namespace ICSharpCode.NRefactory.CSharp
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);
}

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 @@ -360,9 +360,9 @@ namespace ICSharpCode.NRefactory.CSharp
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)
@ -445,9 +445,9 @@ namespace ICSharpCode.NRefactory.CSharp @@ -445,9 +445,9 @@ namespace ICSharpCode.NRefactory.CSharp
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)
@ -585,6 +585,11 @@ namespace ICSharpCode.NRefactory.CSharp @@ -585,6 +585,11 @@ namespace ICSharpCode.NRefactory.CSharp
return VisitChildren (namedArgumentExpression, data);
}
public virtual S VisitNamedExpression (NamedExpression namedExpression, T data)
{
return VisitChildren (namedExpression, data);
}
public virtual S VisitEmptyExpression (EmptyExpression emptyExpression, T 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 @@ @@ -1,4 +1,4 @@
//
//
// ErrorNode.cs
//
// Author:
@ -34,7 +34,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -34,7 +34,7 @@ namespace ICSharpCode.NRefactory.CSharp
/// </summary>
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 {
get {
@ -42,13 +42,13 @@ namespace ICSharpCode.NRefactory.CSharp @@ -42,13 +42,13 @@ namespace ICSharpCode.NRefactory.CSharp
}
}
public override AstLocation StartLocation {
public override TextLocation StartLocation {
get {
return maxLoc;
}
}
public override AstLocation EndLocation {
public override TextLocation EndLocation {
get {
return maxLoc;
}
@ -58,7 +58,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -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
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; @@ -30,11 +30,15 @@ using System.Linq;
namespace ICSharpCode.NRefactory.CSharp
{
/// <summary>
/// delegate(Parameters) {Body}
/// [async] delegate(Parameters) {Body}
/// </summary>
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 {
get; set;
}
@ -78,7 +82,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -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);
}
@ -86,7 +90,8 @@ namespace ICSharpCode.NRefactory.CSharp @@ -86,7 +90,8 @@ namespace ICSharpCode.NRefactory.CSharp
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
{
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 @@ @@ -1,4 +1,4 @@
//
//
// AnonymousTypeCreateExpression.cs
//
// Author:
@ -41,7 +41,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -41,7 +41,7 @@ namespace ICSharpCode.NRefactory.CSharp
get { return GetChildByRole (Roles.LPar); }
}
public AstNodeCollection<Expression> Initializer {
public AstNodeCollection<Expression> Initializers {
get { return GetChildrenByRole (Roles.Expression); }
}
@ -53,9 +53,9 @@ namespace ICSharpCode.NRefactory.CSharp @@ -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);
}
}
@ -64,7 +64,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -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);
}
@ -72,7 +72,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -72,7 +72,7 @@ namespace ICSharpCode.NRefactory.CSharp
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
{
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 @@ @@ -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.Collections.Generic;
@ -33,7 +51,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -33,7 +51,7 @@ namespace ICSharpCode.NRefactory.CSharp
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);
}

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 @@ -33,6 +33,20 @@ namespace ICSharpCode.NRefactory.CSharp
/// </summary>
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
public new static readonly ArrayInitializerExpression Null = new NullArrayInitializerExpression ();
@ -44,7 +58,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -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);
}
@ -68,7 +82,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -68,7 +82,7 @@ namespace ICSharpCode.NRefactory.CSharp
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);
}

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 @@ -55,7 +55,7 @@ namespace ICSharpCode.NRefactory.CSharp
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);
}

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 @@ -74,7 +74,7 @@ namespace ICSharpCode.NRefactory.CSharp
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);
}

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 @@ -31,23 +31,23 @@ namespace ICSharpCode.NRefactory.CSharp
/// </summary>
public class BaseReferenceExpression : Expression
{
public AstLocation Location {
public TextLocation Location {
get;
set;
}
public override AstLocation StartLocation {
public override TextLocation StartLocation {
get {
return Location;
}
}
public override AstLocation EndLocation {
public override TextLocation EndLocation {
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);
}

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 @@ -67,7 +67,7 @@ namespace ICSharpCode.NRefactory.CSharp
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);
}
@ -128,11 +128,15 @@ namespace ICSharpCode.NRefactory.CSharp @@ -128,11 +128,15 @@ namespace ICSharpCode.NRefactory.CSharp
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
// or to the short-circuiting (conditional) operator:
// MCS and old NRefactory used bitwise='|', logical='||'
// but the C# spec uses logical='|', conditional='||'
/// <summary>left &amp; right</summary>
BitwiseAnd,
/// <summary>left | right</summary>
@ -174,11 +178,6 @@ namespace ICSharpCode.NRefactory.CSharp @@ -174,11 +178,6 @@ namespace ICSharpCode.NRefactory.CSharp
ShiftRight,
/// <summary>left ?? right</summary>
NullCoalescing,
/// <summary>
/// Any binary operator (used in pattern matching)
/// </summary>
Any
NullCoalescing
}
}

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 @@ -59,7 +59,7 @@ namespace ICSharpCode.NRefactory.CSharp
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);
}

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 @@ -57,7 +57,7 @@ namespace ICSharpCode.NRefactory.CSharp
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);
}

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 @@ -71,7 +71,7 @@ namespace ICSharpCode.NRefactory.CSharp
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);
}

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 @@ -57,7 +57,7 @@ namespace ICSharpCode.NRefactory.CSharp
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);
}

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 @@ -62,7 +62,7 @@ namespace ICSharpCode.NRefactory.CSharp
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);
}

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 @@ @@ -1,4 +1,4 @@
//
//
// EmptyExpression.cs
//
// Author:
@ -32,15 +32,15 @@ namespace ICSharpCode.NRefactory.CSharp @@ -32,15 +32,15 @@ namespace ICSharpCode.NRefactory.CSharp
/// </summary>
public class EmptyExpression : Expression, IRelocatable
{
AstLocation location;
TextLocation location;
public override AstLocation StartLocation {
public override TextLocation StartLocation {
get {
return location;
}
}
public override AstLocation EndLocation {
public override TextLocation EndLocation {
get {
return location;
}
@ -50,19 +50,19 @@ namespace ICSharpCode.NRefactory.CSharp @@ -50,19 +50,19 @@ namespace ICSharpCode.NRefactory.CSharp
{
}
public EmptyExpression (AstLocation location)
public EmptyExpression (TextLocation location)
{
this.location = location;
}
#region IRelocationable implementation
void IRelocatable.SetStartLocation (AstLocation startLocation)
void IRelocatable.SetStartLocation (TextLocation startLocation)
{
this.location = startLocation;
}
#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);
}

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 @@ @@ -1,10 +1,23 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
// 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.IO;
using System.Linq;
namespace ICSharpCode.NRefactory.CSharp
{
@ -28,7 +41,7 @@ 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);
}
@ -59,7 +72,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -59,7 +72,7 @@ namespace ICSharpCode.NRefactory.CSharp
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);
}
@ -90,11 +103,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -90,11 +103,7 @@ namespace ICSharpCode.NRefactory.CSharp
// Make debugging easier by giving Expressions a ToString() implementation
public override string ToString()
{
if (IsNull)
return "Null";
StringWriter w = new StringWriter();
AcceptVisitor(new OutputVisitor(w, new CSharpFormattingOptions()), null);
return w.ToString();
return DebugToString();
}
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 @@ -38,7 +38,7 @@ namespace ICSharpCode.NRefactory.CSharp
this.Identifier = identifier;
}
public IdentifierExpression(string identifier, AstLocation location)
public IdentifierExpression(string identifier, TextLocation location)
{
SetChildByRole(Roles.Identifier, CSharp.Identifier.Create (identifier, location));
}
@ -52,7 +52,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -52,7 +52,7 @@ namespace ICSharpCode.NRefactory.CSharp
return GetChildByRole (Roles.Identifier).Name;
}
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 @@ -60,7 +60,7 @@ namespace ICSharpCode.NRefactory.CSharp
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);
}

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 @@ -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);
}

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 @@ -50,7 +50,7 @@ namespace ICSharpCode.NRefactory.CSharp
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);
}

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 @@ -45,7 +45,7 @@ namespace ICSharpCode.NRefactory.CSharp
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);
}

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 @@ @@ -1,6 +1,6 @@
//
// LambdaExpression.cs
//
//
// Author:
// Mike Krüger <mkrueger@novell.com>
//
@ -29,14 +29,17 @@ using System.Linq; @@ -29,14 +29,17 @@ using System.Linq;
namespace ICSharpCode.NRefactory.CSharp
{
/// <summary>
/// Parameters => Body
/// [async] Parameters => Body
/// </summary>
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 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); }
}
@ -49,7 +52,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -49,7 +52,7 @@ namespace ICSharpCode.NRefactory.CSharp
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);
}
@ -57,7 +60,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -57,7 +60,7 @@ namespace ICSharpCode.NRefactory.CSharp
protected internal override bool DoMatch(AstNode other, PatternMatching.Match match)
{
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 @@ @@ -1,4 +1,4 @@
//
//
// MemberReferenceExpression.cs
//
// Author:
@ -43,7 +43,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -43,7 +43,7 @@ namespace ICSharpCode.NRefactory.CSharp
return GetChildByRole (Roles.Identifier).Name;
}
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 @@ -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);
}

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

@ -0,0 +1,77 @@ @@ -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 @@ @@ -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 @@ -31,16 +31,16 @@ namespace ICSharpCode.NRefactory.CSharp
/// </summary>
public class NullReferenceExpression : Expression
{
AstLocation location;
public override AstLocation StartLocation {
TextLocation location;
public override TextLocation StartLocation {
get {
return location;
}
}
public override AstLocation EndLocation {
public override TextLocation EndLocation {
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 @@ -48,12 +48,12 @@ namespace ICSharpCode.NRefactory.CSharp
{
}
public NullReferenceExpression (AstLocation location)
public NullReferenceExpression (TextLocation 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);
}

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 @@ -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);
}

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 @@ -53,7 +53,7 @@ namespace ICSharpCode.NRefactory.CSharp
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);
}

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 @@ @@ -1,4 +1,4 @@
//
//
// PointerReferenceExpression.cs
//
// Author:
@ -45,7 +45,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -45,7 +45,7 @@ namespace ICSharpCode.NRefactory.CSharp
return GetChildByRole (Roles.Identifier).Name;
}
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 @@ -53,7 +53,7 @@ namespace ICSharpCode.NRefactory.CSharp
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);
}

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 @@ -33,17 +33,17 @@ namespace ICSharpCode.NRefactory.CSharp
{
public static readonly object AnyValue = new object();
AstLocation startLocation;
public override AstLocation StartLocation {
TextLocation startLocation;
public override TextLocation StartLocation {
get {
return startLocation;
}
}
string literalValue;
public override AstLocation EndLocation {
public override TextLocation EndLocation {
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 @@ -69,7 +69,7 @@ namespace ICSharpCode.NRefactory.CSharp
this.literalValue = literalValue ?? "";
}
public PrimitiveExpression (object value, AstLocation startLocation, string literalValue)
public PrimitiveExpression (object value, TextLocation startLocation, string literalValue)
{
this.Value = value;
this.startLocation = startLocation;
@ -77,13 +77,13 @@ namespace ICSharpCode.NRefactory.CSharp @@ -77,13 +77,13 @@ namespace ICSharpCode.NRefactory.CSharp
}
#region IRelocationable implementation
void IRelocatable.SetStartLocation (AstLocation startLocation)
void IRelocatable.SetStartLocation (TextLocation startLocation)
{
this.startLocation = startLocation;
}
#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);
}

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 @@ @@ -1,5 +1,20 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
// 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;
@ -21,7 +36,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -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);
}
@ -37,7 +52,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -37,7 +52,7 @@ namespace ICSharpCode.NRefactory.CSharp
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);
}
@ -89,11 +104,15 @@ namespace ICSharpCode.NRefactory.CSharp @@ -89,11 +104,15 @@ namespace ICSharpCode.NRefactory.CSharp
return GetChildByRole (Roles.Identifier).Name;
}
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);
}
@ -120,16 +139,20 @@ namespace ICSharpCode.NRefactory.CSharp @@ -120,16 +139,20 @@ namespace ICSharpCode.NRefactory.CSharp
return GetChildByRole (Roles.Identifier).Name;
}
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 {
get { return GetChildByRole (Roles.Expression); }
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);
}
@ -153,10 +176,14 @@ namespace ICSharpCode.NRefactory.CSharp @@ -153,10 +176,14 @@ namespace ICSharpCode.NRefactory.CSharp
return GetChildByRole(Roles.Identifier).Name;
}
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 {
get { return GetChildByRole(Roles.Assign); }
}
@ -166,7 +193,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -166,7 +193,7 @@ namespace ICSharpCode.NRefactory.CSharp
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);
}
@ -190,7 +217,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -190,7 +217,7 @@ namespace ICSharpCode.NRefactory.CSharp
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);
}
@ -237,10 +264,14 @@ namespace ICSharpCode.NRefactory.CSharp @@ -237,10 +264,14 @@ namespace ICSharpCode.NRefactory.CSharp
return GetChildByRole(JoinIdentifierRole).Name;
}
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 {
get { return GetChildByRole (InKeywordRole); }
}
@ -277,11 +308,15 @@ namespace ICSharpCode.NRefactory.CSharp @@ -277,11 +308,15 @@ namespace ICSharpCode.NRefactory.CSharp
return GetChildByRole (IntoIdentifierRole).Name;
}
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);
}
@ -309,7 +344,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -309,7 +344,7 @@ namespace ICSharpCode.NRefactory.CSharp
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);
}
@ -341,7 +376,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -341,7 +376,7 @@ namespace ICSharpCode.NRefactory.CSharp
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);
}
@ -371,7 +406,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -371,7 +406,7 @@ namespace ICSharpCode.NRefactory.CSharp
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);
}
@ -408,7 +443,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -408,7 +443,7 @@ namespace ICSharpCode.NRefactory.CSharp
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);
}

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 @@ -57,7 +57,7 @@ namespace ICSharpCode.NRefactory.CSharp
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);
}

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

Loading…
Cancel
Save