提交 ddd5d88d 编写于 作者: D David Poeschl

Revert "Make compilation outputs available via a workspace service (#34809)"

This reverts commit 3bdbd560.
上级 6a63e85c
......@@ -1792,35 +1792,30 @@ public void Debug()
parsedArgs.Errors.Verify();
Assert.False(parsedArgs.CompilationOptions.DebugPlusMode);
Assert.False(parsedArgs.EmitPdb);
Assert.False(parsedArgs.EmitPdbFile);
Assert.Equal(parsedArgs.EmitOptions.DebugInformationFormat, platformPdbKind);
parsedArgs = DefaultParse(new[] { "/debug-", "a.cs" }, WorkingDirectory);
parsedArgs.Errors.Verify();
Assert.False(parsedArgs.CompilationOptions.DebugPlusMode);
Assert.False(parsedArgs.EmitPdb);
Assert.False(parsedArgs.EmitPdbFile);
Assert.Equal(parsedArgs.EmitOptions.DebugInformationFormat, platformPdbKind);
parsedArgs = DefaultParse(new[] { "/debug", "a.cs" }, WorkingDirectory);
parsedArgs.Errors.Verify();
Assert.False(parsedArgs.CompilationOptions.DebugPlusMode);
Assert.True(parsedArgs.EmitPdb);
Assert.True(parsedArgs.EmitPdbFile);
Assert.Equal(parsedArgs.EmitOptions.DebugInformationFormat, platformPdbKind);
parsedArgs = DefaultParse(new[] { "/debug+", "a.cs" }, WorkingDirectory);
parsedArgs.Errors.Verify();
Assert.True(parsedArgs.CompilationOptions.DebugPlusMode);
Assert.True(parsedArgs.EmitPdb);
Assert.True(parsedArgs.EmitPdbFile);
Assert.Equal(parsedArgs.EmitOptions.DebugInformationFormat, platformPdbKind);
parsedArgs = DefaultParse(new[] { "/debug+", "/debug-", "a.cs" }, WorkingDirectory);
parsedArgs.Errors.Verify();
Assert.False(parsedArgs.CompilationOptions.DebugPlusMode);
Assert.False(parsedArgs.EmitPdb);
Assert.False(parsedArgs.EmitPdbFile);
Assert.Equal(parsedArgs.EmitOptions.DebugInformationFormat, platformPdbKind);
parsedArgs = DefaultParse(new[] { "/debug:full", "a.cs" }, WorkingDirectory);
......@@ -1834,7 +1829,6 @@ public void Debug()
Assert.False(parsedArgs.CompilationOptions.DebugPlusMode);
Assert.True(parsedArgs.EmitPdb);
Assert.Equal(parsedArgs.EmitOptions.DebugInformationFormat, platformPdbKind);
Assert.Equal(Path.Combine(WorkingDirectory, "a.pdb"), parsedArgs.GetPdbFilePath("a.dll"));
parsedArgs = DefaultParse(new[] { "/debug:pdbonly", "a.cs" }, WorkingDirectory);
parsedArgs.Errors.Verify();
......@@ -1847,14 +1841,12 @@ public void Debug()
Assert.False(parsedArgs.CompilationOptions.DebugPlusMode);
Assert.True(parsedArgs.EmitPdb);
Assert.Equal(parsedArgs.EmitOptions.DebugInformationFormat, DebugInformationFormat.PortablePdb);
Assert.Equal(Path.Combine(WorkingDirectory, "a.pdb"), parsedArgs.GetPdbFilePath("a.dll"));
parsedArgs = DefaultParse(new[] { "/debug:embedded", "a.cs" }, WorkingDirectory);
parsedArgs.Errors.Verify();
Assert.False(parsedArgs.CompilationOptions.DebugPlusMode);
Assert.True(parsedArgs.EmitPdb);
Assert.Equal(parsedArgs.EmitOptions.DebugInformationFormat, DebugInformationFormat.Embedded);
Assert.Equal(Path.Combine(WorkingDirectory, "a.pdb"), parsedArgs.GetPdbFilePath("a.dll"));
parsedArgs = DefaultParse(new[] { "/debug:PDBONLY", "a.cs" }, WorkingDirectory);
parsedArgs.Errors.Verify();
......@@ -1922,23 +1914,14 @@ public void Pdb()
{
var parsedArgs = DefaultParse(new[] { "/pdb:something", "a.cs" }, WorkingDirectory);
Assert.Equal(Path.Combine(WorkingDirectory, "something.pdb"), parsedArgs.PdbPath);
Assert.Equal(Path.Combine(WorkingDirectory, "something.pdb"), parsedArgs.GetPdbFilePath("a.dll"));
Assert.False(parsedArgs.EmitPdbFile);
parsedArgs = DefaultParse(new[] { "/pdb:something", "/debug:embedded", "a.cs" }, WorkingDirectory);
Assert.Equal(Path.Combine(WorkingDirectory, "something.pdb"), parsedArgs.PdbPath);
Assert.Equal(Path.Combine(WorkingDirectory, "something.pdb"), parsedArgs.GetPdbFilePath("a.dll"));
Assert.False(parsedArgs.EmitPdbFile);
parsedArgs = DefaultParse(new[] { "/debug", "a.cs" }, WorkingDirectory);
// No pdb
parsedArgs = DefaultParse(new[] { @"/debug", "a.cs" }, WorkingDirectory);
parsedArgs.Errors.Verify();
Assert.Null(parsedArgs.PdbPath);
Assert.True(parsedArgs.EmitPdbFile);
Assert.Equal(Path.Combine(WorkingDirectory, "a.pdb"), parsedArgs.GetPdbFilePath("a.dll"));
parsedArgs = DefaultParse(new[] { "/pdb", "/debug", "a.cs" }, WorkingDirectory);
parsedArgs.Errors.Verify(Diagnostic(ErrorCode.ERR_NoFileSpec).WithArguments("/pdb"));
Assert.Equal(Path.Combine(WorkingDirectory, "a.pdb"), parsedArgs.GetPdbFilePath("a.dll"));
parsedArgs = DefaultParse(new[] { "/pdb:", "/debug", "a.cs" }, WorkingDirectory);
parsedArgs.Errors.Verify(Diagnostic(ErrorCode.ERR_NoFileSpec).WithArguments("/pdb:"));
......@@ -3329,7 +3312,6 @@ public void ParseOut()
Assert.Equal("MyBinary.dll", parsedArgs.OutputFileName);
Assert.Equal("MyBinary.dll", parsedArgs.CompilationOptions.ModuleName);
Assert.Equal(@"C:\MyFolder", parsedArgs.OutputDirectory);
Assert.Equal(@"C:\MyFolder\MyBinary.dll", parsedArgs.GetOutputFilePath(parsedArgs.OutputFileName));
// Should handle quotes
parsedArgs = DefaultParse(new[] { @"/out:""C:\My Folder\MyBinary.dll""", "a.cs" }, baseDirectory);
......@@ -3346,7 +3328,6 @@ public void ParseOut()
Assert.Equal("MyBinary.dll", parsedArgs.OutputFileName);
Assert.Equal("MyBinary.dll", parsedArgs.CompilationOptions.ModuleName);
Assert.Equal(baseDirectory, parsedArgs.OutputDirectory);
Assert.Equal(Path.Combine(baseDirectory, "MyBinary.dll"), parsedArgs.GetOutputFilePath(parsedArgs.OutputFileName));
// Should expand partially qualified paths
parsedArgs = DefaultParse(new[] { @"/out:..\MyBinary.dll", "a.cs" }, baseDirectory);
......
......@@ -292,51 +292,6 @@ internal CommandLineArguments()
{
}
/// <summary>
/// Returns a full path of the file that the compiler will generate the assembly to if compilation succeeds.
/// </summary>
/// <remarks>
/// The method takes <paramref name="outputFileName"/> rather than using the value of <see cref="OutputFileName"/>
/// since the latter might be unspecified, in which case actual output path can't be determined for C# command line
/// without creating a compilation and finding an entry point. VB does not allow <see cref="OutputFileName"/> to
/// be unspecified.
/// </remarks>
public string GetOutputFilePath(string outputFileName)
{
if (outputFileName == null)
{
throw new ArgumentNullException(nameof(outputFileName));
}
return Path.Combine(OutputDirectory, outputFileName);
}
/// <summary>
/// Returns a full path of the PDB file that the compiler will generate the debug symbols to
/// if <see cref="EmitPdbFile"/> is true and the compilation succeeds.
/// </summary>
/// <remarks>
/// The method takes <paramref name="outputFileName"/> rather than using the value of <see cref="OutputFileName"/>
/// since the latter might be unspecified, in which case actual output path can't be determined for C# command line
/// without creating a compilation and finding an entry point. VB does not allow <see cref="OutputFileName"/> to
/// be unspecified.
/// </remarks>
public string GetPdbFilePath(string outputFileName)
{
if (outputFileName == null)
{
throw new ArgumentNullException(nameof(outputFileName));
}
return PdbPath ?? Path.Combine(OutputDirectory, Path.ChangeExtension(outputFileName, ".pdb"));
}
/// <summary>
/// Returns true if the PDB is generated to a PDB file, as opposed to embedded to the output binary and not generated at all.
/// </summary>
public bool EmitPdbFile
=> EmitPdb && EmitOptions.DebugInformationFormat != DebugInformationFormat.Embedded;
#region Metadata References
/// <summary>
......
......@@ -870,8 +870,8 @@ private int RunCore(TextWriter consoleOutput, ErrorLogger errorLogger, Cancellat
cancellationToken.ThrowIfCancellationRequested();
string outputName = GetOutputFileName(compilation, cancellationToken);
var finalPeFilePath = Arguments.GetOutputFilePath(outputName);
var finalPdbFilePath = Arguments.GetPdbFilePath(outputName);
var finalPeFilePath = Path.Combine(Arguments.OutputDirectory, outputName);
var finalPdbFilePath = Arguments.PdbPath ?? Path.ChangeExtension(finalPeFilePath, ".pdb");
var finalXmlFilePath = Arguments.DocumentationPath;
NoThrowStreamDisposer sourceLinkStreamDisposerOpt = null;
......@@ -1023,8 +1023,10 @@ private int RunCore(TextWriter consoleOutput, ErrorLogger errorLogger, Cancellat
if (success)
{
bool emitPdbFile = Arguments.EmitPdb && emitOptions.DebugInformationFormat != Emit.DebugInformationFormat.Embedded;
var peStreamProvider = new CompilerEmitStreamProvider(this, finalPeFilePath);
var pdbStreamProviderOpt = Arguments.EmitPdbFile ? new CompilerEmitStreamProvider(this, finalPdbFilePath) : null;
var pdbStreamProviderOpt = emitPdbFile ? new CompilerEmitStreamProvider(this, finalPdbFilePath) : null;
string finalRefPeFilePath = Arguments.OutputRefFilePath;
var refPeStreamProviderOpt = finalRefPeFilePath != null ? new CompilerEmitStreamProvider(this, finalRefPeFilePath) : null;
......
*REMOVED*Microsoft.CodeAnalysis.Operations.IEventAssignmentOperation.EventReference.get -> Microsoft.CodeAnalysis.Operations.IEventReferenceOperation
*REMOVED*Microsoft.CodeAnalysis.SpecialType.Count = 43 -> Microsoft.CodeAnalysis.SpecialType
Microsoft.CodeAnalysis.CommandLineArguments.EmitPdbFile.get -> bool
Microsoft.CodeAnalysis.CommandLineArguments.GetOutputFilePath(string outputFileName) -> string
Microsoft.CodeAnalysis.CommandLineArguments.GetPdbFilePath(string outputFileName) -> string
Microsoft.CodeAnalysis.IArrayTypeSymbol.ElementNullableAnnotation.get -> Microsoft.CodeAnalysis.NullableAnnotation
Microsoft.CodeAnalysis.IDiscardSymbol.NullableAnnotation.get -> Microsoft.CodeAnalysis.NullableAnnotation
Microsoft.CodeAnalysis.IEventSymbol.NullableAnnotation.get -> Microsoft.CodeAnalysis.NullableAnnotation
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.IO;
using System.Reflection.Metadata;
using System.Reflection;
using System.Reflection.Metadata.Ecma335;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Debugging;
using Microsoft.CodeAnalysis.EditAndContinue;
using Microsoft.CodeAnalysis.Emit;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.CodeAnalysis.UnitTests;
using Microsoft.DiaSymReader;
using Microsoft.DiaSymReader.PortablePdb;
using Moq;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.EditAndContinue.UnitTests
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.EditAndContinue
{
public class EditAndContinueMethodDebugInfoReaderTests
{
......@@ -23,24 +22,26 @@ private class DummyMetadataImportProvider : IMetadataImportProvider
public object GetMetadataImport() => throw new NotImplementedException();
}
[Fact]
public void Create_Errors()
private class DummySymReaderMetadataProvider : ISymReaderMetadataProvider
{
Assert.Throws<ArgumentNullException>(() => EditAndContinueMethodDebugInfoReader.Create((ISymUnmanagedReader5)null));
Assert.Throws<ArgumentNullException>(() => EditAndContinueMethodDebugInfoReader.Create((MetadataReader)null));
Assert.Throws<ArgumentNullException>(() => EditAndContinueMethodDebugInfoReader.Create(null, 1));
public unsafe bool TryGetStandaloneSignature(int standaloneSignatureToken, out byte* signature, out int length)
=> throw new NotImplementedException();
var mockSymReader = new Mock<ISymUnmanagedReader5>().Object;
Assert.Throws<ArgumentOutOfRangeException>(() => EditAndContinueMethodDebugInfoReader.Create(mockSymReader, 0));
Assert.Throws<ArgumentOutOfRangeException>(() => EditAndContinueMethodDebugInfoReader.Create(mockSymReader, -1));
public bool TryGetTypeDefinitionInfo(int typeDefinitionToken, out string namespaceName, out string typeName, out TypeAttributes attributes)
=> throw new NotImplementedException();
public bool TryGetTypeReferenceInfo(int typeReferenceToken, out string namespaceName, out string typeName)
=> throw new NotImplementedException();
}
[Theory]
[InlineData(DebugInformationFormat.PortablePdb, true)]
[InlineData(DebugInformationFormat.PortablePdb, false)]
[InlineData(DebugInformationFormat.Pdb, true)]
public void DebugInfo(DebugInformationFormat format, bool useSymReader)
[InlineData(DebugInformationFormat.PortablePdb)]
[InlineData(DebugInformationFormat.Pdb)]
public void DebugInfo(DebugInformationFormat format)
{
var symBinder = new SymBinder();
var metadataImportProvider = new DummyMetadataImportProvider();
var source = @"
using System;
delegate void D();
......@@ -60,22 +61,22 @@ public static void Main()
compilation.EmitToArray(new EmitOptions(debugInformationFormat: format), pdbStream: pdbStream);
pdbStream.Position = 0;
DebugInformationReaderProvider provider;
EditAndContinueMethodDebugInfoReader reader;
var pdbStreamCom = SymUnmanagedStreamFactory.CreateStream(pdbStream);
if (format == DebugInformationFormat.PortablePdb && useSymReader)
ISymUnmanagedReader5 symReader5;
if (format == DebugInformationFormat.PortablePdb)
{
var pdbStreamCom = SymUnmanagedStreamFactory.CreateStream(pdbStream);
var metadataImportProvider = new DummyMetadataImportProvider();
Assert.Equal(0, new SymBinder().GetReaderFromPdbStream(metadataImportProvider, pdbStreamCom, out var symReader));
reader = EditAndContinueMethodDebugInfoReader.Create((ISymUnmanagedReader5)symReader, version: 1);
int hr = symBinder.GetReaderFromPdbStream(metadataImportProvider, pdbStreamCom, out var symReader);
Assert.Equal(0, hr);
symReader5 = (ISymUnmanagedReader5)symReader;
}
else
{
provider = DebugInformationReaderProvider.CreateFromStream(pdbStream);
reader = provider.CreateEditAndContinueMethodDebugInfoReader();
symReader5 = SymUnmanagedReaderFactory.CreateReader<ISymUnmanagedReader5>(pdbStream, new DummySymReaderMetadataProvider());
}
var reader = EditAndContinueMethodDebugInfoReader.Create(symReader5, version: 1);
// Main method
var debugInfo = reader.GetDebugInfo(MetadataTokens.MethodDefinitionHandle(5));
Assert.Equal(0, debugInfo.GetMethodOrdinal());
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.Debugging.UnitTests
{
public class DebugInformationReaderProviderTests
{
[Fact]
public void CreateFrom_Errors()
{
Assert.Throws<ArgumentException>(() => DebugInformationReaderProvider.CreateFromStream(new TestStream(canRead: false, canSeek: true, canWrite: true)));
Assert.Throws<ArgumentException>(() => DebugInformationReaderProvider.CreateFromStream(new TestStream(canRead: true, canSeek: false, canWrite: true)));
Assert.Throws<ArgumentNullException>(() => DebugInformationReaderProvider.CreateFromStream(null));
Assert.Throws<ArgumentNullException>(() => DebugInformationReaderProvider.CreateFromMetadataReader(null));
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.IO;
using System.Reflection.Metadata.Ecma335;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.Emit.UnitTests
{
public class CompilationOutputFilesTests : TestBase
{
[Fact]
public void OpenStream_Errors()
{
Assert.Throws<ArgumentException>(() => new CompilationOutputFiles(@"a.dll"));
Assert.Throws<ArgumentException>(() => new CompilationOutputFiles(@"\a.dll", @"a.dll"));
}
[Fact]
public void AssemblyAndPdb()
{
var source = @"class C { public static void Main() { int x = 1; } }";
var compilation = CSharpTestBase.CreateCompilationWithMscorlib40AndSystemCore(source, options: TestOptions.DebugDll, assemblyName: "lib");
var pdbStream = new MemoryStream();
var peImage = compilation.EmitToArray(new EmitOptions(debugInformationFormat: DebugInformationFormat.PortablePdb), pdbStream: pdbStream);
pdbStream.Position = 0;
var dir = Temp.CreateDirectory();
var dllFile = dir.CreateFile("a.dll").WriteAllBytes(peImage);
var pdbFile = dir.CreateFile("a.pdb").WriteAllBytes(pdbStream.ToArray());
var outputs = new CompilationOutputFiles(dllFile.Path, pdbFile.Path);
using (var pdb = outputs.OpenPdb())
{
var encReader = pdb.CreateEditAndContinueMethodDebugInfoReader();
Assert.True(encReader.IsPortable);
var localSig = encReader.GetLocalSignature(MetadataTokens.MethodDefinitionHandle(1));
Assert.Equal(MetadataTokens.StandaloneSignatureHandle(1), localSig);
}
using (var metadata = outputs.OpenAssemblyMetadata(prefetch: false))
{
var mdReader = metadata.GetMetadataReader();
Assert.Equal("lib", mdReader.GetString(mdReader.GetAssemblyDefinition().Name));
}
// make sure all files are closed and can be deleted
Directory.Delete(dir.Path, recursive: true);
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.IO;
using System.Linq;
using System.Reflection.Metadata.Ecma335;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.Emit.UnitTests
{
public class CompilationOutputsTests
{
private class TestCompilationOutputs : CompilationOutputs
{
private readonly Func<Stream> _openAssemblyStream;
private readonly Func<Stream> _openPdbStream;
public TestCompilationOutputs(Func<Stream> openAssemblyStream = null, Func<Stream> openPdbStream = null)
{
_openAssemblyStream = openAssemblyStream;
_openPdbStream = openPdbStream;
}
public override string AssemblyDisplayPath => "assembly";
public override string PdbDisplayPath => "pdb";
protected override Stream OpenAssemblyStream() => (_openAssemblyStream ?? throw new NotImplementedException()).Invoke();
protected override Stream OpenPdbStream() => (_openPdbStream ?? throw new NotImplementedException()).Invoke();
}
[Theory]
[InlineData(true, false)]
[InlineData(false, true)]
public void OpenStream_Errors(bool canRead, bool canSeek)
{
var outputs = new TestCompilationOutputs(
openAssemblyStream: () => new TestStream(canRead, canSeek, canWrite: true),
openPdbStream: () => new TestStream(canRead, canSeek, canWrite: true));
Assert.Throws<InvalidOperationException>(() => outputs.OpenAssemblyMetadata(prefetch: false));
Assert.Throws<InvalidOperationException>(() => outputs.OpenPdb());
}
[Theory]
[InlineData(DebugInformationFormat.PortablePdb)]
[InlineData(DebugInformationFormat.Embedded)]
[InlineData(DebugInformationFormat.Pdb)]
public void AssemblyAndPdb(DebugInformationFormat format)
{
var source = @"class C { public static void Main() { int x = 1; } }";
var compilation = CSharpTestBase.CreateCompilationWithMscorlib40AndSystemCore(source, options: TestOptions.DebugDll, assemblyName: "lib");
var pdbStream = (format != DebugInformationFormat.Embedded) ? new MemoryStream() : null;
var peImage = compilation.EmitToArray(new EmitOptions(debugInformationFormat: format), pdbStream: pdbStream);
Stream currentPEStream = null;
Stream currentPdbStream = null;
var outputs = new TestCompilationOutputs(
openAssemblyStream: () => currentPEStream = new MemoryStream(peImage.ToArray()),
openPdbStream: () =>
{
if (pdbStream == null)
{
return null;
}
currentPdbStream = new MemoryStream();
pdbStream.Position = 0;
pdbStream.CopyTo(currentPdbStream);
currentPdbStream.Position = 0;
return currentPdbStream;
});
using (var pdb = outputs.OpenPdb())
{
var encReader = pdb.CreateEditAndContinueMethodDebugInfoReader();
Assert.Equal(format != DebugInformationFormat.Pdb, encReader.IsPortable);
var localSig = encReader.GetLocalSignature(MetadataTokens.MethodDefinitionHandle(1));
Assert.Equal(MetadataTokens.StandaloneSignatureHandle(1), localSig);
}
if (format == DebugInformationFormat.Embedded)
{
Assert.Throws<ObjectDisposedException>(() => currentPEStream.Length);
}
else
{
Assert.Throws<ObjectDisposedException>(() => currentPdbStream.Length);
}
using (var metadata = outputs.OpenAssemblyMetadata(prefetch: false))
{
Assert.NotEqual(0, currentPEStream.Length);
var mdReader = metadata.GetMetadataReader();
Assert.Equal("lib", mdReader.GetString(mdReader.GetAssemblyDefinition().Name));
}
Assert.Throws<ObjectDisposedException>(() => currentPEStream.Length);
using (var metadata = outputs.OpenAssemblyMetadata(prefetch: true))
{
// the stream has been closed since we prefetched the metadata:
Assert.Throws<ObjectDisposedException>(() => currentPEStream.Length);
var mdReader = metadata.GetMetadataReader();
Assert.Equal("lib", mdReader.GetString(mdReader.GetAssemblyDefinition().Name));
}
}
}
}
......@@ -10,7 +10,6 @@
<ProjectReference Include="..\..\Compilers\Core\Portable\Microsoft.CodeAnalysis.csproj" />
<ProjectReference Include="..\..\Compilers\CSharp\Portable\Microsoft.CodeAnalysis.CSharp.csproj" />
<ProjectReference Include="..\..\Compilers\Test\Resources\Core\Microsoft.CodeAnalysis.Compiler.Test.Resources.csproj" />
<ProjectReference Include="..\..\Compilers\Test\Utilities\CSharp\Microsoft.CodeAnalysis.CSharp.Test.Utilities.csproj" />
<ProjectReference Include="..\..\EditorFeatures\CSharp.Wpf\Microsoft.CodeAnalysis.CSharp.EditorFeatures.Wpf.csproj" />
<ProjectReference Include="..\..\Compilers\VisualBasic\Portable\Microsoft.CodeAnalysis.VisualBasic.vbproj" />
<ProjectReference Include="..\..\Test\PdbUtilities\Roslyn.Test.PdbUtilities.csproj" />
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.IO;
using System.Reflection;
using System.Reflection.Metadata;
using System.Runtime.InteropServices;
using System.Threading;
using Microsoft.CodeAnalysis.EditAndContinue;
using Microsoft.DiaSymReader;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Debugging
{
/// <summary>
/// An abstraction of a symbol reader that provides a reader of Edit and Continue debug information.
/// Owns the underlying PDB reader.
/// </summary>
internal abstract class DebugInformationReaderProvider : IDisposable
{
private sealed class DummySymReaderMetadataProvider : ISymReaderMetadataProvider
{
public static readonly DummySymReaderMetadataProvider Instance = new DummySymReaderMetadataProvider();
public unsafe bool TryGetStandaloneSignature(int standaloneSignatureToken, out byte* signature, out int length)
=> throw ExceptionUtilities.Unreachable;
public bool TryGetTypeDefinitionInfo(int typeDefinitionToken, out string namespaceName, out string typeName, out TypeAttributes attributes)
=> throw ExceptionUtilities.Unreachable;
public bool TryGetTypeReferenceInfo(int typeReferenceToken, out string namespaceName, out string typeName)
=> throw ExceptionUtilities.Unreachable;
}
private sealed class Portable : DebugInformationReaderProvider
{
private readonly MetadataReaderProvider _pdbReaderProvider;
public Portable(MetadataReaderProvider pdbReaderProvider)
=> _pdbReaderProvider = pdbReaderProvider;
public override EditAndContinueMethodDebugInfoReader CreateEditAndContinueMethodDebugInfoReader()
=> EditAndContinueMethodDebugInfoReader.Create(_pdbReaderProvider.GetMetadataReader());
public override void Dispose()
=> _pdbReaderProvider.Dispose();
}
private sealed class Native : DebugInformationReaderProvider
{
private readonly Stream _stream;
private readonly int _version;
private ISymUnmanagedReader5 _symReader;
public Native(Stream stream, ISymUnmanagedReader5 symReader, int version)
{
_stream = stream;
_symReader = symReader;
_version = version;
}
public override EditAndContinueMethodDebugInfoReader CreateEditAndContinueMethodDebugInfoReader()
=> EditAndContinueMethodDebugInfoReader.Create(_symReader, _version);
public override void Dispose()
{
_stream.Dispose();
var symReader = Interlocked.Exchange(ref _symReader, null);
if (symReader != null && Marshal.IsComObject(symReader))
{
Marshal.ReleaseComObject(symReader);
}
}
}
public abstract void Dispose();
/// <summary>
/// Creates EnC debug information reader.
/// </summary>
public abstract EditAndContinueMethodDebugInfoReader CreateEditAndContinueMethodDebugInfoReader();
/// <summary>
/// Creates <see cref="DebugInformationReaderProvider"/> from a stream of Portable or Windows PDB.
/// </summary>
/// <returns>
/// Provider instance, which keeps the <paramref name="stream"/> open until disposed.
/// </returns>
/// <remarks>
/// Requires Microsoft.DiaSymReader.Native.{platform}.dll to be available for reading Windows PDB.
/// </remarks>
/// <exception cref="ArgumentNullException"><paramref name="stream"/> is null.</exception>
/// <exception cref="ArgumentException"><paramref name="stream"/> does not support read and seek operations.</exception>
/// <exception cref="Exception">Error reading debug information from <paramref name="stream"/>.</exception>
public static DebugInformationReaderProvider CreateFromStream(Stream stream)
{
if (stream == null)
{
throw new ArgumentNullException(nameof(stream));
}
if (!stream.CanRead || !stream.CanSeek)
{
throw new ArgumentException(FeaturesResources.StreamMustSupportReadAndSeek, nameof(stream));
}
bool isPortable = stream.ReadByte() == 'B' && stream.ReadByte() == 'S' && stream.ReadByte() == 'J' && stream.ReadByte() == 'B';
stream.Position = 0;
if (isPortable)
{
return new Portable(MetadataReaderProvider.FromPortablePdbStream(stream));
}
// We can use DummySymReaderMetadataProvider since we do not need to decode signatures,
// which is the only operation SymReader needs the provider for.
return new Native(stream, SymUnmanagedReaderFactory.CreateReader<ISymUnmanagedReader5>(
stream, DummySymReaderMetadataProvider.Instance, SymUnmanagedReaderCreationOptions.UseAlternativeLoadPath), version: 1);
}
/// <summary>
/// Creates <see cref="DebugInformationReaderProvider"/> from a Portable PDB metadata reader provider.
/// </summary>
/// <returns>
/// Provider instance, which takes ownership of the <paramref name="metadataProvider"/> until disposed.
/// </returns>
/// <exception cref="ArgumentNullException"><paramref name="metadataProvider"/> is null.</exception>
public static DebugInformationReaderProvider CreateFromMetadataReader(MetadataReaderProvider metadataProvider)
=> new Portable(metadataProvider ?? throw new ArgumentNullException(nameof(metadataProvider)));
}
}
......@@ -139,32 +139,8 @@ private static bool TryGetCustomDebugInformation(MetadataReader reader, EntityHa
}
}
/// <summary>
/// Creates <see cref="EditAndContinueMethodDebugInfoReader"/> backed by a given <see cref="ISymUnmanagedReader5"/>.
/// </summary>
/// <param name="symReader">SymReader open on a Portable or Windows PDB.</param>
/// <param name="version">The version of the PDB to read.</param>
/// <exception cref="ArgumentNullException"><paramref name="symReader"/> is null.</exception>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="version"/> is less than 1.</exception>
/// <exception cref="COMException">Error reading debug information.</exception>
/// <returns>
/// The resulting reader does not take ownership of the <paramref name="symReader"/> or the memory it reads.
/// </returns>
/// <remarks>
/// Automatically detects the underlying PDB format and returns the appropriate reader.
/// </remarks>
public unsafe static EditAndContinueMethodDebugInfoReader Create(ISymUnmanagedReader5 symReader, int version = 1)
public unsafe static EditAndContinueMethodDebugInfoReader Create(ISymUnmanagedReader5 symReader, int version)
{
if (symReader == null)
{
throw new ArgumentNullException(nameof(symReader));
}
if (version <= 0)
{
throw new ArgumentOutOfRangeException(nameof(version));
}
int hr = symReader.GetPortableDebugMetadataByVersion(version, metadata: out byte* metadata, size: out int size);
Marshal.ThrowExceptionForHR(hr);
......@@ -177,16 +153,5 @@ public unsafe static EditAndContinueMethodDebugInfoReader Create(ISymUnmanagedRe
return new Native(symReader, version);
}
}
/// <summary>
/// Creates <see cref="EditAndContinueMethodDebugInfoReader"/> back by a given <see cref="MetadataReader"/>.
/// </summary>
/// <param name="pdbReader"><see cref="MetadataReader"/> open on a Portable PDB.</param>
/// <exception cref="ArgumentNullException"><paramref name="pdbReader"/> is null.</exception>
/// <returns>
/// The resulting reader does not take ownership of the <paramref name="pdbReader"/> or the memory it reads.
/// </returns>
public unsafe static EditAndContinueMethodDebugInfoReader Create(MetadataReader pdbReader)
=> new Portable(pdbReader ?? throw new ArgumentNullException(nameof(pdbReader)));
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.IO;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Emit
{
internal sealed class CompilationOutputFiles : CompilationOutputs
{
internal static readonly CompilationOutputFiles None = new CompilationOutputFiles();
public override string AssemblyDisplayPath => AssemblyFilePath;
public override string PdbDisplayPath => PdbFilePath;
public string PdbFilePath { get; }
public string AssemblyFilePath { get; }
public CompilationOutputFiles(string assemblyFilePath = null, string pdbFilePath = null)
{
if (assemblyFilePath != null)
{
CompilerPathUtilities.RequireAbsolutePath(assemblyFilePath, nameof(assemblyFilePath));
}
if (pdbFilePath != null)
{
CompilerPathUtilities.RequireAbsolutePath(pdbFilePath, nameof(pdbFilePath));
}
AssemblyFilePath = assemblyFilePath;
PdbFilePath = pdbFilePath;
}
/// <summary>
/// Opens an assembly file produced by the compiler (corresponds to OutputAssembly build task parameter).
/// </summary>
protected override Stream OpenAssemblyStream()
=> AssemblyFilePath != null ? FileUtilities.OpenRead(AssemblyFilePath) : null;
/// <summary>
/// Opens a PDB file produced by the compiler.
/// Returns null if the compiler generated no PDB (the symbols might be embedded in the assembly).
/// </summary>
/// <remarks>
/// The stream must be readable and seekable.
/// </remarks>
protected override Stream OpenPdbStream()
=> PdbFilePath != null ? FileUtilities.OpenRead(PdbFilePath) : null;
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.IO;
using System.Linq;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
using Microsoft.CodeAnalysis.Debugging;
namespace Microsoft.CodeAnalysis.Emit
{
/// <summary>
/// Reads compilation outputs such as output assembly and PDB.
/// </summary>
internal abstract class CompilationOutputs
{
/// <summary>
/// String describing the assembly to be used in user facing error messages (e.g. file path).
/// </summary>
public abstract string AssemblyDisplayPath { get; }
/// <summary>
/// String describing the PDB to be used in user facing error messages (e.g. file path).
/// </summary>
public abstract string PdbDisplayPath { get; }
/// <summary>
/// Opens metadata section of the assembly file produced by the compiler.
/// </summary>
/// <param name="prefetch">
/// True to prefetch all metadata from the assembly and close the underlying stream on return,
/// otherwise keeps the underlying stream open until the returned <see cref="MetadataReaderProvider"/> is disposed.
/// </param>
/// <returns>
/// Instance of <see cref="MetadataReaderProvider"/>, which owns the opened metadata and must be disposed once the caller is done reading the data,
/// or null if the assembly is not available.
/// </returns>
/// <exception cref="BadImageFormatException">Invalid format of the assembly data.</exception>
/// <exception cref="InvalidOperationException">The stream returned by <see cref="OpenAssemblyStreamChecked"/> does not support read and seek operations.</exception>
/// <exception cref="Exception">Error while reading assembly data.</exception>
public virtual MetadataReaderProvider OpenAssemblyMetadata(bool prefetch)
{
var peStream = OpenAssemblyStreamChecked();
if (peStream != null)
{
PEHeaders peHeaders;
using (var peReader = new PEReader(peStream, PEStreamOptions.LeaveOpen))
{
peHeaders = peReader.PEHeaders;
}
peStream.Position = peHeaders.MetadataStartOffset;
return MetadataReaderProvider.FromMetadataStream(
peStream,
prefetch ? MetadataStreamOptions.PrefetchMetadata : MetadataStreamOptions.Default,
size: peHeaders.MetadataSize);
}
return null;
}
/// <summary>
/// Opens PDB produced by the compiler.
/// The caller must dispose the returned <see cref="DebugInformationReaderProvider"/>.
/// </summary>
/// <returns>
/// Instance of <see cref="DebugInformationReaderProvider"/>, which owns the opened PDB and must be disposed once the caller is done reading the data,
/// or null if PDB is not available.
/// </returns>
/// <exception cref="BadImageFormatException">Invalid format of the PDB or assembly data.</exception>
/// <exception cref="InvalidOperationException">The stream returned by <see cref="OpenPdbStreamChecked"/> or <see cref="OpenAssemblyStreamChecked"/> does not support read and seek operations.</exception>
/// <exception cref="Exception">Error while reading assembly data.</exception>
/// <remarks>
/// If a separate PDB stream is not available (<see cref="OpenPdbStreamChecked"/> returns null) opens the PDB embedded in the assembly, if present.
/// </remarks>
public virtual DebugInformationReaderProvider OpenPdb()
{
var stream = OpenPdbStreamChecked();
if (stream != null)
{
return DebugInformationReaderProvider.CreateFromStream(stream);
}
// check for embedded PDB
using (var peReader = new PEReader(OpenAssemblyStreamChecked()))
{
var embeddedPdbEntry = peReader.ReadDebugDirectory().FirstOrDefault(e => e.Type == DebugDirectoryEntryType.EmbeddedPortablePdb);
if (embeddedPdbEntry.DataSize != 0)
{
return DebugInformationReaderProvider.CreateFromMetadataReader(peReader.ReadEmbeddedPortablePdbDebugDirectoryData(embeddedPdbEntry));
}
}
return null;
}
private Stream ValidateStream(Stream stream, string methodName)
{
if (stream != null && (!stream.CanRead || !stream.CanSeek))
{
throw new InvalidOperationException(string.Format(FeaturesResources.MethodMustReturnStreamThatSupportsReadAndSeek, methodName));
}
return stream;
}
private Stream OpenPdbStreamChecked()
=> ValidateStream(OpenPdbStream(), nameof(OpenPdbStream));
private Stream OpenAssemblyStreamChecked()
=> ValidateStream(OpenAssemblyStream(), nameof(OpenAssemblyStream));
/// <summary>
/// Opens an assembly file produced by the compiler.
/// </summary>
/// <remarks>
/// The stream must be readable and seekable.
/// </remarks>
/// <returns>New <see cref="Stream"/> instance or null if the assembly is not available.</returns>
protected abstract Stream OpenAssemblyStream();
/// <summary>
/// Opens a PDB file produced by the compiler.
/// </summary>
/// <remarks>
/// The stream must be readable and seekable.
/// </remarks>
/// <returns>New <see cref="Stream"/> instance or null if the compiler generated no PDB (the symbols might be embedded in the assembly).</returns>
protected abstract Stream OpenPdbStream();
}
}
......@@ -2388,15 +2388,6 @@ internal class FeaturesResources {
}
}
/// <summary>
/// Looks up a localized string similar to {0} must return a stream that supports read and seek operations..
/// </summary>
internal static string MethodMustReturnStreamThatSupportsReadAndSeek {
get {
return ResourceManager.GetString("MethodMustReturnStreamThatSupportsReadAndSeek", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Methods.
/// </summary>
......@@ -3491,15 +3482,6 @@ internal class FeaturesResources {
}
}
/// <summary>
/// Looks up a localized string similar to Stream must support read and seek operations..
/// </summary>
internal static string StreamMustSupportReadAndSeek {
get {
return ResourceManager.GetString("StreamMustSupportReadAndSeek", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Structures.
/// </summary>
......
......@@ -1623,10 +1623,4 @@ This version used in: {2}</value>
<data name="Target_type_matches" xml:space="preserve">
<value>Target type matches</value>
</data>
<data name="StreamMustSupportReadAndSeek" xml:space="preserve">
<value>Stream must support read and seek operations.</value>
</data>
<data name="MethodMustReturnStreamThatSupportsReadAndSeek" xml:space="preserve">
<value>{0} must return a stream that supports read and seek operations.</value>
</data>
</root>
\ No newline at end of file
......@@ -222,11 +222,6 @@
<target state="new">Merge with previous '{0}' statement</target>
<note />
</trans-unit>
<trans-unit id="MethodMustReturnStreamThatSupportsReadAndSeek">
<source>{0} must return a stream that supports read and seek operations.</source>
<target state="new">{0} must return a stream that supports read and seek operations.</target>
<note />
</trans-unit>
<trans-unit id="Move_contents_to_namespace">
<source>Move contents to namespace...</source>
<target state="new">Move contents to namespace...</target>
......@@ -352,11 +347,6 @@
<target state="new">Split into nested '{0}' statements</target>
<note />
</trans-unit>
<trans-unit id="StreamMustSupportReadAndSeek">
<source>Stream must support read and seek operations.</source>
<target state="new">Stream must support read and seek operations.</target>
<note />
</trans-unit>
<trans-unit id="Target_type_matches">
<source>Target type matches</source>
<target state="new">Target type matches</target>
......
......@@ -222,11 +222,6 @@
<target state="new">Merge with previous '{0}' statement</target>
<note />
</trans-unit>
<trans-unit id="MethodMustReturnStreamThatSupportsReadAndSeek">
<source>{0} must return a stream that supports read and seek operations.</source>
<target state="new">{0} must return a stream that supports read and seek operations.</target>
<note />
</trans-unit>
<trans-unit id="Move_contents_to_namespace">
<source>Move contents to namespace...</source>
<target state="new">Move contents to namespace...</target>
......@@ -352,11 +347,6 @@
<target state="new">Split into nested '{0}' statements</target>
<note />
</trans-unit>
<trans-unit id="StreamMustSupportReadAndSeek">
<source>Stream must support read and seek operations.</source>
<target state="new">Stream must support read and seek operations.</target>
<note />
</trans-unit>
<trans-unit id="Target_type_matches">
<source>Target type matches</source>
<target state="new">Target type matches</target>
......
......@@ -222,11 +222,6 @@
<target state="new">Merge with previous '{0}' statement</target>
<note />
</trans-unit>
<trans-unit id="MethodMustReturnStreamThatSupportsReadAndSeek">
<source>{0} must return a stream that supports read and seek operations.</source>
<target state="new">{0} must return a stream that supports read and seek operations.</target>
<note />
</trans-unit>
<trans-unit id="Move_contents_to_namespace">
<source>Move contents to namespace...</source>
<target state="new">Move contents to namespace...</target>
......@@ -352,11 +347,6 @@
<target state="new">Split into nested '{0}' statements</target>
<note />
</trans-unit>
<trans-unit id="StreamMustSupportReadAndSeek">
<source>Stream must support read and seek operations.</source>
<target state="new">Stream must support read and seek operations.</target>
<note />
</trans-unit>
<trans-unit id="Target_type_matches">
<source>Target type matches</source>
<target state="new">Target type matches</target>
......
......@@ -222,11 +222,6 @@
<target state="new">Merge with previous '{0}' statement</target>
<note />
</trans-unit>
<trans-unit id="MethodMustReturnStreamThatSupportsReadAndSeek">
<source>{0} must return a stream that supports read and seek operations.</source>
<target state="new">{0} must return a stream that supports read and seek operations.</target>
<note />
</trans-unit>
<trans-unit id="Move_contents_to_namespace">
<source>Move contents to namespace...</source>
<target state="new">Move contents to namespace...</target>
......@@ -352,11 +347,6 @@
<target state="new">Split into nested '{0}' statements</target>
<note />
</trans-unit>
<trans-unit id="StreamMustSupportReadAndSeek">
<source>Stream must support read and seek operations.</source>
<target state="new">Stream must support read and seek operations.</target>
<note />
</trans-unit>
<trans-unit id="Target_type_matches">
<source>Target type matches</source>
<target state="new">Target type matches</target>
......
......@@ -222,11 +222,6 @@
<target state="new">Merge with previous '{0}' statement</target>
<note />
</trans-unit>
<trans-unit id="MethodMustReturnStreamThatSupportsReadAndSeek">
<source>{0} must return a stream that supports read and seek operations.</source>
<target state="new">{0} must return a stream that supports read and seek operations.</target>
<note />
</trans-unit>
<trans-unit id="Move_contents_to_namespace">
<source>Move contents to namespace...</source>
<target state="new">Move contents to namespace...</target>
......@@ -352,11 +347,6 @@
<target state="new">Split into nested '{0}' statements</target>
<note />
</trans-unit>
<trans-unit id="StreamMustSupportReadAndSeek">
<source>Stream must support read and seek operations.</source>
<target state="new">Stream must support read and seek operations.</target>
<note />
</trans-unit>
<trans-unit id="Target_type_matches">
<source>Target type matches</source>
<target state="new">Target type matches</target>
......
......@@ -222,11 +222,6 @@
<target state="new">Merge with previous '{0}' statement</target>
<note />
</trans-unit>
<trans-unit id="MethodMustReturnStreamThatSupportsReadAndSeek">
<source>{0} must return a stream that supports read and seek operations.</source>
<target state="new">{0} must return a stream that supports read and seek operations.</target>
<note />
</trans-unit>
<trans-unit id="Move_contents_to_namespace">
<source>Move contents to namespace...</source>
<target state="new">Move contents to namespace...</target>
......@@ -352,11 +347,6 @@
<target state="new">Split into nested '{0}' statements</target>
<note />
</trans-unit>
<trans-unit id="StreamMustSupportReadAndSeek">
<source>Stream must support read and seek operations.</source>
<target state="new">Stream must support read and seek operations.</target>
<note />
</trans-unit>
<trans-unit id="Target_type_matches">
<source>Target type matches</source>
<target state="new">Target type matches</target>
......
......@@ -222,11 +222,6 @@
<target state="new">Merge with previous '{0}' statement</target>
<note />
</trans-unit>
<trans-unit id="MethodMustReturnStreamThatSupportsReadAndSeek">
<source>{0} must return a stream that supports read and seek operations.</source>
<target state="new">{0} must return a stream that supports read and seek operations.</target>
<note />
</trans-unit>
<trans-unit id="Move_contents_to_namespace">
<source>Move contents to namespace...</source>
<target state="new">Move contents to namespace...</target>
......@@ -352,11 +347,6 @@
<target state="new">Split into nested '{0}' statements</target>
<note />
</trans-unit>
<trans-unit id="StreamMustSupportReadAndSeek">
<source>Stream must support read and seek operations.</source>
<target state="new">Stream must support read and seek operations.</target>
<note />
</trans-unit>
<trans-unit id="Target_type_matches">
<source>Target type matches</source>
<target state="new">Target type matches</target>
......
......@@ -222,11 +222,6 @@
<target state="new">Merge with previous '{0}' statement</target>
<note />
</trans-unit>
<trans-unit id="MethodMustReturnStreamThatSupportsReadAndSeek">
<source>{0} must return a stream that supports read and seek operations.</source>
<target state="new">{0} must return a stream that supports read and seek operations.</target>
<note />
</trans-unit>
<trans-unit id="Move_contents_to_namespace">
<source>Move contents to namespace...</source>
<target state="new">Move contents to namespace...</target>
......@@ -352,11 +347,6 @@
<target state="new">Split into nested '{0}' statements</target>
<note />
</trans-unit>
<trans-unit id="StreamMustSupportReadAndSeek">
<source>Stream must support read and seek operations.</source>
<target state="new">Stream must support read and seek operations.</target>
<note />
</trans-unit>
<trans-unit id="Target_type_matches">
<source>Target type matches</source>
<target state="new">Target type matches</target>
......
......@@ -222,11 +222,6 @@
<target state="new">Merge with previous '{0}' statement</target>
<note />
</trans-unit>
<trans-unit id="MethodMustReturnStreamThatSupportsReadAndSeek">
<source>{0} must return a stream that supports read and seek operations.</source>
<target state="new">{0} must return a stream that supports read and seek operations.</target>
<note />
</trans-unit>
<trans-unit id="Move_contents_to_namespace">
<source>Move contents to namespace...</source>
<target state="new">Move contents to namespace...</target>
......@@ -352,11 +347,6 @@
<target state="new">Split into nested '{0}' statements</target>
<note />
</trans-unit>
<trans-unit id="StreamMustSupportReadAndSeek">
<source>Stream must support read and seek operations.</source>
<target state="new">Stream must support read and seek operations.</target>
<note />
</trans-unit>
<trans-unit id="Target_type_matches">
<source>Target type matches</source>
<target state="new">Target type matches</target>
......
......@@ -222,11 +222,6 @@
<target state="new">Merge with previous '{0}' statement</target>
<note />
</trans-unit>
<trans-unit id="MethodMustReturnStreamThatSupportsReadAndSeek">
<source>{0} must return a stream that supports read and seek operations.</source>
<target state="new">{0} must return a stream that supports read and seek operations.</target>
<note />
</trans-unit>
<trans-unit id="Move_contents_to_namespace">
<source>Move contents to namespace...</source>
<target state="new">Move contents to namespace...</target>
......@@ -352,11 +347,6 @@
<target state="new">Split into nested '{0}' statements</target>
<note />
</trans-unit>
<trans-unit id="StreamMustSupportReadAndSeek">
<source>Stream must support read and seek operations.</source>
<target state="new">Stream must support read and seek operations.</target>
<note />
</trans-unit>
<trans-unit id="Target_type_matches">
<source>Target type matches</source>
<target state="new">Target type matches</target>
......
......@@ -222,11 +222,6 @@
<target state="new">Merge with previous '{0}' statement</target>
<note />
</trans-unit>
<trans-unit id="MethodMustReturnStreamThatSupportsReadAndSeek">
<source>{0} must return a stream that supports read and seek operations.</source>
<target state="new">{0} must return a stream that supports read and seek operations.</target>
<note />
</trans-unit>
<trans-unit id="Move_contents_to_namespace">
<source>Move contents to namespace...</source>
<target state="new">Move contents to namespace...</target>
......@@ -352,11 +347,6 @@
<target state="new">Split into nested '{0}' statements</target>
<note />
</trans-unit>
<trans-unit id="StreamMustSupportReadAndSeek">
<source>Stream must support read and seek operations.</source>
<target state="new">Stream must support read and seek operations.</target>
<note />
</trans-unit>
<trans-unit id="Target_type_matches">
<source>Target type matches</source>
<target state="new">Target type matches</target>
......
......@@ -222,11 +222,6 @@
<target state="new">Merge with previous '{0}' statement</target>
<note />
</trans-unit>
<trans-unit id="MethodMustReturnStreamThatSupportsReadAndSeek">
<source>{0} must return a stream that supports read and seek operations.</source>
<target state="new">{0} must return a stream that supports read and seek operations.</target>
<note />
</trans-unit>
<trans-unit id="Move_contents_to_namespace">
<source>Move contents to namespace...</source>
<target state="new">Move contents to namespace...</target>
......@@ -352,11 +347,6 @@
<target state="new">Split into nested '{0}' statements</target>
<note />
</trans-unit>
<trans-unit id="StreamMustSupportReadAndSeek">
<source>Stream must support read and seek operations.</source>
<target state="new">Stream must support read and seek operations.</target>
<note />
</trans-unit>
<trans-unit id="Target_type_matches">
<source>Target type matches</source>
<target state="new">Target type matches</target>
......
......@@ -222,11 +222,6 @@
<target state="new">Merge with previous '{0}' statement</target>
<note />
</trans-unit>
<trans-unit id="MethodMustReturnStreamThatSupportsReadAndSeek">
<source>{0} must return a stream that supports read and seek operations.</source>
<target state="new">{0} must return a stream that supports read and seek operations.</target>
<note />
</trans-unit>
<trans-unit id="Move_contents_to_namespace">
<source>Move contents to namespace...</source>
<target state="new">Move contents to namespace...</target>
......@@ -352,11 +347,6 @@
<target state="new">Split into nested '{0}' statements</target>
<note />
</trans-unit>
<trans-unit id="StreamMustSupportReadAndSeek">
<source>Stream must support read and seek operations.</source>
<target state="new">Stream must support read and seek operations.</target>
<note />
</trans-unit>
<trans-unit id="Target_type_matches">
<source>Target type matches</source>
<target state="new">Target type matches</target>
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.CodeAnalysis.Host;
namespace Microsoft.CodeAnalysis.Emit
namespace Microsoft.CodeAnalysis.Test.Utilities
{
internal interface ICompilationOutputsProviderService : IWorkspaceService
public struct CompilationOutputFiles
{
CompilationOutputs GetCompilationOutputs(ProjectId projectId);
public readonly string PE;
public readonly string Pdb;
public readonly string XmlDocs;
public CompilationOutputFiles(string pe, string pdb = null, string xmlDocs = null)
{
PE = pe;
Pdb = pdb;
XmlDocs = xmlDocs;
}
}
}
......@@ -64,7 +64,6 @@
<InternalsVisibleTo Include="Roslyn.Services.Test.Utilities" />
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.EditorFeatures.Test.Utilities" />
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.Workspaces.UnitTests" />
<InternalsVisibleTo Include="Microsoft.VisualStudio.LanguageServices.CSharp.UnitTests" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\..\Compilers\Shared\CoreClrAnalyzerAssemblyLoader.cs" />
......
......@@ -9,7 +9,6 @@
</PropertyGroup>
<ItemGroup Label="Project References">
<ProjectReference Include="..\..\..\Compilers\Test\Resources\Core\Microsoft.CodeAnalysis.Compiler.Test.Resources.csproj" />
<ProjectReference Include="..\..\..\Compilers\Test\Utilities\CSharp\Microsoft.CodeAnalysis.CSharp.Test.Utilities.csproj" />
<ProjectReference Include="..\..\..\Compilers\Test\Utilities\VisualBasic\Microsoft.CodeAnalysis.VisualBasic.Test.Utilities.vbproj" />
<ProjectReference Include="..\..\..\Compilers\VisualBasic\Portable\Microsoft.CodeAnalysis.VisualBasic.vbproj" />
<ProjectReference Include="..\..\..\EditorFeatures\TestUtilities2\Microsoft.CodeAnalysis.EditorFeatures.Test.Utilities.vbproj" />
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.IO;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem;
using Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim.Framework;
using Roslyn.Test.Utilities;
using Xunit;
using DisposableFile = Microsoft.CodeAnalysis.Test.Utilities.DisposableFile;
namespace Roslyn.VisualStudio.CSharp.UnitTests.ProjectSystemShim.CPS
{
[UseExportProvider]
public class AnalyzersTests : TestBase
public class AnalyzersTests
{
[WpfFact]
[Trait(Traits.Feature, Traits.Features.ProjectSystemShims)]
public void RuleSet_GeneralOption_CPS()
{
var ruleSetFile = Temp.CreateFile().WriteAllText(
@"<?xml version=""1.0"" encoding=""utf-8""?>
string ruleSetSource = @"<?xml version=""1.0"" encoding=""utf-8""?>
<RuleSet Name=""Ruleset1"" Description=""Test"" ToolsVersion=""12.0"">
<IncludeAll Action=""Error"" />
</RuleSet>
");
";
using (var ruleSetFile = new DisposableFile())
using (var environment = new TestEnvironment())
using (var project = CSharpHelpers.CreateCSharpCPSProject(environment, "Test"))
{
File.WriteAllText(ruleSetFile.Path, ruleSetSource);
var workspaceProject = environment.Workspace.CurrentSolution.Projects.Single();
var options = (CSharpCompilationOptions)workspaceProject.CompilationOptions;
......@@ -44,20 +50,21 @@ public void RuleSet_GeneralOption_CPS()
[Trait(Traits.Feature, Traits.Features.ProjectSystemShims)]
public void RuleSet_SpecificOptions_CPS()
{
var ruleSetFile = Temp.CreateFile().WriteAllText(
@"<?xml version=""1.0"" encoding=""utf-8""?>
string ruleSetSource = @"<?xml version=""1.0"" encoding=""utf-8""?>
<RuleSet Name=""Ruleset1"" Description=""Test"" ToolsVersion=""12.0"">
<IncludeAll Action=""Warning"" />
<Rules AnalyzerId=""Microsoft.Analyzers.ManagedCodeAnalysis"" RuleNamespace=""Microsoft.Rules.Managed"">
<Rule Id=""CA1012"" Action=""Error"" />
</Rules>
</RuleSet>
");
";
using (var ruleSetFile = new DisposableFile())
using (var environment = new TestEnvironment())
using (var project = CSharpHelpers.CreateCSharpCPSProject(environment, "Test"))
{
// Verify SetRuleSetFile updates the ruleset.
File.WriteAllText(ruleSetFile.Path, ruleSetSource);
project.SetOptions($"/ruleset:{ruleSetFile.Path}");
// We need to explicitly update the command line arguments so the new ruleset is used to update options.
......@@ -71,7 +78,7 @@ public void RuleSet_SpecificOptions_CPS()
[Trait(Traits.Feature, Traits.Features.ProjectSystemShims)]
public void RuleSet_PathCanBeFound()
{
var ruleSetFile = Temp.CreateFile();
using (var ruleSetFile = new DisposableFile())
using (var environment = new TestEnvironment())
{
ProjectId projectId;
......
......@@ -17,20 +17,42 @@
namespace Roslyn.VisualStudio.CSharp.UnitTests.ProjectSystemShim.LegacyProject
{
[UseExportProvider]
public class AnalyzersTests : TestBase
public class AnalyzersTests
{
private sealed class DisposableFile : IDisposable
{
private readonly string _filePath;
public DisposableFile()
{
_filePath = System.IO.Path.GetTempFileName();
}
public void Dispose()
{
File.Delete(_filePath);
}
public string Path
{
get { return _filePath; }
}
}
[WpfFact]
[Trait(Traits.Feature, Traits.Features.ProjectSystemShims)]
public void RuleSet_GeneralOption()
{
var ruleSetFile = Temp.CreateFile().WriteAllText(
@"<?xml version=""1.0"" encoding=""utf-8""?>
string ruleSetSource = @"<?xml version=""1.0"" encoding=""utf-8""?>
<RuleSet Name=""Ruleset1"" Description=""Test"" ToolsVersion=""12.0"">
<IncludeAll Action=""Error"" />
</RuleSet>
");
";
using (var ruleSetFile = new DisposableFile())
using (var environment = new TestEnvironment())
{
File.WriteAllText(ruleSetFile.Path, ruleSetSource);
var project = CSharpHelpers.CreateCSharpProject(environment, "Test");
var options = (CSharpCompilationOptions)environment.GetUpdatedCompilationOptionOfSingleProject();
......@@ -45,12 +67,12 @@ public void RuleSet_GeneralOption()
}
}
[WpfFact]
[Trait(Traits.Feature, Traits.Features.ProjectSystemShims)]
public void RuleSet_CanBeFetchedFromWorkspace()
{
var ruleSetFile = Temp.CreateFile();
using (var ruleSetFile = new DisposableFile())
using (var environment = new TestEnvironment())
{
var project = CSharpHelpers.CreateCSharpProject(environment, "Test");
......@@ -66,15 +88,17 @@ public void RuleSet_CanBeFetchedFromWorkspace()
[Trait(Traits.Feature, Traits.Features.ProjectSystemShims)]
public void RuleSet_ProjectSettingOverridesGeneralOption()
{
var ruleSetFile = Temp.CreateFile().WriteAllText(
@"<?xml version=""1.0"" encoding=""utf-8""?>
string ruleSetSource = @"<?xml version=""1.0"" encoding=""utf-8""?>
<RuleSet Name=""Ruleset1"" Description=""Test"" ToolsVersion=""12.0"">
<IncludeAll Action=""Warning"" />
</RuleSet>
");
";
using (var ruleSetFile = new DisposableFile())
using (var environment = new TestEnvironment())
{
File.WriteAllText(ruleSetFile.Path, ruleSetSource);
var project = CSharpHelpers.CreateCSharpProject(environment, "Test");
((IAnalyzerHost)project).SetRuleSetFile(ruleSetFile.Path);
......@@ -97,18 +121,20 @@ public void RuleSet_ProjectSettingOverridesGeneralOption()
[Trait(Traits.Feature, Traits.Features.ProjectSystemShims)]
public void RuleSet_SpecificOptions()
{
var ruleSetFile = Temp.CreateFile().WriteAllText(
@"<?xml version=""1.0"" encoding=""utf-8""?>
string ruleSetSource = @"<?xml version=""1.0"" encoding=""utf-8""?>
<RuleSet Name=""Ruleset1"" Description=""Test"" ToolsVersion=""12.0"">
<IncludeAll Action=""Warning"" />
<Rules AnalyzerId=""Microsoft.Analyzers.ManagedCodeAnalysis"" RuleNamespace=""Microsoft.Rules.Managed"">
<Rule Id=""CA1012"" Action=""Error"" />
</Rules>
</RuleSet>
");
";
using (var ruleSetFile = new DisposableFile())
using (var environment = new TestEnvironment())
{
File.WriteAllText(ruleSetFile.Path, ruleSetSource);
var project = CSharpHelpers.CreateCSharpProject(environment, "Test");
((IAnalyzerHost)project).SetRuleSetFile(ruleSetFile.Path);
......@@ -124,17 +150,20 @@ public void RuleSet_SpecificOptions()
[Trait(Traits.Feature, Traits.Features.ProjectSystemShims)]
public void RuleSet_ProjectSettingsOverrideSpecificOptions()
{
var ruleSetFile = Temp.CreateFile().WriteAllText(
@"<?xml version=""1.0"" encoding=""utf-8""?>
string ruleSetSource = @"<?xml version=""1.0"" encoding=""utf-8""?>
<RuleSet Name=""Ruleset1"" Description=""Test"" ToolsVersion=""12.0"">
<IncludeAll Action=""Warning"" />
<Rules AnalyzerId=""Microsoft.Analyzers.ManagedCodeAnalysis"" RuleNamespace=""Microsoft.Rules.Managed"">
<Rule Id=""CS1014"" Action=""None"" />
</Rules>
</RuleSet>
");
";
using (var ruleSetFile = new DisposableFile())
using (var environment = new TestEnvironment())
{
File.WriteAllText(ruleSetFile.Path, ruleSetSource);
var project = CSharpHelpers.CreateCSharpProject(environment, "Test");
((IAnalyzerHost)project).SetRuleSetFile(ruleSetFile.Path);
......@@ -151,7 +180,7 @@ public void RuleSet_ProjectSettingsOverrideSpecificOptions()
[Trait(Traits.Feature, Traits.Features.ProjectSystemShims)]
public void SetRuleSetFile_RemoveExtraBackslashes()
{
var ruleSetFile = Temp.CreateFile();
using (var ruleSetFile = new DisposableFile())
using (var environment = new TestEnvironment())
{
var project = CSharpHelpers.CreateCSharpProject(environment, "Test");
......@@ -173,18 +202,20 @@ public void SetRuleSetFile_RemoveExtraBackslashes()
[WorkItem(468, "https://github.com/dotnet/roslyn/issues/468")]
public void RuleSet_ProjectSettingsOverrideSpecificOptionsAndRestore()
{
var ruleSetFile = Temp.CreateFile().WriteAllText(
@"<?xml version=""1.0"" encoding=""utf-8""?>
string ruleSetSource = @"<?xml version=""1.0"" encoding=""utf-8""?>
<RuleSet Name=""Ruleset1"" Description=""Test"" ToolsVersion=""12.0"">
<IncludeAll Action=""Warning"" />
<Rules AnalyzerId=""Microsoft.Analyzers.ManagedCodeAnalysis"" RuleNamespace=""Microsoft.Rules.Managed"">
<Rule Id=""CS1014"" Action=""None"" />
</Rules>
</RuleSet>
");
";
using (var ruleSetFile = new DisposableFile())
using (var environment = new TestEnvironment())
{
File.WriteAllText(ruleSetFile.Path, ruleSetSource);
var project = CSharpHelpers.CreateCSharpProject(environment, "Test");
((IAnalyzerHost)project).SetRuleSetFile(ruleSetFile.Path);
......@@ -212,18 +243,20 @@ public void RuleSet_ProjectSettingsOverrideSpecificOptionsAndRestore()
[WorkItem(468, "https://github.com/dotnet/roslyn/issues/468")]
public void RuleSet_ProjectNoWarnOverridesOtherSettings()
{
var ruleSetFile = Temp.CreateFile().WriteAllText(
@"<?xml version=""1.0"" encoding=""utf-8""?>
string ruleSetSource = @"<?xml version=""1.0"" encoding=""utf-8""?>
<RuleSet Name=""Ruleset1"" Description=""Test"" ToolsVersion=""12.0"">
<IncludeAll Action=""Warning"" />
<Rules AnalyzerId=""Microsoft.Analyzers.ManagedCodeAnalysis"" RuleNamespace=""Microsoft.Rules.Managed"">
<Rule Id=""CS1014"" Action=""Info"" />
</Rules>
</RuleSet>
");
";
using (var ruleSetFile = new DisposableFile())
using (var environment = new TestEnvironment())
{
File.WriteAllText(ruleSetFile.Path, ruleSetSource);
var project = CSharpHelpers.CreateCSharpProject(environment, "Test");
((IAnalyzerHost)project).SetRuleSetFile(ruleSetFile.Path);
......@@ -244,16 +277,16 @@ public void RuleSet_ProjectNoWarnOverridesOtherSettings()
[WorkItem(33505, "https://github.com/dotnet/roslyn/pull/33505")]
public void RuleSet_FileChangingOnDiskRefreshes(bool useCpsProject)
{
string ruleSetSource =
@"<?xml version=""1.0"" encoding=""utf-8""?>
string ruleSetSource = @"<?xml version=""1.0"" encoding=""utf-8""?>
<RuleSet Name=""Ruleset1"" Description=""Test"" ToolsVersion=""12.0"">
<IncludeAll Action=""Error"" />
</RuleSet>
";
var ruleSetFile = Temp.CreateFile().WriteAllText(ruleSetSource);
using (var ruleSetFile = new DisposableFile())
using (var environment = new TestEnvironment())
{
File.WriteAllText(ruleSetFile.Path, ruleSetSource);
if (useCpsProject)
{
CSharpHelpers.CreateCSharpCPSProject(environment, "Test", binOutputPath: null, $"/ruleset:\"{ruleSetFile.Path}\"");
......
......@@ -5,8 +5,6 @@
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.VisualStudio.LanguageServices.CSharp.ProjectSystemShim.Interop;
using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem;
using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem.Interop;
using Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim.Framework;
using Roslyn.Test.Utilities;
using Xunit;
......@@ -118,65 +116,20 @@ public void ProjectOutputPathAndOutputExeNameChange()
project.SetOutputFileName(initialPath);
Assert.Equal(initialPath, project.GetOutputFileName());
var outputs = (CompilationOutputFilesWithImplicitPdbPath)environment.Workspace.GetCompilationOutputs(project.Test_VisualStudioProject.Id);
Assert.Equal(initialPath, outputs.AssemblyFilePath);
// Change output folder from command line arguments - verify that objOutputPath changes.
var newPath = @"C:\NewFolder\test.dll";
project.SetOutputFileName(newPath);
Assert.Equal(newPath, project.GetOutputFileName());
outputs = (CompilationOutputFilesWithImplicitPdbPath)environment.Workspace.GetCompilationOutputs(project.Test_VisualStudioProject.Id);
Assert.Equal(newPath, outputs.AssemblyFilePath);
// Change output file name - verify that outputPath changes.
newPath = @"C:\NewFolder\test2.dll";
project.SetOutputFileName(newPath);
Assert.Equal(newPath, project.GetOutputFileName());
outputs = (CompilationOutputFilesWithImplicitPdbPath)environment.Workspace.GetCompilationOutputs(project.Test_VisualStudioProject.Id);
Assert.Equal(newPath, outputs.AssemblyFilePath);
// Change output file name and folder - verify that outputPath changes.
newPath = @"C:\NewFolder3\test3.dll";
project.SetOutputFileName(newPath);
Assert.Equal(newPath, project.GetOutputFileName());
outputs = (CompilationOutputFilesWithImplicitPdbPath)environment.Workspace.GetCompilationOutputs(project.Test_VisualStudioProject.Id);
Assert.Equal(newPath, outputs.AssemblyFilePath);
}
}
[WpfFact]
public void ProjectCompilationOutputsChange()
{
using (var environment = new TestEnvironment())
{
var project = CSharpHelpers.CreateCSharpProject(environment, "Test");
var outputs = (CompilationOutputFilesWithImplicitPdbPath)environment.Workspace.GetCompilationOutputs(project.Test_VisualStudioProject.Id);
Assert.Equal(null, outputs.AssemblyFilePath);
Assert.Equal(0, ((ICompilerOptionsHostObject)project).SetCompilerOptions(@"/pdb:C:\a\1.pdb /debug+", out _));
// Compilation doesn't have output file, so we don't expect any build outputs either.
outputs = (CompilationOutputFilesWithImplicitPdbPath)environment.Workspace.GetCompilationOutputs(project.Test_VisualStudioProject.Id);
Assert.Equal(null, outputs.AssemblyFilePath);
Assert.Equal(0, ((ICompilerOptionsHostObject)project).SetCompilerOptions(@"/out:C:\a\2.dll /debug+", out _));
outputs = (CompilationOutputFilesWithImplicitPdbPath)environment.Workspace.GetCompilationOutputs(project.Test_VisualStudioProject.Id);
Assert.Equal(@"C:\a\2.dll", outputs.AssemblyFilePath);
project.SetOutputFileName(@"C:\a\3.dll");
outputs = (CompilationOutputFilesWithImplicitPdbPath)environment.Workspace.GetCompilationOutputs(project.Test_VisualStudioProject.Id);
Assert.Equal(@"C:\a\3.dll", outputs.AssemblyFilePath);
Assert.Equal(0, ((ICompilerOptionsHostObject)project).SetCompilerOptions(@"/pdb:C:\a\4.pdb /debug+", out _));
outputs = (CompilationOutputFilesWithImplicitPdbPath)environment.Workspace.GetCompilationOutputs(project.Test_VisualStudioProject.Id);
Assert.Equal(@"C:\a\3.dll", outputs.AssemblyFilePath);
}
}
}
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.IO;
using System.Linq;
using System.Reflection.Metadata.Ecma335;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Emit;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem.UnitTests
{
public class VisualStudioCompilationOutputFilesTests : TestBase
{
[Fact]
public void OpenStream_Errors()
{
Assert.Throws<ArgumentException>(() => new CompilationOutputFilesWithImplicitPdbPath(@"a.dll"));
}
[Theory]
[InlineData(true)]
[InlineData(false)]
public void AssemblyAndPdb(bool exactPdbPath)
{
var dir = Temp.CreateDirectory();
var dllFile = dir.CreateFile("lib.dll");
var pdbFile = dir.CreateFile("lib.pdb");
var source = @"class C { public static void Main() { int x = 1; } }";
var compilation = CSharpTestBase.CreateCompilationWithMscorlib40AndSystemCore(source, options: TestOptions.DebugDll, assemblyName: "lib");
var pdbStream = new MemoryStream();
var debugDirPdbPath = exactPdbPath ? pdbFile.Path : "a/y/z/lib.pdb";
var peImage = compilation.EmitToArray(new EmitOptions(debugInformationFormat: DebugInformationFormat.PortablePdb, pdbFilePath: debugDirPdbPath), pdbStream: pdbStream);
pdbStream.Position = 0;
dllFile.WriteAllBytes(peImage);
pdbFile.WriteAllBytes(pdbStream.ToArray());
var outputs = new CompilationOutputFilesWithImplicitPdbPath(dllFile.Path);
using (var pdb = outputs.OpenPdb())
{
var encReader = pdb.CreateEditAndContinueMethodDebugInfoReader();
Assert.True(encReader.IsPortable);
var localSig = encReader.GetLocalSignature(MetadataTokens.MethodDefinitionHandle(1));
Assert.Equal(MetadataTokens.StandaloneSignatureHandle(1), localSig);
}
using (var metadata = outputs.OpenAssemblyMetadata(prefetch: false))
{
var mdReader = metadata.GetMetadataReader();
Assert.Equal("lib", mdReader.GetString(mdReader.GetAssemblyDefinition().Name));
}
// make sure all files are closed and can be deleted
Directory.Delete(dir.Path, recursive: true);
}
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.IO;
using System.Linq;
using System.Reflection.PortableExecutable;
using Microsoft.CodeAnalysis.Emit;
using Roslyn.Utilities;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
{
/// <summary>
/// Provides access to compilation outputs based only on the path of the output asssembly.
/// If PDB path is known upfront use <see cref="CompilationOutputFiles"/> instead.
/// </summary>
internal sealed class CompilationOutputFilesWithImplicitPdbPath : CompilationOutputs
{
public string AssemblyFilePath { get; }
public CompilationOutputFilesWithImplicitPdbPath(string assemblyFilePath = null)
{
if (assemblyFilePath != null)
{
CompilerPathUtilities.RequireAbsolutePath(assemblyFilePath, nameof(assemblyFilePath));
}
AssemblyFilePath = assemblyFilePath;
}
public override string AssemblyDisplayPath => AssemblyFilePath;
public override string PdbDisplayPath => Path.GetFileNameWithoutExtension(AssemblyFilePath) + ".pdb";
protected override Stream OpenAssemblyStream()
=> AssemblyFilePath != null ? FileUtilities.OpenRead(AssemblyFilePath) : null;
protected override Stream OpenPdbStream()
{
var assemblyStream = OpenAssemblyStream();
if (assemblyStream == null)
{
return null;
}
// find associated PDB
string pdbPath;
using (var peReader = new PEReader(assemblyStream))
{
var pdbEntry = peReader.ReadDebugDirectory().FirstOrDefault(
e => e.Type == DebugDirectoryEntryType.EmbeddedPortablePdb || e.Type == DebugDirectoryEntryType.CodeView);
if (pdbEntry.Type != DebugDirectoryEntryType.CodeView)
{
return null;
}
pdbPath = peReader.ReadCodeViewDebugDirectoryData(pdbEntry).Path;
}
// First try to use the full path as specified in the PDB, then look next to the assembly.
Stream result;
try
{
result = new FileStream(pdbPath, FileMode.Open, FileAccess.Read, FileShare.Read);
}
catch (Exception e) when (e is FileNotFoundException || e is DirectoryNotFoundException)
{
pdbPath = Path.Combine(Path.GetDirectoryName(AssemblyFilePath), PathUtilities.GetFileName(pdbPath));
result = FileUtilities.OpenRead(pdbPath);
}
return result;
}
}
}
......@@ -31,8 +31,6 @@ internal abstract partial class AbstractLegacyProject : ForegroundThreadAffiniti
protected IProjectCodeModel ProjectCodeModel { get; set; }
protected VisualStudioWorkspace Workspace { get; }
internal VisualStudioProject Test_VisualStudioProject => VisualStudioProject;
/// <summary>
/// The path to the directory of the project. Read-only, since although you can rename
/// a project in Visual Studio you can't change the folder of a project without an
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Emit;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
{
internal sealed class VisualStudioCompilationOutputsProviderService : ICompilationOutputsProviderService
{
private readonly VisualStudioWorkspaceImpl _workspace;
public VisualStudioCompilationOutputsProviderService(VisualStudioWorkspaceImpl workspace)
{
_workspace = workspace;
}
public CompilationOutputs GetCompilationOutputs(ProjectId projectId)
=> _workspace.GetCompilationOutputs(projectId);
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Composition;
using Microsoft.CodeAnalysis.Emit;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
{
[ExportWorkspaceServiceFactory(typeof(ICompilationOutputsProviderService), ServiceLayer.Host), Shared]
internal sealed class VisualStudioCompilationOutputsProviderServiceFactory : IWorkspaceServiceFactory
{
private readonly VisualStudioWorkspaceImpl _workspace;
[ImportingConstructor]
public VisualStudioCompilationOutputsProviderServiceFactory(VisualStudioWorkspaceImpl workspace)
{
_workspace = workspace;
}
public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices)
=> new VisualStudioCompilationOutputsProviderService(_workspace);
}
}
......@@ -233,11 +233,6 @@ internal string IntermediateOutputFilePath
get => _intermediateOutputFilePath;
set
{
// The Project System doesn't always indicate whether we emit PDB, what kind of PDB we emit nor the path of the PDB.
// To work around we look for the PDB on the path specified in the PDB debug directory.
// https://github.com/dotnet/roslyn/issues/35065
_workspace.SetCompilationOutputs(Id, new CompilationOutputFilesWithImplicitPdbPath(value));
// Unlike OutputFilePath and OutputRefFilePath, the intermediate output path isn't represented in the workspace anywhere;
// thus, we won't mutate the solution. We'll still call ChangeProjectOutputPath so we have the rest of the output path tracking
// for any P2P reference conversion.
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System;
using System.Collections.Immutable;
using System.IO;
using Microsoft.CodeAnalysis;
......@@ -21,7 +19,7 @@ internal class VisualStudioProjectOptionsProcessor : IDisposable
/// Gate to guard all mutable fields in this class.
/// The lock hierarchy means you are allowed to call out of this class and into <see cref="_project"/> while holding the lock.
/// </summary>
private readonly object _gate = new object();
private object _gate = new object();
private string _commandLine = "";
private CommandLineArguments _commandLineArgumentsForCommandLine;
private string _explicitRuleSetFilePath;
......
......@@ -11,9 +11,7 @@
using EnvDTE;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.EditAndContinue;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Emit;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Shared.Utilities;
......@@ -91,9 +89,6 @@ internal abstract partial class VisualStudioWorkspaceImpl : VisualStudioWorkspac
private readonly Lazy<IProjectCodeModelFactory> _projectCodeModelFactory;
private readonly Dictionary<ProjectId, CompilationOutputs> _projectCompilationOutputs = new Dictionary<ProjectId, CompilationOutputs>();
private readonly object _projectCompilationOutputsGuard = new object();
public VisualStudioWorkspaceImpl(ExportProvider exportProvider, IAsyncServiceProvider asyncServiceProvider)
: base(VisualStudioMefHostServices.Create(exportProvider))
{
......@@ -1489,7 +1484,6 @@ protected internal override void OnProjectRemoved(ProjectId projectId)
_projectToHierarchyMap = _projectToHierarchyMap.Remove(projectId);
_projectToGuidMap = _projectToGuidMap.Remove(projectId);
_projectToRuleSetFilePath.Remove(projectId);
_projectCompilationOutputs.Remove(projectId);
foreach (var (projectName, projects) in _projectSystemNameToProjectsMap)
{
......@@ -1809,23 +1803,5 @@ private void RefreshMetadataReferencesForFile(object sender, string fullFilePath
changedProjectIds.Free();
}
}
internal void SetCompilationOutputs(ProjectId projectId, CompilationOutputs outputs)
{
Contract.ThrowIfNull(outputs);
lock (_projectCompilationOutputsGuard)
{
_projectCompilationOutputs[projectId] = outputs;
}
}
internal CompilationOutputs GetCompilationOutputs(ProjectId projectId)
{
lock (_projectCompilationOutputsGuard)
{
return _projectCompilationOutputs.TryGetValue(projectId, out var outputs) ? outputs : CompilationOutputFiles.None;
}
}
}
}
' 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
Imports Microsoft.CodeAnalysis.Emit
Imports Microsoft.CodeAnalysis.Test.Utilities
Imports Microsoft.CodeAnalysis.VisualBasic
Imports Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem
Imports Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim.Framework
Imports Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim.VisualBasicHelpers
Imports Roslyn.Test.Utilities
......@@ -224,9 +222,6 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim
project.SetCompilerOptions(compilerOptions)
Assert.Equal("C:\test.dll", project.GetOutputFileName())
Dim outputs = CType(environment.Workspace.GetCompilationOutputs(project.Test_VisualStudioProject.Id), CompilationOutputFilesWithImplicitPdbPath)
Assert.Equal("C:\test.dll", outputs.AssemblyFilePath)
' Change output folder from command line arguments - verify that objOutputPath changes.
Dim newPath = "C:\NewFolder\test.dll"
compilerOptions = CreateMinimalCompilerOptions(project)
......@@ -235,9 +230,6 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim
project.SetCompilerOptions(compilerOptions)
Assert.Equal(newPath, project.GetOutputFileName())
outputs = CType(environment.Workspace.GetCompilationOutputs(project.Test_VisualStudioProject.Id), CompilationOutputFilesWithImplicitPdbPath)
Assert.Equal("C:\NewFolder\test.dll", outputs.AssemblyFilePath)
' Change output file name - verify that outputPath changes.
newPath = "C:\NewFolder\test2.dll"
compilerOptions = CreateMinimalCompilerOptions(project)
......@@ -246,9 +238,6 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim
project.SetCompilerOptions(compilerOptions)
Assert.Equal(newPath, project.GetOutputFileName())
outputs = CType(environment.Workspace.GetCompilationOutputs(project.Test_VisualStudioProject.Id), CompilationOutputFilesWithImplicitPdbPath)
Assert.Equal("C:\NewFolder\test2.dll", outputs.AssemblyFilePath)
' Change output file name and folder - verify that outputPath changes.
newPath = "C:\NewFolder3\test3.dll"
compilerOptions = CreateMinimalCompilerOptions(project)
......@@ -256,9 +245,6 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim
compilerOptions.wszExeName = "test3.dll"
project.SetCompilerOptions(compilerOptions)
Assert.Equal(newPath, project.GetOutputFileName())
outputs = CType(environment.Workspace.GetCompilationOutputs(project.Test_VisualStudioProject.Id), CompilationOutputFilesWithImplicitPdbPath)
Assert.Equal("C:\NewFolder3\test3.dll", outputs.AssemblyFilePath)
End Using
End Sub
End Class
......
......@@ -107,7 +107,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim.Fr
Public ReadOnly Property ServiceProvider As IServiceProvider
Public ReadOnly Property ExportProvider As Composition.ExportProvider
Public ReadOnly Property Workspace As VisualStudioWorkspaceImpl
Public ReadOnly Property Workspace As VisualStudioWorkspace
Get
Return _workspace
End Get
......
......@@ -18,6 +18,15 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.ProjectSystemShim.Vi
commandLineParserServiceOpt:=New VisualBasicCommandLineParserService())
End Function
Public Function CreateVisualBasicProjectWithNullBinPath(environment As TestEnvironment, projectName As String) As VisualBasicProject
Return New VisualBasicProject(projectName,
MockCompilerHost.FullFrameworkCompilerHost,
environment.CreateHierarchy(projectName, projectBinPath:=Nothing, projectCapabilities:="VB"),
environment.ServiceProvider,
environment.ThreadingContext,
commandLineParserServiceOpt:=New VisualBasicCommandLineParserService())
End Function
Public Function CreateMinimalCompilerOptions(project As VisualBasicProject) As VBCompilerOptions
Dim options As VBCompilerOptions = Nothing
options.wszExeName = project.AssemblyName + ".exe"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册