Skip to content

Commit 2d13c49

Browse files
authored
Fix StackOverflowException in RoutePatternAnalyzer (#48105)
1 parent b69ed4c commit 2d13c49

File tree

1 file changed

+63
-75
lines changed

1 file changed

+63
-75
lines changed

src/Framework/AspNetCoreAnalyzers/src/Analyzers/RouteEmbeddedLanguage/RoutePatternAnalyzer.cs

Lines changed: 63 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -31,94 +31,82 @@ private void AnalyzeSemanticModel(SemanticModelAnalysisContext context)
3131
var cancellationToken = context.CancellationToken;
3232

3333
var root = syntaxTree.GetRoot(cancellationToken);
34-
var wellKnownTypes = WellKnownTypes.GetOrCreate(context.SemanticModel.Compilation);
3534
var routeUsageCache = RouteUsageCache.GetOrCreate(context.SemanticModel.Compilation);
36-
Analyze(context, root, wellKnownTypes, routeUsageCache, cancellationToken);
35+
36+
// Update to use FilterSpan when available. See https://github.com/dotnet/aspnetcore/issues/48157
37+
foreach (var item in root.DescendantTokens())
38+
{
39+
cancellationToken.ThrowIfCancellationRequested();
40+
41+
AnalyzeToken(context, routeUsageCache, item, cancellationToken);
42+
}
3743
}
3844

