提交 fc8692ea 编写于 作者: H Heejae Chang

make sure we use normalized string when creating analyzer reference checksum

make sure we use ordered list of document/projectIds when creating checksum
make sure we set HasAllInformation when creating projectInfo

added unit test
上级 7a69be81
......@@ -157,6 +157,40 @@ public async Task TestUpdateDocumentInfo()
await VerifySolutionUpdate(code, s => s.WithDocumentFolders(s.Projects.First().Documents.First().Id, new[] { "test" }));
}
[Fact, Trait(Traits.Feature, Traits.Features.RemoteHost)]
public async Task TestHasAllInformation()
{
var code = @"class Test { void Method() { } }";
await VerifySolutionUpdate(code, s => s.WithHasAllInformation(s.ProjectIds.First(), false));
}
[Fact, Trait(Traits.Feature, Traits.Features.RemoteHost)]
public async Task TestAddUpdateRemoveProjects()
{
var code = @"class Test { void Method() { } }";
await VerifySolutionUpdate(code, s =>
{
var existingProjectId = s.ProjectIds.First();
s = s.AddProject("newProject", "newProject", LanguageNames.CSharp).Solution;
var project = s.GetProject(existingProjectId);
project = project.WithCompilationOptions(project.CompilationOptions.WithModuleName("modified"));
var existingDocumentId = project.DocumentIds.First();
project = project.AddDocument("newDocument", SourceText.From("// new text")).Project;
var document = project.GetDocument(existingDocumentId);
document = document.WithSourceCodeKind(SourceCodeKind.Script);
return document.Project.Solution;
});
}
private static async Task VerifySolutionUpdate(string code, Func<Solution, Solution> newSolutionGetter)
{
using (var workspace = await TestWorkspace.CreateCSharpAsync(code))
......
......@@ -518,10 +518,13 @@ private void WriteTo(AnalyzerReference reference, ObjectWriter writer, bool chec
writer.WriteString(nameof(AnalyzerFileReference));
writer.WriteInt32((int)SerializationKinds.FilePath);
if (!checksum)
if (checksum)
{
// we don't write full path when creating checksum
writer.WriteString(file.FullPath);
// make sure we always normalize assemblyPath to lower case since it comes from Assembly.Location
// unlike FullPath which comes from string
writer.WriteString(assemblyPath.ToLowerInvariant());
return;
}
// TODO: remove this kind of host specific knowledge from common layer.
......@@ -531,6 +534,7 @@ private void WriteTo(AnalyzerReference reference, ObjectWriter writer, bool chec
// 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(file.FullPath);
writer.WriteString(assemblyPath);
return;
}
......
// 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.Collections.Immutable;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Internal.Log;
......@@ -33,8 +32,11 @@ private async Task<ProjectStateChecksums> ComputeChecksumsAsync(CancellationToke
using (Logger.LogBlock(FunctionId.ProjectState_ComputeChecksumsAsync, FilePath, cancellationToken))
{
// get states by id order to have deterministic checksum
var documentChecksumsTasks = DocumentIds.Select(id => DocumentStates[id].GetChecksumAsync(cancellationToken));
var additionalDocumentChecksumTasks = AdditionalDocumentIds.Select(id => AdditionalDocumentStates[id].GetChecksumAsync(cancellationToken));
var orderedDocumentIds = ChecksumCache.GetOrCreate(DocumentIds, _ => DocumentIds.OrderBy(id => id.Id).ToImmutableArray());
var documentChecksumsTasks = orderedDocumentIds.Select(id => DocumentStates[id].GetChecksumAsync(cancellationToken));
var orderedAdditionalDocumentIds = ChecksumCache.GetOrCreate(AdditionalDocumentIds, _ => AdditionalDocumentIds.OrderBy(id => id.Id).ToImmutableArray());
var additionalDocumentChecksumTasks = orderedAdditionalDocumentIds.Select(id => AdditionalDocumentStates[id].GetChecksumAsync(cancellationToken));
var serializer = new Serializer(_solutionServices.Workspace);
......@@ -62,25 +64,5 @@ private async Task<ProjectStateChecksums> ComputeChecksumsAsync(CancellationToke
new TextDocumentChecksumCollection(additionalChecksums));
}
}
/// <summary>
/// hold onto object checksum that currently doesn't have a place to hold onto checksum
/// </summary>
private static class ChecksumCache
{
private static readonly ConditionalWeakTable<object, object> s_cache = new ConditionalWeakTable<object, object>();
public static Checksum GetOrCreate(object value, ConditionalWeakTable<object, object>.CreateValueCallback checksumCreator)
{
// same key should always return same checksum
return (Checksum)s_cache.GetValue(value, checksumCreator);
}
public static T GetOrCreate<T>(object value, ConditionalWeakTable<object, object>.CreateValueCallback checksumCreator) where T : IChecksummedObject
{
// same key should always return same checksum
return (T)s_cache.GetValue(value, checksumCreator);
}
}
}
}
// 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.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
......@@ -32,9 +33,10 @@ private async Task<SolutionStateChecksums> ComputeChecksumsAsync(CancellationTok
using (Logger.LogBlock(FunctionId.SolutionState_ComputeChecksumsAsync, FilePath, cancellationToken))
{
// get states by id order to have deterministic checksum
var projectChecksumTasks = ProjectIds.Select(id => ProjectStates[id])
.Where(s => RemoteSupportedLanguages.IsSupported(s.Language))
.Select(s => s.GetChecksumAsync(cancellationToken));
var orderedProjectIds = ChecksumCache.GetOrCreate(ProjectIds, _ => ProjectIds.OrderBy(id => id.Id).ToImmutableArray());
var projectChecksumTasks = orderedProjectIds.Select(id => ProjectStates[id])
.Where(s => RemoteSupportedLanguages.IsSupported(s.Language))
.Select(s => s.GetChecksumAsync(cancellationToken));
var serializer = new Serializer(_solutionServices.Workspace);
var infoChecksum = serializer.CreateChecksum(SolutionInfo.Attributes, cancellationToken);
......
......@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Runtime.CompilerServices;
using System.Threading;
using Microsoft.CodeAnalysis.Remote;
using Roslyn.Utilities;
......@@ -263,4 +264,29 @@ public DocumentStateChecksums(params object[] children) : base(nameof(DocumentSt
}
}
}
/// <summary>
/// hold onto object checksum that currently doesn't have a place to hold onto checksum
/// </summary>
internal static class ChecksumCache
{
private static readonly ConditionalWeakTable<object, object> s_cache = new ConditionalWeakTable<object, object>();
public static IReadOnlyList<T> GetOrCreate<T>(IReadOnlyList<T> unorderedList, ConditionalWeakTable<object, object>.CreateValueCallback orderedListGetter)
{
return (IReadOnlyList<T>)s_cache.GetValue(unorderedList, orderedListGetter);
}
public static Checksum GetOrCreate(object value, ConditionalWeakTable<object, object>.CreateValueCallback checksumCreator)
{
// same key should always return same checksum
return (Checksum)s_cache.GetValue(value, checksumCreator);
}
public static T GetOrCreate<T>(object value, ConditionalWeakTable<object, object>.CreateValueCallback checksumCreator) where T : IChecksummedObject
{
// same key should always return same checksum
return (T)s_cache.GetValue(value, checksumCreator);
}
}
}
......@@ -138,6 +138,9 @@ public async Task CreateSolutionSnapshotId_Full()
{
var solution = CreateFullSolution();
var firstProjectChecksum = await solution.GetProject(solution.ProjectIds[0]).State.GetChecksumAsync(CancellationToken.None);
var secondProjectChecksum = await solution.GetProject(solution.ProjectIds[1]).State.GetChecksumAsync(CancellationToken.None);
var snapshotService = (new SolutionSynchronizationServiceFactory()).CreateService(solution.Workspace.Services) as ISolutionSynchronizationService;
using (var snapshot = await snapshotService.CreatePinnedRemotableDataScopeAsync(solution, CancellationToken.None).ConfigureAwait(false))
{
......@@ -151,8 +154,8 @@ public async Task CreateSolutionSnapshotId_Full()
Assert.Equal(solutionObject.Projects.Count, 2);
var projects = solutionObject.Projects.ToProjectObjects(snapshotService);
VerifySnapshotInService(snapshotService, projects[0], 1, 1, 1, 1, 1);
VerifySnapshotInService(snapshotService, projects[1], 1, 0, 0, 0, 0);
VerifySnapshotInService(snapshotService, projects.Where(p => p.Checksum == firstProjectChecksum).First(), 1, 1, 1, 1, 1);
VerifySnapshotInService(snapshotService, projects.Where(p => p.Checksum == secondProjectChecksum).First(), 1, 0, 0, 0, 0);
}
}
......
......@@ -453,7 +453,7 @@ private async Task<ProjectInfo> CreateProjectInfoAsync(Checksum projectChecksum)
projectInfo.Id, projectInfo.Version, projectInfo.Name, projectInfo.AssemblyName,
projectInfo.Language, projectInfo.FilePath, projectInfo.OutputFilePath,
compilationOptions, parseOptions,
documents, p2p, metadata, analyzers, additionals, projectInfo.IsSubmission);
documents, p2p, metadata, analyzers, additionals, projectInfo.IsSubmission).WithHasAllInformation(projectInfo.HasAllInformation);
}
private async Task<List<T>> CreateCollectionAsync<T>(ChecksumCollection collections)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册