AL icon indicating copy to clipboard operation
AL copied to clipboard

System.NullReferenceException on GetSymbolInfo with a custom Code Analyzer

Open Arthurvdv opened this issue 10 months ago • 0 comments

I'm unsure if this scenario is supported, as the issue occurs with a custom code analyzer and I haven't encountered it with any of the Microsoft-provided analyzers. Nevertheless, I wanted to report it here, hoping that it might be a low-hanging fruit issue and could lead to a small improvement in the CodeAnalysis library.

1. Describe the bug The 'GetSymbolInfo' method of the Microsoft.Dynamics.Nav.CodeAnalysis.dll throws an NullReferenceException on the case of pragma directives on the example file.

2. To Reproduce I've provided a small as possible code snippet which should raise this exception.

using Microsoft.Dynamics.Nav.CodeAnalysis;
using Microsoft.Dynamics.Nav.CodeAnalysis.Diagnostics;
using System.Collections.Immutable;

namespace BusinessCentral.CustomCodeAnalyzer;

[DiagnosticAnalyzer]
public class MyDiagnosticAnalyzer : DiagnosticAnalyzer
{
    public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; }
        = ImmutableArray.Create(DiagnosticDescriptors.MyDiagnosticAnalyzer);

    public override void Initialize(AnalysisContext context) =>
        context.RegisterSyntaxNodeAction(new Action<SyntaxNodeAnalysisContext>(this.AnalyzeNode), SyntaxKind.IdentifierName);

    private void AnalyzeNode(SyntaxNodeAnalysisContext ctx)
    {
        var symbolInfo = ctx.SemanticModel.GetSymbolInfo(ctx.Node, ctx.CancellationToken); // This line causes an System.NullReferenceException 
    }
}
report 50000 "My Report"
{
    dataset
    {
        dataitem(Integer; Integer)
        {
#pragma warning disable AL0432
            column(ContactHomePage; Contact."Home Page") { }
#pragma warning restore AL0432
        }
    }

    var
        Contact: Record Contact;
}
Analyzer 'MyCustomCodeAnalyzer.MyDiagnosticAnalyzer' threw an exception of type 'System.NullReferenceException' with message 'System.NullReferenceException: Object reference not set to an instance of an object.
   at Microsoft.Dynamics.Nav.CodeAnalysis.BinderFactory.BinderFactoryVisitor.VisitCore(SyntaxNode node) in X:\Prod\Microsoft.Dynamics.Nav.CodeAnalysis\Binder\BinderFactory.cs:line 327
   at Microsoft.Dynamics.Nav.CodeAnalysis.SyntaxVisitor`1.VisitPragmaWarningDirectiveTrivia(PragmaWarningDirectiveTriviaSyntax node) in X:\Prod\Microsoft.Dynamics.Nav.CodeAnalysis\Generated\SyntaxVisitor.Generated.cs:line 1677
   at Microsoft.Dynamics.Nav.CodeAnalysis.Syntax.PragmaWarningDirectiveTriviaSyntax.Accept[TResult](SyntaxVisitor`1 visitor) in X:\Prod\Microsoft.Dynamics.Nav.CodeAnalysis\Generated\SyntaxNodes.Generated.cs:line 31636
   at Microsoft.Dynamics.Nav.CodeAnalysis.BinderFactory.GetBinder(SyntaxNode node, Int32 position) in X:\Prod\Microsoft.Dynamics.Nav.CodeAnalysis\Binder\BinderFactory.cs:line 81
   at Microsoft.Dynamics.Nav.CodeAnalysis.Compilation.GetBinder(SyntaxNode syntax) in X:\Prod\Microsoft.Dynamics.Nav.CodeAnalysis\Compilation\Compilation.cs:line 1526
   at Microsoft.Dynamics.Nav.CodeAnalysis.ReportDataItemSemanticModel.GetSymbolInfoWorker(SyntaxNode node, CancellationToken cancellationToken) in X:\Prod\Microsoft.Dynamics.Nav.CodeAnalysis\Compilation\ReportDataItemSemanticModel.cs:line 96
   at Microsoft.Dynamics.Nav.CodeAnalysis.SyntaxTreeSemanticModel.GetSymbolInfoWorker(SyntaxNode node, CancellationToken cancellationToken) in X:\Prod\Microsoft.Dynamics.Nav.CodeAnalysis\Compilation\SyntaxTreeSemanticModel.cs:line 95
   at Microsoft.Dynamics.Nav.CodeAnalysis.SemanticModel.GetSymbolInfo(ExpressionSyntax expression, CancellationToken cancellationToken) in X:\Prod\Microsoft.Dynamics.Nav.CodeAnalysis\Compilation\SemanticModel.cs:line 551
   at Microsoft.Dynamics.Nav.CodeAnalysis.SemanticModel.GetSymbolInfoFromNode(SyntaxNode node, CancellationToken cancellationToken) in X:\Prod\Microsoft.Dynamics.Nav.CodeAnalysis\Compilation\SemanticModel.cs:line 409
   at BusinessCentral.CustomCodeAnalyzer.RuleSomething.AnalyzeNode(SyntaxNodeAnalysisContext ctx) in C:\Users\arthur.vandevondervo\repo\BusinessCentral.LinterCop\BusinessCentral.LinterCop\Design\Test.cs:line 19
   at Microsoft.Dynamics.Nav.CodeAnalysis.Diagnostics.AnalyzerExecutor.ExecuteAndCatchIfThrows_NoLock(DiagnosticAnalyzer analyzer, Action analyze, Nullable`1 info) in X:\Prod\Microsoft.Dynamics.Nav.CodeAnalysis\DiagnosticAnalyzer\AnalyzerExecutor.cs:line 1088'

3. Expected behavior It would be great if the method would return a null in this example.

I had mitigated this to exclude PragmaWarningDirectiveTrivia, something like;

private void AnalyzeNode(SyntaxNodeAnalysisContext ctx)
{
    if (ctx.Node.Parent.Kind != SyntaxKind.PragmaWarningDirectiveTrivia)
    {
        var symbolInfo = ctx.SemanticModel.GetSymbolInfo(ctx.Node, ctx.CancellationToken);
    }
}

Recently another issue has occured, where I've now discovered also Preprocessor directives can cause this same exception. I have again mitigated this, but would be great if this could be handled by the GetSymbolInfo itself.

4. Actual behavior Image

5. Versions:

  • AL Language: 15.0.1290655
  • Visual Studio Code: 1.97.2
  • Business Central: not applicable
  • List of Visual Studio Code extensions that you have installed: not applicable
  • Operating System:
    • [X] Windows
    • [ ] Linux
    • [ ] MacOS

Final Checklist

Please remember to do the following:

  • [X] Search the issue repository to ensure you are reporting a new issue
  • [X] Reproduce the issue after disabling all extensions except the AL Language extension
  • [X] Simplify your code around the issue to better isolate the problem

Arthurvdv avatar Feb 19 '25 19:02 Arthurvdv