| // 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/type.dart'; |
| import 'package:analyzer/dart/element/nullability_suffix.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 cyclicInitializationErrorEncoding = 'DartType.CYCLICINITIALIZATIONERROR'; |
| 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 nullThrownErrorEncoding = 'DartType.NULLTHROWNERROR'; |
| 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 cyclicInitializationErrorLibs = 'cyclicInitializationErrorLibs'; |
| 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 nullThrownErrorLibs = 'nullThrownErrorLibs'; |
| 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, |
| assertionErrorEncoding: assertionErrorLibs, |
| boolEncoding: boolLibs, |
| byteDataEncoding: byteDataLibs, |
| castErrorEncoding: castErrorLibs, |
| concurrentModificationErrorEncoding: concurrentModificationErrorLibs, |
| cyclicInitializationErrorEncoding: cyclicInitializationErrorLibs, |
| 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, |
| nullThrownErrorEncoding: nullThrownErrorLibs, |
| 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, |
| }; |
| var result = <String, String>{}; |
| encodings.forEach((key, value) { |
| result[key] = value; |
| result[key + "_NULLABLE"] = value + "Nullable"; |
| }); |
| return result; |
| }(); |
| |
| // 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, |
| cyclicInitializationErrorEncoding, |
| 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, |
| nullThrownErrorEncoding, |
| 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. |
| for (var unit in library.units) { |
| visitCompilationUnit(unit); |
| } |
| } |
| |
| void visitCompilationUnit(CompilationUnitElement unit) { |
| // 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 unit.topLevelVariables) { |
| if (variable.isPublic) { |
| addToTable(typeString(variable.type), variable.name, |
| [voidEncoding, voidEncoding], |
| isMethod: false); |
| } |
| } |
| for (var function in unit.functions) { |
| if (function.isPublic && !function.isOperator) { |
| addToTable(typeString(function.returnType), function.name, |
| protoString(null, function.parameters)); |
| } |
| } |
| for (var classElement in unit.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.isNotEmpty) { |
| addToTable( |
| typeString(classElement.thisType), |
| '${classString(classElement)}.${constructor.name}', |
| protoString(null, constructor.parameters)); |
| } |
| } |
| 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.parameters)); |
| } else { |
| addToTable(typeString(method.returnType), method.name, |
| protoString(classElement.thisType, method.parameters)); |
| } |
| } |
| } |
| for (var accessor in classElement.accessors) { |
| if (accessor.isPublic && accessor.isGetter) { |
| 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.displayName) { |
| case 'AbstractClassInstantiationError': |
| return abstractClassInstantiationErrorEncoding; |
| case 'ArgumentError': |
| return argumentErrorEncoding; |
| case 'AssertionError': |
| return assertionErrorEncoding; |
| case 'CastError': |
| return castErrorEncoding; |
| case 'ConcurrentModificationError': |
| return concurrentModificationErrorEncoding; |
| case 'CyclicInitializationError': |
| return cyclicInitializationErrorEncoding; |
| 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 'NullThrownError': |
| return nullThrownErrorEncoding; |
| 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<ParameterElement> 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 invididual 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('}'); |
| } |