Skip to content

Commit cd16b47

Browse files
committed
Don't warn about IScheduler.Schedule
Close #188
1 parent 8a3f6f6 commit cd16b47

3 files changed

Lines changed: 44 additions & 28 deletions

File tree

IDisposableAnalyzers.Test/IDISP004DoNotIgnoreCreatedTests/Valid.Rx.cs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
namespace IDisposableAnalyzers.Test.IDISP004DoNotIgnoreCreatedTests
1+
namespace IDisposableAnalyzers.Test.IDISP004DoNotIgnoreCreatedTests
22
{
33
using Gu.Roslyn.Asserts;
44
using NUnit.Framework;
@@ -303,5 +303,26 @@ internal string AddAndReturnToString()
303303
}";
304304
RoslynAssert.Valid(Analyzer, DisposableCode, compositeDisposableExtCode, code);
305305
}
306+
307+
[Test]
308+
public static void ISchedulerSchedule()
309+
{
310+
var code = @"
311+
namespace N
312+
{
313+
using System;
314+
using System.Reactive.Concurrency;
315+
316+
class C
317+
{
318+
internal void M(IScheduler scheduler)
319+
{
320+
scheduler.Schedule(() => Console.WriteLine());
321+
}
322+
}
323+
}";
324+
325+
RoslynAssert.Valid(Analyzer, code);
326+
}
306327
}
307328
}

IDisposableAnalyzers/Analyzers/CreationAnalyzer.cs

Lines changed: 21 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
namespace IDisposableAnalyzers
22
{
33
using System.Collections.Immutable;
4-
using System.Diagnostics.CodeAnalysis;
54
using Gu.Roslyn.AnalyzerExtensions;
65
using Microsoft.CodeAnalysis;
76
using Microsoft.CodeAnalysis.CSharp;
@@ -25,7 +24,7 @@ public override void Initialize(AnalysisContext context)
2524
private static void Handle(SyntaxNodeAnalysisContext context)
2625
{
2726
if (!context.IsExcludedFromAnalysis() &&
28-
ShouldCheck(context, out var expression))
27+
ShouldCheck(context) is { } expression)
2928
{
3029
if (context.Node is ObjectCreationExpressionSyntax objectCreation &&
3130
context.SemanticModel.TryGetType(objectCreation, context.CancellationToken, out var type) &&
@@ -45,33 +44,28 @@ private static void Handle(SyntaxNodeAnalysisContext context)
4544
}
4645
}
4746

48-
private static bool ShouldCheck(SyntaxNodeAnalysisContext context, [NotNullWhen(true)] out ExpressionSyntax? expression)
47+
private static ExpressionSyntax? ShouldCheck(SyntaxNodeAnalysisContext context)
4948
{
50-
if (context.Node is ExpressionSyntax candidate)
49+
return context.Node switch
5150
{
52-
switch (candidate.Kind())
53-
{
54-
case SyntaxKind.InvocationExpression:
55-
case SyntaxKind.ObjectCreationExpression:
56-
expression = candidate;
57-
return true;
58-
case SyntaxKind.SimpleMemberAccessExpression
59-
when candidate is MemberAccessExpressionSyntax memberAccess &&
60-
context.SemanticModel.TryGetSymbol(memberAccess.Expression, context.CancellationToken, out IPropertySymbol? property) &&
61-
Disposable.IsPotentiallyAssignableFrom(property.Type, context.Compilation):
62-
expression = memberAccess.Expression;
63-
return true;
64-
case SyntaxKind.ConditionalAccessExpression
65-
when candidate is ConditionalAccessExpressionSyntax conditionalAccess &&
66-
context.SemanticModel.TryGetSymbol(conditionalAccess.Expression, context.CancellationToken, out IPropertySymbol? property) &&
67-
Disposable.IsPotentiallyAssignableFrom(property.Type, context.Compilation):
68-
expression = conditionalAccess.Expression;
69-
return true;
70-
}
71-
}
72-
73-
expression = null;
74-
return false;
51+
InvocationExpressionSyntax { Expression: MemberAccessExpressionSyntax { Expression:{} expression, Name: { Identifier: { ValueText: "Schedule" } } } }
52+
when context.SemanticModel.TryGetNamedType(expression, context.CancellationToken, out var type) &&
53+
type.IsAssignableTo(KnownSymbol.RxIScheduler, context.SemanticModel.Compilation)
54+
=> null,
55+
InvocationExpressionSyntax invocation
56+
=> invocation,
57+
ObjectCreationExpressionSyntax objectCreation
58+
=> objectCreation,
59+
MemberAccessExpressionSyntax { Expression: { } expression }
60+
when context.SemanticModel.TryGetSymbol(expression, context.CancellationToken, out IPropertySymbol? property) &&
61+
Disposable.IsPotentiallyAssignableFrom(property.Type, context.Compilation)
62+
=> expression,
63+
ConditionalAccessExpressionSyntax { Expression: { } expression }
64+
when context.SemanticModel.TryGetSymbol(expression, context.CancellationToken, out IPropertySymbol? property) &&
65+
Disposable.IsPotentiallyAssignableFrom(property.Type, context.Compilation)
66+
=> expression,
67+
_ => null,
68+
};
7569
}
7670

7771
private static bool IsStaticFieldInitializer(ObjectCreationExpressionSyntax objectCreation)

IDisposableAnalyzers/Helpers/KnownSymbols/KnownSymbol.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ internal static class KnownSymbol
6161

6262
internal static readonly SerialDisposableType SerialDisposable = new SerialDisposableType();
6363
internal static readonly RxDisposableType RxDisposable = new RxDisposableType();
64+
internal static readonly QualifiedType RxIScheduler = new QualifiedType("System.Reactive.Concurrency.IScheduler");
6465
internal static readonly SingleAssignmentDisposableType SingleAssignmentDisposable = new SingleAssignmentDisposableType();
6566
internal static readonly CompositeDisposableType CompositeDisposable = new CompositeDisposableType();
6667

0 commit comments

Comments
 (0)