提交 bf385f86 编写于 作者: C Cyrus Najmabadi

Don't add null checks for nullable-structs. The fact that they're nullable...

Don't add null checks for nullable-structs.  The fact that they're nullable indicates they don't need checks.
上级 a300e982
......@@ -3,6 +3,7 @@
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeRefactorings;
using Microsoft.CodeAnalysis.CodeStyle;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.CodeStyle;
using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeRefactorings;
using Microsoft.CodeAnalysis.GenerateConstructorFromMembers;
......@@ -955,7 +956,7 @@ class Z
public Z(int a, string b{|Navigation:)|}
{
if (b == null)
if (b is null)
{
throw new ArgumentNullException(nameof(b));
}
......@@ -970,6 +971,82 @@ class Z
Option(CodeStyleOptions.PreferThrowExpression, CodeStyleOptions.FalseWithSilentEnforcement)));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructorFromMembers)]
public async Task TestAddNullChecks3()
{
await TestWithPickMembersDialogAsync(
@"
using System;
using System.Collections.Generic;
class Z
{
int a;
int? b;
[||]
}",
@"
using System;
using System.Collections.Generic;
class Z
{
int a;
int? b;
public Z(int a, int? b{|Navigation:)|}
{
this.a = a;
this.b = b;
}
}",
chosenSymbols: new string[] { "a", "b" },
optionsCallback: options => options[0].Value = true,
parameters: new TestParameters(options:
Option(CodeStyleOptions.PreferThrowExpression, CodeStyleOptions.FalseWithSilentEnforcement)));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructorFromMembers)]
public async Task TestAddNullChecks_CSharp6()
{
await TestWithPickMembersDialogAsync(
@"
using System;
using System.Collections.Generic;
class Z
{
int a;
string b;
[||]
}",
@"
using System;
using System.Collections.Generic;
class Z
{
int a;
string b;
public Z(int a, string b{|Navigation:)|}
{
if (b == null)
{
throw new ArgumentNullException(nameof(b));
}
this.a = a;
this.b = b;
}
}",
chosenSymbols: new string[] { "a", "b" },
optionsCallback: options => options[0].Value = true,
parameters: new TestParameters(
parseOptions: CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp6),
options: Option(CodeStyleOptions.PreferThrowExpression, CodeStyleOptions.FalseWithSilentEnforcement)));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateConstructorFromMembers)]
public async Task TestMissingOnMember1()
{
......
......@@ -59,14 +59,14 @@ protected override async Task<Document> GetChangedDocumentAsync(CancellationToke
var compilation = await _document.Project.GetCompilationAsync(cancellationToken).ConfigureAwait(false);
var (fields, constructor) = factory.CreateFieldDelegatingConstructor(
compilation,
syntaxTree.Options,
_state.ContainingType.Name,
_state.ContainingType,
_state.Parameters,
parameterToExistingFieldMap,
parameterToNewFieldMap: null,
addNullChecks: _addNullChecks,
preferThrowExpression: preferThrowExpression,
cancellationToken: cancellationToken);
preferThrowExpression: preferThrowExpression);
// If the user has selected a set of members (i.e. TextSpan is not empty), then we will
// choose the right location (i.e. null) to insert the constructor. However, if they're
......
......@@ -260,18 +260,7 @@ private bool IsNullLiteral(IOperation operand)
Compilation compilation, SyntaxGenerator generator,
IParameterSymbol parameter, ParseOptions options)
{
var identifier = generator.IdentifierName(parameter.Name);
var nullExpr = generator.NullLiteralExpression();
var condition = generator.SupportsPatterns(options)
? generator.IsPatternExpression(identifier, generator.ConstantPattern(nullExpr))
: generator.ReferenceEqualsExpression(identifier, nullExpr);
// generates: if (s == null) throw new ArgumentNullException(nameof(s))
return (TStatementSyntax)generator.IfStatement(
condition,
SpecializedCollections.SingletonEnumerable(
generator.ThrowStatement(
CreateArgumentNullException(compilation, generator, parameter))));
return (TStatementSyntax)generator.CreateNullCheckAndThrowStatement(compilation, parameter, options);
}
private static TStatementSyntax CreateStringCheckStatement(
......
......@@ -66,18 +66,18 @@ internal static partial class SyntaxGeneratorExtensions
public static (ImmutableArray<ISymbol> fields, ISymbol constructor) CreateFieldDelegatingConstructor(
this SyntaxGenerator factory,
Compilation compilation,
ParseOptions parseOptions,
string typeName,
INamedTypeSymbol containingTypeOpt,
ImmutableArray<IParameterSymbol> parameters,
IDictionary<string, ISymbol> parameterToExistingFieldMap,
IDictionary<string, string> parameterToNewFieldMap,
bool addNullChecks,
bool preferThrowExpression,
CancellationToken cancellationToken)
bool preferThrowExpression)
{
var fields = factory.CreateFieldsForParameters(parameters, parameterToNewFieldMap);
var statements = factory.CreateAssignmentStatements(
compilation, parameters, parameterToExistingFieldMap, parameterToNewFieldMap,
compilation, parseOptions, parameters, parameterToExistingFieldMap, parameterToNewFieldMap,
addNullChecks, preferThrowExpression).SelectAsArray(
s => s.WithAdditionalAnnotations(Simplifier.Annotation));
......@@ -180,15 +180,21 @@ private static bool TryGetValue(IDictionary<string, ISymbol> dictionary, string
factory.IdentifierName(parameter.Name))));
}
public static SyntaxNode CreateIfNullThrowStatement(
public static SyntaxNode CreateNullCheckAndThrowStatement(
this SyntaxGenerator factory,
Compilation compilation,
IParameterSymbol parameter)
IParameterSymbol parameter,
ParseOptions options)
{
var identifier = factory.IdentifierName(parameter.Name);
var nullExpr = factory.NullLiteralExpression();
var condition = factory.SupportsPatterns(options)
? factory.IsPatternExpression(identifier, factory.ConstantPattern(nullExpr))
: factory.ReferenceEqualsExpression(identifier, nullExpr);
// generates: if (s == null) throw new ArgumentNullException(nameof(s))
return factory.IfStatement(
factory.ReferenceEqualsExpression(
factory.IdentifierName(parameter.Name),
factory.NullLiteralExpression()),
condition,
SpecializedCollections.SingletonEnumerable(
factory.ExpressionStatement(
factory.CreateThrowArgumentNullExpression(compilation, parameter))));
......@@ -197,6 +203,7 @@ private static bool TryGetValue(IDictionary<string, ISymbol> dictionary, string
public static ImmutableArray<SyntaxNode> CreateAssignmentStatements(
this SyntaxGenerator factory,
Compilation compilation,
ParseOptions parseOptions,
ImmutableArray<IParameterSymbol> parameters,
IDictionary<string, ISymbol> parameterToExistingFieldMap,
IDictionary<string, string> parameterToNewFieldMap,
......@@ -233,7 +240,7 @@ private static bool TryGetValue(IDictionary<string, ISymbol> dictionary, string
.WithAdditionalAnnotations(Simplifier.Annotation);
factory.AddAssignmentStatements(
compilation, parameter, fieldAccess,
compilation, parseOptions, parameter, fieldAccess,
addNullChecks, preferThrowExpression,
nullCheckStatements, assignStatements);
}
......@@ -246,6 +253,7 @@ private static bool TryGetValue(IDictionary<string, ISymbol> dictionary, string
public static void AddAssignmentStatements(
this SyntaxGenerator factory,
Compilation compilation,
ParseOptions parseOptions,
IParameterSymbol parameter,
SyntaxNode fieldAccess,
bool addNullChecks,
......@@ -253,7 +261,10 @@ private static bool TryGetValue(IDictionary<string, ISymbol> dictionary, string
ArrayBuilder<SyntaxNode> nullCheckStatements,
ArrayBuilder<SyntaxNode> assignStatements)
{
var shouldAddNullCheck = addNullChecks && parameter.Type.CanAddNullCheck();
// Don't want to add a null check for something of the form `int?`. The type was
// already declared as nullable to indicate that null is ok. Adding a null check
// just disallows something that should be allowed.
var shouldAddNullCheck = addNullChecks && parameter.Type.CanAddNullCheck() && !parameter.Type.IsNullable();
if (shouldAddNullCheck && preferThrowExpression)
{
// Generate: this.x = x ?? throw ...
......@@ -266,7 +277,7 @@ private static bool TryGetValue(IDictionary<string, ISymbol> dictionary, string
{
// generate: if (x == null) throw ...
nullCheckStatements.Add(
factory.CreateIfNullThrowStatement(compilation, parameter));
factory.CreateNullCheckAndThrowStatement(compilation, parameter, parseOptions));
}
// generate: this.x = x;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册