diff --git a/eng/targets/Settings.props b/eng/targets/Settings.props index 45d3a2045367d..29cb0772f5142 100644 --- a/eng/targets/Settings.props +++ b/eng/targets/Settings.props @@ -17,6 +17,8 @@ $(NoWarn);NU1507 + $(NoWarn);RSEXPERIMENTAL005 + CommonExtensions Microsoft\VBCSharp\LanguageServices diff --git a/src/Compilers/CSharp/Portable/CSharpParseOptions.cs b/src/Compilers/CSharp/Portable/CSharpParseOptions.cs index 8ae7033ac2fd0..650f5b27cf0ad 100644 --- a/src/Compilers/CSharp/Portable/CSharpParseOptions.cs +++ b/src/Compilers/CSharp/Portable/CSharpParseOptions.cs @@ -230,6 +230,14 @@ static void addSingleNamespaceParts(ArrayBuilder> namespa } } + /// + /// Used for parsing .cs file-based programs. + /// + /// + /// In this mode, ignored directives #: are allowed. + /// + internal bool FileBasedProgram => Features.ContainsKey("FileBasedProgram"); + internal override void ValidateOptions(ArrayBuilder builder) { ValidateOptions(builder, MessageProvider.Instance); diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index d482f2ad9b4f2..dd2f750ea57fa 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -8122,4 +8122,13 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ An expression tree may not contain an extension property access + + '#:' directives cannot be after first token in file + + + '#:' directives can be only used in file-based programs ('/feature:FileBasedProgram') + + + '#:' directives cannot be after '#if' directive + diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index 9d85d3a14cf13..3ee0557087076 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -2386,13 +2386,19 @@ internal enum ErrorCode ERR_UnderspecifiedExtension = 9295, ERR_ExpressionTreeContainsExtensionPropertyAccess = 9296, + ERR_PPIgnoredFollowsToken = 9297, + ERR_PPIgnoredNeedsFileBasedProgram = 9298, + ERR_PPIgnoredFollowsIf = 9299, + // Note: you will need to do the following after adding errors: // 1) Update ErrorFacts.IsBuildOnlyDiagnostic (src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs) + // 2) Add message to CSharpResources.resx // Note: you will need to do the following after adding warnings: // 1) Re-generate compiler code (eng\generate-compiler-code.cmd). // 2) Update ErrorFacts.IsBuildOnlyDiagnostic (src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs) // 3) Update ErrorFacts.GetWarningLevel (src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs) // 4) Update DiagnosticTest.WarningLevel_2 (src/Compilers/CSharp/Test/Syntax/Diagnostics/DiagnosticTest.cs) + // 5) Add message and '_Title' to CSharpResources.resx } } diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs index 69e4f74bf2725..9941defbe5926 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs @@ -2503,6 +2503,9 @@ or ErrorCode.ERR_InvalidExtensionParameterReference or ErrorCode.ERR_ValueParameterSameNameAsExtensionTypeParameter or ErrorCode.ERR_UnderspecifiedExtension or ErrorCode.ERR_ExpressionTreeContainsExtensionPropertyAccess + or ErrorCode.ERR_PPIgnoredFollowsToken + or ErrorCode.ERR_PPIgnoredNeedsFileBasedProgram + or ErrorCode.ERR_PPIgnoredFollowsIf => false, }; #pragma warning restore CS8524 // The switch expression does not handle some values of its input type (it is not exhaustive) involving an unnamed enum value. diff --git a/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4 b/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4 index 3c53475dbf132..02c4b6ce75cbe 100644 --- a/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4 +++ b/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4 @@ -1279,6 +1279,7 @@ directive_trivia | end_if_directive_trivia | end_region_directive_trivia | error_directive_trivia + | ignored_directive_trivia | line_or_span_directive_trivia | load_directive_trivia | nullable_directive_trivia @@ -1333,6 +1334,10 @@ error_directive_trivia : '#' 'error' ; +ignored_directive_trivia + : '#' ':' + ; + line_or_span_directive_trivia : line_directive_trivia | line_span_directive_trivia diff --git a/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Internal.Generated.cs b/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Internal.Generated.cs index f268ad36627da..5a024081d1d9b 100644 --- a/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Internal.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Internal.Generated.cs @@ -26604,6 +26604,96 @@ internal override GreenNode SetAnnotations(SyntaxAnnotation[]? annotations) => new ShebangDirectiveTriviaSyntax(this.Kind, this.hashToken, this.exclamationToken, this.endOfDirectiveToken, this.isActive, GetDiagnostics(), annotations); } +internal sealed partial class IgnoredDirectiveTriviaSyntax : DirectiveTriviaSyntax +{ + internal readonly SyntaxToken hashToken; + internal readonly SyntaxToken colonToken; + internal readonly SyntaxToken endOfDirectiveToken; + internal readonly bool isActive; + + internal IgnoredDirectiveTriviaSyntax(SyntaxKind kind, SyntaxToken hashToken, SyntaxToken colonToken, SyntaxToken endOfDirectiveToken, bool isActive, DiagnosticInfo[]? diagnostics, SyntaxAnnotation[]? annotations) + : base(kind, diagnostics, annotations) + { + this.SlotCount = 3; + this.AdjustFlagsAndWidth(hashToken); + this.hashToken = hashToken; + this.AdjustFlagsAndWidth(colonToken); + this.colonToken = colonToken; + this.AdjustFlagsAndWidth(endOfDirectiveToken); + this.endOfDirectiveToken = endOfDirectiveToken; + this.isActive = isActive; + } + + internal IgnoredDirectiveTriviaSyntax(SyntaxKind kind, SyntaxToken hashToken, SyntaxToken colonToken, SyntaxToken endOfDirectiveToken, bool isActive, SyntaxFactoryContext context) + : base(kind) + { + this.SetFactoryContext(context); + this.SlotCount = 3; + this.AdjustFlagsAndWidth(hashToken); + this.hashToken = hashToken; + this.AdjustFlagsAndWidth(colonToken); + this.colonToken = colonToken; + this.AdjustFlagsAndWidth(endOfDirectiveToken); + this.endOfDirectiveToken = endOfDirectiveToken; + this.isActive = isActive; + } + + internal IgnoredDirectiveTriviaSyntax(SyntaxKind kind, SyntaxToken hashToken, SyntaxToken colonToken, SyntaxToken endOfDirectiveToken, bool isActive) + : base(kind) + { + this.SlotCount = 3; + this.AdjustFlagsAndWidth(hashToken); + this.hashToken = hashToken; + this.AdjustFlagsAndWidth(colonToken); + this.colonToken = colonToken; + this.AdjustFlagsAndWidth(endOfDirectiveToken); + this.endOfDirectiveToken = endOfDirectiveToken; + this.isActive = isActive; + } + + public override SyntaxToken HashToken => this.hashToken; + public SyntaxToken ColonToken => this.colonToken; + public override SyntaxToken EndOfDirectiveToken => this.endOfDirectiveToken; + public override bool IsActive => this.isActive; + + internal override GreenNode? GetSlot(int index) + => index switch + { + 0 => this.hashToken, + 1 => this.colonToken, + 2 => this.endOfDirectiveToken, + _ => null, + }; + + internal override SyntaxNode CreateRed(SyntaxNode? parent, int position) => new CSharp.Syntax.IgnoredDirectiveTriviaSyntax(this, parent, position); + + public override void Accept(CSharpSyntaxVisitor visitor) => visitor.VisitIgnoredDirectiveTrivia(this); + public override TResult Accept(CSharpSyntaxVisitor visitor) => visitor.VisitIgnoredDirectiveTrivia(this); + + public IgnoredDirectiveTriviaSyntax Update(SyntaxToken hashToken, SyntaxToken colonToken, SyntaxToken endOfDirectiveToken, bool isActive) + { + if (hashToken != this.HashToken || colonToken != this.ColonToken || endOfDirectiveToken != this.EndOfDirectiveToken) + { + var newNode = SyntaxFactory.IgnoredDirectiveTrivia(hashToken, colonToken, endOfDirectiveToken, isActive); + var diags = GetDiagnostics(); + if (diags?.Length > 0) + newNode = newNode.WithDiagnosticsGreen(diags); + var annotations = GetAnnotations(); + if (annotations?.Length > 0) + newNode = newNode.WithAnnotationsGreen(annotations); + return newNode; + } + + return this; + } + + internal override GreenNode SetDiagnostics(DiagnosticInfo[]? diagnostics) + => new IgnoredDirectiveTriviaSyntax(this.Kind, this.hashToken, this.colonToken, this.endOfDirectiveToken, this.isActive, diagnostics, GetAnnotations()); + + internal override GreenNode SetAnnotations(SyntaxAnnotation[]? annotations) + => new IgnoredDirectiveTriviaSyntax(this.Kind, this.hashToken, this.colonToken, this.endOfDirectiveToken, this.isActive, GetDiagnostics(), annotations); +} + internal sealed partial class NullableDirectiveTriviaSyntax : DirectiveTriviaSyntax { internal readonly SyntaxToken hashToken; @@ -26967,6 +27057,7 @@ internal partial class CSharpSyntaxVisitor public virtual TResult VisitReferenceDirectiveTrivia(ReferenceDirectiveTriviaSyntax node) => this.DefaultVisit(node); public virtual TResult VisitLoadDirectiveTrivia(LoadDirectiveTriviaSyntax node) => this.DefaultVisit(node); public virtual TResult VisitShebangDirectiveTrivia(ShebangDirectiveTriviaSyntax node) => this.DefaultVisit(node); + public virtual TResult VisitIgnoredDirectiveTrivia(IgnoredDirectiveTriviaSyntax node) => this.DefaultVisit(node); public virtual TResult VisitNullableDirectiveTrivia(NullableDirectiveTriviaSyntax node) => this.DefaultVisit(node); } @@ -27216,6 +27307,7 @@ internal partial class CSharpSyntaxVisitor public virtual void VisitReferenceDirectiveTrivia(ReferenceDirectiveTriviaSyntax node) => this.DefaultVisit(node); public virtual void VisitLoadDirectiveTrivia(LoadDirectiveTriviaSyntax node) => this.DefaultVisit(node); public virtual void VisitShebangDirectiveTrivia(ShebangDirectiveTriviaSyntax node) => this.DefaultVisit(node); + public virtual void VisitIgnoredDirectiveTrivia(IgnoredDirectiveTriviaSyntax node) => this.DefaultVisit(node); public virtual void VisitNullableDirectiveTrivia(NullableDirectiveTriviaSyntax node) => this.DefaultVisit(node); } @@ -27953,6 +28045,9 @@ public override CSharpSyntaxNode VisitLoadDirectiveTrivia(LoadDirectiveTriviaSyn public override CSharpSyntaxNode VisitShebangDirectiveTrivia(ShebangDirectiveTriviaSyntax node) => node.Update((SyntaxToken)Visit(node.HashToken), (SyntaxToken)Visit(node.ExclamationToken), (SyntaxToken)Visit(node.EndOfDirectiveToken), node.IsActive); + public override CSharpSyntaxNode VisitIgnoredDirectiveTrivia(IgnoredDirectiveTriviaSyntax node) + => node.Update((SyntaxToken)Visit(node.HashToken), (SyntaxToken)Visit(node.ColonToken), (SyntaxToken)Visit(node.EndOfDirectiveToken), node.IsActive); + public override CSharpSyntaxNode VisitNullableDirectiveTrivia(NullableDirectiveTriviaSyntax node) => node.Update((SyntaxToken)Visit(node.HashToken), (SyntaxToken)Visit(node.NullableKeyword), (SyntaxToken)Visit(node.SettingToken), (SyntaxToken)Visit(node.TargetToken), (SyntaxToken)Visit(node.EndOfDirectiveToken), node.IsActive); } @@ -33237,6 +33332,20 @@ public ShebangDirectiveTriviaSyntax ShebangDirectiveTrivia(SyntaxToken hashToken return new ShebangDirectiveTriviaSyntax(SyntaxKind.ShebangDirectiveTrivia, hashToken, exclamationToken, endOfDirectiveToken, isActive, this.context); } + public IgnoredDirectiveTriviaSyntax IgnoredDirectiveTrivia(SyntaxToken hashToken, SyntaxToken colonToken, SyntaxToken endOfDirectiveToken, bool isActive) + { +#if DEBUG + if (hashToken == null) throw new ArgumentNullException(nameof(hashToken)); + if (hashToken.Kind != SyntaxKind.HashToken) throw new ArgumentException(nameof(hashToken)); + if (colonToken == null) throw new ArgumentNullException(nameof(colonToken)); + if (colonToken.Kind != SyntaxKind.ColonToken) throw new ArgumentException(nameof(colonToken)); + if (endOfDirectiveToken == null) throw new ArgumentNullException(nameof(endOfDirectiveToken)); + if (endOfDirectiveToken.Kind != SyntaxKind.EndOfDirectiveToken) throw new ArgumentException(nameof(endOfDirectiveToken)); +#endif + + return new IgnoredDirectiveTriviaSyntax(SyntaxKind.IgnoredDirectiveTrivia, hashToken, colonToken, endOfDirectiveToken, isActive, this.context); + } + public NullableDirectiveTriviaSyntax NullableDirectiveTrivia(SyntaxToken hashToken, SyntaxToken nullableKeyword, SyntaxToken settingToken, SyntaxToken? targetToken, SyntaxToken endOfDirectiveToken, bool isActive) { #if DEBUG @@ -38545,6 +38654,20 @@ public static ShebangDirectiveTriviaSyntax ShebangDirectiveTrivia(SyntaxToken ha return new ShebangDirectiveTriviaSyntax(SyntaxKind.ShebangDirectiveTrivia, hashToken, exclamationToken, endOfDirectiveToken, isActive); } + public static IgnoredDirectiveTriviaSyntax IgnoredDirectiveTrivia(SyntaxToken hashToken, SyntaxToken colonToken, SyntaxToken endOfDirectiveToken, bool isActive) + { +#if DEBUG + if (hashToken == null) throw new ArgumentNullException(nameof(hashToken)); + if (hashToken.Kind != SyntaxKind.HashToken) throw new ArgumentException(nameof(hashToken)); + if (colonToken == null) throw new ArgumentNullException(nameof(colonToken)); + if (colonToken.Kind != SyntaxKind.ColonToken) throw new ArgumentException(nameof(colonToken)); + if (endOfDirectiveToken == null) throw new ArgumentNullException(nameof(endOfDirectiveToken)); + if (endOfDirectiveToken.Kind != SyntaxKind.EndOfDirectiveToken) throw new ArgumentException(nameof(endOfDirectiveToken)); +#endif + + return new IgnoredDirectiveTriviaSyntax(SyntaxKind.IgnoredDirectiveTrivia, hashToken, colonToken, endOfDirectiveToken, isActive); + } + public static NullableDirectiveTriviaSyntax NullableDirectiveTrivia(SyntaxToken hashToken, SyntaxToken nullableKeyword, SyntaxToken settingToken, SyntaxToken? targetToken, SyntaxToken endOfDirectiveToken, bool isActive) { #if DEBUG diff --git a/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Main.Generated.cs b/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Main.Generated.cs index 66df0106254e3..6998b9cf5448b 100644 --- a/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Main.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Main.Generated.cs @@ -747,6 +747,9 @@ public partial class CSharpSyntaxVisitor /// Called when the visitor visits a ShebangDirectiveTriviaSyntax node. public virtual TResult? VisitShebangDirectiveTrivia(ShebangDirectiveTriviaSyntax node) => this.DefaultVisit(node); + /// Called when the visitor visits a IgnoredDirectiveTriviaSyntax node. + public virtual TResult? VisitIgnoredDirectiveTrivia(IgnoredDirectiveTriviaSyntax node) => this.DefaultVisit(node); + /// Called when the visitor visits a NullableDirectiveTriviaSyntax node. public virtual TResult? VisitNullableDirectiveTrivia(NullableDirectiveTriviaSyntax node) => this.DefaultVisit(node); } @@ -1485,6 +1488,9 @@ public partial class CSharpSyntaxVisitor /// Called when the visitor visits a ShebangDirectiveTriviaSyntax node. public virtual void VisitShebangDirectiveTrivia(ShebangDirectiveTriviaSyntax node) => this.DefaultVisit(node); + /// Called when the visitor visits a IgnoredDirectiveTriviaSyntax node. + public virtual void VisitIgnoredDirectiveTrivia(IgnoredDirectiveTriviaSyntax node) => this.DefaultVisit(node); + /// Called when the visitor visits a NullableDirectiveTriviaSyntax node. public virtual void VisitNullableDirectiveTrivia(NullableDirectiveTriviaSyntax node) => this.DefaultVisit(node); } @@ -2223,6 +2229,9 @@ public partial class CSharpSyntaxRewriter : CSharpSyntaxVisitor public override SyntaxNode? VisitShebangDirectiveTrivia(ShebangDirectiveTriviaSyntax node) => node.Update(VisitToken(node.HashToken), VisitToken(node.ExclamationToken), VisitToken(node.EndOfDirectiveToken), node.IsActive); + public override SyntaxNode? VisitIgnoredDirectiveTrivia(IgnoredDirectiveTriviaSyntax node) + => node.Update(VisitToken(node.HashToken), VisitToken(node.ColonToken), VisitToken(node.EndOfDirectiveToken), node.IsActive); + public override SyntaxNode? VisitNullableDirectiveTrivia(NullableDirectiveTriviaSyntax node) => node.Update(VisitToken(node.HashToken), VisitToken(node.NullableKeyword), VisitToken(node.SettingToken), VisitToken(node.TargetToken), VisitToken(node.EndOfDirectiveToken), node.IsActive); } @@ -6511,6 +6520,19 @@ public static ShebangDirectiveTriviaSyntax ShebangDirectiveTrivia(SyntaxToken ha public static ShebangDirectiveTriviaSyntax ShebangDirectiveTrivia(bool isActive) => SyntaxFactory.ShebangDirectiveTrivia(SyntaxFactory.Token(SyntaxKind.HashToken), SyntaxFactory.Token(SyntaxKind.ExclamationToken), SyntaxFactory.Token(SyntaxKind.EndOfDirectiveToken), isActive); + /// Creates a new IgnoredDirectiveTriviaSyntax instance. + public static IgnoredDirectiveTriviaSyntax IgnoredDirectiveTrivia(SyntaxToken hashToken, SyntaxToken colonToken, SyntaxToken endOfDirectiveToken, bool isActive) + { + if (hashToken.Kind() != SyntaxKind.HashToken) throw new ArgumentException(nameof(hashToken)); + if (colonToken.Kind() != SyntaxKind.ColonToken) throw new ArgumentException(nameof(colonToken)); + if (endOfDirectiveToken.Kind() != SyntaxKind.EndOfDirectiveToken) throw new ArgumentException(nameof(endOfDirectiveToken)); + return (IgnoredDirectiveTriviaSyntax)Syntax.InternalSyntax.SyntaxFactory.IgnoredDirectiveTrivia((Syntax.InternalSyntax.SyntaxToken)hashToken.Node!, (Syntax.InternalSyntax.SyntaxToken)colonToken.Node!, (Syntax.InternalSyntax.SyntaxToken)endOfDirectiveToken.Node!, isActive).CreateRed(); + } + + /// Creates a new IgnoredDirectiveTriviaSyntax instance. + public static IgnoredDirectiveTriviaSyntax IgnoredDirectiveTrivia(bool isActive) + => SyntaxFactory.IgnoredDirectiveTrivia(SyntaxFactory.Token(SyntaxKind.HashToken), SyntaxFactory.Token(SyntaxKind.ColonToken), SyntaxFactory.Token(SyntaxKind.EndOfDirectiveToken), isActive); + /// Creates a new NullableDirectiveTriviaSyntax instance. public static NullableDirectiveTriviaSyntax NullableDirectiveTrivia(SyntaxToken hashToken, SyntaxToken nullableKeyword, SyntaxToken settingToken, SyntaxToken targetToken, SyntaxToken endOfDirectiveToken, bool isActive) { diff --git a/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Syntax.Generated.cs b/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Syntax.Generated.cs index aa66360fb08d8..4623b79d7ea54 100644 --- a/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Syntax.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/CSharpSyntaxGenerator/CSharpSyntaxGenerator.SourceGenerator/Syntax.xml.Syntax.Generated.cs @@ -16572,6 +16572,55 @@ public ShebangDirectiveTriviaSyntax Update(SyntaxToken hashToken, SyntaxToken ex public ShebangDirectiveTriviaSyntax WithIsActive(bool isActive) => Update(this.HashToken, this.ExclamationToken, this.EndOfDirectiveToken, isActive); } +/// +/// This node is associated with the following syntax kinds: +/// +/// +/// +/// +public sealed partial class IgnoredDirectiveTriviaSyntax : DirectiveTriviaSyntax +{ + + internal IgnoredDirectiveTriviaSyntax(InternalSyntax.CSharpSyntaxNode green, SyntaxNode? parent, int position) + : base(green, parent, position) + { + } + + public override SyntaxToken HashToken => new SyntaxToken(this, ((InternalSyntax.IgnoredDirectiveTriviaSyntax)this.Green).hashToken, Position, 0); + + public SyntaxToken ColonToken => new SyntaxToken(this, ((InternalSyntax.IgnoredDirectiveTriviaSyntax)this.Green).colonToken, GetChildPosition(1), GetChildIndex(1)); + + public override SyntaxToken EndOfDirectiveToken => new SyntaxToken(this, ((InternalSyntax.IgnoredDirectiveTriviaSyntax)this.Green).endOfDirectiveToken, GetChildPosition(2), GetChildIndex(2)); + + public override bool IsActive => ((InternalSyntax.IgnoredDirectiveTriviaSyntax)this.Green).IsActive; + + internal override SyntaxNode? GetNodeSlot(int index) => null; + + internal override SyntaxNode? GetCachedSlot(int index) => null; + + public override void Accept(CSharpSyntaxVisitor visitor) => visitor.VisitIgnoredDirectiveTrivia(this); + public override TResult? Accept(CSharpSyntaxVisitor visitor) where TResult : default => visitor.VisitIgnoredDirectiveTrivia(this); + + public IgnoredDirectiveTriviaSyntax Update(SyntaxToken hashToken, SyntaxToken colonToken, SyntaxToken endOfDirectiveToken, bool isActive) + { + if (hashToken != this.HashToken || colonToken != this.ColonToken || endOfDirectiveToken != this.EndOfDirectiveToken) + { + var newNode = SyntaxFactory.IgnoredDirectiveTrivia(hashToken, colonToken, endOfDirectiveToken, isActive); + var annotations = GetAnnotations(); + return annotations?.Length > 0 ? newNode.WithAnnotations(annotations) : newNode; + } + + return this; + } + + internal override DirectiveTriviaSyntax WithHashTokenCore(SyntaxToken hashToken) => WithHashToken(hashToken); + public new IgnoredDirectiveTriviaSyntax WithHashToken(SyntaxToken hashToken) => Update(hashToken, this.ColonToken, this.EndOfDirectiveToken, this.IsActive); + public IgnoredDirectiveTriviaSyntax WithColonToken(SyntaxToken colonToken) => Update(this.HashToken, colonToken, this.EndOfDirectiveToken, this.IsActive); + internal override DirectiveTriviaSyntax WithEndOfDirectiveTokenCore(SyntaxToken endOfDirectiveToken) => WithEndOfDirectiveToken(endOfDirectiveToken); + public new IgnoredDirectiveTriviaSyntax WithEndOfDirectiveToken(SyntaxToken endOfDirectiveToken) => Update(this.HashToken, this.ColonToken, endOfDirectiveToken, this.IsActive); + public IgnoredDirectiveTriviaSyntax WithIsActive(bool isActive) => Update(this.HashToken, this.ColonToken, this.EndOfDirectiveToken, isActive); +} + /// /// This node is associated with the following syntax kinds: /// diff --git a/src/Compilers/CSharp/Portable/Parser/DirectiveParser.cs b/src/Compilers/CSharp/Portable/Parser/DirectiveParser.cs index 7c6641d1fd3a1..8ab5f8c772445 100644 --- a/src/Compilers/CSharp/Portable/Parser/DirectiveParser.cs +++ b/src/Compilers/CSharp/Portable/Parser/DirectiveParser.cs @@ -108,10 +108,14 @@ public CSharpSyntaxNode ParseDirective( break; default: - if (lexer.Options.Kind == SourceCodeKind.Script && contextualKind == SyntaxKind.ExclamationToken && hashPosition == 0 && !hash.HasTrailingTrivia) + if (contextualKind == SyntaxKind.ExclamationToken && hashPosition == 0 && !hash.HasTrailingTrivia) { result = this.ParseShebangDirective(hash, this.EatToken(SyntaxKind.ExclamationToken), isActive); } + else if (contextualKind == SyntaxKind.ColonToken && !hash.HasTrailingTrivia) + { + result = this.ParseIgnoredDirective(hash, this.EatToken(SyntaxKind.ColonToken), isActive, isFollowingToken); + } else { var id = this.EatToken(SyntaxKind.IdentifierToken, false); @@ -681,6 +685,26 @@ private DirectiveTriviaSyntax ParseShebangDirective(SyntaxToken hash, SyntaxToke return SyntaxFactory.ShebangDirectiveTrivia(hash, exclamation, this.ParseEndOfDirectiveWithOptionalPreprocessingMessage(), isActive); } + private DirectiveTriviaSyntax ParseIgnoredDirective(SyntaxToken hash, SyntaxToken colon, bool isActive, bool isFollowingToken) + { + if (!lexer.Options.FileBasedProgram) + { + colon = this.AddError(colon, ErrorCode.ERR_PPIgnoredNeedsFileBasedProgram); + } + + if (isFollowingToken) + { + colon = this.AddError(colon, ErrorCode.ERR_PPIgnoredFollowsToken); + } + + if (_context.SeenAnyIfDirectives) + { + colon = this.AddError(colon, ErrorCode.ERR_PPIgnoredFollowsIf); + } + + return SyntaxFactory.IgnoredDirectiveTrivia(hash, colon, this.ParseEndOfDirectiveWithOptionalPreprocessingMessage(), isActive); + } + private SyntaxToken ParseEndOfDirectiveWithOptionalPreprocessingMessage() => this.lexer.LexEndOfDirectiveWithOptionalPreprocessingMessage(); diff --git a/src/Compilers/CSharp/Portable/Parser/Directives.cs b/src/Compilers/CSharp/Portable/Parser/Directives.cs index 30d0149a20605..101314b0b7cb0 100644 --- a/src/Compilers/CSharp/Portable/Parser/Directives.cs +++ b/src/Compilers/CSharp/Portable/Parser/Directives.cs @@ -117,13 +117,15 @@ internal enum DefineState [DebuggerDisplay("{GetDebuggerDisplay(), nq}")] internal readonly struct DirectiveStack { - public static readonly DirectiveStack Empty = new DirectiveStack(ConsList.Empty); + public static readonly DirectiveStack Empty = new DirectiveStack(ConsList.Empty, seenAnyIfDirectives: false); private readonly ConsList? _directives; + private readonly bool _seenAnyIfDirectives; - private DirectiveStack(ConsList? directives) + private DirectiveStack(ConsList? directives, bool seenAnyIfDirectives) { _directives = directives; + _seenAnyIfDirectives = seenAnyIfDirectives; } public static void InterlockedInitialize(ref DirectiveStack location, DirectiveStack value) @@ -145,6 +147,8 @@ public bool IsEmpty } } + public bool SeenAnyIfDirectives => _seenAnyIfDirectives; + public DefineState IsDefined(string id) { for (var current = _directives; current != null && current.Any(); current = current.Tail) @@ -235,7 +239,7 @@ public DirectiveStack Add(Directive directive) } RoslynDebug.AssertNotNull(_directives); // If 'prevIf' isn't null, then '_directives' wasn't null. - return new DirectiveStack(CompleteIf(_directives, out _)); + return new DirectiveStack(CompleteIf(_directives, out _), seenAnyIfDirectives: _seenAnyIfDirectives); case SyntaxKind.EndRegionDirectiveTrivia: var prevRegion = GetPreviousRegion(_directives); if (prevRegion == null || !prevRegion.Any()) @@ -244,9 +248,10 @@ public DirectiveStack Add(Directive directive) } RoslynDebug.AssertNotNull(_directives); // If 'prevRegion' isn't null, then '_directives' wasn't null. - return new DirectiveStack(CompleteRegion(_directives)); // remove region directives from stack but leave everything else + return new DirectiveStack(CompleteRegion(_directives), seenAnyIfDirectives: _seenAnyIfDirectives); // remove region directives from stack but leave everything else default: - return new DirectiveStack(new ConsList(directive, _directives ?? ConsList.Empty)); + return new DirectiveStack(new ConsList(directive, _directives ?? ConsList.Empty), + seenAnyIfDirectives: _seenAnyIfDirectives || directive.Kind is SyntaxKind.IfDirectiveTrivia); } } diff --git a/src/Compilers/CSharp/Portable/Parser/Lexer.cs b/src/Compilers/CSharp/Portable/Parser/Lexer.cs index 3ef0208c74f8a..719961f828e30 100644 --- a/src/Compilers/CSharp/Portable/Parser/Lexer.cs +++ b/src/Compilers/CSharp/Portable/Parser/Lexer.cs @@ -2600,6 +2600,11 @@ private bool ScanDirectiveToken(ref TokenInfo info) info.Kind = SyntaxKind.MinusToken; break; + case ':': + TextWindow.AdvanceChar(); + info.Kind = SyntaxKind.ColonToken; + break; + case '!': TextWindow.AdvanceChar(); if (TextWindow.PeekChar() == '=') diff --git a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt index 57a3f640e82e5..fd4173df29920 100644 --- a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt @@ -1,5 +1,4 @@ abstract Microsoft.CodeAnalysis.CSharp.InterceptableLocation.Equals(Microsoft.CodeAnalysis.CSharp.InterceptableLocation? other) -> bool - Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.AddAttributeLists(params Microsoft.CodeAnalysis.CSharp.Syntax.AttributeListSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax.AddConstraintClauses(params Microsoft.CodeAnalysis.CSharp.Syntax.TypeParameterConstraintClauseSyntax![]! items) -> Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! @@ -41,3 +40,21 @@ static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ExtensionDeclaration(Microsof virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitExtensionDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! node) -> void virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitExtensionDeclaration(Microsoft.CodeAnalysis.CSharp.Syntax.ExtensionDeclarationSyntax! node) -> TResult? +[RSEXPERIMENTAL005]Microsoft.CodeAnalysis.CSharp.Syntax.IgnoredDirectiveTriviaSyntax +[RSEXPERIMENTAL005]Microsoft.CodeAnalysis.CSharp.Syntax.IgnoredDirectiveTriviaSyntax.ColonToken.get -> Microsoft.CodeAnalysis.SyntaxToken +[RSEXPERIMENTAL005]Microsoft.CodeAnalysis.CSharp.Syntax.IgnoredDirectiveTriviaSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken hashToken, Microsoft.CodeAnalysis.SyntaxToken colonToken, Microsoft.CodeAnalysis.SyntaxToken endOfDirectiveToken, bool isActive) -> Microsoft.CodeAnalysis.CSharp.Syntax.IgnoredDirectiveTriviaSyntax! +[RSEXPERIMENTAL005]Microsoft.CodeAnalysis.CSharp.Syntax.IgnoredDirectiveTriviaSyntax.WithColonToken(Microsoft.CodeAnalysis.SyntaxToken colonToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.IgnoredDirectiveTriviaSyntax! +[RSEXPERIMENTAL005]Microsoft.CodeAnalysis.CSharp.Syntax.IgnoredDirectiveTriviaSyntax.WithEndOfDirectiveToken(Microsoft.CodeAnalysis.SyntaxToken endOfDirectiveToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.IgnoredDirectiveTriviaSyntax! +[RSEXPERIMENTAL005]Microsoft.CodeAnalysis.CSharp.Syntax.IgnoredDirectiveTriviaSyntax.WithHashToken(Microsoft.CodeAnalysis.SyntaxToken hashToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.IgnoredDirectiveTriviaSyntax! +[RSEXPERIMENTAL005]Microsoft.CodeAnalysis.CSharp.Syntax.IgnoredDirectiveTriviaSyntax.WithIsActive(bool isActive) -> Microsoft.CodeAnalysis.CSharp.Syntax.IgnoredDirectiveTriviaSyntax! +Microsoft.CodeAnalysis.CSharp.SyntaxKind.IgnoredDirectiveTrivia = 9080 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind +override Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitIgnoredDirectiveTrivia(Microsoft.CodeAnalysis.CSharp.Syntax.IgnoredDirectiveTriviaSyntax! node) -> Microsoft.CodeAnalysis.SyntaxNode? +[RSEXPERIMENTAL005]override Microsoft.CodeAnalysis.CSharp.Syntax.IgnoredDirectiveTriviaSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> void +[RSEXPERIMENTAL005]override Microsoft.CodeAnalysis.CSharp.Syntax.IgnoredDirectiveTriviaSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor! visitor) -> TResult? +[RSEXPERIMENTAL005]override Microsoft.CodeAnalysis.CSharp.Syntax.IgnoredDirectiveTriviaSyntax.EndOfDirectiveToken.get -> Microsoft.CodeAnalysis.SyntaxToken +[RSEXPERIMENTAL005]override Microsoft.CodeAnalysis.CSharp.Syntax.IgnoredDirectiveTriviaSyntax.HashToken.get -> Microsoft.CodeAnalysis.SyntaxToken +[RSEXPERIMENTAL005]override Microsoft.CodeAnalysis.CSharp.Syntax.IgnoredDirectiveTriviaSyntax.IsActive.get -> bool +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.IgnoredDirectiveTrivia(bool isActive) -> Microsoft.CodeAnalysis.CSharp.Syntax.IgnoredDirectiveTriviaSyntax! +static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.IgnoredDirectiveTrivia(Microsoft.CodeAnalysis.SyntaxToken hashToken, Microsoft.CodeAnalysis.SyntaxToken colonToken, Microsoft.CodeAnalysis.SyntaxToken endOfDirectiveToken, bool isActive) -> Microsoft.CodeAnalysis.CSharp.Syntax.IgnoredDirectiveTriviaSyntax! +virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitIgnoredDirectiveTrivia(Microsoft.CodeAnalysis.CSharp.Syntax.IgnoredDirectiveTriviaSyntax! node) -> void +virtual Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitIgnoredDirectiveTrivia(Microsoft.CodeAnalysis.CSharp.Syntax.IgnoredDirectiveTriviaSyntax! node) -> TResult? diff --git a/src/Compilers/CSharp/Portable/Syntax/DirectiveTriviaSyntax.cs b/src/Compilers/CSharp/Portable/Syntax/DirectiveTriviaSyntax.cs index 704298132f7a4..17880ee6cdf7b 100644 --- a/src/Compilers/CSharp/Portable/Syntax/DirectiveTriviaSyntax.cs +++ b/src/Compilers/CSharp/Portable/Syntax/DirectiveTriviaSyntax.cs @@ -56,6 +56,8 @@ public SyntaxToken DirectiveNameToken return ((LoadDirectiveTriviaSyntax)this).LoadKeyword; case SyntaxKind.ShebangDirectiveTrivia: return ((ShebangDirectiveTriviaSyntax)this).ExclamationToken; + case SyntaxKind.IgnoredDirectiveTrivia: + return ((IgnoredDirectiveTriviaSyntax)this).ColonToken; case SyntaxKind.NullableDirectiveTrivia: return ((NullableDirectiveTriviaSyntax)this).NullableKeyword; default: diff --git a/src/Compilers/CSharp/Portable/Syntax/IgnoredDirectiveTriviaSyntax.cs b/src/Compilers/CSharp/Portable/Syntax/IgnoredDirectiveTriviaSyntax.cs new file mode 100644 index 0000000000000..584eb1aef7c14 --- /dev/null +++ b/src/Compilers/CSharp/Portable/Syntax/IgnoredDirectiveTriviaSyntax.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Diagnostics.CodeAnalysis; + +// NOTE: This whole file should be removed once the experimental attribute is not needed +// (the source generator should be used to emit this code instead). + +namespace Microsoft.CodeAnalysis.CSharp.Syntax; + +[Experimental(RoslynExperiments.IgnoredDirectives, UrlFormat = RoslynExperiments.IgnoredDirectives_Url)] +partial class IgnoredDirectiveTriviaSyntax; diff --git a/src/Compilers/CSharp/Portable/Syntax/Syntax.xml b/src/Compilers/CSharp/Portable/Syntax/Syntax.xml index 4c34bbf696e2c..369768857720f 100644 --- a/src/Compilers/CSharp/Portable/Syntax/Syntax.xml +++ b/src/Compilers/CSharp/Portable/Syntax/Syntax.xml @@ -5100,6 +5100,7 @@ + @@ -5113,6 +5114,20 @@ + + + + + + + + + + + + + + diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs index d110fee28917e..6ba23a9cfc285 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs @@ -929,5 +929,7 @@ public enum SyntaxKind : ushort SpreadElement = 9078, ExtensionDeclaration = 9079, + + IgnoredDirectiveTrivia = 9080, } } diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs index b2b8b824b17ac..9cd9333a54557 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs @@ -291,6 +291,7 @@ public static bool IsPreprocessorDirective(SyntaxKind kind) case SyntaxKind.LoadDirectiveTrivia: case SyntaxKind.BadDirectiveTrivia: case SyntaxKind.ShebangDirectiveTrivia: + case SyntaxKind.IgnoredDirectiveTrivia: case SyntaxKind.NullableDirectiveTrivia: return true; default: diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index 068f107e816e6..3a04390a29050 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -1682,6 +1682,21 @@ Metoda {0} určuje omezení struct pro parametr typu {1}, ale odpovídající parametr typu {2} přepsané nebo explicitně implementované metody {3} není typ, který nemůže mít hodnotu null. + + '#:' directives cannot be after '#if' directive + '#:' directives cannot be after '#if' directive + + + + '#:' directives cannot be after first token in file + '#:' directives cannot be after first token in file + + + + '#:' directives can be only used in file-based programs ('/feature:FileBasedProgram') + '#:' directives can be only used in file-based programs ('/feature:FileBasedProgram') + + Constructor '{0}' leaves required member '{1}' uninitialized. Konstruktor {0} ponechá požadovaný člen {1} neinicializovaný. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index dace7bde958f8..641e3a0a91ad0 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -1682,6 +1682,21 @@ Die Methode "{0}" gibt eine struct-Einschränkung für den Typparameter "{1}" an, aber der zugehörige Typparameter "{2}" der außer Kraft gesetzten oder explizit implementierten Methode "{3}" ist kein Non-Nullable-Werttyp. + + '#:' directives cannot be after '#if' directive + '#:' directives cannot be after '#if' directive + + + + '#:' directives cannot be after first token in file + '#:' directives cannot be after first token in file + + + + '#:' directives can be only used in file-based programs ('/feature:FileBasedProgram') + '#:' directives can be only used in file-based programs ('/feature:FileBasedProgram') + + Constructor '{0}' leaves required member '{1}' uninitialized. Der Konstruktor "{0}" lässt den erforderlichen Member "{1}" deinitialisiert. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index 2eb9d48228ab9..e8053fcf06405 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -1682,6 +1682,21 @@ El método "{0}" especifica una restricción "struct" para el parámetro de tipo "{1}", pero el parámetro de tipo correspondiente "{2}" de los métodos invalidados o implementados explícitamente "{3}" no es un tipo de valor que acepta valores NULL. + + '#:' directives cannot be after '#if' directive + '#:' directives cannot be after '#if' directive + + + + '#:' directives cannot be after first token in file + '#:' directives cannot be after first token in file + + + + '#:' directives can be only used in file-based programs ('/feature:FileBasedProgram') + '#:' directives can be only used in file-based programs ('/feature:FileBasedProgram') + + Constructor '{0}' leaves required member '{1}' uninitialized. El constructor "{0}" deja el miembro requerido "{1}" sin inicializar. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index df38a03fcc1ca..e5bca98561f73 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -1682,6 +1682,21 @@ La méthode '{0}' spécifie une contrainte 'struct' pour le paramètre de type '{1}', mais le paramètre de type '{2}' correspondant de la méthode substituée ou explicitement implémentée '{3}' n'est pas un type valeur non-nullable. + + '#:' directives cannot be after '#if' directive + '#:' directives cannot be after '#if' directive + + + + '#:' directives cannot be after first token in file + '#:' directives cannot be after first token in file + + + + '#:' directives can be only used in file-based programs ('/feature:FileBasedProgram') + '#:' directives can be only used in file-based programs ('/feature:FileBasedProgram') + + Constructor '{0}' leaves required member '{1}' uninitialized. Le constructeur « {0} » laisse le membre « {1} » requis non initialisé. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index 5610170431e2e..157330cb2bad4 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -1682,6 +1682,21 @@ Il metodo '{0}' specifica un vincolo 'struct' per il parametro di tipo '{1}', ma il parametro di tipo corrispondente '{2}' del metodo '{3}' sottoposto a override o implementato in modo esplicito non è un tipo valore che non ammette valori Null. + + '#:' directives cannot be after '#if' directive + '#:' directives cannot be after '#if' directive + + + + '#:' directives cannot be after first token in file + '#:' directives cannot be after first token in file + + + + '#:' directives can be only used in file-based programs ('/feature:FileBasedProgram') + '#:' directives can be only used in file-based programs ('/feature:FileBasedProgram') + + Constructor '{0}' leaves required member '{1}' uninitialized. Il costruttore '{0}' lascia non inizializzato il membro richiesto '{1}'. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index a15745b5f8e45..2127c58399bab 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -1682,6 +1682,21 @@ メソッド '{0}' は、型パラメーター '{1}' に対して 'struct' 制約を指定していますが、オーバーライドされた、または明示的に実装されたメソッド '{3}' の対応する型パラメーター '{2}' は NULL 非許容の値型ではありません。 + + '#:' directives cannot be after '#if' directive + '#:' directives cannot be after '#if' directive + + + + '#:' directives cannot be after first token in file + '#:' directives cannot be after first token in file + + + + '#:' directives can be only used in file-based programs ('/feature:FileBasedProgram') + '#:' directives can be only used in file-based programs ('/feature:FileBasedProgram') + + Constructor '{0}' leaves required member '{1}' uninitialized. コンストラクター '{0}' は、必要なメンバー '{1}' を初期化しないままにします。 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index 24ba7f9d10c13..83dcf11bca751 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -1682,6 +1682,21 @@ '{0}' 메서드는 형식 매개 변수 '{1}'의 'struct' 제약 조건을 지정하지만 재정의되었거나 명시적으로 구현된 '{3}' 메서드의 해당 형식 매개 변수 '{2}'이(가) null을 허용하지 않는 값 형식이 아닙니다. + + '#:' directives cannot be after '#if' directive + '#:' directives cannot be after '#if' directive + + + + '#:' directives cannot be after first token in file + '#:' directives cannot be after first token in file + + + + '#:' directives can be only used in file-based programs ('/feature:FileBasedProgram') + '#:' directives can be only used in file-based programs ('/feature:FileBasedProgram') + + Constructor '{0}' leaves required member '{1}' uninitialized. 생성자 '{0}'은(는) 필수 멤버 '{1}'을(를) 초기화되지 않은 상태로 둡니다. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index d493a435e49f4..fd9c20663a0ba 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -1682,6 +1682,21 @@ Metoda „{0}” określa ograniczenie „struct” dla parametru typu „{1}”, lecz odpowiadający parametr typu „{2}” przesłoniętej lub jawnie zaimplementowanej metody „{3}” nie jest nienullowalnym typem wartości. + + '#:' directives cannot be after '#if' directive + '#:' directives cannot be after '#if' directive + + + + '#:' directives cannot be after first token in file + '#:' directives cannot be after first token in file + + + + '#:' directives can be only used in file-based programs ('/feature:FileBasedProgram') + '#:' directives can be only used in file-based programs ('/feature:FileBasedProgram') + + Constructor '{0}' leaves required member '{1}' uninitialized. Konstruktor „{0}” pozostawia wymaganą składową "{1}". diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index d1314a1f45e98..3969ca7bf83d0 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -1682,6 +1682,21 @@ O método '{0}' especifica uma restrição 'struct' para o parâmetro de tipo '{1}', mas o parâmetro de tipo correspondente '{2}' do método substituído ou implementado explicitamente '{3}' não é um tipo de valor não anulável. + + '#:' directives cannot be after '#if' directive + '#:' directives cannot be after '#if' directive + + + + '#:' directives cannot be after first token in file + '#:' directives cannot be after first token in file + + + + '#:' directives can be only used in file-based programs ('/feature:FileBasedProgram') + '#:' directives can be only used in file-based programs ('/feature:FileBasedProgram') + + Constructor '{0}' leaves required member '{1}' uninitialized. O construtor '{0}' deixa o membro obrigatório '{1}' não inicializado. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index 46a7390dcb912..c2b43cecfcf0a 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -1682,6 +1682,21 @@ Метод "{0}" задает ограничение struct для параметра типа "{1}", но соответствующий параметр типа "{2}" переопределенного или явно реализованного метода "{3}" не является типом значения, не допускающим значение NULL. + + '#:' directives cannot be after '#if' directive + '#:' directives cannot be after '#if' directive + + + + '#:' directives cannot be after first token in file + '#:' directives cannot be after first token in file + + + + '#:' directives can be only used in file-based programs ('/feature:FileBasedProgram') + '#:' directives can be only used in file-based programs ('/feature:FileBasedProgram') + + Constructor '{0}' leaves required member '{1}' uninitialized. Конструктор "{0}" оставляет необходимый элемент "{1}" не инициализированным. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index 6161bd4a1569a..7a33cc92ed372 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -1682,6 +1682,21 @@ '{0}' yöntemi, '{1}' tür parametresi için bir 'struct' kısıtlaması belirtiyor, ancak geçersiz kılınan veya açıkça uygulanan '{3}' yönteminin karşılık gelen '{2}' tür parametresi boş değer atanamaz bir tip değil. + + '#:' directives cannot be after '#if' directive + '#:' directives cannot be after '#if' directive + + + + '#:' directives cannot be after first token in file + '#:' directives cannot be after first token in file + + + + '#:' directives can be only used in file-based programs ('/feature:FileBasedProgram') + '#:' directives can be only used in file-based programs ('/feature:FileBasedProgram') + + Constructor '{0}' leaves required member '{1}' uninitialized. Oluşturucu '{0}', gerekli '{1}' üyesinin başlatmasını geri alıyor. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index 37e1cdbe2ff0f..57d79284de704 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -1682,6 +1682,21 @@ 方法 "{0}" 为类型参数 "{1}" 指定了 "struct" 约束,但重写的或显式实现的方法 "{3}" 的相应类型参数 "{2}" 不是不可为 null 的值类型。 + + '#:' directives cannot be after '#if' directive + '#:' directives cannot be after '#if' directive + + + + '#:' directives cannot be after first token in file + '#:' directives cannot be after first token in file + + + + '#:' directives can be only used in file-based programs ('/feature:FileBasedProgram') + '#:' directives can be only used in file-based programs ('/feature:FileBasedProgram') + + Constructor '{0}' leaves required member '{1}' uninitialized. 构造函数“{0}”的必需成员“{1}”未初始化。 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index 50a644618727a..20a4511f62f68 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -1682,6 +1682,21 @@ 方法 '{0}' 會為型別參數 '{1}' 指定 'struct' 條件約束,但覆寫或明確實作的方法 '{3}' 對應型別參數 '{2}' 是不可為 Null 實值型別。 + + '#:' directives cannot be after '#if' directive + '#:' directives cannot be after '#if' directive + + + + '#:' directives cannot be after first token in file + '#:' directives cannot be after first token in file + + + + '#:' directives can be only used in file-based programs ('/feature:FileBasedProgram') + '#:' directives can be only used in file-based programs ('/feature:FileBasedProgram') + + Constructor '{0}' leaves required member '{1}' uninitialized. 建構函式 '{0}' 未初始化必要的成員 '{1}'。 diff --git a/src/Compilers/CSharp/Test/Syntax/Generated/Syntax.Test.xml.Generated.cs b/src/Compilers/CSharp/Test/Syntax/Generated/Syntax.Test.xml.Generated.cs index 604aa3566ef2d..10a3e4a9a239e 100644 --- a/src/Compilers/CSharp/Test/Syntax/Generated/Syntax.Test.xml.Generated.cs +++ b/src/Compilers/CSharp/Test/Syntax/Generated/Syntax.Test.xml.Generated.cs @@ -742,6 +742,9 @@ private static Syntax.InternalSyntax.LoadDirectiveTriviaSyntax GenerateLoadDirec private static Syntax.InternalSyntax.ShebangDirectiveTriviaSyntax GenerateShebangDirectiveTrivia() => InternalSyntaxFactory.ShebangDirectiveTrivia(InternalSyntaxFactory.Token(SyntaxKind.HashToken), InternalSyntaxFactory.Token(SyntaxKind.ExclamationToken), InternalSyntaxFactory.Token(SyntaxKind.EndOfDirectiveToken), new bool()); + private static Syntax.InternalSyntax.IgnoredDirectiveTriviaSyntax GenerateIgnoredDirectiveTrivia() + => InternalSyntaxFactory.IgnoredDirectiveTrivia(InternalSyntaxFactory.Token(SyntaxKind.HashToken), InternalSyntaxFactory.Token(SyntaxKind.ColonToken), InternalSyntaxFactory.Token(SyntaxKind.EndOfDirectiveToken), new bool()); + private static Syntax.InternalSyntax.NullableDirectiveTriviaSyntax GenerateNullableDirectiveTrivia() => InternalSyntaxFactory.NullableDirectiveTrivia(InternalSyntaxFactory.Token(SyntaxKind.HashToken), InternalSyntaxFactory.Token(SyntaxKind.NullableKeyword), InternalSyntaxFactory.Token(SyntaxKind.EnableKeyword), null, InternalSyntaxFactory.Token(SyntaxKind.EndOfDirectiveToken), new bool()); #endregion Green Generators @@ -3882,6 +3885,19 @@ public void TestShebangDirectiveTriviaFactoryAndProperties() AttachAndCheckDiagnostics(node); } + [Fact] + public void TestIgnoredDirectiveTriviaFactoryAndProperties() + { + var node = GenerateIgnoredDirectiveTrivia(); + + Assert.Equal(SyntaxKind.HashToken, node.HashToken.Kind); + Assert.Equal(SyntaxKind.ColonToken, node.ColonToken.Kind); + Assert.Equal(SyntaxKind.EndOfDirectiveToken, node.EndOfDirectiveToken.Kind); + Assert.Equal(new bool(), node.IsActive); + + AttachAndCheckDiagnostics(node); + } + [Fact] public void TestNullableDirectiveTriviaFactoryAndProperties() { @@ -10243,6 +10259,32 @@ public void TestShebangDirectiveTriviaIdentityRewriter() Assert.Same(oldNode, newNode); } + [Fact] + public void TestIgnoredDirectiveTriviaTokenDeleteRewriter() + { + var oldNode = GenerateIgnoredDirectiveTrivia(); + var rewriter = new TokenDeleteRewriter(); + var newNode = rewriter.Visit(oldNode); + + if(!oldNode.IsMissing) + { + Assert.NotEqual(oldNode, newNode); + } + + Assert.NotNull(newNode); + Assert.True(newNode.IsMissing, "No tokens => missing"); + } + + [Fact] + public void TestIgnoredDirectiveTriviaIdentityRewriter() + { + var oldNode = GenerateIgnoredDirectiveTrivia(); + var rewriter = new IdentityRewriter(); + var newNode = rewriter.Visit(oldNode); + + Assert.Same(oldNode, newNode); + } + [Fact] public void TestNullableDirectiveTriviaTokenDeleteRewriter() { @@ -11006,6 +11048,9 @@ private static LoadDirectiveTriviaSyntax GenerateLoadDirectiveTrivia() private static ShebangDirectiveTriviaSyntax GenerateShebangDirectiveTrivia() => SyntaxFactory.ShebangDirectiveTrivia(SyntaxFactory.Token(SyntaxKind.HashToken), SyntaxFactory.Token(SyntaxKind.ExclamationToken), SyntaxFactory.Token(SyntaxKind.EndOfDirectiveToken), new bool()); + private static IgnoredDirectiveTriviaSyntax GenerateIgnoredDirectiveTrivia() + => SyntaxFactory.IgnoredDirectiveTrivia(SyntaxFactory.Token(SyntaxKind.HashToken), SyntaxFactory.Token(SyntaxKind.ColonToken), SyntaxFactory.Token(SyntaxKind.EndOfDirectiveToken), new bool()); + private static NullableDirectiveTriviaSyntax GenerateNullableDirectiveTrivia() => SyntaxFactory.NullableDirectiveTrivia(SyntaxFactory.Token(SyntaxKind.HashToken), SyntaxFactory.Token(SyntaxKind.NullableKeyword), SyntaxFactory.Token(SyntaxKind.EnableKeyword), default(SyntaxToken), SyntaxFactory.Token(SyntaxKind.EndOfDirectiveToken), new bool()); #endregion Red Generators @@ -14146,6 +14191,19 @@ public void TestShebangDirectiveTriviaFactoryAndProperties() Assert.Equal(node, newNode); } + [Fact] + public void TestIgnoredDirectiveTriviaFactoryAndProperties() + { + var node = GenerateIgnoredDirectiveTrivia(); + + Assert.Equal(SyntaxKind.HashToken, node.HashToken.Kind()); + Assert.Equal(SyntaxKind.ColonToken, node.ColonToken.Kind()); + Assert.Equal(SyntaxKind.EndOfDirectiveToken, node.EndOfDirectiveToken.Kind()); + Assert.Equal(new bool(), node.IsActive); + var newNode = node.WithHashToken(node.HashToken).WithColonToken(node.ColonToken).WithEndOfDirectiveToken(node.EndOfDirectiveToken).WithIsActive(node.IsActive); + Assert.Equal(node, newNode); + } + [Fact] public void TestNullableDirectiveTriviaFactoryAndProperties() { @@ -20507,6 +20565,32 @@ public void TestShebangDirectiveTriviaIdentityRewriter() Assert.Same(oldNode, newNode); } + [Fact] + public void TestIgnoredDirectiveTriviaTokenDeleteRewriter() + { + var oldNode = GenerateIgnoredDirectiveTrivia(); + var rewriter = new TokenDeleteRewriter(); + var newNode = rewriter.Visit(oldNode); + + if(!oldNode.IsMissing) + { + Assert.NotEqual(oldNode, newNode); + } + + Assert.NotNull(newNode); + Assert.True(newNode.IsMissing, "No tokens => missing"); + } + + [Fact] + public void TestIgnoredDirectiveTriviaIdentityRewriter() + { + var oldNode = GenerateIgnoredDirectiveTrivia(); + var rewriter = new IdentityRewriter(); + var newNode = rewriter.Visit(oldNode); + + Assert.Same(oldNode, newNode); + } + [Fact] public void TestNullableDirectiveTriviaTokenDeleteRewriter() { diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/CSharpParseOptionsTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/CSharpParseOptionsTests.cs index 57d82e0f09cfd..95acc81fd07c9 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/CSharpParseOptionsTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/CSharpParseOptionsTests.cs @@ -63,6 +63,7 @@ public void TestFieldsForEqualsAndGetHashCode() ReflectionAssert.AssertPublicAndInternalFieldsAndProperties( typeof(CSharpParseOptions), "Features", + "FileBasedProgram", "Language", "LanguageVersion", "InterceptorsNamespaces", diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/IgnoredDirectiveParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/IgnoredDirectiveParsingTests.cs new file mode 100644 index 0000000000000..5acd0beb53958 --- /dev/null +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/IgnoredDirectiveParsingTests.cs @@ -0,0 +1,557 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Linq; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests; + +public sealed class IgnoredDirectiveParsingTests(ITestOutputHelper output) : ParsingTests(output) +{ + private const string FeatureName = "FileBasedProgram"; + + [Theory, CombinatorialData] + public void FeatureFlag(bool script) + { + var options = script ? TestOptions.Script : TestOptions.Regular; + + var source = """ + #!xyz + #:name value + """; + + VerifyTrivia(); + UsingTree(source, options, + // (2,2): error CS9282: '#:' directives can be only used in file-based programs ('/feature:FileBasedProgram') + // #:name value + Diagnostic(ErrorCode.ERR_PPIgnoredNeedsFileBasedProgram, ":").WithLocation(2, 2)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.EndOfFileToken); + { + L(SyntaxKind.ShebangDirectiveTrivia); + { + N(SyntaxKind.HashToken); + N(SyntaxKind.ExclamationToken); + N(SyntaxKind.EndOfDirectiveToken); + { + L(SyntaxKind.PreprocessingMessageTrivia, "xyz"); + T(SyntaxKind.EndOfLineTrivia, "\n"); + } + } + L(SyntaxKind.IgnoredDirectiveTrivia); + { + N(SyntaxKind.HashToken); + N(SyntaxKind.ColonToken); + N(SyntaxKind.EndOfDirectiveToken); + { + L(SyntaxKind.PreprocessingMessageTrivia, "name value"); + } + } + } + } + EOF(); + + UsingTree(source, options.WithFeature(FeatureName)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.EndOfFileToken); + { + L(SyntaxKind.ShebangDirectiveTrivia); + { + N(SyntaxKind.HashToken); + N(SyntaxKind.ExclamationToken); + N(SyntaxKind.EndOfDirectiveToken); + { + L(SyntaxKind.PreprocessingMessageTrivia, "xyz"); + T(SyntaxKind.EndOfLineTrivia, "\n"); + } + } + L(SyntaxKind.IgnoredDirectiveTrivia); + { + N(SyntaxKind.HashToken); + N(SyntaxKind.ColonToken); + N(SyntaxKind.EndOfDirectiveToken); + { + L(SyntaxKind.PreprocessingMessageTrivia, "name value"); + } + } + } + } + EOF(); + } + + [Fact] + public void Semantics() + { + var source = """ + #!xyz + #:name value + System.Console.WriteLine(123); + """; + CompileAndVerify(source, + parseOptions: TestOptions.Regular.WithFeature(FeatureName), + expectedOutput: "123").VerifyDiagnostics(); + } + + [Fact] + public void Api() + { + var source = """ + #:abc + """; + var root = SyntaxFactory.ParseCompilationUnit(source, options: TestOptions.Regular.WithFeature(FeatureName)); + var trivia = root.EndOfFileToken.GetLeadingTrivia().Single(); + Assert.Equal(SyntaxKind.IgnoredDirectiveTrivia, trivia.Kind()); + Assert.True(SyntaxFacts.IsPreprocessorDirective(trivia.Kind())); + Assert.True(SyntaxFacts.IsTrivia(trivia.Kind())); + var structure = (IgnoredDirectiveTriviaSyntax)trivia.GetStructure()!; + Assert.Equal(":", structure.DirectiveNameToken.ToFullString()); + var messageTrivia = structure.EndOfDirectiveToken.GetLeadingTrivia().Single(); + Assert.Equal(SyntaxKind.PreprocessingMessageTrivia, messageTrivia.Kind()); + Assert.Equal("abc", messageTrivia.ToString()); + trivia.GetDiagnostics().Verify(); + } + + [Fact] + public void Api_Diagnostics() + { + var source = """ + #if X + #endif + #:abc + """; + var root = SyntaxFactory.ParseCompilationUnit(source, options: TestOptions.Regular.WithFeature(FeatureName)); + var trivia = root.EndOfFileToken.GetLeadingTrivia().Last(); + Assert.Equal(SyntaxKind.IgnoredDirectiveTrivia, trivia.Kind()); + Assert.True(SyntaxFacts.IsPreprocessorDirective(trivia.Kind())); + Assert.True(SyntaxFacts.IsTrivia(trivia.Kind())); + var structure = (IgnoredDirectiveTriviaSyntax)trivia.GetStructure()!; + Assert.Equal(":", structure.DirectiveNameToken.ToFullString()); + var messageTrivia = structure.EndOfDirectiveToken.GetLeadingTrivia().Single(); + Assert.Equal(SyntaxKind.PreprocessingMessageTrivia, messageTrivia.Kind()); + Assert.Equal("abc", messageTrivia.ToString()); + trivia.GetDiagnostics().Verify( + // (3,2): error CS9283: '#:' directives cannot be after '#if' directive + // #:abc + Diagnostic(ErrorCode.ERR_PPIgnoredFollowsIf, ":").WithLocation(3, 2)); + } + + [Theory, CombinatorialData] + public void ShebangNotFirst(bool script, bool featureFlag) + { + var options = script ? TestOptions.Script : TestOptions.Regular; + + if (featureFlag) + { + options = options.WithFeature(FeatureName); + } + + var source = """ + #!xyz + """; + + VerifyTrivia(); + UsingTree(source, options, + // (1,2): error CS1024: Preprocessor directive expected + // #!xyz + Diagnostic(ErrorCode.ERR_PPDirectiveExpected, "#").WithLocation(1, 2)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.EndOfFileToken); + { + L(SyntaxKind.WhitespaceTrivia, " "); + L(SyntaxKind.BadDirectiveTrivia); + { + N(SyntaxKind.HashToken); + M(SyntaxKind.IdentifierToken); + N(SyntaxKind.EndOfDirectiveToken); + { + L(SyntaxKind.SkippedTokensTrivia); + { + N(SyntaxKind.ExclamationToken); + N(SyntaxKind.IdentifierToken, "xyz"); + } + } + } + } + } + EOF(); + } + + [Fact] + public void AfterToken() + { + var source = """ + #:x + M(); + #:y + """; + + VerifyTrivia(); + UsingTree(source, TestOptions.Regular.WithFeature(FeatureName), + // (3,2): error CS9281: '#:' directives cannot be after first token in file + // #:y + Diagnostic(ErrorCode.ERR_PPIgnoredFollowsToken, ":").WithLocation(3, 2)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.ExpressionStatement); + { + N(SyntaxKind.InvocationExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "M"); + { + L(SyntaxKind.IgnoredDirectiveTrivia); + { + N(SyntaxKind.HashToken); + N(SyntaxKind.ColonToken); + N(SyntaxKind.EndOfDirectiveToken); + { + L(SyntaxKind.PreprocessingMessageTrivia, "x"); + T(SyntaxKind.EndOfLineTrivia, "\n"); + } + } + } + } + N(SyntaxKind.ArgumentList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + } + N(SyntaxKind.SemicolonToken); + { + T(SyntaxKind.EndOfLineTrivia, "\n"); + } + } + } + N(SyntaxKind.EndOfFileToken); + { + L(SyntaxKind.IgnoredDirectiveTrivia); + { + N(SyntaxKind.HashToken); + N(SyntaxKind.ColonToken); + N(SyntaxKind.EndOfDirectiveToken); + { + L(SyntaxKind.PreprocessingMessageTrivia, "y"); + } + } + } + } + EOF(); + } + + [Fact] + public void AfterIf() + { + var source = """ + #:x + #if X + #:y + #endif + #:z + """; + + VerifyTrivia(); + UsingTree(source, TestOptions.Regular.WithFeature(FeatureName), + // (3,2): error CS9283: '#:' directives cannot be after '#if' directive + // #:y + Diagnostic(ErrorCode.ERR_PPIgnoredFollowsIf, ":").WithLocation(3, 2), + // (5,2): error CS9283: '#:' directives cannot be after '#if' directive + // #:z + Diagnostic(ErrorCode.ERR_PPIgnoredFollowsIf, ":").WithLocation(5, 2)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.EndOfFileToken); + { + L(SyntaxKind.IgnoredDirectiveTrivia); + { + N(SyntaxKind.HashToken); + N(SyntaxKind.ColonToken); + N(SyntaxKind.EndOfDirectiveToken); + { + L(SyntaxKind.PreprocessingMessageTrivia, "x"); + T(SyntaxKind.EndOfLineTrivia, "\n"); + } + } + L(SyntaxKind.IfDirectiveTrivia); + { + N(SyntaxKind.HashToken); + N(SyntaxKind.IfKeyword); + { + T(SyntaxKind.WhitespaceTrivia, " "); + } + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "X"); + } + N(SyntaxKind.EndOfDirectiveToken); + { + T(SyntaxKind.EndOfLineTrivia, "\n"); + } + } + L(SyntaxKind.IgnoredDirectiveTrivia); + { + N(SyntaxKind.HashToken); + N(SyntaxKind.ColonToken); + N(SyntaxKind.EndOfDirectiveToken); + { + L(SyntaxKind.PreprocessingMessageTrivia, "y"); + T(SyntaxKind.EndOfLineTrivia, "\n"); + } + } + L(SyntaxKind.EndIfDirectiveTrivia); + { + N(SyntaxKind.HashToken); + N(SyntaxKind.EndIfKeyword); + N(SyntaxKind.EndOfDirectiveToken); + { + T(SyntaxKind.EndOfLineTrivia, "\n"); + } + } + L(SyntaxKind.IgnoredDirectiveTrivia); + { + N(SyntaxKind.HashToken); + N(SyntaxKind.ColonToken); + N(SyntaxKind.EndOfDirectiveToken); + { + L(SyntaxKind.PreprocessingMessageTrivia, "z"); + } + } + } + } + EOF(); + } + + [Fact] + public void AfterComment() + { + var source = """ + #:x + // comment + #:y + """; + + VerifyTrivia(); + UsingTree(source, TestOptions.Regular.WithFeature(FeatureName)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.EndOfFileToken); + { + L(SyntaxKind.IgnoredDirectiveTrivia); + { + N(SyntaxKind.HashToken); + N(SyntaxKind.ColonToken); + N(SyntaxKind.EndOfDirectiveToken); + { + L(SyntaxKind.PreprocessingMessageTrivia, "x"); + T(SyntaxKind.EndOfLineTrivia, "\n"); + } + } + L(SyntaxKind.SingleLineCommentTrivia); + L(SyntaxKind.EndOfLineTrivia, "\n"); + L(SyntaxKind.IgnoredDirectiveTrivia); + { + N(SyntaxKind.HashToken); + N(SyntaxKind.ColonToken); + N(SyntaxKind.EndOfDirectiveToken); + { + L(SyntaxKind.PreprocessingMessageTrivia, "y"); + } + } + } + } + EOF(); + } + + [Fact] + public void AfterDefine() + { + var source = """ + #:x + #define y + #:y + """; + + VerifyTrivia(); + UsingTree(source, TestOptions.Regular.WithFeature(FeatureName)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.EndOfFileToken); + { + L(SyntaxKind.IgnoredDirectiveTrivia); + { + N(SyntaxKind.HashToken); + N(SyntaxKind.ColonToken); + N(SyntaxKind.EndOfDirectiveToken); + { + L(SyntaxKind.PreprocessingMessageTrivia, "x"); + T(SyntaxKind.EndOfLineTrivia, "\n"); + } + } + L(SyntaxKind.DefineDirectiveTrivia); + { + N(SyntaxKind.HashToken); + N(SyntaxKind.DefineKeyword); + { + T(SyntaxKind.WhitespaceTrivia, " "); + } + N(SyntaxKind.IdentifierToken, "y"); + N(SyntaxKind.EndOfDirectiveToken); + { + T(SyntaxKind.EndOfLineTrivia, "\n"); + } + } + L(SyntaxKind.IgnoredDirectiveTrivia); + { + N(SyntaxKind.HashToken); + N(SyntaxKind.ColonToken); + N(SyntaxKind.EndOfDirectiveToken); + { + L(SyntaxKind.PreprocessingMessageTrivia, "y"); + } + } + } + } + EOF(); + } + + [Fact] + public void SpaceBeforeHash() + { + var source = """ + #:x + """; + + VerifyTrivia(); + UsingTree(source, TestOptions.Regular.WithFeature(FeatureName)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.EndOfFileToken); + { + L(SyntaxKind.WhitespaceTrivia, " "); + L(SyntaxKind.IgnoredDirectiveTrivia); + { + N(SyntaxKind.HashToken); + N(SyntaxKind.ColonToken); + N(SyntaxKind.EndOfDirectiveToken); + { + L(SyntaxKind.PreprocessingMessageTrivia, "x"); + } + } + } + } + EOF(); + } + + [Fact] + public void SpacesAfterHash() + { + var source = """ + # : x + """; + + VerifyTrivia(); + UsingTree(source, TestOptions.Regular.WithFeature(FeatureName), + // (1,2): error CS1024: Preprocessor directive expected + // # : x + Diagnostic(ErrorCode.ERR_PPDirectiveExpected, "#").WithLocation(1, 2)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.EndOfFileToken); + { + L(SyntaxKind.WhitespaceTrivia, " "); + L(SyntaxKind.BadDirectiveTrivia); + { + N(SyntaxKind.HashToken); + { + T(SyntaxKind.WhitespaceTrivia, " "); + } + M(SyntaxKind.IdentifierToken); + N(SyntaxKind.EndOfDirectiveToken); + { + L(SyntaxKind.SkippedTokensTrivia); + { + N(SyntaxKind.ColonToken); + { + T(SyntaxKind.WhitespaceTrivia, " "); + } + N(SyntaxKind.IdentifierToken, "x"); + } + } + } + } + } + EOF(); + } + + [Fact] + public void NoMessage() + { + var source = """ + #: + """; + + VerifyTrivia(); + UsingTree(source, TestOptions.Regular.WithFeature(FeatureName)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.EndOfFileToken); + { + L(SyntaxKind.IgnoredDirectiveTrivia); + { + N(SyntaxKind.HashToken); + N(SyntaxKind.ColonToken); + N(SyntaxKind.EndOfDirectiveToken); + } + } + } + EOF(); + } + + [Fact] + public void NoColon() + { + var source = """ + # + """; + + VerifyTrivia(); + UsingTree(source, TestOptions.Regular.WithFeature(FeatureName), + // (1,1): error CS1024: Preprocessor directive expected + // # + Diagnostic(ErrorCode.ERR_PPDirectiveExpected, "#").WithLocation(1, 1)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.EndOfFileToken); + { + L(SyntaxKind.BadDirectiveTrivia); + { + N(SyntaxKind.HashToken); + M(SyntaxKind.IdentifierToken); + N(SyntaxKind.EndOfDirectiveToken); + } + } + } + EOF(); + } +} diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/ParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/ParsingTests.cs index 930ced6a0a2bc..f69df41310e44 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/ParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/ParsingTests.cs @@ -11,6 +11,7 @@ using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; using Xunit; using Xunit.Abstractions; using Xunit.Sdk; @@ -20,7 +21,8 @@ namespace Microsoft.CodeAnalysis.CSharp.UnitTests public abstract class ParsingTests : CSharpTestBase { private CSharpSyntaxNode? _node; - private IEnumerator? _treeEnumerator; + private IEnumerator? _treeEnumerator; + private bool _verifyTrivia; private readonly ITestOutputHelper _output; public ParsingTests(ITestOutputHelper output) @@ -192,6 +194,12 @@ protected void UsingNode(CSharpSyntaxNode root) _treeEnumerator = nodes.GetEnumerator(); } + protected void VerifyTrivia(bool enabled = true) + { + VerifyEnumeratorConsumed(); + _verifyTrivia = enabled; + } + /// /// Moves the enumerator and asserts that the current node is of the given kind. /// @@ -204,6 +212,7 @@ protected SyntaxNodeOrToken N(SyntaxKind kind, string? value = null) var current = _treeEnumerator.Current; Assert.Equal(kind, current.Kind()); + Assert.False(current.IsTrivia); Assert.False(current.IsMissing); if (value != null) @@ -211,7 +220,7 @@ protected SyntaxNodeOrToken N(SyntaxKind kind, string? value = null) Assert.Equal(current.ToString(), value); } - return current; + return current.NodeOrToken; } catch when (DumpAndCleanup()) { @@ -229,10 +238,53 @@ protected SyntaxNodeOrToken M(SyntaxKind kind) try { Assert.True(_treeEnumerator!.MoveNext()); - SyntaxNodeOrToken current = _treeEnumerator.Current; + var current = _treeEnumerator.Current; Assert.Equal(kind, current.Kind()); Assert.True(current.IsMissing); - return current; + return current.NodeOrToken; + } + catch when (DumpAndCleanup()) + { + throw; + } + } + + /// + /// Asserts leading trivia. + /// + [DebuggerHidden] + protected SyntaxTrivia L(SyntaxKind kind, string? value = null) + { + return Trivia(kind, value, trailing: false); + } + + /// + /// Asserts trailing trivia. + /// + [DebuggerHidden] + protected SyntaxTrivia T(SyntaxKind kind, string? value = null) + { + return Trivia(kind, value, trailing: true); + } + + [DebuggerHidden] + private SyntaxTrivia Trivia(SyntaxKind kind, string? value, bool trailing) + { + try + { + Assert.True(_treeEnumerator!.MoveNext()); + var current = _treeEnumerator.Current; + + Assert.Equal(kind, current.Kind()); + Assert.True(current.IsTrivia); + Assert.Equal(trailing, current.IsTrailing); + + if (value != null) + { + Assert.Equal(current.ToString().ReplaceLineEndings("\n"), value); + } + + return current.Trivia; } catch when (DumpAndCleanup()) { @@ -254,35 +306,80 @@ protected void EOF() } } - private IEnumerable EnumerateNodes(CSharpSyntaxNode node, bool dump) + private IEnumerable EnumerateNodes(CSharpSyntaxNode node, bool dump) { Print(node, dump); yield return node; - var stack = new Stack(24); - stack.Push(node.ChildNodesAndTokens().GetEnumerator()); + var stack = new Stack<(SyntaxTriviaList.Enumerator, ChildSyntaxList.Enumerator, SyntaxTriviaList.Enumerator)>(24); + stack.Push((default, node.ChildNodesAndTokens().GetEnumerator(), default)); Open(dump); while (stack.Count > 0) { - var en = stack.Pop(); - if (!en.MoveNext()) + var (en1, en2, en3) = stack.Pop(); + + byte en; + SyntaxTrivia currentTrivia = default; + SyntaxNodeOrToken currentChild = default; + + if (en1.MoveNext()) + { + currentTrivia = en1.Current; + en = 1; + } + else if (en2.MoveNext()) + { + currentChild = en2.Current; + en = 2; + } + else if (en3.MoveNext()) + { + currentTrivia = en3.Current; + en = 3; + } + else { // no more down this branch Close(dump); continue; } - var current = en.Current; - stack.Push(en); // put it back on stack (struct enumerator) + stack.Push((en1, en2, en3)); // put it back on stack (struct enumerator) + + if (en != 2) // we are on a trivia + { + Print(currentTrivia, trailing: en == 3, dump); + yield return new SyntaxNodeOrTokenOrTrivia(currentTrivia, trailing: en == 3); - Print(current, dump); - yield return current; + if (currentTrivia.TryGetStructure(out var triviaStructure)) + { + // trivia has a structure, so consider its children + stack.Push((default, triviaStructure.ChildNodesAndTokens().GetEnumerator(), default)); + Open(dump); + } - if (current.IsNode) + continue; + } + + Print(currentChild, dump); + yield return currentChild; + + if (currentChild.AsNode(out var currentChildNode)) { // not token, so consider children - stack.Push(current.ChildNodesAndTokens().GetEnumerator()); + stack.Push((default, currentChildNode.ChildNodesAndTokens().GetEnumerator(), default)); + Open(dump); + continue; + } + + if (_verifyTrivia && currentChild.AsToken(out var currentChildToken) && + (currentChildToken.HasLeadingTrivia || currentChildToken.HasTrailingTrivia)) + { + // token with trivia + stack.Push((currentChildToken.GetLeadingTrivia().GetEnumerator(), + default, + currentChildToken.GetTrailingTrivia().GetEnumerator())); Open(dump); continue; } @@ -295,30 +392,53 @@ private void Print(SyntaxNodeOrToken node, bool dump) { if (dump) { - switch (node.Kind()) + if (!node.IsMissing && ShouldIncludeText(node.Kind())) { - case SyntaxKind.IdentifierToken: - case SyntaxKind.NumericLiteralToken: - case SyntaxKind.StringLiteralToken: - case SyntaxKind.Utf8StringLiteralToken: - case SyntaxKind.SingleLineRawStringLiteralToken: - case SyntaxKind.Utf8SingleLineRawStringLiteralToken: - case SyntaxKind.MultiLineRawStringLiteralToken: - case SyntaxKind.Utf8MultiLineRawStringLiteralToken: - if (node.IsMissing) - { - goto default; - } - var value = node.ToString().Replace("\"", "\\\""); - _output.WriteLine(@"N(SyntaxKind.{0}, ""{1}"");", node.Kind(), value); - break; - default: - _output.WriteLine("{0}(SyntaxKind.{1});", node.IsMissing ? "M" : "N", node.Kind()); - break; + var value = node.ToString().Replace("\"", "\\\""); + _output.WriteLine(@"N(SyntaxKind.{0}, ""{1}"");", node.Kind(), value); } + else + { + _output.WriteLine("{0}(SyntaxKind.{1});", node.IsMissing ? "M" : "N", node.Kind()); + } + } + } + + private void Print(SyntaxTrivia trivia, bool trailing, bool dump) + { + if (dump) + { + string? value = ShouldIncludeText(trivia.Kind()) + ? $""" + , "{trivia.ToString().Replace("\"", "\\\"").ReplaceLineEndings("\\n")}" + """ + : null; + _output.WriteLine($""" + {(trailing ? "T" : "L")}(SyntaxKind.{trivia.Kind()}{value}); + """); } } + private static bool ShouldIncludeText(SyntaxKind kind) + { + // This can be changed without failing existing tests, + // it only affects the baseline output printed when a test fails. + return kind + is SyntaxKind.IdentifierToken + or SyntaxKind.NumericLiteralToken + or SyntaxKind.StringLiteralToken + or SyntaxKind.Utf8StringLiteralToken + or SyntaxKind.SingleLineRawStringLiteralToken + or SyntaxKind.Utf8SingleLineRawStringLiteralToken + or SyntaxKind.MultiLineRawStringLiteralToken + or SyntaxKind.Utf8MultiLineRawStringLiteralToken + or SyntaxKind.BadToken + or SyntaxKind.WhitespaceTrivia + or SyntaxKind.EndOfLineTrivia + or SyntaxKind.PreprocessingMessageTrivia + ; + } + private void Open(bool dump) { if (dump) @@ -379,5 +499,45 @@ protected static void ParseIncompleteSyntax(string text) return tokensBuilder.ToImmutableAndFree(); } } + + private readonly struct SyntaxNodeOrTokenOrTrivia + { + public bool IsTrivia { get; } + public bool IsTrailing { get; } + public SyntaxNodeOrToken NodeOrToken { get; } + public SyntaxTrivia Trivia { get; } + + public SyntaxNodeOrTokenOrTrivia(SyntaxNodeOrToken nodeOrToken) + { + NodeOrToken = nodeOrToken; + Trivia = default; + IsTrivia = false; + IsTrailing = false; + } + + public SyntaxNodeOrTokenOrTrivia(SyntaxTrivia trivia, bool trailing) + { + NodeOrToken = default; + Trivia = trivia; + IsTrivia = true; + IsTrailing = trailing; + } + + public bool IsMissing => !IsTrivia && NodeOrToken.IsMissing; + + public SyntaxKind Kind() => IsTrivia ? Trivia.Kind() : NodeOrToken.Kind(); + + public override string ToString() => IsTrivia ? Trivia.ToString() : NodeOrToken.ToString(); + + public static implicit operator SyntaxNodeOrTokenOrTrivia(SyntaxNode node) + { + return new SyntaxNodeOrTokenOrTrivia(node); + } + + public static implicit operator SyntaxNodeOrTokenOrTrivia(SyntaxNodeOrToken nodeOrToken) + { + return new SyntaxNodeOrTokenOrTrivia(nodeOrToken); + } + } } } diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/ScriptParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/ScriptParsingTests.cs index 18a55b0dd7804..1ed38eebcfb49 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/ScriptParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/ScriptParsingTests.cs @@ -9716,8 +9716,7 @@ public void ShebangInComment() [Fact] public void ShebangNotInScript() { - ParseAndValidate("#!/usr/bin/env csi", TestOptions.Regular, - new ErrorDescription { Code = (int)ErrorCode.ERR_PPDirectiveExpected, Line = 1, Column = 1 }); + ParseAndValidate("#!/usr/bin/env csi", TestOptions.Regular); } private void TestShebang(SyntaxTrivia trivia, string expectedSkippedText) diff --git a/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxNodeTests.cs b/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxNodeTests.cs index 645ee0ad29ad3..913605abf6fbc 100644 --- a/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxNodeTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxNodeTests.cs @@ -383,10 +383,11 @@ public void TestContainsDirective() testContainsHelper1("#undef x", SyntaxKind.UndefDirectiveTrivia); testContainsHelper1("#warning", SyntaxKind.WarningDirectiveTrivia); - // #! is special and is only recognized at start of a script file and nowhere else. + // #! is special and is only recognized at start of a file and nowhere else. testContainsHelper2(new[] { SyntaxKind.ShebangDirectiveTrivia }, SyntaxFactory.ParseCompilationUnit("#!command", options: TestOptions.Script)); testContainsHelper2(new[] { SyntaxKind.BadDirectiveTrivia }, SyntaxFactory.ParseCompilationUnit(" #!command", options: TestOptions.Script)); - testContainsHelper2(new[] { SyntaxKind.BadDirectiveTrivia }, SyntaxFactory.ParseCompilationUnit("#!command", options: TestOptions.Regular)); + testContainsHelper2(new[] { SyntaxKind.ShebangDirectiveTrivia }, SyntaxFactory.ParseCompilationUnit("#!command", options: TestOptions.Regular)); + testContainsHelper2([SyntaxKind.IgnoredDirectiveTrivia], SyntaxFactory.ParseCompilationUnit("#:x")); return; @@ -470,7 +471,7 @@ static void testContainsHelper2(SyntaxKind[] directiveKinds, CompilationUnitSynt { Assert.True(compilationUnit.ContainsDirectives); foreach (var directiveKind in directiveKinds) - Assert.True(compilationUnit.ContainsDirective(directiveKind)); + Assert.True(compilationUnit.ContainsDirective(directiveKind), directiveKind.ToString()); for (var kind = SyntaxKind.TildeToken; kind < SyntaxKind.XmlElement; kind++) { diff --git a/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxNormalizerTests.cs b/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxNormalizerTests.cs index 4abda44062fae..856a0faa50743 100644 --- a/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxNormalizerTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxNormalizerTests.cs @@ -3705,6 +3705,27 @@ void Goo(A x) """); } + [Fact] + public void IgnoredDirectives() + { + TestNormalizeDeclaration(""" + #:a + #: b c + { + #:d + } + #:e + """, """ + #:a + #:b c + { + #:d + } + #:e + + """); + } + [Fact, WorkItem(542887, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542887")] public void TestFormattingForBlockSyntax() { diff --git a/src/Compilers/Core/Portable/InternalUtilities/RoslynExperiments.cs b/src/Compilers/Core/Portable/InternalUtilities/RoslynExperiments.cs index 9394f13b21c30..3919a71673d49 100644 --- a/src/Compilers/Core/Portable/InternalUtilities/RoslynExperiments.cs +++ b/src/Compilers/Core/Portable/InternalUtilities/RoslynExperiments.cs @@ -17,4 +17,7 @@ internal static class RoslynExperiments internal const string GeneratorHostOutputs = "RSEXPERIMENTAL004"; internal const string GeneratorHostOutputs_Url = "https://github.com/dotnet/roslyn/issues/74753"; + + internal const string IgnoredDirectives = "RSEXPERIMENTAL005"; + internal const string IgnoredDirectives_Url = "https://github.com/dotnet/roslyn/issues/77697"; } diff --git a/src/Compilers/Core/RebuildTest/CSharpDeterministicKeyBuilderTests.cs b/src/Compilers/Core/RebuildTest/CSharpDeterministicKeyBuilderTests.cs index f8f1d60ede2ea..ca95cc1bf5288 100644 --- a/src/Compilers/Core/RebuildTest/CSharpDeterministicKeyBuilderTests.cs +++ b/src/Compilers/Core/RebuildTest/CSharpDeterministicKeyBuilderTests.cs @@ -55,7 +55,7 @@ protected override CSharpCompilation CreateCompilation(SyntaxTree[] syntaxTrees, public void VerifyUpToDate() { verifyCount(11); - verifyCount(12); + verifyCount(13); verifyCount(63); verifyCount(9); diff --git a/src/EditorFeatures/CSharpTest/Classification/SyntacticClassifierTests.cs b/src/EditorFeatures/CSharpTest/Classification/SyntacticClassifierTests.cs index 28358c6810405..a84ea085613c6 100644 --- a/src/EditorFeatures/CSharpTest/Classification/SyntacticClassifierTests.cs +++ b/src/EditorFeatures/CSharpTest/Classification/SyntacticClassifierTests.cs @@ -1504,8 +1504,7 @@ public async Task ShebangAsFirstCommentInNonScript(TestHost testHost) var expected = new[] { - PPKeyword("#"), - PPText("!/usr/bin/env scriptcs"), + Comment("#!/usr/bin/env scriptcs"), Identifier("System"), Operators.Dot, Identifier("Console"), diff --git a/src/Tools/SemanticSearch/ReferenceAssemblies/Apis/Microsoft.CodeAnalysis.CSharp.txt b/src/Tools/SemanticSearch/ReferenceAssemblies/Apis/Microsoft.CodeAnalysis.CSharp.txt index b37e71720462c..31577ead6d1b7 100644 --- a/src/Tools/SemanticSearch/ReferenceAssemblies/Apis/Microsoft.CodeAnalysis.CSharp.txt +++ b/src/Tools/SemanticSearch/ReferenceAssemblies/Apis/Microsoft.CodeAnalysis.CSharp.txt @@ -431,6 +431,7 @@ Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitGroupClause(Microsoft.Co Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitIdentifierName(Microsoft.CodeAnalysis.CSharp.Syntax.IdentifierNameSyntax) Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitIfDirectiveTrivia(Microsoft.CodeAnalysis.CSharp.Syntax.IfDirectiveTriviaSyntax) Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitIfStatement(Microsoft.CodeAnalysis.CSharp.Syntax.IfStatementSyntax) +Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitIgnoredDirectiveTrivia(Microsoft.CodeAnalysis.CSharp.Syntax.IgnoredDirectiveTriviaSyntax) Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitImplicitArrayCreationExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ImplicitArrayCreationExpressionSyntax) Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitImplicitElementAccess(Microsoft.CodeAnalysis.CSharp.Syntax.ImplicitElementAccessSyntax) Microsoft.CodeAnalysis.CSharp.CSharpSyntaxRewriter.VisitImplicitObjectCreationExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ImplicitObjectCreationExpressionSyntax) @@ -726,6 +727,7 @@ Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitGroupClause(Microsoft.Cod Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitIdentifierName(Microsoft.CodeAnalysis.CSharp.Syntax.IdentifierNameSyntax) Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitIfDirectiveTrivia(Microsoft.CodeAnalysis.CSharp.Syntax.IfDirectiveTriviaSyntax) Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitIfStatement(Microsoft.CodeAnalysis.CSharp.Syntax.IfStatementSyntax) +Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitIgnoredDirectiveTrivia(Microsoft.CodeAnalysis.CSharp.Syntax.IgnoredDirectiveTriviaSyntax) Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitImplicitArrayCreationExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ImplicitArrayCreationExpressionSyntax) Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitImplicitElementAccess(Microsoft.CodeAnalysis.CSharp.Syntax.ImplicitElementAccessSyntax) Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor.VisitImplicitObjectCreationExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ImplicitObjectCreationExpressionSyntax) @@ -975,6 +977,7 @@ Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor`1.VisitGroupClause(Microsoft.C Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor`1.VisitIdentifierName(Microsoft.CodeAnalysis.CSharp.Syntax.IdentifierNameSyntax) Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor`1.VisitIfDirectiveTrivia(Microsoft.CodeAnalysis.CSharp.Syntax.IfDirectiveTriviaSyntax) Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor`1.VisitIfStatement(Microsoft.CodeAnalysis.CSharp.Syntax.IfStatementSyntax) +Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor`1.VisitIgnoredDirectiveTrivia(Microsoft.CodeAnalysis.CSharp.Syntax.IgnoredDirectiveTriviaSyntax) Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor`1.VisitImplicitArrayCreationExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ImplicitArrayCreationExpressionSyntax) Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor`1.VisitImplicitElementAccess(Microsoft.CodeAnalysis.CSharp.Syntax.ImplicitElementAccessSyntax) Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor`1.VisitImplicitObjectCreationExpression(Microsoft.CodeAnalysis.CSharp.Syntax.ImplicitObjectCreationExpressionSyntax) @@ -2826,6 +2829,18 @@ Microsoft.CodeAnalysis.CSharp.Syntax.IfStatementSyntax.get_Else Microsoft.CodeAnalysis.CSharp.Syntax.IfStatementSyntax.get_IfKeyword Microsoft.CodeAnalysis.CSharp.Syntax.IfStatementSyntax.get_OpenParenToken Microsoft.CodeAnalysis.CSharp.Syntax.IfStatementSyntax.get_Statement +Microsoft.CodeAnalysis.CSharp.Syntax.IgnoredDirectiveTriviaSyntax +Microsoft.CodeAnalysis.CSharp.Syntax.IgnoredDirectiveTriviaSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor) +Microsoft.CodeAnalysis.CSharp.Syntax.IgnoredDirectiveTriviaSyntax.Accept``1(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor{``0}) +Microsoft.CodeAnalysis.CSharp.Syntax.IgnoredDirectiveTriviaSyntax.Update(Microsoft.CodeAnalysis.SyntaxToken,Microsoft.CodeAnalysis.SyntaxToken,Microsoft.CodeAnalysis.SyntaxToken,System.Boolean) +Microsoft.CodeAnalysis.CSharp.Syntax.IgnoredDirectiveTriviaSyntax.WithColonToken(Microsoft.CodeAnalysis.SyntaxToken) +Microsoft.CodeAnalysis.CSharp.Syntax.IgnoredDirectiveTriviaSyntax.WithEndOfDirectiveToken(Microsoft.CodeAnalysis.SyntaxToken) +Microsoft.CodeAnalysis.CSharp.Syntax.IgnoredDirectiveTriviaSyntax.WithHashToken(Microsoft.CodeAnalysis.SyntaxToken) +Microsoft.CodeAnalysis.CSharp.Syntax.IgnoredDirectiveTriviaSyntax.WithIsActive(System.Boolean) +Microsoft.CodeAnalysis.CSharp.Syntax.IgnoredDirectiveTriviaSyntax.get_ColonToken +Microsoft.CodeAnalysis.CSharp.Syntax.IgnoredDirectiveTriviaSyntax.get_EndOfDirectiveToken +Microsoft.CodeAnalysis.CSharp.Syntax.IgnoredDirectiveTriviaSyntax.get_HashToken +Microsoft.CodeAnalysis.CSharp.Syntax.IgnoredDirectiveTriviaSyntax.get_IsActive Microsoft.CodeAnalysis.CSharp.Syntax.ImplicitArrayCreationExpressionSyntax Microsoft.CodeAnalysis.CSharp.Syntax.ImplicitArrayCreationExpressionSyntax.Accept(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor) Microsoft.CodeAnalysis.CSharp.Syntax.ImplicitArrayCreationExpressionSyntax.Accept``1(Microsoft.CodeAnalysis.CSharp.CSharpSyntaxVisitor{``0}) @@ -5060,6 +5075,8 @@ Microsoft.CodeAnalysis.CSharp.SyntaxFactory.IfStatement(Microsoft.CodeAnalysis.C Microsoft.CodeAnalysis.CSharp.SyntaxFactory.IfStatement(Microsoft.CodeAnalysis.SyntaxList{Microsoft.CodeAnalysis.CSharp.Syntax.AttributeListSyntax},Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax,Microsoft.CodeAnalysis.CSharp.Syntax.StatementSyntax,Microsoft.CodeAnalysis.CSharp.Syntax.ElseClauseSyntax) Microsoft.CodeAnalysis.CSharp.SyntaxFactory.IfStatement(Microsoft.CodeAnalysis.SyntaxList{Microsoft.CodeAnalysis.CSharp.Syntax.AttributeListSyntax},Microsoft.CodeAnalysis.SyntaxToken,Microsoft.CodeAnalysis.SyntaxToken,Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax,Microsoft.CodeAnalysis.SyntaxToken,Microsoft.CodeAnalysis.CSharp.Syntax.StatementSyntax,Microsoft.CodeAnalysis.CSharp.Syntax.ElseClauseSyntax) Microsoft.CodeAnalysis.CSharp.SyntaxFactory.IfStatement(Microsoft.CodeAnalysis.SyntaxToken,Microsoft.CodeAnalysis.SyntaxToken,Microsoft.CodeAnalysis.CSharp.Syntax.ExpressionSyntax,Microsoft.CodeAnalysis.SyntaxToken,Microsoft.CodeAnalysis.CSharp.Syntax.StatementSyntax,Microsoft.CodeAnalysis.CSharp.Syntax.ElseClauseSyntax) +Microsoft.CodeAnalysis.CSharp.SyntaxFactory.IgnoredDirectiveTrivia(Microsoft.CodeAnalysis.SyntaxToken,Microsoft.CodeAnalysis.SyntaxToken,Microsoft.CodeAnalysis.SyntaxToken,System.Boolean) +Microsoft.CodeAnalysis.CSharp.SyntaxFactory.IgnoredDirectiveTrivia(System.Boolean) Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ImplicitArrayCreationExpression(Microsoft.CodeAnalysis.CSharp.Syntax.InitializerExpressionSyntax) Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ImplicitArrayCreationExpression(Microsoft.CodeAnalysis.SyntaxToken,Microsoft.CodeAnalysis.SyntaxToken,Microsoft.CodeAnalysis.SyntaxTokenList,Microsoft.CodeAnalysis.SyntaxToken,Microsoft.CodeAnalysis.CSharp.Syntax.InitializerExpressionSyntax) Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ImplicitArrayCreationExpression(Microsoft.CodeAnalysis.SyntaxTokenList,Microsoft.CodeAnalysis.CSharp.Syntax.InitializerExpressionSyntax) @@ -5915,6 +5932,7 @@ Microsoft.CodeAnalysis.CSharp.SyntaxKind.IdentifierToken Microsoft.CodeAnalysis.CSharp.SyntaxKind.IfDirectiveTrivia Microsoft.CodeAnalysis.CSharp.SyntaxKind.IfKeyword Microsoft.CodeAnalysis.CSharp.SyntaxKind.IfStatement +Microsoft.CodeAnalysis.CSharp.SyntaxKind.IgnoredDirectiveTrivia Microsoft.CodeAnalysis.CSharp.SyntaxKind.ImplicitArrayCreationExpression Microsoft.CodeAnalysis.CSharp.SyntaxKind.ImplicitElementAccess Microsoft.CodeAnalysis.CSharp.SyntaxKind.ImplicitKeyword