1
ļ»æ// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
3
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
4
// software and associated documentation files (the "Software"), to deal in the Software
5
// without restriction, including without limitation the rights to use, copy, modify, merge,
6
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
7
// to whom the Software is furnished to do so, subject to the following conditions:
9
// The above copyright notice and this permission notice shall be included in all copies or
10
// substantial portions of the Software.
12
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
13
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
15
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
16
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
17
// DEALINGS IN THE SOFTWARE.
21
using System.CodeDom.Compiler;
24
using System.Text.RegularExpressions;
25
using ICSharpCode.NRefactory.CSharp.Resolver;
26
using ICSharpCode.NRefactory.CSharp.TypeSystem;
27
using ICSharpCode.NRefactory.TypeSystem;
28
using Microsoft.CSharp;
29
using NUnit.Framework;
31
namespace ICSharpCode.NRefactory.CSharp
34
public class CodeDomConvertVisitorTests : ResolverTestBase
36
CodeDomConvertVisitor convertVisitor;
37
CSharpUnresolvedFile unresolvedFile;
39
public override void SetUp()
42
unresolvedFile = new CSharpUnresolvedFile("test.cs");
43
unresolvedFile.RootUsingScope.Usings.Add(MakeReference("System"));
44
unresolvedFile.RootUsingScope.Usings.Add(MakeReference("System.Collections.Generic"));
45
unresolvedFile.RootUsingScope.Usings.Add(MakeReference("System.Linq"));
47
convertVisitor = new CodeDomConvertVisitor();
48
convertVisitor.AllowSnippetNodes = false;
49
convertVisitor.UseFullyQualifiedTypeNames = true;
52
#region Helper methods
53
CodeObject ConvertInContext(string program)
55
var p = PrepareResolver(program);
56
return convertVisitor.Convert(p.Item2, p.Item1);
59
string ConvertHelper(AstNode node, Action<CSharpCodeProvider, CodeObject, TextWriter, CodeGeneratorOptions> action)
61
CSharpResolver resolver = new CSharpResolver(compilation);
62
resolver = resolver.WithCurrentUsingScope(unresolvedFile.RootUsingScope.Resolve(compilation));
63
resolver = resolver.WithCurrentTypeDefinition(compilation.FindType(KnownTypeCode.Object).GetDefinition());
64
var codeObj = convertVisitor.Convert(node, new CSharpAstResolver(resolver, node));
66
StringWriter writer = new StringWriter();
68
action(new CSharpCodeProvider(), codeObj, writer, new CodeGeneratorOptions { IndentString = " " });
69
return Regex.Replace(writer.ToString(), @"\s+", " ").Trim();
72
string ConvertExpression(Expression expr)
74
return ConvertHelper(expr, (p,obj,w,opt) => p.GenerateCodeFromExpression((CodeExpression)obj, w, opt));
77
string ConvertExpression(string code)
79
CSharpParser parser = new CSharpParser();
80
var expr = parser.ParseExpression(code);
81
Assert.IsFalse(parser.HasErrors);
82
return ConvertExpression(expr);
85
string ConvertStatement(Statement statement)
87
return ConvertHelper(statement, (p,obj,w,opt) => p.GenerateCodeFromStatement((CodeStatement)obj, w, opt));
90
string ConvertStatement(string code)
92
CSharpParser parser = new CSharpParser();
93
var expr = parser.ParseStatements(code).Single();
94
Assert.IsFalse(parser.HasErrors);
95
return ConvertStatement(expr);
98
string ConvertMember(EntityDeclaration entity)
100
return ConvertHelper(entity, (p,obj,w,opt) => p.GenerateCodeFromMember((CodeTypeMember)obj, w, opt));
103
string ConvertMember(string code)
105
CSharpParser parser = new CSharpParser();
106
var expr = parser.ParseTypeMembers(code).Single();
107
Assert.IsFalse(parser.HasErrors);
108
return ConvertMember(expr);
111
string ConvertTypeDeclaration(EntityDeclaration decl)
113
return ConvertHelper(decl, (p,obj,w,opt) => p.GenerateCodeFromType((CodeTypeDeclaration)obj, w, opt));
116
string ConvertTypeDeclaration(string code)
118
CSharpParser parser = new CSharpParser();
119
var syntaxTree = parser.Parse(code, "program.cs");
120
Assert.IsFalse(parser.HasErrors);
121
return ConvertTypeDeclaration((EntityDeclaration)syntaxTree.Children.Single());
124
string ConvertSyntaxTree(SyntaxTree syntaxTree)
126
return ConvertHelper(syntaxTree, (p,obj,w,opt) => p.GenerateCodeFromCompileUnit((CodeCompileUnit)obj, w, opt));
129
string ConvertSyntaxTree(string code)
131
CSharpParser parser = new CSharpParser();
132
var syntaxTree = parser.Parse(code, "program.cs");
133
Assert.IsFalse(parser.HasErrors);
134
var result = ConvertSyntaxTree(syntaxTree);
135
var idx = result.IndexOf("namespace", StringComparison.Ordinal);
137
result = result.Substring (idx);
142
#region Type References
144
public void MultidimensionalArrayTypeReference()
146
Assert.AreEqual("default(int[,][])", ConvertExpression("default(int[,][])"));
150
public void NestedTypeInGenericType()
152
Assert.AreEqual("default(System.Collections.Generic.List<string>.Enumerator)",
153
ConvertExpression("default(List<string>.Enumerator)"));
154
convertVisitor.UseFullyQualifiedTypeNames = false;
155
Assert.AreEqual("default(List<string>.Enumerator)",
156
ConvertExpression("default(List<string>.Enumerator)"));
162
public void CreateArray()
164
Assert.AreEqual("new int[10]", ConvertExpression("new int[10]"));
167
[Test, ExpectedException(typeof(NotSupportedException))]
168
public void CreateJaggedArray()
170
ConvertExpression("new int[10][]");
173
[Test, ExpectedException(typeof(NotSupportedException))]
174
public void Create2DArray()
176
ConvertExpression("new int[10, 20]");
180
public void CreateImplicitlyTypedArray()
182
// implicitly-typed array not supported in CodeDom, so the conversion should infer the type
183
Assert.AreEqual("new int[] { 1, 2, 3}", ConvertExpression("new [] { 1, 2, 3 }"));
184
Assert.AreEqual("new System.Collections.Generic.List<string>[] { new System.Collections.Generic.List<string>()}",
185
ConvertExpression("new [] { new List<string>() }"));
188
[Test, ExpectedException(typeof(NotSupportedException))]
189
public void Create2DImplicitlyTypedArray()
191
ConvertExpression("new [,] { { 1, 2 }, { 3, 4 }}");
197
public void ArithmeticOperators()
199
Assert.AreEqual("(0 + 1)", ConvertExpression("0 + 1"));
200
Assert.AreEqual("(0 - 1)", ConvertExpression("0 - 1"));
201
Assert.AreEqual("(0 * 1)", ConvertExpression("0 * 1"));
202
Assert.AreEqual("(0 / 1)", ConvertExpression("0 / 1"));
203
Assert.AreEqual("(0 % 1)", ConvertExpression("0 % 1"));
204
Assert.AreEqual("(0 & 1)", ConvertExpression("0 & 1"));
205
Assert.AreEqual("(0 | 1)", ConvertExpression("0 | 1"));
206
Assert.AreEqual("(0 < 1)", ConvertExpression("0 < 1"));
207
Assert.AreEqual("(0 > 1)", ConvertExpression("0 > 1"));
208
Assert.AreEqual("(0 <= 1)", ConvertExpression("0 <= 1"));
209
Assert.AreEqual("(0 >= 1)", ConvertExpression("0 >= 1"));
210
Assert.AreEqual("(true && false)", ConvertExpression("true && false"));
211
Assert.AreEqual("(true || false)", ConvertExpression("true || false"));
215
public void EqualityOperator()
217
Assert.AreEqual("(0 == 1)", ConvertExpression("0 == 1"));
218
Assert.AreEqual("(default(object) == null)", ConvertExpression("default(object) == null"));
222
public void InEqualityOperator()
224
Assert.AreEqual("((0 == 1) == false)", ConvertExpression("0 != 1"));
225
Assert.AreEqual("(default(object) != null)", ConvertExpression("default(object) != null"));
229
public void UnaryOperators()
231
Assert.AreEqual("(a == false)", ConvertExpression("!a"));
232
Assert.AreEqual("(0 - a)", ConvertExpression("-a"));
233
Assert.AreEqual("a", ConvertExpression("+a"));
239
Assert.AreEqual("((double)(0))", ConvertExpression("(double)0"));
243
#region Member Access
245
public void StaticProperty()
247
Assert.AreEqual("System.Environment.TickCount", ConvertExpression("Environment.TickCount"));
251
public void FullyQualifiedEnumFieldAccess()
253
string program = "class A { object x = $System.StringComparison.Ordinal$; }";
254
var cfre = (CodeFieldReferenceExpression)ConvertInContext(program);
255
Assert.AreEqual("Ordinal", cfre.FieldName);
256
var ctre = ((CodeTypeReferenceExpression)cfre.TargetObject);
257
Assert.AreEqual("System.StringComparison", ctre.Type.BaseType);
261
public void EnumFieldAccess()
263
string program = "using System; class A { object x = $StringComparison.Ordinal$; }";
264
var cfre = (CodeFieldReferenceExpression)ConvertInContext(program);
265
Assert.AreEqual("Ordinal", cfre.FieldName);
266
var ctre = ((CodeTypeReferenceExpression)cfre.TargetObject);
267
Assert.AreEqual("System.StringComparison", ctre.Type.BaseType);
271
public void InstanceMethodInvocation()
273
Assert.AreEqual("this.Equals(null)", ConvertExpression("Equals(null)"));
277
public void StaticMethodInvocation()
279
Assert.AreEqual("object.Equals(null, null)", ConvertExpression("Equals(null, null)"));
283
public void BaseMemberAccess()
285
Assert.AreEqual("base.X", ConvertExpression("base.X"));
286
Assert.AreEqual("base[i]", ConvertExpression("base[i]"));
290
public void GenericMethodReference()
292
Assert.AreEqual("this.Stuff<string>", ConvertExpression("this.Stuff<string>"));
293
Assert.AreEqual("this.Stuff<string>", ConvertExpression("Stuff<string>"));
297
public void ByReferenceCall()
299
Assert.AreEqual("a.Call(ref x, out y, z)", ConvertExpression("a.Call(ref x, out y, z)"));
303
public void MemberAccessOnType()
305
Assert.AreEqual("string.Empty", ConvertExpression("string.Empty"));
311
public void MethodInvocationStatement()
313
Assert.AreEqual("a.SomeMethod();", ConvertStatement("a.SomeMethod();"));
317
public void Assignment()
319
Assert.AreEqual("a = 1;", ConvertStatement("a = 1;"));
322
[Test, ExpectedException(typeof(NotSupportedException))]
323
public void AssignmentNotSupportedInExpression()
325
ConvertStatement("a = b = 1;");
329
public void BlockStatement()
331
Assert.AreEqual("if (true) { a = 1; b = 2; }",
332
ConvertStatement("{ a = 1; b = 2; }"));
336
public void CompoundAssign()
338
Assert.AreEqual("a = (a + 1);", ConvertStatement("a += 1;"));
339
Assert.AreEqual("a = (a - 1);", ConvertStatement("a -= 1;"));
340
Assert.AreEqual("a = (a * 1);", ConvertStatement("a *= 1;"));
341
Assert.AreEqual("a = (a / 1);", ConvertStatement("a /= 1;"));
342
Assert.AreEqual("a = (a % 1);", ConvertStatement("a %= 1;"));
343
Assert.AreEqual("a = (a & 1);", ConvertStatement("a &= 1;"));
344
Assert.AreEqual("a = (a | 1);", ConvertStatement("a |= 1;"));
348
public void Increment()
350
Assert.AreEqual("a = (a + 1);", ConvertStatement("a++;"));
351
Assert.AreEqual("a = (a + 1);", ConvertStatement("++a;"));
352
Assert.AreEqual("a = (a - 1);", ConvertStatement("a--;"));
353
Assert.AreEqual("a = (a - 1);", ConvertStatement("--a;"));
357
public void ForLoop()
359
Assert.AreEqual("for (int i = 0; (i < 10); i = (i + 1)) { }",
360
ConvertStatement("for (int i = 0; i < 10; i++) {}"));
364
public void WhileLoop()
366
Assert.AreEqual("for (new object(); (i < 10); new object()) { }",
367
ConvertStatement("while (i < 10);"));
371
public void VariableDeclarationWithArrayInitializer()
373
Assert.AreEqual("int[] nums = new int[] { 1, 2};",
374
ConvertStatement("int[] nums = { 1, 2 };"));
378
public void TryCatch()
380
Assert.AreEqual("try { a = 1; } catch (System.Exception ex) { ex.ToString(); }",
381
ConvertStatement("try { a = 1; } catch (Exception ex) { ex.ToString(); }"));
385
public void TryEmptyCatch()
387
Assert.AreEqual("try { a = 1; } catch (System.Exception ) { }",
388
ConvertStatement("try { a = 1; } catch (Exception) { }"));
392
public void TryFinally()
394
Assert.AreEqual("try { a = 1; } finally { a = 0; }",
395
ConvertStatement("try { a = 1; } finally { a = 0; }"));
401
public void MethodParameterNamedValue()
403
Assert.AreEqual("void M(string value) { System.Console.WriteLine(value); }",
404
ConvertMember("void M(string value) { Console.WriteLine(value); }"));
408
public void ValueInProperty()
410
Assert.AreEqual("string P { set { System.Console.WriteLine(value); } }",
411
ConvertMember("string P { set { Console.WriteLine(value); } }"));
415
public void MethodWithAttribute()
417
Assert.AreEqual("[Test()] void MethodWithAttribute() { }",
418
ConvertMember("[Test] void MethodWithAttribute() { }"));
422
public void PublicNonVirtualMethod()
424
Assert.AreEqual("public void Method() { }",
425
ConvertMember("public void Method() { }"));
429
public void PublicVirtualMethod()
431
Assert.AreEqual("public virtual void Method() { }",
432
ConvertMember("public virtual void Method() { }"));
436
public void NestedClass()
438
Assert.AreEqual("public class Outer { public class Inner { } }",
439
ConvertTypeDeclaration("class Outer { class Inner { } }"));
443
public void Constructor()
445
string code = "public class Test : Base { public Test(string x) : base(x) { } }";
446
Assert.AreEqual(code, ConvertTypeDeclaration(code));
452
string code = "public enum E { [Description(\"Text\")] None, B = 2, }";
453
Assert.AreEqual(code, ConvertTypeDeclaration(code));
459
Assert.AreEqual("public class X {" +
462
ConvertMember("public class X { int A, B; }"));
468
Assert.AreEqual("public class X {" +
469
" protected event System.EventHandler A;" +
470
" protected event System.EventHandler B; }",
471
ConvertMember("public class X { protected event EventHandler A, B; }"));
477
public void TestGlobalNamespaceFix ()
479
Assert.AreEqual("namespace A { using System; public class AClass { } } namespace B { using System.IO; using System; public class AClass { } }",
480
ConvertSyntaxTree("using System; namespace A { public class AClass {} } namespace B { using System.IO; public class AClass {} }"));