/
ValidateArgumentsCorrectlyAnalyzer.cs
111 lines (83 loc) · 3.65 KB
/
ValidateArgumentsCorrectlyAnalyzer.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
// Copyright (c) Josef Pihrt and Contributors. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Text;
using Roslynator.CSharp.SyntaxWalkers;
namespace Roslynator.CSharp.Analysis
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public sealed class ValidateArgumentsCorrectlyAnalyzer : BaseDiagnosticAnalyzer
{
private static ImmutableArray<DiagnosticDescriptor> _supportedDiagnostics;
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
{
get
{
if (_supportedDiagnostics.IsDefault)
Immutable.InterlockedInitialize(ref _supportedDiagnostics, DiagnosticRules.ValidateArgumentsCorrectly);
return _supportedDiagnostics;
}
}
public override void Initialize(AnalysisContext context)
{
base.Initialize(context);
context.RegisterSyntaxNodeAction(f => AnalyzeMethodDeclaration(f), SyntaxKind.MethodDeclaration);
}
private static void AnalyzeMethodDeclaration(SyntaxNodeAnalysisContext context)
{
var methodDeclaration = (MethodDeclarationSyntax)context.Node;
BlockSyntax body = methodDeclaration.Body;
if (body == null)
return;
ParameterListSyntax parameterList = methodDeclaration.ParameterList;
if (parameterList == null)
return;
if (!parameterList.Parameters.Any())
return;
SyntaxList<StatementSyntax> statements = body.Statements;
int statementCount = statements.Count;
int index = -1;
for (int i = 0; i < statementCount; i++)
{
if (IsConditionWithThrow(statements[i])
|| ArgumentNullCheckAnalysis.IsArgumentNullExceptionThrowIfNullCheck(statements[i], context.SemanticModel, context.CancellationToken))
{
index++;
}
else
{
break;
}
}
if (index == -1)
return;
if (index == statementCount - 1)
return;
TextSpan span = TextSpan.FromBounds(statements[index + 1].SpanStart, statements.Last().Span.End);
if (body.ContainsUnbalancedIfElseDirectives(span))
return;
context.CancellationToken.ThrowIfCancellationRequested();
ContainsYieldWalker walker = ContainsYieldWalker.GetInstance();
walker.VisitBlock(body);
YieldStatementSyntax yieldStatement = walker.YieldStatement;
ContainsYieldWalker.Free(walker);
if (yieldStatement == null)
return;
if (yieldStatement.SpanStart < statements[index].Span.End)
return;
DiagnosticHelpers.ReportDiagnostic(
context,
DiagnosticRules.ValidateArgumentsCorrectly,
Location.Create(body.SyntaxTree, new TextSpan(statements[index + 1].SpanStart, 0)));
}
private static bool IsConditionWithThrow(StatementSyntax statement)
{
return statement is IfStatementSyntax ifStatement
&& ifStatement.IsSimpleIf()
&& ifStatement.SingleNonBlockStatementOrDefault().IsKind(SyntaxKind.ThrowStatement);
}
}
}