Skip to content

Commit

Permalink
Cleanup generator pipeline from leftover diagnostic reporting infrast…
Browse files Browse the repository at this point in the history
…ructure
  • Loading branch information
DoctorKrolic committed Mar 11, 2024
1 parent 92d640a commit 67eb993
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 162 deletions.
132 changes: 45 additions & 87 deletions src/ArgumentParsing.Generators/ArgumentParserGenerator.Extract.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using System.Diagnostics;
using ArgumentParsing.Generators.Extensions;
using ArgumentParsing.Generators.Models;
using ArgumentParsing.Generators.Utils;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;

Expand All @@ -12,44 +11,38 @@ public partial class ArgumentParserGenerator
{
private static readonly SymbolDisplayFormat s_qualifiedNameFormat = SymbolDisplayFormat.FullyQualifiedFormat.WithGlobalNamespaceStyle(SymbolDisplayGlobalNamespaceStyle.Omitted);

private static (ArgumentParserInfo? ArgumentParserInfo, OptionsHelpInfo? OptionsHelpInfo, ImmutableEquatableArray<DiagnosticInfo> Diagnostics) ExtractMainInfo(GeneratorAttributeSyntaxContext context, CancellationToken cancellationToken)
private static (ArgumentParserInfo? ArgumentParserInfo, OptionsHelpInfo? OptionsHelpInfo) ExtractMainInfo(GeneratorAttributeSyntaxContext context, CancellationToken cancellationToken)
{
var argumentParserMethodSyntax = (MethodDeclarationSyntax)context.TargetNode;
var argumentParserMethodSymbol = (IMethodSymbol)context.TargetSymbol;

var diagnosticsBuilder = ImmutableArray.CreateBuilder<DiagnosticInfo>();

SimpleParameterInfo? parameterInfo = null;
INamedTypeSymbol? validOptionsType = null;

var hasErrors = false;

if (argumentParserMethodSymbol.Parameters is not [var singleParameter])
{
hasErrors = true;
return default;
}
else
{
var singleParameterSyntax = argumentParserMethodSyntax.ParameterList.Parameters[0];

if (singleParameter.IsParams ||
singleParameter.RefKind != RefKind.None ||
singleParameter.ScopedKind != ScopedKind.None ||
argumentParserMethodSymbol.IsExtensionMethod)
{
hasErrors = true;
}
var singleParameterSyntax = argumentParserMethodSyntax.ParameterList.Parameters[0];

var singleParameterType = singleParameter.Type;
if (singleParameter.IsParams ||
singleParameter.RefKind != RefKind.None ||
singleParameter.ScopedKind != ScopedKind.None ||
argumentParserMethodSymbol.IsExtensionMethod)
{
return default;
}

if (!singleParameterType.IsEnumerableCollectionOfStrings())
{
hasErrors = true;
}
var singleParameterType = singleParameter.Type;

parameterInfo = new(singleParameterType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat), singleParameter.Name);
if (!singleParameterType.IsEnumerableCollectionOfStrings())
{
return default;
}

parameterInfo = new(singleParameterType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat), singleParameter.Name);

var returnTypeSyntax = argumentParserMethodSyntax.ReturnType;
var returnType = argumentParserMethodSymbol.ReturnType;

Expand All @@ -59,38 +52,25 @@ private static (ArgumentParserInfo? ArgumentParserInfo, OptionsHelpInfo? Options
if (returnType is not INamedTypeSymbol { TypeArguments: [var optionsType] } namedReturnType ||
!namedReturnType.ConstructedFrom.Equals(parseResultOfTType, SymbolEqualityComparer.Default))
{
hasErrors = true;
}
else
{
if (optionsType is not INamedTypeSymbol { SpecialType: SpecialType.None, TypeKind: TypeKind.Class or TypeKind.Struct } namedOptionsType || !namedOptionsType.Constructors.Any(c => c.Parameters.Length == 0))
{
hasErrors = true;
}
else
{
validOptionsType = namedOptionsType;
}
return default;
}

if (validOptionsType is null)
if (optionsType is not INamedTypeSymbol { SpecialType: SpecialType.None, TypeKind: TypeKind.Class or TypeKind.Struct } namedOptionsType || !namedOptionsType.Constructors.Any(c => c.Parameters.Length == 0))
{
return (null, null, diagnosticsBuilder.ToImmutable());
return default;
}

validOptionsType = namedOptionsType;

cancellationToken.ThrowIfCancellationRequested();

var (optionsInfo, optionsHelpInfo, optionsDiagnostics) = ExtractInfoFromOptionsType(validOptionsType, compilation, cancellationToken);
hasErrors |= optionsInfo is null;
diagnosticsBuilder.AddRange(optionsDiagnostics);
var (optionsInfo, optionsHelpInfo) = ExtractInfoFromOptionsType(validOptionsType, compilation, cancellationToken);

if (hasErrors)
if (optionsHelpInfo is null)
{
return (null, null, diagnosticsBuilder.ToImmutable());
return default;
}

Debug.Assert(parameterInfo is not null);

var methodInfo = new ArgumentParserMethodInfo(
argumentParserMethodSyntax.Modifiers.ToString(),
argumentParserMethodSymbol.ReturnType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat),
Expand All @@ -102,18 +82,14 @@ private static (ArgumentParserInfo? ArgumentParserInfo, OptionsHelpInfo? Options
methodInfo,
optionsInfo!);

return (argumentParserInfo, optionsHelpInfo, diagnosticsBuilder.ToImmutable());
return (argumentParserInfo, optionsHelpInfo);
}

private static (OptionsInfo? OptionsInfo, OptionsHelpInfo? OptionsHelpInfo, ImmutableArray<DiagnosticInfo> Diagnostics) ExtractInfoFromOptionsType(INamedTypeSymbol optionsType, Compilation compilation, CancellationToken cancellationToken)
private static (OptionsInfo? OptionsInfo, OptionsHelpInfo? OptionsHelpInfo) ExtractInfoFromOptionsType(INamedTypeSymbol optionsType, Compilation compilation, CancellationToken cancellationToken)
{
var optionsBuilder = ImmutableArray.CreateBuilder<OptionInfo>();
var optionsHelpBuilder = ImmutableArray.CreateBuilder<OptionHelpInfo>();

var diagnosticsBuilder = ImmutableArray.CreateBuilder<DiagnosticInfo>();

var hasErrors = false;

var seenShortNames = new HashSet<char>();
var seenLongNames = new HashSet<string>();

Expand All @@ -131,7 +107,7 @@ private static (OptionsInfo? OptionsInfo, OptionsHelpInfo? OptionsHelpInfo, Immu

if (member is IFieldSymbol { IsRequired: true })
{
hasErrors = true;
return default;
}

if (member is not IPropertySymbol property)
Expand Down Expand Up @@ -246,15 +222,15 @@ private static (OptionsInfo? OptionsInfo, OptionsHelpInfo? OptionsHelpInfo, Immu
{
if (property.IsRequired)
{
hasErrors = true;
return default;
}

continue;
}

if (property is not { DeclaredAccessibility: >= Accessibility.Internal, SetMethod.DeclaredAccessibility: >= Accessibility.Internal })
{
hasErrors = true;
return default;
}

var propertyName = property.Name;
Expand All @@ -267,13 +243,9 @@ private static (OptionsInfo? OptionsInfo, OptionsHelpInfo? OptionsHelpInfo, Immu
{
var snv = shortName.Value;

if (!char.IsLetter(snv))
{
hasErrors = true;
}
else if (!seenShortNames.Add(snv))
if (!char.IsLetter(snv) || !seenShortNames.Add(snv))
{
hasErrors = true;
return default;
}
}

Expand All @@ -284,32 +256,27 @@ private static (OptionsInfo? OptionsInfo, OptionsHelpInfo? OptionsHelpInfo, Immu

if (!shortName.HasValue && longName is null)
{
hasErrors = true;
return default;
}

if (longName is not null)
{
if (!char.IsLetter(longName[0]) || !longName.Replace("-", string.Empty).All(char.IsLetterOrDigit))
if (!char.IsLetter(longName[0]) || !longName.Replace("-", string.Empty).All(char.IsLetterOrDigit) || !seenLongNames.Add(longName))
{
hasErrors = true;
}
else if (!seenLongNames.Add(longName))
{
hasErrors = true;
return default;
}
}

var (parseStrategy, nullableUnderlyingType, sequenceType, sequenceUnderlyingType) = GetParseStrategyForOption(propertyType, compilation);

if (parseStrategy == ParseStrategy.None)
{
hasErrors = true;
continue;
return default;
}

if (isRequired && parseStrategy == ParseStrategy.Flag && nullableUnderlyingType is null)
{
hasErrors = true;
return default;
}

optionsBuilder.Add(new(
Expand All @@ -332,26 +299,22 @@ private static (OptionsInfo? OptionsInfo, OptionsHelpInfo? OptionsHelpInfo, Immu
{
var hasParameter = parameterMap.ContainsKey(parameterIndex);

if (parameterIndex < 0)
{
hasErrors = true;
}
else if (hasParameter)
if (parameterIndex < 0 || hasParameter)
{
hasErrors = true;
return default;
}

parameterName ??= propertyName.ToKebabCase();

if (!char.IsLetter(parameterName[0]) || !parameterName.Replace("-", string.Empty).All(char.IsLetterOrDigit))
{
hasErrors = true;
return default;
}

var (parseStrategy, nullableUnderlyingType) = GetParseStrategyForParameter(propertyType);
if (parseStrategy == ParseStrategy.None)
{
hasErrors = true;
return default;
}

if (!hasParameter)
Expand All @@ -375,15 +338,15 @@ private static (OptionsInfo? OptionsInfo, OptionsHelpInfo? OptionsHelpInfo, Immu

if (declaredRemainingParameters)
{
hasErrors = true;
return default;
}

declaredRemainingParameters = true;

var (parseStrategy, _, sequenceType, sequenceUnderlyingType) = GetParseStrategyForOption(propertyType, compilation);
if (parseStrategy == ParseStrategy.None || sequenceType == SequenceType.None)
{
hasErrors = true;
return default;
}

remainingParametersInfo = new(
Expand All @@ -406,7 +369,7 @@ private static (OptionsInfo? OptionsInfo, OptionsHelpInfo? OptionsHelpInfo, Immu

if (index > (lastSeenIndex + 1))
{
hasErrors = true;
return default;
}

var parameterInfo = pair.Value;
Expand All @@ -423,7 +386,7 @@ private static (OptionsInfo? OptionsInfo, OptionsHelpInfo? OptionsHelpInfo, Immu
{
if (!canNextParameterBeRequired)
{
hasErrors = true;
return default;
}
}
else
Expand All @@ -432,11 +395,6 @@ private static (OptionsInfo? OptionsInfo, OptionsHelpInfo? OptionsHelpInfo, Immu
}
}

if (hasErrors)
{
return (null, null, diagnosticsBuilder.ToImmutable());
}

var qualifiedName = optionsType.ToDisplayString(s_qualifiedNameFormat);
var optionsInfo = new OptionsInfo(
qualifiedName,
Expand All @@ -451,7 +409,7 @@ private static (OptionsInfo? OptionsInfo, OptionsHelpInfo? OptionsHelpInfo, Immu
parametersHelpBuilder.ToImmutable(),
remainingParametersHelpInfo);

return (optionsInfo, optionsHelpInfo, diagnosticsBuilder.ToImmutable());
return (optionsInfo, optionsHelpInfo);

static (ParseStrategy, string? NullableUnderlyingType, SequenceType, string? SequenceUnderlyingType) GetParseStrategyForOption(ITypeSymbol type, Compilation compilation)
{
Expand Down
12 changes: 2 additions & 10 deletions src/ArgumentParsing.Generators/ArgumentParserGenerator.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using ArgumentParsing.Generators.Extensions;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;

Expand All @@ -13,13 +12,8 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
.ForAttributeWithMetadataName(
"ArgumentParsing.GeneratedArgumentParserAttribute",
static (node, _) => node is MethodDeclarationSyntax,
ExtractMainInfo);

var diagnostics = extractedInfosProvider
.Where(info => !info.Diagnostics.IsDefaultOrEmpty)
.Select((info, _) => info.Diagnostics);

context.ReportDiagnostics(diagnostics);
ExtractMainInfo)
.Where(info => info != default);

var infoFromCompilation = context.CompilationProvider
.Select(ExtractInfoFromCompilation);
Expand All @@ -28,7 +22,6 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
.Select((info, _) => info.EnvironmentInfo);

var argumentParserInfos = extractedInfosProvider
.Where(info => info.ArgumentParserInfo is not null)
.Select((info, _) => info.ArgumentParserInfo!)
.Combine(environmentInfo);

Expand All @@ -38,7 +31,6 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
.Select((info, _) => info.AssemblyVersionInfo);

var optionsHelpInfos = extractedInfosProvider
.Where(info => info.OptionsHelpInfo is not null)
.Select((info, _) => info.OptionsHelpInfo!)
.Combine(assemblyVersionInfo);

Expand Down
19 changes: 0 additions & 19 deletions src/ArgumentParsing.Generators/Extensions/DiagnosticsExtension.cs

This file was deleted.

Loading

0 comments on commit 67eb993

Please sign in to comment.