-
Notifications
You must be signed in to change notification settings - Fork 464
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3352 from Evangelink/RS0037
RS0046: Avoid Opt suffix in nullable-enabled code
- Loading branch information
Showing
19 changed files
with
679 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
74 changes: 74 additions & 0 deletions
74
src/Roslyn.Diagnostics.Analyzers/CSharp/CSharpAvoidOptSuffixForNullableEnableCode.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
// 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.Immutable; | ||
using Analyzer.Utilities; | ||
using Analyzer.Utilities.Extensions; | ||
using Analyzer.Utilities.Lightup; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.CSharp; | ||
using Microsoft.CodeAnalysis.CSharp.Syntax; | ||
using Microsoft.CodeAnalysis.Diagnostics; | ||
using Roslyn.Diagnostics.Analyzers; | ||
|
||
namespace Roslyn.Diagnostics.CSharp.Analyzers | ||
{ | ||
/// <summary> | ||
/// RS0046: Avoid 'Opt' suffix for nullable enable code | ||
/// </summary> | ||
[DiagnosticAnalyzer(LanguageNames.CSharp)] | ||
public sealed class CSharpAvoidOptSuffixForNullableEnableCode : DiagnosticAnalyzer | ||
{ | ||
internal const string OptSuffix = "Opt"; | ||
|
||
private static readonly LocalizableString s_localizableTitle = new LocalizableResourceString(nameof(RoslynDiagnosticsAnalyzersResources.AvoidOptSuffixForNullableEnableCodeTitle), RoslynDiagnosticsAnalyzersResources.ResourceManager, typeof(RoslynDiagnosticsAnalyzersResources)); | ||
private static readonly LocalizableString s_localizableMessage = new LocalizableResourceString(nameof(RoslynDiagnosticsAnalyzersResources.AvoidOptSuffixForNullableEnableCodeMessage), RoslynDiagnosticsAnalyzersResources.ResourceManager, typeof(RoslynDiagnosticsAnalyzersResources)); | ||
private static readonly LocalizableString s_localizableDescription = new LocalizableResourceString(nameof(RoslynDiagnosticsAnalyzersResources.AvoidOptSuffixForNullableEnableCodeDescription), RoslynDiagnosticsAnalyzersResources.ResourceManager, typeof(RoslynDiagnosticsAnalyzersResources)); | ||
|
||
internal static DiagnosticDescriptor Rule = new DiagnosticDescriptor( | ||
RoslynDiagnosticIds.AvoidOptSuffixForNullableEnableCodeRuleId, | ||
s_localizableTitle, | ||
s_localizableMessage, | ||
DiagnosticCategory.RoslynDiagnosticsDesign, | ||
DiagnosticSeverity.Warning, | ||
isEnabledByDefault: true, | ||
description: s_localizableDescription, | ||
helpLinkUri: null, | ||
customTags: WellKnownDiagnosticTags.Telemetry); | ||
|
||
public sealed override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Rule); | ||
|
||
public override void Initialize(AnalysisContext context) | ||
{ | ||
context.EnableConcurrentExecution(); | ||
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); | ||
|
||
context.RegisterSyntaxNodeAction(context => | ||
{ | ||
var parameter = (ParameterSyntax)context.Node; | ||
ReportOnInvalidIdentifier(parameter.Identifier, context.SemanticModel, context.ReportDiagnostic); | ||
}, SyntaxKind.Parameter); | ||
|
||
context.RegisterSyntaxNodeAction(context => | ||
{ | ||
var variableDeclarator = (VariableDeclaratorSyntax)context.Node; | ||
ReportOnInvalidIdentifier(variableDeclarator.Identifier, context.SemanticModel, context.ReportDiagnostic); | ||
}, SyntaxKind.VariableDeclarator); | ||
} | ||
|
||
private static void ReportOnInvalidIdentifier(SyntaxToken identifier, SemanticModel semanticModel, Action<Diagnostic> reportAction) | ||
{ | ||
if (!identifier.Text.EndsWith(OptSuffix, StringComparison.Ordinal) || | ||
!semanticModel.GetNullableContext(identifier.SpanStart).AnnotationsEnabled()) | ||
{ | ||
return; | ||
} | ||
|
||
var symbol = semanticModel.GetDeclaredSymbol(identifier.Parent); | ||
if (symbol?.GetMemberOrLocalOrParameterType()?.NullableAnnotation() == Analyzer.Utilities.Lightup.NullableAnnotation.Annotated) | ||
{ | ||
reportAction(identifier.CreateDiagnostic(Rule)); | ||
} | ||
} | ||
} | ||
} |
63 changes: 63 additions & 0 deletions
63
....Diagnostics.Analyzers/CSharp/CSharpAvoidOptSuffixForNullableEnableCodeCodeFixProvider.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
// 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.Collections.Immutable; | ||
using System.Composition; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.CodeActions; | ||
using Microsoft.CodeAnalysis.CodeFixes; | ||
using Microsoft.CodeAnalysis.Rename; | ||
using Roslyn.Diagnostics.Analyzers; | ||
|
||
namespace Roslyn.Diagnostics.CSharp.Analyzers | ||
{ | ||
[ExportCodeFixProvider(LanguageNames.CSharp)] | ||
[Shared] | ||
public sealed class CSharpAvoidOptSuffixForNullableEnableCodeCodeFixProvider : CodeFixProvider | ||
{ | ||
public override ImmutableArray<string> FixableDiagnosticIds => ImmutableArray.Create(CSharpAvoidOptSuffixForNullableEnableCode.Rule.Id); | ||
|
||
public override FixAllProvider GetFixAllProvider() | ||
=> WellKnownFixAllProviders.BatchFixer; | ||
|
||
public override async Task RegisterCodeFixesAsync(CodeFixContext context) | ||
{ | ||
var title = RoslynDiagnosticsAnalyzersResources.AvoidOptSuffixForNullableEnableCodeCodeFixTitle; | ||
|
||
foreach (var diagnostic in context.Diagnostics) | ||
{ | ||
var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); | ||
var variable = root.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true); | ||
if (variable == null) | ||
{ | ||
continue; | ||
} | ||
|
||
var semanticModel = await context.Document.GetSemanticModelAsync(context.CancellationToken).ConfigureAwait(false); | ||
var variableSymbol = semanticModel.GetDeclaredSymbol(variable, context.CancellationToken); | ||
if (variableSymbol == null || variableSymbol.Name.Length <= CSharpAvoidOptSuffixForNullableEnableCode.OptSuffix.Length) | ||
{ | ||
continue; | ||
} | ||
|
||
var newName = variableSymbol.Name.Substring(0, variableSymbol.Name.Length - CSharpAvoidOptSuffixForNullableEnableCode.OptSuffix.Length); | ||
|
||
// There is no symbol matching the new name so we can register the codefix | ||
if (semanticModel.LookupSymbols(diagnostic.Location.SourceSpan.Start, variableSymbol.ContainingType, newName).IsEmpty) | ||
{ | ||
context.RegisterCodeFix( | ||
CodeAction.Create( | ||
title, | ||
cancellationToken => RemoveOptSuffixOnVariableAsync(context.Document, variableSymbol, newName, cancellationToken), | ||
equivalenceKey: title), | ||
diagnostic); | ||
} | ||
} | ||
} | ||
|
||
private static async Task<Solution> RemoveOptSuffixOnVariableAsync(Document document, ISymbol variableSymbol, string newName, CancellationToken cancellationToken) | ||
=> await Renamer.RenameSymbolAsync(document.Project.Solution, variableSymbol, newName, document.Project.Solution.Options, cancellationToken) | ||
.ConfigureAwait(false); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.