public bool IsFixableDiagnostic(Diagnostic diagnostic) { // We only offer fix for configurable code style diagnostics which have one of more editorconfig based storage locations. // Also skip suppressed diagnostics defensively, though the code fix engine should ideally never call us for suppressed diagnostics. if ( diagnostic.IsSuppressed || SuppressionHelpers.IsNotConfigurableDiagnostic(diagnostic) || diagnostic.Location.SourceTree == null ) { return(false); } var language = diagnostic.Location.SourceTree.Options.Language; return(IDEDiagnosticIdToOptionMappingHelper.TryGetMappedOptions( diagnostic.Id, language, out var options ) && !options.IsEmpty && options.All( o => o.StorageLocations.Any(l => l is IEditorConfigStorageLocation2) )); }
private static void AddDiagnosticIdToFadingOptionMapping(string diagnosticId, PerLanguageOption2 <bool>?fadingOption) { if (fadingOption != null) { IDEDiagnosticIdToOptionMappingHelper.AddFadingOptionMapping(diagnosticId, fadingOption); } }
private static ImmutableArray <(string diagnosticId, ImmutableHashSet <IOption2> codeStyleOptions)> GetIDEDiagnosticIdsAndOptions( string languageName) { const string diagnosticIdPrefix = "IDE"; var diagnosticIdAndOptions = new List <(string diagnosticId, ImmutableHashSet <IOption2> options)>(); var uniqueDiagnosticIds = new HashSet <string>(); foreach (var assembly in MefHostServices.DefaultAssemblies) { var analyzerReference = new AnalyzerFileReference(assembly.Location, TestAnalyzerAssemblyLoader.LoadFromFile); foreach (var analyzer in analyzerReference.GetAnalyzers(languageName)) { foreach (var descriptor in analyzer.SupportedDiagnostics) { var diagnosticId = descriptor.Id; ValidateHelpLinkForDiagnostic(diagnosticId, descriptor.HelpLinkUri); if (!diagnosticId.StartsWith(diagnosticIdPrefix) || !int.TryParse(diagnosticId.Substring(startIndex: diagnosticIdPrefix.Length), out _)) { // Ignore non-IDE diagnostic IDs (such as ENCxxxx diagnostics) and // diagnostic IDs for suggestions, fading, etc. (such as IDExxxxWithSuggestion) continue; } if (!IDEDiagnosticIdToOptionMappingHelper.TryGetMappedOptions(diagnosticId, languageName, out var options)) { options = ImmutableHashSet <IOption2> .Empty; } if (uniqueDiagnosticIds.Add(diagnosticId)) { diagnosticIdAndOptions.Add((diagnosticId, options)); } else { Assert.True(diagnosticIdAndOptions.All(tuple => tuple.diagnosticId != diagnosticId || tuple.options.SetEquals(options))); } } } } diagnosticIdAndOptions.Sort(); return(diagnosticIdAndOptions.ToImmutableArray()); }
public async Task Test_FadingOptions(string diagnosticId, bool fadingOptionValue) { var analyzer = new Analyzer(diagnosticId, throughAdditionalLocations: false); var analyzerMap = new Dictionary <string, ImmutableArray <DiagnosticAnalyzer> > { { LanguageNames.CSharp, ImmutableArray.Create <DiagnosticAnalyzer>(analyzer) } }; using var workspace = TestWorkspace.CreateCSharp(new string[] { "class A { }", "class E { }" }, parseOptions: CSharpParseOptions.Default, composition: SquiggleUtilities.CompositionWithSolutionCrawler); // Set fading option var fadingOption = GetFadingOptionForDiagnostic(diagnosticId); workspace.GlobalOptions.SetGlobalOption(new OptionKey(fadingOption, LanguageNames.CSharp), fadingOptionValue); // Add mapping from diagnostic ID to fading option IDEDiagnosticIdToOptionMappingHelper.AddFadingOptionMapping(diagnosticId, fadingOption); // Set up the tagger using var wrapper = new DiagnosticTaggerWrapper <DiagnosticsClassificationTaggerProvider, ClassificationTag>(workspace, analyzerMap); var tagger = wrapper.TaggerProvider.CreateTagger <ClassificationTag>(workspace.Documents.First().GetTextBuffer()); using var disposable = tagger as IDisposable; // test first update await wrapper.WaitForTags(); var snapshot = workspace.Documents.First().GetTextBuffer().CurrentSnapshot; var spans = tagger.GetTags(snapshot.GetSnapshotSpanCollection()).ToList(); if (!fadingOptionValue) { // We should get no tag spans when the fading option is disabled. Assert.Empty(spans); } else { // We should get a single tag span, which is diagnostic's primary location. Assert.Equal(1, spans.Count); Assert.Equal(new Span(0, 10), spans[0].Span.Span); Assert.Equal(ClassificationTypeDefinitions.UnnecessaryCode, spans[0].Tag.ClassificationType.Classification); } }
private static void AddDiagnosticIdToOptionMapping(string diagnosticId, ImmutableHashSet <ILanguageSpecificOption> options, string language) => IDEDiagnosticIdToOptionMappingHelper.AddOptionMapping(diagnosticId, options, language);
private static void AddDiagnosticIdToOptionMapping(string diagnosticId, ImmutableHashSet <IPerLanguageOption> options) => IDEDiagnosticIdToOptionMappingHelper.AddOptionMapping(diagnosticId, options);
private async Task <ImmutableArray <(string diagnosticId, string?title)> > GetThirdPartyDiagnosticIdsAndTitlesAsync(Document document, CancellationToken cancellationToken) { var tree = await document.GetRequiredSyntaxTreeAsync(cancellationToken).ConfigureAwait(false); var range = new TextSpan(0, tree.Length); // Compute diagnostics for everything that is not an IDE analyzer var diagnostics = (await _diagnosticService.GetDiagnosticsForSpanAsync(document, range, shouldIncludeDiagnostic: static diagnosticId => !(IDEDiagnosticIdToOptionMappingHelper.IsKnownIDEDiagnosticId(diagnosticId)), includeCompilerDiagnostics: true, includeSuppressedDiagnostics: false, cancellationToken: cancellationToken).ConfigureAwait(false)); // ensure more than just known diagnostics were returned if (!diagnostics.Any()) { return(ImmutableArray <(string diagnosticId, string?title)> .Empty); } return(diagnostics.SelectAsArray(static d => (d.Id, d.Title)).Distinct());