diff --git a/src/CFamily.UnitTests/Subprocess/MessageHandlerTests.cs b/src/CFamily.UnitTests/Subprocess/MessageHandlerTests.cs index 0bf4a6629e..a4c7fa3aa7 100644 --- a/src/CFamily.UnitTests/Subprocess/MessageHandlerTests.cs +++ b/src/CFamily.UnitTests/Subprocess/MessageHandlerTests.cs @@ -128,7 +128,7 @@ public void HandleMessage_IssuesForAnalyzedFileAreNotIgnored(string fileNameInMe context.IssueConverter.Invocations.Count.Should().Be(1); context.IssueConsumer.Invocations.Count.Should().Be(1); - context.IssueConsumer.Verify(x => x.Accept(analyzedFile, It.IsAny>())); + context.IssueConsumer.Verify(x => x.Set(analyzedFile, It.IsAny>())); } [TestMethod] diff --git a/src/CFamily/Subprocess/MessageHandler.cs b/src/CFamily/Subprocess/MessageHandler.cs index 0f49e6415c..306769203b 100644 --- a/src/CFamily/Subprocess/MessageHandler.cs +++ b/src/CFamily/Subprocess/MessageHandler.cs @@ -109,7 +109,7 @@ public void HandleMessage(Message message) // Rules that start with internal shouldn't be treated as issues. // Some of them should be handled like `internal.fileDependency`. See: https://github.com/SonarSource/sonarlint-visualstudio/issues/2611 - // Others should can simply ignored like `internal.z3RefutationRate`, which is used to log in the scanner how many issues are rejected by the Z3 solver + // Others should can simply ignored like `internal.z3RefutationRate`, which is used to log in the scanner how many issues are rejected by the Z3 solver case string s when s.StartsWith("internal."): break; @@ -137,11 +137,12 @@ private void HandleAnalysisIssue(Message message) IssueCount++; var issue = issueConverter.Convert(message, request.Context.CFamilyLanguage, request.Context.RulesConfiguration); - // Note: the file being analyzed might have been closed by the time the analysis results are + // Note: the file being analyzed might have been closed by the time the analysis results are // returned. This doesn't cause a crash; all active taggers will have been detached from the // TextBufferIssueTracker when the file was closed, but the TextBufferIssueTracker will // still exist and handle the call. - issueConsumer.Accept(request.Context.File, new[] { issue }); + // todo https://sonarsource.atlassian.net/browse/SLVS-1661 + issueConsumer.Set(request.Context.File, new[] { issue }); } internal /* for testing */ static bool IsIssueForActiveRule(Message message, ICFamilyRulesConfig rulesConfiguration) diff --git a/src/Core.UnitTests/Analysis/AnalysisServiceTests.cs b/src/Core.UnitTests/Analysis/AnalysisServiceTests.cs index 56096b6f9b..d543a6cd0c 100644 --- a/src/Core.UnitTests/Analysis/AnalysisServiceTests.cs +++ b/src/Core.UnitTests/Analysis/AnalysisServiceTests.cs @@ -40,7 +40,7 @@ public void MefCtor_CheckIsSingleton() { MefTestHelpers.CheckIsSingletonMefComponent(); } - + [TestMethod] public void ScheduleAnalysis_AnalysisScheduler_CachesIssueConsumer_And_RunsAnalyzerController() { @@ -54,7 +54,7 @@ public void ScheduleAnalysis_AnalysisScheduler_CachesIssueConsumer_And_RunsAnaly var testSubject = CreateTestSubject(analyzerController, issueConsumerStorage, scheduler); testSubject.ScheduleAnalysis("file/path", analysisId, detectedLanguages, issueConsumer, analyzerOptions); - + Received.InOrder(() => { scheduler.Schedule("file/path", Arg.Any>(), Arg.Any()); @@ -62,7 +62,7 @@ public void ScheduleAnalysis_AnalysisScheduler_CachesIssueConsumer_And_RunsAnaly analyzerController.ExecuteAnalysis("file/path", analysisId, detectedLanguages, issueConsumer, analyzerOptions, Arg.Any()); }); } - + [TestMethod] public void ScheduleAnalysis_JobCancelledBeforeStarting_DoesNotExecute() { @@ -72,7 +72,7 @@ public void ScheduleAnalysis_JobCancelledBeforeStarting_DoesNotExecute() var testSubject = CreateTestSubject(analyzerController, issueConsumerStorage, scheduler); testSubject.ScheduleAnalysis("file/path", default, default, default, default); - + scheduler.Received().Schedule("file/path", Arg.Any>(), Arg.Any()); issueConsumerStorage.DidNotReceiveWithAnyArgs().Set(default, default, default); analyzerController.DidNotReceiveWithAnyArgs().ExecuteAnalysis(default, default, default, default, default, default); @@ -90,26 +90,26 @@ public void ScheduleAnalysis_ProvidesCorrectTimeout(int envSettingsResponse, int Environment.SetEnvironmentVariable(EnvironmentSettings.AnalysisTimeoutEnvVar, envSettingsResponse.ToString()); var scheduler = Substitute.For(); var testSubject = CreateTestSubject(scheduler: scheduler); - + testSubject.ScheduleAnalysis("file/path", default, default, default, default); - + scheduler.Received().Schedule("file/path", Arg.Any>(), expectedTimeout); } finally { Environment.SetEnvironmentVariable(EnvironmentSettings.AnalysisTimeoutEnvVar, null); } - + } - + [TestMethod] public void ScheduleAnalysis_NoEnvironmentSettings_DefaultTimeout() { var scheduler = Substitute.For(); var testSubject = CreateTestSubject(scheduler: scheduler); - + testSubject.ScheduleAnalysis("file/path", default, default, default, default); - + scheduler.Received().Schedule("file/path", Arg.Any>(), AnalysisService.DefaultAnalysisTimeoutMs); } @@ -118,12 +118,12 @@ public void PublishIssues_NoConsumerInStorage_DoesNothing() { var issueConsumerStorage = CreateIssueConsumerStorageWithStoredItem(Guid.NewGuid(), null, false); var testSubject = CreateTestSubject(issueConsumerStorage:issueConsumerStorage); - + var act = () => testSubject.PublishIssues("file/path", Guid.NewGuid(), Substitute.For>()); - + act.Should().NotThrow(); } - + [TestMethod] public void PublishIssues_DifferentAnalysisId_DoesNothing() { @@ -131,12 +131,12 @@ public void PublishIssues_DifferentAnalysisId_DoesNothing() var issueConsumer = Substitute.For(); var issueConsumerStorage = CreateIssueConsumerStorageWithStoredItem(Guid.NewGuid(), issueConsumer, true); var testSubject = CreateTestSubject(issueConsumerStorage:issueConsumerStorage); - + testSubject.PublishIssues("file/path", analysisId, Substitute.For>()); - - issueConsumer.DidNotReceiveWithAnyArgs().Accept(default, default); + + issueConsumer.DidNotReceiveWithAnyArgs().Set(default, default); } - + [TestMethod] public void PublishIssues_MatchingConsumer_PublishesIssues() { @@ -147,10 +147,10 @@ public void PublishIssues_MatchingConsumer_PublishesIssues() var analysisIssues = Substitute.For>(); testSubject.PublishIssues("file/path", analysisId, analysisIssues); - - issueConsumer.Received().Accept("file/path", analysisIssues); + + issueConsumer.Received().Set("file/path", analysisIssues); } - + [DataRow(true)] [DataRow(false)] [DataTestMethod] @@ -170,22 +170,22 @@ public void CancelForFile_JobCancelledBeforeStarting_DoesNotExecute() var issueConsumerStorage = Substitute.For(); var scheduler = CreateDefaultScheduler(true); var testSubject = CreateTestSubject(issueConsumerStorage: issueConsumerStorage, scheduler: scheduler); - + testSubject.CancelForFile("file/path"); - + scheduler.Received().Schedule("file/path", Arg.Any>(), -1); issueConsumerStorage.DidNotReceiveWithAnyArgs().Remove(default); } - + [TestMethod] public void CancelForFile_RunsConsumerStorageClearAsScheduledJob() { var issueConsumerStorage = Substitute.For(); var scheduler = CreateDefaultScheduler(); var testSubject = CreateTestSubject(issueConsumerStorage: issueConsumerStorage, scheduler: scheduler); - + testSubject.CancelForFile("file/path"); - + Received.InOrder(() => { scheduler.Schedule("file/path", Arg.Any>(), -1); @@ -202,7 +202,7 @@ private static IAnalysisService CreateTestSubject(IAnalyzerController analyzerCo scheduler ??= Substitute.For(); return new AnalysisService(analyzerController, issueConsumerStorage, scheduler); } - + private static IIssueConsumerStorage CreateIssueConsumerStorageWithStoredItem(Guid analysisId, IIssueConsumer issueConsumer, bool result) { var issueConsumerStorage = Substitute.For(); @@ -214,7 +214,7 @@ private static IIssueConsumerStorage CreateIssueConsumerStorageWithStoredItem(Gu }); return issueConsumerStorage; } - + private static IScheduler CreateDefaultScheduler(bool createCancelled = false) { var cancellationTokenSource = new CancellationTokenSource(); diff --git a/src/Core/Analysis/AnalysisService.cs b/src/Core/Analysis/AnalysisService.cs index bcb54721a9..07b70e93da 100644 --- a/src/Core/Analysis/AnalysisService.cs +++ b/src/Core/Analysis/AnalysisService.cs @@ -50,7 +50,7 @@ public void PublishIssues(string filePath, Guid analysisId, IEnumerable public interface IIssueConsumer { - void Accept(string path, IEnumerable issues); + void Set(string path, IEnumerable issues); } diff --git a/src/Integration.Vsix.UnitTests/Analysis/IssueConsumerFactoryTests.cs b/src/Integration.Vsix.UnitTests/Analysis/IssueConsumerFactoryTests.cs index 77fbd40d4f..d3a12d3d04 100644 --- a/src/Integration.Vsix.UnitTests/Analysis/IssueConsumerFactoryTests.cs +++ b/src/Integration.Vsix.UnitTests/Analysis/IssueConsumerFactoryTests.cs @@ -58,7 +58,7 @@ public void Create_InitializedIssueConsumerReturned() /* The empty issues list is passed as an argument here because it's impossible to verify the actual pipeline due to the fact that mocking ITextSnapshot in a way that then can be used by a SnapshotSpan takes a lot of effort */ - consumer.Accept("analysisfile.txt", []); + consumer.Set("analysisfile.txt", []); publishedIssuesSnapshot.Should().NotBeNull(); publishedIssuesSnapshot.AnalyzedFilePath.Should().Be("updatedfile.txt"); // filename should be updted by this point diff --git a/src/Integration.Vsix.UnitTests/ReferencesTests.cs b/src/Integration.Vsix.UnitTests/ReferencesTests.cs index 498957f87f..336d243fe3 100644 --- a/src/Integration.Vsix.UnitTests/ReferencesTests.cs +++ b/src/Integration.Vsix.UnitTests/ReferencesTests.cs @@ -32,7 +32,7 @@ public class ReferencesTests public void MicrosoftVisualStudioVCProjectEngine_EnsureCorrectVersion() { var codeAnalysisAssemblyVersion = AssemblyHelper.GetVersionOfReferencedAssembly( - typeof(SonarLint.VisualStudio.Integration.Vsix.AccumulatingIssueConsumer), // any type in the VSIX assembly will do + typeof(SonarLint.VisualStudio.Integration.Vsix.IssueConsumer), // any type in the VSIX assembly will do "Microsoft.VisualStudio.VCProjectEngine"); AssertIsCorrectMajorVersion(codeAnalysisAssemblyVersion.Major); diff --git a/src/Integration.Vsix.UnitTests/SonarLintTagger/AccumulatingIssueConsumerTests.cs b/src/Integration.Vsix.UnitTests/SonarLintTagger/IssueConsumerTests.cs similarity index 82% rename from src/Integration.Vsix.UnitTests/SonarLintTagger/AccumulatingIssueConsumerTests.cs rename to src/Integration.Vsix.UnitTests/SonarLintTagger/IssueConsumerTests.cs index cbcc4ae160..268003c867 100644 --- a/src/Integration.Vsix.UnitTests/SonarLintTagger/AccumulatingIssueConsumerTests.cs +++ b/src/Integration.Vsix.UnitTests/SonarLintTagger/IssueConsumerTests.cs @@ -18,22 +18,15 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using System; -using System.Collections.Generic; -using System.Linq; -using FluentAssertions; -using Microsoft.VisualStudio.TestTools.UnitTesting; using Microsoft.VisualStudio.Text; -using Moq; using SonarLint.VisualStudio.Core.Analysis; using SonarLint.VisualStudio.Integration.Vsix; using SonarLint.VisualStudio.IssueVisualization.Models; -using SonarLint.VisualStudio.TestInfrastructure; namespace SonarLint.VisualStudio.Integration.UnitTests.SonarLintTagger { [TestClass] - public class AccumulatingIssueConsumerTests + public class IssueConsumerTests { private static readonly IAnalysisIssue ValidIssue = CreateIssue(startLine: 1, endLine: 1); private static readonly ITextSnapshot ValidTextSnapshot = CreateSnapshot(lineCount: 10); @@ -44,18 +37,18 @@ public class AccumulatingIssueConsumerTests [TestMethod] public void Ctor_InvalidArgs_Throws() { - AccumulatingIssueConsumer.OnIssuesChanged validCallback = _ => { }; + IssueConsumer.OnIssuesChanged validCallback = _ => { }; - Action act = () => new AccumulatingIssueConsumer(null, ValidFilePath, validCallback, ValidConverter); + Action act = () => new IssueConsumer(null, ValidFilePath, validCallback, ValidConverter); act.Should().ThrowExactly().And.ParamName.Should().Be("analysisSnapshot"); - act = () => new AccumulatingIssueConsumer(ValidTextSnapshot, null, validCallback, ValidConverter); + act = () => new IssueConsumer(ValidTextSnapshot, null, validCallback, ValidConverter); act.Should().ThrowExactly().And.ParamName.Should().Be("analysisFilePath"); - act = () => new AccumulatingIssueConsumer(ValidTextSnapshot, ValidFilePath, null, ValidConverter); + act = () => new IssueConsumer(ValidTextSnapshot, ValidFilePath, null, ValidConverter); act.Should().ThrowExactly().And.ParamName.Should().Be("onIssuesChangedCallback"); - act = () => new AccumulatingIssueConsumer(ValidTextSnapshot, ValidFilePath, validCallback, null); + act = () => new IssueConsumer(ValidTextSnapshot, ValidFilePath, validCallback, null); act.Should().ThrowExactly().And.ParamName.Should().Be("issueToIssueVisualizationConverter"); } @@ -65,11 +58,11 @@ public void Accept_WrongFile_CallbackIsNotCalled() var callbackSpy = new OnIssuesChangedCallbackSpy(); var issues = new IAnalysisIssue[] { ValidIssue }; - var testSubject = new AccumulatingIssueConsumer(ValidTextSnapshot, "c:\\file1.txt", callbackSpy.Callback, ValidConverter); + var testSubject = new IssueConsumer(ValidTextSnapshot, "c:\\file1.txt", callbackSpy.Callback, ValidConverter); using (new AssertIgnoreScope()) { - testSubject.Accept("wrong file", issues); + testSubject.Set("wrong file", issues); } callbackSpy.CallCount.Should().Be(0); @@ -95,11 +88,11 @@ public void Accept_IssuesNotInSnapshotAreIgnored_CallbackIsCalledWithExpectedIss var callbackSpy = new OnIssuesChangedCallbackSpy(); var converter = CreatePassthroughConverter(); - var testSubject = new AccumulatingIssueConsumer(snapshot, ValidFilePath, callbackSpy.Callback, converter); + var testSubject = new IssueConsumer(snapshot, ValidFilePath, callbackSpy.Callback, converter); using (new AssertIgnoreScope()) { - testSubject.Accept(ValidFilePath, issues); + testSubject.Set(ValidFilePath, issues); } callbackSpy.CallCount.Should().Be(1); @@ -122,16 +115,16 @@ public void Accept_HasFileLevelIssues_NotIgnored() var callbackSpy = new OnIssuesChangedCallbackSpy(); var converter = CreatePassthroughConverter(); - var testSubject = new AccumulatingIssueConsumer(snapshot, ValidFilePath, callbackSpy.Callback, converter); + var testSubject = new IssueConsumer(snapshot, ValidFilePath, callbackSpy.Callback, converter); - testSubject.Accept(ValidFilePath, issues); + testSubject.Set(ValidFilePath, issues); callbackSpy.CallCount.Should().Be(1); callbackSpy.LastSuppliedIssues.Should().BeEquivalentTo(issues); } [TestMethod] - public void Accept_MultipleCallsToAccept_IssuesAreAccumulated() + public void Accept_MultipleCallsToAccept_IssuesAreReplaced() { var callbackSpy = new OnIssuesChangedCallbackSpy(); var firstSetOfIssues = new[] @@ -147,19 +140,19 @@ public void Accept_MultipleCallsToAccept_IssuesAreAccumulated() var snapshot = CreateSnapshot(lineCount: 10); var converter = CreatePassthroughConverter(); - var testSubject = new AccumulatingIssueConsumer(snapshot, ValidFilePath, callbackSpy.Callback, converter); + var testSubject = new IssueConsumer(snapshot, ValidFilePath, callbackSpy.Callback, converter); // 1. First call - testSubject.Accept(ValidFilePath, firstSetOfIssues); + testSubject.Set(ValidFilePath, firstSetOfIssues); callbackSpy.CallCount.Should().Be(1); callbackSpy.LastSuppliedIssues.Should().BeEquivalentTo(firstSetOfIssues); // 2. Second call - testSubject.Accept(ValidFilePath, secondSetOfIssues); + testSubject.Set(ValidFilePath, secondSetOfIssues); callbackSpy.CallCount.Should().Be(2); - callbackSpy.LastSuppliedIssues.Should().BeEquivalentTo(firstSetOfIssues.Union(secondSetOfIssues)); + callbackSpy.LastSuppliedIssues.Should().BeEquivalentTo(secondSetOfIssues); } private class OnIssuesChangedCallbackSpy @@ -217,7 +210,7 @@ private static IAnalysisIssueVisualizationConverter CreatePassthroughConverter() mockIssueConverter .Setup(x => x.Convert(It.IsAny(), It.IsAny())) .Returns((issue, snapshot) => CreateIssueViz(issue, new SnapshotSpan())); - + return mockIssueConverter.Object; IAnalysisIssueVisualization CreateIssueViz(IAnalysisIssue issue, SnapshotSpan snapshotSpan) diff --git a/src/Integration.Vsix.UnitTests/SonarLintTagger/VsAwareAnalysisServiceTests.cs b/src/Integration.Vsix.UnitTests/SonarLintTagger/VsAwareAnalysisServiceTests.cs index 61eff57691..472ce93daa 100644 --- a/src/Integration.Vsix.UnitTests/SonarLintTagger/VsAwareAnalysisServiceTests.cs +++ b/src/Integration.Vsix.UnitTests/SonarLintTagger/VsAwareAnalysisServiceTests.cs @@ -125,7 +125,7 @@ public void RequestAnalysis_ClearsErrorListAndSchedulesAnalysisOnBackgroundThrea Received.InOrder(() => { threadHandling.RunOnBackgroundThread(Arg.Any>>()); - issueConsumer.Accept(analysisFilePath, []); + issueConsumer.Set(analysisFilePath, []); analysisService.ScheduleAnalysis(analysisFilePath, Arg.Any(), Arg.Any>(), diff --git a/src/Integration.Vsix/Analysis/IssueConsumerFactory.cs b/src/Integration.Vsix/Analysis/IssueConsumerFactory.cs index 86e45cbbd6..7f9b06712c 100644 --- a/src/Integration.Vsix/Analysis/IssueConsumerFactory.cs +++ b/src/Integration.Vsix/Analysis/IssueConsumerFactory.cs @@ -74,7 +74,7 @@ public IIssueConsumer Create(ITextDocument textDocument, SnapshotChangedHandler onSnapshotChanged) { var issueHandler = new IssueHandler(textDocument, projectName, projectGuid, suppressedIssueMatcher, onSnapshotChanged, localHotspotsStore); - var issueConsumer = new AccumulatingIssueConsumer(analysisSnapshot, analysisFilePath, issueHandler.HandleNewIssues, converter); + var issueConsumer = new IssueConsumer(analysisSnapshot, analysisFilePath, issueHandler.HandleNewIssues, converter); return issueConsumer; } diff --git a/src/Integration.Vsix/SonarLintTagger/AccumulatingIssueConsumer.cs b/src/Integration.Vsix/SonarLintTagger/IssueConsumer.cs similarity index 81% rename from src/Integration.Vsix/SonarLintTagger/AccumulatingIssueConsumer.cs rename to src/Integration.Vsix/SonarLintTagger/IssueConsumer.cs index 3259845e70..f7e09675f2 100644 --- a/src/Integration.Vsix/SonarLintTagger/AccumulatingIssueConsumer.cs +++ b/src/Integration.Vsix/SonarLintTagger/IssueConsumer.cs @@ -18,41 +18,37 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; using Microsoft.VisualStudio.Text; using SonarLint.VisualStudio.Core.Analysis; using SonarLint.VisualStudio.IssueVisualization.Models; -/* +/* * Instancing: a new instance of this class should be created for each analysis request. - * + * * The class is initialized with the text snapshot representing the state of the text buffer * at the point the analysis was triggered. - * + * * The job of the class is to: - * 1) map the issue start/end positions supplied by the analyzer to spans in the supplied text snapshot, and - * 2) accumulate the list of issues that have return by the analyzer so far - * - * Each time IIssueConsumer.Accept is called, the new issues will be mapped back to the + * 1) map the issue start/end positions supplied by the analyzer to spans in the supplied text snapshot, and + * 2) replace the previous list of issues + * + * Each time IIssueConsumer.Set is called, the new issues will be mapped back to the * supplied snapshot and decorated with the additional data required for filtering and tagging. * Then, all of the issues that have been received so far will be passed to the OnIssuesChanged delegate. - * + * * However, it's possible that the text buffer could have been edited since the analysis * was triggered. It is the responsibility of the callback to translate the supplied IssueVisualizations * to the current text buffer snapshot, if necessary. - * - * + * + * * Mapping from reported issue line/char positions to the analysis snapshot * ------------------------------------------------------------------------ - * Currently, the JS/CFamily analyzers run against the file on disc, not the content of + * Currently, the JS/CFamily analyzers run against the file on disc, not the content of * the snapshot. We're assuming that analysis is triggered on save so the state of the * text snapshot matches the file on disc which is being analyzed. * We expect always to be able to map back from the reported issue to the snapshot. * However, we code defensively and strip out any issues that can't be mapped. - * + * */ namespace SonarLint.VisualStudio.Integration.Vsix @@ -60,28 +56,25 @@ namespace SonarLint.VisualStudio.Integration.Vsix /// /// Handles processing the issues for a single analysis request /// - internal class AccumulatingIssueConsumer : IIssueConsumer + internal class IssueConsumer : IIssueConsumer { // See bug #1487: this text snapshot should match the content of the file being analysed private readonly ITextSnapshot analysisSnapshot; private readonly IAnalysisIssueVisualizationConverter issueToIssueVisualizationConverter; - private readonly List allIssues; private readonly string analysisFilePath; private readonly OnIssuesChanged onIssuesChanged; public delegate void OnIssuesChanged(IEnumerable issues); - public AccumulatingIssueConsumer(ITextSnapshot analysisSnapshot, string analysisFilePath, OnIssuesChanged onIssuesChangedCallback, IAnalysisIssueVisualizationConverter issueToIssueVisualizationConverter) + public IssueConsumer(ITextSnapshot analysisSnapshot, string analysisFilePath, OnIssuesChanged onIssuesChangedCallback, IAnalysisIssueVisualizationConverter issueToIssueVisualizationConverter) { this.analysisSnapshot = analysisSnapshot ?? throw new ArgumentNullException(nameof(analysisSnapshot)); this.analysisFilePath = analysisFilePath ?? throw new ArgumentNullException(nameof(analysisFilePath)); this.onIssuesChanged = onIssuesChangedCallback ?? throw new ArgumentNullException(nameof(onIssuesChangedCallback)); this.issueToIssueVisualizationConverter = issueToIssueVisualizationConverter ?? throw new ArgumentNullException(nameof(issueToIssueVisualizationConverter)); - - allIssues = new List(); } - public void Accept(string path, IEnumerable issues) + public void Set(string path, IEnumerable issues) { // Callback from the daemon when new results are available if (path != analysisFilePath) @@ -92,14 +85,10 @@ public void Accept(string path, IEnumerable issues) Debug.Assert(issues.All(IsIssueFileLevelOrInAnalysisSnapshot), "Not all reported issues could be mapped to the analysis snapshot"); - var newIssues = issues + onIssuesChanged.Invoke(issues .Where(IsIssueFileLevelOrInAnalysisSnapshot) .Select(x => issueToIssueVisualizationConverter.Convert(x, analysisSnapshot)) - .ToArray(); - - allIssues.AddRange(newIssues); - - onIssuesChanged.Invoke(allIssues); + .ToList()); } /// diff --git a/src/Integration.Vsix/SonarLintTagger/VsAwareAnalysisService.cs b/src/Integration.Vsix/SonarLintTagger/VsAwareAnalysisService.cs index 2eb634d121..7b831d0a06 100644 --- a/src/Integration.Vsix/SonarLintTagger/VsAwareAnalysisService.cs +++ b/src/Integration.Vsix/SonarLintTagger/VsAwareAnalysisService.cs @@ -38,7 +38,7 @@ void RequestAnalysis(ITextDocument document, IAnalyzerOptions options); bool IsAnalysisSupported(IEnumerable detectedLanguages); - + void CancelForFile(string filePath); } @@ -52,7 +52,7 @@ internal class VsAwareAnalysisService : IVsAwareAnalysisService private readonly IAnalysisService analysisService; [ImportingConstructor] - public VsAwareAnalysisService(IVsProjectInfoProvider vsProjectInfoProvider, + public VsAwareAnalysisService(IVsProjectInfoProvider vsProjectInfoProvider, IIssueConsumerFactory issueConsumerFactory, IAnalysisService analysisService, IThreadHandling threadHandling) @@ -76,7 +76,7 @@ public void RequestAnalysis(ITextDocument document, public bool IsAnalysisSupported(IEnumerable detectedLanguages) => analysisService.IsAnalysisSupported(detectedLanguages); - public void CancelForFile(string filePath) => + public void CancelForFile(string filePath) => analysisService.CancelForFile(filePath); private async Task RequestAnalysisAsync(ITextDocument document, @@ -87,7 +87,7 @@ private async Task RequestAnalysisAsync(ITextDocument document, { var (projectName, projectGuid) = await vsProjectInfoProvider.GetDocumentProjectInfoAsync(analysisSnapshot.FilePath); var issueConsumer = issueConsumerFactory.Create(document, analysisSnapshot.FilePath, analysisSnapshot.TextSnapshot, projectName, projectGuid, errorListHandler); - + await ScheduleAnalysisOnBackgroundThreadAsync(analysisSnapshot.FilePath, detectedLanguages, issueConsumer, options); } @@ -99,11 +99,11 @@ private async Task ScheduleAnalysisOnBackgroundThreadAsync(string filePath, await threadHandling.RunOnBackgroundThread(() => { ClearErrorList(filePath, issueConsumer); - + analysisService.ScheduleAnalysis(filePath, Guid.NewGuid(), detectedLanguages, issueConsumer, analyzerOptions); }); } - private static void ClearErrorList(string filePath, IIssueConsumer issueConsumer) => - issueConsumer.Accept(filePath, []); + private static void ClearErrorList(string filePath, IIssueConsumer issueConsumer) => + issueConsumer.Set(filePath, []); } diff --git a/src/SLCore.Listeners.UnitTests/Implementation/Analysis/RaisedFindingProcessorTests.cs b/src/SLCore.Listeners.UnitTests/Implementation/Analysis/RaisedFindingProcessorTests.cs index e854d379ad..1aea5df67e 100644 --- a/src/SLCore.Listeners.UnitTests/Implementation/Analysis/RaisedFindingProcessorTests.cs +++ b/src/SLCore.Listeners.UnitTests/Implementation/Analysis/RaisedFindingProcessorTests.cs @@ -38,24 +38,20 @@ namespace SonarLint.VisualStudio.SLCore.Listeners.UnitTests.Implementation.Analy public class RaisedFindingProcessorTests { [TestMethod] - public void MefCtor_CheckIsExported() - { + public void MefCtor_CheckIsExported() => MefTestHelpers.CheckTypeCanBeImported( MefTestHelpers.CreateExport(), MefTestHelpers.CreateExport(), MefTestHelpers.CreateExport(), MefTestHelpers.CreateExport(), MefTestHelpers.CreateExport()); - } [TestMethod] - public void MefCtor_CheckIsSingleton() - { + public void MefCtor_CheckIsSingleton() => MefTestHelpers.CheckIsSingletonMefComponent(); - } - + [TestMethod] - public void RaiseFindings_AnalysisIDisNull_Ignores() + public void RaiseFindings_AnalysisIdIsNull_Ignores() { var raiseFindingParams = new RaiseFindingParams("CONFIGURATION_ID", new Dictionary>(), false, null); @@ -70,7 +66,7 @@ public void RaiseFindings_AnalysisIDisNull_Ignores() analysisService.DidNotReceive().PublishIssues(Arg.Any(), Arg.Any(), Arg.Any>()); raiseFindingParamsToAnalysisIssueConverter.DidNotReceive().GetAnalysisIssues(Arg.Any(), Arg.Any>()); } - + [TestMethod] public void RaiseFindings_NoFindings_Ignores() { @@ -203,8 +199,10 @@ public void RaiseFindings_HasIssuesNotIntermediate_PublishFindings() analysisStatusNotifier.Received(1).AnalysisFinished(2, TimeSpan.Zero); } - [TestMethod] - public void RaiseFindings_MultipleFiles_PublishFindingsForEachFile() + [DataRow(true)] + [DataRow(false)] + [DataTestMethod] + public void RaiseFindings_MultipleFiles_PublishFindingsForEachFile(bool isIntermediate) { var analysisId = Guid.NewGuid(); var fileUri1 = new FileUri("file://C:/somefile"); @@ -217,7 +215,7 @@ public void RaiseFindings_MultipleFiles_PublishFindingsForEachFile() var findingsByFileUri = new Dictionary> { { fileUri1, [raisedFinding1] }, { fileUri2, [raisedFinding2] } }; - var raiseFindingParams = new RaiseFindingParams("CONFIGURATION_ID", findingsByFileUri, false, analysisId); + var raiseFindingParams = new RaiseFindingParams("CONFIGURATION_ID", findingsByFileUri, isIntermediate, analysisId); var analysisService = Substitute.For(); var raiseFindingParamsToAnalysisIssueConverter = Substitute.For(); @@ -241,26 +239,6 @@ public void RaiseFindings_MultipleFiles_PublishFindingsForEachFile() analysisStatusNotifierFactory.Received(1).Create("SLCoreAnalyzer", fileUri2.LocalPath, analysisId); } - [TestMethod] - public void RaiseFindings_HasIssuesIntermediate_DoNotPublishFindings() - { - var raisedFinding1 = CreateTestFinding("csharpsquid:S100"); - var raisedFinding2 = CreateTestFinding("javascript:S101"); - var raisedFinding3 = CreateTestFinding("secrets:S1012"); - var raisedFindings = new List { raisedFinding1, raisedFinding2, raisedFinding3 }; - - var findingsByFileUri = new Dictionary> { { new FileUri("file://C:/somefile"), raisedFindings } }; - var raiseFindingParams = new RaiseFindingParams("CONFIGURATION_ID", findingsByFileUri, true, Guid.NewGuid()); - - var analysisService = Substitute.For(); - - var testSubject = CreateTestSubject(analysisService: analysisService); - - testSubject.RaiseFinding(raiseFindingParams); - - analysisService.DidNotReceiveWithAnyArgs().PublishIssues(default, default, default); - } - private RaisedFindingProcessor CreateTestSubject( IAnalysisService analysisService = null, IRaiseFindingToAnalysisIssueConverter raiseFindingToAnalysisIssueConverter = null, @@ -273,7 +251,7 @@ private RaisedFindingProcessor CreateTestSubject( analysisService ?? Substitute.For(), raiseFindingToAnalysisIssueConverter ?? Substitute.For(), analysisStatusNotifierFactory ?? Substitute.For(), logger ?? new TestLogger()); - + private static IRaiseFindingToAnalysisIssueConverter CreateConverter(FileUri fileUri, IReadOnlyCollection raisedFindingDtos, IAnalysisIssue[] findings) { @@ -282,7 +260,7 @@ private static IRaiseFindingToAnalysisIssueConverter CreateConverter(FileUri fil .GetAnalysisIssues(fileUri, Arg.Is>(x => x.SequenceEqual(raisedFindingDtos))).Returns(findings); return raiseFindingParamsToAnalysisIssueConverter; } - + private ISLCoreConstantsProvider CreateConstantsProviderWithLanguages(params SloopLanguage[] languages) { var slCoreConstantsProvider = Substitute.For(); diff --git a/src/SLCore.Listeners/Implementation/Analysis/RaisedFindingProcessor.cs b/src/SLCore.Listeners/Implementation/Analysis/RaisedFindingProcessor.cs index 7969af767d..1be9ce63a4 100644 --- a/src/SLCore.Listeners/Implementation/Analysis/RaisedFindingProcessor.cs +++ b/src/SLCore.Listeners/Implementation/Analysis/RaisedFindingProcessor.cs @@ -58,7 +58,7 @@ public RaisedFindingProcessor(ISLCoreConstantsProvider slCoreConstantsProvider, analyzableLanguagesRuleKeyPrefixes = CalculateAnalyzableRulePrefixes(slCoreConstantsProvider); } - + public void RaiseFinding(RaiseFindingParams parameters) where T : RaisedFindingDto { if (!IsValid(parameters)) @@ -68,7 +68,7 @@ public void RaiseFinding(RaiseFindingParams parameters) where T : RaisedFi PublishFindings(parameters); } - + private bool IsValid(RaiseFindingParams parameters) where T : RaisedFindingDto { var logContext = $"[{nameof(RaiseFinding)}+{typeof(T).Name}]"; @@ -78,12 +78,6 @@ private bool IsValid(RaiseFindingParams parameters) where T : RaisedFindin return false; } - if (parameters.isIntermediatePublication) - { - logger.LogVerbose($"{logContext} {nameof(parameters.isIntermediatePublication)}=true, ignoring..."); - return false; - } - if (parameters.issuesByFileUri.Count == 0) { logger.LogVerbose($"{logContext} Empty {nameof(parameters.issuesByFileUri)} dictionary, ignoring..."); @@ -92,7 +86,7 @@ private bool IsValid(RaiseFindingParams parameters) where T : RaisedFindin return true; } - + private void PublishFindings(RaiseFindingParams parameters) where T : RaisedFindingDto { foreach (var fileAndIssues in parameters.issuesByFileUri) @@ -112,7 +106,7 @@ private T[] GetSupportedLanguageFindings(IEnumerable findings) where T : R { return findings.Where(i => analyzableLanguagesRuleKeyPrefixes.Exists(languageRepo => i.ruleKey.StartsWith(languageRepo))).ToArray(); } - + private static List CalculateAnalyzableRulePrefixes(ISLCoreConstantsProvider slCoreConstantsProvider) { return slCoreConstantsProvider.SLCoreAnalyzableLanguages?