提交 57e75065 编写于 作者: J Julien 提交者: VSadov

Tuples: solve IDE crash with Extract Method (#10740)

上级 4ec7f756
......@@ -716,7 +716,7 @@ private BoundExpression BindTupleExpression(TupleExpressionSyntax node, Diagnost
if (hasNaturalType)
{
tupleTypeOpt = TupleTypeSymbol.Create(elements, elementNamesArray, node, this, diagnostics);
tupleTypeOpt = TupleTypeSymbol.Create(elements, elementNamesArray, this.Compilation, node, diagnostics);
}
return new BoundTupleLiteral(node, elementNamesArray, boundArguments.ToImmutableAndFree(), tupleTypeOpt, hasErrors);
......
......@@ -440,14 +440,13 @@ private TypeSymbol BindTupleType(TupleTypeSyntax syntax, DiagnosticBag diagnosti
return new ExtendedErrorTypeSymbol(this.Compilation.Assembly.GlobalNamespace, LookupResultKind.NotCreatable, diagnostics.Add(ErrorCode.ERR_TupleTooFewElements, syntax.Location));
}
return TupleTypeSymbol.Create(
typesArray,
elementNames == null ?
return TupleTypeSymbol.Create(typesArray,
elementNames == null ?
default(ImmutableArray<string>) :
elementNames.ToImmutableAndFree(),
syntax,
this,
diagnostics);
this.Compilation,
syntax,
diagnostics);
}
private static void CollectTupleFieldMemberNames(string name, int position, int tupleSize, ref ArrayBuilder<string> elementNames)
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.CodeAnalysis.CodeGen;
using Microsoft.CodeAnalysis.Collections;
using Microsoft.CodeAnalysis.CSharp.Emit;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Emit;
using Microsoft.CodeAnalysis.Symbols;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
......@@ -11,16 +21,6 @@
using System.Reflection.Metadata;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeGen;
using Microsoft.CodeAnalysis.Collections;
using Microsoft.CodeAnalysis.CSharp.Emit;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Emit;
using Microsoft.CodeAnalysis.Symbols;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp
{
......@@ -2792,6 +2792,48 @@ protected override IPointerTypeSymbol CommonCreatePointerTypeSymbol(ITypeSymbol
return CreatePointerTypeSymbol(elementType.EnsureCSharpSymbolOrNull<ITypeSymbol, TypeSymbol>("elementType"));
}
protected override INamedTypeSymbol CommonCreateTupleTypeSymbol(ImmutableArray<ITypeSymbol> elementTypes, ImmutableArray<string> elementNames)
{
if (elementTypes.IsDefault)
{
throw new ArgumentNullException(nameof(elementTypes));
}
if (elementTypes.Length <= 1)
{
throw new ArgumentException(CodeAnalysisResources.TuplesNeedAtLeastTwoElements, nameof(elementNames));
}
if (!elementNames.IsDefault)
{
if (elementNames.Length != elementTypes.Length)
{
throw new ArgumentException(CodeAnalysisResources.TupleNamesAllOrNone, nameof(elementNames));
}
for (int i = 0; i < elementNames.Length; i++)
{
if ((object)elementNames[i] == null)
{
throw new ArgumentNullException($"{nameof(elementNames)}[{i}]");
}
}
}
var typesBuilder = ArrayBuilder<TypeSymbol>.GetInstance(elementTypes.Length);
for (int i = 0; i < elementTypes.Length; i++)
{
if (elementTypes[i] == null)
{
throw new ArgumentNullException($"{nameof(elementTypes)}[{i}]");
}
typesBuilder.Add(elementTypes[i].EnsureCSharpSymbolOrNull<ITypeSymbol, TypeSymbol>($"{nameof(elementTypes)}[{i}]"));
}
return TupleTypeSymbol.Create(typesBuilder.ToImmutableAndFree(), elementNames, this);
}
protected override ITypeSymbol CommonDynamicType
{
get { return DynamicType; }
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.Cci;
using Microsoft.CodeAnalysis.RuntimeMembers;
using Roslyn.Utilities;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using Microsoft.Cci;
using Microsoft.CodeAnalysis.RuntimeMembers;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
/// <summary>
/// A TupleTypeSymbol represents a tuple type, such as (int, byte) or (int a, long b).
/// </summary>
internal sealed class TupleTypeSymbol : NamedTypeSymbol, ITupleTypeSymbol
internal sealed class TupleTypeSymbol : NamedTypeSymbol
{
private readonly NamedTypeSymbol _underlyingType;
private readonly ImmutableArray<TupleFieldSymbol> _fields;
......@@ -74,9 +74,9 @@ internal sealed class TupleTypeSymbol : NamedTypeSymbol, ITupleTypeSymbol
internal static TupleTypeSymbol Create(
ImmutableArray<TypeSymbol> elementTypes,
ImmutableArray<string> elementNames,
CSharpSyntaxNode syntax,
Binder binder,
DiagnosticBag diagnostics
CSharpCompilation compilation,
CSharpSyntaxNode syntax = null,
DiagnosticBag diagnostics = null
)
{
Debug.Assert(elementNames.IsDefault || elementTypes.Length == elementNames.Length);
......@@ -87,9 +87,10 @@ DiagnosticBag diagnostics
{
throw ExceptionUtilities.Unreachable;
}
NamedTypeSymbol underlyingType = GetTupleUnderlyingType(elementTypes, syntax, binder, diagnostics);
return new TupleTypeSymbol(underlyingType, elementNames, binder.Compilation.Assembly);
NamedTypeSymbol underlyingType = GetTupleUnderlyingType(elementTypes, syntax, compilation, diagnostics);
return new TupleTypeSymbol(underlyingType, elementNames, compilation.Assembly);
}
/// <summary>
......@@ -268,21 +269,34 @@ internal static int NumberOfValueTuples(int numElements, out int remainder)
/// <summary>
/// Produces the underlying ValueTuple corresponding to this list of element types.
///
/// Pass a null diagnostic bag and syntax node if you don't care about diagnostics.
/// </summary>
private static NamedTypeSymbol GetTupleUnderlyingType(ImmutableArray<TypeSymbol> elementTypes, CSharpSyntaxNode syntax, Binder binder, DiagnosticBag diagnostics)
private static NamedTypeSymbol GetTupleUnderlyingType(ImmutableArray<TypeSymbol> elementTypes, CSharpSyntaxNode syntax, CSharpCompilation compilation, DiagnosticBag diagnostics)
{
int numElements = elementTypes.Length;
int remainder;
int chainLength = NumberOfValueTuples(numElements, out remainder);
NamedTypeSymbol currentSymbol = default(NamedTypeSymbol);
NamedTypeSymbol firstTupleType = binder.GetWellKnownType(GetTupleType(remainder), diagnostics, syntax);
NamedTypeSymbol firstTupleType = compilation.GetWellKnownType(GetTupleType(remainder));
if ((object)diagnostics != null && (object)syntax != null)
{
Binder.ReportUseSiteDiagnostics(firstTupleType, diagnostics, syntax);
}
currentSymbol = firstTupleType.Construct(ImmutableArray.Create(elementTypes, (chainLength - 1) * (RestPosition - 1), remainder));
int loop = chainLength - 1;
if (loop > 0)
{
NamedTypeSymbol chainedTupleType = binder.GetWellKnownType(GetTupleType(RestPosition), diagnostics, syntax);
NamedTypeSymbol chainedTupleType = compilation.GetWellKnownType(GetTupleType(RestPosition));
if ((object)diagnostics != null && (object)syntax != null)
{
Binder.ReportUseSiteDiagnostics(firstTupleType, diagnostics, syntax);
}
do
{
......@@ -513,6 +527,27 @@ internal NamedTypeSymbol UnderlyingTupleType
internal bool HasFriendlyNames => _hasFriendlyNames;
public override ImmutableArray<ITypeSymbol> TupleElementTypes
{
get
{
return _fields.SelectAsArray(f => (ITypeSymbol)f.Type);
}
}
public override ImmutableArray<string> TupleElementNames
{
get
{
if (_hasFriendlyNames)
{
return _fields.SelectAsArray(f => f.Name);
}
return default(ImmutableArray<string>);
}
}
internal override NamedTypeSymbol BaseTypeNoUseSiteDiagnostics
{
get
......@@ -909,10 +944,6 @@ internal override bool GetUnificationUseSiteDiagnosticRecursive(ref DiagnosticIn
#endregion
#region ITupleTypeSymbol Members
#endregion
#region ISymbol Members
internal override AttributeUsageInfo GetAttributeUsageInfo()
......
......@@ -556,13 +556,17 @@ public virtual bool IsAnonymousType
/// <summary>
/// Is this a symbol for a Tuple
/// </summary>
public virtual bool IsTupleType
{
get
{
return false;
}
}
public virtual bool IsTupleType => false;
/// <summary>
/// If this symbol represents a tuple type, get the types of the tuple's elements.
/// </summary>
public virtual ImmutableArray<ITypeSymbol> TupleElementTypes => default(ImmutableArray<ITypeSymbol>);
/// <summary>
/// If this symbol represents a tuple type, get the names of the tuple's elements.
/// </summary>
public virtual ImmutableArray<string> TupleElementNames => default(ImmutableArray<string>);
/// <summary>
/// Is this type a managed type (false for everything but enum, pointer, and
......
......@@ -4,13 +4,16 @@
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Roslyn.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities;
using System;
using System.Collections.Immutable;
using System.Linq;
using System.Text;
using Xunit;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests.CodeGen
{
[Trait(Traits.Feature, Traits.Features.Tuples)]
public class CodeGenTupleTests : CSharpTestBase
{
private static readonly string trivial2uple =
......@@ -886,7 +889,12 @@ static void Main()
Assert.Equal("(System.Int32 Item1, System.String Item2, System.Int32 c)", model.GetTypeInfo(node).Type.ToTestDisplayString());
var x = nodes.OfType<VariableDeclaratorSyntax>().First();
Assert.Equal("(System.Int32 Item1, System.String a) x", model.GetDeclaredSymbol(x).ToTestDisplayString());
var xSymbol = ((SourceLocalSymbol)model.GetDeclaredSymbol(x)).Type;
Assert.Equal("(System.Int32 Item1, System.String a)", xSymbol.ToTestDisplayString());
Assert.True(xSymbol.IsTupleType);
Assert.Equal(new[] { "System.Int32", "System.String" }, xSymbol.TupleElementTypes.SelectAsArray(t => t.ToTestDisplayString()));
Assert.Equal(new[] { "Item1", "a" }, xSymbol.TupleElementNames);
}
[Fact]
......@@ -2451,6 +2459,244 @@ static void Main()
var comp = CompileAndVerify(source, expectedOutput: "12345678901234567890123456789012345", parseOptions: TestOptions.Regular.WithTuplesFeature());
}
[Fact]
public void CreateTupleTypeSymbol_BadArguments()
{
var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef }); // no ValueTuple
ITypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32);
Assert.Throws<ArgumentNullException>(() => comp.CreateTupleTypeSymbol(default(ImmutableArray<ITypeSymbol>), default(ImmutableArray<string>)));
// 0-tuple and 1-tuple are not supported at this point
Assert.Throws<ArgumentException>(() => comp.CreateTupleTypeSymbol(ImmutableArray<ITypeSymbol>.Empty, default(ImmutableArray<string>)));
Assert.Throws<ArgumentException>(() => comp.CreateTupleTypeSymbol(new[] { intType }.AsImmutable(), default(ImmutableArray<string>)));
// if names are provided, you need one for each element
Assert.Throws<ArgumentException>(() => comp.CreateTupleTypeSymbol(new[] { intType, intType }.AsImmutable(), new[] { "Item1" }.AsImmutable()));
// if names are provided, they can't be null
Assert.Throws<ArgumentNullException>(() => comp.CreateTupleTypeSymbol(new[] { intType, intType }.AsImmutable(), new[] { "Item1", null }.AsImmutable()));
// null types aren't allowed
Assert.Throws<ArgumentNullException>(() => comp.CreateTupleTypeSymbol(new[] { intType, null }.AsImmutable(), default(ImmutableArray<string>)));
}
[Fact]
public void CreateTupleTypeSymbol_WithValueTuple()
{
var tupleComp = CreateCompilationWithMscorlib(trivial2uple + trivial3uple + trivalRemainingTuples);
var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef, tupleComp.ToMetadataReference() });
ITypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32);
ITypeSymbol stringType = comp.GetSpecialType(SpecialType.System_String);
var tupleWithoutNames = comp.CreateTupleTypeSymbol(ImmutableArray.Create(intType, stringType), default(ImmutableArray<string>));
Assert.True(tupleWithoutNames.IsTupleType);
Assert.Equal("(System.Int32, System.String)", tupleWithoutNames.ToTestDisplayString());
Assert.False(((TupleTypeSymbol)tupleWithoutNames).HasFriendlyNames);
Assert.True(tupleWithoutNames.TupleElementNames.IsDefault);
Assert.Equal(new[] { "System.Int32", "System.String" }, tupleWithoutNames.TupleElementTypes.Select(t => t.ToTestDisplayString()));
Assert.Equal(SymbolKind.NamedType, tupleWithoutNames.Kind);
}
[Fact]
public void CreateTupleTypeSymbol_NoNames()
{
var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef }); // no ValueTuple
ITypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32);
ITypeSymbol stringType = comp.GetSpecialType(SpecialType.System_String);
var tupleWithoutNames = comp.CreateTupleTypeSymbol(ImmutableArray.Create(intType, stringType), default(ImmutableArray<string>));
Assert.True(tupleWithoutNames.IsTupleType);
Assert.Equal("(System.Int32, System.String)", tupleWithoutNames.ToTestDisplayString());
Assert.False(((TupleTypeSymbol)tupleWithoutNames).HasFriendlyNames);
Assert.True(tupleWithoutNames.TupleElementNames.IsDefault);
Assert.Equal(new[] { "System.Int32", "System.String" }, tupleWithoutNames.TupleElementTypes.Select(t => t.ToTestDisplayString()));
Assert.Equal(SymbolKind.NamedType, tupleWithoutNames.Kind);
}
[Fact]
public void CreateTupleTypeSymbol_WithNames()
{
var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef }); // no ValueTuple
ITypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32);
ITypeSymbol stringType = comp.GetSpecialType(SpecialType.System_String);
var tupleWithNames = comp.CreateTupleTypeSymbol(ImmutableArray.Create(intType, stringType), ImmutableArray.Create("Alice", "Bob"));
Assert.True(tupleWithNames.IsTupleType);
Assert.Equal("(System.Int32 Alice, System.String Bob)", tupleWithNames.ToTestDisplayString());
Assert.True(((TupleTypeSymbol)tupleWithNames).HasFriendlyNames);
Assert.Equal(new[] { "Alice", "Bob" }, tupleWithNames.TupleElementNames);
Assert.Equal(new[] { "System.Int32", "System.String" }, tupleWithNames.TupleElementTypes.Select(t => t.ToTestDisplayString()));
Assert.Equal(SymbolKind.NamedType, tupleWithNames.Kind);
}
[Fact]
public void CreateTupleTypeSymbol_WithBadNames()
{
var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef }); // no ValueTuple
ITypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32);
var tupleWithNames = comp.CreateTupleTypeSymbol(ImmutableArray.Create(intType, intType), ImmutableArray.Create("Item2", "Item1"));
Assert.True(tupleWithNames.IsTupleType);
Assert.Equal("(System.Int32 Item2, System.Int32 Item1)", tupleWithNames.ToTestDisplayString());
Assert.True(((TupleTypeSymbol)tupleWithNames).HasFriendlyNames);
Assert.Equal(new[] { "Item2", "Item1" }, tupleWithNames.TupleElementNames);
Assert.Equal(new[] { "System.Int32", "System.Int32" }, tupleWithNames.TupleElementTypes.Select(t => t.ToTestDisplayString()));
Assert.Equal(SymbolKind.NamedType, tupleWithNames.Kind);
}
[Fact]
public void CreateTupleTypeSymbol_Tuple8NoNames()
{
var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef }); // no ValueTuple
ITypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32);
ITypeSymbol stringType = comp.GetSpecialType(SpecialType.System_String);
var tuple8WithoutNames = comp.CreateTupleTypeSymbol(ImmutableArray.Create(intType, stringType, intType, stringType, intType, stringType, intType, stringType),
default(ImmutableArray<string>));
Assert.True(tuple8WithoutNames.IsTupleType);
Assert.Equal("(System.Int32, System.String, System.Int32, System.String, System.Int32, System.String, System.Int32, System.String)",
tuple8WithoutNames.ToTestDisplayString());
Assert.False(((TupleTypeSymbol)tuple8WithoutNames).HasFriendlyNames);
Assert.True(tuple8WithoutNames.TupleElementNames.IsDefault);
Assert.Equal(new[] { "System.Int32", "System.String", "System.Int32", "System.String", "System.Int32", "System.String", "System.Int32", "System.String" },
tuple8WithoutNames.TupleElementTypes.Select(t => t.ToTestDisplayString()));
}
[Fact]
public void CreateTupleTypeSymbol_Tuple8WithNames()
{
var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef }); // no ValueTuple
ITypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32);
ITypeSymbol stringType = comp.GetSpecialType(SpecialType.System_String);
var tuple8WithNames = comp.CreateTupleTypeSymbol(ImmutableArray.Create(intType, stringType, intType, stringType, intType, stringType, intType, stringType),
ImmutableArray.Create("Alice1", "Alice2", "Alice3", "Alice4", "Alice5", "Alice6", "Alice7", "Alice8"));
Assert.True(tuple8WithNames.IsTupleType);
Assert.Equal("(System.Int32 Alice1, System.String Alice2, System.Int32 Alice3, System.String Alice4, System.Int32 Alice5, System.String Alice6, System.Int32 Alice7, System.String Alice8)",
tuple8WithNames.ToTestDisplayString());
Assert.True(((TupleTypeSymbol)tuple8WithNames).HasFriendlyNames);
Assert.Equal(new[] { "Alice1", "Alice2", "Alice3", "Alice4", "Alice5", "Alice6", "Alice7", "Alice8" }, tuple8WithNames.TupleElementNames);
Assert.Equal(new[] { "System.Int32", "System.String", "System.Int32", "System.String", "System.Int32", "System.String", "System.Int32", "System.String" },
tuple8WithNames.TupleElementTypes.Select(t => t.ToTestDisplayString()));
}
[Fact]
public void CreateTupleTypeSymbol_Tuple9NoNames()
{
var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef }); // no ValueTuple
ITypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32);
ITypeSymbol stringType = comp.GetSpecialType(SpecialType.System_String);
var tuple9WithoutNames = comp.CreateTupleTypeSymbol(ImmutableArray.Create(intType, stringType, intType, stringType, intType, stringType, intType, stringType, intType),
default(ImmutableArray<string>));
Assert.True(tuple9WithoutNames.IsTupleType);
Assert.Equal("(System.Int32, System.String, System.Int32, System.String, System.Int32, System.String, System.Int32, System.String, System.Int32)",
tuple9WithoutNames.ToTestDisplayString());
Assert.False(((TupleTypeSymbol)tuple9WithoutNames).HasFriendlyNames);
Assert.True(tuple9WithoutNames.TupleElementNames.IsDefault);
Assert.Equal(new[] { "System.Int32", "System.String", "System.Int32", "System.String", "System.Int32", "System.String", "System.Int32", "System.String", "System.Int32" },
tuple9WithoutNames.TupleElementTypes.Select(t => t.ToTestDisplayString()));
}
[Fact]
public void CreateTupleTypeSymbol_Tuple9WithNames()
{
var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef }); // no ValueTuple
ITypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32);
ITypeSymbol stringType = comp.GetSpecialType(SpecialType.System_String);
var tuple9WithNames = comp.CreateTupleTypeSymbol(ImmutableArray.Create(intType, stringType, intType, stringType, intType, stringType, intType, stringType, intType),
ImmutableArray.Create("Alice1", "Alice2", "Alice3", "Alice4", "Alice5", "Alice6", "Alice7", "Alice8", "Alice9"));
Assert.True(tuple9WithNames.IsTupleType);
Assert.Equal("(System.Int32 Alice1, System.String Alice2, System.Int32 Alice3, System.String Alice4, System.Int32 Alice5, System.String Alice6, System.Int32 Alice7, System.String Alice8, System.Int32 Alice9)",
tuple9WithNames.ToTestDisplayString());
Assert.True(((TupleTypeSymbol)tuple9WithNames).HasFriendlyNames);
Assert.Equal(new[] { "Alice1", "Alice2", "Alice3", "Alice4", "Alice5", "Alice6", "Alice7", "Alice8", "Alice9" }, tuple9WithNames.TupleElementNames);
Assert.Equal(new[] { "System.Int32", "System.String", "System.Int32", "System.String", "System.Int32", "System.String", "System.Int32", "System.String", "System.Int32" },
tuple9WithNames.TupleElementTypes.Select(t => t.ToTestDisplayString()));
}
[Fact]
public void CreateTupleTypeSymbol_ElementTypeIsError()
{
var tupleComp = CreateCompilationWithMscorlib(trivial2uple + trivial3uple + trivalRemainingTuples);
var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef, tupleComp.ToMetadataReference() });
ITypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32);
var tupleWithoutNames = comp.CreateTupleTypeSymbol(ImmutableArray.Create(intType, ErrorTypeSymbol.UnknownResultType), default(ImmutableArray<string>));
Assert.Equal(SymbolKind.NamedType, tupleWithoutNames.Kind);
var types = tupleWithoutNames.TupleElementTypes;
Assert.Equal(2, types.Length);
Assert.Equal(SymbolKind.NamedType, types[0].Kind);
Assert.Equal(SymbolKind.ErrorType, types[1].Kind);
}
[Fact]
public void CreateTupleTypeSymbol_BadNames()
{
var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef });
ITypeSymbol intType = comp.GetSpecialType(SpecialType.System_Int32);
// illegal C# identifiers and blank
var tuple2 = comp.CreateTupleTypeSymbol(ImmutableArray.Create(intType, intType), ImmutableArray.Create("123", ""));
Assert.Equal(new[] { "123", "" }, tuple2.TupleElementNames);
// reserved identifiers
var tuple3 = comp.CreateTupleTypeSymbol(ImmutableArray.Create(intType, intType), ImmutableArray.Create("return", "class"));
Assert.Equal(new[] { "return", "class" }, tuple3.TupleElementNames);
}
[Fact]
public void CreateTupleTypeSymbol_VisualBasicElements()
{
var vbSource = @"Public Class C
End Class";
var vbComp = CreateVisualBasicCompilation("VB", vbSource,
compilationOptions: new VisualBasic.VisualBasicCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
vbComp.VerifyDiagnostics();
ITypeSymbol vbType = (ITypeSymbol)vbComp.GlobalNamespace.GetMembers("C").Single();
var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef });
INamedTypeSymbol intType = comp.GetSpecialType(SpecialType.System_String);
Assert.Throws<ArgumentException>(() => comp.CreateTupleTypeSymbol(ImmutableArray.Create(intType, vbType), default(ImmutableArray<string>)));
}
[Fact]
public void TupleMethodsOnNonTupleType()
{
var comp = CSharpCompilation.Create("test", references: new[] { MscorlibRef });
INamedTypeSymbol intType = comp.GetSpecialType(SpecialType.System_String);
Assert.False(intType.IsTupleType);
Assert.True(intType.TupleElementNames.IsDefault);
Assert.True(intType.TupleElementTypes.IsDefault);
}
[Fact]
public void TupleTargetTypeTwice()
{
......@@ -2838,6 +3084,69 @@ static void Main()
);
}
// PROTOTYPE(tuples): this test is for a precedent reference
// it does not test tuples and should be removed or moved to appropriate location
[Fact]
public void InterpolatedConvertedType()
{
var source = @"
class C
{
static void Main()
{
System.IFormattable x = (System.IFormattable)$""qq {1} qq"";
}
}
" + trivial2uple + trivial3uple;
var tree = Parse(source);
var comp = CreateCompilationWithMscorlib(tree);
var model = comp.GetSemanticModel(tree, ignoreAccessibility: false);
var nodes = tree.GetCompilationUnitRoot().DescendantNodes();
var node = nodes.OfType<InterpolatedStringExpressionSyntax>().Single();
Assert.Equal(@"$""qq {1} qq""", node.ToString());
Assert.Equal("System.String", model.GetTypeInfo(node).Type.ToTestDisplayString());
Assert.Equal("System.String", model.GetTypeInfo(node).ConvertedType.ToTestDisplayString());
Assert.Equal(Conversion.Identity, model.GetConversion(node));
Assert.Equal(Conversion.Identity, model.GetConversion(node.Parent));
var x = nodes.OfType<VariableDeclaratorSyntax>().First();
Assert.Equal("System.IFormattable x", model.GetDeclaredSymbol(x).ToTestDisplayString());
}
// PROTOTYPE(tuples): this test is for a precedent reference
// it does not test tuples and should be removed or moved to appropriate location
[Fact]
public void InterpolatedConvertedTypeInSource()
{
var source = @"
class C
{
static void Main()
{
System.IFormattable x = $""qq {1} qq"";
}
}
" + trivial2uple + trivial3uple;
var tree = Parse(source);
var comp = CreateCompilationWithMscorlib(tree);
var model = comp.GetSemanticModel(tree, ignoreAccessibility: false);
var nodes = tree.GetCompilationUnitRoot().DescendantNodes();
var node = nodes.OfType<InterpolatedStringExpressionSyntax>().Single();
Assert.Equal(@"$""qq {1} qq""", node.ToString());
Assert.Equal("System.String", model.GetTypeInfo(node).Type.ToTestDisplayString());
Assert.Equal("System.IFormattable", model.GetTypeInfo(node).ConvertedType.ToTestDisplayString());
Assert.Equal(Conversion.InterpolatedString, model.GetConversion(node));
var x = nodes.OfType<VariableDeclaratorSyntax>().First();
Assert.Equal("System.IFormattable x", model.GetDeclaredSymbol(x).ToTestDisplayString());
}
[Fact]
public void TupleConvertedType01()
{
......@@ -3985,4 +4294,4 @@ static void Main()
}
}
}
\ No newline at end of file
}
......@@ -600,7 +600,6 @@
<Compile Include="Symbols\CommonAttributeDataExtensions.cs" />
<Compile Include="Symbols\CustomModifier.cs" />
<Compile Include="Symbols\IAliasSymbol.cs" />
<Compile Include="Symbols\ITupleTypeSymbol.cs" />
<Compile Include="Symbols\IArrayTypeSymbol.cs" />
<Compile Include="Symbols\IAssemblySymbol.cs" />
<Compile Include="Symbols\IDynamicTypeSymbol.cs" />
......
......@@ -1144,6 +1144,24 @@ internal class CodeAnalysisResources {
}
}
/// <summary>
/// Looks up a localized string similar to If names are used in a tuple type, then there must be a name for every element..
/// </summary>
internal static string TupleNamesAllOrNone {
get {
return ResourceManager.GetString("TupleNamesAllOrNone", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Tuples must have at least two elements..
/// </summary>
internal static string TuplesNeedAtLeastTwoElements {
get {
return ResourceManager.GetString("TuplesNeedAtLeastTwoElements", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to type must be a subclass of SyntaxAnnotation..
/// </summary>
......
......@@ -513,4 +513,10 @@
<value>Exception occurred with following context:
{0}</value>
</data>
<data name="TupleNamesAllOrNone" xml:space="preserve">
<value>If names are used in a tuple type, then there must be a name for every element.</value>
</data>
<data name="TuplesNeedAtLeastTwoElements" xml:space="preserve">
<value>Tuples must have at least two elements.</value>
</data>
</root>
\ No newline at end of file
......@@ -823,6 +823,19 @@ public INamedTypeSymbol GetTypeByMetadataName(string fullyQualifiedMetadataName)
protected abstract INamedTypeSymbol CommonGetTypeByMetadataName(string metadataName);
/// <summary>
/// Returns a new INamedTypeSymbol with the given element types and (optional) element names.
/// </summary>
/// <remarks>
/// Since VB doesn't support tuples yet, this call will fail in a VB compilation.
/// </remarks>
public INamedTypeSymbol CreateTupleTypeSymbol(ImmutableArray<ITypeSymbol> elementTypes, ImmutableArray<string> elementNames = default(ImmutableArray<string>))
{
return CommonCreateTupleTypeSymbol(elementTypes, elementNames);
}
protected abstract INamedTypeSymbol CommonCreateTupleTypeSymbol(ImmutableArray<ITypeSymbol> elementTypes, ImmutableArray<string> elementNames);
#endregion
#region Diagnostics
......
......@@ -134,5 +134,20 @@ public interface INamedTypeSymbol : ITypeSymbol
/// If false, the symbol does not contain extension methods.
/// </summary>
bool MightContainExtensionMethods { get; }
/// <summary>
/// Returns the types of the elements for types that are tuples.
///
/// If this type is not a tuple, then returns default.
/// </summary>
ImmutableArray<ITypeSymbol> TupleElementTypes { get; }
/// <summary>
/// Returns the friendly-names of the elements for types that are tuples and that have friendly-names.
///
/// If this type is not a tuple, then returns default.
/// If this type has no friendly-names, then returns default.
/// </summary>
ImmutableArray<string> TupleElementNames { get; }
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Immutable;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis
{
/// <summary>
/// Represents a tuple.
/// </summary>
/// <remarks>
/// This interface is reserved for implementation by its associated APIs. We reserve the right to
/// change it in the future.
/// </remarks>
public interface ITupleTypeSymbol : ITypeSymbol
{
// not sure what will be here.
// "UnderlyingType" ?
}
}
......@@ -2599,6 +2599,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return CreateArrayTypeSymbol(elementType.EnsureVbSymbolOrNothing(Of TypeSymbol)(NameOf(elementType)), rank)
End Function
Protected Overrides Function CommonCreateTupleTypeSymbol(elementTypes As ImmutableArray(Of ITypeSymbol), elementNames As ImmutableArray(Of String)) As INamedTypeSymbol
Throw New NotSupportedException(VBResources.TuplesNotSupported)
End Function
Protected Overrides Function CommonCreatePointerTypeSymbol(elementType As ITypeSymbol) As IPointerTypeSymbol
Throw New NotSupportedException(VBResources.ThereAreNoPointerTypesInVB)
End Function
......
......@@ -1201,6 +1201,18 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
End Get
End Property
Public ReadOnly Property TupleElementTypes As ImmutableArray(Of ITypeSymbol) Implements INamedTypeSymbol.TupleElementTypes
Get
Return Nothing
End Get
End Property
Public ReadOnly Property TupleElementNames As ImmutableArray(Of String) Implements INamedTypeSymbol.TupleElementNames
Get
Return Nothing
End Get
End Property
Public Overrides Sub Accept(visitor As SymbolVisitor)
visitor.VisitNamedType(Me)
End Sub
......
......@@ -12252,6 +12252,15 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
End Get
End Property
'''<summary>
''' Looks up a localized string similar to Tuples are not supported in VB..
'''</summary>
Friend ReadOnly Property TuplesNotSupported() As String
Get
Return ResourceManager.GetString("TuplesNotSupported", resourceCulture)
End Get
End Property
'''<summary>
''' Looks up a localized string similar to Type argument cannot be Nothing.
'''</summary>
......
......@@ -5358,4 +5358,7 @@
<data name="ERR_PeWritingFailure" xml:space="preserve">
<value>An error occurred while writing the output file: {0}</value>
</data>
</root>
<data name="TuplesNotSupported" xml:space="preserve">
<value>Tuples are not supported in VB.</value>
</data>
</root>
\ No newline at end of file
......@@ -1205,6 +1205,13 @@ BC2014: the value '_' is invalid for option 'RootNamespace'
Assert.Throws(Of NotSupportedException)(Function() compilation.CreatePointerTypeSymbol(Nothing))
End Sub
<Fact()>
<Trait(Traits.Feature, Traits.Features.Tuples)>
Public Sub TuplesNotSupported()
Dim compilation = VisualBasicCompilation.Create("HelloWorld")
Assert.Throws(Of NotSupportedException)(Function() compilation.CreateTupleTypeSymbol(New ImmutableArray(Of ITypeSymbol), New ImmutableArray(Of String)))
End Sub
<Fact()>
Public Sub GetEntryPoint_Exe()
Dim source = <compilation name="Name1">
......
......@@ -45,6 +45,26 @@ End Structure
CompilationUtils.AssertNoDeclarationDiagnostics(compilation)
End Sub
<Fact>
<Trait(Traits.Feature, Traits.Features.Tuples)>
Public Sub TupleAPIs()
Dim compilation = CompilationUtils.CreateCompilationWithMscorlib(
<compilation name="AAA">
<file name="a.vb">
Public Class C
Shared ch1 as C
End Class
</file>
</compilation>)
Dim globalNS = compilation.SourceModule.GlobalNamespace
Dim structC = DirectCast(globalNS.GetMembers().Single(), NamedTypeSymbol)
Dim field = DirectCast(structC.GetMembers()(1), FieldSymbol)
Dim fieldType = DirectCast(field.Type, INamedTypeSymbol)
Assert.False(fieldType.IsTupleType)
Assert.True(fieldType.TupleElementTypes.IsDefault)
Assert.True(fieldType.TupleElementNames.IsDefault)
End Sub
<Fact>
Public Sub Fields1()
......
......@@ -1255,5 +1255,89 @@ public int I
}
", options: Option(SimplificationOptions.QualifyFieldAccess, true));
}
[Fact, Trait(Traits.Feature, Traits.Features.EncapsulateField), Trait(Traits.Feature, Test.Utilities.Traits.Features.Tuples)]
public async Task Tuple()
{
var text = @"
class C
{
private (int, string) b[|o|]b;
void M()
{
var q = bob;
}
}
";
var expected = @"
class C
{
private (int, string) bob;
public (int, string) Bob
{
get
{
return bob;
}
set
{
bob = value;
}
}
void M()
{
var q = bob;
}
}
";
await TestAsync(text, expected, compareTokens: false, index: 1, parseOptions: TestOptions.Regular.WithTuplesFeature());
}
[Fact, Trait(Traits.Feature, Traits.Features.EncapsulateField), Trait(Traits.Feature, Test.Utilities.Traits.Features.Tuples)]
public async Task TupleWithNames()
{
var text = @"
class C
{
private (int a, string b) b[|o|]b;
void M()
{
var q = bob.b;
}
}
";
var expected = @"
class C
{
private (int a, string b) bob;
public (int a, string b) Bob
{
get
{
return bob;
}
set
{
bob = value;
}
}
void M()
{
var q = bob.b;
}
}
";
await TestAsync(text, expected, compareTokens: false, index: 1, parseOptions: TestOptions.Regular.WithTuplesFeature());
}
}
}
......@@ -2,6 +2,7 @@
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp.CodeRefactorings.ExtractMethod;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
......@@ -433,5 +434,55 @@ private static void NewMethod(out Construct obj1, out Construct obj2, out Constr
compareTokens: false);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsExtractMethod), Trait(Traits.Feature, Test.Utilities.Traits.Features.Tuples)]
public async Task TestTuple()
{
await TestAsync(
@"class Program { static void Main ( string [ ] args ) { [| (int, int) x = (1, 2); |] System . Console . WriteLine ( x.Item1 ); } } ",
@"class Program { static void Main ( string [ ] args ) { (int, int) x = {|Rename:NewMethod|}(); System.Console.WriteLine(x.Item1); } private static (int, int) NewMethod() { return (1, 2); } }",
index: 0,
parseOptions: TestOptions.Regular.WithTuplesFeature());
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsExtractMethod), Trait(Traits.Feature, Test.Utilities.Traits.Features.Tuples)]
public async Task TestTupleDeclarationWithNames()
{
await TestAsync(
@"class Program { static void Main ( string [ ] args ) { [| (int a, int b) x = (1, 2); |] System . Console . WriteLine ( x.a ); } } ",
@"class Program { static void Main ( string [ ] args ) { (int a, int b) x = {|Rename:NewMethod|}(); System.Console.WriteLine(x.a); } private static (int a, int b) NewMethod() { return (1, 2); } }",
index: 0,
parseOptions: TestOptions.Regular.WithTuplesFeature());
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsExtractMethod), Trait(Traits.Feature, Test.Utilities.Traits.Features.Tuples)]
public async Task TestTupleLiteralWithNames()
{
await TestAsync(
@"class Program { static void Main ( string [ ] args ) { [| (int, int) x = (a: 1, b: 2); |] System . Console . WriteLine ( x.Item1 ); } } ",
@"class Program { static void Main ( string [ ] args ) { (int, int) x = {|Rename:NewMethod|}(); System.Console.WriteLine(x.Item1); } private static (int, int) NewMethod() { return (a: 1, b: 2); } }",
index: 0,
parseOptions: TestOptions.Regular.WithTuplesFeature());
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsExtractMethod), Trait(Traits.Feature, Test.Utilities.Traits.Features.Tuples)]
public async Task TestTupleDeclarationAndLiteralWithNames()
{
await TestAsync(
@"class Program { static void Main ( string [ ] args ) { [| (int a, int b) x = (c: 1, d: 2); |] System . Console . WriteLine ( x.a ); } } ",
@"class Program { static void Main ( string [ ] args ) { (int a, int b) x = {|Rename:NewMethod|}(); System.Console.WriteLine(x.a); } private static (int a, int b) NewMethod() { return (c: 1, d: 2); } }",
index: 0,
parseOptions: TestOptions.Regular.WithTuplesFeature());
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsExtractMethod), Trait(Traits.Feature, Test.Utilities.Traits.Features.Tuples)]
public async Task TestTupleIntoVar()
{
await TestAsync(
@"class Program { static void Main ( string [ ] args ) { [| var x = (c: 1, d: 2); |] System . Console . WriteLine ( x.c ); } } ",
@"class Program { static void Main ( string [ ] args ) { (int c, int d) x = {|Rename:NewMethod|}(); System.Console.WriteLine(x.c); } private static (int c, int d) NewMethod() { return (c: 1, d: 2); } }",
index: 0,
parseOptions: TestOptions.Regular.WithTuplesFeature());
}
}
}
\ No newline at end of file
......@@ -3,6 +3,7 @@
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeGeneration;
using Microsoft.CodeAnalysis.CSharp.CodeRefactorings.GenerateDefaultConstructors;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Test.Utilities;
......@@ -198,5 +199,25 @@ public async Task TestException4()
@"using System ; using System . Collections . Generic ; using System . Linq ; class Program : Exception { public Program ( ) { } public Program ( ) { } public Program ( string message ) : base ( message ) { } public Program ( string message , Exception innerException ) : base ( message , innerException ) { } protected Program ( System . Runtime . Serialization . SerializationInfo info , System . Runtime . Serialization . StreamingContext context ) : base ( info , context ) { } static void Main ( string [ ] args ) { } } ",
index: 2);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateDefaultConstructors), Trait(Traits.Feature, Test.Utilities.Traits.Features.Tuples)]
public async Task Tuple()
{
await TestAsync(
@"class C : [||]B { } class B { public B((int, string) x) { } }",
@"class C : B { public C((int, string) x) : base(x) { } } class B { public B((int, string) x) { } }",
index: 0,
parseOptions: TestOptions.Regular.WithTuplesFeature());
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateDefaultConstructors), Trait(Traits.Feature, Test.Utilities.Traits.Features.Tuples)]
public async Task TupleWithNames()
{
await TestAsync(
@"class C : [||]B { } class B { public B((int a, string b) x) { } }",
@"class C : B { public C((int a, string b) x) : base(x) { } } class B { public B((int a, string b) x) { } }",
index: 0,
parseOptions: TestOptions.Regular.WithTuplesFeature());
}
}
}
......@@ -3,6 +3,7 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp.CodeRefactorings.GenerateFromMembers.GenerateConstructor;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Simplification;
using Roslyn.Test.Utilities;
......@@ -180,5 +181,16 @@ public async Task TestGenerateConstructorNotOfferedForDuplicate()
await TestMissingAsync(
"using System ; class X { public X ( string v ) { } static void Test ( ) { new X ( new [|string|] ( ) ) ; } } ");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructor)]
public async Task Tuple()
{
await TestAsync(
@"using System . Collections . Generic ; class Z { [|(int, string) a ;|] } ",
@"using System . Collections . Generic ; class Z { (int, string) a ; public Z ( (int, string) a ) { this . a = a ; } } ",
index: 0,
parseOptions: TestOptions.Regular.WithTuplesFeature());
}
}
}
......@@ -6,6 +6,7 @@
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.CodeFixes.ImplementInterface;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces;
using Roslyn.Test.Utilities;
......@@ -2689,5 +2690,15 @@ public async Task TestImplementInterfaceThroughStaticMemberInGenericClass()
@"using System ; using System . Collections ; using System . Collections . Generic ; using System . Linq ; using System . Threading . Tasks ; class Issue2785 < T > : IList < object > { private static List < object > innerList = new List < object > ( ) ; public object this [ int index ] { get { return ( ( IList < object > ) innerList ) [ index ] ; } set { ( ( IList < object > ) innerList ) [ index ] = value ; } } public int Count { get { return ( ( IList < object > ) innerList ) . Count ; } } public bool IsReadOnly { get { return ( ( IList < object > ) innerList ) . IsReadOnly ; } } public void Add ( object item ) { ( ( IList < object > ) innerList ) . Add ( item ) ; } public void Clear ( ) { ( ( IList < object > ) innerList ) . Clear ( ) ; } public bool Contains ( object item ) { return ( ( IList < object > ) innerList ) . Contains ( item ) ; } public void CopyTo ( object [ ] array , int arrayIndex ) { ( ( IList < object > ) innerList ) . CopyTo ( array , arrayIndex ) ; } public IEnumerator < object > GetEnumerator ( ) { return ( ( IList < object > ) innerList ) . GetEnumerator ( ) ; } public int IndexOf ( object item ) { return ( ( IList < object > ) innerList ) . IndexOf ( item ) ; } public void Insert ( int index , object item ) { ( ( IList < object > ) innerList ) . Insert ( index , item ) ; } public bool Remove ( object item ) { return ( ( IList < object > ) innerList ) . Remove ( item ) ; } public void RemoveAt ( int index ) { ( ( IList < object > ) innerList ) . RemoveAt ( index ) ; } IEnumerator IEnumerable . GetEnumerator ( ) { return ( ( IList < object > ) innerList ) . GetEnumerator ( ) ; } } ",
index: 1);
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsImplementInterface), Trait(Traits.Feature, Test.Utilities.Traits.Features.Tuples)]
public async Task Tuple()
{
await TestAsync(
@"interface IInterface { void Method1 ( ) ; } class Class : [|IInterface|] { (int, string) x; } ",
@"using System; interface IInterface { void Method1 ( ) ; } class Class : IInterface { (int, string) x; public void Method1 ( ) { throw new NotImplementedException ( ) ; } } ",
parseOptions: TestOptions.Regular.WithTuplesFeature());
}
}
}
......@@ -30,7 +30,8 @@ public abstract class AbstractCodeActionOrUserDiagnosticTest
IList<TextSpan> expectedSpans,
SyntaxNode fixedRoot,
string annotationKind,
bool compareTokens)
bool compareTokens,
ParseOptions parseOptions = null)
{
expectedSpans = expectedSpans ?? new List<TextSpan>();
var annotatedTokens = fixedRoot.GetAnnotatedNodesAndTokens(annotationKind).Select(n => (SyntaxToken)n).ToList();
......@@ -39,7 +40,7 @@ public abstract class AbstractCodeActionOrUserDiagnosticTest
if (expectedSpans.Count > 0)
{
var expectedTokens = TokenUtilities.GetTokens(TokenUtilities.GetSyntaxRoot(expectedText, GetLanguage()));
var expectedTokens = TokenUtilities.GetTokens(TokenUtilities.GetSyntaxRoot(expectedText, GetLanguage(), parseOptions));
var actualTokens = TokenUtilities.GetTokens(fixedRoot);
for (var i = 0; i < Math.Min(expectedTokens.Count, actualTokens.Count); i++)
......@@ -193,7 +194,8 @@ public abstract class AbstractCodeActionOrUserDiagnosticTest
workspace, expected, index,
actions,
conflictSpans, renameSpans, warningSpans,
compareTokens: compareTokens);
compareTokens: compareTokens,
parseOptions: parseOptions);
}
}
......@@ -201,10 +203,11 @@ public abstract class AbstractCodeActionOrUserDiagnosticTest
TestWorkspace workspace, string expected,
int index, IList<CodeAction> actions,
IList<TextSpan> conflictSpans, IList<TextSpan> renameSpans, IList<TextSpan> warningSpans,
bool compareTokens)
bool compareTokens,
ParseOptions parseOptions = null)
{
var operations = await VerifyInputsAndGetOperationsAsync(index, actions);
return await TestOperationsAsync(workspace, expected, operations.ToList(), conflictSpans, renameSpans, warningSpans, compareTokens, expectedChangedDocumentId: null);
return await TestOperationsAsync(workspace, expected, operations.ToList(), conflictSpans, renameSpans, warningSpans, compareTokens, expectedChangedDocumentId: null, parseOptions: parseOptions);
}
private static bool IsWorkspaceElement(string text)
......@@ -220,7 +223,8 @@ private static bool IsWorkspaceElement(string text)
IList<TextSpan> renameSpans,
IList<TextSpan> warningSpans,
bool compareTokens,
DocumentId expectedChangedDocumentId)
DocumentId expectedChangedDocumentId,
ParseOptions parseOptions = null)
{
var appliedChanges = ApplyOperationsAndGetSolution(workspace, operations);
var oldSolution = appliedChanges.Item1;
......@@ -246,9 +250,9 @@ private static bool IsWorkspaceElement(string text)
Assert.Equal(expectedText, actualText);
}
TestAnnotations(expectedText, conflictSpans, fixedRoot, ConflictAnnotation.Kind, compareTokens);
TestAnnotations(expectedText, renameSpans, fixedRoot, RenameAnnotation.Kind, compareTokens);
TestAnnotations(expectedText, warningSpans, fixedRoot, WarningAnnotation.Kind, compareTokens);
TestAnnotations(expectedText, conflictSpans, fixedRoot, ConflictAnnotation.Kind, compareTokens, parseOptions);
TestAnnotations(expectedText, renameSpans, fixedRoot, RenameAnnotation.Kind, compareTokens, parseOptions);
TestAnnotations(expectedText, warningSpans, fixedRoot, WarningAnnotation.Kind, compareTokens, parseOptions);
return Tuple.Create(oldSolution, newSolution);
}
......
......@@ -243,13 +243,11 @@ public bool IsAnonymousType
}
}
public bool IsTupleType
{
get
{
return _symbol.IsTupleType;
}
}
public bool IsTupleType => _symbol.IsTupleType;
public ImmutableArray<ITypeSymbol> TupleElementTypes => _symbol.TupleElementTypes;
public ImmutableArray<string> TupleElementNames => _symbol.TupleElementNames;
ITypeSymbol ITypeSymbol.OriginalDefinition
{
......
......@@ -18,6 +18,7 @@ public static class Features
public const string Diagnostics = nameof(Diagnostics);
public const string Formatting = nameof(Formatting);
public const string LinkedFileDiffMerging = nameof(LinkedFileDiffMerging);
public const string Tuples = nameof(Tuples);
}
public const string Environment = nameof(Environment);
......
......@@ -78,15 +78,15 @@ public static IList<SyntaxToken> GetTokens(SyntaxNode node)
}
}
internal static SyntaxNode GetSyntaxRoot(string expectedText, string language)
internal static SyntaxNode GetSyntaxRoot(string expectedText, string language, ParseOptions options = null)
{
if (language == LanguageNames.CSharp)
{
return CS.SyntaxFactory.ParseCompilationUnit(expectedText);
return CS.SyntaxFactory.ParseCompilationUnit(expectedText, options: (CS.CSharpParseOptions)options);
}
else
{
return VB.SyntaxFactory.ParseCompilationUnit(expectedText);
return VB.SyntaxFactory.ParseCompilationUnit(expectedText, options: (VB.VisualBasicParseOptions)options);
}
}
}
......
......@@ -2,14 +2,11 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Simplification;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.CSharp.Extensions
{
......@@ -110,6 +107,11 @@ public TypeSyntax CreateSimpleTypeSyntax(INamedTypeSymbol symbol)
return SyntaxFactory.QualifiedName(SyntaxFactory.IdentifierName("System"), SyntaxFactory.IdentifierName("String"));
}
if (symbol.IsTupleType)
{
return CreateTupleTypeSyntax(symbol);
}
if (symbol.Name == string.Empty || symbol.IsAnonymousType)
{
return SyntaxFactory.QualifiedName(SyntaxFactory.IdentifierName("System"), SyntaxFactory.IdentifierName("Object"));
......@@ -145,6 +147,22 @@ public TypeSyntax CreateSimpleTypeSyntax(INamedTypeSymbol symbol)
SyntaxFactory.TypeArgumentList(SyntaxFactory.SeparatedList(typeArguments)));
}
private TupleTypeSyntax CreateTupleTypeSyntax(INamedTypeSymbol symbol)
{
var list = new SeparatedSyntaxList<TupleElementSyntax>();
var types = symbol.TupleElementTypes;
var names = symbol.TupleElementNames;
bool hasNames = !names.IsDefault;
for (int i = 0; i < types.Length; i++)
{
var name = hasNames ? SyntaxFactory.IdentifierName(names[i]) : null;
list = list.Add(SyntaxFactory.TupleElement(GenerateTypeSyntax(types[i]), name));
}
return SyntaxFactory.TupleType(list);
}
public override TypeSyntax VisitNamedType(INamedTypeSymbol symbol)
{
var typeSyntax = CreateSimpleTypeSyntax(symbol);
......
......@@ -74,13 +74,11 @@ public bool IsAnonymousType
}
}
public bool IsTupleType
{
get
{
return false;
}
}
public bool IsTupleType => false;
public ImmutableArray<ITypeSymbol> TupleElementTypes => default(ImmutableArray<ITypeSymbol>);
public ImmutableArray<string> TupleElementNames => default(ImmutableArray<string>);
public new ITypeSymbol OriginalDefinition
{
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis
{
internal abstract partial class SymbolKey
{
private class TupleTypeSymbolKey : AbstractSymbolKey<TupleTypeSymbolKey>
{
private readonly SymbolKey[] _types;
private readonly string[] _names;
internal TupleTypeSymbolKey(INamedTypeSymbol symbol, Visitor visitor)
{
Debug.Assert(symbol.IsTupleType);
_types = symbol.TupleElementTypes.Select(t => GetOrCreate(t, visitor)).ToArray();
_names = symbol.TupleElementNames.IsDefault ? null : symbol.TupleElementNames.ToArray();
}
public override SymbolKeyResolution Resolve(Compilation compilation, bool ignoreAssemblyKey, CancellationToken cancellationToken)
{
return CreateSymbolInfo(Resolve(compilation, ignoreAssemblyKey));
}
private IEnumerable<INamedTypeSymbol> Resolve(
Compilation compilation,
bool ignoreAssemblyKey)
{
// We need all types to have a resolution and we ignore ambiguous candidates
ITypeSymbol[] types = _types.Select(a => a.Resolve(compilation, ignoreAssemblyKey).Symbol as ITypeSymbol).ToArray();
if (types.Any(a => a == null))
{
return SpecializedCollections.EmptyEnumerable<INamedTypeSymbol>();
}
if (_names == null)
{
return SpecializedCollections.SingletonEnumerable(compilation.CreateTupleTypeSymbol(types.ToImmutableArray()));
}
else
{
return SpecializedCollections.SingletonEnumerable(compilation.CreateTupleTypeSymbol(types.ToImmutableArray(), _names.ToImmutableArray()));
}
}
internal override bool Equals(TupleTypeSymbolKey other, ComparisonOptions options)
{
var comparer = SymbolKeyComparer.GetComparer(options);
return SequenceEquals(other._types, _types, comparer)
&& SequenceEquals(other._names, _names, StringComparer.Ordinal);
}
internal override int GetHashCode(ComparisonOptions options)
{
// Types are good enough for hash code, we don't need to include names.
return Hash.CombineValues(_types);
}
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis
{
......@@ -71,9 +67,17 @@ public override SymbolKey VisitModule(IModuleSymbol moduleSymbol)
public override SymbolKey VisitNamedType(INamedTypeSymbol namedTypeSymbol)
{
return namedTypeSymbol.TypeKind == TypeKind.Error
? new ErrorTypeSymbolKey(namedTypeSymbol, this)
: (SymbolKey)new NamedTypeSymbolKey(namedTypeSymbol, this);
if (namedTypeSymbol.TypeKind == TypeKind.Error)
{
return new ErrorTypeSymbolKey(namedTypeSymbol, this);
}
if (namedTypeSymbol.IsTupleType)
{
return new TupleTypeSymbolKey(namedTypeSymbol, this);
}
return new NamedTypeSymbolKey(namedTypeSymbol, this);
}
public override SymbolKey VisitNamespace(INamespaceSymbol namespaceSymbol)
......
......@@ -398,6 +398,7 @@
<Compile Include="Packaging\IPackageSearchService.cs" />
<Compile Include="FindSymbols\SymbolTree\ISymbolTreeInfoCacheService.cs" />
<Compile Include="FindSymbols\FindReferences\MetadataUnifyingEquivalenceComparer.cs" />
<Compile Include="SymbolId\SymbolKey.TupleTypeSymbolKey.cs" />
<Compile Include="Utilities\ArraySlice.cs" />
<Compile Include="Utilities\BKTree.cs" />
<Compile Include="FindSymbols\SyntaxTree\AbstractSyntaxTreeInfo.cs" />
......@@ -978,4 +979,4 @@
<ImportGroup Label="Targets">
<Import Project="..\..\..\..\build\Targets\VSL.Imports.targets" />
</ImportGroup>
</Project>
</Project>
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册