Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add a new diagnostic/code fix to prompt analyzer authors to enable re… #3440

Merged
merged 7 commits into from
Mar 29, 2020
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
<AnalyzerNupkgAssembly Include="Microsoft.CodeAnalysis.Analyzers.dll" />
<AnalyzerNupkgAssembly Include="Microsoft.CodeAnalysis.CSharp.Analyzers.dll" />
<AnalyzerNupkgAssembly Include="Microsoft.CodeAnalysis.VisualBasic.Analyzers.dll" />
<AnalyzerNupkgFile Include="Microsoft.CodeAnalysis.Analyzers.targets" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<Project>
<!-- Workaround for https://github.com/dotnet/roslyn/issues/4655 -->
<ItemGroup Condition="Exists('$(MSBuildProjectDirectory)\AnalyzerReleases.Shipped.md')" >
<AdditionalFiles Include="AnalyzerReleases.Shipped.md" />
</ItemGroup>
<ItemGroup Condition="Exists('$(MSBuildProjectDirectory)\AnalyzerReleases.Unshipped.md')" >
<AdditionalFiles Include="AnalyzerReleases.Unshipped.md" />
</ItemGroup>
mavasani marked this conversation as resolved.
Show resolved Hide resolved
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -494,4 +494,13 @@
<data name="InvalidEntryInAnalyzerReleasesFileRuleDescription" xml:space="preserve">
<value>Invalid entry in analyzer release file.</value>
</data>
<data name="EnableAnalyzerReleaseTrackingRuleTitle" xml:space="preserve">
<value>Enable analyzer release tracking</value>
</data>
<data name="EnableAnalyzerReleaseTrackingRuleMessage" xml:space="preserve">
<value>Enable analyzer release tracking for the analyzer project containing rule '{0}'</value>
</data>
<data name="EnableAnalyzerReleaseTrackingRuleDescription" xml:space="preserve">
<value>Enabling release tracking for analyzer packages helps in tracking and documenting the analyzer diagnostics that ship and/or change with each analyzer release. See details at https://github.com/dotnet/roslyn-analyzers/blob/master/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md.</value>
</data>
</root>
1 change: 1 addition & 0 deletions src/Microsoft.CodeAnalysis.Analyzers/Core/DiagnosticIds.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,6 @@ internal static class DiagnosticIds
public const string RemoveDuplicateEntriesForAnalyzerReleaseRuleId = "RS2005";
public const string RemoveDuplicateEntriesBetweenAnalyzerReleasesRuleId = "RS2006";
public const string InvalidEntryInAnalyzerReleasesFileRuleId = "RS2007";
public const string EnableAnalyzerReleaseTrackingRuleId = "RS2008";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,8 @@ public sealed partial class DiagnosticDescriptorCreationAnalyzer : DiagnosticAna
InvalidEntryInAnalyzerReleasesFileRule,
InvalidHeaderInAnalyzerReleasesFileRule,
InvalidUndetectedEntryInAnalyzerReleasesFileRule,
InvalidRemovedOrChangedWithoutPriorNewEntryInAnalyzerReleasesFileRule);
InvalidRemovedOrChangedWithoutPriorNewEntryInAnalyzerReleasesFileRule,
EnableAnalyzerReleaseTrackingRule);

public override void Initialize(AnalysisContext context)
{
Expand Down Expand Up @@ -505,6 +506,11 @@ ConcurrentDictionary<string, ConcurrentBag<Location>> UpdateNamedTypeFactory(str
AnalyzeAnalyzerReleases(ruleId, argument, category, analyzerName, helpLink, isEnabledByDefault,
defaultSeverity, shippedData, unshippedData, operationAnalysisContext.ReportDiagnostic);
}
else if (shippedData == null && unshippedData == null)
{
var diagnostic = argument.CreateDiagnostic(EnableAnalyzerReleaseTrackingRule, ruleId);
operationAnalysisContext.ReportDiagnostic(diagnostic);
}
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,17 @@ public sealed partial class DiagnosticDescriptorCreationAnalyzer
helpLinkUri: "https://github.com/dotnet/roslyn-analyzers/blob/master/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md",
customTags: WellKnownDiagnosticTags.Telemetry);

