void AddMethods(InterfaceGen iface, CodeGenerationOptions opt) { var handlers = new List <string> (); foreach (var m in iface.Methods) { Methods.Add(new InterfaceEventHandlerImplMethod(iface, m, handlers, opt)); } var is_empty_method = new MethodWriter { Name = "__IsEmpty", IsInternal = true, IsStatic = true, ReturnType = TypeReferenceWriter.Bool }; is_empty_method.Parameters.Add(new MethodParameterWriter("value", new TypeReferenceWriter(iface.Name + "Implementor"))); if (!iface.Methods.Any(m => m.EventName != string.Empty) || handlers.Count == 0) { is_empty_method.Body.Add("return true;"); } else { is_empty_method.Body.Add($"return {string.Join (" && ", handlers.Select (e => string.Format ("value.{0}Handler == null", e)))};"); } Methods.Add(is_empty_method); }
public void FindGenericTypes() { var table = new SymbolTable(); var list = new InterfaceGen(new GenBaseSupport { Name = "System.Collections.Generic.IList`1", FullName = "System.Collections.Generic.IList`1", JavaSimpleName = "System.Collections.Generic.IList`1" }); table.AddType(list); var dict = new InterfaceGen(new GenBaseSupport { Name = "System.Collections.Generic.IDictionary`2", FullName = "System.Collections.Generic.IDictionary`2", JavaSimpleName = "System.Collections.Generic.IDictionary`2" }); table.AddType(dict); Assert.AreEqual("System.Collections.Generic.IList`1", table.Lookup("System.Collections.Generic.IList<Java.Util.Locale.LanguageRange>").FullName); Assert.AreEqual("System.Collections.Generic.IList`1", table.Lookup("System.Collections.Generic.IList<List<Java.Util.Locale.LanguageRange>>").FullName); Assert.AreEqual("System.Collections.Generic.IDictionary`2", table.Lookup("System.Collections.Generic.IDictionary<string, Java.Util.Locale.LanguageRange>").FullName); Assert.AreEqual("System.Collections.Generic.IDictionary`2", table.Lookup("System.Collections.Generic.IDictionary<string, List<Java.Util.Locale.LanguageRange>>").FullName); Assert.AreEqual("System.Collections.Generic.IList`1", table.Lookup("System.Collections.Generic.IList<Dictionary<string, Java.Util.Locale.LanguageRange>>").FullName); }
void AddClassHandle(InterfaceGen iface, CodeGenerationOptions opt) { if (opt.SupportDefaultInterfaceMethods && (iface.HasDefaultMethods || iface.HasStaticMethods)) { Fields.Add(new PeerMembersField(opt, iface.RawJniName, iface.Name, true)); } }
public InterfaceEventHandlerImplClass(InterfaceGen iface, CodeGenerationOptions opt, CodeGeneratorContext context) { var jni_class = "mono/" + iface.RawJniName.Replace('$', '_') + "Implementor"; Name = iface.Name + "Implementor"; Inherits = "global::Java.Lang.Object"; Implements.Add(iface.Name); IsInternal = true; IsSealed = true; IsPartial = true; Attributes.Add(new RegisterAttr(jni_class, additionalProperties: iface.AdditionalAttributeString()) { UseGlobal = true }); if (iface.NeedsSender) { Fields.Add(new FieldWriter { Name = "sender", Type = TypeReferenceWriter.Object }); } AddConstructor(iface, jni_class, opt); AddMethods(iface, opt); }
public InterfaceInvokerProperty(InterfaceGen iface, Property property, CodeGenerationOptions opt, CodeGeneratorContext context) { this.property = property; this.opt = opt; Name = property.AdjustedName; PropertyType = new TypeReferenceWriter(opt.GetTypeReferenceName(property)); IsPublic = true; IsUnsafe = true; SourceWriterExtensions.AddSupportedOSPlatform(Attributes, property.Getter, opt); HasGet = property.Getter != null; if (property.Getter != null) { HasGet = true; getter_callback = new MethodCallback(iface, property.Getter, opt, property.AdjustedName, false); } if (property.Setter != null) { HasSet = true; setter_callback = new MethodCallback(iface, property.Setter, opt, property.AdjustedName, false); } context_this = context.ContextType.GetObjectHandleProperty(opt, "this"); }
public InterfaceExtensionsClass(InterfaceGen iface, string declaringTypeName, CodeGenerationOptions opt) { Name = $"{declaringTypeName}{iface.Name}Extensions"; IsPublic = true; IsStatic = true; IsPartial = true; foreach (var method in iface.Methods.Where(m => !m.IsStatic)) { if (method.CanHaveStringOverload) { // TODO: Don't allow obsolete here to match old generator. // Probably should allow this in the future. var deprecated = method.Deprecated; method.Deprecated = null; Methods.Add(new BoundMethodExtensionStringOverload(method, opt, iface.FullName)); method.Deprecated = deprecated; } if (method.Asyncify) { Methods.Add(new MethodExtensionAsyncWrapper(method, opt, iface.FullName)); } } }
public InterfaceListenerProperty(InterfaceGen iface, string name, string nameSpec, string methodName, string fullDelegateName, CodeGenerationOptions opt) { Name = name; PropertyType = new TypeReferenceWriter(opt.GetOutputName(fullDelegateName)) { Nullable = opt.SupportNullableReferenceTypes }; IsPublic = true; HasGet = true; var handlerPrefix = iface.Methods.Count > 1 ? methodName : string.Empty; GetBody.Add($"{opt.GetOutputName (iface.FullName)}Implementor{opt.NullableOperator} impl = Impl{name};"); GetBody.Add($"return impl == null ? null : impl.{handlerPrefix}Handler;"); HasSet = true; SetBody.Add($"{opt.GetOutputName (iface.FullName)}Implementor{opt.NullableOperator} impl = Impl{name};"); SetBody.Add($"if (impl == null) {{"); SetBody.Add($"\timpl = new {opt.GetOutputName (iface.FullName)}Implementor ({(iface.NeedsSender ? "this" : string.Empty)});"); SetBody.Add($"\tImpl{name} = impl;"); SetBody.Add($"}} else"); SetBody.Add($"impl.{nameSpec}Handler = value;"); }
private static void FixupInterface(InterfaceGen gen) { foreach (var method in gen.Methods.Where(m => m.IsKotlinNameMangled)) { FixMethodName(method); } }
public InterfaceListenerEvent(InterfaceGen iface, string name, string nameSpec, string fullDelegateName, string wrefSuffix, string add, string remove, bool hasHandlerArgument, CodeGenerationOptions opt) { Name = name; EventType = new TypeReferenceWriter(opt.GetOutputName(fullDelegateName)); IsPublic = true; HasAdd = true; AddBody.Add($"global::Java.Interop.EventHelper.AddEventHandler<{opt.GetOutputName (iface.FullName)}, {opt.GetOutputName (iface.FullName)}Implementor>("); AddBody.Add($"ref weak_implementor_{wrefSuffix},"); AddBody.Add($"__Create{iface.Name}Implementor,"); AddBody.Add($"{add + (hasHandlerArgument ? "_Event_With_Handler_Helper" : null)},"); AddBody.Add($"__h => __h.{nameSpec}Handler += value);"); HasRemove = true; RemoveBody.Add($"global::Java.Interop.EventHelper.RemoveEventHandler<{opt.GetOutputName (iface.FullName)}, {opt.GetOutputName (iface.FullName)}Implementor>("); RemoveBody.Add($"ref weak_implementor_{wrefSuffix},"); RemoveBody.Add($"{opt.GetOutputName (iface.FullName)}Implementor.__IsEmpty,"); RemoveBody.Add($"{remove},"); RemoveBody.Add($"__h => __h.{nameSpec}Handler -= value);"); if (hasHandlerArgument) { helper_method = new InterfaceListenerEventHandlerHelper(iface, add, opt); } }
void AddConstructor(InterfaceGen iface, Method method, CodeGenerationOptions opt) { var ctor = new ConstructorWriter { Name = iface.GetArgsName(method), IsPublic = true }; if (method.IsEventHandlerWithHandledProperty) { ctor.Parameters.Add(new MethodParameterWriter("handled", TypeReferenceWriter.Bool)); ctor.Body.Add("this.handled = handled;"); } foreach (var p in method.Parameters) { if (p.IsSender) { continue; } ctor.Parameters.Add(new MethodParameterWriter(p.Name, new TypeReferenceWriter(opt.GetTypeReferenceName(p)))); ctor.Body.Add($"this.{opt.GetSafeIdentifier (p.Name)} = {opt.GetSafeIdentifier (p.Name)};"); } Constructors.Add(ctor); }
public InterfaceInvokerClass(InterfaceGen iface, CodeGenerationOptions opt, CodeGeneratorContext context) { Name = $"{iface.Name}Invoker"; IsInternal = true; IsPartial = true; UsePriorityOrder = true; Inherits = "global::Java.Lang.Object"; Implements.Add(iface.Name); Attributes.Add(new RegisterAttr(iface.RawJniName, noAcw: true, additionalProperties: iface.AdditionalAttributeString()) { UseGlobal = true }); Fields.Add(new PeerMembersField(opt, iface.RawJniName, $"{iface.Name}Invoker", false)); Properties.Add(new InterfaceHandleGetter()); Properties.Add(new JniPeerMembersGetter()); Properties.Add(new InterfaceThresholdClassGetter()); Properties.Add(new ThresholdTypeGetter()); Fields.Add(new FieldWriter { Name = "class_ref", Type = TypeReferenceWriter.IntPtr, IsShadow = opt.BuildingCoreAssembly }); Methods.Add(new GetObjectMethod(iface, opt)); Methods.Add(new ValidateMethod(iface)); Methods.Add(new DisposeMethod()); Constructors.Add(new InterfaceInvokerConstructor(iface, context)); AddMemberInvokers(iface, new HashSet <string> (), opt, context); }
void AddCharSequenceEnumerators(InterfaceGen iface) { if (iface.FullName == "Java.Lang.ICharSequence") { Methods.Add(new CharSequenceEnumeratorMethod()); Methods.Add(new CharSequenceGenericEnumeratorMethod()); } }
void AddNestedSiblingTypes(InterfaceGen iface, CodeGenerationOptions opt, CodeGeneratorContext context, GenerationInfo genInfo) { // Generate sibling types for nested types we don't want to nest foreach (var nest in iface.NestedTypes.Where(t => t.Unnest)) { pre_sibling_types.Add(SourceWriterExtensions.BuildManagedTypeModel(nest, opt, context, genInfo)); } }
public InterfaceListenerEventHandlerHelper(InterfaceGen iface, string add, CodeGenerationOptions opt) { Name = add + "_Event_With_Handler_Helper"; Parameters.Add(new MethodParameterWriter("value", new TypeReferenceWriter(opt.GetOutputName(iface.FullName)))); ReturnType = TypeReferenceWriter.Void; Body.Add($"{add} (value, null);"); }
public CreateImplementorMethod(InterfaceGen iface, CodeGenerationOptions opt) { Name = $"__Create{iface.Name}Implementor"; ReturnType = new TypeReferenceWriter($"{opt.GetOutputName (iface.FullName)}Implementor"); Body.Add($"return new {opt.GetOutputName (iface.FullName)}Implementor ({(iface.NeedsSender ? "this" : "")});"); }
public InterfaceListenerEventHandlerHelper(InterfaceGen iface, Method method, string add, CodeGenerationOptions opt) { Name = add + "_Event_With_Handler_Helper"; Parameters.Add(new MethodParameterWriter("value", new TypeReferenceWriter(opt.GetOutputName(iface.FullName)))); ReturnType = TypeReferenceWriter.Void; SourceWriterExtensions.AddSupportedOSPlatform(Attributes, method, opt); Body.Add($"{add} (value, null);"); }
void AddNestedTypes(InterfaceGen iface, CodeGenerationOptions opt, CodeGeneratorContext context, GenerationInfo genInfo) { // Generate nested types for supported nested types. This is a new addition in C#8. // Prior to this, types nested in an interface had to be generated as sibling types. // The "Unnest" property is used to support backwards compatibility with pre-C#8 bindings. foreach (var nest in iface.NestedTypes.Where(t => !t.Unnest)) { NestedTypes.Add(SourceWriterExtensions.BuildManagedTypeModel(nest, opt, context, genInfo)); } }
public static void AddInterfaceListenerEventOrProperty(TypeWriter tw, InterfaceGen iface, Method method, ClassGen target, string name, string connector_fmt, string add, string remove, CodeGenerationOptions opt) { if (method.EventName == string.Empty) { return; } var nameSpec = iface.Methods.Count > 1 ? method.AdjustedName : string.Empty; var idx = iface.FullName.LastIndexOf("."); var start = iface.Name.StartsWith("IOn") ? 3 : 1; var full_delegate_name = iface.FullName.Substring(0, idx + 1) + iface.Name.Substring(start, iface.Name.Length - start - 8) + nameSpec; if (method.IsSimpleEventHandler) { full_delegate_name = "EventHandler"; } else if (method.RetVal.IsVoid || method.IsEventHandlerWithHandledProperty) { full_delegate_name = "EventHandler<" + iface.FullName.Substring(0, idx + 1) + iface.GetArgsName(method) + ">"; } else { full_delegate_name += "Handler"; } if (method.RetVal.IsVoid || method.IsEventHandlerWithHandledProperty) { if (opt.GetSafeIdentifier(name) != name) { Report.LogCodedWarning(0, Report.WarningInvalidEventName2, method, iface.FullName, name); return; } else { var mt = target.Methods.Where(method => string.Compare(method.Name, connector_fmt, StringComparison.OrdinalIgnoreCase) == 0 && method.IsListenerConnector).FirstOrDefault(); var hasHandlerArgument = mt != null && mt.IsListenerConnector && mt.Parameters.Count == 2 && mt.Parameters [1].Type == "Android.OS.Handler"; tw.Events.Add(new InterfaceListenerEvent(iface, name, nameSpec, full_delegate_name, connector_fmt, add, remove, hasHandlerArgument, opt)); } } else { if (opt.GetSafeIdentifier(name) != name) { Report.LogCodedWarning(0, Report.WarningInvalidEventPropertyName, method, iface.FullName, name); return; } tw.Properties.Add(new InterfaceListenerPropertyImplementor(iface, name, opt)); tw.Properties.Add(new InterfaceListenerProperty(iface, name, nameSpec, method.AdjustedName, full_delegate_name, opt)); } }
void AddMemberInvokers(InterfaceGen iface, HashSet <string> members, CodeGenerationOptions opt, CodeGeneratorContext context) { AddPropertyInvokers(iface, iface.Properties.Where(p => !p.Getter.IsStatic && !p.Getter.IsInterfaceDefaultMethod), members, opt, context); AddMethodInvokers(iface, iface.Methods.Where(m => !m.IsStatic && !m.IsInterfaceDefaultMethod), members, opt, context); AddCharSequenceEnumerators(iface); foreach (var i in iface.GetAllDerivedInterfaces()) { AddPropertyInvokers(iface, i.Properties.Where(p => !p.Getter.IsStatic && !p.Getter.IsInterfaceDefaultMethod), members, opt, context); AddMethodInvokers(iface, i.Methods.Where(m => !m.IsStatic && !m.IsInterfaceDefaultMethod && !iface.IsCovariantMethod(m) && !(i.FullName.StartsWith("Java.Lang.ICharSequence") && m.Name.EndsWith("Formatted"))), members, opt, context); AddCharSequenceEnumerators(i); } }
void AddFields(InterfaceGen iface, CodeGenerationOptions opt, CodeGeneratorContext context) { // Interface fields are only supported with DIM if (!opt.SupportInterfaceConstants && !opt.SupportDefaultInterfaceMethods) { return; } var seen = new HashSet <string> (); var fields = iface.GetGeneratableFields(opt).ToList(); SourceWriterExtensions.AddFields(this, iface, fields, seen, opt, context); }
void AddProperties(InterfaceGen iface, CodeGenerationOptions opt) { foreach (var prop in iface.Properties.Where(p => !p.Getter.IsStatic && !p.Getter.IsInterfaceDefaultMethod)) { Properties.Add(new BoundInterfacePropertyDeclaration(iface, prop, iface.AssemblyQualifiedName + "Invoker", opt)); } if (!opt.SupportDefaultInterfaceMethods) { return; } var dim_properties = iface.Properties.Where(p => p.Getter.IsInterfaceDefaultMethod || p.Getter.IsStatic); foreach (var prop in dim_properties) { if (prop.Getter.IsAbstract) { var baseProp = iface.BaseSymbol != null?iface.BaseSymbol.GetPropertyByName(prop.Name, true) : null; if (baseProp != null) { if (baseProp.Type != prop.Getter.Return) { // This may not be required if we can change generic parameter support to return constrained type (not just J.L.Object). //writer.WriteLine ("{0}// skipped generating property {1} because its Java method declaration is variant that we cannot represent in C#", indent, property.Name); return; } } var bound_property = new BoundAbstractProperty(iface, prop, opt); Properties.Add(bound_property); if (prop.Type.StartsWith("Java.Lang.ICharSequence", StringComparison.Ordinal) && !bound_property.IsOverride) { Properties.Add(new BoundPropertyStringVariant(prop, opt)); } } else { var bound_property = new BoundProperty(iface, prop, opt, true, false); Properties.Add(bound_property); if (prop.Type.StartsWith("Java.Lang.ICharSequence", StringComparison.Ordinal) && !bound_property.IsOverride) { Properties.Add(new BoundPropertyStringVariant(prop, opt)); } } } }
void AddAlternativesClass(InterfaceGen iface, CodeGenerationOptions opt, CodeGeneratorContext context) { if (iface.NoAlternatives) { return; } var staticMethods = iface.Methods.Where(m => m.IsStatic); if (iface.Fields.Any() || staticMethods.Any()) { pre_sibling_types.Add(new InterfaceMemberAlternativeClass(iface, opt, context)); } }
void AddPropertyInvokers(InterfaceGen iface, IEnumerable <Property> properties, HashSet <string> members, CodeGenerationOptions opt, CodeGeneratorContext context) { foreach (var prop in properties) { if (members.Contains(prop.Name)) { continue; } members.Add(prop.Name); Properties.Add(new InterfaceInvokerProperty(iface, prop, opt, context)); } }
void AddAbstractMethodDeclaration(GenBase klass, Method method, InterfaceGen iface) { Methods.Add(new BoundMethodAbstractDeclaration(iface, method, opt, klass)); if (method.IsReturnCharSequence || method.Parameters.HasCharSequence) { Methods.Add(new BoundMethodStringOverload(method, opt)); } if (method.Asyncify) { Methods.Add(new MethodAsyncWrapper(method, opt)); } }
// static IntPtr Validate (IntPtr handle) // { // if (!JNIEnv.IsInstanceOf (handle, java_class_ref)) // throw new InvalidCastException (string.Format (\"Unable to convert instance of type '{{0}}' to type '{{1}}'.\", JNIEnv.GetClassNameFromInstance (handle), \"{iface.JavaName}\")); // // return handle; // } public ValidateMethod(InterfaceGen iface) { Name = "Validate"; ReturnType = TypeReferenceWriter.IntPtr; IsStatic = true; Parameters.Add(new MethodParameterWriter("handle", TypeReferenceWriter.IntPtr)); Body.Add("if (!JNIEnv.IsInstanceOf (handle, java_class_ref))"); Body.Add($"\tthrow new InvalidCastException ($\"Unable to convert instance of type '{{JNIEnv.GetClassNameFromInstance (handle)}}' to type '{iface.JavaName}'.\");"); Body.Add("return handle;"); }
// public IfaceInvoker (IntPtr handle, JniHandleOwnership transfer) : base (Validate (handle), transfer) // { // IntPtr local_ref = JNIEnv.GetObjectClass (this) // this.class_ref = JNIEnv.NewGlobalRef (local_ref); // JNIEnv.DeleteLocalRef (local_ref); // } public InterfaceInvokerConstructor(InterfaceGen iface, CodeGeneratorContext context) { Name = iface.Name + "Invoker"; IsPublic = true; Parameters.Add(new MethodParameterWriter("handle", TypeReferenceWriter.IntPtr)); Parameters.Add(new MethodParameterWriter("transfer", new TypeReferenceWriter("JniHandleOwnership"))); BaseCall = "base (Validate (handle), transfer)"; Body.Add($"IntPtr local_ref = JNIEnv.GetObjectClass ({context.ContextType.GetObjectHandleProperty ("this")});"); Body.Add("this.class_ref = JNIEnv.NewGlobalRef (local_ref);"); Body.Add("JNIEnv.DeleteLocalRef (local_ref);"); }
// Historically .NET has not allowed interface implemented fields or constants, so we // initially worked around that by moving them to an abstract class, generally // IMyInterface -> MyInterfaceConsts // This was later expanded to accomodate static interface methods, creating a more appropriately named class // IMyInterface -> MyInterface // In this case the XXXConsts class is [Obsolete]'d and simply inherits from the newer class // in order to maintain backward compatibility. // If we're creating a binding that supports DIM, we remove the XXXConsts class as they've been // [Obsolete:iserror] for a long time, and we add [Obsolete] to the interface "class". public InterfaceMemberAlternativeClass(InterfaceGen iface, CodeGenerationOptions opt, CodeGeneratorContext context) { var should_obsolete = opt.SupportInterfaceConstants && opt.SupportDefaultInterfaceMethods; Name = iface.HasManagedName ? iface.Name.Substring(1) + "Consts" : iface.Name.Substring(1); Inherits = "Java.Lang.Object"; IsPublic = true; IsAbstract = true; UsePriorityOrder = true; SourceWriterExtensions.AddSupportedOSPlatform(Attributes, iface, opt); Attributes.Add(new RegisterAttr(iface.RawJniName, noAcw: true, additionalProperties: iface.AdditionalAttributeString()) { AcwLast = true }); if (should_obsolete) { Attributes.Add(new ObsoleteAttr($"Use the '{iface.FullName}' type. This class will be removed in a future release.") { WriteGlobal = true, NoAtSign = true }); } Constructors.Add(new ConstructorWriter { Name = Name, IsInternal = true }); var needs_class_ref = AddFields(iface, should_obsolete, opt, context); AddMethods(iface, should_obsolete, opt); if (needs_class_ref || iface.Methods.Where(m => m.IsStatic).Any()) { Fields.Add(new PeerMembersField(opt, iface.RawJniName, Name, false)); } if (!iface.HasManagedName && !opt.SupportInterfaceConstants) { sibling_classes.Add(new InterfaceConstsForwardClass(iface)); } }
// For each interface, generate either an abstract method or an explicit implementation method. void AddInterfaceAbstractMembers(ClassGen klass, InterfaceGen iface, CodeGenerationOptions opt, CodeGeneratorContext context) { foreach (var method in iface.Methods.Where(m => !m.IsInterfaceDefaultMethod && !m.IsStatic)) { var mapped = false; var sig = method.GetSignature(); if (context.ContextGeneratedMethods.Any(_ => _.Name == method.Name && _.JniSignature == method.JniSignature)) { continue; } for (var cls = klass; cls != null; cls = cls.BaseGen) { if (cls.ContainsMethod(method, false) || cls != klass && klass.ExplicitlyImplementedInterfaceMethods.Contains(sig)) { mapped = true; break; } } if (mapped) { continue; } if (klass.ExplicitlyImplementedInterfaceMethods.Contains(sig)) { Methods.Add(new MethodExplicitInterfaceImplementation(iface, method, opt)); } else { AddAbstractMethodDeclaration(klass, method, iface); } context.ContextGeneratedMethods.Add(method); } foreach (var prop in iface.Properties.Where(p => !p.Getter.IsInterfaceDefaultMethod && !p.Getter.IsStatic)) { if (klass.ContainsProperty(prop.Name, false)) { continue; } AddAbstractPropertyDeclaration(klass, prop, opt); } }
void AddMethodInvokers(InterfaceGen iface, IEnumerable <Method> methods, HashSet <string> members, CodeGenerationOptions opt, CodeGeneratorContext context) { foreach (var m in methods) { var sig = m.GetSignature(); if (members.Contains(sig)) { continue; } members.Add(sig); Methods.Add(new InterfaceInvokerMethod(iface, m, opt, context)); } }
// public static IInterface? GetObject (IntPtr handle, JniHandleOwnership transfer) // { // return global::Java.Lang.Object.GetObject<IInterface> (handle, transfer); // } public GetObjectMethod(InterfaceGen iface, CodeGenerationOptions opt) { Name = "GetObject"; ReturnType = new TypeReferenceWriter(iface.Name) { Nullable = opt.SupportNullableReferenceTypes }; IsPublic = true; IsStatic = true; Parameters.Add(new MethodParameterWriter("handle", TypeReferenceWriter.IntPtr)); Parameters.Add(new MethodParameterWriter("transfer", new TypeReferenceWriter("JniHandleOwnership"))); Body.Add($"return global::Java.Lang.Object.GetObject<{iface.Name}> (handle, transfer);"); }