Skip to content

Commit

Permalink
Merge pull request #62681 from CyrusNajmabadi/symbolKeyContextualType
Browse files Browse the repository at this point in the history
Allow symbol keys to resolve against error symbols.
  • Loading branch information
CyrusNajmabadi authored Jul 18, 2022
2 parents fdedcf5 + b1ac573 commit 027ff7b
Show file tree
Hide file tree
Showing 26 changed files with 1,050 additions and 300 deletions.
408 changes: 408 additions & 0 deletions src/EditorFeatures/CSharpTest/SymbolKey/SymbolKeyErrorTypeTests.cs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#nullable disable

using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Simplification\SimplifierOptions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Simplification\SpecialTypeAnnotation.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Simplification\SymbolAnnotation.cs" />
<Compile Include="$(MSBuildThisFileDirectory)SymbolKey\SymbolKey.AbstractSymbolKey.cs" />
<Compile Include="$(MSBuildThisFileDirectory)SymbolKey\SymbolKey.AliasSymbolKey.cs" />
<Compile Include="$(MSBuildThisFileDirectory)SymbolKey\SymbolKey.AnonymousFunctionOrDelegateSymbolKey.cs" />
<Compile Include="$(MSBuildThisFileDirectory)SymbolKey\SymbolKey.AnonymousTypeSymbolKey.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// 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.

