diff --git a/eng/config/globalconfigs/Common.globalconfig b/eng/config/globalconfigs/Common.globalconfig index b3339efbab8ce..1766acf873729 100644 --- a/eng/config/globalconfigs/Common.globalconfig +++ b/eng/config/globalconfigs/Common.globalconfig @@ -41,7 +41,7 @@ dotnet_diagnostic.RS0006.severity = error dotnet_diagnostic.RS0012.severity = warning dotnet_diagnostic.RS0014.severity = warning dotnet_diagnostic.RS0015.severity = warning -dotnet_diagnostic.RS0016.severity = error +dotnet_diagnostic.RS0016.severity = none # PROTOTYPE(ft): re-enable before feature merge dotnet_diagnostic.RS0017.severity = error dotnet_diagnostic.RS0018.severity = warning dotnet_diagnostic.RS0022.severity = error diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index d05760fe0229b..c779781950f88 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -7091,4 +7091,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ unsigned right shift + + file types + diff --git a/src/Compilers/CSharp/Portable/Declarations/DeclarationModifiers.cs b/src/Compilers/CSharp/Portable/Declarations/DeclarationModifiers.cs index 7f4f224ad24b3..f42d991e744d6 100644 --- a/src/Compilers/CSharp/Portable/Declarations/DeclarationModifiers.cs +++ b/src/Compilers/CSharp/Portable/Declarations/DeclarationModifiers.cs @@ -36,8 +36,12 @@ internal enum DeclarationModifiers : uint Async = 1 << 20, Ref = 1 << 21, // used only for structs - All = (1 << 23) - 1, // all modifiers - Unset = 1 << 23, // used when a modifiers value hasn't yet been computed + + // PROTOTYPE(ft): leaving 22 free since required is using it + File = 1 << 23, // used only for types + + All = (1 << 24) - 1, // all modifiers + Unset = 1 << 24, // used when a modifiers value hasn't yet been computed AccessibilityMask = PrivateProtected | Private | Protected | Internal | ProtectedInternal | Public, } diff --git a/src/Compilers/CSharp/Portable/Errors/MessageID.cs b/src/Compilers/CSharp/Portable/Errors/MessageID.cs index e2266ed44bead..5070db6cb72d0 100644 --- a/src/Compilers/CSharp/Portable/Errors/MessageID.cs +++ b/src/Compilers/CSharp/Portable/Errors/MessageID.cs @@ -253,6 +253,8 @@ internal enum MessageID IDS_FeatureUnsignedRightShift = MessageBase + 12823, IDS_FeatureExtendedNameofScope = MessageBase + 12824, + + IDS_FeatureFileTypes = MessageBase + 12850, // PROTOTYPE(ft): pack ID before merge } // Message IDs may refer to strings that need to be localized. @@ -375,6 +377,7 @@ internal static LanguageVersion RequiredVersion(this MessageID feature) case MessageID.IDS_FeatureUTF8StringLiterals: // semantic check case MessageID.IDS_FeatureUnsignedRightShift: // semantic check for declarations and consumption, parsing check for doc comments case MessageID.IDS_FeatureExtendedNameofScope: // semantic check + case MessageID.IDS_FeatureFileTypes: // semantic check return LanguageVersion.Preview; // C# 10.0 features. diff --git a/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4 b/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4 index 2adb71f2ceb9d..da6c46a3367d2 100644 --- a/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4 +++ b/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4 @@ -99,6 +99,7 @@ modifier | 'async' | 'const' | 'extern' + | 'file' | 'fixed' | 'internal' | 'new' diff --git a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs index 7504624b559aa..5450bd9459492 100644 --- a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs +++ b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs @@ -1163,6 +1163,8 @@ internal static DeclarationModifiers GetModifier(SyntaxKind kind, SyntaxKind con return DeclarationModifiers.Partial; case SyntaxKind.AsyncKeyword: return DeclarationModifiers.Async; + case SyntaxKind.FileKeyword: + return DeclarationModifiers.File; } goto default; @@ -1243,8 +1245,18 @@ private void ParseModifiers(SyntaxListBuilder tokens, bool forAccessors) break; } + case DeclarationModifiers.File: + if (!IsFeatureEnabled(MessageID.IDS_FeatureFileTypes) && !ShouldContextualKeywordBeTreatedAsModifier(parsingStatementNotDeclaration: false)) + { + return; + } + + // LangVersion errors for 'file' modifier are given during binding. + modTok = ConvertToKeyword(EatToken()); + break; + case DeclarationModifiers.Async: - if (!ShouldAsyncBeTreatedAsModifier(parsingStatementNotDeclaration: false)) + if (!ShouldContextualKeywordBeTreatedAsModifier(parsingStatementNotDeclaration: false)) { return; } @@ -1281,16 +1293,16 @@ bool isStructOrRecordKeyword(SyntaxToken token) } } - private bool ShouldAsyncBeTreatedAsModifier(bool parsingStatementNotDeclaration) + private bool ShouldContextualKeywordBeTreatedAsModifier(bool parsingStatementNotDeclaration) { - Debug.Assert(this.CurrentToken.ContextualKind == SyntaxKind.AsyncKeyword); + Debug.Assert(this.CurrentToken.Kind == SyntaxKind.IdentifierToken && GetModifier(this.CurrentToken) != DeclarationModifiers.None); // Adapted from CParser::IsAsyncMethod. if (IsNonContextualModifier(PeekToken(1))) { // If the next token is a (non-contextual) modifier keyword, then this token is - // definitely the async keyword + // definitely a modifier return true; } @@ -1301,7 +1313,7 @@ private bool ShouldAsyncBeTreatedAsModifier(bool parsingStatementNotDeclaration) try { - this.EatToken(); //move past contextual 'async' + this.EatToken(); //move past contextual token if (!parsingStatementNotDeclaration && (this.CurrentToken.ContextualKind == SyntaxKind.PartialKeyword)) @@ -1309,13 +1321,12 @@ private bool ShouldAsyncBeTreatedAsModifier(bool parsingStatementNotDeclaration) this.EatToken(); // "partial" doesn't affect our decision, so look past it. } - // Comment directly from CParser::IsAsyncMethod. - // ... 'async' [partial] ... - // ... 'async' [partial] ... - // ... 'async' [partial] ... - // ... 'async' [partial] ... - // ... 'async' [partial] ... - // ... 'async' [partial] ... + // ... 'TOKEN' [partial] ... + // ... 'TOKEN' [partial] ... + // ... 'TOKEN' [partial] ... + // ... 'TOKEN' [partial] ... + // ... 'TOKEN' [partial] ... + // ... 'TOKEN' [partial] ... // DEVNOTE: Although we parse async user defined conversions, operators, etc. here, // anything other than async methods are detected as erroneous later, during the define phase @@ -1332,56 +1343,56 @@ private bool ShouldAsyncBeTreatedAsModifier(bool parsingStatementNotDeclaration) if (ScanType() != ScanTypeFlags.NotType) { - // We've seen "async TypeName". Now we have to determine if we should we treat - // 'async' as a modifier. Or is the user actually writing something like - // "public async Goo" where 'async' is actually the return type. + // We've seen "TOKEN TypeName". Now we have to determine if we should we treat + // 'TOKEN' as a modifier. Or is the user actually writing something like + // "public TOKEN Goo" where 'TOKEN' is actually the return type. if (IsPossibleMemberName()) { - // we have: "async Type X" or "async Type this", 'async' is definitely a + // we have: "TOKEN Type X" or "TOKEN Type this", 'TOKEN' is definitely a // modifier here. return true; } var currentTokenKind = this.CurrentToken.Kind; - // The file ends with "async TypeName", it's not legal code, and it's much + // The file ends with "TOKEN TypeName", it's not legal code, and it's much // more likely that this is meant to be a modifier. if (currentTokenKind == SyntaxKind.EndOfFileToken) { return true; } - // "async TypeName }". In this case, we just have an incomplete member, and - // we should definitely default to 'async' being considered a return type here. + // "TOKEN TypeName }". In this case, we just have an incomplete member, and + // we should definitely default to 'TOKEN' being considered a return type here. if (currentTokenKind == SyntaxKind.CloseBraceToken) { return true; } - // "async TypeName void". In this case, we just have an incomplete member before - // an existing member. Treat this 'async' as a keyword. + // "TOKEN TypeName void". In this case, we just have an incomplete member before + // an existing member. Treat this 'TOKEN' as a keyword. if (SyntaxFacts.IsPredefinedType(this.CurrentToken.Kind)) { return true; } - // "async TypeName public". In this case, we just have an incomplete member before - // an existing member. Treat this 'async' as a keyword. + // "TOKEN TypeName public". In this case, we just have an incomplete member before + // an existing member. Treat this 'TOKEN' as a keyword. if (IsNonContextualModifier(this.CurrentToken)) { return true; } - // "async TypeName class". In this case, we just have an incomplete member before - // an existing type declaration. Treat this 'async' as a keyword. + // "TOKEN TypeName class". In this case, we just have an incomplete member before + // an existing type declaration. Treat this 'TOKEN' as a keyword. if (IsTypeDeclarationStart()) { return true; } - // "async TypeName namespace". In this case, we just have an incomplete member before - // an existing namespace declaration. Treat this 'async' as a keyword. + // "TOKEN TypeName namespace". In this case, we just have an incomplete member before + // an existing namespace declaration. Treat this 'TOKEN' as a keyword. if (currentTokenKind == SyntaxKind.NamespaceKeyword) { return true; @@ -2661,8 +2672,7 @@ static bool isAcceptableNonDeclarationStatement(StatementSyntax statement, bool private bool IsMisplacedModifier(SyntaxListBuilder modifiers, SyntaxList attributes, TypeSyntax type, out MemberDeclarationSyntax result) { if (GetModifier(this.CurrentToken) != DeclarationModifiers.None && - this.CurrentToken.ContextualKind != SyntaxKind.PartialKeyword && - this.CurrentToken.ContextualKind != SyntaxKind.AsyncKeyword && + this.CurrentToken.ContextualKind is not (SyntaxKind.PartialKeyword or SyntaxKind.AsyncKeyword or SyntaxKind.FileKeyword) && IsComplete(type)) { var misplacedModifier = this.CurrentToken; @@ -7969,7 +7979,7 @@ private bool IsPossibleLocalDeclarationStatement(bool isGlobalScriptLevel) tk = this.CurrentToken.ContextualKind; var isPossibleAttributeOrModifier = (IsAdditionalLocalFunctionModifier(tk) || tk == SyntaxKind.OpenBracketToken) - && (tk != SyntaxKind.AsyncKeyword || ShouldAsyncBeTreatedAsModifier(parsingStatementNotDeclaration: true)); + && (tk != SyntaxKind.AsyncKeyword || ShouldContextualKeywordBeTreatedAsModifier(parsingStatementNotDeclaration: true)); if (isPossibleAttributeOrModifier) { return true; diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/ModifierUtils.cs b/src/Compilers/CSharp/Portable/Symbols/Source/ModifierUtils.cs index f28cdf1356928..433b7550cb820 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/ModifierUtils.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/ModifierUtils.cs @@ -86,6 +86,11 @@ internal static DeclarationModifiers CheckModifiers( modifierErrors |= !Binder.CheckFeatureAvailability(errorLocation.SourceTree, MessageID.IDS_FeaturePrivateProtected, diagnostics, errorLocation); } + if ((result & DeclarationModifiers.File) != 0) + { + modifierErrors |= !Binder.CheckFeatureAvailability(errorLocation.SourceTree, MessageID.IDS_FeatureFileTypes, diagnostics, errorLocation); + } + return result; } @@ -281,6 +286,8 @@ internal static string ConvertSingleModifierToSyntaxText(DeclarationModifiers mo return SyntaxFacts.GetText(SyntaxKind.AsyncKeyword); case DeclarationModifiers.Ref: return SyntaxFacts.GetText(SyntaxKind.RefKeyword); + case DeclarationModifiers.File: + return SyntaxFacts.GetText(SyntaxKind.FileKeyword); default: throw ExceptionUtilities.UnexpectedValue(modifier); } @@ -328,6 +335,8 @@ private static DeclarationModifiers ToDeclarationModifier(SyntaxKind kind) return DeclarationModifiers.Volatile; case SyntaxKind.RefKeyword: return DeclarationModifiers.Ref; + case SyntaxKind.FileKeyword: + return DeclarationModifiers.File; default: throw ExceptionUtilities.UnexpectedValue(kind); } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs index cd25021d1d4d5..062255f17974c 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs @@ -249,7 +249,8 @@ private DeclarationModifiers MakeModifiers(TypeKind typeKind, BindingDiagnosticB { Symbol containingSymbol = this.ContainingSymbol; DeclarationModifiers defaultAccess; - var allowedModifiers = DeclarationModifiers.AccessibilityMask; + // PROTOTYPE(ft): confirm whether 'file' types can be nested + var allowedModifiers = DeclarationModifiers.AccessibilityMask | DeclarationModifiers.File; if (containingSymbol.Kind == SymbolKind.Namespace) { diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs index 112f15b9b8343..4da3999520625 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs @@ -405,6 +405,9 @@ public enum SyntaxKind : ushort /// Represents . UnmanagedKeyword = 8446, + /// Represents . + FileKeyword = 8447, + // when adding a contextual keyword following functions must be adapted: // // diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs index 1ffefc6557ffb..6577fed1a2090 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs @@ -1138,7 +1138,7 @@ public static SyntaxKind GetPreprocessorKeywordKind(string text) public static IEnumerable GetContextualKeywordKinds() { - for (int i = (int)SyntaxKind.YieldKeyword; i <= (int)SyntaxKind.UnmanagedKeyword; i++) + for (int i = (int)SyntaxKind.YieldKeyword; i <= (int)SyntaxKind.FileKeyword; i++) // PROTOTYPE(ft): will conflict with required { yield return (SyntaxKind)i; } @@ -1191,6 +1191,7 @@ public static bool IsContextualKeyword(SyntaxKind kind) case SyntaxKind.RecordKeyword: case SyntaxKind.ManagedKeyword: case SyntaxKind.UnmanagedKeyword: + case SyntaxKind.FileKeyword: return true; default: return false; @@ -1310,6 +1311,8 @@ public static SyntaxKind GetContextualKeywordKind(string text) return SyntaxKind.ManagedKeyword; case "unmanaged": return SyntaxKind.UnmanagedKeyword; + case "file": + return SyntaxKind.FileKeyword; default: return SyntaxKind.None; } @@ -1751,6 +1754,8 @@ public static string GetText(SyntaxKind kind) return "managed"; case SyntaxKind.UnmanagedKeyword: return "unmanaged"; + case SyntaxKind.FileKeyword: + return "file"; default: return string.Empty; } diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index 55dda0b93eacd..b92a529983355 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -1477,6 +1477,11 @@ obor názvů pro celý soubor + + file types + file types + + generic attributes obecné atributy diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index 21a69156cbe6c..d810eb2b31e83 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -1477,6 +1477,11 @@ Dateibereichsnamespace + + file types + file types + + generic attributes Generische Attribute diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index b47e9241de939..f0cbc782552ab 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -1477,6 +1477,11 @@ espacio de nombres con ámbito de archivo + + file types + file types + + generic attributes atributos genéricos diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index 74ab389c8ae18..386b55de2416a 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -1477,6 +1477,11 @@ espace de noms inclus dans l'étendue de fichier + + file types + file types + + generic attributes attributs génériques diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index c92c607c46ea6..30d4680434080 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -1477,6 +1477,11 @@ spazio dei nomi con ambito file + + file types + file types + + generic attributes attributi generici diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index 70a9b6ea60df3..e5caa8f74442b 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -1477,6 +1477,11 @@ ファイルスコープの名前空間 + + file types + file types + + generic attributes 汎用属性 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index 67692f912a123..3cae36e463245 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -1477,6 +1477,11 @@ 파일 범위 네임스페이스 + + file types + file types + + generic attributes 제네릭 특성 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index 76ce08171770f..2146a592c67a3 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -1477,6 +1477,11 @@ przestrzeń nazw z określonym zakresem plików + + file types + file types + + generic attributes atrybuty ogólne diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index 9408d573e96f6..7f9ed175d0c85 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -1477,6 +1477,11 @@ namespace de escopo de arquivo + + file types + file types + + generic attributes atributos genéricos diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index 3cafc50cb8524..0c6369f0f8bcc 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -1477,6 +1477,11 @@ пространство имен с файловой областью + + file types + file types + + generic attributes универсальные атрибуты diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index f9690e228a1e1..b5dbed29ec3ee 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -1477,6 +1477,11 @@ dosya kapsamlı ad alanı + + file types + file types + + generic attributes genel öznitelikler diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index cb476cfa1b2b7..d34e183163cea 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -1477,6 +1477,11 @@ 文件范围内的命名空间 + + file types + file types + + generic attributes 通用属性 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index 7544797983a45..c7eabe25da772 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -1477,6 +1477,11 @@ 以檔案為範圍的命名空間 + + file types + file types + + generic attributes 一般屬性 diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FileModifierTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FileModifierTests.cs new file mode 100644 index 0000000000000..aeceafa616a16 --- /dev/null +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/Source/FileModifierTests.cs @@ -0,0 +1,49 @@ +// 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 Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests +{ + public class FileModifierTests : CSharpTestBase + { + [Fact] + public void LangVersion() + { + var source = """ + file class C { } + """; + + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + comp.VerifyDiagnostics( + // (1,12): error CS8652: The feature 'file types' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // file class C { } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "C").WithArguments("file types").WithLocation(1, 12)); + + comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + } + + [Fact] + public void Nested() + { + var source = """ + class Outer + { + file class C { } + } + """; + + var comp = CreateCompilation(source, parseOptions: TestOptions.Regular10); + comp.VerifyDiagnostics( + // (3,16): error CS8652: The feature 'file types' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // file class C { } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "C").WithArguments("file types").WithLocation(3, 16)); + + comp = CreateCompilation(source); + comp.VerifyDiagnostics(); + } + } +} diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/FileModifierParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/FileModifierParsingTests.cs new file mode 100644 index 0000000000000..14c5f663d3e76 --- /dev/null +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/FileModifierParsingTests.cs @@ -0,0 +1,2680 @@ +// 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; +using System.Linq; +using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Microsoft.CodeAnalysis.Test.Utilities; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests +{ + public class FileModifierParsingTests : ParsingTests + { + public FileModifierParsingTests(ITestOutputHelper output) : base(output) { } + + protected override SyntaxTree ParseTree(string text, CSharpParseOptions? options) + { + return SyntaxFactory.ParseSyntaxTree(text, options ?? TestOptions.Regular); + } + + private void UsingNode(string text, params DiagnosticDescription[] expectedDiagnostics) + { + UsingNode(text, options: null, expectedParsingDiagnostics: expectedDiagnostics); + } + + private new void UsingNode(string text, CSharpParseOptions? options, params DiagnosticDescription[] expectedDiagnostics) + { + UsingNode(text, options, expectedParsingDiagnostics: expectedDiagnostics); + } + + private void UsingNode(string text, CSharpParseOptions? options = null, DiagnosticDescription[]? expectedParsingDiagnostics = null, DiagnosticDescription[]? expectedBindingDiagnostics = null) + { + options ??= TestOptions.RegularPreview; + expectedParsingDiagnostics ??= Array.Empty(); + expectedBindingDiagnostics ??= expectedParsingDiagnostics; + + var tree = UsingTree(text, options); + Validate(text, (CSharpSyntaxNode)tree.GetRoot(), expectedParsingDiagnostics); + + var comp = CreateCompilation(tree); + comp.VerifyDiagnostics(expectedBindingDiagnostics); + } + + [Theory] + [InlineData(SyntaxKind.ClassKeyword)] + [InlineData(SyntaxKind.StructKeyword)] + [InlineData(SyntaxKind.InterfaceKeyword)] + [InlineData(SyntaxKind.RecordKeyword)] + [InlineData(SyntaxKind.EnumKeyword)] + public void FileModifier_01(SyntaxKind typeKeyword) + { + UsingNode($$""" + file {{SyntaxFacts.GetText(typeKeyword)}} C { } + """); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxFacts.GetBaseTypeDeclarationKind(typeKeyword)); + { + N(SyntaxKind.FileKeyword); + N(typeKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [InlineData(SyntaxKind.ClassKeyword)] + [InlineData(SyntaxKind.StructKeyword)] + [InlineData(SyntaxKind.InterfaceKeyword)] + [InlineData(SyntaxKind.RecordKeyword)] + public void FileModifier_02(SyntaxKind typeKeyword) + { + UsingNode($$""" + file partial {{SyntaxFacts.GetText(typeKeyword)}} C { } + """); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxFacts.GetBaseTypeDeclarationKind(typeKeyword)); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.PartialKeyword); + N(typeKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileModifier_02_Enum() + { + UsingNode($$""" + file partial enum C { } + """, + expectedParsingDiagnostics: new[] + { + // (1,6): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. + // file partial enum C { } + Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(1, 6) + }, + // note: we also get duplicate ERR_PartialMisplaced diagnostics on `partial enum C { }`. + expectedBindingDiagnostics: new[] + { + // (1,6): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. + // file partial enum C { } + Diagnostic(ErrorCode.ERR_PartialMisplaced, "partial").WithLocation(1, 6), + // (1,19): error CS0267: The 'partial' modifier can only appear immediately before 'class', 'record', 'struct', 'interface', or a method return type. + // file partial enum C { } + Diagnostic(ErrorCode.ERR_PartialMisplaced, "C").WithLocation(1, 19) + }); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.EnumDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.EnumKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [InlineData(SyntaxKind.ClassKeyword)] + [InlineData(SyntaxKind.StructKeyword)] + [InlineData(SyntaxKind.InterfaceKeyword)] + public void FileModifier_03(SyntaxKind typeKeyword) + { + UsingNode($$""" + partial file {{SyntaxFacts.GetText(typeKeyword)}} C { } + """, + expectedParsingDiagnostics: new[] + { + // (1,14): error CS1002: ; expected + // partial file {{SyntaxFacts.GetText(typeKeyword)}} C { } + Diagnostic(ErrorCode.ERR_SemicolonExpected, SyntaxFacts.GetText(typeKeyword)).WithLocation(1, 14) + }, + expectedBindingDiagnostics: new[] + { + // (1,1): error CS0246: The type or namespace name 'partial' could not be found (are you missing a using directive or an assembly reference?) + // partial file interface C { } + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "partial").WithArguments("partial").WithLocation(1, 1), + // (1,9): warning CS0168: The variable 'file' is declared but never used + // partial file interface C { } + Diagnostic(ErrorCode.WRN_UnreferencedVar, "file").WithArguments("file").WithLocation(1, 9), + // (1,14): error CS1002: ; expected + // partial file {{SyntaxFacts.GetText(typeKeyword)}} C { } + Diagnostic(ErrorCode.ERR_SemicolonExpected, SyntaxFacts.GetText(typeKeyword)).WithLocation(1, 14) + }); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "partial"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "file"); + } + } + M(SyntaxKind.SemicolonToken); + } + } + N(SyntaxFacts.GetBaseTypeDeclarationKind(typeKeyword)); + { + N(typeKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + // PROTOTYPE(ft): is it fine that records parse as a single declaration here, but not other type kinds? + [Theory] + [InlineData(SyntaxKind.RecordKeyword)] + public void FileModifier_04(SyntaxKind typeKeyword) + { + UsingNode($$""" + partial file {{SyntaxFacts.GetText(typeKeyword)}} C { } + """); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxFacts.GetBaseTypeDeclarationKind(typeKeyword)); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.FileKeyword); + N(typeKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileModifier_05() + { + UsingNode($$""" + file partial record struct C { } + """); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.RecordStructDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.RecordKeyword); + N(SyntaxKind.StructKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + // PROTOTYPE(ft): is it fine that records parse here, but not other type kinds? + [Fact] + public void FileModifier_06() + { + UsingNode($$""" + partial file record struct C { } + """); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.RecordStructDeclaration); + { + N(SyntaxKind.PartialKeyword); + N(SyntaxKind.FileKeyword); + N(SyntaxKind.RecordKeyword); + N(SyntaxKind.StructKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileModifier_07_CSharp10() + { + UsingNode($$""" + file partial ref struct C { } + """, + options: TestOptions.Regular10, + expectedParsingDiagnostics: new[] + { + // (1,14): error CS1003: Syntax error, ',' expected + // file partial ref struct C { } + Diagnostic(ErrorCode.ERR_SyntaxError, "ref").WithArguments(",", "ref").WithLocation(1, 14), + // (1,18): error CS1002: ; expected + // file partial ref struct C { } + Diagnostic(ErrorCode.ERR_SemicolonExpected, "struct").WithLocation(1, 18) + }, + expectedBindingDiagnostics: new[] + { + // (1,1): error CS0246: The type or namespace name 'file' could not be found (are you missing a using directive or an assembly reference?) + // file partial ref struct C { } + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "file").WithArguments("file").WithLocation(1, 1), + // (1,6): warning CS0168: The variable 'partial' is declared but never used + // file partial ref struct C { } + Diagnostic(ErrorCode.WRN_UnreferencedVar, "partial").WithArguments("partial").WithLocation(1, 6), + // (1,14): error CS1003: Syntax error, ',' expected + // file partial ref struct C { } + Diagnostic(ErrorCode.ERR_SyntaxError, "ref").WithArguments(",", "ref").WithLocation(1, 14), + // (1,18): error CS1002: ; expected + // file partial ref struct C { } + Diagnostic(ErrorCode.ERR_SemicolonExpected, "struct").WithLocation(1, 18) + }); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "file"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "partial"); + } + } + M(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.StructDeclaration); + { + N(SyntaxKind.StructKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileModifier_07() + { + UsingNode($$""" + file partial ref struct C { } + """, + // (1,14): error CS1585: Member modifier 'ref' must precede the member type and name + // file partial ref struct C { } + Diagnostic(ErrorCode.ERR_BadModifierLocation, "ref").WithArguments("ref").WithLocation(1, 14)); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "partial"); + } + } + N(SyntaxKind.StructDeclaration); + { + N(SyntaxKind.RefKeyword); + N(SyntaxKind.StructKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileModifier_08() + { + UsingNode($$""" + partial file ref struct C { } + """, + expectedParsingDiagnostics: new[] + { + // (1,14): error CS1003: Syntax error, ',' expected + // partial file ref struct C { } + Diagnostic(ErrorCode.ERR_SyntaxError, "ref").WithArguments(",", "ref").WithLocation(1, 14), + // (1,18): error CS1002: ; expected + // partial file ref struct C { } + Diagnostic(ErrorCode.ERR_SemicolonExpected, "struct").WithLocation(1, 18) + }, + expectedBindingDiagnostics: new[] + { + // (1,1): error CS0246: The type or namespace name 'partial' could not be found (are you missing a using directive or an assembly reference?) + // partial file ref struct C { } + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "partial").WithArguments("partial").WithLocation(1, 1), + // (1,9): warning CS0168: The variable 'file' is declared but never used + // partial file ref struct C { } + Diagnostic(ErrorCode.WRN_UnreferencedVar, "file").WithArguments("file").WithLocation(1, 9), + // (1,14): error CS1003: Syntax error, ',' expected + // partial file ref struct C { } + Diagnostic(ErrorCode.ERR_SyntaxError, "ref").WithArguments(",", "ref").WithLocation(1, 14), + // (1,18): error CS1002: ; expected + // partial file ref struct C { } + Diagnostic(ErrorCode.ERR_SemicolonExpected, "struct").WithLocation(1, 18) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "partial"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "file"); + } + } + M(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.StructDeclaration); + { + N(SyntaxKind.StructKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileModifier_09() + { + UsingNode($$""" + file abstract class C { } + """); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.AbstractKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileModifier_10() + { + UsingNode($$""" + abstract file class C { } + """); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.AbstractKeyword); + N(SyntaxKind.FileKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [InlineData(SyntaxKind.ClassKeyword)] + [InlineData(SyntaxKind.StructKeyword)] + [InlineData(SyntaxKind.InterfaceKeyword)] + [InlineData(SyntaxKind.RecordKeyword)] + [InlineData(SyntaxKind.EnumKeyword)] + public void FileModifier_11(SyntaxKind typeKeyword) + { + UsingNode($$""" + public file {{SyntaxFacts.GetText(typeKeyword)}} C { } + """); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxFacts.GetBaseTypeDeclarationKind(typeKeyword)); + { + N(SyntaxKind.PublicKeyword); + N(SyntaxKind.FileKeyword); + N(typeKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Theory] + [InlineData(SyntaxKind.ClassKeyword)] + [InlineData(SyntaxKind.StructKeyword)] + [InlineData(SyntaxKind.InterfaceKeyword)] + [InlineData(SyntaxKind.RecordKeyword)] + [InlineData(SyntaxKind.EnumKeyword)] + public void FileModifier_12(SyntaxKind typeKeyword) + { + UsingNode($$""" + file public {{SyntaxFacts.GetText(typeKeyword)}} C { } + """); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxFacts.GetBaseTypeDeclarationKind(typeKeyword)); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.PublicKeyword); + N(typeKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileModifier_13() + { + UsingNode(""" + file class C { } + """, + options: TestOptions.Regular10, + expectedBindingDiagnostics: new[] + { + // (1,12): error CS8652: The feature 'file types' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // file class C { } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "C").WithArguments("file types").WithLocation(1, 12) + }); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileModifier_14() + { + UsingNode(""" + file delegate void D(); + """); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.DelegateDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "D"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileModifier_15() + { + UsingNode(""" + namespace NS + { + file class C { } + } + """); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.NamespaceDeclaration); + { + N(SyntaxKind.NamespaceKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "NS"); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileModifier_16() + { + UsingNode(""" + namespace NS; + file class C { } + """); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.FileScopedNamespaceDeclaration); + { + N(SyntaxKind.NamespaceKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "NS"); + } + N(SyntaxKind.SemicolonToken); + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileModifier_17() + { + UsingNode(""" + class Outer + { + file class C { } + } + """); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "Outer"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileModifier_18() + { + UsingNode(""" + class C + { + file delegate* M(); + } + """, + expectedBindingDiagnostics: new[] + { + // (3,10): error CS0214: Pointers and fixed size buffers may only be used in an unsafe context + // file delegate* M(); + Diagnostic(ErrorCode.ERR_UnsafeNeeded, "delegate*").WithLocation(3, 10), + // (3,31): error CS0106: The modifier 'file' is not valid for this item + // file delegate* M(); + Diagnostic(ErrorCode.ERR_BadMemberFlag, "M").WithArguments("file").WithLocation(3, 31), + // (3,31): error CS0501: 'C.M()' must declare a body because it is not marked abstract, extern, or partial + // file delegate* M(); + Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "M").WithArguments("C.M()").WithLocation(3, 31) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.FunctionPointerType); + { + N(SyntaxKind.DelegateKeyword); + N(SyntaxKind.AsteriskToken); + N(SyntaxKind.FunctionPointerParameterList); + { + N(SyntaxKind.LessThanToken); + N(SyntaxKind.FunctionPointerParameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.FunctionPointerParameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + } + N(SyntaxKind.GreaterThanToken); + } + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileMember_01() + { + UsingNode(""" + class C + { + file void M() { } + } + """, + expectedBindingDiagnostics: new[] + { + // (3,15): error CS0106: The modifier 'file' is not valid for this item + // file void M() { } + Diagnostic(ErrorCode.ERR_BadMemberFlag, "M").WithArguments("file").WithLocation(3, 15) + }); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileMember_02() + { + UsingNode(""" + class C + { + file int x; + } + """, + expectedBindingDiagnostics: new[] + { + // (3,14): error CS0106: The modifier 'file' is not valid for this item + // file int x; + Diagnostic(ErrorCode.ERR_BadMemberFlag, "x").WithArguments("file").WithLocation(3, 14), + // (3,14): warning CS0169: The field 'C.x' is never used + // file int x; + Diagnostic(ErrorCode.WRN_UnreferencedField, "x").WithArguments("C.x").WithLocation(3, 14) + }); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.FieldDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "x"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileMember_03() + { + UsingNode($$""" + class C + { + file event Action x; + } + """, + expectedBindingDiagnostics: new[] + { + // (3,16): error CS0246: The type or namespace name 'Action' could not be found (are you missing a using directive or an assembly reference?) + // file event Action x; + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "Action").WithArguments("Action").WithLocation(3, 16), + // (3,23): error CS0106: The modifier 'file' is not valid for this item + // file event Action x; + Diagnostic(ErrorCode.ERR_BadMemberFlag, "x").WithArguments("file").WithLocation(3, 23), + // (3,23): warning CS0067: The event 'C.x' is never used + // file event Action x; + Diagnostic(ErrorCode.WRN_UnreferencedEvent, "x").WithArguments("C.x").WithLocation(3, 23) + }); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.EventFieldDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.EventKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Action"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "x"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileMember_04() + { + var source = $$""" + class C + { + file int x { get; set; } + } + """; + + UsingNode(source, expectedBindingDiagnostics: new[] + { + // (3,14): error CS0106: The modifier 'file' is not valid for this item + // file int x { get; set; } + Diagnostic(ErrorCode.ERR_BadMemberFlag, "x").WithArguments("file").WithLocation(3, 14) + }); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.PropertyDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.IdentifierToken, "x"); + N(SyntaxKind.AccessorList); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.GetAccessorDeclaration); + { + N(SyntaxKind.GetKeyword); + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.SetAccessorDeclaration); + { + N(SyntaxKind.SetKeyword); + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileMember_05() + { + var source = $$""" + class C + { + async file void M() { } + } + """; + + UsingNode(source, expectedBindingDiagnostics: new[] + { + // (3,21): error CS0106: The modifier 'file' is not valid for this item + // async file void M() { } + Diagnostic(ErrorCode.ERR_BadMemberFlag, "M").WithArguments("file").WithLocation(3, 21), + // (3,21): warning CS1998: This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread. + // async file void M() { } + Diagnostic(ErrorCode.WRN_AsyncLacksAwaits, "M").WithLocation(3, 21) + }); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.AsyncKeyword); + N(SyntaxKind.FileKeyword); + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void MemberNamedFile_01() + { + UsingNode($$""" + class C + { + int file; + } + """, expectedBindingDiagnostics: new[] + { + // (3,9): warning CS0169: The field 'C.file' is never used + // int file; + Diagnostic(ErrorCode.WRN_UnreferencedField, "file").WithArguments("C.file").WithLocation(3, 9) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.FieldDeclaration); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "file"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void MemberNamedFile_02() + { + UsingNode($$""" + class C + { + int file { get; set; } + } + """); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.PropertyDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.IdentifierToken, "file"); + N(SyntaxKind.AccessorList); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.GetAccessorDeclaration); + { + N(SyntaxKind.GetKeyword); + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.SetAccessorDeclaration); + { + N(SyntaxKind.SetKeyword); + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void MemberNamedFile_03() + { + UsingNode($$""" + class C + { + event Action file; + } + """, + expectedBindingDiagnostics: new[] + { + // (3,11): error CS0246: The type or namespace name 'Action' could not be found (are you missing a using directive or an assembly reference?) + // event Action file; + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "Action").WithArguments("Action").WithLocation(3, 11), + // (3,18): warning CS0067: The event 'C.file' is never used + // event Action file; + Diagnostic(ErrorCode.WRN_UnreferencedEvent, "file").WithArguments("C.file").WithLocation(3, 18) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.EventFieldDeclaration); + { + N(SyntaxKind.EventKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Action"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "file"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void MemberNamedFile_04() + { + UsingNode($$""" + class C + { + void file() { } + } + """); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "file"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void MemberNamedFile_05() + { + UsingNode($$""" + file class file { } + """, + expectedBindingDiagnostics: new[] + { + // (1,12): warning CS8981: The type name 'file' only contains lower-cased ascii characters. Such names may become reserved for the language. + // file class file { } + Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "file").WithArguments("file").WithLocation(1, 12) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "file"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void MemberNamedFile_06_CSharp10() + { + UsingNode($$""" + class C + { + file async; + } + """, + options: TestOptions.Regular10, + expectedBindingDiagnostics: new[] + { + // (3,5): error CS0246: The type or namespace name 'file' could not be found (are you missing a using directive or an assembly reference?) + // file async; + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "file").WithArguments("file").WithLocation(3, 5), + // (3,10): warning CS0169: The field 'C.async' is never used + // file async; + Diagnostic(ErrorCode.WRN_UnreferencedField, "async").WithArguments("C.async").WithLocation(3, 10) + }); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.FieldDeclaration); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "file"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "async"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void MemberNamedFile_06() + { + UsingNode($$""" + class C + { + file async; + } + """, + // (3,15): error CS1519: Invalid token ';' in class, record, struct, or interface member declaration + // file async; + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ";").WithArguments(";").WithLocation(3, 15), + // (3,15): error CS1519: Invalid token ';' in class, record, struct, or interface member declaration + // file async; + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ";").WithArguments(";").WithLocation(3, 15)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "async"); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void MemberNamedFile_07_CSharp10() + { + UsingNode($$""" + class C + { + file item; + } + """, + options: TestOptions.Regular10, + expectedBindingDiagnostics: new[] + { + // (3,5): error CS0246: The type or namespace name 'file' could not be found (are you missing a using directive or an assembly reference?) + // file item; + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "file").WithArguments("file").WithLocation(3, 5), + // (3,10): warning CS0169: The field 'C.item' is never used + // file item; + Diagnostic(ErrorCode.WRN_UnreferencedField, "item").WithArguments("C.item").WithLocation(3, 10) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.FieldDeclaration); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "file"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "item"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + // PROTOTYPE(ft): confirm with LDM whether this breaking change is acceptable (compared to CSharp10 version above). + [Fact] + public void MemberNamedFile_07() + { + UsingNode($$""" + class C + { + file item; + } + """, + expectedParsingDiagnostics: new[] + { + // (3,14): error CS1519: Invalid token ';' in class, record, struct, or interface member declaration + // file item; + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ";").WithArguments(";").WithLocation(3, 14), + // (3,14): error CS1519: Invalid token ';' in class, record, struct, or interface member declaration + // file item; + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ";").WithArguments(";").WithLocation(3, 14) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "item"); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + [Fact] + public void MemberNamedFile_08() + { + UsingNode($$""" + record file { } + """, + expectedBindingDiagnostics: new[] + { + // (1,8): warning CS8981: The type name 'file' only contains lower-cased ascii characters. Such names may become reserved for the language. + // record file { } + Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "file").WithArguments("file").WithLocation(1, 8) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.RecordDeclaration); + { + N(SyntaxKind.RecordKeyword); + N(SyntaxKind.IdentifierToken, "file"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void Errors_01_CSharp10() + { + UsingNode($$""" + file + """, + options: TestOptions.Regular10, + // (1,1): error CS0116: A namespace cannot directly contain members such as fields, methods or statements + // file + Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "file").WithLocation(1, 1)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "file"); + } + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void Errors_01() + { + UsingNode($$""" + file + """, + // (1,1): error CS0116: A namespace cannot directly contain members such as fields, methods or statements + // file + Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "file").WithLocation(1, 1)); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.FileKeyword); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void Errors_02_CSharp10() + { + UsingNode($$""" + file; + """, + options: TestOptions.Regular10, + expectedBindingDiagnostics: new[] + { + // (1,1): error CS0103: The name 'file' does not exist in the current context + // file; + Diagnostic(ErrorCode.ERR_NameNotInContext, "file").WithArguments("file").WithLocation(1, 1), + // (1,1): error CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement + // file; + Diagnostic(ErrorCode.ERR_IllegalStatement, "file").WithLocation(1, 1) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.ExpressionStatement); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "file"); + } + N(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void Errors_02() + { + UsingNode($$""" + file; + """, + expectedParsingDiagnostics: new[] + { + // (1,1): error CS0116: A namespace cannot directly contain members such as fields, methods or statements + // file; + Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "file").WithLocation(1, 1) + }, + expectedBindingDiagnostics: new[] + { + // (1,1): error CS0116: A namespace cannot directly contain members such as fields, methods or statements + // file; + Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "file").WithLocation(1, 1), + // (1,5): error CS8937: At least one top-level statement must be non-empty. + // file; + Diagnostic(ErrorCode.ERR_SimpleProgramIsEmpty, ";").WithLocation(1, 5) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.FileKeyword); + } + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.EmptyStatement); + { + N(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void Errors_03_CSharp10() + { + UsingNode($$""" + file namespace NS; + """, + options: TestOptions.Regular10, + expectedParsingDiagnostics: new[] + { + // (1,1): error CS0116: A namespace cannot directly contain members such as fields, methods or statements + // file namespace NS; + Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "file").WithLocation(1, 1) + }, + expectedBindingDiagnostics: new[] + { + // (1,1): error CS0116: A namespace cannot directly contain members such as fields, methods or statements + // file namespace NS; + Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "file").WithLocation(1, 1), + // (1,16): error CS8956: File-scoped namespace must precede all other members in a file. + // file namespace NS; + Diagnostic(ErrorCode.ERR_FileScopedNamespaceNotBeforeAllMembers, "NS").WithLocation(1, 16) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "file"); + } + } + N(SyntaxKind.FileScopedNamespaceDeclaration); + { + N(SyntaxKind.NamespaceKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "NS"); + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void Errors_03() + { + UsingNode($$""" + file namespace NS; + """, + expectedBindingDiagnostics: new[] + { + // (1,1): error CS1671: A namespace declaration cannot have modifiers or attributes + // file namespace NS; + Diagnostic(ErrorCode.ERR_BadModifiersOnNamespace, "file").WithLocation(1, 1) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.FileScopedNamespaceDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.NamespaceKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "NS"); + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void Errors_04_CSharp10() + { + UsingNode($$""" + file namespace NS { } + """, + options: TestOptions.Regular10, + expectedParsingDiagnostics: new[] + { + // (1,1): error CS0116: A namespace cannot directly contain members such as fields, methods or statements + // file namespace NS { } + Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "file").WithLocation(1, 1) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "file"); + } + } + N(SyntaxKind.NamespaceDeclaration); + { + N(SyntaxKind.NamespaceKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "NS"); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void Errors_04() + { + UsingNode($$""" + file namespace NS { } + """, + expectedBindingDiagnostics: new[] + { + // (1,1): error CS1671: A namespace declaration cannot have modifiers or attributes + // file namespace NS { } + Diagnostic(ErrorCode.ERR_BadModifiersOnNamespace, "file").WithLocation(1, 1) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.NamespaceDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.NamespaceKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "NS"); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void File_Repeated() + { + const int FileModifiersCount = 100000; + var manyFileModifiers = string.Join(" ", Enumerable.Repeat("file", FileModifiersCount)); + UsingNode(manyFileModifiers, + expectedParsingDiagnostics: new[] + { + Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "file").WithLocation(1, 499996) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.IncompleteMember); + { + for (var i = 0; i < FileModifiersCount; i++) + { + N(SyntaxKind.FileKeyword); + } + N(SyntaxKind.EndOfFileToken); + } + } + EOF(); + + UsingNode(manyFileModifiers + " class { }", + expectedParsingDiagnostics: new[] + { + Diagnostic(ErrorCode.ERR_IdentifierExpected, "{").WithLocation(1, 500007) + }, + expectedBindingDiagnostics: new[] + { + Diagnostic(ErrorCode.ERR_DuplicateModifier, "file").WithArguments("file").WithLocation(1, 6), + Diagnostic(ErrorCode.ERR_IdentifierExpected, "{").WithLocation(1, 500007) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + for (int i = 0; i < FileModifiersCount; i++) + { + N(SyntaxKind.FileKeyword); + } + N(SyntaxKind.ClassKeyword); + M(SyntaxKind.IdentifierToken); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void MethodNamedRecord_01_CSharp8() + { + UsingNode(""" + class C + { + file record(); + } + """, + options: TestOptions.Regular8, + expectedBindingDiagnostics: new[] + { + // (3,5): error CS0246: The type or namespace name 'file' could not be found (are you missing a using directive or an assembly reference?) + // file record(); + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "file").WithArguments("file").WithLocation(3, 5), + // (3,10): error CS0501: 'C.record()' must declare a body because it is not marked abstract, extern, or partial + // file record(); + Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "record").WithArguments("C.record()").WithLocation(3, 10) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "file"); + } + N(SyntaxKind.IdentifierToken, "record"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void MethodNamedRecord_01_CSharpNext() + { + UsingNode(""" + class C + { + file record(); + } + """, + expectedBindingDiagnostics: new[] + { + // (3,10): error CS0106: The modifier 'file' is not valid for this item + // file record(); + Diagnostic(ErrorCode.ERR_BadMemberFlag, "record").WithArguments("file").WithLocation(3, 10), + // (3,10): error CS1520: Method must have a return type + // file record(); + Diagnostic(ErrorCode.ERR_MemberNeedsType, "record").WithLocation(3, 10) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ConstructorDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.IdentifierToken, "record"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void MethodNamedRecord_02_CSharp8() + { + UsingNode(""" + class C + { + file record() { } + } + """, + options: TestOptions.Regular8, + expectedBindingDiagnostics: new[] + { + // (3,5): error CS0246: The type or namespace name 'file' could not be found (are you missing a using directive or an assembly reference?) + // file record() { } + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "file").WithArguments("file").WithLocation(3, 5), + // (3,10): error CS0161: 'C.record()': not all code paths return a value + // file record() { } + Diagnostic(ErrorCode.ERR_ReturnExpected, "record").WithArguments("C.record()").WithLocation(3, 10) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "file"); + } + N(SyntaxKind.IdentifierToken, "record"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void MethodNamedRecord_02_CSharpNext() + { + UsingNode(""" + class C + { + file record() { } + } + """, expectedBindingDiagnostics: new[] + { + // (3,10): error CS0106: The modifier 'file' is not valid for this item + // file record() { } + Diagnostic(ErrorCode.ERR_BadMemberFlag, "record").WithArguments("file").WithLocation(3, 10), + // (3,10): error CS1520: Method must have a return type + // file record() { } + Diagnostic(ErrorCode.ERR_MemberNeedsType, "record").WithLocation(3, 10) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.ConstructorDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.IdentifierToken, "record"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileRecord_01_CSharp8() + { + UsingNode(""" + class C + { + file record X(); + } + """, + options: TestOptions.Regular8, + expectedBindingDiagnostics: new[] + { + // (3,10): error CS0246: The type or namespace name 'record' could not be found (are you missing a using directive or an assembly reference?) + // file record X(); + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "record").WithArguments("record").WithLocation(3, 10), + // (3,17): error CS0106: The modifier 'file' is not valid for this item + // file record X(); + Diagnostic(ErrorCode.ERR_BadMemberFlag, "X").WithArguments("file").WithLocation(3, 17), + // (3,17): error CS0501: 'C.X()' must declare a body because it is not marked abstract, extern, or partial + // file record X(); + Diagnostic(ErrorCode.ERR_ConcreteMissingBody, "X").WithArguments("C.X()").WithLocation(3, 17) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "record"); + } + N(SyntaxKind.IdentifierToken, "X"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileRecord_01_CSharpNext() + { + UsingNode(""" + class C + { + file record X(); + } + """); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.RecordDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.RecordKeyword); + N(SyntaxKind.IdentifierToken, "X"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileRecord_02_CSharp8() + { + UsingNode(""" + class C + { + file record X() { } + } + """, + options: TestOptions.Regular8, + expectedBindingDiagnostics: new[] + { + // (3,10): error CS0246: The type or namespace name 'record' could not be found (are you missing a using directive or an assembly reference?) + // file record X() { } + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "record").WithArguments("record").WithLocation(3, 10), + // (3,17): error CS0106: The modifier 'file' is not valid for this item + // file record X() { } + Diagnostic(ErrorCode.ERR_BadMemberFlag, "X").WithArguments("file").WithLocation(3, 17), + // (3,17): error CS0161: 'C.X()': not all code paths return a value + // file record X() { } + Diagnostic(ErrorCode.ERR_ReturnExpected, "X").WithArguments("C.X()").WithLocation(3, 17) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "record"); + } + N(SyntaxKind.IdentifierToken, "X"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileRecord_02_CSharpNext() + { + UsingNode(""" + class C + { + file record X() { } + } + """); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.RecordDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.RecordKeyword); + N(SyntaxKind.IdentifierToken, "X"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileRecord_03_CSharp8() + { + UsingNode(""" + class C + { + file record X; + } + """, + options: TestOptions.Regular8, expectedBindingDiagnostics: new[] + { + // (3,10): error CS0246: The type or namespace name 'record' could not be found (are you missing a using directive or an assembly reference?) + // file record X; + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "record").WithArguments("record").WithLocation(3, 10), + // (3,17): error CS0106: The modifier 'file' is not valid for this item + // file record X; + Diagnostic(ErrorCode.ERR_BadMemberFlag, "X").WithArguments("file").WithLocation(3, 17), + // (3,17): warning CS0169: The field 'C.X' is never used + // file record X; + Diagnostic(ErrorCode.WRN_UnreferencedField, "X").WithArguments("C.X").WithLocation(3, 17) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.FieldDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "record"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "X"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void FileRecord_03_CSharpNext() + { + UsingNode(""" + class C + { + file record X; + } + """); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.RecordDeclaration); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.RecordKeyword); + N(SyntaxKind.IdentifierToken, "X"); + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void LocalVariable_01() + { + UsingNode(""" + void M() + { + file file; + } + """, + expectedBindingDiagnostics: new[] + { + // (1,6): warning CS8321: The local function 'M' is declared but never used + // void M() + Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "M").WithArguments("M").WithLocation(1, 6), + // (3,5): error CS0118: 'file' is a variable but is used like a type + // file file; + Diagnostic(ErrorCode.ERR_BadSKknown, "file").WithArguments("file", "variable", "type").WithLocation(3, 5), + // (3,10): warning CS0168: The variable 'file' is declared but never used + // file file; + Diagnostic(ErrorCode.WRN_UnreferencedVar, "file").WithArguments("file").WithLocation(3, 10) + }); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.LocalFunctionStatement); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "file"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "file"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void LocalVariable_02() + { + UsingNode(""" + void M() + { + int file; + } + """, + expectedBindingDiagnostics: new[] + { + // (1,6): warning CS8321: The local function 'M' is declared but never used + // void M() + Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "M").WithArguments("M").WithLocation(1, 6), + // (3,9): warning CS0168: The variable 'file' is declared but never used + // int file; + Diagnostic(ErrorCode.WRN_UnreferencedVar, "file").WithArguments("file").WithLocation(3, 9) + }); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.LocalFunctionStatement); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "file"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + // PROTOTYPE(ft): confirm whether this breaking change is acceptable + [Fact] + public void TopLevelVariable_01_CSharp10() + { + UsingNode(""" + file file; + """, + options: TestOptions.Regular10, + expectedBindingDiagnostics: new[] + { + // (1,1): error CS0118: 'file' is a variable but is used like a type + // file file; + Diagnostic(ErrorCode.ERR_BadSKknown, "file").WithArguments("file", "variable", "type").WithLocation(1, 1), + // (1,6): warning CS0168: The variable 'file' is declared but never used + // file file; + Diagnostic(ErrorCode.WRN_UnreferencedVar, "file").WithArguments("file").WithLocation(1, 6) + }); + + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "file"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "file"); + } + } + N(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void TopLevelVariable_01() + { + UsingNode(""" + file file; + """, + expectedParsingDiagnostics: new[] + { + // (1,6): error CS0116: A namespace cannot directly contain members such as fields, methods or statements + // file file; + Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "file").WithLocation(1, 6) + }, + expectedBindingDiagnostics: new[] + { + // (1,6): error CS0116: A namespace cannot directly contain members such as fields, methods or statements + // file file; + Diagnostic(ErrorCode.ERR_NamespaceUnexpected, "file").WithLocation(1, 6), + // (1,10): error CS8937: At least one top-level statement must be non-empty. + // file file; + Diagnostic(ErrorCode.ERR_SimpleProgramIsEmpty, ";").WithLocation(1, 10) + }); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.FileKeyword); + N(SyntaxKind.FileKeyword); + } + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.EmptyStatement); + { + N(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void TopLevelVariable_02() + { + UsingNode(""" + int file; + """, + expectedBindingDiagnostics: new[] + { + // (1,5): warning CS0168: The variable 'file' is declared but never used + // int file; + Diagnostic(ErrorCode.WRN_UnreferencedVar, "file").WithArguments("file").WithLocation(1, 5) + }); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.LocalDeclarationStatement); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "file"); + } + } + N(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void LambdaReturn() + { + UsingNode(""" + _ = file () => { }; + """, + expectedBindingDiagnostics: new[] + { + // (1,1): error CS8183: Cannot infer the type of implicitly-typed discard. + // _ = file () => { }; + Diagnostic(ErrorCode.ERR_DiscardTypeInferenceFailed, "_").WithLocation(1, 1), + // (1,5): error CS0246: The type or namespace name 'file' could not be found (are you missing a using directive or an assembly reference?) + // _ = file () => { }; + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "file").WithArguments("file").WithLocation(1, 5) + }); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.ExpressionStatement); + { + N(SyntaxKind.SimpleAssignmentExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "_"); + } + N(SyntaxKind.EqualsToken); + N(SyntaxKind.ParenthesizedLambdaExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "file"); + } + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.EqualsGreaterThanToken); + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + } + N(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void LocalFunctionReturn() + { + UsingNode(""" + file local() { }; + """, + expectedBindingDiagnostics: new[] + { + // (1,1): error CS0246: The type or namespace name 'file' could not be found (are you missing a using directive or an assembly reference?) + // file local() { }; + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "file").WithArguments("file").WithLocation(1, 1), + // (1,6): error CS0161: 'local()': not all code paths return a value + // file local() { }; + Diagnostic(ErrorCode.ERR_ReturnExpected, "local").WithArguments("local()").WithLocation(1, 6), + // (1,6): warning CS8321: The local function 'local' is declared but never used + // file local() { }; + Diagnostic(ErrorCode.WRN_UnreferencedLocalFunction, "local").WithArguments("local").WithLocation(1, 6) + }); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.LocalFunctionStatement); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "file"); + } + N(SyntaxKind.IdentifierToken, "local"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + } + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.EmptyStatement); + { + N(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void ParameterModifier() + { + UsingNode(""" + class C + { + void M(file int x) { } + } + """, + expectedParsingDiagnostics: new[] + { + // (3,17): error CS1001: Identifier expected + // void M(file int x) { } + Diagnostic(ErrorCode.ERR_IdentifierExpected, "int").WithLocation(3, 17), + // (3,17): error CS1003: Syntax error, ',' expected + // void M(file int x) { } + Diagnostic(ErrorCode.ERR_SyntaxError, "int").WithArguments(",", "int").WithLocation(3, 17) + }, + expectedBindingDiagnostics: new[] + { + // (3,12): error CS0246: The type or namespace name 'file' could not be found (are you missing a using directive or an assembly reference?) + // void M(file int x) { } + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "file").WithArguments("file").WithLocation(3, 12), + // (3,17): error CS1001: Identifier expected + // void M(file int x) { } + Diagnostic(ErrorCode.ERR_IdentifierExpected, "int").WithLocation(3, 17), + // (3,17): error CS1003: Syntax error, ',' expected + // void M(file int x) { } + Diagnostic(ErrorCode.ERR_SyntaxError, "int").WithArguments(",", "int").WithLocation(3, 17) + }); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "file"); + } + M(SyntaxKind.IdentifierToken); + } + M(SyntaxKind.CommaToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.IntKeyword); + } + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + + [Fact] + public void ParameterType() + { + UsingNode(""" + class C + { + void M(file x) { } + } + """, + expectedBindingDiagnostics: new[] + { + // (3,12): error CS0246: The type or namespace name 'file' could not be found (are you missing a using directive or an assembly reference?) + // void M(file x) { } + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "file").WithArguments("file").WithLocation(3, 12) + }); + N(SyntaxKind.CompilationUnit); + { + N(SyntaxKind.ClassDeclaration); + { + N(SyntaxKind.ClassKeyword); + N(SyntaxKind.IdentifierToken, "C"); + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.VoidKeyword); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "file"); + } + N(SyntaxKind.IdentifierToken, "x"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + N(SyntaxKind.CloseBraceToken); + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + } +}