Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix all providers support #1581

Merged
merged 104 commits into from
Jul 30, 2020
Merged
Show file tree
Hide file tree
Changes from 88 commits
Commits
Show all changes
104 commits
Select commit Hold shift + click to select a range
4521b5b
Something to begin with fix all providers.
savpek Jul 9, 2019
ee6b443
Basic routine for fix all dummy version.
savpek Jul 9, 2019
c5b9f1a
Added api etc for fixall.
savpek Jul 10, 2019
b944850
Initial version that should return changes.
savpek Jul 14, 2019
fa5c771
For some reason file changes are not serialized correctly, fix routin…
savpek Jul 15, 2019
f08d007
Created more revelant service files.
savpek Jul 16, 2019
fc35db8
Merge remote-tracking branch 'upstream/master' into feature/fix-all-p…
savpek Jul 16, 2019
1924d0a
Refactored some logig down to base class.
savpek Jul 16, 2019
c21c3e9
Added missing attribute.
savpek Jul 16, 2019
1966273
Fixed invalid import for importingConstructor.
savpek Jul 16, 2019
946d582
Refactored code a bit.
savpek Jul 28, 2019
e3e157b
Added expected result after everything is fixed.
savpek Jul 29, 2019
65bfe78
Merge remote-tracking branch 'upstream/master' into feature/fix-all-p…
savpek Jul 29, 2019
5650bcb
Moved assert as utility.
savpek Jul 29, 2019
a7ba31d
Moved fix all abstractions to correct location.
savpek Jul 29, 2019
0ab87eb
Added tests and support for simple get api for available fixes.
savpek Jul 29, 2019
581617f
Moved certain logic down to fixallprovider.
savpek Jul 29, 2019
a6c960f
Refactored diagnostic to expose more context internally for fix all.
savpek Jul 29, 2019
3497ebf
Minor regression fixes.
savpek Jul 29, 2019
7474a19
Refactoring and added correct scoping for tests.
savpek Jul 29, 2019
f3434ad
Now fix all providers works as intended.
savpek Jul 30, 2019
0cfc015
Refactoring.
savpek Jul 31, 2019
d3eff2c
Refactoring.
savpek Aug 1, 2019
2e5d557
Removed need for workaround on tessts.
savpek Aug 1, 2019
8c5b249
Refactored initialazation logig with analyzer workers.
savpek Aug 1, 2019
1caf5b9
Testfix.
savpek Aug 1, 2019
5ddf21a
Added scoping for fix all run service.
savpek Aug 1, 2019
22fc24a
Improved test to contain asserts for changes.
savpek Aug 1, 2019
111a8c7
Refactored tests.
savpek Aug 1, 2019
0fefa86
Todo marker test for unused import fix (doesn't pass yet).
savpek Aug 2, 2019
8360a65
Added support for action filtering.
savpek Aug 2, 2019
179e8f3
Tweaks.
savpek Aug 3, 2019
26b1187
Fix for diagnostic blocks.
savpek Aug 3, 2019
47aa179
Merge remote-tracking branch 'upstream/master' into feature/fix-all-p…
savpek Aug 3, 2019
96f81d8
Fixed bug.
savpek Aug 3, 2019
2a3c2e3
Merge remote-tracking branch 'upstream/master' into feature/fix-all-p…
savpek Aug 11, 2019
d6b944a
Added logging for executed fix all actions.
savpek Aug 11, 2019
ceafed9
Merge branch 'master' into feature/fix-all-providers
savpek Sep 21, 2019
e0cefe2
Hardcoded trick to get RCSxxxx work
savpek Sep 21, 2019
d36901d
Refactoring and now remove unnecessary imports is working as intended
savpek Sep 21, 2019
ff6e299
Fixes for 'fix everything'
savpek Sep 21, 2019
f078907
Updates to work with unused usings
savpek Sep 22, 2019
cdec274
Small tweaks for fixing
savpek Sep 22, 2019
0484d1d
Refactoring
savpek Sep 22, 2019
5525fc3
Improved initialization logig and fixed few tests
savpek Sep 22, 2019
d6722d6
Refactoring for services and base class
savpek Sep 22, 2019
fa77d9d
Some test fixes
savpek Sep 29, 2019
123cdff
Additional test fixes
savpek Sep 29, 2019
1057ff5
Blocked fix everything in project and solution scope in first version
savpek Sep 29, 2019
39e6871
Fixed asyncronity issue
savpek Sep 29, 2019
8fe471d
Merge remote-tracking branch 'upstream/master' into feature/fix-all-p…
savpek Sep 29, 2019
376d48c
Tweaks and fix for hanging ci test runs
savpek Sep 29, 2019
478e309
Added comment to improve readibility
savpek Sep 29, 2019
61a5467
Testfix
savpek Oct 4, 2019
9e3c01a
Fixed typo
savpek Oct 4, 2019
e2f7397
Merge branch 'master' into feature/fix-all-providers
savpek Oct 4, 2019
1bdbe2f
Merge branch 'master' into feature/fix-all-providers
savpek Oct 12, 2019
865bcef
Tweak for fix all action sorting and grouping
savpek Oct 12, 2019
da12044
Merge branch 'feature/fix-all-providers' of https://github.com/savpek…
savpek Oct 12, 2019
e5b852c
Removed unused method
savpek Oct 13, 2019
45d41f8
Merge branch 'master' into feature/fix-all-providers
savpek Oct 13, 2019
b9a7331
Merge branch 'master' into feature/fix-all-providers
savpek Oct 13, 2019
0e2b462
Merge branch 'master' into feature/fix-all-providers
savpek Oct 17, 2019
17d2799
Merge branch 'master' into feature/fix-all-providers
savpek Oct 18, 2019
b50cd3d
Merge remote-tracking branch 'upstream/master' into feature/fix-all-p…
savpek Dec 5, 2019
8bf62d2
Merge branch 'feature/fix-all-providers' of https://github.com/savpek…
savpek Dec 5, 2019
822afd1
Renamame for events to keep backward compatibility and timeout update
savpek Dec 5, 2019
7195ee2
Testing to use existing routines from code actions with fix all actions
savpek Dec 5, 2019
508008b
Refactoring logig down to base classes and test fix
savpek Dec 5, 2019
c69d9cb
Added support for get all text and wants changes
savpek Dec 5, 2019
1763ba8
Correctly pass wantsTextChanges and wantscodeactions to fix all service
savpek Dec 5, 2019
be73028
Added missing Wants* flags to tests
savpek Dec 5, 2019
45f4cd6
Merge branch 'master' into feature/fix-all-providers
savpek Dec 5, 2019
5b7fcf9
Merge remote-tracking branch 'upstream/master' into feature/fix-all-p…
savpek Dec 5, 2019
f61fd3f
Merge branch 'feature/fix-all-providers' of https://github.com/savpek…
savpek Dec 5, 2019
857d52d
Merge branch 'master' into feature/fix-all-providers
david-driscoll Jan 11, 2020
d5a202c
Buildfix
savpek Jan 11, 2020
3a56636
Removed unused method
savpek Jan 11, 2020
2034710
Ignore casing on refactoring asserts
savpek Jan 11, 2020
c355744
Merge branch 'master' into feature/fix-all-providers
savpek Jan 19, 2020
134e033
Merge branch 'master' into feature/fix-all-providers
savpek Jan 26, 2020
b04a69b
Review fixes
savpek Jan 26, 2020
0c18232
Added AssertIgnoringIndentAndNewlines and removed unused code
savpek Jan 26, 2020
908d868
Merge branch 'master' into feature/fix-all-providers
bjorkstromm Jan 27, 2020
85f4e8c
Merge branch 'master' into feature/fix-all-providers
david-driscoll Feb 12, 2020
c33be2e
Merge branch 'master' into feature/fix-all-providers
savpek Feb 14, 2020
60f5063
Merge branch 'master' into feature/fix-all-providers
savpek Feb 15, 2020
6021c80
Merge branch 'master' into feature/fix-all-providers
savpek Feb 23, 2020
1eb7fc8
Merge branch 'master' into feature/fix-all-providers
savpek Mar 11, 2020
b65b26b
Merge branch 'master' into feature/fix-all-providers
savpek Mar 19, 2020
6cd2070
Merge branch 'master' into feature/fix-all-providers
savpek Mar 28, 2020
eb38533
Merge branch 'master' into feature/fix-all-providers
filipw Apr 14, 2020
30163f9
Merge branch 'master' into feature/fix-all-providers
savpek Apr 15, 2020
8f8d9a1
Merge branch 'master' into feature/fix-all-providers
savpek Apr 15, 2020
84d6712
Merge
savpek Jun 5, 2020
33c3e53
Merge branch 'master' into feature/fix-all-providers
savpek Jun 6, 2020
40b5b01
Merge branch 'master' into feature/fix-all-providers
savpek Jun 6, 2020
598b5d2
Merge branch 'master' into feature/fix-all-providers
savpek Jun 6, 2020
c38631d
Merge branch 'master' into feature/fix-all-providers
savpek Jun 6, 2020
1b939bb
Merge branch 'master' into feature/fix-all-providers
savpek Jun 9, 2020
396920c
Merge remote-tracking branch 'origin/master' into feature/fix-all-pro…
david-driscoll Jul 29, 2020
d8252f7
fixed compliation error
david-driscoll Jul 29, 2020
4dc7c18
Merge remote-tracking branch 'origin/master' into feature/fix-all-pro…
david-driscoll Jul 29, 2020
bae0914
added skip for single failing test
david-driscoll Jul 30, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions src/OmniSharp.Abstractions/Models/v1/FixAll/FixAllItem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace OmniSharp.Abstractions.Models.V1.FixAll
{
public class FixAllItem
{
public FixAllItem() {}
public FixAllItem(string id, string message)
{
Id = id;
Message = message;
}

public string Id { get; set; }
public string Message { get; set; }
}
}
11 changes: 11 additions & 0 deletions src/OmniSharp.Abstractions/Models/v1/FixAll/GetFixAllRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using OmniSharp.Mef;
using OmniSharp.Models;

namespace OmniSharp.Abstractions.Models.V1.FixAll
{
[OmniSharpEndpoint(OmniSharpEndpoints.GetFixAll, typeof(GetFixAllRequest), typeof(GetFixAllResponse))]
public class GetFixAllRequest: SimpleFileRequest
{
public FixAllScope Scope { get; set; } = FixAllScope.Document;
}
}
14 changes: 14 additions & 0 deletions src/OmniSharp.Abstractions/Models/v1/FixAll/GetFixAllResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System.Collections.Generic;

namespace OmniSharp.Abstractions.Models.V1.FixAll
{
public class GetFixAllResponse
{
public GetFixAllResponse(IEnumerable<FixAllItem> fixableItems)
{
Items = fixableItems;
}

public IEnumerable<FixAllItem> Items { get; set; }
}
}
17 changes: 17 additions & 0 deletions src/OmniSharp.Abstractions/Models/v1/FixAll/RunFixAllRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using OmniSharp.Mef;
using OmniSharp.Models;

namespace OmniSharp.Abstractions.Models.V1.FixAll
{
[OmniSharpEndpoint(OmniSharpEndpoints.RunFixAll, typeof(RunFixAllRequest), typeof(RunFixAllResponse))]
public class RunFixAllRequest : SimpleFileRequest
{
public FixAllScope Scope { get; set; } = FixAllScope.Document;

// If this is null -> filter not set -> try to fix all issues in current defined scope.
public FixAllItem[] FixAllFilter { get; set; }
public int Timeout { get; set; } = 3000;
public bool WantsAllCodeActionOperations { get; set; }
public bool WantsTextChanges { get; set; }
}
}
17 changes: 17 additions & 0 deletions src/OmniSharp.Abstractions/Models/v1/FixAll/RunFixAllResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System.Collections.Generic;
using OmniSharp.Models;

namespace OmniSharp.Abstractions.Models.V1.FixAll
{
public class RunFixAllResponse : IAggregateResponse
{
public RunFixAllResponse()
{
Changes = new List<FileOperationResponse>();
}

public IEnumerable<FileOperationResponse> Changes { get; set; }

public IAggregateResponse Merge(IAggregateResponse response) { return response; }
}
}
9 changes: 9 additions & 0 deletions src/OmniSharp.Abstractions/Models/v1/FixAll/RunFixAllScope.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace OmniSharp.Abstractions.Models.V1.FixAll
{
public enum FixAllScope
{
Document = 0,
Project = 1,
Solution = 2
}
}
3 changes: 2 additions & 1 deletion src/OmniSharp.Abstractions/OmniSharpEndpoints.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ public static class OmniSharpEndpoints
public const string WorkspaceInformation = "/projects";
public const string ProjectInformation = "/project";
public const string FixUsings = "/fixusings";

public const string RunFixAll = "/runfixall";
public const string GetFixAll = "/getfixall";
public const string CheckAliveStatus = "/checkalivestatus";
public const string CheckReadyStatus = "/checkreadystatus";
public const string StopServer = "/stopserver";
Expand Down
9 changes: 5 additions & 4 deletions src/OmniSharp.Roslyn.CSharp/Helpers/DiagnosticExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
using Microsoft.CodeAnalysis;
using OmniSharp.Models.Diagnostics;
using OmniSharp.Roslyn.CSharp.Services.Diagnostics;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading.Tasks;

namespace OmniSharp.Helpers
{
internal static class DiagnosticExtensions
{
private static readonly ImmutableHashSet<string> _tagFilter =
ImmutableHashSet.Create<string>("Unnecessary");
ImmutableHashSet.Create("Unnecessary");

internal static DiagnosticLocation ToDiagnosticLocation(this Diagnostic diagnostic)
{
Expand All @@ -32,9 +32,10 @@ internal static DiagnosticLocation ToDiagnosticLocation(this Diagnostic diagnost
};
}

internal static IEnumerable<DiagnosticLocation> DistinctDiagnosticLocationsByProject(this IEnumerable<(string projectName, Diagnostic diagnostic)> diagnostics)
internal static IEnumerable<DiagnosticLocation> DistinctDiagnosticLocationsByProject(this IEnumerable<DocumentDiagnostics> documentDiagnostic)
{
return diagnostics
return documentDiagnostic
.SelectMany(x => x.Diagnostics, (parent, child) => (projectName: parent.ProjectName, diagnostic: child))
.Select(x => new
{
location = x.diagnostic.ToDiagnosticLocation(),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Collections.Immutable;
using System.Composition;
using System.Linq;
using System.Threading.Tasks;
Expand All @@ -9,7 +8,6 @@
using OmniSharp.Mef;
using OmniSharp.Models;
using OmniSharp.Models.CodeCheck;
using OmniSharp.Models.Diagnostics;
using OmniSharp.Options;
using OmniSharp.Roslyn.CSharp.Workers.Diagnostics;

Expand Down Expand Up @@ -45,11 +43,11 @@ public async Task<QuickFixResponse> Handle(CodeCheckRequest request)
return GetResponseFromDiagnostics(diagnostics, request.FileName);
}

private static QuickFixResponse GetResponseFromDiagnostics(ImmutableArray<(string projectName, Diagnostic diagnostic)> diagnostics, string fileName)
private static QuickFixResponse GetResponseFromDiagnostics(ImmutableArray<DocumentDiagnostics> diagnostics, string fileName)
{
var diagnosticLocations = diagnostics
.Where(x => (string.IsNullOrEmpty(fileName)
|| x.diagnostic.Location.GetLineSpan().Path == fileName))
.Where(x => string.IsNullOrEmpty(fileName)
|| x.DocumentPath == fileName)
.DistinctDiagnosticLocationsByProject()
.Where(x => x.FileName != null);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using OmniSharp.Roslyn.CSharp.Services.Diagnostics;

namespace OmniSharp.Roslyn.CSharp.Services.Refactoring
{

public class DocumentWithFixProvidersAndMatchingDiagnostics
{
private readonly DocumentDiagnostics _documentDiagnostics;

// http://source.roslyn.io/#Microsoft.VisualStudio.LanguageServices.CSharp/LanguageService/CSharpCodeCleanupFixer.cs,d9a375db0f1e430e,references
// CS8019 isn't directly used (via roslyn) but has an analyzer that report different diagnostic based on CS8019 to improve user experience.
private static readonly Dictionary<string, string> _customDiagVsFixMap = new Dictionary<string, string>
{
{ "CS8019", "RemoveUnnecessaryImportsFixable" }
};

private DocumentWithFixProvidersAndMatchingDiagnostics(CodeFixProvider provider, DocumentDiagnostics documentDiagnostics)
{
CodeFixProvider = provider;
_documentDiagnostics = documentDiagnostics;
FixAllProvider = provider.GetFixAllProvider();
}

public CodeFixProvider CodeFixProvider { get; }
public FixAllProvider FixAllProvider { get; }
public DocumentId DocumentId => _documentDiagnostics.DocumentId;
public ProjectId ProjectId => _documentDiagnostics.ProjectId;
public string DocumentPath => _documentDiagnostics.DocumentPath;

public IEnumerable<(string id, string messsage)> FixableDiagnostics => _documentDiagnostics.Diagnostics
.Where(x => HasFixToShow(x.Id))
.Select(x => (x.Id, x.GetMessage()));

// Theres specific filterings between what is shown and what is fixed because of some custom mappings
// between diagnostics and their fixers. We dont want to show text 'RemoveUnnecessaryImportsFixable: ...'
// but instead 'CS8019: ...' where actual fixer is RemoveUnnecessaryImportsFixable behind the scenes.
private bool HasFixToShow(string diagnosticId)
{
return CodeFixProvider.FixableDiagnosticIds.Any(id => id == diagnosticId) && !_customDiagVsFixMap.ContainsValue(diagnosticId) || HasMappedFixAvailable(diagnosticId);
}

public bool HasFixForId(string diagnosticId)
{
return CodeFixProvider.FixableDiagnosticIds.Any(id => id == diagnosticId && !_customDiagVsFixMap.ContainsKey(diagnosticId)) || HasMappedFixAvailable(diagnosticId);
}

private bool HasMappedFixAvailable(string diagnosticId)
{
return (_customDiagVsFixMap.ContainsKey(diagnosticId) && CodeFixProvider.FixableDiagnosticIds.Any(id => id == _customDiagVsFixMap[diagnosticId]));
}

public static ImmutableArray<DocumentWithFixProvidersAndMatchingDiagnostics> CreateWithMatchingProviders(ImmutableArray<CodeFixProvider> providers, DocumentDiagnostics documentDiagnostics)
{
return
providers
.Select(provider => new DocumentWithFixProvidersAndMatchingDiagnostics(provider, documentDiagnostics))
.Where(x => x._documentDiagnostics.Diagnostics.Any(d => x.HasFixToShow(d.Id)) || x._documentDiagnostics.Diagnostics.Any(d => x.HasFixForId(d.Id)))
.Where(x => x.FixAllProvider != null)
.ToImmutableArray();
}

public async Task<(CodeAction action, ImmutableArray<string> idsToFix)> RegisterCodeFixesOrDefault(Document document)
{
CodeAction action = null;

var fixableDiagnostics = _documentDiagnostics
.Diagnostics
.Where(x => HasFixForId(x.Id))
.ToImmutableArray();

foreach (var diagnostic in fixableDiagnostics)
{
var context = new CodeFixContext(
document,
diagnostic,
(a, _) =>
{
if (action == null)
{
action = a;
}
},
CancellationToken.None);

await CodeFixProvider.RegisterCodeFixesAsync(context).ConfigureAwait(false);
}

if(action == null)
return default;

return (action, fixableDiagnostics.Select(x => x.Id).Distinct().ToImmutableArray());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using System.Collections.Generic;
using System.Composition;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.Extensions.Logging;
using OmniSharp.Abstractions.Models.V1.FixAll;
using OmniSharp.Mef;
using OmniSharp.Roslyn.CSharp.Services.Refactoring.V2;
using OmniSharp.Roslyn.CSharp.Workers.Diagnostics;
using OmniSharp.Services;

namespace OmniSharp.Roslyn.CSharp.Services.Refactoring
{
[OmniSharpHandler(OmniSharpEndpoints.GetFixAll, LanguageNames.CSharp)]
public class GetFixAllCodeActionService : BaseCodeActionService<GetFixAllRequest, GetFixAllResponse>
{
[ImportingConstructor]
public GetFixAllCodeActionService(
OmniSharpWorkspace workspace,
[ImportMany] IEnumerable<ICodeActionProvider> providers,
ILoggerFactory loggerFactory,
ICsDiagnosticWorker diagnostics,
CachingCodeFixProviderForProjects codeFixesForProject
) : base(workspace, providers, loggerFactory.CreateLogger<GetFixAllCodeActionService>(), diagnostics, codeFixesForProject)
{
}

public override async Task<GetFixAllResponse> Handle(GetFixAllRequest request)
{
var availableFixes = await GetDiagnosticsMappedWithFixAllProviders(request.Scope, request.FileName);

var distinctDiagnosticsThatCanBeFixed = availableFixes
.SelectMany(x => x.FixableDiagnostics)
.GroupBy(x => x.id) // Distinct isn't good fit here since theres cases where Id has multiple different messages based on location, just show one of them.
.Select(x => x.First())
.Select(x => new FixAllItem(x.id, x.messsage))
.OrderBy(x => x.Id)
.ToArray();

return new GetFixAllResponse(distinctDiagnosticsThatCanBeFixed);
}
}
}
Loading