提交 45cb3aba 编写于 作者: C CyrusNajmabadi

Properly use ?. in an expression containing a nullable type.

上级 a2bfbbcb
......@@ -360,5 +360,75 @@ public void Method<T>(Expression<Func<T, string>> functor)
}
}");
}
[WorkItem(19774, "https://github.com/dotnet/roslyn/issues/19774")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseNullPropagation)]
public async Task TestNullableMemberAccess()
{
await TestInRegularAndScriptAsync(
@"
using System;
class C
{
void Main(DateTime? toDate)
{
var v = [||]toDate == null ? null : toDate.Value.ToString(""yyyy/MM/ dd"");
}
}
",
@"
using System;
class C
{
void Main(DateTime? toDate)
{
var v = toDate?.ToString(""yyyy/MM/ dd"");
}
}
");
}
[WorkItem(19774, "https://github.com/dotnet/roslyn/issues/19774")]
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseNullPropagation)]
public async Task TestNullableElementAccess()
{
await TestInRegularAndScriptAsync(
@"
using System;
struct S
{
public string this[int i] => """";
}
class C
{
void Main(S? s)
{
var x = [||]s == null ? null : s.Value[0];
}
}
",
@"
using System;
struct S
{
public string this[int i] => """";
}
class C
{
void Main(S? s)
{
var x = s?[0];
}
}
");
}
}
}
\ No newline at end of file
......@@ -65,6 +65,7 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context)
syntaxFacts.GetPartsOfConditionalExpression(
conditionalExpression, out var condition, out var whenTrue, out var whenFalse);
var whenPartIsNullable = diagnostic.Properties.ContainsKey(UseNullPropagationConstants.WhenPartIsNullable);
editor.ReplaceNode(conditionalExpression,
(c, g) => {
syntaxFacts.GetPartsOfConditionalExpression(
......@@ -82,7 +83,7 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context)
}
var newNode = CreateConditionalAccessExpression(
syntaxFacts, g, currentWhenPartToCheck, match, c);
syntaxFacts, g, whenPartIsNullable, currentWhenPartToCheck, match, c);
newNode = newNode.WithTriviaFrom(c);
return newNode;
......@@ -93,10 +94,41 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context)
}
private SyntaxNode CreateConditionalAccessExpression(
ISyntaxFactsService syntaxFacts, SyntaxGenerator generator,
ISyntaxFactsService syntaxFacts, SyntaxGenerator generator, bool whenPartIsNullable,
SyntaxNode whenPart, SyntaxNode match, SyntaxNode currentConditional)
{
var memberAccess = match.Parent as TMemberAccessExpression;
if (whenPartIsNullable)
{
if (match.Parent is TMemberAccessExpression memberAccess)
{
var nameNode = syntaxFacts.GetNameOfMemberAccessExpression(memberAccess);
syntaxFacts.GetNameAndArityOfSimpleName(nameNode, out var name, out var arity);
var comparer = syntaxFacts.IsCaseSensitive
? StringComparer.Ordinal
: CaseInsensitiveComparison.Comparer;
if (arity == 0 && comparer.Equals(name, nameof(Nullable<int>.Value)))
{
// They're calling ".Value" off of a nullable. Because we're moving to ?.
// we want to remove the .Value as well. i.e. we should generate:
//
// foo?.Bar() not foo?.Value.Bar();
return CreateConditionalAccessExpression(
syntaxFacts, generator, whenPart, match,
memberAccess.Parent, currentConditional);
}
}
}
return CreateConditionalAccessExpression(
syntaxFacts, generator, whenPart, match,
match.Parent, currentConditional);
}
private SyntaxNode CreateConditionalAccessExpression(
ISyntaxFactsService syntaxFacts, SyntaxGenerator generator,
SyntaxNode whenPart, SyntaxNode match, SyntaxNode matchParent, SyntaxNode currentConditional)
{
var memberAccess = matchParent as TMemberAccessExpression;
if (memberAccess != null)
{
return whenPart.ReplaceNode(memberAccess,
......@@ -106,7 +138,7 @@ public override Task RegisterCodeFixesAsync(CodeFixContext context)
syntaxFacts.GetNameOfMemberAccessExpression(memberAccess))));
}
var elementAccess = match.Parent as TElementAccessExpression;
var elementAccess = matchParent as TElementAccessExpression;
if (elementAccess != null)
{
return whenPart.ReplaceNode(elementAccess,
......
......@@ -8,6 +8,11 @@
namespace Microsoft.CodeAnalysis.UseNullPropagation
{
internal static class UseNullPropagationConstants
{
public const string WhenPartIsNullable = nameof(WhenPartIsNullable);
}
internal abstract class AbstractUseNullPropagationDiagnosticAnalyzer<
TSyntaxKind,
TExpressionSyntax,
......@@ -147,10 +152,18 @@ private void AnalyzeSyntax(SyntaxNodeAnalysisContext context, INamedTypeSymbol e
conditionPartToCheck.GetLocation(),
whenPartToCheck.GetLocation());
var properties = ImmutableDictionary<string, string>.Empty;
var whenPartIsNullable = semanticModel.GetTypeInfo(whenPartMatch).Type?.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T;
if (whenPartIsNullable)
{
properties = properties.Add(UseNullPropagationConstants.WhenPartIsNullable, "");
}
context.ReportDiagnostic(Diagnostic.Create(
this.GetDescriptorWithSeverity(option.Notification.Value),
conditionalExpression.GetLocation(),
locations));
locations,
properties));
}
internal static SyntaxNode GetWhenPartMatch(
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册