Skip to content

Commit 9d1cba9

Browse files
committed
Handle backslash in literals and tests.
1 parent e804d7c commit 9d1cba9

3 files changed

Lines changed: 105 additions & 8 deletions

File tree

AspNetCoreAnalyzers.Tests/ASP002MissingParameterTests/CodeFix.cs

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ public class CodeFix
1111
private static readonly ExpectedDiagnostic ExpectedDiagnostic = ExpectedDiagnostic.Create(ASP002MissingParameter.Descriptor);
1212
private static readonly CodeFixProvider Fix = new TemplateTextFix();
1313

14-
[TestCase("api/{↓value}", "api/{text}")]
15-
[TestCase("api/{↓value:alpha}", "api/{text:alpha}")]
14+
[TestCase("\"api/{↓value}\"", "\"api/{text}\"")]
15+
[TestCase("\"api/{↓value:alpha}\"", "\"api/{text:alpha}\"")]
1616
public void WhenWrongName(string before, string after)
1717
{
1818
var code = @"
@@ -31,7 +31,7 @@ public IActionResult GetValue(string text)
3131
return this.Ok(text);
3232
}
3333
}
34-
}".AssertReplace("api/{↓value}", before);
34+
}".AssertReplace("\"api/{↓value}\"", before);
3535

3636
var fixedCode = @"
3737
namespace ValidCode
@@ -49,7 +49,51 @@ public IActionResult GetValue(string text)
4949
return this.Ok(text);
5050
}
5151
}
52-
}".AssertReplace("api/{text}", after);
52+
}".AssertReplace("\"api/{text}\"", after);
53+
54+
AnalyzerAssert.CodeFix(Analyzer, Fix, ExpectedDiagnostic, code, fixedCode);
55+
}
56+
57+
[TestCase("\"api/{text1}/{↓value}\"", "\"api/{text1}/{text2}\"")]
58+
[TestCase("\"api/{text1:regex(\\\\d+)}/{↓value}\"", "\"api/{text1:regex(\\\\d+)}/{text2}\"")]
59+
[TestCase("@\"api/{text1:regex(\\d+)}/{↓value}\"", "@\"api/{text1:regex(\\d+)}/{text2}\"")]
60+
public void WhenWrongNameSecondParameter(string before, string after)
61+
{
62+
var code = @"
63+
namespace ValidCode
64+
{
65+
using System.Threading.Tasks;
66+
using Microsoft.AspNetCore.Mvc;
67+
using Microsoft.EntityFrameworkCore;
68+
69+
[ApiController]
70+
public class OrdersController : Controller
71+
{
72+
[HttpGet(""api/{text1}/{↓value}"")]
73+
public IActionResult GetValue(string text1, string text2)
74+
{
75+
return this.Ok(text1 + text2);
76+
}
77+
}
78+
}".AssertReplace("\"api/{text1}/{↓value}\"", before);
79+
80+
var fixedCode = @"
81+
namespace ValidCode
82+
{
83+
using System.Threading.Tasks;
84+
using Microsoft.AspNetCore.Mvc;
85+
using Microsoft.EntityFrameworkCore;
86+
87+
[ApiController]
88+
public class OrdersController : Controller
89+
{
90+
[HttpGet(""api/{text1}/{text2}"")]
91+
public IActionResult GetValue(string text1, string text2)
92+
{
93+
return this.Ok(text1 + text2);
94+
}
95+
}
96+
}".AssertReplace("\"api/{text1}/{text2}\"", after);
5397

5498
AnalyzerAssert.CodeFix(Analyzer, Fix, ExpectedDiagnostic, code, fixedCode);
5599
}

AspNetCoreAnalyzers.Tests/ASP004ParameterSyntaxTests/Diagnostics.cs

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
namespace AspNetCoreAnalyzers.Tests.ASP004ParameterSyntaxTests
22
{
3+
using System.Globalization;
34
using Gu.Roslyn.Asserts;
5+
using Microsoft.CodeAnalysis;
46
using Microsoft.CodeAnalysis.Diagnostics;
7+
using Microsoft.CodeAnalysis.Text;
58
using NUnit.Framework;
69

710
public class Diagnostics
@@ -10,6 +13,7 @@ public class Diagnostics
1013
private static readonly ExpectedDiagnostic ExpectedDiagnostic = ExpectedDiagnostic.Create(ASP004ParameterSyntax.Descriptor);
1114

1215
[TestCase("\"api/orders/{id:↓wrong}\"")]
16+
[TestCase("@\"api/orders/{id:↓wrong}\"")]
1317
[TestCase("\"api/orders/{id:min1)}\"")]
1418
[TestCase("\"api/orders/{id:max1)}\"")]
1519
[TestCase("\"api/orders/{id:min(↓wrong))}\"")]
@@ -38,10 +42,10 @@ public IActionResult GetId(long id)
3842
AnalyzerAssert.Diagnostics(Analyzer, ExpectedDiagnostic, code);
3943
}
4044

