| // Copyright (c) 2024, 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:_fe_analyzer_shared/src/metadata/ast.dart'; |
| |
| import '../metadata/evaluate.dart'; |
| |
| /// Returns the arguments expression, if [expression] is of the form |
| /// `Helper(foo)`, and [expression] otherwise. |
| /// |
| /// This is used to simplify testing of metadata expression where most can |
| /// only occur as arguments to a constant constructor invocation. To avoid the |
| /// clutter, these tests use a `Helper` class which is omitted in the test |
| /// output. |
| Expression unwrap(Expression expression) { |
| if (expression case ConstructorInvocation( |
| type: NamedTypeAnnotation(reference: ClassReference(name: 'Helper')), |
| constructor: ConstructorReference(name: 'new'), |
| arguments: [PositionalArgument(expression: Expression argument)], |
| )) { |
| return argument; |
| } |
| return expression; |
| } |
| |
| /// Creates a list containing structured and readable textual representation of |
| /// the [resolved] expression and the result of evaluating [resolved]. |
| /// |
| /// If [getFieldInitializer] is provided, it is used to dereference constant |
| /// field references during evaluation. |
| List<String> evaluationToText( |
| Expression resolved, { |
| GetFieldInitializer? getFieldInitializer, |
| }) { |
| List<String> list = []; |
| |
| Expression unwrappedResolved = unwrap(resolved); |
| list.add('resolved=${expressionToText(unwrappedResolved)}'); |
| |
| Map<FieldReference, Expression> dereferences = {}; |
| Expression evaluated = evaluateExpression( |
| unwrappedResolved, |
| getFieldInitializer: getFieldInitializer, |
| dereferences: dereferences, |
| ); |
| list.add('evaluate=${expressionToText(evaluated)}'); |
| for (MapEntry<FieldReference, Expression> entry in dereferences.entries) { |
| list.add('${entry.key.name}=${expressionToText(entry.value)}'); |
| } |
| |
| return list; |
| } |
| |
| /// Creates a list containing structured and readable textual representation of |
| /// the [unresolved] and [resolved] expressions. |
| List<String> expressionsToText({ |
| required Expression unresolved, |
| required Expression resolved, |
| }) { |
| List<String> list = []; |
| list.add('unresolved=${expressionToText(unwrap(unresolved))}'); |
| |
| // The identifiers in [expression] haven't been resolved, so |
| // we call [Expression.resolve] to convert the expression into |
| // its resolved equivalent. |
| Expression lateResolved = unresolved.resolve() ?? unresolved; |
| |
| Expression unwrappedResolved = unwrap(resolved); |
| String earlyResolvedText = expressionToText(unwrappedResolved); |
| String lateResolvedText = expressionToText(unwrap(lateResolved)); |
| |
| // These should always be the same. If not we include both to |
| // signal the error. |
| if (earlyResolvedText == lateResolvedText) { |
| list.add('resolved=${earlyResolvedText}'); |
| } else { |
| list.add('early-resolved=${earlyResolvedText}'); |
| list.add('late-resolved=${lateResolvedText}'); |
| } |
| |
| return list; |
| } |
| |
| /// Creates a structured and readable textual representation of [expression]. |
| String expressionToText(Expression expression) { |
| Writer writer = new Writer(); |
| return writer.expressionToText(expression); |
| } |
| |
| /// Helper class for creating a structured and readable textual representation |
| /// of an [Expression] node. |
| class Writer { |
| StringBuffer sb = new StringBuffer(); |
| bool _lastWasNewLine = true; |
| int _indentLevel = 0; |
| |
| String expressionToText(Expression expression) { |
| sb.clear(); |
| _expressionToText(expression); |
| return sb.toString(); |
| } |
| |
| void _incIndent({int amount = 1, required bool addNewLine}) { |
| _indentLevel += amount; |
| if (addNewLine) { |
| _addNewLine(); |
| } |
| } |
| |
| void _decIndent({int amount = 1, bool addNewLine = false}) { |
| _indentLevel -= amount; |
| if (addNewLine) { |
| _addNewLine(); |
| } |
| } |
| |
| void _addNewLine() { |
| sb.write('\n'); |
| _lastWasNewLine = true; |
| } |
| |
| void _write(String value) { |
| if (_lastWasNewLine) { |
| sb.write(' ' * _indentLevel); |
| } |
| sb.write(value); |
| _lastWasNewLine = false; |
| } |
| |
| void _expressionToText(Expression expression) { |
| switch (expression) { |
| case InvalidExpression(): |
| _write('InvalidExpression()'); |
| case StaticGet(): |
| _write('StaticGet('); |
| _referenceToText(expression.reference); |
| _write(')'); |
| case FunctionTearOff(): |
| _write('FunctionTearOff('); |
| _referenceToText(expression.reference); |
| _write(')'); |
| case ConstructorTearOff(): |
| _write('ConstructorTearOff('); |
| _typeAnnotationToText(expression.type); |
| _write('.'); |
| _referenceToText(expression.reference); |
| _write(')'); |
| case ConstructorInvocation(): |
| _write('ConstructorInvocation('); |
| _incIndent(addNewLine: true); |
| _typeAnnotationToText(expression.type); |
| _write('.'); |
| _referenceToText(expression.constructor); |
| _argumentsToText(expression.arguments); |
| _decIndent(); |
| _write(')'); |
| case IntegerLiteral(): |
| _write('IntegerLiteral('); |
| if (expression.text != null) { |
| _write(expression.text!); |
| } else { |
| _write('value=${expression.value}'); |
| } |
| _write(')'); |
| case DoubleLiteral(): |
| _write('DoubleLiteral('); |
| _write(expression.text); |
| _write(')'); |
| case BooleanLiteral(): |
| _write('BooleanLiteral('); |
| _write('${expression.value}'); |
| _write(')'); |
| case NullLiteral(): |
| _write('NullLiteral()'); |
| case SymbolLiteral(): |
| _write('SymbolLiteral('); |
| _write(expression.parts.join()); |
| _write(')'); |
| case StringLiteral(): |
| _write('StringLiteral('); |
| _stringPartsToText(expression.parts); |
| _write(')'); |
| case AdjacentStringLiterals(): |
| _write('AdjacentStringLiterals('); |
| _incIndent(addNewLine: false); |
| _expressionsToText(expression.expressions, delimiter: ''); |
| _decIndent(); |
| _write(')'); |
| case ImplicitInvocation(): |
| _write('ImplicitInvocation('); |
| _incIndent(addNewLine: true); |
| _expressionToText(expression.receiver); |
| _typeArgumentsToText(expression.typeArguments); |
| _argumentsToText(expression.arguments); |
| _decIndent(); |
| _write(')'); |
| case StaticInvocation(): |
| _write('StaticInvocation('); |
| _incIndent(addNewLine: true); |
| _referenceToText(expression.function); |
| _typeArgumentsToText(expression.typeArguments); |
| _argumentsToText(expression.arguments); |
| _decIndent(); |
| _write(')'); |
| case Instantiation(): |
| _write('Instantiation('); |
| _expressionToText(expression.receiver); |
| _typeArgumentsToText(expression.typeArguments); |
| _write(')'); |
| case MethodInvocation(): |
| _write('MethodInvocation('); |
| _incIndent(addNewLine: true); |
| _expressionToText(expression.receiver); |
| _write('.'); |
| _write(expression.name); |
| _typeArgumentsToText(expression.typeArguments); |
| _argumentsToText(expression.arguments); |
| _decIndent(); |
| _write(')'); |
| case PropertyGet(): |
| _write('PropertyGet('); |
| _expressionToText(expression.receiver); |
| _write('.'); |
| _write(expression.name); |
| _write(')'); |
| case NullAwarePropertyGet(): |
| _write('NullAwarePropertyGet('); |
| _expressionToText(expression.receiver); |
| _write('?.'); |
| _write(expression.name); |
| _write(')'); |
| case TypeLiteral(): |
| _write('TypeLiteral('); |
| _typeAnnotationToText(expression.typeAnnotation); |
| _write(')'); |
| case ParenthesizedExpression(): |
| _write('ParenthesizedExpression('); |
| _expressionToText(expression.expression); |
| _write(')'); |
| case ConditionalExpression(): |
| _write('ConditionalExpression('); |
| _incIndent(addNewLine: true); |
| _expressionToText(expression.condition); |
| _incIndent(addNewLine: true); |
| _write('? '); |
| _incIndent(addNewLine: false); |
| _expressionToText(expression.then); |
| _decIndent(addNewLine: true); |
| _write(': '); |
| _incIndent(addNewLine: false); |
| _expressionToText(expression.otherwise); |
| _decIndent(amount: 3); |
| _write(')'); |
| case ListLiteral(): |
| _write('ListLiteral('); |
| _typeArgumentsToText(expression.typeArguments); |
| _write('['); |
| _elementsToText(expression.elements); |
| _write('])'); |
| case SetOrMapLiteral(): |
| _write('SetOrMapLiteral('); |
| _typeArgumentsToText(expression.typeArguments); |
| _write('{'); |
| _elementsToText(expression.elements); |
| _write('})'); |
| case RecordLiteral(): |
| _write('RecordLiteral('); |
| _recordFieldsToText(expression.fields); |
| _write(')'); |
| break; |
| case IfNull(): |
| _write('IfNull('); |
| _incIndent(addNewLine: true); |
| _expressionToText(expression.left); |
| _addNewLine(); |
| _write(' ?? '); |
| _addNewLine(); |
| _expressionToText(expression.right); |
| _decIndent(addNewLine: true); |
| _write(')'); |
| case LogicalExpression(): |
| _write('LogicalExpression('); |
| _expressionToText(expression.left); |
| _write(' '); |
| _write(expression.operator.text); |
| _write(' '); |
| _expressionToText(expression.right); |
| _write(')'); |
| case EqualityExpression(): |
| _write('EqualityExpression('); |
| _expressionToText(expression.left); |
| _write(expression.isNotEquals ? ' != ' : ' == '); |
| _expressionToText(expression.right); |
| _write(')'); |
| case BinaryExpression(): |
| _write('BinaryExpression('); |
| _expressionToText(expression.left); |
| _write(' '); |
| _write(expression.operator.text); |
| _write(' '); |
| _expressionToText(expression.right); |
| _write(')'); |
| case UnaryExpression(): |
| _write('UnaryExpression('); |
| _write(expression.operator.text); |
| _expressionToText(expression.expression); |
| _write(')'); |
| case IsTest(): |
| _write('IsTest('); |
| _expressionToText(expression.expression); |
| _write(' is'); |
| if (expression.isNot) { |
| _write('!'); |
| } |
| _write(' '); |
| _typeAnnotationToText(expression.type); |
| _write(')'); |
| case AsExpression(): |
| _write('AsExpression('); |
| _expressionToText(expression.expression); |
| _write(' as '); |
| _typeAnnotationToText(expression.type); |
| _write(')'); |
| case NullCheck(): |
| _write('NullCheck('); |
| _expressionToText(expression.expression); |
| _write(')'); |
| case UnresolvedExpression(): |
| _write('UnresolvedExpression('); |
| _unresolvedToText(expression.unresolved); |
| _write(')'); |
| } |
| } |
| |
| void _referenceToText(Reference reference) { |
| switch (reference) { |
| case FieldReference(): |
| _write(reference.name); |
| case FunctionReference(): |
| _write(reference.name); |
| case ConstructorReference(): |
| _write(reference.name); |
| case TypeReference(): |
| _write(reference.name); |
| case ClassReference(): |
| _write(reference.name); |
| case TypedefReference(): |
| _write(reference.name); |
| case ExtensionReference(): |
| _write(reference.name); |
| case ExtensionTypeReference(): |
| _write(reference.name); |
| case EnumReference(): |
| _write(reference.name); |
| case MixinReference(): |
| _write(reference.name); |
| case FunctionTypeParameterReference(): |
| _write(reference.name); |
| } |
| } |
| |
| void _typeAnnotationToText(TypeAnnotation typeAnnotation) { |
| switch (typeAnnotation) { |
| case NamedTypeAnnotation(): |
| _referenceToText(typeAnnotation.reference); |
| _typeArgumentsToText(typeAnnotation.typeArguments); |
| case NullableTypeAnnotation(): |
| _typeAnnotationToText(typeAnnotation.typeAnnotation); |
| _write('?'); |
| case VoidTypeAnnotation(): |
| _write('void'); |
| case DynamicTypeAnnotation(): |
| _write('dynamic'); |
| case InvalidTypeAnnotation(): |
| _write('{invalid-type-annotation}'); |
| case UnresolvedTypeAnnotation(): |
| _write('{unresolved-type-annotation:'); |
| _unresolvedToText(typeAnnotation.unresolved); |
| _write('}'); |
| case FunctionTypeAnnotation(:TypeAnnotation? returnType): |
| if (returnType != null) { |
| _typeAnnotationToText(returnType); |
| _write(' '); |
| } |
| _write('Function'); |
| if (typeAnnotation.typeParameters.isNotEmpty) { |
| _write('<'); |
| } |
| _formalParametersToText(typeAnnotation.formalParameters); |
| case FunctionTypeParameterType(): |
| _write(typeAnnotation.functionTypeParameter.name); |
| case RecordTypeAnnotation(): |
| _write('('); |
| String comma = ''; |
| for (RecordTypeEntry entry in typeAnnotation.positional) { |
| _write(comma); |
| _metadataToText(entry.metadata); |
| _typeAnnotationToText(entry.typeAnnotation); |
| if (entry.name != null) { |
| _write(' '); |
| _write(entry.name!); |
| } |
| comma = ', '; |
| } |
| if (typeAnnotation.named.isNotEmpty) { |
| _write(comma); |
| sb.write('{'); |
| comma = ''; |
| for (RecordTypeEntry entry in typeAnnotation.named) { |
| _write(comma); |
| _metadataToText(entry.metadata); |
| _typeAnnotationToText(entry.typeAnnotation); |
| if (entry.name != null) { |
| _write(' '); |
| _write(entry.name!); |
| } |
| comma = ', '; |
| } |
| sb.write('}'); |
| } else if (typeAnnotation.positional.length == 1) { |
| sb.write(','); |
| } |
| _write(')'); |
| } |
| } |
| |
| void _typeArgumentsToText(List<TypeAnnotation> typeArguments) { |
| if (typeArguments.isNotEmpty) { |
| _write('<'); |
| String comma = ''; |
| for (TypeAnnotation typeArgument in typeArguments) { |
| _write(comma); |
| _typeAnnotationToText(typeArgument); |
| comma = ','; |
| } |
| _write('>'); |
| } |
| } |
| |
| void _formalParametersToText(List<FormalParameter> formalParameters) { |
| _write('('); |
| String comma = ''; |
| bool inNamed = false; |
| for (FormalParameter formalParameter in formalParameters) { |
| _write(comma); |
| if (!inNamed && formalParameter.isNamed) { |
| _write('{'); |
| inNamed = true; |
| } |
| if (formalParameter.metadata.isNotEmpty) { |
| _metadataToText(formalParameter.metadata); |
| } |
| if (inNamed && formalParameter.isRequired) { |
| _write('required '); |
| } |
| if (formalParameter.typeAnnotation != null) { |
| _typeAnnotationToText(formalParameter.typeAnnotation!); |
| if (formalParameter.name != null) { |
| _write(' '); |
| } |
| } |
| if (formalParameter.name != null) { |
| _write(formalParameter.name!); |
| } |
| if (formalParameter.defaultValue != null) { |
| _write(' = '); |
| _expressionToText(formalParameter.defaultValue!); |
| } |
| comma = ', '; |
| } |
| if (inNamed) { |
| _write('}'); |
| } |
| _write(')'); |
| } |
| |
| void _argumentToText(Argument argument) { |
| switch (argument) { |
| case PositionalArgument(): |
| _expressionToText(argument.expression); |
| case NamedArgument(): |
| _write(argument.name); |
| _write(': '); |
| _expressionToText(argument.expression); |
| } |
| } |
| |
| static final int _newLine = '\n'.codeUnitAt(0); |
| static final int _backSlash = r'\'.codeUnitAt(0); |
| static final int _dollar = r'$'.codeUnitAt(0); |
| static final int _quote = "'".codeUnitAt(0); |
| |
| String _escape(String text) { |
| StringBuffer sb = new StringBuffer(); |
| for (int c in text.codeUnits) { |
| if (c == _newLine) { |
| sb.write(r'\n'); |
| } else if (c == _backSlash) { |
| sb.write(r'\\'); |
| } else if (c == _dollar) { |
| sb.write(r'\$'); |
| } else if (c == _quote) { |
| sb.write(r"\'"); |
| } else if (c < 0x20 || c >= 0x80) { |
| String hex = c.toRadixString(16); |
| hex = ("0" * (4 - hex.length)) + hex; |
| sb.write('\\u$hex'); |
| } else { |
| sb.writeCharCode(c); |
| } |
| } |
| return sb.toString(); |
| } |
| |
| void _stringPartsToText(List<StringLiteralPart> parts) { |
| _write("'"); |
| for (StringLiteralPart part in parts) { |
| switch (part) { |
| case StringPart(): |
| _write(_escape(part.text)); |
| case InterpolationPart(): |
| _write(r'${'); |
| _expressionToText(part.expression); |
| _write('}'); |
| } |
| } |
| _write("'"); |
| } |
| |
| void _listToText<E>( |
| List<E> list, |
| void Function(E) elementToText, { |
| required String delimiter, |
| bool useNewLine = false, |
| String prefix = '', |
| }) { |
| if (list.isNotEmpty) { |
| bool hasNewLine = useNewLine && list.length > 1; |
| if (hasNewLine) { |
| _incIndent(addNewLine: false); |
| } |
| String comma = ''; |
| for (E element in list) { |
| _write(comma); |
| if (hasNewLine) { |
| _addNewLine(); |
| } |
| _write(prefix); |
| elementToText(element); |
| comma = delimiter; |
| } |
| if (hasNewLine) { |
| _decIndent(); |
| } |
| } |
| } |
| |
| void _argumentsToText(List<Argument> arguments) { |
| _write('('); |
| _listToText(arguments, _argumentToText, delimiter: ', ', useNewLine: true); |
| _write(')'); |
| } |
| |
| void _expressionsToText( |
| List<Expression> expressions, { |
| required String delimiter, |
| String prefix = '', |
| }) { |
| _listToText( |
| expressions, |
| _expressionToText, |
| delimiter: delimiter, |
| useNewLine: true, |
| ); |
| } |
| |
| void _metadataToText(List<Expression> metadata) { |
| if (metadata.isNotEmpty) { |
| _expressionsToText(metadata, delimiter: ' ', prefix: '@'); |
| _write(' '); |
| } |
| } |
| |
| void _elementToText(Element element) { |
| switch (element) { |
| case ExpressionElement(): |
| _write('ExpressionElement('); |
| if (element.isNullAware) { |
| _write('?'); |
| } |
| _expressionToText(element.expression); |
| _write(')'); |
| case MapEntryElement(): |
| _write('MapEntryElement('); |
| if (element.isNullAwareKey) { |
| _write('?'); |
| } |
| _expressionToText(element.key); |
| _write(':'); |
| if (element.isNullAwareValue) { |
| _write('?'); |
| } |
| _expressionToText(element.value); |
| _write(')'); |
| case SpreadElement(): |
| _write('SpreadElement('); |
| if (element.isNullAware) { |
| _write('?'); |
| } |
| _write('...'); |
| _expressionToText(element.expression); |
| _write(')'); |
| case IfElement(): |
| _write('IfElement('); |
| _incIndent(addNewLine: true); |
| _expressionToText(element.condition); |
| _write(','); |
| _addNewLine(); |
| _elementToText(element.then); |
| if (element.otherwise != null) { |
| _write(','); |
| _addNewLine(); |
| _elementToText(element.otherwise!); |
| } |
| _decIndent(); |
| _write(')'); |
| } |
| } |
| |
| void _elementsToText(List<Element> elements) { |
| _listToText(elements, _elementToText, delimiter: ', ', useNewLine: true); |
| } |
| |
| void _recordFieldToText(RecordField field) { |
| switch (field) { |
| case RecordNamedField(): |
| _write(field.name); |
| _write(': '); |
| _expressionToText(field.expression); |
| case RecordPositionalField(): |
| _expressionToText(field.expression); |
| } |
| } |
| |
| void _recordFieldsToText(List<RecordField> fields) { |
| _listToText(fields, _recordFieldToText, delimiter: ', '); |
| } |
| |
| void _unresolvedToText(Unresolved unresolved) { |
| switch (unresolved) { |
| case UnresolvedIdentifier(): |
| _write('UnresolvedIdentifier('); |
| _write(unresolved.name); |
| _write(')'); |
| case UnresolvedAccess(): |
| _write('UnresolvedAccess('); |
| _incIndent(addNewLine: true); |
| _protoToText(unresolved.prefix); |
| _write('.'); |
| _write(unresolved.name); |
| _decIndent(); |
| _write(')'); |
| case UnresolvedInstantiate(): |
| _write('UnresolvedInstantiate('); |
| _incIndent(addNewLine: true); |
| _protoToText(unresolved.prefix); |
| _typeArgumentsToText(unresolved.typeArguments); |
| _decIndent(); |
| _write(')'); |
| case UnresolvedInvoke(): |
| _write('UnresolvedInvoke('); |
| _incIndent(addNewLine: true); |
| _protoToText(unresolved.prefix); |
| _addNewLine(); |
| _argumentsToText(unresolved.arguments); |
| _decIndent(); |
| _write(')'); |
| } |
| } |
| |
| void _protoToText(Proto proto) { |
| switch (proto) { |
| case UnresolvedIdentifier(): |
| _unresolvedToText(proto); |
| case UnresolvedAccess(): |
| _unresolvedToText(proto); |
| case UnresolvedInstantiate(): |
| _unresolvedToText(proto); |
| case UnresolvedInvoke(): |
| _unresolvedToText(proto); |
| case ClassProto(): |
| _write('ClassProto('); |
| _referenceToText(proto.reference); |
| _write(')'); |
| case GenericClassProto(): |
| _write('GenericClassProto('); |
| _referenceToText(proto.reference); |
| _typeArgumentsToText(proto.typeArguments); |
| _write(')'); |
| case EnumProto(): |
| _write('EnumProto('); |
| _referenceToText(proto.reference); |
| _write(')'); |
| case GenericEnumProto(): |
| _write('GenericEnumProto('); |
| _referenceToText(proto.reference); |
| _typeArgumentsToText(proto.typeArguments); |
| _write(')'); |
| case MixinProto(): |
| _write('MixinProto('); |
| _referenceToText(proto.reference); |
| _write(')'); |
| case GenericMixinProto(): |
| _write('GenericMixinProto('); |
| _referenceToText(proto.reference); |
| _typeArgumentsToText(proto.typeArguments); |
| _write(')'); |
| case ExtensionProto(): |
| _write('ExtensionProto('); |
| _referenceToText(proto.reference); |
| _write(')'); |
| case ExtensionTypeProto(): |
| _write('ExtensionTypeProto('); |
| _referenceToText(proto.reference); |
| _write(')'); |
| case GenericExtensionTypeProto(): |
| _write('GenericExtensionTypeProto('); |
| _referenceToText(proto.reference); |
| _typeArgumentsToText(proto.typeArguments); |
| _write(')'); |
| case TypedefProto(): |
| _write('TypedefProto('); |
| _referenceToText(proto.reference); |
| _write(')'); |
| case GenericTypedefProto(): |
| _write('GenericTypedefProto('); |
| _referenceToText(proto.reference); |
| _typeArgumentsToText(proto.typeArguments); |
| _write(')'); |
| case VoidProto(): |
| _write('VoidProto('); |
| _referenceToText(proto.reference); |
| _write(')'); |
| case DynamicProto(): |
| _write('DynamicProto('); |
| _referenceToText(proto.reference); |
| _write(')'); |
| case ConstructorProto(): |
| _write('ConstructorProto('); |
| _referenceToText(proto.type); |
| _referenceToText(proto.reference); |
| _typeArgumentsToText(proto.typeArguments); |
| _write(')'); |
| case FieldProto(): |
| _write('FieldProto('); |
| _referenceToText(proto.reference); |
| _write(')'); |
| case FunctionProto(): |
| _write('FunctionProto('); |
| _referenceToText(proto.reference); |
| _write(')'); |
| case FunctionInstantiationProto(): |
| _write('FunctionInstantiationProto('); |
| _referenceToText(proto.reference); |
| _typeArgumentsToText(proto.typeArguments); |
| _write(')'); |
| case PrefixProto(): |
| _write('PrefixProto('); |
| _write(proto.prefix); |
| _write(')'); |
| case IdentifierProto(): |
| _write('IdentifierProto('); |
| _write(proto.text); |
| if (proto.typeArguments != null) { |
| _typeArgumentsToText(proto.typeArguments!); |
| } |
| if (proto.arguments != null) { |
| _argumentsToText(proto.arguments!); |
| } |
| _write(')'); |
| case InstanceAccessProto(): |
| _write('InstanceAccessProto('); |
| _protoToText(proto.receiver); |
| if (proto.isNullAware) { |
| _write('?.'); |
| } else { |
| _write('.'); |
| } |
| _write(proto.text); |
| _write(')'); |
| case ExpressionInstantiationProto(): |
| _write('ExpressionInstantiationProto('); |
| _protoToText(proto.receiver); |
| _typeArgumentsToText(proto.typeArguments); |
| _write(')'); |
| case InstanceInvocationProto(): |
| _write('InstanceInvocationProto('); |
| _protoToText(proto.receiver); |
| _typeArgumentsToText(proto.typeArguments); |
| _argumentsToText(proto.arguments); |
| _write(')'); |
| case InvalidAccessProto(): |
| _write('InvalidAccessProto('); |
| _protoToText(proto.receiver); |
| _write(proto.text); |
| _write(')'); |
| case InvalidInstantiationProto(): |
| _write('InvalidInstantiationProto('); |
| _protoToText(proto.receiver); |
| _typeArgumentsToText(proto.typeArguments); |
| _write(')'); |
| case InvalidInvocationProto(): |
| _write('InvalidInvocationProto('); |
| _protoToText(proto.receiver); |
| _typeArgumentsToText(proto.typeArguments); |
| _argumentsToText(proto.arguments); |
| _write(')'); |
| case ExpressionProto(): |
| _write('ExpressionProto('); |
| _expressionToText(proto.expression); |
| _write(')'); |
| case FunctionTypeParameterProto(): |
| _write('FunctionTypeParameterProto('); |
| _write(proto.functionTypeParameter.name); |
| _write(')'); |
| } |
| } |
| } |