提交 62ae8a04 编写于 作者: B Balaji Krishnan

Incorporate PR feedback from @cyrusnajmabadi

Most fixes are about code style.

Major changes are in:
1. the algorithm to determine if type is apparent in creation or conversion methods.
2. option serialization/deserialization.
上级 41a68099
......@@ -32,19 +32,19 @@ public class UseExplicitTypingTests : AbstractCSharpDiagnosticProviderBasedUserD
// specify all options explicitly to override defaults.
private IDictionary<OptionKey, object> ExplicitTypingEverywhere() =>
Options(CSharpCodeStyleOptions.UseVarWherePossible, offWithInfo)
.With(CSharpCodeStyleOptions.UseVarWhenTypeIsApparent, offWithInfo)
.With(CSharpCodeStyleOptions.UseVarForIntrinsicTypes, offWithInfo);
Options(CSharpCodeStyleOptions.UseImplicitTypeWherePossible, offWithInfo)
.With(CSharpCodeStyleOptions.UseImplicitTypeWhereApparent, offWithInfo)
.With(CSharpCodeStyleOptions.UseImplicitTypeForIntrinsicTypes, offWithInfo);
private IDictionary<OptionKey, object> ExplicitTypingEnforcements() =>
Options(CSharpCodeStyleOptions.UseVarWherePossible, offWithWarning)
.With(CSharpCodeStyleOptions.UseVarWhenTypeIsApparent, offWithError)
.With(CSharpCodeStyleOptions.UseVarForIntrinsicTypes, offWithInfo);
Options(CSharpCodeStyleOptions.UseImplicitTypeWherePossible, offWithWarning)
.With(CSharpCodeStyleOptions.UseImplicitTypeWhereApparent, offWithError)
.With(CSharpCodeStyleOptions.UseImplicitTypeForIntrinsicTypes, offWithInfo);
private IDictionary<OptionKey, object> ExplicitTypingNoneEnforcement() =>
Options(CSharpCodeStyleOptions.UseVarWherePossible, offWithNone)
.With(CSharpCodeStyleOptions.UseVarWhenTypeIsApparent, offWithNone)
.With(CSharpCodeStyleOptions.UseVarForIntrinsicTypes, offWithNone);
Options(CSharpCodeStyleOptions.UseImplicitTypeWherePossible, offWithNone)
.With(CSharpCodeStyleOptions.UseImplicitTypeWhereApparent, offWithNone)
.With(CSharpCodeStyleOptions.UseImplicitTypeForIntrinsicTypes, offWithNone);
private IDictionary<OptionKey, object> Options(OptionKey option, object value)
{
......
......@@ -33,34 +33,34 @@ public class UseImplicitTypingTests : AbstractCSharpDiagnosticProviderBasedUserD
// specify all options explicitly to override defaults.
private IDictionary<OptionKey, object> ImplicitTypingEverywhere() =>
Options(CSharpCodeStyleOptions.UseVarWherePossible, onWithInfo)
.With(CSharpCodeStyleOptions.UseVarWhenTypeIsApparent, onWithInfo)
.With(CSharpCodeStyleOptions.UseVarForIntrinsicTypes, onWithInfo);
Options(CSharpCodeStyleOptions.UseImplicitTypeWherePossible, onWithInfo)
.With(CSharpCodeStyleOptions.UseImplicitTypeWhereApparent, onWithInfo)
.With(CSharpCodeStyleOptions.UseImplicitTypeForIntrinsicTypes, onWithInfo);
private IDictionary<OptionKey, object> ImplicitTypingWhereApparent() =>
Options(CSharpCodeStyleOptions.UseVarWherePossible, offWithInfo)
.With(CSharpCodeStyleOptions.UseVarWhenTypeIsApparent, onWithInfo)
.With(CSharpCodeStyleOptions.UseVarForIntrinsicTypes, offWithInfo);
Options(CSharpCodeStyleOptions.UseImplicitTypeWherePossible, offWithInfo)
.With(CSharpCodeStyleOptions.UseImplicitTypeWhereApparent, onWithInfo)
.With(CSharpCodeStyleOptions.UseImplicitTypeForIntrinsicTypes, offWithInfo);
private IDictionary<OptionKey, object> ImplicitTypingWhereApparentAndForIntrinsics() =>
Options(CSharpCodeStyleOptions.UseVarWherePossible, offWithInfo)
.With(CSharpCodeStyleOptions.UseVarWhenTypeIsApparent, onWithInfo)
.With(CSharpCodeStyleOptions.UseVarForIntrinsicTypes, onWithInfo);
Options(CSharpCodeStyleOptions.UseImplicitTypeWherePossible, offWithInfo)
.With(CSharpCodeStyleOptions.UseImplicitTypeWhereApparent, onWithInfo)
.With(CSharpCodeStyleOptions.UseImplicitTypeForIntrinsicTypes, onWithInfo);
private IDictionary<OptionKey, object> ImplicitTypingButKeepIntrinsics() =>
Options(CSharpCodeStyleOptions.UseVarWherePossible, onWithInfo)
.With(CSharpCodeStyleOptions.UseVarForIntrinsicTypes, offWithInfo)
.With(CSharpCodeStyleOptions.UseVarWhenTypeIsApparent, onWithInfo);
Options(CSharpCodeStyleOptions.UseImplicitTypeWherePossible, onWithInfo)
.With(CSharpCodeStyleOptions.UseImplicitTypeForIntrinsicTypes, offWithInfo)
.With(CSharpCodeStyleOptions.UseImplicitTypeWhereApparent, onWithInfo);
private IDictionary<OptionKey, object> ImplicitTypingEnforcements() =>
Options(CSharpCodeStyleOptions.UseVarWherePossible, onWithWarning)
.With(CSharpCodeStyleOptions.UseVarWhenTypeIsApparent, onWithError)
.With(CSharpCodeStyleOptions.UseVarForIntrinsicTypes, onWithInfo);
Options(CSharpCodeStyleOptions.UseImplicitTypeWherePossible, onWithWarning)
.With(CSharpCodeStyleOptions.UseImplicitTypeWhereApparent, onWithError)
.With(CSharpCodeStyleOptions.UseImplicitTypeForIntrinsicTypes, onWithInfo);
private IDictionary<OptionKey, object> ImplicitTypingNoneEnforcement() =>
Options(CSharpCodeStyleOptions.UseVarWherePossible, onWithNone)
.With(CSharpCodeStyleOptions.UseVarWhenTypeIsApparent, onWithNone)
.With(CSharpCodeStyleOptions.UseVarForIntrinsicTypes, onWithNone);
Options(CSharpCodeStyleOptions.UseImplicitTypeWherePossible, onWithNone)
.With(CSharpCodeStyleOptions.UseImplicitTypeWhereApparent, onWithNone)
.With(CSharpCodeStyleOptions.UseImplicitTypeForIntrinsicTypes, onWithNone);
private IDictionary<OptionKey, object> Options(OptionKey option, object value)
{
......@@ -906,6 +906,30 @@ static void M()
}", options: ImplicitTypingEverywhere());
}
[WpfFact, Trait(Traits.Feature, Traits.Features.CodeActionsUseImplicitTyping)]
public async Task SuggestVarInUnCheckedExpression()
{
await TestAsync(
@"using System;
class C
{
static void M()
{
long number1 = int.MaxValue + 20L;
[|int|] intNumber = unchecked((int)number1);
}
}",
@"using System;
class C
{
static void M()
{
long number1 = int.MaxValue + 20L;
var intNumber = unchecked((int)number1);
}
}", options: ImplicitTypingEverywhere());
}
[WpfFact, Trait(Traits.Feature, Traits.Features.CodeActionsUseImplicitTyping)]
public async Task SuggestVarInAwaitExpression()
{
......@@ -1182,6 +1206,56 @@ public void Process()
}", options: ImplicitTypingWhereApparent());
}
[WpfFact, Trait(Traits.Feature, Traits.Features.CodeActionsUseImplicitTyping)]
public async Task SuggestVarWhereTypingIsEvident_CreationHelpers()
{
await TestAsync(
@"class C
{
public void Process()
{
[|XElement|] a = XElement.Load();
}
}
class XElement
{
internal static XElement Load() => return null;
}",
@"class C
{
public void Process()
{
var a = XElement.Load();
}
}
class XElement
{
internal static XElement Load() => return null;
}", options: ImplicitTypingWhereApparent());
}
[WpfFact, Trait(Traits.Feature, Traits.Features.CodeActionsUseImplicitTyping)]
public async Task SuggestVarWhereTypingIsEvident_CreationHelpersWithInferredTypeArguments()
{
await TestAsync(
@"using System;
class C
{
public void Process()
{
[|Tuple<int, bool>|] a = Tuple.Create(0, true);
}
}",
@"using System;
class C
{
public void Process()
{
var a = Tuple.Create(0, true);
}
}", options: ImplicitTypingWhereApparent());
}
[WpfFact, Trait(Traits.Feature, Traits.Features.CodeActionsUseImplicitTyping)]
public async Task SuggestVarWhereTypingIsEvident_ConvertToType()
{
......
......@@ -908,38 +908,38 @@ internal class CSharpFeaturesResources {
}
/// <summary>
/// Looks up a localized string similar to Use explicit typing instead of &apos;var&apos;.
/// Looks up a localized string similar to Use explicit type instead of &apos;var&apos;.
/// </summary>
internal static string UseExplicitTyping {
internal static string UseExplicitType {
get {
return ResourceManager.GetString("UseExplicitTyping", resourceCulture);
return ResourceManager.GetString("UseExplicitType", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Use explicit typing.
/// Looks up a localized string similar to Use explicit type.
/// </summary>
internal static string UseExplicitTypingDiagnosticTitle {
internal static string UseExplicitTypeDiagnosticTitle {
get {
return ResourceManager.GetString("UseExplicitTypingDiagnosticTitle", resourceCulture);
return ResourceManager.GetString("UseExplicitTypeDiagnosticTitle", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to use &apos;var&apos; instead of typename.
/// Looks up a localized string similar to use &apos;var&apos; instead of explicit type.
/// </summary>
internal static string UseImplicitTyping {
internal static string UseImplicitType {
get {
return ResourceManager.GetString("UseImplicitTyping", resourceCulture);
return ResourceManager.GetString("UseImplicitType", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Use implicit typing.
/// Looks up a localized string similar to Use implicit type.
/// </summary>
internal static string UseImplicitTypingDiagnosticTitle {
internal static string UseImplicitTypeDiagnosticTitle {
get {
return ResourceManager.GetString("UseImplicitTypingDiagnosticTitle", resourceCulture);
return ResourceManager.GetString("UseImplicitTypeDiagnosticTitle", resourceCulture);
}
}
......
......@@ -437,16 +437,16 @@
<data name="DelegateInvocationCanBeSimplified" xml:space="preserve">
<value>Delegate invocation can be simplified.</value>
</data>
<data name="UseExplicitTyping" xml:space="preserve">
<value>Use explicit typing instead of 'var'</value>
<data name="UseExplicitType" xml:space="preserve">
<value>Use explicit type instead of 'var'</value>
</data>
<data name="UseExplicitTypingDiagnosticTitle" xml:space="preserve">
<value>Use explicit typing</value>
<data name="UseExplicitTypeDiagnosticTitle" xml:space="preserve">
<value>Use explicit type</value>
</data>
<data name="UseImplicitTyping" xml:space="preserve">
<value>use 'var' instead of typename</value>
<data name="UseImplicitType" xml:space="preserve">
<value>use 'var' instead of explicit type</value>
</data>
<data name="UseImplicitTypingDiagnosticTitle" xml:space="preserve">
<value>Use implicit typing</value>
<data name="UseImplicitTypeDiagnosticTitle" xml:space="preserve">
<value>Use implicit type</value>
</data>
</root>
\ No newline at end of file
......@@ -35,18 +35,10 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
return;
}
var node = token.GetAncestors<SyntaxNode>().First(n => n.Span.Contains(span));
if (node?.IsKind(SyntaxKind.PredefinedType,
SyntaxKind.ArrayType,
SyntaxKind.IdentifierName,
SyntaxKind.GenericName,
SyntaxKind.AliasQualifiedName) == false)
{
return;
}
var node = root.FindNode(span, getInnermostNodeForTie: true);
var codeAction = new MyCodeAction(
CSharpFeaturesResources.UseExplicitTyping,
CSharpFeaturesResources.UseExplicitType,
c => HandleDeclaration(document, root, node, context.CancellationToken));
context.RegisterCodeFix(codeAction, context.Diagnostics.First());
......@@ -69,7 +61,7 @@ private async Task<Document> HandleDeclaration(Document document, SyntaxNode roo
else
{
Debug.Assert(false, $"unhandled kind {declarationContext.Kind().ToString()}");
return null;
return document;
}
var typeSymbol = semanticModel.GetTypeInfo(typeSyntax).ConvertedType;
......
......@@ -32,25 +32,20 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context)
return;
}
var node = token.GetAncestors<SyntaxNode>().First(n => n.Span.Contains(span));
if (node == null ||
!(node.IsKind(SyntaxKind.PredefinedType) ||
node.IsKind(SyntaxKind.ArrayType) ||
node.IsKind(SyntaxKind.IdentifierName) ||
node.IsKind(SyntaxKind.GenericName) ||
node.IsKind(SyntaxKind.AliasQualifiedName)))
var node = root.FindNode(span, getInnermostNodeForTie: true);
if (node == null || !SyntaxFacts.IsTypeSyntax(node.Kind()))
{
return;
}
var codeAction = new MyCodeAction(
CSharpFeaturesResources.UseImplicitTyping,
c => ReplaceTypeWithVar(document, root, node));
CSharpFeaturesResources.UseImplicitType,
c => ReplaceTypeWithVarAsync(document, root, node));
context.RegisterCodeFix(codeAction, context.Diagnostics.First());
}
private static Task<Document> ReplaceTypeWithVar(Document document, SyntaxNode root, SyntaxNode node)
private static Task<Document> ReplaceTypeWithVarAsync(Document document, SyntaxNode root, SyntaxNode node)
{
var implicitType = SyntaxFactory.IdentifierName("var")
.WithLeadingTrivia(node.GetLeadingTrivia())
......
......@@ -17,8 +17,8 @@ internal static class CSharpCodeStyleOptions
// TODO: get sign off on public api changes.
public static readonly Option<bool> UseVarWhenDeclaringLocals = new Option<bool>(FeatureName, "UseVarWhenDeclaringLocals", defaultValue: true);
public static readonly Option<SimpleCodeStyleOption> UseVarForIntrinsicTypes = new Option<SimpleCodeStyleOption>(FeatureName, "UseImplicitTypingForIntrinsics", defaultValue: SimpleCodeStyleOption.Default);
public static readonly Option<SimpleCodeStyleOption> UseVarWhenTypeIsApparent = new Option<SimpleCodeStyleOption>(FeatureName, "UseImplicitTypingWhereApparent", defaultValue: SimpleCodeStyleOption.Default);
public static readonly Option<SimpleCodeStyleOption> UseVarWherePossible = new Option<SimpleCodeStyleOption>(FeatureName, "UseImplicitTypingWherePossible", defaultValue: SimpleCodeStyleOption.Default);
public static readonly Option<SimpleCodeStyleOption> UseImplicitTypeForIntrinsicTypes = new Option<SimpleCodeStyleOption>(FeatureName, nameof(UseImplicitTypeForIntrinsicTypes), defaultValue: SimpleCodeStyleOption.Default);
public static readonly Option<SimpleCodeStyleOption> UseImplicitTypeWhereApparent = new Option<SimpleCodeStyleOption>(FeatureName, nameof(UseImplicitTypeWhereApparent), defaultValue: SimpleCodeStyleOption.Default);
public static readonly Option<SimpleCodeStyleOption> UseImplicitTypeWherePossible = new Option<SimpleCodeStyleOption>(FeatureName, nameof(UseImplicitTypeWherePossible), defaultValue: SimpleCodeStyleOption.Default);
}
}
......@@ -14,9 +14,9 @@ internal class CSharpCodeStyleOptionsProvider : IOptionProvider
private readonly IEnumerable<IOption> _options = new List<IOption>
{
CSharpCodeStyleOptions.UseVarWhenDeclaringLocals,
CSharpCodeStyleOptions.UseVarWherePossible,
CSharpCodeStyleOptions.UseVarWhenTypeIsApparent,
CSharpCodeStyleOptions.UseVarForIntrinsicTypes
CSharpCodeStyleOptions.UseImplicitTypeWherePossible,
CSharpCodeStyleOptions.UseImplicitTypeWhereApparent,
CSharpCodeStyleOptions.UseImplicitTypeForIntrinsicTypes
}.ToImmutableArray();
public IEnumerable<IOption> GetOptions()
......
......@@ -9,6 +9,7 @@
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.Diagnostics.TypingStyles
{
......@@ -16,9 +17,9 @@ internal partial class CSharpTypingStyleDiagnosticAnalyzerBase
{
internal class State
{
private readonly Dictionary<TypingStyles, DiagnosticSeverity> _styleToSeverityMap;
private readonly Dictionary<TypeStyle, DiagnosticSeverity> _styleToSeverityMap;
public TypingStyles StylePreferences { get; private set; }
public TypeStyle TypeStyle { get; private set; }
public bool IsInIntrinsicTypeContext { get; private set; }
public bool IsTypingApparentInContext { get; private set; }
public bool IsInVariableDeclarationContext { get; }
......@@ -26,7 +27,7 @@ internal class State
public State(bool isVariableDeclarationContext)
{
this.IsInVariableDeclarationContext = isVariableDeclarationContext;
_styleToSeverityMap = new Dictionary<TypingStyles, DiagnosticSeverity>();
_styleToSeverityMap = new Dictionary<TypeStyle, DiagnosticSeverity>();
}
public static State Generate(SyntaxNode declaration, SemanticModel semanticModel, OptionSet optionSet, bool isVariableDeclarationContext, CancellationToken cancellationToken)
......@@ -40,15 +41,15 @@ public DiagnosticSeverity GetDiagnosticSeverityPreference()
{
if (IsInIntrinsicTypeContext)
{
return _styleToSeverityMap[TypingStyles.VarForIntrinsic];
return _styleToSeverityMap[TypeStyle.ImplicitTypeForIntrinsicTypes];
}
else if (IsTypingApparentInContext)
{
return _styleToSeverityMap[TypingStyles.VarWhereApparent];
return _styleToSeverityMap[TypeStyle.ImplicitTypeWhereApparent];
}
else
{
return _styleToSeverityMap[TypingStyles.VarWherePossible];
return _styleToSeverityMap[TypeStyle.ImplicitTypeWherePossible];
}
}
......@@ -57,13 +58,11 @@ public DiagnosticSeverity GetDiagnosticSeverityPreference()
private void Initialize(SyntaxNode declaration, SemanticModel semanticModel, OptionSet optionSet, CancellationToken cancellationToken)
{
this.StylePreferences = GetCurrentTypingStylePreferences(optionSet);
this.TypeStyle = GetCurrentTypingStylePreferences(optionSet);
IsTypingApparentInContext =
IsInVariableDeclarationContext
? IsTypeApparentInDeclaration((VariableDeclarationSyntax)declaration,
semanticModel, StylePreferences, cancellationToken)
: false;
&& IsTypeApparentInDeclaration((VariableDeclarationSyntax)declaration, semanticModel, TypeStyle, cancellationToken);
IsInIntrinsicTypeContext = IsIntrinsicType(declaration);
}
......@@ -72,7 +71,7 @@ private void Initialize(SyntaxNode declaration, SemanticModel semanticModel, Opt
/// Returns true if type information could be gleaned by simply looking at the given statement.
/// This typically means that the type name occurs in either left hand or right hand side of an assignment.
/// </summary>
private bool IsTypeApparentInDeclaration(VariableDeclarationSyntax variableDeclaration, SemanticModel semanticModel, TypingStyles stylePreferences, CancellationToken cancellationToken)
private bool IsTypeApparentInDeclaration(VariableDeclarationSyntax variableDeclaration, SemanticModel semanticModel, TypeStyle stylePreferences, CancellationToken cancellationToken)
{
var initializer = variableDeclaration.Variables.Single().Initializer;
var initializerExpression = GetInitializerExpression(initializer);
......@@ -86,7 +85,7 @@ private bool IsTypeApparentInDeclaration(VariableDeclarationSyntax variableDecla
// literals, use var if options allow usage here.
if (initializerExpression.IsAnyLiteralExpression())
{
return stylePreferences.HasFlag(TypingStyles.VarForIntrinsic);
return stylePreferences.HasFlag(TypeStyle.ImplicitTypeForIntrinsicTypes);
}
// constructor invocations cases:
......@@ -107,13 +106,12 @@ private bool IsTypeApparentInDeclaration(VariableDeclarationSyntax variableDecla
}
// other Conversion cases:
// a. conversion with helpers like: int.Parse, TextSpan.From methods
// a. conversion with helpers like: int.Parse methods
// b. types that implement IConvertible and then invoking .ToType()
// c. System.Convert.Totype()
var declaredTypeSymbol = semanticModel.GetTypeInfo(variableDeclaration.Type, cancellationToken).Type;
var expressionOnRightSide = initializerExpression.WalkDownParentheses();
var memberName = expressionOnRightSide.GetRightmostName();
var memberName = initializerExpression.GetRightmostName();
if (memberName == null)
{
return false;
......@@ -135,14 +133,7 @@ private bool IsTypeApparentInDeclaration(VariableDeclarationSyntax variableDecla
}
private bool IsIntrinsicType(SyntaxNode declarationStatement) =>
declarationStatement.IsKind(SyntaxKind.VariableDeclaration)
? ((VariableDeclarationSyntax)declarationStatement).Variables.Single().Initializer.Value.IsAnyLiteralExpression()
: false;
private ExpressionSyntax GetInitializerExpression(EqualsValueClauseSyntax initializer) =>
initializer.Value is CheckedExpressionSyntax
? ((CheckedExpressionSyntax)initializer.Value).Expression
: initializer.Value;
(declarationStatement as VariableDeclarationSyntax)?.Variables.Single().Initializer.Value.IsAnyLiteralExpression() == true;
private bool IsPossibleCreationOrConversionMethod(IMethodSymbol methodSymbol, ITypeSymbol declaredType, SemanticModel semanticModel, ExpressionSyntax typeName, CancellationToken cancellationToken)
{
......@@ -157,32 +148,24 @@ private bool IsPossibleCreationOrConversionMethod(IMethodSymbol methodSymbol, IT
|| IsPossibleConversionMethod(methodSymbol, declaredType, typeInInvocation, semanticModel, cancellationToken);
}
/// <summary>
/// Looks for types that have static methods that return the same type as the container.
/// e.g: int.Parse, XElement.Load, Tuple.Create etc.
/// </summary>
private bool IsPossibleCreationMethod(IMethodSymbol methodSymbol, ITypeSymbol declaredType, ITypeSymbol typeInInvocation)
{
var isTypeInfoSame = false;
// Pattern: Method name is a prefix match of one of these well known method names
// and method is a member of type being created.
// cases: int.ParseXXX, TextSpan.FromBounds,
if (methodSymbol.Name.StartsWith("Parse", StringComparison.Ordinal)
|| methodSymbol.Name.StartsWith("From", StringComparison.Ordinal))
if (!methodSymbol.IsStatic)
{
isTypeInfoSame = typeInInvocation.Equals(declaredType);
}
// Pattern: Method name is an exact match of one of these well known creation methods
// and method is a member of type being created.
// cases: node.With, Tuple.Create, State.Generate
if (methodSymbol.Name.Equals("With", StringComparison.Ordinal)
|| methodSymbol.Name.Equals("Create", StringComparison.Ordinal)
|| methodSymbol.Name.Equals("Generate", StringComparison.Ordinal))
{
isTypeInfoSame = typeInInvocation.Equals(declaredType);
return false;
}
return isTypeInfoSame;
return IsDeclaredTypeEqualToReturnType(methodSymbol, declaredType, typeInInvocation);
}
/// <summary>
/// If we have a method ToXXX and its return type is also XXX, then type name is apparent
/// e.g: Convert.ToString.
/// </summary>
private bool IsPossibleConversionMethod(IMethodSymbol methodSymbol, ITypeSymbol declaredType, ITypeSymbol typeInInvocation, SemanticModel semanticModel, CancellationToken cancellationToken)
{
// take `char` from `char? c = `
......@@ -190,44 +173,62 @@ private bool IsPossibleConversionMethod(IMethodSymbol methodSymbol, ITypeSymbol
? declaredType.GetTypeArguments().First().Name
: declaredType.Name;
// case: Convert.ToString or iConvertible.ToChar
var returnType = methodSymbol.ReturnType;
if (methodSymbol.Name.Equals("To" + declaredTypeName, StringComparison.Ordinal))
{
var convertType = semanticModel.Compilation.ConvertType();
var iConvertibleType = semanticModel.Compilation.IConvertibleType();
return typeInInvocation.Equals(convertType)
|| typeInInvocation.Equals(iConvertibleType);
return IsDeclaredTypeEqualToReturnType(methodSymbol, declaredType, typeInInvocation);
}
return false;
}
private TypingStyles GetCurrentTypingStylePreferences(OptionSet optionSet)
/// <remarks>
/// If there are type arguments on either side of assignment, we match type names instead of type equality
/// to account for inferred generic type arguments.
/// e.g: Tuple.Create(0, true) returns Tuple&lt;X,y&gt; which isn't the same as type Tuple.
/// otherwise, we match for type equivalence
/// </remarks>
private static bool IsDeclaredTypeEqualToReturnType(IMethodSymbol methodSymbol, ITypeSymbol declaredType, ITypeSymbol typeInInvocation)
{
var returnType = methodSymbol.ReturnType;
if (declaredType.GetTypeArguments().Length > 0 ||
typeInInvocation.GetTypeArguments().Length > 0)
{
return declaredType.Name.Equals(returnType.Name);
}
else
{
return declaredType.Equals(returnType);
}
}
private TypeStyle GetCurrentTypingStylePreferences(OptionSet optionSet)
{
var stylePreferences = TypingStyles.None;
var stylePreferences = TypeStyle.None;
var styleForIntrinsicTypes = optionSet.GetOption(CSharpCodeStyleOptions.UseVarForIntrinsicTypes);
var styleForApparent = optionSet.GetOption(CSharpCodeStyleOptions.UseVarWhenTypeIsApparent);
var styleForElsewhere = optionSet.GetOption(CSharpCodeStyleOptions.UseVarWherePossible);
var styleForIntrinsicTypes = optionSet.GetOption(CSharpCodeStyleOptions.UseImplicitTypeForIntrinsicTypes);
var styleForApparent = optionSet.GetOption(CSharpCodeStyleOptions.UseImplicitTypeWhereApparent);
var styleForElsewhere = optionSet.GetOption(CSharpCodeStyleOptions.UseImplicitTypeWherePossible);
_styleToSeverityMap.Add(TypingStyles.VarForIntrinsic, styleForIntrinsicTypes.Notification.Value);
_styleToSeverityMap.Add(TypingStyles.VarWhereApparent, styleForApparent.Notification.Value);
_styleToSeverityMap.Add(TypingStyles.VarWherePossible, styleForElsewhere.Notification.Value);
_styleToSeverityMap.Add(TypeStyle.ImplicitTypeForIntrinsicTypes, styleForIntrinsicTypes.Notification.Value);
_styleToSeverityMap.Add(TypeStyle.ImplicitTypeWhereApparent, styleForApparent.Notification.Value);
_styleToSeverityMap.Add(TypeStyle.ImplicitTypeWherePossible, styleForElsewhere.Notification.Value);
if (styleForIntrinsicTypes.IsChecked)
{
stylePreferences |= TypingStyles.VarForIntrinsic;
stylePreferences |= TypeStyle.ImplicitTypeForIntrinsicTypes;
}
if (styleForApparent.IsChecked)
{
stylePreferences |= TypingStyles.VarWhereApparent;
stylePreferences |= TypeStyle.ImplicitTypeWhereApparent;
}
if (styleForElsewhere.IsChecked)
{
stylePreferences |= TypingStyles.VarWherePossible;
stylePreferences |= TypeStyle.ImplicitTypeWherePossible;
}
return stylePreferences;
......
......@@ -6,6 +6,7 @@
using System.Diagnostics;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Options;
......@@ -16,34 +17,34 @@ namespace Microsoft.CodeAnalysis.CSharp.Diagnostics.TypingStyles
internal abstract partial class CSharpTypingStyleDiagnosticAnalyzerBase : DiagnosticAnalyzer, IBuiltInAnalyzer
{
[Flags]
internal enum TypingStyles
internal enum TypeStyle
{
None = 0,
VarForIntrinsic = 1 << 0,
VarWhereApparent = 1 << 1,
VarWherePossible = 1 << 2,
ImplicitTypeForIntrinsicTypes = 1 << 0,
ImplicitTypeWhereApparent = 1 << 1,
ImplicitTypeWherePossible = 1 << 2,
}
private readonly string _diagnosticId;
private readonly LocalizableString _title;
private readonly LocalizableString _message;
private readonly Lazy<DiagnosticDescriptor> _noneDiagnosticDescriptor;
private readonly Lazy<DiagnosticDescriptor> _infoDiagnosticDescriptor;
private readonly Lazy<DiagnosticDescriptor> _warningDiagnosticDescriptor;
private readonly Lazy<DiagnosticDescriptor> _errorDiagnosticDescriptor;
private readonly Dictionary<DiagnosticSeverity, Lazy<DiagnosticDescriptor>> _severityToDescriptorMap;
private readonly DiagnosticDescriptor _noneDiagnosticDescriptor;
private readonly DiagnosticDescriptor _infoDiagnosticDescriptor;
private readonly DiagnosticDescriptor _warningDiagnosticDescriptor;
private readonly DiagnosticDescriptor _errorDiagnosticDescriptor;
private readonly Dictionary<DiagnosticSeverity, DiagnosticDescriptor> _severityToDescriptorMap;
public CSharpTypingStyleDiagnosticAnalyzerBase(string diagnosticId, LocalizableString title, LocalizableString message)
{
_diagnosticId = diagnosticId;
_title = title;
_message = message;
_noneDiagnosticDescriptor = new Lazy<DiagnosticDescriptor>(() => CreateDiagnosticDescriptor(DiagnosticSeverity.Hidden));
_infoDiagnosticDescriptor = new Lazy<DiagnosticDescriptor>(() => CreateDiagnosticDescriptor(DiagnosticSeverity.Info));
_warningDiagnosticDescriptor = new Lazy<DiagnosticDescriptor>(() => CreateDiagnosticDescriptor(DiagnosticSeverity.Warning));
_errorDiagnosticDescriptor = new Lazy<DiagnosticDescriptor>(() => CreateDiagnosticDescriptor(DiagnosticSeverity.Error));
_noneDiagnosticDescriptor = CreateDiagnosticDescriptor(DiagnosticSeverity.Hidden);
_infoDiagnosticDescriptor = CreateDiagnosticDescriptor(DiagnosticSeverity.Info);
_warningDiagnosticDescriptor = CreateDiagnosticDescriptor(DiagnosticSeverity.Warning);
_errorDiagnosticDescriptor = CreateDiagnosticDescriptor(DiagnosticSeverity.Error);
_severityToDescriptorMap =
new Dictionary<DiagnosticSeverity, Lazy<DiagnosticDescriptor>>
new Dictionary<DiagnosticSeverity, DiagnosticDescriptor>
{
{DiagnosticSeverity.Hidden, _noneDiagnosticDescriptor },
{DiagnosticSeverity.Info, _infoDiagnosticDescriptor },
......@@ -62,8 +63,8 @@ public CSharpTypingStyleDiagnosticAnalyzerBase(string diagnosticId, LocalizableS
isEnabledByDefault: true);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics =>
ImmutableArray.Create(_noneDiagnosticDescriptor.Value, _infoDiagnosticDescriptor.Value,
_warningDiagnosticDescriptor.Value, _errorDiagnosticDescriptor.Value);
ImmutableArray.Create(_noneDiagnosticDescriptor, _infoDiagnosticDescriptor,
_warningDiagnosticDescriptor, _errorDiagnosticDescriptor);
public DiagnosticAnalyzerCategory GetAnalyzerCategory() =>
DiagnosticAnalyzerCategory.SemanticSpanAnalysis;
......@@ -73,29 +74,36 @@ public override void Initialize(AnalysisContext context)
context.RegisterSyntaxNodeAction(HandleVariableDeclaration, SyntaxKind.VariableDeclaration, SyntaxKind.ForEachStatement);
}
protected abstract bool IsStylePreferred(SyntaxNode declarationStatement, SemanticModel semanticModel, OptionSet optionSet, State state, CancellationToken cancellationToken);
protected abstract bool IsStylePreferred(SemanticModel semanticModel, OptionSet optionSet, State state, CancellationToken cancellationToken);
protected abstract bool TryAnalyzeVariableDeclaration(TypeSyntax typeName, SemanticModel semanticModel, OptionSet optionSet, CancellationToken cancellationToken, out TextSpan issueSpan);
protected abstract bool AssignmentSupportsStylePreference(SyntaxToken identifier, TypeSyntax typeName, EqualsValueClauseSyntax initializer, SemanticModel semanticModel, OptionSet optionSet, CancellationToken cancellationToken);
protected static ExpressionSyntax GetInitializerExpression(EqualsValueClauseSyntax initializer) =>
initializer.Value is CheckedExpressionSyntax
? ((CheckedExpressionSyntax)initializer.Value).Expression.WalkDownParentheses()
: initializer.Value.WalkDownParentheses();
private void HandleVariableDeclaration(SyntaxNodeAnalysisContext context)
{
TypeSyntax declaredType;
State state = null;
var shouldAnalyze = false;
var declarationStatement = context.Node;
var optionSet = GetOptionSet(context.Options);
State state = null;
var semanticModel = context.SemanticModel;
var cancellationToken = context.CancellationToken;
if (declarationStatement.IsKind(SyntaxKind.VariableDeclaration))
{
var declaration = (VariableDeclarationSyntax)declarationStatement;
declaredType = declaration.Type;
shouldAnalyze = ShouldAnalyzeVariableDeclaration(declaration, context.SemanticModel, context.CancellationToken);
shouldAnalyze = ShouldAnalyzeVariableDeclaration(declaration, semanticModel, cancellationToken);
if (shouldAnalyze)
{
state = State.Generate(declarationStatement, context.SemanticModel, optionSet, isVariableDeclarationContext: true, cancellationToken: context.CancellationToken);
shouldAnalyze = IsStylePreferred(declaration, context.SemanticModel, optionSet, state, context.CancellationToken);
state = State.Generate(declarationStatement, semanticModel, optionSet, isVariableDeclarationContext: true, cancellationToken: cancellationToken);
shouldAnalyze = IsStylePreferred(semanticModel, optionSet, state, cancellationToken);
}
}
else if (declarationStatement.IsKind(SyntaxKind.ForEachStatement))
......@@ -103,8 +111,8 @@ private void HandleVariableDeclaration(SyntaxNodeAnalysisContext context)
var declaration = (ForEachStatementSyntax)declarationStatement;
declaredType = declaration.Type;
state = State.Generate(declarationStatement, context.SemanticModel, optionSet, isVariableDeclarationContext: false, cancellationToken: context.CancellationToken);
shouldAnalyze = IsStylePreferred(declaration, context.SemanticModel, optionSet, state, context.CancellationToken);
state = State.Generate(declarationStatement, semanticModel, optionSet, isVariableDeclarationContext: false, cancellationToken: cancellationToken);
shouldAnalyze = IsStylePreferred(semanticModel, optionSet, state, cancellationToken);
}
else
{
......@@ -118,10 +126,10 @@ private void HandleVariableDeclaration(SyntaxNodeAnalysisContext context)
TextSpan diagnosticSpan;
if (TryAnalyzeVariableDeclaration(declaredType, context.SemanticModel, optionSet, context.CancellationToken, out diagnosticSpan))
if (TryAnalyzeVariableDeclaration(declaredType, semanticModel, optionSet, cancellationToken, out diagnosticSpan))
{
var descriptor = _severityToDescriptorMap[state.GetDiagnosticSeverityPreference()];
context.ReportDiagnostic(CreateDiagnostic(descriptor.Value, declarationStatement, diagnosticSpan));
context.ReportDiagnostic(CreateDiagnostic(descriptor, declarationStatement, diagnosticSpan));
}
}
}
......@@ -132,15 +140,15 @@ private void HandleVariableDeclaration(SyntaxNodeAnalysisContext context)
private bool ShouldAnalyzeVariableDeclaration(VariableDeclarationSyntax variableDeclaration, SemanticModel semanticModel, CancellationToken cancellationToken)
{
// var is applicable only for local variables.
if (variableDeclaration.Parent.IsKind(SyntaxKind.FieldDeclaration) ||
variableDeclaration.Parent.IsKind(SyntaxKind.EventFieldDeclaration))
if (variableDeclaration.IsParentKind(SyntaxKind.FieldDeclaration,
SyntaxKind.EventFieldDeclaration))
{
return false;
}
// implicitly typed variables cannot have multiple declarators and
// must have an initializer.
if (variableDeclaration.Variables.Count > 1 ||
if (variableDeclaration.Variables.Count != 1 ||
!variableDeclaration.Variables.Single().Initializer.IsKind(SyntaxKind.EqualsValueClause))
{
return false;
......
......@@ -15,10 +15,10 @@ namespace Microsoft.CodeAnalysis.CSharp.Diagnostics.TypingStyles
internal sealed class CSharpUseExplicitTypingDiagnosticAnalyzer : CSharpTypingStyleDiagnosticAnalyzerBase
{
private static readonly LocalizableString s_Title =
new LocalizableResourceString(nameof(CSharpFeaturesResources.UseExplicitTypingDiagnosticTitle), CSharpFeaturesResources.ResourceManager, typeof(CSharpFeaturesResources));
new LocalizableResourceString(nameof(CSharpFeaturesResources.UseExplicitTypeDiagnosticTitle), CSharpFeaturesResources.ResourceManager, typeof(CSharpFeaturesResources));
private static readonly LocalizableString s_Message =
new LocalizableResourceString(nameof(CSharpFeaturesResources.UseExplicitTyping), CSharpFeaturesResources.ResourceManager, typeof(CSharpFeaturesResources));
new LocalizableResourceString(nameof(CSharpFeaturesResources.UseExplicitType), CSharpFeaturesResources.ResourceManager, typeof(CSharpFeaturesResources));
public CSharpUseExplicitTypingDiagnosticAnalyzer()
: base(diagnosticId: IDEDiagnosticIds.UseExplicitTypingDiagnosticId,
......@@ -27,9 +27,9 @@ public CSharpUseExplicitTypingDiagnosticAnalyzer()
{
}
protected override bool IsStylePreferred(SyntaxNode declarationStatement, SemanticModel semanticModel, OptionSet optionSet, State state, CancellationToken cancellationToken)
protected override bool IsStylePreferred(SemanticModel semanticModel, OptionSet optionSet, State state, CancellationToken cancellationToken)
{
var stylePreferences = state.StylePreferences;
var stylePreferences = state.TypeStyle;
var shouldNotify = state.ShouldNotify();
// If notification preference is None, don't offer the suggestion.
......@@ -40,15 +40,15 @@ protected override bool IsStylePreferred(SyntaxNode declarationStatement, Semant
if (state.IsInIntrinsicTypeContext)
{
return !stylePreferences.HasFlag(TypingStyles.VarForIntrinsic);
return !stylePreferences.HasFlag(TypeStyle.ImplicitTypeForIntrinsicTypes);
}
else if (state.IsTypingApparentInContext)
{
return !stylePreferences.HasFlag(TypingStyles.VarWhereApparent);
return !stylePreferences.HasFlag(TypeStyle.ImplicitTypeWhereApparent);
}
else
{
return !stylePreferences.HasFlag(TypingStyles.VarWherePossible);
return !stylePreferences.HasFlag(TypeStyle.ImplicitTypeWherePossible);
}
}
......
......@@ -17,10 +17,10 @@ internal sealed class CSharpUseImplicitTypingDiagnosticAnalyzer : CSharpTypingSt
{
private static readonly LocalizableString s_Title =
new LocalizableResourceString(nameof(CSharpFeaturesResources.UseImplicitTypingDiagnosticTitle), CSharpFeaturesResources.ResourceManager, typeof(CSharpFeaturesResources));
new LocalizableResourceString(nameof(CSharpFeaturesResources.UseImplicitTypeDiagnosticTitle), CSharpFeaturesResources.ResourceManager, typeof(CSharpFeaturesResources));
private static readonly LocalizableString s_Message =
new LocalizableResourceString(nameof(CSharpFeaturesResources.UseImplicitTyping), CSharpFeaturesResources.ResourceManager, typeof(CSharpFeaturesResources));
new LocalizableResourceString(nameof(CSharpFeaturesResources.UseImplicitType), CSharpFeaturesResources.ResourceManager, typeof(CSharpFeaturesResources));
public CSharpUseImplicitTypingDiagnosticAnalyzer()
: base(diagnosticId: IDEDiagnosticIds.UseImplicitTypingDiagnosticId,
......@@ -29,9 +29,9 @@ public CSharpUseImplicitTypingDiagnosticAnalyzer()
{
}
protected override bool IsStylePreferred(SyntaxNode declarationStatement, SemanticModel semanticModel, OptionSet optionSet, State state, CancellationToken cancellationToken)
protected override bool IsStylePreferred(SemanticModel semanticModel, OptionSet optionSet, State state, CancellationToken cancellationToken)
{
var stylePreferences = state.StylePreferences;
var stylePreferences = state.TypeStyle;
var shouldNotify = state.ShouldNotify();
// If notification preference is None, don't offer the suggestion.
......@@ -42,25 +42,24 @@ protected override bool IsStylePreferred(SyntaxNode declarationStatement, Semant
if (state.IsInIntrinsicTypeContext)
{
return stylePreferences.HasFlag(TypingStyles.VarForIntrinsic);
return stylePreferences.HasFlag(TypeStyle.ImplicitTypeForIntrinsicTypes);
}
else if (state.IsTypingApparentInContext)
{
return stylePreferences.HasFlag(TypingStyles.VarWhereApparent);
return stylePreferences.HasFlag(TypeStyle.ImplicitTypeWhereApparent);
}
else
{
return stylePreferences.HasFlag(TypingStyles.VarWherePossible);
return stylePreferences.HasFlag(TypeStyle.ImplicitTypeWherePossible);
}
}
protected override bool TryAnalyzeVariableDeclaration(TypeSyntax typeName, SemanticModel semanticModel, OptionSet optionSet, CancellationToken cancellationToken, out TextSpan issueSpan)
{
issueSpan = default(TextSpan);
// If it is already var, return.
if (typeName.IsTypeInferred(semanticModel))
{
issueSpan = default(TextSpan);
return false;
}
......@@ -74,6 +73,7 @@ protected override bool TryAnalyzeVariableDeclaration(TypeSyntax typeName, Seman
var conflict = semanticModel.GetSpeculativeSymbolInfo(typeName.SpanStart, candidateReplacementNode, SpeculativeBindingOption.BindAsTypeOrNamespace).Symbol;
if (conflict?.IsKind(SymbolKind.NamedType) == true)
{
issueSpan = default(TextSpan);
return false;
}
......@@ -85,6 +85,7 @@ protected override bool TryAnalyzeVariableDeclaration(TypeSyntax typeName, Seman
// implicitly typed variables cannot be constants.
if ((variableDeclaration.Parent as LocalDeclarationStatementSyntax)?.IsConst == true)
{
issueSpan = default(TextSpan);
return false;
}
......@@ -92,14 +93,17 @@ protected override bool TryAnalyzeVariableDeclaration(TypeSyntax typeName, Seman
if (AssignmentSupportsStylePreference(variable.Identifier, typeName, variable.Initializer, semanticModel, optionSet, cancellationToken))
{
issueSpan = candidateIssueSpan;
return true;
}
}
else if (typeName.IsParentKind(SyntaxKind.ForEachStatement))
{
issueSpan = candidateIssueSpan;
return true;
}
return issueSpan != default(TextSpan);
issueSpan = default(TextSpan);
return false;
}
/// <summary>
......@@ -111,7 +115,7 @@ protected override bool TryAnalyzeVariableDeclaration(TypeSyntax typeName, Seman
/// </returns>
protected override bool AssignmentSupportsStylePreference(SyntaxToken identifier, TypeSyntax typeName, EqualsValueClauseSyntax initializer, SemanticModel semanticModel, OptionSet optionSet, CancellationToken cancellationToken)
{
var expression = initializer.Value;
var expression = GetInitializerExpression(initializer);
// var cannot be assigned null
if (expression.IsKind(SyntaxKind.NullLiteralExpression))
......@@ -121,9 +125,8 @@ protected override bool AssignmentSupportsStylePreference(SyntaxToken identifier
// cannot use implicit typing on method group, anonymous function or on dynamic
var declaredType = semanticModel.GetTypeInfo(typeName, cancellationToken).Type;
if (declaredType != null
&& (declaredType.TypeKind == TypeKind.Delegate
|| declaredType.TypeKind == TypeKind.Dynamic))
if (declaredType != null &&
(declaredType.TypeKind == TypeKind.Delegate || declaredType.TypeKind == TypeKind.Dynamic))
{
return false;
}
......
......@@ -36,7 +36,7 @@ internal static class PredefinedCodeFixProviderNames
public const string Suppression = nameof(Suppression);
public const string AddOverloads = "Add Overloads to member";
public const string AddNew = "Add new keyword to member";
public const string UseImplicitTyping = "Use var";
public const string UseExplicitTyping = "Use typename instead of var";
public const string UseImplicitTyping = nameof(UseImplicitTyping);
public const string UseExplicitTyping = nameof(UseExplicitTyping);
}
}
// 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.Runtime.Serialization;
namespace Microsoft.CodeAnalysis.CodeStyle
{
[DataContract]
internal class NotificationOption
{
public string Name { get; }
public DiagnosticSeverity Value { get; }
[DataMember]
public string Name { get; set; }
[DataMember]
public DiagnosticSeverity Value { get; set; }
public static readonly NotificationOption None = new NotificationOption(nameof(None), DiagnosticSeverity.Hidden);
public static readonly NotificationOption Info = new NotificationOption(nameof(Info), DiagnosticSeverity.Info);
......
// 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.Runtime.Serialization;
namespace Microsoft.CodeAnalysis.CodeStyle
{
[DataContract]
internal class SimpleCodeStyleOption
{
public static readonly SimpleCodeStyleOption Default = new SimpleCodeStyleOption(false, NotificationOption.None);
......@@ -12,8 +15,10 @@ public SimpleCodeStyleOption(bool isChecked, NotificationOption notification)
Notification = notification;
}
[DataMember]
public bool IsChecked { get; set; }
[DataMember]
public NotificationOption Notification { get; set; }
}
}
......@@ -158,6 +158,7 @@
<Reference Include="System" />
<Reference Include="System.ComponentModel.Composition" />
<Reference Include="System.Core" />
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xaml" />
<Reference Include="System.Xml" />
......@@ -206,6 +207,7 @@
<Compile Include="ObjectBrowser\ListItemFactory.cs" />
<Compile Include="Options\AdvancedOptionPageStrings.cs" />
<Compile Include="Options\IntelliSenseOptionPageStrings.cs" />
<Compile Include="Options\SerializationHelpers.cs" />
<Compile Include="Venus\CSharpAdditionalFormattingRuleLanguageService.cs" />
<Compile Include="CSharpPackage.cs" />
<Compile Include="CSharpVSResources.Designer.cs">
......
......@@ -459,42 +459,42 @@ public int Style_UseVarWhenDeclaringLocals
set { SetBooleanOption(CSharpCodeStyleOptions.UseVarWhenDeclaringLocals, value); }
}
public int Style_UseVarWherePossible
public string Style_UseVarWherePossible
{
get
{
var option = _optionService.GetOption(CSharpCodeStyleOptions.UseVarWherePossible);
var option = _optionService.GetOption(CSharpCodeStyleOptions.UseImplicitTypeWherePossible);
return GetUseVarOption(option);
}
set
{
SetUseVarOption(CSharpCodeStyleOptions.UseVarWherePossible, value);
SetUseVarOption(CSharpCodeStyleOptions.UseImplicitTypeWherePossible, value);
}
}
public int Style_UseVarWhenTypeIsApparent
public string Style_UseVarWhenTypeIsApparent
{
get
{
var option = _optionService.GetOption(CSharpCodeStyleOptions.UseVarWhenTypeIsApparent);
var option = _optionService.GetOption(CSharpCodeStyleOptions.UseImplicitTypeWhereApparent);
return GetUseVarOption(option);
}
set
{
SetUseVarOption(CSharpCodeStyleOptions.UseVarWhenTypeIsApparent, value);
SetUseVarOption(CSharpCodeStyleOptions.UseImplicitTypeWhereApparent, value);
}
}
public int Style_UseVarForIntrinsicTypes
public string Style_UseVarForIntrinsicTypes
{
get
{
var option = _optionService.GetOption(CSharpCodeStyleOptions.UseVarForIntrinsicTypes);
var option = _optionService.GetOption(CSharpCodeStyleOptions.UseImplicitTypeForIntrinsicTypes);
return GetUseVarOption(option);
}
set
{
SetUseVarOption(CSharpCodeStyleOptions.UseVarForIntrinsicTypes, value);
SetUseVarOption(CSharpCodeStyleOptions.UseImplicitTypeForIntrinsicTypes, value);
}
}
......@@ -562,49 +562,17 @@ private void SetBooleanOption(PerLanguageOption<bool> key, int value)
_optionService.SetOptions(optionSet);
}
private static int GetUseVarOption(SimpleCodeStyleOption option)
private static string GetUseVarOption(SimpleCodeStyleOption option)
{
var offset = option.IsChecked ? 0 : Enum.GetValues(typeof(DiagnosticSeverity)).Length;
var baseValue = (int)option.Notification.Value;
return offset + baseValue;
return option.SerializeObject();
}
private void SetUseVarOption(Option<SimpleCodeStyleOption> option, int value)
private void SetUseVarOption(Option<SimpleCodeStyleOption> option, string value)
{
SimpleCodeStyleOption convertedValue = SimpleCodeStyleOption.Default;
var optionSet = _optionService.GetOptions();
switch (value)
{
case 0:
convertedValue = new SimpleCodeStyleOption(true, NotificationOption.None);
break;
case 1:
convertedValue = new SimpleCodeStyleOption(true, NotificationOption.Info);
break;
case 2:
convertedValue = new SimpleCodeStyleOption(true, NotificationOption.Warning);
break;
case 3:
convertedValue = new SimpleCodeStyleOption(true, NotificationOption.Error);
break;
case 4:
convertedValue = new SimpleCodeStyleOption(false, NotificationOption.None);
break;
case 5:
convertedValue = new SimpleCodeStyleOption(false, NotificationOption.Info);
break;
case 6:
convertedValue = new SimpleCodeStyleOption(false, NotificationOption.Warning);
break;
case 7:
convertedValue = new SimpleCodeStyleOption(false, NotificationOption.Error);
break;
default:
break;
}
convertedValue = (SimpleCodeStyleOption)value.DeserializeObject<SimpleCodeStyleOption>();
optionSet = optionSet.WithChangedOption(option, convertedValue);
_optionService.SetOptions(optionSet);
}
......
......@@ -211,19 +211,19 @@ public override bool TryFetch(OptionKey optionKey, out object value)
}
// code style: use var options.
if (optionKey.Option == CSharpCodeStyleOptions.UseVarForIntrinsicTypes)
if (optionKey.Option == CSharpCodeStyleOptions.UseImplicitTypeForIntrinsicTypes)
{
var useVarValue = this.Manager.GetValueOrDefault(Style_UseVarForIntrinsicTypes, defaultValue: 0);
var useVarValue = this.Manager.GetValueOrDefault<string>(Style_UseVarForIntrinsicTypes);
return FetchUseVarOption(useVarValue, out value);
}
else if (optionKey.Option == CSharpCodeStyleOptions.UseVarWhenTypeIsApparent)
else if (optionKey.Option == CSharpCodeStyleOptions.UseImplicitTypeWhereApparent)
{
var useVarValue = this.Manager.GetValueOrDefault(Style_UseVarWhenTypeIsApparent, defaultValue: 0);
var useVarValue = this.Manager.GetValueOrDefault<string>(Style_UseVarWhenTypeIsApparent);
return FetchUseVarOption(useVarValue, out value);
}
else if (optionKey.Option == CSharpCodeStyleOptions.UseVarWherePossible)
else if (optionKey.Option == CSharpCodeStyleOptions.UseImplicitTypeWherePossible)
{
var useVarValue = this.Manager.GetValueOrDefault(Style_UseVarWherePossible, defaultValue: 0);
var useVarValue = this.Manager.GetValueOrDefault<string>(Style_UseVarWherePossible);
return FetchUseVarOption(useVarValue, out value);
}
......@@ -297,15 +297,15 @@ public override bool TryPersist(OptionKey optionKey, object value)
}
// code style: use var options.
if (optionKey.Option == CSharpCodeStyleOptions.UseVarForIntrinsicTypes)
if (optionKey.Option == CSharpCodeStyleOptions.UseImplicitTypeForIntrinsicTypes)
{
return PersistUseVarOption(Style_UseVarForIntrinsicTypes, value);
}
else if (optionKey.Option == CSharpCodeStyleOptions.UseVarWhenTypeIsApparent)
else if (optionKey.Option == CSharpCodeStyleOptions.UseImplicitTypeWhereApparent)
{
return PersistUseVarOption(Style_UseVarWhenTypeIsApparent, value);
}
else if (optionKey.Option == CSharpCodeStyleOptions.UseVarWherePossible)
else if (optionKey.Option == CSharpCodeStyleOptions.UseImplicitTypeWherePossible)
{
return PersistUseVarOption(Style_UseVarWherePossible, value);
}
......@@ -315,48 +315,23 @@ public override bool TryPersist(OptionKey optionKey, object value)
private bool PersistUseVarOption(string option, object value)
{
var convertedValue = (SimpleCodeStyleOption)value;
var offset = convertedValue.IsChecked ? 0 : Enum.GetValues(typeof(DiagnosticSeverity)).Length;
var baseValue = (int)convertedValue.Notification.Value;
this.Manager.SetValueAsync(option, value: baseValue + offset, isMachineLocal: false);
var serializedValue = ((SimpleCodeStyleOption)value).SerializeObject();
this.Manager.SetValueAsync(option, value: serializedValue, isMachineLocal: false);
return true;
}
private static bool FetchUseVarOption(int useVarOptionValue, out object value)
{
switch (useVarOptionValue)
{
case 0:
value = new SimpleCodeStyleOption(true, NotificationOption.None);
break;
case 1:
value = new SimpleCodeStyleOption(true, NotificationOption.Info);
break;
case 2:
value = new SimpleCodeStyleOption(true, NotificationOption.Warning);
break;
case 3:
value = new SimpleCodeStyleOption(true, NotificationOption.Error);
break;
case 4:
value = new SimpleCodeStyleOption(false, NotificationOption.None);
break;
case 5:
value = new SimpleCodeStyleOption(false, NotificationOption.Info);
break;
case 6:
value = new SimpleCodeStyleOption(false, NotificationOption.Warning);
break;
case 7:
value = new SimpleCodeStyleOption(false, NotificationOption.Error);
break;
default:
value = null;
break;
private static bool FetchUseVarOption(string useVarOptionValue, out object value)
{
if (string.IsNullOrEmpty(useVarOptionValue))
{
value = SimpleCodeStyleOption.Default;
}
else
{
value = useVarOptionValue.DeserializeObject<SimpleCodeStyleOption>();
}
return value != null;
return true;
}
}
}
\ No newline at end of file
......@@ -191,9 +191,9 @@ internal StyleViewModel(OptionSet optionSet, IServiceProvider serviceProvider) :
new NotificationOptionViewModel(NotificationOption.Error, KnownMonikers.StatusError)
};
Items.Add(new CheckBoxWithComboOptionViewModel(CSharpCodeStyleOptions.UseVarForIntrinsicTypes, CSharpVSResources.UseVarForIntrinsicTypes, s_varForIntrinsicsPreviewTrue, s_varForIntrinsicsPreviewFalse, this, optionSet, notificationOptions));
Items.Add(new CheckBoxWithComboOptionViewModel(CSharpCodeStyleOptions.UseVarWhenTypeIsApparent, CSharpVSResources.UseVarWhenTypeIsApparent, s_varWhereApparentPreviewTrue, s_varWhereApparentPreviewFalse, this, optionSet, notificationOptions));
Items.Add(new CheckBoxWithComboOptionViewModel(CSharpCodeStyleOptions.UseVarWherePossible, CSharpVSResources.UseVarWhenPossible, s_varWherePossiblePreviewTrue, s_varWherePossiblePreviewFalse, this, optionSet, notificationOptions));
Items.Add(new CheckBoxWithComboOptionViewModel(CSharpCodeStyleOptions.UseImplicitTypeForIntrinsicTypes, CSharpVSResources.UseVarForIntrinsicTypes, s_varForIntrinsicsPreviewTrue, s_varForIntrinsicsPreviewFalse, this, optionSet, notificationOptions));
Items.Add(new CheckBoxWithComboOptionViewModel(CSharpCodeStyleOptions.UseImplicitTypeWhereApparent, CSharpVSResources.UseVarWhenTypeIsApparent, s_varWhereApparentPreviewTrue, s_varWhereApparentPreviewFalse, this, optionSet, notificationOptions));
Items.Add(new CheckBoxWithComboOptionViewModel(CSharpCodeStyleOptions.UseImplicitTypeWherePossible, CSharpVSResources.UseVarWhenPossible, s_varWherePossiblePreviewTrue, s_varWherePossiblePreviewFalse, this, optionSet, notificationOptions));
}
}
}
using System.IO;
using System.Runtime.Serialization;
using System.Text;
namespace Microsoft.VisualStudio.LanguageServices.CSharp.Options
{
internal static class SerializationHelpers
{
public static string SerializeObject<T>(this T toSerialize)
{
using (var stream = new MemoryStream())
{
var serializer = new DataContractSerializer(typeof(T));
serializer.WriteObject(stream, toSerialize);
stream.Seek(0, SeekOrigin.Begin);
using (var streamReader = new StreamReader(stream))
{
return streamReader.ReadToEnd();
}
}
}
public static object DeserializeObject<T>(this string toDeserialize)
{
using (var stream = new MemoryStream())
{
var data = Encoding.UTF8.GetBytes(toDeserialize);
stream.Write(data, 0, data.Length);
stream.Seek(0, SeekOrigin.Begin);
DataContractSerializer serializer = new DataContractSerializer(typeof(T));
return serializer.ReadObject(stream);
}
}
}
}
......@@ -33,7 +33,7 @@ public CheckBoxWithComboOptionViewModel(IOption option, string description, stri
var codeStyleOption = ((SimpleCodeStyleOption)options.GetOption(new OptionKey(option, option.IsPerLanguage ? info.Language : null)));
SetProperty(ref _isChecked, codeStyleOption.IsChecked);
var notificationViewModel = items.Where(i => i.Notification == codeStyleOption.Notification).Single();
var notificationViewModel = items.Where(i => i.Notification.Value == codeStyleOption.Notification.Value).Single();
SetProperty(ref _selectedNotificationOption, notificationViewModel);
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册