blob: ab62b215fdf75d2b96f6eb9a6c31b61fe96750c9 [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.
import 'package:kernel/ast.dart';
import '../fasta/problems.dart';
/// Convert '→' to '->' because '→' doesn't show up in some terminals.
/// Remove prefixes that are used very often in tests.
String _shortenInstrumentationString(String s) => s
.replaceAll('→', '->')
.replaceAll('dart.core::', '')
.replaceAll('dart.async::', '')
.replaceAll('test::', '');
/// Interface providing the ability to record property/value pairs associated
/// with source file locations. Intended to facilitate testing.
abstract class Instrumentation {
/// Records a property/value pair associated with the given URI and offset.
void record(Uri uri, int offset, String property, InstrumentationValue value);
}
/// Interface for values recorded by [Instrumentation].
abstract class InstrumentationValue {
const InstrumentationValue();
/// Checks if the given String is an accurate description of this value.
///
/// The default implementation just checks for equality with the return value
/// of [toString], however derived classes may want a more sophisticated
/// implementation (e.g. to allow abbreviations in the description).
///
/// Derived classes should ensure that the invariant holds:
/// `this.matches(this.toString())` should always return `true`.
bool matches(String description) => description == toString();
}
/// Instance of [InstrumentationValue] describing a forwarding stub.
class InstrumentationValueForForwardingStub extends InstrumentationValue {
final Procedure procedure;
InstrumentationValueForForwardingStub(this.procedure);
@override
String toString() {
var buffer = new StringBuffer();
void writeParameter(VariableDeclaration parameter) {
var covariances = <String>[];
if (parameter.isGenericCovariantImpl) {
covariances.add('genericImpl');
}
if (parameter.isCovariant) {
covariances.add('explicit');
}
buffer.write('covariance=(${covariances.join(', ')}) ');
buffer.write(parameter.type);
buffer.write(' ');
buffer.write(parameter.name);
}
if (procedure.isAbstract) {
buffer.write('abstract ');
}
var function = procedure.function;
buffer.write(function.returnType);
buffer.write(' ');
switch (procedure.kind) {
case ProcedureKind.Operator:
buffer.write('operator');
break;
case ProcedureKind.Method:
break;
case ProcedureKind.Setter:
buffer.write('set ');
break;
case ProcedureKind.Getter:
buffer.write('get ');
break;
default:
unhandled('${procedure.kind}', 'InstrumentationValueForForwardingStub',
-1, null);
break;
}
buffer.write(procedure.name.name);
if (function.typeParameters.isNotEmpty) {
buffer.write('<');
for (int i = 0; i < function.typeParameters.length; i++) {
if (i != 0) buffer.write(', ');
var typeParameter = function.typeParameters[i];
var covariances = <String>[];
if (typeParameter.isGenericCovariantImpl) {
covariances.add('genericImpl');
}
buffer.write('covariance=(${covariances.join(', ')}) ');
buffer.write(typeParameter.name);
buffer.write(' extends ');
buffer.write(
new InstrumentationValueForType(typeParameter.bound).toString());
}
buffer.write('>');
}
buffer.write('(');
for (int i = 0; i < function.positionalParameters.length; i++) {
if (i != 0) buffer.write(', ');
if (i == function.requiredParameterCount) buffer.write('[');
writeParameter(function.positionalParameters[i]);
}
if (function.requiredParameterCount <
function.positionalParameters.length) {
buffer.write(']');
}
if (function.namedParameters.isNotEmpty) {
if (function.positionalParameters.length != 0) buffer.write(', ');
buffer.write('{');
for (int i = 0; i < function.namedParameters.length; i++) {
if (i != 0) buffer.write(', ');
writeParameter(function.namedParameters[i]);
}
buffer.write('}');
}
buffer.write(')');
return _shortenInstrumentationString(buffer.toString());
}
}
/// Instance of [InstrumentationValue] describing a [Member].
class InstrumentationValueForMember extends InstrumentationValue {
final Member member;
InstrumentationValueForMember(this.member);
@override
String toString() => _shortenInstrumentationString(member.toString());
}
/// Instance of [InstrumentationValue] describing a [DartType].
class InstrumentationValueForType extends InstrumentationValue {
final DartType type;
InstrumentationValueForType(this.type);
@override
String toString() => _shortenInstrumentationString(type.toString());
}
/// Instance of [InstrumentationValue] describing a list of [DartType]s.
class InstrumentationValueForTypeArgs extends InstrumentationValue {
final List<DartType> types;
InstrumentationValueForTypeArgs(this.types);
@override
String toString() => types
.map((type) => new InstrumentationValueForType(type).toString())
.join(', ');
}
/// Instance of [InstrumentationValue] which only matches the given literal
/// string.
class InstrumentationValueLiteral extends InstrumentationValue {
final String value;
const InstrumentationValueLiteral(this.value);
@override
String toString() => value;
}