提交 4b73d33b 编写于 作者: C CyrusNajmabadi

Add CodeStyle option to allow users to customer the 'Invoke Delegate With...

Add CodeStyle option to allow users to customer the 'Invoke Delegate With Conditional Access' analyzer.
上级 26f56cc5
......@@ -164,6 +164,7 @@
<Compile Include="Completion\CompletionServiceTests.cs" />
<Compile Include="Diagnostics\AddUsing\AddUsingTests_NuGet.cs" />
<Compile Include="Diagnostics\GenerateMethod\GenerateConversionTests.cs" />
<Compile Include="Diagnostics\InvokeDelegateWithConditionalAccess\InvokeDelegateWithConditionalAccessTests_FixAllTests.cs" />
<Compile Include="Diagnostics\MakeMethodSynchronous\MakeMethodSynchronousTests.cs" />
<Compile Include="CodeActions\MoveDeclarationNearReference\MoveDeclarationNearReferenceTests.cs" />
<Compile Include="CodeActions\Preview\ErrorCases\ExceptionInCodeAction.cs" />
......
......@@ -11,7 +11,7 @@
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics.InvokeDelegateWithConditionalAccess
{
public class InvokeDelegateWithConditionalAccessTests : AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest
public partial class InvokeDelegateWithConditionalAccessTests : AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest
{
internal override Tuple<DiagnosticAnalyzer, CodeFixProvider> CreateDiagnosticProviderAndFixer(Workspace workspace)
{
......@@ -47,6 +47,60 @@ void Foo()
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInvokeDelegateWithConditionalAccess)]
public async Task TestOnIf()
{
await TestAsync(
@"class C
{
System.Action a;
void Foo()
{
var v = a;
[||]if (v != null)
{
v();
}
}
}",
@"
class C
{
System.Action a;
void Foo()
{
a?.Invoke();
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInvokeDelegateWithConditionalAccess)]
public async Task TestOnInvoke()
{
await TestAsync(
@"class C
{
System.Action a;
void Foo()
{
var v = a;
if (v != null)
{
[||]v();
}
}
}",
@"
class C
{
System.Action a;
void Foo()
{
a?.Invoke();
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInvokeDelegateWithConditionalAccess)]
[WorkItem(13226, "https://github.com/dotnet/roslyn/issues/13226")]
public async Task TestMissingBeforeCSharp6()
......@@ -296,6 +350,37 @@ void M()
@"
using System;
class C
{
public event EventHandler E;
void M()
{
this.E?.Invoke(this, EventArgs.Empty);
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInvokeDelegateWithConditionalAccess)]
public async Task TestSimpleForm2()
{
await TestAsync(
@"
using System;
class C
{
public event EventHandler E;
void M()
{
if (this.E != null)
{
[||]this.E(this, EventArgs.Empty);
}
}
}",
@"
using System;
class C
{
public event EventHandler E;
......
// 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.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.InvokeDelegateWithConditionalAccess;
using Microsoft.CodeAnalysis.Diagnostics;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics.InvokeDelegateWithConditionalAccess
{
public partial class InvokeDelegateWithConditionalAccessTests
{
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInvokeDelegateWithConditionalAccess)]
public async Task TestFixAllInDocument1()
{
await TestAsync(
@"class C
{
System.Action a;
void Foo()
{
{|FixAllInDocument:var|} v = a;
if (v != null)
{
v();
}
var x = a;
if (x != null)
{
x();
}
}
}",
@"
class C
{
System.Action a;
void Foo()
{
a?.Invoke();
a?.Invoke();
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInvokeDelegateWithConditionalAccess)]
public async Task TestFixAllInDocument2()
{
await TestAsync(
@"class C
{
System.Action a;
void Foo()
{
var v = a;
{|FixAllInDocument:if|} (v != null)
{
v();
}
var x = a;
if (x != null)
{
x();
}
}
}",
@"
class C
{
System.Action a;
void Foo()
{
a?.Invoke();
a?.Invoke();
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInvokeDelegateWithConditionalAccess)]
public async Task TestFixAllInDocument3()
{
await TestAsync(
@"class C
{
System.Action a;
void Foo()
{
var v = a;
if (v != null)
{
{|FixAllInDocument:v|}();
}
var x = a;
if (x != null)
{
x();
}
}
}",
@"
class C
{
System.Action a;
void Foo()
{
a?.Invoke();
a?.Invoke();
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInvokeDelegateWithConditionalAccess)]
public async Task TestFixAllInDocument4()
{
await TestAsync(
@"class C
{
System.Action a;
void Foo()
{
var v = a;
if (v != null)
{
v();
}
{|FixAllInDocument:var|} x = a;
if (x != null)
{
x();
}
}
}",
@"
class C
{
System.Action a;
void Foo()
{
a?.Invoke();
a?.Invoke();
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInvokeDelegateWithConditionalAccess)]
public async Task TestFixAllInDocument5()
{
await TestAsync(
@"class C
{
System.Action a;
void Foo()
{
var v = a;
if (v != null)
{
v();
}
var x = a;
{|FixAllInDocument:if|} (x != null)
{
x();
}
}
}",
@"
class C
{
System.Action a;
void Foo()
{
a?.Invoke();
a?.Invoke();
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsInvokeDelegateWithConditionalAccess)]
public async Task TestFixAllInDocument6()
{
await TestAsync(
@"class C
{
System.Action a;
void Foo()
{
var v = a;
if (v != null)
{
v();
}
var x = a;
if (x != null)
{
{|FixAllInDocument:x|}();
}
}
}",
@"
class C
{
System.Action a;
void Foo()
{
a?.Invoke();
a?.Invoke();
}
}");
}
}
}
\ No newline at end of file
......@@ -325,6 +325,7 @@
<Compile Include="IntroduceVariable\CSharpIntroduceVariableService_IntroduceLocal.cs" />
<Compile Include="IntroduceVariable\CSharpIntroduceVariableService_IntroduceQueryLocal.cs" />
<Compile Include="InvokeDelegateWithConditionalAccess\InvokeDelegateWithConditionalAccessAnalyzer.cs" />
<Compile Include="InvokeDelegateWithConditionalAccess\InvokeDelegateWithConditionalAccessCodeFixProvider.FixAllProvider.cs" />
<Compile Include="InvokeDelegateWithConditionalAccess\InvokeDelegateWithConditionalAccessCodeFixProvider.cs" />
<Compile Include="LanguageServices\CSharpAnonymousTypeDisplayService.cs" />
<Compile Include="LanguageServices\CSharpSymbolDisplayService.cs" />
......
......@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis.CSharp.CodeStyle;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Text;
......@@ -18,18 +19,30 @@ internal static class Constants
[DiagnosticAnalyzer(LanguageNames.CSharp)]
internal class InvokeDelegateWithConditionalAccessAnalyzer : DiagnosticAnalyzer, IBuiltInAnalyzer
{
private static readonly DiagnosticDescriptor s_descriptor = new DiagnosticDescriptor(
IDEDiagnosticIds.InvokeDelegateWithConditionalAccessId,
CSharpFeaturesResources.Delegate_invocation_can_be_simplified,
CSharpFeaturesResources.Delegate_invocation_can_be_simplified,
DiagnosticCategory.Style,
DiagnosticSeverity.Hidden,
isEnabledByDefault: true,
customTags: DiagnosticCustomTags.Unnecessary);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(s_descriptor);
private static readonly DiagnosticDescriptor s_descriptor =
CreateDescriptor(DiagnosticSeverity.Hidden);
private static readonly DiagnosticDescriptor s_unnecessaryDescriptor =
CreateDescriptor(DiagnosticSeverity.Hidden, DiagnosticCustomTags.Unnecessary);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
=> ImmutableArray.Create(s_descriptor, s_unnecessaryDescriptor);
public bool OpenFileOnly(Workspace workspace) => false;
private static DiagnosticDescriptor CreateDescriptor(
DiagnosticSeverity severity, params string[] customTags)
{
return new DiagnosticDescriptor(
IDEDiagnosticIds.InvokeDelegateWithConditionalAccessId,
CSharpFeaturesResources.Delegate_invocation_can_be_simplified,
CSharpFeaturesResources.Delegate_invocation_can_be_simplified,
DiagnosticCategory.Style,
severity,
isEnabledByDefault: true,
customTags: customTags);
}
public override void Initialize(AnalysisContext context)
{
context.RegisterSyntaxNodeAction(SyntaxNodeAction, SyntaxKind.IfStatement);
......@@ -37,6 +50,16 @@ public override void Initialize(AnalysisContext context)
private void SyntaxNodeAction(SyntaxNodeAnalysisContext syntaxContext)
{
var options = syntaxContext.Options.GetOptionSet();
var styleOption = options.GetOption(CSharpCodeStyleOptions.PreferConditionalFunctionCall);
if (!styleOption.Value)
{
// Bail immediately if the user has disabled this feature.
return;
}
var severity = styleOption.Notification.Value;
// look for the form "if (a != null)" or "if (null != a)"
var ifStatement = (IfStatementSyntax)syntaxContext.Node;
......@@ -85,12 +108,18 @@ private void SyntaxNodeAction(SyntaxNodeAnalysisContext syntaxContext)
}
var condition = (BinaryExpressionSyntax)ifStatement.Condition;
if (TryCheckVariableAndIfStatementForm(syntaxContext, ifStatement, condition, expressionStatement, invocationExpression))
if (TryCheckVariableAndIfStatementForm(
syntaxContext, ifStatement, condition,
expressionStatement, invocationExpression,
severity))
{
return;
}
TryCheckSingleIfStatementForm(syntaxContext, ifStatement, condition, expressionStatement, invocationExpression);
TryCheckSingleIfStatementForm(
syntaxContext, ifStatement, condition,
expressionStatement, invocationExpression,
severity);
}
private bool TryCheckSingleIfStatementForm(
......@@ -98,7 +127,8 @@ private void SyntaxNodeAction(SyntaxNodeAnalysisContext syntaxContext)
IfStatementSyntax ifStatement,
BinaryExpressionSyntax condition,
ExpressionStatementSyntax expressionStatement,
InvocationExpressionSyntax invocationExpression)
InvocationExpressionSyntax invocationExpression,
DiagnosticSeverity severity)
{
var cancellationToken = syntaxContext.CancellationToken;
......@@ -125,14 +155,23 @@ private void SyntaxNodeAction(SyntaxNodeAnalysisContext syntaxContext)
var properties = ImmutableDictionary<string, string>.Empty.Add(Constants.Kind, Constants.SingleIfStatementForm);
syntaxContext.ReportDiagnostic(Diagnostic.Create(s_descriptor,
Location.Create(tree, TextSpan.FromBounds(ifStatement.SpanStart, expressionStatement.SpanStart)),
var previouToken = expressionStatement.GetFirstToken().GetPreviousToken();
var nextToken = expressionStatement.GetLastToken().GetNextToken();
syntaxContext.ReportDiagnostic(Diagnostic.Create(s_unnecessaryDescriptor,
Location.Create(tree, TextSpan.FromBounds(ifStatement.SpanStart, previouToken.Span.End)),
additionalLocations, properties));
var descriptor = CreateDescriptor(severity);
syntaxContext.ReportDiagnostic(Diagnostic.Create(descriptor,
expressionStatement.GetLocation(),
additionalLocations, properties));
if (expressionStatement.Span.End != ifStatement.Span.End)
if (nextToken.Span.Start < ifStatement.Span.End)
{
syntaxContext.ReportDiagnostic(Diagnostic.Create(s_descriptor,
Location.Create(tree, TextSpan.FromBounds(expressionStatement.Span.End, ifStatement.Span.End)),
syntaxContext.ReportDiagnostic(Diagnostic.Create(s_unnecessaryDescriptor,
Location.Create(tree, TextSpan.FromBounds(nextToken.Span.Start, ifStatement.Span.End)),
additionalLocations, properties));
}
......@@ -148,7 +187,8 @@ private void SyntaxNodeAction(SyntaxNodeAnalysisContext syntaxContext)
IfStatementSyntax ifStatement,
BinaryExpressionSyntax condition,
ExpressionStatementSyntax expressionStatement,
InvocationExpressionSyntax invocationExpression)
InvocationExpressionSyntax invocationExpression,
DiagnosticSeverity severity)
{
var cancellationToken = syntaxContext.CancellationToken;
cancellationToken.ThrowIfCancellationRequested();
......@@ -239,14 +279,25 @@ private void SyntaxNodeAction(SyntaxNodeAnalysisContext syntaxContext)
var properties = ImmutableDictionary<string, string>.Empty.Add(Constants.Kind, Constants.VariableAndIfStatementForm);
syntaxContext.ReportDiagnostic(Diagnostic.Create(s_descriptor,
Location.Create(tree, TextSpan.FromBounds(localDeclarationStatement.SpanStart, expressionStatement.SpanStart)),
var previousToken = expressionStatement.GetFirstToken().GetPreviousToken();
var nextToken = expressionStatement.GetLastToken().GetNextToken();
syntaxContext.ReportDiagnostic(Diagnostic.Create(s_unnecessaryDescriptor,
Location.Create(tree, TextSpan.FromBounds(
localDeclarationStatement.SpanStart, previousToken.Span.End)),
additionalLocations, properties));
var descriptor = CreateDescriptor(severity);
syntaxContext.ReportDiagnostic(Diagnostic.Create(descriptor,
expressionStatement.GetLocation(),
additionalLocations, properties));
if (expressionStatement.Span.End != ifStatement.Span.End)
if (nextToken.Span.Start < ifStatement.Span.End)
{
syntaxContext.ReportDiagnostic(Diagnostic.Create(s_descriptor,
Location.Create(tree, TextSpan.FromBounds(expressionStatement.Span.End, ifStatement.Span.End)),
syntaxContext.ReportDiagnostic(Diagnostic.Create(s_unnecessaryDescriptor,
Location.Create(tree, TextSpan.FromBounds(
nextToken.Span.Start, ifStatement.Span.End)),
additionalLocations, properties));
}
......
// 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 System.Composition;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp.Extensions;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.Formatting;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.InvokeDelegateWithConditionalAccess
{
internal partial class InvokeDelegateWithConditionalAccessCodeFixProvider : CodeFixProvider
{
private class InvokeDelegateWithConditionalAccessFixAllProvider : BatchFixAllProvider
{
private readonly InvokeDelegateWithConditionalAccessCodeFixProvider _provider;
public InvokeDelegateWithConditionalAccessFixAllProvider(InvokeDelegateWithConditionalAccessCodeFixProvider provider)
{
_provider = provider;
}
internal override async Task<CodeAction> GetFixAsync(
ImmutableDictionary<Document, ImmutableArray<Diagnostic>> documentsAndDiagnosticsToFixMap,
FixAllState fixAllState,
CancellationToken cancellationToken)
{
// Process all documents in parallel.
var updatedDocumentTasks = documentsAndDiagnosticsToFixMap.Select(
kvp => FixAsync(fixAllState, kvp.Key, kvp.Value, cancellationToken));
await Task.WhenAll(updatedDocumentTasks).ConfigureAwait(false);
var currentSolution = fixAllState.Solution;
foreach (var task in updatedDocumentTasks)
{
var updatedDocument = await task.ConfigureAwait(false);
currentSolution = currentSolution.WithDocumentSyntaxRoot(
updatedDocument.Id,
await updatedDocument.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false));
}
var title = GetFixAllTitle(fixAllState);
return new CodeAction.SolutionChangeAction(title, _ => Task.FromResult(currentSolution));
}
private Task<Document> FixAsync(
FixAllState fixAllState, Document document, ImmutableArray<Diagnostic> diagnostics, CancellationToken cancellationToken)
{
// Filter out the diagnostics we created for the faded out code. We don't want
// to try to fix those as well as the normal diagnostics we created.
var filteredDiagnostics = diagnostics.WhereAsArray(
d => !d.Descriptor.CustomTags.Contains(WellKnownDiagnosticTags.Unnecessary));
// Defer to the actual SimplifyNullCheckCodeFixProvider to process htis
// document. It can process all the diagnostics and apply them properly.
return _provider.FixAllAsync(document, filteredDiagnostics, cancellationToken);
}
}
}
}
......@@ -19,41 +19,61 @@
namespace Microsoft.CodeAnalysis.CSharp.InvokeDelegateWithConditionalAccess
{
[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(InvokeDelegateWithConditionalAccessCodeFixProvider)), Shared]
internal class InvokeDelegateWithConditionalAccessCodeFixProvider : CodeFixProvider
internal partial class InvokeDelegateWithConditionalAccessCodeFixProvider : CodeFixProvider
{
public override ImmutableArray<string> FixableDiagnosticIds { get; } = ImmutableArray.Create(IDEDiagnosticIds.InvokeDelegateWithConditionalAccessId);
public override FixAllProvider GetFixAllProvider() => BatchFixAllProvider.Instance;
public override FixAllProvider GetFixAllProvider()
=> new InvokeDelegateWithConditionalAccessFixAllProvider(this);
public override Task RegisterCodeFixesAsync(CodeFixContext context)
{
context.RegisterCodeFix(new MyCodeAction(
CSharpFeaturesResources.Delegate_invocation_can_be_simplified,
c => UpdateDocumentAsync(context.Document, context.Diagnostics.First(), c),
equivalenceKey: nameof(InvokeDelegateWithConditionalAccessCodeFixProvider)),
c => FixAsync(context.Document, context.Diagnostics.First(), c)),
context.Diagnostics);
return Task.FromResult(false);
return SpecializedTasks.EmptyTask;
}
private async Task<Document> UpdateDocumentAsync(
private Task<Document> FixAsync(
Document document, Diagnostic diagnostic, CancellationToken cancellationToken)
{
return FixAllAsync(document, ImmutableArray.Create(diagnostic), cancellationToken);
}
private async Task<Document> FixAllAsync(
Document document, ImmutableArray<Diagnostic> diagnostics, CancellationToken cancellationToken)
{
var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
var editor = new SyntaxEditor(root, document.Project.Solution.Workspace);
foreach (var diagnostic in diagnostics)
{
cancellationToken.ThrowIfCancellationRequested();
AddEdits(root, editor, diagnostic, cancellationToken);
}
var newRoot = editor.GetChangedRoot();
return document.WithSyntaxRoot(newRoot);
}
private void AddEdits(
SyntaxNode root, SyntaxEditor editor, Diagnostic diagnostic, CancellationToken cancellationToken)
{
if (diagnostic.Properties[Constants.Kind] == Constants.VariableAndIfStatementForm)
{
return HandVariableAndIfStatementFormAsync(document, root, diagnostic, cancellationToken);
HandleVariableAndIfStatementForm(root, editor, diagnostic, cancellationToken);
}
else
{
Debug.Assert(diagnostic.Properties[Constants.Kind] == Constants.SingleIfStatementForm);
return HandleSingleIfStatementForm(document, root, diagnostic, cancellationToken);
HandleSingleIfStatementForm(root, editor, diagnostic, cancellationToken);
}
}
private Document HandleSingleIfStatementForm(
Document document,
private void HandleSingleIfStatementForm(
SyntaxNode root,
SyntaxEditor editor,
Diagnostic diagnostic,
CancellationToken cancellationToken)
{
......@@ -84,12 +104,11 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context)
newStatement = newStatement.WithAdditionalAnnotations(Formatter.Annotation);
cancellationToken.ThrowIfCancellationRequested();
var newRoot = root.ReplaceNode(ifStatement, newStatement);
return document.WithSyntaxRoot(newRoot);
editor.ReplaceNode(ifStatement, newStatement);
}
private static Document HandVariableAndIfStatementFormAsync(
Document document, SyntaxNode root, Diagnostic diagnostic, CancellationToken cancellationToken)
private static void HandleVariableAndIfStatementForm(
SyntaxNode root, SyntaxEditor editor, Diagnostic diagnostic, CancellationToken cancellationToken)
{
var localDeclarationLocation = diagnostic.AdditionalLocations[0];
var ifStatementLocation = diagnostic.AdditionalLocations[1];
......@@ -115,21 +134,17 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context)
newStatement = newStatement.WithAdditionalAnnotations(Formatter.Annotation);
var editor = new SyntaxEditor(root, document.Project.Solution.Workspace);
editor.ReplaceNode(ifStatement, newStatement);
editor.RemoveNode(localDeclarationStatement, SyntaxRemoveOptions.KeepLeadingTrivia | SyntaxRemoveOptions.AddElasticMarker);
cancellationToken.ThrowIfCancellationRequested();
var newRoot = editor.GetChangedRoot();
return document.WithSyntaxRoot(newRoot);
}
private class MyCodeAction : CodeAction.DocumentChangeAction
{
public MyCodeAction(string title, Func<CancellationToken, Task<Document>> createChangedDocument, string equivalenceKey)
: base(title, createChangedDocument, equivalenceKey)
public MyCodeAction(Func<CancellationToken, Task<Document>> createChangedDocument)
: base(CSharpFeaturesResources.Delegate_invocation_can_be_simplified, createChangedDocument)
{
}
}
}
}
}
\ No newline at end of file
......@@ -870,6 +870,15 @@ internal class CSharpVSResources {
}
}
/// <summary>
/// Looks up a localized string similar to Prefer conditional function call.
/// </summary>
internal static string Prefer_conditional_function_call {
get {
return ResourceManager.GetString("Prefer_conditional_function_call", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Prefer explicit type.
/// </summary>
......
......@@ -489,4 +489,7 @@
<data name="Prefer_throw_expression" xml:space="preserve">
<value>Prefer throw-expression</value>
</data>
<data name="Prefer_conditional_function_call" xml:space="preserve">
<value>Prefer conditional function call</value>
</data>
</root>
\ No newline at end of file
......@@ -226,6 +226,7 @@ void Init()
}
}";
/*
private static readonly string s_preferThrowExpression = @"
using System;
......@@ -249,6 +250,30 @@ public C(string s)
//]
}
}
";
*/
private static readonly string s_preferConditionalFunctionCall = @"
using System;
class C
{
private string s;
public C(string s)
{
//[
// Prefer:
func?.Invoke(args);
// Over:
if (func != null)
{
func(args);
}
//]
}
}
";
#endregion
......@@ -292,7 +317,8 @@ internal StyleViewModel(OptionSet optionSet, IServiceProvider serviceProvider) :
CodeStyleItems.Add(new SimpleCodeStyleOptionViewModel(CSharpCodeStyleOptions.UseImplicitTypeWhereApparent, CSharpVSResources.When_variable_type_is_apparent, s_varWhereApparentPreviewTrue, s_varWhereApparentPreviewFalse, this, optionSet, varGroupTitle, typeStylePreferences));
CodeStyleItems.Add(new SimpleCodeStyleOptionViewModel(CSharpCodeStyleOptions.UseImplicitTypeWherePossible, CSharpVSResources.Elsewhere, s_varWherePossiblePreviewTrue, s_varWherePossiblePreviewFalse, this, optionSet, varGroupTitle, typeStylePreferences));
CodeStyleItems.Add(new SimpleCodeStyleOptionViewModel(CodeStyleOptions.PreferThrowExpression, CSharpVSResources.Prefer_throw_expression, s_preferThrowExpression, s_preferThrowExpression, this, optionSet, nullCheckingTitle));
CodeStyleItems.Add(new SimpleCodeStyleOptionViewModel(CSharpCodeStyleOptions.PreferConditionalFunctionCall, CSharpVSResources.Prefer_conditional_function_call, s_preferConditionalFunctionCall, s_preferConditionalFunctionCall, this, optionSet, nullCheckingTitle));
//CodeStyleItems.Add(new SimpleCodeStyleOptionViewModel(CodeStyleOptions.PreferThrowExpression, CSharpVSResources.Prefer_throw_expression, s_preferThrowExpression, s_preferThrowExpression, this, optionSet, nullCheckingTitle));
}
}
}
......@@ -19,5 +19,8 @@ internal static class CSharpCodeStyleOptions
public static readonly Option<CodeStyleOption<bool>> UseImplicitTypeWherePossible = new Option<CodeStyleOption<bool>>(nameof(CSharpCodeStyleOptions), nameof(UseImplicitTypeWherePossible), defaultValue: CodeStyleOption<bool>.Default,
storageLocations: new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.UseImplicitTypeWherePossible"));
public static readonly Option<CodeStyleOption<bool>> PreferConditionalFunctionCall = new Option<CodeStyleOption<bool>>(nameof(CSharpCodeStyleOptions), nameof(PreferConditionalFunctionCall), defaultValue: CodeStyleOptions.trueWithSuggestionEnforcement,
storageLocations: new RoamingProfileStorageLocation("TextEditor.CSharp.Specific.PreferConditionalFunctionCall"));
}
}
......@@ -12,7 +12,7 @@ public class CodeStyleOptions
/// but with none enforcement, so that the user is not prompted about their usage.
/// </remarks>
private static readonly CodeStyleOption<bool> trueWithNoneEnforcement = new CodeStyleOption<bool>(value: true, notification: NotificationOption.None);
private static readonly CodeStyleOption<bool> trueWithSuggestionEnforcement = new CodeStyleOption<bool>(value: true, notification: NotificationOption.Suggestion);
internal static readonly CodeStyleOption<bool> trueWithSuggestionEnforcement = new CodeStyleOption<bool>(value: true, notification: NotificationOption.Suggestion);
/// <summary>
/// This option says if we should simplify away the <see langword="this"/>. or <see langword="Me"/>. in field access expressions.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册