From f1c9fc49f895cc089919510bc759eb353eb90a64 Mon Sep 17 00:00:00 2001 From: Hossein Yousefi Date: Tue, 13 Jun 2023 15:20:15 +0200 Subject: [PATCH] Non static nested class construction (#297) Construct the non-static nested classes correctly --- .../apisummarizer/disasm/TypeUtils.java | 6 +- jnigen/lib/src/bindings/c_generator.dart | 9 +- jnigen/lib/src/bindings/dart_generator.dart | 4 +- jnigen/lib/src/bindings/linker.dart | 15 +--- jnigen/lib/src/bindings/renamer.dart | 9 +- jnigen/lib/src/bindings/unnester.dart | 83 +++++++++++++++++++ jnigen/lib/src/config/config_types.dart | 3 +- jnigen/lib/src/elements/elements.dart | 6 +- jnigen/lib/src/generate_bindings.dart | 2 + .../c_based/c_bindings/simple_package.c | 38 +++++---- .../c_based/dart_bindings/simple_package.dart | 70 ++++++++-------- .../dart_bindings/simple_package.dart | 68 ++++++++------- .../jnigen/generics/GrandParent.java | 18 ++-- .../runtime_test_registrant.dart | 16 ++++ 14 files changed, 232 insertions(+), 115 deletions(-) create mode 100644 jnigen/lib/src/bindings/unnester.dart diff --git a/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/disasm/TypeUtils.java b/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/disasm/TypeUtils.java index 7cb6f1e9..521c02d5 100644 --- a/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/disasm/TypeUtils.java +++ b/jnigen/java/src/main/java/com/github/dart_lang/jnigen/apisummarizer/disasm/TypeUtils.java @@ -20,7 +20,11 @@ class TypeUtils { public static String parentName(Type type) { - return type.getClassName().split("\\$")[0]; + var className = type.getClassName(); + if (!className.contains("$")) { + return null; + } + return className.split("\\$")[0]; } public static String simpleName(Type type) { diff --git a/jnigen/lib/src/bindings/c_generator.dart b/jnigen/lib/src/bindings/c_generator.dart index 7ca6ef11..dedef766 100644 --- a/jnigen/lib/src/bindings/c_generator.dart +++ b/jnigen/lib/src/bindings/c_generator.dart @@ -390,9 +390,12 @@ class _CParamGenerator extends Visitor { @override String visit(Param node) { final paramName = - _cTypeKeywords.contains(node.name) ? '${node.name}0' : node.name; - final type = node.type.accept(const _CReturnType()); - if (addReturnType) return '$type $paramName'; + (_cTypeKeywords.contains(node.name) ? '${node.name}0' : node.name) + .replaceAll('\$', '_'); + if (addReturnType) { + final type = node.type.accept(const _CReturnType()); + return '$type $paramName'; + } return paramName; } } diff --git a/jnigen/lib/src/bindings/dart_generator.dart b/jnigen/lib/src/bindings/dart_generator.dart index a1559cf3..2854e6be 100644 --- a/jnigen/lib/src/bindings/dart_generator.dart +++ b/jnigen/lib/src/bindings/dart_generator.dart @@ -333,7 +333,7 @@ class _ClassGenerator extends Visitor { .map((typeParam) => 'this.$typeParam,') .join(_newLine(depth: 2)); final superClass = (node.classDecl.superclass!.type as DeclaredType); - final superTypeClassesCall = superClass.classDecl.isObject() + final superTypeClassesCall = superClass.classDecl.isObject ? '' : superClass.params .accept(_TypeClassGenerator(resolver)) @@ -1331,7 +1331,7 @@ class _TypeVarLocator extends TypeVisitor>> { @override Map> visitDeclaredType(DeclaredType node) { - if (node.classDecl.isObject()) { + if (node.classDecl.isObject) { return {}; } final offset = node.classDecl.allTypeParams.length - node.params.length; diff --git a/jnigen/lib/src/bindings/linker.dart b/jnigen/lib/src/bindings/linker.dart index cdddaf54..d6b44a5f 100644 --- a/jnigen/lib/src/bindings/linker.dart +++ b/jnigen/lib/src/bindings/linker.dart @@ -92,20 +92,7 @@ class _ClassLinker extends Visitor { log.finest('Linking ${node.binaryName}.'); _linked.add(node); - node.parent = resolve(node.parentName); - node.parent!.accept(this); - // Add type params of outer classes to the nested classes - final allTypeParams = []; - if (!node.modifiers.contains('static')) { - for (final typeParam in node.parent!.allTypeParams) { - if (!node.allTypeParams.contains(typeParam)) { - // Add only if it's not shadowing another type param. - allTypeParams.add(typeParam); - } - } - } - allTypeParams.addAll(node.typeParams); - node.allTypeParams = allTypeParams; + node.parent = node.parentName == null ? null : resolve(node.parentName); final typeLinker = _TypeLinker(resolve); node.superclass ??= TypeUsage.object; diff --git a/jnigen/lib/src/bindings/renamer.dart b/jnigen/lib/src/bindings/renamer.dart index d5f9a733..607216ea 100644 --- a/jnigen/lib/src/bindings/renamer.dart +++ b/jnigen/lib/src/bindings/renamer.dart @@ -65,6 +65,7 @@ const Set _keywords = { 'throw', 'true', 'try', + 'type', // Is used for type classes. 'typedef', 'var', 'void', @@ -213,8 +214,8 @@ class _MethodRenamer implements Visitor { node.finalName = _renameConflict(nameCounts, name); node.classDecl.methodNumsAfterRenaming[sig] = nameCounts[name]! - 1; } - log.fine( - 'Method ${node.classDecl.binaryName}#${node.name} is named ${node.finalName}'); + log.fine('Method ${node.classDecl.binaryName}#${node.name}' + ' is named ${node.finalName}'); final paramRenamer = _ParamRenamer(config); for (final param in node.params) { @@ -242,8 +243,8 @@ class _FieldRenamer implements Visitor { nameCounts, node.name, ); - log.fine( - 'Field ${node.classDecl.binaryName}#${node.name} is named ${node.finalName}'); + log.fine('Field ${node.classDecl.binaryName}#${node.name}' + ' is named ${node.finalName}'); } } diff --git a/jnigen/lib/src/bindings/unnester.dart b/jnigen/lib/src/bindings/unnester.dart new file mode 100644 index 00000000..00522051 --- /dev/null +++ b/jnigen/lib/src/bindings/unnester.dart @@ -0,0 +1,83 @@ +// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +import '../elements/elements.dart'; +import 'visitor.dart'; + +/// A [Visitor] that processes nested classes. +/// +/// Nested classes are not supported in Dart. So this "unnests" them into +/// separate classes. +class Unnester extends Visitor { + @override + void visit(node) { + final classProcessor = _ClassUnnester(); + for (final classDecl in node.decls.values) { + classDecl.accept(classProcessor); + } + } +} + +class _ClassUnnester extends Visitor { + final processed = {}; + + @override + void visit(ClassDecl node) { + if (processed.contains(node)) return; + processed.add(node); + // We need to visit the ancestors first. + node.parent?.accept(this); + + // Add type params of outer classes to the nested classes. + final allTypeParams = []; + if (!node.isStatic) { + allTypeParams.addAll(node.parent?.allTypeParams ?? []); + } + allTypeParams.addAll(node.typeParams); + node.allTypeParams = allTypeParams; + + if (node.isNested && !node.isStatic) { + const methodProcessor = _MethodUnnester(); + for (final method in node.methods) { + method.accept(methodProcessor); + } + } + } +} + +class _MethodUnnester extends Visitor { + const _MethodUnnester(); + + @override + void visit(Method node) { + assert(!node.classDecl.isStatic); + assert(node.classDecl.isNested); + if (node.isCtor || node.isStatic) { + // Non-static nested classes take an instance of their outer class as the + // first parameter. This is not accounted for by the summarizer, so we + // manually add it as the first parameter. + final parentTypeParamCount = node.classDecl.allTypeParams.length - + node.classDecl.typeParams.length; + final parentTypeParams = [ + for (final typeParam + in node.classDecl.allTypeParams.take(parentTypeParamCount)) ...[ + TypeUsage( + shorthand: typeParam.name, kind: Kind.typeVariable, typeJson: {}) + ..type = TypeVar(name: typeParam.name), + ] + ]; + final parentType = DeclaredType( + binaryName: node.classDecl.parent!.binaryName, + params: parentTypeParams, + )..classDecl = node.classDecl.parent!; + final parentTypeUsage = TypeUsage( + shorthand: parentType.binaryName, kind: Kind.declared, typeJson: {}) + ..type = parentType; + final param = Param(name: '\$parent', type: parentTypeUsage); + // Make the list modifiable. + if (node.params.isEmpty) node.params = []; + node.params.insert(0, param); + } + } +} diff --git a/jnigen/lib/src/config/config_types.dart b/jnigen/lib/src/config/config_types.dart index 63a418c2..58fc9a51 100644 --- a/jnigen/lib/src/config/config_types.dart +++ b/jnigen/lib/src/config/config_types.dart @@ -401,7 +401,8 @@ class Config { ..finalName = decl['name'] ..typeClassName = decl['type_class'] ..superCount = decl['super_count'] - ..allTypeParams = []; + ..allTypeParams = [] + ..parent = null; for (final typeParamEntry in ((decl['type_params'] as YamlMap?)?.entries) ?? >[]) { diff --git a/jnigen/lib/src/elements/elements.dart b/jnigen/lib/src/elements/elements.dart index 15f2f451..51c19b95 100644 --- a/jnigen/lib/src/elements/elements.dart +++ b/jnigen/lib/src/elements/elements.dart @@ -167,7 +167,9 @@ class ClassDecl extends ClassMember implements Element { @override String get name => finalName; - bool isObject() => superCount == 0; + bool get isObject => superCount == 0; + + bool get isNested => parentName != null; } @JsonEnum() @@ -455,7 +457,7 @@ class Method extends ClassMember implements Element { final List annotations; final JavaDocComment? javadoc; final List typeParams; - final List params; + List params; final TypeUsage returnType; /// The [ClassDecl] where this method is defined. diff --git a/jnigen/lib/src/generate_bindings.dart b/jnigen/lib/src/generate_bindings.dart index 5c9dc9be..87727dce 100644 --- a/jnigen/lib/src/generate_bindings.dart +++ b/jnigen/lib/src/generate_bindings.dart @@ -9,6 +9,7 @@ import 'bindings/c_generator.dart'; import 'bindings/dart_generator.dart'; import 'bindings/excluder.dart'; import 'bindings/linker.dart'; +import 'bindings/unnester.dart'; import 'bindings/renamer.dart'; import 'elements/elements.dart'; import 'summary/summary.dart'; @@ -36,6 +37,7 @@ Future generateJniBindings(Config config) async { classes.accept(Excluder(config)); await classes.accept(Linker(config)); + classes.accept(Unnester()); classes.accept(Renamer(config)); final cBased = config.outputConfig.bindingsType == BindingsType.cBased; diff --git a/jnigen/test/simple_package_test/c_based/c_bindings/simple_package.c b/jnigen/test/simple_package_test/c_based/c_bindings/simple_package.c index e388ec77..4a170e76 100644 --- a/jnigen/test/simple_package_test/c_based/c_bindings/simple_package.c +++ b/jnigen/test/simple_package_test/c_based/c_bindings/simple_package.c @@ -1513,7 +1513,7 @@ jclass _c_GrandParent_Parent = NULL; jmethodID _m_GrandParent_Parent__ctor = NULL; FFI_PLUGIN_EXPORT -JniResult GrandParent_Parent__ctor(jobject parentValue, jobject value) { +JniResult GrandParent_Parent__ctor(jobject _parent, jobject newValue) { load_env(); load_class_global_ref( &_c_GrandParent_Parent, @@ -1521,12 +1521,13 @@ JniResult GrandParent_Parent__ctor(jobject parentValue, jobject value) { if (_c_GrandParent_Parent == NULL) return (JniResult){.value = {.j = 0}, .exception = check_exception()}; load_method(_c_GrandParent_Parent, &_m_GrandParent_Parent__ctor, "", - "(Ljava/lang/Object;Ljava/lang/Object;)V"); + "(Lcom/github/dart_lang/jnigen/generics/GrandParent;Ljava/lang/" + "Object;)V"); if (_m_GrandParent_Parent__ctor == NULL) return (JniResult){.value = {.j = 0}, .exception = check_exception()}; jobject _result = (*jniEnv)->NewObject(jniEnv, _c_GrandParent_Parent, - _m_GrandParent_Parent__ctor, parentValue, value); + _m_GrandParent_Parent__ctor, _parent, newValue); return to_global_ref_result(_result); } @@ -1596,9 +1597,7 @@ jclass _c_GrandParent_Parent_Child = NULL; jmethodID _m_GrandParent_Parent_Child__ctor = NULL; FFI_PLUGIN_EXPORT -JniResult GrandParent_Parent_Child__ctor(jobject grandParentValue, - jobject parentValue, - jobject value) { +JniResult GrandParent_Parent_Child__ctor(jobject _parent, jobject newValue) { load_env(); load_class_global_ref( &_c_GrandParent_Parent_Child, @@ -1607,12 +1606,13 @@ JniResult GrandParent_Parent_Child__ctor(jobject grandParentValue, return (JniResult){.value = {.j = 0}, .exception = check_exception()}; load_method(_c_GrandParent_Parent_Child, &_m_GrandParent_Parent_Child__ctor, "", - "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V"); + "(Lcom/github/dart_lang/jnigen/generics/GrandParent$Parent;Ljava/" + "lang/Object;)V"); if (_m_GrandParent_Parent_Child__ctor == NULL) return (JniResult){.value = {.j = 0}, .exception = check_exception()}; jobject _result = (*jniEnv)->NewObject(jniEnv, _c_GrandParent_Parent_Child, _m_GrandParent_Parent_Child__ctor, - grandParentValue, parentValue, value); + _parent, newValue); return to_global_ref_result(_result); } @@ -1773,7 +1773,8 @@ jclass _c_GrandParent_StaticParent_Child = NULL; jmethodID _m_GrandParent_StaticParent_Child__ctor = NULL; FFI_PLUGIN_EXPORT -JniResult GrandParent_StaticParent_Child__ctor(jobject parentValue, +JniResult GrandParent_StaticParent_Child__ctor(jobject _parent, + jobject parentValue, jobject value) { load_env(); load_class_global_ref( @@ -1781,14 +1782,16 @@ JniResult GrandParent_StaticParent_Child__ctor(jobject parentValue, "com/github/dart_lang/jnigen/generics/GrandParent$StaticParent$Child"); if (_c_GrandParent_StaticParent_Child == NULL) return (JniResult){.value = {.j = 0}, .exception = check_exception()}; - load_method(_c_GrandParent_StaticParent_Child, - &_m_GrandParent_StaticParent_Child__ctor, "", - "(Ljava/lang/Object;Ljava/lang/Object;)V"); + load_method( + _c_GrandParent_StaticParent_Child, + &_m_GrandParent_StaticParent_Child__ctor, "", + "(Lcom/github/dart_lang/jnigen/generics/GrandParent$StaticParent;Ljava/" + "lang/Object;Ljava/lang/Object;)V"); if (_m_GrandParent_StaticParent_Child__ctor == NULL) return (JniResult){.value = {.j = 0}, .exception = check_exception()}; jobject _result = (*jniEnv)->NewObject( jniEnv, _c_GrandParent_StaticParent_Child, - _m_GrandParent_StaticParent_Child__ctor, parentValue, value); + _m_GrandParent_StaticParent_Child__ctor, _parent, parentValue, value); return to_global_ref_result(_result); } @@ -1934,18 +1937,19 @@ jclass _c_MyMap_MyEntry = NULL; jmethodID _m_MyMap_MyEntry__ctor = NULL; FFI_PLUGIN_EXPORT -JniResult MyMap_MyEntry__ctor(jobject key, jobject value) { +JniResult MyMap_MyEntry__ctor(jobject _parent, jobject key, jobject value) { load_env(); load_class_global_ref(&_c_MyMap_MyEntry, "com/github/dart_lang/jnigen/generics/MyMap$MyEntry"); if (_c_MyMap_MyEntry == NULL) return (JniResult){.value = {.j = 0}, .exception = check_exception()}; load_method(_c_MyMap_MyEntry, &_m_MyMap_MyEntry__ctor, "", - "(Ljava/lang/Object;Ljava/lang/Object;)V"); + "(Lcom/github/dart_lang/jnigen/generics/MyMap;Ljava/lang/" + "Object;Ljava/lang/Object;)V"); if (_m_MyMap_MyEntry__ctor == NULL) return (JniResult){.value = {.j = 0}, .exception = check_exception()}; - jobject _result = (*jniEnv)->NewObject(jniEnv, _c_MyMap_MyEntry, - _m_MyMap_MyEntry__ctor, key, value); + jobject _result = (*jniEnv)->NewObject( + jniEnv, _c_MyMap_MyEntry, _m_MyMap_MyEntry__ctor, _parent, key, value); return to_global_ref_result(_result); } diff --git a/jnigen/test/simple_package_test/c_based/dart_bindings/simple_package.dart b/jnigen/test/simple_package_test/c_based/dart_bindings/simple_package.dart index 5cdec376..4e16f1e8 100644 --- a/jnigen/test/simple_package_test/c_based/dart_bindings/simple_package.dart +++ b/jnigen/test/simple_package_test/c_based/dart_bindings/simple_package.dart @@ -1578,22 +1578,22 @@ class GrandParent_Parent<$T extends jni.JObject, $S extends jni.JObject> jni.JniResult Function( ffi.Pointer, ffi.Pointer)>(); - /// from: public void (T parentValue, S value) + /// from: public void (com.github.dart_lang.jnigen.generics.GrandParent $parent, S newValue) /// The returned object must be deleted after use, by calling the `delete` method. factory GrandParent_Parent( - $T parentValue, - $S value, { + GrandParent<$T> $parent, + $S newValue, { jni.JObjType<$T>? T, jni.JObjType<$S>? S, }) { T ??= jni.lowestCommonSuperType([ - parentValue.$type, + ($parent.$type as $GrandParentType).T, ]) as jni.JObjType<$T>; S ??= jni.lowestCommonSuperType([ - value.$type, + newValue.$type, ]) as jni.JObjType<$S>; return GrandParent_Parent.fromRef( - T, S, _ctor(parentValue.reference, value.reference).object); + T, S, _ctor($parent.reference, newValue.reference).object); } } @@ -1747,40 +1747,32 @@ class GrandParent_Parent_Child<$T extends jni.JObject, $S extends jni.JObject, static final _ctor = jniLookup< ffi.NativeFunction< - jni.JniResult Function( - ffi.Pointer, - ffi.Pointer, + jni.JniResult Function(ffi.Pointer, ffi.Pointer)>>("GrandParent_Parent_Child__ctor") .asFunction< - jni.JniResult Function(ffi.Pointer, ffi.Pointer, - ffi.Pointer)>(); + jni.JniResult Function( + ffi.Pointer, ffi.Pointer)>(); - /// from: public void (T grandParentValue, S parentValue, U value) + /// from: public void (com.github.dart_lang.jnigen.generics.GrandParent$Parent $parent, U newValue) /// The returned object must be deleted after use, by calling the `delete` method. factory GrandParent_Parent_Child( - $T grandParentValue, - $S parentValue, - $U value, { + GrandParent_Parent<$T, $S> $parent, + $U newValue, { jni.JObjType<$T>? T, jni.JObjType<$S>? S, jni.JObjType<$U>? U, }) { T ??= jni.lowestCommonSuperType([ - grandParentValue.$type, + ($parent.$type as $GrandParent_ParentType).T, ]) as jni.JObjType<$T>; S ??= jni.lowestCommonSuperType([ - parentValue.$type, + ($parent.$type as $GrandParent_ParentType).S, ]) as jni.JObjType<$S>; U ??= jni.lowestCommonSuperType([ - value.$type, + newValue.$type, ]) as jni.JObjType<$U>; return GrandParent_Parent_Child.fromRef( - T, - S, - U, - _ctor(grandParentValue.reference, parentValue.reference, - value.reference) - .object); + T, S, U, _ctor($parent.reference, newValue.reference).object); } } @@ -2006,16 +1998,17 @@ class GrandParent_StaticParent_Child<$S extends jni.JObject, static final _ctor = jniLookup< ffi.NativeFunction< - jni.JniResult Function( + jni.JniResult Function(ffi.Pointer, ffi.Pointer, ffi.Pointer)>>( "GrandParent_StaticParent_Child__ctor") .asFunction< - jni.JniResult Function( - ffi.Pointer, ffi.Pointer)>(); + jni.JniResult Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer)>(); - /// from: public void (S parentValue, U value) + /// from: public void (com.github.dart_lang.jnigen.generics.GrandParent$StaticParent $parent, S parentValue, U value) /// The returned object must be deleted after use, by calling the `delete` method. factory GrandParent_StaticParent_Child( + GrandParent_StaticParent<$S> $parent, $S parentValue, $U value, { jni.JObjType<$S>? S, @@ -2023,12 +2016,16 @@ class GrandParent_StaticParent_Child<$S extends jni.JObject, }) { S ??= jni.lowestCommonSuperType([ parentValue.$type, + ($parent.$type as $GrandParent_StaticParentType).S, ]) as jni.JObjType<$S>; U ??= jni.lowestCommonSuperType([ value.$type, ]) as jni.JObjType<$U>; return GrandParent_StaticParent_Child.fromRef( - S, U, _ctor(parentValue.reference, value.reference).object); + S, + U, + _ctor($parent.reference, parentValue.reference, value.reference) + .object); } } @@ -2270,15 +2267,18 @@ class MyMap_MyEntry<$K extends jni.JObject, $V extends jni.JObject> static final _ctor = jniLookup< ffi.NativeFunction< - jni.JniResult Function(ffi.Pointer, + jni.JniResult Function( + ffi.Pointer, + ffi.Pointer, ffi.Pointer)>>("MyMap_MyEntry__ctor") .asFunction< - jni.JniResult Function( - ffi.Pointer, ffi.Pointer)>(); + jni.JniResult Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer)>(); - /// from: public void (K key, V value) + /// from: public void (com.github.dart_lang.jnigen.generics.MyMap $parent, K key, V value) /// The returned object must be deleted after use, by calling the `delete` method. factory MyMap_MyEntry( + MyMap<$K, $V> $parent, $K key, $V value, { jni.JObjType<$K>? K, @@ -2286,12 +2286,14 @@ class MyMap_MyEntry<$K extends jni.JObject, $V extends jni.JObject> }) { K ??= jni.lowestCommonSuperType([ key.$type, + ($parent.$type as $MyMapType).K, ]) as jni.JObjType<$K>; V ??= jni.lowestCommonSuperType([ value.$type, + ($parent.$type as $MyMapType).V, ]) as jni.JObjType<$V>; return MyMap_MyEntry.fromRef( - K, V, _ctor(key.reference, value.reference).object); + K, V, _ctor($parent.reference, key.reference, value.reference).object); } } diff --git a/jnigen/test/simple_package_test/dart_only/dart_bindings/simple_package.dart b/jnigen/test/simple_package_test/dart_only/dart_bindings/simple_package.dart index 76effbba..fb92e1dd 100644 --- a/jnigen/test/simple_package_test/dart_only/dart_bindings/simple_package.dart +++ b/jnigen/test/simple_package_test/dart_only/dart_bindings/simple_package.dart @@ -1459,27 +1459,29 @@ class GrandParent_Parent<$T extends jni.JObject, $S extends jni.JObject> jni.Jni.env.SetObjectField(reference, _id_value, value.reference); static final _id_ctor = jni.Jni.accessors.getMethodIDOf( - _class.reference, r"", r"(Ljava/lang/Object;Ljava/lang/Object;)V"); + _class.reference, + r"", + r"(Lcom/github/dart_lang/jnigen/generics/GrandParent;Ljava/lang/Object;)V"); - /// from: public void (T parentValue, S value) + /// from: public void (com.github.dart_lang.jnigen.generics.GrandParent $parent, S newValue) /// The returned object must be deleted after use, by calling the `delete` method. factory GrandParent_Parent( - $T parentValue, - $S value, { + GrandParent<$T> $parent, + $S newValue, { jni.JObjType<$T>? T, jni.JObjType<$S>? S, }) { T ??= jni.lowestCommonSuperType([ - parentValue.$type, + ($parent.$type as $GrandParentType).T, ]) as jni.JObjType<$T>; S ??= jni.lowestCommonSuperType([ - value.$type, + newValue.$type, ]) as jni.JObjType<$S>; return GrandParent_Parent.fromRef( T, S, jni.Jni.accessors.newObjectWithArgs(_class.reference, _id_ctor, - [parentValue.reference, value.reference]).object); + [$parent.reference, newValue.reference]).object); } } @@ -1605,37 +1607,35 @@ class GrandParent_Parent_Child<$T extends jni.JObject, $S extends jni.JObject, set value($U value) => jni.Jni.env.SetObjectField(reference, _id_value, value.reference); - static final _id_ctor = jni.Jni.accessors.getMethodIDOf(_class.reference, - r"", r"(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V"); + static final _id_ctor = jni.Jni.accessors.getMethodIDOf( + _class.reference, + r"", + r"(Lcom/github/dart_lang/jnigen/generics/GrandParent$Parent;Ljava/lang/Object;)V"); - /// from: public void (T grandParentValue, S parentValue, U value) + /// from: public void (com.github.dart_lang.jnigen.generics.GrandParent$Parent $parent, U newValue) /// The returned object must be deleted after use, by calling the `delete` method. factory GrandParent_Parent_Child( - $T grandParentValue, - $S parentValue, - $U value, { + GrandParent_Parent<$T, $S> $parent, + $U newValue, { jni.JObjType<$T>? T, jni.JObjType<$S>? S, jni.JObjType<$U>? U, }) { T ??= jni.lowestCommonSuperType([ - grandParentValue.$type, + ($parent.$type as $GrandParent_ParentType).T, ]) as jni.JObjType<$T>; S ??= jni.lowestCommonSuperType([ - parentValue.$type, + ($parent.$type as $GrandParent_ParentType).S, ]) as jni.JObjType<$S>; U ??= jni.lowestCommonSuperType([ - value.$type, + newValue.$type, ]) as jni.JObjType<$U>; return GrandParent_Parent_Child.fromRef( T, S, U, - jni.Jni.accessors.newObjectWithArgs(_class.reference, _id_ctor, [ - grandParentValue.reference, - parentValue.reference, - value.reference - ]).object); + jni.Jni.accessors.newObjectWithArgs(_class.reference, _id_ctor, + [$parent.reference, newValue.reference]).object); } } @@ -1838,11 +1838,14 @@ class GrandParent_StaticParent_Child<$S extends jni.JObject, jni.Jni.env.SetObjectField(reference, _id_value, value.reference); static final _id_ctor = jni.Jni.accessors.getMethodIDOf( - _class.reference, r"", r"(Ljava/lang/Object;Ljava/lang/Object;)V"); + _class.reference, + r"", + r"(Lcom/github/dart_lang/jnigen/generics/GrandParent$StaticParent;Ljava/lang/Object;Ljava/lang/Object;)V"); - /// from: public void (S parentValue, U value) + /// from: public void (com.github.dart_lang.jnigen.generics.GrandParent$StaticParent $parent, S parentValue, U value) /// The returned object must be deleted after use, by calling the `delete` method. factory GrandParent_StaticParent_Child( + GrandParent_StaticParent<$S> $parent, $S parentValue, $U value, { jni.JObjType<$S>? S, @@ -1850,6 +1853,7 @@ class GrandParent_StaticParent_Child<$S extends jni.JObject, }) { S ??= jni.lowestCommonSuperType([ parentValue.$type, + ($parent.$type as $GrandParent_StaticParentType).S, ]) as jni.JObjType<$S>; U ??= jni.lowestCommonSuperType([ value.$type, @@ -1857,8 +1861,11 @@ class GrandParent_StaticParent_Child<$S extends jni.JObject, return GrandParent_StaticParent_Child.fromRef( S, U, - jni.Jni.accessors.newObjectWithArgs(_class.reference, _id_ctor, - [parentValue.reference, value.reference]).object); + jni.Jni.accessors.newObjectWithArgs(_class.reference, _id_ctor, [ + $parent.reference, + parentValue.reference, + value.reference + ]).object); } } @@ -2084,11 +2091,14 @@ class MyMap_MyEntry<$K extends jni.JObject, $V extends jni.JObject> jni.Jni.env.SetObjectField(reference, _id_value, value.reference); static final _id_ctor = jni.Jni.accessors.getMethodIDOf( - _class.reference, r"", r"(Ljava/lang/Object;Ljava/lang/Object;)V"); + _class.reference, + r"", + r"(Lcom/github/dart_lang/jnigen/generics/MyMap;Ljava/lang/Object;Ljava/lang/Object;)V"); - /// from: public void (K key, V value) + /// from: public void (com.github.dart_lang.jnigen.generics.MyMap $parent, K key, V value) /// The returned object must be deleted after use, by calling the `delete` method. factory MyMap_MyEntry( + MyMap<$K, $V> $parent, $K key, $V value, { jni.JObjType<$K>? K, @@ -2096,15 +2106,17 @@ class MyMap_MyEntry<$K extends jni.JObject, $V extends jni.JObject> }) { K ??= jni.lowestCommonSuperType([ key.$type, + ($parent.$type as $MyMapType).K, ]) as jni.JObjType<$K>; V ??= jni.lowestCommonSuperType([ value.$type, + ($parent.$type as $MyMapType).V, ]) as jni.JObjType<$V>; return MyMap_MyEntry.fromRef( K, V, jni.Jni.accessors.newObjectWithArgs(_class.reference, _id_ctor, - [key.reference, value.reference]).object); + [$parent.reference, key.reference, value.reference]).object); } } diff --git a/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/generics/GrandParent.java b/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/generics/GrandParent.java index a12675a6..b7034034 100644 --- a/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/generics/GrandParent.java +++ b/jnigen/test/simple_package_test/java/com/github/dart_lang/jnigen/generics/GrandParent.java @@ -12,11 +12,11 @@ public GrandParent(T value) { } public Parent stringParent() { - return new Parent<>(value, "Hello"); + return new Parent<>("Hello"); } public Parent varParent(S nestedValue) { - return new Parent<>(value, nestedValue); + return new Parent<>(nestedValue); } public static StaticParent stringStaticParent() { @@ -54,9 +54,9 @@ public class Parent { public T parentValue; public S value; - public Parent(T parentValue, S value) { - this.parentValue = parentValue; - this.value = value; + public Parent(S newValue) { + parentValue = GrandParent.this.value; + value = newValue; } public class Child { @@ -64,10 +64,10 @@ public class Child { public S parentValue; public U value; - public Child(T grandParentValue, S parentValue, U value) { - this.grandParentValue = grandParentValue; - this.parentValue = parentValue; - this.value = value; + public Child(U newValue) { + this.grandParentValue = GrandParent.this.value; + this.parentValue = Parent.this.value; + this.value = newValue; } } } diff --git a/jnigen/test/simple_package_test/runtime_test_registrant.dart b/jnigen/test/simple_package_test/runtime_test_registrant.dart index 6472985c..f3075ac7 100644 --- a/jnigen/test/simple_package_test/runtime_test_registrant.dart +++ b/jnigen/test/simple_package_test/runtime_test_registrant.dart @@ -417,6 +417,22 @@ void registerTests(String groupName, TestRunnerCallback test) { }); }); }); + test('Constructing non-static nested classes', () { + using((arena) { + final grandParent = GrandParent(1.toJInteger())..deletedIn(arena); + final parent = GrandParent_Parent(grandParent, 2.toJInteger()) + ..deletedIn(arena); + final child = GrandParent_Parent_Child(parent, 3.toJInteger()) + ..deletedIn(arena); + expect(grandParent.value.intValue(deleteOriginal: true), 1); + expect(parent.parentValue.intValue(deleteOriginal: true), 1); + expect(parent.value.intValue(deleteOriginal: true), 2); + expect(child.grandParentValue.intValue(deleteOriginal: true), 1); + expect(child.parentValue.intValue(deleteOriginal: true), 2); + expect(child.value.intValue(deleteOriginal: true), 3); + }); + }); + group('Generic type inference', () { test('MyStack.of1', () { using((arena) {