• 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

99.03
/NetFabric.CodeAnalysis/ITypeSymbolExtensions.IsEnumerable.cs
1
using Microsoft.CodeAnalysis;
2
using System;
3
using System.Diagnostics.CodeAnalysis;
4
using System.Linq;
5

6
namespace NetFabric.CodeAnalysis;
7

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

21
    /// <summary>
22
    /// Gets a value indicating whether 'foreach' considers <see cref="Microsoft.CodeAnalysis.ITypeSymbol"/> to be enumerable.
23
    /// </summary>
24
    /// <param name="typeSymbol">The <see cref="Microsoft.CodeAnalysis.ITypeSymbol"/> to test.</param>
25
    /// <param name="compilation">The <see cref="Microsoft.CodeAnalysis.Compilation"/> context.</param>
26
    /// <param name="enumerableSymbols">If methods returns <c>true</c>, contains information on the methods 'foreach' will use to enumerate.</param>
27
    /// <param name="errors">Gets information on what error caused the method to return <c>false</c>.</param>
28
    /// <returns><c>true</c> if 'foreach' considers <see cref="Microsoft.CodeAnalysis.ITypeSymbol"/> to be enumerable; otherwise, <c>false</c>.</returns>
29
    public static bool IsEnumerable(this ITypeSymbol typeSymbol, Compilation compilation,
30
        [NotNullWhen(true)] out EnumerableSymbols? enumerableSymbols,
31
        out Errors errors)
32
    {
33
        var forEachUsesIndexer = typeSymbol.TypeKind == TypeKind.Array || typeSymbol.IsSpanOrReadOnlySpanType();
24✔
34

35
        if (typeSymbol.TypeKind != TypeKind.Interface)
24✔
36
        {
37
            var getEnumerator = typeSymbol.GetPublicMethod(NameOf.GetEnumerator);
21✔
38
            if (getEnumerator is not null)
21✔
39
            {
40
                return HandleGetEnumerator(getEnumerator, compilation, out enumerableSymbols, out errors);
17✔
41
            }
42

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

51
        if (typeSymbol.ImplementsInterface(SpecialType.System_Collections_Generic_IEnumerable_T, out var genericArguments))
6✔
52
        {
53
            var genericEnumerableType = compilation
3✔
54
                .GetSpecialType(SpecialType.System_Collections_Generic_IEnumerable_T)
3✔
55
                .Construct(genericArguments[0]);
3✔
56
            var genericEnumeratorType = compilation
3✔
57
                .GetSpecialType(SpecialType.System_Collections_Generic_IEnumerator_T)
3✔
58
                .Construct(genericArguments[0]);
3✔
59
            var enumeratorType = compilation.GetSpecialType(SpecialType.System_Collections_IEnumerator);
3✔
60
            var disposableType = compilation.GetSpecialType(SpecialType.System_IDisposable);
3✔
61

62
            enumerableSymbols = new EnumerableSymbols(
3✔
63
                forEachUsesIndexer,
3✔
64
                genericEnumerableType.GetPublicMethod(NameOf.GetEnumerator, Type.EmptyTypes)!,
3✔
65
                new EnumeratorSymbols(
3✔
66
                    genericEnumeratorType.GetPublicReadProperty(NameOf.Current)!,
3✔
67
                    enumeratorType.GetPublicMethod(NameOf.MoveNext, Type.EmptyTypes)!)
3✔
68
                    {
3✔
69
                        Reset = enumeratorType.GetPublicMethod(NameOf.Reset, Type.EmptyTypes),
3✔
70
                        Dispose = disposableType.GetPublicMethod(NameOf.Dispose, Type.EmptyTypes),
3✔
71
                        IsGenericsEnumeratorInterface = true,
3✔
72
                        IsEnumeratorInterface = true,
3✔
73
                    }
3✔
74
            );
3✔
75
            errors = Errors.None; 
3✔
76
            return true;
3✔
77
        }
78

79
        if (typeSymbol.ImplementsInterface(SpecialType.System_Collections_IEnumerable, out _))
3✔
80
        {
81
            var enumerableType = compilation.GetSpecialType(SpecialType.System_Collections_IEnumerable);
2✔
82
            var enumeratorType = compilation.GetSpecialType(SpecialType.System_Collections_IEnumerator);
2✔
83

84
            enumerableSymbols = new EnumerableSymbols(
2✔
85
                forEachUsesIndexer,
2✔
86
                enumerableType.GetPublicMethod(NameOf.GetEnumerator, Type.EmptyTypes)!,
2✔
87
                new EnumeratorSymbols(
2✔
88
                    enumeratorType.GetPublicReadProperty(NameOf.Current)!,
2✔
89
                    enumeratorType.GetPublicMethod(NameOf.MoveNext, Type.EmptyTypes)!)
2✔
90
                {
2✔
91
                    Reset = enumeratorType.GetPublicMethod(NameOf.Reset, Type.EmptyTypes),
2✔
92
                    IsEnumeratorInterface = true,
2✔
93
                }                   
2✔
94
            );
2✔
95
            errors = Errors.None; 
2✔
96
            return true;
2✔
97
        }
98

99
        enumerableSymbols = default;
1✔
100
        errors = Errors.MissingGetEnumerator;
1✔
101
        return false;
1✔
102
    }
103

104
    static bool HandleGetEnumerator(IMethodSymbol getEnumerator, 
105
        Compilation compilation,
106
        [NotNullWhen(true)] out EnumerableSymbols? enumerableSymbols,
107
        out Errors errors)
108
    {
109
        var enumeratorType = getEnumerator.ReturnType;
18✔
110

111
        var current = enumeratorType.GetPublicReadProperty(NameOf.Current);
18✔
112
        if (current is null)
18✔
113
        {
114
            enumerableSymbols = default;
2✔
115
            errors = Errors.MissingCurrent;
2✔
116
            return false;
2✔
117
        }
118

119
        var moveNext = enumeratorType.GetPublicMethod(NameOf.MoveNext);
16✔
120
        if (moveNext is null)
16✔
121
        {
122
            enumerableSymbols = default;
1✔
123
            errors = Errors.MissingMoveNext;
1✔
124
            return false;
1✔
125
        }
126

127
        var reset = enumeratorType.GetPublicMethod("Reset");
15✔
128
        _ = enumeratorType.IsDisposable(compilation, out var dispose, out var isRefLike);
15✔
129

130
        enumerableSymbols = new EnumerableSymbols(
15✔
131
            false,
15✔
132
            getEnumerator,
15✔
133
            new EnumeratorSymbols(current, moveNext)
15✔
134
            {
15✔
135
                Reset = reset,
15✔
136
                Dispose = dispose,
15✔
137
                IsValueType = enumeratorType.IsValueType,
15✔
138
                IsRefLikeType = isRefLike,
15✔
139
                IsGenericsEnumeratorInterface =
15✔
140
                    enumeratorType.TypeKind == TypeKind.Interface
15✔
141
                    && enumeratorType.ImplementsInterface(
15✔
142
                        SpecialType.System_Collections_Generic_IEnumerable_T, out _),
15✔
143
                IsEnumeratorInterface =
15✔
144
                    enumeratorType.TypeKind == TypeKind.Interface,
15✔
145
            }
15✔
146
        );
15✔
147
        errors = Errors.None;
15✔
148
        return true;
15✔
149
    }
150
}
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