提交 756c5c08 编写于 作者: V VSadov

IsImplicitlyDeclared in tuple fields.

上级 68e7b737
......@@ -26,7 +26,11 @@ internal sealed class TupleErrorFieldSymbol : SynthesizedFieldSymbolBase
private readonly ImmutableArray<Location> _locations;
private readonly DiagnosticInfo _useSiteDiagnosticInfo;
public TupleErrorFieldSymbol(NamedTypeSymbol container, string name, int tupleElementIndex, Location location, TypeSymbol type, DiagnosticInfo useSiteDiagnosticInfo)
// default tuple elements like Item1 or Item20 could be provided by the user or
// otherwise implicitly declared by compiler
private readonly bool _isImplicitlyDeclared;
public TupleErrorFieldSymbol(NamedTypeSymbol container, string name, int tupleElementIndex, Location location, TypeSymbol type, DiagnosticInfo useSiteDiagnosticInfo, bool isImplicitlyDeclared)
: base(container, name, isPublic:true, isReadOnly:false, isStatic:false)
{
Debug.Assert(name != null);
......@@ -34,6 +38,7 @@ public TupleErrorFieldSymbol(NamedTypeSymbol container, string name, int tupleEl
_locations = location == null ? ImmutableArray<Location>.Empty : ImmutableArray.Create(location);
_useSiteDiagnosticInfo = useSiteDiagnosticInfo;
_tupleElementIndex = tupleElementIndex;
_isImplicitlyDeclared = isImplicitlyDeclared;
}
public override bool IsTupleField
......@@ -92,7 +97,9 @@ public override ImmutableArray<SyntaxReference> DeclaringSyntaxReferences
{
get
{
return GetDeclaringSyntaxReferenceHelper<CSharpSyntaxNode>(_locations);
return _isImplicitlyDeclared ?
ImmutableArray<SyntaxReference>.Empty :
GetDeclaringSyntaxReferenceHelper<CSharpSyntaxNode>(_locations);
}
}
......@@ -100,7 +107,7 @@ public override bool IsImplicitlyDeclared
{
get
{
return false;
return _isImplicitlyDeclared;
}
}
......
......@@ -147,10 +147,15 @@ internal class TupleElementFieldSymbol : TupleFieldSymbol
{
private readonly ImmutableArray<Location> _locations;
public TupleElementFieldSymbol(TupleTypeSymbol container, FieldSymbol underlyingField, int tupleElementIndex, Location location)
// default tuple elements like Item1 or Item20 could be provided by the user or
// otherwise implicitly declared by compiler
private readonly bool _isImplicitlyDeclared;
public TupleElementFieldSymbol(TupleTypeSymbol container, FieldSymbol underlyingField, int tupleElementIndex, Location location, bool isImplicitlyDeclared)
: base(container, underlyingField, tupleElementIndex)
{
_locations = location == null ? ImmutableArray<Location>.Empty : ImmutableArray.Create(location);
_isImplicitlyDeclared = isImplicitlyDeclared;
}
public override ImmutableArray<Location> Locations
......@@ -165,7 +170,9 @@ public override ImmutableArray<SyntaxReference> DeclaringSyntaxReferences
{
get
{
return GetDeclaringSyntaxReferenceHelper<CSharpSyntaxNode>(_locations);
return _isImplicitlyDeclared ?
ImmutableArray<SyntaxReference>.Empty :
GetDeclaringSyntaxReferenceHelper<CSharpSyntaxNode>(_locations);
}
}
......@@ -173,7 +180,7 @@ public override bool IsImplicitlyDeclared
{
get
{
return false;
return _isImplicitlyDeclared;
}
}
......@@ -223,8 +230,8 @@ internal sealed class TupleVirtualElementFieldSymbol : TupleElementFieldSymbol
{
private readonly string _name;
public TupleVirtualElementFieldSymbol(TupleTypeSymbol container, FieldSymbol underlyingField, string name, int tupleElementIndex, Location location)
: base(container, underlyingField, tupleElementIndex, location)
public TupleVirtualElementFieldSymbol(TupleTypeSymbol container, FieldSymbol underlyingField, string name, int tupleElementIndex, Location location, bool isImplicitlyDeclared)
: base(container, underlyingField, tupleElementIndex, location, isImplicitlyDeclared)
{
Debug.Assert(name != null);
Debug.Assert(name != underlyingField.Name || !container.UnderlyingNamedType.Equals(underlyingField.ContainingType, TypeCompareKind.IgnoreDynamicAndTupleNames),
......
......@@ -820,7 +820,9 @@ private ImmutableArray<Symbol> CreateMembers()
var providedName = _elementNames.IsDefault ? null : _elementNames[tupleFieldIndex];
var location = _elementLocations.IsDefault ? null : _elementLocations[tupleFieldIndex];
var defaultName = TupleMemberName(tupleFieldIndex + 1);
var providedIsNotDefault = providedName != defaultName;
// if provided name does not match the default one,
// then default element as declared implicitly
var defaultImplicitlyDeclared = providedName != defaultName;
var fieldSymbol = field.AsMember(currentUnderlying);
......@@ -831,29 +833,29 @@ private ImmutableArray<Symbol> CreateMembers()
// Add a field with default name. It should be present regardless.
// Make it virtual since we are not at the top level
// tupleFieldIndex << 1 because this is a default element
members.Add(new TupleVirtualElementFieldSymbol(this, fieldSymbol, defaultName, tupleFieldIndex << 1, location));
members.Add(new TupleVirtualElementFieldSymbol(this, fieldSymbol, defaultName, tupleFieldIndex << 1, location, defaultImplicitlyDeclared));
if (providedIsNotDefault && providedName != null)
if (defaultImplicitlyDeclared && providedName != null)
{
// The name given doesn't match default name Item8, etc.
// Add a field with the given name
// tupleFieldIndex << 1 + 1, because this is not a default element
members.Add(new TupleVirtualElementFieldSymbol(this, fieldSymbol, providedName, (tupleFieldIndex << 1) + 1, location));
members.Add(new TupleVirtualElementFieldSymbol(this, fieldSymbol, providedName, (tupleFieldIndex << 1) + 1, location, isImplicitlyDeclared: false));
}
}
else if (providedIsNotDefault)
else if (defaultImplicitlyDeclared)
{
Debug.Assert(fieldSymbol.Name == defaultName, "top level underlying field must match default name");
// Add the underlying field as an element. It should have the default name.
// tupleFieldIndex << 1 because this is a default element
members.Add(new TupleElementFieldSymbol(this, fieldSymbol, tupleFieldIndex << 1, location));
members.Add(new TupleElementFieldSymbol(this, fieldSymbol, tupleFieldIndex << 1, location, defaultImplicitlyDeclared));
if (providedName != null)
{
// Add a field with the given name
// tupleFieldIndex << 1 + 1, because this is not a default element
members.Add(new TupleVirtualElementFieldSymbol(this, fieldSymbol, providedName, (tupleFieldIndex << 1) + 1, location));
members.Add(new TupleVirtualElementFieldSymbol(this, fieldSymbol, providedName, (tupleFieldIndex << 1) + 1, location, isImplicitlyDeclared: false));
}
}
else
......@@ -861,7 +863,7 @@ private ImmutableArray<Symbol> CreateMembers()
Debug.Assert(fieldSymbol.Name == defaultName, "top level underlying field must match default name");
// tupleFieldIndex << 1 because this is a default element
members.Add(new TupleElementFieldSymbol(this, fieldSymbol, tupleFieldIndex << 1, location));
members.Add(new TupleElementFieldSymbol(this, fieldSymbol, tupleFieldIndex << 1, location, isImplicitlyDeclared: false));
}
elementsMatchedByFields[tupleFieldIndex] = true; // mark as handled
......@@ -944,18 +946,20 @@ private ImmutableArray<Symbol> CreateMembers()
var providedName = _elementNames.IsDefault ? null : _elementNames[i];
var location = _elementLocations.IsDefault ? null : _elementLocations[i];
var defaultName = TupleMemberName(i + 1);
var providedIsNotDefault = providedName != defaultName;
// if provided name does not match the default one,
// then default element as declared implicitly
var defaultImplicitlyDeclared = providedName != defaultName;
// Add default element field.
// i << 1 because this is a default element
members.Add(new TupleErrorFieldSymbol(this, defaultName, i << 1, providedIsNotDefault ? null: location, _elementTypes[i], diagnosticInfo));
members.Add(new TupleErrorFieldSymbol(this, defaultName, i << 1, defaultImplicitlyDeclared ? null: location, _elementTypes[i], diagnosticInfo, defaultImplicitlyDeclared));
if (providedIsNotDefault && providedName != null)
if (defaultImplicitlyDeclared && providedName != null)
{
// Add frieldly named element field.
// (i << 1) + 1, because this is not a default element
members.Add(new TupleErrorFieldSymbol(this, providedName, (i << 1) + 1, location, _elementTypes[i], diagnosticInfo));
members.Add(new TupleErrorFieldSymbol(this, providedName, (i << 1) + 1, location, _elementTypes[i], diagnosticInfo, isImplicitlyDeclared: false));
}
}
}
......
......@@ -3292,7 +3292,7 @@ static void Main()
Assert.True(mItem1.GetAttributes().IsEmpty);
Assert.Null(mItem1.GetUseSiteDiagnostic());
Assert.True(mItem1.Locations.IsEmpty);
Assert.False(mItem1.IsImplicitlyDeclared);
Assert.True(mItem1.IsImplicitlyDeclared);
Assert.Null(mItem1.TypeLayoutOffset);
}
......@@ -3967,8 +3967,8 @@ public ValueTuple(T1 item1, T2 item2)
Assert.Equal("error CS8128: Member 'Item1' was not found on type 'ValueTuple<T1, T2>' from assembly 'comp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'.",
mItem1.GetUseSiteDiagnostic().ToString());
Assert.True(mItem1.Locations.IsDefaultOrEmpty);
Assert.Equal("string", mItem1.DeclaringSyntaxReferences.Single().GetSyntax().ToString());
Assert.False(mItem1.IsImplicitlyDeclared);
Assert.True(mItem1.DeclaringSyntaxReferences.IsDefaultOrEmpty);
Assert.True(mItem1.IsImplicitlyDeclared);
Assert.Null(mItem1.TypeLayoutOffset);
AssertTestDisplayString(mTuple.GetMembers(),
......@@ -8658,9 +8658,9 @@ static void Main()
Assert.True(m1Item1.GetAttributes().IsEmpty);
Assert.Null(m1Item1.GetUseSiteDiagnostic());
Assert.False(m1Item1.Locations.IsDefaultOrEmpty);
Assert.Equal("int", m1Item1.DeclaringSyntaxReferences.Single().GetSyntax().ToString());
Assert.True(m1Item1.DeclaringSyntaxReferences.IsDefaultOrEmpty);
Assert.Equal("Item1", m1Item1.TupleUnderlyingField.Name);
Assert.False(m1Item1.IsImplicitlyDeclared);
Assert.True(m1Item1.IsImplicitlyDeclared);
Assert.Null(m1Item1.TypeLayoutOffset);
Assert.True(m2Item1.IsTupleField);
......@@ -8676,8 +8676,10 @@ static void Main()
Assert.False(m2Item1.Locations.IsDefaultOrEmpty);
Assert.Equal("Item1", m2Item1.Name);
Assert.Equal("Item1", m2Item1.TupleUnderlyingField.Name);
Assert.Equal(m2Item1.Locations.Single(), m2Item1.TupleUnderlyingField.Locations.Single());
Assert.False(m2Item1.IsImplicitlyDeclared);
Assert.NotEqual(m2Item1.Locations.Single(), m2Item1.TupleUnderlyingField.Locations.Single());
Assert.Equal("MetadataFile(System.ValueTuple.dll)", m2Item1.TupleUnderlyingField.Locations.Single().ToString());
Assert.Equal("SourceFile([826..828))", m2Item1.Locations.Single().ToString());
Assert.True(m2Item1.IsImplicitlyDeclared);
Assert.Null(m2Item1.TypeLayoutOffset);
Assert.True(m2a2.IsTupleField);
......@@ -8905,9 +8907,9 @@ static void Main()
Assert.True(m3Item8.GetAttributes().IsEmpty);
Assert.Null(m3Item8.GetUseSiteDiagnostic());
Assert.False(m3Item8.Locations.IsDefaultOrEmpty);
Assert.Equal("int", m3Item8.DeclaringSyntaxReferences.Single().GetSyntax().ToString());
Assert.True(m3Item8.DeclaringSyntaxReferences.IsDefaultOrEmpty);
Assert.Equal("Item1", m3Item8.TupleUnderlyingField.Name);
Assert.False(m3Item8.IsImplicitlyDeclared);
Assert.True(m3Item8.IsImplicitlyDeclared);
Assert.Null(m3Item8.TypeLayoutOffset);
var m3TupleRestTuple = (NamedTypeSymbol)((FieldSymbol)m3Tuple.GetMembers("Rest").Single()).Type;
......@@ -9100,7 +9102,7 @@ static void Main()
Assert.Null(m4Item8.GetUseSiteDiagnostic());
Assert.False(m4Item8.Locations.IsDefaultOrEmpty);
Assert.Equal("Item1", m4Item8.TupleUnderlyingField.Name);
Assert.False(m4Item8.IsImplicitlyDeclared);
Assert.True(m4Item8.IsImplicitlyDeclared);
Assert.Null(m4Item8.TypeLayoutOffset);
var m4h4 = (FieldSymbol)m4Tuple.GetMembers("h4").Single();
......@@ -9719,7 +9721,7 @@ static void Main()
Assert.Null(m8Item8.GetUseSiteDiagnostic());
Assert.False(m8Item8.Locations.IsDefaultOrEmpty);
Assert.Equal("Item1", m8Item8.TupleUnderlyingField.Name);
Assert.False(m8Item8.IsImplicitlyDeclared);
Assert.True(m8Item8.IsImplicitlyDeclared);
Assert.Null(m8Item8.TypeLayoutOffset);
var m8Item1 = (FieldSymbol)m8Tuple.GetMembers("Item1").Last();
......@@ -9918,9 +9920,9 @@ static void Main()
Assert.True(m1Item1.GetAttributes().IsEmpty);
Assert.Null(m1Item1.GetUseSiteDiagnostic());
Assert.False(m1Item1.Locations.IsDefaultOrEmpty);
Assert.Equal("1", m1Item1.DeclaringSyntaxReferences.Single().GetSyntax().ToString());
Assert.True(m1Item1.DeclaringSyntaxReferences.IsDefaultOrEmpty);
Assert.Equal("Item1", m1Item1.TupleUnderlyingField.DeclaringSyntaxReferences.Single().GetSyntax().ToString());
Assert.False(m1Item1.IsImplicitlyDeclared);
Assert.True(m1Item1.IsImplicitlyDeclared);
Assert.Null(m1Item1.TypeLayoutOffset);
Assert.True(m2Item1.IsTupleField);
......@@ -9934,10 +9936,12 @@ static void Main()
Assert.True(m2Item1.GetAttributes().IsEmpty);
Assert.Null(m2Item1.GetUseSiteDiagnostic());
Assert.False(m2Item1.Locations.IsDefaultOrEmpty);
Assert.Equal("a2", m2Item1.DeclaringSyntaxReferences.Single().GetSyntax().ToString());
Assert.True(m2Item1.DeclaringSyntaxReferences.IsDefaultOrEmpty);
Assert.Equal("Item1", m2Item1.TupleUnderlyingField.DeclaringSyntaxReferences.Single().GetSyntax().ToString());
Assert.Equal(m2Item1.Locations.Single(), m2Item1.TupleUnderlyingField.Locations.Single());
Assert.False(m2Item1.IsImplicitlyDeclared);
Assert.NotEqual(m2Item1.Locations.Single(), m2Item1.TupleUnderlyingField.Locations.Single());
Assert.Equal("SourceFile([891..896))", m2Item1.TupleUnderlyingField.Locations.Single().ToString());
Assert.Equal("SourceFile([196..198))", m2Item1.Locations.Single().ToString());
Assert.True(m2Item1.IsImplicitlyDeclared);
Assert.Null(m2Item1.TypeLayoutOffset);
Assert.True(m2a2.IsTupleField);
......
......@@ -208,7 +208,7 @@ private async Task<TriggerIdentifierKind> DetermineIfRenamableSymbolAsync(ISymbo
// Get the source symbol if possible
var sourceSymbol = await SymbolFinder.FindSourceDefinitionAsync(symbol, document.Project.Solution, _cancellationToken).ConfigureAwait(false) ?? symbol;
if (!sourceSymbol.Locations.All(loc => loc.IsInSource))
if (sourceSymbol.IsImplicitlyDeclared || !sourceSymbol.Locations.All(loc => loc.IsInSource))
{
return TriggerIdentifierKind.NotRenamable;
}
......
......@@ -1194,5 +1194,121 @@ void M()
Assert.NotEmpty(await state.GetDocumentDiagnosticsAsync());
}
}
[WpfFact]
[Trait(Traits.Feature, Traits.Features.RenameTracking)]
public async Task RenameImplicitTupleField()
{
var code = @"
class C
{
void M()
{
(int, int) x = (1, 2);
var y = x.Item1$$;
}
}";
using (var state = await RenameTrackingTestState.CreateAsync(code, LanguageNames.CSharp))
{
state.EditorOperations.Backspace();
state.EditorOperations.Backspace();
await state.AssertNoTag();
Assert.Empty(await state.GetDocumentDiagnosticsAsync());
}
}
[WpfFact]
[Trait(Traits.Feature, Traits.Features.RenameTracking)]
public async Task RenameImplicitTupleFieldExtended()
{
var code = @"
class C
{
void M()
{
(int, int, int, int, int, int, int, int, int, int) x = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
var y = x.Item9$$;
}
}
";
using (var state = await RenameTrackingTestState.CreateAsync(code, LanguageNames.CSharp))
{
state.EditorOperations.Backspace();
state.EditorOperations.Backspace();
await state.AssertNoTag();
Assert.Empty(await state.GetDocumentDiagnosticsAsync());
}
}
[WpfFact]
[Trait(Traits.Feature, Traits.Features.RenameTracking)]
public async Task RenameExplicitTupleField()
{
var code = @"
class C
{
void M()
{
(int Item1, int) x = (1, 2);
var y = x.Item1$$;
}
}";
using (var state = await RenameTrackingTestState.CreateAsync(code, LanguageNames.CSharp))
{
state.EditorOperations.Backspace();
state.EditorOperations.Backspace();
await state.AssertTag("Item1", "Ite", invokeAction: true);
// Make sure the rename completed
var expectedCode = @"
class C
{
void M()
{
(int Ite, int) x = (1, 2);
var y = x.Ite;
}
}";
Assert.Equal(expectedCode, state.HostDocument.TextBuffer.CurrentSnapshot.GetText());
await state.AssertNoTag();
}
}
[WpfFact]
[Trait(Traits.Feature, Traits.Features.RenameTracking)]
public async Task RenameExplicitTupleFieldExtended()
{
var code = @"
class C
{
void M()
{
(int, int, int, int, int, int, int, int, int Item9, int) x = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
var y = x.Item9$$;
}
}";
using (var state = await RenameTrackingTestState.CreateAsync(code, LanguageNames.CSharp))
{
state.EditorOperations.Backspace();
state.EditorOperations.Backspace();
await state.AssertTag("Item9", "Ite", invokeAction: true);
// Make sure the rename completed
var expectedCode = @"
class C
{
void M()
{
(int, int, int, int, int, int, int, int, int Ite, int) x = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
var y = x.Ite;
}
}";
Assert.Equal(expectedCode, state.HostDocument.TextBuffer.CurrentSnapshot.GetText());
await state.AssertNoTag();
}
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册