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

dendrodocs / dotnet-tool / 15993184477

01 Jul 2025 07:49AM UTC coverage: 57.669% (-8.5%) from 66.139%
15993184477

Pull #52

github

web-flow
Merge 247e5cc08 into 5901c209c
Pull Request #52: Add OperationWalker support and fix implicit object creation expressions

183 of 388 branches covered (47.16%)

Branch coverage included in aggregate %.

17 of 110 new or added lines in 2 files covered. (15.45%)

475 of 753 relevant lines covered (63.08%)

0.63 hits per line

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

52.55
/src/DendroDocs.Tool/Analyzers/InvocationsAnalyzer.cs
1
namespace DendroDocs.Tool;
2

3
internal class InvocationsAnalyzer(SemanticModel semanticModel, List<Statement> statements) : CSharpSyntaxWalker
1✔
4
{
5
    public override void VisitObjectCreationExpression(ObjectCreationExpressionSyntax node)
6
    {
1✔
7
        string containingType = semanticModel.GetTypeDisplayString(node);
1✔
8

9
        var invocation = new InvocationDescription(containingType, node.Type.ToString());
1✔
10
        statements.Add(invocation);
1✔
11

12
        if (node.ArgumentList != null)
1✔
13
        {
1✔
14
            foreach (var argument in node.ArgumentList.Arguments)
1✔
15
            {
1✔
16
                var argumentDescription = new ArgumentDescription(semanticModel.GetTypeDisplayString(argument.Expression), argument.Expression.ToString());
1✔
17
                invocation.Arguments.Add(argumentDescription);
1✔
18
            }
1✔
19
        }
1✔
20

21
        if (node.Initializer != null)
1!
22
        {
×
23
            foreach (var expression in node.Initializer.Expressions)
×
24
            {
×
25
                var argumentDescription = new ArgumentDescription(semanticModel.GetTypeDisplayString(expression), expression.ToString());
×
26
                invocation.Arguments.Add(argumentDescription);
×
27
            }
×
28
        }
×
29

30
        base.VisitObjectCreationExpression(node);
1✔
31
    }
1✔
32

33
    public override void VisitImplicitObjectCreationExpression(ImplicitObjectCreationExpressionSyntax node)
34
    {
1✔
35
        // For implicit object creation (new()), get the type from the semantic model
36
        var typeInfo = semanticModel.GetTypeInfo(node);
1✔
37
        string containingType = typeInfo.Type?.ToDisplayString() ?? string.Empty;
1!
38
        string typeName = typeInfo.Type?.Name ?? "object";
1!
39

40
        var invocation = new InvocationDescription(containingType, typeName);
1✔
41
        statements.Add(invocation);
1✔
42

43
        if (node.ArgumentList != null)
1✔
44
        {
1✔
45
            foreach (var argument in node.ArgumentList.Arguments)
1✔
46
            {
1✔
47
                var argumentDescription = new ArgumentDescription(semanticModel.GetTypeDisplayString(argument.Expression), argument.Expression.ToString());
1✔
48
                invocation.Arguments.Add(argumentDescription);
1✔
49
            }
1✔
50
        }
1✔
51

52
        if (node.Initializer != null)
1!
NEW
53
        {
×
NEW
54
            foreach (var expression in node.Initializer.Expressions)
×
NEW
55
            {
×
NEW
56
                var argumentDescription = new ArgumentDescription(semanticModel.GetTypeDisplayString(expression), expression.ToString());
×
NEW
57
                invocation.Arguments.Add(argumentDescription);
×
NEW
58
            }
×
NEW
59
        }
×
60

61
        base.VisitImplicitObjectCreationExpression(node);
1✔
62
    }
1✔
63

64
    public override void VisitSwitchStatement(SwitchStatementSyntax node)
65
    {
1✔
66
        var branchingAnalyzer = new BranchingAnalyzer(semanticModel, statements);
1✔
67
        branchingAnalyzer.Visit(node);
1✔
68
    }
1✔
69

70
    public override void VisitSwitchExpression(SwitchExpressionSyntax node)
71
    {
1✔
72
        var branchingAnalyzer = new BranchingAnalyzer(semanticModel, statements);
1✔
73
        branchingAnalyzer.Visit(node);
1✔
74
    }
1✔
75

76
    public override void VisitIfStatement(IfStatementSyntax node)
77
    {
1✔
78
        var branchingAnalyzer = new BranchingAnalyzer(semanticModel, statements);
1✔
79
        branchingAnalyzer.Visit(node);
1✔
80
    }
1✔
81

82
    public override void VisitForEachStatement(ForEachStatementSyntax node)
83
    {
1✔
84
        var loopingAnalyzer = new LoopingAnalyzer(semanticModel, statements);
1✔
85
        loopingAnalyzer.Visit(node);
1✔
86
    }
1✔
87

88
    public override void VisitInvocationExpression(InvocationExpressionSyntax node)
89
    {
1✔
90
        var expression = this.GetExpressionWithSymbol(node);
1✔
91

92
        if (semanticModel.GetConstantValue(node).HasValue && IsNameofExpression(node.Expression))
1!
93
        {
×
94
            // nameof is compiler sugar, and is actually a method we are not interrested in
95
            return;
×
96
        }
97

98
        if (Program.RuntimeOptions.VerboseOutput && semanticModel.GetSymbolInfo(expression).Symbol is null)
1!
99
        {
×
100
            Console.WriteLine("WARN: Could not resolve type of invocation of the following block:");
×
101
            Console.WriteLine(node.ToFullString());
×
102
            return;
×
103
        }
104

105
        var symbolInfo = semanticModel.GetSymbolInfo(expression);
1✔
106
        var containingType = symbolInfo.Symbol?.ContainingSymbol ?? symbolInfo.CandidateSymbols.FirstOrDefault()?.ContainingSymbol;
1!
107
        var containingTypeAsString = containingType?.ToDisplayString() ?? string.Empty;
1!
108

109
        var methodName = node.Expression switch
1!
110
        {
1✔
111
            MemberAccessExpressionSyntax m => m.Name.ToString(),
×
112
            IdentifierNameSyntax i => i.Identifier.ValueText,
1✔
113
            _ => string.Empty
×
114
        };
1✔
115

116
        var invocation = new InvocationDescription(containingTypeAsString, methodName);
1✔
117
        statements.Add(invocation);
1✔
118

119
        foreach (var argument in node.ArgumentList.Arguments)
1!
120
        {
×
121
            var value = argument.Expression.ResolveValue(semanticModel);
×
122

123
            var argumentDescription = new ArgumentDescription(semanticModel.GetTypeDisplayString(argument.Expression), value);
×
124
            invocation.Arguments.Add(argumentDescription);
×
125
        }
×
126

127
        base.VisitInvocationExpression(node);
1✔
128
    }
1✔
129

130
    private ExpressionSyntax GetExpressionWithSymbol(InvocationExpressionSyntax node)
131
    {
1✔
132
        var expression = node.Expression;
1✔
133

134
        if (semanticModel.GetSymbolInfo(expression).Symbol == null)
1!
135
        {
×
136
            // This might be part of a chain of extention methods (f.e. Fluent API's), the symbols are only available at the beginning of the chain.
137
            var pNode = (SyntaxNode)node;
×
138

139
            while (pNode != null && (pNode is not InvocationExpressionSyntax || (pNode is InvocationExpressionSyntax && (semanticModel.GetTypeInfo(pNode).Type?.Kind == SymbolKind.ErrorType || semanticModel.GetSymbolInfo(expression).Symbol == null))))
×
140
            {
×
141
                pNode = pNode.Parent;
×
142

143
                if (pNode is InvocationExpressionSyntax syntax)
×
144
                {
×
145
                    expression = syntax.Expression;
×
146
                }
×
147
            }
×
148
        }
×
149

150
        return expression;
1✔
151
    }
1✔
152

153
    public override void VisitReturnStatement(ReturnStatementSyntax node)
154
    {
1✔
155
        var returnDescription = new ReturnDescription(node.Expression?.ResolveValue(semanticModel) ?? string.Empty);
1!
156
        statements.Add(returnDescription);
1✔
157

158
        base.VisitReturnStatement(node);
1✔
159
    }
1✔
160

161
    public override void VisitArrowExpressionClause(ArrowExpressionClauseSyntax node)
162
    {
×
163
        var returnDescription = new ReturnDescription(node.Expression.ResolveValue(semanticModel));
×
164
        statements.Add(returnDescription);
×
165

166
        base.VisitArrowExpressionClause(node);
×
167
    }
×
168

169
    public override void VisitAssignmentExpression(AssignmentExpressionSyntax node)
170
    {
×
171
        var assignmentDescription = new AssignmentDescription(node.Left.ToString(), node.OperatorToken.Text, node.Right.ToString());
×
172
        statements.Add(assignmentDescription);
×
173

174
        base.VisitAssignmentExpression(node);
×
175
    }
×
176

177
    private static bool IsNameofExpression(ExpressionSyntax expression)
178
    {
×
179
        return expression is IdentifierNameSyntax identifier && string.Equals(identifier.Identifier.ValueText, "nameof", StringComparison.Ordinal);
×
180
    }
×
181
}
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