Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Options validation source generator #87587

Merged
merged 13 commits into from
Jun 20, 2023
Merged
19 changes: 18 additions & 1 deletion docs/project/list-of-diagnostics.md
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,24 @@ The diagnostic id values reserved for .NET Libraries analyzer warnings are `SYSL
| __`SYSLIB1116`__ | *_`SYSLIB1100`-`SYSLIB1118` reserved for Microsoft.Extensions.Configuration.Binder.SourceGeneration.* |
| __`SYSLIB1117`__ | *_`SYSLIB1100`-`SYSLIB1118` reserved for Microsoft.Extensions.Configuration.Binder.SourceGeneration.* |
| __`SYSLIB1118`__ | *_`SYSLIB1100`-`SYSLIB1118` reserved for Microsoft.Extensions.Configuration.Binder.SourceGeneration.* |

| __`SYSLIB1201`__ | Options validation generator: Can't use 'ValidateObjectMembersAttribute' or `ValidateEnumeratedItemsAttribute` on fields or properties with open generic types. |
| __`SYSLIB1202`__ | Options validation generator: A member type has no fields or properties to validate. |
| __`SYSLIB1203`__ | Options validation generator: A type has no fields or properties to validate. |
| __`SYSLIB1204`__ | Options validation generator: A type annotated with `OptionsValidatorAttribute` doesn't implement the necessary interface. |
| __`SYSLIB1205`__ | Options validation generator: A type already includes an implementation of the 'Validate' method. |
| __`SYSLIB1206`__ | Options validation generator: Can't validate private fields or properties. |
| __`SYSLIB1207`__ | Options validation generator: Member type is not enumerable. |
| __`SYSLIB1208`__ | Options validation generator: Validators used for transitive or enumerable validation must have a constructor with no parameters. |
| __`SYSLIB1209`__ | Options validation generator: `OptionsValidatorAttribute` can't be applied to a static class. |
| __`SYSLIB1210`__ | Options validation generator: Null validator type specified for the `ValidateObjectMembersAttribute` or 'ValidateEnumeratedItemsAttribute' attributes. |
| __`SYSLIB1211`__ | Options validation generator: Unsupported circular references in model types. |
| __`SYSLIB1212`__ | Options validation generator: Member potentially missing transitive validation. |
| __`SYSLIB1213`__ | Options validation generator: Member potentially missing enumerable validation. |
| __`SYSLIB1214`__ | *_`SYSLIB1214`-`SYSLIB1218` reserved for Microsoft.Extensions.Options.SourceGeneration.* |
| __`SYSLIB1215`__ | *_`SYSLIB1214`-`SYSLIB1218` reserved for Microsoft.Extensions.Options.SourceGeneration.* |
| __`SYSLIB1216`__ | *_`SYSLIB1214`-`SYSLIB1218` reserved for Microsoft.Extensions.Options.SourceGeneration.* |
| __`SYSLIB1217`__ | *_`SYSLIB1214`-`SYSLIB1218` reserved for Microsoft.Extensions.Options.SourceGeneration.* |
| __`SYSLIB1218`__ | *_`SYSLIB1214`-`SYSLIB1218` reserved for Microsoft.Extensions.Options.SourceGeneration.* |

### Diagnostic Suppressions (`SYSLIBSUPPRESS****`)

Expand Down
40 changes: 40 additions & 0 deletions src/libraries/Common/src/System/ThrowHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,46 @@ internal static void ThrowIfNull(
[DoesNotReturn]
#endif
private static void Throw(string? paramName) => throw new ArgumentNullException(paramName);

/// <summary>
/// Throws either an <see cref="System.ArgumentNullException"/> or an <see cref="System.ArgumentException"/>
/// if the specified string is <see langword="null"/> or whitespace respectively.
/// </summary>
/// <param name="argument">String to be checked for <see langword="null"/> or whitespace.</param>
/// <param name="paramName">The name of the parameter being checked.</param>
/// <returns>The original value of <paramref name="argument"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
#if NETCOREAPP3_0_OR_GREATER
[return: NotNull]
#endif
public static string IfNullOrWhitespace(
#if NETCOREAPP3_0_OR_GREATER
[NotNull]
#endif
string? argument,
[CallerArgumentExpression(nameof(argument))] string paramName = "")
{
#if !NETCOREAPP3_1_OR_GREATER
if (argument == null)
{
throw new ArgumentNullException(paramName);
}
#endif

if (string.IsNullOrWhiteSpace(argument))
{
if (argument == null)
{
throw new ArgumentNullException(paramName);
}
else
{
throw new ArgumentException(paramName, "Argument is whitespace");
}
}

return argument;
}
}
}

Expand Down
95 changes: 95 additions & 0 deletions src/libraries/Microsoft.Extensions.Options/gen/DiagDescriptors.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.CodeAnalysis;
using System;

namespace Microsoft.Extensions.Options.Generators
{
internal sealed class DiagDescriptors : DiagDescriptorsBase
{
private const string Category = "Microsoft.Extensions.Options.SourceGeneration";

public static DiagnosticDescriptor CantUseWithGenericTypes { get; } = Make(
id: "SYSLIB1201",
tarekgh marked this conversation as resolved.
Show resolved Hide resolved
title: SR.CantUseWithGenericTypesTitle,
messageFormat: SR.CantUseWithGenericTypesMessage,
category: Category);

public static DiagnosticDescriptor NoEligibleMember { get; } = Make(
id: "SYSLIB1202",
title: SR.NoEligibleMemberTitle,
messageFormat: SR.NoEligibleMemberMessage,
category: Category,
defaultSeverity: DiagnosticSeverity.Warning);

public static DiagnosticDescriptor NoEligibleMembersFromValidator { get; } = Make(
id: "SYSLIB1203",
title: SR.NoEligibleMembersFromValidatorTitle,
messageFormat: SR.NoEligibleMembersFromValidatorMessage,
category: Category,
defaultSeverity: DiagnosticSeverity.Warning);

public static DiagnosticDescriptor DoesntImplementIValidateOptions { get; } = Make(
id: "SYSLIB1204",
title: SR.DoesntImplementIValidateOptionsTitle,
messageFormat: SR.DoesntImplementIValidateOptionsMessage,
category: Category);

public static DiagnosticDescriptor AlreadyImplementsValidateMethod { get; } = Make(
id: "SYSLIB1205",
title: SR.AlreadyImplementsValidateMethodTitle,
messageFormat: SR.AlreadyImplementsValidateMethodMessage,
category: Category);

public static DiagnosticDescriptor MemberIsInaccessible { get; } = Make(
id: "SYSLIB1206",
title: SR.MemberIsInaccessibleTitle,
messageFormat: SR.MemberIsInaccessibleMessage,
category: Category);

public static DiagnosticDescriptor NotEnumerableType { get; } = Make(
id: "SYSLIB1207",
title: SR.NotEnumerableTypeTitle,
messageFormat: SR.NotEnumerableTypeMessage,
category: Category);

public static DiagnosticDescriptor ValidatorsNeedSimpleConstructor { get; } = Make(
id: "SYSLIB1208",
title: SR.ValidatorsNeedSimpleConstructorTitle,
messageFormat: SR.ValidatorsNeedSimpleConstructorMessage,
category: Category);

public static DiagnosticDescriptor CantBeStaticClass { get; } = Make(
id: "SYSLIB1209",
title: SR.CantBeStaticClassTitle,
messageFormat: SR.CantBeStaticClassMessage,
category: Category);

public static DiagnosticDescriptor NullValidatorType { get; } = Make(
id: "SYSLIB1210",
title: SR.NullValidatorTypeTitle,
messageFormat: SR.NullValidatorTypeMessage,
category: Category);

public static DiagnosticDescriptor CircularTypeReferences { get; } = Make(
id: "SYSLIB1211",
title: SR.CircularTypeReferencesTitle,
messageFormat: SR.CircularTypeReferencesMessage,
category: Category);

public static DiagnosticDescriptor PotentiallyMissingTransitiveValidation { get; } = Make(
id: "SYSLIB1212",
title: SR.PotentiallyMissingTransitiveValidationTitle,
messageFormat: SR.PotentiallyMissingTransitiveValidationMessage,
category: Category,
defaultSeverity: DiagnosticSeverity.Warning);

public static DiagnosticDescriptor PotentiallyMissingEnumerableValidation { get; } = Make(
id: "SYSLIB1213",
title: SR.PotentiallyMissingEnumerableValidationTitle,
messageFormat: SR.PotentiallyMissingEnumerableValidationMessage,
category: Category,
defaultSeverity: DiagnosticSeverity.Warning);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using Microsoft.CodeAnalysis;

namespace Microsoft.Extensions.Options.Generators
{
#pragma warning disable CA1052 // Static holder types should be Static or NotInheritable
internal class DiagDescriptorsBase
#pragma warning restore CA1052
{
protected static DiagnosticDescriptor Make(
string id,
string title,
string messageFormat,
string category,
DiagnosticSeverity defaultSeverity = DiagnosticSeverity.Error,
bool isEnabledByDefault = true)
{
return new(
id,
title,
messageFormat,
category,
defaultSeverity,
isEnabledByDefault);
}
}
}
Loading