| // Copyright (c) 2020, 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 '../ast.dart'; |
| |
| String nullabilityToString(Nullability nullability) { |
| switch (nullability) { |
| case Nullability.legacy: |
| return '*'; |
| case Nullability.nullable: |
| return '?'; |
| case Nullability.undetermined: |
| return '%'; |
| case Nullability.nonNullable: |
| return ''; |
| } |
| } |
| |
| String nameToString(Name? node, {bool includeLibraryName = false}) { |
| if (node == null) { |
| return 'null'; |
| } else if (node.library != null && includeLibraryName) { |
| return '${libraryNameToString(node.library)}::${node.text}'; |
| } else { |
| return node.text; |
| } |
| } |
| |
| String libraryNameToString(Library? node) { |
| return node == null ? 'null' : node.name ?? 'library ${node.importUri}'; |
| } |
| |
| String libraryReferenceToString(Reference? reference) { |
| if (reference == null) { |
| return '<missing-library-reference>'; |
| } else { |
| Library? node = reference.node as Library?; |
| if (node != null) { |
| return node.importUri.toString(); |
| } else { |
| CanonicalName? canonicalName = reference.canonicalName; |
| if (canonicalName != null) { |
| return qualifiedCanonicalNameToString(canonicalName, |
| includeLibraryName: false); |
| } else { |
| return '<unlinked-library-reference>'; |
| } |
| } |
| } |
| } |
| |
| String qualifiedClassNameToString(Class node, |
| {bool includeLibraryName = false}) { |
| TreeNode? parent = node.parent; |
| if (parent is Library && includeLibraryName) { |
| return libraryNameToString(parent) + '::' + classNameToString(node); |
| } else { |
| return classNameToString(node); |
| } |
| } |
| |
| String qualifiedCanonicalNameToString(CanonicalName canonicalName, |
| {bool includeLibraryName = false, |
| bool includeLibraryNamesInTypes = false}) { |
| if (canonicalName.isRoot) { |
| return '<root>'; |
| } else if (canonicalName.parent!.isRoot) { |
| // Library. |
| return 'library ${canonicalName.name}'; |
| } else if (canonicalName.parent!.parent!.isRoot) { |
| // Class or extension. |
| if (!includeLibraryName) { |
| return canonicalName.name; |
| } |
| String parentName = qualifiedCanonicalNameToString(canonicalName.parent!, |
| includeLibraryName: includeLibraryName, |
| includeLibraryNamesInTypes: includeLibraryNamesInTypes); |
| return '$parentName::${canonicalName.name}'; |
| } else { |
| // Constructor, field, procedure (factory, getter, setter etc), typedef; |
| // but we could technically be anywhere in the "hierarchy" --- at the |
| // @typedef for instance, or at the uri of a library for a private name. |
| CanonicalName parentNotPrivateUri = canonicalName.parent!; |
| if (canonicalName.name.startsWith("_")) { |
| parentNotPrivateUri = parentNotPrivateUri.parent!; |
| } |
| if (parentNotPrivateUri.name == CanonicalName.typedefsName) { |
| includeLibraryName = includeLibraryNamesInTypes; |
| } |
| if (parentNotPrivateUri.parent!.parent!.parent?.isRoot == true) { |
| // Parent is class (or extension). |
| String parentName = qualifiedCanonicalNameToString( |
| parentNotPrivateUri.parent!, |
| includeLibraryName: includeLibraryName, |
| includeLibraryNamesInTypes: includeLibraryNamesInTypes); |
| return "$parentName.${canonicalName.name}"; |
| } else { |
| // Parent is library. |
| if (!includeLibraryName) { |
| return canonicalName.name; |
| } |
| String parentName = qualifiedCanonicalNameToString( |
| parentNotPrivateUri.parent!, |
| includeLibraryName: includeLibraryName, |
| includeLibraryNamesInTypes: includeLibraryNamesInTypes); |
| return '$parentName::${canonicalName.name}'; |
| } |
| } |
| } |
| |
| String qualifiedClassNameToStringByReference(Reference? reference, |
| {bool includeLibraryName = false}) { |
| if (reference == null) { |
| return '<missing-class-reference>'; |
| } else { |
| Class? node = reference.node as Class?; |
| if (node != null) { |
| return qualifiedClassNameToString(node, |
| includeLibraryName: includeLibraryName); |
| } else { |
| CanonicalName? canonicalName = reference.canonicalName; |
| if (canonicalName != null) { |
| return qualifiedCanonicalNameToString(canonicalName, |
| includeLibraryName: includeLibraryName); |
| } else { |
| return '<unlinked-class-reference>'; |
| } |
| } |
| } |
| } |
| |
| String classNameToString(Class? node) { |
| return node == null ? 'null' : node.name; |
| } |
| |
| String qualifiedExtensionNameToString(Extension node, |
| {bool includeLibraryName = false}) { |
| TreeNode? parent = node.parent; |
| if (parent is Library && includeLibraryName) { |
| return libraryNameToString(parent) + '::' + extensionNameToString(node); |
| } else { |
| return extensionNameToString(node); |
| } |
| } |
| |
| String qualifiedExtensionNameToStringByReference(Reference? reference, |
| {bool includeLibraryName = false}) { |
| if (reference == null) { |
| return '<missing-extension-reference>'; |
| } else { |
| Extension? node = reference.node as Extension?; |
| if (node != null) { |
| return qualifiedExtensionNameToString(node, |
| includeLibraryName: includeLibraryName); |
| } else { |
| CanonicalName? canonicalName = reference.canonicalName; |
| if (canonicalName != null) { |
| return qualifiedCanonicalNameToString(canonicalName, |
| includeLibraryName: includeLibraryName); |
| } else { |
| return '<unlinked-extension-reference>'; |
| } |
| } |
| } |
| } |
| |
| String extensionNameToString(Extension? node) { |
| return node == null ? 'null' : node.name; |
| } |
| |
| String qualifiedExtensionTypeDeclarationNameToString( |
| ExtensionTypeDeclaration node, |
| {bool includeLibraryName = false}) { |
| TreeNode? parent = node.parent; |
| if (parent is Library && includeLibraryName) { |
| return libraryNameToString(parent) + |
| '::' + |
| extensionTypeDeclarationNameToString(node); |
| } else { |
| return extensionTypeDeclarationNameToString(node); |
| } |
| } |
| |
| String qualifiedExtensionTypeDeclarationNameToStringByReference( |
| Reference? reference, |
| {bool includeLibraryName = false}) { |
| if (reference == null) { |
| return '<missing-extension-type-declaration-reference>'; |
| } else { |
| ExtensionTypeDeclaration? node = |
| reference.node as ExtensionTypeDeclaration?; |
| if (node != null) { |
| return qualifiedExtensionTypeDeclarationNameToString(node, |
| includeLibraryName: includeLibraryName); |
| } else { |
| CanonicalName? canonicalName = reference.canonicalName; |
| if (canonicalName != null) { |
| return qualifiedCanonicalNameToString(canonicalName, |
| includeLibraryName: includeLibraryName); |
| } else { |
| return '<unlinked-extension-type-declaration-reference>'; |
| } |
| } |
| } |
| } |
| |
| String extensionTypeDeclarationNameToString(ExtensionTypeDeclaration? node) { |
| return node == null ? 'null' : node.name; |
| } |
| |
| String qualifiedTypedefNameToString(Typedef node, |
| {bool includeLibraryName = false}) { |
| TreeNode? parent = node.parent; |
| if (parent is Library && includeLibraryName) { |
| return libraryNameToString(parent) + '::' + typedefNameToString(node); |
| } else { |
| return typedefNameToString(node); |
| } |
| } |
| |
| String qualifiedTypedefNameToStringByReference(Reference? reference, |
| {bool includeLibraryName = false}) { |
| if (reference == null) { |
| return '<missing-typedef-reference>'; |
| } else { |
| Typedef? node = reference.node as Typedef?; |
| if (node != null) { |
| return qualifiedTypedefNameToString(node, |
| includeLibraryName: includeLibraryName); |
| } else { |
| CanonicalName? canonicalName = reference.canonicalName; |
| if (canonicalName != null) { |
| return qualifiedCanonicalNameToString(canonicalName, |
| includeLibraryName: includeLibraryName); |
| } else { |
| return '<unlinked-typedef-reference>'; |
| } |
| } |
| } |
| } |
| |
| String typedefNameToString(Typedef? node) { |
| return node == null ? 'null' : node.name; |
| } |
| |
| String qualifiedMemberNameToString(Member node, |
| {bool includeLibraryName = false}) { |
| TreeNode? parent = node.parent; |
| if (parent is Class) { |
| return qualifiedClassNameToString(parent, |
| includeLibraryName: includeLibraryName) + |
| '.' + |
| memberNameToString(node); |
| } else if (parent is ExtensionTypeDeclaration) { |
| return qualifiedExtensionTypeDeclarationNameToString(parent, |
| includeLibraryName: includeLibraryName) + |
| '.' + |
| memberNameToString(node); |
| } else if (parent is Library && includeLibraryName) { |
| return libraryNameToString(parent) + '::' + memberNameToString(node); |
| } else { |
| return memberNameToString(node); |
| } |
| } |
| |
| String qualifiedMemberNameToStringByReference(Reference? reference, |
| {bool includeLibraryName = false}) { |
| if (reference == null) { |
| return '<missing-member-reference>'; |
| } else { |
| Member? node = reference.node as Member?; |
| if (node != null) { |
| return qualifiedMemberNameToString(node, |
| includeLibraryName: includeLibraryName); |
| } else { |
| CanonicalName? canonicalName = reference.canonicalName; |
| if (canonicalName != null) { |
| return qualifiedCanonicalNameToString(canonicalName, |
| includeLibraryName: includeLibraryName); |
| } else { |
| return '<unlinked-member-reference>'; |
| } |
| } |
| } |
| } |
| |
| String memberNameToString(Member node) { |
| return node.name.text; |
| } |
| |
| String qualifiedTypeParameterNameToString(TypeParameter node, |
| {required bool includeLibraryName, required bool recurseOnLocalFunction}) { |
| GenericDeclaration? declaration = node.declaration; |
| String? declarationName = |
| _qualifiedTypeParameterGenericDeclarationNameToString(declaration, |
| includeLibraryName: includeLibraryName, |
| recurseOnLocalFunction: recurseOnLocalFunction); |
| if (declarationName != null) { |
| return "$declarationName.${typeParameterNameToString(node)}"; |
| } |
| |
| return typeParameterNameToString(node); |
| } |
| |
| String? _qualifiedTypeParameterGenericDeclarationNameToString( |
| GenericDeclaration? declaration, |
| {required bool includeLibraryName, |
| required bool recurseOnLocalFunction}) { |
| switch (declaration) { |
| case Class(): |
| return qualifiedClassNameToString(declaration, |
| includeLibraryName: includeLibraryName); |
| case Extension(): |
| return qualifiedExtensionNameToString(declaration, |
| includeLibraryName: includeLibraryName); |
| case ExtensionTypeDeclaration(): |
| return qualifiedExtensionTypeDeclarationNameToString(declaration, |
| includeLibraryName: includeLibraryName); |
| case Typedef(): |
| return qualifiedTypedefNameToString(declaration, |
| includeLibraryName: includeLibraryName); |
| case Procedure(): |
| return qualifiedMemberNameToString(declaration, |
| includeLibraryName: includeLibraryName); |
| case LocalFunction(): |
| if (recurseOnLocalFunction && |
| declaration is FunctionDeclaration && |
| declaration.variable.name != null) { |
| TreeNode? parent = declaration.parent; |
| while (parent != null && parent is! GenericDeclaration) { |
| parent = parent.parent; |
| } |
| if (parent is GenericDeclaration) { |
| String? parentName = |
| _qualifiedTypeParameterGenericDeclarationNameToString(parent, |
| includeLibraryName: includeLibraryName, |
| recurseOnLocalFunction: recurseOnLocalFunction); |
| return "$parentName.${declaration.variable.name}"; |
| } |
| } |
| return null; |
| case null: |
| return null; |
| } |
| } |
| |
| String qualifiedStructuralParameterNameToString(StructuralParameter node, |
| {bool includeLibraryName = false}) { |
| return structuralParameterNameToString(node); |
| } |
| |
| String typeParameterNameToString(TypeParameter node) { |
| return node.name ?? |
| "null-named TypeParameter ${node.runtimeType} ${node.hashCode}"; |
| } |
| |
| String structuralParameterNameToString(StructuralParameter node) { |
| return node.name ?? |
| "null-named StructuralParameter " |
| "${node.runtimeType} ${node.hashCode}"; |
| } |
| |
| String? getEscapedCharacter(int codeUnit) { |
| switch (codeUnit) { |
| case 9: |
| return r'\t'; |
| case 10: |
| return r'\n'; |
| case 11: |
| return r'\v'; |
| case 12: |
| return r'\f'; |
| case 13: |
| return r'\r'; |
| case 34: |
| return r'\"'; |
| case 36: |
| return r'\$'; |
| case 92: |
| return r'\\'; |
| default: |
| if (codeUnit < 32 || codeUnit > 126) { |
| return r'\u' + '$codeUnit'.padLeft(4, '0'); |
| } else { |
| return null; |
| } |
| } |
| } |
| |
| String escapeString(String string) { |
| StringBuffer? buffer; |
| for (int i = 0; i < string.length; ++i) { |
| String? character = getEscapedCharacter(string.codeUnitAt(i)); |
| if (character != null) { |
| buffer ??= new StringBuffer(string.substring(0, i)); |
| buffer.write(character); |
| } else { |
| buffer?.write(string[i]); |
| } |
| } |
| return buffer == null ? string : buffer.toString(); |
| } |