internal static readonly DiagnosticDescriptor EnableAnalyzerReleaseTrackingRule = new DiagnosticDescriptor(
id: DiagnosticIds.EnableAnalyzerReleaseTrackingRuleId,
title: CodeAnalysisDiagnosticsResources.EnableAnalyzerReleaseTrackingRuleTitle,
messageFormat: CodeAnalysisDiagnosticsResources.EnableAnalyzerReleaseTrackingRuleMessage,
category: DiagnosticCategory.MicrosoftCodeAnalysisReleaseTracking,
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true,
description: CodeAnalysisDiagnosticsResources.EnableAnalyzerReleaseTrackingRuleDescription,
helpLinkUri: "https://github.com/dotnet/roslyn-analyzers/blob/master/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md",
customTags: WellKnownDiagnosticTags.Telemetry);

private static bool TryGetReleaseTrackingData(
ImmutableArray<AdditionalText> additionalTexts,
CancellationToken cancellationToken,
Expand All @@ -169,8 +180,8 @@ private static bool TryGetReleaseTrackingData(
if (!TryGetReleaseTrackingFiles(additionalTexts, cancellationToken, out var shippedText, out var unshippedText))
{
// TODO: Report a diagnostic that both must be specified if either shippedText or unshippedText is non-null.
shippedData = default;
unshippedData = default;
shippedData = shippedText != null ? ReleaseTrackingData.Default : null;
unshippedData = unshippedText != null ? ReleaseTrackingData.Default : null;
invalidFileDiagnostics = null;
return false;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// 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.Diagnostics;
Expand Down Expand Up @@ -57,6 +58,12 @@ public ReleaseTrackingFixAllProvider() { }
return null;
}

if (fixAllContext.CodeActionEquivalenceKey == CodeAnalysisDiagnosticsResources.EnableAnalyzerReleaseTrackingRuleTitle)
{
var projectIds = diagnosticsToFix.Select(d => d.Key.Id).ToImmutableArray();
return new FixAllAddAdditionalDocumentsAction(projectIds, fixAllContext.Solution);
}

return new FixAllAdditionalDocumentChangeAction(fixAllContext.Scope, fixAllContext.Solution, diagnosticsToFix, fixAllContext.CodeActionEquivalenceKey);
}

Expand Down Expand Up @@ -101,6 +108,10 @@ protected override async Task<Solution> GetChangedSolutionAsync(CancellationToke
var newText = await UpdateEntriesInUnshippedFileForDiagnosticsAsync(unshippedDocument, diagnostics, cancellationToken).ConfigureAwait(false);
updatedUnshippedText.Add((unshippedDocument.Id, newText));
}
else
{
throw new NotImplementedException();
}
}

Solution newSolution = _solution;
Expand Down Expand Up @@ -141,6 +152,32 @@ private static async Task<SourceText> UpdateEntriesInUnshippedFileForDiagnostics
return await UpdateEntriesInUnshippedFileAsync(unshippedDataDocument, entriesToUpdate, cancellationToken).ConfigureAwait(false);
}
}

private sealed class FixAllAddAdditionalDocumentsAction : CodeAction
{
private readonly ImmutableArray<ProjectId> _projectIds;
private readonly Solution _solution;

public FixAllAddAdditionalDocumentsAction(ImmutableArray<ProjectId> projectIds, Solution solution)
{
_projectIds = projectIds;
_solution = solution;
}

public override string Title => CodeAnalysisDiagnosticsResources.EnableAnalyzerReleaseTrackingRuleTitle;
public override string EquivalenceKey => CodeAnalysisDiagnosticsResources.EnableAnalyzerReleaseTrackingRuleTitle;

protected override async Task<Solution> GetChangedSolutionAsync(CancellationToken cancellationToken)
{
var newSolution = _solution;
foreach (var projectId in _projectIds)
{
newSolution = await AddAnalyzerReleaseTrackingFilesAsync(newSolution.GetProject(projectId)).ConfigureAwait(false);
}

return newSolution;
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,16 @@ public sealed partial class AnalyzerReleaseTrackingFix : CodeFixProvider
private const string EntryFieldSeparator = "|";
private static readonly string[] s_entryFieldSeparators = new[] { EntryFieldSeparator };

internal const string ShippedAnalyzerReleaseTrackingFileDefaultContent = @"; Shipped analyzer releases
" + CommonAnalyzerReleaseTrackingContent;
internal const string UnshippedAnalyzerReleaseTrackingFileDefaultContent = @"; Unshipped analyzer release
" + CommonAnalyzerReleaseTrackingContent;
private const string CommonAnalyzerReleaseTrackingContent = @"; https://github.com/dotnet/roslyn-analyzers/blob/master/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md

";

public override ImmutableArray<string> FixableDiagnosticIds =>
ImmutableArray.Create(DiagnosticIds.DeclareDiagnosticIdInAnalyzerReleaseRuleId, DiagnosticIds.UpdateDiagnosticIdInAnalyzerReleaseRuleId);
ImmutableArray.Create(DiagnosticIds.DeclareDiagnosticIdInAnalyzerReleaseRuleId, DiagnosticIds.UpdateDiagnosticIdInAnalyzerReleaseRuleId, DiagnosticIds.EnableAnalyzerReleaseTrackingRuleId);

public override FixAllProvider GetFixAllProvider()
=> new ReleaseTrackingFixAllProvider();
Expand Down Expand Up @@ -65,6 +73,13 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context)
}
break;

