|
// 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.
using System.Diagnostics;
using System.Linq;
using Microsoft.CodeAnalysis.Shared.Extensions;
namespace Microsoft.CodeAnalysis;
internal partial struct SymbolKey
{
/// <summary>
/// Anonymous functions and anonymous-delegates (the special VB synthesized delegate types),
/// only come into existence when someone has explicitly written a lambda in their source
/// code. So to appropriately round-trip this symbol we store the location that the lambda
/// was at so that we can find the symbol again when we resolve the key.
/// </summary>
private static class AnonymousFunctionOrDelegateSymbolKey
{
public static void Create(ISymbol symbol, SymbolKeyWriter visitor)
{
Debug.Assert(symbol.IsAnonymousDelegateType() || symbol.IsAnonymousFunction());
// Write out if this was an anonymous delegate or anonymous function.
// In both cases they'll have the same location (the location of
// the lambda that forced them into existence). When we resolve the
// symbol later, if it's an anonymous delegate, we'll first resolve to
// the anonymous-function, then use that anonymous-functoin to get at
// the synthesized anonymous delegate.
visitor.WriteBoolean(symbol.IsAnonymousDelegateType());
visitor.WriteLocation(symbol.Locations.First());
}
public static SymbolKeyResolution Resolve(SymbolKeyReader reader, out string? failureReason)
{
var isAnonymousDelegateType = reader.ReadBoolean();
var location = reader.ReadLocation(out var locationFailureReason)!;
if (locationFailureReason != null)
{
failureReason = $"({nameof(AnonymousFunctionOrDelegateSymbolKey)} {nameof(location)} failed -> {locationFailureReason})";
return default;
}
var syntaxTree = location.SourceTree;
if (syntaxTree == null)
{
failureReason = $"({nameof(AnonymousFunctionOrDelegateSymbolKey)} {nameof(SyntaxTree)} failed)";
return default;
}
var semanticModel = reader.Compilation.GetSemanticModel(syntaxTree);
var root = syntaxTree.GetRoot(reader.CancellationToken);
var node = root.FindNode(location.SourceSpan, getInnermostNodeForTie: true);
var symbol = semanticModel.GetSymbolInfo(node, reader.CancellationToken)
.GetAnySymbol();
// 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 is IMethodSymbol methodSymbol)
{
var anonymousDelegate = methodSymbol.AssociatedAnonymousDelegate;
symbol = anonymousDelegate;
}
failureReason = null;
return new SymbolKeyResolution(symbol);
}
}
}
|