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

NetFabric / NetFabric.Hyperlinq.Analyzer / 6482787016

11 Oct 2023 12:54PM UTC coverage: 80.314% (+0.9%) from 79.368%
6482787016

Pull #75

github

aalmada
Refactoring
Pull Request #75: Add IsIndexable

501 of 644 branches covered (0.0%)

Branch coverage included in aggregate %.

110 of 110 new or added lines in 13 files covered. (100.0%)

882 of 1078 relevant lines covered (81.82%)

20.07 hits per line

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

61.54
/NetFabric.Hyperlinq.Analyzer/Utils/MethodDeclarationSyntaxExtensions.cs
1
using Microsoft.CodeAnalysis;
2
using Microsoft.CodeAnalysis.CSharp;
3
using Microsoft.CodeAnalysis.CSharp.Syntax;
4
using Microsoft.CodeAnalysis.Diagnostics;
5
using NetFabric.CodeAnalysis;
6
using System;
7
using System.Diagnostics.CodeAnalysis;
8
using System.Linq;
9

10
namespace NetFabric.Hyperlinq.Analyzer
11
{
12
    static class MethodDeclarationSyntaxExtensions
13
    {
14
        public static bool ReturnsVoid(this MethodDeclarationSyntax methodDeclarationSyntax)
15
            => methodDeclarationSyntax.ReturnType is PredefinedTypeSyntax predefinedTypeSyntax
944✔
16
               && predefinedTypeSyntax.Keyword.IsKind(SyntaxKind.VoidKeyword);
944✔
17

18
        public static bool Returns(this MethodDeclarationSyntax methodDeclarationSyntax, string valueText)
19
            => methodDeclarationSyntax.ReturnType is IdentifierNameSyntax identifierNameSyntax
16!
20
                && identifierNameSyntax.Identifier.ValueText == valueText;
16✔
21

22
        public static bool ReturnsEnumerable(this MethodDeclarationSyntax methodDeclarationSyntax, SyntaxNodeAnalysisContext context)
23
        {
24
            var typeSymbol = context.SemanticModel.GetTypeInfo(methodDeclarationSyntax.ReturnType).Type;
×
25
            return !(typeSymbol is null)
×
26
                && (typeSymbol.IsEnumerable(context.Compilation, out _)
×
27
                || typeSymbol.IsAsyncEnumerable(context.Compilation, out _));
×
28
        }
29

30
        public static bool ReturnsEnumerableInterface(this MethodDeclarationSyntax methodDeclarationSyntax, SyntaxNodeAnalysisContext context)
31
        {
32
            var typeSymbol = context.SemanticModel.GetTypeInfo(methodDeclarationSyntax.ReturnType).Type;
132✔
33
            return !(typeSymbol is null)
132✔
34
                && typeSymbol.TypeKind == TypeKind.Interface
132✔
35
                && (typeSymbol.IsEnumerable(context.Compilation, out _)
132✔
36
                || typeSymbol.IsAsyncEnumerable(context.Compilation, out _));
132✔
37
        }
38

39
        public static bool IsExtensionMethod(this MethodDeclarationSyntax methodDeclarationSyntax, [NotNullWhen(true)] out ParameterSyntax? parameterSyntax)
40
        {
41
            var parameters = methodDeclarationSyntax.ParameterList.Parameters;
×
42
            if (parameters.Count != 0)
×
43
            {
44
                parameterSyntax = parameters[0];
×
45
                return parameterSyntax.Modifiers.Any(modifier => modifier.IsKind(SyntaxKind.ThisKeyword));
×
46
            }
47

48
            parameterSyntax = null;
×
49
            return false;
×
50
        }
51

52
        public static bool IsEnumerableInstanceMethod(this MethodDeclarationSyntax methodDeclarationSyntax, SyntaxNodeAnalysisContext context)
53
        {
54
            var typeDeclaration = methodDeclarationSyntax.Ancestors().OfType<TypeDeclarationSyntax>().FirstOrDefault();
×
55
            return typeDeclaration is not null && typeDeclaration.IsEnumerable(context);
×
56
        }
57

58
        public static bool IsEnumerableExtensionMethod(this MethodDeclarationSyntax methodDeclarationSyntax, SyntaxNodeAnalysisContext context)
59
        {
60
            if (methodDeclarationSyntax.IsExtensionMethod(out var parameterSyntax))
×
61
            {
62
                if (parameterSyntax.Type is not null)
×
63
                {
64
                    var typeSymbol = context.SemanticModel.GetTypeInfo(parameterSyntax.Type).Type;
×
65
                    if (typeSymbol is not null)
×
66
                    {
67
                        return typeSymbol.IsEnumerable(context.Compilation, out _) || typeSymbol.IsAsyncEnumerable(context.Compilation, out _);
×
68
                    }
69
                }
70
            }
71

72
            return false;
×
73
        }
74

75
        public static bool IsDispose(this MethodDeclarationSyntax methodDeclarationSyntax)
76
            => methodDeclarationSyntax.Identifier.ValueText == "Dispose"
108✔
77
                && methodDeclarationSyntax.ReturnsVoid()
108✔
78
                && methodDeclarationSyntax.ParameterList.Parameters.Count == 0;
108✔
79

80
        public static bool IsAsyncDispose(this MethodDeclarationSyntax methodDeclarationSyntax)
81
            => methodDeclarationSyntax.Identifier.ValueText == "DisposeAsync"
93✔
82
                && methodDeclarationSyntax.Returns("ValueTask")
93✔
83
                && methodDeclarationSyntax.ParameterList.Parameters.Count == 0; 
93✔
84

85
        public static bool IsReset(this MethodDeclarationSyntax methodDeclarationSyntax)
86
            => methodDeclarationSyntax.Identifier.ValueText == "Reset"
35✔
87
                && methodDeclarationSyntax.ReturnsVoid()
35✔
88
                && methodDeclarationSyntax.ParameterList.Parameters.Count == 0;
35✔
89

90
        public static bool IsEmptyMethod(this MethodDeclarationSyntax methodDeclarationSyntax)
91
        {
92
            if (methodDeclarationSyntax.Body is null)
23✔
93
            {
94
                if (methodDeclarationSyntax.ExpressionBody is null)
5!
95
                    return false;
×
96

97
                var expression = methodDeclarationSyntax.ExpressionBody.Expression.ToString().Trim();
5✔
98
                if (expression.StartsWith("throw"))
5✔
99
                    return true;
4✔
100
            }
101
            else
102
            {
103
                var statements = methodDeclarationSyntax.Body.Statements;
18✔
104
                if (statements.Count == 0)
18✔
105
                    return true;
14✔
106

107
                if (statements.Count == 1)
4✔
108
                {
109
                    var statement = statements[0].ToString().Trim();
3✔
110

111
                    if (statement.StartsWith("throw"))
3✔
112
                        return true;
1✔
113
                }
114
            }
115

116
            return false;
4✔
117
        }
118

119
        public static bool IsEmptyAsyncMethod(this MethodDeclarationSyntax methodDeclarationSyntax)
120
        {
121
            if (methodDeclarationSyntax.Body is null)
25✔
122
            {
123
                if (methodDeclarationSyntax.ExpressionBody is null)
17!
124
                    return false;
×
125

126
                var expression = methodDeclarationSyntax.ExpressionBody.Expression.ToString().Trim();
17✔
127
                if (expression.StartsWith("default")
17✔
128
                    || expression.StartsWith("new ValueTask")
17✔
129
                    || expression.StartsWith("throw"))
17✔
130
                    return true;
16✔
131
            }
132
            else
133
            {
134
                var statements = methodDeclarationSyntax.Body.Statements;
8✔
135
                if (statements.Count == 0)
8!
136
                    return true;
×
137

138
                if (statements.Count == 1)
8✔
139
                {
140
                    var statement = statements[0].ToString().Trim();
4✔
141

142
                    if (statement.StartsWith("return default") 
4✔
143
                        || statement.StartsWith("return new ValueTask") 
4✔
144
                        || statement.StartsWith("throw"))
4✔
145
                        return true;
4✔
146
                }
147
            }
148

149
            return false;
5✔
150
        }
151

152
        public static bool IsPublic(this MethodDeclarationSyntax methodDeclarationSyntax)
153
        {
154
            for (SyntaxNode? node = methodDeclarationSyntax; node is not null; node = node.Parent)
×
155
            {
156
                if (node is TypeDeclarationSyntax type)
×
157
                {
158
                    if (!type.Modifiers.Any(modifier => modifier.IsKind(SyntaxKind.PublicKeyword)))
×
159
                        return false;
×
160
                }
161
                else if (node is MethodDeclarationSyntax method)
×
162
                {
163
                    if (!method.Modifiers.Any(modifier => modifier.IsKind(SyntaxKind.PublicKeyword)))
×
164
                        return false;
×
165
                }
166
            }
167
            return true;
×
168
        }
169

170
        public static bool AllReturnsImplement(this MethodDeclarationSyntax methodDeclarationSyntax, SpecialType type, SyntaxNodeAnalysisContext context)
171
        {
172
            foreach (var returnStatementSyntax in methodDeclarationSyntax.DescendantNodes().OfType<ReturnStatementSyntax>())
46✔
173
            {
174
                var expression = returnStatementSyntax.Expression;
18✔
175
                if (expression is null)
18!
176
                    return false;
×
177

178
                var returnType = context.SemanticModel.GetTypeInfo(expression).Type;
18✔
179
                if (returnType is null || !returnType.ImplementsInterface(type, out _))
18✔
180
                    return false;
4✔
181
            }
182
            return true;
3✔
183
        }
4✔
184

185
        public static bool HasAttribute(this MethodDeclarationSyntax methodDeclarationSyntax, string name)
186
            => methodDeclarationSyntax.AttributeLists
×
187
                .Select(attributeList => attributeList.Target)
×
188
                .Any(target => 
×
189
                    target is not null &&
×
190
                    (target.Identifier.ValueText == name || target.Identifier.ValueText == $"{name}Attribute"));
×
191
    }
192
}
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

© 2026 Coveralls, Inc