Skip to content

Commit 6f26b70

Browse files
committed
ASP002 Route parameter type does not match the method parameter name.
1 parent 5ca663b commit 6f26b70

File tree

11 files changed

+365
-23
lines changed

11 files changed

+365
-23
lines changed

AspNetCoreAnalyzers.Tests/ASP002MissingParameterTests/CodeFix.cs renamed to AspNetCoreAnalyzers.Tests/ASP002RouteParameterNameTests/CodeFix.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
namespace AspNetCoreAnalyzers.Tests.ASP002MissingParameterTests
1+
namespace AspNetCoreAnalyzers.Tests.ASP002RouteParameterNameTests
22
{
33
using Gu.Roslyn.Asserts;
44
using Microsoft.CodeAnalysis.CodeFixes;
@@ -8,7 +8,7 @@ namespace AspNetCoreAnalyzers.Tests.ASP002MissingParameterTests
88
public class CodeFix
99
{
1010
private static readonly DiagnosticAnalyzer Analyzer = new AttributeAnalyzer();
11-
private static readonly ExpectedDiagnostic ExpectedDiagnostic = ExpectedDiagnostic.Create(ASP007MissingParameter.Descriptor);
11+
private static readonly ExpectedDiagnostic ExpectedDiagnostic = ExpectedDiagnostic.Create(ASP002RouteParameterName.Descriptor);
1212
private static readonly CodeFixProvider Fix = new TemplateTextFix();
1313

1414
[TestCase("\"api/{↓value}\"", "\"api/{text}\"")]
Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
namespace AspNetCoreAnalyzers.Tests.ASP002RouteParameterNameTests
2+
{
3+
using Gu.Roslyn.Asserts;
4+
using Microsoft.CodeAnalysis.Diagnostics;
5+
using NUnit.Framework;
6+
7+
public class ValidCode
8+
{
9+
private static readonly DiagnosticAnalyzer Analyzer = new AttributeAnalyzer();
10+
11+
[TestCase("\"api/{text}\"")]
12+
[TestCase("@\"api/{text}\"")]
13+
[TestCase("\"api/{text:alpha}\"")]
14+
public void When(string after)
15+
{
16+
var code = @"
17+
namespace ValidCode
18+
{
19+
using System.Threading.Tasks;
20+
using Microsoft.AspNetCore.Mvc;
21+
using Microsoft.EntityFrameworkCore;
22+
23+
[ApiController]
24+
public class OrdersController : Controller
25+
{
26+
[HttpGet(""api/{text}"")]
27+
public IActionResult GetValue(string text)
28+
{
29+
return this.Ok(text);
30+
}
31+
}
32+
}".AssertReplace("\"api/{text}\"", after);
33+
34+
AnalyzerAssert.Valid(Analyzer, code);
35+
}
36+
37+
[TestCase("\"api/orders/\" + \"{wrong}\"")]
38+
public void IgnoreWhen(string template)
39+
{
40+
var code = @"
41+
namespace ValidCode
42+
{
43+
using Microsoft.AspNetCore.Mvc;
44+
45+
[ApiController]
46+
public class OrdersController : Controller
47+
{
48+
[HttpGet(""api/orders/{value}"")]
49+
public IActionResult GetId(string value)
50+
{
51+
return this.Ok(value);
52+
}
53+
}
54+
}".AssertReplace("\"api/orders/{value}\"", template);
55+
AnalyzerAssert.Valid(Analyzer, code);
56+
}
57+
58+
[Test]
59+
public void ImplicitFromRoute()
60+
{
61+
var order = @"
62+
namespace ValidCode
63+
{
64+
public class Order
65+
{
66+
public int Id { get; set; }
67+
}
68+
}";
69+
70+
var db = @"
71+
namespace ValidCode
72+
{
73+
using Microsoft.EntityFrameworkCore;
74+
75+
public class Db : DbContext
76+
{
77+
public DbSet<Order> Orders { get; set; }
78+
}
79+
}";
80+
var code = @"
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+
private readonly Db db;
91+
92+
public OrdersController(Db db)
93+
{
94+
this.db = db;
95+
}
96+
97+
[HttpGet(""api/orders/{id}"")]
98+
public async Task<IActionResult> GetOrder(int id)
99+
{
100+
var match = await this.db.Orders.FirstOrDefaultAsync(x => x.Id == id);
101+
if (match == null)
102+
{
103+
return this.NotFound();
104+
}
105+
106+
return this.Ok(match);
107+
}
108+
}
109+
}";
110+
AnalyzerAssert.Valid(Analyzer, order, db, code);
111+
}
112+
113+
[Test]
114+
public void ExplicitFromRoute()
115+
{
116+
var order = @"
117+
namespace ValidCode
118+
{
119+
public class Order
120+
{
121+
public int Id { get; set; }
122+
}
123+
}";
124+
125+
var db = @"
126+
namespace ValidCode
127+
{
128+
using Microsoft.EntityFrameworkCore;
129+
130+
public class Db : DbContext
131+
{
132+
public DbSet<Order> Orders { get; set; }
133+
}
134+
}";
135+
var code = @"
136+
namespace ValidCode
137+
{
138+
using System.Threading.Tasks;
139+
using Microsoft.AspNetCore.Mvc;
140+
using Microsoft.EntityFrameworkCore;
141+
142+
[ApiController]
143+
public class OrdersController : Controller
144+
{
145+
private readonly Db db;
146+
147+
public OrdersController(Db db)
148+
{
149+
this.db = db;
150+
}
151+
152+
[HttpGet(""api/orders/{id}"")]
153+
public async Task<IActionResult> GetOrder([FromRoute]int id)
154+
{
155+
var match = await this.db.Orders.FirstOrDefaultAsync(x => x.Id == id);
156+
if (match == null)
157+
{
158+
return this.NotFound();
159+
}
160+
161+
return this.Ok(match);
162+
}
163+
}
164+
}";
165+
AnalyzerAssert.Valid(Analyzer, order, db, code);
166+
}
167+
168+
[Test]
169+
public void WhenFromHeaderAndNoRouteParameter()
170+
{
171+
var order = @"
172+
namespace ValidCode
173+
{
174+
public class Order
175+
{
176+
public int Id { get; set; }
177+
}
178+
}";
179+
180+
var db = @"
181+
namespace ValidCode
182+
{
183+
using Microsoft.EntityFrameworkCore;
184+
185+
public class Db : DbContext
186+
{
187+
public DbSet<Order> Orders { get; set; }
188+
}
189+
}";
190+
var code = @"
191+
namespace ValidCode
192+
{
193+
using System.Threading.Tasks;
194+
using Microsoft.AspNetCore.Mvc;
195+
using Microsoft.EntityFrameworkCore;
196+
197+
[ApiController]
198+
public class OrdersController : Controller
199+
{
200+
private readonly Db db;
201+
202+
public OrdersController(Db db)
203+
{
204+
this.db = db;
205+
}
206+
207+
[HttpGet(""api/orders"")]
208+
public async Task<IActionResult> GetOrder([FromHeader]int id)
209+
{
210+
var match = await this.db.Orders.FirstOrDefaultAsync(x => x.Id == id);
211+
if (match == null)
212+
{
213+
return this.NotFound();
214+
}
215+
216+
return this.Ok(match);
217+
}
218+
}
219+
}";
220+
AnalyzerAssert.Valid(Analyzer, order, db, code);
221+
}
222+
}
223+
}

