Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Emit MetadataUpdateOriginalTypeAttribute #63169

Merged
merged 3 commits into from
Aug 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
using Microsoft.CodeAnalysis.CSharp.Emit;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Symbols;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.CSharp.Symbols
Expand Down Expand Up @@ -1606,6 +1607,26 @@ internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, r
ref attributes,
compilation.TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_RequiredMemberAttribute__ctor));
}

// Add MetadataUpdateOriginalTypeAttribute when a reloadable type is emitted to EnC delta
if (moduleBuilder.EncSymbolChanges?.IsReplaced(((ISymbolInternal)this).GetISymbol()) == true)
{
// Note that we use this source named type symbol in the attribute argument (of System.Type).
// We do not have access to the original symbol from this compilation. However, System.Type
// is encoded in the attribute as a string containing a fully qualified type name.
// The name of the current type symbol as provided by ISymbol.Name is the same as the name of
// the original type symbol that is being replaced by this type symbol.
// The "#{generation}" suffix is appended to the TypeDef name in the metadata writer,
// but not to the attribute value.
var originalType = this;

AddSynthesizedAttribute(
ref attributes,
compilation.TrySynthesizeAttribute(
WellKnownMember.System_Runtime_CompilerServices_MetadataUpdateOriginalTypeAttribute__ctor,
ImmutableArray.Create(new TypedConstant(compilation.GetWellKnownType(WellKnownType.System_Type), TypedConstantKind.Type, originalType)),
isOptionalUse: true));
}
}

#endregion
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,27 +145,48 @@ internal static EntityHandle Handle(int rowNumber, TableIndex table)
internal static bool IsDefinition(HandleKind kind)
=> kind is not (HandleKind.AssemblyReference or HandleKind.ModuleReference or HandleKind.TypeReference or HandleKind.MemberReference or HandleKind.TypeSpecification or HandleKind.MethodSpecification);

/// <summary>
/// Checks that the EncLog contains specified rows.
/// Any default values in the expected <paramref name="rows"/> are ignored to facilitate conditional code.
/// </summary>
internal static void CheckEncLog(MetadataReader reader, params EditAndContinueLogEntry[] rows)
{
AssertEx.Equal(rows, reader.GetEditAndContinueLogEntries(), itemInspector: EncLogRowToString);
AssertEx.Equal(
rows.Where(r => r.Handle != default),
tmat marked this conversation as resolved.
Show resolved Hide resolved
reader.GetEditAndContinueLogEntries(), itemInspector: EncLogRowToString);
}

/// <summary>
/// Checks that the EncLog contains specified definition rows. References are ignored as they are usually not interesting to validate. They are emitted as needed.
/// Any default values in the expected <paramref name="rows"/> are ignored to facilitate conditional code.
/// </summary>
internal static void CheckEncLogDefinitions(MetadataReader reader, params EditAndContinueLogEntry[] rows)
{
AssertEx.Equal(rows, reader.GetEditAndContinueLogEntries().Where(e => IsDefinition(e.Handle.Kind)), itemInspector: EncLogRowToString);
AssertEx.Equal(
rows.Where(r => r.Handle != default),
reader.GetEditAndContinueLogEntries().Where(e => IsDefinition(e.Handle.Kind)), itemInspector: EncLogRowToString);
}

/// <summary>
/// Checks that the EncMap contains specified handles.
/// Any default values in the expected <paramref name="handles"/> are ignored to facilitate conditional code.
/// </summary>
internal static void CheckEncMap(MetadataReader reader, params EntityHandle[] handles)
{
AssertEx.Equal(handles, reader.GetEditAndContinueMapEntries(), itemInspector: EncMapRowToString);
AssertEx.Equal(
handles.Where(h => h != default),
reader.GetEditAndContinueMapEntries(), itemInspector: EncMapRowToString);
}

/// <summary>
/// Checks that the EncMap contains specified definition handles. References are ignored as they are usually not interesting to validate. They are emitted as needed.
/// Any default values in the expected <paramref name="handles"/> are ignored to facilitate conditional code.
/// </summary>
internal static void CheckEncMapDefinitions(MetadataReader reader, params EntityHandle[] handles)
{
AssertEx.Equal(handles, reader.GetEditAndContinueMapEntries().Where(e => IsDefinition(e.Kind)), itemInspector: EncMapRowToString);
AssertEx.Equal(
handles.Where(h => h != default),
reader.GetEditAndContinueMapEntries().Where(e => IsDefinition(e.Kind)), itemInspector: EncMapRowToString);
}

internal static void CheckAttributes(MetadataReader reader, params CustomAttributeRow[] rows)
Expand Down Expand Up @@ -203,7 +224,7 @@ private static void CheckNames<THandle>(
Func<THandle, Handle> toHandle,
string[] expectedNames)
{
var aggregator = new MetadataAggregator(readers[0], readers.Skip(1).ToArray());
var aggregator = GetAggregator(readers);

AssertEx.Equal(expectedNames, entityHandles.Select(handle =>
{
Expand All @@ -215,6 +236,27 @@ private static void CheckNames<THandle>(
}));
}

public static void CheckBlobValue(IList<MetadataReader> readers, BlobHandle valueHandle, byte[] expectedValue)
{
var aggregator = GetAggregator(readers);

var genHandle = (BlobHandle)aggregator.GetGenerationHandle(valueHandle, out int blobGeneration);
var attributeData = readers[blobGeneration].GetBlobBytes(genHandle);
AssertEx.Equal(expectedValue, attributeData);
}

public static void CheckStringValue(IList<MetadataReader> readers, StringHandle valueHandle, string expectedValue)
{
var aggregator = GetAggregator(readers);

var genHandle = (StringHandle)aggregator.GetGenerationHandle(valueHandle, out int blobGeneration);
var attributeData = readers[blobGeneration].GetString(genHandle);
AssertEx.Equal(expectedValue, attributeData);
}

public static MetadataAggregator GetAggregator(IList<MetadataReader> readers)
=> new MetadataAggregator(readers[0], readers.Skip(1).ToArray());

internal static string EncLogRowToString(EditAndContinueLogEntry row)
{
TableIndex tableIndex;
Expand Down
Loading