Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/features/partial-properties' i…
Browse files Browse the repository at this point in the history
…nto partial-properties-10
  • Loading branch information
RikkiGibson committed May 31, 2024
2 parents 93fb17a + 8b6bdf2 commit 63e1536
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,34 @@ public partial void M() { }
Assert.Equal(implementation, ResolveSymbol(implementation, comp, SymbolKeyComparison.None));
}

[Fact]
public void ExtendedPartialPropertyDefinitionAndImplementationResolveCorrectly()
{
var src = """
using System;
namespace NS
{
public partial class C1
{
private int x;
public partial int Prop { get; set; }
public partial int Prop { get => x; set => x = value; }
}
}
""";

var comp = (Compilation)CreateCompilation(src, assemblyName: "Test");

var ns = comp.SourceModule.GlobalNamespace.GetMembers("NS").Single() as INamespaceSymbol;
var type = ns.GetTypeMembers("C1").FirstOrDefault();
var definition = type.GetMembers("Prop").First() as IPropertySymbol;
var implementation = definition.PartialImplementationPart;

// Assert that both the definition and implementation resolve back to themselves
Assert.Equal(definition, ResolveSymbol(definition, comp, SymbolKeyComparison.None));
Assert.Equal(implementation, ResolveSymbol(implementation, comp, SymbolKeyComparison.None));
}

[Fact, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/916341")]
public void ExplicitIndexerImplementationResolvesCorrectly()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,19 +73,27 @@ private static ImmutableArray<RoslynNavigationBarItem> GetMembersInTypes(
continue;
}

// https://github.com/dotnet/roslyn/issues/73772: also do this for properties?
var method = member as IMethodSymbol;
if (method != null && method.PartialImplementationPart != null)
if (member is IMethodSymbol { PartialImplementationPart: { } } methodSymbol)
{
memberItems.AddIfNotNull(CreateItemForMember(solution, method, tree, cancellationToken));
memberItems.AddIfNotNull(CreateItemForMember(solution, method.PartialImplementationPart, tree, cancellationToken));
memberItems.AddIfNotNull(CreateItemForMember(solution, methodSymbol, tree, cancellationToken));
memberItems.AddIfNotNull(CreateItemForMember(solution, methodSymbol.PartialImplementationPart, tree, cancellationToken));
}
else
else if (member is IPropertySymbol { PartialImplementationPart: { } } propertySymbol)
{
memberItems.AddIfNotNull(CreateItemForMember(solution, propertySymbol, tree, cancellationToken));
memberItems.AddIfNotNull(CreateItemForMember(solution, propertySymbol.PartialImplementationPart, tree, cancellationToken));
}
else if (member is IMethodSymbol or IPropertySymbol)
{
Debug.Assert(method == null || method.PartialDefinitionPart == null, "NavBar expected GetMembers to return partial method definition parts but the implementation part was returned.");
Debug.Assert(member is IMethodSymbol { PartialDefinitionPart: null } or IPropertySymbol { PartialDefinitionPart: null },
$"NavBar expected GetMembers to return partial method/property definition parts but the implementation part was returned.");

memberItems.AddIfNotNull(CreateItemForMember(solution, member, tree, cancellationToken));
}
else
{
memberItems.AddIfNotNull(CreateItemForMember(solution, member, tree, cancellationToken));
}
}

memberItems.Sort((x, y) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ private IEnumerable<ISymbol> FindMembers(IEnumerable<INamespaceOrTypeSymbol> con
private IEnumerable<ISymbol> FindMembers(IEnumerable<INamedTypeSymbol> types, NameAndArity nameAndArity)
{
// Get the matching members from all types (including constructors and explicit interface
// implementations). If there is a partial method, prefer returning the implementation over
// implementations). If there is a partial method/property, prefer returning the implementation over
// the definition (since the definition will not be a candidate for setting a breakpoint).
var members = types.SelectMany(t => GetMembers(t, nameAndArity.Name))
.Select(s => GetPartialImplementationPartOrNull(s) ?? s);
Expand All @@ -227,9 +227,12 @@ private async Task<IEnumerable<INamedTypeSymbol>> GetAllTypesAsync(CancellationT
return namespaces.GetAllTypes(cancellationToken);
}

// https://github.com/dotnet/roslyn/issues/73772: also do this for properties?
private static IMethodSymbol GetPartialImplementationPartOrNull(ISymbol symbol)
=> (symbol.Kind == SymbolKind.Method) ? ((IMethodSymbol)symbol).PartialImplementationPart : null;
private static ISymbol GetPartialImplementationPartOrNull(ISymbol symbol) => symbol.Kind switch
{
SymbolKind.Method => ((IMethodSymbol)symbol).PartialImplementationPart,
SymbolKind.Property => ((IPropertySymbol)symbol).PartialImplementationPart,
_ => null
};

/// <summary>
/// Is this method or property a valid place to set a breakpoint and does it match the expected parameter count?
Expand Down

0 comments on commit 63e1536

Please sign in to comment.