Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -55,19 +55,42 @@ public override void Initialize(AnalysisContext context)
};
}

private static void CheckForNullValue(OperationAnalysisContext context, IOperation operation)
{
if (operation is IConditionalOperation conditionalOp)
{
if (conditionalOp.WhenTrue is { } whenTrue)
{
CheckForNullValue(context, whenTrue);
}

if (conditionalOp.WhenFalse is { } whenFalse)
{
CheckForNullValue(context, whenFalse);
}
}
else if (operation.ConstantValue is { HasValue: true, Value: null } &&
operation.Syntax is { } nullSyntax)
{
context.ReportDiagnostic(Diagnostic.Create(Descriptor, nullSyntax.GetLocation()));
}
}

private void AnalyzerReturnOperation(OperationAnalysisContext context)
{
var returnOperation = (IReturnOperation)context.Operation;

if (returnOperation.ReturnedValue is { ConstantValue: { HasValue: true, Value: null } } && // could be null for implicit returns
returnOperation.ReturnedValue.Syntax is { } returnedValueSyntax &&
Utils.GetContainingFunctionBlock(returnOperation) is { } block &&
FindOwningSymbol(block, context.ContainingSymbol) is { } method &&
!method.IsAsync &&
Utils.IsTask(method.ReturnType) &&
!this.LanguageUtils.MethodReturnsNullableReferenceType(method))
// ReturnedValue is null for implicit/void returns
if (returnOperation.ReturnedValue is not { } returnedValue ||
Utils.GetContainingFunctionBlock(returnOperation) is not { } block ||
FindOwningSymbol(block, context.ContainingSymbol) is not { } owningMethod ||
owningMethod.IsAsync ||
!Utils.IsTask(owningMethod.ReturnType) ||
this.LanguageUtils.MethodReturnsNullableReferenceType(owningMethod))
{
context.ReportDiagnostic(Diagnostic.Create(Descriptor, returnedValueSyntax.GetLocation()));
return;
}

CheckForNullValue(context, returnedValue);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ public Task<object> GetTaskObj()
}

[Fact]
public async Task NullInTernary_NoDiagnostic_FalseNegative()
public async Task NullInTernary_Diagnostic()
{
var test = @"
using System.Threading.Tasks;
Expand All @@ -156,7 +156,7 @@ class Test
{
public Task<object> GetTaskObj(bool b)
{
return b ? default(Task<object>) : null;
return b ? [|default(Task<object>)|] : [|null|];
}
}
";
Expand All @@ -166,6 +166,47 @@ public Task<object> GetTaskObj(bool b)
}.RunAsync();
}

[Fact]
public async Task NullInTernaryReturnStatement_Diagnostic()
{
var csharpTest = @"
using System.Threading.Tasks;

class Test
{
public Task First(bool flag)
{
return flag
? [|null|]
: Task.CompletedTask;
}

public Task Second(bool flag) =>
flag
? [|null|]
: Task.CompletedTask;
}
";
await new CSVerify.Test
{
TestCode = csharpTest,
}.RunAsync();

var vbTest = @"
Imports System.Threading.Tasks

Friend Class Test
Public Function First(flag As Boolean) As Task
Return If(flag, [|Nothing|], Task.CompletedTask)
End Function
End Class
";
await new VerifyVB.Test
{
TestCode = vbTest,
}.RunAsync();
}

[Fact]
public async Task MultipleFaultyReturns_MultipleDiagnostics()
{
Expand Down
Morty Proxy This is a proxified and sanitized view of the page, visit original site.