41-
[TestCase("\"api/orders/{id:regex(\\\\d):minlength(↓wrong))}\"")]
42-
[TestCase("@\"api/orders/{id:regex(\\d):minlength(↓wrong))}\"")]
4345
[TestCase("\"api/orders/{id:minlength(↓wrong))}\"")]
4446
[TestCase("\"api/orders/{id:maxlength(↓wrong))}\"")]
47+
[TestCase("\"api/orders/{id:regex(\\\\d):minlength(↓wrong))}\"")]
48+
[TestCase("@\"api/orders/{id:regex(\\d):minlength(↓wrong))}\"")]
4549
public void WhenString(string before)
4650
{
4751
var code = @"
@@ -62,5 +66,32 @@ public IActionResult GetId(string id)
6266

6367
AnalyzerAssert.Diagnostics(Analyzer, ExpectedDiagnostic, code);
6468
}
69+
70+
[TestCase("\"api/orders/{id:regex(\\\\d):minlength(wrong))}\"", 53, 58)]
71+
[TestCase("@\"api/orders/{id:regex(\\d):minlength(wrong))}\"", 53, 56)]
72+
public void WhenStringExplicitSpan(string before, int start, int end)
73+
{
74+
var code = @"
75+
namespace ValidCode
76+
{
77+
using Microsoft.AspNetCore.Mvc;
78+
79+
[ApiController]
80+
public class OrdersController : Controller
81+
{
82+
[HttpGet(""api/orders/{id:wrong}"")]
83+
public IActionResult GetId(string id)
84+
{
85+
return this.Ok(id);
86+
}
87+
}
88+
}".AssertReplace("\"api/orders/{id:wrong}\"", before);
89+
90+
var expectedDiagnostic = new ExpectedDiagnostic(
91+
ASP004ParameterSyntax.DiagnosticId,
92+
ASP004ParameterSyntax.Descriptor.MessageFormat.ToString(CultureInfo.InvariantCulture),
93+
new FileLinePositionSpan("OrdersController.cs", new LinePosition(8, start), new LinePosition(8, end)));
94+
AnalyzerAssert.Diagnostics(Analyzer, expectedDiagnostic, code);
95+
}
6596
}
6697
}

AspNetCoreAnalyzers/Helpers/Span.cs

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,9 @@ public override int GetHashCode()
5353
}
5454
}
5555

56-
public Location GetLocation() => Location.Create(this.literal.SyntaxTree, new TextSpan(this.literal.SpanStart + this.TextSpan.Start + 1, this.TextSpan.Length));
56+
public Location GetLocation() => GetLocation(this.literal, this.TextSpan);
5757

58-
public Location GetLocation(int start) => Location.Create(this.literal.SyntaxTree, new TextSpan(this.literal.SpanStart + this.TextSpan.Start + start + 1, this.TextSpan.Length));
58+
public Location GetLocation(int start) => Location.Create(this.literal.SyntaxTree, new TextSpan(this.literal.SpanStart + this.TextSpan.Start + start + 1, this.TextSpan.Length - start));
5959

6060
public Location GetLocation(int start, int length) => Location.Create(this.literal.SyntaxTree, new TextSpan(this.literal.SpanStart + this.TextSpan.Start + start + 1, length));
6161

@@ -83,5 +83,27 @@ internal Span Substring(int index)
8383
{
8484
return new Span(this.literal, this.TextSpan.Start + index, this.TextSpan.Start + index + this.TextSpan.Length);
8585
}
86+
87+
private static Location GetLocation(LiteralExpressionSyntax literal, TextSpan textSpan)
88+
{
89+
var text = literal.Token.ValueText;
90+
return Location.Create(literal.SyntaxTree, TextSpan.FromBounds(GetIndex(textSpan.Start), GetIndex(textSpan.End)));
91+
92+
int GetIndex(int pos)
93+
{
94+
var index = literal.SpanStart + 1;
95+
for (var j = 0; j < pos; j++)
96+
{
97+
if (text[j] == '\\')
98+
{
99+
index++;
100+
}
101+
102+
index++;
103+
}
104+
105+
return index;
106+
}
107+
}
86108
}
87109
}

0 commit comments

Comments
 (0)