Skip to content

Syntax node actions for partial constructors are not called for the defining part #86086

Description

@bjornhellander

Version Used: 5.9.0

Steps to Reproduce:

using System.Collections.Concurrent;
using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Diagnostics;

namespace PartialConstructorTestProject;

[TestClass]
public sealed class PartialConstructorTests
{
    [TestMethod]
    public async Task SyntaxNodeAction_IsCalledForBothPartsOfPartialConstructor()
    {
        var source = """
            public partial class C
            {
                public partial C(int x);
                public partial C(int x) { }
            }
            """;
        var compilation = CSharpCompilation.Create(
            "Test",
            [CSharpSyntaxTree.ParseText(source, new CSharpParseOptions(LanguageVersion.Default))],
            [MetadataReference.CreateFromFile(typeof(object).Assembly.Location)],
            new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
        Assert.IsEmpty(compilation.GetDiagnostics());

        var analyzer = new ConstructorRecordingAnalyzer();
        await compilation.WithAnalyzers([analyzer]).GetAnalyzerDiagnosticsAsync();
        Assert.AreEqual("3, 4", string.Join(", ", analyzer.VisitedLines.Order())); // Fails here with only 4
    }

    [DiagnosticAnalyzer(LanguageNames.CSharp)]
    private sealed class ConstructorRecordingAnalyzer : DiagnosticAnalyzer
    {
        private static readonly DiagnosticDescriptor Descriptor = new(
            "TEST0001", "Unused", "Unused", "Test", DiagnosticSeverity.Warning, isEnabledByDefault: true);

        public ConcurrentBag<int> VisitedLines { get; } = [];

        public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => [Descriptor];

        public override void Initialize(AnalysisContext context)
        {
            context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
            context.EnableConcurrentExecution();
            context.RegisterSyntaxNodeAction(HandleConstructor, SyntaxKind.ConstructorDeclaration);
        }

        private void HandleConstructor(SyntaxNodeAnalysisContext c)
        {
            VisitedLines.Add(c.Node.GetLocation().GetLineSpan().StartLinePosition.Line + 1);
        }
    }
}

Expected Behavior:

The registered action should be called for both parts.

Actual Behavior:

It is only called for the implementing part.

Activity

  1. bjornhellander commented on Oct 16, 2026

    @bjornhellander
    Author

    Nodes within the defining parts (like parameters) does not trigger a registered action either.

  2. changed the title [-]Syntax node actions for constructors are not called for the defining part[/-] [+]Syntax node actions for partial constructors are not called for the defining part[/+] on Oct 16, 2026
  3. self-assigned this
    on Oct 19, 2026
  4. added theissue type on Oct 19, 2026
  5. added this to the 18.13 milestone on Oct 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions