| // Copyright (c) 2023, 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 'dart:io' show Directory, File; |
| |
| import 'package:_fe_analyzer_shared/src/util/options.dart'; |
| import 'package:front_end/src/api_prototype/compiler_options.dart' |
| show parseExperimentalArguments, parseExperimentalFlags; |
| import 'package:front_end/src/api_prototype/experimental_flags.dart' |
| show ExperimentalFlag; |
| import 'package:front_end/src/base/command_line_options.dart'; |
| import 'package:testing/testing.dart' show TestDescription; |
| |
| const Option<String?> overwriteCurrentSdkVersion = const Option( |
| '--overwrite-current-sdk-version', |
| const StringValue(), |
| ); |
| const Option<bool> noVerifyCmd = const Option( |
| '--no-verify', |
| const BoolValue(false), |
| ); |
| |
| const List<Option> folderOptionsSpecification = [ |
| Options.enableExperiment, |
| Options.enableUnscheduledExperiments, |
| Options.forceLateLoweringSentinel, |
| overwriteCurrentSdkVersion, |
| Options.forceLateLowering, |
| Options.forceStaticFieldLowering, |
| Options.forceNoExplicitGetterCalls, |
| Options.forceConstructorTearOffLowering, |
| Options.noDefines, |
| noVerifyCmd, |
| Options.target, |
| Options.defines, |
| Options.showOffsets, |
| ]; |
| |
| class SuiteFolderOptions { |
| final Uri baseUri; |
| final Map<Uri, FolderOptions> _folderOptions = {}; |
| |
| SuiteFolderOptions(this.baseUri); |
| |
| FolderOptions _computeFolderOptions(Directory directory) { |
| FolderOptions? folderOptions = _folderOptions[directory.uri]; |
| if (folderOptions == null) { |
| bool? enableUnscheduledExperiments; |
| int? forceLateLowering; |
| bool? forceLateLoweringSentinel; |
| bool? forceStaticFieldLowering; |
| bool? forceNoExplicitGetterCalls; |
| int? forceConstructorTearOffLowering; |
| bool noVerify = false; |
| Map<String, String>? defines = {}; |
| String target = "vm"; |
| bool showOffsets = false; |
| if (directory.uri == baseUri) { |
| folderOptions = new FolderOptions( |
| {}, |
| enableUnscheduledExperiments: enableUnscheduledExperiments, |
| forceLateLowerings: forceLateLowering, |
| forceLateLoweringSentinel: forceLateLoweringSentinel, |
| forceStaticFieldLowering: forceStaticFieldLowering, |
| forceNoExplicitGetterCalls: forceNoExplicitGetterCalls, |
| forceConstructorTearOffLowering: forceConstructorTearOffLowering, |
| defines: defines, |
| noVerify: noVerify, |
| target: target, |
| showOffsets: showOffsets, |
| ); |
| } else { |
| File optionsFile = new File.fromUri( |
| directory.uri.resolve('folder.options'), |
| ); |
| if (optionsFile.existsSync()) { |
| List<String> arguments = ParsedOptions.readOptionsFile( |
| optionsFile.readAsStringSync(), |
| ); |
| ParsedOptions parsedOptions = ParsedOptions.parse( |
| arguments, |
| folderOptionsSpecification, |
| ); |
| List<String> experimentalFlagsArguments = |
| Options.enableExperiment.read(parsedOptions) ?? <String>[]; |
| String? overwriteCurrentSdkVersionArgument = |
| overwriteCurrentSdkVersion.read(parsedOptions); |
| enableUnscheduledExperiments = Options.enableUnscheduledExperiments |
| .read(parsedOptions); |
| forceLateLoweringSentinel = Options.forceLateLoweringSentinel.read( |
| parsedOptions, |
| ); |
| forceLateLowering = Options.forceLateLowering.read(parsedOptions); |
| forceStaticFieldLowering = Options.forceStaticFieldLowering.read( |
| parsedOptions, |
| ); |
| forceNoExplicitGetterCalls = Options.forceNoExplicitGetterCalls.read( |
| parsedOptions, |
| ); |
| forceConstructorTearOffLowering = Options |
| .forceConstructorTearOffLowering |
| .read(parsedOptions); |
| defines = parsedOptions.defines; |
| showOffsets = Options.showOffsets.read(parsedOptions); |
| if (Options.noDefines.read(parsedOptions)) { |
| if (defines.isNotEmpty) { |
| throw "Can't have no defines and specific defines " |
| "at the same time."; |
| } |
| defines = null; |
| } |
| noVerify = noVerifyCmd.read(parsedOptions); |
| target = Options.target.read(parsedOptions); |
| folderOptions = new FolderOptions( |
| parseExperimentalFlags( |
| parseExperimentalArguments(experimentalFlagsArguments), |
| onError: (String message) => throw new ArgumentError(message), |
| onWarning: (String message) => throw new ArgumentError(message), |
| ), |
| enableUnscheduledExperiments: enableUnscheduledExperiments, |
| forceLateLowerings: forceLateLowering, |
| forceLateLoweringSentinel: forceLateLoweringSentinel, |
| forceStaticFieldLowering: forceStaticFieldLowering, |
| forceNoExplicitGetterCalls: forceNoExplicitGetterCalls, |
| forceConstructorTearOffLowering: forceConstructorTearOffLowering, |
| defines: defines, |
| noVerify: noVerify, |
| target: target, |
| overwriteCurrentSdkVersion: overwriteCurrentSdkVersionArgument, |
| showOffsets: showOffsets, |
| ); |
| } else { |
| folderOptions = _computeFolderOptions(directory.parent); |
| } |
| } |
| _folderOptions[directory.uri] = folderOptions; |
| } |
| return folderOptions; |
| } |
| |
| FolderOptions computeFolderOptions(TestDescription description) { |
| Directory directory = new File.fromUri(description.uri).parent; |
| return _computeFolderOptions(directory); |
| } |
| |
| static Map<ExperimentalFlag, bool> computeForcedExperimentalFlags( |
| Map<String, String> environment, |
| ) { |
| Map<ExperimentalFlag, bool> experimentalFlags = <ExperimentalFlag, bool>{ |
| // Force enable features in development. |
| ExperimentalFlag.nullAwareElements: true, |
| ExperimentalFlag.inferenceUsingBounds: true, |
| ExperimentalFlag.getterSetterError: true, |
| }; |
| |
| void addForcedExperimentalFlag(String name, ExperimentalFlag flag) { |
| if (environment.containsKey(name)) { |
| experimentalFlags[flag] = environment[name] == "true"; |
| } |
| } |
| |
| addForcedExperimentalFlag( |
| "enableNonNullable", |
| ExperimentalFlag.nonNullable, |
| ); |
| return experimentalFlags; |
| } |
| } |
| |
| /// Options used for all tests within a given folder. |
| /// |
| /// This is used for instance for defining target, mode, and experiment specific |
| /// test folders. |
| class FolderOptions { |
| final Map<ExperimentalFlag, bool> _explicitExperimentalFlags; |
| final bool? enableUnscheduledExperiments; |
| final int? forceLateLowerings; |
| final bool? forceLateLoweringSentinel; |
| final bool? forceStaticFieldLowering; |
| final bool? forceNoExplicitGetterCalls; |
| final int? forceConstructorTearOffLowering; |
| final Map<String, String>? defines; |
| final bool noVerify; |
| final String target; |
| final String? overwriteCurrentSdkVersion; |
| final bool showOffsets; |
| |
| FolderOptions( |
| this._explicitExperimentalFlags, { |
| this.enableUnscheduledExperiments, |
| this.forceLateLowerings, |
| this.forceLateLoweringSentinel, |
| this.forceStaticFieldLowering, |
| this.forceNoExplicitGetterCalls, |
| this.forceConstructorTearOffLowering, |
| this.defines = const {}, |
| this.noVerify = false, |
| this.target = "vm", |
| // can be null |
| this.overwriteCurrentSdkVersion, |
| this.showOffsets = false, |
| }) : assert( |
| // no this doesn't make any sense but left to underline |
| // that this is allowed to be null! |
| defines != null || defines == null, |
| ); |
| |
| /// Computes the experimental flag for the folder. |
| /// |
| /// [forcedExperimentalFlags] is used to override the default flags the |
| /// folder. |
| Map<ExperimentalFlag, bool> computeExplicitExperimentalFlags( |
| Map<ExperimentalFlag, bool> forcedExperimentalFlags, |
| ) { |
| Map<ExperimentalFlag, bool> flags = {}; |
| flags.addAll(_explicitExperimentalFlags); |
| flags.addAll(forcedExperimentalFlags); |
| return flags; |
| } |
| } |