< Summary

Information
Class: NexusLabs.Needlr.Generators.GenerateConstructorSuggestionAnalyzer
Assembly: NexusLabs.Needlr.Generators
File(s): /home/runner/work/needlr/needlr/src/NexusLabs.Needlr.Generators/GenerateConstructorSuggestionAnalyzer.cs
Line coverage
93%
Covered lines: 371
Uncovered lines: 25
Coverable lines: 396
Total lines: 704
Line coverage: 93.6%
Branch coverage
84%
Covered branches: 246
Total branches: 291
Branch coverage: 84.5%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

/home/runner/work/needlr/needlr/src/NexusLabs.Needlr.Generators/GenerateConstructorSuggestionAnalyzer.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.Collections.Immutable;
 4using System.Linq;
 5
 6using Microsoft.CodeAnalysis;
 7using Microsoft.CodeAnalysis.CSharp;
 8using Microsoft.CodeAnalysis.CSharp.Syntax;
 9using Microsoft.CodeAnalysis.Diagnostics;
 10
 11using NexusLabs.Needlr.Generators.Models;
 12using NexusLabs.Needlr.Roslyn.Shared;
 13
 14namespace NexusLabs.Needlr.Generators;
 15
 16/// <summary>
 17/// Suggests Needlr-generated constructors only when an authored constructor is
 18/// mechanically equivalent to the generator's supported parameter, guard, and
 19/// field-assignment model.
 20/// </summary>
 21[DiagnosticAnalyzer(LanguageNames.CSharp)]
 22public sealed class GenerateConstructorSuggestionAnalyzer : DiagnosticAnalyzer
 23{
 24    private const string ConstructorGuardAttributeName = "ConstructorGuardAttribute";
 25    private const string ConstructorGuardDefinitionAttributeName = "ConstructorGuardDefinitionAttribute";
 26    private const string ConstructorIgnoreAttributeName = "ConstructorIgnoreAttribute";
 27    private const string DeferToContainerAttributeName = "DeferToContainerAttribute";
 28    private const string RecordConstructorOverloadParameterAttributeName = "RecordConstructorOverloadParameterAttribute"
 29
 30    /// <summary>
 31    /// Gets the diagnostics produced by this analyzer.
 32    /// </summary>
 33    public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics =>
 41434        ImmutableArray.Create(DiagnosticDescriptors.GenerateConstructorSuggested);
 35
 36    /// <summary>
 37    /// Registers symbol analysis for named types.
 38    /// </summary>
 39    /// <param name="context">The analyzer initialization context.</param>
 40    public override void Initialize(AnalysisContext context)
 41    {
 6642        context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
 6643        context.EnableConcurrentExecution();
 6644        context.RegisterSyntaxNodeAction(
 6645            AnalyzeClassDeclaration,
 6646            SyntaxKind.ClassDeclaration);
 6647    }
 48
 49    private static void AnalyzeClassDeclaration(SyntaxNodeAnalysisContext context)
 50    {
 61651        var classDeclaration = (ClassDeclarationSyntax)context.Node;
 61652        if (context.SemanticModel.GetDeclaredSymbol(
 61653                classDeclaration,
 61654                context.CancellationToken) is not
 61655            INamedTypeSymbol typeSymbol)
 56        {
 057            return;
 58        }
 59
 61660        if (!IsSupportedType(typeSymbol) ||
 61661            HasExistingConstructorGenerationConfiguration(typeSymbol) ||
 61662            HasDeferToContainerAttribute(typeSymbol) ||
 61663            RequiresParameterlessActivation(typeSymbol))
 64        {
 565            return;
 66        }
 67
 61168        if (typeSymbol.BaseType is not null &&
 61169            typeSymbol.BaseType.SpecialType != SpecialType.System_Object &&
 61170            !GeneratedConstructorEligibility.HasAccessibleParameterlessConstructor(typeSymbol.BaseType))
 71        {
 172            return;
 73        }
 74
 61075        var constructors = typeSymbol.InstanceConstructors
 71976            .Where(constructor => !constructor.IsImplicitlyDeclared)
 61077            .ToArray();
 61078        if (constructors.Length != 1)
 47379            return;
 80
 13781        var constructor = constructors[0];
 13782        if (constructor.DeclaredAccessibility != Accessibility.Public ||
 13783            constructor.GetAttributes().Length != 0 ||
 13784            constructor.Parameters.Any(IsUnsupportedParameter))
 85        {
 786            return;
 87        }
 88
 13089        var constructorSyntax = classDeclaration.Members
 13090            .OfType<ConstructorDeclarationSyntax>()
 13091            .SingleOrDefault(declaration =>
 25192                SymbolEqualityComparer.Default.Equals(
 25193                    context.SemanticModel.GetDeclaredSymbol(
 25194                        declaration,
 25195                        context.CancellationToken),
 25196                    constructor));
 13097        if (constructorSyntax is not null)
 98        {
 12199            if (IsGeneratedSyntax(constructorSyntax) ||
 121100                !MatchesOrdinaryConstructor(
 121101                    context,
 121102                    typeSymbol,
 121103                    constructor,
 121104                    constructorSyntax))
 105            {
 113106                return;
 107            }
 108
 8109            context.ReportDiagnostic(Diagnostic.Create(
 8110                DiagnosticDescriptors.GenerateConstructorSuggested,
 8111                constructorSyntax.Identifier.GetLocation(),
 8112                typeSymbol.Name));
 8113            return;
 114        }
 115
 9116        if (classDeclaration.ParameterList is null ||
 9117            typeSymbol.DeclaringSyntaxReferences.Length != 1 ||
 9118            IsGeneratedSyntax(classDeclaration) ||
 9119            !MatchesPrimaryConstructor(
 9120                context,
 9121                typeSymbol,
 9122                constructor,
 9123                classDeclaration))
 124        {
 5125            return;
 126        }
 127
 4128        context.ReportDiagnostic(Diagnostic.Create(
 4129            DiagnosticDescriptors.GenerateConstructorSuggested,
 4130            classDeclaration.Identifier.GetLocation(),
 4131            typeSymbol.Name));
 4132    }
 133
 134    private static bool IsSupportedType(INamedTypeSymbol typeSymbol)
 135    {
 616136        return typeSymbol.TypeKind == TypeKind.Class &&
 616137            !typeSymbol.IsRecord &&
 616138            !typeSymbol.IsFileLocal &&
 616139            typeSymbol.ContainingType is null;
 140    }
 141
 142    private static bool HasExistingConstructorGenerationConfiguration(
 143        INamedTypeSymbol typeSymbol)
 144    {
 615145        if (GeneratedConstructorEligibility.HasGenerateConstructorAttribute(typeSymbol))
 1146            return true;
 147
 6945148        foreach (var member in typeSymbol.GetMembers())
 149        {
 5721150            foreach (var attribute in member.GetAttributes())
 151            {
 2152                var attributeClass = attribute.AttributeClass;
 2153                if (attributeClass is null)
 154                    continue;
 155
 2156                if (GeneratedConstructorEligibility.IsNeedlrGeneratorsAttribute(
 2157                        attributeClass,
 2158                        ConstructorGuardAttributeName) ||
 2159                    GeneratedConstructorEligibility.IsNeedlrGeneratorsAttribute(
 2160                        attributeClass,
 2161                        ConstructorIgnoreAttributeName) ||
 2162                    GeneratedConstructorEligibility.IsNeedlrGeneratorsAttribute(
 2163                        attributeClass,
 2164                        RecordConstructorOverloadParameterAttributeName) ||
 2165                    IsConstructorGuardAlias(attributeClass))
 166                {
 1167                    return true;
 168                }
 169            }
 170        }
 171
 613172        return false;
 173    }
 174
 175    private static bool IsConstructorGuardAlias(INamedTypeSymbol attributeClass)
 176    {
 1177        return attributeClass.GetAttributes().Any(attribute =>
 2178            attribute.AttributeClass is { } metaAttributeClass &&
 2179            GeneratedConstructorEligibility.IsNeedlrGeneratorsAttribute(
 2180                metaAttributeClass,
 2181                ConstructorGuardDefinitionAttributeName));
 182    }
 183
 184    private static bool HasDeferToContainerAttribute(INamedTypeSymbol typeSymbol)
 185    {
 613186        return typeSymbol.GetAttributes().Any(attribute =>
 1121187            attribute.AttributeClass is { } attributeClass &&
 1121188            attributeClass.Name == DeferToContainerAttributeName &&
 1121189            attributeClass.ContainingNamespace?.ToDisplayString() ==
 1121190                "NexusLabs.Needlr");
 191    }
 192
 193    private static bool RequiresParameterlessActivation(INamedTypeSymbol typeSymbol)
 194    {
 612195        return typeSymbol.AllInterfaces.Any(interfaceSymbol =>
 612196        {
 37197            var namespaceName =
 37198                interfaceSymbol.ContainingNamespace?.ToDisplayString();
 37199            if (namespaceName == "NexusLabs.Needlr")
 612200            {
 37201                return interfaceSymbol.Name is
 37202                    "IServiceCollectionPlugin" or
 37203                    "IPostBuildServiceCollectionPlugin" or
 37204                    "IWebApplicationBuilderPlugin" or
 37205                    "IHostApplicationBuilderPlugin";
 612206            }
 612207
 0208            return namespaceName == "NexusLabs.Needlr.SignalR" &&
 0209                interfaceSymbol.Name == "IHubRegistrationPlugin";
 612210        });
 211    }
 212
 213    private static bool IsUnsupportedParameter(IParameterSymbol parameter)
 214    {
 251215        return parameter.RefKind != RefKind.None ||
 251216            parameter.IsParams ||
 251217            parameter.HasExplicitDefaultValue ||
 251218            parameter.GetAttributes().Length != 0 ||
 251219            ContainsPointerType(parameter.Type);
 220    }
 221
 222    private static bool MatchesOrdinaryConstructor(
 223        SyntaxNodeAnalysisContext context,
 224        INamedTypeSymbol typeSymbol,
 225        IMethodSymbol constructor,
 226        ConstructorDeclarationSyntax constructorSyntax)
 227    {
 121228        if (constructorSyntax.Initializer is not null ||
 121229            constructorSyntax.Body is null ||
 121230            constructorSyntax.ExpressionBody is not null)
 231        {
 72232            return false;
 233        }
 234
 49235        var fields =
 49236            GeneratedConstructorEligibility.GetEligibleConstructorFields(
 49237                typeSymbol);
 49238        if (fields.Count == 0 || fields.Count != constructor.Parameters.Length)
 37239            return false;
 240
 52241        for (var i = 0; i < fields.Count; i++)
 242        {
 15243            if (!MatchesParameter(fields[i], constructor.Parameters[i]))
 1244                return false;
 245        }
 246
 11247        var semanticModel = context.SemanticModel;
 11248        var statements = constructorSyntax.Body.Statements;
 11249        var guards = new GeneratedConstructorGuardKind[fields.Count];
 11250        var statementIndex = 0;
 251
 50252        for (var i = 0; i < fields.Count; i++)
 253        {
 14254            if (statementIndex >= statements.Count ||
 14255                !TryMatchGuardStatement(
 14256                    semanticModel.Compilation,
 14257                    semanticModel,
 14258                    statements[statementIndex],
 14259                    constructor.Parameters[i],
 14260                    fields[i].Type,
 14261                    out var guard))
 262            {
 263                continue;
 264            }
 265
 7266            guards[i] = guard;
 7267            statementIndex++;
 268        }
 269
 44270        for (var i = 0; i < fields.Count; i++)
 271        {
 14272            if (statementIndex >= statements.Count ||
 14273                !MatchesAssignmentStatement(
 14274                    semanticModel,
 14275                    statements[statementIndex],
 14276                    fields[i],
 14277                    constructor.Parameters[i]))
 278            {
 3279                return false;
 280            }
 281
 11282            statementIndex++;
 283        }
 284
 8285        return statementIndex == statements.Count &&
 8286            GuardsCanBeGenerated(fields, guards);
 287    }
 288
 289    private static bool MatchesPrimaryConstructor(
 290        SyntaxNodeAnalysisContext context,
 291        INamedTypeSymbol typeSymbol,
 292        IMethodSymbol constructor,
 293        ClassDeclarationSyntax primaryDeclaration)
 294    {
 9295        if (primaryDeclaration.ParameterList is null ||
 9296            primaryDeclaration.BaseList?.Types
 9297                .OfType<PrimaryConstructorBaseTypeSyntax>()
 0298                .Any(baseType => baseType.ArgumentList.Arguments.Count > 0) ==
 9299                    true)
 300        {
 0301            return false;
 302        }
 303
 9304        var fields = GeneratedConstructorEligibility
 9305            .GetOrderedInstanceFields(typeSymbol)
 9306            .Where(field =>
 14307                field.DeclaredAccessibility == Accessibility.Private &&
 14308                field.IsReadOnly)
 9309            .ToArray();
 9310        if (fields.Length == 0 || fields.Length != constructor.Parameters.Length)
 1311            return false;
 312
 8313        var initializers = new ExpressionSyntax[fields.Length];
 8314        var guards = new GeneratedConstructorGuardKind[fields.Length];
 38315        for (var i = 0; i < fields.Length; i++)
 316        {
 12317            if (!MatchesParameter(fields[i], constructor.Parameters[i]) ||
 12318                !TryGetFieldInitializer(
 12319                    fields[i],
 12320                    context.CancellationToken,
 12321                    out var initializer) ||
 12322                initializer.SyntaxTree != primaryDeclaration.SyntaxTree ||
 12323                !TryMatchPrimaryInitializer(
 12324                    context.SemanticModel.Compilation,
 12325                    context.SemanticModel,
 12326                    initializer,
 12327                    constructor.Parameters[i],
 12328                    fields[i].Type,
 12329                    out guards[i]))
 330            {
 1331                return false;
 332            }
 333
 11334            initializers[i] = initializer;
 335        }
 336
 7337        var guardedCount = guards.Count(
 17338            guard => guard != GeneratedConstructorGuardKind.None);
 7339        if (guardedCount > 0 && fields.Length > 1)
 1340            return false;
 341
 6342        if (HasOtherInstanceInitializer(
 6343                context,
 6344                primaryDeclaration,
 6345                fields) ||
 6346            HasPrimaryParameterReferenceOutsideInitializers(
 6347                context,
 6348                primaryDeclaration,
 6349                constructor.Parameters,
 6350                initializers))
 351        {
 2352            return false;
 353        }
 354
 4355        return GuardsCanBeGenerated(fields, guards);
 356    }
 357
 358    private static bool MatchesParameter(
 359        IFieldSymbol field,
 360        IParameterSymbol parameter)
 361    {
 27362        var parameterName =
 27363            ConstructorGenerationDiscoveryHelper.GetParameterName(field.Name);
 27364        if (parameterName.Length > 0 && parameterName[0] == '@')
 0365            parameterName = parameterName.Substring(1);
 366
 27367        return parameter.Name == parameterName &&
 27368            field.Type.ToDisplayString(
 27369                ConstructorGenerationDiscoveryHelper.NullableAwareFormat) ==
 27370            parameter.Type.ToDisplayString(
 27371                ConstructorGenerationDiscoveryHelper.NullableAwareFormat);
 372    }
 373
 374    private static bool TryMatchGuardStatement(
 375        Compilation compilation,
 376        SemanticModel semanticModel,
 377        StatementSyntax statement,
 378        IParameterSymbol parameter,
 379        ITypeSymbol fieldType,
 380        out GeneratedConstructorGuardKind guard)
 381    {
 14382        guard = GeneratedConstructorGuardKind.None;
 14383        if (statement is not ExpressionStatementSyntax
 14384            {
 14385                Expression: InvocationExpressionSyntax invocation,
 14386            } ||
 14387            invocation.ArgumentList.Arguments.Count != 1 ||
 14388            !ReferencesSymbol(
 14389                semanticModel,
 14390                invocation.ArgumentList.Arguments[0].Expression,
 14391                parameter))
 392        {
 6393            return false;
 394        }
 395
 8396        if (semanticModel.GetSymbolInfo(invocation).Symbol is not
 8397            IMethodSymbol { IsStatic: true } method)
 398        {
 0399            return false;
 400        }
 401
 8402        var argumentNullException =
 8403            compilation.GetTypeByMetadataName(
 8404                "System.ArgumentNullException");
 8405        var argumentException =
 8406            compilation.GetTypeByMetadataName("System.ArgumentException");
 407
 8408        if (method.Name == "ThrowIfNull" &&
 8409            SymbolEqualityComparer.Default.Equals(
 8410                method.ContainingType,
 8411                argumentNullException))
 412        {
 4413            guard = GeneratedConstructorGuardKind.NotNull;
 414        }
 4415        else if (method.Name == "ThrowIfNullOrEmpty" &&
 4416            SymbolEqualityComparer.Default.Equals(
 4417                method.ContainingType,
 4418                argumentException))
 419        {
 2420            guard = GeneratedConstructorGuardKind.NotNullOrEmpty;
 421        }
 2422        else if (method.Name == "ThrowIfNullOrWhiteSpace" &&
 2423            SymbolEqualityComparer.Default.Equals(
 2424                method.ContainingType,
 2425                argumentException))
 426        {
 2427            guard = GeneratedConstructorGuardKind.NotNullOrWhiteSpace;
 428        }
 429        else
 430        {
 0431            return false;
 432        }
 433
 8434        return IsGuardCompatible(fieldType, guard);
 435    }
 436
 437    private static bool MatchesAssignmentStatement(
 438        SemanticModel semanticModel,
 439        StatementSyntax statement,
 440        IFieldSymbol field,
 441        IParameterSymbol parameter)
 442    {
 14443        return statement is ExpressionStatementSyntax
 14444            {
 14445                Expression: AssignmentExpressionSyntax assignment,
 14446            } &&
 14447            assignment.IsKind(SyntaxKind.SimpleAssignmentExpression) &&
 14448            ReferencesSymbol(semanticModel, assignment.Left, field) &&
 14449            ReferencesSymbol(semanticModel, assignment.Right, parameter);
 450    }
 451
 452    private static bool TryMatchPrimaryInitializer(
 453        Compilation compilation,
 454        SemanticModel semanticModel,
 455        ExpressionSyntax initializer,
 456        IParameterSymbol parameter,
 457        ITypeSymbol fieldType,
 458        out GeneratedConstructorGuardKind guard)
 459    {
 12460        guard = GeneratedConstructorGuardKind.None;
 12461        if (ReferencesSymbol(semanticModel, initializer, parameter))
 6462            return true;
 463
 6464        if (initializer is not BinaryExpressionSyntax
 6465            {
 6466                RawKind: (int)SyntaxKind.CoalesceExpression,
 6467                Right: ThrowExpressionSyntax
 6468                {
 6469                    Expression: ObjectCreationExpressionSyntax creation,
 6470                },
 6471            } coalesce ||
 6472            !ReferencesSymbol(semanticModel, coalesce.Left, parameter) ||
 6473            creation.Initializer is not null ||
 6474            creation.ArgumentList?.Arguments.Count != 1)
 475        {
 1476            return false;
 477        }
 478
 5479        var argumentNullException =
 5480            compilation.GetTypeByMetadataName(
 5481                "System.ArgumentNullException");
 5482        if (!SymbolEqualityComparer.Default.Equals(
 5483                semanticModel.GetTypeInfo(creation).Type,
 5484                argumentNullException) ||
 5485            creation.ArgumentList.Arguments[0].Expression is not
 5486                InvocationExpressionSyntax
 5487                {
 5488                    Expression: IdentifierNameSyntax nameofIdentifier,
 5489                    ArgumentList.Arguments.Count: 1,
 5490                } nameofInvocation ||
 5491            nameofIdentifier.Identifier.ValueText != "nameof" ||
 5492            !ReferencesSymbol(
 5493                semanticModel,
 5494                nameofInvocation.ArgumentList.Arguments[0].Expression,
 5495                parameter))
 496        {
 0497            return false;
 498        }
 499
 5500        guard = GeneratedConstructorGuardKind.NotNull;
 5501        return IsGuardCompatible(fieldType, guard);
 502    }
 503
 504    private static bool HasOtherInstanceInitializer(
 505        SyntaxNodeAnalysisContext context,
 506        ClassDeclarationSyntax declaration,
 507        IReadOnlyList<IFieldSymbol> captureFields)
 508    {
 6509        var captures = new HashSet<IFieldSymbol>(
 6510            captureFields,
 6511            SymbolEqualityComparer.Default);
 512
 31513        foreach (var member in declaration.Members)
 514        {
 10515            if (member is FieldDeclarationSyntax fieldDeclaration)
 516            {
 32517                foreach (var variable in fieldDeclaration.Declaration.Variables)
 518                {
 8519                    if (variable.Initializer is null ||
 8520                        context.SemanticModel.GetDeclaredSymbol(
 8521                            variable,
 8522                            context.CancellationToken) is not
 8523                            IFieldSymbol field ||
 8524                        field.IsStatic ||
 8525                        captures.Contains(field))
 526                    {
 527                        continue;
 528                    }
 529
 0530                    return true;
 531                }
 532            }
 2533            else if (member is PropertyDeclarationSyntax
 2534                {
 2535                    Initializer: not null,
 2536                } propertyDeclaration &&
 2537                context.SemanticModel.GetDeclaredSymbol(
 2538                    propertyDeclaration,
 2539                    context.CancellationToken) is
 2540                    IPropertySymbol { IsStatic: false })
 541            {
 1542                return true;
 543            }
 1544            else if (member is EventFieldDeclarationSyntax
 1545                eventFieldDeclaration)
 546            {
 0547                foreach (var variable in
 0548                    eventFieldDeclaration.Declaration.Variables)
 549                {
 0550                    if (variable.Initializer is not null &&
 0551                        context.SemanticModel.GetDeclaredSymbol(
 0552                            variable,
 0553                            context.CancellationToken) is
 0554                            IEventSymbol { IsStatic: false })
 555                    {
 0556                        return true;
 557                    }
 558                }
 559            }
 560        }
 561
 5562        return false;
 563    }
 564
 565    private static bool HasPrimaryParameterReferenceOutsideInitializers(
 566        SyntaxNodeAnalysisContext context,
 567        ClassDeclarationSyntax declaration,
 568        ImmutableArray<IParameterSymbol> parameters,
 569        IReadOnlyList<ExpressionSyntax> initializers)
 570    {
 66571        foreach (var identifier in
 5572            declaration.DescendantNodes().OfType<IdentifierNameSyntax>())
 573        {
 31574            if (context.SemanticModel.GetSymbolInfo(
 31575                    identifier,
 31576                    context.CancellationToken).Symbol is not
 31577                IParameterSymbol referencedParameter)
 578            {
 579                continue;
 580            }
 581
 10582            var parameterIndex = IndexOfParameter(
 10583                parameters,
 10584                referencedParameter);
 10585            if (parameterIndex < 0)
 586                continue;
 587
 10588            var allowedInitializer = initializers[parameterIndex];
 10589            if (!allowedInitializer.Span.Contains(identifier.Span))
 1590                return true;
 591        }
 592
 4593        return false;
 1594    }
 595
 596    private static int IndexOfParameter(
 597        ImmutableArray<IParameterSymbol> parameters,
 598        IParameterSymbol candidate)
 599    {
 24600        for (var i = 0; i < parameters.Length; i++)
 601        {
 12602            if (SymbolEqualityComparer.Default.Equals(parameters[i], candidate))
 10603                return i;
 604        }
 605
 0606        return -1;
 607    }
 608
 609    private static bool TryGetFieldInitializer(
 610        IFieldSymbol field,
 611        System.Threading.CancellationToken cancellationToken,
 612        out ExpressionSyntax initializer)
 613    {
 36614        foreach (var syntaxReference in field.DeclaringSyntaxReferences)
 615        {
 12616            if (syntaxReference.GetSyntax(cancellationToken) is
 12617                VariableDeclaratorSyntax
 12618                {
 12619                    Initializer.Value: { } value,
 12620                })
 621            {
 12622                initializer = value;
 12623                return true;
 624            }
 625        }
 626
 0627        initializer = null!;
 0628        return false;
 629    }
 630
 631    private static bool GuardsCanBeGenerated(
 632        IReadOnlyList<IFieldSymbol> fields,
 633        IReadOnlyList<GeneratedConstructorGuardKind> guards)
 634    {
 56635        for (var i = 0; i < fields.Count; i++)
 636        {
 16637            if (!IsGuardCompatible(fields[i].Type, guards[i]))
 0638                return false;
 639        }
 640
 12641        return true;
 642    }
 643
 644    private static bool IsGuardCompatible(
 645        ITypeSymbol fieldType,
 646        GeneratedConstructorGuardKind guard)
 647    {
 29648        return guard switch
 29649        {
 8650            GeneratedConstructorGuardKind.None => true,
 29651            GeneratedConstructorGuardKind.NotNull =>
 13652                ConstructorGuardAnalysisHelper.CanBeRuntimeNull(fieldType),
 29653            GeneratedConstructorGuardKind.NotNullOrEmpty or
 29654            GeneratedConstructorGuardKind.NotNullOrWhiteSpace =>
 8655                fieldType.SpecialType == SpecialType.System_String,
 0656            _ => false,
 29657        };
 658    }
 659
 660    private static bool ReferencesSymbol(
 661        SemanticModel semanticModel,
 662        ExpressionSyntax expression,
 663        ISymbol symbol)
 664    {
 54665        return SymbolEqualityComparer.Default.Equals(
 54666            semanticModel.GetSymbolInfo(expression).Symbol,
 54667            symbol);
 668    }
 669
 670    private static bool ContainsPointerType(ITypeSymbol type)
 671    {
 283672        return type switch
 283673        {
 1674            IPointerTypeSymbol => true,
 0675            IFunctionPointerTypeSymbol => true,
 283676            IArrayTypeSymbol arrayType =>
 36677                ContainsPointerType(arrayType.ElementType),
 246678            _ => false,
 283679        };
 680    }
 681
 682    private static bool IsGeneratedSyntax(SyntaxNode syntax)
 683    {
 130684        var filePath = syntax.SyntaxTree.FilePath;
 130685        if (filePath.EndsWith(".g.cs", StringComparison.OrdinalIgnoreCase) ||
 130686            filePath.EndsWith(
 130687                ".generated.cs",
 130688                StringComparison.OrdinalIgnoreCase) ||
 130689            filePath.EndsWith(
 130690                ".designer.cs",
 130691                StringComparison.OrdinalIgnoreCase))
 692        {
 0693            return true;
 694        }
 695
 130696        var leadingText = syntax.SyntaxTree
 130697            .GetRoot()
 130698            .GetLeadingTrivia()
 130699            .ToFullString();
 130700        return leadingText.IndexOf(
 130701            "<auto-generated",
 130702            StringComparison.OrdinalIgnoreCase) >= 0;
 703    }
 704}

