Skip to content
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
66 changes: 64 additions & 2 deletions Raven.CodeAnalysis.Test/TaskCompletionSourceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public class TaskCompletionSourceTests : CodeFixVerifier
{
//No diagnostics expected to show up
[TestMethod]
public void TestMethod1()
public void Generic_with_RunContinuationsAsynchronously()
{
const string input = @"
class C
Expand All @@ -26,7 +26,7 @@ class C
}

[TestMethod]
public void TestMethod2()
public void Generic_without_RunContinuationsAsynchronously()
{
const string input = @"
class C
Expand Down Expand Up @@ -70,6 +70,68 @@ class C
}
});
}

//No diagnostics expected to show up
[TestMethod]
public void NonGeneric_with_RunContinuationsAsynchronously()
{
const string input = @"
class C
{
private void Method1() { var tcs = new TaskCompletionSource(TaskContinuationOptions.RunContinuationsAsynchronously); }

private void Method2() { var tcs = new System.Threading.Tasks.TaskCompletionSource(null, System.Threading.Tasks.TaskContinuationOptions.RunContinuationsAsynchronously); }

private void Method3() { var tcs = new TaskCompletionSource(TaskContinuationOptions.RunContinuationsAsynchronously | TaskContinuationOptions.AttachedToParent); }
}";
VerifyCSharpDiagnostic(input);
}

[TestMethod]
public void NonGeneric_without_RunContinuationsAsynchronously()
{
const string input = @"
class C
{
private void Method1() { var tcs = new TaskCompletionSource(); }

private void Method2() { var tcs = new System.Threading.Tasks.TaskCompletionSource(); }

private void Method3() { var tcs = new TaskCompletionSource(TaskContinuationOptions.AttachedToParent); }
}";
VerifyCSharpDiagnostic(
input,
new DiagnosticResult
{
Id = DiagnosticIds.TaskCompletionSourceMustHaveRunContinuationsAsynchronouslySet,
Message = "TaskCompletionSource must have TaskCreationOptions.RunContinuationsAsynchronously set",
Severity = DiagnosticSeverity.Error,
Locations = new[]
{
new DiagnosticResultLocation("Test0.cs", 4, 37)
}
},
new DiagnosticResult
{
Id = DiagnosticIds.TaskCompletionSourceMustHaveRunContinuationsAsynchronouslySet,
Message = "TaskCompletionSource must have TaskCreationOptions.RunContinuationsAsynchronously set",
Severity = DiagnosticSeverity.Error,
Locations = new[]
{
new DiagnosticResultLocation("Test0.cs", 6, 40)
}
},
new DiagnosticResult
{
Id = DiagnosticIds.TaskCompletionSourceMustHaveRunContinuationsAsynchronouslySet,
Message = "TaskCompletionSource must have TaskCreationOptions.RunContinuationsAsynchronously set",
Severity = DiagnosticSeverity.Error,
Locations = new[]
{
new DiagnosticResultLocation("Test0.cs", 8, 37)
}
});
}

protected override DiagnosticAnalyzer GetCSharpDiagnosticAnalyzer()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,9 @@ public override void Initialize(AnalysisContext context)
private static void AnalyzeSyntax(SyntaxNodeAnalysisContext context)
{
var objectCreationExpressionSyntax = (ObjectCreationExpressionSyntax)context.Node;
var genericNameSyntax = objectCreationExpressionSyntax.Type as GenericNameSyntax;
if (genericNameSyntax == null)
{
var qualifiedNameSyntax = objectCreationExpressionSyntax.Type as QualifiedNameSyntax;
if (qualifiedNameSyntax == null)
return;

genericNameSyntax = qualifiedNameSyntax.Right as GenericNameSyntax;
if (genericNameSyntax == null)
return;
}

if (string.Equals(genericNameSyntax.Identifier.Text, TaskCompletionSourceName) == false)
if (IsGenericTaskCompletionSourceCreation(objectCreationExpressionSyntax) == false &&
IsNonGenericTaskCompletionSourceCreation(objectCreationExpressionSyntax) == false)
return;

var arguments = objectCreationExpressionSyntax.ArgumentList;
Expand All @@ -51,6 +41,31 @@ private static void AnalyzeSyntax(SyntaxNodeAnalysisContext context)
ReportDiagnostic(context, objectCreationExpressionSyntax);
}

private static bool IsGenericTaskCompletionSourceCreation(ObjectCreationExpressionSyntax objectCreationExpressionSyntax) =>
IsTaskCompletionSource<GenericNameSyntax>(objectCreationExpressionSyntax);

private static bool IsNonGenericTaskCompletionSourceCreation(ObjectCreationExpressionSyntax objectCreationExpressionSyntax) =>
IsTaskCompletionSource<IdentifierNameSyntax>(objectCreationExpressionSyntax);

private static bool IsTaskCompletionSource<TNameSyntax>(ObjectCreationExpressionSyntax objectCreationExpressionSyntax)
where TNameSyntax : SimpleNameSyntax
{
var nameSyntax = objectCreationExpressionSyntax.Type as TNameSyntax;

if (nameSyntax == null)
{
var qualifiedNameSyntax = objectCreationExpressionSyntax.Type as QualifiedNameSyntax;
if (qualifiedNameSyntax == null)
return false;

nameSyntax = qualifiedNameSyntax.Right as TNameSyntax;
if (nameSyntax == null)
return false;
}

return string.Equals(nameSyntax.Identifier.Text, TaskCompletionSourceName);
}

private static bool IsRunContinuationsAsynchronously(ExpressionSyntax expression)
{
var memberAccessExpressionSyntax = expression as MemberAccessExpressionSyntax;
Expand Down
Loading