From e0f0a2aa2e156792bb1e898b4ca9687e509e9adb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Artur=20Zgodzi=C5=84ski?= Date: Tue, 22 Feb 2011 21:14:33 +0100 Subject: [PATCH 01/30] Modifications of solution and project files made by VS2010. --- .gitignore | 3 +- ILSpy.sln | 92 ++++++++++--------- .../ICSharpCode.NRefactory.Demo.csproj | 16 +++- .../ICSharpCode.NRefactory.csproj | 6 -- 4 files changed, 61 insertions(+), 56 deletions(-) diff --git a/.gitignore b/.gitignore index b96f1bdfd..a81b8dbf5 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ bin/ obj/ /ICSharpCode.Decompiler/Properties/AssemblyInfo.cs -/ILSpy/Properties/AssemblyInfo.cs \ No newline at end of file +/ILSpy/Properties/AssemblyInfo.cs +*.suo \ No newline at end of file diff --git a/ILSpy.sln b/ILSpy.sln index 409cbd730..14784f3b7 100644 --- a/ILSpy.sln +++ b/ILSpy.sln @@ -1,7 +1,6 @@  Microsoft Visual Studio Solution File, Format Version 11.00 # Visual Studio 2010 -# SharpDevelop 4.0.1.7096 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ILSpy", "ILSpy\ILSpy.csproj", "{1E85EFF9-E370-4683-83E4-8A3D063FF791}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.TreeView", "SharpTreeView\ICSharpCode.TreeView.csproj", "{DDE2A481-8271-4EAC-A330-8FA6A38D13D1}" @@ -18,67 +17,70 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.Decompiler.Test EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x86 = Debug|x86 - Release|x86 = Release|x86 Debug|Any CPU = Debug|Any CPU + Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU + Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {1E85EFF9-E370-4683-83E4-8A3D063FF791}.Debug|x86.Build.0 = Debug|x86 - {1E85EFF9-E370-4683-83E4-8A3D063FF791}.Debug|x86.ActiveCfg = Debug|x86 - {1E85EFF9-E370-4683-83E4-8A3D063FF791}.Release|x86.Build.0 = Release|x86 - {1E85EFF9-E370-4683-83E4-8A3D063FF791}.Release|x86.ActiveCfg = Release|x86 - {1E85EFF9-E370-4683-83E4-8A3D063FF791}.Debug|Any CPU.Build.0 = Debug|Any CPU {1E85EFF9-E370-4683-83E4-8A3D063FF791}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1E85EFF9-E370-4683-83E4-8A3D063FF791}.Release|Any CPU.Build.0 = Release|Any CPU + {1E85EFF9-E370-4683-83E4-8A3D063FF791}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1E85EFF9-E370-4683-83E4-8A3D063FF791}.Debug|x86.ActiveCfg = Debug|x86 + {1E85EFF9-E370-4683-83E4-8A3D063FF791}.Debug|x86.Build.0 = Debug|x86 {1E85EFF9-E370-4683-83E4-8A3D063FF791}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DDE2A481-8271-4EAC-A330-8FA6A38D13D1}.Debug|x86.Build.0 = Debug|Any CPU - {DDE2A481-8271-4EAC-A330-8FA6A38D13D1}.Debug|x86.ActiveCfg = Debug|Any CPU - {DDE2A481-8271-4EAC-A330-8FA6A38D13D1}.Release|x86.Build.0 = Release|Any CPU - {DDE2A481-8271-4EAC-A330-8FA6A38D13D1}.Release|x86.ActiveCfg = Release|Any CPU - {DDE2A481-8271-4EAC-A330-8FA6A38D13D1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1E85EFF9-E370-4683-83E4-8A3D063FF791}.Release|Any CPU.Build.0 = Release|Any CPU + {1E85EFF9-E370-4683-83E4-8A3D063FF791}.Release|x86.ActiveCfg = Release|x86 + {1E85EFF9-E370-4683-83E4-8A3D063FF791}.Release|x86.Build.0 = Release|x86 {DDE2A481-8271-4EAC-A330-8FA6A38D13D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DDE2A481-8271-4EAC-A330-8FA6A38D13D1}.Release|Any CPU.Build.0 = Release|Any CPU + {DDE2A481-8271-4EAC-A330-8FA6A38D13D1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DDE2A481-8271-4EAC-A330-8FA6A38D13D1}.Debug|x86.ActiveCfg = Debug|Any CPU + {DDE2A481-8271-4EAC-A330-8FA6A38D13D1}.Debug|x86.Build.0 = Debug|Any CPU {DDE2A481-8271-4EAC-A330-8FA6A38D13D1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|x86.Build.0 = net_2_0_Debug|Any CPU - {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|x86.ActiveCfg = net_4_0_Debug|Any CPU - {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|Any CPU.Build.0 = net_2_0_Debug|Any CPU + {DDE2A481-8271-4EAC-A330-8FA6A38D13D1}.Release|Any CPU.Build.0 = Release|Any CPU + {DDE2A481-8271-4EAC-A330-8FA6A38D13D1}.Release|x86.ActiveCfg = Release|Any CPU + {DDE2A481-8271-4EAC-A330-8FA6A38D13D1}.Release|x86.Build.0 = Release|Any CPU {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|Any CPU.ActiveCfg = net_4_0_Debug|Any CPU - {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|x86.Build.0 = net_2_0_Debug|Any CPU - {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|x86.ActiveCfg = net_4_0_Release|Any CPU - {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|Any CPU.Build.0 = net_2_0_Debug|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|Any CPU.Build.0 = net_4_0_Debug|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|x86.ActiveCfg = net_4_0_Debug|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|x86.Build.0 = net_2_0_Debug|Any CPU {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|Any CPU.ActiveCfg = net_4_0_Release|Any CPU - {6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}.Debug|x86.Build.0 = Debug|Any CPU - {6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}.Debug|x86.ActiveCfg = Debug|Any CPU - {6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|Any CPU.Build.0 = net_4_0_Release|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|x86.ActiveCfg = net_4_0_Release|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|x86.Build.0 = net_2_0_Debug|Any CPU {6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}.Release|x86.Build.0 = Release|Any CPU - {6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}.Release|x86.ActiveCfg = Release|Any CPU - {6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}.Release|Any CPU.Build.0 = Release|Any CPU + {6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}.Debug|x86.ActiveCfg = Debug|Any CPU + {6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}.Debug|x86.Build.0 = Debug|Any CPU {6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}.Release|Any CPU.ActiveCfg = Release|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|Any CPU.Build.0 = Debug|Any CPU + {6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}.Release|Any CPU.Build.0 = Release|Any CPU + {6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}.Release|x86.ActiveCfg = Release|Any CPU + {6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}.Release|x86.Build.0 = Release|Any CPU {984CC812-9470-4A13-AFF9-CC44068D666C}.Debug|Any CPU.ActiveCfg = Debug|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|Any CPU.Build.0 = Release|Any CPU + {984CC812-9470-4A13-AFF9-CC44068D666C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {984CC812-9470-4A13-AFF9-CC44068D666C}.Debug|x86.ActiveCfg = Debug|Any CPU + {984CC812-9470-4A13-AFF9-CC44068D666C}.Debug|x86.Build.0 = Debug|Any CPU {984CC812-9470-4A13-AFF9-CC44068D666C}.Release|Any CPU.ActiveCfg = Release|Any CPU - {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|Any CPU.Build.0 = Debug|Any CPU + {984CC812-9470-4A13-AFF9-CC44068D666C}.Release|Any CPU.Build.0 = Release|Any CPU + {984CC812-9470-4A13-AFF9-CC44068D666C}.Release|x86.ActiveCfg = Release|Any CPU + {984CC812-9470-4A13-AFF9-CC44068D666C}.Release|x86.Build.0 = Release|Any CPU {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Debug|Any CPU.ActiveCfg = Debug|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|Any CPU.Build.0 = Release|Any CPU + {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Debug|x86.ActiveCfg = Debug|Any CPU + {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Debug|x86.Build.0 = Debug|Any CPU {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Release|Any CPU.ActiveCfg = Release|Any CPU - {FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Debug|x86.Build.0 = Debug|x86 - {FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Debug|x86.ActiveCfg = Debug|x86 - {FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Debug|Any CPU.Build.0 = Debug|x86 + {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Release|Any CPU.Build.0 = Release|Any CPU + {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Release|x86.ActiveCfg = Release|Any CPU + {3B2A5653-EC97-4001-BB9B-D90F1AF2C371}.Release|x86.Build.0 = Release|Any CPU {FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Debug|Any CPU.ActiveCfg = Debug|x86 - {FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Release|x86.Build.0 = Release|x86 - {FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Release|x86.ActiveCfg = Release|x86 - {FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Release|Any CPU.Build.0 = Release|x86 + {FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Debug|Any CPU.Build.0 = Debug|x86 + {FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Debug|x86.ActiveCfg = Debug|x86 + {FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Debug|x86.Build.0 = Debug|x86 {FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Release|Any CPU.ActiveCfg = Release|x86 + {FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Release|Any CPU.Build.0 = Release|x86 + {FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Release|x86.ActiveCfg = Release|x86 + {FEC0DA52-C4A6-4710-BE36-B484A20C5E22}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE EndGlobalSection EndGlobal diff --git a/NRefactory/ICSharpCode.NRefactory.Demo/ICSharpCode.NRefactory.Demo.csproj b/NRefactory/ICSharpCode.NRefactory.Demo/ICSharpCode.NRefactory.Demo.csproj index 36ea620c6..906a94773 100644 --- a/NRefactory/ICSharpCode.NRefactory.Demo/ICSharpCode.NRefactory.Demo.csproj +++ b/NRefactory/ICSharpCode.NRefactory.Demo/ICSharpCode.NRefactory.Demo.csproj @@ -40,21 +40,29 @@ - + + Form + VBEditDialog.cs - + + UserControl + VBDomView.cs - + + Form + MainForm.cs - + + UserControl + VBDemo.cs diff --git a/NRefactory/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj b/NRefactory/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj index 6fdcd0c9f..68821f953 100644 --- a/NRefactory/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj +++ b/NRefactory/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj @@ -350,11 +350,5 @@ Mono.Cecil - - - {D68133BD-1E63-496E-9EDE-4FBDBF77B486} - Mono.Cecil - - \ No newline at end of file From d13d7bd48fcf933d229c9b85fbfc1f022353873a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Artur=20Zgodzi=C5=84ski?= Date: Tue, 22 Feb 2011 23:56:47 +0100 Subject: [PATCH 02/30] Basic output of custom attributes attached to types and methods. --- ICSharpCode.Decompiler/Ast/AstBuilder.cs | 23 +++- .../Tests/CustomAttributes.cs | 15 +++ .../Tests/ICSharpCode.Decompiler.Tests.csproj | 9 ++ ICSharpCode.Decompiler/Tests/TestRunner.cs | 104 ++++++++++++++---- .../CSharp/OutputVisitor/OutputVisitor.cs | 11 +- 5 files changed, 139 insertions(+), 23 deletions(-) create mode 100644 ICSharpCode.Decompiler/Tests/CustomAttributes.cs diff --git a/ICSharpCode.Decompiler/Ast/AstBuilder.cs b/ICSharpCode.Decompiler/Ast/AstBuilder.cs index 1d91f59b6..e2363ddb8 100644 --- a/ICSharpCode.Decompiler/Ast/AstBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstBuilder.cs @@ -180,7 +180,8 @@ namespace Decompiler AddTypeMembers(astType, typeDef); } - + + ConvertCustomAtributes(astType, typeDef); return astType; } @@ -461,6 +462,7 @@ namespace Decompiler astMethod.Modifiers = ConvertModifiers(methodDef); astMethod.Body = AstMethodBodyBuilder.CreateMethodBody(methodDef, context); } + ConvertCustomAtributes(astMethod, methodDef); return astMethod; } @@ -565,5 +567,24 @@ namespace Decompiler yield return astParam; } } + + static void ConvertCustomAtributes(AttributedNode attributedNode, ICustomAttributeProvider customAttributeProvider) + { + if (customAttributeProvider.HasCustomAttributes) + { + var section = new AttributeSection(); + //section.AttributeTarget = target; + foreach (var customAttribute in customAttributeProvider.CustomAttributes) + { + ICSharpCode.NRefactory.CSharp.Attribute attribute = new ICSharpCode.NRefactory.CSharp.Attribute(); + //customAttribute. + attribute.Type = ConvertType(customAttribute.AttributeType); + section.Attributes.Add(attribute); + + } + + attributedNode.Attributes.Add(section); + } + } } } diff --git a/ICSharpCode.Decompiler/Tests/CustomAttributes.cs b/ICSharpCode.Decompiler/Tests/CustomAttributes.cs new file mode 100644 index 000000000..fa12ffa9b --- /dev/null +++ b/ICSharpCode.Decompiler/Tests/CustomAttributes.cs @@ -0,0 +1,15 @@ +// 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) + +using System; + + +public static class CustomAtributes +{ + [Flags] + public enum EnumWithFlag + { + Item1, + Item2 + } +} diff --git a/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj b/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj index 8d0896ef5..b6ce307f5 100644 --- a/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj +++ b/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj @@ -38,6 +38,14 @@ TRACE + + False + ..\..\libs\Gallio.dll + + + False + ..\..\libs\MbUnit.dll + 3.5 @@ -49,6 +57,7 @@ + diff --git a/ICSharpCode.Decompiler/Tests/TestRunner.cs b/ICSharpCode.Decompiler/Tests/TestRunner.cs index d4fa06fdd..da07307da 100644 --- a/ICSharpCode.Decompiler/Tests/TestRunner.cs +++ b/ICSharpCode.Decompiler/Tests/TestRunner.cs @@ -9,6 +9,7 @@ using System.Text; using Decompiler; using Microsoft.CSharp; using Mono.Cecil; +using MbUnit.Framework; namespace ICSharpCode.Decompiler.Tests { @@ -16,14 +17,31 @@ namespace ICSharpCode.Decompiler.Tests { public static void Main() { - Test(@"..\..\Tests\DelegateConstruction.cs"); - + TestFile(@"..\..\Tests\DelegateConstruction.cs"); + Console.ReadKey(); } - - - - static void Test(string fileName) + + [Test] + //[Row(@"..\..\Tests\DelegateConstruction.cs")] + //[Row(@"..\..\Tests\Loops.cs")] + [Row(@"..\..\Tests\CustomAttributes.cs")] + public void RoundtripFile(string fileName) + { + string code = File.ReadAllText(fileName); + AssemblyDefinition assembly = Compile(code); + AstBuilder decompiler = new AstBuilder(new DecompilerContext()); + decompiler.AddAssembly(assembly); + StringWriter output = new StringWriter(); + decompiler.GenerateCode(new PlainTextOutput(output)); + + var decompiledCode = output.ToString(); + var onlyCode = "using System;" + Environment.NewLine + StripCodeFileHeader(code); + + Assert.AreEqual(onlyCode, decompiledCode); + } + + static void TestFile(string fileName) { string code = File.ReadAllText(fileName); AssemblyDefinition assembly = Compile(code); @@ -32,11 +50,45 @@ namespace ICSharpCode.Decompiler.Tests StringWriter output = new StringWriter(); decompiler.GenerateCode(new PlainTextOutput(output)); StringWriter diff = new StringWriter(); - if (!Compare(code, output.ToString(), diff)) { + if (!Compare(code, output.ToString(), diff)) + { throw new Exception("Test failure." + Environment.NewLine + diff.ToString()); } } - + + static string StripCodeFileHeader(string code) + { + var reader = new StringReader(code); + + var buffer = new StringWriter(); + + string line; + var skipBlankLine = false; + while ((line = reader.ReadLine()) != null) + { + if (line.Trim().StartsWith("//")) + { + skipBlankLine = true; + continue; + } + else if (line.StartsWith("using ")) + { + skipBlankLine = true; + continue; + } + else if (skipBlankLine && String.IsNullOrWhiteSpace(line)) + { + continue; + } + + skipBlankLine = false; + + buffer.WriteLine(line); + } + + return buffer.ToString(); + } + static bool Compare(string input1, string input2, StringWriter diff) { bool ok = true; @@ -44,55 +96,67 @@ namespace ICSharpCode.Decompiler.Tests StringReader r1 = new StringReader(input1); StringReader r2 = new StringReader(input2); string line1, line2; - while ((line1 = r1.ReadLine()) != null) { + while ((line1 = r1.ReadLine()) != null) + { string trimmed = line1.Trim(); - if (trimmed.Length == 0 || trimmed.StartsWith("//", StringComparison.Ordinal) || line1.StartsWith("using ", StringComparison.Ordinal)) { + if (trimmed.Length == 0 || trimmed.StartsWith("//", StringComparison.Ordinal) || line1.StartsWith("using ", StringComparison.Ordinal)) + { diff.WriteLine(" " + line1); continue; } line2 = r2.ReadLine(); while (line2 != null && (line2.StartsWith("using ", StringComparison.Ordinal) || line2.Trim().Length == 0)) line2 = r2.ReadLine(); - if (line2 == null) { + if (line2 == null) + { ok = false; diff.WriteLine("-" + line1); continue; } - if (line1 != line2) { + if (line1 != line2) + { ok = false; if (numberOfContinuousMistakes++ > 5) return false; diff.WriteLine("-" + line1); diff.WriteLine("+" + line2); - } else { + } + else + { if (numberOfContinuousMistakes > 0) numberOfContinuousMistakes--; diff.WriteLine(" " + line1); } } - while ((line2 = r2.ReadLine()) != null) { + while ((line2 = r2.ReadLine()) != null) + { ok = false; diff.WriteLine("+" + line2); } return ok; } - + static AssemblyDefinition Compile(string code) { - CSharpCodeProvider provider = new CSharpCodeProvider(new Dictionary {{ "CompilerVersion", "v4.0" }}); + CSharpCodeProvider provider = new CSharpCodeProvider(new Dictionary { { "CompilerVersion", "v4.0" } }); CompilerParameters options = new CompilerParameters(); options.ReferencedAssemblies.Add("System.Core.dll"); CompilerResults results = provider.CompileAssemblyFromSource(options, code); - try { - if (results.Errors.Count > 0) { + try + { + if (results.Errors.Count > 0) + { StringBuilder b = new StringBuilder("Compiler error:"); - foreach (var error in results.Errors) { + foreach (var error in results.Errors) + { b.AppendLine(error.ToString()); } throw new Exception(b.ToString()); } return AssemblyDefinition.ReadAssembly(results.PathToAssembly); - } finally { + } + finally + { File.Delete(results.PathToAssembly); results.TempFiles.Delete(); } diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs index cf880653e..933a7f9a1 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs @@ -1083,7 +1083,8 @@ namespace ICSharpCode.NRefactory.CSharp StartNode(attribute); attribute.Type.AcceptVisitor(this, data); Space(policy.BeforeMethodCallParentheses); - WriteCommaSeparatedListInParenthesis(attribute.Arguments, policy.WithinMethodCallParentheses); + if (attribute.Arguments.Count != 0) + WriteCommaSeparatedListInParenthesis(attribute.Arguments, policy.WithinMethodCallParentheses); return EndNode(attribute); } @@ -1879,8 +1880,14 @@ namespace ICSharpCode.NRefactory.CSharp public object VisitSimpleType(SimpleType simpleType, object data) { + bool inAttribute = currentContainerNode is Attribute; StartNode(simpleType); - WriteIdentifier(simpleType.Identifier); + + var identifier = simpleType.Identifier; + if (inAttribute && identifier.EndsWith("Attribute")) + identifier = identifier.Substring(0, identifier.Length - 9); + WriteIdentifier(identifier); + WriteTypeArguments(simpleType.TypeArguments); return EndNode(simpleType); } From b4c55dc7050e338a188671c9da3bfb786adb3826 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Artur=20Zgodzi=C5=84ski?= Date: Wed, 23 Feb 2011 09:40:26 +0100 Subject: [PATCH 03/30] Removed redundant int base type of enum. --- .../CSharp/OutputVisitor/OutputVisitor.cs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs index 933a7f9a1..8c5911e70 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs @@ -1161,7 +1161,7 @@ namespace ICSharpCode.NRefactory.CSharp } WriteIdentifier(typeDeclaration.Name); WriteTypeParameters(typeDeclaration.TypeParameters); - if (typeDeclaration.BaseTypes.Any()) { + if (typeDeclaration.BaseTypes.Any() && !IsStandardEnum(typeDeclaration)) { Space(); WriteToken(":", TypeDeclaration.ColonRole); Space(); @@ -1192,6 +1192,22 @@ namespace ICSharpCode.NRefactory.CSharp NewLine(); return EndNode(typeDeclaration); } + + private static bool IsStandardEnum(TypeDeclaration typeDeclaration) + { + if (typeDeclaration.ClassType != ClassType.Enum) + { + return false; + } + + if (typeDeclaration.BaseTypes.Count != 1) // is is possible? + { + return false; + } + + var baseType = typeDeclaration.BaseTypes.First() as PrimitiveType; + return baseType != null && baseType.Keyword == "int"; + } public object VisitUsingAliasDeclaration(UsingAliasDeclaration usingAliasDeclaration, object data) { From 7e5e94534ce24e0d3fd27d2d28337af18c1f84e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Artur=20Zgodzi=C5=84ski?= Date: Wed, 23 Feb 2011 17:42:36 +0100 Subject: [PATCH 04/30] Print a custom attribute's positional arguments. --- ICSharpCode.Decompiler/Ast/AstBuilder.cs | 6 +++++- ICSharpCode.Decompiler/Tests/CustomAttributes.cs | 6 +++++- .../CSharp/Ast/GeneralScope/Attribute.cs | 2 ++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/ICSharpCode.Decompiler/Ast/AstBuilder.cs b/ICSharpCode.Decompiler/Ast/AstBuilder.cs index b4ed67ac3..3a30aae48 100644 --- a/ICSharpCode.Decompiler/Ast/AstBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstBuilder.cs @@ -578,10 +578,14 @@ namespace Decompiler foreach (var customAttribute in customAttributeProvider.CustomAttributes) { ICSharpCode.NRefactory.CSharp.Attribute attribute = new ICSharpCode.NRefactory.CSharp.Attribute(); - //customAttribute. attribute.Type = ConvertType(customAttribute.AttributeType); section.Attributes.Add(attribute); + foreach (var parameter in customAttribute.ConstructorArguments) + { + attribute.Arguments.Add(new PrimitiveExpression(parameter.Value)); + } + } attributedNode.Attributes.Add(section); diff --git a/ICSharpCode.Decompiler/Tests/CustomAttributes.cs b/ICSharpCode.Decompiler/Tests/CustomAttributes.cs index fa12ffa9b..17f1a55ed 100644 --- a/ICSharpCode.Decompiler/Tests/CustomAttributes.cs +++ b/ICSharpCode.Decompiler/Tests/CustomAttributes.cs @@ -9,7 +9,11 @@ public static class CustomAtributes [Flags] public enum EnumWithFlag { - Item1, +// Item1, Item2 } + [Obsolete("some message")] + public static void ObsoletedMethod() + { + } } diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/Attribute.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/Attribute.cs index 877771736..b5a44275b 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/Attribute.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/Attribute.cs @@ -25,12 +25,14 @@ // THE SOFTWARE. using System.Collections.Generic; +using System.Diagnostics; namespace ICSharpCode.NRefactory.CSharp { /// /// Attribute(Arguments) /// + [DebuggerDisplay("Attribute {Type}")] public class Attribute : AstNode { public override NodeType NodeType { From 679d525806d8ca7c0820255679aadde728f75881 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Artur=20Zgodzi=C5=84ski?= Date: Thu, 24 Feb 2011 00:59:51 +0100 Subject: [PATCH 05/30] Fixed enum boxing decompilation bug. Enum in attributes better printing. --- ICSharpCode.Decompiler/Ast/AstBuilder.cs | 71 ++++++++++++++++++- .../Ast/AstMethodBodyBuilder.cs | 38 +++------- ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs | 9 +++ .../Tests/CustomAttributes.cs | 8 +++ 4 files changed, 97 insertions(+), 29 deletions(-) diff --git a/ICSharpCode.Decompiler/Ast/AstBuilder.cs b/ICSharpCode.Decompiler/Ast/AstBuilder.cs index 3a30aae48..5bdefecc4 100644 --- a/ICSharpCode.Decompiler/Ast/AstBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstBuilder.cs @@ -6,8 +6,10 @@ using System.Threading; using Decompiler.Transforms; using ICSharpCode.Decompiler; using ICSharpCode.NRefactory.CSharp; +using ICSharpCode.NRefactory.Utils; using Mono.Cecil; using Mono.Cecil.Cil; +using Ast = ICSharpCode.NRefactory.CSharp; using ClassType = ICSharpCode.NRefactory.TypeSystem.ClassType; using VarianceModifier = ICSharpCode.NRefactory.TypeSystem.VarianceModifier; @@ -583,7 +585,17 @@ namespace Decompiler foreach (var parameter in customAttribute.ConstructorArguments) { - attribute.Arguments.Add(new PrimitiveExpression(parameter.Value)); + var isEnum = parameter.Type.IsValueType && !parameter.Type.IsPrimitive; + Expression parameterValue; + if (isEnum) + { + parameterValue = MakePrimitive(Convert.ToInt64(parameter.Value), parameter.Type); + } + else + { + parameterValue = new PrimitiveExpression(parameter.Value); + } + attribute.Arguments.Add(parameterValue); } } @@ -591,5 +603,62 @@ namespace Decompiler attributedNode.Attributes.Add(section); } } + + + internal static Expression MakePrimitive(long val, TypeReference type) + { + if (TypeAnalysis.IsBoolean(type) && val == 0) + return new Ast.PrimitiveExpression(false); + else if (TypeAnalysis.IsBoolean(type) && val == 1) + return new Ast.PrimitiveExpression(true); + if (type != null) + { // cannot rely on type.IsValueType, it's not set for typerefs (but is set for typespecs) + TypeDefinition enumDefinition = type.Resolve(); + if (enumDefinition != null && enumDefinition.IsEnum) + { + foreach (FieldDefinition field in enumDefinition.Fields) + { + if (field.IsStatic && object.Equals(CSharpPrimitiveCast.Cast(TypeCode.Int64, field.Constant, false), val)) + return AstBuilder.ConvertType(enumDefinition).Member(field.Name).WithAnnotation(field); + else if (!field.IsStatic && field.IsRuntimeSpecialName) + type = field.FieldType; // use primitive type of the enum + } + if (IsFlagsEnum(enumDefinition)) + { + Expression expr = null; + foreach (FieldDefinition field in enumDefinition.Fields.Where(fld => fld.IsStatic)) + { + long fieldValue = (long)CSharpPrimitiveCast.Cast(TypeCode.Int64, field.Constant, false); + if (fieldValue == 0) + continue; // skip None enum value + + if ((fieldValue & val) == fieldValue) + { + var fieldExpression = AstBuilder.ConvertType(enumDefinition).Member(field.Name).WithAnnotation(field); + if (expr == null) + expr = fieldExpression; + else + expr = new BinaryOperatorExpression(expr, BinaryOperatorType.BitwiseOr, fieldExpression); + } + } + if (expr != null) + return expr; + } + } + } + TypeCode code = TypeAnalysis.GetTypeCode(type); + if (code == TypeCode.Object) + return new Ast.PrimitiveExpression((int)val); + else + return new Ast.PrimitiveExpression(CSharpPrimitiveCast.Cast(code, val, false)); + } + + static bool IsFlagsEnum(TypeDefinition type) + { + if (!type.HasCustomAttributes) + return false; + + return type.CustomAttributes.Any(attr => attr.AttributeType.FullName == "System.FlagsAttribute"); + } } } diff --git a/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs b/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs index eabbc2203..853cac5a8 100644 --- a/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs @@ -514,7 +514,7 @@ namespace Decompiler return MakeRef(new Ast.IdentifierExpression(((ParameterDefinition)operand).Name).WithAnnotation(operand)); } case Code.Ldc_I4: - return MakePrimitive((int)operand, byteCode.InferredType); + return AstBuilder.MakePrimitive((int)operand, byteCode.InferredType); case Code.Ldc_I8: case Code.Ldc_R4: case Code.Ldc_R8: @@ -763,7 +763,7 @@ namespace Decompiler if (TypeAnalysis.IsBoolean(actualType)) return expr; if (actualIsIntegerOrEnum) { - return new BinaryOperatorExpression(expr, BinaryOperatorType.InEquality, MakePrimitive(0, actualType)); + return new BinaryOperatorExpression(expr, BinaryOperatorType.InEquality, AstBuilder.MakePrimitive(0, actualType)); } else { return new BinaryOperatorExpression(expr, BinaryOperatorType.InEquality, new NullReferenceExpression()); } @@ -771,39 +771,21 @@ namespace Decompiler if (TypeAnalysis.IsBoolean(actualType) && requiredIsIntegerOrEnum) { return new ConditionalExpression { Condition = expr, - TrueExpression = MakePrimitive(1, reqType), - FalseExpression = MakePrimitive(0, reqType) + TrueExpression = AstBuilder.MakePrimitive(1, reqType), + FalseExpression = AstBuilder.MakePrimitive(0, reqType) }; } + + if (expr is PrimitiveExpression && !requiredIsIntegerOrEnum && TypeAnalysis.IsEnum(actualType)) + { + return expr.CastTo(AstBuilder.ConvertType(actualType)); + } + if (actualIsIntegerOrEnum && requiredIsIntegerOrEnum) { return expr.CastTo(AstBuilder.ConvertType(reqType)); } return expr; } } - - Expression MakePrimitive(long val, TypeReference type) - { - if (TypeAnalysis.IsBoolean(type) && val == 0) - return new Ast.PrimitiveExpression(false); - else if (TypeAnalysis.IsBoolean(type) && val == 1) - return new Ast.PrimitiveExpression(true); - if (type != null) { // cannot rely on type.IsValueType, it's not set for typerefs (but is set for typespecs) - TypeDefinition enumDefinition = type.Resolve(); - if (enumDefinition != null && enumDefinition.IsEnum) { - foreach (FieldDefinition field in enumDefinition.Fields) { - if (field.IsStatic && object.Equals(CSharpPrimitiveCast.Cast(TypeCode.Int64, field.Constant, false), val)) - return AstBuilder.ConvertType(enumDefinition).Member(field.Name).WithAnnotation(field); - else if (!field.IsStatic && field.IsRuntimeSpecialName) - type = field.FieldType; // use primitive type of the enum - } - } - } - TypeCode code = TypeAnalysis.GetTypeCode(type); - if (code == TypeCode.Object) - return new Ast.PrimitiveExpression((int)val); - else - return new Ast.PrimitiveExpression(CSharpPrimitiveCast.Cast(code, val, false)); - } } } diff --git a/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs b/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs index 6c79b565e..bcf83ba50 100644 --- a/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs +++ b/ICSharpCode.Decompiler/ILAst/TypeAnalysis.cs @@ -627,6 +627,15 @@ namespace Decompiler { return IsSigned(type) != null; } + + public static bool IsEnum(TypeReference type) + { + if (type == null) + return false; + // unfortunately we cannot rely on type.IsValueType here - it's not set when the instruction operand is a typeref (as opposed to a typespec) + TypeDefinition typeDef = type.Resolve() as TypeDefinition; + return typeDef != null && typeDef.IsEnum; + } static bool? IsSigned(TypeReference type) { diff --git a/ICSharpCode.Decompiler/Tests/CustomAttributes.cs b/ICSharpCode.Decompiler/Tests/CustomAttributes.cs index 17f1a55ed..11258a42e 100644 --- a/ICSharpCode.Decompiler/Tests/CustomAttributes.cs +++ b/ICSharpCode.Decompiler/Tests/CustomAttributes.cs @@ -12,8 +12,16 @@ public static class CustomAtributes // Item1, Item2 } + [AttributeUsage(AttributeTargets.All)] + public class MyAttribute : Attribute + { + } [Obsolete("some message")] public static void ObsoletedMethod() { + //Console.WriteLine("{0} $$$ {1}", AttributeTargets.Interface, (AttributeTargets)(AttributeTargets.Property | AttributeTargets.Field)); + Console.WriteLine("{0} $$$ {1}", AttributeTargets.Interface, AttributeTargets.Property | AttributeTargets.Field); + AttributeTargets attributeTargets = AttributeTargets.Property | AttributeTargets.Field; + Console.WriteLine("{0} $$$ {1}", AttributeTargets.Interface, attributeTargets); } } From d1fff3fdb12291189c2f438887e7c47d9e039fe6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Artur=20Zgodzi=C5=84ski?= Date: Thu, 24 Feb 2011 19:04:29 +0100 Subject: [PATCH 06/30] testing code that helps running independent decompilation tests. --- .../Tests/CodeSampleFileParser.cs | 114 ++++++++++++++++++ .../Tests/CustomAttributes.code.cs | 41 +++++++ .../Tests/CustomAttributes.cs | 27 ----- .../CustomAttributeSamples.cs | 81 +++++++++++++ .../CustomAttributes/CustomAttributeTests.cs | 23 ++++ .../CustomAttributes/CustomAttributes.cs | 47 ++++++++ .../Tests/DecompilerTestBase.cs | 89 ++++++++++++++ .../Tests/ICSharpCode.Decompiler.Tests.csproj | 16 ++- ICSharpCode.Decompiler/Tests/TestRunner.cs | 7 +- .../Tests/{ => Types}/DelegateConstruction.cs | 0 .../Tests/{ => Types}/PropertiesAndEvents.cs | 0 .../Tests/Types/TypeTests.cs | 29 +++++ .../Tests/{ => Types}/ValueTypes.cs | 0 13 files changed, 438 insertions(+), 36 deletions(-) create mode 100644 ICSharpCode.Decompiler/Tests/CodeSampleFileParser.cs create mode 100644 ICSharpCode.Decompiler/Tests/CustomAttributes.code.cs delete mode 100644 ICSharpCode.Decompiler/Tests/CustomAttributes.cs create mode 100644 ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeSamples.cs create mode 100644 ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeTests.cs create mode 100644 ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributes.cs create mode 100644 ICSharpCode.Decompiler/Tests/DecompilerTestBase.cs rename ICSharpCode.Decompiler/Tests/{ => Types}/DelegateConstruction.cs (100%) rename ICSharpCode.Decompiler/Tests/{ => Types}/PropertiesAndEvents.cs (100%) create mode 100644 ICSharpCode.Decompiler/Tests/Types/TypeTests.cs rename ICSharpCode.Decompiler/Tests/{ => Types}/ValueTypes.cs (100%) diff --git a/ICSharpCode.Decompiler/Tests/CodeSampleFileParser.cs b/ICSharpCode.Decompiler/Tests/CodeSampleFileParser.cs new file mode 100644 index 000000000..c481c25e8 --- /dev/null +++ b/ICSharpCode.Decompiler/Tests/CodeSampleFileParser.cs @@ -0,0 +1,114 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; + +namespace ICSharpCode.Decompiler.Tests +{ + static class CodeSampleFileParser + { + public static IEnumerable ListSections(string s) + { + var query = from line in ToLines(s) + let sectionName = ReadSectionName(line) + where sectionName != null + select sectionName; + return query; + } + + public static string GetSection(string sectionName, string s) + { + var lines = ToLines(s); + + bool sectionFound = false; + var sectionText = new StringBuilder(); + + Action parser = null; + + Action commonSectionReader = line => + { + if (IsCommonSectionEnd(line)) + parser = null; + else + sectionText.AppendLine(line); + }; + + Action namedSectionReader = line => + { + string name = ReadSectionName(line); + if (name == null) + sectionText.AppendLine(line); + else if (name != sectionName) + parser = null; + }; + + Action defaultReader = line => + { + if (IsCommonSectionStart(line)) + parser = commonSectionReader; + else if (ReadSectionName(line) == sectionName) + { + parser = namedSectionReader; + sectionFound = true; + } + }; + + foreach(var line in lines) + { + (parser ?? defaultReader)(line); + } + + if (sectionFound) + return sectionText.ToString(); + else + return ""; + } + + public static bool IsCommentOrBlank(string s) + { + if(String.IsNullOrWhiteSpace(s)) + return true; + return s.Trim().StartsWith("//"); + } + + public static string ConcatLines(IEnumerable lines) + { + var buffer = new StringBuilder(); + foreach (var line in lines) + { + buffer.AppendLine(line); + } + return buffer.ToString(); + } + + static string ReadSectionName(string line) + { + line = line.TrimStart(); + if (line.StartsWith("//$$")) + return line.Substring(4).Trim(); + else + return null; + } + + static bool IsCommonSectionStart(string line) + { + return line.Trim() == "//$CS"; + } + + static bool IsCommonSectionEnd(string line) + { + return line.Trim() == "//$CE"; + } + + static IEnumerable ToLines(string s) + { + var reader = new StringReader(s); + string line; + while ((line = reader.ReadLine()) != null) + { + yield return line; + } + } + } +} diff --git a/ICSharpCode.Decompiler/Tests/CustomAttributes.code.cs b/ICSharpCode.Decompiler/Tests/CustomAttributes.code.cs new file mode 100644 index 000000000..4130b0b0f --- /dev/null +++ b/ICSharpCode.Decompiler/Tests/CustomAttributes.code.cs @@ -0,0 +1,41 @@ +using System; +namespace aa +{ + public static class CustomAtributes + { + [Flags] + public enum EnumWithFlag + { + All = 15, + None = 0, + Item1 = 1, + Item2 = 2, + Item3 = 4, + Item4 = 8 + } + [AttributeUsage(AttributeTargets.All)] + public class MyAttribute : Attribute + { + public MyAttribute(CustomAtributes.EnumWithFlag en) + { + } + } + [CustomAtributes.MyAttribute(CustomAtributes.EnumWithFlag.Item1 | CustomAtributes.EnumWithFlag.Item2)] + private static int field; + [CustomAtributes.MyAttribute(CustomAtributes.EnumWithFlag.All)] + public static string Property + { + get + { + return "aa"; + } + } + [Obsolete("some message")] + public static void ObsoletedMethod() + { + Console.WriteLine("{0} $$$ {1}", AttributeTargets.Interface, AttributeTargets.Property | AttributeTargets.Field); + AttributeTargets attributeTargets = AttributeTargets.Property | AttributeTargets.Field; + Console.WriteLine("{0} $$$ {1}", AttributeTargets.Interface, attributeTargets); + } + } +} diff --git a/ICSharpCode.Decompiler/Tests/CustomAttributes.cs b/ICSharpCode.Decompiler/Tests/CustomAttributes.cs deleted file mode 100644 index 11258a42e..000000000 --- a/ICSharpCode.Decompiler/Tests/CustomAttributes.cs +++ /dev/null @@ -1,27 +0,0 @@ -// 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) - -using System; - - -public static class CustomAtributes -{ - [Flags] - public enum EnumWithFlag - { -// Item1, - Item2 - } - [AttributeUsage(AttributeTargets.All)] - public class MyAttribute : Attribute - { - } - [Obsolete("some message")] - public static void ObsoletedMethod() - { - //Console.WriteLine("{0} $$$ {1}", AttributeTargets.Interface, (AttributeTargets)(AttributeTargets.Property | AttributeTargets.Field)); - Console.WriteLine("{0} $$$ {1}", AttributeTargets.Interface, AttributeTargets.Property | AttributeTargets.Field); - AttributeTargets attributeTargets = AttributeTargets.Property | AttributeTargets.Field; - Console.WriteLine("{0} $$$ {1}", AttributeTargets.Interface, attributeTargets); - } -} diff --git a/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeSamples.cs b/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeSamples.cs new file mode 100644 index 000000000..e92a50f59 --- /dev/null +++ b/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeSamples.cs @@ -0,0 +1,81 @@ +// 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) + +//$CS +using System; +//$CE + +//$$ ParameterlessAttributeUsage +namespace ParameterLessAttributeUsage +{ + [Flags] + public enum EnumWithFlagsAttribute + { + None + } +} +//$$ AttributeWithEnumArgument +namespace AttributeWithEnumArgument +{ + [AttributeUsage(AttributeTargets.All)] + public class MyAttributeAttribute : Attribute + { + } +} +//$$ AttributeWithEnumExpressionArgument +namespace AttributeWithEnumExpressionArgument +{ + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Interface)] + public class MyAttributeAttribute : Attribute + { + } +} +//$$ AttributeWithStringExpressionArgument +namespace AttributeWithStringExpressionArgument +{ + [Obsolete("message")] + public class ObsoletedClass + { + } +} +//$$ AttributeAppliedToEvent (ignored) +namespace AttributeAppliedToEvent +{ + [AttributeUsage(AttributeTargets.Event)] + public class MyAttributeAttribute : Attribute + { + } + public class TestClass + { + [MyAttribute] + public event EventHandler MyEvent; + } +} +//$$ AttributeAppliedToField +namespace AttributeAppliedToField +{ + [AttributeUsage(AttributeTargets.Field)] + public class MyAttributeAttribute : Attribute + { + } + public class TestClass + { + [MyAttribute] + public int Field; + } +} +//$$ AttributeAppliedToMethod +namespace AttributeAppliedToMethod +{ + [AttributeUsage(AttributeTargets.Method)] + public class MyAttributeAttribute : Attribute + { + } + public class TestClass + { + [MyAttribute] + public void Method() + { + } + } +} diff --git a/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeTests.cs b/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeTests.cs new file mode 100644 index 000000000..70ff0f799 --- /dev/null +++ b/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeTests.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using MbUnit.Framework; + +namespace ICSharpCode.Decompiler.Tests.CustomAttributes +{ + public class CustomAttributeTests : DecompilerTestBase + { + [StaticTestFactory] + public static IEnumerable CustomAttributeSamples() + { + return GenerateSectionTests(@"CustomAttributes\CustomAttributeSamples.cs"); + } + + [Test] + public void CustomAttributesMultiTest() + { + ValidateFileRoundtrip(@"CustomAttributes\CustomAttributes.cs"); + } + } +} diff --git a/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributes.cs b/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributes.cs new file mode 100644 index 000000000..7baaf2982 --- /dev/null +++ b/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributes.cs @@ -0,0 +1,47 @@ +// 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) + +using System; + + +namespace aa +{ + public static class CustomAtributes + { + [Flags] + public enum EnumWithFlag + { + All = 15, + None = 0, + Item1 = 1, + Item2 = 2, + Item3 = 4, + Item4 = 8 + } + [AttributeUsage(AttributeTargets.All)] + public class MyAttribute : Attribute + { + public MyAttribute(CustomAtributes.EnumWithFlag en) + { + } + } + [CustomAtributes.MyAttribute(CustomAtributes.EnumWithFlag.Item1 | CustomAtributes.EnumWithFlag.Item2)] + private static int field; + [CustomAtributes.MyAttribute(CustomAtributes.EnumWithFlag.All)] + public static string Property + { + get + { + return "aa"; + } + } + [Obsolete("some message")] + public static void ObsoletedMethod() + { + //Console.WriteLine("{0} $$$ {1}", AttributeTargets.Interface, (AttributeTargets)(AttributeTargets.Property | AttributeTargets.Field)); + Console.WriteLine("{0} $$$ {1}", AttributeTargets.Interface, AttributeTargets.Property | AttributeTargets.Field); + AttributeTargets attributeTargets = AttributeTargets.Property | AttributeTargets.Field; + Console.WriteLine("{0} $$$ {1}", AttributeTargets.Interface, attributeTargets); + } + } +} \ No newline at end of file diff --git a/ICSharpCode.Decompiler/Tests/DecompilerTestBase.cs b/ICSharpCode.Decompiler/Tests/DecompilerTestBase.cs new file mode 100644 index 000000000..b27cccf46 --- /dev/null +++ b/ICSharpCode.Decompiler/Tests/DecompilerTestBase.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Mono.Cecil; +using System.IO; +using Decompiler; +using Microsoft.CSharp; +using System.CodeDom.Compiler; +using MbUnit.Framework; + +namespace ICSharpCode.Decompiler.Tests +{ + public abstract class DecompilerTestBase + { + protected static IEnumerable GenerateSectionTests(string samplesFileName) + { + string code = File.ReadAllText(Path.Combine(@"..\..\Tests", samplesFileName)); + foreach (var sectionName in CodeSampleFileParser.ListSections(code)) + { + if (sectionName.EndsWith("(ignored)", StringComparison.OrdinalIgnoreCase)) + continue; + + var testedSectionName = sectionName; + yield return new TestCase(testedSectionName, () => + { + var testCode = CodeSampleFileParser.GetSection(testedSectionName, code); + System.Diagnostics.Debug.WriteLine(testCode); + var decompiledTestCode = RoundtripCode(testCode); + Assert.AreEqual(testCode, decompiledTestCode); + }); + } + } + + protected static void ValidateFileRoundtrip(string samplesFileName) + { + var lines = File.ReadAllLines(Path.Combine(@"..\..\Tests", samplesFileName)); + var testCode = RemoveIgnorableLines(lines); + var decompiledTestCode = RoundtripCode(testCode); + Assert.AreEqual(testCode, decompiledTestCode); + } + + static string RemoveIgnorableLines(IEnumerable lines) + { + return CodeSampleFileParser.ConcatLines(lines.Where(l => !CodeSampleFileParser.IsCommentOrBlank(l))); + } + + /// + /// Compiles and decompiles a source code. + /// + /// The source code to copile. + /// The decompilation result of compiled source code. + static string RoundtripCode(string code) + { + AssemblyDefinition assembly = Compile(code); + AstBuilder decompiler = new AstBuilder(new DecompilerContext()); + decompiler.AddAssembly(assembly); + StringWriter output = new StringWriter(); + decompiler.GenerateCode(new PlainTextOutput(output)); + return output.ToString(); + } + + static AssemblyDefinition Compile(string code) + { + CSharpCodeProvider provider = new CSharpCodeProvider(new Dictionary { { "CompilerVersion", "v4.0" } }); + CompilerParameters options = new CompilerParameters(); + options.ReferencedAssemblies.Add("System.Core.dll"); + CompilerResults results = provider.CompileAssemblyFromSource(options, code); + try + { + if (results.Errors.Count > 0) + { + StringBuilder b = new StringBuilder("Compiler error:"); + foreach (var error in results.Errors) + { + b.AppendLine(error.ToString()); + } + throw new Exception(b.ToString()); + } + return AssemblyDefinition.ReadAssembly(results.PathToAssembly); + } + finally + { + File.Delete(results.PathToAssembly); + results.TempFiles.Delete(); + } + } + } +} diff --git a/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj b/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj index be4061104..1e82a0137 100644 --- a/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj +++ b/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj @@ -56,12 +56,17 @@ - - - - + + + + + + + + + - + @@ -73,5 +78,6 @@ ICSharpCode.Decompiler + \ No newline at end of file diff --git a/ICSharpCode.Decompiler/Tests/TestRunner.cs b/ICSharpCode.Decompiler/Tests/TestRunner.cs index da07307da..d726f91a4 100644 --- a/ICSharpCode.Decompiler/Tests/TestRunner.cs +++ b/ICSharpCode.Decompiler/Tests/TestRunner.cs @@ -22,10 +22,6 @@ namespace ICSharpCode.Decompiler.Tests Console.ReadKey(); } - [Test] - //[Row(@"..\..\Tests\DelegateConstruction.cs")] - //[Row(@"..\..\Tests\Loops.cs")] - [Row(@"..\..\Tests\CustomAttributes.cs")] public void RoundtripFile(string fileName) { string code = File.ReadAllText(fileName); @@ -38,6 +34,9 @@ namespace ICSharpCode.Decompiler.Tests var decompiledCode = output.ToString(); var onlyCode = "using System;" + Environment.NewLine + StripCodeFileHeader(code); + File.WriteAllText(Path.ChangeExtension(fileName, ".decomp.cs"), decompiledCode); + File.WriteAllText(Path.ChangeExtension(fileName, ".code.cs"), onlyCode); + Assert.AreEqual(onlyCode, decompiledCode); } diff --git a/ICSharpCode.Decompiler/Tests/DelegateConstruction.cs b/ICSharpCode.Decompiler/Tests/Types/DelegateConstruction.cs similarity index 100% rename from ICSharpCode.Decompiler/Tests/DelegateConstruction.cs rename to ICSharpCode.Decompiler/Tests/Types/DelegateConstruction.cs diff --git a/ICSharpCode.Decompiler/Tests/PropertiesAndEvents.cs b/ICSharpCode.Decompiler/Tests/Types/PropertiesAndEvents.cs similarity index 100% rename from ICSharpCode.Decompiler/Tests/PropertiesAndEvents.cs rename to ICSharpCode.Decompiler/Tests/Types/PropertiesAndEvents.cs diff --git a/ICSharpCode.Decompiler/Tests/Types/TypeTests.cs b/ICSharpCode.Decompiler/Tests/Types/TypeTests.cs new file mode 100644 index 000000000..fca3ace99 --- /dev/null +++ b/ICSharpCode.Decompiler/Tests/Types/TypeTests.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using MbUnit.Framework; + +namespace ICSharpCode.Decompiler.Tests.Types +{ + public class TypeTests : DecompilerTestBase + { + [Test] + public void ValueTypes() + { + ValidateFileRoundtrip(@"Types\ValueTypes.cs"); + } + + [Test] + public void PropertiesAndEvents() + { + ValidateFileRoundtrip(@"Types\PropertiesAndEvents.cs"); + } + + [Test] + public void DelegateConstruction() + { + ValidateFileRoundtrip(@"Types\DelegateConstruction.cs"); + } + } +} diff --git a/ICSharpCode.Decompiler/Tests/ValueTypes.cs b/ICSharpCode.Decompiler/Tests/Types/ValueTypes.cs similarity index 100% rename from ICSharpCode.Decompiler/Tests/ValueTypes.cs rename to ICSharpCode.Decompiler/Tests/Types/ValueTypes.cs From 464acf02eaf1f7fc57f89300e07af9a53eecf87a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Artur=20Zgodzi=C5=84ski?= Date: Thu, 24 Feb 2011 20:35:28 +0100 Subject: [PATCH 07/30] fixed printing of enum values that cannot be mapped to enum named constants. --- ICSharpCode.Decompiler/Ast/AstBuilder.cs | 17 ++++++-- .../Tests/ICSharpCode.Decompiler.Tests.csproj | 2 + .../Tests/Types/EnumSamples.cs | 39 +++++++++++++++++++ .../Tests/Types/EnumTests.cs | 17 ++++++++ 4 files changed, 71 insertions(+), 4 deletions(-) create mode 100644 ICSharpCode.Decompiler/Tests/Types/EnumSamples.cs create mode 100644 ICSharpCode.Decompiler/Tests/Types/EnumTests.cs diff --git a/ICSharpCode.Decompiler/Ast/AstBuilder.cs b/ICSharpCode.Decompiler/Ast/AstBuilder.cs index 5bdefecc4..4ba5042bb 100644 --- a/ICSharpCode.Decompiler/Ast/AstBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstBuilder.cs @@ -515,6 +515,7 @@ namespace Decompiler Body = AstMethodBodyBuilder.CreateMethodBody(propDef.SetMethod, context) }.WithAnnotation(propDef.SetMethod); } + ConvertCustomAtributes(astProp, propDef); return astProp; } @@ -552,6 +553,7 @@ namespace Decompiler else initializer.Initializer = new PrimitiveExpression(fieldDef.Constant); } + ConvertCustomAtributes(astField, fieldDef); return astField; } @@ -619,12 +621,13 @@ namespace Decompiler foreach (FieldDefinition field in enumDefinition.Fields) { if (field.IsStatic && object.Equals(CSharpPrimitiveCast.Cast(TypeCode.Int64, field.Constant, false), val)) - return AstBuilder.ConvertType(enumDefinition).Member(field.Name).WithAnnotation(field); + return ConvertType(enumDefinition).Member(field.Name).WithAnnotation(field); else if (!field.IsStatic && field.IsRuntimeSpecialName) type = field.FieldType; // use primitive type of the enum } if (IsFlagsEnum(enumDefinition)) { + long enumValue = val; Expression expr = null; foreach (FieldDefinition field in enumDefinition.Fields.Where(fld => fld.IsStatic)) { @@ -632,18 +635,24 @@ namespace Decompiler if (fieldValue == 0) continue; // skip None enum value - if ((fieldValue & val) == fieldValue) + if ((fieldValue & enumValue) == fieldValue) { - var fieldExpression = AstBuilder.ConvertType(enumDefinition).Member(field.Name).WithAnnotation(field); + var fieldExpression = ConvertType(enumDefinition).Member(field.Name).WithAnnotation(field); if (expr == null) expr = fieldExpression; else expr = new BinaryOperatorExpression(expr, BinaryOperatorType.BitwiseOr, fieldExpression); + + enumValue &= ~fieldValue; + if (enumValue == 0) + break; } } - if (expr != null) + if(enumValue == 0 && expr != null) return expr; } + TypeCode enumBaseTypeCode = TypeAnalysis.GetTypeCode(type); + return new Ast.PrimitiveExpression(CSharpPrimitiveCast.Cast(enumBaseTypeCode, val, false)).CastTo(ConvertType(enumDefinition)); } } TypeCode code = TypeAnalysis.GetTypeCode(type); diff --git a/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj b/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj index 1e82a0137..bae7fefe6 100644 --- a/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj +++ b/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj @@ -56,6 +56,8 @@ + + diff --git a/ICSharpCode.Decompiler/Tests/Types/EnumSamples.cs b/ICSharpCode.Decompiler/Tests/Types/EnumSamples.cs new file mode 100644 index 000000000..b1cc54128 --- /dev/null +++ b/ICSharpCode.Decompiler/Tests/Types/EnumSamples.cs @@ -0,0 +1,39 @@ +// 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) + +//$CS +using System; +//$CE + +//$$ SingleValue +public class TS_SingleValue +{ + public AttributeTargets Method() + { + return AttributeTargets.Class; + } +} +//$$ TwoValuesOr +public class TS_TwoValuesOr +{ + public AttributeTargets Method() + { + return AttributeTargets.Class | AttributeTargets.Method; + } +} +//$$ ThreeValuesOr +public class TS_ThreeValuesOr +{ + public AttributeTargets Method() + { + return AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Parameter; + } +} +//$$ UnknownNumericValue +public class TS_UnknownNumericValue +{ + public AttributeTargets Method() + { + return (AttributeTargets)1000000; + } +} diff --git a/ICSharpCode.Decompiler/Tests/Types/EnumTests.cs b/ICSharpCode.Decompiler/Tests/Types/EnumTests.cs new file mode 100644 index 000000000..b4234f623 --- /dev/null +++ b/ICSharpCode.Decompiler/Tests/Types/EnumTests.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using MbUnit.Framework; + +namespace ICSharpCode.Decompiler.Tests.Types +{ + public class EnumTests : DecompilerTestBase + { + [StaticTestFactory] + public static IEnumerable EnumSamples() + { + return GenerateSectionTests(@"Types\EnumSamples.cs"); + } + } +} From fde3c114ec13e318fcef8cd69f531c1a816d730a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Artur=20Zgodzi=C5=84ski?= Date: Thu, 24 Feb 2011 22:28:37 +0100 Subject: [PATCH 08/30] Printing initializers of enum members. --- ICSharpCode.Decompiler/Ast/AstBuilder.cs | 6 ++ .../Tests/Types/EnumSamples.cs | 65 +++++++++++++++++++ .../CSharp/OutputVisitor/OutputVisitor.cs | 7 +- 3 files changed, 75 insertions(+), 3 deletions(-) diff --git a/ICSharpCode.Decompiler/Ast/AstBuilder.cs b/ICSharpCode.Decompiler/Ast/AstBuilder.cs index e87322481..66508ddff 100644 --- a/ICSharpCode.Decompiler/Ast/AstBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstBuilder.cs @@ -161,6 +161,7 @@ namespace Decompiler if (typeDef.IsEnum) { + long expectedEnumMemberValue = 0; foreach (FieldDefinition field in typeDef.Fields) { if (field.IsRuntimeSpecialName) { // the value__ field @@ -168,6 +169,11 @@ namespace Decompiler } else { EnumMemberDeclaration enumMember = new EnumMemberDeclaration(); enumMember.Name = CleanName(field.Name); + long memberValue = (long)CSharpPrimitiveCast.Cast(TypeCode.Int64, field.Constant, false); + if (memberValue != expectedEnumMemberValue) { + enumMember.AddChild(new PrimitiveExpression(field.Constant), EnumMemberDeclaration.InitializerRole); + } + expectedEnumMemberValue = memberValue + 1; astType.AddChild(enumMember, TypeDeclaration.MemberRole); } } diff --git a/ICSharpCode.Decompiler/Tests/Types/EnumSamples.cs b/ICSharpCode.Decompiler/Tests/Types/EnumSamples.cs index b1cc54128..4d08d8a98 100644 --- a/ICSharpCode.Decompiler/Tests/Types/EnumSamples.cs +++ b/ICSharpCode.Decompiler/Tests/Types/EnumSamples.cs @@ -37,3 +37,68 @@ public class TS_UnknownNumericValue return (AttributeTargets)1000000; } } +//$$ AllValue +public class TS_AllValue +{ + public AttributeTargets Method() + { + return AttributeTargets.All; + } +} +//$$ ZeroValue +public class TS_ZeroValue +{ + public AttributeTargets Method() + { + return (AttributeTargets)0; + } +} +//$$ PreservingTypeWhenBoxed +public class TS_PreservingTypeWhenBoxed +{ + public object Method() + { + return AttributeTargets.Delegate; + } +} +//$$ PreservingTypeWhenBoxedTwoEnum +public class TS_PreservingTypeWhenBoxedTwoEnum +{ + public object Method() + { + return AttributeTargets.Class | AttributeTargets.Delegate; + } +} +//$$ DeclarationSimpleEnum +public enum TS_DeclarationSimpleEnum +{ + Item1, + Item2 +} +//$$ DeclarationLongBasedEnum +public enum TS_DeclarationLongBasedEnum : long +{ + Item1, + Item2 +} +//$$ DeclarationLongWithInitializers +public enum TS_DeclarationLongWithInitializers : long +{ + Item1, + Item2 = 20L, + Item3 +} +//$$ DeclarationShortWithInitializers +public enum TS_DeclarationShortWithInitializers : short +{ + Item1, + Item2 = 20, + Item3 +} +//$$ DeclarationByteWithInitializers +public enum TS_DeclarationByteWithInitializers : byte +{ + Item1, + Item2 = 20, + Item3 +} diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs index 4e3111458..ec0ad4b92 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs @@ -146,13 +146,14 @@ namespace ICSharpCode.NRefactory.CSharp /// Writes a comma. /// /// The next node after the comma. - void Comma(AstNode nextNode) + /// When set prevents printing a space after comma. + void Comma(AstNode nextNode, bool noSpacesAfterComma = false) { WriteSpecialsUpToRole(AstNode.Roles.Comma, nextNode); Space(policy.SpacesBeforeComma); formatter.WriteToken(","); lastWritten = LastWritten.Other; - Space(policy.SpacesAfterComma); + Space(!noSpacesAfterComma && policy.SpacesAfterComma); } void WriteCommaSeparatedList(IEnumerable list) @@ -1187,7 +1188,7 @@ namespace ICSharpCode.NRefactory.CSharp if (first) { first = false; } else { - Comma(member); + Comma(member, noSpacesAfterComma: true); NewLine(); } member.AcceptVisitor(this, data); From d8588bde2a9c271dfe7a12681095a1799b3a18fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Artur=20Zgodzi=C5=84ski?= Date: Thu, 24 Feb 2011 22:35:10 +0100 Subject: [PATCH 09/30] forcing printing all initializers of members of Flags enums. --- ICSharpCode.Decompiler/Ast/AstBuilder.cs | 3 ++- ICSharpCode.Decompiler/Tests/Types/EnumSamples.cs | 10 ++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/ICSharpCode.Decompiler/Ast/AstBuilder.cs b/ICSharpCode.Decompiler/Ast/AstBuilder.cs index 66508ddff..341d2974a 100644 --- a/ICSharpCode.Decompiler/Ast/AstBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstBuilder.cs @@ -162,6 +162,7 @@ namespace Decompiler if (typeDef.IsEnum) { long expectedEnumMemberValue = 0; + bool forcePrintingInitializers = IsFlagsEnum(typeDef); foreach (FieldDefinition field in typeDef.Fields) { if (field.IsRuntimeSpecialName) { // the value__ field @@ -170,7 +171,7 @@ namespace Decompiler EnumMemberDeclaration enumMember = new EnumMemberDeclaration(); enumMember.Name = CleanName(field.Name); long memberValue = (long)CSharpPrimitiveCast.Cast(TypeCode.Int64, field.Constant, false); - if (memberValue != expectedEnumMemberValue) { + if (forcePrintingInitializers || memberValue != expectedEnumMemberValue) { enumMember.AddChild(new PrimitiveExpression(field.Constant), EnumMemberDeclaration.InitializerRole); } expectedEnumMemberValue = memberValue + 1; diff --git a/ICSharpCode.Decompiler/Tests/Types/EnumSamples.cs b/ICSharpCode.Decompiler/Tests/Types/EnumSamples.cs index 4d08d8a98..67d81fa30 100644 --- a/ICSharpCode.Decompiler/Tests/Types/EnumSamples.cs +++ b/ICSharpCode.Decompiler/Tests/Types/EnumSamples.cs @@ -102,3 +102,13 @@ public enum TS_DeclarationByteWithInitializers : byte Item2 = 20, Item3 } +//$$ DeclarationFlags +[Flags] +public enum TS_DeclarationFlags +{ + None = 0, + Item1 = 1, + Item2 = 2, + Item3 = 4, + All = 7 +} From 09177affc162fa74369dcb70081879f63cc4846c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Artur=20Zgodzi=C5=84ski?= Date: Fri, 25 Feb 2011 23:50:10 +0100 Subject: [PATCH 10/30] partial support for named arguments in attributes. --- ICSharpCode.Decompiler/Ast/AstBuilder.cs | 31 ++++++++++++------- .../CustomAttributeSamples.cs | 10 +++++- 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/ICSharpCode.Decompiler/Ast/AstBuilder.cs b/ICSharpCode.Decompiler/Ast/AstBuilder.cs index 341d2974a..c1fbc41cf 100644 --- a/ICSharpCode.Decompiler/Ast/AstBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstBuilder.cs @@ -600,21 +600,30 @@ namespace Decompiler attribute.Type = ConvertType(customAttribute.AttributeType); section.Attributes.Add(attribute); - foreach (var parameter in customAttribute.ConstructorArguments) - { - var isEnum = parameter.Type.IsValueType && !parameter.Type.IsPrimitive; - Expression parameterValue; - if (isEnum) + if(customAttribute.HasConstructorArguments) + foreach (var parameter in customAttribute.ConstructorArguments) { - parameterValue = MakePrimitive(Convert.ToInt64(parameter.Value), parameter.Type); + var isEnum = parameter.Type.IsValueType && !parameter.Type.IsPrimitive; + Expression parameterValue; + if (isEnum) + { + parameterValue = MakePrimitive(Convert.ToInt64(parameter.Value), parameter.Type); + } + else + { + parameterValue = new PrimitiveExpression(parameter.Value); + } + attribute.Arguments.Add(parameterValue); } - else + + if (customAttribute.HasProperties) + foreach (var property in customAttribute.Properties) { - parameterValue = new PrimitiveExpression(parameter.Value); + var propertyReference = customAttribute.AttributeType.Resolve().Properties.First(pr => pr.Name == property.Name); + var propertyName = new IdentifierExpression(property.Name).WithAnnotation(propertyReference); + var propertyArgument = new PrimitiveExpression(property.Argument.Value); + attribute.Arguments.Add(new AssignmentExpression(propertyName, propertyArgument)); } - attribute.Arguments.Add(parameterValue); - } - } attributedNode.Attributes.Add(section); diff --git a/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeSamples.cs b/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeSamples.cs index e92a50f59..ef3a8af3f 100644 --- a/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeSamples.cs +++ b/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeSamples.cs @@ -11,7 +11,7 @@ namespace ParameterLessAttributeUsage [Flags] public enum EnumWithFlagsAttribute { - None + None = 0 } } //$$ AttributeWithEnumArgument @@ -79,3 +79,11 @@ namespace AttributeAppliedToMethod } } } +//$$ NamedParameter +namespace NamedParameter +{ + [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] + public class MyAttributeAttribute : Attribute + { + } +} From 9f1eb2b4cdb20bf3406778b5226ac1cebdce344f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Artur=20Zgodzi=C5=84ski?= Date: Sat, 26 Feb 2011 00:21:46 +0100 Subject: [PATCH 11/30] support for type arguments of custom attributes. --- ICSharpCode.Decompiler/Ast/AstBuilder.cs | 7 +++ .../CustomAttributeSamples.cs | 45 +++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/ICSharpCode.Decompiler/Ast/AstBuilder.cs b/ICSharpCode.Decompiler/Ast/AstBuilder.cs index c1fbc41cf..2b3a363dd 100644 --- a/ICSharpCode.Decompiler/Ast/AstBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstBuilder.cs @@ -609,6 +609,13 @@ namespace Decompiler { parameterValue = MakePrimitive(Convert.ToInt64(parameter.Value), parameter.Type); } + else if (parameter.Value is TypeReference) + { + parameterValue = new TypeOfExpression() + { + Type = ConvertType((TypeReference)parameter.Value), + }; + } else { parameterValue = new PrimitiveExpression(parameter.Value); diff --git a/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeSamples.cs b/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeSamples.cs index ef3a8af3f..453328001 100644 --- a/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeSamples.cs +++ b/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeSamples.cs @@ -38,6 +38,22 @@ namespace AttributeWithStringExpressionArgument { } } +//$$ AttributeWithTypeArgument +namespace AttributeWithTypeArgument +{ + [AttributeUsage(AttributeTargets.All)] + public class MyTypeAttribute : Attribute + { + public MyTypeAttribute(Type t) + { + } + } + + [MyType(typeof(Attribute))] + public class SomeClass + { + } +} //$$ AttributeAppliedToEvent (ignored) namespace AttributeAppliedToEvent { @@ -64,6 +80,24 @@ namespace AttributeAppliedToField public int Field; } } +//$$ AttributeAppliedToProperty +namespace AttributeAppliedToProperty +{ + public class TestClass + { + [Obsolete("reason")] + public int Property + { + get + { + return 0; + } + } + } +} +//$$ AttributeAppliedToDelegate +[Obsolete("reason")] +public delegate int AttributeAppliedToDelegate(); //$$ AttributeAppliedToMethod namespace AttributeAppliedToMethod { @@ -79,6 +113,17 @@ namespace AttributeAppliedToMethod } } } +//$$ AttributeAppliedToInterface +[Obsolete("reason")] +public interface AttributeAppliedToInterface +{ +} +//$$ AttributeAppliedToStruct +[Obsolete("reason")] +public struct AttributeAppliedToStruct +{ + public int Field; +} //$$ NamedParameter namespace NamedParameter { From 1df7e5f7775aef22f4c326172c8fdcc1fecd0554 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Artur=20Zgodzi=C5=84ski?= Date: Sat, 26 Feb 2011 00:57:10 +0100 Subject: [PATCH 12/30] corrected printing values of named parameters of attributes. --- ICSharpCode.Decompiler/Ast/AstBuilder.cs | 44 ++++++----- .../CustomAttributeSamples.cs | 73 ++++++++++++++++++- 2 files changed, 96 insertions(+), 21 deletions(-) diff --git a/ICSharpCode.Decompiler/Ast/AstBuilder.cs b/ICSharpCode.Decompiler/Ast/AstBuilder.cs index 2b3a363dd..94473dba2 100644 --- a/ICSharpCode.Decompiler/Ast/AstBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstBuilder.cs @@ -603,23 +603,7 @@ namespace Decompiler if(customAttribute.HasConstructorArguments) foreach (var parameter in customAttribute.ConstructorArguments) { - var isEnum = parameter.Type.IsValueType && !parameter.Type.IsPrimitive; - Expression parameterValue; - if (isEnum) - { - parameterValue = MakePrimitive(Convert.ToInt64(parameter.Value), parameter.Type); - } - else if (parameter.Value is TypeReference) - { - parameterValue = new TypeOfExpression() - { - Type = ConvertType((TypeReference)parameter.Value), - }; - } - else - { - parameterValue = new PrimitiveExpression(parameter.Value); - } + Expression parameterValue = ConvertArgumentValue(parameter); attribute.Arguments.Add(parameterValue); } @@ -628,8 +612,8 @@ namespace Decompiler { var propertyReference = customAttribute.AttributeType.Resolve().Properties.First(pr => pr.Name == property.Name); var propertyName = new IdentifierExpression(property.Name).WithAnnotation(propertyReference); - var propertyArgument = new PrimitiveExpression(property.Argument.Value); - attribute.Arguments.Add(new AssignmentExpression(propertyName, propertyArgument)); + var argumentValue = ConvertArgumentValue(property.Argument); + attribute.Arguments.Add(new AssignmentExpression(propertyName, argumentValue)); } } @@ -637,6 +621,28 @@ namespace Decompiler } } + private static Expression ConvertArgumentValue(CustomAttributeArgument parameter) + { + var type = parameter.Type.Resolve(); + Expression parameterValue; + if (type.IsEnum) + { + parameterValue = MakePrimitive(Convert.ToInt64(parameter.Value), type); + } + else if (parameter.Value is TypeReference) + { + parameterValue = new TypeOfExpression() + { + Type = ConvertType((TypeReference)parameter.Value), + }; + } + else + { + parameterValue = new PrimitiveExpression(parameter.Value); + } + return parameterValue; + } + internal static Expression MakePrimitive(long val, TypeReference type) { diff --git a/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeSamples.cs b/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeSamples.cs index 453328001..af74a2a6a 100644 --- a/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeSamples.cs +++ b/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeSamples.cs @@ -124,11 +124,80 @@ public struct AttributeAppliedToStruct { public int Field; } -//$$ NamedParameter -namespace NamedParameter +//$$ NamedPropertyParameter +namespace NamedPropertyParameter { [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] public class MyAttributeAttribute : Attribute { } } +//$$ NamedStringPropertyParameter +namespace NamedStringPropertyParameter +{ + [AttributeUsage(AttributeTargets.All)] + public class MyAttributeAttribute : Attribute + { + public string Prop + { + get + { + return ""; + } + set + { + return; + } + } + } + [MyAttribute(Prop = "value")] + public class MyClass + { + } +} +//$$ NamedTypePropertyParameter +namespace NamedTypePropertyParameter +{ + [AttributeUsage(AttributeTargets.All)] + public class MyAttributeAttribute : Attribute + { + public Type Prop + { + get + { + return null; + } + set + { + return; + } + } + } + [MyAttribute(Prop = typeof(Enum))] + public class MyClass + { + } +} +//$$ NamedEnumPropertyParameter +namespace NamedEnumPropertyParameter +{ + [AttributeUsage(AttributeTargets.All)] + public class MyAttributeAttribute : Attribute + { + public AttributeTargets Prop + { + get + { + return AttributeTargets.All; + } + set + { + return; + } + } + } + [MyAttribute(Prop = (AttributeTargets.Class | AttributeTargets.Method))] + public class MyClass + { + } +} From 3609dd641aad78f64aad4eea5367a6ebd5ee0b33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Artur=20Zgodzi=C5=84ski?= Date: Sat, 26 Feb 2011 08:07:16 +0100 Subject: [PATCH 13/30] printing of field named arguments in attributes. --- ICSharpCode.Decompiler/Ast/AstBuilder.cs | 17 +++++++++++++---- .../CustomAttributes/CustomAttributeSamples.cs | 13 +++++++++++++ 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/ICSharpCode.Decompiler/Ast/AstBuilder.cs b/ICSharpCode.Decompiler/Ast/AstBuilder.cs index 94473dba2..8be1173f0 100644 --- a/ICSharpCode.Decompiler/Ast/AstBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstBuilder.cs @@ -608,13 +608,22 @@ namespace Decompiler } if (customAttribute.HasProperties) - foreach (var property in customAttribute.Properties) + foreach (var propertyNamedArg in customAttribute.Properties) { - var propertyReference = customAttribute.AttributeType.Resolve().Properties.First(pr => pr.Name == property.Name); - var propertyName = new IdentifierExpression(property.Name).WithAnnotation(propertyReference); - var argumentValue = ConvertArgumentValue(property.Argument); + var propertyReference = customAttribute.AttributeType.Resolve().Properties.First(pr => pr.Name == propertyNamedArg.Name); + var propertyName = new IdentifierExpression(propertyNamedArg.Name).WithAnnotation(propertyReference); + var argumentValue = ConvertArgumentValue(propertyNamedArg.Argument); attribute.Arguments.Add(new AssignmentExpression(propertyName, argumentValue)); } + + if (customAttribute.HasFields) + foreach (var fieldNamedArg in customAttribute.Fields) + { + var fieldReference = customAttribute.AttributeType.Resolve().Fields.First(f => f.Name == fieldNamedArg.Name); + var fieldName = new IdentifierExpression(fieldNamedArg.Name).WithAnnotation(fieldReference); + var argumentValue = ConvertArgumentValue(fieldNamedArg.Argument); + attribute.Arguments.Add(new AssignmentExpression(fieldName, argumentValue)); + } } attributedNode.Attributes.Add(section); diff --git a/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeSamples.cs b/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeSamples.cs index af74a2a6a..1d91f1fe0 100644 --- a/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeSamples.cs +++ b/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeSamples.cs @@ -201,3 +201,16 @@ namespace NamedEnumPropertyParameter { } } +//$$ NamedEnumFieldParameter +namespace NamedEnumFieldParameter +{ + [AttributeUsage(AttributeTargets.All)] + public class MyAttributeAttribute : Attribute + { + public AttributeTargets Field; + } + [MyAttribute(Field = (AttributeTargets.Class | AttributeTargets.Method))] + public class MyClass + { + } +} From 75661da50ed003b453a1d74759f8f1fdfe5311cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Artur=20Zgodzi=C5=84ski?= Date: Sat, 26 Feb 2011 08:50:05 +0100 Subject: [PATCH 14/30] attributed parameter declaration. --- ICSharpCode.Decompiler/Ast/AstBuilder.cs | 1 + .../CustomAttributeSamples.cs | 62 ++++++++++++------- .../Ast/TypeMembers/ParameterDeclaration.cs | 2 +- .../CSharp/OutputVisitor/OutputVisitor.cs | 3 +- 4 files changed, 42 insertions(+), 26 deletions(-) diff --git a/ICSharpCode.Decompiler/Ast/AstBuilder.cs b/ICSharpCode.Decompiler/Ast/AstBuilder.cs index 8be1173f0..d5560eb1a 100644 --- a/ICSharpCode.Decompiler/Ast/AstBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstBuilder.cs @@ -584,6 +584,7 @@ namespace Decompiler } // TODO: params, this + ConvertCustomAtributes(astParam, paramDef); yield return astParam; } } diff --git a/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeSamples.cs b/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeSamples.cs index 1d91f1fe0..85c5b2679 100644 --- a/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeSamples.cs +++ b/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeSamples.cs @@ -54,8 +54,8 @@ namespace AttributeWithTypeArgument { } } -//$$ AttributeAppliedToEvent (ignored) -namespace AttributeAppliedToEvent +//$$ AppliedToEvent +namespace AppliedToEvent { [AttributeUsage(AttributeTargets.Event)] public class MyAttributeAttribute : Attribute @@ -67,8 +67,8 @@ namespace AttributeAppliedToEvent public event EventHandler MyEvent; } } -//$$ AttributeAppliedToField -namespace AttributeAppliedToField +//$$ AppliedToField +namespace AppliedToField { [AttributeUsage(AttributeTargets.Field)] public class MyAttributeAttribute : Attribute @@ -80,8 +80,8 @@ namespace AttributeAppliedToField public int Field; } } -//$$ AttributeAppliedToProperty -namespace AttributeAppliedToProperty +//$$ AppliedToProperty +namespace AppliedToProperty { public class TestClass { @@ -95,11 +95,11 @@ namespace AttributeAppliedToProperty } } } -//$$ AttributeAppliedToDelegate +//$$ AppliedToDelegate [Obsolete("reason")] -public delegate int AttributeAppliedToDelegate(); -//$$ AttributeAppliedToMethod -namespace AttributeAppliedToMethod +public delegate int AppliedToDelegate(); +//$$ AppliedToMethod +namespace AppliedToMethod { [AttributeUsage(AttributeTargets.Method)] public class MyAttributeAttribute : Attribute @@ -113,27 +113,41 @@ namespace AttributeAppliedToMethod } } } -//$$ AttributeAppliedToInterface +//$$ AppliedToInterface [Obsolete("reason")] -public interface AttributeAppliedToInterface +public interface AppliedToInterface { } -//$$ AttributeAppliedToStruct +//$$ AppliedToStruct [Obsolete("reason")] -public struct AttributeAppliedToStruct +public struct AppliedToStruct { public int Field; } -//$$ NamedPropertyParameter -namespace NamedPropertyParameter +//$$ AppliedToParameter +namespace AppliedToParameter +{ + [AttributeUsage(AttributeTargets.Parameter)] + public class MyAttributeAttribute : Attribute + { + } + public class MyClass + { + public void Method([MyAttribute]int val) + { + } + } +} +//$$ NamedInitializerProperty +namespace NamedInitializerProperty { [AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] public class MyAttributeAttribute : Attribute { } } -//$$ NamedStringPropertyParameter -namespace NamedStringPropertyParameter +//$$ NamedInitializerPropertyString +namespace NamedInitializerPropertyString { [AttributeUsage(AttributeTargets.All)] public class MyAttributeAttribute : Attribute @@ -155,8 +169,8 @@ namespace NamedStringPropertyParameter { } } -//$$ NamedTypePropertyParameter -namespace NamedTypePropertyParameter +//$$ NamedInitializerPropertyType +namespace NamedInitializerPropertyType { [AttributeUsage(AttributeTargets.All)] public class MyAttributeAttribute : Attribute @@ -178,8 +192,8 @@ namespace NamedTypePropertyParameter { } } -//$$ NamedEnumPropertyParameter -namespace NamedEnumPropertyParameter +//$$ NamedInitializerPropertyEnum +namespace NamedInitializerPropertyEnum { [AttributeUsage(AttributeTargets.All)] public class MyAttributeAttribute : Attribute @@ -201,8 +215,8 @@ namespace NamedEnumPropertyParameter { } } -//$$ NamedEnumFieldParameter -namespace NamedEnumFieldParameter +//$$ NamedInitializerFieldEnum +namespace NamedInitializerFieldEnum { [AttributeUsage(AttributeTargets.All)] public class MyAttributeAttribute : Attribute diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/ParameterDeclaration.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/ParameterDeclaration.cs index 0334d2a3f..05bd3140e 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/ParameterDeclaration.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/ParameterDeclaration.cs @@ -38,7 +38,7 @@ namespace ICSharpCode.NRefactory.CSharp This } - public class ParameterDeclaration : AstNode + public class ParameterDeclaration : AttributedNode { public static readonly Role AttributeRole = AttributedNode.AttributeRole; public static readonly Role ModifierRole = new Role("Modifier", CSharpTokenNode.Null); diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs index ec0ad4b92..1a7f0e498 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs @@ -1110,7 +1110,8 @@ namespace ICSharpCode.NRefactory.CSharp } WriteCommaSeparatedList(attributeSection.Attributes); WriteToken("]", AstNode.Roles.RBracket); - NewLine(); + if (!(attributeSection.Parent is ParameterDeclaration)) + NewLine(); return EndNode(attributeSection); } From 6b9c2b7462ef1dd10c27859d4c3dd829c1e8d1dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Artur=20Zgodzi=C5=84ski?= Date: Sat, 26 Feb 2011 09:29:07 +0100 Subject: [PATCH 15/30] attribute target: method return --- ICSharpCode.Decompiler/Ast/AstBuilder.cs | 5 +++-- .../CustomAttributes/CustomAttributeSamples.cs | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/ICSharpCode.Decompiler/Ast/AstBuilder.cs b/ICSharpCode.Decompiler/Ast/AstBuilder.cs index d5560eb1a..b072254be 100644 --- a/ICSharpCode.Decompiler/Ast/AstBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstBuilder.cs @@ -480,6 +480,7 @@ namespace Decompiler astMethod.Body = AstMethodBodyBuilder.CreateMethodBody(methodDef, context); } ConvertCustomAtributes(astMethod, methodDef); + ConvertCustomAtributes(astMethod, methodDef.MethodReturnType, AttributeTarget.Return); return astMethod; } @@ -589,12 +590,12 @@ namespace Decompiler } } - static void ConvertCustomAtributes(AttributedNode attributedNode, ICustomAttributeProvider customAttributeProvider) + static void ConvertCustomAtributes(AttributedNode attributedNode, ICustomAttributeProvider customAttributeProvider, AttributeTarget target = AttributeTarget.None) { if (customAttributeProvider.HasCustomAttributes) { var section = new AttributeSection(); - //section.AttributeTarget = target; + section.AttributeTarget = target; foreach (var customAttribute in customAttributeProvider.CustomAttributes) { ICSharpCode.NRefactory.CSharp.Attribute attribute = new ICSharpCode.NRefactory.CSharp.Attribute(); diff --git a/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeSamples.cs b/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeSamples.cs index 85c5b2679..685c87c79 100644 --- a/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeSamples.cs +++ b/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeSamples.cs @@ -228,3 +228,19 @@ namespace NamedInitializerFieldEnum { } } +//$$ TargetReturn +namespace TargetReturn +{ + [AttributeUsage(AttributeTargets.All)] + public class MyAttributeAttribute : Attribute + { + } + public class MyClass + { + [return: MyAttribute] + public int MyMethod() + { + return 5; + } + } +} From 19993ff43bc716452eaf0cb0d8f6ee1470d6b210 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Artur=20Zgodzi=C5=84ski?= Date: Sat, 26 Feb 2011 13:12:19 +0100 Subject: [PATCH 16/30] more attribute targets implemented. --- ICSharpCode.Decompiler/Ast/AstBuilder.cs | 32 ++-- .../AssemblyCustomAttribute.cs | 6 + .../CustomAttributeSamples.cs | 152 ++++++++++++++++++ .../CustomAttributes/CustomAttributeTests.cs | 6 + .../CustomAttributes/CustomAttributes.cs | 1 - .../Tests/DecompilerTestBase.cs | 1 + .../Tests/Helpers/RemoveCompilerAttribute.cs | 31 ++++ .../Tests/ICSharpCode.Decompiler.Tests.csproj | 11 +- ILSpy/CSharpLanguage.cs | 5 +- .../CSharp/Ast/CompilationUnit.cs | 2 +- 10 files changed, 231 insertions(+), 16 deletions(-) create mode 100644 ICSharpCode.Decompiler/Tests/CustomAttributes/AssemblyCustomAttribute.cs create mode 100644 ICSharpCode.Decompiler/Tests/Helpers/RemoveCompilerAttribute.cs diff --git a/ICSharpCode.Decompiler/Ast/AstBuilder.cs b/ICSharpCode.Decompiler/Ast/AstBuilder.cs index b072254be..a3a579fab 100644 --- a/ICSharpCode.Decompiler/Ast/AstBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstBuilder.cs @@ -64,21 +64,25 @@ namespace Decompiler astCompileUnit.AcceptVisitor(new OutputVisitor(outputFormatter, formattingPolicy), null); } - public void AddAssembly(AssemblyDefinition assemblyDefinition) + public void AddAssembly(AssemblyDefinition assemblyDefinition, bool onlyAssemblyLevel = false) { astCompileUnit.AddChild( new UsingDeclaration { Import = new SimpleType("System") }, CompilationUnit.MemberRole); - foreach(TypeDefinition typeDef in assemblyDefinition.MainModule.Types) { - // Skip nested types - they will be added by the parent type - if (typeDef.DeclaringType != null) continue; - // Skip the class - if (typeDef.Name == "") continue; - - AddType(typeDef); - } + ConvertCustomAtributes(astCompileUnit, assemblyDefinition, AttributeTarget.Assembly); + + if(!onlyAssemblyLevel) + foreach (TypeDefinition typeDef in assemblyDefinition.MainModule.Types) + { + // Skip nested types - they will be added by the parent type + if (typeDef.DeclaringType != null) continue; + // Skip the class + if (typeDef.Name == "") continue; + + AddType(typeDef); + } } NamespaceDeclaration GetCodeNamespace(string name) @@ -193,6 +197,11 @@ namespace Decompiler ConvertCustomAtributes(astType, typeDef); return astType; } + + public void Transform(IAstTransform transform) + { + transform.Run(astCompileUnit); + } string CleanName(string name) { @@ -525,11 +534,16 @@ namespace Decompiler astProp.Getter = new Accessor { Body = AstMethodBodyBuilder.CreateMethodBody(propDef.GetMethod, context) }.WithAnnotation(propDef.GetMethod); + ConvertCustomAtributes(astProp.Getter, propDef.GetMethod); + ConvertCustomAtributes(astProp.Getter, propDef.GetMethod.MethodReturnType, AttributeTarget.Return); } if (propDef.SetMethod != null) { astProp.Setter = new Accessor { Body = AstMethodBodyBuilder.CreateMethodBody(propDef.SetMethod, context) }.WithAnnotation(propDef.SetMethod); + ConvertCustomAtributes(astProp.Setter, propDef.SetMethod); + ConvertCustomAtributes(astProp.Setter, propDef.SetMethod.MethodReturnType, AttributeTarget.Return); + ConvertCustomAtributes(astProp.Setter, propDef.SetMethod.Parameters.Last(), AttributeTarget.Param); } ConvertCustomAtributes(astProp, propDef); return astProp; diff --git a/ICSharpCode.Decompiler/Tests/CustomAttributes/AssemblyCustomAttribute.cs b/ICSharpCode.Decompiler/Tests/CustomAttributes/AssemblyCustomAttribute.cs new file mode 100644 index 000000000..9d95a4861 --- /dev/null +++ b/ICSharpCode.Decompiler/Tests/CustomAttributes/AssemblyCustomAttribute.cs @@ -0,0 +1,6 @@ +// 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) + +using System; + +[assembly: CLSCompliant(false)] diff --git a/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeSamples.cs b/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeSamples.cs index 685c87c79..98b4a403b 100644 --- a/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeSamples.cs +++ b/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeSamples.cs @@ -5,6 +5,8 @@ using System; //$CE +//$$ TargetModule (ignored) +//[module: CLSCompliantAttribute(false)] //$$ ParameterlessAttributeUsage namespace ParameterLessAttributeUsage { @@ -95,6 +97,48 @@ namespace AppliedToProperty } } } +//$$ AppliedToPropertyGet +namespace AppliedToPropertyGet +{ + [AttributeUsage(AttributeTargets.All)] + public class MyAttributeAttribute : Attribute + { + } + public class TestClass + { + public int Property + { + [MyAttribute] + get + { + return 0; + } + } + } +} +//$$ AppliedToPropertySet +namespace AppliedToPropertySet +{ + [AttributeUsage(AttributeTargets.All)] + public class MyAttributeAttribute : Attribute + { + } + public class TestClass + { + public int Property + { + get + { + return 3; + } + [MyAttribute] + set + { + return; + } + } + } +} //$$ AppliedToDelegate [Obsolete("reason")] public delegate int AppliedToDelegate(); @@ -244,3 +288,111 @@ namespace TargetReturn } } } +//$$ TargetPropertyGetReturn +namespace TargetPropertyGetReturn +{ + [AttributeUsage(AttributeTargets.All)] + public class MyAttributeAttribute : Attribute + { + } + public class MyClass + { + public int Prop + { + [return: MyAttribute] + get + { + return 3; + } + } + } +} +//$$ TargetPropertySetParam +namespace TargetPropertySetParam +{ + [AttributeUsage(AttributeTargets.All)] + public class MyAttributeAttribute : Attribute + { + } + public class MyClass + { + public int Prop + { + [param: MyAttribute] + set + { + return; + } + } + } +} +//$$ TargetPropertySetReturn +namespace TargetPropertySetReturn +{ + [AttributeUsage(AttributeTargets.All)] + public class MyAttributeAttribute : Attribute + { + } + public class MyClass + { + public int Prop + { + get + { + return 3; + } + [return: MyAttribute] + set + { + return; + } + } + } +} +//$$ TargetPropertyIndexSetParam +namespace TargetPropertyIndexSetParam +{ + [AttributeUsage(AttributeTargets.All)] + public class MyAttributeAttribute : Attribute + { + } + public class MyClass + { + public string this[int index] + { + get + { + return ""; + } + [param: MyAttribute] + set + { + return; + } + } + } +} +//$$ TargetPropertyIndexSetMultiParam +namespace TargetPropertyIndexSetMultiParam +{ + [AttributeUsage(AttributeTargets.All)] + public class MyAttributeAttribute : Attribute + { + public int Field; + } + public class MyClass + { + public string this[[MyAttribute(Field = 2)]int index1, [MyAttribute(Field = 3)]int index2] + { + get + { + return ""; + } + [param: MyAttribute] + set + { + return; + } + } + } +} diff --git a/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeTests.cs b/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeTests.cs index 70ff0f799..d453e484f 100644 --- a/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeTests.cs +++ b/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeTests.cs @@ -19,5 +19,11 @@ namespace ICSharpCode.Decompiler.Tests.CustomAttributes { ValidateFileRoundtrip(@"CustomAttributes\CustomAttributes.cs"); } + + [Test] + public void AssemblyCustomAttributesMultiTest() + { + ValidateFileRoundtrip(@"CustomAttributes\AssemblyCustomAttribute.cs"); + } } } diff --git a/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributes.cs b/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributes.cs index 7baaf2982..bfaf57c8a 100644 --- a/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributes.cs +++ b/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributes.cs @@ -3,7 +3,6 @@ using System; - namespace aa { public static class CustomAtributes diff --git a/ICSharpCode.Decompiler/Tests/DecompilerTestBase.cs b/ICSharpCode.Decompiler/Tests/DecompilerTestBase.cs index b27cccf46..db4368cb7 100644 --- a/ICSharpCode.Decompiler/Tests/DecompilerTestBase.cs +++ b/ICSharpCode.Decompiler/Tests/DecompilerTestBase.cs @@ -55,6 +55,7 @@ namespace ICSharpCode.Decompiler.Tests AssemblyDefinition assembly = Compile(code); AstBuilder decompiler = new AstBuilder(new DecompilerContext()); decompiler.AddAssembly(assembly); + decompiler.Transform(new Helpers.RemoveCompilerAttribute()); StringWriter output = new StringWriter(); decompiler.GenerateCode(new PlainTextOutput(output)); return output.ToString(); diff --git a/ICSharpCode.Decompiler/Tests/Helpers/RemoveCompilerAttribute.cs b/ICSharpCode.Decompiler/Tests/Helpers/RemoveCompilerAttribute.cs new file mode 100644 index 000000000..8b364268e --- /dev/null +++ b/ICSharpCode.Decompiler/Tests/Helpers/RemoveCompilerAttribute.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using ICSharpCode.NRefactory.CSharp; +using Decompiler.Transforms; + +namespace ICSharpCode.Decompiler.Tests.Helpers +{ + class RemoveCompilerAttribute : DepthFirstAstVisitor, IAstTransform + { + public override object VisitAttribute(NRefactory.CSharp.Attribute attribute, object data) + { + var section = (AttributeSection)attribute.Parent; + SimpleType type = attribute.Type as SimpleType; + if (section.AttributeTarget == AttributeTarget.Assembly && + (type.Identifier == "CompilationRelaxationsAttribute" || type.Identifier == "RuntimeCompatibilityAttribute")) + { + attribute.Remove(); + if (section.Attributes.Count == 0) + section.Remove(); + } + return null; + } + + public void Run(AstNode node) + { + node.AcceptVisitor(this, null); + } + } +} diff --git a/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj b/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj index 70e05f043..af8673d30 100644 --- a/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj +++ b/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj @@ -57,6 +57,8 @@ + + @@ -70,7 +72,6 @@ - @@ -79,14 +80,16 @@ {D68133BD-1E63-496E-9EDE-4FBDBF77B486} Mono.Cecil + + {3B2A5653-EC97-4001-BB9B-D90F1AF2C371} + ICSharpCode.NRefactory + {984CC812-9470-4A13-AFF9-CC44068D666C} ICSharpCode.Decompiler - - - + diff --git a/ILSpy/CSharpLanguage.cs b/ILSpy/CSharpLanguage.cs index 7ff152475..6ca6f267f 100644 --- a/ILSpy/CSharpLanguage.cs +++ b/ILSpy/CSharpLanguage.cs @@ -132,6 +132,9 @@ namespace ICSharpCode.ILSpy } } else { base.DecompileAssembly(assembly, fileName, output, options); + AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: null); + codeDomBuilder.AddAssembly(assembly, onlyAssemblyLevel: true); + codeDomBuilder.GenerateCode(output, transformAbortCondition); } } @@ -375,7 +378,7 @@ namespace ICSharpCode.ILSpy CurrentType = currentType }); } - + public override string TypeToString(TypeReference type, bool includeNamespace, ICustomAttributeProvider typeAttributes) { AstType astType = AstBuilder.ConvertType(type, typeAttributes); diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/CompilationUnit.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/CompilationUnit.cs index 9a5047719..1b97a4cd0 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/CompilationUnit.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/CompilationUnit.cs @@ -28,7 +28,7 @@ using System.Collections.Generic; namespace ICSharpCode.NRefactory.CSharp { - public class CompilationUnit : AstNode + public class CompilationUnit : AttributedNode { public static readonly Role MemberRole = new Role("Member", AstNode.Null); From 8b1be87732281a02eb668c62b3f68bcad86d4085 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Artur=20Zgodzi=C5=84ski?= Date: Sat, 26 Feb 2011 14:52:00 +0100 Subject: [PATCH 17/30] changed version of referenced gallio and mbunit libraries. --- .../Tests/ICSharpCode.Decompiler.Tests.csproj | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj b/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj index 78c202773..51344082d 100644 --- a/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj +++ b/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj @@ -38,13 +38,11 @@ TRACE - + False - ..\..\libs\Gallio.dll - + False - ..\..\libs\MbUnit.dll From 33290c2a7f653443f1891bc1a3cc8b8c3d9d25d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Artur=20Zgodzi=C5=84ski?= Date: Sat, 26 Feb 2011 17:38:39 +0100 Subject: [PATCH 18/30] renamed files with sample code --- .../Tests/CustomAttributes/CustomAttributeTests.cs | 6 +++--- ...omAttribute.cs => S_AssemblyCustomAttribute.cs} | 0 ...ibuteSamples.cs => S_CustomAttributeSamples.cs} | 0 .../{CustomAttributes.cs => S_CustomAttributes.cs} | 0 .../Tests/ICSharpCode.Decompiler.Tests.csproj | 14 +++++++------- ICSharpCode.Decompiler/Tests/Types/EnumTests.cs | 2 +- ...teConstruction.cs => S_DelegateConstruction.cs} | 0 .../Types/{EnumSamples.cs => S_EnumSamples.cs} | 0 ...ertiesAndEvents.cs => S_PropertiesAndEvents.cs} | 0 .../Tests/Types/{ValueTypes.cs => S_ValueTypes.cs} | 0 ICSharpCode.Decompiler/Tests/Types/TypeTests.cs | 6 +++--- 11 files changed, 14 insertions(+), 14 deletions(-) rename ICSharpCode.Decompiler/Tests/CustomAttributes/{AssemblyCustomAttribute.cs => S_AssemblyCustomAttribute.cs} (100%) rename ICSharpCode.Decompiler/Tests/CustomAttributes/{CustomAttributeSamples.cs => S_CustomAttributeSamples.cs} (100%) rename ICSharpCode.Decompiler/Tests/CustomAttributes/{CustomAttributes.cs => S_CustomAttributes.cs} (100%) rename ICSharpCode.Decompiler/Tests/Types/{DelegateConstruction.cs => S_DelegateConstruction.cs} (100%) rename ICSharpCode.Decompiler/Tests/Types/{EnumSamples.cs => S_EnumSamples.cs} (100%) rename ICSharpCode.Decompiler/Tests/Types/{PropertiesAndEvents.cs => S_PropertiesAndEvents.cs} (100%) rename ICSharpCode.Decompiler/Tests/Types/{ValueTypes.cs => S_ValueTypes.cs} (100%) diff --git a/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeTests.cs b/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeTests.cs index d453e484f..76608c595 100644 --- a/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeTests.cs +++ b/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeTests.cs @@ -11,19 +11,19 @@ namespace ICSharpCode.Decompiler.Tests.CustomAttributes [StaticTestFactory] public static IEnumerable CustomAttributeSamples() { - return GenerateSectionTests(@"CustomAttributes\CustomAttributeSamples.cs"); + return GenerateSectionTests(@"CustomAttributes\S_CustomAttributeSamples.cs"); } [Test] public void CustomAttributesMultiTest() { - ValidateFileRoundtrip(@"CustomAttributes\CustomAttributes.cs"); + ValidateFileRoundtrip(@"CustomAttributes\S_CustomAttributes.cs"); } [Test] public void AssemblyCustomAttributesMultiTest() { - ValidateFileRoundtrip(@"CustomAttributes\AssemblyCustomAttribute.cs"); + ValidateFileRoundtrip(@"CustomAttributes\S_AssemblyCustomAttribute.cs"); } } } diff --git a/ICSharpCode.Decompiler/Tests/CustomAttributes/AssemblyCustomAttribute.cs b/ICSharpCode.Decompiler/Tests/CustomAttributes/S_AssemblyCustomAttribute.cs similarity index 100% rename from ICSharpCode.Decompiler/Tests/CustomAttributes/AssemblyCustomAttribute.cs rename to ICSharpCode.Decompiler/Tests/CustomAttributes/S_AssemblyCustomAttribute.cs diff --git a/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeSamples.cs b/ICSharpCode.Decompiler/Tests/CustomAttributes/S_CustomAttributeSamples.cs similarity index 100% rename from ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeSamples.cs rename to ICSharpCode.Decompiler/Tests/CustomAttributes/S_CustomAttributeSamples.cs diff --git a/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributes.cs b/ICSharpCode.Decompiler/Tests/CustomAttributes/S_CustomAttributes.cs similarity index 100% rename from ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributes.cs rename to ICSharpCode.Decompiler/Tests/CustomAttributes/S_CustomAttributes.cs diff --git a/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj b/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj index 51344082d..146aca67d 100644 --- a/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj +++ b/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj @@ -54,16 +54,16 @@ - - + + - - + + - - + + @@ -72,7 +72,7 @@ - + diff --git a/ICSharpCode.Decompiler/Tests/Types/EnumTests.cs b/ICSharpCode.Decompiler/Tests/Types/EnumTests.cs index b4234f623..07af8968b 100644 --- a/ICSharpCode.Decompiler/Tests/Types/EnumTests.cs +++ b/ICSharpCode.Decompiler/Tests/Types/EnumTests.cs @@ -11,7 +11,7 @@ namespace ICSharpCode.Decompiler.Tests.Types [StaticTestFactory] public static IEnumerable EnumSamples() { - return GenerateSectionTests(@"Types\EnumSamples.cs"); + return GenerateSectionTests(@"Types\S_EnumSamples.cs"); } } } diff --git a/ICSharpCode.Decompiler/Tests/Types/DelegateConstruction.cs b/ICSharpCode.Decompiler/Tests/Types/S_DelegateConstruction.cs similarity index 100% rename from ICSharpCode.Decompiler/Tests/Types/DelegateConstruction.cs rename to ICSharpCode.Decompiler/Tests/Types/S_DelegateConstruction.cs diff --git a/ICSharpCode.Decompiler/Tests/Types/EnumSamples.cs b/ICSharpCode.Decompiler/Tests/Types/S_EnumSamples.cs similarity index 100% rename from ICSharpCode.Decompiler/Tests/Types/EnumSamples.cs rename to ICSharpCode.Decompiler/Tests/Types/S_EnumSamples.cs diff --git a/ICSharpCode.Decompiler/Tests/Types/PropertiesAndEvents.cs b/ICSharpCode.Decompiler/Tests/Types/S_PropertiesAndEvents.cs similarity index 100% rename from ICSharpCode.Decompiler/Tests/Types/PropertiesAndEvents.cs rename to ICSharpCode.Decompiler/Tests/Types/S_PropertiesAndEvents.cs diff --git a/ICSharpCode.Decompiler/Tests/Types/ValueTypes.cs b/ICSharpCode.Decompiler/Tests/Types/S_ValueTypes.cs similarity index 100% rename from ICSharpCode.Decompiler/Tests/Types/ValueTypes.cs rename to ICSharpCode.Decompiler/Tests/Types/S_ValueTypes.cs diff --git a/ICSharpCode.Decompiler/Tests/Types/TypeTests.cs b/ICSharpCode.Decompiler/Tests/Types/TypeTests.cs index fca3ace99..3875edd1c 100644 --- a/ICSharpCode.Decompiler/Tests/Types/TypeTests.cs +++ b/ICSharpCode.Decompiler/Tests/Types/TypeTests.cs @@ -11,19 +11,19 @@ namespace ICSharpCode.Decompiler.Tests.Types [Test] public void ValueTypes() { - ValidateFileRoundtrip(@"Types\ValueTypes.cs"); + ValidateFileRoundtrip(@"Types\S_ValueTypes.cs"); } [Test] public void PropertiesAndEvents() { - ValidateFileRoundtrip(@"Types\PropertiesAndEvents.cs"); + ValidateFileRoundtrip(@"Types\S_PropertiesAndEvents.cs"); } [Test] public void DelegateConstruction() { - ValidateFileRoundtrip(@"Types\DelegateConstruction.cs"); + ValidateFileRoundtrip(@"Types\S_DelegateConstruction.cs"); } } } From e8c25366067c0181dd124638a0e1c096291e2288 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Artur=20Zgodzi=C5=84ski?= Date: Sat, 26 Feb 2011 18:32:42 +0100 Subject: [PATCH 19/30] BugFix: incorrectly removed empty constructors with parameters --- .../Ast/Transforms/ConvertConstructorCallIntoInitializer.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/ICSharpCode.Decompiler/Ast/Transforms/ConvertConstructorCallIntoInitializer.cs b/ICSharpCode.Decompiler/Ast/Transforms/ConvertConstructorCallIntoInitializer.cs index 4ffa69c9c..ee2225073 100644 --- a/ICSharpCode.Decompiler/Ast/Transforms/ConvertConstructorCallIntoInitializer.cs +++ b/ICSharpCode.Decompiler/Ast/Transforms/ConvertConstructorCallIntoInitializer.cs @@ -48,6 +48,7 @@ namespace Decompiler.Transforms if (ctors.Length == 1 && ctors[0].Body.Children.Count() == 0 && ctors[0].Initializer.ConstructorInitializerType == ConstructorInitializerType.Base && ctors[0].Initializer.Arguments.Count() == 0 + && ctors[0].Parameters.Count == 0 && ctors[0].Modifiers == ((typeDeclaration.Modifiers & Modifiers.Abstract) == Modifiers.Abstract ? Modifiers.Protected : Modifiers.Public)) { ctors[0].Remove(); From cd200fa5046255ed0794eae360f2db6da6c4e424 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Artur=20Zgodzi=C5=84ski?= Date: Tue, 1 Mar 2011 18:36:22 +0100 Subject: [PATCH 20/30] Replaced MBUnit with NUnit. --- .../CustomAttributes/CustomAttributeTests.cs | 10 ++-- .../S_CustomAttributeSamples.cs | 2 +- .../Tests/DecompilerTestBase.cs | 21 +------- ...onstruction.cs => DelegateConstruction.cs} | 0 .../Tests/ICSharpCode.Decompiler.Tests.csproj | 13 ++--- ...iesAndEvents.cs => PropertiesAndEvents.cs} | 0 ICSharpCode.Decompiler/Tests/TestRunner.cs | 52 ------------------- .../Tests/Types/EnumTests.cs | 8 +-- .../Tests/Types/TypeTests.cs | 19 +------ .../{Types/S_ValueTypes.cs => ValueTypes.cs} | 0 10 files changed, 17 insertions(+), 108 deletions(-) rename ICSharpCode.Decompiler/Tests/{Types/S_DelegateConstruction.cs => DelegateConstruction.cs} (100%) rename ICSharpCode.Decompiler/Tests/{Types/S_PropertiesAndEvents.cs => PropertiesAndEvents.cs} (100%) rename ICSharpCode.Decompiler/Tests/{Types/S_ValueTypes.cs => ValueTypes.cs} (100%) diff --git a/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeTests.cs b/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeTests.cs index 76608c595..4f040b293 100644 --- a/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeTests.cs +++ b/ICSharpCode.Decompiler/Tests/CustomAttributes/CustomAttributeTests.cs @@ -2,16 +2,16 @@ using System.Collections.Generic; using System.Linq; using System.Text; -using MbUnit.Framework; +using NUnit.Framework; namespace ICSharpCode.Decompiler.Tests.CustomAttributes { public class CustomAttributeTests : DecompilerTestBase { - [StaticTestFactory] - public static IEnumerable CustomAttributeSamples() - { - return GenerateSectionTests(@"CustomAttributes\S_CustomAttributeSamples.cs"); + [Test] + public void CustomAttributeSamples() + { + ValidateFileRoundtrip(@"CustomAttributes\S_CustomAttributeSamples.cs"); } [Test] diff --git a/ICSharpCode.Decompiler/Tests/CustomAttributes/S_CustomAttributeSamples.cs b/ICSharpCode.Decompiler/Tests/CustomAttributes/S_CustomAttributeSamples.cs index 98b4a403b..aa6d4660a 100644 --- a/ICSharpCode.Decompiler/Tests/CustomAttributes/S_CustomAttributeSamples.cs +++ b/ICSharpCode.Decompiler/Tests/CustomAttributes/S_CustomAttributeSamples.cs @@ -46,7 +46,7 @@ namespace AttributeWithTypeArgument [AttributeUsage(AttributeTargets.All)] public class MyTypeAttribute : Attribute { - public MyTypeAttribute(Type t) + public MyTypeAttribute(Type t) : base() { } } diff --git a/ICSharpCode.Decompiler/Tests/DecompilerTestBase.cs b/ICSharpCode.Decompiler/Tests/DecompilerTestBase.cs index db4368cb7..c1a13b925 100644 --- a/ICSharpCode.Decompiler/Tests/DecompilerTestBase.cs +++ b/ICSharpCode.Decompiler/Tests/DecompilerTestBase.cs @@ -7,31 +7,12 @@ using System.IO; using Decompiler; using Microsoft.CSharp; using System.CodeDom.Compiler; -using MbUnit.Framework; +using NUnit.Framework; namespace ICSharpCode.Decompiler.Tests { public abstract class DecompilerTestBase { - protected static IEnumerable GenerateSectionTests(string samplesFileName) - { - string code = File.ReadAllText(Path.Combine(@"..\..\Tests", samplesFileName)); - foreach (var sectionName in CodeSampleFileParser.ListSections(code)) - { - if (sectionName.EndsWith("(ignored)", StringComparison.OrdinalIgnoreCase)) - continue; - - var testedSectionName = sectionName; - yield return new TestCase(testedSectionName, () => - { - var testCode = CodeSampleFileParser.GetSection(testedSectionName, code); - System.Diagnostics.Debug.WriteLine(testCode); - var decompiledTestCode = RoundtripCode(testCode); - Assert.AreEqual(testCode, decompiledTestCode); - }); - } - } - protected static void ValidateFileRoundtrip(string samplesFileName) { var lines = File.ReadAllLines(Path.Combine(@"..\..\Tests", samplesFileName)); diff --git a/ICSharpCode.Decompiler/Tests/Types/S_DelegateConstruction.cs b/ICSharpCode.Decompiler/Tests/DelegateConstruction.cs similarity index 100% rename from ICSharpCode.Decompiler/Tests/Types/S_DelegateConstruction.cs rename to ICSharpCode.Decompiler/Tests/DelegateConstruction.cs diff --git a/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj b/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj index 146aca67d..d7b6f327a 100644 --- a/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj +++ b/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj @@ -38,10 +38,7 @@ TRACE - - False - - + False @@ -59,10 +56,10 @@ - + - - + + @@ -72,7 +69,7 @@ - + diff --git a/ICSharpCode.Decompiler/Tests/Types/S_PropertiesAndEvents.cs b/ICSharpCode.Decompiler/Tests/PropertiesAndEvents.cs similarity index 100% rename from ICSharpCode.Decompiler/Tests/Types/S_PropertiesAndEvents.cs rename to ICSharpCode.Decompiler/Tests/PropertiesAndEvents.cs diff --git a/ICSharpCode.Decompiler/Tests/TestRunner.cs b/ICSharpCode.Decompiler/Tests/TestRunner.cs index d726f91a4..543200603 100644 --- a/ICSharpCode.Decompiler/Tests/TestRunner.cs +++ b/ICSharpCode.Decompiler/Tests/TestRunner.cs @@ -9,7 +9,6 @@ using System.Text; using Decompiler; using Microsoft.CSharp; using Mono.Cecil; -using MbUnit.Framework; namespace ICSharpCode.Decompiler.Tests { @@ -22,24 +21,6 @@ namespace ICSharpCode.Decompiler.Tests Console.ReadKey(); } - public void RoundtripFile(string fileName) - { - string code = File.ReadAllText(fileName); - AssemblyDefinition assembly = Compile(code); - AstBuilder decompiler = new AstBuilder(new DecompilerContext()); - decompiler.AddAssembly(assembly); - StringWriter output = new StringWriter(); - decompiler.GenerateCode(new PlainTextOutput(output)); - - var decompiledCode = output.ToString(); - var onlyCode = "using System;" + Environment.NewLine + StripCodeFileHeader(code); - - File.WriteAllText(Path.ChangeExtension(fileName, ".decomp.cs"), decompiledCode); - File.WriteAllText(Path.ChangeExtension(fileName, ".code.cs"), onlyCode); - - Assert.AreEqual(onlyCode, decompiledCode); - } - static void TestFile(string fileName) { string code = File.ReadAllText(fileName); @@ -55,39 +36,6 @@ namespace ICSharpCode.Decompiler.Tests } } - static string StripCodeFileHeader(string code) - { - var reader = new StringReader(code); - - var buffer = new StringWriter(); - - string line; - var skipBlankLine = false; - while ((line = reader.ReadLine()) != null) - { - if (line.Trim().StartsWith("//")) - { - skipBlankLine = true; - continue; - } - else if (line.StartsWith("using ")) - { - skipBlankLine = true; - continue; - } - else if (skipBlankLine && String.IsNullOrWhiteSpace(line)) - { - continue; - } - - skipBlankLine = false; - - buffer.WriteLine(line); - } - - return buffer.ToString(); - } - static bool Compare(string input1, string input2, StringWriter diff) { bool ok = true; diff --git a/ICSharpCode.Decompiler/Tests/Types/EnumTests.cs b/ICSharpCode.Decompiler/Tests/Types/EnumTests.cs index 07af8968b..b84147082 100644 --- a/ICSharpCode.Decompiler/Tests/Types/EnumTests.cs +++ b/ICSharpCode.Decompiler/Tests/Types/EnumTests.cs @@ -2,16 +2,16 @@ using System.Collections.Generic; using System.Linq; using System.Text; -using MbUnit.Framework; +using NUnit.Framework; namespace ICSharpCode.Decompiler.Tests.Types { public class EnumTests : DecompilerTestBase { - [StaticTestFactory] - public static IEnumerable EnumSamples() + [Test] + public void EnumSamples() { - return GenerateSectionTests(@"Types\S_EnumSamples.cs"); + ValidateFileRoundtrip(@"Types\S_EnumSamples.cs"); } } } diff --git a/ICSharpCode.Decompiler/Tests/Types/TypeTests.cs b/ICSharpCode.Decompiler/Tests/Types/TypeTests.cs index 3875edd1c..56d7db39f 100644 --- a/ICSharpCode.Decompiler/Tests/Types/TypeTests.cs +++ b/ICSharpCode.Decompiler/Tests/Types/TypeTests.cs @@ -2,28 +2,11 @@ using System.Collections.Generic; using System.Linq; using System.Text; -using MbUnit.Framework; +using NUnit.Framework; namespace ICSharpCode.Decompiler.Tests.Types { public class TypeTests : DecompilerTestBase { - [Test] - public void ValueTypes() - { - ValidateFileRoundtrip(@"Types\S_ValueTypes.cs"); - } - - [Test] - public void PropertiesAndEvents() - { - ValidateFileRoundtrip(@"Types\S_PropertiesAndEvents.cs"); - } - - [Test] - public void DelegateConstruction() - { - ValidateFileRoundtrip(@"Types\S_DelegateConstruction.cs"); - } } } diff --git a/ICSharpCode.Decompiler/Tests/Types/S_ValueTypes.cs b/ICSharpCode.Decompiler/Tests/ValueTypes.cs similarity index 100% rename from ICSharpCode.Decompiler/Tests/Types/S_ValueTypes.cs rename to ICSharpCode.Decompiler/Tests/ValueTypes.cs From f25904a47432767797efae10ffa8e1ad285b0ada Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Artur=20Zgodzi=C5=84ski?= Date: Tue, 1 Mar 2011 20:38:53 +0100 Subject: [PATCH 21/30] changed TextRunner to accept test file name. --- .../Tests/CustomAttributes/S_CustomAttributes.cs | 2 +- ICSharpCode.Decompiler/Tests/TestRunner.cs | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/ICSharpCode.Decompiler/Tests/CustomAttributes/S_CustomAttributes.cs b/ICSharpCode.Decompiler/Tests/CustomAttributes/S_CustomAttributes.cs index bfaf57c8a..dbd064eb4 100644 --- a/ICSharpCode.Decompiler/Tests/CustomAttributes/S_CustomAttributes.cs +++ b/ICSharpCode.Decompiler/Tests/CustomAttributes/S_CustomAttributes.cs @@ -20,7 +20,7 @@ namespace aa [AttributeUsage(AttributeTargets.All)] public class MyAttribute : Attribute { - public MyAttribute(CustomAtributes.EnumWithFlag en) + public MyAttribute(CustomAtributes.EnumWithFlag en) : base() { } } diff --git a/ICSharpCode.Decompiler/Tests/TestRunner.cs b/ICSharpCode.Decompiler/Tests/TestRunner.cs index 543200603..71815fffa 100644 --- a/ICSharpCode.Decompiler/Tests/TestRunner.cs +++ b/ICSharpCode.Decompiler/Tests/TestRunner.cs @@ -14,9 +14,12 @@ namespace ICSharpCode.Decompiler.Tests { public class TestRunner { - public static void Main() + public static void Main(string[] args) { - TestFile(@"..\..\Tests\DelegateConstruction.cs"); + if (args.Length == 1) + TestFile(args[0]); + else + TestFile(@"..\..\Tests\DelegateConstruction.cs"); Console.ReadKey(); } @@ -27,6 +30,7 @@ namespace ICSharpCode.Decompiler.Tests AssemblyDefinition assembly = Compile(code); AstBuilder decompiler = new AstBuilder(new DecompilerContext()); decompiler.AddAssembly(assembly); + decompiler.Transform(new Helpers.RemoveCompilerAttribute()); StringWriter output = new StringWriter(); decompiler.GenerateCode(new PlainTextOutput(output)); StringWriter diff = new StringWriter(); From bad6fdabf281fa125e68f141a1dcee675b817a95 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Wed, 2 Mar 2011 23:10:58 +0100 Subject: [PATCH 22/30] For assembly attributes, put each attribute into its own section. --- ICSharpCode.Decompiler/Ast/AstBuilder.cs | 77 ++++++++++++++---------- 1 file changed, 44 insertions(+), 33 deletions(-) diff --git a/ICSharpCode.Decompiler/Ast/AstBuilder.cs b/ICSharpCode.Decompiler/Ast/AstBuilder.cs index 7cdd5ff1e..f16356dba 100644 --- a/ICSharpCode.Decompiler/Ast/AstBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstBuilder.cs @@ -71,9 +71,10 @@ namespace Decompiler Import = new SimpleType("System") }, CompilationUnit.MemberRole); - ConvertCustomAtributes(astCompileUnit, assemblyDefinition, AttributeTarget.Assembly); + ConvertCustomAttributes(astCompileUnit, assemblyDefinition, AttributeTarget.Assembly); + ConvertCustomAttributes(astCompileUnit, assemblyDefinition.MainModule, AttributeTarget.Module); - if(!onlyAssemblyLevel) + if (!onlyAssemblyLevel) { foreach (TypeDefinition typeDef in assemblyDefinition.MainModule.Types) { // Skip nested types - they will be added by the parent type @@ -83,6 +84,7 @@ namespace Decompiler AddType(typeDef); } + } } NamespaceDeclaration GetCodeNamespace(string name) @@ -194,7 +196,7 @@ namespace Decompiler AddTypeMembers(astType, typeDef); } - ConvertCustomAtributes(astType, typeDef); + ConvertCustomAttributes(astType, typeDef); return astType; } @@ -488,8 +490,8 @@ namespace Decompiler astMethod.Modifiers = ConvertModifiers(methodDef); astMethod.Body = AstMethodBodyBuilder.CreateMethodBody(methodDef, context); } - ConvertCustomAtributes(astMethod, methodDef); - ConvertCustomAtributes(astMethod, methodDef.MethodReturnType, AttributeTarget.Return); + ConvertCustomAttributes(astMethod, methodDef); + ConvertCustomAttributes(astMethod, methodDef.MethodReturnType, AttributeTarget.Return); return astMethod; } @@ -534,18 +536,18 @@ namespace Decompiler astProp.Getter = new Accessor { Body = AstMethodBodyBuilder.CreateMethodBody(propDef.GetMethod, context) }.WithAnnotation(propDef.GetMethod); - ConvertCustomAtributes(astProp.Getter, propDef.GetMethod); - ConvertCustomAtributes(astProp.Getter, propDef.GetMethod.MethodReturnType, AttributeTarget.Return); + ConvertCustomAttributes(astProp.Getter, propDef.GetMethod); + ConvertCustomAttributes(astProp.Getter, propDef.GetMethod.MethodReturnType, AttributeTarget.Return); } if (propDef.SetMethod != null) { astProp.Setter = new Accessor { Body = AstMethodBodyBuilder.CreateMethodBody(propDef.SetMethod, context) }.WithAnnotation(propDef.SetMethod); - ConvertCustomAtributes(astProp.Setter, propDef.SetMethod); - ConvertCustomAtributes(astProp.Setter, propDef.SetMethod.MethodReturnType, AttributeTarget.Return); - ConvertCustomAtributes(astProp.Setter, propDef.SetMethod.Parameters.Last(), AttributeTarget.Param); + ConvertCustomAttributes(astProp.Setter, propDef.SetMethod); + ConvertCustomAttributes(astProp.Setter, propDef.SetMethod.MethodReturnType, AttributeTarget.Return); + ConvertCustomAttributes(astProp.Setter, propDef.SetMethod.Parameters.Last(), AttributeTarget.Param); } - ConvertCustomAtributes(astProp, propDef); + ConvertCustomAttributes(astProp, propDef); return astProp; } @@ -583,7 +585,7 @@ namespace Decompiler else initializer.Initializer = new PrimitiveExpression(fieldDef.Constant); } - ConvertCustomAtributes(astField, fieldDef); + ConvertCustomAttributes(astField, fieldDef); return astField; } @@ -599,50 +601,59 @@ namespace Decompiler } // TODO: params, this - ConvertCustomAtributes(astParam, paramDef); + ConvertCustomAttributes(astParam, paramDef); yield return astParam; } } - static void ConvertCustomAtributes(AstNode attributedNode, ICustomAttributeProvider customAttributeProvider, AttributeTarget target = AttributeTarget.None) + static void ConvertCustomAttributes(AstNode attributedNode, ICustomAttributeProvider customAttributeProvider, AttributeTarget target = AttributeTarget.None) { - if (customAttributeProvider.HasCustomAttributes) - { - var section = new AttributeSection(); - section.AttributeTarget = target; - foreach (var customAttribute in customAttributeProvider.CustomAttributes) - { - ICSharpCode.NRefactory.CSharp.Attribute attribute = new ICSharpCode.NRefactory.CSharp.Attribute(); + if (customAttributeProvider.HasCustomAttributes) { + var attributes = new List(); + foreach (var customAttribute in customAttributeProvider.CustomAttributes) { + var attribute = new ICSharpCode.NRefactory.CSharp.Attribute(); attribute.Type = ConvertType(customAttribute.AttributeType); - section.Attributes.Add(attribute); + attributes.Add(attribute); - if(customAttribute.HasConstructorArguments) - foreach (var parameter in customAttribute.ConstructorArguments) - { + if(customAttribute.HasConstructorArguments) { + foreach (var parameter in customAttribute.ConstructorArguments) { Expression parameterValue = ConvertArgumentValue(parameter); attribute.Arguments.Add(parameterValue); } - - if (customAttribute.HasProperties) - foreach (var propertyNamedArg in customAttribute.Properties) - { + } + if (customAttribute.HasProperties) { + foreach (var propertyNamedArg in customAttribute.Properties) { var propertyReference = customAttribute.AttributeType.Resolve().Properties.First(pr => pr.Name == propertyNamedArg.Name); var propertyName = new IdentifierExpression(propertyNamedArg.Name).WithAnnotation(propertyReference); var argumentValue = ConvertArgumentValue(propertyNamedArg.Argument); attribute.Arguments.Add(new AssignmentExpression(propertyName, argumentValue)); } + } - if (customAttribute.HasFields) - foreach (var fieldNamedArg in customAttribute.Fields) - { + if (customAttribute.HasFields) { + foreach (var fieldNamedArg in customAttribute.Fields) { var fieldReference = customAttribute.AttributeType.Resolve().Fields.First(f => f.Name == fieldNamedArg.Name); var fieldName = new IdentifierExpression(fieldNamedArg.Name).WithAnnotation(fieldReference); var argumentValue = ConvertArgumentValue(fieldNamedArg.Argument); attribute.Arguments.Add(new AssignmentExpression(fieldName, argumentValue)); } + } } - attributedNode.AddChild(section, AttributedNode.AttributeRole); + if (target == AttributeTarget.Module || target == AttributeTarget.Assembly) { + // use separate section for each attribute + foreach (var attribute in attributes) { + var section = new AttributeSection(); + section.AttributeTarget = target; + section.Attributes.Add(attribute); + attributedNode.AddChild(section, AttributedNode.AttributeRole); + } + } else { + // use single section for all attributes + var section = new AttributeSection(); + section.AttributeTarget = target; + section.Attributes.AddRange(attributes); + } } } From 368e39bf19d79f0ab01f83a450fdce94e43c2606 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Wed, 2 Mar 2011 23:12:47 +0100 Subject: [PATCH 23/30] Get rid of warnings in release build. --- ILSpy/CSharpLanguage.cs | 2 +- ILSpy/ILAstLanguage.cs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ILSpy/CSharpLanguage.cs b/ILSpy/CSharpLanguage.cs index 6ca6f267f..4c6adbd2f 100644 --- a/ILSpy/CSharpLanguage.cs +++ b/ILSpy/CSharpLanguage.cs @@ -40,7 +40,7 @@ namespace ICSharpCode.ILSpy public class CSharpLanguage : Language { string name = "C#"; - bool showAllMembers; + bool showAllMembers = false; Predicate transformAbortCondition = null; public CSharpLanguage() diff --git a/ILSpy/ILAstLanguage.cs b/ILSpy/ILAstLanguage.cs index 39fcd50c6..8a7ae6f8e 100644 --- a/ILSpy/ILAstLanguage.cs +++ b/ILSpy/ILAstLanguage.cs @@ -30,10 +30,11 @@ using Mono.Cecil; namespace ICSharpCode.ILSpy { + #if DEBUG /// /// Represents the ILAst "language" used for debugging purposes. /// - public class ILAstLanguage : Language + sealed class ILAstLanguage : Language { string name; bool inlineVariables = true; @@ -78,7 +79,6 @@ namespace ICSharpCode.ILSpy } } - #if DEBUG internal static IEnumerable GetDebugLanguages() { yield return new ILAstLanguage { name = "ILAst (unoptimized)", inlineVariables = false }; @@ -89,7 +89,6 @@ namespace ICSharpCode.ILSpy } } - #endif public override string FileExtension { get { @@ -104,4 +103,5 @@ namespace ICSharpCode.ILSpy return output.ToString(); } } + #endif } From b2e20ba41f551a4ce79c7533378d9a48eb6c41da Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Wed, 2 Mar 2011 23:58:44 +0100 Subject: [PATCH 24/30] Fix attributes on classes/methods/etc. --- ICSharpCode.Decompiler/Ast/AstBuilder.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/ICSharpCode.Decompiler/Ast/AstBuilder.cs b/ICSharpCode.Decompiler/Ast/AstBuilder.cs index f16356dba..a0540bd82 100644 --- a/ICSharpCode.Decompiler/Ast/AstBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstBuilder.cs @@ -653,6 +653,7 @@ namespace Decompiler var section = new AttributeSection(); section.AttributeTarget = target; section.Attributes.AddRange(attributes); + attributedNode.AddChild(section, AttributedNode.AttributeRole); } } } From 39fcd7d72f73d386455d00d63446601c99eafb83 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Thu, 3 Mar 2011 00:00:22 +0100 Subject: [PATCH 25/30] Squashed 'NRefactory/' changes from 2200240..a92606c a92606c Some improvements to output visitor. 136fd88 Fix some parser issues. 41b4385 Port NRefactory to .NET 3.5. 3b6fe6f Adjust resolver to AST changes and disable failing unit tests. 93e9d1e Use implicit conversion operator to convert from Pattern to AST nodes. b37ea77 Re-enabled the unit tests that were commented out. defd426 AST bugfixes. 60d4fe9 Add pattern matching for query expressions. Pattern matching should now work for the complete C# AST. b51f5a6 Add pattern matching for MemberDeclarations. git-subtree-dir: NRefactory git-subtree-split: a92606cb97ef6739d59b30a278d017cf64677f88 --- .../CSharp/AstStructureTests.cs | 15 + .../AliasReferenceExpressionTests.cs | 38 ++- .../Parser/Expression/AnonymousMethodTests.cs | 1 + .../ArrayObjectCreateExpressionTests.cs | 52 ++-- .../Parser/Expression/CastExpressionTests.cs | 151 +++++----- .../Expression/DefaultValueExpressionTests.cs | 60 ++-- .../Expression/IdentifierExpressionTests.cs | 28 +- .../Expression/InvocationExpressionTests.cs | 177 ++++++------ .../Parser/Expression/IsExpressionTests.cs | 15 +- .../Expression/LambdaExpressionTests.cs | 117 ++++---- .../MemberReferenceExpressionTests.cs | 97 ++++--- .../PointerReferenceExpressionTests.cs | 18 +- .../Parser/Expression/QueryExpressionTests.cs | 232 +++++++++++---- .../Expression/SizeOfExpressionTests.cs | 4 +- .../Expression/StackAllocExpressionTests.cs | 9 +- .../Expression/TypeOfExpressionTests.cs | 97 ++++--- .../UnaryOperatorExpressionTests.cs | 6 +- .../GeneralScope/DelegateDeclarationTests.cs | 68 ++--- .../GeneralScope/TypeDeclarationTests.cs | 198 +++++++------ .../GeneralScope/UsingDeclarationTests.cs | 2 +- .../CSharp/Parser/ParseUtil.cs | 41 ++- .../Parser/Statements/FixedStatementTests.cs | 15 +- .../Parser/Statements/ForStatementTests.cs | 20 +- .../Statements/TryCatchStatementTests.cs | 56 +++- .../Parser/Statements/YieldStatementTests.cs | 3 +- .../TypeMembers/EventDeclarationTests.cs | 113 ++++---- .../TypeMembers/FieldDeclarationTests.cs | 62 +++- .../TypeMembers/IndexerDeclarationTests.cs | 37 ++- .../TypeMembers/MethodDeclarationTests.cs | 266 ++++++++++-------- .../TypeMembers/OperatorDeclarationTests.cs | 16 +- .../TypeMembers/PropertyDeclarationTests.cs | 10 +- .../CSharp/Resolver/InvocationTests.cs | 2 +- .../CSharp/Resolver/NameLookupTests.cs | 10 +- .../CSharp/Resolver/UnsafeCodeTests.cs | 2 +- .../ICSharpCode.NRefactory.Tests.csproj | 1 + .../ICSharpCode.NRefactory.VB.Tests.csproj | 1 + .../ICSharpCode.NRefactory.VB.csproj | 1 + .../CSharp/Ast/AstLocation.cs | 6 +- ICSharpCode.NRefactory/CSharp/Ast/AstNode.cs | 5 + .../CSharp/Ast/AstNodeCollection.cs | 18 +- ICSharpCode.NRefactory/CSharp/Ast/AstType.cs | 2 +- .../CSharp/Ast/CSharpModifierToken.cs | 6 + .../CSharp/Ast/CSharpTokenNode.cs | 2 +- .../Ast/Expressions/ArrayCreateExpression.cs | 2 +- .../CSharp/Ast/Expressions/QueryExpression.cs | 61 +++- .../Ast/GeneralScope/AttributeSection.cs | 9 + .../CSharp/Ast/GeneralScope/Constraint.cs | 5 +- .../Ast/GeneralScope/DelegateDeclaration.cs | 19 +- .../Ast/GeneralScope/TypeDeclaration.cs | 9 + .../GeneralScope/TypeParameterDeclaration.cs | 7 +- .../CSharp/Ast/Identifier.cs | 7 +- .../CSharp/Ast/MemberType.cs | 2 +- .../CSharp/Ast/PatternMatching/Pattern.cs | 25 +- .../CSharp/Ast/PatternMatching/Placeholder.cs | 68 +++-- .../CSharp/Ast/SimpleType.cs | 2 +- .../CSharp/Ast/Statements/BlockStatement.cs | 2 +- .../CSharp/Ast/Statements/FixedStatement.cs | 2 +- .../CSharp/Ast/TypeMembers/Accessor.cs | 3 +- .../CSharp/Ast/TypeMembers/AttributedNode.cs | 4 +- .../Ast/TypeMembers/ConstructorDeclaration.cs | 14 +- .../Ast/TypeMembers/DestructorDeclaration.cs | 8 +- .../Ast/TypeMembers/EnumMemberDeclaration.cs | 11 +- .../Ast/TypeMembers/EventDeclaration.cs | 25 +- .../Ast/TypeMembers/FieldDeclaration.cs | 22 +- .../Ast/TypeMembers/IndexerDeclaration.cs | 34 ++- .../Ast/TypeMembers/MemberDeclaration.cs | 6 + .../Ast/TypeMembers/MethodDeclaration.cs | 14 +- .../Ast/TypeMembers/OperatorDeclaration.cs | 27 +- .../Ast/TypeMembers/ParameterDeclaration.cs | 14 +- .../Ast/TypeMembers/PropertyDeclaration.cs | 11 +- .../CSharp/OutputVisitor/OutputVisitor.cs | 77 +++-- .../CSharp/Parser/CSharpParser.cs | 46 +-- .../CSharp/Parser/TypeSystemConvertVisitor.cs | 83 +++--- .../CSharp/Resolver/CSharpResolver.cs | 28 +- .../CSharp/Resolver/MemberLookup.cs | 10 +- .../MemberTypeOrNamespaceReference.cs | 2 +- .../CSharp/Resolver/OverloadResolution.cs | 2 +- .../CSharp/Resolver/ResolveVisitor.cs | 49 ++-- .../SimpleTypeOrNamespaceReference.cs | 2 +- .../CSharp/Resolver/TypeInference.cs | 2 +- .../ICSharpCode.NRefactory.csproj | 17 +- .../TypeSystem/CecilLoader.cs | 2 +- .../TypeSystem/ExtensionMethods.cs | 8 +- .../TypeSystem/IAttribute.cs | 4 + .../TypeSystem/IConstantValue.cs | 4 + ICSharpCode.NRefactory/TypeSystem/IEntity.cs | 4 + .../IExplicitInterfaceImplementation.cs | 4 + ICSharpCode.NRefactory/TypeSystem/IField.cs | 4 + .../TypeSystem/IFreezable.cs | 4 + .../TypeSystem/IInterningProvider.cs | 4 + ICSharpCode.NRefactory/TypeSystem/IMember.cs | 4 + ICSharpCode.NRefactory/TypeSystem/IMethod.cs | 11 +- .../TypeSystem/INamedElement.cs | 4 + .../TypeSystem/IParameter.cs | 4 + .../TypeSystem/IParameterizedMember.cs | 4 + .../TypeSystem/IProjectContent.cs | 4 + .../TypeSystem/ISupportsInterning.cs | 4 + ICSharpCode.NRefactory/TypeSystem/IType.cs | 4 + .../TypeSystem/ITypeDefinition.cs | 4 + .../TypeSystem/ITypeParameter.cs | 4 + .../TypeSystem/ITypeReference.cs | 4 + .../TypeSystem/ITypeResolveContext.cs | 4 + .../TypeSystem/IVariable.cs | 4 + .../TypeSystem/Implementation/AbstractType.cs | 4 +- .../Implementation/DefaultParameter.cs | 9 - .../Implementation/DefaultTypeDefinition.cs | 23 +- .../Implementation/SimpleInterningProvider.cs | 24 +- .../Utils/DotNet35Compat.cs | 58 ++++ NRefactory.sln | 8 +- README | 25 +- VBDomGenerator/VBDomGenerator.csproj | 1 + doc/TODO | 33 ++- 112 files changed, 2055 insertions(+), 1038 deletions(-) create mode 100644 ICSharpCode.NRefactory/Utils/DotNet35Compat.cs diff --git a/ICSharpCode.NRefactory.Tests/CSharp/AstStructureTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/AstStructureTests.cs index 16534dd1d..183efacdb 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/AstStructureTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/AstStructureTests.cs @@ -27,5 +27,20 @@ namespace ICSharpCode.NRefactory.CSharp } } } + + [Test] + public void AstNodesDoNotDeriveFromEachOther() + { + // Ast nodes should derive only from abstract classes; not from concrete types. + // For example, we want to avoid that an AST consumer doing "if (node is PropertyDeclaration)" + // unknowingly also handles IndexerDeclarations. + foreach (Type type in typeof(AstNode).Assembly.GetExportedTypes()) { + if (type == typeof(CSharpModifierToken)) // CSharpModifierToken is the exception (though I'm not too happy about that) + continue; + if (type.IsSubclassOf(typeof(AstNode))) { + Assert.IsTrue(type.BaseType.IsAbstract, type.FullName); + } + } + } } } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/AliasReferenceExpressionTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/AliasReferenceExpressionTests.cs index 8b0298e60..41ba8452c 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/AliasReferenceExpressionTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/AliasReferenceExpressionTests.cs @@ -8,27 +8,43 @@ using NUnit.Framework; namespace ICSharpCode.NRefactory.CSharp.Parser.Expression { - [TestFixture] + [TestFixture, Ignore("Aliases not yet implemented")] public class AliasReferenceExpressionTests { - [Test, Ignore] + [Test] public void GlobalReferenceExpressionTest() { CSharpParser parser = new CSharpParser(); - parser.ParseTypeReference(new StringReader("global::System")); - //Assert.IsTrue(tre.TypeReference.IsGlobal); - //Assert.AreEqual("System", tre.TypeReference.Type); - throw new NotImplementedException(); + AstType type = parser.ParseTypeReference(new StringReader("global::System")); + Assert.IsNotNull( + new MemberType { + Target = new SimpleType("global"), + IsDoubleColon = true, + MemberName = "System" + }.Match(type) + ); } - [Test, Ignore] + [Test] public void GlobalTypeDeclaration() { VariableDeclarationStatement lvd = ParseUtilCSharp.ParseStatement("global::System.String a;"); - //TypeReference typeRef = lvd.GetTypeForVariable(0); - //Assert.IsTrue(typeRef.IsGlobal); - //Assert.AreEqual("System.String", typeRef.Type); - throw new NotImplementedException(); + Assert.IsNotNull( + new VariableDeclarationStatement { + Type = new MemberType { + Target = new MemberType { + Target = new SimpleType("global"), + IsDoubleColon = true, + MemberName = "System" + }, + IsDoubleColon = false, + MemberName = "String", + }, + Variables = { + new VariableInitializer("a") + } + }.Match(lvd) + ); } // TODO: add tests for aliases other than 'global' diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/AnonymousMethodTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/AnonymousMethodTests.cs index 90e68d807..a1d4e1a45 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/AnonymousMethodTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/AnonymousMethodTests.cs @@ -47,6 +47,7 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.Expression public void SimpleAnonymousMethod() { AnonymousMethodExpression ame = Parse("delegate(int a, int b) { return a + b; }"); + Assert.IsTrue(ame.HasParameterList); Assert.AreEqual(2, ame.Parameters.Count()); Assert.AreEqual(1, ame.Body.Statements.Count()); Assert.IsTrue(ame.Body.Children.First() is ReturnStatement); diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/ArrayObjectCreateExpressionTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/ArrayObjectCreateExpressionTests.cs index e3173c8cd..fbe1af58e 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/ArrayObjectCreateExpressionTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/ArrayObjectCreateExpressionTests.cs @@ -6,31 +6,51 @@ using NUnit.Framework; namespace ICSharpCode.NRefactory.CSharp.Parser.Expression { - [TestFixture, Ignore("Needs to be ported to new NRefactory")] + [TestFixture] public class ArrayObjectCreateExpressionTests { [Test] public void ArrayCreateExpressionTest1() { - /* - ArrayCreateExpression ace = ParseUtilCSharp.ParseExpression("new int[5]"); - Assert.AreEqual("System.Int32", ace.CreateType.Type); - Assert.IsTrue(ace.CreateType.IsKeyword); - Assert.AreEqual(1, ace.Arguments.Count); - Assert.AreEqual(new int[] {0}, ace.CreateType.RankSpecifier); - */ - throw new NotImplementedException(); + ParseUtilCSharp.AssertExpression( + "new int[5]", + new ArrayCreateExpression { + Type = new PrimitiveType("int"), + Arguments = { new PrimitiveExpression(5) } + }); } - [Test] + [Test, Ignore("AdditionalArraySpecifiers not yet implemented")] + public void MultidimensionalNestedArray() + { + ParseUtilCSharp.AssertExpression( + "new int[5,2][,,][]", + new ArrayCreateExpression { + Type = new PrimitiveType("int"), + Arguments = { new PrimitiveExpression(5), new PrimitiveExpression(2) }, + AdditionalArraySpecifiers = { + new ArraySpecifier(3), + new ArraySpecifier(1) + } + }); + } + + [Test, Ignore("Array initializers not yet implemented")] public void ImplicitlyTypedArrayCreateExpression() { - /* - ArrayCreateExpression ace = ParseUtilCSharp.ParseExpression("new[] { 1, 10, 100, 1000 }"); - Assert.AreEqual("", ace.CreateType.Type); - Assert.AreEqual(0, ace.Arguments.Count); - Assert.AreEqual(4, ace.ArrayInitializer.CreateExpressions.Count);*/ - throw new NotImplementedException(); + ParseUtilCSharp.AssertExpression( + "new[] { 1, 10, 100, 1000 }", + new ArrayCreateExpression { + Initializer = new ArrayInitializerExpression { + Elements = { + new PrimitiveExpression(1), + new PrimitiveExpression(10), + new PrimitiveExpression(100), + new PrimitiveExpression(1000) + } + } + }); + } } } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/CastExpressionTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/CastExpressionTests.cs index 57604d083..54d8d8c8b 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/CastExpressionTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/CastExpressionTests.cs @@ -9,132 +9,157 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.Expression [TestFixture, Ignore("Port unit tests to new DOM")] public class CastExpressionTests { - /* [Test] public void SimpleCastExpression() { - CastExpression ce = ParseUtilCSharp.ParseExpression("(MyObject)o"); - Assert.AreEqual("MyObject", ce.CastTo.Type); - Assert.IsTrue(ce.Expression is IdentifierExpression); - Assert.AreEqual(CastType.Cast, ce.CastType); + ParseUtilCSharp.AssertExpression( + "(MyObject)o", + new CastExpression { + Type = new SimpleType("MyObject"), + Expression = new IdentifierExpression("o") + }); } [Test] public void ArrayCastExpression() { - CastExpression ce = ParseUtilCSharp.ParseExpression("(MyType[])o"); - Assert.AreEqual("MyType", ce.CastTo.Type); - Assert.AreEqual(new int[] { 0 }, ce.CastTo.RankSpecifier); - Assert.IsTrue(ce.Expression is IdentifierExpression); - Assert.AreEqual(CastType.Cast, ce.CastType); + ParseUtilCSharp.AssertExpression( + "(MyType[])o", + new CastExpression { + Type = new SimpleType("MyType").MakeArrayType(1), + Expression = new IdentifierExpression("o") + }); } [Test] public void NullablePrimitiveCastExpression() { - CastExpression ce = ParseUtilCSharp.ParseExpression("(int?)o"); - Assert.AreEqual("System.Nullable", ce.CastTo.Type); - Assert.AreEqual("System.Int32", ce.CastTo.GenericTypes[0].Type); - Assert.IsTrue(ce.Expression is IdentifierExpression); - Assert.AreEqual(CastType.Cast, ce.CastType); + ParseUtilCSharp.AssertExpression( + "(int?)o", + new CastExpression { + Type = new ComposedType { BaseType = new PrimitiveType("int"), HasNullableSpecifier = true }, + Expression = new IdentifierExpression("o") + }); } [Test] public void NullableCastExpression() { - CastExpression ce = ParseUtilCSharp.ParseExpression("(MyType?)o"); - Assert.AreEqual("System.Nullable", ce.CastTo.Type); - Assert.AreEqual("MyType", ce.CastTo.GenericTypes[0].Type); - Assert.IsTrue(ce.Expression is IdentifierExpression); - Assert.AreEqual(CastType.Cast, ce.CastType); + ParseUtilCSharp.AssertExpression( + "(MyType?)o", + new CastExpression { + Type = new ComposedType { BaseType = new SimpleType("MyType"), HasNullableSpecifier = true }, + Expression = new IdentifierExpression("o") + }); } [Test] public void NullableTryCastExpression() { - CastExpression ce = ParseUtilCSharp.ParseExpression("o as int?"); - Assert.AreEqual("System.Nullable", ce.CastTo.Type); - Assert.IsTrue(ce.CastTo.IsKeyword); - Assert.AreEqual("System.Int32", ce.CastTo.GenericTypes[0].Type); - Assert.IsTrue(ce.Expression is IdentifierExpression); - Assert.AreEqual(CastType.TryCast, ce.CastType); + ParseUtilCSharp.AssertExpression( + "o as int?", + new AsExpression { + Type = new ComposedType { BaseType = new PrimitiveType("int"), HasNullableSpecifier = true }, + Expression = new IdentifierExpression("o") + }); } [Test] public void GenericCastExpression() { - CastExpression ce = ParseUtilCSharp.ParseExpression("(List)o"); - Assert.AreEqual("List", ce.CastTo.Type); - Assert.AreEqual("System.String", ce.CastTo.GenericTypes[0].Type); - Assert.IsTrue(ce.Expression is IdentifierExpression); - Assert.AreEqual(CastType.Cast, ce.CastType); + ParseUtilCSharp.AssertExpression( + "(List)o", + new CastExpression { + Type = new SimpleType("List") { TypeArguments = { new PrimitiveType("string") } }, + Expression = new IdentifierExpression("o") + }); } [Test] public void GenericArrayCastExpression() { - CastExpression ce = ParseUtilCSharp.ParseExpression("(List[])o"); - Assert.AreEqual("List", ce.CastTo.Type); - Assert.AreEqual("System.String", ce.CastTo.GenericTypes[0].Type); - Assert.AreEqual(new int[] { 0 }, ce.CastTo.RankSpecifier); - Assert.IsTrue(ce.Expression is IdentifierExpression); - Assert.AreEqual(CastType.Cast, ce.CastType); + ParseUtilCSharp.AssertExpression( + "(List[])o", + new CastExpression { + Type = new ComposedType { + BaseType = new SimpleType("List") { TypeArguments = { new PrimitiveType("string") } }, + ArraySpecifiers = { new ArraySpecifier(1) } + }, + Expression = new IdentifierExpression("o") + }); } [Test] public void GenericArrayAsCastExpression() { - CastExpression ce = ParseUtilCSharp.ParseExpression("o as List[]"); - Assert.AreEqual("List", ce.CastTo.Type); - Assert.AreEqual("System.String", ce.CastTo.GenericTypes[0].Type); - Assert.AreEqual(new int[] { 0 }, ce.CastTo.RankSpecifier); - Assert.IsTrue(ce.Expression is IdentifierExpression); - Assert.AreEqual(CastType.TryCast, ce.CastType); + ParseUtilCSharp.AssertExpression( + "o as List[]", + new AsExpression { + Type = new ComposedType { + BaseType = new SimpleType("List") { TypeArguments = { new PrimitiveType("string") } }, + ArraySpecifiers = { new ArraySpecifier(1) } + }, + Expression = new IdentifierExpression("o") + }); } [Test] public void CastMemberReferenceOnParenthesizedExpression() { - // yes, we really wanted to evaluate .Member on expr and THEN cast the result to MyType - CastExpression ce = ParseUtilCSharp.ParseExpression("(MyType)(expr).Member"); - Assert.AreEqual("MyType", ce.CastTo.Type); - Assert.IsTrue(ce.Expression is MemberReferenceExpression); - Assert.AreEqual(CastType.Cast, ce.CastType); + // yes, we really want to evaluate .Member on expr and THEN cast the result to MyType + ParseUtilCSharp.AssertExpression( + "(MyType)(expr).Member", + new CastExpression { + Type = new SimpleType("MyType"), + Expression = new ParenthesizedExpression { Expression = new IdentifierExpression("expr") }.Member("Member") + }); } [Test] public void TryCastParenthesizedExpression() { - CastExpression ce = ParseUtilCSharp.ParseExpression("(o) as string"); - Assert.AreEqual("System.String", ce.CastTo.ToString()); - Assert.IsTrue(ce.Expression is ParenthesizedExpression); - Assert.AreEqual(CastType.TryCast, ce.CastType); + ParseUtilCSharp.AssertExpression( + "(o) as string", + new AsExpression { + Expression = new ParenthesizedExpression { Expression = new IdentifierExpression("o") }, + Type = new PrimitiveType("string") + }); } [Test] public void CastNegation() { - CastExpression ce = ParseUtilCSharp.ParseExpression("(uint)-negativeValue"); - Assert.AreEqual("System.UInt32", ce.CastTo.ToString()); - Assert.IsTrue(ce.Expression is UnaryOperatorExpression); - Assert.AreEqual(CastType.Cast, ce.CastType); + ParseUtilCSharp.AssertExpression( + "(uint)-negativeValue", + new CastExpression { + Type = new PrimitiveType("uint"), + Expression = new UnaryOperatorExpression( + UnaryOperatorType.Minus, + new IdentifierExpression("negativeValue") + )}); } - */ [Test] public void SubtractionIsNotCast() { - BinaryOperatorExpression boe = ParseUtilCSharp.ParseExpression("(BigInt)-negativeValue"); - Assert.IsTrue(boe.Left is ParenthesizedExpression); - Assert.IsTrue(boe.Right is IdentifierExpression); + ParseUtilCSharp.AssertExpression( + "(BigInt)-negativeValue", + new BinaryOperatorExpression { + Left = new ParenthesizedExpression { Expression = new IdentifierExpression("BigInt") }, + Operator = BinaryOperatorType.Subtract, + Right = new IdentifierExpression("negativeValue") + }); } [Test] public void IntMaxValueToBigInt() { - CastExpression ce = ParseUtilCSharp.ParseExpression("(BigInt)int.MaxValue"); - Assert.AreEqual("BigInt", ce.Type.ToString()); - Assert.IsTrue(ce.Expression is MemberReferenceExpression); + ParseUtilCSharp.AssertExpression( + "(BigInt)int.MaxValue", + new CastExpression { + Type = new SimpleType("BigInt"), + Expression = new PrimitiveExpression("int").Member("MaxValue") + }); } } } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/DefaultValueExpressionTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/DefaultValueExpressionTests.cs index 7419740ff..9c5296920 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/DefaultValueExpressionTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/DefaultValueExpressionTests.cs @@ -6,48 +6,74 @@ using NUnit.Framework; namespace ICSharpCode.NRefactory.CSharp.Parser.Expression { - [TestFixture, Ignore("tests need to be ported")] + [TestFixture, Ignore("Aliases not yet implemented")] public class DefaultValueExpressionTests { [Test] public void SimpleDefaultValue() { DefaultValueExpression toe = ParseUtilCSharp.ParseExpression("default(T)"); - Assert.AreEqual("T", toe.Type); + Assert.AreEqual("T", ((SimpleType)toe.Type).Identifier); } - /* [Test] public void FullQualifiedDefaultValue() { - DefaultValueExpression toe = ParseUtilCSharp.ParseExpression("default(global::MyNamespace.N1.MyType)"); - Assert.IsTrue(toe.TypeReference.IsGlobal); - Assert.AreEqual("MyNamespace.N1.MyType", toe.TypeReference.Type); + ParseUtilCSharp.AssertExpression( + "default(global::MyNamespace.N1.MyType)", + new DefaultValueExpression { + Type = new MemberType { + Target = new MemberType { + Target = new MemberType { + Target = new SimpleType("global"), + IsDoubleColon = true, + MemberName = "MyNamespace" + }, + MemberName = "N1" + }, + MemberName = "MyType" + } + }); } [Test] public void GenericDefaultValue() { - DefaultValueExpression toe = ParseUtilCSharp.ParseExpression("default(MyNamespace.N1.MyType)"); - Assert.AreEqual("MyNamespace.N1.MyType", toe.TypeReference.Type); - Assert.AreEqual("System.String", toe.TypeReference.GenericTypes[0].Type); + ParseUtilCSharp.AssertExpression( + "default(MyNamespace.N1.MyType)", + new DefaultValueExpression { + Type = new MemberType { + Target = new MemberType { + Target = new SimpleType("MyNamespace"), + MemberName = "N1" + }, + MemberName = "MyType", + TypeArguments = { new PrimitiveType("string") } + } + }); } [Test] public void DefaultValueAsIntializer() { - // This test is failing because we need a resolver for the "default:" / "default(" conflict. - LocalVariableDeclaration lvd = ParseUtilCSharp.ParseStatement("T a = default(T);"); - DefaultValueExpression dve = (DefaultValueExpression)lvd.Variables[0].Initializer; - Assert.AreEqual("T", dve.TypeReference.Type); + // This test was problematic (in old NRefactory) because we need a resolver for the "default:" / "default(" conflict. + ParseUtilCSharp.AssertStatement( + "T a = default(T);", + new VariableDeclarationStatement { + Type = new SimpleType("T"), + Variables = { + new VariableInitializer("a", new DefaultValueExpression { Type = new SimpleType("T") }) + }}); } [Test] public void DefaultValueInReturnStatement() { - ReturnStatement rs = ParseUtilCSharp.ParseStatement("return default(T);"); - DefaultValueExpression dve = (DefaultValueExpression)rs.Expression; - Assert.AreEqual("T", dve.TypeReference.Type); - }*/ + ParseUtilCSharp.AssertStatement( + "return default(T);", + new ReturnStatement { + Expression = new DefaultValueExpression { Type = new SimpleType("T") } + }); + } } } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/IdentifierExpressionTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/IdentifierExpressionTests.cs index 6cd54f521..d79658eff 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/IdentifierExpressionTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/IdentifierExpressionTests.cs @@ -39,7 +39,7 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.Expression CheckIdentifier(@"l\U00000065xer", "lexer"); } - [Test] + [Test, Ignore("The @ should not be part of IdentifierExpression.Identifier")] public void TestKeyWordAsIdentifier() { CheckIdentifier("@int", "int"); @@ -51,28 +51,36 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.Expression CheckIdentifier(@"i\u006et", "int"); } - [Test] + [Test, Ignore("The @ should not be part of IdentifierExpression.Identifier")] public void TestKeyWordAsIdentifierStartingWithUnderscore() { CheckIdentifier("@_int", "_int"); } - [Test, Ignore] + [Test] public void GenericMethodReference() { IdentifierExpression ident = ParseUtilCSharp.ParseExpression("M"); - Assert.AreEqual("M", ident.Identifier); - //Assert.AreEqual(1, ident.TypeArguments.Count); - throw new NotImplementedException(); + Assert.IsNotNull( + new IdentifierExpression { + Identifier = "M" , + TypeArguments = { + new PrimitiveType("int") + } + }.Match(ident)); } - [Test, Ignore] + [Test] public void GenericMethodReference2() { IdentifierExpression ident = ParseUtilCSharp.ParseExpression("TargetMethod"); - Assert.AreEqual("TargetMethod", ident.Identifier); - //Assert.AreEqual(1, ident.TypeArguments.Count); - throw new NotImplementedException(); + Assert.IsNotNull( + new IdentifierExpression { + Identifier = "TargetMethod" , + TypeArguments = { + new PrimitiveType("string") + } + }.Match(ident)); } } } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/InvocationExpressionTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/InvocationExpressionTests.cs index f3a39b6fd..73ad17502 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/InvocationExpressionTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/InvocationExpressionTests.cs @@ -7,7 +7,7 @@ using NUnit.Framework; namespace ICSharpCode.NRefactory.CSharp.Parser.Expression { - [TestFixture, Ignore("Port unit tests to new DOM")] + [TestFixture] public class InvocationExpressionTests { [Test] @@ -19,55 +19,71 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.Expression Assert.AreEqual("myMethod", ((IdentifierExpression)ie.Target).Identifier); } - /* TODO port unit tests to new DOM [Test] public void GenericInvocationExpressionTest() { - var expr = ParseUtilCSharp.ParseExpression("myMethod('a')"); - Assert.AreEqual(1, expr.Arguments.Count()); - Assert.IsTrue(expr.TargetObject is IdentifierExpression); - IdentifierExpression ident = (IdentifierExpression)expr.TargetObject; - Assert.AreEqual("myMethod", ident.Identifier); - Assert.AreEqual(1, ident.TypeArguments.Count); - Assert.AreEqual("System.Char", ident.TypeArguments[0].Type); + ParseUtilCSharp.AssertExpression( + "myMethod('a')", + new InvocationExpression { + Target = new IdentifierExpression { + Identifier = "myMethod", + TypeArguments = { new PrimitiveType("char") } + }, + Arguments = { new PrimitiveExpression('a') } + } + ); } [Test] public void GenericInvocation2ExpressionTest() { - var expr = ParseUtilCSharp.ParseExpression("myMethod()"); - Assert.AreEqual(0, expr.Arguments.Count); - Assert.IsTrue(expr.TargetObject is IdentifierExpression); - IdentifierExpression ident = (IdentifierExpression)expr.TargetObject; - Assert.AreEqual("myMethod", ident.Identifier); - Assert.AreEqual(2, ident.TypeArguments.Count); - Assert.AreEqual("T", ident.TypeArguments[0].Type); - Assert.IsFalse(ident.TypeArguments[0].IsKeyword); - Assert.AreEqual("System.Boolean", ident.TypeArguments[1].Type); - Assert.IsTrue(ident.TypeArguments[1].IsKeyword); + ParseUtilCSharp.AssertExpression( + "myMethod()", + new InvocationExpression { + Target = new IdentifierExpression { + Identifier = "myMethod", + TypeArguments = { + new SimpleType("T"), + new PrimitiveType("bool") + } + } + } + ); } [Test] public void AmbiguousGrammarGenericMethodCall() { - InvocationExpression ie = ParseUtilCSharp.ParseExpression("F(G(7))"); - Assert.IsTrue(ie.TargetObject is IdentifierExpression); - Assert.AreEqual(1, ie.Arguments.Count); - ie = (InvocationExpression)ie.Arguments[0]; - Assert.AreEqual(1, ie.Arguments.Count); - Assert.IsTrue(ie.Arguments[0] is PrimitiveExpression); - IdentifierExpression ident = (IdentifierExpression)ie.TargetObject; - Assert.AreEqual("G", ident.Identifier); - Assert.AreEqual(2, ident.TypeArguments.Count); + ParseUtilCSharp.AssertExpression( + "F(G(7))", + new InvocationExpression { + Target = new IdentifierExpression("F"), + Arguments = { + new InvocationExpression { + Target = new IdentifierExpression { + Identifier = "G", + TypeArguments = { new SimpleType("A"), new SimpleType("B") } + }, + Arguments = { new PrimitiveExpression(7) } + }}}); } - [Test] + [Test, Ignore("Mono Parser Bug???")] public void AmbiguousGrammarNotAGenericMethodCall() { - BinaryOperatorExpression boe = ParseUtilCSharp.ParseExpression("F+y"); - Assert.AreEqual(BinaryOperatorType.GreaterThan, boe.Op); - Assert.IsTrue(boe.Left is BinaryOperatorExpression); - Assert.IsTrue(boe.Right is UnaryOperatorExpression); + ParseUtilCSharp.AssertExpression( + "F+y", + new BinaryOperatorExpression { + Left = new BinaryOperatorExpression { + Left = new IdentifierExpression("F"), + Operator = BinaryOperatorType.LessThan, + Right = new IdentifierExpression("A") + }, + Operator = BinaryOperatorType.GreaterThan, + Right = new UnaryOperatorExpression { + Operator = UnaryOperatorType.Plus, + Expression = new IdentifierExpression("y") + }}); } [Test] @@ -76,80 +92,81 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.Expression // this test was written because this bug caused the AbstractASTVisitor to crash InvocationExpression expr = ParseUtilCSharp.ParseExpression("WriteLine(myMethod(,))", true); - Assert.IsTrue(expr.TargetObject is IdentifierExpression); - Assert.AreEqual("WriteLine", ((IdentifierExpression)expr.TargetObject).Identifier); + Assert.IsTrue(expr.Target is IdentifierExpression); + Assert.AreEqual("WriteLine", ((IdentifierExpression)expr.Target).Identifier); Assert.AreEqual(1, expr.Arguments.Count); // here a second null parameter was added incorrectly - Assert.IsTrue(expr.Arguments[0] is InvocationExpression); - CheckSimpleInvoke((InvocationExpression)expr.Arguments[0]); + Assert.IsTrue(expr.Arguments.Single() is InvocationExpression); } - [Test] + [Test, Ignore("Positions not yet accurate when parsing expression only (because class/method is added around it)")] public void NestedInvocationPositions() { InvocationExpression expr = ParseUtilCSharp.ParseExpression("a.B().C(args)"); - Assert.AreEqual(new Location(8, 1), expr.StartLocation); - Assert.AreEqual(new Location(14, 1), expr.EndLocation); - MemberReferenceExpression mre = (MemberReferenceExpression)expr.TargetObject; - Assert.AreEqual(new Location(6, 1), mre.StartLocation); - Assert.AreEqual(new Location(8, 1), mre.EndLocation); + Assert.AreEqual(new AstLocation(1, 8), expr.StartLocation); + Assert.AreEqual(new AstLocation(1, 14), expr.EndLocation); + MemberReferenceExpression mre = (MemberReferenceExpression)expr.Target; + Assert.AreEqual(new AstLocation(1, 6), mre.StartLocation); + Assert.AreEqual(new AstLocation(1, 8), mre.EndLocation); - Assert.AreEqual(new Location(4, 1), mre.TargetObject.StartLocation); - Assert.AreEqual(new Location(6, 1), mre.TargetObject.EndLocation); + Assert.AreEqual(new AstLocation(1, 4), mre.Target.StartLocation); + Assert.AreEqual(new AstLocation(1, 6), mre.Target.EndLocation); } [Test] public void InvocationOnGenericType() { - InvocationExpression expr = ParseUtilCSharp.ParseExpression("A.Foo()"); - MemberReferenceExpression mre = (MemberReferenceExpression)expr.TargetObject; - Assert.AreEqual("Foo", mre.MemberName); - TypeReferenceExpression tre = (TypeReferenceExpression)mre.TargetObject; - Assert.AreEqual("A", tre.TypeReference.Type); - Assert.AreEqual("T", tre.TypeReference.GenericTypes[0].Type); + ParseUtilCSharp.AssertExpression( + "A.Foo()", + new IdentifierExpression { + Identifier = "A", + TypeArguments = { new SimpleType("T") } + }.Invoke("Foo") + ); } [Test] public void InvocationOnInnerClassInGenericType() { - InvocationExpression expr = ParseUtilCSharp.ParseExpression("A.B.Foo()"); - MemberReferenceExpression mre = (MemberReferenceExpression)expr.TargetObject; - Assert.AreEqual("Foo", mre.MemberName); - MemberReferenceExpression mre2 = (MemberReferenceExpression)mre.TargetObject; - Assert.AreEqual("B", mre2.MemberName); - TypeReferenceExpression tre = (TypeReferenceExpression)mre2.TargetObject; - Assert.AreEqual("A", tre.TypeReference.Type); - Assert.AreEqual("T", tre.TypeReference.GenericTypes[0].Type); + ParseUtilCSharp.AssertExpression( + "A.B.Foo()", + new IdentifierExpression { + Identifier = "A", + TypeArguments = { new SimpleType("T") } + }.Member("B").Invoke("Foo") + ); } [Test] public void InvocationOnGenericInnerClassInGenericType() { - InvocationExpression expr = ParseUtilCSharp.ParseExpression("A.B.C.Foo()"); - MemberReferenceExpression mre = (MemberReferenceExpression)expr.TargetObject; - Assert.AreEqual("Foo", mre.MemberName); - TypeReferenceExpression tre = (TypeReferenceExpression)mre.TargetObject; - InnerClassTypeReference ictr = (InnerClassTypeReference)tre.TypeReference; - Assert.AreEqual("B.C", ictr.Type); - Assert.AreEqual(1, ictr.GenericTypes.Count); - Assert.AreEqual("U", ictr.GenericTypes[0].Type); - - Assert.AreEqual("A", ictr.BaseType.Type); - Assert.AreEqual(1, ictr.BaseType.GenericTypes.Count); - Assert.AreEqual("T", ictr.BaseType.GenericTypes[0].Type); + ParseUtilCSharp.AssertExpression( + "A.B.C.Foo()", + new MemberReferenceExpression { + Target = new IdentifierExpression { + Identifier = "A", + TypeArguments = { new SimpleType("T") } + }.Member("B"), + MemberName = "C", + TypeArguments = { new SimpleType("U") } + }.Invoke("Foo")); } - [Test] + [Test, Ignore("named arguments not yet supported")] public void InvocationWithNamedArgument() { - InvocationExpression expr = ParseUtilCSharp.ParseExpression("a(arg: ref v)"); - Assert.AreEqual(1, expr.Arguments.Count); - NamedArgumentExpression nae = (NamedArgumentExpression)expr.Arguments[0]; - Assert.AreEqual("arg", nae.Name); - DirectionExpression dir = (DirectionExpression)nae.Expression; - Assert.AreEqual(FieldDirection.Ref, dir.FieldDirection); - Assert.IsInstanceOf(dir.Expression); - }*/ + ParseUtilCSharp.AssertExpression( + "a(arg: ref v)", + new InvocationExpression { + Target = new IdentifierExpression("a"), + Arguments = { + new NamedArgumentExpression { + Identifier = "arg", + Expression = new DirectionExpression { + FieldDirection = FieldDirection.Ref, + Expression = new IdentifierExpression("v") + }}}}); + } } } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/IsExpressionTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/IsExpressionTests.cs index 4b5039565..bbab99a6f 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/IsExpressionTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/IsExpressionTests.cs @@ -9,15 +9,16 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.Expression [TestFixture] public class IsExpressionTests { - [Test, Ignore] + [Test] public void GenericArrayIsExpression() { - /* TODO - TypeOfIsExpression ce = ParseUtilCSharp.ParseExpression("o is List[]"); - Assert.AreEqual("List", ce.TypeReference.Type); - Assert.AreEqual("System.String", ce.TypeReference.GenericTypes[0].Type); - Assert.AreEqual(new int[] { 0 }, ce.TypeReference.RankSpecifier); - Assert.IsTrue(ce.Expression is IdentifierExpression);*/ + ParseUtilCSharp.AssertExpression( + "o is List[]", + new IsExpression { + Expression = new IdentifierExpression("o"), + Type = new SimpleType("List") { TypeArguments = { new PrimitiveType("string") } }.MakeArrayType(1) + } + ); } [Test] diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/LambdaExpressionTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/LambdaExpressionTests.cs index 5f4addd3e..8350a6756 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/LambdaExpressionTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/LambdaExpressionTests.cs @@ -6,84 +6,103 @@ using NUnit.Framework; namespace ICSharpCode.NRefactory.CSharp.Parser.Expression { - [TestFixture, Ignore("Port unit tests")] + [TestFixture] public class LambdaExpressionTests { - static LambdaExpression ParseCSharp(string program) - { - return ParseUtilCSharp.ParseExpression(program); - } - - [Test] + [Test, Ignore("Lambdas with expression body not yet supported")] public void ImplicitlyTypedExpressionBody() { - /* - LambdaExpression e = ParseCSharp("(x) => x + 1"); - Assert.AreEqual("x", e.Parameters[0].ParameterName); - Assert.IsTrue(e.Parameters[0].TypeReference.IsNull); - Assert.IsTrue(e.ExpressionBody is BinaryOperatorExpression); - Assert.IsTrue(e.ReturnType.IsNull);*/ - throw new NotImplementedException(); + ParseUtilCSharp.AssertExpression( + "(x) => x + 1", + new LambdaExpression { + Parameters = { new ParameterDeclaration { Name = "x" } }, + Body = new BinaryOperatorExpression(new IdentifierExpression("x"), BinaryOperatorType.Add, new PrimitiveExpression(1)) + }); } - /* TODO Port unit tests - [Test] + [Test, Ignore("Lambdas with expression body not yet supported")] public void ImplicitlyTypedExpressionBodyWithoutParenthesis() { - LambdaExpression e = ParseCSharp("x => x + 1"); - Assert.AreEqual("x", e.Parameters[0].ParameterName); - Assert.IsTrue(e.Parameters[0].TypeReference.IsNull); - Assert.IsTrue(e.ExpressionBody is BinaryOperatorExpression); - Assert.IsTrue(e.ReturnType.IsNull); + ParseUtilCSharp.AssertExpression( + "x => x + 1", + new LambdaExpression { + Parameters = { new ParameterDeclaration { Name = "x" } }, + Body = new BinaryOperatorExpression(new IdentifierExpression("x"), BinaryOperatorType.Add, new PrimitiveExpression(1)) + }); } [Test] public void ImplicitlyTypedStatementBody() { - LambdaExpression e = ParseCSharp("(x) => { return x + 1; }"); - Assert.AreEqual("x", e.Parameters[0].ParameterName); - Assert.IsTrue(e.Parameters[0].TypeReference.IsNull); - Assert.IsTrue(e.StatementBody.Children[0] is ReturnStatement); - Assert.IsTrue(e.ReturnType.IsNull); + ParseUtilCSharp.AssertExpression( + "(x) => { return x + 1; }", + new LambdaExpression { + Parameters = { new ParameterDeclaration { Name = "x" } }, + Body = new BlockStatement { + new ReturnStatement { + Expression = new BinaryOperatorExpression( + new IdentifierExpression("x"), BinaryOperatorType.Add, new PrimitiveExpression(1)) + }}}); } [Test] public void ImplicitlyTypedStatementBodyWithoutParenthesis() { - LambdaExpression e = ParseCSharp("x => { return x + 1; }"); - Assert.AreEqual("x", e.Parameters[0].ParameterName); - Assert.IsTrue(e.Parameters[0].TypeReference.IsNull); - Assert.IsTrue(e.StatementBody.Children[0] is ReturnStatement); - Assert.IsTrue(e.ReturnType.IsNull); + ParseUtilCSharp.AssertExpression( + "x => { return x + 1; }", + new LambdaExpression { + Parameters = { new ParameterDeclaration { Name = "x" } }, + Body = new BlockStatement { + new ReturnStatement { + Expression = new BinaryOperatorExpression( + new IdentifierExpression("x"), BinaryOperatorType.Add, new PrimitiveExpression(1)) + }}}); } [Test] public void ExplicitlyTypedStatementBody() { - LambdaExpression e = ParseCSharp("(int x) => { return x + 1; }"); - Assert.AreEqual("x", e.Parameters[0].ParameterName); - Assert.AreEqual("System.Int32", e.Parameters[0].TypeReference.Type); - Assert.IsTrue(e.StatementBody.Children[0] is ReturnStatement); - Assert.IsTrue(e.ReturnType.IsNull); + ParseUtilCSharp.AssertExpression( + "(int x) => { return x + 1; }", + new LambdaExpression { + Parameters = { new ParameterDeclaration { Type = new PrimitiveType("int"), Name = "x" } }, + Body = new BlockStatement { + new ReturnStatement { + Expression = new BinaryOperatorExpression( + new IdentifierExpression("x"), BinaryOperatorType.Add, new PrimitiveExpression(1)) + }}}); } - [Test] - public void ExplicitlyTypedStatementBodyWithRefParameter() + [Test, Ignore("Lambdas with expression body not yet supported")] + public void ExplicitlyTypedWithRefParameter() { - LambdaExpression e = ParseCSharp("(ref int i) => i = 1"); - Assert.AreEqual("i", e.Parameters[0].ParameterName); - Assert.IsTrue((e.Parameters[0].ParamModifier & ParameterModifiers.Ref) == ParameterModifiers.Ref); - Assert.AreEqual("System.Int32", e.Parameters[0].TypeReference.Type); - Assert.IsTrue(e.ReturnType.IsNull); + ParseUtilCSharp.AssertExpression( + "(ref int i) => i = 1", + new LambdaExpression { + Parameters = { + new ParameterDeclaration { + ParameterModifier = ParameterModifier.Ref, + Type = new PrimitiveType("int"), + Name = "x" + } + }, + Body = new AssignmentExpression(new IdentifierExpression("i"), new PrimitiveExpression(1)) + }); } - [Test] + [Test, Ignore("Lambdas with expression body not yet supported")] public void LambdaExpressionContainingConditionalExpression() { - LambdaExpression e = ParseCSharp("rr => rr != null ? rr.ResolvedType : null"); - Assert.AreEqual("rr", e.Parameters[0].ParameterName); - Assert.IsTrue(e.ExpressionBody is ConditionalExpression); - Assert.IsTrue(e.ReturnType.IsNull); - }*/ + ParseUtilCSharp.AssertExpression( + "rr => rr != null ? rr.ResolvedType : null", + new LambdaExpression { + Parameters = { new ParameterDeclaration { Name = "rr" } }, + Body = new ConditionalExpression { + Condition = new BinaryOperatorExpression( + new IdentifierExpression("rr"), BinaryOperatorType.InEquality, new NullReferenceExpression()), + TrueExpression = new IdentifierExpression("rr").Member("ResolvedType"), + FalseExpression = new NullReferenceExpression() + }}); + } } } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/MemberReferenceExpressionTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/MemberReferenceExpressionTests.cs index 3f9ce69eb..960b53355 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/MemberReferenceExpressionTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/MemberReferenceExpressionTests.cs @@ -6,71 +6,84 @@ using NUnit.Framework; namespace ICSharpCode.NRefactory.CSharp.Parser.Expression { - [TestFixture, Ignore] + [TestFixture] public class MemberReferenceExpressionTests { [Test] public void SimpleFieldReferenceExpressionTest() { - MemberReferenceExpression fre = ParseUtilCSharp.ParseExpression("myTargetObject.myField"); - //Assert.AreEqual("myField", fre.MemberName); - //Assert.IsTrue(fre.TargetObject is IdentifierExpression); - //Assert.AreEqual("myTargetObject", ((IdentifierExpression)fre.TargetObject).Identifier); - throw new NotImplementedException(); + ParseUtilCSharp.AssertExpression( + "myTargetObject.myField", + new IdentifierExpression("myTargetObject").Member("myField") + ); + } + + [Test, Ignore("parser is broken and produces IdentifierExpression instead of PrimitiveType")] + public void ShortMaxValueTest() + { + ParseUtilCSharp.AssertExpression( + "short.MaxValue", + new PrimitiveType("short").Member("MaxValue") + ); + } + + [Test, Ignore("Parsing of @-identifiers is broken")] + public void IdentShortMaxValueTest() + { + ParseUtilCSharp.AssertExpression( + "@short.MaxValue", + new IdentifierExpression("short").Member("MaxValue") + ); } - /* TODO port unit tests [Test] public void GenericFieldReferenceExpressionTest() { - MemberReferenceExpression fre = ParseUtilCSharp.ParseExpression("SomeClass.myField"); - Assert.AreEqual("myField", fre.MemberName); - Assert.IsTrue(fre.TargetObject is TypeReferenceExpression); - TypeReference tr = ((TypeReferenceExpression)fre.TargetObject).TypeReference; - Assert.AreEqual("SomeClass", tr.Type); - Assert.AreEqual(1, tr.GenericTypes.Count); - Assert.AreEqual("System.String", tr.GenericTypes[0].Type); + ParseUtilCSharp.AssertExpression( + "SomeClass.myField", + new IdentifierExpression("SomeClass") { TypeArguments = { new PrimitiveType("string") } }.Member("myField") + ); } [Test] public void FullNamespaceGenericFieldReferenceExpressionTest() { - MemberReferenceExpression fre = ParseUtilCSharp.ParseExpression("Namespace.Subnamespace.SomeClass.myField"); - Assert.AreEqual("myField", fre.MemberName); - Assert.IsTrue(fre.TargetObject is TypeReferenceExpression); - TypeReference tr = ((TypeReferenceExpression)fre.TargetObject).TypeReference; - Assert.AreEqual("Namespace.Subnamespace.SomeClass", tr.Type); - Assert.AreEqual(1, tr.GenericTypes.Count); - Assert.AreEqual("System.String", tr.GenericTypes[0].Type); + ParseUtilCSharp.AssertExpression( + "Namespace.Subnamespace.SomeClass.myField", + new MemberReferenceExpression { + Target = new IdentifierExpression("Namespace").Member("Subnamespace"), + TypeArguments = { new PrimitiveType("string") } + }.Member("myField") + ); } - [Test] + [Test, Ignore("Aliases not yet implemented")] public void GlobalFullNamespaceGenericFieldReferenceExpressionTest() { - MemberReferenceExpression fre = ParseUtilCSharp.ParseExpression("global::Namespace.Subnamespace.SomeClass.myField"); - Assert.AreEqual("myField", fre.MemberName); - Assert.IsTrue(fre.TargetObject is TypeReferenceExpression); - TypeReference tr = ((TypeReferenceExpression)fre.TargetObject).TypeReference; - Assert.IsFalse(tr is InnerClassTypeReference); - Assert.AreEqual("Namespace.Subnamespace.SomeClass", tr.Type); - Assert.AreEqual(1, tr.GenericTypes.Count); - Assert.AreEqual("System.String", tr.GenericTypes[0].Type); - Assert.IsTrue(tr.IsGlobal); + ParseUtilCSharp.AssertExpression( + "global::Namespace.Subnamespace.SomeClass.myField", + new MemberReferenceExpression { + Target = new MemberType { + Target = new SimpleType("global"), + IsDoubleColon = true, + MemberName = "Namespace" + }.Member("Subnamespace"), + TypeArguments = { new PrimitiveType("string") } + }.Member("myField") + ); } [Test] public void NestedGenericFieldReferenceExpressionTest() { - MemberReferenceExpression fre = ParseUtilCSharp.ParseExpression("MyType.InnerClass.myField"); - Assert.AreEqual("myField", fre.MemberName); - Assert.IsTrue(fre.TargetObject is TypeReferenceExpression); - InnerClassTypeReference ic = (InnerClassTypeReference)((TypeReferenceExpression)fre.TargetObject).TypeReference; - Assert.AreEqual("InnerClass", ic.Type); - Assert.AreEqual(1, ic.GenericTypes.Count); - Assert.AreEqual("System.Int32", ic.GenericTypes[0].Type); - Assert.AreEqual("MyType", ic.BaseType.Type); - Assert.AreEqual(1, ic.BaseType.GenericTypes.Count); - Assert.AreEqual("System.String", ic.BaseType.GenericTypes[0].Type); - }*/ + ParseUtilCSharp.AssertExpression( + "MyType.InnerClass.myField", + new MemberReferenceExpression { + Target = new IdentifierExpression("MyType") { TypeArguments = { new PrimitiveType("string") } }, + MemberName = "InnerClass", + TypeArguments = { new PrimitiveType("int") } + }.Member("myField") + ); + } } } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/PointerReferenceExpressionTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/PointerReferenceExpressionTests.cs index f02c795e2..895ffff4c 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/PointerReferenceExpressionTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/PointerReferenceExpressionTests.cs @@ -9,13 +9,25 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.Expression [TestFixture] public class PointerReferenceExpressionTests { - [Test, Ignore("where did PointerReferenceExpression.MemberName go?")] + [Test, Ignore("Parser bug!")] public void PointerReferenceExpressionTest() { PointerReferenceExpression pre = ParseUtilCSharp.ParseExpression("myObj.field->b"); Assert.IsTrue(pre.Target is MemberReferenceExpression); - //Assert.AreEqual("b", pre.MemberName); - throw new NotImplementedException(); + Assert.AreEqual("b", pre.MemberName); + } + + [Test, Ignore("Parser bug!")] + public void PointerReferenceGenericMethodTest() + { + ParseUtilCSharp.AssertExpression( + "ptr->M();", + new InvocationExpression { + Target = new PointerReferenceExpression { + Target = new IdentifierExpression("ptr"), + MemberName = "M", + TypeArguments = { new PrimitiveType("string") } + }}); } } } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/QueryExpressionTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/QueryExpressionTests.cs index 7b1d18e03..5601797c9 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/QueryExpressionTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/QueryExpressionTests.cs @@ -6,104 +6,220 @@ using NUnit.Framework; namespace ICSharpCode.NRefactory.CSharp.Parser.Expression { - [TestFixture, Ignore] + [TestFixture, Ignore("Query expressions not yet implemented")] public class QueryExpressionTests { [Test] public void SimpleExpression() { - /* - QueryExpression qe = ParseUtilCSharp.ParseExpression( - "from c in customers where c.City == \"London\" select c" - ); - Assert.AreEqual("c", qe.FromClause.Sources.First().Identifier); - Assert.AreEqual("customers", ((IdentifierExpression)qe.FromClause.Sources.First().Expression).Identifier); - Assert.AreEqual(1, qe.MiddleClauses.Count); - Assert.IsInstanceOf(typeof(QueryExpressionWhereClause), qe.MiddleClauses[0]); - QueryExpressionWhereClause wc = (QueryExpressionWhereClause)qe.MiddleClauses[0]; - Assert.IsInstanceOf(typeof(BinaryOperatorExpression), wc.Condition); - Assert.IsInstanceOf(typeof(QueryExpressionSelectClause), qe.SelectOrGroupClause);*/ - throw new NotImplementedException(); + ParseUtilCSharp.AssertExpression( + "from c in customers where c.City == \"London\" select c", + new QueryExpression { + Clauses = { + new QueryFromClause { + Identifier = "c", + Expression = new IdentifierExpression("customers") + }, + new QueryWhereClause { + Condition = new BinaryOperatorExpression { + Left = new IdentifierExpression("c").Member("City"), + Operator = BinaryOperatorType.Equality, + Right = new PrimitiveExpression("London") + } + }, + new QuerySelectClause { + Expression = new IdentifierExpression("c") + } + }}); } - /* TODO port unit tests [Test] public void ExpressionWithType1() { - QueryExpression qe = ParseUtilCSharp.ParseExpression( - "from Customer c in customers select c" - ); - Assert.AreEqual("c", qe.FromClause.Sources.First().Identifier); - Assert.AreEqual("Customer", qe.FromClause.Sources.First().Type.ToString()); - Assert.AreEqual("customers", ((IdentifierExpression)qe.FromClause.Sources.First().Expression).Identifier); - Assert.IsInstanceOf(typeof(QueryExpressionSelectClause), qe.SelectOrGroupClause); + ParseUtilCSharp.AssertExpression( + "from Customer c in customers select c", + new QueryExpression { + Clauses = { + new QueryFromClause { + Type = new SimpleType("Customer"), + Identifier = "c", + Expression = new IdentifierExpression("customers") + }, + new QuerySelectClause { + Expression = new IdentifierExpression("c") + } + }}); } [Test] public void ExpressionWithType2() { - QueryExpression qe = ParseUtilCSharp.ParseExpression( - "from int c in customers select c" - ); - Assert.AreEqual("c", qe.FromClause.Sources.First().Identifier); - Assert.AreEqual("System.Int32", qe.FromClause.Sources.First().Type.Type); - Assert.AreEqual("customers", ((IdentifierExpression)qe.FromClause.Sources.First().Expression).Identifier); - Assert.IsInstanceOf(typeof(QueryExpressionSelectClause), qe.SelectOrGroupClause); + ParseUtilCSharp.AssertExpression( + "from int c in customers select c", + new QueryExpression { + Clauses = { + new QueryFromClause { + Type = new PrimitiveType("int"), + Identifier = "c", + Expression = new IdentifierExpression("customers") + }, + new QuerySelectClause { + Expression = new IdentifierExpression("c") + } + }}); } [Test] public void ExpressionWithType3() { - QueryExpression qe = ParseUtilCSharp.ParseExpression( - "from S? c in customers select c" - ); - Assert.AreEqual("c", qe.FromClause.Sources.First().Identifier); - Assert.AreEqual("System.Nullable>", qe.FromClause.Sources.First().Type.ToString()); - Assert.AreEqual("customers", ((IdentifierExpression)qe.FromClause.Sources.First().Expression).Identifier); - Assert.IsInstanceOf(typeof(QueryExpressionSelectClause), qe.SelectOrGroupClause); + ParseUtilCSharp.AssertExpression( + "from S? c in customers select c", + new QueryExpression { + Clauses = { + new QueryFromClause { + Type = new ComposedType { + BaseType = new SimpleType { + Identifier = "S", + TypeArguments = { + new PrimitiveType("int").MakeArrayType() + } + }, + HasNullableSpecifier = true + }, + Identifier = "c", + Expression = new IdentifierExpression("customers") + }, + new QuerySelectClause { + Expression = new IdentifierExpression("c") + } + }}); } [Test] public void MultipleGenerators() { - QueryExpression qe = ParseUtilCSharp.ParseExpression(@" + ParseUtilCSharp.AssertExpression( + @" from c in customers where c.City == ""London"" from o in c.Orders where o.OrderDate.Year == 2005 -select new { c.Name, o.OrderID, o.Total }"); - Assert.AreEqual(3, qe.MiddleClauses.Count); - Assert.IsInstanceOf(typeof(QueryExpressionWhereClause), qe.MiddleClauses[0]); - Assert.IsInstanceOf(typeof(QueryExpressionFromClause), qe.MiddleClauses[1]); - Assert.IsInstanceOf(typeof(QueryExpressionWhereClause), qe.MiddleClauses[2]); - - Assert.IsInstanceOf(typeof(QueryExpressionSelectClause), qe.SelectOrGroupClause); +select new { c.Name, o.OrderID, o.Total }", + new QueryExpression { + Clauses = { + new QueryFromClause { + Identifier = "c", + Expression = new IdentifierExpression("customers") + }, + new QueryWhereClause { + Condition = new BinaryOperatorExpression { + Left = new IdentifierExpression("c").Member("City"), + Operator = BinaryOperatorType.Equality, + Right = new PrimitiveExpression("London") + } + }, + new QueryFromClause { + Identifier = "o", + Expression = new IdentifierExpression("c").Member("Orders") + }, + new QueryWhereClause { + Condition = new BinaryOperatorExpression { + Left = new IdentifierExpression("c").Member("OrderDate").Member("Year"), + Operator = BinaryOperatorType.Equality, + Right = new PrimitiveExpression(2005) + } + }, + new QuerySelectClause { + Expression = new ObjectCreateExpression { + Initializer = new ArrayInitializerExpression { + Elements = { + new IdentifierExpression("c").Member("Name"), + new IdentifierExpression("o").Member("OrderID"), + new IdentifierExpression("o").Member("Total") + } + } + } + } + }}); } [Test] public void ExpressionWithOrderBy() { - QueryExpression qe = ParseUtilCSharp.ParseExpression( - "from c in customers orderby c.Name select c" - ); - Assert.AreEqual("c", qe.FromClause.Sources.First().Identifier); - Assert.AreEqual("customers", ((IdentifierExpression)qe.FromClause.Sources.First().Expression).Identifier); - Assert.IsInstanceOf(typeof(QueryExpressionOrderClause), qe.MiddleClauses[0]); - Assert.IsInstanceOf(typeof(QueryExpressionSelectClause), qe.SelectOrGroupClause); + ParseUtilCSharp.AssertExpression( + "from c in customers orderby c.Name select c", + new QueryExpression { + Clauses = { + new QueryFromClause { + Identifier = "c", + Expression = new IdentifierExpression("customers") + }, + new QueryOrderClause { + Orderings = { + new QueryOrdering { + Expression = new IdentifierExpression("c").Member("Name") + } + } + }, + new QuerySelectClause { + Expression = new IdentifierExpression("c") + } + }}); } [Test] public void ExpressionWithOrderByAndLet() { - QueryExpression qe = ParseUtilCSharp.ParseExpression( - "from c in customers orderby c.Name let x = c select x" + ParseUtilCSharp.AssertExpression( + "from c in customers orderby c.Name descending let x = c select x", + new QueryExpression { + Clauses = { + new QueryFromClause { + Identifier = "c", + Expression = new IdentifierExpression("customers") + }, + new QueryOrderClause { + Orderings = { + new QueryOrdering { + Expression = new IdentifierExpression("c").Member("Name"), + Direction = QueryOrderingDirection.Descending + } + } + }, + new QueryLetClause { + Identifier = "x", + Expression = new IdentifierExpression("c") + }, + new QuerySelectClause { + Expression = new IdentifierExpression("x") + } + }}); + } + + [Test] + public void QueryContinuation() + { + ParseUtilCSharp.AssertExpression( + "from a in b select c into d select e", + new QueryExpression { + Clauses = { + new QueryContinuationClause { + PrecedingQuery = new QueryExpression { + Clauses = { + new QueryFromClause { + Identifier = "a", + Expression = new IdentifierExpression("b") + }, + new QuerySelectClause { Expression = new IdentifierExpression("c") } + } + }, + Identifier = "d" + }, + new QuerySelectClause { Expression = new IdentifierExpression("e") } + } + } ); - Assert.AreEqual("c", qe.FromClause.Sources.First().Identifier); - Assert.AreEqual("customers", ((IdentifierExpression)qe.FromClause.Sources.First().Expression).Identifier); - Assert.IsInstanceOf(typeof(QueryExpressionOrderClause), qe.MiddleClauses[0]); - Assert.IsInstanceOf(typeof(QueryExpressionLetClause), qe.MiddleClauses[1]); - Assert.IsInstanceOf(typeof(QueryExpressionSelectClause), qe.SelectOrGroupClause); - }*/ + } } } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/SizeOfExpressionTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/SizeOfExpressionTests.cs index a50c1b77f..f6a85fcb3 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/SizeOfExpressionTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/SizeOfExpressionTests.cs @@ -9,11 +9,11 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.Expression [TestFixture] public class SizeOfExpressionTests { - [Test, Ignore("type references not implemented yet")] + [Test] public void SizeOfExpressionTest() { SizeOfExpression soe = ParseUtilCSharp.ParseExpression("sizeof(MyType)"); - Assert.AreEqual("MyType", soe.Type); + Assert.AreEqual("MyType", ((SimpleType)soe.Type).Identifier); } } } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/StackAllocExpressionTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/StackAllocExpressionTests.cs index 038925a42..c28d559fc 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/StackAllocExpressionTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/StackAllocExpressionTests.cs @@ -2,6 +2,7 @@ // This code is distributed under MIT X11 license (for details please see \doc\license.txt) using System; +using System.Linq; using NUnit.Framework; namespace ICSharpCode.NRefactory.CSharp.Parser.Expression @@ -9,11 +10,13 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.Expression [TestFixture] public class StackAllocExpressionTests { - [Test, Ignore] + [Test] public void StackAllocExpressionTest() { - var sae = ParseUtilCSharp.ParseExpression("stackalloc int[100]"); - throw new NotImplementedException(); // TODO: verify type + length expression + var vd = ParseUtilCSharp.ParseStatement("int* a = stackalloc int[100];"); + StackAllocExpression sae = (StackAllocExpression)vd.Variables.Single().Initializer; + Assert.AreEqual("int", ((PrimitiveType)sae.Type).Keyword); + Assert.AreEqual(100, ((PrimitiveExpression)sae.CountExpression).Value); } } } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/TypeOfExpressionTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/TypeOfExpressionTests.cs index 599aae19f..3dcc932d9 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/TypeOfExpressionTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/TypeOfExpressionTests.cs @@ -6,86 +6,113 @@ using NUnit.Framework; namespace ICSharpCode.NRefactory.CSharp.Parser.Expression { - [TestFixture, Ignore] + [TestFixture] public class TypeOfExpressionTests { [Test] public void SimpleTypeOfExpressionTest() { - //TypeOfExpression toe = ParseUtilCSharp.ParseExpression("typeof(MyNamespace.N1.MyType)"); - //Assert.AreEqual("MyNamespace.N1.MyType", toe.TypeReference.Type); - throw new NotImplementedException(); + ParseUtilCSharp.AssertExpression( + "typeof(MyNamespace.N1.MyType)", + new TypeOfExpression { + Type = new MemberType { + Target = new MemberType { + Target = new SimpleType("MyNamespace"), + MemberName = "N1" + }, + MemberName = "MyType" + }}); } - /* TODO - [Test] + [Test, Ignore("Aliases not yet implemented")] public void GlobalTypeOfExpressionTest() { - TypeOfExpression toe = ParseUtilCSharp.ParseExpression("typeof(global::System.Console)"); - Assert.AreEqual("System.Console", toe.TypeReference.Type); + ParseUtilCSharp.AssertExpression( + "typeof(global::System.Console)", + new TypeOfExpression { + Type = new MemberType { + Target = new MemberType { + Target = new SimpleType("global"), + IsDoubleColon = true, + MemberName = "System" + }, + MemberName = "Console" + }}); } [Test] public void PrimitiveTypeOfExpressionTest() { TypeOfExpression toe = ParseUtilCSharp.ParseExpression("typeof(int)"); - Assert.AreEqual("System.Int32", toe.TypeReference.Type); + Assert.AreEqual("int", ((PrimitiveType)toe.Type).Keyword); } [Test] public void VoidTypeOfExpressionTest() { TypeOfExpression toe = ParseUtilCSharp.ParseExpression("typeof(void)"); - Assert.AreEqual("System.Void", toe.TypeReference.Type); + Assert.AreEqual("void", ((PrimitiveType)toe.Type).Keyword); } [Test] public void ArrayTypeOfExpressionTest() { - TypeOfExpression toe = ParseUtilCSharp.ParseExpression("typeof(MyType[])"); - Assert.AreEqual("MyType", toe.TypeReference.Type); - Assert.AreEqual(new int[] {0}, toe.TypeReference.RankSpecifier); + ParseUtilCSharp.AssertExpression( + "typeof(MyType[])", + new TypeOfExpression { + Type = new SimpleType("MyType").MakeArrayType() + }); } [Test] public void GenericTypeOfExpressionTest() { - TypeOfExpression toe = ParseUtilCSharp.ParseExpression("typeof(MyNamespace.N1.MyType)"); - Assert.AreEqual("MyNamespace.N1.MyType", toe.TypeReference.Type); - Assert.AreEqual("System.String", toe.TypeReference.GenericTypes[0].Type); + ParseUtilCSharp.AssertExpression( + "typeof(MyNamespace.N1.MyType)", + new TypeOfExpression { + Type = new MemberType { + Target = new MemberType { + Target = new SimpleType("MyNamespace"), + MemberName = "N1" + }, + MemberName = "MyType", + TypeArguments = { new PrimitiveType("string") } + }}); } [Test] public void NestedGenericTypeOfExpressionTest() { - TypeOfExpression toe = ParseUtilCSharp.ParseExpression("typeof(MyType.InnerClass.InnerInnerClass)"); - InnerClassTypeReference ic = (InnerClassTypeReference)toe.TypeReference; - Assert.AreEqual("InnerInnerClass", ic.Type); - Assert.AreEqual(0, ic.GenericTypes.Count); - ic = (InnerClassTypeReference)ic.BaseType; - Assert.AreEqual("InnerClass", ic.Type); - Assert.AreEqual(1, ic.GenericTypes.Count); - Assert.AreEqual("System.Int32", ic.GenericTypes[0].Type); - Assert.AreEqual("MyType", ic.BaseType.Type); - Assert.AreEqual(1, ic.BaseType.GenericTypes.Count); - Assert.AreEqual("System.String", ic.BaseType.GenericTypes[0].Type); + ParseUtilCSharp.AssertExpression( + "typeof(MyType.InnerClass.InnerInnerClass)", + new TypeOfExpression { + Type = new MemberType { + Target = new MemberType { + Target = new SimpleType("MyType") { TypeArguments = { new PrimitiveType("string") } }, + MemberName = "InnerClass", + TypeArguments = { new PrimitiveType("int") } + }, + MemberName = "InnerInnerClass" + }}); } [Test] public void NullableTypeOfExpressionTest() { - TypeOfExpression toe = ParseUtilCSharp.ParseExpression("typeof(MyStruct?)"); - Assert.AreEqual("System.Nullable", toe.TypeReference.Type); - Assert.AreEqual("MyStruct", toe.TypeReference.GenericTypes[0].Type); + ParseUtilCSharp.AssertExpression( + "typeof(MyStruct?)", + new TypeOfExpression { + Type = new ComposedType { + BaseType = new SimpleType("MyType"), + HasNullableSpecifier = true + }}); } - [Test] + [Test, Ignore("How do we represent unbound types in the AST?")] public void UnboundTypeOfExpressionTest() { TypeOfExpression toe = ParseUtilCSharp.ParseExpression("typeof(MyType<,>)"); - Assert.AreEqual("MyType", toe.TypeReference.Type); - Assert.IsTrue(toe.TypeReference.GenericTypes[0].IsNull); - Assert.IsTrue(toe.TypeReference.GenericTypes[1].IsNull); - }*/ + throw new NotImplementedException("How do we represent unbound types in the AST?"); + } } } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/UnaryOperatorExpressionTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/UnaryOperatorExpressionTests.cs index c704b8857..a968af1eb 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/UnaryOperatorExpressionTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/UnaryOperatorExpressionTests.cs @@ -84,9 +84,9 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.Expression Assert.AreEqual(UnaryOperatorType.Dereference, uoe.Operator); ParenthesizedExpression pe = (ParenthesizedExpression)uoe.Expression; CastExpression ce = (CastExpression)pe.Expression; - //Assert.AreEqual("SomeType", ce.CastTo.Type); - //Assert.AreEqual(1, ce.CastTo.PointerNestingLevel); - Assert.Ignore("need to check target type"); // TODO + ComposedType type = (ComposedType)ce.Type; + Assert.AreEqual("SomeType", ((SimpleType)type.BaseType).Identifier); + Assert.AreEqual(1, type.PointerRank); UnaryOperatorExpression adrOf = (UnaryOperatorExpression)ce.Expression; Assert.AreEqual(UnaryOperatorType.AddressOf, adrOf.Operator); diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/DelegateDeclarationTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/DelegateDeclarationTests.cs index 51e046976..e443e7b94 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/DelegateDeclarationTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/DelegateDeclarationTests.cs @@ -7,55 +7,41 @@ using NUnit.Framework; namespace ICSharpCode.NRefactory.CSharp.Parser.GeneralScope { - [TestFixture, Ignore("delegates are completely broken at the moment")] + [TestFixture] public class DelegateDeclarationTests { - void TestParameters(DelegateDeclaration dd) - { - Assert.AreEqual(3, dd.Parameters.Count()); - - Assert.AreEqual("a", ((ParameterDeclaration)dd.Parameters.ElementAt(0)).Name); - //Assert.AreEqual("System.Int32", ((ParameterDeclaration)dd.Parameters.ElementAt(0)).TypeReference.Type); - Assert.Ignore("check types"); // TODO - Assert.AreEqual("secondParam", ((ParameterDeclaration)dd.Parameters.ElementAt(1)).Name); - //Assert.AreEqual("System.Int32", ((ParameterDeclaration)dd.Parameters.ElementAt(1)).TypeReference.Type); - - Assert.AreEqual("lastParam", ((ParameterDeclaration)dd.Parameters.ElementAt(2)).Name); - //Assert.AreEqual("MyObj", ((ParameterDeclaration)dd.Parameters.ElementAt(2)).TypeReference.Type); - } - [Test] public void SimpleCSharpDelegateDeclarationTest() { - string program = "public delegate void MyDelegate(int a, int secondParam, MyObj lastParam);\n"; - DelegateDeclaration dd = ParseUtilCSharp.ParseGlobal(program); - Assert.AreEqual("MyDelegate", dd.Name); - //Assert.AreEqual("System.Void", dd.ReturnType.Type); - TestParameters(dd); + ParseUtilCSharp.AssertGlobal( + "public delegate void MyDelegate(int a, int secondParam, MyObj lastParam);", + new DelegateDeclaration { + Modifiers = Modifiers.Public, + ReturnType = new PrimitiveType("void"), + Name = "MyDelegate", + Parameters = { + new ParameterDeclaration(new PrimitiveType("int"), "a"), + new ParameterDeclaration(new PrimitiveType("int"), "secondParam"), + new ParameterDeclaration(new SimpleType("MyObj"), "lastParam") + }}); } - [Test, Ignore] - public void DelegateWithoutNameDeclarationTest() - { - string program = "public delegate void(int a, int secondParam, MyObj lastParam);\n"; - DelegateDeclaration dd = ParseUtilCSharp.ParseGlobal(program, true); - //Assert.AreEqual("System.Void", dd.ReturnType.Type); - //Assert.AreEqual("?", dd.Name); - TestParameters(dd); - } - - [Test, Ignore] + [Test, Ignore("Generics not yet supported")] public void GenericDelegateDeclarationTest() { - string program = "public delegate T CreateObject() where T : ICloneable;\n"; - DelegateDeclaration dd = ParseUtilCSharp.ParseGlobal(program); - Assert.AreEqual("CreateObject", dd.Name); - //Assert.AreEqual("T", dd.ReturnType.Type); - Assert.AreEqual(0, dd.Parameters.Count()); - /*Assert.AreEqual(1, dd.Templates.Count); - Assert.AreEqual("T", dd.Templates[0].Name); - Assert.AreEqual(1, dd.Templates[0].Bases.Count); - Assert.AreEqual("ICloneable", dd.Templates[0].Bases[0].Type);*/ throw new NotImplementedException(); + ParseUtilCSharp.AssertGlobal( + "public delegate T CreateObject() where T : ICloneable;", + new DelegateDeclaration { + Modifiers = Modifiers.Public, + ReturnType = new SimpleType("T"), + Name = "CreateObject", + TypeParameters = { new TypeParameterDeclaration { Name = "T" } }, + Constraints = { + new Constraint { + TypeParameter = "T", + BaseTypes = { new SimpleType("ICloneable") } + } + }}); } [Test] @@ -66,7 +52,7 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.GeneralScope Assert.AreEqual("MyDelegate", ((DelegateDeclaration)nd.Members.Single()).Name); } - [Test, Ignore("inner classes not yet implemented")] + [Test] public void DelegateDeclarationInClass() { string program = "class Outer { delegate void Inner(); }"; diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/TypeDeclarationTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/TypeDeclarationTests.cs index 525306bd6..874816450 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/TypeDeclarationTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/TypeDeclarationTests.cs @@ -70,85 +70,111 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.GeneralScope Assert.AreEqual(Modifiers.Static, td.Modifiers); } - [Test, Ignore] + [Test, Ignore("Generics not yet supported")] public void GenericClassTypeDeclarationTest() { - TypeDeclaration td = ParseUtilCSharp.ParseGlobal("public class G {}"); - - Assert.AreEqual(ClassType.Class, td.ClassType); - Assert.AreEqual("G", td.Name); - Assert.AreEqual(Modifiers.Public, td.Modifiers); - /*Assert.AreEqual(0, td.BaseTypes.Count); - Assert.AreEqual(1, td.TypeArguments.Count()); - Assert.AreEqual("T", td.TypeArguments.Single().Name);*/ throw new NotImplementedException(); + ParseUtilCSharp.AssertGlobal( + "public class G {}", + new TypeDeclaration { + Modifiers = Modifiers.Public, + ClassType = ClassType.Class, + Name = "G", + TypeParameters = { new TypeParameterDeclaration { Name = "T" } } + }); } - - [Test, Ignore] + [Test, Ignore("Constraints not yet supported")] public void GenericClassWithWhere() { - string declr = @" -public class Test where T : IMyInterface -{ -} -"; - TypeDeclaration td = ParseUtilCSharp.ParseGlobal(declr); - - Assert.AreEqual(ClassType.Class, td.ClassType); - Assert.AreEqual("Test", td.Name); - - /*Assert.AreEqual(1, td.Templates.Count); - Assert.AreEqual("T", td.Templates[0].Name); - Assert.AreEqual("IMyInterface", td.Templates[0].Bases[0].Type);*/ throw new NotImplementedException(); + ParseUtilCSharp.AssertGlobal( + @"public class Test where T : IMyInterface { }", + new TypeDeclaration { + Modifiers = Modifiers.Public, + ClassType = ClassType.Class, + Name = "Test", + TypeParameters = { new TypeParameterDeclaration { Name = "T" } }, + Constraints = { + new Constraint { + TypeParameter = "T", + BaseTypes = { new SimpleType("IMyInterface") } + } + }}); } - [Test, Ignore] + [Test, Ignore("Generic classes not yet supported")] public void ComplexGenericClassTypeDeclarationTest() { - string declr = @" -public class Generic : System.IComparable where S : G where T : MyNamespace.IMyInterface -{ -} -"; - TypeDeclaration td = ParseUtilCSharp.ParseGlobal(declr); - - Assert.AreEqual(ClassType.Class, td.ClassType); - Assert.AreEqual("Generic", td.Name); - Assert.AreEqual(Modifiers.Public, td.Modifiers); - /*Assert.AreEqual(1, td.BaseTypes.Count); - Assert.AreEqual("System.IComparable", td.BaseTypes[0].Type); - - Assert.AreEqual(2, td.Templates.Count); - Assert.AreEqual("T", td.Templates[0].Name); - Assert.AreEqual("MyNamespace.IMyInterface", td.Templates[0].Bases[0].Type); - - Assert.AreEqual("S", td.Templates[1].Name); - Assert.AreEqual("G", td.Templates[1].Bases[0].Type); - Assert.AreEqual(1, td.Templates[1].Bases[0].GenericTypes.Count); - Assert.IsTrue(td.Templates[1].Bases[0].GenericTypes[0].IsArrayType); - Assert.AreEqual("T", td.Templates[1].Bases[0].GenericTypes[0].Type); - Assert.AreEqual(new int[] {0}, td.Templates[1].Bases[0].GenericTypes[0].RankSpecifier);*/ throw new NotImplementedException(); + ParseUtilCSharp.AssertGlobal( + "public class Generic : System.IComparable where S : G, new() where T : MyNamespace.IMyInterface", + new TypeDeclaration { + Modifiers = Modifiers.Public, + ClassType = ClassType.Class, + Name = "Generic", + TypeParameters = { + new TypeParameterDeclaration { Variance = VarianceModifier.Contravariant, Name = "T" }, + new TypeParameterDeclaration { Variance = VarianceModifier.Covariant, Name = "S" } + }, + BaseTypes = { + new MemberType { + Target = new SimpleType("System"), + MemberName = "IComparable" + } + }, + Constraints = { + new Constraint { + TypeParameter = "S", + BaseTypes = { + new SimpleType { + Identifier = "G", + TypeArguments = { new SimpleType("T").MakeArrayType() } + }, + new PrimitiveType("new") + } + }, + new Constraint { + TypeParameter = "T", + BaseTypes = { + new MemberType { + Target = new SimpleType("MyNamespace"), + MemberName = "IMyInterface" + } + } + } + } + }); } - [Test, Ignore] + [Test, Ignore("Base types not yet implemented")] public void ComplexClassTypeDeclarationTest() { - string declr = @" + ParseUtilCSharp.AssertGlobal( + @" [MyAttr()] public abstract class MyClass : MyBase, Interface1, My.Test.Interface2 { -} -"; - TypeDeclaration td = ParseUtilCSharp.ParseGlobal(declr); - - Assert.AreEqual(ClassType.Class, td.ClassType); - Assert.AreEqual("MyClass", td.Name); - Assert.AreEqual(Modifiers.Public | Modifiers.Abstract, td.Modifiers); - Assert.AreEqual(1, td.Attributes.Count()); - /* Assert.AreEqual(3, td.BaseTypes.Count); - Assert.AreEqual("MyBase", td.BaseTypes[0].Type); - Assert.AreEqual("Interface1", td.BaseTypes[1].Type); - Assert.AreEqual("My.Test.Interface2", td.BaseTypes[2].Type);*/ throw new NotImplementedException(); +}", + new TypeDeclaration { + Attributes = { + new AttributeSection { + Attributes = { + new Attribute { Type = new SimpleType("MyAttr") } + } + } + }, + Modifiers = Modifiers.Public | Modifiers.Abstract, + ClassType = ClassType.Class, + Name = "MyClass", + BaseTypes = { + new SimpleType("MyBase"), + new SimpleType("Interface1"), + new MemberType { + Target = new MemberType { + Target = new SimpleType("My"), + MemberName = "Test" + }, + MemberName = "Interface2" + } + }}); } [Test] @@ -178,27 +204,37 @@ public abstract class MyClass : MyBase, Interface1, My.Test.Interface2 Assert.AreEqual("MyEnum", td.Name); } - [Test, Ignore] + [Test, Ignore("Mono parser bug?")] public void ContextSensitiveKeywordTest() { - TypeDeclaration td = ParseUtilCSharp.ParseGlobal("partial class partial<[partial: where] where> where where : partial { }"); - - Assert.AreEqual(Modifiers.Partial, td.Modifiers); - Assert.AreEqual("partial", td.Name); - - /* - Assert.AreEqual(1, td.Templates.Count); - TemplateDefinition tp = td.Templates[0]; - Assert.AreEqual("where", tp.Name); - - Assert.AreEqual(1, tp.Attributes.Count); - Assert.AreEqual("partial", tp.Attributes[0].AttributeTarget); - Assert.AreEqual(1, tp.Attributes[0].Attributes.Count); - Assert.AreEqual("where", tp.Attributes[0].Attributes[0].Name); - - Assert.AreEqual(1, tp.Bases.Count); - Assert.AreEqual("partial", tp.Bases[0].Type); - Assert.AreEqual("where", tp.Bases[0].GenericTypes[0].Type);*/ throw new NotImplementedException(); + ParseUtilCSharp.AssertGlobal( + "partial class partial<[partial: where] where> where where : partial { }", + new TypeDeclaration { + Modifiers = Modifiers.Partial, + ClassType = ClassType.Class, + Name = "partial", + TypeParameters = { + new TypeParameterDeclaration { + Attributes = { + new AttributeSection { + AttributeTarget = AttributeTarget.Unknown, + Attributes = { new Attribute { Type = new SimpleType("where") } } + } + }, + Name = "where" + } + }, + Constraints = { + new Constraint { + TypeParameter = "where", + BaseTypes = { + new SimpleType { + Identifier = "partial", + TypeArguments = { new SimpleType("where") } + } + } + } + }}); } [Test] diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/UsingDeclarationTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/UsingDeclarationTests.cs index d79e33fe2..c9d4b7801 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/UsingDeclarationTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/UsingDeclarationTests.cs @@ -43,7 +43,7 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.GeneralScope Assert.AreEqual("My.Name.Space", ud.Namespace); } - [Test] + [Test, Ignore("Aliases to generic types not yet supported")] public void UsingAliasDeclarationTest() { string program = "using TESTME=System;\n" + diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Parser/ParseUtil.cs b/ICSharpCode.NRefactory.Tests/CSharp/Parser/ParseUtil.cs index 94b282539..7522b0284 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Parser/ParseUtil.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Parser/ParseUtil.cs @@ -11,7 +11,7 @@ namespace ICSharpCode.NRefactory.CSharp.Parser /// /// Helper methods for parser unit tests. /// - public class ParseUtilCSharp + public static class ParseUtilCSharp { public static T ParseGlobal(string code, bool expectErrors = false) where T : AstNode { @@ -26,6 +26,14 @@ namespace ICSharpCode.NRefactory.CSharp.Parser return (T)node; } + public static void AssertGlobal(string code, AstNode expectedNode) + { + var node = ParseGlobal(code); + if (expectedNode.Match(node) == null) { + Assert.Fail("Expected '{0}' but was '{1}'", ToCSharp(expectedNode), ToCSharp(node)); + } + } + public static T ParseStatement(string stmt, bool expectErrors = false) where T : AstNode { CSharpParser parser = new CSharpParser(); @@ -39,6 +47,14 @@ namespace ICSharpCode.NRefactory.CSharp.Parser return (T)statement; } + public static void AssertStatement(string code, CSharp.Statement expectedStmt) + { + var stmt = ParseStatement(code); + if (expectedStmt.Match(stmt) == null) { + Assert.Fail("Expected '{0}' but was '{1}'", ToCSharp(expectedStmt), ToCSharp(stmt)); + } + } + public static T ParseExpression(string expr, bool expectErrors = false) where T : AstNode { if (expectErrors) Assert.Ignore("errors not yet implemented"); @@ -53,6 +69,14 @@ namespace ICSharpCode.NRefactory.CSharp.Parser return (T)parsedExpression; } + public static void AssertExpression(string code, CSharp.Expression expectedExpr) + { + var expr = ParseExpression(code); + if (expectedExpr.Match(expr) == null) { + Assert.Fail("Expected '{0}' but was '{1}'", ToCSharp(expectedExpr), ToCSharp(expr)); + } + } + public static T ParseTypeMember(string expr, bool expectErrors = false) where T : AttributedNode { if (expectErrors) Assert.Ignore("errors not yet implemented"); @@ -67,5 +91,20 @@ namespace ICSharpCode.NRefactory.CSharp.Parser Assert.IsTrue(type.IsAssignableFrom(m.GetType()), String.Format("Parsed member was {0} instead of {1} ({2})", m.GetType(), type, m)); return (T)m; } + + public static void AssertTypeMember(string code, CSharp.AttributedNode expectedMember) + { + var member = ParseTypeMember(code); + if (expectedMember.Match(member) == null) { + Assert.Fail("Expected '{0}' but was '{1}'", ToCSharp(expectedMember), ToCSharp(member)); + } + } + + static string ToCSharp(AstNode node) + { + StringWriter w = new StringWriter(); + node.AcceptVisitor(new OutputVisitor(w, new CSharpFormattingPolicy()), null); + return w.ToString(); + } } } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Parser/Statements/FixedStatementTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Parser/Statements/FixedStatementTests.cs index 08ff938b8..bf62bec0e 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Parser/Statements/FixedStatementTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Parser/Statements/FixedStatementTests.cs @@ -6,14 +6,25 @@ using NUnit.Framework; namespace ICSharpCode.NRefactory.CSharp.Parser.Statements { - [TestFixture] + [TestFixture, Ignore("fixed is not implemented")] public class FixedStatementTests { [Test] public void FixedStatementTest() { FixedStatement fixedStmt = ParseUtilCSharp.ParseStatement("fixed (int* ptr = &myIntArr) { }"); - // TODO : Extend test. + ParseUtilCSharp.AssertStatement( + "fixed (int* ptr = &myIntArr) { }", + new FixedStatement { + Type = new PrimitiveType("int").MakePointerType(), + Variables = { + new VariableInitializer { + Name = "ptr", + Initializer = new UnaryOperatorExpression(UnaryOperatorType.AddressOf, new IdentifierExpression("myIntArr")) + } + }, + EmbeddedStatement = new BlockStatement() + }); } } } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Parser/Statements/ForStatementTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Parser/Statements/ForStatementTests.cs index 1d0324f4a..fc18cdab4 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Parser/Statements/ForStatementTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Parser/Statements/ForStatementTests.cs @@ -10,11 +10,17 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.Statements [TestFixture] public class ForStatementTests { - [Test] + [Test, Ignore("variable type in foreach is broken")] public void ForeachStatementTest() { - ForeachStatement foreachStmt = ParseUtilCSharp.ParseStatement("foreach (int i in myColl) {} "); - // TODO : Extend test. + ParseUtilCSharp.AssertStatement( + "foreach (int i in myColl) {} ", + new ForeachStatement { + VariableType = new PrimitiveType("int"), + VariableName = "i", + InExpression = new IdentifierExpression("myColl"), + EmbeddedStatement = new BlockStatement() + }); } [Test, Ignore("for statement is broken when Initializers.Count()!=1")] @@ -40,7 +46,7 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.Statements Assert.IsTrue(inc.Expression is UnaryOperatorExpression); } - [Test, Ignore("for statement is broken when Initializers.Count()!=1")] + [Test] public void ForStatementTestMultipleInitializers() { ForStatement forStmt = ParseUtilCSharp.ParseStatement("for (i = 0, j = 1; i < 6; ++i) {} "); @@ -48,10 +54,12 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.Statements Assert.IsTrue(forStmt.Iterators.All(i => i is ExpressionStatement)); } - [Test, Ignore("for statement is broken when Iterators.Count()!=1")] + [Test] public void ForStatementTestMultipleIterators() { - ForStatement forStmt = ParseUtilCSharp.ParseStatement("for (int i = 5; i < 6; ++i, j--) {} "); + ForStatement forStmt = ParseUtilCSharp.ParseStatement("for (int i = 5, j = 10; i < 6; ++i, j--) {} "); + Assert.AreEqual(1, forStmt.Initializers.Count()); + Assert.AreEqual(2, ((VariableDeclarationStatement)forStmt.Initializers.Single()).Variables.Count()); Assert.AreEqual(2, forStmt.Iterators.Count()); Assert.IsTrue(forStmt.Iterators.All(i => i is ExpressionStatement)); } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Parser/Statements/TryCatchStatementTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Parser/Statements/TryCatchStatementTests.cs index 202b7f0ae..7187f4b5d 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Parser/Statements/TryCatchStatementTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Parser/Statements/TryCatchStatementTests.cs @@ -7,7 +7,7 @@ using NUnit.Framework; namespace ICSharpCode.NRefactory.CSharp.Parser.Statements { - [TestFixture, Ignore] + [TestFixture] public class TryCatchStatementTests { [Test] @@ -20,28 +20,54 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.Statements Assert.AreEqual(string.Empty, tryCatchStatement.CatchClauses.Single().VariableName); } - /* TODO port tests [Test] public void SimpleTryCatchStatementTest2() { - TryCatchStatement tryCatchStatement = ParseUtilCSharp.ParseStatement("try { } catch (Exception e) { } "); - Assert.IsTrue(tryCatchStatement.FinallyBlock.IsNull); - Assert.AreEqual(1, tryCatchStatement.CatchClauses.Count); - Assert.AreEqual("Exception", tryCatchStatement.CatchClauses[0].TypeReference.Type); - Assert.AreEqual("e", tryCatchStatement.CatchClauses[0].VariableName); + ParseUtilCSharp.AssertStatement( + "try { } catch (Exception e) { } ", + new TryCatchStatement { + TryBlock = new BlockStatement(), + CatchClauses = { + new CatchClause { + Type = new SimpleType("Exception"), + VariableName = "e", + Body = new BlockStatement() + } + }}); } [Test] public void SimpleTryCatchFinallyStatementTest() { - TryCatchStatement tryCatchStatement = ParseUtilCSharp.ParseStatement("try { } catch (Exception) { } catch { } finally { } "); - Assert.IsFalse(tryCatchStatement.FinallyBlock.IsNull); - Assert.AreEqual(2, tryCatchStatement.CatchClauses.Count); - Assert.AreEqual("Exception", tryCatchStatement.CatchClauses[0].TypeReference.Type); - Assert.IsEmpty(tryCatchStatement.CatchClauses[0].VariableName); - Assert.IsTrue(tryCatchStatement.CatchClauses[1].TypeReference.IsNull); - Assert.IsEmpty(tryCatchStatement.CatchClauses[1].VariableName); + ParseUtilCSharp.AssertStatement( + "try { } catch (Exception) { } catch { } finally { } ", + new TryCatchStatement { + TryBlock = new BlockStatement(), + CatchClauses = { + new CatchClause { + Type = new SimpleType("Exception"), + Body = new BlockStatement() + }, + new CatchClause { Body = new BlockStatement() } + }, + FinallyBlock = new BlockStatement() + }); + } + + [Test] + public void TestEmptyFinallyDoesNotMatchNullFinally() + { + TryCatchStatement c1 = new TryCatchStatement { + TryBlock = new BlockStatement(), + CatchClauses = { new CatchClause { Body = new BlockStatement() } } + }; + TryCatchStatement c2 = new TryCatchStatement { + TryBlock = new BlockStatement(), + CatchClauses = { new CatchClause { Body = new BlockStatement() } }, + FinallyBlock = new BlockStatement() + }; + Assert.IsNull(c1.Match(c2)); + Assert.IsNull(c2.Match(c1)); // and vice versa } - */ } } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Parser/Statements/YieldStatementTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Parser/Statements/YieldStatementTests.cs index ae5598f2c..ae4d75d93 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Parser/Statements/YieldStatementTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Parser/Statements/YieldStatementTests.cs @@ -21,8 +21,7 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.Statements [Test] public void YieldBreakStatementTest() { - YieldStatement yieldStmt = ParseUtilCSharp.ParseStatement("yield break;"); - Assert.IsTrue(yieldStmt.Expression.IsNull); + ParseUtilCSharp.ParseStatement("yield break;"); } [Test] diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/EventDeclarationTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/EventDeclarationTests.cs index fe1bd468c..7e9d13453 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/EventDeclarationTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/EventDeclarationTests.cs @@ -6,79 +6,84 @@ using NUnit.Framework; namespace ICSharpCode.NRefactory.CSharp.Parser.TypeMembers { - [TestFixture, Ignore] + [TestFixture, Ignore("events are broken")] public class EventDeclarationTests { [Test] public void SimpleEventDeclarationTest() { - CustomEventDeclaration ed = ParseUtilCSharp.ParseTypeMember("event System.EventHandler MyEvent;"); - Assert.AreEqual("MyEvent", ed.Name); - //Assert.AreEqual("System.EventHandler", ed.TypeReference.Type); - Assert.Ignore(); // check type - - Assert.IsTrue(ed.AddAccessor.IsNull); - Assert.IsTrue(ed.RemoveAccessor.IsNull); + ParseUtilCSharp.AssertTypeMember( + "event EventHandler MyEvent;", + new EventDeclaration { + ReturnType = new SimpleType("EventHandler"), + Variables = { + new VariableInitializer { + Name = "MyEvent" + } + }}); } - /* TODO Port tests [Test] public void MultipleEventDeclarationTest() { - TypeDeclaration t = ParseUtilCSharp.ParseGlobal("class C { public event EventHandler A, B; }"); - Assert.AreEqual(2, t.Children.Count); - - EventDeclaration ed = (EventDeclaration)t.Children[0]; - Assert.AreEqual(Modifiers.Public, ed.Modifier); - Assert.AreEqual("EventHandler", ed.TypeReference.Type); - Assert.AreEqual("A", ed.Name); - - ed = (EventDeclaration)t.Children[1]; - Assert.AreEqual(Modifiers.Public, ed.Modifier); - Assert.AreEqual("EventHandler", ed.TypeReference.Type); - Assert.AreEqual("B", ed.Name); + ParseUtilCSharp.AssertTypeMember( + "public event EventHandler A = null, B = delegate {};", + new EventDeclaration { + Modifiers = Modifiers.Public, + ReturnType = new SimpleType("EventHandler"), + Variables = { + new VariableInitializer { + Name = "A", + Initializer = new NullReferenceExpression() + }, + new VariableInitializer { + Name = "B", + Initializer = new AnonymousMethodExpression() + } + }}); } [Test] - public void EventImplementingInterfaceDeclarationTest() + public void AddRemoveEventDeclarationTest() { - EventDeclaration ed = ParseUtilCSharp.ParseTypeMember("event EventHandler MyInterface.MyEvent;"); - - Assert.AreEqual("MyEvent", ed.Name); - Assert.AreEqual("EventHandler", ed.TypeReference.Type); - - Assert.IsFalse(ed.HasAddRegion); - Assert.IsFalse(ed.HasRemoveRegion); - - Assert.AreEqual("MyInterface", ed.InterfaceImplementations[0].InterfaceType.Type); - Assert.AreEqual("MyEvent", ed.InterfaceImplementations[0].MemberName); + ParseUtilCSharp.AssertTypeMember( + "public event System.EventHandler MyEvent { add { } remove { } }", + new CustomEventDeclaration { + Modifiers = Modifiers.Public, + ReturnType = new MemberType { + Target = new SimpleType("System"), + MemberName = "EventHandler" + }, + Name = "MyEvent", + AddAccessor = new Accessor { Body = new BlockStatement() }, + RemoveAccessor = new Accessor { Body = new BlockStatement() } + }); } [Test] public void EventImplementingGenericInterfaceDeclarationTest() { - EventDeclaration ed = ParseUtilCSharp.ParseTypeMember("event EventHandler MyInterface.MyEvent;"); - - Assert.AreEqual("MyEvent", ed.Name); - Assert.AreEqual("EventHandler", ed.TypeReference.Type); - - Assert.IsFalse(ed.HasAddRegion); - Assert.IsFalse(ed.HasRemoveRegion); - - Assert.AreEqual("MyInterface", ed.InterfaceImplementations[0].InterfaceType.Type); - Assert.AreEqual("System.String", ed.InterfaceImplementations[0].InterfaceType.GenericTypes[0].Type); - Assert.AreEqual("MyEvent", ed.InterfaceImplementations[0].MemberName); + ParseUtilCSharp.AssertTypeMember( + "event EventHandler MyInterface.MyEvent { add { } [Attr] remove {} }", + new CustomEventDeclaration { + ReturnType = new SimpleType("EventHandler"), + PrivateImplementationType = new SimpleType{ + Identifier = "MyInterface", + TypeArguments = { new PrimitiveType("string") } + }, + Name = "MyEvent", + AddAccessor = new Accessor { Body = new BlockStatement() }, + RemoveAccessor = new Accessor { + Attributes = { + new AttributeSection { + Attributes = { + new Attribute { Type = new SimpleType("Attr") } + } + } + }, + Body = new BlockStatement() + } + }); } - - [Test] - public void AddRemoveEventDeclarationTest() - { - EventDeclaration ed = ParseUtilCSharp.ParseTypeMember("event System.EventHandler MyEvent { add { } remove { } }"); - Assert.AreEqual("MyEvent", ed.Name); - Assert.AreEqual("System.EventHandler", ed.TypeReference.Type); - - Assert.IsTrue(ed.HasAddRegion); - Assert.IsTrue(ed.HasRemoveRegion); - }*/ } } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/FieldDeclarationTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/FieldDeclarationTests.cs index f91cbed4a..6f47dc588 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/FieldDeclarationTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/FieldDeclarationTests.cs @@ -6,22 +6,62 @@ using NUnit.Framework; namespace ICSharpCode.NRefactory.CSharp.Parser.TypeMembers { - [TestFixture, Ignore] + [TestFixture] public class FieldDeclarationTests { - [Test] + [Test, Ignore("multidimensional array rank incorrect?")] public void SimpleFieldDeclarationTest() { - throw new NotImplementedException(); - /* - FieldDeclaration fd = ParseUtilCSharp.ParseTypeMember("int[,,,] myField;"); - Assert.AreEqual("System.Int32", fd.TypeReference.Type); - Assert.AreEqual(new int[] { 3 } , fd.TypeReference.RankSpecifier); - Assert.AreEqual(1, fd.Fields.Count); - - Assert.AreEqual("myField", ((VariableDeclaration)fd.Fields[0]).Name);*/ + ParseUtilCSharp.AssertTypeMember( + "int[,,,] myField;", + new FieldDeclaration { + ReturnType = new PrimitiveType("int").MakeArrayType(4), + Variables = { new VariableInitializer("myField") } + }); + } + + [Test] + public void MultipleFieldDeclarationTest() + { + ParseUtilCSharp.AssertTypeMember( + "int a = 1, b = 2;", + new FieldDeclaration { + ReturnType = new PrimitiveType("int"), + Variables = { + new VariableInitializer("a", new PrimitiveExpression(1)), + new VariableInitializer("b", new PrimitiveExpression(2)), + } + }); } - // TODO add more tests + [Test] + public void FieldWithArrayInitializer() + { + ParseUtilCSharp.AssertTypeMember( + "public static readonly int[] arr = { 1, 2, 3 };", + new FieldDeclaration { + Modifiers = Modifiers.Public | Modifiers.Static | Modifiers.Readonly, + ReturnType = new PrimitiveType("int").MakeArrayType(), + Variables = { + new VariableInitializer { + Name = "arr", + Initializer = new ArrayInitializerExpression { + Elements = { + new PrimitiveExpression(1), + new PrimitiveExpression(2), + new PrimitiveExpression(3) + } + } + } + }}); + } + + [Test, Ignore("How do we represent fixed-size fields in the AST?")] + public void FieldWithFixedSize() + { + ParseUtilCSharp.AssertTypeMember( + "public unsafe fixed int Field[100];", + new FieldDeclaration()); + } } } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/IndexerDeclarationTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/IndexerDeclarationTests.cs index 90f14b26e..5353808fc 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/IndexerDeclarationTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/IndexerDeclarationTests.cs @@ -13,13 +13,16 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.TypeMembers [Test] public void IndexerDeclarationTest() { - IndexerDeclaration id = ParseUtilCSharp.ParseTypeMember("int this[int a, string b] { get { } set { } }"); + IndexerDeclaration id = ParseUtilCSharp.ParseTypeMember("public int this[int a, string b] { get { } protected set { } }"); Assert.AreEqual(2, id.Parameters.Count()); Assert.IsNotNull(id.Getter, "No get region found!"); Assert.IsNotNull(id.Setter, "No set region found!"); + Assert.AreEqual(Modifiers.Public, id.Modifiers); + Assert.AreEqual(Modifiers.None, id.Getter.Modifiers); + Assert.AreEqual(Modifiers.Protected, id.Setter.Modifiers); } - [Test, Ignore("type reference is not yet implemented")] + [Test, Ignore("explicit interface implementation not yet supported")] public void IndexerImplementingInterfaceTest() { IndexerDeclaration id = ParseUtilCSharp.ParseTypeMember("int MyInterface.this[int a, string b] { get { } set { } }"); @@ -27,21 +30,29 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.TypeMembers Assert.IsNotNull(id.Getter, "No get region found!"); Assert.IsNotNull(id.Setter, "No set region found!"); - Assert.AreEqual("MyInterface", id.PrivateImplementationType); + Assert.AreEqual("MyInterface", ((SimpleType)id.PrivateImplementationType).Identifier); } - [Test, Ignore] + [Test, Ignore("explicit interface implementation not yet supported")] public void IndexerImplementingGenericInterfaceTest() { - throw new NotImplementedException(); - /* - IndexerDeclaration id = ParseUtilCSharp.ParseTypeMember("int MyInterface.this[int a, string b] { get { } set { } }"); - Assert.AreEqual(2, id.Parameters.Count); - Assert.IsNotNull(id.GetAccessor, "No get region found!"); - Assert.IsNotNull(id.SetAccessor, "No set region found!"); - - Assert.AreEqual("MyInterface", id.InterfaceImplementations[0].InterfaceType.Type); - Assert.AreEqual("System.String", id.InterfaceImplementations[0].InterfaceType.GenericTypes[0].Type);*/ + ParseUtilCSharp.AssertTypeMember( + "int MyInterface.this[int a, string b] { get { } [Attr] set { } }", + new IndexerDeclaration { + ReturnType = new PrimitiveType("int"), + PrivateImplementationType = new SimpleType { + Identifier = "MyInterface", + TypeArguments = { new PrimitiveType("string") } + }, + Parameters = { + new ParameterDeclaration(new PrimitiveType("int"), "a"), + new ParameterDeclaration(new PrimitiveType("string"), "b") + }, + Getter = new Accessor { Body = new BlockStatement() }, + Setter = new Accessor { + Attributes = { new AttributeSection(new Attribute { Type = new SimpleType("Attr") }) }, + Body = new BlockStatement() + }}); } } } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/MethodDeclarationTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/MethodDeclarationTests.cs index 53e0f3138..e3302d7c0 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/MethodDeclarationTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/MethodDeclarationTests.cs @@ -3,49 +3,50 @@ using System; using System.Linq; +using ICSharpCode.NRefactory.TypeSystem; using NUnit.Framework; namespace ICSharpCode.NRefactory.CSharp.Parser.TypeMembers { - [TestFixture] + [TestFixture, Ignore("Generics not yet implemented")] public class MethodDeclarationTests { - [Test, Ignore("type references not yet implemented")] + [Test] public void SimpleMethodDeclarationTest() { MethodDeclaration md = ParseUtilCSharp.ParseTypeMember("void MyMethod() {} "); - Assert.AreEqual("System.Void", md.ReturnType); + Assert.AreEqual("void", ((PrimitiveType)md.ReturnType).Keyword); Assert.AreEqual(0, md.Parameters.Count()); Assert.IsFalse(md.IsExtensionMethod); } - [Test, Ignore("type references not yet implemented")] + [Test] public void AbstractMethodDeclarationTest() { MethodDeclaration md = ParseUtilCSharp.ParseTypeMember("abstract void MyMethod();"); - Assert.AreEqual("System.Void", md.ReturnType); + Assert.AreEqual("void", ((PrimitiveType)md.ReturnType).Keyword); Assert.AreEqual(0, md.Parameters.Count()); Assert.IsFalse(md.IsExtensionMethod); Assert.IsTrue(md.Body.IsNull); Assert.AreEqual(Modifiers.Abstract, md.Modifiers); } - [Test, Ignore("type references not yet implemented")] + [Test] public void DefiningPartialMethodDeclarationTest() { MethodDeclaration md = ParseUtilCSharp.ParseTypeMember("partial void MyMethod();"); - Assert.AreEqual("System.Void", md.ReturnType); + Assert.AreEqual("void", ((PrimitiveType)md.ReturnType).Keyword); Assert.AreEqual(0, md.Parameters.Count()); Assert.IsFalse(md.IsExtensionMethod); Assert.IsTrue(md.Body.IsNull); Assert.AreEqual(Modifiers.Partial, md.Modifiers); } - [Test, Ignore("type references not yet implemented")] + [Test] public void ImplementingPartialMethodDeclarationTest() { MethodDeclaration md = ParseUtilCSharp.ParseTypeMember("partial void MyMethod() { }"); - Assert.AreEqual("System.Void", md.ReturnType); + Assert.AreEqual("void", ((PrimitiveType)md.ReturnType).Keyword); Assert.AreEqual(0, md.Parameters.Count()); Assert.IsFalse(md.IsExtensionMethod); Assert.IsFalse(md.Body.IsNull); @@ -81,6 +82,7 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.TypeMembers Assert.AreEqual(2, md.StartLocation.Line, "StartLocation.Y"); Assert.AreEqual(5, md.EndLocation.Line, "EndLocation.Y"); Assert.AreEqual(3, md.StartLocation.Column, "StartLocation.X"); + Assert.AreEqual(4, md.EndLocation.Column, "EndLocation.X"); } [Test] @@ -89,142 +91,176 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.TypeMembers MethodDeclaration md = ParseUtilCSharp.ParseTypeMember("void MyMethod(int) {} ", true); Assert.AreEqual("System.Void", md.ReturnType); Assert.AreEqual(1, md.Parameters.Count()); - //Assert.AreEqual("?", ((ParameterDeclarationExpression)md.Parameters[0]).ParameterName); + Assert.AreEqual("int", ((PrimitiveType)md.Parameters.Single().Type).Keyword); } - /* TODO: port unit tests [Test] public void GenericVoidMethodDeclarationTest() { - MethodDeclaration md = ParseUtilCSharp.ParseTypeMember("void MyMethod(T a) {} "); - Assert.AreEqual("System.Void", md.ReturnType); - Assert.AreEqual(1, md.Parameters.Count()); - Assert.AreEqual("T", md.Parameters.Single().Type); - Assert.AreEqual("a", md.Parameters.Single().Name); - - Assert.AreEqual(1, md.TypeParameters.Count()); - Assert.AreEqual("T", md.Templates[0].Name); + ParseUtilCSharp.AssertTypeMember( + "void MyMethod(T a) {} ", + new MethodDeclaration { + ReturnType = new PrimitiveType("void"), + Name = "MyMethod", + TypeParameters = { new TypeParameterDeclaration { Name = "T" } }, + Parameters = { new ParameterDeclaration(new SimpleType("T"), "a") }, + Body = new BlockStatement() + }); } [Test] public void GenericMethodDeclarationTest() { - MethodDeclaration md = ParseUtilCSharp.ParseTypeMember("T MyMethod(T a) {} "); - Assert.AreEqual("T", md.TypeReference.Type); - Assert.AreEqual(1, md.Parameters.Count); - Assert.AreEqual("T", ((ParameterDeclarationExpression)md.Parameters[0]).TypeReference.Type); - Assert.AreEqual("a", ((ParameterDeclarationExpression)md.Parameters[0]).ParameterName); - - Assert.AreEqual(1, md.Templates.Count); - Assert.AreEqual("T", md.Templates[0].Name); + ParseUtilCSharp.AssertTypeMember( + "T MyMethod(T a) {} ", + new MethodDeclaration { + ReturnType = new SimpleType("T"), + Name = "MyMethod", + TypeParameters = { new TypeParameterDeclaration { Name = "T" } }, + Parameters = { new ParameterDeclaration(new SimpleType("T"), "a") }, + Body = new BlockStatement() + }); } [Test] public void GenericMethodDeclarationWithConstraintTest() { - string program = "T MyMethod(T a) where T : ISomeInterface {} "; - MethodDeclaration md = ParseUtilCSharp.ParseTypeMember(program); - Assert.AreEqual("T", md.TypeReference.Type); - Assert.AreEqual(1, md.Parameters.Count); - Assert.AreEqual("T", ((ParameterDeclarationExpression)md.Parameters[0]).TypeReference.Type); - Assert.AreEqual("a", ((ParameterDeclarationExpression)md.Parameters[0]).ParameterName); - - Assert.AreEqual(1, md.Templates.Count); - Assert.AreEqual("T", md.Templates[0].Name); - Assert.AreEqual(1, md.Templates[0].Bases.Count); - Assert.AreEqual("ISomeInterface", md.Templates[0].Bases[0].Type); + ParseUtilCSharp.AssertTypeMember( + "T MyMethod(T a) where T : ISomeInterface {} ", + new MethodDeclaration { + ReturnType = new SimpleType("T"), + Name = "MyMethod", + TypeParameters = { new TypeParameterDeclaration { Name = "T" } }, + Parameters = { new ParameterDeclaration(new SimpleType("T"), "a") }, + Constraints = { + new Constraint { + TypeParameter = "T", + BaseTypes = { new SimpleType("ISomeInterface") } + } + }, + Body = new BlockStatement() + }); } [Test] public void GenericMethodInInterface() { - const string program = @"interface MyInterface { + ParseUtilCSharp.AssertGlobal( + @"interface MyInterface { T MyMethod(T a) where T : ISomeInterface; } -"; - TypeDeclaration td = ParseUtilCSharp.ParseGlobal(program); - MethodDeclaration md = (MethodDeclaration)td.Children[0]; - Assert.AreEqual("T", md.TypeReference.Type); - Assert.AreEqual(1, md.Parameters.Count); - Assert.AreEqual("T", ((ParameterDeclarationExpression)md.Parameters[0]).TypeReference.Type); - Assert.AreEqual("a", ((ParameterDeclarationExpression)md.Parameters[0]).ParameterName); - - Assert.AreEqual(1, md.Templates.Count); - Assert.AreEqual("T", md.Templates[0].Name); - Assert.AreEqual(1, md.Templates[0].Bases.Count); - Assert.AreEqual("ISomeInterface", md.Templates[0].Bases[0].Type); +", + new TypeDeclaration { + ClassType = ClassType.Interface, + Members = { + new MethodDeclaration { + ReturnType = new SimpleType("T"), + Name = "MyMethod", + TypeParameters = { new TypeParameterDeclaration { Name = "T" } }, + Parameters = { new ParameterDeclaration(new SimpleType("T"), "a") }, + Constraints = { + new Constraint { + TypeParameter = "T", + BaseTypes = { new SimpleType("ISomeInterface") } + } + } + }}}); } [Test] public void GenericVoidMethodInInterface() { - const string program = @"interface MyInterface { + ParseUtilCSharp.AssertGlobal( + @"interface MyInterface { void MyMethod(T a) where T : ISomeInterface; } -"; - TypeDeclaration td = ParseUtilCSharp.ParseGlobal(program); - MethodDeclaration md = (MethodDeclaration)td.Children[0]; - Assert.AreEqual("System.Void", md.TypeReference.Type); - Assert.AreEqual(1, md.Parameters.Count); - Assert.AreEqual("T", ((ParameterDeclarationExpression)md.Parameters[0]).TypeReference.Type); - Assert.AreEqual("a", ((ParameterDeclarationExpression)md.Parameters[0]).ParameterName); - - Assert.AreEqual(1, md.Templates.Count); - Assert.AreEqual("T", md.Templates[0].Name); - Assert.AreEqual(1, md.Templates[0].Bases.Count); - Assert.AreEqual("ISomeInterface", md.Templates[0].Bases[0].Type); +", + new TypeDeclaration { + ClassType = ClassType.Interface, + Members = { + new MethodDeclaration { + ReturnType = new PrimitiveType("void"), + Name = "MyMethod", + TypeParameters = { new TypeParameterDeclaration { Name = "T" } }, + Parameters = { new ParameterDeclaration(new SimpleType("T"), "a") }, + Constraints = { + new Constraint { + TypeParameter = "T", + BaseTypes = { new SimpleType("ISomeInterface") } + } + } + }}}); } [Test] public void ShadowingMethodInInterface() { - const string program = @"interface MyInterface : IDisposable { + ParseUtilCSharp.AssertGlobal( + @"interface MyInterface : IDisposable { new void Dispose(); } -"; - TypeDeclaration td = ParseUtilCSharp.ParseGlobal(program); - MethodDeclaration md = (MethodDeclaration)td.Children[0]; - Assert.AreEqual("System.Void", md.TypeReference.Type); - Assert.AreEqual(0, md.Parameters.Count); - Assert.AreEqual(Modifiers.New, md.Modifier); +", + new TypeDeclaration { + ClassType = ClassType.Interface, + BaseTypes = { new SimpleType("IDisposable") }, + Members = { + new MethodDeclaration { + Modifiers = Modifiers.New, + ReturnType = new PrimitiveType("void"), + Name = "Dispose" + }}}); } [Test] public void MethodImplementingInterfaceTest() { - MethodDeclaration md = ParseUtilCSharp.ParseTypeMember("int MyInterface.MyMethod() {} "); - Assert.AreEqual("System.Int32", md.TypeReference.Type); - - Assert.AreEqual("MyInterface", md.InterfaceImplementations[0].InterfaceType.Type); + ParseUtilCSharp.AssertGlobal( + "int MyInterface.MyMethod() {} ", + new MethodDeclaration { + ReturnType = new PrimitiveType("int"), + PrivateImplementationType = new SimpleType("MyInterface"), + Name = "MyMethod", + Body = new BlockStatement() + }); } [Test] public void MethodImplementingGenericInterfaceTest() { - MethodDeclaration md = ParseUtilCSharp.ParseTypeMember("int MyInterface.MyMethod() {} "); - Assert.AreEqual("System.Int32", md.TypeReference.Type); - - Assert.AreEqual("MyInterface", md.InterfaceImplementations[0].InterfaceType.Type); - Assert.AreEqual("System.String", md.InterfaceImplementations[0].InterfaceType.GenericTypes[0].Type); + ParseUtilCSharp.AssertGlobal( + "int MyInterface.MyMethod() {} ", + new MethodDeclaration { + ReturnType = new PrimitiveType("int"), + PrivateImplementationType = new SimpleType("MyInterface") { TypeArguments = { new PrimitiveType("string") } }, + Name = "MyMethod", + Body = new BlockStatement() + }); } [Test] public void VoidMethodImplementingInterfaceTest() { - MethodDeclaration md = ParseUtilCSharp.ParseTypeMember("void MyInterface.MyMethod() {} "); - Assert.AreEqual("System.Void", md.TypeReference.Type); - - Assert.AreEqual("MyInterface", md.InterfaceImplementations[0].InterfaceType.Type); + ParseUtilCSharp.AssertGlobal( + "void MyInterface.MyMethod() {} ", + new MethodDeclaration { + ReturnType = new PrimitiveType("void"), + PrivateImplementationType = new SimpleType("MyInterface"), + Name = "MyMethod", + Body = new BlockStatement() + }); } [Test] public void VoidMethodImplementingGenericInterfaceTest() { - MethodDeclaration md = ParseUtilCSharp.ParseTypeMember("void MyInterface.MyMethod() {} "); - Assert.AreEqual("System.Void", md.TypeReference.Type); - - Assert.AreEqual("MyInterface", md.InterfaceImplementations[0].InterfaceType.Type); - Assert.AreEqual("System.String", md.InterfaceImplementations[0].InterfaceType.GenericTypes[0].Type); + ParseUtilCSharp.AssertGlobal( + "void MyInterface.MyMethod() {} ", + new MethodDeclaration { + ReturnType = new PrimitiveType("void"), + PrivateImplementationType = new SimpleType("MyInterface"), + Name = "MyMethod", + Body = new BlockStatement() + }); } [Test] @@ -234,9 +270,9 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.TypeMembers "void a() where T { }", true // expect errors ); Assert.AreEqual("a", md.Name); - Assert.AreEqual(1, md.Templates.Count); - Assert.AreEqual("T", md.Templates[0].Name); - Assert.AreEqual(0, md.Templates[0].Bases.Count); + Assert.AreEqual(1, md.TypeParameters.Count); + Assert.AreEqual("T", md.TypeParameters.Single().Name); + Assert.AreEqual(0, md.Constraints.Count()); } [Test] @@ -246,11 +282,11 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.TypeMembers "public static int ToInt32(this string s) { return int.Parse(s); }" ); Assert.AreEqual("ToInt32", md.Name); + Assert.AreEqual("s", md.Parameters.First().Name); + Assert.AreEqual(ParameterModifier.This, md.Parameters.First().ParameterModifier); + Assert.AreEqual("string", ((PrimitiveType)md.Parameters.First().Type).Keyword); Assert.IsTrue(md.IsExtensionMethod); - Assert.AreEqual("s", md.Parameters[0].ParameterName); - Assert.AreEqual("System.String", md.Parameters[0].TypeReference.Type); } - */ [Test] public void VoidExtensionMethodTest() @@ -265,7 +301,6 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.TypeMembers Assert.IsTrue(md.IsExtensionMethod); } - /* TODO [Test] public void MethodWithEmptyAssignmentErrorInBody() { @@ -277,27 +312,32 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.TypeMembers "}", true // expect errors ); Assert.AreEqual("A", md.Name); - Assert.AreEqual(new Location(1, 2), md.Body.StartLocation); - Assert.AreEqual(new Location(2, 5), md.Body.EndLocation); + Assert.AreEqual(new AstLocation(1, 2), md.Body.StartLocation); + Assert.AreEqual(new AstLocation(2, 5), md.Body.EndLocation); } [Test] public void OptionalParameterTest() { - MethodDeclaration md = ParseUtilCSharp.ParseTypeMember( - "public void Foo(string bar = null, int baz = 0) { }" - ); - Assert.AreEqual("Foo", md.Name); - - Assert.AreEqual("bar", md.Parameters[0].ParameterName); - Assert.AreEqual("System.String", md.Parameters[0].TypeReference.Type); - Assert.AreEqual(ParameterModifiers.In | ParameterModifiers.Optional, md.Parameters[0].ParamModifier); - Assert.IsNull(((PrimitiveExpression)md.Parameters[0].DefaultValue).Value); - - Assert.AreEqual("baz", md.Parameters[1].ParameterName); - Assert.AreEqual("System.Int32", md.Parameters[1].TypeReference.Type); - Assert.AreEqual(ParameterModifiers.In | ParameterModifiers.Optional, md.Parameters[1].ParamModifier); - Assert.AreEqual(0, ((PrimitiveExpression)md.Parameters[1].DefaultValue).Value); - }*/ + ParseUtilCSharp.AssertTypeMember( + "public void Foo(string bar = null, int baz = 0) { }", + new MethodDeclaration { + Modifiers = Modifiers.Public, + ReturnType = new PrimitiveType("void"), + Name = "Foo", + Body = new BlockStatement(), + Parameters = { + new ParameterDeclaration { + Type = new PrimitiveType("string"), + Name = "bar", + DefaultExpression = new NullReferenceExpression() + }, + new ParameterDeclaration { + Type = new PrimitiveType("int"), + Name = "baz", + DefaultExpression = new PrimitiveExpression(0) + } + }}); + } } } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/OperatorDeclarationTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/OperatorDeclarationTests.cs index e2901f54e..4956d374a 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/OperatorDeclarationTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/OperatorDeclarationTests.cs @@ -10,43 +10,43 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.TypeMembers [TestFixture] public class OperatorDeclarationTests { - [Test, Ignore("type references not yet implemented")] + [Test] public void ImplictOperatorDeclarationTest() { OperatorDeclaration od = ParseUtilCSharp.ParseTypeMember("public static implicit operator double(MyObject f) { return 0.5d; }"); Assert.AreEqual(OperatorType.Implicit, od.OperatorType); Assert.AreEqual(1, od.Parameters.Count()); - Assert.AreEqual("System.Double", od.ReturnType); + Assert.AreEqual("double", ((PrimitiveType)od.ReturnType).Keyword); Assert.AreEqual("op_Implicit", od.Name); } - [Test, Ignore("type references not yet implemented")] + [Test] public void ExplicitOperatorDeclarationTest() { OperatorDeclaration od = ParseUtilCSharp.ParseTypeMember("public static explicit operator double(MyObject f) { return 0.5d; }"); Assert.AreEqual(OperatorType.Explicit, od.OperatorType); Assert.AreEqual(1, od.Parameters.Count()); - Assert.AreEqual("System.Double", od.ReturnType); + Assert.AreEqual("double", ((PrimitiveType)od.ReturnType).Keyword); Assert.AreEqual("op_Explicit", od.Name); } - [Test, Ignore("type references not yet implemented")] + [Test] public void BinaryPlusOperatorDeclarationTest() { OperatorDeclaration od = ParseUtilCSharp.ParseTypeMember("public static MyObject operator +(MyObject a, MyObject b) {}"); Assert.AreEqual(OperatorType.Addition, od.OperatorType); Assert.AreEqual(2, od.Parameters.Count()); - Assert.AreEqual("MyObject", od.ReturnType); + Assert.AreEqual("MyObject", ((SimpleType)od.ReturnType).Identifier); Assert.AreEqual("op_Addition", od.Name); } - [Test, Ignore("type references not yet implemented")] + [Test] public void UnaryPlusOperatorDeclarationTest() { OperatorDeclaration od = ParseUtilCSharp.ParseTypeMember("public static MyObject operator +(MyObject a) {}"); Assert.AreEqual(OperatorType.UnaryPlus, od.OperatorType); Assert.AreEqual(1, od.Parameters.Count()); - Assert.AreEqual("MyObject", od.ReturnType); + Assert.AreEqual("MyObject", ((SimpleType)od.ReturnType).Identifier); Assert.AreEqual("op_UnaryPlus", od.Name); } } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/PropertyDeclarationTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/PropertyDeclarationTests.cs index 5c4bebed3..fba68f26e 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/PropertyDeclarationTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/PropertyDeclarationTests.cs @@ -66,7 +66,7 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.TypeMembers Assert.AreEqual(new AstLocation(4, code.IndexOf("}\n\t}") + 1 - line4Pos + 1), pd.Setter.Body.EndLocation); } - [Test, Ignore("type references not yet implemented")] + [Test, Ignore("explicit interface implementation not yet implemented")] public void PropertyImplementingInterfaceTest() { PropertyDeclaration pd = ParseUtilCSharp.ParseTypeMember("int MyInterface.MyProperty { get {} } "); @@ -74,10 +74,10 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.TypeMembers Assert.IsFalse(pd.Getter.IsNull); Assert.IsTrue(pd.Setter.IsNull); - Assert.AreEqual("MyInterface", pd.PrivateImplementationType); + Assert.AreEqual("MyInterface", ((SimpleType)pd.PrivateImplementationType).Identifier); } - [Test, Ignore("type references not yet implemented")] + [Test, Ignore("explicit interface implementation not yet implemented")] public void PropertyImplementingGenericInterfaceTest() { PropertyDeclaration pd = ParseUtilCSharp.ParseTypeMember("int MyInterface.MyProperty { get {} } "); @@ -85,9 +85,7 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.TypeMembers Assert.IsFalse(pd.Getter.IsNull); Assert.IsTrue(pd.Setter.IsNull); - throw new NotImplementedException(); - //Assert.AreEqual("MyInterface", pd.InterfaceImplementations[0].InterfaceType.Type); - //Assert.AreEqual("System.String", pd.InterfaceImplementations[0].InterfaceType.GenericTypes[0].Type); + Assert.IsNotNull(new SimpleType { Identifier = "MyInterface", TypeArguments = { new PrimitiveType("string") } }.Match(pd.PrivateImplementationType)); } } } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/InvocationTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/InvocationTests.cs index 11ab8c47c..2f84aa28c 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/InvocationTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/InvocationTests.cs @@ -122,7 +122,7 @@ class A { Assert.AreEqual("System.Void", Resolve(program).Type.ReflectionName); } - [Test] + [Test, Ignore("parser is broken for events")] public void EventCallTest() { string program = @"using System; diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/NameLookupTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/NameLookupTests.cs index 374817f4d..40cd75b3b 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/NameLookupTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/NameLookupTests.cs @@ -366,7 +366,7 @@ class TestClass { Assert.AreEqual("System.Collections.ArrayList", member.Type.FullName, "the full type should be resolved"); } - [Test] + [Test, Ignore("Parser position bug")] public void ImportAliasNamespaceResolveTest() { NamespaceResolveResult ns; @@ -394,7 +394,7 @@ class TestClass { Assert.AreEqual("System.Collections.ArrayList", rr.Type.FullName, "a"); } - [Test] + [Test, Ignore("Parser position bug")] public void ResolveNamespaceSD_863() { string program = @"using System; @@ -432,7 +432,7 @@ namespace A.B { Assert.AreEqual("A.B.C", trr.Type.FullName); } - [Test] + [Test, Ignore("parser is broken and produces IdentifierExpression instead of PrimitiveType")] public void ShortMaxValueTest() { string program = @"using System; @@ -471,7 +471,7 @@ class TestClass { Assert.AreEqual("XX.XX.Test", mrr.Member.FullName); } - [Test] + [Test, Ignore("Parser position bug")] public void ClassNameLookup1() { string program = @"namespace MainNamespace { @@ -490,7 +490,7 @@ namespace Test.Subnamespace { Assert.AreEqual("Test.Subnamespace.Test.TheClass", trr.Type.FullName); } - [Test] + [Test, Ignore("Parser position bug")] public void ClassNameLookup2() { string program = @"using Test.Subnamespace; diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/UnsafeCodeTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/UnsafeCodeTests.cs index bf77b15c9..f5ef169b6 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Resolver/UnsafeCodeTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Resolver/UnsafeCodeTests.cs @@ -9,7 +9,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver [TestFixture] public class UnsafeCodeTests : ResolverTestBase { - [Test, Ignore("Parser produces parse tree that doesn't match DOM definition??")] + [Test, Ignore("fixed statement not implemented in parser")] public void FixedStatement() { string program = @"using System; diff --git a/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj b/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj index f08560c21..7bc0981b5 100644 --- a/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj +++ b/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj @@ -11,6 +11,7 @@ Properties 10.0.0 2.0 + Client x86 diff --git a/ICSharpCode.NRefactory.VB.Tests/ICSharpCode.NRefactory.VB.Tests.csproj b/ICSharpCode.NRefactory.VB.Tests/ICSharpCode.NRefactory.VB.Tests.csproj index db980b370..fef832cb3 100644 --- a/ICSharpCode.NRefactory.VB.Tests/ICSharpCode.NRefactory.VB.Tests.csproj +++ b/ICSharpCode.NRefactory.VB.Tests/ICSharpCode.NRefactory.VB.Tests.csproj @@ -19,6 +19,7 @@ 4 v4.0 false + Client True diff --git a/ICSharpCode.NRefactory.VB/ICSharpCode.NRefactory.VB.csproj b/ICSharpCode.NRefactory.VB/ICSharpCode.NRefactory.VB.csproj index 52d851010..477002241 100644 --- a/ICSharpCode.NRefactory.VB/ICSharpCode.NRefactory.VB.csproj +++ b/ICSharpCode.NRefactory.VB/ICSharpCode.NRefactory.VB.csproj @@ -9,6 +9,7 @@ ICSharpCode.NRefactory.VB v4.0 Properties + Client x86 diff --git a/ICSharpCode.NRefactory/CSharp/Ast/AstLocation.cs b/ICSharpCode.NRefactory/CSharp/Ast/AstLocation.cs index 511d6fd06..2d0a5a796 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/AstLocation.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/AstLocation.cs @@ -57,11 +57,11 @@ namespace ICSharpCode.NRefactory.CSharp get { return column; } } - public override bool Equals (object other) + public override bool Equals (object obj) { - if (!(other is AstLocation)) + if (!(obj is AstLocation)) return false; - return (AstLocation)other == this; + return (AstLocation)obj == this; } public override int GetHashCode () diff --git a/ICSharpCode.NRefactory/CSharp/Ast/AstNode.cs b/ICSharpCode.NRefactory/CSharp/Ast/AstNode.cs index a5361ef4f..2dab5a5ad 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/AstNode.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/AstNode.cs @@ -606,6 +606,11 @@ namespace ICSharpCode.NRefactory.CSharp } protected internal abstract bool DoMatch(AstNode other, Match match); + + internal virtual bool DoMatchCollection(Role role, AstNode pos, Match match, Stack backtrackingStack) + { + return DoMatch(pos, match); + } #endregion // the Root role must be available when creating the null nodes, so we can't put it in the Roles class diff --git a/ICSharpCode.NRefactory/CSharp/Ast/AstNodeCollection.cs b/ICSharpCode.NRefactory/CSharp/Ast/AstNodeCollection.cs index 033ad7913..c7f266d97 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/AstNodeCollection.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/AstNodeCollection.cs @@ -174,18 +174,12 @@ namespace ICSharpCode.NRefactory.CSharp if (cur1 == null) break; - Pattern pattern = cur1 as Pattern; - if (pattern == null && cur1.NodeType == NodeType.Placeholder) - pattern = cur1.GetChildByRole(TypePlaceholder.ChildRole) as Pattern; - if (pattern != null) { - Debug.Assert(stack.Count == patternStack.Count); - success = pattern.DoMatchCollection(role, cur2, match, stack); - Debug.Assert(stack.Count >= patternStack.Count); - while (stack.Count > patternStack.Count) - patternStack.Push(cur1.NextSibling); - } else { - success = cur1.DoMatch(cur2, match); - } + Debug.Assert(stack.Count == patternStack.Count); + success = cur1.DoMatchCollection(role, cur2, match, stack); + Debug.Assert(stack.Count >= patternStack.Count); + while (stack.Count > patternStack.Count) + patternStack.Push(cur1.NextSibling); + cur1 = cur1.NextSibling; if (cur2 != null) cur2 = cur2.NextSibling; diff --git a/ICSharpCode.NRefactory/CSharp/Ast/AstType.cs b/ICSharpCode.NRefactory/CSharp/Ast/AstType.cs index 08bf473d4..a35204e3c 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/AstType.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/AstType.cs @@ -40,7 +40,7 @@ namespace ICSharpCode.NRefactory.CSharp return new ComposedType { BaseType = this }.MakePointerType(); } - public virtual AstType MakeArrayType(int rank) + public virtual AstType MakeArrayType(int rank = 1) { return new ComposedType { BaseType = this }.MakeArrayType(rank); } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/CSharpModifierToken.cs b/ICSharpCode.NRefactory/CSharp/Ast/CSharpModifierToken.cs index 6b2b12959..ec0a85705 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/CSharpModifierToken.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/CSharpModifierToken.cs @@ -48,6 +48,12 @@ namespace ICSharpCode.NRefactory.CSharp } } + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + CSharpModifierToken o = other as CSharpModifierToken; + return o != null && this.modifier == o.modifier; + } + // 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> lengthTable = new List> () { diff --git a/ICSharpCode.NRefactory/CSharp/Ast/CSharpTokenNode.cs b/ICSharpCode.NRefactory/CSharp/Ast/CSharpTokenNode.cs index 4e6288963..a776f259f 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/CSharpTokenNode.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/CSharpTokenNode.cs @@ -88,7 +88,7 @@ namespace ICSharpCode.NRefactory.CSharp protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) { CSharpTokenNode o = other as CSharpTokenNode; - return o != null; + return o != null && !o.IsNull && !(o is CSharpModifierToken); } public override string ToString () diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ArrayCreateExpression.cs b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ArrayCreateExpression.cs index 6578c5826..dffc3dd3d 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ArrayCreateExpression.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/ArrayCreateExpression.cs @@ -41,7 +41,7 @@ namespace ICSharpCode.NRefactory.CSharp protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) { ArrayCreateExpression o = other as ArrayCreateExpression; - return o != null && this.Type.DoMatch(o.Type, match) && this.Arguments.DoMatch(o.Arguments, match) && this.Initializer.DoMatch(o.Initializer, match); + return o != null && this.Type.DoMatch(o.Type, match) && this.Arguments.DoMatch(o.Arguments, match) && this.AdditionalArraySpecifiers.DoMatch(o.AdditionalArraySpecifiers, match) && this.Initializer.DoMatch(o.Initializer, match); } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/QueryExpression.cs b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/QueryExpression.cs index 79a357e87..9841a7468 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Expressions/QueryExpression.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Expressions/QueryExpression.cs @@ -45,7 +45,7 @@ namespace ICSharpCode.NRefactory.CSharp protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) { QueryExpression o = other as QueryExpression; - return o != null && this.Clauses.DoMatch(o.Clauses, match); + return o != null && !o.IsNull && this.Clauses.DoMatch(o.Clauses, match); } } @@ -54,12 +54,6 @@ namespace ICSharpCode.NRefactory.CSharp public override NodeType NodeType { get { return NodeType.QueryClause; } } - - protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) - { - QueryClause o = other as QueryClause; - throw new NotImplementedException(); - } } /// @@ -103,6 +97,12 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitQueryContinuationClause (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + QueryContinuationClause o = other as QueryContinuationClause; + return o != null && MatchString(this.Identifier, o.Identifier) && this.PrecedingQuery.DoMatch(o.PrecedingQuery, match); + } } public class QueryFromClause : QueryClause @@ -133,6 +133,13 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitQueryFromClause (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + QueryFromClause o = other as QueryFromClause; + return o != null && this.Type.DoMatch(o.Type, match) && MatchString(this.Identifier, o.Identifier) + && this.Expression.DoMatch(o.Expression, match); + } } public class QueryLetClause : QueryClause @@ -163,6 +170,12 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitQueryLetClause (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + QueryLetClause o = other as QueryLetClause; + return o != null && MatchString(this.Identifier, o.Identifier) && this.Expression.DoMatch(o.Expression, match); + } } @@ -181,6 +194,12 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitQueryWhereClause (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + QueryWhereClause o = other as QueryWhereClause; + return o != null && this.Condition.DoMatch(o.Condition, match); + } } /// @@ -266,6 +285,16 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitQueryJoinClause (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + QueryJoinClause o = other as QueryJoinClause; + return o != null && this.IsGroupJoin == o.IsGroupJoin + && this.Type.DoMatch(o.Type, match) && MatchString(this.JoinIdentifier, o.JoinIdentifier) + && this.InExpression.DoMatch(o.InExpression, match) && this.OnExpression.DoMatch(o.OnExpression, match) + && this.EqualsExpression.DoMatch(o.EqualsExpression, match) + && MatchString(this.IntoIdentifier, o.IntoIdentifier); + } } public class QueryOrderClause : QueryClause @@ -284,6 +313,12 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitQueryOrderClause (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + QueryOrderClause o = other as QueryOrderClause; + return o != null && this.Orderings.DoMatch(o.Orderings, match); + } } public class QueryOrdering : AstNode @@ -340,6 +375,12 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitQuerySelectClause (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + QuerySelectClause o = other as QuerySelectClause; + return o != null && this.Expression.DoMatch(o.Expression, match); + } } public class QueryGroupClause : QueryClause @@ -371,5 +412,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitQueryGroupClause (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + QueryGroupClause o = other as QueryGroupClause; + return o != null && this.Projection.DoMatch(o.Projection, match) && this.Key.DoMatch(o.Key, match); + } } } \ No newline at end of file diff --git a/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/AttributeSection.cs b/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/AttributeSection.cs index a192718da..901f6ba06 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/AttributeSection.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/AttributeSection.cs @@ -64,6 +64,15 @@ namespace ICSharpCode.NRefactory.CSharp return o != null && this.AttributeTarget == o.AttributeTarget && this.Attributes.DoMatch(o.Attributes, match); } + public AttributeSection() + { + } + + public AttributeSection(Attribute attr) + { + this.Attributes.Add(attr); + } + public static string GetAttributeTargetName(AttributeTarget attributeTarget) { switch (attributeTarget) { diff --git a/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/Constraint.cs b/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/Constraint.cs index 514a41192..8bac245c7 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/Constraint.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/Constraint.cs @@ -31,6 +31,9 @@ namespace ICSharpCode.NRefactory.CSharp /// /// where TypeParameter : BaseTypes /// + /// + /// new(), struct and class constraints are represented using a PrimitiveType "new", "struct" or "class" + /// public class Constraint : AstNode { public readonly static Role ColonRole = TypeDeclaration.ColonRole; @@ -51,8 +54,6 @@ namespace ICSharpCode.NRefactory.CSharp } } - // TODO: what about new(), struct and class constraints? - public AstNodeCollection BaseTypes { get { return GetChildrenByRole (BaseTypeRole); } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/DelegateDeclaration.cs b/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/DelegateDeclaration.cs index eccac9382..e014a4b3f 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/DelegateDeclaration.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/DelegateDeclaration.cs @@ -40,6 +40,11 @@ namespace ICSharpCode.NRefactory.CSharp } } + public AstType ReturnType { + get { return GetChildByRole (Roles.Type); } + set { SetChildByRole (Roles.Type, value); } + } + public string Name { get { return GetChildByRole (Roles.Identifier).Name; @@ -49,11 +54,6 @@ namespace ICSharpCode.NRefactory.CSharp } } - public AstType ReturnType { - get { return GetChildByRole (Roles.Type); } - set { SetChildByRole (Roles.Type, value); } - } - public AstNodeCollection TypeParameters { get { return GetChildrenByRole (Roles.TypeParameter); } } @@ -78,5 +78,14 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitDelegateDeclaration (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + DelegateDeclaration o = other as DelegateDeclaration; + return o != null && this.MatchAttributesAndModifiers(o, match) + && this.ReturnType.DoMatch(o.ReturnType, match) && MatchString(this.Name, o.Name) + && this.TypeParameters.DoMatch(o.TypeParameters, match) && this.Parameters.DoMatch(o.Parameters, match) + && this.Constraints.DoMatch(o.Constraints, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/TypeDeclaration.cs b/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/TypeDeclaration.cs index fd638f2da..df7ac2138 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/TypeDeclaration.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/TypeDeclaration.cs @@ -87,5 +87,14 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitTypeDeclaration (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + TypeDeclaration o = other as TypeDeclaration; + return o != null && this.ClassType == o.ClassType && this.MatchAttributesAndModifiers(o, match) + && MatchString(this.Name, o.Name) && this.TypeParameters.DoMatch(o.TypeParameters, match) + && this.BaseTypes.DoMatch(o.BaseTypes, match) && this.Constraints.DoMatch(o.Constraints, match) + && this.Members.DoMatch(o.Members, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/TypeParameterDeclaration.cs b/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/TypeParameterDeclaration.cs index 30e2fdf2f..84c9b2f50 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/TypeParameterDeclaration.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/GeneralScope/TypeParameterDeclaration.cs @@ -15,12 +15,17 @@ namespace ICSharpCode.NRefactory.CSharp /// public class TypeParameterDeclaration : AstNode { + public static readonly Role AttributeRole = AttributedNode.AttributeRole; public static readonly Role VarianceRole = new Role("Variance"); public override NodeType NodeType { get { return NodeType.Unknown; } } + public AstNodeCollection Attributes { + get { return GetChildrenByRole (AttributeRole); } + } + public VarianceModifier Variance { get; set; } @@ -42,7 +47,7 @@ namespace ICSharpCode.NRefactory.CSharp protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) { TypeParameterDeclaration o = other as TypeParameterDeclaration; - return o != null && this.Variance == o.Variance && MatchString(this.Name, o.Name); + return o != null && this.Variance == o.Variance && MatchString(this.Name, o.Name) && this.Attributes.DoMatch(o.Attributes, match); } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Identifier.cs b/ICSharpCode.NRefactory/CSharp/Ast/Identifier.cs index f63e97bf7..2db1b06e0 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Identifier.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Identifier.cs @@ -43,6 +43,11 @@ namespace ICSharpCode.NRefactory.CSharp { return default (S); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + return other == null || other.IsNull; + } } public override NodeType NodeType { @@ -95,7 +100,7 @@ namespace ICSharpCode.NRefactory.CSharp protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) { Identifier o = other as Identifier; - return o != null && MatchString(this.Name, o.Name); + return o != null && !o.IsNull && MatchString(this.Name, o.Name); } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/MemberType.cs b/ICSharpCode.NRefactory/CSharp/Ast/MemberType.cs index 70448e56a..b91048a5c 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/MemberType.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/MemberType.cs @@ -77,7 +77,7 @@ namespace ICSharpCode.NRefactory.CSharp b.Append(this.MemberName); if (this.TypeArguments.Any()) { b.Append('<'); - b.Append(string.Join(", ", this.TypeArguments)); + b.Append(DotNet35Compat.StringJoin(", ", this.TypeArguments)); b.Append('>'); } return b.ToString(); diff --git a/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Pattern.cs b/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Pattern.cs index 073415f51..37c89a58e 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Pattern.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Pattern.cs @@ -29,34 +29,29 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching } } - internal virtual bool DoMatchCollection(Role role, AstNode pos, Match match, Stack backtrackingStack) + public static implicit operator AstType(Pattern p) { - return DoMatch(pos, match); + return p != null ? new TypePlaceholder(p) : null; } - public AstType ToType() + public static implicit operator Expression(Pattern p) { - return new TypePlaceholder(this); + return p != null ? new ExpressionPlaceholder(p) : null; } - public Expression ToExpression() + public static implicit operator Statement(Pattern p) { - return new ExpressionPlaceholder(this); + return p != null ? new StatementPlaceholder(p) : null; } - public Statement ToStatement() + public static implicit operator BlockStatement(Pattern p) { - return new StatementPlaceholder(this); + return p != null ? new BlockStatementPlaceholder(p) : null; } - public BlockStatement ToBlock() + public static implicit operator VariableInitializer(Pattern p) { - return new BlockStatementPlaceholder(this); - } - - public VariableInitializer ToVariable() - { - return new VariablePlaceholder(this); + return p != null ? new VariablePlaceholder(p) : null; } // Make debugging easier by giving Patterns a ToString() implementation diff --git a/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Placeholder.cs b/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Placeholder.cs index 2bac1c6e1..f68feb443 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Placeholder.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Placeholder.cs @@ -2,16 +2,19 @@ // This code is distributed under MIT X11 license (for details please see \doc\license.txt) using System; +using System.Collections.Generic; namespace ICSharpCode.NRefactory.CSharp.PatternMatching { + // Placeholders do not store their child in the AST tree; but keep it as a separate child. + // This allows reusing the child in multiple placeholders; thus enabling the sharing of AST subtrees. sealed class TypePlaceholder : AstType { - public static readonly Role ChildRole = new Role("Child", AstNode.Null); + readonly AstNode child; public TypePlaceholder(AstNode child) { - AddChild(child, TypePlaceholder.ChildRole); + this.child = child; } public override NodeType NodeType { @@ -20,20 +23,27 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching public override S AcceptVisitor(IAstVisitor visitor, T data) { - return ((IPatternAstVisitor)visitor).VisitPlaceholder(this, GetChildByRole(TypePlaceholder.ChildRole), data); + return ((IPatternAstVisitor)visitor).VisitPlaceholder(this, child, data); } protected internal override bool DoMatch(AstNode other, Match match) { - return GetChildByRole(TypePlaceholder.ChildRole).DoMatch(other, match); + return child.DoMatch(other, match); + } + + internal override bool DoMatchCollection(Role role, AstNode pos, Match match, Stack backtrackingStack) + { + return child.DoMatchCollection(role, pos, match, backtrackingStack); } } sealed class ExpressionPlaceholder : Expression { + readonly AstNode child; + public ExpressionPlaceholder(AstNode child) { - AddChild(child, TypePlaceholder.ChildRole); + this.child = child; } public override NodeType NodeType { @@ -42,20 +52,27 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching public override S AcceptVisitor(IAstVisitor visitor, T data) { - return ((IPatternAstVisitor)visitor).VisitPlaceholder(this, GetChildByRole(TypePlaceholder.ChildRole), data); + return ((IPatternAstVisitor)visitor).VisitPlaceholder(this, child, data); } protected internal override bool DoMatch(AstNode other, Match match) { - return GetChildByRole(TypePlaceholder.ChildRole).DoMatch(other, match); + return child.DoMatch(other, match); + } + + internal override bool DoMatchCollection(Role role, AstNode pos, Match match, Stack backtrackingStack) + { + return child.DoMatchCollection(role, pos, match, backtrackingStack); } } sealed class StatementPlaceholder : Statement { + readonly AstNode child; + public StatementPlaceholder(AstNode child) { - AddChild(child, TypePlaceholder.ChildRole); + this.child = child; } public override NodeType NodeType { @@ -64,20 +81,27 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching public override S AcceptVisitor(IAstVisitor visitor, T data) { - return ((IPatternAstVisitor)visitor).VisitPlaceholder(this, GetChildByRole(TypePlaceholder.ChildRole), data); + return ((IPatternAstVisitor)visitor).VisitPlaceholder(this, child, data); } protected internal override bool DoMatch(AstNode other, Match match) { - return GetChildByRole(TypePlaceholder.ChildRole).DoMatch(other, match); + return child.DoMatch(other, match); + } + + internal override bool DoMatchCollection(Role role, AstNode pos, Match match, Stack backtrackingStack) + { + return child.DoMatchCollection(role, pos, match, backtrackingStack); } } sealed class BlockStatementPlaceholder : BlockStatement { + readonly AstNode child; + public BlockStatementPlaceholder(AstNode child) { - AddChild(child, TypePlaceholder.ChildRole); + this.child = child; } public override NodeType NodeType { @@ -86,20 +110,27 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching public override S AcceptVisitor(IAstVisitor visitor, T data) { - return ((IPatternAstVisitor)visitor).VisitPlaceholder(this, GetChildByRole(TypePlaceholder.ChildRole), data); + return ((IPatternAstVisitor)visitor).VisitPlaceholder(this, child, data); } protected internal override bool DoMatch(AstNode other, Match match) { - return GetChildByRole(TypePlaceholder.ChildRole).DoMatch(other, match); + return child.DoMatch(other, match); + } + + internal override bool DoMatchCollection(Role role, AstNode pos, Match match, Stack backtrackingStack) + { + return child.DoMatchCollection(role, pos, match, backtrackingStack); } } sealed class VariablePlaceholder : VariableInitializer { + readonly AstNode child; + public VariablePlaceholder(AstNode child) { - AddChild(child, TypePlaceholder.ChildRole); + this.child = child; } public override NodeType NodeType { @@ -108,12 +139,17 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching public override S AcceptVisitor(IAstVisitor visitor, T data) { - return ((IPatternAstVisitor)visitor).VisitPlaceholder(this, GetChildByRole(TypePlaceholder.ChildRole), data); + return ((IPatternAstVisitor)visitor).VisitPlaceholder(this, child, data); } protected internal override bool DoMatch(AstNode other, Match match) { - return GetChildByRole(TypePlaceholder.ChildRole).DoMatch(other, match); + return child.DoMatch(other, match); + } + + internal override bool DoMatchCollection(Role role, AstNode pos, Match match, Stack backtrackingStack) + { + return child.DoMatchCollection(role, pos, match, backtrackingStack); } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/SimpleType.cs b/ICSharpCode.NRefactory/CSharp/Ast/SimpleType.cs index 55839229c..237b3b55b 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/SimpleType.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/SimpleType.cs @@ -76,7 +76,7 @@ namespace ICSharpCode.NRefactory.CSharp StringBuilder b = new StringBuilder(this.Identifier); if (this.TypeArguments.Any()) { b.Append('<'); - b.Append(string.Join(", ", this.TypeArguments)); + b.Append(DotNet35Compat.StringJoin(", ", this.TypeArguments)); b.Append('>'); } return b.ToString(); diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/BlockStatement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/BlockStatement.cs index d43a0d538..9ee89966d 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/BlockStatement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/BlockStatement.cs @@ -77,7 +77,7 @@ namespace ICSharpCode.NRefactory.CSharp protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) { BlockStatement o = other as BlockStatement; - return o != null && this.Statements.DoMatch(o.Statements, match); + return o != null && !o.IsNull && this.Statements.DoMatch(o.Statements, match); } #region Builder methods diff --git a/ICSharpCode.NRefactory/CSharp/Ast/Statements/FixedStatement.cs b/ICSharpCode.NRefactory/CSharp/Ast/Statements/FixedStatement.cs index b1b7759f0..9a8efbc9a 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/Statements/FixedStatement.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/Statements/FixedStatement.cs @@ -67,7 +67,7 @@ namespace ICSharpCode.NRefactory.CSharp protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) { FixedStatement o = other as FixedStatement; - return o != null && this.Variables.DoMatch(o.Variables, match) && this.EmbeddedStatement.DoMatch(o.EmbeddedStatement, match); + return o != null && this.Type.DoMatch(o.Type, match) && this.Variables.DoMatch(o.Variables, match) && this.EmbeddedStatement.DoMatch(o.EmbeddedStatement, match); } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/Accessor.cs b/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/Accessor.cs index 910aec75f..c487032eb 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/Accessor.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/Accessor.cs @@ -64,7 +64,8 @@ namespace ICSharpCode.NRefactory.CSharp protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) { - throw new NotImplementedException(); + Accessor o = other as Accessor; + return o != null && !o.IsNull && this.MatchAttributesAndModifiers(o, match) && this.Body.DoMatch(o.Body, match); } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/AttributedNode.cs b/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/AttributedNode.cs index 1b878d91c..41eec380d 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/AttributedNode.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/AttributedNode.cs @@ -58,9 +58,9 @@ namespace ICSharpCode.NRefactory.CSharp } } - protected internal override bool DoMatch(AstNode other, ICSharpCode.NRefactory.CSharp.PatternMatching.Match match) + protected bool MatchAttributesAndModifiers(AttributedNode o, PatternMatching.Match match) { - throw new NotImplementedException(); + return this.Modifiers == o.Modifiers && this.Attributes.DoMatch(o.Attributes, match); } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/ConstructorDeclaration.cs b/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/ConstructorDeclaration.cs index 97f808051..4971a4eec 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/ConstructorDeclaration.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/ConstructorDeclaration.cs @@ -70,6 +70,13 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitConstructorDeclaration (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + ConstructorDeclaration o = other as ConstructorDeclaration; + return o != null && this.MatchAttributesAndModifiers(o, match) && this.Parameters.DoMatch(o.Parameters, match) + && this.Initializer.DoMatch(o.Initializer, match) && this.Body.DoMatch(o.Body, match); + } } public enum ConstructorInitializerType { @@ -98,6 +105,11 @@ namespace ICSharpCode.NRefactory.CSharp { return default (S); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + return other == null || other.IsNull; + } } public override NodeType NodeType { @@ -123,7 +135,7 @@ namespace ICSharpCode.NRefactory.CSharp protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) { ConstructorInitializer o = other as ConstructorInitializer; - return o != null && this.ConstructorInitializerType == o.ConstructorInitializerType && this.Arguments.DoMatch(o.Arguments, match); + return o != null && !o.IsNull && this.ConstructorInitializerType == o.ConstructorInitializerType && this.Arguments.DoMatch(o.Arguments, match); } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/DestructorDeclaration.cs b/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/DestructorDeclaration.cs index 2798d0660..8a892b275 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/DestructorDeclaration.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/DestructorDeclaration.cs @@ -1,6 +1,6 @@ // // DestructorDeclaration.cs -// +// // Author: // Mike Krüger // @@ -61,5 +61,11 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitDestructorDeclaration (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + DestructorDeclaration o = other as DestructorDeclaration; + return o != null && this.MatchAttributesAndModifiers(o, match) && this.Body.DoMatch(o.Body, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/EnumMemberDeclaration.cs b/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/EnumMemberDeclaration.cs index 0715898f0..e2784f565 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/EnumMemberDeclaration.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/EnumMemberDeclaration.cs @@ -1,6 +1,6 @@ -// +// // EnumMemberDeclaration.cs -// +// // Author: // Mike Krüger // @@ -53,6 +53,13 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitEnumMemberDeclaration (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + EnumMemberDeclaration o = other as EnumMemberDeclaration; + return o != null && this.MatchAttributesAndModifiers(o, match) + && MatchString(this.Name, o.Name) && this.Initializer.DoMatch(o.Initializer, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/EventDeclaration.cs b/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/EventDeclaration.cs index 3a916782d..49d28ede3 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/EventDeclaration.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/EventDeclaration.cs @@ -28,8 +28,17 @@ using System.Collections.Generic; namespace ICSharpCode.NRefactory.CSharp { - public class EventDeclaration : MemberDeclaration + public class EventDeclaration : AttributedNode { + public override NodeType NodeType { + get { return NodeType.Member; } + } + + public AstType ReturnType { + get { return GetChildByRole (Roles.Type); } + set { SetChildByRole(Roles.Type, value); } + } + public AstNodeCollection Variables { get { return GetChildrenByRole (Roles.Variable); } } @@ -38,6 +47,13 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitEventDeclaration (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + EventDeclaration o = other as EventDeclaration; + return o != null && this.MatchAttributesAndModifiers(o, match) + && this.ReturnType.DoMatch(o.ReturnType, match) && this.Variables.DoMatch(o.Variables, match); + } } public class CustomEventDeclaration : MemberDeclaration @@ -67,5 +83,12 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitCustomEventDeclaration (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + CustomEventDeclaration o = other as CustomEventDeclaration; + return o != null && this.MatchMember(o, match) + && this.AddAccessor.DoMatch(o.AddAccessor, match) && this.RemoveAccessor.DoMatch(o.RemoveAccessor, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/FieldDeclaration.cs b/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/FieldDeclaration.cs index 3ca04772d..1003aa9b7 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/FieldDeclaration.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/FieldDeclaration.cs @@ -1,6 +1,6 @@ // // FieldDeclaration.cs -// +// // Author: // Mike Krüger // @@ -29,9 +29,18 @@ using System.Linq; namespace ICSharpCode.NRefactory.CSharp { - public class FieldDeclaration : MemberDeclaration + public class FieldDeclaration : AttributedNode { - public AstNodeCollection Variables { + public override NodeType NodeType { + get { return NodeType.Member; } + } + + public AstType ReturnType { + get { return GetChildByRole (Roles.Type); } + set { SetChildByRole(Roles.Type, value); } + } + + public AstNodeCollection Variables { get { return GetChildrenByRole (Roles.Variable); } } @@ -39,5 +48,12 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitFieldDeclaration (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + FieldDeclaration o = other as FieldDeclaration; + return o != null && this.MatchAttributesAndModifiers(o, match) + && this.ReturnType.DoMatch(o.ReturnType, match) && this.Variables.DoMatch(o.Variables, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/IndexerDeclaration.cs b/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/IndexerDeclaration.cs index 5b63c9c4f..4d19c97d7 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/IndexerDeclaration.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/IndexerDeclaration.cs @@ -1,6 +1,6 @@ // // IndexerDeclaration.cs -// +// // Author: // Mike Krüger // @@ -29,13 +29,16 @@ using System.Linq; namespace ICSharpCode.NRefactory.CSharp { - public class IndexerDeclaration : PropertyDeclaration + public class IndexerDeclaration : MemberDeclaration { + public static readonly Role GetterRole = PropertyDeclaration.GetterRole; + public static readonly Role SetterRole = PropertyDeclaration.SetterRole; + public CSharpTokenNode LBracketToken { get { return GetChildByRole (Roles.LBracket); } } - public AstNodeCollection Parameters { + public AstNodeCollection Parameters { get { return GetChildrenByRole (Roles.Parameter); } } @@ -43,9 +46,34 @@ namespace ICSharpCode.NRefactory.CSharp get { return GetChildByRole (Roles.RBracket); } } + public CSharpTokenNode LBraceToken { + get { return GetChildByRole (Roles.LBrace); } + } + + public Accessor Getter { + get { return GetChildByRole(GetterRole); } + set { SetChildByRole(GetterRole, value); } + } + + public Accessor Setter { + get { return GetChildByRole(SetterRole); } + set { SetChildByRole(SetterRole, value); } + } + + public CSharpTokenNode RBraceToken { + get { return GetChildByRole (Roles.RBrace); } + } + public override S AcceptVisitor (IAstVisitor visitor, T data) { return visitor.VisitIndexerDeclaration (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + IndexerDeclaration o = other as IndexerDeclaration; + return o != null && this.MatchMember(o, match) && this.Parameters.DoMatch(o.Parameters, match) + && this.Getter.DoMatch(o.Getter, match) && this.Setter.DoMatch(o.Setter, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/MemberDeclaration.cs b/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/MemberDeclaration.cs index 5cd468cfe..a7e1b74e4 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/MemberDeclaration.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/MemberDeclaration.cs @@ -55,5 +55,11 @@ namespace ICSharpCode.NRefactory.CSharp public override NodeType NodeType { get { return NodeType.Member; } } + + protected bool MatchMember(MemberDeclaration o, PatternMatching.Match match) + { + return MatchAttributesAndModifiers(o, match) && this.ReturnType.DoMatch(o.ReturnType, match) + && this.PrivateImplementationType.DoMatch(o.PrivateImplementationType, match) && MatchString(this.Name, o.Name); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/MethodDeclaration.cs b/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/MethodDeclaration.cs index ef740bd86..556c0a3a4 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/MethodDeclaration.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/MethodDeclaration.cs @@ -1,6 +1,6 @@ // // MethodDeclaration.cs -// +// // Author: // Mike Krüger // @@ -39,7 +39,7 @@ namespace ICSharpCode.NRefactory.CSharp get { return GetChildByRole (Roles.LPar); } } - public AstNodeCollection Parameters { + public AstNodeCollection Parameters { get { return GetChildrenByRole (Roles.Parameter); } } @@ -47,7 +47,7 @@ namespace ICSharpCode.NRefactory.CSharp get { return GetChildByRole (Roles.RPar); } } - public AstNodeCollection Constraints { + public AstNodeCollection Constraints { get { return GetChildrenByRole (Roles.Constraint); } } @@ -67,5 +67,13 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitMethodDeclaration (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + MethodDeclaration o = other as MethodDeclaration; + return o != null && this.MatchMember(o, match) && this.TypeParameters.DoMatch(o.TypeParameters, match) + && this.Parameters.DoMatch(o.Parameters, match) && this.Constraints.DoMatch(o.Constraints, match) + && this.Body.DoMatch(o.Body, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/OperatorDeclaration.cs b/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/OperatorDeclaration.cs index c8a326c49..7215412eb 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/OperatorDeclaration.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/OperatorDeclaration.cs @@ -1,6 +1,6 @@ // // OperatorDeclaration.cs -// +// // Author: // Mike Krüger // @@ -66,7 +66,7 @@ namespace ICSharpCode.NRefactory.CSharp Explicit } - public class OperatorDeclaration : MemberDeclaration + public class OperatorDeclaration : AttributedNode { public static readonly Role OperatorTypeRole = new Role("OperatorType", CSharpTokenNode.Null); public static readonly Role OperatorKeywordRole = Roles.Keyword; @@ -76,11 +76,16 @@ namespace ICSharpCode.NRefactory.CSharp set; } + public AstType ReturnType { + get { return GetChildByRole (Roles.Type); } + set { SetChildByRole(Roles.Type, value); } + } + public CSharpTokenNode LParToken { get { return GetChildByRole (Roles.LPar); } } - public AstNodeCollection Parameters { + public AstNodeCollection Parameters { get { return GetChildrenByRole (Roles.Parameter); } } @@ -103,9 +108,25 @@ namespace ICSharpCode.NRefactory.CSharp return Mono.CSharp.Operator.GetName((Mono.CSharp.Operator.OpType)type); } + public override NodeType NodeType { + get { return NodeType.Member; } + } + public override S AcceptVisitor (IAstVisitor visitor, T data) { return visitor.VisitOperatorDeclaration (this, data); } + + public string Name { + get { return GetName(this.OperatorType); } + } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + OperatorDeclaration o = other as OperatorDeclaration; + return o != null && this.MatchAttributesAndModifiers(o, match) && this.OperatorType == o.OperatorType + && this.ReturnType.DoMatch(o.ReturnType, match) + && this.Parameters.DoMatch(o.Parameters, match) && this.Body.DoMatch(o.Body, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/ParameterDeclaration.cs b/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/ParameterDeclaration.cs index 0334d2a3f..5544c5aa7 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/ParameterDeclaration.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/ParameterDeclaration.cs @@ -85,7 +85,19 @@ namespace ICSharpCode.NRefactory.CSharp protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) { ParameterDeclaration o = other as ParameterDeclaration; - return o != null && this.Attributes.DoMatch(o.Attributes, match) && this.ParameterModifier == o.ParameterModifier && MatchString(this.Name, o.Name) && this.DefaultExpression.DoMatch(o.DefaultExpression, match); + return o != null && this.Attributes.DoMatch(o.Attributes, match) && this.ParameterModifier == o.ParameterModifier + && this.Type.DoMatch(o.Type, match) && MatchString(this.Name, o.Name) + && this.DefaultExpression.DoMatch(o.DefaultExpression, match); + } + + public ParameterDeclaration() + { + } + + public ParameterDeclaration(AstType type, string name) + { + this.Type = type; + this.Name = name; } } } diff --git a/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/PropertyDeclaration.cs b/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/PropertyDeclaration.cs index d13ce8f5c..2d1376a0e 100644 --- a/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/PropertyDeclaration.cs +++ b/ICSharpCode.NRefactory/CSharp/Ast/TypeMembers/PropertyDeclaration.cs @@ -1,6 +1,6 @@ -// +// // PropertyDeclaration.cs -// +// // Author: // Mike Krüger // @@ -53,5 +53,12 @@ namespace ICSharpCode.NRefactory.CSharp { return visitor.VisitPropertyDeclaration (this, data); } + + protected internal override bool DoMatch(AstNode other, PatternMatching.Match match) + { + PropertyDeclaration o = other as PropertyDeclaration; + return o != null && this.MatchMember(o, match) + && this.Getter.DoMatch(o.Getter, match) && this.Setter.DoMatch(o.Setter, match); + } } } diff --git a/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs b/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs index 1c67668d0..960058789 100644 --- a/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs +++ b/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs @@ -22,7 +22,7 @@ namespace ICSharpCode.NRefactory.CSharp readonly IOutputFormatter formatter; readonly CSharpFormattingPolicy policy; - AstNode currentContainerNode; + readonly Stack containerStack = new Stack(); readonly Stack positionStack = new Stack(); /// @@ -65,21 +65,23 @@ namespace ICSharpCode.NRefactory.CSharp #region StartNode/EndNode void StartNode(AstNode node) { - Debug.Assert(currentContainerNode == null || node.Parent == currentContainerNode); + // Ensure that nodes are visited in the proper nested order. + // Jumps to different subtrees are allowed only for the child of a placeholder node. + Debug.Assert(containerStack.Count == 0 || node.Parent == containerStack.Peek() || containerStack.Peek().NodeType == NodeType.Placeholder); if (positionStack.Count > 0) WriteSpecialsUpToNode(node); - currentContainerNode = node; + containerStack.Push(node); positionStack.Push(node.FirstChild); formatter.StartNode(node); } object EndNode(AstNode node) { - Debug.Assert(node == currentContainerNode); + Debug.Assert(node == containerStack.Peek()); AstNode pos = positionStack.Pop(); Debug.Assert(pos == null || pos.Parent == node); WriteSpecials(pos, null); - currentContainerNode = node.Parent; + containerStack.Pop(); formatter.EndNode(node); return null; } @@ -146,13 +148,14 @@ namespace ICSharpCode.NRefactory.CSharp /// Writes a comma. /// /// The next node after the comma. - void Comma(AstNode nextNode) + /// When set prevents printing a space after comma. + void Comma(AstNode nextNode, bool noSpaceAfterComma = false) { WriteSpecialsUpToRole(AstNode.Roles.Comma, nextNode); Space(policy.SpacesBeforeComma); formatter.WriteToken(","); lastWritten = LastWritten.Other; - Space(policy.SpacesAfterComma); + Space(!noSpaceAfterComma && policy.SpacesAfterComma); } void WriteCommaSeparatedList(IEnumerable list) @@ -179,12 +182,34 @@ namespace ICSharpCode.NRefactory.CSharp RPar(); } - void WriteCommaSeparatedListInBrackets(IEnumerable list) + #if DOTNET35 + void WriteCommaSeparatedList(IEnumerable list) + { + WriteCommaSeparatedList(list.SafeCast()); + } + + void WriteCommaSeparatedList(IEnumerable list) + { + WriteCommaSeparatedList(list.SafeCast()); + } + + void WriteCommaSeparatedListInParenthesis(IEnumerable list, bool spaceWithin) + { + WriteCommaSeparatedListInParenthesis(list.SafeCast(), spaceWithin); + } + + void WriteCommaSeparatedListInParenthesis(IEnumerable list, bool spaceWithin) + { + WriteCommaSeparatedListInParenthesis(list.SafeCast(), spaceWithin); + } + #endif + + void WriteCommaSeparatedListInBrackets(IEnumerable list) { WriteToken("[", AstNode.Roles.LBracket); if (list.Any()) { Space(policy.SpacesWithinBrackets); - WriteCommaSeparatedList(list); + WriteCommaSeparatedList(list.SafeCast()); Space(policy.SpacesWithinBrackets); } WriteToken("]", AstNode.Roles.RBracket); @@ -207,7 +232,7 @@ namespace ICSharpCode.NRefactory.CSharp void WriteIdentifier(string identifier, Role identifierRole = null) { WriteSpecialsUpToRole(identifierRole ?? AstNode.Roles.Identifier); - if (IsKeyword(identifier, currentContainerNode)) { + if (IsKeyword(identifier, containerStack.Peek())) { if (lastWritten == LastWritten.KeywordOrIdentifier) Space(); // this space is not strictly required, so we call Space() formatter.WriteToken("@"); @@ -265,7 +290,8 @@ namespace ICSharpCode.NRefactory.CSharp /// void Semicolon() { - if (currentContainerNode.Role != ForStatement.InitializerRole && currentContainerNode.Role != ForStatement.IteratorRole && currentContainerNode.Role != UsingStatement.ResourceAcquisitionRole) { + Role role = containerStack.Peek().Role; // get the role of the current node + if (!(role == ForStatement.InitializerRole || role == ForStatement.IteratorRole || role == UsingStatement.ResourceAcquisitionRole)) { WriteToken(";", AstNode.Roles.Semicolon); NewLine(); } @@ -351,7 +377,7 @@ namespace ICSharpCode.NRefactory.CSharp { if (typeParameters.Any()) { WriteToken("<", AstNode.Roles.LChevron); - WriteCommaSeparatedList(typeParameters); + WriteCommaSeparatedList(typeParameters.SafeCast()); WriteToken(">", AstNode.Roles.RChevron); } } @@ -1033,7 +1059,7 @@ namespace ICSharpCode.NRefactory.CSharp StartNode(queryOrderClause); WriteKeyword("orderby"); Space(); - WriteCommaSeparatedList(queryOrderClause.Orderings); + WriteCommaSeparatedList(queryOrderClause.Orderings.SafeCast()); return EndNode(queryOrderClause); } @@ -1083,7 +1109,8 @@ namespace ICSharpCode.NRefactory.CSharp StartNode(attribute); attribute.Type.AcceptVisitor(this, data); Space(policy.BeforeMethodCallParentheses); - WriteCommaSeparatedListInParenthesis(attribute.Arguments, policy.WithinMethodCallParentheses); + if (attribute.Arguments.Count != 0 || !attribute.GetChildByRole(AstNode.Roles.LPar).IsNull) + WriteCommaSeparatedListInParenthesis(attribute.Arguments, policy.WithinMethodCallParentheses); return EndNode(attribute); } @@ -1096,9 +1123,10 @@ namespace ICSharpCode.NRefactory.CSharp WriteToken(":", AttributeSection.Roles.Colon); Space(); } - WriteCommaSeparatedList(attributeSection.Attributes); + WriteCommaSeparatedList(attributeSection.Attributes.SafeCast()); WriteToken("]", AstNode.Roles.RBracket); - NewLine(); + if (!(attributeSection.Parent is ParameterDeclaration)) + NewLine(); return EndNode(attributeSection); } @@ -1176,7 +1204,7 @@ namespace ICSharpCode.NRefactory.CSharp if (first) { first = false; } else { - Comma(member); + Comma(member, noSpaceAfterComma: true); NewLine(); } member.AcceptVisitor(this, data); @@ -1345,7 +1373,7 @@ namespace ICSharpCode.NRefactory.CSharp LPar(); Space(policy.WithinForParentheses); - WriteCommaSeparatedList(forStatement.Initializers); + WriteCommaSeparatedList(forStatement.Initializers.SafeCast()); WriteToken(";", AstNode.Roles.Semicolon); Space(policy.SpacesAfterSemicolon); @@ -1353,7 +1381,7 @@ namespace ICSharpCode.NRefactory.CSharp WriteToken(";", AstNode.Roles.Semicolon); Space(policy.SpacesAfterSemicolon); - WriteCommaSeparatedList(forStatement.Iterators); + WriteCommaSeparatedList(forStatement.Iterators.SafeCast()); Space(policy.WithinForParentheses); RPar(); @@ -1889,7 +1917,10 @@ namespace ICSharpCode.NRefactory.CSharp { StartNode(memberType); memberType.Target.AcceptVisitor(this, data); - WriteToken(".", MemberType.Roles.Dot); + if (memberType.IsDoubleColon) + WriteToken("::", MemberType.Roles.Dot); + else + WriteToken(".", MemberType.Roles.Dot); WriteIdentifier(memberType.MemberName); WriteTypeArguments(memberType.TypeArguments); return EndNode(memberType); @@ -1925,6 +1956,11 @@ namespace ICSharpCode.NRefactory.CSharp { StartNode(primitiveType); WriteKeyword(primitiveType.Keyword); + if (primitiveType.Keyword == "new") { + // new() constraint + LPar(); + RPar(); + } return EndNode(primitiveType); } @@ -1943,6 +1979,7 @@ namespace ICSharpCode.NRefactory.CSharp public object VisitTypeParameterDeclaration(TypeParameterDeclaration typeParameterDeclaration, object data) { StartNode(typeParameterDeclaration); + WriteAttributes(typeParameterDeclaration.Attributes); switch (typeParameterDeclaration.Variance) { case VarianceModifier.Invariant: break; diff --git a/ICSharpCode.NRefactory/CSharp/Parser/CSharpParser.cs b/ICSharpCode.NRefactory/CSharp/Parser/CSharpParser.cs index bb447f4c6..68ac7ee2f 100644 --- a/ICSharpCode.NRefactory/CSharp/Parser/CSharpParser.cs +++ b/ICSharpCode.NRefactory/CSharp/Parser/CSharpParser.cs @@ -225,7 +225,7 @@ namespace ICSharpCode.NRefactory.CSharp var typeArgLocation = LocationsBag.GetLocations (c.MemberName); if (typeArgLocation != null) newType.AddChild (new CSharpTokenNode (Convert (typeArgLocation[0]), 1), TypeDeclaration.Roles.LChevron); -// AddTypeArguments (newType, typeArgLocation, c.MemberName.TypeArguments); + AddTypeParameters (newType, typeArgLocation, c.MemberName.TypeArguments); if (typeArgLocation != null) newType.AddChild (new CSharpTokenNode (Convert (typeArgLocation[1]), 1), TypeDeclaration.Roles.RChevron); AddConstraints (newType, c); @@ -254,7 +254,7 @@ namespace ICSharpCode.NRefactory.CSharp var typeArgLocation = LocationsBag.GetLocations (s.MemberName); if (typeArgLocation != null) newType.AddChild (new CSharpTokenNode (Convert (typeArgLocation[0]), 1), TypeDeclaration.Roles.LChevron); -// AddTypeArguments (newType, typeArgLocation, s.MemberName.TypeArguments); + AddTypeParameters (newType, typeArgLocation, s.MemberName.TypeArguments); if (typeArgLocation != null) newType.AddChild (new CSharpTokenNode (Convert (typeArgLocation[1]), 1), TypeDeclaration.Roles.RChevron); AddConstraints (newType, s); @@ -283,7 +283,7 @@ namespace ICSharpCode.NRefactory.CSharp var typeArgLocation = LocationsBag.GetLocations (i.MemberName); if (typeArgLocation != null) newType.AddChild (new CSharpTokenNode (Convert (typeArgLocation[0]), 1), MemberReferenceExpression.Roles.LChevron); -// AddTypeArguments (newType, typeArgLocation, i.MemberName.TypeArguments); + AddTypeParameters (newType, typeArgLocation, i.MemberName.TypeArguments); if (typeArgLocation != null) newType.AddChild (new CSharpTokenNode (Convert (typeArgLocation[1]), 1), MemberReferenceExpression.Roles.RChevron); AddConstraints (newType, i); @@ -307,12 +307,12 @@ namespace ICSharpCode.NRefactory.CSharp if (location != null) newDelegate.AddChild (new CSharpTokenNode (Convert (location[0]), "delegate".Length), TypeDeclaration.Roles.Keyword); newDelegate.AddChild (ConvertToType (d.ReturnType), AstNode.Roles.Type); - newDelegate.AddChild (new Identifier (d.Name, Convert (d.MemberName.Location)), AstNode.Roles.Identifier); + newDelegate.AddChild (new Identifier (d.Basename, Convert (d.MemberName.Location)), AstNode.Roles.Identifier); if (d.MemberName.TypeArguments != null) { var typeArgLocation = LocationsBag.GetLocations (d.MemberName); if (typeArgLocation != null) newDelegate.AddChild (new CSharpTokenNode (Convert (typeArgLocation[0]), 1), TypeDeclaration.Roles.LChevron); -// AddTypeArguments (newDelegate, typeArgLocation, d.MemberName.TypeArguments); + AddTypeParameters (newDelegate, typeArgLocation, d.MemberName.TypeArguments); if (typeArgLocation != null) newDelegate.AddChild (new CSharpTokenNode (Convert (typeArgLocation[1]), 1), TypeDeclaration.Roles.RChevron); AddConstraints (newDelegate, d); @@ -632,7 +632,7 @@ namespace ICSharpCode.NRefactory.CSharp var typeArgLocation = LocationsBag.GetLocations (m.MemberName); if (typeArgLocation != null) newMethod.AddChild (new CSharpTokenNode (Convert (typeArgLocation[0]), 1), MemberReferenceExpression.Roles.LChevron); -// AddTypeArguments (newMethod, typeArgLocation, m.MemberName.TypeArguments); + AddTypeParameters (newMethod, typeArgLocation, m.MemberName.TypeArguments); if (typeArgLocation != null) newMethod.AddChild (new CSharpTokenNode (Convert (typeArgLocation[1]), 1), MemberReferenceExpression.Roles.RChevron); @@ -1234,7 +1234,7 @@ namespace ICSharpCode.NRefactory.CSharp statement.Remove (); newSection.AddChild (statement, SwitchSection.Roles.EmbeddedStatement); - } + } result.AddChild (newSection, SwitchStatement.SwitchSectionRole); } @@ -1835,17 +1835,22 @@ namespace ICSharpCode.NRefactory.CSharp } } - void AddTypeArguments (AstNode parent, LocationsBag.MemberLocations location, Mono.CSharp.TypeArguments typeArguments) + void AddTypeParameters (AstNode parent, List location, Mono.CSharp.TypeArguments typeArguments) { if (typeArguments == null || typeArguments.IsEmpty) return; for (int i = 0; i < typeArguments.Count; i++) { if (location != null && i > 0 && i - 1 < location.Count) parent.AddChild (new CSharpTokenNode (Convert (location[i - 1]), 1), InvocationExpression.Roles.Comma); - var arg = typeArguments.Args[i]; + var arg = (TypeParameterName)typeArguments.Args[i]; if (arg == null) continue; - parent.AddChild (ConvertToType (arg), InvocationExpression.Roles.TypeArgument); + TypeParameterDeclaration tp = new TypeParameterDeclaration(); + // TODO: attributes + if (arg.Variance != Variance.None) + throw new NotImplementedException(); // TODO: variance + tp.AddChild (new Identifier (arg.Name, Convert (arg.Location)), InvocationExpression.Roles.Identifier); + parent.AddChild (tp, InvocationExpression.Roles.TypeParameter); } } @@ -1871,11 +1876,12 @@ namespace ICSharpCode.NRefactory.CSharp Constraints c = d.Constraints[i]; var location = LocationsBag.GetLocations (c); var constraint = new Constraint (); - parent.AddChild (new CSharpTokenNode (Convert (location[0]), "where".Length), InvocationExpression.Roles.Keyword); - parent.AddChild (new Identifier (c.TypeParameter.Value, Convert (c.TypeParameter.Location)), InvocationExpression.Roles.Identifier); - parent.AddChild (new CSharpTokenNode (Convert (location[1]), 1), Constraint.ColonRole); + constraint.AddChild (new CSharpTokenNode (Convert (location[0]), "where".Length), InvocationExpression.Roles.Keyword); + constraint.AddChild (new Identifier (c.TypeParameter.Value, Convert (c.TypeParameter.Location)), InvocationExpression.Roles.Identifier); + constraint.AddChild (new CSharpTokenNode (Convert (location[1]), 1), Constraint.ColonRole); foreach (var expr in c.ConstraintExpressions) - parent.AddChild (ConvertToType (expr), Constraint.BaseTypeRole); + constraint.AddChild (ConvertToType (expr), Constraint.BaseTypeRole); + parent.AddChild (constraint, AstNode.Roles.Constraint); } } @@ -1892,7 +1898,7 @@ namespace ICSharpCode.NRefactory.CSharp DirectionExpression direction = new DirectionExpression (); direction.FieldDirection = arg.ArgType == Argument.AType.Out ? FieldDirection.Out : FieldDirection.Ref; var argLocation = LocationsBag.GetLocations (arg); - if (location != null) + if (argLocation != null) direction.AddChild (new CSharpTokenNode (Convert (argLocation[0]), "123".Length), InvocationExpression.Roles.Keyword); direction.AddChild ((Expression)arg.Expr.Accept (this), InvocationExpression.Roles.Expression); @@ -2115,10 +2121,10 @@ namespace ICSharpCode.NRefactory.CSharp if (location != null) result.AddChild (new CSharpTokenNode (Convert (location[0]), "stackalloc".Length), StackAllocExpression.Roles.Keyword); result.AddChild (ConvertToType (stackAllocExpression.TypeExpression), StackAllocExpression.Roles.Type); - if (location != null) + if (location != null && location.Count > 1) result.AddChild (new CSharpTokenNode (Convert (location[1]), 1), StackAllocExpression.Roles.LBracket); result.AddChild ((Expression)stackAllocExpression.CountExpression.Accept (this), StackAllocExpression.Roles.Expression); - if (location != null) + if (location != null && location.Count > 2) result.AddChild (new CSharpTokenNode (Convert (location[2]), 1), StackAllocExpression.Roles.RBracket); return result; } @@ -2540,7 +2546,7 @@ namespace ICSharpCode.NRefactory.CSharp return EmptyList.Instance; } - public IEnumerable ParseStatements(TextReader reader) + public IEnumerable ParseStatements(TextReader reader) { string code = "void M() { " + reader.ReadToEnd() + "}"; var members = ParseTypeMembers(new StringReader(code)); @@ -2548,10 +2554,10 @@ namespace ICSharpCode.NRefactory.CSharp if (method != null && method.Body != null) return method.Body.Statements; else - return EmptyList.Instance; + return EmptyList.Instance; } - public AstNode ParseTypeReference(TextReader reader) + public AstType ParseTypeReference(TextReader reader) { // TODO: add support for parsing type references throw new NotImplementedException(); diff --git a/ICSharpCode.NRefactory/CSharp/Parser/TypeSystemConvertVisitor.cs b/ICSharpCode.NRefactory/CSharp/Parser/TypeSystemConvertVisitor.cs index 281e3e569..6fac5b0da 100644 --- a/ICSharpCode.NRefactory/CSharp/Parser/TypeSystemConvertVisitor.cs +++ b/ICSharpCode.NRefactory/CSharp/Parser/TypeSystemConvertVisitor.cs @@ -145,9 +145,11 @@ namespace ICSharpCode.NRefactory.CSharp else if (td.ClassType == ClassType.Enum || td.ClassType == ClassType.Struct) td.IsSealed = true; // enums/structs are implicitly sealed - //TODO ConvertTypeParameters(td.TypeParameters, typeDeclaration.TypeParameters, typeDeclaration.Constraints); + ConvertTypeParameters(td.TypeParameters, typeDeclaration.TypeParameters, typeDeclaration.Constraints); - // TODO: base type references? + foreach (AstType baseType in typeDeclaration.BaseTypes) { + td.BaseTypes.Add(ConvertType(baseType)); + } foreach (AttributedNode member in typeDeclaration.Members) { member.AcceptVisitor(this, data); @@ -159,7 +161,7 @@ namespace ICSharpCode.NRefactory.CSharp public override IEntity VisitDelegateDeclaration(DelegateDeclaration delegateDeclaration, object data) { - var td = CreateTypeDefinition(delegateDeclaration.Name); + var td = currentTypeDefinition = CreateTypeDefinition(delegateDeclaration.Name); td.ClassType = ClassType.Delegate; td.Region = MakeRegion(delegateDeclaration); td.BaseTypes.Add(multicastDelegateReference); @@ -168,9 +170,14 @@ namespace ICSharpCode.NRefactory.CSharp ApplyModifiers(td, delegateDeclaration.Modifiers); td.IsSealed = true; // delegates are implicitly sealed - // TODO: convert return type, convert parameters - AddDefaultMethodsToDelegate(td, SharedTypes.UnknownType, EmptyList.Instance); + ConvertTypeParameters(td.TypeParameters, delegateDeclaration.TypeParameters, delegateDeclaration.Constraints); + + ITypeReference returnType = ConvertType(delegateDeclaration.ReturnType); + List parameters = new List(); + ConvertParameters(parameters, delegateDeclaration.Parameters); + AddDefaultMethodsToDelegate(td, returnType, parameters); + currentTypeDefinition = (DefaultTypeDefinition)currentTypeDefinition.DeclaringTypeDefinition; return td; } @@ -299,7 +306,7 @@ namespace ICSharpCode.NRefactory.CSharp m.BodyRegion = MakeRegion(methodDeclaration.Body); - //TODO ConvertTypeParameters(m.TypeParameters, methodDeclaration.TypeParameters, methodDeclaration.Constraints); + ConvertTypeParameters(m.TypeParameters, methodDeclaration.TypeParameters, methodDeclaration.Constraints); m.ReturnType = ConvertType(methodDeclaration.ReturnType); ConvertAttributes(m.Attributes, methodDeclaration.Attributes.Where(s => s.AttributeTarget != AttributeTarget.Return)); ConvertAttributes(m.ReturnTypeAttributes, methodDeclaration.Attributes.Where(s => s.AttributeTarget == AttributeTarget.Return)); @@ -318,7 +325,13 @@ namespace ICSharpCode.NRefactory.CSharp return m; } - DefaultExplicitInterfaceImplementation ConvertInterfaceImplementation(AstNode interfaceType, string memberName) + void ConvertTypeParameters(IList output, IEnumerable typeParameters, IEnumerable constraints) + { + if (typeParameters.Any()) + throw new NotImplementedException(); + } + + DefaultExplicitInterfaceImplementation ConvertInterfaceImplementation(AstType interfaceType, string memberName) { return new DefaultExplicitInterfaceImplementation(ConvertType(interfaceType), memberName); } @@ -327,7 +340,7 @@ namespace ICSharpCode.NRefactory.CSharp #region Operators public override IEntity VisitOperatorDeclaration(OperatorDeclaration operatorDeclaration, object data) { - DefaultMethod m = new DefaultMethod(currentTypeDefinition, OperatorDeclaration.GetName(operatorDeclaration.OperatorType)); + DefaultMethod m = new DefaultMethod(currentTypeDefinition, operatorDeclaration.Name); m.EntityType = EntityType.Operator; m.Region = MakeRegion(operatorDeclaration); m.BodyRegion = MakeRegion(operatorDeclaration.Body); @@ -395,13 +408,6 @@ namespace ICSharpCode.NRefactory.CSharp public override IEntity VisitPropertyDeclaration(PropertyDeclaration propertyDeclaration, object data) { DefaultProperty p = new DefaultProperty(currentTypeDefinition, propertyDeclaration.Name); - HandlePropertyOrIndexer(p, propertyDeclaration); - currentTypeDefinition.Properties.Add(p); - return p; - } - - void HandlePropertyOrIndexer(DefaultProperty p, PropertyDeclaration propertyDeclaration) - { p.Region = MakeRegion(propertyDeclaration); p.BodyRegion = MakeBraceRegion(propertyDeclaration); ApplyModifiers(p, propertyDeclaration.Modifiers); @@ -413,13 +419,25 @@ namespace ICSharpCode.NRefactory.CSharp } p.Getter = ConvertAccessor(propertyDeclaration.Getter, p.Accessibility); p.Setter = ConvertAccessor(propertyDeclaration.Setter, p.Accessibility); + currentTypeDefinition.Properties.Add(p); + return p; } public override IEntity VisitIndexerDeclaration(IndexerDeclaration indexerDeclaration, object data) { DefaultProperty p = new DefaultProperty(currentTypeDefinition, "Items"); p.EntityType = EntityType.Indexer; - HandlePropertyOrIndexer(p, indexerDeclaration); + p.Region = MakeRegion(indexerDeclaration); + p.BodyRegion = MakeBraceRegion(indexerDeclaration); + ApplyModifiers(p, indexerDeclaration.Modifiers); + p.ReturnType = ConvertType(indexerDeclaration.ReturnType); + ConvertAttributes(p.Attributes, indexerDeclaration.Attributes); + if (!indexerDeclaration.PrivateImplementationType.IsNull) { + p.Accessibility = Accessibility.None; + p.InterfaceImplementations.Add(ConvertInterfaceImplementation(indexerDeclaration.PrivateImplementationType, p.Name)); + } + p.Getter = ConvertAccessor(indexerDeclaration.Getter, p.Accessibility); + p.Setter = ConvertAccessor(indexerDeclaration.Setter, p.Accessibility); ConvertParameters(p.Parameters, indexerDeclaration.Parameters); currentTypeDefinition.Properties.Add(p); return p; @@ -528,14 +546,14 @@ namespace ICSharpCode.NRefactory.CSharp #endregion #region Types - ITypeReference ConvertType(AstNode node, bool isInUsingDeclaration = false) + ITypeReference ConvertType(AstType type, bool isInUsingDeclaration = false) { - return ConvertType(node, currentTypeDefinition, currentMethod, usingScope, isInUsingDeclaration); + return ConvertType(type, currentTypeDefinition, currentMethod, usingScope, isInUsingDeclaration); } - internal static ITypeReference ConvertType(AstNode node, ITypeDefinition parentTypeDefinition, IMethod parentMethodDefinition, UsingScope parentUsingScope, bool isInUsingDeclaration) + internal static ITypeReference ConvertType(AstType type, ITypeDefinition parentTypeDefinition, IMethod parentMethodDefinition, UsingScope parentUsingScope, bool isInUsingDeclaration) { - SimpleType s = node as SimpleType; + SimpleType s = type as SimpleType; if (s != null) { List typeArguments = new List(); foreach (var ta in s.TypeArguments) { @@ -551,25 +569,8 @@ namespace ICSharpCode.NRefactory.CSharp } return new SimpleTypeOrNamespaceReference(s.Identifier, typeArguments, parentTypeDefinition, parentUsingScope, isInUsingDeclaration); } - IdentifierExpression ident = node as IdentifierExpression; - if (ident != null) { - // TODO: get rid of this code once the parser produces SimpleType instead of IdentifierExpression - List typeArguments = new List(); - foreach (var ta in ident.TypeArguments) { - typeArguments.Add(ConvertType(ta, parentTypeDefinition, parentMethodDefinition, parentUsingScope, isInUsingDeclaration)); - } - if (typeArguments.Count == 0 && parentMethodDefinition != null) { - // SimpleTypeOrNamespaceReference doesn't support method type parameters, - // so we directly handle them here. - foreach (ITypeParameter tp in parentMethodDefinition.TypeParameters) { - if (tp.Name == s.Identifier) - return tp; - } - } - return new SimpleTypeOrNamespaceReference(ident.Identifier, typeArguments, parentTypeDefinition, parentUsingScope, isInUsingDeclaration); - } - PrimitiveType p = node as PrimitiveType; + PrimitiveType p = type as PrimitiveType; if (p != null) { switch (p.Keyword) { case "string": @@ -608,7 +609,7 @@ namespace ICSharpCode.NRefactory.CSharp return SharedTypes.UnknownType; } } - MemberType m = node as MemberType; + MemberType m = type as MemberType; if (m != null) { ITypeOrNamespaceReference t; if (m.IsDoubleColon) { @@ -629,7 +630,7 @@ namespace ICSharpCode.NRefactory.CSharp } return new MemberTypeOrNamespaceReference(t, m.MemberName, typeArguments, parentTypeDefinition, parentUsingScope); } - ComposedType c = node as ComposedType; + ComposedType c = type as ComposedType; if (c != null) { ITypeReference t = ConvertType(c.BaseType, parentTypeDefinition, parentMethodDefinition, parentUsingScope, isInUsingDeclaration); if (c.HasNullableSpecifier) { @@ -643,7 +644,7 @@ namespace ICSharpCode.NRefactory.CSharp } return t; } - Debug.WriteLine("Unknown node used as type: " + node); + Debug.WriteLine("Unknown node used as type: " + type); return SharedTypes.UnknownType; } #endregion diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs b/ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs index 3dbf53a42..904bbae99 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/CSharpResolver.cs @@ -26,13 +26,22 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver internal readonly CancellationToken cancellationToken; #region Constructor - public CSharpResolver(ITypeResolveContext context, CancellationToken cancellationToken = default(CancellationToken)) + public CSharpResolver(ITypeResolveContext context) + { + if (context == null) + throw new ArgumentNullException("context"); + this.context = context; + } + + #if !DOTNET35 + public CSharpResolver(ITypeResolveContext context, CancellationToken cancellationToken) { if (context == null) throw new ArgumentNullException("context"); this.context = context; this.cancellationToken = cancellationToken; } + #endif #endregion #region Properties @@ -1513,12 +1522,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } } - ResolveResult rr = LookupSimpleNameOrTypeName( + return LookupSimpleNameOrTypeName( identifier, typeArguments, isInvocationTarget ? SimpleNameLookupMode.InvocationTarget : SimpleNameLookupMode.Expression); - if (rr == ErrorResult && typeArguments.Count == 0) - rr = new UnknownIdentifierResolveResult(identifier); - return rr; } public ResolveResult LookupSimpleNamespaceOrTypeName(string identifier, IList typeArguments, bool isUsingDeclaration = false) @@ -1633,7 +1639,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } // if we didn't find anything: repeat lookup with parent namespace } - return ErrorResult; + if (typeArguments.Count == 0) + return new UnknownIdentifierResolveResult(identifier); + else + return ErrorResult; } /// @@ -1822,7 +1831,8 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } else { // No candidate found at all (not even an inapplicable one). // This can happen with empty method groups (as sometimes used with extension methods) - return new UnknownMethodResolveResult(mgrr.TargetType, mgrr.MethodName, mgrr.TypeArguments, CreateParameters(arguments, argumentNames)); + return new UnknownMethodResolveResult( + mgrr.TargetType, mgrr.MethodName, mgrr.TypeArguments, CreateParameters(arguments, argumentNames)); } } UnknownMemberResolveResult umrr = target as UnknownMemberResolveResult; @@ -1840,9 +1850,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver return ErrorResult; } - static List CreateParameters(ResolveResult[] arguments, string[] argumentNames) + static List CreateParameters(ResolveResult[] arguments, string[] argumentNames) { - List list = new List(); + List list = new List(); if (argumentNames == null) { argumentNames = new string[arguments.Length]; } else { diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/MemberLookup.cs b/ICSharpCode.NRefactory/CSharp/Resolver/MemberLookup.cs index 615c23947..f124141fa 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/MemberLookup.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/MemberLookup.cs @@ -170,10 +170,10 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver Predicate memberFilter = delegate(IMember member) { return !member.IsOverride && member.Name == name && IsAccessible(member, allowProtectedAccess); }; - members.AddRange(type.GetMethods(context, memberFilter)); - members.AddRange(type.GetProperties(context, memberFilter)); - members.AddRange(type.GetFields(context, memberFilter)); - members.AddRange(type.GetEvents(context, memberFilter)); + members.AddRange(type.GetMethods(context, memberFilter.SafeCast()).SafeCast()); + members.AddRange(type.GetProperties(context, memberFilter.SafeCast()).SafeCast()); + members.AddRange(type.GetFields(context, memberFilter.SafeCast()).SafeCast()); + members.AddRange(type.GetEvents(context, memberFilter.SafeCast()).SafeCast()); if (isInvocation) members.RemoveAll(m => !IsInvocable(m, context)); } else { @@ -183,7 +183,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver return method.TypeParameters.Count == typeArgumentCount && !method.IsOverride && method.Name == name && IsAccessible(method, allowProtectedAccess); }; - members.AddRange(type.GetMethods(context, memberFilter)); + members.AddRange(type.GetMethods(context, memberFilter).SafeCast()); } // TODO: can't members also hide types? diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/MemberTypeOrNamespaceReference.cs b/ICSharpCode.NRefactory/CSharp/Resolver/MemberTypeOrNamespaceReference.cs index e9b0da565..350701a0e 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/MemberTypeOrNamespaceReference.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/MemberTypeOrNamespaceReference.cs @@ -62,7 +62,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver if (typeArguments.Count == 0) return target.ToString() + "." + identifier; else - return target.ToString() + "." + identifier + "<" + string.Join(",", typeArguments) + ">"; + return target.ToString() + "." + identifier + "<" + DotNet35Compat.StringJoin(",", typeArguments) + ">"; } } } diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/OverloadResolution.cs b/ICSharpCode.NRefactory/CSharp/Resolver/OverloadResolution.cs index 7c72f8d8b..d4d1fca43 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/OverloadResolution.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/OverloadResolution.cs @@ -446,7 +446,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver { bool c1IsBetter = false; bool c2IsBetter = false; - foreach (var pair in t1.Zip>(t2, Tuple.Create)) { + foreach (var pair in t1.Zip(t2, (a,b) => new { Item1 = a, Item2 = b })) { switch (MoreSpecificFormalParameter(pair.Item1, pair.Item2)) { case 1: c1IsBetter = true; diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs b/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs index f950a474e..060bdfa7f 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/ResolveVisitor.cs @@ -224,11 +224,11 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver return VisitFieldOrEventDeclaration(eventDeclaration); } - ResolveResult VisitFieldOrEventDeclaration(MemberDeclaration fieldDeclaration) + ResolveResult VisitFieldOrEventDeclaration(AttributedNode fieldOrEventDeclaration) { - int initializerCount = fieldDeclaration.GetChildrenByRole(FieldDeclaration.Roles.Variable).Count(); + int initializerCount = fieldOrEventDeclaration.GetChildrenByRole(FieldDeclaration.Roles.Variable).Count(); ResolveResult result = null; - for (AstNode node = fieldDeclaration.FirstChild; node != null; node = node.NextSibling) { + for (AstNode node = fieldOrEventDeclaration.FirstChild; node != null; node = node.NextSibling) { if (node.Role == FieldDeclaration.Roles.Variable) { if (resolver.CurrentTypeDefinition != null) { resolver.CurrentMember = resolver.CurrentTypeDefinition.Fields.FirstOrDefault(f => f.Region.IsInside(node.StartLocation)); @@ -309,14 +309,14 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } // handle properties/indexers - ResolveResult VisitPropertyMember(PropertyDeclaration propertyDeclaration) + ResolveResult VisitPropertyMember(MemberDeclaration propertyOrIndexerDeclaration) { try { if (resolver.CurrentTypeDefinition != null) { - resolver.CurrentMember = resolver.CurrentTypeDefinition.Properties.FirstOrDefault(p => p.Region.IsInside(propertyDeclaration.StartLocation)); + resolver.CurrentMember = resolver.CurrentTypeDefinition.Properties.FirstOrDefault(p => p.Region.IsInside(propertyOrIndexerDeclaration.StartLocation)); } - for (AstNode node = propertyDeclaration.FirstChild; node != null; node = node.NextSibling) { + for (AstNode node = propertyOrIndexerDeclaration.FirstChild; node != null; node = node.NextSibling) { if (node.Role == PropertyDeclaration.SetterRole && resolver.CurrentMember != null) { resolver.PushBlock(); resolver.AddVariable(resolver.CurrentMember.ReturnType, "value"); @@ -472,9 +472,9 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver return ie != null && ie.Target == node; } - IType ResolveType(AstNode node) + IType ResolveType(AstType type) { - return MakeTypeReference(node).Resolve(resolver.Context); + return MakeTypeReference(type).Resolve(resolver.Context); } public override ResolveResult VisitAnonymousMethodExpression(AnonymousMethodExpression anonymousMethodExpression, object data) @@ -593,7 +593,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } } - ResolveResult[] GetArguments(IEnumerable argumentExpressions, out string[] argumentNames) + ResolveResult[] GetArguments(IEnumerable argumentExpressions, out string[] argumentNames) { argumentNames = null; // TODO: add support for named arguments ResolveResult[] arguments = new ResolveResult[argumentExpressions.Count()]; @@ -951,7 +951,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver /// Creates a type reference for the specified type node. /// If the type node is 'var', performs type inference on the initializer expression. /// - ITypeReference MakeTypeReference(AstNode type, AstNode initializerExpression, bool isForEach) + ITypeReference MakeTypeReference(AstType type, AstNode initializerExpression, bool isForEach) { if (initializerExpression != null && IsVar(type)) { return new VarTypeReference(this, resolver.Clone(), initializerExpression, isForEach); @@ -960,14 +960,16 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver } } - ITypeReference MakeTypeReference(AstNode type) + ITypeReference MakeTypeReference(AstType type) { return TypeSystemConvertVisitor.ConvertType(type, resolver.CurrentTypeDefinition, resolver.CurrentMember as IMethod, resolver.UsingScope, false); } - static bool IsVar(AstNode returnType) + static bool IsVar(AstType returnType) { - return returnType is IdentifierExpression && ((IdentifierExpression)returnType).Identifier == "var"; + return returnType is SimpleType + && ((SimpleType)returnType).Identifier == "var" + && ((SimpleType)returnType).TypeArguments.Count == 0; } sealed class VarTypeReference : ITypeReference @@ -1072,25 +1074,36 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver public override ResolveResult VisitPrimitiveType(PrimitiveType primitiveType, object data) { ScanChildren(primitiveType); - return new TypeResolveResult(MakeTypeReference(primitiveType).Resolve(resolver.Context)); + return new TypeResolveResult(ResolveType(primitiveType)); } public override ResolveResult VisitSimpleType(SimpleType simpleType, object data) { ScanChildren(simpleType); - return new TypeResolveResult(MakeTypeReference(simpleType).Resolve(resolver.Context)); + return ResolveTypeOrNamespace(simpleType); + } + + ResolveResult ResolveTypeOrNamespace(AstType type) + { + ITypeReference typeRef = MakeTypeReference(type); + ITypeOrNamespaceReference typeOrNsRef = typeRef as ITypeOrNamespaceReference; + if (typeOrNsRef != null) { + return typeOrNsRef.DoResolve(resolver.Context); + } else { + return new TypeResolveResult(typeRef.Resolve(resolver.Context)); + } } public override ResolveResult VisitMemberType(MemberType memberType, object data) { ScanChildren(memberType); - return new TypeResolveResult(MakeTypeReference(memberType).Resolve(resolver.Context)); + return ResolveTypeOrNamespace(memberType); } public override ResolveResult VisitComposedType(ComposedType composedType, object data) { ScanChildren(composedType); - return new TypeResolveResult(MakeTypeReference(composedType).Resolve(resolver.Context)); + return new TypeResolveResult(ResolveType(composedType)); } #endregion @@ -1135,7 +1148,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver { throw new NotImplementedException(); } - */ + */ #endregion public override ResolveResult VisitIdentifier(Identifier identifier, object data) diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/SimpleTypeOrNamespaceReference.cs b/ICSharpCode.NRefactory/CSharp/Resolver/SimpleTypeOrNamespaceReference.cs index e51fde628..a500e85e0 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/SimpleTypeOrNamespaceReference.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/SimpleTypeOrNamespaceReference.cs @@ -57,7 +57,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver if (typeArguments.Count == 0) return identifier; else - return identifier + "<" + string.Join(",", typeArguments) + ">"; + return identifier + "<" + DotNet35Compat.StringJoin(",", typeArguments) + ">"; } } } diff --git a/ICSharpCode.NRefactory/CSharp/Resolver/TypeInference.cs b/ICSharpCode.NRefactory/CSharp/Resolver/TypeInference.cs index afdfca58d..488a6c31f 100644 --- a/ICSharpCode.NRefactory/CSharp/Resolver/TypeInference.cs +++ b/ICSharpCode.NRefactory/CSharp/Resolver/TypeInference.cs @@ -856,7 +856,7 @@ namespace ICSharpCode.NRefactory.CSharp.Resolver bool success; IType[] result = InferTypeArgumentsFromBounds( candidateDef.TypeParameters, - new ParameterizedType(candidateDef, candidateDef.TypeParameters), + new ParameterizedType(candidateDef, candidateDef.TypeParameters.SafeCast()), lowerBounds, upperBounds, out success); if (success) { diff --git a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj index 6fdcd0c9f..8698db3e8 100644 --- a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj +++ b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj @@ -7,7 +7,7 @@ Library ICSharpCode.NRefactory ICSharpCode.NRefactory - v4.0 + v3.5 Properties 10.0.0 2.0 @@ -15,6 +15,9 @@ False false 1591,0618 + + False + -Microsoft.Design#CA1026;-Microsoft.Security#CA2104 AnyCPU @@ -27,24 +30,27 @@ bin\Debug\ Full False - DEBUG;TRACE;FULL_AST + DEBUG;TRACE;FULL_AST;DOTNET35 + False bin\Release\ None True - TRACE;FULL_AST + TRACE;FULL_AST;DOTNET35 + False - full + Full false 4 true - none + None true 4 + false @@ -322,6 +328,7 @@ + diff --git a/ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs b/ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs index 65bcae4b9..7564ed995 100644 --- a/ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs +++ b/ICSharpCode.NRefactory/TypeSystem/CecilLoader.cs @@ -297,7 +297,7 @@ namespace ICSharpCode.NRefactory.TypeSystem } } - static readonly string DynamicAttributeFullName = typeof(DynamicAttribute).FullName; + const string DynamicAttributeFullName = "System.Runtime.CompilerServices.DynamicAttribute"; static bool HasDynamicAttribute(ICustomAttributeProvider attributeProvider, int typeIndex) { diff --git a/ICSharpCode.NRefactory/TypeSystem/ExtensionMethods.cs b/ICSharpCode.NRefactory/TypeSystem/ExtensionMethods.cs index 4c830048a..da2a6c06a 100644 --- a/ICSharpCode.NRefactory/TypeSystem/ExtensionMethods.cs +++ b/ICSharpCode.NRefactory/TypeSystem/ExtensionMethods.cs @@ -70,15 +70,17 @@ namespace ICSharpCode.NRefactory.TypeSystem throw new ArgumentNullException("context"); HashSet typeDefinitions = new HashSet(); - Func> recursion = + Func> recursion = t => t.GetBaseTypes(context).Select(b => b.GetDefinition()).Where(d => d != null && typeDefinitions.Add(d)); ITypeDefinition typeDef = type as ITypeDefinition; if (typeDef != null) { typeDefinitions.Add(typeDef); - return TreeTraversal.PreOrder(typeDef, recursion); + return TreeTraversal.PreOrder(typeDef, recursion); } else { - return TreeTraversal.PreOrder(recursion(type), recursion); + return TreeTraversal.PreOrder( + type.GetBaseTypes(context).Select(b => b.GetDefinition()).Where(d => d != null && typeDefinitions.Add(d)), + recursion); } } diff --git a/ICSharpCode.NRefactory/TypeSystem/IAttribute.cs b/ICSharpCode.NRefactory/TypeSystem/IAttribute.cs index 62d748290..b9bb2dd97 100644 --- a/ICSharpCode.NRefactory/TypeSystem/IAttribute.cs +++ b/ICSharpCode.NRefactory/TypeSystem/IAttribute.cs @@ -10,7 +10,9 @@ namespace ICSharpCode.NRefactory.TypeSystem /// /// Represents an attribute. /// + #if WITH_CONTRACTS [ContractClass(typeof(IAttributeContract))] + #endif [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix")] public interface IAttribute : IFreezable { @@ -35,6 +37,7 @@ namespace ICSharpCode.NRefactory.TypeSystem IList> NamedArguments { get; } } + #if WITH_CONTRACTS [ContractClassFor(typeof(IAttribute))] abstract class IAttributeContract : IFreezableContract, IAttribute { @@ -63,4 +66,5 @@ namespace ICSharpCode.NRefactory.TypeSystem } } } + #endif } diff --git a/ICSharpCode.NRefactory/TypeSystem/IConstantValue.cs b/ICSharpCode.NRefactory/TypeSystem/IConstantValue.cs index 030f5a118..8ea9a8f3d 100644 --- a/ICSharpCode.NRefactory/TypeSystem/IConstantValue.cs +++ b/ICSharpCode.NRefactory/TypeSystem/IConstantValue.cs @@ -6,7 +6,9 @@ using System.Diagnostics.Contracts; namespace ICSharpCode.NRefactory.TypeSystem { + #if WITH_CONTRACTS [ContractClass(typeof(IConstantValueContract))] + #endif public interface IConstantValue : IFreezable { /// @@ -30,6 +32,7 @@ namespace ICSharpCode.NRefactory.TypeSystem object GetValue(ITypeResolveContext context); } + #if WITH_CONTRACTS [ContractClassFor(typeof(IConstantValue))] abstract class IConstantValueContract : IFreezableContract, IConstantValue { @@ -46,4 +49,5 @@ namespace ICSharpCode.NRefactory.TypeSystem return null; } } + #endif } diff --git a/ICSharpCode.NRefactory/TypeSystem/IEntity.cs b/ICSharpCode.NRefactory/TypeSystem/IEntity.cs index 752cb693d..d9f92d1ce 100644 --- a/ICSharpCode.NRefactory/TypeSystem/IEntity.cs +++ b/ICSharpCode.NRefactory/TypeSystem/IEntity.cs @@ -7,7 +7,9 @@ using System.Diagnostics.Contracts; namespace ICSharpCode.NRefactory.TypeSystem { + #if WITH_CONTRACTS [ContractClass(typeof(IEntityContract))] + #endif public interface IEntity : INamedElement, IFreezable { EntityType EntityType { get; } @@ -75,6 +77,7 @@ namespace ICSharpCode.NRefactory.TypeSystem //bool IsAccessible(IClass callingClass, bool isAccessThoughReferenceOfCurrentClass); } + #if WITH_CONTRACTS [ContractClassFor(typeof(IEntity))] abstract class IEntityContract : INamedElementContract, IEntity { @@ -144,4 +147,5 @@ namespace ICSharpCode.NRefactory.TypeSystem { } } + #endif } diff --git a/ICSharpCode.NRefactory/TypeSystem/IExplicitInterfaceImplementation.cs b/ICSharpCode.NRefactory/TypeSystem/IExplicitInterfaceImplementation.cs index 91259ff0e..60452a670 100644 --- a/ICSharpCode.NRefactory/TypeSystem/IExplicitInterfaceImplementation.cs +++ b/ICSharpCode.NRefactory/TypeSystem/IExplicitInterfaceImplementation.cs @@ -9,7 +9,9 @@ namespace ICSharpCode.NRefactory.TypeSystem /// /// Represents an explicit interface implementation. /// + #if WITH_CONTRACTS [ContractClass(typeof(IExplicitInterfaceImplementationContract))] + #endif public interface IExplicitInterfaceImplementation : IFreezable { /// @@ -23,6 +25,7 @@ namespace ICSharpCode.NRefactory.TypeSystem string MemberName { get; } } + #if WITH_CONTRACTS [ContractClassFor(typeof(IExplicitInterfaceImplementation))] abstract class IExplicitInterfaceImplementationContract : IFreezableContract, IExplicitInterfaceImplementation { @@ -40,4 +43,5 @@ namespace ICSharpCode.NRefactory.TypeSystem } } } + #endif } diff --git a/ICSharpCode.NRefactory/TypeSystem/IField.cs b/ICSharpCode.NRefactory/TypeSystem/IField.cs index c72526a78..c5c015299 100644 --- a/ICSharpCode.NRefactory/TypeSystem/IField.cs +++ b/ICSharpCode.NRefactory/TypeSystem/IField.cs @@ -9,7 +9,9 @@ namespace ICSharpCode.NRefactory.TypeSystem /// /// Represents a field or constant. /// + #if WITH_CONTRACTS [ContractClass(typeof(IFieldContract))] + #endif public interface IField : IMember, IVariable { /// @@ -28,6 +30,7 @@ namespace ICSharpCode.NRefactory.TypeSystem bool IsVolatile { get; } } + #if WITH_CONTRACTS [ContractClassFor(typeof(IField))] abstract class IFieldContract : IMemberContract, IField { @@ -63,4 +66,5 @@ namespace ICSharpCode.NRefactory.TypeSystem get { return null; } } } + #endif } diff --git a/ICSharpCode.NRefactory/TypeSystem/IFreezable.cs b/ICSharpCode.NRefactory/TypeSystem/IFreezable.cs index 1705b4d75..baa35f42d 100644 --- a/ICSharpCode.NRefactory/TypeSystem/IFreezable.cs +++ b/ICSharpCode.NRefactory/TypeSystem/IFreezable.cs @@ -6,7 +6,9 @@ using System.Diagnostics.Contracts; namespace ICSharpCode.NRefactory.TypeSystem { + #if WITH_CONTRACTS [ContractClass(typeof(IFreezableContract))] + #endif public interface IFreezable { /// @@ -20,6 +22,7 @@ namespace ICSharpCode.NRefactory.TypeSystem void Freeze(); } + #if WITH_CONTRACTS [ContractClassFor(typeof(IFreezable))] abstract class IFreezableContract : IFreezable { @@ -33,4 +36,5 @@ namespace ICSharpCode.NRefactory.TypeSystem Contract.Ensures(self.IsFrozen); } } + #endif } diff --git a/ICSharpCode.NRefactory/TypeSystem/IInterningProvider.cs b/ICSharpCode.NRefactory/TypeSystem/IInterningProvider.cs index 3e8f45655..16b23d063 100644 --- a/ICSharpCode.NRefactory/TypeSystem/IInterningProvider.cs +++ b/ICSharpCode.NRefactory/TypeSystem/IInterningProvider.cs @@ -25,7 +25,9 @@ namespace ICSharpCode.NRefactory.TypeSystem /// and which are used only within a single type definition. Then a persistent file format could be organized so /// that shared objects are loaded only once, yet non-shared objects get loaded lazily together with the class. /// + #if WITH_CONTRACTS [ContractClass(typeof(IInterningProviderContract))] + #endif public interface IInterningProvider { /// @@ -39,6 +41,7 @@ namespace ICSharpCode.NRefactory.TypeSystem IList InternList(IList list) where T : class; } + #if WITH_CONTRACTS [ContractClassFor(typeof(IInterningProvider))] abstract class IInterningProviderContract : IInterningProvider { @@ -54,4 +57,5 @@ namespace ICSharpCode.NRefactory.TypeSystem return list; } } + #endif } diff --git a/ICSharpCode.NRefactory/TypeSystem/IMember.cs b/ICSharpCode.NRefactory/TypeSystem/IMember.cs index 4fc545495..4a51074bf 100644 --- a/ICSharpCode.NRefactory/TypeSystem/IMember.cs +++ b/ICSharpCode.NRefactory/TypeSystem/IMember.cs @@ -10,7 +10,9 @@ namespace ICSharpCode.NRefactory.TypeSystem /// /// Method/field/entity. /// + #if WITH_CONTRACTS [ContractClass(typeof(IMemberContract))] + #endif public interface IMember : IEntity { /// @@ -58,6 +60,7 @@ namespace ICSharpCode.NRefactory.TypeSystem } } + #if WITH_CONTRACTS [ContractClassFor(typeof(IMember))] abstract class IMemberContract : IEntityContract, IMember { @@ -101,4 +104,5 @@ namespace ICSharpCode.NRefactory.TypeSystem get { return false; } } } + #endif } diff --git a/ICSharpCode.NRefactory/TypeSystem/IMethod.cs b/ICSharpCode.NRefactory/TypeSystem/IMethod.cs index 56ded253d..e66ab0782 100644 --- a/ICSharpCode.NRefactory/TypeSystem/IMethod.cs +++ b/ICSharpCode.NRefactory/TypeSystem/IMethod.cs @@ -10,7 +10,9 @@ namespace ICSharpCode.NRefactory.TypeSystem /// /// Represents a method, constructor, destructor or operator. /// + #if WITH_CONTRACTS [ContractClass(typeof(IMethodContract))] + #endif public interface IMethod : IParameterizedMember { /// @@ -30,6 +32,7 @@ namespace ICSharpCode.NRefactory.TypeSystem bool IsOperator { get; } } + #if WITH_CONTRACTS [ContractClassFor(typeof(IMethod))] abstract class IMethodContract : IParameterizedMemberContract, IMethod { @@ -47,13 +50,6 @@ namespace ICSharpCode.NRefactory.TypeSystem } } -// IList IMethod.HandlesClauses { -// get { -// Contract.Ensures(Contract.Result>() != null); -// return null; -// } -// } - bool IMethod.IsExtensionMethod { get { return false; } } @@ -70,4 +66,5 @@ namespace ICSharpCode.NRefactory.TypeSystem get { return false; } } } + #endif } diff --git a/ICSharpCode.NRefactory/TypeSystem/INamedElement.cs b/ICSharpCode.NRefactory/TypeSystem/INamedElement.cs index 407caf6c3..789108543 100644 --- a/ICSharpCode.NRefactory/TypeSystem/INamedElement.cs +++ b/ICSharpCode.NRefactory/TypeSystem/INamedElement.cs @@ -6,7 +6,9 @@ using System.Diagnostics.Contracts; namespace ICSharpCode.NRefactory.TypeSystem { + #if WITH_CONTRACTS [ContractClass(typeof(INamedElementContract))] + #endif public interface INamedElement { /// @@ -63,6 +65,7 @@ namespace ICSharpCode.NRefactory.TypeSystem } } + #if WITH_CONTRACTS [ContractClassFor(typeof(INamedElement))] abstract class INamedElementContract : INamedElement { @@ -94,4 +97,5 @@ namespace ICSharpCode.NRefactory.TypeSystem } } } + #endif } diff --git a/ICSharpCode.NRefactory/TypeSystem/IParameter.cs b/ICSharpCode.NRefactory/TypeSystem/IParameter.cs index 0333a45a9..3f7d9b082 100644 --- a/ICSharpCode.NRefactory/TypeSystem/IParameter.cs +++ b/ICSharpCode.NRefactory/TypeSystem/IParameter.cs @@ -7,7 +7,9 @@ using System.Diagnostics.Contracts; namespace ICSharpCode.NRefactory.TypeSystem { + #if WITH_CONTRACTS [ContractClass(typeof(IParameterContract))] + #endif public interface IParameter : IVariable, IFreezable { /// @@ -46,6 +48,7 @@ namespace ICSharpCode.NRefactory.TypeSystem bool IsOptional { get; } } + #if WITH_CONTRACTS [ContractClassFor(typeof(IParameter))] abstract class IParameterContract : IVariableContract, IParameter { @@ -92,4 +95,5 @@ namespace ICSharpCode.NRefactory.TypeSystem { } } + #endif } diff --git a/ICSharpCode.NRefactory/TypeSystem/IParameterizedMember.cs b/ICSharpCode.NRefactory/TypeSystem/IParameterizedMember.cs index e719ca59a..a60c75133 100644 --- a/ICSharpCode.NRefactory/TypeSystem/IParameterizedMember.cs +++ b/ICSharpCode.NRefactory/TypeSystem/IParameterizedMember.cs @@ -10,12 +10,15 @@ namespace ICSharpCode.NRefactory.TypeSystem /// /// Represents a method or property. /// + #if WITH_CONTRACTS [ContractClass(typeof(IParameterizedMemberContract))] + #endif public interface IParameterizedMember : IMember { IList Parameters { get; } } + #if WITH_CONTRACTS [ContractClassFor(typeof(IParameterizedMember))] abstract class IParameterizedMemberContract : IMemberContract, IParameterizedMember { @@ -26,4 +29,5 @@ namespace ICSharpCode.NRefactory.TypeSystem } } } + #endif } diff --git a/ICSharpCode.NRefactory/TypeSystem/IProjectContent.cs b/ICSharpCode.NRefactory/TypeSystem/IProjectContent.cs index 274bcfbe3..be4d9651d 100644 --- a/ICSharpCode.NRefactory/TypeSystem/IProjectContent.cs +++ b/ICSharpCode.NRefactory/TypeSystem/IProjectContent.cs @@ -10,12 +10,15 @@ namespace ICSharpCode.NRefactory.TypeSystem /// /// Mutable container of all classes in an assembly. /// + #if WITH_CONTRACTS [ContractClass(typeof(IProjectContentContract))] + #endif public interface IProjectContent : ITypeResolveContext { IList AssemblyAttributes { get; } } + #if WITH_CONTRACTS [ContractClassFor(typeof(IProjectContent))] abstract class IProjectContentContract : ITypeResolveContextContract, IProjectContent { @@ -26,4 +29,5 @@ namespace ICSharpCode.NRefactory.TypeSystem } } } + #endif } diff --git a/ICSharpCode.NRefactory/TypeSystem/ISupportsInterning.cs b/ICSharpCode.NRefactory/TypeSystem/ISupportsInterning.cs index 771ff43f9..86de1c379 100644 --- a/ICSharpCode.NRefactory/TypeSystem/ISupportsInterning.cs +++ b/ICSharpCode.NRefactory/TypeSystem/ISupportsInterning.cs @@ -11,7 +11,9 @@ namespace ICSharpCode.NRefactory.TypeSystem /// Interface for TypeSystem objects that support interning. /// See for more information. /// + #if WITH_CONTRACTS [ContractClass(typeof(ISupportsInterningContract))] + #endif public interface ISupportsInterning { /// @@ -30,6 +32,7 @@ namespace ICSharpCode.NRefactory.TypeSystem bool EqualsForInterning(ISupportsInterning other); } + #if WITH_CONTRACTS [ContractClassFor(typeof(ISupportsInterning))] abstract class ISupportsInterningContract : ISupportsInterning { @@ -48,4 +51,5 @@ namespace ICSharpCode.NRefactory.TypeSystem return false; } } + #endif } diff --git a/ICSharpCode.NRefactory/TypeSystem/IType.cs b/ICSharpCode.NRefactory/TypeSystem/IType.cs index d8cec4091..f6d3b3a32 100644 --- a/ICSharpCode.NRefactory/TypeSystem/IType.cs +++ b/ICSharpCode.NRefactory/TypeSystem/IType.cs @@ -7,7 +7,9 @@ using System.Diagnostics.Contracts; namespace ICSharpCode.NRefactory.TypeSystem { + #if WITH_CONTRACTS [ContractClass(typeof(ITypeContract))] + #endif public interface IType : ITypeReference, INamedElement, IEquatable { /// @@ -90,6 +92,7 @@ namespace ICSharpCode.NRefactory.TypeSystem IEnumerable GetEvents(ITypeResolveContext context, Predicate filter = null); } + #if WITH_CONTRACTS [ContractClassFor(typeof(IType))] abstract class ITypeContract : ITypeReferenceContract, IType { @@ -209,4 +212,5 @@ namespace ICSharpCode.NRefactory.TypeSystem return this; } } + #endif } diff --git a/ICSharpCode.NRefactory/TypeSystem/ITypeDefinition.cs b/ICSharpCode.NRefactory/TypeSystem/ITypeDefinition.cs index dc8576d8f..905a85fdc 100644 --- a/ICSharpCode.NRefactory/TypeSystem/ITypeDefinition.cs +++ b/ICSharpCode.NRefactory/TypeSystem/ITypeDefinition.cs @@ -10,7 +10,9 @@ namespace ICSharpCode.NRefactory.TypeSystem /// /// Represents a class, enum, interface, struct, delegate or VB module. /// + #if WITH_CONTRACTS [ContractClass(typeof(ITypeDefinitionContract))] + #endif public interface ITypeDefinition : IType, IEntity { ClassType ClassType { get; } @@ -44,6 +46,7 @@ namespace ICSharpCode.NRefactory.TypeSystem IEnumerable Members { get; } } + #if WITH_CONTRACTS [ContractClassFor(typeof(ITypeDefinition))] abstract class ITypeDefinitionContract : ITypeContract, ITypeDefinition { @@ -181,4 +184,5 @@ namespace ICSharpCode.NRefactory.TypeSystem } #endregion } + #endif } diff --git a/ICSharpCode.NRefactory/TypeSystem/ITypeParameter.cs b/ICSharpCode.NRefactory/TypeSystem/ITypeParameter.cs index ee7f43dfc..75d6d4cb4 100644 --- a/ICSharpCode.NRefactory/TypeSystem/ITypeParameter.cs +++ b/ICSharpCode.NRefactory/TypeSystem/ITypeParameter.cs @@ -11,7 +11,9 @@ namespace ICSharpCode.NRefactory.TypeSystem /// /// Type parameter of a generic class/method. /// + #if WITH_CONTRACTS [ContractClass(typeof(ITypeParameterContract))] + #endif public interface ITypeParameter : IType, IFreezable { /// @@ -99,6 +101,7 @@ namespace ICSharpCode.NRefactory.TypeSystem Contravariant }; + #if WITH_CONTRACTS [ContractClassFor(typeof(ITypeParameter))] abstract class ITypeParameterContract : ITypeContract, ITypeParameter { @@ -178,4 +181,5 @@ namespace ICSharpCode.NRefactory.TypeSystem { } } + #endif } diff --git a/ICSharpCode.NRefactory/TypeSystem/ITypeReference.cs b/ICSharpCode.NRefactory/TypeSystem/ITypeReference.cs index 70f105b3a..50795311b 100644 --- a/ICSharpCode.NRefactory/TypeSystem/ITypeReference.cs +++ b/ICSharpCode.NRefactory/TypeSystem/ITypeReference.cs @@ -11,7 +11,9 @@ namespace ICSharpCode.NRefactory.TypeSystem /// Represents a reference to a type. /// Must be resolved before it can be used as type. /// + #if WITH_CONTRACTS [ContractClass(typeof(ITypeReferenceContract))] + #endif public interface ITypeReference { // Keep this interface simple: I decided against having GetMethods/GetEvents etc. here, @@ -26,6 +28,7 @@ namespace ICSharpCode.NRefactory.TypeSystem IType Resolve(ITypeResolveContext context); } + #if WITH_CONTRACTS [ContractClassFor(typeof(ITypeReference))] abstract class ITypeReferenceContract : ITypeReference { @@ -36,4 +39,5 @@ namespace ICSharpCode.NRefactory.TypeSystem return null; } } + #endif } \ No newline at end of file diff --git a/ICSharpCode.NRefactory/TypeSystem/ITypeResolveContext.cs b/ICSharpCode.NRefactory/TypeSystem/ITypeResolveContext.cs index 335153ee6..3c89b13ad 100644 --- a/ICSharpCode.NRefactory/TypeSystem/ITypeResolveContext.cs +++ b/ICSharpCode.NRefactory/TypeSystem/ITypeResolveContext.cs @@ -12,7 +12,9 @@ namespace ICSharpCode.NRefactory.TypeSystem /// /// Context representing the set of assemblies in which a type is being searched. /// + #if WITH_CONTRACTS [ContractClass(typeof(ITypeResolveContextContract))] + #endif public interface ITypeResolveContext { /// @@ -91,6 +93,7 @@ namespace ICSharpCode.NRefactory.TypeSystem CacheManager CacheManager { get; } } + #if WITH_CONTRACTS [ContractClassFor(typeof(ITypeResolveContext))] abstract class ITypeResolveContextContract : ITypeResolveContext { @@ -140,4 +143,5 @@ namespace ICSharpCode.NRefactory.TypeSystem return null; } } + #endif } diff --git a/ICSharpCode.NRefactory/TypeSystem/IVariable.cs b/ICSharpCode.NRefactory/TypeSystem/IVariable.cs index cc4dfa9c4..5c8f1d903 100644 --- a/ICSharpCode.NRefactory/TypeSystem/IVariable.cs +++ b/ICSharpCode.NRefactory/TypeSystem/IVariable.cs @@ -9,7 +9,9 @@ namespace ICSharpCode.NRefactory.TypeSystem /// /// Represents a variable (name/return type pair). /// + #if WITH_CONTRACTS [ContractClass(typeof(IVariableContract))] + #endif public interface IVariable { /// @@ -33,6 +35,7 @@ namespace ICSharpCode.NRefactory.TypeSystem IConstantValue ConstantValue { get; } } + #if WITH_CONTRACTS [ContractClassFor(typeof(IVariable))] abstract class IVariableContract : IVariable { @@ -62,4 +65,5 @@ namespace ICSharpCode.NRefactory.TypeSystem get { return null; } } } + #endif } diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractType.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractType.cs index b2f981df6..9fd926da9 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractType.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/AbstractType.cs @@ -19,9 +19,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation if (string.IsNullOrEmpty(ns)) { return name; } else { - string combinedName = ns + "." + name; - Contract.Assume(!string.IsNullOrEmpty(combinedName)); - return combinedName; + return ns + "." + name; } } } diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultParameter.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultParameter.cs index 220f09a12..0f412842d 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultParameter.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultParameter.cs @@ -53,19 +53,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation base.FreezeInternal(); } - [ContractInvariantMethod] - void ObjectInvariant() - { - Contract.Invariant(type != null); - Contract.Invariant(name != null); - } - public string Name { get { return name; } set { if (value == null) throw new ArgumentNullException(); - Contract.EndContractBlock(); CheckBeforeMutation(); name = value; } @@ -76,7 +68,6 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation set { if (value == null) throw new ArgumentNullException(); - Contract.EndContractBlock(); CheckBeforeMutation(); type = value; } diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeDefinition.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeDefinition.cs index 4964cacc4..881d38585 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeDefinition.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/DefaultTypeDefinition.cs @@ -60,7 +60,6 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation throw new ArgumentNullException("declaringTypeDefinition"); if (string.IsNullOrEmpty(name)) throw new ArgumentException("name"); - Contract.EndContractBlock(); this.projectContent = declaringTypeDefinition.ProjectContent; this.declaringTypeDefinition = declaringTypeDefinition; this.name = name; @@ -73,20 +72,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation throw new ArgumentNullException("projectContent"); if (string.IsNullOrEmpty(name)) throw new ArgumentException("name"); - Contract.EndContractBlock(); this.projectContent = projectContent; this.ns = ns ?? string.Empty; this.name = name; } - [ContractInvariantMethod] - void ObjectInvariant() - { - Contract.Invariant(projectContent != null); - Contract.Invariant(!string.IsNullOrEmpty(name)); - Contract.Invariant(ns != null); - } - public ClassType ClassType { get { return classType; } set { @@ -164,7 +154,10 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation public IEnumerable Members { get { - return this.Fields.Concat(this.Properties).Concat(this.Methods).Concat(this.Events); + return this.Fields.SafeCast() + .Concat(this.Properties.SafeCast()) + .Concat(this.Methods.SafeCast()) + .Concat(this.Events.SafeCast()); } } @@ -187,15 +180,11 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation public string FullName { get { if (declaringTypeDefinition != null) { - string combinedName = declaringTypeDefinition.FullName + "." + this.name; - Contract.Assume(!string.IsNullOrEmpty(combinedName)); - return combinedName; + return declaringTypeDefinition.FullName + "." + this.name; } else if (string.IsNullOrEmpty(ns)) { return this.name; } else { - string combinedName = this.ns + "." + this.name; - Contract.Assume(!string.IsNullOrEmpty(combinedName)); - return combinedName; + return this.ns + "." + this.name; } } } diff --git a/ICSharpCode.NRefactory/TypeSystem/Implementation/SimpleInterningProvider.cs b/ICSharpCode.NRefactory/TypeSystem/Implementation/SimpleInterningProvider.cs index ce5c85864..7ed18be85 100644 --- a/ICSharpCode.NRefactory/TypeSystem/Implementation/SimpleInterningProvider.cs +++ b/ICSharpCode.NRefactory/TypeSystem/Implementation/SimpleInterningProvider.cs @@ -2,6 +2,7 @@ // This code is distributed under MIT X11 license (for details please see \doc\license.txt) using System; +using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; @@ -51,16 +52,27 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation } } - sealed class ListComparer : IEqualityComparer> + sealed class ListComparer : IEqualityComparer { - public bool Equals(IEnumerable a, IEnumerable b) + public bool Equals(IEnumerable a, IEnumerable b) { if (a.GetType() != b.GetType()) return false; - return Enumerable.SequenceEqual(a, b, ReferenceComparer.Instance); + IEnumerator e1 = a.GetEnumerator(); + IEnumerator e2 = b.GetEnumerator(); + while (e1.MoveNext()) { + // e1 has more elements than e2; or elements are different + if (!e2.MoveNext() || e1.Current != e2.Current) + return false; + } + if (e2.MoveNext()) // e2 has more elements than e1 + return false; + // No need to dispose e1/e2: non-generic IEnumerator doesn't implement IDisposable, + // and the underlying enumerator will likely be a List.Enumerator which has an empty Dispose() method. + return true; } - public int GetHashCode(IEnumerable obj) + public int GetHashCode(IEnumerable obj) { int hashCode = obj.GetType().GetHashCode(); unchecked { @@ -75,7 +87,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation Dictionary byValueDict = new Dictionary(); Dictionary supportsInternDict = new Dictionary(new InterningComparer()); - Dictionary, IEnumerable> listDict = new Dictionary, IEnumerable>(new ListComparer()); + Dictionary listDict = new Dictionary(new ListComparer()); public T Intern(T obj) where T : class { @@ -118,7 +130,7 @@ namespace ICSharpCode.NRefactory.TypeSystem.Implementation } if (!list.IsReadOnly) list = new ReadOnlyCollection(list); - IEnumerable output; + IEnumerable output; if (listDict.TryGetValue(list, out output)) list = (IList)output; else diff --git a/ICSharpCode.NRefactory/Utils/DotNet35Compat.cs b/ICSharpCode.NRefactory/Utils/DotNet35Compat.cs new file mode 100644 index 000000000..85c599947 --- /dev/null +++ b/ICSharpCode.NRefactory/Utils/DotNet35Compat.cs @@ -0,0 +1,58 @@ +// 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) + +using System; +using System.Collections.Generic; +using System.Linq; + +internal static class DotNet35Compat +{ + public static string StringJoin(string separator, IEnumerable elements) + { + #if DOTNET35 + return string.Join(separator, elements.Select(e => e != null ? e.ToString() : null).ToArray()); + #else + return string.Join(separator, elements); + #endif + } + + public static IEnumerable SafeCast(this IEnumerable elements) where T : U + { + #if DOTNET35 + foreach (T item in elements) + yield return item; + #else + return elements; + #endif + } + + public static Predicate SafeCast(this Predicate predicate) where U : T + { + #if DOTNET35 + return e => predicate(e); + #else + return predicate; + #endif + } + + #if DOTNET35 + public static IEnumerable Zip(this IEnumerable input1, IEnumerable input2, Func f) + { + using (var e1 = input1.GetEnumerator()) + using (var e2 = input2.GetEnumerator()) + while (e1.MoveNext() && e2.MoveNext()) + yield return f(e1.Current, e2.Current); + } + #endif +} + +#if DOTNET35 +namespace System.Diagnostics.Contracts { } +namespace System.Threading +{ + internal struct CancellationToken + { + public void ThrowIfCancellationRequested() {} + } +} +#endif diff --git a/NRefactory.sln b/NRefactory.sln index 575ae336b..24aed9f13 100644 --- a/NRefactory.sln +++ b/NRefactory.sln @@ -71,13 +71,13 @@ Global {870115DD-960A-4406-A6B9-600BCDC36A03}.Release|x86.Build.0 = Release|Any CPU {870115DD-960A-4406-A6B9-600BCDC36A03}.Release|x86.ActiveCfg = Release|Any CPU {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|Any CPU.Build.0 = net_4_0_Debug|Any CPU - {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|Any CPU.ActiveCfg = net_4_0_Debug|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|Any CPU.ActiveCfg = net_3_5_Debug|Any CPU {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|x86.Build.0 = net_4_0_Debug|Any CPU - {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|x86.ActiveCfg = net_4_0_Debug|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|x86.ActiveCfg = net_3_5_Debug|Any CPU {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|Any CPU.Build.0 = net_4_0_Debug|Any CPU - {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|Any CPU.ActiveCfg = net_4_0_Release|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|Any CPU.ActiveCfg = net_3_5_Release|Any CPU {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|x86.Build.0 = net_4_0_Debug|Any CPU - {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|x86.ActiveCfg = net_4_0_Release|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|x86.ActiveCfg = net_3_5_Release|Any CPU EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution StartupItem = ICSharpCode.NRefactory\ICSharpCode.NRefactory.csproj diff --git a/README b/README index 9cdcf0b24..ea347e6d3 100644 --- a/README +++ b/README @@ -6,15 +6,22 @@ ICSharpCode.NRefactory.TypeSystem: ICSharpCode.NRefactory.TypeSystem.Implementation: Contains base classes that help implementing the type system interfaces. -ICSharpCode.NRefactory.CSharp.Dom: +ICSharpCode.NRefactory.CSharp.Ast: Abstract Syntax Tree for C# ICSharpCode.NRefactory.CSharp.Resolver: Semantic analysis for C# -ICSharpCode.NRefactory.VB.Dom: +ICSharpCode.NRefactory.Util: + Various helper classes. + +ICSharpCode.NRefactory.VB.Dom: (in the separate ICSharpCode.NRefactory.VB assembly) Abstract Syntax Tree for VB +Dependencies: + .NET 3.5 or .NET 4.0 + Mono.Cecil 0.9.4 + Null-Object pattern: The NRefactory library makes extensive use of the null object pattern. As a result, NullReferenceExceptions should be very rare when working with this library. @@ -32,6 +39,10 @@ Null-Object pattern: error cases. Use ResolveResult.IsError to detect resolver errors. Also note that many resolver errors still have a meaningful type attached, this allows code completion to work in the presence of minor semantic errors. + + The C# AST makes use of special null nodes when accessing the getter of an AST property and no + child node with that role exists. Check the IsNull property to test whether a node is a null node. + Null nodes are not considered to be part of the AST (e.g. they don't have a parent). FAQ: Q: What is the difference between types and type definitions? @@ -193,3 +204,13 @@ A: Because if you're asking whether a type is a struct, it's very likely that yo If you really need to know, you can do "type.GetDefinition() != null && type.GetDefinition().ClassType == WhatIWant" yourself, but for the most part you should be fine with IsReferenceType, IsEnum and IsDelegate. + + +Q: What's the difference between the .NET 3.5 and .NET 4.0 versions? + +A: As for visible API difference, not much. The .NET 4.0 build has some additional overloads for a few methods, + taking a System.Threading.CancellationToken to allow aborting a resolve run. + Internally, the .NET 4.0 version might be tiny bit more performant because it uses covariance for IEnumerable, + where the .NET 3.5 version has to allocate wrapper objects instead. + + Both versions support loading assemblies of all .NET versions (1.0 to 4.0); and both support C# 4.0. diff --git a/VBDomGenerator/VBDomGenerator.csproj b/VBDomGenerator/VBDomGenerator.csproj index 8de206bd6..c9e014b1f 100644 --- a/VBDomGenerator/VBDomGenerator.csproj +++ b/VBDomGenerator/VBDomGenerator.csproj @@ -19,6 +19,7 @@ false v4.0 OnBuildSuccess + Client bin\Debug\ diff --git a/doc/TODO b/doc/TODO index a0e8045ea..1b43f8b85 100644 --- a/doc/TODO +++ b/doc/TODO @@ -1,15 +1,24 @@ -TypeSystem API: + +Parser: +- "extern alias" declarations +- "fixed int Field[100];" (fixed-size field declarations) +- support generics +- fix bugs (see currently ignored unit tests) +- put newlines into the AST +- add API to report errors +- allow multithreaded parsing -* Decide on the fate of ISupportsInterning (depends on how we're going to implement persistence) +Resolver: +- Tons of unit tests for TypeSystemConvertVisitor +- Lambda expressions +- Handle attributes +- Port all #D resolver unit tests to NR +- Port all MD resolver unit tests to NR -* Try to build SharedTypes for void, int, etc. - Take care of equality with the real System.Void, System.Int32 etc. - This seems to be hard/impossible to do, see comment in SharedTypes.cs. - I'm trying to work without those types now. - - Note that having shared type *references* is possible (typeof(int).ToTypeReference()) +Features: +- Code Completion +- Find References +- Extract Method refactoring -* Implement the C# parser producing the DOM -* Implement ResolveVisitor -* Implement all the nasty context-dependent stuff (local variables, lambdas) that CSharpResolver doesn't do (yet) - Where should that go? I'd like to keep it out of CSharpResolver, that class is bloated enough with the pure logic. +For integration into SharpDevelop: +- Review NR and DOM changes done in the timeframe \ No newline at end of file From d80719c4ee8c36f8c96c78e572a6ffcd42a62e7d Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Thu, 3 Mar 2011 00:07:08 +0100 Subject: [PATCH 26/30] Adjust ILSpy to NRefactory changes. --- .../Ast/DeclareVariableInSmallestScope.cs | 4 +- .../Ast/Transforms/DelegateConstruction.cs | 4 +- .../Transforms/PatternStatementTransform.cs | 50 ++++++++++--------- .../Ast/Transforms/PushNegation.cs | 4 +- ILSpy.sln | 9 ++-- Mono.Cecil/Mono.Cecil/SecurityDeclaration.cs | 2 +- .../CSharp/Ast/PatternMatching/Pattern.cs | 10 ++++ 7 files changed, 48 insertions(+), 35 deletions(-) diff --git a/ICSharpCode.Decompiler/Ast/DeclareVariableInSmallestScope.cs b/ICSharpCode.Decompiler/Ast/DeclareVariableInSmallestScope.cs index af82e224d..fe6a15d51 100644 --- a/ICSharpCode.Decompiler/Ast/DeclareVariableInSmallestScope.cs +++ b/ICSharpCode.Decompiler/Ast/DeclareVariableInSmallestScope.cs @@ -15,8 +15,8 @@ namespace Decompiler { static readonly ExpressionStatement assignmentPattern = new ExpressionStatement( new AssignmentExpression( - new NamedNode("ident", new IdentifierExpression()).ToExpression(), - new AnyNode("init").ToExpression() + new NamedNode("ident", new IdentifierExpression()), + new AnyNode("init") )); /// diff --git a/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs b/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs index d5bf7d8b2..87df7aca8 100644 --- a/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs +++ b/ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs @@ -196,8 +196,8 @@ namespace Decompiler.Transforms // "variableName.MemberName = right;" ExpressionStatement closureFieldAssignmentPattern = new ExpressionStatement( new AssignmentExpression( - new NamedNode("left", new MemberReferenceExpression { Target = new IdentifierExpression(variable.Name) }).ToExpression(), - new AnyNode("right").ToExpression() + new NamedNode("left", new MemberReferenceExpression { Target = new IdentifierExpression(variable.Name) }), + new AnyNode("right") ) ); Match m = closureFieldAssignmentPattern.Match(cur); diff --git a/ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs b/ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs index 78a9d3596..bdc4b1d37 100644 --- a/ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs +++ b/ICSharpCode.Decompiler/Ast/Transforms/PatternStatementTransform.cs @@ -26,14 +26,14 @@ namespace Decompiler.Transforms /// $type $variable = $initializer; /// static readonly AstNode variableDeclPattern = new VariableDeclarationStatement { - Type = new AnyNode("type").ToType(), + Type = new AnyNode("type"), Variables = { new NamedNode( "variable", new VariableInitializer { - Initializer = new AnyNode("initializer").ToExpression() + Initializer = new AnyNode("initializer") } - ).ToVariable() + ) } }; @@ -41,7 +41,7 @@ namespace Decompiler.Transforms /// Variable declaration without initializer. /// static readonly AstNode simpleVariableDefinition = new VariableDeclarationStatement { - Type = new AnyNode().ToType(), + Type = new AnyNode(), Variables = { new VariableInitializer() // any name but no initializer } @@ -49,7 +49,7 @@ namespace Decompiler.Transforms #region using static readonly AstNode usingTryCatchPattern = new TryCatchStatement { - TryBlock = new AnyNode("body").ToBlock(), + TryBlock = new AnyNode("body"), FinallyBlock = new BlockStatement { new Choice { { "valueType", @@ -58,7 +58,7 @@ namespace Decompiler.Transforms { "referenceType", new IfElseStatement { Condition = new BinaryOperatorExpression( - new NamedNode("ident", new IdentifierExpression()).ToExpression(), + new NamedNode("ident", new IdentifierExpression()), BinaryOperatorType.InEquality, new NullReferenceExpression() ), @@ -102,14 +102,14 @@ namespace Decompiler.Transforms #region foreach UsingStatement foreachPattern = new UsingStatement { ResourceAcquisition = new VariableDeclarationStatement { - Type = new AnyNode("enumeratorType").ToType(), + Type = new AnyNode("enumeratorType"), Variables = { new NamedNode( "enumeratorVariable", new VariableInitializer { Initializer = new AnyNode("collection").ToExpression().Invoke("GetEnumerator") } - ).ToVariable() + ) } }, EmbeddedStatement = new Choice { @@ -123,14 +123,14 @@ namespace Decompiler.Transforms Condition = new IdentifierExpressionBackreference("enumeratorVariable").ToExpression().Invoke("MoveNext"), EmbeddedStatement = new BlockStatement { new VariableDeclarationStatement { - Type = new AnyNode("itemType").ToType(), + Type = new AnyNode("itemType"), Variables = { new NamedNode( "itemVariable", new VariableInitializer { Initializer = new IdentifierExpressionBackreference("enumeratorVariable").ToExpression().Member("Current") } - ).ToVariable() + ) } }, new Repeat(new AnyNode("statement")).ToStatement() @@ -141,16 +141,16 @@ namespace Decompiler.Transforms { "itemVariableOutsideLoop", new BlockStatement { new VariableDeclarationStatement { - Type = new AnyNode("itemType").ToType(), + Type = new AnyNode("itemType"), Variables = { - new NamedNode("itemVariable", new VariableInitializer()).ToVariable() + new NamedNode("itemVariable", new VariableInitializer()) } }, new WhileStatement { Condition = new IdentifierExpressionBackreference("enumeratorVariable").ToExpression().Invoke("MoveNext"), EmbeddedStatement = new BlockStatement { new AssignmentExpression { - Left = new IdentifierExpressionBackreference("itemVariable").ToExpression(), + Left = new IdentifierExpressionBackreference("itemVariable"), Operator = AssignmentOperatorType.Assign, Right = new IdentifierExpressionBackreference("enumeratorVariable").ToExpression().Member("Current") }, @@ -191,20 +191,22 @@ namespace Decompiler.Transforms #region for WhileStatement forPattern = new WhileStatement { Condition = new BinaryOperatorExpression { - Left = new NamedNode("ident", new IdentifierExpression()).ToExpression(), + Left = new NamedNode("ident", new IdentifierExpression()), Operator = BinaryOperatorType.Any, - Right = new AnyNode("endExpr").ToExpression() + Right = new AnyNode("endExpr") }, EmbeddedStatement = new BlockStatement { - new Repeat(new AnyNode("statement")).ToStatement(), - new NamedNode( - "increment", - new ExpressionStatement( - new AssignmentExpression { - Left = new Backreference("ident").ToExpression(), - Operator = AssignmentOperatorType.Any, - Right = new AnyNode().ToExpression() - })).ToStatement() + Statements = { + new Repeat(new AnyNode("statement")), + new NamedNode( + "increment", + new ExpressionStatement( + new AssignmentExpression { + Left = new Backreference("ident"), + Operator = AssignmentOperatorType.Any, + Right = new AnyNode() + })) + } } }; diff --git a/ICSharpCode.Decompiler/Ast/Transforms/PushNegation.cs b/ICSharpCode.Decompiler/Ast/Transforms/PushNegation.cs index 0a9d943ee..1d04bd941 100644 --- a/ICSharpCode.Decompiler/Ast/Transforms/PushNegation.cs +++ b/ICSharpCode.Decompiler/Ast/Transforms/PushNegation.cs @@ -77,13 +77,13 @@ namespace Decompiler.Transforms } readonly static AstNode asCastIsNullPattern = new BinaryOperatorExpression( - new AnyNode("expr").ToExpression().CastAs(new AnyNode("type").ToType()), + new AnyNode("expr").ToExpression().CastAs(new AnyNode("type")), BinaryOperatorType.Equality, new NullReferenceExpression() ); readonly static AstNode asCastIsNotNullPattern = new BinaryOperatorExpression( - new AnyNode("expr").ToExpression().CastAs(new AnyNode("type").ToType()), + new AnyNode("expr").ToExpression().CastAs(new AnyNode("type")), BinaryOperatorType.InEquality, new NullReferenceExpression() ); diff --git a/ILSpy.sln b/ILSpy.sln index 14784f3b7..ebfadb908 100644 --- a/ILSpy.sln +++ b/ILSpy.sln @@ -1,6 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 11.00 # Visual Studio 2010 +# SharpDevelop 4.0.1.7096 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ILSpy", "ILSpy\ILSpy.csproj", "{1E85EFF9-E370-4683-83E4-8A3D063FF791}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.TreeView", "SharpTreeView\ICSharpCode.TreeView.csproj", "{DDE2A481-8271-4EAC-A330-8FA6A38D13D1}" @@ -39,13 +40,13 @@ Global {DDE2A481-8271-4EAC-A330-8FA6A38D13D1}.Release|Any CPU.Build.0 = Release|Any CPU {DDE2A481-8271-4EAC-A330-8FA6A38D13D1}.Release|x86.ActiveCfg = Release|Any CPU {DDE2A481-8271-4EAC-A330-8FA6A38D13D1}.Release|x86.Build.0 = Release|Any CPU - {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|Any CPU.ActiveCfg = net_4_0_Debug|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|Any CPU.ActiveCfg = net_3_5_Debug|Any CPU {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|Any CPU.Build.0 = net_4_0_Debug|Any CPU - {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|x86.ActiveCfg = net_4_0_Debug|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|x86.ActiveCfg = net_3_5_Debug|Any CPU {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Debug|x86.Build.0 = net_2_0_Debug|Any CPU - {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|Any CPU.ActiveCfg = net_4_0_Release|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|Any CPU.ActiveCfg = net_3_5_Release|Any CPU {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|Any CPU.Build.0 = net_4_0_Release|Any CPU - {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|x86.ActiveCfg = net_4_0_Release|Any CPU + {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|x86.ActiveCfg = net_3_5_Release|Any CPU {D68133BD-1E63-496E-9EDE-4FBDBF77B486}.Release|x86.Build.0 = net_2_0_Debug|Any CPU {6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {6C55B776-26D4-4DB3-A6AB-87E783B2F3D1}.Debug|Any CPU.Build.0 = Debug|Any CPU diff --git a/Mono.Cecil/Mono.Cecil/SecurityDeclaration.cs b/Mono.Cecil/Mono.Cecil/SecurityDeclaration.cs index b09e4a6e8..8fcfcc458 100644 --- a/Mono.Cecil/Mono.Cecil/SecurityDeclaration.cs +++ b/Mono.Cecil/Mono.Cecil/SecurityDeclaration.cs @@ -177,7 +177,7 @@ namespace Mono.Cecil { { return module.HasImage () ? module.Read (ref variable, self, (provider, reader) => reader.ReadSecurityDeclarations (provider)) - : LazyInitializer.EnsureInitialized(ref variable); + : variable = new Collection(); } } } diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Pattern.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Pattern.cs index 37c89a58e..23f5c2ea5 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Pattern.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/PatternMatching/Pattern.cs @@ -39,11 +39,21 @@ namespace ICSharpCode.NRefactory.CSharp.PatternMatching return p != null ? new ExpressionPlaceholder(p) : null; } + public Expression ToExpression() + { + return new ExpressionPlaceholder(this); + } + public static implicit operator Statement(Pattern p) { return p != null ? new StatementPlaceholder(p) : null; } + public Statement ToStatement() + { + return new StatementPlaceholder(this); + } + public static implicit operator BlockStatement(Pattern p) { return p != null ? new BlockStatementPlaceholder(p) : null; From d1ccd69715a3ae1e30a68879899c7e64a595a3f6 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Thu, 3 Mar 2011 01:33:00 +0100 Subject: [PATCH 27/30] Don't show ": int" when enums derive from Int32. --- ICSharpCode.Decompiler/Ast/AstBuilder.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ICSharpCode.Decompiler/Ast/AstBuilder.cs b/ICSharpCode.Decompiler/Ast/AstBuilder.cs index a0540bd82..91903c245 100644 --- a/ICSharpCode.Decompiler/Ast/AstBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstBuilder.cs @@ -172,7 +172,9 @@ namespace Decompiler foreach (FieldDefinition field in typeDef.Fields) { if (field.IsRuntimeSpecialName) { // the value__ field - astType.AddChild(ConvertType(field.FieldType), TypeDeclaration.BaseTypeRole); + if (field.FieldType != typeDef.Module.TypeSystem.Int32) { + astType.AddChild(ConvertType(field.FieldType), TypeDeclaration.BaseTypeRole); + } } else { EnumMemberDeclaration enumMember = new EnumMemberDeclaration(); enumMember.Name = CleanName(field.Name); From ed118a1bd5906635ebfdf9a327434801ad0005fa Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Thu, 3 Mar 2011 01:44:35 +0100 Subject: [PATCH 28/30] Remove "Attribute" suffix and add support for attributes on type parameters. --- ICSharpCode.Decompiler/Ast/AstBuilder.cs | 20 ++++++++++++++----- .../S_CustomAttributeSamples.cs | 13 +++++++++++- .../Tests/Helpers/RemoveCompilerAttribute.cs | 2 +- .../CSharp/OutputVisitor/OutputVisitor.cs | 4 +++- 4 files changed, 31 insertions(+), 8 deletions(-) diff --git a/ICSharpCode.Decompiler/Ast/AstBuilder.cs b/ICSharpCode.Decompiler/Ast/AstBuilder.cs index 91903c245..434f91888 100644 --- a/ICSharpCode.Decompiler/Ast/AstBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstBuilder.cs @@ -499,11 +499,16 @@ namespace Decompiler IEnumerable MakeTypeParameters(IEnumerable genericParameters) { - return genericParameters.Select( - gp => new TypeParameterDeclaration { - Name = CleanName(gp.Name), - Variance = gp.IsContravariant ? VarianceModifier.Contravariant : gp.IsCovariant ? VarianceModifier.Covariant : VarianceModifier.Invariant - }); + foreach (var gp in genericParameters) { + TypeParameterDeclaration tp = new TypeParameterDeclaration(); + tp.Name = CleanName(gp.Name); + if (gp.IsContravariant) + tp.Variance = VarianceModifier.Contravariant; + else if (gp.IsCovariant) + tp.Variance = VarianceModifier.Covariant; + ConvertCustomAttributes(tp, gp); + yield return tp; + } } IEnumerable MakeConstraints(IEnumerable genericParameters) @@ -616,6 +621,11 @@ namespace Decompiler var attribute = new ICSharpCode.NRefactory.CSharp.Attribute(); attribute.Type = ConvertType(customAttribute.AttributeType); attributes.Add(attribute); + + SimpleType st = attribute.Type as SimpleType; + if (st != null && st.Identifier.EndsWith("Attribute", StringComparison.Ordinal)) { + st.Identifier = st.Identifier.Substring(0, st.Identifier.Length - "Attribute".Length); + } if(customAttribute.HasConstructorArguments) { foreach (var parameter in customAttribute.ConstructorArguments) { diff --git a/ICSharpCode.Decompiler/Tests/CustomAttributes/S_CustomAttributeSamples.cs b/ICSharpCode.Decompiler/Tests/CustomAttributes/S_CustomAttributeSamples.cs index aa6d4660a..866d9aa06 100644 --- a/ICSharpCode.Decompiler/Tests/CustomAttributes/S_CustomAttributeSamples.cs +++ b/ICSharpCode.Decompiler/Tests/CustomAttributes/S_CustomAttributeSamples.cs @@ -382,7 +382,7 @@ namespace TargetPropertyIndexSetMultiParam } public class MyClass { - public string this[[MyAttribute(Field = 2)]int index1, [MyAttribute(Field = 3)]int index2] + public string this[[MyAttribute(Field = 2)] int index1, [MyAttribute(Field = 3)] int index2] { get { @@ -396,3 +396,14 @@ namespace TargetPropertyIndexSetMultiParam } } } +//$$ ClassAttributeOnTypeParameter +namespace ClassAttributeOnTypeParameter +{ + [AttributeUsage(AttributeTargets.All)] + public class MyAttributeAttribute : Attribute + { + } + public class MyClass<[MyAttribute] T> + { + } +} diff --git a/ICSharpCode.Decompiler/Tests/Helpers/RemoveCompilerAttribute.cs b/ICSharpCode.Decompiler/Tests/Helpers/RemoveCompilerAttribute.cs index 8b364268e..00b5b4dba 100644 --- a/ICSharpCode.Decompiler/Tests/Helpers/RemoveCompilerAttribute.cs +++ b/ICSharpCode.Decompiler/Tests/Helpers/RemoveCompilerAttribute.cs @@ -14,7 +14,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers var section = (AttributeSection)attribute.Parent; SimpleType type = attribute.Type as SimpleType; if (section.AttributeTarget == AttributeTarget.Assembly && - (type.Identifier == "CompilationRelaxationsAttribute" || type.Identifier == "RuntimeCompatibilityAttribute")) + (type.Identifier == "CompilationRelaxations" || type.Identifier == "RuntimeCompatibility")) { attribute.Remove(); if (section.Attributes.Count == 0) diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs index e5c307f66..bcc2e4394 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs @@ -1135,7 +1135,9 @@ namespace ICSharpCode.NRefactory.CSharp } WriteCommaSeparatedList(attributeSection.Attributes.SafeCast()); WriteToken("]", AstNode.Roles.RBracket); - if (!(attributeSection.Parent is ParameterDeclaration)) + if (attributeSection.Parent is ParameterDeclaration || attributeSection.Parent is TypeParameterDeclaration) + Space(); + else NewLine(); return EndNode(attributeSection); } From c24ec99ae052fd84478333ee2affc46e14f91322 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Thu, 3 Mar 2011 01:50:27 +0100 Subject: [PATCH 29/30] Output constraints for generic methods. --- ICSharpCode.Decompiler/Ast/AstBuilder.cs | 19 +++++++++++++++++-- ICSharpCode.Decompiler/Tests/Generics.cs | 4 ++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/ICSharpCode.Decompiler/Ast/AstBuilder.cs b/ICSharpCode.Decompiler/Ast/AstBuilder.cs index 434f91888..f7f63a15d 100644 --- a/ICSharpCode.Decompiler/Ast/AstBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstBuilder.cs @@ -513,8 +513,23 @@ namespace Decompiler IEnumerable MakeConstraints(IEnumerable genericParameters) { - // TODO - return Enumerable.Empty(); + foreach (var gp in genericParameters) { + Constraint c = new Constraint(); + c.TypeParameter = CleanName(gp.Name); + // class/struct must be first + if (gp.HasReferenceTypeConstraint) + c.BaseTypes.Add(new PrimitiveType("class")); + if (gp.HasNotNullableValueTypeConstraint) + c.BaseTypes.Add(new PrimitiveType("struct")); + + foreach (var constraintType in gp.Constraints) + c.BaseTypes.Add(ConvertType(constraintType)); + + if (gp.HasDefaultConstructorConstraint) + c.BaseTypes.Add(new PrimitiveType("new")); // new() must be last + if (c.BaseTypes.Any()) + yield return c; + } } ConstructorDeclaration CreateConstructor(MethodDefinition methodDef) diff --git a/ICSharpCode.Decompiler/Tests/Generics.cs b/ICSharpCode.Decompiler/Tests/Generics.cs index 636eb708c..d0b6cf240 100644 --- a/ICSharpCode.Decompiler/Tests/Generics.cs +++ b/ICSharpCode.Decompiler/Tests/Generics.cs @@ -27,4 +27,8 @@ public static class Generics } } } + + public static void MethodWithConstraint() where T : class, S where S : ICloneable, new() + { + } } From a55f0218e6f6f32a6a142a9d3bf4c5a1bda7301a Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Thu, 3 Mar 2011 03:17:48 +0100 Subject: [PATCH 30/30] Fix output of float/double literals that are infinite or NaN. --- .../CSharp/OutputVisitor/OutputVisitor.cs | 97 ++++++++++++------- 1 file changed, 61 insertions(+), 36 deletions(-) diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs index bcc2e4394..5f9d0f1c7 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs @@ -784,52 +784,75 @@ namespace ICSharpCode.NRefactory.CSharp public object VisitPrimitiveExpression(PrimitiveExpression primitiveExpression, object data) { StartNode(primitiveExpression); - formatter.WriteToken(ToCSharpString(primitiveExpression)); - lastWritten = LastWritten.Other; + WritePrimitiveValue(primitiveExpression.Value); return EndNode(primitiveExpression); } - internal static string ToCSharpString(PrimitiveExpression primitiveExpression) + void WritePrimitiveValue(object val) { - if (primitiveExpression.Value == null) { - return "null"; + if (val == null) { + // usually NullReferenceExpression should be used for this, but we'll handle it anyways + WriteKeyword("null"); + return; } - object val = primitiveExpression.Value; - if (val is bool) { if ((bool)val) { - return "true"; + WriteKeyword("true"); } else { - return "false"; + WriteKeyword("false"); } + return; } if (val is string) { - return "\"" + ConvertString(val.ToString()) + "\""; - } - - if (val is char) { - return "'" + ConvertCharLiteral((char)val) + "'"; - } - - if (val is decimal) { - return ((decimal)val).ToString(NumberFormatInfo.InvariantInfo) + "m"; - } - - if (val is float) { - return ((float)val).ToString(NumberFormatInfo.InvariantInfo) + "f"; - } - - if (val is double) { - string text = ((double)val).ToString(NumberFormatInfo.InvariantInfo); - if (text.IndexOf('.') < 0 && text.IndexOf('E') < 0) - return text + ".0"; - else - return text; - } - - if (val is IFormattable) { + formatter.WriteToken("\"" + ConvertString(val.ToString()) + "\""); + lastWritten = LastWritten.Other; + } else if (val is char) { + formatter.WriteToken("'" + ConvertCharLiteral((char)val) + "'"); + lastWritten = LastWritten.Other; + } else if (val is decimal) { + formatter.WriteToken(((decimal)val).ToString(NumberFormatInfo.InvariantInfo) + "m"); + lastWritten = LastWritten.Other; + } else if (val is float) { + float f = (float)val; + if (float.IsInfinity(f) || float.IsNaN(f)) { + // Strictly speaking, these aren't PrimitiveExpressions; + // but we still support writing these to make life easier for code generators. + WriteKeyword("float"); + WriteToken(".", AstNode.Roles.Dot); + if (float.IsPositiveInfinity(f)) + WriteIdentifier("PositiveInfinity"); + else if (float.IsNegativeInfinity(f)) + WriteIdentifier("NegativeInfinity"); + else + WriteIdentifier("NaN"); + return; + } + formatter.WriteToken(f.ToString("R", NumberFormatInfo.InvariantInfo) + "f"); + lastWritten = LastWritten.Other; + } else if (val is double) { + double f = (double)val; + if (double.IsInfinity(f) || double.IsNaN(f)) { + // Strictly speaking, these aren't PrimitiveExpressions; + // but we still support writing these to make life easier for code generators. + WriteKeyword("double"); + WriteToken(".", AstNode.Roles.Dot); + if (double.IsPositiveInfinity(f)) + WriteIdentifier("PositiveInfinity"); + else if (double.IsNegativeInfinity(f)) + WriteIdentifier("NegativeInfinity"); + else + WriteIdentifier("NaN"); + return; + } + string number = f.ToString("R", NumberFormatInfo.InvariantInfo); + if (number.IndexOf('.') < 0 && number.IndexOf('E') < 0) + number += ".0"; + formatter.WriteToken(number); + // needs space if identifier follows number; this avoids mistaking the following identifier as type suffix + lastWritten = LastWritten.KeywordOrIdentifier; + } else if (val is IFormattable) { StringBuilder b = new StringBuilder(); // if (primitiveExpression.LiteralFormat == LiteralFormat.HexadecimalNumber) { // b.Append("0x"); @@ -843,13 +866,15 @@ namespace ICSharpCode.NRefactory.CSharp if (val is long || val is ulong) { b.Append("L"); } - return b.ToString(); + formatter.WriteToken(b.ToString()); + // needs space if identifier follows number; this avoids mistaking the following identifier as type suffix + lastWritten = LastWritten.KeywordOrIdentifier; } else { - return val.ToString(); + formatter.WriteToken(val.ToString()); + lastWritten = LastWritten.Other; } } - static string ConvertCharLiteral(char ch) { if (ch == '\'') return "\\'";