diff options
author | Marius Ungureanu <teromario@yahoo.com> | 2018-02-23 17:37:14 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-02-23 17:37:14 +0300 |
commit | 1ba94df4b5359d08c0c0ff7adccebf67778173fc (patch) | |
tree | 89be95db2bafc6ef1bb40f1009b80875d0cb09e3 /main/src | |
parent | 5fa872b257473c4bc4e30e0e13af5aa8596c5d53 (diff) |
[Refactoring] Switch to Roslyn CodeFixService (#3636)
* [Refactoring] Switch to Roslyn CodeFixService
* Flush some fixes and cleanups
* [Ide] More dead code removal
* [Refactoring] Delete dead code, migrate options to the diagnostic workspace provider
Also fix refactorings taking into account options UI.
* Fix a NRE
* [Refactoring] Fix code issues still appearing for suppressed diagnostics
* This file was not committed
* [Refactoring] Some updates to prevent some possible NREs and uniformization
* [Ide] Re-enable new error backend for C# and add test for compiler diagnostics fixes
Diffstat (limited to 'main/src')
23 files changed, 375 insertions, 1169 deletions
diff --git a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Parser/CSharpParsedDocument.cs b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Parser/CSharpParsedDocument.cs index 6be03cc78c..faff647bc7 100644 --- a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Parser/CSharpParsedDocument.cs +++ b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Parser/CSharpParsedDocument.cs @@ -517,8 +517,8 @@ namespace MonoDevelop.CSharp.Parser static readonly IReadOnlyList<Error> emptyErrors = Array.Empty<Error> (); public override async Task<IReadOnlyList<Error>> GetErrorsAsync (CancellationToken cancellationToken = default(CancellationToken)) { - //if (Ide.IdeApp.Preferences.EnableSourceAnalysis) - // return emptyErrors; + if (Ide.IdeApp.Preferences.EnableSourceAnalysis) + return emptyErrors; var model = GetAst<SemanticModel> (); if (model == null) diff --git a/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Refactoring/PackageCodeDiagnosticProvider.cs b/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Refactoring/PackageCodeDiagnosticProvider.cs index 8b87157e1a..6c0b36215b 100644 --- a/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Refactoring/PackageCodeDiagnosticProvider.cs +++ b/main/src/addins/MonoDevelop.PackageManagement/MonoDevelop.PackageManagement.Refactoring/PackageCodeDiagnosticProvider.cs @@ -1,113 +1,113 @@ -// -// PackageCodeDiagnosticProvider.cs -// -// Author: -// Mike Krüger <mkrueger@xamarin.com> -// -// Copyright (c) 2015 Xamarin Inc. (http://xamarin.com) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. +//// +//// PackageCodeDiagnosticProvider.cs +//// +//// Author: +//// Mike Krüger <mkrueger@xamarin.com> +//// +//// Copyright (c) 2015 Xamarin Inc. (http://xamarin.com) +//// +//// Permission is hereby granted, free of charge, to any person obtaining a copy +//// of this software and associated documentation files (the "Software"), to deal +//// in the Software without restriction, including without limitation the rights +//// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +//// copies of the Software, and to permit persons to whom the Software is +//// furnished to do so, subject to the following conditions: +//// +//// The above copyright notice and this permission notice shall be included in +//// all copies or substantial portions of the Software. +//// +//// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +//// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +//// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +//// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +//// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +//// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +//// THE SOFTWARE. -using System; -using MonoDevelop.CodeIssues; -using MonoDevelop.Core; -using MonoDevelop.Projects; -using System.Linq; -using System.IO; -using System.Collections.Generic; -using System.Reflection; -using System.Threading; -using System.Threading.Tasks; -using MonoDevelop.Ide.Editor; -using MonoDevelop.Ide.TypeSystem; -using MonoDevelop.Ide; +//using System; +//using MonoDevelop.CodeIssues; +//using MonoDevelop.Core; +//using MonoDevelop.Projects; +//using System.Linq; +//using System.IO; +//using System.Collections.Generic; +//using System.Reflection; +//using System.Threading; +//using System.Threading.Tasks; +//using MonoDevelop.Ide.Editor; +//using MonoDevelop.Ide.TypeSystem; +//using MonoDevelop.Ide; -namespace MonoDevelop.PackageManagement.Refactoring -{ - sealed class PackageCodeDiagnosticProvider : CodeDiagnosticProvider - { - static readonly Dictionary<Project, AnalyzersFromAssembly> diagnosticCache = new Dictionary<Project, AnalyzersFromAssembly> (); +//namespace MonoDevelop.PackageManagement.Refactoring +//{ +// sealed class PackageCodeDiagnosticProvider : CodeDiagnosticProvider +// { +// static readonly Dictionary<Project, AnalyzersFromAssembly> diagnosticCache = new Dictionary<Project, AnalyzersFromAssembly> (); - static PackageCodeDiagnosticProvider () - { - IdeApp.Workspace.SolutionUnloaded += delegate { - diagnosticCache.Clear (); - }; - IdeApp.Workspace.ActiveConfigurationChanged += delegate { - diagnosticCache.Clear (); - }; - } +// static PackageCodeDiagnosticProvider () +// { +// IdeApp.Workspace.SolutionUnloaded += delegate { +// diagnosticCache.Clear (); +// }; +// IdeApp.Workspace.ActiveConfigurationChanged += delegate { +// diagnosticCache.Clear (); +// }; +// } - public async override Task<IEnumerable<CodeDiagnosticFixDescriptor>> GetCodeFixDescriptorsAsync (DocumentContext document, string language, CancellationToken cancellationToken = default(CancellationToken)) - { - var diags = await GetProjectDiagnosticsAsync (document.Project, language, cancellationToken).ConfigureAwait (false); - return diags.Fixes; - } +// public async override Task<IEnumerable<CodeDiagnosticFixDescriptor>> GetCodeFixDescriptorsAsync (DocumentContext document, string language, CancellationToken cancellationToken = default(CancellationToken)) +// { +// var diags = await GetProjectDiagnosticsAsync (document.Project, language, cancellationToken).ConfigureAwait (false); +// return diags.Fixes; +// } - public async override Task<IEnumerable<CodeDiagnosticDescriptor>> GetCodeDiagnosticDescriptorsAsync (DocumentContext document, string language, CancellationToken cancellationToken = default(CancellationToken)) - { - var diags = await GetProjectDiagnosticsAsync (document.Project, language, cancellationToken).ConfigureAwait (false); - return diags.Analyzers; - } +// public async override Task<IEnumerable<CodeDiagnosticDescriptor>> GetCodeDiagnosticDescriptorsAsync (DocumentContext document, string language, CancellationToken cancellationToken = default(CancellationToken)) +// { +// var diags = await GetProjectDiagnosticsAsync (document.Project, language, cancellationToken).ConfigureAwait (false); +// return diags.Analyzers; +// } - public async override Task<IEnumerable<MonoDevelop.CodeActions.CodeRefactoringDescriptor>> GetCodeRefactoringDescriptorsAsync (DocumentContext document, string language, CancellationToken cancellationToken) - { - var diags = await GetProjectDiagnosticsAsync (document.Project, language, cancellationToken).ConfigureAwait (false); - return diags.Refactorings; - } +// public async override Task<IEnumerable<MonoDevelop.CodeActions.CodeRefactoringDescriptor>> GetCodeRefactoringDescriptorsAsync (DocumentContext document, string language, CancellationToken cancellationToken) +// { +// var diags = await GetProjectDiagnosticsAsync (document.Project, language, cancellationToken).ConfigureAwait (false); +// return diags.Refactorings; +// } - static async Task<AnalyzersFromAssembly> GetProjectDiagnosticsAsync (Project project, string language, CancellationToken cancellationToken) - { - if (project == null) - return AnalyzersFromAssembly.Empty; - AnalyzersFromAssembly result; - if (diagnosticCache.TryGetValue(project, out result)) - return result; +// static async Task<AnalyzersFromAssembly> GetProjectDiagnosticsAsync (Project project, string language, CancellationToken cancellationToken) +// { +// if (project == null) +// return AnalyzersFromAssembly.Empty; +// AnalyzersFromAssembly result; +// if (diagnosticCache.TryGetValue(project, out result)) +// return result; - result = new AnalyzersFromAssembly (); +// result = new AnalyzersFromAssembly (); - var dotNetProject = project as DotNetProject; - if (dotNetProject != null) { - var proxy = new DotNetProjectProxy (dotNetProject); - if (proxy.HasPackages ()) { - var packagesPath = await GetPackagesPath (proxy); - foreach (var file in Directory.EnumerateFiles (packagesPath, "*.dll", SearchOption.AllDirectories)) { - cancellationToken.ThrowIfCancellationRequested (); - try { - var asm = Assembly.LoadFrom (file); - result.AddAssembly (asm); - } catch (Exception) { - } - } - } - } - diagnosticCache[project] = result; - return result; - } +// var dotNetProject = project as DotNetProject; +// if (dotNetProject != null) { +// var proxy = new DotNetProjectProxy (dotNetProject); +// if (proxy.HasPackages ()) { +// var packagesPath = await GetPackagesPath (proxy); +// foreach (var file in Directory.EnumerateFiles (packagesPath, "*.dll", SearchOption.AllDirectories)) { +// cancellationToken.ThrowIfCancellationRequested (); +// try { +// var asm = Assembly.LoadFrom (file); +// result.AddAssembly (asm); +// } catch (Exception) { +// } +// } +// } +// } +// diagnosticCache[project] = result; +// return result; +// } - static Task<FilePath> GetPackagesPath (IDotNetProject project) - { - return Runtime.RunInMainThread (() => { - var solutionManager = PackageManagementServices.Workspace.GetSolutionManager (project.ParentSolution); - var nugetProject = solutionManager.GetNuGetProject (project); - return nugetProject.GetPackagesFolderPath (solutionManager); - }); - } - } -}
\ No newline at end of file +// static Task<FilePath> GetPackagesPath (IDotNetProject project) +// { +// return Runtime.RunInMainThread (() => { +// var solutionManager = PackageManagementServices.Workspace.GetSolutionManager (project.ParentSolution); +// var nugetProject = solutionManager.GetNuGetProject (project); +// return nugetProject.GetPackagesFolderPath (solutionManager); +// }); +// } +// } +//}
\ No newline at end of file diff --git a/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.AnalysisCore/AnalysisCommands.cs b/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.AnalysisCore/AnalysisCommands.cs index 348cc789a9..3abed75c3d 100644 --- a/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.AnalysisCore/AnalysisCommands.cs +++ b/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.AnalysisCore/AnalysisCommands.cs @@ -44,6 +44,9 @@ namespace MonoDevelop.AnalysisCore class ExportRulesHandler : CommandHandler { + static MonoDevelopWorkspaceDiagnosticAnalyzerProviderService.OptionsTable options = + ((MonoDevelopWorkspaceDiagnosticAnalyzerProviderService)Ide.Composition.CompositionManager.GetExportedValue<IWorkspaceDiagnosticAnalyzerProviderService> ()).Options; + protected override void Run () { var lang = "text/x-csharp"; @@ -55,7 +58,8 @@ namespace MonoDevelop.AnalysisCore Dictionary<CodeDiagnosticDescriptor, DiagnosticSeverity?> severities = new Dictionary<CodeDiagnosticDescriptor, DiagnosticSeverity?> (); - foreach (var node in BuiltInCodeDiagnosticProvider.GetBuiltInCodeDiagnosticDescriptorsAsync (CodeRefactoringService.MimeTypeToLanguage(lang), true).Result) { + var language = CodeRefactoringService.MimeTypeToLanguage (lang); + foreach (var node in options.AllDiagnostics.Where (x => x.Languages.Contains (language))) { severities [node] = node.DiagnosticSeverity; // if (node.GetProvider ().SupportedDiagnostics.Length > 1) { // foreach (var subIssue in node.GetProvider ().SupportedDiagnostics) { @@ -90,7 +94,7 @@ namespace MonoDevelop.AnalysisCore } var providerStates = new Dictionary<CodeRefactoringDescriptor, bool> (); - foreach (var node in BuiltInCodeDiagnosticProvider.GetBuiltInCodeRefactoringDescriptorsAsync (CodeRefactoringService.MimeTypeToLanguage(lang), true).Result) { + foreach (var node in options.AllRefactorings.Where (x => x.Language.Contains (language))) { providerStates [node] = node.IsEnabled; } diff --git a/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.AnalysisCore/MonoDevelopWorkspaceDiagnosticAnalyzerProviderService.OptionsTable.cs b/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.AnalysisCore/MonoDevelopWorkspaceDiagnosticAnalyzerProviderService.OptionsTable.cs new file mode 100644 index 0000000000..667665a194 --- /dev/null +++ b/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.AnalysisCore/MonoDevelopWorkspaceDiagnosticAnalyzerProviderService.OptionsTable.cs @@ -0,0 +1,114 @@ +// +// MonoDevelopWorkspaceDiagnosticAnalyzerProviderService.OptionsTable.cs +// +// Author: +// Marius Ungureanu <maungu@microsoft.com> +// +// Copyright (c) 2018 +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CodeRefactorings; +using Microsoft.CodeAnalysis.Diagnostics; +using MonoDevelop.AnalysisCore.Gui; +using MonoDevelop.CodeActions; +using MonoDevelop.CodeIssues; +using MonoDevelop.Core; + +namespace MonoDevelop.AnalysisCore +{ + partial class MonoDevelopWorkspaceDiagnosticAnalyzerProviderService + { + internal class OptionsTable + { + Dictionary<string, CodeDiagnosticDescriptor> diagnosticTable = new Dictionary<string, CodeDiagnosticDescriptor> (); + Dictionary<Type, CodeRefactoringDescriptor> refactoringTable = new Dictionary<Type, CodeRefactoringDescriptor> (); + List<CodeDiagnosticDescriptor> diagnostics = new List<CodeDiagnosticDescriptor> (); + + public IEnumerable<CodeDiagnosticDescriptor> AllDiagnostics => diagnostics; + public IEnumerable<CodeRefactoringDescriptor> AllRefactorings => refactoringTable.Values; + + public bool TryGetDiagnosticDescriptor (string id, out CodeDiagnosticDescriptor desc) + { + return diagnosticTable.TryGetValue (id, out desc); + } + + public bool TryGetRefactoringDescriptor (Type t, out CodeRefactoringDescriptor desc) + { + return refactoringTable.TryGetValue (t, out desc); + } + + // Needed to support configuration of diagnostics and code fixes/refactorings. + public void ProcessAssembly (Assembly asm) + { + try { + foreach (var type in asm.GetTypes ()) { + + //HACK: Workaround for missing UI + if (type == typeof (Microsoft.CodeAnalysis.GenerateOverrides.GenerateOverridesCodeRefactoringProvider)) + continue; + if (type == typeof (Microsoft.CodeAnalysis.AddMissingReference.AbstractAddMissingReferenceCodeFixProvider)) + continue; + + var analyzerAttr = (DiagnosticAnalyzerAttribute)type.GetCustomAttributes (typeof (DiagnosticAnalyzerAttribute), false).FirstOrDefault (); + if (analyzerAttr != null) { + try { + var analyzer = (DiagnosticAnalyzer)Activator.CreateInstance (type); + var descriptor = new CodeDiagnosticDescriptor (analyzerAttr.Languages, type); + + foreach (var diag in analyzer.SupportedDiagnostics) { + if (!IsDiagnosticSupported (diag)) + continue; + + diagnosticTable[diag.Id] = descriptor; + } + diagnostics.Add (descriptor); + } catch (Exception e) { + LoggingService.LogError ($"error while adding diagnostic analyzer {type} from assembly {asm.FullName}", e); + } + } + + var exportAttr = type.GetCustomAttributes (typeof (ExportCodeRefactoringProviderAttribute), false).FirstOrDefault () as ExportCodeRefactoringProviderAttribute; + if (exportAttr != null) { + refactoringTable[type] = new CodeRefactoringDescriptor (type, exportAttr); + } + } + } catch (ReflectionTypeLoadException ex) { + foreach (var subException in ex.LoaderExceptions) { + LoggingService.LogError ("Error while loading diagnostics in " + asm.FullName, subException); + } + throw; + } + } + + static bool IsDiagnosticSupported (DiagnosticDescriptor diag) + { + //filter out E&C analyzers as we don't support E&C + return !diag.CustomTags.Contains (WellKnownDiagnosticTags.EditAndContinue); + } + } + } +} diff --git a/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.AnalysisCore/MonoDevelopWorkspaceDiagnosticAnalyzerProviderService.cs b/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.AnalysisCore/MonoDevelopWorkspaceDiagnosticAnalyzerProviderService.cs index cddacc5754..5f3184e237 100644 --- a/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.AnalysisCore/MonoDevelopWorkspaceDiagnosticAnalyzerProviderService.cs +++ b/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.AnalysisCore/MonoDevelopWorkspaceDiagnosticAnalyzerProviderService.cs @@ -39,10 +39,12 @@ namespace MonoDevelop.AnalysisCore [Export(typeof(IWorkspaceDiagnosticAnalyzerProviderService))] partial class MonoDevelopWorkspaceDiagnosticAnalyzerProviderService : IWorkspaceDiagnosticAnalyzerProviderService { + static readonly AnalyzerAssemblyLoader analyzerAssemblyLoader = new AnalyzerAssemblyLoader (); readonly static string diagnosticAnalyzerAssembly = typeof (DiagnosticAnalyzerAttribute).Assembly.GetName ().Name; + const bool ClrHeapEnabled = false; - static readonly AnalyzerAssemblyLoader analyzerAssemblyLoader = new AnalyzerAssemblyLoader (); + internal OptionsTable Options = new OptionsTable (); readonly ImmutableArray<HostDiagnosticAnalyzerPackage> hostDiagnosticAnalyzerInfo; const string extensionPath = "/MonoDevelop/Refactoring/AnalyzerAssemblies"; @@ -50,6 +52,7 @@ namespace MonoDevelop.AnalysisCore public MonoDevelopWorkspaceDiagnosticAnalyzerProviderService () { LoadAnalyzerAssemblies (); + RefactoringEssentials.NRefactory6Host.GetLocalizedString = GettextCatalog.GetString; hostDiagnosticAnalyzerInfo = CreateHostDiagnosticAnalyzerPackages (); } @@ -96,6 +99,7 @@ namespace MonoDevelop.AnalysisCore // Figure out a way to disable E&C analyzers. assemblies.Add (asm.Location); + Options.ProcessAssembly (asm); } catch (Exception e) { LoggingService.LogError ("Error while loading diagnostics in " + asm.FullName, e); } diff --git a/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeActions/CodeActionContainer.cs b/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeActions/CodeActionContainer.cs index f8522866e1..28fec6bcef 100644 --- a/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeActions/CodeActionContainer.cs +++ b/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeActions/CodeActionContainer.cs @@ -24,96 +24,50 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -using System.Collections.Generic; -using Microsoft.CodeAnalysis.CodeActions; using System; -using MonoDevelop.CodeIssues; using System.Linq; +using System.Collections.Generic; using Microsoft.CodeAnalysis; -using System.Collections; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CodeRefactorings; +using System.Collections.Immutable; namespace MonoDevelop.CodeActions { class CodeActionContainer { - public static readonly CodeActionContainer Empty = new CodeActionContainer(); + public static readonly CodeActionContainer Empty = new CodeActionContainer(ImmutableArray<CodeFixCollection>.Empty, ImmutableArray<CodeRefactoring>.Empty); public bool IsEmpty { get { - return CodeFixActions.Count + DiagnosticsAtCaret.Count + CodeRefactoringActions.Count == 0; + return CodeFixActions.Length + CodeRefactoringActions.Length == 0; } } - IReadOnlyList<ValidCodeDiagnosticAction> codeFixActions; - public IReadOnlyList<ValidCodeDiagnosticAction> CodeFixActions { + ImmutableArray<CodeFixCollection> codeFixActions; + public ImmutableArray<CodeFixCollection> CodeFixActions { get { - return codeFixActions ?? new ValidCodeDiagnosticAction[0]; + return codeFixActions; } private set { codeFixActions = value; } } - IReadOnlyList<ValidCodeAction> codeRefactoringActions; - - public IReadOnlyList<ValidCodeAction> CodeRefactoringActions { + ImmutableArray<CodeRefactoring> codeRefactoringActions; + public ImmutableArray<CodeRefactoring> CodeRefactoringActions { get { - return codeRefactoringActions ?? new ValidCodeAction[0]; + return codeRefactoringActions; } private set { codeRefactoringActions = value; } } - public IEnumerable<ValidCodeAction> AllValidCodeActions { - get { - return CodeRefactoringActions.Concat (CodeFixActions); - } - } - - IReadOnlyList<Diagnostic> diagnosticsAtCaret; - public IReadOnlyList<Diagnostic> DiagnosticsAtCaret { - get { - return diagnosticsAtCaret ?? new Diagnostic[0]; - } - private set { - diagnosticsAtCaret = value.Distinct (new DiagnosticComparer()).ToList (); - } - } - - class DiagnosticComparer : IEqualityComparer<Diagnostic> - { - bool IEqualityComparer<Diagnostic>.Equals (Diagnostic x, Diagnostic y) - { - if (x.Id != null && y.Id != null) - return x.Id == y.Id; - return x.Equals (y); - } - - int IEqualityComparer<Diagnostic>.GetHashCode (Diagnostic obj) - { - return obj.Id != null ? obj.Id.GetHashCode () : obj.GetHashCode (); - } - } - - CodeActionContainer () - { - CodeFixActions = new List<ValidCodeDiagnosticAction> (); - CodeRefactoringActions = new List<ValidCodeAction> (); - DiagnosticsAtCaret = new List<Diagnostic> (); - } - - internal CodeActionContainer (List<ValidCodeDiagnosticAction> codeDiagnosticActions, List<ValidCodeAction> codeRefactoringActions, List<Diagnostic> diagnosticsAtCaret) + internal CodeActionContainer (ImmutableArray<CodeFixCollection> codeDiagnosticActions, ImmutableArray<CodeRefactoring> codeRefactoringActions) { - if (codeDiagnosticActions == null) - throw new ArgumentNullException ("codeDiagnosticActions"); - if (codeRefactoringActions == null) - throw new ArgumentNullException ("codeRefactoringActions"); - if (diagnosticsAtCaret == null) - throw new ArgumentNullException ("diagnosticsAtCaret"); CodeFixActions = codeDiagnosticActions; CodeRefactoringActions = codeRefactoringActions; - DiagnosticsAtCaret = diagnosticsAtCaret; } } }
\ No newline at end of file diff --git a/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeActions/CodeActionEditorExtension.cs b/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeActions/CodeActionEditorExtension.cs index 941aba52af..e8fa0110be 100644 --- a/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeActions/CodeActionEditorExtension.cs +++ b/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeActions/CodeActionEditorExtension.cs @@ -35,6 +35,7 @@ using System.Threading.Tasks; using Gtk; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CodeRefactorings; using Microsoft.CodeAnalysis.Formatting; using Microsoft.CodeAnalysis.Text; using MonoDevelop.AnalysisCore; @@ -100,8 +101,6 @@ namespace MonoDevelop.CodeActions Task<CodeActionContainer> smartTagTask; CancellationTokenSource quickFixCancellationTokenSource = new CancellationTokenSource (); - List<CodeDiagnosticFixDescriptor> codeFixes; - void HandleCaretPositionChanged (object sender, EventArgs e) { if (Editor.IsInAtomicUndo) @@ -110,8 +109,8 @@ namespace MonoDevelop.CodeActions if (AnalysisOptions.EnableFancyFeatures && DocumentContext.ParsedDocument != null) { if (HasCurrentFixes) { var curOffset = Editor.CaretOffset; - foreach (var fix in smartTagTask.Result.AllValidCodeActions) { - if (!fix.ValidSegment.Contains (curOffset)) { + foreach (var fix in smartTagTask.Result.CodeFixActions) { + if (!fix.TextSpan.Contains (curOffset)) { RemoveWidget (); break; } @@ -124,6 +123,8 @@ namespace MonoDevelop.CodeActions } } + static ICodeFixService codeFixService = Ide.Composition.CompositionManager.GetExportedValue<ICodeFixService> (); + static ICodeRefactoringService codeRefactoringService = Ide.Composition.CompositionManager.GetExportedValue<ICodeRefactoringService> (); internal Task<CodeActionContainer> GetCurrentFixesAsync (CancellationToken cancellationToken) { var loc = Editor.CaretOffset; @@ -132,80 +133,19 @@ namespace MonoDevelop.CodeActions return Task.FromResult (CodeActionContainer.Empty); } TextSpan span; - if (Editor.IsSomethingSelected) { var selectionRange = Editor.SelectionRange; span = selectionRange.Offset >= 0 ? TextSpan.FromBounds (selectionRange.Offset, selectionRange.EndOffset) : TextSpan.FromBounds (loc, loc); } else { span = TextSpan.FromBounds (loc, loc); } - var rExt = Editor.GetContent<ResultsEditorExtension> (); - var errorList = Editor - .GetTextSegmentMarkersAt (Editor.CaretOffset) - .OfType<IErrorMarker> () - .Where (rm => !string.IsNullOrEmpty (rm.Error.Id)).ToList (); + return Task.Run (async delegate { try { - var result = await CodeDiagnosticRunner.Check (new AnalysisDocument (Editor, DocumentContext), cancellationToken).ConfigureAwait (false); - var diagnosticsAtCaret = result.OfType<DiagnosticResult> ().Where (d => d.Region.Contains (loc)).Select (d => d.Diagnostic).ToList (); + var fixes = await codeFixService.GetFixesAsync (ad, span, true, cancellationToken); + var refactorings = await codeRefactoringService.GetRefactoringsAsync (ad, span, cancellationToken); - var codeIssueFixes = new List<ValidCodeDiagnosticAction> (); - var diagnosticIds = diagnosticsAtCaret.Select (diagnostic => diagnostic.Id).Concat (errorList.Select (rm => rm.Error.Id)).ToList (); - if (codeFixes == null) { - codeFixes = (await CodeRefactoringService.GetCodeFixesAsync (DocumentContext, CodeRefactoringService.MimeTypeToLanguage (Editor.MimeType), cancellationToken).ConfigureAwait (false)).ToList (); - } - var root = await ad.GetSyntaxRootAsync (cancellationToken).ConfigureAwait (false); - foreach (var cfp in codeFixes) { - if (cancellationToken.IsCancellationRequested) - return CodeActionContainer.Empty; - var provider = cfp.GetCodeFixProvider (); - if (!provider.FixableDiagnosticIds.Any (diagnosticIds.Contains)) - continue; - - // These two delegates were factored out, as using them as lambdas in the inner loop creates more captures than declaring them here. - Func<Diagnostic, bool> providerIdsContain = d => provider.FixableDiagnosticIds.Contains (d.Id); - Action<Microsoft.CodeAnalysis.CodeActions.CodeAction, ImmutableArray<Diagnostic>> codeFixRegistration = (ca, d) => codeIssueFixes.Add (new ValidCodeDiagnosticAction (cfp, ca, d, d [0].Location.SourceSpan)); - try { - var groupedDiagnostics = diagnosticsAtCaret - .Concat (errorList.Select (em => em.Error.Tag) - .OfType<Diagnostic> ()) - .GroupBy (d => d.Location.SourceSpan); - foreach (var g in groupedDiagnostics) { - if (cancellationToken.IsCancellationRequested) - return CodeActionContainer.Empty; - var diagnosticSpan = g.Key; - var validDiagnostics = g.Where (providerIdsContain).ToImmutableArray (); - if (validDiagnostics.Length == 0) { - continue; - } - if (diagnosticSpan.Start < 0 || diagnosticSpan.End > root.Span.End) { - continue; - } - await provider.RegisterCodeFixesAsync (new CodeFixContext (ad, diagnosticSpan, validDiagnostics, codeFixRegistration, cancellationToken)).ConfigureAwait (false); - - // TODO: Is that right ? Currently it doesn't really make sense to run one code fix provider on several overlapping diagnostics at the same location - // However the generate constructor one has that case and if I run it twice the same code action is generated twice. So there is a dupe check problem there. - // Work around for now is to only take the first diagnostic batch. - break; - } - } catch (OperationCanceledException) { - return CodeActionContainer.Empty; - } catch (AggregateException ae) { - ae.Flatten ().Handle (aex => aex is OperationCanceledException); - return CodeActionContainer.Empty; - } catch (Exception ex) { - LoggingService.LogError ("Error while getting refactorings from code fix provider " + cfp.Name, ex); - continue; - } - } - var codeActions = new List<ValidCodeAction> (); - foreach (var action in await CodeRefactoringService.GetValidActionsAsync (Editor, DocumentContext, span, cancellationToken).ConfigureAwait (false)) { - codeActions.Add (action); - } - if (cancellationToken.IsCancellationRequested) - return CodeActionContainer.Empty; - - var codeActionContainer = new CodeActionContainer (codeIssueFixes, codeActions, diagnosticsAtCaret); + var codeActionContainer = new CodeActionContainer (fixes, refactorings); Application.Invoke ((o, args) => { if (cancellationToken.IsCancellationRequested) return; @@ -229,7 +169,6 @@ namespace MonoDevelop.CodeActions } }, cancellationToken); - } async void PopupQuickFixMenu (Gdk.EventButton evt, Action<CodeFixMenu> menuAction) @@ -335,8 +274,8 @@ namespace MonoDevelop.CodeActions bool first = true; var smartTagLocBegin = offset; - foreach (var fix in fixes.CodeFixActions.Concat (fixes.CodeRefactoringActions)) { - var textSpan = fix.ValidSegment; + foreach (var fix in fixes.CodeFixActions) { + var textSpan = fix.TextSpan; if (textSpan.IsEmpty) continue; if (first || offset < textSpan.Start) { @@ -356,7 +295,7 @@ namespace MonoDevelop.CodeActions currentSmartTag.CancelPopup += CurrentSmartTag_CancelPopup; currentSmartTag.ShowPopup += CurrentSmartTag_ShowPopup; currentSmartTag.Tag = fixes; - currentSmartTag.IsVisible = fixes.CodeFixActions.Count > 0; + currentSmartTag.IsVisible = fixes.CodeFixActions.Sum (x => x.Fixes.Length) > 0; editor.AddMarker (currentSmartTag); } diff --git a/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeActions/CodeActionPanelWidget.cs b/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeActions/CodeActionPanelWidget.cs index a2ba81c573..52368ba888 100644 --- a/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeActions/CodeActionPanelWidget.cs +++ b/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeActions/CodeActionPanelWidget.cs @@ -34,6 +34,8 @@ using MonoDevelop.Refactoring; using System.Collections.Generic; using GLib; using MonoDevelop.CodeIssues; +using MonoDevelop.AnalysisCore; +using Microsoft.CodeAnalysis.Diagnostics; namespace MonoDevelop.CodeActions { @@ -59,10 +61,13 @@ namespace MonoDevelop.CodeActions readonly TreeStore treeStore = new TreeStore (typeof(string), typeof(bool), typeof(CodeRefactoringDescriptor)); readonly Dictionary<CodeRefactoringDescriptor, bool> providerStates = new Dictionary<CodeRefactoringDescriptor, bool> (); + static MonoDevelopWorkspaceDiagnosticAnalyzerProviderService.OptionsTable options = + ((MonoDevelopWorkspaceDiagnosticAnalyzerProviderService)Ide.Composition.CompositionManager.GetExportedValue<IWorkspaceDiagnosticAnalyzerProviderService> ()).Options; + void GetAllProviderStates () { var language = CodeRefactoringService.MimeTypeToLanguage (mimeType); - foreach (var node in BuiltInCodeDiagnosticProvider.GetBuiltInCodeRefactoringDescriptorsAsync (CodeRefactoringService.MimeTypeToLanguage(language), true).Result) { + foreach (var node in options.AllRefactorings.Where (x => x.Language.Contains (language))) { providerStates [node] = node.IsEnabled; } } diff --git a/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeActions/CodeFixMenuService.cs b/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeActions/CodeFixMenuService.cs index 3e1a3491c0..df1fb480aa 100644 --- a/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeActions/CodeFixMenuService.cs +++ b/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeActions/CodeFixMenuService.cs @@ -48,6 +48,7 @@ using MonoDevelop.Ide.Composition; using MonoDevelop.Ide.Editor; using MonoDevelop.Refactoring; using RefactoringEssentials; +using MonoDevelop.AnalysisCore; namespace MonoDevelop.CodeActions { @@ -76,6 +77,8 @@ namespace MonoDevelop.CodeActions usages.Set (id, CodeActionUsages [id]); } + static MonoDevelopWorkspaceDiagnosticAnalyzerProviderService.OptionsTable options = + ((MonoDevelopWorkspaceDiagnosticAnalyzerProviderService)Ide.Composition.CompositionManager.GetExportedValue<IWorkspaceDiagnosticAnalyzerProviderService> ()).Options; public static async Task<CodeFixMenu> CreateFixMenu (TextEditor editor, CodeActionContainer fixes, CancellationToken cancellationToken = default(CancellationToken)) { var menu = new CodeFixMenu (); @@ -86,191 +89,101 @@ namespace MonoDevelop.CodeActions int mnemonic = 1; - foreach (var fix in fixes.CodeFixActions.OrderByDescending (i => GetUsage (i.CodeAction.EquivalenceKey))) { - AddFixMenuItem (editor, menu, ref mnemonic, fix.CodeAction); - } + var suppressLabel = GettextCatalog.GetString ("_Suppress"); + var suppressMenu = new CodeFixMenu (suppressLabel); - bool first = true; - foreach (var fix in fixes.CodeRefactoringActions) { - if (first) { - if (menu.Items.Count > 0) - menu.Add (CodeFixMenuEntry.Separator); - first = false; - } - - AddFixMenuItem (editor, menu, ref mnemonic, fix.CodeAction); - } + var fixAllLabel = GettextCatalog.GetString ("_Fix all"); + var fixAllMenu = new CodeFixMenu (fixAllLabel); - var warningsAtCaret = (await editor.DocumentContext.AnalysisDocument.GetSemanticModelAsync (cancellationToken)) - .GetDiagnostics (new TextSpan (editor.CaretOffset, 0)) - .Where (diag => diag.Severity == DiagnosticSeverity.Warning).ToList (); + var configureLabel = GettextCatalog.GetString ("_Options"); + var configureMenu = new CodeFixMenu (configureLabel); - var caretSpan = new TextSpan (editor.CaretOffset, 0); + foreach (var cfa in fixes.CodeFixActions.OrderByDescending (x => x.Fixes.Max(y => GetUsage (y.Action.EquivalenceKey)))) { + var state = cfa.FixAllState; + var scopes = cfa.SupportedScopes; - first = true; - foreach (var warning in warningsAtCaret) { - if (string.IsNullOrWhiteSpace (warning.Descriptor.Title.ToString ())) - continue; - var label = GettextCatalog.GetString ("_Options for \u2018{0}\u2019", warning.Descriptor.Title); - var subMenu = new CodeFixMenu (label); + foreach (var fix in cfa.Fixes) { + var diag = fix.PrimaryDiagnostic; - await AddSuppressionMenuItems (subMenu, editor, warning, caretSpan); + if (options.TryGetDiagnosticDescriptor (diag.Id, out var descriptor) && !descriptor.GetIsEnabled (diag.Descriptor)) + continue; + + bool isSuppress = fix.Action is TopLevelSuppressionCodeAction; - if (subMenu.Items.Count > 0) { + if (isSuppress) { + AddFixMenuItem (editor, suppressMenu, ref mnemonic, fix.Action); + continue; + } - if (first) { - menu.Add (CodeFixMenuEntry.Separator); - first = false; + AddFixMenuItem (editor, menu, ref mnemonic, fix.Action); + + var configurable = !DescriptorHasTag (diag.Descriptor, WellKnownDiagnosticTags.NotConfigurable); + if (descriptor != null && configurable) { + var optionsMenuItem = new CodeFixMenuEntry (GettextCatalog.GetString ("_Configure Rule \u2018{0}\u2019", diag.Descriptor.Title), + delegate { + IdeApp.Workbench.ShowGlobalPreferencesDialog (null, "C#", dialog => { + var panel = dialog.GetPanel<CodeIssuePanel> ("C#"); + if (panel == null) + return; + panel.Widget.SelectCodeIssue (fix.PrimaryDiagnostic.Descriptor.Id); + }); + }); + configureMenu.Add (optionsMenuItem); } - menu.Add (subMenu); + if (!scopes.Contains (FixAllScope.Document)) + continue; + + // FIXME: No global undo yet to support fixall in project/solution + var fixState = state.WithScopeAndEquivalenceKey (FixAllScope.Document, fix.Action.EquivalenceKey); + + var provider = state.FixAllProvider; + if (provider == null) + continue; + + // FIXME: Use a real progress tracker. + var fixAll = await provider.GetFixAsync (fixState.CreateFixAllContext (new RoslynProgressTracker (), cancellationToken)); + AddFixMenuItem (editor, fixAllMenu, ref mnemonic, fixAll); } } - first = true; - foreach (var diag in fixes.DiagnosticsAtCaret) { - if (string.IsNullOrWhiteSpace (diag.Descriptor.Title.ToString ())) + bool first = true; + foreach (var refactoring in fixes.CodeRefactoringActions) { + if (options.TryGetRefactoringDescriptor (refactoring.GetType (), out var descriptor) && !descriptor.IsEnabled) continue; - var notConfigurable = DescriptorHasTag (diag.Descriptor, WellKnownDiagnosticTags.NotConfigurable); - - var label = GettextCatalog.GetString ("_Options for \u2018{0}\u2019", diag.Descriptor.Title); - var subMenu = new CodeFixMenu (label); - if (first) { - menu.Add (CodeFixMenuEntry.Separator); + if (menu.Items.Count > 0) + menu.Add (CodeFixMenuEntry.Separator); first = false; } - await AddSuppressionMenuItems (subMenu, editor, diag, caretSpan); - - var descriptor = BuiltInCodeDiagnosticProvider.GetCodeDiagnosticDescriptor (diag.Id); - - if (descriptor != null && IsConfigurable (diag.Descriptor)) { - var optionsMenuItem = new CodeFixMenuEntry (GettextCatalog.GetString ("_Configure Rule"), - delegate { - IdeApp.Workbench.ShowGlobalPreferencesDialog (null, "C#", dialog => { - var panel = dialog.GetPanel<CodeIssuePanel> ("C#"); - if (panel == null) - return; - panel.Widget.SelectCodeIssue (diag.Descriptor.Id); - }); - }); - subMenu.Add (optionsMenuItem); + foreach (var action in refactoring.Actions) { + AddFixMenuItem (editor, menu, ref mnemonic, action); } + } - foreach (var fix in fixes.CodeFixActions.OrderByDescending (i => GetUsage (i.CodeAction.EquivalenceKey))) { - if (cancellationToken.IsCancellationRequested) - return null; - var provider = fix.Diagnostic.GetCodeFixProvider ().GetFixAllProvider (); - if (provider == null) - continue; - - if (!provider.GetSupportedFixAllScopes ().Contains (FixAllScope.Document)) - continue; - - var language = editor.DocumentContext.AnalysisDocument.Project.Language; - var diagnosticdDescriptor = fix.Diagnostic?.GetCodeDiagnosticDescriptor (language); - if (diagnosticdDescriptor == null) - continue; - - var subMenu2 = new CodeFixMenu (GettextCatalog.GetString ("Fix all")); - - var diagnosticAnalyzer = diagnosticdDescriptor.GetProvider (); - if (!diagnosticAnalyzer.SupportedDiagnostics.Contains (diag.Descriptor)) - continue; - - var menuItem = new CodeFixMenuEntry ( - GettextCatalog.GetString ("In _Document"), - async delegate { await FixAll (editor, fix, provider, diagnosticAnalyzer); } - ); - subMenu2.Add (menuItem); - subMenu.Add (CodeFixMenuEntry.Separator); - subMenu.Add (subMenu2); - } + first = true; - menu.Add (subMenu); + if (fixAllMenu.Items.Count != 0) { + if (first) + menu.Add (CodeFixMenuEntry.Separator); + menu.Add (fixAllMenu); + first = false; } - return menu; - } - - static async Task FixAll (TextEditor editor, ValidCodeDiagnosticAction fix, FixAllProvider provider, DiagnosticAnalyzer diagnosticAnalyzer) - { - var diagnosticIds = diagnosticAnalyzer.SupportedDiagnostics.Select (d => d.Id).ToImmutableHashSet (); - - var analyzers = new [] { diagnosticAnalyzer }.ToImmutableArray (); - - var dict = ImmutableDictionary<Document, ImmutableArray<Diagnostic>>.Empty; - var doc = editor.DocumentContext.AnalysisDocument; - var diagnostics = await GetDiagnosticsForDocument (analyzers, doc, diagnosticIds, CancellationToken.None); - - dict = dict.Add (doc, diagnostics); - var fixAllDiagnosticProvider = new FixAllState.FixMultipleDiagnosticProvider (dict); - - var ctx = new FixAllContext ( - editor.DocumentContext.AnalysisDocument, - fix.Diagnostic.GetCodeFixProvider (), - FixAllScope.Document, - fix.CodeAction.EquivalenceKey, - diagnosticIds, - fixAllDiagnosticProvider, - default (CancellationToken) - ); - - var fixAll = await provider.GetFixAsync (ctx); - using (var undo = editor.OpenUndoGroup ()) { - await CodeDiagnosticDescriptor.RunAction (editor.DocumentContext, fixAll, default (CancellationToken)); + if (suppressMenu.Items.Count != 0) { + if (first) + menu.Add (CodeFixMenuEntry.Separator); + menu.Add (suppressMenu); + first = false; } - } - - static async Task<ImmutableArray<Diagnostic>> GetDiagnosticsForDocument (ImmutableArray<DiagnosticAnalyzer> analyzers, Microsoft.CodeAnalysis.Document doc, ImmutableHashSet<string> diagnostics, CancellationToken token) - { - var sol = doc.Project.Solution; - var options = new CompilationWithAnalyzersOptions ( - new WorkspaceAnalyzerOptions ( - new AnalyzerOptions (ImmutableArray<AdditionalText>.Empty), - sol.Options, - sol), - delegate (Exception exception, DiagnosticAnalyzer analyzer, Diagnostic diag) { - LoggingService.LogError ("Exception in diagnostic analyzer " + diag.Id + ":" + diag.GetMessage (), exception); - }, - true, - false - ); - - var model = await doc.GetSemanticModelAsync (token).ConfigureAwait (false); - var compilationWithAnalyzer = model.Compilation.WithAnalyzers (analyzers, options); - - var diagnosticList = new List<Diagnostic> (); - diagnosticList.AddRange (await compilationWithAnalyzer.GetAnalyzerSemanticDiagnosticsAsync (model, null, token).ConfigureAwait (false)); - diagnosticList.AddRange (await compilationWithAnalyzer.GetAnalyzerSemanticDiagnosticsAsync (model, null, token).ConfigureAwait (false)); - - return diagnosticList.ToImmutableArray (); - } - - static async Task AddSuppressionMenuItems (CodeFixMenu menu, TextEditor editor, Diagnostic diag, TextSpan span) - { - var workspace = editor.DocumentContext.AnalysisDocument.Project.Solution.Workspace; - var language = editor.DocumentContext.AnalysisDocument.Project.Language; - var mefExporter = (IMefHostExportProvider)workspace.Services.HostServices; - - //TODO: cache this - var suppressionProviders = mefExporter.GetExports<ISuppressionFixProvider, CodeChangeProviderMetadata> () - .ToPerLanguageMapWithMultipleLanguages(); - - foreach (var suppressionProvider in suppressionProviders[LanguageNames.CSharp].Select (lz => lz.Value)) { - if (!suppressionProvider.CanBeSuppressedOrUnsuppressed (diag)) { - continue; - } - try { - var fixes = await suppressionProvider.GetSuppressionsAsync (editor.DocumentContext.AnalysisDocument, span, new [] { diag }, default (CancellationToken)).ConfigureAwait (false); - foreach (var fix in fixes) { - AddFixMenuItem (editor, menu, fix.Action); - } - } catch (Exception e) { - LoggingService.LogError ("Error while adding fixes", e); - } + if (configureMenu.Items.Count != 0) { + if (first) + menu.Add (CodeFixMenuEntry.Separator); + menu.Add (configureMenu); + first = false; } + return menu; } static bool DescriptorHasTag (DiagnosticDescriptor desc, string tag) @@ -278,11 +191,6 @@ namespace MonoDevelop.CodeActions return desc.CustomTags.Any (c => CultureInfo.InvariantCulture.CompareInfo.Compare (c, tag) == 0); } - static bool IsConfigurable (DiagnosticDescriptor desc) - { - return !DescriptorHasTag (desc, WellKnownDiagnosticTags.NotConfigurable); - } - static CodeFixMenuEntry CreateFixMenuEntry (TextEditor editor, CodeAction fix) { int mnemonic = -1; diff --git a/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeActions/CodeRefactoringService.cs b/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeActions/CodeRefactoringService.cs index cb53d0a708..8f480dc917 100644 --- a/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeActions/CodeRefactoringService.cs +++ b/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeActions/CodeRefactoringService.cs @@ -43,117 +43,6 @@ namespace MonoDevelop.CodeActions { static class CodeRefactoringService { - readonly static List<CodeDiagnosticProvider> providers = new List<CodeDiagnosticProvider> (); - - static CodeRefactoringService () - { - providers.Add (new BuiltInCodeDiagnosticProvider ()); - - AddinManager.AddExtensionNodeHandler ("/MonoDevelop/Refactoring/CodeDiagnosticProvider", delegate (object sender, ExtensionNodeEventArgs args) { - var node = (TypeExtensionNode)args.ExtensionNode; - switch (args.Change) { - case ExtensionChange.Add: - providers.Add ((CodeDiagnosticProvider)node.CreateInstance ()); - break; - } - }); - } - - public async static Task<IEnumerable<CodeDiagnosticDescriptor>> GetCodeDiagnosticsAsync (DocumentContext documentContext, string language, CancellationToken cancellationToken = default (CancellationToken)) - { - var result = new List<CodeDiagnosticDescriptor> (); - - foreach (var provider in providers) { - if (cancellationToken.IsCancellationRequested) - return Enumerable.Empty<CodeDiagnosticDescriptor> (); - result.AddRange (await provider.GetCodeDiagnosticDescriptorsAsync (documentContext, language, cancellationToken).ConfigureAwait (false)); - } - return result; - } - - public async static Task<IEnumerable<CodeDiagnosticFixDescriptor>> GetCodeFixesAsync (DocumentContext documentContext, string language, CancellationToken cancellationToken = default (CancellationToken)) - { - var result = new List<CodeDiagnosticFixDescriptor> (); - foreach (var provider in providers) { - result.AddRange (await provider.GetCodeFixDescriptorsAsync (documentContext, language, cancellationToken).ConfigureAwait (false)); - } - return result; - } - - public async static Task<IEnumerable<CodeRefactoringDescriptor>> GetCodeRefactoringsAsync (DocumentContext documentContext, string language, CancellationToken cancellationToken = default (CancellationToken)) - { - var result = new List<CodeRefactoringDescriptor> (); - foreach (var provider in providers) { - result.AddRange (await provider.GetCodeRefactoringDescriptorsAsync (documentContext, language, cancellationToken).ConfigureAwait (false)); - } - return result; - } - - static List<CodeRefactoringDescriptor> codeRefactoringCache; - public static async Task<IEnumerable<ValidCodeAction>> GetValidActionsAsync (TextEditor editor, DocumentContext doc, TextSpan span, CancellationToken cancellationToken = default (CancellationToken)) - { - if (editor == null) - throw new ArgumentNullException ("editor"); - if (doc == null) - throw new ArgumentNullException ("doc"); - var parsedDocument = doc.ParsedDocument; - var actions = new List<ValidCodeAction> (); - if (parsedDocument == null) - return actions;
- var analysisDocument = doc.AnalysisDocument; - if (analysisDocument == null) - return actions; - - var model = await analysisDocument.GetSemanticModelAsync (cancellationToken); - if (model == null) - return actions; - var root = await model.SyntaxTree.GetRootAsync (cancellationToken).ConfigureAwait (false); - if (span.End > root.Span.End) - return actions; - TextSpan tokenSegment = span; - var token = root.FindToken (span.Start); - if (!token.IsMissing) - tokenSegment = token.Span; - try { - if (codeRefactoringCache == null) { - codeRefactoringCache = (await GetCodeRefactoringsAsync (doc, MimeTypeToLanguage (editor.MimeType), cancellationToken).ConfigureAwait (false)).ToList (); - } - foreach (var descriptor in codeRefactoringCache) { - if (!descriptor.IsEnabled) - continue; - if (cancellationToken.IsCancellationRequested || analysisDocument == null) - return Enumerable.Empty<ValidCodeAction> (); - try { - await descriptor.GetProvider ().ComputeRefactoringsAsync ( - new CodeRefactoringContext (analysisDocument, span, delegate (CodeAction ca) { - var nrca = ca as NRefactoryCodeAction; - var validSegment = tokenSegment; - if (nrca != null) - validSegment = nrca.TextSpan; - actions.Add (new ValidCodeAction (ca, validSegment)); - }, cancellationToken) - ).ConfigureAwait (false); - } catch (OperationCanceledException) { - if (cancellationToken.IsCancellationRequested) - return Enumerable.Empty<ValidCodeAction> (); - } catch (AggregateException) { - if (cancellationToken.IsCancellationRequested) - return Enumerable.Empty<ValidCodeAction> (); - } catch (Exception e) { - LoggingService.LogError ("Error while getting refactorings from " + descriptor.IdString, e); - continue; - } - } - } catch (OperationCanceledException) { - if (cancellationToken.IsCancellationRequested) - return Enumerable.Empty<ValidCodeAction> (); - } catch (AggregateException) { - if (cancellationToken.IsCancellationRequested) - return Enumerable.Empty<ValidCodeAction> (); - } - return actions; - } - public static string MimeTypeToLanguage (string mimeType) { switch (mimeType) { diff --git a/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeActions/ValidCodeAction.cs b/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeActions/ValidCodeAction.cs deleted file mode 100644 index 803cd429be..0000000000 --- a/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeActions/ValidCodeAction.cs +++ /dev/null @@ -1,47 +0,0 @@ -// -// ValidCodeAction.cs -// -// Author: -// Mike Krüger <mkrueger@xamarin.com> -// -// Copyright (c) 2015 Xamarin Inc. (http://xamarin.com) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -using Microsoft.CodeAnalysis.CodeActions; -using Microsoft.CodeAnalysis.Text; - -namespace MonoDevelop.CodeActions -{ - /// <summary> - /// Represents a code action that's valid at a specific segment. - /// </summary> - class ValidCodeAction - { - public CodeAction CodeAction { get; private set; } - - public TextSpan ValidSegment { get; private set; } - - public ValidCodeAction (CodeAction codeAction, TextSpan validSegment) - { - this.CodeAction = codeAction; - this.ValidSegment = validSegment; - } - } -}
\ No newline at end of file diff --git a/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeActions/ValidCodeDiagnosticAction.cs b/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeActions/ValidCodeDiagnosticAction.cs deleted file mode 100644 index 5c946ac714..0000000000 --- a/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeActions/ValidCodeDiagnosticAction.cs +++ /dev/null @@ -1,62 +0,0 @@ -// -// ValidCodeDiagnosticAction.cs -// -// Author: -// Mike Krüger <mkrueger@xamarin.com> -// -// Copyright (c) 2015 Xamarin Inc. (http://xamarin.com) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -using System; -using Microsoft.CodeAnalysis.CodeActions; -using MonoDevelop.Core.Text; -using MonoDevelop.CodeActions; -using Microsoft.CodeAnalysis; -using MonoDevelop.CodeIssues; -using Microsoft.CodeAnalysis.Text; -using System.Collections.Immutable; - -namespace MonoDevelop.CodeActions -{ - /// <summary> - /// Represents a code action that's valid at a specific segment that was created as a action for a specific code diagnostic. - /// </summary> - class ValidCodeDiagnosticAction : ValidCodeAction - { - ImmutableArray<Diagnostic> validDiagnostics; - - public CodeDiagnosticFixDescriptor Diagnostic { - get; - private set; - } - - public ImmutableArray<Diagnostic> ValidDiagnostics { - get { - return validDiagnostics; - } - } - - public ValidCodeDiagnosticAction (CodeDiagnosticFixDescriptor diagnostic, CodeAction codeAction, ImmutableArray<Diagnostic> validDiagnostics, TextSpan validSegment) : base (codeAction, validSegment) - { - this.Diagnostic = diagnostic; - this.validDiagnostics = validDiagnostics; - } - } -}
\ No newline at end of file diff --git a/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeIssues/AnalyzersFromAssembly.cs b/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeIssues/AnalyzersFromAssembly.cs deleted file mode 100644 index 7a0ab88b9f..0000000000 --- a/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeIssues/AnalyzersFromAssembly.cs +++ /dev/null @@ -1,148 +0,0 @@ -// -// AnalyzersFromAssembly.cs -// -// Author: -// Mike Krüger <mkrueger@xamarin.com> -// -// Copyright (c) 2015 Xamarin Inc. (http://xamarin.com) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -using System; -using System.Linq; -using System.Collections.Generic; -using System.Reflection; -using System.Threading; -using MonoDevelop.CodeIssues; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.CodeFixes; -using RefactoringEssentials; -using MonoDevelop.Core; -using System.Threading.Tasks; -using MonoDevelop.Ide.Editor; -using MonoDevelop.CodeActions; -using Microsoft.CodeAnalysis.CodeRefactorings; -using Microsoft.CodeAnalysis; -using Mono.Addins; -using MonoDevelop.Core.AddIns; - -namespace MonoDevelop.CodeIssues -{ - - class AnalyzersFromAssembly - { - public List<CodeDiagnosticDescriptor> Analyzers; - public List<CodeDiagnosticFixDescriptor> Fixes; - public List<CodeRefactoringDescriptor> Refactorings; - - public readonly static AnalyzersFromAssembly Empty = new AnalyzersFromAssembly (); - - const string extensionPath = "/MonoDevelop/Refactoring/AnalyzerAssemblies"; - string [] RuntimeEnabledAssemblies; - public AnalyzersFromAssembly () - { - Analyzers = new List<CodeDiagnosticDescriptor> (); - Fixes = new List<CodeDiagnosticFixDescriptor> (); - Refactorings = new List<CodeRefactoringDescriptor> (); - - LoadAnalyzerAssemblies (); - } - - void LoadAnalyzerAssemblies () - { - RuntimeEnabledAssemblies = AddinManager.GetExtensionNodes<AssemblyExtensionNode> (extensionPath).Select (b => b.FileName).ToArray (); - } - - readonly static string diagnosticAnalyzerAssembly = typeof (DiagnosticAnalyzerAttribute).Assembly.GetName ().Name; - - const bool ClrHeapEnabled = false; - internal void AddAssembly (System.Reflection.Assembly asm, bool force = false) - { - //FIXME; this is a really hacky arbitrary heuristic - //we should be using proper MEF composition APIs as part of the addin scan - if (!force) { - var assemblyName = asm.GetName ().Name; - if (Array.IndexOf (RuntimeEnabledAssemblies, assemblyName) == -1) { - switch (assemblyName) { - case "ClrHeapAllocationAnalyzer": - if (!ClrHeapEnabled) - return; - break; - //blacklist - case "FSharpBinding": - return; - //addin assemblies that reference roslyn - default: - var refAsm = asm.GetReferencedAssemblies (); - if (refAsm.Any (a => a.Name == diagnosticAnalyzerAssembly) && refAsm.Any (a => a.Name == "MonoDevelop.Ide")) - break; - return; - } - } - } - - try { - foreach (var type in asm.GetTypes ()) { - - //HACK: Workaround for missing UI - if (type == typeof (Microsoft.CodeAnalysis.GenerateOverrides.GenerateOverridesCodeRefactoringProvider)) - continue; - - var analyzerAttr = (DiagnosticAnalyzerAttribute)type.GetCustomAttributes (typeof (DiagnosticAnalyzerAttribute), false).FirstOrDefault (); - if (analyzerAttr != null) { - try { - var analyzer = (DiagnosticAnalyzer)Activator.CreateInstance (type); - - if (analyzer.SupportedDiagnostics.Any (IsDiagnosticSupported)) { - Analyzers.Add (new CodeDiagnosticDescriptor (analyzerAttr.Languages, type)); - } - } catch (Exception e) { - LoggingService.LogError ($"error while adding diagnostic analyzer {type} from assembly {asm.FullName}", e); - } - } - - var codeFixAttr = (ExportCodeFixProviderAttribute)type.GetCustomAttributes (typeof(ExportCodeFixProviderAttribute), false).FirstOrDefault (); - if (codeFixAttr != null) { - Fixes.Add (new CodeDiagnosticFixDescriptor (type, codeFixAttr)); - } - - var exportAttr = type.GetCustomAttributes (typeof(ExportCodeRefactoringProviderAttribute), false).FirstOrDefault () as ExportCodeRefactoringProviderAttribute; - if (exportAttr != null) { - Refactorings.Add (new CodeRefactoringDescriptor (type, exportAttr)); - } - } - } catch (ReflectionTypeLoadException ex) { - foreach (var subException in ex.LoaderExceptions) { - LoggingService.LogError ("Error while loading diagnostics in " + asm.FullName, subException); - } - throw; - } - } - - static bool IsDiagnosticSupported (DiagnosticDescriptor diag) - { - //filter out E&C analyzers as we don't support E&C - if (diag.CustomTags.Contains (WellKnownDiagnosticTags.EditAndContinue)) { - return false; - } - - return true; - } - } -} diff --git a/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeIssues/BuiltInCodeDiagnosticProvider.cs b/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeIssues/BuiltInCodeDiagnosticProvider.cs deleted file mode 100644 index 08eff6b5d7..0000000000 --- a/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeIssues/BuiltInCodeDiagnosticProvider.cs +++ /dev/null @@ -1,112 +0,0 @@ -// -// BuiltInCodeDiagnosticProvider.cs -// -// Author: -// Mike Krüger <mkrueger@xamarin.com> -// -// Copyright (c) 2015 Xamarin Inc. (http://xamarin.com) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -using System; -using System.Linq; -using System.Collections.Generic; -using System.Threading; -using MonoDevelop.CodeIssues; -using MonoDevelop.Core; -using System.Threading.Tasks; -using MonoDevelop.Ide.Editor; -using MonoDevelop.CodeActions; - -namespace MonoDevelop.CodeIssues -{ - - /// <summary> - /// Provides all IDE code diagnostics and fix provider. - /// (Scans the app domain for providers) - /// </summary> - class BuiltInCodeDiagnosticProvider : CodeDiagnosticProvider - { - readonly static Task<AnalyzersFromAssembly> builtInDiagnostics; - - static BuiltInCodeDiagnosticProvider () - { - RefactoringEssentials.NRefactory6Host.GetLocalizedString = GettextCatalog.GetString; - builtInDiagnostics = Task.Run (() => { - var result = new AnalyzersFromAssembly (); - foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) { - try { - result.AddAssembly (asm); - } catch (Exception e) { - LoggingService.LogError ("Error while loading diagnostics in " + asm.FullName, e); - } - } - return result; - }); - } - - internal static CodeDiagnosticDescriptor GetCodeDiagnosticDescriptor (string diagnosticId) - { - foreach (var builtInDescriptor in GetBuiltInCodeDiagnosticDescriptorsAsync (null).Result) { - if (builtInDescriptor.GetProvider ().SupportedDiagnostics.Any (diagnostic => diagnosticId == diagnostic.Id)) - return builtInDescriptor; - } - return null; - } - - internal async static Task<IEnumerable<CodeDiagnosticDescriptor>> GetBuiltInCodeDiagnosticDescriptorsAsync (string language, bool includeDisabledNodes = false, CancellationToken cancellationToken = default (CancellationToken)) - { - builtInDiagnostics.Wait (cancellationToken); - var diags = await builtInDiagnostics; - var builtInCodeDiagnostics = diags.Analyzers; - if (string.IsNullOrEmpty (language)) - return includeDisabledNodes ? builtInCodeDiagnostics : builtInCodeDiagnostics.Where (act => act.IsEnabled); - return includeDisabledNodes ? builtInCodeDiagnostics.Where (ca => ca.Languages.Contains (language)) : builtInCodeDiagnostics.Where (ca => ca.Languages.Contains (language) && ca.IsEnabled); - } - - public async static Task<IEnumerable<CodeDiagnosticFixDescriptor>> GetBuiltInCodeFixDescriptorsAsync (string language, CancellationToken cancellationToken = default (CancellationToken)) - { - var diags = await builtInDiagnostics.ConfigureAwait (false); - var builtInCodeFixes = diags.Fixes; - return string.IsNullOrEmpty (language) ? builtInCodeFixes : builtInCodeFixes.Where (cfp => cfp.Languages.Contains (language)); - } - - public async static Task<IEnumerable<CodeRefactoringDescriptor>> GetBuiltInCodeRefactoringDescriptorsAsync (string language, bool includeDisabledNodes = false, CancellationToken cancellationToken = default (CancellationToken)) - { - var diags = await builtInDiagnostics.ConfigureAwait (false); - var builtInCodeFixes = diags.Refactorings; - return string.IsNullOrEmpty (language) ? builtInCodeFixes : builtInCodeFixes.Where (cfp => cfp.Language.Contains (language)); - } - - public override Task<IEnumerable<CodeDiagnosticFixDescriptor>> GetCodeFixDescriptorsAsync (DocumentContext document, string language, CancellationToken cancellationToken) - { - return GetBuiltInCodeFixDescriptorsAsync (language, cancellationToken); - } - - public override Task<IEnumerable<CodeDiagnosticDescriptor>> GetCodeDiagnosticDescriptorsAsync (DocumentContext document, string language, CancellationToken cancellationToken) - { - return GetBuiltInCodeDiagnosticDescriptorsAsync (language, false, cancellationToken); - } - - public override Task<IEnumerable<CodeRefactoringDescriptor>> GetCodeRefactoringDescriptorsAsync (DocumentContext document, string language, CancellationToken cancellationToken = default (CancellationToken)) - { - return GetBuiltInCodeRefactoringDescriptorsAsync (language, false, cancellationToken); - } - } -}
\ No newline at end of file diff --git a/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeIssues/CodeDiagnosticDescriptor.cs b/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeIssues/CodeDiagnosticDescriptor.cs index 114a56ff2d..c0a9daca33 100644 --- a/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeIssues/CodeDiagnosticDescriptor.cs +++ b/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeIssues/CodeDiagnosticDescriptor.cs @@ -124,6 +124,11 @@ namespace MonoDevelop.CodeIssues return PropertyService.Get ("CodeIssues." + Languages + "." + IdString + "." + diagnostic.Id + ".enabled", true); } + internal bool GetIsEnabled (string diagnosticId) + { + return PropertyService.Get ("CodeIssues." + Languages + "." + IdString + "." + diagnosticId + ".enabled", true); + } + internal void SetIsEnabled (DiagnosticDescriptor diagnostic, bool value) { PropertyService.Set ("CodeIssues." + Languages + "." + IdString + "." + diagnostic.Id + ".enabled", value); diff --git a/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeIssues/CodeDiagnosticFixDescriptor.cs b/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeIssues/CodeDiagnosticFixDescriptor.cs deleted file mode 100644 index b70fd9e0e2..0000000000 --- a/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeIssues/CodeDiagnosticFixDescriptor.cs +++ /dev/null @@ -1,89 +0,0 @@ -// -// CodeFixDescriptor.cs -// -// Author: -// Mike Krüger <mkrueger@xamarin.com> -// -// Copyright (c) 2014 Xamarin Inc. (http://xamarin.com) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -using System; -using Microsoft.CodeAnalysis.CodeFixes; -using Microsoft.CodeAnalysis.Diagnostics; -using System.Linq; -using MonoDevelop.Core; - -namespace MonoDevelop.CodeIssues -{ - class CodeDiagnosticFixDescriptor - { - readonly Type codeFixProviderType; - readonly ExportCodeFixProviderAttribute attribute; - CodeFixProvider instance; - - public string Name { - get { - return attribute.Name; - } - } - - public string[] Languages { - get { - return attribute.Languages; - } - } - - internal CodeDiagnosticFixDescriptor (Type codeFixProviderType, ExportCodeFixProviderAttribute attribute) - { - if (codeFixProviderType == null) - throw new ArgumentNullException ("codeFixProviderType"); - if (attribute == null) - throw new ArgumentNullException ("attribute"); - this.codeFixProviderType = codeFixProviderType; - this.attribute = attribute; - } - - public CodeFixProvider GetCodeFixProvider () - { - if (instance == null) { - try { - instance = (CodeFixProvider)Activator.CreateInstance (codeFixProviderType); - } catch (InvalidCastException) { - LoggingService.LogError (codeFixProviderType + " can't be cast to CodeFixProvider."); - throw; - } - } - - return instance; - } - - public CodeDiagnosticDescriptor GetCodeDiagnosticDescriptor (string language) - { - var fixableIds = GetCodeFixProvider ().FixableDiagnosticIds.ToList (); - - foreach (var descriptor in BuiltInCodeDiagnosticProvider.GetBuiltInCodeDiagnosticDescriptorsAsync (language).Result) { - if (descriptor.GetProvider ().SupportedDiagnostics.Any (diagnostic => fixableIds.Contains (diagnostic.Id))) - return descriptor; - - } - return null; - - } - } -} diff --git a/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeIssues/CodeDiagnosticProvider.cs b/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeIssues/CodeDiagnosticProvider.cs deleted file mode 100644 index 479d24dffb..0000000000 --- a/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeIssues/CodeDiagnosticProvider.cs +++ /dev/null @@ -1,45 +0,0 @@ -// -// CodeDiagnosticProvider.cs -// -// Author: -// Mike Krüger <mkrueger@xamarin.com> -// -// Copyright (c) 2015 Xamarin Inc. (http://xamarin.com) -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -using System.Collections.Generic; -using System.Threading; -using MonoDevelop.CodeIssues; -using System.Threading.Tasks; -using MonoDevelop.Ide.Editor; -using MonoDevelop.CodeActions; - -namespace MonoDevelop.CodeIssues -{ - /// <summary> - /// The code diagnostic provider gives a list of code diagnostic and fix providers from an arbitrary source. - /// </summary> - abstract class CodeDiagnosticProvider - { - public abstract Task<IEnumerable<CodeDiagnosticDescriptor>> GetCodeDiagnosticDescriptorsAsync (DocumentContext document, string language, CancellationToken cancellationToken = default (CancellationToken)); - public abstract Task<IEnumerable<CodeDiagnosticFixDescriptor>> GetCodeFixDescriptorsAsync (DocumentContext document, string language, CancellationToken cancellationToken = default (CancellationToken)); - public abstract Task<IEnumerable<CodeRefactoringDescriptor>> GetCodeRefactoringDescriptorsAsync (DocumentContext document, string language, CancellationToken cancellationToken = default (CancellationToken)); - } -}
\ No newline at end of file diff --git a/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeIssues/CodeDiagnosticRunner.cs b/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeIssues/CodeDiagnosticRunner.cs index fda8a10732..6da380030f 100644 --- a/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeIssues/CodeDiagnosticRunner.cs +++ b/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeIssues/CodeDiagnosticRunner.cs @@ -48,131 +48,11 @@ namespace MonoDevelop.CodeIssues { static class CodeDiagnosticRunner { - static List<DiagnosticAnalyzer> providers = new List<DiagnosticAnalyzer> (); - static IEnumerable<CodeDiagnosticDescriptor> diagnostics; - static Dictionary<string, CodeDiagnosticDescriptor> diagnosticTable; - static SemaphoreSlim diagnosticLock = new SemaphoreSlim (1, 1); + static MonoDevelopWorkspaceDiagnosticAnalyzerProviderService.OptionsTable options = + ((MonoDevelopWorkspaceDiagnosticAnalyzerProviderService)Ide.Composition.CompositionManager.GetExportedValue<IWorkspaceDiagnosticAnalyzerProviderService> ()).Options; + static TraceListener consoleTraceListener = new ConsoleTraceListener (); - static bool SkipContext (DocumentContext ctx) - { - return (ctx.IsAdHocProject || !(ctx.Project is MonoDevelop.Projects.DotNetProject)); - } - - static async Task GetDescriptorTable (AnalysisDocument analysisDocument, CancellationToken cancellationToken) - { - if (diagnosticTable != null) - return; - - bool locked = await diagnosticLock.WaitAsync (Timeout.Infinite, cancellationToken).ConfigureAwait (false); - if (diagnosticTable != null) - return; - - try { - var language = CodeRefactoringService.MimeTypeToLanguage (analysisDocument.Editor.MimeType); - var alreadyAdded = new HashSet<Type> (); - - var table = new Dictionary<string, CodeDiagnosticDescriptor> (); - - diagnostics = await CodeRefactoringService.GetCodeDiagnosticsAsync (analysisDocument.DocumentContext, language, cancellationToken); - foreach (var diagnostic in diagnostics) { - if (!alreadyAdded.Add (diagnostic.DiagnosticAnalyzerType)) - continue; - var provider = diagnostic.GetProvider (); - if (provider == null) - continue; - foreach (var diag in provider.SupportedDiagnostics) - table [diag.Id] = diagnostic; - - providers.Add (provider); - } - - diagnosticTable = table; - } finally { - if (locked) - diagnosticLock.Release (); - } - } - - // Old code, until we get EditorFeatures into composition so we can switch code fix service. - public static async Task<IEnumerable<Result>> Check (AnalysisDocument analysisDocument, CancellationToken cancellationToken) - { - var input = analysisDocument.DocumentContext; - if (!AnalysisOptions.EnableFancyFeatures || input.Project == null || !input.IsCompileableInProject || input.AnalysisDocument == null) - return Enumerable.Empty<Result> (); - if (SkipContext (input)) - return Enumerable.Empty<Result> (); - try { - var model = await analysisDocument.DocumentContext.AnalysisDocument.GetSemanticModelAsync (cancellationToken); - if (model == null) - return Enumerable.Empty<Result> (); - var compilation = model.Compilation; - var language = CodeRefactoringService.MimeTypeToLanguage (analysisDocument.Editor.MimeType); - - await GetDescriptorTable (analysisDocument, cancellationToken); - - if (providers.Count == 0 || cancellationToken.IsCancellationRequested) - return Enumerable.Empty<Result> (); - #if DEBUG - Debug.Listeners.Add (consoleTraceListener); - #endif - - CompilationWithAnalyzers compilationWithAnalyzer; - var analyzers = ImmutableArray<DiagnosticAnalyzer>.Empty.AddRange (providers); - var diagnosticList = new List<Diagnostic> (); - try { - var sol = analysisDocument.DocumentContext.AnalysisDocument.Project.Solution; - var options = new CompilationWithAnalyzersOptions ( - new WorkspaceAnalyzerOptions ( - new AnalyzerOptions (ImmutableArray<AdditionalText>.Empty), - sol.Options, - sol), - delegate (Exception exception, DiagnosticAnalyzer analyzer, Diagnostic diag) { - LoggingService.LogError ("Exception in diagnostic analyzer " + diag.Id + ":" + diag.GetMessage (), exception); - }, - false, - false - ); - - compilationWithAnalyzer = compilation.WithAnalyzers (analyzers, options); - if (input.ParsedDocument == null || cancellationToken.IsCancellationRequested) - return Enumerable.Empty<Result> (); - - diagnosticList.AddRange (await compilationWithAnalyzer.GetAnalyzerSemanticDiagnosticsAsync (model, null, cancellationToken).ConfigureAwait (false)); - diagnosticList.AddRange (await compilationWithAnalyzer.GetAnalyzerSyntaxDiagnosticsAsync (model.SyntaxTree, cancellationToken).ConfigureAwait (false)); - } catch (OperationCanceledException) { - } catch (AggregateException ae) { - ae.Flatten ().Handle (ix => ix is OperationCanceledException); - } catch (Exception ex) { - LoggingService.LogError ("Error creating analyzer compilation", ex); - return Enumerable.Empty<Result> (); - } finally { - #if DEBUG - Debug.Listeners.Remove (consoleTraceListener); - #endif - CompilationWithAnalyzers.ClearAnalyzerState (analyzers); - } - - return diagnosticList - .Where (d => !d.Id.StartsWith("CS", StringComparison.Ordinal)) - .Where (d => !diagnosticTable.TryGetValue (d.Id, out var desc) || desc.GetIsEnabled (d.Descriptor)) - .Select (diagnostic => { - var res = new DiagnosticResult(diagnostic); - // var line = analysisDocument.Editor.GetLineByOffset (res.Region.Start); - // Console.WriteLine (diagnostic.Id + "/" + res.Region +"/" + analysisDocument.Editor.GetTextAt (line)); - return res; - }); - } catch (OperationCanceledException) { - return Enumerable.Empty<Result> (); - } catch (AggregateException ae) { - ae.Flatten ().Handle (ix => ix is OperationCanceledException); - return Enumerable.Empty<Result> (); - } catch (Exception e) { - LoggingService.LogError ("Error while running diagnostics.", e); - return Enumerable.Empty<Result> (); - } - } - public static async Task<IEnumerable<Result>> Check (AnalysisDocument analysisDocument, CancellationToken cancellationToken, ImmutableArray<DiagnosticData> results) { var input = analysisDocument.DocumentContext; @@ -183,20 +63,21 @@ namespace MonoDevelop.CodeIssues Debug.Listeners.Add (consoleTraceListener); #endif - await GetDescriptorTable (analysisDocument, cancellationToken); - var resultList = new List<Result> (results.Length); foreach (var data in results) { if (input.IsAdHocProject && SkipError (data.Id)) continue; + if (data.IsSuppressed) + continue; + if (DataHasTag (data, WellKnownDiagnosticTags.EditAndContinue)) continue; - if (diagnosticTable.TryGetValue (data.Id, out var descriptor) && !descriptor.IsEnabled) + if (options.TryGetDiagnosticDescriptor (data.Id, out var desc) && !desc.GetIsEnabled (data.Id)) continue; - - var diagnostic = await data.ToDiagnosticAsync (analysisDocument, cancellationToken); + + var diagnostic = await data.ToDiagnosticAsync (analysisDocument, cancellationToken, desc); resultList.Add (new DiagnosticResult (diagnostic)); } return resultList; @@ -241,17 +122,13 @@ namespace MonoDevelop.CodeIssues return !lexicalError.Contains (errorId); } - static async Task<Diagnostic> ToDiagnosticAsync (this DiagnosticData data, AnalysisDocument analysisDocument, CancellationToken cancellationToken) + static async Task<Diagnostic> ToDiagnosticAsync (this DiagnosticData data, AnalysisDocument analysisDocument, CancellationToken cancellationToken, CodeDiagnosticDescriptor desc) { var project = analysisDocument.DocumentContext.AnalysisDocument.Project; var location = await data.DataLocation.ConvertLocationAsync (project, cancellationToken).ConfigureAwait (false); var additionalLocations = await data.AdditionalLocations.ConvertLocationsAsync (project, cancellationToken).ConfigureAwait (false); - DiagnosticSeverity severity; - if (diagnosticTable.TryGetValue (data.Id, out var desc)) - severity = diagnosticTable [data.Id].GetSeverity (data.Id, data.Severity); - else - severity = data.Severity; + DiagnosticSeverity severity = desc != null ? desc.GetSeverity (data.Id, data.Severity) : data.Severity; return Diagnostic.Create ( data.Id, data.Category, data.Message, severity, data.DefaultSeverity, diff --git a/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeIssues/CodeIssuePanelWidget.cs b/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeIssues/CodeIssuePanelWidget.cs index 59a26bc5ca..db0004a6c8 100644 --- a/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeIssues/CodeIssuePanelWidget.cs +++ b/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.CodeIssues/CodeIssuePanelWidget.cs @@ -32,6 +32,8 @@ using Gdk; using GLib; using Gtk; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; +using MonoDevelop.AnalysisCore; using MonoDevelop.CodeActions; using MonoDevelop.Components; using MonoDevelop.Core; @@ -79,9 +81,16 @@ namespace MonoDevelop.CodeIssues readonly Dictionary<Tuple<CodeDiagnosticDescriptor, DiagnosticDescriptor>, DiagnosticSeverity?> severities = new Dictionary<Tuple<CodeDiagnosticDescriptor, DiagnosticDescriptor>, DiagnosticSeverity?> (); readonly Dictionary<Tuple<CodeDiagnosticDescriptor, DiagnosticDescriptor>, bool> enableState = new Dictionary<Tuple<CodeDiagnosticDescriptor, DiagnosticDescriptor>, bool> (); + static MonoDevelopWorkspaceDiagnosticAnalyzerProviderService.OptionsTable options = + ((MonoDevelopWorkspaceDiagnosticAnalyzerProviderService)Ide.Composition.CompositionManager.GetExportedValue<IWorkspaceDiagnosticAnalyzerProviderService> ()).Options; + void GetAllSeverities () { - foreach (var node in BuiltInCodeDiagnosticProvider.GetBuiltInCodeDiagnosticDescriptorsAsync (CodeRefactoringService.MimeTypeToLanguage (mimeType), true).Result) { + var language = CodeRefactoringService.MimeTypeToLanguage (mimeType); + foreach (var node in options.AllDiagnostics) { + if (!node.Languages.Contains (language)) + continue; + foreach (var subIssue in node.GetProvider ().SupportedDiagnostics.Where (IsConfigurable).ToList ()) { var sub = new Tuple<CodeDiagnosticDescriptor, DiagnosticDescriptor> (node, subIssue); severities [sub] = node.GetSeverity (subIssue); diff --git a/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.Refactoring.addin.xml b/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.Refactoring.addin.xml index 63bc190940..1b2f6f142a 100644 --- a/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.Refactoring.addin.xml +++ b/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.Refactoring.addin.xml @@ -159,6 +159,8 @@ <Assembly file="Refactoring Essentials" /> <Assembly file="Microsoft.CodeAnalysis.CSharp" /> <Assembly file="Microsoft.CodeAnalysis.CSharp.Features" /> + <Assembly file="Microsoft.CodeAnalysis.EditorFeatures" /> + <Assembly file="Microsoft.CodeAnalysis.EditorFeatures.CSharp" /> <Assembly file="Microsoft.CodeAnalysis.Features" /> <Assembly file="Microsoft.CodeAnalysis.VisualBasic" /> <Assembly file="Microsoft.CodeAnalysis.VisualBasic.Features" /> diff --git a/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.Refactoring.csproj b/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.Refactoring.csproj index bb5f9b40b2..d2b8064860 100644 --- a/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.Refactoring.csproj +++ b/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.Refactoring.csproj @@ -174,12 +174,6 @@ <Compile Include="MonoDevelop.CodeIssues\CodeDiagnosticRunner.cs" /> <Compile Include="MonoDevelop.CodeActions\CodeActionContainer.cs" /> <Compile Include="MonoDevelop.AnalysisCore\IssueMarker.cs" /> - <Compile Include="MonoDevelop.CodeIssues\CodeDiagnosticProvider.cs" /> - <Compile Include="MonoDevelop.CodeIssues\BuiltInCodeDiagnosticProvider.cs" /> - <Compile Include="MonoDevelop.CodeIssues\AnalyzersFromAssembly.cs" /> - <Compile Include="MonoDevelop.CodeActions\ValidCodeAction.cs" /> - <Compile Include="MonoDevelop.CodeActions\ValidCodeDiagnosticAction.cs" /> - <Compile Include="MonoDevelop.CodeIssues\CodeDiagnosticFixDescriptor.cs" /> <Compile Include="MonoDevelop.Refactoring\Commands.cs" /> <Compile Include="MonoDevelop.Refactoring\RefactoringSymbolInfo.cs" /> <Compile Include="MonoDevelop.CodeIssues\CodeFix.cs" /> @@ -203,6 +197,7 @@ <Compile Include="MonoDevelop.Refactoring.ExtractInterface\ExtractInterfaceDialog.cs" /> <Compile Include="MonoDevelop.AnalysisCore\MonoDevelopWorkspaceDiagnosticAnalyzerProviderService.cs" /> <Compile Include="MonoDevelop.AnalysisCore\MonoDevelopWorkspaceDiagnosticAnalyzerProviderService.AnalyzerAssemblyLoader.cs" /> + <Compile Include="MonoDevelop.AnalysisCore\MonoDevelopWorkspaceDiagnosticAnalyzerProviderService.OptionsTable.cs" /> </ItemGroup> <ItemGroup> <Folder Include="MonoDevelop.Refactoring\" /> @@ -350,6 +345,7 @@ <InternalsVisibleTo Include="MonoDevelop.CSharpBinding" /> <InternalsVisibleTo Include="MonoDevelop.PackageManagement" /> <InternalsVisibleTo Include="MonoDevelop.MonoDroid" /> + <InternalsVisibleTo Include="MonoDevelop.Refactoring.Tests" /> </ItemGroup> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <ItemGroup> diff --git a/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.Refactoring/AnalyzeWholeSolutionHandler.cs b/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.Refactoring/AnalyzeWholeSolutionHandler.cs index 8fe1b65c0e..8994b736d3 100644 --- a/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.Refactoring/AnalyzeWholeSolutionHandler.cs +++ b/main/src/addins/MonoDevelop.Refactoring/MonoDevelop.Refactoring/AnalyzeWholeSolutionHandler.cs @@ -28,11 +28,11 @@ using MonoDevelop.Components.Commands; using MonoDevelop.Ide.TypeSystem; using System.Threading.Tasks; using System.Threading; -using Microsoft.CodeAnalysis.Diagnostics; using System.Collections.Generic; using MonoDevelop.CodeActions; using MonoDevelop.Ide.Editor; using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Options; using MonoDevelop.CodeIssues; using MonoDevelop.Core; @@ -42,23 +42,26 @@ using MonoDevelop.Ide.Gui.Pads; using System.Collections.Immutable; using System.Linq; using MonoDevelop.Ide.Gui.Components; +using MonoDevelop.AnalysisCore; namespace MonoDevelop.Refactoring { class AnalyzeWholeSolutionHandler : CommandHandler { + static MonoDevelopWorkspaceDiagnosticAnalyzerProviderService.OptionsTable options = + ((MonoDevelopWorkspaceDiagnosticAnalyzerProviderService)Ide.Composition.CompositionManager.GetExportedValue<IWorkspaceDiagnosticAnalyzerProviderService> ()).Options; + internal static async Task<List<DiagnosticAnalyzer>> GetProviders (Project project) {
var providers = new List<DiagnosticAnalyzer> (); var alreadyAdded = new HashSet<Type> (); - var diagnostics = await CodeRefactoringService.GetCodeDiagnosticsAsync (new EmptyDocumentContext (project), LanguageNames.CSharp, default (CancellationToken)); + var diagnostics = options.AllDiagnostics.Where (x => x.Languages.Contains (LanguageNames.CSharp)); var diagnosticTable = new Dictionary<string, CodeDiagnosticDescriptor> (); foreach (var diagnostic in diagnostics) { - if (alreadyAdded.Contains (diagnostic.DiagnosticAnalyzerType)) - continue; if (!diagnostic.IsEnabled) continue; - alreadyAdded.Add (diagnostic.DiagnosticAnalyzerType); + if (!alreadyAdded.Add (diagnostic.DiagnosticAnalyzerType)) + continue; var provider = diagnostic.GetProvider (); if (provider == null) continue; diff --git a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.cs b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.cs index 3899d41417..f3074a2e58 100644 --- a/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.cs +++ b/main/src/core/MonoDevelop.Ide/MonoDevelop.Ide.TypeSystem/MonoDevelopWorkspace.cs @@ -103,8 +103,8 @@ namespace MonoDevelop.Ide.TypeSystem IdeApp.Workspace.ActiveConfigurationChanged += HandleActiveConfigurationChanged;
}
ISolutionCrawlerRegistrationService solutionCrawler = Services.GetService<ISolutionCrawlerRegistrationService> ();
- //Options = Options.WithChangedOption (Microsoft.CodeAnalysis.Diagnostics.InternalRuntimeDiagnosticOptions.Syntax, true)
- // .WithChangedOption (Microsoft.CodeAnalysis.Diagnostics.InternalRuntimeDiagnosticOptions.Semantic, true);
+ Options = Options.WithChangedOption (Microsoft.CodeAnalysis.Diagnostics.InternalRuntimeDiagnosticOptions.Syntax, true)
+ .WithChangedOption (Microsoft.CodeAnalysis.Diagnostics.InternalRuntimeDiagnosticOptions.Semantic, true);
if (IdeApp.Preferences.EnableSourceAnalysis) {
solutionCrawler.Register (this);
|