提交 eeb1ea90 编写于 作者: H Heejae Chang 提交者: GitHub

Merge pull request #14083 from heejaechang/unknownlanguage

made checksum builder to resilient to missing data such as compilatio…
......@@ -18,11 +18,29 @@ namespace Microsoft.CodeAnalysis.Execution
/// </summary>
internal abstract class Asset : ChecksumObject
{
public static readonly Asset Null = 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.Null, WellKnownChecksumObjects.Null)
{
}
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 Null = 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 Null = nameof(Null);
public const string Projects = nameof(Projects);
public const string Documents = nameof(Documents);
public const string TextDocuments = nameof(TextDocuments);
......
......@@ -89,8 +89,12 @@ 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.Null if this particular project doesn't support compiler options.
// this one is really bit wierd since project state has both compilation/parse options but only has support compilation.
// for now, we use support compilation for both options
var compilationOptions = projectState.SupportsCompilation ? subAssetBuilder.Build(projectState, projectState.CompilationOptions, cancellationToken) : Asset.Null;
var parseOptions = projectState.SupportsCompilation ? subAssetBuilder.Build(projectState, projectState.ParseOptions, cancellationToken) : Asset.Null;
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.Null)
{
// check nil case
return Asset.Null;
}
// 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.Null))
{
result[Checksum.Null] = Asset.Null;
}
// 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.Null:
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.
先完成此消息的编辑!
想要评论请 注册