case DiagnosticIds.EnableAnalyzerReleaseTrackingRuleId:
codeAction = CodeAction.Create(
CodeAnalysisDiagnosticsResources.EnableAnalyzerReleaseTrackingRuleTitle,
cancellationToken => AddAnalyzerReleaseTrackingFilesAsync(context.Document.Project),
equivalenceKey: CodeAnalysisDiagnosticsResources.EnableAnalyzerReleaseTrackingRuleTitle);
break;

default:
Debug.Fail($"Unsupported diagnostic ID {diagnostic.Id}");
continue;
Expand All @@ -79,6 +94,25 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context)
return Task.CompletedTask;
}

private static Task<Solution> AddAnalyzerReleaseTrackingFilesAsync(Project project)
{
project = AddAdditionalDocument(project, DiagnosticDescriptorCreationAnalyzer.ShippedFileName, ShippedAnalyzerReleaseTrackingFileDefaultContent);
project = AddAdditionalDocument(project, DiagnosticDescriptorCreationAnalyzer.UnshippedFileName, UnshippedAnalyzerReleaseTrackingFileDefaultContent);
return Task.FromResult(project.Solution);

// Local functions.
static Project AddAdditionalDocument(Project project, string name, string fileContent)
{
TextDocument? additionalDocument = project.AdditionalDocuments.FirstOrDefault(doc => string.Equals(doc.Name, name, StringComparison.OrdinalIgnoreCase));
if (additionalDocument == null)
{
project = project.AddAdditionalDocument(name, fileContent).Project;
}

return project;
}
}