namespace Microsoft.CodeAnalysis
{
internal partial struct SymbolKey
{
private abstract class AbstractSymbolKey<TSymbol>
where TSymbol : class, ISymbol
{
public abstract void Create(TSymbol symbol, SymbolKeyWriter writer);

public SymbolKeyResolution Resolve(SymbolKeyReader reader, out string? failureReason)
=> Resolve(reader, reader.CurrentContextualSymbol as TSymbol, out failureReason);

protected abstract SymbolKeyResolution Resolve(SymbolKeyReader reader, TSymbol? contextualSymbol, out string? failureReason);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,22 @@ namespace Microsoft.CodeAnalysis
{
internal partial struct SymbolKey
{
private static class AliasSymbolKey
private sealed class AliasSymbolKey : AbstractSymbolKey<IAliasSymbol>
{
public static void Create(IAliasSymbol symbol, SymbolKeyWriter visitor)
public static readonly AliasSymbolKey Instance = new();

public sealed override void Create(IAliasSymbol symbol, SymbolKeyWriter visitor)
{
visitor.WriteString(symbol.Name);
visitor.WriteSymbolKey(symbol.Target);
visitor.WriteString(symbol.DeclaringSyntaxReferences.FirstOrDefault()?.SyntaxTree.FilePath ?? "");
}

public static SymbolKeyResolution Resolve(SymbolKeyReader reader, out string? failureReason)
protected sealed override SymbolKeyResolution Resolve(
SymbolKeyReader reader, IAliasSymbol? contextualSymbol, out string? failureReason)
{
var name = reader.ReadRequiredString();
var targetResolution = reader.ReadSymbolKey(out var targetFailureReason);
var targetResolution = reader.ReadSymbolKey(contextualSymbol?.Target, out var targetFailureReason);
var filePath = reader.ReadRequiredString();

if (targetFailureReason != null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,9 @@ public static SymbolKeyResolution Resolve(SymbolKeyReader reader, out string? fa
// If this was a key for an anonymous delegate type, then go find the
// associated delegate for this lambda and return that instead of the
// lambda function symbol itself.
if (isAnonymousDelegateType && symbol != null)
if (isAnonymousDelegateType && symbol is IMethodSymbol methodSymbol)
{
var anonymousDelegate = ((IMethodSymbol)symbol).AssociatedAnonymousDelegate;
var anonymousDelegate = methodSymbol.AssociatedAnonymousDelegate;
symbol = anonymousDelegate;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ namespace Microsoft.CodeAnalysis
{
internal partial struct SymbolKey
{
private static class AnonymousTypeSymbolKey
private sealed class AnonymousTypeSymbolKey : AbstractSymbolKey<INamedTypeSymbol>
{
public static void Create(INamedTypeSymbol symbol, SymbolKeyWriter visitor)
public static readonly AnonymousTypeSymbolKey Instance = new();

public sealed override void Create(INamedTypeSymbol symbol, SymbolKeyWriter visitor)
{
Debug.Assert(symbol.IsAnonymousType);

Expand All @@ -29,13 +31,21 @@ public static void Create(INamedTypeSymbol symbol, SymbolKeyWriter visitor)
visitor.WriteLocationArray(propertyLocations);
}

public static SymbolKeyResolution Resolve(SymbolKeyReader reader, out string? failureReason)
protected sealed override SymbolKeyResolution Resolve(
SymbolKeyReader reader, INamedTypeSymbol? contextualSymbol, out string? failureReason)
{
using var propertyTypes = reader.ReadSymbolKeyArray<ITypeSymbol>(out var propertyTypesFailureReason);
#pragma warning disable IDE0007 // Use implicit type
using PooledArrayBuilder<string> propertyNames = reader.ReadStringArray()!;
#pragma warning restore IDE0007 // Use implicit type
contextualSymbol = contextualSymbol is { IsAnonymousType: true } ? contextualSymbol : null;

var contextualProperties = contextualSymbol?.GetMembers().OfType<IPropertySymbol>().ToImmutableArray() ?? ImmutableArray<IPropertySymbol>.Empty;

using var propertyTypes = reader.ReadSymbolKeyArray<INamedTypeSymbol, ITypeSymbol>(
contextualSymbol,
getContextualSymbol: (contextualSymbol, i) => SafeGet(contextualProperties, i)?.Type,
out var propertyTypesFailureReason);

using var propertyNames = reader.ReadStringArray();
using var propertyIsReadOnly = reader.ReadBooleanArray();

var propertyLocations = ReadPropertyLocations(reader, out var propertyLocationsFailureReason);

if (propertyTypesFailureReason != null)
Expand All @@ -53,7 +63,7 @@ public static SymbolKeyResolution Resolve(SymbolKeyReader reader, out string? fa
if (!propertyTypes.IsDefault)
{
var anonymousType = reader.Compilation.CreateAnonymousTypeSymbol(
propertyTypes.ToImmutable(), propertyNames.ToImmutable(),
propertyTypes.ToImmutable(), propertyNames.ToImmutable()!,
propertyIsReadOnly.ToImmutable(), propertyLocations);
failureReason = null;
return new SymbolKeyResolution(anonymousType);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,20 @@ namespace Microsoft.CodeAnalysis
{
internal partial struct SymbolKey
{
private static class ArrayTypeSymbolKey
private sealed class ArrayTypeSymbolKey : AbstractSymbolKey<IArrayTypeSymbol>
{
public static void Create(IArrayTypeSymbol symbol, SymbolKeyWriter visitor)
public static readonly ArrayTypeSymbolKey Instance = new();

public sealed override void Create(IArrayTypeSymbol symbol, SymbolKeyWriter visitor)
{
visitor.WriteSymbolKey(symbol.ElementType);
visitor.WriteInteger(symbol.Rank);
}

public static SymbolKeyResolution Resolve(SymbolKeyReader reader, out string? failureReason)
protected sealed override SymbolKeyResolution Resolve(
SymbolKeyReader reader, IArrayTypeSymbol? contextualSymbol, out string? failureReason)
{
var elementTypeResolution = reader.ReadSymbolKey(out var elementTypeFailureReason);
var elementTypeResolution = reader.ReadSymbolKey(contextualSymbol?.ElementType, out var elementTypeFailureReason);
var rank = reader.ReadInteger();

if (elementTypeFailureReason != null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,19 @@ namespace Microsoft.CodeAnalysis
{
internal partial struct SymbolKey
{
private static class AssemblySymbolKey
private sealed class AssemblySymbolKey : AbstractSymbolKey<IAssemblySymbol>
{
public static void Create(IAssemblySymbol symbol, SymbolKeyWriter visitor)
public static readonly AssemblySymbolKey Instance = new();

public sealed override void Create(IAssemblySymbol symbol, SymbolKeyWriter visitor)
{
// If the format of this ever changed, then it's necessary to fixup the
// SymbolKeyComparer.RemoveAssemblyKeys function.
visitor.WriteString(symbol.Identity.Name);
}

public static SymbolKeyResolution Resolve(SymbolKeyReader reader, out string? failureReason)
protected sealed override SymbolKeyResolution Resolve(
SymbolKeyReader reader, IAssemblySymbol? contextualSymbol, out string? failureReason)
{
var assemblyName = reader.ReadString();
var compilation = reader.Compilation;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,18 @@ namespace Microsoft.CodeAnalysis
{
internal partial struct SymbolKey
{
private static class DynamicTypeSymbolKey
private sealed class DynamicTypeSymbolKey : AbstractSymbolKey<IDynamicTypeSymbol>
{
public static void Create(SymbolKeyWriter _)
public static readonly DynamicTypeSymbolKey Instance = new();

public sealed override void Create(IDynamicTypeSymbol symbol, SymbolKeyWriter writer)
{
// No need to encode anything here. There is only ever one dynamic-symbol
// per compilation.
}

public static SymbolKeyResolution Resolve(SymbolKeyReader reader, out string? failureReason)
protected sealed override SymbolKeyResolution Resolve(
SymbolKeyReader reader, IDynamicTypeSymbol? contextualSymbol, out string? failureReason)
{
if (reader.Compilation.Language == LanguageNames.VisualBasic)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ namespace Microsoft.CodeAnalysis
{
internal partial struct SymbolKey
{
private static class ErrorTypeSymbolKey
private sealed class ErrorTypeSymbolKey : AbstractSymbolKey<INamedTypeSymbol>
{
public static void Create(INamedTypeSymbol symbol, SymbolKeyWriter visitor)
public static readonly ErrorTypeSymbolKey Instance = new();

public sealed override void Create(INamedTypeSymbol symbol, SymbolKeyWriter visitor)
{
visitor.WriteString(symbol.Name);
switch (symbol.ContainingSymbol)
Expand Down Expand Up @@ -60,14 +62,18 @@ private static ImmutableArray<string> GetContainingNamespaceNamesInReverse(IName
return builder.ToImmutable();
}

public static SymbolKeyResolution Resolve(SymbolKeyReader reader, out string? failureReason)
protected sealed override SymbolKeyResolution Resolve(
SymbolKeyReader reader, INamedTypeSymbol? contextualType, out string? failureReason)
{
var name = reader.ReadRequiredString();
var containingSymbolResolution = ResolveContainer(reader, out var containingSymbolFailureReason);
var containingSymbolResolution = ResolveContainer(reader, contextualType, out var containingSymbolFailureReason);
var arity = reader.ReadInteger();
var isConstructed = reader.ReadBoolean();

using var typeArguments = reader.ReadSymbolKeyArray<ITypeSymbol>(out var typeArgumentsFailureReason);
using var typeArguments = reader.ReadSymbolKeyArray<INamedTypeSymbol, ITypeSymbol>(
contextualType,
getContextualSymbol: static (contextualType, i) => SafeGet(contextualType.TypeArguments, i),
out var typeArgumentsFailureReason);

if (containingSymbolFailureReason != null)
{
Expand All @@ -77,15 +83,12 @@ public static SymbolKeyResolution Resolve(SymbolKeyReader reader, out string? fa

if (typeArgumentsFailureReason != null)
{
Contract.ThrowIfFalse(typeArguments.IsDefault);
failureReason = $"({nameof(ErrorTypeSymbolKey)} {nameof(typeArguments)} failed -> {typeArgumentsFailureReason})";
return default;
}

if (typeArguments.IsDefault)
{
failureReason = $"({nameof(ErrorTypeSymbolKey)} {nameof(typeArguments)} failed)";
return default;
}
Contract.ThrowIfTrue(typeArguments.IsDefault);

using var result = PooledArrayBuilder<INamedTypeSymbol>.GetInstance();

Expand All @@ -104,12 +107,13 @@ public static SymbolKeyResolution Resolve(SymbolKeyReader reader, out string? fa
return CreateResolution(result, $"({nameof(ErrorTypeSymbolKey)} failed)", out failureReason);
}

private static SymbolKeyResolution ResolveContainer(SymbolKeyReader reader, out string? failureReason)
private static SymbolKeyResolution ResolveContainer(
SymbolKeyReader reader, INamedTypeSymbol? contextualType, out string? failureReason)
{
var type = reader.ReadInteger();

if (type == 0)
return reader.ReadSymbolKey(out failureReason);
return reader.ReadSymbolKey(contextualType?.ContainingType, out failureReason);

if (type == 1)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,21 @@ namespace Microsoft.CodeAnalysis
{
internal partial struct SymbolKey
{
private static class EventSymbolKey
private sealed class EventSymbolKey : AbstractSymbolKey<IEventSymbol>
{
public static void Create(IEventSymbol symbol, SymbolKeyWriter visitor)
public static readonly EventSymbolKey Instance = new();

public sealed override void Create(IEventSymbol symbol, SymbolKeyWriter visitor)
{
visitor.WriteString(symbol.MetadataName);
visitor.WriteSymbolKey(symbol.ContainingType);
}

public static SymbolKeyResolution Resolve(SymbolKeyReader reader, out string? failureReason)
protected sealed override SymbolKeyResolution Resolve(
SymbolKeyReader reader, IEventSymbol? contextualSymbol, out string? failureReason)
{
var metadataName = reader.ReadString();
var containingTypeResolution = reader.ReadSymbolKey(out var containingTypeFailureReason);
var containingTypeResolution = reader.ReadSymbolKey(contextualSymbol?.ContainingType, out var containingTypeFailureReason);

if (containingTypeFailureReason != null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,21 @@ namespace Microsoft.CodeAnalysis
{
internal partial struct SymbolKey
{
private static class FieldSymbolKey
private sealed class FieldSymbolKey : AbstractSymbolKey<IFieldSymbol>
{
public static void Create(IFieldSymbol symbol, SymbolKeyWriter visitor)
public static readonly FieldSymbolKey Instance = new();

public sealed override void Create(IFieldSymbol symbol, SymbolKeyWriter visitor)
{
visitor.WriteString(symbol.MetadataName);
visitor.WriteSymbolKey(symbol.ContainingType);
}

public static SymbolKeyResolution Resolve(SymbolKeyReader reader, out string? failureReason)
protected sealed override SymbolKeyResolution Resolve(
SymbolKeyReader reader, IFieldSymbol? contextualSymbol, out string? failureReason)
{
var metadataName = reader.ReadString();
var containingTypeResolution = reader.ReadSymbolKey(out var containingTypeFailureReason);
var containingTypeResolution = reader.ReadSymbolKey(contextualSymbol?.ContainingType, out var containingTypeFailureReason);

if (containingTypeFailureReason != null)
{
Expand Down
Loading

0 comments on commit 027ff7b

Please sign in to comment.