| // 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({required bool addNewLine}) { | |
| const int amount = 1; | |
| _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(')'); | |
| } | |
| } | |
| } |