diff --git a/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md index 5b85be93d498a..57b35de0133bc 100644 --- a/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md +++ b/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md @@ -338,3 +338,16 @@ Console.WriteLine($"{{{12:X}}}"); The workaround is to remove the extra braces in the format string. You can learn more about this change in the associated [roslyn issue](https://github.com/dotnet/roslyn/issues/57750). + +## Types cannot be named `required` + +***Introduced in Visual Studio 2022 version 17.3.*** Starting in C# 11, types cannot be named `required`. The compiler will report an error on all such type names. To work around this, the type name and all usages must be escaped with an `@`: + +```csharp +class required {} // Error CS9029 +class @required {} // No error +``` + +This was done as `required` is now a member modifier for properties and fields. + +You can learn more about this change in the associated [csharplang issue](https://github.com/dotnet/csharplang/issues/3630). diff --git a/docs/contributing/Compiler Test Plan.md b/docs/contributing/Compiler Test Plan.md index 31b02c8061806..0219996d62e13 100644 --- a/docs/contributing/Compiler Test Plan.md +++ b/docs/contributing/Compiler Test Plan.md @@ -39,8 +39,8 @@ This document provides guidance for thinking about language interactions and tes - Access modifiers (public, protected, internal, protected internal, private protected, private), static, ref - type declarations (class, record class/struct with or without positional members, struct, interface, type parameter) - methods -- fields -- properties (including get/set/init accessors) +- fields (required and not) +- properties (including get/set/init accessors, required and not) - events (including add/remove accessors) - Parameter modifiers (ref, out, in, params) - Attributes (including generic attributes and security attributes) @@ -110,6 +110,7 @@ This document provides guidance for thinking about language interactions and tes - pre-processing directives - COM interop - modopt and modreq +- CompilerFeatureRequiredAttribute - ref assemblies - extern alias - UnmanagedCallersOnly diff --git a/src/Analyzers/CSharp/Tests/OrderModifiers/OrderModifiersTests.cs b/src/Analyzers/CSharp/Tests/OrderModifiers/OrderModifiersTests.cs index d5de825a48f55..5805646c4955d 100644 --- a/src/Analyzers/CSharp/Tests/OrderModifiers/OrderModifiersTests.cs +++ b/src/Analyzers/CSharp/Tests/OrderModifiers/OrderModifiersTests.cs @@ -431,5 +431,39 @@ static internal class C2 static internal class Nested { } }"); } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsOrderModifiers)] + public async Task RequiredAfterAllOnProp() + { + await TestInRegularAndScriptAsync(""" + class C + { + [|required|] public virtual unsafe int Prop { get; init; } + } + """, + """ + class C + { + public virtual unsafe required int Prop { get; init; } + } + """); + } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsOrderModifiers)] + public async Task RequiredAfterAllButVolatileOnField() + { + await TestInRegularAndScriptAsync(""" + class C + { + [|required|] public unsafe volatile int Field; + } + """, + """ + class C + { + public unsafe required volatile int Field; + } + """); + } } } diff --git a/src/CodeStyle/Core/Analyzers/PublicAPI.Unshipped.txt b/src/CodeStyle/Core/Analyzers/PublicAPI.Unshipped.txt index b79a079b6d63e..691883be01a72 100644 --- a/src/CodeStyle/Core/Analyzers/PublicAPI.Unshipped.txt +++ b/src/CodeStyle/Core/Analyzers/PublicAPI.Unshipped.txt @@ -41,6 +41,7 @@ Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers.IsOverride.get -> b Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers.IsPartial.get -> bool Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers.IsReadOnly.get -> bool Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers.IsRef.get -> bool +Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers.IsRequired.get -> bool Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers.IsSealed.get -> bool Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers.IsStatic.get -> bool Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers.IsUnsafe.get -> bool @@ -56,6 +57,7 @@ Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers.WithIsNew(bool isNe Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers.WithIsOverride(bool isOverride) -> Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers.WithIsReadOnly(bool isReadOnly) -> Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers.WithIsRef(bool isRef) -> Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers +Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers.WithIsRequired(bool isRequired) -> Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers.WithIsSealed(bool isSealed) -> Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers.WithIsStatic(bool isStatic) -> Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers.WithIsUnsafe(bool isUnsafe) -> Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers @@ -84,6 +86,7 @@ static Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers.Override.get static Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers.Partial.get -> Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers static Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers.ReadOnly.get -> Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers static Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers.Ref.get -> Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers +static Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers.Required.get -> Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers static Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers.Sealed.get -> Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers static Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers.Static.get -> Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers static Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers.TryParse(string value, out Microsoft.CodeAnalysis.Internal.Editing.DeclarationModifiers modifiers) -> bool diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Attributes.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Attributes.cs index 9bacba924af14..118b374e5ea2f 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Attributes.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Attributes.cs @@ -194,7 +194,8 @@ private BoundAttribute BindAttributeCore(AttributeSyntax node, NamedTypeSymbol a diagnostics, out var memberResolutionResult, out var candidateConstructors, - allowProtectedConstructorsOfBaseType: true); + allowProtectedConstructorsOfBaseType: true, + suppressUnsupportedRequiredMembersError: false); attributeConstructor = memberResolutionResult.Member; expanded = memberResolutionResult.Resolution == MemberResolutionKind.ApplicableInExpandedForm; argsToParamsOpt = memberResolutionResult.Result.ArgsToParamsOpt; @@ -238,6 +239,11 @@ private BoundAttribute BindAttributeCore(AttributeSyntax node, NamedTypeSymbol a ImmutableArray boundNamedArguments = analyzedArguments.NamedArguments?.ToImmutableAndFree() ?? ImmutableArray.Empty; Debug.Assert(boundNamedArguments.All(arg => !arg.Right.NeedsToBeConverted())); + if (attributeConstructor is not null) + { + CheckRequiredMembersInObjectInitializer(attributeConstructor, ImmutableArray.CastUp(boundNamedArguments), node, diagnostics); + } + analyzedArguments.ConstructorArguments.Free(); return new BoundAttribute( diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index b68da7a2b9efd..93e1463d4bcfc 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -4073,7 +4073,8 @@ private BoundExpression BindConstructorInitializerCore( diagnostics, out memberResolutionResult, out candidateConstructors, - allowProtectedConstructorsOfBaseType: true); + allowProtectedConstructorsOfBaseType: true, + suppressUnsupportedRequiredMembersError: true); MethodSymbol resultMember = memberResolutionResult.Member; validateRecordCopyConstructor(constructor, baseType, resultMember, errorLocation, diagnostics); @@ -4125,6 +4126,13 @@ private BoundExpression BindConstructorInitializerCore( diagnostics); } + if (resultMember.HasSetsRequiredMembers && !constructor.HasSetsRequiredMembers) + { + hasErrors = true; + // This constructor must add 'SetsRequiredMembers' because it chains to a constructor that has that attribute. + diagnostics.Add(ErrorCode.ERR_ChainingToSetsRequiredMembersRequiresSetsRequiredMembers, errorLocation); + } + return new BoundCall( nonNullSyntax, receiver, @@ -4977,6 +4985,102 @@ private static void ReportDuplicateObjectMemberInitializers(BoundExpression boun } } +#nullable enable + private static void CheckRequiredMembersInObjectInitializer( + MethodSymbol constructor, + ImmutableArray initializers, + SyntaxNode creationSyntax, + BindingDiagnosticBag diagnostics) + { + if (!constructor.ShouldCheckRequiredMembers()) + { + return; + } + + if (constructor.ContainingType.HasRequiredMembersError) + { + // An error will be reported on the constructor if from source, or a use-site diagnostic will be reported on the use if from metadata. + return; + } + + var requiredMembers = constructor.ContainingType.AllRequiredMembers; + + if (requiredMembers.Count == 0) + { + return; + } + + var requiredMembersBuilder = requiredMembers.ToBuilder(); + + if (initializers.IsDefaultOrEmpty) + { + reportMembers(); + return; + } + + foreach (var initializer in initializers) + { + if (initializer is not BoundAssignmentOperator assignmentOperator) + { + continue; + } + + var memberSymbol = assignmentOperator.Left switch + { + // Regular initializers + BoundObjectInitializerMember member => member.MemberSymbol, + // Attribute initializers + BoundPropertyAccess propertyAccess => propertyAccess.PropertySymbol, + BoundFieldAccess fieldAccess => fieldAccess.FieldSymbol, + // Error cases + _ => null + }; + + if (memberSymbol is null) + { + continue; + } + + if (!requiredMembersBuilder.TryGetValue(memberSymbol.Name, out var requiredMember)) + { + continue; + } + + if (!memberSymbol.Equals(requiredMember, TypeCompareKind.ConsiderEverything)) + { + continue; + } + + requiredMembersBuilder.Remove(memberSymbol.Name); + + if (assignmentOperator.Right is BoundObjectInitializerExpressionBase initializerExpression) + { + // Required member '{0}' must be assigned a value, it cannot use a nested member or collection initializer. + diagnostics.Add(ErrorCode.ERR_RequiredMembersMustBeAssignedValue, initializerExpression.Syntax.Location, requiredMember); + } + } + + reportMembers(); + + void reportMembers() + { + Location location = creationSyntax switch + { + ObjectCreationExpressionSyntax { Type: { } type } => type.Location, + BaseObjectCreationExpressionSyntax { NewKeyword: { } newKeyword } => newKeyword.GetLocation(), + AttributeSyntax { Name: { } name } => name.Location, + _ => creationSyntax.Location + }; + + foreach (var (_, member) in requiredMembersBuilder) + { + // Required member '{0}' must be set in the object initializer or attribute constructor. + diagnostics.Add(ErrorCode.ERR_RequiredMemberMustBeSet, location, member); + } + } + } +#nullable disable + private BoundCollectionInitializerExpression BindCollectionInitializerExpression( InitializerExpressionSyntax initializerSyntax, TypeSymbol initializerType, @@ -5375,7 +5479,8 @@ protected BoundExpression BindClassCreationExpression( diagnostics, out MemberResolutionResult memberResolutionResult, out ImmutableArray candidateConstructors, - allowProtectedConstructorsOfBaseType: false) && + allowProtectedConstructorsOfBaseType: false, + suppressUnsupportedRequiredMembersError: false) && !type.IsAbstract) { var method = memberResolutionResult.Member; @@ -5421,7 +5526,7 @@ protected BoundExpression BindClassCreationExpression( } boundInitializerOpt = makeBoundInitializerOpt(); - result = new BoundObjectCreationExpression( + var creation = new BoundObjectCreationExpression( node, method, candidateConstructors, @@ -5437,7 +5542,9 @@ protected BoundExpression BindClassCreationExpression( type, hasError); - return result; + CheckRequiredMembersInObjectInitializer(creation.Constructor, creation.InitializerExpressionOpt?.Initializers ?? default, creation.Syntax, diagnostics); + + return creation; } LookupResultKind resultKind; @@ -5709,7 +5816,8 @@ internal bool TryPerformConstructorOverloadResolution( BindingDiagnosticBag diagnostics, out MemberResolutionResult memberResolutionResult, out ImmutableArray candidateConstructors, - bool allowProtectedConstructorsOfBaseType) // Last to make named arguments more convenient. + bool allowProtectedConstructorsOfBaseType, + bool suppressUnsupportedRequiredMembersError) // Last to make named arguments more convenient. { // Get accessible constructors for performing overload resolution. ImmutableArray allInstanceConstructors; @@ -5757,7 +5865,7 @@ internal bool TryPerformConstructorOverloadResolution( } } - diagnostics.Add(errorLocation, useSiteInfo); + ReportConstructorUseSiteDiagnostics(errorLocation, diagnostics, suppressUnsupportedRequiredMembersError, useSiteInfo); if (succeededIgnoringAccessibility) { @@ -5814,6 +5922,31 @@ internal bool TryPerformConstructorOverloadResolution( return succeededConsideringAccessibility; } + internal static bool ReportConstructorUseSiteDiagnostics(Location errorLocation, BindingDiagnosticBag diagnostics, bool suppressUnsupportedRequiredMembersError, CompoundUseSiteInfo useSiteInfo) + { + if (suppressUnsupportedRequiredMembersError && useSiteInfo.AccumulatesDiagnostics && useSiteInfo.Diagnostics is { Count: not 0 }) + { + diagnostics.AddDependencies(useSiteInfo); + foreach (var diagnostic in useSiteInfo.Diagnostics) + { + // We don't want to report this error here because we'll report ERR_RequiredMembersBaseTypeInvalid. That error is suppressable by the + // user using the `SetsRequiredMembers` attribute on the constructor, so reporting this error would prevent that from working. + if ((ErrorCode)diagnostic.Code == ErrorCode.ERR_RequiredMembersInvalid) + { + continue; + } + + diagnostics.ReportUseSiteDiagnostic(diagnostic, errorLocation); + } + + return true; + } + else + { + return diagnostics.Add(errorLocation, useSiteInfo); + } + } + private ImmutableArray GetAccessibleConstructorsForOverloadResolution(NamedTypeSymbol type, ref CompoundUseSiteInfo useSiteInfo) { ImmutableArray allInstanceConstructors; diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Initializers.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Initializers.cs index c25b15d69fdb3..52da4ec292718 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Initializers.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Initializers.cs @@ -18,7 +18,6 @@ internal struct ProcessedFieldInitializers { internal ImmutableArray BoundInitializers { get; set; } internal BoundStatement? LoweredInitializers { get; set; } - internal NullableWalker.VariableState AfterInitializersState; internal bool HasErrors { get; set; } internal ImportChain? FirstImportChain { get; set; } } diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 248035e54030b..d2ba164fdaa89 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -7031,6 +7031,39 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ The type name only contains lower-cased ascii characters. Such names may become reserved for the language. + + Types and aliases cannot be named 'required'. + + + required members + + + '{0}' must be required because it overrides required member '{1}' + + + Required member '{0}' cannot be hidden by '{1}'. + + + Required member '{0}' cannot be less visible or have a setter less visible than the containing type '{1}'. + + + Do not use 'System.Runtime.CompilerServices.RequiredMemberAttribute'. Use the 'required' keyword on required fields and properties instead. + + + Required member '{0}' must be settable. + + + Required member '{0}' must be set in the object initializer or attribute constructor. + + + Required member '{0}' must be assigned a value, it cannot use a nested member or collection initializer. + + + The required members list for '{0}' is malformed and cannot be interpreted. + + + The required members list for the base type '{0}' is malformed and cannot be interpreted. To use this constructor, apply the 'SetsRequiredMembers' attribute. + Line contains different whitespace than the closing line of the raw string literal: '{0}' versus '{1}' @@ -7061,12 +7094,33 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ UTF-8 string literals + + An expression tree may not contain UTF-8 string conversion or literal. + + + This constructor must add 'SetsRequiredMembers' because it chains to a constructor that has that attribute. + + + '{2}' cannot satisfy the 'new()' constraint on parameter '{1}' in the generic type or or method '{0}' because '{2}' has required members. + unsigned right shift relaxed shift operator + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. + + + Required member '{0}' should not be attributed with 'ObsoleteAttribute' unless the containing type is obsolete or all constructors are obsolete. + + + Members attributed with 'ObsoleteAttribute' should not be required unless the containing type is obsolete or all constructors are obsolete. + + + Ref returning properties cannot be required. + Unexpected keyword 'unchecked' diff --git a/src/Compilers/CSharp/Portable/Compilation/MethodBodySemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/MethodBodySemanticModel.cs index 7b425fcee19c8..eba9d23ee4424 100644 --- a/src/Compilers/CSharp/Portable/Compilation/MethodBodySemanticModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/MethodBodySemanticModel.cs @@ -304,7 +304,7 @@ protected override BoundNode RewriteNullableBoundNodesWithSnapshots( out NullableWalker.SnapshotManager snapshotManager, ref ImmutableDictionary remappedSymbols) { - var afterInitializersState = NullableWalker.GetAfterInitializersState(Compilation, MemberSymbol); + var afterInitializersState = NullableWalker.GetAfterInitializersState(Compilation, MemberSymbol, boundRoot); return NullableWalker.AnalyzeAndRewrite(Compilation, MemberSymbol, boundRoot, binder, afterInitializersState, diagnostics, createSnapshots, out snapshotManager, ref remappedSymbols); } diff --git a/src/Compilers/CSharp/Portable/Compiler/AnonymousTypeMethodBodySynthesizer.cs b/src/Compilers/CSharp/Portable/Compiler/AnonymousTypeMethodBodySynthesizer.cs index 9d9fac748c464..86eb7b3a6f942 100644 --- a/src/Compilers/CSharp/Portable/Compiler/AnonymousTypeMethodBodySynthesizer.cs +++ b/src/Compilers/CSharp/Portable/Compiler/AnonymousTypeMethodBodySynthesizer.cs @@ -69,6 +69,8 @@ internal override bool HasSpecialName { get { return true; } } + + protected override bool HasSetsRequiredMembersImpl => false; } private sealed partial class AnonymousTypePropertyGetAccessorSymbol : SynthesizedMethodBase diff --git a/src/Compilers/CSharp/Portable/Compiler/MethodBodySynthesizer.Lowered.cs b/src/Compilers/CSharp/Portable/Compiler/MethodBodySynthesizer.Lowered.cs index dcd697fcfa8d6..9b05b5cb9998e 100644 --- a/src/Compilers/CSharp/Portable/Compiler/MethodBodySynthesizer.Lowered.cs +++ b/src/Compilers/CSharp/Portable/Compiler/MethodBodySynthesizer.Lowered.cs @@ -290,6 +290,8 @@ internal override void GenerateMethodBody(TypeCompilationState compilationState, F.CloseMethod(F.ThrowNull()); } } + + protected sealed override bool HasSetsRequiredMembersImpl => throw ExceptionUtilities.Unreachable; } internal abstract partial class MethodToClassRewriter diff --git a/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs b/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs index 505f9aebffbcf..9ae7b2f0ac368 100644 --- a/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs +++ b/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs @@ -625,6 +625,7 @@ private void CompileNamedType(NamedTypeSymbol containingType) useConstructorExitWarnings: true, initialNullableState: null, getFinalNullableState: false, + baseOrThisInitializer: null, finalNullableState: out _); } } @@ -1006,7 +1007,8 @@ private void CompileMethod( useConstructorExitWarnings: false, initialNullableState: null, getFinalNullableState: true, - out processedInitializers.AfterInitializersState); + baseOrThisInitializer: null, + out _); } var unusedDiagnostics = DiagnosticBag.GetInstance(); @@ -1026,28 +1028,12 @@ private void CompileMethod( processedInitializers.HasErrors = processedInitializers.HasErrors || analyzedInitializers.HasAnyErrors; } - if (includeInitializersInBody && - processedInitializers.AfterInitializersState is null && - ReportNullableDiagnostics) - { - NullableWalker.AnalyzeIfNeeded( - _compilation, - methodSymbol, - // we analyze to produce an AfterInitializersState even if there are no initializers - // because it conveniently allows us to capture all the 'default' states for applicable members - analyzedInitializers ?? GetSynthesizedEmptyBody(methodSymbol), - diagsForCurrentMethod.DiagnosticBag, - useConstructorExitWarnings: false, - initialNullableState: null, - getFinalNullableState: true, - out processedInitializers.AfterInitializersState); - } - body = BindMethodBody( methodSymbol, compilationState, diagsForCurrentMethod, - processedInitializers.AfterInitializersState, + includeInitializersInBody, + analyzedInitializers, ReportNullableDiagnostics, out importChain, out originalBodyNested, @@ -1704,19 +1690,31 @@ private static void GetStateMachineSlotDebugInfo( } // NOTE: can return null if the method has no body. - internal static BoundBlock BindMethodBody(MethodSymbol method, TypeCompilationState compilationState, BindingDiagnosticBag diagnostics) +#nullable enable + internal static BoundBlock? BindMethodBody(MethodSymbol method, TypeCompilationState compilationState, BindingDiagnosticBag diagnostics) { - return BindMethodBody(method, compilationState, diagnostics, nullableInitialState: null, reportNullableDiagnostics: true, out _, out _, out _, out _); + return BindMethodBody( + method, + compilationState, + diagnostics, + includeInitializersInBody: false, + initializersBody: null, + reportNullableDiagnostics: true, + importChain: out _, + originalBodyNested: out _, + prependedDefaultValueTypeConstructorInitializer: out _, + forSemanticModel: out _); } // NOTE: can return null if the method has no body. - private static BoundBlock BindMethodBody( + private static BoundBlock? BindMethodBody( MethodSymbol method, TypeCompilationState compilationState, BindingDiagnosticBag diagnostics, - NullableWalker.VariableState nullableInitialState, + bool includeInitializersInBody, + BoundNode? initializersBody, bool reportNullableDiagnostics, - out ImportChain importChain, + out ImportChain? importChain, out bool originalBodyNested, out bool prependedDefaultValueTypeConstructorInitializer, out MethodBodySemanticModel.InitialState forSemanticModel) @@ -1726,11 +1724,15 @@ private static BoundBlock BindMethodBody( importChain = null; forSemanticModel = default; - BoundBlock body; + BoundBlock? body; + NullableWalker.VariableState? nullableInitialState = null; + + initializersBody ??= GetSynthesizedEmptyBody(method); if (method is SynthesizedRecordConstructor recordStructPrimaryCtor && method.ContainingType.IsRecordStruct) { body = BoundBlock.SynthesizedNoLocals(recordStructPrimaryCtor.GetSyntax()); + nullableInitialState = getInitializerState(body); } else if (method is SourceMemberMethodSymbol sourceMethod) { @@ -1759,12 +1761,15 @@ syntaxNode is ConstructorDeclarationSyntax constructorSyntax && importChain = bodyBinder.ImportChain; BoundNode methodBody = bodyBinder.BindMethodBody(syntaxNode, diagnostics); BoundNode methodBodyForSemanticModel = methodBody; - NullableWalker.SnapshotManager snapshotManager = null; - ImmutableDictionary remappedSymbols = null; + NullableWalker.SnapshotManager? snapshotManager = null; + ImmutableDictionary? remappedSymbols = null; var compilation = bodyBinder.Compilation; + nullableInitialState = getInitializerState(methodBody); + if (reportNullableDiagnostics) { + Debug.Assert(diagnostics.DiagnosticBag != null); if (compilation.IsNullableAnalysisEnabledIn(method)) { var isSufficientLangVersion = compilation.LanguageVersion >= MessageID.IDS_FeatureNullableReferenceTypes.RequiredVersion(); @@ -1792,17 +1797,17 @@ syntaxNode is ConstructorDeclarationSyntax constructorSyntax && useConstructorExitWarnings: true, nullableInitialState, getFinalNullableState: false, + baseOrThisInitializer: null, finalNullableState: out _); } } - forSemanticModel = new MethodBodySemanticModel.InitialState(syntaxNode, methodBodyForSemanticModel, bodyBinder, snapshotManager, remappedSymbols); switch (methodBody.Kind) { case BoundKind.ConstructorMethodBody: var constructor = (BoundConstructorMethodBody)methodBody; - body = constructor.BlockBody ?? constructor.ExpressionBody; + body = constructor.BlockBody ?? constructor.ExpressionBody!; if (constructor.Initializer is BoundExpressionStatement expressionStatement) { @@ -1831,7 +1836,8 @@ syntaxNode is ConstructorDeclarationSyntax constructorSyntax && case BoundKind.NonConstructorMethodBody: var nonConstructor = (BoundNonConstructorMethodBody)methodBody; - body = nonConstructor.BlockBody ?? nonConstructor.ExpressionBody; + body = nonConstructor.BlockBody ?? nonConstructor.ExpressionBody!; + Debug.Assert(body != null); break; case BoundKind.Block: @@ -1844,7 +1850,7 @@ syntaxNode is ConstructorDeclarationSyntax constructorSyntax && else { var property = sourceMethod.AssociatedSymbol as SourcePropertySymbolBase; - if ((object)property != null && property.IsAutoPropertyWithGetAccessor) + if (property is not null && property.IsAutoPropertyWithGetAccessor) { return MethodBodySynthesizer.ConstructAutoPropertyAccessorBody(sourceMethod); } @@ -1861,15 +1867,18 @@ syntaxNode is ConstructorDeclarationSyntax constructorSyntax && var stmts = ArrayBuilder.GetInstance(); ctor.GenerateMethodBodyStatements(factory, stmts, diagnostics); body = BoundBlock.SynthesizedNoLocals(node, stmts.ToImmutableAndFree()); + nullableInitialState = getInitializerState(body); } else { // synthesized methods should return their bound bodies body = null; + nullableInitialState = getInitializerState(null); } if (reportNullableDiagnostics && method.IsConstructor() && method.IsImplicitlyDeclared && nullableInitialState is object) { + Debug.Assert(diagnostics.AccumulatesDiagnostics); NullableWalker.AnalyzeIfNeeded( compilationState.Compilation, method, @@ -1878,6 +1887,7 @@ syntaxNode is ConstructorDeclarationSyntax constructorSyntax && useConstructorExitWarnings: true, nullableInitialState, getFinalNullableState: false, + baseOrThisInitializer: null, finalNullableState: out _); } @@ -1909,7 +1919,18 @@ syntaxNode is ConstructorDeclarationSyntax constructorSyntax && } return BoundBlock.SynthesizedNoLocals(method.GetNonNullSyntaxNode(), statements); + + NullableWalker.VariableState? getInitializerState(BoundNode? body) + { + if (reportNullableDiagnostics && includeInitializersInBody) + { + return NullableWalker.GetAfterInitializersState(compilationState.Compilation, method, initializersBody, body, diagnostics); + } + + return null; + } } +#nullable disable private static BoundBlock GetSynthesizedEmptyBody(Symbol symbol) { @@ -2141,7 +2162,9 @@ private static BoundCall GenerateBaseCopyConstructorInitializer(SynthesizedRecor return null; } - if (Binder.ReportUseSite(baseConstructor, diagnostics, diagnosticsLocation)) + var constructorUseSiteInfo = new CompoundUseSiteInfo(diagnostics, constructor.ContainingAssembly); + constructorUseSiteInfo.Add(baseConstructor.GetUseSiteInfo()); + if (Binder.ReportConstructorUseSiteDiagnostics(diagnosticsLocation, diagnostics, suppressUnsupportedRequiredMembersError: constructor.HasSetsRequiredMembers, constructorUseSiteInfo)) { return null; } diff --git a/src/Compilers/CSharp/Portable/Declarations/DeclarationModifiers.cs b/src/Compilers/CSharp/Portable/Declarations/DeclarationModifiers.cs index 7f4f224ad24b3..87a30c1b2290d 100644 --- a/src/Compilers/CSharp/Portable/Declarations/DeclarationModifiers.cs +++ b/src/Compilers/CSharp/Portable/Declarations/DeclarationModifiers.cs @@ -36,6 +36,8 @@ internal enum DeclarationModifiers : uint Async = 1 << 20, Ref = 1 << 21, // used only for structs + Required = 1 << 22, // Used only for properties and fields + All = (1 << 23) - 1, // all modifiers Unset = 1 << 23, // used when a modifiers value hasn't yet been computed diff --git a/src/Compilers/CSharp/Portable/Declarations/DeclarationTreeBuilder.cs b/src/Compilers/CSharp/Portable/Declarations/DeclarationTreeBuilder.cs index 68917838c97bd..aa111512f55b1 100644 --- a/src/Compilers/CSharp/Portable/Declarations/DeclarationTreeBuilder.cs +++ b/src/Compilers/CSharp/Portable/Declarations/DeclarationTreeBuilder.cs @@ -750,6 +750,7 @@ private static ImmutableSegmentedDictionary GetNonTypeMember bool anyMethodHadExtensionSyntax = false; bool anyMemberHasAttributes = false; bool anyNonTypeMembers = false; + bool anyRequiredMembers = false; var memberNameBuilder = s_memberNameBuilderPool.Allocate(); @@ -769,6 +770,11 @@ private static ImmutableSegmentedDictionary GetNonTypeMember { anyMemberHasAttributes = true; } + + if (!anyRequiredMembers && checkPropertyOrFieldMemberForRequiredModifier(member)) + { + anyRequiredMembers = true; + } } if (anyMethodHadExtensionSyntax) @@ -786,7 +792,24 @@ private static ImmutableSegmentedDictionary GetNonTypeMember declFlags |= SingleTypeDeclaration.TypeDeclarationFlags.HasAnyNontypeMembers; } + if (anyRequiredMembers) + { + declFlags |= SingleTypeDeclaration.TypeDeclarationFlags.HasRequiredMembers; + } + return ToImmutableAndFree(memberNameBuilder); + + static bool checkPropertyOrFieldMemberForRequiredModifier(Syntax.InternalSyntax.CSharpSyntaxNode member) + { + var modifiers = member switch + { + Syntax.InternalSyntax.FieldDeclarationSyntax fieldDeclaration => fieldDeclaration.Modifiers, + Syntax.InternalSyntax.PropertyDeclarationSyntax propertyDeclaration => propertyDeclaration.Modifiers, + _ => default + }; + + return modifiers.Any((int)SyntaxKind.RequiredKeyword); + } } private static bool CheckMethodMemberForExtensionSyntax(Syntax.InternalSyntax.CSharpSyntaxNode member) diff --git a/src/Compilers/CSharp/Portable/Declarations/SingleTypeDeclaration.cs b/src/Compilers/CSharp/Portable/Declarations/SingleTypeDeclaration.cs index 3c2a209adf7e8..bacdf2682c2d7 100644 --- a/src/Compilers/CSharp/Portable/Declarations/SingleTypeDeclaration.cs +++ b/src/Compilers/CSharp/Portable/Declarations/SingleTypeDeclaration.cs @@ -56,6 +56,8 @@ internal enum TypeDeclarationFlags : ushort HasReturnWithExpression = 1 << 8, IsSimpleProgram = 1 << 9, + + HasRequiredMembers = 1 << 10, } internal SingleTypeDeclaration( @@ -189,6 +191,8 @@ public bool IsSimpleProgram } } + public bool HasRequiredMembers => (_flags & TypeDeclarationFlags.HasRequiredMembers) != 0; + protected override ImmutableArray GetNamespaceOrTypeDeclarationChildren() { return StaticCast.From(_children); diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index 78c6adef4601a..f3dbf964d4240 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -2072,6 +2072,22 @@ internal enum ErrorCode ERR_CannotBeConvertedToUTF8 = 9026, ERR_MisplacedUnchecked = 9027, + ERR_RequiredNameDisallowed = 9029, + ERR_OverrideMustHaveRequired = 9030, + ERR_RequiredMemberCannotBeHidden = 9031, + ERR_RequiredMemberCannotBeLessVisibleThanContainingType = 9032, + ERR_ExplicitRequiredMember = 9033, + ERR_RequiredMemberMustBeSettable = 9034, + ERR_RequiredMemberMustBeSet = 9035, + ERR_RequiredMembersMustBeAssignedValue = 9036, + ERR_RequiredMembersInvalid = 9037, + ERR_RequiredMembersBaseTypeInvalid = 9038, + ERR_ChainingToSetsRequiredMembersRequiresSetsRequiredMembers = 9039, + ERR_NewConstraintCannotHaveRequiredMembers = 9040, + ERR_UnsupportedCompilerFeature = 9041, + WRN_ObsoleteMembersShouldNotBeRequired = 9042, + ERR_RefReturningPropertiesCannotBeRequired = 9043, + #endregion // Note: you will need to re-generate compiler code after adding warnings (eng\generate-compiler-code.cmd) diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs index 5cc54ce5f9b5b..952aa649b0bf6 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs @@ -499,6 +499,7 @@ internal static int GetWarningLevel(ErrorCode code) case ErrorCode.WRN_UseDefViolationThisSupportedVersion: case ErrorCode.WRN_UnassignedThisAutoPropertySupportedVersion: case ErrorCode.WRN_UnassignedThisSupportedVersion: + case ErrorCode.WRN_ObsoleteMembersShouldNotBeRequired: return 1; default: return 0; diff --git a/src/Compilers/CSharp/Portable/Errors/MessageID.cs b/src/Compilers/CSharp/Portable/Errors/MessageID.cs index a4e8a45325abd..ac133c4752460 100644 --- a/src/Compilers/CSharp/Portable/Errors/MessageID.cs +++ b/src/Compilers/CSharp/Portable/Errors/MessageID.cs @@ -254,6 +254,7 @@ internal enum MessageID IDS_FeatureUnsignedRightShift = MessageBase + 12823, IDS_FeatureExtendedNameofScope = MessageBase + 12824, IDS_FeatureRelaxedShiftOperator = MessageBase + 12825, + IDS_FeatureRequiredMembers = MessageBase + 12826, } // Message IDs may refer to strings that need to be localized. @@ -368,6 +369,7 @@ internal static LanguageVersion RequiredVersion(this MessageID feature) case MessageID.IDS_FeatureGenericAttributes: // semantic check case MessageID.IDS_FeatureNewLinesInInterpolations: // semantic check case MessageID.IDS_FeatureListPattern: // semantic check + case MessageID.IDS_FeatureRequiredMembers: // semantic check case MessageID.IDS_FeatureCacheStaticMethodGroupConversion: // lowering check case MessageID.IDS_FeatureSpanCharConstantPattern: case MessageID.IDS_FeatureAutoDefaultStructs: // semantic check diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs index 46dc5f566b6ba..475ae6f10c12f 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs @@ -11,6 +11,7 @@ using System.Linq; using System.Runtime.CompilerServices; using System.Text; +using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.PooledObjects; @@ -235,6 +236,8 @@ private PooledDictionary private readonly bool _hasInitialState; + private readonly MethodSymbol? _baseOrThisInitializer; + #if DEBUG /// /// Contains the expressions that should not be inserted into . @@ -418,6 +421,7 @@ private NullableWalker( Binder binder, Conversions conversions, Variables? variables, + MethodSymbol? baseOrThisInitializer, ArrayBuilder<(BoundReturnStatement, TypeWithAnnotations)>? returnTypesOpt, ImmutableDictionary.Builder? analyzedNullabilityMapOpt, SnapshotManager.Builder? snapshotBuilderOpt, @@ -425,6 +429,7 @@ private NullableWalker( : base(compilation, symbol, node, EmptyStructTypeCache.CreatePrecise(), trackUnassignments: true) { Debug.Assert(!useDelegateInvokeParameterTypes || delegateInvokeMethodOpt is object); + Debug.Assert(baseOrThisInitializer is null or { MethodKind: MethodKind.Constructor }); _variables = variables ?? Variables.Create(symbol); _binder = binder; @@ -438,6 +443,7 @@ private NullableWalker( _snapshotBuilderOpt = snapshotBuilderOpt; _isSpeculative = isSpeculative; _hasInitialState = variables is { }; + _baseOrThisInitializer = baseOrThisInitializer; } public string GetDebuggerDisplay() @@ -669,6 +675,12 @@ void checkMemberStateOnConstructorExit(MethodSymbol constructor, Symbol member, { return; } + + if (symbol.IsRequired() && constructor.ShouldCheckRequiredMembers()) + { + return; + } + var annotations = symbol.GetFlowAnalysisAnnotations(); if ((annotations & FlowAnalysisAnnotations.AllowNull) != 0) { @@ -811,46 +823,43 @@ void makeNotNullMembersMaybeNull() { if (method.IsConstructor()) { - if (needsDefaultInitialStateForMembers()) + foreach (var member in getMembersNeedingDefaultInitialState()) { - foreach (var member in method.ContainingType.GetMembersUnordered()) + if (member.IsStatic != method.IsStatic) { - if (member.IsStatic != method.IsStatic) - { - continue; - } + continue; + } - var memberToInitialize = member; - switch (member) - { - case PropertySymbol: - // skip any manually implemented properties. - continue; - case FieldSymbol { IsConst: true }: + var memberToInitialize = member; + switch (member) + { + case PropertySymbol: + // skip any manually implemented properties. + continue; + case FieldSymbol { IsConst: true }: + continue; + case FieldSymbol { AssociatedSymbol: PropertySymbol prop }: + // this is a property where assigning 'default' causes us to simply update + // the state to the output state of the property + // thus we skip setting an initial state for it here + if (IsPropertyOutputMoreStrictThanInput(prop)) + { continue; - case FieldSymbol { AssociatedSymbol: PropertySymbol prop }: - // this is a property where assigning 'default' causes us to simply update - // the state to the output state of the property - // thus we skip setting an initial state for it here - if (IsPropertyOutputMoreStrictThanInput(prop)) - { - continue; - } + } - // We want to initialize auto-property state to the default state, but not computed properties. - memberToInitialize = prop; - break; - default: - break; - } - var memberSlot = getSlotForFieldOrPropertyOrEvent(memberToInitialize); - if (memberSlot > 0) + // We want to initialize auto-property state to the default state, but not computed properties. + memberToInitialize = prop; + break; + default: + break; + } + var memberSlot = getSlotForFieldOrPropertyOrEvent(memberToInitialize); + if (memberSlot > 0) + { + var type = memberToInitialize.GetTypeOrReturnType(); + if (!type.NullableAnnotation.IsOblivious()) { - var type = memberToInitialize.GetTypeOrReturnType(); - if (!type.NullableAnnotation.IsOblivious()) - { - this.State[memberSlot] = type.Type.IsPossiblyNullableReferenceTypeTypeParameter() ? NullableFlowState.MaybeDefault : NullableFlowState.MaybeNull; - } + this.State[memberSlot] = type.Type.IsPossiblyNullableReferenceTypeTypeParameter() ? NullableFlowState.MaybeDefault : NullableFlowState.MaybeNull; } } } @@ -868,24 +877,101 @@ void makeNotNullMembersMaybeNull() } } - bool needsDefaultInitialStateForMembers() + return; + + ImmutableArray getMembersNeedingDefaultInitialState() { if (_hasInitialState) { - return false; + return ImmutableArray.Empty; + } + + bool includeCurrentTypeRequiredMembers = true; + bool includeBaseRequiredMembers = true; + bool hasThisConstructorInitializer = false; + + if (method is SourceMemberMethodSymbol { SyntaxNode: ConstructorDeclarationSyntax { Initializer: { RawKind: var initializerKind } } }) + { + // We have multiple ways of entering the nullable walker: we could be just analyzing the initializers, with a BoundStatementList body and _baseOrThisInitializer + // having been provided, or we could be analyzing the body of a constructor, with a BoundConstructorBody body and _baseOrThisInitializer being null. + var baseOrThisInitializer = (_baseOrThisInitializer ?? GetConstructorThisOrBaseSymbol(this.methodMainNode)); + // If there's an error in the base or this initializer, presume that we should set all required members to default. + includeBaseRequiredMembers = baseOrThisInitializer?.ShouldCheckRequiredMembers() ?? true; + if (initializerKind == (int)SyntaxKind.ThisConstructorInitializer) + { + hasThisConstructorInitializer = true; + // If we chained to a `this` constructor, a SetsRequiredMembers attribute applies to both the current type's required members and the base type's required members. + includeCurrentTypeRequiredMembers = includeBaseRequiredMembers; + } + else if (initializerKind == (int)SyntaxKind.BaseConstructorInitializer) + { + // If we chained to a `base` constructor, a SetsRequiredMembers attribute applies to the base type's required members only, and the current type's required members + // are not assumed to be initialized. + includeCurrentTypeRequiredMembers = true; + } } // Pre-C# 11, we don't use a default initial state for value type instance constructors without `: this()` // because any usages of uninitialized fields will get definite assignment errors anyway. - if (!method.HasThisConstructorInitializer(out _) + if (!hasThisConstructorInitializer && (!method.ContainingType.IsValueType || method.IsStatic || compilation.IsFeatureEnabled(MessageID.IDS_FeatureAutoDefaultStructs))) { - return true; + return membersToBeInitialized(method.ContainingType, includeAllMembers: true, includeCurrentTypeRequiredMembers, includeBaseRequiredMembers); } - return method.IncludeFieldInitializersInBody(); + // We want to presume all required members of the type are uninitialized, and in addition we want to set all fields to + // default if we can get to this constructor by doing so (ie, : this() in a value type). + return membersToBeInitialized(method.ContainingType, includeAllMembers: method.IncludeFieldInitializersInBody(), includeCurrentTypeRequiredMembers, includeBaseRequiredMembers); + + static ImmutableArray membersToBeInitialized(NamedTypeSymbol containingType, bool includeAllMembers, bool includeCurrentTypeRequiredMembers, bool includeBaseRequiredMembers) + { + return (includeAllMembers, includeCurrentTypeRequiredMembers, includeBaseRequiredMembers) switch + { + (includeAllMembers: false, includeCurrentTypeRequiredMembers: false, includeBaseRequiredMembers: false) + => ImmutableArray.Empty, + + (includeAllMembers: false, includeCurrentTypeRequiredMembers: true, includeBaseRequiredMembers: false) + => containingType.GetMembersUnordered().SelectAsArray(predicate: SymbolExtensions.IsRequired, selector: getFieldSymbolToBeInitialized), + + (includeAllMembers: false, includeCurrentTypeRequiredMembers: true, includeBaseRequiredMembers: true) + => containingType.AllRequiredMembers.SelectAsArray(static kvp => getFieldSymbolToBeInitialized(kvp.Value)), + + (includeAllMembers: true, includeCurrentTypeRequiredMembers: _, includeBaseRequiredMembers: false) + => containingType.GetMembersUnordered().SelectAsArray(getFieldSymbolToBeInitialized), + + (includeAllMembers: true, includeCurrentTypeRequiredMembers: true, includeBaseRequiredMembers: true) + => getAllTypeAndRequiredMembers(containingType), + + (includeAllMembers: _, includeCurrentTypeRequiredMembers: false, includeBaseRequiredMembers: true) + => throw ExceptionUtilities.Unreachable, + }; + + static ImmutableArray getAllTypeAndRequiredMembers(TypeSymbol containingType) + { + var members = containingType.GetMembersUnordered(); + var requiredMembers = containingType.BaseTypeNoUseSiteDiagnostics?.AllRequiredMembers ?? ImmutableSegmentedDictionary.Empty; + + if (requiredMembers.IsEmpty) + { + return members; + } + + var builder = ArrayBuilder.GetInstance(members.Length + requiredMembers.Count); + builder.AddRange(members); + foreach (var (_, requiredMember) in requiredMembers) + { + // We want to assume that all required members were _not_ set by the chained constructor + builder.Add(getFieldSymbolToBeInitialized(requiredMember)); + } + + return builder.ToImmutableAndFree(); + } + + static Symbol getFieldSymbolToBeInitialized(Symbol requiredMember) + => requiredMember is SourcePropertySymbol { IsAutoPropertyWithGetAccessor: true } prop ? prop.BackingField : requiredMember; + } } } @@ -1128,6 +1214,7 @@ internal static void AnalyzeIfNeeded( bool useConstructorExitWarnings, VariableState? initialNullableState, bool getFinalNullableState, + MethodSymbol? baseOrThisInitializer, out VariableState? finalNullableState) { if (!HasRequiredLanguageVersion(compilation) || !compilation.IsNullableAnalysisEnabledIn(method)) @@ -1137,13 +1224,13 @@ internal static void AnalyzeIfNeeded( // Once we address https://github.com/dotnet/roslyn/issues/46579 we should also always pass `getFinalNullableState: true` in debug mode. // We will likely always need to write a 'null' out for the out parameter in this code path, though, because // we don't want to introduce behavior differences between debug and release builds - Analyze(compilation, method, node, new DiagnosticBag(), useConstructorExitWarnings: false, initialNullableState: null, getFinalNullableState: false, out _, requiresAnalysis: false); + Analyze(compilation, method, node, new DiagnosticBag(), useConstructorExitWarnings: false, initialNullableState: null, getFinalNullableState: false, baseOrThisInitializer, out _, requiresAnalysis: false); } finalNullableState = null; return; } - Analyze(compilation, method, node, diagnostics, useConstructorExitWarnings, initialNullableState, getFinalNullableState, out finalNullableState); + Analyze(compilation, method, node, diagnostics, useConstructorExitWarnings, initialNullableState, getFinalNullableState, baseOrThisInitializer, out finalNullableState); } private static void Analyze( @@ -1154,6 +1241,7 @@ private static void Analyze( bool useConstructorExitWarnings, VariableState? initialNullableState, bool getFinalNullableState, + MethodSymbol? baseOrThisInitializer, out VariableState? finalNullableState, bool requiresAnalysis = true) { @@ -1178,6 +1266,7 @@ private static void Analyze( useDelegateInvokeReturnType: false, delegateInvokeMethodOpt: null, initialState: initialNullableState, + baseOrThisInitializer, analyzedNullabilityMapOpt: null, snapshotBuilderOpt: null, returnTypesOpt: null, @@ -1186,36 +1275,67 @@ private static void Analyze( requiresAnalysis); } - /// - /// Gets the "after initializers state" which should be used at the beginning of nullable analysis - /// of certain constructors. Only used for semantic model and debug verification. - /// - internal static VariableState? GetAfterInitializersState(CSharpCompilation compilation, Symbol? symbol) + internal static VariableState? GetAfterInitializersState(CSharpCompilation compilation, Symbol? symbol, BoundNode constructorBody) { if (symbol is MethodSymbol method && method.IncludeFieldInitializersInBody() && method.ContainingType is SourceMemberContainerTypeSymbol containingType) { - var unusedDiagnostics = DiagnosticBag.GetInstance(); + Binder.ProcessedFieldInitializers discardedInitializers = default; + Binder.BindFieldInitializers(compilation, null, method.IsStatic ? containingType.StaticInitializers : containingType.InstanceInitializers, BindingDiagnosticBag.Discarded, ref discardedInitializers); + return GetAfterInitializersState(compilation, method, InitializerRewriter.RewriteConstructor(discardedInitializers.BoundInitializers, method), constructorBody, diagnostics: BindingDiagnosticBag.Discarded); + } + + return null; + } + + /// + /// Gets the "after initializers state" which should be used at the beginning of nullable analysis + /// of certain constructors. + /// + internal static VariableState? GetAfterInitializersState(CSharpCompilation compilation, MethodSymbol method, BoundNode nodeToAnalyze, BoundNode? constructorBody, BindingDiagnosticBag diagnostics) + { + Debug.Assert(method.IsConstructor()); + bool ownsDiagnostics; + DiagnosticBag diagnosticsBag; + if (diagnostics.DiagnosticBag == null) + { + diagnostics = BindingDiagnosticBag.Discarded; + diagnosticsBag = DiagnosticBag.GetInstance(); + ownsDiagnostics = true; + } + else + { + diagnosticsBag = diagnostics.DiagnosticBag; + ownsDiagnostics = false; + } - Binder.ProcessedFieldInitializers initializers = default; - Binder.BindFieldInitializers(compilation, null, method.IsStatic ? containingType.StaticInitializers : containingType.InstanceInitializers, BindingDiagnosticBag.Discarded, ref initializers); - NullableWalker.AnalyzeIfNeeded( - compilation, - method, - InitializerRewriter.RewriteConstructor(initializers.BoundInitializers, method), - unusedDiagnostics, - useConstructorExitWarnings: false, - initialNullableState: null, - getFinalNullableState: true, - out var afterInitializersState); + MethodSymbol? baseOrThisInitializer = GetConstructorThisOrBaseSymbol(constructorBody); - unusedDiagnostics.Free(); + NullableWalker.AnalyzeIfNeeded( + compilation, + method, + nodeToAnalyze, + diagnosticsBag, + useConstructorExitWarnings: false, + initialNullableState: null, + getFinalNullableState: true, + baseOrThisInitializer, + out var afterInitializersState); - return afterInitializersState; + if (ownsDiagnostics) + { + diagnosticsBag.Free(); } - return null; + return afterInitializersState; + } + + private static MethodSymbol? GetConstructorThisOrBaseSymbol(BoundNode? constructorBody) + { + return constructorBody is BoundConstructorMethodBody { Initializer: BoundExpressionStatement { Expression: BoundCall { Method: { MethodKind: MethodKind.Constructor } initializerMethod } } } + ? initializerMethod + : null; } /// @@ -1231,7 +1351,7 @@ internal static void AnalyzeWithoutRewrite( DiagnosticBag diagnostics, bool createSnapshots) { - _ = AnalyzeWithSemanticInfo(compilation, symbol, node, binder, initialState: GetAfterInitializersState(compilation, symbol), diagnostics, createSnapshots, requiresAnalysis: false); + _ = AnalyzeWithSemanticInfo(compilation, symbol, node, binder, initialState: GetAfterInitializersState(compilation, symbol, node), diagnostics, createSnapshots, requiresAnalysis: false); } /// @@ -1282,6 +1402,7 @@ private static (SnapshotManager?, ImmutableDictionary.Builder? analyzedNullabilityMapOpt, SnapshotManager.Builder? snapshotBuilderOpt, ArrayBuilder<(BoundReturnStatement, TypeWithAnnotations)>? returnTypesOpt, @@ -1495,6 +1620,7 @@ private static void Analyze( binder, conversions, initialState is null ? null : Variables.Create(initialState.Variables), + baseOrThisInitializer, returnTypesOpt, analyzedNullabilityMapOpt, snapshotBuilderOpt); @@ -4040,6 +4166,7 @@ internal static TypeWithAnnotations BestTypeForLambdaReturns( binder, conversions: conversions, variables: null, + baseOrThisInitializer: null, returnTypesOpt: null, analyzedNullabilityMapOpt: null, snapshotBuilderOpt: null); diff --git a/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4 b/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4 index 5f38144661b96..341813ef6e3ca 100644 --- a/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4 +++ b/src/Compilers/CSharp/Portable/Generated/CSharp.Generated.g4 @@ -109,6 +109,7 @@ modifier | 'public' | 'readonly' | 'ref' + | 'required' | 'sealed' | 'static' | 'unsafe' diff --git a/src/Compilers/CSharp/Portable/Generated/ErrorFacts.Generated.cs b/src/Compilers/CSharp/Portable/Generated/ErrorFacts.Generated.cs index 0186b7f67e09c..f1c7d74365494 100644 --- a/src/Compilers/CSharp/Portable/Generated/ErrorFacts.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/ErrorFacts.Generated.cs @@ -287,6 +287,7 @@ public static bool IsWarning(ErrorCode code) case ErrorCode.WRN_UseDefViolationThisSupportedVersion: case ErrorCode.WRN_UnassignedThisAutoPropertySupportedVersion: case ErrorCode.WRN_UnassignedThisSupportedVersion: + case ErrorCode.WRN_ObsoleteMembersShouldNotBeRequired: return true; default: return false; diff --git a/src/Compilers/CSharp/Portable/Lowering/IteratorRewriter/IteratorFinallyMethodSymbol.cs b/src/Compilers/CSharp/Portable/Lowering/IteratorRewriter/IteratorFinallyMethodSymbol.cs index 1240b4c79e1c7..93d78aeb2f272 100644 --- a/src/Compilers/CSharp/Portable/Lowering/IteratorRewriter/IteratorFinallyMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Lowering/IteratorRewriter/IteratorFinallyMethodSymbol.cs @@ -255,5 +255,7 @@ internal override int CalculateLocalSyntaxOffset(int localPosition, SyntaxTree l { return _stateMachineType.KickoffMethod.CalculateLocalSyntaxOffset(localPosition, localTree); } + + protected sealed override bool HasSetsRequiredMembersImpl => throw ExceptionUtilities.Unreachable; } } diff --git a/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/SynthesizedStateMachineProperty.cs b/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/SynthesizedStateMachineProperty.cs index de2abd9ed0871..8ca68abb3e257 100644 --- a/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/SynthesizedStateMachineProperty.cs +++ b/src/Compilers/CSharp/Portable/Lowering/StateMachineRewriter/SynthesizedStateMachineProperty.cs @@ -151,6 +151,8 @@ public override bool IsExtern get { return false; } } + internal override bool IsRequired => false; + internal override ObsoleteAttributeData ObsoleteAttributeData { get { return null; } diff --git a/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs b/src/Compilers/CSharp/Portable/Parser/LanguageParser.cs index cbf5857fb5726..e5b791ebe2763 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.RequiredKeyword: + return DeclarationModifiers.Required; } goto default; @@ -1171,8 +1173,9 @@ internal static DeclarationModifiers GetModifier(SyntaxKind kind, SyntaxKind con } } - private void ParseModifiers(SyntaxListBuilder tokens, bool forAccessors) + private void ParseModifiers(SyntaxListBuilder tokens, bool forAccessors, bool forTopLevelStatements) { + Debug.Assert(!(forAccessors && forTopLevelStatements)); while (true) { var newMod = GetModifier(this.CurrentToken); @@ -1244,7 +1247,7 @@ private void ParseModifiers(SyntaxListBuilder tokens, bool forAccessors) } case DeclarationModifiers.Async: - if (!ShouldAsyncBeTreatedAsModifier(parsingStatementNotDeclaration: false)) + if (!ShouldAsyncOrRequiredBeTreatedAsModifier(parsingStatementNotDeclaration: false)) { return; } @@ -1253,6 +1256,20 @@ private void ParseModifiers(SyntaxListBuilder tokens, bool forAccessors) modTok = CheckFeatureAvailability(modTok, MessageID.IDS_FeatureAsync); break; + case DeclarationModifiers.Required: + // In C# 11, required in a modifier position is always a keyword if not escaped. Otherwise, we reuse the async detection + // machinery to make a conservative guess as to whether the user meant required to be a keyword, so that they get a good langver + // diagnostic and all the machinery to upgrade their project kicks in. The only exception to this rule is top level statements, + // where the user could conceivably have a local named required. For these locations, we need to disambiguate as well. + if ((!IsFeatureEnabled(MessageID.IDS_FeatureRequiredMembers) || forTopLevelStatements) && !ShouldAsyncOrRequiredBeTreatedAsModifier(parsingStatementNotDeclaration: false)) + { + return; + } + + modTok = ConvertToKeyword(this.EatToken()); + + break; + default: modTok = this.EatToken(); break; @@ -1281,16 +1298,16 @@ bool isStructOrRecordKeyword(SyntaxToken token) } } - private bool ShouldAsyncBeTreatedAsModifier(bool parsingStatementNotDeclaration) + private bool ShouldAsyncOrRequiredBeTreatedAsModifier(bool parsingStatementNotDeclaration) { - Debug.Assert(this.CurrentToken.ContextualKind == SyntaxKind.AsyncKeyword); + Debug.Assert(this.CurrentToken.ContextualKind is SyntaxKind.AsyncKeyword or SyntaxKind.RequiredKeyword); // 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 the async or required keyword return true; } @@ -1301,7 +1318,7 @@ private bool ShouldAsyncBeTreatedAsModifier(bool parsingStatementNotDeclaration) try { - this.EatToken(); //move past contextual 'async' + this.EatToken(); //move past contextual 'async' or 'required' if (!parsingStatementNotDeclaration && (this.CurrentToken.ContextualKind == SyntaxKind.PartialKeyword)) @@ -1318,6 +1335,8 @@ private bool ShouldAsyncBeTreatedAsModifier(bool parsingStatementNotDeclaration) // ... 'async' [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 + // The comments in general were not updated to add "async or required" everywhere to preserve + // history, but generally wherever async occurs, it can also be required. if (!parsingStatementNotDeclaration) { @@ -2356,7 +2375,7 @@ private MemberDeclarationSyntax ParseMemberDeclarationOrStatementCore(SyntaxKind } // All modifiers that might start an expression are processed above. - this.ParseModifiers(modifiers, forAccessors: false); + this.ParseModifiers(modifiers, forAccessors: false, forTopLevelStatements: true); bool haveModifiers = (modifiers.Count > 0); MemberDeclarationSyntax result; @@ -2663,6 +2682,7 @@ private bool IsMisplacedModifier(SyntaxListBuilder modifiers, SyntaxList Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.InterpolatedSingleLineRawStringStartToken = 9072 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.MultiLineRawStringLiteralToken = 8519 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind +Microsoft.CodeAnalysis.CSharp.SyntaxKind.RequiredKeyword = 8447 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind Microsoft.CodeAnalysis.CSharp.SyntaxKind.SingleLineRawStringLiteralToken = 8518 -> Microsoft.CodeAnalysis.CSharp.SyntaxKind static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ConstructorDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken identifier, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.ConstructorInitializerSyntax? initializer, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax! body) -> Microsoft.CodeAnalysis.CSharp.Syntax.ConstructorDeclarationSyntax! *REMOVED*static Microsoft.CodeAnalysis.CSharp.SyntaxFactory.ConstructorDeclaration(Microsoft.CodeAnalysis.SyntaxList attributeLists, Microsoft.CodeAnalysis.SyntaxTokenList modifiers, Microsoft.CodeAnalysis.SyntaxToken identifier, Microsoft.CodeAnalysis.CSharp.Syntax.ParameterListSyntax! parameterList, Microsoft.CodeAnalysis.CSharp.Syntax.ConstructorInitializerSyntax! initializer, Microsoft.CodeAnalysis.CSharp.Syntax.BlockSyntax! body) -> Microsoft.CodeAnalysis.CSharp.Syntax.ConstructorDeclarationSyntax! diff --git a/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Members.cs b/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Members.cs index d3939bc460f9a..196a02819a2d6 100644 --- a/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Members.cs +++ b/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Members.cs @@ -27,9 +27,9 @@ private void VisitFieldType(IFieldSymbol symbol) public override void VisitField(IFieldSymbol symbol) { - AddAccessibilityIfRequired(symbol); - AddMemberModifiersIfRequired(symbol); - AddFieldModifiersIfRequired(symbol); + AddAccessibilityIfNeeded(symbol); + AddMemberModifiersIfNeeded(symbol); + AddFieldModifiersIfNeeded(symbol); if (format.MemberOptions.IncludesOption(SymbolDisplayMemberOptions.IncludeType) && this.isFirstSymbolVisited && @@ -38,7 +38,7 @@ public override void VisitField(IFieldSymbol symbol) VisitFieldType(symbol); AddSpace(); - AddCustomModifiersIfRequired(symbol.CustomModifiers); + AddCustomModifiersIfNeeded(symbol.CustomModifiers); } if (format.MemberOptions.IncludesOption(SymbolDisplayMemberOptions.IncludeContainingType) && @@ -122,31 +122,31 @@ private static bool ShouldMethodDisplayReadOnly(IMethodSymbol method, IPropertyS public override void VisitProperty(IPropertySymbol symbol) { - AddAccessibilityIfRequired(symbol); - AddMemberModifiersIfRequired(symbol); + AddAccessibilityIfNeeded(symbol); + AddMemberModifiersIfNeeded(symbol); if (ShouldPropertyDisplayReadOnly(symbol)) { - AddReadOnlyIfRequired(); + AddReadOnlyIfNeeded(); } if (format.MemberOptions.IncludesOption(SymbolDisplayMemberOptions.IncludeType)) { if (symbol.ReturnsByRef) { - AddRefIfRequired(); + AddRefIfNeeded(); } else if (symbol.ReturnsByRefReadonly) { - AddRefReadonlyIfRequired(); + AddRefReadonlyIfNeeded(); } - AddCustomModifiersIfRequired(symbol.RefCustomModifiers); + AddCustomModifiersIfNeeded(symbol.RefCustomModifiers); symbol.Type.Accept(this.NotFirstVisitor); AddSpace(); - AddCustomModifiersIfRequired(symbol.TypeCustomModifiers); + AddCustomModifiersIfNeeded(symbol.TypeCustomModifiers); } if (format.MemberOptions.IncludesOption(SymbolDisplayMemberOptions.IncludeContainingType) && @@ -183,7 +183,7 @@ private void AddPropertyNameAndParameters(IPropertySymbol symbol) if (getMemberNameWithoutInterfaceName) { - AddExplicitInterfaceIfRequired(symbol.ExplicitInterfaceImplementations); + AddExplicitInterfaceIfNeeded(symbol.ExplicitInterfaceImplementations); } if (symbol.IsIndexer) @@ -203,20 +203,20 @@ private void AddPropertyNameAndParameters(IPropertySymbol symbol) if (this.format.MemberOptions.IncludesOption(SymbolDisplayMemberOptions.IncludeParameters) && symbol.Parameters.Any()) { AddPunctuation(SyntaxKind.OpenBracketToken); - AddParametersIfRequired(hasThisParameter: false, isVarargs: false, parameters: symbol.Parameters); + AddParametersIfNeeded(hasThisParameter: false, isVarargs: false, parameters: symbol.Parameters); AddPunctuation(SyntaxKind.CloseBracketToken); } } public override void VisitEvent(IEventSymbol symbol) { - AddAccessibilityIfRequired(symbol); - AddMemberModifiersIfRequired(symbol); + AddAccessibilityIfNeeded(symbol); + AddMemberModifiersIfNeeded(symbol); var accessor = symbol.AddMethod ?? symbol.RemoveMethod; if (accessor is object && ShouldMethodDisplayReadOnly(accessor)) { - AddReadOnlyIfRequired(); + AddReadOnlyIfNeeded(); } if (format.KindOptions.IncludesOption(SymbolDisplayKindOptions.IncludeMemberKeyword)) @@ -245,7 +245,7 @@ private void AddEventName(IEventSymbol symbol) { if (symbol.Name.LastIndexOf('.') > 0) { - AddExplicitInterfaceIfRequired(symbol.ExplicitInterfaceImplementations); + AddExplicitInterfaceIfNeeded(symbol.ExplicitInterfaceImplementations); this.builder.Add(CreatePart(SymbolDisplayPartKind.EventName, symbol, ExplicitInterfaceHelpers.GetMemberNameWithoutInterfaceName(symbol.Name))); @@ -300,12 +300,12 @@ public override void VisitMethod(IMethodSymbol symbol) if ((object)symbol.ContainingType != null || (symbol.ContainingSymbol is ITypeSymbol)) { - AddAccessibilityIfRequired(symbol); - AddMemberModifiersIfRequired(symbol); + AddAccessibilityIfNeeded(symbol); + AddMemberModifiersIfNeeded(symbol); if (ShouldMethodDisplayReadOnly(symbol)) { - AddReadOnlyIfRequired(); + AddReadOnlyIfNeeded(); } if (format.MemberOptions.IncludesOption(SymbolDisplayMemberOptions.IncludeType)) @@ -333,14 +333,14 @@ public override void VisitMethod(IMethodSymbol symbol) if (symbol.ReturnsByRef) { - AddRefIfRequired(); + AddRefIfNeeded(); } else if (symbol.ReturnsByRefReadonly) { - AddRefReadonlyIfRequired(); + AddRefReadonlyIfNeeded(); } - AddCustomModifiersIfRequired(symbol.RefCustomModifiers); + AddCustomModifiersIfNeeded(symbol.RefCustomModifiers); if (symbol.ReturnsVoid) { @@ -352,7 +352,7 @@ public override void VisitMethod(IMethodSymbol symbol) } AddSpace(); - AddCustomModifiersIfRequired(symbol.ReturnTypeCustomModifiers); + AddCustomModifiersIfNeeded(symbol.ReturnTypeCustomModifiers); break; } } @@ -476,7 +476,7 @@ public override void VisitMethod(IMethodSymbol symbol) } case MethodKind.ExplicitInterfaceImplementation: { - AddExplicitInterfaceIfRequired(symbol.ExplicitInterfaceImplementations); + AddExplicitInterfaceIfNeeded(symbol.ExplicitInterfaceImplementations); if (!format.CompilerInternalOptions.IncludesOption(SymbolDisplayCompilerInternalOptions.UseMetadataMethodNames) && symbol.GetSymbol()?.OriginalDefinition is SourceUserDefinedOperatorSymbolBase sourceUserDefinedOperatorSymbolBase) @@ -601,11 +601,11 @@ void visitFunctionPointerSignature(IMethodSymbol symbol) { AddParameterRefKind(param.RefKind); - AddCustomModifiersIfRequired(param.RefCustomModifiers); + AddCustomModifiersIfNeeded(param.RefCustomModifiers); param.Type.Accept(this.NotFirstVisitor); - AddCustomModifiersIfRequired(param.CustomModifiers, leadingSpace: true, trailingSpace: false); + AddCustomModifiersIfNeeded(param.CustomModifiers, leadingSpace: true, trailingSpace: false); AddPunctuation(SyntaxKind.CommaToken); AddSpace(); @@ -620,11 +620,11 @@ void visitFunctionPointerSignature(IMethodSymbol symbol) AddRefReadonly(); } - AddCustomModifiersIfRequired(symbol.RefCustomModifiers); + AddCustomModifiersIfNeeded(symbol.RefCustomModifiers); symbol.ReturnType.Accept(this.NotFirstVisitor); - AddCustomModifiersIfRequired(symbol.ReturnTypeCustomModifiers, leadingSpace: true, trailingSpace: false); + AddCustomModifiersIfNeeded(symbol.ReturnTypeCustomModifiers, leadingSpace: true, trailingSpace: false); AddPunctuation(SyntaxKind.GreaterThanToken); } @@ -723,7 +723,7 @@ private void AddParameters(IMethodSymbol symbol) if (format.MemberOptions.IncludesOption(SymbolDisplayMemberOptions.IncludeParameters)) { AddPunctuation(SyntaxKind.OpenParenToken); - AddParametersIfRequired( + AddParametersIfNeeded( hasThisParameter: symbol.IsExtensionMethod && symbol.MethodKind != MethodKind.ReducedExtension, isVarargs: symbol.IsVararg, parameters: symbol.Parameters); @@ -755,8 +755,8 @@ public override void VisitParameter(IParameterSymbol symbol) if (includeType) { - AddParameterRefKindIfRequired(symbol.RefKind); - AddCustomModifiersIfRequired(symbol.RefCustomModifiers, leadingSpace: false, trailingSpace: true); + AddParameterRefKindIfNeeded(symbol.RefKind); + AddCustomModifiersIfNeeded(symbol.RefCustomModifiers, leadingSpace: false, trailingSpace: true); if (symbol.IsParams && format.ParameterOptions.IncludesOption(SymbolDisplayParameterOptions.IncludeParamsRefOut)) { @@ -765,7 +765,7 @@ public override void VisitParameter(IParameterSymbol symbol) } symbol.Type.Accept(this.NotFirstVisitor); - AddCustomModifiersIfRequired(symbol.CustomModifiers, leadingSpace: true, trailingSpace: false); + AddCustomModifiersIfNeeded(symbol.CustomModifiers, leadingSpace: true, trailingSpace: false); } if (includeName) @@ -811,7 +811,7 @@ private static bool CanAddConstant(ITypeSymbol type, object value) return value.GetType().GetTypeInfo().IsPrimitive || value is string || value is decimal; } - private void AddFieldModifiersIfRequired(IFieldSymbol symbol) + private void AddFieldModifiersIfNeeded(IFieldSymbol symbol) { if (format.MemberOptions.IncludesOption(SymbolDisplayMemberOptions.IncludeModifiers) && !IsEnumMember(symbol)) @@ -838,7 +838,7 @@ private void AddFieldModifiersIfRequired(IFieldSymbol symbol) } } - private void AddMemberModifiersIfRequired(ISymbol symbol) + private void AddMemberModifiersIfNeeded(ISymbol symbol) { INamedTypeSymbol containingType = symbol.ContainingType; @@ -850,6 +850,7 @@ private void AddMemberModifiersIfRequired(ISymbol symbol) (containingType.TypeKind != TypeKind.Interface && !IsEnumMember(symbol) && !IsLocalFunction(symbol)))) { var isConst = symbol is IFieldSymbol && ((IFieldSymbol)symbol).IsConst; + var isRequired = symbol is IFieldSymbol { IsRequired: true } or IPropertySymbol { IsRequired: true }; if (symbol.IsStatic && !isConst) { AddKeyword(SyntaxKind.StaticKeyword); @@ -885,10 +886,16 @@ private void AddMemberModifiersIfRequired(ISymbol symbol) AddKeyword(SyntaxKind.VirtualKeyword); AddSpace(); } + + if (isRequired) + { + AddKeyword(SyntaxKind.RequiredKeyword); + AddSpace(); + } } } - private void AddParametersIfRequired(bool hasThisParameter, bool isVarargs, ImmutableArray parameters) + private void AddParametersIfNeeded(bool hasThisParameter, bool isVarargs, ImmutableArray parameters) { if (format.ParameterOptions == SymbolDisplayParameterOptions.None) { @@ -948,7 +955,7 @@ private void AddAccessor(IPropertySymbol property, IMethodSymbol method, SyntaxK if (!ShouldPropertyDisplayReadOnly(property) && ShouldMethodDisplayReadOnly(method, property)) { - AddReadOnlyIfRequired(); + AddReadOnlyIfNeeded(); } AddKeyword(keyword); @@ -956,7 +963,7 @@ private void AddAccessor(IPropertySymbol property, IMethodSymbol method, SyntaxK } } - private void AddExplicitInterfaceIfRequired(ImmutableArray implementedMembers) where T : ISymbol + private void AddExplicitInterfaceIfNeeded(ImmutableArray implementedMembers) where T : ISymbol { if (format.MemberOptions.IncludesOption(SymbolDisplayMemberOptions.IncludeExplicitInterface) && !implementedMembers.IsEmpty) { @@ -972,7 +979,7 @@ private void AddExplicitInterfaceIfRequired(ImmutableArray implementedMemb } } - private void AddCustomModifiersIfRequired(ImmutableArray customModifiers, bool leadingSpace = false, bool trailingSpace = true) + private void AddCustomModifiersIfNeeded(ImmutableArray customModifiers, bool leadingSpace = false, bool trailingSpace = true) { if (this.format.CompilerInternalOptions.IncludesOption(SymbolDisplayCompilerInternalOptions.IncludeCustomModifiers) && !customModifiers.IsEmpty) { @@ -997,7 +1004,7 @@ private void AddCustomModifiersIfRequired(ImmutableArray customM } } - private void AddRefIfRequired() + private void AddRefIfNeeded() { if (format.MemberOptions.IncludesOption(SymbolDisplayMemberOptions.IncludeRef)) { @@ -1011,7 +1018,7 @@ private void AddRef() AddSpace(); } - private void AddRefReadonlyIfRequired() + private void AddRefReadonlyIfNeeded() { if (format.MemberOptions.IncludesOption(SymbolDisplayMemberOptions.IncludeRef)) { @@ -1027,7 +1034,7 @@ private void AddRefReadonly() AddSpace(); } - private void AddReadOnlyIfRequired() + private void AddReadOnlyIfNeeded() { // 'readonly' in this context is effectively a 'ref' modifier // because it affects whether the 'this' parameter is 'ref' or 'in'. @@ -1038,7 +1045,7 @@ private void AddReadOnlyIfRequired() } } - private void AddParameterRefKindIfRequired(RefKind refKind) + private void AddParameterRefKindIfNeeded(RefKind refKind) { if (format.ParameterOptions.IncludesOption(SymbolDisplayParameterOptions.IncludeParamsRefOut)) { diff --git a/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Types.cs b/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Types.cs index a216deaffc65d..6e7532e5ad779 100644 --- a/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Types.cs +++ b/src/Compilers/CSharp/Portable/SymbolDisplay/SymbolDisplayVisitor.Types.cs @@ -61,7 +61,7 @@ private void VisitArrayTypeWithoutNullability(IArrayTypeSymbol symbol) { if (!this.isFirstSymbolVisited) { - AddCustomModifiersIfRequired(arrayType.CustomModifiers, leadingSpace: true); + AddCustomModifiersIfNeeded(arrayType.CustomModifiers, leadingSpace: true); } AddArrayRank(arrayType); @@ -145,7 +145,7 @@ public override void VisitPointerType(IPointerTypeSymbol symbol) if (!this.isFirstSymbolVisited) { - AddCustomModifiersIfRequired(symbol.CustomModifiers, leadingSpace: true); + AddCustomModifiersIfNeeded(symbol.CustomModifiers, leadingSpace: true); } AddPunctuation(SyntaxKind.AsteriskToken); } @@ -159,7 +159,7 @@ public override void VisitTypeParameter(ITypeParameterSymbol symbol) { if (this.isFirstSymbolVisited) { - AddTypeParameterVarianceIfRequired(symbol); + AddTypeParameterVarianceIfNeeded(symbol); } //variance and constraints are handled by methods and named types @@ -208,7 +208,7 @@ private void VisitNamedTypeWithoutNullability(INamedTypeSymbol symbol) if (typeArg.TypeKind != TypeKind.Pointer) { typeArg.Accept(this.NotFirstVisitor); - AddCustomModifiersIfRequired(symbol.GetTypeArgumentCustomModifiers(0), leadingSpace: true, trailingSpace: false); + AddCustomModifiersIfNeeded(symbol.GetTypeArgumentCustomModifiers(0), leadingSpace: true, trailingSpace: false); AddPunctuation(SyntaxKind.QuestionToken); @@ -233,11 +233,11 @@ private void VisitNamedTypeWithoutNullability(INamedTypeSymbol symbol) var invokeMethod = symbol.DelegateInvokeMethod; if (invokeMethod.ReturnsByRef) { - AddRefIfRequired(); + AddRefIfNeeded(); } else if (invokeMethod.ReturnsByRefReadonly) { - AddRefReadonlyIfRequired(); + AddRefReadonlyIfNeeded(); } if (invokeMethod.ReturnsVoid) @@ -426,7 +426,7 @@ private void AddDelegateParameters(INamedTypeSymbol symbol) { var method = symbol.DelegateInvokeMethod; AddPunctuation(SyntaxKind.OpenParenToken); - AddParametersIfRequired(hasThisParameter: false, isVarargs: method.IsVararg, parameters: method.Parameters); + AddParametersIfNeeded(hasThisParameter: false, isVarargs: method.IsVararg, parameters: method.Parameters); AddPunctuation(SyntaxKind.CloseParenToken); } } @@ -731,7 +731,7 @@ private void AddTypeKind(INamedTypeSymbol symbol) } } - private void AddTypeParameterVarianceIfRequired(ITypeParameterSymbol symbol) + private void AddTypeParameterVarianceIfNeeded(ITypeParameterSymbol symbol) { if (format.GenericsOptions.IncludesOption(SymbolDisplayGenericsOptions.IncludeVariance)) { @@ -785,7 +785,7 @@ private void AddTypeArguments(ISymbol owner, ImmutableArray false; + public sealed override ImmutableArray GetTypeMembers() { return ImmutableArray.Empty; diff --git a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.DelegateTemplateSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.DelegateTemplateSymbol.cs index 1c2afa6b1e8a7..66b9a61e63a21 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.DelegateTemplateSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.DelegateTemplateSymbol.cs @@ -159,6 +159,8 @@ static SynthesizedDelegateInvokeMethod createInvokeMethod( public override IEnumerable MemberNames => GetMembers().SelectAsArray(member => member.Name); + internal override bool HasDeclaredRequiredMembers => false; + public override ImmutableArray GetMembers() => _members; public override ImmutableArray GetMembers(string name) => GetMembers().WhereAsArray((member, name) => member.Name == name, name); diff --git a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.FieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.FieldSymbol.cs index 10010ac113676..da38096f344db 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.FieldSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.FieldSymbol.cs @@ -150,6 +150,8 @@ internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, r ImmutableArray.Create( new TypedConstant(manager.System_Diagnostics_DebuggerBrowsableState, TypedConstantKind.Enum, DebuggerBrowsableState.Never)))); } + + internal override bool IsRequired => false; } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.PropertySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.PropertySymbol.cs index d55c65c360a9f..5d5630d1af30d 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.PropertySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.PropertySymbol.cs @@ -129,6 +129,8 @@ public override bool IsAbstract get { return false; } } + internal override bool IsRequired => false; + internal sealed override ObsoleteAttributeData ObsoleteAttributeData { get { return null; } diff --git a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.SynthesizedMethodBase.cs b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.SynthesizedMethodBase.cs index 6a19be4e5f635..b9fcf514dd8f9 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.SynthesizedMethodBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.SynthesizedMethodBase.cs @@ -231,6 +231,8 @@ internal sealed override int CalculateLocalSyntaxOffset(int localPosition, Synta { throw ExceptionUtilities.Unreachable; } + + protected override bool HasSetsRequiredMembersImpl => throw ExceptionUtilities.Unreachable; } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.TemplateSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.TemplateSymbol.cs index 3ff50c6ba3fa6..9e0c07b2cc20f 100644 --- a/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.TemplateSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/SynthesizedSymbols/AnonymousType.TemplateSymbol.cs @@ -103,6 +103,8 @@ public override TypeKind TypeKind get { return TypeKind.Class; } } + internal override bool HasDeclaredRequiredMembers => false; + public override ImmutableArray GetMembers() { return _members; diff --git a/src/Compilers/CSharp/Portable/Symbols/CompletionPart.cs b/src/Compilers/CSharp/Portable/Symbols/CompletionPart.cs index db5bf7a0a20f3..c69369a4361fa 100644 --- a/src/Compilers/CSharp/Portable/Symbols/CompletionPart.cs +++ b/src/Compilers/CSharp/Portable/Symbols/CompletionPart.cs @@ -49,15 +49,16 @@ internal enum CompletionPart SynthesizedExplicitImplementations = 1 << 13, StartMemberChecks = 1 << 14, FinishMemberChecks = 1 << 15, - MembersCompleted = 1 << 16, // this should be the last (highest-value) part + MembersCompletedChecksStarted = 1 << 16, + MembersCompleted = 1 << 17, // this should be the last (highest-value) part - All = (1 << 17) - 1, + All = (1 << 18) - 1, // This is the work we can do if ForceComplete is scoped to a particular SyntaxTree. NamedTypeSymbolWithLocationAll = Attributes | StartBaseType | FinishBaseType | StartInterfaces | FinishInterfaces | EnumUnderlyingType | TypeArguments | TypeParameters | Members | TypeMembers | SynthesizedExplicitImplementations | StartMemberChecks | FinishMemberChecks, - NamedTypeSymbolAll = NamedTypeSymbolWithLocationAll | MembersCompleted, + NamedTypeSymbolAll = NamedTypeSymbolWithLocationAll | MembersCompletedChecksStarted | MembersCompleted, // For Usings StartValidatingImports = 1 << 4, diff --git a/src/Compilers/CSharp/Portable/Symbols/ConstraintsHelper.cs b/src/Compilers/CSharp/Portable/Symbols/ConstraintsHelper.cs index 2c7e49518efa3..468a4eb20cfc7 100644 --- a/src/Compilers/CSharp/Portable/Symbols/ConstraintsHelper.cs +++ b/src/Compilers/CSharp/Portable/Symbols/ConstraintsHelper.cs @@ -945,6 +945,8 @@ private static bool CheckBasicConstraints( } // See TypeBind::CheckSingleConstraint. + // Any new locals added to this method are likely going to cause EndToEndTests.Constraints to overflow. Break new locals out into + // another function. private static bool CheckConstraints( Symbol containingSymbol, in CheckConstraintsArgs args, @@ -995,14 +997,34 @@ private static bool CheckConstraints( } // Check the constructor constraint. - if (typeParameter.HasConstructorConstraint && !SatisfiesConstructorConstraint(typeArgument.Type)) + if (typeParameter.HasConstructorConstraint && errorIfNotSatisfiesConstructorConstraint(containingSymbol, typeParameter, typeArgument, diagnosticsBuilder)) { - // "'{2}' must be a non-abstract type with a public parameterless constructor in order to use it as parameter '{1}' in the generic type or method '{0}'" - diagnosticsBuilder.Add(new TypeParameterDiagnosticInfo(typeParameter, new UseSiteInfo(new CSDiagnosticInfo(ErrorCode.ERR_NewConstraintNotSatisfied, containingSymbol.ConstructedFrom(), typeParameter, typeArgument.Type)))); return false; } return !hasError; + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool errorIfNotSatisfiesConstructorConstraint(Symbol containingSymbol, TypeParameterSymbol typeParameter, TypeWithAnnotations typeArgument, ArrayBuilder diagnosticsBuilder) + { + var error = SatisfiesConstructorConstraint(typeArgument.Type); + + switch (error) + { + case ConstructorConstraintError.None: + return false; + case ConstructorConstraintError.NoPublicParameterlessConstructorOrAbstractType: + // "'{2}' must be a non-abstract type with a public parameterless constructor in order to use it as parameter '{1}' in the generic type or method '{0}'" + diagnosticsBuilder.Add(new TypeParameterDiagnosticInfo(typeParameter, new UseSiteInfo(new CSDiagnosticInfo(ErrorCode.ERR_NewConstraintNotSatisfied, containingSymbol.ConstructedFrom(), typeParameter, typeArgument.Type)))); + return true; + case ConstructorConstraintError.HasRequiredMembers: + // '{2}' cannot satisfy the 'new()' constraint on parameter '{1}' in the generic type or or method '{0}' because '{2}' has required members. + diagnosticsBuilder.Add(new TypeParameterDiagnosticInfo(typeParameter, new UseSiteInfo(new CSDiagnosticInfo(ErrorCode.ERR_NewConstraintCannotHaveRequiredMembers, containingSymbol.ConstructedFrom(), typeParameter, typeArgument.Type)))); + return true; + default: + throw ExceptionUtilities.UnexpectedValue(error); + } + } } [MethodImpl(MethodImplOptions.NoInlining)] @@ -1341,25 +1363,37 @@ private static void AddInterface(ArrayBuilder builder, NamedTyp } } + private enum ConstructorConstraintError + { + None, + NoPublicParameterlessConstructorOrAbstractType, + HasRequiredMembers, + } + [MethodImpl(MethodImplOptions.NoInlining)] - private static bool SatisfiesConstructorConstraint(TypeSymbol typeArgument) + private static ConstructorConstraintError SatisfiesConstructorConstraint(TypeSymbol typeArgument) { switch (typeArgument.TypeKind) { case TypeKind.Struct: - return HasPublicParameterlessConstructor((NamedTypeSymbol)typeArgument, synthesizedIfMissing: true); + return SatisfiesPublicParameterlessConstructor((NamedTypeSymbol)typeArgument, synthesizedIfMissing: true); case TypeKind.Enum: case TypeKind.Dynamic: - return true; + return ConstructorConstraintError.None; case TypeKind.Class: - return HasPublicParameterlessConstructor((NamedTypeSymbol)typeArgument, synthesizedIfMissing: false) && !typeArgument.IsAbstract; + if (typeArgument.IsAbstract) + { + return ConstructorConstraintError.NoPublicParameterlessConstructorOrAbstractType; + } + + return SatisfiesPublicParameterlessConstructor((NamedTypeSymbol)typeArgument, synthesizedIfMissing: false); case TypeKind.TypeParameter: { var typeParameter = (TypeParameterSymbol)typeArgument; - return typeParameter.HasConstructorConstraint || typeParameter.IsValueType; + return typeParameter.HasConstructorConstraint || typeParameter.IsValueType ? ConstructorConstraintError.None : ConstructorConstraintError.NoPublicParameterlessConstructorOrAbstractType; } case TypeKind.Submission: @@ -1367,24 +1401,41 @@ private static bool SatisfiesConstructorConstraint(TypeSymbol typeArgument) throw ExceptionUtilities.UnexpectedValue(typeArgument.TypeKind); default: - return false; + return ConstructorConstraintError.NoPublicParameterlessConstructorOrAbstractType; } } - /// - /// Return true if the type has a public parameterless constructor. - /// - private static bool HasPublicParameterlessConstructor(NamedTypeSymbol type, bool synthesizedIfMissing) + private static ConstructorConstraintError SatisfiesPublicParameterlessConstructor(NamedTypeSymbol type, bool synthesizedIfMissing) { Debug.Assert(type.TypeKind is TypeKind.Class or TypeKind.Struct); + + bool hasAnyRequiredMembers = type.HasAnyRequiredMembers; + foreach (var constructor in type.InstanceConstructors) { if (constructor.ParameterCount == 0) { - return constructor.DeclaredAccessibility == Accessibility.Public; + if (constructor.DeclaredAccessibility != Accessibility.Public) + { + return ConstructorConstraintError.NoPublicParameterlessConstructorOrAbstractType; + } + else if (hasAnyRequiredMembers && constructor.ShouldCheckRequiredMembers()) + { + return ConstructorConstraintError.HasRequiredMembers; + } + else + { + return ConstructorConstraintError.None; + } } } - return synthesizedIfMissing; + + return (synthesizedIfMissing, hasAnyRequiredMembers) switch + { + (false, _) => ConstructorConstraintError.NoPublicParameterlessConstructorOrAbstractType, + (true, true) => ConstructorConstraintError.HasRequiredMembers, + (true, false) => ConstructorConstraintError.None, + }; } /// diff --git a/src/Compilers/CSharp/Portable/Symbols/ErrorMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/ErrorMethodSymbol.cs index 297301f6b0a83..c28022499e6cd 100644 --- a/src/Compilers/CSharp/Portable/Symbols/ErrorMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/ErrorMethodSymbol.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.Collections.Immutable; +using System.Diagnostics; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Symbols @@ -274,5 +275,14 @@ internal override bool GenerateDebugInfo } internal sealed override bool IsNullableAnalysisEnabled() => false; + + protected override bool HasSetsRequiredMembersImpl + { + get + { + Debug.Assert(MethodKind == MethodKind.Constructor); + return false; + } + } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/ErrorPropertySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/ErrorPropertySymbol.cs index 09256e0b3b6f8..536658ed92722 100644 --- a/src/Compilers/CSharp/Portable/Symbols/ErrorPropertySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/ErrorPropertySymbol.cs @@ -77,6 +77,8 @@ public ErrorPropertySymbol(Symbol containingSymbol, TypeSymbol type, string name public override bool IsExtern { get { return false; } } + internal override bool IsRequired => false; + internal sealed override ObsoleteAttributeData ObsoleteAttributeData { get { return null; } } public override ImmutableArray Parameters { get { return ImmutableArray.Empty; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/ErrorTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/ErrorTypeSymbol.cs index fdb77ade632e6..286394b84209e 100644 --- a/src/Compilers/CSharp/Portable/Symbols/ErrorTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/ErrorTypeSymbol.cs @@ -130,6 +130,8 @@ public override IEnumerable MemberNames } } + internal sealed override bool HasDeclaredRequiredMembers => false; + /// /// Get all the members of this symbol. /// diff --git a/src/Compilers/CSharp/Portable/Symbols/EventSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/EventSymbol.cs index ef4e73e663137..42664a4724719 100644 --- a/src/Compilers/CSharp/Portable/Symbols/EventSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/EventSymbol.cs @@ -307,20 +307,14 @@ internal bool CalculateUseSiteDiagnostic(ref UseSiteInfo result) return false; } - protected override int HighestPriorityUseSiteError - { - get - { - return (int)ErrorCode.ERR_BindToBogus; - } - } + protected sealed override bool IsHighestPriorityUseSiteErrorCode(int code) => code is (int)ErrorCode.ERR_UnsupportedCompilerFeature or (int)ErrorCode.ERR_BindToBogus; public sealed override bool HasUnsupportedMetadata { get { DiagnosticInfo? info = GetUseSiteInfo().DiagnosticInfo; - return (object?)info != null && info.Code == (int)ErrorCode.ERR_BindToBogus; + return (object?)info != null && info.Code is (int)ErrorCode.ERR_BindToBogus or (int)ErrorCode.ERR_UnsupportedCompilerFeature; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/FieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/FieldSymbol.cs index b0b29af001f44..043cc415d096b 100644 --- a/src/Compilers/CSharp/Portable/Symbols/FieldSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/FieldSymbol.cs @@ -327,6 +327,11 @@ internal virtual FieldSymbol AsMember(NamedTypeSymbol newOwner) return newOwner.IsDefinition ? this : new SubstitutedFieldSymbol(newOwner as SubstitutedNamedTypeSymbol, this); } + /// + /// Returns true if this field is required to be set in an object initializer on object creation. + /// + internal abstract bool IsRequired { get; } + #region Use-Site Diagnostics internal override UseSiteInfo GetUseSiteInfo() @@ -368,22 +373,16 @@ internal bool CalculateUseSiteDiagnostic(ref UseSiteInfo result) } /// - /// Return error code that has highest priority while calculating use site error for this symbol. + /// Returns true if the error code is highest priority while calculating use site error for this symbol. /// - protected override int HighestPriorityUseSiteError - { - get - { - return (int)ErrorCode.ERR_BindToBogus; - } - } + protected sealed override bool IsHighestPriorityUseSiteErrorCode(int code) => code is (int)ErrorCode.ERR_UnsupportedCompilerFeature or (int)ErrorCode.ERR_BindToBogus; public sealed override bool HasUnsupportedMetadata { get { DiagnosticInfo info = GetUseSiteInfo().DiagnosticInfo; - return (object)info != null && info.Code == (int)ErrorCode.ERR_BindToBogus; + return (object)info != null && info.Code is (int)ErrorCode.ERR_BindToBogus or (int)ErrorCode.ERR_UnsupportedCompilerFeature; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/FunctionPointers/FunctionPointerMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/FunctionPointers/FunctionPointerMethodSymbol.cs index 2f41d2d20166b..3d33ae01354b3 100644 --- a/src/Compilers/CSharp/Portable/Symbols/FunctionPointers/FunctionPointerMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/FunctionPointers/FunctionPointerMethodSymbol.cs @@ -830,5 +830,6 @@ public override bool IsVararg internal override int CalculateLocalSyntaxOffset(int localPosition, SyntaxTree localTree) => throw ExceptionUtilities.Unreachable; internal override IEnumerable GetSecurityInformation() => throw ExceptionUtilities.Unreachable; internal sealed override bool IsNullableAnalysisEnabled() => throw ExceptionUtilities.Unreachable; + protected sealed override bool HasSetsRequiredMembersImpl => throw ExceptionUtilities.Unreachable; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEAssemblySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEAssemblySymbol.cs index 8415f05846631..6beb3835b6b24 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEAssemblySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEAssemblySymbol.cs @@ -11,6 +11,7 @@ using System.Linq; using System.Reflection.Metadata.Ecma335; +using System.Threading; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE @@ -63,6 +64,10 @@ internal sealed class PEAssemblySymbol : MetadataOrSourceAssemblySymbol /// private ImmutableArray _lazyCustomAttributes; +#nullable enable + private DiagnosticInfo? _lazyCachedCompilerFeatureRequiredDiagnosticInfo = CSDiagnosticInfo.EmptyErrorInfo; +#nullable disable + internal PEAssemblySymbol(PEAssembly assembly, DocumentationProvider documentationProvider, bool isLinked, MetadataImportOptions importOptions) { Debug.Assert(assembly != null); @@ -280,5 +285,22 @@ internal PEModuleSymbol PrimaryModule } public override AssemblyMetadata GetMetadata() => _assembly.GetNonDisposableMetadata(); + +#nullable enable + internal DiagnosticInfo? GetCompilerFeatureRequiredDiagnostic() + { + if (_lazyCachedCompilerFeatureRequiredDiagnosticInfo == CSDiagnosticInfo.EmptyErrorInfo) + { + Interlocked.CompareExchange( + ref _lazyCachedCompilerFeatureRequiredDiagnosticInfo, + PEUtilities.DeriveCompilerFeatureRequiredAttributeDiagnostic(this, PrimaryModule, this.Assembly.Handle, CompilerFeatureRequiredFeatures.None, new MetadataDecoder(PrimaryModule)), + CSDiagnosticInfo.EmptyErrorInfo); + } + + return _lazyCachedCompilerFeatureRequiredDiagnosticInfo; + } + + public override bool HasUnsupportedMetadata + => GetCompilerFeatureRequiredDiagnostic()?.Code == (int)ErrorCode.ERR_UnsupportedCompilerFeature || base.HasUnsupportedMetadata; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEEventSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEEventSymbol.cs index e2ac339e1f650..741a8460157c8 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEEventSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEEventSymbol.cs @@ -468,17 +468,37 @@ internal override UseSiteInfo GetUseSiteInfo() { UseSiteInfo result = new UseSiteInfo(primaryDependency); CalculateUseSiteDiagnostic(ref result); + deriveCompilerFeatureRequiredUseSiteInfo(ref result); _lazyCachedUseSiteInfo.Initialize(primaryDependency, result); } return _lazyCachedUseSiteInfo.ToUseSiteInfo(primaryDependency); + + void deriveCompilerFeatureRequiredUseSiteInfo(ref UseSiteInfo result) + { + var containingType = (PENamedTypeSymbol)ContainingType; + PEModuleSymbol containingPEModule = _containingType.ContainingPEModule; + var diag = PEUtilities.DeriveCompilerFeatureRequiredAttributeDiagnostic( + this, + containingPEModule, + Handle, + allowedFeatures: CompilerFeatureRequiredFeatures.None, + new MetadataDecoder(containingPEModule, containingType)); + + diag ??= containingType.GetCompilerFeatureRequiredDiagnostic(); + + if (diag != null) + { + result = new UseSiteInfo(diag); + } + } } internal override ObsoleteAttributeData ObsoleteAttributeData { get { - ObsoleteAttributeHelpers.InitializeObsoleteDataFromMetadata(ref _lazyObsoleteAttributeData, _handle, (PEModuleSymbol)(this.ContainingModule), ignoreByRefLikeMarker: false); + ObsoleteAttributeHelpers.InitializeObsoleteDataFromMetadata(ref _lazyObsoleteAttributeData, _handle, (PEModuleSymbol)(this.ContainingModule), ignoreByRefLikeMarker: false, ignoreRequiredMemberMarker: false); return _lazyObsoleteAttributeData; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEFieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEFieldSymbol.cs index 9ee7886fdee54..fd77b1d805746 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEFieldSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEFieldSymbol.cs @@ -29,9 +29,10 @@ internal sealed class PEFieldSymbol : FieldSymbol private struct PackedFlags { // Layout: - // |..............................|vvvvv| + // |............................|rr|vvvvv| // // f = FlowAnalysisAnnotations. 5 bits (4 value bits + 1 completion bit). + // r = Required members. 2 bits (1 value bit + 1 completion bit). private const int HasDisallowNullAttribute = 0x1 << 0; private const int HasAllowNullAttribute = 0x1 << 1; @@ -39,6 +40,9 @@ private struct PackedFlags private const int HasNotNullAttribute = 0x1 << 3; private const int FlowAnalysisAnnotationsCompletionBit = 0x1 << 4; + private const int HasRequiredMemberAttribute = 0x1 << 5; + private const int RequiredMemberCompletionBit = 0x1 << 6; + private int _bits; public bool SetFlowAnalysisAnnotations(FlowAnalysisAnnotations value) @@ -67,6 +71,24 @@ public bool TryGetFlowAnalysisAnnotations(out FlowAnalysisAnnotations value) Debug.Assert(value == 0 || result); return result; } + + public bool SetHasRequiredMemberAttribute(bool isRequired) + { + int bitsToSet = RequiredMemberCompletionBit | (isRequired ? HasRequiredMemberAttribute : 0); + return ThreadSafeFlagOperations.Set(ref _bits, bitsToSet); + } + + public bool TryGetHasRequiredMemberAttribute(out bool hasRequiredMemberAttribute) + { + if ((_bits & RequiredMemberCompletionBit) != 0) + { + hasRequiredMemberAttribute = (_bits & HasRequiredMemberAttribute) != 0; + return true; + } + + hasRequiredMemberAttribute = false; + return false; + } } private readonly FieldDefinitionHandle _handle; @@ -568,17 +590,37 @@ internal override UseSiteInfo GetUseSiteInfo() { UseSiteInfo result = new UseSiteInfo(primaryDependency); CalculateUseSiteDiagnostic(ref result); + deriveCompilerFeatureRequiredUseSiteInfo(ref result); _lazyCachedUseSiteInfo.Initialize(primaryDependency, result); } return _lazyCachedUseSiteInfo.ToUseSiteInfo(primaryDependency); + + void deriveCompilerFeatureRequiredUseSiteInfo(ref UseSiteInfo result) + { + var containingType = (PENamedTypeSymbol)ContainingType; + PEModuleSymbol containingPEModule = _containingType.ContainingPEModule; + var diag = PEUtilities.DeriveCompilerFeatureRequiredAttributeDiagnostic( + this, + containingPEModule, + Handle, + allowedFeatures: CompilerFeatureRequiredFeatures.None, + new MetadataDecoder(containingPEModule, containingType)); + + diag ??= containingType.GetCompilerFeatureRequiredDiagnostic(); + + if (diag != null) + { + result = new UseSiteInfo(diag); + } + } } internal override ObsoleteAttributeData ObsoleteAttributeData { get { - ObsoleteAttributeHelpers.InitializeObsoleteDataFromMetadata(ref _lazyObsoleteAttributeData, _handle, (PEModuleSymbol)(this.ContainingModule), ignoreByRefLikeMarker: false); + ObsoleteAttributeHelpers.InitializeObsoleteDataFromMetadata(ref _lazyObsoleteAttributeData, _handle, (PEModuleSymbol)(this.ContainingModule), ignoreByRefLikeMarker: false, ignoreRequiredMemberMarker: false); return _lazyObsoleteAttributeData; } } @@ -587,5 +629,19 @@ internal override ObsoleteAttributeData ObsoleteAttributeData { get { return null; } } + + internal override bool IsRequired + { + get + { + if (!_packedFlags.TryGetHasRequiredMemberAttribute(out bool hasRequiredMemberAttribute)) + { + hasRequiredMemberAttribute = ContainingPEModule.Module.HasAttribute(_handle, AttributeDescription.RequiredMemberAttribute); + _packedFlags.SetHasRequiredMemberAttribute(hasRequiredMemberAttribute); + } + + return hasRequiredMemberAttribute; + } + } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEMethodSymbol.cs index 3cb3947d4ff0b..852bf34165db0 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEMethodSymbol.cs @@ -47,7 +47,7 @@ private struct PackedFlags { // We currently pack everything into a 32-bit int with the following layout: // - // |u|t|s|r|q|p|ooo|n|m|l|k|j|i|h|g|f|e|d|c|b|aaaaa| + // |w|v|u|t|s|r|q|p|ooo|n|m|l|k|j|i|h|g|f|e|d|c|b|aaaaa| // // a = method kind. 5 bits. // b = method kind populated. 1 bit. @@ -72,7 +72,9 @@ private struct PackedFlags // s = IsInitOnlyBit. 1 bit. // t = IsInitOnlyPopulatedBit. 1 bit. // u = IsUnmanagedCallersOnlyAttributePopulated. 1 bit. - // 6 bits remain for future purposes. + // v = IsSetsRequiredMembersBit. 1 bit. + // w = IsSetsRequiredMembersPopulated. 1 bit. + // 4 bits remain for future purposes. private const int MethodKindOffset = 0; private const int MethodKindMask = 0x1F; @@ -98,6 +100,8 @@ private struct PackedFlags private const int IsInitOnlyBit = 0x1 << 24; private const int IsInitOnlyPopulatedBit = 0x1 << 25; private const int IsUnmanagedCallersOnlyAttributePopulatedBit = 0x1 << 26; + private const int HasSetsRequiredMembersBit = 0x1 << 27; + private const int HasSetsRequiredMembersPopulatedBit = 0x1 << 28; private int _bits; @@ -134,6 +138,8 @@ public MethodKind MethodKind public bool IsInitOnly => (_bits & IsInitOnlyBit) != 0; public bool IsInitOnlyPopulated => (_bits & IsInitOnlyPopulatedBit) != 0; public bool IsUnmanagedCallersOnlyAttributePopulated => (_bits & IsUnmanagedCallersOnlyAttributePopulatedBit) != 0; + public bool HasSetsRequiredMembers => (_bits & HasSetsRequiredMembersBit) != 0; + public bool HasSetsRequiredMembersPopulated => (_bits & HasSetsRequiredMembersPopulatedBit) != 0; #if DEBUG static PackedFlags() @@ -240,6 +246,14 @@ public void SetIsUnmanagedCallersOnlyAttributePopulated() { ThreadSafeFlagOperations.Set(ref _bits, IsUnmanagedCallersOnlyAttributePopulatedBit); } + + public bool InitializeSetsRequiredMembersBit(bool value) + { + int bitsToSet = HasSetsRequiredMembersPopulatedBit; + if (value) bitsToSet |= HasSetsRequiredMembersBit; + + return ThreadSafeFlagOperations.Set(ref _bits, bitsToSet); + } } /// @@ -938,14 +952,26 @@ public override ImmutableArray GetAttributes() ? _packedFlags.IsReadOnly : IsValidReadOnlyTarget; + bool checkForRequiredMembers = this.ShouldCheckRequiredMembers() && this.ContainingType.HasAnyRequiredMembers; + bool isExtensionMethod = false; bool isReadOnly = false; - if (checkForExtension || checkForIsReadOnly) + if (checkForExtension || checkForIsReadOnly || checkForRequiredMembers) { - containingPEModuleSymbol.LoadCustomAttributesFilterCompilerAttributes(_handle, - ref attributeData, - out isExtensionMethod, - out isReadOnly); + attributeData = containingPEModuleSymbol.GetCustomAttributesForToken(_handle, + filteredOutAttribute1: out CustomAttributeHandle extensionAttribute, + filterOut1: AttributeDescription.CaseSensitiveExtensionAttribute, + filteredOutAttribute2: out CustomAttributeHandle isReadOnlyAttribute, + filterOut2: AttributeDescription.IsReadOnlyAttribute, + filteredOutAttribute3: out _, + filterOut3: (checkForRequiredMembers && DeriveCompilerFeatureRequiredDiagnostic() is null) ? AttributeDescription.CompilerFeatureRequiredAttribute : default, + filteredOutAttribute4: out _, + filterOut4: (checkForRequiredMembers && ObsoleteAttributeData is null) ? AttributeDescription.ObsoleteAttribute : default, + filteredOutAttribute5: out _, + filterOut5: default); + + isExtensionMethod = !extensionAttribute.IsNil; + isReadOnly = !isReadOnlyAttribute.IsNil; } else { @@ -1344,6 +1370,7 @@ internal override UseSiteInfo GetUseSiteInfo() CalculateUseSiteDiagnostic(ref result); var diagnosticInfo = result.DiagnosticInfo; + MergeUseSiteDiagnostics(ref diagnosticInfo, DeriveCompilerFeatureRequiredDiagnostic()); EnsureTypeParametersAreLoaded(ref diagnosticInfo); if (diagnosticInfo == null && GetUnmanagedCallersOnlyAttributeData(forceComplete: true) is UnmanagedCallersOnlyAttributeData data) { @@ -1355,12 +1382,55 @@ internal override UseSiteInfo GetUseSiteInfo() } } + if (diagnosticInfo == null && this.ShouldCheckRequiredMembers() && ContainingType.HasRequiredMembersError) + { + diagnosticInfo = new CSDiagnosticInfo(ErrorCode.ERR_RequiredMembersInvalid, ContainingType); + } + return InitializeUseSiteDiagnostic(result.AdjustDiagnosticInfo(diagnosticInfo)); } return GetCachedUseSiteInfo(); } + private DiagnosticInfo DeriveCompilerFeatureRequiredDiagnostic() + { + var containingModule = _containingType.ContainingPEModule; + var decoder = new MetadataDecoder(containingModule, this); + var diag = PEUtilities.DeriveCompilerFeatureRequiredAttributeDiagnostic(this, containingModule, Handle, allowedFeatures: MethodKind == MethodKind.Constructor ? CompilerFeatureRequiredFeatures.RequiredMembers : CompilerFeatureRequiredFeatures.None, decoder); + + if (diag != null) + { + return diag; + } + + diag = Signature.ReturnParam.DeriveCompilerFeatureRequiredDiagnostic(decoder); + if (diag != null) + { + return diag; + } + + foreach (var param in Parameters) + { + diag = ((PEParameterSymbol)param).DeriveCompilerFeatureRequiredDiagnostic(decoder); + if (diag != null) + { + return diag; + } + } + + foreach (var typeParam in TypeParameters) + { + diag = ((PETypeParameterSymbol)typeParam).DeriveCompilerFeatureRequiredDiagnostic(decoder); + if (diag != null) + { + return diag; + } + } + + return _containingType.GetCompilerFeatureRequiredDiagnostic(); + } + private UseSiteInfo GetCachedUseSiteInfo() { return (_uncommonFields?._lazyCachedUseSiteInfo ?? default).ToUseSiteInfo(PrimaryDependency); @@ -1411,6 +1481,21 @@ internal override ImmutableArray GetAppliedConditionalSymbols() } } + protected override bool HasSetsRequiredMembersImpl + { + get + { + Debug.Assert(MethodKind == MethodKind.Constructor); + if (!_packedFlags.HasSetsRequiredMembersPopulated) + { + var result = _containingType.ContainingPEModule.Module.HasAttribute(_handle, AttributeDescription.SetsRequiredMembersAttribute); + _packedFlags.InitializeSetsRequiredMembersBit(result); + } + + return _packedFlags.HasSetsRequiredMembers; + } + } + internal override int CalculateLocalSyntaxOffset(int localPosition, SyntaxTree localTree) { throw ExceptionUtilities.Unreachable; @@ -1422,7 +1507,7 @@ internal override ObsoleteAttributeData ObsoleteAttributeData { if (!_packedFlags.IsObsoleteAttributePopulated) { - var result = ObsoleteAttributeHelpers.GetObsoleteDataFromMetadata(_handle, (PEModuleSymbol)ContainingModule, ignoreByRefLikeMarker: false); + var result = ObsoleteAttributeHelpers.GetObsoleteDataFromMetadata(_handle, (PEModuleSymbol)ContainingModule, ignoreByRefLikeMarker: false, ignoreRequiredMemberMarker: MethodKind == MethodKind.Constructor); if (result != null) { result = InterlockedOperations.Initialize(ref AccessUncommonFields()._lazyObsoleteAttributeData, result, ObsoleteAttributeData.Uninitialized); diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEModuleSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEModuleSymbol.cs index 82ad9299e0433..ff1f0d5a8cc13 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEModuleSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEModuleSymbol.cs @@ -102,6 +102,10 @@ private enum NullableMemberMetadata private NullableMemberMetadata _lazyNullableMemberMetadata; +#nullable enable + private DiagnosticInfo? _lazyCachedCompilerFeatureRequiredDiagnosticInfo = CSDiagnosticInfo.EmptyErrorInfo; +#nullable disable + internal PEModuleSymbol(PEAssemblySymbol assemblySymbol, PEModule module, MetadataImportOptions importOptions, int ordinal) : this((AssemblySymbol)assemblySymbol, module, importOptions, ordinal) { @@ -279,15 +283,6 @@ internal void LoadCustomAttributes(EntityHandle token, ref ImmutableArray customAttributes, - out bool foundExtension, - out bool foundReadOnly) - { - var loadedCustomAttributes = GetCustomAttributesFilterCompilerAttributes(token, out foundExtension, out foundReadOnly); - ImmutableInterlocked.InterlockedInitialize(ref customAttributes, loadedCustomAttributes); - } - internal void LoadCustomAttributesFilterExtensions(EntityHandle token, ref ImmutableArray customAttributes) { @@ -299,7 +294,7 @@ internal ImmutableArray GetCustomAttributesForToken(EntityH out CustomAttributeHandle filteredOutAttribute1, AttributeDescription filterOut1) { - return GetCustomAttributesForToken(token, out filteredOutAttribute1, filterOut1, out _, default, out _, default, out _, default); + return GetCustomAttributesForToken(token, out filteredOutAttribute1, filterOut1, out _, default, out _, default, out _, default, out _, default); } /// @@ -314,12 +309,15 @@ internal ImmutableArray GetCustomAttributesForToken(EntityH out CustomAttributeHandle filteredOutAttribute3, AttributeDescription filterOut3, out CustomAttributeHandle filteredOutAttribute4, - AttributeDescription filterOut4) + AttributeDescription filterOut4, + out CustomAttributeHandle filteredOutAttribute5, + AttributeDescription filterOut5) { filteredOutAttribute1 = default; filteredOutAttribute2 = default; filteredOutAttribute3 = default; filteredOutAttribute4 = default; + filteredOutAttribute5 = default; ArrayBuilder customAttributesBuilder = null; try @@ -353,6 +351,12 @@ internal ImmutableArray GetCustomAttributesForToken(EntityH continue; } + if (matchesFilter(customAttributeHandle, filterOut5)) + { + filteredOutAttribute5 = customAttributeHandle; + continue; + } + if (customAttributesBuilder == null) { customAttributesBuilder = ArrayBuilder.GetInstance(); @@ -434,7 +438,8 @@ internal ImmutableArray GetCustomAttributesFilterCompilerAt filteredOutAttribute2: out CustomAttributeHandle isReadOnlyAttribute, filterOut2: AttributeDescription.IsReadOnlyAttribute, filteredOutAttribute3: out _, filterOut3: default, - filteredOutAttribute4: out _, filterOut4: default); + filteredOutAttribute4: out _, filterOut4: default, + filteredOutAttribute5: out _, filterOut5: default); foundExtension = !extensionAttribute.IsNil; foundReadOnly = !isReadOnlyAttribute.IsNil; @@ -755,5 +760,22 @@ internal bool ShouldDecodeNullableAttributes(Symbol symbol) return false; } + +#nullable enable + internal DiagnosticInfo? GetCompilerFeatureRequiredDiagnostic() + { + if (_lazyCachedCompilerFeatureRequiredDiagnosticInfo == CSDiagnosticInfo.EmptyErrorInfo) + { + Interlocked.CompareExchange( + ref _lazyCachedCompilerFeatureRequiredDiagnosticInfo, + PEUtilities.DeriveCompilerFeatureRequiredAttributeDiagnostic(this, this, Token, CompilerFeatureRequiredFeatures.None, new MetadataDecoder(this)), + CSDiagnosticInfo.EmptyErrorInfo); + } + + return _lazyCachedCompilerFeatureRequiredDiagnosticInfo ?? (_assemblySymbol as PEAssemblySymbol)?.GetCompilerFeatureRequiredDiagnostic(); + } + + public override bool HasUnsupportedMetadata + => GetCompilerFeatureRequiredDiagnostic()?.Code == (int)ErrorCode.ERR_UnsupportedCompilerFeature || base.HasUnsupportedMetadata; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PENamedTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PENamedTypeSymbol.cs index 68d0f534621fc..47d94ec32230c 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PENamedTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PENamedTypeSymbol.cs @@ -143,6 +143,7 @@ private class UncommonProperties internal NamedTypeSymbol lazyComImportCoClassType = ErrorTypeSymbol.UnknownResultType; internal ThreeState lazyHasEmbeddedAttribute = ThreeState.Unknown; internal ThreeState lazyHasInterpolatedStringHandlerAttribute = ThreeState.Unknown; + internal ThreeState lazyHasRequiredMembers = ThreeState.Unknown; #if DEBUG internal bool IsDefaultValue() @@ -157,7 +158,8 @@ internal bool IsDefaultValue() lazyDefaultMemberName == null && (object)lazyComImportCoClassType == (object)ErrorTypeSymbol.UnknownResultType && !lazyHasEmbeddedAttribute.HasValue() && - !lazyHasInterpolatedStringHandlerAttribute.HasValue(); + !lazyHasInterpolatedStringHandlerAttribute.HasValue() && + !lazyHasRequiredMembers.HasValue(); } #endif } @@ -197,7 +199,7 @@ internal static PENamedTypeSymbol Create( if (mrEx != null) { - result._lazyCachedUseSiteInfo.Initialize(new CSDiagnosticInfo(ErrorCode.ERR_BogusType, result)); + result._lazyCachedUseSiteInfo.Initialize(result.DeriveCompilerFeatureRequiredDiagnostic() ?? new CSDiagnosticInfo(ErrorCode.ERR_BogusType, result)); } return result; @@ -259,7 +261,7 @@ internal static PENamedTypeSymbol Create( if (mrEx != null || metadataArity < containerMetadataArity) { - result._lazyCachedUseSiteInfo.Initialize(new CSDiagnosticInfo(ErrorCode.ERR_BogusType, result)); + result._lazyCachedUseSiteInfo.Initialize(result.DeriveCompilerFeatureRequiredDiagnostic() ?? new CSDiagnosticInfo(ErrorCode.ERR_BogusType, result)); } return result; @@ -329,7 +331,7 @@ private PENamedTypeSymbol( if (makeBad) { - _lazyCachedUseSiteInfo.Initialize(new CSDiagnosticInfo(ErrorCode.ERR_BogusType, this)); + _lazyCachedUseSiteInfo.Initialize(DeriveCompilerFeatureRequiredDiagnostic() ?? new CSDiagnosticInfo(ErrorCode.ERR_BogusType, this)); } } @@ -677,7 +679,10 @@ public override ImmutableArray GetAttributes() IsReadOnly ? AttributeDescription.IsReadOnlyAttribute : default, out _, // Filter out [IsByRefLike] - IsRefLikeType ? AttributeDescription.IsByRefLikeAttribute : default); + IsRefLikeType ? AttributeDescription.IsByRefLikeAttribute : default, + out _, + // Filter out [CompilerFeatureRequired] + (IsRefLikeType && DeriveCompilerFeatureRequiredDiagnostic() is null) ? AttributeDescription.CompilerFeatureRequiredAttribute : default); ImmutableInterlocked.InterlockedInitialize(ref uncommon.lazyCustomAttributes, loadedCustomAttributes); } @@ -824,6 +829,27 @@ private static ICollection CreateReadOnlyMemberNames(HashSet nam } } + internal override bool HasDeclaredRequiredMembers + { + get + { + var uncommon = GetUncommonProperties(); + if (uncommon == s_noUncommonProperties) + { + return false; + } + + if (uncommon.lazyHasRequiredMembers.HasValue()) + { + return uncommon.lazyHasRequiredMembers.Value(); + } + + var hasRequiredMemberAttribute = ContainingPEModule.Module.HasAttribute(_handle, AttributeDescription.RequiredMemberAttribute); + uncommon.lazyHasRequiredMembers = hasRequiredMemberAttribute.ToThreeState(); + return hasRequiredMemberAttribute; + } + } + public override ImmutableArray GetMembers() { EnsureAllMembersAreLoaded(); @@ -2001,7 +2027,14 @@ internal override UseSiteInfo GetUseSiteInfo() protected virtual DiagnosticInfo GetUseSiteDiagnosticImpl() { - DiagnosticInfo diagnostic = null; + // GetCompilerFeatureRequiredDiagnostic depends on UnsupportedCompilerFeature being the highest priority diagnostic, or it will return incorrect + // results and assert in Debug mode. + DiagnosticInfo diagnostic = DeriveCompilerFeatureRequiredDiagnostic(); + + if (diagnostic != null) + { + return diagnostic; + } if (!MergeUseSiteDiagnostics(ref diagnostic, CalculateUseSiteDiagnostic())) { @@ -2037,6 +2070,45 @@ protected virtual DiagnosticInfo GetUseSiteDiagnosticImpl() return diagnostic; } +#nullable enable + internal DiagnosticInfo? GetCompilerFeatureRequiredDiagnostic() + { + var useSiteInfo = GetUseSiteInfo(); + if (useSiteInfo.DiagnosticInfo is { Code: (int)ErrorCode.ERR_UnsupportedCompilerFeature } diag) + { + return diag; + } + + Debug.Assert(DeriveCompilerFeatureRequiredDiagnostic() is null); + return null; + } + + private DiagnosticInfo? DeriveCompilerFeatureRequiredDiagnostic() + { + var decoder = new MetadataDecoder(ContainingPEModule, this); + var diag = PEUtilities.DeriveCompilerFeatureRequiredAttributeDiagnostic(this, ContainingPEModule, Handle, allowedFeatures: IsRefLikeType ? CompilerFeatureRequiredFeatures.RefStructs : CompilerFeatureRequiredFeatures.None, decoder); + + if (diag != null) + { + return diag; + } + + foreach (var typeParameter in TypeParameters) + { + diag = ((PETypeParameterSymbol)typeParameter).DeriveCompilerFeatureRequiredDiagnostic(decoder); + + if (diag != null) + { + return diag; + } + } + + return ContainingType is PENamedTypeSymbol containingType + ? containingType.GetCompilerFeatureRequiredDiagnostic() + : ContainingPEModule.GetCompilerFeatureRequiredDiagnostic(); + } +#nullable disable + internal string DefaultMemberName { get @@ -2239,7 +2311,7 @@ internal override ObsoleteAttributeData ObsoleteAttributeData } bool ignoreByRefLikeMarker = this.IsRefLikeType; - ObsoleteAttributeHelpers.InitializeObsoleteDataFromMetadata(ref uncommon.lazyObsoleteAttributeData, _handle, ContainingPEModule, ignoreByRefLikeMarker); + ObsoleteAttributeHelpers.InitializeObsoleteDataFromMetadata(ref uncommon.lazyObsoleteAttributeData, _handle, ContainingPEModule, ignoreByRefLikeMarker, ignoreRequiredMemberMarker: false); return uncommon.lazyObsoleteAttributeData; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEParameterSymbol.cs index 284e33daf6c95..ab8ca6ae6b1ae 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEParameterSymbol.cs @@ -997,6 +997,8 @@ public override ImmutableArray GetAttributes() out isReadOnlyAttribute, filterIsReadOnlyAttribute ? AttributeDescription.IsReadOnlyAttribute : default, out _, + default, + out _, default); if (!paramArrayAttribute.IsNil || !constantAttribute.IsNil) @@ -1067,5 +1069,25 @@ public sealed override bool Equals(Symbol other, TypeCompareKind compareKind) nps.Equals(this, compareKind) : base.Equals(other, compareKind); } + +#nullable enable + internal DiagnosticInfo? DeriveCompilerFeatureRequiredDiagnostic(MetadataDecoder decoder) + => PEUtilities.DeriveCompilerFeatureRequiredAttributeDiagnostic(this, (PEModuleSymbol)ContainingModule, Handle, allowedFeatures: CompilerFeatureRequiredFeatures.None, decoder); + + public override bool HasUnsupportedMetadata + { + get + { + var containingModule = (PEModuleSymbol)ContainingModule; + var decoder = ContainingSymbol switch + { + PEMethodSymbol method => new MetadataDecoder(containingModule, method), + PEPropertySymbol => new MetadataDecoder(containingModule, (PENamedTypeSymbol)ContainingType), + _ => throw ExceptionUtilities.UnexpectedValue(this.ContainingSymbol.Kind) + }; + + return DeriveCompilerFeatureRequiredDiagnostic(decoder) is { Code: (int)ErrorCode.ERR_UnsupportedCompilerFeature } || base.HasUnsupportedMetadata; + } + } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEPropertySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEPropertySymbol.cs index ea1982d34f099..ec5d0a6e3ebda 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEPropertySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEPropertySymbol.cs @@ -17,6 +17,7 @@ using Microsoft.CodeAnalysis.CSharp.DocumentationComments; using Microsoft.CodeAnalysis.CSharp.Emit; using Microsoft.CodeAnalysis.PooledObjects; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE { @@ -47,14 +48,53 @@ internal class PEPropertySymbol private const int UnsetAccessibility = -1; private int _declaredAccessibility = UnsetAccessibility; - private readonly Flags _flags; + private PackedFlags _flags; - [Flags] - private enum Flags : byte + private struct PackedFlags { - IsSpecialName = 1, - IsRuntimeSpecialName = 2, - CallMethodsDirectly = 4 + // Layout: + // |...........................|rr|c|n|s| + // + // s = special name flag. 1 bit + // n = runtime special name flag. 1 bit + // c = call methods directly flag. 1 bit + // r = Required member. 2 bits (1 bit for value + 1 completion bit). + private const int IsSpecialNameFlag = 1 << 0; + private const int IsRuntimeSpecialNameFlag = 1 << 1; + private const int CallMethodsDirectlyFlag = 1 << 2; + private const int HasRequiredMemberAttribute = 1 << 4; + private const int RequiredMemberCompletionBit = 1 << 5; + + private int _bits; + + public PackedFlags(bool isSpecialName, bool isRuntimeSpecialName, bool callMethodsDirectly) + { + _bits = (isSpecialName ? IsSpecialNameFlag : 0) + | (isRuntimeSpecialName ? IsRuntimeSpecialNameFlag : 0) + | (callMethodsDirectly ? CallMethodsDirectlyFlag : 0); + } + + public void SetHasRequiredMemberAttribute(bool isRequired) + { + var bitsToSet = (isRequired ? HasRequiredMemberAttribute : 0) | RequiredMemberCompletionBit; + ThreadSafeFlagOperations.Set(ref _bits, bitsToSet); + } + + public bool TryGetHasRequiredMemberAttribute(out bool hasRequiredMemberAttribute) + { + if ((_bits & RequiredMemberCompletionBit) != 0) + { + hasRequiredMemberAttribute = (_bits & HasRequiredMemberAttribute) != 0; + return true; + } + + hasRequiredMemberAttribute = false; + return false; + } + + public bool IsSpecialName => (_bits & IsSpecialNameFlag) != 0; + public bool IsRuntimeSpecialName => (_bits & IsRuntimeSpecialNameFlag) != 0; + public bool CallMethodsDirectly => (_bits & CallMethodsDirectlyFlag) != 0; } internal static PEPropertySymbol Create( @@ -204,20 +244,10 @@ private PEPropertySymbol( } } - if (callMethodsDirectly) - { - _flags |= Flags.CallMethodsDirectly; - } - - if ((mdFlags & PropertyAttributes.SpecialName) != 0) - { - _flags |= Flags.IsSpecialName; - } - - if ((mdFlags & PropertyAttributes.RTSpecialName) != 0) - { - _flags |= Flags.IsRuntimeSpecialName; - } + _flags = new PackedFlags( + isSpecialName: (mdFlags & PropertyAttributes.SpecialName) != 0, + isRuntimeSpecialName: (mdFlags & PropertyAttributes.RTSpecialName) != 0, + callMethodsDirectly); static bool anyUnexpectedRequiredModifiers(ParamInfo[] propertyParams) { @@ -277,7 +307,7 @@ public override string Name internal override bool HasSpecialName { - get { return (_flags & Flags.IsSpecialName) != 0; } + get { return _flags.IsSpecialName; } } public override string MetadataName @@ -462,6 +492,21 @@ public override bool IsStatic } } + internal override bool IsRequired + { + get + { + if (!_flags.TryGetHasRequiredMemberAttribute(out bool hasRequiredMemberAttribute)) + { + var containingPEModuleSymbol = (PEModuleSymbol)this.ContainingModule; + hasRequiredMemberAttribute = containingPEModuleSymbol.Module.HasAttribute(_handle, AttributeDescription.RequiredMemberAttribute); + _flags.SetHasRequiredMemberAttribute(hasRequiredMemberAttribute); + } + + return hasRequiredMemberAttribute; + } + } + public override ImmutableArray Parameters { get { return _parameters; } @@ -623,7 +668,7 @@ public override ImmutableArray ExplicitInterfaceImplementations internal override bool MustCallMethodsDirectly { - get { return (_flags & Flags.CallMethodsDirectly) != 0; } + get { return _flags.CallMethodsDirectly; } } private static bool DoSignaturesMatch( @@ -739,17 +784,49 @@ internal override UseSiteInfo GetUseSiteInfo() { var result = new UseSiteInfo(primaryDependency); CalculateUseSiteDiagnostic(ref result); + var diag = deriveCompilerFeatureRequiredUseSiteInfo(); + MergeUseSiteDiagnostics(ref diag, result.DiagnosticInfo); + result = result.AdjustDiagnosticInfo(diag); _lazyCachedUseSiteInfo.Initialize(primaryDependency, result); } return _lazyCachedUseSiteInfo.ToUseSiteInfo(primaryDependency); + + DiagnosticInfo deriveCompilerFeatureRequiredUseSiteInfo() + { + var containingType = (PENamedTypeSymbol)ContainingType; + PEModuleSymbol containingPEModule = _containingType.ContainingPEModule; + var decoder = new MetadataDecoder(containingPEModule, containingType); + var diag = PEUtilities.DeriveCompilerFeatureRequiredAttributeDiagnostic( + this, + containingPEModule, + Handle, + allowedFeatures: CompilerFeatureRequiredFeatures.None, + decoder); + + if (diag != null) + { + return diag; + } + + foreach (var param in Parameters) + { + diag = ((PEParameterSymbol)param).DeriveCompilerFeatureRequiredDiagnostic(decoder); + if (diag != null) + { + return diag; + } + } + + return containingType.GetCompilerFeatureRequiredDiagnostic(); + } } internal override ObsoleteAttributeData ObsoleteAttributeData { get { - ObsoleteAttributeHelpers.InitializeObsoleteDataFromMetadata(ref _lazyObsoleteAttributeData, _handle, (PEModuleSymbol)(this.ContainingModule), ignoreByRefLikeMarker: false); + ObsoleteAttributeHelpers.InitializeObsoleteDataFromMetadata(ref _lazyObsoleteAttributeData, _handle, (PEModuleSymbol)(this.ContainingModule), ignoreByRefLikeMarker: false, ignoreRequiredMemberMarker: false); return _lazyObsoleteAttributeData; } } @@ -758,7 +835,7 @@ internal override bool HasRuntimeSpecialName { get { - return (_flags & Flags.IsRuntimeSpecialName) != 0; + return _flags.IsRuntimeSpecialName; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PETypeParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PETypeParameterSymbol.cs index 9c1cd3c683066..147b7b07f8bc1 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PETypeParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PETypeParameterSymbol.cs @@ -165,7 +165,7 @@ private ImmutableArray GetDeclaredConstraintTypes(ConsList< if (constraints.Count > 0) { var symbolsBuilder = ArrayBuilder.GetInstance(); - MetadataDecoder tokenDecoder = GetDecoderForConstraintTypes(moduleSymbol); + MetadataDecoder tokenDecoder = GetDecoder(moduleSymbol); TypeWithAnnotations bestObjectConstraint = default; @@ -246,7 +246,7 @@ private ImmutableArray GetDeclaredConstraintTypes(ConsList< return _lazyDeclaredConstraintTypes; } - private MetadataDecoder GetDecoderForConstraintTypes(PEModuleSymbol moduleSymbol) + private MetadataDecoder GetDecoder(PEModuleSymbol moduleSymbol) { MetadataDecoder tokenDecoder; if (_containingSymbol.Kind == SymbolKind.Method) @@ -534,7 +534,7 @@ internal override bool? IsNotNullable { // We must have filtered out some Object constraints, lets calculate nullability from them. var symbolsBuilder = ArrayBuilder.GetInstance(); - MetadataDecoder tokenDecoder = GetDecoderForConstraintTypes(moduleSymbol); + MetadataDecoder tokenDecoder = GetDecoder(moduleSymbol); bool hasUnmanagedModreqPattern = false; var metadataReader = module.MetadataReader; @@ -705,5 +705,18 @@ private NamedTypeSymbol GetDefaultBaseType() { get { return null; } } + +#nullable enable + internal DiagnosticInfo? DeriveCompilerFeatureRequiredDiagnostic(MetadataDecoder decoder) + => PEUtilities.DeriveCompilerFeatureRequiredAttributeDiagnostic(this, (PEModuleSymbol)ContainingModule, Handle, CompilerFeatureRequiredFeatures.None, decoder); + + public override bool HasUnsupportedMetadata + { + get + { + var containingModule = (PEModuleSymbol)ContainingModule; + return DeriveCompilerFeatureRequiredDiagnostic(GetDecoder(containingModule)) is { Code: (int)ErrorCode.ERR_UnsupportedCompilerFeature } || base.HasUnsupportedMetadata; + } + } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEUtilities.cs b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEUtilities.cs new file mode 100644 index 0000000000000..4d88aa5c074d3 --- /dev/null +++ b/src/Compilers/CSharp/Portable/Symbols/Metadata/PE/PEUtilities.cs @@ -0,0 +1,19 @@ +// 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.Reflection.Metadata; + +namespace Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE; + +internal static class PEUtilities +{ + internal static DiagnosticInfo? DeriveCompilerFeatureRequiredAttributeDiagnostic(Symbol symbol, PEModuleSymbol module, EntityHandle handle, CompilerFeatureRequiredFeatures allowedFeatures, MetadataDecoder decoder) + { + string? disallowedFeature = module.Module.GetFirstUnsupportedCompilerFeatureFromToken(handle, decoder, allowedFeatures); + return disallowedFeature != null + ? // '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. + new CSDiagnosticInfo(ErrorCode.ERR_UnsupportedCompilerFeature, symbol, disallowedFeature) + : null; + } +} diff --git a/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs index ac29ff0719671..b710bf43f30ce 100644 --- a/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs @@ -579,6 +579,13 @@ public bool IsConditional } } + /// + /// Returns true if this is a constructor attributed with HasSetsRequiredMembers + /// + internal bool HasSetsRequiredMembers => MethodKind == MethodKind.Constructor && HasSetsRequiredMembersImpl; + + protected abstract bool HasSetsRequiredMembersImpl { get; } + /// /// Some method kinds do not participate in overriding/hiding (e.g. constructors). /// @@ -1049,22 +1056,16 @@ static bool isGenericMethod([DisallowNull] MethodSymbol? method) #nullable disable /// - /// Return error code that has highest priority while calculating use site error for this symbol. + /// Returns true if the error code is highest priority while calculating use site error for this symbol. /// - protected override int HighestPriorityUseSiteError - { - get - { - return (int)ErrorCode.ERR_BindToBogus; - } - } + protected sealed override bool IsHighestPriorityUseSiteErrorCode(int code) => code is (int)ErrorCode.ERR_UnsupportedCompilerFeature or (int)ErrorCode.ERR_BindToBogus; public sealed override bool HasUnsupportedMetadata { get { DiagnosticInfo info = GetUseSiteInfo().DiagnosticInfo; - return (object)info != null && info.Code == (int)ErrorCode.ERR_BindToBogus; + return (object)info != null && info.Code is (int)ErrorCode.ERR_BindToBogus or (int)ErrorCode.ERR_UnsupportedCompilerFeature; } } @@ -1209,5 +1210,29 @@ public override int GetHashCode() { return base.GetHashCode(); } + +#nullable enable + protected static void AddRequiredMembersMarkerAttributes(ref ArrayBuilder attributes, MethodSymbol methodToAttribute) + { + if (methodToAttribute.ShouldCheckRequiredMembers() && methodToAttribute.ContainingType.HasAnyRequiredMembers) + { + var obsoleteData = methodToAttribute.ObsoleteAttributeData; + Debug.Assert(obsoleteData != ObsoleteAttributeData.Uninitialized, "getting synthesized attributes before attributes are decoded"); + + CSharpCompilation declaringCompilation = methodToAttribute.DeclaringCompilation; + if (obsoleteData == null) + { + AddSynthesizedAttribute(ref attributes, declaringCompilation.TrySynthesizeAttribute(WellKnownMember.System_ObsoleteAttribute__ctor, + ImmutableArray.Create( + new TypedConstant(declaringCompilation.GetSpecialType(SpecialType.System_String), TypedConstantKind.Primitive, PEModule.RequiredMembersMarker), // message + new TypedConstant(declaringCompilation.GetSpecialType(SpecialType.System_Boolean), TypedConstantKind.Primitive, true)) // error + )); + } + + AddSynthesizedAttribute(ref attributes, declaringCompilation.TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_CompilerFeatureRequiredAttribute__ctor, + ImmutableArray.Create(new TypedConstant(declaringCompilation.GetSpecialType(SpecialType.System_String), TypedConstantKind.Primitive, nameof(CompilerFeatureRequiredFeatures.RequiredMembers))) + )); + } + } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/NamedTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/NamedTypeSymbol.cs index d5b7e34f12285..19639974753a0 100644 --- a/src/Compilers/CSharp/Portable/Symbols/NamedTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/NamedTypeSymbol.cs @@ -11,6 +11,8 @@ using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Threading; +using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Symbols; using Roslyn.Utilities; @@ -24,6 +26,14 @@ internal abstract partial class NamedTypeSymbol : TypeSymbol, INamedTypeSymbolIn { private bool _hasNoBaseCycles; + private static readonly ImmutableSegmentedDictionary RequiredMembersErrorSentinel = ImmutableSegmentedDictionary.Empty.Add("", null!); + + /// + /// if uninitialized. if there are errors. if + /// there are no required members. Otherwise, the required members. + /// + private ImmutableSegmentedDictionary _lazyRequiredMembers = default; + // Only the compiler can create NamedTypeSymbols. internal NamedTypeSymbol(TupleExtraData tupleData = null) { @@ -494,6 +504,134 @@ internal abstract bool MangleName /// public abstract IEnumerable MemberNames { get; } + /// + /// True if this type declares any required members. It does not recursively check up the tree for _all_ required members. + /// + internal abstract bool HasDeclaredRequiredMembers { get; } + +#nullable enable + /// + /// Whether the type encountered an error while trying to build its complete list of required members. + /// + internal bool HasRequiredMembersError + { + get + { + CalculateRequiredMembersIfRequired(); + Debug.Assert(!_lazyRequiredMembers.IsDefault); + return _lazyRequiredMembers == RequiredMembersErrorSentinel; + } + } + + /// + /// Returns true if there are any required members. Prefer calling this over checking for empty, as + /// this will avoid calculating base type requirements if not necessary. + /// + internal bool HasAnyRequiredMembers => HasDeclaredRequiredMembers || !AllRequiredMembers.IsEmpty; + + /// + /// The full list of all required members for this type, including from base classes. If is true, + /// this returns empty. + /// + /// + /// Do not call this API if all you need are the required members declared on this type. Use instead, filtering for + /// required members, instead of calling this API. If you only need to determine whether this type or any base types have required members, call + /// , which will avoid calling this API if not required. + /// + internal ImmutableSegmentedDictionary AllRequiredMembers + { + get + { + CalculateRequiredMembersIfRequired(); + Debug.Assert(!_lazyRequiredMembers.IsDefault); + if (_lazyRequiredMembers == RequiredMembersErrorSentinel) + { + return ImmutableSegmentedDictionary.Empty; + } + + return _lazyRequiredMembers; + } + } + + private void CalculateRequiredMembersIfRequired() + { + if (!_lazyRequiredMembers.IsDefault) + { + return; + } + + ImmutableSegmentedDictionary.Builder? builder = null; + bool success = TryCalculateRequiredMembers(ref builder); + + var requiredMembers = success + ? builder?.ToImmutable() ?? ImmutableSegmentedDictionary.Empty + : RequiredMembersErrorSentinel; + + RoslynImmutableInterlocked.InterlockedInitialize(ref _lazyRequiredMembers, requiredMembers); + } + + /// + /// Attempts to calculate the required members for this type. Returns false if there were errors. + /// + private bool TryCalculateRequiredMembers(ref ImmutableSegmentedDictionary.Builder? requiredMembersBuilder) + { + var lazyRequiredMembers = _lazyRequiredMembers; + if (_lazyRequiredMembers == RequiredMembersErrorSentinel) + { + if (lazyRequiredMembers.IsDefault) + { + return false; + } + else + { + requiredMembersBuilder = lazyRequiredMembers.ToBuilder(); + return true; + } + } + + if (BaseTypeNoUseSiteDiagnostics?.TryCalculateRequiredMembers(ref requiredMembersBuilder) == false) + { + return false; + } + + // We need to make sure that members from a base type weren't hidden by members from the current type. + if (!HasDeclaredRequiredMembers && requiredMembersBuilder == null) + { + return true; + } + + return addCurrentTypeMembers(ref requiredMembersBuilder); + + bool addCurrentTypeMembers(ref ImmutableSegmentedDictionary.Builder? requiredMembersBuilder) + { + requiredMembersBuilder ??= ImmutableSegmentedDictionary.CreateBuilder(); + + foreach (var member in GetMembersUnordered()) + { + if (requiredMembersBuilder.ContainsKey(member.Name)) + { + // This is only permitted if the member is an override of a required member from a base type, and is required itself. + if (!member.IsRequired() + || member.GetOverriddenMember() is not { } overriddenMember + || !overriddenMember.Equals(requiredMembersBuilder[member.Name], TypeCompareKind.ConsiderEverything)) + { + return false; + } + } + + if (!member.IsRequired()) + { + continue; + } + + requiredMembersBuilder[member.Name] = member; + } + + return true; + } + } +#nullable disable + /// /// Get all the members of this symbol. /// diff --git a/src/Compilers/CSharp/Portable/Symbols/NativeIntegerTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/NativeIntegerTypeSymbol.cs index 2c4fd31ec8e93..9687a3462bc72 100644 --- a/src/Compilers/CSharp/Portable/Symbols/NativeIntegerTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/NativeIntegerTypeSymbol.cs @@ -51,6 +51,8 @@ internal NativeIntegerTypeSymbol(NamedTypeSymbol underlyingType) : base(underlyi public override IEnumerable MemberNames => GetMembers().Select(m => m.Name); + internal override bool HasDeclaredRequiredMembers => false; + /// /// Certain members from the underlying types are not exposed from the native integer types: /// constructors other than the default parameterless constructor are not supported; diff --git a/src/Compilers/CSharp/Portable/Symbols/ObsoleteAttributeHelpers.cs b/src/Compilers/CSharp/Portable/Symbols/ObsoleteAttributeHelpers.cs index f9658e1da2f38..ed20191a807a2 100644 --- a/src/Compilers/CSharp/Portable/Symbols/ObsoleteAttributeHelpers.cs +++ b/src/Compilers/CSharp/Portable/Symbols/ObsoleteAttributeHelpers.cs @@ -26,11 +26,11 @@ internal static class ObsoleteAttributeHelpers /// Initialize the ObsoleteAttributeData by fetching attributes and decoding ObsoleteAttributeData. This can be /// done for Metadata symbol easily whereas trying to do this for source symbols could result in cycles. /// - internal static void InitializeObsoleteDataFromMetadata(ref ObsoleteAttributeData data, EntityHandle token, PEModuleSymbol containingModule, bool ignoreByRefLikeMarker) + internal static void InitializeObsoleteDataFromMetadata(ref ObsoleteAttributeData data, EntityHandle token, PEModuleSymbol containingModule, bool ignoreByRefLikeMarker, bool ignoreRequiredMemberMarker) { if (ReferenceEquals(data, ObsoleteAttributeData.Uninitialized)) { - ObsoleteAttributeData obsoleteAttributeData = GetObsoleteDataFromMetadata(token, containingModule, ignoreByRefLikeMarker); + ObsoleteAttributeData obsoleteAttributeData = GetObsoleteDataFromMetadata(token, containingModule, ignoreByRefLikeMarker, ignoreRequiredMemberMarker); Interlocked.CompareExchange(ref data, obsoleteAttributeData, ObsoleteAttributeData.Uninitialized); } } @@ -39,9 +39,9 @@ internal static void InitializeObsoleteDataFromMetadata(ref ObsoleteAttributeDat /// Get the ObsoleteAttributeData by fetching attributes and decoding ObsoleteAttributeData. This can be /// done for Metadata symbol easily whereas trying to do this for source symbols could result in cycles. /// - internal static ObsoleteAttributeData GetObsoleteDataFromMetadata(EntityHandle token, PEModuleSymbol containingModule, bool ignoreByRefLikeMarker) + internal static ObsoleteAttributeData GetObsoleteDataFromMetadata(EntityHandle token, PEModuleSymbol containingModule, bool ignoreByRefLikeMarker, bool ignoreRequiredMemberMarker) { - var obsoleteAttributeData = containingModule.Module.TryGetDeprecatedOrExperimentalOrObsoleteAttribute(token, new MetadataDecoder(containingModule), ignoreByRefLikeMarker); + var obsoleteAttributeData = containingModule.Module.TryGetDeprecatedOrExperimentalOrObsoleteAttribute(token, new MetadataDecoder(containingModule), ignoreByRefLikeMarker, ignoreRequiredMemberMarker); Debug.Assert(obsoleteAttributeData == null || !obsoleteAttributeData.IsUninitialized); return obsoleteAttributeData; } diff --git a/src/Compilers/CSharp/Portable/Symbols/ParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/ParameterSymbol.cs index 027cd87d57f51..23113b65ba428 100644 --- a/src/Compilers/CSharp/Portable/Symbols/ParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/ParameterSymbol.cs @@ -415,21 +415,15 @@ internal sealed override ObsoleteAttributeData? ObsoleteAttributeData /// internal abstract bool HasInterpolatedStringHandlerArgumentError { get; } - protected sealed override int HighestPriorityUseSiteError - { - get - { - return (int)ErrorCode.ERR_BogusType; - } - } + protected sealed override bool IsHighestPriorityUseSiteErrorCode(int code) => code is (int)ErrorCode.ERR_UnsupportedCompilerFeature or (int)ErrorCode.ERR_BogusType; - public sealed override bool HasUnsupportedMetadata + public override bool HasUnsupportedMetadata { get { UseSiteInfo info = default; DeriveUseSiteInfoFromParameter(ref info, this); - return info.DiagnosticInfo?.Code == (int)ErrorCode.ERR_BogusType; + return info.DiagnosticInfo?.Code is (int)ErrorCode.ERR_BogusType or (int)ErrorCode.ERR_UnsupportedCompilerFeature; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/PropertySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/PropertySymbol.cs index 72d99b8ffed28..245c42e1b0d21 100644 --- a/src/Compilers/CSharp/Portable/Symbols/PropertySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/PropertySymbol.cs @@ -182,6 +182,11 @@ public bool IsWriteOnly } } + /// + /// Returns true if this property is required to be set in an object initializer on object creation. + /// + internal abstract bool IsRequired { get; } + /// /// True if the property itself is excluded from code coverage instrumentation. /// True for source properties marked with . @@ -395,22 +400,16 @@ internal bool CalculateUseSiteDiagnostic(ref UseSiteInfo result) } /// - /// Return error code that has highest priority while calculating use site error for this symbol. + /// Returns true if the error code is highest priority while calculating use site error for this symbol. /// - protected override int HighestPriorityUseSiteError - { - get - { - return (int)ErrorCode.ERR_BindToBogus; - } - } + protected sealed override bool IsHighestPriorityUseSiteErrorCode(int code) => code is (int)ErrorCode.ERR_UnsupportedCompilerFeature or (int)ErrorCode.ERR_BindToBogus; public sealed override bool HasUnsupportedMetadata { get { DiagnosticInfo info = GetUseSiteInfo().DiagnosticInfo; - return (object)info != null && info.Code == (int)ErrorCode.ERR_BindToBogus; + return (object)info != null && info.Code is (int)ErrorCode.ERR_BindToBogus or (int)ErrorCode.ERR_UnsupportedCompilerFeature; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/PublicModel/FieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/PublicModel/FieldSymbol.cs index cdb351051f5f0..152c4b0705169 100644 --- a/src/Compilers/CSharp/Portable/Symbols/PublicModel/FieldSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/PublicModel/FieldSymbol.cs @@ -81,6 +81,8 @@ bool IFieldSymbol.IsExplicitlyNamedTupleElement bool IFieldSymbol.IsVolatile => _underlying.IsVolatile; + bool IFieldSymbol.IsRequired => _underlying.IsRequired; + bool IFieldSymbol.IsFixedSizeBuffer => _underlying.IsFixedSizeBuffer; int IFieldSymbol.FixedSize => _underlying.FixedSize; diff --git a/src/Compilers/CSharp/Portable/Symbols/PublicModel/PropertySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/PublicModel/PropertySymbol.cs index da7ba61459435..90182156c74f3 100644 --- a/src/Compilers/CSharp/Portable/Symbols/PublicModel/PropertySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/PublicModel/PropertySymbol.cs @@ -91,6 +91,8 @@ bool IPropertySymbol.IsWithEvents get { return false; } } + bool IPropertySymbol.IsRequired => _underlying.IsRequired; + ImmutableArray IPropertySymbol.TypeCustomModifiers { get { return _underlying.TypeWithAnnotations.CustomModifiers; } diff --git a/src/Compilers/CSharp/Portable/Symbols/ReducedExtensionMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/ReducedExtensionMethodSymbol.cs index acaf3d1f1e2d6..13b88243aa82d 100644 --- a/src/Compilers/CSharp/Portable/Symbols/ReducedExtensionMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/ReducedExtensionMethodSymbol.cs @@ -588,6 +588,8 @@ public override int GetHashCode() return _reducedFrom.GetHashCode(); } + protected sealed override bool HasSetsRequiredMembersImpl => throw ExceptionUtilities.Unreachable; + #nullable enable private sealed class ReducedExtensionMethodParameterSymbol : WrappedParameterSymbol diff --git a/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingNamedTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingNamedTypeSymbol.cs index 2cbb456b5e414..b0b09dc44586e 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingNamedTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Retargeting/RetargetingNamedTypeSymbol.cs @@ -120,6 +120,8 @@ public override IEnumerable MemberNames } } + internal override bool HasDeclaredRequiredMembers => _underlyingType.HasDeclaredRequiredMembers; + public override ImmutableArray GetMembers() { return this.RetargetingTranslator.Retarget(_underlyingType.GetMembers()); diff --git a/src/Compilers/CSharp/Portable/Symbols/SignatureOnlyMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/SignatureOnlyMethodSymbol.cs index 59a09861eb1cf..bb92c1a6e5afb 100644 --- a/src/Compilers/CSharp/Portable/Symbols/SignatureOnlyMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/SignatureOnlyMethodSymbol.cs @@ -172,6 +172,8 @@ internal override bool IsMetadataFinal internal override int CalculateLocalSyntaxOffset(int localPosition, SyntaxTree localTree) { throw ExceptionUtilities.Unreachable; } + protected sealed override bool HasSetsRequiredMembersImpl => throw ExceptionUtilities.Unreachable; + #endregion } } diff --git a/src/Compilers/CSharp/Portable/Symbols/SignatureOnlyPropertySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/SignatureOnlyPropertySymbol.cs index fee6bf4bcadeb..0c2297b9ce522 100644 --- a/src/Compilers/CSharp/Portable/Symbols/SignatureOnlyPropertySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/SignatureOnlyPropertySymbol.cs @@ -85,6 +85,8 @@ public SignatureOnlyPropertySymbol( public override bool IsExtern { get { throw ExceptionUtilities.Unreachable; } } + internal override bool IsRequired => throw ExceptionUtilities.Unreachable; + internal override ObsoleteAttributeData ObsoleteAttributeData { get { throw ExceptionUtilities.Unreachable; } } public override AssemblySymbol ContainingAssembly { get { throw ExceptionUtilities.Unreachable; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/FieldSymbolWithAttributesAndModifiers.cs b/src/Compilers/CSharp/Portable/Symbols/Source/FieldSymbolWithAttributesAndModifiers.cs index 14e6819f33646..7c950d271e97a 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/FieldSymbolWithAttributesAndModifiers.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/FieldSymbolWithAttributesAndModifiers.cs @@ -159,7 +159,7 @@ internal sealed override ObsoleteAttributeData ObsoleteAttributeData } } - internal override void DecodeWellKnownAttribute(ref DecodeWellKnownAttributeArguments arguments) + protected override void DecodeWellKnownAttributeImpl(ref DecodeWellKnownAttributeArguments arguments) { Debug.Assert((object)arguments.AttributeSyntaxOpt != null); var diagnostics = (BindingDiagnosticBag)arguments.Diagnostics; @@ -204,7 +204,14 @@ internal override void DecodeWellKnownAttribute(ref DecodeWellKnownAttributeArgu MarshalAsAttributeDecoder.Decode(ref arguments, AttributeTargets.Field, MessageProvider.Instance); } else if (ReportExplicitUseOfReservedAttributes(in arguments, - ReservedAttributes.DynamicAttribute | ReservedAttributes.IsReadOnlyAttribute | ReservedAttributes.IsUnmanagedAttribute | ReservedAttributes.IsByRefLikeAttribute | ReservedAttributes.TupleElementNamesAttribute | ReservedAttributes.NullableAttribute | ReservedAttributes.NativeIntegerAttribute)) + ReservedAttributes.DynamicAttribute + | ReservedAttributes.IsReadOnlyAttribute + | ReservedAttributes.IsUnmanagedAttribute + | ReservedAttributes.IsByRefLikeAttribute + | ReservedAttributes.TupleElementNamesAttribute + | ReservedAttributes.NullableAttribute + | ReservedAttributes.NativeIntegerAttribute + | ReservedAttributes.RequiredMemberAttribute)) { } else if (attribute.IsTargetAttribute(this, AttributeDescription.DateTimeConstantAttribute)) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/ModifierUtils.cs b/src/Compilers/CSharp/Portable/Symbols/Source/ModifierUtils.cs index 871d971984913..ae56b7d0e6655 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/ModifierUtils.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/ModifierUtils.cs @@ -100,12 +100,13 @@ internal static DeclarationModifiers CheckModifiers( modifierErrors = true; } - if ((result & DeclarationModifiers.PrivateProtected) != 0) - { - modifierErrors |= !Binder.CheckFeatureAvailability(errorLocation.SourceTree, MessageID.IDS_FeaturePrivateProtected, diagnostics, errorLocation); - } + modifierErrors |= checkFeature(DeclarationModifiers.PrivateProtected, MessageID.IDS_FeaturePrivateProtected) + | checkFeature(DeclarationModifiers.Required, MessageID.IDS_FeatureRequiredMembers); return result; + + bool checkFeature(DeclarationModifiers modifier, MessageID featureID) + => ((result & modifier) != 0) && !Binder.CheckFeatureAvailability(errorLocation.SourceTree, featureID, diagnostics, errorLocation); } private static void ReportPartialError(Location errorLocation, BindingDiagnosticBag diagnostics, SyntaxTokenList? modifierTokens) @@ -301,6 +302,8 @@ internal static string ConvertSingleModifierToSyntaxText(DeclarationModifiers mo return SyntaxFacts.GetText(SyntaxKind.AsyncKeyword); case DeclarationModifiers.Ref: return SyntaxFacts.GetText(SyntaxKind.RefKeyword); + case DeclarationModifiers.Required: + return SyntaxFacts.GetText(SyntaxKind.RequiredKeyword); default: throw ExceptionUtilities.UnexpectedValue(modifier); } @@ -348,6 +351,8 @@ private static DeclarationModifiers ToDeclarationModifier(SyntaxKind kind) return DeclarationModifiers.Volatile; case SyntaxKind.RefKeyword: return DeclarationModifiers.Ref; + case SyntaxKind.RequiredKeyword: + return DeclarationModifiers.Required; default: throw ExceptionUtilities.UnexpectedValue(kind); } @@ -437,6 +442,21 @@ internal static CSDiagnosticInfo CheckAccessibility(DeclarationModifiers modifie } } + if ((modifiers & DeclarationModifiers.Required) != 0) + { + switch (symbol) + { + case FieldSymbol or PropertySymbol when symbol.DeclaredAccessibility < symbol.ContainingType.DeclaredAccessibility: + case PropertySymbol { SetMethod.DeclaredAccessibility: var accessibility } when accessibility < symbol.ContainingType.DeclaredAccessibility: + // Required member '{0}' cannot be less visible or have a setter less visible than the containing type '{1}'. + return new CSDiagnosticInfo(ErrorCode.ERR_RequiredMemberCannotBeLessVisibleThanContainingType, symbol, symbol.ContainingType); + case PropertySymbol { SetMethod: null }: + case FieldSymbol when (modifiers & DeclarationModifiers.ReadOnly) != 0: + // Required member '{0}' must be settable. + return new CSDiagnosticInfo(ErrorCode.ERR_RequiredMemberMustBeSettable, symbol); + } + } + return null; } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceAssemblySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceAssemblySymbol.cs index edddf9d51e120..3380a2b8eef1b 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceAssemblySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceAssemblySymbol.cs @@ -2326,7 +2326,7 @@ AttributeLocation IAttributeTargetSymbol.AllowedAttributeLocations } } - internal override void DecodeWellKnownAttribute(ref DecodeWellKnownAttributeArguments arguments) + protected override void DecodeWellKnownAttributeImpl(ref DecodeWellKnownAttributeArguments arguments) { DecodeWellKnownAttribute(ref arguments, arguments.Index, isFromNetModule: false); } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceComplexParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceComplexParameterSymbol.cs index 4055fcadafe8a..599940a2ada43 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceComplexParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceComplexParameterSymbol.cs @@ -665,7 +665,7 @@ internal override (CSharpAttributeData?, BoundAttribute?) EarlyDecodeWellKnownAt } #nullable disable - internal override void DecodeWellKnownAttribute(ref DecodeWellKnownAttributeArguments arguments) + protected override void DecodeWellKnownAttributeImpl(ref DecodeWellKnownAttributeArguments arguments) { Debug.Assert((object)arguments.AttributeSyntaxOpt != null); diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbolBase.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbolBase.cs index 1c35bb314b9a9..69f6da87c60a0 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbolBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceConstructorSymbolBase.cs @@ -6,7 +6,9 @@ using System.Collections.Immutable; using System.Diagnostics; +using Microsoft.CodeAnalysis.CSharp.Emit; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Text; using Roslyn.Utilities; @@ -246,5 +248,46 @@ internal sealed override int CalculateLocalSyntaxOffset(int position, SyntaxTree protected abstract CSharpSyntaxNode GetInitializer(); protected abstract bool IsWithinExpressionOrBlockBody(int position, out int offset); + +#nullable enable + protected sealed override bool HasSetsRequiredMembersImpl + => GetEarlyDecodedWellKnownAttributeData()?.HasSetsRequiredMembersAttribute == true; + + internal sealed override (CSharpAttributeData?, BoundAttribute?) EarlyDecodeWellKnownAttribute(ref EarlyDecodeWellKnownAttributeArguments arguments) + { + if (arguments.SymbolPart == AttributeLocation.None) + { + if (CSharpAttributeData.IsTargetEarlyAttribute(arguments.AttributeType, arguments.AttributeSyntax, AttributeDescription.SetsRequiredMembersAttribute)) + { + var earlyData = arguments.GetOrCreateData(); + earlyData.HasSetsRequiredMembersAttribute = true; + + if (ContainingType.IsWellKnownSetsRequiredMembersAttribute()) + { + // Avoid a binding cycle for this scenario. + return (null, null); + } + + var (attributeData, boundAttribute) = arguments.Binder.GetAttribute(arguments.AttributeSyntax, arguments.AttributeType, beforeAttributePartBound: null, afterAttributePartBound: null, out bool hasAnyDiagnostics); + + if (!hasAnyDiagnostics) + { + return (attributeData, boundAttribute); + } + else + { + return (null, null); + } + } + } + + return base.EarlyDecodeWellKnownAttribute(ref arguments); + } + + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + { + base.AddSynthesizedAttributes(moduleBuilder, ref attributes); + AddRequiredMembersMarkerAttributes(ref attributes, this); + } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceDelegateMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceDelegateMethodSymbol.cs index 529f8083b2a18..4aab753f54d9f 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceDelegateMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceDelegateMethodSymbol.cs @@ -239,6 +239,8 @@ internal override LexicalSortKey GetLexicalSortKey() // so we will keep them the same. return new LexicalSortKey(this.syntaxReferenceOpt.GetLocation(), this.DeclaringCompilation); } + + protected override bool HasSetsRequiredMembersImpl => false; } private sealed class InvokeMethod : SourceDelegateMethodSymbol diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventSymbol.cs index b783563433e81..0e885bce17ba4 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventSymbol.cs @@ -285,7 +285,7 @@ internal override ObsoleteAttributeData? ObsoleteAttributeData } } - internal sealed override void DecodeWellKnownAttribute(ref DecodeWellKnownAttributeArguments arguments) + protected sealed override void DecodeWellKnownAttributeImpl(ref DecodeWellKnownAttributeArguments arguments) { var attribute = arguments.Attribute; Debug.Assert(!attribute.HasErrors); diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceFieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceFieldSymbol.cs index 5bc11d3088b82..5178324229998 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceFieldSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceFieldSymbol.cs @@ -110,7 +110,7 @@ public override NamedTypeSymbol ContainingType } } - internal sealed override void DecodeWellKnownAttribute(ref DecodeWellKnownAttributeArguments arguments) + protected sealed override void DecodeWellKnownAttributeImpl(ref DecodeWellKnownAttributeArguments arguments) { Debug.Assert((object)arguments.AttributeSyntaxOpt != null); Debug.Assert(arguments.Diagnostics is BindingDiagnosticBag); @@ -126,7 +126,7 @@ internal sealed override void DecodeWellKnownAttribute(ref DecodeWellKnownAttrib } else { - base.DecodeWellKnownAttribute(ref arguments); + base.DecodeWellKnownAttributeImpl(ref arguments); } } @@ -154,6 +154,8 @@ internal sealed override bool HasRuntimeSpecialName return this.Name == WellKnownMemberNames.EnumBackingFieldName; } } + + internal override bool IsRequired => (Modifiers & DeclarationModifiers.Required) != 0; } internal abstract class SourceFieldSymbolWithSyntaxReference : SourceFieldSymbol diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs index 79c9a05a2183c..1cc6f1f986183 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol.cs @@ -29,7 +29,7 @@ private struct Flags { // We current pack everything into one 32-bit int; layout is given below. // - // | |vvv|zzzz|f|d|yy|wwwwww| + // | |ss|vvv|zzzz|f|d|yy|wwwwww| // // w = special type. 6 bits. // y = IsManagedType. 2 bits. @@ -37,6 +37,7 @@ private struct Flags // f = FlattenedMembersIsSorted. 1 bit. // z = TypeKind. 4 bits. // v = NullableContext. 3 bits. + // s = DeclaredRequiredMembers. 2 bits private int _flags; private const int SpecialTypeOffset = 0; @@ -57,6 +58,9 @@ private struct Flags private const int NullableContextOffset = TypeKindOffset + TypeKindSize; private const int NullableContextSize = 3; + private const int HasDeclaredRequiredMembersOffset = NullableContextOffset + NullableContextSize; + private const int HasDeclaredRequiredMembersSize = 2; + private const int SpecialTypeMask = (1 << SpecialTypeSize) - 1; private const int ManagedKindMask = (1 << ManagedKindSize) - 1; private const int TypeKindMask = (1 << TypeKindSize) - 1; @@ -65,6 +69,8 @@ private struct Flags private const int FieldDefinitionsNotedBit = 1 << FieldDefinitionsNotedOffset; private const int FlattenedMembersIsSortedBit = 1 << FlattenedMembersIsSortedOffset; + private const int HasDeclaredMembersBit = (1 << HasDeclaredRequiredMembersOffset); + private const int HasDeclaredMembersBitSet = (1 << (HasDeclaredRequiredMembersOffset + 1)); public SpecialType SpecialType { @@ -140,6 +146,25 @@ public bool SetNullableContext(byte? value) { return ThreadSafeFlagOperations.Set(ref _flags, (((int)value.ToNullableContextFlags() & NullableContextMask) << NullableContextOffset)); } + + public bool TryGetHasDeclaredRequiredMembers(out bool value) + { + if ((_flags & (HasDeclaredMembersBitSet)) != 0) + { + value = (_flags & HasDeclaredMembersBit) != 0; + return true; + } + else + { + value = false; + return false; + } + } + + public bool SetHasDeclaredRequiredMembers(bool value) + { + return ThreadSafeFlagOperations.Set(ref _flags, HasDeclaredMembersBitSet | (value ? HasDeclaredMembersBit : 0)); + } } private static readonly ObjectPool> s_duplicateRecordMemberSignatureDictionary = @@ -450,14 +475,26 @@ internal static void ReportReservedTypeName(string? name, CSharpCompilation comp return; } - if (name == SyntaxFacts.GetText(SyntaxKind.RecordKeyword) && compilation.LanguageVersion >= MessageID.IDS_FeatureRecords.RequiredVersion()) + if (reportIfContextual(SyntaxKind.RecordKeyword, MessageID.IDS_FeatureRecords, ErrorCode.WRN_RecordNamedDisallowed) + || reportIfContextual(SyntaxKind.RequiredKeyword, MessageID.IDS_FeatureRequiredMembers, ErrorCode.ERR_RequiredNameDisallowed)) { - diagnostics.Add(ErrorCode.WRN_RecordNamedDisallowed, location); + return; } else if (IsReservedTypeName(name)) { diagnostics.Add(ErrorCode.WRN_LowerCaseTypeName, location, name); } + + bool reportIfContextual(SyntaxKind contextualKind, MessageID featureId, ErrorCode error) + { + if (name == SyntaxFacts.GetText(contextualKind) && compilation.LanguageVersion >= featureId.RequiredVersion()) + { + diagnostics.Add(error, location); + return true; + } + + return false; + } } #endregion @@ -561,6 +598,7 @@ internal override void ForceComplete(SourceLocation? locationOpt, CancellationTo } break; + case CompletionPart.MembersCompletedChecksStarted: case CompletionPart.MembersCompleted: { ImmutableArray members = this.GetMembersUnordered(); @@ -594,12 +632,22 @@ internal override void ForceComplete(SourceLocation? locationOpt, CancellationTo } EnsureFieldDefinitionsNoted(); + cancellationToken.ThrowIfCancellationRequested(); - // We've completed all members, so we're ready for the PointedAtManagedTypeChecks; - // proceed to the next iteration. - state.NotePartComplete(CompletionPart.MembersCompleted); - break; + if (state.NotePartComplete(CompletionPart.MembersCompletedChecksStarted)) + { + var diagnostics = BindingDiagnosticBag.GetInstance(); + AfterMembersCompletedChecks(diagnostics); + AddDeclarationDiagnostics(diagnostics); + + // We've completed all members, so we're ready for the PointedAtManagedTypeChecks; + // proceed to the next iteration. + var thisThreadCompleted = state.NotePartComplete(CompletionPart.MembersCompleted); + Debug.Assert(thisThreadCompleted); + diagnostics.Free(); + } } + break; case CompletionPart.None: return; @@ -1290,6 +1338,21 @@ private void CheckMemberNameDistinctFromType(Symbol member, BindingDiagnosticBag } } + internal override bool HasDeclaredRequiredMembers + { + get + { + if (_flags.TryGetHasDeclaredRequiredMembers(out bool hasDeclaredMembers)) + { + return hasDeclaredMembers; + } + + hasDeclaredMembers = declaration.Declarations.Any(static decl => decl.HasRequiredMembers); + _flags.SetHasDeclaredRequiredMembers(hasDeclaredMembers); + return hasDeclaredMembers; + } + } + internal override ImmutableArray GetMembersUnordered() { var result = _lazyMembersFlattened; @@ -1608,6 +1671,7 @@ protected void AfterMembersChecks(BindingDiagnosticBag diagnostics) CheckSequentialOnPartialType(diagnostics); CheckForProtectedInStaticClass(diagnostics); CheckForUnmatchedOperators(diagnostics); + CheckForRequiredMemberAttribute(diagnostics); var location = Locations[0]; var compilation = DeclaringCompilation; @@ -1691,6 +1755,10 @@ static bool needsTupleElementNamesAttribute(TypeSymbol type) } } + protected virtual void AfterMembersCompletedChecks(BindingDiagnosticBag diagnostics) + { + } + private void CheckMemberNamesDistinctFromType(BindingDiagnosticBag diagnostics) { foreach (var member in GetMembersAndInitializers().NonTypeMembers) @@ -2373,6 +2441,40 @@ private void CheckForEqualityAndGetHashCode(BindingDiagnosticBag diagnostics) } } + private void CheckForRequiredMemberAttribute(BindingDiagnosticBag diagnostics) + { + if (HasDeclaredRequiredMembers) + { + // Ensure that an error is reported if the required constructor isn't present. + _ = Binder.GetWellKnownTypeMember(DeclaringCompilation, WellKnownMember.System_Runtime_CompilerServices_RequiredMemberAttribute__ctor, diagnostics, Locations[0]); + } + + if (HasAnyRequiredMembers) + { + _ = Binder.GetWellKnownTypeMember(DeclaringCompilation, WellKnownMember.System_Runtime_CompilerServices_CompilerFeatureRequiredAttribute__ctor, diagnostics, Locations[0]); + + if (this.IsRecord) + { + // Copy constructors need to emit SetsRequiredMembers on the ctor + _ = Binder.GetWellKnownTypeMember(DeclaringCompilation, WellKnownMember.System_Diagnostics_CodeAnalysis_SetsRequiredMembersAttribute__ctor, diagnostics, Locations[0]); + } + } + + if (BaseTypeNoUseSiteDiagnostics is (not SourceMemberContainerTypeSymbol) and { HasRequiredMembersError: true }) + { + foreach (var member in GetMembersUnordered()) + { + if (member is not MethodSymbol method || !method.ShouldCheckRequiredMembers()) + { + continue; + } + + // The required members list for the base type '{0}' is malformed and cannot be interpreted. To use this constructor, apply the 'SetsRequiredMembers' attribute. + diagnostics.Add(ErrorCode.ERR_RequiredMembersBaseTypeInvalid, method.Locations[0], BaseTypeNoUseSiteDiagnostics); + } + } + } + private bool TypeOverridesObjectMethod(string name) { foreach (var method in this.GetMembers(name).OfType()) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol_ImplementationChecks.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol_ImplementationChecks.cs index 8c4711244344b..59d299c5b24fd 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol_ImplementationChecks.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberContainerSymbol_ImplementationChecks.cs @@ -712,6 +712,12 @@ private void CheckNewModifier(Symbol symbol, bool isNew, BindingDiagnosticBag di AddHidingAbstractDiagnostic(symbol, symbolLocation, hiddenMember, diagnostics, ref unused); + if (hiddenMember.IsRequired()) + { + // Required member '{0}' cannot be hidden by '{1}'. + diagnostics.Add(ErrorCode.ERR_RequiredMemberCannotBeHidden, symbolLocation, hiddenMember, symbol); + } + return; } } @@ -900,6 +906,11 @@ void checkSingleOverriddenMember(Symbol overridingMember, Symbol overriddenMembe // it is ok to override with no tuple names, for compatibility with C# 6, but otherwise names should match diagnostics.Add(ErrorCode.ERR_CantChangeTupleNamesOnOverride, overridingMemberLocation, overridingMember, overriddenMember); } + else if (overriddenMember is PropertySymbol { IsRequired: true } && overridingMember is PropertySymbol { IsRequired: false }) + { + // '{0}' must be required because it overrides required member '{1}' + diagnostics.Add(ErrorCode.ERR_OverrideMustHaveRequired, overridingMemberLocation, overridingMember, overriddenMember); + } else { // As in dev11, we don't compare obsoleteness to the immediately-overridden member, @@ -1410,6 +1421,13 @@ private static void CheckNonOverrideMember( diagnosticAdded = true; } + if (hiddenMember.IsRequired()) + { + // Required member '{0}' cannot be hidden by '{1}'. + diagnostics.Add(ErrorCode.ERR_RequiredMemberCannotBeHidden, hidingMemberLocation, hiddenMember, hidingMember); + diagnosticAdded = true; + } + if (diagnosticAdded) { break; diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs index 14f2e44a90c84..49acec15bccbe 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberFieldSymbol.cs @@ -114,6 +114,14 @@ internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, r AddSynthesizedAttribute(ref attributes, compilation.SynthesizeDecimalConstantAttribute(value.DecimalValue)); } } + + // Synthesize RequiredMemberAttribute if this field is required + if (IsRequired) + { + AddSynthesizedAttribute( + ref attributes, + this.DeclaringCompilation.TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_RequiredMemberAttribute__ctor)); + } } public override Symbol AssociatedSymbol @@ -149,7 +157,8 @@ internal static DeclarationModifiers MakeModifiers(NamedTypeSymbol containingTyp DeclarationModifiers.Volatile | DeclarationModifiers.Fixed | DeclarationModifiers.Unsafe | - DeclarationModifiers.Abstract; // filtered out later + DeclarationModifiers.Abstract | + DeclarationModifiers.Required; // Some of these are filtered out later, when illegal, for better error messages. var errorLocation = new SourceLocation(firstIdentifier); DeclarationModifiers result = ModifierUtils.MakeAndCheckNontypeMemberModifiers( @@ -188,7 +197,13 @@ internal static DeclarationModifiers MakeModifiers(NamedTypeSymbol containingTyp diagnostics.Add(ErrorCode.ERR_BadMemberFlag, errorLocation, SyntaxFacts.GetText(SyntaxKind.VolatileKeyword)); } - result &= ~(DeclarationModifiers.Static | DeclarationModifiers.ReadOnly | DeclarationModifiers.Const | DeclarationModifiers.Volatile); + if ((result & DeclarationModifiers.Required) != 0) + { + // The modifier 'required' is not valid for this item + diagnostics.Add(ErrorCode.ERR_BadMemberFlag, errorLocation, SyntaxFacts.GetText(SyntaxKind.RequiredKeyword)); + } + + result &= ~(DeclarationModifiers.Static | DeclarationModifiers.ReadOnly | DeclarationModifiers.Const | DeclarationModifiers.Volatile | DeclarationModifiers.Required); Debug.Assert((result & ~(DeclarationModifiers.AccessibilityMask | DeclarationModifiers.Fixed | DeclarationModifiers.Unsafe | DeclarationModifiers.New)) == 0); } @@ -218,10 +233,24 @@ internal static DeclarationModifiers MakeModifiers(NamedTypeSymbol containingTyp diagnostics.Add(ErrorCode.ERR_BadMemberFlag, errorLocation, SyntaxFacts.GetText(SyntaxKind.UnsafeKeyword)); } + if ((result & DeclarationModifiers.Required) != 0) + { + // The modifier 'required' is not valid for this item + diagnostics.Add(ErrorCode.ERR_BadMemberFlag, errorLocation, SyntaxFacts.GetText(SyntaxKind.RequiredKeyword)); + result &= ~DeclarationModifiers.Required; + } + result |= DeclarationModifiers.Static; // "constants are considered static members" } else { + if ((result & DeclarationModifiers.Static) != 0 && (result & DeclarationModifiers.Required) != 0) + { + // The modifier 'required' is not valid for this item + diagnostics.Add(ErrorCode.ERR_BadMemberFlag, errorLocation, SyntaxFacts.GetText(SyntaxKind.RequiredKeyword)); + result &= ~DeclarationModifiers.Required; + } + // NOTE: always cascading on a const, so suppress. // NOTE: we're being a bit sneaky here - we're using the containingType rather than this symbol // to determine whether or not unsafe is allowed. Since this symbol and the containing type are diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbol.cs index 276e745c4547e..127b3aecc35dc 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbol.cs @@ -5,6 +5,7 @@ using System.Collections.Immutable; using System.Linq; using Microsoft.CodeAnalysis.CSharp.Syntax; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Symbols { @@ -78,5 +79,7 @@ internal void ReportAsyncParameterErrors(BindingDiagnosticBag diagnostics, Locat static Location getLocation(ParameterSymbol parameter, Location location) => parameter.Locations.FirstOrDefault() ?? location; } + + protected override bool HasSetsRequiredMembersImpl => throw ExceptionUtilities.Unreachable; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs index ae7179d9ef187..257918705685d 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs @@ -318,7 +318,7 @@ public override ImmutableArray GetReturnTypeAttributes() } #nullable enable - internal sealed override (CSharpAttributeData?, BoundAttribute?) EarlyDecodeWellKnownAttribute(ref EarlyDecodeWellKnownAttributeArguments arguments) + internal override (CSharpAttributeData?, BoundAttribute?) EarlyDecodeWellKnownAttribute(ref EarlyDecodeWellKnownAttributeArguments arguments) { Debug.Assert(arguments.SymbolPart == AttributeLocation.None || arguments.SymbolPart == AttributeLocation.Return); @@ -466,7 +466,7 @@ internal sealed override ImmutableArray GetAppliedConditionalSymbols() return data != null ? data.ConditionalSymbols : ImmutableArray.Empty; } - internal sealed override void DecodeWellKnownAttribute(ref DecodeWellKnownAttributeArguments arguments) + protected sealed override void DecodeWellKnownAttributeImpl(ref DecodeWellKnownAttributeArguments arguments) { Debug.Assert(!arguments.Attribute.HasErrors); Debug.Assert(arguments.SymbolPart == AttributeLocation.None || arguments.SymbolPart == AttributeLocation.Return); diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceModuleSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceModuleSymbol.cs index 283ee801f565f..d075530f97e93 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceModuleSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceModuleSymbol.cs @@ -498,7 +498,7 @@ private ModuleWellKnownAttributeData GetDecodedWellKnownAttributeData() return (ModuleWellKnownAttributeData)attributesBag.DecodedWellKnownAttributeData; } - internal override void DecodeWellKnownAttribute(ref DecodeWellKnownAttributeArguments arguments) + protected override void DecodeWellKnownAttributeImpl(ref DecodeWellKnownAttributeArguments arguments) { Debug.Assert((object)arguments.AttributeSyntaxOpt != null); diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs index 530209c782d40..7b0b8baf70e3e 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceNamedTypeSymbol.cs @@ -1042,7 +1042,7 @@ internal override ObsoleteAttributeData ObsoleteAttributeData } } - internal sealed override void DecodeWellKnownAttribute(ref DecodeWellKnownAttributeArguments arguments) + protected sealed override void DecodeWellKnownAttributeImpl(ref DecodeWellKnownAttributeArguments arguments) { Debug.Assert((object)arguments.AttributeSyntaxOpt != null); var diagnostics = (BindingDiagnosticBag)arguments.Diagnostics; @@ -1110,7 +1110,16 @@ internal sealed override void DecodeWellKnownAttribute(ref DecodeWellKnownAttrib diagnostics.Add(ErrorCode.ERR_CantUseRequiredAttribute, arguments.AttributeSyntaxOpt.Name.Location); } else if (ReportExplicitUseOfReservedAttributes(in arguments, - ReservedAttributes.DynamicAttribute | ReservedAttributes.IsReadOnlyAttribute | ReservedAttributes.IsUnmanagedAttribute | ReservedAttributes.IsByRefLikeAttribute | ReservedAttributes.TupleElementNamesAttribute | ReservedAttributes.NullableAttribute | ReservedAttributes.NullableContextAttribute | ReservedAttributes.NativeIntegerAttribute | ReservedAttributes.CaseSensitiveExtensionAttribute)) + ReservedAttributes.DynamicAttribute + | ReservedAttributes.IsReadOnlyAttribute + | ReservedAttributes.IsUnmanagedAttribute + | ReservedAttributes.IsByRefLikeAttribute + | ReservedAttributes.TupleElementNamesAttribute + | ReservedAttributes.NullableAttribute + | ReservedAttributes.NullableContextAttribute + | ReservedAttributes.NativeIntegerAttribute + | ReservedAttributes.CaseSensitiveExtensionAttribute + | ReservedAttributes.RequiredMemberAttribute)) { } else if (attribute.IsTargetAttribute(this, AttributeDescription.SecurityCriticalAttribute) @@ -1548,17 +1557,24 @@ internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, r var obsoleteData = ObsoleteAttributeData; Debug.Assert(obsoleteData != ObsoleteAttributeData.Uninitialized, "getting synthesized attributes before attributes are decoded"); - // If user specified an Obsolete attribute, we cannot emit ours. - // NB: we do not check the kind of deprecation. - // we will not emit Obsolete even if Deprecated or Experimental was used. - // we do not want to get into a scenario where different kinds of deprecation are combined together. - // - if (obsoleteData == null && !this.IsRestrictedType(ignoreSpanLikeTypes: true)) + if (!this.IsRestrictedType(ignoreSpanLikeTypes: true)) { - AddSynthesizedAttribute(ref attributes, compilation.TrySynthesizeAttribute(WellKnownMember.System_ObsoleteAttribute__ctor, - ImmutableArray.Create( - new TypedConstant(compilation.GetSpecialType(SpecialType.System_String), TypedConstantKind.Primitive, PEModule.ByRefLikeMarker), // message - new TypedConstant(compilation.GetSpecialType(SpecialType.System_Boolean), TypedConstantKind.Primitive, true)), // error=true + // If user specified an Obsolete attribute, we cannot emit ours. + // NB: we do not check the kind of deprecation. + // we will not emit Obsolete even if Deprecated or Experimental was used. + // we do not want to get into a scenario where different kinds of deprecation are combined together. + // + if (obsoleteData == null) + { + AddSynthesizedAttribute(ref attributes, compilation.TrySynthesizeAttribute(WellKnownMember.System_ObsoleteAttribute__ctor, + ImmutableArray.Create( + new TypedConstant(compilation.GetSpecialType(SpecialType.System_String), TypedConstantKind.Primitive, PEModule.ByRefLikeMarker), // message + new TypedConstant(compilation.GetSpecialType(SpecialType.System_Boolean), TypedConstantKind.Primitive, true)), // error=true + isOptionalUse: true)); + } + + AddSynthesizedAttribute(ref attributes, compilation.TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_CompilerFeatureRequiredAttribute__ctor, + ImmutableArray.Create(new TypedConstant(compilation.GetSpecialType(SpecialType.System_String), TypedConstantKind.Primitive, nameof(CompilerFeatureRequiredFeatures.RefStructs))), isOptionalUse: true)); } } @@ -1583,6 +1599,13 @@ internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, r AddSynthesizedAttribute(ref attributes, this.DeclaringCompilation.TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_CompilerGeneratedAttribute__ctor)); } + + if (HasDeclaredRequiredMembers) + { + AddSynthesizedAttribute( + ref attributes, + compilation.TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_RequiredMemberAttribute__ctor)); + } } #endregion @@ -1615,5 +1638,42 @@ internal bool IsSimpleProgram return this.declaration.Declarations.Any(d => d.IsSimpleProgram); } } + + protected override void AfterMembersCompletedChecks(BindingDiagnosticBag diagnostics) + { + base.AfterMembersCompletedChecks(diagnostics); + + // We need to give warnings if Obsolete is applied to any required members and there are constructors where a user would be forced to set that member, + // unless: + // 1. We're in an obsolete context ourselves, or + // 2. All constructors of this type are obsolete or attributed with SetsRequiredMembersAttribute + // We don't warn for obsolete required members from base types, as the user either has a warning that they're depending on an obsolete constructor/type + // already, or the original author ignored this warning. + + // Obsolete states should have already been calculated by this point in the pipeline. + Debug.Assert(ObsoleteKind != ObsoleteAttributeKind.Uninitialized); + Debug.Assert(GetMembers().All(m => m.ObsoleteKind != ObsoleteAttributeKind.Uninitialized)); + + if (ObsoleteKind != ObsoleteAttributeKind.None + || GetMembers().All(m => m is not MethodSymbol { MethodKind: MethodKind.Constructor, ObsoleteKind: ObsoleteAttributeKind.None } method + || !method.ShouldCheckRequiredMembers())) + { + return; + } + + foreach (var member in GetMembers()) + { + if (!member.IsRequired()) + { + continue; + } + + if (member.ObsoleteKind != ObsoleteAttributeKind.None) + { + // Required member '{0}' should not be attributed with 'ObsoleteAttribute' unless the containing type is obsolete or all constructors are obsolete. + diagnostics.Add(ErrorCode.WRN_ObsoleteMembersShouldNotBeRequired, member.Locations[0], member); + } + } + } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs index 443c8d2e3496a..3f21d758fda75 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs @@ -292,6 +292,11 @@ private static DeclarationModifiers MakeModifiers( if (!isInterface) { allowedModifiers |= DeclarationModifiers.Override; + + if (!isIndexer) + { + allowedModifiers |= DeclarationModifiers.Required; + } } else { @@ -352,6 +357,13 @@ private static DeclarationModifiers MakeModifiers( mods |= DeclarationModifiers.Indexer; } + if ((mods & DeclarationModifiers.Static) != 0 && (mods & DeclarationModifiers.Required) != 0) + { + // The modifier 'required' is not valid for this item + diagnostics.Add(ErrorCode.ERR_BadMemberFlag, location, SyntaxFacts.GetText(SyntaxKind.RequiredKeyword)); + mods &= ~DeclarationModifiers.Required; + } + return mods; } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs index 99e6173021d3c..d136fe32d4007 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs @@ -89,6 +89,7 @@ protected SourcePropertySymbolBase( { Debug.Assert(!isExpressionBodied || !isAutoProperty); Debug.Assert(!isExpressionBodied || !hasInitializer); + Debug.Assert((modifiers & DeclarationModifiers.Required) == 0 || this is SourcePropertySymbol); _syntaxRef = syntax.GetReference(); Location = location; @@ -518,6 +519,8 @@ public override bool IsVirtual get { return (_modifiers & DeclarationModifiers.Virtual) != 0; } } + internal sealed override bool IsRequired => (_modifiers & DeclarationModifiers.Required) != 0; + internal bool IsNew { get { return (_modifiers & DeclarationModifiers.New) != 0; } @@ -674,6 +677,12 @@ internal override void AfterAddingTypeMembersChecks(ConversionsBase conversions, CheckInitializer(IsAutoProperty, ContainingType.IsInterface, IsStatic, Location, diagnostics); } + if (RefKind != RefKind.None && IsRequired) + { + // Ref returning properties cannot be required. + diagnostics.Add(ErrorCode.ERR_RefReturningPropertiesCannotBeRequired, Location); + } + if (IsAutoPropertyWithGetAccessor) { Debug.Assert(GetMethod is object); @@ -1150,6 +1159,13 @@ internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, r { AddSynthesizedAttribute(ref attributes, moduleBuilder.SynthesizeIsReadOnlyAttribute(this)); } + + if (IsRequired) + { + AddSynthesizedAttribute( + ref attributes, + compilation.TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_RequiredMemberAttribute__ctor)); + } } internal sealed override bool IsDirectlyExcludedFromCodeCoverage => @@ -1229,7 +1245,7 @@ internal override ObsoleteAttributeData ObsoleteAttributeData } } - internal override void DecodeWellKnownAttribute(ref DecodeWellKnownAttributeArguments arguments) + protected override void DecodeWellKnownAttributeImpl(ref DecodeWellKnownAttributeArguments arguments) { Debug.Assert(arguments.AttributeSyntaxOpt != null); @@ -1263,7 +1279,14 @@ internal override void DecodeWellKnownAttribute(ref DecodeWellKnownAttributeArgu diagnostics.Add(ErrorCode.ERR_ExplicitDynamicAttr, arguments.AttributeSyntaxOpt.Location); } else if (ReportExplicitUseOfReservedAttributes(in arguments, - ReservedAttributes.DynamicAttribute | ReservedAttributes.IsReadOnlyAttribute | ReservedAttributes.IsUnmanagedAttribute | ReservedAttributes.IsByRefLikeAttribute | ReservedAttributes.TupleElementNamesAttribute | ReservedAttributes.NullableAttribute | ReservedAttributes.NativeIntegerAttribute)) + ReservedAttributes.DynamicAttribute + | ReservedAttributes.IsReadOnlyAttribute + | ReservedAttributes.IsUnmanagedAttribute + | ReservedAttributes.IsByRefLikeAttribute + | ReservedAttributes.TupleElementNamesAttribute + | ReservedAttributes.NullableAttribute + | ReservedAttributes.NativeIntegerAttribute + | ReservedAttributes.RequiredMemberAttribute)) { } else if (attribute.IsTargetAttribute(this, AttributeDescription.DisallowNullAttribute)) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceTypeParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceTypeParameterSymbol.cs index 224192292262b..0d63479a00d05 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceTypeParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceTypeParameterSymbol.cs @@ -418,7 +418,7 @@ internal byte GetSynthesizedNullableAttributeValue() return NullableAnnotationExtensions.ObliviousAttributeValue; } - internal sealed override void DecodeWellKnownAttribute(ref DecodeWellKnownAttributeArguments arguments) + protected sealed override void DecodeWellKnownAttributeImpl(ref DecodeWellKnownAttributeArguments arguments) { Debug.Assert((object)arguments.AttributeSyntaxOpt != null); Debug.Assert(arguments.Diagnostics is BindingDiagnosticBag); @@ -427,13 +427,9 @@ internal sealed override void DecodeWellKnownAttribute(ref DecodeWellKnownAttrib Debug.Assert(!attribute.HasErrors); Debug.Assert(arguments.SymbolPart == AttributeLocation.None); - if (attribute.IsTargetAttribute(this, AttributeDescription.NullableAttribute)) - { - // NullableAttribute should not be set explicitly. - ((BindingDiagnosticBag)arguments.Diagnostics).Add(ErrorCode.ERR_ExplicitNullableAttribute, arguments.AttributeSyntaxOpt.Location); - } + ReportExplicitUseOfReservedAttributes(in arguments, ReservedAttributes.NullableAttribute); - base.DecodeWellKnownAttribute(ref arguments); + base.DecodeWellKnownAttributeImpl(ref arguments); } protected bool? CalculateReferenceTypeConstraintIsNullable(TypeParameterConstraintKind constraints) diff --git a/src/Compilers/CSharp/Portable/Symbols/SubstitutedNamedTypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/SubstitutedNamedTypeSymbol.cs index d3a312282f8c0..5f62fd41389e3 100644 --- a/src/Compilers/CSharp/Portable/Symbols/SubstitutedNamedTypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/SubstitutedNamedTypeSymbol.cs @@ -204,6 +204,8 @@ public sealed override ImmutableArray GetTypeMembers(string nam return OriginalDefinition.GetTypeMembers(name, arity).SelectAsArray((t, self) => t.AsMember(self), this); } + internal sealed override bool HasDeclaredRequiredMembers => OriginalDefinition.HasDeclaredRequiredMembers; + public sealed override ImmutableArray GetMembers() { var builder = ArrayBuilder.GetInstance(); diff --git a/src/Compilers/CSharp/Portable/Symbols/Symbol.cs b/src/Compilers/CSharp/Portable/Symbols/Symbol.cs index 4e92167e21cfc..4f1a4d2545fea 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Symbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Symbol.cs @@ -939,16 +939,10 @@ protected AssemblySymbol PrimaryDependency } /// - /// Return error code that has highest priority while calculating use site error for this symbol. + /// Returns true if the error code is the highest priority while calculating use site error for this symbol. /// Supposed to be ErrorCode, but it causes inconsistent accessibility error. /// - protected virtual int HighestPriorityUseSiteError - { - get - { - return int.MaxValue; - } - } + protected virtual bool IsHighestPriorityUseSiteErrorCode(int code) => true; /// /// Indicates that this symbol uses metadata that cannot be supported by the language. @@ -987,7 +981,7 @@ internal bool MergeUseSiteDiagnostics(ref DiagnosticInfo result, DiagnosticInfo return false; } - if (info.Severity == DiagnosticSeverity.Error && (info.Code == HighestPriorityUseSiteError || HighestPriorityUseSiteError == Int32.MaxValue)) + if (info.Severity == DiagnosticSeverity.Error && IsHighestPriorityUseSiteErrorCode(info.Code)) { // this error is final, no other error can override it: result = info; @@ -1122,7 +1116,6 @@ internal bool DeriveUseSiteInfoFromParameters(ref UseSiteInfo re return false; } - [Flags] internal enum AllowedRequiredModifierType { @@ -1384,6 +1377,7 @@ internal enum ReservedAttributes NullablePublicOnlyAttribute = 1 << 8, NativeIntegerAttribute = 1 << 9, CaseSensitiveExtensionAttribute = 1 << 10, + RequiredMemberAttribute = 1 << 11, } internal bool ReportExplicitUseOfReservedAttributes(in DecodeWellKnownAttributeArguments arguments, ReservedAttributes reserved) @@ -1438,6 +1432,12 @@ internal bool ReportExplicitUseOfReservedAttributes(in DecodeWellKnownAttributeA // ExtensionAttribute should not be set explicitly. diagnostics.Add(ErrorCode.ERR_ExplicitExtension, arguments.AttributeSyntaxOpt.Location); } + else if ((reserved & ReservedAttributes.RequiredMemberAttribute) != 0 && + attribute.IsTargetAttribute(this, AttributeDescription.RequiredMemberAttribute)) + { + // Do not use 'System.Runtime.CompilerServices.RequiredMemberAttribute'. Use the 'required' keyword on required fields and properties instead. + diagnostics.Add(ErrorCode.ERR_ExplicitRequiredMember, arguments.AttributeSyntaxOpt.Location); + } else { return false; diff --git a/src/Compilers/CSharp/Portable/Symbols/SymbolExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/SymbolExtensions.cs index 7a27991ad8521..7392e9e350ffd 100644 --- a/src/Compilers/CSharp/Portable/Symbols/SymbolExtensions.cs +++ b/src/Compilers/CSharp/Portable/Symbols/SymbolExtensions.cs @@ -839,5 +839,10 @@ internal static bool HasAsyncMethodBuilderAttribute(this Symbol symbol, [NotNull builderArgument = null; return false; } + + internal static bool IsRequired(this Symbol symbol) => symbol is FieldSymbol { IsRequired: true } or PropertySymbol { IsRequired: true }; + + internal static bool ShouldCheckRequiredMembers(this MethodSymbol method) + => method is { MethodKind: MethodKind.Constructor, HasSetsRequiredMembers: false }; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Symbol_Attributes.cs b/src/Compilers/CSharp/Portable/Symbols/Symbol_Attributes.cs index 472f6df41f379..153bdb1e09f92 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Symbol_Attributes.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Symbol_Attributes.cs @@ -209,7 +209,23 @@ internal static bool EarlyDecodeDeprecatedOrExperimentalOrObsoleteAttribute( /// this (base) method. /// /// - internal virtual void DecodeWellKnownAttribute(ref DecodeWellKnownAttributeArguments arguments) +#nullable enable + protected void DecodeWellKnownAttribute(ref DecodeWellKnownAttributeArguments arguments) + { + Debug.Assert(arguments.Diagnostics.DiagnosticBag is not null); + Debug.Assert(arguments.AttributeSyntaxOpt is not null); + if (arguments.Attribute.IsTargetAttribute(this, AttributeDescription.CompilerFeatureRequiredAttribute)) + { + // Do not use '{FullName}'. This is reserved for compiler usage. + arguments.Diagnostics.DiagnosticBag.Add(ErrorCode.ERR_ExplicitReservedAttr, arguments.AttributeSyntaxOpt.Location, AttributeDescription.CompilerFeatureRequiredAttribute.FullName); + return; + } + + DecodeWellKnownAttributeImpl(ref arguments); + } +#nullable disable + + protected virtual void DecodeWellKnownAttributeImpl(ref DecodeWellKnownAttributeArguments arguments) { } @@ -654,7 +670,7 @@ private void EarlyDecodeWellKnownAttributeTypes(ImmutableArray } /// - /// This method validates attribute usage for each bound attribute and calls + /// This method validates attribute usage for each bound attribute and calls /// on attributes with valid attribute usage. /// This method is called by the binder when it is finished binding a set of attributes on the symbol so that /// the symbol can extract data from the attribute arguments and potentially perform validation specific to diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordCopyCtor.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordCopyCtor.cs index 511c0e79b50e0..d99de6306574b 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordCopyCtor.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/Records/SynthesizedRecordCopyCtor.cs @@ -64,6 +64,11 @@ internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, r var compilation = this.DeclaringCompilation; AddSynthesizedAttribute(ref attributes, compilation.TrySynthesizeAttribute(WellKnownMember.System_Runtime_CompilerServices_CompilerGeneratedAttribute__ctor)); Debug.Assert(WellKnownMembers.IsSynthesizedAttributeOptional(WellKnownMember.System_Runtime_CompilerServices_CompilerGeneratedAttribute__ctor)); + + if (HasSetsRequiredMembersImpl) + { + AddSynthesizedAttribute(ref attributes, compilation.TrySynthesizeAttribute(WellKnownMember.System_Diagnostics_CodeAnalysis_SetsRequiredMembersAttribute__ctor)); + } } internal static MethodSymbol? FindCopyConstructor(NamedTypeSymbol containingType, NamedTypeSymbol within, ref CompoundUseSiteInfo useSiteInfo) @@ -127,5 +132,9 @@ internal static bool HasCopyConstructorSignature(MethodSymbol member) method.Parameters[0].Type.Equals(containingType, TypeCompareKind.AllIgnoreOptions) && method.Parameters[0].RefKind == RefKind.None; } + + protected sealed override bool HasSetsRequiredMembersImpl + // If the record type has a required members error, then it does have required members of some kind, we emit the SetsRequiredMembers attribute. + => ContainingType.HasAnyRequiredMembers || ContainingType.HasRequiredMembersError; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedBackingFieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedBackingFieldSymbol.cs index 6001d8b361c51..6aa06f16efe02 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedBackingFieldSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedBackingFieldSymbol.cs @@ -63,7 +63,7 @@ internal override TypeWithAnnotations GetFieldType(ConsList fieldsB internal override bool HasPointerType => _property.HasPointerType; - internal sealed override void DecodeWellKnownAttribute(ref DecodeWellKnownAttributeArguments arguments) + protected sealed override void DecodeWellKnownAttributeImpl(ref DecodeWellKnownAttributeArguments arguments) { Debug.Assert((object)arguments.AttributeSyntaxOpt != null); Debug.Assert(arguments.Diagnostics is BindingDiagnosticBag); @@ -79,7 +79,7 @@ internal sealed override void DecodeWellKnownAttribute(ref DecodeWellKnownAttrib } else { - base.DecodeWellKnownAttribute(ref arguments); + base.DecodeWellKnownAttributeImpl(ref arguments); } } @@ -151,5 +151,7 @@ private void CheckForFieldTargetedAttribute(BindingDiagnosticBag diagnostics) } } } + + internal override bool IsRequired => false; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedContainer.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedContainer.cs index 2d1937a69877a..dd677239e1078 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedContainer.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedContainer.cs @@ -104,6 +104,8 @@ internal override ImmutableArray TypeArgumentsWithAnnotatio internal sealed override bool IsInterpolatedStringHandlerType => false; + internal sealed override bool HasDeclaredRequiredMembers => false; + public override ImmutableArray GetMembers() { Symbol constructor = this.Constructor; diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedDelegateSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedDelegateSymbol.cs index e5c17ffc70887..b8c36fde38207 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedDelegateSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedDelegateSymbol.cs @@ -238,5 +238,7 @@ public override bool IsExtern { get { return false; } } + + protected sealed override bool HasSetsRequiredMembersImpl => throw ExceptionUtilities.Unreachable; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEmbeddedAttributeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEmbeddedAttributeSymbol.cs index 91fdaa6613923..a03039d83a6ca 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEmbeddedAttributeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEmbeddedAttributeSymbol.cs @@ -67,6 +67,8 @@ public SynthesizedEmbeddedAttributeSymbolBase( public override IEnumerable MemberNames => Constructors.Select(m => m.Name); + internal override bool HasDeclaredRequiredMembers => false; + public override Accessibility DeclaredAccessibility => Accessibility.Internal; public override TypeKind TypeKind => TypeKind.Class; diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEntryPointSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEntryPointSymbol.cs index 4ec47baf02f08..70fb7b7600ebd 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEntryPointSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedEntryPointSymbol.cs @@ -307,6 +307,8 @@ private static BoundCall CreateParameterlessCall(CSharpSyntaxNode syntax, BoundE { WasCompilerGenerated = true }; } + protected sealed override bool HasSetsRequiredMembersImpl => throw ExceptionUtilities.Unreachable; + /// A synthesized entrypoint that forwards all calls to an async Main Method internal sealed class AsyncForwardEntryPoint : SynthesizedEntryPointSymbol { diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedFieldSymbolBase.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedFieldSymbolBase.cs index 43bd4c4a94592..09a9100ffbd56 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedFieldSymbolBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedFieldSymbolBase.cs @@ -192,5 +192,7 @@ public override bool IsImplicitlyDeclared { get { return true; } } + + internal override bool IsRequired => false; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedGlobalMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedGlobalMethodSymbol.cs index 4b66d9d66ebfe..893bb85ea8ed1 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedGlobalMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedGlobalMethodSymbol.cs @@ -335,5 +335,7 @@ internal override int CalculateLocalSyntaxOffset(int localPosition, SyntaxTree l } internal sealed override bool IsNullableAnalysisEnabled() => false; + + protected sealed override bool HasSetsRequiredMembersImpl => throw ExceptionUtilities.Unreachable; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedImplementationMethod.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedImplementationMethod.cs index 23fe785515aa3..eeecc9bf23d90 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedImplementationMethod.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedImplementationMethod.cs @@ -265,5 +265,7 @@ internal override ImmutableArray GetAppliedConditionalSymbols() { return ImmutableArray.Empty; } + + protected sealed override bool HasSetsRequiredMembersImpl => throw ExceptionUtilities.Unreachable; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInstanceConstructor.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInstanceConstructor.cs index 0c27009d34a61..04181bb9f7947 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInstanceConstructor.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInstanceConstructor.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; +using Microsoft.CodeAnalysis.CSharp.Emit; using Microsoft.CodeAnalysis.PooledObjects; using Roslyn.Utilities; @@ -316,5 +317,12 @@ internal virtual void GenerateMethodBodyStatements(SyntheticBoundNodeFactory fac // overridden in a derived class to add extra statements to the body of the generated constructor } + protected override bool HasSetsRequiredMembersImpl => false; + + internal override void AddSynthesizedAttributes(PEModuleBuilder moduleBuilder, ref ArrayBuilder attributes) + { + base.AddSynthesizedAttributes(moduleBuilder, ref attributes); + AddRequiredMembersMarkerAttributes(ref attributes, this); + } } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInteractiveInitializerMethod.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInteractiveInitializerMethod.cs index c6f7bc3fbe8dc..69baa906a9872 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInteractiveInitializerMethod.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedInteractiveInitializerMethod.cs @@ -275,5 +275,7 @@ private static void CalculateReturnType( : compilation.GetTypeByReflectionType(submissionReturnTypeOpt, diagnostics); returnType = taskT.Construct(resultType); } + + protected sealed override bool HasSetsRequiredMembersImpl => throw ExceptionUtilities.Unreachable; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedIntrinsicOperatorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedIntrinsicOperatorSymbol.cs index 047fcb25a065d..6c41f283a2cd1 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedIntrinsicOperatorSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedIntrinsicOperatorSymbol.cs @@ -423,6 +423,8 @@ internal override int CalculateLocalSyntaxOffset(int localPosition, SyntaxTree l internal sealed override bool IsNullableAnalysisEnabled() => false; + protected sealed override bool HasSetsRequiredMembersImpl => throw ExceptionUtilities.Unreachable; + public override bool Equals(Symbol obj, TypeCompareKind compareKind) { if (obj == (object)this) diff --git a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedStaticConstructor.cs b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedStaticConstructor.cs index 1166c2218d61a..948bd9f64071d 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedStaticConstructor.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Synthesized/SynthesizedStaticConstructor.cs @@ -428,5 +428,7 @@ private bool CalculateShouldEmit(ImmutableArray boundInitializ return false; } + + protected sealed override bool HasSetsRequiredMembersImpl => throw ExceptionUtilities.Unreachable; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs index 0c0dc519d3b39..68b5f61f69aaf 100644 --- a/src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs @@ -512,23 +512,18 @@ internal Microsoft.Cci.PrimitiveTypeCode PrimitiveTypeCode #region Use-Site Diagnostics /// - /// Return error code that has highest priority while calculating use site error for this symbol. + /// Returns true if the error code is highest priority while calculating use site error for this symbol. /// - protected override int HighestPriorityUseSiteError - { - get - { - return (int)ErrorCode.ERR_BogusType; - } - } + protected sealed override bool IsHighestPriorityUseSiteErrorCode(int code) + => code is (int)ErrorCode.ERR_UnsupportedCompilerFeature or (int)ErrorCode.ERR_BogusType; - public sealed override bool HasUnsupportedMetadata + public override bool HasUnsupportedMetadata { get { DiagnosticInfo info = GetUseSiteInfo().DiagnosticInfo; - return (object)info != null && info.Code == (int)ErrorCode.ERR_BogusType; + return (object)info != null && info.Code is (int)ErrorCode.ERR_UnsupportedCompilerFeature or (int)ErrorCode.ERR_BogusType; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs index a822a91c2ef2b..61a6905d0fb6e 100644 --- a/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs +++ b/src/Compilers/CSharp/Portable/Symbols/TypeSymbolExtensions.cs @@ -2035,6 +2035,12 @@ private static bool IsWellKnownCompilerServicesTopLevelType(this TypeSymbol type internal static bool IsCompilerServicesTopLevelType(this TypeSymbol typeSymbol) => typeSymbol.ContainingType is null && IsContainedInNamespace(typeSymbol, "System", "Runtime", "CompilerServices"); + internal static bool IsWellKnownSetsRequiredMembersAttribute(this TypeSymbol type) + => type.Name == "SetsRequiredMembersAttribute" && type.IsWellKnownDiagnosticsCodeAnalysisTopLevelType(); + + private static bool IsWellKnownDiagnosticsCodeAnalysisTopLevelType(this TypeSymbol typeSymbol) + => typeSymbol.ContainingType is null && IsContainedInNamespace(typeSymbol, "System", "Diagnostics", "CodeAnalysis"); + private static bool IsContainedInNamespace(this TypeSymbol typeSymbol, string outerNS, string midNS, string innerNS) { var innerNamespace = typeSymbol.ContainingNamespace; diff --git a/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedFieldSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedFieldSymbol.cs index d623fd5268c5e..166c0264211ce 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedFieldSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedFieldSymbol.cs @@ -204,5 +204,7 @@ public override bool IsStatic return _underlyingField.IsStatic; } } + + internal sealed override bool IsRequired => _underlyingField.IsRequired; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedMethodSymbol.cs index 19343a9b2d55b..06f156ca7690b 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedMethodSymbol.cs @@ -358,5 +358,7 @@ internal override bool GenerateDebugInfo internal override bool IsDeclaredReadOnly => UnderlyingMethod.IsDeclaredReadOnly; internal override bool IsInitOnly => UnderlyingMethod.IsInitOnly; + + protected sealed override bool HasSetsRequiredMembersImpl => UnderlyingMethod.HasSetsRequiredMembers; } } diff --git a/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedPropertySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedPropertySymbol.cs index e0ee3f5cdbbb8..e9f62600a2a8a 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedPropertySymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Wrapped/WrappedPropertySymbol.cs @@ -161,6 +161,8 @@ public override bool IsExtern } } + internal sealed override bool IsRequired => _underlyingProperty.IsRequired; + internal override ObsoleteAttributeData ObsoleteAttributeData { get diff --git a/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs b/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs index 0679b8e72e600..61b11e8c5304b 100644 --- a/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs +++ b/src/Compilers/CSharp/Portable/Syntax/SyntaxKind.cs @@ -404,6 +404,8 @@ public enum SyntaxKind : ushort ManagedKeyword = 8445, /// Represents . UnmanagedKeyword = 8446, + /// Represents . + RequiredKeyword = 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 3d3d4df8ba185..15f25ee859988 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.RequiredKeyword; i++) { 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.RequiredKeyword: return true; default: return false; @@ -1310,6 +1311,8 @@ public static SyntaxKind GetContextualKeywordKind(string text) return SyntaxKind.ManagedKeyword; case "unmanaged": return SyntaxKind.UnmanagedKeyword; + case "required": + return SyntaxKind.RequiredKeyword; default: return SyntaxKind.None; } @@ -1749,6 +1752,8 @@ public static string GetText(SyntaxKind kind) return "managed"; case SyntaxKind.UnmanagedKeyword: return "unmanaged"; + case SyntaxKind.RequiredKeyword: + return "required"; 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 54d74682e7041..dce3c6b332446 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -292,6 +292,11 @@ __arglist nemůže mít argument předávaný pomocí in nebo out + + This constructor must add 'SetsRequiredMembers' because it chains to a constructor that has that attribute. + This constructor must add 'SetsRequiredMembers' because it chains to a constructor that has that attribute. + + The operator '{0}' requires a matching non-checked version of the operator to also be defined The operator '{0}' requires a matching non-checked version of the operator to also be defined @@ -447,6 +452,11 @@ Přístupové objekty {0} a {1} by měly být buď oba jenom pro inicializaci, nebo ani jeden. + + Do not use 'System.Runtime.CompilerServices.RequiredMemberAttribute'. Use the 'required' keyword on required fields and properties instead. + Do not use 'System.Runtime.CompilerServices.RequiredMemberAttribute'. Use the 'required' keyword on required fields and properties instead. + + The given expression cannot be used in a fixed statement Daný výraz nelze použít v příkazu fixed. @@ -497,6 +507,11 @@ Strom výrazů nesmí obsahovat operátor řazené kolekce členů == nebo !=. + + An expression tree may not contain UTF-8 string conversion or literal. + An expression tree may not contain UTF-8 string conversion or literal. + + An expression tree may not contain a with-expression. Strom výrazů nesmí obsahovat výraz with. @@ -902,6 +917,11 @@ Omezení new() nejde používat s omezením unmanaged. + + '{2}' cannot satisfy the 'new()' constraint on parameter '{1}' in the generic type or or method '{0}' because '{2}' has required members. + '{2}' cannot satisfy the 'new()' constraint on parameter '{1}' in the generic type or or method '{0}' because '{2}' has required members. + + Newlines inside a non-verbatim interpolated string are not supported in C# {0}. Please use language version {1} or greater. V jazyce C# {0} se nové řádky uvnitř neliterálního interpolovaného řetězce nepodporují. Použijte prosím verzi jazyka {1} nebo novější. @@ -1032,6 +1052,11 @@ Metoda {0} určuje omezení default pro parametr typu {1}, ale odpovídající parametr typu {2} přepsané nebo explicitně implementované metody {3} není omezený na typ odkazu nebo hodnoty. + + '{0}' must be required because it overrides required member '{1}' + '{0}' must be required because it overrides required member '{1}' + + Method '{0}' specifies a 'class' constraint for type parameter '{1}', but corresponding type parameter '{2}' of overridden or explicitly implemented method '{3}' is not a reference type. Metoda {0} určuje omezení class pro parametr typu {1}, ale odpovídající parametr typu {2} přepsané nebo explicitně implementované metody {3} není odkazový typ. @@ -1167,11 +1192,56 @@ Levá strana přiřazení odkazu musí být lokální proměnná nebo parametr odkazu. + + Ref returning properties cannot be required. + Ref returning properties cannot be required. + + Relational patterns may not be used for a floating-point NaN. Relační vzory se nedají použít pro hodnotu Není číslo s plovoucí desetinnou čárkou. + + Required member '{0}' cannot be hidden by '{1}'. + Required member '{0}' cannot be hidden by '{1}'. + + + + Required member '{0}' cannot be less visible or have a setter less visible than the containing type '{1}'. + Required member '{0}' cannot be less visible or have a setter less visible than the containing type '{1}'. + + + + Required member '{0}' must be set in the object initializer or attribute constructor. + Required member '{0}' must be set in the object initializer or attribute constructor. + + + + Required member '{0}' must be settable. + Required member '{0}' must be settable. + + + + The required members list for the base type '{0}' is malformed and cannot be interpreted. To use this constructor, apply the 'SetsRequiredMembers' attribute. + The required members list for the base type '{0}' is malformed and cannot be interpreted. To use this constructor, apply the 'SetsRequiredMembers' attribute. + + + + The required members list for '{0}' is malformed and cannot be interpreted. + The required members list for '{0}' is malformed and cannot be interpreted. + + + + Required member '{0}' must be assigned a value, it cannot use a nested member or collection initializer. + Required member '{0}' must be assigned a value, it cannot use a nested member or collection initializer. + + + + Types and aliases cannot be named 'required'. + Types and aliases cannot be named 'required'. + + '{0}': Target runtime doesn't support covariant types in overrides. Type must be '{2}' to match overridden member '{1}' {0}: Cílový modul runtime nepodporuje v přepisech kovariantní typy. Typ musí být {2}, aby odpovídal přepsanému členu {1}. @@ -1377,6 +1447,11 @@ {0} má atribut UnmanagedCallersOnly a nedá se převést na typ delegáta. Pro tuto metodu získejte ukazatel na funkci. UnmanagedCallersOnly is not localizable. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. + + List patterns may not be used for a value of type '{0}'. Vzory seznamů se nedají používat pro hodnotu typu {0}. @@ -1537,6 +1612,11 @@ relaxed shift operator + + required members + required members + + sealed ToString in record zapečetěný ToString v záznamu @@ -1707,6 +1787,16 @@ Převádí se skupina metod na nedelegující typ. + + Required member '{0}' should not be attributed with 'ObsoleteAttribute' unless the containing type is obsolete or all constructors are obsolete. + Required member '{0}' should not be attributed with 'ObsoleteAttribute' unless the containing type is obsolete or all constructors are obsolete. + + + + Members attributed with 'ObsoleteAttribute' should not be required unless the containing type is obsolete or all constructors are obsolete. + Members attributed with 'ObsoleteAttribute' should not be required unless the containing type is obsolete or all constructors are obsolete. + + Parameter '{0}' must have a non-null value when exiting because parameter '{1}' is non-null. Parametr {0} musí mít při ukončení hodnotu jinou než null, protože parametr {1} není null. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index ce8ae626726a1..0e45a9d46b803 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -292,6 +292,11 @@ "__arglist" darf kein über "in" oder "out" übergebenes Argument umfassen. + + This constructor must add 'SetsRequiredMembers' because it chains to a constructor that has that attribute. + This constructor must add 'SetsRequiredMembers' because it chains to a constructor that has that attribute. + + The operator '{0}' requires a matching non-checked version of the operator to also be defined The operator '{0}' requires a matching non-checked version of the operator to also be defined @@ -447,6 +452,11 @@ "init-only" muss entweder für beide oder für keine der Zugriffsmethoden "{0}" und "{1}" festgelegt sein. + + Do not use 'System.Runtime.CompilerServices.RequiredMemberAttribute'. Use the 'required' keyword on required fields and properties instead. + Do not use 'System.Runtime.CompilerServices.RequiredMemberAttribute'. Use the 'required' keyword on required fields and properties instead. + + The given expression cannot be used in a fixed statement Der angegebene Ausdruck kann nicht in einer fixed-Anweisung verwendet werden. @@ -497,6 +507,11 @@ Eine Ausdrucksbaumstruktur darf keinen ==- oder !=-Tupeloperator enthalten. + + An expression tree may not contain UTF-8 string conversion or literal. + An expression tree may not contain UTF-8 string conversion or literal. + + An expression tree may not contain a with-expression. Eine Ausdrucksbaumstruktur darf keinen with-Ausdruck enthalten. @@ -902,6 +917,11 @@ Die new()-Einschränkung kann nicht mit der unmanaged-Einschränkung verwendet werden. + + '{2}' cannot satisfy the 'new()' constraint on parameter '{1}' in the generic type or or method '{0}' because '{2}' has required members. + '{2}' cannot satisfy the 'new()' constraint on parameter '{1}' in the generic type or or method '{0}' because '{2}' has required members. + + Newlines inside a non-verbatim interpolated string are not supported in C# {0}. Please use language version {1} or greater. Zeilenumbrüche innerhalb einer nicht ausführlichen interpolierten Zeichenfolge werden in C#-{0} nicht unterstützt. Verwenden Sie die Sprachversion {1} oder höher. @@ -1032,6 +1052,11 @@ Die Methode "{0}" gibt eine default-Einschränkung für den Typparameter "{1}" an, aber der zugehörige Typparameter "{2}" der überschriebenen oder explizit implementierten Methode "{3}" ist auf einen Verweistyp oder einen Werttyp beschränkt. + + '{0}' must be required because it overrides required member '{1}' + '{0}' must be required because it overrides required member '{1}' + + Method '{0}' specifies a 'class' constraint for type parameter '{1}', but corresponding type parameter '{2}' of overridden or explicitly implemented method '{3}' is not a reference type. Die Methode "{0}" gibt eine class-Einschränkung für den Typparameter "{1}" an, aber der zugehörige Typparameter "{2}" der außer Kraft gesetzten oder explizit implementierten Methode "{3}" ist kein Verweistyp. @@ -1167,11 +1192,56 @@ Die linke Seite einer ref-Zuweisung muss ein lokaler Verweis oder ein Parameter sein. + + Ref returning properties cannot be required. + Ref returning properties cannot be required. + + Relational patterns may not be used for a floating-point NaN. Relationale Muster dürfen nicht für Gleitkomma-NaNs verwendet werden. + + Required member '{0}' cannot be hidden by '{1}'. + Required member '{0}' cannot be hidden by '{1}'. + + + + Required member '{0}' cannot be less visible or have a setter less visible than the containing type '{1}'. + Required member '{0}' cannot be less visible or have a setter less visible than the containing type '{1}'. + + + + Required member '{0}' must be set in the object initializer or attribute constructor. + Required member '{0}' must be set in the object initializer or attribute constructor. + + + + Required member '{0}' must be settable. + Required member '{0}' must be settable. + + + + The required members list for the base type '{0}' is malformed and cannot be interpreted. To use this constructor, apply the 'SetsRequiredMembers' attribute. + The required members list for the base type '{0}' is malformed and cannot be interpreted. To use this constructor, apply the 'SetsRequiredMembers' attribute. + + + + The required members list for '{0}' is malformed and cannot be interpreted. + The required members list for '{0}' is malformed and cannot be interpreted. + + + + Required member '{0}' must be assigned a value, it cannot use a nested member or collection initializer. + Required member '{0}' must be assigned a value, it cannot use a nested member or collection initializer. + + + + Types and aliases cannot be named 'required'. + Types and aliases cannot be named 'required'. + + '{0}': Target runtime doesn't support covariant types in overrides. Type must be '{2}' to match overridden member '{1}' {0}: Die Zielruntime unterstützt keine covarianten Typen in Überschreibungen. Der Typ muss "{2}" sein, um dem überschriebenen Member "{1}" zu entsprechen. @@ -1377,6 +1447,11 @@ "{0}" ist mit dem Attribut "UnmanagedCallersOnly" versehen und kann nicht in einen Delegattyp konvertiert werden. Rufen Sie einen Funktionszeiger auf diese Methode ab. UnmanagedCallersOnly is not localizable. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. + + List patterns may not be used for a value of type '{0}'. Listenmuster dürfen nicht für einen Wert vom Typ „{0}“ verwendet werden. @@ -1537,6 +1612,11 @@ relaxed shift operator + + required members + required members + + sealed ToString in record versiegelte "ToString" im Datensatz @@ -1707,6 +1787,16 @@ Die Methodengruppe wird in einen Nichtdelegattyp konvertiert. + + Required member '{0}' should not be attributed with 'ObsoleteAttribute' unless the containing type is obsolete or all constructors are obsolete. + Required member '{0}' should not be attributed with 'ObsoleteAttribute' unless the containing type is obsolete or all constructors are obsolete. + + + + Members attributed with 'ObsoleteAttribute' should not be required unless the containing type is obsolete or all constructors are obsolete. + Members attributed with 'ObsoleteAttribute' should not be required unless the containing type is obsolete or all constructors are obsolete. + + Parameter '{0}' must have a non-null value when exiting because parameter '{1}' is non-null. Der Parameter "{0}" muss beim Beenden einen Wert ungleich NULL aufweisen, weil Parameter "{1}" nicht NULL ist. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index ec1b16f021635..4aaa165d2d341 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -292,6 +292,11 @@ __arglist no puede tener un argumento que se ha pasado con "in" o "out" + + This constructor must add 'SetsRequiredMembers' because it chains to a constructor that has that attribute. + This constructor must add 'SetsRequiredMembers' because it chains to a constructor that has that attribute. + + The operator '{0}' requires a matching non-checked version of the operator to also be defined The operator '{0}' requires a matching non-checked version of the operator to also be defined @@ -447,6 +452,11 @@ Los descriptores de acceso "{0}" y "{1}" deben ser los dos solo de inicialización o ninguno de ellos + + Do not use 'System.Runtime.CompilerServices.RequiredMemberAttribute'. Use the 'required' keyword on required fields and properties instead. + Do not use 'System.Runtime.CompilerServices.RequiredMemberAttribute'. Use the 'required' keyword on required fields and properties instead. + + The given expression cannot be used in a fixed statement La expresión proporcionada no se puede utilizar en una instrucción "fixed" @@ -497,6 +507,11 @@ Un árbol de expresión no puede contener un operador de tupla == o !=. + + An expression tree may not contain UTF-8 string conversion or literal. + An expression tree may not contain UTF-8 string conversion or literal. + + An expression tree may not contain a with-expression. Un árbol de expresión no puede contener una expresión with. @@ -902,6 +917,11 @@ La restricción "new()" no se puede utilizar con la restricción "unmanaged" + + '{2}' cannot satisfy the 'new()' constraint on parameter '{1}' in the generic type or or method '{0}' because '{2}' has required members. + '{2}' cannot satisfy the 'new()' constraint on parameter '{1}' in the generic type or or method '{0}' because '{2}' has required members. + + Newlines inside a non-verbatim interpolated string are not supported in C# {0}. Please use language version {1} or greater. No se admiten líneas nuevas dentro de una cadena interpolada no textual en C# {0}. Utilice la versión de idioma {1} o superior. @@ -1032,6 +1052,11 @@ El método "{0}" especifica una restricción "default" para el parámetro de tipo "{1}", pero el parámetro de tipo "{2}" correspondiente del método "{3}" invalidado o implementado explícitamente se restringe a un tipo de referencia o a un tipo de valor. + + '{0}' must be required because it overrides required member '{1}' + '{0}' must be required because it overrides required member '{1}' + + Method '{0}' specifies a 'class' constraint for type parameter '{1}', but corresponding type parameter '{2}' of overridden or explicitly implemented method '{3}' is not a reference type. El método "{0}" especifica una restricción "class" para el parámetro de tipo "{1}", pero el parámetro de tipo correspondiente "{2}" de los métodos invalidados o implementados explícitamente "{3}" no es un tipo de referencia. @@ -1167,11 +1192,56 @@ La parte izquierda de una asignación de referencias debe ser una referencia local o un parámetro. + + Ref returning properties cannot be required. + Ref returning properties cannot be required. + + Relational patterns may not be used for a floating-point NaN. No se pueden usar patrones relacionales para un valor NaN de punto flotante. + + Required member '{0}' cannot be hidden by '{1}'. + Required member '{0}' cannot be hidden by '{1}'. + + + + Required member '{0}' cannot be less visible or have a setter less visible than the containing type '{1}'. + Required member '{0}' cannot be less visible or have a setter less visible than the containing type '{1}'. + + + + Required member '{0}' must be set in the object initializer or attribute constructor. + Required member '{0}' must be set in the object initializer or attribute constructor. + + + + Required member '{0}' must be settable. + Required member '{0}' must be settable. + + + + The required members list for the base type '{0}' is malformed and cannot be interpreted. To use this constructor, apply the 'SetsRequiredMembers' attribute. + The required members list for the base type '{0}' is malformed and cannot be interpreted. To use this constructor, apply the 'SetsRequiredMembers' attribute. + + + + The required members list for '{0}' is malformed and cannot be interpreted. + The required members list for '{0}' is malformed and cannot be interpreted. + + + + Required member '{0}' must be assigned a value, it cannot use a nested member or collection initializer. + Required member '{0}' must be assigned a value, it cannot use a nested member or collection initializer. + + + + Types and aliases cannot be named 'required'. + Types and aliases cannot be named 'required'. + + '{0}': Target runtime doesn't support covariant types in overrides. Type must be '{2}' to match overridden member '{1}' "{0}": el entorno de ejecución de destino no admite los tipos de covariante en las invalidaciones. El tipo debe ser "{2}" para que coincida con el miembro "{1}" invalidado. @@ -1377,6 +1447,11 @@ ' {0} ' tiene un atributo ' UnmanagedCallersOnly ' y no se puede convertir en un tipo de delegado. Obtenga un puntero de función a este método. UnmanagedCallersOnly is not localizable. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. + + List patterns may not be used for a value of type '{0}'. No se pueden utilizar patrones de lista para un valor de tipo "{0}". @@ -1537,6 +1612,11 @@ relaxed shift operator + + required members + required members + + sealed ToString in record ToString sellado en el registro @@ -1707,6 +1787,16 @@ Convirtiendo grupo de métodos a tipo no delegado + + Required member '{0}' should not be attributed with 'ObsoleteAttribute' unless the containing type is obsolete or all constructors are obsolete. + Required member '{0}' should not be attributed with 'ObsoleteAttribute' unless the containing type is obsolete or all constructors are obsolete. + + + + Members attributed with 'ObsoleteAttribute' should not be required unless the containing type is obsolete or all constructors are obsolete. + Members attributed with 'ObsoleteAttribute' should not be required unless the containing type is obsolete or all constructors are obsolete. + + Parameter '{0}' must have a non-null value when exiting because parameter '{1}' is non-null. El parámetro "{0}" debe tener un valor que no sea NULL al salir porque el parámetro "{1}" no es NULL. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index 09530006516cc..cece1cf713d80 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -292,6 +292,11 @@ __arglist ne peut pas avoir un argument passé par 'in' ou 'out' + + This constructor must add 'SetsRequiredMembers' because it chains to a constructor that has that attribute. + This constructor must add 'SetsRequiredMembers' because it chains to a constructor that has that attribute. + + The operator '{0}' requires a matching non-checked version of the operator to also be defined The operator '{0}' requires a matching non-checked version of the operator to also be defined @@ -447,6 +452,11 @@ Les accesseurs '{0}' et '{1}' doivent tous deux être initialiseurs uniquement ou ne pas l'être + + Do not use 'System.Runtime.CompilerServices.RequiredMemberAttribute'. Use the 'required' keyword on required fields and properties instead. + Do not use 'System.Runtime.CompilerServices.RequiredMemberAttribute'. Use the 'required' keyword on required fields and properties instead. + + The given expression cannot be used in a fixed statement Impossible d'utiliser l'expression donnée dans une instruction fixed @@ -497,6 +507,11 @@ Une arborescence de l'expression ne peut pas contenir un opérateur de tuple == ou != + + An expression tree may not contain UTF-8 string conversion or literal. + An expression tree may not contain UTF-8 string conversion or literal. + + An expression tree may not contain a with-expression. Une arborescence de l'expression ne peut pas contenir d'expression with. @@ -902,6 +917,11 @@ La contrainte 'new()' ne peut pas être utilisée avec la contrainte 'unmanaged' + + '{2}' cannot satisfy the 'new()' constraint on parameter '{1}' in the generic type or or method '{0}' because '{2}' has required members. + '{2}' cannot satisfy the 'new()' constraint on parameter '{1}' in the generic type or or method '{0}' because '{2}' has required members. + + Newlines inside a non-verbatim interpolated string are not supported in C# {0}. Please use language version {1} or greater. Les nouvelles lignes à l'intérieur d'une chaîne interpolée non textuelle ne sont pas prises en charge en C# {0}. Veuillez utiliser la version linguistique {1} ou supérieure. @@ -1032,6 +1052,11 @@ La méthode '{0}' spécifie une contrainte 'default' pour le paramètre de type '{1}', mais le paramètre de type '{2}' correspondant de la méthode substituée ou explicitement implémentée '{3}' est limité à un type référence ou à un type valeur. + + '{0}' must be required because it overrides required member '{1}' + '{0}' must be required because it overrides required member '{1}' + + Method '{0}' specifies a 'class' constraint for type parameter '{1}', but corresponding type parameter '{2}' of overridden or explicitly implemented method '{3}' is not a reference type. La méthode '{0}' spécifie une contrainte 'class' pour le paramètre de type '{1}', mais le paramètre de type '{2}' correspondant de la méthode substituée ou explicitement implémentée '{3}' n'est pas un type référence. @@ -1167,11 +1192,56 @@ La partie gauche d'une assignation par référence doit être une variable locale ou un paramètre ref. + + Ref returning properties cannot be required. + Ref returning properties cannot be required. + + Relational patterns may not be used for a floating-point NaN. Les modèles relationnels ne peuvent pas être utilisés pour une valeur NaN à virgule flottante. + + Required member '{0}' cannot be hidden by '{1}'. + Required member '{0}' cannot be hidden by '{1}'. + + + + Required member '{0}' cannot be less visible or have a setter less visible than the containing type '{1}'. + Required member '{0}' cannot be less visible or have a setter less visible than the containing type '{1}'. + + + + Required member '{0}' must be set in the object initializer or attribute constructor. + Required member '{0}' must be set in the object initializer or attribute constructor. + + + + Required member '{0}' must be settable. + Required member '{0}' must be settable. + + + + The required members list for the base type '{0}' is malformed and cannot be interpreted. To use this constructor, apply the 'SetsRequiredMembers' attribute. + The required members list for the base type '{0}' is malformed and cannot be interpreted. To use this constructor, apply the 'SetsRequiredMembers' attribute. + + + + The required members list for '{0}' is malformed and cannot be interpreted. + The required members list for '{0}' is malformed and cannot be interpreted. + + + + Required member '{0}' must be assigned a value, it cannot use a nested member or collection initializer. + Required member '{0}' must be assigned a value, it cannot use a nested member or collection initializer. + + + + Types and aliases cannot be named 'required'. + Types and aliases cannot be named 'required'. + + '{0}': Target runtime doesn't support covariant types in overrides. Type must be '{2}' to match overridden member '{1}' '{0}' : le runtime cible ne prend pas en charge les types covariants dans les substitutions. Le type doit être '{2}' pour correspondre au membre substitué '{1}' @@ -1377,6 +1447,11 @@ '{0}' est attribué avec 'UnmanagedCallersOnly' et ne peut pas être converti en type délégué. Obtenez un pointeur de fonction vers cette méthode. UnmanagedCallersOnly is not localizable. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. + + List patterns may not be used for a value of type '{0}'. Les modèles de liste ne peuvent pas être utilisés pour une valeur de type '{0}'. @@ -1537,6 +1612,11 @@ relaxed shift operator + + required members + required members + + sealed ToString in record ToString scellé dans l’enregistrement @@ -1707,6 +1787,16 @@ Conversion d’un groupe de méthodes en type non-délégué + + Required member '{0}' should not be attributed with 'ObsoleteAttribute' unless the containing type is obsolete or all constructors are obsolete. + Required member '{0}' should not be attributed with 'ObsoleteAttribute' unless the containing type is obsolete or all constructors are obsolete. + + + + Members attributed with 'ObsoleteAttribute' should not be required unless the containing type is obsolete or all constructors are obsolete. + Members attributed with 'ObsoleteAttribute' should not be required unless the containing type is obsolete or all constructors are obsolete. + + Parameter '{0}' must have a non-null value when exiting because parameter '{1}' is non-null. Le paramètre '{0}' doit avoir une valeur non null au moment de la sortie, car le paramètre '{1}' a une valeur non null. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index cdc9bd83aa9fd..8f4381a1c7f98 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -292,6 +292,11 @@ __arglist non può contenere un argomento passato da 'in' o 'out' + + This constructor must add 'SetsRequiredMembers' because it chains to a constructor that has that attribute. + This constructor must add 'SetsRequiredMembers' because it chains to a constructor that has that attribute. + + The operator '{0}' requires a matching non-checked version of the operator to also be defined The operator '{0}' requires a matching non-checked version of the operator to also be defined @@ -447,6 +452,11 @@ Il tipo di sola inizializzazione può essere specificato per entrambe le funzioni di accesso '{0}' e '{1}' o per nessuna di esse + + Do not use 'System.Runtime.CompilerServices.RequiredMemberAttribute'. Use the 'required' keyword on required fields and properties instead. + Do not use 'System.Runtime.CompilerServices.RequiredMemberAttribute'. Use the 'required' keyword on required fields and properties instead. + + The given expression cannot be used in a fixed statement Non è possibile usare l'espressione specificata in un'istruzione fixed @@ -497,6 +507,11 @@ Un albero delle espressioni non può contenere un operatore == o != di tupla + + An expression tree may not contain UTF-8 string conversion or literal. + An expression tree may not contain UTF-8 string conversion or literal. + + An expression tree may not contain a with-expression. Un albero delle espressioni non può contenere un'espressione with. @@ -902,6 +917,11 @@ Non è possibile usare il vincolo 'new()' con il vincolo 'unmanaged' + + '{2}' cannot satisfy the 'new()' constraint on parameter '{1}' in the generic type or or method '{0}' because '{2}' has required members. + '{2}' cannot satisfy the 'new()' constraint on parameter '{1}' in the generic type or or method '{0}' because '{2}' has required members. + + Newlines inside a non-verbatim interpolated string are not supported in C# {0}. Please use language version {1} or greater. Nuove linee all'interno di una stringa interpolata non verbatim non sono supportate in C# {0}. Usare la versione del linguaggio {1} o le versioni successive. @@ -1032,6 +1052,11 @@ Il metodo '{0}' specifica un vincolo 'default' per il parametro di tipo '{1}', ma il parametro di tipo corrispondente '{2}' del metodo '{3}' sottoposto a override o implementato in modo esplicito è vincolato a un tipo riferimento a un tipo valore. + + '{0}' must be required because it overrides required member '{1}' + '{0}' must be required because it overrides required member '{1}' + + Method '{0}' specifies a 'class' constraint for type parameter '{1}', but corresponding type parameter '{2}' of overridden or explicitly implemented method '{3}' is not a reference type. Il metodo '{0}' specifica un vincolo 'class' per il parametro di tipo '{1}', ma il parametro di tipo corrispondente '{2}' del metodo '{3}' sottoposto a override o implementato in modo esplicito non è un tipo riferimento. @@ -1167,11 +1192,56 @@ La parte sinistra di un'assegnazione ref deve essere un parametro o una variabile locale ref. + + Ref returning properties cannot be required. + Ref returning properties cannot be required. + + Relational patterns may not be used for a floating-point NaN. Non è possibile usare i criteri relazionali per un valore NaN a virgola mobile. + + Required member '{0}' cannot be hidden by '{1}'. + Required member '{0}' cannot be hidden by '{1}'. + + + + Required member '{0}' cannot be less visible or have a setter less visible than the containing type '{1}'. + Required member '{0}' cannot be less visible or have a setter less visible than the containing type '{1}'. + + + + Required member '{0}' must be set in the object initializer or attribute constructor. + Required member '{0}' must be set in the object initializer or attribute constructor. + + + + Required member '{0}' must be settable. + Required member '{0}' must be settable. + + + + The required members list for the base type '{0}' is malformed and cannot be interpreted. To use this constructor, apply the 'SetsRequiredMembers' attribute. + The required members list for the base type '{0}' is malformed and cannot be interpreted. To use this constructor, apply the 'SetsRequiredMembers' attribute. + + + + The required members list for '{0}' is malformed and cannot be interpreted. + The required members list for '{0}' is malformed and cannot be interpreted. + + + + Required member '{0}' must be assigned a value, it cannot use a nested member or collection initializer. + Required member '{0}' must be assigned a value, it cannot use a nested member or collection initializer. + + + + Types and aliases cannot be named 'required'. + Types and aliases cannot be named 'required'. + + '{0}': Target runtime doesn't support covariant types in overrides. Type must be '{2}' to match overridden member '{1}' '{0}': il runtime di destinazione non supporta tipi covarianti negli override. Il tipo deve essere '{2}' in modo da corrispondere al membro '{1}' di cui è stato eseguito l'override @@ -1377,6 +1447,11 @@ '{0}', a cui è assegnato l'attributo 'UnmanagedCallersOnly', non può essere convertito in un tipo delegato. Ottenere un puntatore a funzione per questo metodo. UnmanagedCallersOnly is not localizable. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. + + List patterns may not be used for a value of type '{0}'. Non è possibile usare i modelli di elenco per un valore di tipo '{0}'. @@ -1537,6 +1612,11 @@ relaxed shift operator + + required members + required members + + sealed ToString in record ToString sealed nel record @@ -1707,6 +1787,16 @@ Conversione del gruppo di metodi in un tipo non delegato + + Required member '{0}' should not be attributed with 'ObsoleteAttribute' unless the containing type is obsolete or all constructors are obsolete. + Required member '{0}' should not be attributed with 'ObsoleteAttribute' unless the containing type is obsolete or all constructors are obsolete. + + + + Members attributed with 'ObsoleteAttribute' should not be required unless the containing type is obsolete or all constructors are obsolete. + Members attributed with 'ObsoleteAttribute' should not be required unless the containing type is obsolete or all constructors are obsolete. + + Parameter '{0}' must have a non-null value when exiting because parameter '{1}' is non-null. Il parametro '{0}' deve avere un valore non Null quando viene terminato perché il parametro '{1}' è non Null. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index b9b2570f68a9a..901fcd8fd3afa 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -292,6 +292,11 @@ __arglist では、'in' や 'out' で引数を渡すことができません + + This constructor must add 'SetsRequiredMembers' because it chains to a constructor that has that attribute. + This constructor must add 'SetsRequiredMembers' because it chains to a constructor that has that attribute. + + The operator '{0}' requires a matching non-checked version of the operator to also be defined The operator '{0}' requires a matching non-checked version of the operator to also be defined @@ -447,6 +452,11 @@ アクセサー '{0}' と '{1}' は、両方 init 専用か、両方そうでないかのいずれかでなければなりません + + Do not use 'System.Runtime.CompilerServices.RequiredMemberAttribute'. Use the 'required' keyword on required fields and properties instead. + Do not use 'System.Runtime.CompilerServices.RequiredMemberAttribute'. Use the 'required' keyword on required fields and properties instead. + + The given expression cannot be used in a fixed statement 指定された式を fixed ステートメントで使用することはできません @@ -497,6 +507,11 @@ 式ツリーにタプルの == または != 演算子を含めることはできません + + An expression tree may not contain UTF-8 string conversion or literal. + An expression tree may not contain UTF-8 string conversion or literal. + + An expression tree may not contain a with-expression. 式ツリーは、with 式を含むことはできません @@ -902,6 +917,11 @@ new()' 制約は 'unmanaged' 制約と一緒には使用できません + + '{2}' cannot satisfy the 'new()' constraint on parameter '{1}' in the generic type or or method '{0}' because '{2}' has required members. + '{2}' cannot satisfy the 'new()' constraint on parameter '{1}' in the generic type or or method '{0}' because '{2}' has required members. + + Newlines inside a non-verbatim interpolated string are not supported in C# {0}. Please use language version {1} or greater. 非逐語的な補間された文字列内の改行は、C# {0} ではサポートされていません。{1} またはそれ以上の言語バージョンを使用してください。 @@ -1032,6 +1052,11 @@ メソッド '{0}' は、型パラメーター '{1}' に対して 'default' 制約を指定していますが、オーバーライドされた、または明示的に実装されたメソッド '{3}' の対応する型パラメーター '{2}' は、参照型または値の型に制約されています。 + + '{0}' must be required because it overrides required member '{1}' + '{0}' must be required because it overrides required member '{1}' + + Method '{0}' specifies a 'class' constraint for type parameter '{1}', but corresponding type parameter '{2}' of overridden or explicitly implemented method '{3}' is not a reference type. メソッド '{0}' は、型パラメーター '{1}' に対して 'class' 制約を指定していますが、オーバーライドされた、または明示的に実装されたメソッド '{3}' の対応する型パラメーター '{2}' は参照型ではありません。 @@ -1167,11 +1192,56 @@ ref 代入の左辺は、ref ローカルまたはパラメーターにする必要があります。 + + Ref returning properties cannot be required. + Ref returning properties cannot be required. + + Relational patterns may not be used for a floating-point NaN. リレーショナル パターンは、浮動小数点の NaN に使用することはできません。 + + Required member '{0}' cannot be hidden by '{1}'. + Required member '{0}' cannot be hidden by '{1}'. + + + + Required member '{0}' cannot be less visible or have a setter less visible than the containing type '{1}'. + Required member '{0}' cannot be less visible or have a setter less visible than the containing type '{1}'. + + + + Required member '{0}' must be set in the object initializer or attribute constructor. + Required member '{0}' must be set in the object initializer or attribute constructor. + + + + Required member '{0}' must be settable. + Required member '{0}' must be settable. + + + + The required members list for the base type '{0}' is malformed and cannot be interpreted. To use this constructor, apply the 'SetsRequiredMembers' attribute. + The required members list for the base type '{0}' is malformed and cannot be interpreted. To use this constructor, apply the 'SetsRequiredMembers' attribute. + + + + The required members list for '{0}' is malformed and cannot be interpreted. + The required members list for '{0}' is malformed and cannot be interpreted. + + + + Required member '{0}' must be assigned a value, it cannot use a nested member or collection initializer. + Required member '{0}' must be assigned a value, it cannot use a nested member or collection initializer. + + + + Types and aliases cannot be named 'required'. + Types and aliases cannot be named 'required'. + + '{0}': Target runtime doesn't support covariant types in overrides. Type must be '{2}' to match overridden member '{1}' '{0}': ターゲットのランタイムはオーバーライドで covariant 型をサポートしていません。型は、オーバーライドされるメンバー '{1}' と一致する '{2}' にする必要があります @@ -1377,6 +1447,11 @@ '{0}' は 'UnmanagedCallersOnly' 属性が設定されているため、デリゲート型に変換できません。このメソッドへの関数ポインターを取得してください。 UnmanagedCallersOnly is not localizable. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. + + List patterns may not be used for a value of type '{0}'. リスト パターンは、'{0}' 型の値に使用されない可能性があります。 @@ -1537,6 +1612,11 @@ relaxed shift operator + + required members + required members + + sealed ToString in record レコードでシールされた ToString @@ -1707,6 +1787,16 @@ メソッド グループを非デリゲート型に変換しています + + Required member '{0}' should not be attributed with 'ObsoleteAttribute' unless the containing type is obsolete or all constructors are obsolete. + Required member '{0}' should not be attributed with 'ObsoleteAttribute' unless the containing type is obsolete or all constructors are obsolete. + + + + Members attributed with 'ObsoleteAttribute' should not be required unless the containing type is obsolete or all constructors are obsolete. + Members attributed with 'ObsoleteAttribute' should not be required unless the containing type is obsolete or all constructors are obsolete. + + Parameter '{0}' must have a non-null value when exiting because parameter '{1}' is non-null. パラメーター '{1}' が null 以外であるため、パラメーター '{0}' には、終了時に null 以外の値が含まれている必要があります。 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index b2c3ae161e9fa..b912f1bccf640 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -292,6 +292,11 @@ __arglist는 'in' 또는 'out'으로 전달되는 인수를 가질 수 없습니다. + + This constructor must add 'SetsRequiredMembers' because it chains to a constructor that has that attribute. + This constructor must add 'SetsRequiredMembers' because it chains to a constructor that has that attribute. + + The operator '{0}' requires a matching non-checked version of the operator to also be defined The operator '{0}' requires a matching non-checked version of the operator to also be defined @@ -447,6 +452,11 @@ '{0}' 및 '{1}' 접근자는 둘 다 초기값 전용이거나 둘 다 초기값 전용이 아니어야 합니다. + + Do not use 'System.Runtime.CompilerServices.RequiredMemberAttribute'. Use the 'required' keyword on required fields and properties instead. + Do not use 'System.Runtime.CompilerServices.RequiredMemberAttribute'. Use the 'required' keyword on required fields and properties instead. + + The given expression cannot be used in a fixed statement fixed 문에서는 지정된 식을 사용할 수 없습니다. @@ -497,6 +507,11 @@ 식 트리에는 튜플 == 또는 != 연산자를 사용할 수 없습니다. + + An expression tree may not contain UTF-8 string conversion or literal. + An expression tree may not contain UTF-8 string conversion or literal. + + An expression tree may not contain a with-expression. 식 트리에는 with 식이 포함될 수 없습니다. @@ -902,6 +917,11 @@ new()' 제약 조건은 'unmanaged' 제약 조건과 함께 사용할 수 없습니다. + + '{2}' cannot satisfy the 'new()' constraint on parameter '{1}' in the generic type or or method '{0}' because '{2}' has required members. + '{2}' cannot satisfy the 'new()' constraint on parameter '{1}' in the generic type or or method '{0}' because '{2}' has required members. + + Newlines inside a non-verbatim interpolated string are not supported in C# {0}. Please use language version {1} or greater. 축자가 아닌 보간된 문자열 내의 줄 바꿈은 C# {0}에서 지원되지 않습니다. {1} 이상의 언어 버전을 사용하세요. @@ -1032,6 +1052,11 @@ 메서드 '{0}'이(가) 형식 매개 변수 '{1}'의 'default' 제약 조건을 지정하지만 재정의되었거나 명시적으로 구현된 메서드 '{3}'의 해당 형식 매개 변수 '{2}'이(가) 참조 형식 또는 값 형식으로 제한됩니다. + + '{0}' must be required because it overrides required member '{1}' + '{0}' must be required because it overrides required member '{1}' + + Method '{0}' specifies a 'class' constraint for type parameter '{1}', but corresponding type parameter '{2}' of overridden or explicitly implemented method '{3}' is not a reference type. '{0}' 메서드는 형식 매개 변수 '{1}'의 'class' 제약 조건을 지정하지만 재정의되었거나 명시적으로 구현된 '{3}' 메서드의 해당 형식 매개 변수 '{2}'이(가) 참조 형식이 아닙니다. @@ -1167,11 +1192,56 @@ 참조 할당의 왼쪽은 참조 로컬 또는 매개 변수여야 합니다. + + Ref returning properties cannot be required. + Ref returning properties cannot be required. + + Relational patterns may not be used for a floating-point NaN. 부동 소수점 NaN에는 관계형 패턴을 사용할 수 없습니다. + + Required member '{0}' cannot be hidden by '{1}'. + Required member '{0}' cannot be hidden by '{1}'. + + + + Required member '{0}' cannot be less visible or have a setter less visible than the containing type '{1}'. + Required member '{0}' cannot be less visible or have a setter less visible than the containing type '{1}'. + + + + Required member '{0}' must be set in the object initializer or attribute constructor. + Required member '{0}' must be set in the object initializer or attribute constructor. + + + + Required member '{0}' must be settable. + Required member '{0}' must be settable. + + + + The required members list for the base type '{0}' is malformed and cannot be interpreted. To use this constructor, apply the 'SetsRequiredMembers' attribute. + The required members list for the base type '{0}' is malformed and cannot be interpreted. To use this constructor, apply the 'SetsRequiredMembers' attribute. + + + + The required members list for '{0}' is malformed and cannot be interpreted. + The required members list for '{0}' is malformed and cannot be interpreted. + + + + Required member '{0}' must be assigned a value, it cannot use a nested member or collection initializer. + Required member '{0}' must be assigned a value, it cannot use a nested member or collection initializer. + + + + Types and aliases cannot be named 'required'. + Types and aliases cannot be named 'required'. + + '{0}': Target runtime doesn't support covariant types in overrides. Type must be '{2}' to match overridden member '{1}' '{0}': 대상 런타임이 재정의에서 공변(covariant) 형식을 지원하지 않습니다. 재정의된 멤버 '{1}'과(와) 일치하려면 '{2}' 형식이어야 합니다. @@ -1377,6 +1447,11 @@ '{0}'에는 'UnmanagedCallersOnly' 특성이 지정되어 있으며 이 항목은 대리자 형식으로 변환할 수 없습니다. 이 메서드에 대한 함수 포인터를 가져오세요. UnmanagedCallersOnly is not localizable. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. + + List patterns may not be used for a value of type '{0}'. 목록 패턴은 '{0}' 형식 값에 사용할 수 없습니다. @@ -1537,6 +1612,11 @@ relaxed shift operator + + required members + required members + + sealed ToString in record 레코드의 봉인된 ToString @@ -1707,6 +1787,16 @@ 메소드 그룹을 비 위임 유형으로 변환 + + Required member '{0}' should not be attributed with 'ObsoleteAttribute' unless the containing type is obsolete or all constructors are obsolete. + Required member '{0}' should not be attributed with 'ObsoleteAttribute' unless the containing type is obsolete or all constructors are obsolete. + + + + Members attributed with 'ObsoleteAttribute' should not be required unless the containing type is obsolete or all constructors are obsolete. + Members attributed with 'ObsoleteAttribute' should not be required unless the containing type is obsolete or all constructors are obsolete. + + Parameter '{0}' must have a non-null value when exiting because parameter '{1}' is non-null. 매개 변수 '{1}'이(가) null이 아니므로 매개 변수 '{0}'은(는) 종료할 때 null이 아닌 값을 가져야 합니다. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index 612db1badd628..615e1651fb077 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -292,6 +292,11 @@ Element __arglist nie może mieć argumentu przekazywanego przez parametr „in” ani „out” + + This constructor must add 'SetsRequiredMembers' because it chains to a constructor that has that attribute. + This constructor must add 'SetsRequiredMembers' because it chains to a constructor that has that attribute. + + The operator '{0}' requires a matching non-checked version of the operator to also be defined The operator '{0}' requires a matching non-checked version of the operator to also be defined @@ -447,6 +452,11 @@ Tylko do inicjowania powinny być obie metody dostępu „{0}” i „{1}” albo żadna z nich + + Do not use 'System.Runtime.CompilerServices.RequiredMemberAttribute'. Use the 'required' keyword on required fields and properties instead. + Do not use 'System.Runtime.CompilerServices.RequiredMemberAttribute'. Use the 'required' keyword on required fields and properties instead. + + The given expression cannot be used in a fixed statement Podanego wyrażenia nie można użyć w instrukcji fixed @@ -497,6 +507,11 @@ Drzewo wyrażenia nie może zawierać operatora == ani != krotki. + + An expression tree may not contain UTF-8 string conversion or literal. + An expression tree may not contain UTF-8 string conversion or literal. + + An expression tree may not contain a with-expression. Drzewo wyrażeń nie może zawierać wyrażenia with. @@ -902,6 +917,11 @@ Ograniczenie „new()” nie może być używane z ograniczeniem „unmanaged” + + '{2}' cannot satisfy the 'new()' constraint on parameter '{1}' in the generic type or or method '{0}' because '{2}' has required members. + '{2}' cannot satisfy the 'new()' constraint on parameter '{1}' in the generic type or or method '{0}' because '{2}' has required members. + + Newlines inside a non-verbatim interpolated string are not supported in C# {0}. Please use language version {1} or greater. Nowe wiersze wewnątrz ciągu interpolowanego nie będącego ciągiem dosłownym nie są obsługiwane w {0} języka C#. Użyj wersji językowej {1} lub nowszej. @@ -1032,6 +1052,11 @@ Metoda „{0}” określa ograniczenie „default” dla parametru typu „{1}”, lecz odpowiadający parametr typu „{2}” przesłoniętej lub jawnie zaimplementowanej metody „{3}” jest ograniczony do typu odwołania lub typu wartości. + + '{0}' must be required because it overrides required member '{1}' + '{0}' must be required because it overrides required member '{1}' + + Method '{0}' specifies a 'class' constraint for type parameter '{1}', but corresponding type parameter '{2}' of overridden or explicitly implemented method '{3}' is not a reference type. Metoda „{0}” określa ograniczenie „class” dla parametru typu „{1}”, lecz odpowiadający parametr typu „{2}” przesłoniętej lub jawnie zaimplementowanej metody „{3}” nie jest typem referencyjnym. @@ -1167,11 +1192,56 @@ Lewa strona przypisania odwołania musi być odwołaniem lokalnym lub parametrem. + + Ref returning properties cannot be required. + Ref returning properties cannot be required. + + Relational patterns may not be used for a floating-point NaN. Wzorców relacyjnych nie można używać na potrzeby zmiennoprzecinkowej wartości NaN. + + Required member '{0}' cannot be hidden by '{1}'. + Required member '{0}' cannot be hidden by '{1}'. + + + + Required member '{0}' cannot be less visible or have a setter less visible than the containing type '{1}'. + Required member '{0}' cannot be less visible or have a setter less visible than the containing type '{1}'. + + + + Required member '{0}' must be set in the object initializer or attribute constructor. + Required member '{0}' must be set in the object initializer or attribute constructor. + + + + Required member '{0}' must be settable. + Required member '{0}' must be settable. + + + + The required members list for the base type '{0}' is malformed and cannot be interpreted. To use this constructor, apply the 'SetsRequiredMembers' attribute. + The required members list for the base type '{0}' is malformed and cannot be interpreted. To use this constructor, apply the 'SetsRequiredMembers' attribute. + + + + The required members list for '{0}' is malformed and cannot be interpreted. + The required members list for '{0}' is malformed and cannot be interpreted. + + + + Required member '{0}' must be assigned a value, it cannot use a nested member or collection initializer. + Required member '{0}' must be assigned a value, it cannot use a nested member or collection initializer. + + + + Types and aliases cannot be named 'required'. + Types and aliases cannot be named 'required'. + + '{0}': Target runtime doesn't support covariant types in overrides. Type must be '{2}' to match overridden member '{1}' „{0}”: docelowe środowisko uruchomieniowe nie obsługuje typów kowariantnych w przesłonięciach. Typem musi być „{2}”, aby zachować zgodność z przesłoniętą składową „{1}”. @@ -1377,6 +1447,11 @@ Element „{0}” ma atrybut „UnmanagedCallersOnly” i nie można go przekonwertować na typ delegowany. Uzyskaj wskaźnik funkcji do tej metody. UnmanagedCallersOnly is not localizable. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. + + List patterns may not be used for a value of type '{0}'. Wzorców list nie można używać na potrzeby wartości typu „{0}”. @@ -1537,6 +1612,11 @@ relaxed shift operator + + required members + required members + + sealed ToString in record zapieczętowany obiekt ToString w rekordzie @@ -1707,6 +1787,16 @@ Konwertowanie grupy metod na typ inny niż delegowany + + Required member '{0}' should not be attributed with 'ObsoleteAttribute' unless the containing type is obsolete or all constructors are obsolete. + Required member '{0}' should not be attributed with 'ObsoleteAttribute' unless the containing type is obsolete or all constructors are obsolete. + + + + Members attributed with 'ObsoleteAttribute' should not be required unless the containing type is obsolete or all constructors are obsolete. + Members attributed with 'ObsoleteAttribute' should not be required unless the containing type is obsolete or all constructors are obsolete. + + Parameter '{0}' must have a non-null value when exiting because parameter '{1}' is non-null. Parametr „{0}” musi mieć wartość inną niż null podczas kończenia działania, ponieważ parametr „{1}” ma wartość inną niż null. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index 7a187e14bbad4..ee2f2367ba706 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -292,6 +292,11 @@ __arglist não pode ter um argumento passado por 'in' ou 'out' + + This constructor must add 'SetsRequiredMembers' because it chains to a constructor that has that attribute. + This constructor must add 'SetsRequiredMembers' because it chains to a constructor that has that attribute. + + The operator '{0}' requires a matching non-checked version of the operator to also be defined The operator '{0}' requires a matching non-checked version of the operator to also be defined @@ -447,6 +452,11 @@ Os acessadores '{0}' e '{1}' devem ser somente de inicialização ou nenhum + + Do not use 'System.Runtime.CompilerServices.RequiredMemberAttribute'. Use the 'required' keyword on required fields and properties instead. + Do not use 'System.Runtime.CompilerServices.RequiredMemberAttribute'. Use the 'required' keyword on required fields and properties instead. + + The given expression cannot be used in a fixed statement A expressão determinada não pode ser usada em uma instrução fixed @@ -497,6 +507,11 @@ Uma árvore de expressão não pode conter um operador == ou != de tupla + + An expression tree may not contain UTF-8 string conversion or literal. + An expression tree may not contain UTF-8 string conversion or literal. + + An expression tree may not contain a with-expression. Uma árvore de expressão não pode conter uma expressão with. @@ -902,6 +917,11 @@ A restrição 'new()' não pode ser usada com a restrição 'unmanaged' + + '{2}' cannot satisfy the 'new()' constraint on parameter '{1}' in the generic type or or method '{0}' because '{2}' has required members. + '{2}' cannot satisfy the 'new()' constraint on parameter '{1}' in the generic type or or method '{0}' because '{2}' has required members. + + Newlines inside a non-verbatim interpolated string are not supported in C# {0}. Please use language version {1} or greater. Novas linhas dentro de uma cadeia de caracteres interpolada não textual não são suportadas no C# {0}. Use a versão {1} da linguagem ou superior. @@ -1032,6 +1052,11 @@ O método '{0}' especifica uma restrição 'default' para o parâmetro de tipo '{1}', mas o parâmetro de tipo correspondente '{2}' do método substituído ou implementado explicitamente '{3}' está restrito por um tipo de referência ou um tipo de valor. + + '{0}' must be required because it overrides required member '{1}' + '{0}' must be required because it overrides required member '{1}' + + Method '{0}' specifies a 'class' constraint for type parameter '{1}', but corresponding type parameter '{2}' of overridden or explicitly implemented method '{3}' is not a reference type. O método '{0}' especifica uma restrição de 'class' para o parâmetro de tipo '{1}', mas o parâmetro de tipo correspondente '{2}' do método substituído ou implementado explicitamente '{3}' não é um tipo de referência. @@ -1167,11 +1192,56 @@ O lado esquerdo da atribuição ref precisa ser um parâmetro ou local ref. + + Ref returning properties cannot be required. + Ref returning properties cannot be required. + + Relational patterns may not be used for a floating-point NaN. Os padrões relacionais não podem ser usados para um NaN de ponto flutuante. + + Required member '{0}' cannot be hidden by '{1}'. + Required member '{0}' cannot be hidden by '{1}'. + + + + Required member '{0}' cannot be less visible or have a setter less visible than the containing type '{1}'. + Required member '{0}' cannot be less visible or have a setter less visible than the containing type '{1}'. + + + + Required member '{0}' must be set in the object initializer or attribute constructor. + Required member '{0}' must be set in the object initializer or attribute constructor. + + + + Required member '{0}' must be settable. + Required member '{0}' must be settable. + + + + The required members list for the base type '{0}' is malformed and cannot be interpreted. To use this constructor, apply the 'SetsRequiredMembers' attribute. + The required members list for the base type '{0}' is malformed and cannot be interpreted. To use this constructor, apply the 'SetsRequiredMembers' attribute. + + + + The required members list for '{0}' is malformed and cannot be interpreted. + The required members list for '{0}' is malformed and cannot be interpreted. + + + + Required member '{0}' must be assigned a value, it cannot use a nested member or collection initializer. + Required member '{0}' must be assigned a value, it cannot use a nested member or collection initializer. + + + + Types and aliases cannot be named 'required'. + Types and aliases cannot be named 'required'. + + '{0}': Target runtime doesn't support covariant types in overrides. Type must be '{2}' to match overridden member '{1}' '{0}': o runtime de destino não dá suporte a tipos covariantes em substituições. O tipo precisa ser '{2}' para corresponder ao membro substituído '{1}' @@ -1377,6 +1447,11 @@ '{0}' foi atribuído com 'UnmanagedCallersOnly' e não pode ser convertido em um tipo delegado. Obtenha um ponteiro de função para esse método. UnmanagedCallersOnly is not localizable. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. + + List patterns may not be used for a value of type '{0}'. Os padrões de lista não podem ser usados para um valor do tipo '{0}'. @@ -1537,6 +1612,11 @@ relaxed shift operator + + required members + required members + + sealed ToString in record ToString selado no registro @@ -1707,6 +1787,16 @@ Convertendo grupo de método em tipo não delegado + + Required member '{0}' should not be attributed with 'ObsoleteAttribute' unless the containing type is obsolete or all constructors are obsolete. + Required member '{0}' should not be attributed with 'ObsoleteAttribute' unless the containing type is obsolete or all constructors are obsolete. + + + + Members attributed with 'ObsoleteAttribute' should not be required unless the containing type is obsolete or all constructors are obsolete. + Members attributed with 'ObsoleteAttribute' should not be required unless the containing type is obsolete or all constructors are obsolete. + + Parameter '{0}' must have a non-null value when exiting because parameter '{1}' is non-null. O parâmetro '{0}' precisa ter um valor não nulo durante a saída porque o parâmetro '{1}' não é nulo. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index 859b291ef2d94..a87388330791f 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -292,6 +292,11 @@ В __arglist невозможно передать аргумент с помощью in или out + + This constructor must add 'SetsRequiredMembers' because it chains to a constructor that has that attribute. + This constructor must add 'SetsRequiredMembers' because it chains to a constructor that has that attribute. + + The operator '{0}' requires a matching non-checked version of the operator to also be defined The operator '{0}' requires a matching non-checked version of the operator to also be defined @@ -447,6 +452,11 @@ Каждый из методов доступа "{0}" и "{1}" должен вызываться только во время инициализации либо ни один из этих методов доступа не должен вызываться таким образом. + + Do not use 'System.Runtime.CompilerServices.RequiredMemberAttribute'. Use the 'required' keyword on required fields and properties instead. + Do not use 'System.Runtime.CompilerServices.RequiredMemberAttribute'. Use the 'required' keyword on required fields and properties instead. + + The given expression cannot be used in a fixed statement Заданное выражение невозможно использовать в операторе fixed @@ -497,6 +507,11 @@ Дерево выражений не может содержать оператор == или != кортежа. + + An expression tree may not contain UTF-8 string conversion or literal. + An expression tree may not contain UTF-8 string conversion or literal. + + An expression tree may not contain a with-expression. Дерево выражения не может содержать выражение with. @@ -902,6 +917,11 @@ Ограничение "new()" невозможно использовать вместе с ограничением "unmanaged" + + '{2}' cannot satisfy the 'new()' constraint on parameter '{1}' in the generic type or or method '{0}' because '{2}' has required members. + '{2}' cannot satisfy the 'new()' constraint on parameter '{1}' in the generic type or or method '{0}' because '{2}' has required members. + + Newlines inside a non-verbatim interpolated string are not supported in C# {0}. Please use language version {1} or greater. Новые строки внутри небуквальной интерполированной строки не поддерживаются в C# {0}. Используйте версию языка {1} или более позднюю. @@ -1032,6 +1052,11 @@ Метод "{0}" задает ограничение "default" для параметра типа "{1}", но соответствующий параметр типа "{2}" переопределенного или явно реализованного метода "{3}" ограничен и может представлять собой только тип ссылки или тип значения. + + '{0}' must be required because it overrides required member '{1}' + '{0}' must be required because it overrides required member '{1}' + + Method '{0}' specifies a 'class' constraint for type parameter '{1}', but corresponding type parameter '{2}' of overridden or explicitly implemented method '{3}' is not a reference type. Метод "{0}" задает ограничение class для параметра типа "{1}", но соответствующий параметр типа "{2}" переопределенного или явно реализованного метода "{3}" не является ссылочным типом. @@ -1167,11 +1192,56 @@ Левая часть выражения назначения ссылки должна быть локальной ссылкой или параметром. + + Ref returning properties cannot be required. + Ref returning properties cannot be required. + + Relational patterns may not be used for a floating-point NaN. Реляционные шаблоны не могут использоваться для NaN с плавающей запятой. + + Required member '{0}' cannot be hidden by '{1}'. + Required member '{0}' cannot be hidden by '{1}'. + + + + Required member '{0}' cannot be less visible or have a setter less visible than the containing type '{1}'. + Required member '{0}' cannot be less visible or have a setter less visible than the containing type '{1}'. + + + + Required member '{0}' must be set in the object initializer or attribute constructor. + Required member '{0}' must be set in the object initializer or attribute constructor. + + + + Required member '{0}' must be settable. + Required member '{0}' must be settable. + + + + The required members list for the base type '{0}' is malformed and cannot be interpreted. To use this constructor, apply the 'SetsRequiredMembers' attribute. + The required members list for the base type '{0}' is malformed and cannot be interpreted. To use this constructor, apply the 'SetsRequiredMembers' attribute. + + + + The required members list for '{0}' is malformed and cannot be interpreted. + The required members list for '{0}' is malformed and cannot be interpreted. + + + + Required member '{0}' must be assigned a value, it cannot use a nested member or collection initializer. + Required member '{0}' must be assigned a value, it cannot use a nested member or collection initializer. + + + + Types and aliases cannot be named 'required'. + Types and aliases cannot be named 'required'. + + '{0}': Target runtime doesn't support covariant types in overrides. Type must be '{2}' to match overridden member '{1}' "{0}": целевая среда выполнения не поддерживает ковариантные типы в переопределениях. Для сопоставления переопределенного элемента "{1}" необходимо использовать тип "{2}". @@ -1377,6 +1447,11 @@ "{0}" имеет атрибут "UnmanagedCallersOnly" и не может быть преобразован в тип делегата. Получите указатель на функцию для этого метода. UnmanagedCallersOnly is not localizable. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. + + List patterns may not be used for a value of type '{0}'. Шаблоны списка не могут использоваться для значений типа "{0}". @@ -1537,6 +1612,11 @@ relaxed shift operator + + required members + required members + + sealed ToString in record запечатанный ToString в записи @@ -1707,6 +1787,16 @@ Преобразование группы методов в незаменямый тип + + Required member '{0}' should not be attributed with 'ObsoleteAttribute' unless the containing type is obsolete or all constructors are obsolete. + Required member '{0}' should not be attributed with 'ObsoleteAttribute' unless the containing type is obsolete or all constructors are obsolete. + + + + Members attributed with 'ObsoleteAttribute' should not be required unless the containing type is obsolete or all constructors are obsolete. + Members attributed with 'ObsoleteAttribute' should not be required unless the containing type is obsolete or all constructors are obsolete. + + Parameter '{0}' must have a non-null value when exiting because parameter '{1}' is non-null. При выходе параметр "{0}" должен иметь значение, отличное от NULL, так как параметр "{1}" имеет значение, отличное от NULL. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index 8f7d57c2c3f19..92edf366b2405 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -292,6 +292,11 @@ __arglist, 'in' veya 'out' tarafından geçirilen bir bağımsız değişkene sahip olamaz + + This constructor must add 'SetsRequiredMembers' because it chains to a constructor that has that attribute. + This constructor must add 'SetsRequiredMembers' because it chains to a constructor that has that attribute. + + The operator '{0}' requires a matching non-checked version of the operator to also be defined The operator '{0}' requires a matching non-checked version of the operator to also be defined @@ -447,6 +452,11 @@ '{0}' ve '{1}' erişimcilerinin ikisi de yalnızca init olmalıdır ya da ikisi de olmamalıdır + + Do not use 'System.Runtime.CompilerServices.RequiredMemberAttribute'. Use the 'required' keyword on required fields and properties instead. + Do not use 'System.Runtime.CompilerServices.RequiredMemberAttribute'. Use the 'required' keyword on required fields and properties instead. + + The given expression cannot be used in a fixed statement Belirtilen ifade, fixed deyiminde kullanılamıyor @@ -497,6 +507,11 @@ İfade ağacı, demetin == veya != işlecini içeremez. + + An expression tree may not contain UTF-8 string conversion or literal. + An expression tree may not contain UTF-8 string conversion or literal. + + An expression tree may not contain a with-expression. İfade ağacı, with ifadesi içeremez. @@ -902,6 +917,11 @@ 'new()' kısıtlaması, 'unmanaged' kısıtlamasıyla kullanılamaz + + '{2}' cannot satisfy the 'new()' constraint on parameter '{1}' in the generic type or or method '{0}' because '{2}' has required members. + '{2}' cannot satisfy the 'new()' constraint on parameter '{1}' in the generic type or or method '{0}' because '{2}' has required members. + + Newlines inside a non-verbatim interpolated string are not supported in C# {0}. Please use language version {1} or greater. Tam olmayan düz metin arasına kod eklenmiş dize içindeki yeni satırlar, C# {0} içinde desteklenmiyor. Lütfen {1} dil sürümünü veya daha üstünü kullanın. @@ -1032,6 +1052,11 @@ '{0}' metodu, '{1}' tür parametresi için bir 'default' kısıtlaması belirtiyor, ancak geçersiz kılınan veya açıkça uygulanan '{3}' metodunun karşılık gelen '{2}' tür parametresi bir başvuru türü veya değer türüyle kısıtlanmış. + + '{0}' must be required because it overrides required member '{1}' + '{0}' must be required because it overrides required member '{1}' + + Method '{0}' specifies a 'class' constraint for type parameter '{1}', but corresponding type parameter '{2}' of overridden or explicitly implemented method '{3}' is not a reference type. '{0}' yöntemi, '{1}' tür parametresi için bir 'class' kısıtlaması belirtiyor, ancak geçersiz kılınan veya açıkça uygulanan '{3}' yönteminin karşılık gelen '{2}' tür parametresi bir başvuru türü değil. @@ -1167,11 +1192,56 @@ ref atamasının sol tarafı, yerel ref veya parametresi olmalıdır. + + Ref returning properties cannot be required. + Ref returning properties cannot be required. + + Relational patterns may not be used for a floating-point NaN. İlişkisel desenler, kayan noktalı NaN için kullanılamaz. + + Required member '{0}' cannot be hidden by '{1}'. + Required member '{0}' cannot be hidden by '{1}'. + + + + Required member '{0}' cannot be less visible or have a setter less visible than the containing type '{1}'. + Required member '{0}' cannot be less visible or have a setter less visible than the containing type '{1}'. + + + + Required member '{0}' must be set in the object initializer or attribute constructor. + Required member '{0}' must be set in the object initializer or attribute constructor. + + + + Required member '{0}' must be settable. + Required member '{0}' must be settable. + + + + The required members list for the base type '{0}' is malformed and cannot be interpreted. To use this constructor, apply the 'SetsRequiredMembers' attribute. + The required members list for the base type '{0}' is malformed and cannot be interpreted. To use this constructor, apply the 'SetsRequiredMembers' attribute. + + + + The required members list for '{0}' is malformed and cannot be interpreted. + The required members list for '{0}' is malformed and cannot be interpreted. + + + + Required member '{0}' must be assigned a value, it cannot use a nested member or collection initializer. + Required member '{0}' must be assigned a value, it cannot use a nested member or collection initializer. + + + + Types and aliases cannot be named 'required'. + Types and aliases cannot be named 'required'. + + '{0}': Target runtime doesn't support covariant types in overrides. Type must be '{2}' to match overridden member '{1}' '{0}': Hedef çalışma zamanı, geçersiz kılmalarda birlikte değişken türleri desteklemiyor. Tür, geçersiz kılınan '{1}' üyesiyle eşleşmek için '{2}' olmalıdır @@ -1377,6 +1447,11 @@ '{0}', 'UnmanagedCallersOnly' özniteliğine sahip ve temsilci türüne dönüştürülemez. Bu yöntem için bir işlev işaretçisi edinin. UnmanagedCallersOnly is not localizable. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. + + List patterns may not be used for a value of type '{0}'. Liste desenleri, '{0}' türünde bir değer için kullanılamaz. @@ -1537,6 +1612,11 @@ relaxed shift operator + + required members + required members + + sealed ToString in record kayıtta mühürlü ToString @@ -1707,6 +1787,16 @@ Yöntem grubunu temsilci olmayan türe dönüştürme + + Required member '{0}' should not be attributed with 'ObsoleteAttribute' unless the containing type is obsolete or all constructors are obsolete. + Required member '{0}' should not be attributed with 'ObsoleteAttribute' unless the containing type is obsolete or all constructors are obsolete. + + + + Members attributed with 'ObsoleteAttribute' should not be required unless the containing type is obsolete or all constructors are obsolete. + Members attributed with 'ObsoleteAttribute' should not be required unless the containing type is obsolete or all constructors are obsolete. + + Parameter '{0}' must have a non-null value when exiting because parameter '{1}' is non-null. '{1}' parametresi null olmadığından '{0}' parametresi çıkış yaparken null olmayan bir değere sahip olmalıdır. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index 745b87bac8d45..f813feca45eb8 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -292,6 +292,11 @@ __arglist 不能有 "in" 或 "out" 传递的参数 + + This constructor must add 'SetsRequiredMembers' because it chains to a constructor that has that attribute. + This constructor must add 'SetsRequiredMembers' because it chains to a constructor that has that attribute. + + The operator '{0}' requires a matching non-checked version of the operator to also be defined The operator '{0}' requires a matching non-checked version of the operator to also be defined @@ -447,6 +452,11 @@ 访问器 {0} 和 {1} 应同时为 init-only,或两者都不是 + + Do not use 'System.Runtime.CompilerServices.RequiredMemberAttribute'. Use the 'required' keyword on required fields and properties instead. + Do not use 'System.Runtime.CompilerServices.RequiredMemberAttribute'. Use the 'required' keyword on required fields and properties instead. + + The given expression cannot be used in a fixed statement 给定表达式不能用于 fixed 语句中 @@ -497,6 +507,11 @@ 表达式树不能包含元组 == 或 != 运算符 + + An expression tree may not contain UTF-8 string conversion or literal. + An expression tree may not contain UTF-8 string conversion or literal. + + An expression tree may not contain a with-expression. 表达式树不能包含 with 表达式。 @@ -902,6 +917,11 @@ "new()" 约束不能与 "unmanaged" 约束一起使用 + + '{2}' cannot satisfy the 'new()' constraint on parameter '{1}' in the generic type or or method '{0}' because '{2}' has required members. + '{2}' cannot satisfy the 'new()' constraint on parameter '{1}' in the generic type or or method '{0}' because '{2}' has required members. + + Newlines inside a non-verbatim interpolated string are not supported in C# {0}. Please use language version {1} or greater. C# {0}不支持非逐字内插字符串内的换行符。请使用语言版本 {1} 或更高版本。 @@ -1032,6 +1052,11 @@ 方法“{0}”为类型参数“{1}”指定了 "default" 约束,但被替代的或显式实现的方法“{3}”的对应类型参数“{2}” 仅限于引用类型或值类型。 + + '{0}' must be required because it overrides required member '{1}' + '{0}' must be required because it overrides required member '{1}' + + Method '{0}' specifies a 'class' constraint for type parameter '{1}', but corresponding type parameter '{2}' of overridden or explicitly implemented method '{3}' is not a reference type. 方法 "{0}" 为类型参数 "{1}" 指定了 "class" 约束,但重写的或显式实现的方法 "{3}" 的对应类型参数 "{2}" 不是引用类型。 @@ -1167,11 +1192,56 @@ ref 赋值左侧必须为 ref 本地函数或参数。 + + Ref returning properties cannot be required. + Ref returning properties cannot be required. + + Relational patterns may not be used for a floating-point NaN. 关系模式可能不能用于浮点 NaN。 + + Required member '{0}' cannot be hidden by '{1}'. + Required member '{0}' cannot be hidden by '{1}'. + + + + Required member '{0}' cannot be less visible or have a setter less visible than the containing type '{1}'. + Required member '{0}' cannot be less visible or have a setter less visible than the containing type '{1}'. + + + + Required member '{0}' must be set in the object initializer or attribute constructor. + Required member '{0}' must be set in the object initializer or attribute constructor. + + + + Required member '{0}' must be settable. + Required member '{0}' must be settable. + + + + The required members list for the base type '{0}' is malformed and cannot be interpreted. To use this constructor, apply the 'SetsRequiredMembers' attribute. + The required members list for the base type '{0}' is malformed and cannot be interpreted. To use this constructor, apply the 'SetsRequiredMembers' attribute. + + + + The required members list for '{0}' is malformed and cannot be interpreted. + The required members list for '{0}' is malformed and cannot be interpreted. + + + + Required member '{0}' must be assigned a value, it cannot use a nested member or collection initializer. + Required member '{0}' must be assigned a value, it cannot use a nested member or collection initializer. + + + + Types and aliases cannot be named 'required'. + Types and aliases cannot be named 'required'. + + '{0}': Target runtime doesn't support covariant types in overrides. Type must be '{2}' to match overridden member '{1}' “{0}”: 目标运行时不支持替代中的协变类型。类型必须为“{2}”才能匹配替代成员“{1}” @@ -1377,6 +1447,11 @@ “{0}”使用 "UnmanagedCallersOnly" 进行特性化,无法转换为委托类型。请获取指向此方法的函数指针。 UnmanagedCallersOnly is not localizable. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. + + List patterns may not be used for a value of type '{0}'. 列表模式不能用于类型为“{0}”的值。 @@ -1537,6 +1612,11 @@ relaxed shift operator + + required members + required members + + sealed ToString in record 记录的密封 ToString @@ -1707,6 +1787,16 @@ 将方法组转换为非委托类型 + + Required member '{0}' should not be attributed with 'ObsoleteAttribute' unless the containing type is obsolete or all constructors are obsolete. + Required member '{0}' should not be attributed with 'ObsoleteAttribute' unless the containing type is obsolete or all constructors are obsolete. + + + + Members attributed with 'ObsoleteAttribute' should not be required unless the containing type is obsolete or all constructors are obsolete. + Members attributed with 'ObsoleteAttribute' should not be required unless the containing type is obsolete or all constructors are obsolete. + + Parameter '{0}' must have a non-null value when exiting because parameter '{1}' is non-null. 退出时参数“{0}”必须具有非 null 值,因为参数“{1}”是非 null。 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index 1e48c3c1d7af0..52e37a047e597 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -292,6 +292,11 @@ __arglist 不得包含 'in' 或 'out' 傳遞的引數 + + This constructor must add 'SetsRequiredMembers' because it chains to a constructor that has that attribute. + This constructor must add 'SetsRequiredMembers' because it chains to a constructor that has that attribute. + + The operator '{0}' requires a matching non-checked version of the operator to also be defined The operator '{0}' requires a matching non-checked version of the operator to also be defined @@ -447,6 +452,11 @@ 存取子 '{0}' 與 '{1}' 不得同時是或不是僅供初始化 + + Do not use 'System.Runtime.CompilerServices.RequiredMemberAttribute'. Use the 'required' keyword on required fields and properties instead. + Do not use 'System.Runtime.CompilerServices.RequiredMemberAttribute'. Use the 'required' keyword on required fields and properties instead. + + The given expression cannot be used in a fixed statement 指定運算式無法用於 fixed 陳述式中 @@ -497,6 +507,11 @@ 運算式樹狀架構不得包含元組 == 或 != 運算子 + + An expression tree may not contain UTF-8 string conversion or literal. + An expression tree may not contain UTF-8 string conversion or literal. + + An expression tree may not contain a with-expression. 運算式樹狀架構不得包含 with 運算式。 @@ -902,6 +917,11 @@ new()' 條件約束不能和 'unmanaged' 條件約束一起使用 + + '{2}' cannot satisfy the 'new()' constraint on parameter '{1}' in the generic type or or method '{0}' because '{2}' has required members. + '{2}' cannot satisfy the 'new()' constraint on parameter '{1}' in the generic type or or method '{0}' because '{2}' has required members. + + Newlines inside a non-verbatim interpolated string are not supported in C# {0}. Please use language version {1} or greater. C# {0} 不支援非逐字差補字串內的新行。請使用語言版本 {1} 或更高版本。 @@ -1032,6 +1052,11 @@ 方法 '{0}' 會為型別參數 '{1}' 指定 'default' 條件約束,但覆寫或明確實作方法 '{3}' 的對應型別參數 '{2}' 會限制為參考型別或實值型別。 + + '{0}' must be required because it overrides required member '{1}' + '{0}' must be required because it overrides required member '{1}' + + Method '{0}' specifies a 'class' constraint for type parameter '{1}', but corresponding type parameter '{2}' of overridden or explicitly implemented method '{3}' is not a reference type. 方法 '{0}' 會為型別參數 '{1}' 指定 'class' 條件約束,但覆寫或明確實作的方法 '{3}' 對應型別參數 '{2}' 不屬於參考型別。 @@ -1167,11 +1192,56 @@ 參考指派的左側必須為參考本機或參數。 + + Ref returning properties cannot be required. + Ref returning properties cannot be required. + + Relational patterns may not be used for a floating-point NaN. 浮點 NaN 不可使用關聯性模式。 + + Required member '{0}' cannot be hidden by '{1}'. + Required member '{0}' cannot be hidden by '{1}'. + + + + Required member '{0}' cannot be less visible or have a setter less visible than the containing type '{1}'. + Required member '{0}' cannot be less visible or have a setter less visible than the containing type '{1}'. + + + + Required member '{0}' must be set in the object initializer or attribute constructor. + Required member '{0}' must be set in the object initializer or attribute constructor. + + + + Required member '{0}' must be settable. + Required member '{0}' must be settable. + + + + The required members list for the base type '{0}' is malformed and cannot be interpreted. To use this constructor, apply the 'SetsRequiredMembers' attribute. + The required members list for the base type '{0}' is malformed and cannot be interpreted. To use this constructor, apply the 'SetsRequiredMembers' attribute. + + + + The required members list for '{0}' is malformed and cannot be interpreted. + The required members list for '{0}' is malformed and cannot be interpreted. + + + + Required member '{0}' must be assigned a value, it cannot use a nested member or collection initializer. + Required member '{0}' must be assigned a value, it cannot use a nested member or collection initializer. + + + + Types and aliases cannot be named 'required'. + Types and aliases cannot be named 'required'. + + '{0}': Target runtime doesn't support covariant types in overrides. Type must be '{2}' to match overridden member '{1}' '{0}': 在覆寫中,目標執行階段不支援 Covariant 類型。類型必須是 '{2}',才符合覆寫的成員 '{1}' @@ -1377,6 +1447,11 @@ '{0}' 使用 'UnmanagedCallersOnly' 屬性化,因此無法轉換為委派類型。取得此方法的函式指標。 UnmanagedCallersOnly is not localizable. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. + '{0}' requires compiler feature '{1}', which is not supported by this version of the C# compiler. + + List patterns may not be used for a value of type '{0}'. 類型 '{0}' 的值不可使用清單模式。 @@ -1537,6 +1612,11 @@ relaxed shift operator + + required members + required members + + sealed ToString in record 記錄中有密封的 ToString @@ -1707,6 +1787,16 @@ 將方法群組轉換為非委派類型 + + Required member '{0}' should not be attributed with 'ObsoleteAttribute' unless the containing type is obsolete or all constructors are obsolete. + Required member '{0}' should not be attributed with 'ObsoleteAttribute' unless the containing type is obsolete or all constructors are obsolete. + + + + Members attributed with 'ObsoleteAttribute' should not be required unless the containing type is obsolete or all constructors are obsolete. + Members attributed with 'ObsoleteAttribute' should not be required unless the containing type is obsolete or all constructors are obsolete. + + Parameter '{0}' must have a non-null value when exiting because parameter '{1}' is non-null. 因為參數 '{1}' 不是 null,所以參數 '{0}' 在結束時必須具有非 Null 值。 diff --git a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_IsByRefLike.cs b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_IsByRefLike.cs index 6cf7d507d903d..61a7964dcfdd9 100644 --- a/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_IsByRefLike.cs +++ b/src/Compilers/CSharp/Test/Emit2/Attributes/AttributeTests_IsByRefLike.cs @@ -21,8 +21,9 @@ namespace Microsoft.CodeAnalysis.CSharp.UnitTests { public class AttributeTests_IsByRefLike : CSharpTestBase { - [Fact] - public void IsByRefLikeIsWrittenToMetadata_SameAssembly() + [Theory] + [CombinatorialData] + public void IsByRefLikeIsWrittenToMetadata_SameAssembly(bool includeCompilerFeatureRequired) { var text = @" namespace System.Runtime.CompilerServices @@ -38,32 +39,34 @@ public ref struct S1 {} void validate(ModuleSymbol module) { var type = module.ContainingAssembly.GetTypeByMetadataName("Test").GetTypeMember("S1"); - AssertReferencedIsByRefLike(type); + AssertReferencedIsByRefLike(type, hasCompilerFeatureRequired: includeCompilerFeatureRequired); var peModule = (PEModuleSymbol)module; Assert.True(peModule.Module.HasIsByRefLikeAttribute(((PENamedTypeSymbol)type).Handle)); AssertDeclaresType(peModule, WellKnownType.System_Runtime_CompilerServices_IsByRefLikeAttribute, Accessibility.Public); } - CompileAndVerify(text, verify: Verification.Passes, symbolValidator: validate); + CompileAndVerify(new[] { text, GetCompilerFeatureRequiredAttributeText(includeCompilerFeatureRequired) }, verify: Verification.Passes, symbolValidator: validate); } - [Fact] - public void IsByRefLikeIsWrittenToMetadata_NeedsToBeGenerated() + [Theory] + [CombinatorialData] + public void IsByRefLikeIsWrittenToMetadata_NeedsToBeGenerated(bool includeCompilerFeatureRequired) { var text = @" ref struct S1{} "; - CompileAndVerify(text, verify: Verification.Passes, symbolValidator: module => + CompileAndVerify(new[] { text, GetCompilerFeatureRequiredAttributeText(includeCompilerFeatureRequired) }, verify: Verification.Passes, symbolValidator: module => { var type = module.ContainingAssembly.GetTypeByMetadataName("S1"); - AssertReferencedIsByRefLike(type); + AssertReferencedIsByRefLike(type, hasCompilerFeatureRequired: includeCompilerFeatureRequired); }); } - [Fact] - public void IsByRefLikeIsWrittenToMetadata_NeedsToBeGeneratedNested() + [Theory] + [CombinatorialData] + public void IsByRefLikeIsWrittenToMetadata_NeedsToBeGeneratedNested(bool includeCompilerFeatureRequired) { var text = @" class Test @@ -72,15 +75,16 @@ public ref struct S1 {} } "; - CompileAndVerify(text, verify: Verification.Passes, symbolValidator: module => + CompileAndVerify(new[] { text, GetCompilerFeatureRequiredAttributeText(includeCompilerFeatureRequired) }, verify: Verification.Passes, symbolValidator: module => { var type = module.ContainingAssembly.GetTypeByMetadataName("Test").GetTypeMember("S1"); - AssertReferencedIsByRefLike(type); + AssertReferencedIsByRefLike(type, hasCompilerFeatureRequired: includeCompilerFeatureRequired); }); } - [Fact] - public void IsByRefLikeIsWrittenToMetadata_NeedsToBeGeneratedGeneric() + [Theory] + [CombinatorialData] + public void IsByRefLikeIsWrittenToMetadata_NeedsToBeGeneratedGeneric(bool includeCompilerFeatureRequired) { var text = @" class Test @@ -92,18 +96,19 @@ public ref struct S1 {} void validate(ModuleSymbol module) { var type = module.ContainingAssembly.GetTypeByMetadataName("Test+S1`1"); - AssertReferencedIsByRefLike(type); + AssertReferencedIsByRefLike(type, hasCompilerFeatureRequired: includeCompilerFeatureRequired); var peModule = (PEModuleSymbol)module; Assert.True(peModule.Module.HasIsByRefLikeAttribute(((PENamedTypeSymbol)type).Handle)); AssertDeclaresType(peModule, WellKnownType.System_Runtime_CompilerServices_IsByRefLikeAttribute, Accessibility.Internal); } - CompileAndVerify(text, symbolValidator: validate); + CompileAndVerify(new[] { text, GetCompilerFeatureRequiredAttributeText(includeCompilerFeatureRequired) }, symbolValidator: validate); } - [Fact] - public void IsByRefLikeIsWrittenToMetadata_NeedsToBeGeneratedNestedInGeneric() + [Theory] + [CombinatorialData] + public void IsByRefLikeIsWrittenToMetadata_NeedsToBeGeneratedNestedInGeneric(bool includeCompilerFeatureRequired) { var text = @" class Test @@ -112,15 +117,16 @@ public ref struct S1 {} } "; - CompileAndVerify(text, verify: Verification.Passes, symbolValidator: module => + CompileAndVerify(new[] { text, GetCompilerFeatureRequiredAttributeText(includeCompilerFeatureRequired) }, verify: Verification.Passes, symbolValidator: module => { var type = module.ContainingAssembly.GetTypeByMetadataName("Test`1").GetTypeMember("S1"); - AssertReferencedIsByRefLike(type); + AssertReferencedIsByRefLike(type, hasCompilerFeatureRequired: includeCompilerFeatureRequired); }); } - [Fact] - public void IsByRefLikeIsWrittenToMetadata_DifferentAssembly() + [Theory] + [CombinatorialData] + public void IsByRefLikeIsWrittenToMetadata_DifferentAssembly(bool includeCompilerFeatureRequired) { var codeA = @" namespace System.Runtime.CompilerServices @@ -128,7 +134,7 @@ namespace System.Runtime.CompilerServices public class IsByRefLikeAttribute : System.Attribute { } }"; - var referenceA = CreateCompilation(codeA).VerifyDiagnostics().ToMetadataReference(); + var referenceA = CreateCompilation(new[] { codeA, GetCompilerFeatureRequiredAttributeText(includeCompilerFeatureRequired) }).VerifyDiagnostics().ToMetadataReference(); var codeB = @" class Test @@ -141,8 +147,8 @@ public ref struct S1 {} { var type = module.ContainingAssembly.GetTypeByMetadataName("Test").GetTypeMember("S1"); - AssertReferencedIsByRefLike(type); - AssertNoIsByRefLikeAttributeExists(module.ContainingAssembly); + AssertReferencedIsByRefLike(type, hasCompilerFeatureRequired: includeCompilerFeatureRequired); + AssertNoIsByRefLikeAttributeOrCompilerFeatureRequiredAttributeExists(module.ContainingAssembly, includeCompilerFeatureRequired); }); } @@ -436,7 +442,7 @@ public ref struct S1{} var type = module.ContainingAssembly.GetTypeByMetadataName("Test").GetTypeMember("S1"); AssertReferencedIsByRefLike(type); - AssertNoIsByRefLikeAttributeExists(module.ContainingAssembly); + AssertNoIsByRefLikeAttributeOrCompilerFeatureRequiredAttributeExists(module.ContainingAssembly, hasCompilerFeatureRequired: false); }); } @@ -609,7 +615,7 @@ public void M(Test p) void symbolValidator(ModuleSymbol module) { // No attribute is copied - AssertNoIsByRefLikeAttributeExists(module.ContainingAssembly); + AssertNoIsByRefLikeAttributeOrCompilerFeatureRequiredAttributeExists(module.ContainingAssembly, hasCompilerFeatureRequired: false); var type = module.ContainingAssembly.GetTypeByMetadataName("Test"); @@ -642,8 +648,9 @@ public ref struct S1{} ); } - [Fact] - public void IsByRefLikeObsolete() + [Theory] + [CombinatorialData] + public void IsByRefLikeObsolete(bool includeCompilerFeatureRequired) { var text = @" namespace System.Runtime.CompilerServices @@ -672,12 +679,14 @@ void validate(ModuleSymbol module) if (module is PEModuleSymbol peModule) { - Assert.True(peModule.Module.HasIsByRefLikeAttribute(((PENamedTypeSymbol)type).Handle)); + var peType = (PENamedTypeSymbol)type; + Assert.True(peModule.Module.HasIsByRefLikeAttribute(peType.Handle)); AssertDeclaresType(peModule, WellKnownType.System_Runtime_CompilerServices_IsByRefLikeAttribute, Accessibility.Public); + AssertHasCompilerFeatureRequired(includeCompilerFeatureRequired, peType, peModule, new MetadataDecoder(peModule)); } }; - CompileAndVerify(text, verify: Verification.Passes, symbolValidator: validate, sourceSymbolValidator: validate); + CompileAndVerify(new[] { text, GetCompilerFeatureRequiredAttributeText(includeCompilerFeatureRequired) }, verify: Verification.Passes, symbolValidator: validate, sourceSymbolValidator: validate); } [Fact] @@ -707,8 +716,9 @@ public class ObsoleteAttribute{} }); } - [Fact] - public void IsByRefLikeDeprecated() + [Theory] + [CombinatorialData] + public void IsByRefLikeDeprecated(bool includeCompilerFeatureRequired) { var text = @" using System; @@ -742,7 +752,7 @@ public ref struct S1 {} } "; - CompileAndVerify(text, verify: Verification.Passes, symbolValidator: module => + CompileAndVerify(new[] { text, GetCompilerFeatureRequiredAttributeText(includeCompilerFeatureRequired) }, verify: Verification.Passes, symbolValidator: module => { var type = module.ContainingAssembly.GetTypeByMetadataName("Test").GetTypeMember("S1"); Assert.True(type.IsRefLikeType); @@ -750,11 +760,15 @@ public ref struct S1 {} var attribute = type.GetAttributes().Single(); Assert.Equal("Windows.Foundation.Metadata.DeprecatedAttribute", attribute.AttributeClass.ToDisplayString()); Assert.Equal(42u, attribute.ConstructorArguments.ElementAt(2).Value); + + var peModule = (PEModuleSymbol)module; + AssertHasCompilerFeatureRequired(includeCompilerFeatureRequired, (PENamedTypeSymbol)type, peModule, new MetadataDecoder(peModule)); }); } - [Fact] - public void IsByRefLikeDeprecatedAndObsolete() + [Theory] + [CombinatorialData] + public void IsByRefLikeDeprecatedAndObsolete(bool includeCompilerFeatureRequired) { var text = @" using System; @@ -789,7 +803,7 @@ public ref struct S1 {} } "; - CompileAndVerify(text, verify: Verification.Passes, symbolValidator: module => + CompileAndVerify(new[] { text, GetCompilerFeatureRequiredAttributeText(includeCompilerFeatureRequired) }, verify: Verification.Passes, symbolValidator: module => { var type = module.ContainingAssembly.GetTypeByMetadataName("Test").GetTypeMember("S1"); Assert.True(type.IsRefLikeType); @@ -802,6 +816,9 @@ public ref struct S1 {} var attribute = attributes[0]; Assert.Equal("System.ObsoleteAttribute", attribute.AttributeClass.ToDisplayString()); Assert.Equal(0, attribute.ConstructorArguments.Count()); + + var peModule = (PEModuleSymbol)module; + AssertHasCompilerFeatureRequired(includeCompilerFeatureRequired, (PENamedTypeSymbol)type, peModule, new MetadataDecoder(peModule)); }); } @@ -845,15 +862,16 @@ public ref struct S2 {} ); } - [Fact] - public void ObsoleteHasErrorEqualsTrue() + [Theory] + [CombinatorialData] + public void ObsoleteHasErrorEqualsTrue(bool includeCompilerFeatureRequired) { var text = @"public ref struct S {}"; - CompileAndVerify(text, verify: Verification.Passes, symbolValidator: module => + CompileAndVerify(new[] { text, GetCompilerFeatureRequiredAttributeText(includeCompilerFeatureRequired) }, verify: Verification.Passes, symbolValidator: module => { var type = module.ContainingAssembly.GetTypeByMetadataName("S"); - AssertReferencedIsByRefLike(type); + AssertReferencedIsByRefLike(type, hasCompilerFeatureRequired: includeCompilerFeatureRequired); }); } @@ -929,8 +947,9 @@ void Method() } [WorkItem(22198, "https://github.com/dotnet/roslyn/issues/22198")] - [Fact] - public void SpecialTypes_CorLib() + [Theory] + [CombinatorialData] + public void SpecialTypes_CorLib(bool includeCompilerFeatureRequired) { var source1 = @" @@ -955,28 +974,44 @@ public ref struct RuntimeArgumentHandle { } public ref struct NotTypedReference { } }"; - var compilation1 = CreateEmptyCompilation(source1, assemblyName: GetUniqueName()); + + var compilerFeatureRequiredAttribute = includeCompilerFeatureRequired ? + """ + namespace System.Runtime.CompilerServices + { + public class CompilerFeatureRequiredAttribute : Attribute + { + public CompilerFeatureRequiredAttribute(string featureName) + { + FeatureName = featureName; + } + public string FeatureName { get; } + } + } + """ : ""; + var compilation1 = CreateEmptyCompilation(new[] { source1, compilerFeatureRequiredAttribute }, assemblyName: GetUniqueName()); // PEVerify: Type load failed. CompileAndVerify(compilation1, verify: Verification.FailsPEVerify, symbolValidator: module => { var type = module.ContainingAssembly.GetTypeByMetadataName("System.TypedReference"); - AssertReferencedIsByRefLike(type, hasObsolete: false); + AssertReferencedIsByRefLike(type, hasObsolete: false, hasCompilerFeatureRequired: includeCompilerFeatureRequired); type = module.ContainingAssembly.GetTypeByMetadataName("System.ArgIterator"); - AssertReferencedIsByRefLike(type, hasObsolete: false); + AssertReferencedIsByRefLike(type, hasObsolete: false, hasCompilerFeatureRequired: includeCompilerFeatureRequired); type = module.ContainingAssembly.GetTypeByMetadataName("System.RuntimeArgumentHandle"); - AssertReferencedIsByRefLike(type, hasObsolete: false); + AssertReferencedIsByRefLike(type, hasObsolete: false, hasCompilerFeatureRequired: includeCompilerFeatureRequired); // control case. Not a special type. type = module.ContainingAssembly.GetTypeByMetadataName("System.NotTypedReference"); - AssertReferencedIsByRefLike(type, hasObsolete: true); + AssertReferencedIsByRefLike(type, hasObsolete: true, hasCompilerFeatureRequired: includeCompilerFeatureRequired); }); } - [Fact] - public void SpecialTypes_NotCorLib() + [Theory] + [CombinatorialData] + public void SpecialTypes_NotCorLib(bool includeCompilerFeatureRequired) { var text = @" namespace System @@ -985,24 +1020,25 @@ public ref struct TypedReference { } } "; - CompileAndVerify(text, verify: Verification.Passes, symbolValidator: module => + CompileAndVerify(new[] { text, GetCompilerFeatureRequiredAttributeText(includeCompilerFeatureRequired) }, verify: Verification.Passes, symbolValidator: module => { var type = module.ContainingAssembly.GetTypeByMetadataName("System.TypedReference"); - AssertReferencedIsByRefLike(type); + AssertReferencedIsByRefLike(type, hasCompilerFeatureRequired: includeCompilerFeatureRequired); }); } - private static void AssertReferencedIsByRefLike(TypeSymbol type, bool hasObsolete = true) + private static void AssertReferencedIsByRefLike(TypeSymbol type, bool hasObsolete = true, bool hasCompilerFeatureRequired = false) { var peType = (PENamedTypeSymbol)type; Assert.True(peType.IsRefLikeType); - // there is no [Obsolete] or [IsByRef] attribute returned + // there is no [Obsolete], [IsByRef], or [CompilerFeatureRequired] attribute returned Assert.Empty(peType.GetAttributes()); var peModule = (PEModuleSymbol)peType.ContainingModule; - var obsoleteAttribute = peModule.Module.TryGetDeprecatedOrExperimentalOrObsoleteAttribute(peType.Handle, new MetadataDecoder(peModule), ignoreByRefLikeMarker: false); + var decoder = new MetadataDecoder(peModule); + var obsoleteAttribute = peModule.Module.TryGetDeprecatedOrExperimentalOrObsoleteAttribute(peType.Handle, decoder, ignoreByRefLikeMarker: false, ignoreRequiredMemberMarker: false); if (hasObsolete) { @@ -1014,6 +1050,18 @@ private static void AssertReferencedIsByRefLike(TypeSymbol type, bool hasObsolet { Assert.Null(obsoleteAttribute); } + + AssertHasCompilerFeatureRequired(hasCompilerFeatureRequired, peType, peModule, decoder); + } + + private static void AssertHasCompilerFeatureRequired(bool hasCompilerFeatureRequired, PENamedTypeSymbol peType, PEModuleSymbol peModule, MetadataDecoder decoder) + { + var compilerFeatureRequiredToken = peModule.Module.GetFirstUnsupportedCompilerFeatureFromToken(peType.Handle, decoder, CompilerFeatureRequiredFeatures.RefStructs); + Assert.Null(compilerFeatureRequiredToken); + + compilerFeatureRequiredToken = peModule.Module.GetFirstUnsupportedCompilerFeatureFromToken(peType.Handle, decoder, CompilerFeatureRequiredFeatures.None); + var shouldHaveMarker = hasCompilerFeatureRequired && !peType.IsRestrictedType(ignoreSpanLikeTypes: true); + Assert.Equal(shouldHaveMarker ? nameof(CompilerFeatureRequiredFeatures.RefStructs) : null, compilerFeatureRequiredToken); } private static void AssertNotReferencedIsByRefLikeAttribute(ImmutableArray attributes) @@ -1024,10 +1072,12 @@ private static void AssertNotReferencedIsByRefLikeAttribute(ImmutableArray hasAttribute ? CompilerFeatureRequiredAttribute : ""; } } diff --git a/src/Compilers/CSharp/Test/Symbol/SymbolDisplay/SymbolDisplayTests.cs b/src/Compilers/CSharp/Test/Symbol/SymbolDisplay/SymbolDisplayTests.cs index 2160aa0efaca0..e509163614250 100644 --- a/src/Compilers/CSharp/Test/Symbol/SymbolDisplay/SymbolDisplayTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/SymbolDisplay/SymbolDisplayTests.cs @@ -2744,6 +2744,7 @@ public void TestMembersInScriptGlobals() globalNamespaceStyle: SymbolDisplayGlobalNamespaceStyle.Omitted, genericsOptions: SymbolDisplayGenericsOptions.IncludeTypeParameters | SymbolDisplayGenericsOptions.IncludeTypeConstraints, memberOptions: + SymbolDisplayMemberOptions.IncludeModifiers | SymbolDisplayMemberOptions.IncludeRef | SymbolDisplayMemberOptions.IncludeType | SymbolDisplayMemberOptions.IncludeParameters | @@ -7991,5 +7992,39 @@ void M(string s!!) SymbolDisplayPartKind.ParameterName, SymbolDisplayPartKind.Punctuation); } + + [Fact] + public void TestRequiredProperty() + { + var source = @" +class C +{ + required int Prop { get; set; } +} +"; + + var comp = CreateCompilation(source); + var propertySymbol = comp.GetMember("C.Prop").GetPublicSymbol(); + + Verify(propertySymbol.ToDisplayParts(s_memberSignatureDisplayFormat), "required int C.Prop { get; set; }", + SymbolDisplayPartKind.Keyword, + SymbolDisplayPartKind.Space, + SymbolDisplayPartKind.Keyword, + SymbolDisplayPartKind.Space, + SymbolDisplayPartKind.ClassName, + SymbolDisplayPartKind.Punctuation, + SymbolDisplayPartKind.PropertyName, + SymbolDisplayPartKind.Space, + SymbolDisplayPartKind.Punctuation, + SymbolDisplayPartKind.Space, + SymbolDisplayPartKind.Keyword, + SymbolDisplayPartKind.Punctuation, + SymbolDisplayPartKind.Space, + SymbolDisplayPartKind.Keyword, + SymbolDisplayPartKind.Punctuation, + SymbolDisplayPartKind.Space, + SymbolDisplayPartKind.Punctuation); + + } } } diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/CSharpCompilerFeatureRequiredTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/CSharpCompilerFeatureRequiredTests.cs new file mode 100644 index 0000000000000..78f82892ae51a --- /dev/null +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/CSharpCompilerFeatureRequiredTests.cs @@ -0,0 +1,692 @@ +// 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.Collections.Generic; +using System.Linq; +using Microsoft.CodeAnalysis.CodeGen; +using Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Microsoft.CodeAnalysis.Test.Utilities; +using Microsoft.CodeAnalysis.UnitTests; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Symbols; + +public class CSharpCompilerFeatureRequiredTests : BaseCompilerFeatureRequiredTests +{ + private class CompilerFeatureRequiredTests_CSharp : CSharpTestBase { } + + private readonly CompilerFeatureRequiredTests_CSharp _csharpTest = new CompilerFeatureRequiredTests_CSharp(); + + protected override CSharpTestSource GetUsage() => """ + #pragma warning disable 168 // Unused local + OnType onType; + OnType.M(); + OnMethod.M(); + OnMethodReturn.M(); + OnParameter.M(1); + _ = OnField.Field; + OnProperty.Property = 1; + _ = OnProperty.Property; + OnPropertySetter.Property = 1; + _ = OnPropertySetter.Property; + OnPropertyGetter.Property = 1; + _ = OnPropertyGetter.Property; + OnEvent.Event += () => {}; + OnEvent.Event -= () => {}; + OnEventAdder.Event += () => {}; + OnEventAdder.Event -= () => {}; + OnEventRemover.Event += () => {}; + OnEventRemover.Event -= () => {}; + OnEnum onEnum; + _ = OnEnumMember.A; + OnClassTypeParameter onClassTypeParameter; + OnMethodTypeParameter.M(); + OnDelegateType onDelegateType; + OnIndexedPropertyParameter.set_Property(1, 1); + _ = OnIndexedPropertyParameter.get_Property(1); + new OnThisIndexerParameter()[1] = 1; + _ = new OnThisIndexerParameter()[1]; + """; + + internal override string VisualizeRealIL(IModuleSymbol peModule, CompilationTestData.MethodData methodData, IReadOnlyDictionary markers, bool areLocalsZeroed) + { + return _csharpTest.VisualizeRealIL(peModule, methodData, markers, areLocalsZeroed); + } + + protected override CSharpCompilation CreateCompilationWithIL(CSharpTestSource source, string ilSource) + { + return CSharpTestBase.CreateCompilationWithIL(source, ilSource); + } + + protected override CSharpCompilation CreateCompilation(CSharpTestSource source, MetadataReference[] references) + { + return CSharpTestBase.CreateCompilation(source, references); + } + + protected override CompilationVerifier CompileAndVerify(CSharpCompilation compilation) + { + return _csharpTest.CompileAndVerify(compilation); + } + + protected override void AssertNormalErrors(CSharpCompilation comp) + { + comp.VerifyDiagnostics( + // (2,1): error CS9041: 'OnType' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnType onType; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnType").WithArguments("OnType", "test").WithLocation(2, 1), + // (3,1): error CS9041: 'OnType' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnType.M(); + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnType").WithArguments("OnType", "test").WithLocation(3, 1), + // (3,8): error CS9041: 'OnType' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnType.M(); + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "M").WithArguments("OnType", "test").WithLocation(3, 8), + // (4,10): error CS9041: 'OnMethod.M()' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnMethod.M(); + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "M").WithArguments("OnMethod.M()", "test").WithLocation(4, 10), + // (5,16): error CS9041: 'void' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnMethodReturn.M(); + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "M").WithArguments("void", "test").WithLocation(5, 16), + // (6,13): error CS9041: 'int' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnParameter.M(1); + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "M").WithArguments("int", "test").WithLocation(6, 13), + // (7,13): error CS9041: 'OnField.Field' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // _ = OnField.Field; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "Field").WithArguments("OnField.Field", "test").WithLocation(7, 13), + // (8,12): error CS9041: 'OnProperty.Property' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnProperty.Property = 1; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "Property").WithArguments("OnProperty.Property", "test").WithLocation(8, 12), + // (9,16): error CS9041: 'OnProperty.Property' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // _ = OnProperty.Property; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "Property").WithArguments("OnProperty.Property", "test").WithLocation(9, 16), + // (10,18): error CS9041: 'OnPropertySetter.Property.set' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnPropertySetter.Property = 1; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "Property").WithArguments("OnPropertySetter.Property.set", "test").WithLocation(10, 18), + // (13,22): error CS9041: 'OnPropertyGetter.Property.get' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // _ = OnPropertyGetter.Property; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "Property").WithArguments("OnPropertyGetter.Property.get", "test").WithLocation(13, 22), + // (14,9): error CS9041: 'OnEvent.Event' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnEvent.Event += () => {}; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "Event").WithArguments("OnEvent.Event", "test").WithLocation(14, 9), + // (15,9): error CS9041: 'OnEvent.Event' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnEvent.Event -= () => {}; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "Event").WithArguments("OnEvent.Event", "test").WithLocation(15, 9), + // (20,1): error CS9041: 'OnEnum' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnEnum onEnum; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnEnum").WithArguments("OnEnum", "test").WithLocation(20, 1), + // (21,18): error CS9041: 'OnEnumMember.A' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // _ = OnEnumMember.A; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "A").WithArguments("OnEnumMember.A", "test").WithLocation(21, 18), + // (22,1): error CS9041: 'T' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnClassTypeParameter onClassTypeParameter; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnClassTypeParameter").WithArguments("T", "test").WithLocation(22, 1), + // (23,23): error CS9041: 'T' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnMethodTypeParameter.M(); + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "M").WithArguments("T", "test").WithLocation(23, 23), + // (24,1): error CS9041: 'OnDelegateType' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnDelegateType onDelegateType; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnDelegateType").WithArguments("OnDelegateType", "test").WithLocation(24, 1), + // (25,28): error CS9041: 'int' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnIndexedPropertyParameter.set_Property(1, 1); + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "set_Property").WithArguments("int", "test").WithLocation(25, 28), + // (26,32): error CS9041: 'int' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // _ = OnIndexedPropertyParameter.get_Property(1); + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "get_Property").WithArguments("int", "test").WithLocation(26, 32), + // (27,1): error CS9041: 'int' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // new OnThisIndexerParameter()[1] = 1; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "new OnThisIndexerParameter()[1]").WithArguments("int", "test").WithLocation(27, 1), + // (28,5): error CS9041: 'int' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // _ = new OnThisIndexerParameter()[1]; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "new OnThisIndexerParameter()[1]").WithArguments("int", "test").WithLocation(28, 5) + ); + + var onType = comp.GetTypeByMetadataName("OnType"); + Assert.True(onType!.HasUnsupportedMetadata); + Assert.True(onType.GetMember("M").HasUnsupportedMetadata); + + var onMethod = comp.GetTypeByMetadataName("OnMethod"); + Assert.False(onMethod!.HasUnsupportedMetadata); + Assert.True(onMethod.GetMember("M").HasUnsupportedMetadata); + + var onMethodReturn = comp.GetTypeByMetadataName("OnMethodReturn"); + Assert.False(onMethodReturn!.HasUnsupportedMetadata); + Assert.True(onMethodReturn.GetMember("M").HasUnsupportedMetadata); + + var onParameter = comp.GetTypeByMetadataName("OnParameter"); + Assert.False(onParameter!.HasUnsupportedMetadata); + var onParameterMethod = onParameter.GetMember("M"); + Assert.True(onParameterMethod.HasUnsupportedMetadata); + Assert.True(onParameterMethod.Parameters[0].HasUnsupportedMetadata); + + var onField = comp.GetTypeByMetadataName("OnField"); + Assert.False(onField!.HasUnsupportedMetadata); + Assert.True(onField.GetMember("Field").HasUnsupportedMetadata); + + var onProperty = comp.GetTypeByMetadataName("OnProperty"); + Assert.False(onProperty!.HasUnsupportedMetadata); + Assert.True(onProperty.GetMember("Property").HasUnsupportedMetadata); + + var onPropertyGetter = comp.GetTypeByMetadataName("OnPropertyGetter"); + Assert.False(onPropertyGetter!.HasUnsupportedMetadata); + var onPropertyGetterProperty = onPropertyGetter.GetMember("Property"); + Assert.False(onPropertyGetterProperty.HasUnsupportedMetadata); + Assert.False(onPropertyGetterProperty.SetMethod.HasUnsupportedMetadata); + Assert.True(onPropertyGetterProperty.GetMethod.HasUnsupportedMetadata); + + var onPropertySetter = comp.GetTypeByMetadataName("OnPropertySetter"); + Assert.False(onPropertySetter!.HasUnsupportedMetadata); + var onPropertySetterProperty = onPropertySetter.GetMember("Property"); + Assert.False(onPropertySetterProperty.HasUnsupportedMetadata); + Assert.True(onPropertySetterProperty.SetMethod.HasUnsupportedMetadata); + Assert.False(onPropertySetterProperty.GetMethod.HasUnsupportedMetadata); + + var onEvent = comp.GetTypeByMetadataName("OnEvent"); + Assert.False(onEvent!.HasUnsupportedMetadata); + Assert.True(onEvent.GetMember("Event").HasUnsupportedMetadata); + + var onEventAdder = comp.GetTypeByMetadataName("OnEventAdder"); + Assert.False(onEventAdder!.HasUnsupportedMetadata); + var onEventAdderEvent = onEventAdder.GetMember("Event"); + Assert.False(onEventAdderEvent.HasUnsupportedMetadata); + Assert.True(onEventAdderEvent.AddMethod!.HasUnsupportedMetadata); + Assert.False(onEventAdderEvent.RemoveMethod!.HasUnsupportedMetadata); + + var onEventRemover = comp.GetTypeByMetadataName("OnEventRemover"); + Assert.False(onEventRemover!.HasUnsupportedMetadata); + var onEventRemoverEvent = onEventRemover.GetMember("Event"); + Assert.False(onEventRemoverEvent.HasUnsupportedMetadata); + Assert.False(onEventRemoverEvent.AddMethod!.HasUnsupportedMetadata); + Assert.True(onEventRemoverEvent.RemoveMethod!.HasUnsupportedMetadata); + + var onEnum = comp.GetTypeByMetadataName("OnEnum"); + Assert.True(onEnum!.HasUnsupportedMetadata); + + var onEnumMember = comp.GetTypeByMetadataName("OnEnumMember"); + Assert.False(onEnumMember!.HasUnsupportedMetadata); + Assert.True(onEnumMember.GetMember("A").HasUnsupportedMetadata); + + var onClassTypeParameter = comp.GetTypeByMetadataName("OnClassTypeParameter`1"); + Assert.True(onClassTypeParameter!.HasUnsupportedMetadata); + Assert.True(onClassTypeParameter.TypeParameters[0].HasUnsupportedMetadata); + + var onMethodTypeParameter = comp.GetTypeByMetadataName("OnMethodTypeParameter"); + Assert.False(onMethodTypeParameter!.HasUnsupportedMetadata); + var onMethodTypeParameterMethod = onMethodTypeParameter.GetMember("M"); + Assert.True(onMethodTypeParameterMethod.HasUnsupportedMetadata); + Assert.True(onMethodTypeParameterMethod.TypeParameters[0].HasUnsupportedMetadata); + + var onDelegateType = comp.GetTypeByMetadataName("OnDelegateType"); + Assert.True(onDelegateType!.HasUnsupportedMetadata); + + var onIndexedPropertyParameter = comp.GetTypeByMetadataName("OnIndexedPropertyParameter"); + Assert.False(onIndexedPropertyParameter!.HasUnsupportedMetadata); + Assert.True(onIndexedPropertyParameter.GetMember("get_Property").Parameters[0].HasUnsupportedMetadata); + Assert.True(onIndexedPropertyParameter.GetMember("set_Property").Parameters[0].HasUnsupportedMetadata); + + var onThisParameterIndexer = comp.GetTypeByMetadataName("OnThisIndexerParameter"); + Assert.False(onThisParameterIndexer!.HasUnsupportedMetadata); + var indexer = onThisParameterIndexer.GetMember("this[]"); + Assert.True(indexer.HasUnsupportedMetadata); + Assert.True(indexer.Parameters[0].HasUnsupportedMetadata); + } + + protected override void AssertModuleErrors(CSharpCompilation comp, MetadataReference ilRef) + { + comp.VerifyDiagnostics( + // (2,1): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnType onType; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnType").WithArguments("OnModule", "test").WithLocation(2, 1), + // (3,1): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnType.M(); + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnType").WithArguments("OnModule", "test").WithLocation(3, 1), + // (3,8): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnType.M(); + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "M").WithArguments("OnModule", "test").WithLocation(3, 8), + // (4,1): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnMethod.M(); + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnMethod").WithArguments("OnModule", "test").WithLocation(4, 1), + // (4,10): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnMethod.M(); + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "M").WithArguments("OnModule", "test").WithLocation(4, 10), + // (5,1): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnMethodReturn.M(); + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnMethodReturn").WithArguments("OnModule", "test").WithLocation(5, 1), + // (5,16): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnMethodReturn.M(); + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "M").WithArguments("OnModule", "test").WithLocation(5, 16), + // (6,1): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnParameter.M(1); + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnParameter").WithArguments("OnModule", "test").WithLocation(6, 1), + // (6,13): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnParameter.M(1); + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "M").WithArguments("OnModule", "test").WithLocation(6, 13), + // (7,5): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // _ = OnField.Field; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnField").WithArguments("OnModule", "test").WithLocation(7, 5), + // (7,13): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // _ = OnField.Field; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "Field").WithArguments("OnModule", "test").WithLocation(7, 13), + // (8,1): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnProperty.Property = 1; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnProperty").WithArguments("OnModule", "test").WithLocation(8, 1), + // (8,12): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnProperty.Property = 1; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "Property").WithArguments("OnModule", "test").WithLocation(8, 12), + // (9,5): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // _ = OnProperty.Property; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnProperty").WithArguments("OnModule", "test").WithLocation(9, 5), + // (9,16): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // _ = OnProperty.Property; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "Property").WithArguments("OnModule", "test").WithLocation(9, 16), + // (10,1): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnPropertySetter.Property = 1; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnPropertySetter").WithArguments("OnModule", "test").WithLocation(10, 1), + // (10,18): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnPropertySetter.Property = 1; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "Property").WithArguments("OnModule", "test").WithLocation(10, 18), + // (11,5): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // _ = OnPropertySetter.Property; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnPropertySetter").WithArguments("OnModule", "test").WithLocation(11, 5), + // (11,22): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // _ = OnPropertySetter.Property; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "Property").WithArguments("OnModule", "test").WithLocation(11, 22), + // (12,1): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnPropertyGetter.Property = 1; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnPropertyGetter").WithArguments("OnModule", "test").WithLocation(12, 1), + // (12,18): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnPropertyGetter.Property = 1; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "Property").WithArguments("OnModule", "test").WithLocation(12, 18), + // (13,5): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // _ = OnPropertyGetter.Property; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnPropertyGetter").WithArguments("OnModule", "test").WithLocation(13, 5), + // (13,22): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // _ = OnPropertyGetter.Property; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "Property").WithArguments("OnModule", "test").WithLocation(13, 22), + // (14,1): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnEvent.Event += () => {}; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnEvent").WithArguments("OnModule", "test").WithLocation(14, 1), + // (14,9): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnEvent.Event += () => {}; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "Event").WithArguments("OnModule", "test").WithLocation(14, 9), + // (15,1): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnEvent.Event -= () => {}; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnEvent").WithArguments("OnModule", "test").WithLocation(15, 1), + // (15,9): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnEvent.Event -= () => {}; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "Event").WithArguments("OnModule", "test").WithLocation(15, 9), + // (16,1): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnEventAdder.Event += () => {}; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnEventAdder").WithArguments("OnModule", "test").WithLocation(16, 1), + // (16,14): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnEventAdder.Event += () => {}; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "Event").WithArguments("OnModule", "test").WithLocation(16, 14), + // (17,1): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnEventAdder.Event -= () => {}; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnEventAdder").WithArguments("OnModule", "test").WithLocation(17, 1), + // (17,14): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnEventAdder.Event -= () => {}; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "Event").WithArguments("OnModule", "test").WithLocation(17, 14), + // (18,1): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnEventRemover.Event += () => {}; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnEventRemover").WithArguments("OnModule", "test").WithLocation(18, 1), + // (18,16): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnEventRemover.Event += () => {}; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "Event").WithArguments("OnModule", "test").WithLocation(18, 16), + // (19,1): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnEventRemover.Event -= () => {}; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnEventRemover").WithArguments("OnModule", "test").WithLocation(19, 1), + // (19,16): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnEventRemover.Event -= () => {}; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "Event").WithArguments("OnModule", "test").WithLocation(19, 16), + // (20,1): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnEnum onEnum; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnEnum").WithArguments("OnModule", "test").WithLocation(20, 1), + // (21,5): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // _ = OnEnumMember.A; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnEnumMember").WithArguments("OnModule", "test").WithLocation(21, 5), + // (21,18): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // _ = OnEnumMember.A; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "A").WithArguments("OnModule", "test").WithLocation(21, 18), + // (22,1): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnClassTypeParameter onClassTypeParameter; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnClassTypeParameter").WithArguments("OnModule", "test").WithLocation(22, 1), + // (23,1): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnMethodTypeParameter.M(); + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnMethodTypeParameter").WithArguments("OnModule", "test").WithLocation(23, 1), + // (23,23): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnMethodTypeParameter.M(); + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "M").WithArguments("OnModule", "test").WithLocation(23, 23), + // (24,1): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnDelegateType onDelegateType; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnDelegateType").WithArguments("OnModule", "test").WithLocation(24, 1), + // (25,1): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnIndexedPropertyParameter.set_Property(1, 1); + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnIndexedPropertyParameter").WithArguments("OnModule", "test").WithLocation(25, 1), + // (25,28): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnIndexedPropertyParameter.set_Property(1, 1); + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "set_Property").WithArguments("OnModule", "test").WithLocation(25, 28), + // (26,5): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // _ = OnIndexedPropertyParameter.get_Property(1); + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnIndexedPropertyParameter").WithArguments("OnModule", "test").WithLocation(26, 5), + // (26,32): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // _ = OnIndexedPropertyParameter.get_Property(1); + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "get_Property").WithArguments("OnModule", "test").WithLocation(26, 32), + // (27,5): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // new OnThisIndexerParameter()[1] = 1; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnThisIndexerParameter").WithArguments("OnModule", "test").WithLocation(27, 5), + // (27,5): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // new OnThisIndexerParameter()[1] = 1; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnThisIndexerParameter").WithArguments("OnModule", "test").WithLocation(27, 5), + // (28,9): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // _ = new OnThisIndexerParameter()[1]; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnThisIndexerParameter").WithArguments("OnModule", "test").WithLocation(28, 9), + // (28,9): error CS9041: 'OnModule' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // _ = new OnThisIndexerParameter()[1]; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnThisIndexerParameter").WithArguments("OnModule", "test").WithLocation(28, 9) + ); + + Assert.True(comp.GetReferencedAssemblySymbol(ilRef).Modules.Single().HasUnsupportedMetadata); + } + + protected override void AssertAssemblyErrors(CSharpCompilation comp, MetadataReference ilRef) + { + comp.VerifyDiagnostics( + // (2,1): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnType onType; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnType").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(2, 1), + // (3,1): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnType.M(); + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnType").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(3, 1), + // (3,8): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnType.M(); + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "M").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(3, 8), + // (4,1): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnMethod.M(); + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnMethod").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(4, 1), + // (4,10): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnMethod.M(); + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "M").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(4, 10), + // (5,1): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnMethodReturn.M(); + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnMethodReturn").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(5, 1), + // (5,16): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnMethodReturn.M(); + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "M").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(5, 16), + // (6,1): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnParameter.M(1); + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnParameter").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(6, 1), + // (6,13): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnParameter.M(1); + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "M").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(6, 13), + // (7,5): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // _ = OnField.Field; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnField").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(7, 5), + // (7,13): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // _ = OnField.Field; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "Field").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(7, 13), + // (8,1): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnProperty.Property = 1; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnProperty").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(8, 1), + // (8,12): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnProperty.Property = 1; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "Property").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(8, 12), + // (9,5): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // _ = OnProperty.Property; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnProperty").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(9, 5), + // (9,16): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // _ = OnProperty.Property; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "Property").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(9, 16), + // (10,1): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnPropertySetter.Property = 1; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnPropertySetter").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(10, 1), + // (10,18): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnPropertySetter.Property = 1; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "Property").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(10, 18), + // (11,5): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // _ = OnPropertySetter.Property; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnPropertySetter").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(11, 5), + // (11,22): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // _ = OnPropertySetter.Property; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "Property").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(11, 22), + // (12,1): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnPropertyGetter.Property = 1; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnPropertyGetter").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(12, 1), + // (12,18): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnPropertyGetter.Property = 1; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "Property").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(12, 18), + // (13,5): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // _ = OnPropertyGetter.Property; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnPropertyGetter").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(13, 5), + // (13,22): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // _ = OnPropertyGetter.Property; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "Property").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(13, 22), + // (14,1): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnEvent.Event += () => {}; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnEvent").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(14, 1), + // (14,9): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnEvent.Event += () => {}; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "Event").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(14, 9), + // (15,1): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnEvent.Event -= () => {}; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnEvent").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(15, 1), + // (15,9): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnEvent.Event -= () => {}; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "Event").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(15, 9), + // (16,1): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnEventAdder.Event += () => {}; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnEventAdder").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(16, 1), + // (16,14): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnEventAdder.Event += () => {}; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "Event").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(16, 14), + // (17,1): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnEventAdder.Event -= () => {}; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnEventAdder").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(17, 1), + // (17,14): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnEventAdder.Event -= () => {}; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "Event").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(17, 14), + // (18,1): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnEventRemover.Event += () => {}; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnEventRemover").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(18, 1), + // (18,16): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnEventRemover.Event += () => {}; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "Event").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(18, 16), + // (19,1): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnEventRemover.Event -= () => {}; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnEventRemover").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(19, 1), + // (19,16): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnEventRemover.Event -= () => {}; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "Event").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(19, 16), + // (20,1): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnEnum onEnum; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnEnum").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(20, 1), + // (21,5): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // _ = OnEnumMember.A; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnEnumMember").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(21, 5), + // (21,18): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // _ = OnEnumMember.A; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "A").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(21, 18), + // (22,1): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnClassTypeParameter onClassTypeParameter; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnClassTypeParameter").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(22, 1), + // (23,1): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnMethodTypeParameter.M(); + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnMethodTypeParameter").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(23, 1), + // (23,23): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnMethodTypeParameter.M(); + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "M").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(23, 23), + // (24,1): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnDelegateType onDelegateType; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnDelegateType").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(24, 1), + // (25,1): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnIndexedPropertyParameter.set_Property(1, 1); + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnIndexedPropertyParameter").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(25, 1), + // (25,28): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // OnIndexedPropertyParameter.set_Property(1, 1); + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "set_Property").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(25, 28), + // (26,5): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // _ = OnIndexedPropertyParameter.get_Property(1); + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnIndexedPropertyParameter").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(26, 5), + // (26,32): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // _ = OnIndexedPropertyParameter.get_Property(1); + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "get_Property").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(26, 32), + // (27,5): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // new OnThisIndexerParameter()[1] = 1; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnThisIndexerParameter").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(27, 5), + // (27,5): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // new OnThisIndexerParameter()[1] = 1; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnThisIndexerParameter").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(27, 5), + // (28,9): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // _ = new OnThisIndexerParameter()[1]; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnThisIndexerParameter").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(28, 9), + // (28,9): error CS9041: 'AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' requires compiler feature 'test', which is not supported by this version of the C# compiler. + // _ = new OnThisIndexerParameter()[1]; + Diagnostic(ErrorCode.ERR_UnsupportedCompilerFeature, "OnThisIndexerParameter").WithArguments("AssemblyTest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", "test").WithLocation(28, 9) + ); + + Assert.True(comp.GetReferencedAssemblySymbol(ilRef).HasUnsupportedMetadata); + } + + [Fact] + public void Application() + { + var comp = CSharpTestBase.CreateCompilation(new[] { """ + using System; + using System.Runtime.CompilerServices; + + [CompilerFeatureRequired("OnType")] + public class OnType + { + } + + public class OnMethod + { + [CompilerFeatureRequired("OnMethod")] + public static void M() {} + } + + public class OnMethodReturn + { + [return: CompilerFeatureRequired("OnMethodReturn")] + public static void M() {} + } + + public class OnParameter + { + public static void M([CompilerFeatureRequired("OnParameter")] int param) {} + } + + public class OnField + { + [CompilerFeatureRequired("OnField")] + public static int Field; + } + + public class OnProperty + { + [CompilerFeatureRequired("OnProperty")] + public static int Property { get => 0; set {} } + } + + public class OnPropertySetter + { + public static int Property { get => 0; [CompilerFeatureRequired("OnPropertySetter")] set {} } + } + + public class OnPropertyGetter + { + public static int Property { [CompilerFeatureRequired("OnPropertyGetter")] get => 0; set {} } + } + + public class OnEvent + { + [CompilerFeatureRequired("OnEvent")] + public static event Action Event { add {} remove {} } + } + + public class OnEventAdder + { + public static event Action Event { [CompilerFeatureRequired("OnEventAdder")] add {} remove {} } + } + + public class OnEventRemover + { + public static event Action Event { [CompilerFeatureRequired("OnEventRemover")] add {} remove {} } + } + + [CompilerFeatureRequired("OnEnum")] + public enum OnEnum + { + A + } + + public enum OnEnumMember + { + [CompilerFeatureRequired("OnEnumMember")] A + } + + public class OnClassTypeParameter<[CompilerFeatureRequired("OnClassTypeParameter")] T> + { + } + + public class OnMethodTypeParameter + { + public static void M<[CompilerFeatureRequired("OnMethodTypeParameter")] T>() {} + } + + [CompilerFeatureRequired("OnDelegateType")] + public delegate void OnDelegateType(); + """, CSharpTestBase.CompilerFeatureRequiredAttribute }); + + comp.VerifyDiagnostics( + // (4,2): error CS8335: Do not use 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute'. This is reserved for compiler usage. + // [CompilerFeatureRequired("OnType")] + Diagnostic(ErrorCode.ERR_ExplicitReservedAttr, @"CompilerFeatureRequired(""OnType"")").WithArguments("System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute").WithLocation(4, 2), + // (11,6): error CS8335: Do not use 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute'. This is reserved for compiler usage. + // [CompilerFeatureRequired("OnMethod")] + Diagnostic(ErrorCode.ERR_ExplicitReservedAttr, @"CompilerFeatureRequired(""OnMethod"")").WithArguments("System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute").WithLocation(11, 6), + // (17,14): error CS8335: Do not use 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute'. This is reserved for compiler usage. + // [return: CompilerFeatureRequired("OnMethodReturn")] + Diagnostic(ErrorCode.ERR_ExplicitReservedAttr, @"CompilerFeatureRequired(""OnMethodReturn"")").WithArguments("System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute").WithLocation(17, 14), + // (23,27): error CS8335: Do not use 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute'. This is reserved for compiler usage. + // public static void M([CompilerFeatureRequired("OnParameter")] int param) {} + Diagnostic(ErrorCode.ERR_ExplicitReservedAttr, @"CompilerFeatureRequired(""OnParameter"")").WithArguments("System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute").WithLocation(23, 27), + // (28,6): error CS8335: Do not use 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute'. This is reserved for compiler usage. + // [CompilerFeatureRequired("OnField")] + Diagnostic(ErrorCode.ERR_ExplicitReservedAttr, @"CompilerFeatureRequired(""OnField"")").WithArguments("System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute").WithLocation(28, 6), + // (34,6): error CS8335: Do not use 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute'. This is reserved for compiler usage. + // [CompilerFeatureRequired("OnProperty")] + Diagnostic(ErrorCode.ERR_ExplicitReservedAttr, @"CompilerFeatureRequired(""OnProperty"")").WithArguments("System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute").WithLocation(34, 6), + // (40,45): error CS8335: Do not use 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute'. This is reserved for compiler usage. + // public static int Property { get => 0; [CompilerFeatureRequired("OnPropertySetter")] set {} } + Diagnostic(ErrorCode.ERR_ExplicitReservedAttr, @"CompilerFeatureRequired(""OnPropertySetter"")").WithArguments("System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute").WithLocation(40, 45), + // (45,35): error CS8335: Do not use 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute'. This is reserved for compiler usage. + // public static int Property { [CompilerFeatureRequired("OnPropertyGetter")] get => 0; set {} } + Diagnostic(ErrorCode.ERR_ExplicitReservedAttr, @"CompilerFeatureRequired(""OnPropertyGetter"")").WithArguments("System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute").WithLocation(45, 35), + // (50,6): error CS8335: Do not use 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute'. This is reserved for compiler usage. + // [CompilerFeatureRequired("OnEvent")] + Diagnostic(ErrorCode.ERR_ExplicitReservedAttr, @"CompilerFeatureRequired(""OnEvent"")").WithArguments("System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute").WithLocation(50, 6), + // (56,41): error CS8335: Do not use 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute'. This is reserved for compiler usage. + // public static event Action Event { [CompilerFeatureRequired("OnEventAdder")] add {} remove {} } + Diagnostic(ErrorCode.ERR_ExplicitReservedAttr, @"CompilerFeatureRequired(""OnEventAdder"")").WithArguments("System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute").WithLocation(56, 41), + // (61,41): error CS8335: Do not use 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute'. This is reserved for compiler usage. + // public static event Action Event { [CompilerFeatureRequired("OnEventRemover")] add {} remove {} } + Diagnostic(ErrorCode.ERR_ExplicitReservedAttr, @"CompilerFeatureRequired(""OnEventRemover"")").WithArguments("System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute").WithLocation(61, 41), + // (64,2): error CS8335: Do not use 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute'. This is reserved for compiler usage. + // [CompilerFeatureRequired("OnEnum")] + Diagnostic(ErrorCode.ERR_ExplicitReservedAttr, @"CompilerFeatureRequired(""OnEnum"")").WithArguments("System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute").WithLocation(64, 2), + // (72,6): error CS8335: Do not use 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute'. This is reserved for compiler usage. + // [CompilerFeatureRequired("OnEnumMember")] A + Diagnostic(ErrorCode.ERR_ExplicitReservedAttr, @"CompilerFeatureRequired(""OnEnumMember"")").WithArguments("System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute").WithLocation(72, 6), + // (75,36): error CS8335: Do not use 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute'. This is reserved for compiler usage. + // public class OnClassTypeParameter<[CompilerFeatureRequired("OnClassTypeParameter")] T> + Diagnostic(ErrorCode.ERR_ExplicitReservedAttr, @"CompilerFeatureRequired(""OnClassTypeParameter"")").WithArguments("System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute").WithLocation(75, 36), + // (81,27): error CS8335: Do not use 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute'. This is reserved for compiler usage. + // public static void M<[CompilerFeatureRequired("OnMethodTypeParameter")] T>() {} + Diagnostic(ErrorCode.ERR_ExplicitReservedAttr, @"CompilerFeatureRequired(""OnMethodTypeParameter"")").WithArguments("System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute").WithLocation(81, 27), + // (84,2): error CS8335: Do not use 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute'. This is reserved for compiler usage. + // [CompilerFeatureRequired("OnDelegateType")] + Diagnostic(ErrorCode.ERR_ExplicitReservedAttr, @"CompilerFeatureRequired(""OnDelegateType"")").WithArguments("System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute").WithLocation(84, 2) + ); + } +} diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/MissingSpecialMember.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/MissingSpecialMember.cs index 9c2d6db7b4322..ed06e428959e9 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/MissingSpecialMember.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/MissingSpecialMember.cs @@ -611,7 +611,10 @@ public void AllWellKnownTypes() case WellKnownType.System_Runtime_CompilerServices_NativeIntegerAttribute: case WellKnownType.System_Runtime_CompilerServices_IsExternalInit: case WellKnownType.System_Runtime_CompilerServices_DefaultInterpolatedStringHandler: + case WellKnownType.System_Runtime_CompilerServices_RequiredMemberAttribute: + case WellKnownType.System_Diagnostics_CodeAnalysis_SetsRequiredMembersAttribute: case WellKnownType.System_MemoryExtensions: + case WellKnownType.System_Runtime_CompilerServices_CompilerFeatureRequiredAttribute: // Not yet in the platform. continue; case WellKnownType.Microsoft_CodeAnalysis_Runtime_Instrumentation: @@ -969,9 +972,12 @@ public void AllWellKnownTypeMembers() case WellKnownMember.System_Runtime_CompilerServices_NativeIntegerAttribute__ctor: case WellKnownMember.System_Runtime_CompilerServices_NativeIntegerAttribute__ctorTransformFlags: case WellKnownMember.System_Runtime_CompilerServices_DefaultInterpolatedStringHandler__ToStringAndClear: + case WellKnownMember.System_Runtime_CompilerServices_RequiredMemberAttribute__ctor: + case WellKnownMember.System_Diagnostics_CodeAnalysis_SetsRequiredMembersAttribute__ctor: case WellKnownMember.System_MemoryExtensions__SequenceEqual_Span_T: case WellKnownMember.System_MemoryExtensions__SequenceEqual_ReadOnlySpan_T: case WellKnownMember.System_MemoryExtensions__AsSpan_String: + case WellKnownMember.System_Runtime_CompilerServices_CompilerFeatureRequiredAttribute__ctor: // Not yet in the platform. continue; case WellKnownMember.Microsoft_CodeAnalysis_Runtime_Instrumentation__CreatePayloadForMethodsSpanningSingleFile: diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/MockNamedTypeSymbol.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/MockNamedTypeSymbol.cs index bdb7812c8f2d7..d5e358d3b6939 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/MockNamedTypeSymbol.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/MockNamedTypeSymbol.cs @@ -89,6 +89,8 @@ public override IEnumerable MemberNames } } + internal override bool HasDeclaredRequiredMembers => throw new NotImplementedException(); + public override ImmutableArray GetMembers() { return _children.AsImmutable(); diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/RequiredMembersTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/RequiredMembersTests.cs new file mode 100644 index 0000000000000..190ca0cc07578 --- /dev/null +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/RequiredMembersTests.cs @@ -0,0 +1,4531 @@ +// 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.Generic; +using System.Linq; +using Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE; +using Microsoft.CodeAnalysis.CSharp.Symbols.Retargeting; +using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Symbols; + +[CompilerTrait(CompilerFeature.RequiredMembers)] +public class RequiredMembersTests : CSharpTestBase +{ + private const string RequiredMemberAttributeVB = @" +Namespace System.Runtime.CompilerServices + + Public Class RequiredMemberAttribute + Inherits Attribute + End Class +End Namespace +Namespace System.Diagnostics.CodeAnalysis + + Public Class SetsRequiredMembersAttribute + Inherits Attribute + End Class +End Namespace"; + + private static CSharpCompilation CreateCompilationWithRequiredMembers(CSharpTestSource source, IEnumerable? references = null, CSharpParseOptions? parseOptions = null, CSharpCompilationOptions? options = null, string? assemblyName = null, TargetFramework targetFramework = TargetFramework.Standard) + => CreateCompilation(new[] { source, RequiredMemberAttribute, SetsRequiredMembersAttribute, CompilerFeatureRequiredAttribute }, references, options: options, parseOptions: parseOptions, assemblyName: assemblyName, targetFramework: targetFramework); + + private Compilation CreateVisualBasicCompilationWithRequiredMembers(string source) + => CreateVisualBasicCompilation(new[] { source, RequiredMemberAttributeVB }); + + private static Action ValidateRequiredMembersInModule(string[] memberPaths, string expectedAttributeLayout) + { + return module => + { + if (module is PEModuleSymbol peModule) + { + var actualAttributes = RequiredMemberAttributesVisitor.GetString(peModule); + AssertEx.AssertEqualToleratingWhitespaceDifferences(expectedAttributeLayout, actualAttributes); + } + + var requiredTypes = new HashSet(); + + foreach (var memberPath in memberPaths) + { + var member = module.GlobalNamespace.GetMember(memberPath); + AssertEx.NotNull(member, $"Member {memberPath} was not found"); + Assert.True(member is PropertySymbol or FieldSymbol, $"Unexpected member symbol type {member.Kind}"); + Assert.True(member.IsRequired()); + if (module is SourceModuleSymbol) + { + Assert.All(member.GetAttributes(), attr => AssertEx.NotEqual("System.Runtime.CompilerServices.RequiredMemberAttribute", attr.AttributeClass.ToTestDisplayString())); + } + else + { + AssertEx.Any(member.GetAttributes(), attr => attr.AttributeClass.ToTestDisplayString() == "System.Runtime.CompilerServices.RequiredMemberAttribute"); + } + + requiredTypes.Add((NamedTypeSymbol)member.ContainingType); + } + + foreach (var type in requiredTypes) + { + AssertTypeRequiredMembersInvariants(module, type); + } + }; + } + + private static Action GetTypeRequiredMembersInvariantsValidator(string expectedType) + { + return module => + { + var type = module.GlobalNamespace.GetTypeMember(expectedType); + Assert.NotNull(type); + AssertTypeRequiredMembersInvariants(module, type); + }; + } + + private static void AssertTypeRequiredMembersInvariants(ModuleSymbol module, NamedTypeSymbol type) + { + Assert.True(type.HasAnyRequiredMembers); + + var peModule = module as PEModuleSymbol; + foreach (var ctor in type.GetMembers().Where(m => m is MethodSymbol { MethodKind: MethodKind.Constructor })) + { + var ctorAttributes = ctor.GetAttributes(); + + // Attributes should be filtered out when loaded from metadata, and are only added during emit in source + Assert.DoesNotContain(ctorAttributes, attr => attr.AttributeClass.ToTestDisplayString() is "System.ObsoleteAttribute" or "System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute"); + + if (peModule is not null) + { + var peMethod = (PEMethodSymbol)ctor; + var decoder = new MetadataDecoder(peModule, peMethod); + var obsoleteAttribute = peModule.Module.TryGetDeprecatedOrExperimentalOrObsoleteAttribute(peMethod.Handle, decoder, ignoreByRefLikeMarker: false, ignoreRequiredMemberMarker: false); + string? unsupportedCompilerFeatureToken = peModule.Module.GetFirstUnsupportedCompilerFeatureFromToken(peMethod.Handle, decoder, CompilerFeatureRequiredFeatures.None); + + if (ctorAttributes.Any(attr => attr.AttributeClass.ToTestDisplayString() == "System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute")) + { + Assert.Null(obsoleteAttribute); + Assert.Null(unsupportedCompilerFeatureToken); + } + else + { + Assert.NotNull(obsoleteAttribute); + Assert.Equal(PEModule.RequiredMembersMarker, obsoleteAttribute.Message); + Assert.True(obsoleteAttribute.IsError); + + Assert.Equal(nameof(CompilerFeatureRequiredFeatures.RequiredMembers), unsupportedCompilerFeatureToken); + Assert.Null(peModule.Module.GetFirstUnsupportedCompilerFeatureFromToken(peMethod.Handle, decoder, CompilerFeatureRequiredFeatures.RequiredMembers)); + } + } + } + } + + [Fact] + public void InvalidModifierLocations() + { + var comp = CreateCompilationWithRequiredMembers(@" +required class C1 +{ + required void M(required int i) + { + } + + required C1() { } + required ~C1() { } + + required int this[int i] { get => 0; set { } } + + int Prop1 { required get; } + int Prop2 { required set { } } +} +required struct S {} +required delegate void D(); +required interface I1 +{ + required int Prop3 { get; set; } + required int Field; +} +interface I2 +{ + public int Prop4 { get; } +} +class C2 : I2 +{ + required int I2.Prop4 => 0; +} +"); + + comp.VerifyDiagnostics( + // (2,16): error CS0106: The modifier 'required' is not valid for this item + // required class C1 + Diagnostic(ErrorCode.ERR_BadMemberFlag, "C1").WithArguments("required").WithLocation(2, 16), + // (4,19): error CS0106: The modifier 'required' is not valid for this item + // required void M(required int i) + Diagnostic(ErrorCode.ERR_BadMemberFlag, "M").WithArguments("required").WithLocation(4, 19), + // (4,21): error CS0246: The type or namespace name 'required' could not be found (are you missing a using directive or an assembly reference?) + // required void M(required int i) + Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "required").WithArguments("required").WithLocation(4, 21), + // (4,30): error CS1001: Identifier expected + // required void M(required int i) + Diagnostic(ErrorCode.ERR_IdentifierExpected, "int").WithLocation(4, 30), + // (4,30): error CS1003: Syntax error, ',' expected + // required void M(required int i) + Diagnostic(ErrorCode.ERR_SyntaxError, "int").WithArguments(",").WithLocation(4, 30), + // (8,14): error CS0106: The modifier 'required' is not valid for this item + // required C1() { } + Diagnostic(ErrorCode.ERR_BadMemberFlag, "C1").WithArguments("required").WithLocation(8, 14), + // (9,15): error CS0106: The modifier 'required' is not valid for this item + // required ~C1() { } + Diagnostic(ErrorCode.ERR_BadMemberFlag, "C1").WithArguments("required").WithLocation(9, 15), + // (11,18): error CS0106: The modifier 'required' is not valid for this item + // required int this[int i] { get => 0; set { } } + Diagnostic(ErrorCode.ERR_BadMemberFlag, "this").WithArguments("required").WithLocation(11, 18), + // (13,26): error CS0106: The modifier 'required' is not valid for this item + // int Prop1 { required get; } + Diagnostic(ErrorCode.ERR_BadMemberFlag, "get").WithArguments("required").WithLocation(13, 26), + // (14,26): error CS0106: The modifier 'required' is not valid for this item + // int Prop2 { required set { } } + Diagnostic(ErrorCode.ERR_BadMemberFlag, "set").WithArguments("required").WithLocation(14, 26), + // (16,17): error CS0106: The modifier 'required' is not valid for this item + // required struct S {} + Diagnostic(ErrorCode.ERR_BadMemberFlag, "S").WithArguments("required").WithLocation(16, 17), + // (17,24): error CS0106: The modifier 'required' is not valid for this item + // required delegate void D(); + Diagnostic(ErrorCode.ERR_BadMemberFlag, "D").WithArguments("required").WithLocation(17, 24), + // (18,20): error CS0106: The modifier 'required' is not valid for this item + // required interface I1 + Diagnostic(ErrorCode.ERR_BadMemberFlag, "I1").WithArguments("required").WithLocation(18, 20), + // (20,18): error CS0106: The modifier 'required' is not valid for this item + // required int Prop3 { get; set; } + Diagnostic(ErrorCode.ERR_BadMemberFlag, "Prop3").WithArguments("required").WithLocation(20, 18), + // (21,18): error CS0525: Interfaces cannot contain instance fields + // required int Field; + Diagnostic(ErrorCode.ERR_InterfacesCantContainFields, "Field").WithLocation(21, 18), + // (21,18): warning CS0649: Field 'I1.Field' is never assigned to, and will always have its default value 0 + // required int Field; + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "Field").WithArguments("I1.Field", "0").WithLocation(21, 18), + // (29,21): error CS0106: The modifier 'required' is not valid for this item + // required int I2.Prop4 => 0; + Diagnostic(ErrorCode.ERR_BadMemberFlag, "Prop4").WithArguments("required").WithLocation(29, 21) + ); + } + + [Fact] + public void InvalidModifierCombinations() + { + var comp = CreateCompilationWithRequiredMembers(@" +unsafe struct C +{ + required const int F1 = 1; + required static int F2 = 2; + required static int P1 { get; set; } + required fixed int F3[10]; +} +", options: TestOptions.UnsafeReleaseDll); + + comp.VerifyDiagnostics( + // (4,24): error CS0106: The modifier 'required' is not valid for this item + // required const int F1 = 1; + Diagnostic(ErrorCode.ERR_BadMemberFlag, "F1").WithArguments("required").WithLocation(4, 24), + // (5,25): error CS0106: The modifier 'required' is not valid for this item + // required static int F2 = 2; + Diagnostic(ErrorCode.ERR_BadMemberFlag, "F2").WithArguments("required").WithLocation(5, 25), + // (5,25): warning CS0414: The field 'C.F2' is assigned but its value is never used + // required static int F2 = 2; + Diagnostic(ErrorCode.WRN_UnreferencedFieldAssg, "F2").WithArguments("C.F2").WithLocation(5, 25), + // (6,25): error CS0106: The modifier 'required' is not valid for this item + // required static int P1 { get; set; } + Diagnostic(ErrorCode.ERR_BadMemberFlag, "P1").WithArguments("required").WithLocation(6, 25), + // (7,24): error CS0106: The modifier 'required' is not valid for this item + // required fixed int F3[10]; + Diagnostic(ErrorCode.ERR_BadMemberFlag, "F3").WithArguments("required").WithLocation(7, 24) + ); + } + + [Fact] + public void LangVersion() + { + string code = @" +#pragma warning disable CS0649 // Field is never assigned +class C +{ + internal required int Field; + internal required int Prop { get; set; } +} +"; + var comp = CreateCompilationWithRequiredMembers(code, parseOptions: TestOptions.Regular10); + + comp.VerifyDiagnostics( + // (5,27): error CS8652: The feature 'required members' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // internal required int Field; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Field").WithArguments("required members").WithLocation(5, 27), + // (6,27): error CS8652: The feature 'required members' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // internal required int Prop { get; set; } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Prop").WithArguments("required members").WithLocation(6, 27) + ); + + comp = CreateCompilationWithRequiredMembers(code, parseOptions: TestOptions.RegularNext); + comp.VerifyDiagnostics(); + } + + [Fact] + public void DuplicateKeyword() + { + var comp = CreateCompilationWithRequiredMembers(@" +class C +{ + internal required required int Field; + internal required required int Prop { get; set; } +} +"); + + comp.VerifyDiagnostics( + // (4,23): error CS1004: Duplicate 'required' modifier + // internal required required int Field; + Diagnostic(ErrorCode.ERR_DuplicateModifier, "required").WithArguments("required").WithLocation(4, 23), + // (4,36): warning CS0649: Field 'C.Field' is never assigned to, and will always have its default value 0 + // internal required required int Field; + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "Field").WithArguments("C.Field", "0").WithLocation(4, 36), + // (5,23): error CS1004: Duplicate 'required' modifier + // internal required required int Prop { get; set; } + Diagnostic(ErrorCode.ERR_DuplicateModifier, "required").WithArguments("required").WithLocation(5, 23) + ); + } + + [Theory] + [CombinatorialData] + public void InvalidNames(bool use10) + { + string code = @" +namespace N1 +{ + struct required {} +} +namespace N2 +{ + class required {} +} +namespace N3 +{ + interface required {} +} +namespace N4 +{ + delegate void required(); +} +namespace N5 +{ + record required(); +} +namespace N6 +{ + record struct required(); +} +namespace N7 +{ + class C + { + class required {} + } +} +namespace N8 +{ + class required {} +} +"; + var comp = CreateCompilationWithRequiredMembers(code, parseOptions: use10 ? TestOptions.Regular10 : TestOptions.RegularNext); + + comp.VerifyDiagnostics( + use10 ? + new[] + { + // (4,12): warning CS8981: The type name 'required' only contains lower-cased ascii characters. Such names may become reserved for the language. + // struct required {} + Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "required").WithArguments("required").WithLocation(4, 12), + // (8,11): warning CS8981: The type name 'required' only contains lower-cased ascii characters. Such names may become reserved for the language. + // class required {} + Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "required").WithArguments("required").WithLocation(8, 11), + // (12,15): warning CS8981: The type name 'required' only contains lower-cased ascii characters. Such names may become reserved for the language. + // interface required {} + Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "required").WithArguments("required").WithLocation(12, 15), + // (16,19): warning CS8981: The type name 'required' only contains lower-cased ascii characters. Such names may become reserved for the language. + // delegate void required(); + Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "required").WithArguments("required").WithLocation(16, 19), + // (20,12): warning CS8981: The type name 'required' only contains lower-cased ascii characters. Such names may become reserved for the language. + // record required(); + Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "required").WithArguments("required").WithLocation(20, 12), + // (24,19): warning CS8981: The type name 'required' only contains lower-cased ascii characters. Such names may become reserved for the language. + // record struct required(); + Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "required").WithArguments("required").WithLocation(24, 19), + // (30,15): warning CS8981: The type name 'required' only contains lower-cased ascii characters. Such names may become reserved for the language. + // class required {} + Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "required").WithArguments("required").WithLocation(30, 15), + // (35,11): warning CS8981: The type name 'required' only contains lower-cased ascii characters. Such names may become reserved for the language. + // class required {} + Diagnostic(ErrorCode.WRN_LowerCaseTypeName, "required").WithArguments("required").WithLocation(35, 11) + } : + new[] + { + // (4,12): error CS9029: Types and aliases cannot be named 'required'. + // struct required {} + Diagnostic(ErrorCode.ERR_RequiredNameDisallowed, "required").WithLocation(4, 12), + // (8,11): error CS9029: Types and aliases cannot be named 'required'. + // class required {} + Diagnostic(ErrorCode.ERR_RequiredNameDisallowed, "required").WithLocation(8, 11), + // (12,15): error CS9029: Types and aliases cannot be named 'required'. + // interface required {} + Diagnostic(ErrorCode.ERR_RequiredNameDisallowed, "required").WithLocation(12, 15), + // (16,19): error CS9029: Types and aliases cannot be named 'required'. + // delegate void required(); + Diagnostic(ErrorCode.ERR_RequiredNameDisallowed, "required").WithLocation(16, 19), + // (20,12): error CS9029: Types and aliases cannot be named 'required'. + // record required(); + Diagnostic(ErrorCode.ERR_RequiredNameDisallowed, "required").WithLocation(20, 12), + // (24,19): error CS9029: Types and aliases cannot be named 'required'. + // record struct required(); + Diagnostic(ErrorCode.ERR_RequiredNameDisallowed, "required").WithLocation(24, 19), + // (30,15): error CS9029: Types and aliases cannot be named 'required'. + // class required {} + Diagnostic(ErrorCode.ERR_RequiredNameDisallowed, "required").WithLocation(30, 15), + // (35,11): error CS9029: Types and aliases cannot be named 'required'. + // class required {} + Diagnostic(ErrorCode.ERR_RequiredNameDisallowed, "required").WithLocation(35, 11) + } + ); + + code = code.Replace("required", "@required"); + comp = CreateCompilationWithRequiredMembers(code, parseOptions: use10 ? TestOptions.Regular10 : TestOptions.RegularNext); + comp.VerifyDiagnostics(); + } + + [Fact] + public void MissingRequiredMemberAttribute() + { + var comp = CreateCompilationWithRequiredMembers(@" +class C +{ + public required int I { get; set; } +}"); + + comp.MakeTypeMissing(WellKnownType.System_Runtime_CompilerServices_RequiredMemberAttribute); + + // (2,7): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.RequiredMemberAttribute..ctor' + // class C + var expected = Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "C").WithArguments("System.Runtime.CompilerServices.RequiredMemberAttribute", ".ctor").WithLocation(2, 7); + comp.VerifyDiagnostics(expected); + comp.VerifyEmitDiagnostics(expected); + } + + [Fact] + public void MissingRequiredMemberAttributeCtor() + { + var comp = CreateCompilationWithRequiredMembers(@" +class C +{ + public required int I { get; set; } +} +"); + + comp.MakeMemberMissing(WellKnownMember.System_Runtime_CompilerServices_RequiredMemberAttribute__ctor); + + // (2,7): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.RequiredMemberAttribute..ctor' + // class C + var expected = Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "C").WithArguments("System.Runtime.CompilerServices.RequiredMemberAttribute", ".ctor").WithLocation(2, 7); + comp.VerifyDiagnostics(expected); + comp.VerifyEmitDiagnostics(expected); + } + + [Fact] + public void MissingCompilerFeatureRequiredAttribute() + { + var comp = CreateCompilationWithRequiredMembers(@" +class C +{ + public required int I { get; set; } +}"); + + comp.MakeTypeMissing(WellKnownType.System_Runtime_CompilerServices_CompilerFeatureRequiredAttribute); + + // (2,7): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute..ctor' + // class C + var expected = Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "C").WithArguments("System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute", ".ctor").WithLocation(2, 7); + + comp.VerifyDiagnostics(expected); + comp.VerifyEmitDiagnostics(expected); + } + + [Fact] + public void MissingCompilerFeatureRequiredAttributeCtor() + { + var comp = CreateCompilationWithRequiredMembers(@" +class C +{ + public required int I { get; set; } +} +"); + + comp.MakeMemberMissing(WellKnownMember.System_Runtime_CompilerServices_CompilerFeatureRequiredAttribute__ctor); + + // (2,7): error CS0656: Missing compiler required member 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute..ctor' + // class C + var expected = Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "C").WithArguments("System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute", ".ctor").WithLocation(2, 7); + comp.VerifyDiagnostics(expected); + comp.VerifyEmitDiagnostics(expected); + } + + [Fact] + public void RequiredMemberAttributeEmitted() + { + var comp = CreateCompilationWithRequiredMembers(@" +class C +{ + public required int Prop { get; set; } + public required int Field; +} +"); + + var expectedRequiredMembers = new[] { "C.Prop", "C.Field" }; + + var expectedAttributeLayout = @" +[RequiredMember] C + [RequiredMember] System.Int32 C.Field + [RequiredMember] System.Int32 C.Prop { get; set; } +"; + + var symbolValidator = ValidateRequiredMembersInModule(expectedRequiredMembers, expectedAttributeLayout); + var verifier = CompileAndVerify(comp, sourceSymbolValidator: symbolValidator, symbolValidator: symbolValidator); + verifier.VerifyDiagnostics( + // (5,25): warning CS0649: Field 'C.Field' is never assigned to, and will always have its default value 0 + // public required int Field; + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "Field").WithArguments("C.Field", "0").WithLocation(5, 25) + ); + } + + [Theory] + [CombinatorialData] + public void RequiredMemberAttributeEmitted_OverrideRequiredProperty_MissingRequiredOnOverride01(bool useMetadataReference) + { + var @base = @" +public class Base +{ + public virtual required int Prop { get; set; } +}"; + + var derived = @" +class Derived : Base +{ + public override int Prop { get; set; } +} +"; + + var comp = CreateCompilationWithRequiredMembers(@base + derived); + + comp.VerifyDiagnostics( + // (8,25): error CS9030: 'Derived.Prop' must be required because it overrides required member 'Base.Prop' + // public override int Prop { get; set; } + Diagnostic(ErrorCode.ERR_OverrideMustHaveRequired, "Prop").WithArguments("Derived.Prop", "Base.Prop").WithLocation(8, 25) + ); + + var baseComp = CreateCompilationWithRequiredMembers(@base); + baseComp.VerifyDiagnostics(); + + comp = CreateCompilation(derived, references: new[] { useMetadataReference ? baseComp.ToMetadataReference() : baseComp.EmitToImageReference() }); + comp.VerifyDiagnostics( + // (4,25): error CS9030: 'Derived.Prop' must be required because it overrides required member 'Base.Prop' + // public override int Prop { get; set; } + Diagnostic(ErrorCode.ERR_OverrideMustHaveRequired, "Prop").WithArguments("Derived.Prop", "Base.Prop").WithLocation(4, 25) + ); + } + + [Theory] + [CombinatorialData] + public void RequiredMemberAttributeEmitted_OverrideRequiredProperty_MissingRequiredOnOverride02(bool useMetadataReference) + { + var @base = @" +public class Base +{ + public virtual int Prop { get; set; } +}"; + + var derived = @" +public class Derived : Base +{ + public override required int Prop { get; set; } +}"; + + var derivedDerived = @" +class DerivedDerived : Derived +{ + public override int Prop { get; set; } +} +"; + + var comp = CreateCompilationWithRequiredMembers(@base + derived + derivedDerived); + + comp.VerifyDiagnostics( + // (12,25): error CS9030: 'DerivedDerived.Prop' must be required because it overrides required member 'Derived.Prop' + // public override int Prop { get; set; } + Diagnostic(ErrorCode.ERR_OverrideMustHaveRequired, "Prop").WithArguments("DerivedDerived.Prop", "Derived.Prop").WithLocation(12, 25) + ); + + var baseComp = CreateCompilationWithRequiredMembers(@base); + baseComp.VerifyDiagnostics(); + + MetadataReference baseReference = useMetadataReference ? baseComp.ToMetadataReference() : baseComp.EmitToImageReference(); + var derivedComp = CreateCompilation(derived, references: new[] { baseReference }); + derivedComp.VerifyDiagnostics(); + + comp = CreateCompilation(derivedDerived, new[] { baseReference, useMetadataReference ? derivedComp.ToMetadataReference() : derivedComp.EmitToImageReference() }); + comp.VerifyDiagnostics( + // (4,25): error CS9030: 'DerivedDerived.Prop' must be required because it overrides required member 'Derived.Prop' + // public override int Prop { get; set; } + Diagnostic(ErrorCode.ERR_OverrideMustHaveRequired, "Prop").WithArguments("DerivedDerived.Prop", "Derived.Prop").WithLocation(4, 25) + ); + } + + [Theory] + [CombinatorialData] + public void RequiredMemberAttributeEmitted_OverrideRequiredProperty(bool useMetadataReference) + { + var @base = @" +public class Base +{ + public virtual required int Prop { get; set; } +} +"; + + string derived = @" +class Derived : Base +{ + public override required int Prop { get; set; } +} +"; + var comp = CreateCompilationWithRequiredMembers(@base + derived); + + var expectedRequiredMembers = new[] { "Base.Prop", "Derived.Prop" }; + + var expectedAttributeLayout = @" +[RequiredMember] Base + [RequiredMember] System.Int32 Base.Prop { get; set; } +[RequiredMember] Derived + [RequiredMember] System.Int32 Derived.Prop { get; set; }"; + + var symbolValidator = ValidateRequiredMembersInModule(expectedRequiredMembers, expectedAttributeLayout); + var verifier = CompileAndVerify(comp, sourceSymbolValidator: symbolValidator, symbolValidator: symbolValidator); + verifier.VerifyDiagnostics(); + + var baseComp = CreateCompilationWithRequiredMembers(@base, assemblyName: "test"); + baseComp.VerifyDiagnostics(); + + comp = CreateCompilation(derived, new[] { useMetadataReference ? baseComp.ToMetadataReference() : baseComp.EmitToImageReference() }); + expectedAttributeLayout = @" +[RequiredMember] Derived + [RequiredMember] System.Int32 Derived.Prop { get; set; } +"; + symbolValidator = ValidateRequiredMembersInModule(new[] { "Derived.Prop" }, expectedAttributeLayout); + verifier = CompileAndVerify(comp, symbolValidator: symbolValidator, sourceSymbolValidator: symbolValidator); + verifier.VerifyDiagnostics(); + } + + [Theory] + [CombinatorialData] + public void RequiredMemberAttributeEmitted_AddRequiredOnOverride(bool useMetadataReference) + { + var @base = @" +public class Base +{ + public virtual int Prop { get; set; } +} +"; + + var derived = @" +public class Derived : Base +{ + public override required int Prop { get; set; } +} +"; + + var derivedDerived = @" +class DerivedDerived : Derived +{ + public override required int Prop { get; set; } +} +"; + var comp = CreateCompilationWithRequiredMembers(@base + derived + derivedDerived); + + var expectedRequiredMembers = new[] { "Derived.Prop", "DerivedDerived.Prop" }; + + var expectedAttributeLayout = @" +[RequiredMember] Derived + [RequiredMember] System.Int32 Derived.Prop { get; set; } +[RequiredMember] DerivedDerived + [RequiredMember] System.Int32 DerivedDerived.Prop { get; set; } +"; + + var symbolValidator = ValidateRequiredMembersInModule(expectedRequiredMembers, expectedAttributeLayout); + var verifier = CompileAndVerify(comp, sourceSymbolValidator: symbolValidator, symbolValidator: symbolValidator); + verifier.VerifyDiagnostics(); + + var baseComp = CreateCompilationWithRequiredMembers(@base); + baseComp.VerifyDiagnostics(); + var baseReference = useMetadataReference ? baseComp.ToMetadataReference() : baseComp.EmitToImageReference(); + + var derivedComp = CreateCompilation(derived, new[] { baseReference }); + derivedComp.VerifyDiagnostics(); + + comp = CreateCompilation(derivedDerived, new[] { baseReference, useMetadataReference ? derivedComp.ToMetadataReference() : derivedComp.EmitToImageReference() }); + expectedAttributeLayout = @" +[RequiredMember] DerivedDerived + [RequiredMember] System.Int32 DerivedDerived.Prop { get; set; } +"; + symbolValidator = ValidateRequiredMembersInModule(new[] { "DerivedDerived.Prop" }, expectedAttributeLayout); + verifier = CompileAndVerify(comp, sourceSymbolValidator: symbolValidator, symbolValidator: symbolValidator); + verifier.VerifyDiagnostics(); + } + + [Fact] + public void RequiredMemberAttributeEmitted_NestedTypeHasRequired() + { + var comp = CreateCompilationWithRequiredMembers(@" +class Outer +{ + class Inner + { + public required int Prop { get; set; } + public required int Field; + } +} +"); + + var expectedRequiredMembers = new[] { "Outer.Inner.Prop", "Outer.Inner.Field" }; + + var expectedAttributeLayout = @" +Outer + [RequiredMember] Outer.Inner + [RequiredMember] System.Int32 Outer.Inner.Field + [RequiredMember] System.Int32 Outer.Inner.Prop { get; set; }"; + + var symbolValidator = ValidateRequiredMembersInModule(expectedRequiredMembers, expectedAttributeLayout); + var verifier = CompileAndVerify(comp, sourceSymbolValidator: symbolValidator, symbolValidator: symbolValidator); + verifier.VerifyDiagnostics( + // (7,29): warning CS0649: Field 'Outer.Inner.Field' is never assigned to, and will always have its default value 0 + // public required int Field; + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "Field").WithArguments("Outer.Inner.Field", "0").WithLocation(7, 29) + ); + } + + [Theory] + [CombinatorialData] + public void RequiredMemberAttributeEmitted_AbstractProperty(bool useMetadataReference) + { + var @base = @" +public abstract class Base +{ + public required abstract int Prop { get; set; } +}"; + + var derived = @" +class Derived : Base +{ + public override required int Prop { get; set; } +} +"; + var comp = CreateCompilationWithRequiredMembers(@base + derived); + + var expectedRequiredMembers = new[] { "Base.Prop", "Derived.Prop" }; + + var expectedAttributeLayout = @" +[RequiredMember] Base + [RequiredMember] System.Int32 Base.Prop { get; set; } +[RequiredMember] Derived + [RequiredMember] System.Int32 Derived.Prop { get; set; } +"; + + var symbolValidator = ValidateRequiredMembersInModule(expectedRequiredMembers, expectedAttributeLayout); + var verifier = CompileAndVerify(comp, sourceSymbolValidator: symbolValidator, symbolValidator: symbolValidator); + verifier.VerifyDiagnostics(); + + var baseComp = CreateCompilationWithRequiredMembers(@base, assemblyName: "base"); + baseComp.VerifyDiagnostics(); + var baseReference = useMetadataReference ? baseComp.ToMetadataReference() : baseComp.EmitToImageReference(); + + comp = CreateCompilation(derived, new[] { baseReference }, assemblyName: "derived"); + + expectedAttributeLayout = @" +[RequiredMember] Derived + [RequiredMember] System.Int32 Derived.Prop { get; set; } +"; + + symbolValidator = ValidateRequiredMembersInModule(new[] { "Derived.Prop" }, expectedAttributeLayout); + verifier = CompileAndVerify(comp, sourceSymbolValidator: symbolValidator, symbolValidator: symbolValidator); + verifier.VerifyDiagnostics(); + } + + [Theory] + [CombinatorialData] + public void HidingRequiredMembers(bool useMetadataReference) + { + var @base = +@" +#pragma warning disable CS0649 // Never assigned +public class Base +{ + public required int Field; + public required int Prop { get; set; } +}"; + + var derived = @" +class Derived1 : Base +{ + public new int Field; // 1 + public new int Prop { get; set; } // 2 +} +class Derived2 : Base +{ + public new int Prop; // 3 + public new int Field { get; set; } // 4 +} +class Derived3 : Base +{ + public int Field; // 1 + public int Prop { get; set; } // 2 +} +"; + var comp = CreateCompilationWithRequiredMembers(@base + derived); + + comp.VerifyDiagnostics( + // (10,20): error CS9031: Required member 'Base.Field' cannot be hidden by 'Derived1.Field'. + // public new int Field; // 1 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeHidden, "Field").WithArguments("Base.Field", "Derived1.Field").WithLocation(10, 20), + // (11,20): error CS9031: Required member 'Base.Prop' cannot be hidden by 'Derived1.Prop'. + // public new int Prop { get; set; } // 2 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeHidden, "Prop").WithArguments("Base.Prop", "Derived1.Prop").WithLocation(11, 20), + // (15,20): error CS9031: Required member 'Base.Prop' cannot be hidden by 'Derived2.Prop'. + // public new int Prop; // 3 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeHidden, "Prop").WithArguments("Base.Prop", "Derived2.Prop").WithLocation(15, 20), + // (16,20): error CS9031: Required member 'Base.Field' cannot be hidden by 'Derived2.Field'. + // public new int Field { get; set; } // 4 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeHidden, "Field").WithArguments("Base.Field", "Derived2.Field").WithLocation(16, 20), + // (20,16): warning CS0108: 'Derived3.Field' hides inherited member 'Base.Field'. Use the new keyword if hiding was intended. + // public int Field; // 1 + Diagnostic(ErrorCode.WRN_NewRequired, "Field").WithArguments("Derived3.Field", "Base.Field").WithLocation(20, 16), + // (20,16): error CS9031: Required member 'Base.Field' cannot be hidden by 'Derived3.Field'. + // public int Field; // 1 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeHidden, "Field").WithArguments("Base.Field", "Derived3.Field").WithLocation(20, 16), + // (21,16): error CS9031: Required member 'Base.Prop' cannot be hidden by 'Derived3.Prop'. + // public int Prop { get; set; } // 2 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeHidden, "Prop").WithArguments("Base.Prop", "Derived3.Prop").WithLocation(21, 16) + ); + + var baseComp = CreateCompilationWithRequiredMembers(@base); + baseComp.VerifyDiagnostics(); + + comp = CreateCompilation("#pragma warning disable CS0649 // Never assigned" + derived, new[] { useMetadataReference ? baseComp.ToMetadataReference() : baseComp.EmitToImageReference() }); + comp.VerifyDiagnostics( + // (4,20): error CS9031: Required member 'Base.Field' cannot be hidden by 'Derived1.Field'. + // public new int Field; // 1 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeHidden, "Field").WithArguments("Base.Field", "Derived1.Field").WithLocation(4, 20), + // (5,20): error CS9031: Required member 'Base.Prop' cannot be hidden by 'Derived1.Prop'. + // public new int Prop { get; set; } // 2 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeHidden, "Prop").WithArguments("Base.Prop", "Derived1.Prop").WithLocation(5, 20), + // (9,20): error CS9031: Required member 'Base.Prop' cannot be hidden by 'Derived2.Prop'. + // public new int Prop; // 3 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeHidden, "Prop").WithArguments("Base.Prop", "Derived2.Prop").WithLocation(9, 20), + // (10,20): error CS9031: Required member 'Base.Field' cannot be hidden by 'Derived2.Field'. + // public new int Field { get; set; } // 4 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeHidden, "Field").WithArguments("Base.Field", "Derived2.Field").WithLocation(10, 20), + // (14,16): warning CS0108: 'Derived3.Field' hides inherited member 'Base.Field'. Use the new keyword if hiding was intended. + // public int Field; // 1 + Diagnostic(ErrorCode.WRN_NewRequired, "Field").WithArguments("Derived3.Field", "Base.Field").WithLocation(14, 16), + // (14,16): error CS9031: Required member 'Base.Field' cannot be hidden by 'Derived3.Field'. + // public int Field; // 1 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeHidden, "Field").WithArguments("Base.Field", "Derived3.Field").WithLocation(14, 16), + // (15,16): error CS9031: Required member 'Base.Prop' cannot be hidden by 'Derived3.Prop'. + // public int Prop { get; set; } // 2 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeHidden, "Prop").WithArguments("Base.Prop", "Derived3.Prop").WithLocation(15, 16) + ); + } + + [Fact] + public void RequiredMembersMustBeAsVisibleAsContainingType() + { + var comp = CreateCompilationWithRequiredMembers(@" +#pragma warning disable CS0649 // Never assigned +#pragma warning disable CS0169 // Never used +public class PublicClass +{ + public required int PublicProperty { get; set; } + internal protected required int InternalProtectedProperty { get; set; } // 1 + internal required int InternalProperty { get; set; } // 2 + protected required int ProtectedProperty { get; set; } // 3 + private protected required int PrivateProtectedProperty { get; set; } // 4 + private required int PrivateProperty { get; set; } // 5 + public required int PublicField; + internal protected required int InternalProtectedField; // 6 + internal required int InternalField; // 7 + protected required int ProtectedField; // 8 + private protected required int PrivateProtectedField; // 9 + private required int PrivateField; // 10 +} +internal class InternalClass +{ + public required int PublicProperty { get; set; } + internal protected required int InternalProtectedProperty { get; set; } + internal required int InternalProperty { get; set; } + protected required int ProtectedProperty { get; set; } // 11 + private protected required int PrivateProtectedProperty { get; set; } // 12 + private required int PrivateProperty { get; set; } // 13 + public required int PublicField; + internal protected required int InternalProtectedField; + internal required int InternalField; + protected required int ProtectedField; // 14 + private protected required int PrivateProtectedField; // 15 + private required int PrivateField; // 16 +} +internal class Outer +{ + protected internal class ProtectedInternalClass + { + public required int PublicProperty { get; set; } + internal protected required int InternalProtectedProperty { get; set; } + internal required int InternalProperty { get; set; } // 17 + protected required int ProtectedProperty { get; set; } // 18 + private protected required int PrivateProtectedProperty { get; set; } // 19 + private required int PrivateProperty { get; set; } // 20 + public required int PublicField; + internal protected required int InternalProtectedField; + internal required int InternalField; // 21 + protected required int ProtectedField; // 22 + private protected required int PrivateProtectedField; // 23 + private required int PrivateField; // 24 + } + protected class ProtectedClass + { + public required int PublicProperty { get; set; } + internal protected required int InternalProtectedProperty { get; set; } + internal required int InternalProperty { get; set; } + protected required int ProtectedProperty { get; set; } + private protected required int PrivateProtectedProperty { get; set; } // 25 + private required int PrivateProperty { get; set; } // 26 + public required int PublicField; + internal protected required int InternalProtectedField; + internal required int InternalField; + protected required int ProtectedField; + private protected required int PrivateProtectedField; // 27 + private required int PrivateField; // 28 + } + private protected class PrivateProtectedClass + { + public required int PublicProperty { get; set; } + internal protected required int InternalProtectedProperty { get; set; } + internal required int InternalProperty { get; set; } + protected required int ProtectedProperty { get; set; } + private protected required int PrivateProtectedProperty { get; set; } + private required int PrivateProperty { get; set; } // 29 + public required int PublicField; + internal protected required int InternalProtectedField; + internal required int InternalField; + protected required int ProtectedField; + private protected required int PrivateProtectedField; + private required int PrivateField; // 30 + } + private class PrivateClass + { + public required int PublicProperty { get; set; } + internal protected required int InternalProtectedProperty { get; set; } + internal required int InternalProperty { get; set; } + protected required int ProtectedProperty { get; set; } + private protected required int PrivateProtectedProperty { get; set; } + private required int PrivateProperty { get; set; } + public required int PublicField; + internal protected required int InternalProtectedField; + internal required int InternalField; + protected required int ProtectedField; + private protected required int PrivateProtectedField; + private required int PrivateField; + } +} +"); + + comp.VerifyDiagnostics( + // (7,37): error CS9032: Required member 'PublicClass.InternalProtectedProperty' cannot be less visible or have a setter less visible than the containing type 'PublicClass'. + // internal protected required int InternalProtectedProperty { get; set; } // 1 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeLessVisibleThanContainingType, "InternalProtectedProperty").WithArguments("PublicClass.InternalProtectedProperty", "PublicClass").WithLocation(7, 37), + // (8,27): error CS9032: Required member 'PublicClass.InternalProperty' cannot be less visible or have a setter less visible than the containing type 'PublicClass'. + // internal required int InternalProperty { get; set; } // 2 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeLessVisibleThanContainingType, "InternalProperty").WithArguments("PublicClass.InternalProperty", "PublicClass").WithLocation(8, 27), + // (9,28): error CS9032: Required member 'PublicClass.ProtectedProperty' cannot be less visible or have a setter less visible than the containing type 'PublicClass'. + // protected required int ProtectedProperty { get; set; } // 3 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeLessVisibleThanContainingType, "ProtectedProperty").WithArguments("PublicClass.ProtectedProperty", "PublicClass").WithLocation(9, 28), + // (10,36): error CS9032: Required member 'PublicClass.PrivateProtectedProperty' cannot be less visible or have a setter less visible than the containing type 'PublicClass'. + // private protected required int PrivateProtectedProperty { get; set; } // 4 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeLessVisibleThanContainingType, "PrivateProtectedProperty").WithArguments("PublicClass.PrivateProtectedProperty", "PublicClass").WithLocation(10, 36), + // (11,26): error CS9032: Required member 'PublicClass.PrivateProperty' cannot be less visible or have a setter less visible than the containing type 'PublicClass'. + // private required int PrivateProperty { get; set; } // 5 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeLessVisibleThanContainingType, "PrivateProperty").WithArguments("PublicClass.PrivateProperty", "PublicClass").WithLocation(11, 26), + // (13,37): error CS9032: Required member 'PublicClass.InternalProtectedField' cannot be less visible or have a setter less visible than the containing type 'PublicClass'. + // internal protected required int InternalProtectedField; // 6 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeLessVisibleThanContainingType, "InternalProtectedField").WithArguments("PublicClass.InternalProtectedField", "PublicClass").WithLocation(13, 37), + // (14,27): error CS9032: Required member 'PublicClass.InternalField' cannot be less visible or have a setter less visible than the containing type 'PublicClass'. + // internal required int InternalField; // 7 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeLessVisibleThanContainingType, "InternalField").WithArguments("PublicClass.InternalField", "PublicClass").WithLocation(14, 27), + // (15,28): error CS9032: Required member 'PublicClass.ProtectedField' cannot be less visible or have a setter less visible than the containing type 'PublicClass'. + // protected required int ProtectedField; // 8 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeLessVisibleThanContainingType, "ProtectedField").WithArguments("PublicClass.ProtectedField", "PublicClass").WithLocation(15, 28), + // (16,36): error CS9032: Required member 'PublicClass.PrivateProtectedField' cannot be less visible or have a setter less visible than the containing type 'PublicClass'. + // private protected required int PrivateProtectedField; // 9 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeLessVisibleThanContainingType, "PrivateProtectedField").WithArguments("PublicClass.PrivateProtectedField", "PublicClass").WithLocation(16, 36), + // (17,26): error CS9032: Required member 'PublicClass.PrivateField' cannot be less visible or have a setter less visible than the containing type 'PublicClass'. + // private required int PrivateField; // 10 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeLessVisibleThanContainingType, "PrivateField").WithArguments("PublicClass.PrivateField", "PublicClass").WithLocation(17, 26), + // (24,28): error CS9032: Required member 'InternalClass.ProtectedProperty' cannot be less visible or have a setter less visible than the containing type 'InternalClass'. + // protected required int ProtectedProperty { get; set; } // 11 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeLessVisibleThanContainingType, "ProtectedProperty").WithArguments("InternalClass.ProtectedProperty", "InternalClass").WithLocation(24, 28), + // (25,36): error CS9032: Required member 'InternalClass.PrivateProtectedProperty' cannot be less visible or have a setter less visible than the containing type 'InternalClass'. + // private protected required int PrivateProtectedProperty { get; set; } // 12 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeLessVisibleThanContainingType, "PrivateProtectedProperty").WithArguments("InternalClass.PrivateProtectedProperty", "InternalClass").WithLocation(25, 36), + // (26,26): error CS9032: Required member 'InternalClass.PrivateProperty' cannot be less visible or have a setter less visible than the containing type 'InternalClass'. + // private required int PrivateProperty { get; set; } // 13 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeLessVisibleThanContainingType, "PrivateProperty").WithArguments("InternalClass.PrivateProperty", "InternalClass").WithLocation(26, 26), + // (30,28): error CS9032: Required member 'InternalClass.ProtectedField' cannot be less visible or have a setter less visible than the containing type 'InternalClass'. + // protected required int ProtectedField; // 14 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeLessVisibleThanContainingType, "ProtectedField").WithArguments("InternalClass.ProtectedField", "InternalClass").WithLocation(30, 28), + // (31,36): error CS9032: Required member 'InternalClass.PrivateProtectedField' cannot be less visible or have a setter less visible than the containing type 'InternalClass'. + // private protected required int PrivateProtectedField; // 15 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeLessVisibleThanContainingType, "PrivateProtectedField").WithArguments("InternalClass.PrivateProtectedField", "InternalClass").WithLocation(31, 36), + // (32,26): error CS9032: Required member 'InternalClass.PrivateField' cannot be less visible or have a setter less visible than the containing type 'InternalClass'. + // private required int PrivateField; // 16 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeLessVisibleThanContainingType, "PrivateField").WithArguments("InternalClass.PrivateField", "InternalClass").WithLocation(32, 26), + // (40,31): error CS9032: Required member 'Outer.ProtectedInternalClass.InternalProperty' cannot be less visible or have a setter less visible than the containing type 'Outer.ProtectedInternalClass'. + // internal required int InternalProperty { get; set; } // 17 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeLessVisibleThanContainingType, "InternalProperty").WithArguments("Outer.ProtectedInternalClass.InternalProperty", "Outer.ProtectedInternalClass").WithLocation(40, 31), + // (41,32): error CS9032: Required member 'Outer.ProtectedInternalClass.ProtectedProperty' cannot be less visible or have a setter less visible than the containing type 'Outer.ProtectedInternalClass'. + // protected required int ProtectedProperty { get; set; } // 18 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeLessVisibleThanContainingType, "ProtectedProperty").WithArguments("Outer.ProtectedInternalClass.ProtectedProperty", "Outer.ProtectedInternalClass").WithLocation(41, 32), + // (42,40): error CS9032: Required member 'Outer.ProtectedInternalClass.PrivateProtectedProperty' cannot be less visible or have a setter less visible than the containing type 'Outer.ProtectedInternalClass'. + // private protected required int PrivateProtectedProperty { get; set; } // 19 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeLessVisibleThanContainingType, "PrivateProtectedProperty").WithArguments("Outer.ProtectedInternalClass.PrivateProtectedProperty", "Outer.ProtectedInternalClass").WithLocation(42, 40), + // (43,30): error CS9032: Required member 'Outer.ProtectedInternalClass.PrivateProperty' cannot be less visible or have a setter less visible than the containing type 'Outer.ProtectedInternalClass'. + // private required int PrivateProperty { get; set; } // 20 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeLessVisibleThanContainingType, "PrivateProperty").WithArguments("Outer.ProtectedInternalClass.PrivateProperty", "Outer.ProtectedInternalClass").WithLocation(43, 30), + // (46,31): error CS9032: Required member 'Outer.ProtectedInternalClass.InternalField' cannot be less visible or have a setter less visible than the containing type 'Outer.ProtectedInternalClass'. + // internal required int InternalField; // 21 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeLessVisibleThanContainingType, "InternalField").WithArguments("Outer.ProtectedInternalClass.InternalField", "Outer.ProtectedInternalClass").WithLocation(46, 31), + // (47,32): error CS9032: Required member 'Outer.ProtectedInternalClass.ProtectedField' cannot be less visible or have a setter less visible than the containing type 'Outer.ProtectedInternalClass'. + // protected required int ProtectedField; // 22 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeLessVisibleThanContainingType, "ProtectedField").WithArguments("Outer.ProtectedInternalClass.ProtectedField", "Outer.ProtectedInternalClass").WithLocation(47, 32), + // (48,40): error CS9032: Required member 'Outer.ProtectedInternalClass.PrivateProtectedField' cannot be less visible or have a setter less visible than the containing type 'Outer.ProtectedInternalClass'. + // private protected required int PrivateProtectedField; // 23 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeLessVisibleThanContainingType, "PrivateProtectedField").WithArguments("Outer.ProtectedInternalClass.PrivateProtectedField", "Outer.ProtectedInternalClass").WithLocation(48, 40), + // (49,30): error CS9032: Required member 'Outer.ProtectedInternalClass.PrivateField' cannot be less visible or have a setter less visible than the containing type 'Outer.ProtectedInternalClass'. + // private required int PrivateField; // 24 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeLessVisibleThanContainingType, "PrivateField").WithArguments("Outer.ProtectedInternalClass.PrivateField", "Outer.ProtectedInternalClass").WithLocation(49, 30), + // (57,40): error CS9032: Required member 'Outer.ProtectedClass.PrivateProtectedProperty' cannot be less visible or have a setter less visible than the containing type 'Outer.ProtectedClass'. + // private protected required int PrivateProtectedProperty { get; set; } // 25 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeLessVisibleThanContainingType, "PrivateProtectedProperty").WithArguments("Outer.ProtectedClass.PrivateProtectedProperty", "Outer.ProtectedClass").WithLocation(57, 40), + // (58,30): error CS9032: Required member 'Outer.ProtectedClass.PrivateProperty' cannot be less visible or have a setter less visible than the containing type 'Outer.ProtectedClass'. + // private required int PrivateProperty { get; set; } // 26 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeLessVisibleThanContainingType, "PrivateProperty").WithArguments("Outer.ProtectedClass.PrivateProperty", "Outer.ProtectedClass").WithLocation(58, 30), + // (63,40): error CS9032: Required member 'Outer.ProtectedClass.PrivateProtectedField' cannot be less visible or have a setter less visible than the containing type 'Outer.ProtectedClass'. + // private protected required int PrivateProtectedField; // 27 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeLessVisibleThanContainingType, "PrivateProtectedField").WithArguments("Outer.ProtectedClass.PrivateProtectedField", "Outer.ProtectedClass").WithLocation(63, 40), + // (64,30): error CS9032: Required member 'Outer.ProtectedClass.PrivateField' cannot be less visible or have a setter less visible than the containing type 'Outer.ProtectedClass'. + // private required int PrivateField; // 28 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeLessVisibleThanContainingType, "PrivateField").WithArguments("Outer.ProtectedClass.PrivateField", "Outer.ProtectedClass").WithLocation(64, 30), + // (73,30): error CS9032: Required member 'Outer.PrivateProtectedClass.PrivateProperty' cannot be less visible or have a setter less visible than the containing type 'Outer.PrivateProtectedClass'. + // private required int PrivateProperty { get; set; } // 29 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeLessVisibleThanContainingType, "PrivateProperty").WithArguments("Outer.PrivateProtectedClass.PrivateProperty", "Outer.PrivateProtectedClass").WithLocation(73, 30), + // (79,30): error CS9032: Required member 'Outer.PrivateProtectedClass.PrivateField' cannot be less visible or have a setter less visible than the containing type 'Outer.PrivateProtectedClass'. + // private required int PrivateField; // 30 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeLessVisibleThanContainingType, "PrivateField").WithArguments("Outer.PrivateProtectedClass.PrivateField", "Outer.PrivateProtectedClass").WithLocation(79, 30) + ); + } + + [Fact] + public void RequiredMembersMustBeAsVisibleAsContainingType_InaccessibleSetters() + { + var comp = CreateCompilationWithRequiredMembers(@" +public class PublicClass +{ + public required int InternalProtected { get; internal protected set; } // 1 + public required int Internal { get; internal set; } // 2 + public required int Protected { get; protected set; } // 3 + public required int PrivateProtected { get; private protected set; } // 4 + public required int Private { get; private set; } // 5 +} +internal class InternalClass +{ + public required int InternalProtected { get; internal protected set; } + public required int Internal { get; internal set; } + public required int Protected { get; protected set; } // 6 + public required int PrivateProtected { get; private protected set; } // 7 + public required int Private { get; private set; } // 8 +} +internal class Outer +{ + protected internal class InternalProtectedClass + { + public required int InternalProtected { get; internal protected set; } + public required int Internal { get; internal set; } // 9 + public required int Protected { get; protected set; } // 10 + public required int PrivateProtected { get; private protected set; } // 11 + public required int Private { get; private set; } // 12 + } + protected class ProtectedClass + { + public required int InternalProtected { get; internal protected set; } + public required int Internal { get; internal set; } + public required int Protected { get; protected set; } + public required int PrivateProtected { get; private protected set; } // 13 + public required int Private { get; private set; } // 14 + } + private protected class PrivateProtectedClass + { + public required int InternalProtected { get; internal protected set; } + public required int Internal { get; internal set; } + public required int Protected { get; protected set; } + public required int PrivateProtected { get; private protected set; } + public required int Private { get; private set; } // 15 + } + private class PrivateClass + { + public required int InternalProtected { get; internal protected set; } + public required int Internal { get; internal set; } + public required int Protected { get; protected set; } + public required int PrivateProtected { get; private protected set; } + public required int Private { get; private set; } + } +} +"); + + comp.VerifyDiagnostics( + // (4,25): error CS9032: Required member 'PublicClass.InternalProtected' cannot be less visible or have a setter less visible than the containing type 'PublicClass'. + // public required int InternalProtected { get; internal protected set; } // 1 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeLessVisibleThanContainingType, "InternalProtected").WithArguments("PublicClass.InternalProtected", "PublicClass").WithLocation(4, 25), + // (5,25): error CS9032: Required member 'PublicClass.Internal' cannot be less visible or have a setter less visible than the containing type 'PublicClass'. + // public required int Internal { get; internal set; } // 2 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeLessVisibleThanContainingType, "Internal").WithArguments("PublicClass.Internal", "PublicClass").WithLocation(5, 25), + // (6,25): error CS9032: Required member 'PublicClass.Protected' cannot be less visible or have a setter less visible than the containing type 'PublicClass'. + // public required int Protected { get; protected set; } // 3 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeLessVisibleThanContainingType, "Protected").WithArguments("PublicClass.Protected", "PublicClass").WithLocation(6, 25), + // (7,25): error CS9032: Required member 'PublicClass.PrivateProtected' cannot be less visible or have a setter less visible than the containing type 'PublicClass'. + // public required int PrivateProtected { get; private protected set; } // 4 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeLessVisibleThanContainingType, "PrivateProtected").WithArguments("PublicClass.PrivateProtected", "PublicClass").WithLocation(7, 25), + // (8,25): error CS9032: Required member 'PublicClass.Private' cannot be less visible or have a setter less visible than the containing type 'PublicClass'. + // public required int Private { get; private set; } // 5 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeLessVisibleThanContainingType, "Private").WithArguments("PublicClass.Private", "PublicClass").WithLocation(8, 25), + // (14,25): error CS9032: Required member 'InternalClass.Protected' cannot be less visible or have a setter less visible than the containing type 'InternalClass'. + // public required int Protected { get; protected set; } // 6 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeLessVisibleThanContainingType, "Protected").WithArguments("InternalClass.Protected", "InternalClass").WithLocation(14, 25), + // (15,25): error CS9032: Required member 'InternalClass.PrivateProtected' cannot be less visible or have a setter less visible than the containing type 'InternalClass'. + // public required int PrivateProtected { get; private protected set; } // 7 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeLessVisibleThanContainingType, "PrivateProtected").WithArguments("InternalClass.PrivateProtected", "InternalClass").WithLocation(15, 25), + // (16,25): error CS9032: Required member 'InternalClass.Private' cannot be less visible or have a setter less visible than the containing type 'InternalClass'. + // public required int Private { get; private set; } // 8 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeLessVisibleThanContainingType, "Private").WithArguments("InternalClass.Private", "InternalClass").WithLocation(16, 25), + // (23,29): error CS9032: Required member 'Outer.InternalProtectedClass.Internal' cannot be less visible or have a setter less visible than the containing type 'Outer.InternalProtectedClass'. + // public required int Internal { get; internal set; } // 9 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeLessVisibleThanContainingType, "Internal").WithArguments("Outer.InternalProtectedClass.Internal", "Outer.InternalProtectedClass").WithLocation(23, 29), + // (24,29): error CS9032: Required member 'Outer.InternalProtectedClass.Protected' cannot be less visible or have a setter less visible than the containing type 'Outer.InternalProtectedClass'. + // public required int Protected { get; protected set; } // 10 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeLessVisibleThanContainingType, "Protected").WithArguments("Outer.InternalProtectedClass.Protected", "Outer.InternalProtectedClass").WithLocation(24, 29), + // (25,29): error CS9032: Required member 'Outer.InternalProtectedClass.PrivateProtected' cannot be less visible or have a setter less visible than the containing type 'Outer.InternalProtectedClass'. + // public required int PrivateProtected { get; private protected set; } // 11 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeLessVisibleThanContainingType, "PrivateProtected").WithArguments("Outer.InternalProtectedClass.PrivateProtected", "Outer.InternalProtectedClass").WithLocation(25, 29), + // (26,29): error CS9032: Required member 'Outer.InternalProtectedClass.Private' cannot be less visible or have a setter less visible than the containing type 'Outer.InternalProtectedClass'. + // public required int Private { get; private set; } // 12 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeLessVisibleThanContainingType, "Private").WithArguments("Outer.InternalProtectedClass.Private", "Outer.InternalProtectedClass").WithLocation(26, 29), + // (33,29): error CS9032: Required member 'Outer.ProtectedClass.PrivateProtected' cannot be less visible or have a setter less visible than the containing type 'Outer.ProtectedClass'. + // public required int PrivateProtected { get; private protected set; } // 13 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeLessVisibleThanContainingType, "PrivateProtected").WithArguments("Outer.ProtectedClass.PrivateProtected", "Outer.ProtectedClass").WithLocation(33, 29), + // (34,29): error CS9032: Required member 'Outer.ProtectedClass.Private' cannot be less visible or have a setter less visible than the containing type 'Outer.ProtectedClass'. + // public required int Private { get; private set; } // 14 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeLessVisibleThanContainingType, "Private").WithArguments("Outer.ProtectedClass.Private", "Outer.ProtectedClass").WithLocation(34, 29), + // (42,29): error CS9032: Required member 'Outer.PrivateProtectedClass.Private' cannot be less visible or have a setter less visible than the containing type 'Outer.PrivateProtectedClass'. + // public required int Private { get; private set; } // 15 + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeLessVisibleThanContainingType, "Private").WithArguments("Outer.PrivateProtectedClass.Private", "Outer.PrivateProtectedClass").WithLocation(42, 29) + ); + } + + [Fact] + public void UsingRequiredMemberAttributeExplicitly() + { + var comp = CreateCompilationWithRequiredMembers(@" +using System.Runtime.CompilerServices; +[RequiredMember] +class C +{ + [RequiredMember] + public int Prop { get; set; } + [RequiredMember] + public int Field; +} +"); + + comp.VerifyDiagnostics( + // (3,2): error CS9033: Do not use 'System.Runtime.CompilerServices.RequiredMemberAttribute'. Use the 'required' keyword on required fields and properties instead. + // [RequiredMember] + Diagnostic(ErrorCode.ERR_ExplicitRequiredMember, "RequiredMember").WithLocation(3, 2), + // (6,6): error CS9033: Do not use 'System.Runtime.CompilerServices.RequiredMemberAttribute'. Use the 'required' keyword on required fields and properties instead. + // [RequiredMember] + Diagnostic(ErrorCode.ERR_ExplicitRequiredMember, "RequiredMember").WithLocation(6, 6), + // (8,6): error CS9033: Do not use 'System.Runtime.CompilerServices.RequiredMemberAttribute'. Use the 'required' keyword on required fields and properties instead. + // [RequiredMember] + Diagnostic(ErrorCode.ERR_ExplicitRequiredMember, "RequiredMember").WithLocation(8, 6), + // (9,16): warning CS0649: Field 'C.Field' is never assigned to, and will always have its default value 0 + // public int Field; + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "Field").WithArguments("C.Field", "0").WithLocation(9, 16) + ); + + var prop = comp.SourceModule.GlobalNamespace.GetMember("C.Prop"); + Assert.False(prop.IsRequired); + } + + [Fact] + public void UsingRequiredMemberAttributeExplicitly_WrongLocations() + { + var comp = CreateCompilation(@" +using System; +using System.Runtime.CompilerServices; +class C +{ + [RequiredMember] + void M() {} + [RequiredMember] + event Action E; + [RequiredMember] + C() {} + [RequiredMember] + ~C() {} + [return: RequiredMember] + void M<[RequiredMember] T>([RequiredMember] int i) {} +} + +namespace System.Runtime.CompilerServices +{ + public class RequiredMemberAttribute : Attribute + { + public RequiredMemberAttribute() + { + } + } +} +"); + + comp.VerifyDiagnostics( + // (9,18): warning CS0067: The event 'C.E' is never used + // event Action E; + Diagnostic(ErrorCode.WRN_UnreferencedEvent, "E").WithArguments("C.E").WithLocation(9, 18) + ); + } + + [Fact] + public void RequiredWithInitializer() + { + var comp = CreateCompilationWithRequiredMembers(@" +class C +{ + public required int Field = 1; + public required int Prop { get; set; } = 1; +} +"); + + comp.VerifyDiagnostics(); + } + + [Fact] + public void RefReturningProperties() + { + var comp = CreateCompilationWithRequiredMembers(@" +class C +{ + private int i; + public required ref int Prop1 => ref i; + public required ref readonly int Prop2 => ref i; +} +"); + + comp.VerifyDiagnostics( + // (5,29): error CS9034: Required member 'C.Prop1' must be settable. + // public required ref int Prop1 => ref i; + Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSettable, "Prop1").WithArguments("C.Prop1").WithLocation(5, 29), + // (5,29): error CS9043: Ref returning properties cannot be required. + // public required ref int Prop1 => ref i; + Diagnostic(ErrorCode.ERR_RefReturningPropertiesCannotBeRequired, "Prop1").WithLocation(5, 29), + // (6,38): error CS9034: Required member 'C.Prop2' must be settable. + // public required ref readonly int Prop2 => ref i; + Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSettable, "Prop2").WithArguments("C.Prop2").WithLocation(6, 38), + // (6,38): error CS9043: Ref returning properties cannot be required. + // public required ref readonly int Prop2 => ref i; + Diagnostic(ErrorCode.ERR_RefReturningPropertiesCannotBeRequired, "Prop2").WithLocation(6, 38) + ); + } + + [Theory] + [InlineData("internal")] + [InlineData("internal protected")] + [InlineData("protected")] + [InlineData("private protected")] + [InlineData("private")] + public void UnsettableMembers(string setterAccessibility) + { + var comp = CreateCompilationWithRequiredMembers($$""" +#pragma warning disable CS0649 // Unassigned field +public class C +{ + public required readonly int Field; + public required int Prop1 { get; } + public required int Prop2 { get; {{setterAccessibility}} set; } +} +"""); + + comp.VerifyDiagnostics( + // (4,34): error CS9034: Required member 'C.Field' must be settable. + // public required readonly int Field; + Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSettable, "Field").WithArguments("C.Field").WithLocation(4, 34), + // (5,25): error CS9034: Required member 'C.Prop1' must be settable. + // public required int Prop1 { get; } + Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSettable, "Prop1").WithArguments("C.Prop1").WithLocation(5, 25), + // (6,25): error CS9032: Required member 'C.Prop2' cannot be less visible or have a setter less visible than the containing type 'C'. + // public required int Prop2 { get; private set; } + Diagnostic(ErrorCode.ERR_RequiredMemberCannotBeLessVisibleThanContainingType, "Prop2").WithArguments("C.Prop2", "C").WithLocation(6, 25) + ); + } + + [Fact] + public void ObsoleteMember_NoObsoleteContext() + { + var comp = CreateCompilationWithRequiredMembers(""" + using System; + #pragma warning disable CS0649 // Unassigned field + class C + { + [Obsolete] + public required int Field; + [Obsolete] + public required int Prop1 { get; set; } + } + """); + + comp.VerifyDiagnostics( + // (6,25): warning CS9042: Required member 'C.Field' should not be attributed with 'ObsoleteAttribute' unless the containing type is obsolete or all constructors are obsolete. + // public required int Field; + Diagnostic(ErrorCode.WRN_ObsoleteMembersShouldNotBeRequired, "Field").WithArguments("C.Field").WithLocation(6, 25), + // (8,25): warning CS9042: Required member 'C.Prop1' should not be attributed with 'ObsoleteAttribute' unless the containing type is obsolete or all constructors are obsolete. + // public required int Prop1 { get; set; } + Diagnostic(ErrorCode.WRN_ObsoleteMembersShouldNotBeRequired, "Prop1").WithArguments("C.Prop1").WithLocation(8, 25) + ); + } + + [Fact] + public void ObsoleteMember_NoObsoleteContext_Struct() + { + var comp = CreateCompilationWithRequiredMembers(""" + using System; + #pragma warning disable CS0649 // Unassigned field + struct S + { + [Obsolete] + public required int Field; + [Obsolete] + public required int Prop1 { get; set; } + } + """); + + comp.VerifyDiagnostics( + // (6,25): warning CS9042: Required member 'S.Field' should not be attributed with 'ObsoleteAttribute' unless the containing type is obsolete or all constructors are obsolete. + // public required int Field; + Diagnostic(ErrorCode.WRN_ObsoleteMembersShouldNotBeRequired, "Field").WithArguments("S.Field").WithLocation(6, 25), + // (8,25): warning CS9042: Required member 'S.Prop1' should not be attributed with 'ObsoleteAttribute' unless the containing type is obsolete or all constructors are obsolete. + // public required int Prop1 { get; set; } + Diagnostic(ErrorCode.WRN_ObsoleteMembersShouldNotBeRequired, "Prop1").WithArguments("S.Prop1").WithLocation(8, 25) + ); + } + + [Fact] + public void ObsoleteMember_ObsoleteContext() + { + var comp = CreateCompilationWithRequiredMembers(""" + using System; + #pragma warning disable CS0649 // Unassigned field + [Obsolete] + class C + { + [Obsolete] + public required int Field; + [Obsolete] + public required int Prop1 { get; set; } + } + """); + + comp.VerifyDiagnostics(); + } + + [Fact] + public void ObsoleteMember_ObsoleteOrSetsRequiredMembersConstructors_01() + { + var comp = CreateCompilationWithRequiredMembers(""" + using System; + using System.Diagnostics.CodeAnalysis; + #pragma warning disable CS0649 // Unassigned field + class C + { + [Obsolete] + public C() { } + [SetsRequiredMembers] + public C(int i) { } + + [Obsolete] + public required int Field; + [Obsolete] + public required int Prop1 { get; set; } + } + + """); + + comp.VerifyDiagnostics(); + } + + [Fact] + public void ObsoleteMember_ObsoleteOrSetsRequiredMembersConstructors_02() + { + var comp = CreateCompilationWithRequiredMembers(""" + using System; + using System.Diagnostics.CodeAnalysis; + #pragma warning disable CS0649 // Unassigned field + class C + { + [Obsolete] + public C() { } + [SetsRequiredMembers] + public C(int i) { } + + public C(bool b) { } + + [Obsolete] + public required int Field; + [Obsolete] + public required int Prop1 { get; set; } + } + + """); + + comp.VerifyDiagnostics( + // (14,25): warning CS9042: Required member 'C.Field' should not be attributed with 'ObsoleteAttribute' unless the containing type is obsolete or all constructors are obsolete. + // public required int Field; + Diagnostic(ErrorCode.WRN_ObsoleteMembersShouldNotBeRequired, "Field").WithArguments("C.Field").WithLocation(14, 25), + // (16,25): warning CS9042: Required member 'C.Prop1' should not be attributed with 'ObsoleteAttribute' unless the containing type is obsolete or all constructors are obsolete. + // public required int Prop1 { get; set; } + Diagnostic(ErrorCode.WRN_ObsoleteMembersShouldNotBeRequired, "Prop1").WithArguments("C.Prop1").WithLocation(16, 25) + ); + } + + [Fact] + public void ReadonlyPropertiesAndStructs() + { + var comp = CreateCompilationWithRequiredMembers(@" +readonly struct S1 +{ + public required readonly int Prop1 { get => 1; set {} } +} +struct S2 +{ + public readonly int Prop2 { get => 1; set {} } +} +struct S3 +{ + public int Prop2 { get => 1; readonly set {} } +} +"); + + comp.VerifyDiagnostics(); + } + + [Theory] + [CombinatorialData] + public void EnforcedRequiredMembers_NoInheritance_NoneSet(bool useMetadataReference, [CombinatorialValues("", " C")] string constructor) + { + var c = @" +public class C +{ + public required int Prop { get; set; } + public required int Field; +} +"; + + var creation = $@"C c = new{constructor}();"; + var comp = CreateCompilationWithRequiredMembers(new[] { c, creation }); + + var expectedDiagnostics = constructor == " C" ? new[] + { + // (1,11): error CS9035: Required member 'C.Prop' must be set in the object initializer or attribute constructor. + // C c = new C(); + Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "C").WithArguments("C.Prop").WithLocation(1, 11), + // (1,11): error CS9035: Required member 'C.Field' must be set in the object initializer or attribute constructor. + // C c = new C(); + Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "C").WithArguments("C.Field").WithLocation(1, 11) + } + : new[] { + // (1,7): error CS9035: Required member 'C.Prop' must be set in the object initializer or attribute constructor. + // C c = new(); + Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "new").WithArguments("C.Prop").WithLocation(1, 7), + // (1,7): error CS9035: Required member 'C.Field' must be set in the object initializer or attribute constructor. + // C c = new(); + Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "new").WithArguments("C.Field").WithLocation(1, 7) + }; + + comp.VerifyDiagnostics(expectedDiagnostics); + + var cComp = CreateCompilationWithRequiredMembers(c); + comp = CreateCompilation(creation, references: new[] { useMetadataReference ? cComp.ToMetadataReference() : cComp.EmitToImageReference() }); + + comp.VerifyDiagnostics(expectedDiagnostics); + } + + [Theory] + [CombinatorialData] + public void EnforcedRequiredMembers_NoInheritance_NoneSet_HasSetsRequiredMembers(bool useMetadataReference, [CombinatorialValues("", " C")] string constructor, [CombinatorialValues("", "method: ")] string target) + { + var c = $$""" + using System.Diagnostics.CodeAnalysis; + public class C + { + public required int Prop { get; set; } + public required int Field; + + [{{target}}SetsRequiredMembers] + public C() {} + } + """; + + var creation = $@"C c = new{constructor}();"; + var comp = CreateCompilationWithRequiredMembers(new[] { c, creation }); + + comp.VerifyDiagnostics(); + + var cComp = CreateCompilationWithRequiredMembers(c); + comp = CreateCompilation(creation, references: new[] { useMetadataReference ? cComp.ToMetadataReference() : cComp.EmitToImageReference() }); + + comp.VerifyDiagnostics(); + } + + [Theory] + [CombinatorialData] + public void EnforcedRequiredMembers_NoInheritance_PartialSet(bool useMetadataReference, [CombinatorialValues("", " C")] string constructor) + { + var c = @" +public class C +{ + public required int Prop1 { get; set; } + public required int Prop2 { get; set; } + public required int Field1; + public required int Field2; +} +"; + + var creation = $@"C c = new{constructor}() {{ Prop2 = 1, Field2 = 1 }};"; + var comp = CreateCompilationWithRequiredMembers(new[] { c, creation }); + + var expectedDiagnostics = constructor == " C" ? new[] + { + // (1,11): error CS9035: Required member 'C.Prop1' must be set in the object initializer or attribute constructor. + // C c = new C() { Prop2 = 1, Field2 = 1 }; + Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "C").WithArguments("C.Prop1").WithLocation(1, 11), + // (1,11): error CS9035: Required member 'C.Field1' must be set in the object initializer or attribute constructor. + // C c = new C() { Prop2 = 1, Field2 = 1 }; + Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "C").WithArguments("C.Field1").WithLocation(1, 11) + } + : new[] { + // (1,7): error CS9035: Required member 'C.Prop1' must be set in the object initializer or attribute constructor. + // C c = new() { Prop2 = 1, Field2 = 1 }; + Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "new").WithArguments("C.Prop1").WithLocation(1, 7), + // (1,7): error CS9035: Required member 'C.Field1' must be set in the object initializer or attribute constructor. + // C c = new() { Prop2 = 1, Field2 = 1 }; + Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "new").WithArguments("C.Field1").WithLocation(1, 7) + }; + + comp.VerifyDiagnostics(expectedDiagnostics); + + var cComp = CreateCompilationWithRequiredMembers(c); + comp = CreateCompilation(creation, references: new[] { useMetadataReference ? cComp.ToMetadataReference() : cComp.EmitToImageReference() }); + + comp.VerifyDiagnostics(expectedDiagnostics); + } + + [Theory] + [CombinatorialData] + public void EnforcedRequiredMembers_NoInheritance_AllSet(bool useMetadataReference, [CombinatorialValues("", " C")] string constructor) + { + var c = @" +public class C +{ + public required int Prop1 { get; set; } + public required int Field1; +} +"; + + var creation = @" +C c = new" + constructor + @"() { Prop1 = 1, Field1 = 1 }; +System.Console.WriteLine($""{c.Prop1}, {c.Field1}""); +"; + var comp = CreateCompilationWithRequiredMembers(new[] { c, creation }); + CompileAndVerify(comp, expectedOutput: "1, 1"); + + var cComp = CreateCompilationWithRequiredMembers(c); + comp = CreateCompilation(creation, references: new[] { useMetadataReference ? cComp.ToMetadataReference() : cComp.EmitToImageReference() }); + CompileAndVerify(comp, expectedOutput: "1, 1"); + } + + [Fact] + public void EnforcedRequiredMembers_NoInheritance_Unsettable() + { + var c = @" +var c = new C(); +c = new C() { Prop1 = 1, Field1 = 1 }; + +public class C +{ + public required int Prop1 { get; } + public required readonly int Field1; +} +"; + var comp = CreateCompilationWithRequiredMembers(c); + comp.VerifyDiagnostics( + // (2,13): error CS9035: Required member 'C.Prop1' must be set in the object initializer or attribute constructor. + // var c = new C(); + Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "C").WithArguments("C.Prop1").WithLocation(2, 13), + // (2,13): error CS9035: Required member 'C.Field1' must be set in the object initializer or attribute constructor. + // var c = new C(); + Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "C").WithArguments("C.Field1").WithLocation(2, 13), + // (3,15): error CS0200: Property or indexer 'C.Prop1' cannot be assigned to -- it is read only + // c = new C() { Prop1 = 1, Field1 = 1 }; + Diagnostic(ErrorCode.ERR_AssgReadonlyProp, "Prop1").WithArguments("C.Prop1").WithLocation(3, 15), + // (3,26): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // c = new C() { Prop1 = 1, Field1 = 1 }; + Diagnostic(ErrorCode.ERR_AssgReadonly, "Field1").WithLocation(3, 26), + // (7,25): error CS9034: Required member 'C.Prop1' must be settable. + // public required int Prop1 { get; } + Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSettable, "Prop1").WithArguments("C.Prop1").WithLocation(7, 25), + // (8,34): error CS9034: Required member 'C.Field1' must be settable. + // public required readonly int Field1; + Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSettable, "Field1").WithArguments("C.Field1").WithLocation(8, 34) + ); + } + + [Fact] + public void EnforcedRequiredMembers_NoInheritance_Unsettable_FromMetadata() + { + var vb = @" +Imports System.Runtime.CompilerServices + + +Public Class C + + Public Readonly Property Prop1 As Integer + + Public Readonly Field1 As Integer +End Class +"; + + var vbComp = CreateVisualBasicCompilationWithRequiredMembers(vb); + vbComp.VerifyEmitDiagnostics(); + + var c = @" +var c = new C(); +c = new C() { Prop1 = 1, Field1 = 1 }; +"; + var comp = CreateCompilation(new[] { c }, references: new[] { vbComp.EmitToImageReference() }); + comp.VerifyDiagnostics( + // (2,13): error CS9035: Required member 'C.Prop1' must be set in the object initializer or attribute constructor. + // var c = new C(); + Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "C").WithArguments("C.Prop1").WithLocation(2, 13), + // (2,13): error CS9035: Required member 'C.Field1' must be set in the object initializer or attribute constructor. + // var c = new C(); + Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "C").WithArguments("C.Field1").WithLocation(2, 13), + // (3,15): error CS0200: Property or indexer 'C.Prop1' cannot be assigned to -- it is read only + // c = new C() { Prop1 = 1, Field1 = 1 }; + Diagnostic(ErrorCode.ERR_AssgReadonlyProp, "Prop1").WithArguments("C.Prop1").WithLocation(3, 15), + // (3,26): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // c = new C() { Prop1 = 1, Field1 = 1 }; + Diagnostic(ErrorCode.ERR_AssgReadonly, "Field1").WithLocation(3, 26) + ); + } + + [Fact] + public void EnforcedRequiredMembers_NoInheritance_Unsettable_HasSetsRequiredMembers() + { + var c = @" +using System.Diagnostics.CodeAnalysis; +var c = new C(); +c = new C() { Prop1 = 1, Field1 = 1 }; + +public class C +{ + public required int Prop1 { get; } + public required readonly int Field1; + + [SetsRequiredMembers] + public C() {} +} +"; + var comp = CreateCompilationWithRequiredMembers(c); + comp.VerifyDiagnostics( + // (4,15): error CS0200: Property or indexer 'C.Prop1' cannot be assigned to -- it is read only + // c = new C() { Prop1 = 1, Field1 = 1 }; + Diagnostic(ErrorCode.ERR_AssgReadonlyProp, "Prop1").WithArguments("C.Prop1").WithLocation(4, 15), + // (4,26): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer) + // c = new C() { Prop1 = 1, Field1 = 1 }; + Diagnostic(ErrorCode.ERR_AssgReadonly, "Field1").WithLocation(4, 26), + // (8,25): error CS9034: Required member 'C.Prop1' must be settable. + // public required int Prop1 { get; } + Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSettable, "Prop1").WithArguments("C.Prop1").WithLocation(8, 25), + // (9,34): error CS9034: Required member 'C.Field1' must be settable. + // public required readonly int Field1; + Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSettable, "Field1").WithArguments("C.Field1").WithLocation(9, 34) + ); + } + + [Fact] + public void EnforcedRequiredMembers_NoInheritance_DisallowedNestedObjectInitializer() + { + var c = @" +var c = new C() { D1 = { NestedProp = 1 }, D2 = { NestedProp = 2 } }; + +public class C +{ + public required D D1 { get; set; } + public required D D2; +} +public class D +{ + public int NestedProp { get; set; } +} +"; + var comp = CreateCompilationWithRequiredMembers(c); + comp.VerifyDiagnostics( + // (2,24): error CS9036: Required member 'C.D1' must be assigned a value, it cannot use a nested member or collection initializer. + // var c = new C() { D1 = { NestedProp = 1 }, D2 = { NestedProp = 2 } }; + Diagnostic(ErrorCode.ERR_RequiredMembersMustBeAssignedValue, "{ NestedProp = 1 }").WithArguments("C.D1").WithLocation(2, 24), + // (2,49): error CS9036: Required member 'C.D2' must be assigned a value, it cannot use a nested member or collection initializer. + // var c = new C() { D1 = { NestedProp = 1 }, D2 = { NestedProp = 2 } }; + Diagnostic(ErrorCode.ERR_RequiredMembersMustBeAssignedValue, "{ NestedProp = 2 }").WithArguments("C.D2").WithLocation(2, 49) + ); + } + + [Fact] + public void EnforcedRequiredMembers_NoInheritance_DisallowedNestedObjectInitializer_HasSetsRequiredMembers() + { + var c = @" +using System.Diagnostics.CodeAnalysis; +var c = new C() { D1 = { NestedProp = 1 }, D2 = { NestedProp = 2 } }; + +public class C +{ + public required D D1 { get; set; } + public required D D2; + + [SetsRequiredMembers] + public C() {} +} +public class D +{ + public int NestedProp { get; set; } +} +"; + var comp = CreateCompilationWithRequiredMembers(c); + comp.VerifyDiagnostics(); + } + + [Fact] + public void EnforcedRequiredMembers_NoInheritance_NestedObjectCreationAllowed() + { + var c = @" +var c = new C() { D1 = new() { NestedProp = 1 }, D2 = new() { NestedProp = 2 } }; + +public class C +{ + public required D D1 { get; set; } + public required D D2; +} +public class D +{ + public int NestedProp { get; set; } +} +"; + var comp = CreateCompilationWithRequiredMembers(c); + CompileAndVerify(comp).VerifyDiagnostics(); + } + + [Fact] + public void EnforcedRequiredMembers_NoInheritance_DisallowedNestedCollectionInitializer() + { + var c = @" +using System.Collections.Generic; +var c = new C() { L1 = { 1, 2, 3 }, L2 = { 4, 5, 6 } }; + +public class C +{ + public required List L1 { get; set; } + public required List L2; +} +"; + var comp = CreateCompilationWithRequiredMembers(c); + comp.VerifyDiagnostics( + // (3,24): error CS9036: Required member 'C.L1' must be assigned a value, it cannot use a nested member or collection initializer. + // var c = new C() { L1 = { 1, 2, 3 }, L2 = { 4, 5, 6 } }; + Diagnostic(ErrorCode.ERR_RequiredMembersMustBeAssignedValue, "{ 1, 2, 3 }").WithArguments("C.L1").WithLocation(3, 24), + // (3,42): error CS9036: Required member 'C.L2' must be assigned a value, it cannot use a nested member or collection initializer. + // var c = new C() { L1 = { 1, 2, 3 }, L2 = { 4, 5, 6 } }; + Diagnostic(ErrorCode.ERR_RequiredMembersMustBeAssignedValue, "{ 4, 5, 6 }").WithArguments("C.L2").WithLocation(3, 42) + ); + } + + [Fact] + public void EnforcedRequiredMembers_NoInheritance_DisallowedNestedCollectionInitializer_HasSetsRequiredMember() + { + var c = @" +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +var c = new C() { L1 = { 1, 2, 3 }, L2 = { 4, 5, 6 } }; + +public class C +{ + public required List L1 { get; set; } + public required List L2; + + [SetsRequiredMembers] + public C() {} +} +"; + var comp = CreateCompilationWithRequiredMembers(c); + comp.VerifyDiagnostics(); + } + + [Fact] + public void EnforcedRequiredMembers_NoInheritance_NestedObjectCreationWithCollectionInitializerAllowed() + { + var c = @" +using System.Collections.Generic; +var c = new C() { L1 = new() { 1, 2, 3 }, L2 = new() { 4, 5, 6 } }; + +public class C +{ + public required List L1 { get; set; } + public required List L2; +} +"; + var comp = CreateCompilationWithRequiredMembers(c); + CompileAndVerify(comp).VerifyDiagnostics(); + } + + [Theory] + [CombinatorialData] + public void EnforcedRequiredMembers_Inheritance_NoneSet(bool useMetadataReference) + { + var @base = @" +public class Base +{ + public required int Prop1 { get; set; } + public required int Field1; +} +"; + + var code = @" +_ = new Derived(); + +public class Derived : Base +{ + public required int Prop2 { get; set; } + public required int Field2; +} +"; + + var comp = CreateCompilationWithRequiredMembers(new[] { @base, code }); + + var expectedDiagnostics = new[] { + // (2,9): error CS9035: Required member 'Base.Prop1' must be set in the object initializer or attribute constructor. + // _ = new Derived(); + Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "Derived").WithArguments("Base.Prop1").WithLocation(2, 9), + // (2,9): error CS9035: Required member 'Base.Field1' must be set in the object initializer or attribute constructor. + // _ = new Derived(); + Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "Derived").WithArguments("Base.Field1").WithLocation(2, 9), + // (2,9): error CS9035: Required member 'Derived.Prop2' must be set in the object initializer or attribute constructor. + // _ = new Derived(); + Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "Derived").WithArguments("Derived.Prop2").WithLocation(2, 9), + // (2,9): error CS9035: Required member 'Derived.Field2' must be set in the object initializer or attribute constructor. + // _ = new Derived(); + Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "Derived").WithArguments("Derived.Field2").WithLocation(2, 9) + }; + + comp.VerifyDiagnostics(expectedDiagnostics); + + var baseComp = CreateCompilationWithRequiredMembers(@base); + baseComp.VerifyEmitDiagnostics(); + + comp = CreateCompilation(code, new[] { useMetadataReference ? baseComp.ToMetadataReference() : baseComp.EmitToImageReference() }); + comp.VerifyDiagnostics(expectedDiagnostics); + } + + [Theory] + [CombinatorialData] + public void EnforcedRequiredMembers_Inheritance_NoneSet_HasSetsRequiredMembers(bool useMetadataReference) + { + var @base = @" +public class Base +{ + public required int Prop1 { get; set; } + public required int Field1; +} +"; + + var derived = @" +using System.Diagnostics.CodeAnalysis; + +public class Derived : Base +{ + public required int Prop2 { get; set; } + public required int Field2; + + [SetsRequiredMembers] + public Derived() {} +} +"; + + var code = @"_ = new Derived();"; + + var comp = CreateCompilationWithRequiredMembers(new[] { @base, derived, code }); + var validator = GetTypeRequiredMembersInvariantsValidator("Derived"); + CompileAndVerify(comp, sourceSymbolValidator: validator, symbolValidator: validator).VerifyDiagnostics(); + + var baseComp = CreateCompilationWithRequiredMembers(@base); + baseComp.VerifyEmitDiagnostics(); + var baseRef = useMetadataReference ? baseComp.ToMetadataReference() : baseComp.EmitToImageReference(); + + var derivedComp = CreateCompilation(derived, new[] { baseRef }); + CompileAndVerify(derivedComp, sourceSymbolValidator: validator, symbolValidator: validator).VerifyDiagnostics(); + + comp = CreateCompilation(code, new[] { baseRef, useMetadataReference ? derivedComp.ToMetadataReference() : derivedComp.EmitToImageReference() }); + CompileAndVerify(comp).VerifyDiagnostics(); + } + + [Theory] + [CombinatorialData] + public void EnforcedRequiredMembers_Inheritance_PartialSet(bool useMetadataReference) + { + var @base = @" +public class Base +{ + public required int Prop1 { get; set; } + public required int Field1; + public required int Prop2 { get; set; } + public required int Field2; +} +"; + + var code = @" +_ = new Derived() { Prop1 = 1, Field1 = 1, Prop3 = 3, Field3 = 3 }; + +public class Derived : Base +{ + public required int Prop3 { get; set; } + public required int Field3; + public required int Prop4 { get; set; } + public required int Field4; +} +"; + + var comp = CreateCompilationWithRequiredMembers(new[] { @base, code }); + + var expectedDiagnostics = new[] { + // (2,9): error CS9035: Required member 'Base.Prop2' must be set in the object initializer or attribute constructor. + // _ = new Derived() { Prop1 = 1, Field1 = 1, Prop3 = 3, Field3 = 3 }; + Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "Derived").WithArguments("Base.Prop2").WithLocation(2, 9), + // (2,9): error CS9035: Required member 'Base.Field2' must be set in the object initializer or attribute constructor. + // _ = new Derived() { Prop1 = 1, Field1 = 1, Prop3 = 3, Field3 = 3 }; + Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "Derived").WithArguments("Base.Field2").WithLocation(2, 9), + // (2,9): error CS9035: Required member 'Derived.Prop4' must be set in the object initializer or attribute constructor. + // _ = new Derived() { Prop1 = 1, Field1 = 1, Prop3 = 3, Field3 = 3 }; + Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "Derived").WithArguments("Derived.Prop4").WithLocation(2, 9), + // (2,9): error CS9035: Required member 'Derived.Field4' must be set in the object initializer or attribute constructor. + // _ = new Derived() { Prop1 = 1, Field1 = 1, Prop3 = 3, Field3 = 3 }; + Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "Derived").WithArguments("Derived.Field4").WithLocation(2, 9) + }; + + comp.VerifyDiagnostics(expectedDiagnostics); + + var baseComp = CreateCompilationWithRequiredMembers(@base); + baseComp.VerifyEmitDiagnostics(); + + comp = CreateCompilation(code, new[] { useMetadataReference ? baseComp.ToMetadataReference() : baseComp.EmitToImageReference() }); + comp.VerifyDiagnostics(expectedDiagnostics); + } + + [Theory] + [CombinatorialData] + public void EnforcedRequiredMembers_Inheritance_AllSet(bool useMetadataReference) + { + var @base = @" +public class Base +{ + public required int Prop1 { get; set; } + public required int Field1; +} +"; + + var code = @" +_ = new Derived() { Prop1 = 1, Field1 = 1, Prop2 = 2, Field2 = 2 }; + +public class Derived : Base +{ + public required int Prop2 { get; set; } + public required int Field2; +} +"; + + var comp = CreateCompilationWithRequiredMembers(new[] { @base, code }); + var validator = GetTypeRequiredMembersInvariantsValidator("Derived"); + CompileAndVerify(comp, sourceSymbolValidator: validator, symbolValidator: validator).VerifyDiagnostics(); + + var baseComp = CreateCompilationWithRequiredMembers(@base); + baseComp.VerifyEmitDiagnostics(); + + comp = CreateCompilation(code, new[] { useMetadataReference ? baseComp.ToMetadataReference() : baseComp.EmitToImageReference() }); + CompileAndVerify(comp, sourceSymbolValidator: validator, symbolValidator: validator).VerifyDiagnostics(); + } + + [Theory] + [CombinatorialData] + public void EnforcedRequiredMembers_Inheritance_NoMembersOnDerivedType(bool useMetadataReference) + { + var @base = @" +public class Base +{ + public required int Prop1 { get; set; } + public required int Field1; +} +"; + + var code = @" +_ = new Derived() { Prop1 = 1, Field1 = 1 }; + +public class Derived : Base +{ +} +"; + + var comp = CreateCompilationWithRequiredMembers(new[] { @base, code }); + var validator = GetTypeRequiredMembersInvariantsValidator("Derived"); + CompileAndVerify(comp, sourceSymbolValidator: validator, symbolValidator: validator).VerifyDiagnostics(); + + var baseComp = CreateCompilationWithRequiredMembers(@base); + baseComp.VerifyEmitDiagnostics(); + + comp = CreateCompilation(code, new[] { useMetadataReference ? baseComp.ToMetadataReference() : baseComp.EmitToImageReference() }); + CompileAndVerify(comp, sourceSymbolValidator: validator, symbolValidator: validator).VerifyDiagnostics(); + } + + [Fact] + public void EnforcedRequiredMembers_ThroughRetargeting_NoneSet() + { + var retargetedCode = @"public class C {}"; + + var originalC = CreateCompilation(new AssemblyIdentity("Ret", new Version(1, 0, 0, 0), isRetargetable: true), retargetedCode, TargetFrameworkUtil.StandardReferences); + + var @base = @" +public class Base +{ + public required C Prop1 { get; set; } + public required C Field1; +} +"; + + var baseComp = CreateCompilationWithRequiredMembers(@base, new[] { originalC.ToMetadataReference() }, targetFramework: TargetFramework.Standard); + + var retargetedC = CreateCompilation(new AssemblyIdentity("Ret", new Version(2, 0, 0, 0), isRetargetable: true), retargetedCode, TargetFrameworkUtil.StandardReferences); + + var code = @" +_ = new Derived(); + +public class Derived : Base +{ + public required C Prop2 { get; set; } + public required C Field2; +} +"; + + var comp = CreateCompilation(code, new[] { baseComp.ToMetadataReference(), retargetedC.ToMetadataReference() }, targetFramework: TargetFramework.Standard); + comp.VerifyDiagnostics( + // (2,9): error CS9035: Required member 'Base.Field1' must be set in the object initializer or attribute constructor. + // _ = new Derived(); + Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "Derived").WithArguments("Base.Field1").WithLocation(2, 9), + // (2,9): error CS9035: Required member 'Base.Prop1' must be set in the object initializer or attribute constructor. + // _ = new Derived(); + Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "Derived").WithArguments("Base.Prop1").WithLocation(2, 9), + // (2,9): error CS9035: Required member 'Derived.Prop2' must be set in the object initializer or attribute constructor. + // _ = new Derived(); + Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "Derived").WithArguments("Derived.Prop2").WithLocation(2, 9), + // (2,9): error CS9035: Required member 'Derived.Field2' must be set in the object initializer or attribute constructor. + // _ = new Derived(); + Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "Derived").WithArguments("Derived.Field2").WithLocation(2, 9) + ); + + var baseSymbol = comp.GetTypeByMetadataName("Base"); + Assert.IsType(baseSymbol); + } + + [Fact] + public void EnforcedRequiredMembers_ThroughRetargeting_NoneSet_HasSetsRequiredMembers() + { + var retargetedCode = @"public class C {}"; + + var originalC = CreateCompilation(new AssemblyIdentity("Ret", new Version(1, 0, 0, 0), isRetargetable: true), retargetedCode, TargetFrameworkUtil.StandardReferences); + + var @base = @" +public class Base +{ + public required C Prop1 { get; set; } + public required C Field1; +} +"; + + var originalCRef = originalC.ToMetadataReference(); + var baseComp = CreateCompilationWithRequiredMembers(@base, new[] { originalCRef }, targetFramework: TargetFramework.Standard); + + var derived = @" +using System.Diagnostics.CodeAnalysis; +public class Derived : Base +{ + public required C Prop2 { get; set; } + public required C Field2; + + [SetsRequiredMembers] + public Derived() {} +} +"; + + var baseRef = baseComp.ToMetadataReference(); + var derivedComp = CreateCompilation(derived, new[] { baseRef, originalCRef }, targetFramework: TargetFramework.Standard); + + var retargetedC = CreateCompilation(new AssemblyIdentity("Ret", new Version(2, 0, 0, 0), isRetargetable: true), retargetedCode, TargetFrameworkUtil.StandardReferences); + + var code = @" +_ = new Derived(); +"; + + var comp = CreateCompilation(code, new[] { baseRef, derivedComp.ToMetadataReference(), retargetedC.ToMetadataReference() }, targetFramework: TargetFramework.Standard); + comp.VerifyDiagnostics(); + + var baseSymbol = comp.GetTypeByMetadataName("Derived"); + Assert.IsType(baseSymbol); + } + + [Fact] + public void EnforcedRequiredMembers_ThroughRetargeting_AllSet() + { + var retargetedCode = @"public class C {}"; + + var originalC = CreateCompilation(new AssemblyIdentity("Ret", new Version(1, 0, 0, 0), isRetargetable: true), retargetedCode, TargetFrameworkUtil.StandardReferences); + + var @base = @" +public class Base +{ + public required C Prop1 { get; set; } + public required C Field1; +} +"; + + var baseComp = CreateCompilationWithRequiredMembers(@base, new[] { originalC.ToMetadataReference() }, targetFramework: TargetFramework.Standard); + + var retargetedC = CreateCompilation(new AssemblyIdentity("Ret", new Version(2, 0, 0, 0), isRetargetable: true), retargetedCode, TargetFrameworkUtil.StandardReferences); + + var code = @" +_ = new Derived() { Prop1 = new(), Field1 = new(), Prop2 = new(), Field2 = new() }; + +public class Derived : Base +{ + public required C Prop2 { get; set; } + public required C Field2; +} +"; + + var comp = CreateCompilation(code, new[] { baseComp.ToMetadataReference(), retargetedC.ToMetadataReference() }, targetFramework: TargetFramework.Standard); + comp.VerifyDiagnostics(); + + var baseSymbol = comp.GetTypeByMetadataName("Base"); + Assert.IsType(baseSymbol); + } + + [Theory] + [CombinatorialData] + public void EnforcedRequiredMembers_Override_NoneSet(bool useMetadataReference) + { + var @base = @" +public class Base +{ + public virtual required int Prop1 { get; set; } +} +"; + + var code = @" +_ = new Derived(); + +public class Derived : Base +{ + public override required int Prop1 { get; set; } +} +"; + + var comp = CreateCompilationWithRequiredMembers(new[] { @base, code }); + + var expectedDiagnostics = new[] { + // (2,9): error CS9035: Required member 'Derived.Prop1' must be set in the object initializer or attribute constructor. + // _ = new Derived(); + Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "Derived").WithArguments("Derived.Prop1").WithLocation(2, 9) + }; + + comp.VerifyDiagnostics(expectedDiagnostics); + + var baseComp = CreateCompilationWithRequiredMembers(@base); + baseComp.VerifyEmitDiagnostics(); + + comp = CreateCompilation(code, new[] { useMetadataReference ? baseComp.ToMetadataReference() : baseComp.EmitToImageReference() }); + comp.VerifyDiagnostics(expectedDiagnostics); + } + + [Theory] + [CombinatorialData] + public void EnforcedRequiredMembers_Override_NoneSet_HasSetsRequiredMembers(bool useMetadataReference) + { + var @base = @" +public class Base +{ + public virtual required int Prop1 { get; set; } +} +"; + + var code = @" +using System.Diagnostics.CodeAnalysis; +_ = new Derived(); + +public class Derived : Base +{ + public override required int Prop1 { get; set; } + + [SetsRequiredMembers] + public Derived() {} +} +"; + + var comp = CreateCompilationWithRequiredMembers(new[] { @base, code }); + + comp.VerifyDiagnostics(); + + var baseComp = CreateCompilationWithRequiredMembers(@base); + baseComp.VerifyEmitDiagnostics(); + + comp = CreateCompilation(code, new[] { useMetadataReference ? baseComp.ToMetadataReference() : baseComp.EmitToImageReference() }); + comp.VerifyDiagnostics(); + } + + [Theory] + [CombinatorialData] + public void EnforcedRequiredMembers_Override_PartialSet(bool useMetadataReference) + { + var @base = @" +public class Base +{ + public virtual required int Prop1 { get; set; } + public virtual required int Prop2 { get; set; } +} +"; + + var code = @" +_ = new Derived() { Prop2 = 1 }; + +public class Derived : Base +{ + public override required int Prop1 { get; set; } + public override required int Prop2 { get; set; } +} +"; + + var comp = CreateCompilationWithRequiredMembers(new[] { @base, code }); + + var expectedDiagnostics = new[] { + // (2,9): error CS9035: Required member 'Derived.Prop1' must be set in the object initializer or attribute constructor. + // _ = new Derived() { Prop2 = 1 }; + Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "Derived").WithArguments("Derived.Prop1").WithLocation(2, 9) + }; + + comp.VerifyDiagnostics(expectedDiagnostics); + + var baseComp = CreateCompilationWithRequiredMembers(@base); + baseComp.VerifyEmitDiagnostics(); + + comp = CreateCompilation(code, new[] { useMetadataReference ? baseComp.ToMetadataReference() : baseComp.EmitToImageReference() }); + comp.VerifyDiagnostics(expectedDiagnostics); + } + + [Theory] + [CombinatorialData] + public void EnforcedRequiredMembers_Override_AllSet(bool useMetadataReference) + { + var @base = @" +public class Base +{ + public virtual required int Prop1 { get; set; } + public virtual required int Prop2 { get; set; } +} +"; + + var code = @" +_ = new Derived() { Prop1 = 1, Prop2 = 1 }; + +public class Derived : Base +{ + public override required int Prop1 { get; set; } + public override required int Prop2 { get; set; } +} +"; + + var comp = CreateCompilationWithRequiredMembers(new[] { @base, code }); + CompileAndVerify(comp).VerifyDiagnostics(); + + var baseComp = CreateCompilationWithRequiredMembers(@base); + baseComp.VerifyEmitDiagnostics(); + + comp = CreateCompilation(code, new[] { useMetadataReference ? baseComp.ToMetadataReference() : baseComp.EmitToImageReference() }); + CompileAndVerify(comp).VerifyDiagnostics(); + } + + [Fact] + public void EnforcedRequiredMembers_OverrideRetargeted_AllSet() + { + var retargetedCode = @"public class C {}"; + var originalC = CreateCompilation(new AssemblyIdentity("Ret", new Version(1, 0, 0, 0), isRetargetable: true), retargetedCode, TargetFrameworkUtil.StandardReferences); + + var @base = @" +public class Base +{ + public required virtual C Prop1 { get; set; } +} +"; + + var baseComp = CreateCompilationWithRequiredMembers(@base, new[] { originalC.ToMetadataReference() }, targetFramework: TargetFramework.Standard); + var retargetedC = CreateCompilation(new AssemblyIdentity("Ret", new Version(2, 0, 0, 0), isRetargetable: true), retargetedCode, TargetFrameworkUtil.StandardReferences); + + var code = @" +_ = new Derived() { Prop1 = new() }; + +public class Derived : Base +{ + public override required C Prop1 { get; set; } +} +"; + + var comp = CreateCompilation(code, new[] { baseComp.ToMetadataReference(), retargetedC.ToMetadataReference() }); + comp.VerifyDiagnostics(); + + Assert.IsType(comp.GetTypeByMetadataName("Base")); + } + + [Fact] + public void EnforcedRequiredMembers_OverrideRetargeted_NoneSet() + { + var retargetedCode = @"public class C {}"; + var originalC = CreateCompilation(new AssemblyIdentity("Ret", new Version(1, 0, 0, 0), isRetargetable: true), retargetedCode, TargetFrameworkUtil.StandardReferences); + + var @base = @" +public class Base +{ + public required virtual C Prop1 { get; set; } +} +"; + + var baseComp = CreateCompilationWithRequiredMembers(@base, new[] { originalC.ToMetadataReference() }, targetFramework: TargetFramework.Standard); + var retargetedC = CreateCompilation(new AssemblyIdentity("Ret", new Version(2, 0, 0, 0), isRetargetable: true), retargetedCode, TargetFrameworkUtil.StandardReferences); + + var code = @" +_ = new Derived(); + +public class Derived : Base +{ + public override required C Prop1 { get; set; } +} +"; + + var comp = CreateCompilation(code, new[] { baseComp.ToMetadataReference(), retargetedC.ToMetadataReference() }); + comp.VerifyDiagnostics( + // (2,9): error CS9035: Required member 'Derived.Prop1' must be set in the object initializer or attribute constructor. + // _ = new Derived(); + Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "Derived").WithArguments("Derived.Prop1").WithLocation(2, 9) + ); + + Assert.IsType(comp.GetTypeByMetadataName("Base")); + } + + [Fact] + public void EnforcedRequiredMembers_ShadowedInSource_01() + { + var vb = @" +Imports System.Runtime.CompilerServices + +Public Class Base + + Public Property P As Integer +End Class + + +Public Class Derived + Inherits Base + + Public Shadows Property P As Integer +End Class +"; + + var vbComp = CreateVisualBasicCompilationWithRequiredMembers(vb); + CompileAndVerify(vbComp).VerifyDiagnostics(); + + var c = @" +_ = new Derived2(); +_ = new Derived3(); + +class Derived2 : Derived +{ + public Derived2() {} + public Derived2(int x) {} +} +class Derived3 : Derived { }"; + + var comp = CreateCompilation(c, new[] { vbComp.EmitToImageReference() }); + comp.VerifyDiagnostics( + // (7,12): error CS9038: The required members list for the base type 'Derived' is malformed and cannot be interpreted. To use this constructor, apply the 'SetsRequiredMembers' attribute. + // public Derived2() {} + Diagnostic(ErrorCode.ERR_RequiredMembersBaseTypeInvalid, "Derived2").WithArguments("Derived").WithLocation(7, 12), + // (8,12): error CS9038: The required members list for the base type 'Derived' is malformed and cannot be interpreted. To use this constructor, apply the 'SetsRequiredMembers' attribute. + // public Derived2(int x) {} + Diagnostic(ErrorCode.ERR_RequiredMembersBaseTypeInvalid, "Derived2").WithArguments("Derived").WithLocation(8, 12), + // (10,7): error CS9038: The required members list for the base type 'Derived' is malformed and cannot be interpreted. To use this constructor, apply the 'SetsRequiredMembers' attribute. + // class Derived3 : Derived { } + Diagnostic(ErrorCode.ERR_RequiredMembersBaseTypeInvalid, "Derived3").WithArguments("Derived").WithLocation(10, 7) + ); + } + + [Fact] + public void EnforcedRequiredMembers_ShadowedInSource_01_HasSetsRequiredMembers() + { + var vb = @" +Imports System.Runtime.CompilerServices + +Public Class Base + + Public Property P As Integer +End Class + + +Public Class Derived + Inherits Base + + Public Shadows Property P As Integer +End Class +"; + + var vbComp = CreateVisualBasicCompilationWithRequiredMembers(vb); + CompileAndVerify(vbComp).VerifyDiagnostics(); + + var c = @" +using System.Diagnostics.CodeAnalysis; +_ = new Derived2(); + +class Derived2 : Derived +{ + [SetsRequiredMembers] + public Derived2() {} + [SetsRequiredMembers] + public Derived2(int x) {} +}"; + + var comp = CreateCompilation(c, new[] { vbComp.EmitToImageReference() }); + comp.VerifyDiagnostics(); + } + + [Fact] + public void EnforcedRequiredMembers_ShadowedInSource_02() + { + var vb = @" +Imports System.Runtime.CompilerServices + +Public Class Base + + Public Property P As Integer +End Class + + +Public Class Derived + Inherits Base + Public Shadows Property P As Integer +End Class +"; + + var vbComp = CreateVisualBasicCompilationWithRequiredMembers(vb); + CompileAndVerify(vbComp).VerifyDiagnostics(); + + var c = @" +_ = new Derived2(); +_ = new Derived3(); + +class Derived2 : Derived +{ + public Derived2() {} +} +class Derived3 : Derived { }"; + + var comp = CreateCompilation(c, new[] { vbComp.EmitToImageReference() }); + comp.VerifyDiagnostics( + // (7,12): error CS9038: The required members list for the base type 'Derived' is malformed and cannot be interpreted. To use this constructor, apply the 'SetsRequiredMembers' attribute. + // public Derived2() {} + Diagnostic(ErrorCode.ERR_RequiredMembersBaseTypeInvalid, "Derived2").WithArguments("Derived").WithLocation(7, 12), + // (9,7): error CS9038: The required members list for the base type 'Derived' is malformed and cannot be interpreted. To use this constructor, apply the 'SetsRequiredMembers' attribute. + // class Derived3 : Derived { } + Diagnostic(ErrorCode.ERR_RequiredMembersBaseTypeInvalid, "Derived3").WithArguments("Derived").WithLocation(9, 7) + ); + } + + [Fact] + public void EnforcedRequiredMembers_ShadowedInSource_03() + { + var vb = @" +Imports System.Runtime.CompilerServices + +Public Class Base + + Public Property P As Integer +End Class + +Public Class Derived + Inherits Base + Public Shadows Property P As Integer +End Class +"; + + var vbComp = CreateVisualBasicCompilationWithRequiredMembers(vb); + CompileAndVerify(vbComp).VerifyDiagnostics(); + + var c = @" +_ = new Derived2(); +_ = new Derived3(); + +class Derived2 : Derived +{ + public Derived2() {} +} +class Derived3 : Derived { }"; + + var comp = CreateCompilation(c, new[] { vbComp.EmitToImageReference() }); + comp.VerifyDiagnostics( + // (7,12): error CS9038: The required members list for the base type 'Derived' is malformed and cannot be interpreted. To use this constructor, apply the 'SetsRequiredMembers' attribute. + // public Derived2() {} + Diagnostic(ErrorCode.ERR_RequiredMembersBaseTypeInvalid, "Derived2").WithArguments("Derived").WithLocation(7, 12), + // (9,7): error CS9038: The required members list for the base type 'Derived' is malformed and cannot be interpreted. To use this constructor, apply the 'SetsRequiredMembers' attribute. + // class Derived3 : Derived { } + Diagnostic(ErrorCode.ERR_RequiredMembersBaseTypeInvalid, "Derived3").WithArguments("Derived").WithLocation(9, 7) + ); + } + + + /// + /// This IL is the equivalent of: + /// public record Derived : Base + /// { + /// public {propertyIsRequired ? required : ""} new int P { get; init; } + /// } + /// + private static string GetShadowingRecordIl(bool propertyIsRequired) + { + var propertyAttribute = propertyIsRequired ? + """ + .custom instance void [original]RequiredMemberAttribute::.ctor() = ( + 01 00 00 00 + ) + """ : ""; + return $$""" + .assembly extern original {} + + .class public auto ansi beforefieldinit Derived + extends [original]Base + implements class [mscorlib]System.IEquatable`1 + { + .custom instance void [original]RequiredMemberAttribute::.ctor() = ( + 01 00 00 00 + ) + // Fields + .field private initonly int32 '

k__BackingField' + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + .custom instance void [mscorlib]System.Diagnostics.DebuggerBrowsableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggerBrowsableState) = ( + 01 00 00 00 00 00 00 00 + ) + + // Methods + .method family hidebysig specialname virtual + instance class [mscorlib]System.Type get_EqualityContract () cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + ldnull + throw + } // end of method Derived::get_EqualityContract + + .method public hidebysig specialname + instance int32 get_P () cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + ldnull + throw + } // end of method Derived::get_P + + .method public hidebysig specialname + instance void modreq([mscorlib]System.Runtime.CompilerServices.IsExternalInit) set_P ( + int32 'value' + ) cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + ldnull + throw + } // end of method Derived::set_P + + .method public hidebysig virtual + instance string ToString () cil managed + { + ldnull + throw + } // end of method Derived::ToString + + .method family hidebysig virtual + instance bool PrintMembers ( + class [mscorlib]System.Text.StringBuilder builder + ) cil managed + { + ldnull + throw + } // end of method Derived::PrintMembers + + .method public hidebysig specialname static + bool op_Inequality ( + class Derived left, + class Derived right + ) cil managed + { + ldnull + throw + } // end of method Derived::op_Inequality + + .method public hidebysig specialname static + bool op_Equality ( + class Derived left, + class Derived right + ) cil managed + { + ldnull + throw + } // end of method Derived::op_Equality + + .method public hidebysig virtual + instance int32 GetHashCode () cil managed + { + ldnull + throw + } // end of method Derived::GetHashCode + + .method public hidebysig virtual + instance bool Equals ( + object obj + ) cil managed + { + ldnull + throw + } // end of method Derived::Equals + + .method public final hidebysig virtual + instance bool Equals ( + class [original]Base other + ) cil managed + { + ldnull + throw + } // end of method Derived::Equals + + .method public hidebysig newslot virtual + instance bool Equals ( + class Derived other + ) cil managed + { + ldnull + throw + } // end of method Derived::Equals + + .method public hidebysig newslot virtual + instance class Derived '$' () cil managed + { + .custom instance void [mscorlib]System.Runtime.CompilerServices.PreserveBaseOverridesAttribute::.ctor() = ( + 01 00 00 00 + ) + .override method instance class [original]Base [original]Base::'$'() + ldnull + throw + } // end of method Derived::'$' + + .method family hidebysig specialname rtspecialname + instance void .ctor ( + class Derived original + ) cil managed + { + ldnull + throw + } // end of method Derived::.ctor + + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + ldnull + throw + } // end of method Derived::.ctor + + // Properties + .property instance class [mscorlib]System.Type EqualityContract() + { + .get instance class [mscorlib]System.Type Derived::get_EqualityContract() + } + .property instance int32 P() + { + {{propertyAttribute}} + .get instance int32 Derived::get_P() + .set instance void modreq([mscorlib]System.Runtime.CompilerServices.IsExternalInit) Derived::set_P(int32) + } + + } // end of class Derived + """; + } + + [Fact] + public void EnforcedRequiredMembers_ShadowedInSource_04() + { + var original = @" +public record Base +{ + public required int P { get; init; } +} +"; + + var originalComp = CreateCompilationWithRequiredMembers(new[] { original, IsExternalInitTypeDefinition }, assemblyName: "original"); + CompileAndVerify(originalComp, verify: ExecutionConditionUtil.IsCoreClr ? Verification.Passes : Verification.Skipped).VerifyDiagnostics(); + + var ilSource = GetShadowingRecordIl(propertyIsRequired: false); + + var il = CompileIL(ilSource); + + var c = @" +_ = new DerivedDerived1(); +_ = new DerivedDerived2(); +_ = new DerivedDerived3(); + +record DerivedDerived1 : Derived +{ + public DerivedDerived1() + { + } +} +record DerivedDerived2 : Derived +{ +} +record DerivedDerived3() : Derived; +"; + + var comp = CreateCompilation(c, new[] { il, originalComp.EmitToImageReference() }); + comp.VerifyDiagnostics( + // (8,12): error CS9038: The required members list for the base type 'Derived' is malformed and cannot be interpreted. To use this constructor, apply the 'SetsRequiredMembers' attribute. + // public DerivedDerived1() + Diagnostic(ErrorCode.ERR_RequiredMembersBaseTypeInvalid, "DerivedDerived1").WithArguments("Derived").WithLocation(8, 12), + // (12,8): error CS9038: The required members list for the base type 'Derived' is malformed and cannot be interpreted. To use this constructor, apply the 'SetsRequiredMembers' attribute. + // record DerivedDerived2 : Derived + Diagnostic(ErrorCode.ERR_RequiredMembersBaseTypeInvalid, "DerivedDerived2").WithArguments("Derived").WithLocation(12, 8), + // (15,8): error CS9038: The required members list for the base type 'Derived' is malformed and cannot be interpreted. To use this constructor, apply the 'SetsRequiredMembers' attribute. + // record DerivedDerived3() : Derived; + Diagnostic(ErrorCode.ERR_RequiredMembersBaseTypeInvalid, "DerivedDerived3").WithArguments("Derived").WithLocation(15, 8) + ); + } + + [Fact] + public void EnforcedRequiredMembers_ShadowedInSource_04_HasSetsRequiredMembers() + { + var original = @" +public record Base +{ + public required int P { get; init; } +} +"; + + var originalComp = CreateCompilationWithRequiredMembers(new[] { original, IsExternalInitTypeDefinition }, assemblyName: "original"); + CompileAndVerify(originalComp, verify: ExecutionConditionUtil.IsCoreClr ? Verification.Passes : Verification.Skipped).VerifyDiagnostics(); + + var ilSource = GetShadowingRecordIl(propertyIsRequired: false); + + var il = CompileIL(ilSource); + + var c = @" +using System.Diagnostics.CodeAnalysis; + +_ = new DerivedDerived1(); + +record DerivedDerived1 : Derived +{ + [SetsRequiredMembers] + public DerivedDerived1() + { + } +} +"; + + var comp = CreateCompilation(c, new[] { il, originalComp.EmitToImageReference() }); + comp.VerifyDiagnostics(); + } + + [Fact] + public void EnforcedRequiredMembers_ShadowedInSource_04_HasSetsRequiredMembers_ManualBaseCall() + { + var original = @" +public record Base +{ + public required int P { get; init; } +} +"; + + var originalComp = CreateCompilationWithRequiredMembers(new[] { original, IsExternalInitTypeDefinition }, assemblyName: "original"); + CompileAndVerify(originalComp, verify: ExecutionConditionUtil.IsCoreClr ? Verification.Passes : Verification.Skipped).VerifyDiagnostics(); + + var ilSource = GetShadowingRecordIl(propertyIsRequired: false); + + var il = CompileIL(ilSource); + + var c = @" +using System.Diagnostics.CodeAnalysis; + +_ = new DerivedDerived1(); + +record DerivedDerived1 : Derived +{ + [SetsRequiredMembers] + public DerivedDerived1() + { + } + + [SetsRequiredMembers] + public DerivedDerived1(int unused) : base(null) + { + } + + public DerivedDerived1(bool unused) : base(null) + { + } +} +"; + + var comp = CreateCompilation(c, new[] { il, originalComp.EmitToImageReference() }); + comp.VerifyDiagnostics( + // (18,12): error CS9038: The required members list for the base type 'Derived' is malformed and cannot be interpreted. To use this constructor, apply the 'SetsRequiredMembers' attribute. + // public DerivedDerived1(bool unused) : base(null) + Diagnostic(ErrorCode.ERR_RequiredMembersBaseTypeInvalid, "DerivedDerived1").WithArguments("Derived").WithLocation(18, 12) + ); + } + + [Fact] + public void EnforcedRequiredMembers_ShadowedInSource_06() + { + var original = @" +public record Base +{ + public required int P { get; init; } +} +"; + + var originalComp = CreateCompilationWithRequiredMembers(new[] { original, IsExternalInitTypeDefinition }, assemblyName: "original"); + CompileAndVerify(originalComp, verify: ExecutionConditionUtil.IsCoreClr ? Verification.Passes : Verification.Skipped).VerifyDiagnostics(); + + var ilSource = GetShadowingRecordIl(propertyIsRequired: true); + var il = CompileIL(ilSource); + + var c = @" +_ = new DerivedDerived1(); +_ = new DerivedDerived2(); +_ = new DerivedDerived3(); + +record DerivedDerived1 : Derived +{ + public DerivedDerived1() + { + } +} +record DerivedDerived2 : Derived +{ +} +record DerivedDerived3() : Derived; +"; + + var comp = CreateCompilation(c, new[] { il, originalComp.EmitToImageReference() }); + comp.VerifyDiagnostics( + // (8,12): error CS9038: The required members list for the base type 'Derived' is malformed and cannot be interpreted. To use this constructor, apply the 'SetsRequiredMembers' attribute. + // public DerivedDerived1() + Diagnostic(ErrorCode.ERR_RequiredMembersBaseTypeInvalid, "DerivedDerived1").WithArguments("Derived").WithLocation(8, 12), + // (12,8): error CS9038: The required members list for the base type 'Derived' is malformed and cannot be interpreted. To use this constructor, apply the 'SetsRequiredMembers' attribute. + // record DerivedDerived2 : Derived + Diagnostic(ErrorCode.ERR_RequiredMembersBaseTypeInvalid, "DerivedDerived2").WithArguments("Derived").WithLocation(12, 8), + // (15,8): error CS9038: The required members list for the base type 'Derived' is malformed and cannot be interpreted. To use this constructor, apply the 'SetsRequiredMembers' attribute. + // record DerivedDerived3() : Derived; + Diagnostic(ErrorCode.ERR_RequiredMembersBaseTypeInvalid, "DerivedDerived3").WithArguments("Derived").WithLocation(15, 8) + ); + } + + [Fact] + public void EnforcedRequiredMembers_ShadowedInSource_06_HasSetsRequiredMembers() + { + var original = @" +public record Base +{ + public required int P { get; init; } +} +"; + + var originalComp = CreateCompilationWithRequiredMembers(new[] { original, IsExternalInitTypeDefinition }, assemblyName: "original"); + CompileAndVerify(originalComp, verify: ExecutionConditionUtil.IsCoreClr ? Verification.Passes : Verification.Skipped).VerifyDiagnostics(); + + var ilSource = GetShadowingRecordIl(propertyIsRequired: true); + var il = CompileIL(ilSource); + + var c = @" +using System.Diagnostics.CodeAnalysis; + +_ = new DerivedDerived1(); + +record DerivedDerived1 : Derived +{ + [SetsRequiredMembers] + public DerivedDerived1() + { + } +} +"; + + var comp = CreateCompilation(c, new[] { il, originalComp.EmitToImageReference() }); + comp.VerifyDiagnostics(); + } + + [Fact] + public void EnforcedRequiredMembers_ShadowedFromMetadata_01() + { + var vb = @" +Imports System.Diagnostics.CodeAnalysis +Imports System.Runtime.CompilerServices + +Public Class Base + + Public Property P As Integer +End Class + + +Public Class Derived + Inherits Base + + Public Shadows Property P As Integer + + Public Sub New() + End Sub + + + Public Sub New(unused As Integer) + End Sub +End Class +"; + + var vbComp = CreateVisualBasicCompilationWithRequiredMembers(vb); + CompileAndVerify(vbComp).VerifyDiagnostics(); + + var c = """ + _ = new Derived(); + _ = new Derived(1); + """; + var comp = CreateCompilation(c, new[] { vbComp.EmitToImageReference() }); + comp.VerifyDiagnostics( + // (1,9): error CS9037: The required members list for 'Derived' is malformed and cannot be interpreted. + // _ = new Derived(); + Diagnostic(ErrorCode.ERR_RequiredMembersInvalid, "Derived").WithArguments("Derived").WithLocation(1, 9) + ); + } + + [Fact] + public void EnforcedRequiredMembers_ShadowedFromMetadata_02() + { + var vb = @" +Imports System.Diagnostics.CodeAnalysis +Imports System.Runtime.CompilerServices + +Public Class Base + + Public Property P As Integer +End Class + + +Public Class Derived + Inherits Base + Public Shadows Property P As Integer + + Public Sub New() + End Sub + + + Public Sub New(unused As Integer) + End Sub +End Class +"; + + var vbComp = CreateVisualBasicCompilationWithRequiredMembers(vb); + CompileAndVerify(vbComp).VerifyDiagnostics(); + + var c = """ + _ = new Derived(); + _ = new Derived(1); + """; + var comp = CreateCompilation(c, new[] { vbComp.EmitToImageReference() }); + comp.VerifyDiagnostics( + // (1,9): error CS9037: The required members list for 'Derived' is malformed and cannot be interpreted. + // _ = new Derived(); + Diagnostic(ErrorCode.ERR_RequiredMembersInvalid, "Derived").WithArguments("Derived").WithLocation(1, 9) + ); + } + + [Fact] + public void EnforcedRequiredMembers_ShadowedFromMetadata_03() + { + var vb = @" +Imports System.Diagnostics.CodeAnalysis +Imports System.Runtime.CompilerServices + +Public Class Base + + Public Property P As Integer +End Class + +Public Class Derived + Inherits Base + Public Shadows Property P As Integer + + Public Sub New() + End Sub + + + Public Sub New(unused As Integer) + End Sub +End Class +"; + + var vbComp = CreateVisualBasicCompilationWithRequiredMembers(vb); + CompileAndVerify(vbComp).VerifyDiagnostics(); + + var c = """ + _ = new Derived(); + _ = new Derived(1); + """; + var comp = CreateCompilation(c, new[] { vbComp.EmitToImageReference() }); + comp.VerifyDiagnostics( + // (1,9): error CS9037: The required members list for 'Derived' is malformed and cannot be interpreted. + // _ = new Derived(); + Diagnostic(ErrorCode.ERR_RequiredMembersInvalid, "Derived").WithArguments("Derived").WithLocation(1, 9) + ); + } + + [Fact] + public void InterpolatedStringHandlerWithRequiredMembers() + { + var code = @" +CustomHandler handler = $""""; + +partial class CustomHandler +{ + public required int Field; +}"; + + var handler = GetInterpolatedStringCustomHandlerType("CustomHandler", "partial class", useBoolReturns: false); + + var comp = CreateCompilationWithRequiredMembers(new[] { code, handler }); + comp.VerifyDiagnostics( + // (2,25): error CS9035: Required member 'CustomHandler.Field' must be set in the object initializer or attribute constructor. + // CustomHandler handler = $""; + Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, @"$""""").WithArguments("CustomHandler.Field").WithLocation(2, 25) + ); + } + + [Fact] + public void CoClassWithRequiredMembers_NoneSet() + { + string code = @" +using System; +using System.Runtime.InteropServices; + +_ = new I(); + +[ComImport, Guid(""00020810-0000-0000-C000-000000000046"")] +[CoClass(typeof(C))] +interface I +{ +} + +class C : I +{ + public required int P { get; set; } +} + +"; + var comp = CreateCompilationWithRequiredMembers(code); + comp.VerifyDiagnostics( + // (5,9): error CS9035: Required member 'C.P' must be set in the object initializer or attribute constructor. + // _ = new I(); + Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "I").WithArguments("C.P").WithLocation(5, 9) + ); + } + + [Fact] + public void CoClassWithRequiredMembers_AllSet() + { + string code = @" +using System; +using System.Runtime.InteropServices; + +_ = new I() { P = 1 }; + +[ComImport, Guid(""00020810-0000-0000-C000-000000000046"")] +[CoClass(typeof(C))] +interface I +{ + public int P { get; set; } +} + +class C : I +{ + public required int P { get; set; } +} +"; + var comp = CreateCompilationWithRequiredMembers(code); + comp.VerifyDiagnostics( + // (5,9): error CS9035: Required member 'C.P' must be set in the object initializer or attribute constructor. + // _ = new I() { P = 1 }; + Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "I").WithArguments("C.P").WithLocation(5, 9) + ); + } + + [Fact] + public void RequiredMemberInAttribute_NotSet() + { + var code = @" +using System; + +[Attr] +class C +{ +} + +class AttrAttribute : Attribute +{ + public required int P { get; set; } +} +"; + + var comp = CreateCompilationWithRequiredMembers(code); + comp.VerifyDiagnostics( + // (4,2): error CS9035: Required member 'AttrAttribute.P' must be set in the object initializer or attribute constructor. + // [Attr] + Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "Attr").WithArguments("AttrAttribute.P").WithLocation(4, 2) + ); + } + + [Fact] + public void RequiredMemberInAttribute_AllSet() + { + var code = @" +using System; + +[Attr(P = 1, F = 2)] +class C +{ +} + +class AttrAttribute : Attribute +{ + public required int P { get; set; } + public required int F; +} +"; + + var comp = CreateCompilationWithRequiredMembers(code); + var verifier = CompileAndVerify(comp, symbolValidator: verify, sourceSymbolValidator: verify); + verifier.VerifyDiagnostics(); + + static void verify(ModuleSymbol module) + { + var c = module.GlobalNamespace.GetMember("C"); + var attr = c.GetAttributes().Single(); + AssertEx.Equal("AttrAttribute", attr.AttributeClass.ToTestDisplayString()); + Assert.Equal(2, attr.CommonNamedArguments.Length); + Assert.Equal(1, (int)attr.CommonNamedArguments[0].Value.ValueInternal!); + Assert.Equal(2, (int)attr.CommonNamedArguments[1].Value.ValueInternal!); + } + } + + [Fact] + public void RequiredMemberInAttribute_Recursive01() + { + var code = @" +using System; + +[Attr(P = 1, F = 2)] +class AttrAttribute : Attribute +{ + public required int P { get; set; } + public required int F; +} +"; + + var comp = CreateCompilationWithRequiredMembers(code); + var verifier = CompileAndVerify(comp, symbolValidator: verify, sourceSymbolValidator: verify); + verifier.VerifyDiagnostics(); + + static void verify(ModuleSymbol module) + { + var attrAttribute = module.GlobalNamespace.GetMember("AttrAttribute"); + var attr = attrAttribute.GetAttributes().Where(a => a.AttributeClass!.Name == "AttrAttribute").Single(); + AssertEx.Equal("AttrAttribute", attr.AttributeClass.ToTestDisplayString()); + Assert.Equal(2, attr.CommonNamedArguments.Length); + Assert.Equal(1, (int)attr.CommonNamedArguments[0].Value.ValueInternal!); + Assert.Equal(2, (int)attr.CommonNamedArguments[1].Value.ValueInternal!); + } + } + + [Fact] + public void RequiredMemberInAttribute_Recursive02() + { + var code = @" +using System; + +class AttrAttribute : Attribute +{ + [Attr(P = 1, F = 2)] + public required int P { get; set; } + public required int F; +} +"; + + var comp = CreateCompilationWithRequiredMembers(code); + var verifier = CompileAndVerify(comp, symbolValidator: verify, sourceSymbolValidator: verify); + verifier.VerifyDiagnostics(); + + static void verify(ModuleSymbol module) + { + var attrAttribute = module.GlobalNamespace.GetMember("AttrAttribute"); + var p = attrAttribute.GetMember("P"); + var attr = p.GetAttributes().Where(a => a.AttributeClass!.Name == "AttrAttribute").Single(); + AssertEx.Equal("AttrAttribute", attr.AttributeClass.ToTestDisplayString()); + Assert.Equal(2, attr.CommonNamedArguments.Length); + Assert.Equal(1, (int)attr.CommonNamedArguments[0].Value.ValueInternal!); + Assert.Equal(2, (int)attr.CommonNamedArguments[1].Value.ValueInternal!); + } + } + + [Fact] + public void RequiredMemberInAttribute_Recursive03() + { + var code = @" +using System; + +class AttrAttribute : Attribute +{ + public required int P { get; set; } + [Attr(P = 1, F = 2)] + public required int F; +} +"; + + var comp = CreateCompilationWithRequiredMembers(code); + var verifier = CompileAndVerify(comp, symbolValidator: verify, sourceSymbolValidator: verify); + verifier.VerifyDiagnostics(); + + static void verify(ModuleSymbol module) + { + var attrAttribute = module.GlobalNamespace.GetMember("AttrAttribute"); + var f = attrAttribute.GetMember("F"); + var attr = f.GetAttributes().Where(a => a.AttributeClass!.Name == "AttrAttribute").Single(); + AssertEx.Equal("AttrAttribute", attr.AttributeClass.ToTestDisplayString()); + Assert.Equal(2, attr.CommonNamedArguments.Length); + Assert.Equal(1, (int)attr.CommonNamedArguments[0].Value.ValueInternal!); + Assert.Equal(2, (int)attr.CommonNamedArguments[1].Value.ValueInternal!); + } + } + + [Fact] + public void RequiredMemberInAttribute_Recursive04() + { + var code = @" +namespace System.Runtime.CompilerServices; + +[RequiredMember] +public class RequiredMemberAttribute : Attribute +{ + public required int P { get; set; } +} +"; + + var comp = CreateCompilation(new[] { code, CompilerFeatureRequiredAttribute }); + comp.VerifyDiagnostics( + // (4,2): error CS9035: Required member 'RequiredMemberAttribute.P' must be set in the object initializer or attribute constructor. + // [RequiredMember] + Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "RequiredMember").WithArguments("System.Runtime.CompilerServices.RequiredMemberAttribute.P").WithLocation(4, 2), + // (4,2): error CS9033: Do not use 'System.Runtime.CompilerServices.RequiredMemberAttribute'. Use the 'required' keyword on required fields and properties instead. + // [RequiredMember] + Diagnostic(ErrorCode.ERR_ExplicitRequiredMember, "RequiredMember").WithLocation(4, 2) + ); + } + + [Fact] + public void RequiredMemberInAttribute_Recursive05() + { + var code = @" +namespace System.Runtime.CompilerServices; + +public class RequiredMemberAttribute : Attribute +{ + [RequiredMember] + public required int P { get; set; } +} +"; + + var comp = CreateCompilation(new[] { code, CompilerFeatureRequiredAttribute }); + comp.VerifyDiagnostics( + // (6,6): error CS9035: Required member 'RequiredMemberAttribute.P' must be set in the object initializer or attribute constructor. + // [RequiredMember] + Diagnostic(ErrorCode.ERR_RequiredMemberMustBeSet, "RequiredMember").WithArguments("System.Runtime.CompilerServices.RequiredMemberAttribute.P").WithLocation(6, 6), + // (6,6): error CS9033: Do not use 'System.Runtime.CompilerServices.RequiredMemberAttribute'. Use the 'required' keyword on required fields and properties instead. + // [RequiredMember] + Diagnostic(ErrorCode.ERR_ExplicitRequiredMember, "RequiredMember").WithLocation(6, 6) + ); + } + + [Fact] + public void SetsRequiredMemberInAttribute_Recursive() + { + var code = @" +namespace System.Diagnostics.CodeAnalysis; + +public class SetsRequiredMembersAttribute : Attribute +{ + public required int P { get; set; } + + [SetsRequiredMembers] + public SetsRequiredMembersAttribute() + { + } +} + +public class C +{ + public required int Prop { get; set; } + + [SetsRequiredMembers] + public C() + { + } + + static void M() + { + _ = new C(); + } +} +"; + + var comp = CreateCompilation(new[] { code, RequiredMemberAttribute, CompilerFeatureRequiredAttribute }); + comp.VerifyDiagnostics(); + } + + [Fact, CompilerTrait(CompilerFeature.NullableReferenceTypes)] + public void RequiredMemberSuppressesNullabilityWarnings_01() + { + var code = @" +#pragma warning disable CS0649 // Field is never assigned to +#nullable enable +class C +{ + public required string P1 { get; set; } + public required string F1; + public string P2 { get; set; } + public string F2; +} +"; + + var comp = CreateCompilationWithRequiredMembers(code); + comp.VerifyDiagnostics( + // (8,19): warning CS8618: Non-nullable property 'P2' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. + // public string P2 { get; set; } + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "P2").WithArguments("property", "P2").WithLocation(8, 19), + // (9,19): warning CS8618: Non-nullable field 'F2' must contain a non-null value when exiting constructor. Consider declaring the field as nullable. + // public string F2; + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "F2").WithArguments("field", "F2").WithLocation(9, 19) + ); + } + + [Fact, CompilerTrait(CompilerFeature.NullableReferenceTypes)] + public void RequiredMemberSuppressesNullabilityWarnings_02() + { + var code = @" +#pragma warning disable CS0649 // Field is never assigned to +#nullable enable +class C +{ + public required string P1 { get; set; } + public required string F1; + public string P2 { get; set; } + public string F2; + + public C() + { + } + + public C(int _) {} +} +"; + + var comp = CreateCompilationWithRequiredMembers(code); + comp.VerifyDiagnostics( + // (11,12): warning CS8618: Non-nullable property 'P2' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. + // public C() + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "C").WithArguments("property", "P2").WithLocation(11, 12), + // (11,12): warning CS8618: Non-nullable field 'F2' must contain a non-null value when exiting constructor. Consider declaring the field as nullable. + // public C() + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "C").WithArguments("field", "F2").WithLocation(11, 12), + // (15,12): warning CS8618: Non-nullable property 'P2' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. + // public C(int _) {} + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "C").WithArguments("property", "P2").WithLocation(15, 12), + // (15,12): warning CS8618: Non-nullable field 'F2' must contain a non-null value when exiting constructor. Consider declaring the field as nullable. + // public C(int _) {} + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "C").WithArguments("field", "F2").WithLocation(15, 12) + ); + } + + [Fact, CompilerTrait(CompilerFeature.NullableReferenceTypes)] + public void RequiredMemberSuppressesNullabilityWarnings_03() + { + var code = @" +#pragma warning disable CS0649 // Field is never assigned to +#nullable enable +struct S +{ + public required string P1 { get; set; } + public required string F1; + public string P2 { get; set; } + public string F2; +} +"; + + var comp = CreateCompilationWithRequiredMembers(code); + comp.VerifyDiagnostics( + ); + } + + [Fact, CompilerTrait(CompilerFeature.NullableReferenceTypes)] + public void RequiredMemberSuppressesNullabilityWarnings_04() + { + var code = @" +#pragma warning disable CS0649 // Field is never assigned to +#nullable enable +struct S +{ + public required string P1 { get; set; } + public required string F1; + public string P2 { get; set; } + public string F2; + + public S() {} +} +"; + + var comp = CreateCompilationWithRequiredMembers(code); + comp.VerifyDiagnostics( + // (11,12): warning CS8618: Non-nullable property 'P2' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. + // public S() {} + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "S").WithArguments("property", "P2").WithLocation(11, 12), + // (11,12): warning CS8618: Non-nullable field 'F2' must contain a non-null value when exiting constructor. Consider declaring the field as nullable. + // public S() {} + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "S").WithArguments("field", "F2").WithLocation(11, 12) + ); + } + + [Fact, CompilerTrait(CompilerFeature.NullableReferenceTypes)] + public void RequiredMemberSuppressesNullabilityWarnings_MemberNotNull_NoChainedConstructor() + { + var code = @" +using System.Diagnostics.CodeAnalysis; +#nullable enable +class C +{ + private string _field; + public required string Field { get => _field; [MemberNotNull(nameof(_field))] set => _field = value; } + + public C() { } +}"; + + var comp = CreateCompilationWithRequiredMembers(new[] { code, MemberNotNullAttributeDefinition }); + comp.VerifyDiagnostics( + // (9,12): warning CS8618: Non-nullable field '_field' must contain a non-null value when exiting constructor. Consider declaring the field as nullable. + // public C() { } + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "C").WithArguments("field", "_field").WithLocation(9, 12) + ); + } + + [Fact, CompilerTrait(CompilerFeature.NullableReferenceTypes)] + public void RequiredMemberSuppressesNullabilityWarnings_MemberNotNull_ChainedConstructor() + { + var code = @" +using System.Diagnostics.CodeAnalysis; +#nullable enable +class C +{ + private string _field; + public required string Field { get => _field; [MemberNotNull(nameof(_field))] set => _field = value; } + + public C() { } + public C(bool unused) : this() + { + _field.ToString(); + Field.ToString(); + } +}"; + + var comp = CreateCompilationWithRequiredMembers(new[] { code, MemberNotNullAttributeDefinition }); + comp.VerifyDiagnostics( + // (9,12): warning CS8618: Non-nullable field '_field' must contain a non-null value when exiting constructor. Consider declaring the field as nullable. + // public C() { } + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "C").WithArguments("field", "_field").WithLocation(9, 12) + ); + } + + [Fact, CompilerTrait(CompilerFeature.NullableReferenceTypes)] + public void RequiredMemberSuppressesNullabilityWarnings_ChainedConstructor_01() + { + var code = @" +#nullable enable +public class C +{ + public required string Prop { get; set; } + public required string Field; + + public C(bool unused) { } + + public C() : this(true) + { + Prop.ToString(); + Field.ToString(); + } +} +"; + + var comp = CreateCompilationWithRequiredMembers(code); + comp.VerifyDiagnostics( + // (12,9): warning CS8602: Dereference of a possibly null reference. + // Prop.ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "Prop").WithLocation(12, 9), + // (13,9): warning CS8602: Dereference of a possibly null reference. + // Field.ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "Field").WithLocation(13, 9) + ); + } + + [Fact, CompilerTrait(CompilerFeature.NullableReferenceTypes)] + public void RequiredMemberSuppressesNullabilityWarnings_ChainedConstructor_02() + { + var code = @" +#nullable enable +public struct C +{ + public required string Prop { get; set; } + public required string Field; + + public C(bool unused) { } + + public C() : this(true) + { + Prop.ToString(); + Field.ToString(); + } +} +"; + + var comp = CreateCompilationWithRequiredMembers(code); + comp.VerifyDiagnostics( + // (11,9): warning CS8602: Dereference of a possibly null reference. + // Prop.ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "Prop").WithLocation(12, 9), + // (13,9): warning CS8602: Dereference of a possibly null reference. + // Field.ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "Field").WithLocation(13, 9) + ); + } + + [Fact, CompilerTrait(CompilerFeature.NullableReferenceTypes)] + public void RequiredMemberSuppressesNullabilityWarnings_ChainedConstructor_03() + { + var code = @" +#nullable enable +public struct C +{ + public required string Prop { get; set; } + + public C(bool unused) : this() + { + Prop.ToString(); + } +} +"; + + var comp = CreateCompilationWithRequiredMembers(code); + comp.VerifyDiagnostics( + // (9,9): warning CS8602: Dereference of a possibly null reference. + // Prop.ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "Prop").WithLocation(9, 9) + ); + } + + [Theory, CompilerTrait(CompilerFeature.NullableReferenceTypes)] + [InlineData(": base()")] + [InlineData("")] + public void RequiredMemberSuppressesNullabilityWarnings_ChainedConstructor_04(string baseSyntax) + { + var code = $$""" +#nullable enable +public class Base +{ + public required string Prop1 { get; set; } + public string Prop2 { get; set; } = null!; + public required string Field1; + public string Field2 = null!; +} + +public class Derived : Base +{ + public Derived() {{baseSyntax}} + { + Prop1.ToString(); + Prop2.ToString(); + Field1.ToString(); + Field2.ToString(); + } +} +"""; + + var comp = CreateCompilationWithRequiredMembers(code); + comp.VerifyDiagnostics( + // (14,9): warning CS8602: Dereference of a possibly null reference. + // Prop1.ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "Prop1").WithLocation(14, 9), + // (16,9): warning CS8602: Dereference of a possibly null reference. + // Field1.ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "Field1").WithLocation(16, 9) + ); + } + + [Theory, CompilerTrait(CompilerFeature.NullableReferenceTypes)] + [InlineData(": base()")] + [InlineData("")] + public void RequiredMemberSuppressesNullabilityWarnings_ChainedConstructor_05(string baseSyntax) + { + var code = $$""" +#nullable enable +public class Base +{ + public required string Prop1 { get; set; } + public string Prop2 { get; set; } = null!; + public required string Field1; + public string Field2 = null!; +} + +public class Derived : Base +{ + public required string Prop3 { get; set; } + public string Prop4 { get; set; } = null!; + public required string Field3; + public string Field4 = null!; + + public Derived() {{baseSyntax}} + { + Prop1.ToString(); // 1 + Prop2.ToString(); + Prop3.ToString(); // 2 + Prop4.ToString(); + Field1.ToString(); // 1 + Field2.ToString(); + Field3.ToString(); // 2 + Field4.ToString(); + } +} +"""; + + var comp = CreateCompilationWithRequiredMembers(code); + comp.VerifyDiagnostics( + // (19,9): warning CS8602: Dereference of a possibly null reference. + // Prop1.ToString(); // 1 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "Prop1").WithLocation(19, 9), + // (21,9): warning CS8602: Dereference of a possibly null reference. + // Prop3.ToString(); // 2 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "Prop3").WithLocation(21, 9), + // (23,9): warning CS8602: Dereference of a possibly null reference. + // Field1.ToString(); // 1 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "Field1").WithLocation(23, 9), + // (25,9): warning CS8602: Dereference of a possibly null reference. + // Field3.ToString(); // 2 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "Field3").WithLocation(25, 9) + ); + } + + [Theory, CompilerTrait(CompilerFeature.NullableReferenceTypes)] + [InlineData(": base()")] + [InlineData("")] + public void RequiredMemberSuppressesNullabilityWarnings_ChainedConstructor_06(string baseSyntax) + { + var code = @$" +#nullable enable +public class Base +{{ + public required string Prop1 {{ get; set; }} + public string Prop2 {{ get; set; }} = null!; +}} + +public class Derived : Base +{{ + public required string Prop3 {{ get; set; }} + public string Prop4 {{ get; set; }} + + public Derived() {baseSyntax} + {{ + Prop1.ToString(); // 1 + Prop2.ToString(); + Prop3.ToString(); // 2 + Prop4.ToString(); // 3 + }} +}} +"; + + var comp = CreateCompilationWithRequiredMembers(code); + comp.VerifyDiagnostics( + // (16,9): warning CS8602: Dereference of a possibly null reference. + // Prop1.ToString(); // 1 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "Prop1").WithLocation(16, 9), + // (18,9): warning CS8602: Dereference of a possibly null reference. + // Prop3.ToString(); // 2 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "Prop3").WithLocation(18, 9), + // (19,9): warning CS8602: Dereference of a possibly null reference. + // Prop4.ToString(); // 3 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "Prop4").WithLocation(19, 9) + ); + } + + [Fact, CompilerTrait(CompilerFeature.NullableReferenceTypes)] + public void RequiredMemberSuppressesNullabilityWarnings_ChainedConstructor_07() + { + var code = @" +#nullable enable +public class Base +{ + public required string Prop1 { get; set; } + public string Prop2 { get; set; } = null!; +} + +public class Derived : Base +{ + public required string Prop3 { get; set; } + public string Prop4 { get; set; } + + public Derived(bool unused) { Prop4 = null!; } + + public Derived() : this(true) + { + Prop1.ToString(); // 1 + Prop2.ToString(); + Prop3.ToString(); // 2 + Prop4.ToString(); + } +} +"; + + var comp = CreateCompilationWithRequiredMembers(code); + comp.VerifyDiagnostics( + // (18,9): warning CS8602: Dereference of a possibly null reference. + // Prop1.ToString(); // 1 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "Prop1").WithLocation(18, 9), + // (20,9): warning CS8602: Dereference of a possibly null reference. + // Prop3.ToString(); // 2 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "Prop3").WithLocation(20, 9) + ); + } + + [Fact, CompilerTrait(CompilerFeature.NullableReferenceTypes)] + public void RequiredMemberSuppressesNullabilityWarnings_ChainedConstructor_08() + { + var code = """ + using System.Diagnostics.CodeAnalysis; + #nullable enable + public class Base + { + public required string Prop1 { get; set; } + public string Prop2 { get; set; } = null!; + + [SetsRequiredMembers] + protected Base() {} // 1 + } + + public class Derived : Base + { + public required string Prop3 { get; set; } + public string Prop4 { get; set; } + + public Derived() : base() // 2 + { + Prop1.ToString(); + Prop2.ToString(); + Prop3.ToString(); // 3 + Prop4.ToString(); // 4 + } + } + """; + + var comp = CreateCompilationWithRequiredMembers(code); + comp.VerifyDiagnostics( + // (9,15): warning CS8618: Non-nullable property 'Prop1' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. + // protected Base() {} // 1 + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "Base").WithArguments("property", "Prop1").WithLocation(9, 15), + // (17,24): error CS9039: This constructor must add 'SetsRequiredMembers' because it chains to a constructor that has that attribute. + // public Derived() : base() // 2 + Diagnostic(ErrorCode.ERR_ChainingToSetsRequiredMembersRequiresSetsRequiredMembers, "base").WithLocation(17, 24), + // (21,9): warning CS8602: Dereference of a possibly null reference. + // Prop3.ToString(); // 3 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "Prop3").WithLocation(21, 9), + // (22,9): warning CS8602: Dereference of a possibly null reference. + // Prop4.ToString(); // 4 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "Prop4").WithLocation(22, 9) + ); + } + + [Fact, CompilerTrait(CompilerFeature.NullableReferenceTypes)] + public void RequiredMemberSuppressesNullabilityWarnings_ChainedConstructor_09() + { + var code = """ + using System.Diagnostics.CodeAnalysis; + #nullable enable + public class Base + { + public required string Prop1 { get; set; } + public string Prop2 { get; set; } = null!; + + protected Base() {} + } + + public class Derived : Base + { + public required string Prop3 { get; set; } + public string Prop4 { get; set; } + + [SetsRequiredMembers] + public Derived(int unused) : base() + { + Prop4 = null!; + } + + public Derived() : this(0) + { + Prop1.ToString(); + Prop2.ToString(); + Prop3.ToString(); + Prop4.ToString(); + } + } + """; + + var comp = CreateCompilationWithRequiredMembers(code); + comp.VerifyDiagnostics( + // (17,12): warning CS8618: Non-nullable property 'Prop3' must contain a non-null value when exiting constructor. Consider declaring the property as nullable. + // public Derived(int unused) : base() + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "Derived").WithArguments("property", "Prop3").WithLocation(17, 12), + // (22,24): error CS9039: This constructor must add 'SetsRequiredMembers' because it chains to a constructor that has that attribute. + // public Derived() : this(0) + Diagnostic(ErrorCode.ERR_ChainingToSetsRequiredMembersRequiresSetsRequiredMembers, "this").WithLocation(22, 24) + ); + } + + [Fact, CompilerTrait(CompilerFeature.NullableReferenceTypes)] + public void RequiredMemberSuppressesNullabilityWarnings_ChainedConstructor_10() + { + // This IL is equivalent to: + // #nullable enable + // [constructor: SetsRequiredMembers] + // public record Base(bool unused) { public required string Prop { get; init; } } + var il = """ + .assembly extern attr {} + + .class public auto ansi beforefieldinit Base + extends [mscorlib]System.Object + implements class [mscorlib]System.IEquatable`1 + { + .custom instance void System.Runtime.CompilerServices.NullableContextAttribute::.ctor(uint8) = ( + 01 00 01 00 00 + ) + .custom instance void System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = ( + 01 00 00 00 00 + ) + // Fields + .field public string Field1 + .custom instance void [attr]RequiredMemberAttribute::.ctor() = ( + 01 00 00 00 + ) + .field public string Field2 + .custom instance void System.Runtime.CompilerServices.NullableAttribute::.ctor(uint8) = ( + 01 00 02 00 00 + ) + .custom instance void [attr]RequiredMemberAttribute::.ctor() = ( + 01 00 00 00 + ) + + // Methods + .method public hidebysig specialname rtspecialname + instance void .ctor ( + bool 'unused' + ) cil managed + { + .custom instance void [attr]System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute::.ctor() = ( + 01 00 00 00 + ) + ldnull + throw + } // end of method Base::.ctor + + .method family hidebysig specialname newslot virtual + instance class [mscorlib]System.Type get_EqualityContract () cil managed + { + .custom instance void [mscorlib]mscorlib.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + ldnull + throw + } // end of method Base::get_EqualityContract + + .method public hidebysig specialname + instance bool get_unused () cil managed + { + .custom instance void [mscorlib]mscorlib.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + ldnull + throw + } // end of method Base::get_unused + + .method public hidebysig specialname + instance void modreq([mscorlib]mscorlib.CompilerServices.IsExternalInit) set_unused ( + bool 'value' + ) cil managed + { + .custom instance void [mscorlib]mscorlib.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + ldnull + throw + } // end of method Base::set_unused + + .method public hidebysig virtual + instance string ToString () cil managed + { + .custom instance void [mscorlib]mscorlib.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + ldnull + throw + } // end of method Base::ToString + + .method family hidebysig newslot virtual + instance bool PrintMembers ( + class [mscorlib]System.Text.StringBuilder builder + ) cil managed + { + .custom instance void [mscorlib]mscorlib.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + ldnull + throw + } // end of method Base::PrintMembers + + .method public hidebysig specialname static + bool op_Inequality ( + class Base left, + class Base right + ) cil managed + { + .custom instance void [mscorlib]mscorlib.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + ldnull + throw + } // end of method Base::op_Inequality + + .method public hidebysig specialname static + bool op_Equality ( + class Base left, + class Base right + ) cil managed + { + .custom instance void [mscorlib]mscorlib.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + ldnull + throw + } // end of method Base::op_Equality + + .method public hidebysig virtual + instance int32 GetHashCode () cil managed + { + .custom instance void [mscorlib]mscorlib.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + ldnull + throw + } // end of method Base::GetHashCode + + .method public hidebysig virtual + instance bool Equals ( + object obj + ) cil managed + { + .custom instance void [mscorlib]mscorlib.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + ldnull + throw + } // end of method Base::Equals + + .method public hidebysig newslot virtual + instance bool Equals ( + class Base other + ) cil managed + { + .custom instance void [mscorlib]mscorlib.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + ldnull + throw + } // end of method Base::Equals + + .method public hidebysig newslot virtual + instance class Base '$' () cil managed + { + .custom instance void [mscorlib]mscorlib.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + ldnull + throw + } // end of method Base::'$' + + .method family hidebysig specialname rtspecialname + instance void .ctor ( + class Base original + ) cil managed + { + .custom instance void [mscorlib]mscorlib.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + ldnull + throw + } // end of method Base::.ctor + + .method public hidebysig + instance void Deconstruct ( + [out] bool& 'unused' + ) cil managed + { + .custom instance void [mscorlib]mscorlib.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + ldnull + throw + } // end of method Base::Deconstruct + + // Properties + .property instance class [mscorlib]System.Type EqualityContract() + { + .get instance class [mscorlib]System.Type Base::get_EqualityContract() + } + .property instance bool 'unused'() + { + .get instance bool Base::get_unused() + .set instance void modreq([mscorlib]mscorlib.CompilerServices.IsExternalInit) Base::set_unused(bool) + } + } // end of class Base + + .class private auto ansi sealed beforefieldinit System.Runtime.CompilerServices.NullableAttribute + extends [mscorlib]System.Attribute + { + .custom instance void [mscorlib]mscorlib.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + .custom instance void Microsoft.CodeAnalysis.EmbeddedAttribute::.ctor() = ( + 01 00 00 00 + ) + .custom instance void [mscorlib]System.AttributeUsageAttribute::.ctor(valuetype [mscorlib]System.AttributeTargets) = ( + 01 00 84 6b 00 00 02 00 54 02 0d 41 6c 6c 6f 77 + 4d 75 6c 74 69 70 6c 65 00 54 02 09 49 6e 68 65 + 72 69 74 65 64 00 + ) + // Fields + .field public initonly uint8[] NullableFlags + + // Methods + .method public hidebysig specialname rtspecialname + instance void .ctor ( + uint8 '' + ) cil managed + { + ldnull + throw + } // end of method NullableAttribute::.ctor + + .method public hidebysig specialname rtspecialname + instance void .ctor ( + uint8[] '' + ) cil managed + { + ldnull + throw + } // end of method NullableAttribute::.ctor + } // end of class mscorlib.CompilerServices.NullableAttribute + + .class private auto ansi sealed beforefieldinit System.Runtime.CompilerServices.NullableContextAttribute + extends [mscorlib]System.Attribute + { + .custom instance void [mscorlib]mscorlib.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + .custom instance void Microsoft.CodeAnalysis.EmbeddedAttribute::.ctor() = ( + 01 00 00 00 + ) + .custom instance void [mscorlib]System.AttributeUsageAttribute::.ctor(valuetype [mscorlib]System.AttributeTargets) = ( + 01 00 4c 14 00 00 02 00 54 02 0d 41 6c 6c 6f 77 + 4d 75 6c 74 69 70 6c 65 00 54 02 09 49 6e 68 65 + 72 69 74 65 64 00 + ) + // Fields + .field public initonly uint8 Flag + + // Methods + .method public hidebysig specialname rtspecialname + instance void .ctor ( + uint8 '' + ) cil managed + { + ldnull + throw + } // end of method NullableContextAttribute::.ctor + } + .class private auto ansi sealed beforefieldinit Microsoft.CodeAnalysis.EmbeddedAttribute + extends [mscorlib]System.Attribute + { + .custom instance void [mscorlib]mscorlib.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + .custom instance void Microsoft.CodeAnalysis.EmbeddedAttribute::.ctor() = ( + 01 00 00 00 + ) + // Methods + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + ldnull + throw + } // end of method EmbeddedAttribute::.ctor + } // end of class Microsoft.CodeAnalysis.EmbeddedAttribute + """; + + var attrComp = CreateCompilationWithRequiredMembers("", assemblyName: "attr"); + + var code = """ + #nullable enable + public record Derived(bool unused) : Base(unused); + """; + + var comp = CreateCompilationWithIL(code, ilSource: il, references: new[] { attrComp.EmitToImageReference() }); + comp.VerifyDiagnostics( + // (2,42): error CS9039: This constructor must add 'SetsRequiredMembers' because it chains to a constructor that has that attribute. + // public record Derived(bool unused) : Base(unused); + Diagnostic(ErrorCode.ERR_ChainingToSetsRequiredMembersRequiresSetsRequiredMembers, "(unused)").WithLocation(2, 42) + ); + } + + [Fact] + public void SetsRequiredMembersAppliedToRecordCopyConstructor_DeclaredInType() + { + var code = """ + public record C + { + public required string Prop1 { get; set; } + public required int Field1; + } + """; + + var comp = CreateCompilationWithRequiredMembers(code); + CompileAndVerify(comp, sourceSymbolValidator: validate, symbolValidator: validate); + + void validate(ModuleSymbol module) + { + var c = module.GlobalNamespace.GetTypeMember("C"); + var copyCtor = c.GetMembers(".ctor").Cast().Single(m => m.ParameterCount == 1); + + if (copyCtor is SynthesizedRecordCopyCtor) + { + Assert.Empty(copyCtor.GetAttributes()); + } + else + { + AssertEx.Equal("System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute..ctor()", + copyCtor.GetAttributes().Single(a => a.AttributeClass!.IsWellKnownSetsRequiredMembersAttribute()).AttributeConstructor.ToTestDisplayString()); + } + } + } + + [Fact] + public void SetsRequiredMembersAppliedToRecordCopyConstructor_DeclaredInType_SetsRequiredMembersMissing() + { + var code = """ + public record C + { + public required string Prop1 { get; set; } + public required int Field1; + } + """; + + var comp = CreateCompilationWithRequiredMembers(code); + comp.MakeMemberMissing(WellKnownMember.System_Diagnostics_CodeAnalysis_SetsRequiredMembersAttribute__ctor); + comp.VerifyDiagnostics( + // (1,15): error CS0656: Missing compiler required member 'System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute..ctor' + // public record C + Diagnostic(ErrorCode.ERR_MissingPredefinedMember, "C").WithArguments("System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute", ".ctor").WithLocation(1, 15) + ); + } + + [Fact, CompilerTrait(CompilerFeature.NullableReferenceTypes)] + public void RequiredMemberSuppressesNullabilityWarnings_ChainedConstructor_11() + { + var code = """ + #nullable enable + public class Base + { + public required string Prop1 { get; set; } + public string Prop2 { get; set; } = null!; + } + + public class Derived : Base + { + public required string Prop3 { get; set; } = Prop1.ToString(); + public string Prop4 { get; set; } = Prop2.ToString(); + } + """; + + var comp = CreateCompilationWithRequiredMembers(code); + comp.VerifyDiagnostics( + // (10,50): error CS0236: A field initializer cannot reference the non-static field, method, or property 'Base.Prop1' + // public required string Prop3 { get; set; } = Prop1.ToString(); + Diagnostic(ErrorCode.ERR_FieldInitRefNonstatic, "Prop1").WithArguments("Base.Prop1").WithLocation(10, 50), + // (11,41): error CS0236: A field initializer cannot reference the non-static field, method, or property 'Base.Prop2' + // public string Prop4 { get; set; } = Prop2.ToString(); + Diagnostic(ErrorCode.ERR_FieldInitRefNonstatic, "Prop2").WithArguments("Base.Prop2").WithLocation(11, 41) + ); + } + + [Theory] + [CombinatorialData] + public void SetsRequiredMembersAppliedToRecordCopyConstructor_DeclaredInBase(bool useMetadataReference) + { + var @base = """ + public record Base + { + public required string Prop1 { get; set; } + public required int Field1; + } + """; + + var code = """ + public record Derived : Base; + """; + + var comp = CreateCompilationWithRequiredMembers(new[] { @base, code }); + CompileAndVerify(comp, sourceSymbolValidator: validate, symbolValidator: validate); + + var baseComp = CreateCompilationWithRequiredMembers(@base); + CompileAndVerify(baseComp).VerifyDiagnostics(); + + comp = CreateCompilation(code, references: new[] { useMetadataReference ? baseComp.ToMetadataReference() : baseComp.EmitToImageReference() }); + CompileAndVerify(comp, sourceSymbolValidator: validate, symbolValidator: validate); + + void validate(ModuleSymbol module) + { + var c = module.GlobalNamespace.GetTypeMember("Derived"); + var copyCtor = c.GetMembers(".ctor").Cast().Single(m => m.ParameterCount == 1); + + if (copyCtor is SynthesizedRecordCopyCtor) + { + Assert.Empty(copyCtor.GetAttributes()); + } + else + { + AssertEx.Equal("System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute..ctor()", + copyCtor.GetAttributes().Single(a => a.AttributeClass!.IsWellKnownSetsRequiredMembersAttribute()).AttributeConstructor.ToTestDisplayString()); + } + } + } + + [Theory] + [InlineData("struct")] + [InlineData("class")] + public void ForbidRequiredAsNew_NoInheritance(string typeKind) + { + var code = $$""" + M(); + + void M() where T : new() + { + } + + {{typeKind}} C + { + public required int Prop1 { get; set; } + } + """; + + var comp = CreateCompilationWithRequiredMembers(code); + comp.VerifyDiagnostics( + // (1,1): error CS9040: 'C' cannot satisfy the 'new()' constraint on parameter 'T' in the generic type or or method 'M()' because 'C' has required members. + // M(); + Diagnostic(ErrorCode.ERR_NewConstraintCannotHaveRequiredMembers, "M").WithArguments("M()", "T", "C").WithLocation(1, 1) + ); + } + + [Theory] + [CombinatorialData] + public void ForbidRequiredAsNew_Inheritance(bool useMetadataReference) + { + var @base = """ + public class Base + { + public required int Prop1 { get; set; } + } + """; + + var code = """ + M(); + + void M() where T : new() + { + } + + class Derived : Base + { + } + """; + + var comp = CreateCompilationWithRequiredMembers(new[] { @base, code }); + comp.VerifyDiagnostics( + // (1,1): error CS9040: 'Derived' cannot satisfy the 'new()' constraint on parameter 'T' in the generic type or or method 'M()' because 'Derived' has required members. + // M(); + Diagnostic(ErrorCode.ERR_NewConstraintCannotHaveRequiredMembers, "M").WithArguments("M()", "T", "Derived").WithLocation(1, 1) + ); + + var baseComp = CreateCompilationWithRequiredMembers(@base); + CompileAndVerify(baseComp).VerifyDiagnostics(); + + comp = CreateCompilation(code, references: new[] { useMetadataReference ? baseComp.ToMetadataReference() : baseComp.EmitToImageReference() }); + comp.VerifyDiagnostics( + // (1,1): error CS9040: 'Derived' cannot satisfy the 'new()' constraint on parameter 'T' in the generic type or or method 'M()' because 'Derived' has required members. + // M(); + Diagnostic(ErrorCode.ERR_NewConstraintCannotHaveRequiredMembers, "M").WithArguments("M()", "T", "Derived").WithLocation(1, 1) + ); + } + + [Theory] + [InlineData("class")] + [InlineData("struct")] + public void AllowRequiredAsNew_SetsRequiredMembersOnConstructor(string typeKind) + { + var code = $$""" + using System.Diagnostics.CodeAnalysis; + M(); + + void M() where T : new() + { + } + + {{typeKind}} C + { + public required int Prop1 { get; set; } + + [SetsRequiredMembers] + public C() + { + } + } + """; + + var comp = CreateCompilationWithRequiredMembers(code); + CompileAndVerify(comp).VerifyDiagnostics(); + } + + [Fact] + public void AllowRequiredAsNew_IndirectionViaStruct() + { + var code = """ + M1(); + + void M1() where T : struct + { + M2(); + } + + void M2() where T : new() + { + } + + struct C + { + public required int Prop1 { get; set; } + } + """; + + var comp = CreateCompilationWithRequiredMembers(code); + CompileAndVerify(comp).VerifyDiagnostics(); + } + + [Fact] + public void HasExistingObsoleteAttribute_RequiredMembersOnSelf() + { + var code = """ + using System; + class C + { + public required int Prop { get; set; } + + [Obsolete("Reason 1", false)] + public C() { } + + + [Obsolete("Reason 2", true)] + public C(int unused) { } + } + """; + + var comp = CreateCompilationWithRequiredMembers(code); + CompileAndVerify(comp, symbolValidator: validate, sourceSymbolValidator: validate).VerifyDiagnostics(); + + static void validate(ModuleSymbol m) + { + var c = m.GlobalNamespace.GetTypeMember("C"); + var ctors = c.GetMembers(".ctor").Cast().ToArray(); + + Assert.Equal(2, ctors.Length); + + assertAttributeData(ctors[0], "Reason 1", expectedError: false); + assertAttributeData(ctors[1], "Reason 2", expectedError: true); + + static void assertAttributeData(MethodSymbol ctor, string expectedReason, bool expectedError) + { + var attrData = ctor.GetAttributes().Single(); + AssertEx.Equal("System.ObsoleteAttribute", attrData.AttributeClass.ToTestDisplayString()); + var attrArgs = attrData.ConstructorArguments.ToArray(); + Assert.Equal(2, attrArgs.Length); + AssertEx.Equal(expectedReason, (string)attrArgs[0].ValueInternal!); + Assert.Equal(expectedError, (bool)attrArgs[1].ValueInternal!); + } + } + } + + [Fact] + public void HasExistingObsoleteAttribute_RequiredMembersOnBase() + { + var code = """ + using System; + class Base + { + public required int Prop { get; set; } + } + + class Derived : Base + { + [Obsolete("Reason 1", false)] + public Derived() { } + + + [Obsolete("Reason 2", true)] + public Derived(int unused) { } + } + """; + + var comp = CreateCompilationWithRequiredMembers(code); + CompileAndVerify(comp, symbolValidator: validate, sourceSymbolValidator: validate).VerifyDiagnostics(); + + static void validate(ModuleSymbol m) + { + var c = m.GlobalNamespace.GetTypeMember("Derived"); + var ctors = c.GetMembers(".ctor").Cast().ToArray(); + + Assert.Equal(2, ctors.Length); + + assertAttributeData(ctors[0], "Reason 1", expectedError: false); + assertAttributeData(ctors[1], "Reason 2", expectedError: true); + + static void assertAttributeData(MethodSymbol ctor, string expectedReason, bool expectedError) + { + var attrData = ctor.GetAttributes().Single(); + AssertEx.Equal("System.ObsoleteAttribute", attrData.AttributeClass.ToTestDisplayString()); + var attrArgs = attrData.ConstructorArguments.ToArray(); + Assert.Equal(2, attrArgs.Length); + AssertEx.Equal(expectedReason, (string)attrArgs[0].ValueInternal!); + Assert.Equal(expectedError, (bool)attrArgs[1].ValueInternal!); + } + } + } + + [Theory] + [CombinatorialData] + public void PublicAPITests(bool isRequired) + { + var requiredText = isRequired ? "required" : ""; + var comp = CreateCompilationWithRequiredMembers($$""" + public class C + { + public {{requiredText}} int Field; + public {{requiredText}} int Property { get; set; } + } + """); + + var c = comp.GlobalNamespace.GetTypeMember("C"); + + var field = c.GetField("Field").GetPublicSymbol(); + Assert.Equal(isRequired, field.IsRequired); + + var property = c.GetProperty("Property").GetPublicSymbol(); + Assert.Equal(isRequired, property.IsRequired); + } +} diff --git a/src/Compilers/CSharp/Test/Syntax/Diagnostics/DiagnosticTest.cs b/src/Compilers/CSharp/Test/Syntax/Diagnostics/DiagnosticTest.cs index 1747b716dcf6d..276e7d3c00751 100644 --- a/src/Compilers/CSharp/Test/Syntax/Diagnostics/DiagnosticTest.cs +++ b/src/Compilers/CSharp/Test/Syntax/Diagnostics/DiagnosticTest.cs @@ -270,6 +270,7 @@ public void WarningLevel_2() case ErrorCode.WRN_CallerMemberNamePreferredOverCallerArgumentExpression: case ErrorCode.WRN_CallerArgumentExpressionAttributeHasInvalidParameterName: case ErrorCode.WRN_CallerArgumentExpressionAttributeSelfReferential: + case ErrorCode.WRN_ObsoleteMembersShouldNotBeRequired: Assert.Equal(1, ErrorFacts.GetWarningLevel(errorCode)); break; case ErrorCode.WRN_MainIgnored: diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/MemberDeclarationParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/MemberDeclarationParsingTests.cs index 2337ff563f551..91c17017ab136 100644 --- a/src/Compilers/CSharp/Test/Syntax/Parsing/MemberDeclarationParsingTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Parsing/MemberDeclarationParsingTests.cs @@ -4,6 +4,7 @@ #nullable disable +using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -34,6 +35,10 @@ private SyntaxTree UsingTree(string text, CSharpParseOptions options, params Dia return tree; } + private static readonly CSharpParseOptions RequiredMembersOptions = TestOptions.RegularNext; + public static readonly IEnumerable Regular10AndScriptAndRequiredMembersMinimum = new[] { new[] { TestOptions.Regular10 }, new[] { RequiredMembersOptions }, new[] { TestOptions.Script.WithLanguageVersion(LanguageVersion.CSharp10) } }; + public static readonly IEnumerable Regular10AndScript = new[] { new[] { TestOptions.Regular10 }, new[] { TestOptions.Script.WithLanguageVersion(LanguageVersion.CSharp10) } }; + [Fact] [WorkItem(367, "https://github.com/dotnet/roslyn/issues/367")] public void ParsePrivate() @@ -1206,6 +1211,717 @@ public void SetAndInitAccessor() } } + [Theory, CompilerTrait(CompilerFeature.RequiredMembers)] + [MemberData(nameof(Regular10AndScriptAndRequiredMembersMinimum))] + public void RequiredModifierProperty_01(CSharpParseOptions parseOptions) + { + UsingDeclaration("required string Prop { get; }", options: parseOptions); + N(SyntaxKind.PropertyDeclaration); + { + N(SyntaxKind.RequiredKeyword); + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.StringKeyword); + } + N(SyntaxKind.IdentifierToken, "Prop"); + N(SyntaxKind.AccessorList); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.GetAccessorDeclaration); + { + N(SyntaxKind.GetKeyword); + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } + + [Theory, CompilerTrait(CompilerFeature.RequiredMembers)] + [MemberData(nameof(Regular10AndScript))] + public void RequiredModifierProperty_02(CSharpParseOptions parseOptions) + { + UsingDeclaration("required Prop { get; }", options: parseOptions); + N(SyntaxKind.PropertyDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "required"); + } + N(SyntaxKind.IdentifierToken, "Prop"); + N(SyntaxKind.AccessorList); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.GetAccessorDeclaration); + { + N(SyntaxKind.GetKeyword); + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } + + [Fact, CompilerTrait(CompilerFeature.RequiredMembers)] + public void RequiredModifierProperty_03() + { + UsingDeclaration("required Prop { get; }", options: RequiredMembersOptions, + // (1,1): error CS1073: Unexpected token '{' + // required Prop { get; } + Diagnostic(ErrorCode.ERR_UnexpectedToken, "required Prop").WithArguments("{").WithLocation(1, 1), + // (1,15): error CS1519: Invalid token '{' in class, record, struct, or interface member declaration + // required Prop { get; } + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "{").WithArguments("{").WithLocation(1, 15) + ); + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.RequiredKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Prop"); + } + } + EOF(); + } + + [Theory, CompilerTrait(CompilerFeature.RequiredMembers)] + [MemberData(nameof(Regular10AndScript))] + public void RequiredModifierProperty_04(CSharpParseOptions parseOptions) + { + UsingDeclaration("required required { get; }", options: parseOptions); + N(SyntaxKind.PropertyDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "required"); + } + N(SyntaxKind.IdentifierToken, "required"); + N(SyntaxKind.AccessorList); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.GetAccessorDeclaration); + { + N(SyntaxKind.GetKeyword); + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } + + [Fact, CompilerTrait(CompilerFeature.RequiredMembers)] + public void RequiredModifierProperty_05() + { + UsingDeclaration("required required { get; }", options: RequiredMembersOptions, + // (1,1): error CS1073: Unexpected token '{' + // required required { get; } + Diagnostic(ErrorCode.ERR_UnexpectedToken, "required required").WithArguments("{").WithLocation(1, 1), + // (1,19): error CS1519: Invalid token '{' in class, record, struct, or interface member declaration + // required required { get; } + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "{").WithArguments("{").WithLocation(1, 19) + ); + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.RequiredKeyword); + N(SyntaxKind.RequiredKeyword); + } + EOF(); + } + + [Fact, CompilerTrait(CompilerFeature.RequiredMembers)] + public void RequiredModifierProperty_06() + { + UsingDeclaration("required required Prop { get; }", options: RequiredMembersOptions, + // (1,1): error CS1073: Unexpected token '{' + // required required Prop { get; } + Diagnostic(ErrorCode.ERR_UnexpectedToken, "required required Prop").WithArguments("{").WithLocation(1, 1), + // (1,24): error CS1519: Invalid token '{' in class, record, struct, or interface member declaration + // required required Prop { get; } + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "{").WithArguments("{").WithLocation(1, 24) + ); + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.RequiredKeyword); + N(SyntaxKind.RequiredKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Prop"); + } + } + EOF(); + } + + [Fact, CompilerTrait(CompilerFeature.RequiredMembers)] + public void RequiredModifierProperty_07() + { + UsingDeclaration("required Type required { get; }", options: RequiredMembersOptions); + N(SyntaxKind.PropertyDeclaration); + { + N(SyntaxKind.RequiredKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Type"); + } + N(SyntaxKind.IdentifierToken, "required"); + N(SyntaxKind.AccessorList); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.GetAccessorDeclaration); + { + N(SyntaxKind.GetKeyword); + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } + + [Theory, CompilerTrait(CompilerFeature.RequiredMembers)] + [MemberData(nameof(Regular10AndScriptAndRequiredMembersMinimum))] + public void RequiredModifierField_01(CSharpParseOptions parseOptions) + { + UsingDeclaration("required string Field;", options: parseOptions); + N(SyntaxKind.FieldDeclaration); + { + N(SyntaxKind.RequiredKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.StringKeyword); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "Field"); + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Theory, CompilerTrait(CompilerFeature.RequiredMembers)] + [MemberData(nameof(Regular10AndScript))] + public void RequiredModifierField_02(CSharpParseOptions parseOptions) + { + UsingDeclaration("required Field;", options: parseOptions); + N(SyntaxKind.FieldDeclaration); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "required"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "Field"); + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Fact, CompilerTrait(CompilerFeature.RequiredMembers)] + public void RequiredModifierField_03() + { + UsingDeclaration("required Field;", options: RequiredMembersOptions, + // (1,1): error CS1073: Unexpected token ';' + // required Field; + Diagnostic(ErrorCode.ERR_UnexpectedToken, "required Field").WithArguments(";").WithLocation(1, 1), + // (1,15): error CS1519: Invalid token ';' in class, record, struct, or interface member declaration + // required Field; + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ";").WithArguments(";").WithLocation(1, 15) + ); + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.RequiredKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "Field"); + } + } + EOF(); + } + + [Theory, CompilerTrait(CompilerFeature.RequiredMembers)] + [MemberData(nameof(Regular10AndScript))] + public void RequiredModifierField_04(CSharpParseOptions parseOptions) + { + UsingDeclaration("required required;", options: parseOptions); + N(SyntaxKind.FieldDeclaration); + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "required"); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "required"); + } + } + N(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Fact, CompilerTrait(CompilerFeature.RequiredMembers)] + public void RequiredModifierField_05() + { + UsingDeclaration("required required;", options: RequiredMembersOptions, + // (1,1): error CS1073: Unexpected token ';' + // required required; + Diagnostic(ErrorCode.ERR_UnexpectedToken, "required required").WithArguments(";").WithLocation(1, 1), + // (1,18): error CS1519: Invalid token ';' in class, record, struct, or interface member declaration + // required required; + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, ";").WithArguments(";").WithLocation(1, 18) + ); + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.RequiredKeyword); + N(SyntaxKind.RequiredKeyword); + } + EOF(); + } + + [Theory, CompilerTrait(CompilerFeature.RequiredMembers)] + [MemberData(nameof(Regular10AndScriptAndRequiredMembersMinimum))] + public void RequiredModifierMethod_01(CSharpParseOptions parseOptions) + { + // Note this is a semantic error, not a syntactic one + UsingDeclaration("required string M() {}", options: parseOptions); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.RequiredKeyword); + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.StringKeyword); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } + + [Theory, CompilerTrait(CompilerFeature.RequiredMembers)] + [MemberData(nameof(Regular10AndScript))] + public void RequiredModifierMethod_02(CSharpParseOptions parseOptions) + { + UsingDeclaration("required M() {}", options: parseOptions); + N(SyntaxKind.MethodDeclaration); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "required"); + } + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } + + [Fact, CompilerTrait(CompilerFeature.RequiredMembers)] + public void RequiredModifierMethod_03() + { + UsingDeclaration("required M() {}", options: RequiredMembersOptions); + N(SyntaxKind.ConstructorDeclaration); + { + N(SyntaxKind.RequiredKeyword); + N(SyntaxKind.IdentifierToken, "M"); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } + + [Theory, CompilerTrait(CompilerFeature.RequiredMembers)] + [MemberData(nameof(Regular10AndScriptAndRequiredMembersMinimum))] + public void RequiredModifierOperator(CSharpParseOptions parseOptions) + { + // Note this is a semantic error, not a syntactic one + UsingDeclaration("static required C operator+(C c1, C c2) {}", options: parseOptions); + N(SyntaxKind.OperatorDeclaration); + { + N(SyntaxKind.StaticKeyword); + N(SyntaxKind.RequiredKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "C"); + } + N(SyntaxKind.OperatorKeyword); + N(SyntaxKind.PlusToken); + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "C"); + } + N(SyntaxKind.IdentifierToken, "c1"); + } + N(SyntaxKind.CommaToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "C"); + } + N(SyntaxKind.IdentifierToken, "c2"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } + + [Theory, CompilerTrait(CompilerFeature.RequiredMembers)] + [MemberData(nameof(Regular10AndScriptAndRequiredMembersMinimum))] + public void RequiredModifierConversion_01(CSharpParseOptions parseOptions) + { + // Note this is a semantic error, not a syntactic one + UsingDeclaration("static required implicit operator C(S s) {}", options: parseOptions); + N(SyntaxKind.ConversionOperatorDeclaration); + { + N(SyntaxKind.StaticKeyword); + N(SyntaxKind.RequiredKeyword); + N(SyntaxKind.ImplicitKeyword); + N(SyntaxKind.OperatorKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "C"); + } + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "S"); + } + N(SyntaxKind.IdentifierToken, "s"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } + + [Theory, CompilerTrait(CompilerFeature.RequiredMembers)] + [MemberData(nameof(Regular10AndScript))] + public void RequiredModifierConversion_02(CSharpParseOptions parseOptions) + { + UsingDeclaration("static implicit required operator C(S s) {}", options: parseOptions, + // (1,17): error CS8652: The feature 'static abstract members in interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // static implicit required operator C(S s) {} + Diagnostic(ErrorCode.ERR_FeatureInPreview, "required ").WithArguments("static abstract members in interfaces").WithLocation(1, 17), + // (1,26): error CS1003: Syntax error, '.' expected + // static implicit required operator C(S s) {} + Diagnostic(ErrorCode.ERR_SyntaxError, "operator").WithArguments(".").WithLocation(1, 26) + ); + N(SyntaxKind.ConversionOperatorDeclaration); + { + N(SyntaxKind.StaticKeyword); + N(SyntaxKind.ImplicitKeyword); + N(SyntaxKind.ExplicitInterfaceSpecifier); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "required"); + } + M(SyntaxKind.DotToken); + } + N(SyntaxKind.OperatorKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "C"); + } + N(SyntaxKind.ParameterList); + { + N(SyntaxKind.OpenParenToken); + N(SyntaxKind.Parameter); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "S"); + } + N(SyntaxKind.IdentifierToken, "s"); + } + N(SyntaxKind.CloseParenToken); + } + N(SyntaxKind.Block); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } + + [Theory, CompilerTrait(CompilerFeature.RequiredMembers)] + [MemberData(nameof(Regular10AndScriptAndRequiredMembersMinimum))] + public void RequiredModifierIncompleteProperty_01(CSharpParseOptions parseOptions) + { + UsingDeclaration("required string Prop { get;", options: parseOptions, + // (1,28): error CS1513: } expected + // required string Prop { get; + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(1, 28) + ); + N(SyntaxKind.PropertyDeclaration); + { + N(SyntaxKind.RequiredKeyword); + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.StringKeyword); + } + N(SyntaxKind.IdentifierToken, "Prop"); + N(SyntaxKind.AccessorList); + { + N(SyntaxKind.OpenBraceToken); + N(SyntaxKind.GetAccessorDeclaration); + { + N(SyntaxKind.GetKeyword); + N(SyntaxKind.SemicolonToken); + } + M(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } + + [Theory, CompilerTrait(CompilerFeature.RequiredMembers)] + [MemberData(nameof(Regular10AndScriptAndRequiredMembersMinimum))] + public void RequiredModifierIncompleteProperty_02(CSharpParseOptions parseOptions) + { + UsingDeclaration("required string Prop {", options: parseOptions, + // (1,23): error CS1513: } expected + // required string Prop { + Diagnostic(ErrorCode.ERR_RbraceExpected, "").WithLocation(1, 23) + ); + N(SyntaxKind.PropertyDeclaration); + { + N(SyntaxKind.RequiredKeyword); + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.StringKeyword); + } + N(SyntaxKind.IdentifierToken, "Prop"); + N(SyntaxKind.AccessorList); + { + N(SyntaxKind.OpenBraceToken); + M(SyntaxKind.CloseBraceToken); + } + } + EOF(); + } + + [Theory, CompilerTrait(CompilerFeature.RequiredMembers)] + [MemberData(nameof(Regular10AndScriptAndRequiredMembersMinimum))] + public void RequiredModifierIncompleteMember_01(CSharpParseOptions parseOptions) + { + UsingDeclaration("required string Prop", options: parseOptions, + // (1,21): error CS1002: ; expected + // required string Prop + Diagnostic(ErrorCode.ERR_SemicolonExpected, "").WithLocation(1, 21) + ); + N(SyntaxKind.FieldDeclaration); + { + N(SyntaxKind.RequiredKeyword); + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.StringKeyword); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "Prop"); + } + } + M(SyntaxKind.SemicolonToken); + } + EOF(); + } + + [Theory, CompilerTrait(CompilerFeature.RequiredMembers)] + [MemberData(nameof(Regular10AndScriptAndRequiredMembersMinimum))] + public void RequiredModifierIncompleteMember_02(CSharpParseOptions parseOptions) + { + UsingDeclaration("required string", options: parseOptions, + // (1,16): error CS1519: Invalid token '' in class, record, struct, or interface member declaration + // required string + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "").WithArguments("").WithLocation(1, 16) + ); + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.RequiredKeyword); + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.StringKeyword); + } + } + EOF(); + } + + [Theory, CompilerTrait(CompilerFeature.RequiredMembers)] + [MemberData(nameof(Regular10AndScriptAndRequiredMembersMinimum))] + public void RequiredModifierIncompleteMember_03(CSharpParseOptions parseOptions) + { + UsingDeclaration("required C", options: parseOptions, + // (1,11): error CS1519: Invalid token '' in class, record, struct, or interface member declaration + // required C + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "").WithArguments("").WithLocation(1, 11) + ); + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.RequiredKeyword); + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "C"); + } + } + EOF(); + } + + [Theory, CompilerTrait(CompilerFeature.RequiredMembers)] + [MemberData(nameof(Regular10AndScript))] + public void RequiredModifierIncompleteMember_04(CSharpParseOptions parseOptions) + { + UsingDeclaration("required", options: parseOptions, + // (1,9): error CS1519: Invalid token '' in class, record, struct, or interface member declaration + // required + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "").WithArguments("").WithLocation(1, 9) + ); + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "required"); + } + } + EOF(); + } + + [Fact, CompilerTrait(CompilerFeature.RequiredMembers)] + public void RequiredModifierIncompleteMember_05() + { + UsingDeclaration("required", options: RequiredMembersOptions, + // (1,9): error CS1519: Invalid token '' in class, record, struct, or interface member declaration + // required + Diagnostic(ErrorCode.ERR_InvalidMemberDecl, "").WithArguments("").WithLocation(1, 9) + ); + N(SyntaxKind.IncompleteMember); + { + N(SyntaxKind.RequiredKeyword); + } + EOF(); + } + + [Theory, CompilerTrait(CompilerFeature.RequiredMembers), WorkItem(61510, "https://github.com/dotnet/roslyn/issues/61510")] + [MemberData(nameof(Regular10AndScriptAndRequiredMembersMinimum))] + public void RequiredModifier_LocalNamedRequired_TopLevelStatements(CSharpParseOptions parseOptions) + { + bool isScript = parseOptions.Kind == SourceCodeKind.Script; + + UsingTree(""" + bool required; + required = true; + """, options: parseOptions); + N(SyntaxKind.CompilationUnit); + { + if (isScript) + { + N(SyntaxKind.FieldDeclaration); + } + else + { + N(SyntaxKind.GlobalStatement); + N(SyntaxKind.LocalDeclarationStatement); + } + + { + N(SyntaxKind.VariableDeclaration); + { + N(SyntaxKind.PredefinedType); + { + N(SyntaxKind.BoolKeyword); + } + N(SyntaxKind.VariableDeclarator); + { + N(SyntaxKind.IdentifierToken, "required"); + } + } + N(SyntaxKind.SemicolonToken); + } + N(SyntaxKind.GlobalStatement); + { + N(SyntaxKind.ExpressionStatement); + { + N(SyntaxKind.SimpleAssignmentExpression); + { + N(SyntaxKind.IdentifierName); + { + N(SyntaxKind.IdentifierToken, "required"); + } + N(SyntaxKind.EqualsToken); + N(SyntaxKind.TrueLiteralExpression); + { + N(SyntaxKind.TrueKeyword); + } + } + N(SyntaxKind.SemicolonToken); + } + } + N(SyntaxKind.EndOfFileToken); + } + EOF(); + } + [Fact] public void OperatorDeclaration_ExplicitImplementation_01() { diff --git a/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxNormalizerTests.cs b/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxNormalizerTests.cs index f399aa02adfc1..7b5b77c70a41f 100644 --- a/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxNormalizerTests.cs +++ b/src/Compilers/CSharp/Test/Syntax/Syntax/SyntaxNormalizerTests.cs @@ -1307,6 +1307,14 @@ public void TestNormalizeXmlArgumentsInDocComment7() TestNormalizeDeclaration(Text, Expected); } + [Fact] + public void TestRequiredKeywordNormalization() + { + const string Expected = @"public required partial int Field;"; + const string Text = @"public required partial int Field;"; + TestNormalizeDeclaration(Text, Expected); + } + [Fact] [WorkItem(61518, "https://github.com/dotnet/roslyn/issues/61518")] public void TestNormalizeNestedUsingStatements1() diff --git a/src/Compilers/Core/Portable/Binding/BindingDiagnosticBag.cs b/src/Compilers/Core/Portable/Binding/BindingDiagnosticBag.cs index 7fc154a1614f0..dd6f574547594 100644 --- a/src/Compilers/Core/Portable/Binding/BindingDiagnosticBag.cs +++ b/src/Compilers/Core/Portable/Binding/BindingDiagnosticBag.cs @@ -8,6 +8,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Symbols; @@ -26,6 +27,7 @@ protected BindingDiagnosticBag(DiagnosticBag? diagnosticBag) DiagnosticBag = diagnosticBag; } + [MemberNotNullWhen(true, nameof(DiagnosticBag))] internal bool AccumulatesDiagnostics => DiagnosticBag is object; internal void AddRange(ImmutableArray diagnostics) where T : Diagnostic diff --git a/src/Compilers/Core/Portable/MetadataReader/PEModule.cs b/src/Compilers/Core/Portable/MetadataReader/PEModule.cs index a4704092eb521..16c3a5db53233 100644 --- a/src/Compilers/Core/Portable/MetadataReader/PEModule.cs +++ b/src/Compilers/Core/Portable/MetadataReader/PEModule.cs @@ -1107,11 +1107,13 @@ internal bool HasIsByRefLikeAttribute(EntityHandle token) } internal const string ByRefLikeMarker = "Types with embedded references are not supported in this version of your compiler."; + internal const string RequiredMembersMarker = "Constructors of types with required members are not supported in this version of your compiler."; internal ObsoleteAttributeData TryGetDeprecatedOrExperimentalOrObsoleteAttribute( EntityHandle token, IAttributeNamedArgumentDecoder decoder, - bool ignoreByRefLikeMarker) + bool ignoreByRefLikeMarker, + bool ignoreRequiredMemberMarker) { AttributeInfo info; @@ -1129,6 +1131,8 @@ internal ObsoleteAttributeData TryGetDeprecatedOrExperimentalOrObsoleteAttribute { case ByRefLikeMarker when ignoreByRefLikeMarker: return null; + case RequiredMembersMarker when ignoreRequiredMemberMarker: + return null; } return obsoleteData; } @@ -1145,6 +1149,60 @@ internal ObsoleteAttributeData TryGetDeprecatedOrExperimentalOrObsoleteAttribute } #nullable enable + internal string? GetFirstUnsupportedCompilerFeatureFromToken(EntityHandle token, IAttributeNamedArgumentDecoder attributeNamedArgumentDecoder, CompilerFeatureRequiredFeatures allowedFeatures) + { + List? infos = FindTargetAttributes(token, AttributeDescription.CompilerFeatureRequiredAttribute); + + if (infos == null) + { + return null; + } + + foreach (var info in infos) + { + if (!info.HasValue || !TryGetAttributeReader(info.Handle, out BlobReader sigReader) || !CrackStringInAttributeValue(out string? featureName, ref sigReader)) + { + continue; + } + + bool isOptional = false; + if (sigReader.RemainingBytes >= 2) + { + try + { + var numNamedArgs = sigReader.ReadUInt16(); + for (uint i = 0; i < numNamedArgs; i++) + { + (KeyValuePair nameValuePair, bool isProperty, SerializationTypeCode typeCode, SerializationTypeCode elementTypeCode) namedArgValues = + attributeNamedArgumentDecoder.DecodeCustomAttributeNamedArgumentOrThrow(ref sigReader); + + if (namedArgValues is ({ Key: "IsOptional" }, isProperty: true, typeCode: SerializationTypeCode.Boolean, _)) + { + isOptional = (bool)namedArgValues.nameValuePair.Value.ValueInternal!; + break; + } + } + } + catch (Exception e) when (e is UnsupportedSignatureContent or BadImageFormatException) { } + } + + if (!isOptional && (allowedFeatures & getFeatureKind(featureName)) == 0) + { + return featureName; + } + } + + return null; + + static CompilerFeatureRequiredFeatures getFeatureKind(string? feature) + => feature switch + { + nameof(CompilerFeatureRequiredFeatures.RefStructs) => CompilerFeatureRequiredFeatures.RefStructs, + nameof(CompilerFeatureRequiredFeatures.RequiredMembers) => CompilerFeatureRequiredFeatures.RequiredMembers, + _ => CompilerFeatureRequiredFeatures.None, + }; + } + internal UnmanagedCallersOnlyAttributeData? TryGetUnmanagedCallersOnlyAttribute( EntityHandle token, IAttributeNamedArgumentDecoder attributeArgumentDecoder, @@ -2129,9 +2187,10 @@ public bool HasValue } } - internal List FindTargetAttributes(EntityHandle hasAttribute, AttributeDescription description) +#nullable enable + internal List? FindTargetAttributes(EntityHandle hasAttribute, AttributeDescription description) { - List result = null; + List? result = null; try { @@ -2155,6 +2214,7 @@ internal List FindTargetAttributes(EntityHandle hasAttribute, Att return result; } +#nullable disable internal AttributeInfo FindTargetAttribute(EntityHandle hasAttribute, AttributeDescription description) { diff --git a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt index c2331cd21ec09..1d622432a2be9 100644 --- a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt @@ -1,6 +1,7 @@ *REMOVED*override abstract Microsoft.CodeAnalysis.Diagnostic.Equals(object? obj) -> bool abstract Microsoft.CodeAnalysis.SymbolVisitor.DefaultResult.get -> TResult Microsoft.CodeAnalysis.Compilation.GetTypesByMetadataName(string! fullyQualifiedMetadataName) -> System.Collections.Immutable.ImmutableArray +Microsoft.CodeAnalysis.IFieldSymbol.IsRequired.get -> bool Microsoft.CodeAnalysis.IImportScope Microsoft.CodeAnalysis.IImportScope.Aliases.get -> System.Collections.Immutable.ImmutableArray Microsoft.CodeAnalysis.IImportScope.ExternAliases.get -> System.Collections.Immutable.ImmutableArray @@ -48,6 +49,7 @@ Microsoft.CodeAnalysis.IOperation.OperationList.Reversed.Reversed() -> void Microsoft.CodeAnalysis.IOperation.OperationList.Reversed.Count.get -> int Microsoft.CodeAnalysis.IOperation.OperationList.Reversed.GetEnumerator() -> Microsoft.CodeAnalysis.IOperation.OperationList.Reversed.Enumerator Microsoft.CodeAnalysis.IOperation.OperationList.Reversed.ToImmutableArray() -> System.Collections.Immutable.ImmutableArray +Microsoft.CodeAnalysis.IPropertySymbol.IsRequired.get -> bool Microsoft.CodeAnalysis.SemanticModel.GetImportScopes(int position, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Collections.Immutable.ImmutableArray Microsoft.CodeAnalysis.ISymbol.Accept(Microsoft.CodeAnalysis.SymbolVisitor! visitor, TArgument argument) -> TResult Microsoft.CodeAnalysis.SymbolVisitor @@ -90,5 +92,4 @@ virtual Microsoft.CodeAnalysis.SymbolVisitor.VisitPointerTyp virtual Microsoft.CodeAnalysis.SymbolVisitor.VisitProperty(Microsoft.CodeAnalysis.IPropertySymbol! symbol, TArgument argument) -> TResult virtual Microsoft.CodeAnalysis.SymbolVisitor.VisitRangeVariable(Microsoft.CodeAnalysis.IRangeVariableSymbol! symbol, TArgument argument) -> TResult virtual Microsoft.CodeAnalysis.SymbolVisitor.VisitTypeParameter(Microsoft.CodeAnalysis.ITypeParameterSymbol! symbol, TArgument argument) -> TResult - Microsoft.CodeAnalysis.Operations.BinaryOperatorKind.UnsignedRightShift = 25 -> Microsoft.CodeAnalysis.Operations.BinaryOperatorKind \ No newline at end of file diff --git a/src/Compilers/Core/Portable/Symbols/Attributes/AttributeDescription.cs b/src/Compilers/Core/Portable/Symbols/Attributes/AttributeDescription.cs index 83af6b8d78120..75575454f1da8 100644 --- a/src/Compilers/Core/Portable/Symbols/Attributes/AttributeDescription.cs +++ b/src/Compilers/Core/Portable/Symbols/Attributes/AttributeDescription.cs @@ -479,5 +479,8 @@ static AttributeDescription() internal static readonly AttributeDescription UnmanagedCallersOnlyAttribute = new AttributeDescription("System.Runtime.InteropServices", "UnmanagedCallersOnlyAttribute", s_signatures_HasThis_Void_Only); internal static readonly AttributeDescription InterpolatedStringHandlerAttribute = new AttributeDescription("System.Runtime.CompilerServices", "InterpolatedStringHandlerAttribute", s_signatures_HasThis_Void_Only); internal static readonly AttributeDescription InterpolatedStringHandlerArgumentAttribute = new AttributeDescription("System.Runtime.CompilerServices", "InterpolatedStringHandlerArgumentAttribute", s_signaturesOfInterpolatedStringArgumentAttribute); + internal static readonly AttributeDescription RequiredMemberAttribute = new AttributeDescription("System.Runtime.CompilerServices", "RequiredMemberAttribute", s_signatures_HasThis_Void_Only); + internal static readonly AttributeDescription SetsRequiredMembersAttribute = new AttributeDescription("System.Diagnostics.CodeAnalysis", "SetsRequiredMembersAttribute", s_signatures_HasThis_Void_Only); + internal static readonly AttributeDescription CompilerFeatureRequiredAttribute = new AttributeDescription("System.Runtime.CompilerServices", "CompilerFeatureRequiredAttribute", s_signatures_HasThis_Void_String_Only); } } diff --git a/src/Compilers/Core/Portable/Symbols/Attributes/CommonMethodEarlyWellKnownAttributeData.cs b/src/Compilers/Core/Portable/Symbols/Attributes/CommonMethodEarlyWellKnownAttributeData.cs index 94ee22f574fa9..d41640ca4e082 100644 --- a/src/Compilers/Core/Portable/Symbols/Attributes/CommonMethodEarlyWellKnownAttributeData.cs +++ b/src/Compilers/Core/Portable/Symbols/Attributes/CommonMethodEarlyWellKnownAttributeData.cs @@ -52,5 +52,23 @@ public ObsoleteAttributeData? ObsoleteAttributeData } } #endregion + + #region SetsRequiredMembers + private bool _hasSetsRequiredMembers = false; + public bool HasSetsRequiredMembersAttribute + { + get + { + VerifySealed(expected: true); + return _hasSetsRequiredMembers; + } + set + { + VerifySealed(false); + _hasSetsRequiredMembers = value; + SetDataStored(); + } + } + #endregion } } diff --git a/src/Compilers/Core/Portable/Symbols/CompilerFeatureRequiredFeatures.cs b/src/Compilers/Core/Portable/Symbols/CompilerFeatureRequiredFeatures.cs new file mode 100644 index 0000000000000..e4dc65b31dbf4 --- /dev/null +++ b/src/Compilers/Core/Portable/Symbols/CompilerFeatureRequiredFeatures.cs @@ -0,0 +1,15 @@ +// 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; + +namespace Microsoft.CodeAnalysis; + +[Flags] +internal enum CompilerFeatureRequiredFeatures +{ + None = 0, + RefStructs = 1 << 0, + RequiredMembers = 1 << 1, +} diff --git a/src/Compilers/Core/Portable/Symbols/IFieldSymbol.cs b/src/Compilers/Core/Portable/Symbols/IFieldSymbol.cs index 31875be2575b9..476f34cf1fdf4 100644 --- a/src/Compilers/Core/Portable/Symbols/IFieldSymbol.cs +++ b/src/Compilers/Core/Portable/Symbols/IFieldSymbol.cs @@ -41,6 +41,11 @@ public interface IFieldSymbol : ISymbol ///

bool IsVolatile { get; } + /// + /// True if this field is required to be set in an object initializer during construction. + /// + bool IsRequired { get; } + /// /// Returns true if this field was declared as "fixed". /// Note that for a fixed-size buffer declaration, this.Type will be a pointer type, of which diff --git a/src/Compilers/Core/Portable/Symbols/IPropertySymbol.cs b/src/Compilers/Core/Portable/Symbols/IPropertySymbol.cs index bd40a5adcbc5f..177e264f5aaa6 100644 --- a/src/Compilers/Core/Portable/Symbols/IPropertySymbol.cs +++ b/src/Compilers/Core/Portable/Symbols/IPropertySymbol.cs @@ -31,6 +31,11 @@ public interface IPropertySymbol : ISymbol /// bool IsWriteOnly { get; } + /// + /// True if this property is required to be set in an object initializer during construction. + /// + bool IsRequired { get; } + /// /// Returns true if this property is an auto-created WithEvents property that takes place of /// a field member when the field is marked as WithEvents. diff --git a/src/Compilers/Core/Portable/WellKnownMember.cs b/src/Compilers/Core/Portable/WellKnownMember.cs index 03ac1ab640f21..8eef3970f4ebb 100644 --- a/src/Compilers/Core/Portable/WellKnownMember.cs +++ b/src/Compilers/Core/Portable/WellKnownMember.cs @@ -520,10 +520,14 @@ internal enum WellKnownMember System_Runtime_CompilerServices_DefaultInterpolatedStringHandler__ToStringAndClear, + System_Runtime_CompilerServices_RequiredMemberAttribute__ctor, + System_Diagnostics_CodeAnalysis_SetsRequiredMembersAttribute__ctor, System_MemoryExtensions__SequenceEqual_Span_T, System_MemoryExtensions__SequenceEqual_ReadOnlySpan_T, System_MemoryExtensions__AsSpan_String, + System_Runtime_CompilerServices_CompilerFeatureRequiredAttribute__ctor, + Count // Remember to update the AllWellKnownTypeMembers tests when making changes here diff --git a/src/Compilers/Core/Portable/WellKnownMembers.cs b/src/Compilers/Core/Portable/WellKnownMembers.cs index b912ab6405bae..d43618ec1631b 100644 --- a/src/Compilers/Core/Portable/WellKnownMembers.cs +++ b/src/Compilers/Core/Portable/WellKnownMembers.cs @@ -3561,6 +3561,20 @@ static WellKnownMembers() 0, // Method Signature (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_String, // Return Type + // System_Runtime_CompilerServices_RequiredMemberAttribute__ctor + (byte)MemberFlags.Constructor, // Flags + (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_Runtime_CompilerServices_RequiredMemberAttribute - WellKnownType.ExtSentinel), // DeclaringTypeId + 0, // Arity + 0, // Method Signature + (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Void, // Return Type + + // System_Diagnostics_CodeAnalysis_SetsRequiredMembersAttribute__ctor + (byte)MemberFlags.Constructor, // Flags + (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_Diagnostics_CodeAnalysis_SetsRequiredMembersAttribute - WellKnownType.ExtSentinel), // DeclaringTypeId + 0, // Arity + 0, // Method Signature + (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Void, // Return Type + // System_MemoryExtensions__SequenceEqual_Span_T (byte)(MemberFlags.Method | MemberFlags.Static), // Flags @@ -3602,6 +3616,14 @@ static WellKnownMembers() 1, (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Char, (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_String, + + // System_Runtime_CompilerServices_CompilerFeatureRequiredAttribute__ctor + (byte)MemberFlags.Constructor, // Flags + (byte)WellKnownType.ExtSentinel, (byte)(WellKnownType.System_Runtime_CompilerServices_CompilerFeatureRequiredAttribute - WellKnownType.ExtSentinel), // DeclaringTypeId + 0, // Arity + 1, // Method Signature + (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_Void, // Return Type + (byte)SignatureTypeCode.TypeHandle, (byte)SpecialType.System_String, }; string[] allNames = new string[(int)WellKnownMember.Count] @@ -4049,9 +4071,12 @@ static WellKnownMembers() "Append", // System_Text_StringBuilder__AppendObject ".ctor", // System_Text_StringBuilder__ctor "ToStringAndClear", // System_Runtime_CompilerServices_DefaultInterpolatedStringHandler__ToStringAndClear + ".ctor", // System_Runtime_CompilerServices_RequiredMemberAttribute__ctor + ".ctor", // System_Diagnostics_CodeAnalysis_SetsRequiredMembersAttribute__ctor "SequenceEqual", // System_MemoryExtensions__SequenceEqual_Span_T "SequenceEqual", // System_MemoryExtensions__SequenceEqual_ReadOnlySpan_T "AsSpan", // System_MemoryExtensions__AsSpan_String + ".ctor", // System_Runtime_CompilerServices_CompilerFeatureRequiredAttribute_ctor }; s_descriptors = MemberDescriptor.InitializeFromStream(new System.IO.MemoryStream(initializationBytes, writable: false), allNames); diff --git a/src/Compilers/Core/Portable/WellKnownTypes.cs b/src/Compilers/Core/Portable/WellKnownTypes.cs index d3889371c3841..292597a71b9e0 100644 --- a/src/Compilers/Core/Portable/WellKnownTypes.cs +++ b/src/Compilers/Core/Portable/WellKnownTypes.cs @@ -317,8 +317,12 @@ internal enum WellKnownType System_ArgumentNullException, + System_Runtime_CompilerServices_RequiredMemberAttribute, + System_Diagnostics_CodeAnalysis_SetsRequiredMembersAttribute, System_MemoryExtensions, + System_Runtime_CompilerServices_CompilerFeatureRequiredAttribute, + NextAvailable, // Remember to update the AllWellKnownTypes tests when making changes here } @@ -628,7 +632,10 @@ internal static class WellKnownTypes "System.Runtime.CompilerServices.DefaultInterpolatedStringHandler", "System.ArgumentNullException", + "System.Runtime.CompilerServices.RequiredMemberAttribute", + "System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute", "System.MemoryExtensions", + "System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute", }; private static readonly Dictionary s_nameToTypeIdMap = new Dictionary((int)Count); diff --git a/src/Compilers/Test/Core/BaseCompilerFeatureRequiredTests.cs b/src/Compilers/Test/Core/BaseCompilerFeatureRequiredTests.cs new file mode 100644 index 0000000000000..4f12333daa6d0 --- /dev/null +++ b/src/Compilers/Test/Core/BaseCompilerFeatureRequiredTests.cs @@ -0,0 +1,710 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Linq; +using System.Reflection.Metadata; +using Microsoft.CodeAnalysis.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.UnitTests; + +public abstract class BaseCompilerFeatureRequiredTests : CommonTestBase where TCompilation : Compilation +{ + private static string CompilerFeatureRequiredApplication( + bool? isOptional) + { + var builder = new BlobBuilder(); + builder.WriteSerializedString("test"); + var featureLengthAndName = string.Join(" ", builder.ToImmutableArray().Select(b => $"{b:x2}")); + + var isOptionalText = isOptional switch + { + true => "01 00 54 02 0a 49 73 4f 70 74 69 6f 6e 61 6c 01", // One optional parameter, "IsOptional", true + false => "01 00 54 02 0a 49 73 4f 70 74 69 6f 6e 61 6c 00", // One optional parameter, "IsOptional", false + null => "00 00" // No optional parameters + }; + + return $""" + .custom instance void System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute::.ctor(string) = ( + 01 00 {featureLengthAndName} {isOptionalText} + ) + """; + } + + private const string CompilerFeatureRequiredIl = + """ + .class public auto ansi sealed beforefieldinit System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute + extends [mscorlib]System.Attribute + { + .custom instance void [mscorlib]System.AttributeUsageAttribute::.ctor(valuetype [mscorlib]System.AttributeTargets) = ( + 01 00 ff 7f 00 00 02 00 54 02 0d 41 6c 6c 6f 77 + 4d 75 6c 74 69 70 6c 65 01 54 02 09 49 6e 68 65 + 72 69 74 65 64 00 + ) + // Fields + .field private initonly string 'k__BackingField' + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + .field private initonly bool 'k__BackingField' + .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = ( + 01 00 00 00 + ) + + .field public static literal string RefStructs = "RefStructs" + .field public static literal string RequiredMembers = "RequiredMembers" + + // Methods + .method public hidebysig specialname rtspecialname + instance void .ctor ( + string featureName + ) cil managed + { + ldarg.0 + call instance void [mscorlib]System.Attribute::.ctor() + ldarg.0 + ldarg.1 + stfld string System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute::'k__BackingField' + ret + } // end of method CompilerFeatureRequiredAttribute::.ctor + + .method public hidebysig specialname + instance string get_FeatureName () cil managed + { + ldarg.0 + ldfld string System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute::'k__BackingField' + ret + } // end of method CompilerFeatureRequiredAttribute::get_FeatureName + + .method public hidebysig specialname + instance bool get_IsOptional () cil managed + { + ldarg.0 + ldfld bool System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute::'k__BackingField' + ret + } // end of method CompilerFeatureRequiredAttribute::get_IsOptional + + .method public hidebysig specialname + instance void modreq([mscorlib]System.Runtime.CompilerServices.IsExternalInit) set_IsOptional ( + bool 'value' + ) cil managed + { + ldarg.0 + ldarg.1 + stfld bool System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute::'k__BackingField' + ret + } // end of method CompilerFeatureRequiredAttribute::set_IsOptional + + // Properties + .property instance string FeatureName() + { + .get instance string System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute::get_FeatureName() + } + .property instance bool IsOptional() + { + .get instance bool System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute::get_IsOptional() + .set instance void modreq([mscorlib]System.Runtime.CompilerServices.IsExternalInit) System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute::set_IsOptional(bool) + } + + } // end of class System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute + """; + + // This IL is equivalent to the following definition, which format holes for the required attribute under test: + // [CompilerFeatureRequired("test")] + // public class OnType + // { + // } + // + // public class OnMethod + // { + // [CompilerFeatureRequired("test")] + // public static void M() {} + // } + // + // public class OnMethodReturn + // { + // [return: CompilerFeatureRequired("test")] + // public static void M() {} + // } + // + // public class OnParameter + // { + // public static void M([CompilerFeatureRequired("test")] int param) {} + // } + // + // public class OnField + // { + // [CompilerFeatureRequired("test")] + // public static int Field; + // } + // + // public class OnProperty + // { + // [CompilerFeatureRequired("test")] + // public static int Property { get => 0; set {} } + // } + // + // public class OnPropertySetter + // { + // public static int Property { get => 0; [CompilerFeatureRequired("test")] set {} } + // } + // + // public class OnPropertyGetter + // { + // public static int Property { [CompilerFeatureRequired("test")] get => 0; set {} } + // } + // + // public class OnEvent + // { + // [CompilerFeatureRequired("test")] + // public static event Action Event { add {} remove {} } + // } + // + // public class OnEventAdder + // { + // public static event Action Event { [CompilerFeatureRequired("test")] add {} remove {} } + // } + // + // public class OnEventRemover + // { + // public static event Action Event { [CompilerFeatureRequired("test")] add {} remove {} } + // } + // + // [CompilerFeatureRequired("test")] + // public enum OnEnum + // { + // A + // } + // + // public enum OnEnumMember + // { + // [CompilerFeatureRequired("test")] A + // } + // + // public class OnClassTypeParameter<[CompilerFeatureRequired("test")] T> + // { + // } + // + // public class OnMethodTypeParameter + // { + // public static void M<[CompilerFeatureRequired("test")] T>() {} + // } + // + // [CompilerFeatureRequired("test")] + // public delegate void OnDelegateType(); + // + // VB: + // Public Class OnIndexedPropertyParameter + // Public Property [Property]( param As Integer) As Integer + // Get + // Return 1 + // End Get + // Set + // End Set + // End Property + // End Class + private string GetTestIl(string attributeApplication) + { + return $$""" + .class public auto ansi beforefieldinit OnType + extends [mscorlib]System.Object + { + {{attributeApplication}} + // Methods + .method public hidebysig static + void M () cil managed + { + ret + } // end of method OnMethod::M + } // end of class OnType + + .class public auto ansi beforefieldinit OnMethod + extends [mscorlib]System.Object + { + // Methods + .method public hidebysig static + void M () cil managed + { + {{attributeApplication}} + ret + } // end of method OnMethod::M + } // end of class OnMethod + + .class public auto ansi beforefieldinit OnMethodReturn + extends [mscorlib]System.Object + { + // Methods + .method public hidebysig static + void M () cil managed + { + .param [0] + {{attributeApplication}} + ret + } // end of method OnMethodReturn::M + } // end of class OnMethodReturn + + .class public auto ansi beforefieldinit OnParameter + extends [mscorlib]System.Object + { + // Methods + .method public hidebysig static + void M ( + int32 param + ) cil managed + { + .param [1] + {{attributeApplication}} + ret + } // end of method OnParameter::M + } // end of class OnParameter + + .class public auto ansi beforefieldinit OnField + extends [mscorlib]System.Object + { + // Fields + .field public static int32 Field + {{attributeApplication}} + } // end of class OnField + + .class public auto ansi beforefieldinit OnProperty + extends [mscorlib]System.Object + { + // Methods + .method public hidebysig specialname static + int32 get_Property () cil managed + { + ldc.i4.0 + ret + } // end of method OnProperty::get_Property + + .method public hidebysig specialname static + void set_Property ( + int32 'value' + ) cil managed + { + ret + } // end of method OnProperty::set_Property + + // Properties + .property int32 Property() + { + {{attributeApplication}} + .get int32 OnProperty::get_Property() + .set void OnProperty::set_Property(int32) + } + + } // end of class OnProperty + + .class public auto ansi beforefieldinit OnPropertySetter + extends [mscorlib]System.Object + { + // Methods + .method public hidebysig specialname static + int32 get_Property () cil managed + { + ldc.i4.0 + ret + } // end of method OnPropertySetter::get_Property + + .method public hidebysig specialname static + void set_Property ( + int32 'value' + ) cil managed + { + {{attributeApplication}} + ret + } // end of method OnPropertySetter::set_Property + + // Properties + .property int32 Property() + { + .get int32 OnPropertySetter::get_Property() + .set void OnPropertySetter::set_Property(int32) + } + } // end of class OnPropertySetter + + .class public auto ansi beforefieldinit OnPropertyGetter + extends [mscorlib]System.Object + { + // Methods + .method public hidebysig specialname static + int32 get_Property () cil managed + { + {{attributeApplication}} + ldc.i4.0 + ret + } // end of method OnPropertyGetter::get_Property + + .method public hidebysig specialname static + void set_Property ( + int32 'value' + ) cil managed + { + ret + } // end of method OnPropertyGetter::set_Property + + // Properties + .property int32 Property() + { + .get int32 OnPropertyGetter::get_Property() + .set void OnPropertyGetter::set_Property(int32) + } + + } // end of class OnPropertyGetter + + .class public auto ansi beforefieldinit OnEvent + extends [mscorlib]System.Object + { + // Methods + .method public hidebysig specialname static + void add_Event ( + class [mscorlib]System.Action 'value' + ) cil managed + { + ret + } // end of method OnEvent::add_Event + + .method public hidebysig specialname static + void remove_Event ( + class [mscorlib]System.Action 'value' + ) cil managed + { + ret + } // end of method OnEvent::remove_Event + + // Events + .event [mscorlib]System.Action Event + { + {{attributeApplication}} + .addon void OnEvent::add_Event(class [mscorlib]System.Action) + .removeon void OnEvent::remove_Event(class [mscorlib]System.Action) + } + + + } // end of class OnEvent + + .class public auto ansi beforefieldinit OnEventAdder + extends [mscorlib]System.Object + { + // Methods + .method public hidebysig specialname static + void add_Event ( + class [mscorlib]System.Action 'value' + ) cil managed + { + {{attributeApplication}} + ret + } // end of method OnEventAdder::add_Event + + .method public hidebysig specialname static + void remove_Event ( + class [mscorlib]System.Action 'value' + ) cil managed + { + ret + } // end of method OnEventAdder::remove_Event + + // Events + .event [mscorlib]System.Action Event + { + .addon void OnEventAdder::add_Event(class [mscorlib]System.Action) + .removeon void OnEventAdder::remove_Event(class [mscorlib]System.Action) + } + + + } // end of class OnEventAdder + + .class public auto ansi beforefieldinit OnEventRemover + extends [mscorlib]System.Object + { + // Methods + .method public hidebysig specialname static + void add_Event ( + class [mscorlib]System.Action 'value' + ) cil managed + { + ret + } // end of method OnEventRemover::add_Event + + .method public hidebysig specialname static + void remove_Event ( + class [mscorlib]System.Action 'value' + ) cil managed + { + {{attributeApplication}} + ret + } // end of method OnEventRemover::remove_Event + + // Events + .event [mscorlib]System.Action Event + { + .addon void OnEventRemover::add_Event(class [mscorlib]System.Action) + .removeon void OnEventRemover::remove_Event(class [mscorlib]System.Action) + } + + + } // end of class OnEventRemover + + .class public auto ansi sealed OnEnum + extends [mscorlib]System.Enum + { + {{attributeApplication}} + // Fields + .field public specialname rtspecialname int32 value__ + .field public static literal valuetype OnEnum A = int32(0) + + } // end of class OnEnum + + .class public auto ansi sealed OnEnumMember + extends [mscorlib]System.Enum + { + // Fields + .field public specialname rtspecialname int32 value__ + .field public static literal valuetype OnEnumMember A = int32(0) + {{attributeApplication}} + + } // end of class OnEnumMember + + .class public auto ansi beforefieldinit OnClassTypeParameter`1 + extends [mscorlib]System.Object + { + .param type T + {{attributeApplication}} + } // end of class OnClassTypeParameter`1 + + .class public auto ansi beforefieldinit OnMethodTypeParameter + extends [mscorlib]System.Object + { + // Methods + .method public hidebysig static + void M () cil managed + { + .param type T + {{attributeApplication}} + ret + } // end of method OnMethodTypeParameter::M + } // end of class OnMethodTypeParameter + + .class public auto ansi sealed OnDelegateType + extends [mscorlib]System.MulticastDelegate + { + {{attributeApplication}} + // Methods + .method public hidebysig specialname rtspecialname + instance void .ctor ( + object 'object', + native int 'method' + ) runtime managed + { + } // end of method OnDelegateType::.ctor + + .method public hidebysig newslot virtual + instance void Invoke () runtime managed + { + } // end of method OnDelegateType::Invoke + + .method public hidebysig newslot virtual + instance class [mscorlib]System.IAsyncResult BeginInvoke ( + class [mscorlib]System.AsyncCallback callback, + object 'object' + ) runtime managed + { + } // end of method OnDelegateType::BeginInvoke + + .method public hidebysig newslot virtual + instance void EndInvoke ( + class [mscorlib]System.IAsyncResult result + ) runtime managed + { + } // end of method OnDelegateType::EndInvoke + + } // end of class OnDelegateType + + .class public auto ansi OnIndexedPropertyParameter + extends [mscorlib]System.Object + { + // Methods + .method public specialname static + int32 get_Property ( + int32 param + ) cil managed + { + .param [1] + {{attributeApplication}} + + ldc.i4.1 + stloc.0 + ldloc.0 + ret + } // end of method OnIndexedPropertyParameter::get_Property + + .method public specialname static + void set_Property ( + int32 param, + int32 Value + ) cil managed + { + .param [1] + {{attributeApplication}} + + ret + } // end of method OnIndexedPropertyParameter::set_Property + + // Properties + .property int32 Property( + int32 param + ) + { + .get int32 OnIndexedPropertyParameter::get_Property(int32) + .set void OnIndexedPropertyParameter::set_Property(int32, int32) + } + + } // end of class OnIndexedPropertyParameter + + .class public auto ansi beforefieldinit OnThisIndexerParameter + extends [mscorlib]System.Object + { + .custom instance void [mscorlib]System.Reflection.DefaultMemberAttribute::.ctor(string) = ( + 01 00 04 49 74 65 6d 00 00 + ) + // Methods + .method public hidebysig specialname + instance int32 get_Item ( + int32 i + ) cil managed + { + .param [1] + {{attributeApplication}} + ldc.i4.0 + ret + } // end of method OnThisIndexerParameter::get_Item + + .method public hidebysig specialname + instance void set_Item ( + int32 i, + int32 'value' + ) cil managed + { + .param [1] + {{attributeApplication}} + ret + } // end of method OnThisIndexerParameter::set_Item + + .method public hidebysig specialname rtspecialname + instance void .ctor () cil managed + { + ldarg.0 + call instance void [mscorlib]System.Object::.ctor() + ret + } // end of method OnThisIndexerParameter::.ctor + + // Properties + .property instance int32 Item( + int32 i + ) + { + .get instance int32 OnThisIndexerParameter::get_Item(int32) + .set instance void OnThisIndexerParameter::set_Item(int32, int32) + } + } // end of class OnThisIndexerParameter + """; + } + + protected abstract TSource GetUsage(); + protected abstract TCompilation CreateCompilationWithIL(TSource source, string ilSource); + protected abstract TCompilation CreateCompilation(TSource source, MetadataReference[] references); + protected abstract CompilationVerifier CompileAndVerify(TCompilation compilation); + + [Theory] + [InlineData(true)] + [InlineData(false)] + [InlineData(null)] + public void OnNormalSymbols(bool? isOptional) + { + var testIl = $""" + {CompilerFeatureRequiredIl} + {GetTestIl(CompilerFeatureRequiredApplication(isOptional: isOptional))} + """; + var comp = CreateCompilationWithIL(source: GetUsage(), ilSource: testIl); + + if (isOptional == true) + { + CompileAndVerify(comp).VerifyDiagnostics(); + } + else + { + AssertNormalErrors(comp); + } + } + + protected abstract void AssertNormalErrors(TCompilation compilation); + + [Theory] + [InlineData(true)] + [InlineData(false)] + [InlineData(null)] + public void OnAssembly(bool? isOptional) + { + var il = $$""" + .assembly 'AssemblyTest' + { + {{CompilerFeatureRequiredApplication(isOptional: isOptional)}} + } + + .assembly extern mscorlib + { + .publickeytoken = (B7 7A 5C 56 19 34 E0 89) + .ver 4:0:0:0 + } + + {{CompilerFeatureRequiredIl}} + {{GetTestIl(attributeApplication: "")}} + """; + + var compiledIl = CompileIL(il, prependDefaultHeader: false); + + var comp = CreateCompilation(source: GetUsage(), references: new[] { compiledIl }); + + if (isOptional == true) + { + CompileAndVerify(comp).VerifyDiagnostics(); + } + else + { + AssertAssemblyErrors(comp, compiledIl); + } + } + + protected abstract void AssertAssemblyErrors(TCompilation compilation, MetadataReference ilRef); + + [Theory] + [InlineData(true)] + [InlineData(false)] + [InlineData(null)] + public void OnModule(bool? isOptional) + { + var il = $$""" + .module OnModule + {{CompilerFeatureRequiredApplication(isOptional: isOptional)}} + + {{CompilerFeatureRequiredIl}} + {{GetTestIl(attributeApplication: "")}} + """; + + + var compiledIl = CompileIL(il); + var comp = CreateCompilation(source: GetUsage(), references: new[] { compiledIl }); + + if (isOptional == true) + { + CompileAndVerify(comp).VerifyDiagnostics(); + } + else + { + AssertModuleErrors(comp, compiledIl); + } + } + + protected abstract void AssertModuleErrors(TCompilation compilation, MetadataReference ilRef); +} diff --git a/src/Compilers/Test/Core/Traits/CompilerFeature.cs b/src/Compilers/Test/Core/Traits/CompilerFeature.cs index 7a58820fda4fb..a5503dc6d8e7f 100644 --- a/src/Compilers/Test/Core/Traits/CompilerFeature.cs +++ b/src/Compilers/Test/Core/Traits/CompilerFeature.cs @@ -43,5 +43,6 @@ public enum CompilerFeature ModuleInitializers, FunctionPointers, RecordStructs, + RequiredMembers, } } diff --git a/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs b/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs index ece6d0057b533..43b4045dd195c 100644 --- a/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs +++ b/src/Compilers/Test/Utilities/CSharp/CSharpTestBase.cs @@ -625,6 +625,48 @@ public UnmanagedCallersOnlyAttribute() { } } }"; + protected const string RequiredMemberAttribute = @" +namespace System.Runtime.CompilerServices +{ + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Field | AttributeTargets.Property, Inherited = false, AllowMultiple = false)] + public sealed class RequiredMemberAttribute : Attribute + { + public RequiredMemberAttribute() + { + } + } +} +"; + + protected const string SetsRequiredMembersAttribute = @" +namespace System.Diagnostics.CodeAnalysis +{ + [AttributeUsage(AttributeTargets.Constructor, Inherited = false, AllowMultiple = false)] + public sealed class SetsRequiredMembersAttribute : Attribute + { + public SetsRequiredMembersAttribute() + { + } + } +} +"; + + internal const string CompilerFeatureRequiredAttribute = """ + namespace System.Runtime.CompilerServices + { + [AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)] + public sealed class CompilerFeatureRequiredAttribute : Attribute + { + public CompilerFeatureRequiredAttribute(string featureName) + { + FeatureName = featureName; + } + public string FeatureName { get; } + public bool IsOptional { get; set; } + } + } + """; + protected static CSharpCompilationOptions WithNullableEnable(CSharpCompilationOptions options = null) { return WithNullable(options, NullableContextOptions.Enable); @@ -1316,12 +1358,12 @@ internal static void VerifyUsesOfNullability(Symbol symbol, ImmutableArray references, CSharpCompilationOptions options = null, CSharpParseOptions parseOptions = null) { - var trees = (source == null) ? null : source.Select(s => Parse(s, options: parseOptions)).ToArray(); + var trees = (source ?? CSharpTestSource.None).GetSyntaxTrees(parseOptions); Func createCompilationLambda = () => CSharpCompilation.Create(identity.Name, options: options ?? TestOptions.ReleaseDll, references: references, syntaxTrees: trees); ValidateCompilation(createCompilationLambda); diff --git a/src/Compilers/Test/Utilities/CSharp/NativeIntegerAttributesVisitor.cs b/src/Compilers/Test/Utilities/CSharp/NativeIntegerAttributesVisitor.cs index 91859566bcbc6..74a59cf8965bc 100644 --- a/src/Compilers/Test/Utilities/CSharp/NativeIntegerAttributesVisitor.cs +++ b/src/Compilers/Test/Utilities/CSharp/NativeIntegerAttributesVisitor.cs @@ -2,11 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - -using System.Collections.Generic; using System.Collections.Immutable; -using System.Diagnostics; using System.Text; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE; @@ -16,7 +12,7 @@ namespace Microsoft.CodeAnalysis.CSharp.Test.Utilities /// /// Returns a string with all symbols containing NativeIntegerAttributes. /// - internal sealed class NativeIntegerAttributesVisitor : CSharpSymbolVisitor + internal sealed class NativeIntegerAttributesVisitor : TestAttributesVisitor { internal static string GetString(PEModuleSymbol module) { @@ -26,109 +22,11 @@ internal static string GetString(PEModuleSymbol module) return builder.ToString(); } - private readonly StringBuilder _builder; - private readonly HashSet _reported; - - private NativeIntegerAttributesVisitor(StringBuilder builder) - { - _builder = builder; - _reported = new HashSet(); - } - - public override void DefaultVisit(Symbol symbol) - { - ReportSymbol(symbol); - } - - public override void VisitModule(ModuleSymbol module) - { - Visit(module.GlobalNamespace); - } - - public override void VisitNamespace(NamespaceSymbol @namespace) - { - VisitList(@namespace.GetMembers()); - } - - public override void VisitNamedType(NamedTypeSymbol type) - { - ReportSymbol(type); - VisitList(type.TypeParameters); - - foreach (var member in type.GetMembers()) - { - // Skip accessors since those are covered by associated symbol. - if (member.IsAccessor()) continue; - Visit(member); - } - } - - public override void VisitMethod(MethodSymbol method) - { - ReportSymbol(method); - VisitList(method.TypeParameters); - VisitList(method.Parameters); - } - - public override void VisitEvent(EventSymbol @event) - { - ReportSymbol(@event); - Visit(@event.AddMethod); - Visit(@event.RemoveMethod); - } - - public override void VisitProperty(PropertySymbol property) - { - ReportSymbol(property); - VisitList(property.Parameters); - Visit(property.GetMethod); - Visit(property.SetMethod); - } - - public override void VisitTypeParameter(TypeParameterSymbol typeParameter) + private NativeIntegerAttributesVisitor(StringBuilder builder) : base(builder) { - ReportSymbol(typeParameter); } - private void VisitList(ImmutableArray symbols) where TSymbol : Symbol - { - foreach (var symbol in symbols) - { - Visit(symbol); - } - } - - /// - /// Return the containing symbol used in the hierarchy here. Specifically, the - /// hierarchy contains types, members, and parameters only, and accessors are - /// considered members of the associated symbol rather than the type. - /// - private static Symbol GetContainingSymbol(Symbol symbol) - { - if (symbol.IsAccessor()) - { - return ((MethodSymbol)symbol).AssociatedSymbol; - } - var containingSymbol = symbol.ContainingSymbol; - return containingSymbol?.Kind == SymbolKind.Namespace ? null : containingSymbol; - } - - private static string GetIndentString(Symbol symbol) - { - int level = 0; - while (true) - { - symbol = GetContainingSymbol(symbol); - if (symbol is null) - { - break; - } - level++; - } - return new string(' ', level * 4); - } - - private static readonly SymbolDisplayFormat _displayFormat = SymbolDisplayFormat.TestFormatWithConstraints. + protected override SymbolDisplayFormat DisplayFormat => SymbolDisplayFormat.TestFormatWithConstraints. WithMemberOptions( SymbolDisplayMemberOptions.IncludeParameters | SymbolDisplayMemberOptions.IncludeType | @@ -136,100 +34,9 @@ private static string GetIndentString(Symbol symbol) SymbolDisplayMemberOptions.IncludeExplicitInterface). WithCompilerInternalOptions(SymbolDisplayCompilerInternalOptions.UseNativeIntegerUnderlyingType); - private void ReportContainingSymbols(Symbol symbol) - { - symbol = GetContainingSymbol(symbol); - if (symbol is null) - { - return; - } - if (_reported.Contains(symbol)) - { - return; - } - ReportContainingSymbols(symbol); - _builder.Append(GetIndentString(symbol)); - _builder.AppendLine(symbol.ToDisplayString(_displayFormat)); - _reported.Add(symbol); - } - - private void ReportSymbol(Symbol symbol) - { - var type = (symbol as TypeSymbol) ?? symbol.GetTypeOrReturnType().Type; - var attribute = GetNativeIntegerAttribute((symbol is MethodSymbol method) ? method.GetReturnTypeAttributes() : symbol.GetAttributes()); - Debug.Assert((type?.ContainsNativeIntegerWrapperType() != true) || (attribute != null)); - if (attribute == null) - { - return; - } - ReportContainingSymbols(symbol); - _builder.Append(GetIndentString(symbol)); - _builder.Append($"{ReportAttribute(attribute)} "); - _builder.AppendLine(symbol.ToDisplayString(_displayFormat)); - _reported.Add(symbol); - } + protected override bool TypeRequiresAttribute(TypeSymbol? type) => type?.ContainsNativeIntegerWrapperType() == true; - private static string ReportAttribute(CSharpAttributeData attribute) - { - var builder = new StringBuilder(); - builder.Append("["); - - var name = attribute.AttributeClass.Name; - if (name.EndsWith("Attribute")) name = name.Substring(0, name.Length - 9); - builder.Append(name); - - var arguments = attribute.ConstructorArguments.ToImmutableArray(); - if (arguments.Length > 0) - { - builder.Append("("); - printValues(builder, arguments); - builder.Append(")"); - } - - builder.Append("]"); - return builder.ToString(); - - static void printValues(StringBuilder builder, ImmutableArray values) - { - for (int i = 0; i < values.Length; i++) - { - if (i > 0) - { - builder.Append(", "); - } - printValue(builder, values[i]); - } - } - - static void printValue(StringBuilder builder, TypedConstant value) - { - if (value.Kind == TypedConstantKind.Array) - { - builder.Append("{ "); - printValues(builder, value.Values); - builder.Append(" }"); - } - else - { - builder.Append(value.Value); - } - } - } - - private static CSharpAttributeData GetNativeIntegerAttribute(ImmutableArray attributes) => + protected override CSharpAttributeData? GetTargetAttribute(ImmutableArray attributes) => GetAttribute(attributes, "System.Runtime.CompilerServices", "NativeIntegerAttribute"); - - private static CSharpAttributeData GetAttribute(ImmutableArray attributes, string namespaceName, string name) - { - foreach (var attribute in attributes) - { - var containingType = attribute.AttributeConstructor.ContainingType; - if (containingType.Name == name && containingType.ContainingNamespace.QualifiedName == namespaceName) - { - return attribute; - } - } - return null; - } } } diff --git a/src/Compilers/Test/Utilities/CSharp/NullableAttributesVisitor.cs b/src/Compilers/Test/Utilities/CSharp/NullableAttributesVisitor.cs index 04bc720e91fcb..cdae7795a3732 100644 --- a/src/Compilers/Test/Utilities/CSharp/NullableAttributesVisitor.cs +++ b/src/Compilers/Test/Utilities/CSharp/NullableAttributesVisitor.cs @@ -2,20 +2,18 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -#nullable disable - -using System.Collections.Generic; using System.Collections.Immutable; using System.Text; using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE; +using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CSharp.Test.Utilities { /// /// Returns a string with all symbols containing nullable attributes. /// - internal sealed class NullableAttributesVisitor : CSharpSymbolVisitor + internal sealed class NullableAttributesVisitor : TestAttributesVisitor { internal static string GetString(PEModuleSymbol module) { @@ -26,30 +24,11 @@ internal static string GetString(PEModuleSymbol module) } private readonly PEModuleSymbol _module; - private readonly StringBuilder _builder; - private readonly HashSet _reported; - private CSharpAttributeData _nullableContext; + private CSharpAttributeData? _nullableContext; - private NullableAttributesVisitor(PEModuleSymbol module, StringBuilder builder) + private NullableAttributesVisitor(PEModuleSymbol module, StringBuilder builder) : base(builder) { _module = module; - _builder = builder; - _reported = new HashSet(); - } - - public override void DefaultVisit(Symbol symbol) - { - ReportSymbol(symbol); - } - - public override void VisitModule(ModuleSymbol module) - { - Visit(module.GlobalNamespace); - } - - public override void VisitNamespace(NamespaceSymbol @namespace) - { - VisitList(@namespace.GetMembers()); } public override void VisitNamedType(NamedTypeSymbol type) @@ -57,15 +36,7 @@ public override void VisitNamedType(NamedTypeSymbol type) var previousContext = _nullableContext; _nullableContext = GetNullableContextAttribute(type.GetAttributes()) ?? _nullableContext; - ReportSymbol(type); - VisitList(type.TypeParameters); - - foreach (var member in type.GetMembers()) - { - // Skip accessors since those are covered by associated symbol. - if (member.IsAccessor()) continue; - Visit(member); - } + base.VisitNamedType(type); _nullableContext = previousContext; } @@ -75,96 +46,19 @@ public override void VisitMethod(MethodSymbol method) var previousContext = _nullableContext; _nullableContext = GetNullableContextAttribute(method.GetAttributes()) ?? _nullableContext; - ReportSymbol(method); - VisitList(method.TypeParameters); - VisitList(method.Parameters); + base.VisitMethod(method); _nullableContext = previousContext; } - public override void VisitEvent(EventSymbol @event) - { - ReportSymbol(@event); - Visit(@event.AddMethod); - Visit(@event.RemoveMethod); - } - - public override void VisitProperty(PropertySymbol property) - { - ReportSymbol(property); - VisitList(property.Parameters); - Visit(property.GetMethod); - Visit(property.SetMethod); - } - - public override void VisitTypeParameter(TypeParameterSymbol typeParameter) - { - ReportSymbol(typeParameter); - } - - private void VisitList(ImmutableArray symbols) where TSymbol : Symbol - { - foreach (var symbol in symbols) - { - Visit(symbol); - } - } - - /// - /// Return the containing symbol used in the hierarchy here. Specifically, the - /// hierarchy contains types, members, and parameters only, and accessors are - /// considered members of the associated symbol rather than the type. - /// - private static Symbol GetContainingSymbol(Symbol symbol) - { - if (symbol.IsAccessor()) - { - return ((MethodSymbol)symbol).AssociatedSymbol; - } - var containingSymbol = symbol.ContainingSymbol; - return containingSymbol?.Kind == SymbolKind.Namespace ? null : containingSymbol; - } - - private static string GetIndentString(Symbol symbol) - { - int level = 0; - while (true) - { - symbol = GetContainingSymbol(symbol); - if (symbol is null) - { - break; - } - level++; - } - return new string(' ', level * 4); - } - - private static readonly SymbolDisplayFormat _displayFormat = SymbolDisplayFormat.TestFormatWithConstraints. + protected override SymbolDisplayFormat DisplayFormat => SymbolDisplayFormat.TestFormatWithConstraints. WithMemberOptions( SymbolDisplayMemberOptions.IncludeParameters | SymbolDisplayMemberOptions.IncludeType | SymbolDisplayMemberOptions.IncludeRef | SymbolDisplayMemberOptions.IncludeExplicitInterface); - private void ReportContainingSymbols(Symbol symbol) - { - symbol = GetContainingSymbol(symbol); - if (symbol is null) - { - return; - } - if (_reported.Contains(symbol)) - { - return; - } - ReportContainingSymbols(symbol); - _builder.Append(GetIndentString(symbol)); - _builder.AppendLine(symbol.ToDisplayString(_displayFormat)); - _reported.Add(symbol); - } - - private void ReportSymbol(Symbol symbol) + protected override void ReportSymbol(Symbol symbol) { var nullableContextAttribute = GetNullableContextAttribute(symbol.GetAttributes()); var nullableAttribute = GetNullableAttribute((symbol is MethodSymbol method) ? method.GetReturnTypeAttributes() : symbol.GetAttributes()); @@ -196,7 +90,7 @@ private void ReportSymbol(Symbol symbol) _builder.Append($"{ReportAttribute(nullableAttribute)} "); } - _builder.AppendLine(symbol.ToDisplayString(_displayFormat)); + _builder.AppendLine(symbol.ToDisplayString(DisplayFormat)); _reported.Add(symbol); } @@ -216,70 +110,20 @@ private static Symbol GetAccessSymbol(Symbol symbol) } } - private static string ReportAttribute(CSharpAttributeData attribute) - { - var builder = new StringBuilder(); - builder.Append("["); - - var name = attribute.AttributeClass.Name; - if (name.EndsWith("Attribute")) name = name.Substring(0, name.Length - 9); - builder.Append(name); - - var arguments = attribute.ConstructorArguments.ToImmutableArray(); - if (arguments.Length > 0) - { - builder.Append("("); - printValues(builder, arguments); - builder.Append(")"); - } - - builder.Append("]"); - return builder.ToString(); - - static void printValues(StringBuilder builder, ImmutableArray values) - { - for (int i = 0; i < values.Length; i++) - { - if (i > 0) - { - builder.Append(", "); - } - printValue(builder, values[i]); - } - } - - static void printValue(StringBuilder builder, TypedConstant value) - { - if (value.Kind == TypedConstantKind.Array) - { - builder.Append("{ "); - printValues(builder, value.Values); - builder.Append(" }"); - } - else - { - builder.Append(value.Value); - } - } - } - - private static CSharpAttributeData GetNullableContextAttribute(ImmutableArray attributes) => + private static CSharpAttributeData? GetNullableContextAttribute(ImmutableArray attributes) => GetAttribute(attributes, "System.Runtime.CompilerServices", "NullableContextAttribute"); - private static CSharpAttributeData GetNullableAttribute(ImmutableArray attributes) => + private static CSharpAttributeData? GetNullableAttribute(ImmutableArray attributes) => GetAttribute(attributes, "System.Runtime.CompilerServices", "NullableAttribute"); - private static CSharpAttributeData GetAttribute(ImmutableArray attributes, string namespaceName, string name) + protected override bool TypeRequiresAttribute(TypeSymbol? type) { - foreach (var attribute in attributes) - { - var containingType = attribute.AttributeConstructor.ContainingType; - if (containingType.Name == name && containingType.ContainingNamespace.QualifiedName == namespaceName) - { - return attribute; - } - } - return null; + throw ExceptionUtilities.Unreachable; + } + + protected override CSharpAttributeData GetTargetAttribute(ImmutableArray attributes) + { + throw ExceptionUtilities.Unreachable; } } } diff --git a/src/Compilers/Test/Utilities/CSharp/RequiredMemberAttributesVisitor.cs b/src/Compilers/Test/Utilities/CSharp/RequiredMemberAttributesVisitor.cs new file mode 100644 index 0000000000000..00c93aa972ba1 --- /dev/null +++ b/src/Compilers/Test/Utilities/CSharp/RequiredMemberAttributesVisitor.cs @@ -0,0 +1,35 @@ +// 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.Collections.Immutable; +using System.Text; +using Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE; + +namespace Microsoft.CodeAnalysis.CSharp.Test.Utilities; + +internal class RequiredMemberAttributesVisitor : TestAttributesVisitor +{ + internal static string GetString(PEModuleSymbol module) + { + var builder = new StringBuilder(); + var visitor = new RequiredMemberAttributesVisitor(builder); + visitor.Visit(module); + return builder.ToString(); + } + + private RequiredMemberAttributesVisitor(StringBuilder builder) : base(builder) + { + } + + protected override SymbolDisplayFormat DisplayFormat => SymbolDisplayFormat.TestFormat; + + protected override CSharpAttributeData? GetTargetAttribute(ImmutableArray attributes) + => GetAttribute(attributes, "System.Runtime.CompilerServices", "RequiredMemberAttribute"); + + protected override bool TypeRequiresAttribute(TypeSymbol? type) + { + return false; + } +} diff --git a/src/Compilers/Test/Utilities/CSharp/TestAttributesVisitor.cs b/src/Compilers/Test/Utilities/CSharp/TestAttributesVisitor.cs new file mode 100644 index 0000000000000..d8308e85cae85 --- /dev/null +++ b/src/Compilers/Test/Utilities/CSharp/TestAttributesVisitor.cs @@ -0,0 +1,220 @@ +// 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.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics; +using System.Text; +using Microsoft.CodeAnalysis.CSharp.Symbols; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.Test.Utilities +{ + internal abstract class TestAttributesVisitor : CSharpSymbolVisitor + { + protected readonly StringBuilder _builder; + protected readonly HashSet _reported; + + protected TestAttributesVisitor(StringBuilder builder) + { + _builder = builder; + _reported = new HashSet(); + } + + public override void DefaultVisit(Symbol symbol) + { + ReportSymbol(symbol); + } + + public override void VisitModule(ModuleSymbol module) + { + Visit(module.GlobalNamespace); + } + + public override void VisitNamespace(NamespaceSymbol @namespace) + { + VisitList(@namespace.GetMembers()); + } + + public override void VisitNamedType(NamedTypeSymbol type) + { + ReportSymbol(type); + VisitList(type.TypeParameters); + + foreach (var member in type.GetMembers()) + { + // Skip accessors since those are covered by associated symbol. + if (member.IsAccessor()) continue; + Visit(member); + } + } + + public override void VisitMethod(MethodSymbol method) + { + ReportSymbol(method); + VisitList(method.TypeParameters); + VisitList(method.Parameters); + } + + public override void VisitEvent(EventSymbol @event) + { + ReportSymbol(@event); + Visit(@event.AddMethod); + Visit(@event.RemoveMethod); + } + + public override void VisitProperty(PropertySymbol property) + { + ReportSymbol(property); + VisitList(property.Parameters); + Visit(property.GetMethod); + Visit(property.SetMethod); + } + + public override void VisitTypeParameter(TypeParameterSymbol typeParameter) + { + ReportSymbol(typeParameter); + } + + private void VisitList(ImmutableArray symbols) where TSymbol : Symbol + { + foreach (var symbol in symbols) + { + Visit(symbol); + } + } + + /// + /// Return the containing symbol used in the hierarchy here. Specifically, the + /// hierarchy contains types, members, and parameters only, and accessors are + /// considered members of the associated symbol rather than the type. + /// + private static Symbol? GetContainingSymbol(Symbol symbol) + { + if (symbol.IsAccessor()) + { + return ((MethodSymbol)symbol).AssociatedSymbol; + } + var containingSymbol = symbol.ContainingSymbol; + return containingSymbol?.Kind == SymbolKind.Namespace ? null : containingSymbol; + } + + protected static string GetIndentString(Symbol symbol) + { + int level = 0; + var current = symbol; + while (true) + { + current = GetContainingSymbol(current); + if (current is null) + { + break; + } + level++; + } + return new string(' ', level * 4); + } + + protected abstract SymbolDisplayFormat DisplayFormat { get; } + + protected void ReportContainingSymbols(Symbol symbol) + { + var s = GetContainingSymbol(symbol); + if (s is null) + { + return; + } + if (_reported.Contains(s)) + { + return; + } + ReportContainingSymbols(s); + _builder.Append(GetIndentString(s)); + _builder.AppendLine(s.ToDisplayString(DisplayFormat)); + _reported.Add(s); + } + + protected virtual void ReportSymbol(Symbol symbol) + { + var type = (symbol as TypeSymbol) ?? symbol.GetTypeOrReturnType().Type; + var attribute = GetTargetAttribute((symbol is MethodSymbol method) ? method.GetReturnTypeAttributes() : symbol.GetAttributes()); + Debug.Assert((!TypeRequiresAttribute(type)) || (attribute != null)); + if (attribute == null) + { + return; + } + ReportContainingSymbols(symbol); + _builder.Append(GetIndentString(symbol)); + _builder.Append($"{ReportAttribute(attribute)} "); + _builder.AppendLine(symbol.ToDisplayString(DisplayFormat)); + _reported.Add(symbol); + } + + protected static string ReportAttribute(CSharpAttributeData attribute) + { + var builder = new StringBuilder(); + builder.Append('['); + + Assert.NotNull(attribute.AttributeClass); + var name = attribute.AttributeClass!.Name; + if (name.EndsWith("Attribute")) name = name.Substring(0, name.Length - 9); + builder.Append(name); + + var arguments = attribute.ConstructorArguments.ToImmutableArray(); + if (arguments.Length > 0) + { + builder.Append('('); + printValues(builder, arguments); + builder.Append(')'); + } + + builder.Append(']'); + return builder.ToString(); + + static void printValues(StringBuilder builder, ImmutableArray values) + { + for (int i = 0; i < values.Length; i++) + { + if (i > 0) + { + builder.Append(", "); + } + printValue(builder, values[i]); + } + } + + static void printValue(StringBuilder builder, TypedConstant value) + { + if (value.Kind == TypedConstantKind.Array) + { + builder.Append("{ "); + printValues(builder, value.Values); + builder.Append(" }"); + } + else + { + builder.Append(value.Value); + } + } + } + + protected abstract bool TypeRequiresAttribute(TypeSymbol? type); + + protected abstract CSharpAttributeData? GetTargetAttribute(ImmutableArray attributes); + + protected static CSharpAttributeData? GetAttribute(ImmutableArray attributes, string namespaceName, string name) + { + foreach (var attribute in attributes) + { + Assert.NotNull(attribute.AttributeConstructor); + var containingType = attribute.AttributeConstructor!.ContainingType; + if (containingType.Name == name && containingType.ContainingNamespace.QualifiedName == namespaceName) + { + return attribute; + } + } + return null; + } + } +} diff --git a/src/Compilers/VisualBasic/Portable/Binding/Binder.vb b/src/Compilers/VisualBasic/Portable/Binding/Binder.vb index 60e4e3a773b20..c5c56102eff92 100644 --- a/src/Compilers/VisualBasic/Portable/Binding/Binder.vb +++ b/src/Compilers/VisualBasic/Portable/Binding/Binder.vb @@ -575,7 +575,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Dim useSiteInfo As UseSiteInfo(Of AssemblySymbol) = member.GetUseSiteInfo() If useSiteInfo.DiagnosticInfo Is Nothing Then - Symbol.MergeUseSiteInfo(useSiteInfo, member.ContainingType.GetUseSiteInfo(), highestPriorityUseSiteError:=0) + member.MergeUseSiteInfo(useSiteInfo, member.ContainingType.GetUseSiteInfo()) End If Return useSiteInfo diff --git a/src/Compilers/VisualBasic/Portable/Errors/ErrorFactories.vb b/src/Compilers/VisualBasic/Portable/Errors/ErrorFactories.vb index 71b099a93abdf..023c7c2731778 100644 --- a/src/Compilers/VisualBasic/Portable/Errors/ErrorFactories.vb +++ b/src/Compilers/VisualBasic/Portable/Errors/ErrorFactories.vb @@ -26,6 +26,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End Function Public Shared ReadOnly VoidDiagnosticInfo As DiagnosticInfo = ErrorInfo(ERRID.Void) + Public Shared ReadOnly EmptyDiagnosticInfo As DiagnosticInfo = ErrorInfo(ERRID.ERR_None) Public Shared ReadOnly GetErrorInfo_ERR_WithEventsRequiresClass As Func(Of DiagnosticInfo) = Function() ErrorInfo(ERRID.ERR_WithEventsRequiresClass) diff --git a/src/Compilers/VisualBasic/Portable/Errors/Errors.vb b/src/Compilers/VisualBasic/Portable/Errors/Errors.vb index 9cd4e9a6c63c4..dc5213173ded5 100644 --- a/src/Compilers/VisualBasic/Portable/Errors/Errors.vb +++ b/src/Compilers/VisualBasic/Portable/Errors/Errors.vb @@ -1764,7 +1764,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic ERR_MultipleAnalyzerConfigsInSameDir = 37317 ERR_StdInOptionProvidedButConsoleInputIsNotRedirected = 37318 - ERR_NextAvailable = 37319 + ERR_UnsupportedCompilerFeature = 37319 + ERR_DoNotUseCompilerFeatureRequired = 37320 + + ERR_NextAvailable = 37321 '// WARNINGS BEGIN HERE WRN_UseOfObsoleteSymbol2 = 40000 diff --git a/src/Compilers/VisualBasic/Portable/Symbols/ArrayTypeSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/ArrayTypeSymbol.vb index fe5c553eaf68a..cb522160892b6 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/ArrayTypeSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/ArrayTypeSymbol.vb @@ -369,14 +369,15 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols ' Check type. Dim elementUseSiteInfo As UseSiteInfo(Of AssemblySymbol) = DeriveUseSiteInfoFromType(Me.ElementType) - If elementUseSiteInfo.DiagnosticInfo?.Code = ERRID.ERR_UnsupportedType1 Then + If elementUseSiteInfo.DiagnosticInfo IsNot Nothing AndAlso IsHighestPriorityUseSiteError(elementUseSiteInfo.DiagnosticInfo.Code) Then Return elementUseSiteInfo End If ' Check custom modifiers. Dim modifiersUseSiteInfo As UseSiteInfo(Of AssemblySymbol) = DeriveUseSiteInfoFromCustomModifiers(Me.CustomModifiers) - Return MergeUseSiteInfo(elementUseSiteInfo, modifiersUseSiteInfo) + MergeUseSiteInfo(elementUseSiteInfo, modifiersUseSiteInfo) + Return elementUseSiteInfo End Function Friend Overrides Function GetUnificationUseSiteDiagnosticRecursive(owner As Symbol, ByRef checkedTypes As HashSet(Of TypeSymbol)) As DiagnosticInfo diff --git a/src/Compilers/VisualBasic/Portable/Symbols/EventSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/EventSymbol.vb index 70241f7359c4b..3a033ba0e0afc 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/EventSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/EventSymbol.vb @@ -195,7 +195,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Friend Function CalculateUseSiteInfo() As UseSiteInfo(Of AssemblySymbol) Debug.Assert(Me.IsDefinition) ' Check event type. - Dim useSiteInfo = MergeUseSiteInfo(New UseSiteInfo(Of AssemblySymbol)(PrimaryDependency), DeriveUseSiteInfoFromType(Me.Type)) + Dim useSiteInfo = New UseSiteInfo(Of AssemblySymbol)(PrimaryDependency) + MergeUseSiteInfo(useSiteInfo, DeriveUseSiteInfoFromType(Me.Type)) Dim errorInfo As DiagnosticInfo = useSiteInfo.DiagnosticInfo If errorInfo IsNot Nothing Then @@ -237,16 +238,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Return useSiteInfo End Function - Protected Overrides ReadOnly Property HighestPriorityUseSiteError As Integer - Get - Return ERRID.ERR_UnsupportedType1 - End Get - End Property + Protected Overrides Function IsHighestPriorityUseSiteError(code As Integer) As Boolean + Return code = ERRID.ERR_UnsupportedType1 OrElse code = ERRID.ERR_UnsupportedCompilerFeature + End Function Public NotOverridable Overrides ReadOnly Property HasUnsupportedMetadata As Boolean Get Dim info As DiagnosticInfo = GetUseSiteInfo().DiagnosticInfo - Return info IsNot Nothing AndAlso (info.Code = ERRID.ERR_UnsupportedType1 OrElse info.Code = ERRID.ERR_UnsupportedEvent1) + Return info IsNot Nothing AndAlso (info.Code = ERRID.ERR_UnsupportedType1 OrElse info.Code = ERRID.ERR_UnsupportedEvent1 OrElse info.Code = ERRID.ERR_UnsupportedCompilerFeature) End Get End Property diff --git a/src/Compilers/VisualBasic/Portable/Symbols/FieldSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/FieldSymbol.vb index 88924bd0e60d8..adc1123758104 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/FieldSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/FieldSymbol.vb @@ -280,21 +280,19 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Debug.Assert(IsDefinition) ' Check type. - Dim useSiteInfo As UseSiteInfo(Of AssemblySymbol) = MergeUseSiteInfo(New UseSiteInfo(Of AssemblySymbol)(PrimaryDependency), DeriveUseSiteInfoFromType(Me.Type)) + Dim useSiteInfo As UseSiteInfo(Of AssemblySymbol) = New UseSiteInfo(Of AssemblySymbol)(PrimaryDependency) - If useSiteInfo.DiagnosticInfo?.Code = ERRID.ERR_UnsupportedField1 Then + If MergeUseSiteInfo(useSiteInfo, DeriveUseSiteInfoFromType(Me.Type)) Then Return useSiteInfo End If ' Check custom modifiers. Dim modifiersUseSiteInfo As UseSiteInfo(Of AssemblySymbol) = DeriveUseSiteInfoFromCustomModifiers(Me.CustomModifiers) - If modifiersUseSiteInfo.DiagnosticInfo?.Code = ERRID.ERR_UnsupportedField1 Then - Return modifiersUseSiteInfo + If MergeUseSiteInfo(useSiteInfo, modifiersUseSiteInfo) Then + Return useSiteInfo End If - useSiteInfo = MergeUseSiteInfo(useSiteInfo, modifiersUseSiteInfo) - ' If the member is in an assembly with unified references, ' we check if its definition depends on a type from a unified reference. If useSiteInfo.DiagnosticInfo Is Nothing AndAlso Me.ContainingModule.HasUnifiedReferences Then @@ -315,16 +313,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols ''' ''' Return error code that has highest priority while calculating use site error for this symbol. ''' - Protected Overrides ReadOnly Property HighestPriorityUseSiteError As Integer - Get - Return ERRID.ERR_UnsupportedField1 - End Get - End Property + Protected Overrides Function IsHighestPriorityUseSiteError(code As Integer) As Boolean + Return code = ERRID.ERR_UnsupportedField1 OrElse code = ERRID.ERR_UnsupportedCompilerFeature + End Function Public NotOverridable Overrides ReadOnly Property HasUnsupportedMetadata As Boolean Get Dim info As DiagnosticInfo = GetUseSiteInfo().DiagnosticInfo - Return info IsNot Nothing AndAlso info.Code = ERRID.ERR_UnsupportedField1 + Return info IsNot Nothing AndAlso (info.Code = ERRID.ERR_UnsupportedField1 OrElse info.Code = ERRID.ERR_UnsupportedCompilerFeature) End Get End Property @@ -422,6 +418,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property + Private ReadOnly Property IFieldSymbol_IsRequired As Boolean Implements IFieldSymbol.IsRequired + Get + Return False + End Get + End Property + Private ReadOnly Property IFieldSymbol_IsFixedSizeBuffer As Boolean Implements IFieldSymbol.IsFixedSizeBuffer Get Return False diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEAssemblySymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEAssemblySymbol.vb index 2cbea1d30b4e2..b7ac701c2213a 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEAssemblySymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEAssemblySymbol.vb @@ -11,6 +11,7 @@ Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports System.Runtime.InteropServices Imports System.Reflection.Metadata.Ecma335 +Imports System.Threading Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE @@ -65,6 +66,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Private _lazyCustomAttributes As ImmutableArray(Of VisualBasicAttributeData) + Private _lazyCachedCompilerFeatureRequiredDiagnosticInfo As DiagnosticInfo = ErrorFactory.EmptyDiagnosticInfo + Friend Sub New(assembly As PEAssembly, documentationProvider As DocumentationProvider, isLinked As Boolean, importOptions As MetadataImportOptions) Debug.Assert(assembly IsNot Nothing) @@ -257,5 +260,27 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Public Overrides Function GetMetadata() As AssemblyMetadata Return _assembly.GetNonDisposableMetadata() End Function + + Friend Function GetCompilerFeatureRequiredDiagnosticInfo() As DiagnosticInfo + If _lazyCachedCompilerFeatureRequiredDiagnosticInfo Is ErrorFactory.EmptyDiagnosticInfo Then + Interlocked.CompareExchange( + _lazyCachedCompilerFeatureRequiredDiagnosticInfo, + DeriveCompilerFeatureRequiredAttributeDiagnostic(Me, PrimaryModule, _assembly.Handle, CompilerFeatureRequiredFeatures.None, New MetadataDecoder(PrimaryModule)), + ErrorFactory.EmptyDiagnosticInfo) + End If + + Return _lazyCachedCompilerFeatureRequiredDiagnosticInfo + End Function + + Public Overrides ReadOnly Property HasUnsupportedMetadata As Boolean + Get + Dim info = GetCompilerFeatureRequiredDiagnosticInfo() + If info IsNot Nothing Then + Return info.Code = DirectCast(ERRID.ERR_UnsupportedCompilerFeature, Integer) OrElse MyBase.HasUnsupportedMetadata + End If + + Return MyBase.HasUnsupportedMetadata + End Get + End Property End Class End Namespace diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEEventSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEEventSymbol.vb index 8b97e585a9c4d..d72f126a5fbcb 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEEventSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEEventSymbol.vb @@ -291,14 +291,38 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Friend Overrides Function GetUseSiteInfo() As UseSiteInfo(Of AssemblySymbol) Dim primaryDependency As AssemblySymbol = Me.PrimaryDependency + Dim containingModule = _containingType.ContainingPEModule If Not _lazyCachedUseSiteInfo.IsInitialized Then - _lazyCachedUseSiteInfo.Initialize(primaryDependency, CalculateUseSiteInfo()) + Dim useSiteInfo As UseSiteInfo(Of AssemblySymbol) = CalculateUseSiteInfo() + Dim errorInfo = useSiteInfo.DiagnosticInfo + DeriveCompilerFeatureRequiredDiagnostic(errorInfo) + _lazyCachedUseSiteInfo.Initialize(primaryDependency, useSiteInfo.AdjustDiagnosticInfo(errorInfo)) End If Return _lazyCachedUseSiteInfo.ToUseSiteInfo(primaryDependency) End Function + Private Sub DeriveCompilerFeatureRequiredDiagnostic(ByRef errorInfo As DiagnosticInfo) + If errorInfo IsNot Nothing Then + Return + End If + + Dim containingModule = _containingType.ContainingPEModule + errorInfo = DeriveCompilerFeatureRequiredAttributeDiagnostic( + Me, + containingModule, + Handle, + CompilerFeatureRequiredFeatures.None, + New MetadataDecoder(containingModule, _containingType)) + + If errorInfo IsNot Nothing Then + Return + End If + + errorInfo = _containingType.GetCompilerFeatureRequiredDiagnostic() + End Sub + ''' ''' This is for perf, not for correctness. ''' diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEFieldSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEFieldSymbol.vb index bb09dc34f1427..159f2adc4e68e 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEFieldSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEFieldSymbol.vb @@ -383,6 +383,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE If Not _lazyCachedUseSiteInfo.IsInitialized Then Dim fieldUseSiteInfo = CalculateUseSiteInfo() + If fieldUseSiteInfo.DiagnosticInfo Is Nothing Then + Dim errorInfo = DeriveCompilerFeatureRequiredDiagnostic(fieldUseSiteInfo) + If errorInfo IsNot Nothing Then + fieldUseSiteInfo = New UseSiteInfo(Of AssemblySymbol)(errorInfo) + End If + End If + ' if there was no previous use site error for this symbol, check the constant value If fieldUseSiteInfo.DiagnosticInfo Is Nothing Then @@ -403,6 +410,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Return _lazyCachedUseSiteInfo.ToUseSiteInfo(primaryDependency) End Function + Private Function DeriveCompilerFeatureRequiredDiagnostic(ByRef result As UseSiteInfo(Of AssemblySymbol)) As DiagnosticInfo + Dim containingModule = _containingType.ContainingPEModule + Return If(DeriveCompilerFeatureRequiredAttributeDiagnostic(Me, containingModule, Handle, CompilerFeatureRequiredFeatures.None, New MetadataDecoder(containingModule, _containingType)), + _containingType.GetCompilerFeatureRequiredDiagnostic()) + End Function + Friend ReadOnly Property Handle As FieldDefinitionHandle Get Return _handle diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEMethodSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEMethodSymbol.vb index 6392cbced26f0..406a96f7fcbfc 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEMethodSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEMethodSymbol.vb @@ -388,7 +388,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE End If End If - If Not IsShared AndAlso String.Equals(name, WellKnownMemberNames.DelegateInvokeName, StringComparison.Ordinal) AndAlso _containingType.TypeKind = TYPEKIND.Delegate Then + If Not IsShared AndAlso String.Equals(name, WellKnownMemberNames.DelegateInvokeName, StringComparison.Ordinal) AndAlso _containingType.TypeKind = TypeKind.Delegate Then Return MethodKind.DelegateInvoke End If @@ -949,7 +949,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE ''' false if the method is already associated with a property or event. ''' Friend Function SetAssociatedProperty(propertySymbol As PEPropertySymbol, methodKind As MethodKind) As Boolean - Debug.Assert((methodKind = methodKind.PropertyGet) OrElse (methodKind = methodKind.PropertySet)) + Debug.Assert((methodKind = MethodKind.PropertyGet) OrElse (methodKind = MethodKind.PropertySet)) Return Me.SetAssociatedPropertyOrEvent(propertySymbol, methodKind) End Function @@ -958,7 +958,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE ''' false if the method is already associated with a property or event. '''
Friend Function SetAssociatedEvent(eventSymbol As PEEventSymbol, methodKind As MethodKind) As Boolean - Debug.Assert((methodKind = methodKind.EventAdd) OrElse (methodKind = methodKind.EventRemove) OrElse (methodKind = methodKind.EventRaise)) + Debug.Assert((methodKind = MethodKind.EventAdd) OrElse (methodKind = MethodKind.EventRemove) OrElse (methodKind = MethodKind.EventRaise)) Return Me.SetAssociatedPropertyOrEvent(eventSymbol, methodKind) End Function @@ -1143,6 +1143,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE If Not _packedFlags.IsUseSiteDiagnosticPopulated Then Dim useSiteInfo As UseSiteInfo(Of AssemblySymbol) = CalculateUseSiteInfo() Dim errorInfo As DiagnosticInfo = useSiteInfo.DiagnosticInfo + DeriveCompilerFeatureRequiredUseSiteInfo(errorInfo) EnsureTypeParametersAreLoaded(errorInfo) CheckUnmanagedCallersOnly(errorInfo) Return InitializeUseSiteInfo(useSiteInfo.AdjustDiagnosticInfo(errorInfo)) @@ -1166,6 +1167,41 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE End If End Sub + Private Sub DeriveCompilerFeatureRequiredUseSiteInfo(ByRef errorInfo As DiagnosticInfo) + If errorInfo IsNot Nothing Then + Return + End If + + Dim containingModule = _containingType.ContainingPEModule + Dim decoder As New MetadataDecoder(containingModule, Me) + + errorInfo = DeriveCompilerFeatureRequiredAttributeDiagnostic(Me, DirectCast(containingModule, PEModuleSymbol), Handle, CompilerFeatureRequiredFeatures.None, decoder) + If errorInfo IsNot Nothing Then + Return + End If + + errorInfo = Signature.ReturnParam.DeriveCompilerFeatureRequiredDiagnostic(decoder) + If errorInfo IsNot Nothing Then + Return + End If + + For Each parameter In Parameters + errorInfo = DirectCast(parameter, PEParameterSymbol).DeriveCompilerFeatureRequiredDiagnostic(decoder) + If errorInfo IsNot Nothing Then + Return + End If + Next + + For Each typeParameter In TypeParameters + errorInfo = DirectCast(typeParameter, PETypeParameterSymbol).DeriveCompilerFeatureRequiredDiagnostic(decoder) + If errorInfo IsNot Nothing Then + Return + End If + Next + + errorInfo = _containingType.GetCompilerFeatureRequiredDiagnostic() + End Sub + Private Function InitializeUseSiteInfo(useSiteInfo As UseSiteInfo(Of AssemblySymbol)) As UseSiteInfo(Of AssemblySymbol) If _packedFlags.IsUseSiteDiagnosticPopulated Then Return GetCachedUseSiteInfo() diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEModuleSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEModuleSymbol.vb index 1eeb87e58d3bd..e3b80d4cd247a 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEModuleSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEModuleSymbol.vb @@ -79,6 +79,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Private _lazyTypeNames As ICollection(Of String) Private _lazyNamespaceNames As ICollection(Of String) + Private _lazyCachedCompilerFeatureRequiredDiagnosticInfo As DiagnosticInfo = ErrorFactory.EmptyDiagnosticInfo + Friend Sub New(assemblySymbol As PEAssemblySymbol, [module] As PEModule, importOptions As MetadataImportOptions, ordinal As Integer) Me.New(DirectCast(assemblySymbol, AssemblySymbol), [module], importOptions, ordinal) Debug.Assert(ordinal >= 0) @@ -466,7 +468,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Yield ContainingAssembly.CreateMultipleForwardingErrorTypeSymbol(name, Me, firstSymbol, secondSymbol) Else - Yield firstSymbol.LookupTopLevelMetadataType(name, digThroughForwardedTypes:=true) + Yield firstSymbol.LookupTopLevelMetadataType(name, digThroughForwardedTypes:=True) End If Next End Function @@ -484,5 +486,28 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Public Overrides Function GetMetadata() As ModuleMetadata Return _module.GetNonDisposableMetadata() End Function + + Friend Function GetCompilerFeatureRequiredDiagnostic() As DiagnosticInfo + If _lazyCachedCompilerFeatureRequiredDiagnosticInfo Is ErrorFactory.EmptyDiagnosticInfo Then + Interlocked.CompareExchange( + _lazyCachedCompilerFeatureRequiredDiagnosticInfo, + DeriveCompilerFeatureRequiredAttributeDiagnostic(Me, Me, EntityHandle.ModuleDefinition, CompilerFeatureRequiredFeatures.None, New MetadataDecoder(Me)), + ErrorFactory.EmptyDiagnosticInfo) + End If + + Return If(_lazyCachedCompilerFeatureRequiredDiagnosticInfo, + TryCast(ContainingAssembly, PEAssemblySymbol)?.GetCompilerFeatureRequiredDiagnosticInfo()) + End Function + + Public Overrides ReadOnly Property HasUnsupportedMetadata As Boolean + Get + Dim info = GetCompilerFeatureRequiredDiagnostic() + If info IsNot Nothing Then + Return info.Code = DirectCast(ERRID.ERR_UnsupportedCompilerFeature, Integer) OrElse MyBase.HasUnsupportedMetadata + End If + + Return MyBase.HasUnsupportedMetadata + End Get + End Property End Class End Namespace diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PENamedTypeSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PENamedTypeSymbol.vb index 26f53df3b08ee..66e1b5ce8715b 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PENamedTypeSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PENamedTypeSymbol.vb @@ -164,7 +164,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE End If If makeBad OrElse metadataArity < containerMetadataArity Then - _lazyCachedUseSiteInfo.Initialize(ErrorFactory.ErrorInfo(ERRID.ERR_UnsupportedType1, Me)) + _lazyCachedUseSiteInfo.Initialize(If(DeriveCompilerFeatureRequiredDiagnostic(), ErrorFactory.ErrorInfo(ERRID.ERR_UnsupportedType1, Me))) End If Debug.Assert(Not _mangleName OrElse _name.Length < name.Length) @@ -1274,6 +1274,13 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE End Function Private Function CalculateUseSiteInfoImpl() As UseSiteInfo(Of AssemblySymbol) + ' GetCompilerFeatureRequiredDiagnostic depends on this being the highest priority use-site diagnostic. If another + ' diagnostic was calculated first and cached, it will return incorrect results and assert in Debug mode. + Dim compilerFeatureRequiredDiagnostic = DeriveCompilerFeatureRequiredDiagnostic() + If compilerFeatureRequiredDiagnostic IsNot Nothing Then + Return New UseSiteInfo(Of AssemblySymbol)(compilerFeatureRequiredDiagnostic) + End If + Dim useSiteInfo = CalculateUseSiteInfo() If useSiteInfo.DiagnosticInfo Is Nothing Then @@ -1318,6 +1325,39 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Return useSiteInfo End Function + Friend Function GetCompilerFeatureRequiredDiagnostic() As DiagnosticInfo + Dim typeUseSiteInfo = GetUseSiteInfo() + If typeUseSiteInfo.DiagnosticInfo?.Code = ERRID.ERR_UnsupportedCompilerFeature Then + Return typeUseSiteInfo.DiagnosticInfo + End If + + Debug.Assert(DeriveCompilerFeatureRequiredDiagnostic() Is Nothing) + + Return Nothing + End Function + + Private Function DeriveCompilerFeatureRequiredDiagnostic() As DiagnosticInfo + Dim decoder = New MetadataDecoder(ContainingPEModule, Me) + + Dim diagnostic = DeriveCompilerFeatureRequiredAttributeDiagnostic(Me, ContainingPEModule, Handle, CompilerFeatureRequiredFeatures.None, decoder) + + If diagnostic IsNot Nothing Then + Return diagnostic + End If + + For Each typeParameter In TypeParameters + diagnostic = DirectCast(typeParameter, PETypeParameterSymbol).DeriveCompilerFeatureRequiredDiagnostic(decoder) + + If diagnostic IsNot Nothing Then + Return diagnostic + End If + Next + + Dim containingPEType = TryCast(ContainingType, PENamedTypeSymbol) + + Return If(containingPEType IsNot Nothing, containingPEType.GetCompilerFeatureRequiredDiagnostic(), ContainingPEModule.GetCompilerFeatureRequiredDiagnostic()) + End Function + ''' ''' Return true if the type parameters specified on the nested type (Me), ''' that represent the corresponding type parameters on the containing diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEParameterSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEParameterSymbol.vb index 21b1018a09ebd..8865007dbdcb9 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEParameterSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEParameterSymbol.vb @@ -655,5 +655,23 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Return DirectCast(_containingSymbol.ContainingModule, PEModuleSymbol).Module End Get End Property + + Friend Function DeriveCompilerFeatureRequiredDiagnostic(decoder As MetadataDecoder) As DiagnosticInfo + Return DeriveCompilerFeatureRequiredAttributeDiagnostic(Me, DirectCast(Me.ContainingModule, PEModuleSymbol), Handle, CompilerFeatureRequiredFeatures.None, decoder) + End Function + + Public Overrides ReadOnly Property HasUnsupportedMetadata As Boolean + Get + Dim containingModule = DirectCast(Me.ContainingModule, PEModuleSymbol) + Dim containingMethod = TryCast(Me.ContainingSymbol, PEMethodSymbol) + Dim decoder = If(containingMethod IsNot Nothing, + New MetadataDecoder(containingModule, containingMethod), + New MetadataDecoder(containingModule, DirectCast(ContainingType, PENamedTypeSymbol))) + + Dim info = DeriveCompilerFeatureRequiredDiagnostic(decoder) + + Return (info IsNot Nothing AndAlso (info.Code = ERRID.ERR_UnsupportedType1 OrElse info.Code = ERRID.ERR_UnsupportedCompilerFeature)) OrElse MyBase.HasUnsupportedMetadata + End Get + End Property End Class End Namespace diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEPropertySymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEPropertySymbol.vb index 7756a63151118..6a12ecc276166 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEPropertySymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEPropertySymbol.vb @@ -545,12 +545,43 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Dim primaryDependency As AssemblySymbol = Me.PrimaryDependency If Not _lazyCachedUseSiteInfo.IsInitialized Then - _lazyCachedUseSiteInfo.Initialize(primaryDependency, CalculateUseSiteInfo()) + Dim useSiteInfo As UseSiteInfo(Of AssemblySymbol) = CalculateUseSiteInfo() + Dim errorInfo = useSiteInfo.DiagnosticInfo + DeriveCompilerFeatureRequiredDiagnostic(errorInfo) + _lazyCachedUseSiteInfo.Initialize(primaryDependency, useSiteInfo.AdjustDiagnosticInfo(errorInfo)) End If Return _lazyCachedUseSiteInfo.ToUseSiteInfo(primaryDependency) End Function + Private Sub DeriveCompilerFeatureRequiredDiagnostic(ByRef errorInfo As DiagnosticInfo) + If errorInfo IsNot Nothing Then + Return + End If + + Dim containingModule = _containingType.ContainingPEModule + Dim decoder = New MetadataDecoder(containingModule, _containingType) + errorInfo = DeriveCompilerFeatureRequiredAttributeDiagnostic( + Me, + containingModule, + Handle, + CompilerFeatureRequiredFeatures.None, + decoder) + + If errorInfo IsNot Nothing Then + Return + End If + + For Each param In Parameters + errorInfo = DirectCast(param, PEParameterSymbol).DeriveCompilerFeatureRequiredDiagnostic(decoder) + If errorInfo IsNot Nothing Then + Return + End If + Next + + errorInfo = _containingType.GetCompilerFeatureRequiredDiagnostic() + End Sub + Friend ReadOnly Property Handle As PropertyDefinitionHandle Get Return _handle diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PETypeParameterSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PETypeParameterSymbol.vb index 175d97bab669a..1ecc93c7051df 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PETypeParameterSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PETypeParameterSymbol.vb @@ -284,7 +284,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Dim useSiteInfo As New UseSiteInfo(Of AssemblySymbol)(primaryDependency) For Each pair In diagnosticsBuilder - useSiteInfo = MergeUseSiteInfo(useSiteInfo, pair.UseSiteInfo) + MergeUseSiteInfo(useSiteInfo, pair.UseSiteInfo) If useSiteInfo.DiagnosticInfo IsNot Nothing Then Exit For End If @@ -305,6 +305,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE Return _lazyCachedBoundsUseSiteInfo.ToUseSiteInfo(PrimaryDependency) End Function + Friend Function DeriveCompilerFeatureRequiredDiagnostic(decoder As MetadataDecoder) As DiagnosticInfo + Return DeriveCompilerFeatureRequiredAttributeDiagnostic(Me, DirectCast(ContainingModule, PEModuleSymbol), Handle, CompilerFeatureRequiredFeatures.None, decoder) + End Function + ''' ''' This is for perf, not for correctness. ''' @@ -314,6 +318,19 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE End Get End Property + Public Overrides ReadOnly Property HasUnsupportedMetadata As Boolean + Get + Dim containingModule = DirectCast(Me.ContainingModule, PEModuleSymbol) + Dim containingMethod = TryCast(Me.ContainingSymbol, PEMethodSymbol) + Dim decoder = If(containingMethod IsNot Nothing, + New MetadataDecoder(containingModule, containingMethod), + New MetadataDecoder(containingModule, DirectCast(ContainingSymbol, PENamedTypeSymbol))) + Dim info As DiagnosticInfo = DeriveCompilerFeatureRequiredDiagnostic(decoder) + + Return info IsNot Nothing AndAlso info.Code = DirectCast(ERRID.ERR_UnsupportedCompilerFeature, Integer) OrElse MyBase.HasUnsupportedMetadata + End Get + End Property + End Class End Namespace diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEUtilities.vb b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEUtilities.vb new file mode 100644 index 0000000000000..aca8e9c580f3e --- /dev/null +++ b/src/Compilers/VisualBasic/Portable/Symbols/Metadata/PE/PEUtilities.vb @@ -0,0 +1,18 @@ +' 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. + +Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE + Module PEUtilities + + Friend Function DeriveCompilerFeatureRequiredAttributeDiagnostic(symbol As Symbol, [module] As PEModuleSymbol, handle As System.Reflection.Metadata.EntityHandle, allowedFeatures As CompilerFeatureRequiredFeatures, decoder As MetadataDecoder) As DiagnosticInfo + Dim unsupportedFeature = [module].Module.GetFirstUnsupportedCompilerFeatureFromToken(handle, decoder, allowedFeatures) + If unsupportedFeature IsNot Nothing Then + ' '{0}' requires compiler feature '{1}', which is not supported by this version of the Visual Basic compiler. + Return ErrorFactory.ErrorInfo(ERRID.ERR_UnsupportedCompilerFeature, symbol, unsupportedFeature) + Else + Return Nothing + End If + End Function + End Module +End Namespace diff --git a/src/Compilers/VisualBasic/Portable/Symbols/MethodSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/MethodSymbol.vb index e0e2004668807..b4281e0f81983 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/MethodSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/MethodSymbol.vb @@ -633,36 +633,33 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Debug.Assert(IsDefinition) ' Check return type. - Dim useSiteInfo As UseSiteInfo(Of AssemblySymbol) = MergeUseSiteInfo(New UseSiteInfo(Of AssemblySymbol)(Me.PrimaryDependency), DeriveUseSiteInfoFromType(Me.ReturnType)) + Dim useSiteInfo As UseSiteInfo(Of AssemblySymbol) = New UseSiteInfo(Of AssemblySymbol)(Me.PrimaryDependency) - If useSiteInfo.DiagnosticInfo?.Code = ERRID.ERR_UnsupportedMethod1 Then + If MergeUseSiteInfo(useSiteInfo, DeriveUseSiteInfoFromType(Me.ReturnType)) Then Return useSiteInfo End If ' Check return type custom modifiers. Dim refModifiersUseSiteInfo = DeriveUseSiteInfoFromCustomModifiers(Me.RefCustomModifiers) - If refModifiersUseSiteInfo.DiagnosticInfo?.Code = ERRID.ERR_UnsupportedMethod1 Then - Return refModifiersUseSiteInfo + If MergeUseSiteInfo(useSiteInfo, refModifiersUseSiteInfo) Then + Return useSiteInfo End If Dim typeModifiersUseSiteInfo = DeriveUseSiteInfoFromCustomModifiers(Me.ReturnTypeCustomModifiers, allowIsExternalInit:=IsInitOnly) - If typeModifiersUseSiteInfo.DiagnosticInfo?.Code = ERRID.ERR_UnsupportedMethod1 Then - Return typeModifiersUseSiteInfo + If MergeUseSiteInfo(useSiteInfo, typeModifiersUseSiteInfo) Then + Return useSiteInfo End If ' Check parameters. Dim parametersUseSiteInfo = DeriveUseSiteInfoFromParameters(Me.Parameters) - If parametersUseSiteInfo.DiagnosticInfo?.Code = ERRID.ERR_UnsupportedMethod1 Then - Return parametersUseSiteInfo + If MergeUseSiteInfo(useSiteInfo, parametersUseSiteInfo) Then + Return useSiteInfo End If - Dim errorInfo As DiagnosticInfo = If(useSiteInfo.DiagnosticInfo, - If(refModifiersUseSiteInfo.DiagnosticInfo, - If(typeModifiersUseSiteInfo.DiagnosticInfo, - parametersUseSiteInfo.DiagnosticInfo))) + Dim errorInfo As DiagnosticInfo = useSiteInfo.DiagnosticInfo ' If the member is in an assembly with unified references, ' we check if its definition depends on a type from a unified reference. @@ -694,16 +691,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols ''' ''' Return error code that has highest priority while calculating use site error for this symbol. ''' - Protected Overrides ReadOnly Property HighestPriorityUseSiteError As Integer - Get - Return ERRID.ERR_UnsupportedMethod1 - End Get - End Property + Protected Overrides Function IsHighestPriorityUseSiteError(code As Integer) As Boolean + Return code = ERRID.ERR_UnsupportedMethod1 OrElse code = ERRID.ERR_UnsupportedCompilerFeature + End Function Public NotOverridable Overrides ReadOnly Property HasUnsupportedMetadata As Boolean Get Dim info As DiagnosticInfo = GetUseSiteInfo().DiagnosticInfo - Return info IsNot Nothing AndAlso info.Code = ERRID.ERR_UnsupportedMethod1 + Return info IsNot Nothing AndAlso (info.Code = ERRID.ERR_UnsupportedMethod1 OrElse info.Code = ERRID.ERR_UnsupportedCompilerFeature) End Get End Property diff --git a/src/Compilers/VisualBasic/Portable/Symbols/NamedTypeSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/NamedTypeSymbol.vb index 2e4a4604268ca..77b23983ca0b2 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/NamedTypeSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/NamedTypeSymbol.vb @@ -995,14 +995,15 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols ' Check definition. Dim definitionUseSiteInfo As UseSiteInfo(Of AssemblySymbol) = DeriveUseSiteInfoFromType(Me.OriginalDefinition) - If definitionUseSiteInfo.DiagnosticInfo?.Code = ERRID.ERR_UnsupportedType1 Then + If definitionUseSiteInfo.DiagnosticInfo IsNot Nothing AndAlso IsHighestPriorityUseSiteError(definitionUseSiteInfo.DiagnosticInfo.Code) Then Return definitionUseSiteInfo End If ' Check type arguments. Dim argsUseSiteInfo As UseSiteInfo(Of AssemblySymbol) = DeriveUseSiteInfoFromTypeArguments() - Return MergeUseSiteInfo(definitionUseSiteInfo, argsUseSiteInfo) + MergeUseSiteInfo(definitionUseSiteInfo, argsUseSiteInfo) + Return definitionUseSiteInfo End Function Private Function DeriveUseSiteInfoFromTypeArguments() As UseSiteInfo(Of AssemblySymbol) @@ -1011,14 +1012,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Do For Each arg As TypeSymbol In currentType.TypeArgumentsNoUseSiteDiagnostics - If MergeUseSiteInfo(argsUseSiteInfo, DeriveUseSiteInfoFromType(arg), ERRID.ERR_UnsupportedType1) Then + If MergeUseSiteInfo(argsUseSiteInfo, DeriveUseSiteInfoFromType(arg)) Then Return argsUseSiteInfo End If Next If currentType.HasTypeArgumentsCustomModifiers Then For i As Integer = 0 To Me.Arity - 1 - If MergeUseSiteInfo(argsUseSiteInfo, DeriveUseSiteInfoFromCustomModifiers(Me.GetTypeArgumentCustomModifiers(i)), ERRID.ERR_UnsupportedType1) Then + If MergeUseSiteInfo(argsUseSiteInfo, DeriveUseSiteInfoFromCustomModifiers(Me.GetTypeArgumentCustomModifiers(i))) Then Return argsUseSiteInfo End If Next diff --git a/src/Compilers/VisualBasic/Portable/Symbols/ObsoleteAttributeHelpers.vb b/src/Compilers/VisualBasic/Portable/Symbols/ObsoleteAttributeHelpers.vb index a6eeb6ec76e1e..12411f11b7d10 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/ObsoleteAttributeHelpers.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/ObsoleteAttributeHelpers.vb @@ -33,7 +33,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Friend Shared Function GetObsoleteDataFromMetadata(token As EntityHandle, containingModule As PEModuleSymbol) As ObsoleteAttributeData Dim obsoleteAttributeData As ObsoleteAttributeData = Nothing ' ignoreByRefLikeMarker := False, since VB does not support ref-like types - obsoleteAttributeData = containingModule.Module.TryGetDeprecatedOrExperimentalOrObsoleteAttribute(token, New MetadataDecoder(containingModule), ignoreByRefLikeMarker:=False) + ' https://github.com/dotnet/roslyn/issues/61435: Determine what support will be added for VB + obsoleteAttributeData = containingModule.Module.TryGetDeprecatedOrExperimentalOrObsoleteAttribute(token, New MetadataDecoder(containingModule), ignoreByRefLikeMarker:=False, ignoreRequiredMemberMarker:=False) Debug.Assert(obsoleteAttributeData Is Nothing OrElse Not obsoleteAttributeData.IsUninitialized) Return obsoleteAttributeData End Function diff --git a/src/Compilers/VisualBasic/Portable/Symbols/ParameterSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/ParameterSymbol.vb index 632da5069692e..b446c8cd44acc 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/ParameterSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/ParameterSymbol.vb @@ -276,16 +276,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols ''' Friend MustOverride ReadOnly Property CallerArgumentExpressionParameterIndex As Integer - Protected Overrides ReadOnly Property HighestPriorityUseSiteError As Integer - Get - Return ERRID.ERR_UnsupportedType1 - End Get - End Property + Protected Overrides Function IsHighestPriorityUseSiteError(code As Integer) As Boolean + Return code = ERRID.ERR_UnsupportedType1 OrElse code = ERRID.ERR_UnsupportedCompilerFeature + End Function - Public NotOverridable Overrides ReadOnly Property HasUnsupportedMetadata As Boolean + Public Overrides ReadOnly Property HasUnsupportedMetadata As Boolean Get - Dim info As DiagnosticInfo = DeriveUseSiteInfoFromParameter(Me, HighestPriorityUseSiteError).DiagnosticInfo - Return info IsNot Nothing AndAlso info.Code = ERRID.ERR_UnsupportedType1 + Dim info As DiagnosticInfo = DeriveUseSiteInfoFromParameter(Me).DiagnosticInfo + Return info IsNot Nothing AndAlso (info.Code = ERRID.ERR_UnsupportedType1 OrElse info.Code = ERRID.ERR_UnsupportedCompilerFeature) End Get End Property diff --git a/src/Compilers/VisualBasic/Portable/Symbols/PropertySymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/PropertySymbol.vb index 857d89fc10f57..3e4a04375b2f1 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/PropertySymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/PropertySymbol.vb @@ -404,36 +404,33 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols Debug.Assert(IsDefinition) ' Check return type. - Dim useSiteInfo As UseSiteInfo(Of AssemblySymbol) = MergeUseSiteInfo(New UseSiteInfo(Of AssemblySymbol)(Me.PrimaryDependency), DeriveUseSiteInfoFromType(Me.Type)) + Dim useSiteInfo As UseSiteInfo(Of AssemblySymbol) = New UseSiteInfo(Of AssemblySymbol)(Me.PrimaryDependency) - If useSiteInfo.DiagnosticInfo?.Code = ERRID.ERR_UnsupportedProperty1 Then + If MergeUseSiteInfo(useSiteInfo, DeriveUseSiteInfoFromType(Me.Type)) Then Return useSiteInfo End If ' Check return type custom modifiers. Dim refModifiersUseSiteInfo = DeriveUseSiteInfoFromCustomModifiers(Me.RefCustomModifiers) - If refModifiersUseSiteInfo.DiagnosticInfo?.Code = ERRID.ERR_UnsupportedProperty1 Then - Return refModifiersUseSiteInfo + If MergeUseSiteInfo(useSiteInfo, refModifiersUseSiteInfo) Then + Return useSiteInfo End If Dim typeModifiersUseSiteInfo = DeriveUseSiteInfoFromCustomModifiers(Me.TypeCustomModifiers) - If typeModifiersUseSiteInfo.DiagnosticInfo?.Code = ERRID.ERR_UnsupportedProperty1 Then - Return typeModifiersUseSiteInfo + If MergeUseSiteInfo(useSiteInfo, typeModifiersUseSiteInfo) Then + Return useSiteInfo End If ' Check parameters. Dim parametersUseSiteInfo = DeriveUseSiteInfoFromParameters(Me.Parameters) - If parametersUseSiteInfo.DiagnosticInfo?.Code = ERRID.ERR_UnsupportedProperty1 Then - Return parametersUseSiteInfo + If MergeUseSiteInfo(useSiteInfo, parametersUseSiteInfo) Then + Return useSiteInfo End If - Dim errorInfo As DiagnosticInfo = If(useSiteInfo.DiagnosticInfo, - If(refModifiersUseSiteInfo.DiagnosticInfo, - If(typeModifiersUseSiteInfo.DiagnosticInfo, - parametersUseSiteInfo.DiagnosticInfo))) + Dim errorInfo As DiagnosticInfo = useSiteInfo.DiagnosticInfo ' If the member is in an assembly with unified references, ' we check if its definition depends on a type from a unified reference. @@ -464,16 +461,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols ''' ''' Return error code that has highest priority while calculating use site error for this symbol. ''' - Protected Overrides ReadOnly Property HighestPriorityUseSiteError As Integer - Get - Return ERRID.ERR_UnsupportedProperty1 - End Get - End Property + Protected Overrides Function IsHighestPriorityUseSiteError(code As Integer) As Boolean + Return code = ERRID.ERR_UnsupportedProperty1 OrElse code = ERRID.ERR_UnsupportedCompilerFeature + End Function Public NotOverridable Overrides ReadOnly Property HasUnsupportedMetadata As Boolean Get Dim info As DiagnosticInfo = GetUseSiteInfo().DiagnosticInfo - Return info IsNot Nothing AndAlso info.Code = ERRID.ERR_UnsupportedProperty1 + Return info IsNot Nothing AndAlso (info.Code = ERRID.ERR_UnsupportedProperty1 OrElse info.Code = ERRID.ERR_UnsupportedCompilerFeature) End Get End Property @@ -577,6 +572,12 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols End Get End Property + Private ReadOnly Property IPropertySymbol_IsRequired As Boolean Implements IPropertySymbol.IsRequired + Get + Return False + End Get + End Property + Private ReadOnly Property IPropertySymbol_ReturnsByRef As Boolean Implements IPropertySymbol.ReturnsByRef Get Return Me.ReturnsByRef diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Symbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/Symbol.vb index 22fec68b94238..ce1970087765d 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Symbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Symbol.vb @@ -946,21 +946,14 @@ Namespace Microsoft.CodeAnalysis.VisualBasic End Sub ''' - ''' Return error code that has highest priority while calculating use site error for this symbol. + ''' Returns true if the error code is highest priority while calculating use site error for this symbol. ''' - Protected Overridable ReadOnly Property HighestPriorityUseSiteError As Integer ' Supposed to be ERRID, but it causes inconsistent accessibility error. - Get - Return Integer.MaxValue - End Get - End Property - - Friend Function MergeUseSiteInfo(first As UseSiteInfo(Of AssemblySymbol), second As UseSiteInfo(Of AssemblySymbol)) As UseSiteInfo(Of AssemblySymbol) - MergeUseSiteInfo(first, second, HighestPriorityUseSiteError) - Return first + Protected Overridable Function IsHighestPriorityUseSiteError(code As Integer) As Boolean ' Supposed to be ERRID, but it causes inconsistent accessibility error. + Return False End Function - Friend Shared Function MergeUseSiteInfo(ByRef result As UseSiteInfo(Of AssemblySymbol), other As UseSiteInfo(Of AssemblySymbol), highestPriorityUseSiteError As Integer) As Boolean - If other.DiagnosticInfo?.Code = highestPriorityUseSiteError Then + Friend Function MergeUseSiteInfo(ByRef result As UseSiteInfo(Of AssemblySymbol), other As UseSiteInfo(Of AssemblySymbol)) As Boolean + If other.DiagnosticInfo IsNot Nothing AndAlso IsHighestPriorityUseSiteError(other.DiagnosticInfo.Code) Then result = other Return True End If @@ -978,26 +971,26 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Return False Else - Return result.DiagnosticInfo.Code = highestPriorityUseSiteError + Return IsHighestPriorityUseSiteError(result.DiagnosticInfo.Code) End If End Function - Friend Function DeriveUseSiteInfoFromParameter(param As ParameterSymbol, highestPriorityUseSiteError As Integer) As UseSiteInfo(Of AssemblySymbol) + Friend Function DeriveUseSiteInfoFromParameter(param As ParameterSymbol) As UseSiteInfo(Of AssemblySymbol) Dim useSiteInfo As UseSiteInfo(Of AssemblySymbol) = DeriveUseSiteInfoFromType(param.Type) - If useSiteInfo.DiagnosticInfo?.Code = highestPriorityUseSiteError Then + If useSiteInfo.DiagnosticInfo IsNot Nothing AndAlso IsHighestPriorityUseSiteError(useSiteInfo.DiagnosticInfo.Code) Then Return useSiteInfo End If Dim refModifiersUseSiteInfo As UseSiteInfo(Of AssemblySymbol) = DeriveUseSiteInfoFromCustomModifiers(param.RefCustomModifiers) - If refModifiersUseSiteInfo.DiagnosticInfo?.Code = highestPriorityUseSiteError Then + If refModifiersUseSiteInfo.DiagnosticInfo IsNot Nothing AndAlso IsHighestPriorityUseSiteError(refModifiersUseSiteInfo.DiagnosticInfo.Code) Then Return refModifiersUseSiteInfo End If Dim modifiersUseSiteInfo As UseSiteInfo(Of AssemblySymbol) = DeriveUseSiteInfoFromCustomModifiers(param.CustomModifiers) - If modifiersUseSiteInfo.DiagnosticInfo?.Code = highestPriorityUseSiteError Then + If modifiersUseSiteInfo.DiagnosticInfo IsNot Nothing AndAlso IsHighestPriorityUseSiteError(modifiersUseSiteInfo.DiagnosticInfo.Code) Then Return modifiersUseSiteInfo End If @@ -1019,10 +1012,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Friend Function DeriveUseSiteInfoFromParameters(parameters As ImmutableArray(Of ParameterSymbol)) As UseSiteInfo(Of AssemblySymbol) Dim paramsUseSiteInfo As UseSiteInfo(Of AssemblySymbol) = Nothing - Dim highestPriorityUseSiteError As Integer = Me.HighestPriorityUseSiteError For Each param As ParameterSymbol In parameters - If MergeUseSiteInfo(paramsUseSiteInfo, DeriveUseSiteInfoFromParameter(param, highestPriorityUseSiteError), highestPriorityUseSiteError) Then + If MergeUseSiteInfo(paramsUseSiteInfo, DeriveUseSiteInfoFromParameter(param)) Then Exit For End If Next @@ -1035,7 +1027,6 @@ Namespace Microsoft.CodeAnalysis.VisualBasic Optional allowIsExternalInit As Boolean = False ) As UseSiteInfo(Of AssemblySymbol) Dim modifiersUseSiteInfo As UseSiteInfo(Of AssemblySymbol) = Nothing - Dim highestPriorityUseSiteError As Integer = Me.HighestPriorityUseSiteError For Each modifier As CustomModifier In customModifiers Dim useSiteInfo As UseSiteInfo(Of AssemblySymbol) @@ -1046,7 +1037,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic useSiteInfo = New UseSiteInfo(Of AssemblySymbol)(ErrorFactory.ErrorInfo(ERRID.ERR_UnsupportedType1, String.Empty)) GetSymbolSpecificUnsupportedMetadataUseSiteErrorInfo(useSiteInfo) - If MergeUseSiteInfo(modifiersUseSiteInfo, useSiteInfo, highestPriorityUseSiteError) Then + If MergeUseSiteInfo(modifiersUseSiteInfo, useSiteInfo) Then Exit For End If End If @@ -1054,7 +1045,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic useSiteInfo = DeriveUseSiteInfoFromType(DirectCast(modifier, VisualBasicCustomModifier).ModifierSymbol) - If MergeUseSiteInfo(modifiersUseSiteInfo, useSiteInfo, highestPriorityUseSiteError) Then + If MergeUseSiteInfo(modifiersUseSiteInfo, useSiteInfo) Then Exit For End If Next diff --git a/src/Compilers/VisualBasic/Portable/Symbols/Symbol_Attributes.vb b/src/Compilers/VisualBasic/Portable/Symbols/Symbol_Attributes.vb index 860b150e5b5b9..accc2a1242633 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/Symbol_Attributes.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/Symbol_Attributes.vb @@ -197,6 +197,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic If arguments.Attribute.IsTargetAttribute(Me, AttributeDescription.SkipLocalsInitAttribute) Then DirectCast(arguments.Diagnostics, BindingDiagnosticBag).Add(ERRID.WRN_AttributeNotSupportedInVB, arguments.AttributeSyntaxOpt.Location, AttributeDescription.SkipLocalsInitAttribute.FullName) + ElseIf arguments.Attribute.IsTargetAttribute(Me, AttributeDescription.CompilerFeatureRequiredAttribute) Then + DirectCast(arguments.Diagnostics, BindingDiagnosticBag).Add(ERRID.ERR_DoNotUseCompilerFeatureRequired, arguments.AttributeSyntaxOpt.Location) End If End Sub diff --git a/src/Compilers/VisualBasic/Portable/Symbols/TypeSymbol.vb b/src/Compilers/VisualBasic/Portable/Symbols/TypeSymbol.vb index e4d95b74e5600..6b264e8d829f9 100644 --- a/src/Compilers/VisualBasic/Portable/Symbols/TypeSymbol.vb +++ b/src/Compilers/VisualBasic/Portable/Symbols/TypeSymbol.vb @@ -513,16 +513,14 @@ Done: ''' ''' Return error code that has highest priority while calculating use site error for this symbol. ''' - Protected Overrides ReadOnly Property HighestPriorityUseSiteError As Integer - Get - Return ERRID.ERR_UnsupportedType1 - End Get - End Property + Protected Overrides Function IsHighestPriorityUseSiteError(code As Integer) As Boolean + Return code = ERRID.ERR_UnsupportedType1 OrElse code = ERRID.ERR_UnsupportedCompilerFeature + End Function - Public NotOverridable Overrides ReadOnly Property HasUnsupportedMetadata As Boolean + Public Overrides ReadOnly Property HasUnsupportedMetadata As Boolean Get Dim info As DiagnosticInfo = GetUseSiteInfo().DiagnosticInfo - Return info IsNot Nothing AndAlso info.Code = ERRID.ERR_UnsupportedType1 + Return info IsNot Nothing AndAlso (info.Code = ERRID.ERR_UnsupportedType1 OrElse info.Code = ERRID.ERR_UnsupportedCompilerFeature) End Get End Property diff --git a/src/Compilers/VisualBasic/Portable/VBResources.resx b/src/Compilers/VisualBasic/Portable/VBResources.resx index ddc50375ced3d..88b1c456310b2 100644 --- a/src/Compilers/VisualBasic/Portable/VBResources.resx +++ b/src/Compilers/VisualBasic/Portable/VBResources.resx @@ -5650,4 +5650,10 @@ {0} '{1}' cannot implement interface '{3}' because it contains shared abstract or virtual '{2}'. - + + '{0}' requires compiler feature '{1}', which is not supported by this version of the Visual Basic compiler. + + + 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute' is reserved for compiler usage only. + + \ No newline at end of file diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.cs.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.cs.xlf index 4f727b95692a5..d79bad69eb7db 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.cs.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.cs.xlf @@ -27,6 +27,11 @@ Typ {0} nemůže být vložený, protože má neabstraktní člen. Zvažte nastavení vlastnosti Vložit typy spolupráce na hodnotu false. + + 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute' is reserved for compiler usage only. + 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute' is reserved for compiler usage only. + + Multiple analyzer config files cannot be in the same directory ('{0}'). Ve stejném adresáři nemůže být více konfiguračních souborů analyzátoru ({0}). @@ -72,6 +77,11 @@ Atribut UnmanagedCallersOnly se nepodporuje. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the Visual Basic compiler. + '{0}' requires compiler feature '{1}', which is not supported by this version of the Visual Basic compiler. + + caller argument expression výraz argumentu volajícího diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.de.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.de.xlf index 1f2f27dde2ae5..c130472905343 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.de.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.de.xlf @@ -27,6 +27,11 @@ Der Typ "{0}" kann nicht eingebettet werden, weil er einen nicht abstrakten Member aufweist. Legen Sie die Eigenschaft "Interoptypen einbetten" ggf. auf FALSE fest. + + 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute' is reserved for compiler usage only. + 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute' is reserved for compiler usage only. + + Multiple analyzer config files cannot be in the same directory ('{0}'). Dasselbe Verzeichnis ({0}) darf nicht mehrere Konfigurationsdateien des Analysetools enthalten. @@ -72,6 +77,11 @@ Das Attribut "UnmanagedCallersOnly" wird nicht unterstützt. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the Visual Basic compiler. + '{0}' requires compiler feature '{1}', which is not supported by this version of the Visual Basic compiler. + + caller argument expression Aufruferargumentausdruck diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.es.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.es.xlf index 71a8e098e538b..53d192e23a74c 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.es.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.es.xlf @@ -27,6 +27,11 @@ El tipo "{0}" no se puede incrustar porque tiene un miembro no abstracto. Puede establecer la propiedad "Incrustar tipos de interoperabilidad" en false. + + 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute' is reserved for compiler usage only. + 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute' is reserved for compiler usage only. + + Multiple analyzer config files cannot be in the same directory ('{0}'). No es posible que un mismo directorio ("{0}") contenga varios archivos de configuración del analizador. @@ -72,6 +77,11 @@ No se admite el atributo "UnmanagedCallersOnly". + + '{0}' requires compiler feature '{1}', which is not supported by this version of the Visual Basic compiler. + '{0}' requires compiler feature '{1}', which is not supported by this version of the Visual Basic compiler. + + caller argument expression expresión de argumento de autor de llamada diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.fr.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.fr.xlf index e4767346a5d1e..d80659dcbe299 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.fr.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.fr.xlf @@ -27,6 +27,11 @@ Impossible d'incorporer le type '{0}', car il a un membre non abstrait. Affectez la valeur false à la propriété 'Incorporer les types interop'. + + 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute' is reserved for compiler usage only. + 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute' is reserved for compiler usage only. + + Multiple analyzer config files cannot be in the same directory ('{0}'). Plusieurs fichiers config d'analyseur ne peuvent pas figurer dans le même répertoire ('{0}'). @@ -72,6 +77,11 @@ L'attribut 'UnmanagedCallersOnly' n'est pas pris en charge. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the Visual Basic compiler. + '{0}' requires compiler feature '{1}', which is not supported by this version of the Visual Basic compiler. + + caller argument expression expression d’argument de l’appelant diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.it.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.it.xlf index fd2a31df9b3d1..b897a4801bf89 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.it.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.it.xlf @@ -27,6 +27,11 @@ Non è possibile incorporare il tipo '{0}' perché contiene un membro non astratto. Provare a impostare la proprietà 'Incorpora tipi di interoperabilità' su false. + + 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute' is reserved for compiler usage only. + 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute' is reserved for compiler usage only. + + Multiple analyzer config files cannot be in the same directory ('{0}'). La stessa directory ('{0}') non può contenere più file di configurazione dell'analizzatore. @@ -72,6 +77,11 @@ L'attributo 'UnmanagedCallersOnly' non è supportato. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the Visual Basic compiler. + '{0}' requires compiler feature '{1}', which is not supported by this version of the Visual Basic compiler. + + caller argument expression espressione passata come argomento del chiamante diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.ja.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.ja.xlf index e2b1817109b0a..333a89fdb4add 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.ja.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.ja.xlf @@ -27,6 +27,11 @@ 型 '{0}' には非抽象メンバーがあるため、この型を埋め込むことはできません。'相互運用型の埋め込み' プロパティを false に設定することをご検討ください。 + + 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute' is reserved for compiler usage only. + 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute' is reserved for compiler usage only. + + Multiple analyzer config files cannot be in the same directory ('{0}'). 複数のアナライザー構成ファイルを同じディレクトリに入れることはできません ('{0}')。 @@ -72,6 +77,11 @@ 'UnmanagedCallersOnly' 属性はサポートされていません。 + + '{0}' requires compiler feature '{1}', which is not supported by this version of the Visual Basic compiler. + '{0}' requires compiler feature '{1}', which is not supported by this version of the Visual Basic compiler. + + caller argument expression 呼び出し元の引数式 diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.ko.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.ko.xlf index 43a937fb41b42..e9b9e3a1d4c40 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.ko.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.ko.xlf @@ -27,6 +27,11 @@ '{0}' 형식에는 비추상 멤버가 있으므로 해당 형식을 포함할 수 없습니다. 'Interop 형식 포함' 속성을 false로 설정해보세요. + + 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute' is reserved for compiler usage only. + 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute' is reserved for compiler usage only. + + Multiple analyzer config files cannot be in the same directory ('{0}'). 분석기 구성 파일 여러 개가 동일한 디렉터리('{0}')에 있을 수 없습니다. @@ -72,6 +77,11 @@ 'UnmanagedCallersOnly' 특성은 지원되지 않습니다. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the Visual Basic compiler. + '{0}' requires compiler feature '{1}', which is not supported by this version of the Visual Basic compiler. + + caller argument expression 호출자 인수 표현식 diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.pl.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.pl.xlf index 8b0e1284b9b05..9183d572e299f 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.pl.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.pl.xlf @@ -27,6 +27,11 @@ Nie można osadzić typu „{0}”, ponieważ ma nieabstrakcyjną składową. Rozważ ustawienie wartości false dla właściwości „Osadź typy międzyoperacyjne”. + + 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute' is reserved for compiler usage only. + 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute' is reserved for compiler usage only. + + Multiple analyzer config files cannot be in the same directory ('{0}'). Wiele plików konfiguracji analizatora nie może znajdować się w tym samym katalogu („{0}”). @@ -72,6 +77,11 @@ Atrybut „UnmanagedCallersOnly” jest nieobsługiwany. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the Visual Basic compiler. + '{0}' requires compiler feature '{1}', which is not supported by this version of the Visual Basic compiler. + + caller argument expression wyrażenie argumentu wywołującego diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.pt-BR.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.pt-BR.xlf index e91263aa51b73..8ec37b0530323 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.pt-BR.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.pt-BR.xlf @@ -27,6 +27,11 @@ O tipo '{0}' não pode ser inserido porque tem um membro que não é abstrato. Considere a definição da propriedade 'Inserir Tipos de Interoperabilidade' como false. + + 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute' is reserved for compiler usage only. + 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute' is reserved for compiler usage only. + + Multiple analyzer config files cannot be in the same directory ('{0}'). Não é possível que haja vários arquivos de configuração do analisador no mesmo diretório ('{0}'). @@ -72,6 +77,11 @@ Não há suporte para o atributo 'UnmanagedCallersOnly'. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the Visual Basic compiler. + '{0}' requires compiler feature '{1}', which is not supported by this version of the Visual Basic compiler. + + caller argument expression expressão do argumento do chamador diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.ru.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.ru.xlf index 8ccd8d8ae8018..b1030e6230aaa 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.ru.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.ru.xlf @@ -27,6 +27,11 @@ Не удается внедрить тип "{0}", так как он имеет неабстрактный член. Попробуйте задать для свойства "Внедрить типы взаимодействия" значение false. + + 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute' is reserved for compiler usage only. + 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute' is reserved for compiler usage only. + + Multiple analyzer config files cannot be in the same directory ('{0}'). В одном каталоге ("{0}") не может находиться несколько файлов конфигурации анализатора. @@ -72,6 +77,11 @@ Атрибут "UnmanagedCallersOnly" не поддерживается. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the Visual Basic compiler. + '{0}' requires compiler feature '{1}', which is not supported by this version of the Visual Basic compiler. + + caller argument expression выражение аргумента вызывающего diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.tr.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.tr.xlf index b315b6e323114..74617aa20bef5 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.tr.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.tr.xlf @@ -27,6 +27,11 @@ '{0}' türünün soyut olmayan bir üyesi olduğundan bu tür eklenemiyor. 'Embed Interop Types' özelliğini false olarak ayarlamayı deneyin. + + 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute' is reserved for compiler usage only. + 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute' is reserved for compiler usage only. + + Multiple analyzer config files cannot be in the same directory ('{0}'). Birden çok çözümleyici yapılandırma dosyası aynı dizinde ('{0}') olamaz. @@ -72,6 +77,11 @@ 'UnmanagedCallersOnly' özniteliği desteklenmez. + + '{0}' requires compiler feature '{1}', which is not supported by this version of the Visual Basic compiler. + '{0}' requires compiler feature '{1}', which is not supported by this version of the Visual Basic compiler. + + caller argument expression çağıran bağımsız değişken ifadesi diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.zh-Hans.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.zh-Hans.xlf index 9f902db122398..f68447a699f22 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.zh-Hans.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.zh-Hans.xlf @@ -27,6 +27,11 @@ 无法嵌入类型“{0}”,因为它有非抽象成员。请考虑将“嵌入互操作类型”属性设置为 false。 + + 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute' is reserved for compiler usage only. + 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute' is reserved for compiler usage only. + + Multiple analyzer config files cannot be in the same directory ('{0}'). 多个分析器配置文件不能位于同一目录({0})中。 @@ -72,6 +77,11 @@ 不支持 "UnmanagedCallersOnly" 属性。 + + '{0}' requires compiler feature '{1}', which is not supported by this version of the Visual Basic compiler. + '{0}' requires compiler feature '{1}', which is not supported by this version of the Visual Basic compiler. + + caller argument expression 调用方参数表达式 diff --git a/src/Compilers/VisualBasic/Portable/xlf/VBResources.zh-Hant.xlf b/src/Compilers/VisualBasic/Portable/xlf/VBResources.zh-Hant.xlf index af7fad4fef316..f05fb08ec4276 100644 --- a/src/Compilers/VisualBasic/Portable/xlf/VBResources.zh-Hant.xlf +++ b/src/Compilers/VisualBasic/Portable/xlf/VBResources.zh-Hant.xlf @@ -27,6 +27,11 @@ 因為類型 '{0}' 有非抽象成員,所以無法內嵌。請考慮將 [內嵌 Interop 類型] 屬性設為 false。 + + 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute' is reserved for compiler usage only. + 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute' is reserved for compiler usage only. + + Multiple analyzer config files cannot be in the same directory ('{0}'). 多個分析器組態檔無法處於相同目錄 ('{0}') 中。 @@ -72,6 +77,11 @@ 不支援 'UnmanagedCallersOnly' 屬性。 + + '{0}' requires compiler feature '{1}', which is not supported by this version of the Visual Basic compiler. + '{0}' requires compiler feature '{1}', which is not supported by this version of the Visual Basic compiler. + + caller argument expression 呼叫者引數運算式 diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/VisualBasicCompilerFeatureRequiredTests.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/VisualBasicCompilerFeatureRequiredTests.vb new file mode 100644 index 0000000000000..f1a9c4e3941c2 --- /dev/null +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/Metadata/PE/VisualBasicCompilerFeatureRequiredTests.vb @@ -0,0 +1,739 @@ +' 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. + +Imports Microsoft.CodeAnalysis +Imports Microsoft.CodeAnalysis.CodeGen +Imports Microsoft.CodeAnalysis.CSharp.UnitTests.Symbols +Imports Microsoft.CodeAnalysis.Test.Utilities +Imports Microsoft.CodeAnalysis.UnitTests +Imports Microsoft.CodeAnalysis.VisualBasic +Imports Microsoft.CodeAnalysis.VisualBasic.Symbols +Imports Microsoft.CodeAnalysis.VisualBasic.UnitTests + +Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests + + Public Class VisualBasicCompilerFeatureRequiredTests + Inherits BaseCompilerFeatureRequiredTests(Of VisualBasicCompilation, XElement) + + Private Class CompilerFeatureRequiredTests_VisualBasic + Inherits BasicTestBase + End Class + + Private ReadOnly _testBase As New CompilerFeatureRequiredTests_VisualBasic() + + Friend Overrides Function VisualizeRealIL(peModule As IModuleSymbol, methodData As CompilationTestData.MethodData, markers As IReadOnlyDictionary(Of Integer, String), areLocalsZeroed As Boolean) As String + Return _testBase.VisualizeRealIL(peModule, methodData, markers, areLocalsZeroed) + End Function + + Protected Overrides Function GetUsage() As XElement + Return + + + + End Function + + Protected Overrides Function CreateCompilationWithIL(source As XElement, ilSource As String) As VisualBasicCompilation + Return CreateCompilationWithCustomILSource(source, ilSource) + End Function + + Protected Overrides Function CreateCompilation(source As XElement, references() As MetadataReference) As VisualBasicCompilation + Return CompilationUtils.CreateCompilation(source, references) + End Function + + Protected Overrides Function CompileAndVerify(compilation As VisualBasicCompilation) As CompilationVerifier + Return _testBase.CompileAndVerify(compilation) + End Function + + Protected Overrides Sub AssertNormalErrors(comp As VisualBasicCompilation) + comp.AssertTheseDiagnostics( + + ) + + Dim onType = comp.GetTypeByMetadataName("OnType") + Assert.True(onType.HasUnsupportedMetadata) + Assert.True(onType.GetMember(Of MethodSymbol)("M").HasUnsupportedMetadata) + + Dim onMethod = comp.GetTypeByMetadataName("OnMethod") + Assert.False(onMethod.HasUnsupportedMetadata) + Assert.True(onMethod.GetMember(Of MethodSymbol)("M").HasUnsupportedMetadata) + + Dim onMethodReturn = comp.GetTypeByMetadataName("OnMethodReturn") + Assert.False(onMethodReturn.HasUnsupportedMetadata) + Assert.True(onMethodReturn.GetMember(Of MethodSymbol)("M").HasUnsupportedMetadata) + + Dim onParameter = comp.GetTypeByMetadataName("OnParameter") + Assert.False(onParameter.HasUnsupportedMetadata) + Dim onParameterMethod = onParameter.GetMember(Of MethodSymbol)("M") + Assert.True(onParameterMethod.HasUnsupportedMetadata) + Assert.True(onParameterMethod.Parameters(0).HasUnsupportedMetadata) + + Dim onField = comp.GetTypeByMetadataName("OnField") + Assert.False(onField.HasUnsupportedMetadata) + Assert.True(onField.GetMember(Of FieldSymbol)("Field").HasUnsupportedMetadata) + + Dim onProperty = comp.GetTypeByMetadataName("OnProperty") + Assert.False(onProperty.HasUnsupportedMetadata) + Assert.True(onProperty.GetMember(Of PropertySymbol)("Property").HasUnsupportedMetadata) + + Dim onPropertyGetter = comp.GetTypeByMetadataName("OnPropertyGetter") + Assert.False(onPropertyGetter.HasUnsupportedMetadata) + Dim onPropertyGetterProperty = onPropertyGetter.GetMember(Of PropertySymbol)("Property") + Assert.False(onPropertyGetterProperty.HasUnsupportedMetadata) + Assert.False(onPropertyGetterProperty.SetMethod.HasUnsupportedMetadata) + Assert.True(onPropertyGetterProperty.GetMethod.HasUnsupportedMetadata) + + Dim onPropertySetter = comp.GetTypeByMetadataName("OnPropertySetter") + Assert.False(onPropertySetter.HasUnsupportedMetadata) + Dim onPropertySetterProperty = onPropertySetter.GetMember(Of PropertySymbol)("Property") + Assert.False(onPropertySetterProperty.HasUnsupportedMetadata) + Assert.True(onPropertySetterProperty.SetMethod.HasUnsupportedMetadata) + Assert.False(onPropertySetterProperty.GetMethod.HasUnsupportedMetadata) + + Dim onEvent = comp.GetTypeByMetadataName("OnEvent") + Assert.False(onEvent.HasUnsupportedMetadata) + Assert.True(onEvent.GetMember(Of EventSymbol)("Event").HasUnsupportedMetadata) + + Dim onEventAdder = comp.GetTypeByMetadataName("OnEventAdder") + Assert.False(onEventAdder.HasUnsupportedMetadata) + Dim onEventAdderEvent = onEventAdder.GetMember(Of EventSymbol)("Event") + Assert.False(onEventAdderEvent.HasUnsupportedMetadata) + Assert.True(onEventAdderEvent.AddMethod.HasUnsupportedMetadata) + Assert.False(onEventAdderEvent.RemoveMethod.HasUnsupportedMetadata) + + Dim onEventRemover = comp.GetTypeByMetadataName("OnEventRemover") + Assert.False(onEventRemover.HasUnsupportedMetadata) + Dim onEventRemoverEvent = onEventRemover.GetMember(Of EventSymbol)("Event") + Assert.False(onEventRemoverEvent.HasUnsupportedMetadata) + Assert.False(onEventRemoverEvent.AddMethod.HasUnsupportedMetadata) + Assert.True(onEventRemoverEvent.RemoveMethod.HasUnsupportedMetadata) + + Dim onEnum = comp.GetTypeByMetadataName("OnEnum") + Assert.True(onEnum.HasUnsupportedMetadata) + + Dim onEnumMember = comp.GetTypeByMetadataName("OnEnumMember") + Assert.False(onEnumMember.HasUnsupportedMetadata) + Assert.True(onEnumMember.GetMember(Of FieldSymbol)("A").HasUnsupportedMetadata) + + Dim onClassTypeParameter = comp.GetTypeByMetadataName("OnClassTypeParameter`1") + Assert.True(onClassTypeParameter.HasUnsupportedMetadata) + Assert.True(onClassTypeParameter.TypeParameters(0).HasUnsupportedMetadata) + + Dim onMethodTypeParameter = comp.GetTypeByMetadataName("OnMethodTypeParameter") + Assert.False(onMethodTypeParameter.HasUnsupportedMetadata) + Dim onMethodTypeParameterMethod = onMethodTypeParameter.GetMember(Of MethodSymbol)("M") + Assert.True(onMethodTypeParameterMethod.HasUnsupportedMetadata) + Assert.True(onMethodTypeParameterMethod.TypeParameters(0).HasUnsupportedMetadata) + + Dim onDelegateType = comp.GetTypeByMetadataName("OnDelegateType") + Assert.True(onDelegateType.HasUnsupportedMetadata) + + Dim onIndexedPropertyParameter = comp.GetTypeByMetadataName("OnIndexedPropertyParameter") + Assert.False(onIndexedPropertyParameter.HasUnsupportedMetadata) + Assert.True(onIndexedPropertyParameter.GetMember(Of MethodSymbol)("get_Property").Parameters(0).HasUnsupportedMetadata) + Assert.True(onIndexedPropertyParameter.GetMember(Of MethodSymbol)("set_Property").Parameters(0).HasUnsupportedMetadata) + + Dim onThisParameterIndexer = comp.GetTypeByMetadataName("OnThisIndexerParameter") + Assert.False(onThisParameterIndexer.HasUnsupportedMetadata) + Dim indexer = onThisParameterIndexer.GetMember(Of PropertySymbol)("Item") + Assert.True(indexer.HasUnsupportedMetadata) + Assert.True(indexer.Parameters(0).HasUnsupportedMetadata) + End Sub + + Protected Overrides Sub AssertModuleErrors(comp As VisualBasicCompilation, ilRef As MetadataReference) + comp.AssertTheseDiagnostics( + + ) + + Assert.True(comp.GetReferencedAssemblySymbol(ilRef).Modules.Single().HasUnsupportedMetadata) + End Sub + + Protected Overrides Sub AssertAssemblyErrors(comp As VisualBasicCompilation, ilRef As MetadataReference) + comp.AssertTheseDiagnostics( + + ) + + Assert.True(comp.GetReferencedAssemblySymbol(ilRef).HasUnsupportedMetadata) + End Sub + + + Public Sub Application() + Dim compilation = CompilationUtils.CreateCompilation( + +Public Class OnType +End Class + +Public Class OnMethod + + Public Sub OnMethod() + End Sub +End Class + +Public Class OnMethodReturn + Public Function OnMethodReturn() As Integer + Return 1 + End Function +End Class + +Public Class OnField + + Public Field As Integer +End Class + +Public Class OnProperty + + Public Property Prop As Integer +End Class + +Public Class OnPropertySetter + Public Property Prop As Integer + Get + Return 1 + End Get + + Set + End Set + End Property +End Class + +Public Class OnPropertyGetter + Public Property Prop As Integer + + Get + Return 1 + End Get + Set + End Set + End Property +End Class + +Public Class OnEvent + + Public Event [Event] As Action +End Class + +Public Class OnEventAdder + Public Custom Event [Event] As Action + + AddHandler(value As Action) + End AddHandler + RemoveHandler(value As Action) + End RemoveHandler + RaiseEvent + End RaiseEvent + End Event +End Class + +Public Class OnEventRemover + Public Custom Event [Event] As Action + AddHandler(value As Action) + End AddHandler + + RemoveHandler(value As Action) + End RemoveHandler + RaiseEvent + End RaiseEvent + End Event +End Class + +Public Class OnEventRaiseEvent + Public Custom Event [Event] As Action + AddHandler(value As Action) + End AddHandler + RemoveHandler(value As Action) + End RemoveHandler + + RaiseEvent + End RaiseEvent + End Event +End Class + + +Public Enum OnEnum + A +End Enum + +Public Enum OnEnumMember + A +End Enum + + +Public Delegate Sub OnDelegate() +]]> + + + + Public Class CompilerFeatureRequiredAttribute + Inherits Attribute + + Public Sub New(featureName As String) + FeatureName = featureName + End Sub + + Public ReadOnly Property FeatureName As String + + Public Property IsOptional As Boolean + End Class +End Namespace +]]> + + + ) + + compilation.AssertTheseDiagnostics( + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +BC37320: 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute' is reserved for compiler usage only. + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +BC37320: 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute' is reserved for compiler usage only. + Public Function OnMethodReturn() As Integer + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +BC37320: 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute' is reserved for compiler usage only. + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +BC37320: 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute' is reserved for compiler usage only. + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +BC37320: 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute' is reserved for compiler usage only. + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +BC37320: 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute' is reserved for compiler usage only. + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +BC37320: 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute' is reserved for compiler usage only. + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +BC37320: 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute' is reserved for compiler usage only. + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +BC37320: 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute' is reserved for compiler usage only. + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +BC37320: 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute' is reserved for compiler usage only. + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +BC37320: 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute' is reserved for compiler usage only. + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +BC37320: 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute' is reserved for compiler usage only. + A + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +BC37320: 'System.Runtime.CompilerServices.CompilerFeatureRequiredAttribute' is reserved for compiler usage only. + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +]]>) + End Sub + End Class +End Namespace diff --git a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/WellKnownTypeValidationTests.vb b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/WellKnownTypeValidationTests.vb index 1b772e94a64f0..ae13c2d50ad69 100644 --- a/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/WellKnownTypeValidationTests.vb +++ b/src/Compilers/VisualBasic/Test/Symbol/SymbolsTests/WellKnownTypeValidationTests.vb @@ -546,7 +546,10 @@ End Namespace WellKnownType.System_Runtime_CompilerServices_NativeIntegerAttribute, WellKnownType.System_Runtime_CompilerServices_IsExternalInit, WellKnownType.System_Runtime_CompilerServices_DefaultInterpolatedStringHandler, - WellKnownType.System_MemoryExtensions + WellKnownType.System_Runtime_CompilerServices_RequiredMemberAttribute, + WellKnownType.System_Diagnostics_CodeAnalysis_SetsRequiredMembersAttribute, + WellKnownType.System_MemoryExtensions, + WellKnownType.System_Runtime_CompilerServices_CompilerFeatureRequiredAttribute ' Not available on all platforms. Continue For Case WellKnownType.ExtSentinel @@ -613,7 +616,11 @@ End Namespace WellKnownType.System_Runtime_CompilerServices_NativeIntegerAttribute, WellKnownType.System_Runtime_CompilerServices_IsExternalInit, WellKnownType.System_Runtime_CompilerServices_DefaultInterpolatedStringHandler, - WellKnownType.System_MemoryExtensions + WellKnownType.System_Runtime_CompilerServices_RequiredMemberAttribute, + WellKnownType.System_Diagnostics_CodeAnalysis_SetsRequiredMembersAttribute, + WellKnownType.System_MemoryExtensions, + WellKnownType.System_Runtime_CompilerServices_CompilerFeatureRequiredAttribute + ' Not available on all platforms. Continue For Case WellKnownType.ExtSentinel @@ -703,9 +710,12 @@ End Namespace WellKnownMember.System_Runtime_CompilerServices_NativeIntegerAttribute__ctor, WellKnownMember.System_Runtime_CompilerServices_NativeIntegerAttribute__ctorTransformFlags, WellKnownMember.System_Runtime_CompilerServices_DefaultInterpolatedStringHandler__ToStringAndClear, + WellKnownMember.System_Runtime_CompilerServices_RequiredMemberAttribute__ctor, + WellKnownMember.System_Diagnostics_CodeAnalysis_SetsRequiredMembersAttribute__ctor, WellKnownMember.System_MemoryExtensions__SequenceEqual_Span_T, WellKnownMember.System_MemoryExtensions__SequenceEqual_ReadOnlySpan_T, - WellKnownMember.System_MemoryExtensions__AsSpan_String + WellKnownMember.System_MemoryExtensions__AsSpan_String, + WellKnownMember.System_Runtime_CompilerServices_CompilerFeatureRequiredAttribute__ctor ' Not available yet, but will be in upcoming release. Continue For Case WellKnownMember.Microsoft_CodeAnalysis_Runtime_Instrumentation__CreatePayloadForMethodsSpanningSingleFile, @@ -851,9 +861,12 @@ End Namespace WellKnownMember.System_Runtime_CompilerServices_NativeIntegerAttribute__ctor, WellKnownMember.System_Runtime_CompilerServices_NativeIntegerAttribute__ctorTransformFlags, WellKnownMember.System_Runtime_CompilerServices_DefaultInterpolatedStringHandler__ToStringAndClear, + WellKnownMember.System_Runtime_CompilerServices_RequiredMemberAttribute__ctor, + WellKnownMember.System_Diagnostics_CodeAnalysis_SetsRequiredMembersAttribute__ctor, WellKnownMember.System_MemoryExtensions__SequenceEqual_Span_T, WellKnownMember.System_MemoryExtensions__SequenceEqual_ReadOnlySpan_T, - WellKnownMember.System_MemoryExtensions__AsSpan_String + WellKnownMember.System_MemoryExtensions__AsSpan_String, + WellKnownMember.System_Runtime_CompilerServices_CompilerFeatureRequiredAttribute__ctor ' Not available yet, but will be in upcoming release. Continue For Case WellKnownMember.Microsoft_CodeAnalysis_Runtime_Instrumentation__CreatePayloadForMethodsSpanningSingleFile, diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/KeywordCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/KeywordCompletionProviderTests.cs index d14fa2d8ddba7..5c3d6722ef93b 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/KeywordCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/KeywordCompletionProviderTests.cs @@ -616,5 +616,73 @@ public async Task TestInCastExpressionThatMightBeParenthesizedExpression2(bool h await VerifyItemExistsAsync(markup, "nameof"); } } + + [Theory] + [InlineData("class")] + [InlineData("struct")] + public async Task SuggestRequiredInClassOrStruct(string type) + { + var markup = $$""" + {{type}} C + { + $$ + """; + + await VerifyItemExistsAsync(markup, "required"); + } + + [Fact] + public async Task DoNotSuggestRequiredInInterface() + { + var markup = $$""" + interface I + { + public $$ + """; + + await VerifyItemIsAbsentAsync(markup, "required"); + } + + [Theory] + [InlineData("static")] + [InlineData("const")] + [InlineData("readonly")] + public async Task DoNotSuggestRequiredOnFilteredKeywordMembers(string keyword) + { + var markup = $$""" + class C + { + {{keyword}} $$ + """; + + await VerifyItemIsAbsentAsync(markup, "required"); + } + + [Theory] + [InlineData("static")] + [InlineData("const")] + [InlineData("readonly")] + public async Task DoNotSuggestFilteredKeywordsOnRequiredMembers(string keyword) + { + var markup = $$""" + class C + { + required $$ + """; + + await VerifyItemIsAbsentAsync(markup, keyword); + } + + [Fact] + public async Task DoNotSuggestRequiredOnRequiredMembers() + { + var markup = $$""" + class C + { + required $$ + """; + + await VerifyItemIsAbsentAsync(markup, "required"); + } } } diff --git a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/OverrideCompletionProviderTests.cs b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/OverrideCompletionProviderTests.cs index 043ff896b0a6a..1c1b7484e8f71 100644 --- a/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/OverrideCompletionProviderTests.cs +++ b/src/EditorFeatures/CSharpTest/Completion/CompletionProviders/OverrideCompletionProviderTests.cs @@ -12,6 +12,7 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.CodeStyle; using Microsoft.CodeAnalysis.CSharp.Completion.Providers; +using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Shared.Extensions; @@ -2700,6 +2701,191 @@ public override bool Equals(object obj) } } + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task CommitRequiredKeywordAdded() + { + var markupBeforeCommit = """ + class Base + { + public virtual required int Prop { get; } + } + + class Derived : Base + { + override $$ + } + """; + + var expectedCodeAfterCommit = """ + class Base + { + public virtual required int Prop { get; } + } + + class Derived : Base + { + public override required int Prop + { + get + { + return base.Prop;$$ + } + } + } + """; + await VerifyCustomCommitProviderAsync(markupBeforeCommit, "Prop", expectedCodeAfterCommit); + } + + [WpfTheory, Trait(Traits.Feature, Traits.Features.Completion)] + [InlineData("required override")] + [InlineData("override required")] + public async Task CommitRequiredKeywordPreserved(string ordering) + { + var markupBeforeCommit = $@" + + class Base +{{ + public virtual required int Prop {{ get; }} +}} + +class Derived : Base +{{ + {ordering} $$ +}} + +"; + + var expectedCodeAfterCommit = """ + class Base + { + public virtual required int Prop { get; } + } + + class Derived : Base + { + public override required int Prop + { + get + { + return base.Prop;$$ + } + } + } + """; + await VerifyCustomCommitProviderAsync(markupBeforeCommit, "Prop", expectedCodeAfterCommit); + } + + [WpfTheory, Trait(Traits.Feature, Traits.Features.Completion)] + [InlineData("required override")] + [InlineData("override required")] + public async Task CommitRequiredKeywordPreservedWhenBaseIsNotRequired(string ordering) + { + var markupBeforeCommit = $@" + + class Base +{{ + public virtual int Prop {{ get; }} +}} + +class Derived : Base +{{ + {ordering} $$ +}} + +"; + + var expectedCodeAfterCommit = """ + class Base + { + public virtual int Prop { get; } + } + + class Derived : Base + { + public override required int Prop + { + get + { + return base.Prop;$$ + } + } + } + """; + await VerifyCustomCommitProviderAsync(markupBeforeCommit, "Prop", expectedCodeAfterCommit); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task CommitRequiredKeywordRemovedForMethods() + { + var markupBeforeCommit = """ + class Base + { + public virtual void M() { } + } + + class Derived : Base + { + required override $$ + } + """; + + var expectedCodeAfterCommit = """ + class Base + { + public virtual void M() { } + } + + class Derived : Base + { + public override void M() + { + base.M();$$ + } + } + """; + await VerifyCustomCommitProviderAsync(markupBeforeCommit, "M()", expectedCodeAfterCommit); + } + + [WpfFact, Trait(Traits.Feature, Traits.Features.Completion)] + public async Task CommitRequiredKeywordRemovedForIndexers() + { + var markupBeforeCommit = """ + class Base + { + public virtual int this[int i] { get { } set { } } + } + + class Derived : Base + { + required override $$ + } + """; + + var expectedCodeAfterCommit = """ + class Base + { + public virtual int this[int i] { get { } set { } } + } + + class Derived : Base + { + public override int this[int i] + { + get + { + return base[i];$$ + } + + set + { + base[i] = value; + } + } + } + """; + await VerifyCustomCommitProviderAsync(markupBeforeCommit, "this[int i]", expectedCodeAfterCommit); + } + #endregion #region "EditorBrowsable should be ignored" diff --git a/src/EditorFeatures/CSharpTest/ExtractInterface/ExtractInterfaceTests.cs b/src/EditorFeatures/CSharpTest/ExtractInterface/ExtractInterfaceTests.cs index 11a9f08e8fa74..40a6ffb3431d5 100644 --- a/src/EditorFeatures/CSharpTest/ExtractInterface/ExtractInterfaceTests.cs +++ b/src/EditorFeatures/CSharpTest/ExtractInterface/ExtractInterfaceTests.cs @@ -623,6 +623,7 @@ public async Task ExtractInterface_CodeGen_Methods() abstract class MyClass$$ { + public required int RequiredProperty { get; set; } public void ExtractableMethod_Normal() { } public void ExtractableMethod_ParameterTypes(System.Diagnostics.CorrelationManager x, Nullable y = 7, string z = ""42"") { } public abstract void ExtractableMethod_Abstract(); @@ -634,6 +635,8 @@ unsafe public void UnsafeMethod(int *p) { } interface IMyClass { + int RequiredProperty { get; set; } + void ExtractableMethod_Abstract(); void ExtractableMethod_Normal(); void ExtractableMethod_ParameterTypes(CorrelationManager x, int? y = 7, string z = ""42""); diff --git a/src/EditorFeatures/CSharpTest/GenerateOverrides/GenerateOverridesTests.cs b/src/EditorFeatures/CSharpTest/GenerateOverrides/GenerateOverridesTests.cs index e98f9c7673c09..5112ab86a02c8 100644 --- a/src/EditorFeatures/CSharpTest/GenerateOverrides/GenerateOverridesTests.cs +++ b/src/EditorFeatures/CSharpTest/GenerateOverrides/GenerateOverridesTests.cs @@ -250,5 +250,31 @@ public override void M(T1? a, T2 b, T1? c, T3? d) } }", new[] { "M" }); } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsGenerateOverrides)] + public async Task TestRequiredProperty() + { + await TestWithPickMembersDialogAsync( +@" +class Base +{ + public virtual required int Property { get; set; } +} + +class Derived : Base +{ + [||] +}", +@" +class Base +{ + public virtual required int Property { get; set; } +} + +class Derived : Base +{ + public override required int Property { get => base.Property; set => base.Property = value; } +}", new[] { "Property" }); + } } } diff --git a/src/EditorFeatures/CSharpTest/ImplementAbstractClass/ImplementAbstractClassTests.cs b/src/EditorFeatures/CSharpTest/ImplementAbstractClass/ImplementAbstractClassTests.cs index 99716e7d0f9a6..2416c4743f663 100644 --- a/src/EditorFeatures/CSharpTest/ImplementAbstractClass/ImplementAbstractClassTests.cs +++ b/src/EditorFeatures/CSharpTest/ImplementAbstractClass/ImplementAbstractClassTests.cs @@ -2075,5 +2075,41 @@ public override void M(T1? a, T2 b, T1? c, T3? d) } }"); } + + [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsImplementAbstractClass)] + public async Task TestRequiredMember() + { + await TestAllOptionsOffAsync( + """ + abstract class C + { + public abstract required int Property { get; set; } + } + class [|D|] : C + { + } + """, + """ + abstract class C + { + public abstract required int Property { get; set; } + } + class D : C + { + public override required int Property + { + get + { + throw new System.NotImplementedException(); + } + + set + { + throw new System.NotImplementedException(); + } + } + } + """); + } } } diff --git a/src/EditorFeatures/Test/Diagnostics/IDEDiagnosticIDConfigurationTests.cs b/src/EditorFeatures/Test/Diagnostics/IDEDiagnosticIDConfigurationTests.cs index c5ec99b1f1c90..1609ec47fd481 100644 --- a/src/EditorFeatures/Test/Diagnostics/IDEDiagnosticIDConfigurationTests.cs +++ b/src/EditorFeatures/Test/Diagnostics/IDEDiagnosticIDConfigurationTests.cs @@ -858,7 +858,7 @@ No editorconfig based code style option No editorconfig based code style option # IDE0036, PreferredModifierOrder -csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async +csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,required,volatile,async # IDE0037, PreferInferredTupleNames dotnet_style_prefer_inferred_tuple_names = true diff --git a/src/EditorFeatures/Test/MetadataAsSource/MetadataAsSourceTests.CSharp.cs b/src/EditorFeatures/Test/MetadataAsSource/MetadataAsSourceTests.CSharp.cs index bfeff38a61c62..eb6ba181f5608 100644 --- a/src/EditorFeatures/Test/MetadataAsSource/MetadataAsSourceTests.CSharp.cs +++ b/src/EditorFeatures/Test/MetadataAsSource/MetadataAsSourceTests.CSharp.cs @@ -742,6 +742,77 @@ public class C await GenerateAndVerifySourceAsync(metadataSource, symbolName, LanguageNames.CSharp, expected: expected, signaturesOnly: signaturesOnly, languageVersion: "Preview", metadataLanguageVersion: "Preview"); } + + [Theory, CombinatorialData, Trait(Traits.Feature, Traits.Features.MetadataAsSource)] + public async Task TestRequiredProperty(bool signaturesOnly) + { + var metadataSource = """ + public class C { public required int Property { get; set; } } + namespace System.Runtime.CompilerServices + { + public sealed class RequiredMemberAttribute : Attribute { } + public sealed class CompilerFeatureRequiredAttribute : Attribute + { + public CompilerFeatureRequiredAttribute(string featureName) + { + FeatureName = featureName; + } + public string FeatureName { get; } + public bool IsOptional { get; set; } + } + } + + """; + var symbolName = "C"; + + // ICSharpDecompiler does not yet support decoding required members nicely + var expected = signaturesOnly switch + { + true => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null +// {CodeAnalysisResources.InMemoryAssembly} +#endregion + +using System.Runtime.CompilerServices; + +[RequiredMember] +public class [|C|] +{{ + public C(); + + [RequiredMember] + public required int Property {{ get; set; }} +}}", + false => $@"#region {FeaturesResources.Assembly} ReferencedAssembly, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null +// {CodeAnalysisResources.InMemoryAssembly} +// Decompiled with ICSharpCode.Decompiler {ICSharpCodeDecompilerVersion} +#endregion + +using System; +using System.Runtime.CompilerServices; + +[RequiredMember] +public class [|C|] +{{ + [RequiredMember] + public int Property {{ get; set; }} + + [Obsolete(""Constructors of types with required members are not supported in this version of your compiler."", true)] + [CompilerFeatureRequired(""RequiredMembers"")] + public C() + {{ + }} +}} +#if false // {CSharpEditorResources.Decompilation_log} +{string.Format(CSharpEditorResources._0_items_in_cache, 6)} +------------------ +{string.Format(CSharpEditorResources.Resolve_0, "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")} +{string.Format(CSharpEditorResources.Found_single_assembly_0, "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")} +{string.Format(CSharpEditorResources.Load_from_0, "mscorlib.v4_6_1038_0.dll")} +#endif", + }; + + await GenerateAndVerifySourceAsync(metadataSource, symbolName, LanguageNames.CSharp, languageVersion: "Preview", metadataLanguageVersion: "Preview", expected: expected, signaturesOnly: signaturesOnly); + } } } } diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/DisplayClassVariable.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/DisplayClassVariable.cs index d04f935e73e1a..4619b76bdf234 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/DisplayClassVariable.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/DisplayClassVariable.cs @@ -159,6 +159,8 @@ public override bool IsVolatile get { return false; } } + internal override bool IsRequired => throw ExceptionUtilities.Unreachable; + public override FlowAnalysisAnnotations FlowAnalysisAnnotations { get { return FlowAnalysisAnnotations.None; } diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EEMethodSymbol.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EEMethodSymbol.cs index 3ec5f88a3bcc3..b61c9c4fad836 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EEMethodSymbol.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EEMethodSymbol.cs @@ -722,5 +722,7 @@ internal override int CalculateLocalSyntaxOffset(int localPosition, SyntaxTree l } internal override bool IsNullableAnalysisEnabled() => false; + + protected override bool HasSetsRequiredMembersImpl => throw ExceptionUtilities.Unreachable; } } diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EENamedTypeSymbol.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EENamedTypeSymbol.cs index 69fa80e320486..b6856a5f05ff1 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EENamedTypeSymbol.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/EENamedTypeSymbol.cs @@ -164,6 +164,8 @@ public override IEnumerable MemberNames get { throw ExceptionUtilities.Unreachable; } } + internal override bool HasDeclaredRequiredMembers => false; + public override ImmutableArray GetMembers() { return _methods.Cast(); diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/PlaceholderMethodSymbol.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/PlaceholderMethodSymbol.cs index bafe42bc6c090..bed4b97588505 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/PlaceholderMethodSymbol.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/PlaceholderMethodSymbol.cs @@ -273,6 +273,8 @@ internal override int CalculateLocalSyntaxOffset(int localPosition, SyntaxTree l internal override bool IsNullableAnalysisEnabled() => false; + protected override bool HasSetsRequiredMembersImpl => throw ExceptionUtilities.Unreachable; + #if DEBUG protected override MethodSymbolAdapter CreateCciAdapter() { diff --git a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/SynthesizedContextMethodSymbol.cs b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/SynthesizedContextMethodSymbol.cs index 8d4af67a7dd76..5121e63935310 100644 --- a/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/SynthesizedContextMethodSymbol.cs +++ b/src/ExpressionEvaluator/CSharp/Source/ExpressionCompiler/Symbols/SynthesizedContextMethodSymbol.cs @@ -218,5 +218,7 @@ internal override bool IsMetadataVirtual(bool ignoreInterfaceImplementationChang { throw ExceptionUtilities.Unreachable; } + + protected override bool HasSetsRequiredMembersImpl => throw ExceptionUtilities.Unreachable; } } diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/KeywordCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/KeywordCompletionProvider.cs index 23896ed0f34fe..2c74a4a4cc164 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/KeywordCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/KeywordCompletionProvider.cs @@ -127,6 +127,7 @@ public KeywordCompletionProvider() new RefKeywordRecommender(), new RegionKeywordRecommender(), new RemoveKeywordRecommender(), + new RequiredKeywordRecommender(), new RestoreKeywordRecommender(), new ReturnKeywordRecommender(), new SByteKeywordRecommender(), diff --git a/src/Features/CSharp/Portable/Completion/CompletionProviders/OverrideCompletionProvider.cs b/src/Features/CSharp/Portable/Completion/CompletionProviders/OverrideCompletionProvider.cs index 38c03288c1c4b..ad3728c43364f 100644 --- a/src/Features/CSharp/Portable/Completion/CompletionProviders/OverrideCompletionProvider.cs +++ b/src/Features/CSharp/Portable/Completion/CompletionProviders/OverrideCompletionProvider.cs @@ -85,6 +85,7 @@ public override bool TryDetermineModifiers(SyntaxToken startToken, SourceText te var isUnsafe = false; var isSealed = false; var isAbstract = false; + var isRequired = false; while (IsOnStartLine(token.SpanStart, text, startLine) && !token.IsKind(SyntaxKind.None)) { @@ -104,6 +105,9 @@ public override bool TryDetermineModifiers(SyntaxToken startToken, SourceText te break; case SyntaxKind.ExternKeyword: break; + case SyntaxKind.RequiredKeyword: + isRequired = true; + break; // Filter on the most recently typed accessibility; keep the first one we see @@ -175,7 +179,7 @@ public override bool TryDetermineModifiers(SyntaxToken startToken, SourceText te token = previousToken; } - modifiers = new DeclarationModifiers(isUnsafe: isUnsafe, isAbstract: isAbstract, isOverride: true, isSealed: isSealed); + modifiers = new DeclarationModifiers(isUnsafe: isUnsafe, isAbstract: isAbstract, isOverride: true, isSealed: isSealed, isRequired: isRequired); return overrideToken.IsKind(SyntaxKind.OverrideKeyword) && IsOnStartLine(overrideToken.Parent!.SpanStart, text, startLine); } diff --git a/src/Features/CSharp/Portable/Completion/KeywordRecommenders/RequiredKeywordRecommender.cs b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/RequiredKeywordRecommender.cs new file mode 100644 index 0000000000000..7d8ddfabdc374 --- /dev/null +++ b/src/Features/CSharp/Portable/Completion/KeywordRecommenders/RequiredKeywordRecommender.cs @@ -0,0 +1,33 @@ +// 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.Collections.Generic; +using System.Linq; +using System.Threading; +using Microsoft.CodeAnalysis.CSharp.Extensions.ContextQuery; +using Microsoft.CodeAnalysis.CSharp.Utilities; +using Roslyn.Utilities; + +namespace Microsoft.CodeAnalysis.CSharp.Completion.KeywordRecommenders; + +internal class RequiredKeywordRecommender : AbstractSyntacticSingleKeywordRecommender +{ + private static readonly ISet s_validModifiers = SyntaxKindSet.AllMemberModifiers.Where(s => s is not (SyntaxKind.RequiredKeyword or SyntaxKind.StaticKeyword or SyntaxKind.ReadOnlyKeyword or SyntaxKind.ConstKeyword)).ToSet(); + + private static readonly ISet s_validTypeDeclarations = new HashSet(SyntaxFacts.EqualityComparer) + { + SyntaxKind.StructDeclaration, + SyntaxKind.ClassDeclaration, + }; + + public RequiredKeywordRecommender() + : base(SyntaxKind.RequiredKeyword) + { + } + + protected override bool IsValidContext(int position, CSharpSyntaxContext context, CancellationToken cancellationToken) + { + return context.IsMemberDeclarationContext(s_validModifiers, s_validTypeDeclarations, canBePartial: true, cancellationToken); + } +} diff --git a/src/Features/Core/Portable/ImplementAbstractClass/ImplementAbstractClassData.cs b/src/Features/Core/Portable/ImplementAbstractClass/ImplementAbstractClassData.cs index 16f75ef9ad787..47eb4f3de379c 100644 --- a/src/Features/Core/Portable/ImplementAbstractClass/ImplementAbstractClassData.cs +++ b/src/Features/Core/Portable/ImplementAbstractClass/ImplementAbstractClassData.cs @@ -155,7 +155,7 @@ private ImmutableArray GenerateMembers( Compilation compilation, ISymbol member, ISymbol? throughMember, bool addUnsafe, ImplementTypePropertyGenerationBehavior propertyGenerationBehavior) { - var modifiers = new DeclarationModifiers(isOverride: true, isUnsafe: addUnsafe); + var modifiers = new DeclarationModifiers(isOverride: true, isUnsafe: addUnsafe, isRequired: member.IsRequired()); var accessibility = member.ComputeResultantAccessibility(ClassType); // only call through one of members for this symbol if we can actually access the symbol diff --git a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedFieldSymbol.cs b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedFieldSymbol.cs index 657d380893451..ba1cff59efdaf 100644 --- a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedFieldSymbol.cs +++ b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedFieldSymbol.cs @@ -39,6 +39,8 @@ public WrappedFieldSymbol(IFieldSymbol fieldSymbol, IDocumentationCommentFormatt public bool IsVolatile => _symbol.IsVolatile; + public bool IsRequired => _symbol.IsRequired; + public bool IsFixedSizeBuffer => _symbol.IsFixedSizeBuffer; public int FixedSize => _symbol.FixedSize; diff --git a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedPropertySymbol.cs b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedPropertySymbol.cs index e3746247a0d2b..11e7109453bee 100644 --- a/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedPropertySymbol.cs +++ b/src/Features/Core/Portable/MetadataAsSource/AbstractMetadataAsSourceService.WrappedPropertySymbol.cs @@ -41,6 +41,8 @@ public ImmutableArray ExplicitInterfaceImplementations public bool IsWriteOnly => _symbol.IsWriteOnly; + public bool IsRequired => _symbol.IsRequired; + public bool ReturnsByRef => _symbol.ReturnsByRef; public bool ReturnsByRefReadonly => _symbol.ReturnsByRefReadonly; diff --git a/src/VisualStudio/CSharp/Impl/LanguageService/CSharpHelpContextService.cs b/src/VisualStudio/CSharp/Impl/LanguageService/CSharpHelpContextService.cs index 65fc71ee8dc02..c19847d9f99b0 100644 --- a/src/VisualStudio/CSharp/Impl/LanguageService/CSharpHelpContextService.cs +++ b/src/VisualStudio/CSharp/Impl/LanguageService/CSharpHelpContextService.cs @@ -386,6 +386,10 @@ private static bool TryGetTextForContextualKeyword(SyntaxToken token, [NotNullWh : "whereclause_CSharpKeyword"; return true; + + case SyntaxKind.RequiredKeyword: + text = Keyword("required"); + return true; } } diff --git a/src/VisualStudio/CSharp/Test/F1Help/F1HelpTests.cs b/src/VisualStudio/CSharp/Test/F1Help/F1HelpTests.cs index fc383e565f7f1..e046727aaaba8 100644 --- a/src/VisualStudio/CSharp/Test/F1Help/F1HelpTests.cs +++ b/src/VisualStudio/CSharp/Test/F1Help/F1HelpTests.cs @@ -1775,5 +1775,16 @@ void goo() } }", "checked"); } + + [Fact] + public async Task TestRequired() + { + await Test_KeywordAsync(""" + public class C + { + re[||]quired int Field; + } + """, "required"); + } } } diff --git a/src/VisualStudio/Core/Test/Options/CSharpEditorConfigGeneratorTests.vb b/src/VisualStudio/Core/Test/Options/CSharpEditorConfigGeneratorTests.vb index ad386fc00f988..3250dcaac36da 100644 --- a/src/VisualStudio/Core/Test/Options/CSharpEditorConfigGeneratorTests.vb +++ b/src/VisualStudio/Core/Test/Options/CSharpEditorConfigGeneratorTests.vb @@ -122,7 +122,7 @@ csharp_style_conditional_delegate_call = true # Modifier preferences csharp_prefer_static_local_function = true -csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async +csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,required,volatile,async # Code-block preferences csharp_prefer_braces = true @@ -359,7 +359,7 @@ csharp_style_conditional_delegate_call = true # Modifier preferences csharp_prefer_static_local_function = true -csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async +csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,required,volatile,async # Code-block preferences csharp_prefer_braces = true diff --git a/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs b/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs index 4341cdafc55c1..9916ea6ba7e0d 100644 --- a/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs +++ b/src/Workspaces/CSharp/Portable/CodeGeneration/CSharpSyntaxGenerator.cs @@ -1376,6 +1376,7 @@ public override SyntaxNode WithAccessibility(SyntaxNode declaration, Accessibili DeclarationModifiers.Const | DeclarationModifiers.New | DeclarationModifiers.ReadOnly | + DeclarationModifiers.Required | DeclarationModifiers.Static | DeclarationModifiers.Unsafe | DeclarationModifiers.Volatile; @@ -1405,6 +1406,7 @@ public override SyntaxNode WithAccessibility(SyntaxNode declaration, Accessibili DeclarationModifiers.New | DeclarationModifiers.Override | DeclarationModifiers.ReadOnly | + DeclarationModifiers.Required | DeclarationModifiers.Sealed | DeclarationModifiers.Static | DeclarationModifiers.Virtual | @@ -1658,6 +1660,9 @@ private static SyntaxTokenList AsModifierList(Accessibility accessibility, Decla if (modifiers.IsExtern) list.Add(SyntaxFactory.Token(SyntaxKind.ExternKeyword)); + if (modifiers.IsRequired) + list.Add(SyntaxFactory.Token(SyntaxKind.RequiredKeyword)); + // partial and ref must be last if (modifiers.IsRef) list.Add(SyntaxFactory.Token(SyntaxKind.RefKeyword)); diff --git a/src/Workspaces/CSharp/Portable/CodeGeneration/FieldGenerator.cs b/src/Workspaces/CSharp/Portable/CodeGeneration/FieldGenerator.cs index c9cfe089a9ff9..f8d8628093b74 100644 --- a/src/Workspaces/CSharp/Portable/CodeGeneration/FieldGenerator.cs +++ b/src/Workspaces/CSharp/Portable/CodeGeneration/FieldGenerator.cs @@ -137,6 +137,11 @@ private static SyntaxTokenList GenerateModifiers(IFieldSymbol field, CSharpCodeG { tokens.Add(SyntaxFactory.Token(SyntaxKind.ReadOnlyKeyword)); } + + if (field.IsRequired) + { + tokens.Add(SyntaxFactory.Token(SyntaxKind.RequiredKeyword)); + } } if (CodeGenerationFieldInfo.GetIsUnsafe(field)) diff --git a/src/Workspaces/CSharp/Portable/CodeGeneration/PropertyGenerator.cs b/src/Workspaces/CSharp/Portable/CodeGeneration/PropertyGenerator.cs index 68d8cb9d6153e..f5b03afeb38f0 100644 --- a/src/Workspaces/CSharp/Portable/CodeGeneration/PropertyGenerator.cs +++ b/src/Workspaces/CSharp/Portable/CodeGeneration/PropertyGenerator.cs @@ -397,6 +397,11 @@ private static SyntaxTokenList GenerateModifiers( { tokens.Add(SyntaxFactory.Token(SyntaxKind.AbstractKeyword)); } + + if (property.IsRequired) + { + tokens.Add(SyntaxFactory.Token(SyntaxKind.RequiredKeyword)); + } } } diff --git a/src/Workspaces/CSharpTest/CodeGeneration/SyntaxGeneratorTests.cs b/src/Workspaces/CSharpTest/CodeGeneration/SyntaxGeneratorTests.cs index 1d8dd06a567fc..1829328657951 100644 --- a/src/Workspaces/CSharpTest/CodeGeneration/SyntaxGeneratorTests.cs +++ b/src/Workspaces/CSharpTest/CodeGeneration/SyntaxGeneratorTests.cs @@ -786,6 +786,10 @@ public void TestFieldDeclarations() VerifySyntax( Generator.FieldDeclaration("fld", Generator.TypeExpression(SpecialType.System_Int32), accessibility: Accessibility.NotApplicable, modifiers: DeclarationModifiers.Static | DeclarationModifiers.ReadOnly), "static readonly int fld;"); + + VerifySyntax( + Generator.FieldDeclaration("fld", Generator.TypeExpression(SpecialType.System_Int32), accessibility: Accessibility.NotApplicable, modifiers: DeclarationModifiers.Required), + "required int fld;"); } [Fact] @@ -1011,6 +1015,10 @@ public void TestPropertyDeclarations() Generator.PropertyDeclaration("p", Generator.IdentifierName("x"), modifiers: DeclarationModifiers.Abstract), "abstract x p { get; set; }"); + VerifySyntax( + Generator.PropertyDeclaration("p", Generator.IdentifierName("x"), modifiers: DeclarationModifiers.Required), + "required x p { get; set; }"); + VerifySyntax( Generator.PropertyDeclaration("p", Generator.IdentifierName("x"), modifiers: DeclarationModifiers.ReadOnly, getAccessorStatements: new[] { Generator.IdentifierName("y") }), "x p\r\n{\r\n get\r\n {\r\n y;\r\n }\r\n}"); @@ -3621,6 +3629,17 @@ class C }"); } + [Fact] + public void TestPropertyModifiers2() + { + TestModifiersAsync(DeclarationModifiers.ReadOnly | DeclarationModifiers.Required, + @" +class C +{ + [|public required int X => 0;|] +}"); + } + [Fact, WorkItem(1084965, " https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1084965")] public void TestFieldModifiers1() { @@ -3632,6 +3651,17 @@ class C }"); } + [Fact] + public void TestFieldModifiers2() + { + TestModifiersAsync(DeclarationModifiers.Required, + @" +class C +{ + public required int [|X|]; +}"); + } + [Fact, WorkItem(1084965, " https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1084965")] public void TestEvent1() { diff --git a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationFieldSymbol.cs b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationFieldSymbol.cs index 08db582288b0b..670c09122ecd4 100644 --- a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationFieldSymbol.cs +++ b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationFieldSymbol.cs @@ -78,6 +78,8 @@ public bool IsReadOnly public bool IsVolatile => false; + public bool IsRequired => Modifiers.IsRequired; + public bool IsFixedSizeBuffer => false; public int FixedSize => 0; diff --git a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationPropertySymbol.cs b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationPropertySymbol.cs index 01fd6dc9c256c..7719be11d3a96 100644 --- a/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationPropertySymbol.cs +++ b/src/Workspaces/Core/Portable/CodeGeneration/Symbols/CodeGenerationPropertySymbol.cs @@ -76,6 +76,8 @@ public override TResult Accept(SymbolVisitor this.GetMethod == null && this.SetMethod != null; + public bool IsRequired => Modifiers.IsRequired; + public new IPropertySymbol OriginalDefinition => this; public RefKind RefKind => _refKind; diff --git a/src/Workspaces/Core/Portable/Editing/DeclarationModifiers.cs b/src/Workspaces/Core/Portable/Editing/DeclarationModifiers.cs index 4bffd525485cd..df4f81dd1d41e 100644 --- a/src/Workspaces/Core/Portable/Editing/DeclarationModifiers.cs +++ b/src/Workspaces/Core/Portable/Editing/DeclarationModifiers.cs @@ -37,7 +37,8 @@ internal DeclarationModifiers( bool isWriteOnly = false, bool isRef = false, bool isVolatile = false, - bool isExtern = false) + bool isExtern = false, + bool isRequired = false) : this( (isStatic ? Modifiers.Static : Modifiers.None) | (isAbstract ? Modifiers.Abstract : Modifiers.None) | @@ -54,7 +55,8 @@ internal DeclarationModifiers( (isWriteOnly ? Modifiers.WriteOnly : Modifiers.None) | (isRef ? Modifiers.Ref : Modifiers.None) | (isVolatile ? Modifiers.Volatile : Modifiers.None) | - (isExtern ? Modifiers.Extern : Modifiers.None)) + (isExtern ? Modifiers.Extern : Modifiers.None) | + (isRequired ? Modifiers.Required : Modifiers.None)) { } @@ -81,7 +83,8 @@ IMethodSymbol or isUnsafe: symbol.RequiresUnsafeModifier(), isVolatile: field?.IsVolatile == true, isExtern: symbol.IsExtern, - isAsync: method?.IsAsync == true); + isAsync: method?.IsAsync == true, + isRequired: symbol.IsRequired()); } // Only named types, members of named types, and local functions have modifiers. @@ -121,6 +124,8 @@ IMethodSymbol or public bool IsExtern => (_modifiers & Modifiers.Extern) != 0; + public bool IsRequired => (_modifiers & Modifiers.Required) != 0; + public DeclarationModifiers WithIsStatic(bool isStatic) => new(SetFlag(_modifiers, Modifiers.Static, isStatic)); @@ -170,6 +175,9 @@ public DeclarationModifiers WithIsVolatile(bool isVolatile) public DeclarationModifiers WithIsExtern(bool isExtern) => new(SetFlag(_modifiers, Modifiers.Extern, isExtern)); + public DeclarationModifiers WithIsRequired(bool isRequired) + => new(SetFlag(_modifiers, Modifiers.Required, isRequired)); + private static Modifiers SetFlag(Modifiers existing, Modifiers modifier, bool isSet) => isSet ? (existing | modifier) : (existing & ~modifier); @@ -194,6 +202,7 @@ private enum Modifiers Ref = 1 << 13, Volatile = 1 << 14, Extern = 1 << 15, + Required = 1 << 16, #pragma warning restore format } @@ -215,6 +224,7 @@ private enum Modifiers public static DeclarationModifiers Ref => new(Modifiers.Ref); public static DeclarationModifiers Volatile => new(Modifiers.Volatile); public static DeclarationModifiers Extern => new(Modifiers.Extern); + public static DeclarationModifiers Required => new(Modifiers.Required); public static DeclarationModifiers operator |(DeclarationModifiers left, DeclarationModifiers right) => new(left._modifiers | right._modifiers); diff --git a/src/Workspaces/Core/Portable/PublicAPI.Unshipped.txt b/src/Workspaces/Core/Portable/PublicAPI.Unshipped.txt index 31acdde754b1d..a099023a41ba1 100644 --- a/src/Workspaces/Core/Portable/PublicAPI.Unshipped.txt +++ b/src/Workspaces/Core/Portable/PublicAPI.Unshipped.txt @@ -2,9 +2,12 @@ Microsoft.CodeAnalysis.CodeFixes.DocumentBasedFixAllProvider.DocumentBasedFixAll Microsoft.CodeAnalysis.CodeFixes.FixAllContext.FixAllContext(Microsoft.CodeAnalysis.Document document, Microsoft.CodeAnalysis.Text.TextSpan? diagnosticSpan, Microsoft.CodeAnalysis.CodeFixes.CodeFixProvider codeFixProvider, Microsoft.CodeAnalysis.CodeFixes.FixAllScope scope, string codeActionEquivalenceKey, System.Collections.Generic.IEnumerable diagnosticIds, Microsoft.CodeAnalysis.CodeFixes.FixAllContext.DiagnosticProvider fixAllDiagnosticProvider, System.Threading.CancellationToken cancellationToken) -> void Microsoft.CodeAnalysis.CodeFixes.FixAllScope.ContainingMember = 4 -> Microsoft.CodeAnalysis.CodeFixes.FixAllScope Microsoft.CodeAnalysis.CodeFixes.FixAllScope.ContainingType = 5 -> Microsoft.CodeAnalysis.CodeFixes.FixAllScope +Microsoft.CodeAnalysis.Editing.DeclarationModifiers.IsRequired.get -> bool +Microsoft.CodeAnalysis.Editing.DeclarationModifiers.WithIsRequired(bool isRequired) -> Microsoft.CodeAnalysis.Editing.DeclarationModifiers Microsoft.CodeAnalysis.Editing.SyntaxEditor.SyntaxEditor(Microsoft.CodeAnalysis.SyntaxNode root, Microsoft.CodeAnalysis.Host.HostWorkspaceServices services) -> void *REMOVED*static Microsoft.CodeAnalysis.Editing.SyntaxGenerator.DefaultRemoveOptions -> Microsoft.CodeAnalysis.SyntaxRemoveOptions static Microsoft.CodeAnalysis.CodeFixes.FixAllProvider.Create(System.Func, System.Threading.Tasks.Task> fixAllAsync, System.Collections.Immutable.ImmutableArray supportedFixAllScopes) -> Microsoft.CodeAnalysis.CodeFixes.FixAllProvider +static Microsoft.CodeAnalysis.Editing.DeclarationModifiers.Required.get -> Microsoft.CodeAnalysis.Editing.DeclarationModifiers static Microsoft.CodeAnalysis.Recommendations.Recommender.GetRecommendedSymbolsAtPositionAsync(Microsoft.CodeAnalysis.Document document, int position, Microsoft.CodeAnalysis.Options.OptionSet options = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task> static readonly Microsoft.CodeAnalysis.Editing.SyntaxGenerator.DefaultRemoveOptions -> Microsoft.CodeAnalysis.SyntaxRemoveOptions Microsoft.CodeAnalysis.Rename.SymbolRenameOptions @@ -27,5 +30,4 @@ Microsoft.CodeAnalysis.Rename.DocumentRenameOptions.RenameMatchingTypeInStrings. Microsoft.CodeAnalysis.Rename.DocumentRenameOptions.RenameMatchingTypeInComments.init -> void static Microsoft.CodeAnalysis.Rename.Renamer.RenameDocumentAsync(Microsoft.CodeAnalysis.Document document, Microsoft.CodeAnalysis.Rename.DocumentRenameOptions options, string newDocumentName, System.Collections.Generic.IReadOnlyList newDocumentFolders = null, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task static Microsoft.CodeAnalysis.Rename.Renamer.RenameSymbolAsync(Microsoft.CodeAnalysis.Solution solution, Microsoft.CodeAnalysis.ISymbol symbol, Microsoft.CodeAnalysis.Rename.SymbolRenameOptions options, string newName, System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) -> System.Threading.Tasks.Task - -Microsoft.CodeAnalysis.Editing.OperatorKind.UnsignedRightShift = 26 -> Microsoft.CodeAnalysis.Editing.OperatorKind \ No newline at end of file +Microsoft.CodeAnalysis.Editing.OperatorKind.UnsignedRightShift = 26 -> Microsoft.CodeAnalysis.Editing.OperatorKind diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/ISymbolExtensions.cs b/src/Workspaces/Core/Portable/Shared/Extensions/ISymbolExtensions.cs index 5071112465fb2..e5525aa4b1c14 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/ISymbolExtensions.cs +++ b/src/Workspaces/Core/Portable/Shared/Extensions/ISymbolExtensions.cs @@ -33,7 +33,8 @@ public static DeclarationModifiers GetSymbolModifiers(this ISymbol symbol) isUnsafe: symbol.RequiresUnsafeModifier(), isVirtual: symbol.IsVirtual, isOverride: symbol.IsOverride, - isSealed: symbol.IsSealed); + isSealed: symbol.IsSealed, + isRequired: symbol.IsRequired()); } /// diff --git a/src/Workspaces/Core/Portable/Shared/Extensions/SyntaxGeneratorExtensions.cs b/src/Workspaces/Core/Portable/Shared/Extensions/SyntaxGeneratorExtensions.cs index d40fc5c753cfc..476546f982bd6 100644 --- a/src/Workspaces/Core/Portable/Shared/Extensions/SyntaxGeneratorExtensions.cs +++ b/src/Workspaces/Core/Portable/Shared/Extensions/SyntaxGeneratorExtensions.cs @@ -409,6 +409,11 @@ public static async Task OverridePropertyAsync( codeFactory.IdentifierName("value"))); } + // The user can add required if they want, but if the property being overridden is required, this one needs to be as well. + modifiers = modifiers.WithIsRequired(overriddenProperty.IsIndexer + ? false + : (modifiers.IsRequired || overriddenProperty.IsRequired)); + // Only generate a getter if the base getter is accessible. IMethodSymbol? accessorGet = null; if (overriddenProperty.GetMethod != null && overriddenProperty.GetMethod.IsAccessibleWithin(containingType)) @@ -507,6 +512,9 @@ private static async Task OverrideMethodAsync( Document newDocument, CancellationToken cancellationToken) { + // Required is not a valid modifier for methods, so clear it if the user typed it + modifiers = modifiers.WithIsRequired(false); + // Abstract: Throw not implemented if (overriddenMethod.IsAbstract) { diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CodeStyle/CSharpIdeCodeStyleOptions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CodeStyle/CSharpIdeCodeStyleOptions.cs index fa9248ac0eea3..f282254a41186 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CodeStyle/CSharpIdeCodeStyleOptions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CodeStyle/CSharpIdeCodeStyleOptions.cs @@ -25,6 +25,7 @@ internal sealed class CSharpIdeCodeStyleOptions : IdeCodeStyleOptions, IEquatabl SyntaxKind.VirtualKeyword, SyntaxKind.AbstractKeyword, SyntaxKind.SealedKeyword, SyntaxKind.OverrideKeyword, SyntaxKind.ReadOnlyKeyword, SyntaxKind.UnsafeKeyword, + SyntaxKind.RequiredKeyword, SyntaxKind.VolatileKeyword, SyntaxKind.AsyncKeyword); diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ISymbolExtensions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ISymbolExtensions.cs index 50904af7d6edc..36e48e9ae3fb7 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ISymbolExtensions.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/Core/Extensions/ISymbolExtensions.cs @@ -280,6 +280,9 @@ public static bool IsWriteableFieldOrProperty([NotNullWhen(returnValue: true)] t _ => false, }; + public static bool IsRequired([NotNullWhen(returnValue: true)] this ISymbol? symbol) + => symbol is IFieldSymbol { IsRequired: true } or IPropertySymbol { IsRequired: true }; + public static ITypeSymbol? GetMemberType(this ISymbol symbol) => symbol switch { diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Utilities/SyntaxKindSet.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Utilities/SyntaxKindSet.cs index 26b76911d2860..132a1de02a285 100644 --- a/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Utilities/SyntaxKindSet.cs +++ b/src/Workspaces/SharedUtilitiesAndExtensions/Workspace/CSharp/Utilities/SyntaxKindSet.cs @@ -38,6 +38,7 @@ internal class SyntaxKindSet SyntaxKind.PrivateKeyword, SyntaxKind.ProtectedKeyword, SyntaxKind.ReadOnlyKeyword, + SyntaxKind.RequiredKeyword, SyntaxKind.SealedKeyword, SyntaxKind.StaticKeyword, SyntaxKind.UnsafeKeyword,