Skip to content

Commit

Permalink
Options validation source generator (#87587)
Browse files Browse the repository at this point in the history
  • Loading branch information
tarekgh authored Jun 20, 2023
1 parent 7f4334e commit de6f07e
Show file tree
Hide file tree
Showing 78 changed files with 12,224 additions and 1 deletion.
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",
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

0 comments on commit de6f07e

Please sign in to comment.