|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable disable
using System;
using System.Collections.Immutable;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeGeneration;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.CodeStyle;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Roslyn.Utilities;
using Xunit;
using CS = Microsoft.CodeAnalysis.CSharp;
namespace Microsoft.CodeAnalysis.Editor.UnitTests.CodeGeneration;
using static CSharpSyntaxTokens;
[Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public partial class CodeGenerationTests
{
[UseExportProvider]
public class CSharp
{
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddNamespace()
{
var input = "namespace [|N1|] { }";
var expected = @"namespace N1 {
namespace N2
{
}
}";
await TestAddNamespaceAsync(input, expected,
name: "N2");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddField()
{
var input = "class [|C|] { }";
var expected = @"class C
{
public int F;
}";
await TestAddFieldAsync(input, expected,
type: GetTypeSymbol(typeof(int)));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddStaticField()
{
var input = "class [|C|] { }";
var expected = @"class C
{
private static string F;
}";
await TestAddFieldAsync(input, expected,
type: GetTypeSymbol(typeof(string)),
accessibility: Accessibility.Private,
modifiers: new Editing.DeclarationModifiers(isStatic: true));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddArrayField()
{
var input = "class [|C|] { }";
var expected = @"class C
{
public int[] F;
}";
await TestAddFieldAsync(input, expected,
type: CreateArrayType(typeof(int)));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddUnsafeField()
{
var input = "class [|C|] { }";
var expected = @"class C
{
public unsafe int F;
}";
await TestAddFieldAsync(input, expected,
modifiers: new Editing.DeclarationModifiers(isUnsafe: true),
type: GetTypeSymbol(typeof(int)));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddFieldToCompilationUnit()
{
var input = "";
var expected = "public int F;\n";
await TestAddFieldAsync(input, expected,
type: GetTypeSymbol(typeof(int)), addToCompilationUnit: true);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddConstructor()
{
var input = "class [|C|] { }";
var expected = @"class C
{
public C()
{
}
}";
await TestAddConstructorAsync(input, expected);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddConstructorWithoutBody()
{
var input = "class [|C|] { }";
var expected = @"class C
{
public C();
}";
await TestAddConstructorAsync(input, expected,
context: new CodeGenerationContext(generateMethodBodies: false));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddConstructorResolveNamespaceImport()
{
var input = "class [|C|] { }";
var expected = @"using System;
class C
{
public C(DateTime dt, int i)
{
}
}";
await TestAddConstructorAsync(input, expected,
parameters: Parameters(Parameter(typeof(DateTime), "dt"), Parameter(typeof(int), "i")));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddChainedConstructor()
{
var input = "class [|C|] { public C(int i) { } }";
var expected = "class C { public C() : this(42) { } public C(int i) { } }";
await TestAddConstructorAsync(input, expected,
thisArguments: ImmutableArray.Create<SyntaxNode>(CS.SyntaxFactory.ParseExpression("42")));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddStaticConstructor()
{
var input = "class [|C|] { }";
var expected = @"class C
{
static C()
{
}
}";
await TestAddConstructorAsync(input, expected,
modifiers: new Editing.DeclarationModifiers(isStatic: true));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration), WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544082")]
public async Task AddClass()
{
var input = "namespace [|N|] { }";
var expected = @"namespace N
{
public class C
{
}
}";
await TestAddNamedTypeAsync(input, expected);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddClassEscapeName()
{
var input = "namespace [|N|] { }";
var expected = @"namespace N
{
public class @class
{
}
}";
await TestAddNamedTypeAsync(input, expected,
name: "class");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddClassUnicodeName()
{
var input = "namespace [|N|] { }";
var expected = @"namespace N
{
public class classæøå
{
}
}";
await TestAddNamedTypeAsync(input, expected,
name: "classæøå");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration), WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544405")]
public async Task AddStaticClass()
{
var input = "namespace [|N|] { }";
var expected = @"namespace N
{
public static class C
{
}
}";
await TestAddNamedTypeAsync(input, expected,
modifiers: new Editing.DeclarationModifiers(isStatic: true));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration), WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544405")]
public async Task AddStaticAbstractClass()
{
var input = "namespace [|N|] { }";
var expected = @"namespace N
{
public static class C
{
}
}";
// note that 'abstract' is dropped here
await TestAddNamedTypeAsync(input, expected,
modifiers: new Editing.DeclarationModifiers(isStatic: true, isAbstract: true));
}
[Theory, Trait(Traits.Feature, Traits.Features.CodeGeneration), WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544405")]
[InlineData(Accessibility.NotApplicable)]
[InlineData(Accessibility.Internal)]
[InlineData(Accessibility.Public)]
public async Task AddFileClass(Accessibility accessibility)
{
var input = "namespace [|N|] { }";
var expected = @"namespace N
{
file class C
{
}
}";
// note: when invalid combinations of modifiers+accessibility are present here,
// we actually drop the accessibility. This is similar to what is done if someone declares a 'static abstract class C { }'.
await TestAddNamedTypeAsync(input, expected,
accessibility: accessibility,
modifiers: new Editing.DeclarationModifiers(isFile: true));
}
[Theory, Trait(Traits.Feature, Traits.Features.CodeGeneration), WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544405")]
[InlineData("struct", TypeKind.Struct)]
[InlineData("interface", TypeKind.Interface)]
[InlineData("enum", TypeKind.Enum)]
public async Task AddFileType(string kindString, TypeKind typeKind)
{
var input = "namespace [|N|] { }";
var expected = @"namespace N
{
file " + kindString + @" C
{
}
}";
await TestAddNamedTypeAsync(input, expected,
typeKind: typeKind,
modifiers: new Editing.DeclarationModifiers(isFile: true));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration), WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544405")]
public async Task AddSealedClass()
{
var input = "namespace [|N|] { }";
var expected = @"namespace N
{
private sealed class C
{
}
}";
await TestAddNamedTypeAsync(input, expected,
accessibility: Accessibility.Private,
modifiers: new Editing.DeclarationModifiers(isSealed: true));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration), WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544405")]
public async Task AddAbstractClass()
{
var input = "namespace [|N|] { }";
var expected = @"namespace N
{
protected internal abstract class C
{
}
}";
await TestAddNamedTypeAsync(input, expected,
accessibility: Accessibility.ProtectedOrInternal,
modifiers: new Editing.DeclarationModifiers(isAbstract: true));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddStruct()
{
var input = "namespace [|N|] { }";
var expected = @"namespace N
{
internal struct S
{
}
}";
await TestAddNamedTypeAsync(input, expected,
name: "S",
accessibility: Accessibility.Internal,
typeKind: TypeKind.Struct);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration), WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546224")]
public async Task AddSealedStruct()
{
var input = "namespace [|N|] { }";
var expected = @"namespace N
{
public struct S
{
}
}";
await TestAddNamedTypeAsync(input, expected,
name: "S",
modifiers: new Editing.DeclarationModifiers(isSealed: true),
accessibility: Accessibility.Public,
typeKind: TypeKind.Struct);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddInterface()
{
var input = "namespace [|N|] { }";
var expected = @"namespace N
{
public interface I
{
}
}";
await TestAddNamedTypeAsync(input, expected,
name: "I",
typeKind: TypeKind.Interface);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration), WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544080")]
public async Task AddEnum()
{
var input = "namespace [|N|] { }";
var expected = @"namespace N
{
public enum E
{
}
}";
await TestAddNamedTypeAsync(input, expected, "E",
typeKind: TypeKind.Enum);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration), WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544527")]
public async Task AddEnumWithValues()
{
var input = "namespace [|N|] { }";
var expected = @"namespace N
{
public enum E
{
F1 = 1,
F2 = 2
}
}";
await TestAddNamedTypeAsync(input, expected, "E",
typeKind: TypeKind.Enum,
members: Members(CreateEnumField("F1", 1), CreateEnumField("F2", 2)));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration), WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544080")]
public async Task AddDelegateType()
{
var input = "class [|C|] { }";
var expected = @"class C
{
public delegate int D(string s);
}";
await TestAddDelegateTypeAsync(input, expected,
returnType: typeof(int),
parameters: Parameters(Parameter(typeof(string), "s")));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration), WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546224")]
public async Task AddSealedDelegateType()
{
var input = "class [|C|] { }";
var expected = @"class C
{
public delegate int D(string s);
}";
await TestAddDelegateTypeAsync(input, expected,
returnType: typeof(int),
parameters: Parameters(Parameter(typeof(string), "s")),
modifiers: new Editing.DeclarationModifiers(isSealed: true));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddEvent()
{
var input = "class [|C|] { }";
var expected = @"class C
{
public event System.Action E;
}";
await TestAddEventAsync(input, expected,
context: new CodeGenerationContext(addImports: false));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddCustomEventToClassFromSourceSymbol()
{
var sourceGenerated = @"class [|C2|]
{
event EventHandler Click
{
add
{
Events.AddHandler(""ClickEvent"", value)
}
remove
{
Events.RemoveHandler(""ClickEvent"", value)
}
}
}";
var input = "class [|C1|] { }";
var expected = @"class C1
{
event EventHandler Click
{
add
{
Events.AddHandler(""ClickEvent"", value)
}
remove
{
Events.RemoveHandler(""ClickEvent"", value)
}
}
}";
var context = new CodeGenerationContext(reuseSyntax: true);
await TestGenerateFromSourceSymbolAsync(sourceGenerated, input, expected, onlyGenerateMembers: true, context: context);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddUnsafeEvent()
{
var input = "class [|C|] { }";
var expected = @"class C
{
public unsafe event System.Action E;
}";
await TestAddEventAsync(input, expected,
modifiers: new Editing.DeclarationModifiers(isUnsafe: true),
context: new CodeGenerationContext(addImports: false));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddEventWithAccessors()
{
var input = "class [|C|] { }";
var expected = @"class C
{
public event System.Action E
{
add
{
}
remove
{
}
}
}";
await TestAddEventAsync(input, expected,
addMethod: CodeGenerationSymbolFactory.CreateAccessorSymbol(ImmutableArray<AttributeData>.Empty, Accessibility.NotApplicable, ImmutableArray<SyntaxNode>.Empty),
removeMethod: CodeGenerationSymbolFactory.CreateAccessorSymbol(ImmutableArray<AttributeData>.Empty, Accessibility.NotApplicable, ImmutableArray<SyntaxNode>.Empty),
context: new CodeGenerationContext(addImports: false));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddMethodToClass()
{
var input = "class [|C|] { }";
var expected = @"class C
{
public void M()
{
}
}";
await TestAddMethodAsync(input, expected,
returnType: typeof(void));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddMethodToClassFromSourceSymbol()
{
var sourceGenerated = @"class [|C2|]
{
public int FInt()
{
return 0;
}
}";
var input = "class [|C1|] { }";
var expected = @"class C1
{
public int FInt()
{
return 0;
}
}";
var context = new CodeGenerationContext(reuseSyntax: true);
await TestGenerateFromSourceSymbolAsync(sourceGenerated, input, expected, onlyGenerateMembers: true, context: context);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddMethodToClassEscapedName()
{
var input = "class [|C|] { }";
var expected = @"using System;
class C
{
public DateTime @static()
{
}
}";
await TestAddMethodAsync(input, expected,
name: "static",
returnType: typeof(DateTime));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddStaticMethodToStruct()
{
var input = "struct [|S|] { }";
var expected = @"struct S
{
public static int M()
{
$$
}
}";
await TestAddMethodAsync(input, expected,
modifiers: new Editing.DeclarationModifiers(isStatic: true),
returnType: typeof(int),
statements: "return 0;");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddSealedOverrideMethod()
{
var input = "class [|C|] { }";
var expected = @"class C
{
public sealed override int GetHashCode()
{
$$
}
}";
await TestAddMethodAsync(input, expected,
name: "GetHashCode",
modifiers: new Editing.DeclarationModifiers(isOverride: true, isSealed: true),
returnType: typeof(int),
statements: "return 0;");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddAbstractMethod()
{
var input = "abstract class [|C|] { }";
var expected = @"abstract class C
{
public abstract int M();
}";
await TestAddMethodAsync(input, expected,
modifiers: new Editing.DeclarationModifiers(isAbstract: true),
returnType: typeof(int));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddMethodWithoutBody()
{
var input = "class [|C|] { }";
var expected = @"class C
{
public int M();
}";
await TestAddMethodAsync(input, expected,
returnType: typeof(int),
context: new CodeGenerationContext(generateMethodBodies: false));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddGenericMethod()
{
var input = "class [|C|] { }";
var expected = @"class C
{
public int M<T>()
{
$$
}
}";
await TestAddMethodAsync(input, expected,
returnType: typeof(int),
typeParameters: ImmutableArray.Create(CodeGenerationSymbolFactory.CreateTypeParameterSymbol("T")),
statements: "return new T().GetHashCode();");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddVirtualMethod()
{
var input = "class [|C|] { }";
var expected = @"class C
{
protected virtual int M()
{
$$
}
}";
await TestAddMethodAsync(input, expected,
accessibility: Accessibility.Protected,
modifiers: new Editing.DeclarationModifiers(isVirtual: true),
returnType: typeof(int),
statements: "return 0;");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddUnsafeNewMethod()
{
var input = "class [|C|] { }";
var expected = @"class C
{
public unsafe new string ToString()
{
$$
}
}";
await TestAddMethodAsync(input, expected,
name: "ToString",
modifiers: new Editing.DeclarationModifiers(isNew: true, isUnsafe: true),
returnType: typeof(string),
statements: "return String.Empty;");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddExplicitImplementationOfUnsafeMethod()
{
var input = "interface I { unsafe void M(int i); } class [|C|] : I { }";
var expected = @"interface I { unsafe void M(int i); }
class C : I
{
unsafe void I.M(int i)
{
}
}";
await TestAddMethodAsync(input, expected,
name: "M",
returnType: typeof(void),
parameters: Parameters(Parameter(typeof(int), "i")),
modifiers: new Editing.DeclarationModifiers(isUnsafe: true),
getExplicitInterfaces: s => s.LookupSymbols(input.IndexOf('M'), null, "M").OfType<IMethodSymbol>().ToImmutableArray());
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddExplicitImplementation()
{
var input = "interface I { void M(int i); } class [|C|] : I { }";
var expected = @"interface I { void M(int i); }
class C : I
{
void I.M(int i)
{
}
}";
await TestAddMethodAsync(input, expected,
name: "M",
returnType: typeof(void),
parameters: Parameters(Parameter(typeof(int), "i")),
getExplicitInterfaces: s => s.LookupSymbols(input.IndexOf('M'), null, "M").OfType<IMethodSymbol>().ToImmutableArray());
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddTrueFalseOperators()
{
var input = @"
class [|C|]
{
}";
var expected = @"
class C
{
public static bool operator true(C other)
{
$$
}
public static bool operator false(C other)
{
$$
}
}";
await TestAddOperatorsAsync(input, expected,
[CodeGenerationOperatorKind.True, CodeGenerationOperatorKind.False],
parameters: Parameters(Parameter("C", "other")),
returnType: typeof(bool),
statements: "return false;");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddUnaryOperators()
{
var input = @"
class [|C|]
{
}";
var expected = @"
class C
{
public static object operator +(C other)
{
$$
}
public static object operator -(C other)
{
$$
}
public static object operator !(C other)
{
$$
}
public static object operator ~(C other)
{
$$
}
public static object operator ++(C other)
{
$$
}
public static object operator --(C other)
{
$$
}
}";
await TestAddOperatorsAsync(input, expected,
[
CodeGenerationOperatorKind.UnaryPlus,
CodeGenerationOperatorKind.UnaryNegation,
CodeGenerationOperatorKind.LogicalNot,
CodeGenerationOperatorKind.OnesComplement,
CodeGenerationOperatorKind.Increment,
CodeGenerationOperatorKind.Decrement
],
parameters: Parameters(Parameter("C", "other")),
returnType: typeof(object),
statements: "return null;");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddBinaryOperators()
{
var input = @"
class [|C|]
{
}";
var expected = @"
class C
{
public static object operator +(C a, C b)
{
$$
}
public static object operator -(C a, C b)
{
$$
}
public static object operator *(C a, C b)
{
$$
}
public static object operator /(C a, C b)
{
$$
}
public static object operator %(C a, C b)
{
$$
}
public static object operator &(C a, C b)
{
$$
}
public static object operator |(C a, C b)
{
$$
}
public static object operator ^(C a, C b)
{
$$
}
public static object operator <<(C a, C b)
{
$$
}
public static object operator >>(C a, C b)
{
$$
}
}";
await TestAddOperatorsAsync(input, expected,
[
CodeGenerationOperatorKind.Addition,
CodeGenerationOperatorKind.Subtraction,
CodeGenerationOperatorKind.Multiplication,
CodeGenerationOperatorKind.Division,
CodeGenerationOperatorKind.Modulus,
CodeGenerationOperatorKind.BitwiseAnd,
CodeGenerationOperatorKind.BitwiseOr,
CodeGenerationOperatorKind.ExclusiveOr,
CodeGenerationOperatorKind.LeftShift,
CodeGenerationOperatorKind.RightShift
],
parameters: Parameters(Parameter("C", "a"), Parameter("C", "b")),
returnType: typeof(object),
statements: "return null;");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddComparisonOperators()
{
var input = @"
class [|C|]
{
}";
var expected = @"
class C
{
public static bool operator ==(C a, C b)
{
$$
}
public static bool operator !=(C a, C b)
{
$$
}
public static bool operator <(C a, C b)
{
$$
}
public static bool operator >(C a, C b)
{
$$
}
public static bool operator <=(C a, C b)
{
$$
}
public static bool operator >=(C a, C b)
{
$$
}
}";
await TestAddOperatorsAsync(input, expected,
[
CodeGenerationOperatorKind.Equality,
CodeGenerationOperatorKind.Inequality,
CodeGenerationOperatorKind.GreaterThan,
CodeGenerationOperatorKind.LessThan,
CodeGenerationOperatorKind.LessThanOrEqual,
CodeGenerationOperatorKind.GreaterThanOrEqual
],
parameters: Parameters(Parameter("C", "a"), Parameter("C", "b")),
returnType: typeof(bool),
statements: "return true;");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddUnsupportedOperator()
{
var input = "class [|C|] { }";
await TestAddUnsupportedOperatorAsync(input,
operatorKind: CodeGenerationOperatorKind.Like,
parameters: Parameters(Parameter("C", "a"), Parameter("C", "b")),
returnType: typeof(bool),
statements: "return true;");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddExplicitConversion()
{
var input = @"class [|C|] { }";
var expected = @"class C
{
public static explicit operator int(C other)
{
$$
}
}";
await TestAddConversionAsync(input, expected,
toType: typeof(int),
fromType: Parameter("C", "other"),
statements: "return 0;");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddImplicitConversion()
{
var input = @"class [|C|] { }";
var expected = @"class C
{
public static implicit operator int(C other)
{
$$
}
}";
await TestAddConversionAsync(input, expected,
toType: typeof(int),
fromType: Parameter("C", "other"),
isImplicit: true,
statements: "return 0;");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddStatements()
{
var input = "class C { public void [|M|]() { Console.WriteLine(1); } }";
var expected = "class C { public void M() { Console.WriteLine(1); $$} }";
await TestAddStatementsAsync(input, expected, "Console.WriteLine(2);");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
[WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/840265")]
public async Task AddDefaultParameterWithNonDefaultValueToMethod()
{
var input = "class C { public void [|M|]() { } }";
var expected = "class C { public void M(string text =\"Hello\") { } }";
await TestAddParametersAsync(input, expected,
Parameters(Parameter(typeof(string), "text", true, "Hello")));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddDefaultParameterWithDefaultValueToMethod()
{
var input = "class C { public void [|M|]() { } }";
var expected = "class C { public void M(double number =0) { } }";
await TestAddParametersAsync(input, expected,
Parameters(Parameter(typeof(double), "number", true)));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddParametersToMethod()
{
var input = "class C { public void [|M|]() { } }";
var expected = "class C { public void M(int num, string text =\"Hello!\", float floating =0.5F) { } }";
await TestAddParametersAsync(input, expected,
Parameters(Parameter(typeof(int), "num"), Parameter(typeof(string), "text", true, "Hello!"), Parameter(typeof(float), "floating", true, .5f)));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
[WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/841365")]
public async Task AddParamsParameterToMethod()
{
var input = "class C { public void [|M|]() { } }";
var expected = "class C { public void M(params char[]characters) { } }";
await TestAddParametersAsync(input, expected,
Parameters(Parameter(typeof(char[]), "characters", isParams: true)));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration), WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/544015")]
public async Task AddAutoProperty()
{
var input = "class [|C|] { }";
var expected = @"class C
{
public int P { get; internal set; }
}";
await TestAddPropertyAsync(input, expected,
type: typeof(int),
setterAccessibility: Accessibility.Internal);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddUnsafeAutoProperty()
{
var input = "class [|C|] { }";
var expected = @"class C
{
public unsafe int P { get; internal set; }
}";
await TestAddPropertyAsync(input, expected,
type: typeof(int),
modifiers: new Editing.DeclarationModifiers(isUnsafe: true),
setterAccessibility: Accessibility.Internal);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddPropertyToClassFromSourceSymbol()
{
var sourceGenerated = @"class [|C2|]
{
public int P
{
get
{
return 0;
}
}
}";
var input = "class [|C1|] { }";
var expected = @"class C1
{
public int P
{
get
{
return 0;
}
}
}";
var context = new CodeGenerationContext(reuseSyntax: true);
await TestGenerateFromSourceSymbolAsync(sourceGenerated, input, expected, onlyGenerateMembers: true, context: context);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddIndexer1()
{
var input = "class [|C|] { }";
var expected = "class C { public string this[int i] => String.Empty; }";
await TestAddPropertyAsync(input, expected,
type: typeof(string),
parameters: Parameters(Parameter(typeof(int), "i")),
getStatements: "return String.Empty;",
isIndexer: true);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddIndexer2()
{
var input = "class [|C|] { }";
var expected = @"class C
{
public string this[int i]
{
get
{
$$
}
}
}";
await TestAddPropertyAsync(input, expected,
type: typeof(string),
parameters: Parameters(Parameter(typeof(int), "i")),
getStatements: "return String.Empty;",
isIndexer: true,
options: new OptionsCollection(LanguageNames.CSharp)
{
{ CSharpCodeStyleOptions.PreferExpressionBodiedAccessors, CSharpCodeStyleOptions.NeverWithSilentEnforcement },
{ CSharpCodeStyleOptions.PreferExpressionBodiedIndexers, CSharpCodeStyleOptions.NeverWithSilentEnforcement },
});
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddParameterfulProperty()
{
var input = "class [|C|] { }";
var expected = @"class C
{
public string get_P(int i, int j)
{
$$
}
public void set_P(int i, int j, string value)
{
}
}";
await TestAddPropertyAsync(input, expected,
type: typeof(string),
getStatements: "return String.Empty;",
setStatements: "",
parameters: Parameters(Parameter(typeof(int), "i"), Parameter(typeof(int), "j")));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddAttributeToTypes()
{
var input = "class [|C|] { }";
var expected = @"[System.Serializable]
class C { }";
await TestAddAttributeAsync(input, expected, typeof(SerializableAttribute));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task RemoveAttributeFromTypes()
{
var input = @"[System.Serializable] class [|C|] { }";
var expected = "class C { }";
await TestRemoveAttributeAsync<SyntaxNode>(input, expected, typeof(SerializableAttribute));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddAttributeToMethods()
{
var input = "class C { public void [|M()|] { } }";
var expected = "class C { [System.Serializable] public void M() { } }";
await TestAddAttributeAsync(input, expected, typeof(SerializableAttribute));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task RemoveAttributeFromMethods()
{
var input = "class C { [System.Serializable] public void [|M()|] { } }";
var expected = "class C { public void M() { } }";
await TestRemoveAttributeAsync<SyntaxNode>(input, expected, typeof(SerializableAttribute));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddAttributeToFields()
{
var input = "class C { [|public int F|]; }";
var expected = "class C { [System.Serializable] public int F; }";
await TestAddAttributeAsync(input, expected, typeof(SerializableAttribute));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task RemoveAttributeFromFields()
{
var input = "class C { [System.Serializable] public int [|F|]; }";
var expected = "class C { public int F; }";
await TestRemoveAttributeAsync<FieldDeclarationSyntax>(input, expected, typeof(SerializableAttribute));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddAttributeToProperties()
{
var input = "class C { public int [|P|] { get; set; }}";
var expected = "class C { [System.Serializable] public int P { get; set; } }";
await TestAddAttributeAsync(input, expected, typeof(SerializableAttribute));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task RemoveAttributeFromProperties()
{
var input = "class C { [System.Serializable] public int [|P|] { get; set; }}";
var expected = "class C { public int P { get; set; } }";
await TestRemoveAttributeAsync<SyntaxNode>(input, expected, typeof(SerializableAttribute));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddAttributeToPropertyAccessor()
{
var input = "class C { public int P { [|get|]; set; }}";
var expected = "class C { public int P { [System.Serializable] get; set; }}";
await TestAddAttributeAsync(input, expected, typeof(SerializableAttribute));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task RemoveAttributeFromPropertyAccessor()
{
var input = "class C { public int P { [System.Serializable] [|get|]; set; } }";
var expected = "class C { public int P { get; set; } }";
await TestRemoveAttributeAsync<SyntaxNode>(input, expected, typeof(SerializableAttribute));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddAttributeToEnums()
{
var input = "enum [|C|] { One, Two }";
var expected = @"[System.Serializable]
enum C { One, Two }";
await TestAddAttributeAsync(input, expected, typeof(SerializableAttribute));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task RemoveAttributeFromEnums()
{
var input = "[System.Serializable] enum [|C|] { One, Two }";
var expected = "enum C { One, Two }";
await TestRemoveAttributeAsync<SyntaxNode>(input, expected, typeof(SerializableAttribute));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddAttributeToEnumMembers()
{
var input = "enum C { [|One|], Two }";
var expected = "enum C { [System.Serializable] One, Two }";
await TestAddAttributeAsync(input, expected, typeof(SerializableAttribute));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task RemoveAttributeFromEnumMembers()
{
var input = "enum C { [System.Serializable] [|One|], Two }";
var expected = "enum C { One, Two }";
await TestRemoveAttributeAsync<SyntaxNode>(input, expected, typeof(SerializableAttribute));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddAttributeToIndexer()
{
var input = "class C { public int [|this[int y]|] { get; set; }}";
var expected = "class C { [System.Serializable] public int this[int y] { get; set; } }";
await TestAddAttributeAsync(input, expected, typeof(SerializableAttribute));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task RemoveAttributeFromIndexer()
{
var input = "class C { [System.Serializable] public int [|this[int y]|] { get; set; }}";
var expected = "class C { public int this[int y] { get; set; } }";
await TestRemoveAttributeAsync<SyntaxNode>(input, expected, typeof(SerializableAttribute));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddAttributeToOperator()
{
var input = "class C { public static C operator [|+|] (C c1, C c2) { return new C(); }}";
var expected = "class C { [System.Serializable] public static C operator +(C c1, C c2) { return new C(); } }";
await TestAddAttributeAsync(input, expected, typeof(SerializableAttribute));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task RemoveAttributeFromOperator()
{
var input = "class C { [System.Serializable] public static C operator [|+|](C c1, C c2) { return new C(); }}";
var expected = "class C { public static C operator +(C c1, C c2) { return new C(); } }";
await TestRemoveAttributeAsync<SyntaxNode>(input, expected, typeof(SerializableAttribute));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddAttributeToDelegate()
{
var input = "delegate int [|D()|];";
var expected = @"[System.Serializable]
delegate int D();";
await TestAddAttributeAsync(input, expected, typeof(SerializableAttribute));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task RemoveAttributeFromDelegate()
{
var input = "[System.Serializable] delegate int [|D()|];";
var expected = "delegate int D();";
await TestRemoveAttributeAsync<SyntaxNode>(input, expected, typeof(SerializableAttribute));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddAttributeToParam()
{
var input = "class C { public void M([|int x|]) { } }";
var expected = "class C { public void M([System.Serializable] int x) { } }";
await TestAddAttributeAsync(input, expected, typeof(SerializableAttribute));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task RemoveAttributeFromParam()
{
var input = "class C { public void M([System.Serializable] [|int x|]) { } }";
var expected = "class C { public void M(int x) { } }";
await TestRemoveAttributeAsync<SyntaxNode>(input, expected, typeof(SerializableAttribute));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddAttributeToTypeParam()
{
var input = "class C<[|T|]> { }";
var expected = "class C<[System.Serializable] T> { }";
await TestAddAttributeAsync(input, expected, typeof(SerializableAttribute));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task RemoveAttributeFromTypeParam()
{
var input = "class C<[System.Serializable] [|T|]> { }";
var expected = "class C<T> { }";
await TestRemoveAttributeAsync<SyntaxNode>(input, expected, typeof(SerializableAttribute));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddAttributeToCompilationUnit()
{
var input = "[|class C { } class D {} |]";
var expected = @"[assembly: System.Serializable]
class C { }
class D { }";
await TestAddAttributeAsync(input, expected, typeof(SerializableAttribute), AssemblyKeyword);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task AddAttributeWithWrongTarget()
{
var input = "[|class C { } class D {} |]";
var expected = "";
await Assert.ThrowsAsync<AggregateException>(async () =>
await TestAddAttributeAsync(input, expected, typeof(SerializableAttribute), RefKeyword));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task RemoveAttributeWithTrivia()
{
// With trivia.
var input = @"// Comment 1
[System.Serializable] // Comment 2
/* Comment 3*/ class [|C|] { }";
var expected = @"// Comment 1
/* Comment 3*/ class C { }";
await TestRemoveAttributeAsync<SyntaxNode>(input, expected, typeof(SerializableAttribute));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task RemoveAttributeWithTrivia_NewLine()
{
// With trivia, redundant newline at end of attribute removed.
var input = @"// Comment 1
[System.Serializable]
/* Comment 3*/ class [|C|] { }";
var expected = @"// Comment 1
/* Comment 3*/ class C { }";
await TestRemoveAttributeAsync<SyntaxNode>(input, expected, typeof(SerializableAttribute));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task RemoveAttributeWithMultipleAttributes()
{
// Multiple attributes.
var input = @"// Comment 1
/*Comment2*/[ /*Comment3*/ System.Serializable /*Comment4*/, /*Comment5*/System.Flags /*Comment6*/] /*Comment7*/
/* Comment 8*/
class [|C|] { }";
var expected = @"// Comment 1
/*Comment2*/[ /*Comment3*/ /*Comment5*/System.Flags /*Comment6*/] /*Comment7*/
/* Comment 8*/
class C { }";
await TestRemoveAttributeAsync<SyntaxNode>(input, expected, typeof(SerializableAttribute));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task RemoveAttributeWithMultipleAttributeLists()
{
// Multiple attributes.
var input = @"// Comment 1
/*Comment2*/[ /*Comment3*/ System.Serializable /*Comment4*/, /*Comment5*/System.Flags /*Comment6*/] /*Comment7*/
[ /*Comment9*/ System.Obsolete /*Comment10*/] /*Comment11*/
/* Comment12*/
class [|C|] { }";
var expected = @"// Comment 1
/*Comment2*/[ /*Comment3*/ /*Comment5*/System.Flags /*Comment6*/] /*Comment7*/
[ /*Comment9*/ System.Obsolete /*Comment10*/] /*Comment11*/
/* Comment12*/
class C { }";
await TestRemoveAttributeAsync<SyntaxNode>(input, expected, typeof(SerializableAttribute));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task TestUpdateModifiers()
{
var input = @"public static class [|C|] // Comment 1
{
// Comment 2
}";
var expected = @"internal partial sealed class C // Comment 1
{
// Comment 2
}";
var eol = SyntaxFactory.EndOfLine(@"");
var newModifiers = new[] { InternalKeyword.WithLeadingTrivia(eol) }.Concat(
CreateModifierTokens(new Editing.DeclarationModifiers(isSealed: true, isPartial: true), LanguageNames.CSharp));
await TestUpdateDeclarationAsync<ClassDeclarationSyntax>(input, expected, modifiers: newModifiers);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task TestUpdateAccessibility()
{
var input = @"// Comment 0
public static class [|C|] // Comment 1
{
// Comment 2
}";
var expected = @"// Comment 0
internal static class C // Comment 1
{
// Comment 2
}";
await TestUpdateDeclarationAsync<ClassDeclarationSyntax>(input, expected, accessibility: Accessibility.Internal);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task TestUpdateDeclarationType()
{
var input = @"
public static class C
{
// Comment 1
public static char [|F|]() { return 0; }
}";
var expected = @"
public static class C
{
// Comment 1
public static int F() { return 0; }
}";
await TestUpdateDeclarationAsync<MethodDeclarationSyntax>(input, expected, getType: GetTypeSymbol(typeof(int)));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task TestUpdateDeclarationMembers()
{
var input = @"
public static class [|C|]
{
// Comment 0
public int {|RetainedMember:f|};
// Comment 1
public static char F() { return 0; }
}";
var expected = @"
public static class C
{
// Comment 0
public int f;
public int f2;
}";
var getField = CreateField(Accessibility.Public, new Editing.DeclarationModifiers(), typeof(int), "f2");
var getMembers = ImmutableArray.Create(getField);
await TestUpdateDeclarationAsync<ClassDeclarationSyntax>(
input, expected, getNewMembers: getMembers);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
public async Task TestUpdateDeclarationMembers_DifferentOrder()
{
var input = @"
public static class [|C|]
{
// Comment 0
public int f;
// Comment 1
public static char {|RetainedMember:F|}() { return 0; }
}";
var expected = @"
public static class C
{
public int f2;
// Comment 1
public static char F() { return 0; }
}";
var getField = CreateField(Accessibility.Public, new Editing.DeclarationModifiers(), typeof(int), "f2");
var getMembers = ImmutableArray.Create(getField);
await TestUpdateDeclarationAsync<ClassDeclarationSyntax>(input, expected, getNewMembers: getMembers, declareNewMembersAtTop: true);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGenerationSortDeclarations)]
public async Task SortAroundDestructor()
{
var generationSource = "public class [|C|] { public C(){} public int this[int index]{get{return 0;}set{value = 0;}} }";
var initial = "public class [|C|] { ~C(){} }";
var expected = @"public class C {
public C()
{
}
~C(){}
public int this[int index]
{
get
{
}
set
{
}
}
}";
await TestGenerateFromSourceSymbolAsync(generationSource, initial, expected, onlyGenerateMembers: true);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeGenerationSortDeclarations)]
public async Task SortOperators()
{
var generationSource = @"
namespace N
{
public class [|C|]
{
// Unary operators
public static bool operator false (C other) { return false; }
public static bool operator true (C other) { return true; }
public static C operator ++ (C other) { return null; }
public static C operator -- (C other) { return null; }
public static C operator ~ (C other) { return null; }
public static C operator ! (C other) { return null; }
public static C operator - (C other) { return null; }
public static C operator + (C other) { return null; }
// Binary operators
public static C operator >> (C a, int shift) { return null; }
public static C operator << (C a, int shift) { return null; }
public static C operator ^ (C a, C b) { return null; }
public static C operator | (C a, C b) { return null; }
public static C operator & (C a, C b) { return null; }
public static C operator % (C a, C b) { return null; }
public static C operator / (C a, C b) { return null; }
public static C operator * (C a, C b) { return null; }
public static C operator - (C a, C b) { return null; }
public static C operator + (C a, C b) { return null; }
// Comparison operators
public static bool operator >= (C a, C b) { return true; }
public static bool operator <= (C a, C b) { return true; }
public static bool operator > (C a, C b) { return true; }
public static bool operator < (C a, C b) { return true; }
public static bool operator != (C a, C b) { return true; }
public static bool operator == (C a, C b) { return true; }
}
}";
var initial = "namespace [|N|] { }";
var expected = @"namespace N
{
public class C
{
public static C operator +(C other);
public static C operator +(C a, C b);
public static C operator -(C other);
public static C operator -(C a, C b);
public static C operator !(C other);
public static C operator ~(C other);
public static C operator ++(C other);
public static C operator --(C other);
public static C operator *(C a, C b);
public static C operator /(C a, C b);
public static C operator %(C a, C b);
public static C operator &(C a, C b);
public static C operator |(C a, C b);
public static C operator ^(C a, C b);
public static C operator <<(C a, int shift);
public static C operator >>(C a, int shift);
public static bool operator ==(C a, C b);
public static bool operator !=(C a, C b);
public static bool operator <(C a, C b);
public static bool operator >(C a, C b);
public static bool operator <=(C a, C b);
public static bool operator >=(C a, C b);
public static bool operator true(C other);
public static bool operator false(C other);
}
}";
await TestGenerateFromSourceSymbolAsync(generationSource, initial, expected,
forceLanguage: LanguageNames.CSharp,
context: new CodeGenerationContext(generateMethodBodies: false));
}
}
[Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/665008")]
public async Task TestExtensionMethods()
{
var generationSource = @"
public static class [|C|]
{
public static void ExtMethod1(this string s, int y, string z) {}
}";
var initial = "public static class [|C|] {}";
var expected = @"public static class C
{
public static void ExtMethod1(this string s, int y, string z);
}";
await TestGenerateFromSourceSymbolAsync(generationSource, initial, expected,
context: new CodeGenerationContext(generateMethodBodies: false),
onlyGenerateMembers: true);
}
[Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/530829")]
public async Task TestVBPropertiesWithParams()
{
var generationSource = @"
Namespace N
Public Class [|C|]
Public Overridable Property IndexProp(ByVal p1 As Integer) As String
Get
Return Nothing
End Get
Set(ByVal value As String)
End Set
End Property
End Class
End Namespace
";
var initial = "namespace [|N|] {}";
var expected = @"namespace N
{
public class C
{
public virtual string get_IndexProp(int p1);
public virtual void set_IndexProp(int p1, string value);
}
}";
await TestGenerateFromSourceSymbolAsync(generationSource, initial, expected,
context: new CodeGenerationContext(generateMethodBodies: false));
}
[Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/812738")]
public async Task TestRefParamsWithDefaultValue()
{
var generationSource = @"
Public Class [|C|]
Public Sub Goo(x As Integer, Optional ByRef y As Integer = 10, Optional ByRef z As Object = Nothing)
End Sub
End Class";
var initial = "public class [|C|] {}";
var expected = @"public class C
{
public void Goo(int x, ref int y, ref object z);
}";
await TestGenerateFromSourceSymbolAsync(generationSource, initial, expected,
context: new CodeGenerationContext(generateMethodBodies: false),
onlyGenerateMembers: true);
}
[Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/848357")]
public async Task TestConstraints()
{
var generationSource = @"
namespace N
{
public class [|C|]<T, U> where T : struct where U : class
{
public void Goo<Q, R>() where Q : new() where R : IComparable { }
public delegate void D<T, U>(T t, U u) where T : struct where U : class;
}
}
";
var initial = "namespace [|N|] {}";
var expected = @"namespace N
{
public class C<T, U>
where T : struct
where U : class
{
public void Goo<Q, R>()
where Q : new()
where R : IComparable;
public delegate void D<T, U>(T t, U u)
where T : struct
where U : class;
}
}";
await TestGenerateFromSourceSymbolAsync(generationSource, initial, expected,
context: new CodeGenerationContext(generateMethodBodies: false),
onlyGenerateMembers: true);
}
}
|