Skip to content

Commit

Permalink
Fix StackOverflowException in RoutePatternAnalyzer (dotnet#48105)
Browse files Browse the repository at this point in the history
  • Loading branch information
JamesNK authored May 10, 2023
1 parent b69ed4c commit 2d13c49
Showing 1 changed file with 63 additions and 75 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,94 +31,82 @@ private void AnalyzeSemanticModel(SemanticModelAnalysisContext context)
var cancellationToken = context.CancellationToken;

var root = syntaxTree.GetRoot(cancellationToken);
var wellKnownTypes = WellKnownTypes.GetOrCreate(context.SemanticModel.Compilation);
var routeUsageCache = RouteUsageCache.GetOrCreate(context.SemanticModel.Compilation);
Analyze(context, root, wellKnownTypes, routeUsageCache, cancellationToken);

// Update to use FilterSpan when available. See https://github.com/dotnet/aspnetcore/issues/48157
foreach (var item in root.DescendantTokens())
{
cancellationToken.ThrowIfCancellationRequested();

AnalyzeToken(context, routeUsageCache, item, cancellationToken);
}
}

private void Analyze(
SemanticModelAnalysisContext context,
SyntaxNode node,
WellKnownTypes wellKnownTypes,
RouteUsageCache routeUsageCache,
CancellationToken cancellationToken)
private static void AnalyzeToken(SemanticModelAnalysisContext context, RouteUsageCache routeUsageCache, SyntaxToken token, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();

foreach (var child in node.ChildNodesAndTokens())
if (!RouteStringSyntaxDetector.IsRouteStringSyntaxToken(token, context.SemanticModel, cancellationToken, out var options))
{
if (child.IsNode)
{
Analyze(context, child.AsNode()!, wellKnownTypes, routeUsageCache, cancellationToken);
}
else
{
var token = child.AsToken();
if (!RouteStringSyntaxDetector.IsRouteStringSyntaxToken(token, context.SemanticModel, cancellationToken, out var options))
{
continue;
}
return;
}

var routeUsage = routeUsageCache.Get(token, cancellationToken);
if (routeUsage is null)
{
continue;
}
var routeUsage = routeUsageCache.Get(token, cancellationToken);
if (routeUsage is null)
{
return;
}

foreach (var diag in routeUsage.RoutePattern.Diagnostics)
{
context.ReportDiagnostic(Diagnostic.Create(
DiagnosticDescriptors.RoutePatternIssue,
Location.Create(context.SemanticModel.SyntaxTree, diag.Span),
DiagnosticDescriptors.RoutePatternIssue.DefaultSeverity,
additionalLocations: null,
properties: null,
diag.Message));
}
foreach (var diag in routeUsage.RoutePattern.Diagnostics)
{
context.ReportDiagnostic(Diagnostic.Create(
DiagnosticDescriptors.RoutePatternIssue,
Location.Create(context.SemanticModel.SyntaxTree, diag.Span),
DiagnosticDescriptors.RoutePatternIssue.DefaultSeverity,
additionalLocations: null,
properties: null,
diag.Message));
}

if (routeUsage.UsageContext.MethodSymbol != null)
{
var routeParameterNames = new HashSet<string>(routeUsage.RoutePattern.RouteParameters.Select(p => p.Name), StringComparer.OrdinalIgnoreCase);
if (routeUsage.UsageContext.MethodSymbol != null)
{
var routeParameterNames = new HashSet<string>(routeUsage.RoutePattern.RouteParameters.Select(p => p.Name), StringComparer.OrdinalIgnoreCase);

foreach (var parameter in routeUsage.UsageContext.ResolvedParameters)
{
routeParameterNames.Remove(parameter.RouteParameterName);
}
foreach (var parameter in routeUsage.UsageContext.ResolvedParameters)
{
routeParameterNames.Remove(parameter.RouteParameterName);
}

foreach (var unusedParameterName in routeParameterNames)
foreach (var unusedParameterName in routeParameterNames)
{
var unusedParameter = routeUsage.RoutePattern.GetRouteParameter(unusedParameterName);

var parameterInsertIndex = -1;
var insertPoint = CalculateInsertPoint(
unusedParameter.Name,
routeUsage.RoutePattern.RouteParameters,
routeUsage.UsageContext.ResolvedParameters);
if (insertPoint is { } ip)
{
parameterInsertIndex = routeUsage.UsageContext.Parameters.IndexOf(ip.ExistingParameter);
if (!ip.Before)
{
var unusedParameter = routeUsage.RoutePattern.GetRouteParameter(unusedParameterName);

var parameterInsertIndex = -1;
var insertPoint = CalculateInsertPoint(
unusedParameter.Name,
routeUsage.RoutePattern.RouteParameters,
routeUsage.UsageContext.ResolvedParameters);
if (insertPoint is { } ip)
{
parameterInsertIndex = routeUsage.UsageContext.Parameters.IndexOf(ip.ExistingParameter);
if (!ip.Before)
{
parameterInsertIndex++;
}
}

// These properties are used by the fixer.
var propertiesBuilder = ImmutableDictionary.CreateBuilder<string, string?>();
propertiesBuilder.Add("RouteParameterName", unusedParameter.Name);
propertiesBuilder.Add("RouteParameterPolicy", string.Join(string.Empty, unusedParameter.Policies));
propertiesBuilder.Add("RouteParameterIsOptional", unusedParameter.IsOptional.ToString(CultureInfo.InvariantCulture));
propertiesBuilder.Add("RouteParameterInsertIndex", parameterInsertIndex.ToString(CultureInfo.InvariantCulture));

context.ReportDiagnostic(Diagnostic.Create(
DiagnosticDescriptors.RoutePatternUnusedParameter,
Location.Create(context.SemanticModel.SyntaxTree, unusedParameter.Span),
DiagnosticDescriptors.RoutePatternUnusedParameter.DefaultSeverity,
additionalLocations: null,
properties: propertiesBuilder.ToImmutableDictionary(),
unusedParameterName));
parameterInsertIndex++;
}
}

// These properties are used by the fixer.
var propertiesBuilder = ImmutableDictionary.CreateBuilder<string, string?>();
propertiesBuilder.Add("RouteParameterName", unusedParameter.Name);
propertiesBuilder.Add("RouteParameterPolicy", string.Join(string.Empty, unusedParameter.Policies));
propertiesBuilder.Add("RouteParameterIsOptional", unusedParameter.IsOptional.ToString(CultureInfo.InvariantCulture));
propertiesBuilder.Add("RouteParameterInsertIndex", parameterInsertIndex.ToString(CultureInfo.InvariantCulture));

context.ReportDiagnostic(Diagnostic.Create(
DiagnosticDescriptors.RoutePatternUnusedParameter,
Location.Create(context.SemanticModel.SyntaxTree, unusedParameter.Span),
DiagnosticDescriptors.RoutePatternUnusedParameter.DefaultSeverity,
additionalLocations: null,
properties: propertiesBuilder.ToImmutableDictionary(),
unusedParameterName));
}
}
}
Expand Down

0 comments on commit 2d13c49

Please sign in to comment.