diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index 383223be84200..f62e0d476b2fd 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -2108,19 +2108,18 @@ private BoundExpression SynthesizeReceiver(SyntaxNode node, Symbol member, Bindi (currentType.IsInterface && (declaringType.IsObjectType() || currentType.AllInterfacesNoUseSiteDiagnostics.Contains(declaringType)))) { bool hasErrors = false; - if (EnclosingNameofArgument != node) + if (!IsInsideNameof || (EnclosingNameofArgument != node && !node.IsFeatureEnabled(MessageID.IDS_FeatureInstanceMemberInNameof))) { + DiagnosticInfo diagnosticInfoOpt = null; if (InFieldInitializer && !currentType.IsScriptClass) { //can't access "this" in field initializers - Error(diagnostics, 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(diagnostics, ErrorCode.ERR_ObjectRequired, node, member); - hasErrors = true; + diagnosticInfoOpt = new CSDiagnosticInfo(ErrorCode.ERR_ObjectRequired, member); } else { @@ -2132,12 +2131,24 @@ 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(diagnostics, ErrorCode.ERR_ObjectRequired, node, member); - hasErrors = true; + diagnosticInfoOpt = new CSDiagnosticInfo(ErrorCode.ERR_ObjectRequired, member); } } - hasErrors = hasErrors || IsRefOrOutThisParameterCaptured(node, diagnostics); + diagnosticInfoOpt ??= GetDiagnosticIfRefOrOutThisParameterCaptured(); + hasErrors = diagnosticInfoOpt is not null; + + if (hasErrors) + { + if (IsInsideNameof) + { + CheckFeatureAvailability(node, MessageID.IDS_FeatureInstanceMemberInNameof, diagnostics); + } + else + { + Error(diagnostics, diagnosticInfoOpt, node); + } + } } return ThisReference(node, currentType, hasErrors, wasCompilerGenerated: true); @@ -2309,20 +2320,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; @@ -7746,10 +7772,17 @@ private bool CheckInstanceOrStatic( { if (instanceReceiver == true) { - 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 if (CheckFeatureAvailability(node, MessageID.IDS_FeatureInstanceMemberInNameof, diagnostics)) + { + return false; + } resultKind = LookupResultKind.StaticInstanceMismatch; return true; } diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 7b3d76e2f2759..d0db9d09556ab 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -6814,6 +6814,9 @@ 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? + + instance member in 'nameof' + The primary constructor conflicts with the synthesized copy constructor. diff --git a/src/Compilers/CSharp/Portable/Errors/MessageID.cs b/src/Compilers/CSharp/Portable/Errors/MessageID.cs index a080b65853dd6..92e08d6ae0c10 100644 --- a/src/Compilers/CSharp/Portable/Errors/MessageID.cs +++ b/src/Compilers/CSharp/Portable/Errors/MessageID.cs @@ -265,6 +265,8 @@ internal enum MessageID IDS_FeaturePrimaryConstructors = MessageBase + 12833, IDS_FeatureUsingTypeAlias = MessageBase + 12834, + + IDS_FeatureInstanceMemberInNameof = MessageBase + 12835, } // Message IDs may refer to strings that need to be localized. @@ -449,6 +451,7 @@ internal static LanguageVersion RequiredVersion(this MessageID feature) case MessageID.IDS_FeatureLambdaParamsArray: // semantic check case MessageID.IDS_FeaturePrimaryConstructors: // declaration table check case MessageID.IDS_FeatureUsingTypeAlias: // semantic check + case MessageID.IDS_FeatureInstanceMemberInNameof: // semantic check return LanguageVersion.Preview; // C# 11.0 features. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index 9eec4895c74af..cf2d5091ce7e3 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -1907,6 +1907,11 @@ odvozený typ delegáta + + instance member in 'nameof' + instance member in 'nameof' + + lambda attributes atributy lambda diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index f419ece90e2c2..d1aa50feea941 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -1907,6 +1907,11 @@ abgeleiteter Delegattyp + + instance member in 'nameof' + instance member in 'nameof' + + lambda attributes Lambdaattribute diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index 0434ca386a6b7..1d7eae3b86136 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -1907,6 +1907,11 @@ tipo de delegado inferido + + instance member in 'nameof' + instance member in 'nameof' + + lambda attributes atributos de lambda diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index 11a4c75e46504..d9515827f9d61 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -1907,6 +1907,11 @@ type délégué déduit + + instance member in 'nameof' + instance member in 'nameof' + + lambda attributes attributs lambda diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index ca1540f042777..b9599ffc38273 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -1907,6 +1907,11 @@ tipo di delegato dedotto + + instance member in 'nameof' + instance member in 'nameof' + + lambda attributes attributi lambda diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index 561713d66a430..edc79dc35b41a 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -1907,6 +1907,11 @@ 推論されたデリゲート型 + + instance member in 'nameof' + instance member in 'nameof' + + lambda attributes ラムダ属性 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index 128a8a2b7a1eb..8ba51bf19c702 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -1907,6 +1907,11 @@ 유추된 대리자 형식 + + instance member in 'nameof' + instance member in 'nameof' + + lambda attributes 람다 특성 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index c228fd971f016..d50d0d8303084 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -1907,6 +1907,11 @@ Typ delegowania wywnioskowanego + + instance member in 'nameof' + instance member in 'nameof' + + lambda attributes atrybuty lambda diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index 3c63e31f63721..6b2d4acb4bb83 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -1907,6 +1907,11 @@ tipo representante inferido + + instance member in 'nameof' + instance member in 'nameof' + + lambda attributes lambda attributes diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index a82d18a9c3940..d1362cd391fc4 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -1907,6 +1907,11 @@ выводимый тип делегата + + instance member in 'nameof' + instance member in 'nameof' + + lambda attributes лямбда-атрибуты diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index 6ce875379dc5b..63258ad292658 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -1907,6 +1907,11 @@ çıkarsanan temsilci türü + + instance member in 'nameof' + instance member in 'nameof' + + lambda attributes lambda öznitelikleri diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index cbfe6c7f76eb0..80a8f77bb0f6b 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -1907,6 +1907,11 @@ 推断的委托类型 + + instance member in 'nameof' + instance member in 'nameof' + + lambda attributes Lambda 属性 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index 15c8a3eb6db39..04a3ec570e8e7 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -1907,6 +1907,11 @@ 推斷委派類型 + + instance member in 'nameof' + instance member in 'nameof' + + lambda attributes Lambda 屬性 diff --git a/src/Compilers/CSharp/Test/Emit2/FlowAnalysis/FlowTests.cs b/src/Compilers/CSharp/Test/Emit2/FlowAnalysis/FlowTests.cs index a6474e1d6859e..f718c080bade6 100644 --- a/src/Compilers/CSharp/Test/Emit2/FlowAnalysis/FlowTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/FlowAnalysis/FlowTests.cs @@ -5912,5 +5912,31 @@ public static void Main() "; CreateCompilation(source).VerifyDiagnostics(); } + + [Fact] + public void NameOf_Nested() + { + var source = """ + System.Console.WriteLine(C.M()); + public class C + { + private C c; + public static string M() => nameof(c.c.c); + } + """; + + var expectedDiagnostic = + // (4,15): warning CS0649: Field 'C.c' is never assigned to, and will always have its default value null + // private C c; + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "c").WithArguments("C.c", "null").WithLocation(4, 15); + + CompileAndVerify(source, parseOptions: TestOptions.RegularNext, expectedOutput: "c").VerifyDiagnostics(expectedDiagnostic); + CompileAndVerify(source, parseOptions: TestOptions.RegularPreview, expectedOutput: "c").VerifyDiagnostics(expectedDiagnostic); + CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics( + expectedDiagnostic, + // (5,40): error CS8652: The feature 'instance member in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public static string M() => nameof(c.c.c); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "c").WithArguments("instance member in 'nameof'").WithLocation(5, 40)); + } } } diff --git a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_INameOfOperation.cs b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_INameOfOperation.cs index 2587442a62a18..4f7975c981bb2 100644 --- a/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_INameOfOperation.cs +++ b/src/Compilers/CSharp/Test/IOperation/IOperation/IOperationTests_INameOfOperation.cs @@ -223,5 +223,208 @@ void M() "; VerifyFlowGraphAndDiagnosticsForTest(source, expectedFlowGraph, expectedDiagnostics); } + + [CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)] + [Fact] + public void NameOfFlow_InstanceMemberFromStatic_Flat() + { + var source = """ + public class C + { + public int Property { get; } + public int Field; + public event System.Action Event; + + public static string StaticMethod() + /**/{ + return nameof(Property) + + nameof(Field) + + nameof(Event); + }/**/ + } + """; + + var expectedFlowGraph = """ + Block[B0] - Entry + Statements (0) + Next (Regular) Block[B1] + Block[B1] - Block + Predecessors: [B0] + Statements (0) + Next (Return) Block[B2] + IBinaryOperation (BinaryOperatorKind.Add) (OperationKind.Binary, Type: System.String, Constant: "PropertyFieldEvent") (Syntax: 'nameof(Prop ... meof(Event)') + Left: + IBinaryOperation (BinaryOperatorKind.Add) (OperationKind.Binary, Type: System.String, Constant: "PropertyField") (Syntax: 'nameof(Prop ... meof(Field)') + Left: + ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: "Property") (Syntax: 'nameof(Property)') + Right: + ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: "Field") (Syntax: 'nameof(Field)') + Right: + ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: "Event") (Syntax: 'nameof(Event)') + Block[B2] - Exit + Predecessors: [B1] + Statements (0) + """; + + VerifyFlowGraphAndDiagnosticsForTest(source, expectedFlowGraph, DiagnosticDescription.None); + } + + [CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)] + [Fact] + public void NameOfFlow_InstanceMemberFromStatic_Flat_MethodGroup() + { + var source = """ + public class C + { + public void Method1() { } + public void Method1(int i) { } + public void Method2() { } + public static void Method2(int i) { } + + public static string StaticMethod() + /**/{ + return nameof(Method1) + + nameof(Method2); + }/**/ + } + """; + + var expectedFlowGraph = """ + Block[B0] - Entry + Statements (0) + Next (Regular) Block[B1] + Block[B1] - Block + Predecessors: [B0] + Statements (0) + Next (Return) Block[B2] + IBinaryOperation (BinaryOperatorKind.Add) (OperationKind.Binary, Type: System.String, Constant: "Method1Method2") (Syntax: 'nameof(Meth ... of(Method2)') + Left: + ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: "Method1") (Syntax: 'nameof(Method1)') + Right: + ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: "Method2") (Syntax: 'nameof(Method2)') + Block[B2] - Exit + Predecessors: [B1] + Statements (0) + """; + + VerifyFlowGraphAndDiagnosticsForTest(source, expectedFlowGraph, DiagnosticDescription.None); + } + + [CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)] + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/67565")] + public void NameOfFlow_InstanceMemberFromStatic_Nested() + { + var source = """ + public class C + { + public C1 Property { get; } + public C1 Field; + + public static string StaticMethod() + /**/{ + return nameof(Property.Property) + + nameof(Property.Field) + + nameof(Property.Event) + + nameof(Field.Property) + + nameof(Field.Field) + + nameof(Field.Event); + }/**/ + } + + public class C1 + { + public int Property { get; } + public int Field; + public event System.Action Event; + } + """; + + var expectedFlowGraph = """ + Block[B0] - Entry + Statements (0) + Next (Regular) Block[B1] + Block[B1] - Block + Predecessors: [B0] + Statements (0) + Next (Return) Block[B2] + IBinaryOperation (BinaryOperatorKind.Add) (OperationKind.Binary, Type: System.String, Constant: "PropertyFieldEventPropertyFieldEvent") (Syntax: 'nameof(Prop ... ield.Event)') + Left: + IBinaryOperation (BinaryOperatorKind.Add) (OperationKind.Binary, Type: System.String, Constant: "PropertyFieldEventPropertyField") (Syntax: 'nameof(Prop ... ield.Field)') + Left: + IBinaryOperation (BinaryOperatorKind.Add) (OperationKind.Binary, Type: System.String, Constant: "PropertyFieldEventProperty") (Syntax: 'nameof(Prop ... d.Property)') + Left: + IBinaryOperation (BinaryOperatorKind.Add) (OperationKind.Binary, Type: System.String, Constant: "PropertyFieldEvent") (Syntax: 'nameof(Prop ... erty.Event)') + Left: + IBinaryOperation (BinaryOperatorKind.Add) (OperationKind.Binary, Type: System.String, Constant: "PropertyField") (Syntax: 'nameof(Prop ... erty.Field)') + Left: + ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: "Property") (Syntax: 'nameof(Prop ... y.Property)') + Right: + ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: "Field") (Syntax: 'nameof(Property.Field)') + Right: + ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: "Event") (Syntax: 'nameof(Property.Event)') + Right: + ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: "Property") (Syntax: 'nameof(Field.Property)') + Right: + ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: "Field") (Syntax: 'nameof(Field.Field)') + Right: + ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: "Event") (Syntax: 'nameof(Field.Event)') + Block[B2] - Exit + Predecessors: [B1] + Statements (0) + """; + + VerifyFlowGraphAndDiagnosticsForTest(source, expectedFlowGraph, DiagnosticDescription.None); + } + + [CompilerTrait(CompilerFeature.IOperation, CompilerFeature.Dataflow)] + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/67565")] + public void NameOfFlow_InstanceMemberFromStatic_Nested_MethodGroup() + { + var source = """ + public class C + { + public C1 Property { get; } + public C1 Field; + public event System.Action Event; + + public static string StaticMethod() + /**/{ + return nameof(Property.Method) + + nameof(Field.Method) + + nameof(Event.Invoke); + }/**/ + } + + public class C1 + { + public void Method() { } + public void Method(int i) { } + } + """; + + var expectedFlowGraph = """ + Block[B0] - Entry + Statements (0) + Next (Regular) Block[B1] + Block[B1] - Block + Predecessors: [B0] + Statements (0) + Next (Return) Block[B2] + IBinaryOperation (BinaryOperatorKind.Add) (OperationKind.Binary, Type: System.String, Constant: "MethodMethodInvoke") (Syntax: 'nameof(Prop ... ent.Invoke)') + Left: + IBinaryOperation (BinaryOperatorKind.Add) (OperationKind.Binary, Type: System.String, Constant: "MethodMethod") (Syntax: 'nameof(Prop ... eld.Method)') + Left: + ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: "Method") (Syntax: 'nameof(Property.Method)') + Right: + ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: "Method") (Syntax: 'nameof(Field.Method)') + Right: + ILiteralOperation (OperationKind.Literal, Type: System.String, Constant: "Invoke") (Syntax: 'nameof(Event.Invoke)') + Block[B2] - Exit + Predecessors: [B1] + Statements (0) + """; + + VerifyFlowGraphAndDiagnosticsForTest(source, expectedFlowGraph, DiagnosticDescription.None); + } } } diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs index 4699165bab2b7..98a9d1f8137a9 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NameOfTests.cs @@ -4,13 +4,15 @@ #nullable disable -using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Threading; +using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Roslyn.Test.Utilities; using Xunit; -using System.Threading; -using System.Linq; namespace Microsoft.CodeAnalysis.CSharp.UnitTests { @@ -954,6 +956,315 @@ private static void Use(object o) {} Assert.Equal(0, symbolInfo.CandidateSymbols.Length); } + [Fact] + public void SymbolInfo_InstanceMemberFromStatic_Flat() + { + var source = """ + public class C + { + public int Property { get; } + public int Field; + public event System.Action Event; + + public static string StaticField = + nameof(Property) + + nameof(Field) + + nameof(Event); + } + """; + var comp = CreateCompilation(source).VerifyDiagnostics(); + + var cProperty = comp.GetMember("C.Property"); + var cField = comp.GetMember("C.Field"); + var cEvent = comp.GetMember("C.Event"); + + var tree = comp.SyntaxTrees.Single(); + var tree2 = SyntaxFactory.ParseSyntaxTree(source + " "); + + var initializer = tree2.GetRoot().DescendantNodes().OfType().Single(); + + var nameofCalls = getNameOfCalls(tree); + Assert.Equal(3, nameofCalls.Length); + var nameofCalls2 = getNameOfCalls(tree2); + Assert.Equal(3, nameofCalls2.Length); + + var model = comp.GetSemanticModel(tree); + + verify(0, "Property", cProperty); + verify(1, "Field", cField); + verify(2, "Event", cEvent); + + void verify(int index, string expression, Symbol symbol) + { + var argument = nameofCalls[index].ArgumentList.Arguments.Single().Expression; + Assert.Equal(expression, argument.ToString()); + + verifySymbolInfo(model.GetSymbolInfo(argument)); + + var argument2 = nameofCalls2[index].ArgumentList.Arguments.Single().Expression; + Assert.Equal(expression, argument2.ToString()); + + Assert.True(model.TryGetSpeculativeSemanticModel(initializer.Position, initializer, out var model2)); + + verifySymbolInfo(model2.GetSymbolInfo(argument2)); + + verifySymbolInfo(model.GetSpeculativeSymbolInfo(argument2.Position, argument2, SpeculativeBindingOption.BindAsExpression)); + + Assert.True(model.GetSpeculativeSymbolInfo(argument2.Position, argument2, SpeculativeBindingOption.BindAsTypeOrNamespace).IsEmpty); + + void verifySymbolInfo(SymbolInfo symbolInfo) + { + Assert.NotNull(symbolInfo.Symbol); + Assert.Same(symbol.GetPublicSymbol(), symbolInfo.Symbol); + } + } + + static ImmutableArray getNameOfCalls(SyntaxTree tree) + { + return tree.GetRoot().DescendantNodes().OfType() + .Where(e => e.Expression is IdentifierNameSyntax { Identifier.ValueText: "nameof" }) + .ToImmutableArray(); + } + } + + [Fact] + public void SymbolInfo_InstanceMemberFromStatic_Flat_MethodGroup() + { + var source = """ + public class C + { + public void Method1() { } + public void Method1(int i) { } + public void Method2() { } + public static void Method2(int i) { } + + public static string StaticField = + nameof(Method1) + + nameof(Method2); + } + """; + var comp = CreateCompilation(source).VerifyDiagnostics(); + + var cMethods1 = comp.GetMembers("C.Method1"); + Assert.Equal(2, cMethods1.Length); + var cMethods2 = comp.GetMembers("C.Method2"); + Assert.Equal(2, cMethods2.Length); + + var tree = comp.SyntaxTrees.Single(); + var tree2 = SyntaxFactory.ParseSyntaxTree(source + " "); + + var initializer = tree2.GetRoot().DescendantNodes().OfType().Single(); + + var nameofCalls = getNameOfCalls(tree); + Assert.Equal(2, nameofCalls.Length); + var nameofCalls2 = getNameOfCalls(tree2); + Assert.Equal(2, nameofCalls2.Length); + + var model = comp.GetSemanticModel(tree); + + verify(0, "Method1", cMethods1); + verify(1, "Method2", cMethods2); + + void verify(int index, string expression, ImmutableArray symbols) + { + var argument = nameofCalls[index].ArgumentList.Arguments.Single().Expression; + Assert.Equal(expression, argument.ToString()); + + verifySymbolInfo(CandidateReason.MemberGroup, model.GetSymbolInfo(argument)); + + var argument2 = nameofCalls2[index].ArgumentList.Arguments.Single().Expression; + Assert.Equal(expression, argument2.ToString()); + + Assert.True(model.TryGetSpeculativeSemanticModel(initializer.Position, initializer, out var model2)); + + verifySymbolInfo(CandidateReason.MemberGroup, model2.GetSymbolInfo(argument2)); + + verifySymbolInfo(CandidateReason.OverloadResolutionFailure, model.GetSpeculativeSymbolInfo(argument2.Position, argument2, SpeculativeBindingOption.BindAsExpression)); + + Assert.True(model.GetSpeculativeSymbolInfo(argument2.Position, argument2, SpeculativeBindingOption.BindAsTypeOrNamespace).IsEmpty); + + void verifySymbolInfo(CandidateReason reason, SymbolInfo symbolInfo) + { + Assert.Equal(reason, symbolInfo.CandidateReason); + AssertEx.SetEqual( + symbols.Select(s => s.GetPublicSymbol()), + symbolInfo.CandidateSymbols, + Roslyn.Utilities.ReferenceEqualityComparer.Instance); + } + } + + static ImmutableArray getNameOfCalls(SyntaxTree tree) + { + return tree.GetRoot().DescendantNodes().OfType() + .Where(e => e.Expression is IdentifierNameSyntax { Identifier.ValueText: "nameof" }) + .ToImmutableArray(); + } + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/67565")] + public void SymbolInfo_InstanceMemberFromStatic_Nested() + { + var source = """ + public class C + { + public C1 Property { get; } + public C1 Field; + + public static string StaticField = + nameof(Property.Property) + + nameof(Property.Field) + + nameof(Property.Event) + + nameof(Field.Property) + + nameof(Field.Field) + + nameof(Field.Event); + } + + public class C1 + { + public int Property { get; } + public int Field; + public event System.Action Event; + } + """; + var comp = CreateCompilation(source).VerifyDiagnostics(); + + var c1Property = comp.GetMember("C1.Property"); + var c1Field = comp.GetMember("C1.Field"); + var c1Event = comp.GetMember("C1.Event"); + + var tree = comp.SyntaxTrees.Single(); + var tree2 = SyntaxFactory.ParseSyntaxTree(source + " "); + + var initializer = tree2.GetRoot().DescendantNodes().OfType().Single(); + + var nameofCalls = getNameOfCalls(tree); + Assert.Equal(6, nameofCalls.Length); + var nameofCalls2 = getNameOfCalls(tree2); + Assert.Equal(6, nameofCalls2.Length); + + var model = comp.GetSemanticModel(tree); + + verify(0, "Property.Property", c1Property); + verify(1, "Property.Field", c1Field); + verify(2, "Property.Event", c1Event); + verify(3, "Field.Property", c1Property); + verify(4, "Field.Field", c1Field); + verify(5, "Field.Event", c1Event); + + void verify(int index, string expression, Symbol symbol) + { + var argument = nameofCalls[index].ArgumentList.Arguments.Single().Expression; + Assert.Equal(expression, argument.ToString()); + + verifySymbolInfo(model.GetSymbolInfo(argument)); + + var argument2 = nameofCalls2[index].ArgumentList.Arguments.Single().Expression; + Assert.Equal(expression, argument2.ToString()); + + Assert.True(model.TryGetSpeculativeSemanticModel(initializer.Position, initializer, out var model2)); + + verifySymbolInfo(model2.GetSymbolInfo(argument2)); + + verifySymbolInfo(model.GetSpeculativeSymbolInfo(argument2.Position, argument2, SpeculativeBindingOption.BindAsExpression)); + + Assert.True(model.GetSpeculativeSymbolInfo(argument2.Position, argument2, SpeculativeBindingOption.BindAsTypeOrNamespace).IsEmpty); + + void verifySymbolInfo(SymbolInfo symbolInfo) + { + Assert.NotNull(symbolInfo.Symbol); + Assert.Same(symbol.GetPublicSymbol(), symbolInfo.Symbol); + } + } + + static ImmutableArray getNameOfCalls(SyntaxTree tree) + { + return tree.GetRoot().DescendantNodes().OfType() + .Where(e => e.Expression is IdentifierNameSyntax { Identifier.ValueText: "nameof" }) + .ToImmutableArray(); + } + } + + [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/67565")] + public void SymbolInfo_InstanceMemberFromStatic_Nested_MethodGroup() + { + var source = """ + public class C + { + public C1 Property { get; } + public C1 Field; + public event System.Action Event; + + public static string StaticField = + nameof(Property.Method) + + nameof(Field.Method) + + nameof(Event.Invoke); + } + + public class C1 + { + public void Method() { } + public void Method(int i) { } + } + """; + var comp = CreateCompilation(source).VerifyDiagnostics(); + + var c1Methods = comp.GetMembers("C1.Method").ToArray(); + Assert.Equal(2, c1Methods.Length); + var c1Event = comp.GetMember("C1.Event"); + var actionInvoke = comp.GetWellKnownType(WellKnownType.System_Action).GetMember("Invoke"); + + var tree = comp.SyntaxTrees.Single(); + var tree2 = SyntaxFactory.ParseSyntaxTree(source + " "); + + var initializer = tree2.GetRoot().DescendantNodes().OfType().Single(); + + var nameofCalls = getNameOfCalls(tree); + Assert.Equal(3, nameofCalls.Length); + var nameofCalls2 = getNameOfCalls(tree2); + Assert.Equal(3, nameofCalls2.Length); + + var model = comp.GetSemanticModel(tree); + + verify(0, "Property.Method", c1Methods); + verify(1, "Field.Method", c1Methods); + verify(2, "Event.Invoke", actionInvoke); + + void verify(int index, string expression, params Symbol[] symbols) + { + var argument = nameofCalls[index].ArgumentList.Arguments.Single().Expression; + Assert.Equal(expression, argument.ToString()); + + verifySymbolInfo(CandidateReason.MemberGroup, model.GetSymbolInfo(argument)); + + var argument2 = nameofCalls2[index].ArgumentList.Arguments.Single().Expression; + Assert.Equal(expression, argument2.ToString()); + + Assert.True(model.TryGetSpeculativeSemanticModel(initializer.Position, initializer, out var model2)); + + verifySymbolInfo(CandidateReason.MemberGroup, model2.GetSymbolInfo(argument2)); + + verifySymbolInfo(CandidateReason.OverloadResolutionFailure, model.GetSpeculativeSymbolInfo(argument2.Position, argument2, SpeculativeBindingOption.BindAsExpression)); + + Assert.True(model.GetSpeculativeSymbolInfo(argument2.Position, argument2, SpeculativeBindingOption.BindAsTypeOrNamespace).IsEmpty); + + void verifySymbolInfo(CandidateReason reason, SymbolInfo symbolInfo) + { + Assert.Equal(reason, symbolInfo.CandidateReason); + AssertEx.SetEqual( + symbols.Select(s => s.GetPublicSymbol()), + symbolInfo.CandidateSymbols, + Roslyn.Utilities.ReferenceEqualityComparer.Instance); + } + } + + static ImmutableArray getNameOfCalls(SyntaxTree tree) + { + return tree.GetRoot().DescendantNodes().OfType() + .Where(e => e.Expression is IdentifierNameSyntax { Identifier.ValueText: "nameof" }) + .ToImmutableArray(); + } + } + [Fact] public void ExtensionMethodConstraintFailed() { @@ -1487,5 +1798,580 @@ 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_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(); + CompileAndVerify(source, parseOptions: TestOptions.RegularPreview, 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; + public event System.Action Event; + public static string M() => nameof(Property.Property) + + "","" + nameof(Property.Field) + + "","" + nameof(Property.Method) + + "","" + nameof(Property.Event) + + "","" + nameof(Field.Property) + + "","" + nameof(Field.Field) + + "","" + nameof(Field.Method) + + "","" + nameof(Field.Event) + + "","" + nameof(Event.Invoke) + ; +} + +public class C1 +{ + public int Property { get; } + public int Field; + public void Method(){} + public event System.Action Event; +}"; + var expectedOutput = "Property,Field,Method,Event,Property,Field,Method,Event,Invoke"; + CompileAndVerify(source, parseOptions: TestOptions.RegularNext, expectedOutput: expectedOutput).VerifyDiagnostics(); + CompileAndVerify(source, parseOptions: TestOptions.RegularPreview, expectedOutput: expectedOutput).VerifyDiagnostics(); + CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics( + // (8,40): error CS8652: The feature 'instance member 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("instance member in 'nameof'").WithLocation(8, 40), + // (9,24): error CS8652: The feature 'instance member 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("instance member in 'nameof'").WithLocation(9, 24), + // (10,24): error CS8652: The feature 'instance member 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("instance member in 'nameof'").WithLocation(10, 24), + // (11,24): error CS8652: The feature 'instance member 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("instance member in 'nameof'").WithLocation(11, 24), + // (12,24): error CS8652: The feature 'instance member 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("instance member in 'nameof'").WithLocation(12, 24), + // (13,24): error CS8652: The feature 'instance member 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("instance member in 'nameof'").WithLocation(13, 24), + // (14,24): error CS8652: The feature 'instance member 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("instance member in 'nameof'").WithLocation(14, 24), + // (15,24): error CS8652: The feature 'instance member 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("instance member in 'nameof'").WithLocation(15, 24), + // (16,24): error CS8652: The feature 'instance member 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("instance member in 'nameof'").WithLocation(16, 24)); + } + + [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] + public void InstanceFromStatic_Lambdas() + { + var source = """ + using System; + Console.Write(C.Names()); + public class C + { + public object Property { get; } + public object Field; + public event Action Event; + public void Method() { } + public static string Names() + { + var lambda1 = static () => nameof(Property); + var lambda2 = static (string f = nameof(Field)) => f; + var lambda3 = static () => nameof(Event.Invoke); + var lambda4 = static (string i = nameof(Event.Invoke)) => i; + return lambda1() + "," + lambda2() + "," + lambda3() + "," + lambda4(); + } + } + """; + var expectedOutput = "Property,Field,Invoke,Invoke"; + + CompileAndVerify(source, parseOptions: TestOptions.RegularNext, expectedOutput: expectedOutput).VerifyDiagnostics(); + CompileAndVerify(source, parseOptions: TestOptions.RegularPreview, expectedOutput: expectedOutput).VerifyDiagnostics(); + CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics( + // (12,40): error CS8652: The feature 'lambda optional parameters' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // var lambda2 = static (string f = nameof(Field)) => f; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "=").WithArguments("lambda optional parameters").WithLocation(12, 40), + // (13,43): error CS8652: The feature 'instance member in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // var lambda3 = static () => nameof(Event.Invoke); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Event").WithArguments("instance member in 'nameof'").WithLocation(13, 43), + // (14,40): error CS8652: The feature 'lambda optional parameters' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // var lambda4 = static (string i = nameof(Event.Invoke)) => i; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "=").WithArguments("lambda optional parameters").WithLocation(14, 40), + // (14,49): error CS8652: The feature 'instance member in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // var lambda4 = static (string i = nameof(Event.Invoke)) => i; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Event").WithArguments("instance member in 'nameof'").WithLocation(14, 49)); + } + + [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] + public void InstanceFromStatic_LocalFunctions() + { + var source = """ + using System; + Console.Write(C.Names()); + public class C + { + public object Property { get; } + public object Field; + public event Action Event; + public void Method() { } + public static string Names() + { + static string local1() => nameof(Property); + static string local2(string f = nameof(Field)) => f; + static string local3() => nameof(Event.Invoke); + static string local4(string i = nameof(Event.Invoke)) => i; + return local1() + "," + local2() + "," + local3() + "," + local4(); + } + } + """; + var expectedOutput = "Property,Field,Invoke,Invoke"; + + CompileAndVerify(source, parseOptions: TestOptions.RegularNext, expectedOutput: expectedOutput).VerifyDiagnostics(); + CompileAndVerify(source, parseOptions: TestOptions.RegularPreview, expectedOutput: expectedOutput).VerifyDiagnostics(); + CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics( + // (13,42): error CS8652: The feature 'instance member in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // static string local3() => nameof(Event.Invoke); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Event").WithArguments("instance member in 'nameof'").WithLocation(13, 42), + // (14,48): error CS8652: The feature 'instance member in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // static string local4(string i = nameof(Event.Invoke)) => i; + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Event").WithArguments("instance member in 'nameof'").WithLocation(14, 48)); + } + + [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); +}"; + CompileAndVerify(source, parseOptions: TestOptions.RegularNext, expectedOutput: "Length").VerifyDiagnostics(); + CompileAndVerify(source, parseOptions: TestOptions.RegularPreview, expectedOutput: "Length").VerifyDiagnostics(); + CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics( + // (5,39): error CS8652: The feature 'instance member 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("instance member 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; } +}"; + var expectedDiagnostics = new[] + { + // (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.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(source, parseOptions: TestOptions.RegularPreview).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics( + // (5,29): error CS8652: The feature 'instance member 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("instance member 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){ S = s; } + public C() : this(nameof(S.Length)){} + public string S { get; } +}"; + CompileAndVerify(source, parseOptions: TestOptions.RegularNext, expectedOutput: "Length").VerifyDiagnostics(); + CompileAndVerify(source, parseOptions: TestOptions.RegularPreview, expectedOutput: "Length").VerifyDiagnostics(); + CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics( + // (6,30): error CS8652: The feature 'instance member 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("instance member in 'nameof'").WithLocation(6, 30)); + } + + [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] + 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()); + } +}"; + CompileAndVerify(source, parseOptions: TestOptions.RegularNext, expectedOutput: "Length").VerifyDiagnostics(); + CompileAndVerify(source, parseOptions: TestOptions.RegularPreview, expectedOutput: "Length").VerifyDiagnostics(); + CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics( + // (12,42): error CS8652: The feature 'instance member 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("instance member 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); +}"; + CompileAndVerify(source, parseOptions: TestOptions.RegularNext, expectedOutput: "StaticProp").VerifyDiagnostics(); + CompileAndVerify(source, parseOptions: TestOptions.RegularPreview, expectedOutput: "StaticProp").VerifyDiagnostics(); + CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics( + // (7,33): error CS8652: The feature 'instance member 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("instance member 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); +}"; + CompileAndVerify(source, parseOptions: TestOptions.RegularNext, expectedOutput: "StaticProp").VerifyDiagnostics(); + CompileAndVerify(source, parseOptions: TestOptions.RegularPreview, expectedOutput: "StaticProp").VerifyDiagnostics(); + CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics( + // (7,40): error CS8652: The feature 'instance member 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("instance member in 'nameof'").WithLocation(7, 40), + // (7,40): error CS8652: The feature 'instance member 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("instance member 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); +}"; + CompileAndVerify(source, parseOptions: TestOptions.RegularNext, expectedOutput: "M").VerifyDiagnostics(); + CompileAndVerify(source, parseOptions: TestOptions.RegularPreview, expectedOutput: "M").VerifyDiagnostics(); + CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics( + // (6,40): error CS8652: The feature 'instance member 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("instance member 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); +}"; + CompileAndVerify(source, parseOptions: TestOptions.RegularNext, expectedOutput: "StaticMethod").VerifyDiagnostics(); + CompileAndVerify(source, parseOptions: TestOptions.RegularPreview, expectedOutput: "StaticMethod").VerifyDiagnostics(); + CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics(); + } + + [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] + public void TestCannotReferenceInstanceMembersFromStaticMemberInNameofInCSharp11() + { + var source = @" +public class C +{ + public string S { get; } + public static string M() => nameof(S.Length); +}"; + CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics( + // (5,40): error CS8652: The feature 'instance member 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("instance member in 'nameof'").WithLocation(5, 40)); + } + + [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] + public void TestCannotReferenceInstanceMembersFromFieldInitializerInNameofInCSharp11() + { + var source = @" +public class C +{ + public string S { get; } = nameof(S.Length); +}"; + CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics( + // (4,39): error CS8652: The feature 'instance member 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("instance member in 'nameof'").WithLocation(4, 39)); + } + + [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] + public void TestCannotReferenceInstanceMembersFromAttributeInNameofInCSharp11() + { + var source = @" +public class C +{ + [System.Obsolete(nameof(S.Length))] + public int P { get; } + public string S { get; } +}"; + CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics( + // (4,29): error CS8652: The feature 'instance member 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("instance member in 'nameof'").WithLocation(4, 29)); + } + + [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] + public void TestCannotReferenceInstanceMembersFromConstructorInitializersInNameofInCSharp11() + { + var source = @" +public class C +{ + public C(string s){} + public C() : this(nameof(S.Length)){} + public string S { get; } +}"; + CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics( + // (5,30): error CS8652: The feature 'instance member 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("instance member in 'nameof'").WithLocation(5, 30)); + } + + [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] + public void TestCannotAccessStructInstancePropertyInLambdaInNameofInCSharp11() + { + 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.Regular11).VerifyDiagnostics( + // (9,42): error CS8652: The feature 'instance member 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("instance member in 'nameof'").WithLocation(9, 42)); + } + + [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] + public void TestCannotReferenceStaticPropertyFromInstanceMemberInNameofInCSharp11() + { + var source = @" +public class C +{ + public C Prop { get; } + public static int StaticProp { get; } + public string M() => nameof(Prop.StaticProp); +}"; + CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics( + // (6,33): error CS8652: The feature 'instance member 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("instance member in 'nameof'").WithLocation(6, 33)); + } + + [Fact] + 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); +}"; + CompileAndVerify(source, parseOptions: TestOptions.Regular11, expectedOutput: "StaticMethod").VerifyDiagnostics(); + CompileAndVerify(source, parseOptions: TestOptions.RegularPreview, expectedOutput: "StaticMethod").VerifyDiagnostics(); + } + + [Fact] + 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()); + } +}"; + CompileAndVerify(source, parseOptions: TestOptions.Regular11, expectedOutput: "Length").VerifyDiagnostics(); + CompileAndVerify(source, parseOptions: TestOptions.RegularPreview, 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 : Attribute +{ + public readonly string S; + public Attr(string s) { S = s; } +}"; + CompileAndVerify(source, parseOptions: TestOptions.RegularNext, expectedOutput: "StaticMethod").VerifyDiagnostics(); + CompileAndVerify(source, parseOptions: TestOptions.RegularPreview, expectedOutput: "StaticMethod").VerifyDiagnostics(); + CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics( + // (7,18): error CS8652: The feature 'instance member in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // [Attr(nameof(Prop.StaticMethod))] + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Prop").WithArguments("instance member in 'nameof'").WithLocation(7, 18)); + } + + [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 : Attribute +{ + public readonly string S; + public Attr(string s) { S = s; } +}"; + CompileAndVerify(source, parseOptions: TestOptions.RegularNext, expectedOutput: "Prop").VerifyDiagnostics(); + CompileAndVerify(source, parseOptions: TestOptions.RegularPreview, expectedOutput: "Prop").VerifyDiagnostics(); + CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics( + // (7,18): error CS8652: The feature 'instance member in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // [Attr(nameof(Prop.Prop))] + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Prop.Prop").WithArguments("instance member in 'nameof'").WithLocation(7, 18)); + } + + [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 : Attribute +{ + public readonly string S; + public Attr(string s) { S = s; } +}"; + CompileAndVerify(source, parseOptions: TestOptions.RegularNext, expectedOutput: "Prop").VerifyDiagnostics(); + CompileAndVerify(source, parseOptions: TestOptions.RegularPreview, expectedOutput: "Prop").VerifyDiagnostics(); + CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics( + // (5,14): error CS8652: The feature 'instance member in 'nameof'' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // [Attr(nameof(C.Prop.Prop))] + Diagnostic(ErrorCode.ERR_FeatureInPreview, "C.Prop.Prop").WithArguments("instance member in 'nameof'").WithLocation(5, 14)); + } + + [Fact, WorkItem(40229, "https://github.com/dotnet/roslyn/issues/40229")] + public void TestInvalidRecursiveUsageOfNameofInAttributesDoesNotCrashCompiler1() + { + var source = @" +class C +{ + [Attr(nameof(Method().Method))] + T Method() where T : C => default; +} +class Attr : System.Attribute { public Attr(string s) {} }"; + var expectedDiagnostics = new[] + { + // (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) + }; + CreateCompilation(source, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(source, parseOptions: TestOptions.RegularPreview).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics(expectedDiagnostics); + } + + [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) {} }"; + var expectedDiagnostics = new[] + { + // (4,18): error CS8082: Sub-expression cannot be used in an argument to nameof. + // [Attr(nameof(Method().Method))] + Diagnostic(ErrorCode.ERR_SubexpressionNotInNameof, "Method()").WithLocation(4, 18) + }; + CreateCompilation(source, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(source, parseOptions: TestOptions.RegularPreview).VerifyDiagnostics(expectedDiagnostics); + CreateCompilation(source, parseOptions: TestOptions.Regular11).VerifyDiagnostics(expectedDiagnostics); + } } } diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs index f35bd414f7716..fe6c672902c0a 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/StaticAbstractMembersInInterfacesTests.cs @@ -13102,18 +13102,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 CS0704: Cannot do non-virtual member lookup in 'T' because it is a type parameter // _ = nameof(T.P03); Diagnostic(ErrorCode.ERR_LookupInTypeVariable, "T").WithArguments("T").WithLocation(35, 20), @@ -13984,18 +13972,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 CS0704: Cannot do non-virtual member lookup in 'T' because it is a type parameter // _ = nameof(T.P03); Diagnostic(ErrorCode.ERR_LookupInTypeVariable, "T").WithArguments("T").WithLocation(35, 20), diff --git a/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests.vb b/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests.vb index 4499972614167..2741b9b1d2052 100644 --- a/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests.vb +++ b/src/EditorFeatures/Test2/IntelliSense/CSharpCompletionCommandHandlerTests.vb @@ -11487,5 +11487,65 @@ class Program Await state.AssertCompletionItemsDoNotContainAny("first", "second") End Using End Function + + + Public Async Function NameOf_Flat() As Task + Using state = TestStateFactory.CreateCSharpTestState( + + , + languageVersion:=LanguageVersion.Preview) + + state.SendInvokeCompletionList() + Await state.AssertCompletionItemsContainAll("Property0", "Field0", "Event0") + Await state.AssertCompletionItemsDoNotContainAny("Property1", "Field1", "Event1") + End Using + End Function + + + Public Async Function NameOf_Nested() As Task + Using state = TestStateFactory.CreateCSharpTestState( + + , + languageVersion:=LanguageVersion.Preview) + + state.SendInvokeCompletionList() + Await state.AssertCompletionItemsContainAll("Property1", "Field1", "Event1") + Await state.AssertCompletionItemsDoNotContainAny("Property0", "Field0", "Event0") + End Using + End Function End Class End Namespace