private static bool TryGetParameterType(ParameterPair pair, out string typeName) { if (pair.Template?.Type is TextAndLocation templateType && pair.Method is IParameterSymbol parameter) { switch (templateType.Text) { // https://docs.microsoft.com/en-us/aspnet/core/fundamentals/routing?view=aspnetcore-2.2#route-constraint-reference case "bool" when parameter.Type != KnownSymbol.Boolean: case "decimal" when parameter.Type != KnownSymbol.Decimal: case "double" when parameter.Type != KnownSymbol.Float: case "float" when parameter.Type != KnownSymbol.Double: case "int" when parameter.Type != KnownSymbol.Int32: case "long" when parameter.Type != KnownSymbol.Int64: typeName = templateType.Text; return(true); case "datetime" when parameter.Type != KnownSymbol.DateTime: typeName = "System.DateTime"; return(true); case "guid" when parameter.Type != KnownSymbol.Guid: typeName = "System.Guid"; return(true); case "alpha" when parameter.Type != KnownSymbol.String: typeName = "string"; return(true); } } typeName = null; return(false); }
private static bool HasWrongType(ParameterPair pair, out string correctType, out Location constraintLocation, out string correctConstraint) { if (pair.Route is TemplateParameter templateParameter && templateParameter.Constraints is ImmutableArray <RouteConstraint> constraints && pair.Symbol is IParameterSymbol parameterSymbol) { foreach (var constraint in constraints) { // https://docs.microsoft.com/en-us/aspnet/core/fundamentals/routing?view=aspnetcore-2.2#route-constraint-reference if (TryGetType(constraint.Span, out var type)) { correctType = parameterSymbol.Type == type ? null : type.Alias ?? type.FullName; constraintLocation = constraint.Span.GetLocation(); correctConstraint = GetCorrectConstraintType(constraint); return(correctType != null); } if (constraint.Span.Equals("?", StringComparison.Ordinal) && parameterSymbol.Type.IsValueType && parameterSymbol.Type.OriginalDefinition.SpecialType != SpecialType.System_Nullable_T) { correctType = parameterSymbol.Type.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat) + "?"; constraintLocation = constraint.Span.GetLocation(); correctConstraint = string.Empty; return(true); } } if (!constraints.TryFirst(x => x.Span.Equals("?", StringComparison.Ordinal), out _) && parameterSymbol.Type.OriginalDefinition.SpecialType == SpecialType.System_Nullable_T && parameterSymbol.Type is INamedTypeSymbol namedType && namedType.TypeArguments.TrySingle(out var typeArg)) { correctType = typeArg.ToString(); constraintLocation = templateParameter.Name.GetLocation(); correctConstraint = $"{templateParameter.Name}?"; return(true); } } correctType = null; constraintLocation = null; correctConstraint = null; return(false); bool TryGetType(Span constraint, out QualifiedType type) { if (constraint.Equals("bool", StringComparison.Ordinal)) { type = KnownSymbol.Boolean; return(true); } if (constraint.Equals("decimal", StringComparison.Ordinal)) { type = KnownSymbol.Decimal; return(true); } if (constraint.Equals("double", StringComparison.Ordinal)) { type = KnownSymbol.Double; return(true); } if (constraint.Equals("float", StringComparison.Ordinal)) { type = KnownSymbol.Float; return(true); } if (constraint.Equals("int", StringComparison.Ordinal)) { type = KnownSymbol.Int32; return(true); } if (constraint.Equals("long", StringComparison.Ordinal) || constraint.StartsWith("min(", StringComparison.OrdinalIgnoreCase) || constraint.StartsWith("max(", StringComparison.OrdinalIgnoreCase) || constraint.StartsWith("range(", StringComparison.OrdinalIgnoreCase)) { type = KnownSymbol.Int64; return(true); } if (constraint.Equals("datetime", StringComparison.Ordinal)) { type = KnownSymbol.DateTime; return(true); } if (constraint.Equals("guid", StringComparison.Ordinal)) { type = KnownSymbol.Guid; return(true); } if (constraint.Equals("alpha", StringComparison.OrdinalIgnoreCase) || constraint.StartsWith("regex(", StringComparison.OrdinalIgnoreCase) || constraint.StartsWith("length(", StringComparison.OrdinalIgnoreCase) || constraint.StartsWith("minlength(", StringComparison.OrdinalIgnoreCase) || constraint.StartsWith("maxlength(", StringComparison.OrdinalIgnoreCase)) { type = KnownSymbol.String; return(true); } type = null; return(false); } string GetCorrectConstraintType(RouteConstraint constraint) { if (constraint.Span.Equals("bool", StringComparison.Ordinal) || constraint.Span.Equals("decimal", StringComparison.Ordinal) || constraint.Span.Equals("double", StringComparison.Ordinal) || constraint.Span.Equals("float", StringComparison.Ordinal) || constraint.Span.Equals("int", StringComparison.Ordinal) || constraint.Span.Equals("long", StringComparison.Ordinal) || constraint.Span.Equals("datetime", StringComparison.Ordinal) || constraint.Span.Equals("guid", StringComparison.Ordinal)) { return(parameterSymbol.Type.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat) .ToLower()); } return(null); } }