diff --git a/src/Compilers/CSharp/Portable/Binder/Binder.cs b/src/Compilers/CSharp/Portable/Binder/Binder.cs index 363c8b60ca59598897f6475f0081a3ca887104e4..d6779d14dfdb0f88dd7169387d093a92a843b482 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder.cs @@ -329,6 +329,9 @@ internal virtual Imports GetImports(ConsList basesBeingResolved) return _next.GetImports(basesBeingResolved); } + protected virtual bool InExecutableBinder + => _next.InExecutableBinder; + /// /// The type containing the binding context /// diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs index a80989af3599893ab2fbc0c969a71b69e46ef7e9..e05bf782d0f4ae93124f4328961fb6fff8c8e0ef 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs @@ -338,11 +338,23 @@ internal NamespaceOrTypeOrAliasSymbolWithAnnotations BindNamespaceOrTypeOrAliasS { case SyntaxKind.NullableType: { - TypeSyntax typeArgumentSyntax = ((NullableTypeSyntax)syntax).ElementType; + var nullableSyntax = (NullableTypeSyntax)syntax; + TypeSyntax typeArgumentSyntax = nullableSyntax.ElementType; TypeSymbolWithAnnotations typeArgument = BindType(typeArgumentSyntax, diagnostics, basesBeingResolved); TypeSymbolWithAnnotations constructedType; if (Compilation.IsFeatureEnabled(MessageID.IDS_FeatureStaticNullChecking)) { + if (InExecutableBinder) + { + // Inside a method body or other executable code, we can afford to pull on NonNullTypes symbol or question IsValueType without causing cycles. + // Types created outside executable context should be checked by the responsible symbol (the method symbol checks its return type, for instance). + + if (!typeArgument.IsValueType && NonNullTypesContext.NonNullTypes != true) + { + diagnostics.Add(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, nullableSyntax.QuestionToken.GetLocation()); + } + } + constructedType = typeArgument.SetIsAnnotated(Compilation); if (!ShouldCheckConstraints) { diff --git a/src/Compilers/CSharp/Portable/Binder/BuckStopsHereBinder.cs b/src/Compilers/CSharp/Portable/Binder/BuckStopsHereBinder.cs index 15012a853822ed12ce50676355ef55b73a359433..343ba5b5012aa105813da1c20e00efdea5bb4a28 100644 --- a/src/Compilers/CSharp/Portable/Binder/BuckStopsHereBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/BuckStopsHereBinder.cs @@ -56,6 +56,8 @@ protected override LocalFunctionSymbol LookupLocalFunction(SyntaxToken nameToken internal override uint LocalScopeDepth => Binder.ExternalScope; + protected override bool InExecutableBinder => false; + internal override bool IsAccessibleHelper(Symbol symbol, TypeSymbol accessThroughType, out bool failedThroughTypeCheck, ref HashSet useSiteDiagnostics, ConsList basesBeingResolved) { failedThroughTypeCheck = false; diff --git a/src/Compilers/CSharp/Portable/Binder/ExecutableCodeBinder.cs b/src/Compilers/CSharp/Portable/Binder/ExecutableCodeBinder.cs index d38596fe670c8a830e5421f9d8c75a4c282ba703..f7cd439b1b321b4a158a91689a9250d386d73bf0 100644 --- a/src/Compilers/CSharp/Portable/Binder/ExecutableCodeBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/ExecutableCodeBinder.cs @@ -46,6 +46,9 @@ internal override Symbol ContainingMemberOrLambda get { return _memberSymbol ?? Next.ContainingMemberOrLambda; } } + protected override bool InExecutableBinder + => true; + internal Symbol MemberSymbol { get { return _memberSymbol; } } internal override Binder GetBinder(SyntaxNode node) diff --git a/src/Compilers/CSharp/Portable/Binder/InMethodBinder.cs b/src/Compilers/CSharp/Portable/Binder/InMethodBinder.cs index b316b4875aca126ae8503ff32658186a43b6b3f5..7f76216d7483b39aa4129b6b8a79f3d4406d59b7 100644 --- a/src/Compilers/CSharp/Portable/Binder/InMethodBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/InMethodBinder.cs @@ -66,6 +66,8 @@ protected override LocalFunctionSymbol LookupLocalFunction(SyntaxToken nameToken internal override uint LocalScopeDepth => Binder.TopLevelScope; + protected override bool InExecutableBinder => true; + internal override Symbol ContainingMemberOrLambda { get diff --git a/src/Compilers/CSharp/Portable/Binder/WithMethodTypeParametersBinder.cs b/src/Compilers/CSharp/Portable/Binder/WithMethodTypeParametersBinder.cs index 279522d8a17c200b386a206c60331937e5e876cb..61156c9d11b2b7a8ea5db02806ea1ec6c8699bbe 100644 --- a/src/Compilers/CSharp/Portable/Binder/WithMethodTypeParametersBinder.cs +++ b/src/Compilers/CSharp/Portable/Binder/WithMethodTypeParametersBinder.cs @@ -20,6 +20,8 @@ internal WithMethodTypeParametersBinder(MethodSymbol methodSymbol, Binder next) _methodSymbol = methodSymbol; } + protected override bool InExecutableBinder => false; + internal override Symbol ContainingMemberOrLambda { get diff --git a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs index 0d0a6e729e4933d5e0be2fd52916ea2ec4ce2022..9b8465b900d965ebe58de59dfd34371c499217f8 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs +++ b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs @@ -13970,7 +13970,7 @@ internal class CSharpResources { } /// - /// Looks up a localized string similar to The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context.. + /// Looks up a localized string similar to The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context.. /// internal static string WRN_MissingNonNullTypesContext { get { @@ -13979,7 +13979,7 @@ internal class CSharpResources { } /// - /// Looks up a localized string similar to The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context.. + /// Looks up a localized string similar to The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context.. /// internal static string WRN_MissingNonNullTypesContext_Title { get { @@ -13987,6 +13987,24 @@ internal class CSharpResources { } } + /// + /// Looks up a localized string similar to The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context.. + /// + internal static string WRN_MissingNonNullTypesContextForAnnotation { + get { + return ResourceManager.GetString("WRN_MissingNonNullTypesContextForAnnotation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context.. + /// + internal static string WRN_MissingNonNullTypesContextForAnnotation_Title { + get { + return ResourceManager.GetString("WRN_MissingNonNullTypesContextForAnnotation_Title", resourceCulture); + } + } + /// /// Looks up a localized string similar to Parameter '{0}' has no matching param tag in the XML comment for '{1}' (but other parameters do). /// diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 18f98fab1e667d7d7609212bca90d1c148b67de2..09e202b2be1c89f8b53d85e5ffabb674e8fc1f53 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -5369,6 +5369,12 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ The type cannot be used as type parameter in the generic type or method. Nullability of type argument doesn't match constraint type. + + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + + + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + Explicit application of 'System.Runtime.CompilerServices.NullableAttribute' is not allowed. @@ -5382,10 +5388,10 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Please use language version {0} or greater to use the NonNullTypes attribute. - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. A void or int returning entry point cannot be async @@ -5522,4 +5528,4 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ An out variable cannot be declared as a ref local - \ No newline at end of file + diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index da2b6239e124edb7ee7a1e645b16e2b2cc4975e3..2c4474771b42de1350b4fbbf0e472ca31e08f5fa 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -1616,6 +1616,7 @@ internal enum ErrorCode WRN_MissingNonNullTypesContext = 8629, ERR_NonNullTypesNotAvailable = 8630, WRN_NullabilityMismatchInTypeParameterConstraint = 8631, + WRN_MissingNonNullTypesContextForAnnotation = 8632, } // Note: you will need to re-generate compiler code after adding warnings (build\scripts\generate-compiler-code.cmd) } diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs index 412e076a3a83533db2b2af9f5b7b96010b635ab5..800d0ffa1192c4fbe9afaaf8d92a22d9c05c86a8 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs @@ -348,6 +348,7 @@ internal static int GetWarningLevel(ErrorCode code) case ErrorCode.WRN_TupleBinopLiteralNameMismatch: case ErrorCode.WRN_TypeParameterSameAsOuterMethodTypeParameter: case ErrorCode.WRN_MissingNonNullTypesContext: + case ErrorCode.WRN_MissingNonNullTypesContextForAnnotation: return 1; default: return 0; diff --git a/src/Compilers/CSharp/Portable/Generated/ErrorFacts.Generated.cs b/src/Compilers/CSharp/Portable/Generated/ErrorFacts.Generated.cs index 38e943285e5903bd332358d93703b690bee68841..0a63123cf036c5a2e33c08e6961a511342ec216a 100644 --- a/src/Compilers/CSharp/Portable/Generated/ErrorFacts.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/ErrorFacts.Generated.cs @@ -204,6 +204,7 @@ public static bool IsWarning(ErrorCode code) case ErrorCode.WRN_NoBestNullabilityConditionalExpression: case ErrorCode.WRN_MissingNonNullTypesContext: case ErrorCode.WRN_NullabilityMismatchInTypeParameterConstraint: + case ErrorCode.WRN_MissingNonNullTypesContextForAnnotation: return true; default: return false; diff --git a/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs index bdfdee88a42160fa98d001cf8e2c53a5e9097582..fe6c3597545ca1c25fe37e7b0397213c74ac2a3a 100644 --- a/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/MethodSymbol.cs @@ -964,7 +964,7 @@ internal virtual bool SynthesizesLoweredBoundBody { get { - return (AssociatedSymbol ?? ContainingType)?.NonNullTypes; + return (AssociatedSymbol ?? ContainingSymbol)?.NonNullTypes; } } diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index 991b8899b178462dc2d0a6622421b19f407ec3ef..60dc56a490285dc5b0288e656f522eef69e79654 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -403,13 +403,23 @@ - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. + + + + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + + + + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index 161b60dfa4143c310724a61b2803434c95ef41aa..e4baa9efd82fd97d9d57ffed0657990570252655 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -403,13 +403,23 @@ - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. + + + + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + + + + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index aa8b8ae4ea7be26c1633d7b3de3f742b60802111..5f471b46ceb837bfb548a2ce05076843202977f8 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -403,13 +403,23 @@ - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. + + + + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + + + + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index 1fa0516736b2f8ae92f0df891a699aac2dccdfc8..5b32e09535e9a9b0bc1b25d03a89041269546aac 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -403,13 +403,23 @@ - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. + + + + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + + + + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index deb1b51596c5aa4b254c58d6a38989b747bbc088..1709d6d9f1f25e276bdecbbf4edfb2889ff0af30 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -403,13 +403,23 @@ - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. + + + + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + + + + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index e93f9aaa013f97cc75436df2b375f9568d73ff41..562392542e816fde1d436c9c637cce991bcaa764 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -403,13 +403,23 @@ - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. + + + + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + + + + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index 952c8886c3cc614801048254dd71c12d0db42454..8e62f43e2a2ab2b93b37ce7a5bde54e794cb26b0 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -403,13 +403,23 @@ - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. + + + + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + + + + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index ff46f483c86ed27e98965da7aa7c6e861c55dce1..c8536dfe460e2a1e1aa7683ab81bc401f89c9f2d 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -403,13 +403,23 @@ - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. + + + + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + + + + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index 686e4c767b2fff4a6a2d6e5f95071d8c9bb6430c..1f8c24a2c993ea3aedcc4639bd56681ccb2bbf3e 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -403,13 +403,23 @@ - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. + + + + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + + + + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index 25c9e1797ac6589c6216e1ff0e2b40e9f25b3ca6..e480bd0699caaf9c59851472b9f4b6cf41f672db 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -403,13 +403,23 @@ - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. + + + + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + + + + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index 6323c77556dea1342d55516f8d0c9a18ebf81b13..4fb1a199151084119c27f78d7aff7aa1fa6c0901 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -403,13 +403,23 @@ - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. + + + + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + + + + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index 3f0fb9b568ec72097950baf06d76acd17fd35828..dc2ab9993d3a538be7b852d0411f90538de74a67 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -403,13 +403,23 @@ - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. + + + + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + + + + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index bc17a90d2227839ebf0e7c992876d956d05e7f70..1837bc40519c13374ded7208283ca0ffab0b8e7f 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -403,13 +403,23 @@ - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. + + + + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + + + + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. - The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. + The suppression operator (!) should be used in code with a '[NonNullTypes(true/false)]' context. diff --git a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_Nullable.cs b/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_Nullable.cs index f8424aece4c0723d602794e3c5025f455b3ea14a..83448ea0d655281a87e9ed18e124b6b8bf4d9559 100644 --- a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_Nullable.cs +++ b/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_Nullable.cs @@ -579,7 +579,7 @@ static void Main() new C(); } }"; - var comp2 = CreateCompilation(source2, parseOptions: TestOptions.Regular8, references: new[] { comp.EmitToImageReference() }); + var comp2 = CreateCompilation(new[] { source2, NonNullTypesTrue, NonNullTypesAttributesDefinition }, parseOptions: TestOptions.Regular8, references: new[] { comp.EmitToImageReference() }); comp2.VerifyDiagnostics(); var type = comp2.GetMember("C"); @@ -681,10 +681,10 @@ static void Main() new C(); } }"; - var comp2 = CreateCompilation(new[] { source, source2 }, parseOptions: TestOptions.Regular8); + var comp2 = CreateCompilation(new[] { source, source2, NonNullTypesTrue, NonNullTypesAttributesDefinition }, parseOptions: TestOptions.Regular8); comp2.VerifyEmitDiagnostics(); - comp2 = CreateCompilation(source2, parseOptions: TestOptions.Regular8, references: new[] { comp.EmitToImageReference() }); + comp2 = CreateCompilation(new[] { source2, NonNullTypesTrue, NonNullTypesAttributesDefinition }, parseOptions: TestOptions.Regular8, references: new[] { comp.EmitToImageReference() }); comp2.VerifyEmitDiagnostics(); var type = comp2.GetMember("C"); @@ -1292,7 +1292,7 @@ static void G() F((object? o) => { }); } }"; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular8, options: TestOptions.ReleaseModule); + var comp = CreateCompilation(new[] { source, NonNullTypesTrue, NonNullTypesAttributesDefinition }, parseOptions: TestOptions.Regular8, options: TestOptions.ReleaseModule); comp.VerifyEmitDiagnostics( // (9,12): error CS0518: Predefined type 'System.Runtime.CompilerServices.NullableAttribute' is not defined or imported // F((object? o) => { }); @@ -1311,7 +1311,7 @@ static void M() L(); } }"; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular8, options: TestOptions.ReleaseModule); + var comp = CreateCompilation(new[] { source, NonNullTypesTrue, NonNullTypesAttributesDefinition }, parseOptions: TestOptions.Regular8, options: TestOptions.ReleaseModule); comp.VerifyEmitDiagnostics( // (5,9): error CS0518: Predefined type 'System.Runtime.CompilerServices.NullableAttribute' is not defined or imported // object?[] L() => throw new System.NotImplementedException(); @@ -1330,7 +1330,7 @@ static void M() L(null, 2); } }"; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular8, options: TestOptions.ReleaseModule); + var comp = CreateCompilation(new[] { source, NonNullTypesTrue, NonNullTypesAttributesDefinition }, parseOptions: TestOptions.Regular8, options: TestOptions.ReleaseModule); comp.VerifyEmitDiagnostics( // (5,16): error CS0518: Predefined type 'System.Runtime.CompilerServices.NullableAttribute' is not defined or imported // void L(object? x, object y) { } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs index 5b6d3a4885e4c72236c683182ba8403aa9fb9636..3a876f6c7b9f45d1846fa8b9140afb71f67313fe 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs @@ -161,7 +161,7 @@ static void Main() } [Fact] - public void SuppressionOperatorWithoutNonNullTypesContext() + public void SuppressionWithoutNonNullTypes() { CSharpCompilation c = CreateCompilation(@" class C @@ -188,6 +188,117 @@ static void Main(string z = null!) ); } + [Fact] + public void AnnotationWithoutNonNullTypes() + { + CSharpCompilation c = CreateCompilation(@" +class C +{ + static string? field = M2(out string? x1); // warn 1 + static string? P + { + get + { + string? x2 = null; // warn 2 + return x2; + } + } + static string? MethodWithLocalFunction() + { + string? x3 = local(); // warn 3 + return x3; + + string? local() // warn 4 + { + string? x4 = null; // warn 5 + return x4; + } + } + static string? Lambda() + { + System.Func x5 = () => // warn 6 + { + string? x6 = null; // warn 7 + return x6; + }; + return x5(); + } + static string M2(out string? x4) => throw null; +} +", parseOptions: TestOptions.Regular8); + + // PROTOTYPE(NullableReferenceTypes): we need to warn on misuse of annotation every place a type could appear (not just in executable code) + c.VerifyDiagnostics( + // (4,41): warning CS8632: The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + // static string? field = M2(out string? x1); // warn 1 + Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(4, 41), + // (9,19): warning CS8632: The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + // string? x2 = null; // warn 2 + Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(9, 19), + // (15,15): warning CS8632: The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + // string? x3 = local(); // warn 3 + Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(15, 15), + // (20,19): warning CS8632: The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + // string? x4 = null; // warn 5 + Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(20, 19), + // (18,15): warning CS8632: The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + // string? local() // warn 4 + Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(18, 15), + // (26,27): warning CS8632: The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + // System.Func x5 = () => // warn 6 + Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(26, 27), + // (28,19): warning CS8632: The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + // string? x6 = null; // warn 7 + Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(28, 19) + ); + } + + [Fact] + public void AnnotationWithoutNonNullTypes_GenericType() + { + CSharpCompilation c = CreateCompilation(@" +public class C where T : class +{ + public T? M(T? x1) + { + T? y1 = x1; // warn + return y1; + } +} +public class E where T : struct +{ + public T? M(T? x2) + { + T? y2 = x2; + return y2; + } +} +", parseOptions: TestOptions.Regular8); + + // PROTOTYPE(NullableReferenceTypes): we need to warn on misuse of annotation every place a type could appear (not just in executable code) + c.VerifyDiagnostics( + // (6,10): warning CS8632: The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + // T? y1 = x1; // warn + Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(6, 10) + ); + + var client = @" +class Client +{ + void M(C c) + { + c.M("""").ToString(); + } +} +"; + var comp2 = CreateCompilation(client, references: new[] { c.EmitToImageReference() }, parseOptions: TestOptions.Regular8); + comp2.VerifyDiagnostics( + // (6,9): warning CS8602: Possible dereference of a null reference. + // c.M("").ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, @"c.M("""")").WithLocation(6, 9) + ); + } + [Fact] public void NullableAttribute_NotRequiredCSharp7_01() { @@ -2356,6 +2467,12 @@ public void M2() compilation.VerifyTypes(); compilation.VerifyDiagnostics( + // (14,24): warning CS8632: The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + // foreach (string? ns in NCollection()) + Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(14, 24), + // (34,24): warning CS8632: The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + // foreach (string? ns in FalseNCollection()) + Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(34, 24), // (16,13): warning CS8602: Possible dereference of a null reference. // ns /*T:string?*/ .ToString(); // warn 1 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "ns").WithLocation(16, 13), @@ -2517,6 +2634,12 @@ public void M() compilation.VerifyTypes(); compilation.VerifyDiagnostics( + // (13,24): warning CS8632: The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + // NOut(out string? ns2); + Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(13, 24), + // (21,29): warning CS8632: The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + // FalseNOut(out string? ns3); + Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(21, 29), // (14,9): warning CS8602: Possible dereference of a null reference. // ns2 /*T:string?*/ .ToString(); // warn 1 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "ns2").WithLocation(14, 9), @@ -2685,6 +2808,12 @@ public class Base compilation.VerifyTypes(); compilation.VerifyDiagnostics( + // (13,15): warning CS8628: The annotation for nullable reference types should only be used in code with a '[NonNullTypes(true)]' context. + // string? ns2 = NMethod(); + Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(13, 15), + // (21,15): warning CS8628: The annotation for nullable reference types should only be used in code with a '[NonNullTypes(true)]' context. + // string? ns3 = FalseNMethod(); + Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(21, 15), // (14,9): warning CS8602: Possible dereference of a null reference. // ns2 /*T:string?*/ .ToString(); // warn 1 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "ns2").WithLocation(14, 9), @@ -4951,7 +5080,13 @@ class B : A compilation.VerifyDiagnostics( // (18,31): warning CS8609: Nullability of reference types in return type doesn't match overridden member. // public override string?[] M1() - Diagnostic(ErrorCode.WRN_NullabilityMismatchInReturnTypeOnOverride, "M1").WithLocation(18, 31) + Diagnostic(ErrorCode.WRN_NullabilityMismatchInReturnTypeOnOverride, "M1").WithLocation(18, 31), + // (20,26): warning CS8628: The annotation for nullable reference types should only be used in code with a '[NonNullTypes(true)]' context. + // return new string?[] {}; + Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(20, 26), + // (26,21): warning CS8628: The annotation for nullable reference types should only be used in code with a '[NonNullTypes(true)]' context. + // return new S?[] {}; + Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(26, 21) ); } @@ -5121,7 +5256,13 @@ class B : IA compilation.VerifyDiagnostics( // (11,18): warning CS8616: Nullability of reference types in return type doesn't match implemented member 'string[] IA.M1()'. // string?[] IA.M1() - Diagnostic(ErrorCode.WRN_NullabilityMismatchInReturnTypeOnExplicitImplementation, "M1").WithArguments("string[] IA.M1()").WithLocation(11, 18) + Diagnostic(ErrorCode.WRN_NullabilityMismatchInReturnTypeOnExplicitImplementation, "M1").WithArguments("string[] IA.M1()").WithLocation(11, 18), + // (13,26): warning CS8628: The annotation for nullable reference types should only be used in code with a '[NonNullTypes(true)]' context. + // return new string?[] {}; + Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(13, 26), + // (19,21): warning CS8628: The annotation for nullable reference types should only be used in code with a '[NonNullTypes(true)]' context. + // return new S?[] {}; + Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(19, 21) ); } @@ -8203,7 +8344,7 @@ void M(string? s) [Fact] public void MethodWithOutNullableParameter_AfterNotNullWhenTrue() { - CSharpCompilation c = CreateCompilation(@" + CSharpCompilation c = CreateCompilation(new[] { @" using System.Runtime.CompilerServices; public class C { @@ -8225,7 +8366,7 @@ public void Main(string? s) } public static bool M([NotNullWhenTrue] string? s, out string? s2) => throw null; } -" + NotNullWhenTrueAttributeDefinition, parseOptions: TestOptions.Regular8); +", NonNullTypesTrue, NonNullTypesAttributesDefinition, NotNullWhenTrueAttributeDefinition }, parseOptions: TestOptions.Regular8); c.VerifyDiagnostics( // (10,13): warning CS8602: Possible dereference of a null reference. @@ -8249,7 +8390,7 @@ public void Main(string? s) [Fact] public void MethodWithOutNullableParameter_AfterEnsuresNotNull() { - CSharpCompilation c = CreateCompilation(@" + CSharpCompilation c = CreateCompilation(new[] { @" using System.Runtime.CompilerServices; public class C { @@ -8271,7 +8412,7 @@ public void Main(string? s) } public static bool M([EnsuresNotNull] string? s, out string? s2) => throw null; } -" + EnsuresNotNullAttributeDefinition, parseOptions: TestOptions.Regular8); +", NonNullTypesTrue, NonNullTypesAttributesDefinition, EnsuresNotNullAttributeDefinition }, parseOptions: TestOptions.Regular8); c.VerifyDiagnostics( // (10,13): warning CS8602: Possible dereference of a null reference. @@ -9309,7 +9450,7 @@ public void Main(string s) [Fact] public void NotNullWhenTrue_Simple() { - CSharpCompilation c = CreateCompilation(@" + CSharpCompilation c = CreateCompilation(new[] { @" using System.Runtime.CompilerServices; public class C { @@ -9328,7 +9469,7 @@ public void Main(string key) } public static bool TryGetValue(string key, [NotNullWhenTrue] out string? value) => throw null; } -" + NotNullWhenTrueAttributeDefinition, parseOptions: TestOptions.Regular8); +", NonNullTypesTrue, NonNullTypesAttributesDefinition, NotNullWhenTrueAttributeDefinition }, parseOptions: TestOptions.Regular8); c.VerifyDiagnostics( // (13,13): warning CS8602: Possible dereference of a null reference. @@ -9348,7 +9489,7 @@ public void NotNullWhenTrue_WithNotNullWhenFalse_WithVoidReturn() { // When both NotNullWhenTrue and NotNullWhenFalse are applied, it's the same as EnsuresNotNull, // even if the method doesn't return bool. - CSharpCompilation c = CreateCompilation(@" + CSharpCompilation c = CreateCompilation(new[] { @" using System.Runtime.CompilerServices; public class C { @@ -9359,7 +9500,7 @@ public void Main() } public static void M([NotNullWhenTrue, NotNullWhenFalse] out string? value) => throw null; } -" + NotNullWhenTrueAttributeDefinition + NotNullWhenFalseAttributeDefinition, parseOptions: TestOptions.Regular8); +", NonNullTypesTrue, NonNullTypesAttributesDefinition, NotNullWhenTrueAttributeDefinition, NotNullWhenFalseAttributeDefinition } , parseOptions: TestOptions.Regular8); c.VerifyDiagnostics(); @@ -12277,7 +12418,7 @@ void Test1(object x1, object? y1) [Fact] public void ConditionalBranching_14() { - var compilation = CreateCompilation(@" + var compilation = CreateCompilation(new[] { @" class C { C? _cField = null; @@ -12367,7 +12508,7 @@ void Test7(C? c7) } } } -", parseOptions: TestOptions.Regular8); +", NonNullTypesTrue, NonNullTypesAttributesDefinition }, parseOptions: TestOptions.Regular8); compilation.VerifyDiagnostics( // (17,13): warning CS8602: Possible dereference of a null reference. @@ -12802,7 +12943,7 @@ void Test(object? x) [Fact] public void ConditionalBranching_IsConstantPattern_NullConstant() { - CSharpCompilation c = CreateCompilation(@" + CSharpCompilation c = CreateCompilation(new[] { @" class C { void Test(object? x) @@ -12818,7 +12959,7 @@ void Test(object? x) } } } -", parseOptions: TestOptions.Regular8); +", NonNullTypesTrue, NonNullTypesAttributesDefinition }, parseOptions: TestOptions.Regular8); c.VerifyDiagnostics( // (9,13): warning CS8602: Possible dereference of a null reference. @@ -36997,7 +37138,7 @@ static void Main() o = new C(); // 2 } }"; - var comp = CreateCompilation(source1, new[] { ref0 }, parseOptions: TestOptions.Regular8); + var comp = CreateCompilation(new[] { source1, NonNullTypesTrue, NonNullTypesAttributesDefinition }, new[] { ref0 }, parseOptions: TestOptions.Regular8); comp.VerifyDiagnostics( // (6,19): error CS0454: Circular constraint dependency involving 'T' and 'T' // o = new C(); // 1 @@ -37031,7 +37172,7 @@ static void Main() o = new C(); // 4 } }"; - comp = CreateCompilation(source1, new[] { ref0 }, parseOptions: TestOptions.Regular8); + comp = CreateCompilation(new[] { source1, NonNullTypesTrue, NonNullTypesAttributesDefinition }, new[] { ref0 }, parseOptions: TestOptions.Regular8); // PROTOTYPE(NullableReferenceTypes): TypeSymbolExtensions.GetTypeRefWithAttributes // drops the top-level nullability when emitting the `T?` constraint. See also // AttributeTests_Nullable.EmitAttribute_Constraint_03. @@ -37659,6 +37800,71 @@ void verifyConstraintTypes(string methodName, params string[] expectedTypes) } } + [Fact] + public void Constraint_LocalFunction() + { + var source = @" +class C +{ + [System.Runtime.CompilerServices.NonNullTypes(true)] + void M1() + { + local(new C(), new C(), new C(), null); + void local(T t, T2 t2, T3 t3, string? s) where T : C where T2 : C? where T3 : T? + { + T? x = t; + x!.ToString(); + } + } + [System.Runtime.CompilerServices.NonNullTypes(false)] + void M2() + { + local(new C(), new C(), new C(), null); + void local(T t, T2 t2, T3 t3, string? s) where T : C where T2 : C? where T3 : T? + { + T? x = t; // warn 1 + x!.ToString(); + } + } + void M3() + { + local(new C(), new C(), new C(), null); + void local(T t, T2 t2, T3 t3, string? s) where T : C where T2 : C? where T3 : T? + { + T? x = t; // warn 2 + x!.ToString(); // warn 3 + } + } +}"; + var comp = CreateCompilation(new[] { source, NonNullTypesAttributesDefinition }, parseOptions: TestOptions.Regular8); + comp.VerifyDiagnostics( + // (20,14): warning CS8632: The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + // T? x = t; // warn 1 + Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(20, 14), + // (29,14): warning CS8632: The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + // T? x = t; // warn 2 + Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(29, 14), + // (30,13): warning CS8629: The suppression operator (!) should be used in code with a `[NonNullTypes(true/false)]` context. + // x!.ToString(); // warn 3 + Diagnostic(ErrorCode.WRN_MissingNonNullTypesContext, "x!").WithLocation(30, 13) + ); + var tree = comp.SyntaxTrees.First(); + var model = comp.GetSemanticModel(tree); + + var localSyntaxes = tree.GetRoot().DescendantNodes().OfType(); + + verifyLocalFunction(localSyntaxes.ElementAt(0), "C.M1.local", new[] { "C!" }); + verifyLocalFunction(localSyntaxes.ElementAt(1), "C.M2.local", new[] { "C" }); + verifyLocalFunction(localSyntaxes.ElementAt(2), "C.M3.local", new[] { "C" }); + + void verifyLocalFunction(LocalFunctionStatementSyntax localSyntax, string expectedName, string[] expectedConstraintTypes) + { + var localSymbol = (LocalFunctionSymbol)model.GetDeclaredSymbol(localSyntax); + var constraintTypes = localSymbol.TypeParameters[0].ConstraintTypesNoUseSiteDiagnostics; + AssertEx.Equal(expectedConstraintTypes, constraintTypes.SelectAsArray(t => t.ToTestDisplayString(true))); + } + } + [Fact] public void Constraint_Oblivious_01() { @@ -38182,9 +38388,19 @@ static void Main() var comp = CreateCompilation(source, parseOptions: TestOptions.Regular8, references: new[] { ref0 }); // PROTOTYPE(NullableReferenceTypes): Should report a warning for A0() and A2(). comp.VerifyDiagnostics( + // (5,22): warning CS8632: The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + // new A0(); // warning + Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(5, 22), + // (7,22): warning CS8632: The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + // new A2(); + Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(7, 22), + // (9,22): warning CS8632: The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + // new A5(); + Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(9, 22), // (9,16): warning CS8631: The type 'string?' cannot be used as type parameter 'T' in the generic type or method 'A5'. Nullability of type argument 'string?' doesn't match constraint type 'System.IEquatable'. // new A5(); - Diagnostic(ErrorCode.WRN_NullabilityMismatchInTypeParameterConstraint, "string?").WithArguments("A5", "System.IEquatable", "T", "string?").WithLocation(9, 16)); + Diagnostic(ErrorCode.WRN_NullabilityMismatchInTypeParameterConstraint, "string?").WithArguments("A5", "System.IEquatable", "T", "string?").WithLocation(9, 16) + ); verifyTypeParameterConstraint("A0", "System.IEquatable"); verifyTypeParameterConstraint("A1", "System.IEquatable"); verifyTypeParameterConstraint("A2", "System.IEquatable"); @@ -38198,7 +38414,17 @@ static void Main() ref0 = comp0.EmitToImageReference(); comp = CreateCompilation(source, parseOptions: TestOptions.Regular8, references: new[] { ref0 }); // PROTOTYPE(NullableReferenceTypes): Should report same warnings as other two cases. - comp.VerifyDiagnostics(); + comp.VerifyDiagnostics( + // (5,22): warning CS8632: The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + // new A0(); // warning + Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(5, 22), + // (7,22): warning CS8632: The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + // new A2(); + Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(7, 22), + // (9,22): warning CS8632: The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + // new A5(); + Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(9, 22) + ); verifyTypeParameterConstraint("A0", "System.IEquatable"); verifyTypeParameterConstraint("A1", "System.IEquatable"); verifyTypeParameterConstraint("A2", "System.IEquatable"); @@ -38213,9 +38439,19 @@ static void Main() comp = CreateCompilation(source, parseOptions: TestOptions.Regular8, references: new[] { ref0 }); // PROTOTYPE(NullableReferenceTypes): Should report a warning for A0() and A2(). comp.VerifyDiagnostics( + // (5,22): warning CS8632: The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + // new A0(); // warning + Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(5, 22), + // (7,22): warning CS8632: The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + // new A2(); + Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(7, 22), + // (9,22): warning CS8632: The annotation for nullable reference types should only be used in code within a '[NonNullTypes(true)]' context. + // new A5(); + Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(9, 22), // (9,16): warning CS8631: The type 'string?' cannot be used as type parameter 'T' in the generic type or method 'A5'. Nullability of type argument 'string?' doesn't match constraint type 'System.IEquatable'. // new A5(); - Diagnostic(ErrorCode.WRN_NullabilityMismatchInTypeParameterConstraint, "string?").WithArguments("A5", "System.IEquatable", "T", "string?").WithLocation(9, 16)); + Diagnostic(ErrorCode.WRN_NullabilityMismatchInTypeParameterConstraint, "string?").WithArguments("A5", "System.IEquatable", "T", "string?").WithLocation(9, 16) + ); verifyTypeParameterConstraint("A0", "System.IEquatable"); verifyTypeParameterConstraint("A1", "System.IEquatable"); verifyTypeParameterConstraint("A2", "System.IEquatable"); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/UninitializedNonNullableFieldTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/UninitializedNonNullableFieldTests.cs index 4baaa4e5e84a29b7069e7707f4018847ad48e4ba..78add55638bb70482cdbd07ecc48bf998d7aa201 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/UninitializedNonNullableFieldTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/UninitializedNonNullableFieldTests.cs @@ -385,7 +385,7 @@ internal C(object o) P2 = new object?[] { o }; } }"; - var comp = CreateCompilation(source, parseOptions: TestOptions.Regular8); + var comp = CreateCompilation(new[] { source, NonNullTypesTrue, NonNullTypesAttributesDefinition }, parseOptions: TestOptions.Regular8); comp.VerifyDiagnostics(); } diff --git a/src/Compilers/CSharp/Test/Syntax/Diagnostics/DiagnosticTest.cs b/src/Compilers/CSharp/Test/Syntax/Diagnostics/DiagnosticTest.cs index 24487e7f15ed8cd1bb7e7be322beb21021558338..066165950158c50cc914367c6fb6db4cee7b9cd6 100644 --- a/src/Compilers/CSharp/Test/Syntax/Diagnostics/DiagnosticTest.cs +++ b/src/Compilers/CSharp/Test/Syntax/Diagnostics/DiagnosticTest.cs @@ -281,6 +281,7 @@ public void WarningLevel_2() case ErrorCode.WRN_NoBestNullabilityConditionalExpression: case ErrorCode.WRN_MissingNonNullTypesContext: case ErrorCode.WRN_NullabilityMismatchInTypeParameterConstraint: + case ErrorCode.WRN_MissingNonNullTypesContextForAnnotation: Assert.Equal(1, ErrorFacts.GetWarningLevel(errorCode)); break; case ErrorCode.WRN_InvalidVersionFormat: