Skip to content

Commit

Permalink
Merge pull request #14013 from heejaechang/ioexception
Browse files Browse the repository at this point in the history
Merge pull request #13997 from heejaechang/handleException
  • Loading branch information
heejaechang authored Sep 23, 2016
2 parents f62ee52 + 8172192 commit 872c8a4
Show file tree
Hide file tree
Showing 2 changed files with 249 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ namespace Microsoft.CodeAnalysis.Execution
{
internal abstract class AbstractReferenceSerializationService : IReferenceSerializationService
{
private const int MetadataFailed = int.MaxValue;

private static readonly ConditionalWeakTable<Metadata, object> s_lifetimeMap = new ConditionalWeakTable<Metadata, object>();

private readonly ITemporaryStorageService _storageService;
Expand Down Expand Up @@ -92,6 +94,14 @@ public void WriteTo(AnalyzerReference reference, ObjectWriter writer, Cancellati
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);

Expand All @@ -104,7 +114,14 @@ public void WriteTo(AnalyzerReference reference, ObjectWriter writer, Cancellati
// 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(GetAnalyzerAssemblyPath(file));
writer.WriteString(assemblyPath);
return;
}

var unresolved = reference as UnresolvedAnalyzerReference;
if (unresolved != null)
{
WriteUnresolvedAnalyzerReferenceTo(reference, writer);
return;
}

Expand All @@ -115,14 +132,6 @@ public void WriteTo(AnalyzerReference reference, ObjectWriter writer, Cancellati
throw new NotSupportedException(nameof(AnalyzerImageReference));
}

var unresolved = reference as UnresolvedAnalyzerReference;
if (unresolved != null)
{
writer.WriteString(nameof(UnresolvedAnalyzerReference));
writer.WriteString(reference.FullPath);
return;
}

throw ExceptionUtilities.UnexpectedValue(reference.GetType());
}

Expand Down Expand Up @@ -167,16 +176,21 @@ private Checksum CreatePortableExecutableReferenceChecksum(PortableExecutableRef
using (var stream = SerializableBytes.CreateWritableStream())
using (var writer = new ObjectWriter(stream, cancellationToken: cancellationToken))
{
WriteMvidsTo(reference, writer, cancellationToken);
WriteMvidsTo(TryGetMetadata(reference), writer, cancellationToken);

stream.Position = 0;
return Checksum.Create(stream);
}
}

private void WriteMvidsTo(PortableExecutableReference reference, ObjectWriter writer, CancellationToken cancellationToken)
private void WriteMvidsTo(Metadata metadata, ObjectWriter writer, CancellationToken cancellationToken)
{
var metadata = reference.GetMetadata();
if (metadata == null)
{
// handle error case where we couldn't load metadata of the reference.
// this basically won't write anything to writer
return;
}

var assemblyMetadata = metadata as AssemblyMetadata;
if (assemblyMetadata != null)
Expand Down Expand Up @@ -216,7 +230,7 @@ private void WritePortableExecutableReferenceTo(
{
WritePortableExecutableReferenceHeaderTo(reference, SerializationKinds.Bits, writer, cancellationToken);

WriteTo(reference.GetMetadata(), writer, cancellationToken);
WriteTo(TryGetMetadata(reference), writer, cancellationToken);

// TODO: what I should do with documentation provider? it is not exposed outside
}
Expand All @@ -230,11 +244,19 @@ private PortableExecutableReference ReadPortableExecutableReferenceFrom(ObjectRe

var filePath = reader.ReadString();

var tuple = ReadMetadataFrom(reader, kind, cancellationToken);
var tuple = TryReadMetadataFrom(reader, kind, cancellationToken);
if (tuple == null)
{
// TODO: deal with xml document provider properly
// should we shadow copy xml doc comment?

// image doesn't exist
return new MissingMetadataReference(properties, filePath, XmlDocumentationProvider.Default);
}

// TODO: deal with xml document provider properly
// should be shadow copy xml doc comment?
return new SerializedMetadataReference(properties, filePath, tuple.Item1, tuple.Item2, XmlDocumentationProvider.Default);
// should we shadow copy xml doc comment?
return new SerializedMetadataReference(properties, filePath, tuple.Value.Item1, tuple.Value.Item2, XmlDocumentationProvider.Default);
}

throw ExceptionUtilities.UnexpectedValue(kind);
Expand Down Expand Up @@ -262,6 +284,13 @@ private MetadataReferenceProperties ReadMetadataReferencePropertiesFrom(ObjectRe

private void WriteTo(Metadata metadata, ObjectWriter writer, CancellationToken cancellationToken)
{
if (metadata == null)
{
// handle error case where metadata failed to load
writer.WriteInt32(MetadataFailed);
return;
}

var assemblyMetadata = metadata as AssemblyMetadata;
if (assemblyMetadata != null)
{
Expand Down Expand Up @@ -319,10 +348,17 @@ private bool TryWritePortableExecutableReferenceBackedByTemporaryStorageTo(
}
}

private ValueTuple<Metadata, ImmutableArray<ITemporaryStreamStorage>> ReadMetadataFrom(
private ValueTuple<Metadata, ImmutableArray<ITemporaryStreamStorage>>? TryReadMetadataFrom(
ObjectReader reader, SerializationKinds kind, CancellationToken cancellationToken)
{
var metadataKind = (MetadataImageKind)reader.ReadInt32();
var imageKind = reader.ReadInt32();
if (imageKind == MetadataFailed)
{
// error case
return null;
}

var metadataKind = (MetadataImageKind)imageKind;
if (metadataKind == MetadataImageKind.Assembly)
{
using (var pooledMetadata = Creator.CreateList<ModuleMetadata>())
Expand Down Expand Up @@ -466,6 +502,41 @@ private unsafe void WriteTo(MetadataReader reader, ObjectWriter writer, Cancella
writer.WriteValue(bytes);
}

private static void WriteUnresolvedAnalyzerReferenceTo(AnalyzerReference reference, ObjectWriter writer)
{
writer.WriteString(nameof(UnresolvedAnalyzerReference));
writer.WriteString(reference.FullPath);
}

private static Metadata TryGetMetadata(PortableExecutableReference reference)
{
try
{
return reference.GetMetadata();
}
catch
{
// we have a reference but the file the reference is pointing to
// might not actually exist on disk.
// in that case, rather than crashing, we will handle it gracefully.
return null;
}
}

private string TryGetAnalyzerAssemblyPath(AnalyzerFileReference file)
{
try
{
return GetAnalyzerAssemblyPath(file);
}
catch
{
// we can't load the assembly analyzer file reference is pointing to.
// rather than crashing, handle it gracefully
return null;
}
}

private sealed class PinnedObject : IDisposable
{
private readonly GCHandle _gcHandle;
Expand Down Expand Up @@ -500,6 +571,41 @@ public void Dispose()
}
}

private sealed class MissingMetadataReference : PortableExecutableReference
{
private readonly DocumentationProvider _provider;

public MissingMetadataReference(
MetadataReferenceProperties properties, string fullPath, DocumentationProvider initialDocumentation) :
base(properties, fullPath, initialDocumentation)
{
// TODO: doc comment provider is a bit wierd.
_provider = initialDocumentation;
}

protected override DocumentationProvider CreateDocumentationProvider()
{
// TODO: properly implement this
return null;
}

protected override Metadata GetMetadataImpl()
{
// we just throw "FileNotFoundException" even if it might not be actual reason
// why metadata has failed to load. in this context, we don't care much on actual
// reason. we just need to maintain failure when re-constructing solution to maintain
// snapshot integrity.
//
// if anyone care actual reason, he should get that info from original Solution.
throw new FileNotFoundException(FilePath);
}

protected override PortableExecutableReference WithPropertiesImpl(MetadataReferenceProperties properties)
{
return new MissingMetadataReference(properties, FilePath, _provider);
}
}

private sealed class SerializedMetadataReference : PortableExecutableReference, ISupportTemporaryStorage
{
private readonly Metadata _metadata;
Expand Down
Loading

0 comments on commit 872c8a4

Please sign in to comment.