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

NetFabric / NetFabric.CodeAnalysis / 6277926364

22 Sep 2023 06:38PM UTC coverage: 73.953% (-9.2%) from 83.158%
6277926364

push

github

web-flow
Add IsIndexable (#28)

323 of 452 branches covered (0.0%)

Branch coverage included in aggregate %.

349 of 349 new or added lines in 18 files covered. (100.0%)

648 of 861 relevant lines covered (75.26%)

20.93 hits per line

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

97.37
/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
    /// <summary>
12
    /// Checks if the provided <paramref name="typeSymbol"/> can be used as a source in an <c>await foreach</c>
13
    /// statement, indicating whether it is an async enumerable.
14
    /// </summary>
15
    /// <param name="typeSymbol">The <see cref="ITypeSymbol"/> to be checked for async enumerability.</param>
16
    /// <param name="compilation">The <see cref="Compilation"/> representing the current
17
    /// compilation context.</param>
18
    /// <returns>
19
    /// <c>true</c> if the <paramref name="typeSymbol"/> is an async enumerable; otherwise, <c>false</c>.
20
    /// </returns>
21
    /// <remarks>
22
    /// This method examines the provided <paramref name="typeSymbol"/> to determine if it can be
23
    /// used as a source in an <c>await foreach</c> statement, indicating whether it is an async enumerable.
24
    /// To be considered an async enumerable, the type should support asynchronous iteration,
25
    /// typically by implementing the <see cref="IAsyncEnumerable{T}"/> interface or providing
26
    /// a suitable asynchronous <c>GetAsyncEnumerator</c> method.
27
    /// 
28
    /// If the type is an async enumerable, it is considered an async source for an <c>await foreach</c> statement.
29
    /// </remarks>
30
    public static bool IsAsyncEnumerable(this ITypeSymbol typeSymbol, Compilation compilation)
31
        => IsAsyncEnumerable(typeSymbol, compilation, out _, out _);
×
32

33
    /// <summary>
34
    /// Checks if the provided <paramref name="typeSymbol"/> can be used as a source in an <c>await foreach</c>
35
    /// statement, indicating whether it is an async enumerable, and if so, retrieves information about
36
    /// the async enumerable symbols.
37
    /// </summary>
38
    /// <param name="typeSymbol">The <see cref="ITypeSymbol"/> to be checked for async enumerability.</param>
39
    /// <param name="compilation">The <see cref="Compilation"/> representing the current
40
    /// compilation context.</param>
41
    /// <param name="enumerableSymbols">
42
    /// When the method returns <c>true</c>, this parameter will contain information about the
43
    /// async enumerable symbols associated with the <paramref name="typeSymbol"/>. If the method returns
44
    /// <c>false</c>, this parameter will be <c>null</c>.
45
    /// </param>
46
    /// <returns>
47
    /// <c>true</c> if the <paramref name="typeSymbol"/> is an async enumerable; otherwise, <c>false</c>.
48
    /// </returns>
49
    /// <remarks>
50
    /// This method examines the provided <paramref name="typeSymbol"/> to determine if it can be
51
    /// used as a source in an <c>await foreach</c> statement, indicating whether it is an async enumerable.
52
    /// To be considered an async enumerable, the type should support asynchronous iteration,
53
    /// typically by implementing the <see cref="IAsyncEnumerable{T}"/> interface or providing
54
    /// a suitable asynchronous <c>GetAsyncEnumerator</c> method.
55
    /// 
56
    /// If the type is an async enumerable, the method provides information about the async
57
    /// enumerable symbols associated with it, which can be useful for various code analysis tasks.
58
    /// </remarks>
59
    public static bool IsAsyncEnumerable(this ITypeSymbol typeSymbol, Compilation compilation,
60
        [NotNullWhen(true)] out AsyncEnumerableSymbols? enumerableSymbols)
61
        => IsAsyncEnumerable(typeSymbol, compilation, out enumerableSymbols, out _);
×
62

63
    /// <summary>
64
    /// Checks if the provided <paramref name="typeSymbol"/> can be used as a source in an <c>await foreach</c>
65
    /// statement, indicating whether it is an async enumerable, and if so, retrieves information about
66
    /// the async enumerable symbols.
67
    /// </summary>
68
    /// <param name="typeSymbol">The <see cref="ITypeSymbol"/> to be checked for async enumerability.</param>
69
    /// <param name="compilation">The <see cref="Compilation"/> representing the current
70
    /// compilation context.</param>
71
    /// <param name="enumerableSymbols">
72
    /// When the method returns <c>true</c>, this parameter will contain information about the
73
    /// async enumerable symbols associated with the <paramref name="typeSymbol"/>. If the method returns
74
    /// <c>false</c>, this parameter will be <c>null</c>.
75
    /// </param>
76
    /// <returns>
77
    /// <c>true</c> if the <paramref name="typeSymbol"/> is an async enumerable; otherwise, <c>false</c>.
78
    /// </returns>
79
    /// <remarks>
80
    /// This method examines the provided <paramref name="typeSymbol"/> to determine if it can be
81
    /// used as a source in an <c>await foreach</c> statement, indicating whether it is an async enumerable.
82
    /// To be considered an async enumerable, the type should support asynchronous iteration,
83
    /// typically by implementing the <see cref="IAsyncEnumerable{T}"/> interface or providing
84
    /// a suitable asynchronous <c>GetAsyncEnumerator</c> method.
85
    /// 
86
    /// If the type is an async enumerable, the method provides information about the async
87
    /// enumerable symbols associated with it, which can be useful for various code analysis tasks.
88
    /// </remarks>    
89
    public static bool IsAsyncEnumerable(this ITypeSymbol typeSymbol, Compilation compilation,
90
    [NotNullWhen(true)] out AsyncEnumerableSymbols? enumerableSymbols,
91
        out IsAsyncEnumerableError error)
92
    {
93
        if (typeSymbol.TypeKind != TypeKind.Interface)
15✔
94
        {
95
            var getEnumerator =
14✔
96
                typeSymbol.GetPublicMethod(NameOf.GetAsyncEnumerator, typeof(CancellationToken))
14✔
97
                ?? typeSymbol.GetPublicMethod(NameOf.GetAsyncEnumerator);
14✔
98
            if (getEnumerator is not null)
14✔
99
                return HandleGetAsyncEnumerator(getEnumerator, compilation, out enumerableSymbols, out error);
10✔
100

101
            getEnumerator = compilation.GetExtensionMethodsWithName(typeSymbol, NameOf.GetAsyncEnumerator)
4✔
102
                .FirstOrDefault(methodSymbol => methodSymbol.Parameters.Length == 1 || methodSymbol.Parameters.Length == 2);
6✔
103
            if (getEnumerator is not null)
4✔
104
            {
105
                return HandleGetAsyncEnumerator(getEnumerator, compilation, out enumerableSymbols, out error);
2✔
106
            }
107
        }
108

109
        var asyncEnumerableType = compilation.GetTypeByMetadataName("System.Collections.Generic.IAsyncEnumerable`1")!;
3✔
110
        if (typeSymbol.ImplementsInterface(asyncEnumerableType, out var genericArguments))
3✔
111
        {
112
            var asyncEnumeratorType = compilation.GetTypeByMetadataName("System.Collections.Generic.IAsyncEnumerator`1")!.Construct(genericArguments[0]);
2✔
113
            var asyncDisposableType = compilation.GetTypeByMetadataName("System.IAsyncDisposable")!;
2✔
114

115
            enumerableSymbols = new AsyncEnumerableSymbols(
2✔
116
                asyncEnumerableType.GetPublicMethod(NameOf.GetAsyncEnumerator, typeof(CancellationToken))!,
2✔
117
                new AsyncEnumeratorSymbols(
2✔
118
                    asyncEnumeratorType.GetPublicReadProperty(NameOf.Current)!,
2✔
119
                    asyncEnumeratorType.GetPublicMethod(NameOf.MoveNextAsync, Type.EmptyTypes)!)
2✔
120
                {
2✔
121
                    DisposeAsync = asyncDisposableType.GetPublicMethod(NameOf.DisposeAsync, Type.EmptyTypes),
2✔
122
                    IsAsyncEnumeratorInterface = true,
2✔
123
                }
2✔
124
            );
2✔
125
            error = IsAsyncEnumerableError.None; 
2✔
126
            return true;
2✔
127
        }
128
        
129
        enumerableSymbols = default;
1✔
130
        error = IsAsyncEnumerableError.MissingGetAsyncEnumerator;
1✔
131
        return false;
1✔
132
    }
133

134
    static bool HandleGetAsyncEnumerator(IMethodSymbol getEnumerator, 
135
        Compilation compilation,
136
        [NotNullWhen(true)] out AsyncEnumerableSymbols? enumerableSymbols,
137
        out IsAsyncEnumerableError error)
138
    {
139
        var enumeratorType = getEnumerator.ReturnType;
12✔
140

141
        var current = enumeratorType.GetPublicReadProperty(NameOf.Current);
12✔
142
        if (current is null)
12✔
143
        {
144
            enumerableSymbols = default;
1✔
145
            error = IsAsyncEnumerableError.MissingCurrent;
1✔
146
            return false;
1✔
147
        }
148

149
        var moveNext = enumeratorType.GetPublicMethod(NameOf.MoveNextAsync);
11✔
150
        if (moveNext is null || 
11✔
151
            moveNext.ReturnType is not INamedTypeSymbol namedReturnType || 
11✔
152
            namedReturnType.ToDisplayString() != "System.Threading.Tasks.ValueTask<bool>")
11✔
153
        {
154
            enumerableSymbols = default;
2✔
155
            error = IsAsyncEnumerableError.MissingMoveNextAsync;
2✔
156
            return false;
2✔
157
        }
158

159
        _ = enumeratorType.IsAsyncDisposable(compilation, out var dispose);
9✔
160

161
        enumerableSymbols = new AsyncEnumerableSymbols(
9✔
162
            getEnumerator,
9✔
163
            new AsyncEnumeratorSymbols(current, moveNext)
9✔
164
            {
9✔
165
                DisposeAsync = dispose,
9✔
166
                IsValueType = getEnumerator.ReturnType.IsValueType,
9✔
167
                IsAsyncEnumeratorInterface = enumeratorType.TypeKind == TypeKind.Interface,
9✔
168
            }
9✔
169
        );
9✔
170
        error = IsAsyncEnumerableError.None;
9✔
171
        return true;
9✔
172
    }
173
}
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