diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 5fd068b866369..a5b2fed924c27 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -3302,7 +3302,7 @@ A catch() block after a catch (System.Exception e) block can catch non-CLS excep '{0}' does not contain a constructor that takes {1} arguments - Assembly and module attributes must precede all other elements defined in a file except using clauses and extern alias declarations + Assembly, module, and main attributes must precede all other elements defined in a file except using clauses and extern alias declarations Expected expression @@ -3975,7 +3975,7 @@ You should consider suppressing the warning only if you're sure that you don't w Cannot declare namespace in script code - Assembly and module attributes are not allowed in this context + Assembly, module, and main attributes are not allowed in this context Delegate '{0}' has no invoke method or an invoke method with a return type or parameter types that are not supported. @@ -6986,4 +6986,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Line contains different whitespace than the closing line of the raw string literal: '{0}' versus '{1}' + + 'main' as an attribute target specifier + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/Errors/MessageID.cs b/src/Compilers/CSharp/Portable/Errors/MessageID.cs index c3a022ba2bbde..3941622cd3f1a 100644 --- a/src/Compilers/CSharp/Portable/Errors/MessageID.cs +++ b/src/Compilers/CSharp/Portable/Errors/MessageID.cs @@ -244,6 +244,7 @@ internal enum MessageID IDS_FeatureCacheStaticMethodGroupConversion = MessageBase + 12816, IDS_FeatureRawStringLiterals = MessageBase + 12817, + IDS_FeatureMainAttributeLocation = MessageBase + 12818, } // Message IDs may refer to strings that need to be localized. @@ -360,6 +361,7 @@ internal static LanguageVersion RequiredVersion(this MessageID feature) case MessageID.IDS_FeatureListPattern: // semantic check case MessageID.IDS_FeatureCacheStaticMethodGroupConversion: // lowering check case MessageID.IDS_ParameterNullChecking: // syntax check + case MessageID.IDS_FeatureMainAttributeLocation: // syntax check return LanguageVersion.Preview; // C# 10.0 features. diff --git a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs index d0a0ac11e529c..58d5edea59bbc 100644 --- a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs +++ b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs @@ -866,6 +866,7 @@ private static bool IsGlobalAttributeTarget(SyntaxToken token) { case AttributeLocation.Assembly: case AttributeLocation.Module: + case AttributeLocation.Main: return true; default: return false; @@ -928,10 +929,12 @@ private AttributeListSyntax ParseAttributeDeclaration() var attributes = _pool.AllocateSeparated(); try { - if (attrLocation != null && attrLocation.Identifier.ToAttributeLocation() == AttributeLocation.Module) + attrLocation = attrLocation?.Identifier.ToAttributeLocation() switch { - attrLocation = CheckFeatureAvailability(attrLocation, MessageID.IDS_FeatureModuleAttrLoc); - } + AttributeLocation.Module => CheckFeatureAvailability(attrLocation, MessageID.IDS_FeatureModuleAttrLoc), + AttributeLocation.Main => CheckFeatureAvailability(attrLocation, MessageID.IDS_FeatureMainAttributeLocation), + _ => attrLocation + }; this.ParseAttributes(attributes); var closeBracket = this.EatToken(SyntaxKind.CloseBracketToken); diff --git a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt index d367804586e73..4a89318f0eb7b 100644 --- a/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/CSharp/Portable/PublicAPI.Unshipped.txt @@ -28,3 +28,4 @@ static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.TryStatement(Microsoft.CodeAn static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.TryStatement(Microsoft.CodeAnalysis.SyntaxToken tryKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax! block, Microsoft.CodeAnalysis.SyntaxList catches, Microsoft.CodeAnalysis.CSharp.Syntax.FinallyClauseSyntax? finally) -> Microsoft.CodeAnalysis.CSharp.Syntax.TryStatementSyntax! *REMOVED*static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.TryStatement(Microsoft.CodeAnalysis.SyntaxToken tryKeyword, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax! block, Microsoft.CodeAnalysis.SyntaxList catches, Microsoft.CodeAnalysis.CSharp.Syntax.FinallyClauseSyntax! finally) -> Microsoft.CodeAnalysis.CSharp.Syntax.TryStatementSyntax! static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.InterpolatedStringExpression(Microsoft.CodeAnalysis.SyntaxToken stringStartToken, Microsoft.CodeAnalysis.SyntaxToken stringEndToken) -> Microsoft.CodeAnalysis.CSharp.Syntax.InterpolatedStringExpressionSyntax! +Microsoft.CodeAnalysis.CSharp.SyntaxKind.MainKeyword = 8447 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/AttributeLocation.cs b/src/Compilers/CSharp/Portable/Symbols/Source/AttributeLocation.cs index 583e2a11971ee..862b3b0f2c2ac 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/AttributeLocation.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/AttributeLocation.cs @@ -29,9 +29,10 @@ internal enum AttributeLocation : short Parameter = 1 << 7, Return = 1 << 8, TypeParameter = 1 << 9, + Main = 1 << 10, // must be the last: - Unknown = 1 << 10, + Unknown = 1 << 11, } internal static class AttributeLocationExtensions @@ -90,6 +91,10 @@ internal static string ToDisplayString(this AttributeLocation locations) result.Append("typevar"); break; + case AttributeLocation.Main: + result.Append("main"); + break; + default: throw ExceptionUtilities.UnexpectedValue(i); } @@ -139,6 +144,8 @@ private static AttributeLocation ToAttributeLocation(string text) return AttributeLocation.Property; case "typevar": return AttributeLocation.TypeParameter; + case "main": + return AttributeLocation.Main; default: return AttributeLocation.None; } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceAssemblySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceAssemblySymbol.cs index edddf9d51e120..930625e23a060 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceAssemblySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceAssemblySymbol.cs @@ -2322,7 +2322,7 @@ AttributeLocation IAttributeTargetSymbol.AllowedAttributeLocations { get { - return IsInteractive ? AttributeLocation.None : AttributeLocation.Assembly | AttributeLocation.Module; + return IsInteractive ? AttributeLocation.None : AttributeLocation.Assembly | AttributeLocation.Module | AttributeLocation.Main; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Symbol_Attributes.cs b/src/Compilers/CSharp/Portable/Symbols/Symbol_Attributes.cs index 472f6df41f379..7cb2ec4e110f6 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Symbol_Attributes.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Symbol_Attributes.cs @@ -551,6 +551,7 @@ private static bool MatchAttributeTarget(IAttributeTargetSymbol attributeTarget, { case AttributeLocation.Assembly: case AttributeLocation.Module: + case AttributeLocation.Main: // global attributes are disallowed in interactive code: diagnostics.Add(ErrorCode.ERR_GlobalAttributesNotAllowed, targetOpt.Identifier.GetLocation()); break; diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedSimpleProgramEntryPointSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedSimpleProgramEntryPointSymbol.cs index 1dda4db66ed28..8288ac24edcc1 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedSimpleProgramEntryPointSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedSimpleProgramEntryPointSymbol.cs @@ -13,7 +13,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols { - internal sealed class SynthesizedSimpleProgramEntryPointSymbol : SourceMemberMethodSymbol + internal sealed class SynthesizedSimpleProgramEntryPointSymbol : SourceMemberMethodSymbol, IAttributeTargetSymbol { /// /// The corresponding . @@ -281,6 +281,22 @@ internal override bool IsDefinedInSourceTree(SyntaxTree tree, TextSpan? definedW public SyntaxNode ReturnTypeSyntax => CompilationUnit.Members.First(m => m.Kind() == SyntaxKind.GlobalStatement); + internal override OneOrMany> GetAttributeDeclarations() + { + // there could me multiple simple program entry points. Only consider [main:] attributes + // if we're the entry point that will ultimately be selected. + if (this == GetSimpleProgramEntryPoint(DeclaringCompilation)) + { + return OneOrMany.Create(((SourceAssemblySymbol)ContainingAssembly).GetAttributeDeclarations()); + } + + return OneOrMany>.Empty; + } + + protected override IAttributeTargetSymbol AttributeOwner => (IAttributeTargetSymbol)this.ContainingAssembly; + + AttributeLocation IAttributeTargetSymbol.DefaultAttributeLocation => AttributeLocation.Main; + private static bool IsNullableAnalysisEnabled(CSharpCompilation compilation, CompilationUnitSyntax syntax) { foreach (var member in syntax.Members) diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs index b6252d4c4d2df..6be53c0cdaf30 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs @@ -396,6 +396,8 @@ public enum SyntaxKind : ushort ManagedKeyword = 8445, /// Represents . UnmanagedKeyword = 8446, + /// Represents . + MainKeyword = 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 0c9328b86bf1c..b0a63eb99595c 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxKindFacts.cs @@ -1075,7 +1075,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.MainKeyword; i++) { yield return (SyntaxKind)i; } @@ -1128,6 +1128,7 @@ public static bool IsContextualKeyword(SyntaxKind kind) case SyntaxKind.RecordKeyword: case SyntaxKind.ManagedKeyword: case SyntaxKind.UnmanagedKeyword: + case SyntaxKind.MainKeyword: return true; default: return false; @@ -1247,6 +1248,8 @@ public static SyntaxKind GetContextualKeywordKind(string text) return SyntaxKind.ManagedKeyword; case "unmanaged": return SyntaxKind.UnmanagedKeyword; + case "main": + return SyntaxKind.MainKeyword; default: return SyntaxKind.None; } @@ -1684,6 +1687,8 @@ public static string GetText(SyntaxKind kind) return "managed"; case SyntaxKind.UnmanagedKeyword: return "unmanaged"; + case SyntaxKind.MainKeyword: + return "main"; 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 cf8a63c0ca222..c4912579f7b35 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -1432,6 +1432,11 @@ vzor seznamu + + 'main' as an attribute target specifier + 'main' as an attribute target specifier + + newlines in interpolations nové řádky v interpolacích @@ -8220,8 +8225,8 @@ Blok catch() po bloku catch (System.Exception e) může zachytit výjimky, kter - Assembly and module attributes must precede all other elements defined in a file except using clauses and extern alias declarations - Atributy sestavení a modulu musí předcházet přede všemi ostatními prvky definovanými v souboru s výjimkou klauzulí using a deklarací externích aliasů. + Assembly, module, and main attributes must precede all other elements defined in a file except using clauses and extern alias declarations + Atributy sestavení a modulu musí předcházet přede všemi ostatními prvky definovanými v souboru s výjimkou klauzulí using a deklarací externích aliasů. @@ -9325,8 +9330,8 @@ Potlačení upozornění zvažte jenom v případě, když určitě nechcete če - Assembly and module attributes are not allowed in this context - Atributy sestavení a modulů nejsou v tomto kontextu povolené. + Assembly, module, and main attributes are not allowed in this context + Atributy sestavení a modulů nejsou v tomto kontextu povolené. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index f26a9dabd49f8..4ac938ac597cf 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -1432,6 +1432,11 @@ Listenmuster + + 'main' as an attribute target specifier + 'main' as an attribute target specifier + + newlines in interpolations Zeilenumbrüche in Interpolationen @@ -8220,8 +8225,8 @@ Ein catch()-Block nach einem catch (System.Exception e)-Block kann nicht-CLS-Aus - Assembly and module attributes must precede all other elements defined in a file except using clauses and extern alias declarations - Assembly- und Modulattribute müssen vor allen anderen in einer Datei definierten Elementen mit Ausnahme von using-Klauseln und externen Aliasdeklarationen angegeben werden. + Assembly, module, and main attributes must precede all other elements defined in a file except using clauses and extern alias declarations + Assembly- und Modulattribute müssen vor allen anderen in einer Datei definierten Elementen mit Ausnahme von using-Klauseln und externen Aliasdeklarationen angegeben werden. @@ -9325,8 +9330,8 @@ Sie sollten das Unterdrücken der Warnung nur in Betracht ziehen, wenn Sie siche - Assembly and module attributes are not allowed in this context - Assembly- und Modulattribute sind in diesem Kontext nicht zulässig. + Assembly, module, and main attributes are not allowed in this context + Assembly- und Modulattribute sind in diesem Kontext nicht zulässig. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index bf487453d1132..6057ea9c03c6f 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -1432,6 +1432,11 @@ patrón de lista + + 'main' as an attribute target specifier + 'main' as an attribute target specifier + + newlines in interpolations Nuevas líneas en interpolaciones @@ -8220,8 +8225,8 @@ Un bloque catch() después de un bloque catch (System.Exception e) puede abarcar - Assembly and module attributes must precede all other elements defined in a file except using clauses and extern alias declarations - Los atributos de módulo y ensamblado deben ir delante de los demás elementos definidos en un archivo, excepto las cláusulas using y las declaraciones de alias externos + Assembly, module, and main attributes must precede all other elements defined in a file except using clauses and extern alias declarations + Los atributos de módulo y ensamblado deben ir delante de los demás elementos definidos en un archivo, excepto las cláusulas using y las declaraciones de alias externos @@ -9325,8 +9330,8 @@ Considere la posibilidad de suprimir la advertencia solo si tiene la seguridad d - Assembly and module attributes are not allowed in this context - En este contexto no se permiten atributos de ensamblado y módulo + Assembly, module, and main attributes are not allowed in this context + En este contexto no se permiten atributos de ensamblado y módulo diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index 42694a4856397..c7ddc616bfed7 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -1432,6 +1432,11 @@ modèle de liste + + 'main' as an attribute target specifier + 'main' as an attribute target specifier + + newlines in interpolations sauts de ligne dans les interpolations @@ -8220,8 +8225,8 @@ Un bloc catch() après un bloc catch (System.Exception e) peut intercepter des e - Assembly and module attributes must precede all other elements defined in a file except using clauses and extern alias declarations - Les attributs de l'assembly et du module doivent précéder tous les autres éléments définis dans un fichier à l'exception des clauses using et des déclarations d'alias extern + Assembly, module, and main attributes must precede all other elements defined in a file except using clauses and extern alias declarations + Les attributs de l'assembly et du module doivent précéder tous les autres éléments définis dans un fichier à l'exception des clauses using et des déclarations d'alias extern @@ -9325,8 +9330,8 @@ Supprimez l'avertissement seulement si vous êtes sûr de ne pas vouloir attendr - Assembly and module attributes are not allowed in this context - Les attributs d'assembly et de module ne sont pas autorisés dans ce contexte + Assembly, module, and main attributes are not allowed in this context + Les attributs d'assembly et de module ne sont pas autorisés dans ce contexte diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index 970507838682e..204905c58eaff 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -1432,6 +1432,11 @@ modello di elenco + + 'main' as an attribute target specifier + 'main' as an attribute target specifier + + newlines in interpolations nuove linee nelle interpolazioni @@ -8220,8 +8225,8 @@ Un blocco catch() dopo un blocco catch (System.Exception e) può rilevare eccezi - Assembly and module attributes must precede all other elements defined in a file except using clauses and extern alias declarations - Gli attributi di modulo e assembly devono precedere tutti gli altri elementi definiti in un file ad eccezione delle clausole using e delle dichiarazioni di alias extern + Assembly, module, and main attributes must precede all other elements defined in a file except using clauses and extern alias declarations + Gli attributi di modulo e assembly devono precedere tutti gli altri elementi definiti in un file ad eccezione delle clausole using e delle dichiarazioni di alias extern @@ -9325,8 +9330,8 @@ Come procedura consigliata, è consigliabile attendere sempre la chiamata. - Assembly and module attributes are not allowed in this context - Gli attributi di assembly e modulo non sono consentiti in questo contesto + Assembly, module, and main attributes are not allowed in this context + Gli attributi di assembly e modulo non sono consentiti in questo contesto diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index 8e4920c4ec36e..c6677137dcca2 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -1432,6 +1432,11 @@ リスト パターン + + 'main' as an attribute target specifier + 'main' as an attribute target specifier + + newlines in interpolations 補間における改行 @@ -8220,8 +8225,8 @@ AssemblyInfo.cs ファイルで RuntimeCompatibilityAttribute が false に設 - Assembly and module attributes must precede all other elements defined in a file except using clauses and extern alias declarations - アセンブリ属性とモジュール属性は、句および extern エイリアス宣言を使用する場合を除き、ファイルで定義された他のすべての要素の前に指定しなければなりません + Assembly, module, and main attributes must precede all other elements defined in a file except using clauses and extern alias declarations + アセンブリ属性とモジュール属性は、句および extern エイリアス宣言を使用する場合を除き、ファイルで定義された他のすべての要素の前に指定しなければなりません @@ -9325,8 +9330,8 @@ You should consider suppressing the warning only if you're sure that you don't w - Assembly and module attributes are not allowed in this context - アセンブリ属性とモジュール属性は、このコンテキストでは許可されていません + Assembly, module, and main attributes are not allowed in this context + アセンブリ属性とモジュール属性は、このコンテキストでは許可されていません diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index 02c6a1afa275d..4002d78f6e1aa 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -1432,6 +1432,11 @@ 목록 패턴 + + 'main' as an attribute target specifier + 'main' as an attribute target specifier + + newlines in interpolations 보간에서 줄 바꿈 @@ -8219,8 +8224,8 @@ catch (System.Exception e) 블록 뒤의 catch() 블록은 RuntimeCompatibilityA - Assembly and module attributes must precede all other elements defined in a file except using clauses and extern alias declarations - using 절과 extern 별칭 선언을 제외하고 어셈블리 특성과 모듈 특성은 파일에 정의된 다른 모든 요소보다 앞에 와야 합니다. + Assembly, module, and main attributes must precede all other elements defined in a file except using clauses and extern alias declarations + using 절과 extern 별칭 선언을 제외하고 어셈블리 특성과 모듈 특성은 파일에 정의된 다른 모든 요소보다 앞에 와야 합니다. @@ -9324,8 +9329,8 @@ You should consider suppressing the warning only if you're sure that you don't w - Assembly and module attributes are not allowed in this context - 이 컨텍스트에 어셈블리 및 모듈 특성이 허용되지 않습니다. + Assembly, module, and main attributes are not allowed in this context + 이 컨텍스트에 어셈블리 및 모듈 특성이 허용되지 않습니다. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index 0b54d90f80b4f..0761b71377e4b 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -1432,6 +1432,11 @@ wzorzec listy + + 'main' as an attribute target specifier + 'main' as an attribute target specifier + + newlines in interpolations nowe wiersze w interpolacjach @@ -8220,8 +8225,8 @@ Blok catch() po bloku catch (System.Exception e) może przechwytywać wyjątki n - Assembly and module attributes must precede all other elements defined in a file except using clauses and extern alias declarations - Atrybuty zestawu i modułu muszą występować przed wszystkimi innymi elementami zdefiniowanymi w pliku poza klauzulami using i deklaracjami aliasów zewnętrznych + Assembly, module, and main attributes must precede all other elements defined in a file except using clauses and extern alias declarations + Atrybuty zestawu i modułu muszą występować przed wszystkimi innymi elementami zdefiniowanymi w pliku poza klauzulami using i deklaracjami aliasów zewnętrznych @@ -9325,8 +9330,8 @@ Pominięcie ostrzeżenia należy wziąć pod uwagę tylko w sytuacji, gdy na pew - Assembly and module attributes are not allowed in this context - Atrybuty zestawów i modułów nie są dozwolone w tym kontekście + Assembly, module, and main attributes are not allowed in this context + Atrybuty zestawów i modułów nie są dozwolone w tym kontekście diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index 5d7a3f8be564c..d74a6125abc15 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -1432,6 +1432,11 @@ padrão de lista + + 'main' as an attribute target specifier + 'main' as an attribute target specifier + + newlines in interpolations novas linhas em interpolações @@ -8220,8 +8225,8 @@ Um bloco catch() depois de um bloco catch (System.Exception e) poderá capturar - Assembly and module attributes must precede all other elements defined in a file except using clauses and extern alias declarations - Os atributos assembly e module devem preceder todos os outros elementos definidos em um arquivo, exceto as cláusulas using e as declarações de alias externas + Assembly, module, and main attributes must precede all other elements defined in a file except using clauses and extern alias declarations + Os atributos assembly e module devem preceder todos os outros elementos definidos em um arquivo, exceto as cláusulas using e as declarações de alias externas @@ -9325,8 +9330,8 @@ Você pode suprimir o aviso se tiver certeza de que não vai querer aguardar a c - Assembly and module attributes are not allowed in this context - Atributos assembly e module não são permitidos neste contexto + Assembly, module, and main attributes are not allowed in this context + Atributos assembly e module não são permitidos neste contexto diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index 5e4da7accecbc..34f7d4b9d719b 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -1432,6 +1432,11 @@ шаблон списка + + 'main' as an attribute target specifier + 'main' as an attribute target specifier + + newlines in interpolations новые линии в интерполяции @@ -8220,8 +8225,8 @@ A catch() block after a catch (System.Exception e) block can catch non-CLS excep - Assembly and module attributes must precede all other elements defined in a file except using clauses and extern alias declarations - Атрибуты сборки и модуля должны находиться перед всеми остальными элементами в файле, кроме предложений using и описаний внешних псевдонимов. + Assembly, module, and main attributes must precede all other elements defined in a file except using clauses and extern alias declarations + Атрибуты сборки и модуля должны находиться перед всеми остальными элементами в файле, кроме предложений using и описаний внешних псевдонимов. @@ -9325,8 +9330,8 @@ You should consider suppressing the warning only if you're sure that you don't w - Assembly and module attributes are not allowed in this context - В данном контексте нельзя использовать атрибуты сборки и модуля + Assembly, module, and main attributes are not allowed in this context + В данном контексте нельзя использовать атрибуты сборки и модуля diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index 96705aed73f17..31b1d9270994b 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -1432,6 +1432,11 @@ liste deseni + + 'main' as an attribute target specifier + 'main' as an attribute target specifier + + newlines in interpolations ilişkilendirmedeki yeni satırlar @@ -8220,8 +8225,8 @@ RuntimeCompatibilityAttribute AssemblyInfo.cs dosyasında false olarak ayarlanm - Assembly and module attributes must precede all other elements defined in a file except using clauses and extern alias declarations - Assembly ve module öznitelikleri, using yan tümceleri ve extern diğer ad bildirimleri dışında dosyada tanımlanan diğer tüm öğelerden önce gelmelidir + Assembly, module, and main attributes must precede all other elements defined in a file except using clauses and extern alias declarations + Assembly ve module öznitelikleri, using yan tümceleri ve extern diğer ad bildirimleri dışında dosyada tanımlanan diğer tüm öğelerden önce gelmelidir @@ -9325,8 +9330,8 @@ Yalnızca asenkron çağrının tamamlanmasını beklemek istemediğinizden ve - Assembly and module attributes are not allowed in this context - Derleme ve modül özniteliklerine bu bağlamda izin verilmiyor + Assembly, module, and main attributes are not allowed in this context + Derleme ve modül özniteliklerine bu bağlamda izin verilmiyor diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index d9a0d08a783b2..690a26ba69fc9 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -1432,6 +1432,11 @@ 列表模式 + + 'main' as an attribute target specifier + 'main' as an attribute target specifier + + newlines in interpolations 内插中的换行符 @@ -8225,8 +8230,8 @@ A catch() block after a catch (System.Exception e) block can catch non-CLS excep - Assembly and module attributes must precede all other elements defined in a file except using clauses and extern alias declarations - 程序集和模块特性必须位于文件中定义的所有其他元素之前(using 子句和外部别名声明除外) + Assembly, module, and main attributes must precede all other elements defined in a file except using clauses and extern alias declarations + 程序集和模块特性必须位于文件中定义的所有其他元素之前(using 子句和外部别名声明除外) @@ -9330,8 +9335,8 @@ You should consider suppressing the warning only if you're sure that you don't w - Assembly and module attributes are not allowed in this context - 在此上下文中不允许有程序集和模块特性 + Assembly, module, and main attributes are not allowed in this context + 在此上下文中不允许有程序集和模块特性 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index 551b2ed6161a4..083b25b0f1f94 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -1432,6 +1432,11 @@ 清單模式 + + 'main' as an attribute target specifier + 'main' as an attribute target specifier + + newlines in interpolations 插補中的新行 @@ -8220,8 +8225,8 @@ A catch() block after a catch (System.Exception e) block can catch non-CLS excep - Assembly and module attributes must precede all other elements defined in a file except using clauses and extern alias declarations - 組件和模組屬性必須位於檔案中所有定義的其他項目之前 (using 子句與外部別名宣告除外) + Assembly, module, and main attributes must precede all other elements defined in a file except using clauses and extern alias declarations + 組件和模組屬性必須位於檔案中所有定義的其他項目之前 (using 子句與外部別名宣告除外) @@ -9325,8 +9330,8 @@ You should consider suppressing the warning only if you're sure that you don't w - Assembly and module attributes are not allowed in this context - 此內容中不可使用組件與模組屬性 + Assembly, module, and main attributes are not allowed in this context + 此內容中不可使用組件與模組屬性 diff --git a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests.cs b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests.cs index c81ab5e705d19..e1c259989257a 100644 --- a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests.cs @@ -5043,7 +5043,6 @@ public void M<[X]U>() { } }); } - #endregion #region Error Tests diff --git a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Locations.cs b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Locations.cs index b12d41deb17c3..bf4ab1b07d6e4 100644 --- a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Locations.cs +++ b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Locations.cs @@ -49,7 +49,7 @@ public class A : Attribute { } "; CreateCompilation(new[] { source1, source2 }).VerifyDiagnostics( - // (4,6): error CS1730: Assembly and module attributes must precede all other elements defined in a file except using clauses and extern alias declarations + // (4,6): error CS1730: Assembly, module, and main attributes must precede all other elements defined in a file except using clauses and extern alias declarations Diagnostic(ErrorCode.ERR_GlobalAttributesNotFirst, "assembly")); } diff --git a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Main.cs b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Main.cs new file mode 100644 index 0000000000000..1a3fe3f8db268 --- /dev/null +++ b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_Main.cs @@ -0,0 +1,401 @@ +// 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.Collections.Immutable; +using Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Microsoft.CodeAnalysis.Test.Utilities; +using Xunit; +using System.Linq; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests +{ + public class AttributeTests_Main : CSharpTestBase + { + [Fact] + public void TestMainAttributes() + { + var source = @" +using System; + +[main: My(""one"")] +Console.WriteLine(""Hello World""); + +public class MyAttribute : Attribute { public MyAttribute(string name) {} } +"; + + CompileAndVerify(source, + options: TestOptions.DebugExe.WithMetadataImportOptions(MetadataImportOptions.All), + symbolValidator: verifyAttributes, + sourceSymbolValidator: verifyAttributes, + expectedOutput: "Hello World"); + + static void verifyAttributes(ModuleSymbol module) + { + var attributes = GetSimpleEntryPointAttributes(module); + var attribute = Assert.Single(attributes); + + attribute.VerifyValue(0, TypedConstantKind.Primitive, "one"); + Assert.Equal(@"MyAttribute(""one"")", attribute.ToString()); + } + } + + [Fact] + public void TestMultipleMainAttributes() + { + var source = @" +using System; + +[main: My(""one"")] +[main: My(""two"")] +[main: My(""three"")] +Console.WriteLine(""Hello World""); + +[AttributeUsage(AttributeTargets.All, AllowMultiple = true)] +public class MyAttribute : Attribute { public MyAttribute(string name) {} } +"; + CompileAndVerify(source, + options: TestOptions.DebugExe.WithMetadataImportOptions(MetadataImportOptions.All), + symbolValidator: verifyAttributes, + sourceSymbolValidator: verifyAttributes, + expectedOutput: "Hello World"); + + static void verifyAttributes(ModuleSymbol module) + { + var attributes = GetSimpleEntryPointAttributes(module); + + Assert.Collection(attributes, + verifyAttribute("one"), + verifyAttribute("two"), + verifyAttribute("three")); + + static Action verifyAttribute(string expectedValue) => (attribute) => + { + attribute.VerifyValue(0, TypedConstantKind.Primitive, expectedValue); + Assert.Equal($@"MyAttribute(""{expectedValue}"")", attribute.ToString()); + }; + + } + } + + [Fact] + public void TestMultipleMainAttributesDisallowed() + { + var source = @" +using System; + +[main: My(""one"")] +[main: My(""two"")] +[main: My(""three"")] +Console.WriteLine(""Hello World""); + +public class MyAttribute : Attribute { public MyAttribute(string name) {} } +"; + var compilation = CreateCompilation(source); + compilation.VerifyDiagnostics( + // (5,8): error CS0579: Duplicate 'My' attribute + // [main: My("two")] + Diagnostic(ErrorCode.ERR_DuplicateAttribute, "My").WithArguments("My").WithLocation(5, 8), + // (6,8): error CS0579: Duplicate 'My' attribute + // [main: My("three")] + Diagnostic(ErrorCode.ERR_DuplicateAttribute, "My").WithArguments("My").WithLocation(6, 8) + ); + + var attributes = GetSimpleEntryPointAttributes(compilation.Assembly.Modules[0]); + + Assert.Collection(attributes, + verifyAttribute("one"), + verifyAttribute("two"), + verifyAttribute("three")); + + static Action verifyAttribute(string expectedValue) => (attribute) => + { + attribute.VerifyValue(0, TypedConstantKind.Primitive, expectedValue); + Assert.Equal($@"MyAttribute(""{expectedValue}"")", attribute.ToString()); + }; + } + + [Fact] + public void TestMainAttributesWithAssemblyAndModuleAttributes() + { + var source = @" +using System; + +[main: My(""one"")] +[assembly: My(""two"")] +[module: My(""three"")] +Console.WriteLine(""Hello World""); + +[AttributeUsage(AttributeTargets.All, AllowMultiple = true)] +public class MyAttribute : Attribute { public MyAttribute(string name) {} } +"; + + CompileAndVerify(source, + sourceSymbolValidator: verifyAttributes, + expectedOutput: "Hello World"); + + static void verifyAttributes(ModuleSymbol module) + { + verifySingleAttribute(GetSimpleEntryPoint(module), "one"); + verifySingleAttribute(module.ContainingAssembly, "two"); + verifySingleAttribute(module, "three"); + } + + static void verifySingleAttribute(Symbol symbol, string expectedValue) + { + var attributes = symbol.GetAttributes(); + var attribute = Assert.Single(attributes); + + attribute.VerifyValue(0, TypedConstantKind.Primitive, expectedValue); + Assert.Equal($@"MyAttribute(""{expectedValue}"")", attribute.ToString()); + }; + } + + [Fact] + public void TestMainAttributesWithInvalidAttributesAfter() + { + var source = @" +using System; + +[main: My(""one"")] +[My(""two"")] +Console.WriteLine(""Hello World""); + +[AttributeUsage(AttributeTargets.All, AllowMultiple = true)] +public class MyAttribute : Attribute { public MyAttribute(string name) {} } +"; + + var compilation = CreateCompilation(source); + compilation.VerifyDiagnostics( + // (5,1): error CS7014: Attributes are not valid in this context. + // [My("two")] + Diagnostic(ErrorCode.ERR_AttributesNotAllowed, @"[My(""two"")]").WithLocation(5, 1) + ); + + var entryPoint = GetSimpleEntryPoint(compilation.Assembly.Modules[0]); + + // one is on main + var attribute = Assert.Single(entryPoint.GetAttributes()); + attribute.VerifyValue(0, TypedConstantKind.Primitive, "one"); + Assert.Equal($@"MyAttribute(""one"")", attribute.ToString()); + } + + [Fact] + public void TestMainAttributesWithInvalidAttributesBefore() + { + var source = @" +using System; + +[My(""two"")] +[main: My(""one"")] +Console.WriteLine(""Hello World""); + +[AttributeUsage(AttributeTargets.All, AllowMultiple = true)] +public class MyAttribute : Attribute { public MyAttribute(string name) {} } +"; + + var compilation = CreateCompilation(source); + compilation.VerifyDiagnostics( + // (4,1): error CS7014: Attributes are not valid in this context. + // [My("two")] + Diagnostic(ErrorCode.ERR_AttributesNotAllowed, @"[My(""two"")]").WithLocation(4, 1) + ); + + var entryPoint = GetSimpleEntryPoint(compilation.Assembly.Modules[0]); + + // one is ignored + Assert.Empty(entryPoint.GetAttributes()); + } + + [Fact] + public void TestMainAttributesAfterCode() + { + var source = @" +using System; +Console.WriteLine(""Hello World""); + +[main: My(""one"")] +public class MyAttribute : Attribute { public MyAttribute(string name) {} } +"; + var compilation = CreateCompilation(source); + compilation.VerifyDiagnostics( + // (5,2): error CS1730: Assembly, module, and main attributes must precede all other elements defined in a file except using clauses and extern alias declarations + // [main: My("one")] + Diagnostic(ErrorCode.ERR_GlobalAttributesNotFirst, "main").WithLocation(5, 2) + ); + + var entryPoint = GetSimpleEntryPoint(compilation.Assembly.Modules[0]); + + // one is ignored + Assert.Empty(entryPoint.GetAttributes()); + } + + [Fact] + public void TestMainAttributesInADifferentFile() + { + var source = new[] {@" +using System; +Console.WriteLine(""Hello World""); + +public class MyAttribute : Attribute { public MyAttribute(string name) {} } +", +@" +[main: My(""one"")] +" }; + + CompileAndVerify(source, + options: TestOptions.DebugExe.WithMetadataImportOptions(MetadataImportOptions.All), + sourceSymbolValidator: verifyAttributes, + expectedOutput: "Hello World"); + + static void verifyAttributes(ModuleSymbol module) + { + var attributes = GetSimpleEntryPointAttributes(module); + + var attribute = Assert.Single(attributes); + attribute.VerifyValue(0, TypedConstantKind.Primitive, "one"); + Assert.Equal(@"MyAttribute(""one"")", attribute.ToString()); + } + } + + [Fact] + public void TestInvalidMainAttributesInADifferentFile() + { + var source = new[] {@" +using System; +Console.WriteLine(""Hello World""); + +public class MyAttribute : Attribute { public MyAttribute(string name) {} } +", +@" +class C {} +[main: My(""one"")] +" }; + + var compilation = CreateCompilation(source); + compilation.VerifyDiagnostics( + // (3,2): error CS1730: Assembly, module, and main attributes must precede all other elements defined in a file except using clauses and extern alias declarations + // [main: My("one")] + Diagnostic(ErrorCode.ERR_GlobalAttributesNotFirst, "main").WithLocation(3, 2) + ); + + var entryPoint = GetSimpleEntryPoint(compilation.Assembly.Modules[0]); + + // one is ignored + Assert.Empty(entryPoint.GetAttributes()); + } + + [Fact] + public void TestMainAttributesWithMultipleEntryPoints() + { + var source = new[] {@" +using System; +[main: My(""one"")] + +Console.WriteLine(""Hello World""); + +[AttributeUsage(AttributeTargets.All, AllowMultiple = true)] +public class MyAttribute : Attribute { public MyAttribute(string name) {} } +", +@" +[main: My(""two"")] +System.Console.WriteLine(""Hello World 2""); +", +@" +System.Console.WriteLine(""Hello World 3""); +",}; + + var compilation = CreateCompilation(source); + compilation.VerifyDiagnostics( + // (2,1): error CS8802: Only one compilation unit can have top-level statements. + // System.Console.WriteLine("Hello World 3"); + Diagnostic(ErrorCode.ERR_SimpleProgramMultipleUnitsWithTopLevelStatements, "System").WithLocation(2, 1), + // (3,1): error CS8802: Only one compilation unit can have top-level statements. + // System.Console.WriteLine("Hello World 2"); + Diagnostic(ErrorCode.ERR_SimpleProgramMultipleUnitsWithTopLevelStatements, "System").WithLocation(3, 1) + ); + + var entryPoints = GetSimpleEntryPoints(compilation.Assembly.Modules[0]); + + Assert.Equal(3, entryPoints.Length); + + // first entry point gets all attributes + Assert.Collection(entryPoints[0].GetAttributes(), + verifyAttribute("one"), + verifyAttribute("two")); + + // other entry points get none + Assert.Empty(entryPoints[1].GetAttributes()); + Assert.Empty(entryPoints[2].GetAttributes()); + + static Action verifyAttribute(string expectedValue) => (attribute) => + { + attribute.VerifyValue(0, TypedConstantKind.Primitive, expectedValue); + Assert.Equal($@"MyAttribute(""{expectedValue}"")", attribute.ToString()); + }; + } + + [Theory] + [InlineData("All", true)] + [InlineData("Method", true)] + [InlineData("Class", false)] + [InlineData("Field", false)] + [InlineData("Assembly", false)] + [InlineData("Module", false)] + public void TestMainAttributesWithSpecificLocation(string location, bool valid) + { + var source = CreateCompilation($@" +using System; + +[main: My(""one"")] +Console.WriteLine(""Hello World""); + +[AttributeUsage(AttributeTargets.{location}, AllowMultiple = true)] +public class MyAttribute : Attribute {{ public MyAttribute(string name) {{}} }} +"); + + source.VerifyDiagnostics(valid ? Array.Empty() : + new[] + { + // (4,8): error CS0592: Attribute 'My' is not valid on this declaration type. It is only valid on '...' declarations. + // [main: My("one")] + Diagnostic(ErrorCode.ERR_AttributeOnBadSymbolType, "My").WithArguments("My", location.ToLower()).WithLocation(4, 8) + }); + } + + [Fact] + public void TestMainAttributesInScript() + { + var compilation = CreateSubmission(@" +using System; +[main: My(""one"")] + +public class C {} +public class MyAttribute : Attribute { public MyAttribute(string name) {} }", + parseOptions: TestOptions.Script.WithLanguageVersion(LanguageVersion.Preview)); + + compilation.VerifyDiagnostics( + // (3,2): error CS7026: Assembly and module attributes are not allowed in this context + // [main: My("one")] + Diagnostic(ErrorCode.ERR_GlobalAttributesNotAllowed, "main").WithLocation(3, 2) + ); + } + + private static ImmutableArray GetSimpleEntryPointAttributes(ModuleSymbol module) => GetSimpleEntryPoint(module).GetAttributes(); + + private static MethodSymbol GetSimpleEntryPoint(ModuleSymbol module) => Assert.Single(GetSimpleEntryPoints(module)); + + private static ImmutableArray GetSimpleEntryPoints(ModuleSymbol module) + { + var program = module.GlobalNamespace.GetMember(WellKnownMemberNames.TopLevelStatementsEntryPointTypeName); + var methods = module switch + { + SourceModuleSymbol => program.GetMembers().Where(m => m is SynthesizedSimpleProgramEntryPointSymbol), + _ => program.GetMembers(WellKnownMemberNames.TopLevelStatementsEntryPointMethodName) + }; + return methods.Cast().ToImmutableArray(); + } + } +} diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/TopLevelStatementsTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/TopLevelStatementsTests.cs index 38f818445ecd8..3ac3ccc24a079 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/TopLevelStatementsTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/TopLevelStatementsTests.cs @@ -5871,7 +5871,7 @@ class MyAttribute : System.Attribute var comp = CreateCompilation(text, options: TestOptions.DebugExe, parseOptions: DefaultParseOptions); comp.VerifyDiagnostics( - // (4,2): error CS1730: Assembly and module attributes must precede all other elements defined in a file except using clauses and extern alias declarations + // (4,2): error CS1730: Assembly, module, and main attributes must precede all other elements defined in a file except using clauses and extern alias declarations // [module: MyAttribute] Diagnostic(ErrorCode.ERR_GlobalAttributesNotFirst, "module").WithLocation(4, 2) ); diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/DeclarationParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/DeclarationParsingTests.cs index f6c25667d5b3e..487f982e56bef 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/DeclarationParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/DeclarationParsingTests.cs @@ -556,6 +556,91 @@ public void TestMultipleGlobalAttributeDeclarations() Assert.NotEqual(default, ad.CloseBracketToken); } + [Fact] + public void TestGlobalMainAttribute() + { + var text = "[main:a]"; + var file = this.ParseFile(text, TestOptions.RegularNext); + + Assert.NotNull(file); + Assert.Equal(1, file.AttributeLists.Count); + Assert.Equal(text, file.ToString()); + Assert.Equal(0, file.Errors().Length); + + Assert.Equal(SyntaxKind.AttributeList, file.AttributeLists[0].Kind()); + var ad = (AttributeListSyntax)file.AttributeLists[0]; + + Assert.NotEqual(default, ad.OpenBracketToken); + Assert.NotNull(ad.Target); + Assert.NotEqual(default, ad.Target.Identifier); + Assert.Equal("main", ad.Target.Identifier.ToString()); + Assert.Equal(SyntaxKind.MainKeyword, ad.Target.Identifier.Kind()); + Assert.NotEqual(default, ad.Target.ColonToken); + Assert.Equal(1, ad.Attributes.Count); + Assert.NotNull(ad.Attributes[0].Name); + Assert.Equal("a", ad.Attributes[0].Name.ToString()); + Assert.Null(ad.Attributes[0].ArgumentList); + Assert.NotEqual(default, ad.CloseBracketToken); + } + + [Fact] + public void TestGlobalMainAttribute_Verbatim() + { + var text = "[@main:a]"; + var file = this.ParseFile(text, TestOptions.RegularNext); + + Assert.NotNull(file); + Assert.Equal(1, file.AttributeLists.Count); + Assert.Equal(text, file.ToString()); + Assert.Equal(0, file.Errors().Length); + + Assert.Equal(SyntaxKind.AttributeList, file.AttributeLists[0].Kind()); + var ad = (AttributeListSyntax)file.AttributeLists[0]; + + Assert.NotEqual(default, ad.OpenBracketToken); + Assert.NotNull(ad.Target); + Assert.NotEqual(default, ad.Target.Identifier); + Assert.Equal("@main", ad.Target.Identifier.ToString()); + Assert.Equal(SyntaxKind.IdentifierToken, ad.Target.Identifier.Kind()); + Assert.Equal(AttributeLocation.Main, ad.Target.Identifier.ToAttributeLocation()); + Assert.NotEqual(default, ad.Target.ColonToken); + Assert.Equal(1, ad.Attributes.Count); + Assert.NotNull(ad.Attributes[0].Name); + Assert.Equal("a", ad.Attributes[0].Name.ToString()); + Assert.Null(ad.Attributes[0].ArgumentList); + Assert.NotEqual(default, ad.CloseBracketToken); + } + + [Fact] + public void TestGlobalMainAttribute_LangVersion() + { + var text = "[main:a]"; + var file = this.ParseFile(text, TestOptions.Regular10); + + Assert.NotNull(file); + Assert.Equal(1, file.AttributeLists.Count); + Assert.Equal(text, file.ToString()); + + file.GetDiagnostics().Verify( + // (1,2): error CS8652: The feature ''main' as an attribute target specifier' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // [main:a] + Diagnostic(ErrorCode.ERR_FeatureInPreview, "main:").WithArguments("'main' as an attribute target specifier").WithLocation(1, 2) + ); + } + + [Fact] + public void TestGlobalMainAttribute_LangVersion_Next() + { + var text = "[main:a]"; + var file = this.ParseFile(text, TestOptions.RegularNext); + + Assert.NotNull(file); + Assert.Equal(1, file.AttributeLists.Count); + Assert.Equal(text, file.ToString()); + + file.GetDiagnostics().Verify(); + } + [Fact] public void TestNamespace() {