Skip to content

Commit a6f5368

Browse files
committed
Simplify.
1 parent 4962177 commit a6f5368

4 files changed

Lines changed: 97 additions & 28 deletions

File tree

IDisposableAnalyzers/Analyzers/FieldAndPropertyDeclarationAnalyzer.cs

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,11 @@ public override void Initialize(AnalysisContext context)
2727
private static void HandleField(SyntaxNodeAnalysisContext context)
2828
{
2929
if (!context.IsExcludedFromAnalysis() &&
30-
context.ContainingSymbol is IFieldSymbol field &&
31-
!field.IsStatic &&
32-
!field.IsConst &&
33-
FieldOrProperty.TryCreate(field, out var fieldOrProperty) &&
30+
context.ContainingSymbol is IFieldSymbol { IsStatic: false, IsConst: false } field &&
31+
context.Node is FieldDeclarationSyntax declaration &&
3432
Disposable.IsPotentiallyAssignableFrom(field.Type, context.Compilation))
3533
{
36-
HandleFieldOrProperty(context, fieldOrProperty);
34+
HandleFieldOrProperty(context, new FieldOrPropertyAndDeclaration(field, declaration));
3735
}
3836
}
3937

@@ -51,45 +49,43 @@ private static void HandleProperty(SyntaxNodeAnalysisContext context)
5149
return;
5250
}
5351

54-
var propertyDeclaration = (PropertyDeclarationSyntax)context.Node;
55-
if (propertyDeclaration.ExpressionBody != null)
52+
var declaration = (PropertyDeclarationSyntax)context.Node;
53+
if (declaration.ExpressionBody != null)
5654
{
5755
return;
5856
}
5957

60-
if (propertyDeclaration.TryGetSetter(out var setter) &&
58+
if (declaration.TryGetSetter(out var setter) &&
6159
setter.Body != null)
6260
{
6361
// Handle the backing field
6462
return;
6563
}
6664

67-
if (FieldOrProperty.TryCreate(property, out var fieldOrProperty) &&
68-
Disposable.IsPotentiallyAssignableFrom(property.Type, context.Compilation))
65+
if (Disposable.IsPotentiallyAssignableFrom(property.Type, context.Compilation))
6966
{
70-
HandleFieldOrProperty(context, fieldOrProperty);
67+
HandleFieldOrProperty(context, new FieldOrPropertyAndDeclaration(property, declaration));
7168
}
7269
}
7370

