• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

NetFabric / NetFabric.CodeAnalysis / 6130084901

09 Sep 2023 09:14AM UTC coverage: 83.158% (+0.2%) from 82.932%
6130084901

push

github

web-flow
Fixes (#27)

227 of 266 branches covered (0.0%)

Branch coverage included in aggregate %.

661 of 661 new or added lines in 31 files covered. (100.0%)

642 of 779 relevant lines covered (82.41%)

18.46 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.55
/NetFabric.CodeAnalysis/ITypeSymbolExtensions.IsAsyncEnumerable.cs
1
using Microsoft.CodeAnalysis;
2
using System;
3
using System.Diagnostics.CodeAnalysis;
4
using System.Linq;
5
using System.Threading;
6

7
namespace NetFabric.CodeAnalysis;
8

9
public static partial class ITypeSymbolExtensions
10
{
11

12
    /// <summary>
13
    /// Gets a value indicating whether 'await foreach' considers <see cref="Microsoft.CodeAnalysis.ITypeSymbol"/> to be enumerable.
14
    /// </summary>
15
    /// <param name="typeSymbol">The <see cref="Microsoft.CodeAnalysis.ITypeSymbol"/> to test.</param>
16
    /// <param name="compilation">The <see cref="Microsoft.CodeAnalysis.Compilation"/> context.</param>
17
    /// <param name="enumerableSymbols">If methods returns <c>true</c>, contains information on the methods 'await foreach' will use to enumerate.</param>
18
    /// <returns><c>true</c> if 'await foreach' considers <see cref="Microsoft.CodeAnalysis.ITypeSymbol"/> to be enumerable; otherwise, <c>false</c>.</returns>
19
    public static bool IsAsyncEnumerable(this ITypeSymbol typeSymbol, Compilation compilation,
20
        [NotNullWhen(true)] out AsyncEnumerableSymbols? enumerableSymbols)
21
        => IsAsyncEnumerable(typeSymbol, compilation, out enumerableSymbols, out _);
×
22

23
    /// <summary>
24
    /// Gets a value indicating whether 'await foreach' considers <see cref="Microsoft.CodeAnalysis.ITypeSymbol"/> to be enumerable.
25
    /// </summary>
26
    /// <param name="typeSymbol">The <see cref="Microsoft.CodeAnalysis.ITypeSymbol"/> to test.</param>
27
    /// <param name="compilation">The <see cref="Microsoft.CodeAnalysis.Compilation"/> context.</param>
28
    /// <param name="enumerableSymbols">If methods returns <c>true</c>, contains information on the methods 'await foreach' will use to enumerate.</param>
29
    /// <param name="errors">Gets information on what error caused the method to return <c>false</c>.</param>
30
    /// <returns><c>true</c> if 'await foreach' considers <see cref="Microsoft.CodeAnalysis.ITypeSymbol"/> to be enumerable; otherwise, <c>false</c>.</returns>
31
    public static bool IsAsyncEnumerable(this ITypeSymbol typeSymbol, Compilation compilation,
32
        [NotNullWhen(true)] out AsyncEnumerableSymbols? enumerableSymbols,
33
        out Errors errors)
34
    {
35
        if (typeSymbol.TypeKind != TypeKind.Interface)
14✔
36
        {
37
            var getEnumerator =
13✔
38
                typeSymbol.GetPublicMethod(NameOf.GetAsyncEnumerator, typeof(CancellationToken))
13✔
39
                ?? typeSymbol.GetPublicMethod(NameOf.GetAsyncEnumerator);
13✔
40
            if (getEnumerator is not null)
13✔
41
                return HandleGetAsyncEnumerator(getEnumerator, compilation, out enumerableSymbols, out errors);
9✔
42

43
            getEnumerator = compilation.GetExtensionMethodsWithName(typeSymbol, NameOf.GetAsyncEnumerator)
4✔
44
                .FirstOrDefault(methodSymbol => methodSymbol.Parameters.Length == 1 || methodSymbol.Parameters.Length == 2);
6✔
45
            if (getEnumerator is not null)
4✔
46
            {
47
                return HandleGetAsyncEnumerator(getEnumerator, compilation, out enumerableSymbols, out errors);
2✔
48
            }
49
        }
50

51
        var asyncEnumerableType = compilation.GetTypeByMetadataName("System.Collections.Generic.IAsyncEnumerable`1")!;
3✔
52
        if (typeSymbol.ImplementsInterface(asyncEnumerableType, out var genericArguments))
3✔
53
        {
54
            var asyncEnumeratorType = compilation.GetTypeByMetadataName("System.Collections.Generic.IAsyncEnumerator`1")!.Construct(genericArguments[0]);
2✔
55
            var asyncDisposableType = compilation.GetTypeByMetadataName("System.IAsyncDisposable")!;
2✔
56

57
            enumerableSymbols = new AsyncEnumerableSymbols(
2✔
58
                asyncEnumerableType.GetPublicMethod(NameOf.GetAsyncEnumerator, typeof(CancellationToken))!,
2✔
59
                new AsyncEnumeratorSymbols(
2✔
60
                    asyncEnumeratorType.GetPublicReadProperty(NameOf.Current)!,
2✔
61
                    asyncEnumeratorType.GetPublicMethod(NameOf.MoveNextAsync, Type.EmptyTypes)!)
2✔
62
                {
2✔
63
                    DisposeAsync = asyncDisposableType.GetPublicMethod(NameOf.DisposeAsync, Type.EmptyTypes),
2✔
64
                    IsAsyncEnumeratorInterface = true,
2✔
65
                }
2✔
66
            );
2✔
67
            errors = Errors.None; 
2✔
68
            return true;
2✔
69
        }
70
        
71
        enumerableSymbols = default;
1✔
72
        errors = Errors.MissingGetEnumerator;
1✔
73
        return false;
1✔
74
    }
75

76
    static bool HandleGetAsyncEnumerator(IMethodSymbol getEnumerator, 
77
        Compilation compilation,
78
        [NotNullWhen(true)] out AsyncEnumerableSymbols? enumerableSymbols,
79
        out Errors errors)
80
    {
81
        var enumeratorType = getEnumerator.ReturnType;
11✔
82

83
        var current = enumeratorType.GetPublicReadProperty(NameOf.Current);
11✔
84
        if (current is null)
11✔
85
        {
86
            enumerableSymbols = default;
1✔
87
            errors = Errors.MissingCurrent;
1✔
88
            return false;
1✔
89
        }
90

91
        var moveNext = enumeratorType.GetPublicMethod(NameOf.MoveNextAsync);
10✔
92
        if (moveNext is null)
10✔
93
        {
94
            enumerableSymbols = default;
1✔
95
            errors = Errors.MissingMoveNext;
1✔
96
            return false;
1✔
97
        }
98

99
        _ = enumeratorType.IsAsyncDisposable(compilation, out var dispose);
9✔
100

101
        enumerableSymbols = new AsyncEnumerableSymbols(
9✔
102
            getEnumerator,
9✔
103
            new AsyncEnumeratorSymbols(current, moveNext)
9✔
104
            {
9✔
105
                DisposeAsync = dispose,
9✔
106
                IsValueType = getEnumerator.ReturnType.IsValueType,
9✔
107
                IsAsyncEnumeratorInterface = enumeratorType.TypeKind == TypeKind.Interface,
9✔
108
            }
9✔
109
        );
9✔
110
        errors = Errors.None;
9✔
111
        return true;
9✔
112
    }
113
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc