blob: 165a67ab551b6a685a086024aa675974a8935ffc [file] [log] [blame]
// Copyright (c) 2017, 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.
// @dart = 2.10
import 'package:kernel/ast.dart' as ir;
import '../common/elements.dart';
import '../common/names.dart';
import '../elements/entities.dart';
import 'element_map.dart';
import 'kelements.dart';
/// Interface for determining the form of a `noSuchMethod` implementation.
class NoSuchMethodResolver {
final KernelToElementMap elementMap;
NoSuchMethodResolver(this.elementMap);
CommonElements get _commonElements => elementMap.commonElements;
/// Computes whether [method] is of the form
///
/// noSuchMethod(i) => super.noSuchMethod(i);
///
bool hasForwardingSyntax(KFunction method) {
ir.Procedure node = elementMap.lookupProcedure(method);
if (node.function.positionalParameters.isEmpty) return false;
ir.VariableDeclaration firstParameter =
node.function.positionalParameters.first;
ir.Statement body = node.function.body;
ir.Expression expr;
if (body is ir.Block && body.statements.isNotEmpty) {
ir.Block block = body;
body = block.statements.first;
}
if (body is ir.ReturnStatement) {
expr = body.expression;
}
if (expr is ir.AsExpression &&
elementMap.getDartType(expr.type) == _commonElements.dynamicType) {
ir.AsExpression asExpression = expr;
expr = asExpression.operand;
}
if (expr is ir.SuperMethodInvocation &&
expr.name.text == Identifiers.noSuchMethod_) {
ir.Arguments arguments = expr.arguments;
if (arguments.positional.length == 1 &&
arguments.named.isEmpty &&
arguments.positional.first is ir.VariableGet) {
ir.VariableGet get = arguments.positional.first;
return get.variable == firstParameter;
}
}
return false;
}
/// Computes whether [method] is of the form
///
/// noSuchMethod(i) => throw new Error();
///
bool hasThrowingSyntax(KFunction method) {
ir.Procedure node = elementMap.lookupProcedure(method);
ir.Statement body = node.function.body;
if (body is ir.Block && body.statements.isNotEmpty) {
ir.Block block = body;
body = block.statements.first;
}
ir.Expression expr;
if (body is ir.ReturnStatement) {
expr = body.expression;
} else if (body is ir.ExpressionStatement) {
expr = body.expression;
}
return expr is ir.Throw;
}
/// Returns the `noSuchMethod` that [method] overrides.
FunctionEntity getSuperNoSuchMethod(FunctionEntity method) {
return elementMap.getSuperNoSuchMethod(method.enclosingClass);
}
}