blob: f28e33ab9ab32a1b1c72ccdc49ddbf452b69c194 [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, Platform;
import 'package:_fe_analyzer_shared/src/exhaustiveness/exhaustive.dart';
import 'package:_fe_analyzer_shared/src/exhaustiveness/test_helper.dart';
import 'package:_fe_analyzer_shared/src/exhaustiveness/witness.dart';
import 'package:_fe_analyzer_shared/src/testing/features.dart';
import 'package:_fe_analyzer_shared/src/testing/id.dart'
show ActualData, Id, IdKind, NodeId;
import 'package:_fe_analyzer_shared/src/testing/id_testing.dart'
show DataInterpreter, cfeMarker, runTests;
import 'package:front_end/src/api_prototype/experimental_flags.dart';
import 'package:front_end/src/fasta/kernel/exhaustiveness.dart';
import 'package:front_end/src/testing/id_testing_helper.dart';
import 'package:kernel/ast.dart' hide Variance;
Future<void> main(List<String> args) async {
Directory dataDir = new Directory.fromUri(Platform.script
.resolve('../../../_fe_analyzer_shared/test/exhaustiveness/data'));
await runTests<Features>(dataDir,
args: args,
createUriForFileName: createUriForFileName,
onFailure: onFailure,
runTest: runTestFor<Features>(const ExhaustivenessDataComputer(), [
const TestConfig(cfeMarker, 'cfe with experiments',
explicitExperimentalFlags: const {
ExperimentalFlag.patterns: true,
ExperimentalFlag.records: true,
ExperimentalFlag.sealedClass: true
})
]));
}
class ExhaustivenessDataComputer extends DataComputer<Features> {
const ExhaustivenessDataComputer();
@override
DataInterpreter<Features> get dataValidator =>
const FeaturesDataInterpreter();
/// Function that computes a data mapping for [member].
///
/// Fills [actualMap] with the data.
@override
void computeMemberData(TestResultData testResultData, Member member,
Map<Id, ActualData<Features>> actualMap,
{bool? verbose}) {
member.accept(new ExhaustivenessDataExtractor(
testResultData.compilerResult, actualMap));
}
@override
bool get supportsErrors => true;
}
class ExhaustivenessDataExtractor extends CfeDataExtractor<Features> {
final ExhaustivenessDataForTesting _exhaustivenessData;
ExhaustivenessDataExtractor(InternalCompilerResult compilerResult,
Map<Id, ActualData<Features>> actualMap)
: _exhaustivenessData = compilerResult
.kernelTargetForTesting!.loader.dataForTesting!.exhaustivenessData,
super(compilerResult, actualMap);
Features? computeExhaustivenessData(TreeNode node) {
ExhaustivenessResult? result = _exhaustivenessData.switchResults[node];
if (result != null) {
Features features = new Features();
features[Tags.scrutineeType] = staticTypeToText(result.scrutineeType);
String? subtypes = typesToText(result.scrutineeType.subtypes);
if (subtypes != null) {
features[Tags.subtypes] = subtypes;
}
if (result.scrutineeType.isSealed) {
String? expandedSubtypes =
typesToText(expandSealedSubtypes(result.scrutineeType));
if (subtypes != expandedSubtypes && expandedSubtypes != null) {
features[Tags.expandedSubtypes] = expandedSubtypes;
}
}
Set<String> fieldsOfInterest = {};
for (Space caseSpace in result.caseSpaces) {
for (SingleSpace singleSpace in caseSpace.singleSpaces) {
fieldsOfInterest.addAll(singleSpace.fields.keys);
}
}
if (fieldsOfInterest.isNotEmpty) {
features[Tags.scrutineeFields] =
fieldsToText(result.scrutineeType.fields, fieldsOfInterest);
}
for (ExhaustivenessError error in result.errors) {
if (error is NonExhaustiveError) {
features[Tags.error] = errorToText(error);
}
}
Uri uri = node.location!.file;
for (int i = 0; i < result.caseSpaces.length; i++) {
int offset = result.caseOffsets[i];
Features caseFeatures = new Features();
caseFeatures[Tags.space] = spacesToText(result.caseSpaces[i]);
for (ExhaustivenessError error in result.errors) {
if (error is UnreachableCaseError && error.index == i) {
caseFeatures[Tags.error] = errorToText(error);
}
}
registerValue(
uri, offset, new NodeId(offset, IdKind.node), caseFeatures, node);
}
return features;
}
return null;
}
@override
Features? computeNodeValue(Id id, TreeNode node) {
if (node is SwitchStatement || node is Block || node is BlockExpression) {
return computeExhaustivenessData(node);
}
return null;
}
}