| // Copyright (c) 2019, 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. | |
| // Generates the API tables used by DartFuzz. Automatically generating these | |
| // tables is less error-prone than generating such tables by hand. Furthermore, | |
| // it simplifies regenerating the table when the libraries change. | |
| // | |
| // Usage: | |
| // dart gen_api_table.dart > dartfuzz_api_table.dart | |
| // | |
| // Then send out modified dartfuzz_api_table.dart for review together | |
| // with a modified dartfuzz.dart that increases the version. | |
| import 'package:analyzer/dart/analysis/results.dart'; | |
| import 'package:analyzer/dart/analysis/session.dart'; | |
| import 'package:analyzer/dart/element/element.dart'; | |
| import 'package:analyzer/dart/element/nullability_suffix.dart'; | |
| import 'package:analyzer/dart/element/type.dart'; | |
| import 'gen_util.dart'; | |
| // Enum for different restrictions on parameters for library methods. | |
| // none - No restriction on the corresponding parameter. | |
| // small - Corresponding parameter should be a small value. | |
| // This enum has an equivalent enum in the generated Dartfuzz API table. | |
| enum Restriction { none, small } | |
| // Class that represents Dart library methods. | |
| // | |
| // Proto is a list (of Strings that represent DartTypes) whose first element is | |
| // the DartType of the receiver (DartType.VOID if none). The remaining elements | |
| // are DartTypes of the parameters. The second element is DartType.VOID if there | |
| // are no parameters. | |
| // This class has an equivalent class in the generated Dartfuzz API table. | |
| class DartLib { | |
| final String name; | |
| final List<String> proto; | |
| final List<Restriction>? restrictions; | |
| final bool isMethod; | |
| const DartLib(this.name, this.proto, this.restrictions, this.isMethod); | |
| } | |
| // Constants for strings corresponding to the DartType. | |
| const abstractClassInstantiationErrorEncoding = | |
| 'DartType.ABSTRACTCLASSINSTANTIATIONERROR'; | |
| const argumentErrorEncoding = 'DartType.ARGUMENTERROR'; | |
| const assertionErrorEncoding = 'DartType.ERROR'; | |
| const boolEncoding = 'DartType.BOOL'; | |
| const byteDataEncoding = 'DartType.BYTEDATA'; | |
| const castErrorEncoding = 'DartType.CASTERROR'; | |
| const concurrentModificationErrorEncoding = | |
| 'DartType.CONCURRENTMODIFICATIONERROR'; | |
| const deprecatedEncoding = 'DartType.DEPRECATED'; | |
| const doubleEncoding = 'DartType.DOUBLE'; | |
| const endianEncoding = 'DartType.ENDIAN'; | |
| const errorEncoding = 'DartType.ERROR'; | |
| const exceptionEncoding = 'DartType.EXCEPTION'; | |
| const expandoDoubleEncoding = 'DartType.EXPANDO_DOUBLE'; | |
| const expandoIntEncoding = 'DartType.EXPANDO_INT'; | |
| const fallThroughErrorEncoding = 'DartType.FALLTHROUGHERROR'; | |
| const float32ListEncoding = 'DartType.FLOAT32LIST'; | |
| const float32x4Encoding = 'DartType.FLOAT32X4'; | |
| const float32x4ListEncoding = 'DartType.FLOAT32X4LIST'; | |
| const float64ListEncoding = 'DartType.FLOAT64LIST'; | |
| const float64x2Encoding = 'DartType.FLOAT64X2'; | |
| const float64x2ListEncoding = 'DartType.FLOAT64X2LIST'; | |
| const formatExceptionEncoding = 'DartType.FORMATEXCEPTION'; | |
| const indexErrorEncoding = 'DartType.INDEXERROR'; | |
| const int16ListEncoding = 'DartType.INT16LIST'; | |
| const int32ListEncoding = 'DartType.INT32LIST'; | |
| const int32x4Encoding = 'DartType.INT32X4'; | |
| const int32x4ListEncoding = 'DartType.INT32X4LIST'; | |
| const int64ListEncoding = 'DartType.INT64LIST'; | |
| const int8ListEncoding = 'DartType.INT8LIST'; | |
| const intEncoding = 'DartType.INT'; | |
| const integerDivisionByZeroExceptionEncoding = | |
| 'DartType.INTEGERDIVISIONBYZEROEXCEPTION'; | |
| const listIntEncoding = 'DartType.LIST_INT'; | |
| const mapEntryIntStringEncoding = 'DartType.MAPENTRY_INT_STRING'; | |
| const mapIntStringEncoding = 'DartType.MAP_INT_STRING'; | |
| const nullEncoding = 'DartType.NULL'; | |
| const numEncoding = 'DartType.NUM'; | |
| const provisionalEncoding = 'DartType.PROVISIONAL'; | |
| const rangeErrorEncoding = 'DartType.RANGEERROR'; | |
| const regExpEncoding = 'DartType.REGEXP'; | |
| const runeIteratorEncoding = 'DartType.RUNEITERATOR'; | |
| const runesEncoding = 'DartType.RUNES'; | |
| const setIntEncoding = 'DartType.SET_INT'; | |
| const stackOverflowErrorEncoding = 'DartType.STACKOVERFLOWERROR'; | |
| const stateErrorEncoding = 'DartType.STATEERROR'; | |
| const stringBufferEncoding = 'DartType.STRINGBUFFER'; | |
| const stringEncoding = 'DartType.STRING'; | |
| const symbolEncoding = 'DartType.SYMBOL'; | |
| const typeErrorEncoding = 'DartType.TYPEERROR'; | |
| const uint16ListEncoding = 'DartType.UINT16LIST'; | |
| const uint32ListEncoding = 'DartType.UINT32LIST'; | |
| const uint64ListEncoding = 'DartType.UINT64LIST'; | |
| const uint8ClampedListEncoding = 'DartType.UINT8CLAMPEDLIST'; | |
| const uint8ListEncoding = 'DartType.UINT8LIST'; | |
| const unimplementedErrorEncoding = 'DartType.UNIMPLEMENTEDERROR'; | |
| const unsupportedErrorEncoding = 'DartType.UNSUPPORTEDERROR'; | |
| const voidEncoding = 'DartType.VOID'; | |
| // Constants for the library methods lists' names in dart_api_table.dart. | |
| final abstractClassInstantiationErrorLibs = | |
| 'abstractClassInstantiationErrorLibs'; | |
| final argumentErrorLibs = 'argumentErrorLibs'; | |
| final assertionErrorLibs = 'assertionErrorLibs'; | |
| final boolLibs = 'boolLibs'; | |
| final byteDataLibs = 'byteDataLibs'; | |
| final castErrorLibs = 'castErrorLibs'; | |
| final concurrentModificationErrorLibs = 'concurrentModificationErrorLibs'; | |
| final deprecatedLibs = 'deprecatedLibs'; | |
| final doubleLibs = 'doubleLibs'; | |
| final endianLibs = 'endianLibs'; | |
| final errorLibs = 'errorLibs'; | |
| final exceptionLibs = 'exceptionLibs'; | |
| final expandoDoubleLibs = 'expandoDoubleLibs'; | |
| final expandoIntLibs = 'expandoIntLibs'; | |
| final fallThroughErrorLibs = 'fallThroughErrorLibs'; | |
| final float32ListLibs = 'float32ListLibs'; | |
| final float32x4Libs = 'float32x4Libs'; | |
| final float32x4ListLibs = 'float32x4ListLibs'; | |
| final float64ListLibs = 'float64ListLibs'; | |
| final float64x2Libs = 'float64x2Libs'; | |
| final float64x2ListLibs = 'float64x2ListLibs'; | |
| final formatExceptionLibs = 'formatExceptionLibs'; | |
| final indexErrorLibs = 'indexErrorLibs'; | |
| final int16ListLibs = 'int16ListLibs'; | |
| final int32ListLibs = 'int32ListLibs'; | |
| final int32x4Libs = 'int32x4Libs'; | |
| final int32x4ListLibs = 'int32x4ListLibs'; | |
| final int64ListLibs = 'int64ListLibs'; | |
| final int8ListLibs = 'int8ListLibs'; | |
| final intLibs = 'intLibs'; | |
| final integerDivisionByZeroExceptionLibs = 'integerDivisionByZeroExceptionLibs'; | |
| final listLibs = 'listLibs'; | |
| final mapEntryIntStringLibs = 'mapEntryIntStringLibs'; | |
| final mapLibs = 'mapLibs'; | |
| final nullLibs = 'nullLibs'; | |
| final numLibs = 'numLibs'; | |
| final provisionalLibs = 'provisionalLibs'; | |
| final rangeErrorLibs = 'rangeErrorLibs'; | |
| final regExpLibs = 'regExpLibs'; | |
| final runeIteratorLibs = 'runeIteratorLibs'; | |
| final runesLibs = 'runesLibs'; | |
| final setLibs = 'setLibs'; | |
| final stackOverflowErrorLibs = 'stackOverflowErrorLibs'; | |
| final stateErrorLibs = 'stateErrorLibs'; | |
| final stringBufferLibs = 'stringBufferLibs'; | |
| final stringLibs = 'stringLibs'; | |
| final symbolLibs = 'symbolLibs'; | |
| final typeErrorLibs = 'typeErrorLibs'; | |
| final uint16ListLibs = 'uint16ListLibs'; | |
| final uint32ListLibs = 'uint32ListLibs'; | |
| final uint64ListLibs = 'uint64ListLibs'; | |
| final uint8ClampedListLibs = 'uint8ClampedListLibs'; | |
| final uint8ListLibs = 'uint8ListLibs'; | |
| final unimplementedErrorLibs = 'unimplementedErrorLibs'; | |
| final unsupportedErrorLibs = 'unsupportedErrorLibs'; | |
| final voidLibs = 'voidLibs'; | |
| // Map from the DartType (string) to the name of the library methods list. | |
| final Map<String, String> typeToLibraryMethodsListName = () { | |
| var encodings = <String, String>{ | |
| abstractClassInstantiationErrorEncoding: | |
| abstractClassInstantiationErrorLibs, | |
| argumentErrorEncoding: argumentErrorLibs, | |
| boolEncoding: boolLibs, | |
| byteDataEncoding: byteDataLibs, | |
| castErrorEncoding: castErrorLibs, | |
| concurrentModificationErrorEncoding: concurrentModificationErrorLibs, | |
| deprecatedEncoding: deprecatedLibs, | |
| doubleEncoding: doubleLibs, | |
| endianEncoding: endianLibs, | |
| errorEncoding: errorLibs, | |
| exceptionEncoding: exceptionLibs, | |
| expandoDoubleEncoding: expandoDoubleLibs, | |
| expandoIntEncoding: expandoIntLibs, | |
| fallThroughErrorEncoding: fallThroughErrorLibs, | |
| float32ListEncoding: float32ListLibs, | |
| float32x4Encoding: float32x4Libs, | |
| float32x4ListEncoding: float32x4ListLibs, | |
| float64ListEncoding: float64ListLibs, | |
| float64x2Encoding: float64x2Libs, | |
| float64x2ListEncoding: float64x2ListLibs, | |
| formatExceptionEncoding: formatExceptionLibs, | |
| indexErrorEncoding: indexErrorLibs, | |
| int16ListEncoding: int16ListLibs, | |
| int32ListEncoding: int32ListLibs, | |
| int32x4Encoding: int32x4Libs, | |
| int32x4ListEncoding: int32x4ListLibs, | |
| int64ListEncoding: int64ListLibs, | |
| int8ListEncoding: int8ListLibs, | |
| intEncoding: intLibs, | |
| integerDivisionByZeroExceptionEncoding: integerDivisionByZeroExceptionLibs, | |
| listIntEncoding: listLibs, | |
| mapEntryIntStringEncoding: mapEntryIntStringLibs, | |
| mapIntStringEncoding: mapLibs, | |
| nullEncoding: nullLibs, | |
| numEncoding: numLibs, | |
| provisionalEncoding: provisionalLibs, | |
| rangeErrorEncoding: rangeErrorLibs, | |
| regExpEncoding: regExpLibs, | |
| runeIteratorEncoding: runeIteratorLibs, | |
| runesEncoding: runesLibs, | |
| setIntEncoding: setLibs, | |
| stackOverflowErrorEncoding: stackOverflowErrorLibs, | |
| stateErrorEncoding: stateErrorLibs, | |
| stringBufferEncoding: stringBufferLibs, | |
| stringEncoding: stringLibs, | |
| symbolEncoding: symbolLibs, | |
| typeErrorEncoding: typeErrorLibs, | |
| uint16ListEncoding: uint16ListLibs, | |
| uint32ListEncoding: uint32ListLibs, | |
| uint64ListEncoding: uint64ListLibs, | |
| uint8ClampedListEncoding: uint8ClampedListLibs, | |
| uint8ListEncoding: uint8ListLibs, | |
| unimplementedErrorEncoding: unimplementedErrorLibs, | |
| unsupportedErrorEncoding: unsupportedErrorLibs, | |
| voidEncoding: voidLibs, | |
| }; | |
| return { | |
| for (var MapEntry(:key, :value) in encodings.entries) key: value, | |
| for (var MapEntry(:key, :value) in encodings.entries) | |
| if (key != voidEncoding) '${key}_NULLABLE': '${value}Nullable', | |
| }; | |
| }(); | |
| // Map from return type encoding to list of recognized methods with that | |
| // return type. | |
| final Map<String, List<DartLib>> typeToLibraryMethodsList = () { | |
| var encodings = <String>[ | |
| abstractClassInstantiationErrorEncoding, | |
| argumentErrorEncoding, | |
| assertionErrorEncoding, | |
| boolEncoding, | |
| byteDataEncoding, | |
| castErrorEncoding, | |
| concurrentModificationErrorEncoding, | |
| deprecatedEncoding, | |
| doubleEncoding, | |
| endianEncoding, | |
| errorEncoding, | |
| exceptionEncoding, | |
| expandoDoubleEncoding, | |
| expandoIntEncoding, | |
| fallThroughErrorEncoding, | |
| float32ListEncoding, | |
| float32x4Encoding, | |
| float32x4ListEncoding, | |
| float64ListEncoding, | |
| float64x2Encoding, | |
| float64x2ListEncoding, | |
| formatExceptionEncoding, | |
| indexErrorEncoding, | |
| int16ListEncoding, | |
| int32ListEncoding, | |
| int32x4Encoding, | |
| int32x4ListEncoding, | |
| int64ListEncoding, | |
| int8ListEncoding, | |
| intEncoding, | |
| integerDivisionByZeroExceptionEncoding, | |
| listIntEncoding, | |
| mapEntryIntStringEncoding, | |
| mapIntStringEncoding, | |
| nullEncoding, | |
| numEncoding, | |
| provisionalEncoding, | |
| rangeErrorEncoding, | |
| regExpEncoding, | |
| runeIteratorEncoding, | |
| runesEncoding, | |
| setIntEncoding, | |
| stackOverflowErrorEncoding, | |
| stateErrorEncoding, | |
| stringBufferEncoding, | |
| stringEncoding, | |
| symbolEncoding, | |
| typeErrorEncoding, | |
| uint16ListEncoding, | |
| uint32ListEncoding, | |
| uint64ListEncoding, | |
| uint8ClampedListEncoding, | |
| uint8ListEncoding, | |
| unimplementedErrorEncoding, | |
| unsupportedErrorEncoding, | |
| voidEncoding, | |
| ]; | |
| var result = <String, List<DartLib>>{}; | |
| for (var encoding in encodings) { | |
| result[encoding] = <DartLib>[]; | |
| result[encoding + "_NULLABLE"] = <DartLib>[]; | |
| } | |
| return result; | |
| }(); | |
| final typedDataFloatTypes = [ | |
| float32ListEncoding, | |
| float32x4Encoding, | |
| float32x4ListEncoding, | |
| float64ListEncoding, | |
| float64x2Encoding, | |
| float64x2ListEncoding, | |
| ]; | |
| void main() async { | |
| final session = GenUtil.createAnalysisSession(); | |
| // Visit libraries for table generation. | |
| await visitLibraryAtUri(session, 'dart:async'); | |
| await visitLibraryAtUri(session, 'dart:cli'); | |
| await visitLibraryAtUri(session, 'dart:collection'); | |
| await visitLibraryAtUri(session, 'dart:convert'); | |
| await visitLibraryAtUri(session, 'dart:core'); | |
| await visitLibraryAtUri(session, 'dart:io'); | |
| await visitLibraryAtUri(session, 'dart:isolate'); | |
| await visitLibraryAtUri(session, 'dart:math'); | |
| await visitLibraryAtUri(session, 'dart:typed_data'); | |
| // Generate the tables in a stand-alone Dart class. | |
| dumpHeader(); | |
| dumpTypeToLibraryMethodMap(); | |
| dumpTypedDataFloatTypes(); | |
| for (var key in typeToLibraryMethodsList.keys.toList()..sort()) { | |
| if (typeToLibraryMethodsList[key]!.isNotEmpty) { | |
| // Only output library methods lists that are non-empty. | |
| dumpTable( | |
| typeToLibraryMethodsListName[key]!, | |
| typeToLibraryMethodsList[key]!, | |
| ); | |
| } | |
| } | |
| dumpFooter(); | |
| } | |
| Future<void> visitLibraryAtUri(AnalysisSession session, String uri) async { | |
| final libPath = session.uriConverter.uriToPath(Uri.parse(uri)); | |
| var result = await session.getResolvedLibrary(libPath!); | |
| if (result is ResolvedLibraryResult) { | |
| visitLibrary(result.element); | |
| } else { | |
| throw StateError('Unable to resolve "$uri"'); | |
| } | |
| } | |
| void visitLibrary(LibraryElement library) { | |
| // This uses the element model to traverse the code. The element model | |
| // represents the semantic structure of the code. A library consists of | |
| // one or more compilation units. | |
| // | |
| // Each compilation unit contains elements for all of the top-level | |
| // declarations in a single file, such as variables, functions, and | |
| // classes. Note that `types` only returns classes. You can use | |
| // `mixins` to visit mixins, `enums` to visit enum, `functionTypeAliases` | |
| // to visit typedefs, etc. | |
| for (var variable in library.topLevelVariables) { | |
| if (variable.isPublic) { | |
| addToTable(typeString(variable.type), variable.name!, [ | |
| voidEncoding, | |
| voidEncoding, | |
| ], isMethod: false); | |
| } | |
| } | |
| for (var function in library.topLevelFunctions) { | |
| if (function.isPublic) { | |
| addToTable( | |
| typeString(function.returnType), | |
| function.name!, | |
| protoString(null, function.formalParameters), | |
| ); | |
| } | |
| } | |
| for (var classElement in library.classes) { | |
| if (classElement.isPublic) { | |
| visitClass(classElement); | |
| } | |
| } | |
| } | |
| void visitClass(ClassElement classElement) { | |
| // Classes that cause too many false divergences. | |
| if (classElement.name == 'ProcessInfo' || | |
| classElement.name == 'Platform' || | |
| classElement.name!.startsWith('FileSystem')) { | |
| return; | |
| } | |
| // Every class element contains elements for the members, viz. `methods` visits | |
| // methods, `fields` visits fields, `accessors` visits getters and setters, etc. | |
| // There are also accessors to get the superclass, mixins, interfaces, type | |
| // parameters, etc. | |
| for (var constructor in classElement.constructors) { | |
| if (constructor.isPublic && | |
| constructor.isFactory && | |
| constructor.name != 'new') { | |
| addToTable( | |
| typeString(classElement.thisType), | |
| '${classString(classElement)}.${constructor.name}', | |
| protoString(null, constructor.formalParameters), | |
| ); | |
| } | |
| } | |
| for (var method in classElement.methods) { | |
| if (method.isPublic && !method.isOperator) { | |
| if (method.isStatic) { | |
| addToTable( | |
| typeString(method.returnType), | |
| '${classString(classElement)}.${method.name}', | |
| protoString(null, method.formalParameters), | |
| ); | |
| } else { | |
| addToTable( | |
| typeString(method.returnType), | |
| method.name!, | |
| protoString(classElement.thisType, method.formalParameters), | |
| ); | |
| } | |
| } | |
| } | |
| for (var accessor in classElement.getters) { | |
| if (accessor.isPublic) { | |
| var variable = accessor.variable; | |
| if (accessor.isStatic) { | |
| addToTable( | |
| typeString(variable.type), | |
| '${classElement.name}.${variable.name}', | |
| [voidEncoding, voidEncoding], | |
| isMethod: false, | |
| ); | |
| } else { | |
| addToTable(typeString(variable.type), variable.name!, [ | |
| typeString(classElement.thisType), | |
| voidEncoding, | |
| ], isMethod: false); | |
| } | |
| } | |
| } | |
| } | |
| // Function that returns the explicit class name. | |
| String classString(ClassElement classElement) { | |
| switch (typeString(classElement.thisType)) { | |
| case setIntEncoding: | |
| return 'Set<int>'; | |
| case listIntEncoding: | |
| return 'List<int>'; | |
| case mapIntStringEncoding: | |
| return 'Map<int, String>'; | |
| default: | |
| return classElement.name!; | |
| } | |
| } | |
| // Types are represented by an instance of `DartType`. For classes, the type | |
| // will be an instance of `InterfaceType`, which will provide access to the | |
| // defining (class) element, as well as any type arguments. | |
| String typeString(DartType type) { | |
| String result = typeStringHelper(type); | |
| if (result == "?") { | |
| return result; | |
| } | |
| if (type.nullabilitySuffix == NullabilitySuffix.none) { | |
| return result; | |
| } | |
| return result + "_NULLABLE"; | |
| } | |
| String typeStringHelper(DartType type) { | |
| if (type.isDartCoreBool) { | |
| return boolEncoding; | |
| } else if (type.isDartCoreInt) { | |
| return intEncoding; | |
| } else if (type.isDartCoreDouble) { | |
| return doubleEncoding; | |
| } else if (type.isDartCoreString) { | |
| return stringEncoding; | |
| } | |
| // Supertypes or type parameters are specialized in a consistent manner. | |
| // TODO(ajcbik): inspect type structure semantically, not by display name | |
| // and unify DartFuzz's DartType with analyzer DartType. | |
| switch (type.asCode) { | |
| case 'AbstractClassInstantiationError': | |
| return abstractClassInstantiationErrorEncoding; | |
| case 'ArgumentError': | |
| return argumentErrorEncoding; | |
| case 'AssertionError': | |
| return assertionErrorEncoding; | |
| case 'CastError': | |
| return castErrorEncoding; | |
| case 'ConcurrentModificationError': | |
| return concurrentModificationErrorEncoding; | |
| case 'Deprecated': | |
| return deprecatedEncoding; | |
| case 'E': | |
| return intEncoding; | |
| case 'Endian': | |
| return endianEncoding; | |
| case 'Error': | |
| return errorEncoding; | |
| case 'Exception': | |
| return exceptionEncoding; | |
| case 'Expando<double>': | |
| return expandoDoubleEncoding; | |
| case 'Expando<int>': | |
| return expandoIntEncoding; | |
| case 'FallThroughError': | |
| return fallThroughErrorEncoding; | |
| case 'Float32List': | |
| return float32ListEncoding; | |
| case 'Float32x4': | |
| return float32x4Encoding; | |
| case 'Float32x4List': | |
| return float32x4ListEncoding; | |
| case 'Float64List': | |
| return float64ListEncoding; | |
| case 'Float64x2': | |
| return float64x2Encoding; | |
| case 'Float64x2List': | |
| return float64x2ListEncoding; | |
| case 'FormatException': | |
| return formatExceptionEncoding; | |
| case 'IndexError': | |
| return indexErrorEncoding; | |
| case 'Int16List': | |
| return int16ListEncoding; | |
| case 'Int32List': | |
| return int32ListEncoding; | |
| case 'Int32x4': | |
| return int32x4Encoding; | |
| case 'Int32x4List': | |
| return int32x4ListEncoding; | |
| case 'Int64List': | |
| return int64ListEncoding; | |
| case 'Int8List': | |
| return int8ListEncoding; | |
| case 'IntegerDivisionByZeroException': | |
| return integerDivisionByZeroExceptionEncoding; | |
| case 'List': | |
| case 'List<E>': | |
| case 'List<Object>': | |
| case 'List<dynamic>': | |
| case 'List<int>': | |
| return listIntEncoding; | |
| case 'Map': | |
| case 'Map<K, V>': | |
| case 'Map<dynamic, dynamic>': | |
| case 'Map<int, String>': | |
| return mapIntStringEncoding; | |
| case 'MapEntry': | |
| case 'MapEntry<K, V>': | |
| case 'MapEntry<dynamic, dynamic>': | |
| case 'MapEntry<int, String>': | |
| return mapEntryIntStringEncoding; | |
| case 'Null': | |
| return nullEncoding; | |
| case 'Provisional': | |
| return provisionalEncoding; | |
| case 'RangeError': | |
| return rangeErrorEncoding; | |
| case 'RegExp': | |
| return regExpEncoding; | |
| case 'RuneIterator': | |
| return runeIteratorEncoding; | |
| case 'Runes': | |
| return runesEncoding; | |
| case 'Set': | |
| case 'Set<E>': | |
| case 'Set<Object>': | |
| case 'Set<dynamic>': | |
| case 'Set<int>': | |
| return setIntEncoding; | |
| case 'StackOverflowError': | |
| return stackOverflowErrorEncoding; | |
| case 'StateError': | |
| return stateErrorEncoding; | |
| case 'StringBuffer': | |
| return stringBufferEncoding; | |
| case 'Symbol': | |
| return symbolEncoding; | |
| case 'TypeError': | |
| return typeErrorEncoding; | |
| case 'Uint16List': | |
| return uint16ListEncoding; | |
| case 'Uint32List': | |
| return uint32ListEncoding; | |
| case 'Uint64List': | |
| return uint64ListEncoding; | |
| case 'Uint8ClampedList': | |
| return uint8ClampedListEncoding; | |
| case 'Uint8List': | |
| return uint8ListEncoding; | |
| case 'UnimplementedError': | |
| return unimplementedErrorEncoding; | |
| case 'UnsupportedError': | |
| return unsupportedErrorEncoding; | |
| case 'num': | |
| return doubleEncoding; | |
| case 'void': | |
| return voidEncoding; | |
| } | |
| return '?'; | |
| } | |
| List<String> protoString( | |
| DartType? receiver, | |
| List<FormalParameterElement> parameters, | |
| ) { | |
| final proto = [receiver == null ? voidEncoding : typeString(receiver)]; | |
| // Construct prototype for non-named parameters. | |
| for (var parameter in parameters) { | |
| if (!parameter.isNamed) { | |
| proto.add(typeString(parameter.type)); | |
| } | |
| } | |
| // Use 'void' for an empty parameter list. | |
| proto.length == 1 ? proto.add(voidEncoding) : proto; | |
| return proto; | |
| } | |
| List<DartLib> getTable(String ret) => typeToLibraryMethodsList.containsKey(ret) | |
| ? typeToLibraryMethodsList[ret]! | |
| : throw ArgumentError('Invalid ret value: $ret'); | |
| void addToTable( | |
| String ret, | |
| String name, | |
| List<String> proto, { | |
| bool isMethod = true, | |
| }) { | |
| // If any of the type representations equal a question | |
| // mark, this means that DartFuzz' type system cannot | |
| // deal with such an expression yet. So drop the entry. | |
| if (ret == '?' || proto.contains('?')) { | |
| return; | |
| } | |
| // Avoid the exit function and other functions that give false divergences. | |
| // Note: to prevent certain constructors from being emitted, update the | |
| // exclude list in `shouldFilterConstructor` in gen_type_table.dart and | |
| // regenerate the type table. | |
| if (name == 'exit' || | |
| name == 'pid' || | |
| name == 'hashCode' || | |
| name == 'exitCode' || | |
| // TODO(fizaaluthra): Enable reciprocal and reciprocalSqrt after we resolve | |
| // https://github.com/dart-lang/sdk/issues/39551 | |
| name == 'reciprocal' || | |
| name == 'reciprocalSqrt') { | |
| return; | |
| } | |
| List<Restriction>? restrictions; | |
| // Restrict parameters for a few hardcoded cases, | |
| // for example, to avoid excessive runtime or memory | |
| // allocation in the generated fuzzing program. | |
| if (name == 'padLeft' || name == 'padRight') { | |
| for (var i = 0; i < proto.length - 1; ++i) { | |
| if (proto[i] == intEncoding && proto[i + 1] == stringEncoding) { | |
| restrictions = List<Restriction>.filled(proto.length, Restriction.none); | |
| restrictions[i] = Restriction.small; | |
| restrictions[i + 1] = Restriction.small; | |
| break; | |
| } | |
| } | |
| } else if (name == 'List<int>.filled') { | |
| for (var i = 0; i < proto.length; ++i) { | |
| if (proto[i] == intEncoding) { | |
| restrictions = List<Restriction>.filled(proto.length, Restriction.none); | |
| restrictions[i] = Restriction.small; | |
| break; | |
| } | |
| } | |
| } | |
| // Add to table. | |
| getTable(ret).add(DartLib(name, proto, restrictions, isMethod)); | |
| // Every non-nullable result is also a valid nullable result. | |
| if (!ret.endsWith("_NULLABLE")) { | |
| getTable( | |
| "${ret}_NULLABLE", | |
| ).add(DartLib(name, proto, restrictions, isMethod)); | |
| } | |
| } | |
| void dumpHeader() { | |
| print(''' | |
| // Copyright (c) 2019, 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. | |
| /// NOTE: this code has been generated automatically. | |
| import 'dartfuzz_type_table.dart'; | |
| /// Enum for different restrictions on parameters for library methods. | |
| /// none - No restriction on the corresponding parameter. | |
| /// small - Corresponding parameter should be a small value. | |
| enum Restriction { | |
| none, | |
| small | |
| } | |
| /// Class that represents Dart library methods. | |
| /// | |
| /// The individual lists are organized by return type. | |
| /// Proto is a list of DartTypes whose first element is the type of the | |
| /// DartType of the receiver (DartType.VOID if none). The remaining elements are | |
| /// DartTypes of the parameters. The second element is DartType.VOID if there | |
| /// are no parameters. | |
| class DartLib { | |
| final String name; | |
| final List<DartType> proto; | |
| final List<Restriction>? restrictions; | |
| final bool isMethod; | |
| const DartLib(this.name, this.proto, this.isMethod, | |
| {this.restrictions}); | |
| Restriction getRestriction(int paramIndex) => (restrictions == null) ? | |
| Restriction.none : restrictions![paramIndex]; | |
| '''); | |
| } | |
| void dumpTypeToLibraryMethodMap() { | |
| print(' static final typeToLibraryMethods = {'); | |
| for (var key in typeToLibraryMethodsListName.keys.toList()..sort()) { | |
| if (typeToLibraryMethodsList[key]!.isNotEmpty) { | |
| // Only output a mapping from type to library methods list name for those | |
| // types that have a non-empty library methods list. | |
| print(' $key: ${typeToLibraryMethodsListName[key]},'); | |
| } | |
| } | |
| print(' };'); | |
| } | |
| void dumpTypedDataFloatTypes() { | |
| print(' static const typedDataFloatTypes = ['); | |
| for (var type in typedDataFloatTypes) { | |
| print(' $type,'); | |
| } | |
| print(' ];'); | |
| } | |
| void dumpTable(String identifier, List<DartLib> table) { | |
| print(' static const $identifier = ['); | |
| table.sort( | |
| (a, b) => (a.name.compareTo(b.name) == 0) | |
| ? a.proto.join().compareTo(b.proto.join()) | |
| : a.name.compareTo(b.name), | |
| ); | |
| table.forEach( | |
| (t) => print( | |
| ' DartLib(\'${t.name}\', ${t.proto}, ${t.isMethod}' | |
| '${t.restrictions == null ? "" : ", " | |
| "restrictions: ${t.restrictions}"}),', | |
| ), | |
| ); | |
| print(' ];'); | |
| } | |
| void dumpFooter() { | |
| print('}'); | |
| } |