diff --git a/eng/targets/GenerateServiceHubConfigurationFiles.targets b/eng/targets/GenerateServiceHubConfigurationFiles.targets index 3b1b5a73485a548de49813163bbf2243d61b6bdc..76d1a8b4846662b01f2ed6df50b7b1f82a5b7c03 100644 --- a/eng/targets/GenerateServiceHubConfigurationFiles.targets +++ b/eng/targets/GenerateServiceHubConfigurationFiles.targets @@ -12,7 +12,7 @@ - + diff --git a/src/EditorFeatures/Core/Implementation/TodoComment/ITodoListProvider.cs b/src/EditorFeatures/Core/Implementation/TodoComment/ITodoListProvider.cs index d43efda7b16de7c369560f7dddc473ab7157d97b..41b1918f32a0edd93be68405b506182713c0b8eb 100644 --- a/src/EditorFeatures/Core/Implementation/TodoComment/ITodoListProvider.cs +++ b/src/EditorFeatures/Core/Implementation/TodoComment/ITodoListProvider.cs @@ -7,6 +7,7 @@ using System.Collections.Immutable; using System.Threading; using Microsoft.CodeAnalysis.Common; +using Microsoft.CodeAnalysis.TodoComments; namespace Microsoft.CodeAnalysis.Editor { @@ -23,7 +24,7 @@ internal interface ITodoListProvider /// event EventHandler TodoListUpdated; - ImmutableArray GetTodoItems(Workspace workspace, DocumentId documentId, CancellationToken cancellationToken); + ImmutableArray GetTodoItems(Workspace workspace, DocumentId documentId, CancellationToken cancellationToken); /// /// Get current UpdatedEventArgs stored in ITodoListProvider diff --git a/src/EditorFeatures/Core/Implementation/TodoComment/TodoCommentIncrementalAnalyzer.cs b/src/EditorFeatures/Core/Implementation/TodoComment/TodoCommentIncrementalAnalyzer.cs index f930ee5c6d4b57b891e978e31280dd3fdca3bde1..ef5cd51cf738c8ec218993f843ae157d1c97182f 100644 --- a/src/EditorFeatures/Core/Implementation/TodoComment/TodoCommentIncrementalAnalyzer.cs +++ b/src/EditorFeatures/Core/Implementation/TodoComment/TodoCommentIncrementalAnalyzer.cs @@ -1,255 +1,255 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Diagnostics; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Common; -using Microsoft.CodeAnalysis.Editor.Shared.Options; -using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Shared.Extensions; -using Microsoft.CodeAnalysis.Shared.Options; -using Microsoft.CodeAnalysis.SolutionCrawler; -using Microsoft.CodeAnalysis.Text; -using Microsoft.CodeAnalysis.TodoComments; -using Microsoft.CodeAnalysis.Versions; -using Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis.Editor.Implementation.TodoComments -{ - internal partial class TodoCommentIncrementalAnalyzer : IIncrementalAnalyzer - { - public const string Name = "Todo Comment Document Worker"; - - private readonly TodoCommentIncrementalAnalyzerProvider _owner; - private readonly Workspace _workspace; - private readonly TodoCommentTokens _todoCommentTokens; - private readonly TodoCommentState _state; - - public TodoCommentIncrementalAnalyzer(Workspace workspace, TodoCommentIncrementalAnalyzerProvider owner, TodoCommentTokens todoCommentTokens) - { - _workspace = workspace; - - _owner = owner; - _todoCommentTokens = todoCommentTokens; - - _state = new TodoCommentState(); - } - - public Task DocumentResetAsync(Document document, CancellationToken cancellationToken) - { - // remove cache - _state.Remove(document.Id); - return _state.PersistAsync(document, new Data(VersionStamp.Default, VersionStamp.Default, ImmutableArray.Empty), cancellationToken); - } - - public async Task AnalyzeSyntaxAsync(Document document, InvocationReasons reasons, CancellationToken cancellationToken) - { - // it has an assumption that this will not be called concurrently for same document. - // in fact, in current design, it won't be even called concurrently for different documents. - // but, can be called concurrently for different documents in future if we choose to. - Contract.ThrowIfFalse(document.IsFromPrimaryBranch()); - - if (!document.Project.Solution.Options.GetOption(InternalFeatureOnOffOptions.TodoComments)) - { - return; - } - - // Compute and persist the TODO comments for this document. - var (existingData, newData) = await ComputeAndPersistTodoCommentsAsync(document, _state, _todoCommentTokens, cancellationToken).ConfigureAwait(false); - - // Now update the task list if there are any changes from the previously computed TODO comments, if any. - // NOTE: We don't check for cancellation here to ensure the task list view and our latest - // computed state are identical. - if (existingData == null || existingData.Items.Length != newData.Items.Length) - { - Debug.Assert(_workspace == document.Project.Solution.Workspace); - RaiseTaskListUpdated(_workspace, document.Project.Solution, document.Id, newData.Items); - } - } - - private static async Task<(Data existingData, Data newData)> ComputeAndPersistTodoCommentsAsync( - Document document, - TodoCommentState state, - TodoCommentTokens todoCommentTokens, - CancellationToken cancellationToken) - { - // use tree version so that things like compiler option changes are considered - var textVersion = await document.GetTextVersionAsync(cancellationToken).ConfigureAwait(false); - var syntaxVersion = await document.GetSyntaxVersionAsync(cancellationToken).ConfigureAwait(false); - - var existingData = await state.TryGetExistingDataAsync(document, cancellationToken).ConfigureAwait(false); - if (existingData != null) - { - // check whether we can use the data as it is (can happen when re-using persisted data from previous VS session) - if (CheckVersions(document, textVersion, syntaxVersion, existingData)) - { - return (existingData, existingData); - } - } - - var tokens = todoCommentTokens.GetTokens(document); - var comments = await GetTodoCommentsAsync(document, tokens, cancellationToken).ConfigureAwait(false); - var items = await CreateItemsAsync(document, comments, cancellationToken).ConfigureAwait(false); - - var data = new Data(textVersion, syntaxVersion, items); - await state.PersistAsync(document, data, cancellationToken).ConfigureAwait(false); - return (existingData, data); - } - - private static async Task> GetTodoCommentsAsync(Document document, IList tokens, CancellationToken cancellationToken) - { - var service = document.GetLanguageService(); - if (service == null) - { - // no inproc support - return SpecializedCollections.EmptyList(); - } - - return await service.GetTodoCommentsAsync(document, tokens, cancellationToken).ConfigureAwait(false); - } - - private static async Task> CreateItemsAsync(Document document, IList comments, CancellationToken cancellationToken) - { - var items = ImmutableArray.CreateBuilder(); - if (comments != null) - { - var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); - var syntaxTree = document.SupportsSyntaxTree ? await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false) : null; - - foreach (var comment in comments) - { - items.Add(CreateItem(document, text, syntaxTree, comment)); - } - } - - return items.ToImmutable(); - } - - private static TodoItem CreateItem(Document document, SourceText text, SyntaxTree tree, TodoComment comment) - { - // make sure given position is within valid text range. - var textSpan = new TextSpan(Math.Min(text.Length, Math.Max(0, comment.Position)), 0); - - var location = tree == null ? Location.Create(document.FilePath, textSpan, text.Lines.GetLinePositionSpan(textSpan)) : tree.GetLocation(textSpan); - var originalLineInfo = location.GetLineSpan(); - var mappedLineInfo = location.GetMappedLineSpan(); - - return new TodoItem( - comment.Descriptor.Priority, - comment.Message, - document.Id, - mappedLine: mappedLineInfo.StartLinePosition.Line, - originalLine: originalLineInfo.StartLinePosition.Line, - mappedColumn: mappedLineInfo.StartLinePosition.Character, - originalColumn: originalLineInfo.StartLinePosition.Character, - mappedFilePath: mappedLineInfo.GetMappedFilePathIfExist(), - originalFilePath: document.FilePath); - } - - public ImmutableArray GetTodoItems(Workspace workspace, DocumentId id, CancellationToken cancellationToken) - { - var document = workspace.CurrentSolution.GetDocument(id); - if (document == null) - { - return ImmutableArray.Empty; - } - - // TODO let's think about what to do here. for now, let call it synchronously. also, there is no actual async-ness for the - // TryGetExistingDataAsync, API just happen to be async since our persistent API is async API. but both caller and implementor are - // actually not async. - var (_, newData) = ComputeAndPersistTodoCommentsAsync(document, _state, _todoCommentTokens, cancellationToken).WaitAndGetResult_CanCallOnBackground(cancellationToken); - return newData.Items; - } - - public IEnumerable GetTodoItemsUpdatedEventArgs(Workspace workspace) - { - foreach (var documentId in _state.GetDocumentIds()) - { - yield return new UpdatedEventArgs(Tuple.Create(this, documentId), workspace, documentId.ProjectId, documentId); - } - } - - private static bool CheckVersions(Document document, VersionStamp textVersion, VersionStamp syntaxVersion, Data existingData) - { - // first check full version to see whether we can reuse data in same session, if we can't, check timestamp only version to see whether - // we can use it cross-session. - return document.CanReusePersistedTextVersion(textVersion, existingData.TextVersion) && - document.CanReusePersistedSyntaxTreeVersion(syntaxVersion, existingData.SyntaxVersion); - } - - internal ImmutableArray GetItems_TestingOnly(DocumentId documentId) - { - return _state.GetItems_TestingOnly(documentId); - } - - private void RaiseTaskListUpdated(Workspace workspace, Solution solution, DocumentId documentId, ImmutableArray items) - { - if (_owner != null) - { - _owner.RaiseTaskListUpdated(documentId, workspace, solution, documentId.ProjectId, documentId, items); - } - } - - public void RemoveDocument(DocumentId documentId) - { - _state.Remove(documentId); - - RaiseTaskListUpdated(_workspace, null, documentId, ImmutableArray.Empty); - } - - public bool NeedsReanalysisOnOptionChanged(object sender, OptionChangedEventArgs e) - { - return e.Option == TodoCommentOptions.TokenList; - } - - private class Data - { - public readonly VersionStamp TextVersion; - public readonly VersionStamp SyntaxVersion; - public readonly ImmutableArray Items; - - public Data(VersionStamp textVersion, VersionStamp syntaxVersion, ImmutableArray items) - { - this.TextVersion = textVersion; - this.SyntaxVersion = syntaxVersion; - this.Items = items; - } - } - - #region not used - public Task NewSolutionSnapshotAsync(Solution solution, CancellationToken cancellationToken) - { - return Task.CompletedTask; - } - - public Task DocumentOpenAsync(Document document, CancellationToken cancellationToken) - { - return Task.CompletedTask; - } - - public Task DocumentCloseAsync(Document document, CancellationToken cancellationToken) - { - return Task.CompletedTask; - } - - public Task AnalyzeDocumentAsync(Document document, SyntaxNode bodyOpt, InvocationReasons reasons, CancellationToken cancellationToken) - { - return Task.CompletedTask; - } - - public Task AnalyzeProjectAsync(Project project, bool semanticsChanged, InvocationReasons reasons, CancellationToken cancellationToken) - { - return Task.CompletedTask; - } - - public void RemoveProject(ProjectId projectId) - { - } - #endregion - } -} +//// Licensed to the .NET Foundation under one or more agreements. +//// The .NET Foundation licenses this file to you under the MIT license. +//// See the LICENSE file in the project root for more information. + +//using System; +//using System.Collections.Generic; +//using System.Collections.Immutable; +//using System.Diagnostics; +//using System.Threading; +//using System.Threading.Tasks; +//using Microsoft.CodeAnalysis.Common; +//using Microsoft.CodeAnalysis.Editor.Shared.Options; +//using Microsoft.CodeAnalysis.Options; +//using Microsoft.CodeAnalysis.Shared.Extensions; +//using Microsoft.CodeAnalysis.Shared.Options; +//using Microsoft.CodeAnalysis.SolutionCrawler; +//using Microsoft.CodeAnalysis.Text; +//using Microsoft.CodeAnalysis.TodoComments; +//using Microsoft.CodeAnalysis.Versions; +//using Roslyn.Utilities; + +//namespace Microsoft.CodeAnalysis.Editor.Implementation.TodoComments +//{ +// internal partial class TodoCommentIncrementalAnalyzer : IIncrementalAnalyzer +// { +// public const string Name = "Todo Comment Document Worker"; + +// private readonly TodoCommentIncrementalAnalyzerProvider _owner; +// private readonly Workspace _workspace; +// private readonly TodoCommentTokens _todoCommentTokens; +// private readonly TodoCommentState _state; + +// public TodoCommentIncrementalAnalyzer(Workspace workspace, TodoCommentIncrementalAnalyzerProvider owner, TodoCommentTokens todoCommentTokens) +// { +// _workspace = workspace; + +// _owner = owner; +// _todoCommentTokens = todoCommentTokens; + +// _state = new TodoCommentState(); +// } + +// public Task DocumentResetAsync(Document document, CancellationToken cancellationToken) +// { +// // remove cache +// _state.Remove(document.Id); +// return _state.PersistAsync(document, new Data(VersionStamp.Default, VersionStamp.Default, ImmutableArray.Empty), cancellationToken); +// } + +// public async Task AnalyzeSyntaxAsync(Document document, InvocationReasons reasons, CancellationToken cancellationToken) +// { +// // it has an assumption that this will not be called concurrently for same document. +// // in fact, in current design, it won't be even called concurrently for different documents. +// // but, can be called concurrently for different documents in future if we choose to. +// Contract.ThrowIfFalse(document.IsFromPrimaryBranch()); + +// if (!document.Project.Solution.Options.GetOption(InternalFeatureOnOffOptions.TodoComments)) +// { +// return; +// } + +// // Compute and persist the TODO comments for this document. +// var (existingData, newData) = await ComputeAndPersistTodoCommentsAsync(document, _state, _todoCommentTokens, cancellationToken).ConfigureAwait(false); + +// // Now update the task list if there are any changes from the previously computed TODO comments, if any. +// // NOTE: We don't check for cancellation here to ensure the task list view and our latest +// // computed state are identical. +// if (existingData == null || existingData.Items.Length != newData.Items.Length) +// { +// Debug.Assert(_workspace == document.Project.Solution.Workspace); +// RaiseTaskListUpdated(_workspace, document.Project.Solution, document.Id, newData.Items); +// } +// } + +// private static async Task<(Data existingData, Data newData)> ComputeAndPersistTodoCommentsAsync( +// Document document, +// TodoCommentState state, +// TodoCommentTokens todoCommentTokens, +// CancellationToken cancellationToken) +// { +// // use tree version so that things like compiler option changes are considered +// var textVersion = await document.GetTextVersionAsync(cancellationToken).ConfigureAwait(false); +// var syntaxVersion = await document.GetSyntaxVersionAsync(cancellationToken).ConfigureAwait(false); + +// var existingData = await state.TryGetExistingDataAsync(document, cancellationToken).ConfigureAwait(false); +// if (existingData != null) +// { +// // check whether we can use the data as it is (can happen when re-using persisted data from previous VS session) +// if (CheckVersions(document, textVersion, syntaxVersion, existingData)) +// { +// return (existingData, existingData); +// } +// } + +// var tokens = todoCommentTokens.GetTokens(document); +// var comments = await GetTodoCommentsAsync(document, tokens, cancellationToken).ConfigureAwait(false); +// var items = await CreateItemsAsync(document, comments, cancellationToken).ConfigureAwait(false); + +// var data = new Data(textVersion, syntaxVersion, items); +// await state.PersistAsync(document, data, cancellationToken).ConfigureAwait(false); +// return (existingData, data); +// } + +// private static async Task> GetTodoCommentsAsync(Document document, IList tokens, CancellationToken cancellationToken) +// { +// var service = document.GetLanguageService(); +// if (service == null) +// { +// // no inproc support +// return SpecializedCollections.EmptyList(); +// } + +// return await service.GetTodoCommentsAsync(document, tokens, cancellationToken).ConfigureAwait(false); +// } + +// private static async Task> CreateItemsAsync(Document document, IList comments, CancellationToken cancellationToken) +// { +// var items = ImmutableArray.CreateBuilder(); +// if (comments != null) +// { +// var text = await document.GetTextAsync(cancellationToken).ConfigureAwait(false); +// var syntaxTree = document.SupportsSyntaxTree ? await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false) : null; + +// foreach (var comment in comments) +// { +// items.Add(CreateItem(document, text, syntaxTree, comment)); +// } +// } + +// return items.ToImmutable(); +// } + +// private static TodoItem CreateItem(Document document, SourceText text, SyntaxTree tree, TodoComment comment) +// { +// // make sure given position is within valid text range. +// var textSpan = new TextSpan(Math.Min(text.Length, Math.Max(0, comment.Position)), 0); + +// var location = tree == null ? Location.Create(document.FilePath, textSpan, text.Lines.GetLinePositionSpan(textSpan)) : tree.GetLocation(textSpan); +// var originalLineInfo = location.GetLineSpan(); +// var mappedLineInfo = location.GetMappedLineSpan(); + +// return new TodoItem( +// comment.Descriptor.Priority, +// comment.Message, +// document.Id, +// mappedLine: mappedLineInfo.StartLinePosition.Line, +// originalLine: originalLineInfo.StartLinePosition.Line, +// mappedColumn: mappedLineInfo.StartLinePosition.Character, +// originalColumn: originalLineInfo.StartLinePosition.Character, +// mappedFilePath: mappedLineInfo.GetMappedFilePathIfExist(), +// originalFilePath: document.FilePath); +// } + +// public ImmutableArray GetTodoItems(Workspace workspace, DocumentId id, CancellationToken cancellationToken) +// { +// var document = workspace.CurrentSolution.GetDocument(id); +// if (document == null) +// { +// return ImmutableArray.Empty; +// } + +// // TODO let's think about what to do here. for now, let call it synchronously. also, there is no actual async-ness for the +// // TryGetExistingDataAsync, API just happen to be async since our persistent API is async API. but both caller and implementor are +// // actually not async. +// var (_, newData) = ComputeAndPersistTodoCommentsAsync(document, _state, _todoCommentTokens, cancellationToken).WaitAndGetResult_CanCallOnBackground(cancellationToken); +// return newData.Items; +// } + +// public IEnumerable GetTodoItemsUpdatedEventArgs(Workspace workspace) +// { +// foreach (var documentId in _state.GetDocumentIds()) +// { +// yield return new UpdatedEventArgs(Tuple.Create(this, documentId), workspace, documentId.ProjectId, documentId); +// } +// } + +// private static bool CheckVersions(Document document, VersionStamp textVersion, VersionStamp syntaxVersion, Data existingData) +// { +// // first check full version to see whether we can reuse data in same session, if we can't, check timestamp only version to see whether +// // we can use it cross-session. +// return document.CanReusePersistedTextVersion(textVersion, existingData.TextVersion) && +// document.CanReusePersistedSyntaxTreeVersion(syntaxVersion, existingData.SyntaxVersion); +// } + +// internal ImmutableArray GetItems_TestingOnly(DocumentId documentId) +// { +// return _state.GetItems_TestingOnly(documentId); +// } + +// private void RaiseTaskListUpdated(Workspace workspace, Solution solution, DocumentId documentId, ImmutableArray items) +// { +// if (_owner != null) +// { +// _owner.RaiseTaskListUpdated(documentId, workspace, solution, documentId.ProjectId, documentId, items); +// } +// } + +// public void RemoveDocument(DocumentId documentId) +// { +// _state.Remove(documentId); + +// RaiseTaskListUpdated(_workspace, null, documentId, ImmutableArray.Empty); +// } + +// public bool NeedsReanalysisOnOptionChanged(object sender, OptionChangedEventArgs e) +// { +// return e.Option == TodoCommentOptions.TokenList; +// } + +// private class Data +// { +// public readonly VersionStamp TextVersion; +// public readonly VersionStamp SyntaxVersion; +// public readonly ImmutableArray Items; + +// public Data(VersionStamp textVersion, VersionStamp syntaxVersion, ImmutableArray items) +// { +// this.TextVersion = textVersion; +// this.SyntaxVersion = syntaxVersion; +// this.Items = items; +// } +// } + +// #region not used +// public Task NewSolutionSnapshotAsync(Solution solution, CancellationToken cancellationToken) +// { +// return Task.CompletedTask; +// } + +// public Task DocumentOpenAsync(Document document, CancellationToken cancellationToken) +// { +// return Task.CompletedTask; +// } + +// public Task DocumentCloseAsync(Document document, CancellationToken cancellationToken) +// { +// return Task.CompletedTask; +// } + +// public Task AnalyzeDocumentAsync(Document document, SyntaxNode bodyOpt, InvocationReasons reasons, CancellationToken cancellationToken) +// { +// return Task.CompletedTask; +// } + +// public Task AnalyzeProjectAsync(Project project, bool semanticsChanged, InvocationReasons reasons, CancellationToken cancellationToken) +// { +// return Task.CompletedTask; +// } + +// public void RemoveProject(ProjectId projectId) +// { +// } +// #endregion +// } +//} diff --git a/src/EditorFeatures/Core/Implementation/TodoComment/TodoCommentIncrementalAnalyzerProvider.cs b/src/EditorFeatures/Core/Implementation/TodoComment/TodoCommentIncrementalAnalyzerProvider.cs index 787f811af0277fc330c6e25d3fbb10f775462a8d..8679dfbbdd45163213f482eb7b90aa5cf805f74d 100644 --- a/src/EditorFeatures/Core/Implementation/TodoComment/TodoCommentIncrementalAnalyzerProvider.cs +++ b/src/EditorFeatures/Core/Implementation/TodoComment/TodoCommentIncrementalAnalyzerProvider.cs @@ -1,92 +1,92 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. +//// Licensed to the .NET Foundation under one or more agreements. +//// The .NET Foundation licenses this file to you under the MIT license. +//// See the LICENSE file in the project root for more information. -using System; -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Composition; -using System.Linq; -using System.Runtime.CompilerServices; -using System.Threading; -using Microsoft.CodeAnalysis.Common; -using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.SolutionCrawler; +//using System; +//using System.Collections.Generic; +//using System.Collections.Immutable; +//using System.Composition; +//using System.Linq; +//using System.Runtime.CompilerServices; +//using System.Threading; +//using Microsoft.CodeAnalysis.Common; +//using Microsoft.CodeAnalysis.Host; +//using Microsoft.CodeAnalysis.SolutionCrawler; -namespace Microsoft.CodeAnalysis.Editor.Implementation.TodoComments -{ - [Shared] - [Export(typeof(ITodoListProvider))] - [ExportIncrementalAnalyzerProvider( - name: nameof(TodoCommentIncrementalAnalyzerProvider), - workspaceKinds: new[] { WorkspaceKind.Host, WorkspaceKind.Interactive, WorkspaceKind.MiscellaneousFiles })] - internal class TodoCommentIncrementalAnalyzerProvider : IIncrementalAnalyzerProvider, ITodoListProvider - { - private static readonly ConditionalWeakTable s_analyzers = new ConditionalWeakTable(); +//namespace Microsoft.CodeAnalysis.Editor.Implementation.TodoComments +//{ +// [Shared] +// [Export(typeof(ITodoListProvider))] +// [ExportIncrementalAnalyzerProvider( +// name: nameof(TodoCommentIncrementalAnalyzerProvider), +// workspaceKinds: new[] { WorkspaceKind.Host, WorkspaceKind.Interactive, WorkspaceKind.MiscellaneousFiles })] +// internal class TodoCommentIncrementalAnalyzerProvider : IIncrementalAnalyzerProvider, ITodoListProvider +// { +// private static readonly ConditionalWeakTable s_analyzers = new ConditionalWeakTable(); - private readonly TodoCommentTokens _todoCommentTokens; - private readonly EventListenerTracker _eventListenerTracker; +// private readonly TodoCommentTokens _todoCommentTokens; +// private readonly EventListenerTracker _eventListenerTracker; - [ImportingConstructor] - public TodoCommentIncrementalAnalyzerProvider( - TodoCommentTokens todoCommentTokens, - [ImportMany]IEnumerable> eventListeners) - { - _todoCommentTokens = todoCommentTokens; - _eventListenerTracker = new EventListenerTracker(eventListeners, WellKnownEventListeners.TodoListProvider); - } +// [ImportingConstructor] +// public TodoCommentIncrementalAnalyzerProvider( +// TodoCommentTokens todoCommentTokens, +// [ImportMany]IEnumerable> eventListeners) +// { +// _todoCommentTokens = todoCommentTokens; +// _eventListenerTracker = new EventListenerTracker(eventListeners, WellKnownEventListeners.TodoListProvider); +// } - public IIncrementalAnalyzer CreateIncrementalAnalyzer(Workspace workspace) - { - return s_analyzers.GetValue(workspace, w => - new TodoCommentIncrementalAnalyzer(w, this, _todoCommentTokens)); - } +// public IIncrementalAnalyzer CreateIncrementalAnalyzer(Workspace workspace) +// { +// return s_analyzers.GetValue(workspace, w => +// new TodoCommentIncrementalAnalyzer(w, this, _todoCommentTokens)); +// } - internal void RaiseTaskListUpdated(object id, Workspace workspace, Solution solution, ProjectId projectId, DocumentId documentId, ImmutableArray items) - { - _eventListenerTracker.EnsureEventListener(workspace, this); +// internal void RaiseTaskListUpdated(object id, Workspace workspace, Solution solution, ProjectId projectId, DocumentId documentId, ImmutableArray items) +// { +// _eventListenerTracker.EnsureEventListener(workspace, this); - this.TodoListUpdated?.Invoke(this, new TodoItemsUpdatedArgs(Tuple.Create(this, id), workspace, solution, projectId, documentId, items)); - } +// this.TodoListUpdated?.Invoke(this, new TodoItemsUpdatedArgs(Tuple.Create(this, id), workspace, solution, projectId, documentId, items)); +// } - public event EventHandler TodoListUpdated; +// public event EventHandler TodoListUpdated; - public ImmutableArray GetTodoItems(Workspace workspace, DocumentId documentId, CancellationToken cancellationToken) - { - var analyzer = TryGetAnalyzer(workspace); - if (analyzer == null) - { - return ImmutableArray.Empty; - } +// public ImmutableArray GetTodoItems(Workspace workspace, DocumentId documentId, CancellationToken cancellationToken) +// { +// var analyzer = TryGetAnalyzer(workspace); +// if (analyzer == null) +// { +// return ImmutableArray.Empty; +// } - var document = workspace.CurrentSolution.GetDocument(documentId); - if (document == null) - { - return ImmutableArray.Empty; - } +// var document = workspace.CurrentSolution.GetDocument(documentId); +// if (document == null) +// { +// return ImmutableArray.Empty; +// } - return analyzer.GetTodoItems(workspace, document.Id, cancellationToken); - } +// return analyzer.GetTodoItems(workspace, document.Id, cancellationToken); +// } - public IEnumerable GetTodoItemsUpdatedEventArgs(Workspace workspace, CancellationToken cancellationToken) - { - var analyzer = TryGetAnalyzer(workspace); - if (analyzer == null) - { - return ImmutableArray.Empty; - } +// public IEnumerable GetTodoItemsUpdatedEventArgs(Workspace workspace, CancellationToken cancellationToken) +// { +// var analyzer = TryGetAnalyzer(workspace); +// if (analyzer == null) +// { +// return ImmutableArray.Empty; +// } - return analyzer.GetTodoItemsUpdatedEventArgs(workspace); - } +// return analyzer.GetTodoItemsUpdatedEventArgs(workspace); +// } - private TodoCommentIncrementalAnalyzer TryGetAnalyzer(Workspace workspace) - { - if (s_analyzers.TryGetValue(workspace, out var analyzer)) - { - return analyzer; - } +// private TodoCommentIncrementalAnalyzer TryGetAnalyzer(Workspace workspace) +// { +// if (s_analyzers.TryGetValue(workspace, out var analyzer)) +// { +// return analyzer; +// } - return null; - } - } -} +// return null; +// } +// } +//} diff --git a/src/EditorFeatures/Core/Implementation/TodoComment/TodoCommentState.cs b/src/EditorFeatures/Core/Implementation/TodoComment/TodoCommentState.cs index dd429efc15286d3a605e4b08ccbe5b6cbec4a339..274ed2a201e2bf30c260b4147d15071ab2caeaf3 100644 --- a/src/EditorFeatures/Core/Implementation/TodoComment/TodoCommentState.cs +++ b/src/EditorFeatures/Core/Implementation/TodoComment/TodoCommentState.cs @@ -1,118 +1,118 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Collections.Immutable; -using System.IO; -using System.Threading; -using Microsoft.CodeAnalysis.PooledObjects; -using Microsoft.CodeAnalysis.SolutionCrawler; -using Microsoft.CodeAnalysis.SolutionCrawler.State; -using Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis.Editor.Implementation.TodoComments -{ - internal partial class TodoCommentIncrementalAnalyzer : IIncrementalAnalyzer - { - private class TodoCommentState : AbstractDocumentAnalyzerState - { - private const string FormatVersion = "1"; - - protected override string StateName => ""; - - protected override int GetCount(Data data) - { - return data.Items.Length; - } - - protected override Data TryGetExistingData(Stream stream, Document value, CancellationToken cancellationToken) - { - using var reader = ObjectReader.TryGetReader(stream, leaveOpen: true, cancellationToken); - - if (reader != null) - { - var format = reader.ReadString(); - if (string.Equals(format, FormatVersion)) - { - var textVersion = VersionStamp.ReadFrom(reader); - var dataVersion = VersionStamp.ReadFrom(reader); - - using var listDisposer = ArrayBuilder.GetInstance(out var list); - AppendItems(reader, value, list, cancellationToken); - - return new Data(textVersion, dataVersion, list.ToImmutable()); - } - } - - return null; - } - - protected override void WriteTo(Stream stream, Data data, CancellationToken cancellationToken) - { - using var writer = new ObjectWriter(stream, leaveOpen: true, cancellationToken: cancellationToken); - - writer.WriteString(FormatVersion); - data.TextVersion.WriteTo(writer); - data.SyntaxVersion.WriteTo(writer); - - writer.WriteInt32(data.Items.Length); - - foreach (var item in data.Items.OfType()) - { - cancellationToken.ThrowIfCancellationRequested(); - - writer.WriteInt32(item.Priority); - writer.WriteString(item.Message); - - writer.WriteString(item.OriginalFilePath); - writer.WriteInt32(item.OriginalLine); - writer.WriteInt32(item.OriginalColumn); - - writer.WriteString(item.MappedFilePath); - writer.WriteInt32(item.MappedLine); - writer.WriteInt32(item.MappedColumn); - } - } - - public ImmutableArray GetDocumentIds() - { - return DataCache.Keys.ToImmutableArrayOrEmpty(); - } - - public ImmutableArray GetItems_TestingOnly(DocumentId documentId) - { - if (this.DataCache.TryGetValue(documentId, out var entry) && entry.HasCachedData) - { - return entry.Data.Items; - } - - return ImmutableArray.Empty; - } - - private void AppendItems(ObjectReader reader, Document document, ArrayBuilder list, CancellationToken cancellationToken) - { - var count = reader.ReadInt32(); - for (var i = 0; i < count; i++) - { - cancellationToken.ThrowIfCancellationRequested(); - - var priority = reader.ReadInt32(); - var message = reader.ReadString(); - - var originalFile = reader.ReadString(); - var originalLine = reader.ReadInt32(); - var originalColumn = reader.ReadInt32(); - - var mappedFile = reader.ReadString(); - var mappedLine = reader.ReadInt32(); - var mappedColumn = reader.ReadInt32(); - - list.Add(new TodoItem( - priority, message, - document.Id, - mappedLine, originalLine, mappedColumn, originalColumn, mappedFile, originalFile)); - } - } - } - } -} +//// Licensed to the .NET Foundation under one or more agreements. +//// The .NET Foundation licenses this file to you under the MIT license. +//// See the LICENSE file in the project root for more information. + +//using System.Collections.Immutable; +//using System.IO; +//using System.Threading; +//using Microsoft.CodeAnalysis.PooledObjects; +//using Microsoft.CodeAnalysis.SolutionCrawler; +//using Microsoft.CodeAnalysis.SolutionCrawler.State; +//using Roslyn.Utilities; + +//namespace Microsoft.CodeAnalysis.Editor.Implementation.TodoComments +//{ +// internal partial class TodoCommentIncrementalAnalyzer : IIncrementalAnalyzer +// { +// private class TodoCommentState : AbstractDocumentAnalyzerState +// { +// private const string FormatVersion = "1"; + +// protected override string StateName => ""; + +// protected override int GetCount(Data data) +// { +// return data.Items.Length; +// } + +// protected override Data TryGetExistingData(Stream stream, Document value, CancellationToken cancellationToken) +// { +// using var reader = ObjectReader.TryGetReader(stream, leaveOpen: true, cancellationToken); + +// if (reader != null) +// { +// var format = reader.ReadString(); +// if (string.Equals(format, FormatVersion)) +// { +// var textVersion = VersionStamp.ReadFrom(reader); +// var dataVersion = VersionStamp.ReadFrom(reader); + +// using var listDisposer = ArrayBuilder.GetInstance(out var list); +// AppendItems(reader, value, list, cancellationToken); + +// return new Data(textVersion, dataVersion, list.ToImmutable()); +// } +// } + +// return null; +// } + +// protected override void WriteTo(Stream stream, Data data, CancellationToken cancellationToken) +// { +// using var writer = new ObjectWriter(stream, leaveOpen: true, cancellationToken: cancellationToken); + +// writer.WriteString(FormatVersion); +// data.TextVersion.WriteTo(writer); +// data.SyntaxVersion.WriteTo(writer); + +// writer.WriteInt32(data.Items.Length); + +// foreach (var item in data.Items.OfType()) +// { +// cancellationToken.ThrowIfCancellationRequested(); + +// writer.WriteInt32(item.Priority); +// writer.WriteString(item.Message); + +// writer.WriteString(item.OriginalFilePath); +// writer.WriteInt32(item.OriginalLine); +// writer.WriteInt32(item.OriginalColumn); + +// writer.WriteString(item.MappedFilePath); +// writer.WriteInt32(item.MappedLine); +// writer.WriteInt32(item.MappedColumn); +// } +// } + +// public ImmutableArray GetDocumentIds() +// { +// return DataCache.Keys.ToImmutableArrayOrEmpty(); +// } + +// public ImmutableArray GetItems_TestingOnly(DocumentId documentId) +// { +// if (this.DataCache.TryGetValue(documentId, out var entry) && entry.HasCachedData) +// { +// return entry.Data.Items; +// } + +// return ImmutableArray.Empty; +// } + +// private void AppendItems(ObjectReader reader, Document document, ArrayBuilder list, CancellationToken cancellationToken) +// { +// var count = reader.ReadInt32(); +// for (var i = 0; i < count; i++) +// { +// cancellationToken.ThrowIfCancellationRequested(); + +// var priority = reader.ReadInt32(); +// var message = reader.ReadString(); + +// var originalFile = reader.ReadString(); +// var originalLine = reader.ReadInt32(); +// var originalColumn = reader.ReadInt32(); + +// var mappedFile = reader.ReadString(); +// var mappedLine = reader.ReadInt32(); +// var mappedColumn = reader.ReadInt32(); + +// list.Add(new TodoItem( +// priority, message, +// document.Id, +// mappedLine, originalLine, mappedColumn, originalColumn, mappedFile, originalFile)); +// } +// } +// } +// } +//} diff --git a/src/EditorFeatures/Core/Implementation/TodoComment/TodoCommentTokens.cs b/src/EditorFeatures/Core/Implementation/TodoComment/TodoCommentTokens.cs index 3f654571dc9f5365be28c03c9073b27cb1f20fe2..c23911c7c2a37e2c1094fc09c5cda1564a78d5e1 100644 --- a/src/EditorFeatures/Core/Implementation/TodoComment/TodoCommentTokens.cs +++ b/src/EditorFeatures/Core/Implementation/TodoComment/TodoCommentTokens.cs @@ -1,58 +1,58 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Collections.Generic; -using System.Collections.Immutable; -using System.ComponentModel.Composition; -using System.Globalization; -using System.Threading; -using Microsoft.CodeAnalysis.TodoComments; - -namespace Microsoft.CodeAnalysis.Editor.Implementation.TodoComments -{ - /// - /// provide comment tokens to scan - /// - /// we use this indirection so that we can get different tokens based on host - /// - [Export] - internal class TodoCommentTokens - { - [ImportingConstructor] - public TodoCommentTokens() - { - } - - private class TokenInfo - { - internal readonly string OptionText; - internal readonly ImmutableArray Tokens; - - public TokenInfo(string optionText, ImmutableArray tokens) - { - this.OptionText = optionText; - this.Tokens = tokens; - } - } - - private TokenInfo _lastTokenInfo; - - public ImmutableArray GetTokens(Document document) - { - var optionText = document.Project.Solution.Options.GetOption(TodoCommentOptions.TokenList); - - var lastInfo = _lastTokenInfo; - if (lastInfo != null && lastInfo.OptionText == optionText) - { - return lastInfo.Tokens; - } - - var tokens = Parse(optionText); - - System.Threading.Interlocked.CompareExchange(ref _lastTokenInfo, new TokenInfo(optionText, tokens), lastInfo); - - return tokens; - } - } -} +//// Licensed to the .NET Foundation under one or more agreements. +//// The .NET Foundation licenses this file to you under the MIT license. +//// See the LICENSE file in the project root for more information. + +//using System.Collections.Generic; +//using System.Collections.Immutable; +//using System.ComponentModel.Composition; +//using System.Globalization; +//using System.Threading; +//using Microsoft.CodeAnalysis.TodoComments; + +//namespace Microsoft.CodeAnalysis.Editor.Implementation.TodoComments +//{ +// /// +// /// provide comment tokens to scan +// /// +// /// we use this indirection so that we can get different tokens based on host +// /// +// [Export] +// internal class TodoCommentTokens +// { +// [ImportingConstructor] +// public TodoCommentTokens() +// { +// } + +// private class TokenInfo +// { +// internal readonly string OptionText; +// internal readonly ImmutableArray Tokens; + +// public TokenInfo(string optionText, ImmutableArray tokens) +// { +// this.OptionText = optionText; +// this.Tokens = tokens; +// } +// } + +// private TokenInfo _lastTokenInfo; + +// public ImmutableArray GetTokens(Document document) +// { +// var optionText = document.Project.Solution.Options.GetOption(TodoCommentOptions.TokenList); + +// var lastInfo = _lastTokenInfo; +// if (lastInfo != null && lastInfo.OptionText == optionText) +// { +// return lastInfo.Tokens; +// } + +// var tokens = Parse(optionText); + +// System.Threading.Interlocked.CompareExchange(ref _lastTokenInfo, new TokenInfo(optionText, tokens), lastInfo); + +// return tokens; +// } +// } +//} diff --git a/src/EditorFeatures/Core/Implementation/TodoComment/TodoItem.cs b/src/EditorFeatures/Core/Implementation/TodoComment/TodoItem.cs index 6a510fa3a77b1edd2286d2629e62f526ba8fbc82..fa4f3e487b370e2087a1c5b77fa045ae3bb656a6 100644 --- a/src/EditorFeatures/Core/Implementation/TodoComment/TodoItem.cs +++ b/src/EditorFeatures/Core/Implementation/TodoComment/TodoItem.cs @@ -1,84 +1,84 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. +//// Licensed to the .NET Foundation under one or more agreements. +//// The .NET Foundation licenses this file to you under the MIT license. +//// See the LICENSE file in the project root for more information. -using System; -using Roslyn.Utilities; +//using System; +//using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.Editor -{ - internal sealed class TodoItem : IEquatable - { - public int Priority { get; } - public string Message { get; } - public DocumentId DocumentId { get; } - public string MappedFilePath { get; } - public string OriginalFilePath { get; } - public int MappedLine { get; } - public int MappedColumn { get; } - public int OriginalLine { get; } - public int OriginalColumn { get; } +//namespace Microsoft.CodeAnalysis.Editor +//{ +// internal sealed class TodoItem : IEquatable +// { +// public int Priority { get; } +// public string Message { get; } +// public DocumentId DocumentId { get; } +// public string MappedFilePath { get; } +// public string OriginalFilePath { get; } +// public int MappedLine { get; } +// public int MappedColumn { get; } +// public int OriginalLine { get; } +// public int OriginalColumn { get; } - public TodoItem( - int priority, - string message, - DocumentId documentId, - int mappedLine, - int originalLine, - int mappedColumn, - int originalColumn, - string mappedFilePath, - string originalFilePath) - { - Contract.ThrowIfNull(documentId); +// public TodoItem( +// int priority, +// string message, +// DocumentId documentId, +// int mappedLine, +// int originalLine, +// int mappedColumn, +// int originalColumn, +// string mappedFilePath, +// string originalFilePath) +// { +// Contract.ThrowIfNull(documentId); - Priority = priority; - Message = message; +// Priority = priority; +// Message = message; - DocumentId = documentId; +// DocumentId = documentId; - MappedLine = mappedLine; - MappedColumn = mappedColumn; - MappedFilePath = mappedFilePath; +// MappedLine = mappedLine; +// MappedColumn = mappedColumn; +// MappedFilePath = mappedFilePath; - OriginalLine = originalLine; - OriginalColumn = originalColumn; - OriginalFilePath = originalFilePath; - } +// OriginalLine = originalLine; +// OriginalColumn = originalColumn; +// OriginalFilePath = originalFilePath; +// } - public override bool Equals(object obj) - => obj is TodoItem other && Equals(other); +// public override bool Equals(object obj) +// => obj is TodoItem other && Equals(other); - public override int GetHashCode() - => GetHashCode(this); +// public override int GetHashCode() +// => GetHashCode(this); - public override string ToString() - => $"{Priority} {Message} {MappedFilePath ?? ""} ({MappedLine.ToString()}, {MappedColumn.ToString()}) [original: {OriginalFilePath ?? ""} ({OriginalLine.ToString()}, {OriginalColumn.ToString()})"; +// public override string ToString() +// => $"{Priority} {Message} {MappedFilePath ?? ""} ({MappedLine.ToString()}, {MappedColumn.ToString()}) [original: {OriginalFilePath ?? ""} ({OriginalLine.ToString()}, {OriginalColumn.ToString()})"; - public bool Equals(TodoItem right) - { - if (ReferenceEquals(this, right)) - { - return true; - } +// public bool Equals(TodoItem right) +// { +// if (ReferenceEquals(this, right)) +// { +// return true; +// } - if (right is null) - { - return false; - } +// if (right is null) +// { +// return false; +// } - return DocumentId == right.DocumentId && - Priority == right.Priority && - Message == right.Message && - OriginalLine == right.OriginalLine && - OriginalColumn == right.OriginalColumn; - } +// return DocumentId == right.DocumentId && +// Priority == right.Priority && +// Message == right.Message && +// OriginalLine == right.OriginalLine && +// OriginalColumn == right.OriginalColumn; +// } - public static int GetHashCode(TodoItem item) - => Hash.Combine(item.DocumentId, - Hash.Combine(item.Priority, - Hash.Combine(item.Message, - Hash.Combine(item.OriginalLine, - Hash.Combine(item.OriginalColumn, 0))))); - } -} +// public static int GetHashCode(TodoItem item) +// => Hash.Combine(item.DocumentId, +// Hash.Combine(item.Priority, +// Hash.Combine(item.Message, +// Hash.Combine(item.OriginalLine, +// Hash.Combine(item.OriginalColumn, 0))))); +// } +//} diff --git a/src/EditorFeatures/Core/Implementation/TodoComment/TodoItemsUpdatedArgs.cs b/src/EditorFeatures/Core/Implementation/TodoComment/TodoItemsUpdatedArgs.cs index 0783fb7fce0f758c06a2c2a068ab199fc09377cb..581cdca0919b809091602bcb4c718e08eec70507 100644 --- a/src/EditorFeatures/Core/Implementation/TodoComment/TodoItemsUpdatedArgs.cs +++ b/src/EditorFeatures/Core/Implementation/TodoComment/TodoItemsUpdatedArgs.cs @@ -4,6 +4,7 @@ using System.Collections.Immutable; using Microsoft.CodeAnalysis.Common; +using Microsoft.CodeAnalysis.TodoComments; namespace Microsoft.CodeAnalysis.Editor { @@ -17,10 +18,10 @@ internal sealed class TodoItemsUpdatedArgs : UpdatedEventArgs /// /// The task items associated with the ID. /// - public ImmutableArray TodoItems { get; } + public ImmutableArray TodoItems { get; } public TodoItemsUpdatedArgs( - object id, Workspace workspace, Solution solution, ProjectId projectId, DocumentId documentId, ImmutableArray todoItems) + object id, Workspace workspace, Solution solution, ProjectId projectId, DocumentId documentId, ImmutableArray todoItems) : base(id, workspace, projectId, documentId) { Solution = solution; diff --git a/src/EditorFeatures/TestUtilities/Remote/InProcRemostHostClient.cs b/src/EditorFeatures/TestUtilities/Remote/InProcRemostHostClient.cs index 20ce439979186b1221d4930ff5acc7993add173f..eb9a358c6ea6062334f79cf526ea824d9d22244a 100644 --- a/src/EditorFeatures/TestUtilities/Remote/InProcRemostHostClient.cs +++ b/src/EditorFeatures/TestUtilities/Remote/InProcRemostHostClient.cs @@ -169,7 +169,7 @@ public InProcRemoteServices(bool runCacheCleanup) RegisterService(WellKnownServiceHubServices.RemoteSymbolSearchUpdateEngine, (s, p) => new RemoteSymbolSearchUpdateEngine(s, p)); RegisterService(WellKnownServiceHubServices.RemoteDesignerAttributeService, (s, p) => new RemoteDesignerAttributeService(s, p)); RegisterService(WellKnownServiceHubServices.RemoteProjectTelemetryService, (s, p) => new RemoteProjectTelemetryService(s, p)); - RegisterService(WellKnownServiceHubServices.RemoteTodoCommentService, (s, p) => new RemoteTodoCommentService(s, p)); + RegisterService(WellKnownServiceHubServices.RemoteTodoCommentsService, (s, p) => new RemoteTodoCommentsService(s, p)); RegisterService(WellKnownServiceHubServices.LanguageServer, (s, p) => new LanguageServer(s, p)); } diff --git a/src/Features/Core/Portable/TodoComments/ITodoCommentService.cs b/src/Features/Core/Portable/TodoComments/ITodoCommentService.cs index d73892445a468034ad1907bfb706c6d8bdd8ee6c..571fb32e59978be8b101160974c9129e793ede36 100644 --- a/src/Features/Core/Portable/TodoComments/ITodoCommentService.cs +++ b/src/Features/Core/Portable/TodoComments/ITodoCommentService.cs @@ -3,56 +3,12 @@ // See the LICENSE file in the project root for more information. using System.Collections.Immutable; -using System.Globalization; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.PooledObjects; namespace Microsoft.CodeAnalysis.TodoComments { - /// - /// Description of a TODO comment type to find in a user's comments. - /// - internal readonly struct TodoCommentDescriptor - { - public string Text { get; } - public int Priority { get; } - - public TodoCommentDescriptor(string text, int priority) : this() - { - Text = text; - Priority = priority; - } - - public static ImmutableArray Parse(string data) - { - if (string.IsNullOrWhiteSpace(data)) - return ImmutableArray.Empty; - - var tuples = data.Split('|'); - var result = ArrayBuilder.GetInstance(); - - foreach (var tuple in tuples) - { - if (string.IsNullOrWhiteSpace(tuple)) - continue; - - var pair = tuple.Split(':'); - - if (pair.Length != 2 || string.IsNullOrWhiteSpace(pair[0])) - continue; - - if (!int.TryParse(pair[1], NumberStyles.None, CultureInfo.InvariantCulture, out var priority)) - continue; - - result.Add(new TodoCommentDescriptor(pair[0].Trim(), priority)); - } - - return result.ToImmutableAndFree(); - } - } - /// /// A TODO comment that has been found within the user's code. /// diff --git a/src/Features/Core/Portable/TodoComments/TodoCommentDescriptor.cs b/src/Features/Core/Portable/TodoComments/TodoCommentDescriptor.cs new file mode 100644 index 0000000000000000000000000000000000000000..f2e647a150a19b98a041314811e353501cf2a4b6 --- /dev/null +++ b/src/Features/Core/Portable/TodoComments/TodoCommentDescriptor.cs @@ -0,0 +1,67 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Immutable; +using System.Globalization; +using Microsoft.CodeAnalysis.PooledObjects; + +namespace Microsoft.CodeAnalysis.TodoComments +{ + /// + /// Description of a TODO comment type to find in a user's comments. + /// + internal readonly struct TodoCommentDescriptor + { + public string Text { get; } + public int Priority { get; } + + public TodoCommentDescriptor(string text, int priority) : this() + { + Text = text; + Priority = priority; + } + } + + internal readonly struct ParsedTodoCommentDescriptors + { + /// + /// The original option text that were parsed out of. + /// + public readonly string OptionText; + public readonly ImmutableArray Descriptors; + + public ParsedTodoCommentDescriptors(string optionText, ImmutableArray descriptors) + { + this.OptionText = optionText; + this.Descriptors = descriptors; + } + + public static ParsedTodoCommentDescriptors Parse(string data) + { + if (string.IsNullOrWhiteSpace(data)) + return new ParsedTodoCommentDescriptors(data, ImmutableArray.Empty); + + var tuples = data.Split('|'); + var result = ArrayBuilder.GetInstance(); + + foreach (var tuple in tuples) + { + if (string.IsNullOrWhiteSpace(tuple)) + continue; + + var pair = tuple.Split(':'); + + if (pair.Length != 2 || string.IsNullOrWhiteSpace(pair[0])) + continue; + + if (!int.TryParse(pair[1], NumberStyles.None, CultureInfo.InvariantCulture, out var priority)) + continue; + + result.Add(new TodoCommentDescriptor(pair[0].Trim(), priority)); + } + + return new ParsedTodoCommentDescriptors(data, result.ToImmutableAndFree()); + } + } +} diff --git a/src/VisualStudio/Core/Def/Implementation/TableDataSource/TodoTableItem.cs b/src/VisualStudio/Core/Def/Implementation/TableDataSource/TodoTableItem.cs index 3afcf92442fded77ef1dc52c73c9bae86a3bc915..234e169a1970381966c80a94f2c91db2b0d1def7 100644 --- a/src/VisualStudio/Core/Def/Implementation/TableDataSource/TodoTableItem.cs +++ b/src/VisualStudio/Core/Def/Implementation/TableDataSource/TodoTableItem.cs @@ -7,28 +7,28 @@ using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Editor; using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.TodoComments; using Roslyn.Utilities; namespace Microsoft.VisualStudio.LanguageServices.Implementation.TableDataSource { internal sealed class TodoTableItem : TableItem { - public readonly TodoItem Data; + public readonly TodoCommentInfo Data; private TodoTableItem( Workspace workspace, - TodoItem data, + TodoCommentInfo data, string projectName, Guid projectGuid, string[] projectNames, Guid[] projectGuids) : base(workspace, projectName, projectGuid, projectNames, projectGuids) { - Contract.ThrowIfNull(data); Data = data; } - public static TodoTableItem Create(Workspace workspace, TodoItem data) + public static TodoTableItem Create(Workspace workspace, TodoCommentInfo data) { GetProjectNameAndGuid(workspace, data.DocumentId.ProjectId, out var projectName, out var projectGuid); return new TodoTableItem(workspace, data, projectName, projectGuid, projectNames: Array.Empty(), projectGuids: Array.Empty()); @@ -66,29 +66,19 @@ public override bool EqualsIgnoringLocation(TableItem other) /// We want to avoid displaying diagnostic multuple times when it is reported from /// multi-targeted projects and/or files linked to multiple projects. /// - internal sealed class GroupingComparer : IEqualityComparer, IEqualityComparer + internal sealed class GroupingComparer : IEqualityComparer, IEqualityComparer { public static readonly GroupingComparer Instance = new GroupingComparer(); - public bool Equals(TodoItem left, TodoItem right) + public bool Equals(TodoCommentInfo left, TodoCommentInfo right) { - if (ReferenceEquals(left, right)) - { - return true; - } - - if (left is null || right is null) - { - return false; - } - // We don't need to compare OriginalFilePath since TODO items are only aggregated within a single file. return left.OriginalLine == right.OriginalLine && left.OriginalColumn == right.OriginalColumn; } - public int GetHashCode(TodoItem data) + public int GetHashCode(TodoCommentInfo data) => Hash.Combine(data.OriginalLine, data.OriginalColumn); public bool Equals(TodoTableItem left, TodoTableItem right) diff --git a/src/VisualStudio/Core/Def/Implementation/TableDataSource/VisualStudioBaseTodoListTable.cs b/src/VisualStudio/Core/Def/Implementation/TableDataSource/VisualStudioBaseTodoListTable.cs index 662a2adee037f77fcf2794703b46b48ae780d2f0..e5a8b9675582e5cad110038887b1a8166dcb4ec9 100644 --- a/src/VisualStudio/Core/Def/Implementation/TableDataSource/VisualStudioBaseTodoListTable.cs +++ b/src/VisualStudio/Core/Def/Implementation/TableDataSource/VisualStudioBaseTodoListTable.cs @@ -237,13 +237,13 @@ public override bool TryGetValue(int index, string columnName, out object conten switch (columnName) { case StandardTableKeyNames.Priority: - content = ValueTypeCache.GetOrCreate((VSTASKPRIORITY)data.Priority); + content = ValueTypeCache.GetOrCreate((VSTASKPRIORITY)data.Value.Priority); return content != null; case StandardTableKeyNames.Text: - content = data.Message; + content = data.Value.Message; return content != null; case StandardTableKeyNames.DocumentName: - content = GetFileName(data.OriginalFilePath, data.MappedFilePath); + content = GetFileName(data.Value.OriginalFilePath, data.Value.MappedFilePath); return content != null; case StandardTableKeyNames.Line: content = GetLineColumn(item).Line; diff --git a/src/VisualStudio/Core/Def/Implementation/TodoComment/ITodoCommentService.cs b/src/VisualStudio/Core/Def/Implementation/TodoComments/ITodoCommentsService.cs similarity index 90% rename from src/VisualStudio/Core/Def/Implementation/TodoComment/ITodoCommentService.cs rename to src/VisualStudio/Core/Def/Implementation/TodoComments/ITodoCommentsService.cs index 9e491b8bfaf7bef525d3648e83aeab39d7c27fd2..0c9f1e278f1bf1347ba85a62280c3d5ff3c94de2 100644 --- a/src/VisualStudio/Core/Def/Implementation/TodoComment/ITodoCommentService.cs +++ b/src/VisualStudio/Core/Def/Implementation/TodoComments/ITodoCommentsService.cs @@ -7,12 +7,12 @@ using System.Threading; using Microsoft.CodeAnalysis.Host; -namespace Microsoft.VisualStudio.LanguageServices.Implementation.TodoComment +namespace Microsoft.VisualStudio.LanguageServices.Implementation.TodoComments { /// /// In process service responsible for listening to OOP todo comment notifications. /// - internal interface ITodoCommentService : IWorkspaceService + internal interface ITodoCommentsService : IWorkspaceService { /// /// Called by a host to let this service know that it should start background diff --git a/src/VisualStudio/Core/Def/Implementation/TodoComment/VisualStudioTodoCommentService.cs b/src/VisualStudio/Core/Def/Implementation/TodoComments/VisualStudioTodoCommentsService.cs similarity index 60% rename from src/VisualStudio/Core/Def/Implementation/TodoComment/VisualStudioTodoCommentService.cs rename to src/VisualStudio/Core/Def/Implementation/TodoComments/VisualStudioTodoCommentsService.cs index d66610372f57250ff5669f5aed9ba22b4e7fa808..6550fe5df8a3d1043fc5f68e6a26d55ab5b0bf56 100644 --- a/src/VisualStudio/Core/Def/Implementation/TodoComment/VisualStudioTodoCommentService.cs +++ b/src/VisualStudio/Core/Def/Implementation/TodoComments/VisualStudioTodoCommentsService.cs @@ -7,27 +7,32 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Linq; +using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Common; +using Microsoft.CodeAnalysis.Editor; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; using Microsoft.CodeAnalysis.ErrorReporting; +using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.PooledObjects; -using Microsoft.CodeAnalysis.ProjectTelemetry; using Microsoft.CodeAnalysis.Remote; -using Microsoft.CodeAnalysis.Shared.Extensions; -using Microsoft.CodeAnalysis.TodoComment; using Microsoft.CodeAnalysis.TodoComments; -using Microsoft.Internal.VisualStudio.Shell; using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem; using Roslyn.Utilities; -namespace Microsoft.VisualStudio.LanguageServices.Implementation.TodoComment +namespace Microsoft.VisualStudio.LanguageServices.Implementation.TodoComments { - internal class VisualStudioTodoCommentService - : ForegroundThreadAffinitizedObject, ITodoCommentService, ITodoCommentServiceCallback + internal class VisualStudioTodoCommentsService + : ForegroundThreadAffinitizedObject, ITodoCommentsService, ITodoCommentsServiceCallback, ITodoListProvider { private readonly VisualStudioWorkspaceImpl _workspace; + private readonly EventListenerTracker _eventListenerTracker; + + private readonly ConditionalWeakTable>> _documentToInfos + = new ConditionalWeakTable>>(); /// /// Our connections to the remote OOP server. Created on demand when we startup and then @@ -40,10 +45,19 @@ internal class VisualStudioTodoCommentService /// private AsyncBatchingWorkQueue _workQueue = null!; - public VisualStudioTodoCommentService(VisualStudioWorkspaceImpl workspace, IThreadingContext threadingContext) : base(threadingContext) - => _workspace = workspace; + public event EventHandler? TodoListUpdated; + + public VisualStudioTodoCommentsService( + VisualStudioWorkspaceImpl workspace, + IThreadingContext threadingContext, + EventListenerTracker eventListenerTracker) + : base(threadingContext) + { + _workspace = workspace; + _eventListenerTracker = eventListenerTracker; + } - void ITodoCommentService.Start(CancellationToken cancellationToken) + void ITodoCommentsService.Start(CancellationToken cancellationToken) => _ = StartAsync(cancellationToken); private async Task StartAsync(CancellationToken cancellationToken) @@ -79,14 +93,17 @@ private async Task StartWorkerAsync(CancellationToken cancellationToken) // Pass ourselves in as the callback target for the OOP service. As it discovers // designer attributes it will call back into us to notify VS about it. _keepAliveSession = await client.TryCreateKeepAliveSessionAsync( - WellKnownServiceHubServices.RemoteTodoCommentService, + WellKnownServiceHubServices.RemoteTodoCommentsService, callbackTarget: this, cancellationToken).ConfigureAwait(false); if (_keepAliveSession == null) return; + // Now that we've started, let the VS todo list know to start listening to us + _eventListenerTracker.EnsureEventListener(_workspace, this); + // Now kick off scanning in the OOP process. var success = await _keepAliveSession.TryInvokeAsync( - nameof(IRemoteTodoCommentService.ComputeTodoCommentsAsync), + nameof(IRemoteTodoCommentsService.ComputeTodoCommentsAsync), solution: null, arguments: Array.Empty(), cancellationToken).ConfigureAwait(false); @@ -101,19 +118,31 @@ public Task ReportTodoCommentsAsync(List infos, CancellationTok return Task.CompletedTask; } - private async Task ProcessTodoCommentInfosAsync( + private Task ProcessTodoCommentInfosAsync( ImmutableArray infos, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); - using var _1 = ArrayBuilder.GetInstance(out var filteredInfos); + using var _ = ArrayBuilder.GetInstance(out var filteredInfos); AddFilteredInfos(infos, filteredInfos); - using var _2 = ArrayBuilder.GetInstance(out var tasks); - foreach (var info in filteredInfos) - tasks.Add(Task.Run(() => NotifyTelemetryService(info), cancellationToken)); + foreach (var group in filteredInfos.GroupBy(i => i.DocumentId)) + { + var documentId = group.Key; + var documentInfos = group.ToImmutableArray(); + + // only one thread can be executing ProcessTodoCommentInfosAsync at a time, + // so it's safe to remove/add here. + _documentToInfos.Remove(documentId); + _documentToInfos.Add(documentId, new StrongBox>(documentInfos)); + + this.TodoListUpdated?.Invoke( + this, new TodoItemsUpdatedArgs( + documentId, _workspace, _workspace.CurrentSolution, + documentId.ProjectId, documentId, documentInfos)); + } - await Task.WhenAll(tasks).ConfigureAwait(false); + return Task.CompletedTask; } private void AddFilteredInfos(ImmutableArray infos, ArrayBuilder filteredInfos) @@ -131,38 +160,18 @@ private void AddFilteredInfos(ImmutableArray infos, ArrayBuilde } } - private void ProcessTodoCommentInfosAsync(ProjectTelemetryInfo info) + public ImmutableArray GetTodoItems(Workspace workspace, DocumentId documentId, CancellationToken cancellationToken) { - try - { - var telemetryEvent = TelemetryHelper.TelemetryService.CreateEvent(TelemetryEventPath); - telemetryEvent.SetStringProperty(TelemetryProjectIdName, info.ProjectId.Id.ToString()); - telemetryEvent.SetStringProperty(TelemetryProjectGuidName, Guid.Empty.ToString()); - telemetryEvent.SetStringProperty(TelemetryLanguageName, info.Language); - telemetryEvent.SetIntProperty(TelemetryAnalyzerReferencesCountName, info.AnalyzerReferencesCount); - telemetryEvent.SetIntProperty(TelemetryProjectReferencesCountName, info.ProjectReferencesCount); - telemetryEvent.SetIntProperty(TelemetryMetadataReferencesCountName, info.MetadataReferencesCount); - telemetryEvent.SetIntProperty(TelemetryDocumentsCountName, info.DocumentsCount); - telemetryEvent.SetIntProperty(TelemetryAdditionalDocumentsCountName, info.AdditionalDocumentsCount); - - TelemetryHelper.DefaultTelemetrySession.PostEvent(telemetryEvent); - } - catch (Exception e) - { - // The telemetry service itself can throw. - // So, to be very careful, put this in a try/catch too. - try - { - var exceptionEvent = TelemetryHelper.TelemetryService.CreateEvent(TelemetryExceptionEventPath); - exceptionEvent.SetStringProperty("Type", e.GetTypeDisplayName()); - exceptionEvent.SetStringProperty("Message", e.Message); - exceptionEvent.SetStringProperty("StackTrace", e.StackTrace); - TelemetryHelper.DefaultTelemetrySession.PostEvent(exceptionEvent); - } - catch - { - } - } + return _documentToInfos.TryGetValue(documentId, out var values) + ? values.Value + : ImmutableArray.Empty; + } + + public IEnumerable GetTodoItemsUpdatedEventArgs( + Workspace workspace, CancellationToken cancellationToken) + { + // Don't need to implement this. OOP pushes all items over to VS. So there's no need + return SpecializedCollections.EmptyEnumerable(); } } } diff --git a/src/VisualStudio/Core/Def/Implementation/TodoComment/VisualStudioTodoCommentServiceFactory.cs b/src/VisualStudio/Core/Def/Implementation/TodoComments/VisualStudioTodoCommentsServiceFactory.cs similarity index 54% rename from src/VisualStudio/Core/Def/Implementation/TodoComment/VisualStudioTodoCommentServiceFactory.cs rename to src/VisualStudio/Core/Def/Implementation/TodoComments/VisualStudioTodoCommentsServiceFactory.cs index 15c4a39b92d538a9f03ad661d29a9bfa760af6f7..c2c4eb50e39d0d69ad4b07d817e4bb5ac6dea771 100644 --- a/src/VisualStudio/Core/Def/Implementation/TodoComment/VisualStudioTodoCommentServiceFactory.cs +++ b/src/VisualStudio/Core/Def/Implementation/TodoComments/VisualStudioTodoCommentsServiceFactory.cs @@ -5,6 +5,7 @@ #nullable enable using System; +using System.Collections.Generic; using System.Composition; using Microsoft.CodeAnalysis.Editor; using Microsoft.CodeAnalysis.Editor.Shared.Utilities; @@ -12,25 +13,32 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.VisualStudio.LanguageServices.Implementation.ProjectSystem; -namespace Microsoft.VisualStudio.LanguageServices.Implementation.TodoComment +namespace Microsoft.VisualStudio.LanguageServices.Implementation.TodoComments { [Export(typeof(ITodoListProvider))] - [ExportWorkspaceServiceFactory(typeof(ITodoCommentService), ServiceLayer.Host), Shared] - internal class VisualStudioTodoCommentServiceFactory : IWorkspaceServiceFactory, ITodoListProvider + [ExportWorkspaceServiceFactory(typeof(ITodoCommentsService), ServiceLayer.Host), Shared] + internal class VisualStudioTodoCommentsServiceFactory : IWorkspaceServiceFactory { private readonly IThreadingContext _threadingContext; + private readonly EventListenerTracker _eventListenerTracker; [ImportingConstructor] [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] - public VisualStudioTodoCommentServiceFactory(IThreadingContext threadingContext) - => _threadingContext = threadingContext; + public VisualStudioTodoCommentsServiceFactory( + IThreadingContext threadingContext, + [ImportMany]IEnumerable> eventListeners) + { + _threadingContext = threadingContext; + _eventListenerTracker = new EventListenerTracker(eventListeners, WellKnownEventListeners.TodoListProvider); + } public IWorkspaceService? CreateService(HostWorkspaceServices workspaceServices) { if (!(workspaceServices.Workspace is VisualStudioWorkspaceImpl workspace)) return null; - return new VisualStudioTodoCommentService(workspace, _threadingContext); + return new VisualStudioTodoCommentsService( + workspace, _threadingContext, _eventListenerTracker); } } } diff --git a/src/VisualStudio/Core/Test.Next/Services/ServiceHubServicesTests.cs b/src/VisualStudio/Core/Test.Next/Services/ServiceHubServicesTests.cs index bd1ad116696bfcb48f98d879c611026f0fce993a..172a18716585c52101d4d9329c1abbe10fda8447 100644 --- a/src/VisualStudio/Core/Test.Next/Services/ServiceHubServicesTests.cs +++ b/src/VisualStudio/Core/Test.Next/Services/ServiceHubServicesTests.cs @@ -146,7 +146,7 @@ public async Task TestTodoComments() var comments = await client.TryRunRemoteAsync>( WellKnownServiceHubServices.CodeAnalysisService, - nameof(IRemoteTodoCommentService.GetTodoCommentsAsync), + nameof(IRemoteTodoCommentsService.GetTodoCommentsAsync), solution, new object[] { solution.Projects.First().DocumentIds.First(), ImmutableArray.Create(new TodoCommentDescriptor("TODO", 0)) }, callbackTarget: null, diff --git a/src/VisualStudio/Setup/source.extension.vsixmanifest b/src/VisualStudio/Setup/source.extension.vsixmanifest index 2ed4dbea22597f89a9b49b71877d14e8e255ac2c..e20959f7c660c70fa564e199078abc2c8a125d0a 100644 --- a/src/VisualStudio/Setup/source.extension.vsixmanifest +++ b/src/VisualStudio/Setup/source.extension.vsixmanifest @@ -37,7 +37,7 @@ - + @@ -45,7 +45,7 @@ - + diff --git a/src/Workspaces/Core/Portable/Remote/WellKnownServiceHubServices.cs b/src/Workspaces/Core/Portable/Remote/WellKnownServiceHubServices.cs index 50ceaf84b7755a280556b6350a4d77a78ec75b8c..3150b2d0754b2997749c374943f8fbca0fc2b2a8 100644 --- a/src/Workspaces/Core/Portable/Remote/WellKnownServiceHubServices.cs +++ b/src/Workspaces/Core/Portable/Remote/WellKnownServiceHubServices.cs @@ -15,7 +15,7 @@ public static void Set64bit(bool x64) RemoteDesignerAttributeService = "roslynRemoteDesignerAttributeService" + bit; RemoteProjectTelemetryService = "roslynRemoteProjectTelemetryService" + bit; RemoteSymbolSearchUpdateEngine = "roslynRemoteSymbolSearchUpdateEngine" + bit; - RemoteTodoCommentService = "roslynRemoteTodoCommentService" + bit; + RemoteTodoCommentsService = "roslynRemoteTodoCommentsService" + bit; LanguageServer = "roslynLanguageServer" + bit; } @@ -24,7 +24,7 @@ public static void Set64bit(bool x64) public static string RemoteDesignerAttributeService { get; private set; } = "roslynRemoteDesignerAttributeService"; public static string RemoteProjectTelemetryService { get; private set; } = "roslynRemoteProjectTelemetryService"; public static string RemoteSymbolSearchUpdateEngine { get; private set; } = "roslynRemoteSymbolSearchUpdateEngine"; - public static string RemoteTodoCommentService { get; private set; } = "roslynRemoteTodoCommentService"; + public static string RemoteTodoCommentsService { get; private set; } = "roslynRemoteTodoCommentsService"; public static string LanguageServer { get; private set; } = "roslynLanguageServer"; // these are OOP implementation itself should care. not features that consume OOP care diff --git a/src/Workspaces/Core/Portable/TodoComment/IRemoteTodoCommentsService.cs b/src/Workspaces/Core/Portable/TodoComments/IRemoteTodoCommentsService.cs similarity index 85% rename from src/Workspaces/Core/Portable/TodoComment/IRemoteTodoCommentsService.cs rename to src/Workspaces/Core/Portable/TodoComments/IRemoteTodoCommentsService.cs index 5e8ddd64aff14df63b2d08cd0aeee7bc20ad1574..2123d1cbc6fc08ed84adb449202766c2ab2bef96 100644 --- a/src/Workspaces/Core/Portable/TodoComment/IRemoteTodoCommentsService.cs +++ b/src/Workspaces/Core/Portable/TodoComments/IRemoteTodoCommentsService.cs @@ -7,13 +7,13 @@ using System.Threading; using System.Threading.Tasks; -namespace Microsoft.CodeAnalysis.TodoComment +namespace Microsoft.CodeAnalysis.TodoComments { /// /// Interface to allow host (VS) to inform the OOP service to start incrementally analyzing and /// reporting results back to the host. /// - internal interface IRemoteTodoCommentService + internal interface IRemoteTodoCommentsService { Task ComputeTodoCommentsAsync(CancellationToken cancellation); } diff --git a/src/Workspaces/Core/Portable/TodoComment/ITodoCommentServiceCallback.cs b/src/Workspaces/Core/Portable/TodoComments/ITodoCommentsServiceCallback.cs similarity index 85% rename from src/Workspaces/Core/Portable/TodoComment/ITodoCommentServiceCallback.cs rename to src/Workspaces/Core/Portable/TodoComments/ITodoCommentsServiceCallback.cs index aa2380837b4e8001aa312a7e6d6fc41c31c9458f..c77025b74fbc133c5c5986c7d0dd4a66ba54306c 100644 --- a/src/Workspaces/Core/Portable/TodoComment/ITodoCommentServiceCallback.cs +++ b/src/Workspaces/Core/Portable/TodoComments/ITodoCommentsServiceCallback.cs @@ -8,13 +8,13 @@ using System.Threading; using System.Threading.Tasks; -namespace Microsoft.CodeAnalysis.TodoComment +namespace Microsoft.CodeAnalysis.TodoComments { /// /// Callback the host (VS) passes to the OOP service to allow it to send batch notifications /// about todo comments. /// - internal interface ITodoCommentServiceCallback + internal interface ITodoCommentsServiceCallback { Task ReportTodoCommentsAsync(List infos, CancellationToken cancellationToken); } diff --git a/src/Workspaces/Core/Portable/TodoComment/TodoCommentInfo.cs b/src/Workspaces/Core/Portable/TodoComments/TodoCommentInfo.cs similarity index 98% rename from src/Workspaces/Core/Portable/TodoComment/TodoCommentInfo.cs rename to src/Workspaces/Core/Portable/TodoComments/TodoCommentInfo.cs index 8835782b9335b56bfbf3d2e4b94479647cb4b7a0..8474e13b9528f1268157be95882a797223833fa4 100644 --- a/src/Workspaces/Core/Portable/TodoComment/TodoCommentInfo.cs +++ b/src/Workspaces/Core/Portable/TodoComments/TodoCommentInfo.cs @@ -7,7 +7,7 @@ using Microsoft.CodeAnalysis.Shared.Extensions; using Roslyn.Utilities; -namespace Microsoft.CodeAnalysis.TodoComment +namespace Microsoft.CodeAnalysis.TodoComments { /// /// Serialization typed used to pass information to/from OOP and VS. diff --git a/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysisService_TodoComments.cs b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysisService_TodoComments.cs index 3caf1449320b7a1e75aa32bd58a8aea20bfdec4f..d8cfde589d9a2055d8a50c79d66b6097d721d5b6 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysisService_TodoComments.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/CodeAnalysisService_TodoComments.cs @@ -15,7 +15,7 @@ namespace Microsoft.CodeAnalysis.Remote { // root level service for all Roslyn services - internal partial class CodeAnalysisService : IRemoteTodoCommentService + internal partial class CodeAnalysisService : IRemoteTodoCommentsService { /// /// This is top level entry point for TodoComments service from client (VS). diff --git a/src/Workspaces/Remote/ServiceHub/Services/TodoComment/DescriptorsInfo.cs b/src/Workspaces/Remote/ServiceHub/Services/TodoComment/DescriptorsInfo.cs deleted file mode 100644 index 2a4d84ce96d7f25fcaf6299d829ae9a05e6634f2..0000000000000000000000000000000000000000 --- a/src/Workspaces/Remote/ServiceHub/Services/TodoComment/DescriptorsInfo.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System.Collections.Immutable; -using Microsoft.CodeAnalysis.TodoComments; - -namespace Microsoft.CodeAnalysis.Remote.Services.TodoComment -{ - internal class DescriptorInfo - { - public readonly string OptionText; - public readonly ImmutableArray Descriptors; - - public DescriptorInfo(string optionText, ImmutableArray descriptors) - { - this.OptionText = optionText; - this.Descriptors = descriptors; - } - } -} diff --git a/src/Workspaces/Remote/ServiceHub/Services/TodoComment/RemoteTodoCommentIncrementalAnalyzer_Serialization.cs b/src/Workspaces/Remote/ServiceHub/Services/TodoComment/RemoteTodoCommentIncrementalAnalyzer_Serialization.cs deleted file mode 100644 index 49fcdb04c566616feec31243544ec59dd3887bef..0000000000000000000000000000000000000000 --- a/src/Workspaces/Remote/ServiceHub/Services/TodoComment/RemoteTodoCommentIncrementalAnalyzer_Serialization.cs +++ /dev/null @@ -1,91 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -#nullable enable - -using System.Collections.Immutable; -using System.IO; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.PooledObjects; -using Microsoft.CodeAnalysis.TodoComments; -using Roslyn.Utilities; - -namespace Microsoft.CodeAnalysis.Remote -{ - internal partial class RemoteTodoCommentIncrementalAnalyzer - { - private const string SerializationFormat = "1"; - - private async Task TryReadExistingCommentInfoAsync( - IPersistentStorage storage, Document document, CancellationToken cancellationToken) - { - using var stream = await storage.ReadStreamAsync(document, DataKey, cancellationToken).ConfigureAwait(false); - using var reader = ObjectReader.TryGetReader(stream, cancellationToken: cancellationToken); - return TryReadPersistedInfo(reader); - } - - private async Task PersistTodoCommentsAsync( - IPersistentStorage storage, - Document document, - PersistedTodoCommentInfo info, - CancellationToken cancellationToken) - { - using var memoryStream = new MemoryStream(); - using var writer = new ObjectWriter(memoryStream); - - writer.WriteString(SerializationFormat); - info.Version.WriteTo(writer); - writer.WriteString(info.OptionText); - - writer.WriteInt32(info.TodoComments.Length); - foreach (var comment in info.TodoComments) - comment.WriteTo(writer); - - memoryStream.Position = 0; - await storage.WriteStreamAsync( - document, DataKey, memoryStream, cancellationToken).ConfigureAwait(false); - } - - private static PersistedTodoCommentInfo? TryReadPersistedInfo(ObjectReader reader) - { - if (reader == null) - return null; - - try - { - var serializationFormat = reader.ReadString(); - if (serializationFormat != SerializationFormat) - return null; - - var version = VersionStamp.ReadFrom(reader); - var optionText = reader.ReadString(); - - var count = reader.ReadInt32(); - using var _ = ArrayBuilder.GetInstance(out var comments); - for (int i = 0; i < count; i++) - comments.Add(TodoCommentInfo.ReadFrom(reader)); - - return new PersistedTodoCommentInfo - { - Version = version, - OptionText = optionText, - TodoComments = comments.ToImmutable(), - }; - } - catch - { - } - return null; - } - - private class PersistedTodoCommentInfo - { - public VersionStamp Version; - public string? OptionText; - public ImmutableArray TodoComments; - } - } -} diff --git a/src/Workspaces/Remote/ServiceHub/Services/TodoComments/RemoteTodoCommentIncrementalAnalyzer_Serialization.cs b/src/Workspaces/Remote/ServiceHub/Services/TodoComments/RemoteTodoCommentIncrementalAnalyzer_Serialization.cs new file mode 100644 index 0000000000000000000000000000000000000000..9dfcb876afc5f0750f160854172a822229a5e405 --- /dev/null +++ b/src/Workspaces/Remote/ServiceHub/Services/TodoComments/RemoteTodoCommentIncrementalAnalyzer_Serialization.cs @@ -0,0 +1,91 @@ +//// Licensed to the .NET Foundation under one or more agreements. +//// The .NET Foundation licenses this file to you under the MIT license. +//// See the LICENSE file in the project root for more information. + +//#nullable enable + +//using System.Collections.Immutable; +//using System.IO; +//using System.Threading; +//using System.Threading.Tasks; +//using Microsoft.CodeAnalysis.Host; +//using Microsoft.CodeAnalysis.PooledObjects; +//using Microsoft.CodeAnalysis.TodoComments; +//using Roslyn.Utilities; + +//namespace Microsoft.CodeAnalysis.Remote +//{ +// internal partial class RemoteTodoCommentIncrementalAnalyzer +// { +// private const string SerializationFormat = "1"; + +// private async Task TryReadExistingCommentInfoAsync( +// IPersistentStorage storage, Document document, CancellationToken cancellationToken) +// { +// using var stream = await storage.ReadStreamAsync(document, DataKey, cancellationToken).ConfigureAwait(false); +// using var reader = ObjectReader.TryGetReader(stream, cancellationToken: cancellationToken); +// return TryReadPersistedInfo(reader); +// } + +// private async Task PersistTodoCommentsAsync( +// IPersistentStorage storage, +// Document document, +// PersistedTodoCommentInfo info, +// CancellationToken cancellationToken) +// { +// using var memoryStream = new MemoryStream(); +// using var writer = new ObjectWriter(memoryStream); + +// writer.WriteString(SerializationFormat); +// info.Version.WriteTo(writer); +// writer.WriteString(info.OptionText); + +// writer.WriteInt32(info.TodoComments.Length); +// foreach (var comment in info.TodoComments) +// comment.WriteTo(writer); + +// memoryStream.Position = 0; +// await storage.WriteStreamAsync( +// document, DataKey, memoryStream, cancellationToken).ConfigureAwait(false); +// } + +// private static PersistedTodoCommentInfo? TryReadPersistedInfo(ObjectReader reader) +// { +// if (reader == null) +// return null; + +// try +// { +// var serializationFormat = reader.ReadString(); +// if (serializationFormat != SerializationFormat) +// return null; + +// var version = VersionStamp.ReadFrom(reader); +// var optionText = reader.ReadString(); + +// var count = reader.ReadInt32(); +// using var _ = ArrayBuilder.GetInstance(out var comments); +// for (int i = 0; i < count; i++) +// comments.Add(TodoCommentInfo.ReadFrom(reader)); + +// return new PersistedTodoCommentInfo +// { +// Version = version, +// OptionText = optionText, +// TodoComments = comments.ToImmutable(), +// }; +// } +// catch +// { +// } +// return null; +// } + +// private class PersistedTodoCommentInfo +// { +// public VersionStamp Version; +// public string? OptionText; +// public ImmutableArray TodoComments; +// } +// } +//} diff --git a/src/Workspaces/Remote/ServiceHub/Services/TodoComment/RemoteTodoCommentIncrementalAnalyzer.cs b/src/Workspaces/Remote/ServiceHub/Services/TodoComments/RemoteTodoCommentsIncrementalAnalyzer.cs similarity index 71% rename from src/Workspaces/Remote/ServiceHub/Services/TodoComment/RemoteTodoCommentIncrementalAnalyzer.cs rename to src/Workspaces/Remote/ServiceHub/Services/TodoComments/RemoteTodoCommentsIncrementalAnalyzer.cs index a896c73a3ed6dc327e1e356c5174f0f680894977..4f759f977ab5e63a66bff11e678c538d068007ff 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/TodoComment/RemoteTodoCommentIncrementalAnalyzer.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/TodoComments/RemoteTodoCommentsIncrementalAnalyzer.cs @@ -5,29 +5,22 @@ #nullable enable using System; -using System.Collections.Generic; using System.Collections.Immutable; -using System.IO; -using System.Security.Cryptography; using System.Threading; using System.Threading.Tasks; -using System.Windows.Media.TextFormatting; -using Microsoft.CodeAnalysis; + using Microsoft.CodeAnalysis.Editor.Implementation.TodoComments; using Microsoft.CodeAnalysis.Host; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.PooledObjects; -using Microsoft.CodeAnalysis.ProjectTelemetry; -using Microsoft.CodeAnalysis.Remote.Services.TodoComment; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.SolutionCrawler; using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.TodoComments; -using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.Remote { - internal partial class RemoteTodoCommentIncrementalAnalyzer : IncrementalAnalyzerBase + internal partial class RemoteTodoCommentsIncrementalAnalyzer : IncrementalAnalyzerBase { private const string DataKey = "TodoComment"; @@ -39,9 +32,9 @@ internal partial class RemoteTodoCommentIncrementalAnalyzer : IncrementalAnalyze private readonly IPersistentStorageService _storageService; private readonly object _gate = new object(); - private DescriptorInfo? _lastDescriptorInfo; + private ParsedTodoCommentDescriptors? _lastDescriptorInfo; - public RemoteTodoCommentIncrementalAnalyzer(Workspace workspace, RemoteEndPoint endPoint) + public RemoteTodoCommentsIncrementalAnalyzer(Workspace workspace, RemoteEndPoint endPoint) { _endPoint = endPoint; _storageService = workspace.Services.GetRequiredService(); @@ -50,16 +43,16 @@ public RemoteTodoCommentIncrementalAnalyzer(Workspace workspace, RemoteEndPoint public override bool NeedsReanalysisOnOptionChanged(object sender, OptionChangedEventArgs e) => e.Option == TodoCommentOptions.TokenList; - private DescriptorInfo GetDescriptorInfo(Document document) + private ParsedTodoCommentDescriptors GetParsedTodoCommentDescriptors(Document document) { var optionText = document.Project.Solution.Options.GetOption(TodoCommentOptions.TokenList); lock (_gate) { - if (_lastDescriptorInfo == null || _lastDescriptorInfo.OptionText != optionText) - _lastDescriptorInfo = new DescriptorInfo(optionText, TodoCommentDescriptor.Parse(optionText)); + if (_lastDescriptorInfo == null || _lastDescriptorInfo.Value.OptionText != optionText) + _lastDescriptorInfo = ParsedTodoCommentDescriptors.Parse(optionText); - return _lastDescriptorInfo; + return _lastDescriptorInfo.Value; } } @@ -69,20 +62,20 @@ public override async Task AnalyzeSyntaxAsync(Document document, InvocationReaso if (todoCommentService == null) return; - using var storage = _storageService.GetStorage(document.Project.Solution); + //using var storage = _storageService.GetStorage(document.Project.Solution); - var version = await document.GetSyntaxVersionAsync(cancellationToken).ConfigureAwait(false); - var descriptorInfo = GetDescriptorInfo(document); + //var version = await document.GetSyntaxVersionAsync(cancellationToken).ConfigureAwait(false); + var descriptorInfo = GetParsedTodoCommentDescriptors(document); - var persistedInfo = await TryReadExistingCommentInfoAsync( - storage, document, cancellationToken).ConfigureAwait(false); - if (persistedInfo != null && - persistedInfo.Version == version && - persistedInfo.OptionText == descriptorInfo.OptionText) - { - // Our info for this file is up to date. - return; - } + //var persistedInfo = await TryReadExistingCommentInfoAsync( + // storage, document, cancellationToken).ConfigureAwait(false); + //if (persistedInfo != null && + // persistedInfo.Version == version && + // persistedInfo.OptionText == descriptorInfo.OptionText) + //{ + // // Our info for this file is up to date. + // return; + //} // We're out of date. Recompute this info. var todoComments = await todoCommentService.GetTodoCommentsAsync( @@ -99,16 +92,16 @@ public override async Task AnalyzeSyntaxAsync(Document document, InvocationReaso new object[] { converted }, cancellationToken).ConfigureAwait(false); - persistedInfo = new PersistedTodoCommentInfo - { - Version = version, - OptionText = descriptorInfo.OptionText, - TodoComments = converted.ToImmutable(), - }; + //persistedInfo = new PersistedTodoCommentInfo + //{ + // Version = version, + // OptionText = descriptorInfo.OptionText, + // TodoComments = converted.ToImmutable(), + //}; - // now that we've informed VS, save this information for the future. - await PersistTodoCommentsAsync( - storage, document, persistedInfo, cancellationToken).ConfigureAwait(false); + //// now that we've informed VS, save this information for the future. + //await PersistTodoCommentsAsync( + // storage, document, persistedInfo, cancellationToken).ConfigureAwait(false); } private async Task ConvertAsync( diff --git a/src/Workspaces/Remote/ServiceHub/Services/TodoComment/RemoteTodoCommentIncrementalAnalyzerProvider.cs b/src/Workspaces/Remote/ServiceHub/Services/TodoComments/RemoteTodoCommentsIncrementalAnalyzerProvider.cs similarity index 76% rename from src/Workspaces/Remote/ServiceHub/Services/TodoComment/RemoteTodoCommentIncrementalAnalyzerProvider.cs rename to src/Workspaces/Remote/ServiceHub/Services/TodoComments/RemoteTodoCommentsIncrementalAnalyzerProvider.cs index f34e2d4f44394230af76e2198819faf599f3b9c5..04e5826a54888abc3e545651e81dc70d1b0678e5 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/TodoComment/RemoteTodoCommentIncrementalAnalyzerProvider.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/TodoComments/RemoteTodoCommentsIncrementalAnalyzerProvider.cs @@ -13,16 +13,16 @@ namespace Microsoft.CodeAnalysis.Remote /// and then calls into OOP to tell it to start analyzing the solution. At that point we'll get /// created and added to the solution crawler. /// - internal class RemoteTodoCommentIncrementalAnalyzerProvider : IIncrementalAnalyzerProvider + internal class RemoteTodoCommentsIncrementalAnalyzerProvider : IIncrementalAnalyzerProvider { private readonly RemoteEndPoint _endPoint; - public RemoteTodoCommentIncrementalAnalyzerProvider(RemoteEndPoint endPoint) + public RemoteTodoCommentsIncrementalAnalyzerProvider(RemoteEndPoint endPoint) { _endPoint = endPoint; } public IIncrementalAnalyzer CreateIncrementalAnalyzer(Workspace workspace) - => new RemoteTodoCommentIncrementalAnalyzer(_endPoint); + => new RemoteTodoCommentsIncrementalAnalyzer(workspace, _endPoint); } } diff --git a/src/Workspaces/Remote/ServiceHub/Services/TodoComment/RemoteTodoCommentsService.cs b/src/Workspaces/Remote/ServiceHub/Services/TodoComments/RemoteTodoCommentsService.cs similarity index 79% rename from src/Workspaces/Remote/ServiceHub/Services/TodoComment/RemoteTodoCommentsService.cs rename to src/Workspaces/Remote/ServiceHub/Services/TodoComments/RemoteTodoCommentsService.cs index da31825e8155010f8ffb66c021cf76d0eeccdac4..1c7adafbe4e74d1aeba1342f0715dee499bb219a 100644 --- a/src/Workspaces/Remote/ServiceHub/Services/TodoComment/RemoteTodoCommentsService.cs +++ b/src/Workspaces/Remote/ServiceHub/Services/TodoComments/RemoteTodoCommentsService.cs @@ -10,12 +10,13 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis.ProjectTelemetry; using Microsoft.CodeAnalysis.SolutionCrawler; +using Microsoft.CodeAnalysis.TodoComments; namespace Microsoft.CodeAnalysis.Remote { - internal partial class RemoteTodoCommentService : ServiceBase, IRemoteTodoCommentService + internal partial class RemoteTodoCommentsService : ServiceBase, IRemoteTodoCommentsService { - public RemoteTodoCommentService( + public RemoteTodoCommentsService( Stream stream, IServiceProvider serviceProvider) : base(serviceProvider, stream) { @@ -29,12 +30,12 @@ public Task ComputeTodoCommentsAsync(CancellationToken cancellation) var workspace = SolutionService.PrimaryWorkspace; var endpoint = this.EndPoint; var registrationService = workspace.Services.GetRequiredService(); - var analyzerProvider = new RemoteTodoCommentIncrementalAnalyzerProvider(endpoint); + var analyzerProvider = new RemoteTodoCommentsIncrementalAnalyzerProvider(endpoint); registrationService.AddAnalyzerProvider( analyzerProvider, new IncrementalAnalyzerProviderMetadata( - nameof(RemoteTodoCommentIncrementalAnalyzerProvider), + nameof(RemoteTodoCommentsIncrementalAnalyzerProvider), highPriorityForActiveFile: false, workspaceKinds: WorkspaceKind.RemoteWorkspace));