blob: df3730b04a6123f76e4f25c23b7be0ccb08226fc [file] [log] [blame]
// 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 '../back_end/code_writer.dart';
import 'piece.dart';
/// Piece for a function declaration, function type, or function-typed
/// parameter.
///
/// Handles splitting between the return type and the rest of the function.
class FunctionPiece extends Piece {
/// The return type annotation, if any.
final Piece? _returnType;
/// The rest of the function type signature: name, type parameters,
/// parameters, etc.
final Piece _signature;
/// If this is a function declaration with a (non-empty `;`) body, the body.
final Piece? _body;
/// Whether the return type is a function type.
///
/// When it is, allow splitting fairly cheaply because the return type is
/// usually pretty big and looks good on its own line, or at least better
/// then splitting inside the return type's parameter list. Prefers:
///
/// Function(int x, int y)
/// returnFunction() { ... }
///
/// Over:
///
/// Function(
/// int x,
/// int y,
/// ) returnFunction() { ... }
///
/// If the return type is *not* a function type, is almost always looks worse
/// to split at the return type, so make that high cost.
final bool _isReturnTypeFunctionType;
FunctionPiece(this._returnType, this._signature,
{required bool isReturnTypeFunctionType, Piece? body})
: _body = body,
_isReturnTypeFunctionType = isReturnTypeFunctionType;
@override
List<State> get additionalStates => [if (_returnType != null) State.split];
@override
int stateCost(State state) {
if (state == State.split) return _isReturnTypeFunctionType ? 1 : 4;
return super.stateCost(state);
}
@override
void format(CodeWriter writer, State state) {
if (_returnType case var returnType?) {
// A split inside the return type forces splitting after the return type.
writer.format(returnType, allowNewlines: state == State.split);
// A split in the type parameters or parameters does not force splitting
// after the return type.
writer.splitIf(state == State.split);
}
writer.format(_signature);
if (_body case var body?) writer.format(body);
}
@override
void forEachChild(void Function(Piece piece) callback) {
if (_returnType case var returnType?) callback(returnType);
callback(_signature);
if (_body case var body?) callback(body);
}
@override
String get debugName => 'Fn';
}