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

NetFabric / NetFabric.CodeAnalysis / 6101088975

06 Sep 2023 06:36PM UTC coverage: 82.932% (+2.0%) from 80.942%
6101088975

push

github

web-flow
Add support for GetEnumerator as an extension method (#26)

* Add support for GetEnumerator as an extension method

* Fixes

224 of 264 branches covered (0.0%)

Branch coverage included in aggregate %.

127 of 127 new or added lines in 16 files covered. (100.0%)

636 of 773 relevant lines covered (82.28%)

17.9 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.Collections;
4
using System.Collections.Generic;
5
using System.Diagnostics.CodeAnalysis;
6
using System.Linq;
7

8
namespace NetFabric.CodeAnalysis
9
{
10
    public static partial class ITypeSymbolExtensions
11
    {
12
        /// <summary>
13
        /// Gets a value indicating whether '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 'foreach' will use to enumerate.</param>
18
        /// <returns><c>true</c> if 'foreach' considers <see cref="Microsoft.CodeAnalysis.ITypeSymbol"/> to be enumerable; otherwise, <c>false</c>.</returns>
19
        public static bool IsEnumerable(this ITypeSymbol typeSymbol, Compilation compilation,
20
            [NotNullWhen(true)] out EnumerableSymbols? enumerableSymbols)
21
            => IsEnumerable(typeSymbol, compilation, out enumerableSymbols, out _);
×
22

23
        /// <summary>
24
        /// Gets a value indicating whether '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 '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 'foreach' considers <see cref="Microsoft.CodeAnalysis.ITypeSymbol"/> to be enumerable; otherwise, <c>false</c>.</returns>
31
        public static bool IsEnumerable(this ITypeSymbol typeSymbol, Compilation compilation,
32
            [NotNullWhen(true)] out EnumerableSymbols? enumerableSymbols,
33
            out Errors errors)
34
        {
35
            var forEachUsesIndexer = typeSymbol.TypeKind == TypeKind.Array || typeSymbol.IsSpanOrReadOnlySpanType();
24✔
36

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

46
            if (typeSymbol.ImplementsInterface(SpecialType.System_Collections_Generic_IEnumerable_T, out var genericArguments))
7✔
47
            {
48
                var genericEnumerableType = compilation
3✔
49
                    .GetSpecialType(SpecialType.System_Collections_Generic_IEnumerable_T)
3✔
50
                    .Construct(genericArguments[0]);
3✔
51
                var genericEnumeratorType = compilation
3✔
52
                    .GetSpecialType(SpecialType.System_Collections_Generic_IEnumerator_T)
3✔
53
                    .Construct(genericArguments[0]);
3✔
54
                var enumeratorType = compilation.GetSpecialType(SpecialType.System_Collections_IEnumerator);
3✔
55
                var disposableType = compilation.GetSpecialType(SpecialType.System_IDisposable);
3✔
56

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

74
            if (typeSymbol.ImplementsInterface(SpecialType.System_Collections_IEnumerable, out _))
4✔
75
            {
76
                var enumerableType = compilation.GetSpecialType(SpecialType.System_Collections_IEnumerable);
2✔
77
                var enumeratorType = compilation.GetSpecialType(SpecialType.System_Collections_IEnumerator);
2✔
78

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

94
            var extensionMethod = compilation.GetExtensionMethodsWithName(typeSymbol, NameOf.GetEnumerator)
2✔
95
                .FirstOrDefault(methodSymbol => methodSymbol.Parameters.Length == 1);
3✔
96
            if (extensionMethod is not null)
2✔
97
            {
98
                return HandleGetEnumerator(extensionMethod, compilation, out enumerableSymbols, out errors);
1✔
99
            }
100

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

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

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

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

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

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