提交 7d440446 编写于 作者: H Heejae Chang

made checksum builder to resilient to missing data such as compilation/parse...

made checksum builder to resilient to missing data such as compilation/parse options which some projects such as typescript don't have.

also made creating solution to only include project type workspace knows about to create.

some of these will change once checksum moves into solution state itself, but the concept of having Null data will remain to support projects that don't have all data or filtering out projects that workspace doesn't know how to craete.
上级 52523854
......@@ -18,11 +18,29 @@ namespace Microsoft.CodeAnalysis.Execution
/// </summary>
internal abstract class Asset : ChecksumObject
{
public static readonly Asset Nil = new NullAsset();
public Asset(Checksum checksum, string kind) : base(checksum, kind)
{
// TODO: find out a way to reduce number of asset implementations.
// tried once but couldn't figure out
}
/// <summary>
/// null asset indicating things that doesn't actually exist
/// </summary>
private sealed class NullAsset : Asset
{
public NullAsset() :
base(Checksum.Nil, WellKnownChecksumObjects.Nil)
{
}
public override Task WriteObjectToAsync(ObjectWriter writer, CancellationToken cancellationToken)
{
return SpecializedTasks.EmptyTask;
}
}
}
/// <summary>
......
......@@ -14,6 +14,8 @@ namespace Microsoft.CodeAnalysis.Execution
/// </summary>
internal sealed partial class Checksum : IObjectWritable, IEquatable<Checksum>
{
public static readonly Checksum Nil = new Checksum(ImmutableArray<byte>.Empty);
private readonly ImmutableArray<byte> _checkSum;
private int _lazyHash;
......
......@@ -73,6 +73,8 @@ private static Checksum CreateChecksum(string kind, object[] children)
// TODO: Kind might not actually needed. see whether we can get rid of this
internal static class WellKnownChecksumObjects
{
public const string Nil = nameof(Nil);
public const string Projects = nameof(Projects);
public const string Documents = nameof(Documents);
public const string TextDocuments = nameof(TextDocuments);
......
......@@ -89,8 +89,10 @@ private async Task<ProjectChecksumObject> CreateProjectChecksumObjectAsync(Proje
var additionalDocuments = await subSnapshotBuilder.BuildAsync(projectState.AdditionalDocumentStates, projectState.AdditionalDocumentIds.Select(id => projectState.AdditionalDocumentStates[id]), WellKnownChecksumObjects.TextDocuments, cancellationToken).ConfigureAwait(false);
var subAssetBuilder = new AssetBuilder(subTreeNode);
var compilationOptions = subAssetBuilder.Build(projectState, projectState.CompilationOptions, cancellationToken);
var parseOptions = subAssetBuilder.Build(projectState, projectState.ParseOptions, cancellationToken);
// set Asset.Nil if this particular project doesn't support compiler options
var compilationOptions = projectState.CompilationOptions != null ? subAssetBuilder.Build(projectState, projectState.CompilationOptions, cancellationToken) : Asset.Nil;
var parseOptions = projectState.ParseOptions != null ? subAssetBuilder.Build(projectState, projectState.ParseOptions, cancellationToken) : Asset.Nil;
return new ProjectChecksumObject(
_serializer, info.Checksum, compilationOptions.Checksum, parseOptions.Checksum,
......
......@@ -73,6 +73,12 @@ public IRootChecksumTreeNode CreateRootTreeNode(SolutionState solutionState)
public ChecksumObject GetChecksumObject(Checksum checksum, CancellationToken cancellationToken)
{
if (checksum == Checksum.Nil)
{
// check nil case
return Asset.Nil;
}
// search snapshots we have
foreach (var kv in _rootTreeNodes)
{
......@@ -105,7 +111,13 @@ public ChecksumObject GetChecksumObject(Checksum checksum, CancellationToken can
using (var searchingChecksumsLeft = Creator.CreateChecksumSet(checksums))
{
var numberOfChecksumsToSearch = searchingChecksumsLeft.Object.Count;
var result = new Dictionary<Checksum, ChecksumObject>();
var result = new Dictionary<Checksum, ChecksumObject>(numberOfChecksumsToSearch);
// check nil case
if (searchingChecksumsLeft.Object.Remove(Checksum.Nil))
{
result[Checksum.Nil] = Asset.Nil;
}
// search checksum trees we have
foreach (var kv in _rootTreeNodes)
......
......@@ -43,6 +43,9 @@ public T Deserialize<T>(string kind, ObjectReader reader, CancellationToken canc
switch (kind)
{
case WellKnownChecksumObjects.Nil:
return default(T);
case SolutionChecksumObject.Name:
return (T)(object)DeserializeChecksumObjectWithChildren(reader, cancellationToken);
case ProjectChecksumObject.Name:
......
......@@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
using System.Composition;
using System.IO;
using System.Linq;
using System.Reflection;
......@@ -11,6 +12,7 @@
using Microsoft.CodeAnalysis.CSharp.CodeStyle;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Execution;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Text;
......@@ -493,6 +495,23 @@ public async Task SnapshotWithMissingReferencesTest()
}
}
[Fact]
public async Task UnknownLanguageTest()
{
var hostServices = MefHostServices.Create(MefHostServices.DefaultAssemblies.Add(typeof(NullLanguageService).Assembly));
var solution = new AdhocWorkspace(hostServices).CurrentSolution;
var project1 = solution.AddProject("Project", "Project.dll", NullLanguageService.TestLanguage);
var snapshotService = (new SolutionChecksumServiceFactory()).CreateService(solution.Workspace.Services) as ISolutionChecksumService;
using (var snapshot = await snapshotService.CreateChecksumAsync(project1.Solution, CancellationToken.None).ConfigureAwait(false))
{
// this shouldn't throw
var recovered = await GetSolutionAsync(snapshotService, snapshot).ConfigureAwait(false);
}
}
private static async Task VerifyOptionSetsAsync(Workspace workspace, string language)
{
var assetBuilder = new AssetBuilder(workspace.CurrentSolution);
......@@ -522,12 +541,17 @@ private static async Task VerifyOptionSetsAsync(Workspace workspace, string lang
private async Task<Solution> GetSolutionAsync(ISolutionChecksumService service, ChecksumScope snapshot)
{
var workspace = new AdhocWorkspace();
var solutionInfo = await GetValueAsync<SolutionChecksumObjectInfo>(service, snapshot.SolutionChecksum.Info, WellKnownChecksumObjects.SolutionChecksumObjectInfo).ConfigureAwait(false);
var projects = new List<ProjectInfo>();
foreach (var projectSnapshot in snapshot.SolutionChecksum.Projects.ToProjectObjects(service))
{
var projectInfo = await GetValueAsync<ProjectChecksumObjectInfo>(service, projectSnapshot.Info, WellKnownChecksumObjects.ProjectChecksumObjectInfo).ConfigureAwait(false);
if (!workspace.Services.IsSupported(projectInfo.Language))
{
continue;
}
var documents = new List<DocumentInfo>();
foreach (var documentSnapshot in projectSnapshot.Documents.ToDocumentObjects(service))
{
......@@ -584,7 +608,6 @@ private async Task<Solution> GetSolutionAsync(ISolutionChecksumService service,
documentInfo.IsGenerated));
}
var projectInfo = await GetValueAsync<ProjectChecksumObjectInfo>(service, projectSnapshot.Info, WellKnownChecksumObjects.ProjectChecksumObjectInfo).ConfigureAwait(false);
var compilationOptions = await GetValueAsync<CompilationOptions>(service, projectSnapshot.CompilationOptions, WellKnownChecksumObjects.CompilationOptions).ConfigureAwait(false);
var parseOptions = await GetValueAsync<ParseOptions>(service, projectSnapshot.ParseOptions, WellKnownChecksumObjects.ParseOptions).ConfigureAwait(false);
......@@ -631,6 +654,16 @@ private static Asset BuildAsset(AssetBuilder builder, string kind, object value)
}
}
private interface INullLanguageService : ILanguageService { }
[ExportLanguageService(typeof(INullLanguageService), TestLanguage), Shared]
private class NullLanguageService : INullLanguageService
{
public const string TestLanguage = nameof(TestLanguage);
// do nothing
}
private class MissingAnalyzerLoader : AnalyzerAssemblyLoader
{
protected override Assembly LoadFromPathImpl(string fullPath)
......
......@@ -79,6 +79,14 @@ private async Task<Solution> CreateSolutionAsync(Checksum solutionChecksum, Canc
{
var projectSnapshot = await RoslynServices.AssetService.GetAssetAsync<ProjectChecksumObject>(projectChecksum, cancellationToken).ConfigureAwait(false);
var projectInfo = await RoslynServices.AssetService.GetAssetAsync<ProjectChecksumObjectInfo>(projectSnapshot.Info, cancellationToken).ConfigureAwait(false);
if (!workspace.Services.IsSupported(projectInfo.Language))
{
// only add project our workspace supports.
// workspace doesn't allow creating project with unknown languages
continue;
}
var documents = new List<DocumentInfo>();
foreach (var documentChecksum in projectSnapshot.Documents)
{
......@@ -146,7 +154,6 @@ private async Task<Solution> CreateSolutionAsync(Checksum solutionChecksum, Canc
documentInfo.IsGenerated));
}
var projectInfo = await RoslynServices.AssetService.GetAssetAsync<ProjectChecksumObjectInfo>(projectSnapshot.Info, cancellationToken).ConfigureAwait(false);
var compilationOptions = await RoslynServices.AssetService.GetAssetAsync<CompilationOptions>(projectSnapshot.CompilationOptions, cancellationToken).ConfigureAwait(false);
var parseOptions = await RoslynServices.AssetService.GetAssetAsync<ParseOptions>(projectSnapshot.ParseOptions, cancellationToken).ConfigureAwait(false);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册