private static bool IsAddEntryToUnshippedFileDiagnostic(Diagnostic diagnostic, [NotNullWhen(returnValue: true)] out string? entryToAdd)
{
if (diagnostic.Properties != null &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.VisualBasic.Analyzers" />
<InternalsVisibleTo Include="Microsoft.CodeAnalysis.Analyzers.UnitTests" />
</ItemGroup>
<ItemGroup>
<None Include="..\ReleaseTrackingAnalyzers.Help.md" Link="ReleaseTrackingAnalyzers.Help.md" />
</ItemGroup>
<Import Project="..\..\Utilities\Compiler\Analyzer.Utilities.projitems" Label="Shared" />
<Import Project="..\..\Utilities\Workspaces\Workspaces.Utilities.projitems" Label="Shared" />
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,21 @@
<target state="translated">Nepoužívejte rezervovaná ID diagnostiky.</target>
<note />
</trans-unit>
<trans-unit id="EnableAnalyzerReleaseTrackingRuleDescription">
<source>Enabling release tracking for analyzer packages helps in tracking and documenting the analyzer diagnostics that ship and/or change with each analyzer release. See details at https://github.com/dotnet/roslyn-analyzers/blob/master/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md.</source>
<target state="new">Enabling release tracking for analyzer packages helps in tracking and documenting the analyzer diagnostics that ship and/or change with each analyzer release. See details at https://github.com/dotnet/roslyn-analyzers/blob/master/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md.</target>
<note />
</trans-unit>
<trans-unit id="EnableAnalyzerReleaseTrackingRuleMessage">
<source>Enable analyzer release tracking for the analyzer project containing rule '{0}'</source>
<target state="new">Enable analyzer release tracking for the analyzer project containing rule '{0}'</target>
<note />
</trans-unit>
<trans-unit id="EnableAnalyzerReleaseTrackingRuleTitle">
<source>Enable analyzer release tracking</source>
<target state="new">Enable analyzer release tracking</target>
<note />
</trans-unit>
<trans-unit id="EnableConcurrentExecutionDescription">
<source>Enable concurrent execution</source>
<target state="translated">Povolit souběžné provádění</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,21 @@
<target state="translated">Verwenden Sie keine reservierten Diagnose-IDs.</target>
<note />
</trans-unit>
<trans-unit id="EnableAnalyzerReleaseTrackingRuleDescription">
<source>Enabling release tracking for analyzer packages helps in tracking and documenting the analyzer diagnostics that ship and/or change with each analyzer release. See details at https://github.com/dotnet/roslyn-analyzers/blob/master/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md.</source>
<target state="new">Enabling release tracking for analyzer packages helps in tracking and documenting the analyzer diagnostics that ship and/or change with each analyzer release. See details at https://github.com/dotnet/roslyn-analyzers/blob/master/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md.</target>
<note />
</trans-unit>
<trans-unit id="EnableAnalyzerReleaseTrackingRuleMessage">
<source>Enable analyzer release tracking for the analyzer project containing rule '{0}'</source>
<target state="new">Enable analyzer release tracking for the analyzer project containing rule '{0}'</target>
<note />
</trans-unit>
<trans-unit id="EnableAnalyzerReleaseTrackingRuleTitle">
<source>Enable analyzer release tracking</source>
<target state="new">Enable analyzer release tracking</target>
<note />
</trans-unit>
<trans-unit id="EnableConcurrentExecutionDescription">
<source>Enable concurrent execution</source>
<target state="translated">Gleichzeitige Ausführung aktivieren</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,21 @@
<target state="translated">No use identificadores de diagnóstico reservados.</target>
<note />
</trans-unit>
<trans-unit id="EnableAnalyzerReleaseTrackingRuleDescription">
<source>Enabling release tracking for analyzer packages helps in tracking and documenting the analyzer diagnostics that ship and/or change with each analyzer release. See details at https://github.com/dotnet/roslyn-analyzers/blob/master/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md.</source>
<target state="new">Enabling release tracking for analyzer packages helps in tracking and documenting the analyzer diagnostics that ship and/or change with each analyzer release. See details at https://github.com/dotnet/roslyn-analyzers/blob/master/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md.</target>
<note />
</trans-unit>
<trans-unit id="EnableAnalyzerReleaseTrackingRuleMessage">
<source>Enable analyzer release tracking for the analyzer project containing rule '{0}'</source>
<target state="new">Enable analyzer release tracking for the analyzer project containing rule '{0}'</target>
<note />
</trans-unit>
<trans-unit id="EnableAnalyzerReleaseTrackingRuleTitle">
<source>Enable analyzer release tracking</source>
<target state="new">Enable analyzer release tracking</target>
<note />
</trans-unit>
<trans-unit id="EnableConcurrentExecutionDescription">
<source>Enable concurrent execution</source>
<target state="translated">Habilitar la ejecución simultánea</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,21 @@
<target state="translated">N'utilisez pas d'ID de diagnostic réservés.</target>
<note />
</trans-unit>
<trans-unit id="EnableAnalyzerReleaseTrackingRuleDescription">
<source>Enabling release tracking for analyzer packages helps in tracking and documenting the analyzer diagnostics that ship and/or change with each analyzer release. See details at https://github.com/dotnet/roslyn-analyzers/blob/master/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md.</source>
<target state="new">Enabling release tracking for analyzer packages helps in tracking and documenting the analyzer diagnostics that ship and/or change with each analyzer release. See details at https://github.com/dotnet/roslyn-analyzers/blob/master/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md.</target>
<note />
</trans-unit>
<trans-unit id="EnableAnalyzerReleaseTrackingRuleMessage">
<source>Enable analyzer release tracking for the analyzer project containing rule '{0}'</source>
<target state="new">Enable analyzer release tracking for the analyzer project containing rule '{0}'</target>
<note />
</trans-unit>
<trans-unit id="EnableAnalyzerReleaseTrackingRuleTitle">
<source>Enable analyzer release tracking</source>
<target state="new">Enable analyzer release tracking</target>
<note />
</trans-unit>
<trans-unit id="EnableConcurrentExecutionDescription">
<source>Enable concurrent execution</source>
<target state="translated">Activer l'exécution simultanée</target>
Expand Down
Loading