Skip to content

Commit

Permalink
DocumentState constructors refactoring (#74559)
Browse files Browse the repository at this point in the history
  • Loading branch information
tmat authored Jul 26, 2024
1 parent dabd071 commit 880b946
Show file tree
Hide file tree
Showing 13 changed files with 112 additions and 107 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ public bool ContainsDocument(DocumentId documentId)
filePath: document.FilePath,
isGenerated: document.State.Attributes.IsGenerated)
.WithDesignTimeOnly(document.State.Attributes.DesignTimeOnly)
.WithDocumentServiceProvider(document.State.Services));
.WithDocumentServiceProvider(document.State.DocumentServiceProvider));
}

var matchingSourceText = maybeMatchingSourceText.Value;
Expand Down
2 changes: 1 addition & 1 deletion src/VisualStudio/Core/Test/Venus/DocumentServiceTests.vb
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Venus
Dim openDocument = subjectDocument.GetOpenTextContainer()
Dim sourceGeneratedDocumentId = workspace.GetDocumentIdInCurrentContext(openDocument)
Dim document = Assert.IsType(Of SourceGeneratedDocument)(Await workspace.CurrentSolution.GetDocumentAsync(sourceGeneratedDocumentId, includeSourceGenerated:=True))
Dim documentServices = document.State.Services
Dim documentServices = document.State.DocumentServiceProvider
Dim documentOperations = documentServices.GetService(Of IDocumentOperationService)()

