// // Metadata.xml XPath field reference: path="/api/package[@name='android.os']/class[@name='Vibrator']/field[@name='VIBRATION_EFFECT_SUPPORT_UNKNOWN']" // [Register ("VIBRATION_EFFECT_SUPPORT_UNKNOWN", ApiSince = 30)] // [Obsolete ("This constant will be removed in the future version. Use Android.OS.VibrationEffectSupport enum directly instead of this field.", error: true)] // public const Android.OS.VibrationEffectSupport VibrationEffectSupportUnknown = (Android.OS.VibrationEffectSupport) 0; public BoundField(GenBase type, Field field, CodeGenerationOptions opt) { Name = field.Name; Type = new TypeReferenceWriter(opt.GetOutputName(field.Symbol.FullName)); Comments.Add($"// Metadata.xml XPath field reference: path=\"{type.MetadataXPathReference}/field[@name='{field.JavaName}']\""); Attributes.Add(new RegisterAttr(field.JavaName, additionalProperties: field.AdditionalAttributeString())); if (field.IsEnumified) { Attributes.Add(new GeneratedEnumAttr()); } if (field.IsDeprecated) { Attributes.Add(new ObsoleteAttr(field.DeprecatedComment, field.IsDeprecatedError) { NoAtSign = true, WriteEmptyString = true }); } if (field.Annotation.HasValue()) { Attributes.Add(new CustomAttr(field.Annotation)); } SetVisibility(field.Visibility); IsConst = true; // the Value complication is due to constant enum from negative integer value (C# compiler requires explicit parenthesis). Value = $"({opt.GetOutputName (field.Symbol.FullName)}) {(field.Value.Contains ('-') && field.Symbol.FullName.Contains ('.') ? '(' + field.Value + ')' : field.Value)}"; }
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;"); }
public InterfaceListenerEvent(InterfaceGen iface, Method method, 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; SourceWriterExtensions.AddSupportedOSPlatform(Attributes, method, opt); 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, method, add, opt); } }
protected override void WriteGetterBody(CodeWriter writer) { writer.WriteLine($"const string __id = \"{field.JavaName}.{field.Symbol.JniName}\";"); writer.WriteLine(); var invokeType = SourceWriterExtensions.GetInvokeType(field.GetMethodPrefix); var indirect = field.IsStatic ? "StaticFields" : "InstanceFields"; var invoke = "Get{0}Value"; invoke = string.Format(invoke, invokeType); writer.WriteLine($"var __v = {field.Symbol.ReturnCast}_members.{indirect}.{invoke} (__id{(field.IsStatic ? "" : ", this")});"); if (field.Symbol.IsArray) { writer.WriteLine($"return global::Android.Runtime.JavaArray<{opt.GetOutputName (field.Symbol.ElementType)}>.FromJniHandle (__v.Handle, JniHandleOwnership.TransferLocalRef);"); } else if (field.Symbol.NativeType != field.Symbol.FullName) { writer.WriteLine($"return {field.Symbol.ReturnCast}{(field.Symbol.FromNative (opt, invokeType != "Object" ? "__v" : "__v.Handle", true) + opt.GetNullForgiveness (field))};"); } else { writer.WriteLine("return __v;"); } }
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" : "")});"); }
void AddInheritedInterfaces(InterfaceGen iface, CodeGenerationOptions opt) { foreach (var isym in iface.Interfaces) { var igen = (isym is GenericSymbol ? (isym as GenericSymbol).Gen : isym) as InterfaceGen; // igen *should not* be null here because we *should* only be inheriting interfaces, but // in the case of constants on that interface we create a C# *class* that is registered for the // Java *interface*. Thus when we do type resolution, we are actually pointed to the // Foo abstract class instead of the IFoo interface. if (igen is null || igen.IsConstSugar(opt) || igen.RawVisibility != "public") { continue; } Implements.Add(opt.GetOutputName(isym.FullName)); } if (Implements.Count == 0 && !iface.IsConstSugar(opt)) { if (opt.CodeGenerationTarget != CodeGenerationTarget.JavaInterop1) { Implements.Add("IJavaObject"); } Implements.Add("IJavaPeerable"); } }
public WeakImplementorField(string name, CodeGenerationOptions opt) { Name = "weak_implementor_" + name; Type = new TypeReferenceWriter(opt.GetOutputName("WeakReference")) { Nullable = opt.SupportNullableReferenceTypes }; }
public InterfaceListenerPropertyImplementor(InterfaceGen iface, string name, CodeGenerationOptions opt) { this.name = name; this.opt = opt; Name = "Impl" + name; PropertyType = new TypeReferenceWriter(opt.GetOutputName(iface.FullName) + "Implementor") { Nullable = opt.SupportNullableReferenceTypes }; HasGet = true; GetBody.Add($"if (weak_implementor_{name} == null || !weak_implementor_{name}.IsAlive)"); GetBody.Add($"\treturn null;"); GetBody.Add($"return weak_implementor_{name}.Target as {opt.GetOutputName (iface.FullName)}Implementor;"); HasSet = true; SetBody.Add($"weak_implementor_{name} = new WeakReference (value, true);"); }
void AddImplementedInterfaces(ClassGen klass) { foreach (var isym in klass.Interfaces) { if ((!(isym is GenericSymbol gs) ? isym : gs.Gen) is InterfaceGen gen && (gen.IsConstSugar || gen.RawVisibility != "public")) { continue; } Implements.Add(opt.GetOutputName(isym.FullName)); } }
public GenericExplicitInterfaceImplementationProperty(Property property, GenericSymbol gen, string adapter, Dictionary <string, string> mappings, CodeGenerationOptions opt) { Name = property.AdjustedName; PropertyType = new TypeReferenceWriter(opt.GetTypeReferenceName(property)); ExplicitInterfaceImplementation = opt.GetOutputName(gen.Gen.FullName); Comments.Add($"// This method is explicitly implemented as a member of an instantiated {gen.FullName}"); if (property.Getter != null) { HasGet = true; if (gen.Gen.IsGeneratable) { GetterComments.Add($"// Metadata.xml XPath method reference: path=\"{gen.Gen.MetadataXPathReference}/method[@name='{property.Getter.JavaName}'{property.Getter.Parameters.GetMethodXPathPredicate ()}]\""); } if (property.Getter.GenericArguments != null && property.Getter.GenericArguments.Any()) { GetterAttributes.Add(new CustomAttr(property.Getter.GenericArguments.ToGeneratedAttributeString())); } SourceWriterExtensions.AddSupportedOSPlatform(GetterAttributes, property.Getter, opt); GetterAttributes.Add(new RegisterAttr(property.Getter.JavaName, property.Getter.JniSignature, property.Getter.ConnectorName + ":" + property.Getter.GetAdapterName(opt, adapter), additionalProperties: property.Getter.AdditionalAttributeString())); GetBody.Add($"return {property.Name};"); } if (property.Setter != null) { HasSet = true; if (gen.Gen.IsGeneratable) { SetterComments.Add($"// Metadata.xml XPath method reference: path=\"{gen.Gen.MetadataXPathReference}/method[@name='{property.Setter.JavaName}'{property.Setter.Parameters.GetMethodXPathPredicate ()}]\""); } if (property.Setter.GenericArguments != null && property.Setter.GenericArguments.Any()) { SetterAttributes.Add(new CustomAttr(property.Setter.GenericArguments.ToGeneratedAttributeString())); } SourceWriterExtensions.AddSupportedOSPlatform(SetterAttributes, property.Setter, opt); SetterAttributes.Add(new RegisterAttr(property.Setter.JavaName, property.Setter.JniSignature, property.Setter.ConnectorName + ":" + property.Setter.GetAdapterName(opt, adapter), additionalProperties: property.Setter.AdditionalAttributeString())); // Temporarily rename the parameter to "value" var pname = property.Setter.Parameters [0].Name; property.Setter.Parameters [0].Name = "value"; SetBody.Add($"{property.Name} = {property.Setter.Parameters.GetGenericCall (opt, mappings)};"); property.Setter.Parameters [0].Name = pname; } }
public MethodExplicitInterfaceImplementation(GenBase iface, Method method, CodeGenerationOptions opt) { this.method = method; this.opt = opt; Name = method.Name; ReturnType = new TypeReferenceWriter(opt.GetTypeReferenceName(method.RetVal)); ExplicitInterfaceImplementation = opt.GetOutputName(iface.FullName); SourceWriterExtensions.AddMethodCustomAttributes(Attributes, method); this.AddMethodParameters(method.Parameters, opt); }
public BoundMethodAbstractDeclaration(GenBase gen, Method method, CodeGenerationOptions opt, GenBase impl) { this.method = method; this.opt = opt; ReturnType = new TypeReferenceWriter(opt.GetTypeReferenceName(method.RetVal)); this.AddMethodParameters(method.Parameters, opt); if (method.RetVal.IsGeneric && gen != null) { Name = method.Name; ExplicitInterfaceImplementation = opt.GetOutputName(gen.FullName); SourceWriterExtensions.AddMethodCustomAttributes(Attributes, method); Body.Add("throw new NotImplementedException ();"); return; } Name = method.AdjustedName; IsAbstract = true; IsShadow = impl.RequiresNew(method.Name, method); SetVisibility(method.Visibility); NewFirst = true; if (opt.CodeGenerationTarget != CodeGenerationTarget.JavaInterop1) { method_callback = new MethodCallback(impl, method, opt, null, method.IsReturnCharSequence); } method.JavadocInfo?.AddJavadocs(Comments); if (method.DeclaringType.IsGeneratable) { Comments.Add($"// Metadata.xml XPath method reference: path=\"{method.GetMetadataXPathReference (method.DeclaringType)}\""); } SourceWriterExtensions.AddSupportedOSPlatform(Attributes, method, opt); if (opt.CodeGenerationTarget != CodeGenerationTarget.JavaInterop1) { Attributes.Add(new RegisterAttr(method.JavaName, method.JniSignature, method.ConnectorName, additionalProperties: method.AdditionalAttributeString())); } SourceWriterExtensions.AddMethodCustomAttributes(Attributes, method); }
public ExplicitInterfaceInvokerMethod(GenBase iface, Method method, CodeGenerationOptions opt) { this.method = method; this.opt = opt; Name = method.Name; IsUnsafe = true; ReturnType = new TypeReferenceWriter(opt.GetTypeReferenceName(method.RetVal)); ExplicitInterfaceImplementation = opt.GetOutputName(iface.FullName); this.AddMethodParameters(method.Parameters, opt); SourceWriterExtensions.AddMethodBody(Body, method, opt); }
public GenericExplicitInterfaceImplementationMethod(Method method, GenericSymbol gen, CodeGenerationOptions opt) { this.method = method; this.opt = opt; this.gen = gen; Name = method.Name; ReturnType = new TypeReferenceWriter(opt.GetTypeReferenceName(method.RetVal)); ExplicitInterfaceImplementation = opt.GetOutputName(gen.Gen.FullName); Comments.Add($"// This method is explicitly implemented as a member of an instantiated {gen.FullName}"); SourceWriterExtensions.AddMethodCustomAttributes(Attributes, method); this.AddMethodParameters(method.Parameters, opt); }
protected override void WriteBody(CodeWriter writer) { writer.WriteLine($"var __this = global::Java.Lang.Object.GetObject<{opt.GetOutputName (type.FullName)}> (jnienv, native__this, JniHandleOwnership.DoNotTransfer){opt.NullForgivingOperator};"); foreach (var s in method.Parameters.GetCallbackPrep(opt)) { writer.WriteLine(s); } if (string.IsNullOrEmpty(property_name)) { var call = "__this." + method.Name + (is_formatted ? "Formatted" : string.Empty) + " (" + method.Parameters.GetCall(opt) + ")"; if (method.IsVoid) { writer.WriteLine(call + ";"); } else { writer.WriteLine("{0} {1};", method.Parameters.HasCleanup ? method.RetVal.NativeType + " __ret =" : "return", method.RetVal.ToNative(opt, call)); } } else { if (method.IsVoid) { writer.WriteLine("__this.{0} = {1};", property_name, method.Parameters.GetCall(opt)); } else { writer.WriteLine("{0} {1};", method.Parameters.HasCleanup ? method.RetVal.NativeType + " __ret =" : "return", method.RetVal.ToNative(opt, "__this." + property_name)); } } foreach (var cleanup in method.Parameters.GetCallbackCleanup(opt)) { writer.WriteLine(cleanup); } if (!method.IsVoid && method.Parameters.HasCleanup) { writer.WriteLine("return __ret;"); } }
void AddInheritedInterfaces(InterfaceGen iface, CodeGenerationOptions opt) { foreach (var isym in iface.Interfaces) { var igen = (isym is GenericSymbol ? (isym as GenericSymbol).Gen : isym) as InterfaceGen; if (igen.IsConstSugar(opt) || igen.RawVisibility != "public") { continue; } Implements.Add(opt.GetOutputName(isym.FullName)); } if (Implements.Count == 0 && !iface.IsConstSugar(opt)) { Implements.AddRange(new [] { "IJavaObject", "IJavaPeerable" }); } }
public ClassInvokerClass(ClassGen klass, CodeGenerationOptions opt) { Name = $"{klass.Name}Invoker"; IsInternal = true; IsPartial = true; UsePriorityOrder = true; Inherits = klass.Name; foreach (var igen in klass.GetAllDerivedInterfaces().Where(i => i.IsGeneric)) { Implements.Add(opt.GetOutputName(igen.FullName)); } Attributes.Add(new RegisterAttr(klass.RawJniName, noAcw: true, additionalProperties: klass.AdditionalAttributeString()) { UseGlobal = true }); var ctor = new ConstructorWriter { Name = Name, IsPublic = true, BaseCall = "base (handle, transfer)" }; ctor.Parameters.Add(new MethodParameterWriter("handle", TypeReferenceWriter.IntPtr)); ctor.Parameters.Add(new MethodParameterWriter("transfer", new TypeReferenceWriter("JniHandleOwnership"))); Constructors.Add(ctor); // ClassInvokerHandle Fields.Add(new PeerMembersField(opt, klass.RawJniName, $"{klass.Name}Invoker", false)); Properties.Add(new JniPeerMembersGetter()); Properties.Add(new ThresholdTypeGetter()); AddMemberInvokers(klass, opt, new HashSet <string> ()); }
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);"); }
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 BoundClass(ClassGen klass, CodeGenerationOptions opt, CodeGeneratorContext context, GenerationInfo generationInfo) { context.ContextTypes.Push(klass); context.ContextGeneratedMethods = new List <Method> (); generationInfo.TypeRegistrations.Add(new KeyValuePair <string, string> (klass.RawJniName, klass.AssemblyQualifiedName)); var is_enum = klass.base_symbol != null && klass.base_symbol.FullName == "Java.Lang.Enum"; if (is_enum) { generationInfo.Enums.Add(klass.RawJniName.Replace('/', '.') + ":" + klass.Namespace + ":" + klass.JavaSimpleName); } this.opt = opt; Name = klass.Name; SetVisibility(klass.Visibility); IsShadow = klass.NeedsNew; IsAbstract = klass.IsAbstract; IsSealed = klass.IsFinal; IsPartial = true; UsePriorityOrder = true; AddImplementedInterfaces(klass); Comments.Add($"// Metadata.xml XPath class reference: path=\"{klass.MetadataXPathReference}\""); if (klass.IsDeprecated) { Attributes.Add(new ObsoleteAttr(klass.DeprecatedComment) { WriteAttributeSuffix = true }); } Attributes.Add(new RegisterAttr(klass.RawJniName, null, null, true, klass.AdditionalAttributeString()) { UseGlobal = true, UseShortForm = true }); if (klass.TypeParameters != null && klass.TypeParameters.Any()) { Attributes.Add(new CustomAttr(klass.TypeParameters.ToGeneratedAttributeString())); } // Figure out our base class string obj_type = null; if (klass.base_symbol != null) { obj_type = klass.base_symbol is GenericSymbol gs && gs.IsConcrete ? gs.GetGenericType(null) : opt.GetOutputName(klass.base_symbol.FullName); } if (klass.InheritsObject && obj_type != null) { Inherits = obj_type; } // Handle fields var seen = new HashSet <string> (); SourceWriterExtensions.AddFields(this, klass, klass.Fields, seen, opt, context); var ic = new InterfaceConstsClass(klass, seen, opt, context); if (ic.ShouldGenerate) { NestedTypes.Add(ic); } // Sibling classes if (!klass.AssemblyQualifiedName.Contains('/')) { foreach (InterfaceExtensionInfo nestedIface in klass.GetNestedInterfaceTypes()) { if (nestedIface.Type.Methods.Any(m => m.CanHaveStringOverload) || nestedIface.Type.Methods.Any(m => m.Asyncify)) { sibling_types.Add(new InterfaceExtensionsClass(nestedIface.Type, nestedIface.DeclaringType, opt)); } } } if (klass.IsAbstract) { sibling_types.Add(new ClassInvokerClass(klass, opt)); } AddNestedTypes(klass, opt, context, generationInfo); AddBindingInfrastructure(klass); AddConstructors(klass, opt, context); AddProperties(klass, opt); AddMethods(klass, opt, context); AddAbstractMembers(klass, opt, context); AddExplicitGenericInterfaceMembers(klass, opt); AddCharSequenceEnumerator(klass); context.ContextGeneratedMethods.Clear(); context.ContextTypes.Pop(); }
public ClassInvokerClass(ClassGen klass, CodeGenerationOptions opt) { Name = $"{klass.Name}Invoker"; IsInternal = true; IsPartial = true; UsePriorityOrder = true; Inherits = klass.Name; foreach (var igen in klass.GetAllDerivedInterfaces().Where(i => i.IsGeneric)) { Implements.Add(opt.GetOutputName(igen.FullName)); } if (opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1) { Attributes.Add(new JniTypeSignatureAttr(klass.RawJniName, false)); } else { Attributes.Add(new RegisterAttr(klass.RawJniName, noAcw: true, additionalProperties: klass.AdditionalAttributeString()) { UseGlobal = true }); } SourceWriterExtensions.AddSupportedOSPlatform(Attributes, klass, opt); ConstructorWriter ctor = opt.CodeGenerationTarget == CodeGenerationTarget.JavaInterop1 ? new ConstructorWriter { Name = Name, IsPublic = true, BaseCall = "base (ref reference, options)", Parameters = { new MethodParameterWriter("reference", new TypeReferenceWriter("ref JniObjectReference")), new MethodParameterWriter("options", new TypeReferenceWriter("JniObjectReferenceOptions")), }, } : new ConstructorWriter { Name = Name, IsPublic = true, BaseCall = "base (handle, transfer)", Parameters = { new MethodParameterWriter("handle", TypeReferenceWriter.IntPtr), new MethodParameterWriter("transfer", new TypeReferenceWriter("JniHandleOwnership")), }, } ; Constructors.Add(ctor); // ClassInvokerHandle Fields.Add(new PeerMembersField(opt, klass.RawJniName, $"{klass.Name}Invoker", false)); Properties.Add(new JniPeerMembersGetter()); if (opt.CodeGenerationTarget != CodeGenerationTarget.JavaInterop1) { Properties.Add(new ThresholdTypeGetter()); } AddMemberInvokers(klass, opt, new HashSet <string> ()); }
public void GetOutputNameUseGlobal() { var opt = new CodeGenerationOptions { UseGlobal = true }; Assert.AreEqual(string.Empty, opt.GetOutputName(string.Empty)); Assert.AreEqual("int", opt.GetOutputName("int")); Assert.AreEqual("void", opt.GetOutputName("void")); Assert.AreEqual("void", opt.GetOutputName("System.Void")); Assert.AreEqual("params int[]", opt.GetOutputName("params int[]")); Assert.AreEqual("params global::System.Object[]", opt.GetOutputName("params System.Object[]")); Assert.AreEqual("int[][][]", opt.GetOutputName("int[][][]")); Assert.AreEqual("global::System.Object[][][]", opt.GetOutputName("System.Object[][][]")); Assert.AreEqual("global::System.Collections.Generic.List<string[]>", opt.GetOutputName("System.Collections.Generic.List<string[]>")); Assert.AreEqual("global::System.Collections.Generic.Dictionary<string, string>", opt.GetOutputName("System.Collections.Generic.Dictionary<string, string>")); Assert.AreEqual("global::System.Collections.Generic.List<global::System.Collections.Generic.List<string>>", opt.GetOutputName("System.Collections.Generic.List<System.Collections.Generic.List<string>>")); Assert.AreEqual("global::System.Collections.Generic.List<global::System.Collections.Generic.Dictionary<string, global::System.Collections.Generic.Dictionary<global::System.Object, global::System.Object>>>", opt.GetOutputName("System.Collections.Generic.List<System.Collections.Generic.Dictionary<string, System.Collections.Generic.Dictionary<System.Object, System.Object>>>")); Assert.AreEqual("global::System.Collections.Generic.IList<global::Kotlin.Pair>", opt.GetOutputName("System.Collections.Generic.IList<Kotlin.Pair>")); Assert.AreEqual("global::System.Collections.Generic.IDictionary<string, global::System.Collections.Generic.IList<global::Kotlin.Pair>>", opt.GetOutputName("System.Collections.Generic.IDictionary<string, System.Collections.Generic.IList<Kotlin.Pair>>")); Assert.AreEqual("global::System.Collections.Generic.IDictionary<global::System.Collections.Generic.IList<string>, global::Kotlin.Pair>", opt.GetOutputName("System.Collections.Generic.IDictionary<System.Collections.Generic.IList<string>, Kotlin.Pair>")); Assert.AreEqual("global::System.Collections.Generic.IDictionary<global::System.Collections.Generic.IList<string>, global::System.Collections.Generic.IList<global::Kotlin.Pair>>", opt.GetOutputName("System.Collections.Generic.IDictionary<System.Collections.Generic.IList<string>, System.Collections.Generic.IList<Kotlin.Pair>>")); Assert.AreEqual("global::System.Collections.Generic.List<global::System.Collections.Generic.List<string>[]>[]", opt.GetOutputName("System.Collections.Generic.List<System.Collections.Generic.List<string>[]>[]")); Assert.AreEqual("global::System.Collections.Generic.List<global::System.Collections.Generic.List<string>.Enumerator[]>", opt.GetOutputName("System.Collections.Generic.List<System.Collections.Generic.List<string>.Enumerator[]>")); }