AspNetCoreAnalyzers.Tests/ASP002MissingParameterTests/Diagnostics.cs renamed to AspNetCoreAnalyzers.Tests/ASP007MissingParameterTests/Diagnostics.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
namespace AspNetCoreAnalyzers.Tests.ASP002MissingParameterTests
1+
namespace AspNetCoreAnalyzers.Tests.ASP007MissingParameterTests
22
{
33
using Gu.Roslyn.Asserts;
44
using Microsoft.CodeAnalysis.Diagnostics;

AspNetCoreAnalyzers.Tests/ASP002MissingParameterTests/ValidCode.cs renamed to AspNetCoreAnalyzers.Tests/ASP007MissingParameterTests/ValidCode.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
namespace AspNetCoreAnalyzers.Tests.ASP002MissingParameterTests
1+
namespace AspNetCoreAnalyzers.Tests.ASP007MissingParameterTests
22
{
33
using Gu.Roslyn.Asserts;
44
using Microsoft.CodeAnalysis.Diagnostics;
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
namespace AspNetCoreAnalyzers
2+
{
3+
using Microsoft.CodeAnalysis;
4+
5+
internal static class ASP002RouteParameterName
6+
{
7+
public const string DiagnosticId = "ASP002";
8+
9+
internal static readonly DiagnosticDescriptor Descriptor = new DiagnosticDescriptor(
10+
id: DiagnosticId,
11+
title: "Route parameter type does not match the method parameter name.",
12+
messageFormat: "Route parameter type does not match the method parameter name.",
13+
category: AnalyzerCategory.Routing,
14+
defaultSeverity: DiagnosticSeverity.Warning,
15+
isEnabledByDefault: true,
16+
description: "Route parameter type does not match the method parameter name.",
17+
helpLinkUri: HelpLink.ForId(DiagnosticId));
18+
}
19+
}

AspNetCoreAnalyzers/ASP007MissingParameter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ namespace AspNetCoreAnalyzers
44

55
internal static class ASP007MissingParameter
66
{
7-
public const string DiagnosticId = "ASP002";
7+
public const string DiagnosticId = "ASP007";
88

99
internal static readonly DiagnosticDescriptor Descriptor = new DiagnosticDescriptor(
1010
id: DiagnosticId,

AspNetCoreAnalyzers/Analyzers/AttributeAnalyzer.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,12 @@ public class AttributeAnalyzer : DiagnosticAnalyzer
1616
{
1717
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = ImmutableArray.Create(
1818
ASP001ParameterSymbolName.Descriptor,
19-
ASP007MissingParameter.Descriptor,
19+
ASP002RouteParameterName.Descriptor,
2020
ASP003ParameterSymbolType.Descriptor,
2121
ASP004RouteParameterType.Descriptor,
2222
ASP005ParameterSyntax.Descriptor,
23-
ASP006ParameterRegex.Descriptor);
23+
ASP006ParameterRegex.Descriptor,
24+
ASP007MissingParameter.Descriptor);
2425

2526
public override void Initialize(AnalysisContext context)
2627
{
@@ -52,7 +53,7 @@ context.ContainingSymbol is IMethodSymbol method &&
5253

5354
context.ReportDiagnostic(
5455
Diagnostic.Create(
55-
ASP007MissingParameter.Descriptor,
56+
ASP002RouteParameterName.Descriptor,
5657
templateParameter.Name.GetLocation(),
5758
ImmutableDictionary<string, string>.Empty.Add(
5859
nameof(Text),

AspNetCoreAnalyzers/CodeFixes/TemplateTextFix.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ namespace AspNetCoreAnalyzers
1616
public class TemplateTextFix : CodeFixProvider
1717
{
1818
public override ImmutableArray<string> FixableDiagnosticIds { get; } = ImmutableArray.Create(
19-
ASP007MissingParameter.DiagnosticId,
19+
ASP002RouteParameterName.DiagnosticId,
2020
ASP004RouteParameterType.DiagnosticId,
2121
ASP005ParameterSyntax.DiagnosticId,
2222
ASP006ParameterRegex.DiagnosticId);
@@ -54,7 +54,7 @@ private static string GetTitle(Diagnostic diagnostic)
5454
{
5555
switch (diagnostic.Id)
5656
{
57-
case ASP007MissingParameter.DiagnosticId:
57+
case ASP002RouteParameterName.DiagnosticId:
5858
return "Rename parameter.";
5959
case ASP004RouteParameterType.DiagnosticId:
6060
return "Change type to match symbol.";

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ Roslyn analyzers for ASP.NET.Core.
1717
</tr>
1818
<tr>
1919
<td><a href="https://github.com/DotNetAnalyzers/AspNetCoreAnalyzers/tree/master/documentation/ASP002.md">ASP002</a></td>
20-
<td>The method has no corresponding parameter.</td>
20+
<td>Route parameter type does not match the method parameter name.</td>
2121
</tr>
2222
<tr>
2323
<td><a href="https://github.com/DotNetAnalyzers/AspNetCoreAnalyzers/tree/master/documentation/ASP003.md">ASP003</a></td>
@@ -35,6 +35,10 @@ Roslyn analyzers for ASP.NET.Core.
3535
<td><a href="https://github.com/DotNetAnalyzers/AspNetCoreAnalyzers/tree/master/documentation/ASP006.md">ASP006</a></td>
3636
<td>Escape constraint regex.</td>
3737
</tr>
38+
<tr>
39+
<td><a href="https://github.com/DotNetAnalyzers/AspNetCoreAnalyzers/tree/master/documentation/ASP007.md">ASP007</a></td>
40+
<td>The method has no corresponding parameter.</td>
41+
</tr>
3842
<table>
3943
<!-- end generated table -->
4044

0 commit comments

Comments
 (0)