From 38179e34ba0b858206507635041b203595a5e99d Mon Sep 17 00:00:00 2001 From: yair halberstadt Date: Thu, 17 Jan 2019 09:19:56 +0000 Subject: [PATCH 01/18] Remove code dissallowing Obsolete on Properties, and Unit Test that Obsolete works as expected. --- .../Source/SourceMemberMethodSymbol.cs | 3 - .../AttributeTests_WellKnownAttributes.cs | 119 ++++++++++-------- 2 files changed, 68 insertions(+), 54 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs index a110cbc67f8ef..33328bd4b8f08 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs @@ -1164,9 +1164,6 @@ private void DecodeWellKnownAttributeAppliedToMethod(ref DecodeWellKnownAttribut { arguments.GetOrCreateData().HasDynamicSecurityMethodAttribute = true; } - else if (VerifyObsoleteAttributeAppliedToMethod(ref arguments, AttributeDescription.ObsoleteAttribute)) - { - } else if (VerifyObsoleteAttributeAppliedToMethod(ref arguments, AttributeDescription.DeprecatedAttribute)) { } diff --git a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs b/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs index 0bb412ac4336e..5f7e06cb21f5b 100644 --- a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs +++ b/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs @@ -5678,7 +5678,7 @@ class SelfReferenceInBase1 : IGoo {} } [Fact] - public void TestObsoleteAttributeOnMembers() + public void TestObsleteOnPropertyAccessorsoleteAttributeOnMembers() { var source = @" using System; @@ -5698,6 +5698,16 @@ public static void Main() var f = t.field1; var p1 = t.Property1; var p2 = t.Property2; + + var p3 = t.Prop2; + t.Prop2 = p3; + + var p4 = t.Prop3; + t.Prop3 = p4; + + var p5 = t.Prop4; + t.Prop4 = p5; + t.event1(); t.event1 += () => { }; @@ -5750,6 +5760,7 @@ public static void ObsoleteMethod5() { } public int Prop2 { [Obsolete] get { return 10; } + set {} } public int Prop3 @@ -5758,6 +5769,12 @@ public int Prop3 [Obsolete] set { } } + public int Prop4 + { + [Obsolete] get { return 10; } + [Obsolete] set { } + } + public event Action event2 { [Obsolete] add {} @@ -5793,78 +5810,78 @@ public static void ObsoleteExtensionMethod1(this Test t) { } } "; CreateCompilationWithMscorlib40(source, new[] { ExtensionAssemblyRef }).VerifyDiagnostics( - // (65,10): error CS1667: Attribute 'Obsolete' is not valid on property or event accessors. It is only valid on 'class, struct, enum, constructor, method, property, indexer, field, event, interface, delegate' declarations. - // [Obsolete] get { return 10; } - Diagnostic(ErrorCode.ERR_AttributeNotOnAccessor, "Obsolete").WithArguments("System.ObsoleteAttribute", "class, struct, enum, constructor, method, property, indexer, field, event, interface, delegate"), - // (71,10): error CS1667: Attribute 'Obsolete' is not valid on property or event accessors. It is only valid on 'class, struct, enum, constructor, method, property, indexer, field, event, interface, delegate' declarations. - // [Obsolete] set { } - Diagnostic(ErrorCode.ERR_AttributeNotOnAccessor, "Obsolete").WithArguments("System.ObsoleteAttribute", "class, struct, enum, constructor, method, property, indexer, field, event, interface, delegate"), - // (76,10): error CS1667: Attribute 'Obsolete' is not valid on property or event accessors. It is only valid on 'class, struct, enum, constructor, method, property, indexer, field, event, interface, delegate' declarations. - // [Obsolete] add {} - Diagnostic(ErrorCode.ERR_AttributeNotOnAccessor, "Obsolete").WithArguments("System.ObsoleteAttribute", "class, struct, enum, constructor, method, property, indexer, field, event, interface, delegate"), - // (77,10): error CS1667: Attribute 'Obsolete' is not valid on property or event accessors. It is only valid on 'class, struct, enum, constructor, method, property, indexer, field, event, interface, delegate' declarations. - // [Obsolete("Don't use remove accessor")] remove {} - Diagnostic(ErrorCode.ERR_AttributeNotOnAccessor, "Obsolete").WithArguments("System.ObsoleteAttribute", "class, struct, enum, constructor, method, property, indexer, field, event, interface, delegate"), // (8,9): warning CS0612: 'Test.ObsoleteMethod1()' is obsolete // ObsoleteMethod1(); - Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "ObsoleteMethod1()").WithArguments("Test.ObsoleteMethod1()"), + Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "ObsoleteMethod1()").WithArguments("Test.ObsoleteMethod1()").WithLocation(8, 9), // (9,9): warning CS0618: 'Test.ObsoleteMethod2()' is obsolete: 'Do not call this method' // ObsoleteMethod2(); - Diagnostic(ErrorCode.WRN_DeprecatedSymbolStr, "ObsoleteMethod2()").WithArguments("Test.ObsoleteMethod2()", "Do not call this method"), + Diagnostic(ErrorCode.WRN_DeprecatedSymbolStr, "ObsoleteMethod2()").WithArguments("Test.ObsoleteMethod2()", "Do not call this method").WithLocation(9, 9), // (10,9): error CS0619: 'Test.ObsoleteMethod3()' is obsolete: '' // ObsoleteMethod3(); - Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "ObsoleteMethod3()").WithArguments("Test.ObsoleteMethod3()", ""), + Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "ObsoleteMethod3()").WithArguments("Test.ObsoleteMethod3()", "").WithLocation(10, 9), // (11,9): warning CS0612: 'Test.ObsoleteMethod5()' is obsolete // ObsoleteMethod5(); - Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "ObsoleteMethod5()").WithArguments("Test.ObsoleteMethod5()"), - // (14,9): warning CS0618: 'Test.ObsoleteMethod4()' is obsolete: 'Do not call this method' + Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "ObsoleteMethod5()").WithArguments("Test.ObsoleteMethod5()").WithLocation(11, 9), + // (15,9): warning CS0618: 'Test.ObsoleteMethod4()' is obsolete: 'Do not call this method' // t.ObsoleteMethod4(); - Diagnostic(ErrorCode.WRN_DeprecatedSymbolStr, "t.ObsoleteMethod4()").WithArguments("Test.ObsoleteMethod4()", "Do not call this method"), - // (15,17): warning CS0618: 'Test.field1' is obsolete: 'Do not use this field' + Diagnostic(ErrorCode.WRN_DeprecatedSymbolStr, "t.ObsoleteMethod4()").WithArguments("Test.ObsoleteMethod4()", "Do not call this method").WithLocation(15, 9), + // (16,17): warning CS0618: 'Test.field1' is obsolete: 'Do not use this field' // var f = t.field1; - Diagnostic(ErrorCode.WRN_DeprecatedSymbolStr, "t.field1").WithArguments("Test.field1", "Do not use this field"), - // (16,18): warning CS0618: 'Test.Property1' is obsolete: 'Do not use this property' + Diagnostic(ErrorCode.WRN_DeprecatedSymbolStr, "t.field1").WithArguments("Test.field1", "Do not use this field").WithLocation(16, 17), + // (17,18): warning CS0618: 'Test.Property1' is obsolete: 'Do not use this property' // var p1 = t.Property1; - Diagnostic(ErrorCode.WRN_DeprecatedSymbolStr, "t.Property1").WithArguments("Test.Property1", "Do not use this property"), - // (17,18): warning CS0618: 'Test.Property2' is obsolete: 'Do not use this property' + Diagnostic(ErrorCode.WRN_DeprecatedSymbolStr, "t.Property1").WithArguments("Test.Property1", "Do not use this property").WithLocation(17, 18), + // (18,18): warning CS0618: 'Test.Property2' is obsolete: 'Do not use this property' // var p2 = t.Property2; - Diagnostic(ErrorCode.WRN_DeprecatedSymbolStr, "t.Property2").WithArguments("Test.Property2", "Do not use this property"), - // (19,9): warning CS0618: 'Test.event1' is obsolete: 'Do not use this event' - // t.event1 += () => { }; - Diagnostic(ErrorCode.WRN_DeprecatedSymbolStr, "t.event1").WithArguments("Test.event1", "Do not use this event"), - // (21,9): warning CS0618: 'TestExtension.ObsoleteExtensionMethod1(Test)' is obsolete: 'Do not call this extension method' + Diagnostic(ErrorCode.WRN_DeprecatedSymbolStr, "t.Property2").WithArguments("Test.Property2", "Do not use this property").WithLocation(18, 18), + // (20,18): warning CS0612: 'Test.Prop2.get' is obsolete + // var p3 = t.Prop2; + Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "t.Prop2").WithArguments("Test.Prop2.get").WithLocation(20, 18), + // (24,9): warning CS0612: 'Test.Prop3.set' is obsolete + // t.Prop3 = p4; + Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "t.Prop3").WithArguments("Test.Prop3.set").WithLocation(24, 9), + // (26,18): warning CS0612: 'Test.Prop4.get' is obsolete + // var p5 = t.Prop4; + Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "t.Prop4").WithArguments("Test.Prop4.get").WithLocation(26, 18), + // (27,9): warning CS0612: 'Test.Prop4.set' is obsolete + // t.Prop4 = p5; + Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "t.Prop4").WithArguments("Test.Prop4.set").WithLocation(27, 9), + // (32,9): warning CS0618: 'TestExtension.ObsoleteExtensionMethod1(Test)' is obsolete: 'Do not call this extension method' // t.ObsoleteExtensionMethod1(); - Diagnostic(ErrorCode.WRN_DeprecatedSymbolStr, "t.ObsoleteExtensionMethod1()").WithArguments("TestExtension.ObsoleteExtensionMethod1(Test)", "Do not call this extension method"), - // (23,28): warning CS0618: 'Test.ObsoleteMethod4(int)' is obsolete: 'Do not call this method' + Diagnostic(ErrorCode.WRN_DeprecatedSymbolStr, "t.ObsoleteExtensionMethod1()").WithArguments("TestExtension.ObsoleteExtensionMethod1(Test)", "Do not call this extension method").WithLocation(32, 9), + // (34,28): warning CS0618: 'Test.ObsoleteMethod4(int)' is obsolete: 'Do not call this method' // Action func = t.ObsoleteMethod4; - Diagnostic(ErrorCode.WRN_DeprecatedSymbolStr, "t.ObsoleteMethod4").WithArguments("Test.ObsoleteMethod4(int)", "Do not call this method"), - // (25,24): warning CS0618: 'Test.ObsoleteMethod4()' is obsolete: 'Do not call this method' + Diagnostic(ErrorCode.WRN_DeprecatedSymbolStr, "t.ObsoleteMethod4").WithArguments("Test.ObsoleteMethod4(int)", "Do not call this method").WithLocation(34, 28), + // (36,24): warning CS0618: 'Test.ObsoleteMethod4()' is obsolete: 'Do not call this method' // Action func1 = t.ObsoleteMethod4; - Diagnostic(ErrorCode.WRN_DeprecatedSymbolStr, "t.ObsoleteMethod4").WithArguments("Test.ObsoleteMethod4()", "Do not call this method"), - // (29,30): warning CS0618: 'Test.Property1' is obsolete: 'Do not use this property' + Diagnostic(ErrorCode.WRN_DeprecatedSymbolStr, "t.ObsoleteMethod4").WithArguments("Test.ObsoleteMethod4()", "Do not call this method").WithLocation(36, 24), + // (38,30): warning CS0618: 'Test.Property1' is obsolete: 'Do not use this property' // Test t1 = new Test { Property1 = 10, Property2 =20}; - Diagnostic(ErrorCode.WRN_DeprecatedSymbolStr, "Property1").WithArguments("Test.Property1", "Do not use this property"), - // (29,46): warning CS0618: 'Test.Property2' is obsolete: 'Do not use this property' + Diagnostic(ErrorCode.WRN_DeprecatedSymbolStr, "Property1").WithArguments("Test.Property1", "Do not use this property").WithLocation(38, 30), + // (38,46): warning CS0618: 'Test.Property2' is obsolete: 'Do not use this property' // Test t1 = new Test { Property1 = 10, Property2 =20}; - Diagnostic(ErrorCode.WRN_DeprecatedSymbolStr, "Property2").WithArguments("Test.Property2", "Do not use this property"), - // (28,18): warning CS0612: 'Test.this[int]' is obsolete + Diagnostic(ErrorCode.WRN_DeprecatedSymbolStr, "Property2").WithArguments("Test.Property2", "Do not use this property").WithLocation(38, 46), + // (39,18): warning CS0612: 'Test.this[int]' is obsolete // var i1 = t1[10]; - Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "t1[10]").WithArguments("Test.this[int]"), - // (30,9): warning CS0612: 'GenericTest.ObsoleteMethod1()' is obsolete - // gt.ObsoleteMethod1(); - Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "gt.ObsoleteMethod1()").WithArguments("GenericTest.ObsoleteMethod1()"), - // (31,18): warning CS0618: 'GenericTest.field1' is obsolete: 'Do not use this field' + Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "t1[10]").WithArguments("Test.this[int]").WithLocation(39, 18), + // (42,9): warning CS0612: 'GenericTest.ObsoleteMethod1()' is obsolete + // gt.ObsoleteMethod1(); + Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "gt.ObsoleteMethod1()").WithArguments("GenericTest.ObsoleteMethod1()").WithLocation(42, 9), + // (43,18): warning CS0618: 'GenericTest.field1' is obsolete: 'Do not use this field' // var gf = gt.field1; - Diagnostic(ErrorCode.WRN_DeprecatedSymbolStr, "gt.field1").WithArguments("GenericTest.field1", "Do not use this field"), - // (32,19): warning CS0618: 'GenericTest.Property1' is obsolete: 'Do not use this property' + Diagnostic(ErrorCode.WRN_DeprecatedSymbolStr, "gt.field1").WithArguments("GenericTest.field1", "Do not use this field").WithLocation(43, 18), + // (44,19): warning CS0618: 'GenericTest.Property1' is obsolete: 'Do not use this property' // var gp1 = gt.Property1; - Diagnostic(ErrorCode.WRN_DeprecatedSymbolStr, "gt.Property1").WithArguments("GenericTest.Property1", "Do not use this property"), - // (33,9): warning CS0618: 'GenericTest.event1' is obsolete: 'Do not use this event' + Diagnostic(ErrorCode.WRN_DeprecatedSymbolStr, "gt.Property1").WithArguments("GenericTest.Property1", "Do not use this property").WithLocation(44, 19), + // (30,9): warning CS0618: 'Test.event1' is obsolete: 'Do not use this event' + // t.event1 += () => { }; + Diagnostic(ErrorCode.WRN_DeprecatedSymbolStr, "t.event1").WithArguments("Test.event1", "Do not use this event").WithLocation(30, 9), + // (45,9): warning CS0618: 'GenericTest.event1' is obsolete: 'Do not use this event' // gt.event1 += (i) => { }; - Diagnostic(ErrorCode.WRN_DeprecatedSymbolStr, "gt.event1").WithArguments("GenericTest.event1", "Do not use this event"), - // (104,28): warning CS0067: The event 'GenericTest.event1' is never used + Diagnostic(ErrorCode.WRN_DeprecatedSymbolStr, "gt.event1").WithArguments("GenericTest.event1", "Do not use this event").WithLocation(45, 9), + // (121,28): warning CS0067: The event 'GenericTest.event1' is never used // public event Action event1; - Diagnostic(ErrorCode.WRN_UnreferencedEvent, "event1").WithArguments("GenericTest.event1")); + Diagnostic(ErrorCode.WRN_UnreferencedEvent, "event1").WithArguments("GenericTest.event1").WithLocation(121, 28) } [Fact] From 0af9dcf7eb7452e8b0482ee8f952dadeed63ad47 Mon Sep 17 00:00:00 2001 From: yair halberstadt Date: Fri, 18 Jan 2019 09:01:26 +0000 Subject: [PATCH 02/18] Add further unit tests, and fix bug with suppression of obolete inside accessor declared obsolete. --- .../Symbols/ObsoleteAttributeHelpers.cs | 17 +- .../AttributeTests_WellKnownAttributes.cs | 188 +++++++++++++++--- 2 files changed, 166 insertions(+), 39 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Symbols/ObsoleteAttributeHelpers.cs b/src/Compilers/CSharp/Portable/Symbols/ObsoleteAttributeHelpers.cs index 9afb5890dd69d..708f55bec99b0 100644 --- a/src/Compilers/CSharp/Portable/Symbols/ObsoleteAttributeHelpers.cs +++ b/src/Compilers/CSharp/Portable/Symbols/ObsoleteAttributeHelpers.cs @@ -55,12 +55,7 @@ private static ThreeState GetObsoleteContextState(Symbol symbol, bool forceCompl { while ((object)symbol != null) { - // For property or event accessors, check the associated property or event instead. - if (symbol.IsAccessor()) - { - symbol = ((MethodSymbol)symbol).AssociatedSymbol; - } - else if (symbol.Kind == SymbolKind.Field) + if (symbol.Kind == SymbolKind.Field) { // If this is the backing field of an event, look at the event instead. var associatedSymbol = ((FieldSymbol)symbol).AssociatedSymbol; @@ -81,7 +76,15 @@ private static ThreeState GetObsoleteContextState(Symbol symbol, bool forceCompl return state; } - symbol = symbol.ContainingSymbol; + // For property or event accessors, check the associated property or event next. + if (symbol.IsAccessor()) + { + symbol = ((MethodSymbol)symbol).AssociatedSymbol; + } + else + { + symbol = symbol.ContainingSymbol; + } } return ThreeState.False; diff --git a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs b/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs index 5f7e06cb21f5b..94c6c0dca45dd 100644 --- a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs +++ b/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs @@ -5881,7 +5881,7 @@ public static void ObsoleteExtensionMethod1(this Test t) { } Diagnostic(ErrorCode.WRN_DeprecatedSymbolStr, "gt.event1").WithArguments("GenericTest.event1", "Do not use this event").WithLocation(45, 9), // (121,28): warning CS0067: The event 'GenericTest.event1' is never used // public event Action event1; - Diagnostic(ErrorCode.WRN_UnreferencedEvent, "event1").WithArguments("GenericTest.event1").WithLocation(121, 28) + Diagnostic(ErrorCode.WRN_UnreferencedEvent, "event1").WithArguments("GenericTest.event1").WithLocation(121, 28)); } [Fact] @@ -5985,6 +5985,10 @@ public void TestMethod() {} [Obsolete(""Do not use Prop1"", false)] public int Prop1 { get; set; } + public int Prop2 { [Obsolete(""Do not use Prop2.Get"")] get; set; } + + public int Prop3 { get; [Obsolete(""Do not use Prop3.Get"", true)] set; } + [Obsolete(""Do not use field1"", true)] public TestClass field1; @@ -6010,37 +6014,47 @@ public static void Main() c = c.field1; c.event1(); c.event1 += () => {}; + c.Prop2 = 42; + i = c.Prop2; + c.Prop3 = 42; + i = c.Prop3; } } "; CreateCompilation(source, new[] { peReference }).VerifyDiagnostics( - // (4,29): warning CS0612: 'TestClass1' is obsolete - // public static void goo1(TestClass1 c) {} - Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "TestClass1").WithArguments("TestClass1"), // (5,29): warning CS0618: 'TestClass2' is obsolete: 'TestClass2 is obsolete' // public static void goo2(TestClass2 c) {} - Diagnostic(ErrorCode.WRN_DeprecatedSymbolStr, "TestClass2").WithArguments("TestClass2", "TestClass2 is obsolete"), + Diagnostic(ErrorCode.WRN_DeprecatedSymbolStr, "TestClass2").WithArguments("TestClass2", "TestClass2 is obsolete").WithLocation(5, 29), // (6,29): error CS0619: 'TestClass3' is obsolete: 'Do not use TestClass3' // public static void goo3(TestClass3 c) {} - Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "TestClass3").WithArguments("TestClass3", "Do not use TestClass3"), + Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "TestClass3").WithArguments("TestClass3", "Do not use TestClass3").WithLocation(6, 29), // (7,29): warning CS0618: 'TestClass4' is obsolete: 'TestClass4 is obsolete' // public static void goo4(TestClass4 c) {} - Diagnostic(ErrorCode.WRN_DeprecatedSymbolStr, "TestClass4").WithArguments("TestClass4", "TestClass4 is obsolete"), + Diagnostic(ErrorCode.WRN_DeprecatedSymbolStr, "TestClass4").WithArguments("TestClass4", "TestClass4 is obsolete").WithLocation(7, 29), + // (4,29): warning CS0612: 'TestClass1' is obsolete + // public static void goo1(TestClass1 c) {} + Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "TestClass1").WithArguments("TestClass1").WithLocation(4, 29), // (12,9): warning CS0618: 'TestClass.TestMethod()' is obsolete: 'Do not use TestMethod' // c.TestMethod(); - Diagnostic(ErrorCode.WRN_DeprecatedSymbolStr, "c.TestMethod()").WithArguments("TestClass.TestMethod()", "Do not use TestMethod"), + Diagnostic(ErrorCode.WRN_DeprecatedSymbolStr, "c.TestMethod()").WithArguments("TestClass.TestMethod()", "Do not use TestMethod").WithLocation(12, 9), // (13,17): warning CS0618: 'TestClass.Prop1' is obsolete: 'Do not use Prop1' // var i = c.Prop1; - Diagnostic(ErrorCode.WRN_DeprecatedSymbolStr, "c.Prop1").WithArguments("TestClass.Prop1", "Do not use Prop1"), + Diagnostic(ErrorCode.WRN_DeprecatedSymbolStr, "c.Prop1").WithArguments("TestClass.Prop1", "Do not use Prop1").WithLocation(13, 17), // (14,13): error CS0619: 'TestClass.field1' is obsolete: 'Do not use field1' // c = c.field1; - Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "c.field1").WithArguments("TestClass.field1", "Do not use field1"), + Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "c.field1").WithArguments("TestClass.field1", "Do not use field1").WithLocation(14, 13), // (15,9): error CS0619: 'TestClass.event1' is obsolete: 'Do not use event' // c.event1(); - Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "c.event1").WithArguments("TestClass.event1", "Do not use event"), + Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "c.event1").WithArguments("TestClass.event1", "Do not use event").WithLocation(15, 9), // (16,9): error CS0619: 'TestClass.event1' is obsolete: 'Do not use event' // c.event1 += () => {}; - Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "c.event1").WithArguments("TestClass.event1", "Do not use event")); + Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "c.event1").WithArguments("TestClass.event1", "Do not use event").WithLocation(16, 9), + // (18,13): warning CS0618: 'TestClass.Prop2.get' is obsolete: 'Do not use Prop2.Get' + // i = c.Prop2; + Diagnostic(ErrorCode.WRN_DeprecatedSymbolStr, "c.Prop2").WithArguments("TestClass.Prop2.get", "Do not use Prop2.Get").WithLocation(18, 13), + // (19,9): error CS0619: 'TestClass.Prop3.set' is obsolete: 'Do not use Prop3.Get' + // c.Prop3 = 42; + Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "c.Prop3").WithArguments("TestClass.Prop3.set", "Do not use Prop3.Get").WithLocation(19, 9)); } [Fact] @@ -6103,20 +6117,82 @@ class D6 : D5 [Obsolete] public override void goo() {} } + +class E1 +{ + public virtual int Goo {get; set;} +} +class E2 : E1 +{ + public override int Goo { [Obsolete] get; set;} +} +class E3 : E1 +{ + public new int Goo { [Obsolete] get; set;} +} +class E4 : E1 +{ + public override int Goo {get; set;} +} +class E5 : E4 +{ + public override int Goo { [Obsolete] get; set;} +} +class E6 : E5 +{ + public override int Goo {get; set;} +} + +class F1 +{ + public virtual int Goo { [Obsolete] get; set;} +} +class F2 : F1 +{ + public override int Goo {get; set;} +} +class F3 : F1 +{ + public new int Goo {get; set;} +} +class F4 : F1 +{ + public override int Goo { [Obsolete] get; set;} +} +class F5 : F4 +{ + public override int Goo {get; set;} +} +class F6 : F5 +{ + public override int Goo { [Obsolete] get; set;} +} "; CreateCompilation(source).VerifyDiagnostics( // (10,26): warning CS0809: Obsolete member 'C2.goo()' overrides non-obsolete member 'C1.goo()' // public override void goo() {} - Diagnostic(ErrorCode.WRN_ObsoleteOverridingNonObsolete, "goo").WithArguments("C2.goo()", "C1.goo()"), - // (24,26): warning CS0809: Obsolete member 'C5.goo()' overrides non-obsolete member 'C1.goo()' + Diagnostic(ErrorCode.WRN_ObsoleteOverridingNonObsolete, "goo").WithArguments("C2.goo()", "C1.goo()").WithLocation(10, 26), + // (90,30): warning CS0672: Member 'F2.Goo.get' overrides obsolete member 'F1.Goo.get'. Add the Obsolete attribute to 'F2.Goo.get'. + // public override int Goo {get; set;} + Diagnostic(ErrorCode.WRN_NonObsoleteOverridingObsolete, "get").WithArguments("F2.Goo.get", "F1.Goo.get").WithLocation(90, 30), + // (77,42): warning CS0809: Obsolete member 'E5.Goo.get' overrides non-obsolete member 'E1.Goo.get' + // public override int Goo { [Obsolete] get; set;} + Diagnostic(ErrorCode.WRN_ObsoleteOverridingNonObsolete, "get").WithArguments("E5.Goo.get", "E1.Goo.get").WithLocation(77, 42), + // (51,26): warning CS0672: Member 'D5.goo()' overrides obsolete member 'D1.goo()'. Add the Obsolete attribute to 'D5.goo()'. // public override void goo() {} - Diagnostic(ErrorCode.WRN_ObsoleteOverridingNonObsolete, "goo").WithArguments("C5.goo()", "C1.goo()"), + Diagnostic(ErrorCode.WRN_NonObsoleteOverridingObsolete, "goo").WithArguments("D5.goo()", "D1.goo()").WithLocation(51, 26), // (38,26): warning CS0672: Member 'D2.goo()' overrides obsolete member 'D1.goo()'. Add the Obsolete attribute to 'D2.goo()'. // public override void goo() {} - Diagnostic(ErrorCode.WRN_NonObsoleteOverridingObsolete, "goo").WithArguments("D2.goo()", "D1.goo()"), - // (51,26): warning CS0672: Member 'D5.goo()' overrides obsolete member 'D1.goo()'. Add the Obsolete attribute to 'D5.goo()'. + Diagnostic(ErrorCode.WRN_NonObsoleteOverridingObsolete, "goo").WithArguments("D2.goo()", "D1.goo()").WithLocation(38, 26), + // (24,26): warning CS0809: Obsolete member 'C5.goo()' overrides non-obsolete member 'C1.goo()' // public override void goo() {} - Diagnostic(ErrorCode.WRN_NonObsoleteOverridingObsolete, "goo").WithArguments("D5.goo()", "D1.goo()")); + Diagnostic(ErrorCode.WRN_ObsoleteOverridingNonObsolete, "goo").WithArguments("C5.goo()", "C1.goo()").WithLocation(24, 26), + // (102,30): warning CS0672: Member 'F5.Goo.get' overrides obsolete member 'F1.Goo.get'. Add the Obsolete attribute to 'F5.Goo.get'. + // public override int Goo {get; set;} + Diagnostic(ErrorCode.WRN_NonObsoleteOverridingObsolete, "get").WithArguments("F5.Goo.get", "F1.Goo.get").WithLocation(102, 30), + // (65,42): warning CS0809: Obsolete member 'E2.Goo.get' overrides non-obsolete member 'E1.Goo.get' + // public override int Goo { [Obsolete] get; set;} + Diagnostic(ErrorCode.WRN_ObsoleteOverridingNonObsolete, "get").WithArguments("E2.Goo.get", "E1.Goo.get").WithLocation(65, 42)); } [Fact] @@ -6311,7 +6387,9 @@ public class Test event Action someEvent; [Obsolete] - public static SomeType someProp { get; set; } + public static SomeType someProp { get => new SomeType(); set {} } + + public static string someProp2 { [Obsolete] get => new SomeType().ToString(); } [Obsolete] SomeType this[int x] { get { SomeType y = new SomeType(); return y; } } @@ -6464,6 +6542,11 @@ public int Prop get { return 1; } set { } } + [Obsolete(""Property"", true)] + public int Prop2 + { + get ; [Obsolete] set; + } [Obsolete(""Field"", true)] public int Field; } @@ -6471,6 +6554,7 @@ public int Prop [Att] [Att(Field = 1)] [Att(Prop = 1)] +[Att(Prop2 = 1)] public class Test { [Att()] @@ -6478,24 +6562,30 @@ public static void Main() { } } "; CreateCompilation(source).VerifyDiagnostics( - // (20,6): error CS0619: 'Att.Field' is obsolete: 'Field' + // (24,2): error CS0619: 'Att.Att()' is obsolete: 'Constructor' + // [Att] + Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Att").WithArguments("Att.Att()", "Constructor").WithLocation(24, 2), + // (25,6): error CS0619: 'Att.Field' is obsolete: 'Field' // [Att(Field = 1)] - Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Field = 1").WithArguments("Att.Field", "Field"), - // (20,2): error CS0619: 'Att.Att()' is obsolete: 'Constructor' + Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Field = 1").WithArguments("Att.Field", "Field").WithLocation(25, 6), + // (25,2): error CS0619: 'Att.Att()' is obsolete: 'Constructor' // [Att(Field = 1)] - Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Att(Field = 1)").WithArguments("Att.Att()", "Constructor"), - // (21,6): error CS0619: 'Att.Prop' is obsolete: 'Property' + Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Att(Field = 1)").WithArguments("Att.Att()", "Constructor").WithLocation(25, 2), + // (26,6): error CS0619: 'Att.Prop' is obsolete: 'Property' // [Att(Prop = 1)] - Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Prop = 1").WithArguments("Att.Prop", "Property"), - // (21,2): error CS0619: 'Att.Att()' is obsolete: 'Constructor' + Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Prop = 1").WithArguments("Att.Prop", "Property").WithLocation(26, 6), + // (26,2): error CS0619: 'Att.Att()' is obsolete: 'Constructor' // [Att(Prop = 1)] - Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Att(Prop = 1)").WithArguments("Att.Att()", "Constructor"), - // (24,6): error CS0619: 'Att.Att()' is obsolete: 'Constructor' + Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Att(Prop = 1)").WithArguments("Att.Att()", "Constructor").WithLocation(26, 2), + // (27,6): error CS0619: 'Att.Prop2' is obsolete: 'Property' + // [Att(Prop2 = 1)] + Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Prop2 = 1").WithArguments("Att.Prop2", "Property").WithLocation(27, 6), + // (27,2): error CS0619: 'Att.Att()' is obsolete: 'Constructor' + // [Att(Prop2 = 1)] + Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Att(Prop2 = 1)").WithArguments("Att.Att()", "Constructor").WithLocation(27, 2), + // (30,6): error CS0619: 'Att.Att()' is obsolete: 'Constructor' // [Att()] - Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Att()").WithArguments("Att.Att()", "Constructor"), - // (19,2): error CS0619: 'Att.Att()' is obsolete: 'Constructor' - // [Att] - Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Att").WithArguments("Att.Att()", "Constructor")); + Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Att()").WithArguments("Att.Att()", "Constructor").WithLocation(30, 6)); } [Fact] @@ -8987,5 +9077,39 @@ void M(in int x) // error CS0616: 'IsReadOnlyAttribute' is not an attribute class Diagnostic(ErrorCode.ERR_NotAnAttributeClass).WithArguments("System.Runtime.CompilerServices.IsReadOnlyAttribute").WithLocation(1, 1)); } + + [Fact] + public void TestObsoleteOnPropertyAccessorUsedInNameofAndXmlDocComment() + { + var code = @" +using System; +/// +/// +/// +class C +{ + const string str = nameof(Prop); + + public int Prop { [Obsolete] get; [Obsolete] set; } +} +"; + + CreateCompilation(code).VerifyDiagnostics().VerifyEmitDiagnostics(); + } + + [Fact] + public void TestObsoleteOnPropertyAndAccessors() + { + var code = @" +using System; +class C +{ + [Obsolete] + public int Prop { [Obsolete] get; [Obsolete] set; } +} +"; + + CreateCompilation(code).VerifyDiagnostics().VerifyEmitDiagnostics(); + } } } From 3eb45f4a3d1043079a741c4bc4edebb5e1700f8f Mon Sep 17 00:00:00 2001 From: yair halberstadt Date: Fri, 18 Jan 2019 10:00:06 +0000 Subject: [PATCH 03/18] Fix tests broken as a result of previous change --- .../Attributes/AttributeTests_WellKnownAttributes.cs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs b/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs index 94c6c0dca45dd..efd578bc6d77f 100644 --- a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs +++ b/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs @@ -6883,10 +6883,7 @@ class D Diagnostic(ErrorCode.ERR_AttributeNotOnAccessor, "Deprecated").WithArguments("Windows.Foundation.Metadata.DeprecatedAttribute", "assembly, module, class, struct, enum, constructor, method, property, indexer, field, event, interface, parameter, delegate, return, type parameter").WithLocation(9, 17), // (7,33): warning CS0612: 'A' is obsolete // object P { get { return new A(); } } - Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "A").WithArguments("A").WithLocation(7, 33), - // (9,82): warning CS0612: 'C' is obsolete - // object R { [Deprecated(null, DeprecationType.Deprecate, 0)] get { return new C(); } } - Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "C").WithArguments("C").WithLocation(9, 82)); + Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "A").WithArguments("A").WithLocation(7, 33)); } [Fact] @@ -6937,13 +6934,10 @@ static void M(object o) { } comp.VerifyDiagnostics( // (21,10): error CS1667: Attribute 'Windows.Foundation.Metadata.DeprecatedAttribute' is not valid on property or event accessors. It is only valid on 'assembly, module, class, struct, enum, constructor, method, property, indexer, field, event, interface, parameter, delegate, return, type parameter' declarations. // [Deprecated(null, DeprecationType.Deprecate, 0)] remove { M(new C()); } - Diagnostic(ErrorCode.ERR_AttributeNotOnAccessor, "Deprecated").WithArguments("Windows.Foundation.Metadata.DeprecatedAttribute", "assembly, module, class, struct, enum, constructor, method, property, indexer, field, event, interface, parameter, delegate, return, type parameter"), + Diagnostic(ErrorCode.ERR_AttributeNotOnAccessor, "Deprecated").WithArguments("Windows.Foundation.Metadata.DeprecatedAttribute", "assembly, module, class, struct, enum, constructor, method, property, indexer, field, event, interface, parameter, delegate, return, type parameter").WithLocation(21, 10), // (11,24): warning CS0612: 'A' is obsolete // remove { M(new A()); } - Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "A").WithArguments("A"), - // (21,73): warning CS0612: 'C' is obsolete - // [Deprecated(null, DeprecationType.Deprecate, 0)] remove { M(new C()); } - Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "C").WithArguments("C").WithLocation(21, 73)); + Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "A").WithArguments("A").WithLocation(11, 24)); } [Fact] From dc79ea56489e0a14940404ddbb78fcf5957cb0a2 Mon Sep 17 00:00:00 2001 From: yair halberstadt Date: Fri, 18 Jan 2019 11:07:35 +0000 Subject: [PATCH 04/18] Fix unit test CS1667ERR_AttributeNotOnAccessor --- src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs b/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs index 8a5c65247b878..c25d31c005bdc 100644 --- a/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs +++ b/src/Compilers/CSharp/Test/Symbol/Symbols/SymbolErrorTests.cs @@ -15032,9 +15032,6 @@ public static void Main() } "; var comp = CreateCompilation(text).VerifyDiagnostics( - // (8,10): error CS1667: Attribute 'Obsolete' is not valid on property or event accessors. It is only valid on 'class, struct, enum, constructor, method, property, indexer, field, event, interface, delegate' declarations. - // [Obsolete] // CS1667 - Diagnostic(ErrorCode.ERR_AttributeNotOnAccessor, "Obsolete").WithArguments("System.ObsoleteAttribute", "class, struct, enum, constructor, method, property, indexer, field, event, interface, delegate"), // (10,10): error CS1667: Attribute 'System.Diagnostics.Conditional' is not valid on property or event accessors. It is only valid on 'class, method' declarations. // [System.Diagnostics.Conditional("Bernard")] Diagnostic(ErrorCode.ERR_AttributeNotOnAccessor, "System.Diagnostics.Conditional").WithArguments("System.Diagnostics.Conditional", "class, method") From 376c8d56bcadb6432decf06d628bd242bf6746c3 Mon Sep 17 00:00:00 2001 From: yair halberstadt Date: Mon, 21 Jan 2019 08:34:07 +0000 Subject: [PATCH 05/18] Add unit test to confirm that an obsolete accessor does not suppress warnings from an obsolete return type --- .../Emit/Attributes/AttributeTests_WellKnownAttributes.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs b/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs index efd578bc6d77f..c6c3638d80a47 100644 --- a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs +++ b/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs @@ -6391,6 +6391,8 @@ public class Test public static string someProp2 { [Obsolete] get => new SomeType().ToString(); } + public static SomeType someProp3 { [Obsolete] get => new SomeType(); } + [Obsolete] SomeType this[int x] { get { SomeType y = new SomeType(); return y; } } @@ -6413,9 +6415,12 @@ public class Base {} public class Derived : Base> {} "; CreateCompilation(source).VerifyDiagnostics( + // (27,19): warning CS0612: 'SomeType' is obsolete + // public static SomeType someProp3 { [Obsolete] get => new SomeType(); } + Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "SomeType").WithArguments("SomeType").WithLocation(27, 19), // (20,28): warning CS0067: The event 'Test.someEvent' is never used // event Action someEvent; - Diagnostic(ErrorCode.WRN_UnreferencedEvent, "someEvent").WithArguments("Test.someEvent")); + Diagnostic(ErrorCode.WRN_UnreferencedEvent, "someEvent").WithArguments("Test.someEvent").WithLocation(20, 28) } [Fact] From 272e44a3733b92bd6a75fb708f73d86a4ab3fe6c Mon Sep 17 00:00:00 2001 From: Yair Halberstadt Date: Mon, 21 Jan 2019 09:11:55 +0000 Subject: [PATCH 06/18] Fixed Missing ');' in AttributeTests_WellKnownAttributes --- .../Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs b/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs index c6c3638d80a47..76da82db56dc2 100644 --- a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs +++ b/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs @@ -6420,7 +6420,7 @@ public class Derived : Base> {} Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "SomeType").WithArguments("SomeType").WithLocation(27, 19), // (20,28): warning CS0067: The event 'Test.someEvent' is never used // event Action someEvent; - Diagnostic(ErrorCode.WRN_UnreferencedEvent, "someEvent").WithArguments("Test.someEvent").WithLocation(20, 28) + Diagnostic(ErrorCode.WRN_UnreferencedEvent, "someEvent").WithArguments("Test.someEvent").WithLocation(20, 28)); } [Fact] From 26d8a677f9631da83b157874d06bc701a0ffd7a9 Mon Sep 17 00:00:00 2001 From: Yair Halberstadt Date: Sat, 26 Jan 2019 23:09:14 +0000 Subject: [PATCH 07/18] Update AttributeTests_WellKnownAttributes.cs --- .../Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs b/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs index 76da82db56dc2..747ef20adf18f 100644 --- a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs +++ b/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs @@ -5678,7 +5678,7 @@ class SelfReferenceInBase1 : IGoo {} } [Fact] - public void TestObsleteOnPropertyAccessorsoleteAttributeOnMembers() + public void TestObsoleteAttributeOnMembersAndAccessors() { var source = @" using System; From da56be51c3e2b39a720eb1e9535c619dc7e90c61 Mon Sep 17 00:00:00 2001 From: yair halberstadt Date: Thu, 14 Mar 2019 08:35:17 +0000 Subject: [PATCH 08/18] Allow Deprecated Attribute on property accessors. Forbid Obsolete/Deprecated on event accessors. Give suitable error messages for Obsolete/Deprected on event accessors, and on property accessors pre-C# 8 Add further tests --- .../Portable/CSharpResources.Designer.cs | 18 +++++ .../CSharp/Portable/CSharpResources.resx | 8 +- .../CSharp/Portable/Errors/ErrorCode.cs | 2 +- .../CSharp/Portable/Errors/MessageID.cs | 2 + .../Source/SourceMemberMethodSymbol.cs | 14 +++- .../Portable/xlf/CSharpResources.cs.xlf | 10 +++ .../Portable/xlf/CSharpResources.de.xlf | 10 +++ .../Portable/xlf/CSharpResources.es.xlf | 10 +++ .../Portable/xlf/CSharpResources.fr.xlf | 10 +++ .../Portable/xlf/CSharpResources.it.xlf | 10 +++ .../Portable/xlf/CSharpResources.ja.xlf | 10 +++ .../Portable/xlf/CSharpResources.ko.xlf | 10 +++ .../Portable/xlf/CSharpResources.pl.xlf | 10 +++ .../Portable/xlf/CSharpResources.pt-BR.xlf | 10 +++ .../Portable/xlf/CSharpResources.ru.xlf | 10 +++ .../Portable/xlf/CSharpResources.tr.xlf | 10 +++ .../Portable/xlf/CSharpResources.zh-Hans.xlf | 10 +++ .../Portable/xlf/CSharpResources.zh-Hant.xlf | 10 +++ .../AttributeTests_WellKnownAttributes.cs | 74 +++++++++++++++---- 19 files changed, 227 insertions(+), 21 deletions(-) diff --git a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs index dee1627254694..0a823f8b1db1a 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs +++ b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs @@ -762,6 +762,15 @@ internal static string ERR_AttributeNotOnAccessor { } } + /// + /// Looks up a localized string similar to Attribute '{0}' is not valid on event accessors. It is only valid on '{1}' declarations.. + /// + internal static string ERR_AttributeNotOnEventAccessor { + get { + return ResourceManager.GetString("ERR_AttributeNotOnEventAccessor", resourceCulture); + } + } + /// /// Looks up a localized string similar to Attribute '{0}' is not valid on this declaration type. It is only valid on '{1}' declarations.. /// @@ -11320,6 +11329,15 @@ internal static string IDS_FeatureObjectInitializer { } } + /// + /// Looks up a localized string similar to obsolete property accessors. + /// + internal static string IDS_FeatureObsoleteOnPropertyAccessor { + get { + return ResourceManager.GetString("IDS_FeatureObsoleteOnPropertyAccessor", resourceCulture); + } + } + /// /// Looks up a localized string similar to optional parameter. /// diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 0962f512fb8f8..adc13aed6d75e 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -5796,4 +5796,10 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ The feature '{0}' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. - + + Attribute '{0}' is not valid on event accessors. It is only valid on '{1}' declarations. + + + obsolete property accessors + + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs index 14282f970663d..f0f1d7a5786f7 100644 --- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs +++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs @@ -1598,7 +1598,7 @@ internal enum ErrorCode ERR_PossibleAsyncIteratorWithoutYieldOrAwait = 8420, ERR_StaticLocalFunctionCannotCaptureVariable = 8421, ERR_StaticLocalFunctionCannotCaptureThis = 8422, - + ERR_AttributeNotOnEventAccessor = 8423, #region diagnostics introduced for recursive patterns // 8501, // available ERR_WrongNumberOfSubpatterns = 8502, diff --git a/src/Compilers/CSharp/Portable/Errors/MessageID.cs b/src/Compilers/CSharp/Portable/Errors/MessageID.cs index 269bfe8b6da23..9a5eea603559c 100644 --- a/src/Compilers/CSharp/Portable/Errors/MessageID.cs +++ b/src/Compilers/CSharp/Portable/Errors/MessageID.cs @@ -175,6 +175,7 @@ internal enum MessageID IDS_FeatureStaticLocalFunctions = MessageBase + 12755, IDS_FeatureNameShadowingInNestedFunctions = MessageBase + 12756, IDS_FeatureUnmanagedConstructedTypes = MessageBase + 12757, + IDS_FeatureObsoleteOnPropertyAccessor = MessageBase + 12758, } // Message IDs may refer to strings that need to be localized. @@ -279,6 +280,7 @@ internal static LanguageVersion RequiredVersion(this MessageID feature) case MessageID.IDS_FeatureStaticLocalFunctions: case MessageID.IDS_FeatureNameShadowingInNestedFunctions: case MessageID.IDS_FeatureUnmanagedConstructedTypes: // semantic check + case MessageID.IDS_FeatureObsoleteOnPropertyAccessor: return LanguageVersion.CSharp8; // C# 7.3 features. diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs index 33328bd4b8f08..bbd4f588f01ba 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs @@ -1164,6 +1164,9 @@ private void DecodeWellKnownAttributeAppliedToMethod(ref DecodeWellKnownAttribut { arguments.GetOrCreateData().HasDynamicSecurityMethodAttribute = true; } + else if (VerifyObsoleteAttributeAppliedToMethod(ref arguments, AttributeDescription.ObsoleteAttribute)) + { + } else if (VerifyObsoleteAttributeAppliedToMethod(ref arguments, AttributeDescription.DeprecatedAttribute)) { } @@ -1213,9 +1216,14 @@ private bool VerifyObsoleteAttributeAppliedToMethod( { if (this.IsAccessor()) { - // CS1667: Attribute '{0}' is not valid on property or event accessors. It is only valid on '{1}' declarations. - AttributeUsageInfo attributeUsage = arguments.Attribute.AttributeClass.GetAttributeUsageInfo(); - arguments.Diagnostics.Add(ErrorCode.ERR_AttributeNotOnAccessor, arguments.AttributeSyntaxOpt.Name.Location, description.FullName, attributeUsage.GetValidTargetsErrorArgument()); + if (this is SourceEventAccessorSymbol) + { + // CS1667: Attribute '{0}' is not valid on property or event accessors. It is only valid on '{1}' declarations. + AttributeUsageInfo attributeUsage = arguments.Attribute.AttributeClass.GetAttributeUsageInfo(); + arguments.Diagnostics.Add(ErrorCode.ERR_AttributeNotOnEventAccessor, arguments.AttributeSyntaxOpt.Name.Location, description.FullName, attributeUsage.GetValidTargetsErrorArgument()); + } + + MessageID.IDS_FeatureObsoleteOnPropertyAccessor.CheckFeatureAvailability(arguments.Diagnostics, arguments.AttributeSyntaxOpt.Location); } return true; diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index d035c2a60c12f..8d872e8429c72 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -32,6 +32,11 @@ It is not legal to use nullable reference type '{0}?' in an as expression; use the underlying type '{0}' instead. + + Attribute '{0}' is not valid on event accessors. It is only valid on '{1}' declarations. + Attribute '{0}' is not valid on event accessors. It is only valid on '{1}' declarations. + + Asynchronous foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a suitable public instance definition for '{1}' Asynchronní příkaz foreach nejde použít pro proměnné typu {0}, protože {0} neobsahuje vhodnou veřejnou definici instance pro {1}. @@ -712,6 +717,11 @@ omezení obecného typu objektu + + obsolete property accessors + obsolete property accessors + + warning action enable or safeonly warning action enable or safeonly diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index b024643a85974..59075638a82d1 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -32,6 +32,11 @@ It is not legal to use nullable reference type '{0}?' in an as expression; use the underlying type '{0}' instead. + + Attribute '{0}' is not valid on event accessors. It is only valid on '{1}' declarations. + Attribute '{0}' is not valid on event accessors. It is only valid on '{1}' declarations. + + Asynchronous foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a suitable public instance definition for '{1}' Eine asynchrone foreach-Anweisung kann nicht für Variablen vom Typ "{0}" verwendet werden, weil "{0}" keine geeignete öffentliche Instanzdefinition für "{1}" enthält. @@ -712,6 +717,11 @@ Einschränkung eines generischen Objekttyps + + obsolete property accessors + obsolete property accessors + + warning action enable or safeonly warning action enable or safeonly diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index 7f8d786d27558..e1b4e300da407 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -32,6 +32,11 @@ It is not legal to use nullable reference type '{0}?' in an as expression; use the underlying type '{0}' instead. + + Attribute '{0}' is not valid on event accessors. It is only valid on '{1}' declarations. + Attribute '{0}' is not valid on event accessors. It is only valid on '{1}' declarations. + + Asynchronous foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a suitable public instance definition for '{1}' Una instrucción foreach asincrónica no puede funcionar en variables de tipo "{0}", porque "{0}" no contiene una definición de instancia pública adecuada para "{1}". @@ -712,6 +717,11 @@ restricción de tipo genérico de objeto + + obsolete property accessors + obsolete property accessors + + warning action enable or safeonly warning action enable or safeonly diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index f52acbe8febb6..62669dc5ef459 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -32,6 +32,11 @@ It is not legal to use nullable reference type '{0}?' in an as expression; use the underlying type '{0}' instead. + + Attribute '{0}' is not valid on event accessors. It is only valid on '{1}' declarations. + Attribute '{0}' is not valid on event accessors. It is only valid on '{1}' declarations. + + Asynchronous foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a suitable public instance definition for '{1}' L'instruction foreach asynchrone ne peut pas fonctionner sur des variables de type '{0}', car '{0}' ne contient aucune définition d'instance publique appropriée pour '{1}' @@ -712,6 +717,11 @@ contrainte de type générique d'objet + + obsolete property accessors + obsolete property accessors + + warning action enable or safeonly warning action enable or safeonly diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index efc25958fba07..f70563d0bf203 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -32,6 +32,11 @@ It is not legal to use nullable reference type '{0}?' in an as expression; use the underlying type '{0}' instead. + + Attribute '{0}' is not valid on event accessors. It is only valid on '{1}' declarations. + Attribute '{0}' is not valid on event accessors. It is only valid on '{1}' declarations. + + Asynchronous foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a suitable public instance definition for '{1}' L'istruzione foreach asincrona non può funzionare con variabili di tipo '{0}' perché '{0}' non contiene una definizione di istanza pubblica idonea per '{1}' @@ -712,6 +717,11 @@ vincolo di tipo generico object + + obsolete property accessors + obsolete property accessors + + warning action enable or safeonly warning action enable or safeonly diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index 59924fec2844a..556236fb5e2dc 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -32,6 +32,11 @@ It is not legal to use nullable reference type '{0}?' in an as expression; use the underlying type '{0}' instead. + + Attribute '{0}' is not valid on event accessors. It is only valid on '{1}' declarations. + Attribute '{0}' is not valid on event accessors. It is only valid on '{1}' declarations. + + Asynchronous foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a suitable public instance definition for '{1}' '{0}' は '{1}' の適切なパブリック インスタンス定義を含んでいないため、型 '{0}' の変数に対して非同期 foreach ステートメントを使用することはできません @@ -712,6 +717,11 @@ オブジェクト ジェネリック型の制約 + + obsolete property accessors + obsolete property accessors + + warning action enable or safeonly warning action enable or safeonly diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index 47add2834752b..cc03a9565e1ef 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -32,6 +32,11 @@ It is not legal to use nullable reference type '{0}?' in an as expression; use the underlying type '{0}' instead. + + Attribute '{0}' is not valid on event accessors. It is only valid on '{1}' declarations. + Attribute '{0}' is not valid on event accessors. It is only valid on '{1}' declarations. + + Asynchronous foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a suitable public instance definition for '{1}' '{0}' 형식 변수에서 비동기 foreach 문을 수행할 수 없습니다. '{0}'에는 '{1}'의 적합한 공용 인스턴스 정의가 없기 때문입니다. @@ -712,6 +717,11 @@ 개체 제네릭 형식 제약 조건 + + obsolete property accessors + obsolete property accessors + + warning action enable or safeonly warning action enable or safeonly diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index 5b1f97be39ee5..8900322feb473 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -32,6 +32,11 @@ It is not legal to use nullable reference type '{0}?' in an as expression; use the underlying type '{0}' instead. + + Attribute '{0}' is not valid on event accessors. It is only valid on '{1}' declarations. + Attribute '{0}' is not valid on event accessors. It is only valid on '{1}' declarations. + + Asynchronous foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a suitable public instance definition for '{1}' Asynchroniczna instrukcja foreach nie może operować na zmiennych typu „{0}”, ponieważ typ „{0}” nie zawiera odpowiedniej publicznej definicji wystąpienia elementu „{1}” @@ -712,6 +717,11 @@ ogólne ograniczenie typu obiektu + + obsolete property accessors + obsolete property accessors + + warning action enable or safeonly warning action enable or safeonly diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index 55431bd06f73f..e7a004d5a966e 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -32,6 +32,11 @@ It is not legal to use nullable reference type '{0}?' in an as expression; use the underlying type '{0}' instead. + + Attribute '{0}' is not valid on event accessors. It is only valid on '{1}' declarations. + Attribute '{0}' is not valid on event accessors. It is only valid on '{1}' declarations. + + Asynchronous foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a suitable public instance definition for '{1}' A instrução foreach assíncrona não pode operar em variáveis do tipo '{0}' porque '{0}' não contém uma definição da instância pública adequada para '{1}' @@ -712,6 +717,11 @@ restrição de tipo genérico de objeto + + obsolete property accessors + obsolete property accessors + + warning action enable or safeonly warning action enable or safeonly diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index 770f61513af18..7928a61a51761 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -32,6 +32,11 @@ It is not legal to use nullable reference type '{0}?' in an as expression; use the underlying type '{0}' instead. + + Attribute '{0}' is not valid on event accessors. It is only valid on '{1}' declarations. + Attribute '{0}' is not valid on event accessors. It is only valid on '{1}' declarations. + + Asynchronous foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a suitable public instance definition for '{1}' Асинхронный оператор foreach не работает с переменными типа "{0}", так как "{0}" не содержит подходящее открытое определение экземпляра для "{1}". @@ -712,6 +717,11 @@ ограничение универсального типа для объекта + + obsolete property accessors + obsolete property accessors + + warning action enable or safeonly warning action enable or safeonly diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index 9fcfc34450def..79e4d7c2a4520 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -32,6 +32,11 @@ It is not legal to use nullable reference type '{0}?' in an as expression; use the underlying type '{0}' instead. + + Attribute '{0}' is not valid on event accessors. It is only valid on '{1}' declarations. + Attribute '{0}' is not valid on event accessors. It is only valid on '{1}' declarations. + + Asynchronous foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a suitable public instance definition for '{1}' '{0}', '{1}' için uygun bir genel örnek tanımı içermediğinden zaman uyumsuz foreach deyimi '{0}' türündeki değişkenlerle çalışmaz @@ -712,6 +717,11 @@ nesne genel tür kısıtlamaları + + obsolete property accessors + obsolete property accessors + + warning action enable or safeonly warning action enable or safeonly diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index 864e54c917bdc..b772748c4cfba 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -32,6 +32,11 @@ It is not legal to use nullable reference type '{0}?' in an as expression; use the underlying type '{0}' instead. + + Attribute '{0}' is not valid on event accessors. It is only valid on '{1}' declarations. + Attribute '{0}' is not valid on event accessors. It is only valid on '{1}' declarations. + + Asynchronous foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a suitable public instance definition for '{1}' “{0}”不包含“{1}”的适当公共实例定义,因此异步 foreach 语句不能作用于“{0}”类型的变量 @@ -417,6 +422,11 @@ 对象泛型类型约束 + + obsolete property accessors + obsolete property accessors + + warning action enable or safeonly warning action enable or safeonly diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index 1eee9b9fbd4aa..08cb56139c227 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -32,6 +32,11 @@ It is not legal to use nullable reference type '{0}?' in an as expression; use the underlying type '{0}' instead. + + Attribute '{0}' is not valid on event accessors. It is only valid on '{1}' declarations. + Attribute '{0}' is not valid on event accessors. It is only valid on '{1}' declarations. + + Asynchronous foreach statement cannot operate on variables of type '{0}' because '{0}' does not contain a suitable public instance definition for '{1}' 因為 '{0}' 不包含適用於 '{1}' 的公用執行個體定義,所以非同步的 foreach 陳述式無法在類型為 '{0}' 的變數上運作 @@ -712,6 +717,11 @@ 物件泛型型別條件約束 + + obsolete property accessors + obsolete property accessors + + warning action enable or safeonly warning action enable or safeonly diff --git a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs b/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs index 747ef20adf18f..b9a89eae8f4ea 100644 --- a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs +++ b/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs @@ -5810,6 +5810,12 @@ public static void ObsoleteExtensionMethod1(this Test t) { } } "; CreateCompilationWithMscorlib40(source, new[] { ExtensionAssemblyRef }).VerifyDiagnostics( + // (98,10): error CS8423: Attribute 'System.ObsoleteAttribute' is not valid on event accessors. It is only valid on 'class, struct, enum, constructor, method, property, indexer, field, event, interface, delegate' declarations. + // [Obsolete] add {} + Diagnostic(ErrorCode.ERR_AttributeNotOnEventAccessor, "Obsolete").WithArguments("System.ObsoleteAttribute", "class, struct, enum, constructor, method, property, indexer, field, event, interface, delegate").WithLocation(98, 10), + // (99,10): error CS8423: Attribute 'System.ObsoleteAttribute' is not valid on event accessors. It is only valid on 'class, struct, enum, constructor, method, property, indexer, field, event, interface, delegate' declarations. + // [Obsolete("Don't use remove accessor")] remove {} + Diagnostic(ErrorCode.ERR_AttributeNotOnEventAccessor, "Obsolete").WithArguments("System.ObsoleteAttribute", "class, struct, enum, constructor, method, property, indexer, field, event, interface, delegate").WithLocation(99, 10), // (8,9): warning CS0612: 'Test.ObsoleteMethod1()' is obsolete // ObsoleteMethod1(); Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "ObsoleteMethod1()").WithArguments("Test.ObsoleteMethod1()").WithLocation(8, 9), @@ -6883,9 +6889,6 @@ class D }"; var comp = CreateCompilation(new[] { Parse(source0), Parse(source1) }); comp.VerifyDiagnostics( - // (9,17): error CS1667: Attribute 'Windows.Foundation.Metadata.DeprecatedAttribute' is not valid on property or event accessors. It is only valid on 'assembly, module, class, struct, enum, constructor, method, property, indexer, field, event, interface, parameter, delegate, return, type parameter' declarations. - // object R { [Deprecated(null, DeprecationType.Deprecate, 0)] get { return new C(); } } - Diagnostic(ErrorCode.ERR_AttributeNotOnAccessor, "Deprecated").WithArguments("Windows.Foundation.Metadata.DeprecatedAttribute", "assembly, module, class, struct, enum, constructor, method, property, indexer, field, event, interface, parameter, delegate, return, type parameter").WithLocation(9, 17), // (7,33): warning CS0612: 'A' is obsolete // object P { get { return new A(); } } Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "A").WithArguments("A").WithLocation(7, 33)); @@ -6937,12 +6940,12 @@ static void M(object o) { } }"; var comp = CreateCompilation(new[] { Parse(source0), Parse(source1) }); comp.VerifyDiagnostics( - // (21,10): error CS1667: Attribute 'Windows.Foundation.Metadata.DeprecatedAttribute' is not valid on property or event accessors. It is only valid on 'assembly, module, class, struct, enum, constructor, method, property, indexer, field, event, interface, parameter, delegate, return, type parameter' declarations. - // [Deprecated(null, DeprecationType.Deprecate, 0)] remove { M(new C()); } - Diagnostic(ErrorCode.ERR_AttributeNotOnAccessor, "Deprecated").WithArguments("Windows.Foundation.Metadata.DeprecatedAttribute", "assembly, module, class, struct, enum, constructor, method, property, indexer, field, event, interface, parameter, delegate, return, type parameter").WithLocation(21, 10), // (11,24): warning CS0612: 'A' is obsolete // remove { M(new A()); } - Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "A").WithArguments("A").WithLocation(11, 24)); + Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "A").WithArguments("A").WithLocation(11, 24), + // (21,10): error CS8423: Attribute 'Windows.Foundation.Metadata.DeprecatedAttribute' is not valid on event accessors. It is only valid on 'assembly, module, class, struct, enum, constructor, method, property, indexer, field, event, interface, parameter, delegate, return, type parameter' declarations. + // [Deprecated(null, DeprecationType.Deprecate, 0)] remove { M(new C()); } + Diagnostic(ErrorCode.ERR_AttributeNotOnEventAccessor, "Deprecated").WithArguments("Windows.Foundation.Metadata.DeprecatedAttribute", "assembly, module, class, struct, enum, constructor, method, property, indexer, field, event, interface, parameter, delegate, return, type parameter").WithLocation(21, 10)); } [Fact] @@ -8079,27 +8082,33 @@ void Test() Class2 x2 = null; Class3 x3 = null; Class4 x4 = null; + Class6 x6 = new Class6(); object x5; x5=x1; x5 = x2; x5 = x3; x5 = x4; + x5 = x6.P1; + x6.P1 = 1; + x6.E1 += null; + x6.E1 -= null; } } class Class6 { - int P1 + public int P1 { [Deprecated(""P1.get is deprecated."", DeprecationType.Remove, 1)] get { return 1; } + set {} } - event System.Action E1 + public event System.Action E1 { [Deprecated(""E1.add is deprecated."", DeprecationType.Remove, 1)] add @@ -8114,12 +8123,6 @@ event System.Action E1 var compilation2 = CreateEmptyCompilation(source2, WinRtRefs.Concat(new[] { new CSharpCompilationReference(compilation1) }), TestOptions.ReleaseDll); var expected = new[] { - // (25,10): error CS1667: Attribute 'Windows.Foundation.Metadata.DeprecatedAttribute' is not valid on property or event accessors. It is only valid on 'class, struct, enum, constructor, method, property, indexer, field, event, interface, delegate' declarations. - // [Deprecated("P1.get is deprecated.", DeprecationType.Remove, 1)] - Diagnostic(ErrorCode.ERR_AttributeNotOnAccessor, "Deprecated").WithArguments("Windows.Foundation.Metadata.DeprecatedAttribute", "class, struct, enum, constructor, method, property, indexer, field, event, interface, delegate").WithLocation(25, 10), - // (34,10): error CS1667: Attribute 'Windows.Foundation.Metadata.DeprecatedAttribute' is not valid on property or event accessors. It is only valid on 'class, struct, enum, constructor, method, property, indexer, field, event, interface, delegate' declarations. - // [Deprecated("E1.add is deprecated.", DeprecationType.Remove, 1)] - Diagnostic(ErrorCode.ERR_AttributeNotOnAccessor, "Deprecated").WithArguments("Windows.Foundation.Metadata.DeprecatedAttribute", "class, struct, enum, constructor, method, property, indexer, field, event, interface, delegate").WithLocation(34, 10), // (8,9): warning CS0618: 'Class1' is obsolete: 'Class1 is deprecated.' // Class1 x1 = null; Diagnostic(ErrorCode.WRN_DeprecatedSymbolStr, "Class1").WithArguments("Class1", "Class1 is deprecated.").WithLocation(8, 9), @@ -8131,7 +8134,13 @@ event System.Action E1 Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Class3").WithArguments("Class3", "Class3 is deprecated.").WithLocation(10, 9), // (11,9): error CS0619: 'Class4' is obsolete: 'Class4 is deprecated.' // Class4 x4 = null; - Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Class4").WithArguments("Class4", "Class4 is deprecated.").WithLocation(11, 9) + Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Class4").WithArguments("Class4", "Class4 is deprecated.").WithLocation(11, 9), + // (19,14): error CS0619: 'Class6.P1.get' is obsolete: 'P1.get is deprecated.' + // x5 = x6.P1; + Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "x6.P1").WithArguments("Class6.P1.get", "P1.get is deprecated.").WithLocation(19, 14), + // (40,10): error CS8423: Attribute 'Windows.Foundation.Metadata.DeprecatedAttribute' is not valid on event accessors. It is only valid on 'class, struct, enum, constructor, method, property, indexer, field, event, interface, delegate' declarations. + // [Deprecated("E1.add is deprecated.", DeprecationType.Remove, 1)] + Diagnostic(ErrorCode.ERR_AttributeNotOnEventAccessor, "Deprecated").WithArguments("Windows.Foundation.Metadata.DeprecatedAttribute", "class, struct, enum, constructor, method, property, indexer, field, event, interface, delegate").WithLocation(40, 10) }; compilation2.VerifyDiagnostics(expected); @@ -9110,5 +9119,38 @@ class C CreateCompilation(code).VerifyDiagnostics().VerifyEmitDiagnostics(); } + + [Fact] + public void TestObsoleteOnPropertyAccessorCSharp7() + { + var code = @" +class C +{ + public int Prop { [Obsolete] get; set; } +} +"; + + CreateCompilation(code, parseOptions: new CSharpParseOptions(LanguageVersion.CSharp7_3)).VerifyDiagnostics( + // (4,24): error CS8652: The feature 'obsolete property accessors' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public int Prop { [Obsolete] get; set; } + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Obsolete").WithArguments("obsolete property accessors").WithLocation(4, 24)); + } + + [Fact] + public void TestDeprecatedOnPropertyAccessorCSharp7() + { + var code = @" +using Windows.Foundation.Metadata; +class C +{ + public int Prop { [Deprecated(""don't use this"", DeprecationType.Remove, 50331648u)] get; set; } +} +"; + + CreateEmptyCompilation(code, references: WinRtRefs, parseOptions: new CSharpParseOptions(LanguageVersion.CSharp7_3)).VerifyDiagnostics( + // (5,24): error CS8652: The feature 'obsolete property accessors' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // public int Prop { [Deprecated("don't use this", DeprecationType.Remove, 50331648u)] get; set; } + Diagnostic(ErrorCode.ERR_FeatureInPreview, @"Deprecated(""don't use this"", DeprecationType.Remove, 50331648u)").WithArguments("obsolete property accessors").WithLocation(5, 24)); + } } } From 451c7386d7b59439b6eac0c272d1e0e6a1dcc925 Mon Sep 17 00:00:00 2001 From: yair halberstadt Date: Thu, 14 Mar 2019 08:47:07 +0000 Subject: [PATCH 09/18] Fix comment in SourceMemberMethodSymbol.VerifyObsoleteAttributeAppliedToMethod --- .../CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs index bbd4f588f01ba..1d930d0ca7dcb 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs @@ -1218,7 +1218,7 @@ private bool VerifyObsoleteAttributeAppliedToMethod( { if (this is SourceEventAccessorSymbol) { - // CS1667: Attribute '{0}' is not valid on property or event accessors. It is only valid on '{1}' declarations. + // CS1667: Attribute '{0}' is not valid on event accessors. It is only valid on '{1}' declarations. AttributeUsageInfo attributeUsage = arguments.Attribute.AttributeClass.GetAttributeUsageInfo(); arguments.Diagnostics.Add(ErrorCode.ERR_AttributeNotOnEventAccessor, arguments.AttributeSyntaxOpt.Name.Location, description.FullName, attributeUsage.GetValidTargetsErrorArgument()); } From 4755eaa8b9f7d1ba6cff9ab21a19f13529f3f309 Mon Sep 17 00:00:00 2001 From: yair halberstadt Date: Thu, 14 Mar 2019 09:07:47 +0000 Subject: [PATCH 10/18] Change feature message from 'obsolete property accessors' to 'obsolete on property accessor'. Fix missing using directive in unit test. --- .../CSharp/Portable/CSharpResources.Designer.cs | 2 +- src/Compilers/CSharp/Portable/CSharpResources.resx | 2 +- src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf | 4 ++-- src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf | 4 ++-- src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf | 4 ++-- src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf | 4 ++-- src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf | 4 ++-- src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf | 4 ++-- src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf | 4 ++-- src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf | 4 ++-- .../CSharp/Portable/xlf/CSharpResources.pt-BR.xlf | 4 ++-- src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf | 4 ++-- src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf | 4 ++-- .../CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf | 4 ++-- .../CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf | 4 ++-- .../Attributes/AttributeTests_WellKnownAttributes.cs | 9 +++++---- 16 files changed, 33 insertions(+), 32 deletions(-) diff --git a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs index 0a823f8b1db1a..e1f2ef91dda83 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs +++ b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs @@ -11330,7 +11330,7 @@ internal static string IDS_FeatureObjectInitializer { } /// - /// Looks up a localized string similar to obsolete property accessors. + /// Looks up a localized string similar to obsolete on property accessor. /// internal static string IDS_FeatureObsoleteOnPropertyAccessor { get { diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index adc13aed6d75e..3c550f3f99ab3 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -5800,6 +5800,6 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ Attribute '{0}' is not valid on event accessors. It is only valid on '{1}' declarations. - obsolete property accessors + obsolete on property accessor \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index 4543a7623208b..5fc1d3377d949 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -718,8 +718,8 @@ - obsolete property accessors - obsolete property accessors + obsolete on property accessor + obsolete on property accessor diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index 97b7c3f00224d..6ab6be1059c81 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -718,8 +718,8 @@ - obsolete property accessors - obsolete property accessors + obsolete on property accessor + obsolete on property accessor diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index badc6a35b45c1..00b5ca6329f09 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -720,8 +720,8 @@ - obsolete property accessors - obsolete property accessors + obsolete on property accessor + obsolete on property accessor diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index 78beaec0214d8..2f9053e4dc8b0 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -719,8 +719,8 @@ - obsolete property accessors - obsolete property accessors + obsolete on property accessor + obsolete on property accessor diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index 27d4c5e5010b9..fe4d148023adc 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -718,8 +718,8 @@ - obsolete property accessors - obsolete property accessors + obsolete on property accessor + obsolete on property accessor diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index 229a0900e0efe..ae3a72b531c76 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -718,8 +718,8 @@ - obsolete property accessors - obsolete property accessors + obsolete on property accessor + obsolete on property accessor diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index a54b4e6306f5f..ea680bcb768df 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -718,8 +718,8 @@ - obsolete property accessors - obsolete property accessors + obsolete on property accessor + obsolete on property accessor diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index ef53c2a04e53c..f437189d55278 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -718,8 +718,8 @@ - obsolete property accessors - obsolete property accessors + obsolete on property accessor + obsolete on property accessor diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index 4918ae6f0d18d..0cf6d49bf6ac1 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -718,8 +718,8 @@ - obsolete property accessors - obsolete property accessors + obsolete on property accessor + obsolete on property accessor diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index 09b37b1254fe1..73e5197b19fae 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -718,8 +718,8 @@ - obsolete property accessors - obsolete property accessors + obsolete on property accessor + obsolete on property accessor diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index 0aba2b1fbf398..e2c84a93555db 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -719,8 +719,8 @@ - obsolete property accessors - obsolete property accessors + obsolete on property accessor + obsolete on property accessor diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index 6ed47138241a7..d9c9896794835 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -719,8 +719,8 @@ - obsolete property accessors - obsolete property accessors + obsolete on property accessor + obsolete on property accessor diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index e3c5cc21a3b35..288e4c7fbe3e9 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -718,8 +718,8 @@ - obsolete property accessors - obsolete property accessors + obsolete on property accessor + obsolete on property accessor diff --git a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs b/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs index b9a89eae8f4ea..325957a45abd4 100644 --- a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs +++ b/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs @@ -9124,6 +9124,7 @@ class C public void TestObsoleteOnPropertyAccessorCSharp7() { var code = @" +using System; class C { public int Prop { [Obsolete] get; set; } @@ -9131,9 +9132,9 @@ class C "; CreateCompilation(code, parseOptions: new CSharpParseOptions(LanguageVersion.CSharp7_3)).VerifyDiagnostics( - // (4,24): error CS8652: The feature 'obsolete property accessors' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (4,24): error CS8652: The feature 'obsolete on property accessor' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // public int Prop { [Obsolete] get; set; } - Diagnostic(ErrorCode.ERR_FeatureInPreview, "Obsolete").WithArguments("obsolete property accessors").WithLocation(4, 24)); + Diagnostic(ErrorCode.ERR_FeatureInPreview, "Obsolete").WithArguments("obsolete on property accessor").WithLocation(5, 24)); } [Fact] @@ -9148,9 +9149,9 @@ class C "; CreateEmptyCompilation(code, references: WinRtRefs, parseOptions: new CSharpParseOptions(LanguageVersion.CSharp7_3)).VerifyDiagnostics( - // (5,24): error CS8652: The feature 'obsolete property accessors' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // (5,24): error CS8652: The feature 'obsolete on property accessor' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. // public int Prop { [Deprecated("don't use this", DeprecationType.Remove, 50331648u)] get; set; } - Diagnostic(ErrorCode.ERR_FeatureInPreview, @"Deprecated(""don't use this"", DeprecationType.Remove, 50331648u)").WithArguments("obsolete property accessors").WithLocation(5, 24)); + Diagnostic(ErrorCode.ERR_FeatureInPreview, @"Deprecated(""don't use this"", DeprecationType.Remove, 50331648u)").WithArguments("obsolete on property accessor").WithLocation(5, 24)); } } } From c327ac2c6d0523e1769ab31b7aeb953f6d408c2c Mon Sep 17 00:00:00 2001 From: yair halberstadt Date: Fri, 22 Mar 2019 08:40:15 +0000 Subject: [PATCH 11/18] Changes based on code review. Add more tests for obsolete on accessors, and Don't report 2 diagnostics for obsolete on an event in C# 7. --- .../Source/SourceMemberMethodSymbol.cs | 6 +- .../AttributeTests_WellKnownAttributes.cs | 152 +++++++++++++++++- 2 files changed, 152 insertions(+), 6 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs index 1d930d0ca7dcb..b72085a3570e7 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMemberMethodSymbol.cs @@ -1222,8 +1222,10 @@ private bool VerifyObsoleteAttributeAppliedToMethod( AttributeUsageInfo attributeUsage = arguments.Attribute.AttributeClass.GetAttributeUsageInfo(); arguments.Diagnostics.Add(ErrorCode.ERR_AttributeNotOnEventAccessor, arguments.AttributeSyntaxOpt.Name.Location, description.FullName, attributeUsage.GetValidTargetsErrorArgument()); } - - MessageID.IDS_FeatureObsoleteOnPropertyAccessor.CheckFeatureAvailability(arguments.Diagnostics, arguments.AttributeSyntaxOpt.Location); + else + { + MessageID.IDS_FeatureObsoleteOnPropertyAccessor.CheckFeatureAvailability(arguments.Diagnostics, arguments.AttributeSyntaxOpt.Location); + } } return true; diff --git a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs b/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs index 325957a45abd4..74b2bfa6e4db4 100644 --- a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs +++ b/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs @@ -6201,6 +6201,69 @@ class F6 : F5 Diagnostic(ErrorCode.WRN_ObsoleteOverridingNonObsolete, "get").WithArguments("E2.Goo.get", "E1.Goo.get").WithLocation(65, 42)); } + [Fact] + public void TestConsumptionOfObsoleteAttributeOnOverriddenAccessors() + { + var source = @" +using System; + +class Base +{ + public virtual int Foo { [Obsolete] get; set;} + public virtual int Goo { get; set; } + public virtual int Hoo { [Obsolete(""Base.Hoo is Obsolete"", true)] get; set; } + public virtual int Joo { [Obsolete(""Base.Joo is Obsolete"", false)] get; set; } + [Obsolete(""Base.Koo is Obsolete"")] public virtual int Koo { get; set; } +} +class Derived : Base +{ + public override int Foo { get; set; } + public override int Goo { [Obsolete] get; set; } + public override int Hoo { [Obsolete(""Derived.Hoo is Obsolete"", false)] get; set; } + public override int Joo { [Obsolete(""Derived.Joo is Obsolete"", true)] get; set; } + public override int Koo { [Obsolete(""Derived.Koo is Obsolete"")] get; set; } +} + +public class Program +{ + public void Main() + { + var derived = new Derived(); + _ = derived.Foo; + _ = derived.Goo; + _ = derived.Hoo; + _ = derived.Joo; + _ = derived.Koo; + } +} +"; + CreateCompilation(source).VerifyDiagnostics( + // (14,31): warning CS0672: Member 'Derived.Foo.get' overrides obsolete member 'Base.Foo.get'. Add the Obsolete attribute to 'Derived.Foo.get'. + // public override int Foo { get; set; } + Diagnostic(ErrorCode.WRN_NonObsoleteOverridingObsolete, "get").WithArguments("Derived.Foo.get", "Base.Foo.get").WithLocation(14, 31), + // (15,42): warning CS0809: Obsolete member 'Derived.Goo.get' overrides non-obsolete member 'Base.Goo.get' + // public override int Goo { [Obsolete] get; set; } + Diagnostic(ErrorCode.WRN_ObsoleteOverridingNonObsolete, "get").WithArguments("Derived.Goo.get", "Base.Goo.get").WithLocation(15, 42), + // (18,25): warning CS0672: Member 'Derived.Koo' overrides obsolete member 'Base.Koo'. Add the Obsolete attribute to 'Derived.Koo'. + // public override int Koo { [Obsolete("Derived.Koo is Obsolete")] get; set; } + Diagnostic(ErrorCode.WRN_NonObsoleteOverridingObsolete, "Koo").WithArguments("Derived.Koo", "Base.Koo").WithLocation(18, 25), + // (18,69): warning CS0809: Obsolete member 'Derived.Koo.get' overrides non-obsolete member 'Base.Koo.get' + // public override int Koo { [Obsolete("Derived.Koo is Obsolete")] get; set; } + Diagnostic(ErrorCode.WRN_ObsoleteOverridingNonObsolete, "get").WithArguments("Derived.Koo.get", "Base.Koo.get").WithLocation(18, 69), + // (26,7): warning CS0612: 'Base.Foo.get' is obsolete + // _ = derived.Foo; + Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "derived.Foo").WithArguments("Base.Foo.get").WithLocation(26, 7), + // (28,13): error CS0619: 'Base.Hoo.get' is obsolete: 'Base.Hoo is Obsolete' + // _ = derived.Hoo; + Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "derived.Hoo").WithArguments("Base.Hoo.get", "Base.Hoo is Obsolete").WithLocation(28, 13), + // (29,13): warning CS0618: 'Base.Joo.get' is obsolete: 'Base.Joo is Obsolete' + // _ = derived.Joo; + Diagnostic(ErrorCode.WRN_DeprecatedSymbolStr, "derived.Joo").WithArguments("Base.Joo.get", "Base.Joo is Obsolete").WithLocation(29, 13), + // (30,13): warning CS0618: 'Base.Koo' is obsolete: 'Base.Koo is Obsolete' + // _ = derived.Koo; + Diagnostic(ErrorCode.WRN_DeprecatedSymbolStr, "derived.Koo").WithArguments("Base.Koo", "Base.Koo is Obsolete").WithLocation(30, 13)); + } + [Fact] public void TestObsoleteAttributeCycles() { @@ -6556,7 +6619,7 @@ public int Prop [Obsolete(""Property"", true)] public int Prop2 { - get ; [Obsolete] set; + get ; set; } [Obsolete(""Field"", true)] public int Field; @@ -8091,6 +8154,8 @@ void Test() x5 = x4; x5 = x6.P1; x6.P1 = 1; + x5 = x6.P2; + x6.P2 = 1; x6.E1 += null; x6.E1 -= null; } @@ -8108,6 +8173,16 @@ public int P1 set {} } + public int P2 + { + get + { + return 1; + } + [Deprecated(""P1.get is deprecated."", DeprecationType.Remove, 1)] + set {} + } + public event System.Action E1 { [Deprecated(""E1.add is deprecated."", DeprecationType.Remove, 1)] @@ -8138,9 +8213,12 @@ public event System.Action E1 // (19,14): error CS0619: 'Class6.P1.get' is obsolete: 'P1.get is deprecated.' // x5 = x6.P1; Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "x6.P1").WithArguments("Class6.P1.get", "P1.get is deprecated.").WithLocation(19, 14), - // (40,10): error CS8423: Attribute 'Windows.Foundation.Metadata.DeprecatedAttribute' is not valid on event accessors. It is only valid on 'class, struct, enum, constructor, method, property, indexer, field, event, interface, delegate' declarations. + // (22,9): error CS0619: 'Class6.P2.set' is obsolete: 'P1.get is deprecated.' + // x6.P2 = 1; + Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "x6.P2").WithArguments("Class6.P2.set", "P1.get is deprecated.").WithLocation(22, 9), + // (52,10): error CS8423: Attribute 'Windows.Foundation.Metadata.DeprecatedAttribute' is not valid on event accessors. It is only valid on 'class, struct, enum, constructor, method, property, indexer, field, event, interface, delegate' declarations. // [Deprecated("E1.add is deprecated.", DeprecationType.Remove, 1)] - Diagnostic(ErrorCode.ERR_AttributeNotOnEventAccessor, "Deprecated").WithArguments("Windows.Foundation.Metadata.DeprecatedAttribute", "class, struct, enum, constructor, method, property, indexer, field, event, interface, delegate").WithLocation(40, 10) + Diagnostic(ErrorCode.ERR_AttributeNotOnEventAccessor, "Deprecated").WithArguments("Windows.Foundation.Metadata.DeprecatedAttribute", "class, struct, enum, constructor, method, property, indexer, field, event, interface, delegate").WithLocation(52, 10) }; compilation2.VerifyDiagnostics(expected); @@ -9112,12 +9190,26 @@ public void TestObsoleteOnPropertyAndAccessors() using System; class C { + public void M() => Prop = Prop; + [Obsolete] public int Prop { [Obsolete] get; [Obsolete] set; } } "; - CreateCompilation(code).VerifyDiagnostics().VerifyEmitDiagnostics(); + CreateCompilation(code).VerifyDiagnostics( + // (5,24): warning CS0612: 'C.Prop' is obsolete + // public void M() => Prop = Prop; + Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "Prop").WithArguments("C.Prop").WithLocation(5, 24), + // (5,24): warning CS0612: 'C.Prop.set' is obsolete + // public void M() => Prop = Prop; + Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "Prop").WithArguments("C.Prop.set").WithLocation(5, 24), + // (5,31): warning CS0612: 'C.Prop' is obsolete + // public void M() => Prop = Prop; + Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "Prop").WithArguments("C.Prop").WithLocation(5, 31), + // (5,31): warning CS0612: 'C.Prop.get' is obsolete + // public void M() => Prop = Prop; + Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "Prop").WithArguments("C.Prop.get").WithLocation(5, 31)); } [Fact] @@ -9153,5 +9245,57 @@ class C // public int Prop { [Deprecated("don't use this", DeprecationType.Remove, 50331648u)] get; set; } Diagnostic(ErrorCode.ERR_FeatureInPreview, @"Deprecated(""don't use this"", DeprecationType.Remove, 50331648u)").WithArguments("obsolete on property accessor").WithLocation(5, 24)); } + + [Fact] + public void TestObsoleteOnEventAccessorCSharp7() + { + var code = @" +using System; +class C +{ + public event System.Action E + { + [Obsolete] + add + { + } + remove + { + } + } +} +"; + + CreateCompilation(code, parseOptions: new CSharpParseOptions(LanguageVersion.CSharp7_3)).VerifyDiagnostics( + // (7,10): error CS8423: Attribute 'System.ObsoleteAttribute' is not valid on event accessors. It is only valid on 'class, struct, enum, constructor, method, property, indexer, field, event, interface, delegate' declarations. + // [Obsolete] + Diagnostic(ErrorCode.ERR_AttributeNotOnEventAccessor, "Obsolete").WithArguments("System.ObsoleteAttribute", "class, struct, enum, constructor, method, property, indexer, field, event, interface, delegate").WithLocation(7, 10)); + } + + [Fact] + public void TestDeprecatedOnEventAccessorCSharp7() + { + var code = @" +using Windows.Foundation.Metadata; +class C +{ + public event System.Action E + { + [Deprecated(""don't use this"", DeprecationType.Remove, 50331648u)] + add + { + } + remove + { + } + } +} +"; + + CreateEmptyCompilation(code, references: WinRtRefs, parseOptions: new CSharpParseOptions(LanguageVersion.CSharp7_3)).VerifyDiagnostics( + // (7,10): error CS8423: Attribute 'Windows.Foundation.Metadata.DeprecatedAttribute' is not valid on event accessors. It is only valid on 'class, struct, enum, constructor, method, property, indexer, field, event, interface, delegate' declarations. + // [Deprecated("don't use this", DeprecationType.Remove, 50331648u)] + Diagnostic(ErrorCode.ERR_AttributeNotOnEventAccessor, "Deprecated").WithArguments("Windows.Foundation.Metadata.DeprecatedAttribute", "class, struct, enum, constructor, method, property, indexer, field, event, interface, delegate").WithLocation(7, 10)); + } } } From dc32918a86d153b8fad6ce40bf2b69171bd2fe49 Mon Sep 17 00:00:00 2001 From: yair halberstadt Date: Fri, 22 Mar 2019 09:09:06 +0000 Subject: [PATCH 12/18] Report obsolete from setter on attribute property --- .../Portable/Binder/Binder_Attributes.cs | 9 +++ .../AttributeTests_WellKnownAttributes.cs | 68 ++++++++++++++----- 2 files changed, 60 insertions(+), 17 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Attributes.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Attributes.cs index a85cd53a1599e..f5f76059799ae 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Attributes.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Attributes.cs @@ -353,6 +353,15 @@ private BoundExpression BindNamedAttributeArgument(AttributeArgumentSyntax named ReportDiagnosticsIfObsolete(diagnostics, namedArgumentNameSymbol, namedArgument, hasBaseReceiver: false); + if (namedArgumentNameSymbol.Kind == SymbolKind.Property) + { + var propertySymbol = (PropertySymbol)namedArgumentNameSymbol; + if (propertySymbol.SetMethod != null) + { + ReportDiagnosticsIfObsolete(diagnostics, propertySymbol.SetMethod, namedArgument, hasBaseReceiver: false); + } + } + Debug.Assert(resultKind == LookupResultKind.Viable || wasError); TypeSymbol namedArgumentType; diff --git a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs b/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs index 74b2bfa6e4db4..c4fc90b95ef4c 100644 --- a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs +++ b/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs @@ -6619,7 +6619,20 @@ public int Prop [Obsolete(""Property"", true)] public int Prop2 { - get ; set; + get; set; + } + public int Prop3 + { + get; [Obsolete(""setter"", true)]set; + } + [Obsolete(""Property"", true)] + public int Prop4 + { + get; [Obsolete(""setter"", true)]set; + } + public int Prop5 + { + [Obsolete(""setter"", true)]get; set; } [Obsolete(""Field"", true)] public int Field; @@ -6629,6 +6642,9 @@ public int Prop2 [Att(Field = 1)] [Att(Prop = 1)] [Att(Prop2 = 1)] +[Att(Prop3 = 1)] +[Att(Prop4 = 1)] +[Att(Prop5 = 1)] public class Test { [Att()] @@ -6636,30 +6652,48 @@ public static void Main() { } } "; CreateCompilation(source).VerifyDiagnostics( - // (24,2): error CS0619: 'Att.Att()' is obsolete: 'Constructor' + // (37,2): error CS0619: 'Att.Att()' is obsolete: 'Constructor' // [Att] - Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Att").WithArguments("Att.Att()", "Constructor").WithLocation(24, 2), - // (25,6): error CS0619: 'Att.Field' is obsolete: 'Field' + Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Att").WithArguments("Att.Att()", "Constructor").WithLocation(37, 2), + // (38,6): error CS0619: 'Att.Field' is obsolete: 'Field' // [Att(Field = 1)] - Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Field = 1").WithArguments("Att.Field", "Field").WithLocation(25, 6), - // (25,2): error CS0619: 'Att.Att()' is obsolete: 'Constructor' + Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Field = 1").WithArguments("Att.Field", "Field").WithLocation(38, 6), + // (38,2): error CS0619: 'Att.Att()' is obsolete: 'Constructor' // [Att(Field = 1)] - Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Att(Field = 1)").WithArguments("Att.Att()", "Constructor").WithLocation(25, 2), - // (26,6): error CS0619: 'Att.Prop' is obsolete: 'Property' + Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Att(Field = 1)").WithArguments("Att.Att()", "Constructor").WithLocation(38, 2), + // (39,6): error CS0619: 'Att.Prop' is obsolete: 'Property' // [Att(Prop = 1)] - Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Prop = 1").WithArguments("Att.Prop", "Property").WithLocation(26, 6), - // (26,2): error CS0619: 'Att.Att()' is obsolete: 'Constructor' + Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Prop = 1").WithArguments("Att.Prop", "Property").WithLocation(39, 6), + // (39,2): error CS0619: 'Att.Att()' is obsolete: 'Constructor' // [Att(Prop = 1)] - Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Att(Prop = 1)").WithArguments("Att.Att()", "Constructor").WithLocation(26, 2), - // (27,6): error CS0619: 'Att.Prop2' is obsolete: 'Property' + Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Att(Prop = 1)").WithArguments("Att.Att()", "Constructor").WithLocation(39, 2), + // (40,6): error CS0619: 'Att.Prop2' is obsolete: 'Property' // [Att(Prop2 = 1)] - Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Prop2 = 1").WithArguments("Att.Prop2", "Property").WithLocation(27, 6), - // (27,2): error CS0619: 'Att.Att()' is obsolete: 'Constructor' + Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Prop2 = 1").WithArguments("Att.Prop2", "Property").WithLocation(40, 6), + // (40,2): error CS0619: 'Att.Att()' is obsolete: 'Constructor' // [Att(Prop2 = 1)] - Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Att(Prop2 = 1)").WithArguments("Att.Att()", "Constructor").WithLocation(27, 2), - // (30,6): error CS0619: 'Att.Att()' is obsolete: 'Constructor' + Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Att(Prop2 = 1)").WithArguments("Att.Att()", "Constructor").WithLocation(40, 2), + // (41,6): error CS0619: 'Att.Prop3.set' is obsolete: 'setter' + // [Att(Prop3 = 1)] + Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Prop3 = 1").WithArguments("Att.Prop3.set", "setter").WithLocation(41, 6), + // (41,2): error CS0619: 'Att.Att()' is obsolete: 'Constructor' + // [Att(Prop3 = 1)] + Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Att(Prop3 = 1)").WithArguments("Att.Att()", "Constructor").WithLocation(41, 2), + // (42,6): error CS0619: 'Att.Prop4' is obsolete: 'Property' + // [Att(Prop4 = 1)] + Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Prop4 = 1").WithArguments("Att.Prop4", "Property").WithLocation(42, 6), + // (42,6): error CS0619: 'Att.Prop4.set' is obsolete: 'setter' + // [Att(Prop4 = 1)] + Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Prop4 = 1").WithArguments("Att.Prop4.set", "setter").WithLocation(42, 6), + // (42,2): error CS0619: 'Att.Att()' is obsolete: 'Constructor' + // [Att(Prop4 = 1)] + Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Att(Prop4 = 1)").WithArguments("Att.Att()", "Constructor").WithLocation(42, 2), + // (43,2): error CS0619: 'Att.Att()' is obsolete: 'Constructor' + // [Att(Prop5 = 1)] + Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Att(Prop5 = 1)").WithArguments("Att.Att()", "Constructor").WithLocation(43, 2), + // (46,6): error CS0619: 'Att.Att()' is obsolete: 'Constructor' // [Att()] - Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Att()").WithArguments("Att.Att()", "Constructor").WithLocation(30, 6)); + Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Att()").WithArguments("Att.Att()", "Constructor").WithLocation(46, 6) } [Fact] From 904f95d39ccf8b6b80f9406e60c903ab21673bf6 Mon Sep 17 00:00:00 2001 From: yair halberstadt Date: Fri, 22 Mar 2019 09:10:09 +0000 Subject: [PATCH 13/18] Fix typo --- .../Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs b/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs index c4fc90b95ef4c..a2ba5c481e520 100644 --- a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs +++ b/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs @@ -6693,7 +6693,7 @@ public static void Main() { } Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Att(Prop5 = 1)").WithArguments("Att.Att()", "Constructor").WithLocation(43, 2), // (46,6): error CS0619: 'Att.Att()' is obsolete: 'Constructor' // [Att()] - Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Att()").WithArguments("Att.Att()", "Constructor").WithLocation(46, 6) + Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Att()").WithArguments("Att.Att()", "Constructor").WithLocation(46, 6)); } [Fact] From d1e4cfd0977032539c57a4387295f8f88e889f11 Mon Sep 17 00:00:00 2001 From: yair halberstadt Date: Fri, 22 Mar 2019 09:19:37 +0000 Subject: [PATCH 14/18] Add test for obsolete attribute on indexer accessors. --- .../AttributeTests_WellKnownAttributes.cs | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs b/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs index a2ba5c481e520..e76c67a0b23e7 100644 --- a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs +++ b/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs @@ -6696,6 +6696,42 @@ public static void Main() { } Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Att()").WithArguments("Att.Att()", "Constructor").WithLocation(46, 6)); } + [Fact] + public void TestObsoleteAttributeOnIndexerAccessors() + { + var source = @" +using System; + +class C1 +{ + public int this[int index] { [Obsolete] get => 1; set {} } +} + +class C2 +{ + public int this[int index] { get => 1; [Obsolete] set {} } +} + +public class Program +{ + public void Main() + { + var c1 = new C1(); + c1[0] = c1[0]; + var c2 = new C2(); + c2[0] = c2[0]; + } +} +"; + CreateCompilation(source).VerifyDiagnostics( + // (19,17): warning CS0612: 'C1.this[int].get' is obsolete + // c1[0] = c1[0]; + Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "c1[0]").WithArguments("C1.this[int].get").WithLocation(19, 17), + // (21,9): warning CS0612: 'C2.this[int].set' is obsolete + // c2[0] = c2[0]; + Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "c2[0]").WithArguments("C2.this[int].set").WithLocation(21, 9)); + } + [Fact] public void TestObsoleteAttributeOnMembers2() { From 921240d7aba6499a7bdf00d1e3bee2b2d8253c53 Mon Sep 17 00:00:00 2001 From: Yair Halberstadt Date: Sat, 23 Mar 2019 20:00:37 +0000 Subject: [PATCH 15/18] Replace Foo with Boo --- .../AttributeTests_WellKnownAttributes.cs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs b/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs index e76c67a0b23e7..3c7ce9cd07e5d 100644 --- a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs +++ b/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs @@ -6209,7 +6209,7 @@ public void TestConsumptionOfObsoleteAttributeOnOverriddenAccessors() class Base { - public virtual int Foo { [Obsolete] get; set;} + public virtual int Boo { [Obsolete] get; set;} public virtual int Goo { get; set; } public virtual int Hoo { [Obsolete(""Base.Hoo is Obsolete"", true)] get; set; } public virtual int Joo { [Obsolete(""Base.Joo is Obsolete"", false)] get; set; } @@ -6217,7 +6217,7 @@ class Base } class Derived : Base { - public override int Foo { get; set; } + public override int Boo { get; set; } public override int Goo { [Obsolete] get; set; } public override int Hoo { [Obsolete(""Derived.Hoo is Obsolete"", false)] get; set; } public override int Joo { [Obsolete(""Derived.Joo is Obsolete"", true)] get; set; } @@ -6229,7 +6229,7 @@ public class Program public void Main() { var derived = new Derived(); - _ = derived.Foo; + _ = derived.Boo; _ = derived.Goo; _ = derived.Hoo; _ = derived.Joo; @@ -6238,9 +6238,9 @@ public void Main() } "; CreateCompilation(source).VerifyDiagnostics( - // (14,31): warning CS0672: Member 'Derived.Foo.get' overrides obsolete member 'Base.Foo.get'. Add the Obsolete attribute to 'Derived.Foo.get'. - // public override int Foo { get; set; } - Diagnostic(ErrorCode.WRN_NonObsoleteOverridingObsolete, "get").WithArguments("Derived.Foo.get", "Base.Foo.get").WithLocation(14, 31), + // (14,31): warning CS0672: Member 'Derived.Boo.get' overrides obsolete member 'Base.Boo.get'. Add the Obsolete attribute to 'Derived.Boo.get'. + // public override int Boo { get; set; } + Diagnostic(ErrorCode.WRN_NonObsoleteOverridingObsolete, "get").WithArguments("Derived.Boo.get", "Base.Boo.get").WithLocation(14, 31), // (15,42): warning CS0809: Obsolete member 'Derived.Goo.get' overrides non-obsolete member 'Base.Goo.get' // public override int Goo { [Obsolete] get; set; } Diagnostic(ErrorCode.WRN_ObsoleteOverridingNonObsolete, "get").WithArguments("Derived.Goo.get", "Base.Goo.get").WithLocation(15, 42), @@ -6250,9 +6250,9 @@ public void Main() // (18,69): warning CS0809: Obsolete member 'Derived.Koo.get' overrides non-obsolete member 'Base.Koo.get' // public override int Koo { [Obsolete("Derived.Koo is Obsolete")] get; set; } Diagnostic(ErrorCode.WRN_ObsoleteOverridingNonObsolete, "get").WithArguments("Derived.Koo.get", "Base.Koo.get").WithLocation(18, 69), - // (26,7): warning CS0612: 'Base.Foo.get' is obsolete - // _ = derived.Foo; - Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "derived.Foo").WithArguments("Base.Foo.get").WithLocation(26, 7), + // (26,7): warning CS0612: 'Base.Boo.get' is obsolete + // _ = derived.Boo; + Diagnostic(ErrorCode.WRN_DeprecatedSymbol, "derived.Boo").WithArguments("Base.Boo.get").WithLocation(26, 7), // (28,13): error CS0619: 'Base.Hoo.get' is obsolete: 'Base.Hoo is Obsolete' // _ = derived.Hoo; Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "derived.Hoo").WithArguments("Base.Hoo.get", "Base.Hoo is Obsolete").WithLocation(28, 13), From 4bc5bcb7f88b3eb2c2d4c6aa77b47e936d560f10 Mon Sep 17 00:00:00 2001 From: yair halberstadt Date: Sun, 31 Mar 2019 11:06:57 +0100 Subject: [PATCH 16/18] Deal correctly with an obsolete inherited set method on an attribute --- .../Portable/Binder/Binder_Attributes.cs | 5 +- .../AttributeTests_WellKnownAttributes.cs | 88 +++++++++++++++++++ 2 files changed, 91 insertions(+), 2 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Attributes.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Attributes.cs index f5f76059799ae..057e15ce08d86 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Attributes.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Attributes.cs @@ -356,9 +356,10 @@ private BoundExpression BindNamedAttributeArgument(AttributeArgumentSyntax named if (namedArgumentNameSymbol.Kind == SymbolKind.Property) { var propertySymbol = (PropertySymbol)namedArgumentNameSymbol; - if (propertySymbol.SetMethod != null) + var setMethod = propertySymbol.GetOwnOrInheritedSetMethod(); + if (setMethod != null) { - ReportDiagnosticsIfObsolete(diagnostics, propertySymbol.SetMethod, namedArgument, hasBaseReceiver: false); + ReportDiagnosticsIfObsolete(diagnostics, setMethod, namedArgument, hasBaseReceiver: false); } } diff --git a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs b/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs index 3c7ce9cd07e5d..c2903a974db4f 100644 --- a/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs +++ b/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_WellKnownAttributes.cs @@ -6696,6 +6696,94 @@ public static void Main() { } Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Att()").WithArguments("Att.Att()", "Constructor").WithLocation(46, 6)); } + [Fact] + public void TestOverridenObsoleteSetterOnAttributes() + { + var source = @" +using System; + +[AttributeUsage(AttributeTargets.All, AllowMultiple = true)] +public class BaseAtt : Attribute +{ + public virtual int Prop + { + get { return 1; } + [Obsolete(""setter"", true)] set { } + } + + public virtual int Prop1 + { + get { return 1; } + [Obsolete(""setter"", true)] set { } + } + + public virtual int Prop2 + { + get { return 1; } + [Obsolete(""base setter"", true)] set { } + } + + public virtual int Prop3 + { + get { return 1; } + set { } + } +} + +[AttributeUsage(AttributeTargets.All, AllowMultiple = true)] +public class DerivedAtt : BaseAtt +{ + public override int Prop + { + get { return 1; } + } + + public override int Prop1 + { + get { return 1; } + set { } + } + + public override int Prop2 + { + get { return 1; } + [Obsolete(""derived setter"", true)] set { } + } + + public override int Prop3 + { + get { return 1; } + [Obsolete(""setter"", true)] set { } + } +} + +[DerivedAtt(Prop = 1)] +[DerivedAtt(Prop1 = 1)] +[DerivedAtt(Prop2 = 1)] +[DerivedAtt(Prop3 = 1)] +public class Test +{ + public static void Main() { } +} +"; + CreateCompilation(source).VerifyDiagnostics( + // (43,9): warning CS0672: Member 'DerivedAtt.Prop1.set' overrides obsolete member 'BaseAtt.Prop1.set'. Add the Obsolete attribute to 'DerivedAtt.Prop1.set'. + // set { } + Diagnostic(ErrorCode.WRN_NonObsoleteOverridingObsolete, "set").WithArguments("DerivedAtt.Prop1.set", "BaseAtt.Prop1.set").WithLocation(43, 9), + // (55,36): warning CS0809: Obsolete member 'DerivedAtt.Prop3.set' overrides non-obsolete member 'BaseAtt.Prop3.set' + // [Obsolete("setter", true)] set { } + Diagnostic(ErrorCode.WRN_ObsoleteOverridingNonObsolete, "set").WithArguments("DerivedAtt.Prop3.set", "BaseAtt.Prop3.set").WithLocation(55, 36), + // (59,13): error CS0619: 'BaseAtt.Prop.set' is obsolete: 'setter' + // [DerivedAtt(Prop = 1)] + Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Prop = 1").WithArguments("BaseAtt.Prop.set", "setter").WithLocation(59, 13), + // (60,13): error CS0619: 'BaseAtt.Prop1.set' is obsolete: 'setter' + // [DerivedAtt(Prop1 = 1)] + Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Prop1 = 1").WithArguments("BaseAtt.Prop1.set", "setter").WithLocation(60, 13), + // (61,13): error CS0619: 'BaseAtt.Prop2.set' is obsolete: 'base setter' + // [DerivedAtt(Prop2 = 1)] + Diagnostic(ErrorCode.ERR_DeprecatedSymbolStr, "Prop2 = 1").WithArguments("BaseAtt.Prop2.set", "base setter").WithLocation(61, 13)); + } + [Fact] public void TestObsoleteAttributeOnIndexerAccessors() { From ad5175d7c2730524a992d2100749f0b19853ee0a Mon Sep 17 00:00:00 2001 From: Yair Halberstadt Date: Mon, 1 Apr 2019 08:36:01 +0100 Subject: [PATCH 17/18] Reorder MessageId usages --- src/Compilers/CSharp/Portable/Errors/MessageID.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Errors/MessageID.cs b/src/Compilers/CSharp/Portable/Errors/MessageID.cs index d03e0a38e64ce..b584782d73be3 100644 --- a/src/Compilers/CSharp/Portable/Errors/MessageID.cs +++ b/src/Compilers/CSharp/Portable/Errors/MessageID.cs @@ -175,10 +175,9 @@ internal enum MessageID IDS_FeatureStaticLocalFunctions = MessageBase + 12755, IDS_FeatureNameShadowingInNestedFunctions = MessageBase + 12756, IDS_FeatureUnmanagedConstructedTypes = MessageBase + 12757, - + IDS_FeatureObsoleteOnPropertyAccessor = MessageBase + 12758, IDS_DefaultInterfaceImplementation = MessageBase + 12800, IDS_BaseTypeInBaseExpression = MessageBase + 12801, - IDS_FeatureObsoleteOnPropertyAccessor = MessageBase + 12758, } // Message IDs may refer to strings that need to be localized. @@ -283,9 +282,9 @@ internal static LanguageVersion RequiredVersion(this MessageID feature) case MessageID.IDS_FeatureStaticLocalFunctions: case MessageID.IDS_FeatureNameShadowingInNestedFunctions: case MessageID.IDS_FeatureUnmanagedConstructedTypes: // semantic check + case MessageID.IDS_FeatureObsoleteOnPropertyAccessor: case MessageID.IDS_DefaultInterfaceImplementation: // semantic check case MessageID.IDS_BaseTypeInBaseExpression: - case MessageID.IDS_FeatureObsoleteOnPropertyAccessor: return LanguageVersion.CSharp8; // C# 7.3 features. From 9a563e3fae2afbbd0e4f388744cb9cc807f3d329 Mon Sep 17 00:00:00 2001 From: Yair Halberstadt Date: Mon, 1 Apr 2019 08:36:51 +0100 Subject: [PATCH 18/18] Undo formatting change --- src/Compilers/CSharp/Portable/Errors/MessageID.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Compilers/CSharp/Portable/Errors/MessageID.cs b/src/Compilers/CSharp/Portable/Errors/MessageID.cs index b584782d73be3..497446b361b3c 100644 --- a/src/Compilers/CSharp/Portable/Errors/MessageID.cs +++ b/src/Compilers/CSharp/Portable/Errors/MessageID.cs @@ -176,6 +176,7 @@ internal enum MessageID IDS_FeatureNameShadowingInNestedFunctions = MessageBase + 12756, IDS_FeatureUnmanagedConstructedTypes = MessageBase + 12757, IDS_FeatureObsoleteOnPropertyAccessor = MessageBase + 12758, + IDS_DefaultInterfaceImplementation = MessageBase + 12800, IDS_BaseTypeInBaseExpression = MessageBase + 12801, }