|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#nullable disable
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using System;
using System.Linq;
using Xunit;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests.Symbols.Source
{
public class EventTests : CSharpTestBase
{
#region Positive Cases
[WorkItem(537323, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537323")]
[Fact]
public void EventInStructFollowedByClassDecl()
{
var text =
@"using System;
struct Test1
{
event MyEvent ITest.Clicked;
}
class main1
{
public static void Main()
{
}
}
";
var comp = CreateCompilation(text);
var actualSymbols = comp.Assembly.GlobalNamespace.GetMembers();
var actual = string.Join(", ", actualSymbols.Where(s => !s.IsImplicitlyDeclared).Select(symbol => symbol.Name).OrderBy(name => name));
Assert.Equal("main1, Test1", actual);
}
[WorkItem(537401, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537401")]
[Fact]
public void EventEscapedIdentifier()
{
var text = @"
delegate void @out();
class C1
{
event @out @in;
}
";
var comp = CreateCompilation(Parse(text));
NamedTypeSymbol c1 = (NamedTypeSymbol)comp.SourceModule.GlobalNamespace.GetMembers("C1").Single();
//EventSymbol ein = c1.GetMembers("in").Single();
//Assert.Equal("in", ein.Name);
//Assert.Equal("C1.@in", ein.ToString());
//NamedTypeSymbol dout = ein.Type;
//Assert.Equal("out", dout.Name);
//Assert.Equal("@out", dout.ToString());
}
[Fact]
public void InstanceFieldLikeEventDeclaration()
{
var text = @"
class C
{
public virtual event System.Action E;
}
";
var comp = CreateCompilation(text);
var global = comp.GlobalNamespace;
var @class = global.GetMember<NamedTypeSymbol>("C");
var @event = @class.GetMember<EventSymbol>("E");
Assert.Equal(SymbolKind.Event, @event.Kind);
Assert.Equal(Accessibility.Public, @event.DeclaredAccessibility);
Assert.True(@event.IsVirtual);
Assert.False(@event.IsStatic);
var addMethod = @event.AddMethod;
Assert.Equal(MethodKind.EventAdd, addMethod.MethodKind);
Assert.Equal("void C.E.add", addMethod.ToTestDisplayString());
addMethod.CheckAccessorShape(@event);
var removeMethod = @event.RemoveMethod;
Assert.Equal(MethodKind.EventRemove, removeMethod.MethodKind);
Assert.Equal("void C.E.remove", removeMethod.ToTestDisplayString());
removeMethod.CheckAccessorShape(@event);
Assert.True(@event.HasAssociatedField);
var associatedField = @event.AssociatedField;
Assert.Equal(SymbolKind.Field, associatedField.Kind);
Assert.Equal(Accessibility.Private, associatedField.DeclaredAccessibility);
Assert.False(associatedField.IsStatic);
Assert.Equal(@event.Type, associatedField.Type);
}
[Fact]
public void StaticFieldLikeEventDeclaration()
{
var text = @"
class C
{
internal static event System.Action E;
}
";
var comp = CreateCompilation(text);
var global = comp.GlobalNamespace;
var @class = global.GetMember<NamedTypeSymbol>("C");
var @event = @class.GetMember<EventSymbol>("E");
Assert.Equal(SymbolKind.Event, @event.Kind);
Assert.Equal(Accessibility.Internal, @event.DeclaredAccessibility);
Assert.True(@event.IsStatic);
var addMethod = @event.AddMethod;
Assert.Equal(MethodKind.EventAdd, addMethod.MethodKind);
Assert.Equal("void C.E.add", addMethod.ToTestDisplayString());
addMethod.CheckAccessorShape(@event);
var removeMethod = @event.RemoveMethod;
Assert.Equal(MethodKind.EventRemove, removeMethod.MethodKind);
Assert.Equal("void C.E.remove", removeMethod.ToTestDisplayString());
removeMethod.CheckAccessorShape(@event);
Assert.True(@event.HasAssociatedField);
var associatedField = @event.AssociatedField;
Assert.Equal(SymbolKind.Field, associatedField.Kind);
Assert.Equal(Accessibility.Private, associatedField.DeclaredAccessibility);
Assert.True(associatedField.IsStatic);
Assert.Equal(@event.Type, associatedField.Type);
}
[Fact]
public void InstanceCustomEventDeclaration()
{
var text = @"
class C
{
protected event System.Action E { add { } remove { } }
}
";
var comp = CreateCompilation(text);
var global = comp.GlobalNamespace;
var @class = global.GetMember<NamedTypeSymbol>("C");
var @event = @class.GetMember<EventSymbol>("E");
Assert.Equal(SymbolKind.Event, @event.Kind);
Assert.Equal(Accessibility.Protected, @event.DeclaredAccessibility);
Assert.False(@event.IsVirtual);
Assert.False(@event.IsStatic);
var addMethod = @event.AddMethod;
Assert.Equal(MethodKind.EventAdd, addMethod.MethodKind);
Assert.Equal("void C.E.add", addMethod.ToTestDisplayString());
addMethod.CheckAccessorShape(@event);
var removeMethod = @event.RemoveMethod;
Assert.Equal(MethodKind.EventRemove, removeMethod.MethodKind);
Assert.Equal("void C.E.remove", removeMethod.ToTestDisplayString());
removeMethod.CheckAccessorShape(@event);
Assert.False(@event.HasAssociatedField);
Assert.Null(@event.AssociatedField);
}
[Fact]
public void StaticCustomEventDeclaration()
{
var text = @"
class C
{
private static event System.Action E { add { } remove { } }
}
";
var comp = CreateCompilation(text);
var global = comp.GlobalNamespace;
var @class = global.GetMember<NamedTypeSymbol>("C");
var @event = @class.GetMember<EventSymbol>("E");
Assert.Equal(SymbolKind.Event, @event.Kind);
Assert.Equal(Accessibility.Private, @event.DeclaredAccessibility);
Assert.False(@event.IsVirtual);
Assert.True(@event.IsStatic);
var addMethod = @event.AddMethod;
Assert.Equal(MethodKind.EventAdd, addMethod.MethodKind);
Assert.Equal("void C.E.add", addMethod.ToTestDisplayString());
addMethod.CheckAccessorShape(@event);
var removeMethod = @event.RemoveMethod;
Assert.Equal(MethodKind.EventRemove, removeMethod.MethodKind);
Assert.Equal("void C.E.remove", removeMethod.ToTestDisplayString());
removeMethod.CheckAccessorShape(@event);
Assert.False(@event.HasAssociatedField);
Assert.Null(@event.AssociatedField);
}
[Fact]
public void UseAccessorParameter()
{
var text = @"
class C
{
protected event System.Action E
{
add
{
value();
}
remove
{
value();
}
}
}
";
CreateCompilation(text).VerifyDiagnostics();
}
[ClrOnlyFact]
public void EventInvocation()
{
var text =
@"using System;
public class Program
{
static void Main()
{
EventHandler<EventArgs> handler1 = (s, ev) => System.Console.Write(""H1"");
EventHandler<EventArgs> handler2 = (s, ev) => System.Console.Write(""H2"");
var e = new E();
e./*anchorE_3*/E1 += handler1;
e.E1 += handler2;
System.Console.Write(""T1"");
e.TriggerE1();
e.E1 -= handler1;
System.Console.Write(""T2"");
e.TriggerE1();
e.E1 -= handler2;
System.Console.Write(""T3"");
e.TriggerE1();
e.E2 += handler1;
e.E2 += handler2;
System.Console.Write(""T4"");
e.TriggerE2();
e.E2 -= handler1;
System.Console.Write(""T5"");
e.TriggerE2();
e.E2 -= handler2;
System.Console.Write(""T6"");
e.TriggerE2();
}
}
public class E
{
public event EventHandler<EventArgs> E1;
public EventHandler<EventArgs> _E2;
public event EventHandler<EventArgs> E2
{
add { _E2 += value; }
remove { _E2 -= value; }
}
public void Connect()
{
/*anchorE_1*/E1 += (s, e) => {};
}
public void TriggerE1()
{
if(/*anchorE_2*/E1 != null) E1(null, null);
}
public void TriggerE2() { if(_E2 != null) _E2(null, null); }
}
";
var compVerifier = CompileAndVerify(text, expectedOutput: "T1H1H2T2H2T3T4H1H2T5H2T6");
compVerifier.VerifyDiagnostics(DiagnosticDescription.None);
var semanticModel = compVerifier.Compilation.GetSemanticModel(compVerifier.Compilation.SyntaxTrees.Single());
var eventSymbol1 = semanticModel.LookupSymbols(text.IndexOf("/*anchorE_1*/", StringComparison.Ordinal), name: "E1").SingleOrDefault() as IEventSymbol;
Assert.NotNull(eventSymbol1);
var eventSymbol2 = semanticModel.LookupSymbols(text.IndexOf("/*anchorE_2*/", StringComparison.Ordinal), name: "E1").SingleOrDefault() as IEventSymbol;
Assert.NotNull(eventSymbol2);
}
[WorkItem(542748, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542748")]
[Fact()]
public void FieldLikeEventAccessorIsSynthesized()
{
var text = @"
delegate void D();
class C
{
internal event D FieldLikeEvent;
}
";
var comp = CreateCompilation(text);
NamedTypeSymbol type01 = comp.SourceModule.GlobalNamespace.GetTypeMembers("C").Single();
var fevent = type01.GetMembers("FieldLikeEvent").Single() as EventSymbol;
Assert.NotNull(fevent.AddMethod);
Assert.True(fevent.AddMethod.IsImplicitlyDeclared, "FieldLikeEvent AddAccessor");
Assert.NotNull(fevent.AddMethod);
Assert.True(fevent.RemoveMethod.IsImplicitlyDeclared, "FieldLikeEvent RemoveAccessor");
}
[Fact, WorkItem(7845, "https://github.com/dotnet/roslyn/issues/7845")]
public void EventWithDynamicAttribute_DynamicAttributeIsSynthesized()
{
var source = @"
class A
{
public event System.Action<dynamic> E1;
public event System.Action<dynamic> E2 { add {} remove {} }
public System.Action<dynamic> P { get; set; }
}";
Action<ModuleSymbol> validator = module =>
{
var peModule = (PEModuleSymbol)module;
var type = peModule.GlobalNamespace.GetMember<NamedTypeSymbol>("A");
var e1 = type.GetMember<EventSymbol>("E1");
var e2 = type.GetMember<EventSymbol>("E2");
var p = type.GetMember<PropertySymbol>("P");
Assert.Equal("System.Action<dynamic>", e1.Type.ToTestDisplayString());
Assert.Equal("System.Action<dynamic>", e2.Type.ToTestDisplayString());
Assert.Equal("System.Action<dynamic>", p.Type.ToTestDisplayString());
Assert.Equal(1, e1.AddMethod.ParameterTypesWithAnnotations.Length);
Assert.Equal("System.Action<dynamic>", e1.AddMethod.ParameterTypesWithAnnotations[0].ToTestDisplayString());
Assert.Equal(1, e1.RemoveMethod.ParameterTypesWithAnnotations.Length);
Assert.Equal("System.Action<dynamic>", e1.RemoveMethod.ParameterTypesWithAnnotations[0].ToTestDisplayString());
Assert.Equal(1, e2.AddMethod.ParameterTypesWithAnnotations.Length);
Assert.Equal("System.Action<dynamic>", e2.AddMethod.ParameterTypesWithAnnotations[0].ToTestDisplayString());
Assert.Equal(1, e2.RemoveMethod.ParameterTypesWithAnnotations.Length);
Assert.Equal("System.Action<dynamic>", e2.RemoveMethod.ParameterTypesWithAnnotations[0].ToTestDisplayString());
Assert.Equal(1, e1.GetAttributes(AttributeDescription.DynamicAttribute).Count());
Assert.Equal(1, e2.GetAttributes(AttributeDescription.DynamicAttribute).Count());
Assert.Equal(1, p.GetAttributes(AttributeDescription.DynamicAttribute).Count());
};
var comp = CreateEmptyCompilation(source, new[] { MscorlibRef, SystemCoreRef });
CompileAndVerify(comp, symbolValidator: validator);
}
[Fact, WorkItem(7845, "https://github.com/dotnet/roslyn/issues/7845")]
public void EventFieldWithDynamicAttribute_CannotCompileWithoutSystemCore()
{
var source = @"
public class A
{
public event System.Action<dynamic> E1;
}";
var libComp = CreateEmptyCompilation(source, new[] { MscorlibRef }).VerifyDiagnostics(
// (4,32): error CS1980: Cannot define a class or member that utilizes 'dynamic' because the compiler required type 'System.Runtime.CompilerServices.DynamicAttribute' cannot be found. Are you missing a reference?
// public event System.Action<dynamic> E1;
Diagnostic(ErrorCode.ERR_DynamicAttributeMissing, "dynamic").WithArguments("System.Runtime.CompilerServices.DynamicAttribute").WithLocation(4, 32),
// (4,41): warning CS0067: The event 'A.E1' is never used
// public event System.Action<dynamic> E1;
Diagnostic(ErrorCode.WRN_UnreferencedEvent, "E1").WithArguments("A.E1").WithLocation(4, 41));
}
[Fact, WorkItem(7845, "https://github.com/dotnet/roslyn/issues/7845")]
public void EventWithDynamicAttribute_CannotCompileWithoutSystemCore()
{
var source = @"
public class A
{
public event System.Action<dynamic> E1 { add {} remove {} }
}";
var libComp = CreateEmptyCompilation(source, references: new[] { MscorlibRef }).VerifyDiagnostics(
// (4,32): error CS1980: Cannot define a class or member that utilizes 'dynamic' because the compiler required type 'System.Runtime.CompilerServices.DynamicAttribute' cannot be found. Are you missing a reference?
// public event System.Action<dynamic> E1 { add {} remove {} }
Diagnostic(ErrorCode.ERR_DynamicAttributeMissing, "dynamic").WithArguments("System.Runtime.CompilerServices.DynamicAttribute").WithLocation(4, 32));
}
[Fact, WorkItem(7845, "https://github.com/dotnet/roslyn/issues/7845")]
public void EventFieldWithDynamicAttribute_IsLoadedAsDynamic()
{
var libText = @"
public class C
{
public event System.Action<dynamic> E1;
public void RaiseEvent() => E1(this);
public void Print() => System.Console.WriteLine(""Print method ran."");
}";
var libComp = CreateCompilation(source: libText).VerifyDiagnostics();
var libAssemblyRef = libComp.EmitToImageReference();
var source = @"
class LambdaConsumer
{
static void Main()
{
var c = new C();
c.E1 += f => f.Print();
c.RaiseEvent();
}
}";
Action<ModuleSymbol> validator = module =>
{
var sourceModule = (SourceModuleSymbol)module;
var compilation = sourceModule.DeclaringCompilation;
var tree = compilation.SyntaxTrees.First();
var model = compilation.GetSemanticModel(tree);
var lambdaSyntax = tree.GetRoot().DescendantNodes().OfType<SimpleLambdaExpressionSyntax>().First();
Assert.Equal("f => f.Print()", lambdaSyntax.ToFullString());
var lambdaTypeInfo = model.GetTypeInfo(lambdaSyntax);
Assert.Equal("System.Action<dynamic>", lambdaTypeInfo.ConvertedType.ToTestDisplayString());
var parameterSyntax = lambdaSyntax.DescendantNodes().OfType<ParameterSyntax>().First();
var parameterSymbol = model.GetDeclaredSymbol(parameterSyntax);
Assert.Equal("dynamic", parameterSymbol.Type.ToTestDisplayString());
};
CompileAndVerify(source: source, references: new[] { TargetFrameworkUtil.StandardCSharpReference, libAssemblyRef },
expectedOutput: "Print method ran.", sourceSymbolValidator: validator);
}
[Fact, WorkItem(7845, "https://github.com/dotnet/roslyn/issues/7845")]
public void EventWithDynamicAttribute_IsLoadedAsDynamic()
{
var libText = @"
public class C {
private System.Action<dynamic> _e1;
public event System.Action<dynamic> E1 { add { _e1 = value; } remove {} }
public void RaiseEvent() => _e1(this);
public void Print() => System.Console.WriteLine(""Print method ran."");
}";
var libComp = CreateCompilation(source: libText);
libComp.VerifyDiagnostics();
var libAssemblyRef = libComp.EmitToImageReference();
var source = @"
class D
{
static void Main()
{
var c = new C();
c.E1 += f => f.Print();
c.RaiseEvent();
}
}";
Action<ModuleSymbol> validator = module =>
{
var sourceModule = (SourceModuleSymbol)module;
var compilation = module.DeclaringCompilation;
var tree = compilation.SyntaxTrees.First();
var model = compilation.GetSemanticModel(tree);
var lambdaSyntax = tree.GetRoot().DescendantNodes().OfType<SimpleLambdaExpressionSyntax>().First();
Assert.Equal("f => f.Print()", lambdaSyntax.ToFullString());
var lambdaTypeInfo = model.GetTypeInfo(lambdaSyntax);
Assert.Equal("System.Action<dynamic>", lambdaTypeInfo.ConvertedType.ToTestDisplayString());
var parameterSyntax = lambdaSyntax.DescendantNodes().OfType<ParameterSyntax>().First();
var parameterSymbol = model.GetDeclaredSymbol(parameterSyntax);
Assert.Equal("dynamic", parameterSymbol.Type.ToTestDisplayString());
};
var compilationVerifier = CompileAndVerify(source: source, references: new[] { TargetFrameworkUtil.StandardCSharpReference, libAssemblyRef },
expectedOutput: "Print method ran.");
}
[Fact, WorkItem(7845, "https://github.com/dotnet/roslyn/issues/7845")]
public void EventFieldWithDynamicAttribute_IsLoadedAsDynamicViaCompilationRef()
{
var libText = @"
public class C
{
public event System.Action<dynamic> E1;
public void RaiseEvent() => E1(this);
public void Print() => System.Console.WriteLine(""Print method ran."");
}";
var libComp = CreateCompilation(libText);
var libCompRef = new CSharpCompilationReference(libComp);
var source = @"
class D
{
static void Main()
{
var c = new C();
c.E1 += f => f.Print();
c.RaiseEvent();
}
}";
var expectedOutput = "Print method ran.";
var compilationVerifier = CompileAndVerify(source: source,
references: new[] { libCompRef },
targetFramework: TargetFramework.StandardAndCSharp,
expectedOutput: expectedOutput);
}
[Fact, WorkItem(7845, "https://github.com/dotnet/roslyn/issues/7845")]
public void EventFieldWithDynamicAttribute_CanBeOverridden()
{
var libText = @"
public class C
{
public virtual event System.Action<dynamic> E1 { add { System.Console.WriteLine(""Not called""); } remove {} }
public virtual event System.Action<dynamic> E2 { add { System.Console.WriteLine(""Not called""); } remove {} }
public virtual event System.Action<object> E3 { add { System.Console.WriteLine(""Not called""); } remove {} }
}";
var libComp = CreateCompilation(source: libText);
var libAssemblyRef = libComp.EmitToImageReference();
var source = @"
class B : C
{
public override event System.Action<dynamic> E1;
public override event System.Action<object> E2;
public override event System.Action<dynamic> E3;
public void RaiseE1(object s) => E1(s);
public void RaiseE2(string s) => E2(s);
public void RaiseE3(string s) => E3(s);
}
class A
{
static void Main()
{
var b1 = new B();
b1.E1 += f => System.Console.WriteLine(f.Insert(0, ""Success1: ""));
b1.E2 += f => System.Console.WriteLine(""Success2"");
b1.E3 += f => System.Console.WriteLine(f.Insert(0, ""Success3: ""));
b1.RaiseE1(""Alice"");
b1.RaiseE2(""Bob"");
b1.RaiseE3(""Charlie"");
var b2 = new B();
b2.E1 += Print;
b2.E2 += Print;
b2.E3 += Print;
b2.RaiseE1(""Alice"");
b2.RaiseE2(""Bob"");
b2.RaiseE3(""Charlie"");
}
static void Print(object o) => System.Console.WriteLine(""Printed: "" + (System.String)o);
}";
var expectedOutput =
@"Success1: Alice
Success2
Success3: Charlie
Printed: Alice
Printed: Bob
Printed: Charlie
";
var compilationVerifier = CompileAndVerify(
source: source,
targetFramework: TargetFramework.StandardAndCSharp,
references: new[] { libAssemblyRef },
expectedOutput: expectedOutput);
}
[Fact, WorkItem(7845, "https://github.com/dotnet/roslyn/issues/7845")]
public void EventWithDynamicAttribute_OverriddenTypeDoesntLeak()
{
var libText = @"
public class CL1
{
public virtual event System.Action<dynamic> E1 { add {} remove {} }
public virtual event System.Action<dynamic> E2 { add {} remove {} }
}";
var libComp = CreateCompilation(source: libText);
var libAssemblyRef = libComp.EmitToImageReference();
var source = @"
public class CL2 : CL1
{
public override event System.Action<object> E1;
public override event System.Action<object> E2 { add {} remove {} }
}";
Action<ModuleSymbol> validator = module =>
{
var peModule = (PEModuleSymbol)module;
var type = peModule.GlobalNamespace.GetMember<NamedTypeSymbol>("CL2");
var e1 = type.GetMember<EventSymbol>("E1");
var e2 = type.GetMember<EventSymbol>("E2");
Assert.Equal("System.Action<System.Object>", e1.Type.ToTestDisplayString());
Assert.Equal("System.Action<System.Object>", e2.Type.ToTestDisplayString());
};
CompileAndVerify(source: source, references: new[] { libAssemblyRef }, symbolValidator: validator);
}
[Fact, WorkItem(7845, "https://github.com/dotnet/roslyn/issues/7845")]
public void EventFieldWithDynamicAttribute_OverriddenTypeDoesntLeak()
{
var libText = @"
public class CL1
{
public virtual event System.Action<dynamic> E1;
public virtual event System.Action<dynamic> E2;
}";
var libComp = CreateCompilation(source: libText);
var libAssemblyRef = libComp.EmitToImageReference();
var source = @"
public class CL2 : CL1
{
public override event System.Action<object> E1;
public override event System.Action<object> E2 { add {} remove {} }
}";
Action<ModuleSymbol> validator = module =>
{
var peModule = (PEModuleSymbol)module;
var type = peModule.GlobalNamespace.GetMember<NamedTypeSymbol>("CL2");
var e1 = type.GetMember<EventSymbol>("E1");
var e2 = type.GetMember<EventSymbol>("E2");
Assert.Equal("System.Action<System.Object>", e1.Type.ToTestDisplayString());
Assert.Equal("System.Action<System.Object>", e2.Type.ToTestDisplayString());
};
CompileAndVerify(source: source, references: new[] { libAssemblyRef }, symbolValidator: validator);
}
[Fact, WorkItem(7845, "https://github.com/dotnet/roslyn/issues/7845")]
public void EventWithoutDynamicAttributeFromLegacyCompiler()
{
#region IL for class C
// This is most of the IL generated by the native compiler (4.6) when compiling class C below:
// public class C
// {
// public event System.Action<dynamic> E;
// public void Raise() { E("Event raised"); }
// }
// The important thing here is that the .event doesn't have a DynamicAttribute, but the add and remove accessors do.
// Because of that the event will only be loaded as Action<object>, not Action<dynamic>
var ilSource = @"
.assembly extern System.Core
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.class public auto ansi beforefieldinit C
extends [mscorlib]System.Object
{
.field private class [mscorlib]System.Action`1<object> E
.custom instance void [System.Core]System.Runtime.CompilerServices.DynamicAttribute::.ctor(bool[]) = ( 01 00 02 00 00 00 00 01 00 00 )
.method public hidebysig specialname instance void
add_E(class [mscorlib]System.Action`1<object> 'value') cil managed
{
.param [1]
.custom instance void [System.Core]System.Runtime.CompilerServices.DynamicAttribute::.ctor(bool[]) = ( 01 00 02 00 00 00 00 01 00 00 )
// Code size 48 (0x30)
.maxstack 3
.locals init (class [mscorlib]System.Action`1<object> V_0,
class [mscorlib]System.Action`1<object> V_1,
class [mscorlib]System.Action`1<object> V_2,
bool V_3)
IL_0000: ldarg.0
IL_0001: ldfld class [mscorlib]System.Action`1<object> C::E
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: stloc.1
IL_0009: ldloc.1
IL_000a: ldarg.1
IL_000b: call class [mscorlib]System.Delegate [mscorlib]System.Delegate::Combine(class [mscorlib]System.Delegate,
class [mscorlib]System.Delegate)
IL_0010: castclass class [mscorlib]System.Action`1<object>
IL_0015: stloc.2
IL_0016: ldarg.0
IL_0017: ldflda class [mscorlib]System.Action`1<object> C::E
IL_001c: ldloc.2
IL_001d: ldloc.1
IL_001e: call !!0 [mscorlib]System.Threading.Interlocked::CompareExchange<class [mscorlib]System.Action`1<object>>(!!0&,
!!0,
!!0)
IL_0023: stloc.0
IL_0024: ldloc.0
IL_0025: ldloc.1
IL_0026: ceq
IL_0028: ldc.i4.0
IL_0029: ceq
IL_002b: stloc.3
IL_002c: ldloc.3
IL_002d: brtrue.s IL_0007
IL_002f: ret
} // end of method C::add_E
.method public hidebysig specialname instance void
remove_E(class [mscorlib]System.Action`1<object> 'value') cil managed
{
.param [1]
.custom instance void [System.Core]System.Runtime.CompilerServices.DynamicAttribute::.ctor(bool[]) = ( 01 00 02 00 00 00 00 01 00 00 )
// Code size 48 (0x30)
.maxstack 3
.locals init (class [mscorlib]System.Action`1<object> V_0,
class [mscorlib]System.Action`1<object> V_1,
class [mscorlib]System.Action`1<object> V_2,
bool V_3)
IL_0000: ldarg.0
IL_0001: ldfld class [mscorlib]System.Action`1<object> C::E
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: stloc.1
IL_0009: ldloc.1
IL_000a: ldarg.1
IL_000b: call class [mscorlib]System.Delegate [mscorlib]System.Delegate::Remove(class [mscorlib]System.Delegate,
class [mscorlib]System.Delegate)
IL_0010: castclass class [mscorlib]System.Action`1<object>
IL_0015: stloc.2
IL_0016: ldarg.0
IL_0017: ldflda class [mscorlib]System.Action`1<object> C::E
IL_001c: ldloc.2
IL_001d: ldloc.1
IL_001e: call !!0 [mscorlib]System.Threading.Interlocked::CompareExchange<class [mscorlib]System.Action`1<object>>(!!0&,
!!0,
!!0)
IL_0023: stloc.0
IL_0024: ldloc.0
IL_0025: ldloc.1
IL_0026: ceq
IL_0028: ldc.i4.0
IL_0029: ceq
IL_002b: stloc.3
IL_002c: ldloc.3
IL_002d: brtrue.s IL_0007
IL_002f: ret
} // end of method C::remove_E
.method public hidebysig instance void
Raise() cil managed
{
// Code size 19 (0x13)
.maxstack 8
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldfld class [mscorlib]System.Action`1<object> C::E
IL_0007: ldstr ""Event raised""
IL_000c: callvirt instance void class [mscorlib]
System.Action`1<object>::Invoke(!0)
IL_0011: nop
IL_0012: ret
} // end of method C::Raise
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]
System.Object::.ctor()
IL_0006: ret
} // end of method C::.ctor
.event class [mscorlib]
System.Action`1<object> E
{
.addon instance void C::add_E(class [mscorlib]
System.Action`1<object>)
.removeon instance void C::remove_E(class [mscorlib]
System.Action`1<object>)
} // end of event C::E
} // end of class C
";
#endregion
var source = @"
class D
{
static void Main()
{
C x = new C();
x.E += Print;
x.Raise();
}
static void Print(object o) {
System.Console.WriteLine(o.ToString());
}
}
";
var compVerifier = CompileAndVerify(source, new[] { TargetFrameworkUtil.StandardCSharpReference, CompileIL(ilSource) },
expectedOutput: "Event raised");
var comp = (CSharpCompilation)compVerifier.Compilation;
var classSymbol = (PENamedTypeSymbol)comp.GetTypeByMetadataName("C");
var eventSymbol = (PEEventSymbol)classSymbol.GetMember("E");
Assert.Equal("System.Action<System.Object>", eventSymbol.Type.ToTestDisplayString());
}
[Fact]
public void StaticEventDoesNotRequireInstanceReceiver()
{
var source = @"using System;
class C
{
public static event EventHandler E;
}";
var compilation = CreateCompilation(source).VerifyDiagnostics(
// (4,38): warning CS0067: The event 'C.E' is never used
// public static event EventHandler E;
Diagnostic(ErrorCode.WRN_UnreferencedEvent, "E").WithArguments("C.E").WithLocation(4, 38));
var eventSymbol = compilation.GetMember<EventSymbol>("C.E");
Assert.False(eventSymbol.RequiresInstanceReceiver);
}
[Fact]
public void InstanceEventRequiresInstanceReceiver()
{
var source = @"using System;
class C
{
public event EventHandler E;
}";
var compilation = CreateCompilation(source).VerifyDiagnostics(
// (4,31): warning CS0067: The event 'C.E' is never used
// public event EventHandler E;
Diagnostic(ErrorCode.WRN_UnreferencedEvent, "E").WithArguments("C.E").WithLocation(4, 31));
var eventSymbol = compilation.GetMember<EventSymbol>("C.E");
Assert.True(eventSymbol.RequiresInstanceReceiver);
}
#endregion
#region Error cases
[ConditionalFact(typeof(NoUsedAssembliesValidation))] // The test hook is blocked by https://github.com/dotnet/roslyn/issues/39979
[WorkItem(39979, "https://github.com/dotnet/roslyn/issues/39979")]
public void VoidEvent()
{
var text =
@"interface I
{
event void E;
}
class C
{
event void E;
}
";
CreateCompilation(text).VerifyDiagnostics(
// (3,11): error CS1547: Keyword 'void' cannot be used in this context
Diagnostic(ErrorCode.ERR_NoVoidHere, "void"),
// (7,11): error CS1547: Keyword 'void' cannot be used in this context
Diagnostic(ErrorCode.ERR_NoVoidHere, "void"),
//CONSIDER: it would be nice to suppress these
// (7,11): error CS0670: Field cannot have void type
Diagnostic(ErrorCode.ERR_FieldCantHaveVoidType, "void"),
// (7,16): warning CS0067: The event 'C.E' is never used
// event void E;
Diagnostic(ErrorCode.WRN_UnreferencedEvent, "E").WithArguments("C.E"));
}
[Fact]
public void Assignment()
{
var text = @"
class DeclaringType
{
public event System.Action<int> e { add { } remove { } }
public event System.Action<int> f;
void Method()
{
e = null; //CS0079
f = null; //fine
}
}
class OtherType
{
void Method()
{
DeclaringType d = new DeclaringType();
d.e = null; //CS0079
d.f = null; //CS0070
}
}
";
CreateCompilation(text).VerifyDiagnostics(
// (9,9): error CS0079: The event 'DeclaringType.e' can only appear on the left hand side of += or -=
// e = null; //CS0079
Diagnostic(ErrorCode.ERR_BadEventUsageNoField, "e").WithArguments("DeclaringType.e"),
// (19,11): error CS0079: The event 'DeclaringType.e' can only appear on the left hand side of += or -=
// d.e = null; //CS0079
Diagnostic(ErrorCode.ERR_BadEventUsageNoField, "e").WithArguments("DeclaringType.e"),
// (20,11): error CS0070: The event 'DeclaringType.f' can only appear on the left hand side of += or -= (except when used from within the type 'DeclaringType')
// d.f = null; //CS0070
Diagnostic(ErrorCode.ERR_BadEventUsage, "f").WithArguments("DeclaringType.f", "DeclaringType"));
}
[Fact]
public void Overriding()
{
var text = @"
using System;
class C
{
static void Main() { }
public virtual event Action<int> e
{
add { }
remove { }
}
public virtual event Action<int> f;
void Goo()
{
e = null; //CS0079
f = null; //fine
}
}
class D : C
{
public override event Action<int> e;
public override event Action<int> f
{
add { }
remove { }
}
void Goo()
{
e = null; //fine
f = null; //CS0070 (since the least-overridden event is field-like)
}
}
class E : D
{
public sealed override event Action<int> e
{
add { }
remove { }
}
public sealed override event Action<int> f;
void Goo()
{
e = null; //CS0079
f = null; //fine
}
}
";
CreateCompilation(text).VerifyDiagnostics(
// (17,9): error CS0079: The event 'C.e' can only appear on the left hand side of += or -=
// e = null; //CS0079
Diagnostic(ErrorCode.ERR_BadEventUsageNoField, "e").WithArguments("C.e"),
// (34,9): error CS0070: The event 'C.f' can only appear on the left hand side of += or -= (except when used from within the type 'C')
// f = null; //CS0070 (since the least-overridden event is field-like)
Diagnostic(ErrorCode.ERR_BadEventUsage, "f").WithArguments("C.f", "C"),
// (49,9): error CS0079: The event 'C.e' can only appear on the left hand side of += or -=
// e = null; //CS0079
Diagnostic(ErrorCode.ERR_BadEventUsageNoField, "e").WithArguments("C.e"),
// (24,39): warning CS0414: The field 'D.e' is assigned but its value is never used
// public override event Action<int> e;
Diagnostic(ErrorCode.WRN_UnreferencedFieldAssg, "e").WithArguments("D.e"),
// (45,46): warning CS0414: The field 'E.f' is assigned but its value is never used
// public sealed override event Action<int> f;
Diagnostic(ErrorCode.WRN_UnreferencedFieldAssg, "f").WithArguments("E.f"),
// (13,38): warning CS0414: The field 'C.f' is assigned but its value is never used
// public virtual event Action<int> f;
Diagnostic(ErrorCode.WRN_UnreferencedFieldAssg, "f").WithArguments("C.f"));
}
[Fact]
public void EventAccessibility()
{
var text = @"
class C
{
private event System.Action e1;
protected event System.Action e2;
internal event System.Action e3;
protected internal event System.Action e4;
public event System.Action e5;
private event System.Action f1 { add { } remove { } }
protected event System.Action f2 { add { } remove { } }
internal event System.Action f3 { add { } remove { } }
protected internal event System.Action f4 { add { } remove { } }
public event System.Action f5 { add { } remove { } }
}
class D
{
void Goo(C c)
{
c.e1 = null; //CS0122
c.e2 = null; //CS0122
c.e3 = null; //CS0070
c.e4 = null; //CS0070
c.e5 = null; //CS0070
c.f1 = null; //CS0122 (Dev10 also reports CS0079)
c.f2 = null; //CS0122 (Dev10 also reports CS0079)
c.f3 = null; //CS0079
c.f4 = null; //CS0079
c.f5 = null; //CS0079
}
}
";
CreateCompilation(text).VerifyDiagnostics(
// (21,11): error CS0122: 'C.e1' is inaccessible due to its protection level
// c.e1 = null; //CS0122
Diagnostic(ErrorCode.ERR_BadAccess, "e1").WithArguments("C.e1"),
// (22,11): error CS0122: 'C.e2' is inaccessible due to its protection level
// c.e2 = null; //CS0122
Diagnostic(ErrorCode.ERR_BadAccess, "e2").WithArguments("C.e2"),
// (23,11): error CS0070: The event 'C.e3' can only appear on the left hand side of += or -= (except when used from within the type 'C')
// c.e3 = null; //CS0070
Diagnostic(ErrorCode.ERR_BadEventUsage, "e3").WithArguments("C.e3", "C"),
// (24,11): error CS0070: The event 'C.e4' can only appear on the left hand side of += or -= (except when used from within the type 'C')
// c.e4 = null; //CS0070
Diagnostic(ErrorCode.ERR_BadEventUsage, "e4").WithArguments("C.e4", "C"),
// (25,11): error CS0070: The event 'C.e5' can only appear on the left hand side of += or -= (except when used from within the type 'C')
// c.e5 = null; //CS0070
Diagnostic(ErrorCode.ERR_BadEventUsage, "e5").WithArguments("C.e5", "C"),
// (27,11): error CS0122: 'C.f1' is inaccessible due to its protection level
// c.f1 = null; //CS0122 (Dev10 also reports CS0079)
Diagnostic(ErrorCode.ERR_BadAccess, "f1").WithArguments("C.f1"),
// (28,11): error CS0122: 'C.f2' is inaccessible due to its protection level
// c.f2 = null; //CS0122 (Dev10 also reports CS0079)
Diagnostic(ErrorCode.ERR_BadAccess, "f2").WithArguments("C.f2"),
// (29,11): error CS0079: The event 'C.f3' can only appear on the left hand side of += or -=
// c.f3 = null; //CS0079
Diagnostic(ErrorCode.ERR_BadEventUsageNoField, "f3").WithArguments("C.f3"),
// (30,11): error CS0079: The event 'C.f4' can only appear on the left hand side of += or -=
// c.f4 = null; //CS0079
Diagnostic(ErrorCode.ERR_BadEventUsageNoField, "f4").WithArguments("C.f4"),
// (31,11): error CS0079: The event 'C.f5' can only appear on the left hand side of += or -=
// c.f5 = null; //CS0079
Diagnostic(ErrorCode.ERR_BadEventUsageNoField, "f5").WithArguments("C.f5"),
// (4,33): warning CS0067: The event 'C.e1' is never used
// private event System.Action e1;
Diagnostic(ErrorCode.WRN_UnreferencedEvent, "e1").WithArguments("C.e1"),
// (5,35): warning CS0067: The event 'C.e2' is never used
// protected event System.Action e2;
Diagnostic(ErrorCode.WRN_UnreferencedEvent, "e2").WithArguments("C.e2"));
}
/// <summary>
/// Even though the raise accessor is part of the event in metadata, it
/// is just another method in C#.
/// </summary>
[Fact]
public void InterfaceRaiseAccessor()
{
var ilSource = @"
.class interface public abstract auto ansi Interface
{
.method public hidebysig newslot specialname abstract virtual instance void
add_e(class [mscorlib]System.Action 'value') cil managed
{
}
.method public hidebysig newslot specialname abstract virtual instance void
remove_e(class [mscorlib]System.Action 'value') cil managed
{
}
.method public hidebysig newslot specialname abstract virtual instance void
raise_e(object sender, object e) cil managed
{
}
.event [mscorlib]System.Action e
{
.addon instance void Interface::add_e(class [mscorlib]System.Action)
.removeon instance void Interface::remove_e(class [mscorlib]System.Action)
.fire instance void Interface::raise_e(object, object)
} // end of event Interface::e
} // end of class Interface
";
var csharpSource = @"
class C : Interface
{
// not implementing event or raise (separate error for each)
}
class D : Interface
{
public event System.Action e;
// not implementing raise (error)
}
class E : Interface
{
public event System.Action e;
public void raise_e(object sender, object e) { }
}
";
CreateCompilationWithILAndMscorlib40(csharpSource, ilSource).VerifyDiagnostics(
// (2,7): error CS0535: 'C' does not implement interface member 'Interface.raise_e(object, object)'
// class C : Interface
Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "Interface").WithArguments("C", "Interface.raise_e(object, object)"),
// (2,7): error CS0535: 'C' does not implement interface member 'Interface.e'
// class C : Interface
Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "Interface").WithArguments("C", "Interface.e"),
// (7,7): error CS0535: 'D' does not implement interface member 'Interface.raise_e(object, object)'
// class D : Interface
Diagnostic(ErrorCode.ERR_UnimplementedInterfaceMember, "Interface").WithArguments("D", "Interface.raise_e(object, object)"),
// (15,32): warning CS0067: The event 'E.e' is never used
// public event System.Action e;
Diagnostic(ErrorCode.WRN_UnreferencedEvent, "e").WithArguments("E.e"),
// (9,32): warning CS0067: The event 'D.e' is never used
// public event System.Action e;
Diagnostic(ErrorCode.WRN_UnreferencedEvent, "e").WithArguments("D.e"));
}
[WorkItem(541704, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/541704")]
[Fact]
public void OperationsInDeclaringType()
{
var text = @"
class C
{
event System.Action E;
event System.Action F { add { } remove { } }
void Method(ref System.Action a)
{
E = a;
E += a;
a = E;
Method(ref E);
E.Invoke();
bool b1 = E is System.Action;
E++; //CS0023
E |= true; //CS0019 (Dev10 also reports CS0029)
F = a; //CS0079
F += a;
a = F; //CS0079
Method(ref F); //CS0079
F.Invoke(); //CS0079
bool b2 = F is System.Action; //CS0079
F++; //CS0079
F |= true; //CS0079
}
}
";
CreateCompilation(text).VerifyDiagnostics(
// (15,9): error CS0023: Operator '++' cannot be applied to operand of type 'System.Action'
// E++; //CS0023
Diagnostic(ErrorCode.ERR_BadUnaryOp, "E++").WithArguments("++", "System.Action"),
// (16,9): error CS0019: Operator '|=' cannot be applied to operands of type 'System.Action' and 'bool'
// E |= true; //CS0019 (Dev10 also reports CS0029)
Diagnostic(ErrorCode.ERR_BadBinaryOps, "E |= true").WithArguments("|=", "System.Action", "bool"),
// (18,9): error CS0079: The event 'C.F' can only appear on the left hand side of += or -=
// F = a; //CS0079
Diagnostic(ErrorCode.ERR_BadEventUsageNoField, "F").WithArguments("C.F"),
// (20,13): error CS0079: The event 'C.F' can only appear on the left hand side of += or -=
// a = F; //CS0079
Diagnostic(ErrorCode.ERR_BadEventUsageNoField, "F").WithArguments("C.F"),
// (21,20): error CS0079: The event 'C.F' can only appear on the left hand side of += or -=
// Method(ref F); //CS0079
Diagnostic(ErrorCode.ERR_BadEventUsageNoField, "F").WithArguments("C.F"),
// (22,9): error CS0079: The event 'C.F' can only appear on the left hand side of += or -=
// F.Invoke(); //CS0079
Diagnostic(ErrorCode.ERR_BadEventUsageNoField, "F").WithArguments("C.F"),
// (23,19): error CS0079: The event 'C.F' can only appear on the left hand side of += or -=
// bool b2 = F is System.Action; //CS0079
Diagnostic(ErrorCode.ERR_BadEventUsageNoField, "F").WithArguments("C.F"),
// (24,9): error CS0079: The event 'C.F' can only appear on the left hand side of += or -=
// F++; //CS0079
Diagnostic(ErrorCode.ERR_BadEventUsageNoField, "F").WithArguments("C.F"),
// (25,9): error CS0079: The event 'C.F' can only appear on the left hand side of += or -=
// F |= true; //CS0079
Diagnostic(ErrorCode.ERR_BadEventUsageNoField, "F").WithArguments("C.F"));
}
[Fact]
public void OperationsInNonDeclaringType()
{
var text = @"
class C
{
public event System.Action E;
public event System.Action F { add { } remove { } }
}
class D
{
void Method(ref System.Action a, C c)
{
c.E = a; //CS0070
c.E += a;
a = c.E; //CS0070
Method(ref c.E, c); //CS0070
c.E.Invoke(); //CS0070
bool b1 = c.E is System.Action; //CS0070
c.E++; //CS0070
c.E |= true; //CS0070
c.F = a; //CS0079
c.F += a;
a = c.F; //CS0079
Method(ref c.F, c); //CS0079
c.F.Invoke(); //CS0079
bool b2 = c.F is System.Action; //CS0079
c.F++; //CS0079
c.F |= true; //CS0079
}
}
";
CreateCompilation(text).VerifyDiagnostics(
// (12,11): error CS0070: The event 'C.E' can only appear on the left hand side of += or -= (except when used from within the type 'C')
// c.E = a; //CS0070
Diagnostic(ErrorCode.ERR_BadEventUsage, "E").WithArguments("C.E", "C"),
// (14,15): error CS0070: The event 'C.E' can only appear on the left hand side of += or -= (except when used from within the type 'C')
// a = c.E; //CS0070
Diagnostic(ErrorCode.ERR_BadEventUsage, "E").WithArguments("C.E", "C"),
// (15,22): error CS0070: The event 'C.E' can only appear on the left hand side of += or -= (except when used from within the type 'C')
// Method(ref c.E, c); //CS0070
Diagnostic(ErrorCode.ERR_BadEventUsage, "E").WithArguments("C.E", "C"),
// (16,11): error CS0070: The event 'C.E' can only appear on the left hand side of += or -= (except when used from within the type 'C')
// c.E.Invoke(); //CS0070
Diagnostic(ErrorCode.ERR_BadEventUsage, "E").WithArguments("C.E", "C"),
// (17,21): error CS0070: The event 'C.E' can only appear on the left hand side of += or -= (except when used from within the type 'C')
// bool b1 = c.E is System.Action; //CS0070
Diagnostic(ErrorCode.ERR_BadEventUsage, "E").WithArguments("C.E", "C"),
// (18,11): error CS0070: The event 'C.E' can only appear on the left hand side of += or -= (except when used from within the type 'C')
// c.E++; //CS0070
Diagnostic(ErrorCode.ERR_BadEventUsage, "E").WithArguments("C.E", "C"),
// (19,11): error CS0070: The event 'C.E' can only appear on the left hand side of += or -= (except when used from within the type 'C')
// c.E |= true; //CS0070
Diagnostic(ErrorCode.ERR_BadEventUsage, "E").WithArguments("C.E", "C"),
// (21,11): error CS0079: The event 'C.F' can only appear on the left hand side of += or -=
// c.F = a; //CS0079
Diagnostic(ErrorCode.ERR_BadEventUsageNoField, "F").WithArguments("C.F"),
// (23,15): error CS0079: The event 'C.F' can only appear on the left hand side of += or -=
// a = c.F; //CS0079
Diagnostic(ErrorCode.ERR_BadEventUsageNoField, "F").WithArguments("C.F"),
// (24,22): error CS0079: The event 'C.F' can only appear on the left hand side of += or -=
// Method(ref c.F, c); //CS0079
Diagnostic(ErrorCode.ERR_BadEventUsageNoField, "F").WithArguments("C.F"),
// (25,11): error CS0079: The event 'C.F' can only appear on the left hand side of += or -=
// c.F.Invoke(); //CS0079
Diagnostic(ErrorCode.ERR_BadEventUsageNoField, "F").WithArguments("C.F"),
// (26,21): error CS0079: The event 'C.F' can only appear on the left hand side of += or -=
// bool b2 = c.F is System.Action; //CS0079
Diagnostic(ErrorCode.ERR_BadEventUsageNoField, "F").WithArguments("C.F"),
// (27,11): error CS0079: The event 'C.F' can only appear on the left hand side of += or -=
// c.F++; //CS0079
Diagnostic(ErrorCode.ERR_BadEventUsageNoField, "F").WithArguments("C.F"),
// (28,11): error CS0079: The event 'C.F' can only appear on the left hand side of += or -=
// c.F |= true; //CS0079
Diagnostic(ErrorCode.ERR_BadEventUsageNoField, "F").WithArguments("C.F"));
}
[Fact]
public void ConversionFails()
{
var text = @"
class C
{
event System.Action E;
event System.Action F { add { } remove { } }
void Method()
{
E += x => { };
F += new System.Action<int>(x => {});
}
}
";
CreateCompilation(text).VerifyDiagnostics(
// (9,9): error CS1593: Delegate 'System.Action' does not take 1 arguments
// E += x => { };
Diagnostic(ErrorCode.ERR_BadDelArgCount, "E += x => { }").WithArguments("System.Action", "1"),
// (10,9): error CS0029: Cannot implicitly convert type 'System.Action<int>' to 'System.Action'
// F += new System.Action<int>(x => {});
Diagnostic(ErrorCode.ERR_NoImplicitConv, "F += new System.Action<int>(x => {})").WithArguments("System.Action<int>", "System.Action"),
// (4,25): warning CS0067: The event 'C.E' is never used
// event System.Action E;
Diagnostic(ErrorCode.WRN_UnreferencedEvent, "E").WithArguments("C.E"));
}
[Fact]
public void StructEvent1()
{
var text = @"
struct S
{
event System.Action E;
event System.Action F { add { } remove { } }
S(int unused) : this()
{
}
S(int unused1, int unused2)
{
// CS0171: E not initialized before C# 11
// No error for F
}
S This { get { return this; } }
void Method(S s)
{
s.E = null; //fine, since receiver is a variable
This.E = null; //CS1612: receiver is not a variable
}
}
";
CreateCompilation(text, parseOptions: TestOptions.Regular10).VerifyDiagnostics(
// (11,5): error CS0171: Field 'S.E' must be fully assigned before control is returned to the caller. Consider updating to language version '11.0' to auto-default the field.
// S(int unused1, int unused2)
Diagnostic(ErrorCode.ERR_UnassignedThisUnsupportedVersion, "S").WithArguments("S.E", "11.0").WithLocation(11, 5),
// (22,9): error CS1612: Cannot modify the return value of 'S.This' because it is not a variable
// This.E = null; //CS1612: receiver is not a variable
Diagnostic(ErrorCode.ERR_ReturnNotLValue, "This").WithArguments("S.This").WithLocation(22, 9));
CreateCompilation(text, parseOptions: TestOptions.Regular11).VerifyDiagnostics(
// (22,9): error CS1612: Cannot modify the return value of 'S.This' because it is not a variable
// This.E = null; //CS1612: receiver is not a variable
Diagnostic(ErrorCode.ERR_ReturnNotLValue, "This").WithArguments("S.This").WithLocation(22, 9));
}
[WorkItem(546356, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546356")]
[Fact]
public void StructEvent2()
{
var source = @"
using System;
struct S
{
event Action E;
int P { get; set; }
static S Make()
{
return new S();
}
static void Main()
{
Make().E += () => {}; // fine
Make().P += 1; // CS1612
}
}
";
CreateCompilation(source).VerifyDiagnostics(
// (17,9): error CS1612: Cannot modify the return value of 'S.Make()' because it is not a variable
// Make().P += 1; // CS1612
Diagnostic(ErrorCode.ERR_ReturnNotLValue, "Make()").WithArguments("S.Make()"),
// (6,18): warning CS0067: The event 'S.E' is never used
// event Action E;
Diagnostic(ErrorCode.WRN_UnreferencedEvent, "E").WithArguments("S.E"));
}
[WorkItem(546356, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/546356")]
[Fact]
public void StructEvent3()
{
var source = @"
struct S
{
event System.Action E;
event System.Action F { add { } remove { } }
S Property { get { return this; } }
S Method() { return this; }
void Method(S parameter)
{
Property.E = null; //CS1612
Method().E = null; //CS1612
parameter.E = null;
Property.E += null;
Method().E += null;
parameter.E += null;
Property.F += null;
Method().F += null;
parameter.F += null;
}
}
";
CreateCompilation(source).VerifyDiagnostics(
// (12,9): error CS1612: Cannot modify the return value of 'S.Property' because it is not a variable
// Property.E = null;
Diagnostic(ErrorCode.ERR_ReturnNotLValue, "Property").WithArguments("S.Property"),
// (13,9): error CS1612: Cannot modify the return value of 'S.Method()' because it is not a variable
// Method().E = null;
Diagnostic(ErrorCode.ERR_ReturnNotLValue, "Method()").WithArguments("S.Method()"));
}
// CONSIDER: it would be nice to test this scenario with an event from metadata,
// but ilasm won't accept and event without both add and remove.
[Fact]
public void UseMissingAccessor()
{
var text = @"
class C
{
event System.Action E { remove { } } //CS0065
void Goo()
{
E += null; //no separate error
}
}
";
var expected = new[] {
// (4,25): error CS0065: 'C.E': event property must have both add and remove accessors
// event System.Action E { remove { } }
Diagnostic(ErrorCode.ERR_EventNeedsBothAccessors, "E").WithArguments("C.E")
};
CreateCompilation(text).VerifyDiagnostics(expected).VerifyEmitDiagnostics(expected);
CreateCompilation(text).VerifyEmitDiagnostics(expected);
}
[WorkItem(542570, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542570")]
[Fact]
public void UseMissingAccessorInInterface()
{
var text = @"
delegate void myDelegate(int name = 1);
interface i1
{
event myDelegate myevent { }
}
";
CreateCompilation(text).VerifyDiagnostics(
Diagnostic(ErrorCode.ERR_EventNeedsBothAccessors, "myevent").WithArguments("i1.myevent"));
}
[ClrOnlyFact(ClrOnlyReason.Ilasm)]
public void CS1545ERR_BindToBogusProp2_AccessorSignatureMismatch()
{
var ilSource = @"
.class public auto ansi beforefieldinit Base
extends [mscorlib]System.Object
{
.method public hidebysig newslot specialname virtual instance void
WithModopt(class [mscorlib]System.Action`1<int32 modopt(int32) []> 'value') cil managed
{
ret
}
.method public hidebysig newslot specialname virtual instance void
WithoutModopt(class [mscorlib]System.Action`1<int32[]> 'value') cil managed
{
ret
}
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
ldarg.0
call instance void [mscorlib]System.Object::.ctor()
ret
}
// E: Y / A: Y / R: Y
.event class [mscorlib]System.Action`1<int32 modopt(int32) []> Event7
{
.addon instance void Base::WithModopt(class [mscorlib]System.Action`1<int32 modopt(int32) []>)
.removeon instance void Base::WithModopt(class [mscorlib]System.Action`1<int32 modopt(int32) []>)
} // end of event Base::Event1
// E: Y / A: Y / R: N
.event class [mscorlib]System.Action`1<int32 modopt(int32) []> Event6
{
.addon instance void Base::WithModopt(class [mscorlib]System.Action`1<int32 modopt(int32) []>)
.removeon instance void Base::WithoutModopt(class [mscorlib]System.Action`1<int32[]>)
} // end of event Base::Event1
// E: Y / A: N / R: Y
.event class [mscorlib]System.Action`1<int32 modopt(int32) []> Event5
{
.addon instance void Base::WithoutModopt(class [mscorlib]System.Action`1<int32[]>)
.removeon instance void Base::WithModopt(class [mscorlib]System.Action`1<int32 modopt(int32) []>)
} // end of event Base::Event1
// E: Y / A: N / R: N
.event class [mscorlib]System.Action`1<int32 modopt(int32) []> Event4
{
.addon instance void Base::WithoutModopt(class [mscorlib]System.Action`1<int32[]>)
.removeon instance void Base::WithoutModopt(class [mscorlib]System.Action`1<int32[]>)
} // end of event Base::Event1
// E: N / A: Y / R: Y
.event class [mscorlib]System.Action`1<int32[]> Event3
{
.addon instance void Base::WithModopt(class [mscorlib]System.Action`1<int32 modopt(int32) []>)
.removeon instance void Base::WithModopt(class [mscorlib]System.Action`1<int32 modopt(int32) []>)
} // end of event Base::Event1
// E: N / A: Y / R: N
.event class [mscorlib]System.Action`1<int32[]> Event2
{
.addon instance void Base::WithModopt(class [mscorlib]System.Action`1<int32 modopt(int32) []>)
.removeon instance void Base::WithoutModopt(class [mscorlib]System.Action`1<int32[]>)
} // end of event Base::Event1
// E: N / A: N / R: Y
.event class [mscorlib]System.Action`1<int32[]> Event1
{
.addon instance void Base::WithoutModopt(class [mscorlib]System.Action`1<int32[]>)
.removeon instance void Base::WithModopt(class [mscorlib]System.Action`1<int32 modopt(int32) []>)
} // end of event Base::Event1
// E: N / A: N / R: N
.event class [mscorlib]System.Action`1<int32[]> Event0
{
.addon instance void Base::WithoutModopt(class [mscorlib]System.Action`1<int32[]>)
.removeon instance void Base::WithoutModopt(class [mscorlib]System.Action`1<int32[]>)
} // end of event Base::Event1
} // end of class Base
";
var csharpSource = @"
class C
{
void Method(Base b)
{
b.Event0 += null; //fine
b.Event1 += null;
b.Event2 += null;
b.Event3 += null;
b.Event4 += null;
b.Event5 += null;
b.Event6 += null;
b.Event7 += null; //fine
}
}
";
CreateCompilationWithILAndMscorlib40(csharpSource, ilSource).VerifyDiagnostics(
// (7,11): error CS1545: Property, indexer, or event 'Base.Event1' is not supported by the language; try directly calling accessor methods 'Base.Event0.add' or 'Base.Event7.add'
// b.Event1 += null;
Diagnostic(ErrorCode.ERR_BindToBogusProp2, "Event1").WithArguments("Base.Event1", "Base.Event0.add", "Base.Event7.add"),
// (8,11): error CS1545: Property, indexer, or event 'Base.Event2' is not supported by the language; try directly calling accessor methods 'Base.Event7.add' or 'Base.Event0.add'
// b.Event2 += null;
Diagnostic(ErrorCode.ERR_BindToBogusProp2, "Event2").WithArguments("Base.Event2", "Base.Event7.add", "Base.Event0.add"),
// (9,11): error CS1545: Property, indexer, or event 'Base.Event3' is not supported by the language; try directly calling accessor methods 'Base.Event7.add' or 'Base.Event7.add'
// b.Event3 += null;
Diagnostic(ErrorCode.ERR_BindToBogusProp2, "Event3").WithArguments("Base.Event3", "Base.Event7.add", "Base.Event7.add"),
// (10,11): error CS1545: Property, indexer, or event 'Base.Event4' is not supported by the language; try directly calling accessor methods 'Base.Event0.add' or 'Base.Event0.add'
// b.Event4 += null;
Diagnostic(ErrorCode.ERR_BindToBogusProp2, "Event4").WithArguments("Base.Event4", "Base.Event0.add", "Base.Event0.add"),
// (11,11): error CS1545: Property, indexer, or event 'Base.Event5' is not supported by the language; try directly calling accessor methods 'Base.Event0.add' or 'Base.Event7.add'
// b.Event5 += null;
Diagnostic(ErrorCode.ERR_BindToBogusProp2, "Event5").WithArguments("Base.Event5", "Base.Event0.add", "Base.Event7.add"),
// (12,11): error CS1545: Property, indexer, or event 'Base.Event6' is not supported by the language; try directly calling accessor methods 'Base.Event7.add' or 'Base.Event0.add'
// b.Event6 += null;
Diagnostic(ErrorCode.ERR_BindToBogusProp2, "Event6").WithArguments("Base.Event6", "Base.Event7.add", "Base.Event0.add"));
}
[ClrOnlyFact(ClrOnlyReason.Ilasm)]
public void CallAccessorsDirectly()
{
var ilSource = @"
.class public auto ansi beforefieldinit Base
extends [mscorlib]System.Object
{
.method public hidebysig newslot specialname virtual instance void
add_Event1(class [mscorlib]System.Action`1<int32[]> 'value') cil managed
{
ret
}
.method public hidebysig newslot specialname virtual instance void
remove_Event1(class [mscorlib]System.Action`1<int32[]> 'value') cil managed
{
ret
}
.method public hidebysig newslot specialname virtual instance void
add_Event2(class [mscorlib]System.Action`1<int32[]> 'value') cil managed
{
ret
}
.method public hidebysig newslot specialname virtual instance void
remove_Event2(class [mscorlib]System.Action`1<int32[]> 'value') cil managed
{
ret
}
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
ldarg.0
call instance void [mscorlib]System.Object::.ctor()
ret
}
// Accessors are missing modopt
.event class [mscorlib]System.Action`1<int32 modopt(int32) []> Event1
{
.addon instance void Base::add_Event1(class [mscorlib]System.Action`1<int32[]>)
.removeon instance void Base::remove_Event1(class [mscorlib]System.Action`1<int32[]>)
} // end of event Base::Event1
// Accessors are fine
.event class [mscorlib]System.Action`1<int32[]> Event2
{
.addon instance void Base::add_Event2(class [mscorlib]System.Action`1<int32[]>)
.removeon instance void Base::remove_Event2(class [mscorlib]System.Action`1<int32[]>)
} // end of event Base::Event2
} // end of class Base
";
var csharpSource = @"
class C
{
void Method(Base b)
{
b.add_Event1(null); //fine, since event is bogus
b.add_Event2(null); //CS0571 - can't call directly - use event accessor
}
}
";
CreateCompilationWithILAndMscorlib40(csharpSource, ilSource).VerifyDiagnostics(
// (7,11): error CS0571: 'Base.Event2.add': cannot explicitly call operator or accessor
// b.add_Event2(null);
Diagnostic(ErrorCode.ERR_CantCallSpecialMethod, "add_Event2").WithArguments("Base.Event2.add"));
}
[Fact]
public void BogusAccessorSignatures()
{
var ilSource = @"
.class public auto ansi beforefieldinit Base
extends [mscorlib]System.Object
{
.method public hidebysig newslot specialname virtual instance void
remove_Event(class [mscorlib]System.Action`1<int32> 'value') cil managed
{
ret
}
.method public hidebysig newslot specialname virtual instance void
add_Event1(class [mscorlib]System.Action 'value') cil managed
{
ret
}
.method public hidebysig newslot specialname virtual instance void
add_Event2(class [mscorlib]System.Action`1<int64> 'value') cil managed
{
ret
}
.method public hidebysig newslot specialname virtual instance void
add_Event3(class [mscorlib]System.Action`1<int32> 'value', int32 'extra') cil managed
{
ret
}
.method public hidebysig newslot specialname virtual instance int32
add_Event4(class [mscorlib]System.Action`1<int32> 'value') cil managed
{
ldc.i4.0
ret
}
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
ldarg.0
call instance void [mscorlib]System.Object::.ctor()
ret
}
// Adder has different type
.event class [mscorlib]System.Action`1<int32> Event1
{
.addon instance void Base::add_Event1(class [mscorlib]System.Action)
.removeon instance void Base::remove_Event(class [mscorlib]System.Action`1<int32>)
} // end of event Base::Event1
// Adder has different type arg
.event class [mscorlib]System.Action`1<int32> Event2
{
.addon instance void Base::add_Event2(class [mscorlib]System.Action`1<int64>)
.removeon instance void Base::remove_Event(class [mscorlib]System.Action`1<int32>)
} // end of event Base::Event2
// Adder has an extra parameter
.event class [mscorlib]System.Action`1<int32> Event3
{
.addon instance void Base::add_Event3(class [mscorlib]System.Action`1<int32>, int32)
.removeon instance void Base::remove_Event(class [mscorlib]System.Action`1<int32>)
} // end of event Base::Event3
// Adder has a return type
.event class [mscorlib]System.Action`1<int32> Event4
{
.addon instance int32 Base::add_Event4(class [mscorlib]System.Action`1<int32>)
.removeon instance void Base::remove_Event(class [mscorlib]System.Action`1<int32>)
} // end of event Base::Event4
} // end of class Base
";
var csharpSource = @"
class C
{
void Method(Base b)
{
b.Event1 += null;
b.Event2 += null;
b.Event3 += null;
b.Event4 += null;
}
}
";
CreateCompilationWithILAndMscorlib40(csharpSource, ilSource).VerifyDiagnostics(
// (6,11): error CS1545: Property, indexer, or event 'Base.Event1' is not supported by the language; try directly calling accessor methods 'Base.add_Event1(System.Action)' or 'Base.remove_Event(System.Action<int>)'
// b.Event1 += null;
Diagnostic(ErrorCode.ERR_BindToBogusProp2, "Event1").WithArguments("Base.Event1", "Base.add_Event1(System.Action)", "Base.remove_Event(System.Action<int>)"),
// (7,11): error CS1545: Property, indexer, or event 'Base.Event2' is not supported by the language; try directly calling accessor methods 'Base.add_Event2(System.Action<long>)' or 'Base.remove_Event(System.Action<int>)'
// b.Event2 += null;
Diagnostic(ErrorCode.ERR_BindToBogusProp2, "Event2").WithArguments("Base.Event2", "Base.add_Event2(System.Action<long>)", "Base.remove_Event(System.Action<int>)"),
// (8,11): error CS1545: Property, indexer, or event 'Base.Event3' is not supported by the language; try directly calling accessor methods 'Base.add_Event3(System.Action<int>, int)' or 'Base.remove_Event(System.Action<int>)'
// b.Event3 += null;
Diagnostic(ErrorCode.ERR_BindToBogusProp2, "Event3").WithArguments("Base.Event3", "Base.add_Event3(System.Action<int>, int)", "Base.remove_Event(System.Action<int>)"),
// (9,11): error CS1545: Property, indexer, or event 'Base.Event4' is not supported by the language; try directly calling accessor methods 'Base.add_Event4(System.Action<int>)' or 'Base.remove_Event(System.Action<int>)'
// b.Event4 += null;
Diagnostic(ErrorCode.ERR_BindToBogusProp2, "Event4").WithArguments("Base.Event4", "Base.add_Event4(System.Action<int>)", "Base.remove_Event(System.Action<int>)"));
}
[Fact]
public void InaccessibleAccessor()
{
var ilSource = @"
.class public auto ansi beforefieldinit Base
extends [mscorlib]System.Object
{
.method public hidebysig newslot specialname virtual instance void
remove_Event(class [mscorlib]System.Action`1<int32> 'value') cil managed
{
ret
}
.method private hidebysig newslot specialname virtual instance void
add_Event1(class [mscorlib]System.Action`1<int32> 'value') cil managed
{
ret
}
.method family hidebysig newslot specialname virtual instance void
add_Event2(class [mscorlib]System.Action`1<int32> 'value') cil managed
{
ret
}
.method assembly hidebysig newslot specialname virtual instance void
add_Event3(class [mscorlib]System.Action`1<int32> 'value') cil managed
{
ret
}
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
ldarg.0
call instance void [mscorlib]System.Object::.ctor()
ret
}
.event class [mscorlib]System.Action`1<int32> Event1
{
.addon instance void Base::add_Event1(class [mscorlib]System.Action`1<int32>)
.removeon instance void Base::remove_Event(class [mscorlib]System.Action`1<int32>)
} // end of event Base::Event1
.event class [mscorlib]System.Action`1<int32> Event2
{
.addon instance void Base::add_Event2(class [mscorlib]System.Action`1<int32>)
.removeon instance void Base::remove_Event(class [mscorlib]System.Action`1<int32>)
} // end of event Base::Event2
.event class [mscorlib]System.Action`1<int32> Event3
{
.addon instance void Base::add_Event3(class [mscorlib]System.Action`1<int32>)
.removeon instance void Base::remove_Event(class [mscorlib]System.Action`1<int32>)
} // end of event Base::Event3
} // end of class Base
";
var csharpSource = @"
class C
{
void Method(Base b)
{
b.Event1 += null;
b.Event2 += null;
b.Event3 += null;
}
}
";
var compilation = CreateCompilationWithILAndMscorlib40(csharpSource, ilSource);
compilation.VerifyDiagnostics(
// (6,9): error CS0122: 'Base.Event1.add' is inaccessible due to its protection level
// b.Event1 += null;
Diagnostic(ErrorCode.ERR_BadAccess, "b.Event1 += null").WithArguments("Base.Event1.add"),
// (7,9): error CS0122: 'Base.Event2.add' is inaccessible due to its protection level
// b.Event2 += null;
Diagnostic(ErrorCode.ERR_BadAccess, "b.Event2 += null").WithArguments("Base.Event2.add"),
// (8,9): error CS0122: 'Base.Event3.add' is inaccessible due to its protection level
// b.Event3 += null;
Diagnostic(ErrorCode.ERR_BadAccess, "b.Event3 += null").WithArguments("Base.Event3.add"));
var @class = compilation.GlobalNamespace.GetMember<NamedTypeSymbol>("Base");
var event1 = @class.GetMember<EventSymbol>("Event1");
var event2 = @class.GetMember<EventSymbol>("Event2");
var event3 = @class.GetMember<EventSymbol>("Event3");
Assert.NotNull(event1.AddMethod);
Assert.Equal(Accessibility.Private, event1.AddMethod.DeclaredAccessibility);
Assert.NotNull(event1.RemoveMethod);
Assert.Equal(Accessibility.Public, event1.RemoveMethod.DeclaredAccessibility);
Assert.NotNull(event2.AddMethod);
Assert.Equal(Accessibility.Protected, event2.AddMethod.DeclaredAccessibility);
Assert.NotNull(event2.RemoveMethod);
Assert.Equal(Accessibility.Public, event2.RemoveMethod.DeclaredAccessibility);
Assert.NotNull(event3.AddMethod);
Assert.Equal(Accessibility.Internal, event3.AddMethod.DeclaredAccessibility);
Assert.NotNull(event3.RemoveMethod);
Assert.Equal(Accessibility.Public, event3.RemoveMethod.DeclaredAccessibility);
}
[WorkItem(538956, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538956")]
[Fact]
public void EventAccessorDoesNotHideMethod()
{
const string cSharpSource = @"
interface IA {
void add_E(string e);
}
interface IB : IA {
event System.Action E;
}
class Program {
static void Main() {
IB x = null;
x.add_E(null);
}
}
";
CreateCompilation(cSharpSource).VerifyDiagnostics();
}
[WorkItem(538956, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538956")]
[Fact]
public void EventAccessorDoesNotConflictWithMethod()
{
const string cSharpSource = @"
interface IA {
void add_E(string e);
}
interface IB {
event System.Action E;
}
interface IC : IA, IB { }
class Program {
static void Main() {
IC x = null;
x.add_E(null);
}
}
";
CreateCompilation(cSharpSource).VerifyDiagnostics();
}
[WorkItem(538992, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/538992")]
[Fact]
public void CannotAccessEventThroughParenthesizedType()
{
const string cSharpSource = @"
class Program
{
static event System.Action E;
static void Main()
{
(Program).E();
}
}
";
CreateCompilation(cSharpSource).VerifyDiagnostics(
// (8,10): error CS0119: 'Program' is a 'type', which is not valid in the given context
// (Program).E();
Diagnostic(ErrorCode.ERR_BadSKunknown, "Program").WithArguments("Program", "type"));
}
[Fact]
public void CustomEventInvocable()
{
const string cSharpSource = @"
class Outer
{
public static void Q()
{
}
class Goo
{
public static event System.Action Q { add { } remove { } }
class Bar
{
void f()
{
Q();
}
}
}
}
";
CreateCompilation(cSharpSource).VerifyDiagnostics(
// (16,17): error CS0079: The event 'Outer.Goo.Q' can only appear on the left hand side of += or -=
// Q();
Diagnostic(ErrorCode.ERR_BadEventUsageNoField, "Q").WithArguments("Outer.Goo.Q"));
}
[WorkItem(542461, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/542461")]
[Fact]
public void EventMustDelegate()
{
const string cSharpSource = @"
using System;
namespace MyCollections
{
using System.Collections;
public delegate void ChangedEventHandler(object sender, EventArgs e);
public class ListWithChangedEvent : ArrayList
{
public event ListWithChangedEvent Changed;
protected virtual void OnChanged(EventArgs e)
{
if (Changed != null)
Changed(this, e);
}
public override int Add(object value)
{
int i = base.Add(value);
OnChanged(EventArgs.Empty);
return i;
}
public override object this[int index]
{
set
{
base[index] = value;
OnChanged(EventArgs.Empty);
}
}
}
}
namespace TestEvents
{
using MyCollections;
class EventListener
{
private ListWithChangedEvent List;
public EventListener(ListWithChangedEvent list)
{
List = list;
List.Changed += new ChangedEventHandler(ListChanged);
}
private void ListChanged(object sender, EventArgs e)
{
}
public void Detach()
{
List.Changed -= new ChangedEventHandler(ListChanged);
List = null;
}
}
}
";
CreateCompilation(cSharpSource).VerifyDiagnostics(
// (9,43): error CS0066: 'MyCollections.ListWithChangedEvent.Changed': event must be of a delegate type
// public event ListWithChangedEvent Changed;
Diagnostic(ErrorCode.ERR_EventNotDelegate, "Changed").WithArguments("MyCollections.ListWithChangedEvent.Changed"),
// Dev10 doesn't report this cascading error, but it seems reasonable since the field isn't a delegate.
// (13,17): error CS0149: Method name expected
// Changed(this, e);
Diagnostic(ErrorCode.ERR_MethodNameExpected, "Changed"));
}
[WorkItem(543791, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/543791")]
[Fact]
public void MultipleDeclaratorsOneError()
{
var source = @"
class A
{
event Unknown a, b;
}
";
CreateCompilation(source).VerifyDiagnostics(
// (4,5): error CS0246: The type or namespace name 'Unknown' could not be found (are you missing a using directive or an assembly reference?)
Diagnostic(ErrorCode.ERR_SingleTypeNameNotFound, "Unknown").WithArguments("Unknown"),
// (4,19): warning CS0067: The event 'A.a' is never used
// event Unknown a, b;
Diagnostic(ErrorCode.WRN_UnreferencedEvent, "a").WithArguments("A.a"),
// (4,22): warning CS0067: The event 'A.b' is never used
// event Unknown a, b;
Diagnostic(ErrorCode.WRN_UnreferencedEvent, "b").WithArguments("A.b"));
}
[WorkItem(545682, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/545682")]
[ClrOnlyFact(ClrOnlyReason.Ilasm)]
public void EventHidingMethod()
{
var source1 =
@".class public A
{
.method public hidebysig specialname rtspecialname instance void .ctor() { ret }
.method public instance void E1() { ret }
.method public instance void E2() { ret }
}
.class public B extends A
{
.method public hidebysig specialname rtspecialname instance void .ctor() { ret }
.method public instance void add_E1(class [mscorlib]System.Action v) { ret }
.method public instance void remove_E1(class [mscorlib]System.Action v) { ret }
.event [mscorlib]System.Action E1
{
.addon instance void B::add_E1(class [mscorlib]System.Action);
.removeon instance void B::remove_E1(class [mscorlib]System.Action);
}
.method public instance void add_E2(class [mscorlib]System.Action v) { ret }
.method public instance void remove_E2() { ret }
.event [mscorlib]System.Action E2
{
.addon instance void B::add_E2(class [mscorlib]System.Action);
.removeon instance void B::remove_E2();
}
}";
var reference1 = CompileIL(source1);
var source2 =
@"class C
{
static void M(B b)
{
b.E1(); // B.E1 valid, should hide A.E1
b.E2(); // B.E2 invalid, should not hide A.E2
}
}";
var compilation2 = CreateCompilation(source2, new[] { reference1 });
compilation2.VerifyDiagnostics(
// (5, 11): error CS0079: The event 'B.E1' can only appear on the left hand side of += or -=
Diagnostic(ErrorCode.ERR_BadEventUsageNoField, "E1").WithArguments("B.E1").WithLocation(5, 11));
}
[WorkItem(547071, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/547071")]
[Fact]
public void InvalidEventDeclarations()
{
CreateCompilation("event this").VerifyDiagnostics(
// (1,7): error CS1031: Type expected
// event this
Diagnostic(ErrorCode.ERR_TypeExpected, "this"),
// (1,11): error CS1514: { expected
// event this
Diagnostic(ErrorCode.ERR_LbraceExpected, ""),
// (1,11): error CS1513: } expected
// event this
Diagnostic(ErrorCode.ERR_RbraceExpected, ""),
// (1,7): error CS0065: '<invalid-global-code>.': event property must have both add and remove accessors
// event this
Diagnostic(ErrorCode.ERR_EventNeedsBothAccessors, "").WithArguments("<invalid-global-code>."));
CreateCompilation("event System.Action E<T>").VerifyDiagnostics(
// (1,21): error CS7002: Unexpected use of a generic name
// event System.Action E<T>
Diagnostic(ErrorCode.ERR_UnexpectedGenericName, "E"),
// (1,25): error CS1514: { expected
// event System.Action E<T>
Diagnostic(ErrorCode.ERR_LbraceExpected, ""),
// (1,25): error CS1513: } expected
// event System.Action E<T>
Diagnostic(ErrorCode.ERR_RbraceExpected, ""),
// (1,21): error CS0065: '<invalid-global-code>.E': event property must have both add and remove accessors
// event System.Action E<T>
Diagnostic(ErrorCode.ERR_EventNeedsBothAccessors, "E").WithArguments("<invalid-global-code>.E"));
CreateCompilation("event").VerifyDiagnostics(
// (1,6): error CS1031: Type expected
// event
Diagnostic(ErrorCode.ERR_TypeExpected, ""),
// (1,6): error CS1514: { expected
// event
Diagnostic(ErrorCode.ERR_LbraceExpected, ""),
// (1,6): error CS1513: } expected
// event
Diagnostic(ErrorCode.ERR_RbraceExpected, ""),
// (1,6): error CS0065: '<invalid-global-code>.': event property must have both add and remove accessors
// event
Diagnostic(ErrorCode.ERR_EventNeedsBothAccessors, "").WithArguments("<invalid-global-code>."));
CreateCompilation("event System.Action ").VerifyDiagnostics(
// (1,21): error CS1001: Identifier expected
// event System.Action
Diagnostic(ErrorCode.ERR_IdentifierExpected, ""),
// (1,21): error CS1514: { expected
// event System.Action
Diagnostic(ErrorCode.ERR_LbraceExpected, ""),
// (1,21): error CS1513: } expected
// event System.Action
Diagnostic(ErrorCode.ERR_RbraceExpected, ""),
// (1,21): error CS0065: '<invalid-global-code>.': event property must have both add and remove accessors
// event System.Action
Diagnostic(ErrorCode.ERR_EventNeedsBothAccessors, "").WithArguments("<invalid-global-code>."));
CreateCompilation("event System.Action System.IFormattable.").VerifyDiagnostics(
// (1,40): error CS0071: An explicit interface implementation of an event must use event accessor syntax
// event System.Action System.IFormattable.
Diagnostic(ErrorCode.ERR_ExplicitEventFieldImpl, ".").WithLocation(1, 40),
// (1,41): error CS1001: Identifier expected
// event System.Action System.IFormattable.
Diagnostic(ErrorCode.ERR_IdentifierExpected, "").WithLocation(1, 41),
// (1,21): error CS0540: '<invalid-global-code>.': containing type does not implement interface 'IFormattable'
// event System.Action System.IFormattable.
Diagnostic(ErrorCode.ERR_ClassDoesntImplementInterface, "System.IFormattable").WithArguments("<invalid-global-code>.", "System.IFormattable").WithLocation(1, 21),
// (1,41): error CS0539: '<invalid-global-code>.' in explicit interface declaration is not a member of interface
// event System.Action System.IFormattable.
Diagnostic(ErrorCode.ERR_InterfaceMemberNotFound, "").WithArguments("<invalid-global-code>.").WithLocation(1, 41));
}
[ClrOnlyFact(ClrOnlyReason.Ilasm)]
public void OverriddenEventCustomModifiers()
{
var il = @"
.class public auto ansi beforefieldinit Base
extends [mscorlib]System.Object
{
.field private class [mscorlib]System.Action`1<int32 modopt(int64) []> E
.method public hidebysig newslot specialname virtual
instance void add_E(class [mscorlib]System.Action`1<int32 modopt(int64) []> 'value') cil managed
{
ret
}
.method public hidebysig newslot specialname virtual
instance void remove_E(class [mscorlib]System.Action`1<int32 modopt(int64) []> 'value') cil managed
{
ret
}
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
ldarg.0
call instance void [mscorlib]System.Object::.ctor()
ret
}
.event class [mscorlib]System.Action`1<int32 modopt(int64) []> E
{
.addon instance void Base::add_E(class [mscorlib]System.Action`1<int32 modopt(int64) []>)
.removeon instance void Base::remove_E(class [mscorlib]System.Action`1<int32 modopt(int64) []>)
} // end of event Base::E
} // end of class Base
";
var source = @"
using System;
class Derived1 : Base
{
public override event Action<int[]> E;
}
class Derived2 : Base
{
public override event Action<int[]> E
{
add { }
remove { }
}
}
";
var comp = CreateCompilation(source, new[] { CompileIL(il) });
comp.VerifyDiagnostics(
// (6,41): warning CS0067: The event 'Derived1.E' is never used
// public override event Action<int[]> E;
Diagnostic(ErrorCode.WRN_UnreferencedEvent, "E").WithArguments("Derived1.E"));
var global = comp.GlobalNamespace;
var @base = global.GetMember<NamedTypeSymbol>("Base");
var baseEvent = @base.GetMember<EventSymbol>("E");
var baseEventType = baseEvent.Type;
Assert.Equal("System.Action<System.Int32 modopt(System.Int64) []>", baseEventType.ToTestDisplayString()); // Note modopt
var derived1 = global.GetMember<NamedTypeSymbol>("Derived1");
var event1 = derived1.GetMember<EventSymbol>("E");
Assert.Equal(baseEventType, event1.Type);
Assert.Equal(baseEventType, event1.AssociatedField.Type);
Assert.Equal(baseEventType, event1.AddMethod.ParameterTypesWithAnnotations.Single().Type);
Assert.Equal(baseEventType, event1.RemoveMethod.ParameterTypesWithAnnotations.Single().Type);
var derived2 = global.GetMember<NamedTypeSymbol>("Derived2");
var event2 = derived2.GetMember<EventSymbol>("E");
Assert.Equal(baseEventType, event2.Type);
Assert.Null(event2.AssociatedField);
Assert.Equal(baseEventType, event2.AddMethod.ParameterTypesWithAnnotations.Single().Type);
Assert.Equal(baseEventType, event2.RemoveMethod.ParameterTypesWithAnnotations.Single().Type);
}
[Fact]
public void OverriddenAccessorName()
{
var il = @"
.class public auto ansi beforefieldinit Base
extends [mscorlib]System.Object
{
.field private class [mscorlib]System.Action E
.method public hidebysig newslot specialname virtual
instance void myAdd(class [mscorlib]System.Action 'value') cil managed
{
ret
}
.method public hidebysig newslot specialname virtual
instance void myRemove(class [mscorlib]System.Action 'value') cil managed
{
ret
}
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
ldarg.0
call instance void [mscorlib]System.Object::.ctor()
ret
}
.event [mscorlib]System.Action E
{
.addon instance void Base::myAdd(class [mscorlib]System.Action)
.removeon instance void Base::myRemove(class [mscorlib]System.Action)
} // end of event Base::E
} // end of class Base
";
var source = @"
using System;
class Derived1 : Base
{
public override event Action E;
}
class Derived2 : Base
{
public override event Action E
{
add { }
remove { }
}
}
";
var comp = CreateCompilation(source, new[] { CompileIL(il) });
comp.VerifyDiagnostics(
// (6,34): warning CS0067: The event 'Derived1.E' is never used
// public override event Action E;
Diagnostic(ErrorCode.WRN_UnreferencedEvent, "E").WithArguments("Derived1.E"));
var derived1 = comp.GlobalNamespace.GetMember<NamedTypeSymbol>("Derived1");
var event1 = derived1.GetMember<EventSymbol>("E");
Assert.Equal("myAdd", event1.AddMethod.Name);
Assert.Equal("myRemove", event1.RemoveMethod.Name);
var derived2 = comp.GlobalNamespace.GetMember<NamedTypeSymbol>("Derived2");
var event2 = derived2.GetMember<EventSymbol>("E");
Assert.Equal("myAdd", event2.AddMethod.Name);
Assert.Equal("myRemove", event2.RemoveMethod.Name);
}
[Fact, WorkItem(570905, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/570905")]
public void OverriddenAccessorName_BaseMissingAccessor()
{
var source = @"
using System;
class Base
{
public virtual event Action E { } // Missing accessors.
}
class Derived1 : Base
{
public override event Action E;
}
class Derived2 : Base
{
public override event Action E
{
add { }
remove { }
}
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (6,33): error CS0065: 'Base.E': event property must have both add and remove accessors
// public virtual event Action E { } // Missing accessors.
Diagnostic(ErrorCode.ERR_EventNeedsBothAccessors, "E").WithArguments("Base.E"),
// (11,34): warning CS0067: The event 'Derived1.E' is never used
// public override event Action E;
Diagnostic(ErrorCode.WRN_UnreferencedEvent, "E").WithArguments("Derived1.E"));
var derived1 = comp.GlobalNamespace.GetMember<NamedTypeSymbol>("Derived1");
var event1 = derived1.GetMember<EventSymbol>("E");
Assert.Equal("add_E", event1.AddMethod.Name);
Assert.Equal("remove_E", event1.RemoveMethod.Name);
var derived2 = comp.GlobalNamespace.GetMember<NamedTypeSymbol>("Derived2");
var event2 = derived2.GetMember<EventSymbol>("E");
Assert.Equal("add_E", event2.AddMethod.Name);
Assert.Equal("remove_E", event2.RemoveMethod.Name);
}
[WorkItem(850168, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/850168")]
[Fact]
public void AbstractFieldLikeEvent()
{
var source = @"
using System;
public abstract class A
{
public abstract event Action E;
public abstract event Action F = null; // Invalid initializer.
}
";
var comp = CreateCompilation(source);
var typeA = comp.GlobalNamespace.GetMember<NamedTypeSymbol>("A");
var eventE = typeA.GetMember<EventSymbol>("E");
var eventF = typeA.GetMember<EventSymbol>("F");
Assert.Null(eventE.AssociatedField);
Assert.NotNull(eventF.AssociatedField); // Since it has an initializer.
}
[Fact, WorkItem(406, "https://github.com/dotnet/roslyn/issues/406")]
public void AbstractBaseEvent()
{
var source =
@"using System;
namespace ConsoleApplication3
{
public abstract class BaseWithAbstractEvent
{
public abstract event Action MyEvent;
}
public class SuperWithOverriddenEvent : BaseWithAbstractEvent
{
public override event Action MyEvent
{
add { base.MyEvent += value; } // error
remove { base.MyEvent -= value; } // error
}
public void Goo()
{
base.MyEvent += Goo; // error
}
}
class Program
{
static void Main()
{
SuperWithOverriddenEvent swoe = new SuperWithOverriddenEvent();
swoe.MyEvent += Main;
}
}
}";
CreateCompilation(source).VerifyDiagnostics(
// (14,19): error CS0205: Cannot call an abstract base member: 'BaseWithAbstractEvent.MyEvent'
// add { base.MyEvent += value; } // error
Diagnostic(ErrorCode.ERR_AbstractBaseCall, "base.MyEvent += value").WithArguments("ConsoleApplication3.BaseWithAbstractEvent.MyEvent").WithLocation(14, 19),
// (15,22): error CS0205: Cannot call an abstract base member: 'BaseWithAbstractEvent.MyEvent'
// remove { base.MyEvent -= value; } // error
Diagnostic(ErrorCode.ERR_AbstractBaseCall, "base.MyEvent -= value").WithArguments("ConsoleApplication3.BaseWithAbstractEvent.MyEvent").WithLocation(15, 22),
// (20,13): error CS0205: Cannot call an abstract base member: 'BaseWithAbstractEvent.MyEvent'
// base.MyEvent += Goo; // error
Diagnostic(ErrorCode.ERR_AbstractBaseCall, "base.MyEvent += Goo").WithArguments("ConsoleApplication3.BaseWithAbstractEvent.MyEvent").WithLocation(20, 13)
);
}
[Fact, WorkItem(40092, "https://github.com/dotnet/roslyn/issues/40092")]
public void ExternEventInitializer()
{
var text = @"
delegate void D();
class Test
{
#pragma warning disable 414 // The field '{0}' is assigned but its value is never used
#pragma warning disable 626 // Method, operator, or accessor '{0}' is marked external and has no attributes on it. Consider adding a DllImport attribute to specify the external implementation.
public extern event D e = null; // 1
}
";
CreateCompilation(text).VerifyDiagnostics(
// (8,27): error CS8760: 'Test.e': extern event cannot have initializer
// public extern event D e = null; // 1
Diagnostic(ErrorCode.ERR_ExternEventInitializer, "e").WithArguments("Test.e").WithLocation(8, 27));
}
#endregion
}
}
|