提交 522f532a 编写于 作者: N Neal Gafter

Merge branch 'master' of https://github.com/dotnet/roslyn

......@@ -40,7 +40,6 @@ internal static class EmitHelpers
throw;
}
var pdbName = FileNameUtilities.ChangeExtension(compilation.SourceModule.Name, "pdb");
var diagnostics = DiagnosticBag.GetInstance();
var emitOptions = EmitOptions.Default;
......@@ -64,11 +63,11 @@ internal static class EmitHelpers
testData.Module = moduleBeingBuilt;
}
baseline = moduleBeingBuilt.PreviousGeneration;
var definitionMap = moduleBeingBuilt.PreviousDefinitions;
var changes = moduleBeingBuilt.Changes;
EmitBaseline newBaseline = null;
if (compilation.Compile(
moduleBeingBuilt,
win32Resources: null,
......@@ -81,48 +80,26 @@ internal static class EmitHelpers
// Map the definitions from the previous compilation to the current compilation.
// This must be done after compiling above since synthesized definitions
// (generated when compiling method bodies) may be required.
baseline = MapToCompilation(compilation, moduleBeingBuilt);
var pdbOutputInfo = new Cci.PdbOutputInfo(pdbName, pdbStream);
using (var pdbWriter = new Cci.PdbWriter(pdbOutputInfo, (testData != null) ? testData.SymWriterFactory : null))
{
var context = new EmitContext(moduleBeingBuilt, null, diagnostics);
var encId = Guid.NewGuid();
try
{
var writer = new DeltaMetadataWriter(
context,
compilation.MessageProvider,
baseline,
encId,
definitionMap,
changes,
cancellationToken);
Cci.MetadataSizes metadataSizes;
writer.WriteMetadataAndIL(pdbWriter, metadataStream, ilStream, out metadataSizes);
writer.GetMethodTokens(updatedMethods);
bool hasErrors = diagnostics.HasAnyErrors();
return new EmitDifferenceResult(
success: !hasErrors,
diagnostics: diagnostics.ToReadOnlyAndFree(),
baseline: hasErrors ? null : writer.GetDelta(baseline, compilation, encId, metadataSizes));
}
catch (Cci.PdbWritingException e)
{
diagnostics.Add(ErrorCode.FTL_DebugEmitFailure, Location.None, e.Message);
}
catch (PermissionSetFileReadException e)
{
diagnostics.Add(ErrorCode.ERR_PermissionSetAttributeFileReadError, Location.None, e.FileName, e.PropertyName, e.Message);
}
}
var mappedBaseline = MapToCompilation(compilation, moduleBeingBuilt);
newBaseline = compilation.SerializeToDeltaStreams(
moduleBeingBuilt,
mappedBaseline,
definitionMap,
changes,
metadataStream,
ilStream,
pdbStream,
updatedMethods,
diagnostics,
testData?.SymWriterFactory,
cancellationToken);
}
return new EmitDifferenceResult(success: false, diagnostics: diagnostics.ToReadOnlyAndFree(), baseline: null);
return new EmitDifferenceResult(
success: newBaseline != null,
diagnostics: diagnostics.ToReadOnlyAndFree(),
baseline: newBaseline);
}
/// <summary>
......
......@@ -111,7 +111,7 @@ internal sealed class PEDeltaAssemblyBuilder : PEAssemblyBuilderBase, IPEDeltaAs
{
return false;
}
builder.Add(new AnonymousTypeKeyField(fieldName));
builder.Add(AnonymousTypeKeyField.CreateField(fieldName));
}
return true;
}
......
......@@ -7,7 +7,7 @@
using System.Runtime.InteropServices;
using System.Threading;
using Microsoft.CodeAnalysis.Collections;
using Microsoft.CodeAnalysis.CSharp.Emit;
using Microsoft.CodeAnalysis.Emit;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.Symbols
......@@ -131,10 +131,10 @@ internal AnonymousTypeTemplateSymbol(AnonymousTypeManager manager, AnonymousType
this.SpecialMembers = specialMembers.AsImmutable();
}
internal Microsoft.CodeAnalysis.Emit.AnonymousTypeKey GetAnonymousTypeKey()
internal AnonymousTypeKey GetAnonymousTypeKey()
{
var properties = this.Properties.SelectAsArray(p => new Microsoft.CodeAnalysis.Emit.AnonymousTypeKeyField(p.Name));
return new Microsoft.CodeAnalysis.Emit.AnonymousTypeKey(properties);
var properties = this.Properties.SelectAsArray(p => AnonymousTypeKeyField.CreateField(p.Name));
return new AnonymousTypeKey(properties);
}
/// <summary>
......
......@@ -32,13 +32,10 @@ private Guid CompiledGuid(string source, string assemblyName)
return result;
}
private ImmutableArray<byte> GetBytesEmitted(string source, Platform platform, bool debug, bool deterministic)
private ImmutableArray<byte> EmitDeterministic(string source, Platform platform, bool debug)
{
var options = (debug ? TestOptions.DebugExe : TestOptions.ReleaseExe).WithPlatform(platform);
if (deterministic)
{
options = options.WithFeatures((new[] { "dEtErmInIstIc" }).AsImmutable()); // expect case-insensitivity
}
options = options.WithFeatures((new[] { "dEtErmInIstIc" }).AsImmutable()); // expect case-insensitivity
var compilation = CreateCompilation(source, assemblyName: "DeterminismTest", references: new[] { MscorlibRef }, options: options);
......@@ -49,19 +46,6 @@ private ImmutableArray<byte> GetBytesEmitted(string source, Platform platform, b
return compilation.EmitToArray();
}
private class ImmutableByteArrayEqualityComparer : IEqualityComparer<ImmutableArray<byte>>
{
public bool Equals(ImmutableArray<byte> x, ImmutableArray<byte> y)
{
return x.SequenceEqual(y);
}
public int GetHashCode(ImmutableArray<byte> obj)
{
return obj.GetHashCode();
}
}
[Fact(Skip = "900646"), WorkItem(900646)]
public void Simple()
{
......@@ -80,28 +64,37 @@ public void Simple()
}
[Fact]
public void CompareAllBytesEmitted()
public void CompareAllBytesEmitted_Release()
{
var source =
@"class Program
{
public static void Main(string[] args) {}
}";
var comparer = new ImmutableByteArrayEqualityComparer();
var result1 = EmitDeterministic(source, platform: Platform.AnyCpu32BitPreferred, debug: false);
var result2 = EmitDeterministic(source, platform: Platform.AnyCpu32BitPreferred, debug: false);
AssertEx.Equal(result1, result2);
var result1 = GetBytesEmitted(source, platform: Platform.AnyCpu32BitPreferred, debug: true, deterministic: true);
var result2 = GetBytesEmitted(source, platform: Platform.AnyCpu32BitPreferred, debug: true, deterministic: true);
Assert.Equal(result1, result2, comparer);
var result3 = EmitDeterministic(source, platform: Platform.X64, debug: false);
var result4 = EmitDeterministic(source, platform: Platform.X64, debug: false);
AssertEx.Equal(result3, result4);
}
var result3 = GetBytesEmitted(source, platform: Platform.X64, debug: false, deterministic: true);
var result4 = GetBytesEmitted(source, platform: Platform.X64, debug: false, deterministic: true);
Assert.Equal(result3, result4, comparer);
Assert.NotEqual(result1, result3, comparer);
[Fact(Skip="https://github.com/dotnet/roslyn/issues/926"), WorkItem(926)]
public void CompareAllBytesEmitted_Debug()
{
var source =
@"class Program
{
public static void Main(string[] args) {}
}";
var result1 = EmitDeterministic(source, platform: Platform.AnyCpu32BitPreferred, debug: true);
var result2 = EmitDeterministic(source, platform: Platform.AnyCpu32BitPreferred, debug: true);
AssertEx.Equal(result1, result2);
var result5 = GetBytesEmitted(source, platform: Platform.X64, debug: false, deterministic: false);
var result6 = GetBytesEmitted(source, platform: Platform.X64, debug: false, deterministic: false);
Assert.NotEqual(result5, result6, comparer);
Assert.NotEqual(result3, result5, comparer);
var result3 = EmitDeterministic(source, platform: Platform.X64, debug: true);
var result4 = EmitDeterministic(source, platform: Platform.X64, debug: true);
AssertEx.Equal(result3, result4);
}
[Fact]
......
......@@ -4511,6 +4511,109 @@ .maxstack 2
}
}
[Fact]
public void AnonymousTypes_DifferentCase()
{
var source0 =
@"class C
{
static void M()
{
var x = new { A = 1, B = 2 };
var y = new { a = 3, b = 4 };
}
}";
var source1 =
@"class C
{
static void M()
{
var x = new { a = 1, B = 2 };
var y = new { AB = 3 };
}
}";
var source2 =
@"class C
{
static void M()
{
var x = new { a = 1, B = 2 };
var y = new { Ab = 5 };
}
}";
var compilation0 = CreateCompilationWithMscorlib(source0, options: TestOptions.DebugDll);
var compilation1 = compilation0.WithSource(source1);
var compilation2 = compilation1.WithSource(source2);
var testData0 = new CompilationTestData();
var bytes0 = compilation0.EmitToArray(testData: testData0);
using (var md0 = ModuleMetadata.CreateFromImage(bytes0))
{
var generation0 = EmitBaseline.CreateInitialBaseline(md0, testData0.GetMethodData("C.M").EncDebugInfoProvider());
var method0 = compilation0.GetMember<MethodSymbol>("C.M");
var reader0 = md0.MetadataReader;
CheckNames(reader0, reader0.GetTypeDefNames(), "<Module>", "<>f__AnonymousType0`2", "<>f__AnonymousType1`2", "C");
var method1 = compilation1.GetMember<MethodSymbol>("C.M");
var diff1 = compilation1.EmitDifference(
generation0,
ImmutableArray.Create(new SemanticEdit(SemanticEditKind.Update, method0, method1, GetEquivalentNodesMap(method1, method0), preserveLocalVariables: true)));
using (var md1 = diff1.GetMetadata())
{
var reader1 = md1.Reader;
CheckNames(new[] { reader0, reader1 }, reader1.GetTypeDefNames(), "<>f__AnonymousType2`2", "<>f__AnonymousType3`1");
diff1.VerifyIL("C.M",
@"{
// Code size 17 (0x11)
.maxstack 2
.locals init ([unchanged] V_0,
[unchanged] V_1,
<>f__AnonymousType2<int, int> V_2, //x
<>f__AnonymousType3<int> V_3) //y
IL_0000: nop
IL_0001: ldc.i4.1
IL_0002: ldc.i4.2
IL_0003: newobj ""<>f__AnonymousType2<int, int>..ctor(int, int)""
IL_0008: stloc.2
IL_0009: ldc.i4.3
IL_000a: newobj ""<>f__AnonymousType3<int>..ctor(int)""
IL_000f: stloc.3
IL_0010: ret
}");
var method2 = compilation2.GetMember<MethodSymbol>("C.M");
var diff2 = compilation2.EmitDifference(
diff1.NextGeneration,
ImmutableArray.Create(new SemanticEdit(SemanticEditKind.Update, method1, method2, GetEquivalentNodesMap(method2, method1), preserveLocalVariables: true)));
using (var md2 = diff2.GetMetadata())
{
var reader2 = md2.Reader;
CheckNames(new[] { reader0, reader1, reader2 }, reader2.GetTypeDefNames(), "<>f__AnonymousType4`1");
diff2.VerifyIL("C.M",
@"{
// Code size 18 (0x12)
.maxstack 2
.locals init ([unchanged] V_0,
[unchanged] V_1,
<>f__AnonymousType2<int, int> V_2, //x
[unchanged] V_3,
<>f__AnonymousType4<int> V_4) //y
IL_0000: nop
IL_0001: ldc.i4.1
IL_0002: ldc.i4.2
IL_0003: newobj ""<>f__AnonymousType2<int, int>..ctor(int, int)""
IL_0008: stloc.2
IL_0009: ldc.i4.5
IL_000a: newobj ""<>f__AnonymousType4<int>..ctor(int)""
IL_000f: stloc.s V_4
IL_0011: ret
}");
}
}
}
}
/// <summary>
/// Should not re-use locals if the method metadata
/// signature is unsupported.
......
......@@ -16,46 +16,46 @@ internal abstract partial class CommonCompiler
/// </summary>
private sealed class CompilerEmitStreamProvider : Compilation.EmitStreamProvider, IDisposable
{
private static Stream s_uninitialized = Stream.Null;
private readonly CommonCompiler _compiler;
private readonly TouchedFileLogger _touchedFileLogger;
private readonly string _filePath;
private Stream _stream;
private readonly bool _streamCreatedByNativePdbWriter;
private Stream _lazyStream;
internal CompilerEmitStreamProvider(CommonCompiler compiler, TouchedFileLogger touchedFileLogger, string filePath)
internal CompilerEmitStreamProvider(CommonCompiler compiler, string filePath, bool streamCreatedByNativePdbWriter)
{
_compiler = compiler;
_touchedFileLogger = touchedFileLogger;
_filePath = filePath;
_streamCreatedByNativePdbWriter = streamCreatedByNativePdbWriter;
_lazyStream = s_uninitialized;
}
public void Dispose()
{
_stream?.Dispose();
_stream = null;
if (_lazyStream != s_uninitialized)
{
_lazyStream?.Dispose();
_lazyStream = s_uninitialized;
}
}
public override Stream GetStream(DiagnosticBag diagnostics)
{
if (_stream == null)
if (_lazyStream == s_uninitialized)
{
_stream = OpenFile(_filePath, diagnostics);
_lazyStream = _streamCreatedByNativePdbWriter ? null : OpenFile(_filePath, diagnostics);
}
return _stream;
return _lazyStream;
}
private Stream OpenFile(string filePath, DiagnosticBag diagnostics)
{
try
{
Stream stream = _compiler.FileOpen(filePath, FileMode.Create, FileAccess.ReadWrite, FileShare.None);
if (_touchedFileLogger != null)
{
_touchedFileLogger.AddWritten(filePath);
}
return stream;
return _compiler.FileOpen(filePath, FileMode.Create, FileAccess.ReadWrite, FileShare.None);
}
catch (Exception e)
{
......
......@@ -400,27 +400,27 @@ private int RunCore(TextWriter consoleOutput, ErrorLogger errorLogger, Cancellat
string finalPdbFilePath;
string finalXmlFilePath;
FileStream xml = null;
FileStream xmlStreamOpt = null;
cancellationToken.ThrowIfCancellationRequested();
finalXmlFilePath = Arguments.DocumentationPath;
if (finalXmlFilePath != null)
{
xml = OpenFile(finalXmlFilePath, consoleOutput, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite | FileShare.Delete);
if (xml == null)
xmlStreamOpt = OpenFile(finalXmlFilePath, consoleOutput, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite | FileShare.Delete);
if (xmlStreamOpt == null)
{
return Failed;
}
xml.SetLength(0);
xmlStreamOpt.SetLength(0);
}
cancellationToken.ThrowIfCancellationRequested();
IEnumerable<DiagnosticInfo> errors;
using (var win32Res = GetWin32Resources(Arguments, compilation, out errors))
using (xml)
using (var win32ResourceStreamOpt = GetWin32Resources(Arguments, compilation, out errors))
using (xmlStreamOpt)
{
if (ReportErrors(errors, consoleOutput, errorLogger))
{
......@@ -439,25 +439,27 @@ private int RunCore(TextWriter consoleOutput, ErrorLogger errorLogger, Cancellat
WithOutputNameOverride(outputName).
WithPdbFilePath(finalPdbFilePath);
var pdbOutputInfo = Arguments.EmitPdb
? new Cci.PdbOutputInfo(finalPdbFilePath)
: Cci.PdbOutputInfo.None;
using (var peStreamProvider = new CompilerEmitStreamProvider(this, touchedFilesLogger, finalOutputPath))
using (var peStreamProvider = new CompilerEmitStreamProvider(this, finalOutputPath, streamCreatedByNativePdbWriter: false))
using (var pdbStreamProviderOpt = Arguments.EmitPdb ? new CompilerEmitStreamProvider(this, finalOutputPath, streamCreatedByNativePdbWriter: true) : null)
{
emitResult = compilation.Emit(
peStreamProvider,
pdbOutputInfo,
xml,
win32Res,
pdbStreamProviderOpt,
(xmlStreamOpt != null) ? new Compilation.SimpleEmitStreamProvider(xmlStreamOpt) : null,
(win32ResourceStreamOpt != null) ? new Compilation.SimpleEmitStreamProvider(win32ResourceStreamOpt) : null,
Arguments.ManifestResources,
emitOptions,
getAnalyzerDiagnostics,
cancellationToken);
if (emitResult.Success && !pdbOutputInfo.IsNone && touchedFilesLogger != null)
if (emitResult.Success && touchedFilesLogger != null)
{
touchedFilesLogger.AddWritten(pdbOutputInfo.FileName);
if (pdbStreamProviderOpt != null)
{
touchedFilesLogger.AddWritten(finalPdbFilePath);
}
touchedFilesLogger.AddWritten(finalOutputPath);
}
}
}
......
......@@ -89,6 +89,12 @@ public bool EmitDebugInformation
get { return _store.GetOrDefault("EmitDebugInformation", false); }
}
public string ErrorLog
{
set { _store[nameof(ErrorLog)] = value; }
get { return (string)_store[nameof(ErrorLog)]; }
}
public int FileAlignment
{
set { _store["FileAlignment"] = value; }
......@@ -174,6 +180,12 @@ public ITaskItem[] References
get { return (ITaskItem[])_store["References"]; }
}
public bool ReportAnalyzer
{
set { _store[nameof(ReportAnalyzer)] = value; }
get { return _store.GetOrDefault(nameof(ReportAnalyzer), false); }
}
public ITaskItem[] Resources
{
set { _store["Resources"] = value; }
......@@ -535,7 +547,10 @@ protected internal virtual void AddResponseFileCommands(CommandLineBuilderExtens
commandLine.AppendPlusOrMinusSwitch("/optimize", this._store, "Optimize");
commandLine.AppendSwitchIfNotNull("/out:", this.OutputAssembly);
commandLine.AppendSwitchIfNotNull("/ruleset:", this.CodeAnalysisRuleSet);
commandLine.AppendSwitchIfNotNull("/errorlog:", this.ErrorLog);
commandLine.AppendSwitchIfNotNull("/subsystemversion:", this.SubsystemVersion);
// TODO: uncomment the below line once "/reportanalyzer" switch is added to compiler.
//commandLine.AppendWhenTrue("/reportanalyzer", this._store, "ReportAnalyzer");
// If the strings "LogicalName" or "Access" ever change, make sure to search/replace everywhere in vsproject.
commandLine.AppendSwitchIfNotNull("/resource:", this.Resources, new string[] { "LogicalName", "Access" });
commandLine.AppendSwitchIfNotNull("/target:", this.TargetType);
......
......@@ -83,6 +83,7 @@
EmitDebugInformation="$(DebugSymbols)"
EnvironmentVariables="$(CscEnvironment)"
ErrorEndLocation="$(ErrorEndLocation)"
ErrorLog="$(ErrorLog)"
ErrorReport="$(ErrorReport)"
FileAlignment="$(FileAlignment)"
GenerateFullPaths="$(GenerateFullPaths)"
......@@ -104,6 +105,7 @@
Prefer32Bit="$(Prefer32Bit)"
PreferredUILang="$(PreferredUILang)"
References="@(ReferencePath)"
ReportAnalyzer="$(ReportAnalyzer)"
Resources="@(_CoreCompileResourceInputs);@(CompiledLicenseFile)"
ResponseFiles="$(CompilerResponseFile)"
Sources="@(Compile)"
......
......@@ -68,6 +68,7 @@
DocumentationFile="@(DocFileItem)"
EmitDebugInformation="$(DebugSymbols)"
EnvironmentVariables="$(VbcEnvironment)"
ErrorLog="$(ErrorLog)"
ErrorReport="$(ErrorReport)"
FileAlignment="$(FileAlignment)"
GenerateDocumentation="$(GenerateDocumentation)"
......@@ -97,6 +98,7 @@
PreferredUILang="$(PreferredUILang)"
References="@(ReferencePath)"
RemoveIntegerChecks="$(RemoveIntegerChecks)"
ReportAnalyzer="$(ReportAnalyzer)"
Resources="@(_CoreCompileResourceInputs);@(CompiledLicenseFile)"
ResponseFiles="$(CompilerResponseFile)"
RootNamespace="$(RootNamespace)"
......
......@@ -35,6 +35,7 @@ internal sealed class SimpleEmitStreamProvider : EmitStreamProvider
internal SimpleEmitStreamProvider(Stream stream)
{
Debug.Assert(stream != null);
_stream = stream;
}
......
......@@ -51,6 +51,8 @@ public abstract partial class Compilation
/// </summary>
private SmallDictionary<int, bool> _lazyMakeMemberMissingMap;
private Dictionary<string, string> _lazyFeatures;
internal Compilation(
string name,
ImmutableArray<MetadataReference> references,
......@@ -1369,9 +1371,9 @@ internal void EnsureAnonymousTypeTemplates(CancellationToken cancellationToken)
/// Emit the IL for the compiled source code into the specified stream.
/// </summary>
/// <param name="peStreamProvider">Provides the PE stream the compiler will write to.</param>
/// <param name="pdbOutputInfo">Provides the PDB stream the compiler will write to.</param>
/// <param name="xmlDocumentationStream">Stream to which the compilation's XML documentation will be written. Null to forego XML generation.</param>
/// <param name="win32Resources">Stream from which the compilation's Win32 resources will be read (in RES format).
/// <param name="pdbStreamProvider">Provides the PDB stream the compiler will write to.</param>
/// <param name="xmlDocumentationStreamProvider">Stream to which the compilation's XML documentation will be written. Null to forego XML generation.</param>
/// <param name="win32ResourcesProvider">Stream from which the compilation's Win32 resources will be read (in RES format).
/// Null to indicate that there are none. The RES format begins with a null resource entry.</param>
/// <param name="manifestResources">List of the compilation's managed resources. Null to indicate that there are none.</param>
/// <param name="options">Emit options.</param>
......@@ -1379,19 +1381,19 @@ internal void EnsureAnonymousTypeTemplates(CancellationToken cancellationToken)
/// <param name="cancellationToken">To cancel the emit process.</param>
internal EmitResult Emit(
EmitStreamProvider peStreamProvider,
Cci.PdbOutputInfo pdbOutputInfo,
Stream xmlDocumentationStream = null,
Stream win32Resources = null,
IEnumerable<ResourceDescription> manifestResources = null,
EmitOptions options = null,
Func<ImmutableArray<Diagnostic>> getHostDiagnostics = null,
CancellationToken cancellationToken = default(CancellationToken))
EmitStreamProvider pdbStreamProvider,
EmitStreamProvider xmlDocumentationStreamProvider,
EmitStreamProvider win32ResourcesProvider,
IEnumerable<ResourceDescription> manifestResources,
EmitOptions options,
Func<ImmutableArray<Diagnostic>> getHostDiagnostics,
CancellationToken cancellationToken)
{
return Emit(
peStreamProvider,
pdbOutputInfo,
new SimpleEmitStreamProvider(xmlDocumentationStream),
new SimpleEmitStreamProvider(win32Resources),
pdbStreamProvider,
xmlDocumentationStreamProvider,
win32ResourcesProvider,
manifestResources,
options,
testData: null,
......@@ -1399,6 +1401,34 @@ internal void EnsureAnonymousTypeTemplates(CancellationToken cancellationToken)
cancellationToken: cancellationToken);
}
/// <summary>
/// This overload is only intended to be directly called by tests that want to pass <paramref name="testData"/>.
/// The map is used for storing a list of methods and their associated IL.
/// </summary>
/// <returns>True if emit succeeded.</returns>
internal EmitResult Emit(
Stream peStream,
Stream pdbStream,
Stream xmlDocumentationStream,
Stream win32Resources,
IEnumerable<ResourceDescription> manifestResources,
EmitOptions options,
CompilationTestData testData,
Func<ImmutableArray<Diagnostic>> getHostDiagnostics,
CancellationToken cancellationToken)
{
return Emit(
new SimpleEmitStreamProvider(peStream),
(pdbStream != null) ? new SimpleEmitStreamProvider(pdbStream) : null,
(xmlDocumentationStream != null) ? new SimpleEmitStreamProvider(xmlDocumentationStream) : null,
(win32Resources != null) ? new SimpleEmitStreamProvider(win32Resources) : null,
manifestResources,
options,
testData,
getHostDiagnostics,
cancellationToken);
}
/// <summary>
/// Emit the differences between the compilation and the previous generation
/// for Edit and Continue. The differences are expressed as added and changed
......@@ -1481,35 +1511,7 @@ internal void EnsureAnonymousTypeTemplates(CancellationToken cancellationToken)
ICollection<MethodDefinitionHandle> updatedMethodHandles,
CompilationTestData testData,
CancellationToken cancellationToken);
/// <summary>
/// This overload is only intended to be directly called by tests that want to pass <paramref name="testData"/>.
/// The map is used for storing a list of methods and their associated IL.
/// </summary>
/// <returns>True if emit succeeded.</returns>
internal EmitResult Emit(
Stream peStream,
Stream pdbStream,
Stream xmlDocumentationStream,
Stream win32Resources,
IEnumerable<ResourceDescription> manifestResources,
EmitOptions options,
CompilationTestData testData,
Func<ImmutableArray<Diagnostic>> getHostDiagnostics,
CancellationToken cancellationToken)
{
return Emit(
new SimpleEmitStreamProvider(peStream),
new Cci.PdbOutputInfo(pdbStream),
new SimpleEmitStreamProvider(xmlDocumentationStream),
new SimpleEmitStreamProvider(win32Resources),
manifestResources,
options,
testData,
getHostDiagnostics,
cancellationToken);
}
/// <summary>
/// This overload is only intended to be directly called by tests that want to pass <paramref name="testData"/>.
/// The map is used for storing a list of methods and their associated IL.
......@@ -1517,7 +1519,7 @@ internal void EnsureAnonymousTypeTemplates(CancellationToken cancellationToken)
/// <returns>True if emit succeeded.</returns>
internal EmitResult Emit(
EmitStreamProvider peStreamProvider,
Cci.PdbOutputInfo pdbOutputInfo,
EmitStreamProvider pdbStreamProvider,
EmitStreamProvider xmlDocumentationStreamProvider,
EmitStreamProvider win32ResourcesStreamProvider,
IEnumerable<ResourceDescription> manifestResources,
......@@ -1568,13 +1570,13 @@ internal void EnsureAnonymousTypeTemplates(CancellationToken cancellationToken)
return ToEmitResultAndFree(diagnostics, success: false);
}
var win32Resources = win32ResourcesStreamProvider.GetStream(diagnostics);
var xmlDocumentationStream = xmlDocumentationStreamProvider.GetStream(diagnostics);
var win32Resources = win32ResourcesStreamProvider?.GetStream(diagnostics);
var xmlDocumentationStream = xmlDocumentationStreamProvider?.GetStream(diagnostics);
if (!this.Compile(
moduleBeingBuilt,
win32Resources,
xmlDocumentationStream,
generateDebugInfo: pdbOutputInfo.IsValid,
generateDebugInfo: pdbStreamProvider != null,
diagnostics: diagnostics,
filterOpt: null,
cancellationToken: cancellationToken))
......@@ -1583,6 +1585,7 @@ internal void EnsureAnonymousTypeTemplates(CancellationToken cancellationToken)
}
var hostDiagnostics = getHostDiagnostics?.Invoke() ?? ImmutableArray<Diagnostic>.Empty;
diagnostics.AddRange(hostDiagnostics);
if (hostDiagnostics.Any(x => x.Severity == DiagnosticSeverity.Error))
{
......@@ -1592,7 +1595,7 @@ internal void EnsureAnonymousTypeTemplates(CancellationToken cancellationToken)
bool success = SerializeToPeStream(
moduleBeingBuilt,
peStreamProvider,
pdbOutputInfo,
pdbStreamProvider,
testData?.SymWriterFactory,
diagnostics,
metadataOnly: options.EmitMetadataOnly,
......@@ -1605,11 +1608,11 @@ private static EmitResult ToEmitResultAndFree(DiagnosticBag diagnostics, bool su
{
return new EmitResult(success, diagnostics.ToReadOnlyAndFree());
}
internal bool SerializeToPeStream(
CommonPEModuleBuilder moduleBeingBuilt,
EmitStreamProvider peStreamProvider,
Cci.PdbOutputInfo pdbOutputInfo,
EmitStreamProvider pdbStreamProvider,
Func<object> testSymWriterFactory,
DiagnosticBag diagnostics,
bool metadataOnly,
......@@ -1621,7 +1624,7 @@ private static EmitResult ToEmitResultAndFree(DiagnosticBag diagnostics, bool su
Stream signingInputStream = null;
DiagnosticBag metadataDiagnostics = null;
DiagnosticBag pdbBag = null;
Stream pdbOriginalStream = null;
Stream pdbStream = null;
Stream pdbTempStream = null;
Stream peStream = null;
Stream peTempStream = null;
......@@ -1630,29 +1633,36 @@ private static EmitResult ToEmitResultAndFree(DiagnosticBag diagnostics, bool su
try
{
if (pdbOutputInfo.IsValid)
if (pdbStreamProvider != null)
{
// The calls ISymUnmanagedWriter2.GetDebugInfo require a file name in order to succeed. This is
// frequently used during PDB writing. Ensure a name is provided here in the case we were given
// only a Stream value.
if (pdbOutputInfo.Stream != null && pdbOutputInfo.FileName == null)
Func<Stream> getNativePdbStream = () =>
{
pdbOutputInfo = new Cci.PdbOutputInfo(FileNameUtilities.ChangeExtension(SourceModule.Name, "pdb"), pdbOutputInfo.Stream);
}
pdbStream = pdbStreamProvider.GetStream(diagnostics);
if (pdbStream == null)
{
return null;
}
// Native PDB writer is able to update an existing stream.
// It checks for length to determine whether the given stream has existing data to be updated,
// or whether it should start writing PDB data from scratch. Thus if not writing to a seekable empty stream ,
// let's create an in-memory temp stream for the PDB writer and copy all data to the actual stream at once at the end.
if (pdbOutputInfo.Stream != null && (!pdbOutputInfo.Stream.CanSeek || pdbOutputInfo.Stream.Length != 0))
{
pdbOriginalStream = pdbOutputInfo.Stream;
pdbTempStream = new MemoryStream();
pdbOutputInfo = pdbOutputInfo.WithStream(pdbTempStream);
}
var retStream = pdbStream;
// Native PDB writer is able to update an existing stream.
// It checks for length to determine whether the given stream has existing data to be updated,
// or whether it should start writing PDB data from scratch. Thus if not writing to a seekable empty stream ,
// let's create an in-memory temp stream for the PDB writer and copy all data to the actual stream at once at the end.
if (!retStream.CanSeek || retStream.Length != 0)
{
retStream = pdbTempStream = new MemoryStream();
}
return retStream;
};
// The calls ISymUnmanagedWriter2.GetDebugInfo require a file name in order to succeed. This is
// frequently used during PDB writing. Ensure a name is provided here in the case we were given
// only a Stream value.
nativePdbWriter = new Cci.PdbWriter(
pdbOutputInfo,
getNativePdbStream,
moduleBeingBuilt.EmitOptions.PdbFilePath ?? FileNameUtilities.ChangeExtension(SourceModule.Name, "pdb"),
testSymWriterFactory);
}
......@@ -1719,7 +1729,7 @@ private static EmitResult ToEmitResultAndFree(DiagnosticBag diagnostics, bool su
nativePdbWriter.WritePdbToOutput();
pdbTempStream.Position = 0;
pdbTempStream.CopyTo(pdbOriginalStream);
pdbTempStream.CopyTo(pdbStream);
}
}
catch (Cci.PdbWritingException ex)
......@@ -1772,7 +1782,57 @@ private static EmitResult ToEmitResultAndFree(DiagnosticBag diagnostics, bool su
return true;
}
private Dictionary<string, string> _lazyFeatures;
internal EmitBaseline SerializeToDeltaStreams(
CommonPEModuleBuilder moduleBeingBuilt,
EmitBaseline baseline,
DefinitionMap definitionMap,
SymbolChanges changes,
Stream metadataStream,
Stream ilStream,
Stream pdbStream,
ICollection<MethodDefinitionHandle> updatedMethods,
DiagnosticBag diagnostics,
Func<object> testSymWriterFactory,
CancellationToken cancellationToken)
{
using (var pdbWriter = new Cci.PdbWriter(
() => pdbStream,
moduleBeingBuilt.EmitOptions.PdbFilePath ?? FileNameUtilities.ChangeExtension(SourceModule.Name, "pdb"),
testSymWriterFactory))
{
var context = new EmitContext((Cci.IModule)moduleBeingBuilt, null, diagnostics);
var encId = Guid.NewGuid();
try
{
var writer = new DeltaMetadataWriter(
context,
MessageProvider,
baseline,
encId,
definitionMap,
changes,
cancellationToken);
Cci.MetadataSizes metadataSizes;
writer.WriteMetadataAndIL(pdbWriter, metadataStream, ilStream, out metadataSizes);
writer.GetMethodTokens(updatedMethods);
return diagnostics.HasAnyErrors() ? null : writer.GetDelta(baseline, this, encId, metadataSizes);
}
catch (Cci.PdbWritingException e)
{
diagnostics.Add(MessageProvider.CreateDiagnostic(MessageProvider.ERR_PdbWritingFailed, Location.None, e.Message));
return null;
}
catch (PermissionSetFileReadException e)
{
diagnostics.Add(MessageProvider.CreateDiagnostic(MessageProvider.ERR_PermissionSetAttributeFileReadError, Location.None, e.FileName, e.PropertyName, e.Message));
return null;
}
}
}
internal string Feature(string p)
{
if (_lazyFeatures == null)
......
......@@ -21,7 +21,17 @@ internal struct AnonymousTypeKeyField : IEquatable<AnonymousTypeKeyField>
/// </summary>
internal readonly bool IsKey;
internal AnonymousTypeKeyField(string name, bool isKey = false)
internal static AnonymousTypeKeyField CreateField(string name)
{
return new AnonymousTypeKeyField(name, isKey: false);
}
internal static AnonymousTypeKeyField CreateField(string name, bool isKey)
{
return new AnonymousTypeKeyField(name.ToLowerInvariant(), isKey);
}
private AnonymousTypeKeyField(string name, bool isKey)
{
this.Name = name;
this.IsKey = isKey;
......
......@@ -29,64 +29,6 @@ internal sealed class PdbWritingException : Exception
}
}
/// <summary>
/// This struct abstracts away the possible values for specifying the output information
/// for a PDB. It is legal to specify a file name, a stream or both. In the case both
/// are specified though the <see cref="Stream"/> value will be preferred.
/// </summary>
/// <remarks>
/// The file name is still used within the PDB writing code hence is not completely
/// redundant in the face of a <see cref="Stream"/> value.
/// </remarks>
internal struct PdbOutputInfo
{
internal static PdbOutputInfo None
{
get { return new PdbOutputInfo(); }
}
internal readonly string FileName;
internal readonly Stream Stream;
internal bool IsNone
{
get { return FileName == null && Stream == null; }
}
internal bool IsValid
{
get { return !IsNone; }
}
internal PdbOutputInfo(string fileName)
{
Debug.Assert(fileName != null);
FileName = fileName;
Stream = null;
}
internal PdbOutputInfo(Stream stream)
{
FileName = null;
Stream = stream;
}
internal PdbOutputInfo(string fileName, Stream stream)
{
Debug.Assert(fileName != null);
Debug.Assert(stream != null && stream.CanWrite);
FileName = fileName;
Stream = stream;
}
internal PdbOutputInfo WithStream(Stream stream)
{
return FileName != null
? new PdbOutputInfo(FileName, stream)
: new PdbOutputInfo(stream);
}
}
internal sealed class PdbWriter : IDisposable
{
internal const uint HiddenLocalAttributesValue = 1u;
......@@ -94,7 +36,8 @@ internal sealed class PdbWriter : IDisposable
private static Type s_lazyCorSymWriterSxSType;
private readonly PdbOutputInfo _pdbOutputInfo;
private readonly Func<Stream> _streamProvider;
private readonly string _fileName;
private readonly Func<object> _symWriterFactory;
private MetadataWriter _metadataWriter;
private ISymUnmanagedWriter2 _symWriter;
......@@ -111,10 +54,11 @@ internal sealed class PdbWriter : IDisposable
private uint[] _sequencePointEndLines;
private uint[] _sequencePointEndColumns;
public PdbWriter(PdbOutputInfo pdbOutputInfo, Func<object> symWriterFactory = null)
public PdbWriter(Func<Stream> streamProvider, string fileName, Func<object> symWriterFactory = null)
{
Debug.Assert(pdbOutputInfo.IsValid);
_pdbOutputInfo = pdbOutputInfo;
Debug.Assert(streamProvider != null);
_streamProvider = streamProvider;
_fileName = fileName;
_symWriterFactory = symWriterFactory;
CreateSequencePointBuffers(capacity: 64);
}
......@@ -131,8 +75,8 @@ public void Dispose()
}
/// <summary>
/// Close the PDB writer and write the contents to the location specified by the <see cref="PdbOutputInfo"/>
/// value. If a file name was specified this is the method which will cause it to be created.
/// Close the PDB writer and write the contents to the stream provided by <see cref="_streamProvider"/>
/// or file name specified by <see cref="_fileName"/> value if no stream has been provided.
/// </summary>
public void WritePdbToOutput()
{
......@@ -615,11 +559,14 @@ private static Type GetCorSymWriterSxSType()
public void SetMetadataEmitter(MetadataWriter metadataWriter)
{
Stream streamOpt = _streamProvider();
try
{
var instance = (ISymUnmanagedWriter2)(_symWriterFactory != null ? _symWriterFactory() : Activator.CreateInstance(GetCorSymWriterSxSType()));
var comStream = _pdbOutputInfo.Stream != null ? new ComStreamWrapper(_pdbOutputInfo.Stream) : null;
instance.Initialize(new PdbMetadataWrapper(metadataWriter), _pdbOutputInfo.FileName, comStream, fullBuild: true);
var comStream = (streamOpt != null) ? new ComStreamWrapper(streamOpt) : null;
instance.Initialize(new PdbMetadataWrapper(metadataWriter), _fileName, comStream, fullBuild: true);
_metadataWriter = metadataWriter;
_symWriter = instance;
......
......@@ -55,11 +55,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit
testData.Module = moduleBeingBuilt
End If
baseline = moduleBeingBuilt.PreviousGeneration
Dim definitionMap = moduleBeingBuilt.PreviousDefinitions
Dim changes = moduleBeingBuilt.Changes
Dim newBaseline As EmitBaseline = Nothing
If compilation.Compile(moduleBeingBuilt,
win32Resources:=Nothing,
xmlDocStream:=Nothing,
......@@ -71,43 +71,26 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit
' Map the definitions from the previous compilation to the current compilation.
' This must be done after compiling above since synthesized definitions
' (generated when compiling method bodies) may be required.
baseline = MapToCompilation(compilation, moduleBeingBuilt)
Dim pdbOutputInfo = New Cci.PdbOutputInfo(pdbName, pdbStream)
Using pdbWriter = New Cci.PdbWriter(pdbOutputInfo, If(testData IsNot Nothing, testData.SymWriterFactory, Nothing))
Dim context = New EmitContext(moduleBeingBuilt, Nothing, diagnostics)
Dim encId = Guid.NewGuid()
Try
Dim writer = New DeltaMetadataWriter(
context,
compilation.MessageProvider,
baseline,
encId,
definitionMap,
changes,
cancellationToken)
Dim metadataSizes As Cci.MetadataSizes = Nothing
writer.WriteMetadataAndIL(pdbWriter, metadataStream, ilStream, metadataSizes)
writer.GetMethodTokens(updatedMethods)
Dim hasErrors = diagnostics.HasAnyErrors()
Return New EmitDifferenceResult(
success:=Not hasErrors,
diagnostics:=diagnostics.ToReadOnlyAndFree(),
baseline:=If(hasErrors, Nothing, writer.GetDelta(baseline, compilation, encId, metadataSizes)))
Catch e As Cci.PdbWritingException
diagnostics.Add(ERRID.ERR_PDBWritingFailed, Location.None, e.Message)
Catch e As PermissionSetFileReadException
diagnostics.Add(ERRID.ERR_PermissionSetAttributeFileReadError, Location.None, e.FileName, e.PropertyName, e.Message)
End Try
End Using
Dim mappedBaseline = MapToCompilation(compilation, moduleBeingBuilt)
newBaseline = compilation.SerializeToDeltaStreams(
moduleBeingBuilt,
mappedBaseline,
definitionMap,
changes,
metadataStream,
ilStream,
pdbStream,
updatedMethods,
diagnostics,
testData?.SymWriterFactory,
cancellationToken)
End If
Return New EmitDifferenceResult(success:=False, diagnostics:=diagnostics.ToReadOnlyAndFree(), baseline:=Nothing)
Return New EmitDifferenceResult(
success:=newBaseline IsNot Nothing,
diagnostics:=diagnostics.ToReadOnlyAndFree(),
baseline:=newBaseline)
End Function
Friend Function MapToCompilation(
......
......@@ -117,7 +117,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit
Dim index = typeParameter.Ordinal
Debug.Assert(properties(index).Name Is Nothing)
' ReadOnly anonymous type properties were 'Key' properties.
properties(index) = New AnonymousTypeKeyField([property].Name, [property].IsReadOnly)
properties(index) = AnonymousTypeKeyField.CreateField([property].Name, isKey:=[property].IsReadOnly)
End If
Next
......@@ -135,8 +135,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit
Dim method = DirectCast(members(0), MethodSymbol)
Debug.Assert(method.Parameters.Count + If(method.IsSub, 0, 1) = type.TypeParameters.Length)
Dim parameters = ArrayBuilder(Of AnonymousTypeKeyField).GetInstance()
parameters.AddRange(method.Parameters.SelectAsArray(Function(p) New AnonymousTypeKeyField(p.Name)))
parameters.Add(New AnonymousTypeKeyField(AnonymousTypeDescriptor.GetReturnParameterName(Not method.IsSub)))
parameters.AddRange(method.Parameters.SelectAsArray(Function(p) AnonymousTypeKeyField.CreateField(p.Name, isKey:=False)))
parameters.Add(AnonymousTypeKeyField.CreateField(AnonymousTypeDescriptor.GetReturnParameterName(Not method.IsSub), isKey:=False))
Return New AnonymousTypeKey(parameters.ToImmutableAndFree(), isDelegate:=True)
End Function
......
......@@ -2,8 +2,8 @@
Imports System.Collections.Generic
Imports System.Collections.Immutable
Imports System.Threading
Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.Emit
Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
Partial Friend NotInheritable Class AnonymousTypeManager
......@@ -124,9 +124,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
parameters.Free()
End Sub
Friend Overrides Function GetAnonymousTypeKey() As Microsoft.CodeAnalysis.Emit.AnonymousTypeKey
Dim parameters = TypeDescr.Parameters.SelectAsArray(Function(p) New Microsoft.CodeAnalysis.Emit.AnonymousTypeKeyField(p.Name))
Return New Microsoft.CodeAnalysis.Emit.AnonymousTypeKey(parameters, isDelegate:=True)
Friend Overrides Function GetAnonymousTypeKey() As AnonymousTypeKey
Dim parameters = TypeDescr.Parameters.SelectAsArray(Function(p) AnonymousTypeKeyField.CreateField(p.Name, isKey:=False))
Return New AnonymousTypeKey(parameters, isDelegate:=True)
End Function
Public Overrides Function GetMembers() As ImmutableArray(Of Symbol)
......@@ -170,7 +170,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
End Get
End Property
Friend Overrides Sub AddSynthesizedAttributes(compilationState as ModuleCompilationState, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData))
Friend Overrides Sub AddSynthesizedAttributes(compilationState As ModuleCompilationState, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData))
MyBase.AddSynthesizedAttributes(compilationState, attributes)
' Attribute: System.Runtime.CompilerServices.CompilerGeneratedAttribute()
......
......@@ -2,9 +2,9 @@
Imports System.Collections.Generic
Imports System.Collections.Immutable
Imports System.Threading
Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.Collections
Imports Microsoft.CodeAnalysis.Emit
Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
......@@ -91,9 +91,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
End Sub
Friend Overrides Function GetAnonymousTypeKey() As Microsoft.CodeAnalysis.Emit.AnonymousTypeKey
Dim properties = _properties.SelectAsArray(Function(p) New Microsoft.CodeAnalysis.Emit.AnonymousTypeKeyField(p.Name, p.IsReadOnly))
Return New Microsoft.CodeAnalysis.Emit.AnonymousTypeKey(properties)
Friend Overrides Function GetAnonymousTypeKey() As AnonymousTypeKey
Dim properties = _properties.SelectAsArray(Function(p) AnonymousTypeKeyField.CreateField(p.Name, isKey:=p.IsReadOnly))
Return New AnonymousTypeKey(properties)
End Function
Friend Overrides ReadOnly Property GeneratedNamePrefix As String
......@@ -140,7 +140,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
End Get
End Property
Friend Overrides Sub AddSynthesizedAttributes(compilationState as ModuleCompilationState, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData))
Friend Overrides Sub AddSynthesizedAttributes(compilationState As ModuleCompilationState, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData))
MyBase.AddSynthesizedAttributes(compilationState, attributes)
' Attribute: System.Runtime.CompilerServices.CompilerGeneratedAttribute()
......
' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

' Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
Imports Microsoft.CodeAnalysis.Test.Utilities
Imports System
Imports System.Collections.Generic
Imports System.Collections.Immutable
Imports System.Linq
Imports System.Threading
Imports Xunit
Imports Microsoft.CodeAnalysis.Test.Utilities
Imports Roslyn.Test.Utilities
Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Emit
Public Class DeterministicTests : Inherits BasicTestBase
Public Class DeterministicTests
Inherits BasicTestBase
Private Function GetBytesEmitted(source As String, platform As Platform, debug As Boolean, deterministic As Boolean) As ImmutableArray(Of Byte)
Private Function GetBytesEmitted(source As String, platform As Platform, debug As Boolean) As ImmutableArray(Of Byte)
Dim options = If(debug, TestOptions.DebugExe, TestOptions.ReleaseExe).WithPlatform(platform)
If deterministic Then
options = options.WithFeatures({"dEtErmInIstIc"}.AsImmutable()) ' expect case-insensitivity
End If
options = options.WithFeatures({"dEtErmInIstIc"}.AsImmutable()) ' expect case-insensitivity
Dim compilation = CreateCompilationWithMscorlib({source}, assemblyName:="DeterminismTest", compOptions:=options)
......@@ -27,40 +26,36 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests.Emit
Return compilation.EmitToArray()
End Function
Private Class ImmutableByteArrayEqualityComparer : Implements IEqualityComparer(Of ImmutableArray(Of Byte))
Public Overloads Function Equals(x As ImmutableArray(Of Byte), y As ImmutableArray(Of Byte)) As Boolean Implements IEqualityComparer(Of ImmutableArray(Of Byte)).Equals
Return x.SequenceEqual(y)
End Function
Public Overloads Function GetHashCode(obj As ImmutableArray(Of Byte)) As Integer Implements IEqualityComparer(Of ImmutableArray(Of Byte)).GetHashCode
Return obj.GetHashCode()
End Function
End Class
<Fact>
Public Sub CompareAllBytesEmitted()
Public Sub CompareAllBytesEmitted_Release()
Dim source =
"Class Program
Shared Sub Main()
End Sub
End Class"
Dim comparer = New ImmutableByteArrayEqualityComparer()
Dim result1 = GetBytesEmitted(source, platform:=Platform.AnyCpu32BitPreferred, debug:=False)
Dim result2 = GetBytesEmitted(source, platform:=Platform.AnyCpu32BitPreferred, debug:=False)
AssertEx.Equal(result1, result2)
Dim result1 = GetBytesEmitted(source, platform:=Platform.AnyCpu32BitPreferred, debug:=True, deterministic:=True)
Dim result2 = GetBytesEmitted(source, platform:=Platform.AnyCpu32BitPreferred, debug:=True, deterministic:=True)
Assert.Equal(result1, result2, comparer)
Dim result3 = GetBytesEmitted(source, platform:=Platform.X64, debug:=False)
Dim result4 = GetBytesEmitted(source, platform:=Platform.X64, debug:=False)
AssertEx.Equal(result3, result4)
End Sub
Dim result3 = GetBytesEmitted(source, platform:=Platform.X64, debug:=False, deterministic:=True)
Dim result4 = GetBytesEmitted(source, platform:=Platform.X64, debug:=False, deterministic:=True)
Assert.Equal(result3, result4, comparer)
Assert.NotEqual(result1, result3, comparer)
<Fact(Skip:="https://github.com/dotnet/roslyn/issues/926"), WorkItem(926)>
Public Sub CompareAllBytesEmitted_Debug()
Dim source =
"Class Program
Shared Sub Main()
End Sub
End Class"
Dim result1 = GetBytesEmitted(source, platform:=Platform.AnyCpu32BitPreferred, debug:=True)
Dim result2 = GetBytesEmitted(source, platform:=Platform.AnyCpu32BitPreferred, debug:=True)
AssertEx.Equal(result1, result2)
Dim result5 = GetBytesEmitted(source, platform:=Platform.X64, debug:=False, deterministic:=False)
Dim result6 = GetBytesEmitted(source, platform:=Platform.X64, debug:=False, deterministic:=False)
Assert.NotEqual(result5, result6, comparer)
Assert.NotEqual(result3, result5, comparer)
Dim result3 = GetBytesEmitted(source, platform:=Platform.X64, debug:=True)
Dim result4 = GetBytesEmitted(source, platform:=Platform.X64, debug:=True)
AssertEx.Equal(result3, result4)
End Sub
End Class
End Namespace
......@@ -3746,6 +3746,114 @@ End Class
End Using
End Sub
<Fact>
Public Sub AnonymousTypes_DifferentCase()
Dim sources0 = <compilation>
<file name="a.vb"><![CDATA[
Class C
Shared Sub M()
Dim x As New With {.A = 1, .B = 2}
Dim y As New With {.a = 3, .b = 4}
End Sub
End Class
]]></file>
</compilation>
Dim sources1 = <compilation>
<file name="a.vb"><![CDATA[
Class C
Shared Sub M()
Dim x As New With {.a = 1, .B = 2}
Dim y As New With {.AB = 3}
Dim z As New With {.ab = 4}
End Sub
End Class
]]></file>
</compilation>
Dim sources2 = <compilation>
<file name="a.vb"><![CDATA[
Class C
Shared Sub M()
Dim x As New With {.a = 1, .B = 2}
Dim z As New With {.Ab = 5}
End Sub
End Class
]]></file>
</compilation>
Dim compilation0 = CreateCompilationWithMscorlib(sources0, TestOptions.DebugDll)
Dim compilation1 = compilation0.WithSource(sources1)
Dim compilation2 = compilation1.WithSource(sources2)
Dim testData0 = New CompilationTestData()
Dim bytes0 = compilation0.EmitToArray(testData:=testData0)
Using md0 = ModuleMetadata.CreateFromImage(bytes0)
Dim generation0 = EmitBaseline.CreateInitialBaseline(ModuleMetadata.CreateFromImage(bytes0),
testData0.GetMethodData("C.M").EncDebugInfoProvider)
Dim method0 = compilation0.GetMember(Of MethodSymbol)("C.M")
Dim reader0 = md0.MetadataReader
CheckNames(reader0, reader0.GetTypeDefNames(),
"<Module>",
"VB$AnonymousType_0`2",
"C")
Dim method1 = compilation1.GetMember(Of MethodSymbol)("C.M")
Dim diff1 = compilation1.EmitDifference(
generation0,
ImmutableArray.Create(New SemanticEdit(SemanticEditKind.Update, method0, method1, GetEquivalentNodesMap(method1, method0), preserveLocalVariables:=True)))
Using md1 = diff1.GetMetadata()
Dim reader1 = md1.Reader
CheckNames({reader0, reader1}, reader1.GetTypeDefNames(), "VB$AnonymousType_1`1")
diff1.VerifyIL("C.M",
"{
// Code size 25 (0x19)
.maxstack 2
.locals init ([unchanged] V_0,
[unchanged] V_1,
VB$AnonymousType_0(Of Integer, Integer) V_2, //x
VB$AnonymousType_1(Of Integer) V_3, //y
VB$AnonymousType_1(Of Integer) V_4) //z
IL_0000: nop
IL_0001: ldc.i4.1
IL_0002: ldc.i4.2
IL_0003: newobj ""Sub VB$AnonymousType_0(Of Integer, Integer)..ctor(Integer, Integer)""
IL_0008: stloc.2
IL_0009: ldc.i4.3
IL_000a: newobj ""Sub VB$AnonymousType_1(Of Integer)..ctor(Integer)""
IL_000f: stloc.3
IL_0010: ldc.i4.4
IL_0011: newobj ""Sub VB$AnonymousType_1(Of Integer)..ctor(Integer)""
IL_0016: stloc.s V_4
IL_0018: ret
}")
Dim method2 = compilation2.GetMember(Of MethodSymbol)("C.M")
Dim diff2 = compilation2.EmitDifference(
diff1.NextGeneration,
ImmutableArray.Create(New SemanticEdit(SemanticEditKind.Update, method1, method2, GetEquivalentNodesMap(method2, method1), preserveLocalVariables:=True)))
Using md2 = diff2.GetMetadata()
Dim reader2 = md2.Reader
CheckNames({reader0, reader1, reader2}, reader2.GetTypeDefNames())
diff2.VerifyIL("C.M",
"{
// Code size 18 (0x12)
.maxstack 2
.locals init ([unchanged] V_0,
[unchanged] V_1,
VB$AnonymousType_0(Of Integer, Integer) V_2, //x
[unchanged] V_3,
[unchanged] V_4,
VB$AnonymousType_1(Of Integer) V_5) //z
IL_0000: nop
IL_0001: ldc.i4.1
IL_0002: ldc.i4.2
IL_0003: newobj ""Sub VB$AnonymousType_0(Of Integer, Integer)..ctor(Integer, Integer)""
IL_0008: stloc.2
IL_0009: ldc.i4.5
IL_000a: newobj ""Sub VB$AnonymousType_1(Of Integer)..ctor(Integer)""
IL_000f: stloc.s V_5
IL_0011: ret
}")
End Using
End Using
End Using
End Sub
''' <summary>
''' Should not re-use locals with custom modifiers.
''' </summary>
......
......@@ -35,7 +35,7 @@ internal static void TestNotReusedOnAssemblyDiffers(string projectLanguage)
var metadataProject = context.CurrentSolution
.AddProject(projectId, "Metadata", "Metadata", LanguageNames.CSharp).GetProject(projectId)
.AddMetadataReference(TestReferences.NetFx.v4_0_30319.mscorlib)
.WithCompilationOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
.WithCompilationOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, optimizationLevel: OptimizationLevel.Release));
var references = new List<MetadataReference>();
......
......@@ -637,16 +637,16 @@ public void TestThrowsOnGenerateNamespace()
using (var context = new TestContext())
{
Assert.Throws<ArgumentException>(() =>
{
try
{
context.GenerateSource(namespaceSymbol);
}
catch (AggregateException ae)
{
throw ae.InnerException;
}
});
{
try
{
context.GenerateSource(namespaceSymbol);
}
catch (AggregateException ae)
{
throw ae.InnerException;
}
});
}
}
......
......@@ -22,10 +22,11 @@ public static class CompilationExtensions
DiagnosticDescription[] expectedWarnings = null)
{
var stream = new MemoryStream();
MemoryStream pdbStream = (compilation.Options.OptimizationLevel == OptimizationLevel.Debug) ? new MemoryStream() : null;
var emitResult = compilation.Emit(
peStream: stream,
pdbStream: null,
pdbStream: pdbStream,
xmlDocumentationStream: null,
win32Resources: null,
manifestResources: null,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册