|
// 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.Runtime.Serialization;
using System;
using System.Diagnostics;
namespace Microsoft.CodeAnalysis.Contracts.EditAndContinue;
/// <summary>
/// ManagedModuleMethodId is a token/version pair which is used to uniquely identify the
/// symbol store's understanding of a particular CLR method within a module context.
/// See <see cref="ManagedMethodId"/> for more details.
/// </summary>
[DataContract]
[DebuggerDisplay("{GetDebuggerDisplay(),nq}")]
internal readonly struct ManagedModuleMethodId : IEquatable<ManagedModuleMethodId>
{
/// <summary>
/// Creates a ManagedModuleMethodId.
/// </summary>
/// <param name="token">Method token.</param>
/// <param name="version">Method version.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// If <paramref name="token"/> is less or equals 0x06000000 or <paramref name="version"/> is less or equals zero.
/// </exception>
public ManagedModuleMethodId(
int token,
int version)
{
// 0x06 means that the token is for a MethodDef.
// Valid method tokens are expected to be greather than 0x06000000.
if (token <= 0x06000000)
throw new ArgumentOutOfRangeException(nameof(token));
if (version <= 0)
throw new ArgumentOutOfRangeException(nameof(version));
Token = token;
Version = version;
}
/// <summary>
/// The method definition metadata token of the method that contains this symbol.
/// </summary>
[DataMember(Name = "token")]
public int Token { get; }
/// <summary>
/// MethodVersion is a 1-based index. This will be '1' for methods that have not
/// been edited through Edit-and-continue. For edited methods, the version indicates
/// the EnC apply of this method.
/// Thus, if the user does 5 EnC applies and a particular method is only edited in the 5th apply,
/// then there are two method ids for this method, and they have Version = 1 and Version = 5.
///
/// The debugger needs to deal with old versions of the method because they will
/// continue to be on the call stack until control is unwound.The debugger can also hit
/// breakpoints or stop for exceptions within exception handling regions of old
/// methods. In other words, if the user sets a breakpoint within the catch block of a
/// non-leaf method, the debugger needs to set that breakpoint within the old version
/// of the method.
///
/// In scenarios such as function breakpoint binding, the value '0' may used to
/// indicate the current version of the method.
/// </summary>
[DataMember(Name = "version")]
public int Version { get; }
public bool Equals(ManagedModuleMethodId other)
{
return Token == other.Token && Version == other.Version;
}
public override bool Equals(object? obj) => obj is ManagedModuleMethodId method && Equals(method);
public override int GetHashCode() => Token ^ Version;
public static bool operator ==(ManagedModuleMethodId left, ManagedModuleMethodId right) => left.Equals(right);
public static bool operator !=(ManagedModuleMethodId left, ManagedModuleMethodId right) => !(left == right);
internal string GetDebuggerDisplay() => $"0x{Token:X8} v{Version}";
}
|