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