提交 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 ...@@ -400,5 +400,6 @@ internal enum FunctionId
AssetStorage_ForceGC, AssetStorage_ForceGC,
RemoteHost_Bitness, RemoteHost_Bitness,
Intellisense_Completion, 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. // 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.Collections.Immutable;
using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Threading; using System.Threading;
using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.Emit;
...@@ -65,6 +66,15 @@ public static MetadataOnlyImage Create(Workspace workspace, ITemporaryStorageSer ...@@ -65,6 +66,15 @@ public static MetadataOnlyImage Create(Workspace workspace, ITemporaryStorageSer
{ {
workspace.LogTestMessage(" " + diagnostic.GetMessage()); 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 ...@@ -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 /// 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. /// 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> /// </summary>
public virtual bool? HasSuccessfullyLoadedTransitively => null; public virtual bool? HasSuccessfullyLoaded => null;
/// <summary> /// <summary>
/// The final compilation if available, otherwise an empty <see cref="ValueSource{Compilation}"/>. /// The final compilation if available, otherwise an empty <see cref="ValueSource{Compilation}"/>.
...@@ -132,15 +132,15 @@ public FullDeclarationState(Compilation declarationCompilation) ...@@ -132,15 +132,15 @@ public FullDeclarationState(Compilation declarationCompilation)
/// </summary> /// </summary>
private sealed class FinalState : State 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 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()) : base(finalCompilationSource, finalCompilationSource.GetValue().Clone().RemoveAllReferences())
{ {
_hasSuccessfullyLoadedTransitively = hasSuccessfullyLoadedTransitively; _hasSuccessfullyLoaded = hasSuccessfullyLoaded;
} }
} }
} }
......
...@@ -178,7 +178,7 @@ public CompilationTracker FreezePartialStateWithTree(SolutionState solution, Doc ...@@ -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. // 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. // As a policy, all partial-state projects are said to have incomplete references, since the state has no guarantees.
return new CompilationTracker(inProgressProject, return new CompilationTracker(inProgressProject,
new FinalState(new ConstantValueSource<Compilation>(inProgressCompilation), hasSuccessfullyLoadedTransitively: false)); new FinalState(new ConstantValueSource<Compilation>(inProgressCompilation), hasSuccessfullyLoaded: false));
} }
/// <summary> /// <summary>
...@@ -395,7 +395,7 @@ private async Task<Compilation> GetOrBuildDeclarationCompilationAsync(SolutionSt ...@@ -395,7 +395,7 @@ private async Task<Compilation> GetOrBuildDeclarationCompilationAsync(SolutionSt
var finalCompilation = state.FinalCompilation.GetValue(cancellationToken); var finalCompilation = state.FinalCompilation.GetValue(cancellationToken);
if (finalCompilation != null) 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 // 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 ...@@ -436,7 +436,7 @@ private async Task<Compilation> GetOrBuildDeclarationCompilationAsync(SolutionSt
var compilation = state.FinalCompilation.GetValue(cancellationToken); var compilation = state.FinalCompilation.GetValue(cancellationToken);
if (compilation != null) 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); compilation = state.Compilation.GetValue(cancellationToken);
...@@ -571,12 +571,12 @@ private Compilation CreateEmptyCompilation() ...@@ -571,12 +571,12 @@ private Compilation CreateEmptyCompilation()
private struct CompilationInfo private struct CompilationInfo
{ {
public Compilation Compilation { get; } 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.Compilation = compilation;
this.HasSuccessfullyLoadedTransitively = hasSuccessfullyLoadedTransitively; this.HasSuccessfullyLoaded = hasSuccessfullyLoaded;
} }
} }
...@@ -640,11 +640,9 @@ public CompilationInfo(Compilation compilation, bool hasSuccessfullyLoadedTransi ...@@ -640,11 +640,9 @@ public CompilationInfo(Compilation compilation, bool hasSuccessfullyLoadedTransi
compilation = UpdateCompilationWithNewReferencesAndRecordAssemblySymbols(compilation, newReferences, metadataReferenceToProjectId); 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, hasSuccessfullyLoaded);
return new CompilationInfo(compilation, hasSuccessfullyLoadedTransitively);
} }
catch (Exception e) when (FatalError.ReportUnlessCanceled(e)) catch (Exception e) when (FatalError.ReportUnlessCanceled(e))
{ {
...@@ -675,44 +673,6 @@ private Compilation UpdateCompilationWithNewReferencesAndRecordAssemblySymbols(C ...@@ -675,44 +673,6 @@ private Compilation UpdateCompilationWithNewReferencesAndRecordAssemblySymbols(C
return compilation; 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> /// <summary>
/// Get a metadata reference to this compilation info's compilation with respect to /// 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 /// another project. For cross language references produce a skeletal assembly. If the
...@@ -853,9 +813,9 @@ public Task<bool> HasSuccessfullyLoadedAsync(SolutionState solution, Cancellatio ...@@ -853,9 +813,9 @@ public Task<bool> HasSuccessfullyLoadedAsync(SolutionState solution, Cancellatio
{ {
var state = this.ReadState(); 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 else
{ {
...@@ -866,7 +826,7 @@ public Task<bool> HasSuccessfullyLoadedAsync(SolutionState solution, Cancellatio ...@@ -866,7 +826,7 @@ public Task<bool> HasSuccessfullyLoadedAsync(SolutionState solution, Cancellatio
private async Task<bool> HasSuccessfullyLoadedSlowAsync(SolutionState solution, CancellationToken cancellationToken) private async Task<bool> HasSuccessfullyLoadedSlowAsync(SolutionState solution, CancellationToken cancellationToken)
{ {
var compilationInfo = await GetOrBuildCompilationInfoAsync(solution, lockGate: true, cancellationToken: cancellationToken).ConfigureAwait(false); var compilationInfo = await GetOrBuildCompilationInfoAsync(solution, lockGate: true, cancellationToken: cancellationToken).ConfigureAwait(false);
return compilationInfo.HasSuccessfullyLoadedTransitively; return compilationInfo.HasSuccessfullyLoaded;
} }
#region Versions #region Versions
......
...@@ -1404,14 +1404,14 @@ public void TestProjectCompletenessWithMultipleProjects() ...@@ -1404,14 +1404,14 @@ public void TestProjectCompletenessWithMultipleProjects()
Assert.True(vbNormalProject.HasSuccessfullyLoadedAsync().Result); Assert.True(vbNormalProject.HasSuccessfullyLoadedAsync().Result);
// check flag for normal project that directly reference a broken project // 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 // check flag for normal project that directly reference only normal project
Assert.True(dependsOnVbNormalProject.HasSuccessfullyLoadedAsync().Result); Assert.True(dependsOnVbNormalProject.HasSuccessfullyLoadedAsync().Result);
// check flag for normal project that indirectly reference a borken project // check flag for normal project that indirectly reference a borken project
// normal project -> normal project -> broken 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 // check flag for normal project that indirectly reference only normal project
// normal project -> normal project -> 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.
先完成此消息的编辑!
想要评论请 注册