Skip to content

API for IgnoredDirectiveTrivia #77697

Closed
@jjonescz

Description

@jjonescz

Background and Motivation

Implementing feature https://github.com/dotnet/csharplang/blob/main/proposals/ignored-directives.md.

Proposed API

  namespace Microsoft.CodeAnalysis.CSharp
 {
      public enum SyntaxKind
      {
+          IgnoredDirectiveTrivia = 9079,
      }

      public static class SyntaxFactory
      {
+          public static IgnoredDirectiveTriviaSyntax IgnoredDirectiveTrivia(SyntaxToken hashToken, SyntaxToken colonToken, SyntaxToken endOfDirectiveToken, bool isActive);
+          public static IgnoredDirectiveTriviaSyntax IgnoredDirectiveTrivia(bool isActive);
      }

      public class CSharpSyntaxVisitor<TResult>
      {
+          public virtual TResult? VisitIgnoredDirectiveTrivia(IgnoredDirectiveTriviaSyntax node);
      }

      public class CSharpSyntaxVisitor
      {
+          public virtual void VisitIgnoredDirectiveTrivia(IgnoredDirectiveTriviaSyntax node);
      }

      public class CSharpSyntaxRewriter : CSharpSyntaxVisitor<SyntaxNode>
      {
+          public override SyntaxNode? VisitIgnoredDirectiveTrivia(IgnoredDirectiveTriviaSyntax node);
      }
 }
 
 namespace Microsoft.CodeAnalysis.CSharp.Syntax
 {
+     public sealed class IgnoredDirectiveTriviaSyntax : DirectiveTriviaSyntax
+     {
+          public override SyntaxToken HashToken { get; }
+          public SyntaxToken ColonToken { get; }
+          public override SyntaxToken EndOfDirectiveToken { get; }
+          public override bool IsActive { get; }
+          public override void Accept(CSharpSyntaxVisitor visitor);
+          public override TResult? Accept<TResult>(CSharpSyntaxVisitor<TResult> visitor) where TResult : default;
+          public IgnoredDirectiveTriviaSyntax Update(SyntaxToken hashToken, SyntaxToken colonToken, SyntaxToken endOfDirectiveToken, bool isActive);
+          public new IgnoredDirectiveTriviaSyntax WithHashToken(SyntaxToken hashToken);
+          public IgnoredDirectiveTriviaSyntax WithColonToken(SyntaxToken colonToken);
+          public new IgnoredDirectiveTriviaSyntax WithEndOfDirectiveToken(SyntaxToken endOfDirectiveToken);
+          public IgnoredDirectiveTriviaSyntax WithIsActive(bool isActive);
+     }
 }

Note that these APIs are generated by Roslyn from

<Node Name="IgnoredDirectiveTriviaSyntax" Base="DirectiveTriviaSyntax">
  <Kind Name="IgnoredDirectiveTrivia"/>
  <Field Name="HashToken" Type="SyntaxToken" Override="true">
    <Kind Name="HashToken"/>
  </Field>
  <Field Name="ColonToken" Type="SyntaxToken">
    <Kind Name="ColonToken"/>
  </Field>
  <Field Name="EndOfDirectiveToken" Type="SyntaxToken" Override="true">
    <Kind Name="EndOfDirectiveToken"/>
  </Field>
  <Field Name="IsActive" Type="bool" Override="true"/>
</Node>

Usage Examples

// This is how 'dotnet run file' will find the directives:
public void FindDirectives(SourceText text)
{
     SyntaxTokenParser tokenizer = SyntaxFactory.CreateTokenParser(text);
     var result = tokenizer.ParseLeadingTrivia();
     foreach (var trivia in result.Token.LeadingTrivia)
     {
          if (trivia.IsKind(SyntaxKind.ShebangDirectiveTrivia))
          {
               // process #!
          }
          else if (trivia.IsKind(SyntaxKind.IgnoredDirectiveTrivia))
          {
               var message = trivia.GetStructure() is IgnoredDirectiveTriviaSyntax { EndOfDirectiveToken.LeadingTrivia: [{ RawKind: (int)SyntaxKind.PreprocessingMessageTrivia } messageTrivia] }
                    ? messageTrivia.ToString().AsSpan().Trim()
                    : "";
               // process #:
          }
     }
}

Alternative Designs

IgnoredDirective is very similar to the existing ShebangDirective:

<Node Name="ShebangDirectiveTriviaSyntax" Base="DirectiveTriviaSyntax">
  <Kind Name="ShebangDirectiveTrivia"/>
  <Field Name="HashToken" Type="SyntaxToken" Override="true">
    <Kind Name="HashToken"/>
  </Field>
  <Field Name="ExclamationToken" Type="SyntaxToken">
    <Kind Name="ExclamationToken"/>
  </Field>
  <Field Name="EndOfDirectiveToken" Type="SyntaxToken" Override="true">
    <Kind Name="EndOfDirectiveToken"/>
  </Field>
  <Field Name="IsActive" Type="bool" Override="true"/>
</Node>

Note that it means the "text" of the directive is appended as leading trivia of kind PreprocessingMessageTrivia on the ignored trivia's EndOfDirectiveToken. We could change that so the text is part of the directive syntax instead. The usage would be simpler but the shape would not be consistent with shebang directive.

Risks

None.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Area-CompilersConcept-APIThis issue involves adding, removing, clarification, or modification of an API.Feature - Run File#: and #! directives and file-based C# programsFeature Requestapi-approvedAPI was approved in API review, it can be implemented

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions