blob: d2d3412274f901976633bc8bd5559b01cf98f63f [file] [log] [blame]
// Copyright (c) 2020, 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 'package:ffigen/src/code_generator.dart';
import 'package:ffigen/src/header_parser/data.dart';
import 'package:logging/logging.dart';
import '../clang_bindings/clang_bindings.dart' as clang_types;
import '../includer.dart';
import '../utils.dart';
final _logger = Logger('ffigen.header_parser.functiondecl_parser');
/// Holds temporary information regarding [Func] while parsing.
class _ParserFunc {
Func? func;
bool incompleteStructParameter = false;
bool unimplementedParameterType = false;
_ParserFunc();
}
final _stack = Stack<_ParserFunc>();
/// Parses a function declaration.
Func? parseFunctionDeclaration(clang_types.CXCursor cursor) {
_stack.push(_ParserFunc());
final funcUsr = cursor.usr();
final funcName = cursor.spelling();
if (shouldIncludeFunc(funcUsr, funcName)) {
_logger.fine('++++ Adding Function: ${cursor.completeStringRepr()}');
final rt = _getFunctionReturnType(cursor);
final parameters = _getParameters(cursor, funcName);
if (clang.clang_Cursor_isFunctionInlined(cursor) != 0) {
_logger.fine('---- Removed Function, reason: inline function: '
'${cursor.completeStringRepr()}');
_logger.warning(
"Skipped Function '$funcName', inline functions are not supported.");
// Returning null so that [addToBindings] function excludes this.
return _stack.pop().func;
}
if (rt.isIncompleteCompound || _stack.top.incompleteStructParameter) {
_logger.fine(
'---- Removed Function, reason: Incomplete struct pass/return by '
'value: ${cursor.completeStringRepr()}');
_logger.warning(
"Skipped Function '$funcName', Incomplete struct pass/return by "
'value not supported.');
// Returning null so that [addToBindings] function excludes this.
return _stack.pop().func;
}
if (rt.baseType is UnimplementedType ||
_stack.top.unimplementedParameterType) {
_logger.fine('---- Removed Function, reason: unsupported return type or '
'parameter type: ${cursor.completeStringRepr()}');
_logger.warning(
"Skipped Function '$funcName', function has unsupported return type "
'or parameter type.');
// Returning null so that [addToBindings] function excludes this.
return _stack.pop().func;
}
_stack.top.func = Func(
dartDoc: getCursorDocComment(
cursor,
nesting.length + commentPrefix.length,
),
usr: funcUsr,
name: config.functionDecl.renameUsingConfig(funcName),
originalName: funcName,
returnType: rt,
parameters: parameters,
exposeSymbolAddress:
config.functionDecl.shouldIncludeSymbolAddress(funcName),
exposeFunctionTypedefs:
config.exposeFunctionTypedefs.shouldInclude(funcName),
isLeaf: config.leafFunctions.shouldInclude(funcName),
ffiNativeConfig: config.ffiNativeConfig,
);
bindingsIndex.addFuncToSeen(funcUsr, _stack.top.func!);
} else if (bindingsIndex.isSeenFunc(funcUsr)) {
_stack.top.func = bindingsIndex.getSeenFunc(funcUsr);
}
return _stack.pop().func;
}
Type _getFunctionReturnType(clang_types.CXCursor cursor) {
return cursor.returnType().toCodeGenType();
}
List<Parameter> _getParameters(clang_types.CXCursor cursor, String funcName) {
final parameters = <Parameter>[];
final totalArgs = clang.clang_Cursor_getNumArguments(cursor);
for (var i = 0; i < totalArgs; i++) {
final paramCursor = clang.clang_Cursor_getArgument(cursor, i);
_logger.finer('===== parameter: ${paramCursor.completeStringRepr()}');
final pt = _getParameterType(paramCursor);
if (pt.isIncompleteCompound) {
_stack.top.incompleteStructParameter = true;
} else if (pt.baseType is UnimplementedType) {
_logger.finer('Unimplemented type: ${pt.baseType}');
_stack.top.unimplementedParameterType = true;
}
final pn = paramCursor.spelling();
/// If [pn] is null or empty, its set to `arg$i` by code_generator.
parameters.add(
Parameter(
originalName: pn,
name: config.functionDecl.renameMemberUsingConfig(funcName, pn),
type: pt,
),
);
}
return parameters;
}
Type _getParameterType(clang_types.CXCursor cursor) {
return cursor.toCodeGenType();
}