Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/monodevelop.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'main/src/addins/CSharpBinding/MonoDevelop.CSharp.Diagnostics/RemoveUnnecessaryImports/RemoveUnnecessaryImportsDiagnosticAnalyzerBase.cs')
-rw-r--r--main/src/addins/CSharpBinding/MonoDevelop.CSharp.Diagnostics/RemoveUnnecessaryImports/RemoveUnnecessaryImportsDiagnosticAnalyzerBase.cs126
1 files changed, 126 insertions, 0 deletions
diff --git a/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Diagnostics/RemoveUnnecessaryImports/RemoveUnnecessaryImportsDiagnosticAnalyzerBase.cs b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Diagnostics/RemoveUnnecessaryImports/RemoveUnnecessaryImportsDiagnosticAnalyzerBase.cs
new file mode 100644
index 0000000000..f04a068105
--- /dev/null
+++ b/main/src/addins/CSharpBinding/MonoDevelop.CSharp.Diagnostics/RemoveUnnecessaryImports/RemoveUnnecessaryImportsDiagnosticAnalyzerBase.cs
@@ -0,0 +1,126 @@
+// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Linq;
+using System.Threading;
+using Microsoft.CodeAnalysis.Shared.Extensions;
+using Microsoft.CodeAnalysis.Text;
+using Roslyn.Utilities;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.CodeAnalysis;
+using ICSharpCode.NRefactory6.CSharp;
+
+namespace MonoDevelop.CSharp.Diagnostics.RemoveUnnecessaryImports
+{
+ internal abstract class RemoveUnnecessaryImportsDiagnosticAnalyzerBase : DiagnosticAnalyzer
+ {
+ // NOTE: This is a trigger diagnostic, which doesn't show up in the ruleset editor and hence doesn't need a conventional IDE Diagnostic ID string.
+ internal const string DiagnosticFixableId = "RemoveUnnecessaryImportsFixable";
+
+ // The NotConfigurable custom tag ensures that user can't turn this diagnostic into a warning / error via
+ // ruleset editor or solution explorer. Setting messageFormat to empty string ensures that we won't display
+ // this diagnostic in the preview pane header.
+ private static readonly DiagnosticDescriptor s_fixableIdDescriptor =
+ new DiagnosticDescriptor(DiagnosticFixableId,
+ title: "", messageFormat: "", category: "",
+ defaultSeverity: DiagnosticSeverity.Hidden,
+ isEnabledByDefault: true,
+ customTags: WellKnownDiagnosticTags.NotConfigurable);
+
+ protected abstract LocalizableString GetTitleAndMessageFormatForClassificationIdDescriptor();
+
+ private DiagnosticDescriptor _classificationIdDescriptor;
+ private DiagnosticDescriptor GetClassificationIdDescriptor()
+ {
+ if (_classificationIdDescriptor == null)
+ {
+ var titleAndMessageFormat = GetTitleAndMessageFormatForClassificationIdDescriptor();
+ _classificationIdDescriptor =
+ new DiagnosticDescriptor(IDEDiagnosticIds.RemoveUnnecessaryImportsDiagnosticId,
+ titleAndMessageFormat,
+ titleAndMessageFormat,
+ DiagnosticAnalyzerCategories.RedundanciesInCode,
+ DiagnosticSeverity.Warning,
+ isEnabledByDefault: true,
+ customTags: DiagnosticCustomTags.Unnecessary);
+ }
+
+ return _classificationIdDescriptor;
+ }
+
+ private ImmutableArray<DiagnosticDescriptor> _descriptors;
+ public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
+ {
+ get
+ {
+ if (_descriptors == null)
+ {
+ _descriptors = ImmutableArray.Create(GetClassificationIdDescriptor());
+ }
+
+ return _descriptors;
+ }
+ }
+
+ public override void Initialize(AnalysisContext context)
+ {
+ context.RegisterSemanticModelAction(this.AnalyzeSemanticModel);
+ }
+
+ private void AnalyzeSemanticModel(SemanticModelAnalysisContext context)
+ {
+ if (context.IsFromGeneratedCode ())
+ return;
+ var tree = context.SemanticModel.SyntaxTree;
+ var root = tree.GetRoot();
+ var unncessaryImports = GetUnnecessaryImports(context.SemanticModel, root);
+ if (unncessaryImports != null && unncessaryImports.Any())
+ {
+ Func<SyntaxNode, SyntaxToken> getLastTokenFunc = GetLastTokenDelegateForContiguousSpans();
+ var contiguousSpans = unncessaryImports.GetContiguousSpans(getLastTokenFunc);
+ var diagnostics = CreateClassificationDiagnostics(contiguousSpans, tree).Concat(
+ CreateFixableDiagnostics(unncessaryImports, tree));
+ var spans = new List<TextSpan> ();
+ foreach (var diagnostic in diagnostics)
+ {
+ if (spans.Any (s => s.OverlapsWith (diagnostic.Location.SourceSpan)))
+ continue;
+ spans.Add (diagnostic.Location.SourceSpan);
+ context.ReportDiagnostic(diagnostic);
+ }
+ }
+ }
+
+ protected abstract IEnumerable<SyntaxNode> GetUnnecessaryImports(SemanticModel semanticModel, SyntaxNode root, CancellationToken cancellationToken = default(CancellationToken));
+ protected virtual Func<SyntaxNode, SyntaxToken> GetLastTokenDelegateForContiguousSpans()
+ {
+ return null;
+ }
+
+ // Create one diagnostic for each unnecessary span that will be classified as Unnecessary
+ private IEnumerable<Diagnostic> CreateClassificationDiagnostics(IEnumerable<TextSpan> contiguousSpans, SyntaxTree tree, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ foreach (var span in contiguousSpans)
+ {
+ if (tree.OverlapsHiddenPosition(span, cancellationToken))
+ {
+ continue;
+ }
+
+ yield return Diagnostic.Create(GetClassificationIdDescriptor(), tree.GetLocation(span));
+ }
+ }
+
+ protected abstract IEnumerable<TextSpan> GetFixableDiagnosticSpans(IEnumerable<SyntaxNode> nodes, SyntaxTree tree, CancellationToken cancellationToken = default(CancellationToken));
+
+ private IEnumerable<Diagnostic> CreateFixableDiagnostics(IEnumerable<SyntaxNode> nodes, SyntaxTree tree, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ var spans = GetFixableDiagnosticSpans(nodes, tree, cancellationToken);
+ foreach (var span in spans) {
+ yield return Diagnostic.Create(GetClassificationIdDescriptor(), tree.GetLocation(span));
+ }
+ }
+ }
+}