From 3aa5a3481c0116cab136c2d0bcbd8e77cb4d3375 Mon Sep 17 00:00:00 2001 From: yair halberstadt Date: Mon, 19 Oct 2020 08:34:02 +0300 Subject: [PATCH 01/14] nameof is allowed to access instance members in a static context, and to capture ref/struct this variables. This fixes a bug where members of instance members could not be accessed inside a nameof in a static context. --- .../Portable/Binder/Binder_Expressions.cs | 2 +- .../Test/Semantic/Semantics/NameOfTests.cs | 83 +++++++++++++++++++ 2 files changed, 84 insertions(+), 1 deletion(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index 3778f2ba83eb6..57e06ce589fca 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -1891,7 +1891,7 @@ private BoundExpression SynthesizeReceiver(SyntaxNode node, Symbol member, Diagn (currentType.IsInterface && (declaringType.IsObjectType() || currentType.AllInterfacesNoUseSiteDiagnostics.Contains(declaringType)))) { bool hasErrors = false; - if (EnclosingNameofArgument != node) + if (!IsInsideNameof) { if (InFieldInitializer && !currentType.IsScriptClass) { diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs index 0a0dc8c945aac..dadaee46079ec 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs @@ -1508,5 +1508,88 @@ public void nameof(string x) var option = TestOptions.ReleaseDll; CreateCompilation(source, options: option).VerifyDiagnostics(); } + + + [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] + public void TestCanReferenceInstanceMembersFromStaticMemberInNameof() + { + var source = @" +public class C +{ + public string S { get; } + public static string M() => nameof(S.Length); +}"; + CreateCompilation(source).VerifyDiagnostics(); + } + + [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] + public void TestCanReferenceInstanceMembersFromFieldInitializerInNameof() + { + var source = @" +public class C +{ + public string S { get; } = nameof(S.Length); +}"; + CreateCompilation(source).VerifyDiagnostics(); + } + + [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] + public void TestCanReferenceInstanceMembersFromAttributeInNameof() + { + var source = @" +public class C +{ + [System.Obsolete(nameof(S.Length))] + public int P { get; } + public string S { get; } +}"; + CreateCompilation(source).VerifyDiagnostics(); + } + + [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] + public void TestCanReferenceInstanceMembersFromConstructorInitializersInNameof() + { + var source = @" +public class C +{ + public C(string s){} + public C() : this(nameof(S.Length)){} + public string S { get; } +}"; + CreateCompilation(source).VerifyDiagnostics(); + } + + [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] + public void TestCanAccessStructInstancePropertyInLambdaInNameof() + { + var source = @" +using System; + +public struct S +{ + public string P { get; } + public void M(ref string x) + { + Func func = () => nameof(P.Length); + } +}"; + CreateCompilation(source).VerifyDiagnostics(); + } + + [Fact] + public void TestCanAccessRefParameterInLambdaInNameof() + { + var source = @" +using System; + +public struct S +{ + public void M(ref string x) + { + Func func = () => nameof(x.Length); + } +}"; + CreateCompilation(source).VerifyDiagnostics(); + } } } From c2149e42cfe9fac3d0b261cd48322014ed4df7e3 Mon Sep 17 00:00:00 2001 From: yair halberstadt Date: Mon, 16 Nov 2020 20:41:19 +0200 Subject: [PATCH 02/14] Only allow nameof to access members in static context in preview language version --- .../Portable/Binder/Binder_Expressions.cs | 16 +++- .../CSharp/Portable/CSharpResources.resx | 59 ++++++------ .../CSharp/Portable/Errors/MessageID.cs | 6 ++ .../Portable/xlf/CSharpResources.cs.xlf | 5 + .../Portable/xlf/CSharpResources.de.xlf | 5 + .../Portable/xlf/CSharpResources.es.xlf | 5 + .../Portable/xlf/CSharpResources.fr.xlf | 5 + .../Portable/xlf/CSharpResources.it.xlf | 5 + .../Portable/xlf/CSharpResources.ja.xlf | 5 + .../Portable/xlf/CSharpResources.ko.xlf | 5 + .../Portable/xlf/CSharpResources.pl.xlf | 5 + .../Portable/xlf/CSharpResources.pt-BR.xlf | 5 + .../Portable/xlf/CSharpResources.ru.xlf | 5 + .../Portable/xlf/CSharpResources.tr.xlf | 5 + .../Portable/xlf/CSharpResources.zh-Hans.xlf | 5 + .../Portable/xlf/CSharpResources.zh-Hant.xlf | 5 + .../Test/Semantic/Semantics/NameOfTests.cs | 92 +++++++++++++++++-- 17 files changed, 199 insertions(+), 39 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index 7fb9574c048aa..44ceb4a13f3b8 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -1891,18 +1891,19 @@ private BoundExpression SynthesizeReceiver(SyntaxNode node, Symbol member, Diagn (currentType.IsInterface && (declaringType.IsObjectType() || currentType.AllInterfacesNoUseSiteDiagnostics.Contains(declaringType)))) { bool hasErrors = false; - if (!IsInsideNameof) + if (!IsInsideNameof || EnclosingNameofArgument != node && !((CSharpParseOptions)node.SyntaxTree.Options).IsFeatureEnabled(MessageID.IDS_FeatureNameofAccessInstanceMembersInAllContexts)) { + var diagnosticsTemp = IsInsideNameof ? new DiagnosticBag() : diagnostics; if (InFieldInitializer && !currentType.IsScriptClass) { //can't access "this" in field initializers - Error(diagnostics, ErrorCode.ERR_FieldInitRefNonstatic, node, member); + Error(diagnosticsTemp, ErrorCode.ERR_FieldInitRefNonstatic, node, member); hasErrors = true; } else if (InConstructorInitializer || InAttributeArgument) { //can't access "this" in constructor initializers or attribute arguments - Error(diagnostics, ErrorCode.ERR_ObjectRequired, node, member); + Error(diagnosticsTemp, ErrorCode.ERR_ObjectRequired, node, member); hasErrors = true; } else @@ -1915,12 +1916,17 @@ private BoundExpression SynthesizeReceiver(SyntaxNode node, Symbol member, Diagn if (!locationIsInstanceMember) { // error CS0120: An object reference is required for the non-static field, method, or property '{0}' - Error(diagnostics, ErrorCode.ERR_ObjectRequired, node, member); + Error(diagnosticsTemp, ErrorCode.ERR_ObjectRequired, node, member); hasErrors = true; } } - hasErrors = hasErrors || IsRefOrOutThisParameterCaptured(node, diagnostics); + hasErrors = hasErrors || IsRefOrOutThisParameterCaptured(node, diagnosticsTemp); + + if (hasErrors && IsInsideNameof) + { + CheckFeatureAvailability(node, MessageID.IDS_FeatureNameofAccessInstanceMembersInAllContexts, diagnostics); + } } return ThisReference(node, currentType, hasErrors, wasCompilerGenerated: true); diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index c843076619698..2ea04e4bf61ee 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -1,17 +1,17 @@  - @@ -6588,4 +6588,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Parameter is unread. Did you forget to use it to initialize the property with that name? - + + nameof can access instance members in all contexts + + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/Errors/MessageID.cs b/src/Compilers/CSharp/Portable/Errors/MessageID.cs index ef50977339133..7a9aae7472c76 100644 --- a/src/Compilers/CSharp/Portable/Errors/MessageID.cs +++ b/src/Compilers/CSharp/Portable/Errors/MessageID.cs @@ -214,6 +214,8 @@ internal enum MessageID IDS_Parameter = MessageBase + 12789, IDS_Return = MessageBase + 12790, IDS_FeatureVarianceSafetyForStaticInterfaceMembers = MessageBase + 12791, + + IDS_FeatureNameofAccessInstanceMembersInAllContexts = MessageBase + 12792, } // Message IDs may refer to strings that need to be localized. @@ -320,6 +322,10 @@ internal static LanguageVersion RequiredVersion(this MessageID feature) // Checks are in the LanguageParser unless otherwise noted. switch (feature) { + // preview features. + case MessageID.IDS_FeatureNameofAccessInstanceMembersInAllContexts: + return LanguageVersion.Preview; + // C# 9.0 features. case MessageID.IDS_FeatureLambdaDiscardParameters: // semantic check case MessageID.IDS_FeatureFunctionPointers: diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index 7ec6b35cb970f..0564560f7fe7e 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -947,6 +947,11 @@ zahození + + nameof can access instance members in all contexts + nameof can access instance members in all contexts + + The assembly '{0}' containing type '{1}' references .NET Framework, which is not supported. The assembly '{0}' containing type '{1}' references .NET Framework, which is not supported. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index e6f844082b98e..24e694c3fd93a 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -947,6 +947,11 @@ Verwerfungen + + nameof can access instance members in all contexts + nameof can access instance members in all contexts + + The assembly '{0}' containing type '{1}' references .NET Framework, which is not supported. The assembly '{0}' containing type '{1}' references .NET Framework, which is not supported. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index fe758f1e1a157..1765de299c5ea 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -947,6 +947,11 @@ descarta + + nameof can access instance members in all contexts + nameof can access instance members in all contexts + + The assembly '{0}' containing type '{1}' references .NET Framework, which is not supported. The assembly '{0}' containing type '{1}' references .NET Framework, which is not supported. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index 27d6f1197fc99..e59cd4780ea32 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -947,6 +947,11 @@ abandons + + nameof can access instance members in all contexts + nameof can access instance members in all contexts + + The assembly '{0}' containing type '{1}' references .NET Framework, which is not supported. The assembly '{0}' containing type '{1}' references .NET Framework, which is not supported. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index 05288f53d8778..5ddd62ad211b6 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -947,6 +947,11 @@ rimuove + + nameof can access instance members in all contexts + nameof can access instance members in all contexts + + The assembly '{0}' containing type '{1}' references .NET Framework, which is not supported. The assembly '{0}' containing type '{1}' references .NET Framework, which is not supported. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index 28f64d42589dd..189907e3698bd 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -947,6 +947,11 @@ 破棄 + + nameof can access instance members in all contexts + nameof can access instance members in all contexts + + The assembly '{0}' containing type '{1}' references .NET Framework, which is not supported. The assembly '{0}' containing type '{1}' references .NET Framework, which is not supported. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index 002e9df6ed418..d7cb59bb86823 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -947,6 +947,11 @@ 무시 항목 + + nameof can access instance members in all contexts + nameof can access instance members in all contexts + + The assembly '{0}' containing type '{1}' references .NET Framework, which is not supported. The assembly '{0}' containing type '{1}' references .NET Framework, which is not supported. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index 48508e910f7d1..13bd1e86d2848 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -947,6 +947,11 @@ odrzucenia + + nameof can access instance members in all contexts + nameof can access instance members in all contexts + + The assembly '{0}' containing type '{1}' references .NET Framework, which is not supported. The assembly '{0}' containing type '{1}' references .NET Framework, which is not supported. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index 3a4aeed90919f..ea89ab2f03220 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -947,6 +947,11 @@ descarta + + nameof can access instance members in all contexts + nameof can access instance members in all contexts + + The assembly '{0}' containing type '{1}' references .NET Framework, which is not supported. The assembly '{0}' containing type '{1}' references .NET Framework, which is not supported. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index e392a33e387cd..ae3ce54bf6f30 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -947,6 +947,11 @@ отменяет + + nameof can access instance members in all contexts + nameof can access instance members in all contexts + + The assembly '{0}' containing type '{1}' references .NET Framework, which is not supported. The assembly '{0}' containing type '{1}' references .NET Framework, which is not supported. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index 40f39af32a009..1aca96032a08e 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -947,6 +947,11 @@ atmalar + + nameof can access instance members in all contexts + nameof can access instance members in all contexts + + The assembly '{0}' containing type '{1}' references .NET Framework, which is not supported. The assembly '{0}' containing type '{1}' references .NET Framework, which is not supported. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index 2ba99ed12f061..8997fd320663e 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -947,6 +947,11 @@ 放弃 + + nameof can access instance members in all contexts + nameof can access instance members in all contexts + + The assembly '{0}' containing type '{1}' references .NET Framework, which is not supported. The assembly '{0}' containing type '{1}' references .NET Framework, which is not supported. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index 6909c740dc23b..d97ed5cd3de36 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -947,6 +947,11 @@ 捨棄 + + nameof can access instance members in all contexts + nameof can access instance members in all contexts + + The assembly '{0}' containing type '{1}' references .NET Framework, which is not supported. The assembly '{0}' containing type '{1}' references .NET Framework, which is not supported. diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs index dadaee46079ec..cb40db1ce8ffd 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs @@ -1509,7 +1509,6 @@ public void nameof(string x) CreateCompilation(source, options: option).VerifyDiagnostics(); } - [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] public void TestCanReferenceInstanceMembersFromStaticMemberInNameof() { @@ -1519,7 +1518,7 @@ public class C public string S { get; } public static string M() => nameof(S.Length); }"; - CreateCompilation(source).VerifyDiagnostics(); + CreateCompilation(source, parseOptions: TestOptions.RegularPreview).VerifyDiagnostics(); } [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] @@ -1530,7 +1529,7 @@ public class C { public string S { get; } = nameof(S.Length); }"; - CreateCompilation(source).VerifyDiagnostics(); + CreateCompilation(source, parseOptions: TestOptions.RegularPreview).VerifyDiagnostics(); } [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] @@ -1543,7 +1542,7 @@ public class C public int P { get; } public string S { get; } }"; - CreateCompilation(source).VerifyDiagnostics(); + CreateCompilation(source, parseOptions: TestOptions.RegularPreview).VerifyDiagnostics(); } [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] @@ -1556,7 +1555,7 @@ public C(string s){} public C() : this(nameof(S.Length)){} public string S { get; } }"; - CreateCompilation(source).VerifyDiagnostics(); + CreateCompilation(source, parseOptions: TestOptions.RegularPreview).VerifyDiagnostics(); } [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] @@ -1573,7 +1572,88 @@ public void M(ref string x) Func func = () => nameof(P.Length); } }"; - CreateCompilation(source).VerifyDiagnostics(); + CreateCompilation(source, parseOptions: TestOptions.RegularPreview).VerifyDiagnostics(); + } + + [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] + public void TestCannotReferenceInstanceMembersFromStaticMemberInNameofInCSharp9() + { + var source = @" +public class C +{ + public string S { get; } + public static string M() => nameof(S.Length); +}"; + CreateCompilation(source, parseOptions: TestOptions.Regular9).VerifyDiagnostics( + // (5,40): error CS8652: The feature 'nameof can access instance members in all contexts' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public static string M() => nameof(S.Length); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "S").WithArguments("nameof can access instance members in all contexts").WithLocation(5, 40)); + } + + [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] + public void TestCannotReferenceInstanceMembersFromFieldInitializerInNameofInCSharp9() + { + var source = @" +public class C +{ + public string S { get; } = nameof(S.Length); +}"; + CreateCompilation(source, parseOptions: TestOptions.Regular9).VerifyDiagnostics( + // (4,39): error CS8652: The feature 'nameof can access instance members in all contexts' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public string S { get; } = nameof(S.Length); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "S").WithArguments("nameof can access instance members in all contexts").WithLocation(4, 39)); + } + + [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] + public void TestCannotReferenceInstanceMembersFromAttributeInNameofInCSharp9() + { + var source = @" +public class C +{ + [System.Obsolete(nameof(S.Length))] + public int P { get; } + public string S { get; } +}"; + CreateCompilation(source, parseOptions: TestOptions.Regular9).VerifyDiagnostics( + // (4,29): error CS8652: The feature 'nameof can access instance members in all contexts' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // [System.Obsolete(nameof(S.Length))] + Diagnostic(ErrorCode.ERR_FeatureInPreview, "S").WithArguments("nameof can access instance members in all contexts").WithLocation(4, 29)); + } + + [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] + public void TestCannotReferenceInstanceMembersFromConstructorInitializersInNameofInCSharp9() + { + var source = @" +public class C +{ + public C(string s){} + public C() : this(nameof(S.Length)){} + public string S { get; } +}"; + CreateCompilation(source, parseOptions: TestOptions.Regular9).VerifyDiagnostics( + // (5,30): error CS8652: The feature 'nameof can access instance members in all contexts' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public C() : this(nameof(S.Length)){} + Diagnostic(ErrorCode.ERR_FeatureInPreview, "S").WithArguments("nameof can access instance members in all contexts").WithLocation(5, 30)); + } + + [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] + public void TestCannotAccessStructInstancePropertyInLambdaInNameofInCSharp9() + { + var source = @" +using System; + +public struct S +{ + public string P { get; } + public void M(ref string x) + { + Func func = () => nameof(P.Length); + } +}"; + CreateCompilation(source, parseOptions: TestOptions.Regular9).VerifyDiagnostics( + // (9,42): error CS8652: The feature 'nameof can access instance members in all contexts' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // Func func = () => nameof(P.Length); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "P").WithArguments("nameof can access instance members in all contexts").WithLocation(9, 42)); } [Fact] From dd4df9f0c32a9cbd42b58ddb96230c8b9555c909 Mon Sep 17 00:00:00 2001 From: yair halberstadt Date: Thu, 24 Dec 2020 22:07:44 +0000 Subject: [PATCH 03/14] Changes based on review by @333fred. Allow accessing static members from an instance in nameof --- .../Portable/Binder/Binder_Expressions.cs | 21 ++- .../CSharp/Portable/Binder/Binder_Symbols.cs | 6 + .../CSharp/Portable/CSharpResources.resx | 6 +- .../CSharp/Portable/Errors/MessageID.cs | 4 +- .../Portable/xlf/CSharpResources.cs.xlf | 8 +- .../Portable/xlf/CSharpResources.de.xlf | 8 +- .../Portable/xlf/CSharpResources.es.xlf | 8 +- .../Portable/xlf/CSharpResources.fr.xlf | 8 +- .../Portable/xlf/CSharpResources.it.xlf | 8 +- .../Portable/xlf/CSharpResources.ja.xlf | 8 +- .../Portable/xlf/CSharpResources.ko.xlf | 8 +- .../Portable/xlf/CSharpResources.pl.xlf | 8 +- .../Portable/xlf/CSharpResources.pt-BR.xlf | 8 +- .../Portable/xlf/CSharpResources.ru.xlf | 8 +- .../Portable/xlf/CSharpResources.tr.xlf | 8 +- .../Portable/xlf/CSharpResources.zh-Hans.xlf | 8 +- .../Portable/xlf/CSharpResources.zh-Hant.xlf | 8 +- .../Test/Semantic/Semantics/NameOfTests.cs | 140 ++++++++++++++++-- 18 files changed, 203 insertions(+), 78 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index 5cd8f3a9af0e8..05d730cea3907 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -1891,7 +1891,7 @@ private BoundExpression SynthesizeReceiver(SyntaxNode node, Symbol member, Diagn (currentType.IsInterface && (declaringType.IsObjectType() || currentType.AllInterfacesNoUseSiteDiagnostics.Contains(declaringType)))) { bool hasErrors = false; - if (!IsInsideNameof || EnclosingNameofArgument != node && !((CSharpParseOptions)node.SyntaxTree.Options).IsFeatureEnabled(MessageID.IDS_FeatureNameofAccessInstanceMembersInAllContexts)) + if (!IsInsideNameof || (EnclosingNameofArgument != node && !IsFeatureEnabled(node, MessageID.IDS_FeatureReducedMemberAccessChecksInNameof))) { var diagnosticsTemp = IsInsideNameof ? new DiagnosticBag() : diagnostics; if (InFieldInitializer && !currentType.IsScriptClass) @@ -1925,7 +1925,7 @@ private BoundExpression SynthesizeReceiver(SyntaxNode node, Symbol member, Diagn if (hasErrors && IsInsideNameof) { - CheckFeatureAvailability(node, MessageID.IDS_FeatureNameofAccessInstanceMembersInAllContexts, diagnostics); + CheckFeatureAvailability(node, MessageID.IDS_FeatureReducedMemberAccessChecksInNameof, diagnostics); } } @@ -7027,12 +7027,19 @@ private bool CheckInstanceOrStatic( if (!symbol.RequiresInstanceReceiver()) { - if (instanceReceiver == true) + if (instanceReceiver == true && !(IsInsideNameof && IsFeatureAvalable(node, MessageID.IDS_FeatureReducedMemberAccessChecksInNameof))) { - ErrorCode errorCode = this.Flags.Includes(BinderFlags.ObjectInitializerMember) ? - ErrorCode.ERR_StaticMemberInObjectInitializer : - ErrorCode.ERR_ObjectProhibited; - Error(diagnostics, errorCode, node, symbol); + if (!IsInsideNameof) + { + ErrorCode errorCode = this.Flags.Includes(BinderFlags.ObjectInitializerMember) ? + ErrorCode.ERR_StaticMemberInObjectInitializer : + ErrorCode.ERR_ObjectProhibited; + Error(diagnostics, errorCode, node, symbol); + } + else + { + CheckFeatureAvailability(node, MessageID.IDS_FeatureReducedMemberAccessChecksInNameof, diagnostics); + } resultKind = LookupResultKind.StaticInstanceMismatch; return true; } diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs index a79f20b35559e..832575fca9fdb 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs @@ -2456,6 +2456,12 @@ protected AssemblySymbol GetForwardedToAssembly(string name, int arity, ref Name } #nullable enable + + internal static bool IsFeatureAvalable(SyntaxNode syntax, MessageID feature) + { + return ((CSharpParseOptions)syntax.SyntaxTree.Options).IsFeatureEnabled(feature); + } + internal static bool CheckFeatureAvailability(SyntaxNode syntax, MessageID feature, DiagnosticBag diagnostics, Location? location = null) { return CheckFeatureAvailability(syntax.SyntaxTree, feature, diagnostics, location ?? syntax.GetLocation()); diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 72ec9654589d8..b51e257226502 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -6591,8 +6591,8 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Parameter is unread. Did you forget to use it to initialize the property with that name? - - nameof can access instance members in all contexts + + reduced member access checks in 'nameof' The primary constructor conflicts with the synthesized copy constructor. @@ -6603,4 +6603,4 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Do not compare function pointer values - + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/Errors/MessageID.cs b/src/Compilers/CSharp/Portable/Errors/MessageID.cs index 37b1df6161f55..9d4caea9f9730 100644 --- a/src/Compilers/CSharp/Portable/Errors/MessageID.cs +++ b/src/Compilers/CSharp/Portable/Errors/MessageID.cs @@ -215,7 +215,7 @@ internal enum MessageID IDS_Return = MessageBase + 12790, IDS_FeatureVarianceSafetyForStaticInterfaceMembers = MessageBase + 12791, IDS_FeatureConstantInterpolatedStrings = MessageBase + 12792, - IDS_FeatureNameofAccessInstanceMembersInAllContexts = MessageBase + 12793, + IDS_FeatureReducedMemberAccessChecksInNameof = MessageBase + 12793, } // Message IDs may refer to strings that need to be localized. @@ -323,7 +323,7 @@ internal static LanguageVersion RequiredVersion(this MessageID feature) switch (feature) { // preview features. - case MessageID.IDS_FeatureNameofAccessInstanceMembersInAllContexts: + case MessageID.IDS_FeatureReducedMemberAccessChecksInNameof: return LanguageVersion.Preview; // C# 9.0 features. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index d81cfcb4f830f..bd03af0e979d5 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -962,9 +962,9 @@ Vytvoření objektu s cílovým typem - - nameof can access instance members in all contexts - nameof can access instance members in all contexts + + reduced member access checks in 'nameof' + reduced member access checks in 'nameof' @@ -10844,4 +10844,4 @@ Pokud chcete odstranit toto varování, můžete místo toho použít /reference - + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index 762c4999632e3..f8e0ca0070439 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -962,9 +962,9 @@ Objekterstellung mit Zieltyp - - nameof can access instance members in all contexts - nameof can access instance members in all contexts + + reduced member access checks in 'nameof' + reduced member access checks in 'nameof' @@ -10844,4 +10844,4 @@ Um die Warnung zu beheben, können Sie stattdessen /reference verwenden (Einbett - + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index 39c0850b7189b..a7b1097ee74bf 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -962,9 +962,9 @@ creación de objetos con tipo de destino - - nameof can access instance members in all contexts - nameof can access instance members in all contexts + + reduced member access checks in 'nameof' + reduced member access checks in 'nameof' @@ -10844,4 +10844,4 @@ Para eliminar la advertencia puede usar /reference (establezca la propiedad Embe - + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index 64466a07a5554..f9ba9b282422d 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -962,9 +962,9 @@ création d'un objet typé cible - - nameof can access instance members in all contexts - nameof can access instance members in all contexts + + reduced member access checks in 'nameof' + reduced member access checks in 'nameof' @@ -10844,4 +10844,4 @@ Pour supprimer l'avertissement, vous pouvez utiliser la commande /reference (dé - + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index 3a7144621438f..71e5644089236 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -962,9 +962,9 @@ creazione di oggetti con tipo di destinazione - - nameof can access instance members in all contexts - nameof can access instance members in all contexts + + reduced member access checks in 'nameof' + reduced member access checks in 'nameof' @@ -10844,4 +10844,4 @@ Per rimuovere l'avviso, è invece possibile usare /reference (impostare la propr - + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index 14e80ce9f5205..37bededd86e1f 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -962,9 +962,9 @@ target-typed object creation - - nameof can access instance members in all contexts - nameof can access instance members in all contexts + + reduced member access checks in 'nameof' + reduced member access checks in 'nameof' @@ -10839,4 +10839,4 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ - + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index ffe7b14988547..5dd1fe718687e 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -962,9 +962,9 @@ target-typed object creation - - nameof can access instance members in all contexts - nameof can access instance members in all contexts + + reduced member access checks in 'nameof' + reduced member access checks in 'nameof' @@ -10839,4 +10839,4 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ - + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index 8632f5d5a1a10..baba371ea4374 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -962,9 +962,9 @@ target-typed object creation - - nameof can access instance members in all contexts - nameof can access instance members in all contexts + + reduced member access checks in 'nameof' + reduced member access checks in 'nameof' @@ -10839,4 +10839,4 @@ Aby usunąć ostrzeżenie, możesz zamiast tego użyć opcji /reference (ustaw w - + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index c8fe0ca41e0bd..824595cf242cf 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -962,9 +962,9 @@ target-typed object creation - - nameof can access instance members in all contexts - nameof can access instance members in all contexts + + reduced member access checks in 'nameof' + reduced member access checks in 'nameof' @@ -10837,4 +10837,4 @@ Para incorporar informações de tipo de interoperabilidade para os dois assembl - + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index 76f1d51e20917..a0a4e9458cc99 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -962,9 +962,9 @@ target-typed object creation - - nameof can access instance members in all contexts - nameof can access instance members in all contexts + + reduced member access checks in 'nameof' + reduced member access checks in 'nameof' @@ -10839,4 +10839,4 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ - + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index 61728adea758d..b97ac76dba5ae 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -962,9 +962,9 @@ target-typed object creation - - nameof can access instance members in all contexts - nameof can access instance members in all contexts + + reduced member access checks in 'nameof' + reduced member access checks in 'nameof' @@ -10839,4 +10839,4 @@ Uyarıyı kaldırmak için, /reference kullanabilirsiniz (Birlikte Çalışma T - + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index f3efa5428e1cb..3a1ff4ea5548e 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -962,9 +962,9 @@ target-typed object creation - - nameof can access instance members in all contexts - nameof can access instance members in all contexts + + reduced member access checks in 'nameof' + reduced member access checks in 'nameof' @@ -10839,4 +10839,4 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ - + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index e88f9da8906a8..61a5f9ffb13e7 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -962,9 +962,9 @@ target-typed object creation - - nameof can access instance members in all contexts - nameof can access instance members in all contexts + + reduced member access checks in 'nameof' + reduced member access checks in 'nameof' @@ -10839,4 +10839,4 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ - + \ No newline at end of file diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs index cb40db1ce8ffd..bcb585230e507 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs @@ -1513,23 +1513,55 @@ public void nameof(string x) public void TestCanReferenceInstanceMembersFromStaticMemberInNameof() { var source = @" +System.Console.Write(C.M()); public class C { - public string S { get; } - public static string M() => nameof(S.Length); + public C1 Property { get; } + public C1 Field { get; } + public event System.Action Event; + public static string M() => nameof(Property.Property) + + "","" + nameof(Property.Field) + + "","" + nameof(Property.Method) + + "","" + nameof(Property.Event) + + "","" + nameof(Property.Event) + + "","" + nameof(Field.Property) + + "","" + nameof(Field.Field) + + "","" + nameof(Field.Method) + + "","" + nameof(Field.Event) + + "","" + nameof(Field.Event) + + "","" + nameof(Event.Invoke) + ; +} + +public class C1 +{ + public int Property { get; } + public int Field; + public void Method(){} + public event System.Action Event; }"; - CreateCompilation(source, parseOptions: TestOptions.RegularPreview).VerifyDiagnostics(); + CompileAndVerify( + source, + options: TestOptions.DebugExe, + parseOptions: TestOptions.RegularPreview, + expectedOutput: "Property,Field,Method,Event,Event,Property,Field,Method,Event,Event,Invoke").VerifyDiagnostics(); + } [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] public void TestCanReferenceInstanceMembersFromFieldInitializerInNameof() { var source = @" +System.Console.Write(new C().S); public class C { public string S { get; } = nameof(S.Length); }"; - CreateCompilation(source, parseOptions: TestOptions.RegularPreview).VerifyDiagnostics(); + CompileAndVerify( + source, + options: TestOptions.DebugExe, + parseOptions: TestOptions.RegularPreview, + expectedOutput: "Length").VerifyDiagnostics(); } [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] @@ -1575,6 +1607,57 @@ public void M(ref string x) CreateCompilation(source, parseOptions: TestOptions.RegularPreview).VerifyDiagnostics(); } + [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] + public void TestCanReferenceStaticMembersFromInstanceMemberInNameof1() + { + var source = @" +public class C +{ + public C Prop { get; } + public static int StaticProp { get; } + public string M() => nameof(Prop.StaticProp); +}"; + CreateCompilation(source, parseOptions: TestOptions.RegularPreview).VerifyDiagnostics(); + } + + [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] + public void TestCanReferenceStaticMembersFromInstanceMemberInNameof2() + { + var source = @" +public class C +{ + public C Prop { get; } + public static int StaticProp { get; } + public static string M() => nameof(Prop.StaticProp); +}"; + CreateCompilation(source, parseOptions: TestOptions.RegularPreview).VerifyDiagnostics(); + } + + [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] + public void TestCanReferenceStaticMembersFromInstanceMemberInNameof3() + { + var source = @" +public class C +{ + public C Prop { get; } + public static string M() => nameof(Prop.M); +}"; + CreateCompilation(source, parseOptions: TestOptions.RegularPreview).VerifyDiagnostics(); + } + + [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] + public void TestCanReferenceStaticMembersFromInstanceMemberInNameof4() + { + var source = @" +public class C +{ + public C Prop { get; } + public static void StaticMethod(){} + public string M() => nameof(Prop.StaticMethod); +}"; + CreateCompilation(source, parseOptions: TestOptions.RegularPreview).VerifyDiagnostics(); + } + [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] public void TestCannotReferenceInstanceMembersFromStaticMemberInNameofInCSharp9() { @@ -1585,9 +1668,9 @@ public class C public static string M() => nameof(S.Length); }"; CreateCompilation(source, parseOptions: TestOptions.Regular9).VerifyDiagnostics( - // (5,40): error CS8652: The feature 'nameof can access instance members in all contexts' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (5,40): error CS8652: The feature 'reduced member access checks in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // public static string M() => nameof(S.Length); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "S").WithArguments("nameof can access instance members in all contexts").WithLocation(5, 40)); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "S").WithArguments("reduced member access checks in 'nameof'").WithLocation(5, 40)); } [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] @@ -1599,9 +1682,9 @@ public class C public string S { get; } = nameof(S.Length); }"; CreateCompilation(source, parseOptions: TestOptions.Regular9).VerifyDiagnostics( - // (4,39): error CS8652: The feature 'nameof can access instance members in all contexts' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (4,39): error CS8652: The feature 'reduced member access checks in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // public string S { get; } = nameof(S.Length); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "S").WithArguments("nameof can access instance members in all contexts").WithLocation(4, 39)); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "S").WithArguments("reduced member access checks in 'nameof'").WithLocation(4, 39)); } [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] @@ -1615,9 +1698,9 @@ public class C public string S { get; } }"; CreateCompilation(source, parseOptions: TestOptions.Regular9).VerifyDiagnostics( - // (4,29): error CS8652: The feature 'nameof can access instance members in all contexts' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (4,29): error CS8652: The feature 'reduced member access checks in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // [System.Obsolete(nameof(S.Length))] - Diagnostic(ErrorCode.ERR_FeatureInPreview, "S").WithArguments("nameof can access instance members in all contexts").WithLocation(4, 29)); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "S").WithArguments("reduced member access checks in 'nameof'").WithLocation(4, 29)); } [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] @@ -1631,9 +1714,9 @@ public C() : this(nameof(S.Length)){} public string S { get; } }"; CreateCompilation(source, parseOptions: TestOptions.Regular9).VerifyDiagnostics( - // (5,30): error CS8652: The feature 'nameof can access instance members in all contexts' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (5,30): error CS8652: The feature 'reduced member access checks in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // public C() : this(nameof(S.Length)){} - Diagnostic(ErrorCode.ERR_FeatureInPreview, "S").WithArguments("nameof can access instance members in all contexts").WithLocation(5, 30)); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "S").WithArguments("reduced member access checks in 'nameof'").WithLocation(5, 30)); } [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] @@ -1651,9 +1734,38 @@ public void M(ref string x) } }"; CreateCompilation(source, parseOptions: TestOptions.Regular9).VerifyDiagnostics( - // (9,42): error CS8652: The feature 'nameof can access instance members in all contexts' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (9,42): error CS8652: The feature 'reduced member access checks in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // Func func = () => nameof(P.Length); - Diagnostic(ErrorCode.ERR_FeatureInPreview, "P").WithArguments("nameof can access instance members in all contexts").WithLocation(9, 42)); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "P").WithArguments("reduced member access checks in 'nameof'").WithLocation(9, 42)); + } + + [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] + public void TestCannotReferenceStaticPropertyFromInstanceMemberInNameofInCSharp9() + { + var source = @" +public class C +{ + public C Prop { get; } + public static int StaticProp { get; } + public string M() => nameof(Prop.StaticProp); +}"; + CreateCompilation(source, parseOptions: TestOptions.Regular9).VerifyDiagnostics( + // (6,33): error CS8652: The feature 'reduced member access checks in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public string M() => nameof(Prop.StaticProp); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Prop.StaticProp").WithArguments("reduced member access checks in 'nameof'").WithLocation(6, 33)); + } + + [Fact] + public void TestCanReferenceStaticMethodFromInstanceMemberInNameofInCSharp9() + { + var source = @" +public class C +{ + public C Prop { get; } + public static void StaticMethod(){} + public string M() => nameof(Prop.StaticMethod); +}"; + CreateCompilation(source, parseOptions: TestOptions.Regular9).VerifyDiagnostics(); } [Fact] From 561251f5e6cd49be181c0be6a9351416fa964323 Mon Sep 17 00:00:00 2001 From: yair halberstadt Date: Thu, 24 Dec 2020 22:21:07 +0000 Subject: [PATCH 04/14] Fix typo and build --- src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs | 4 ++-- src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index 05d730cea3907..b104ed85a4a26 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -1891,7 +1891,7 @@ private BoundExpression SynthesizeReceiver(SyntaxNode node, Symbol member, Diagn (currentType.IsInterface && (declaringType.IsObjectType() || currentType.AllInterfacesNoUseSiteDiagnostics.Contains(declaringType)))) { bool hasErrors = false; - if (!IsInsideNameof || (EnclosingNameofArgument != node && !IsFeatureEnabled(node, MessageID.IDS_FeatureReducedMemberAccessChecksInNameof))) + if (!IsInsideNameof || (EnclosingNameofArgument != node && !IsFeatureAvailable(node, MessageID.IDS_FeatureReducedMemberAccessChecksInNameof))) { var diagnosticsTemp = IsInsideNameof ? new DiagnosticBag() : diagnostics; if (InFieldInitializer && !currentType.IsScriptClass) @@ -7027,7 +7027,7 @@ private bool CheckInstanceOrStatic( if (!symbol.RequiresInstanceReceiver()) { - if (instanceReceiver == true && !(IsInsideNameof && IsFeatureAvalable(node, MessageID.IDS_FeatureReducedMemberAccessChecksInNameof))) + if (instanceReceiver == true && !(IsInsideNameof && IsFeatureAvailable(node, MessageID.IDS_FeatureReducedMemberAccessChecksInNameof))) { if (!IsInsideNameof) { diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs index 832575fca9fdb..e4b9decac3f8d 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs @@ -2457,7 +2457,7 @@ protected AssemblySymbol GetForwardedToAssembly(string name, int arity, ref Name #nullable enable - internal static bool IsFeatureAvalable(SyntaxNode syntax, MessageID feature) + internal static bool IsFeatureAvailable(SyntaxNode syntax, MessageID feature) { return ((CSharpParseOptions)syntax.SyntaxTree.Options).IsFeatureEnabled(feature); } From 1ccdd6f6425db2d5099f8d18fc0af4edab95ab02 Mon Sep 17 00:00:00 2001 From: yair halberstadt Date: Fri, 25 Dec 2020 11:04:35 +0000 Subject: [PATCH 05/14] Fix formatting --- src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs index bcb585230e507..4f638b45eb6a4 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs @@ -1545,7 +1545,6 @@ public void Method(){} options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview, expectedOutput: "Property,Field,Method,Event,Event,Property,Field,Method,Event,Event,Invoke").VerifyDiagnostics(); - } [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] From fbc05735c5d330827ac96369ab2044c3a0d55711 Mon Sep 17 00:00:00 2001 From: yair halberstadt Date: Wed, 30 Dec 2020 20:13:11 +0000 Subject: [PATCH 06/14] Changes based on review by @333fred. Stylistic changes and adding tests. --- .../Portable/Binder/Binder_Expressions.cs | 6 +- .../Test/Semantic/Semantics/NameOfTests.cs | 68 ++++++++++++++++++- 2 files changed, 68 insertions(+), 6 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index b104ed85a4a26..d1da8f04a14f2 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -7027,7 +7027,7 @@ private bool CheckInstanceOrStatic( if (!symbol.RequiresInstanceReceiver()) { - if (instanceReceiver == true && !(IsInsideNameof && IsFeatureAvailable(node, MessageID.IDS_FeatureReducedMemberAccessChecksInNameof))) + if (instanceReceiver == true) { if (!IsInsideNameof) { @@ -7036,9 +7036,9 @@ private bool CheckInstanceOrStatic( ErrorCode.ERR_ObjectProhibited; Error(diagnostics, errorCode, node, symbol); } - else + else if (CheckFeatureAvailability(node, MessageID.IDS_FeatureReducedMemberAccessChecksInNameof, diagnostics)) { - CheckFeatureAvailability(node, MessageID.IDS_FeatureReducedMemberAccessChecksInNameof, diagnostics); + return false; } resultKind = LookupResultKind.StaticInstanceMismatch; return true; diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs index 4f638b45eb6a4..aaaeab7a33cfb 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs @@ -1523,12 +1523,10 @@ public static string M() => nameof(Property.Property) + "","" + nameof(Property.Field) + "","" + nameof(Property.Method) + "","" + nameof(Property.Event) - + "","" + nameof(Property.Event) + "","" + nameof(Field.Property) + "","" + nameof(Field.Field) + "","" + nameof(Field.Method) + "","" + nameof(Field.Event) - + "","" + nameof(Field.Event) + "","" + nameof(Event.Invoke) ; } @@ -1544,7 +1542,7 @@ public void Method(){} source, options: TestOptions.DebugExe, parseOptions: TestOptions.RegularPreview, - expectedOutput: "Property,Field,Method,Event,Event,Property,Field,Method,Event,Event,Invoke").VerifyDiagnostics(); + expectedOutput: "Property,Field,Method,Event,Property,Field,Method,Event,Invoke").VerifyDiagnostics(); } [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] @@ -1782,5 +1780,69 @@ public void M(ref string x) }"; CreateCompilation(source).VerifyDiagnostics(); } + + [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] + public void TestCanReferenceStaticMembersFromInstanceMemberInNameofUsedRecursivelyInAttributes1() + { + var source = @" +class C +{ + [Attr(nameof(Prop.StaticMethod))] + public C Prop { get; } + public static void StaticMethod(){} +} +class Attr : System.Attribute { public Attr(string s) {} }"; + CreateCompilation(source, parseOptions: TestOptions.RegularPreview) + .VerifyDiagnostics() + .VerifyEmitDiagnostics(); + } + + [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] + public void TestCanReferenceStaticMembersFromInstanceMemberInNameofUsedRecursivelyInAttributes2() + { + var source = @" +class C +{ + [Attr(nameof(Prop.Prop))] + public static C Prop { get; } +} +class Attr : System.Attribute { public Attr(string s) {} }"; + CreateCompilation(source, parseOptions: TestOptions.RegularPreview) + .VerifyDiagnostics() + .VerifyEmitDiagnostics(); + } + + [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] + public void TestCanReferenceStaticMembersFromInstanceMemberInNameofUsedRecursivelyInAttributes3() + { + var source = @" + +[Attr(nameof(C.Prop.Prop))] +class C +{ + public static C Prop { get; } +} +class Attr : System.Attribute { public Attr(string s) {} }"; + CreateCompilation(source, parseOptions: TestOptions.RegularPreview) + .VerifyDiagnostics() + .VerifyEmitDiagnostics(); + } + + [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] + public void TestInvalidRecursiveUsageOfNameofInAttributesDoesNotCrashCompiler() + { + var source = @" +class C +{ + [Attr(nameof(Method().Method))] + T Method() where T : C => default; +} +class Attr : System.Attribute { public Attr(string s) {} }"; + CreateCompilation(source, parseOptions: TestOptions.RegularPreview) + .VerifyDiagnostics( + // (4,18): error CS0411: The type arguments for method 'C.Method()' cannot be inferred from the usage. Try specifying the type arguments explicitly. + // [Attr(nameof(Method().Method))] + Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "Method").WithArguments("C.Method()").WithLocation(4, 18)); + } } } From 5e6ff0a605730ac767d621fa5c7c6dff13504cf1 Mon Sep 17 00:00:00 2001 From: yair halberstadt Date: Wed, 30 Dec 2020 20:18:37 +0000 Subject: [PATCH 07/14] Add another test --- .../Test/Semantic/Semantics/NameOfTests.cs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs index aaaeab7a33cfb..687b49feaa788 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs @@ -1829,7 +1829,7 @@ class Attr : System.Attribute { public Attr(string s) {} }"; } [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] - public void TestInvalidRecursiveUsageOfNameofInAttributesDoesNotCrashCompiler() + public void TestInvalidRecursiveUsageOfNameofInAttributesDoesNotCrashCompiler1() { var source = @" class C @@ -1844,5 +1844,22 @@ class Attr : System.Attribute { public Attr(string s) {} }"; // [Attr(nameof(Method().Method))] Diagnostic(ErrorCode.ERR_CantInferMethTypeArgs, "Method").WithArguments("C.Method()").WithLocation(4, 18)); } + + [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] + public void TestInvalidRecursiveUsageOfNameofInAttributesDoesNotCrashCompiler2() + { + var source = @" +class C +{ + [Attr(nameof(Method().Method))] + T Method() where T : C => default; +} +class Attr : System.Attribute { public Attr(string s) {} }"; + CreateCompilation(source, parseOptions: TestOptions.RegularPreview) + .VerifyDiagnostics( + // (4,18): error CS0120: An object reference is required for the non-static field, method, or property 'C.Method()' + // [Attr(nameof(Method().Method))] + Diagnostic(ErrorCode.ERR_ObjectRequired, "Method").WithArguments("C.Method()").WithLocation(4, 18)); + } } } From e241186826089e36fb08648e4931cf120d9b738a Mon Sep 17 00:00:00 2001 From: Yair Halberstadt Date: Wed, 29 Dec 2021 19:11:03 +0000 Subject: [PATCH 08/14] Changes in response to review by @333fred --- src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs index 779ba3c0e0f4c..0b0750b849171 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs @@ -1773,7 +1773,6 @@ public static void StaticMethod(){} } class Attr : System.Attribute { public Attr(string s) {} }"; CreateCompilation(source, parseOptions: TestOptions.RegularPreview) - .VerifyDiagnostics() .VerifyEmitDiagnostics(); } @@ -1788,7 +1787,6 @@ class C } class Attr : System.Attribute { public Attr(string s) {} }"; CreateCompilation(source, parseOptions: TestOptions.RegularPreview) - .VerifyDiagnostics() .VerifyEmitDiagnostics(); } @@ -1804,7 +1802,6 @@ class C } class Attr : System.Attribute { public Attr(string s) {} }"; CreateCompilation(source, parseOptions: TestOptions.RegularPreview) - .VerifyDiagnostics() .VerifyEmitDiagnostics(); } From 63e58285065e64390ea1d4bdfc37c0055ba1c225 Mon Sep 17 00:00:00 2001 From: Yair Halberstadt Date: Thu, 30 Dec 2021 05:39:49 +0000 Subject: [PATCH 09/14] fix build --- src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index 3d94cc24e3239..3a04684ea4652 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -1958,7 +1958,7 @@ private BoundExpression SynthesizeReceiver(SyntaxNode node, Symbol member, Bindi bool hasErrors = false; if (!IsInsideNameof || (EnclosingNameofArgument != node && !IsFeatureAvailable(node, MessageID.IDS_FeatureReducedMemberAccessChecksInNameof))) { - var diagnosticsTemp = IsInsideNameof ? new DiagnosticBag() : diagnostics; + var diagnosticsTemp = IsInsideNameof ? BindingDiagnosticBag.Discarded : diagnostics; if (InFieldInitializer && !currentType.IsScriptClass) { //can't access "this" in field initializers From f6775b0592f2c7eb1724cb004dee9511d25d9434 Mon Sep 17 00:00:00 2001 From: Fredric Silberberg Date: Fri, 28 Jan 2022 11:39:41 -0800 Subject: [PATCH 10/14] Fix test baseline and formatting. --- .../CSharp/Portable/Binder/Binder_Symbols.cs | 2 +- .../StaticAbstractMembersInInterfacesTests.cs | 28 ++----------------- 2 files changed, 3 insertions(+), 27 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs index ca4ee282dcf78..0ec5347b11b1c 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Symbols.cs @@ -2503,7 +2503,7 @@ internal static bool IsFeatureAvailable(SyntaxNode syntax, MessageID feature) { return ((CSharpParseOptions)syntax.SyntaxTree.Options).IsFeatureEnabled(feature); } - + internal static bool CheckFeatureAvailability(SyntaxNode syntax, MessageID feature, BindingDiagnosticBag diagnostics, Location? location = null) { return CheckFeatureAvailability(syntax, feature, diagnostics.DiagnosticBag, location); diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs index 1c2c2532ba11d..719a1db8a8e06 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs @@ -10641,22 +10641,10 @@ static void MT2() where T : I1 } "; var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, - parseOptions: TestOptions.RegularPreview, - targetFramework: _supportingFramework); + parseOptions: TestOptions.RegularPreview, + targetFramework: _supportingFramework); compilation1.VerifyDiagnostics( - // (14,20): error CS0176: Member 'I1.P01' cannot be accessed with an instance reference; qualify it with a type name instead - // _ = nameof(this.P01); - Diagnostic(ErrorCode.ERR_ObjectProhibited, "this.P01").WithArguments("I1.P01").WithLocation(14, 20), - // (15,20): error CS0176: Member 'I1.P04' cannot be accessed with an instance reference; qualify it with a type name instead - // _ = nameof(this.P04); - Diagnostic(ErrorCode.ERR_ObjectProhibited, "this.P04").WithArguments("I1.P04").WithLocation(15, 20), - // (28,20): error CS0176: Member 'I1.P01' cannot be accessed with an instance reference; qualify it with a type name instead - // _ = nameof(x.P01); - Diagnostic(ErrorCode.ERR_ObjectProhibited, "x.P01").WithArguments("I1.P01").WithLocation(28, 20), - // (30,20): error CS0176: Member 'I1.P04' cannot be accessed with an instance reference; qualify it with a type name instead - // _ = nameof(x.P04); - Diagnostic(ErrorCode.ERR_ObjectProhibited, "x.P04").WithArguments("I1.P04").WithLocation(30, 20), // (35,20): error CS0119: 'T' is a type parameter, which is not valid in the given context // _ = nameof(T.P03); Diagnostic(ErrorCode.ERR_BadSKunknown, "T").WithArguments("T", "type parameter").WithLocation(35, 20), @@ -11500,18 +11488,6 @@ static void MT2() where T : I1 targetFramework: _supportingFramework); compilation1.VerifyDiagnostics( - // (14,20): error CS0176: Member 'I1.P01' cannot be accessed with an instance reference; qualify it with a type name instead - // _ = nameof(this.P01); - Diagnostic(ErrorCode.ERR_ObjectProhibited, "this.P01").WithArguments("I1.P01").WithLocation(14, 20), - // (15,20): error CS0176: Member 'I1.P04' cannot be accessed with an instance reference; qualify it with a type name instead - // _ = nameof(this.P04); - Diagnostic(ErrorCode.ERR_ObjectProhibited, "this.P04").WithArguments("I1.P04").WithLocation(15, 20), - // (28,20): error CS0176: Member 'I1.P01' cannot be accessed with an instance reference; qualify it with a type name instead - // _ = nameof(x.P01); - Diagnostic(ErrorCode.ERR_ObjectProhibited, "x.P01").WithArguments("I1.P01").WithLocation(28, 20), - // (30,20): error CS0176: Member 'I1.P04' cannot be accessed with an instance reference; qualify it with a type name instead - // _ = nameof(x.P04); - Diagnostic(ErrorCode.ERR_ObjectProhibited, "x.P04").WithArguments("I1.P04").WithLocation(30, 20), // (35,20): error CS0119: 'T' is a type parameter, which is not valid in the given context // _ = nameof(T.P03); Diagnostic(ErrorCode.ERR_BadSKunknown, "T").WithArguments("T", "type parameter").WithLocation(35, 20), From 5f8c58e4c403a606c1a7cd47ebff1a091ca569d3 Mon Sep 17 00:00:00 2001 From: Jan Jones Date: Wed, 22 Mar 2023 16:13:29 +0100 Subject: [PATCH 11/14] Revert whitespace change --- .../Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs index d81693f724409..fe6c672902c0a 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs @@ -13098,8 +13098,8 @@ static void MT2() where T : I1 } "; var compilation1 = CreateCompilation(source1, options: TestOptions.DebugDll, - parseOptions: TestOptions.RegularPreview, - targetFramework: _supportingFramework); + parseOptions: TestOptions.RegularPreview, + targetFramework: _supportingFramework); compilation1.VerifyDiagnostics( // (35,20): error CS0704: Cannot do non-virtual member lookup in 'T' because it is a type parameter From 7ce5681057cf9cd779724707eb9d330c9d960e24 Mon Sep 17 00:00:00 2001 From: Jan Jones Date: Wed, 22 Mar 2023 16:15:32 +0100 Subject: [PATCH 12/14] Update verified diagnostic --- src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs index 8d5dd63b38ab2..9c974abeef466 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs @@ -1833,9 +1833,9 @@ class C class Attr : System.Attribute { public Attr(string s) {} }"; CreateCompilation(source, parseOptions: TestOptions.RegularPreview) .VerifyDiagnostics( - // (4,18): error CS0120: An object reference is required for the non-static field, method, or property 'C.Method()' + // (4,18): error CS8082: Sub-expression cannot be used in an argument to nameof. // [Attr(nameof(Method().Method))] - Diagnostic(ErrorCode.ERR_ObjectRequired, "Method").WithArguments("C.Method()").WithLocation(4, 18)); + Diagnostic(ErrorCode.ERR_SubexpressionNotInNameof, "Method()").WithLocation(4, 18)); } } } From 34b7a53650cf9b1c89086fba6159f6ca4eaa87c5 Mon Sep 17 00:00:00 2001 From: Jan Jones Date: Thu, 23 Mar 2023 12:03:15 +0100 Subject: [PATCH 13/14] Extend tests --- .../Test/Semantic/Semantics/NameOfTests.cs | 202 ++++++++++++++---- 1 file changed, 158 insertions(+), 44 deletions(-) diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs index 9c974abeef466..cdc6a8c6f881d 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs @@ -1489,14 +1489,37 @@ public void nameof(string x) } [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] - public void TestCanReferenceInstanceMembersFromStaticMemberInNameof() + public void TestCanReferenceInstanceMembersFromStaticMemberInNameof_Flat() + { + var source = @" +System.Console.Write(C.M()); +public class C +{ + public object Property { get; } + public object Field; + public event System.Action Event; + public void M2() { } + public static string M() => nameof(Property) + + "","" + nameof(Field) + + "","" + nameof(Event) + + "","" + nameof(M2) + ; +}"; + var expectedOutput = "Property,Field,Event,M2"; + + CompileAndVerify(source, parseOptions: TestOptions.Regular11, expectedOutput: expectedOutput).VerifyDiagnostics(); + CompileAndVerify(source, parseOptions: TestOptions.RegularNext, expectedOutput: expectedOutput).VerifyDiagnostics(); + } + + [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] + public void TestCanReferenceInstanceMembersFromStaticMemberInNameof_Nested() { var source = @" System.Console.Write(C.M()); public class C { public C1 Property { get; } - public C1 Field { get; } + public C1 Field; public event System.Action Event; public static string M() => nameof(Property.Property) + "","" + nameof(Property.Field) @@ -1517,11 +1540,36 @@ public class C1 public void Method(){} public event System.Action Event; }"; - CompileAndVerify( - source, - options: TestOptions.DebugExe, - parseOptions: TestOptions.RegularPreview, + CompileAndVerify(source, parseOptions: TestOptions.RegularNext, expectedOutput: "Property,Field,Method,Event,Property,Field,Method,Event,Invoke").VerifyDiagnostics(); + CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics( + // (8,40): error CS8652: The feature 'reduced member access checks in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public static string M() => nameof(Property.Property) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Property").WithArguments("reduced member access checks in 'nameof'").WithLocation(8, 40), + // (9,24): error CS8652: The feature 'reduced member access checks in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // + "," + nameof(Property.Field) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Property").WithArguments("reduced member access checks in 'nameof'").WithLocation(9, 24), + // (10,24): error CS8652: The feature 'reduced member access checks in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // + "," + nameof(Property.Method) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Property").WithArguments("reduced member access checks in 'nameof'").WithLocation(10, 24), + // (11,24): error CS8652: The feature 'reduced member access checks in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // + "," + nameof(Property.Event) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Property").WithArguments("reduced member access checks in 'nameof'").WithLocation(11, 24), + // (12,24): error CS8652: The feature 'reduced member access checks in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // + "," + nameof(Field.Property) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Field").WithArguments("reduced member access checks in 'nameof'").WithLocation(12, 24), + // (13,24): error CS8652: The feature 'reduced member access checks in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // + "," + nameof(Field.Field) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Field").WithArguments("reduced member access checks in 'nameof'").WithLocation(13, 24), + // (14,24): error CS8652: The feature 'reduced member access checks in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // + "," + nameof(Field.Method) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Field").WithArguments("reduced member access checks in 'nameof'").WithLocation(14, 24), + // (15,24): error CS8652: The feature 'reduced member access checks in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // + "," + nameof(Field.Event) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Field").WithArguments("reduced member access checks in 'nameof'").WithLocation(15, 24), + // (16,24): error CS8652: The feature 'reduced member access checks in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // + "," + nameof(Event.Invoke) + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Event").WithArguments("reduced member access checks in 'nameof'").WithLocation(16, 24)); } [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] @@ -1533,37 +1581,50 @@ public class C { public string S { get; } = nameof(S.Length); }"; - CompileAndVerify( - source, - options: TestOptions.DebugExe, - parseOptions: TestOptions.RegularPreview, - expectedOutput: "Length").VerifyDiagnostics(); + CompileAndVerify(source, parseOptions: TestOptions.RegularNext, expectedOutput: "Length").VerifyDiagnostics(); + CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics( + // (5,39): error CS8652: The feature 'reduced member access checks in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public string S { get; } = nameof(S.Length); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "S").WithArguments("reduced member access checks in 'nameof'").WithLocation(5, 39)); } [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] public void TestCanReferenceInstanceMembersFromAttributeInNameof() { var source = @" +var p = new C().P; // 1 public class C { [System.Obsolete(nameof(S.Length))] public int P { get; } public string S { get; } }"; - CreateCompilation(source, parseOptions: TestOptions.RegularPreview).VerifyDiagnostics(); + CreateCompilation(source, parseOptions: TestOptions.RegularNext).VerifyDiagnostics( + // (2,9): warning CS0618: 'C.P' is obsolete: 'Length' + // var p = new C().P; // 1 + Diagnostic(ErrorCode.WRN_DeprecatedSymbolStr, "new C().P").WithArguments("C.P", "Length").WithLocation(2, 9)); + CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics( + // (5,29): error CS8652: The feature 'reduced member access checks in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // [System.Obsolete(nameof(S.Length))] + Diagnostic(ErrorCode.ERR_FeatureInPreview, "S").WithArguments("reduced member access checks in 'nameof'").WithLocation(5, 29)); } [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] public void TestCanReferenceInstanceMembersFromConstructorInitializersInNameof() { var source = @" +System.Console.WriteLine(new C().S); public class C { - public C(string s){} + public C(string s){ S = s; } public C() : this(nameof(S.Length)){} public string S { get; } }"; - CreateCompilation(source, parseOptions: TestOptions.RegularPreview).VerifyDiagnostics(); + CompileAndVerify(source, parseOptions: TestOptions.RegularNext, expectedOutput: "Length").VerifyDiagnostics(); + CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics( + // (6,30): error CS8652: The feature 'reduced member access checks in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public C() : this(nameof(S.Length)){} + Diagnostic(ErrorCode.ERR_FeatureInPreview, "S").WithArguments("reduced member access checks in 'nameof'").WithLocation(6, 30)); } [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] @@ -1572,70 +1633,98 @@ public void TestCanAccessStructInstancePropertyInLambdaInNameof() var source = @" using System; +string s = ""str""; +new S().M(ref s); + public struct S { public string P { get; } public void M(ref string x) { Func func = () => nameof(P.Length); + Console.WriteLine(func()); } }"; - CreateCompilation(source, parseOptions: TestOptions.RegularPreview).VerifyDiagnostics(); + CompileAndVerify(source, parseOptions: TestOptions.RegularNext, expectedOutput: "Length").VerifyDiagnostics(); + CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics( + // (12,42): error CS8652: The feature 'reduced member access checks in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // Func func = () => nameof(P.Length); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "P").WithArguments("reduced member access checks in 'nameof'").WithLocation(12, 42)); } [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] public void TestCanReferenceStaticMembersFromInstanceMemberInNameof1() { var source = @" +System.Console.WriteLine(new C().M()); public class C { public C Prop { get; } public static int StaticProp { get; } public string M() => nameof(Prop.StaticProp); }"; - CreateCompilation(source, parseOptions: TestOptions.RegularPreview).VerifyDiagnostics(); + CompileAndVerify(source, parseOptions: TestOptions.RegularNext, expectedOutput: "StaticProp").VerifyDiagnostics(); + CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics( + // (7,33): error CS8652: The feature 'reduced member access checks in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public string M() => nameof(Prop.StaticProp); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Prop.StaticProp").WithArguments("reduced member access checks in 'nameof'").WithLocation(7, 33)); } [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] public void TestCanReferenceStaticMembersFromInstanceMemberInNameof2() { var source = @" +System.Console.WriteLine(C.M()); public class C { public C Prop { get; } public static int StaticProp { get; } public static string M() => nameof(Prop.StaticProp); }"; - CreateCompilation(source, parseOptions: TestOptions.RegularPreview).VerifyDiagnostics(); + CompileAndVerify(source, parseOptions: TestOptions.RegularNext, expectedOutput: "StaticProp").VerifyDiagnostics(); + CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics( + // (7,40): error CS8652: The feature 'reduced member access checks in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public static string M() => nameof(Prop.StaticProp); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Prop").WithArguments("reduced member access checks in 'nameof'").WithLocation(7, 40), + // (7,40): error CS8652: The feature 'reduced member access checks in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public static string M() => nameof(Prop.StaticProp); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Prop.StaticProp").WithArguments("reduced member access checks in 'nameof'").WithLocation(7, 40)); } [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] public void TestCanReferenceStaticMembersFromInstanceMemberInNameof3() { var source = @" +System.Console.WriteLine(C.M()); public class C { public C Prop { get; } public static string M() => nameof(Prop.M); }"; - CreateCompilation(source, parseOptions: TestOptions.RegularPreview).VerifyDiagnostics(); + CompileAndVerify(source, parseOptions: TestOptions.RegularNext, expectedOutput: "M").VerifyDiagnostics(); + CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics( + // (6,40): error CS8652: The feature 'reduced member access checks in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public static string M() => nameof(Prop.M); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Prop").WithArguments("reduced member access checks in 'nameof'").WithLocation(6, 40)); } [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] public void TestCanReferenceStaticMembersFromInstanceMemberInNameof4() { var source = @" +System.Console.WriteLine(new C().M()); public class C { public C Prop { get; } public static void StaticMethod(){} public string M() => nameof(Prop.StaticMethod); }"; - CreateCompilation(source, parseOptions: TestOptions.RegularPreview).VerifyDiagnostics(); + CompileAndVerify(source, parseOptions: TestOptions.RegularNext, expectedOutput: "StaticMethod").VerifyDiagnostics(); + CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics(); } [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] - public void TestCannotReferenceInstanceMembersFromStaticMemberInNameofInCSharp9() + public void TestCannotReferenceInstanceMembersFromStaticMemberInNameofInCSharp11() { var source = @" public class C @@ -1643,28 +1732,28 @@ public class C public string S { get; } public static string M() => nameof(S.Length); }"; - CreateCompilation(source, parseOptions: TestOptions.Regular9).VerifyDiagnostics( + CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics( // (5,40): error CS8652: The feature 'reduced member access checks in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // public static string M() => nameof(S.Length); Diagnostic(ErrorCode.ERR_FeatureInPreview, "S").WithArguments("reduced member access checks in 'nameof'").WithLocation(5, 40)); } [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] - public void TestCannotReferenceInstanceMembersFromFieldInitializerInNameofInCSharp9() + public void TestCannotReferenceInstanceMembersFromFieldInitializerInNameofInCSharp11() { var source = @" public class C { public string S { get; } = nameof(S.Length); }"; - CreateCompilation(source, parseOptions: TestOptions.Regular9).VerifyDiagnostics( + CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics( // (4,39): error CS8652: The feature 'reduced member access checks in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // public string S { get; } = nameof(S.Length); Diagnostic(ErrorCode.ERR_FeatureInPreview, "S").WithArguments("reduced member access checks in 'nameof'").WithLocation(4, 39)); } [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] - public void TestCannotReferenceInstanceMembersFromAttributeInNameofInCSharp9() + public void TestCannotReferenceInstanceMembersFromAttributeInNameofInCSharp11() { var source = @" public class C @@ -1673,14 +1762,14 @@ public class C public int P { get; } public string S { get; } }"; - CreateCompilation(source, parseOptions: TestOptions.Regular9).VerifyDiagnostics( + CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics( // (4,29): error CS8652: The feature 'reduced member access checks in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // [System.Obsolete(nameof(S.Length))] Diagnostic(ErrorCode.ERR_FeatureInPreview, "S").WithArguments("reduced member access checks in 'nameof'").WithLocation(4, 29)); } [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] - public void TestCannotReferenceInstanceMembersFromConstructorInitializersInNameofInCSharp9() + public void TestCannotReferenceInstanceMembersFromConstructorInitializersInNameofInCSharp11() { var source = @" public class C @@ -1689,14 +1778,14 @@ public C(string s){} public C() : this(nameof(S.Length)){} public string S { get; } }"; - CreateCompilation(source, parseOptions: TestOptions.Regular9).VerifyDiagnostics( + CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics( // (5,30): error CS8652: The feature 'reduced member access checks in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // public C() : this(nameof(S.Length)){} Diagnostic(ErrorCode.ERR_FeatureInPreview, "S").WithArguments("reduced member access checks in 'nameof'").WithLocation(5, 30)); } [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] - public void TestCannotAccessStructInstancePropertyInLambdaInNameofInCSharp9() + public void TestCannotAccessStructInstancePropertyInLambdaInNameofInCSharp11() { var source = @" using System; @@ -1709,14 +1798,14 @@ public void M(ref string x) Func func = () => nameof(P.Length); } }"; - CreateCompilation(source, parseOptions: TestOptions.Regular9).VerifyDiagnostics( + CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics( // (9,42): error CS8652: The feature 'reduced member access checks in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // Func func = () => nameof(P.Length); Diagnostic(ErrorCode.ERR_FeatureInPreview, "P").WithArguments("reduced member access checks in 'nameof'").WithLocation(9, 42)); } [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] - public void TestCannotReferenceStaticPropertyFromInstanceMemberInNameofInCSharp9() + public void TestCannotReferenceStaticPropertyFromInstanceMemberInNameofInCSharp11() { var source = @" public class C @@ -1725,23 +1814,24 @@ public class C public static int StaticProp { get; } public string M() => nameof(Prop.StaticProp); }"; - CreateCompilation(source, parseOptions: TestOptions.Regular9).VerifyDiagnostics( + CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics( // (6,33): error CS8652: The feature 'reduced member access checks in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // public string M() => nameof(Prop.StaticProp); Diagnostic(ErrorCode.ERR_FeatureInPreview, "Prop.StaticProp").WithArguments("reduced member access checks in 'nameof'").WithLocation(6, 33)); } [Fact] - public void TestCanReferenceStaticMethodFromInstanceMemberInNameofInCSharp9() + public void TestCanReferenceStaticMethodFromInstanceMemberInNameofInCSharp11() { var source = @" +System.Console.WriteLine(new C().M()); public class C { public C Prop { get; } public static void StaticMethod(){} public string M() => nameof(Prop.StaticMethod); }"; - CreateCompilation(source, parseOptions: TestOptions.Regular9).VerifyDiagnostics(); + CompileAndVerify(source, parseOptions: TestOptions.Regular11, expectedOutput: "StaticMethod").VerifyDiagnostics(); } [Fact] @@ -1750,58 +1840,82 @@ public void TestCanAccessRefParameterInLambdaInNameof() var source = @" using System; +string s = ""str""; +new S().M(ref s); + public struct S { public void M(ref string x) { Func func = () => nameof(x.Length); + Console.WriteLine(func()); } }"; - CreateCompilation(source).VerifyDiagnostics(); + CompileAndVerify(source, expectedOutput: "Length").VerifyDiagnostics(); } [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] public void TestCanReferenceStaticMembersFromInstanceMemberInNameofUsedRecursivelyInAttributes1() { var source = @" +using System; +using System.Reflection; +Console.WriteLine(typeof(C).GetProperty(""Prop"").GetCustomAttribute().S); class C { [Attr(nameof(Prop.StaticMethod))] public C Prop { get; } public static void StaticMethod(){} } -class Attr : System.Attribute { public Attr(string s) {} }"; - CreateCompilation(source, parseOptions: TestOptions.RegularPreview) - .VerifyEmitDiagnostics(); +class Attr : Attribute +{ + public readonly string S; + public Attr(string s) { S = s; } +}"; + CompileAndVerify(source, parseOptions: TestOptions.RegularPreview, expectedOutput: "StaticMethod") + .VerifyDiagnostics(); } [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] public void TestCanReferenceStaticMembersFromInstanceMemberInNameofUsedRecursivelyInAttributes2() { var source = @" +using System; +using System.Reflection; +Console.WriteLine(typeof(C).GetProperty(""Prop"").GetCustomAttribute().S); class C { [Attr(nameof(Prop.Prop))] public static C Prop { get; } } -class Attr : System.Attribute { public Attr(string s) {} }"; - CreateCompilation(source, parseOptions: TestOptions.RegularPreview) - .VerifyEmitDiagnostics(); +class Attr : Attribute +{ + public readonly string S; + public Attr(string s) { S = s; } +}"; + CompileAndVerify(source, parseOptions: TestOptions.RegularPreview, expectedOutput: "Prop") + .VerifyDiagnostics(); } [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] public void TestCanReferenceStaticMembersFromInstanceMemberInNameofUsedRecursivelyInAttributes3() { var source = @" - +using System; +using System.Reflection; +Console.WriteLine(typeof(C).GetCustomAttribute().S); [Attr(nameof(C.Prop.Prop))] class C { public static C Prop { get; } } -class Attr : System.Attribute { public Attr(string s) {} }"; - CreateCompilation(source, parseOptions: TestOptions.RegularPreview) - .VerifyEmitDiagnostics(); +class Attr : Attribute +{ + public readonly string S; + public Attr(string s) { S = s; } +}"; + CompileAndVerify(source, parseOptions: TestOptions.RegularPreview, expectedOutput: "Prop") + .VerifyDiagnostics(); } [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] From ad3e699ab54ad87495bf7957f5442c67b1f45aca Mon Sep 17 00:00:00 2001 From: Jan Jones Date: Thu, 23 Mar 2023 13:38:38 +0100 Subject: [PATCH 14/14] Avoid discarding diagnostic dependencies --- .../Portable/Binder/Binder_Expressions.cs | 50 +++++++++++++------ 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index d5ed8a3727057..3fc5f7db8eeeb 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -2077,18 +2077,16 @@ private BoundExpression SynthesizeReceiver(SyntaxNode node, Symbol member, Bindi bool hasErrors = false; if (!IsInsideNameof || (EnclosingNameofArgument != node && !IsFeatureAvailable(node, MessageID.IDS_FeatureReducedMemberAccessChecksInNameof))) { - var diagnosticsTemp = IsInsideNameof ? BindingDiagnosticBag.Discarded : diagnostics; + DiagnosticInfo diagnosticInfoOpt = null; if (InFieldInitializer && !currentType.IsScriptClass) { //can't access "this" in field initializers - Error(diagnosticsTemp, ErrorCode.ERR_FieldInitRefNonstatic, node, member); - hasErrors = true; + diagnosticInfoOpt = new CSDiagnosticInfo(ErrorCode.ERR_FieldInitRefNonstatic, member); } else if (InConstructorInitializer || InAttributeArgument) { //can't access "this" in constructor initializers or attribute arguments - Error(diagnosticsTemp, ErrorCode.ERR_ObjectRequired, node, member); - hasErrors = true; + diagnosticInfoOpt = new CSDiagnosticInfo(ErrorCode.ERR_ObjectRequired, member); } else { @@ -2100,16 +2098,23 @@ private BoundExpression SynthesizeReceiver(SyntaxNode node, Symbol member, Bindi if (!locationIsInstanceMember) { // error CS0120: An object reference is required for the non-static field, method, or property '{0}' - Error(diagnosticsTemp, ErrorCode.ERR_ObjectRequired, node, member); - hasErrors = true; + diagnosticInfoOpt = new CSDiagnosticInfo(ErrorCode.ERR_ObjectRequired, member); } } - hasErrors = hasErrors || IsRefOrOutThisParameterCaptured(node, diagnosticsTemp); + diagnosticInfoOpt ??= GetDiagnosticIfRefOrOutThisParameterCaptured(); + hasErrors = hasErrors || diagnosticInfoOpt is not null; - if (hasErrors && IsInsideNameof) + if (hasErrors) { - CheckFeatureAvailability(node, MessageID.IDS_FeatureReducedMemberAccessChecksInNameof, diagnostics); + if (IsInsideNameof) + { + CheckFeatureAvailability(node, MessageID.IDS_FeatureReducedMemberAccessChecksInNameof, diagnostics); + } + else + { + Error(diagnostics, diagnosticInfoOpt, node); + } } } @@ -2282,20 +2287,35 @@ private BoundThisReference ThisReference(SyntaxNode node, NamedTypeSymbol thisTy return new BoundThisReference(node, thisTypeOpt ?? CreateErrorType(), hasErrors) { WasCompilerGenerated = wasCompilerGenerated }; } +#nullable enable private bool IsRefOrOutThisParameterCaptured(SyntaxNodeOrToken thisOrBaseToken, BindingDiagnosticBag diagnostics) { - ParameterSymbol thisSymbol = this.ContainingMemberOrLambda.EnclosingThisSymbol(); - // If there is no this parameter, then it is definitely not captured and - // any diagnostic would be cascading. - if ((object)thisSymbol != null && thisSymbol.ContainingSymbol != ContainingMemberOrLambda && thisSymbol.RefKind != RefKind.None) + if (GetDiagnosticIfRefOrOutThisParameterCaptured() is { } diagnosticInfo) { - Error(diagnostics, ErrorCode.ERR_ThisStructNotInAnonMeth, thisOrBaseToken); + var location = thisOrBaseToken.GetLocation(); + Debug.Assert(location is not null); + Error(diagnostics, diagnosticInfo, location); return true; } return false; } + private DiagnosticInfo? GetDiagnosticIfRefOrOutThisParameterCaptured() + { + Debug.Assert(this.ContainingMemberOrLambda is not null); + ParameterSymbol? thisSymbol = this.ContainingMemberOrLambda.EnclosingThisSymbol(); + // If there is no this parameter, then it is definitely not captured and + // any diagnostic would be cascading. + if (thisSymbol is not null && thisSymbol.ContainingSymbol != ContainingMemberOrLambda && thisSymbol.RefKind != RefKind.None) + { + return new CSDiagnosticInfo(ErrorCode.ERR_ThisStructNotInAnonMeth); + } + + return null; + } +#nullable disable + private BoundBaseReference BindBase(BaseExpressionSyntax node, BindingDiagnosticBag diagnostics) { bool hasErrors = false;