Skip to content

Commit 209e632

Browse files
committed
[generator] Prevent generating duplicate EventArgs classes.
1 parent 5136ef9 commit 209e632

File tree

6 files changed

+79
-71
lines changed

6 files changed

+79
-71
lines changed

src/Xamarin.SourceWriter/Models/PropertyWriter.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ public class PropertyWriter : ISourceWriter
3535
public List<AttributeWriter> SetterAttributes { get; } = new List<AttributeWriter> ();
3636
public int Priority { get; set; }
3737
public string ExplicitInterfaceImplementation { get; set; }
38+
public Visibility AutoSetterVisibility { get; set; }
3839

3940
public void SetVisibility (string visibility)
4041
{
@@ -165,6 +166,8 @@ protected virtual void WriteAutomaticPropertyBody (CodeWriter writer)
165166
writer.WriteLine ();
166167
writer.Indent ();
167168
need_unindent = true;
169+
} else {
170+
writer.Write (" ");
168171
}
169172

170173
WriteGetterComments (writer);
@@ -187,6 +190,14 @@ protected virtual void WriteAutomaticPropertyBody (CodeWriter writer)
187190

188191
WriteSetterComments (writer);
189192
WriteSetterAttributes (writer);
193+
194+
if (AutoSetterVisibility == Visibility.Private && !IsPrivate)
195+
writer.Write ("private ");
196+
else if (AutoSetterVisibility == Visibility.Protected && !IsProtected)
197+
writer.Write ("protected ");
198+
if (AutoSetterVisibility == Visibility.Internal && !IsInternal)
199+
writer.Write ("internal ");
200+
190201
writer.Write ("set; ");
191202

192203
if (need_unindent) {

tests/generator-Tests/Unit-Tests/CodeGeneratorTests.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,26 @@ public void ManagedOverrideProperty_Override ()
195195

196196
Assert.True (writer.ToString ().Contains ("public override unsafe int Name {"));
197197
}
198+
199+
[Test]
200+
public void WriteDuplicateInterfaceEventArgs ()
201+
{
202+
// If we have 2 methods that would each create the same EventArgs class,
203+
// make sure we combine them into 1 class with both members instead.
204+
var iface = SupportTypeBuilder.CreateEmptyInterface ("java.code.AnimatorListener");
205+
206+
var method1 = SupportTypeBuilder.CreateMethod (iface, "OnAnimationEnd", options, "boolean", false, true, new Parameter ("param1", "int", "int", false));
207+
var method2 = SupportTypeBuilder.CreateMethod (iface, "OnAnimationEnd", options, "boolean", false, true, new Parameter ("param1", "int", "int", false), new Parameter ("param2", "int", "int", false));
208+
209+
iface.Methods.Add (method1);
210+
iface.Methods.Add (method2);
211+
212+
generator.Context.ContextTypes.Push (iface);
213+
generator.WriteType (iface, string.Empty, new GenerationInfo ("", "", "MyAssembly"));
214+
generator.Context.ContextTypes.Pop ();
215+
216+
Assert.AreEqual (GetExpected (nameof (WriteDuplicateInterfaceEventArgs)), writer.ToString ().NormalizeLineEndings ());
217+
}
198218
}
199219

200220
[TestFixture]

tests/generator-Tests/expected.ji/GenericArguments/Com.Google.Android.Exoplayer.Drm.IExoMediaDrm.cs

