From 24fddfff1a137e0280bad05914737ce311241f0f Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Mon, 15 Jan 2018 15:50:32 +0100 Subject: [PATCH] Added check for value type constraint parameter. --- .../UseIsNullCheck/UseIsNullCheckTests.cs | 37 ++++++++++++++----- .../UseIsNullCheck/UseIsNullCheckTests.vb | 15 ++++++++ .../AbstractUseIsNullDiagnosticAnalyzer.cs | 24 +++++++++++- 3 files changed, 66 insertions(+), 10 deletions(-) diff --git a/src/EditorFeatures/CSharpTest/UseIsNullCheck/UseIsNullCheckTests.cs b/src/EditorFeatures/CSharpTest/UseIsNullCheck/UseIsNullCheckTests.cs index 65ce66c37e5..da5da56a6bf 100644 --- a/src/EditorFeatures/CSharpTest/UseIsNullCheck/UseIsNullCheckTests.cs +++ b/src/EditorFeatures/CSharpTest/UseIsNullCheck/UseIsNullCheckTests.cs @@ -226,22 +226,22 @@ public async Task TestMissingIfValueParameterTypeIsUnconstraintGeneric() @" class C { - public static void NotNull(T value, string parameterName) + public static void NotNull(T value) { if ([||]ReferenceEquals(value, null)) { - throw new System.ArgumentNullException(parameterName); + return; } } } ", @" class C { - public static void NotNull(T value, string parameterName) + public static void NotNull(T value) { if (value == null) { - throw new System.ArgumentNullException(parameterName); + return; } } } @@ -250,17 +250,17 @@ public static void NotNull(T value, string parameterName) [WorkItem(23581, "https://github.com/dotnet/roslyn/issues/23581")] [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseIsNullCheck)] - public async Task TestValueParameterTypeIsConstraintGeneric() + public async Task TestValueParameterTypeIsRefConstraintGeneric() { await TestInRegularAndScriptAsync( @" class C { - public static void NotNull(T value, string parameterName) where T:class + public static void NotNull(T value) where T:class { if ([||]ReferenceEquals(value, null)) { - throw new System.ArgumentNullException(parameterName); + return; } } } @@ -268,11 +268,30 @@ class C @" class C { - public static void NotNull(T value, string parameterName) where T:class + public static void NotNull(T value) where T:class { if (value == null) { - throw new System.ArgumentNullException(parameterName); + return; + } + } +} +"); + } + + [WorkItem(23581, "https://github.com/dotnet/roslyn/issues/23581")] + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsUseIsNullCheck)] + public async Task TestValueParameterTypeIsValueConstraintGeneric() + { + await TestMissingAsync( +@" +class C +{ + public static void NotNull(T value) where T:struct + { + if ([||]ReferenceEquals(value, null)) + { + return; } } } diff --git a/src/EditorFeatures/VisualBasicTest/UseIsNullCheck/UseIsNullCheckTests.vb b/src/EditorFeatures/VisualBasicTest/UseIsNullCheck/UseIsNullCheckTests.vb index 1c3d85e6c58..ce51abf0891 100644 --- a/src/EditorFeatures/VisualBasicTest/UseIsNullCheck/UseIsNullCheckTests.vb +++ b/src/EditorFeatures/VisualBasicTest/UseIsNullCheck/UseIsNullCheckTests.vb @@ -179,6 +179,21 @@ class C return end if end sub +end class") + End Function + + + + Public Async Function TestValueParameterTypeIsValueConstraintGeneric() As Task + Await TestMissingInRegularAndScriptAsync( +"Imports System + +class C + sub M(Of T As Structure)(v as T) + if ([||]ReferenceEquals(Nothing, v)) + return + end if + end sub end class") End Function End Class diff --git a/src/Features/Core/Portable/UseIsNullCheck/AbstractUseIsNullDiagnosticAnalyzer.cs b/src/Features/Core/Portable/UseIsNullCheck/AbstractUseIsNullDiagnosticAnalyzer.cs index cebf9a6ddc8..35ffeb63b21 100644 --- a/src/Features/Core/Portable/UseIsNullCheck/AbstractUseIsNullDiagnosticAnalyzer.cs +++ b/src/Features/Core/Portable/UseIsNullCheck/AbstractUseIsNullDiagnosticAnalyzer.cs @@ -28,7 +28,8 @@ public override bool OpenFileOnly(Workspace workspace) => false; protected override void InitializeWorker(AnalysisContext context) - => context.RegisterCompilationStartAction(compilationContext => { + => context.RegisterCompilationStartAction(compilationContext => + { var objectType = compilationContext.Compilation.GetSpecialType(SpecialType.System_Object); if (objectType != null) { @@ -109,6 +110,11 @@ private void AnalyzeSyntax(SyntaxNodeAnalysisContext context, IMethodSymbol refe return; } + if (HasValueTypeConstraintGenericParameter(syntaxFacts, semanticModel, arguments[0], arguments[1], cancellationToken)) + { + return; + } + var additionalLocations = ImmutableArray.Create(invocation.GetLocation()); var properties = ImmutableDictionary.Empty; @@ -125,6 +131,22 @@ private void AnalyzeSyntax(SyntaxNodeAnalysisContext context, IMethodSymbol refe additionalLocations, properties)); } + private static bool HasValueTypeConstraintGenericParameter(ISyntaxFactsService syntaxFacts, SemanticModel semanticModel, SyntaxNode node1, SyntaxNode node2, CancellationToken cancellationToken) + { + var valueNode = syntaxFacts.IsNullLiteralExpression(syntaxFacts.GetExpressionOfArgument(node1)) ? node2 : node1; + var argumentExpression = syntaxFacts.GetExpressionOfArgument(valueNode); + if (argumentExpression != null) + { + var parameterType = semanticModel.GetTypeInfo(argumentExpression, cancellationToken).Type; + if (parameterType is ITypeParameterSymbol typeParameter) + { + return typeParameter.HasValueTypeConstraint; + } + } + + return false; + } + private static bool MatchesPattern(ISyntaxFactsService syntaxFacts, SyntaxNode node1, SyntaxNode node2) => syntaxFacts.IsNullLiteralExpression(syntaxFacts.GetExpressionOfArgument(node1)) && !syntaxFacts.IsNullLiteralExpression(syntaxFacts.GetExpressionOfArgument(node2)); -- GitLab