Skip to content
This repository has been archived by the owner on Apr 29, 2024. It is now read-only.

Commit

Permalink
Non static nested class construction (#297)
Browse files Browse the repository at this point in the history
Construct the non-static nested classes correctly
  • Loading branch information
HosseinYousefi authored Jun 13, 2023
1 parent 85b7dbc commit f1c9fc4
Show file tree
Hide file tree
Showing 14 changed files with 232 additions and 115 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
9 changes: 6 additions & 3 deletions jnigen/lib/src/bindings/c_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -390,9 +390,12 @@ class _CParamGenerator extends Visitor<Param, String> {
@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;
}
}
Expand Down
4 changes: 2 additions & 2 deletions jnigen/lib/src/bindings/dart_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ class _ClassGenerator extends Visitor<ClassDecl, void> {
.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))
Expand Down Expand Up @@ -1331,7 +1331,7 @@ class _TypeVarLocator extends TypeVisitor<Map<String, List<OutsideInBuffer>>> {

@override
Map<String, List<OutsideInBuffer>> visitDeclaredType(DeclaredType node) {
if (node.classDecl.isObject()) {
if (node.classDecl.isObject) {
return {};
}
final offset = node.classDecl.allTypeParams.length - node.params.length;
Expand Down
15 changes: 1 addition & 14 deletions jnigen/lib/src/bindings/linker.dart
Original file line number Diff line number Diff line change
Expand Up @@ -92,20 +92,7 @@ class _ClassLinker extends Visitor<ClassDecl, void> {
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 = <TypeParam>[];
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;
Expand Down
9 changes: 5 additions & 4 deletions jnigen/lib/src/bindings/renamer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ const Set<String> _keywords = {
'throw',
'true',
'try',
'type', // Is used for type classes.
'typedef',
'var',
'void',
Expand Down Expand Up @@ -213,8 +214,8 @@ class _MethodRenamer implements Visitor<Method, void> {
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) {
Expand Down Expand Up @@ -242,8 +243,8 @@ class _FieldRenamer implements Visitor<Field, void> {
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}');
}
}

Expand Down
83 changes: 83 additions & 0 deletions jnigen/lib/src/bindings/unnester.dart
Original file line number Diff line number Diff line change
@@ -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<Classes, void> {
@override
void visit(node) {
final classProcessor = _ClassUnnester();
for (final classDecl in node.decls.values) {
classDecl.accept(classProcessor);
}
}
}

class _ClassUnnester extends Visitor<ClassDecl, void> {
final processed = <ClassDecl>{};

@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 = <TypeParam>[];
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<Method, void> {
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);
}
}
}
3 changes: 2 additions & 1 deletion jnigen/lib/src/config/config_types.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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) ??
<MapEntry<dynamic, dynamic>>[]) {
Expand Down
6 changes: 4 additions & 2 deletions jnigen/lib/src/elements/elements.dart
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,9 @@ class ClassDecl extends ClassMember implements Element<ClassDecl> {
@override
String get name => finalName;

bool isObject() => superCount == 0;
bool get isObject => superCount == 0;

bool get isNested => parentName != null;
}

@JsonEnum()
Expand Down Expand Up @@ -455,7 +457,7 @@ class Method extends ClassMember implements Element<Method> {
final List<Annotation> annotations;
final JavaDocComment? javadoc;
final List<TypeParam> typeParams;
final List<Param> params;
List<Param> params;
final TypeUsage returnType;

/// The [ClassDecl] where this method is defined.
Expand Down
2 changes: 2 additions & 0 deletions jnigen/lib/src/generate_bindings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -36,6 +37,7 @@ Future<void> 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;
Expand Down
38 changes: 21 additions & 17 deletions jnigen/test/simple_package_test/c_based/c_bindings/simple_package.c
Original file line number Diff line number Diff line change
Expand Up @@ -1513,20 +1513,21 @@ 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,
"com/github/dart_lang/jnigen/generics/GrandParent$Parent");
if (_c_GrandParent_Parent == NULL)
return (JniResult){.value = {.j = 0}, .exception = check_exception()};
load_method(_c_GrandParent_Parent, &_m_GrandParent_Parent__ctor, "<init>",
"(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);
}

Expand Down Expand Up @@ -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,
Expand All @@ -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,
"<init>",
"(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);
}

Expand Down Expand Up @@ -1773,22 +1773,25 @@ 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(
&_c_GrandParent_StaticParent_Child,
"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, "<init>",
"(Ljava/lang/Object;Ljava/lang/Object;)V");
load_method(
_c_GrandParent_StaticParent_Child,
&_m_GrandParent_StaticParent_Child__ctor, "<init>",
"(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);
}

Expand Down Expand Up @@ -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, "<init>",
"(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);
}

Expand Down
Loading

0 comments on commit f1c9fc4

Please sign in to comment.