Lines changed: 10 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -123,42 +123,22 @@ public unsafe void OnEvent (global::Com.Google.Android.Exoplayer.Drm.IExoMediaDr
123123
public partial class ExoMediaDrmOnEventEventArgs : global::System.EventArgs {
124124
public ExoMediaDrmOnEventEventArgs (global::Com.Google.Android.Exoplayer.Drm.IExoMediaDrm p0, byte[] p1, int p2, int p3, byte[] p4)
125125
{
126-
this.p0 = p0;
127-
this.p1 = p1;
128-
this.p2 = p2;
129-
this.p3 = p3;
130-
this.p4 = p4;
126+
this.P0 = p0;
127+
this.P1 = p1;
128+
this.P2 = p2;
129+
this.P3 = p3;
130+
this.P4 = p4;
131131
}
132132

133-
global::Com.Google.Android.Exoplayer.Drm.IExoMediaDrm p0;
133+
public global::Com.Google.Android.Exoplayer.Drm.IExoMediaDrm P0 { get; private set; }
134134

135-
public global::Com.Google.Android.Exoplayer.Drm.IExoMediaDrm P0 {
136-
get { return p0; }
137-
}
138-
139-
byte[] p1;
140-
141-
public byte[] P1 {
142-
get { return p1; }
143-
}
144-
145-
int p2;
135+
public byte[] P1 { get; private set; }
146136

147-
public int P2 {
148-
get { return p2; }
149-
}
150-
151-
int p3;
137+
public int P2 { get; private set; }
152138

153-
public int P3 {
154-
get { return p3; }
155-
}
139+
public int P3 { get; private set; }
156140

157-
byte[] p4;
158-
159-
public byte[] P4 {
160-
get { return p4; }
161-
}
141+
public byte[] P4 { get; private set; }
162142

163143
}
164144

tools/generator/SourceWriters/BoundInterface.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,17 @@ void AddInterfaceEventHandler (InterfaceGen iface, CodeGenerationOptions opt, Co
104104

105105
foreach (var method in iface.Methods.Where (m => m.EventName != string.Empty)) {
106106
if (method.RetVal.IsVoid || method.IsEventHandlerWithHandledProperty) {
107-
if (!method.IsSimpleEventHandler || method.IsEventHandlerWithHandledProperty)
108-
post_sibling_types.Add (new InterfaceEventArgsClass (iface, method, opt, context));
107+
if (!method.IsSimpleEventHandler || method.IsEventHandlerWithHandledProperty) {
108+
var event_args_class = post_sibling_types.OfType<InterfaceEventArgsClass> ().SingleOrDefault (c => c.Name == iface.GetArgsName (method));
109+
110+
// Check if there's an existing EventArgs class to add to
111+
if (event_args_class is null) {
112+
event_args_class = new InterfaceEventArgsClass (iface, method);
113+
post_sibling_types.Add (event_args_class);
114+
}
115+
116+
event_args_class.AddMembersFromMethod (iface, method, opt);
117+
}
109118
} else {
110119
var del = new DelegateWriter {
111120
Name = iface.GetEventDelegateName (method),

tools/generator/SourceWriters/BoundMethod.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,12 @@ public class BoundMethod : MethodWriter
1212
{
1313
readonly MethodCallback callback;
1414

15+
public Method JavaMethod { get; }
16+
1517
public BoundMethod (GenBase type, Method method, CodeGenerationOptions opt, bool generateCallbacks)
1618
{
19+
JavaMethod = method;
20+
1721
if (generateCallbacks && method.IsVirtual)
1822
callback = new MethodCallback (type, method, opt, null, method.IsReturnCharSequence);
1923

tools/generator/SourceWriters/InterfaceEventArgsClass.cs

Lines changed: 23 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,31 @@ namespace generator.SourceWriters
1010
{
1111
public class InterfaceEventArgsClass : ClassWriter
1212
{
13-
public InterfaceEventArgsClass (InterfaceGen iface, Method method, CodeGenerationOptions opt, CodeGeneratorContext context)
13+
public InterfaceEventArgsClass (InterfaceGen iface, Method method)
1414
{
1515
Name = iface.GetArgsName (method);
1616
Inherits = "global::System.EventArgs";
1717

1818
IsPublic = true;
1919
IsPartial = true;
2020

21-
UsePriorityOrder = true;
22-
2321
Comments.Add ($"// event args for {iface.JavaName}.{method.JavaName}");
2422

25-
AddConstructor (iface, method, opt);
26-
23+
// Add: public bool Handled { get; set; }
2724
if (method.IsEventHandlerWithHandledProperty)
28-
Properties.Add (new HandledProperty ());
25+
Properties.Add (new PropertyWriter {
26+
Name = "Handled",
27+
PropertyType = TypeReferenceWriter.Bool,
28+
IsPublic = true,
29+
HasGet = true,
30+
HasSet = true,
31+
IsAutoProperty = true
32+
});
33+
}
2934

35+
public void AddMembersFromMethod (InterfaceGen iface, Method method, CodeGenerationOptions opt)
36+
{
37+
AddConstructor (iface, method, opt);
3038
AddProperties (method, opt);
3139
}
3240

@@ -39,15 +47,15 @@ void AddConstructor (InterfaceGen iface, Method method, CodeGenerationOptions op
3947

4048
if (method.IsEventHandlerWithHandledProperty) {
4149
ctor.Parameters.Add (new MethodParameterWriter ("handled", TypeReferenceWriter.Bool));
42-
ctor.Body.Add ("this.handled = handled;");
50+
ctor.Body.Add ("this.Handled = handled;");
4351
}
4452

4553
foreach (var p in method.Parameters) {
4654
if (p.IsSender)
4755
continue;
4856

4957
ctor.Parameters.Add (new MethodParameterWriter (p.Name, new TypeReferenceWriter (opt.GetTypeReferenceName (p))));
50-
ctor.Body.Add ($"this.{opt.GetSafeIdentifier (p.Name)} = {opt.GetSafeIdentifier (p.Name)};");
58+
ctor.Body.Add ($"this.{p.PropertyName} = {opt.GetSafeIdentifier (p.Name)};");
5159
}
5260

5361
Constructors.Add (ctor);
@@ -59,46 +67,22 @@ void AddProperties (Method method, CodeGenerationOptions opt)
5967
if (p.IsSender)
6068
continue;
6169

62-
Fields.Add (new FieldWriter {
63-
Name = opt.GetSafeIdentifier (p.Name),
64-
Type = new TypeReferenceWriter (opt.GetTypeReferenceName (p))
65-
});
70+
// We've already added this property from a different overload
71+
if (Properties.Any (prop => prop.Name == p.PropertyName))
72+
continue;
6673

6774
var prop = new PropertyWriter {
6875
Name = p.PropertyName,
6976
PropertyType = new TypeReferenceWriter (opt.GetTypeReferenceName (p)),
7077
IsPublic = true,
71-
HasGet = true
78+
HasGet = true,
79+
HasSet = true,
80+
IsAutoProperty = true,
81+
AutoSetterVisibility = Visibility.Private
7282
};
7383

74-
prop.GetBody.Add ($"return {opt.GetSafeIdentifier (p.Name)};");
75-
7684
Properties.Add (prop);
7785
}
7886
}
7987
}
80-
81-
public class HandledProperty : PropertyWriter
82-
{
83-
public HandledProperty ()
84-
{
85-
Name = "Handled";
86-
PropertyType = TypeReferenceWriter.Bool;
87-
88-
IsPublic = true;
89-
90-
HasGet = true;
91-
GetBody.Add ("return handled;");
92-
93-
HasSet = true;
94-
SetBody.Add ("handled = value;");
95-
}
96-
97-
public override void Write (CodeWriter writer)
98-
{
99-
writer.Write ("bool handled;");
100-
101-
base.Write (writer);
102-
}
103-
}
10488
}

0 commit comments

Comments
 (0)