| File: PreferFrameworkType\PreferFrameworkTypeDiagnosticAnalyzerBase.cs | Web Access |
| Project: src\roslyn\src\Features\Core\Portable\Microsoft.CodeAnalysis.Features.csproj (Microsoft.CodeAnalysis.Features) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System.Collections.Immutable; using Microsoft.CodeAnalysis.CodeStyle; using Microsoft.CodeAnalysis.Diagnostics; namespace Microsoft.CodeAnalysis.PreferFrameworkType; internal abstract class PreferFrameworkTypeDiagnosticAnalyzerBase< TSyntaxKind, TExpressionSyntax, TTypeSyntax, TIdentifierNameSyntax, TPredefinedTypeSyntax> : AbstractBuiltInCodeStyleDiagnosticAnalyzer where TSyntaxKind : struct where TExpressionSyntax : SyntaxNode where TTypeSyntax : TExpressionSyntax where TPredefinedTypeSyntax : TTypeSyntax where TIdentifierNameSyntax : TTypeSyntax { protected PreferFrameworkTypeDiagnosticAnalyzerBase() : base(IDEDiagnosticIds.PreferBuiltInOrFrameworkTypeDiagnosticId, EnforceOnBuildValues.PreferBuiltInOrFrameworkType, options: [ CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInDeclaration, CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInMemberAccess, ], new LocalizableResourceString(nameof(FeaturesResources.Use_framework_type), FeaturesResources.ResourceManager, typeof(FeaturesResources)), new LocalizableResourceString(nameof(FeaturesResources.Use_framework_type), FeaturesResources.ResourceManager, typeof(FeaturesResources))) { } public override DiagnosticAnalyzerCategory GetAnalyzerCategory() => DiagnosticAnalyzerCategory.SemanticSpanAnalysis; protected abstract ImmutableArray<TSyntaxKind> SyntaxKindsOfInterest { get; } protected abstract bool IsPredefinedTypeReplaceableWithFrameworkType(TPredefinedTypeSyntax node); protected abstract bool IsIdentifierNameReplaceableWithFrameworkType(SemanticModel semanticModel, TIdentifierNameSyntax node); protected abstract bool IsInMemberAccessOrCrefReferenceContext(TExpressionSyntax node); protected sealed override void InitializeWorker(AnalysisContext context) => context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKindsOfInterest); protected void AnalyzeNode(SyntaxNodeAnalysisContext context) { var semanticModel = context.SemanticModel; var options = context.GetAnalyzerOptions(); var cancellationToken = context.CancellationToken; // if the user never prefers this style, do not analyze at all. // we don't know the context of the node yet, so check all predefined type option preferences and bail early. if (!IsFrameworkTypePreferred(options.PreferPredefinedTypeKeywordInDeclaration) && !IsFrameworkTypePreferred(options.PreferPredefinedTypeKeywordInMemberAccess) && ShouldSkipAnalysis(context.FilterTree, context.Options, context.Compilation.Options, [ options.PreferPredefinedTypeKeywordInDeclaration.Notification, options.PreferPredefinedTypeKeywordInMemberAccess.Notification, ], context.CancellationToken)) { return; } var typeNode = (TTypeSyntax)context.Node; // check if the predefined type is replaceable with an equivalent framework type. switch (typeNode) { case TPredefinedTypeSyntax predefinedType: if (!IsPredefinedTypeReplaceableWithFrameworkType(predefinedType)) return; break; case TIdentifierNameSyntax identifierName: if (!IsIdentifierNameReplaceableWithFrameworkType(semanticModel, identifierName)) return; break; default: return; } // check we have a symbol so that the fixer can generate the right type syntax from it. if (semanticModel.GetSymbolInfo(typeNode, cancellationToken).Symbol is not ITypeSymbol typeSymbol || typeSymbol.SpecialType is SpecialType.None) { return; } // earlier we did a context insensitive check to see if this style was preferred in *any* context at all. // now, we have to make a context sensitive check to see if options settings for our context requires us to report a diagnostic. var optionValue = IsInMemberAccessOrCrefReferenceContext(typeNode) ? options.PreferPredefinedTypeKeywordInMemberAccess : options.PreferPredefinedTypeKeywordInDeclaration; if (IsFrameworkTypePreferred(optionValue)) { context.ReportDiagnostic(DiagnosticHelper.Create( Descriptor, typeNode.GetLocation(), optionValue.Notification, context.Options, additionalLocations: null, PreferFrameworkTypeConstants.Properties)); } static bool IsFrameworkTypePreferred(CodeStyleOption2<bool> optionValue) => !optionValue.Value && optionValue.Notification.Severity != ReportDiagnostic.Suppress; } }