Methods/Properties

get_SupportedDiagnostics()
Initialize(Microsoft.CodeAnalysis.Diagnostics.AnalysisContext)
AnalyzeClassDeclaration(Microsoft.CodeAnalysis.Diagnostics.SyntaxNodeAnalysisContext)
IsSupportedType(Microsoft.CodeAnalysis.INamedTypeSymbol)
HasExistingConstructorGenerationConfiguration(Microsoft.CodeAnalysis.INamedTypeSymbol)
IsConstructorGuardAlias(Microsoft.CodeAnalysis.INamedTypeSymbol)
HasDeferToContainerAttribute(Microsoft.CodeAnalysis.INamedTypeSymbol)
RequiresParameterlessActivation(Microsoft.CodeAnalysis.INamedTypeSymbol)
IsUnsupportedParameter(Microsoft.CodeAnalysis.IParameterSymbol)
MatchesOrdinaryConstructor(Microsoft.CodeAnalysis.Diagnostics.SyntaxNodeAnalysisContext,Microsoft.CodeAnalysis.INamedTypeSymbol,Microsoft.CodeAnalysis.IMethodSymbol,Microsoft.CodeAnalysis.CSharp.Syntax.ConstructorDeclarationSyntax)
MatchesPrimaryConstructor(Microsoft.CodeAnalysis.Diagnostics.SyntaxNodeAnalysisContext,Microsoft.CodeAnalysis.INamedTypeSymbol,Microsoft.CodeAnalysis.IMethodSymbol,Microsoft.CodeAnalysis.CSharp.Syntax.ClassDeclarationSyntax)
MatchesParameter(Microsoft.CodeAnalysis.IFieldSymbol,Microsoft.CodeAnalysis.IParameterSymbol)
TryMatchGuardStatement(Microsoft.CodeAnalysis.Compilation,Microsoft.CodeAnalysis.SemanticModel,Microsoft.CodeAnalysis.CSharp.Syntax.StatementSyntax,Microsoft.CodeAnalysis.IParameterSymbol,Microsoft.CodeAnalysis.ITypeSymbol,NexusLabs.Needlr.Generators.Models.GeneratedConstructorGuardKind&)
MatchesAssignmentStatement(Microsoft.CodeAnalysis.SemanticModel,Microsoft.CodeAnalysis.CSharp.Syntax.StatementSyntax,Microsoft.CodeAnalysis.IFieldSymbol,Microsoft.CodeAnalysis.IParameterSymbol)
TryMatchPrimaryInitializer(Microsoft.CodeAnalysis.Compilation,Microsoft.CodeAnalysis.SemanticModel,Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax,Microsoft.CodeAnalysis.IParameterSymbol,Microsoft.CodeAnalysis.ITypeSymbol,NexusLabs.Needlr.Generators.Models.GeneratedConstructorGuardKind&)
HasOtherInstanceInitializer(Microsoft.CodeAnalysis.Diagnostics.SyntaxNodeAnalysisContext,Microsoft.CodeAnalysis.CSharp.Syntax.ClassDeclarationSyntax,System.Collections.Generic.IReadOnlyList`1<Microsoft.CodeAnalysis.IFieldSymbol>)
HasPrimaryParameterReferenceOutsideInitializers(Microsoft.CodeAnalysis.Diagnostics.SyntaxNodeAnalysisContext,Microsoft.CodeAnalysis.CSharp.Syntax.ClassDeclarationSyntax,System.Collections.Immutable.ImmutableArray`1<Microsoft.CodeAnalysis.IParameterSymbol>,System.Collections.Generic.IReadOnlyList`1<Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax>)
IndexOfParameter(System.Collections.Immutable.ImmutableArray`1<Microsoft.CodeAnalysis.IParameterSymbol>,Microsoft.CodeAnalysis.IParameterSymbol)
TryGetFieldInitializer(Microsoft.CodeAnalysis.IFieldSymbol,System.Threading.CancellationToken,Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax&)
GuardsCanBeGenerated(System.Collections.Generic.IReadOnlyList`1<Microsoft.CodeAnalysis.IFieldSymbol>,System.Collections.Generic.IReadOnlyList`1<NexusLabs.Needlr.Generators.Models.GeneratedConstructorGuardKind>)
IsGuardCompatible(Microsoft.CodeAnalysis.ITypeSymbol,NexusLabs.Needlr.Generators.Models.GeneratedConstructorGuardKind)
ReferencesSymbol(Microsoft.CodeAnalysis.SemanticModel,Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax,Microsoft.CodeAnalysis.ISymbol)
ContainsPointerType(Microsoft.CodeAnalysis.ITypeSymbol)
IsGeneratedSyntax(Microsoft.CodeAnalysis.SyntaxNode)