提交 74213c90 编写于 作者: H Heejae Chang 提交者: Jinu

Removed missing references and p2p transitiveness from project succes… (#23246)

* removed missing references and p2p transitiveness from project successfully loaded check.

also, now we log skeleton assembly failure reasons to improve those common cases

* fixed test failure due to transitiveness change.
上级 0a28f402
......@@ -400,5 +400,6 @@ internal enum FunctionId
AssetStorage_ForceGC,
RemoteHost_Bitness,
Intellisense_Completion,
MetadataOnlyImage_EmitFailure,
}
}
// 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.Runtime.CompilerServices;
using System.Threading;
using Microsoft.CodeAnalysis.Emit;
......@@ -65,6 +66,15 @@ public static MetadataOnlyImage Create(Workspace workspace, ITemporaryStorageSer
{
workspace.LogTestMessage(" " + diagnostic.GetMessage());
}
// log emit failures so that we can improve most common cases
Logger.Log(FunctionId.MetadataOnlyImage_EmitFailure, KeyValueLogMessage.Create(m =>
{
// log errors in the format of
// CS0001:1;CS002:10;...
var groups = emitResult.Diagnostics.GroupBy(d => d.Id).Select(g => $"{g.Key}:{g.Count()}");
m["Errors"] = string.Join(";", groups);
}));
}
}
}
......
......@@ -39,7 +39,7 @@ private class State
/// Specifies whether <see cref="FinalCompilation"/> and all compilations it depends on contain full information or not. This can return
/// null if the state isn't at the point where it would know, and it's necessary to transition to <see cref="FinalState"/> to figure that out.
/// </summary>
public virtual bool? HasSuccessfullyLoadedTransitively => null;
public virtual bool? HasSuccessfullyLoaded => null;
/// <summary>
/// The final compilation if available, otherwise an empty <see cref="ValueSource{Compilation}"/>.
......@@ -132,15 +132,15 @@ public FullDeclarationState(Compilation declarationCompilation)
/// </summary>
private sealed class FinalState : State
{
private readonly bool _hasSuccessfullyLoadedTransitively;
private readonly bool _hasSuccessfullyLoaded;
public override bool? HasSuccessfullyLoadedTransitively => _hasSuccessfullyLoadedTransitively;
public override bool? HasSuccessfullyLoaded => _hasSuccessfullyLoaded;
public override ValueSource<Compilation> FinalCompilation => this.Compilation;
public FinalState(ValueSource<Compilation> finalCompilationSource, bool hasSuccessfullyLoadedTransitively)
public FinalState(ValueSource<Compilation> finalCompilationSource, bool hasSuccessfullyLoaded)
: base(finalCompilationSource, finalCompilationSource.GetValue().Clone().RemoveAllReferences())
{
_hasSuccessfullyLoadedTransitively = hasSuccessfullyLoadedTransitively;
_hasSuccessfullyLoaded = hasSuccessfullyLoaded;
}
}
}
......
......@@ -178,7 +178,7 @@ public CompilationTracker FreezePartialStateWithTree(SolutionState solution, Doc
// have the compilation immediately disappear. So we force it to stay around with a ConstantValueSource.
// As a policy, all partial-state projects are said to have incomplete references, since the state has no guarantees.
return new CompilationTracker(inProgressProject,
new FinalState(new ConstantValueSource<Compilation>(inProgressCompilation), hasSuccessfullyLoadedTransitively: false));
new FinalState(new ConstantValueSource<Compilation>(inProgressCompilation), hasSuccessfullyLoaded: false));
}
/// <summary>
......@@ -395,7 +395,7 @@ private async Task<Compilation> GetOrBuildDeclarationCompilationAsync(SolutionSt
var finalCompilation = state.FinalCompilation.GetValue(cancellationToken);
if (finalCompilation != null)
{
return new CompilationInfo(finalCompilation, state.HasSuccessfullyLoadedTransitively.Value);
return new CompilationInfo(finalCompilation, state.HasSuccessfullyLoaded.Value);
}
// Otherwise, we actually have to build it. Ensure that only one thread is trying to
......@@ -436,7 +436,7 @@ private async Task<Compilation> GetOrBuildDeclarationCompilationAsync(SolutionSt
var compilation = state.FinalCompilation.GetValue(cancellationToken);
if (compilation != null)
{
return Task.FromResult(new CompilationInfo(compilation, state.HasSuccessfullyLoadedTransitively.Value));
return Task.FromResult(new CompilationInfo(compilation, state.HasSuccessfullyLoaded.Value));
}
compilation = state.Compilation.GetValue(cancellationToken);
......@@ -571,12 +571,12 @@ private Compilation CreateEmptyCompilation()
private struct CompilationInfo
{
public Compilation Compilation { get; }
public bool HasSuccessfullyLoadedTransitively { get; }
public bool HasSuccessfullyLoaded { get; }
public CompilationInfo(Compilation compilation, bool hasSuccessfullyLoadedTransitively)
public CompilationInfo(Compilation compilation, bool hasSuccessfullyLoaded)
{
this.Compilation = compilation;
this.HasSuccessfullyLoadedTransitively = hasSuccessfullyLoadedTransitively;
this.HasSuccessfullyLoaded = hasSuccessfullyLoaded;
}
}
......@@ -640,11 +640,9 @@ public CompilationInfo(Compilation compilation, bool hasSuccessfullyLoadedTransi
compilation = UpdateCompilationWithNewReferencesAndRecordAssemblySymbols(compilation, newReferences, metadataReferenceToProjectId);
bool hasSuccessfullyLoadedTransitively = !HasMissingReferences(compilation, this.ProjectState.MetadataReferences) && await ComputeHasSuccessfullyLoadedTransitivelyAsync(solution, hasSuccessfullyLoaded, cancellationToken).ConfigureAwait(false);
this.WriteState(new FinalState(State.CreateValueSource(compilation, solution.Services), hasSuccessfullyLoaded), solution);
this.WriteState(new FinalState(State.CreateValueSource(compilation, solution.Services), hasSuccessfullyLoadedTransitively), solution);
return new CompilationInfo(compilation, hasSuccessfullyLoadedTransitively);
return new CompilationInfo(compilation, hasSuccessfullyLoaded);
}
catch (Exception e) when (FatalError.ReportUnlessCanceled(e))
{
......@@ -675,44 +673,6 @@ private Compilation UpdateCompilationWithNewReferencesAndRecordAssemblySymbols(C
return compilation;
}
private bool HasMissingReferences(Compilation compilation, IReadOnlyList<MetadataReference> metadataReferences)
{
foreach (var reference in metadataReferences)
{
if (compilation.GetAssemblyOrModuleSymbol(reference) == null)
{
return true;
}
}
return false;
}
private async Task<bool> ComputeHasSuccessfullyLoadedTransitivelyAsync(
SolutionState solution, bool hasSuccessfullyLoaded, CancellationToken cancellationToken)
{
if (!hasSuccessfullyLoaded)
{
return false;
}
foreach (var projectReference in this.ProjectState.ProjectReferences)
{
var project = solution.GetProjectState(projectReference.ProjectId);
if (project == null)
{
return false;
}
if (!await solution.HasSuccessfullyLoadedAsync(project, cancellationToken).ConfigureAwait(false))
{
return false;
}
}
return true;
}
/// <summary>
/// Get a metadata reference to this compilation info's compilation with respect to
/// another project. For cross language references produce a skeletal assembly. If the
......@@ -853,9 +813,9 @@ public Task<bool> HasSuccessfullyLoadedAsync(SolutionState solution, Cancellatio
{
var state = this.ReadState();
if (state.HasSuccessfullyLoadedTransitively.HasValue)
if (state.HasSuccessfullyLoaded.HasValue)
{
return state.HasSuccessfullyLoadedTransitively.Value ? SpecializedTasks.True : SpecializedTasks.False;
return state.HasSuccessfullyLoaded.Value ? SpecializedTasks.True : SpecializedTasks.False;
}
else
{
......@@ -866,7 +826,7 @@ public Task<bool> HasSuccessfullyLoadedAsync(SolutionState solution, Cancellatio
private async Task<bool> HasSuccessfullyLoadedSlowAsync(SolutionState solution, CancellationToken cancellationToken)
{
var compilationInfo = await GetOrBuildCompilationInfoAsync(solution, lockGate: true, cancellationToken: cancellationToken).ConfigureAwait(false);
return compilationInfo.HasSuccessfullyLoadedTransitively;
return compilationInfo.HasSuccessfullyLoaded;
}
#region Versions
......
......@@ -1404,14 +1404,14 @@ public void TestProjectCompletenessWithMultipleProjects()
Assert.True(vbNormalProject.HasSuccessfullyLoadedAsync().Result);
// check flag for normal project that directly reference a broken project
Assert.False(dependsOnBrokenProject.HasSuccessfullyLoadedAsync().Result);
Assert.True(dependsOnBrokenProject.HasSuccessfullyLoadedAsync().Result);
// check flag for normal project that directly reference only normal project
Assert.True(dependsOnVbNormalProject.HasSuccessfullyLoadedAsync().Result);
// check flag for normal project that indirectly reference a borken project
// normal project -> normal project -> broken project
Assert.False(transitivelyDependsOnBrokenProjects.HasSuccessfullyLoadedAsync().Result);
Assert.True(transitivelyDependsOnBrokenProjects.HasSuccessfullyLoadedAsync().Result);
// check flag for normal project that indirectly reference only normal project
// normal project -> normal project -> normal project
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册