|
1 | 1 | namespace AspNetCoreAnalyzers |
2 | 2 | { |
3 | 3 | using System; |
| 4 | + using System.Collections.Generic; |
4 | 5 | using System.Collections.Immutable; |
5 | 6 | using System.Linq; |
6 | 7 | using Gu.Roslyn.AnalyzerExtensions; |
@@ -89,10 +90,23 @@ context.ContainingSymbol is IMethodSymbol method && |
89 | 90 | ASP004ParameterSyntax.Descriptor, |
90 | 91 | location, |
91 | 92 | syntax == null |
92 | | - ? ImmutableDictionary<string, string>.Empty |
93 | | - : ImmutableDictionary<string, string>.Empty.Add( |
94 | | - nameof(Text), |
95 | | - syntax))); |
| 93 | + ? ImmutableDictionary<string, string>.Empty |
| 94 | + : ImmutableDictionary<string, string>.Empty.Add( |
| 95 | + nameof(Text), |
| 96 | + syntax))); |
| 97 | + } |
| 98 | + |
| 99 | + if (HasWrongRegexSyntax(segment, out location, out syntax)) |
| 100 | + { |
| 101 | + context.ReportDiagnostic( |
| 102 | + Diagnostic.Create( |
| 103 | + ASP005ParameterRegex.Descriptor, |
| 104 | + location, |
| 105 | + syntax == null |
| 106 | + ? ImmutableDictionary<string, string>.Empty |
| 107 | + : ImmutableDictionary<string, string>.Empty.Add( |
| 108 | + nameof(Text), |
| 109 | + syntax))); |
96 | 110 | } |
97 | 111 | } |
98 | 112 | } |
@@ -322,5 +336,59 @@ bool HasWrongIntArgumentSyntax(RouteConstraint constraint, string methodName, ou |
322 | 336 | return false; |
323 | 337 | } |
324 | 338 | } |
| 339 | + |
| 340 | + private static bool HasWrongRegexSyntax(PathSegment segment, out Location location, out string correctSyntax) |
| 341 | + { |
| 342 | + if (segment.Parameter is TemplateParameter parameter) |
| 343 | + { |
| 344 | + foreach (var constraint in parameter.Constraints) |
| 345 | + { |
| 346 | + var text = constraint.Span.Text; |
| 347 | + if (text.StartsWith("regex(", StringComparison.OrdinalIgnoreCase)) |
| 348 | + { |
| 349 | + for (var i = 6; i < text.Length - 1; i++) |
| 350 | + { |
| 351 | + if (NotEscaped()) |
| 352 | + { |
| 353 | + var escaped = new List<char>(text.Length - 7); |
| 354 | + for (i = 6; i < text.Length - 1; i++) |
| 355 | + { |
| 356 | + escaped.Add(text[i]); |
| 357 | + if (NotEscaped()) |
| 358 | + { |
| 359 | + escaped.Add(text[i]); |
| 360 | + } |
| 361 | + } |
| 362 | + |
| 363 | + location = constraint.Span.GetLocation(6, text.Length - 7); |
| 364 | + correctSyntax = new string(escaped.ToArray()); |
| 365 | + return true; |
| 366 | + } |
| 367 | + |
| 368 | + bool NotEscaped() |
| 369 | + { |
| 370 | + return NotEscapedChar('\\') || |
| 371 | + NotEscapedChar('{') || |
| 372 | + NotEscapedChar('}') || |
| 373 | + NotEscapedChar('[') || |
| 374 | + NotEscapedChar(']'); |
| 375 | + |
| 376 | + bool NotEscapedChar(char c) |
| 377 | + { |
| 378 | + return text[i] == c && |
| 379 | + text[i - 1] != c && |
| 380 | + text[i - 1] != '\\' && |
| 381 | + text[i + 1] != c; |
| 382 | + } |
| 383 | + } |
| 384 | + } |
| 385 | + } |
| 386 | + } |
| 387 | + } |
| 388 | + |
| 389 | + location = null; |
| 390 | + correctSyntax = null; |
| 391 | + return false; |
| 392 | + } |
325 | 393 | } |
326 | 394 | } |
0 commit comments