Assert.False(documentOperations.CanApplyChange)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,17 @@ public static bool CanApplyChange([NotNullWhen(returnValue: true)] this TextDocu
=> document?.State.CanApplyChange() ?? false;

public static bool CanApplyChange([NotNullWhen(returnValue: true)] this TextDocumentState? document)
=> document?.Services.GetService<IDocumentOperationService>()?.CanApplyChange ?? false;
=> document?.DocumentServiceProvider.GetService<IDocumentOperationService>()?.CanApplyChange ?? false;

public static bool SupportsDiagnostics([NotNullWhen(returnValue: true)] this TextDocument? document)
=> document?.State.SupportsDiagnostics() ?? false;

public static bool SupportsDiagnostics([NotNullWhen(returnValue: true)] this TextDocumentState? document)
=> document?.Services.GetService<IDocumentOperationService>()?.SupportDiagnostics ?? false;
=> document?.DocumentServiceProvider.GetService<IDocumentOperationService>()?.SupportDiagnostics ?? false;

public static bool IsRazorDocument(this TextDocument document)
=> IsRazorDocument(document.State);

public static bool IsRazorDocument(this TextDocumentState documentState)
=> documentState.Services.GetService<DocumentPropertiesService>()?.DiagnosticsLspClientName == RazorCSharpLspClientName;
=> documentState.DocumentServiceProvider.GetService<DocumentPropertiesService>()?.DiagnosticsLspClientName == RazorCSharpLspClientName;
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,29 +10,34 @@ namespace Microsoft.CodeAnalysis;

internal sealed class AdditionalDocumentState : TextDocumentState
{
private readonly AdditionalText _additionalText;
public readonly AdditionalText AdditionalText;

private AdditionalDocumentState(
SolutionServices solutionServices,
IDocumentServiceProvider documentServiceProvider,
IDocumentServiceProvider? documentServiceProvider,
DocumentInfo.DocumentAttributes attributes,
ITextAndVersionSource textAndVersionSource,
LoadTextOptions loadTextOptions)
: base(solutionServices, documentServiceProvider, attributes, textAndVersionSource, loadTextOptions)
{
_additionalText = new AdditionalTextWithState(this);
AdditionalText = new AdditionalTextWithState(this);
}

public AdditionalDocumentState(
SolutionServices solutionServices,
DocumentInfo documentInfo,
LoadTextOptions loadTextOptions)
: base(solutionServices, documentInfo, loadTextOptions)
: this(solutionServices, documentInfo.DocumentServiceProvider, documentInfo.Attributes, CreateTextAndVersionSource(solutionServices, documentInfo, loadTextOptions), loadTextOptions)
{
_additionalText = new AdditionalTextWithState(this);
}

public AdditionalText AdditionalText => _additionalText;
protected override TextDocumentState UpdateAttributes(DocumentInfo.DocumentAttributes newAttributes)
=> new AdditionalDocumentState(
SolutionServices,
DocumentServiceProvider,
newAttributes,
TextAndVersionSource,
LoadTextOptions);

public new AdditionalDocumentState UpdateText(TextLoader loader, PreservationMode mode)
=> (AdditionalDocumentState)base.UpdateText(loader, mode);
Expand All @@ -46,8 +51,8 @@ public AdditionalDocumentState(
protected override TextDocumentState UpdateText(ITextAndVersionSource newTextSource, PreservationMode mode, bool incremental)
{
return new AdditionalDocumentState(
this.solutionServices,
this.Services,
this.SolutionServices,
this.DocumentServiceProvider,
this.Attributes,
newTextSource,
this.LoadTextOptions);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

#nullable disable

using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Host;
Expand All @@ -14,38 +12,40 @@ namespace Microsoft.CodeAnalysis;

internal sealed class AnalyzerConfigDocumentState : TextDocumentState
{
private readonly AsyncLazy<AnalyzerConfig> _analyzerConfigValueSource;
private readonly AsyncLazy<AnalyzerConfig> _lazyAnalyzerConfig;

private AnalyzerConfigDocumentState(
SolutionServices solutionServices,
IDocumentServiceProvider documentServiceProvider,
IDocumentServiceProvider? documentServiceProvider,
DocumentInfo.DocumentAttributes attributes,
ITextAndVersionSource textAndVersionSource,
LoadTextOptions loadTextOptions)
LoadTextOptions loadTextOptions,
AsyncLazy<AnalyzerConfig>? lazyAnalyzerConfig = null)
: base(solutionServices, documentServiceProvider, attributes, textAndVersionSource, loadTextOptions)
{
_analyzerConfigValueSource = CreateAnalyzerConfigValueSource();
_lazyAnalyzerConfig = lazyAnalyzerConfig ?? AsyncLazy.Create(
asynchronousComputeFunction: static async (self, cancellationToken) => AnalyzerConfig.Parse(await self.GetTextAsync(cancellationToken).ConfigureAwait(false), self.FilePath),
synchronousComputeFunction: static (self, cancellationToken) => AnalyzerConfig.Parse(self.GetTextSynchronously(cancellationToken), self.FilePath),
arg: this);
}

public AnalyzerConfigDocumentState(
SolutionServices solutionServices,
DocumentInfo documentInfo,
LoadTextOptions loadTextOptions)
: base(solutionServices, documentInfo, loadTextOptions)
: this(solutionServices, documentInfo.DocumentServiceProvider, documentInfo.Attributes, CreateTextAndVersionSource(solutionServices, documentInfo, loadTextOptions), loadTextOptions)
{
_analyzerConfigValueSource = CreateAnalyzerConfigValueSource();
}

private AsyncLazy<AnalyzerConfig> CreateAnalyzerConfigValueSource()
{
return AsyncLazy.Create(
asynchronousComputeFunction: static async (self, cancellationToken) => AnalyzerConfig.Parse(await self.GetTextAsync(cancellationToken).ConfigureAwait(false), self.FilePath),
synchronousComputeFunction: static (self, cancellationToken) => AnalyzerConfig.Parse(self.GetTextSynchronously(cancellationToken), self.FilePath),
arg: this);
}

public AnalyzerConfig GetAnalyzerConfig(CancellationToken cancellationToken) => _analyzerConfigValueSource.GetValue(cancellationToken);
public Task<AnalyzerConfig> GetAnalyzerConfigAsync(CancellationToken cancellationToken) => _analyzerConfigValueSource.GetValueAsync(cancellationToken);
protected override TextDocumentState UpdateAttributes(DocumentInfo.DocumentAttributes newAttributes)
=> new AnalyzerConfigDocumentState(
SolutionServices,
DocumentServiceProvider,
newAttributes,
TextAndVersionSource,
LoadTextOptions,
// Reuse parsed config unless the path changed:
Attributes.FilePath == newAttributes.FilePath ? _lazyAnalyzerConfig : null);

public new AnalyzerConfigDocumentState UpdateText(TextLoader loader, PreservationMode mode)
=> (AnalyzerConfigDocumentState)base.UpdateText(loader, mode);
Expand All @@ -59,10 +59,16 @@ private AsyncLazy<AnalyzerConfig> CreateAnalyzerConfigValueSource()
protected override TextDocumentState UpdateText(ITextAndVersionSource newTextSource, PreservationMode mode, bool incremental)
{
return new AnalyzerConfigDocumentState(
this.solutionServices,
this.Services,
this.SolutionServices,
this.DocumentServiceProvider,
this.Attributes,
newTextSource,
this.LoadTextOptions);
}

public AnalyzerConfig GetAnalyzerConfig(CancellationToken cancellationToken)
=> _lazyAnalyzerConfig.GetValue(cancellationToken);

public Task<AnalyzerConfig> GetAnalyzerConfigAsync(CancellationToken cancellationToken)
=> _lazyAnalyzerConfig.GetValueAsync(cancellationToken);
}
57 changes: 32 additions & 25 deletions src/Workspaces/Core/Portable/Workspace/Solution/DocumentState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ protected DocumentState(
LanguageServices languageServices,
IDocumentServiceProvider? documentServiceProvider,
DocumentInfo.DocumentAttributes attributes,
ParseOptions? options,
ITextAndVersionSource textSource,
LoadTextOptions loadTextOptions,
ParseOptions? options,
ITreeAndVersionSource? treeSource)
: base(languageServices.SolutionServices, documentServiceProvider, attributes, textSource, loadTextOptions)
{
Expand All @@ -53,33 +53,41 @@ protected DocumentState(
TreeSource = treeSource;
}

public DocumentState(
public static DocumentState Create(
LanguageServices languageServices,
DocumentInfo info,
ParseOptions? options,
LoadTextOptions loadTextOptions)
: base(languageServices.SolutionServices, info, loadTextOptions)
{
LanguageServices = languageServices;
ParseOptions = options;
var textSource = CreateTextAndVersionSource(languageServices.SolutionServices, info, loadTextOptions);

// If this is document that doesn't support syntax, then don't even bother holding
// onto any tree source. It will never be used to get a tree, and can only hurt us
// by possibly holding onto data that might cause a slow memory leak.
ITreeAndVersionSource? treeSource;
if (languageServices.GetService<ISyntaxTreeFactoryService>() == null)
{
TreeSource = null;
treeSource = null;
}
else
{
Contract.ThrowIfNull(options);
TreeSource = CreateLazyFullyParsedTree(
TextAndVersionSource,
LoadTextOptions,
treeSource = CreateLazyFullyParsedTree(
textSource,
loadTextOptions,
info.Attributes.SyntaxTreeFilePath,
options,
languageServices);
}

return new DocumentState(
languageServices,
info.DocumentServiceProvider,
info.Attributes,
textSource,
loadTextOptions,
options,
treeSource);
}

[MemberNotNullWhen(true, nameof(TreeSource))]
Expand Down Expand Up @@ -320,11 +328,11 @@ public DocumentState UpdateChecksumAlgorithm(SourceHashAlgorithm checksumAlgorit

return new DocumentState(
LanguageServices,
Services,
DocumentServiceProvider,
Attributes,
ParseOptions,
TextAndVersionSource,
newLoadTextOptions,
ParseOptions,
newTreeSource);
}

Expand Down Expand Up @@ -367,11 +375,11 @@ public DocumentState UpdateParseOptionsAndSourceCodeKind(ParseOptions options, b

return new DocumentState(
LanguageServices,
Services,
DocumentServiceProvider,
Attributes.With(sourceCodeKind: options.Kind),
options,
TextAndVersionSource,
LoadTextOptions,
options,
newTreeSource);
}

Expand All @@ -390,13 +398,9 @@ public DocumentState UpdateSourceCodeKind(SourceCodeKind kind)
return WithAttributes(Attributes.With(sourceCodeKind: kind));
}

public DocumentState WithAttributes(DocumentInfo.DocumentAttributes newAttributes)
protected override TextDocumentState UpdateAttributes(DocumentInfo.DocumentAttributes newAttributes)
{
if (ReferenceEquals(newAttributes, Attributes))
{
return this;
}

Contract.ThrowIfTrue(ReferenceEquals(newAttributes, Attributes));
ITreeAndVersionSource? newTreeSource;

if (newAttributes.SyntaxTreeFilePath != Attributes.SyntaxTreeFilePath)
Expand All @@ -418,14 +422,17 @@ public DocumentState WithAttributes(DocumentInfo.DocumentAttributes newAttribute

return new DocumentState(
LanguageServices,
Services,
DocumentServiceProvider,
newAttributes,
ParseOptions,
TextAndVersionSource,
LoadTextOptions,
ParseOptions,
newTreeSource);
}

public new DocumentState WithAttributes(DocumentInfo.DocumentAttributes newAttributes)
=> (DocumentState)base.WithAttributes(newAttributes);

public new DocumentState UpdateText(SourceText newText, PreservationMode mode)
=> (DocumentState)base.UpdateText(newText, mode);

Expand Down Expand Up @@ -460,11 +467,11 @@ protected override TextDocumentState UpdateText(ITextAndVersionSource newTextSou

return new DocumentState(
LanguageServices,
Services,
DocumentServiceProvider,
Attributes,
ParseOptions,
textSource: newTextSource,
LoadTextOptions,
ParseOptions,
treeSource: newTreeSource);
}

Expand Down Expand Up @@ -503,11 +510,11 @@ internal DocumentState UpdateTree(SyntaxNode newRoot, PreservationMode mode)

return new DocumentState(
LanguageServices,
Services,
DocumentServiceProvider,
Attributes,
ParseOptions,
textSource: text,
LoadTextOptions,
ParseOptions,
treeSource: SimpleTreeAndVersionSource.Create(treeAndVersion));

// use static method so we don't capture references to this
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,11 @@ public DocumentState UpdateTextAndTreeContents(
{
return new DocumentState(
LanguageServices,
Services,
DocumentServiceProvider,
Attributes,
ParseOptions,
siblingTextSource,
LoadTextOptions,
ParseOptions,
treeSource: null);
}

Expand All @@ -77,7 +77,7 @@ public DocumentState UpdateTextAndTreeContents(
// Defer to static helper to make sure we don't accidentally capture anything else we don't want off of 'this'
// (like "this.TreeSource").
return UpdateTextAndTreeContentsWorker(
this.Attributes, this.LanguageServices, this.Services, this.LoadTextOptions, this.ParseOptions,
this.Attributes, this.LanguageServices, this.DocumentServiceProvider, this.LoadTextOptions, this.ParseOptions,
originalTreeSource, siblingTextSource, siblingTreeSource, forceEvenIfTreesWouldDiffer);
}

Expand Down Expand Up @@ -106,7 +106,7 @@ private static DocumentState UpdateTextAndTreeContentsWorker(
var newTreeSource = new LinkedFileReuseTreeAndVersionSource(originalTreeSource, lazyComputation);

return new DocumentState(
languageServices, services, attributes, parseOptions, siblingTextSource, loadTextOptions, newTreeSource);
languageServices, services, attributes, siblingTextSource, loadTextOptions, parseOptions, newTreeSource);

static bool TryReuseSiblingRoot(
string filePath,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ private static async Task<VersionStamp> ComputeLatestDocumentTopLevelChangeVersi

internal DocumentState CreateDocument(DocumentInfo documentInfo, ParseOptions? parseOptions, LoadTextOptions loadTextOptions)
{
var doc = new DocumentState(LanguageServices, documentInfo, parseOptions, loadTextOptions);
var doc = DocumentState.Create(LanguageServices, documentInfo, parseOptions, loadTextOptions);

if (doc.SourceCodeKind != documentInfo.SourceCodeKind)
{
Expand Down
Loading

0 comments on commit 880b946

Please sign in to comment.