提交 0984fad3 编写于 作者: H Heejae Chang

fix analyzer reference round trip issue with shadow copy assembly loader

上级 9b52a613
......@@ -178,10 +178,10 @@ private static Solution UpdateSolution(Solution solution, string projectName, st
{
var (project, document) = GetProjectAndDocument(solution, projectName, documentName);
return document.WithText(GetNameText(document, csAddition, vbAddition)).Project.Solution;
return document.WithText(GetNewText(document, csAddition, vbAddition)).Project.Solution;
}
private static SourceText GetNameText(Document document, string csAddition, string vbAddition)
private static SourceText GetNewText(Document document, string csAddition, string vbAddition)
{
if (document.Project.Language == LanguageNames.CSharp)
{
......
......@@ -85,7 +85,7 @@ public Checksum CreateChecksum(AnalyzerReference reference, CancellationToken ca
using (var stream = SerializableBytes.CreateWritableStream())
using (var writer = new StreamObjectWriter(stream, cancellationToken: cancellationToken))
{
WriteTo(reference, writer, cancellationToken);
WriteTo(reference, writer, checksum: true, cancellationToken: cancellationToken);
stream.Position = 0;
return Checksum.Create(stream);
......@@ -126,50 +126,7 @@ public MetadataReference ReadMetadataReferenceFrom(ObjectReader reader, Cancella
public void WriteTo(AnalyzerReference reference, ObjectWriter writer, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
var file = reference as AnalyzerFileReference;
if (file != null)
{
// fail to load analyzer assembly
var assemblyPath = TryGetAnalyzerAssemblyPath(file);
if (assemblyPath == null)
{
WriteUnresolvedAnalyzerReferenceTo(reference, writer);
return;
}
writer.WriteString(nameof(AnalyzerFileReference));
writer.WriteInt32((int)SerializationKinds.FilePath);
writer.WriteString(file.FullPath);
// TODO: remove this kind of host specific knowledge from common layer.
// but think moving it to host layer where this implementation detail actually exist.
//
// analyzer assembly path to load analyzer acts like
// snapshot version for analyzer (since it is based on shadow copy)
// we can't send over bits and load analyer from memory (image) due to CLR not being able
// to find satellite dlls for analyzers.
writer.WriteString(assemblyPath);
return;
}
var unresolved = reference as UnresolvedAnalyzerReference;
if (unresolved != null)
{
WriteUnresolvedAnalyzerReferenceTo(reference, writer);
return;
}
var image = reference as AnalyzerImageReference;
if (image != null)
{
// TODO: think a way to support this or a way to deal with this kind of situation.
throw new NotSupportedException(nameof(AnalyzerImageReference));
}
throw ExceptionUtilities.UnexpectedValue(reference.GetType());
WriteTo(reference, writer, checksum: false, cancellationToken: cancellationToken);
}
public AnalyzerReference ReadAnalyzerReferenceFrom(ObjectReader reader, CancellationToken cancellationToken)
......@@ -543,6 +500,58 @@ private unsafe void WriteTo(MetadataReader reader, ObjectWriter writer, Cancella
writer.WriteValue(bytes);
}
private void WriteTo(AnalyzerReference reference, ObjectWriter writer, bool checksum, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
var file = reference as AnalyzerFileReference;
if (file != null)
{
// fail to load analyzer assembly
var assemblyPath = TryGetAnalyzerAssemblyPath(file);
if (assemblyPath == null)
{
WriteUnresolvedAnalyzerReferenceTo(reference, writer);
return;
}
writer.WriteString(nameof(AnalyzerFileReference));
writer.WriteInt32((int)SerializationKinds.FilePath);
if (!checksum)
{
// we don't write full path when creating checksum
writer.WriteString(file.FullPath);
}
// TODO: remove this kind of host specific knowledge from common layer.
// but think moving it to host layer where this implementation detail actually exist.
//
// analyzer assembly path to load analyzer acts like
// snapshot version for analyzer (since it is based on shadow copy)
// we can't send over bits and load analyer from memory (image) due to CLR not being able
// to find satellite dlls for analyzers.
writer.WriteString(assemblyPath);
return;
}
var unresolved = reference as UnresolvedAnalyzerReference;
if (unresolved != null)
{
WriteUnresolvedAnalyzerReferenceTo(reference, writer);
return;
}
var image = reference as AnalyzerImageReference;
if (image != null)
{
// TODO: think a way to support this or a way to deal with this kind of situation.
throw new NotSupportedException(nameof(AnalyzerImageReference));
}
throw ExceptionUtilities.UnexpectedValue(reference.GetType());
}
private static void WriteUnresolvedAnalyzerReferenceTo(AnalyzerReference reference, ObjectWriter writer)
{
writer.WriteString(nameof(UnresolvedAnalyzerReference));
......
......@@ -388,6 +388,37 @@ public async Task Missing_Analyzer_Serailization_Desktop_Test()
var assetFromStorage2 = await CloneAssetAsync(serializer, assetFromStorage).ConfigureAwait(false);
}
[Fact]
public async Task RoundTrip_Analyzer_Serailization_Test()
{
var workspace = new AdhocWorkspace();
var serializer = new Serializer(workspace);
var reference = new AnalyzerFileReference(typeof(object).Assembly.Location, new MockShadowCopyAnalyzerAssemblyLoader());
// make sure this doesn't throw
var assetFromFile = SolutionAsset.Create(serializer.CreateChecksum(reference, CancellationToken.None), reference, serializer);
var assetFromStorage = await CloneAssetAsync(serializer, assetFromFile).ConfigureAwait(false);
var assetFromStorage2 = await CloneAssetAsync(serializer, assetFromStorage).ConfigureAwait(false);
}
[Fact]
public async Task RoundTrip_Analyzer_Serailization_Desktop_Test()
{
var hostServices = MefHostServices.Create(
MefHostServices.DefaultAssemblies.Add(typeof(Host.TemporaryStorageServiceFactory.TemporaryStorageService).Assembly));
var workspace = new AdhocWorkspace(hostServices);
var serializer = new Serializer(workspace);
var reference = new AnalyzerFileReference(typeof(object).Assembly.Location, new MockShadowCopyAnalyzerAssemblyLoader());
// make sure this doesn't throw
var assetFromFile = SolutionAsset.Create(serializer.CreateChecksum(reference, CancellationToken.None), reference, serializer);
var assetFromStorage = await CloneAssetAsync(serializer, assetFromFile).ConfigureAwait(false);
var assetFromStorage2 = await CloneAssetAsync(serializer, assetFromStorage).ConfigureAwait(false);
}
[Fact]
public async Task SnapshotWithMissingReferencesTest()
{
......@@ -624,5 +655,18 @@ protected override PortableExecutableReference WithPropertiesImpl(MetadataRefere
return this;
}
}
private class MockShadowCopyAnalyzerAssemblyLoader : IAnalyzerAssemblyLoader
{
public void AddDependencyLocation(string fullPath)
{
}
public Assembly LoadFromPath(string fullPath)
{
// return something other than given one. mimicing behavior of shadow copy
return typeof(SharedAttribute).Assembly;
}
}
}
}
\ No newline at end of file
......@@ -74,6 +74,9 @@ public async Task<Solution> CreateSolutionAsync(Checksum newSolutionChecksum)
solution = await UpdateProjectsAsync(solution, oldSolutionChecksums.Projects, newSolutionChecksums.Projects).ConfigureAwait(false);
}
// make sure created solution has same checksum as given one
Contract.ThrowIfFalse(newSolutionChecksum == await solution.State.GetChecksumAsync(_cancellationToken).ConfigureAwait(false));
return solution;
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册