74-
private static void HandleFieldOrProperty(SyntaxNodeAnalysisContext context, FieldOrProperty fieldOrProperty)
71+
private static void HandleFieldOrProperty(SyntaxNodeAnalysisContext context, FieldOrPropertyAndDeclaration member)
7572
{
76-
using var assignedValues = AssignedValueWalker.Borrow(fieldOrProperty.Symbol, context.SemanticModel, context.CancellationToken);
73+
using var assignedValues = AssignedValueWalker.Borrow(member.FieldOrProperty.Symbol, context.SemanticModel, context.CancellationToken);
7774
using var recursive = RecursiveValues.Borrow(assignedValues, context.SemanticModel, context.CancellationToken);
7875
if (Disposable.IsAnyCreation(recursive, context.SemanticModel, context.CancellationToken).IsEither(Result.Yes, Result.AssumeYes))
7976
{
8077
if (Disposable.IsAnyCachedOrInjected(recursive, context.SemanticModel, context.CancellationToken).IsEither(Result.Yes, Result.AssumeYes) ||
81-
IsMutableFromOutside(fieldOrProperty))
78+
IsMutableFromOutside(member.FieldOrProperty))
8279
{
8380
context.ReportDiagnostic(Diagnostic.Create(Descriptors.IDISP008DoNotMixInjectedAndCreatedForMember, context.Node.GetLocation()));
8481
}
85-
else if (context.Node.TryFirstAncestorOrSelf<TypeDeclarationSyntax>(out var typeDeclaration) &&
86-
DisposableMember.IsDisposed(fieldOrProperty, typeDeclaration, context.SemanticModel, context.CancellationToken).IsEither(Result.No, Result.AssumeNo) &&
87-
!TestFixture.IsAssignedInInitializeAndDisposedInCleanup(fieldOrProperty, typeDeclaration, context.SemanticModel, context.CancellationToken))
82+
else if (DisposableMember.IsDisposed(member, context.SemanticModel, context.CancellationToken).IsEither(Result.No, Result.AssumeNo) &&
83+
!TestFixture.IsAssignedInInitializeAndDisposedInCleanup(member, context.SemanticModel, context.CancellationToken))
8884
{
8985
context.ReportDiagnostic(Diagnostic.Create(Descriptors.IDISP002DisposeMember, context.Node.GetLocation()));
9086

91-
if (!DisposeMethod.TryFindFirst(fieldOrProperty.ContainingType, context.Compilation, Search.TopLevel, out _) &&
92-
!TestFixture.IsAssignedInInitialize(fieldOrProperty, typeDeclaration, context.SemanticModel, context.CancellationToken, out _, out _))
87+
if (!DisposeMethod.TryFindFirst(member.FieldOrProperty.ContainingType, context.Compilation, Search.TopLevel, out _) &&
88+
!TestFixture.IsAssignedInInitialize(member, context.SemanticModel, context.CancellationToken, out _, out _))
9389
{
9490
context.ReportDiagnostic(Diagnostic.Create(Descriptors.IDISP006ImplementIDisposable, context.Node.GetLocation()));
9591
}

IDisposableAnalyzers/Helpers/DisposableMember.cs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,12 @@
33
using System.Threading;
44
using Gu.Roslyn.AnalyzerExtensions;
55
using Microsoft.CodeAnalysis;
6-
using Microsoft.CodeAnalysis.CSharp.Syntax;
76

87
internal static class DisposableMember
98
{
10-
internal static Result IsDisposed(FieldOrProperty member, TypeDeclarationSyntax context, SemanticModel semanticModel, CancellationToken cancellationToken)
9+
internal static Result IsDisposed(FieldOrPropertyAndDeclaration member, SemanticModel semanticModel, CancellationToken cancellationToken)
1110
{
12-
if (semanticModel.TryGetNamedType(context, cancellationToken, out var symbol))
13-
{
14-
return IsDisposed(member, symbol, semanticModel, cancellationToken);
15-
}
16-
17-
return Result.Unknown;
11+
return IsDisposed(member.FieldOrProperty, member.FieldOrProperty.ContainingType, semanticModel, cancellationToken);
1812
}
1913

2014
internal static Result IsDisposed(FieldOrProperty member, INamedTypeSymbol context, SemanticModel semanticModel, CancellationToken cancellationToken)
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
namespace IDisposableAnalyzers
2+
{
3+
using System;
4+
using System.Threading;
5+
using Gu.Roslyn.AnalyzerExtensions;
6+
using Microsoft.CodeAnalysis;
7+
using Microsoft.CodeAnalysis.CSharp.Syntax;
8+
9+
internal struct FieldOrPropertyAndDeclaration : IEquatable<FieldOrPropertyAndDeclaration>
10+
{
11+
internal readonly FieldOrProperty FieldOrProperty;
12+
internal readonly MemberDeclarationSyntax Declaration;
13+
14+
internal FieldOrPropertyAndDeclaration(IFieldSymbol field, FieldDeclarationSyntax declaration)
15+
{
16+
this.FieldOrProperty = new FieldOrProperty(field);
17+
this.Declaration = declaration;
18+
}
19+
20+
internal FieldOrPropertyAndDeclaration(IPropertySymbol property, PropertyDeclarationSyntax declaration)
21+
{
22+
this.FieldOrProperty = new FieldOrProperty(property);
23+
this.Declaration = declaration;
24+
}
25+
26+
public static bool operator ==(FieldOrPropertyAndDeclaration left, FieldOrPropertyAndDeclaration right)
27+
{
28+
return left.Equals(right);
29+
}
30+
31+
public static bool operator !=(FieldOrPropertyAndDeclaration left, FieldOrPropertyAndDeclaration right)
32+
{
33+
return !left.Equals(right);
34+
}
35+
36+
public bool Equals(FieldOrPropertyAndDeclaration other)
37+
{
38+
return this.FieldOrProperty.Equals(other.FieldOrProperty);
39+
}
40+
41+
public override bool Equals(object? obj)
42+
{
43+
return obj is FieldOrPropertyAndDeclaration other && this.Equals(other);
44+
}
45+
46+
public override int GetHashCode()
47+
{
48+
return this.FieldOrProperty.GetHashCode();
49+
}
50+
51+
internal static bool TryCreate(ISymbol memberSymbol, CancellationToken cancellationToken, out FieldOrPropertyAndDeclaration fieldOrProperty)
52+
{
53+
switch (memberSymbol)
54+
{
55+
case IFieldSymbol field
56+
when field.TrySingleDeclaration(cancellationToken, out var declaration):
57+
fieldOrProperty = new FieldOrPropertyAndDeclaration(field, declaration);
58+
return true;
59+
case IPropertySymbol property
60+
when property.TrySingleDeclaration(cancellationToken, out PropertyDeclarationSyntax? declaration):
61+
fieldOrProperty = new FieldOrPropertyAndDeclaration(property, declaration);
62+
return true;
63+
default:
64+
fieldOrProperty = default;
65+
return false;
66+
}
67+
}
68+
}
69+
}

IDisposableAnalyzers/Helpers/TestFixture.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,19 @@
99

1010
internal static class TestFixture
1111
{
12+
internal static bool IsAssignedInInitializeAndDisposedInCleanup(FieldOrPropertyAndDeclaration fieldOrProperty, SemanticModel semanticModel, CancellationToken cancellationToken)
13+
{
14+
return IsAssignedInInitializeAndDisposedInCleanup(fieldOrProperty.FieldOrProperty, (TypeDeclarationSyntax)fieldOrProperty.Declaration.Parent, semanticModel, cancellationToken);
15+
}
16+
1217
internal static bool IsAssignedInInitializeAndDisposedInCleanup(FieldOrProperty fieldOrProperty, TypeDeclarationSyntax scope, SemanticModel semanticModel, CancellationToken cancellationToken)
1318
{
1419
if (AssignmentExecutionWalker.SingleFor(fieldOrProperty.Symbol, scope, SearchScope.Member, semanticModel, cancellationToken, out var assignment) &&
1520
assignment.FirstAncestor<MethodDeclarationSyntax>() is { } methodDeclaration)
1621
{
1722
var cleanup = TearDown(KnownSymbol.NUnitSetUpAttribute, KnownSymbol.NUnitTearDownAttribute) ??
1823
TearDown(KnownSymbol.NUnitOneTimeSetUpAttribute, KnownSymbol.NUnitOneTimeTearDownAttribute) ??
19-
TearDown(KnownSymbol.TestInitializeAttribute, KnownSymbol.TestCleanupAttribute) ??
24+
TearDown(KnownSymbol.TestInitializeAttribute, KnownSymbol.TestCleanupAttribute) ??
2025
TearDown(KnownSymbol.ClassInitializeAttribute, KnownSymbol.ClassCleanupAttribute);
2126
return cleanup is { } &&
2227
DisposableMember.IsDisposed(fieldOrProperty, cleanup, semanticModel, cancellationToken);
@@ -38,6 +43,11 @@ internal static bool IsAssignedInInitializeAndDisposedInCleanup(FieldOrProperty
3843
}
3944
}
4045

46+
internal static bool IsAssignedInInitialize(FieldOrPropertyAndDeclaration fieldOrProperty, SemanticModel semanticModel, CancellationToken cancellationToken, [NotNullWhen(true)] out AssignmentExpressionSyntax? assignment, [NotNullWhen(true)] out AttributeSyntax? attribute)
47+
{
48+
return IsAssignedInInitialize(fieldOrProperty.FieldOrProperty, (TypeDeclarationSyntax)fieldOrProperty.Declaration.Parent, semanticModel, cancellationToken, out assignment, out attribute);
49+
}
50+
4151
internal static bool IsAssignedInInitialize(FieldOrProperty fieldOrProperty, TypeDeclarationSyntax scope, SemanticModel semanticModel, CancellationToken cancellationToken, [NotNullWhen(true)] out AssignmentExpressionSyntax? assignment, [NotNullWhen(true)] out AttributeSyntax? attribute)
4252
{
4353
if (AssignmentExecutionWalker.SingleFor(fieldOrProperty.Symbol, scope, SearchScope.Member, semanticModel, cancellationToken, out assignment) &&

0 commit comments

Comments
 (0)