blob: 61673433fb2756905df1bee35a09809d8c120b0d [file] [log] [blame] [edit]
// 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;
}
}