未验证 提交 45f6e9bc 编写于 作者: H Heejae Chang 提交者: GitHub

connected diagnostic service to task status center (#24690)

* connected diagnostic service to task status center

* PR feedback updated some variable name and string

* fixed test break.

task status center and service provider doesn't exist in unit test

* made GetProject and GetDocument to have same behavior on given ProjectId/DocumentId

* addressed PR feedback

* forgot to remove optional

* moved diagnostic progress reporter out of error list and made its own thing

* removed unnecessary service provider

* removed ?. and adjust ordering

* removed comment

* removed debug only info

* address PR feedbacks

* update on VoidResult

* removed blank line

* more feedbacks
上级 89b0ab9c
......@@ -805,10 +805,19 @@ public async Task ProgressReporterTest()
// set up events
bool started = false;
reporter.Started += (o, a) => { started = true; };
bool stopped = false;
reporter.Stopped += (o, a) => { stopped = true; };
reporter.ProgressChanged += (o, s) =>
{
if (s)
{
started = true;
}
else
{
stopped = true;
}
};
var registrationService = workspace.Services.GetService<ISolutionCrawlerRegistrationService>();
registrationService.Register(workspace);
......
......@@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.Threading;
using Microsoft.CodeAnalysis.Common;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.Diagnostics
{
......@@ -11,6 +12,9 @@ internal interface IDiagnosticService
{
/// <summary>
/// Event to get notified as new diagnostics are discovered by IDiagnosticUpdateSource
///
/// Notifications for this event are serialized to preserve order.
/// However, individual event notifications may occur on any thread.
/// </summary>
event EventHandler<DiagnosticsUpdatedArgs> DiagnosticsUpdated;
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.SolutionCrawler
{
......@@ -15,13 +16,13 @@ internal interface ISolutionCrawlerProgressReporter
bool InProgress { get; }
/// <summary>
/// Raised when there is pending work in solution crawler.
/// Raised when solution crawler progress changed
///
/// bool indicates whether progress is started or stopped
///
/// Notifications for this event are serialized to preserve order.
/// However, individual event notifications may occur on any thread.
/// </summary>
event EventHandler Started;
/// <summary>
/// Raised when there is no more pending work in solution crawler.
/// </summary>
event EventHandler Stopped;
event EventHandler<bool> ProgressChanged;
}
}
......@@ -45,29 +45,16 @@ public bool InProgress
}
}
public event EventHandler Started
public event EventHandler<bool> ProgressChanged
{
add
{
_eventMap.AddEventHandler(nameof(Started), value);
_eventMap.AddEventHandler(nameof(ProgressChanged), value);
}
remove
{
_eventMap.RemoveEventHandler(nameof(Started), value);
}
}
public event EventHandler Stopped
{
add
{
_eventMap.AddEventHandler(nameof(Stopped), value);
}
remove
{
_eventMap.RemoveEventHandler(nameof(Stopped), value);
_eventMap.RemoveEventHandler(nameof(ProgressChanged), value);
}
}
......@@ -95,23 +82,23 @@ public Task Stop()
private Task RaiseStarted()
{
return RaiseEvent(nameof(Started));
return RaiseEvent(nameof(ProgressChanged), running: true);
}
private Task RaiseStopped()
{
return RaiseEvent(nameof(Stopped));
return RaiseEvent(nameof(ProgressChanged), running: false);
}
private Task RaiseEvent(string eventName)
private Task RaiseEvent(string eventName, bool running)
{
// this method name doesn't have Async since it should work as async void.
var ev = _eventMap.GetEventHandlers<EventHandler>(eventName);
var ev = _eventMap.GetEventHandlers<EventHandler<bool>>(eventName);
if (ev.HasHandlers)
{
return _eventQueue.ScheduleTask(() =>
{
ev.RaiseEvent(handler => handler(this, EventArgs.Empty));
ev.RaiseEvent(handler => handler(this, running));
});
}
......@@ -128,13 +115,7 @@ private class NullReporter : ISolutionCrawlerProgressReporter
public bool InProgress => false;
public event EventHandler Started
{
add { }
remove { }
}
public event EventHandler Stopped
public event EventHandler<bool> ProgressChanged
{
add { }
remove { }
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.ComponentModel.Composition;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.SolutionCrawler;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.TaskStatusCenter;
using Roslyn.Utilities;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.Diagnostics
{
[Export(typeof(DiagnosticProgressReporter))]
internal sealed class DiagnosticProgressReporter
{
private static readonly TimeSpan s_minimumInterval = TimeSpan.FromMilliseconds(200);
private readonly IVsTaskStatusCenterService _taskCenterService;
private readonly IDiagnosticService _diagnosticService;
private readonly TaskHandlerOptions _options;
// these fields are never accessed concurrently
private TaskCompletionSource<VoidResult> _currentTask;
private object _lastReportedDocumentOrProject;
private DateTimeOffset _lastTimeReported;
// this is only field that is shared between 2 events streams (IDiagnosticService and ISolutionCrawlerProgressReporter)
// and can be called concurrently.
private volatile ITaskHandler _taskHandler;
[ImportingConstructor]
public DiagnosticProgressReporter(
SVsServiceProvider serviceProvider,
IDiagnosticService diagnosticService,
VisualStudioWorkspace workspace)
{
_lastTimeReported = DateTimeOffset.UtcNow;
_taskCenterService = (IVsTaskStatusCenterService)serviceProvider.GetService(typeof(SVsTaskStatusCenterService));
_diagnosticService = diagnosticService;
var crawlerService = workspace.Services.GetService<ISolutionCrawlerService>();
var reporter = crawlerService.GetProgressReporter(workspace);
Started(reporter.InProgress);
// no event unsubscription since it will remain alive until VS shutdown
reporter.ProgressChanged += OnSolutionCrawlerProgressChanged;
_diagnosticService.DiagnosticsUpdated += OnDiagnosticsUpdated;
_options = new TaskHandlerOptions()
{
Title = ServicesVSResources.Live_code_analysis,
ActionsAfterCompletion = CompletionActions.None
};
}
private void OnDiagnosticsUpdated(object sender, DiagnosticsUpdatedArgs e)
{
// there is no concurrent call to this method since IDiagnosticService will serialize all
// events to preserve event ordering
var solution = e.Solution;
if (solution == null)
{
return;
}
// we ignore report for same document/project as last time
// even if they are from different analyzers
// since, for the progress report, they all show up same
var documentOrProject = (object)e.DocumentId ?? e.ProjectId;
if (_lastReportedDocumentOrProject == documentOrProject)
{
return;
}
var current = DateTimeOffset.UtcNow;
if (current - _lastTimeReported < s_minimumInterval)
{
// make sure we are not flooding UI.
// this is just presentation, fine to not updating UI especially since
// at the end, this notification will go away automatically
return;
}
// only update when we actually change message
_lastReportedDocumentOrProject = documentOrProject;
_lastTimeReported = current;
var document = solution.GetDocument(e.DocumentId);
if (document != null)
{
ChangeProgress(string.Format(ServicesVSResources.Analyzing_0, document.Name ?? document.FilePath ?? "..."));
return;
}
var project = solution.GetProject(e.ProjectId);
if (project != null)
{
ChangeProgress(string.Format(ServicesVSResources.Analyzing_0, project.Name ?? project.FilePath ?? "..."));
return;
}
}
private void OnSolutionCrawlerProgressChanged(object sender, bool running)
{
// there is no concurrent call to this method since ISolutionCrawlerProgressReporter will serialize all
// events to preserve event ordering
Started(running);
}
private void Started(bool running)
{
if (running)
{
// if there is any pending one. make sure it is finished.
_currentTask?.TrySetResult(default);
var taskHandler = _taskCenterService.PreRegister(_options, data: default);
_currentTask = new TaskCompletionSource<VoidResult>();
taskHandler.RegisterTask(_currentTask.Task);
var data = new TaskProgressData
{
ProgressText = null,
CanBeCanceled = false,
PercentComplete = null,
};
// report initial progress
taskHandler.Progress.Report(data);
// set handler
_taskHandler = taskHandler;
}
else
{
// stop progress
_currentTask?.TrySetResult(default);
_currentTask = null;
_taskHandler = null;
}
}
private void ChangeProgress(string message)
{
var data = new TaskProgressData
{
ProgressText = message,
CanBeCanceled = false,
PercentComplete = null,
};
_taskHandler?.Progress.Report(data);
}
}
}
......@@ -40,25 +40,20 @@ private void ConnectToSolutionCrawlerService(Workspace workspace)
}
var reporter = crawlerService.GetProgressReporter(workspace);
reporter.ProgressChanged += OnSolutionCrawlerProgressChanged;
// set initial value
IsStable = !reporter.InProgress;
ChangeStableState(stable: IsStable);
reporter.Started += OnSolutionCrawlerStarted;
reporter.Stopped += OnSolutionCrawlerStopped;
SolutionCrawlerProgressChanged(reporter.InProgress);
}
private void OnSolutionCrawlerStarted(object sender, EventArgs e)
private void OnSolutionCrawlerProgressChanged(object sender, bool running)
{
IsStable = false;
ChangeStableState(IsStable);
SolutionCrawlerProgressChanged(running);
}
private void OnSolutionCrawlerStopped(object sender, EventArgs e)
private void SolutionCrawlerProgressChanged(bool running)
{
IsStable = true;
IsStable = !running;
ChangeStableState(IsStable);
}
}
......
......@@ -20,24 +20,17 @@ internal class MiscellaneousDiagnosticListTable : VisualStudioBaseDiagnosticList
private readonly LiveTableDataSource _source;
[ImportingConstructor]
public MiscellaneousDiagnosticListTable(
SVsServiceProvider serviceProvider, MiscellaneousFilesWorkspace workspace, IDiagnosticService diagnosticService, ITableManagerProvider provider) :
this(serviceProvider, (Workspace)workspace, diagnosticService, provider)
public MiscellaneousDiagnosticListTable(MiscellaneousFilesWorkspace workspace, IDiagnosticService diagnosticService, ITableManagerProvider provider) :
this((Workspace)workspace, diagnosticService, provider)
{
ConnectWorkspaceEvents();
}
/// this is for test only
internal MiscellaneousDiagnosticListTable(Workspace workspace, IDiagnosticService diagnosticService, ITableManagerProvider provider) :
this(null, workspace, diagnosticService, provider)
base(workspace, diagnosticService, provider)
{
}
private MiscellaneousDiagnosticListTable(
SVsServiceProvider serviceProvider, Workspace workspace, IDiagnosticService diagnosticService, ITableManagerProvider provider) :
base(serviceProvider, workspace, diagnosticService, provider)
{
_source = new LiveTableDataSource(serviceProvider, workspace, diagnosticService, IdentifierString);
_source = new LiveTableDataSource(workspace, diagnosticService, IdentifierString);
AddInitialTableSource(workspace.CurrentSolution, _source);
}
......
......@@ -28,23 +28,20 @@ protected class LiveTableDataSource : AbstractRoslynTableDataSource<DiagnosticDa
{
private readonly string _identifier;
private readonly IDiagnosticService _diagnosticService;
private readonly IServiceProvider _serviceProvider;
private readonly Workspace _workspace;
private readonly OpenDocumentTracker<DiagnosticData> _tracker;
public LiveTableDataSource(IServiceProvider serviceProvider, Workspace workspace, IDiagnosticService diagnosticService, string identifier) :
public LiveTableDataSource(Workspace workspace, IDiagnosticService diagnosticService, string identifier) :
base(workspace)
{
_workspace = workspace;
_serviceProvider = serviceProvider;
_identifier = identifier;
_tracker = new OpenDocumentTracker<DiagnosticData>(_workspace);
_diagnosticService = diagnosticService;
_diagnosticService.DiagnosticsUpdated += OnDiagnosticsUpdated;
PopulateInitialData(workspace, diagnosticService);
ConnectToDiagnosticService(workspace, diagnosticService);
}
public override string DisplayName => ServicesVSResources.CSharp_VB_Diagnostics_Table_Data_Source;
......@@ -175,6 +172,19 @@ public override AbstractTableEntriesSource<DiagnosticData> CreateTableEntriesSou
return new TableEntriesSource(this, item.Workspace, item.ProjectId, item.DocumentId, item.Id);
}
private void ConnectToDiagnosticService(Workspace workspace, IDiagnosticService diagnosticService)
{
if (diagnosticService == null)
{
// it can be null in unit test
return;
}
_diagnosticService.DiagnosticsUpdated += OnDiagnosticsUpdated;
PopulateInitialData(workspace, diagnosticService);
}
private static bool ShouldInclude(DiagnosticData diagnostic)
{
if (diagnostic == null)
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.VisualStudio.LanguageServices.Implementation.Utilities;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Shell.TableControl;
using Microsoft.VisualStudio.Shell.TableManager;
......@@ -32,8 +30,7 @@ internal abstract partial class VisualStudioBaseDiagnosticListTable : AbstractTa
SuppressionStateColumnDefinition.ColumnName
};
protected VisualStudioBaseDiagnosticListTable(
SVsServiceProvider serviceProvider, Microsoft.CodeAnalysis.Workspace workspace, IDiagnosticService diagnosticService, ITableManagerProvider provider) :
protected VisualStudioBaseDiagnosticListTable(Workspace workspace, IDiagnosticService diagnosticService, ITableManagerProvider provider) :
base(workspace, provider, StandardTables.ErrorsTable)
{
}
......
......@@ -37,6 +37,7 @@ private void ConnectToBuildUpdateSource(ExternalErrorDiagnosticUpdateSource erro
{
if (errorSource == null)
{
// it can be null in unit test
return;
}
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.ComponentModel;
using System.ComponentModel.Composition;
using System.Linq;
using System.Runtime.CompilerServices;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.Options;
using Microsoft.Internal.VisualStudio.Shell;
using Microsoft.VisualStudio.LanguageServices.Implementation.TaskList;
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Shell.TableManager;
using Roslyn.Utilities;
using Microsoft.VisualStudio.TaskStatusCenter;
namespace Microsoft.VisualStudio.LanguageServices.Implementation.TableDataSource
{
......@@ -29,8 +24,6 @@ internal partial class VisualStudioDiagnosticListTable : VisualStudioBaseDiagnos
private readonly LiveTableDataSource _liveTableSource;
private readonly BuildTableDataSource _buildTableSource;
private const string TypeScriptLanguageName = "TypeScript";
[ImportingConstructor]
public VisualStudioDiagnosticListTable(
SVsServiceProvider serviceProvider,
......@@ -38,7 +31,7 @@ internal partial class VisualStudioDiagnosticListTable : VisualStudioBaseDiagnos
IDiagnosticService diagnosticService,
ExternalErrorDiagnosticUpdateSource errorSource,
ITableManagerProvider provider) :
this(serviceProvider, (Workspace)workspace, diagnosticService, errorSource, provider)
this(workspace, diagnosticService, errorSource, provider)
{
ConnectWorkspaceEvents();
......@@ -66,27 +59,26 @@ private ITableDataSource GetCurrentDataSource()
/// this is for test only
internal VisualStudioDiagnosticListTable(Workspace workspace, IDiagnosticService diagnosticService, ITableManagerProvider provider) :
this(null, workspace, diagnosticService, null, provider)
this(workspace, diagnosticService, errorSource: null, provider)
{
AddInitialTableSource(workspace.CurrentSolution, _liveTableSource);
}
/// this is for test only
internal VisualStudioDiagnosticListTable(Workspace workspace, IDiagnosticService diagnosticService, ExternalErrorDiagnosticUpdateSource errorSource, ITableManagerProvider provider) :
this(null, workspace, diagnosticService, errorSource, provider)
internal VisualStudioDiagnosticListTable(Workspace workspace, ExternalErrorDiagnosticUpdateSource errorSource, ITableManagerProvider provider) :
this(workspace, diagnosticService: null, errorSource, provider)
{
AddInitialTableSource(workspace.CurrentSolution, _buildTableSource);
}
private VisualStudioDiagnosticListTable(
SVsServiceProvider serviceProvider,
Workspace workspace,
IDiagnosticService diagnosticService,
ExternalErrorDiagnosticUpdateSource errorSource,
ITableManagerProvider provider) :
base(serviceProvider, workspace, diagnosticService, provider)
base(workspace, diagnosticService, provider)
{
_liveTableSource = new LiveTableDataSource(serviceProvider, workspace, diagnosticService, IdentifierString);
_liveTableSource = new LiveTableDataSource(workspace, diagnosticService, IdentifierString);
_buildTableSource = new BuildTableDataSource(workspace, errorSource);
}
......
......@@ -26,6 +26,7 @@
using Microsoft.VisualStudio.Shell;
using Microsoft.VisualStudio.Shell.Interop;
using Task = System.Threading.Tasks.Task;
using Microsoft.VisualStudio.LanguageServices.Implementation.Diagnostics;
namespace Microsoft.VisualStudio.LanguageServices.Setup
{
......@@ -94,6 +95,7 @@ protected override void LoadComponentsInUIContext()
{
// we need to load it as early as possible since we can have errors from
// package from each language very early
this.ComponentModel.GetService<DiagnosticProgressReporter>();
this.ComponentModel.GetService<VisualStudioDiagnosticListTable>();
this.ComponentModel.GetService<VisualStudioTodoListTable>();
this.ComponentModel.GetService<VisualStudioDiagnosticListTableCommandHandler>().Initialize(this);
......@@ -108,7 +110,7 @@ protected override void LoadComponentsInUIContext()
this.ComponentModel.GetService<MiscellaneousFilesWorkspace>();
LoadAnalyzerNodeComponents();
Task.Run(() => LoadComponentsBackgroundAsync());
}
......
......@@ -262,6 +262,15 @@ internal class ServicesVSResources {
}
}
/// <summary>
/// Looks up a localized string similar to Analyzing &apos;{0}&apos;.
/// </summary>
internal static string Analyzing_0 {
get {
return ResourceManager.GetString("Analyzing_0", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Applying remove suppressions fix....
/// </summary>
......@@ -1226,6 +1235,15 @@ internal class ServicesVSResources {
}
}
/// <summary>
/// Looks up a localized string similar to Live code analysis.
/// </summary>
internal static string Live_code_analysis {
get {
return ResourceManager.GetString("Live_code_analysis", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Location:.
/// </summary>
......
......@@ -1016,4 +1016,10 @@ I agree to all of the foregoing:</value>
<data name="Code_style_header_use_editor_config" xml:space="preserve">
<value>The settings configured here only apply to your machine. To configure these settings to travel with your solution, use .editorconfig files.</value>
</data>
</root>
<data name="Analyzing_0" xml:space="preserve">
<value>Analyzing '{0}'</value>
</data>
<data name="Live_code_analysis" xml:space="preserve">
<value>Live code analysis</value>
</data>
</root>
\ No newline at end of file
......@@ -1498,6 +1498,16 @@ Souhlasím se všemi výše uvedenými podmínkami:</target>
<target state="new">The settings configured here only apply to your machine. To configure these settings to travel with your solution, use .editorconfig files.</target>
<note />
</trans-unit>
<trans-unit id="Live_code_analysis">
<source>Live code analysis</source>
<target state="new">Live code analysis</target>
<note />
</trans-unit>
<trans-unit id="Analyzing_0">
<source>Analyzing '{0}'</source>
<target state="new">Analyzing '{0}'</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -1498,6 +1498,16 @@ Ich stimme allen vorstehenden Bedingungen zu:</target>
<target state="new">The settings configured here only apply to your machine. To configure these settings to travel with your solution, use .editorconfig files.</target>
<note />
</trans-unit>
<trans-unit id="Live_code_analysis">
<source>Live code analysis</source>
<target state="new">Live code analysis</target>
<note />
</trans-unit>
<trans-unit id="Analyzing_0">
<source>Analyzing '{0}'</source>
<target state="new">Analyzing '{0}'</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -1498,6 +1498,16 @@ Estoy de acuerdo con todo lo anterior:</target>
<target state="new">The settings configured here only apply to your machine. To configure these settings to travel with your solution, use .editorconfig files.</target>
<note />
</trans-unit>
<trans-unit id="Live_code_analysis">
<source>Live code analysis</source>
<target state="new">Live code analysis</target>
<note />
</trans-unit>
<trans-unit id="Analyzing_0">
<source>Analyzing '{0}'</source>
<target state="new">Analyzing '{0}'</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -1498,6 +1498,16 @@ Je suis d'accord avec tout ce qui précède :</target>
<target state="new">The settings configured here only apply to your machine. To configure these settings to travel with your solution, use .editorconfig files.</target>
<note />
</trans-unit>
<trans-unit id="Live_code_analysis">
<source>Live code analysis</source>
<target state="new">Live code analysis</target>
<note />
</trans-unit>
<trans-unit id="Analyzing_0">
<source>Analyzing '{0}'</source>
<target state="new">Analyzing '{0}'</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -1498,6 +1498,16 @@ L'utente accetta le condizioni sopra riportate:</target>
<target state="new">The settings configured here only apply to your machine. To configure these settings to travel with your solution, use .editorconfig files.</target>
<note />
</trans-unit>
<trans-unit id="Live_code_analysis">
<source>Live code analysis</source>
<target state="new">Live code analysis</target>
<note />
</trans-unit>
<trans-unit id="Analyzing_0">
<source>Analyzing '{0}'</source>
<target state="new">Analyzing '{0}'</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -1498,6 +1498,16 @@ I agree to all of the foregoing:</source>
<target state="new">The settings configured here only apply to your machine. To configure these settings to travel with your solution, use .editorconfig files.</target>
<note />
</trans-unit>
<trans-unit id="Live_code_analysis">
<source>Live code analysis</source>
<target state="new">Live code analysis</target>
<note />
</trans-unit>
<trans-unit id="Analyzing_0">
<source>Analyzing '{0}'</source>
<target state="new">Analyzing '{0}'</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -1498,6 +1498,16 @@ I agree to all of the foregoing:</source>
<target state="new">The settings configured here only apply to your machine. To configure these settings to travel with your solution, use .editorconfig files.</target>
<note />
</trans-unit>
<trans-unit id="Live_code_analysis">
<source>Live code analysis</source>
<target state="new">Live code analysis</target>
<note />
</trans-unit>
<trans-unit id="Analyzing_0">
<source>Analyzing '{0}'</source>
<target state="new">Analyzing '{0}'</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -1498,6 +1498,16 @@ Wyrażam zgodę na wszystkie następujące postanowienia:</target>
<target state="new">The settings configured here only apply to your machine. To configure these settings to travel with your solution, use .editorconfig files.</target>
<note />
</trans-unit>
<trans-unit id="Live_code_analysis">
<source>Live code analysis</source>
<target state="new">Live code analysis</target>
<note />
</trans-unit>
<trans-unit id="Analyzing_0">
<source>Analyzing '{0}'</source>
<target state="new">Analyzing '{0}'</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -1498,6 +1498,16 @@ Eu concordo com todo o conteúdo supracitado:</target>
<target state="new">The settings configured here only apply to your machine. To configure these settings to travel with your solution, use .editorconfig files.</target>
<note />
</trans-unit>
<trans-unit id="Live_code_analysis">
<source>Live code analysis</source>
<target state="new">Live code analysis</target>
<note />
</trans-unit>
<trans-unit id="Analyzing_0">
<source>Analyzing '{0}'</source>
<target state="new">Analyzing '{0}'</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -1498,6 +1498,16 @@ I agree to all of the foregoing:</source>
<target state="new">The settings configured here only apply to your machine. To configure these settings to travel with your solution, use .editorconfig files.</target>
<note />
</trans-unit>
<trans-unit id="Live_code_analysis">
<source>Live code analysis</source>
<target state="new">Live code analysis</target>
<note />
</trans-unit>
<trans-unit id="Analyzing_0">
<source>Analyzing '{0}'</source>
<target state="new">Analyzing '{0}'</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -1498,6 +1498,16 @@ Aşağıdakilerin tümünü onaylıyorum:</target>
<target state="new">The settings configured here only apply to your machine. To configure these settings to travel with your solution, use .editorconfig files.</target>
<note />
</trans-unit>
<trans-unit id="Live_code_analysis">
<source>Live code analysis</source>
<target state="new">Live code analysis</target>
<note />
</trans-unit>
<trans-unit id="Analyzing_0">
<source>Analyzing '{0}'</source>
<target state="new">Analyzing '{0}'</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -1498,6 +1498,16 @@ I agree to all of the foregoing:</source>
<target state="new">The settings configured here only apply to your machine. To configure these settings to travel with your solution, use .editorconfig files.</target>
<note />
</trans-unit>
<trans-unit id="Live_code_analysis">
<source>Live code analysis</source>
<target state="new">Live code analysis</target>
<note />
</trans-unit>
<trans-unit id="Analyzing_0">
<source>Analyzing '{0}'</source>
<target state="new">Analyzing '{0}'</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -1498,6 +1498,16 @@ I agree to all of the foregoing:</source>
<target state="new">The settings configured here only apply to your machine. To configure these settings to travel with your solution, use .editorconfig files.</target>
<note />
</trans-unit>
<trans-unit id="Live_code_analysis">
<source>Live code analysis</source>
<target state="new">Live code analysis</target>
<note />
</trans-unit>
<trans-unit id="Analyzing_0">
<source>Analyzing '{0}'</source>
<target state="new">Analyzing '{0}'</target>
<note />
</trans-unit>
</body>
</file>
</xliff>
\ No newline at end of file
......@@ -674,7 +674,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Diagnostics
Dim updateSource = New ExternalErrorDiagnosticUpdateSource(workspace, analyzerService, registration, listener)
Dim tableManagerProvider = New TestTableManagerProvider()
Dim table = New VisualStudioDiagnosticListTable(workspace, service, updateSource, tableManagerProvider)
Dim table = New VisualStudioDiagnosticListTable(workspace, updateSource, tableManagerProvider)
Dim document1 = workspace.CurrentSolution.Projects.First(Function(p) p.Name = "Proj1").Documents.First()
Dim document2 = workspace.CurrentSolution.Projects.First(Function(p) p.Name = "Proj2").Documents.First()
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Roslyn.Utilities
{
/// <summary>
/// Explicitly indicates result is void
/// </summary>
internal struct VoidResult { }
}
......@@ -94,11 +94,7 @@ internal Solution(Workspace workspace, SolutionInfo info)
/// </summary>
public Project GetProject(ProjectId projectId)
{
if (projectId == null)
{
throw new ArgumentNullException(nameof(projectId));
}
// ContainsProject checks projectId being null
if (this.ContainsProject(projectId))
{
return ImmutableHashMapExtensions.GetOrAdd(ref _projectIdToProjectMap, projectId, s_createProjectFunction, this);
......@@ -165,7 +161,8 @@ public DocumentId GetDocumentId(SyntaxTree syntaxTree, ProjectId projectId)
/// </summary>
public Document GetDocument(DocumentId documentId)
{
if (documentId != null && this.ContainsDocument(documentId))
// ContainsDocument checks documentId being null
if (this.ContainsDocument(documentId))
{
return this.GetProject(documentId.ProjectId).GetDocument(documentId);
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册