39-
private void Analyze(
40-
SemanticModelAnalysisContext context,
41-
SyntaxNode node,
42-
WellKnownTypes wellKnownTypes,
43-
RouteUsageCache routeUsageCache,
44-
CancellationToken cancellationToken)
45+
private static void AnalyzeToken(SemanticModelAnalysisContext context, RouteUsageCache routeUsageCache, SyntaxToken token, CancellationToken cancellationToken)
4546
{
46-
cancellationToken.ThrowIfCancellationRequested();
47-
48-
foreach (var child in node.ChildNodesAndTokens())
47+
if (!RouteStringSyntaxDetector.IsRouteStringSyntaxToken(token, context.SemanticModel, cancellationToken, out var options))
4948
{
50-
if (child.IsNode)
51-
{
52-
Analyze(context, child.AsNode()!, wellKnownTypes, routeUsageCache, cancellationToken);
53-
}
54-
else
55-
{
56-
var token = child.AsToken();
57-
if (!RouteStringSyntaxDetector.IsRouteStringSyntaxToken(token, context.SemanticModel, cancellationToken, out var options))
58-
{
59-
continue;
60-
}
49+
return;
50+
}
6151

62-
var routeUsage = routeUsageCache.Get(token, cancellationToken);
63-
if (routeUsage is null)
64-
{
65-
continue;
66-
}
52+
var routeUsage = routeUsageCache.Get(token, cancellationToken);
53+
if (routeUsage is null)
54+
{
55+
return;
56+
}
6757

68-
foreach (var diag in routeUsage.RoutePattern.Diagnostics)
69-
{
70-
context.ReportDiagnostic(Diagnostic.Create(
71-
DiagnosticDescriptors.RoutePatternIssue,
72-
Location.Create(context.SemanticModel.SyntaxTree, diag.Span),
73-
DiagnosticDescriptors.RoutePatternIssue.DefaultSeverity,
74-
additionalLocations: null,
75-
properties: null,
76-
diag.Message));
77-
}
58+
foreach (var diag in routeUsage.RoutePattern.Diagnostics)
59+
{
60+
context.ReportDiagnostic(Diagnostic.Create(
61+
DiagnosticDescriptors.RoutePatternIssue,
62+
Location.Create(context.SemanticModel.SyntaxTree, diag.Span),
63+
DiagnosticDescriptors.RoutePatternIssue.DefaultSeverity,
64+
additionalLocations: null,
65+
properties: null,
66+
diag.Message));
67+
}
7868

79-
if (routeUsage.UsageContext.MethodSymbol != null)
80-
{
81-
var routeParameterNames = new HashSet<string>(routeUsage.RoutePattern.RouteParameters.Select(p => p.Name), StringComparer.OrdinalIgnoreCase);
69+
if (routeUsage.UsageContext.MethodSymbol != null)
70+
{
71+
var routeParameterNames = new HashSet<string>(routeUsage.RoutePattern.RouteParameters.Select(p => p.Name), StringComparer.OrdinalIgnoreCase);
8272

83-
foreach (var parameter in routeUsage.UsageContext.ResolvedParameters)
84-
{
85-
routeParameterNames.Remove(parameter.RouteParameterName);
86-
}
73+
foreach (var parameter in routeUsage.UsageContext.ResolvedParameters)
74+
{
75+
routeParameterNames.Remove(parameter.RouteParameterName);
76+
}
8777

88-
foreach (var unusedParameterName in routeParameterNames)
78+
foreach (var unusedParameterName in routeParameterNames)
79+
{
80+
var unusedParameter = routeUsage.RoutePattern.GetRouteParameter(unusedParameterName);
81+
82+
var parameterInsertIndex = -1;
83+
var insertPoint = CalculateInsertPoint(
84+
unusedParameter.Name,
85+
routeUsage.RoutePattern.RouteParameters,
86+
routeUsage.UsageContext.ResolvedParameters);
87+
if (insertPoint is { } ip)
88+
{
89+
parameterInsertIndex = routeUsage.UsageContext.Parameters.IndexOf(ip.ExistingParameter);
90+
if (!ip.Before)
8991
{
90-
var unusedParameter = routeUsage.RoutePattern.GetRouteParameter(unusedParameterName);
91-
92-
var parameterInsertIndex = -1;
93-
var insertPoint = CalculateInsertPoint(
94-
unusedParameter.Name,
95-
routeUsage.RoutePattern.RouteParameters,
96-
routeUsage.UsageContext.ResolvedParameters);
97-
if (insertPoint is { } ip)
98-
{
99-
parameterInsertIndex = routeUsage.UsageContext.Parameters.IndexOf(ip.ExistingParameter);
100-
if (!ip.Before)
101-
{
102-
parameterInsertIndex++;
103-
}
104-
}
105-
106-
// These properties are used by the fixer.
107-
var propertiesBuilder = ImmutableDictionary.CreateBuilder<string, string?>();
108-
propertiesBuilder.Add("RouteParameterName", unusedParameter.Name);
109-
propertiesBuilder.Add("RouteParameterPolicy", string.Join(string.Empty, unusedParameter.Policies));
110-
propertiesBuilder.Add("RouteParameterIsOptional", unusedParameter.IsOptional.ToString(CultureInfo.InvariantCulture));
111-
propertiesBuilder.Add("RouteParameterInsertIndex", parameterInsertIndex.ToString(CultureInfo.InvariantCulture));
112-
113-
context.ReportDiagnostic(Diagnostic.Create(
114-
DiagnosticDescriptors.RoutePatternUnusedParameter,
115-
Location.Create(context.SemanticModel.SyntaxTree, unusedParameter.Span),
116-
DiagnosticDescriptors.RoutePatternUnusedParameter.DefaultSeverity,
117-
additionalLocations: null,
118-
properties: propertiesBuilder.ToImmutableDictionary(),
119-
unusedParameterName));
92+
parameterInsertIndex++;
12093
}
12194
}
95+
96+
// These properties are used by the fixer.
97+
var propertiesBuilder = ImmutableDictionary.CreateBuilder<string, string?>();
98+
propertiesBuilder.Add("RouteParameterName", unusedParameter.Name);
99+
propertiesBuilder.Add("RouteParameterPolicy", string.Join(string.Empty, unusedParameter.Policies));
100+
propertiesBuilder.Add("RouteParameterIsOptional", unusedParameter.IsOptional.ToString(CultureInfo.InvariantCulture));
101+
propertiesBuilder.Add("RouteParameterInsertIndex", parameterInsertIndex.ToString(CultureInfo.InvariantCulture));
102+
103+
context.ReportDiagnostic(Diagnostic.Create(
104+
DiagnosticDescriptors.RoutePatternUnusedParameter,
105+
Location.Create(context.SemanticModel.SyntaxTree, unusedParameter.Span),
106+
DiagnosticDescriptors.RoutePatternUnusedParameter.DefaultSeverity,
107+
additionalLocations: null,
108+
properties: propertiesBuilder.ToImmutableDictionary(),
109+
unusedParameterName));
122110
}
123111
}
124112
}

0 commit comments

Comments
 (0)