Skip to content

Commit

Permalink
Remove OldResult value from ProjectAnalysisData (#77035)
Browse files Browse the repository at this point in the history
  • Loading branch information
CyrusNajmabadi authored Feb 4, 2025
2 parents 5bbda37 + ace22da commit f4c1b45
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 107 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,139 +10,121 @@
using Microsoft.CodeAnalysis.Workspaces.Diagnostics;
using Roslyn.Utilities;

namespace Microsoft.CodeAnalysis.Diagnostics.EngineV2
namespace Microsoft.CodeAnalysis.Diagnostics.EngineV2;

internal partial class DiagnosticIncrementalAnalyzer
{
internal partial class DiagnosticIncrementalAnalyzer
/// <summary>
/// Simple data holder for local diagnostics for an analyzer
/// </summary>
private readonly struct DocumentAnalysisData
{
public static readonly DocumentAnalysisData Empty = new(VersionStamp.Default, lineCount: 0, []);

/// <summary>
/// Simple data holder for local diagnostics for an analyzer
/// Version of the diagnostic data.
/// </summary>
private readonly struct DocumentAnalysisData
{
public static readonly DocumentAnalysisData Empty = new(VersionStamp.Default, lineCount: 0, []);
public readonly VersionStamp Version;

/// <summary>
/// Version of the diagnostic data.
/// </summary>
public readonly VersionStamp Version;

/// <summary>
/// Number of lines in the document.
/// </summary>
public readonly int LineCount;
/// <summary>
/// Number of lines in the document.
/// </summary>
public readonly int LineCount;

/// <summary>
/// Current data that matches the version.
/// </summary>
public readonly ImmutableArray<DiagnosticData> Items;
/// <summary>
/// Current data that matches the version.
/// </summary>
public readonly ImmutableArray<DiagnosticData> Items;

/// <summary>
/// Last set of data we broadcasted to outer world, or <see langword="default"/>.
/// </summary>
public readonly ImmutableArray<DiagnosticData> OldItems;
/// <summary>
/// Last set of data we broadcasted to outer world, or <see langword="default"/>.
/// </summary>
public readonly ImmutableArray<DiagnosticData> OldItems;

public DocumentAnalysisData(VersionStamp version, int lineCount, ImmutableArray<DiagnosticData> items)
{
Debug.Assert(!items.IsDefault);
public DocumentAnalysisData(VersionStamp version, int lineCount, ImmutableArray<DiagnosticData> items)
{
Debug.Assert(!items.IsDefault);

Version = version;
LineCount = lineCount;
Items = items;
OldItems = default;
}
Version = version;
LineCount = lineCount;
Items = items;
OldItems = default;
}

public DocumentAnalysisData(VersionStamp version, int lineCount, ImmutableArray<DiagnosticData> oldItems, ImmutableArray<DiagnosticData> newItems)
: this(version, lineCount, newItems)
{
Debug.Assert(!oldItems.IsDefault);
OldItems = oldItems;
}
public DocumentAnalysisData(VersionStamp version, int lineCount, ImmutableArray<DiagnosticData> oldItems, ImmutableArray<DiagnosticData> newItems)
: this(version, lineCount, newItems)
{
Debug.Assert(!oldItems.IsDefault);
OldItems = oldItems;
}
}

/// <summary>
/// Data holder for all diagnostics for a project for an analyzer
/// </summary>
private readonly struct ProjectAnalysisData
{
/// <summary>
/// Data holder for all diagnostics for a project for an analyzer
/// ProjectId of this data
/// </summary>
private readonly struct ProjectAnalysisData
{
/// <summary>
/// ProjectId of this data
/// </summary>
public readonly ProjectId ProjectId;

/// <summary>
/// Version of the Items
/// </summary>
public readonly VersionStamp Version;

/// <summary>
/// Current data that matches the version
/// </summary>
public readonly ImmutableDictionary<DiagnosticAnalyzer, DiagnosticAnalysisResult> Result;

/// <summary>
/// When present, holds onto last data we broadcasted to outer world.
/// </summary>
public readonly ImmutableDictionary<DiagnosticAnalyzer, DiagnosticAnalysisResult>? OldResult;

public ProjectAnalysisData(ProjectId projectId, VersionStamp version, ImmutableDictionary<DiagnosticAnalyzer, DiagnosticAnalysisResult> result)
{
ProjectId = projectId;
Version = version;
Result = result;
public readonly ProjectId ProjectId;

OldResult = null;
}
/// <summary>
/// Version of the Items
/// </summary>
public readonly VersionStamp Version;

public ProjectAnalysisData(
ProjectId projectId,
VersionStamp version,
ImmutableDictionary<DiagnosticAnalyzer, DiagnosticAnalysisResult> oldResult,
ImmutableDictionary<DiagnosticAnalyzer, DiagnosticAnalysisResult> newResult)
: this(projectId, version, newResult)
{
OldResult = oldResult;
}
/// <summary>
/// Current data that matches the version
/// </summary>
public readonly ImmutableDictionary<DiagnosticAnalyzer, DiagnosticAnalysisResult> Result;

public ProjectAnalysisData(ProjectId projectId, VersionStamp version, ImmutableDictionary<DiagnosticAnalyzer, DiagnosticAnalysisResult> result)
{
ProjectId = projectId;
Version = version;
Result = result;
}

public DiagnosticAnalysisResult GetResult(DiagnosticAnalyzer analyzer)
=> GetResultOrEmpty(Result, analyzer, ProjectId, Version);

public DiagnosticAnalysisResult GetResult(DiagnosticAnalyzer analyzer)
=> GetResultOrEmpty(Result, analyzer, ProjectId, Version);
public bool TryGetResult(DiagnosticAnalyzer analyzer, out DiagnosticAnalysisResult result)
=> Result.TryGetValue(analyzer, out result);

public bool TryGetResult(DiagnosticAnalyzer analyzer, out DiagnosticAnalysisResult result)
=> Result.TryGetValue(analyzer, out result);
public static async Task<ProjectAnalysisData> CreateAsync(Project project, IEnumerable<StateSet> stateSets, bool avoidLoadingData, CancellationToken cancellationToken)
{
VersionStamp? version = null;

public static async Task<ProjectAnalysisData> CreateAsync(Project project, IEnumerable<StateSet> stateSets, bool avoidLoadingData, CancellationToken cancellationToken)
var builder = ImmutableDictionary.CreateBuilder<DiagnosticAnalyzer, DiagnosticAnalysisResult>();
foreach (var stateSet in stateSets)
{
VersionStamp? version = null;
var state = stateSet.GetOrCreateProjectState(project.Id);
var result = await state.GetAnalysisDataAsync(project, avoidLoadingData, cancellationToken).ConfigureAwait(false);
Contract.ThrowIfFalse(project.Id == result.ProjectId);

var builder = ImmutableDictionary.CreateBuilder<DiagnosticAnalyzer, DiagnosticAnalysisResult>();
foreach (var stateSet in stateSets)
if (!version.HasValue)
{
var state = stateSet.GetOrCreateProjectState(project.Id);
var result = await state.GetAnalysisDataAsync(project, avoidLoadingData, cancellationToken).ConfigureAwait(false);
Contract.ThrowIfFalse(project.Id == result.ProjectId);

if (!version.HasValue)
{
version = result.Version;
}
else if (version.Value != VersionStamp.Default && version.Value != result.Version)
{
// if not all version is same, set version as default.
// this can happen at the initial data loading or
// when document is closed and we put active file state to project state
version = VersionStamp.Default;
}

builder.Add(stateSet.Analyzer, result);
version = result.Version;
}

if (!version.HasValue)
else if (version.Value != VersionStamp.Default && version.Value != result.Version)
{
// there is no saved data to return.
return new ProjectAnalysisData(project.Id, VersionStamp.Default, ImmutableDictionary<DiagnosticAnalyzer, DiagnosticAnalysisResult>.Empty);
// if not all version is same, set version as default.
// this can happen at the initial data loading or
// when document is closed and we put active file state to project state
version = VersionStamp.Default;
}

return new ProjectAnalysisData(project.Id, version.Value, builder.ToImmutable());
builder.Add(stateSet.Analyzer, result);
}

if (!version.HasValue)
{
// there is no saved data to return.
return new ProjectAnalysisData(project.Id, VersionStamp.Default, ImmutableDictionary<DiagnosticAnalyzer, DiagnosticAnalysisResult>.Empty);
}

return new ProjectAnalysisData(project.Id, version.Value, builder.ToImmutable());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ private async Task<ProjectAnalysisData> GetProjectAnalysisDataAsync(
// Now we run analyzers but filter out some information. So on such projects, there will be some perf degradation.
result = await RemoveCompilerSemanticErrorsIfProjectNotLoadedAsync(result, project, cancellationToken).ConfigureAwait(false);

return new ProjectAnalysisData(project.Id, version, existingData.Result, result);
return new ProjectAnalysisData(project.Id, version, result);
}
catch (Exception e) when (FatalError.ReportAndPropagateUnlessCanceled(e, cancellationToken))
{
Expand Down

0 comments on commit f4c1b45

Please sign in to comment.