| // 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; |
| } |