提交 d6b1015e 编写于 作者: B Balaji Krishnan

Check options and bail early in analyzer code.

上级 0aa2fca7
// 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 Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.Options;
......@@ -38,6 +39,12 @@ internal abstract class PreferFrameworkTypeDiagnosticAnalyzerBase<TSyntaxKind, T
DiagnosticSeverity.Hidden,
isEnabledByDefault: true);
private PerLanguageOption<CodeStyleOption<bool>> GetOptionForDeclarationContext =>
CodeStyleOptions.PreferIntrinsicPredefinedTypeKeywordInDeclaration;
private PerLanguageOption<CodeStyleOption<bool>> GetOptionForMemberAccessContext =>
CodeStyleOptions.PreferIntrinsicPredefinedTypeKeywordInMemberAccess;
public bool RunInProcess => true;
public DiagnosticAnalyzerCategory GetAnalyzerCategory() => DiagnosticAnalyzerCategory.SemanticSpanAnalysis;
......@@ -62,6 +69,17 @@ protected void AnalyzeNode(SyntaxNodeAnalysisContext context)
return;
}
var semanticModel = context.SemanticModel;
var cancellationToken = context.CancellationToken;
var language = semanticModel.Language;
// 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 (!IsStylePreferred(optionSet, language))
{
return;
}
var predefinedTypeNode = (TPredefinedTypeSyntax)context.Node;
// check if the predefined type is replaceable with an equivalent framework type.
......@@ -70,9 +88,6 @@ protected void AnalyzeNode(SyntaxNodeAnalysisContext context)
return;
}
var semanticModel = context.SemanticModel;
var cancellationToken = context.CancellationToken;
// check we have a symbol so that the fixer can generate the right type syntax from it.
var typeSymbol = semanticModel.GetSymbolInfo(predefinedTypeNode, cancellationToken).Symbol as ITypeSymbol;
if (typeSymbol == null)
......@@ -80,35 +95,63 @@ protected void AnalyzeNode(SyntaxNodeAnalysisContext context)
return;
}
string applicableDiagnosticId;
PerLanguageOption<CodeStyleOption<bool>> applicableOption;
// 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.
string diagnosticId;
DiagnosticSeverity diagnosticSeverity;
if (ShouldReportDiagnostic(predefinedTypeNode, optionSet, language, out diagnosticId, out diagnosticSeverity))
{
var descriptor = new DiagnosticDescriptor(diagnosticId,
s_preferFrameworkTypeTitle,
s_preferFrameworkTypeMessage,
DiagnosticCategory.Style,
diagnosticSeverity,
isEnabledByDefault: true);
context.ReportDiagnostic(Diagnostic.Create(descriptor, predefinedTypeNode.GetLocation()));
}
}
/// <summary>
/// Detects the context of this occurrence of predefined type and determines if we should report it.
/// </summary>
private bool ShouldReportDiagnostic(TPredefinedTypeSyntax predefinedTypeNode, OptionSet optionSet, string language,
out string diagnosticId, out DiagnosticSeverity severity)
{
CodeStyleOption<bool> optionValue;
// we have a predefined type syntax that is either in a member access context or a declaration context.
// check the appropriate option and determine if we should report a diagnostic.
if (IsInMemberAccessOrCrefReferenceContext(predefinedTypeNode))
{
applicableOption = CodeStyleOptions.PreferIntrinsicPredefinedTypeKeywordInMemberAccess;
applicableDiagnosticId = IDEDiagnosticIds.PreferFrameworkTypeInMemberAccessDiagnosticId;
diagnosticId = IDEDiagnosticIds.PreferFrameworkTypeInMemberAccessDiagnosticId;
optionValue = optionSet.GetOption(GetOptionForMemberAccessContext, language);
}
else
{
applicableOption = CodeStyleOptions.PreferIntrinsicPredefinedTypeKeywordInDeclaration;
applicableDiagnosticId = IDEDiagnosticIds.PreferFrameworkTypeInDeclarationsDiagnosticId;
diagnosticId = IDEDiagnosticIds.PreferFrameworkTypeInDeclarationsDiagnosticId;
optionValue = optionSet.GetOption(GetOptionForDeclarationContext, language);
}
var optionValue = optionSet.GetOption(applicableOption, semanticModel.Language);
var preferFrameworkType = !optionValue.Value;
severity = optionValue.Notification.Value;
return OptionSettingPrefersFrameworkType(optionValue, severity);
}
if (preferFrameworkType && optionValue.Notification.Value != DiagnosticSeverity.Hidden)
{
var descriptor = new DiagnosticDescriptor(applicableDiagnosticId,
s_preferFrameworkTypeTitle,
s_preferFrameworkTypeMessage,
DiagnosticCategory.Style,
optionValue.Notification.Value,
isEnabledByDefault: true);
private bool IsStylePreferred(OptionSet optionSet, string language) =>
IsFrameworkTypePreferred(optionSet, GetOptionForDeclarationContext, language) ||
IsFrameworkTypePreferred(optionSet, GetOptionForMemberAccessContext, language);
context.ReportDiagnostic(Diagnostic.Create(descriptor, predefinedTypeNode.GetLocation()));
}
private bool IsFrameworkTypePreferred(OptionSet optionSet, PerLanguageOption<CodeStyleOption<bool>> option, string language)
{
var optionValue = optionSet.GetOption(option, language);
return OptionSettingPrefersFrameworkType(optionValue, optionValue.Notification.Value);
}
/// <summary>
/// checks if style is preferred and the enforcement is not None.
/// </summary>
/// <remarks>if predefined type is not preferred, it implies the preference is framework type.</remarks>
private static bool OptionSettingPrefersFrameworkType(CodeStyleOption<bool> optionValue, DiagnosticSeverity severity) =>
!optionValue.Value && severity != DiagnosticSeverity.Hidden;
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册